<> <> <> <> DIRECTORY Atom USING [PropList, PutPropOnList], DragOpsCross USING [FieldDescriptor, ioRescheduleRequest, ioResetRequest, JDist8, PCmdFormat, ProcessorRegister, Word], DragOpsCrossUtils USING [CardToWord, HalfToCard, IntToWord, WordToBytes, WordToHalves], HandCoding USING [const0, const1, ConstSpec, drADDB, drADDDB, drALS, drDUP, drFSDB, drJSR, drLC1, drLIP, drLIQB, drLRn, drIODA, drQOR, drQRX, drRADD, drRET, drRETN, drROR, drRRX, drRSUB, drSHL, drSHR, drSIP, drSRn, Lit16, Lit8, popSrc, pushDst, RegSpec, topSrc], HandCodingPseudos USING [Label, LabelRep], HandCodingSupport USING [Area, GetCurrentArea, OutputAlphaBeta, OutputAlphaBetaGammaDelta, OutputByte, SetOutputPC, WordAlign], IO USING [PutF, PutRope, STREAM], PriorityQueue USING [Empty, Insert, Predict, Ref, Remove, SortPred], Rope USING [Compare, ROPE], SymTab USING [Create, EachPairAction, Fetch, GetSize, Pairs, Ref, Store]; HandCodingPseudosImpl: CEDAR PROGRAM IMPORTS Atom, DragOpsCrossUtils, HandCoding, HandCodingSupport, IO, PriorityQueue, Rope, SymTab EXPORTS HandCodingPseudos = BEGIN OPEN DragOpsCross, HandCoding; ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; <> Area: TYPE = HandCodingSupport.Area; Label: TYPE = HandCodingPseudos.Label; LabelRep: TYPE = HandCodingPseudos.LabelRep; LabelUsageList: TYPE = LIST OF LabelUsage; LabelUsage: TYPE = RECORD [ area: Area, offset: INT _ 0, delta: INTEGER _ 0, distWidth: [0..4] _ 1, fixoff: [0..4] _ 0 ]; LabellingError: PUBLIC ERROR [why: ROPE] = CODE; SetLabel: PUBLIC PROC [label: Label] = { area: Area = HandCodingSupport.GetCurrentArea[]; here: CARD _ area.currentPC; IF label.area # NIL THEN ERROR LabellingError["duplicate definition"]; label.offset _ here; label.area _ area; FOR each: LabelUsageList _ NARROW[label.uses], each.rest UNTIL each = NIL DO use: LabelUsage = each.first; where: INT = use.offset; delta: INT = here - where - use.delta; word: Word = DragOpsCrossUtils.IntToWord[delta]; IF use.area # area THEN ERROR LabellingError["wrong area"]; HandCodingSupport.SetOutputPC[where+use.fixoff, area]; SELECT use.distWidth FROM 1 => { IF delta < -128 OR delta > 127 THEN ERROR LabellingError["delta not in a byte"]; HandCodingSupport.OutputByte[area, DragOpsCrossUtils.WordToBytes[word][3]]; }; 2 => { IF delta < FIRST[INTEGER] OR delta > LAST[INTEGER] THEN ERROR LabellingError["delta not in two bytes"]; HandCodingSupport.OutputAlphaBeta[ area, DragOpsCrossUtils.HalfToCard[DragOpsCrossUtils.WordToHalves[word][1]]]; }; 4 => { <<4-byte addresses are absolute, not relative>> HandCodingSupport.OutputAlphaBetaGammaDelta[ area, DragOpsCrossUtils.IntToWord[here - use.delta]]; }; ENDCASE; HandCodingSupport.SetOutputPC[here, area]; ENDLOOP; }; GenLabel: PUBLIC PROC RETURNS [label: Label] = { RETURN [NEW[LabelRep _ [area: NIL, name: NIL, offset: -1, uses: NIL]]]; }; GenLabelHere: PUBLIC PROC RETURNS [label: Label] = { label _ GenLabel[]; SetLabel[label]; }; UseLabel8A: PUBLIC PROC [label: Label] RETURNS [JDist8] = { offset: INT = DeltaLabels[label, 0, 1, 1]; IF offset < -128 OR offset > 127 THEN ERROR LabellingError["delta not in a byte"]; RETURN [IF offset < 0 THEN 256+offset ELSE offset]; }; UseLabel8B: PUBLIC PROC [label: Label] RETURNS [JDist8] = { offset: INT = DeltaLabels[label, 0, 1, 2]; IF offset < -128 OR offset > 127 THEN ERROR LabellingError["delta not in a byte"]; RETURN [IF offset < 0 THEN 256+offset ELSE offset]; }; UseLabel16: PUBLIC PROC [label: Label] RETURNS [Lit16] = { offset: INT = DeltaLabels[label, 0, 2]; IF offset < FIRST[INTEGER] OR offset > LAST[INTEGER] THEN ERROR LabellingError["delta not in two bytes"]; RETURN [IF offset < 0 THEN (offset + LAST[CARDINAL]) + 1 ELSE offset]; }; UseLabel32: PUBLIC PROC [label: Label] RETURNS [Word] = { RETURN [DragOpsCrossUtils.IntToWord[DeltaLabels[label, 0, 4]]]; }; DeltaLabels: PROC [label: Label, plus: INTEGER _ 0, width: [0..4] _ 1, fixoff: NAT _ 1] RETURNS [INT] = { <> pc: CARD; area: Area = HandCodingSupport.GetCurrentArea[]; pc _ area.currentPC; SELECT label.area FROM area => { <> IF width = 4 THEN RETURN [label.offset-plus] ELSE RETURN [label.offset - pc - plus]; }; NIL => { <> uses: LabelUsageList _ NARROW[label.uses]; uses _ CONS[[area: area, offset: pc, distWidth: width, delta: plus, fixoff: fixoff], uses]; label.uses _ uses; RETURN [0]; }; ENDCASE => <> ERROR LabellingError["wrong area"]; }; SymHolder: TYPE = RECORD[tab: SymTab.Ref]; MakeLabelGlobal: PUBLIC PROC [name: ROPE, label: Label] = { area: Area = HandCodingSupport.GetCurrentArea[]; tab: SymTab.Ref _ GetGlobalLabelTable[area]; IF tab = NIL THEN { tab _ SymTab.Create[29, FALSE]; area.props _ Atom.PutPropOnList[area.props, $GlobalLabels, NEW[SymHolder _ [tab]]]; }; [] _ SymTab.Store[tab, name, label]; label.name _ name; }; LabelNameSort: PriorityQueue.SortPred = { xx: HandCodingPseudos.Label = NARROW[x]; yy: HandCodingPseudos.Label = NARROW[y]; RETURN [Rope.Compare[xx.name, yy.name, FALSE] = less]; }; LabelAddrSort: PriorityQueue.SortPred = { xx: HandCodingPseudos.Label = NARROW[x]; yy: HandCodingPseudos.Label = NARROW[y]; RETURN [xx.offset < yy.offset]; }; ShowGlobalLabelTable: PUBLIC PROC [st: IO.STREAM, sortNames: BOOL _ TRUE, area: HandCodingSupport.Area _ NIL] = { <> tab: SymTab.Ref = GetGlobalLabelTable[area]; <> IF tab # NIL THEN { action: SymTab.EachPairAction = { <<[key: Key, val: Val] RETURNS [quit: BOOL]>> label: HandCodingPseudos.Label = NARROW[val]; PriorityQueue.Insert[pq, label]; quit _ FALSE; }; pq: PriorityQueue.Ref = PriorityQueue.Predict[ SymTab.GetSize[tab], IF sortNames THEN LabelNameSort ELSE LabelAddrSort, NIL]; [] _ SymTab.Pairs[tab, action]; WHILE NOT PriorityQueue.Empty[pq] DO label: HandCodingPseudos.Label = NARROW[PriorityQueue.Remove[pq]]; IF sortNames THEN IO.PutF[st, " %g = %w\n", [rope[label.name]], [cardinal[label.offset]]] ELSE IO.PutF[st, " -- %w: %g\n", [cardinal[label.offset]], [rope[label.name]]]; ENDLOOP; IO.PutRope[st, "\n"]; }; }; <<>> GetGlobalLabel: PUBLIC PROC [name: ROPE] RETURNS [Label] = { tab: SymTab.Ref _ GetGlobalLabelTable[NIL]; IF tab = NIL THEN RETURN [NIL]; RETURN [NARROW[SymTab.Fetch[tab, name].val]]; }; GetGlobalLabelTable: PUBLIC PROC [area: Area] RETURNS [tab: SymTab.Ref _ NIL] = { IF area = NIL THEN area _ HandCodingSupport.GetCurrentArea[]; FOR each: Atom.PropList _ area.props, each.rest WHILE each # NIL DO IF each.first.key = $GlobalLabels THEN { symHold: REF SymHolder _ NARROW[each.first.val]; tab _ symHold.tab; EXIT; }; ENDLOOP; }; <> LReg: PUBLIC PROC [reg: RegSpec] = { SELECT TRUE FROM reg.kind = reg => drLRn[reg]; reg = topSrc => drDUP[]; ENDCASE => drQOR[pushA0, reg]; }; PReg: PUBLIC PROC [reg: RegSpec] = { drROR[c: reg, a: topSrc, b: const0]; }; SReg: PUBLIC PROC [reg: RegSpec] = { IF reg.kind = reg THEN drSRn[reg] ELSE drROR[c: reg, a: popSrc, b: const0]; }; AddReg: PUBLIC PROC [reg: RegSpec, const: ConstSpec] = { drRADD[c: reg, a: reg, b: const]; }; SubReg: PUBLIC PROC [reg: RegSpec, const: ConstSpec] = { drRSUB[c: reg, a: reg, b: const]; }; SetRegConst: PUBLIC PROC [reg: RegSpec, const: ConstSpec] = { drROR[c: reg, a: const, b: const0]; }; MoveReg: PUBLIC PROC [dst,src: RegSpec] = { <> SELECT TRUE FROM dst.kind = aux AND src.kind = reg => { drLRn[reg: src]; drROR[c: dst, a: popSrc, b: const0]; }; dst.kind = reg AND src.kind = aux => { drROR[c: pushDst, a: src, b: const0]; drSRn[reg: dst]; }; ENDCASE => drROR[c: dst, a: src, b: const0]; }; MoveRegI: PUBLIC PROC [dst,src: RegSpec, const: ConstSpec] = { drRRX[c: dst, a: src, b: const]; }; LRegI: PUBLIC PROC [reg: RegSpec, const: ConstSpec] = { SELECT const FROM const0 => drQRX[pushA0, reg]; const1 => drQRX[pushA1, reg]; ENDCASE => drRRX[c: pushDst, a: reg, b: const]; }; IndexedJump: PUBLIC PROC [dest: Label, long: BOOL _ FALSE, back: BOOL _ FALSE] = { area: Area = HandCodingSupport.GetCurrentArea[]; thisPC: CARD _ area.currentPC; IF dest # NIL THEN IF long THEN drADDDB[DeltaLabels[dest, 3, 2]] ELSE drADDB[DeltaLabels[dest, 2, 1]]; drJSR[]; }; ProcedureEntry: PUBLIC PROC [label: Label, args: [0..15], dontChangeRL: BOOL _ FALSE] = { <> lit: Lit8 _ (1-LOOPHOLE[args, CARDINAL]) MOD 256; HandCodingSupport.WordAlign[]; IF label # NIL THEN SetLabel[label]; IF NOT dontChangeRL THEN drALS[lit]; }; ProcedureExit: PUBLIC PROC [rets: [0..15], dontChangeSP: BOOL _ FALSE] = { <> lit: Lit8 _ (LOOPHOLE[rets, CARDINAL]-1) MOD 256; SELECT TRUE FROM dontChangeSP => drRETN[]; ENDCASE => drRET[lit]; }; SetupField: PUBLIC PROC [fd: FieldDescriptor] = { <<... generates the appropriate instruction to extract the specified bits from [S], which is performed by left shifting the pair ([S], [S]) until the field is in the corretc position, then masking out the correct # of bits.>> drFSDB[LOOPHOLE[fd, Lit16]]; }; ExtractField: PUBLIC PROC [first: [0..31], bits: [0..31]] = { <<... generates the appropriate instruction to extract the specified bits from [S], which is performed by left shifting the pair ([S], [S]) until the field is in the correct position, then masking out the correct # of bits.>> fd: FieldDescriptor = [ reserved: 0, insert: FALSE, mask: bits, shift: first + bits ]; drSHR[LOOPHOLE[fd, Lit16]]; }; ShiftLeft: PUBLIC PROC [bits: [0..31]] = { <> fd: FieldDescriptor = [ reserved: 0, insert: FALSE, mask: 0, shift: bits ]; drSHL[LOOPHOLE[fd, Lit16]]; }; <> LoadProcessorReg: PUBLIC PROC [which: DragOpsCross.ProcessorRegister] = { <> drLIP[LOOPHOLE[which]]; }; StoreProcessorReg: PUBLIC PROC [which: DragOpsCross.ProcessorRegister] = { <> drSIP[LOOPHOLE[which]]; }; CauseReschedule: PUBLIC PROC = { <<... causes a reschedule interrupt when interrupts are next enabled (possibly immediately). We do this by writing anything to a peculiar IO location.>> pCmd: DragOpsCross.PCmdFormat _ [cache[space: io, direction: write]]; drLC1[]; drLIQB[DragOpsCrossUtils.CardToWord[DragOpsCross.ioRescheduleRequest]]; drIODA[LOOPHOLE[pCmd]]; }; CauseReset: PUBLIC PROC = { <<... causes a reset trap.>> pCmd: DragOpsCross.PCmdFormat _ [cache[space: io, direction: write]]; drLC1[]; drLIQB[DragOpsCrossUtils.CardToWord[DragOpsCross.ioResetRequest]]; drIODA[LOOPHOLE[pCmd]]; }; GetSPLimit: PUBLIC PROC = { <<... enables/disables stack overflow trapping.>> LoadProcessorReg[ifuSLimit]; }; SetSPLimit: PUBLIC PROC = { <<... enables/disables stack overflow trapping.>> StoreProcessorReg[ifuSLimit]; }; GetYoungestPC: PUBLIC PROC = { <<... gets the youngest PC entry in the IFU stack (into [S]). S_S+1.>> LoadProcessorReg[ifuYoungestPC]; }; GetYoungestStatus: PUBLIC PROC = { <<... gets the youngest L entry in the IFU stack (into [S]). S_S+1.>> LoadProcessorReg[ifuYoungestL]; }; GetEldestPC: PUBLIC PROC = { <<... flushes the eldest entry in the IFU stack and puts the PC into [S+1]. S_S+1. The results are undefined if there was no PC to get.>> LoadProcessorReg[ifuEldestPC]; }; GetEldestStatus: PUBLIC PROC = { <<... pushes the RL part of the eldest IFU stack entry. >> LoadProcessorReg[ifuEldestL]; }; SetYoungestPC: PUBLIC PROC = { <<... sets the youngest PC entry in the IFU stack (from [S]). S_S-1.>> StoreProcessorReg[ifuYoungestPC]; }; SetYoungestStatus: PUBLIC PROC = { <<... sets the youngest L entry in the IFU stack (from [S]). S_S-1.>> StoreProcessorReg[ifuYoungestL]; }; SetEldestPC: PUBLIC PROC = { <<... causes a new eldest IFU stack entry to be created and sets the PC part of that entry (from [S]). S_S-1.>> StoreProcessorReg[ifuEldestPC]; }; SetEldestStatus: PUBLIC PROC = { <<... sets the RL part of the eldest IFU stack entry (from [S]).>> StoreProcessorReg[ifuEldestL]; }; <> Pause: PUBLIC PROC = { <<... Instructs the interpreter to pause.>> HandCodingSupport.OutputByte[HandCodingSupport.GetCurrentArea[], LOOPHOLE[0]]; }; Halt: PUBLIC PROC [code: CARDINAL] = { <<... Instructs the interpreter to pause.>> area: Area = HandCodingSupport.GetCurrentArea[]; HandCodingSupport.OutputByte[area, LOOPHOLE[377B]]; HandCodingSupport.OutputAlphaBeta[area, code]; }; END.