0,0 → 1,2466 |
(* |
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. |