123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766 |
- (* Paco, Copyright 2000, Patrik Reali, ETH Zurich *)
- MODULE PCOARM; (** be **)
- (** Code Generator for ARM. Not concurrent ! *)
- IMPORT SYSTEM, Files, PCLIR, PCM(*Trace, PCARMDecoder *), Diagnostics;
- CONST
- (*Trace = FALSE; *)
- 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; (* size of one instruction, in bytes *)
- (** Conditions - instruction is executed if CPSR satisfies the condition *)
- EQ* = { }; (** equal *)
- NE* = { 28 }; (** not equal *)
- CS* = { 29 }; (** carry set *)
- HS* = CS; (** unsigned higher or same *)
- CC* = { 29, 28 }; (** carry clear *)
- LO* = CC; (** unsigned lower *)
- MI* = { 30 }; (** minus/negative *)
- PL* = { 30, 28 }; (** plus/positive or zero *)
- VS* = { 30, 29 }; (** overflow *)
- VC* = { 30, 29, 28 }; (** no overflow *)
- HI* = { 31 }; (** unsigned higher *)
- LS* = { 31, 28 }; (** unsigned lower or same *)
- GE* = { 31, 29 }; (** signed greater or equal *)
- LT* = { 31, 29, 28 }; (** signed less than *)
- GT* = { 31, 30 }; (** signed greater than *)
- LE* = { 31, 30, 28 }; (** signed less than or equal *)
- AL* = { 31, 30, 29 }; (** always *)
- CondMask* = { 31, 30, 29, 28 };
- (** Registers *)
- 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; (** frame pointer *)
- SP* = 13; (** stack pointer *)
- LR* = 14; (** return address *)
- PC* = 15; (** program counter *)
- Registers* = {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; (** valid registers *)
- CPSR* = {}; (** current program status register *)
- SPSR* = { 22 }; (** saved program status register *)
- 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; (** coprocessor registers *)
- (** PSR flags *)
- PSRc* = { 16 }; (** control fields *)
- PSRx* = { 17 }; (** extension fields *)
- PSRs* = { 18 }; (** status fields *)
- PSRf* = { 19 }; (** flags fields *)
- (** useful Bit-Masks *)
- Mask24* = { 0..23 };
- MaskRd* = { 15, 14, 13, 12 };
- (** Common modifiers *)
- Sflag* = { 20 }; (** if set, the condition codes are updated *)
- Bflag* = { 22 }; (** distinguishes between a SWP and a SWPB instruction *)
- Lflag* = { 22 }; (** LDC/STC: specifies long load/store *)
- Lsl* = { }; (** logical shift left *)
- LSR* = { 5 }; (** logical shift right *)
- Asr* = { 6 }; (** arithmetic shift right *)
- Ror* = { 6, 5 }; (** rotate right *)
- RRX* = Ror; (** rotate right with extend *)
- ShiftMask = { 6, 5 };
- Load* = { 20 }; (** load *)
- Store* = { }; (** store *)
- IdxAdd* = { 23 }; (** load/store: the index is added to the base register *)
- IdxSub* = { }; (** load/store: the index is subtracted from the base register *)
- Offset* = { 24 }; (** load/store: offset addressing *)
- PreIdxd* = { 24, 21 }; (** load/store: pre-indexed addressing *)
- PostIdxd* = { }; (** laod/store: post-indexed addressing *)
- (** Addressing Mode 1 - Data-processing operands *)
- A1Imm* = { 25 }; (** shifterOperand contains an 8-bit immediate value plus a 4-bit rotate immediate value *)
- A1Reg* = { }; (** shifterOperand contains a register *)
- A1ShiftImm* = { }; (** shifterOperand contains a register and is shifted by an immeditae *)
- A1ShiftReg* = { 4 }; (** shifterOperand contains a register and is shifted by a register *)
- A1Immediate0* = {}; (** prepared immediate values: 0, 1, 2, 4 and 8 *)
- A1Immediate1* = { 0 };
- A1Immediate2* = { 1 };
- A1Immediate4* = { 2 };
- A1Immediate8* = { 3 };
- A1Immediate31* = { 4, 3, 2, 1, 0 };
- (** Addressing Mode 2 - Load and Store Words or Unsigned Byte *)
- A2Mode* = { 26 }; (** load/store word/unsigned byte *)
- A2Word* = { }; (** load/store word *)
- A2Byte* = { 22 }; (** load/store byte *)
- A2Imm* = { }; (** address contains an immediate value *)
- A2Reg* = { 25 }; (** address contains a register *)
- 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 };
- (** Addressing Mode 3 - Miscellaneous Loads and Stores *)
- A3Mode* = { 7, 4 }; (** micellaneous load/store *)
- A3Halfword* = { 5 }; (** load/store halfword *)
- A3Byte* = { }; (** load/store byte *)
- A3Imm* = { 22 }; (** address contains an immediate value *)
- A3Reg* = { }; (** address contains a register *)
- A3Signed* = { 6 }; (** signed halfword/byte *)
- A3Unsigned* = { }; (** unsigned halfword/byte *)
- 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 };
- (** Addressing Mode 4 - Load and Store Multiple *)
- A4IA* = { 23 }; (** increment after *)
- A4IB* = { 24, 23 }; (** increment before *)
- A4DA* = { }; (** decrement after *)
- A4DB* = { 24 }; (** decrement before *)
- A4W* = { 21 }; (** update address register *)
- A4User* = { 22 }; (** load/store user mode registers *)
- A4LDMMask* = { 20 }; (** if this bit is set, it's a LDM (ifffff it's a addressing mode 4 instruction, Hobbes, idiot) *)
- (** Addressing Mode 5 - Load and Store Coprocessor *)
- A5W* = { 21 }; (** update base register *)
- A5Offset* = { }; (** offset addressing *)
- A5PreIdxd* = { 21 }; (** pre-indexed addressing *)
- A5PostIdxd* = { 24, 21 }; (** post-indexed addressing *)
- A5UnIdxd* = { 24 }; (** unindexed addressing *)
- (** Miscellaneous *)
- MSRImmediate* = { 25 }; (** the operand is a 8bit immediate *)
- MSRRegister* = { }; (** the operand is a register *)
- (** Instruction Opcodes *)
- (* data-processing instructions *)
- 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 };
- (* multiply instructions *)
- 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 };
- (* branch instructions *)
- opB* = { 27, 25 };
- LinkBit* = { 24 };
- opBL* = opB + LinkBit;
- BMask* = { 27, 25, 24 };
- (* load/store instructions *)
- opLDM* = { 27, 20 };
- opLDR* = { 26, 20 };
- opLDRH* = { 20, 7, 4 };
- opSTM* = { 27 };
- opSTR* = { 26 };
- opSTRH* = { 7, 5, 4 };
- (* semaphore instructions *)
- opSWP* = { 24, 7, 4 };
- (* exception-generating instructions *)
- opSWI* = {27, 26, 25, 24 }; (* software interrupt *)
- opBKPT* = { 31, 30, 29, 24, 21, 6, 5, 4 };
- (* coprocessor instructions *)
- 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
- (*Trace W: Texts.Writer;
- t: Texts.Text; *)
- AddrMode: ARRAY 5 OF SET; (* contains bitmasks for validity checks *)
- 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, LSH(v,s))
- END Lsh;
- (*
- PROCEDURE CheckCondition(c: SET);
- BEGIN ASSERT(c - {31, 30, 29, 28} = {})
- END CheckCondition;
- PROCEDURE CheckAddressingMode(mode: LONGINT; am: SET);
- BEGIN ASSERT(am - AddrMode[mode-1] = {})
- END CheckAddressingMode;
- *)
- PROCEDURE CheckReg(register: LONGINT);
- BEGIN ASSERT((0 <= register) & (register < 16), ErrInvalidRegister)
- END CheckReg;
- (*
- PROCEDURE CheckRegisterSet(registers: SET);
- BEGIN ASSERT (registers - Registers = {}, ErrInvalidRegisterSet)
- END CheckRegisterSet;
- *)
- PROCEDURE CheckImm(imm, max: LONGINT);
- BEGIN ASSERT((0 <= imm) & (imm < max), ErrImmediateTooBig)
- END CheckImm;
- (*
- PROCEDURE CheckSignedImm(imm, min, max: LONGINT);
- BEGIN ASSERT((min < imm), ErrImmediateTooSmall);
- ASSERT((imm < max), ErrImmediateTooBig)
- END CheckSignedImm;
- *)
- PROCEDURE CheckSet(set, mask: SET);
- BEGIN ASSERT(set * (-mask) = {}, ErrInvalidMode)
- END CheckSet;
- (** Addressing Mode 3 Helpers *)
- PROCEDURE MakeA3Immediate*(VAR addrMode: SET; offset: LONGINT): SET;
- VAR neg: BOOLEAN; address: SET;
- BEGIN
- neg := offset < 0; offset := ABS(offset);
- ASSERT(offset < 100H);
- (* address[11:8] = offset[7:4], address[3:0] = offset[3:0] *)
- 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;
- (**----- Data Processing Instructions (Addressing Mode 1) -------*)
- 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 := ROT(imm, 1); INC(rot)
- END;
- IF (rot < 32) THEN
- imm := imm + SYSTEM.VAL(SET, 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;
- (** ADC - add with carry (rD <- rN + shifterOperand + carry) *)
- 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;
- (** ADD - add (rD <- rN + shifterOperand) *)
- 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;
- (** AND - bitwise and (rD <- rN AND shifterOperand) *)
- 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;
- (** BIC - clears bits (rD <- rN AND NOT shifterOperand) *)
- 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;
- (** CMN - compare negative (CC updated based on rN + shifterOperand) *)
- PROCEDURE CMN*(cond, addrMode: SET; rN: LONGINT; shifterOperand: SET);
- BEGIN Code(cond + opCMN + addrMode + Lsh(rN, 16) + shifterOperand)
- END CMN;
- (** CMP - compare (CC updateed based on rN - shifterOperand) *)
- PROCEDURE CMP*(cond, addrMode: SET; rN: LONGINT; shifterOperand: SET);
- BEGIN Code(cond + opCMP + addrMode + Lsh(rN, 16) + shifterOperand)
- END CMP;
- (** EOR - XOr (rD <- rN XOR shifterOperand) *)
- 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;
- (** MOV - move (rD <- shifterOperand) *)
- PROCEDURE MOV*(cond, addrMode: SET; rD: LONGINT; shifterOperand, S: SET);
- BEGIN Code(cond + opMOV + addrMode + Lsh(rD, 12) + shifterOperand + S)
- END MOV;
- (** MVN - move negative (rD <- NOT shifterOperand) *)
- PROCEDURE MVN*(cond, addrMode: SET; rD: LONGINT; shifterOperand, S: SET);
- BEGIN Code(cond + opMVN + addrMode + Lsh(rD, 12) + shifterOperand + S)
- END MVN;
- (** ORR - bitwise OR (rD <- rN OR shifterOperand) *)
- 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;
- (** RSB - reverse subtract (rD <- shifterOperand - rN) *)
- 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;
- (** RSC - reverse subtract with carry (rD <- shifterOperand - rN - NOT(carry)) *)
- 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;
- (** SBC - subtract with carry (rD <- rN - shifterOperand - NOT(carry))*)
- 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;
- (** SUB - subtract (rD <- rN - shifterOperand) *)
- 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;
- (** TEQ - test equivalence (CC updated based on rN XOR shifterOperand) *)
- PROCEDURE TEQ*(cond, addrMode: SET; rN: LONGINT; shifterOperand: SET);
- BEGIN Code(cond + opTEQ + addrMode + Lsh(rN, 16) + shifterOperand)
- END TEQ;
- (** TST - test (CC updated based on rN AND shifterOperand) *)
- PROCEDURE TST*(cond, addrMode: SET; rN: LONGINT; shifterOperand: SET);
- BEGIN Code(cond + opTST + addrMode + Lsh(rN, 16) + shifterOperand)
- END TST;
- (**----------------------- Multiply Instructions -----------------------*)
- (** MLA - multiply accumulate (rD <- (rM * rS) + rN) *)
- 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;
- (** MUL - multiply (rD <- rM * rS) *)
- 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;
- (** SMLAL - signed multiply accumulate long (rDLo <- (rA * rB)[31:0] + rDLo, rDHi <- (rA * rB)[63:32] + rDHi + carry) *)
- 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;
- (** SMULL - signed multiply long (rDLo <- (rM * rS)[31:0], rDHi <- (rM * rS)[63:32]) *)
- 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;
- (** UMLAL - unsigned multiply accumulate long (rDLo <- (rM*rS)[31:0] + rDLo, rDHi <- (rM*rS)[63:32] + rDHi + carry) *)
- 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;
- (** UMULL - unsigned multply long (rDLo <- (rM*rS)[31:0], rDHi <- (rM*rS)[63:32]) *)
- 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;
- (**------------------------- Branch Instructions -------------------------*)
- (** B - branch to address. (PC <- PC + extS(address << 2)). Hint: PC is 2 instructions ahead *)
- 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;
- (** BL - branch to address. (LR <- address of instr. after branch instruction, PC <- PC + extS(address << 2))
- Hint: - PC is 2 instructions ahead *)
- PROCEDURE BL*(cond: SET; address: LONGINT);
- BEGIN Code(cond + opBL + Mask24*SYSTEM.VAL(SET, address))
- END BL;
- (**------------ Load/Store Instructions (Addressing Modes 2, 3 & 4) --------------*)
- 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;
- (** LDM - uses Addressing Mode 4 *)
- PROCEDURE LDM*(cond, addrMode: SET; rD: LONGINT; registers, W: SET);
- BEGIN Code(cond + opLDM + addrMode + Lsh(rD, 16) + registers + W)
- END LDM;
- (** LDR - uses Addressing Mode 2 *)
- PROCEDURE LDR*(cond, addrMode: SET; rD, rAdr: LONGINT; address: SET);
- BEGIN Code(cond + opLDR + addrMode + Lsh(rAdr, 16) + Lsh(rD, 12) + address)
- END LDR;
- (** LDRH - uses Addressing Mode 3 *)
- PROCEDURE LDRH*(cond, addrMode: SET; rD, rAdr: LONGINT; address: SET);
- BEGIN Code(cond + opLDRH + addrMode + Lsh(rAdr, 16) + Lsh(rD, 12) + address)
- END LDRH;
- (** STM - uses Addressing Mode 4 *)
- PROCEDURE STM*(cond, addrMode: SET; rD: LONGINT; registers, W: SET);
- BEGIN Code(cond + opSTM + addrMode + Lsh(rD, 16) + registers + W)
- END STM;
- (** STR - uses Addressing Mode 2 *)
- PROCEDURE STR*(cond, addrMode: SET; rAdr, rS: LONGINT; address: SET);
- BEGIN Code(cond + opSTR + addrMode + Lsh(rAdr, 16) + Lsh(rS, 12) + address)
- END STR;
- (** STRH - uses Addressing Mode 3 *)
- 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;
- (**--------------------------- Miscellaneous -----------------------------*)
- (** SWI - software interrupt *)
- PROCEDURE SWI*(cond: SET; code: LONGINT);
- BEGIN CheckImm(code, 1000000H);
- Code(cond + opSWI + Mask24*Lsh(code, 0))
- END SWI;
- (** DCD - puts a 32bit value into the code *)
- PROCEDURE DCD*(value: LONGINT);
- BEGIN dcd := TRUE; Code(SYSTEM.VAL(SET, value))
- END DCD;
- (**--------------------------- Fixup Handling -------------------------------*)
- (* Lock - does not allow automatic flushing of the constant pool. Not reentrant. *)
- PROCEDURE Lock*;
- BEGIN callbackLocked := TRUE
- END Lock;
- (* Unlock - allows automatic flushing of the constant pool. Not reentrant *)
- PROCEDURE Unlock*;
- BEGIN callbackLocked := FALSE; CheckCallback
- END Unlock;
- (* SetConstantPoolBarrier - *)
- PROCEDURE SetConstantPoolBarrier*(pc: LONGINT);
- BEGIN
- ASSERT((codelen < pc) & (pc < codelen + 1000H) OR (pc = -1), INTERNALERROR);
- codeBarrier := pc
- END SetConstantPoolBarrier;
- (* SetConstantPoolBarrierCallback - *)
- PROCEDURE SetConstantPoolBarrierCallback*(callback: Callback);
- BEGIN
- codeBarrierCallback := callback
- END SetConstantPoolBarrierCallback;
- (* CheckCallback - calls the callback handler if necessary *)
- PROCEDURE CheckCallback;
- BEGIN
- IF ~callbackLocked & (codeBarrier # -1) & (codeBarrierCallback # NIL) & (codelen >= codeBarrier) THEN
- Lock; (* lock or we'll get a stack overflow due to endless recursion *)
- codeBarrierCallback(codelen);
- Unlock
- END
- END CheckCallback;
- PROCEDURE ExtractRegister(code: SET; pos: LONGINT): LONGINT;
- BEGIN RETURN 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;
- (**--------------------------- Miscellaneous -------------------------------*)
- 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;
- (*Trace IF Trace THEN NEW(t); Texts.Open(t, ""); PCARMDecoder.Init END *)
- END Init;
- PROCEDURE Code(opcode: SET);
- TYPE Bytes= ARRAY 4 OF CHAR;
- VAR b: Bytes; i: INTEGER;
- BEGIN
- ASSERT(codelen MOD 4 = 0); (* in case PutChar did not write 4x characters *)
- (*Trace IF Trace & dcd THEN
- dcd := FALSE;
- NEW(d); d.pc := codelen;
- IF (dcdLast = NIL) THEN dcdList := d; dcdLast := d
- ELSE dcdLast.next := d; dcdLast := d
- END
- END; *)
- 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) (* little endian *)
- END;
- CheckCallback
- ELSE
- IF ~codeTooLong THEN (* report only once *)
- 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 (* code too long *)
- PCM.Error(244, Diagnostics.Invalid, "Code too long.");
- ELSIF (codelen-start > 0) THEN
- NEW(b, codelen-start);
- SYSTEM.MOVE(ADDRESSOF(code[start]), ADDRESSOF(b[0]), codelen-start);
- f.WriteBytes(r, b^, 0, codelen-start);
- Files.Register(f);
- ELSIF (codelen - start < 0) THEN HALT(MAX(INTEGER)) (* show stack*)
- END;
- f := NIL;
- END Close;
- PROCEDURE BoP*(name: ARRAY OF CHAR);
- (* VAR dcd: DCDList; i: LONGINT; b: ARRAY InstructionSize OF CHAR;
- BEGIN
- Trace IF Trace THEN
- IF (start # codelen) THEN
- dcd := dcdList;
- WHILE (start < codelen) DO
- FOR i := 0 TO InstructionSize-1 DO b[i] := code[start+i] END;
- PCARMDecoder.Decode(start, SYSTEM.VAL(LONGINT, b), (dcd # NIL) & (dcd.pc = start));
- IF (dcd # NIL) & (dcd.pc = start) THEN dcd := dcd.next END;
- INC(start, InstructionSize)
- END;
- ASSERT(start = codelen);
- dcdList := NIL; dcdLast := NIL
- END;
- IF (name = "") THEN COPY("Module Body", name) END;
- Texts.WriteLn(PCARMDecoder.W);
- Texts.WriteString(PCARMDecoder.W, name); Texts.WriteLn(PCARMDecoder.W);
- Texts.Append(t, PCARMDecoder.W.buf)
- END; *)
- END BoP;
- PROCEDURE EoP*;
- END EoP;
- PROCEDURE Dump*;
- (* VAR dcd: DCDList; i: LONGINT; b: ARRAY InstructionSize OF CHAR;
- BEGIN
- Trace IF Trace THEN
- IF (start # codelen) THEN
- dcd := dcdList;
- WHILE (start < codelen) DO
- FOR i := 0 TO InstructionSize-1 DO b[i] := code[start+i] END;
- PCARMDecoder.Decode(start, SYSTEM.VAL(LONGINT, b), (dcd # NIL) & (dcd.pc = start));
- IF (dcd # NIL) & (dcd.pc = start) THEN dcd := dcd.next END;
- INC(start, InstructionSize)
- END;
- ASSERT(start = codelen);
- dcdList := NIL; dcdLast := NIL;
- Texts.WriteLn(PCARMDecoder.W);
- Texts.WriteString(PCARMDecoder.W, "TRAP"); Texts.WriteLn(PCARMDecoder.W);
- Texts.Append(t, PCARMDecoder.W.buf)
- END;
- Oberon.OpenText("ARM Code", t, 600, 400)
- END *)
- END Dump;
- BEGIN
- AddrMode[0] := { 0 .. 31 };
- AddrMode[1] := { 0 .. 31 };
- AddrMode[2] := { 0 .. 31 };
- AddrMode[3] := { 24, 23 };
- AddrMode[4] := { 0 .. 31 };
- SetConstantPoolBarrier(-1)
- END PCOARM.
|