forked from KolibriOS/kolibrios
1793 lines
42 KiB
Plaintext
1793 lines
42 KiB
Plaintext
|
(*
|
||
|
BSD 2-Clause License
|
||
|
|
||
|
Copyright (c) 2019, Anton Krotov
|
||
|
All rights reserved.
|
||
|
*)
|
||
|
|
||
|
MODULE MSP430;
|
||
|
|
||
|
IMPORT IL, LISTS, REG, CHL := CHUNKLISTS, ERRORS, FILES, WRITER,
|
||
|
UTILS, C := CONSOLE, PROG, RTL := MSP430RTL;
|
||
|
|
||
|
|
||
|
CONST
|
||
|
|
||
|
minRAM* = 128; maxRAM* = 10240;
|
||
|
minROM* = 2048; maxROM* = 49152;
|
||
|
|
||
|
minStackSize = 64;
|
||
|
|
||
|
IntVectorSize* = RTL.IntVectorSize;
|
||
|
|
||
|
PC = 0; SP = 1; SR = 2; CG = 3;
|
||
|
|
||
|
R4 = 4; R5 = 5; R6 = 6; R7 = 7;
|
||
|
|
||
|
IR = 13; HP = 14; BP = 15;
|
||
|
|
||
|
ACC = R4;
|
||
|
|
||
|
opRRC = 1000H; opSWPB = 1080H; opRRA = 1100H; opSXT = 1180H;
|
||
|
opPUSH = 1200H; opCALL = 1280H; opRETI = 1300H;
|
||
|
|
||
|
opMOV = 04000H; opADD = 05000H; opADDC = 06000H; opSUBC = 07000H;
|
||
|
opSUB = 08000H; opCMP = 09000H; opDADD = 0A000H; opBIT = 0B000H;
|
||
|
opBIC = 0C000H; opBIS = 0D000H; opXOR = 0E000H; opAND = 0F000H;
|
||
|
|
||
|
opJNE = 2000H; opJEQ = 2400H; opJNC = 2800H; opJC = 2C00H;
|
||
|
opJN = 3000H; opJGE = 3400H; opJL = 3800H; opJMP = 3C00H;
|
||
|
|
||
|
sREG = 0; sIDX = 16; sINDIR = 32; sINCR = 48; BW = 64; dIDX = 128;
|
||
|
|
||
|
NOWORD = 10000H;
|
||
|
|
||
|
RCODE = 0; RDATA = 1; RBSS = 2;
|
||
|
|
||
|
je = 0; jne = je + 1;
|
||
|
jge = 2; jl = jge + 1;
|
||
|
jle = 4; jg = jle + 1;
|
||
|
jb = 6;
|
||
|
|
||
|
|
||
|
TYPE
|
||
|
|
||
|
ANYCODE = POINTER TO RECORD (LISTS.ITEM)
|
||
|
|
||
|
offset: INTEGER
|
||
|
|
||
|
END;
|
||
|
|
||
|
WORD = POINTER TO RECORD (ANYCODE)
|
||
|
|
||
|
val: INTEGER
|
||
|
|
||
|
END;
|
||
|
|
||
|
LABEL = POINTER TO RECORD (ANYCODE)
|
||
|
|
||
|
num: INTEGER
|
||
|
|
||
|
END;
|
||
|
|
||
|
JMP = POINTER TO RECORD (ANYCODE)
|
||
|
|
||
|
cc, label: INTEGER;
|
||
|
short: BOOLEAN
|
||
|
|
||
|
END;
|
||
|
|
||
|
CALL = POINTER TO RECORD (ANYCODE)
|
||
|
|
||
|
label: INTEGER
|
||
|
|
||
|
END;
|
||
|
|
||
|
COMMAND = IL.COMMAND;
|
||
|
|
||
|
RELOC = POINTER TO RECORD (LISTS.ITEM)
|
||
|
|
||
|
section: INTEGER;
|
||
|
WordPtr: WORD
|
||
|
|
||
|
END;
|
||
|
|
||
|
|
||
|
VAR
|
||
|
|
||
|
R: REG.REGS;
|
||
|
|
||
|
CodeList: LISTS.LIST;
|
||
|
RelList: LISTS.LIST;
|
||
|
|
||
|
mem: ARRAY 65536 OF BYTE;
|
||
|
|
||
|
Labels: CHL.INTLIST;
|
||
|
|
||
|
IV: ARRAY RTL.LenIV OF INTEGER;
|
||
|
|
||
|
IdxWords: RECORD src, dst: INTEGER END;
|
||
|
|
||
|
|
||
|
PROCEDURE EmitLabel (L: INTEGER);
|
||
|
VAR
|
||
|
label: LABEL;
|
||
|
|
||
|
BEGIN
|
||
|
NEW(label);
|
||
|
label.num := L;
|
||
|
LISTS.push(CodeList, label)
|
||
|
END EmitLabel;
|
||
|
|
||
|
|
||
|
PROCEDURE EmitWord (val: INTEGER);
|
||
|
VAR
|
||
|
word: WORD;
|
||
|
|
||
|
BEGIN
|
||
|
IF val < 0 THEN
|
||
|
ASSERT(val >= -32768);
|
||
|
val := val MOD 65536
|
||
|
ELSE
|
||
|
ASSERT(val <= 65535)
|
||
|
END;
|
||
|
NEW(word);
|
||
|
word.val := val;
|
||
|
LISTS.push(CodeList, word)
|
||
|
END EmitWord;
|
||
|
|
||
|
|
||
|
PROCEDURE EmitJmp (cc, label: INTEGER);
|
||
|
VAR
|
||
|
jmp: JMP;
|
||
|
|
||
|
BEGIN
|
||
|
NEW(jmp);
|
||
|
jmp.cc := cc;
|
||
|
jmp.label := label;
|
||
|
jmp.short := FALSE;
|
||
|
LISTS.push(CodeList, jmp)
|
||
|
END EmitJmp;
|
||
|
|
||
|
|
||
|
PROCEDURE EmitCall (label: INTEGER);
|
||
|
VAR
|
||
|
call: CALL;
|
||
|
|
||
|
BEGIN
|
||
|
NEW(call);
|
||
|
call.label := label;
|
||
|
LISTS.push(CodeList, call)
|
||
|
END EmitCall;
|
||
|
|
||
|
|
||
|
PROCEDURE bw (b: BOOLEAN): INTEGER;
|
||
|
RETURN BW * ORD(b)
|
||
|
END bw;
|
||
|
|
||
|
|
||
|
PROCEDURE src_x (x, Rn: INTEGER): INTEGER;
|
||
|
BEGIN
|
||
|
IdxWords.src := x
|
||
|
RETURN Rn * 256 + sIDX
|
||
|
END src_x;
|
||
|
|
||
|
|
||
|
PROCEDURE dst_x (x, Rn: INTEGER): INTEGER;
|
||
|
BEGIN
|
||
|
IdxWords.dst := x
|
||
|
RETURN Rn + dIDX
|
||
|
END dst_x;
|
||
|
|
||
|
|
||
|
PROCEDURE indir (Rn: INTEGER): INTEGER;
|
||
|
RETURN Rn * 256 + sINDIR
|
||
|
END indir;
|
||
|
|
||
|
|
||
|
PROCEDURE incr (Rn: INTEGER): INTEGER;
|
||
|
RETURN Rn * 256 + sINCR
|
||
|
END incr;
|
||
|
|
||
|
|
||
|
PROCEDURE imm (x: INTEGER): INTEGER;
|
||
|
VAR
|
||
|
res: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
CASE x OF
|
||
|
| 0: res := CG * 256
|
||
|
| 1: res := src_x(0, CG); IdxWords.src := NOWORD
|
||
|
| 2: res := indir(CG)
|
||
|
| 4: res := indir(SR)
|
||
|
| 8: res := incr(SR)
|
||
|
|-1: res := incr(CG)
|
||
|
ELSE
|
||
|
res := incr(PC);
|
||
|
IdxWords.src := x
|
||
|
END
|
||
|
|
||
|
RETURN res
|
||
|
END imm;
|
||
|
|
||
|
|
||
|
PROCEDURE Op2 (op, src, dst: INTEGER);
|
||
|
BEGIN
|
||
|
ASSERT(BITS(op) + {6, 12..15} = {6, 12..15});
|
||
|
ASSERT(BITS(src) + {4, 5, 8..11} = {4, 5, 8..11});
|
||
|
ASSERT(BITS(dst) + {0..3, 7} = {0..3, 7});
|
||
|
|
||
|
EmitWord(op + src + dst);
|
||
|
|
||
|
IF IdxWords.src # NOWORD THEN
|
||
|
EmitWord(IdxWords.src);
|
||
|
IdxWords.src := NOWORD
|
||
|
END;
|
||
|
|
||
|
IF IdxWords.dst # NOWORD THEN
|
||
|
EmitWord(IdxWords.dst);
|
||
|
IdxWords.dst := NOWORD
|
||
|
END
|
||
|
END Op2;
|
||
|
|
||
|
|
||
|
PROCEDURE Op1 (op, reg, As: INTEGER);
|
||
|
BEGIN
|
||
|
EmitWord(op + reg + As)
|
||
|
END Op1;
|
||
|
|
||
|
|
||
|
PROCEDURE MovRR (src, dst: INTEGER);
|
||
|
BEGIN
|
||
|
Op2(opMOV, src * 256, dst)
|
||
|
END MovRR;
|
||
|
|
||
|
|
||
|
PROCEDURE PushImm (imm: INTEGER);
|
||
|
BEGIN
|
||
|
imm := UTILS.Long(imm);
|
||
|
CASE imm OF
|
||
|
| 0: Op1(opPUSH, CG, sREG)
|
||
|
| 1: Op1(opPUSH, CG, sIDX)
|
||
|
| 2: Op1(opPUSH, CG, sINDIR)
|
||
|
|-1: Op1(opPUSH, CG, sINCR)
|
||
|
ELSE
|
||
|
Op1(opPUSH, PC, sINCR);
|
||
|
EmitWord(imm)
|
||
|
END
|
||
|
END PushImm;
|
||
|
|
||
|
|
||
|
PROCEDURE PutWord (word: INTEGER; VAR adr: INTEGER);
|
||
|
BEGIN
|
||
|
ASSERT(~ODD(adr));
|
||
|
ASSERT((0 <= word) & (word <= 65535));
|
||
|
mem[adr] := word MOD 256;
|
||
|
mem[adr + 1] := word DIV 256;
|
||
|
INC(adr, 2)
|
||
|
END PutWord;
|
||
|
|
||
|
|
||
|
PROCEDURE NewLabel (): INTEGER;
|
||
|
BEGIN
|
||
|
CHL.PushInt(Labels, 0)
|
||
|
RETURN IL.NewLabel()
|
||
|
END NewLabel;
|
||
|
|
||
|
|
||
|
PROCEDURE LabelOffs (n: INTEGER): INTEGER;
|
||
|
RETURN CHL.GetInt(Labels, n)
|
||
|
END LabelOffs;
|
||
|
|
||
|
|
||
|
PROCEDURE Fixup (CodeAdr, IntVectorSize: INTEGER): INTEGER;
|
||
|
VAR
|
||
|
cmd: ANYCODE;
|
||
|
adr: INTEGER;
|
||
|
offset: INTEGER;
|
||
|
diff: INTEGER;
|
||
|
cc: INTEGER;
|
||
|
shorted: BOOLEAN;
|
||
|
|
||
|
BEGIN
|
||
|
REPEAT
|
||
|
shorted := FALSE;
|
||
|
offset := CodeAdr DIV 2;
|
||
|
|
||
|
cmd := CodeList.first(ANYCODE);
|
||
|
WHILE cmd # NIL DO
|
||
|
cmd.offset := offset;
|
||
|
CASE cmd OF
|
||
|
|LABEL: CHL.SetInt(Labels, cmd.num, offset)
|
||
|
|JMP: INC(offset);
|
||
|
IF ~cmd.short THEN
|
||
|
INC(offset);
|
||
|
IF cmd.cc # opJMP THEN
|
||
|
INC(offset)
|
||
|
END
|
||
|
END
|
||
|
|
||
|
|CALL: INC(offset, 2)
|
||
|
|WORD: INC(offset)
|
||
|
END;
|
||
|
cmd := cmd.next(ANYCODE)
|
||
|
END;
|
||
|
|
||
|
cmd := CodeList.first(ANYCODE);
|
||
|
WHILE cmd # NIL DO
|
||
|
IF (cmd IS JMP) & ~cmd(JMP).short THEN
|
||
|
diff := LabelOffs(cmd(JMP).label) - cmd.offset - 1;
|
||
|
IF ABS(diff) <= 512 THEN
|
||
|
cmd(JMP).short := TRUE;
|
||
|
shorted := TRUE
|
||
|
END
|
||
|
END;
|
||
|
cmd := cmd.next(ANYCODE)
|
||
|
END
|
||
|
|
||
|
UNTIL ~shorted;
|
||
|
|
||
|
IF offset * 2 > 10000H - IntVectorSize THEN
|
||
|
ERRORS.Error(203)
|
||
|
END;
|
||
|
|
||
|
adr := CodeAdr;
|
||
|
cmd := CodeList.first(ANYCODE);
|
||
|
WHILE cmd # NIL DO
|
||
|
CASE cmd OF
|
||
|
|LABEL:
|
||
|
|
||
|
|JMP: IF ~cmd.short THEN
|
||
|
CASE cmd.cc OF
|
||
|
|opJNE: cc := opJEQ
|
||
|
|opJEQ: cc := opJNE
|
||
|
|opJNC: cc := opJC
|
||
|
|opJC: cc := opJNC
|
||
|
|opJGE: cc := opJL
|
||
|
|opJL: cc := opJGE
|
||
|
|opJMP: cc := opJMP
|
||
|
END;
|
||
|
|
||
|
IF cc # opJMP THEN
|
||
|
PutWord(cc + 2, adr) (* jcc L *)
|
||
|
END;
|
||
|
|
||
|
PutWord(4030H, adr); (* MOV @PC+, PC *)
|
||
|
PutWord(LabelOffs(cmd.label) * 2, adr)
|
||
|
(* L: *)
|
||
|
ELSE
|
||
|
diff := LabelOffs(cmd.label) - cmd.offset - 1;
|
||
|
ASSERT((-512 <= diff) & (diff <= 511));
|
||
|
PutWord(cmd.cc + diff MOD 1024, adr)
|
||
|
END
|
||
|
|
||
|
|CALL: PutWord(12B0H, adr); (* CALL @PC+ *)
|
||
|
PutWord(LabelOffs(cmd.label) * 2, adr)
|
||
|
|
||
|
|WORD: PutWord(cmd.val, adr)
|
||
|
|
||
|
END;
|
||
|
cmd := cmd.next(ANYCODE)
|
||
|
END
|
||
|
|
||
|
RETURN adr - CodeAdr
|
||
|
END Fixup;
|
||
|
|
||
|
|
||
|
PROCEDURE Push (reg: INTEGER);
|
||
|
BEGIN
|
||
|
Op1(opPUSH, reg, sREG)
|
||
|
END Push;
|
||
|
|
||
|
|
||
|
PROCEDURE Pop (reg: INTEGER);
|
||
|
BEGIN
|
||
|
Op2(opMOV, incr(SP), reg)
|
||
|
END Pop;
|
||
|
|
||
|
|
||
|
PROCEDURE Test (reg: INTEGER);
|
||
|
BEGIN
|
||
|
Op2(opCMP, imm(0), reg)
|
||
|
END Test;
|
||
|
|
||
|
|
||
|
PROCEDURE Clear (reg: INTEGER);
|
||
|
BEGIN
|
||
|
Op2(opMOV, imm(0), reg)
|
||
|
END Clear;
|
||
|
|
||
|
|
||
|
PROCEDURE mov (dst, src: INTEGER);
|
||
|
BEGIN
|
||
|
MovRR(src, dst)
|
||
|
END mov;
|
||
|
|
||
|
|
||
|
PROCEDURE xchg (reg1, reg2: INTEGER);
|
||
|
BEGIN
|
||
|
Push(reg1);
|
||
|
Push(reg2);
|
||
|
Pop(reg1);
|
||
|
Pop(reg2)
|
||
|
END xchg;
|
||
|
|
||
|
|
||
|
PROCEDURE Reloc (section: INTEGER);
|
||
|
VAR
|
||
|
reloc: RELOC;
|
||
|
|
||
|
BEGIN
|
||
|
NEW(reloc);
|
||
|
reloc.section := section;
|
||
|
reloc.WordPtr := CodeList.last(WORD);
|
||
|
LISTS.push(RelList, reloc)
|
||
|
END Reloc;
|
||
|
|
||
|
|
||
|
PROCEDURE CallRTL (proc, params: INTEGER);
|
||
|
BEGIN
|
||
|
EmitCall(RTL.rtl[proc].label);
|
||
|
RTL.Used(proc);
|
||
|
IF params > 0 THEN
|
||
|
Op2(opADD, imm(params * 2), SP)
|
||
|
END
|
||
|
END CallRTL;
|
||
|
|
||
|
|
||
|
PROCEDURE UnOp (VAR reg: INTEGER);
|
||
|
BEGIN
|
||
|
REG.UnOp(R, reg)
|
||
|
END UnOp;
|
||
|
|
||
|
|
||
|
PROCEDURE BinOp (VAR reg1, reg2: INTEGER);
|
||
|
BEGIN
|
||
|
REG.BinOp(R, reg1, reg2)
|
||
|
END BinOp;
|
||
|
|
||
|
|
||
|
PROCEDURE GetRegA;
|
||
|
BEGIN
|
||
|
ASSERT(REG.GetReg(R, ACC))
|
||
|
END GetRegA;
|
||
|
|
||
|
|
||
|
PROCEDURE drop;
|
||
|
BEGIN
|
||
|
REG.Drop(R)
|
||
|
END drop;
|
||
|
|
||
|
|
||
|
PROCEDURE GetAnyReg (): INTEGER;
|
||
|
RETURN REG.GetAnyReg(R)
|
||
|
END GetAnyReg;
|
||
|
|
||
|
|
||
|
PROCEDURE PushAll (NumberOfParameters: INTEGER);
|
||
|
BEGIN
|
||
|
REG.PushAll(R);
|
||
|
DEC(R.pushed, NumberOfParameters)
|
||
|
END PushAll;
|
||
|
|
||
|
|
||
|
PROCEDURE PushAll_1;
|
||
|
BEGIN
|
||
|
REG.PushAll_1(R)
|
||
|
END PushAll_1;
|
||
|
|
||
|
|
||
|
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 jcc (cc, label: INTEGER);
|
||
|
VAR
|
||
|
L: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
CASE cc OF
|
||
|
|jne:
|
||
|
EmitJmp(opJNE, label)
|
||
|
|je:
|
||
|
EmitJmp(opJEQ, label)
|
||
|
|jge:
|
||
|
EmitJmp(opJGE, label)
|
||
|
|jl:
|
||
|
EmitJmp(opJL, label)
|
||
|
|jle:
|
||
|
EmitJmp(opJL, label);
|
||
|
EmitJmp(opJEQ, label)
|
||
|
|jg:
|
||
|
L := NewLabel();
|
||
|
EmitJmp(opJEQ, L);
|
||
|
EmitJmp(opJGE, label);
|
||
|
EmitLabel(L)
|
||
|
|jb:
|
||
|
EmitJmp(opJNC, label)
|
||
|
END
|
||
|
END jcc;
|
||
|
|
||
|
|
||
|
PROCEDURE setcc (cc, reg: INTEGER);
|
||
|
VAR
|
||
|
L: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
L := NewLabel();
|
||
|
Op2(opMOV, imm(1), reg);
|
||
|
jcc(cc, L);
|
||
|
Clear(reg);
|
||
|
EmitLabel(L)
|
||
|
END setcc;
|
||
|
|
||
|
|
||
|
PROCEDURE Shift2 (op, reg, n: INTEGER);
|
||
|
VAR
|
||
|
reg2: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
IF n >= 8 THEN
|
||
|
CASE op OF
|
||
|
|IL.opASR2: Op1(opSWPB, reg, sREG); Op1(opSXT, reg, sREG)
|
||
|
|IL.opROR2: Op1(opSWPB, reg, sREG)
|
||
|
|IL.opLSL2: Op1(opSWPB, reg, sREG); Op2(opBIC, imm(255), reg)
|
||
|
|IL.opLSR2: Op2(opBIC, imm(255), reg); Op1(opSWPB, reg, sREG)
|
||
|
END;
|
||
|
DEC(n, 8)
|
||
|
END;
|
||
|
|
||
|
IF (op = IL.opROR2) & (n > 0) THEN
|
||
|
reg2 := GetAnyReg();
|
||
|
MovRR(reg, reg2)
|
||
|
ELSE
|
||
|
reg2 := -1
|
||
|
END;
|
||
|
|
||
|
WHILE n > 0 DO
|
||
|
CASE op OF
|
||
|
|IL.opASR2: Op1(opRRA, reg, sREG)
|
||
|
|IL.opROR2: Op1(opRRC, reg2, sREG); Op1(opRRC, reg, sREG)
|
||
|
|IL.opLSL2: Op2(opADD, reg * 256, reg)
|
||
|
|IL.opLSR2: Op2(opBIC, imm(1), SR); Op1(opRRC, reg, sREG)
|
||
|
END;
|
||
|
DEC(n)
|
||
|
END;
|
||
|
|
||
|
IF reg2 # -1 THEN
|
||
|
drop
|
||
|
END
|
||
|
|
||
|
END Shift2;
|
||
|
|
||
|
|
||
|
PROCEDURE Neg (reg: INTEGER);
|
||
|
BEGIN
|
||
|
Op2(opXOR, imm(-1), reg);
|
||
|
Op2(opADD, imm(1), reg)
|
||
|
END Neg;
|
||
|
|
||
|
|
||
|
PROCEDURE translate (code: IL.CODES);
|
||
|
VAR
|
||
|
cmd, next: COMMAND;
|
||
|
|
||
|
opcode, param1, param2, label, L, a, n, c1, c2: INTEGER;
|
||
|
|
||
|
reg1, reg2: INTEGER;
|
||
|
|
||
|
cc: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
cmd := code.commands.first(COMMAND);
|
||
|
|
||
|
WHILE cmd # NIL DO
|
||
|
|
||
|
param1 := cmd.param1;
|
||
|
param2 := cmd.param2;
|
||
|
|
||
|
opcode := cmd.opcode;
|
||
|
|
||
|
CASE opcode OF
|
||
|
|IL.opJMP:
|
||
|
EmitJmp(opJMP, param1)
|
||
|
|
||
|
|IL.opCALL:
|
||
|
EmitCall(param1)
|
||
|
|
||
|
|IL.opCALLP:
|
||
|
UnOp(reg1);
|
||
|
Op1(opCALL, reg1, sREG);
|
||
|
drop;
|
||
|
ASSERT(R.top = -1)
|
||
|
|
||
|
|IL.opPRECALL:
|
||
|
PushAll(0)
|
||
|
|
||
|
|IL.opLABEL:
|
||
|
EmitLabel(param1)
|
||
|
|
||
|
|IL.opSADR_PARAM:
|
||
|
Op1(opPUSH, PC, sINCR);
|
||
|
EmitWord(param2);
|
||
|
Reloc(RDATA)
|
||
|
|
||
|
|IL.opERR:
|
||
|
CallRTL(RTL._error, 2)
|
||
|
|
||
|
|IL.opPUSHC:
|
||
|
PushImm(param2)
|
||
|
|
||
|
|IL.opLEAVEC:
|
||
|
Pop(PC)
|
||
|
|
||
|
|IL.opENTER:
|
||
|
ASSERT(R.top = -1);
|
||
|
|
||
|
EmitLabel(param1);
|
||
|
|
||
|
Push(BP);
|
||
|
MovRR(SP, BP);
|
||
|
|
||
|
IF param2 > 8 THEN
|
||
|
Op2(opMOV, imm(param2), R4);
|
||
|
L := NewLabel();
|
||
|
EmitLabel(L);
|
||
|
Push(CG);
|
||
|
Op2(opSUB, imm(1), R4);
|
||
|
jcc(jne, L)
|
||
|
ELSIF param2 > 0 THEN
|
||
|
WHILE param2 > 0 DO
|
||
|
Push(CG);
|
||
|
DEC(param2)
|
||
|
END
|
||
|
END
|
||
|
|
||
|
|IL.opLEAVE, IL.opLEAVER:
|
||
|
ASSERT(param2 = 0);
|
||
|
IF opcode = IL.opLEAVER THEN
|
||
|
UnOp(reg1);
|
||
|
IF reg1 # ACC THEN
|
||
|
GetRegA;
|
||
|
ASSERT(REG.Exchange(R, reg1, ACC));
|
||
|
drop
|
||
|
END;
|
||
|
drop
|
||
|
END;
|
||
|
|
||
|
ASSERT(R.top = -1);
|
||
|
|
||
|
IF param1 > 0 THEN
|
||
|
MovRR(BP, SP)
|
||
|
END;
|
||
|
|
||
|
Pop(BP);
|
||
|
Pop(PC)
|
||
|
|
||
|
|IL.opRES:
|
||
|
ASSERT(R.top = -1);
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opCLEANUP:
|
||
|
IF param2 # 0 THEN
|
||
|
Op2(opADD, imm(param2 * 2), SP)
|
||
|
END
|
||
|
|
||
|
|IL.opCONST:
|
||
|
next := cmd.next(COMMAND);
|
||
|
IF next.opcode = IL.opCONST THEN
|
||
|
c1 := param2;
|
||
|
c2 := next.param2;
|
||
|
next := next.next(COMMAND);
|
||
|
IF (next.opcode = IL.opSAVE) OR (next.opcode = IL.opSAVE16) OR (next.opcode = IL.opSAVE8) THEN
|
||
|
Op2(opMOV + bw(next.opcode = IL.opSAVE8), imm(c1), dst_x(c2, SR));
|
||
|
cmd := next
|
||
|
ELSE
|
||
|
Op2(opMOV, imm(param2), GetAnyReg())
|
||
|
END
|
||
|
ELSIF (next.opcode = IL.opSAVE) OR (next.opcode = IL.opSAVE16) OR (next.opcode = IL.opSAVE8) THEN
|
||
|
UnOp(reg1);
|
||
|
Op2(opMOV + bw(next.opcode = IL.opSAVE8), reg1 * 256, dst_x(param2, SR));
|
||
|
drop;
|
||
|
cmd := next
|
||
|
ELSE
|
||
|
Op2(opMOV, imm(param2), GetAnyReg())
|
||
|
END
|
||
|
|
||
|
|IL.opSADR:
|
||
|
Op2(opMOV, incr(PC), GetAnyReg());
|
||
|
EmitWord(param2);
|
||
|
Reloc(RDATA)
|
||
|
|
||
|
|IL.opGADR:
|
||
|
Op2(opMOV, incr(PC), GetAnyReg());
|
||
|
EmitWord(param2);
|
||
|
Reloc(RBSS)
|
||
|
|
||
|
|IL.opLADR:
|
||
|
reg1 := GetAnyReg();
|
||
|
MovRR(BP, reg1);
|
||
|
Op2(opADD, imm(param2 * 2), reg1)
|
||
|
|
||
|
|IL.opLLOAD8:
|
||
|
Op2(opMOV + BW, src_x(param2 * 2, BP), GetAnyReg())
|
||
|
|
||
|
|IL.opLLOAD16, IL.opVADR:
|
||
|
Op2(opMOV, src_x(param2 * 2, BP), GetAnyReg())
|
||
|
|
||
|
|IL.opGLOAD8:
|
||
|
Op2(opMOV + BW, src_x(param2, SR), GetAnyReg());
|
||
|
Reloc(RBSS)
|
||
|
|
||
|
|IL.opGLOAD16:
|
||
|
Op2(opMOV, src_x(param2, SR), GetAnyReg());
|
||
|
Reloc(RBSS)
|
||
|
|
||
|
|IL.opLOAD8:
|
||
|
UnOp(reg1);
|
||
|
Op2(opMOV + BW, indir(reg1), reg1)
|
||
|
|
||
|
|IL.opLOAD16:
|
||
|
UnOp(reg1);
|
||
|
Op2(opMOV, indir(reg1), reg1)
|
||
|
|
||
|
|IL.opVLOAD8:
|
||
|
reg1 := GetAnyReg();
|
||
|
Op2(opMOV, src_x(param2 * 2, BP), reg1);
|
||
|
Op2(opMOV + BW, indir(reg1), reg1)
|
||
|
|
||
|
|IL.opVLOAD16:
|
||
|
reg1 := GetAnyReg();
|
||
|
Op2(opMOV, src_x(param2 * 2, BP), reg1);
|
||
|
Op2(opMOV, indir(reg1), reg1)
|
||
|
|
||
|
|IL.opSAVE, IL.opSAVE16:
|
||
|
BinOp(reg2, reg1);
|
||
|
Op2(opMOV, reg2 * 256, dst_x(0, reg1));
|
||
|
drop;
|
||
|
drop
|
||
|
|
||
|
|IL.opSAVE8:
|
||
|
BinOp(reg2, reg1);
|
||
|
Op2(opMOV + BW, reg2 * 256, dst_x(0, reg1));
|
||
|
drop;
|
||
|
drop
|
||
|
|
||
|
|IL.opSAVE8C:
|
||
|
UnOp(reg1);
|
||
|
Op2(opMOV + BW, imm(param2), dst_x(0, reg1));
|
||
|
drop
|
||
|
|
||
|
|IL.opSAVE16C, IL.opSAVEC:
|
||
|
UnOp(reg1);
|
||
|
Op2(opMOV, imm(param2), dst_x(0, reg1));
|
||
|
drop
|
||
|
|
||
|
|IL.opUMINUS:
|
||
|
UnOp(reg1);
|
||
|
Neg(reg1)
|
||
|
|
||
|
|IL.opADD:
|
||
|
BinOp(reg1, reg2);
|
||
|
Op2(opADD, reg2 * 256, reg1);
|
||
|
drop
|
||
|
|
||
|
|IL.opADDL, IL.opADDR:
|
||
|
IF param2 # 0 THEN
|
||
|
UnOp(reg1);
|
||
|
Op2(opADD, imm(param2), reg1)
|
||
|
END
|
||
|
|
||
|
|IL.opSUB:
|
||
|
BinOp(reg1, reg2);
|
||
|
Op2(opSUB, reg2 * 256, reg1);
|
||
|
drop
|
||
|
|
||
|
|IL.opSUBR, IL.opSUBL:
|
||
|
UnOp(reg1);
|
||
|
IF param2 # 0 THEN
|
||
|
Op2(opSUB, imm(param2), reg1)
|
||
|
END;
|
||
|
IF opcode = IL.opSUBL THEN
|
||
|
reg2 := GetAnyReg();
|
||
|
Clear(reg2);
|
||
|
Op2(opSUB, reg1 * 256, reg2);
|
||
|
drop;
|
||
|
drop;
|
||
|
ASSERT(REG.GetReg(R, reg2))
|
||
|
END
|
||
|
|
||
|
|IL.opLADR_SAVEC:
|
||
|
Op2(opMOV, imm(param2), dst_x(param1 * 2, BP))
|
||
|
|
||
|
|IL.opLADR_SAVE:
|
||
|
UnOp(reg1);
|
||
|
Op2(opMOV, reg1 * 256, dst_x(param2 * 2, BP));
|
||
|
drop
|
||
|
|
||
|
|IL.opGADR_SAVEC:
|
||
|
Op2(opMOV, imm(param2), dst_x(param1, SR));
|
||
|
Reloc(RBSS)
|
||
|
|
||
|
|IL.opCONST_PARAM:
|
||
|
PushImm(param2)
|
||
|
|
||
|
|IL.opPARAM:
|
||
|
IF param2 = 1 THEN
|
||
|
UnOp(reg1);
|
||
|
Push(reg1);
|
||
|
drop
|
||
|
ELSE
|
||
|
ASSERT(R.top + 1 <= param2);
|
||
|
PushAll(param2)
|
||
|
END
|
||
|
|
||
|
|IL.opEQ..IL.opGE,
|
||
|
IL.opEQC..IL.opGEC:
|
||
|
|
||
|
IF (IL.opEQ <= opcode) & (opcode <= IL.opGE) THEN
|
||
|
BinOp(reg1, reg2);
|
||
|
Op2(opCMP, reg2 * 256, reg1);
|
||
|
drop
|
||
|
ELSE
|
||
|
UnOp(reg1);
|
||
|
Op2(opCMP, imm(param2), reg1)
|
||
|
END;
|
||
|
|
||
|
drop;
|
||
|
cc := cond(opcode);
|
||
|
|
||
|
IF cmd.next(COMMAND).opcode = IL.opJE THEN
|
||
|
label := cmd.next(COMMAND).param1;
|
||
|
jcc(cc, label);
|
||
|
cmd := cmd.next(COMMAND)
|
||
|
|
||
|
ELSIF cmd.next(COMMAND).opcode = IL.opJNE THEN
|
||
|
label := cmd.next(COMMAND).param1;
|
||
|
jcc(ORD(BITS(cc) / {0}), label);
|
||
|
cmd := cmd.next(COMMAND)
|
||
|
|
||
|
ELSE
|
||
|
setcc(cc, GetAnyReg())
|
||
|
END
|
||
|
|
||
|
|IL.opNOP:
|
||
|
|
||
|
|IL.opCODE:
|
||
|
EmitWord(param2)
|
||
|
|
||
|
|IL.opACC:
|
||
|
IF (R.top # 0) OR (R.stk[0] # ACC) THEN
|
||
|
PushAll(0);
|
||
|
GetRegA;
|
||
|
Pop(ACC);
|
||
|
DEC(R.pushed)
|
||
|
END
|
||
|
|
||
|
|IL.opDROP:
|
||
|
UnOp(reg1);
|
||
|
drop
|
||
|
|
||
|
|IL.opJNZ:
|
||
|
UnOp(reg1);
|
||
|
Test(reg1);
|
||
|
jcc(jne, param1)
|
||
|
|
||
|
|IL.opJZ:
|
||
|
UnOp(reg1);
|
||
|
Test(reg1);
|
||
|
jcc(je, param1)
|
||
|
|
||
|
|IL.opJG:
|
||
|
UnOp(reg1);
|
||
|
Test(reg1);
|
||
|
jcc(jg, param1)
|
||
|
|
||
|
|IL.opJE:
|
||
|
UnOp(reg1);
|
||
|
Test(reg1);
|
||
|
jcc(jne, param1);
|
||
|
drop
|
||
|
|
||
|
|IL.opJNE:
|
||
|
UnOp(reg1);
|
||
|
Test(reg1);
|
||
|
jcc(je, param1);
|
||
|
drop
|
||
|
|
||
|
|IL.opNOT:
|
||
|
UnOp(reg1);
|
||
|
Test(reg1);
|
||
|
setcc(je, reg1)
|
||
|
|
||
|
|IL.opORD:
|
||
|
UnOp(reg1);
|
||
|
Test(reg1);
|
||
|
setcc(jne, reg1)
|
||
|
|
||
|
|IL.opLOOP:
|
||
|
|IL.opENDLOOP:
|
||
|
|
||
|
|IL.opGET:
|
||
|
BinOp(reg1, reg2);
|
||
|
drop;
|
||
|
drop;
|
||
|
Op2(opMOV + bw(param2 = 1), indir(reg1), dst_x(0, reg2))
|
||
|
|
||
|
|IL.opGETC:
|
||
|
UnOp(reg2);
|
||
|
drop;
|
||
|
Op2(opMOV + bw(param2 = 1), src_x(param1, SR), dst_x(0, reg2))
|
||
|
|
||
|
|IL.opCHKIDX:
|
||
|
UnOp(reg1);
|
||
|
Op2(opCMP, imm(param2), reg1);
|
||
|
jcc(jb, param1)
|
||
|
|
||
|
|IL.opCHKIDX2:
|
||
|
BinOp(reg1, reg2);
|
||
|
IF param2 # -1 THEN
|
||
|
Op2(opCMP, reg1 * 256, reg2);
|
||
|
MovRR(reg2, reg1);
|
||
|
drop;
|
||
|
jcc(jb, param1)
|
||
|
ELSE
|
||
|
INCL(R.regs, reg1);
|
||
|
DEC(R.top);
|
||
|
R.stk[R.top] := reg2
|
||
|
END
|
||
|
|
||
|
|IL.opINCC, IL.opINCCB:
|
||
|
UnOp(reg1);
|
||
|
Op2(opADD + bw(opcode = IL.opINCCB), imm(param2), dst_x(0, reg1));
|
||
|
drop
|
||
|
|
||
|
|IL.opDECCB:
|
||
|
UnOp(reg1);
|
||
|
Op2(opSUB + BW, imm(param2), dst_x(0, reg1));
|
||
|
drop
|
||
|
|
||
|
|IL.opINC, IL.opINCB:
|
||
|
BinOp(reg1, reg2);
|
||
|
Op2(opADD + bw(opcode = IL.opINCB), reg1 * 256, dst_x(0, reg2));
|
||
|
drop;
|
||
|
drop
|
||
|
|
||
|
|IL.opDEC, IL.opDECB:
|
||
|
BinOp(reg1, reg2);
|
||
|
Op2(opSUB + bw(opcode = IL.opDECB), reg1 * 256, dst_x(0, reg2));
|
||
|
drop;
|
||
|
drop
|
||
|
|
||
|
|IL.opLADR_INCC, IL.opLADR_INCCB:
|
||
|
Op2(opADD + bw(opcode = IL.opLADR_INCCB), imm(param2), dst_x(param1 * 2, BP))
|
||
|
|
||
|
|IL.opLADR_DECCB:
|
||
|
Op2(opSUB + BW, imm(param2), dst_x(param1 * 2, BP))
|
||
|
|
||
|
|IL.opLADR_INC, IL.opLADR_INCB:
|
||
|
UnOp(reg1);
|
||
|
Op2(opADD + bw(opcode = IL.opLADR_INCB), reg1 * 256, dst_x(param2 * 2, BP));
|
||
|
drop
|
||
|
|
||
|
|IL.opLADR_DEC, IL.opLADR_DECB:
|
||
|
UnOp(reg1);
|
||
|
Op2(opSUB + bw(opcode = IL.opLADR_DECB), reg1 * 256, dst_x(param2 * 2, BP));
|
||
|
drop
|
||
|
|
||
|
|IL.opPUSHT:
|
||
|
UnOp(reg1);
|
||
|
Op2(opMOV, src_x(-2, reg1), GetAnyReg())
|
||
|
|
||
|
|IL.opISREC:
|
||
|
PushAll(2);
|
||
|
PushImm(param2);
|
||
|
CallRTL(RTL._guardrec, 3);
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opIS:
|
||
|
PushAll(1);
|
||
|
PushImm(param2);
|
||
|
CallRTL(RTL._is, 2);
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opTYPEGR:
|
||
|
PushAll(1);
|
||
|
PushImm(param2);
|
||
|
CallRTL(RTL._guardrec, 2);
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opTYPEGP:
|
||
|
UnOp(reg1);
|
||
|
PushAll(0);
|
||
|
Push(reg1);
|
||
|
PushImm(param2);
|
||
|
CallRTL(RTL._guard, 2);
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opTYPEGD:
|
||
|
UnOp(reg1);
|
||
|
PushAll(0);
|
||
|
Op1(opPUSH, reg1, sIDX);
|
||
|
EmitWord(-2);
|
||
|
PushImm(param2);
|
||
|
CallRTL(RTL._guardrec, 2);
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opMULS:
|
||
|
BinOp(reg1, reg2);
|
||
|
Op2(opAND, reg2 * 256, reg1);
|
||
|
drop
|
||
|
|
||
|
|IL.opMULSC:
|
||
|
UnOp(reg1);
|
||
|
Op2(opAND, imm(param2), reg1)
|
||
|
|
||
|
|IL.opDIVS:
|
||
|
BinOp(reg1, reg2);
|
||
|
Op2(opXOR, reg2 * 256, reg1);
|
||
|
drop
|
||
|
|
||
|
|IL.opDIVSC:
|
||
|
UnOp(reg1);
|
||
|
Op2(opXOR, imm(param2), reg1)
|
||
|
|
||
|
|IL.opADDS:
|
||
|
BinOp(reg1, reg2);
|
||
|
Op2(opBIS, reg2 * 256, reg1);
|
||
|
drop
|
||
|
|
||
|
|IL.opSUBS:
|
||
|
BinOp(reg1, reg2);
|
||
|
Op2(opBIC, reg2 * 256, reg1);
|
||
|
drop
|
||
|
|
||
|
|IL.opADDSL, IL.opADDSR:
|
||
|
UnOp(reg1);
|
||
|
Op2(opBIS, imm(param2), reg1)
|
||
|
|
||
|
|IL.opSUBSL:
|
||
|
UnOp(reg1);
|
||
|
Op2(opXOR, imm(-1), reg1);
|
||
|
Op2(opAND, imm(param2), reg1)
|
||
|
|
||
|
|IL.opSUBSR:
|
||
|
UnOp(reg1);
|
||
|
Op2(opBIC, imm(param2), reg1)
|
||
|
|
||
|
|IL.opUMINS:
|
||
|
UnOp(reg1);
|
||
|
Op2(opXOR, imm(-1), reg1)
|
||
|
|
||
|
|IL.opLENGTH:
|
||
|
PushAll(2);
|
||
|
CallRTL(RTL._length, 2);
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opMIN:
|
||
|
BinOp(reg1, reg2);
|
||
|
Op2(opCMP, reg2 * 256, reg1);
|
||
|
EmitWord(opJL + 1); (* jl L *)
|
||
|
MovRR(reg2, reg1);
|
||
|
(* L: *)
|
||
|
drop
|
||
|
|
||
|
|
||
|
|IL.opMAX:
|
||
|
BinOp(reg1, reg2);
|
||
|
Op2(opCMP, reg2 * 256, reg1);
|
||
|
EmitWord(opJGE + 1); (* jge L *)
|
||
|
MovRR(reg2, reg1);
|
||
|
(* L: *)
|
||
|
drop
|
||
|
|
||
|
|IL.opMINC:
|
||
|
UnOp(reg1);
|
||
|
Op2(opCMP, imm(param2), reg1);
|
||
|
L := NewLabel();
|
||
|
jcc(jl, L);
|
||
|
Op2(opMOV, imm(param2), reg1);
|
||
|
EmitLabel(L)
|
||
|
|
||
|
|IL.opMAXC:
|
||
|
UnOp(reg1);
|
||
|
Op2(opCMP, imm(param2), reg1);
|
||
|
L := NewLabel();
|
||
|
jcc(jge, L);
|
||
|
Op2(opMOV, imm(param2), reg1);
|
||
|
EmitLabel(L)
|
||
|
|
||
|
|IL.opSWITCH:
|
||
|
UnOp(reg1);
|
||
|
IF param2 = 0 THEN
|
||
|
reg2 := ACC
|
||
|
ELSE
|
||
|
reg2 := R5
|
||
|
END;
|
||
|
IF reg1 # reg2 THEN
|
||
|
ASSERT(REG.GetReg(R, reg2));
|
||
|
ASSERT(REG.Exchange(R, reg1, reg2));
|
||
|
drop
|
||
|
END;
|
||
|
drop
|
||
|
|
||
|
|IL.opENDSW:
|
||
|
|
||
|
|IL.opCASEL:
|
||
|
Op2(opCMP, imm(param1), ACC);
|
||
|
jcc(jl, param2)
|
||
|
|
||
|
|IL.opCASER:
|
||
|
Op2(opCMP, imm(param1), ACC);
|
||
|
jcc(jg, param2)
|
||
|
|
||
|
|IL.opCASELR:
|
||
|
Op2(opCMP, imm(param1), ACC);
|
||
|
jcc(jl, param2);
|
||
|
jcc(jg, cmd.param3)
|
||
|
|
||
|
|IL.opSBOOL:
|
||
|
BinOp(reg2, reg1);
|
||
|
Test(reg2);
|
||
|
setcc(jne, reg2);
|
||
|
Op2(opMOV + BW, reg2 * 256, dst_x(0, reg1));
|
||
|
drop;
|
||
|
drop
|
||
|
|
||
|
|IL.opSBOOLC:
|
||
|
UnOp(reg1);
|
||
|
Op2(opMOV + BW, imm(param2), dst_x(0, reg1));
|
||
|
drop
|
||
|
|
||
|
|IL.opODD:
|
||
|
UnOp(reg1);
|
||
|
Op2(opAND, imm(1), reg1)
|
||
|
|
||
|
|IL.opEQS .. IL.opGES:
|
||
|
PushAll(4);
|
||
|
PushImm((opcode - IL.opEQS) * 12);
|
||
|
CallRTL(RTL._strcmp, 5);
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opLEN:
|
||
|
UnOp(reg1);
|
||
|
drop;
|
||
|
EXCL(R.regs, reg1);
|
||
|
|
||
|
WHILE param2 > 0 DO
|
||
|
UnOp(reg2);
|
||
|
drop;
|
||
|
DEC(param2)
|
||
|
END;
|
||
|
|
||
|
INCL(R.regs, reg1);
|
||
|
ASSERT(REG.GetReg(R, reg1))
|
||
|
|
||
|
|IL.opCHKBYTE:
|
||
|
BinOp(reg1, reg2);
|
||
|
Op2(opCMP, imm(256), reg1);
|
||
|
jcc(jb, param1)
|
||
|
|
||
|
|IL.opLSL, IL.opASR, IL.opROR, IL.opLSR:
|
||
|
PushAll(2);
|
||
|
CASE opcode OF
|
||
|
|IL.opLSL: CallRTL(RTL._lsl, 2)
|
||
|
|IL.opASR: CallRTL(RTL._asr, 2)
|
||
|
|IL.opROR: CallRTL(RTL._ror, 2)
|
||
|
|IL.opLSR: CallRTL(RTL._lsr, 2)
|
||
|
END;
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opLSL1, IL.opASR1, IL.opROR1, IL.opLSR1:
|
||
|
UnOp(reg1);
|
||
|
PushAll_1;
|
||
|
PushImm(param2);
|
||
|
Push(reg1);
|
||
|
drop;
|
||
|
CASE opcode OF
|
||
|
|IL.opLSL1: CallRTL(RTL._lsl, 2)
|
||
|
|IL.opASR1: CallRTL(RTL._asr, 2)
|
||
|
|IL.opROR1: CallRTL(RTL._ror, 2)
|
||
|
|IL.opLSR1: CallRTL(RTL._lsr, 2)
|
||
|
END;
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opASR2, IL.opROR2, IL.opLSL2, IL.opLSR2:
|
||
|
param2 := param2 MOD 16;
|
||
|
IF param2 # 0 THEN
|
||
|
UnOp(reg1);
|
||
|
Shift2(opcode, reg1, param2)
|
||
|
END
|
||
|
|
||
|
|IL.opMUL:
|
||
|
PushAll(2);
|
||
|
CallRTL(RTL._mul, 2);
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opMULC:
|
||
|
UnOp(reg1);
|
||
|
|
||
|
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(reg1)
|
||
|
ELSIF a = 0 THEN
|
||
|
Clear(reg1)
|
||
|
ELSE
|
||
|
IF n > 0 THEN
|
||
|
IF a < 0 THEN
|
||
|
Neg(reg1)
|
||
|
END;
|
||
|
Shift2(IL.opLSL2, reg1, n)
|
||
|
ELSE
|
||
|
PushAll(1);
|
||
|
PushImm(a);
|
||
|
CallRTL(RTL._mul, 2);
|
||
|
GetRegA
|
||
|
END
|
||
|
END
|
||
|
|
||
|
|IL.opDIV:
|
||
|
PushAll(2);
|
||
|
CallRTL(RTL._divmod, 2);
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opDIVR:
|
||
|
ASSERT(param2 > 0);
|
||
|
|
||
|
IF param2 > 1 THEN
|
||
|
n := UTILS.Log2(param2);
|
||
|
IF n > 0 THEN
|
||
|
UnOp(reg1);
|
||
|
Shift2(IL.opASR2, reg1, n)
|
||
|
ELSE
|
||
|
PushAll(1);
|
||
|
PushImm(param2);
|
||
|
CallRTL(RTL._divmod, 2);
|
||
|
GetRegA
|
||
|
END
|
||
|
END
|
||
|
|
||
|
|IL.opDIVL:
|
||
|
UnOp(reg1);
|
||
|
PushAll_1;
|
||
|
PushImm(param2);
|
||
|
Push(reg1);
|
||
|
drop;
|
||
|
CallRTL(RTL._divmod, 2);
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opMOD:
|
||
|
PushAll(2);
|
||
|
CallRTL(RTL._divmod, 2);
|
||
|
ASSERT(REG.GetReg(R, R5))
|
||
|
|
||
|
|IL.opMODR:
|
||
|
ASSERT(param2 > 0);
|
||
|
|
||
|
IF param2 = 1 THEN
|
||
|
UnOp(reg1);
|
||
|
Clear(reg1)
|
||
|
ELSE
|
||
|
IF UTILS.Log2(param2) > 0 THEN
|
||
|
UnOp(reg1);
|
||
|
Op2(opAND, imm(param2 - 1), reg1)
|
||
|
ELSE
|
||
|
PushAll(1);
|
||
|
PushImm(param2);
|
||
|
CallRTL(RTL._divmod, 2);
|
||
|
ASSERT(REG.GetReg(R, R5))
|
||
|
END
|
||
|
END
|
||
|
|
||
|
|IL.opMODL:
|
||
|
UnOp(reg1);
|
||
|
PushAll_1;
|
||
|
PushImm(param2);
|
||
|
Push(reg1);
|
||
|
drop;
|
||
|
CallRTL(RTL._divmod, 2);
|
||
|
ASSERT(REG.GetReg(R, R5))
|
||
|
|
||
|
|IL.opCOPYS:
|
||
|
ASSERT(R.top = 3);
|
||
|
Push(R.stk[2]);
|
||
|
Push(R.stk[0]);
|
||
|
Op2(opCMP, R.stk[1] * 256, R.stk[3]);
|
||
|
EmitWord(3801H); (* JL L1 *)
|
||
|
MovRR(R.stk[1], R.stk[3]);
|
||
|
(* L1: *)
|
||
|
Push(R.stk[3]);
|
||
|
drop;
|
||
|
drop;
|
||
|
drop;
|
||
|
drop;
|
||
|
CallRTL(RTL._move, 3)
|
||
|
|
||
|
|IL.opCOPY:
|
||
|
PushAll(2);
|
||
|
PushImm(param2);
|
||
|
CallRTL(RTL._move, 3)
|
||
|
|
||
|
|IL.opMOVE:
|
||
|
PushAll(3);
|
||
|
CallRTL(RTL._move, 3)
|
||
|
|
||
|
|IL.opCOPYA:
|
||
|
PushAll(4);
|
||
|
PushImm(param2);
|
||
|
CallRTL(RTL._arrcpy, 5);
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opROT:
|
||
|
PushAll(0);
|
||
|
MovRR(SP, ACC);
|
||
|
Push(ACC);
|
||
|
PushImm(param2);
|
||
|
CallRTL(RTL._rot, 2)
|
||
|
|
||
|
|IL.opSAVES:
|
||
|
UnOp(reg1);
|
||
|
PushAll_1;
|
||
|
Op1(opPUSH, PC, sINCR);
|
||
|
EmitWord(param2);
|
||
|
Reloc(RDATA);
|
||
|
Push(reg1);
|
||
|
drop;
|
||
|
PushImm(param1);
|
||
|
CallRTL(RTL._move, 3)
|
||
|
|
||
|
|IL.opCASET:
|
||
|
Push(R5);
|
||
|
Push(R5);
|
||
|
PushImm(param2);
|
||
|
CallRTL(RTL._guardrec, 2);
|
||
|
Pop(R5);
|
||
|
Test(ACC);
|
||
|
jcc(jne, param1)
|
||
|
|
||
|
|IL.opCHR:
|
||
|
UnOp(reg1);
|
||
|
Op2(opAND, imm(255), reg1)
|
||
|
|
||
|
|IL.opABS:
|
||
|
UnOp(reg1);
|
||
|
Test(reg1);
|
||
|
L := NewLabel();
|
||
|
jcc(jge, L);
|
||
|
Neg(reg1);
|
||
|
EmitLabel(L)
|
||
|
|
||
|
|IL.opEQB, IL.opNEB:
|
||
|
BinOp(reg1, reg2);
|
||
|
drop;
|
||
|
|
||
|
Test(reg1);
|
||
|
L := NewLabel();
|
||
|
jcc(je, L);
|
||
|
Op2(opMOV, imm(1), reg1);
|
||
|
EmitLabel(L);
|
||
|
|
||
|
Test(reg2);
|
||
|
L := NewLabel();
|
||
|
jcc(je, L);
|
||
|
Op2(opMOV, imm(1), reg2);
|
||
|
EmitLabel(L);
|
||
|
|
||
|
Op2(opCMP, reg2 * 256, reg1);
|
||
|
IF opcode = IL.opEQB THEN
|
||
|
setcc(je, reg1)
|
||
|
ELSE
|
||
|
setcc(jne, reg1)
|
||
|
END
|
||
|
|
||
|
|IL.opSAVEP:
|
||
|
UnOp(reg1);
|
||
|
Op2(opMOV, incr(PC), reg1 + dIDX);
|
||
|
EmitWord(param2);
|
||
|
Reloc(RCODE);
|
||
|
EmitWord(0);
|
||
|
drop
|
||
|
|
||
|
|IL.opPUSHP:
|
||
|
Op2(opMOV, incr(PC), GetAnyReg());
|
||
|
EmitWord(param2);
|
||
|
Reloc(RCODE)
|
||
|
|
||
|
|IL.opEQP, IL.opNEP:
|
||
|
UnOp(reg1);
|
||
|
Op2(opCMP, incr(PC), reg1);
|
||
|
EmitWord(param1);
|
||
|
Reloc(RCODE);
|
||
|
drop;
|
||
|
reg1 := GetAnyReg();
|
||
|
|
||
|
IF opcode = IL.opEQP THEN
|
||
|
setcc(je, reg1)
|
||
|
ELSIF opcode = IL.opNEP THEN
|
||
|
setcc(jne, reg1)
|
||
|
END
|
||
|
|
||
|
|IL.opVADR_PARAM:
|
||
|
Op1(opPUSH, BP, sIDX);
|
||
|
EmitWord(param2 * 2)
|
||
|
|
||
|
|IL.opNEW:
|
||
|
PushAll(1);
|
||
|
n := param2 + 2;
|
||
|
ASSERT(UTILS.Align(n, 2));
|
||
|
PushImm(n);
|
||
|
PushImm(param1);
|
||
|
CallRTL(RTL._new, 3)
|
||
|
|
||
|
|IL.opRSET:
|
||
|
PushAll(2);
|
||
|
CallRTL(RTL._set, 2);
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opRSETR:
|
||
|
PushAll(1);
|
||
|
PushImm(param2);
|
||
|
CallRTL(RTL._set, 2);
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opRSETL:
|
||
|
UnOp(reg1);
|
||
|
PushAll_1;
|
||
|
PushImm(param2);
|
||
|
Push(reg1);
|
||
|
drop;
|
||
|
CallRTL(RTL._set, 2);
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opRSET1:
|
||
|
PushAll(1);
|
||
|
CallRTL(RTL._set1, 1);
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opINCLC:
|
||
|
UnOp(reg1);
|
||
|
Op2(opBIS, imm(ORD({param2})), dst_x(0, reg1));
|
||
|
drop
|
||
|
|
||
|
|IL.opEXCLC:
|
||
|
UnOp(reg1);
|
||
|
Op2(opBIC, imm(ORD({param2})), dst_x(0, reg1));
|
||
|
drop
|
||
|
|
||
|
|IL.opIN:
|
||
|
PushAll(2);
|
||
|
CallRTL(RTL._in, 2);
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opINR:
|
||
|
PushAll(1);
|
||
|
PushImm(param2);
|
||
|
CallRTL(RTL._in, 2);
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opINL:
|
||
|
PushAll(1);
|
||
|
PushImm(param2);
|
||
|
CallRTL(RTL._in2, 2);
|
||
|
GetRegA
|
||
|
|
||
|
|IL.opINCL:
|
||
|
PushAll(2);
|
||
|
CallRTL(RTL._incl, 2)
|
||
|
|
||
|
|IL.opEXCL:
|
||
|
PushAll(2);
|
||
|
CallRTL(RTL._excl, 2)
|
||
|
|
||
|
|IL.opLADR_INCL, IL.opLADR_EXCL:
|
||
|
PushAll(1);
|
||
|
MovRR(BP, ACC);
|
||
|
Op2(opADD, imm(param2 * 2), ACC);
|
||
|
Push(ACC);
|
||
|
IF opcode = IL.opLADR_INCL THEN
|
||
|
CallRTL(RTL._incl, 2)
|
||
|
ELSIF opcode = IL.opLADR_EXCL THEN
|
||
|
CallRTL(RTL._excl, 2)
|
||
|
END
|
||
|
|
||
|
|IL.opLADR_INCLC:
|
||
|
Op2(opBIS, imm(ORD({param2})), dst_x(param1 * 2, BP))
|
||
|
|
||
|
|IL.opLADR_EXCLC:
|
||
|
Op2(opBIC, imm(ORD({param2})), dst_x(param1 * 2, BP))
|
||
|
|
||
|
END;
|
||
|
|
||
|
cmd := cmd.next(COMMAND)
|
||
|
END;
|
||
|
|
||
|
ASSERT(R.pushed = 0);
|
||
|
ASSERT(R.top = -1)
|
||
|
END translate;
|
||
|
|
||
|
|
||
|
PROCEDURE prolog (ramSize: INTEGER);
|
||
|
VAR
|
||
|
i: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
RTL.Init(EmitLabel, EmitWord, EmitCall, ramSize);
|
||
|
FOR i := 0 TO LEN(RTL.rtl) - 1 DO
|
||
|
RTL.Set(i, NewLabel())
|
||
|
END;
|
||
|
|
||
|
IV[LEN(IV) - 1] := NewLabel();
|
||
|
EmitLabel(IV[LEN(IV) - 1]);
|
||
|
Op2(opMOV, incr(PC), SP);
|
||
|
EmitWord(0);
|
||
|
Op2(opMOV, incr(PC), HP);
|
||
|
EmitWord(0);
|
||
|
Op2(opMOV, imm(5A80H), dst_x(0120H, SR)); (* stop WDT *)
|
||
|
Op2(opMOV, imm(RTL.empty_proc), dst_x(RTL.int, SR));
|
||
|
Op2(opMOV, imm(0), dst_x(RTL.trap, SR))
|
||
|
END prolog;
|
||
|
|
||
|
|
||
|
PROCEDURE epilog;
|
||
|
VAR
|
||
|
L1, i: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
Op2(opBIS, imm(10H), SR); (* CPUOFF *)
|
||
|
|
||
|
L1 := NewLabel();
|
||
|
FOR i := 0 TO LEN(IV) - 2 DO
|
||
|
IV[i] := NewLabel();
|
||
|
EmitLabel(IV[i]);
|
||
|
PushImm(i);
|
||
|
IF i # LEN(IV) - 2 THEN
|
||
|
EmitJmp(opJMP, L1)
|
||
|
END
|
||
|
END;
|
||
|
|
||
|
EmitLabel(L1);
|
||
|
|
||
|
MovRR(SP, IR);
|
||
|
|
||
|
FOR i := 0 TO 15 DO
|
||
|
IF i IN R.regs + R.vregs THEN
|
||
|
Push(i)
|
||
|
END
|
||
|
END;
|
||
|
|
||
|
Push(IR);
|
||
|
Op1(opPUSH, IR, sINDIR);
|
||
|
Op1(opCALL, SR, sIDX);
|
||
|
EmitWord(RTL.int);
|
||
|
Op2(opADD, imm(4), SP);
|
||
|
|
||
|
FOR i := 15 TO 0 BY -1 DO
|
||
|
IF i IN R.regs + R.vregs THEN
|
||
|
Pop(i)
|
||
|
END
|
||
|
END;
|
||
|
|
||
|
Op2(opADD, imm(2), SP);
|
||
|
Op1(opRETI, 0, 0);
|
||
|
|
||
|
RTL.Gen
|
||
|
END epilog;
|
||
|
|
||
|
|
||
|
PROCEDURE hexdgt (n: BYTE): BYTE;
|
||
|
BEGIN
|
||
|
IF n < 10 THEN
|
||
|
n := n + ORD("0")
|
||
|
ELSE
|
||
|
n := n - 10 + ORD("A")
|
||
|
END
|
||
|
|
||
|
RETURN n
|
||
|
END hexdgt;
|
||
|
|
||
|
|
||
|
PROCEDURE WriteHexByte (file: FILES.FILE; byte: BYTE);
|
||
|
BEGIN
|
||
|
WRITER.WriteByte(file, hexdgt(byte DIV 16));
|
||
|
WRITER.WriteByte(file, hexdgt(byte MOD 16));
|
||
|
END WriteHexByte;
|
||
|
|
||
|
|
||
|
PROCEDURE WriteHex (file: FILES.FILE; mem: ARRAY OF BYTE; idx, cnt: INTEGER);
|
||
|
VAR
|
||
|
i, len, chksum: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
WHILE cnt > 0 DO
|
||
|
len := MIN(cnt, 16);
|
||
|
chksum := len + idx DIV 256 + idx MOD 256;
|
||
|
WRITER.WriteByte(file, ORD(":"));
|
||
|
WriteHexByte(file, len);
|
||
|
WriteHexByte(file, idx DIV 256);
|
||
|
WriteHexByte(file, idx MOD 256);
|
||
|
WriteHexByte(file, 0);
|
||
|
FOR i := 1 TO len DO
|
||
|
WriteHexByte(file, mem[idx]);
|
||
|
INC(chksum, mem[idx]);
|
||
|
INC(idx)
|
||
|
END;
|
||
|
WriteHexByte(file, (-chksum) MOD 256);
|
||
|
DEC(cnt, len);
|
||
|
WRITER.WriteByte(file, 0DH);
|
||
|
WRITER.WriteByte(file, 0AH)
|
||
|
END
|
||
|
END WriteHex;
|
||
|
|
||
|
|
||
|
PROCEDURE CodeGen* (code: IL.CODES; outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS);
|
||
|
VAR
|
||
|
i, adr, heap, stack, TextSize, TypesSize, bits, n: INTEGER;
|
||
|
|
||
|
Code, Data, Bss, Free: RECORD address, size: INTEGER END;
|
||
|
|
||
|
ram, rom: INTEGER;
|
||
|
|
||
|
reloc: RELOC;
|
||
|
|
||
|
file: FILES.FILE;
|
||
|
|
||
|
BEGIN
|
||
|
IdxWords.src := NOWORD;
|
||
|
IdxWords.dst := NOWORD;
|
||
|
|
||
|
ram := options.ram;
|
||
|
rom := options.rom;
|
||
|
|
||
|
IF ODD(ram) THEN DEC(ram) END;
|
||
|
IF ODD(rom) THEN DEC(rom) END;
|
||
|
|
||
|
ram := MIN(MAX(ram, minRAM), maxRAM);
|
||
|
rom := MIN(MAX(rom, minROM), maxROM);
|
||
|
|
||
|
IF code.bss > ram - minStackSize - RTL.VarSize THEN
|
||
|
ERRORS.Error(204)
|
||
|
END;
|
||
|
|
||
|
Labels := CHL.CreateIntList();
|
||
|
FOR i := 1 TO code.lcount DO
|
||
|
CHL.PushInt(Labels, 0)
|
||
|
END;
|
||
|
|
||
|
FOR i := 0 TO LEN(mem) - 1 DO
|
||
|
mem[i] := 0
|
||
|
END;
|
||
|
|
||
|
TypesSize := CHL.Length(code.types) * 2;
|
||
|
CodeList := LISTS.create(NIL);
|
||
|
RelList := LISTS.create(NIL);
|
||
|
REG.Init(R, Push, Pop, mov, xchg, NIL, NIL, {R4, R5, R6, R7}, {});
|
||
|
|
||
|
prolog(ram);
|
||
|
translate(code);
|
||
|
epilog;
|
||
|
|
||
|
Code.address := 10000H - rom;
|
||
|
Code.size := Fixup(Code.address, IntVectorSize + TypesSize);
|
||
|
Data.address := Code.address + Code.size;
|
||
|
Data.size := CHL.Length(code.data);
|
||
|
Data.size := Data.size + ORD(ODD(Data.size));
|
||
|
TextSize := Code.size + Data.size;
|
||
|
|
||
|
IF Code.address + TextSize + MAX(code.dmin - Data.size, IntVectorSize + TypesSize) > 10000H THEN
|
||
|
ERRORS.Error(203)
|
||
|
END;
|
||
|
|
||
|
Bss.address := RTL.ram + RTL.VarSize;
|
||
|
Bss.size := code.bss + ORD(ODD(code.bss));
|
||
|
heap := Bss.address + Bss.size;
|
||
|
stack := RTL.ram + ram;
|
||
|
ASSERT(stack - heap >= minStackSize);
|
||
|
adr := Code.address + 2;
|
||
|
PutWord(stack, adr);
|
||
|
adr := Code.address + 6;
|
||
|
PutWord(heap, adr);
|
||
|
|
||
|
reloc := RelList.first(RELOC);
|
||
|
WHILE reloc # NIL DO
|
||
|
adr := reloc.WordPtr.offset * 2;
|
||
|
CASE reloc.section OF
|
||
|
|RCODE: PutWord(LabelOffs(reloc.WordPtr.val) * 2, adr)
|
||
|
|RDATA: PutWord(reloc.WordPtr.val + Data.address, adr)
|
||
|
|RBSS: PutWord(reloc.WordPtr.val + Bss.address, adr)
|
||
|
END;
|
||
|
reloc := reloc.next(RELOC)
|
||
|
END;
|
||
|
|
||
|
adr := Data.address;
|
||
|
|
||
|
FOR i := 0 TO CHL.Length(code.data) - 1 DO
|
||
|
mem[adr] := CHL.GetByte(code.data, i);
|
||
|
INC(adr)
|
||
|
END;
|
||
|
|
||
|
adr := 10000H - IntVectorSize - TypesSize;
|
||
|
|
||
|
FOR i := TypesSize DIV 2 - 1 TO 0 BY -1 DO
|
||
|
PutWord(CHL.GetInt(code.types, i), adr)
|
||
|
END;
|
||
|
|
||
|
FOR i := 0 TO 15 DO
|
||
|
PutWord((33 - i) * i, adr);
|
||
|
END;
|
||
|
|
||
|
FOR n := 0 TO 15 DO
|
||
|
bits := ORD({0 .. n});
|
||
|
FOR i := 0 TO 15 - n DO
|
||
|
PutWord(bits, adr);
|
||
|
bits := LSL(bits, 1)
|
||
|
END
|
||
|
END;
|
||
|
|
||
|
Free.address := Code.address + TextSize;
|
||
|
Free.size := rom - (IntVectorSize + TypesSize + TextSize);
|
||
|
|
||
|
PutWord(Free.address, adr);
|
||
|
PutWord(Free.size, adr);
|
||
|
PutWord(4130H, adr); (* RET *)
|
||
|
PutWord(stack, adr);
|
||
|
|
||
|
FOR i := 0 TO LEN(IV) - 1 DO
|
||
|
PutWord(LabelOffs(IV[i]) * 2, adr)
|
||
|
END;
|
||
|
|
||
|
file := FILES.create(outname);
|
||
|
WriteHex(file, mem, Code.address, TextSize);
|
||
|
WriteHex(file, mem, 10000H - IntVectorSize - TypesSize, IntVectorSize + TypesSize);
|
||
|
|
||
|
WRITER.WriteByte(file, ORD(":"));
|
||
|
WriteHexByte(file, 0);
|
||
|
WriteHexByte(file, 0);
|
||
|
WriteHexByte(file, 0);
|
||
|
WriteHexByte(file, 1);
|
||
|
WriteHexByte(file, 255);
|
||
|
WRITER.WriteByte(file, 0DH);
|
||
|
WRITER.WriteByte(file, 0AH);
|
||
|
|
||
|
FILES.close(file);
|
||
|
|
||
|
INC(TextSize, IntVectorSize + TypesSize);
|
||
|
INC(Bss.size, minStackSize + RTL.VarSize);
|
||
|
|
||
|
C.StringLn("--------------------------------------------");
|
||
|
C.String( " rom: "); C.Int(TextSize); C.String(" of "); C.Int(rom); C.String(" ("); C.Int(TextSize * 100 DIV rom); C.StringLn("%)");
|
||
|
IF Free.size > 0 THEN
|
||
|
C.String( " "); C.Int(Free.size); C.String(" bytes free (0");
|
||
|
C.Hex(Free.address, 4); C.String("H..0"); C.Hex(Free.address + Free.size - 1, 4); C.StringLn("H)")
|
||
|
END;
|
||
|
C.Ln;
|
||
|
C.String( " ram: "); C.Int(Bss.size); C.String(" of "); C.Int(ram); C.String(" ("); C.Int(Bss.size * 100 DIV ram); C.StringLn("%)");
|
||
|
C.StringLn("--------------------------------------------")
|
||
|
|
||
|
END CodeGen;
|
||
|
|
||
|
|
||
|
END MSP430.
|