-- PcHot.mesa  last edit, Bruce  July 31, 1980  2:42 PM

DIRECTORY
  Copier USING [Outer],
  DebugOps USING [ReadCodeWord, ShortREAD],
  DSyms USING [GFHandle, GFrameMdi],
  Frames USING [Invalid],
  Init USING [],
  Lf USING [GF, PC],
  MachineDefs USING [BYTE, FHandle, GFHandle, NullGF],
  Pc USING [BytePC, EVRange, NullPC],
  PcOps USING [BytePC, CacheBase, CacheCBtiCold, ConvertCbti, EpCold, EpToCBtiCold, FindUserCbti, Item, ItemNull, ParentCbtiCold],
  PrincOps USING [BytePC, EntryVectorItem, PrefixHeader, SVPointer],
  State USING [GetGS, GF, GSHandle, LF],
  Storage USING [Pages],
  Symbols USING [BTIndex, BTNull, CBTIndex, CBTNull, MDIndex, MDNull],
  SymbolTable USING [Base, Missing];

PcHot: PROGRAM
  IMPORTS Copier, DebugOps, DSyms, Frames, Lf, PcOps, 
    State, Storage, SymbolTable
  EXPORTS Init, Pc, PcOps =
  BEGIN OPEN PcOps, PrincOps, Symbols;

  NoBti: ERROR = CODE;
  BadReason: ERROR = CODE;
  
  FHandle: TYPE = MachineDefs.FHandle;
  GFHandle: TYPE = MachineDefs.GFHandle;
  EVRange: TYPE = Pc.EVRange;

  data: State.GSHandle ← State.GetGS[];
  cache: PUBLIC CacheBase ← Storage.Pages[1];
  Head, Free: PUBLIC Item;

  Enumerate: PROC [proc: PROC [Item] RETURNS [BOOLEAN], gf: GFHandle]
      RETURNS [i: Item] =
    BEGIN
    next, last: Item;
    FOR i ← Head, cache[i].link UNTIL i = ItemNull DO
      IF cache[i].gf = gf AND proc[i] THEN
	BEGIN
	IF i = Head THEN RETURN;
	cache[last].link ← cache[i].link; cache[i].link ← Head; Head ← i;
        RETURN
	END;
      last ← i;
      ENDLOOP;
    IF Free # ItemNull THEN RETURN;
    FOR i ← Head, next UNTIL i = last DO
      IF (next ← cache[i].link) # last THEN LOOP;
      cache[i].link ← ItemNull;
      cache[last].link ← Free;
      Free ← next;
      RETURN[ItemNull];
      ENDLOOP;
    END;
  
  FindEp: PUBLIC PROC [ep: EVRange, gf: GFHandle] RETURNS [Item] =
    BEGIN
    Find: PROC [i: Item] RETURNS [BOOLEAN] = {RETURN[ep = cache[i].ep]};
    RETURN[Enumerate[Find, gf]];
    END;

  FindUserCbti: PUBLIC PROC [gf: GFHandle, cbti: CBTIndex] RETURNS [Item] = {
    Find: PROC [i: Item] RETURNS [BOOLEAN] = {
      RETURN[gf = cache[i].gf AND cbti = cache[i].userCbti]};
    RETURN[Enumerate[Find, gf]]};

  FindPC: PROC [pc: BytePC, gf: GFHandle] RETURNS [Item] =
    BEGIN
    Find: PROC [i: Item] RETURNS [BOOLEAN] = 
      BEGIN
      RETURN[
	Card[pc] >= Card[cache[i].start] AND Card[pc] <= Card[cache[i].end]]
      END;
    RETURN[Enumerate[Find, gf]];
    END;

  FindCbti: PUBLIC PROC [cbti: CBTIndex] RETURNS [i: Item] =
    BEGIN
    FOR i ← Head, cache[i].link UNTIL i = ItemNull DO
      IF cache[i].dCbti = cbti THEN RETURN;
      ENDLOOP;
    END;

  GetPc: PUBLIC PROC [gf: GFHandle, i: EVRange] RETURNS [pc: BytePC] =
    BEGIN OPEN PrincOps;
--    CSegP: TYPE = POINTER TO MachineDefs.CSegPrefix;
--	gf, LOOPHOLE[@LOOPHOLE[0,CSegP].entry[i].initialpc]];
    InitialPcOffset: CARDINAL = 0;
    pc ← DebugOps.ReadCodeWord[
      gf, SIZE[PrefixHeader]+i*SIZE[EntryVectorItem]+InitialPcOffset];
    RETURN[[pc*2]];
    END; 

  EvalStackEmpty: PUBLIC PROCEDURE [sp: PrincOps.SVPointer ← NIL]
      RETURNS [BOOLEAN] =
    BEGIN
    SV: TYPE = RECORD [inst,ptr: MachineDefs.BYTE];
    sv: SV;
    IF sp = NIL THEN sp ← data.StatePtr;
    IF sp = NIL THEN RETURN[TRUE];
    sv ← DebugOps.ShortREAD[sp+8];  -- yech
    RETURN [sv.ptr = 0]
    END;

  Son: PUBLIC PROC [cbti: CBTIndex] RETURNS [BOOLEAN] =
    BEGIN
    i: Item ← FindCbti[cbti];
    IF i = ItemNull THEN ERROR NoBti;
    RETURN [cache[i].hasSons];
    END;

  Ep: PUBLIC PROC [pc: BytePC, gf: GFHandle]
    RETURNS [ep: EVRange, start: BytePC] =
    BEGIN
    old: Item ← FindPC[pc, gf];
    IF old # ItemNull THEN {ep ← cache[old].ep; start ← cache[old].start}
    ELSE [ep,start] ← PcOps.EpCold[pc,gf];
    RETURN;
    END;

  EpToCBti: PUBLIC PROC [
      ep: EVRange, gf: GFHandle, start: BytePC ← Pc.NullPC]
    RETURNS [cbti: CBTIndex] =
    BEGIN
    old: Item = FindEp[ep, gf];
    RETURN[IF old # ItemNull THEN cache[old].dCbti ELSE PcOps.EpToCBtiCold[ep,gf,start]];
    END;

  CacheCBti: PUBLIC PROC [mdi: MDIndex, gf: GFHandle, cbti: CBTIndex]
    RETURNS [CBTIndex] =
    BEGIN
    i: Item = PcOps.FindUserCbti[gf,cbti];
    IF i # ItemNull THEN RETURN[cache[i].dCbti];
    RETURN[CacheCBtiCold[mdi,gf,cbti]];
    END;

  Fixup: PROC [pc: BytePC, gf: GFHandle] RETURNS [BytePC, GFHandle] =
    BEGIN
    IF gf = NIL THEN gf ← State.GF[];
    IF pc = Pc.NullPC THEN pc ← GetPc[gf,0];
    RETURN[pc,gf];
    END;

  ParentCbti: PUBLIC PROC [pc: BytePC, gf: GFHandle] RETURNS [old: Item, mdi: MDIndex] =
    BEGIN
    old ← FindPC[pc,gf];
    mdi ← DSyms.GFrameMdi[gf !
	SymbolTable.Missing, Frames.Invalid => GOTO noSyms];
    IF old = ItemNull THEN old ← PcOps.ParentCbtiCold[pc,gf,mdi];
    RETURN;
    EXITS
      noSyms => {mdi ← Symbols.MDNull; RETURN};
    END;

  Bti: PUBLIC PROC [pc: BytePC ← Pc.NullPC, gf: GFHandle ← MachineDefs.NullGF]
      RETURNS [bti: BTIndex] =
    BEGIN
    mdi: MDIndex;
    lpc: BytePC;
    lgf: GFHandle;
    i: Item;
    ClosestBti: PROC [base: SymbolTable.Base] = {
      bti ← PcOps.ConvertCbti[bti,pc,cache[i].start,base]};
    [lpc,lgf] ← Fixup[pc,gf];
    [i,mdi] ← ParentCbti[lpc,lgf];
    IF mdi = Symbols.MDNull OR i = ItemNull THEN RETURN[BTNull];
    IF (bti ← cache[i].userCbti) = BTNull THEN RETURN;
    IF ~cache[i].hasSons THEN RETURN;
    Copier.Outer[mdi,ClosestBti];
    END;

  CBti: PUBLIC PROC [
      pc: BytePC ← Pc.NullPC, gf: GFHandle ← MachineDefs.NullGF]
    RETURNS [cbti: CBTIndex] =
    BEGIN
    lpc: BytePC;
    lgf: GFHandle;
    i: Item;
    [lpc,lgf] ← Fixup[pc,gf];
    IF (i ← ParentCbti[lpc, lgf].old) = ItemNull THEN RETURN[CBTNull];
    RETURN[cache[i].dCbti];
    END;

  EntryPC: PUBLIC PROC [ep: EVRange, gf: GFHandle, noSyms: BOOLEAN ← FALSE] 
    RETURNS [pc: BytePC] =
    BEGIN
    pc ← GetPc[gf,ep];
    END;

  ExitPC: PUBLIC PROC [cbti: CBTIndex] RETURNS [BytePC] = {
    i: Item = FindCbti[cbti];
    IF i # ItemNull THEN RETURN[cache[i].end] ELSE ERROR SymbolTable.Missing[NIL]};

  CbtiItem: PROC [f: FHandle, pc: BytePC] RETURNS [Item, BytePC] =
    BEGIN
    SELECT TRUE FROM
      f = NIL => BEGIN f ← State.LF[]; pc ← Lf.PC[f] END;
      pc = Pc.NullPC => pc ← Lf.PC[f];
      ENDCASE;
    RETURN[FindCbti[CBti[pc, Lf.GF[f]]], pc];
    END;

  Entry: PUBLIC PROCEDURE [
      f: FHandle ← NIL, pc: BytePC ← Pc.NullPC] RETURNS [BOOLEAN] =
    BEGIN
    i: Item;
    [i,pc] ← CbtiItem[f,pc];
    IF i = ItemNull THEN ERROR SymbolTable.Missing[NIL];
    RETURN[(cache[i].start = pc) OR
      (cache[i].inner AND Card[cache[i].start]+2 = Card[pc])];
    END;

  Exit: PUBLIC PROCEDURE [
      f: FHandle ← NIL, pc: BytePC ← Pc.NullPC] RETURNS [BOOLEAN] =
    BEGIN
    i: Item;
    [i,pc] ← CbtiItem[f,pc];
    IF i = ItemNull THEN ERROR SymbolTable.Missing[NIL];
    RETURN[cache[i].end = pc];
    END;

  Card: PROC [pc: BytePC] RETURNS [CARDINAL] = INLINE {RETURN[LOOPHOLE[pc]]};

  END.