-- file: PeepholeZ.mesa
-- last edited by Sweet on 11-Aug-82 10:52:34
-- last edited by Satterthwaite on December 16, 1982 11:12 am
DIRECTORY
Alloc: TYPE USING [Notifier],
Code: TYPE USING [codeptr],
CodeDefs: TYPE USING [Base, CCIndex, CCNull, CodeCCIndex, codeType],
ComData: TYPE USING [textIndex, switches],
ESCAlpha: TYPE,
FOpCodes: TYPE,
Log: TYPE USING [Error],
Mopcodes: TYPE,
OpCodeParams: TYPE USING [
BYTE, ExternalProcBase, ExternalProcSlots,
GlobalAddressSlots, GlobalBase, GlobalDoubleLoadSlots, GlobalLoadSlots,
LocalAddressSlots, LocalBase, LocalDoubleLoadSlots, LocalDoublePutSlots,
LocalDoubleStoreSlots, LocalLoadSlots, LocalProcBase, LocalProcSlots,
LocalPutSlots, LocalStoreSlots, ReadLocalIndirect0Slots, ReadSlots,
zEFCn, zGAn, zLAn, zLFCn, zLGDn, zLGn, zLLDn, zLLn,
zPLDn, zPLn, zRLI0n, zRn, zSLDn, zSLn],
OpTableDefs: TYPE USING [InstLength],
P5: TYPE USING [NumberOfParams, P5Error, C0, C1, C1W, C2, LoadConstant],
PeepholeDefs: TYPE USING [InitParameters, PackPair, PeepState],
P5U: TYPE USING [DeleteCell];
PeepholeZ: PROGRAM
IMPORTS CPtr: Code, MPtr: ComData, Log, OpTableDefs, P5, P5U, PeepholeDefs
EXPORTS PeepholeDefs =
BEGIN OPEN PeepholeDefs, OpCodeParams, CodeDefs;
-- imported definitions
BYTE: TYPE = OpCodeParams.BYTE;
CodeCCIndex: TYPE = CodeDefs.CodeCCIndex;
cb: CodeDefs.Base; -- code base (local copy)
PeepholeZNotify: PUBLIC Alloc.Notifier =
BEGIN -- called by allocator whenever table area is repacked
cb ← base[codeType];
END;
UnconvertedInstruction: SIGNAL [opcode: WORD] = CODE;
PeepZ: PUBLIC PROC [start: CodeCCIndex] =
BEGIN -- convert to real instructions (ie from qXXX to zXXX)
OPEN ESCAlpha, Mopcodes, FOpCodes;
next, ci: CCIndex;
state: PeepState;
recentSource: CARDINAL ← 0;
next ← start;
UNTIL (ci ← next) = CCNull DO
next ← cb[ci].flink;
WITH cc: cb[ci] SELECT FROM
code =>
IF ~cc.realinst THEN
BEGIN OPEN state;
DC: PROC = INLINE {P5U.DeleteCell[c]};
InitParameters[@state, LOOPHOLE[ci], c];
SELECT cInst FROM
qACD => MakeReal[ zACD, c];
qADC => MakeReal[ zADC, c];
qADD => MakeReal[zADD, c];
qADDSB => MakeReal[zADDSB, c];
qAF => {Esc[aAF]; DC[]};
qAL0IB => MakeReal[ zAL0IB, c];
qAND => MakeReal[ zAND, c];
qBC => {Esc[aBC]; DC[]};
qBC => {Esc[aBC]; DC[]};
qBITBLT => {Esc[aBITBLT]; DC[]};
qBLTEL => {Esc[aBLEL]; DC[]};
qBLTECL => {Esc[aBLECL]; DC[]};
qBLT => MakeReal[ zBLT, c];
qBLTC => MakeReal[ zBLTC, c];
qBLTL => MakeReal[ zBLTL, c];
qBLTCL => MakeReal[ zBLTCL, c];
qBNDCK => MakeReal[ zBNDCK, c];
qCATCH => MakeReal[zCATCH, c];
qCATCHFSI => {
cc.inst ← zJ2; cc.isize ← 2; cc.realinst ← TRUE}; -- strange but true
qDADD => MakeReal[ zDADD, c];
qDB =>
IF cP[1] = 0 THEN {P5.C0[zD0]; DC[]}
ELSE MakeReal[ zDB, c];
qDBL => MakeReal[ zDBL, c];
qDBS => {EscL[bDBS, cP[1]]; DC[]};
qDCMP => MakeReal[ zDCMP, c];
qDDBL => MakeReal[ zDDBL, c];
qDDIV => {Esc[aSDDIV]; DC[]};
qDDUP => MakeReal[ zDDUP, c];
qDEC => MakeReal[ zDEC, c];
qDEXCH => MakeReal[ zDEXCH, c];
qDI => {Esc[aDI]; DC[]};
qDINC => MakeReal[ zDINC, c];
qDIS => MakeReal[ zDIS, c];
qDIS2 => MakeReal[ zDIS2, c];
qDMOD => {
Esc[aSDDIV]; P5.C0[zREC2]; P5.C0[zDEXCH]; P5.C0[zDIS2]; DC[]};
qDMUL => {Esc[aDMUL]; DC[]};
qDSHIFT => {Esc[aDSHIFT]; DC[]};
qDSK => {EscL[bDSK, cP[1]]; DC[]};
qDSUB => MakeReal[ zDSUB, c];
qDUDIV => {Esc[aUDDIV]; DC[]};
qDUMOD => {
Esc[aUDDIV]; P5.C0[zREC2]; P5.C0[zDEXCH]; P5.C0[zDIS2]; DC[]};
qDUP => MakeReal[ zDUP, c];
qEFC =>
IF cP[1] IN ExternalProcSlots THEN
{P5.C0[zEFCn+cP[1]-ExternalProcBase]; DC[]}
ELSE MakeReal[ zEFCB, c];
qEI => {Esc[aEI]; DC[]};
qEXCH => MakeReal[ zEXCH, c];
qEXDIS => MakeReal[ zEXDIS, c];
qFADD => {Esc[aFADD]; DC[]};
qFCOMP => {Esc[aFCOMP]; DC[]};
qFDIV => {Esc[aFDIV]; DC[]};
qFF => {Esc[aFF]; DC[]};
qFLOAT => {Esc[aFLOAT]; DC[]};
qFMUL => {Esc[aFMUL]; DC[]};
qFSUB => {Esc[aFSUB]; DC[]};
qGA => SELECT cP[1] FROM
IN GlobalAddressSlots => {P5.C0[zGAn+cP[1]-GlobalBase]; DC[]};
IN BYTE => MakeReal[ zGAB, c];
ENDCASE => {P5.C1W[zGAW, cP[1]]; DC[]};
qINC => MakeReal[ zINC, c];
qKFCB => IF MPtr.switches['y] THEN
{MPtr.textIndex ← recentSource; Log.Error[implicitCall]}
ELSE MakeReal[ zKFCB, c];
qLA => SELECT cP[1] FROM
IN LocalAddressSlots => {P5.C0[zLAn+cP[1]-LocalBase]; DC[]};
LocalBase+6 => {P5.C0[zLA6]; DC[]};
LocalBase+8 => {P5.C0[zLA8]; DC[]};
IN BYTE => MakeReal[ zLAB, c];
ENDCASE => {P5.C1W[zLAW, cP[1]]; DC[]};
qLCO => {
P5.C1W[zLIW, cP[1]];
WITH cb[CPtr.codeptr] SELECT FROM
code => lco ← TRUE;
ENDCASE => ERROR;
DC[]};
qLUDIV => {Esc[aLUDIV]; DC[]};
qLFC =>
IF cP[1] IN LocalProcSlots THEN
{P5.C0[zLFCn+cP[1]-LocalProcBase]; DC[]}
ELSE MakeReal[ zLFCB, c];
qLG => {MoveVar[global, load, single, cP[1]]; DC[]};
qLGD => {MoveVar[global, load, double, cP[1]]; DC[]};
qLI => {P5.LoadConstant[cP[1]]; DC[]};
qLID =>
IF cP[1] = 0 THEN {P5.C0[zLID0]; DC[]}
ELSE {P5.LoadConstant[cP[1]]; P5.C0[zLI0]; DC[]};
qLINT => {Esc[aLINT]; DC[]};
qLKB => MakeReal[ zLKB, c];
qLL => {MoveVar[local, load, single, cP[1]]; DC[]};
qLLD => {MoveVar[local, load, double, cP[1]]; DC[]};
qLLK => MakeReal[ zLLKB, c];
qLLOB => {EscL[bLLOB, cP[1]]; DC[]};
qLP => MakeReal[zLP, c];
qLST => {EscL[bLSK, cP[1]]; DC[]};
qLSTE => {EscL[bLSTE, cP[1]]; DC[]};
qLSTF => {EscL[bLSTF, cP[1]]; DC[]};
qME => {Esc[aME]; DC[]};
qMR => {Esc[aMR]; DC[]};
qMUL, qAMUL => MakeReal[ zMUL, c];
qMW => {Esc[aMW]; DC[]};
qMX => {Esc[aMX]; DC[]};
qNC => {Esc[aNC]; DC[]};
qNEG => MakeReal[ zNEG, c];
qNILCK => {Esc[aNILCK]; DC[]};
qNILCKL => {Esc[aNILCKL]; DC[]};
qIOR => MakeReal[ zIOR, c];
qPI => {Esc[aPI]; DC[]};
qPL => {MoveVar[local, put, single, cP[1]]; DC[]};
qPLD => {MoveVar[local, put, double, cP[1]]; DC[]};
qPO => {Esc[aPO]; DC[]};
qPS => {Move[sput, single, cP[1], 0]; DC[]};
qPSD => {Move[sput, double, cP[1], 0]; DC[]};
qPSDL => {Move[sputlong, double, cP[1], 0]; DC[]};
qPSF => {Move[sput, partial, cP[1], cP[2]]; DC[]};
qPSL => {Move[sputlong, single, cP[1], 0]; DC[]};
qPSLF => {Move[sputlong, partial, cP[1], cP[2]]; DC[]};
qR => {Move[read, single, cP[1], 0]; DC[]};
qRC => {EscL[bRC, cP[1]]; DC[]};
qRD => {Move[read, double, cP[1], 0]; DC[]};
qRDL => {Move[readlong, double, cP[1], 0]; DC[]};
qREC => MakeReal[ zREC, c];
qREC2 => MakeReal[ zREC2, c];
qREQ => {Esc[aREQ]; DC[]};
qRET => MakeReal[ zRET, c];
qRF => {Move[read, partial, cP[1], cP[2]]; DC[]};
qRCFS => {Esc[aRCFS]; DC[]};
qRLFS => MakeReal[zRLFS, c];
qRGI => MakeGPReal[zRGIP, c];
qRGIL => MakeGPReal[zRGILP, c];
qRKDI => MakeReal[zRKDIB, c];
qRKI => MakeReal[zRKIB, c];
qRL => {Move[readlong, single, cP[1], 0]; DC[]};
qRLDI => IF cP[1] = LocalBase AND cP[2] = 0 THEN {
P5.C0[zRLDI00]; DC[]}
ELSE MakeLPReal[zRLDIP, c];
qRLDIL => MakeLPReal[zRLDILP, c];
qRLF => {Move[readlong, partial, cP[1], cP[2]]; DC[]};
qRLI =>
IF cP[1] = LocalBase AND cP[2] IN ReadLocalIndirect0Slots THEN {
P5.C0[zRLI0n+cP[2]]; DC[]}
ELSE MakeLPReal[zRLIP, c];
qRLIF => MakeLPFReal[zRLIPF, c];
qRLIL => MakeLPReal[zRLILP, c];
qRLILF => MakeLPFReal[zRLILPF, c];
qRSTR => MakeReal[ zRS, c];
qRSTRL => MakeReal[ zRLS, c];
qSDIV => {Esc[aSDIV]; DC[]};
qSFC => MakeReal[ zSFC, c];
qSG => {MoveVar[global, store, single, cP[1]]; DC[]};
qSGD => {MoveVar[global, store, double, cP[1]]; DC[]};
qSHIFT => MakeReal[ zSHIFT, c];
qSHIFTSB =>
SELECT INTEGER[cP[1]] FROM
0 => DC[];
1 => {P5.C0[zDBL]; DC[]};
IN [-15..15] => MakeReal[ zSHIFTSB, c];
ENDCASE => {P5.LoadConstant[cP[1]]; P5.C0[zSHIFT]; DC[]};
qSL => {MoveVar[local, store, single, cP[1]]; DC[]};
qSLD => {MoveVar[local, store, double, cP[1]]; DC[]};
qSUB => MakeReal[ zSUB, c];
qTRPL => MakeReal[ zTRPL, c];
qUDCMP => MakeReal[ zUDCMP, c];
qUDIV => {Esc[aUDIV]; DC[]};
qW => {Move[write, single, cP[1], 0]; DC[]};
qWD => {Move[write, double, cP[1], 0]; DC[]};
qWDL => {Move[writelong, double, cP[1], 0]; DC[]};
qWF => {Move[write, partial, cP[1], cP[2]]; DC[]};
qWLFS => MakeReal[zWLFS, c];
qWL => {Move[writelong, single, cP[1], 0]; DC[]};
qWLDIL => MakeLPReal[zWLDILP, c];
qWLF => {Move[writelong, partial, cP[1], cP[2]]; DC[]};
qWLI => MakeLPReal[zWLIP, c];
qWLIL => MakeLPReal[zWLILP, c];
qWS => {Move[swrite, single, cP[1], 0]; DC[]};
qWSD => {Move[swrite, double, cP[1], 0]; DC[]};
qWSDL => {Move[swritelong, double, cP[1], 0]; DC[]};
qWSF => {Move[swrite, partial, cP[1], cP[2]]; DC[]};
qWSL => {Move[swritelong, single, cP[1], 0]; DC[]};
qWSLF => {Move[swritelong, partial, cP[1], cP[2]]; DC[]};
qWSTR => MakeReal[ zWS, c];
qWSTRL => MakeReal[ zWLS, c];
qXOR => {Esc[aXOR]; DC[]};
-- Cedar extensions
qBLZL => {Esc[aBLZL]; DC[]};
qGCRT => MakeMiscReal[aCREFTYPE, c];
qPSCIDL => {MoveCounted[sputlong, TRUE, cP[1]]; DC[]};
qPSCDL => {MoveCounted[sputlong, FALSE, cP[1]]; DC[]};
qWCIDL => {MoveCounted[writelong, TRUE, cP[1]]; DC[]};
qWCDL => {MoveCounted[writelong, FALSE, cP[1]]; DC[]};
qWSCIDL => {MoveCounted[swritelong, TRUE, cP[1]]; DC[]};
qWSCDL => {MoveCounted[swritelong, FALSE, cP[1]]; DC[]};
ENDCASE => {SIGNAL UnconvertedInstruction[cInst]; DC[]};
END;
other => WITH cc SELECT FROM
source => recentSource ← index;
ENDCASE => NULL;
ENDCASE => NULL;
ENDLOOP;
END;
Esc: PROC [alpha: BYTE] = INLINE {P5.C1[Mopcodes.zESC, alpha]};
EscL: PROC [alpha, beta: BYTE] = INLINE {P5.C2[Mopcodes.zESCL, alpha, beta]};
MakeReal: PROC [i: BYTE, c: CodeCCIndex] =
BEGIN
IF cb[c].realinst OR P5.NumberOfParams[cb[c].inst] # OpTableDefs.InstLength[i]-1
THEN P5.P5Error[1025];
cb[c].inst ← i;
cb[c].realinst ← TRUE;
END;
MakeLPReal: PROC [i: BYTE, c: CodeCCIndex] =
BEGIN
IF cb[c].realinst OR P5.NumberOfParams[cb[c].inst] # OpTableDefs.InstLength[i]-1+1
THEN P5.P5Error[1027];
P5.C1[i, PackPair[cb[c].parameters[1]-LocalBase, cb[c].parameters[2]]];
P5U.DeleteCell[c];
END;
MakeGPReal: PROC [i: BYTE, c: CodeCCIndex] =
BEGIN
IF cb[c].realinst OR P5.NumberOfParams[cb[c].inst] # OpTableDefs.InstLength[i]-1+1
THEN P5.P5Error[1028];
P5.C1[i, PackPair[cb[c].parameters[1]-GlobalBase, cb[c].parameters[2]]];
P5U.DeleteCell[c];
END;
MakeLPFReal: PROC [i: BYTE, c: CodeCCIndex] =
BEGIN
IF cb[c].realinst OR P5.NumberOfParams[cb[c].inst] # OpTableDefs.InstLength[i]-1+1
THEN P5.P5Error[1027];
P5.C2[i, PackPair[cb[c].parameters[1]-LocalBase, cb[c].parameters[2]], cb[c].parameters[3]];
P5U.DeleteCell[c];
END;
MakeGPFReal: PROC [i: BYTE, c: CodeCCIndex] =
BEGIN
IF cb[c].realinst OR P5.NumberOfParams[cb[c].inst] # OpTableDefs.InstLength[i]-1+1
THEN P5.P5Error[1028];
P5.C2[i, PackPair[cb[c].parameters[1]-GlobalBase, cb[c].parameters[2]], cb[c].parameters[3]];
P5U.DeleteCell[c];
END;
cpeep9: PROC =
BEGIN -- find 2-instruction sequences
RETURN
END;
cpeep10: PROC =
BEGIN -- find bit-testing jumps
RETURN
END;
Mdirection: TYPE = {read, write, swrite, sput, readlong, writelong, swritelong, sputlong};
Mtype: TYPE = {single, double, partial};
MVdirection: TYPE = {load, store, put};
MVtype: TYPE = {single, double};
MVclass: TYPE = {global, local};
MoveB: ARRAY MVclass OF ARRAY MVtype OF
ARRAY MVdirection OF BYTE = [
global: [
single: [Mopcodes.zLGB, Mopcodes.zSGB, Mopcodes.zNOOP],
double: [Mopcodes.zLGDB, Mopcodes.zSGDB, Mopcodes.zNOOP]],
local: [
single: [Mopcodes.zLLB, Mopcodes.zSLB, Mopcodes.zPLB],
double: [Mopcodes.zLLDB, Mopcodes.zSLDB, Mopcodes.zPLDB]]];
RWB: ARRAY MVdirection [load..store] OF ARRAY MVtype [single..double] OF BYTE = [
[Mopcodes.zRB, Mopcodes.zRDB],
[Mopcodes.zWB, Mopcodes.zWDB]];
RW0: ARRAY MVdirection [load..store] OF ARRAY MVtype [single..double] OF BYTE = [
[Mopcodes.zR0, Mopcodes.zRD0],
[Mopcodes.zW0, Mopcodes.zNOOP]];
MoveVar: PROC [c: MVclass, d: MVdirection, t: MVtype, offset: WORD] =
BEGIN -- handles LG, SG, LL, SL, LGD, SGD, LLD, SLD, PL class instructions
OPEN Mopcodes;
SELECT c FROM
local => SELECT t FROM
single => SELECT d FROM
load => IF offset IN LocalLoadSlots THEN
BEGIN P5.C0[zLLn+offset-LocalBase]; RETURN END;
store => IF offset IN LocalStoreSlots THEN
BEGIN P5.C0[zSLn+offset-LocalBase]; RETURN END;
put => IF offset IN LocalPutSlots THEN
BEGIN P5.C0[zPLn+offset-LocalBase]; RETURN END;
ENDCASE;
double => SELECT d FROM
load => SELECT offset FROM
IN LocalDoubleLoadSlots => {P5.C0[zLLDn+offset-LocalBase]; RETURN};
LocalBase+10 => {P5.C0[zLLD10]; RETURN};
ENDCASE;
store => SELECT offset FROM
IN LocalDoubleStoreSlots => {P5.C0[zSLDn+offset-LocalBase]; RETURN};
LocalBase+8 => {P5.C0[zSLD8]; RETURN};
ENDCASE;
put => IF offset IN LocalDoublePutSlots THEN
BEGIN P5.C0[zPLDn+offset-LocalBase]; RETURN END;
ENDCASE;
ENDCASE;
global => SELECT t FROM
single => SELECT d FROM
load => IF offset IN GlobalLoadSlots THEN
BEGIN P5.C0[zLGn+offset-GlobalBase]; RETURN END;
ENDCASE;
double => SELECT d FROM
load => SELECT offset FROM
IN GlobalDoubleLoadSlots => {P5.C0[zLGDn+offset-GlobalBase]; RETURN};
GlobalBase+2 => {P5.C0[zLGD2]; RETURN};
ENDCASE;
ENDCASE;
ENDCASE;
ENDCASE;
IF offset NOT IN BYTE THEN
BEGIN
P5.C1W[IF c = global THEN zGAW ELSE zLAW, offset];
IF d = store AND t = double THEN P5.C1[zWDB, 0] ELSE P5.C0[RW0[d][t]];
RETURN
END;
P5.C1[MoveB[c][t][d], offset];
END;
Move: PROC [d: Mdirection, t: Mtype, offset, field: WORD] =
BEGIN -- handles R, W, RF, WF, WS, WSF, PS, PSF class instructions
OPEN Mopcodes;
IF d = read AND t = single AND offset IN ReadSlots THEN
BEGIN P5.C0[zRn+offset]; RETURN END;
IF offset NOT IN BYTE THEN
BEGIN
P5.LoadConstant[offset];
IF d >= readlong THEN
BEGIN
IF LOOPHOLE[offset, INTEGER]>0 THEN P5.C0[zADC]
ELSE {
P5.LoadConstant[177777B];
P5.C0[zDADD]}
END
ELSE P5.C0[zADD];
offset ← 0;
END;
IF offset = 0 THEN
SELECT d FROM
read => SELECT t FROM
single => P5.C0[zR0];
double => P5.C0[zRD0];
partial => P5.C1[zR0F, field];
ENDCASE; -- single tested above
write => SELECT t FROM
single => P5.C0[zW0];
double => P5.C1[zWDB, offset];
partial => P5.C1[zW0F, field];
ENDCASE;
readlong => SELECT t FROM
single => P5.C0[zRL0];
double => P5.C0[zRDL0];
partial => P5.C1[zRL0F, field];
ENDCASE;
writelong => SELECT t FROM
single => P5.C1[zWLB, offset];
double => P5.C1[zWDLB, offset];
partial => P5.C1[zWL0F, field];
ENDCASE;
sput => SELECT t FROM
single => P5.C1[zPSB, offset];
double => P5.C0[zPSD0];
partial => P5.C1[zPS0F, field];
ENDCASE;
swrite => SELECT t FROM
single => {P5.C1[zPSB, offset]; P5.C0[zDIS]};
double => {P5.C0[zPSD0]; P5.C0[zDIS]};
partial => P5.C1[zWS0F, field];
ENDCASE;
sputlong => SELECT t FROM
single => P5.C1[zPSLB, offset];
double => P5.C1[zPSDLB, offset];
partial => P5.C2[zPSLF, offset, field];
ENDCASE;
swritelong => SELECT t FROM
single => {P5.C1[zPSLB, offset]; P5.C0[zDIS2]};
double => {P5.C1[zPSDLB, offset]; P5.C0[zDIS2]};
partial => {P5.C2[zPSLF, offset, field]; P5.C0[zDIS2]};
ENDCASE;
ENDCASE
ELSE
SELECT d FROM
read => SELECT t FROM
single => P5.C1[zRB, offset];
double => P5.C1[zRDB, offset];
partial => P5.C2[zRF, offset, field];
ENDCASE;
write => SELECT t FROM
single => P5.C1[zWB, offset];
double => P5.C1[zWDB, offset];
partial => P5.C2[zWF, offset, field];
ENDCASE;
sput => SELECT t FROM
single => P5.C1[zPSB, offset];
double => P5.C1[zPSDB, offset];
partial => P5.C2[zPSF, offset, field];
ENDCASE;
swrite => SELECT t FROM
single => {P5.C1[zPSB, offset]; P5.C0[zDIS]};
double => {P5.C1[zPSDB, offset]; P5.C0[zDIS]};
partial => {P5.C2[zPSF, offset, field]; P5.C0[zDIS]};
ENDCASE;
readlong => SELECT t FROM
single => P5.C1[zRLB, offset];
double => P5.C1[zRDLB, offset];
partial => P5.C2[zRLF, offset, field];
ENDCASE;
writelong => SELECT t FROM
single => P5.C1[zWLB, offset];
double => P5.C1[zWDLB, offset];
partial => P5.C2[zWLF, offset, field];
ENDCASE;
sputlong => SELECT t FROM
single => P5.C1[zPSLB, offset];
double => P5.C1[zPSDLB, offset];
partial => P5.C2[zPSLF, offset, field];
ENDCASE;
swritelong => SELECT t FROM
single => {P5.C1[zPSLB, offset]; P5.C0[zDIS2]};
double => {P5.C1[zPSDLB, offset]; P5.C0[zDIS2]};
partial => {P5.C2[zPSLF, offset, field]; P5.C0[zDIS2]};
ENDCASE;
ENDCASE;
END;
-- Cedar extensions
MoveCounted: PROC [d: Mdirection, init: BOOL, offset: WORD] =
BEGIN
OPEN Mopcodes;
SELECT d FROM
sputlong, swritelong =>
BEGIN
countedPut: ARRAY BOOL OF BYTE = [FALSE: zPSCDLB, TRUE: zPSCIDLB];
P5.C1[countedPut[init], offset];
IF d = swritelong THEN P5.C0[zDIS2];
END;
writelong =>
BEGIN
countedWrite: ARRAY BOOL OF BYTE = [FALSE: zWCDLB, TRUE: zWCIDLB];
IF offset NOT IN BYTE THEN
BEGIN
P5.LoadConstant[offset];
IF LOOPHOLE[offset, INTEGER] > 0 THEN P5.C0[zADC]
ELSE {P5.LoadConstant[177777b]; P5.C0[zDADD]};
offset ← 0;
END;
P5.C1[countedWrite[init], offset];
END;
ENDCASE;
END;
MakeMiscReal: PROC [alpha: BYTE, c: CodeCCIndex] =
BEGIN
Esc[alpha]; P5U.DeleteCell[c];
END;
END.