Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
7693 akron1 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 (code: IL.CODES);
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 := code.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* (code: IL.CODES; 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 code.bss > ram - minStackSize - RTL.VarSize THEN
1672
        ERRORS.Error(204)
1673
    END;
1674
 
1675
    Labels := CHL.CreateIntList();
1676
    FOR i := 1 TO code.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(code.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(code);
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(code.data);
1697
    Data.size := Data.size + ORD(ODD(Data.size));
1698
    TextSize  := Code.size + Data.size;
1699
 
1700
    IF Code.address + TextSize + MAX(code.dmin - Data.size, IntVectorSize + TypesSize) > 10000H  THEN
1701
        ERRORS.Error(203)
1702
    END;
1703
 
1704
    Bss.address := RTL.ram + RTL.VarSize;
1705
    Bss.size := code.bss + ORD(ODD(code.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(code.data) - 1 DO
1728
        mem[adr] := CHL.GetByte(code.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(code.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.