2 * TMS320C67xx code generator for TCC
4 * Copyright (c) 2001, 2002 Fabrice Bellard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #ifdef TARGET_DEFS_ONLY
23 /* #define ASSEMBLY_LISTING_C67 */
25 /* number of available registers */
30 /* a register can belong to several classes. The classes must be
31 sorted from more general to more precise (see gv2() code which does
32 assumptions on it). */
33 #define RC_INT 0x0001 /* generic integer register */
34 #define RC_FLOAT 0x0002 /* generic float register */
39 #define RC_INT_BSIDE 0x00000040 /* generic integer register on b side */
40 #define RC_C67_A4 0x00000100
41 #define RC_C67_A5 0x00000200
42 #define RC_C67_B4 0x00000400
43 #define RC_C67_B5 0x00000800
44 #define RC_C67_A6 0x00001000
45 #define RC_C67_A7 0x00002000
46 #define RC_C67_B6 0x00004000
47 #define RC_C67_B7 0x00008000
48 #define RC_C67_A8 0x00010000
49 #define RC_C67_A9 0x00020000
50 #define RC_C67_B8 0x00040000
51 #define RC_C67_B9 0x00080000
52 #define RC_C67_A10 0x00100000
53 #define RC_C67_A11 0x00200000
54 #define RC_C67_B10 0x00400000
55 #define RC_C67_B11 0x00800000
56 #define RC_C67_A12 0x01000000
57 #define RC_C67_A13 0x02000000
58 #define RC_C67_B12 0x04000000
59 #define RC_C67_B13 0x08000000
60 #define RC_IRET RC_C67_A4 /* function return: integer register */
61 #define RC_LRET RC_C67_A5 /* function return: second integer register */
62 #define RC_FRET RC_C67_A4 /* function return: float register */
64 /* pretty names for the registers */
66 TREG_EAX
= 0, // really A2
67 TREG_ECX
, // really A3
68 TREG_EDX
, // really B0
69 TREG_ST0
, // really B1
92 /* return registers for function */
93 #define REG_IRET TREG_C67_A4 /* single word int return register */
94 #define REG_LRET TREG_C67_A5 /* second word return register (for long long) */
95 #define REG_FRET TREG_C67_A4 /* float return register */
97 /* defined if function parameters must be evaluated in reverse order */
98 /* #define INVERT_FUNC_PARAMS */
100 /* defined if structures are passed as pointers. Otherwise structures
101 are directly pushed on stack. */
102 /* #define FUNC_STRUCT_PARAM_AS_PTR */
104 /* pointer size, in bytes */
107 /* long double size and alignment, in bytes */
108 #define LDOUBLE_SIZE 12
109 #define LDOUBLE_ALIGN 4
110 /* maximum alignment (for aligned attribute support) */
113 /******************************************************/
116 #define EM_TCC_TARGET EM_C60
118 /* relocation type for 32 bit data relocation */
119 #define R_DATA_32 R_C60_32
120 #define R_DATA_PTR R_C60_32
121 #define R_JMP_SLOT R_C60_JMP_SLOT
122 #define R_COPY R_C60_COPY
124 #define ELF_START_ADDR 0x00000400
125 #define ELF_PAGE_SIZE 0x1000
127 /******************************************************/
128 #else /* ! TARGET_DEFS_ONLY */
129 /******************************************************/
132 ST_DATA
const int reg_classes
[NB_REGS
] = {
133 /* eax */ RC_INT
| RC_FLOAT
| RC_EAX
,
134 // only allow even regs for floats (allow for doubles)
135 /* ecx */ RC_INT
| RC_ECX
,
136 /* edx */ RC_INT
| RC_INT_BSIDE
| RC_FLOAT
| RC_EDX
,
137 // only allow even regs for floats (allow for doubles)
138 /* st0 */ RC_INT
| RC_INT_BSIDE
| RC_ST0
,
151 /* A10 */ RC_C67_A10
,
152 /* A11 */ RC_C67_A11
,
153 /* B10 */ RC_C67_B10
,
154 /* B11 */ RC_C67_B11
,
155 /* A12 */ RC_C67_A10
,
156 /* A13 */ RC_C67_A11
,
157 /* B12 */ RC_C67_B10
,
161 // although tcc thinks it is passing parameters on the stack,
162 // the C67 really passes up to the first 10 params in special
163 // regs or regs pairs (for 64 bit params). So keep track of
164 // the stack offsets so we can translate to the appropriate
167 #define NoCallArgsPassedOnStack 10
169 int TranslateStackToReg
[NoCallArgsPassedOnStack
];
170 int ParamLocOnStack
[NoCallArgsPassedOnStack
];
171 int TotalBytesPushedOnStack
;
181 #define ALWAYS_ASSERT(x) \
184 tcc_error("internal compiler error file at %s:%d", __FILE__, __LINE__);\
187 /******************************************************/
188 static unsigned long func_sub_sp_offset
;
189 static int func_ret_sub
;
191 static BOOL C67_invert_test
;
192 static int C67_compare_reg
;
194 #ifdef ASSEMBLY_LISTING_C67
202 #ifdef ASSEMBLY_LISTING_C67
203 fprintf(f
, " %08X", c
);
206 if (ind1
> (int) cur_text_section
->data_allocated
)
207 section_realloc(cur_text_section
, ind1
);
208 cur_text_section
->data
[ind
] = c
& 0xff;
209 cur_text_section
->data
[ind
+ 1] = (c
>> 8) & 0xff;
210 cur_text_section
->data
[ind
+ 2] = (c
>> 16) & 0xff;
211 cur_text_section
->data
[ind
+ 3] = (c
>> 24) & 0xff;
216 /* output a symbol and patch all calls to it */
217 void gsym_addr(int t
, int a
)
221 ptr
= (int *) (cur_text_section
->data
+ t
);
225 // extract 32 bit address from MVKH/MVKL
226 n
= ((*ptr
>> 7) & 0xffff);
227 n
|= ((*(ptr
+ 1) >> 7) & 0xffff) << 16;
229 // define a label that will be relocated
231 sym
= get_sym_ref(&char_pointer_type
, cur_text_section
, a
, 0);
232 greloc(cur_text_section
, sym
, t
, R_C60LO16
);
233 greloc(cur_text_section
, sym
, t
+ 4, R_C60HI16
);
235 // clear out where the pointer was
237 *ptr
&= ~(0xffff << 7);
238 *(ptr
+ 1) &= ~(0xffff << 7);
249 // these are regs that tcc doesn't really know about,
250 // but assign them unique values so the mapping routines
251 // can distinguish them
258 #define C67_CREG_ZERO -1 /* Special code for no condition reg test */
261 int ConvertRegToRegClass(int r
)
263 // only works for A4-B13
265 return RC_C67_A4
<< (r
- TREG_C67_A4
);
269 // map TCC reg to C67 reg number
271 int C67_map_regn(int r
)
273 if (r
== 0) // normal tcc regs
275 else if (r
== 1) // normal tcc regs
277 else if (r
== 2) // normal tcc regs
279 else if (r
== 3) // normal tcc regs
281 else if (r
>= TREG_C67_A4
&& r
<= TREG_C67_B13
) // these form a pattern of alt pairs
282 return (((r
& 0xfffffffc) >> 1) | (r
& 1)) + 2;
283 else if (r
== C67_A0
)
284 return 0; // set to A0 (offset reg)
285 else if (r
== C67_B2
)
286 return 2; // set to B2 (offset reg)
287 else if (r
== C67_B3
)
288 return 3; // set to B3 (return address reg)
289 else if (r
== C67_SP
)
290 return 15; // set to SP (B15) (offset reg)
291 else if (r
== C67_FP
)
292 return 15; // set to FP (A15) (offset reg)
293 else if (r
== C67_CREG_ZERO
)
294 return 0; // Special code for no condition reg test
296 ALWAYS_ASSERT(FALSE
);
301 // mapping from tcc reg number to
302 // C67 register to condition code field
304 // valid condition code regs are:
306 // tcc reg 2 ->B0 -> 1
307 // tcc reg 3 ->B1 -> 2
308 // tcc reg 0 -> A2 -> 5
309 // tcc reg 1 -> A3 -> X
312 int C67_map_regc(int r
)
314 if (r
== 0) // normal tcc regs
316 else if (r
== 2) // normal tcc regs
318 else if (r
== 3) // normal tcc regs
320 else if (r
== C67_B2
) // normal tcc regs
322 else if (r
== C67_CREG_ZERO
)
323 return 0; // Special code for no condition reg test
325 ALWAYS_ASSERT(FALSE
);
331 // map TCC reg to C67 reg side A or B
333 int C67_map_regs(int r
)
335 if (r
== 0) // normal tcc regs
337 else if (r
== 1) // normal tcc regs
339 else if (r
== 2) // normal tcc regs
341 else if (r
== 3) // normal tcc regs
343 else if (r
>= TREG_C67_A4
&& r
<= TREG_C67_B13
) // these form a pattern of alt pairs
345 else if (r
== C67_A0
)
346 return 0; // set to A side
347 else if (r
== C67_B2
)
348 return 1; // set to B side
349 else if (r
== C67_B3
)
350 return 1; // set to B side
351 else if (r
== C67_SP
)
352 return 0x1; // set to SP (B15) B side
353 else if (r
== C67_FP
)
354 return 0x0; // set to FP (A15) A side
356 ALWAYS_ASSERT(FALSE
);
361 int C67_map_S12(char *s
)
363 if (strstr(s
, ".S1") != NULL
)
365 else if (strcmp(s
, ".S2"))
368 ALWAYS_ASSERT(FALSE
);
373 int C67_map_D12(char *s
)
375 if (strstr(s
, ".D1") != NULL
)
377 else if (strcmp(s
, ".D2"))
380 ALWAYS_ASSERT(FALSE
);
387 void C67_asm(char *s
, int a
, int b
, int c
)
391 #ifdef ASSEMBLY_LISTING_C67
393 f
= fopen("TCC67_out.txt", "wt");
395 fprintf(f
, "%04X ", ind
);
398 if (strstr(s
, "MVKL") == s
) {
399 C67_g((C67_map_regn(b
) << 23) |
400 ((a
& 0xffff) << 7) | (0x0a << 2) | (C67_map_regs(b
) << 1));
401 } else if (strstr(s
, "MVKH") == s
) {
402 C67_g((C67_map_regn(b
) << 23) |
403 (((a
>> 16) & 0xffff) << 7) |
404 (0x1a << 2) | (C67_map_regs(b
) << 1));
405 } else if (strstr(s
, "STW.D SP POST DEC") == s
) {
406 C67_g((C67_map_regn(a
) << 23) | //src
407 (15 << 18) | //SP B15
408 (2 << 13) | //ucst5 (must keep 8 byte boundary !!)
409 (0xa << 9) | //mode a = post dec ucst
410 (0 << 8) | //r (LDDW bit 0)
411 (1 << 7) | //y D1/D2 use B side
412 (7 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
414 (C67_map_regs(a
) << 1) | //side of src
415 (0 << 0)); //parallel
416 } else if (strstr(s
, "STB.D *+SP[A0]") == s
) {
417 C67_g((C67_map_regn(a
) << 23) | //src
418 (15 << 18) | //base reg A15
419 (0 << 13) | //offset reg A0
420 (5 << 9) | //mode 5 = pos offset, base reg + off reg
421 (0 << 8) | //r (LDDW bit 0)
422 (0 << 7) | //y D1/D2 A side
423 (3 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
425 (C67_map_regs(a
) << 1) | //side of src
426 (0 << 0)); //parallel
427 } else if (strstr(s
, "STH.D *+SP[A0]") == s
) {
428 C67_g((C67_map_regn(a
) << 23) | //src
429 (15 << 18) | //base reg A15
430 (0 << 13) | //offset reg A0
431 (5 << 9) | //mode 5 = pos offset, base reg + off reg
432 (0 << 8) | //r (LDDW bit 0)
433 (0 << 7) | //y D1/D2 A side
434 (5 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
436 (C67_map_regs(a
) << 1) | //side of src
437 (0 << 0)); //parallel
438 } else if (strstr(s
, "STB.D *+SP[A0]") == s
) {
439 C67_g((C67_map_regn(a
) << 23) | //src
440 (15 << 18) | //base reg A15
441 (0 << 13) | //offset reg A0
442 (5 << 9) | //mode 5 = pos offset, base reg + off reg
443 (0 << 8) | //r (LDDW bit 0)
444 (0 << 7) | //y D1/D2 A side
445 (3 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
447 (C67_map_regs(a
) << 1) | //side of src
448 (0 << 0)); //parallel
449 } else if (strstr(s
, "STH.D *+SP[A0]") == s
) {
450 C67_g((C67_map_regn(a
) << 23) | //src
451 (15 << 18) | //base reg A15
452 (0 << 13) | //offset reg A0
453 (5 << 9) | //mode 5 = pos offset, base reg + off reg
454 (0 << 8) | //r (LDDW bit 0)
455 (0 << 7) | //y D1/D2 A side
456 (5 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
458 (C67_map_regs(a
) << 1) | //side of src
459 (0 << 0)); //parallel
460 } else if (strstr(s
, "STW.D *+SP[A0]") == s
) {
461 C67_g((C67_map_regn(a
) << 23) | //src
462 (15 << 18) | //base reg A15
463 (0 << 13) | //offset reg A0
464 (5 << 9) | //mode 5 = pos offset, base reg + off reg
465 (0 << 8) | //r (LDDW bit 0)
466 (0 << 7) | //y D1/D2 A side
467 (7 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
469 (C67_map_regs(a
) << 1) | //side of src
470 (0 << 0)); //parallel
471 } else if (strstr(s
, "STW.D *") == s
) {
472 C67_g((C67_map_regn(a
) << 23) | //src
473 (C67_map_regn(b
) << 18) | //base reg A0
475 (1 << 9) | //mode 1 = pos cst offset
476 (0 << 8) | //r (LDDW bit 0)
477 (C67_map_regs(b
) << 7) | //y D1/D2 base reg side
478 (7 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
480 (C67_map_regs(a
) << 1) | //side of src
481 (0 << 0)); //parallel
482 } else if (strstr(s
, "STH.D *") == s
) {
483 C67_g((C67_map_regn(a
) << 23) | //src
484 (C67_map_regn(b
) << 18) | //base reg A0
486 (1 << 9) | //mode 1 = pos cst offset
487 (0 << 8) | //r (LDDW bit 0)
488 (C67_map_regs(b
) << 7) | //y D1/D2 base reg side
489 (5 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
491 (C67_map_regs(a
) << 1) | //side of src
492 (0 << 0)); //parallel
493 } else if (strstr(s
, "STB.D *") == s
) {
494 C67_g((C67_map_regn(a
) << 23) | //src
495 (C67_map_regn(b
) << 18) | //base reg A0
497 (1 << 9) | //mode 1 = pos cst offset
498 (0 << 8) | //r (LDDW bit 0)
499 (C67_map_regs(b
) << 7) | //y D1/D2 base reg side
500 (3 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
502 (C67_map_regs(a
) << 1) | //side of src
503 (0 << 0)); //parallel
504 } else if (strstr(s
, "STW.D +*") == s
) {
505 ALWAYS_ASSERT(c
< 32);
506 C67_g((C67_map_regn(a
) << 23) | //src
507 (C67_map_regn(b
) << 18) | //base reg A0
509 (1 << 9) | //mode 1 = pos cst offset
510 (0 << 8) | //r (LDDW bit 0)
511 (C67_map_regs(b
) << 7) | //y D1/D2 base reg side
512 (7 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
514 (C67_map_regs(a
) << 1) | //side of src
515 (0 << 0)); //parallel
516 } else if (strstr(s
, "LDW.D SP PRE INC") == s
) {
517 C67_g((C67_map_regn(a
) << 23) | //dst
518 (15 << 18) | //base reg B15
519 (2 << 13) | //ucst5 (must keep 8 byte boundary)
520 (9 << 9) | //mode 9 = pre inc ucst5
521 (0 << 8) | //r (LDDW bit 0)
522 (1 << 7) | //y D1/D2 B side
523 (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
525 (C67_map_regs(a
) << 1) | //side of dst
526 (0 << 0)); //parallel
527 } else if (strstr(s
, "LDDW.D SP PRE INC") == s
) {
528 C67_g((C67_map_regn(a
) << 23) | //dst
529 (15 << 18) | //base reg B15
530 (1 << 13) | //ucst5 (must keep 8 byte boundary)
531 (9 << 9) | //mode 9 = pre inc ucst5
532 (1 << 8) | //r (LDDW bit 1)
533 (1 << 7) | //y D1/D2 B side
534 (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
536 (C67_map_regs(a
) << 1) | //side of dst
537 (0 << 0)); //parallel
538 } else if (strstr(s
, "LDW.D *+SP[A0]") == s
) {
539 C67_g((C67_map_regn(a
) << 23) | //dst
540 (15 << 18) | //base reg A15
541 (0 << 13) | //offset reg A0
542 (5 << 9) | //mode 5 = pos offset, base reg + off reg
543 (0 << 8) | //r (LDDW bit 0)
544 (0 << 7) | //y D1/D2 A side
545 (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
547 (C67_map_regs(a
) << 1) | //side of dst
548 (0 << 0)); //parallel
549 } else if (strstr(s
, "LDDW.D *+SP[A0]") == s
) {
550 C67_g((C67_map_regn(a
) << 23) | //dst
551 (15 << 18) | //base reg A15
552 (0 << 13) | //offset reg A0
553 (5 << 9) | //mode 5 = pos offset, base reg + off reg
554 (1 << 8) | //r (LDDW bit 1)
555 (0 << 7) | //y D1/D2 A side
556 (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
558 (C67_map_regs(a
) << 1) | //side of dst
559 (0 << 0)); //parallel
560 } else if (strstr(s
, "LDH.D *+SP[A0]") == s
) {
561 C67_g((C67_map_regn(a
) << 23) | //dst
562 (15 << 18) | //base reg A15
563 (0 << 13) | //offset reg A0
564 (5 << 9) | //mode 5 = pos offset, base reg + off reg
565 (0 << 8) | //r (LDDW bit 0)
566 (0 << 7) | //y D1/D2 A side
567 (4 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
569 (C67_map_regs(a
) << 1) | //side of dst
570 (0 << 0)); //parallel
571 } else if (strstr(s
, "LDB.D *+SP[A0]") == s
) {
572 C67_g((C67_map_regn(a
) << 23) | //dst
573 (15 << 18) | //base reg A15
574 (0 << 13) | //offset reg A0
575 (5 << 9) | //mode 5 = pos offset, base reg + off reg
576 (0 << 8) | //r (LDDW bit 0)
577 (0 << 7) | //y D1/D2 A side
578 (2 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
580 (C67_map_regs(a
) << 1) | //side of dst
581 (0 << 0)); //parallel
582 } else if (strstr(s
, "LDHU.D *+SP[A0]") == s
) {
583 C67_g((C67_map_regn(a
) << 23) | //dst
584 (15 << 18) | //base reg A15
585 (0 << 13) | //offset reg A0
586 (5 << 9) | //mode 5 = pos offset, base reg + off reg
587 (0 << 8) | //r (LDDW bit 0)
588 (0 << 7) | //y D1/D2 A side
589 (0 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
591 (C67_map_regs(a
) << 1) | //side of dst
592 (0 << 0)); //parallel
593 } else if (strstr(s
, "LDBU.D *+SP[A0]") == s
) {
594 C67_g((C67_map_regn(a
) << 23) | //dst
595 (15 << 18) | //base reg A15
596 (0 << 13) | //offset reg A0
597 (5 << 9) | //mode 5 = pos offset, base reg + off reg
598 (0 << 8) | //r (LDDW bit 0)
599 (0 << 7) | //y D1/D2 A side
600 (1 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
602 (C67_map_regs(a
) << 1) | //side of dst
603 (0 << 0)); //parallel
604 } else if (strstr(s
, "LDW.D *") == s
) {
605 C67_g((C67_map_regn(b
) << 23) | //dst
606 (C67_map_regn(a
) << 18) | //base reg A15
608 (1 << 9) | //mode 1 = pos cst offset
609 (0 << 8) | //r (LDDW bit 0)
610 (C67_map_regs(a
) << 7) | //y D1/D2 src side
611 (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
613 (C67_map_regs(b
) << 1) | //side of dst
614 (0 << 0)); //parallel
615 } else if (strstr(s
, "LDDW.D *") == s
) {
616 C67_g((C67_map_regn(b
) << 23) | //dst
617 (C67_map_regn(a
) << 18) | //base reg A15
619 (1 << 9) | //mode 1 = pos cst offset
620 (1 << 8) | //r (LDDW bit 1)
621 (C67_map_regs(a
) << 7) | //y D1/D2 src side
622 (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
624 (C67_map_regs(b
) << 1) | //side of dst
625 (0 << 0)); //parallel
626 } else if (strstr(s
, "LDH.D *") == s
) {
627 C67_g((C67_map_regn(b
) << 23) | //dst
628 (C67_map_regn(a
) << 18) | //base reg A15
630 (1 << 9) | //mode 1 = pos cst offset
631 (0 << 8) | //r (LDDW bit 0)
632 (C67_map_regs(a
) << 7) | //y D1/D2 src side
633 (4 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
635 (C67_map_regs(b
) << 1) | //side of dst
636 (0 << 0)); //parallel
637 } else if (strstr(s
, "LDB.D *") == s
) {
638 C67_g((C67_map_regn(b
) << 23) | //dst
639 (C67_map_regn(a
) << 18) | //base reg A15
641 (1 << 9) | //mode 1 = pos cst offset
642 (0 << 8) | //r (LDDW bit 0)
643 (C67_map_regs(a
) << 7) | //y D1/D2 src side
644 (2 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
646 (C67_map_regs(b
) << 1) | //side of dst
647 (0 << 0)); //parallel
648 } else if (strstr(s
, "LDHU.D *") == s
) {
649 C67_g((C67_map_regn(b
) << 23) | //dst
650 (C67_map_regn(a
) << 18) | //base reg A15
652 (1 << 9) | //mode 1 = pos cst offset
653 (0 << 8) | //r (LDDW bit 0)
654 (C67_map_regs(a
) << 7) | //y D1/D2 src side
655 (0 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
657 (C67_map_regs(b
) << 1) | //side of dst
658 (0 << 0)); //parallel
659 } else if (strstr(s
, "LDBU.D *") == s
) {
660 C67_g((C67_map_regn(b
) << 23) | //dst
661 (C67_map_regn(a
) << 18) | //base reg A15
663 (1 << 9) | //mode 1 = pos cst offset
664 (0 << 8) | //r (LDDW bit 0)
665 (C67_map_regs(a
) << 7) | //y D1/D2 src side
666 (1 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
668 (C67_map_regs(b
) << 1) | //side of dst
669 (0 << 0)); //parallel
670 } else if (strstr(s
, "LDW.D +*") == s
) {
671 C67_g((C67_map_regn(b
) << 23) | //dst
672 (C67_map_regn(a
) << 18) | //base reg A15
674 (1 << 9) | //mode 1 = pos cst offset
675 (0 << 8) | //r (LDDW bit 0)
676 (C67_map_regs(a
) << 7) | //y D1/D2 src side
677 (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
679 (C67_map_regs(b
) << 1) | //side of dst
680 (0 << 0)); //parallel
681 } else if (strstr(s
, "CMPLTSP") == s
) {
682 xpath
= C67_map_regs(a
) ^ C67_map_regs(b
);
683 ALWAYS_ASSERT(C67_map_regs(c
) == C67_map_regs(a
));
685 C67_g((C67_map_regn(c
) << 23) | //dst
686 (C67_map_regn(b
) << 18) | //src2
687 (C67_map_regn(a
) << 13) | //src1
688 (xpath
<< 12) | //x use cross path for src2
689 (0x3a << 6) | //opcode
690 (0x8 << 2) | //opcode fixed
691 (C67_map_regs(c
) << 1) | //side for reg c
692 (0 << 0)); //parallel
693 } else if (strstr(s
, "CMPGTSP") == s
) {
694 xpath
= C67_map_regs(a
) ^ C67_map_regs(b
);
695 ALWAYS_ASSERT(C67_map_regs(c
) == C67_map_regs(a
));
697 C67_g((C67_map_regn(c
) << 23) | //dst
698 (C67_map_regn(b
) << 18) | //src2
699 (C67_map_regn(a
) << 13) | //src1
700 (xpath
<< 12) | //x use cross path for src2
701 (0x39 << 6) | //opcode
702 (0x8 << 2) | //opcode fixed
703 (C67_map_regs(c
) << 1) | //side for reg c
704 (0 << 0)); //parallel
705 } else if (strstr(s
, "CMPEQSP") == s
) {
706 xpath
= C67_map_regs(a
) ^ C67_map_regs(b
);
707 ALWAYS_ASSERT(C67_map_regs(c
) == C67_map_regs(a
));
709 C67_g((C67_map_regn(c
) << 23) | //dst
710 (C67_map_regn(b
) << 18) | //src2
711 (C67_map_regn(a
) << 13) | //src1
712 (xpath
<< 12) | //x use cross path for src2
713 (0x38 << 6) | //opcode
714 (0x8 << 2) | //opcode fixed
715 (C67_map_regs(c
) << 1) | //side for reg c
716 (0 << 0)); //parallel
719 else if (strstr(s
, "CMPLTDP") == s
) {
720 xpath
= C67_map_regs(a
) ^ C67_map_regs(b
);
721 ALWAYS_ASSERT(C67_map_regs(c
) == C67_map_regs(a
));
723 C67_g((C67_map_regn(c
) << 23) | //dst
724 (C67_map_regn(b
) << 18) | //src2
725 (C67_map_regn(a
) << 13) | //src1
726 (xpath
<< 12) | //x use cross path for src2
727 (0x2a << 6) | //opcode
728 (0x8 << 2) | //opcode fixed
729 (C67_map_regs(c
) << 1) | //side for reg c
730 (0 << 0)); //parallel
731 } else if (strstr(s
, "CMPGTDP") == s
) {
732 xpath
= C67_map_regs(a
) ^ C67_map_regs(b
);
733 ALWAYS_ASSERT(C67_map_regs(c
) == C67_map_regs(a
));
735 C67_g((C67_map_regn(c
) << 23) | //dst
736 (C67_map_regn(b
) << 18) | //src2
737 (C67_map_regn(a
) << 13) | //src1
738 (xpath
<< 12) | //x use cross path for src2
739 (0x29 << 6) | //opcode
740 (0x8 << 2) | //opcode fixed
741 (C67_map_regs(c
) << 1) | //side for reg c
742 (0 << 0)); //parallel
743 } else if (strstr(s
, "CMPEQDP") == s
) {
744 xpath
= C67_map_regs(a
) ^ C67_map_regs(b
);
745 ALWAYS_ASSERT(C67_map_regs(c
) == C67_map_regs(a
));
747 C67_g((C67_map_regn(c
) << 23) | //dst
748 (C67_map_regn(b
) << 18) | //src2
749 (C67_map_regn(a
) << 13) | //src1
750 (xpath
<< 12) | //x use cross path for src2
751 (0x28 << 6) | //opcode
752 (0x8 << 2) | //opcode fixed
753 (C67_map_regs(c
) << 1) | //side for reg c
754 (0 << 0)); //parallel
755 } else if (strstr(s
, "CMPLT") == s
) {
756 xpath
= C67_map_regs(a
) ^ C67_map_regs(b
);
757 ALWAYS_ASSERT(C67_map_regs(c
) == C67_map_regs(a
));
759 C67_g((C67_map_regn(c
) << 23) | //dst
760 (C67_map_regn(b
) << 18) | //src2
761 (C67_map_regn(a
) << 13) | //src1
762 (xpath
<< 12) | //x use cross path for src2
763 (0x57 << 5) | //opcode
764 (0x6 << 2) | //opcode fixed
765 (C67_map_regs(c
) << 1) | //side for reg c
766 (0 << 0)); //parallel
767 } else if (strstr(s
, "CMPGT") == s
) {
768 xpath
= C67_map_regs(a
) ^ C67_map_regs(b
);
769 ALWAYS_ASSERT(C67_map_regs(c
) == C67_map_regs(a
));
771 C67_g((C67_map_regn(c
) << 23) | //dst
772 (C67_map_regn(b
) << 18) | //src2
773 (C67_map_regn(a
) << 13) | //src1
774 (xpath
<< 12) | //x use cross path for src2
775 (0x47 << 5) | //opcode
776 (0x6 << 2) | //opcode fixed
777 (C67_map_regs(c
) << 1) | //side for reg c
778 (0 << 0)); //parallel
779 } else if (strstr(s
, "CMPEQ") == s
) {
780 xpath
= C67_map_regs(a
) ^ C67_map_regs(b
);
781 ALWAYS_ASSERT(C67_map_regs(c
) == C67_map_regs(a
));
783 C67_g((C67_map_regn(c
) << 23) | //dst
784 (C67_map_regn(b
) << 18) | //src2
785 (C67_map_regn(a
) << 13) | //src1
786 (xpath
<< 12) | //x use cross path for src2
787 (0x53 << 5) | //opcode
788 (0x6 << 2) | //opcode fixed
789 (C67_map_regs(c
) << 1) | //side for reg c
790 (0 << 0)); //parallel
791 } else if (strstr(s
, "CMPLTU") == s
) {
792 xpath
= C67_map_regs(a
) ^ C67_map_regs(b
);
793 ALWAYS_ASSERT(C67_map_regs(c
) == C67_map_regs(a
));
795 C67_g((C67_map_regn(c
) << 23) | //dst
796 (C67_map_regn(b
) << 18) | //src2
797 (C67_map_regn(a
) << 13) | //src1
798 (xpath
<< 12) | //x use cross path for src2
799 (0x5f << 5) | //opcode
800 (0x6 << 2) | //opcode fixed
801 (C67_map_regs(c
) << 1) | //side for reg c
802 (0 << 0)); //parallel
803 } else if (strstr(s
, "CMPGTU") == s
) {
804 xpath
= C67_map_regs(a
) ^ C67_map_regs(b
);
805 ALWAYS_ASSERT(C67_map_regs(c
) == C67_map_regs(a
));
807 C67_g((C67_map_regn(c
) << 23) | //dst
808 (C67_map_regn(b
) << 18) | //src2
809 (C67_map_regn(a
) << 13) | //src1
810 (xpath
<< 12) | //x use cross path for src2
811 (0x4f << 5) | //opcode
812 (0x6 << 2) | //opcode fixed
813 (C67_map_regs(c
) << 1) | //side for reg c
814 (0 << 0)); //parallel
815 } else if (strstr(s
, "B DISP") == s
) {
816 C67_g((0 << 29) | //creg
819 (0x4 << 2) | //opcode fixed
821 (0 << 0)); //parallel
822 } else if (strstr(s
, "B.") == s
) {
823 xpath
= C67_map_regs(c
) ^ 1;
825 C67_g((C67_map_regc(b
) << 29) | //creg
828 (C67_map_regn(c
) << 18) | //src2
830 (xpath
<< 12) | //x cross path if !B side
831 (0xd << 6) | //opcode
832 (0x8 << 2) | //opcode fixed
833 (1 << 1) | //must be S2
834 (0 << 0)); //parallel
835 } else if (strstr(s
, "MV.L") == s
) {
836 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
838 C67_g((0 << 29) | //creg
840 (C67_map_regn(c
) << 23) | //dst
841 (C67_map_regn(b
) << 18) | //src2
842 (0 << 13) | //src1 (cst5)
843 (xpath
<< 12) | //x cross path if opposite sides
844 (0x2 << 5) | //opcode
845 (0x6 << 2) | //opcode fixed
846 (C67_map_regs(c
) << 1) | //side of dest
847 (0 << 0)); //parallel
848 } else if (strstr(s
, "SPTRUNC.L") == s
) {
849 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
851 C67_g((0 << 29) | //creg
853 (C67_map_regn(c
) << 23) | //dst
854 (C67_map_regn(b
) << 18) | //src2
855 (0 << 13) | //src1 NA
856 (xpath
<< 12) | //x cross path if opposite sides
857 (0xb << 5) | //opcode
858 (0x6 << 2) | //opcode fixed
859 (C67_map_regs(c
) << 1) | //side of dest
860 (0 << 0)); //parallel
861 } else if (strstr(s
, "DPTRUNC.L") == s
) {
862 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
864 C67_g((0 << 29) | //creg
866 (C67_map_regn(c
) << 23) | //dst
867 ((C67_map_regn(b
) + 1) << 18) | //src2 WEIRD CPU must specify odd reg for some reason
868 (0 << 13) | //src1 NA
869 (xpath
<< 12) | //x cross path if opposite sides
870 (0x1 << 5) | //opcode
871 (0x6 << 2) | //opcode fixed
872 (C67_map_regs(c
) << 1) | //side of dest
873 (0 << 0)); //parallel
874 } else if (strstr(s
, "INTSP.L") == s
) {
875 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
877 C67_g((0 << 29) | //creg
879 (C67_map_regn(c
) << 23) | //dst
880 (C67_map_regn(b
) << 18) | //src2
881 (0 << 13) | //src1 NA
882 (xpath
<< 12) | //x cross path if opposite sides
883 (0x4a << 5) | //opcode
884 (0x6 << 2) | //opcode fixed
885 (C67_map_regs(c
) << 1) | //side of dest
886 (0 << 0)); //parallel
887 } else if (strstr(s
, "INTSPU.L") == s
) {
888 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
890 C67_g((0 << 29) | //creg
892 (C67_map_regn(c
) << 23) | //dst
893 (C67_map_regn(b
) << 18) | //src2
894 (0 << 13) | //src1 NA
895 (xpath
<< 12) | //x cross path if opposite sides
896 (0x49 << 5) | //opcode
897 (0x6 << 2) | //opcode fixed
898 (C67_map_regs(c
) << 1) | //side of dest
899 (0 << 0)); //parallel
900 } else if (strstr(s
, "INTDP.L") == s
) {
901 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
903 C67_g((0 << 29) | //creg
905 (C67_map_regn(c
) << 23) | //dst
906 (C67_map_regn(b
) << 18) | //src2
907 (0 << 13) | //src1 NA
908 (xpath
<< 12) | //x cross path if opposite sides
909 (0x39 << 5) | //opcode
910 (0x6 << 2) | //opcode fixed
911 (C67_map_regs(c
) << 1) | //side of dest
912 (0 << 0)); //parallel
913 } else if (strstr(s
, "INTDPU.L") == s
) {
914 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
916 C67_g((0 << 29) | //creg
918 (C67_map_regn(c
) << 23) | //dst
919 ((C67_map_regn(b
) + 1) << 18) | //src2 WEIRD CPU must specify odd reg for some reason
920 (0 << 13) | //src1 NA
921 (xpath
<< 12) | //x cross path if opposite sides
922 (0x3b << 5) | //opcode
923 (0x6 << 2) | //opcode fixed
924 (C67_map_regs(c
) << 1) | //side of dest
925 (0 << 0)); //parallel
926 } else if (strstr(s
, "SPDP.L") == s
) {
927 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
929 C67_g((0 << 29) | //creg
931 (C67_map_regn(c
) << 23) | //dst
932 (C67_map_regn(b
) << 18) | //src2
933 (0 << 13) | //src1 NA
934 (xpath
<< 12) | //x cross path if opposite sides
935 (0x2 << 6) | //opcode
936 (0x8 << 2) | //opcode fixed
937 (C67_map_regs(c
) << 1) | //side of dest
938 (0 << 0)); //parallel
939 } else if (strstr(s
, "DPSP.L") == s
) {
940 ALWAYS_ASSERT(C67_map_regs(b
) == C67_map_regs(c
));
942 C67_g((0 << 29) | //creg
944 (C67_map_regn(c
) << 23) | //dst
945 ((C67_map_regn(b
) + 1) << 18) | //src2 WEIRD CPU must specify odd reg for some reason
946 (0 << 13) | //src1 NA
947 (0 << 12) | //x cross path if opposite sides
948 (0x9 << 5) | //opcode
949 (0x6 << 2) | //opcode fixed
950 (C67_map_regs(c
) << 1) | //side of dest
951 (0 << 0)); //parallel
952 } else if (strstr(s
, "ADD.L") == s
) {
953 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
955 ALWAYS_ASSERT(C67_map_regs(a
) == C67_map_regs(c
));
957 C67_g((0 << 29) | //creg
959 (C67_map_regn(c
) << 23) | //dst
960 (C67_map_regn(b
) << 18) | //src2 (possible x path)
961 (C67_map_regn(a
) << 13) | //src1
962 (xpath
<< 12) | //x cross path if opposite sides
963 (0x3 << 5) | //opcode
964 (0x6 << 2) | //opcode fixed
965 (C67_map_regs(c
) << 1) | //side of dest
966 (0 << 0)); //parallel
967 } else if (strstr(s
, "SUB.L") == s
) {
968 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
970 ALWAYS_ASSERT(C67_map_regs(a
) == C67_map_regs(c
));
972 C67_g((0 << 29) | //creg
974 (C67_map_regn(c
) << 23) | //dst
975 (C67_map_regn(b
) << 18) | //src2 (possible x path)
976 (C67_map_regn(a
) << 13) | //src1
977 (xpath
<< 12) | //x cross path if opposite sides
978 (0x7 << 5) | //opcode
979 (0x6 << 2) | //opcode fixed
980 (C67_map_regs(c
) << 1) | //side of dest
981 (0 << 0)); //parallel
982 } else if (strstr(s
, "OR.L") == s
) {
983 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
985 ALWAYS_ASSERT(C67_map_regs(a
) == C67_map_regs(c
));
987 C67_g((0 << 29) | //creg
989 (C67_map_regn(c
) << 23) | //dst
990 (C67_map_regn(b
) << 18) | //src2 (possible x path)
991 (C67_map_regn(a
) << 13) | //src1
992 (xpath
<< 12) | //x cross path if opposite sides
993 (0x7f << 5) | //opcode
994 (0x6 << 2) | //opcode fixed
995 (C67_map_regs(c
) << 1) | //side of dest
996 (0 << 0)); //parallel
997 } else if (strstr(s
, "AND.L") == s
) {
998 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
1000 ALWAYS_ASSERT(C67_map_regs(a
) == C67_map_regs(c
));
1002 C67_g((0 << 29) | //creg
1004 (C67_map_regn(c
) << 23) | //dst
1005 (C67_map_regn(b
) << 18) | //src2 (possible x path)
1006 (C67_map_regn(a
) << 13) | //src1
1007 (xpath
<< 12) | //x cross path if opposite sides
1008 (0x7b << 5) | //opcode
1009 (0x6 << 2) | //opcode fixed
1010 (C67_map_regs(c
) << 1) | //side of dest
1011 (0 << 0)); //parallel
1012 } else if (strstr(s
, "XOR.L") == s
) {
1013 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
1015 ALWAYS_ASSERT(C67_map_regs(a
) == C67_map_regs(c
));
1017 C67_g((0 << 29) | //creg
1019 (C67_map_regn(c
) << 23) | //dst
1020 (C67_map_regn(b
) << 18) | //src2 (possible x path)
1021 (C67_map_regn(a
) << 13) | //src1
1022 (xpath
<< 12) | //x cross path if opposite sides
1023 (0x6f << 5) | //opcode
1024 (0x6 << 2) | //opcode fixed
1025 (C67_map_regs(c
) << 1) | //side of dest
1026 (0 << 0)); //parallel
1027 } else if (strstr(s
, "ADDSP.L") == s
) {
1028 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
1030 ALWAYS_ASSERT(C67_map_regs(a
) == C67_map_regs(c
));
1032 C67_g((0 << 29) | //creg
1034 (C67_map_regn(c
) << 23) | //dst
1035 (C67_map_regn(b
) << 18) | //src2 (possible x path)
1036 (C67_map_regn(a
) << 13) | //src1
1037 (xpath
<< 12) | //x cross path if opposite sides
1038 (0x10 << 5) | //opcode
1039 (0x6 << 2) | //opcode fixed
1040 (C67_map_regs(c
) << 1) | //side of dest
1041 (0 << 0)); //parallel
1042 } else if (strstr(s
, "ADDDP.L") == s
) {
1043 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
1045 ALWAYS_ASSERT(C67_map_regs(a
) == C67_map_regs(c
));
1047 C67_g((0 << 29) | //creg
1049 (C67_map_regn(c
) << 23) | //dst
1050 (C67_map_regn(b
) << 18) | //src2 (possible x path)
1051 (C67_map_regn(a
) << 13) | //src1
1052 (xpath
<< 12) | //x cross path if opposite sides
1053 (0x18 << 5) | //opcode
1054 (0x6 << 2) | //opcode fixed
1055 (C67_map_regs(c
) << 1) | //side of dest
1056 (0 << 0)); //parallel
1057 } else if (strstr(s
, "SUBSP.L") == s
) {
1058 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
1060 ALWAYS_ASSERT(C67_map_regs(a
) == C67_map_regs(c
));
1062 C67_g((0 << 29) | //creg
1064 (C67_map_regn(c
) << 23) | //dst
1065 (C67_map_regn(b
) << 18) | //src2 (possible x path)
1066 (C67_map_regn(a
) << 13) | //src1
1067 (xpath
<< 12) | //x cross path if opposite sides
1068 (0x11 << 5) | //opcode
1069 (0x6 << 2) | //opcode fixed
1070 (C67_map_regs(c
) << 1) | //side of dest
1071 (0 << 0)); //parallel
1072 } else if (strstr(s
, "SUBDP.L") == s
) {
1073 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
1075 ALWAYS_ASSERT(C67_map_regs(a
) == C67_map_regs(c
));
1077 C67_g((0 << 29) | //creg
1079 (C67_map_regn(c
) << 23) | //dst
1080 (C67_map_regn(b
) << 18) | //src2 (possible x path)
1081 (C67_map_regn(a
) << 13) | //src1
1082 (xpath
<< 12) | //x cross path if opposite sides
1083 (0x19 << 5) | //opcode
1084 (0x6 << 2) | //opcode fixed
1085 (C67_map_regs(c
) << 1) | //side of dest
1086 (0 << 0)); //parallel
1087 } else if (strstr(s
, "MPYSP.M") == s
) {
1088 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
1090 ALWAYS_ASSERT(C67_map_regs(a
) == C67_map_regs(c
));
1092 C67_g((0 << 29) | //creg
1094 (C67_map_regn(c
) << 23) | //dst
1095 (C67_map_regn(b
) << 18) | //src2 (possible x path)
1096 (C67_map_regn(a
) << 13) | //src1
1097 (xpath
<< 12) | //x cross path if opposite sides
1098 (0x1c << 7) | //opcode
1099 (0x0 << 2) | //opcode fixed
1100 (C67_map_regs(c
) << 1) | //side of dest
1101 (0 << 0)); //parallel
1102 } else if (strstr(s
, "MPYDP.M") == s
) {
1103 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
1105 ALWAYS_ASSERT(C67_map_regs(a
) == C67_map_regs(c
));
1107 C67_g((0 << 29) | //creg
1109 (C67_map_regn(c
) << 23) | //dst
1110 (C67_map_regn(b
) << 18) | //src2 (possible x path)
1111 (C67_map_regn(a
) << 13) | //src1
1112 (xpath
<< 12) | //x cross path if opposite sides
1113 (0x0e << 7) | //opcode
1114 (0x0 << 2) | //opcode fixed
1115 (C67_map_regs(c
) << 1) | //side of dest
1116 (0 << 0)); //parallel
1117 } else if (strstr(s
, "MPYI.M") == s
) {
1118 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
1120 ALWAYS_ASSERT(C67_map_regs(a
) == C67_map_regs(c
));
1122 C67_g((0 << 29) | //creg
1124 (C67_map_regn(c
) << 23) | //dst
1125 (C67_map_regn(b
) << 18) | //src2
1126 (C67_map_regn(a
) << 13) | //src1 (cst5)
1127 (xpath
<< 12) | //x cross path if opposite sides
1128 (0x4 << 7) | //opcode
1129 (0x0 << 2) | //opcode fixed
1130 (C67_map_regs(c
) << 1) | //side of dest
1131 (0 << 0)); //parallel
1132 } else if (strstr(s
, "SHR.S") == s
) {
1133 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
1135 ALWAYS_ASSERT(C67_map_regs(c
) == C67_map_regs(a
));
1137 C67_g((0 << 29) | //creg
1139 (C67_map_regn(c
) << 23) | //dst
1140 (C67_map_regn(b
) << 18) | //src2
1141 (C67_map_regn(a
) << 13) | //src1
1142 (xpath
<< 12) | //x cross path if opposite sides
1143 (0x37 << 6) | //opcode
1144 (0x8 << 2) | //opcode fixed
1145 (C67_map_regs(c
) << 1) | //side of dest
1146 (0 << 0)); //parallel
1147 } else if (strstr(s
, "SHRU.S") == s
) {
1148 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
1150 ALWAYS_ASSERT(C67_map_regs(c
) == C67_map_regs(a
));
1152 C67_g((0 << 29) | //creg
1154 (C67_map_regn(c
) << 23) | //dst
1155 (C67_map_regn(b
) << 18) | //src2
1156 (C67_map_regn(a
) << 13) | //src1
1157 (xpath
<< 12) | //x cross path if opposite sides
1158 (0x27 << 6) | //opcode
1159 (0x8 << 2) | //opcode fixed
1160 (C67_map_regs(c
) << 1) | //side of dest
1161 (0 << 0)); //parallel
1162 } else if (strstr(s
, "SHL.S") == s
) {
1163 xpath
= C67_map_regs(b
) ^ C67_map_regs(c
);
1165 ALWAYS_ASSERT(C67_map_regs(c
) == C67_map_regs(a
));
1167 C67_g((0 << 29) | //creg
1169 (C67_map_regn(c
) << 23) | //dst
1170 (C67_map_regn(b
) << 18) | //src2
1171 (C67_map_regn(a
) << 13) | //src1
1172 (xpath
<< 12) | //x cross path if opposite sides
1173 (0x33 << 6) | //opcode
1174 (0x8 << 2) | //opcode fixed
1175 (C67_map_regs(c
) << 1) | //side of dest
1176 (0 << 0)); //parallel
1177 } else if (strstr(s
, "||ADDK") == s
) {
1178 xpath
= 0; // no xpath required just use the side of the src/dst
1180 C67_g((0 << 29) | //creg
1182 (C67_map_regn(b
) << 23) | //dst
1183 (a
<< 07) | //scst16
1184 (0x14 << 2) | //opcode fixed
1185 (C67_map_regs(b
) << 1) | //side of dst
1186 (1 << 0)); //parallel
1187 } else if (strstr(s
, "ADDK") == s
) {
1188 xpath
= 0; // no xpath required just use the side of the src/dst
1190 C67_g((0 << 29) | //creg
1192 (C67_map_regn(b
) << 23) | //dst
1193 (a
<< 07) | //scst16
1194 (0x14 << 2) | //opcode fixed
1195 (C67_map_regs(b
) << 1) | //side of dst
1196 (0 << 0)); //parallel
1197 } else if (strstr(s
, "NOP") == s
) {
1198 C67_g(((a
- 1) << 13) | //no of cycles
1199 (0 << 0)); //parallel
1201 ALWAYS_ASSERT(FALSE
);
1203 #ifdef ASSEMBLY_LISTING_C67
1204 fprintf(f
, " %s %d %d %d\n", s
, a
, b
, c
);
1209 //r=reg to load, fr=from reg, symbol for relocation, constant
1211 void C67_MVKL(int r
, int fc
)
1213 C67_asm("MVKL.", fc
, r
, 0);
1216 void C67_MVKH(int r
, int fc
)
1218 C67_asm("MVKH.", fc
, r
, 0);
1221 void C67_STB_SP_A0(int r
)
1223 C67_asm("STB.D *+SP[A0]", r
, 0, 0); // STB r,*+SP[A0]
1226 void C67_STH_SP_A0(int r
)
1228 C67_asm("STH.D *+SP[A0]", r
, 0, 0); // STH r,*+SP[A0]
1231 void C67_STW_SP_A0(int r
)
1233 C67_asm("STW.D *+SP[A0]", r
, 0, 0); // STW r,*+SP[A0]
1236 void C67_STB_PTR(int r
, int r2
)
1238 C67_asm("STB.D *", r
, r2
, 0); // STB r, *r2
1241 void C67_STH_PTR(int r
, int r2
)
1243 C67_asm("STH.D *", r
, r2
, 0); // STH r, *r2
1246 void C67_STW_PTR(int r
, int r2
)
1248 C67_asm("STW.D *", r
, r2
, 0); // STW r, *r2
1251 void C67_STW_PTR_PRE_INC(int r
, int r2
, int n
)
1253 C67_asm("STW.D +*", r
, r2
, n
); // STW r, *+r2
1256 void C67_PUSH(int r
)
1258 C67_asm("STW.D SP POST DEC", r
, 0, 0); // STW r,*SP--
1261 void C67_LDW_SP_A0(int r
)
1263 C67_asm("LDW.D *+SP[A0]", r
, 0, 0); // LDW *+SP[A0],r
1266 void C67_LDDW_SP_A0(int r
)
1268 C67_asm("LDDW.D *+SP[A0]", r
, 0, 0); // LDDW *+SP[A0],r
1271 void C67_LDH_SP_A0(int r
)
1273 C67_asm("LDH.D *+SP[A0]", r
, 0, 0); // LDH *+SP[A0],r
1276 void C67_LDB_SP_A0(int r
)
1278 C67_asm("LDB.D *+SP[A0]", r
, 0, 0); // LDB *+SP[A0],r
1281 void C67_LDHU_SP_A0(int r
)
1283 C67_asm("LDHU.D *+SP[A0]", r
, 0, 0); // LDHU *+SP[A0],r
1286 void C67_LDBU_SP_A0(int r
)
1288 C67_asm("LDBU.D *+SP[A0]", r
, 0, 0); // LDBU *+SP[A0],r
1291 void C67_LDW_PTR(int r
, int r2
)
1293 C67_asm("LDW.D *", r
, r2
, 0); // LDW *r,r2
1296 void C67_LDDW_PTR(int r
, int r2
)
1298 C67_asm("LDDW.D *", r
, r2
, 0); // LDDW *r,r2
1301 void C67_LDH_PTR(int r
, int r2
)
1303 C67_asm("LDH.D *", r
, r2
, 0); // LDH *r,r2
1306 void C67_LDB_PTR(int r
, int r2
)
1308 C67_asm("LDB.D *", r
, r2
, 0); // LDB *r,r2
1311 void C67_LDHU_PTR(int r
, int r2
)
1313 C67_asm("LDHU.D *", r
, r2
, 0); // LDHU *r,r2
1316 void C67_LDBU_PTR(int r
, int r2
)
1318 C67_asm("LDBU.D *", r
, r2
, 0); // LDBU *r,r2
1321 void C67_LDW_PTR_PRE_INC(int r
, int r2
)
1323 C67_asm("LDW.D +*", r
, r2
, 0); // LDW *+r,r2
1328 C67_asm("LDW.D SP PRE INC", r
, 0, 0); // LDW *++SP,r
1331 void C67_POP_DW(int r
)
1333 C67_asm("LDDW.D SP PRE INC", r
, 0, 0); // LDDW *++SP,r
1336 void C67_CMPLT(int s1
, int s2
, int dst
)
1338 C67_asm("CMPLT.L1", s1
, s2
, dst
);
1341 void C67_CMPGT(int s1
, int s2
, int dst
)
1343 C67_asm("CMPGT.L1", s1
, s2
, dst
);
1346 void C67_CMPEQ(int s1
, int s2
, int dst
)
1348 C67_asm("CMPEQ.L1", s1
, s2
, dst
);
1351 void C67_CMPLTU(int s1
, int s2
, int dst
)
1353 C67_asm("CMPLTU.L1", s1
, s2
, dst
);
1356 void C67_CMPGTU(int s1
, int s2
, int dst
)
1358 C67_asm("CMPGTU.L1", s1
, s2
, dst
);
1362 void C67_CMPLTSP(int s1
, int s2
, int dst
)
1364 C67_asm("CMPLTSP.S1", s1
, s2
, dst
);
1367 void C67_CMPGTSP(int s1
, int s2
, int dst
)
1369 C67_asm("CMPGTSP.S1", s1
, s2
, dst
);
1372 void C67_CMPEQSP(int s1
, int s2
, int dst
)
1374 C67_asm("CMPEQSP.S1", s1
, s2
, dst
);
1377 void C67_CMPLTDP(int s1
, int s2
, int dst
)
1379 C67_asm("CMPLTDP.S1", s1
, s2
, dst
);
1382 void C67_CMPGTDP(int s1
, int s2
, int dst
)
1384 C67_asm("CMPGTDP.S1", s1
, s2
, dst
);
1387 void C67_CMPEQDP(int s1
, int s2
, int dst
)
1389 C67_asm("CMPEQDP.S1", s1
, s2
, dst
);
1393 void C67_IREG_B_REG(int inv
, int r1
, int r2
) // [!R] B r2
1395 C67_asm("B.S2", inv
, r1
, r2
);
1399 // call with how many 32 bit words to skip
1400 // (0 would branch to the branch instruction)
1402 void C67_B_DISP(int disp
) // B +2 Branch with constant displacement
1404 // Branch point is relative to the 8 word fetch packet
1406 // we will assume the text section always starts on an 8 word (32 byte boundary)
1408 // so add in how many words into the fetch packet the branch is
1411 C67_asm("B DISP", disp
+ ((ind
& 31) >> 2), 0, 0);
1416 C67_asm("NOP", n
, 0, 0);
1419 void C67_ADDK(int n
, int r
)
1421 ALWAYS_ASSERT(abs(n
) < 32767);
1423 C67_asm("ADDK", n
, r
, 0);
1426 void C67_ADDK_PARALLEL(int n
, int r
)
1428 ALWAYS_ASSERT(abs(n
) < 32767);
1430 C67_asm("||ADDK", n
, r
, 0);
1433 void C67_Adjust_ADDK(int *inst
, int n
)
1435 ALWAYS_ASSERT(abs(n
) < 32767);
1437 *inst
= (*inst
& (~(0xffff << 7))) | ((n
& 0xffff) << 7);
1440 void C67_MV(int r
, int v
)
1442 C67_asm("MV.L", 0, r
, v
);
1446 void C67_DPTRUNC(int r
, int v
)
1448 C67_asm("DPTRUNC.L", 0, r
, v
);
1451 void C67_SPTRUNC(int r
, int v
)
1453 C67_asm("SPTRUNC.L", 0, r
, v
);
1456 void C67_INTSP(int r
, int v
)
1458 C67_asm("INTSP.L", 0, r
, v
);
1461 void C67_INTDP(int r
, int v
)
1463 C67_asm("INTDP.L", 0, r
, v
);
1466 void C67_INTSPU(int r
, int v
)
1468 C67_asm("INTSPU.L", 0, r
, v
);
1471 void C67_INTDPU(int r
, int v
)
1473 C67_asm("INTDPU.L", 0, r
, v
);
1476 void C67_SPDP(int r
, int v
)
1478 C67_asm("SPDP.L", 0, r
, v
);
1481 void C67_DPSP(int r
, int v
) // note regs must be on the same side
1483 C67_asm("DPSP.L", 0, r
, v
);
1486 void C67_ADD(int r
, int v
)
1488 C67_asm("ADD.L", v
, r
, v
);
1491 void C67_SUB(int r
, int v
)
1493 C67_asm("SUB.L", v
, r
, v
);
1496 void C67_AND(int r
, int v
)
1498 C67_asm("AND.L", v
, r
, v
);
1501 void C67_OR(int r
, int v
)
1503 C67_asm("OR.L", v
, r
, v
);
1506 void C67_XOR(int r
, int v
)
1508 C67_asm("XOR.L", v
, r
, v
);
1511 void C67_ADDSP(int r
, int v
)
1513 C67_asm("ADDSP.L", v
, r
, v
);
1516 void C67_SUBSP(int r
, int v
)
1518 C67_asm("SUBSP.L", v
, r
, v
);
1521 void C67_MPYSP(int r
, int v
)
1523 C67_asm("MPYSP.M", v
, r
, v
);
1526 void C67_ADDDP(int r
, int v
)
1528 C67_asm("ADDDP.L", v
, r
, v
);
1531 void C67_SUBDP(int r
, int v
)
1533 C67_asm("SUBDP.L", v
, r
, v
);
1536 void C67_MPYDP(int r
, int v
)
1538 C67_asm("MPYDP.M", v
, r
, v
);
1541 void C67_MPYI(int r
, int v
)
1543 C67_asm("MPYI.M", v
, r
, v
);
1546 void C67_SHL(int r
, int v
)
1548 C67_asm("SHL.S", r
, v
, v
);
1551 void C67_SHRU(int r
, int v
)
1553 C67_asm("SHRU.S", r
, v
, v
);
1556 void C67_SHR(int r
, int v
)
1558 C67_asm("SHR.S", r
, v
, v
);
1563 /* load 'r' from value 'sv' */
1564 void load(int r
, SValue
* sv
)
1566 int v
, t
, ft
, fc
, fr
, size
= 0, element
;
1567 BOOL Unsigned
= FALSE
;
1574 v
= fr
& VT_VALMASK
;
1576 if (v
== VT_LLOCAL
) {
1578 v1
.r
= VT_LOCAL
| VT_LVAL
;
1582 } else if ((ft
& VT_BTYPE
) == VT_LDOUBLE
) {
1583 tcc_error("long double not supported");
1584 } else if ((ft
& VT_TYPE
) == VT_BYTE
) {
1586 } else if ((ft
& VT_TYPE
) == (VT_BYTE
| VT_UNSIGNED
)) {
1589 } else if ((ft
& VT_TYPE
) == VT_SHORT
) {
1591 } else if ((ft
& VT_TYPE
) == (VT_SHORT
| VT_UNSIGNED
)) {
1594 } else if ((ft
& VT_BTYPE
) == VT_DOUBLE
) {
1600 // check if fc is a positive reference on the stack,
1601 // if it is tcc is referencing what it thinks is a parameter
1602 // on the stack, so check if it is really in a register.
1605 if (v
== VT_LOCAL
&& fc
> 0) {
1608 for (t
= 0; t
< NoCallArgsPassedOnStack
; t
++) {
1609 if (fc
== stack_pos
)
1612 stack_pos
+= TranslateStackToReg
[t
];
1615 // param has been pushed on stack, get it like a local var
1617 fc
= ParamLocOnStack
[t
] - 8;
1620 if ((fr
& VT_VALMASK
) < VT_CONST
) // check for pure indirect
1624 C67_LDBU_PTR(v
, r
); // LDBU *v,r
1626 C67_LDB_PTR(v
, r
); // LDB *v,r
1627 } else if (size
== 2) {
1629 C67_LDHU_PTR(v
, r
); // LDHU *v,r
1631 C67_LDH_PTR(v
, r
); // LDH *v,r
1632 } else if (size
== 4) {
1633 C67_LDW_PTR(v
, r
); // LDW *v,r
1634 } else if (size
== 8) {
1635 C67_LDDW_PTR(v
, r
); // LDDW *v,r
1638 C67_NOP(4); // NOP 4
1640 } else if (fr
& VT_SYM
) {
1641 greloc(cur_text_section
, sv
->sym
, ind
, R_C60LO16
); // rem the inst need to be patched
1642 greloc(cur_text_section
, sv
->sym
, ind
+ 4, R_C60HI16
);
1645 C67_MVKL(C67_A0
, fc
); //r=reg to load, constant
1646 C67_MVKH(C67_A0
, fc
); //r=reg to load, constant
1651 C67_LDBU_PTR(C67_A0
, r
); // LDBU *A0,r
1653 C67_LDB_PTR(C67_A0
, r
); // LDB *A0,r
1654 } else if (size
== 2) {
1656 C67_LDHU_PTR(C67_A0
, r
); // LDHU *A0,r
1658 C67_LDH_PTR(C67_A0
, r
); // LDH *A0,r
1659 } else if (size
== 4) {
1660 C67_LDW_PTR(C67_A0
, r
); // LDW *A0,r
1661 } else if (size
== 8) {
1662 C67_LDDW_PTR(C67_A0
, r
); // LDDW *A0,r
1665 C67_NOP(4); // NOP 4
1670 // divide offset in bytes to create element index
1671 C67_MVKL(C67_A0
, (fc
/ element
) + 8 / element
); //r=reg to load, constant
1672 C67_MVKH(C67_A0
, (fc
/ element
) + 8 / element
); //r=reg to load, constant
1676 C67_LDBU_SP_A0(r
); // LDBU r, SP[A0]
1678 C67_LDB_SP_A0(r
); // LDB r, SP[A0]
1679 } else if (size
== 2) {
1681 C67_LDHU_SP_A0(r
); // LDHU r, SP[A0]
1683 C67_LDH_SP_A0(r
); // LDH r, SP[A0]
1684 } else if (size
== 4) {
1685 C67_LDW_SP_A0(r
); // LDW r, SP[A0]
1686 } else if (size
== 8) {
1687 C67_LDDW_SP_A0(r
); // LDDW r, SP[A0]
1691 C67_NOP(4); // NOP 4
1695 if (v
== VT_CONST
) {
1697 greloc(cur_text_section
, sv
->sym
, ind
, R_C60LO16
); // rem the inst need to be patched
1698 greloc(cur_text_section
, sv
->sym
, ind
+ 4, R_C60HI16
);
1700 C67_MVKL(r
, fc
); //r=reg to load, constant
1701 C67_MVKH(r
, fc
); //r=reg to load, constant
1702 } else if (v
== VT_LOCAL
) {
1703 C67_MVKL(r
, fc
+ 8); //r=reg to load, constant C67 stack points to next free
1704 C67_MVKH(r
, fc
+ 8); //r=reg to load, constant
1705 C67_ADD(C67_FP
, r
); // MV v,r v -> r
1706 } else if (v
== VT_CMP
) {
1707 C67_MV(C67_compare_reg
, r
); // MV v,r v -> r
1708 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
1710 C67_B_DISP(4); // Branch with constant displacement, skip over this branch, load, nop, load
1711 C67_MVKL(r
, t
); // r=reg to load, 0 or 1 (do this while branching)
1712 C67_NOP(4); // NOP 4
1713 gsym(fc
); // modifies other branches to branch here
1714 C67_MVKL(r
, t
^ 1); // r=reg to load, 0 or 1
1715 } else if (v
!= r
) {
1716 C67_MV(v
, r
); // MV v,r v -> r
1718 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
1719 C67_MV(v
+ 1, r
+ 1); // MV v,r v -> r
1725 /* store register 'r' in lvalue 'v' */
1726 void store(int r
, SValue
* v
)
1728 int fr
, bt
, ft
, fc
, size
, t
, element
;
1732 fr
= v
->r
& VT_VALMASK
;
1734 /* XXX: incorrect if float reg to reg */
1736 if (bt
== VT_LDOUBLE
) {
1737 tcc_error("long double not supported");
1741 else if (bt
== VT_BYTE
)
1743 else if (bt
== VT_DOUBLE
)
1748 if ((v
->r
& VT_VALMASK
) == VT_CONST
) {
1749 /* constant memory reference */
1751 if (v
->r
& VT_SYM
) {
1752 greloc(cur_text_section
, v
->sym
, ind
, R_C60LO16
); // rem the inst need to be patched
1753 greloc(cur_text_section
, v
->sym
, ind
+ 4, R_C60HI16
);
1755 C67_MVKL(C67_A0
, fc
); //r=reg to load, constant
1756 C67_MVKH(C67_A0
, fc
); //r=reg to load, constant
1759 C67_STB_PTR(r
, C67_A0
); // STB r, *A0
1761 C67_STH_PTR(r
, C67_A0
); // STH r, *A0
1762 else if (size
== 4 || size
== 8)
1763 C67_STW_PTR(r
, C67_A0
); // STW r, *A0
1766 C67_STW_PTR_PRE_INC(r
+ 1, C67_A0
, 1); // STW r, *+A0[1]
1767 } else if ((v
->r
& VT_VALMASK
) == VT_LOCAL
) {
1768 // check case of storing to passed argument that
1769 // tcc thinks is on the stack but for C67 is
1770 // passed as a reg. However it may have been
1771 // saved to the stack, if that reg was required
1772 // for a call to a child function
1774 if (fc
> 0) // argument ??
1776 // walk through sizes and figure which param
1780 for (t
= 0; t
< NoCallArgsPassedOnStack
; t
++) {
1781 if (fc
== stack_pos
)
1784 stack_pos
+= TranslateStackToReg
[t
];
1787 // param has been pushed on stack, get it like a local var
1788 fc
= ParamLocOnStack
[t
] - 8;
1796 // divide offset in bytes to create word index
1797 C67_MVKL(C67_A0
, (fc
/ element
) + 8 / element
); //r=reg to load, constant
1798 C67_MVKH(C67_A0
, (fc
/ element
) + 8 / element
); //r=reg to load, constant
1803 C67_STB_SP_A0(r
); // STB r, SP[A0]
1805 C67_STH_SP_A0(r
); // STH r, SP[A0]
1806 else if (size
== 4 || size
== 8)
1807 C67_STW_SP_A0(r
); // STW r, SP[A0]
1810 C67_ADDK(1, C67_A0
); // ADDK 1,A0
1811 C67_STW_SP_A0(r
+ 1); // STW r, SP[A0]
1815 C67_STB_PTR(r
, fr
); // STB r, *fr
1817 C67_STH_PTR(r
, fr
); // STH r, *fr
1818 else if (size
== 4 || size
== 8)
1819 C67_STW_PTR(r
, fr
); // STW r, *fr
1822 C67_STW_PTR_PRE_INC(r
+ 1, fr
, 1); // STW r, *+fr[1]
1828 /* 'is_jmp' is '1' if it is a jump */
1829 static void gcall_or_jmp(int is_jmp
)
1834 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
) {
1836 if (vtop
->r
& VT_SYM
) {
1837 /* relocation case */
1839 // get add into A0, then start the jump B3
1841 greloc(cur_text_section
, vtop
->sym
, ind
, R_C60LO16
); // rem the inst need to be patched
1842 greloc(cur_text_section
, vtop
->sym
, ind
+ 4, R_C60HI16
);
1844 C67_MVKL(C67_A0
, 0); //r=reg to load, constant
1845 C67_MVKH(C67_A0
, 0); //r=reg to load, constant
1846 C67_IREG_B_REG(0, C67_CREG_ZERO
, C67_A0
); // B.S2x A0
1849 C67_NOP(5); // simple jump, just put NOP
1851 // Call, must load return address into B3 during delay slots
1853 sym
= get_sym_ref(&char_pointer_type
, cur_text_section
, ind
+ 12, 0); // symbol for return address
1854 greloc(cur_text_section
, sym
, ind
, R_C60LO16
); // rem the inst need to be patched
1855 greloc(cur_text_section
, sym
, ind
+ 4, R_C60HI16
);
1856 C67_MVKL(C67_B3
, 0); //r=reg to load, constant
1857 C67_MVKH(C67_B3
, 0); //r=reg to load, constant
1858 C67_NOP(3); // put remaining NOPs
1861 /* put an empty PC32 relocation */
1862 ALWAYS_ASSERT(FALSE
);
1865 /* otherwise, indirect call */
1867 C67_IREG_B_REG(0, C67_CREG_ZERO
, r
); // B.S2x r
1870 C67_NOP(5); // simple jump, just put NOP
1872 // Call, must load return address into B3 during delay slots
1874 sym
= get_sym_ref(&char_pointer_type
, cur_text_section
, ind
+ 12, 0); // symbol for return address
1875 greloc(cur_text_section
, sym
, ind
, R_C60LO16
); // rem the inst need to be patched
1876 greloc(cur_text_section
, sym
, ind
+ 4, R_C60HI16
);
1877 C67_MVKL(C67_B3
, 0); //r=reg to load, constant
1878 C67_MVKH(C67_B3
, 0); //r=reg to load, constant
1879 C67_NOP(3); // put remaining NOPs
1884 ST_FUNC
int regargs_nregs(RegArgs
*args
)
1889 /* Return the number of registers needed to return the struct, or 0 if
1890 returning via struct pointer. */
1891 ST_FUNC
int gfunc_sret(CType
*vt
, int variadic
, CType
*ret
, int *ret_align
, int *regsize
, RegArgs
*args
) {
1892 *ret_align
= 1; // Never have to re-align return values for x86-64
1898 /* generate function call with address in (vtop->t, vtop->c) and free function
1899 context. Stack entry is popped */
1900 void gfunc_call(int nb_args
)
1903 int args_sizes
[NoCallArgsPassedOnStack
];
1905 if (nb_args
> NoCallArgsPassedOnStack
) {
1906 tcc_error("more than 10 function params not currently supported");
1907 // handle more than 10, put some on the stack
1910 for (i
= 0; i
< nb_args
; i
++) {
1911 if ((vtop
->type
.t
& VT_BTYPE
) == VT_STRUCT
) {
1912 ALWAYS_ASSERT(FALSE
);
1914 /* simple type (currently always same size) */
1915 /* XXX: implicit cast ? */
1918 if ((vtop
->type
.t
& VT_BTYPE
) == VT_LLONG
) {
1919 tcc_error("long long not supported");
1920 } else if ((vtop
->type
.t
& VT_BTYPE
) == VT_LDOUBLE
) {
1921 tcc_error("long double not supported");
1922 } else if ((vtop
->type
.t
& VT_BTYPE
) == VT_DOUBLE
) {
1928 // put the parameter into the corresponding reg (pair)
1930 r
= gv(RC_C67_A4
<< (2 * i
));
1932 // must put on stack because with 1 pass compiler , no way to tell
1933 // if an up coming nested call might overwrite these regs
1938 C67_STW_PTR_PRE_INC(r
+ 1, C67_SP
, 3); // STW r, *+SP[3] (go back and put the other)
1940 args_sizes
[i
] = size
;
1944 // POP all the params on the stack into registers for the
1945 // immediate call (in reverse order)
1947 for (i
= nb_args
- 1; i
>= 0; i
--) {
1949 if (args_sizes
[i
] == 8)
1950 C67_POP_DW(TREG_C67_A4
+ i
* 2);
1952 C67_POP(TREG_C67_A4
+ i
* 2);
1959 // to be compatible with Code Composer for the C67
1960 // the first 10 parameters must be passed in registers
1961 // (pairs for 64 bits) starting wit; A4:A5, then B4:B5 and
1962 // ending with B12:B13.
1964 // When a call is made, if the caller has its parameters
1965 // in regs A4-B13 these must be saved before/as the call
1966 // parameters are loaded and restored upon return (or if/when needed).
1968 /* generate function prolog of type 't' */
1969 void gfunc_prolog(CType
* func_type
)
1971 int addr
, align
, size
, func_call
, i
;
1975 sym
= func_type
->ref
;
1978 /* if the function returns a structure, then add an
1979 implicit pointer parameter */
1980 func_vt
= sym
->type
;
1981 func_var
= (sym
->c
== FUNC_ELLIPSIS
);
1982 if ((func_vt
.t
& VT_BTYPE
) == VT_STRUCT
) {
1987 NoOfCurFuncArgs
= 0;
1989 /* define parameters */
1990 while ((sym
= sym
->next
) != NULL
) {
1992 sym_push(sym
->v
& ~SYM_FIELD
, type
, VT_LOCAL
| lvalue_type(type
->t
), addr
);
1993 size
= type_size(type
, &align
);
1994 size
= (size
+ 3) & ~3;
1996 // keep track of size of arguments so
1997 // we can translate where tcc thinks they
1998 // are on the stack into the appropriate reg
2000 TranslateStackToReg
[NoOfCurFuncArgs
] = size
;
2003 #ifdef FUNC_STRUCT_PARAM_AS_PTR
2004 /* structs are passed as pointer */
2005 if ((type
->t
& VT_BTYPE
) == VT_STRUCT
) {
2012 /* pascal type call ? */
2013 if (func_call
== FUNC_STDCALL
)
2014 func_ret_sub
= addr
- 8;
2016 C67_MV(C67_FP
, C67_A0
); // move FP -> A0
2017 C67_MV(C67_SP
, C67_FP
); // move SP -> FP
2019 // place all the args passed in regs onto the stack
2022 for (i
= 0; i
< NoOfCurFuncArgs
; i
++) {
2024 ParamLocOnStack
[i
] = loc
; // remember where the param is
2027 C67_PUSH(TREG_C67_A4
+ i
* 2);
2029 if (TranslateStackToReg
[i
] == 8) {
2030 C67_STW_PTR_PRE_INC(TREG_C67_A4
+ i
* 2 + 1, C67_SP
, 3); // STW r, *+SP[1] (go back and put the other)
2034 TotalBytesPushedOnStack
= -loc
;
2036 func_sub_sp_offset
= ind
; // remember where we put the stack instruction
2037 C67_ADDK(0, C67_SP
); // ADDK.L2 loc,SP (just put zero temporarily)
2043 /* generate function epilog */
2044 void gfunc_epilog(void)
2047 int local
= (-loc
+ 7) & -8; // stack must stay aligned to 8 bytes for LDDW instr
2049 C67_NOP(4); // NOP wait for load
2050 C67_IREG_B_REG(0, C67_CREG_ZERO
, C67_B3
); // B.S2 B3
2052 C67_ADDK(local
, C67_SP
); // ADDK.L2 loc,SP
2053 C67_Adjust_ADDK((int *) (cur_text_section
->data
+
2054 func_sub_sp_offset
),
2055 -local
+ TotalBytesPushedOnStack
);
2060 /* generate a jump to a label */
2065 C67_MVKL(C67_A0
, t
); //r=reg to load, constant
2066 C67_MVKH(C67_A0
, t
); //r=reg to load, constant
2067 C67_IREG_B_REG(0, C67_CREG_ZERO
, C67_A0
); // [!R] B.S2x A0
2072 /* generate a jump to a fixed address */
2073 void gjmp_addr(int a
)
2076 // I guess this routine is used for relative short
2077 // local jumps, for now just handle it as the general
2080 // define a label that will be relocated
2082 sym
= get_sym_ref(&char_pointer_type
, cur_text_section
, a
, 0);
2083 greloc(cur_text_section
, sym
, ind
, R_C60LO16
);
2084 greloc(cur_text_section
, sym
, ind
+ 4, R_C60HI16
);
2086 gjmp(0); // place a zero there later the symbol will be added to it
2089 /* generate a test. set 'inv' to invert test. Stack entry is popped */
2090 int gtst(int inv
, int t
)
2095 v
= vtop
->r
& VT_VALMASK
;
2097 /* fast case : can jump directly since flags are set */
2098 // C67 uses B2 sort of as flags register
2100 C67_MVKL(C67_A0
, t
); //r=reg to load, constant
2101 C67_MVKH(C67_A0
, t
); //r=reg to load, constant
2103 if (C67_compare_reg
!= TREG_EAX
&& // check if not already in a conditional test reg
2104 C67_compare_reg
!= TREG_EDX
&&
2105 C67_compare_reg
!= TREG_ST0
&& C67_compare_reg
!= C67_B2
) {
2106 C67_MV(C67_compare_reg
, C67_B2
);
2107 C67_compare_reg
= C67_B2
;
2110 C67_IREG_B_REG(C67_invert_test
^ inv
, C67_compare_reg
, C67_A0
); // [!R] B.S2x A0
2112 t
= ind1
; //return where we need to patch
2114 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
2115 /* && or || optimization */
2116 if ((v
& 1) == inv
) {
2117 /* insert vtop->c jump list in t */
2120 // I guess the idea is to traverse to the
2121 // null at the end of the list and store t
2126 p
= (int *) (cur_text_section
->data
+ n
);
2128 // extract 32 bit address from MVKH/MVKL
2129 n
= ((*p
>> 7) & 0xffff);
2130 n
|= ((*(p
+ 1) >> 7) & 0xffff) << 16;
2132 *p
|= (t
& 0xffff) << 7;
2133 *(p
+ 1) |= ((t
>> 16) & 0xffff) << 7;
2145 /* generate an integer binary operation */
2146 void gen_opi(int op
)
2152 case TOK_ADDC1
: /* add with carry generation */
2157 // C67 can't do const compares, must load into a reg
2158 // so just go to gv2 directly - tktk
2162 if (op
>= TOK_ULT
&& op
<= TOK_GT
)
2163 gv2(RC_INT_BSIDE
, RC_INT
); // make sure r (src1) is on the B Side of CPU
2165 gv2(RC_INT
, RC_INT
);
2170 C67_compare_reg
= C67_B2
;
2174 C67_CMPLT(r
, fr
, C67_B2
);
2175 C67_invert_test
= FALSE
;
2176 } else if (op
== TOK_GE
) {
2177 C67_CMPLT(r
, fr
, C67_B2
);
2178 C67_invert_test
= TRUE
;
2179 } else if (op
== TOK_GT
) {
2180 C67_CMPGT(r
, fr
, C67_B2
);
2181 C67_invert_test
= FALSE
;
2182 } else if (op
== TOK_LE
) {
2183 C67_CMPGT(r
, fr
, C67_B2
);
2184 C67_invert_test
= TRUE
;
2185 } else if (op
== TOK_EQ
) {
2186 C67_CMPEQ(r
, fr
, C67_B2
);
2187 C67_invert_test
= FALSE
;
2188 } else if (op
== TOK_NE
) {
2189 C67_CMPEQ(r
, fr
, C67_B2
);
2190 C67_invert_test
= TRUE
;
2191 } else if (op
== TOK_ULT
) {
2192 C67_CMPLTU(r
, fr
, C67_B2
);
2193 C67_invert_test
= FALSE
;
2194 } else if (op
== TOK_UGE
) {
2195 C67_CMPLTU(r
, fr
, C67_B2
);
2196 C67_invert_test
= TRUE
;
2197 } else if (op
== TOK_UGT
) {
2198 C67_CMPGTU(r
, fr
, C67_B2
);
2199 C67_invert_test
= FALSE
;
2200 } else if (op
== TOK_ULE
) {
2201 C67_CMPGTU(r
, fr
, C67_B2
);
2202 C67_invert_test
= TRUE
;
2203 } else if (op
== '+')
2204 C67_ADD(fr
, r
); // ADD r,fr,r
2206 C67_SUB(fr
, r
); // SUB r,fr,r
2208 C67_AND(fr
, r
); // AND r,fr,r
2210 C67_OR(fr
, r
); // OR r,fr,r
2212 C67_XOR(fr
, r
); // XOR r,fr,r
2214 ALWAYS_ASSERT(FALSE
);
2217 if (op
>= TOK_ULT
&& op
<= TOK_GT
) {
2223 case TOK_SUBC1
: /* sub with carry generation */
2226 case TOK_ADDC2
: /* add with carry use */
2229 case TOK_SUBC2
: /* sub with carry use */
2243 gv2(RC_INT
, RC_INT
);
2247 C67_MPYI(fr
, r
); // 32 bit bultiply fr,r,fr
2248 C67_NOP(8); // NOP 8 for worst case
2251 gv2(RC_INT_BSIDE
, RC_INT_BSIDE
); // shift amount must be on same side as dst
2255 C67_SHL(fr
, r
); // arithmetic/logical shift
2259 gv2(RC_INT_BSIDE
, RC_INT_BSIDE
); // shift amount must be on same side as dst
2263 C67_SHRU(fr
, r
); // logical shift
2267 gv2(RC_INT_BSIDE
, RC_INT_BSIDE
); // shift amount must be on same side as dst
2271 C67_SHR(fr
, r
); // arithmetic shift
2278 /* call generic idiv function */
2279 vpush_global_sym(&func_old_type
, t
);
2284 vtop
->r2
= VT_CONST
;
2303 /* generate a floating point operation 'v = t1 op t2' instruction. The
2304 two operands are guaranted to have the same floating point type */
2305 /* XXX: need to use ST1 too */
2306 void gen_opf(int op
)
2310 if (op
>= TOK_ULT
&& op
<= TOK_GT
)
2311 gv2(RC_EDX
, RC_EAX
); // make sure src2 is on b side
2313 gv2(RC_FLOAT
, RC_FLOAT
); // make sure src2 is on b side
2321 if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
2322 tcc_error("long doubles not supported");
2324 if (op
>= TOK_ULT
&& op
<= TOK_GT
) {
2329 C67_compare_reg
= C67_B2
;
2332 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
2333 C67_CMPLTDP(r
, fr
, C67_B2
);
2335 C67_CMPLTSP(r
, fr
, C67_B2
);
2337 C67_invert_test
= FALSE
;
2338 } else if (op
== TOK_GE
) {
2339 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
2340 C67_CMPLTDP(r
, fr
, C67_B2
);
2342 C67_CMPLTSP(r
, fr
, C67_B2
);
2344 C67_invert_test
= TRUE
;
2345 } else if (op
== TOK_GT
) {
2346 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
2347 C67_CMPGTDP(r
, fr
, C67_B2
);
2349 C67_CMPGTSP(r
, fr
, C67_B2
);
2351 C67_invert_test
= FALSE
;
2352 } else if (op
== TOK_LE
) {
2353 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
2354 C67_CMPGTDP(r
, fr
, C67_B2
);
2356 C67_CMPGTSP(r
, fr
, C67_B2
);
2358 C67_invert_test
= TRUE
;
2359 } else if (op
== TOK_EQ
) {
2360 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
2361 C67_CMPEQDP(r
, fr
, C67_B2
);
2363 C67_CMPEQSP(r
, fr
, C67_B2
);
2365 C67_invert_test
= FALSE
;
2366 } else if (op
== TOK_NE
) {
2367 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
2368 C67_CMPEQDP(r
, fr
, C67_B2
);
2370 C67_CMPEQSP(r
, fr
, C67_B2
);
2372 C67_invert_test
= TRUE
;
2374 ALWAYS_ASSERT(FALSE
);
2376 vtop
->r
= VT_CMP
; // tell TCC that result is in "flags" actually B2
2379 if ((ft
& VT_BTYPE
) == VT_DOUBLE
) {
2380 C67_ADDDP(r
, fr
); // ADD fr,r,fr
2383 C67_ADDSP(r
, fr
); // ADD fr,r,fr
2387 } else if (op
== '-') {
2388 if ((ft
& VT_BTYPE
) == VT_DOUBLE
) {
2389 C67_SUBDP(r
, fr
); // SUB fr,r,fr
2392 C67_SUBSP(r
, fr
); // SUB fr,r,fr
2396 } else if (op
== '*') {
2397 if ((ft
& VT_BTYPE
) == VT_DOUBLE
) {
2398 C67_MPYDP(r
, fr
); // MPY fr,r,fr
2401 C67_MPYSP(r
, fr
); // MPY fr,r,fr
2405 } else if (op
== '/') {
2406 if ((ft
& VT_BTYPE
) == VT_DOUBLE
) {
2407 // must call intrinsic DP floating point divide
2409 /* call generic idiv function */
2410 vpush_global_sym(&func_old_type
, TOK__divd
);
2415 vtop
->r2
= REG_LRET
;
2418 // must call intrinsic SP floating point divide
2420 /* call generic idiv function */
2421 vpush_global_sym(&func_old_type
, TOK__divf
);
2426 vtop
->r2
= VT_CONST
;
2429 ALWAYS_ASSERT(FALSE
);
2436 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
2437 and 'long long' cases. */
2438 void gen_cvt_itof(int t
)
2445 if ((t
& VT_BTYPE
) == VT_DOUBLE
) {
2446 if (t
& VT_UNSIGNED
)
2452 vtop
->type
.t
= VT_DOUBLE
;
2454 if (t
& VT_UNSIGNED
)
2459 vtop
->type
.t
= VT_FLOAT
;
2464 /* convert fp to int 't' type */
2465 /* XXX: handle long long case */
2466 void gen_cvt_ftoi(int t
)
2474 tcc_error("long long not supported");
2476 if ((vtop
->type
.t
& VT_BTYPE
) == VT_DOUBLE
) {
2484 vtop
->type
.t
= VT_INT
;
2489 /* convert from one floating point type to another */
2490 void gen_cvt_ftof(int t
)
2494 if ((vtop
->type
.t
& VT_BTYPE
) == VT_DOUBLE
&&
2495 (t
& VT_BTYPE
) == VT_FLOAT
) {
2496 // convert double to float
2498 gv(RC_FLOAT
); // get it in a register pair
2502 C67_DPSP(r
, r
); // convert it to SP same register
2505 vtop
->type
.t
= VT_FLOAT
;
2506 vtop
->r2
= VT_CONST
; // set this as unused
2507 } else if ((vtop
->type
.t
& VT_BTYPE
) == VT_FLOAT
&&
2508 (t
& VT_BTYPE
) == VT_DOUBLE
) {
2509 // convert float to double
2511 gv(RC_FLOAT
); // get it in a register
2515 if (r
== TREG_EAX
) { // make sure the paired reg is avail
2516 r2
= get_reg(RC_ECX
);
2517 } else if (r
== TREG_EDX
) {
2518 r2
= get_reg(RC_ST0
);
2520 ALWAYS_ASSERT(FALSE
);
2521 r2
= 0; /* avoid warning */
2524 C67_SPDP(r
, r
); // convert it to DP same register
2527 vtop
->type
.t
= VT_DOUBLE
;
2528 vtop
->r2
= r2
; // set this as unused
2530 ALWAYS_ASSERT(FALSE
);
2534 /* computed goto support */
2541 /* Save the stack pointer onto the stack and return the location of its address */
2542 ST_FUNC
void gen_vla_sp_save(int addr
) {
2543 tcc_error("variable length arrays unsupported for this target");
2546 /* Restore the SP from a location on the stack */
2547 ST_FUNC
void gen_vla_sp_restore(int addr
) {
2548 tcc_error("variable length arrays unsupported for this target");
2551 /* Subtract from the stack pointer, and push the resulting value onto the stack */
2552 ST_FUNC
void gen_vla_alloc(CType
*type
, int align
) {
2553 tcc_error("variable length arrays unsupported for this target");
2556 /* end of C67 code generator */
2557 /*************************************************************/
2559 /*************************************************************/