498da3221e
git-svn-id: svn://kolibrios.org@8859 a494cfbc-eb01-0410-851d-a64ba20cac60
2466 lines
52 KiB
Plaintext
2466 lines
52 KiB
Plaintext
(*
|
|
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. |