Rev 7983 | 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 THUMB; |
||
9 | |||
10 | IMPORT PROG, LISTS, CHL := CHUNKLISTS, BIN, REG, IL, C := CONSOLE, |
||
11 | UTILS, WR := WRITER, HEX, ERRORS, TARGETS; |
||
12 | |||
13 | |||
14 | CONST |
||
15 | |||
16 | R0 = 0; R1 = 1; R2 = 2; R3 = 3; R4 = 4; |
||
17 | |||
18 | SP = 13; LR = 14; PC = 15; |
||
19 | |||
20 | ACC = R0; |
||
21 | |||
22 | je = 0; jne = 1; jnb = 2; jb = 3; jge = 10; jl = 11; jg = 12; jle = 13; |
||
23 | |||
24 | inf = 7F800000H; |
||
25 | |||
26 | STM32_minROM* = 16; STM32_maxROM* = 65536; |
||
27 | STM32_minRAM* = 4; STM32_maxRAM* = 65536; |
||
28 | |||
29 | maxIVT* = 1023; |
||
30 | |||
31 | |||
32 | TYPE |
||
33 | |||
34 | COMMAND = IL.COMMAND; |
||
35 | |||
36 | ANYCODE = POINTER TO RECORD (LISTS.ITEM) |
||
37 | |||
38 | offset: INTEGER |
||
39 | |||
40 | END; |
||
41 | |||
42 | CODE = POINTER TO RECORD (ANYCODE) |
||
43 | |||
44 | code: INTEGER |
||
45 | |||
46 | END; |
||
47 | |||
48 | LABEL = POINTER TO RECORD (ANYCODE) |
||
49 | |||
50 | label: INTEGER |
||
51 | |||
52 | END; |
||
53 | |||
54 | JUMP = POINTER TO RECORD (ANYCODE) |
||
55 | |||
56 | label, diff, len, cond: INTEGER; |
||
57 | short: BOOLEAN |
||
58 | |||
59 | END; |
||
60 | |||
61 | JMP = POINTER TO RECORD (JUMP) |
||
62 | |||
63 | END; |
||
64 | |||
65 | JCC = POINTER TO RECORD (JUMP) |
||
66 | |||
67 | END; |
||
68 | |||
69 | CBXZ = POINTER TO RECORD (JUMP) |
||
70 | |||
71 | reg: INTEGER |
||
72 | |||
73 | END; |
||
74 | |||
75 | CALL = POINTER TO RECORD (JUMP) |
||
76 | |||
77 | END; |
||
78 | |||
79 | RELOC = POINTER TO RECORD (ANYCODE) |
||
80 | |||
81 | reg, rel, value: INTEGER |
||
82 | |||
83 | END; |
||
84 | |||
85 | RELOCCODE = ARRAY 7 OF INTEGER; |
||
86 | |||
87 | |||
88 | VAR |
||
89 | |||
90 | R: REG.REGS; |
||
91 | |||
92 | tcount: INTEGER; |
||
93 | |||
94 | CodeList: LISTS.LIST; |
||
95 | |||
96 | program: BIN.PROGRAM; |
||
97 | |||
98 | StkCount: INTEGER; |
||
99 | |||
100 | Target: RECORD |
||
101 | FlashAdr, |
||
102 | SRAMAdr, |
||
103 | IVTLen, |
||
104 | MinStack, |
||
105 | Reserved: INTEGER; |
||
106 | InstrSet: RECORD thumb2, it, cbxz, sdiv: BOOLEAN END |
||
107 | END; |
||
108 | |||
109 | IVT: ARRAY maxIVT + 1 OF INTEGER; |
||
110 | |||
111 | sdivProc, trap, genTrap, entry, emptyProc, int0, genInt: INTEGER; |
||
112 | |||
113 | |||
114 | PROCEDURE Code (code: INTEGER); |
||
115 | VAR |
||
116 | c: CODE; |
||
117 | |||
118 | BEGIN |
||
119 | NEW(c); |
||
120 | c.code := code; |
||
121 | LISTS.push(CodeList, c) |
||
122 | END Code; |
||
123 | |||
124 | |||
125 | PROCEDURE Label (label: INTEGER); |
||
126 | VAR |
||
127 | L: LABEL; |
||
128 | |||
129 | BEGIN |
||
130 | NEW(L); |
||
131 | L.label := label; |
||
132 | LISTS.push(CodeList, L) |
||
133 | END Label; |
||
134 | |||
135 | |||
136 | PROCEDURE jcc (cond, label: INTEGER); |
||
137 | VAR |
||
138 | j: JCC; |
||
139 | |||
140 | BEGIN |
||
141 | NEW(j); |
||
142 | j.label := label; |
||
143 | j.cond := cond; |
||
144 | j.short := FALSE; |
||
145 | j.len := 3; |
||
146 | LISTS.push(CodeList, j) |
||
147 | END jcc; |
||
148 | |||
149 | |||
150 | PROCEDURE cbxz (cond, reg, label: INTEGER); |
||
151 | VAR |
||
152 | j: CBXZ; |
||
153 | |||
154 | BEGIN |
||
155 | NEW(j); |
||
156 | j.label := label; |
||
157 | j.cond := cond; |
||
158 | j.reg := reg; |
||
159 | j.short := FALSE; |
||
160 | j.len := 4; |
||
161 | LISTS.push(CodeList, j) |
||
162 | END cbxz; |
||
163 | |||
164 | |||
165 | PROCEDURE jmp (label: INTEGER); |
||
166 | VAR |
||
167 | j: JMP; |
||
168 | |||
169 | BEGIN |
||
170 | NEW(j); |
||
171 | j.label := label; |
||
172 | j.short := FALSE; |
||
173 | j.len := 2; |
||
174 | LISTS.push(CodeList, j) |
||
175 | END jmp; |
||
176 | |||
177 | |||
178 | PROCEDURE call (label: INTEGER); |
||
179 | VAR |
||
180 | c: CALL; |
||
181 | |||
182 | BEGIN |
||
183 | NEW(c); |
||
184 | c.label := label; |
||
185 | c.short := FALSE; |
||
186 | c.len := 2; |
||
187 | LISTS.push(CodeList, c) |
||
188 | END call; |
||
189 | |||
190 | |||
191 | PROCEDURE reloc (reg, rel, value: INTEGER); |
||
192 | VAR |
||
193 | r: RELOC; |
||
194 | |||
195 | BEGIN |
||
196 | NEW(r); |
||
197 | r.reg := reg; |
||
198 | r.rel := rel; |
||
199 | r.value := value; |
||
200 | LISTS.push(CodeList, r) |
||
201 | END reloc; |
||
202 | |||
203 | |||
204 | PROCEDURE NewLabel (): INTEGER; |
||
205 | BEGIN |
||
206 | BIN.NewLabel(program) |
||
207 | RETURN IL.NewLabel() |
||
208 | END NewLabel; |
||
209 | |||
210 | |||
211 | PROCEDURE range (x, n: INTEGER): BOOLEAN; |
||
212 | RETURN (0 <= x) & (x < LSL(1, n)) |
||
213 | END range; |
||
214 | |||
215 | |||
216 | PROCEDURE srange (x, n: INTEGER): BOOLEAN; |
||
217 | RETURN (-LSL(1, n - 1) <= x) & (x < LSL(1, n - 1)) |
||
218 | END srange; |
||
219 | |||
220 | |||
221 | PROCEDURE gen1 (op, imm, rs, rd: INTEGER); |
||
222 | BEGIN |
||
223 | ASSERT(op IN {0..2}); |
||
224 | ASSERT(range(imm, 5)); |
||
225 | ASSERT(range(rs, 3)); |
||
226 | ASSERT(range(rd, 3)); |
||
227 | Code(LSL(op, 11) + LSL(imm, 6) + LSL(rs, 3) + rd) |
||
228 | END gen1; |
||
229 | |||
230 | |||
231 | PROCEDURE gen2 (i, op: BOOLEAN; imm, rs, rd: INTEGER); |
||
232 | BEGIN |
||
233 | ASSERT(range(imm, 3)); |
||
234 | ASSERT(range(rs, 3)); |
||
235 | ASSERT(range(rd, 3)); |
||
236 | Code(1800H + LSL(ORD(i), 10) + LSL(ORD(op), 9) + LSL(imm, 6) + LSL(rs, 3) + rd) |
||
237 | END gen2; |
||
238 | |||
239 | |||
240 | PROCEDURE gen3 (op, rd, imm: INTEGER); |
||
241 | BEGIN |
||
242 | ASSERT(range(op, 2)); |
||
243 | ASSERT(range(rd, 3)); |
||
244 | ASSERT(range(imm, 8)); |
||
245 | Code(2000H + LSL(op, 11) + LSL(rd, 8) + imm) |
||
246 | END gen3; |
||
247 | |||
248 | |||
249 | PROCEDURE gen4 (op, rs, rd: INTEGER); |
||
250 | BEGIN |
||
251 | ASSERT(range(op, 4)); |
||
252 | ASSERT(range(rs, 3)); |
||
253 | ASSERT(range(rd, 3)); |
||
254 | Code(4000H + LSL(op, 6) + LSL(rs, 3) + rd) |
||
255 | END gen4; |
||
256 | |||
257 | |||
258 | PROCEDURE gen5 (op: INTEGER; h1, h2: BOOLEAN; rs, rd: INTEGER); |
||
259 | BEGIN |
||
260 | ASSERT(range(op, 2)); |
||
261 | ASSERT(range(rs, 3)); |
||
262 | ASSERT(range(rd, 3)); |
||
263 | Code(4400H + LSL(op, 8) + LSL(ORD(h1), 7) + LSL(ORD(h2), 6) + LSL(rs, 3) + rd) |
||
264 | END gen5; |
||
265 | |||
266 | |||
267 | PROCEDURE gen7 (l, b: BOOLEAN; ro, rb, rd: INTEGER); |
||
268 | BEGIN |
||
269 | ASSERT(range(ro, 3)); |
||
270 | ASSERT(range(rb, 3)); |
||
271 | ASSERT(range(rd, 3)); |
||
272 | Code(5000H + LSL(ORD(l), 11) + LSL(ORD(b), 10) + LSL(ro, 6) + LSL(rb, 3) + rd) |
||
273 | END gen7; |
||
274 | |||
275 | |||
276 | PROCEDURE gen8 (h, s: BOOLEAN; ro, rb, rd: INTEGER); |
||
277 | BEGIN |
||
278 | ASSERT(range(ro, 3)); |
||
279 | ASSERT(range(rb, 3)); |
||
280 | ASSERT(range(rd, 3)); |
||
281 | Code(5200H + LSL(ORD(h), 11) + LSL(ORD(s), 10) + LSL(ro, 6) + LSL(rb, 3) + rd) |
||
282 | END gen8; |
||
283 | |||
284 | |||
285 | PROCEDURE gen9 (b, l: BOOLEAN; imm, rb, rd: INTEGER); |
||
286 | BEGIN |
||
287 | ASSERT(range(imm, 5)); |
||
288 | ASSERT(range(rb, 3)); |
||
289 | ASSERT(range(rd, 3)); |
||
290 | Code(6000H + LSL(ORD(b), 12) + LSL(ORD(l), 11) + LSL(imm, 6) + LSL(rb, 3) + rd) |
||
291 | END gen9; |
||
292 | |||
293 | |||
294 | PROCEDURE gen10 (l: BOOLEAN; imm, rb, rd: INTEGER); |
||
295 | BEGIN |
||
296 | ASSERT(range(imm, 5)); |
||
297 | ASSERT(range(rb, 3)); |
||
298 | ASSERT(range(rd, 3)); |
||
299 | Code(8000H + LSL(ORD(l), 11) + LSL(imm, 6) + LSL(rb, 3) + rd) |
||
300 | END gen10; |
||
301 | |||
302 | |||
303 | PROCEDURE gen11 (l: BOOLEAN; rd, imm: INTEGER); |
||
304 | BEGIN |
||
305 | ASSERT(range(rd, 3)); |
||
306 | ASSERT(range(imm, 8)); |
||
307 | Code(9000H + LSL(ORD(l), 11) + LSL(rd, 8) + imm) |
||
308 | END gen11; |
||
309 | |||
310 | |||
311 | PROCEDURE gen12 (sp: BOOLEAN; rd, imm: INTEGER); |
||
312 | BEGIN |
||
313 | ASSERT(range(rd, 3)); |
||
314 | ASSERT(range(imm, 8)); |
||
315 | Code(0A000H + LSL(ORD(sp), 11) + LSL(rd, 8) + imm) |
||
316 | END gen12; |
||
317 | |||
318 | |||
319 | PROCEDURE gen14 (l, r: BOOLEAN; rlist: SET); |
||
320 | VAR |
||
321 | i, n: INTEGER; |
||
322 | |||
323 | BEGIN |
||
324 | ASSERT(range(ORD(rlist), 8)); |
||
325 | |||
326 | n := ORD(r); |
||
327 | FOR i := 0 TO 7 DO |
||
328 | IF i IN rlist THEN |
||
329 | INC(n) |
||
330 | END |
||
331 | END; |
||
332 | |||
333 | IF l THEN |
||
334 | n := -n |
||
335 | END; |
||
336 | |||
337 | INC(StkCount, n); |
||
338 | |||
339 | Code(0B400H + LSL(ORD(l), 11) + LSL(ORD(r), 8) + ORD(rlist)) |
||
340 | END gen14; |
||
341 | |||
342 | |||
343 | PROCEDURE split16 (imm16: INTEGER; VAR imm4, imm1, imm3, imm8: INTEGER); |
||
344 | BEGIN |
||
345 | ASSERT(range(imm16, 16)); |
||
346 | imm8 := imm16 MOD 256; |
||
347 | imm4 := LSR(imm16, 12); |
||
348 | imm3 := LSR(imm16, 8) MOD 8; |
||
349 | imm1 := LSR(imm16, 11) MOD 2; |
||
350 | END split16; |
||
351 | |||
352 | |||
353 | PROCEDURE LslImm (r, imm5: INTEGER); |
||
354 | BEGIN |
||
355 | gen1(0, imm5, r, r) |
||
356 | END LslImm; |
||
357 | |||
358 | |||
359 | PROCEDURE LsrImm (r, imm5: INTEGER); |
||
360 | BEGIN |
||
361 | gen1(1, imm5, r, r) |
||
362 | END LsrImm; |
||
363 | |||
364 | |||
365 | PROCEDURE AsrImm (r, imm5: INTEGER); |
||
366 | BEGIN |
||
367 | gen1(2, imm5, r, r) |
||
368 | END AsrImm; |
||
369 | |||
370 | |||
371 | PROCEDURE AddReg (rd, rs, rn: INTEGER); |
||
372 | BEGIN |
||
373 | gen2(FALSE, FALSE, rn, rs, rd) |
||
374 | END AddReg; |
||
375 | |||
376 | |||
377 | PROCEDURE SubReg (rd, rs, rn: INTEGER); |
||
378 | BEGIN |
||
379 | gen2(FALSE, TRUE, rn, rs, rd) |
||
380 | END SubReg; |
||
381 | |||
382 | |||
383 | PROCEDURE AddImm8 (rd, imm8: INTEGER); |
||
384 | BEGIN |
||
385 | IF imm8 # 0 THEN |
||
386 | gen3(2, rd, imm8) |
||
387 | END |
||
388 | END AddImm8; |
||
389 | |||
390 | |||
391 | PROCEDURE SubImm8 (rd, imm8: INTEGER); |
||
392 | BEGIN |
||
393 | IF imm8 # 0 THEN |
||
394 | gen3(3, rd, imm8) |
||
395 | END |
||
396 | END SubImm8; |
||
397 | |||
398 | |||
399 | PROCEDURE AddSubImm12 (r, imm12: INTEGER; sub: BOOLEAN); |
||
400 | VAR |
||
401 | imm4, imm1, imm3, imm8: INTEGER; |
||
402 | |||
403 | BEGIN |
||
404 | split16(imm12, imm4, imm1, imm3, imm8); |
||
405 | Code(0F200H + LSL(imm1, 10) + r + 0A0H * ORD(sub)); (* addw/subw r, r, imm12 *) |
||
406 | Code(LSL(imm3, 12) + LSL(r, 8) + imm8) |
||
407 | END AddSubImm12; |
||
408 | |||
409 | |||
410 | PROCEDURE MovImm8 (rd, imm8: INTEGER); |
||
411 | BEGIN |
||
412 | gen3(0, rd, imm8) |
||
413 | END MovImm8; |
||
414 | |||
415 | |||
416 | PROCEDURE CmpImm8 (rd, imm8: INTEGER); |
||
417 | BEGIN |
||
418 | gen3(1, rd, imm8) |
||
419 | END CmpImm8; |
||
420 | |||
421 | |||
422 | PROCEDURE Neg (r: INTEGER); |
||
423 | BEGIN |
||
424 | gen4(9, r, r) |
||
425 | END Neg; |
||
426 | |||
427 | |||
428 | PROCEDURE Mul (rd, rs: INTEGER); |
||
429 | BEGIN |
||
430 | gen4(13, rs, rd) |
||
431 | END Mul; |
||
432 | |||
433 | |||
434 | PROCEDURE Str32 (rs, rb: INTEGER); |
||
435 | BEGIN |
||
436 | gen9(FALSE, FALSE, 0, rb, rs) |
||
437 | END Str32; |
||
438 | |||
439 | |||
440 | PROCEDURE Ldr32 (rd, rb: INTEGER); |
||
441 | BEGIN |
||
442 | gen9(FALSE, TRUE, 0, rb, rd) |
||
443 | END Ldr32; |
||
444 | |||
445 | |||
446 | PROCEDURE Str16 (rs, rb: INTEGER); |
||
447 | BEGIN |
||
448 | gen10(FALSE, 0, rb, rs) |
||
449 | END Str16; |
||
450 | |||
451 | |||
452 | PROCEDURE Ldr16 (rd, rb: INTEGER); |
||
453 | BEGIN |
||
454 | gen10(TRUE, 0, rb, rd) |
||
455 | END Ldr16; |
||
456 | |||
457 | |||
458 | PROCEDURE Str8 (rs, rb: INTEGER); |
||
459 | BEGIN |
||
460 | gen9(TRUE, FALSE, 0, rb, rs) |
||
461 | END Str8; |
||
462 | |||
463 | |||
464 | PROCEDURE Ldr8 (rd, rb: INTEGER); |
||
465 | BEGIN |
||
466 | gen9(TRUE, TRUE, 0, rb, rd) |
||
467 | END Ldr8; |
||
468 | |||
469 | |||
470 | PROCEDURE Cmp (r1, r2: INTEGER); |
||
471 | BEGIN |
||
472 | gen4(10, r2, r1) |
||
473 | END Cmp; |
||
474 | |||
475 | |||
476 | PROCEDURE Tst (r: INTEGER); |
||
477 | BEGIN |
||
478 | gen3(1, r, 0) (* cmp r, #0 *) |
||
479 | END Tst; |
||
480 | |||
481 | |||
482 | PROCEDURE LdrSp (r, offset: INTEGER); |
||
483 | BEGIN |
||
484 | gen11(TRUE, r, offset) |
||
485 | END LdrSp; |
||
486 | |||
487 | |||
488 | PROCEDURE MovImm32 (r, imm32: INTEGER); |
||
489 | BEGIN |
||
490 | MovImm8(r, LSR(imm32, 24) MOD 256); |
||
491 | LslImm(r, 8); |
||
492 | AddImm8(r, LSR(imm32, 16) MOD 256); |
||
493 | LslImm(r, 8); |
||
494 | AddImm8(r, LSR(imm32, 8) MOD 256); |
||
495 | LslImm(r, 8); |
||
496 | AddImm8(r, imm32 MOD 256) |
||
497 | END MovImm32; |
||
498 | |||
499 | |||
500 | PROCEDURE low (x: INTEGER): INTEGER; |
||
501 | RETURN x MOD 65536 |
||
502 | END low; |
||
503 | |||
504 | |||
505 | PROCEDURE high (x: INTEGER): INTEGER; |
||
506 | RETURN (x DIV 65536) MOD 65536 |
||
507 | END high; |
||
508 | |||
509 | |||
510 | PROCEDURE movwt (r, imm16, t: INTEGER); |
||
511 | VAR |
||
512 | imm1, imm3, imm4, imm8: INTEGER; |
||
513 | |||
514 | BEGIN |
||
515 | ASSERT(range(r, 3)); |
||
516 | ASSERT(range(imm16, 16)); |
||
517 | ASSERT(range(t, 1)); |
||
518 | split16(imm16, imm4, imm1, imm3, imm8); |
||
519 | Code(0F240H + imm1 * 1024 + t * 128 + imm4); |
||
520 | Code(imm3 * 4096 + r * 256 + imm8); |
||
521 | END movwt; |
||
522 | |||
523 | |||
524 | PROCEDURE inv0 (cond: INTEGER): INTEGER; |
||
525 | RETURN ORD(BITS(cond) / {0}) |
||
526 | END inv0; |
||
527 | |||
528 | |||
529 | PROCEDURE fixup (CodeAdr, DataAdr, BssAdr: INTEGER); |
||
530 | VAR |
||
531 | code: ANYCODE; |
||
532 | count: INTEGER; |
||
533 | shorted: BOOLEAN; |
||
534 | jump: JUMP; |
||
535 | |||
536 | first, second: INTEGER; |
||
537 | |||
538 | reloc, i, diff, len: INTEGER; |
||
539 | |||
540 | RelocCode: RELOCCODE; |
||
541 | |||
542 | |||
543 | PROCEDURE genjcc (cond, offset: INTEGER): INTEGER; |
||
544 | BEGIN |
||
545 | ASSERT(range(cond, 4)); |
||
546 | ASSERT(srange(offset, 8)) |
||
547 | RETURN 0D000H + cond * 256 + offset MOD 256 |
||
548 | END genjcc; |
||
549 | |||
550 | |||
551 | PROCEDURE genjmp (offset: INTEGER): INTEGER; |
||
552 | BEGIN |
||
553 | ASSERT(srange(offset, 11)) |
||
554 | RETURN 0E000H + offset MOD 2048 |
||
555 | END genjmp; |
||
556 | |||
557 | |||
558 | PROCEDURE genlongjmp (offset: INTEGER; VAR first, second: INTEGER); |
||
559 | BEGIN |
||
560 | ASSERT(srange(offset, 22)); |
||
561 | first := 0F000H + ASR(offset, 11) MOD 2048; |
||
562 | second := 0F800H + offset MOD 2048 |
||
563 | END genlongjmp; |
||
564 | |||
565 | |||
566 | PROCEDURE movwt (r, imm16, t: INTEGER; VAR code: RELOCCODE); |
||
567 | VAR |
||
568 | imm1, imm3, imm4, imm8: INTEGER; |
||
569 | |||
570 | BEGIN |
||
571 | split16(imm16, imm4, imm1, imm3, imm8); |
||
572 | code[t * 2] := 0F240H + imm1 * 1024 + t * 128 + imm4; |
||
573 | code[t * 2 + 1] := imm3 * 4096 + r * 256 + imm8 |
||
574 | END movwt; |
||
575 | |||
576 | |||
577 | PROCEDURE genmovimm32 (r, value: INTEGER; VAR code: RELOCCODE); |
||
578 | BEGIN |
||
579 | IF Target.InstrSet.thumb2 THEN |
||
580 | movwt(r, low(value), 0, code); |
||
581 | movwt(r, high(value), 1, code) |
||
582 | ELSE |
||
583 | code[0] := 2000H + r * 256 + UTILS.Byte(value, 3); (* mov r, #imm8 *) |
||
584 | code[1] := 0200H + r * 9; (* lsl r, r, #8 *) |
||
585 | code[2] := 3000H + r * 256 + UTILS.Byte(value, 2); (* add r, #imm8 *) |
||
586 | code[3] := code[1]; (* lsl r, r, #8 *) |
||
587 | code[4] := 3000H + r * 256 + UTILS.Byte(value, 1); (* add r, #imm8 *) |
||
588 | code[5] := code[1]; (* lsl r, r, #8 *) |
||
589 | code[6] := 3000H + r * 256 + UTILS.Byte(value, 0) (* add r, #imm8 *) |
||
590 | END |
||
591 | END genmovimm32; |
||
592 | |||
593 | |||
594 | PROCEDURE PutCode (code: INTEGER); |
||
595 | BEGIN |
||
596 | BIN.PutCode16LE(program, code) |
||
597 | END PutCode; |
||
598 | |||
599 | |||
600 | PROCEDURE genbc (code: JUMP); |
||
601 | VAR |
||
602 | first, second: INTEGER; |
||
603 | |||
604 | BEGIN |
||
605 | CASE code.len OF |
||
606 | |1: PutCode(genjcc(code.cond, code.diff)) |
||
607 | |2: PutCode(genjcc(inv0(code.cond), 0)); |
||
608 | PutCode(genjmp(code.diff)) |
||
609 | |3: PutCode(genjcc(inv0(code.cond), 1)); |
||
610 | genlongjmp(code.diff, first, second); |
||
611 | PutCode(first); |
||
612 | PutCode(second) |
||
613 | END |
||
614 | END genbc; |
||
615 | |||
616 | |||
617 | PROCEDURE SetIV (idx, label, CodeAdr: INTEGER); |
||
618 | VAR |
||
8097 | maxcodehac | 619 | l, h: LISTS.ITEM; |
7983 | leency | 620 | |
621 | BEGIN |
||
8097 | maxcodehac | 622 | l := CodeList.first; |
623 | h := l.next; |
||
7983 | leency | 624 | WHILE idx > 0 DO |
8097 | maxcodehac | 625 | l := h.next; |
626 | h := l.next; |
||
7983 | leency | 627 | DEC(idx) |
628 | END; |
||
629 | label := BIN.GetLabel(program, label) * 2 + CodeAdr + 1; |
||
630 | l(CODE).code := low(label); |
||
631 | h(CODE).code := high(label) |
||
632 | END SetIV; |
||
633 | |||
634 | |||
635 | BEGIN |
||
636 | |||
637 | REPEAT |
||
638 | |||
639 | shorted := FALSE; |
||
640 | count := 0; |
||
641 | |||
642 | code := CodeList.first(ANYCODE); |
||
643 | WHILE code # NIL DO |
||
644 | code.offset := count; |
||
645 | |||
646 | CASE code OF |
||
647 | |CODE: INC(count) |
||
648 | |LABEL: BIN.SetLabel(program, code.label, count) |
||
649 | |JUMP: INC(count, code.len); code.offset := count + ORD(code.short) |
||
650 | |RELOC: INC(count, 7 - ORD(Target.InstrSet.thumb2) * 3 + code.rel MOD 2) |
||
651 | END; |
||
652 | |||
653 | code := code.next(ANYCODE) |
||
654 | END; |
||
655 | |||
656 | code := CodeList.first(ANYCODE); |
||
657 | WHILE code # NIL DO |
||
658 | |||
659 | IF code IS JUMP THEN |
||
660 | jump := code(JUMP); |
||
661 | jump.diff := BIN.GetLabel(program, jump.label) - jump.offset; |
||
662 | len := jump.len; |
||
663 | diff := jump.diff; |
||
664 | CASE jump OF |
||
665 | |JMP: |
||
666 | IF (len = 2) & srange(diff, 11) THEN |
||
667 | len := 1 |
||
668 | END |
||
669 | |||
670 | |JCC: |
||
671 | CASE len OF |
||
672 | |1: |
||
673 | |2: IF srange(diff, 8) THEN DEC(len) END |
||
674 | |3: IF srange(diff, 11) THEN DEC(len) END |
||
675 | END |
||
676 | |||
677 | |CBXZ: |
||
678 | CASE len OF |
||
679 | |1: |
||
680 | |2: IF range(diff, 6) THEN DEC(len) END |
||
681 | |3: IF srange(diff, 8) THEN DEC(len) END |
||
682 | |4: IF srange(diff, 11) THEN DEC(len) END |
||
683 | END |
||
684 | |||
685 | |CALL: |
||
686 | |||
687 | END; |
||
688 | IF len # jump.len THEN |
||
689 | jump.len := len; |
||
690 | jump.short := TRUE; |
||
691 | shorted := TRUE |
||
692 | END |
||
693 | END; |
||
694 | |||
695 | code := code.next(ANYCODE) |
||
696 | END |
||
697 | |||
698 | UNTIL ~shorted; |
||
699 | |||
700 | FOR i := 1 TO Target.IVTLen - 1 DO |
||
701 | SetIV(i, IVT[i], CodeAdr) |
||
702 | END; |
||
703 | |||
704 | code := CodeList.first(ANYCODE); |
||
705 | WHILE code # NIL DO |
||
706 | |||
707 | CASE code OF |
||
708 | |||
709 | |CODE: BIN.PutCode16LE(program, code.code) |
||
710 | |||
711 | |LABEL: |
||
712 | |||
713 | |JMP: |
||
714 | IF code.len = 1 THEN |
||
715 | PutCode(genjmp(code.diff)) |
||
716 | ELSE |
||
717 | genlongjmp(code.diff, first, second); |
||
718 | PutCode(first); |
||
719 | PutCode(second) |
||
720 | END |
||
721 | |||
8097 | maxcodehac | 722 | |JCC: genbc(code) |
7983 | leency | 723 | |
724 | |CBXZ: |
||
725 | IF code.len > 1 THEN |
||
726 | PutCode(2800H + code.reg * 256); (* cmp code.reg, #0 *) |
||
727 | DEC(code.len); |
||
728 | genbc(code) |
||
729 | ELSE |
||
730 | (* cb(n)z code.reg, L *) |
||
731 | PutCode(0B100H + 800H * ORD(code.cond = jne) + 200H * ORD(code.diff >= 32) + (code.diff MOD 32) * 8 + code.reg) |
||
732 | END |
||
733 | |||
734 | |CALL: |
||
735 | genlongjmp(code.diff, first, second); |
||
736 | PutCode(first); |
||
737 | PutCode(second) |
||
738 | |||
739 | |RELOC: |
||
740 | CASE code.rel OF |
||
741 | |BIN.RCODE, BIN.PICCODE: reloc := BIN.GetLabel(program, code.value) * 2 + CodeAdr |
||
742 | |BIN.RDATA, BIN.PICDATA: reloc := code.value + DataAdr |
||
743 | |BIN.RBSS, BIN.PICBSS: reloc := code.value + BssAdr |
||
744 | END; |
||
745 | IF code.rel IN {BIN.PICCODE, BIN.PICDATA, BIN.PICBSS} THEN |
||
746 | DEC(reloc, CodeAdr + 2 * (code.offset - 3 * ORD(Target.InstrSet.thumb2) + 9)) |
||
747 | END; |
||
748 | genmovimm32(code.reg, reloc, RelocCode); |
||
749 | FOR i := 0 TO 6 - 3 * ORD(Target.InstrSet.thumb2) DO |
||
750 | PutCode(RelocCode[i]) |
||
751 | END; |
||
752 | IF code.rel IN {BIN.PICCODE, BIN.PICDATA, BIN.PICBSS} THEN |
||
753 | PutCode(4478H + code.reg) (* add code.reg, PC *) |
||
754 | END |
||
755 | END; |
||
756 | |||
757 | code := code.next(ANYCODE) |
||
758 | END |
||
759 | |||
760 | END fixup; |
||
761 | |||
762 | |||
763 | PROCEDURE push (r: INTEGER); |
||
764 | BEGIN |
||
765 | gen14(FALSE, FALSE, {r}) |
||
766 | END push; |
||
767 | |||
768 | |||
769 | PROCEDURE pop (r: INTEGER); |
||
770 | BEGIN |
||
771 | gen14(TRUE, FALSE, {r}) |
||
772 | END pop; |
||
773 | |||
774 | |||
775 | PROCEDURE mov (r1, r2: INTEGER); |
||
776 | BEGIN |
||
777 | IF (r1 < 8) & (r2 < 8) THEN |
||
778 | gen1(0, 0, r2, r1) |
||
779 | ELSE |
||
780 | gen5(2, r1 >= 8, r2 >= 8, r2 MOD 8, r1 MOD 8) |
||
781 | END |
||
782 | END mov; |
||
783 | |||
784 | |||
785 | PROCEDURE xchg (r1, r2: INTEGER); |
||
786 | BEGIN |
||
8097 | maxcodehac | 787 | push(r1); |
788 | mov(r1, r2); |
||
789 | pop(r2) |
||
7983 | leency | 790 | END xchg; |
791 | |||
792 | |||
793 | PROCEDURE drop; |
||
794 | BEGIN |
||
795 | REG.Drop(R) |
||
796 | END drop; |
||
797 | |||
798 | |||
799 | PROCEDURE GetAnyReg (): INTEGER; |
||
800 | RETURN REG.GetAnyReg(R) |
||
801 | END GetAnyReg; |
||
802 | |||
803 | |||
804 | PROCEDURE UnOp (VAR r: INTEGER); |
||
805 | BEGIN |
||
806 | REG.UnOp(R, r) |
||
807 | END UnOp; |
||
808 | |||
809 | |||
810 | PROCEDURE BinOp (VAR r1, r2: INTEGER); |
||
811 | BEGIN |
||
812 | REG.BinOp(R, r1, r2) |
||
813 | END BinOp; |
||
814 | |||
815 | |||
816 | PROCEDURE PushAll (NumberOfParameters: INTEGER); |
||
817 | BEGIN |
||
818 | REG.PushAll(R); |
||
819 | DEC(R.pushed, NumberOfParameters) |
||
820 | END PushAll; |
||
821 | |||
822 | |||
823 | PROCEDURE cond (op: INTEGER): INTEGER; |
||
824 | VAR |
||
825 | res: INTEGER; |
||
826 | |||
827 | BEGIN |
||
828 | CASE op OF |
||
829 | |IL.opGT, IL.opGTC: res := jg |
||
830 | |IL.opGE, IL.opGEC: res := jge |
||
831 | |IL.opLT, IL.opLTC: res := jl |
||
832 | |IL.opLE, IL.opLEC: res := jle |
||
833 | |IL.opEQ, IL.opEQC: res := je |
||
834 | |IL.opNE, IL.opNEC: res := jne |
||
835 | END |
||
836 | |||
837 | RETURN res |
||
838 | END cond; |
||
839 | |||
840 | |||
841 | PROCEDURE GetRegA; |
||
842 | BEGIN |
||
843 | ASSERT(REG.GetReg(R, ACC)) |
||
844 | END GetRegA; |
||
845 | |||
846 | |||
847 | PROCEDURE MovConst (r, c: INTEGER); |
||
848 | BEGIN |
||
849 | IF (0 <= c) & (c <= 255) THEN |
||
850 | MovImm8(r, c) |
||
851 | ELSIF (-255 <= c) & (c < 0) THEN |
||
852 | MovImm8(r, -c); |
||
853 | Neg(r) |
||
854 | ELSIF UTILS.Log2(c) >= 0 THEN |
||
855 | MovImm8(r, 1); |
||
856 | LslImm(r, UTILS.Log2(c)) |
||
857 | ELSIF c = UTILS.min32 THEN |
||
858 | MovImm8(r, 1); |
||
859 | LslImm(r, 31) |
||
860 | ELSE |
||
861 | IF Target.InstrSet.thumb2 THEN |
||
862 | movwt(r, low(c), 0); |
||
863 | IF (c < 0) OR (c > 65535) THEN |
||
864 | movwt(r, high(c), 1) |
||
865 | END |
||
866 | ELSE |
||
867 | MovImm32(r, c) |
||
868 | END |
||
869 | END |
||
870 | END MovConst; |
||
871 | |||
872 | |||
873 | PROCEDURE CmpConst (r, c: INTEGER); |
||
874 | VAR |
||
875 | r2: INTEGER; |
||
876 | |||
877 | BEGIN |
||
878 | IF (0 <= c) & (c <= 255) THEN |
||
879 | CmpImm8(r, c) |
||
880 | ELSE |
||
881 | r2 := GetAnyReg(); |
||
882 | ASSERT(r2 # r); |
||
883 | MovConst(r2, c); |
||
884 | Cmp(r, r2); |
||
885 | drop |
||
886 | END |
||
887 | END CmpConst; |
||
888 | |||
889 | |||
890 | PROCEDURE LocalOffset (offset: INTEGER): INTEGER; |
||
891 | RETURN offset + StkCount - ORD(offset > 0) |
||
892 | END LocalOffset; |
||
893 | |||
894 | |||
895 | PROCEDURE SetCC (cc, r: INTEGER); |
||
896 | VAR |
||
897 | L1, L2: INTEGER; |
||
898 | |||
899 | BEGIN |
||
900 | IF Target.InstrSet.it THEN |
||
901 | Code(0BF00H + cc * 16 + ((cc + 1) MOD 2) * 8 + 4); (* ite cc *) |
||
902 | MovConst(r, 1); |
||
903 | MovConst(r, 0) |
||
904 | ELSE |
||
905 | L1 := NewLabel(); |
||
906 | L2 := NewLabel(); |
||
907 | jcc(cc, L1); |
||
908 | MovConst(r, 0); |
||
909 | jmp(L2); |
||
910 | Label(L1); |
||
911 | MovConst(r, 1); |
||
912 | Label(L2) |
||
913 | END |
||
914 | END SetCC; |
||
915 | |||
916 | |||
917 | PROCEDURE PushConst (n: INTEGER); |
||
918 | VAR |
||
919 | r: INTEGER; |
||
920 | |||
921 | BEGIN |
||
922 | r := GetAnyReg(); |
||
923 | MovConst(r, n); |
||
924 | push(r); |
||
925 | drop |
||
926 | END PushConst; |
||
927 | |||
928 | |||
929 | PROCEDURE AddConst (r, n: INTEGER); |
||
930 | VAR |
||
931 | r2: INTEGER; |
||
932 | |||
933 | BEGIN |
||
934 | IF n # 0 THEN |
||
935 | IF (-255 <= n) & (n <= 255) THEN |
||
936 | IF n > 0 THEN |
||
937 | AddImm8(r, n) |
||
938 | ELSE |
||
939 | SubImm8(r, -n) |
||
940 | END |
||
941 | ELSIF Target.InstrSet.thumb2 & (-4095 <= n) & (n <= 4095) THEN |
||
942 | IF n > 0 THEN |
||
943 | AddSubImm12(r, n, FALSE) |
||
944 | ELSE |
||
945 | AddSubImm12(r, -n, TRUE) |
||
946 | END |
||
947 | ELSE |
||
948 | r2 := GetAnyReg(); |
||
949 | ASSERT(r2 # r); |
||
950 | IF n > 0 THEN |
||
951 | MovConst(r2, n); |
||
952 | AddReg(r, r, r2) |
||
953 | ELSE |
||
954 | MovConst(r2, -n); |
||
955 | SubReg(r, r, r2) |
||
956 | END; |
||
957 | drop |
||
958 | END |
||
959 | END |
||
960 | END AddConst; |
||
961 | |||
962 | |||
963 | PROCEDURE AddHH (r1, r2: INTEGER); |
||
964 | BEGIN |
||
965 | ASSERT((r1 >= 8) OR (r2 >= 8)); |
||
966 | gen5(0, r1 >= 8, r2 >= 8, r2 MOD 8, r1 MOD 8) |
||
967 | END AddHH; |
||
968 | |||
969 | |||
970 | PROCEDURE AddSP (n: INTEGER); |
||
971 | BEGIN |
||
972 | IF n > 0 THEN |
||
973 | IF n < 127 THEN |
||
974 | Code(0B000H + n) (* add sp, n*4 *) |
||
975 | ELSE |
||
976 | ASSERT(R2 IN R.regs); |
||
977 | MovConst(R2, n * 4); |
||
978 | AddHH(SP, R2) |
||
979 | END; |
||
980 | DEC(StkCount, n) |
||
981 | END |
||
982 | END AddSP; |
||
983 | |||
984 | |||
985 | PROCEDURE cbz (r, label: INTEGER); |
||
986 | BEGIN |
||
987 | IF Target.InstrSet.cbxz THEN |
||
988 | cbxz(je, r, label) |
||
989 | ELSE |
||
990 | Tst(r); |
||
991 | jcc(je, label) |
||
992 | END |
||
993 | END cbz; |
||
994 | |||
995 | |||
996 | PROCEDURE cbnz (r, label: INTEGER); |
||
997 | BEGIN |
||
998 | IF Target.InstrSet.cbxz THEN |
||
999 | cbxz(jne, r, label) |
||
1000 | ELSE |
||
1001 | Tst(r); |
||
1002 | jcc(jne, label) |
||
1003 | END |
||
1004 | END cbnz; |
||
1005 | |||
1006 | |||
1007 | PROCEDURE Shift (op, r1, r2: INTEGER); |
||
1008 | VAR |
||
1009 | L: INTEGER; |
||
1010 | |||
1011 | BEGIN |
||
1012 | LslImm(r2, 27); |
||
1013 | LsrImm(r2, 27); |
||
1014 | L := NewLabel(); |
||
1015 | cbz(r2, L); |
||
1016 | CASE op OF |
||
1017 | |IL.opLSL, IL.opLSL1: gen4(2, r2, r1) |
||
1018 | |IL.opLSR, IL.opLSR1: gen4(3, r2, r1) |
||
1019 | |IL.opASR, IL.opASR1: gen4(4, r2, r1) |
||
1020 | |IL.opROR, IL.opROR1: gen4(7, r2, r1) |
||
1021 | END; |
||
1022 | Label(L) |
||
1023 | END Shift; |
||
1024 | |||
1025 | |||
1026 | PROCEDURE LocAdr (offs: INTEGER); |
||
1027 | VAR |
||
1028 | r1, n: INTEGER; |
||
1029 | |||
1030 | BEGIN |
||
1031 | r1 := GetAnyReg(); |
||
1032 | n := LocalOffset(offs); |
||
1033 | IF n <= 255 THEN |
||
1034 | gen12(TRUE, r1, n) |
||
1035 | ELSE |
||
1036 | MovConst(r1, n * 4); |
||
1037 | AddHH(r1, SP) |
||
1038 | END |
||
1039 | END LocAdr; |
||
1040 | |||
1041 | |||
1042 | PROCEDURE CallRTL (proc, par: INTEGER); |
||
1043 | BEGIN |
||
1044 | call(IL.codes.rtl[proc]); |
||
1045 | AddSP(par) |
||
1046 | END CallRTL; |
||
1047 | |||
1048 | |||
1049 | PROCEDURE divmod; |
||
1050 | BEGIN |
||
1051 | call(sdivProc); |
||
1052 | AddSP(2) |
||
1053 | END divmod; |
||
1054 | |||
1055 | |||
1056 | PROCEDURE translate (pic, stroffs: INTEGER); |
||
1057 | VAR |
||
1058 | cmd, next: COMMAND; |
||
1059 | opcode, param1, param2: INTEGER; |
||
1060 | |||
1061 | r1, r2, r3: INTEGER; |
||
1062 | |||
1063 | a, n, cc, L, L2: INTEGER; |
||
1064 | |||
1065 | BEGIN |
||
1066 | cmd := IL.codes.commands.first(COMMAND); |
||
1067 | |||
1068 | WHILE cmd # NIL DO |
||
1069 | |||
1070 | param1 := cmd.param1; |
||
1071 | param2 := cmd.param2; |
||
1072 | opcode := cmd.opcode; |
||
1073 | |||
1074 | CASE opcode OF |
||
1075 | |||
1076 | |IL.opJMP: |
||
1077 | jmp(param1) |
||
1078 | |||
1079 | |IL.opLABEL: |
||
1080 | Label(param1) |
||
1081 | |||
1082 | |IL.opHANDLER: |
||
1083 | IF param2 = 0 THEN |
||
1084 | int0 := param1 |
||
1085 | ELSIF param2 = 1 THEN |
||
1086 | trap := param1 |
||
1087 | ELSE |
||
1088 | IVT[param2] := param1 |
||
1089 | END |
||
1090 | |||
1091 | |IL.opCALL: |
||
1092 | call(param1) |
||
1093 | |||
1094 | |IL.opCALLP: |
||
1095 | UnOp(r1); |
||
8097 | maxcodehac | 1096 | AddImm8(r1, 1); (* Thumb mode *) |
7983 | leency | 1097 | gen5(3, TRUE, FALSE, r1, 0); (* blx r1 *) |
1098 | drop; |
||
1099 | ASSERT(R.top = -1) |
||
1100 | |||
1101 | |IL.opENTER: |
||
1102 | ASSERT(R.top = -1); |
||
1103 | |||
1104 | Label(param1); |
||
1105 | |||
1106 | gen14(FALSE, TRUE, {}); (* push LR *) |
||
1107 | |||
1108 | n := param2; |
||
1109 | IF n >= 5 THEN |
||
1110 | MovConst(ACC, 0); |
||
1111 | MovConst(R2, n); |
||
1112 | L := NewLabel(); |
||
1113 | Label(L); |
||
1114 | push(ACC); |
||
1115 | SubImm8(R2, 1); |
||
1116 | Tst(R2); |
||
1117 | jcc(jne, L) |
||
1118 | ELSIF n > 0 THEN |
||
1119 | MovConst(ACC, 0); |
||
1120 | WHILE n > 0 DO |
||
1121 | push(ACC); |
||
1122 | DEC(n) |
||
1123 | END |
||
1124 | END; |
||
1125 | StkCount := param2 |
||
1126 | |||
1127 | |IL.opLEAVE, IL.opLEAVER, IL.opLEAVEF: |
||
1128 | IF opcode # IL.opLEAVE THEN |
||
1129 | UnOp(r1); |
||
1130 | IF r1 # ACC THEN |
||
1131 | GetRegA; |
||
1132 | ASSERT(REG.Exchange(R, r1, ACC)); |
||
1133 | drop |
||
1134 | END; |
||
1135 | drop |
||
1136 | END; |
||
1137 | |||
1138 | ASSERT(R.top = -1); |
||
1139 | ASSERT(StkCount = param1); |
||
1140 | |||
1141 | AddSP(param1); |
||
1142 | gen14(TRUE, TRUE, {}) (* pop PC *) |
||
1143 | |||
1144 | |IL.opLEAVEC: |
||
1145 | gen5(3, FALSE, TRUE, 6, 0) (* bx LR *) |
||
1146 | |||
1147 | |IL.opPRECALL: |
||
1148 | PushAll(0) |
||
1149 | |||
1150 | |IL.opPARAM: |
||
1151 | n := param2; |
||
1152 | IF n = 1 THEN |
||
1153 | UnOp(r1); |
||
1154 | push(r1); |
||
1155 | drop |
||
1156 | ELSE |
||
1157 | ASSERT(R.top + 1 <= n); |
||
1158 | PushAll(n) |
||
1159 | END |
||
1160 | |||
1161 | |IL.opCLEANUP: |
||
1162 | AddSP(param2) |
||
1163 | |||
1164 | |IL.opRES, IL.opRESF: |
||
1165 | ASSERT(R.top = -1); |
||
1166 | GetRegA |
||
1167 | |||
1168 | |IL.opPUSHC: |
||
1169 | PushConst(param2) |
||
1170 | |||
1171 | |IL.opONERR: |
||
1172 | MovConst(R0, param2); |
||
1173 | push(R0); |
||
1174 | DEC(StkCount); |
||
1175 | jmp(param1) |
||
1176 | |||
1177 | |IL.opERR: |
||
1178 | call(genTrap) |
||
1179 | |||
8097 | maxcodehac | 1180 | |IL.opNOP, IL.opAND, IL.opOR: |
7983 | leency | 1181 | |
1182 | |IL.opSADR: |
||
1183 | reloc(GetAnyReg(), BIN.RDATA + pic, stroffs + param2) |
||
1184 | |||
1185 | |IL.opGADR: |
||
1186 | reloc(GetAnyReg(), BIN.RBSS + pic, param2) |
||
1187 | |||
1188 | |IL.opLADR: |
||
1189 | LocAdr(param2) |
||
1190 | |||
1191 | |IL.opGLOAD32: |
||
1192 | r1 := GetAnyReg(); |
||
1193 | reloc(r1, BIN.RBSS + pic, param2); |
||
1194 | Ldr32(r1, r1) |
||
1195 | |||
1196 | |IL.opGLOAD16: |
||
1197 | r1 := GetAnyReg(); |
||
1198 | reloc(r1, BIN.RBSS + pic, param2); |
||
1199 | Ldr16(r1, r1) |
||
1200 | |||
1201 | |IL.opGLOAD8: |
||
1202 | r1 := GetAnyReg(); |
||
1203 | reloc(r1, BIN.RBSS + pic, param2); |
||
1204 | Ldr8(r1, r1) |
||
1205 | |||
1206 | |IL.opLLOAD32, IL.opVADR, IL.opVLOAD32: |
||
1207 | r1 := GetAnyReg(); |
||
1208 | n := LocalOffset(param2); |
||
1209 | IF n <= 255 THEN |
||
1210 | LdrSp(r1, n) |
||
1211 | ELSE |
||
1212 | drop; |
||
1213 | LocAdr(param2); |
||
1214 | UnOp(r1); |
||
1215 | Ldr32(r1, r1) |
||
1216 | END; |
||
1217 | IF opcode = IL.opVLOAD32 THEN |
||
1218 | Ldr32(r1, r1) |
||
1219 | END |
||
1220 | |||
1221 | |IL.opLLOAD16: |
||
1222 | LocAdr(param2); |
||
1223 | UnOp(r1); |
||
1224 | Ldr16(r1, r1) |
||
1225 | |||
1226 | |IL.opLLOAD8: |
||
1227 | LocAdr(param2); |
||
1228 | UnOp(r1); |
||
1229 | Ldr8(r1, r1) |
||
1230 | |||
1231 | |IL.opLOAD32, IL.opLOADF: |
||
1232 | UnOp(r1); |
||
1233 | Ldr32(r1, r1) |
||
1234 | |||
1235 | |IL.opLOAD16: |
||
1236 | UnOp(r1); |
||
1237 | Ldr16(r1, r1) |
||
1238 | |||
1239 | |IL.opLOAD8: |
||
1240 | UnOp(r1); |
||
1241 | Ldr8(r1, r1) |
||
1242 | |||
1243 | |IL.opVLOAD16: |
||
1244 | LocAdr(param2); |
||
1245 | UnOp(r1); |
||
1246 | Ldr32(r1, r1); |
||
1247 | Ldr16(r1, r1) |
||
1248 | |||
1249 | |IL.opVLOAD8: |
||
1250 | LocAdr(param2); |
||
1251 | UnOp(r1); |
||
1252 | Ldr32(r1, r1); |
||
1253 | Ldr8(r1, r1) |
||
1254 | |||
1255 | |IL.opSBOOL: |
||
1256 | BinOp(r2, r1); |
||
1257 | Tst(r2); |
||
1258 | SetCC(jne, r2); |
||
1259 | Str8(r2, r1); |
||
1260 | drop; |
||
1261 | drop |
||
1262 | |||
1263 | |IL.opSBOOLC: |
||
1264 | UnOp(r1); |
||
1265 | r2 := GetAnyReg(); |
||
1266 | MovConst(r2, ORD(param2 # 0)); |
||
1267 | Str8(r2, r1); |
||
1268 | drop; |
||
1269 | drop |
||
1270 | |||
1271 | |IL.opSAVEC: |
||
1272 | UnOp(r1); |
||
1273 | r2 := GetAnyReg(); |
||
1274 | MovConst(r2, param2); |
||
1275 | Str32(r2, r1); |
||
1276 | drop; |
||
1277 | drop |
||
1278 | |||
1279 | |IL.opSAVE16C: |
||
1280 | UnOp(r1); |
||
1281 | r2 := GetAnyReg(); |
||
1282 | MovConst(r2, low(param2)); |
||
1283 | Str16(r2, r1); |
||
1284 | drop; |
||
1285 | drop |
||
1286 | |||
1287 | |IL.opSAVE8C: |
||
1288 | UnOp(r1); |
||
1289 | r2 := GetAnyReg(); |
||
1290 | MovConst(r2, param2 MOD 256); |
||
1291 | Str8(r2, r1); |
||
1292 | drop; |
||
1293 | drop |
||
1294 | |||
1295 | |IL.opSAVE, IL.opSAVE32, IL.opSAVEF: |
||
1296 | BinOp(r2, r1); |
||
1297 | Str32(r2, r1); |
||
1298 | drop; |
||
1299 | drop |
||
1300 | |||
1301 | |IL.opSAVEFI: |
||
1302 | BinOp(r2, r1); |
||
1303 | Str32(r1, r2); |
||
1304 | drop; |
||
1305 | drop |
||
1306 | |||
1307 | |IL.opSAVE16: |
||
1308 | BinOp(r2, r1); |
||
1309 | Str16(r2, r1); |
||
1310 | drop; |
||
1311 | drop |
||
1312 | |||
1313 | |IL.opSAVE8: |
||
1314 | BinOp(r2, r1); |
||
1315 | Str8(r2, r1); |
||
1316 | drop; |
||
1317 | drop |
||
1318 | |||
1319 | |IL.opSAVEP: |
||
1320 | UnOp(r1); |
||
1321 | r2 := GetAnyReg(); |
||
1322 | reloc(r2, BIN.RCODE + pic, param2); |
||
1323 | Str32(r2, r1); |
||
1324 | drop; |
||
1325 | drop |
||
1326 | |||
1327 | |IL.opPUSHP: |
||
1328 | reloc(GetAnyReg(), BIN.RCODE + pic, param2) |
||
1329 | |||
1330 | |IL.opEQB, IL.opNEB: |
||
1331 | BinOp(r1, r2); |
||
1332 | drop; |
||
1333 | |||
1334 | L := NewLabel(); |
||
1335 | cbz(r1, L); |
||
1336 | MovConst(r1, 1); |
||
1337 | Label(L); |
||
1338 | |||
1339 | L := NewLabel(); |
||
1340 | cbz(r2, L); |
||
1341 | MovConst(r2, 1); |
||
1342 | Label(L); |
||
1343 | |||
1344 | Cmp(r1, r2); |
||
1345 | IF opcode = IL.opEQB THEN |
||
1346 | SetCC(je, r1) |
||
1347 | ELSE |
||
1348 | SetCC(jne, r1) |
||
1349 | END |
||
1350 | |||
1351 | |IL.opDROP: |
||
1352 | UnOp(r1); |
||
1353 | drop |
||
1354 | |||
8097 | maxcodehac | 1355 | |IL.opJNZ1: |
7983 | leency | 1356 | UnOp(r1); |
1357 | cbnz(r1, param1) |
||
1358 | |||
1359 | |IL.opJG: |
||
1360 | UnOp(r1); |
||
1361 | Tst(r1); |
||
1362 | jcc(jg, param1) |
||
1363 | |||
8097 | maxcodehac | 1364 | |IL.opJNZ: |
7983 | leency | 1365 | UnOp(r1); |
1366 | cbnz(r1, param1); |
||
1367 | drop |
||
1368 | |||
8097 | maxcodehac | 1369 | |IL.opJZ: |
7983 | leency | 1370 | UnOp(r1); |
1371 | cbz(r1, param1); |
||
1372 | drop |
||
1373 | |||
1374 | |IL.opSWITCH: |
||
1375 | UnOp(r1); |
||
1376 | IF param2 = 0 THEN |
||
1377 | r2 := ACC |
||
1378 | ELSE |
||
1379 | r2 := R2 |
||
1380 | END; |
||
1381 | IF r1 # r2 THEN |
||
1382 | ASSERT(REG.GetReg(R, r2)); |
||
1383 | ASSERT(REG.Exchange(R, r1, r2)); |
||
1384 | drop |
||
1385 | END; |
||
1386 | drop |
||
1387 | |||
1388 | |IL.opENDSW: |
||
1389 | |||
1390 | |IL.opCASEL: |
||
1391 | GetRegA; |
||
1392 | CmpConst(ACC, param1); |
||
1393 | jcc(jl, param2); |
||
1394 | drop |
||
1395 | |||
1396 | |IL.opCASER: |
||
1397 | GetRegA; |
||
1398 | CmpConst(ACC, param1); |
||
1399 | jcc(jg, param2); |
||
1400 | drop |
||
1401 | |||
1402 | |IL.opCASELR: |
||
1403 | GetRegA; |
||
1404 | CmpConst(ACC, param1); |
||
1405 | jcc(jl, param2); |
||
1406 | jcc(jg, cmd.param3); |
||
1407 | drop |
||
1408 | |||
1409 | |IL.opCODE: |
||
1410 | Code(param2) |
||
1411 | |||
1412 | |IL.opEQ..IL.opGE, |
||
1413 | IL.opEQC..IL.opGEC: |
||
1414 | IF (IL.opEQ <= opcode) & (opcode <= IL.opGE) THEN |
||
1415 | BinOp(r1, r2); |
||
1416 | Cmp(r1, r2); |
||
1417 | drop |
||
1418 | ELSE |
||
1419 | UnOp(r1); |
||
1420 | CmpConst(r1, param2) |
||
1421 | END; |
||
1422 | |||
1423 | drop; |
||
1424 | cc := cond(opcode); |
||
1425 | next := cmd.next(COMMAND); |
||
1426 | |||
8097 | maxcodehac | 1427 | IF next.opcode = IL.opJNZ THEN |
7983 | leency | 1428 | jcc(cc, next.param1); |
1429 | cmd := next |
||
8097 | maxcodehac | 1430 | ELSIF next.opcode = IL.opJZ THEN |
7983 | leency | 1431 | jcc(inv0(cc), next.param1); |
1432 | cmd := next |
||
1433 | ELSE |
||
1434 | SetCC(cc, GetAnyReg()) |
||
1435 | END |
||
1436 | |||
1437 | |IL.opINCC: |
||
1438 | UnOp(r1); |
||
1439 | r2 := GetAnyReg(); |
||
1440 | Ldr32(r2, r1); |
||
1441 | AddConst(r2, param2); |
||
1442 | Str32(r2, r1); |
||
1443 | drop; |
||
1444 | drop |
||
1445 | |||
1446 | |IL.opINCCB, IL.opDECCB: |
||
1447 | IF opcode = IL.opDECCB THEN |
||
1448 | param2 := -param2 |
||
1449 | END; |
||
1450 | UnOp(r1); |
||
1451 | r2 := GetAnyReg(); |
||
1452 | Ldr8(r2, r1); |
||
1453 | AddConst(r2, param2); |
||
1454 | Str8(r2, r1); |
||
1455 | drop; |
||
1456 | drop |
||
1457 | |||
1458 | |IL.opUMINUS: |
||
1459 | UnOp(r1); |
||
1460 | Neg(r1) |
||
1461 | |||
1462 | |IL.opADD: |
||
1463 | BinOp(r1, r2); |
||
1464 | CASE cmd.next(COMMAND).opcode OF |
||
1465 | |IL.opLOAD32, IL.opLOADF: |
||
1466 | gen7(TRUE, FALSE, r2, r1, r1); (* ldr r1, [r1, r2] *) |
||
1467 | cmd := cmd.next(COMMAND) |
||
1468 | |IL.opLOAD8: |
||
1469 | gen7(TRUE, TRUE, r2, r1, r1); (* ldrb r1, [r1, r2] *) |
||
1470 | cmd := cmd.next(COMMAND) |
||
1471 | |IL.opLOAD16: |
||
1472 | gen8(TRUE, FALSE, r2, r1, r1); (* ldrh r1, [r1, r2] *) |
||
1473 | cmd := cmd.next(COMMAND) |
||
1474 | ELSE |
||
1475 | AddReg(r1, r1, r2) |
||
1476 | END; |
||
1477 | drop |
||
1478 | |||
8097 | maxcodehac | 1479 | |IL.opADDC: |
7983 | leency | 1480 | UnOp(r1); |
1481 | AddConst(r1, param2) |
||
1482 | |||
1483 | |IL.opSUB: |
||
1484 | BinOp(r1, r2); |
||
1485 | SubReg(r1, r1, r2); |
||
1486 | drop |
||
1487 | |||
1488 | |IL.opSUBL, IL.opSUBR: |
||
1489 | UnOp(r1); |
||
1490 | AddConst(r1, -param2); |
||
1491 | IF opcode = IL.opSUBL THEN |
||
1492 | Neg(r1) |
||
1493 | END |
||
1494 | |||
1495 | |IL.opMUL: |
||
1496 | BinOp(r1, r2); |
||
1497 | Mul(r1, r2); |
||
1498 | drop |
||
1499 | |||
1500 | |IL.opMULC: |
||
1501 | UnOp(r1); |
||
1502 | |||
1503 | a := param2; |
||
1504 | IF a > 1 THEN |
||
1505 | n := UTILS.Log2(a) |
||
1506 | ELSIF a < -1 THEN |
||
1507 | n := UTILS.Log2(-a) |
||
1508 | ELSE |
||
1509 | n := -1 |
||
1510 | END; |
||
1511 | |||
1512 | IF a = 1 THEN |
||
1513 | |||
1514 | ELSIF a = -1 THEN |
||
1515 | Neg(r1) |
||
1516 | ELSIF a = 0 THEN |
||
1517 | MovConst(r1, 0) |
||
1518 | ELSE |
||
1519 | IF n > 0 THEN |
||
1520 | IF a < 0 THEN |
||
1521 | Neg(r1) |
||
1522 | END; |
||
1523 | LslImm(r1, n) |
||
1524 | ELSE |
||
1525 | r2 := GetAnyReg(); |
||
1526 | MovConst(r2, a); |
||
1527 | Mul(r1, r2); |
||
1528 | drop |
||
1529 | END |
||
1530 | END |
||
1531 | |||
1532 | |IL.opABS: |
||
1533 | UnOp(r1); |
||
1534 | Tst(r1); |
||
1535 | L := NewLabel(); |
||
1536 | jcc(jge, L); |
||
1537 | Neg(r1); |
||
1538 | Label(L) |
||
1539 | |||
1540 | |IL.opNOT: |
||
1541 | UnOp(r1); |
||
1542 | Tst(r1); |
||
1543 | SetCC(je, r1) |
||
1544 | |||
1545 | |IL.opORD: |
||
1546 | UnOp(r1); |
||
1547 | Tst(r1); |
||
1548 | SetCC(jne, r1) |
||
1549 | |||
1550 | |IL.opCHR: |
||
1551 | UnOp(r1); |
||
1552 | Code(0B2C0H + r1 * 9) (* uxtb r1 *) |
||
1553 | |||
1554 | |IL.opWCHR: |
||
1555 | UnOp(r1); |
||
1556 | Code(0B280H + r1 * 9) (* uxth r1 *) |
||
1557 | |||
1558 | |IL.opASR, IL.opROR, IL.opLSL, IL.opLSR: |
||
1559 | BinOp(r1, r2); |
||
1560 | Shift(opcode, r1, r2); |
||
1561 | drop |
||
1562 | |||
1563 | |IL.opASR1, IL.opROR1, IL.opLSL1, IL.opLSR1: |
||
1564 | MovConst(GetAnyReg(), param2); |
||
1565 | BinOp(r2, r1); |
||
1566 | Shift(opcode, r1, r2); |
||
1567 | INCL(R.regs, r2); |
||
1568 | DEC(R.top); |
||
1569 | R.stk[R.top] := r1 |
||
1570 | |||
1571 | |IL.opASR2, IL.opROR2, IL.opLSL2, IL.opLSR2: |
||
1572 | n := param2 MOD 32; |
||
1573 | IF n # 0 THEN |
||
1574 | UnOp(r1); |
||
1575 | CASE opcode OF |
||
1576 | |IL.opASR2: AsrImm(r1, n) |
||
1577 | |IL.opROR2: r2 := GetAnyReg(); MovConst(r2, n); Shift(IL.opROR, r1, r2); drop |
||
1578 | |IL.opLSL2: LslImm(r1, n) |
||
1579 | |IL.opLSR2: LsrImm(r1, n) |
||
1580 | END |
||
1581 | END |
||
1582 | |||
1583 | |IL.opCHKBYTE: |
||
1584 | BinOp(r1, r2); |
||
1585 | CmpConst(r1, 256); |
||
1586 | jcc(jb, param1) |
||
1587 | |||
1588 | |IL.opCHKIDX: |
||
1589 | UnOp(r1); |
||
1590 | CmpConst(r1, param2); |
||
1591 | jcc(jb, param1) |
||
1592 | |||
1593 | |IL.opCHKIDX2: |
||
1594 | BinOp(r1, r2); |
||
1595 | IF param2 # -1 THEN |
||
1596 | Cmp(r2, r1); |
||
1597 | jcc(jb, param1) |
||
1598 | END; |
||
1599 | INCL(R.regs, r1); |
||
1600 | DEC(R.top); |
||
1601 | R.stk[R.top] := r2 |
||
1602 | |||
1603 | |IL.opLEN: |
||
1604 | n := param2; |
||
1605 | UnOp(r1); |
||
1606 | drop; |
||
1607 | EXCL(R.regs, r1); |
||
1608 | |||
1609 | WHILE n > 0 DO |
||
1610 | UnOp(r2); |
||
1611 | drop; |
||
1612 | DEC(n) |
||
1613 | END; |
||
1614 | |||
1615 | INCL(R.regs, r1); |
||
1616 | ASSERT(REG.GetReg(R, r1)) |
||
1617 | |||
1618 | |IL.opLOOP, IL.opENDLOOP: |
||
1619 | |||
1620 | |IL.opINF: |
||
1621 | MovConst(GetAnyReg(), inf) |
||
1622 | |||
1623 | |IL.opPUSHF: |
||
1624 | UnOp(r1); |
||
1625 | push(r1); |
||
1626 | drop |
||
1627 | |||
1628 | |IL.opCONST: |
||
1629 | MovConst(GetAnyReg(), param2) |
||
1630 | |||
1631 | |IL.opEQP, IL.opNEP: |
||
1632 | reloc(GetAnyReg(), BIN.RCODE + pic, param1); |
||
1633 | BinOp(r1, r2); |
||
1634 | Cmp(r1, r2); |
||
1635 | drop; |
||
1636 | IF opcode = IL.opEQP THEN |
||
1637 | SetCC(je, r1) |
||
1638 | ELSE |
||
1639 | SetCC(jne, r1) |
||
1640 | END |
||
1641 | |||
1642 | |IL.opPUSHT: |
||
1643 | UnOp(r1); |
||
1644 | r2 := GetAnyReg(); |
||
1645 | mov(r2, r1); |
||
1646 | SubImm8(r2, 4); |
||
1647 | Ldr32(r2, r2) |
||
1648 | |||
1649 | |IL.opGET, IL.opGETC: |
||
1650 | IF opcode = IL.opGET THEN |
||
1651 | BinOp(r1, r2) |
||
1652 | ELSIF opcode = IL.opGETC THEN |
||
1653 | UnOp(r2); |
||
1654 | r1 := GetAnyReg(); |
||
1655 | MovConst(r1, param1) |
||
1656 | END; |
||
1657 | drop; |
||
1658 | drop; |
||
1659 | |||
1660 | CASE param2 OF |
||
1661 | |1: Ldr8(r1, r1); Str8(r1, r2) |
||
1662 | |2: Ldr16(r1, r1); Str16(r1, r2) |
||
1663 | |4: Ldr32(r1, r1); Str32(r1, r2) |
||
1664 | END |
||
1665 | |||
1666 | |IL.opINC, IL.opDEC: |
||
1667 | BinOp(r2, r1); |
||
1668 | r3 := GetAnyReg(); |
||
1669 | Ldr32(r3, r1); |
||
1670 | IF opcode = IL.opINC THEN |
||
1671 | AddReg(r3, r3, r2) |
||
1672 | ELSE |
||
1673 | SubReg(r3, r3, r2) |
||
1674 | END; |
||
1675 | Str32(r3, r1); |
||
1676 | drop; |
||
1677 | drop; |
||
1678 | drop |
||
1679 | |||
1680 | |IL.opINCB, IL.opDECB: |
||
1681 | BinOp(r2, r1); |
||
1682 | r3 := GetAnyReg(); |
||
1683 | Ldr8(r3, r1); |
||
1684 | IF opcode = IL.opINCB THEN |
||
1685 | AddReg(r3, r3, r2) |
||
1686 | ELSE |
||
1687 | SubReg(r3, r3, r2) |
||
1688 | END; |
||
1689 | Str8(r3, r1); |
||
1690 | drop; |
||
1691 | drop; |
||
1692 | drop |
||
1693 | |||
1694 | |IL.opMIN, IL.opMAX: |
||
1695 | BinOp(r1, r2); |
||
1696 | Cmp(r1, r2); |
||
1697 | L := NewLabel(); |
||
1698 | IF opcode = IL.opMIN THEN |
||
1699 | cc := jle |
||
1700 | ELSE |
||
1701 | cc := jge |
||
1702 | END; |
||
1703 | jcc(cc, L); |
||
1704 | mov(r1, r2); |
||
1705 | Label(L); |
||
1706 | drop |
||
1707 | |||
1708 | |IL.opMINC, IL.opMAXC: |
||
1709 | UnOp(r1); |
||
1710 | CmpConst(r1, param2); |
||
1711 | L := NewLabel(); |
||
1712 | IF opcode = IL.opMINC THEN |
||
1713 | cc := jle |
||
1714 | ELSE |
||
1715 | cc := jge |
||
1716 | END; |
||
1717 | jcc(cc, L); |
||
1718 | MovConst(r1, param2); |
||
1719 | Label(L) |
||
1720 | |||
1721 | |IL.opMULS: |
||
1722 | BinOp(r1, r2); |
||
1723 | gen4(0, r2, r1); (* and r1, r2 *) |
||
1724 | drop |
||
1725 | |||
1726 | |IL.opMULSC: |
||
1727 | MovConst(GetAnyReg(), param2); |
||
1728 | BinOp(r1, r2); |
||
1729 | gen4(0, r2, r1); (* and r1, r2 *) |
||
1730 | drop |
||
1731 | |||
1732 | |IL.opDIVS: |
||
1733 | BinOp(r1, r2); |
||
1734 | gen4(1, r2, r1); (* eor r1, r2 *) |
||
1735 | drop |
||
1736 | |||
1737 | |IL.opDIVSC: |
||
1738 | MovConst(GetAnyReg(), param2); |
||
1739 | BinOp(r1, r2); |
||
1740 | gen4(1, r2, r1); (* eor r1, r2 *) |
||
1741 | drop |
||
1742 | |||
1743 | |IL.opADDS: |
||
1744 | BinOp(r1, r2); |
||
1745 | gen4(12, r2, r1); (* orr r1, r2 *) |
||
1746 | drop |
||
1747 | |||
1748 | |IL.opSUBS: |
||
1749 | BinOp(r1, r2); |
||
1750 | gen4(14, r2, r1); (* bic r1, r2 *) |
||
1751 | drop |
||
1752 | |||
8097 | maxcodehac | 1753 | |IL.opADDSC: |
7983 | leency | 1754 | MovConst(GetAnyReg(), param2); |
1755 | BinOp(r1, r2); |
||
1756 | gen4(12, r2, r1); (* orr r1, r2 *) |
||
1757 | drop |
||
1758 | |||
1759 | |IL.opSUBSL: |
||
1760 | MovConst(GetAnyReg(), param2); |
||
1761 | BinOp(r1, r2); |
||
1762 | gen4(14, r1, r2); (* bic r2, r1 *) |
||
1763 | INCL(R.regs, r1); |
||
1764 | DEC(R.top); |
||
1765 | R.stk[R.top] := r2 |
||
1766 | |||
1767 | |IL.opSUBSR: |
||
1768 | MovConst(GetAnyReg(), param2); |
||
1769 | BinOp(r1, r2); |
||
1770 | gen4(14, r2, r1); (* bic r1, r2 *) |
||
1771 | drop |
||
1772 | |||
1773 | |IL.opUMINS: |
||
1774 | UnOp(r1); |
||
1775 | gen4(15, r1, r1) (* mvn r1, r1 *) |
||
1776 | |||
1777 | |IL.opINCL, IL.opEXCL: |
||
1778 | BinOp(r1, r2); |
||
1779 | r3 := GetAnyReg(); |
||
1780 | MovConst(r3, 1); |
||
1781 | CmpConst(r1, 32); |
||
1782 | L := NewLabel(); |
||
1783 | jcc(jnb, L); |
||
1784 | gen4(2, r1, r3); (* lsl r3, r1 *) |
||
1785 | Ldr32(r1, r2); |
||
1786 | IF opcode = IL.opINCL THEN |
||
1787 | gen4(12, r3, r1) (* orr r1, r3 *) |
||
1788 | ELSE |
||
1789 | gen4(14, r3, r1) (* bic r1, r3 *) |
||
1790 | END; |
||
1791 | Str32(r1, r2); |
||
1792 | Label(L); |
||
1793 | drop; |
||
1794 | drop; |
||
1795 | drop |
||
1796 | |||
1797 | |IL.opINCLC, IL.opEXCLC: |
||
1798 | UnOp(r2); |
||
1799 | r1 := GetAnyReg(); |
||
1800 | r3 := GetAnyReg(); |
||
1801 | MovConst(r3, 1); |
||
1802 | LslImm(r3, param2); |
||
1803 | Ldr32(r1, r2); |
||
1804 | IF opcode = IL.opINCLC THEN |
||
1805 | gen4(12, r3, r1) (* orr r1, r3 *) |
||
1806 | ELSE |
||
1807 | gen4(14, r3, r1) (* bic r1, r3 *) |
||
1808 | END; |
||
1809 | Str32(r1, r2); |
||
1810 | drop; |
||
1811 | drop; |
||
1812 | drop |
||
1813 | |||
1814 | |IL.opLENGTH: |
||
1815 | PushAll(2); |
||
1816 | CallRTL(IL._length, 2); |
||
1817 | GetRegA |
||
1818 | |||
1819 | |IL.opLENGTHW: |
||
1820 | PushAll(2); |
||
1821 | CallRTL(IL._lengthw, 2); |
||
1822 | GetRegA |
||
1823 | |||
1824 | |IL.opSAVES: |
||
1825 | UnOp(r2); |
||
1826 | REG.PushAll_1(R); |
||
1827 | r1 := GetAnyReg(); |
||
1828 | reloc(r1, BIN.RDATA + pic, stroffs + param2); |
||
1829 | push(r1); |
||
1830 | drop; |
||
1831 | push(r2); |
||
1832 | drop; |
||
1833 | PushConst(param1); |
||
1834 | CallRTL(IL._move, 3) |
||
1835 | |||
1836 | |IL.opEQS .. IL.opGES: |
||
1837 | PushAll(4); |
||
1838 | PushConst(opcode - IL.opEQS); |
||
1839 | CallRTL(IL._strcmp, 5); |
||
1840 | GetRegA |
||
1841 | |||
1842 | |IL.opEQSW .. IL.opGESW: |
||
1843 | PushAll(4); |
||
1844 | PushConst(opcode - IL.opEQSW); |
||
1845 | CallRTL(IL._strcmpw, 5); |
||
1846 | GetRegA |
||
1847 | |||
1848 | |IL.opCOPY: |
||
1849 | PushAll(2); |
||
1850 | PushConst(param2); |
||
1851 | CallRTL(IL._move, 3) |
||
1852 | |||
1853 | |IL.opMOVE: |
||
1854 | PushAll(3); |
||
1855 | CallRTL(IL._move, 3) |
||
1856 | |||
1857 | |IL.opCOPYA: |
||
1858 | PushAll(4); |
||
1859 | PushConst(param2); |
||
1860 | CallRTL(IL._arrcpy, 5); |
||
1861 | GetRegA |
||
1862 | |||
1863 | |IL.opCOPYS: |
||
1864 | PushAll(4); |
||
1865 | PushConst(param2); |
||
1866 | CallRTL(IL._strcpy, 5) |
||
1867 | |||
1868 | |IL.opDIV: |
||
1869 | PushAll(2); |
||
1870 | divmod; |
||
1871 | GetRegA |
||
1872 | |||
1873 | |IL.opDIVL: |
||
1874 | UnOp(r1); |
||
1875 | REG.PushAll_1(R); |
||
1876 | PushConst(param2); |
||
1877 | push(r1); |
||
1878 | drop; |
||
1879 | divmod; |
||
1880 | GetRegA |
||
1881 | |||
1882 | |IL.opDIVR: |
||
1883 | n := UTILS.Log2(param2); |
||
1884 | IF n > 0 THEN |
||
1885 | UnOp(r1); |
||
1886 | AsrImm(r1, n) |
||
1887 | ELSIF n < 0 THEN |
||
1888 | PushAll(1); |
||
1889 | PushConst(param2); |
||
1890 | divmod; |
||
1891 | GetRegA |
||
1892 | END |
||
1893 | |||
1894 | |IL.opMOD: |
||
1895 | PushAll(2); |
||
1896 | divmod; |
||
1897 | mov(R0, R1); |
||
1898 | GetRegA |
||
1899 | |||
1900 | |IL.opMODR: |
||
1901 | n := UTILS.Log2(param2); |
||
1902 | IF n > 0 THEN |
||
1903 | UnOp(r1); |
||
1904 | IF n = 8 THEN |
||
1905 | Code(0B2C0H + r1 * 9) (* uxtb r1 *) |
||
1906 | ELSIF n = 16 THEN |
||
1907 | Code(0B280H + r1 * 9) (* uxth r1 *) |
||
1908 | ELSE |
||
1909 | LslImm(r1, 32 - n); |
||
1910 | LsrImm(r1, 32 - n) |
||
1911 | END |
||
1912 | ELSIF n < 0 THEN |
||
1913 | PushAll(1); |
||
1914 | PushConst(param2); |
||
1915 | divmod; |
||
1916 | mov(R0, R1); |
||
1917 | GetRegA |
||
1918 | ELSE |
||
1919 | UnOp(r1); |
||
1920 | MovConst(r1, 0) |
||
1921 | END |
||
1922 | |||
1923 | |IL.opMODL: |
||
1924 | UnOp(r1); |
||
1925 | REG.PushAll_1(R); |
||
1926 | PushConst(param2); |
||
1927 | push(r1); |
||
1928 | drop; |
||
1929 | divmod; |
||
1930 | mov(R0, R1); |
||
1931 | GetRegA |
||
1932 | |||
1933 | |IL.opIN, IL.opINR: |
||
1934 | IF opcode = IL.opINR THEN |
||
1935 | r2 := GetAnyReg(); |
||
1936 | MovConst(r2, param2) |
||
1937 | END; |
||
1938 | L := NewLabel(); |
||
1939 | L2 := NewLabel(); |
||
1940 | BinOp(r1, r2); |
||
1941 | r3 := GetAnyReg(); |
||
1942 | CmpConst(r1, 32); |
||
1943 | jcc(jb, L); |
||
1944 | MovConst(r1, 0); |
||
1945 | jmp(L2); |
||
1946 | Label(L); |
||
1947 | MovConst(r3, 1); |
||
1948 | Shift(IL.opLSL, r3, r1); |
||
1949 | gen4(0, r3, r2); (* and r2, r3 *) |
||
1950 | SetCC(jne, r1); |
||
1951 | Label(L2); |
||
1952 | drop; |
||
1953 | drop |
||
1954 | |||
1955 | |IL.opINL: |
||
1956 | UnOp(r1); |
||
1957 | r2 := GetAnyReg(); |
||
1958 | MovConst(r2, LSL(1, param2)); |
||
1959 | gen4(0, r2, r1); (* and r1, r2 *) |
||
1960 | SetCC(jne, r1); |
||
1961 | drop |
||
1962 | |||
1963 | |IL.opRSET: |
||
1964 | PushAll(2); |
||
1965 | CallRTL(IL._set, 2); |
||
1966 | GetRegA |
||
1967 | |||
1968 | |IL.opRSETR: |
||
1969 | PushAll(1); |
||
1970 | PushConst(param2); |
||
1971 | CallRTL(IL._set, 2); |
||
1972 | GetRegA |
||
1973 | |||
1974 | |IL.opRSETL: |
||
1975 | UnOp(r1); |
||
1976 | REG.PushAll_1(R); |
||
1977 | PushConst(param2); |
||
1978 | push(r1); |
||
1979 | drop; |
||
1980 | CallRTL(IL._set, 2); |
||
1981 | GetRegA |
||
1982 | |||
1983 | |IL.opRSET1: |
||
1984 | PushAll(1); |
||
1985 | CallRTL(IL._set1, 1); |
||
1986 | GetRegA |
||
1987 | |||
1988 | |IL.opCONSTF: |
||
1989 | MovConst(GetAnyReg(), UTILS.d2s(cmd.float)) |
||
1990 | |||
1991 | |IL.opMULF: |
||
1992 | PushAll(2); |
||
1993 | CallRTL(IL._fmul, 2); |
||
1994 | GetRegA |
||
1995 | |||
1996 | |IL.opDIVF: |
||
1997 | PushAll(2); |
||
1998 | CallRTL(IL._fdiv, 2); |
||
1999 | GetRegA |
||
2000 | |||
2001 | |IL.opDIVFI: |
||
2002 | PushAll(2); |
||
2003 | CallRTL(IL._fdivi, 2); |
||
2004 | GetRegA |
||
2005 | |||
8097 | maxcodehac | 2006 | |IL.opADDF: |
7983 | leency | 2007 | PushAll(2); |
2008 | CallRTL(IL._fadd, 2); |
||
2009 | GetRegA |
||
2010 | |||
2011 | |IL.opSUBFI: |
||
2012 | PushAll(2); |
||
2013 | CallRTL(IL._fsubi, 2); |
||
2014 | GetRegA |
||
2015 | |||
2016 | |IL.opSUBF: |
||
2017 | PushAll(2); |
||
2018 | CallRTL(IL._fsub, 2); |
||
2019 | GetRegA |
||
2020 | |||
2021 | |IL.opEQF..IL.opGEF: |
||
2022 | PushAll(2); |
||
2023 | PushConst(opcode - IL.opEQF); |
||
2024 | CallRTL(IL._fcmp, 3); |
||
2025 | GetRegA |
||
2026 | |||
2027 | |IL.opFLOOR: |
||
2028 | PushAll(1); |
||
2029 | CallRTL(IL._floor, 1); |
||
2030 | GetRegA |
||
2031 | |||
2032 | |IL.opFLT: |
||
2033 | PushAll(1); |
||
2034 | CallRTL(IL._flt, 1); |
||
2035 | GetRegA |
||
2036 | |||
2037 | |IL.opUMINF: |
||
2038 | UnOp(r1); |
||
2039 | r2 := GetAnyReg(); |
||
2040 | MovConst(r2, 1); |
||
2041 | LslImm(r2, 31); |
||
2042 | gen4(1, r2, r1); (* eor r1, r2 *) |
||
2043 | drop |
||
2044 | |||
2045 | |IL.opFABS: |
||
2046 | UnOp(r1); |
||
2047 | r2 := GetAnyReg(); |
||
2048 | MovConst(r2, 1); |
||
2049 | LslImm(r2, 31); |
||
2050 | gen4(14, r2, r1); (* bic r1, r2 *) |
||
2051 | drop |
||
2052 | |||
2053 | |IL.opNEW: |
||
2054 | PushAll(1); |
||
2055 | n := param2 + 8; |
||
2056 | ASSERT(UTILS.Align(n, 32)); |
||
2057 | PushConst(n); |
||
2058 | PushConst(param1); |
||
2059 | CallRTL(IL._new, 3) |
||
2060 | |||
2061 | |IL.opTYPEGP: |
||
2062 | UnOp(r1); |
||
2063 | PushAll(0); |
||
2064 | push(r1); |
||
2065 | PushConst(param2); |
||
2066 | CallRTL(IL._guard, 2); |
||
2067 | GetRegA |
||
2068 | |||
2069 | |IL.opIS: |
||
2070 | PushAll(1); |
||
2071 | PushConst(param2); |
||
2072 | CallRTL(IL._is, 2); |
||
2073 | GetRegA |
||
2074 | |||
2075 | |IL.opISREC: |
||
2076 | PushAll(2); |
||
2077 | PushConst(param2); |
||
2078 | CallRTL(IL._guardrec, 3); |
||
2079 | GetRegA |
||
2080 | |||
2081 | |IL.opTYPEGR: |
||
2082 | PushAll(1); |
||
2083 | PushConst(param2); |
||
2084 | CallRTL(IL._guardrec, 2); |
||
2085 | GetRegA |
||
2086 | |||
2087 | |IL.opTYPEGD: |
||
2088 | UnOp(r1); |
||
2089 | PushAll(0); |
||
2090 | SubImm8(r1, 4); |
||
2091 | Ldr32(r1, r1); |
||
2092 | push(r1); |
||
2093 | PushConst(param2); |
||
2094 | CallRTL(IL._guardrec, 2); |
||
2095 | GetRegA |
||
2096 | |||
2097 | |IL.opCASET: |
||
2098 | push(R2); |
||
2099 | push(R2); |
||
2100 | PushConst(param2); |
||
2101 | CallRTL(IL._guardrec, 2); |
||
2102 | pop(R2); |
||
2103 | cbnz(ACC, param1) |
||
2104 | |||
2105 | |IL.opROT: |
||
2106 | PushAll(0); |
||
2107 | mov(R2, SP); |
||
2108 | push(R2); |
||
2109 | PushConst(param2); |
||
2110 | CallRTL(IL._rot, 2) |
||
2111 | |||
2112 | |IL.opPACK: |
||
2113 | PushAll(2); |
||
2114 | CallRTL(IL._pack, 2) |
||
2115 | |||
2116 | |IL.opPACKC: |
||
2117 | PushAll(1); |
||
2118 | PushConst(param2); |
||
2119 | CallRTL(IL._pack, 2) |
||
2120 | |||
2121 | |IL.opUNPK: |
||
2122 | PushAll(2); |
||
2123 | CallRTL(IL._unpk, 2) |
||
2124 | |||
2125 | END; |
||
2126 | |||
2127 | cmd := cmd.next(COMMAND) |
||
2128 | END; |
||
2129 | |||
2130 | ASSERT(R.pushed = 0); |
||
2131 | ASSERT(R.top = -1) |
||
2132 | END translate; |
||
2133 | |||
2134 | |||
2135 | PROCEDURE prolog (GlobSize, tcount, pic, FlashAdr, sp, ivt_len: INTEGER); |
||
2136 | VAR |
||
2137 | r1, r2, i, dcount: INTEGER; |
||
2138 | |||
2139 | BEGIN |
||
2140 | entry := NewLabel(); |
||
2141 | emptyProc := NewLabel(); |
||
2142 | genInt := NewLabel(); |
||
2143 | genTrap := NewLabel(); |
||
2144 | sdivProc := NewLabel(); |
||
2145 | |||
2146 | trap := emptyProc; |
||
2147 | int0 := emptyProc; |
||
2148 | |||
2149 | IVT[0] := sp; |
||
2150 | IVT[1] := entry; |
||
2151 | FOR i := 2 TO ivt_len - 1 DO |
||
2152 | IVT[i] := genInt |
||
2153 | END; |
||
2154 | |||
2155 | FOR i := 0 TO ivt_len - 1 DO |
||
2156 | Code(low(IVT[i])); |
||
2157 | Code(high(IVT[i])) |
||
2158 | END; |
||
2159 | |||
2160 | Label(entry); |
||
2161 | |||
2162 | r1 := GetAnyReg(); |
||
2163 | r2 := GetAnyReg(); |
||
2164 | reloc(r1, BIN.RDATA + pic, 0); |
||
2165 | |||
2166 | FOR i := 0 TO tcount - 1 DO |
||
2167 | MovConst(r2, CHL.GetInt(IL.codes.types, i)); |
||
2168 | Str32(r2, r1); |
||
2169 | AddImm8(r1, 4) |
||
2170 | END; |
||
2171 | |||
2172 | dcount := CHL.Length(IL.codes.data); |
||
2173 | FOR i := 0 TO dcount - 1 BY 4 DO |
||
2174 | MovConst(r2, BIN.get32le(IL.codes.data, i)); |
||
2175 | Str32(r2, r1); |
||
2176 | AddImm8(r1, 4) |
||
2177 | END; |
||
2178 | |||
2179 | drop; |
||
2180 | drop; |
||
2181 | |||
2182 | r1 := GetAnyReg(); |
||
2183 | MovConst(r1, sp); |
||
2184 | mov(SP, r1); |
||
2185 | reloc(r1, BIN.RDATA + pic, 0); |
||
2186 | push(r1); |
||
2187 | reloc(r1, BIN.RBSS + pic, 0); |
||
2188 | r2 := GetAnyReg(); |
||
2189 | MovConst(r2, GlobSize); |
||
2190 | AddReg(r1, r1, r2); |
||
2191 | drop; |
||
2192 | push(r1); |
||
2193 | drop; |
||
2194 | PushConst(tcount); |
||
2195 | CallRTL(IL._init, 3) |
||
2196 | END prolog; |
||
2197 | |||
2198 | |||
2199 | PROCEDURE epilog; |
||
2200 | VAR |
||
2201 | L1, L2, L3, L4: INTEGER; |
||
2202 | |||
2203 | BEGIN |
||
2204 | Code(0BF30H); (* L2: wfi *) |
||
2205 | Code(0E7FDH); (* b L2 *) |
||
2206 | |||
2207 | Label(genInt); |
||
2208 | Code(0F3EFH); Code(08105H); (* mrs r1, ipsr *) |
||
2209 | gen14(FALSE, TRUE, {R1}); (* push {LR, R1} *) |
||
2210 | call(int0); |
||
2211 | gen14(TRUE, TRUE, {R1}); (* pop {PC, R1} *) |
||
2212 | |||
2213 | Label(emptyProc); |
||
2214 | Code(04770H); (* bx lr *) |
||
2215 | |||
2216 | Label(genTrap); |
||
2217 | call(trap); |
||
2218 | call(entry); |
||
2219 | |||
2220 | Label(sdivProc); |
||
2221 | IF Target.InstrSet.sdiv THEN |
||
2222 | Code(09800H); (* ldr r0, [sp + #0] *) |
||
2223 | Code(09901H); (* ldr r1, [sp + #4] *) |
||
2224 | Code(0FB91H); (* sdiv r2, r1, r0 *) |
||
2225 | Code(0F2F0H); |
||
2226 | Code(00013H); (* mov r3, r2 *) |
||
2227 | Code(04343H); (* mul r3, r0 *) |
||
2228 | Code(01AC9H); (* sub r1, r3 *) |
||
2229 | Code(0DA01H); (* bge L *) |
||
2230 | Code(04401H); (* add r1, r0 *) |
||
2231 | Code(03A01H); (* sub r2, #1 *) |
||
2232 | (* L: *) |
||
2233 | Code(00010H); (* mov r0, r2 *) |
||
2234 | Code(04770H); (* bx lr *) |
||
2235 | ELSE |
||
2236 | (* a / b; a >= 0 *) |
||
2237 | L1 := NewLabel(); |
||
2238 | L2 := NewLabel(); |
||
2239 | L3 := NewLabel(); |
||
2240 | L4 := NewLabel(); |
||
2241 | |||
2242 | LdrSp(R1, 1); |
||
2243 | LdrSp(R2, 0); |
||
2244 | MovConst(R0, 0); |
||
2245 | push(R4); |
||
2246 | |||
2247 | Label(L4); |
||
2248 | Cmp(R1, R2); |
||
2249 | jcc(jl, L1); |
||
2250 | MovConst(R3, 2); |
||
2251 | mov(R4, R2); |
||
2252 | LslImm(R4, 1); |
||
2253 | Label(L3); |
||
2254 | Cmp(R1, R4); |
||
2255 | jcc(jl, L2); |
||
2256 | CmpConst(R4, 0); |
||
2257 | jcc(jle, L2); |
||
2258 | LslImm(R4, 1); |
||
2259 | LslImm(R3, 1); |
||
2260 | jmp(L3); |
||
2261 | Label(L2); |
||
2262 | LsrImm(R4, 1); |
||
2263 | LsrImm(R3, 1); |
||
2264 | SubReg(R1, R1, R4); |
||
2265 | AddReg(R0, R0, R3); |
||
2266 | jmp(L4); |
||
2267 | Label(L1); |
||
2268 | |||
2269 | (* a / b; a < 0 *) |
||
2270 | L1 := NewLabel(); |
||
2271 | L2 := NewLabel(); |
||
2272 | L3 := NewLabel(); |
||
2273 | L4 := NewLabel(); |
||
2274 | |||
2275 | Label(L4); |
||
2276 | CmpConst(R1, 0); |
||
2277 | jcc(jge, L1); |
||
2278 | MovConst(R3, 2); |
||
2279 | mov(R4, R2); |
||
2280 | LslImm(R4, 1); |
||
2281 | Neg(R1); |
||
2282 | Label(L3); |
||
2283 | Cmp(R1, R4); |
||
2284 | jcc(jl, L2); |
||
2285 | CmpConst(R4, 0); |
||
2286 | jcc(jle, L2); |
||
2287 | LslImm(R4, 1); |
||
2288 | LslImm(R3, 1); |
||
2289 | jmp(L3); |
||
2290 | Label(L2); |
||
2291 | Neg(R1); |
||
2292 | LsrImm(R4, 1); |
||
2293 | LsrImm(R3, 1); |
||
2294 | AddReg(R1, R1, R4); |
||
2295 | SubReg(R0, R0, R3); |
||
2296 | jmp(L4); |
||
2297 | Label(L1); |
||
2298 | |||
2299 | pop(R4); |
||
2300 | Code(04770H); (* bx lr *) |
||
2301 | END |
||
2302 | |||
2303 | END epilog; |
||
2304 | |||
2305 | |||
2306 | PROCEDURE CortexM3; |
||
2307 | BEGIN |
||
2308 | Target.FlashAdr := 08000000H; |
||
2309 | Target.SRAMAdr := 20000000H; |
||
2310 | Target.IVTLen := 256; |
||
2311 | Target.Reserved := 0; |
||
2312 | Target.MinStack := 512; |
||
2313 | Target.InstrSet.thumb2 := TRUE; |
||
2314 | Target.InstrSet.it := TRUE; |
||
2315 | Target.InstrSet.sdiv := TRUE; |
||
2316 | Target.InstrSet.cbxz := TRUE |
||
2317 | END CortexM3; |
||
2318 | |||
2319 | |||
2320 | PROCEDURE CodeGen* (outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS); |
||
2321 | VAR |
||
2322 | opt: PROG.OPTIONS; |
||
2323 | |||
2324 | ram, rom: INTEGER; |
||
2325 | |||
2326 | DataAdr, BssAdr, DataSize, BssSize, CodeSize: INTEGER; |
||
2327 | |||
2328 | BEGIN |
||
2329 | IF target = TARGETS.STM32CM3 THEN |
||
2330 | CortexM3 |
||
2331 | END; |
||
2332 | |||
2333 | ram := MIN(MAX(options.ram, STM32_minRAM), STM32_maxRAM) * 1024; |
||
2334 | rom := MIN(MAX(options.rom, STM32_minROM), STM32_maxROM) * 1024; |
||
2335 | |||
2336 | tcount := CHL.Length(IL.codes.types); |
||
2337 | |||
2338 | opt := options; |
||
2339 | CodeList := LISTS.create(NIL); |
||
2340 | |||
2341 | program := BIN.create(IL.codes.lcount); |
||
2342 | |||
2343 | REG.Init(R, push, pop, mov, xchg, NIL, NIL, {R0, R1, R2, R3}, {}); |
||
2344 | |||
2345 | StkCount := 0; |
||
2346 | |||
2347 | DataAdr := Target.SRAMAdr + Target.Reserved; |
||
2348 | DataSize := CHL.Length(IL.codes.data) + tcount * 4 + Target.Reserved; |
||
2349 | WHILE DataSize MOD 4 # 0 DO |
||
2350 | CHL.PushByte(IL.codes.data, 0); |
||
2351 | INC(DataSize) |
||
2352 | END; |
||
2353 | BssAdr := DataAdr + DataSize - Target.Reserved; |
||
2354 | |||
2355 | IL.set_bss(MAX(IL.codes.bss, MAX(IL.codes.dmin - CHL.Length(IL.codes.data), 4))); |
||
2356 | |||
2357 | BssSize := IL.codes.bss; |
||
2358 | ASSERT(UTILS.Align(BssSize, 4)); |
||
2359 | |||
2360 | prolog(BssSize, tcount, ORD(opt.pic), Target.FlashAdr, Target.SRAMAdr + ram, Target.IVTLen); |
||
2361 | translate(ORD(opt.pic), tcount * 4); |
||
2362 | epilog; |
||
2363 | |||
2364 | fixup(Target.FlashAdr, DataAdr, BssAdr); |
||
2365 | |||
2366 | INC(DataSize, BssSize); |
||
2367 | CodeSize := CHL.Length(program.code); |
||
2368 | |||
2369 | IF CodeSize > rom THEN |
||
2370 | ERRORS.Error(203) |
||
2371 | END; |
||
2372 | |||
2373 | IF DataSize > ram - Target.MinStack THEN |
||
2374 | ERRORS.Error(204) |
||
2375 | END; |
||
2376 | |||
8097 | maxcodehac | 2377 | WR.Create(outname); |
7983 | leency | 2378 | |
8097 | maxcodehac | 2379 | HEX.Data2(program.code, 0, CodeSize, high(Target.FlashAdr)); |
2380 | HEX.End; |
||
7983 | leency | 2381 | |
8097 | maxcodehac | 2382 | WR.Close; |
7983 | leency | 2383 | |
2384 | C.StringLn("--------------------------------------------"); |
||
2385 | C.String( " rom: "); C.Int(CodeSize); C.String(" of "); C.Int(rom); C.String(" ("); C.Int(CodeSize * 100 DIV rom); C.StringLn("%)"); |
||
2386 | C.Ln; |
||
2387 | C.String( " ram: "); C.Int(DataSize); C.String(" of "); C.Int(ram); C.String(" ("); C.Int(DataSize * 100 DIV ram); C.StringLn("%)") |
||
2388 | |||
2389 | END CodeGen; |
||
2390 | |||
2391 | |||
2392 | PROCEDURE SetIV* (idx: INTEGER): BOOLEAN; |
||
2393 | VAR |
||
2394 | res: BOOLEAN; |
||
2395 | |||
2396 | BEGIN |
||
2397 | res := IVT[idx] = 0; |
||
2398 | IVT[idx] := 1 |
||
2399 | |||
2400 | RETURN res |
||
2401 | END SetIV; |
||
2402 | |||
2403 | |||
2404 | PROCEDURE init; |
||
2405 | VAR |
||
2406 | i: INTEGER; |
||
2407 | |||
2408 | BEGIN |
||
2409 | FOR i := 0 TO LEN(IVT) - 1 DO |
||
2410 | IVT[i] := 0 |
||
2411 | END |
||
2412 | END init; |
||
2413 | |||
2414 | |||
2415 | BEGIN |
||
2416 | init |
||
2417 | END THUMB.>>>>>=>=>=>=>=>>=>=>=>=>=>=>>>=>=>=>>>>=>>=> |