Subversion Repositories Kolibri OS

Rev

Rev 7696 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
7983 leency 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.