(* BSD 2-Clause License Copyright (c) 2019-2021, Anton Krotov All rights reserved. *) MODULE THUMB; IMPORT PROG, LISTS, CHL := CHUNKLISTS, BIN, REG, IL, C := CONSOLE, UTILS, WR := WRITER, HEX, ERRORS, TARGETS; CONST R0 = 0; R1 = 1; R2 = 2; R3 = 3; R4 = 4; SP = 13; LR = 14; PC = 15; ACC = R0; je = 0; jne = 1; jnb = 2; jb = 3; jge = 10; jl = 11; jg = 12; jle = 13; inf = 7F800000H; minROM* = 16; maxROM* = 65536; minRAM* = 4; maxRAM* = 65536; maxIVT* = 1023; _THUMB2 = 0; _IT = 1; _SDIV = 2; _CBXZ = 3; CortexM0 = {}; CortexM1 = {}; CortexM3 = {_THUMB2, _IT, _SDIV, _CBXZ}; CortexM23 = {_SDIV, _CBXZ}; TYPE COMMAND = IL.COMMAND; ANYCODE = POINTER TO RECORD (LISTS.ITEM) offset: INTEGER END; CODE = POINTER TO RECORD (ANYCODE) code: INTEGER END; LABEL = POINTER TO RECORD (ANYCODE) label: INTEGER END; JUMP = POINTER TO RECORD (ANYCODE) label, diff, len, cond: INTEGER; short: BOOLEAN END; JMP = POINTER TO RECORD (JUMP) END; JCC = POINTER TO RECORD (JUMP) END; CBXZ = POINTER TO RECORD (JUMP) reg: INTEGER END; CALL = POINTER TO RECORD (JUMP) END; RELOC = POINTER TO RECORD (ANYCODE) reg, rel, value: INTEGER END; RELOCCODE = ARRAY 7 OF INTEGER; VAR R: REG.REGS; tcount: INTEGER; CodeList: LISTS.LIST; program: BIN.PROGRAM; StkCount: INTEGER; Target: RECORD FlashAdr, SRAMAdr, IVTLen, MinStack, Reserved: INTEGER; InstrSet: SET; isNXP: BOOLEAN END; IVT: ARRAY maxIVT + 1 OF INTEGER; sdivProc, trap, genTrap, entry, emptyProc, int0, genInt: INTEGER; PROCEDURE Code (code: INTEGER); VAR c: CODE; BEGIN NEW(c); c.code := code; LISTS.push(CodeList, c) END Code; PROCEDURE Label (label: INTEGER); VAR L: LABEL; BEGIN NEW(L); L.label := label; LISTS.push(CodeList, L) END Label; PROCEDURE jcc (cond, label: INTEGER); VAR j: JCC; BEGIN NEW(j); j.label := label; j.cond := cond; j.short := FALSE; j.len := 3; LISTS.push(CodeList, j) END jcc; PROCEDURE cbxz (cond, reg, label: INTEGER); VAR j: CBXZ; BEGIN NEW(j); j.label := label; j.cond := cond; j.reg := reg; j.short := FALSE; j.len := 4; LISTS.push(CodeList, j) END cbxz; PROCEDURE jmp (label: INTEGER); VAR j: JMP; BEGIN NEW(j); j.label := label; j.short := FALSE; j.len := 2; LISTS.push(CodeList, j) END jmp; PROCEDURE call (label: INTEGER); VAR c: CALL; BEGIN NEW(c); c.label := label; c.short := FALSE; c.len := 2; LISTS.push(CodeList, c) END call; PROCEDURE reloc (reg, rel, value: INTEGER); VAR r: RELOC; BEGIN NEW(r); r.reg := reg; r.rel := rel; r.value := value; LISTS.push(CodeList, r) END reloc; PROCEDURE NewLabel (): INTEGER; BEGIN BIN.NewLabel(program) RETURN IL.NewLabel() END NewLabel; PROCEDURE range (x, n: INTEGER): BOOLEAN; RETURN (0 <= x) & (x < LSL(1, n)) END range; PROCEDURE srange (x, n: INTEGER): BOOLEAN; RETURN (-LSL(1, n - 1) <= x) & (x < LSL(1, n - 1)) END srange; PROCEDURE gen1 (op, imm, rs, rd: INTEGER); BEGIN ASSERT(op IN {0..2}); ASSERT(range(imm, 5)); ASSERT(range(rs, 3)); ASSERT(range(rd, 3)); Code(LSL(op, 11) + LSL(imm, 6) + LSL(rs, 3) + rd) END gen1; PROCEDURE gen2 (i, op: BOOLEAN; imm, rs, rd: INTEGER); BEGIN ASSERT(range(imm, 3)); ASSERT(range(rs, 3)); ASSERT(range(rd, 3)); Code(1800H + LSL(ORD(i), 10) + LSL(ORD(op), 9) + LSL(imm, 6) + LSL(rs, 3) + rd) END gen2; PROCEDURE gen3 (op, rd, imm: INTEGER); BEGIN ASSERT(range(op, 2)); ASSERT(range(rd, 3)); ASSERT(range(imm, 8)); Code(2000H + LSL(op, 11) + LSL(rd, 8) + imm) END gen3; PROCEDURE gen4 (op, rs, rd: INTEGER); BEGIN ASSERT(range(op, 4)); ASSERT(range(rs, 3)); ASSERT(range(rd, 3)); Code(4000H + LSL(op, 6) + LSL(rs, 3) + rd) END gen4; PROCEDURE gen5 (op: INTEGER; h1, h2: BOOLEAN; rs, rd: INTEGER); BEGIN ASSERT(range(op, 2)); ASSERT(range(rs, 3)); ASSERT(range(rd, 3)); Code(4400H + LSL(op, 8) + LSL(ORD(h1), 7) + LSL(ORD(h2), 6) + LSL(rs, 3) + rd) END gen5; PROCEDURE gen7 (l, b: BOOLEAN; ro, rb, rd: INTEGER); BEGIN ASSERT(range(ro, 3)); ASSERT(range(rb, 3)); ASSERT(range(rd, 3)); Code(5000H + LSL(ORD(l), 11) + LSL(ORD(b), 10) + LSL(ro, 6) + LSL(rb, 3) + rd) END gen7; PROCEDURE gen8 (h, s: BOOLEAN; ro, rb, rd: INTEGER); BEGIN ASSERT(range(ro, 3)); ASSERT(range(rb, 3)); ASSERT(range(rd, 3)); Code(5200H + LSL(ORD(h), 11) + LSL(ORD(s), 10) + LSL(ro, 6) + LSL(rb, 3) + rd) END gen8; PROCEDURE gen9 (b, l: BOOLEAN; imm, rb, rd: INTEGER); BEGIN ASSERT(range(imm, 5)); ASSERT(range(rb, 3)); ASSERT(range(rd, 3)); Code(6000H + LSL(ORD(b), 12) + LSL(ORD(l), 11) + LSL(imm, 6) + LSL(rb, 3) + rd) END gen9; PROCEDURE gen10 (l: BOOLEAN; imm, rb, rd: INTEGER); BEGIN ASSERT(range(imm, 5)); ASSERT(range(rb, 3)); ASSERT(range(rd, 3)); Code(8000H + LSL(ORD(l), 11) + LSL(imm, 6) + LSL(rb, 3) + rd) END gen10; PROCEDURE gen11 (l: BOOLEAN; rd, imm: INTEGER); BEGIN ASSERT(range(rd, 3)); ASSERT(range(imm, 8)); Code(9000H + LSL(ORD(l), 11) + LSL(rd, 8) + imm) END gen11; PROCEDURE gen12 (sp: BOOLEAN; rd, imm: INTEGER); BEGIN ASSERT(range(rd, 3)); ASSERT(range(imm, 8)); Code(0A000H + LSL(ORD(sp), 11) + LSL(rd, 8) + imm) END gen12; PROCEDURE gen14 (l, r: BOOLEAN; rlist: SET); VAR i, n: INTEGER; BEGIN ASSERT(range(ORD(rlist), 8)); n := ORD(r); FOR i := 0 TO 7 DO IF i IN rlist THEN INC(n) END END; IF l THEN n := -n END; INC(StkCount, n); Code(0B400H + LSL(ORD(l), 11) + LSL(ORD(r), 8) + ORD(rlist)) END gen14; PROCEDURE split16 (imm16: INTEGER; VAR imm4, imm1, imm3, imm8: INTEGER); BEGIN ASSERT(range(imm16, 16)); imm8 := imm16 MOD 256; imm4 := LSR(imm16, 12); imm3 := LSR(imm16, 8) MOD 8; imm1 := LSR(imm16, 11) MOD 2; END split16; PROCEDURE LslImm (r, imm5: INTEGER); BEGIN gen1(0, imm5, r, r) END LslImm; PROCEDURE LsrImm (r, imm5: INTEGER); BEGIN gen1(1, imm5, r, r) END LsrImm; PROCEDURE AsrImm (r, imm5: INTEGER); BEGIN gen1(2, imm5, r, r) END AsrImm; PROCEDURE AddReg (rd, rs, rn: INTEGER); BEGIN gen2(FALSE, FALSE, rn, rs, rd) END AddReg; PROCEDURE SubReg (rd, rs, rn: INTEGER); BEGIN gen2(FALSE, TRUE, rn, rs, rd) END SubReg; PROCEDURE AddImm8 (rd, imm8: INTEGER); BEGIN IF imm8 # 0 THEN gen3(2, rd, imm8) END END AddImm8; PROCEDURE SubImm8 (rd, imm8: INTEGER); BEGIN IF imm8 # 0 THEN gen3(3, rd, imm8) END END SubImm8; PROCEDURE AddSubImm12 (r, imm12: INTEGER; sub: BOOLEAN); VAR imm4, imm1, imm3, imm8: INTEGER; BEGIN split16(imm12, imm4, imm1, imm3, imm8); Code(0F200H + LSL(imm1, 10) + r + 0A0H * ORD(sub)); (* addw/subw r, r, imm12 *) Code(LSL(imm3, 12) + LSL(r, 8) + imm8) END AddSubImm12; PROCEDURE MovImm8 (rd, imm8: INTEGER); BEGIN gen3(0, rd, imm8) END MovImm8; PROCEDURE CmpImm8 (rd, imm8: INTEGER); BEGIN gen3(1, rd, imm8) END CmpImm8; PROCEDURE Neg (r: INTEGER); BEGIN gen4(9, r, r) END Neg; PROCEDURE Mul (rd, rs: INTEGER); BEGIN gen4(13, rs, rd) END Mul; PROCEDURE Str32 (rs, rb: INTEGER); BEGIN gen9(FALSE, FALSE, 0, rb, rs) END Str32; PROCEDURE Ldr32 (rd, rb: INTEGER); BEGIN gen9(FALSE, TRUE, 0, rb, rd) END Ldr32; PROCEDURE Str16 (rs, rb: INTEGER); BEGIN gen10(FALSE, 0, rb, rs) END Str16; PROCEDURE Ldr16 (rd, rb: INTEGER); BEGIN gen10(TRUE, 0, rb, rd) END Ldr16; PROCEDURE Str8 (rs, rb: INTEGER); BEGIN gen9(TRUE, FALSE, 0, rb, rs) END Str8; PROCEDURE Ldr8 (rd, rb: INTEGER); BEGIN gen9(TRUE, TRUE, 0, rb, rd) END Ldr8; PROCEDURE Cmp (r1, r2: INTEGER); BEGIN gen4(10, r2, r1) END Cmp; PROCEDURE Tst (r: INTEGER); BEGIN gen3(1, r, 0) (* cmp r, 0 *) END Tst; PROCEDURE LdrSp (r, offset: INTEGER); BEGIN gen11(TRUE, r, offset) END LdrSp; PROCEDURE MovImm32 (r, imm32: INTEGER); BEGIN MovImm8(r, LSR(imm32, 24) MOD 256); LslImm(r, 8); AddImm8(r, LSR(imm32, 16) MOD 256); LslImm(r, 8); AddImm8(r, LSR(imm32, 8) MOD 256); LslImm(r, 8); AddImm8(r, imm32 MOD 256) END MovImm32; PROCEDURE low (x: INTEGER): INTEGER; RETURN x MOD 65536 END low; PROCEDURE high (x: INTEGER): INTEGER; RETURN (x DIV 65536) MOD 65536 END high; PROCEDURE movwt (r, imm16, t: INTEGER); VAR imm1, imm3, imm4, imm8: INTEGER; BEGIN ASSERT(range(r, 3)); ASSERT(range(imm16, 16)); ASSERT(range(t, 1)); split16(imm16, imm4, imm1, imm3, imm8); Code(0F240H + imm1 * 1024 + t * 128 + imm4); Code(imm3 * 4096 + r * 256 + imm8); END movwt; PROCEDURE inv0 (cond: INTEGER): INTEGER; RETURN ORD(BITS(cond) / {0}) END inv0; PROCEDURE fixup (CodeAdr, DataAdr, BssAdr: INTEGER); VAR code: ANYCODE; count: INTEGER; shorted: BOOLEAN; jump: JUMP; reloc, i, diff, len: INTEGER; RelocCode: RELOCCODE; PROCEDURE genjcc (cond, offset: INTEGER): INTEGER; BEGIN ASSERT(range(cond, 4)); ASSERT(srange(offset, 8)) RETURN 0D000H + cond * 256 + offset MOD 256 END genjcc; PROCEDURE genjmp (offset: INTEGER): INTEGER; BEGIN ASSERT(srange(offset, 11)) RETURN 0E000H + offset MOD 2048 END genjmp; PROCEDURE movwt (r, imm16, t: INTEGER; VAR code: RELOCCODE); VAR imm1, imm3, imm4, imm8: INTEGER; BEGIN split16(imm16, imm4, imm1, imm3, imm8); code[t * 2] := 0F240H + imm1 * 1024 + t * 128 + imm4; code[t * 2 + 1] := imm3 * 4096 + r * 256 + imm8 END movwt; PROCEDURE genmovimm32 (r, value: INTEGER; VAR code: RELOCCODE); BEGIN IF _THUMB2 IN Target.InstrSet THEN movwt(r, low(value), 0, code); movwt(r, high(value), 1, code) ELSE code[0] := 2000H + r * 256 + UTILS.Byte(value, 3); (* movs r, imm8 *) code[1] := 0200H + r * 9; (* lsls r, 8 *) code[2] := 3000H + r * 256 + UTILS.Byte(value, 2); (* adds r, imm8 *) code[3] := code[1]; (* lsls r, 8 *) code[4] := 3000H + r * 256 + UTILS.Byte(value, 1); (* adds r, imm8 *) code[5] := code[1]; (* lsls r, 8 *) code[6] := 3000H + r * 256 + UTILS.Byte(value, 0) (* adds r, imm8 *) END END genmovimm32; PROCEDURE PutCode (code: INTEGER); BEGIN BIN.PutCode16LE(program, code) END PutCode; PROCEDURE genlongjmp (offset: INTEGER); BEGIN ASSERT(srange(offset, 22)); PutCode(0F000H + ASR(offset, 11) MOD 2048); PutCode(0F800H + offset MOD 2048) END genlongjmp; PROCEDURE genbc (code: JUMP); BEGIN CASE code.len OF |1: PutCode(genjcc(code.cond, code.diff)) |2: PutCode(genjcc(inv0(code.cond), 0)); PutCode(genjmp(code.diff)) |3: PutCode(genjcc(inv0(code.cond), 1)); genlongjmp(code.diff) END END genbc; PROCEDURE SetIV (idx, label, CodeAdr: INTEGER); VAR l, h: LISTS.ITEM; BEGIN l := CodeList.first; h := l.next; WHILE idx > 0 DO l := h.next; h := l.next; DEC(idx) END; label := BIN.GetLabel(program, label) * 2 + CodeAdr + 1; l(CODE).code := low(label); h(CODE).code := high(label) END SetIV; BEGIN REPEAT shorted := FALSE; count := 0; code := CodeList.first(ANYCODE); WHILE code # NIL DO code.offset := count; CASE code OF |CODE: INC(count) |LABEL: BIN.SetLabel(program, code.label, count) |JUMP: INC(count, code.len); code.offset := count + ORD(code.short) |RELOC: INC(count, 7 - ORD(_THUMB2 IN Target.InstrSet) * 3 + code.rel MOD 2) END; code := code.next(ANYCODE) END; code := CodeList.first(ANYCODE); WHILE code # NIL DO IF code IS JUMP THEN jump := code(JUMP); jump.diff := BIN.GetLabel(program, jump.label) - jump.offset; len := jump.len; diff := jump.diff; CASE jump OF |JMP: IF (len = 2) & srange(diff, 11) THEN len := 1 END |JCC: CASE len OF |1: |2: IF srange(diff, 8) THEN DEC(len) END |3: IF srange(diff, 11) THEN DEC(len) END END |CBXZ: CASE len OF |1: |2: IF range(diff, 6) THEN DEC(len) END |3: IF srange(diff, 8) THEN DEC(len) END |4: IF srange(diff, 11) THEN DEC(len) END END |CALL: END; IF len # jump.len THEN jump.len := len; jump.short := TRUE; shorted := TRUE END END; code := code.next(ANYCODE) END UNTIL ~shorted; FOR i := 1 TO Target.IVTLen - 1 DO SetIV(i, IVT[i], CodeAdr) END; code := CodeList.first(ANYCODE); WHILE code # NIL DO CASE code OF |CODE: BIN.PutCode16LE(program, code.code) |LABEL: |JMP: IF code.len = 1 THEN PutCode(genjmp(code.diff)) ELSE genlongjmp(code.diff) END |JCC: genbc(code) |CBXZ: IF code.len > 1 THEN PutCode(2800H + code.reg * 256); (* cmp code.reg, 0 *) DEC(code.len); genbc(code) ELSE (* cb(n)z code.reg, L *) PutCode(0B100H + 800H * ORD(code.cond = jne) + 200H * (code.diff DIV 32) + (code.diff MOD 32) * 8 + code.reg) END |CALL: genlongjmp(code.diff) |RELOC: CASE code.rel OF |BIN.RCODE, BIN.PICCODE: reloc := BIN.GetLabel(program, code.value) * 2 + CodeAdr |BIN.RDATA, BIN.PICDATA: reloc := code.value + DataAdr |BIN.RBSS, BIN.PICBSS: reloc := code.value + BssAdr END; IF code.rel IN {BIN.PICCODE, BIN.PICDATA, BIN.PICBSS} THEN DEC(reloc, CodeAdr + 2 * (code.offset - 3 * ORD(_THUMB2 IN Target.InstrSet) + 9)) END; genmovimm32(code.reg, reloc, RelocCode); FOR i := 0 TO 6 - 3 * ORD(_THUMB2 IN Target.InstrSet) DO PutCode(RelocCode[i]) END; IF code.rel IN {BIN.PICCODE, BIN.PICDATA, BIN.PICBSS} THEN PutCode(4478H + code.reg) (* add code.reg, pc *) END END; code := code.next(ANYCODE) END END fixup; PROCEDURE push (r: INTEGER); BEGIN gen14(FALSE, FALSE, {r}) END push; PROCEDURE pop (r: INTEGER); BEGIN gen14(TRUE, FALSE, {r}) END pop; PROCEDURE mov (r1, r2: INTEGER); BEGIN IF (r1 < 8) & (r2 < 8) THEN gen1(0, 0, r2, r1) ELSE gen5(2, r1 >= 8, r2 >= 8, r2 MOD 8, r1 MOD 8) END END mov; PROCEDURE xchg (r1, r2: INTEGER); BEGIN push(r1); mov(r1, r2); pop(r2) END xchg; PROCEDURE drop; BEGIN REG.Drop(R) END drop; PROCEDURE GetAnyReg (): INTEGER; RETURN REG.GetAnyReg(R) END GetAnyReg; PROCEDURE UnOp (VAR r: INTEGER); BEGIN REG.UnOp(R, r) END UnOp; PROCEDURE BinOp (VAR r1, r2: INTEGER); BEGIN REG.BinOp(R, r1, r2) END BinOp; PROCEDURE PushAll (NumberOfParameters: INTEGER); BEGIN REG.PushAll(R); DEC(R.pushed, NumberOfParameters) END PushAll; PROCEDURE cond (op: INTEGER): INTEGER; VAR res: INTEGER; BEGIN CASE op OF |IL.opGT, IL.opGTC: res := jg |IL.opGE, IL.opGEC: res := jge |IL.opLT, IL.opLTC: res := jl |IL.opLE, IL.opLEC: res := jle |IL.opEQ, IL.opEQC: res := je |IL.opNE, IL.opNEC: res := jne END RETURN res END cond; PROCEDURE GetRegA; BEGIN ASSERT(REG.GetReg(R, ACC)) END GetRegA; PROCEDURE MovConst (r, c: INTEGER); BEGIN IF (0 <= c) & (c <= 255) THEN MovImm8(r, c) ELSIF (-255 <= c) & (c < 0) THEN MovImm8(r, -c); Neg(r) ELSIF UTILS.Log2(c) >= 0 THEN MovImm8(r, 1); LslImm(r, UTILS.Log2(c)) ELSIF c = UTILS.min32 THEN MovImm8(r, 1); LslImm(r, 31) ELSE IF _THUMB2 IN Target.InstrSet THEN movwt(r, low(c), 0); IF (c < 0) OR (c > 65535) THEN movwt(r, high(c), 1) END ELSE MovImm32(r, c) END END END MovConst; PROCEDURE CmpConst (r, c: INTEGER); VAR r2: INTEGER; BEGIN IF (0 <= c) & (c <= 255) THEN CmpImm8(r, c) ELSE r2 := GetAnyReg(); ASSERT(r2 # r); MovConst(r2, c); Cmp(r, r2); drop END END CmpConst; PROCEDURE LocalOffset (offset: INTEGER): INTEGER; RETURN offset + StkCount - ORD(offset > 0) END LocalOffset; PROCEDURE SetCC (cc, r: INTEGER); VAR L1, L2: INTEGER; BEGIN IF _IT IN Target.InstrSet THEN Code(0BF00H + cc * 16 + ((cc + 1) MOD 2) * 8 + 4); (* ite cc *) MovConst(r, 1); MovConst(r, 0) ELSE L1 := NewLabel(); L2 := NewLabel(); jcc(cc, L1); MovConst(r, 0); jmp(L2); Label(L1); MovConst(r, 1); Label(L2) END END SetCC; PROCEDURE PushConst (n: INTEGER); VAR r: INTEGER; BEGIN r := GetAnyReg(); MovConst(r, n); push(r); drop END PushConst; PROCEDURE AddConst (r, n: INTEGER); VAR r2: INTEGER; BEGIN IF n # 0 THEN IF (-255 <= n) & (n <= 255) THEN IF n > 0 THEN AddImm8(r, n) ELSE SubImm8(r, -n) END ELSIF (_THUMB2 IN Target.InstrSet) & (-4095 <= n) & (n <= 4095) THEN AddSubImm12(r, ABS(n), n < 0) ELSE r2 := GetAnyReg(); ASSERT(r2 # r); IF n > 0 THEN MovConst(r2, n); AddReg(r, r, r2) ELSE MovConst(r2, -n); SubReg(r, r, r2) END; drop END END END AddConst; PROCEDURE AddHH (r1, r2: INTEGER); BEGIN ASSERT((r1 >= 8) OR (r2 >= 8)); gen5(0, r1 >= 8, r2 >= 8, r2 MOD 8, r1 MOD 8) END AddHH; PROCEDURE AddSP (n: INTEGER); BEGIN IF n > 0 THEN IF n < 127 THEN Code(0B000H + n) (* add sp, n*4 *) ELSE ASSERT(R2 IN R.regs); MovConst(R2, n * 4); AddHH(SP, R2) END; DEC(StkCount, n) END END AddSP; PROCEDURE cbxz2 (c, r, label: INTEGER); BEGIN IF _CBXZ IN Target.InstrSet THEN cbxz(c, r, label) ELSE Tst(r); jcc(c, label) END END cbxz2; PROCEDURE cbz (r, label: INTEGER); BEGIN cbxz2(je, r, label) END cbz; PROCEDURE cbnz (r, label: INTEGER); BEGIN cbxz2(jne, r, label) END cbnz; PROCEDURE Shift (op, r1, r2: INTEGER); VAR L: INTEGER; BEGIN LslImm(r2, 27); LsrImm(r2, 27); L := NewLabel(); cbz(r2, L); CASE op OF |IL.opLSL, IL.opLSL1: gen4(2, r2, r1) |IL.opLSR, IL.opLSR1: gen4(3, r2, r1) |IL.opASR, IL.opASR1: gen4(4, r2, r1) |IL.opROR, IL.opROR1: gen4(7, r2, r1) END; Label(L) END Shift; PROCEDURE LocAdr (offs: INTEGER); VAR r1, n: INTEGER; BEGIN r1 := GetAnyReg(); n := LocalOffset(offs); IF n <= 255 THEN gen12(TRUE, r1, n) ELSE MovConst(r1, n * 4); AddHH(r1, SP) END END LocAdr; PROCEDURE CallRTL (proc, par: INTEGER); BEGIN call(IL.codes.rtl[proc]); AddSP(par) END CallRTL; PROCEDURE divmod; BEGIN call(sdivProc); AddSP(2) END divmod; PROCEDURE cpsid_i; BEGIN Code(0B672H) (* cpsid i *) END cpsid_i; PROCEDURE cpsie_i; BEGIN Code(0B662H) (* cpsie i *) END cpsie_i; PROCEDURE translate (pic, stroffs: INTEGER); VAR cmd, next: COMMAND; opcode, param1, param2: INTEGER; r1, r2, r3: INTEGER; a, n, cc, L, L2: INTEGER; BEGIN cmd := IL.codes.commands.first(COMMAND); WHILE cmd # NIL DO param1 := cmd.param1; param2 := cmd.param2; opcode := cmd.opcode; CASE opcode OF |IL.opJMP: jmp(param1) |IL.opLABEL: Label(param1) |IL.opHANDLER: IF param2 = 0 THEN int0 := param1 ELSIF param2 = 1 THEN trap := param1 ELSE IVT[param2] := param1 END |IL.opCALL: call(param1) |IL.opCALLP: UnOp(r1); AddImm8(r1, 1); (* Thumb mode *) gen5(3, TRUE, FALSE, r1, 0); (* blx r1 *) drop; ASSERT(R.top = -1) |IL.opENTER: ASSERT(R.top = -1); Label(param1); gen14(FALSE, TRUE, {}); (* push {lr} *) n := param2; IF n >= 5 THEN MovConst(ACC, 0); MovConst(R2, n); L := NewLabel(); Label(L); push(ACC); SubImm8(R2, 1); Tst(R2); jcc(jne, L) ELSIF n > 0 THEN MovConst(ACC, 0); WHILE n > 0 DO push(ACC); DEC(n) END END; StkCount := param2 |IL.opLEAVE, IL.opLEAVER, IL.opLEAVEF: IF opcode # IL.opLEAVE THEN UnOp(r1); IF r1 # ACC THEN mov(ACC, r1) END; drop END; ASSERT(R.top = -1); ASSERT(StkCount = param1); AddSP(param1); gen14(TRUE, TRUE, {}) (* pop {pc} *) |IL.opLEAVEC: gen5(3, FALSE, TRUE, 6, 0) (* bx lr *) |IL.opPRECALL: PushAll(0) |IL.opPARAM: n := param2; IF n = 1 THEN UnOp(r1); push(r1); drop ELSE ASSERT(R.top + 1 <= n); PushAll(n) END |IL.opCLEANUP: AddSP(param2) |IL.opRES, IL.opRESF: ASSERT(R.top = -1); GetRegA |IL.opPUSHC: PushConst(param2) |IL.opONERR: cpsid_i; MovConst(R0, param2); push(R0); DEC(StkCount); jmp(param1) |IL.opERR: call(genTrap) |IL.opNOP, IL.opAND, IL.opOR: |IL.opSADR: reloc(GetAnyReg(), BIN.RDATA + pic, stroffs + param2) |IL.opGADR: reloc(GetAnyReg(), BIN.RBSS + pic, param2) |IL.opLADR: LocAdr(param2) |IL.opGLOAD32: r1 := GetAnyReg(); reloc(r1, BIN.RBSS + pic, param2); Ldr32(r1, r1) |IL.opGLOAD16: r1 := GetAnyReg(); reloc(r1, BIN.RBSS + pic, param2); Ldr16(r1, r1) |IL.opGLOAD8: r1 := GetAnyReg(); reloc(r1, BIN.RBSS + pic, param2); Ldr8(r1, r1) |IL.opLADR_SAVE: UnOp(r1); n := LocalOffset(param2); IF n <= 255 THEN gen11(FALSE, r1, n) (* str r1, [sp, n*4] *) ELSE LocAdr(param2); BinOp(r1, r2); Str32(r1, r2); drop END; drop |IL.opLADR_INCC: n := LocalOffset(param1); IF n <= 255 THEN r1 := GetAnyReg(); LdrSp(r1, n); AddConst(r1, param2); gen11(FALSE, r1, n) (* str r1, [sp, n*4] *) ELSE LocAdr(param1); r1 := GetAnyReg(); BinOp(r2, r1); Ldr32(r1, r2); AddConst(r1, param2); BinOp(r2, r1); Str32(r1, r2); drop END; drop |IL.opLLOAD32, IL.opVADR, IL.opVLOAD32: r1 := GetAnyReg(); n := LocalOffset(param2); IF n <= 255 THEN LdrSp(r1, n) ELSE drop; LocAdr(param2); UnOp(r1); Ldr32(r1, r1) END; IF opcode = IL.opVLOAD32 THEN Ldr32(r1, r1) END |IL.opLLOAD16: LocAdr(param2); UnOp(r1); Ldr16(r1, r1) |IL.opLLOAD8: LocAdr(param2); UnOp(r1); Ldr8(r1, r1) |IL.opLOAD32, IL.opLOADF: UnOp(r1); Ldr32(r1, r1) |IL.opLOAD16: UnOp(r1); Ldr16(r1, r1) |IL.opLOAD8: UnOp(r1); Ldr8(r1, r1) |IL.opVLOAD16: LocAdr(param2); UnOp(r1); Ldr32(r1, r1); Ldr16(r1, r1) |IL.opVLOAD8: LocAdr(param2); UnOp(r1); Ldr32(r1, r1); Ldr8(r1, r1) |IL.opSBOOL: BinOp(r2, r1); Tst(r2); SetCC(jne, r2); Str8(r2, r1); drop; drop |IL.opSBOOLC: UnOp(r1); r2 := GetAnyReg(); MovConst(r2, ORD(param2 # 0)); Str8(r2, r1); drop; drop |IL.opSAVEC: UnOp(r1); r2 := GetAnyReg(); MovConst(r2, param2); Str32(r2, r1); drop; drop |IL.opSAVE16C: UnOp(r1); r2 := GetAnyReg(); MovConst(r2, low(param2)); Str16(r2, r1); drop; drop |IL.opSAVE8C: UnOp(r1); r2 := GetAnyReg(); MovConst(r2, param2 MOD 256); Str8(r2, r1); drop; drop |IL.opSAVE, IL.opSAVE32, IL.opSAVEF: BinOp(r2, r1); Str32(r2, r1); drop; drop |IL.opSAVEFI: BinOp(r2, r1); Str32(r1, r2); drop; drop |IL.opSAVE16: BinOp(r2, r1); Str16(r2, r1); drop; drop |IL.opSAVE8: BinOp(r2, r1); Str8(r2, r1); drop; drop |IL.opSAVEP: UnOp(r1); r2 := GetAnyReg(); reloc(r2, BIN.RCODE + pic, param2); Str32(r2, r1); drop; drop |IL.opPUSHP: reloc(GetAnyReg(), BIN.RCODE + pic, param2) |IL.opEQB, IL.opNEB: BinOp(r1, r2); drop; L := NewLabel(); cbz(r1, L); MovConst(r1, 1); Label(L); L := NewLabel(); cbz(r2, L); MovConst(r2, 1); Label(L); Cmp(r1, r2); IF opcode = IL.opEQB THEN SetCC(je, r1) ELSE SetCC(jne, r1) END |IL.opDROP: UnOp(r1); drop |IL.opJNZ1: UnOp(r1); cbnz(r1, param1) |IL.opJG: UnOp(r1); Tst(r1); jcc(jg, param1) |IL.opJNZ: UnOp(r1); cbnz(r1, param1); drop |IL.opJZ: UnOp(r1); cbz(r1, param1); drop |IL.opSWITCH: UnOp(r1); IF param2 = 0 THEN r2 := ACC ELSE r2 := R2 END; IF r1 # r2 THEN ASSERT(REG.GetReg(R, r2)); ASSERT(REG.Exchange(R, r1, r2)); drop END; drop |IL.opENDSW: |IL.opCASEL: GetRegA; CmpConst(ACC, param1); jcc(jl, param2); drop |IL.opCASER: GetRegA; CmpConst(ACC, param1); jcc(jg, param2); drop |IL.opCASELR: GetRegA; CmpConst(ACC, param1); IF param2 = cmd.param3 THEN jcc(jne, param2) ELSE jcc(jl, param2); jcc(jg, cmd.param3) END; drop |IL.opCODE: Code(param2) |IL.opEQ..IL.opGE, IL.opEQC..IL.opGEC: IF (IL.opEQ <= opcode) & (opcode <= IL.opGE) THEN BinOp(r1, r2); Cmp(r1, r2); drop ELSE UnOp(r1); CmpConst(r1, param2) END; drop; cc := cond(opcode); next := cmd.next(COMMAND); IF next.opcode = IL.opJNZ THEN jcc(cc, next.param1); cmd := next ELSIF next.opcode = IL.opJZ THEN jcc(inv0(cc), next.param1); cmd := next ELSE SetCC(cc, GetAnyReg()) END |IL.opINCC: UnOp(r1); r2 := GetAnyReg(); Ldr32(r2, r1); AddConst(r2, param2); Str32(r2, r1); drop; drop |IL.opINCCB, IL.opDECCB: IF opcode = IL.opDECCB THEN param2 := -param2 END; UnOp(r1); r2 := GetAnyReg(); Ldr8(r2, r1); AddConst(r2, param2); Str8(r2, r1); drop; drop |IL.opUMINUS: UnOp(r1); Neg(r1) |IL.opADD: BinOp(r1, r2); CASE cmd.next(COMMAND).opcode OF |IL.opLOAD32, IL.opLOADF: gen7(TRUE, FALSE, r2, r1, r1); (* ldr r1, [r1, r2] *) cmd := cmd.next(COMMAND) |IL.opLOAD8: gen7(TRUE, TRUE, r2, r1, r1); (* ldrb r1, [r1, r2] *) cmd := cmd.next(COMMAND) |IL.opLOAD16: gen8(TRUE, FALSE, r2, r1, r1); (* ldrh r1, [r1, r2] *) cmd := cmd.next(COMMAND) ELSE AddReg(r1, r1, r2) END; drop |IL.opADDC: UnOp(r1); AddConst(r1, param2) |IL.opSUB: BinOp(r1, r2); SubReg(r1, r1, r2); drop |IL.opSUBL, IL.opSUBR: UnOp(r1); AddConst(r1, -param2); IF opcode = IL.opSUBL THEN Neg(r1) END |IL.opMUL: BinOp(r1, r2); Mul(r1, r2); drop |IL.opMULC: UnOp(r1); a := param2; IF a > 1 THEN n := UTILS.Log2(a) ELSIF a < -1 THEN n := UTILS.Log2(-a) ELSE n := -1 END; IF a = 1 THEN ELSIF a = -1 THEN Neg(r1) ELSIF a = 0 THEN MovConst(r1, 0) ELSE IF n > 0 THEN IF a < 0 THEN Neg(r1) END; LslImm(r1, n) ELSE r2 := GetAnyReg(); MovConst(r2, a); Mul(r1, r2); drop END END |IL.opABS: UnOp(r1); Tst(r1); L := NewLabel(); jcc(jge, L); Neg(r1); Label(L) |IL.opNOT: UnOp(r1); Tst(r1); SetCC(je, r1) |IL.opORD: UnOp(r1); Tst(r1); SetCC(jne, r1) |IL.opCHR: UnOp(r1); Code(0B2C0H + r1 * 9) (* uxtb r1, r1 *) |IL.opWCHR: UnOp(r1); Code(0B280H + r1 * 9) (* uxth r1, r1 *) |IL.opASR, IL.opROR, IL.opLSL, IL.opLSR: BinOp(r1, r2); Shift(opcode, r1, r2); drop |IL.opASR1, IL.opROR1, IL.opLSL1, IL.opLSR1: MovConst(GetAnyReg(), param2); BinOp(r2, r1); Shift(opcode, r1, r2); INCL(R.regs, r2); DEC(R.top); R.stk[R.top] := r1 |IL.opASR2, IL.opROR2, IL.opLSL2, IL.opLSR2: n := param2 MOD 32; IF n # 0 THEN UnOp(r1); CASE opcode OF |IL.opASR2: AsrImm(r1, n) |IL.opROR2: r2 := GetAnyReg(); MovConst(r2, n); Shift(IL.opROR, r1, r2); drop |IL.opLSL2: LslImm(r1, n) |IL.opLSR2: LsrImm(r1, n) END END |IL.opCHKBYTE: BinOp(r1, r2); CmpConst(r1, 256); jcc(jb, param1) |IL.opCHKIDX: UnOp(r1); CmpConst(r1, param2); jcc(jb, param1) |IL.opCHKIDX2: BinOp(r1, r2); IF param2 # -1 THEN Cmp(r2, r1); jcc(jb, param1) END; INCL(R.regs, r1); DEC(R.top); R.stk[R.top] := r2 |IL.opLEN: n := param2; UnOp(r1); drop; EXCL(R.regs, r1); WHILE n > 0 DO UnOp(r2); drop; DEC(n) END; INCL(R.regs, r1); ASSERT(REG.GetReg(R, r1)) |IL.opINF: MovConst(GetAnyReg(), inf) |IL.opPUSHF: UnOp(r1); push(r1); drop |IL.opCONST: MovConst(GetAnyReg(), param2) |IL.opEQP, IL.opNEP: reloc(GetAnyReg(), BIN.RCODE + pic, param1); BinOp(r1, r2); Cmp(r1, r2); drop; IF opcode = IL.opEQP THEN SetCC(je, r1) ELSE SetCC(jne, r1) END |IL.opPUSHT: UnOp(r1); r2 := GetAnyReg(); mov(r2, r1); SubImm8(r2, 4); Ldr32(r2, r2) |IL.opGET, IL.opGETC: IF opcode = IL.opGET THEN BinOp(r1, r2) ELSIF opcode = IL.opGETC THEN UnOp(r2); r1 := GetAnyReg(); MovConst(r1, param1) END; drop; drop; CASE param2 OF |1: Ldr8(r1, r1); Str8(r1, r2) |2: Ldr16(r1, r1); Str16(r1, r2) |4: Ldr32(r1, r1); Str32(r1, r2) END |IL.opINC, IL.opDEC: BinOp(r2, r1); r3 := GetAnyReg(); Ldr32(r3, r1); IF opcode = IL.opINC THEN AddReg(r3, r3, r2) ELSE SubReg(r3, r3, r2) END; Str32(r3, r1); drop; drop; drop |IL.opINCB, IL.opDECB: BinOp(r2, r1); r3 := GetAnyReg(); Ldr8(r3, r1); IF opcode = IL.opINCB THEN AddReg(r3, r3, r2) ELSE SubReg(r3, r3, r2) END; Str8(r3, r1); drop; drop; drop |IL.opMIN, IL.opMAX: BinOp(r1, r2); Cmp(r1, r2); L := NewLabel(); IF opcode = IL.opMIN THEN cc := jle ELSE cc := jge END; jcc(cc, L); mov(r1, r2); Label(L); drop |IL.opMINC, IL.opMAXC: UnOp(r1); CmpConst(r1, param2); L := NewLabel(); IF opcode = IL.opMINC THEN cc := jle ELSE cc := jge END; jcc(cc, L); MovConst(r1, param2); Label(L) |IL.opMULS: BinOp(r1, r2); gen4(0, r2, r1); (* ands r1, r2 *) drop |IL.opMULSC: MovConst(GetAnyReg(), param2); BinOp(r1, r2); gen4(0, r2, r1); (* ands r1, r2 *) drop |IL.opDIVS: BinOp(r1, r2); gen4(1, r2, r1); (* eors r1, r2 *) drop |IL.opDIVSC: MovConst(GetAnyReg(), param2); BinOp(r1, r2); gen4(1, r2, r1); (* eors r1, r2 *) drop |IL.opADDS: BinOp(r1, r2); gen4(12, r2, r1); (* orrs r1, r2 *) drop |IL.opSUBS: BinOp(r1, r2); gen4(14, r2, r1); (* bics r1, r2 *) drop |IL.opADDSC: MovConst(GetAnyReg(), param2); BinOp(r1, r2); gen4(12, r2, r1); (* orrs r1, r2 *) drop |IL.opSUBSL: MovConst(GetAnyReg(), param2); BinOp(r1, r2); gen4(14, r1, r2); (* bics r2, r1 *) INCL(R.regs, r1); DEC(R.top); R.stk[R.top] := r2 |IL.opSUBSR: MovConst(GetAnyReg(), param2); BinOp(r1, r2); gen4(14, r2, r1); (* bics r1, r2 *) drop |IL.opUMINS: UnOp(r1); gen4(15, r1, r1) (* mvns r1, r1 *) |IL.opINCL, IL.opEXCL: BinOp(r1, r2); r3 := GetAnyReg(); MovConst(r3, 1); CmpConst(r1, 32); L := NewLabel(); jcc(jnb, L); gen4(2, r1, r3); (* lsls r3, r1 *) Ldr32(r1, r2); IF opcode = IL.opINCL THEN gen4(12, r3, r1) (* orrs r1, r3 *) ELSE gen4(14, r3, r1) (* bics r1, r3 *) END; Str32(r1, r2); Label(L); drop; drop; drop |IL.opINCLC, IL.opEXCLC: UnOp(r2); r1 := GetAnyReg(); r3 := GetAnyReg(); MovConst(r3, 1); LslImm(r3, param2); Ldr32(r1, r2); IF opcode = IL.opINCLC THEN gen4(12, r3, r1) (* orrs r1, r3 *) ELSE gen4(14, r3, r1) (* bics r1, r3 *) END; Str32(r1, r2); drop; drop; drop |IL.opLENGTH: PushAll(2); CallRTL(IL._length, 2); GetRegA |IL.opLENGTHW: PushAll(2); CallRTL(IL._lengthw, 2); GetRegA |IL.opSAVES: UnOp(r2); REG.PushAll_1(R); r1 := GetAnyReg(); reloc(r1, BIN.RDATA + pic, stroffs + param2); push(r1); drop; push(r2); drop; PushConst(param1); CallRTL(IL._move, 3) |IL.opEQS .. IL.opGES: PushAll(4); PushConst(opcode - IL.opEQS); CallRTL(IL._strcmp, 5); GetRegA |IL.opEQSW .. IL.opGESW: PushAll(4); PushConst(opcode - IL.opEQSW); CallRTL(IL._strcmpw, 5); GetRegA |IL.opCOPY: PushAll(2); PushConst(param2); CallRTL(IL._move, 3) |IL.opMOVE: PushAll(3); CallRTL(IL._move, 3) |IL.opCOPYA: PushAll(4); PushConst(param2); CallRTL(IL._arrcpy, 5); GetRegA |IL.opCOPYS: PushAll(4); PushConst(param2); CallRTL(IL._strcpy, 5) |IL.opDIV: PushAll(2); divmod; GetRegA |IL.opDIVL: UnOp(r1); REG.PushAll_1(R); PushConst(param2); push(r1); drop; divmod; GetRegA |IL.opDIVR: n := UTILS.Log2(param2); IF n > 0 THEN UnOp(r1); AsrImm(r1, n) ELSIF n < 0 THEN PushAll(1); PushConst(param2); divmod; GetRegA END |IL.opMOD: PushAll(2); divmod; mov(R0, R1); GetRegA |IL.opMODR: n := UTILS.Log2(param2); IF n > 0 THEN UnOp(r1); IF n = 8 THEN Code(0B2C0H + r1 * 9) (* uxtb r1, r1 *) ELSIF n = 16 THEN Code(0B280H + r1 * 9) (* uxth r1, r1 *) ELSE LslImm(r1, 32 - n); LsrImm(r1, 32 - n) END ELSIF n < 0 THEN PushAll(1); PushConst(param2); divmod; mov(R0, R1); GetRegA ELSE UnOp(r1); MovConst(r1, 0) END |IL.opMODL: UnOp(r1); REG.PushAll_1(R); PushConst(param2); push(r1); drop; divmod; mov(R0, R1); GetRegA |IL.opIN, IL.opINR: IF opcode = IL.opINR THEN r2 := GetAnyReg(); MovConst(r2, param2) END; L := NewLabel(); L2 := NewLabel(); BinOp(r1, r2); r3 := GetAnyReg(); CmpConst(r1, 32); jcc(jb, L); MovConst(r1, 0); jmp(L2); Label(L); MovConst(r3, 1); Shift(IL.opLSL, r3, r1); gen4(0, r3, r2); (* ands r2, r3 *) SetCC(jne, r1); Label(L2); drop; drop |IL.opINL: UnOp(r1); r2 := GetAnyReg(); MovConst(r2, LSL(1, param2)); gen4(0, r2, r1); (* ands r1, r2 *) SetCC(jne, r1); drop |IL.opRSET: PushAll(2); CallRTL(IL._set, 2); GetRegA |IL.opRSETR: PushAll(1); PushConst(param2); CallRTL(IL._set, 2); GetRegA |IL.opRSETL: UnOp(r1); REG.PushAll_1(R); PushConst(param2); push(r1); drop; CallRTL(IL._set, 2); GetRegA |IL.opRSET1: PushAll(1); CallRTL(IL._set1, 1); GetRegA |IL.opCONSTF: MovConst(GetAnyReg(), UTILS.d2s(cmd.float)) |IL.opMULF: PushAll(2); CallRTL(IL._fmul, 2); GetRegA |IL.opDIVF: PushAll(2); CallRTL(IL._fdiv, 2); GetRegA |IL.opDIVFI: PushAll(2); CallRTL(IL._fdivi, 2); GetRegA |IL.opADDF: PushAll(2); CallRTL(IL._fadd, 2); GetRegA |IL.opSUBFI: PushAll(2); CallRTL(IL._fsubi, 2); GetRegA |IL.opSUBF: PushAll(2); CallRTL(IL._fsub, 2); GetRegA |IL.opEQF..IL.opGEF: PushAll(2); PushConst(opcode - IL.opEQF); CallRTL(IL._fcmp, 3); GetRegA |IL.opFLOOR: PushAll(1); CallRTL(IL._floor, 1); GetRegA |IL.opFLT: PushAll(1); CallRTL(IL._flt, 1); GetRegA |IL.opUMINF: UnOp(r1); r2 := GetAnyReg(); MovConst(r2, 1); LslImm(r2, 31); gen4(1, r2, r1); (* eors r1, r2 *) drop |IL.opFABS: UnOp(r1); r2 := GetAnyReg(); MovConst(r2, 1); LslImm(r2, 31); gen4(14, r2, r1); (* bics r1, r2 *) drop |IL.opNEW: cpsid_i; PushAll(1); n := param2 + 4; ASSERT(UTILS.Align(n, 4)); PushConst(n); PushConst(param1); CallRTL(IL._new, 3); cpsie_i |IL.opTYPEGP: UnOp(r1); PushAll(0); push(r1); PushConst(param2); CallRTL(IL._guard, 2); GetRegA |IL.opIS: PushAll(1); PushConst(param2); CallRTL(IL._is, 2); GetRegA |IL.opISREC: PushAll(2); PushConst(param2); CallRTL(IL._guardrec, 3); GetRegA |IL.opTYPEGR: PushAll(1); PushConst(param2); CallRTL(IL._guardrec, 2); GetRegA |IL.opTYPEGD: UnOp(r1); PushAll(0); SubImm8(r1, 4); Ldr32(r1, r1); push(r1); PushConst(param2); CallRTL(IL._guardrec, 2); GetRegA |IL.opCASET: push(R2); push(R2); PushConst(param2); CallRTL(IL._guardrec, 2); pop(R2); cbnz(ACC, param1) |IL.opROT: PushAll(0); mov(R2, SP); push(R2); PushConst(param2); CallRTL(IL._rot, 2) |IL.opPACK: PushAll(2); CallRTL(IL._pack, 2) |IL.opPACKC: PushAll(1); PushConst(param2); CallRTL(IL._pack, 2) |IL.opUNPK: PushAll(2); CallRTL(IL._unpk, 2) END; cmd := cmd.next(COMMAND) END; ASSERT(R.pushed = 0); ASSERT(R.top = -1) END translate; PROCEDURE prolog (GlobSize, tcount, pic, sp, ivt_len: INTEGER); VAR r1, r2, i, dcount: INTEGER; BEGIN entry := NewLabel(); emptyProc := NewLabel(); genInt := NewLabel(); genTrap := NewLabel(); sdivProc := NewLabel(); trap := emptyProc; int0 := emptyProc; IVT[0] := sp; IVT[1] := entry; FOR i := 2 TO ivt_len - 1 DO IVT[i] := genInt END; FOR i := 0 TO ivt_len - 1 DO Code(low(IVT[i])); Code(high(IVT[i])) END; Label(entry); cpsie_i; r1 := GetAnyReg(); r2 := GetAnyReg(); reloc(r1, BIN.RDATA + pic, 0); FOR i := 0 TO tcount - 1 DO MovConst(r2, CHL.GetInt(IL.codes.types, i)); Str32(r2, r1); AddImm8(r1, 4) END; dcount := CHL.Length(IL.codes.data); FOR i := 0 TO dcount - 1 BY 4 DO MovConst(r2, BIN.get32le(IL.codes.data, i)); Str32(r2, r1); AddImm8(r1, 4) END; drop; drop; r1 := GetAnyReg(); MovConst(r1, sp); mov(SP, r1); reloc(r1, BIN.RDATA + pic, 0); push(r1); reloc(r1, BIN.RBSS + pic, 0); r2 := GetAnyReg(); MovConst(r2, GlobSize); AddReg(r1, r1, r2); drop; push(r1); drop; PushConst(tcount); CallRTL(IL._init, 3) END prolog; PROCEDURE epilog; VAR L1, L2, L3, L4: INTEGER; BEGIN (* L2: *) Code(0E7FEH); (* b L2 *) Label(genInt); Code(0F3EFH); Code(08005H); (* mrs r0, ipsr *) gen14(FALSE, TRUE, {R0}); (* push {lr, r0} *) call(int0); gen14(TRUE, TRUE, {R0}); (* pop {pc, r0} *) Label(emptyProc); Code(04770H); (* bx lr *) Label(genTrap); call(trap); call(entry); Label(sdivProc); IF _SDIV IN Target.InstrSet THEN Code(09800H); (* ldr r0, [sp] *) Code(09901H); (* ldr r1, [sp, 4] *) Code(0FB91H); (* sdiv r2, r1, r0 *) Code(0F2F0H); Code(00013H); (* movs r3, r2 *) Code(04343H); (* muls r3, r0, r3 *) Code(01AC9H); (* subs r1, r1, r3 *) Code(0DA01H); (* bge L *) Code(01809H); (* adds r1, r1, r0 *) Code(03A01H); (* subs r2, 1 *) (* L: *) Code(00010H); (* movs r0, r2 *) Code(04770H); (* bx lr *) ELSE (* a / b; a >= 0 *) L1 := NewLabel(); L2 := NewLabel(); L3 := NewLabel(); L4 := NewLabel(); LdrSp(R1, 1); LdrSp(R2, 0); MovConst(R0, 0); push(R4); Label(L4); Cmp(R1, R2); jcc(jl, L1); MovConst(R3, 2); mov(R4, R2); LslImm(R4, 1); Label(L3); Cmp(R1, R4); jcc(jl, L2); CmpConst(R4, 0); jcc(jle, L2); LslImm(R4, 1); LslImm(R3, 1); jmp(L3); Label(L2); LsrImm(R4, 1); LsrImm(R3, 1); SubReg(R1, R1, R4); AddReg(R0, R0, R3); jmp(L4); Label(L1); (* a / b; a < 0 *) L1 := NewLabel(); L2 := NewLabel(); L3 := NewLabel(); L4 := NewLabel(); Label(L4); CmpConst(R1, 0); jcc(jge, L1); MovConst(R3, 2); mov(R4, R2); LslImm(R4, 1); Neg(R1); Label(L3); Cmp(R1, R4); jcc(jl, L2); CmpConst(R4, 0); jcc(jle, L2); LslImm(R4, 1); LslImm(R3, 1); jmp(L3); Label(L2); Neg(R1); LsrImm(R4, 1); LsrImm(R3, 1); AddReg(R1, R1, R4); SubReg(R0, R0, R3); jmp(L4); Label(L1); pop(R4); Code(04770H); (* bx lr *) END END epilog; PROCEDURE SetTarget (FlashStart, SRAMStart: INTEGER; InstrSet: SET; isNXP: BOOLEAN); BEGIN Target.FlashAdr := FlashStart; Target.SRAMAdr := SRAMStart; Target.InstrSet := InstrSet; Target.isNXP := isNXP; Target.IVTLen := 256; (* >= 192 *) Target.Reserved := 0; Target.MinStack := 512; END SetTarget; PROCEDURE CodeGen* (outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS); VAR opt: PROG.OPTIONS; ram, rom, i, j: INTEGER; DataAdr, BssAdr, DataSize, BssSize, CodeSize: INTEGER; BEGIN ram := MIN(MAX(options.ram, minRAM), maxRAM) * 1024; rom := MIN(MAX(options.rom, minROM), maxROM) * 1024; IF target = TARGETS.STM32CM3 THEN SetTarget(08000000H, 20000000H, CortexM3, FALSE) END; tcount := CHL.Length(IL.codes.types); opt := options; CodeList := LISTS.create(NIL); program := BIN.create(IL.codes.lcount); REG.Init(R, push, pop, mov, xchg, {R0, R1, R2, R3}); StkCount := 0; DataAdr := Target.SRAMAdr + Target.Reserved; DataSize := CHL.Length(IL.codes.data) + tcount * 4 + Target.Reserved; WHILE DataSize MOD 4 # 0 DO CHL.PushByte(IL.codes.data, 0); INC(DataSize) END; BssAdr := DataAdr + DataSize - Target.Reserved; IL.set_bss(MAX(IL.codes.bss, MAX(IL.codes.dmin - CHL.Length(IL.codes.data), 4))); BssSize := IL.codes.bss; ASSERT(UTILS.Align(BssSize, 4)); prolog(BssSize, tcount, ORD(opt.pic), Target.SRAMAdr + ram, Target.IVTLen); translate(ORD(opt.pic), tcount * 4); epilog; fixup(Target.FlashAdr, DataAdr, BssAdr); INC(DataSize, BssSize); CodeSize := CHL.Length(program.code); IF CodeSize > rom THEN ERRORS.Error(203) END; IF DataSize > ram - Target.MinStack THEN ERRORS.Error(204) END; IF Target.isNXP THEN BIN.put32le(program.code, 2FCH, 0H); (* code read protection (CRP) *) (* NXP checksum *) j := 0; FOR i := 0 TO 6 DO INC(j, BIN.get32le(program.code, i * 4)) END; BIN.put32le(program.code, 1CH, -j) END; WR.Create(outname); HEX.Data2(program.code, 0, CodeSize, high(Target.FlashAdr)); HEX.End; WR.Close; C.Dashes; C.String( " rom: "); C.Int(CodeSize); C.String(" of "); C.Int(rom); C.String(" ("); C.Int(CodeSize * 100 DIV rom); C.StringLn("%)"); C.Ln; C.String( " ram: "); C.Int(DataSize); C.String(" of "); C.Int(ram); C.String(" ("); C.Int(DataSize * 100 DIV ram); C.StringLn("%)") END CodeGen; PROCEDURE SetIV* (idx: INTEGER): BOOLEAN; VAR res: BOOLEAN; BEGIN res := IVT[idx] = 0; IVT[idx] := 1 RETURN res END SetIV; PROCEDURE init; VAR i: INTEGER; BEGIN FOR i := 0 TO LEN(IVT) - 1 DO IVT[i] := 0 END END init; BEGIN init END THUMB.