ce8fecbc6b
git-svn-id: svn://kolibrios.org@9177 a494cfbc-eb01-0410-851d-a64ba20cac60
1780 lines
41 KiB
Plaintext
1780 lines
41 KiB
Plaintext
(*
|
|
BSD 2-Clause License
|
|
|
|
Copyright (c) 2019-2021, Anton Krotov
|
|
All rights reserved.
|
|
*)
|
|
|
|
MODULE MSP430;
|
|
|
|
IMPORT IL, LISTS, REG, CHL := CHUNKLISTS, ERRORS, WR := WRITER, HEX,
|
|
UTILS, C := CONSOLE, PROG, RTL := MSP430RTL;
|
|
|
|
|
|
CONST
|
|
|
|
chkSTK* = 6;
|
|
|
|
minRAM* = 128; maxRAM* = 2048;
|
|
minROM* = 2048; maxROM* = 24576;
|
|
|
|
StkReserve = RTL.StkReserve;
|
|
|
|
IntVectorSize* = RTL.IntVectorSize;
|
|
|
|
PC = 0; SP = 1; SR = 2; CG = 3;
|
|
|
|
R4 = 4; R5 = 5; R6 = 6; R7 = 7;
|
|
|
|
HP = RTL.HP;
|
|
|
|
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;
|
|
|
|
StkCnt, MaxStkCnt: INTEGER;
|
|
|
|
|
|
PROCEDURE CheckProcDataSize* (VarSize, RamSize: INTEGER): BOOLEAN;
|
|
RETURN (VarSize + 1) * 2 + StkReserve + RTL.VarSize < RamSize
|
|
END CheckProcDataSize;
|
|
|
|
|
|
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 IncStk;
|
|
BEGIN
|
|
INC(StkCnt);
|
|
MaxStkCnt := MAX(StkCnt, MaxStkCnt)
|
|
END IncStk;
|
|
|
|
|
|
PROCEDURE bw (b: BOOLEAN): INTEGER;
|
|
RETURN BW * ORD(b)
|
|
END bw;
|
|
|
|
|
|
PROCEDURE src_x (x, Rn: INTEGER): INTEGER;
|
|
VAR
|
|
res: INTEGER;
|
|
|
|
BEGIN
|
|
IF (x = 0) & ~(Rn IN {PC, SR, CG}) THEN
|
|
res := Rn * 256 + sINDIR
|
|
ELSE
|
|
IdxWords.src := x;
|
|
res := Rn * 256 + sIDX
|
|
END
|
|
|
|
RETURN res
|
|
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 := CG * 256 + sIDX
|
|
| 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} = {});
|
|
ASSERT(BITS(src) - {4, 5, 8..11} = {});
|
|
ASSERT(BITS(dst) - {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;
|
|
IncStk
|
|
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);
|
|
IncStk
|
|
END Push;
|
|
|
|
|
|
PROCEDURE Pop (reg: INTEGER);
|
|
BEGIN
|
|
Op2(opMOV, incr(SP), reg);
|
|
DEC(StkCnt)
|
|
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);
|
|
mov(reg1, reg2);
|
|
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
|
|
IncStk;
|
|
DEC(StkCnt);
|
|
EmitCall(RTL.rtl[proc].label);
|
|
RTL.Used(proc);
|
|
IF params > 0 THEN
|
|
Op2(opADD, imm(params * 2), SP);
|
|
DEC(StkCnt, params)
|
|
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 LocalOffset (offset: INTEGER): INTEGER;
|
|
RETURN (offset + StkCnt - ORD(offset > 0)) * 2
|
|
END LocalOffset;
|
|
|
|
|
|
PROCEDURE LocalDst (offset: INTEGER): INTEGER;
|
|
RETURN dst_x(LocalOffset(offset), SP)
|
|
END LocalDst;
|
|
|
|
|
|
PROCEDURE LocalSrc (offset: INTEGER): INTEGER;
|
|
RETURN src_x(LocalOffset(offset), SP)
|
|
END LocalSrc;
|
|
|
|
|
|
PROCEDURE translate (chk_stk: BOOLEAN);
|
|
VAR
|
|
cmd, next: COMMAND;
|
|
|
|
opcode, param1, param2, L, a, n, c1, c2: INTEGER;
|
|
|
|
reg1, reg2: INTEGER;
|
|
|
|
cc: INTEGER;
|
|
|
|
word: WORD;
|
|
|
|
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:
|
|
EmitJmp(opJMP, param1)
|
|
|
|
|IL.opCALL:
|
|
IncStk;
|
|
DEC(StkCnt);
|
|
EmitCall(param1)
|
|
|
|
|IL.opCALLP:
|
|
IncStk;
|
|
DEC(StkCnt);
|
|
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);
|
|
IncStk;
|
|
EmitWord(param2);
|
|
Reloc(RDATA)
|
|
|
|
|IL.opERR:
|
|
CallRTL(RTL._error, 2)
|
|
|
|
|IL.opPUSHC:
|
|
PushImm(param2)
|
|
|
|
|IL.opONERR:
|
|
DEC(StkCnt);
|
|
EmitWord(0C232H); (* BIC #8, SR; DINT *)
|
|
EmitWord(4303H); (* MOV R3, R3; NOP *)
|
|
PushImm(param2);
|
|
EmitJmp(opJMP, param1)
|
|
|
|
|IL.opLEAVEC:
|
|
Pop(PC)
|
|
|
|
|IL.opENTER:
|
|
ASSERT(R.top = -1);
|
|
EmitLabel(param1);
|
|
n := param2 MOD 65536;
|
|
param2 := param2 DIV 65536;
|
|
StkCnt := 0;
|
|
IF chk_stk THEN
|
|
L := NewLabel();
|
|
Op2(opMOV, SP * 256, R4);
|
|
Op2(opSUB, HP * 256, R4);
|
|
Op2(opCMP, imm(StkReserve), R4);
|
|
word := CodeList.last(WORD);
|
|
jcc(jge, L);
|
|
DEC(StkCnt);
|
|
EmitWord(0C232H); (* BIC #8, SR; DINT *)
|
|
EmitWord(4303H); (* MOV R3, R3; NOP *)
|
|
PushImm(n);
|
|
EmitJmp(opJMP, cmd.param3);
|
|
EmitLabel(L)
|
|
END;
|
|
|
|
IF param2 > 8 THEN
|
|
Op2(opMOV, imm(param2), R4);
|
|
L := NewLabel();
|
|
EmitLabel(L);
|
|
Push(CG);
|
|
Op2(opSUB, imm(1), R4);
|
|
jcc(jne, L)
|
|
ELSE
|
|
FOR n := 1 TO param2 DO
|
|
Push(CG)
|
|
END
|
|
END;
|
|
StkCnt := param2;
|
|
MaxStkCnt := StkCnt
|
|
|
|
|IL.opLEAVE, IL.opLEAVER:
|
|
ASSERT(param2 = 0);
|
|
IF opcode = IL.opLEAVER THEN
|
|
UnOp(reg1);
|
|
IF reg1 # ACC THEN
|
|
mov(ACC, reg1)
|
|
END;
|
|
drop
|
|
END;
|
|
ASSERT(R.top = -1);
|
|
ASSERT(StkCnt = param1);
|
|
IF chk_stk THEN
|
|
INC(word.val, MaxStkCnt * 2)
|
|
END;
|
|
IF param1 > 0 THEN
|
|
Op2(opADD, imm(param1 * 2), SP)
|
|
END;
|
|
Pop(PC)
|
|
|
|
|IL.opRES:
|
|
ASSERT(R.top = -1);
|
|
GetRegA
|
|
|
|
|IL.opCLEANUP:
|
|
IF param2 # 0 THEN
|
|
Op2(opADD, imm(param2 * 2), SP);
|
|
DEC(StkCnt, param2)
|
|
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();
|
|
n := LocalOffset(param2);
|
|
Op2(opMOV, SP * 256, reg1);
|
|
IF n # 0 THEN
|
|
Op2(opADD, imm(n), reg1)
|
|
END
|
|
|
|
|IL.opLLOAD8:
|
|
Op2(opMOV + BW, LocalSrc(param2), GetAnyReg())
|
|
|
|
|IL.opLLOAD16, IL.opVADR:
|
|
Op2(opMOV, LocalSrc(param2), 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, LocalSrc(param2), reg1);
|
|
Op2(opMOV + BW, indir(reg1), reg1)
|
|
|
|
|IL.opVLOAD16:
|
|
reg1 := GetAnyReg();
|
|
Op2(opMOV, LocalSrc(param2), 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.opADDC:
|
|
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
|
|
Neg(reg1)
|
|
END
|
|
|
|
|IL.opLADR_SAVEC:
|
|
Op2(opMOV, imm(param2), LocalDst(param1))
|
|
|
|
|IL.opLADR_SAVE:
|
|
UnOp(reg1);
|
|
Op2(opMOV, reg1 * 256, LocalDst(param2));
|
|
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);
|
|
next := cmd.next(COMMAND);
|
|
|
|
IF next.opcode = IL.opJNZ THEN
|
|
jcc(cc, next.param1);
|
|
cmd := next
|
|
ELSIF next.opcode = IL.opJZ THEN
|
|
jcc(ORD(BITS(cc) / {0}), next.param1);
|
|
cmd := next
|
|
ELSE
|
|
setcc(cc, GetAnyReg())
|
|
END
|
|
|
|
|IL.opNOP, IL.opAND, IL.opOR:
|
|
|
|
|IL.opCODE:
|
|
EmitWord(param2)
|
|
|
|
|IL.opDROP:
|
|
UnOp(reg1);
|
|
drop
|
|
|
|
|IL.opJNZ1:
|
|
UnOp(reg1);
|
|
Test(reg1);
|
|
jcc(jne, param1)
|
|
|
|
|IL.opJG:
|
|
UnOp(reg1);
|
|
Test(reg1);
|
|
jcc(jg, param1)
|
|
|
|
|IL.opJNZ:
|
|
UnOp(reg1);
|
|
Test(reg1);
|
|
jcc(jne, param1);
|
|
drop
|
|
|
|
|IL.opJZ:
|
|
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.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.opCHKBYTE:
|
|
BinOp(reg1, reg2);
|
|
Op2(opCMP, imm(256), reg1);
|
|
jcc(jb, param1)
|
|
|
|
|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);
|
|
jcc(jb, param1)
|
|
END;
|
|
INCL(R.regs, reg1);
|
|
DEC(R.top);
|
|
R.stk[R.top] := reg2
|
|
|
|
|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), LocalDst(param1))
|
|
|
|
|IL.opLADR_DECCB:
|
|
Op2(opSUB + BW, imm(param2), LocalDst(param1))
|
|
|
|
|IL.opLADR_INC, IL.opLADR_INCB:
|
|
UnOp(reg1);
|
|
Op2(opADD + bw(opcode = IL.opLADR_INCB), reg1 * 256, LocalDst(param2));
|
|
drop
|
|
|
|
|IL.opLADR_DEC, IL.opLADR_DECB:
|
|
UnOp(reg1);
|
|
Op2(opSUB + bw(opcode = IL.opLADR_DECB), reg1 * 256, LocalDst(param2));
|
|
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);
|
|
IncStk;
|
|
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.opADDSC:
|
|
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.opMAX,IL.opMIN:
|
|
BinOp(reg1, reg2);
|
|
Op2(opCMP, reg2 * 256, reg1);
|
|
IF opcode = IL.opMIN THEN
|
|
cc := opJL + 1
|
|
ELSE
|
|
cc := opJGE + 1
|
|
END;
|
|
EmitWord(cc); (* jge/jl L *)
|
|
MovRR(reg2, reg1);
|
|
(* L: *)
|
|
drop
|
|
|
|
|IL.opMAXC, IL.opMINC:
|
|
UnOp(reg1);
|
|
Op2(opCMP, imm(param2), reg1);
|
|
L := NewLabel();
|
|
IF opcode = IL.opMINC THEN
|
|
cc := jl
|
|
ELSE
|
|
cc := jge
|
|
END;
|
|
jcc(cc, 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);
|
|
IF param2 = cmd.param3 THEN
|
|
jcc(jne, param2)
|
|
ELSE
|
|
jcc(jl, param2);
|
|
jcc(jg, cmd.param3)
|
|
END
|
|
|
|
|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.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.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);
|
|
IncStk;
|
|
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:
|
|
reg1 := GetAnyReg();
|
|
Op2(opMOV, LocalSrc(param2), reg1);
|
|
Push(reg1);
|
|
drop
|
|
|
|
|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(SP, ACC);
|
|
n := LocalOffset(param2);
|
|
IF n # 0 THEN
|
|
Op2(opADD, imm(n), ACC)
|
|
END;
|
|
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})), LocalDst(param1))
|
|
|
|
|IL.opLADR_EXCLC:
|
|
Op2(opBIC, imm(ORD({param2})), LocalDst(param1))
|
|
|
|
END;
|
|
|
|
cmd := cmd.next(COMMAND)
|
|
END;
|
|
|
|
ASSERT(R.pushed = 0);
|
|
ASSERT(R.top = -1)
|
|
END translate;
|
|
|
|
|
|
PROCEDURE prolog;
|
|
VAR
|
|
i: INTEGER;
|
|
|
|
BEGIN
|
|
RTL.Init(EmitLabel, EmitWord, EmitCall);
|
|
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(0, SP));
|
|
Op2(opMOV, imm(RTL.empty_proc), dst_x(2, SP));
|
|
END prolog;
|
|
|
|
|
|
PROCEDURE epilog;
|
|
VAR
|
|
L1, i, n: 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);
|
|
|
|
n := 0;
|
|
FOR i := 0 TO 15 DO
|
|
IF i IN R.regs THEN
|
|
Push(i);
|
|
INC(n)
|
|
END
|
|
END;
|
|
|
|
MovRR(SP, R4);
|
|
Op2(opADD, imm(n * 2), R4);
|
|
|
|
Push(R4);
|
|
Op1(opPUSH, R4, sINDIR);
|
|
Op1(opCALL, SR, sIDX); EmitWord(-RTL.VarSize); Reloc(RBSS); (* call int *)
|
|
Op2(opADD, imm(4), SP);
|
|
|
|
FOR i := 15 TO 0 BY -1 DO
|
|
IF i IN R.regs THEN
|
|
Pop(i)
|
|
END
|
|
END;
|
|
|
|
Op2(opADD, imm(2), SP);
|
|
Op1(opRETI, 0, 0);
|
|
|
|
RTL.Gen
|
|
END epilog;
|
|
|
|
|
|
PROCEDURE CodeGen* (outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS);
|
|
VAR
|
|
i, adr, heap, stack, TextSize, TypesSize, bits, n, val: INTEGER;
|
|
|
|
Code, Data, Bss: RECORD address, size: INTEGER END;
|
|
|
|
ram, rom: INTEGER;
|
|
|
|
reloc: RELOC;
|
|
|
|
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 IL.codes.bss > ram - StkReserve - RTL.VarSize THEN
|
|
ERRORS.Error(204)
|
|
END;
|
|
|
|
Labels := CHL.CreateIntList();
|
|
FOR i := 1 TO IL.codes.lcount DO
|
|
CHL.PushInt(Labels, 0)
|
|
END;
|
|
|
|
CodeList := LISTS.create(NIL);
|
|
RelList := LISTS.create(NIL);
|
|
REG.Init(R, Push, Pop, mov, xchg, {R4, R5, R6, R7});
|
|
|
|
prolog;
|
|
translate(chkSTK IN options.checking);
|
|
epilog;
|
|
|
|
TypesSize := CHL.Length(IL.codes.types) * 2;
|
|
Data.size := CHL.Length(IL.codes.data);
|
|
IF ODD(Data.size) THEN
|
|
CHL.PushByte(IL.codes.data, 0);
|
|
INC(Data.size)
|
|
END;
|
|
Code.size := Fixup(0, IntVectorSize + TypesSize + Data.size);
|
|
Code.address := 10000H - (IntVectorSize + TypesSize + Data.size + Code.size);
|
|
IF Code.address < 10000H - rom THEN
|
|
ERRORS.Error(203)
|
|
END;
|
|
Code.size := Fixup(Code.address, IntVectorSize + TypesSize + Data.size);
|
|
Data.address := Code.address + Code.size;
|
|
TextSize := Code.size + Data.size;
|
|
|
|
IF Code.address + TextSize + MAX(IL.codes.dmin - Data.size, IntVectorSize + TypesSize) > 10000H THEN
|
|
ERRORS.Error(203)
|
|
END;
|
|
|
|
stack := RTL.ram + ram;
|
|
Bss.size := IL.codes.bss + IL.codes.bss MOD 2;
|
|
DEC(stack, Bss.size);
|
|
Bss.address := stack;
|
|
DEC(stack, RTL.VarSize);
|
|
heap := RTL.ram;
|
|
ASSERT(stack - heap >= StkReserve);
|
|
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;
|
|
val := reloc.WordPtr.val;
|
|
CASE reloc.section OF
|
|
|RCODE: PutWord(LabelOffs(val) * 2, adr)
|
|
|RDATA: PutWord(val + Data.address, adr)
|
|
|RBSS: PutWord((val + Bss.address) MOD 65536, adr)
|
|
END;
|
|
reloc := reloc.next(RELOC)
|
|
END;
|
|
|
|
adr := Data.address;
|
|
|
|
FOR i := 0 TO Data.size - 1 DO
|
|
mem[adr] := CHL.GetByte(IL.codes.data, i);
|
|
INC(adr)
|
|
END;
|
|
|
|
FOR i := TypesSize DIV 2 - 1 TO 0 BY -1 DO
|
|
PutWord(CHL.GetInt(IL.codes.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;
|
|
|
|
PutWord(4130H, adr); (* RET *)
|
|
PutWord(stack, adr);
|
|
PutWord(0001H, adr); (* bsl signature (adr 0FFBEH) *)
|
|
|
|
FOR i := 0 TO LEN(IV) - 1 DO
|
|
PutWord(LabelOffs(IV[i]) * 2, adr)
|
|
END;
|
|
|
|
INC(TextSize, IntVectorSize + TypesSize + Code.address MOD 16);
|
|
INC(Bss.size, StkReserve + RTL.VarSize);
|
|
|
|
WR.Create(outname);
|
|
HEX.Data(mem, Code.address - Code.address MOD 16, TextSize);
|
|
HEX.End;
|
|
WR.Close;
|
|
|
|
C.Dashes;
|
|
C.String(" rom: "); C.Int(TextSize); C.String(" of "); C.Int(rom); C.String(" ("); C.Int(TextSize * 100 DIV rom); C.StringLn("%)");
|
|
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("%)")
|
|
END CodeGen;
|
|
|
|
|
|
END MSP430. |