MODULE PCOARM;
IMPORT SYSTEM, Files, PCLIR, PCM(*Trace, PCARMDecoder *), Diagnostics;
CONST
INTERNALERROR* = 100;
UNIMPLEMENTED* = 101;
NONORTHOGONALITYEXCEPTION* = 102;
ErrBranchOffsetTooBig* = 110;
ErrImmediateTooSmall* = 111;
ErrImmediateTooBig* = 112;
ErrRotateImmTooBig* = 113;
ErrRotateImmOdd* = 114;
ErrInvalidRegister* = 115;
ErrInvalidRegisterSet* = 116;
ErrInvalidMode* = 117;
ErrCaseOffsetTooBig* = 118;
MaxCodeLength* = 256*1024;
InstructionSize* = 4;
EQ* = { };
NE* = { 28 };
CS* = { 29 };
HS* = CS;
CC* = { 29, 28 };
LO* = CC;
MI* = { 30 };
PL* = { 30, 28 };
VS* = { 30, 29 };
VC* = { 30, 29, 28 };
HI* = { 31 };
LS* = { 31, 28 };
GE* = { 31, 29 };
LT* = { 31, 29, 28 };
GT* = { 31, 30 };
LE* = { 31, 30, 28 };
AL* = { 31, 30, 29 };
CondMask* = { 31, 30, 29, 28 };
R0* = 0; R1* = 1; R2* = 2; R3* = 3; R4* = 4; R5* = 5; R6* = 6; R7* = 7; R8* = 8; R9* = 9; R10* = 10; R11* = 11;
FP* = 12;
SP* = 13;
LR* = 14;
PC* = 15;
Registers* = {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
CPSR* = {};
SPSR* = { 22 };
CR0* = 0; CR1* = 1; CR2* = 2; CR3* = 3; CR4* = 4; CR5* = 5; CR6* = 6; CR7* = 7; CR8* = 8; CR9* = 9; CR10* = 10;
CR11* = 11; CR12* = 12; CR13* = 13; CR14* = 14; CR15* = 15;
PSRc* = { 16 };
PSRx* = { 17 };
PSRs* = { 18 };
PSRf* = { 19 };
Mask24* = { 0..23 };
MaskRd* = { 15, 14, 13, 12 };
Sflag* = { 20 };
Bflag* = { 22 };
Lflag* = { 22 };
LSL* = { };
LSR* = { 5 };
ASR* = { 6 };
ROR* = { 6, 5 };
RRX* = ROR;
ShiftMask = { 6, 5 };
Load* = { 20 };
Store* = { };
IdxAdd* = { 23 };
IdxSub* = { };
Offset* = { 24 };
PreIdxd* = { 24, 21 };
PostIdxd* = { };
A1Imm* = { 25 };
A1Reg* = { };
A1ShiftImm* = { };
A1ShiftReg* = { 4 };
A1Immediate0* = {};
A1Immediate1* = { 0 };
A1Immediate2* = { 1 };
A1Immediate4* = { 2 };
A1Immediate8* = { 3 };
A1Immediate31* = { 4, 3, 2, 1, 0 };
A2Mode* = { 26 };
A2Word* = { };
A2Byte* = { 22 };
A2Imm* = { };
A2Reg* = { 25 };
A2WImmOffset* = A2Word + A2Imm + Offset;
A2WRegOffset* = A2Word + A2Reg + Offset;
A2BImmOffset* = A2Byte + A2Imm + Offset;
A2BRegOffset* = A2Byte + A2Reg + Offset;
A2WImmPreIdxd* = A2Word + A2Imm + PreIdxd;
A2WRegPreIdxd* = A2Word + A2Reg + PreIdxd;
A2WImmPostIdxd* = A2Word + A2Imm + PostIdxd;
A2WRegPostIdxd* = A2Word + A2Reg + PostIdxd;
A2BImmPostIdxd* = A2Byte + A2Imm + PostIdxd;
A2BRegPostIdxd* = A2Byte + A2Reg + PostIdxd;
A2AddrModeMask = { 25, 24, 23, 22, 21 };
A3Mode* = { 7, 4 };
A3Halfword* = { 5 };
A3Byte* = { };
A3Imm* = { 22 };
A3Reg* = { };
A3Signed* = { 6 };
A3Unsigned* = { };
A3SHImmOffset* = A3Halfword + A3Imm + A3Signed + Offset;
A3UHImmOffset* = A3Halfword + A3Imm + A3Unsigned + Offset;
A3SHRegOffset* = A3Halfword + A3Reg + A3Signed + Offset;
A3UHRegOffset* = A3Halfword + A3Reg + A3Unsigned + Offset;
A3SBImmOffset* = A3Byte + A3Imm + A3Signed + Offset;
A3UBImmOffset* = A3Byte + A3Imm + A3Unsigned + Offset;
A3SBRegOffset* = A3Byte + A3Reg + A3Signed + Offset;
A3UBRegOffset* = A3Byte + A3Reg + A3Unsigned + Offset;
A3AddrModeMask = { 24, 23, 22, 21, 7, 6, 5, 4 };
A4IA* = { 23 };
A4IB* = { 24, 23 };
A4DA* = { };
A4DB* = { 24 };
A4W* = { 21 };
A4User* = { 22 };
A4LDMMask* = { 20 };
A5W* = { 21 };
A5Offset* = { };
A5PreIdxd* = { 21 };
A5PostIdxd* = { 24, 21 };
A5UnIdxd* = { 24 };
MSRImmediate* = { 25 };
MSRRegister* = { };
opADC* = { 23, 21 };
opADD* = { 23 };
opAND* = { };
opBIC* = { 24, 23, 22 };
opCMN* = { 24, 22, 21, 20 };
opCMP* = { 24, 22, 20 };
opEOR* = { 21 };
opMOV* = { 24, 23, 21 };
opMVN* = { 24, 23, 22, 21 };
opORR* = { 24, 23 };
opRSB* = { 22, 21 };
opRSC* = { 23, 22, 21 };
opSBC* = { 23, 22 };
opSUB* = { 22 };
opTEQ* = { 24, 21, 20 };
opTST* = { 24, 20 };
opMRS* = { 24, 19, 18, 17, 16 };
opMSR* = { 24, 21, 15, 14, 13, 12 };
opMLA* = { 21, 7, 4 };
opMUL* = { 7, 4 };
opSMLAL* = { 23, 22, 21, 7, 4 };
opSMULL* = { 23, 22, 7, 4 };
opUMLAL* = { 23, 21, 7, 4 };
opUMULL* = { 23, 7, 4 };
opB* = { 27, 25 };
LinkBit* = { 24 };
opBL* = opB + LinkBit;
BMask* = { 27, 25, 24 };
opLDM* = { 27, 20 };
opLDR* = { 26, 20 };
opLDRH* = { 20, 7, 4 };
opSTM* = { 27 };
opSTR* = { 26 };
opSTRH* = { 7, 5, 4 };
opSWP* = { 24, 7, 4 };
opSWI* = {27, 26, 25, 24 };
opBKPT* = { 31, 30, 29, 24, 21, 6, 5, 4 };
opCDP* = { 27, 26, 25 };
opLDC* = { 27, 26, 20 };
opMCR* = { 27, 26, 25, 4 };
opMRC* = { 27, 26, 25, 20, 4 };
opSTC* = { 27, 26 };
TYPE
DCDList = POINTER TO RECORD
pc: LONGINT;
next: DCDList;
END;
Callback* = PROCEDURE {DELEGATE} (pc: LONGINT);
VAR
AddrMode: ARRAY 5 OF SET;
f: Files.File;
r: Files.Rider;
start: LONGINT;
code: PCLIR.CodeArray;
codelen: LONGINT;
codeTooLong: BOOLEAN;
sourcepos*: LONGINT;
dcd: BOOLEAN;
codeBarrier: LONGINT;
codeBarrierCallback: Callback;
callbackLocked: BOOLEAN;
PROCEDURE GetCodePos*(): LONGINT;
BEGIN RETURN codelen
END GetCodePos;
PROCEDURE GetInstruction*(pos: LONGINT): SET;
VAR factor, i, l: LONGINT;
BEGIN ASSERT(pos < codelen);
factor := 1;
FOR i := 0 TO 3 DO
l := l + ORD(code[pos+i])*factor;
factor := factor*100H
END;
IF PCM.bigEndian THEN PCM.SwapBytes(l, 0, 4) END;
RETURN SYSTEM.VAL(SET, l)
END GetInstruction;
PROCEDURE GetCode*(VAR codeArr: PCLIR.CodeArray; VAR length, hdrLength, addressFactor: LONGINT);
BEGIN
codeArr := code; length := codelen; hdrLength := codelen DIV 4; addressFactor := 4
END GetCode;
PROCEDURE LSH(v, s: LONGINT): SET;
BEGIN RETURN SYSTEM.VAL(SET, SYSTEM.LSH(v,s))
END LSH;
PROCEDURE CheckReg(register: LONGINT);
BEGIN ASSERT((0 <= register) & (register < 16), ErrInvalidRegister)
END CheckReg;
PROCEDURE CheckImm(imm, max: LONGINT);
BEGIN ASSERT((0 <= imm) & (imm < max), ErrImmediateTooBig)
END CheckImm;
PROCEDURE CheckSet(set, mask: SET);
BEGIN ASSERT(set * (-mask) = {}, ErrInvalidMode)
END CheckSet;
PROCEDURE MakeA3Immediate*(VAR addrMode: SET; offset: LONGINT): SET;
VAR neg: BOOLEAN; address: SET;
BEGIN
neg := offset < 0; offset := ABS(offset);
ASSERT(offset < 100H);
address := SYSTEM.VAL(SET, 100H*(offset DIV 10H) + (offset MOD 10H));
addrMode := addrMode - (A3Imm + IdxAdd + IdxSub);
addrMode := addrMode + A3Imm;
IF ~neg THEN addrMode := addrMode + IdxAdd
ELSE addrMode := addrMode + IdxSub
END;
RETURN address
END MakeA3Immediate;
PROCEDURE MakeA3Register*(register: LONGINT): SET;
BEGIN RETURN SYSTEM.VAL(SET, register)
END MakeA3Register;
PROCEDURE MakeA1Immediate*(immediate: LONGINT; VAR imm: SET): BOOLEAN;
VAR rot: LONGINT;
BEGIN
rot := 0; imm := SYSTEM.VAL(SET, immediate);
WHILE (rot < 32) & (ODD(rot) OR (imm * { 8..31} # {})) DO
imm := SYSTEM.ROT(imm, 1); INC(rot)
END;
IF (rot < 32) THEN
imm := imm + SYSTEM.VAL(SET, SYSTEM.LSH(rot DIV 2, 8));
RETURN TRUE
ELSE
imm := {};
RETURN FALSE
END
END MakeA1Immediate;
PROCEDURE MakeA1Register*(reg: LONGINT): SET;
BEGIN CheckReg(reg);
RETURN SYSTEM.VAL(SET, reg)
END MakeA1Register;
PROCEDURE MakeA1RegSHIFTReg*(reg, shiftreg: LONGINT; mode: SET): SET;
BEGIN CheckReg(reg); CheckReg(shiftreg); CheckSet(mode, ShiftMask);
RETURN LSH(shiftreg, 8) + mode + A1ShiftReg + SYSTEM.VAL(SET, reg)
END MakeA1RegSHIFTReg;
PROCEDURE MakeA1RegSHIFTImm*(reg, imm: LONGINT; mode: SET): SET;
BEGIN CheckReg(reg); CheckImm(imm, 20H); CheckSet(mode, ShiftMask);
RETURN LSH(imm, 7) + mode + A1ShiftImm + SYSTEM.VAL(SET, reg)
END MakeA1RegSHIFTImm;
PROCEDURE ADC*(cond, addrMode: SET; rD, rN: LONGINT; shifterOperand, S: SET);
BEGIN Code(cond + opADC + addrMode + LSH(rN, 16) + LSH(rD, 12) + shifterOperand + S)
END ADC;
PROCEDURE ADD*(cond, addrMode: SET; rD, rN: LONGINT; shifterOperand, S: SET);
BEGIN Code(cond + opADD + addrMode + LSH(rN, 16) + LSH(rD, 12) + shifterOperand + S)
END ADD;
PROCEDURE AND*(cond, addrMode: SET; rD, rN: LONGINT; shifterOperand, S: SET);
BEGIN CheckSet(shifterOperand, {0..11});
Code(cond + opAND + addrMode + LSH(rN, 16) + LSH(rD, 12) + shifterOperand + S)
END AND;
PROCEDURE BIC*(cond, addrMode: SET; rD, rN: LONGINT; shifterOperand, S: SET);
BEGIN Code(cond + opBIC + addrMode + LSH(rN, 16) + LSH(rD, 12) + shifterOperand + S)
END BIC;
PROCEDURE CMN*(cond, addrMode: SET; rN: LONGINT; shifterOperand: SET);
BEGIN Code(cond + opCMN + addrMode + LSH(rN, 16) + shifterOperand)
END CMN;
PROCEDURE CMP*(cond, addrMode: SET; rN: LONGINT; shifterOperand: SET);
BEGIN Code(cond + opCMP + addrMode + LSH(rN, 16) + shifterOperand)
END CMP;
PROCEDURE EOR*(cond, addrMode: SET; rD, rN: LONGINT; shifterOperand, S: SET);
BEGIN Code(cond + opEOR + addrMode + LSH(rN, 16) + LSH(rD, 12) + shifterOperand + S)
END EOR;
PROCEDURE MOV*(cond, addrMode: SET; rD: LONGINT; shifterOperand, S: SET);
BEGIN Code(cond + opMOV + addrMode + LSH(rD, 12) + shifterOperand + S)
END MOV;
PROCEDURE MVN*(cond, addrMode: SET; rD: LONGINT; shifterOperand, S: SET);
BEGIN Code(cond + opMVN + addrMode + LSH(rD, 12) + shifterOperand + S)
END MVN;
PROCEDURE ORR*(cond, addrMode: SET; rD, rN: LONGINT; shifterOperand, S: SET);
BEGIN Code(cond + opORR + addrMode + LSH(rN, 16) + LSH(rD, 12) + shifterOperand + S)
END ORR;
PROCEDURE RSB*(cond, addrMode: SET; rD, rN: LONGINT; shifterOperand, S: SET);
BEGIN Code(cond + opRSB + addrMode + LSH(rN, 16) + LSH(rD, 12) + shifterOperand + S)
END RSB;
PROCEDURE RSC*(cond, addrMode: SET; rD, rN: LONGINT; shifterOperand, S: SET);
BEGIN Code(cond + opRSC + addrMode + LSH(rN, 16) + LSH(rD, 12) + shifterOperand + S)
END RSC;
PROCEDURE SBC*(cond, addrMode: SET; rD, rN: LONGINT; shifterOperand, S: SET);
BEGIN Code(cond + opSBC + addrMode + LSH(rN, 16) + LSH(rD, 12) + shifterOperand + S)
END SBC;
PROCEDURE SUB*(cond, addrMode: SET; rD, rN: LONGINT; shifterOperand, S: SET);
BEGIN Code(cond + opSUB + addrMode + LSH(rN, 16) + LSH(rD, 12) + shifterOperand + S)
END SUB;
PROCEDURE TEQ*(cond, addrMode: SET; rN: LONGINT; shifterOperand: SET);
BEGIN Code(cond + opTEQ + addrMode + LSH(rN, 16) + shifterOperand)
END TEQ;
PROCEDURE TST*(cond, addrMode: SET; rN: LONGINT; shifterOperand: SET);
BEGIN Code(cond + opTST + addrMode + LSH(rN, 16) + shifterOperand)
END TST;
PROCEDURE MLA*(cond: SET; rD, rM, rS, rN: LONGINT; S: SET);
BEGIN ASSERT(rD # rM, NONORTHOGONALITYEXCEPTION);
Code(cond + opMLA + LSH(rD, 16) + LSH(rN, 12) + LSH(rS, 8) + LSH(rM, 0) + S)
END MLA;
PROCEDURE MUL*(cond: SET; rD, rM, rS: LONGINT; S: SET);
BEGIN ASSERT(rD # rM, NONORTHOGONALITYEXCEPTION);
Code(cond + opMUL + LSH(rD, 16) + LSH(rS, 8) + LSH(rM, 0) + S)
END MUL;
PROCEDURE SMLAL*(cond: SET; rDHi, rDLo, rM, rS: LONGINT; S: SET);
BEGIN ASSERT((rDHi # rDLo) & (rDHi # rM) & (rDLo # rM), NONORTHOGONALITYEXCEPTION);
Code(cond + opSMLAL + LSH(rDHi, 16) + LSH(rDLo, 12) + LSH(rS, 8) + LSH(rM, 0) + S)
END SMLAL;
PROCEDURE SMULL*(cond: SET; rDHi, rDLo, rM, rS: LONGINT; S: SET);
BEGIN ASSERT((rDHi # rDLo) & (rDHi # rM) & (rDLo # rM), NONORTHOGONALITYEXCEPTION);
Code(cond + opSMULL + LSH(rDHi, 16) + LSH(rDLo, 12) + LSH(rS, 8) + LSH(rM, 0) + S)
END SMULL;
PROCEDURE UMLAL*(cond: SET; rDLo, rDHi, rM, rS: LONGINT; S: SET);
BEGIN ASSERT((rDHi # rDLo) & (rDHi # rM) & (rDLo # rM), NONORTHOGONALITYEXCEPTION);
Code(cond + opUMLAL + LSH(rDHi, 16) + LSH(rDLo, 12) + LSH(rS, 8) + LSH(rM, 0) + S)
END UMLAL;
PROCEDURE UMULL*(cond: SET; rDLo, rDHi, rM, rS: LONGINT; S: SET);
BEGIN ASSERT((rDHi # rDLo) & (rDHi # rM) & (rDLo # rM), NONORTHOGONALITYEXCEPTION);
Code(cond + opUMULL + LSH(rDHi, 16) + LSH(rDLo, 12) + LSH(rS, 8) + LSH(rM, 0) + S)
END UMULL;
PROCEDURE B*(cond: SET; address: LONGINT);
BEGIN ASSERT((ABS(address) < 1000000H), ErrBranchOffsetTooBig);
ASSERT(cond # {31, 30, 29, 28});
Code(cond + opB + Mask24*SYSTEM.VAL(SET, address))
END B;
PROCEDURE BL*(cond: SET; address: LONGINT);
BEGIN Code(cond + opBL + Mask24*SYSTEM.VAL(SET, address))
END BL;
PROCEDURE MakeA2Immediate*(VAR addrMode: SET; offset: LONGINT): SET;
VAR neg: BOOLEAN; address: SET;
BEGIN
neg := offset < 0; offset := ABS(offset);
ASSERT(offset < 1000H);
address := SYSTEM.VAL(SET, offset);
addrMode := addrMode - (A2Imm + IdxAdd + IdxSub);
addrMode := addrMode + A2Imm;
IF ~neg THEN addrMode := addrMode + IdxAdd
ELSE addrMode := addrMode + IdxSub
END;
RETURN address
END MakeA2Immediate;
PROCEDURE MakeA2Register*(register: LONGINT): SET;
BEGIN RETURN SYSTEM.VAL(SET, register)
END MakeA2Register;
PROCEDURE MakeA2ScaledRegister*(reg: LONGINT; mode: SET; shift: LONGINT): SET;
BEGIN CheckReg(reg); CheckImm(shift, 20H); CheckSet(mode, ShiftMask);
RETURN LSH(shift, 7) + mode + LSH(reg, 0)
END MakeA2ScaledRegister;
PROCEDURE LDM*(cond, addrMode: SET; rD: LONGINT; registers, W: SET);
BEGIN Code(cond + opLDM + addrMode + LSH(rD, 16) + registers + W)
END LDM;
PROCEDURE LDR*(cond, addrMode: SET; rD, rAdr: LONGINT; address: SET);
BEGIN Code(cond + opLDR + addrMode + LSH(rAdr, 16) + LSH(rD, 12) + address)
END LDR;
PROCEDURE LDRH*(cond, addrMode: SET; rD, rAdr: LONGINT; address: SET);
BEGIN Code(cond + opLDRH + addrMode + LSH(rAdr, 16) + LSH(rD, 12) + address)
END LDRH;
PROCEDURE STM*(cond, addrMode: SET; rD: LONGINT; registers, W: SET);
BEGIN Code(cond + opSTM + addrMode + LSH(rD, 16) + registers + W)
END STM;
PROCEDURE STR*(cond, addrMode: SET; rAdr, rS: LONGINT; address: SET);
BEGIN Code(cond + opSTR + addrMode + LSH(rAdr, 16) + LSH(rS, 12) + address)
END STR;
PROCEDURE STRH*(cond, addrMode: SET; rAdr, rS: LONGINT; address: SET);
BEGIN ASSERT(address*{6,5}={}, NONORTHOGONALITYEXCEPTION);
Code(cond + opSTRH + addrMode + LSH(rAdr, 16) + LSH(rS, 12) + address)
END STRH;
PROCEDURE SWI*(cond: SET; code: LONGINT);
BEGIN CheckImm(code, 1000000H);
Code(cond + opSWI + Mask24*LSH(code, 0))
END SWI;
PROCEDURE DCD*(value: LONGINT);
BEGIN dcd := TRUE; Code(SYSTEM.VAL(SET, value))
END DCD;
PROCEDURE Lock*;
BEGIN callbackLocked := TRUE
END Lock;
PROCEDURE Unlock*;
BEGIN callbackLocked := FALSE; CheckCallback
END Unlock;
PROCEDURE SetConstantPoolBarrier*(pc: LONGINT);
BEGIN
ASSERT((codelen < pc) & (pc < codelen + 1000H) OR (pc = -1), INTERNALERROR);
codeBarrier := pc
END SetConstantPoolBarrier;
PROCEDURE SetConstantPoolBarrierCallback*(callback: Callback);
BEGIN
codeBarrierCallback := callback
END SetConstantPoolBarrierCallback;
PROCEDURE CheckCallback;
BEGIN
IF ~callbackLocked & (codeBarrier # -1) & (codeBarrierCallback # NIL) & (codelen >= codeBarrier) THEN
Lock;
codeBarrierCallback(codelen);
Unlock
END
END CheckCallback;
PROCEDURE ExtractRegister(code: SET; pos: LONGINT): LONGINT;
BEGIN RETURN SYSTEM.LSH(SYSTEM.VAL(LONGINT, code), -pos) MOD 10H
END ExtractRegister;
PROCEDURE FixLoad*(pc: LONGINT; address: LONGINT);
VAR b, addrMode, addr: SET; currPos: LONGINT;
BEGIN
b := GetInstruction(pc);
currPos := codelen;
codelen := pc;
IF (b * opLDR = opLDR) THEN
addrMode := b * A2AddrModeMask;
addr := MakeA2Immediate(addrMode, address);
LDR(b*CondMask, addrMode, ExtractRegister(b, 12), ExtractRegister(b, 16), addr)
ELSIF (b * opLDRH = opLDRH) THEN
addrMode := b * A3AddrModeMask;
addr := MakeA3Immediate(addrMode, address);
LDRH(b*CondMask, addrMode, ExtractRegister(b, 12), ExtractRegister(b, 16), addr)
ELSE HALT(INTERNALERROR)
END;
codelen := currPos;
END FixLoad;
PROCEDURE FixJump*(pc: LONGINT; address: LONGINT);
VAR b: SET; currPos: LONGINT;
BEGIN
b := GetInstruction(pc);
ASSERT(b * opB = opB);
currPos := codelen;
codelen := pc;
B(b*CondMask, address);
codelen := currPos
END FixJump;
PROCEDURE FixCall*(pc: LONGINT; address: LONGINT): LONGINT;
VAR b: SET; currPos: LONGINT;
BEGIN
b := GetInstruction(pc);
ASSERT(b * opBL = opBL);
currPos := codelen;
codelen := pc;
BL(b*CondMask, address);
codelen := currPos;
RETURN SYSTEM.VAL(LONGINT, b*Mask24)
END FixCall;
PROCEDURE FixCaseTable*(pc: LONGINT; address: LONGINT);
VAR fixup, currPos: LONGINT;
BEGIN
ASSERT((address >= 0) & (address < 10000H), ErrCaseOffsetTooBig);
fixup := SYSTEM.VAL(LONGINT, GetInstruction(pc) * { 16..31 });
currPos := codelen;
codelen := pc;
DCD(fixup + address);
codelen := currPos
END FixCaseTable;
PROCEDURE Init*(codeFN: ARRAY OF CHAR);
BEGIN
f := Files.New(codeFN);
Files.Register(f);
f.Set(r, 0);
start := 0;
IF (code = NIL) THEN NEW(code, MaxCodeLength) END;
codelen := 0; codeTooLong := FALSE;
END Init;
PROCEDURE Code(opcode: SET);
TYPE Bytes= ARRAY 4 OF CHAR;
VAR b: Bytes; i: INTEGER;
BEGIN
ASSERT(codelen MOD 4 = 0);
IF (codelen <= MaxCodeLength-4) THEN
b := SYSTEM.VAL(Bytes, opcode);
IF PCM.bigEndian THEN PCM.SwapBytes(b, 0, 4) END;
FOR i := 0 TO 3 DO
code[codelen] := b[i]; INC(codelen)
END;
CheckCallback
ELSE
IF ~codeTooLong THEN
codeTooLong := TRUE;
PCM.Error(244, sourcepos, "Code too long.")
END
END
END Code;
PROCEDURE PutChar*(c: CHAR);
BEGIN
code[codelen] := c; INC(codelen)
END PutChar;
PROCEDURE Close*;
VAR b: POINTER TO ARRAY OF CHAR;
BEGIN
IF (codelen > MaxCodeLength) THEN
PCM.Error(244, Diagnostics.Invalid, "Code too long.");
ELSIF (codelen-start > 0) THEN
NEW(b, codelen-start);
SYSTEM.MOVE(SYSTEM.ADR(code[start]), SYSTEM.ADR(b[0]), codelen-start);
f.WriteBytes(r, b^, 0, codelen-start);
Files.Register(f);
ELSIF (codelen - start < 0) THEN HALT(MAX(INTEGER))
END;
f := NIL;
END Close;
PROCEDURE BoP*(name: ARRAY OF CHAR);
END BoP;
PROCEDURE EoP*;
END EoP;
PROCEDURE Dump*;
END Dump;
BEGIN
AddrMode[0] := - {};
AddrMode[1] := - {};
AddrMode[2] := - {};
AddrMode[3] := { 24, 23 };
AddrMode[4] := - {};
SetConstantPoolBarrier(-1)
END PCOARM.