Subversion Repositories Kolibri OS

Rev

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

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