Subversion Repositories Kolibri OS

Rev

Rev 7696 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. (*
  2.     BSD 2-Clause License
  3.  
  4.     Copyright (c) 2019-2020, Anton Krotov
  5.     All rights reserved.
  6. *)
  7.  
  8. MODULE MSP430;
  9.  
  10. IMPORT IL, LISTS, REG, CHL := CHUNKLISTS, ERRORS, WR := WRITER, HEX,
  11.        UTILS, C := CONSOLE, PROG, RTL := MSP430RTL;
  12.  
  13.  
  14. CONST
  15.  
  16.     minRAM* = 128;  maxRAM* = 2048;
  17.     minROM* = 2048; maxROM* = 24576;
  18.  
  19.     minStackSize = 64;
  20.  
  21.     IntVectorSize* = RTL.IntVectorSize;
  22.  
  23.     PC = 0; SP = 1; SR = 2; CG = 3;
  24.  
  25.     R4 = 4; R5 = 5; R6 = 6; R7 = 7;
  26.  
  27.     HP = 14; IR = 15;
  28.  
  29.     ACC = R4;
  30.  
  31.     opRRC  = 1000H;  opSWPB = 1080H;  opRRA  = 1100H;  opSXT = 1180H;
  32.     opPUSH = 1200H;  opCALL = 1280H;  opRETI = 1300H;
  33.  
  34.     opMOV = 04000H;  opADD = 05000H;  opADDC = 06000H;  opSUBC = 07000H;
  35.     opSUB = 08000H;  opCMP = 09000H;  opDADD = 0A000H;  opBIT  = 0B000H;
  36.     opBIC = 0C000H;  opBIS = 0D000H;  opXOR  = 0E000H;  opAND  = 0F000H;
  37.  
  38.     opJNE = 2000H;  opJEQ = 2400H;  opJNC = 2800H;  opJC  = 2C00H;
  39.     opJN  = 3000H;  opJGE = 3400H;  opJL  = 3800H;  opJMP = 3C00H;
  40.  
  41.     sREG = 0; sIDX = 16; sINDIR = 32; sINCR = 48; BW = 64; dIDX = 128;
  42.  
  43.     NOWORD = 10000H;
  44.  
  45.     RCODE = 0; RDATA = 1; RBSS = 2;
  46.  
  47.     je  = 0;  jne = je  + 1;
  48.     jge = 2;  jl  = jge + 1;
  49.     jle = 4;  jg  = jle + 1;
  50.     jb  = 6;
  51.  
  52.  
  53. TYPE
  54.  
  55.     ANYCODE = POINTER TO RECORD (LISTS.ITEM)
  56.  
  57.         offset: INTEGER
  58.  
  59.     END;
  60.  
  61.     WORD = POINTER TO RECORD (ANYCODE)
  62.  
  63.         val: INTEGER
  64.  
  65.     END;
  66.  
  67.     LABEL = POINTER TO RECORD (ANYCODE)
  68.  
  69.         num: INTEGER
  70.  
  71.     END;
  72.  
  73.     JMP = POINTER TO RECORD (ANYCODE)
  74.  
  75.         cc, label: INTEGER;
  76.         short: BOOLEAN
  77.  
  78.     END;
  79.  
  80.     CALL = POINTER TO RECORD (ANYCODE)
  81.  
  82.         label: INTEGER
  83.  
  84.     END;
  85.  
  86.     COMMAND = IL.COMMAND;
  87.  
  88.     RELOC = POINTER TO RECORD (LISTS.ITEM)
  89.  
  90.         section: INTEGER;
  91.         WordPtr: WORD
  92.  
  93.     END;
  94.  
  95.  
  96. VAR
  97.  
  98.     R: REG.REGS;
  99.  
  100.     CodeList: LISTS.LIST;
  101.     RelList:  LISTS.LIST;
  102.  
  103.     mem: ARRAY 65536 OF BYTE;
  104.  
  105.     Labels: CHL.INTLIST;
  106.  
  107.     IV: ARRAY RTL.LenIV OF INTEGER;
  108.  
  109.     IdxWords: RECORD src, dst: INTEGER END;
  110.  
  111.     StkCnt: INTEGER;
  112.  
  113.  
  114. PROCEDURE EmitLabel (L: INTEGER);
  115. VAR
  116.     label: LABEL;
  117.  
  118. BEGIN
  119.     NEW(label);
  120.     label.num := L;
  121.     LISTS.push(CodeList, label)
  122. END EmitLabel;
  123.  
  124.  
  125. PROCEDURE EmitWord (val: INTEGER);
  126. VAR
  127.     word: WORD;
  128.  
  129. BEGIN
  130.     IF val < 0 THEN
  131.         ASSERT(val >= -32768);
  132.         val := val MOD 65536
  133.     ELSE
  134.         ASSERT(val <= 65535)
  135.     END;
  136.     NEW(word);
  137.     word.val := val;
  138.     LISTS.push(CodeList, word)
  139. END EmitWord;
  140.  
  141.  
  142. PROCEDURE EmitJmp (cc, label: INTEGER);
  143. VAR
  144.     jmp: JMP;
  145.  
  146. BEGIN
  147.     NEW(jmp);
  148.     jmp.cc := cc;
  149.     jmp.label := label;
  150.     jmp.short := FALSE;
  151.     LISTS.push(CodeList, jmp)
  152. END EmitJmp;
  153.  
  154.  
  155. PROCEDURE EmitCall (label: INTEGER);
  156. VAR
  157.     call: CALL;
  158.  
  159. BEGIN
  160.     NEW(call);
  161.     call.label := label;
  162.     LISTS.push(CodeList, call)
  163. END EmitCall;
  164.  
  165.  
  166. PROCEDURE bw (b: BOOLEAN): INTEGER;
  167.     RETURN BW * ORD(b)
  168. END bw;
  169.  
  170.  
  171. PROCEDURE src_x (x, Rn: INTEGER): INTEGER;
  172. VAR
  173.     res: INTEGER;
  174.  
  175. BEGIN
  176.     IF (x = 0) & ~(Rn IN {PC, SR, CG}) THEN
  177.         res := Rn * 256 + sINDIR
  178.     ELSE
  179.         IdxWords.src := x;
  180.         res := Rn * 256 + sIDX
  181.     END
  182.  
  183.     RETURN res
  184. END src_x;
  185.  
  186.  
  187. PROCEDURE dst_x (x, Rn: INTEGER): INTEGER;
  188. BEGIN
  189.     IdxWords.dst := x
  190.     RETURN Rn + dIDX
  191. END dst_x;
  192.  
  193.  
  194. PROCEDURE indir (Rn: INTEGER): INTEGER;
  195.     RETURN Rn * 256 + sINDIR
  196. END indir;
  197.  
  198.  
  199. PROCEDURE incr (Rn: INTEGER): INTEGER;
  200.     RETURN Rn * 256 + sINCR
  201. END incr;
  202.  
  203.  
  204. PROCEDURE imm (x: INTEGER): INTEGER;
  205. VAR
  206.     res: INTEGER;
  207.  
  208. BEGIN
  209.     CASE x OF
  210.     | 0: res := CG * 256
  211.     | 1: res := CG * 256 + sIDX
  212.     | 2: res := indir(CG)
  213.     | 4: res := indir(SR)
  214.     | 8: res := incr(SR)
  215.     |-1: res := incr(CG)
  216.     ELSE
  217.         res := incr(PC);
  218.         IdxWords.src := x
  219.     END
  220.  
  221.     RETURN res
  222. END imm;
  223.  
  224.  
  225. PROCEDURE Op2 (op, src, dst: INTEGER);
  226. BEGIN
  227.     ASSERT(BITS(op) - {6, 12..15} = {});
  228.     ASSERT(BITS(src) - {4, 5, 8..11} = {});
  229.     ASSERT(BITS(dst) - {0..3, 7} = {});
  230.  
  231.     EmitWord(op + src + dst);
  232.  
  233.     IF IdxWords.src # NOWORD THEN
  234.         EmitWord(IdxWords.src);
  235.         IdxWords.src := NOWORD
  236.     END;
  237.  
  238.     IF IdxWords.dst # NOWORD THEN
  239.         EmitWord(IdxWords.dst);
  240.         IdxWords.dst := NOWORD
  241.     END
  242. END Op2;
  243.  
  244.  
  245. PROCEDURE Op1 (op, reg, As: INTEGER);
  246. BEGIN
  247.     EmitWord(op + reg + As)
  248. END Op1;
  249.  
  250.  
  251. PROCEDURE MovRR (src, dst: INTEGER);
  252. BEGIN
  253.     Op2(opMOV, src * 256, dst)
  254. END MovRR;
  255.  
  256.  
  257. PROCEDURE PushImm (imm: INTEGER);
  258. BEGIN
  259.     imm := UTILS.Long(imm);
  260.     CASE imm OF
  261.     | 0: Op1(opPUSH, CG, sREG)
  262.     | 1: Op1(opPUSH, CG, sIDX)
  263.     | 2: Op1(opPUSH, CG, sINDIR)
  264.     |-1: Op1(opPUSH, CG, sINCR)
  265.     ELSE
  266.         Op1(opPUSH, PC, sINCR);
  267.         EmitWord(imm)
  268.     END;
  269.     INC(StkCnt)
  270. END PushImm;
  271.  
  272.  
  273. PROCEDURE PutWord (word: INTEGER; VAR adr: INTEGER);
  274. BEGIN
  275.     ASSERT(~ODD(adr));
  276.     ASSERT((0 <= word) & (word <= 65535));
  277.     mem[adr] := word MOD 256;
  278.     mem[adr + 1] := word DIV 256;
  279.     INC(adr, 2)
  280. END PutWord;
  281.  
  282.  
  283. PROCEDURE NewLabel (): INTEGER;
  284. BEGIN
  285.     CHL.PushInt(Labels, 0)
  286.     RETURN IL.NewLabel()
  287. END NewLabel;
  288.  
  289.  
  290. PROCEDURE LabelOffs (n: INTEGER): INTEGER;
  291.     RETURN CHL.GetInt(Labels, n)
  292. END LabelOffs;
  293.  
  294.  
  295. PROCEDURE Fixup (CodeAdr, IntVectorSize: INTEGER): INTEGER;
  296. VAR
  297.     cmd:      ANYCODE;
  298.     adr:      INTEGER;
  299.     offset:   INTEGER;
  300.     diff:     INTEGER;
  301.     cc:       INTEGER;
  302.     shorted:  BOOLEAN;
  303.  
  304. BEGIN
  305.     REPEAT
  306.         shorted := FALSE;
  307.         offset := CodeAdr DIV 2;
  308.  
  309.         cmd := CodeList.first(ANYCODE);
  310.         WHILE cmd # NIL DO
  311.             cmd.offset := offset;
  312.             CASE cmd OF
  313.             |LABEL: CHL.SetInt(Labels, cmd.num, offset)
  314.             |JMP:   INC(offset);
  315.                     IF ~cmd.short THEN
  316.                         INC(offset);
  317.                         IF cmd.cc # opJMP THEN
  318.                             INC(offset)
  319.                         END
  320.                     END
  321.  
  322.             |CALL:  INC(offset, 2)
  323.             |WORD:  INC(offset)
  324.             END;
  325.             cmd := cmd.next(ANYCODE)
  326.         END;
  327.  
  328.         cmd := CodeList.first(ANYCODE);
  329.         WHILE cmd # NIL DO
  330.             IF (cmd IS JMP) & ~cmd(JMP).short THEN
  331.                 diff := LabelOffs(cmd(JMP).label) - cmd.offset - 1;
  332.                 IF ABS(diff) <= 512 THEN
  333.                     cmd(JMP).short := TRUE;
  334.                     shorted := TRUE
  335.                 END
  336.             END;
  337.             cmd := cmd.next(ANYCODE)
  338.         END
  339.  
  340.     UNTIL ~shorted;
  341.  
  342.     IF offset * 2 > 10000H - IntVectorSize THEN
  343.         ERRORS.Error(203)
  344.     END;
  345.  
  346.     adr := CodeAdr;
  347.     cmd := CodeList.first(ANYCODE);
  348.     WHILE cmd # NIL DO
  349.         CASE cmd OF
  350.         |LABEL:
  351.  
  352.         |JMP:   IF ~cmd.short THEN
  353.                     CASE cmd.cc OF
  354.                     |opJNE: cc := opJEQ
  355.                     |opJEQ: cc := opJNE
  356.                     |opJNC: cc := opJC
  357.                     |opJC:  cc := opJNC
  358.                     |opJGE: cc := opJL
  359.                     |opJL:  cc := opJGE
  360.                     |opJMP: cc := opJMP
  361.                     END;
  362.  
  363.                     IF cc # opJMP THEN
  364.                         PutWord(cc + 2, adr)  (* jcc L *)
  365.                     END;
  366.  
  367.                     PutWord(4030H, adr); (* MOV @PC+, PC *)
  368.                     PutWord(LabelOffs(cmd.label) * 2, adr)
  369.                     (* L: *)
  370.                 ELSE
  371.                     diff := LabelOffs(cmd.label) - cmd.offset - 1;
  372.                     ASSERT((-512 <= diff) & (diff <= 511));
  373.                     PutWord(cmd.cc + diff MOD 1024, adr)
  374.                 END
  375.  
  376.         |CALL:  PutWord(12B0H, adr); (* CALL @PC+ *)
  377.                 PutWord(LabelOffs(cmd.label) * 2, adr)
  378.  
  379.         |WORD:  PutWord(cmd.val, adr)
  380.  
  381.         END;
  382.         cmd := cmd.next(ANYCODE)
  383.     END
  384.  
  385.     RETURN adr - CodeAdr
  386. END Fixup;
  387.  
  388.  
  389. PROCEDURE Push (reg: INTEGER);
  390. BEGIN
  391.     Op1(opPUSH, reg, sREG);
  392.     INC(StkCnt)
  393. END Push;
  394.  
  395.  
  396. PROCEDURE Pop (reg: INTEGER);
  397. BEGIN
  398.     Op2(opMOV, incr(SP), reg);
  399.     DEC(StkCnt)
  400. END Pop;
  401.  
  402.  
  403. PROCEDURE Test (reg: INTEGER);
  404. BEGIN
  405.     Op2(opCMP, imm(0), reg)
  406. END Test;
  407.  
  408.  
  409. PROCEDURE Clear (reg: INTEGER);
  410. BEGIN
  411.     Op2(opMOV, imm(0), reg)
  412. END Clear;
  413.  
  414.  
  415. PROCEDURE mov (dst, src: INTEGER);
  416. BEGIN
  417.     MovRR(src, dst)
  418. END mov;
  419.  
  420.  
  421. PROCEDURE xchg (reg1, reg2: INTEGER);
  422. BEGIN
  423.     Push(reg1);
  424.     Push(reg2);
  425.     Pop(reg1);
  426.     Pop(reg2)
  427. END xchg;
  428.  
  429.  
  430. PROCEDURE Reloc (section: INTEGER);
  431. VAR
  432.     reloc: RELOC;
  433.  
  434. BEGIN
  435.     NEW(reloc);
  436.     reloc.section := section;
  437.     reloc.WordPtr := CodeList.last(WORD);
  438.     LISTS.push(RelList, reloc)
  439. END Reloc;
  440.  
  441.  
  442. PROCEDURE CallRTL (proc, params: INTEGER);
  443. BEGIN
  444.     EmitCall(RTL.rtl[proc].label);
  445.     RTL.Used(proc);
  446.     IF params > 0 THEN
  447.         Op2(opADD, imm(params * 2), SP);
  448.         DEC(StkCnt, params)
  449.     END
  450. END CallRTL;
  451.  
  452.  
  453. PROCEDURE UnOp (VAR reg: INTEGER);
  454. BEGIN
  455.     REG.UnOp(R, reg)
  456. END UnOp;
  457.  
  458.  
  459. PROCEDURE BinOp (VAR reg1, reg2: INTEGER);
  460. BEGIN
  461.     REG.BinOp(R, reg1, reg2)
  462. END BinOp;
  463.  
  464.  
  465. PROCEDURE GetRegA;
  466. BEGIN
  467.     ASSERT(REG.GetReg(R, ACC))
  468. END GetRegA;
  469.  
  470.  
  471. PROCEDURE drop;
  472. BEGIN
  473.     REG.Drop(R)
  474. END drop;
  475.  
  476.  
  477. PROCEDURE GetAnyReg (): INTEGER;
  478.     RETURN REG.GetAnyReg(R)
  479. END GetAnyReg;
  480.  
  481.  
  482. PROCEDURE PushAll (NumberOfParameters: INTEGER);
  483. BEGIN
  484.     REG.PushAll(R);
  485.     DEC(R.pushed, NumberOfParameters)
  486. END PushAll;
  487.  
  488.  
  489. PROCEDURE PushAll_1;
  490. BEGIN
  491.     REG.PushAll_1(R)
  492. END PushAll_1;
  493.  
  494.  
  495. PROCEDURE cond (op: INTEGER): INTEGER;
  496. VAR
  497.     res: INTEGER;
  498.  
  499. BEGIN
  500.     CASE op OF
  501.     |IL.opGT, IL.opGTC: res := jg
  502.     |IL.opGE, IL.opGEC: res := jge
  503.     |IL.opLT, IL.opLTC: res := jl
  504.     |IL.opLE, IL.opLEC: res := jle
  505.     |IL.opEQ, IL.opEQC: res := je
  506.     |IL.opNE, IL.opNEC: res := jne
  507.     END
  508.  
  509.     RETURN res
  510. END cond;
  511.  
  512.  
  513. PROCEDURE jcc (cc, label: INTEGER);
  514. VAR
  515.     L: INTEGER;
  516.  
  517. BEGIN
  518.     CASE cc OF
  519.     |jne:
  520.         EmitJmp(opJNE, label)
  521.     |je:
  522.         EmitJmp(opJEQ, label)
  523.     |jge:
  524.         EmitJmp(opJGE, label)
  525.     |jl:
  526.         EmitJmp(opJL, label)
  527.     |jle:
  528.         EmitJmp(opJL, label);
  529.         EmitJmp(opJEQ, label)
  530.     |jg:
  531.         L := NewLabel();
  532.         EmitJmp(opJEQ, L);
  533.         EmitJmp(opJGE, label);
  534.         EmitLabel(L)
  535.     |jb:
  536.         EmitJmp(opJNC, label)
  537.     END
  538. END jcc;
  539.  
  540.  
  541. PROCEDURE setcc (cc, reg: INTEGER);
  542. VAR
  543.     L: INTEGER;
  544.  
  545. BEGIN
  546.     L := NewLabel();
  547.     Op2(opMOV, imm(1), reg);
  548.     jcc(cc, L);
  549.     Clear(reg);
  550.     EmitLabel(L)
  551. END setcc;
  552.  
  553.  
  554. PROCEDURE Shift2 (op, reg, n: INTEGER);
  555. VAR
  556.     reg2: INTEGER;
  557.  
  558. BEGIN
  559.     IF n >= 8 THEN
  560.         CASE op OF
  561.         |IL.opASR2: Op1(opSWPB, reg, sREG); Op1(opSXT, reg, sREG)
  562.         |IL.opROR2: Op1(opSWPB, reg, sREG)
  563.         |IL.opLSL2: Op1(opSWPB, reg, sREG); Op2(opBIC, imm(255), reg)
  564.         |IL.opLSR2: Op2(opBIC, imm(255), reg); Op1(opSWPB, reg, sREG)
  565.         END;
  566.         DEC(n, 8)
  567.     END;
  568.  
  569.     IF (op = IL.opROR2) & (n > 0) THEN
  570.         reg2 := GetAnyReg();
  571.         MovRR(reg, reg2)
  572.     ELSE
  573.         reg2 := -1
  574.     END;
  575.  
  576.     WHILE n > 0 DO
  577.         CASE op OF
  578.         |IL.opASR2: Op1(opRRA, reg, sREG)
  579.         |IL.opROR2: Op1(opRRC, reg2, sREG); Op1(opRRC, reg, sREG)
  580.         |IL.opLSL2: Op2(opADD, reg * 256, reg)
  581.         |IL.opLSR2: Op2(opBIC, imm(1), SR); Op1(opRRC, reg, sREG)
  582.         END;
  583.         DEC(n)
  584.     END;
  585.  
  586.     IF reg2 # -1 THEN
  587.         drop
  588.     END
  589.  
  590. END Shift2;
  591.  
  592.  
  593. PROCEDURE Neg (reg: INTEGER);
  594. BEGIN
  595.     Op2(opXOR, imm(-1), reg);
  596.     Op2(opADD, imm(1), reg)
  597. END Neg;
  598.  
  599.  
  600. PROCEDURE LocalOffset (offset: INTEGER): INTEGER;
  601.     RETURN (offset + StkCnt - ORD(offset > 0)) * 2
  602. END LocalOffset;
  603.  
  604.  
  605. PROCEDURE LocalDst (offset: INTEGER): INTEGER;
  606.     RETURN dst_x(LocalOffset(offset), SP)
  607. END LocalDst;
  608.  
  609.  
  610. PROCEDURE LocalSrc (offset: INTEGER): INTEGER;
  611.     RETURN src_x(LocalOffset(offset), SP)
  612. END LocalSrc;
  613.  
  614.  
  615. PROCEDURE translate;
  616. VAR
  617.     cmd, next: COMMAND;
  618.  
  619.     opcode, param1, param2, L, a, n, c1, c2: INTEGER;
  620.  
  621.     reg1, reg2: INTEGER;
  622.  
  623.     cc: INTEGER;
  624.  
  625. BEGIN
  626.     cmd := IL.codes.commands.first(COMMAND);
  627.  
  628.     WHILE cmd # NIL DO
  629.  
  630.         param1 := cmd.param1;
  631.         param2 := cmd.param2;
  632.  
  633.         opcode := cmd.opcode;
  634.  
  635.         CASE opcode OF
  636.         |IL.opJMP:
  637.             EmitJmp(opJMP, param1)
  638.  
  639.         |IL.opCALL:
  640.             EmitCall(param1)
  641.  
  642.         |IL.opCALLP:
  643.             UnOp(reg1);
  644.             Op1(opCALL, reg1, sREG);
  645.             drop;
  646.             ASSERT(R.top = -1)
  647.  
  648.         |IL.opPRECALL:
  649.             PushAll(0)
  650.  
  651.         |IL.opLABEL:
  652.             EmitLabel(param1)
  653.  
  654.         |IL.opSADR_PARAM:
  655.             Op1(opPUSH, PC, sINCR);
  656.             INC(StkCnt);
  657.             EmitWord(param2);
  658.             Reloc(RDATA)
  659.  
  660.         |IL.opERR:
  661.             CallRTL(RTL._error, 2)
  662.  
  663.         |IL.opPUSHC:
  664.             PushImm(param2)
  665.  
  666.         |IL.opONERR:
  667.             PushImm(param2);
  668.             DEC(StkCnt);
  669.             EmitJmp(opJMP, param1)
  670.  
  671.         |IL.opLEAVEC:
  672.             Pop(PC)
  673.  
  674.         |IL.opENTER:
  675.             ASSERT(R.top = -1);
  676.             StkCnt := 0;
  677.             EmitLabel(param1);
  678.             IF param2 > 8 THEN
  679.                 Op2(opMOV, imm(param2), R4);
  680.                 L := NewLabel();
  681.                 EmitLabel(L);
  682.                 Push(CG);
  683.                 Op2(opSUB, imm(1), R4);
  684.                 jcc(jne, L)
  685.             ELSIF param2 > 0 THEN
  686.                 WHILE param2 > 0 DO
  687.                     Push(CG);
  688.                     DEC(param2)
  689.                 END
  690.             END
  691.  
  692.         |IL.opLEAVE, IL.opLEAVER:
  693.             ASSERT(param2 = 0);
  694.             IF opcode = IL.opLEAVER THEN
  695.                 UnOp(reg1);
  696.                 IF reg1 # ACC THEN
  697.                     GetRegA;
  698.                     ASSERT(REG.Exchange(R, reg1, ACC));
  699.                     drop
  700.                 END;
  701.                 drop
  702.             END;
  703.             ASSERT(R.top = -1);
  704.             ASSERT(StkCnt = param1);
  705.             IF param1 > 0 THEN
  706.                 Op2(opADD, imm(param1 * 2), SP)
  707.             END;
  708.             Pop(PC)
  709.  
  710.         |IL.opRES:
  711.             ASSERT(R.top = -1);
  712.             GetRegA
  713.  
  714.         |IL.opCLEANUP:
  715.             IF param2 # 0 THEN
  716.                 Op2(opADD, imm(param2 * 2), SP);
  717.                 DEC(StkCnt, param2)
  718.             END
  719.  
  720.         |IL.opCONST:
  721.             next := cmd.next(COMMAND);
  722.             IF next.opcode = IL.opCONST THEN
  723.                 c1 := param2;
  724.                 c2 := next.param2;
  725.                 next := next.next(COMMAND);
  726.                 IF (next.opcode = IL.opSAVE) OR (next.opcode = IL.opSAVE16) OR (next.opcode = IL.opSAVE8) THEN
  727.                     Op2(opMOV + bw(next.opcode = IL.opSAVE8), imm(c1), dst_x(c2, SR));
  728.                     cmd := next
  729.                 ELSE
  730.                     Op2(opMOV, imm(param2), GetAnyReg())
  731.                 END
  732.             ELSIF (next.opcode = IL.opSAVE) OR (next.opcode = IL.opSAVE16) OR (next.opcode = IL.opSAVE8) THEN
  733.                 UnOp(reg1);
  734.                 Op2(opMOV + bw(next.opcode = IL.opSAVE8), reg1 * 256, dst_x(param2, SR));
  735.                 drop;
  736.                 cmd := next
  737.             ELSE
  738.                 Op2(opMOV, imm(param2), GetAnyReg())
  739.             END
  740.  
  741.         |IL.opSADR:
  742.             Op2(opMOV, incr(PC), GetAnyReg());
  743.             EmitWord(param2);
  744.             Reloc(RDATA)
  745.  
  746.         |IL.opGADR:
  747.             Op2(opMOV, incr(PC), GetAnyReg());
  748.             EmitWord(param2);
  749.             Reloc(RBSS)
  750.  
  751.         |IL.opLADR:
  752.             reg1 := GetAnyReg();
  753.             n := LocalOffset(param2);
  754.             Op2(opMOV, SP * 256, reg1);
  755.             IF n # 0 THEN
  756.                 Op2(opADD, imm(n), reg1)
  757.             END
  758.  
  759.         |IL.opLLOAD8:
  760.             Op2(opMOV + BW, LocalSrc(param2), GetAnyReg())
  761.  
  762.         |IL.opLLOAD16, IL.opVADR:
  763.             Op2(opMOV, LocalSrc(param2), GetAnyReg())
  764.  
  765.         |IL.opGLOAD8:
  766.             Op2(opMOV + BW, src_x(param2, SR), GetAnyReg());
  767.             Reloc(RBSS)
  768.  
  769.         |IL.opGLOAD16:
  770.             Op2(opMOV, src_x(param2, SR), GetAnyReg());
  771.             Reloc(RBSS)
  772.  
  773.         |IL.opLOAD8:
  774.             UnOp(reg1);
  775.             Op2(opMOV + BW, indir(reg1), reg1)
  776.  
  777.         |IL.opLOAD16:
  778.             UnOp(reg1);
  779.             Op2(opMOV, indir(reg1), reg1)
  780.  
  781.         |IL.opVLOAD8:
  782.             reg1 := GetAnyReg();
  783.             Op2(opMOV, LocalSrc(param2), reg1);
  784.             Op2(opMOV + BW, indir(reg1), reg1)
  785.  
  786.         |IL.opVLOAD16:
  787.             reg1 := GetAnyReg();
  788.             Op2(opMOV, LocalSrc(param2), reg1);
  789.             Op2(opMOV, indir(reg1), reg1)
  790.  
  791.         |IL.opSAVE, IL.opSAVE16:
  792.             BinOp(reg2, reg1);
  793.             Op2(opMOV, reg2 * 256, dst_x(0, reg1));
  794.             drop;
  795.             drop
  796.  
  797.         |IL.opSAVE8:
  798.             BinOp(reg2, reg1);
  799.             Op2(opMOV + BW, reg2 * 256, dst_x(0, reg1));
  800.             drop;
  801.             drop
  802.  
  803.         |IL.opSAVE8C:
  804.             UnOp(reg1);
  805.             Op2(opMOV + BW, imm(param2), dst_x(0, reg1));
  806.             drop
  807.  
  808.         |IL.opSAVE16C, IL.opSAVEC:
  809.             UnOp(reg1);
  810.             Op2(opMOV, imm(param2), dst_x(0, reg1));
  811.             drop
  812.  
  813.         |IL.opUMINUS:
  814.             UnOp(reg1);
  815.             Neg(reg1)
  816.  
  817.         |IL.opADD:
  818.             BinOp(reg1, reg2);
  819.             Op2(opADD, reg2 * 256, reg1);
  820.             drop
  821.  
  822.         |IL.opADDL, IL.opADDR:
  823.             IF param2 # 0 THEN
  824.                 UnOp(reg1);
  825.                 Op2(opADD, imm(param2), reg1)
  826.             END
  827.  
  828.         |IL.opSUB:
  829.             BinOp(reg1, reg2);
  830.             Op2(opSUB, reg2 * 256, reg1);
  831.             drop
  832.  
  833.         |IL.opSUBR, IL.opSUBL:
  834.             UnOp(reg1);
  835.             IF param2 # 0 THEN
  836.                 Op2(opSUB, imm(param2), reg1)
  837.             END;
  838.             IF opcode = IL.opSUBL THEN
  839.                 Neg(reg1)
  840.             END
  841.  
  842.         |IL.opLADR_SAVEC:
  843.             Op2(opMOV, imm(param2), LocalDst(param1))
  844.  
  845.         |IL.opLADR_SAVE:
  846.             UnOp(reg1);
  847.             Op2(opMOV, reg1 * 256, LocalDst(param2));
  848.             drop
  849.  
  850.         |IL.opGADR_SAVEC:
  851.             Op2(opMOV, imm(param2), dst_x(param1, SR));
  852.             Reloc(RBSS)
  853.  
  854.         |IL.opCONST_PARAM:
  855.             PushImm(param2)
  856.  
  857.         |IL.opPARAM:
  858.             IF param2 = 1 THEN
  859.                 UnOp(reg1);
  860.                 Push(reg1);
  861.                 drop
  862.             ELSE
  863.                 ASSERT(R.top + 1 <= param2);
  864.                 PushAll(param2)
  865.             END
  866.  
  867.         |IL.opEQ..IL.opGE,
  868.          IL.opEQC..IL.opGEC:
  869.  
  870.             IF (IL.opEQ <= opcode) & (opcode <= IL.opGE) THEN
  871.                 BinOp(reg1, reg2);
  872.                 Op2(opCMP, reg2 * 256, reg1);
  873.                 drop
  874.             ELSE
  875.                 UnOp(reg1);
  876.                 Op2(opCMP, imm(param2), reg1)
  877.             END;
  878.  
  879.             drop;
  880.             cc := cond(opcode);
  881.             next := cmd.next(COMMAND);
  882.  
  883.             IF next.opcode = IL.opJE THEN
  884.                 jcc(cc, next.param1);
  885.                 cmd := next
  886.             ELSIF next.opcode = IL.opJNE THEN
  887.                 jcc(ORD(BITS(cc) / {0}), next.param1);
  888.                 cmd := next
  889.             ELSE
  890.                 setcc(cc, GetAnyReg())
  891.             END
  892.  
  893.         |IL.opNOP:
  894.  
  895.         |IL.opCODE:
  896.             EmitWord(param2)
  897.  
  898.         |IL.opACC:
  899.             IF (R.top # 0) OR (R.stk[0] # ACC) THEN
  900.                 PushAll(0);
  901.                 GetRegA;
  902.                 Pop(ACC);
  903.                 DEC(R.pushed)
  904.             END
  905.  
  906.         |IL.opDROP:
  907.             UnOp(reg1);
  908.             drop
  909.  
  910.         |IL.opJNZ:
  911.             UnOp(reg1);
  912.             Test(reg1);
  913.             jcc(jne, param1)
  914.  
  915.         |IL.opJZ:
  916.             UnOp(reg1);
  917.             Test(reg1);
  918.             jcc(je, param1)
  919.  
  920.         |IL.opJG:
  921.             UnOp(reg1);
  922.             Test(reg1);
  923.             jcc(jg, param1)
  924.  
  925.         |IL.opJE:
  926.             UnOp(reg1);
  927.             Test(reg1);
  928.             jcc(jne, param1);
  929.             drop
  930.  
  931.         |IL.opJNE:
  932.             UnOp(reg1);
  933.             Test(reg1);
  934.             jcc(je, param1);
  935.             drop
  936.  
  937.         |IL.opNOT:
  938.             UnOp(reg1);
  939.             Test(reg1);
  940.             setcc(je, reg1)
  941.  
  942.         |IL.opORD:
  943.             UnOp(reg1);
  944.             Test(reg1);
  945.             setcc(jne, reg1)
  946.  
  947.         |IL.opLOOP:
  948.         |IL.opENDLOOP:
  949.  
  950.         |IL.opGET:
  951.             BinOp(reg1, reg2);
  952.             drop;
  953.             drop;
  954.             Op2(opMOV + bw(param2 = 1), indir(reg1), dst_x(0, reg2))
  955.  
  956.         |IL.opGETC:
  957.             UnOp(reg2);
  958.             drop;
  959.             Op2(opMOV + bw(param2 = 1), src_x(param1, SR), dst_x(0, reg2))
  960.  
  961.         |IL.opCHKIDX:
  962.             UnOp(reg1);
  963.             Op2(opCMP, imm(param2), reg1);
  964.             jcc(jb, param1)
  965.  
  966.         |IL.opCHKIDX2:
  967.             BinOp(reg1, reg2);
  968.             IF param2 # -1 THEN
  969.                 Op2(opCMP, reg1 * 256, reg2);
  970.                 jcc(jb, param1)
  971.             END;
  972.             INCL(R.regs, reg1);
  973.             DEC(R.top);
  974.             R.stk[R.top] := reg2
  975.  
  976.         |IL.opINCC, IL.opINCCB:
  977.             UnOp(reg1);
  978.             Op2(opADD + bw(opcode = IL.opINCCB), imm(param2), dst_x(0, reg1));
  979.             drop
  980.  
  981.         |IL.opDECCB:
  982.             UnOp(reg1);
  983.             Op2(opSUB + BW, imm(param2), dst_x(0, reg1));
  984.             drop
  985.  
  986.         |IL.opINC, IL.opINCB:
  987.             BinOp(reg1, reg2);
  988.             Op2(opADD + bw(opcode = IL.opINCB), reg1 * 256, dst_x(0, reg2));
  989.             drop;
  990.             drop
  991.  
  992.         |IL.opDEC, IL.opDECB:
  993.             BinOp(reg1, reg2);
  994.             Op2(opSUB + bw(opcode = IL.opDECB), reg1 * 256, dst_x(0, reg2));
  995.             drop;
  996.             drop
  997.  
  998.         |IL.opLADR_INCC, IL.opLADR_INCCB:
  999.             Op2(opADD + bw(opcode = IL.opLADR_INCCB), imm(param2), LocalDst(param1))
  1000.  
  1001.         |IL.opLADR_DECCB:
  1002.             Op2(opSUB + BW, imm(param2), LocalDst(param1))
  1003.  
  1004.         |IL.opLADR_INC, IL.opLADR_INCB:
  1005.             UnOp(reg1);
  1006.             Op2(opADD + bw(opcode = IL.opLADR_INCB), reg1 * 256, LocalDst(param2));
  1007.             drop
  1008.  
  1009.         |IL.opLADR_DEC, IL.opLADR_DECB:
  1010.             UnOp(reg1);
  1011.             Op2(opSUB + bw(opcode = IL.opLADR_DECB), reg1 * 256, LocalDst(param2));
  1012.             drop
  1013.  
  1014.         |IL.opPUSHT:
  1015.             UnOp(reg1);
  1016.             Op2(opMOV, src_x(-2, reg1), GetAnyReg())
  1017.  
  1018.         |IL.opISREC:
  1019.             PushAll(2);
  1020.             PushImm(param2);
  1021.             CallRTL(RTL._guardrec, 3);
  1022.             GetRegA
  1023.  
  1024.         |IL.opIS:
  1025.             PushAll(1);
  1026.             PushImm(param2);
  1027.             CallRTL(RTL._is, 2);
  1028.             GetRegA
  1029.  
  1030.         |IL.opTYPEGR:
  1031.             PushAll(1);
  1032.             PushImm(param2);
  1033.             CallRTL(RTL._guardrec, 2);
  1034.             GetRegA
  1035.  
  1036.         |IL.opTYPEGP:
  1037.             UnOp(reg1);
  1038.             PushAll(0);
  1039.             Push(reg1);
  1040.             PushImm(param2);
  1041.             CallRTL(RTL._guard, 2);
  1042.             GetRegA
  1043.  
  1044.         |IL.opTYPEGD:
  1045.             UnOp(reg1);
  1046.             PushAll(0);
  1047.             Op1(opPUSH, reg1, sIDX);
  1048.             INC(StkCnt);
  1049.             EmitWord(-2);
  1050.             PushImm(param2);
  1051.             CallRTL(RTL._guardrec, 2);
  1052.             GetRegA
  1053.  
  1054.         |IL.opMULS:
  1055.             BinOp(reg1, reg2);
  1056.             Op2(opAND, reg2 * 256, reg1);
  1057.             drop
  1058.  
  1059.         |IL.opMULSC:
  1060.             UnOp(reg1);
  1061.             Op2(opAND, imm(param2), reg1)
  1062.  
  1063.         |IL.opDIVS:
  1064.             BinOp(reg1, reg2);
  1065.             Op2(opXOR, reg2 * 256, reg1);
  1066.             drop
  1067.  
  1068.         |IL.opDIVSC:
  1069.             UnOp(reg1);
  1070.             Op2(opXOR, imm(param2), reg1)
  1071.  
  1072.         |IL.opADDS:
  1073.             BinOp(reg1, reg2);
  1074.             Op2(opBIS, reg2 * 256, reg1);
  1075.             drop
  1076.  
  1077.         |IL.opSUBS:
  1078.             BinOp(reg1, reg2);
  1079.             Op2(opBIC, reg2 * 256, reg1);
  1080.             drop
  1081.  
  1082.         |IL.opADDSL, IL.opADDSR:
  1083.             UnOp(reg1);
  1084.             Op2(opBIS, imm(param2), reg1)
  1085.  
  1086.         |IL.opSUBSL:
  1087.             UnOp(reg1);
  1088.             Op2(opXOR, imm(-1), reg1);
  1089.             Op2(opAND, imm(param2), reg1)
  1090.  
  1091.         |IL.opSUBSR:
  1092.             UnOp(reg1);
  1093.             Op2(opBIC, imm(param2), reg1)
  1094.  
  1095.         |IL.opUMINS:
  1096.             UnOp(reg1);
  1097.             Op2(opXOR, imm(-1), reg1)
  1098.  
  1099.         |IL.opLENGTH:
  1100.             PushAll(2);
  1101.             CallRTL(RTL._length, 2);
  1102.             GetRegA
  1103.  
  1104.         |IL.opMAX,IL.opMIN:
  1105.             BinOp(reg1, reg2);
  1106.             Op2(opCMP, reg2 * 256, reg1);
  1107.             IF opcode = IL.opMIN THEN
  1108.                 cc := opJL + 1
  1109.             ELSE
  1110.                 cc := opJGE + 1
  1111.             END;
  1112.             EmitWord(cc);        (* jge/jl L *)
  1113.             MovRR(reg2, reg1);
  1114.                                  (* L: *)
  1115.             drop
  1116.  
  1117.         |IL.opMAXC, IL.opMINC:
  1118.             UnOp(reg1);
  1119.             Op2(opCMP, imm(param2), reg1);
  1120.             L := NewLabel();
  1121.             IF opcode = IL.opMINC THEN
  1122.                 cc := jl
  1123.             ELSE
  1124.                 cc := jge
  1125.             END;
  1126.             jcc(cc, L);
  1127.             Op2(opMOV, imm(param2), reg1);
  1128.             EmitLabel(L)
  1129.  
  1130.         |IL.opSWITCH:
  1131.             UnOp(reg1);
  1132.             IF param2 = 0 THEN
  1133.                 reg2 := ACC
  1134.             ELSE
  1135.                 reg2 := R5
  1136.             END;
  1137.             IF reg1 # reg2 THEN
  1138.                 ASSERT(REG.GetReg(R, reg2));
  1139.                 ASSERT(REG.Exchange(R, reg1, reg2));
  1140.                 drop
  1141.             END;
  1142.             drop
  1143.  
  1144.         |IL.opENDSW:
  1145.  
  1146.         |IL.opCASEL:
  1147.             Op2(opCMP, imm(param1), ACC);
  1148.             jcc(jl, param2)
  1149.  
  1150.         |IL.opCASER:
  1151.             Op2(opCMP, imm(param1), ACC);
  1152.             jcc(jg, param2)
  1153.  
  1154.         |IL.opCASELR:
  1155.             Op2(opCMP, imm(param1), ACC);
  1156.             jcc(jl, param2);
  1157.             jcc(jg, cmd.param3)
  1158.  
  1159.         |IL.opSBOOL:
  1160.             BinOp(reg2, reg1);
  1161.             Test(reg2);
  1162.             setcc(jne, reg2);
  1163.             Op2(opMOV + BW, reg2 * 256, dst_x(0, reg1));
  1164.             drop;
  1165.             drop
  1166.  
  1167.         |IL.opSBOOLC:
  1168.             UnOp(reg1);
  1169.             Op2(opMOV + BW, imm(param2), dst_x(0, reg1));
  1170.             drop
  1171.  
  1172.         |IL.opEQS .. IL.opGES:
  1173.             PushAll(4);
  1174.             PushImm((opcode - IL.opEQS) * 12);
  1175.             CallRTL(RTL._strcmp, 5);
  1176.             GetRegA
  1177.  
  1178.         |IL.opLEN:
  1179.             UnOp(reg1);
  1180.             drop;
  1181.             EXCL(R.regs, reg1);
  1182.  
  1183.             WHILE param2 > 0 DO
  1184.                 UnOp(reg2);
  1185.                 drop;
  1186.                 DEC(param2)
  1187.             END;
  1188.  
  1189.             INCL(R.regs, reg1);
  1190.             ASSERT(REG.GetReg(R, reg1))
  1191.  
  1192.         |IL.opCHKBYTE:
  1193.             BinOp(reg1, reg2);
  1194.             Op2(opCMP, imm(256), reg1);
  1195.             jcc(jb, param1)
  1196.  
  1197.         |IL.opLSL, IL.opASR, IL.opROR, IL.opLSR:
  1198.             PushAll(2);
  1199.             CASE opcode OF
  1200.             |IL.opLSL: CallRTL(RTL._lsl, 2)
  1201.             |IL.opASR: CallRTL(RTL._asr, 2)
  1202.             |IL.opROR: CallRTL(RTL._ror, 2)
  1203.             |IL.opLSR: CallRTL(RTL._lsr, 2)
  1204.             END;
  1205.             GetRegA
  1206.  
  1207.         |IL.opLSL1, IL.opASR1, IL.opROR1, IL.opLSR1:
  1208.             UnOp(reg1);
  1209.             PushAll_1;
  1210.             PushImm(param2);
  1211.             Push(reg1);
  1212.             drop;
  1213.             CASE opcode OF
  1214.             |IL.opLSL1: CallRTL(RTL._lsl, 2)
  1215.             |IL.opASR1: CallRTL(RTL._asr, 2)
  1216.             |IL.opROR1: CallRTL(RTL._ror, 2)
  1217.             |IL.opLSR1: CallRTL(RTL._lsr, 2)
  1218.             END;
  1219.             GetRegA
  1220.  
  1221.         |IL.opASR2, IL.opROR2, IL.opLSL2, IL.opLSR2:
  1222.             param2 := param2 MOD 16;
  1223.             IF param2 # 0 THEN
  1224.                 UnOp(reg1);
  1225.                 Shift2(opcode, reg1, param2)
  1226.             END
  1227.  
  1228.         |IL.opMUL:
  1229.             PushAll(2);
  1230.             CallRTL(RTL._mul, 2);
  1231.             GetRegA
  1232.  
  1233.         |IL.opMULC:
  1234.             UnOp(reg1);
  1235.  
  1236.             a := param2;
  1237.             IF a > 1 THEN
  1238.                 n := UTILS.Log2(a)
  1239.             ELSIF a < -1 THEN
  1240.                 n := UTILS.Log2(-a)
  1241.             ELSE
  1242.                 n := -1
  1243.             END;
  1244.  
  1245.             IF a = 1 THEN
  1246.  
  1247.             ELSIF a = -1 THEN
  1248.                 Neg(reg1)
  1249.             ELSIF a = 0 THEN
  1250.                 Clear(reg1)
  1251.             ELSE
  1252.                 IF n > 0 THEN
  1253.                     IF a < 0 THEN
  1254.                         Neg(reg1)
  1255.                     END;
  1256.                     Shift2(IL.opLSL2, reg1, n)
  1257.                 ELSE
  1258.                     PushAll(1);
  1259.                     PushImm(a);
  1260.                     CallRTL(RTL._mul, 2);
  1261.                     GetRegA
  1262.                 END
  1263.             END
  1264.  
  1265.         |IL.opDIV:
  1266.             PushAll(2);
  1267.             CallRTL(RTL._divmod, 2);
  1268.             GetRegA
  1269.  
  1270.         |IL.opDIVR:
  1271.             ASSERT(param2 > 0);
  1272.  
  1273.             IF param2 > 1 THEN
  1274.                 n := UTILS.Log2(param2);
  1275.                 IF n > 0 THEN
  1276.                     UnOp(reg1);
  1277.                     Shift2(IL.opASR2, reg1, n)
  1278.                 ELSE
  1279.                     PushAll(1);
  1280.                     PushImm(param2);
  1281.                     CallRTL(RTL._divmod, 2);
  1282.                     GetRegA
  1283.                 END
  1284.             END
  1285.  
  1286.         |IL.opDIVL:
  1287.             UnOp(reg1);
  1288.             PushAll_1;
  1289.             PushImm(param2);
  1290.             Push(reg1);
  1291.             drop;
  1292.             CallRTL(RTL._divmod, 2);
  1293.             GetRegA
  1294.  
  1295.         |IL.opMOD:
  1296.             PushAll(2);
  1297.             CallRTL(RTL._divmod, 2);
  1298.             ASSERT(REG.GetReg(R, R5))
  1299.  
  1300.         |IL.opMODR:
  1301.             ASSERT(param2 > 0);
  1302.  
  1303.             IF param2 = 1 THEN
  1304.                 UnOp(reg1);
  1305.                 Clear(reg1)
  1306.             ELSE
  1307.                 IF UTILS.Log2(param2) > 0 THEN
  1308.                     UnOp(reg1);
  1309.                     Op2(opAND, imm(param2 - 1), reg1)
  1310.                 ELSE
  1311.                     PushAll(1);
  1312.                     PushImm(param2);
  1313.                     CallRTL(RTL._divmod, 2);
  1314.                     ASSERT(REG.GetReg(R, R5))
  1315.                 END
  1316.             END
  1317.  
  1318.         |IL.opMODL:
  1319.             UnOp(reg1);
  1320.             PushAll_1;
  1321.             PushImm(param2);
  1322.             Push(reg1);
  1323.             drop;
  1324.             CallRTL(RTL._divmod, 2);
  1325.             ASSERT(REG.GetReg(R, R5))
  1326.  
  1327.         |IL.opCOPYS:
  1328.             ASSERT(R.top = 3);
  1329.             Push(R.stk[2]);
  1330.             Push(R.stk[0]);
  1331.             Op2(opCMP, R.stk[1] * 256, R.stk[3]);
  1332.             EmitWord(3801H); (* JL L1 *)
  1333.             MovRR(R.stk[1], R.stk[3]);
  1334.                              (* L1:   *)
  1335.             Push(R.stk[3]);
  1336.             drop;
  1337.             drop;
  1338.             drop;
  1339.             drop;
  1340.             CallRTL(RTL._move, 3)
  1341.  
  1342.         |IL.opCOPY:
  1343.             PushAll(2);
  1344.             PushImm(param2);
  1345.             CallRTL(RTL._move, 3)
  1346.  
  1347.         |IL.opMOVE:
  1348.             PushAll(3);
  1349.             CallRTL(RTL._move, 3)
  1350.  
  1351.         |IL.opCOPYA:
  1352.             PushAll(4);
  1353.             PushImm(param2);
  1354.             CallRTL(RTL._arrcpy, 5);
  1355.             GetRegA
  1356.  
  1357.         |IL.opROT:
  1358.             PushAll(0);
  1359.             MovRR(SP, ACC);
  1360.             Push(ACC);
  1361.             PushImm(param2);
  1362.             CallRTL(RTL._rot, 2)
  1363.  
  1364.         |IL.opSAVES:
  1365.             UnOp(reg1);
  1366.             PushAll_1;
  1367.             Op1(opPUSH, PC, sINCR);
  1368.             INC(StkCnt);
  1369.             EmitWord(param2);
  1370.             Reloc(RDATA);
  1371.             Push(reg1);
  1372.             drop;
  1373.             PushImm(param1);
  1374.             CallRTL(RTL._move, 3)
  1375.  
  1376.         |IL.opCASET:
  1377.             Push(R5);
  1378.             Push(R5);
  1379.             PushImm(param2);
  1380.             CallRTL(RTL._guardrec, 2);
  1381.             Pop(R5);
  1382.             Test(ACC);
  1383.             jcc(jne, param1)
  1384.  
  1385.         |IL.opCHR:
  1386.             UnOp(reg1);
  1387.             Op2(opAND, imm(255), reg1)
  1388.  
  1389.         |IL.opABS:
  1390.             UnOp(reg1);
  1391.             Test(reg1);
  1392.             L := NewLabel();
  1393.             jcc(jge, L);
  1394.             Neg(reg1);
  1395.             EmitLabel(L)
  1396.  
  1397.         |IL.opEQB, IL.opNEB:
  1398.             BinOp(reg1, reg2);
  1399.             drop;
  1400.  
  1401.             Test(reg1);
  1402.             L := NewLabel();
  1403.             jcc(je, L);
  1404.             Op2(opMOV, imm(1), reg1);
  1405.             EmitLabel(L);
  1406.  
  1407.             Test(reg2);
  1408.             L := NewLabel();
  1409.             jcc(je, L);
  1410.             Op2(opMOV, imm(1), reg2);
  1411.             EmitLabel(L);
  1412.  
  1413.             Op2(opCMP, reg2 * 256, reg1);
  1414.             IF opcode = IL.opEQB THEN
  1415.                 setcc(je, reg1)
  1416.             ELSE
  1417.                 setcc(jne, reg1)
  1418.             END
  1419.  
  1420.         |IL.opSAVEP:
  1421.             UnOp(reg1);
  1422.             Op2(opMOV, incr(PC), reg1 + dIDX);
  1423.             EmitWord(param2);
  1424.             Reloc(RCODE);
  1425.             EmitWord(0);
  1426.             drop
  1427.  
  1428.         |IL.opPUSHP:
  1429.             Op2(opMOV, incr(PC), GetAnyReg());
  1430.             EmitWord(param2);
  1431.             Reloc(RCODE)
  1432.  
  1433.         |IL.opEQP, IL.opNEP:
  1434.             UnOp(reg1);
  1435.             Op2(opCMP, incr(PC), reg1);
  1436.             EmitWord(param1);
  1437.             Reloc(RCODE);
  1438.             drop;
  1439.             reg1 := GetAnyReg();
  1440.  
  1441.             IF opcode = IL.opEQP THEN
  1442.                 setcc(je, reg1)
  1443.             ELSIF opcode = IL.opNEP THEN
  1444.                 setcc(jne, reg1)
  1445.             END
  1446.  
  1447.         |IL.opVADR_PARAM:
  1448.             reg1 := GetAnyReg();
  1449.             Op2(opMOV, LocalSrc(param2), reg1);
  1450.             Push(reg1);
  1451.             drop
  1452.  
  1453.         |IL.opNEW:
  1454.             PushAll(1);
  1455.             n := param2 + 2;
  1456.             ASSERT(UTILS.Align(n, 2));
  1457.             PushImm(n);
  1458.             PushImm(param1);
  1459.             CallRTL(RTL._new, 3)
  1460.  
  1461.         |IL.opRSET:
  1462.             PushAll(2);
  1463.             CallRTL(RTL._set, 2);
  1464.             GetRegA
  1465.  
  1466.         |IL.opRSETR:
  1467.             PushAll(1);
  1468.             PushImm(param2);
  1469.             CallRTL(RTL._set, 2);
  1470.             GetRegA
  1471.  
  1472.         |IL.opRSETL:
  1473.             UnOp(reg1);
  1474.             PushAll_1;
  1475.             PushImm(param2);
  1476.             Push(reg1);
  1477.             drop;
  1478.             CallRTL(RTL._set, 2);
  1479.             GetRegA
  1480.  
  1481.         |IL.opRSET1:
  1482.             PushAll(1);
  1483.             CallRTL(RTL._set1, 1);
  1484.             GetRegA
  1485.  
  1486.         |IL.opINCLC:
  1487.             UnOp(reg1);
  1488.             Op2(opBIS, imm(ORD({param2})), dst_x(0, reg1));
  1489.             drop
  1490.  
  1491.         |IL.opEXCLC:
  1492.             UnOp(reg1);
  1493.             Op2(opBIC, imm(ORD({param2})), dst_x(0, reg1));
  1494.             drop
  1495.  
  1496.         |IL.opIN:
  1497.             PushAll(2);
  1498.             CallRTL(RTL._in, 2);
  1499.             GetRegA
  1500.  
  1501.         |IL.opINR:
  1502.             PushAll(1);
  1503.             PushImm(param2);
  1504.             CallRTL(RTL._in, 2);
  1505.             GetRegA
  1506.  
  1507.         |IL.opINL:
  1508.             PushAll(1);
  1509.             PushImm(param2);
  1510.             CallRTL(RTL._in2, 2);
  1511.             GetRegA
  1512.  
  1513.         |IL.opINCL:
  1514.             PushAll(2);
  1515.             CallRTL(RTL._incl, 2)
  1516.  
  1517.         |IL.opEXCL:
  1518.             PushAll(2);
  1519.             CallRTL(RTL._excl, 2)
  1520.  
  1521.         |IL.opLADR_INCL, IL.opLADR_EXCL:
  1522.             PushAll(1);
  1523.             MovRR(SP, ACC);
  1524.             n := LocalOffset(param2);
  1525.             IF n # 0 THEN
  1526.                 Op2(opADD, imm(n), ACC)
  1527.             END;
  1528.             Push(ACC);
  1529.             IF opcode = IL.opLADR_INCL THEN
  1530.                 CallRTL(RTL._incl, 2)
  1531.             ELSIF opcode = IL.opLADR_EXCL THEN
  1532.                 CallRTL(RTL._excl, 2)
  1533.             END
  1534.  
  1535.         |IL.opLADR_INCLC:
  1536.             Op2(opBIS, imm(ORD({param2})), LocalDst(param1))
  1537.  
  1538.         |IL.opLADR_EXCLC:
  1539.             Op2(opBIC, imm(ORD({param2})), LocalDst(param1))
  1540.  
  1541.         END;
  1542.  
  1543.         cmd := cmd.next(COMMAND)
  1544.     END;
  1545.  
  1546.     ASSERT(R.pushed = 0);
  1547.     ASSERT(R.top = -1)
  1548. END translate;
  1549.  
  1550.  
  1551. PROCEDURE prolog (ramSize: INTEGER);
  1552. VAR
  1553.     i: INTEGER;
  1554.  
  1555. BEGIN
  1556.     RTL.Init(EmitLabel, EmitWord, EmitCall, ramSize);
  1557.     FOR i := 0 TO LEN(RTL.rtl) - 1 DO
  1558.         RTL.Set(i, NewLabel())
  1559.     END;
  1560.  
  1561.     IV[LEN(IV) - 1] := NewLabel();
  1562.     EmitLabel(IV[LEN(IV) - 1]);
  1563.     Op2(opMOV, incr(PC), SP);
  1564.     EmitWord(0);
  1565.     Op2(opMOV, incr(PC), HP);
  1566.     EmitWord(0);
  1567.     Op2(opMOV, imm(5A80H), dst_x(0120H, SR)); (* stop WDT *)
  1568.     Op2(opMOV, imm(RTL.empty_proc), dst_x(RTL.int, SR));
  1569.     Op2(opMOV, imm(0), dst_x(RTL.trap, SR))
  1570. END prolog;
  1571.  
  1572.  
  1573. PROCEDURE epilog;
  1574. VAR
  1575.     L1, i: INTEGER;
  1576.  
  1577. BEGIN
  1578.     Op2(opBIS, imm(10H), SR); (* CPUOFF *)
  1579.  
  1580.     L1 := NewLabel();
  1581.     FOR i := 0 TO LEN(IV) - 2 DO
  1582.         IV[i] := NewLabel();
  1583.         EmitLabel(IV[i]);
  1584.         PushImm(i);
  1585.         IF i # LEN(IV) - 2 THEN
  1586.             EmitJmp(opJMP, L1)
  1587.         END
  1588.     END;
  1589.  
  1590.     EmitLabel(L1);
  1591.  
  1592.     MovRR(SP, IR);
  1593.  
  1594.     FOR i := 0 TO 15 DO
  1595.         IF i IN R.regs + R.vregs THEN
  1596.             Push(i)
  1597.         END
  1598.     END;
  1599.  
  1600.     Push(IR);
  1601.     Op1(opPUSH, IR, sINDIR);
  1602.     Op1(opCALL, SR, sIDX);
  1603.     EmitWord(RTL.int);
  1604.     Op2(opADD, imm(4), SP);
  1605.  
  1606.     FOR i := 15 TO 0 BY -1 DO
  1607.         IF i IN R.regs + R.vregs THEN
  1608.             Pop(i)
  1609.         END
  1610.     END;
  1611.  
  1612.     Op2(opADD, imm(2), SP);
  1613.     Op1(opRETI, 0, 0);
  1614.  
  1615.     RTL.Gen
  1616. END epilog;
  1617.  
  1618.  
  1619. PROCEDURE CodeGen* (outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS);
  1620. VAR
  1621.     i, adr, heap, stack, TextSize, TypesSize, bits, n: INTEGER;
  1622.  
  1623.     Code, Data, Bss, Free: RECORD address, size: INTEGER END;
  1624.  
  1625.     ram, rom: INTEGER;
  1626.  
  1627.     reloc: RELOC;
  1628.  
  1629.     file: WR.FILE;
  1630.  
  1631. BEGIN
  1632.     IdxWords.src := NOWORD;
  1633.     IdxWords.dst := NOWORD;
  1634.  
  1635.     ram := options.ram;
  1636.     rom := options.rom;
  1637.  
  1638.     IF ODD(ram) THEN DEC(ram) END;
  1639.     IF ODD(rom) THEN DEC(rom) END;
  1640.  
  1641.     ram := MIN(MAX(ram, minRAM), maxRAM);
  1642.     rom := MIN(MAX(rom, minROM), maxROM);
  1643.  
  1644.     IF IL.codes.bss > ram - minStackSize - RTL.VarSize THEN
  1645.         ERRORS.Error(204)
  1646.     END;
  1647.  
  1648.     Labels := CHL.CreateIntList();
  1649.     FOR i := 1 TO IL.codes.lcount DO
  1650.         CHL.PushInt(Labels, 0)
  1651.     END;
  1652.  
  1653.     FOR i := 0 TO LEN(mem) - 1 DO
  1654.         mem[i] := 0
  1655.     END;
  1656.  
  1657.     TypesSize := CHL.Length(IL.codes.types) * 2;
  1658.     CodeList := LISTS.create(NIL);
  1659.     RelList  := LISTS.create(NIL);
  1660.     REG.Init(R, Push, Pop, mov, xchg, NIL, NIL, {R4, R5, R6, R7}, {});
  1661.  
  1662.     prolog(ram);
  1663.     translate;
  1664.     epilog;
  1665.  
  1666.     Code.address := 10000H - rom;
  1667.     Code.size := Fixup(Code.address, IntVectorSize + TypesSize);
  1668.     Data.address := Code.address + Code.size;
  1669.     Data.size := CHL.Length(IL.codes.data);
  1670.     Data.size := Data.size + Data.size MOD 2;
  1671.     TextSize  := Code.size + Data.size;
  1672.  
  1673.     IF Code.address + TextSize + MAX(IL.codes.dmin - Data.size, IntVectorSize + TypesSize) > 10000H  THEN
  1674.         ERRORS.Error(203)
  1675.     END;
  1676.  
  1677.     Bss.address := RTL.ram + RTL.VarSize;
  1678.     Bss.size := IL.codes.bss + IL.codes.bss MOD 2;
  1679.     heap := Bss.address + Bss.size;
  1680.     stack := RTL.ram + ram;
  1681.     ASSERT(stack - heap >= minStackSize);
  1682.     adr := Code.address + 2;
  1683.     PutWord(stack, adr);
  1684.     adr := Code.address + 6;
  1685.     PutWord(heap, adr);
  1686.  
  1687.     reloc := RelList.first(RELOC);
  1688.     WHILE reloc # NIL DO
  1689.         adr := reloc.WordPtr.offset * 2;
  1690.         CASE reloc.section OF
  1691.         |RCODE: PutWord(LabelOffs(reloc.WordPtr.val) * 2, adr)
  1692.         |RDATA: PutWord(reloc.WordPtr.val + Data.address, adr)
  1693.         |RBSS:  PutWord(reloc.WordPtr.val + Bss.address, adr)
  1694.         END;
  1695.         reloc := reloc.next(RELOC)
  1696.     END;
  1697.  
  1698.     adr := Data.address;
  1699.  
  1700.     FOR i := 0 TO CHL.Length(IL.codes.data) - 1 DO
  1701.         mem[adr] := CHL.GetByte(IL.codes.data, i);
  1702.         INC(adr)
  1703.     END;
  1704.  
  1705.     adr := 10000H - IntVectorSize - TypesSize;
  1706.  
  1707.     FOR i := TypesSize DIV 2 - 1 TO 0 BY -1 DO
  1708.         PutWord(CHL.GetInt(IL.codes.types, i), adr)
  1709.     END;
  1710.  
  1711.     FOR i := 0 TO 15 DO
  1712.         PutWord((33 - i) * i, adr);
  1713.     END;
  1714.  
  1715.     FOR n := 0 TO 15 DO
  1716.         bits := ORD({0 .. n});
  1717.         FOR i := 0 TO 15 - n DO
  1718.             PutWord(bits, adr);
  1719.             bits := LSL(bits, 1)
  1720.         END
  1721.     END;
  1722.  
  1723.     Free.address := Code.address + TextSize;
  1724.     Free.size := rom - (IntVectorSize + TypesSize + TextSize);
  1725.  
  1726.     PutWord(Free.address, adr);
  1727.     PutWord(Free.size, adr);
  1728.     PutWord(4130H, adr); (* RET *)
  1729.     PutWord(stack, adr);
  1730.     PutWord(0001H, adr); (* bsl signature (adr 0FFBEH) *)
  1731.  
  1732.     FOR i := 0 TO LEN(IV) - 1 DO
  1733.         PutWord(LabelOffs(IV[i]) * 2, adr)
  1734.     END;
  1735.  
  1736.     file := WR.Create(outname);
  1737.  
  1738.     HEX.Data(file, mem, Code.address, TextSize);
  1739.     HEX.Data(file, mem, 10000H - IntVectorSize - TypesSize, IntVectorSize + TypesSize);
  1740.     HEX.End(file);
  1741.  
  1742.     WR.Close(file);
  1743.  
  1744.     INC(TextSize, IntVectorSize + TypesSize);
  1745.     INC(Bss.size, minStackSize + RTL.VarSize);
  1746.  
  1747.     C.StringLn("--------------------------------------------");
  1748.     C.String(  "  rom:  "); C.Int(TextSize); C.String(" of "); C.Int(rom); C.String("  ("); C.Int(TextSize * 100 DIV rom); C.StringLn("%)");
  1749.     IF Free.size > 0 THEN
  1750.         C.String(  "        "); C.Int(Free.size); C.String(" bytes free (0");
  1751.             C.Hex(Free.address, 4); C.String("H..0"); C.Hex(Free.address + Free.size - 1, 4); C.StringLn("H)")
  1752.     END;
  1753.     C.Ln;
  1754.     C.String(  "  ram:  "); C.Int(Bss.size); C.String(" of "); C.Int(ram); C.String("  ("); C.Int(Bss.size * 100 DIV ram); C.StringLn("%)")
  1755.  
  1756. END CodeGen;
  1757.  
  1758.  
  1759. END MSP430.