Relicensing TinyCC
[tinycc.git] / c67-gen.c
1 /*
2  *  TMS320C67xx code generator for TCC
3  * 
4  *  Copyright (c) 2001, 2002 Fabrice Bellard
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #ifdef TARGET_DEFS_ONLY
22
23 /* #define ASSEMBLY_LISTING_C67 */
24
25 /* number of available registers */
26 #define NB_REGS            24
27
28 /* a register can belong to several classes. The classes must be
29    sorted from more general to more precise (see gv2() code which does
30    assumptions on it). */
31 #define RC_INT     0x0001       /* generic integer register */
32 #define RC_FLOAT   0x0002       /* generic float register */
33 #define RC_EAX     0x0004
34 #define RC_ST0     0x0008
35 #define RC_ECX     0x0010
36 #define RC_EDX     0x0020
37 #define RC_INT_BSIDE  0x00000040        /* generic integer register  on b side */
38 #define RC_C67_A4     0x00000100
39 #define RC_C67_A5     0x00000200
40 #define RC_C67_B4     0x00000400
41 #define RC_C67_B5     0x00000800
42 #define RC_C67_A6     0x00001000
43 #define RC_C67_A7     0x00002000
44 #define RC_C67_B6     0x00004000
45 #define RC_C67_B7     0x00008000
46 #define RC_C67_A8     0x00010000
47 #define RC_C67_A9     0x00020000
48 #define RC_C67_B8     0x00040000
49 #define RC_C67_B9     0x00080000
50 #define RC_C67_A10    0x00100000
51 #define RC_C67_A11    0x00200000
52 #define RC_C67_B10    0x00400000
53 #define RC_C67_B11    0x00800000
54 #define RC_C67_A12    0x01000000
55 #define RC_C67_A13    0x02000000
56 #define RC_C67_B12    0x04000000
57 #define RC_C67_B13    0x08000000
58 #define RC_IRET    RC_C67_A4    /* function return: integer register */
59 #define RC_LRET    RC_C67_A5    /* function return: second integer register */
60 #define RC_FRET    RC_C67_A4    /* function return: float register */
61
62 /* pretty names for the registers */
63 enum {
64     TREG_EAX = 0,               // really A2
65     TREG_ECX,                   // really A3
66     TREG_EDX,                   // really B0
67     TREG_ST0,                   // really B1
68     TREG_C67_A4,
69     TREG_C67_A5,
70     TREG_C67_B4,
71     TREG_C67_B5,
72     TREG_C67_A6,
73     TREG_C67_A7,
74     TREG_C67_B6,
75     TREG_C67_B7,
76     TREG_C67_A8,
77     TREG_C67_A9,
78     TREG_C67_B8,
79     TREG_C67_B9,
80     TREG_C67_A10,
81     TREG_C67_A11,
82     TREG_C67_B10,
83     TREG_C67_B11,
84     TREG_C67_A12,
85     TREG_C67_A13,
86     TREG_C67_B12,
87     TREG_C67_B13,
88 };
89
90 /* return registers for function */
91 #define REG_IRET TREG_C67_A4    /* single word int return register */
92 #define REG_LRET TREG_C67_A5    /* second word return register (for long long) */
93 #define REG_FRET TREG_C67_A4    /* float return register */
94
95 /* defined if function parameters must be evaluated in reverse order */
96 /* #define INVERT_FUNC_PARAMS */
97
98 /* defined if structures are passed as pointers. Otherwise structures
99    are directly pushed on stack. */
100 /* #define FUNC_STRUCT_PARAM_AS_PTR */
101
102 /* pointer size, in bytes */
103 #define PTR_SIZE 4
104
105 /* long double size and alignment, in bytes */
106 #define LDOUBLE_SIZE  12
107 #define LDOUBLE_ALIGN 4
108 /* maximum alignment (for aligned attribute support) */
109 #define MAX_ALIGN     8
110
111 /******************************************************/
112 /* ELF defines */
113
114 #define EM_TCC_TARGET EM_C60
115
116 /* relocation type for 32 bit data relocation */
117 #define R_DATA_32   R_C60_32
118 #define R_DATA_PTR  R_C60_32
119 #define R_JMP_SLOT  R_C60_JMP_SLOT
120 #define R_COPY      R_C60_COPY
121
122 #define ELF_START_ADDR 0x00000400
123 #define ELF_PAGE_SIZE  0x1000
124
125 /******************************************************/
126 #else /* ! TARGET_DEFS_ONLY */
127 /******************************************************/
128 #include "tcc.h"
129
130 ST_DATA const int reg_classes[NB_REGS] = {
131     /* eax */ RC_INT | RC_FLOAT | RC_EAX, 
132     // only allow even regs for floats (allow for doubles)
133     /* ecx */ RC_INT | RC_ECX,
134     /* edx */ RC_INT | RC_INT_BSIDE | RC_FLOAT | RC_EDX,
135     // only allow even regs for floats (allow for doubles)
136     /* st0 */ RC_INT | RC_INT_BSIDE | RC_ST0,
137     /* A4  */ RC_C67_A4,
138     /* A5  */ RC_C67_A5,
139     /* B4  */ RC_C67_B4,
140     /* B5  */ RC_C67_B5,
141     /* A6  */ RC_C67_A6,
142     /* A7  */ RC_C67_A7,
143     /* B6  */ RC_C67_B6,
144     /* B7  */ RC_C67_B7,
145     /* A8  */ RC_C67_A8,
146     /* A9  */ RC_C67_A9,
147     /* B8  */ RC_C67_B8,
148     /* B9  */ RC_C67_B9,
149     /* A10  */ RC_C67_A10,
150     /* A11  */ RC_C67_A11,
151     /* B10  */ RC_C67_B10,
152     /* B11  */ RC_C67_B11,
153     /* A12  */ RC_C67_A10,
154     /* A13  */ RC_C67_A11,
155     /* B12  */ RC_C67_B10,
156     /* B13  */ RC_C67_B11
157 };
158
159 // although tcc thinks it is passing parameters on the stack,
160 // the C67 really passes up to the first 10 params in special
161 // regs or regs pairs (for 64 bit params).  So keep track of
162 // the stack offsets so we can translate to the appropriate 
163 // reg (pair)
164
165 #define NoCallArgsPassedOnStack 10
166 int NoOfCurFuncArgs;
167 int TranslateStackToReg[NoCallArgsPassedOnStack];
168 int ParamLocOnStack[NoCallArgsPassedOnStack];
169 int TotalBytesPushedOnStack;
170
171 #ifndef FALSE
172 # define FALSE 0
173 # define TRUE 1
174 #endif
175
176 #undef BOOL
177 #define BOOL int
178
179 #define ALWAYS_ASSERT(x) \
180 do {\
181    if (!(x))\
182        tcc_error("internal compiler error file at %s:%d", __FILE__, __LINE__);\
183 } while (0)
184
185 /******************************************************/
186 static unsigned long func_sub_sp_offset;
187 static int func_ret_sub;
188
189 static BOOL C67_invert_test;
190 static int C67_compare_reg;
191
192 #ifdef ASSEMBLY_LISTING_C67
193 FILE *f = NULL;
194 #endif
195
196 void C67_g(int c)
197 {
198     int ind1;
199
200 #ifdef ASSEMBLY_LISTING_C67
201     fprintf(f, " %08X", c);
202 #endif
203     ind1 = ind + 4;
204     if (ind1 > (int) cur_text_section->data_allocated)
205         section_realloc(cur_text_section, ind1);
206     cur_text_section->data[ind] = c & 0xff;
207     cur_text_section->data[ind + 1] = (c >> 8) & 0xff;
208     cur_text_section->data[ind + 2] = (c >> 16) & 0xff;
209     cur_text_section->data[ind + 3] = (c >> 24) & 0xff;
210     ind = ind1;
211 }
212
213
214 /* output a symbol and patch all calls to it */
215 void gsym_addr(int t, int a)
216 {
217     int n, *ptr;
218     while (t) {
219         ptr = (int *) (cur_text_section->data + t);
220         {
221             Sym *sym;
222
223             // extract 32 bit address from MVKH/MVKL
224             n = ((*ptr >> 7) & 0xffff);
225             n |= ((*(ptr + 1) >> 7) & 0xffff) << 16;
226
227             // define a label that will be relocated
228
229             sym = get_sym_ref(&char_pointer_type, cur_text_section, a, 0);
230             greloc(cur_text_section, sym, t, R_C60LO16);
231             greloc(cur_text_section, sym, t + 4, R_C60HI16);
232
233             // clear out where the pointer was
234
235             *ptr &= ~(0xffff << 7);
236             *(ptr + 1) &= ~(0xffff << 7);
237         }
238         t = n;
239     }
240 }
241
242 void gsym(int t)
243 {
244     gsym_addr(t, ind);
245 }
246
247 // these are regs that tcc doesn't really know about, 
248 // but asign them unique values so the mapping routines
249 // can distinquish them
250
251 #define C67_A0 105
252 #define C67_SP 106
253 #define C67_B3 107
254 #define C67_FP 108
255 #define C67_B2 109
256 #define C67_CREG_ZERO -1        /* Special code for no condition reg test */
257
258
259 int ConvertRegToRegClass(int r)
260 {
261     // only works for A4-B13
262
263     return RC_C67_A4 << (r - TREG_C67_A4);
264 }
265
266
267 // map TCC reg to C67 reg number
268
269 int C67_map_regn(int r)
270 {
271     if (r == 0)                 // normal tcc regs
272         return 0x2;             // A2
273     else if (r == 1)            // normal tcc regs
274         return 3;               // A3
275     else if (r == 2)            // normal tcc regs
276         return 0;               // B0
277     else if (r == 3)            // normal tcc regs
278         return 1;               // B1
279     else if (r >= TREG_C67_A4 && r <= TREG_C67_B13)     // these form a pattern of alt pairs
280         return (((r & 0xfffffffc) >> 1) | (r & 1)) + 2;
281     else if (r == C67_A0)
282         return 0;               // set to A0 (offset reg)
283     else if (r == C67_B2)
284         return 2;               // set to B2 (offset reg)
285     else if (r == C67_B3)
286         return 3;               // set to B3 (return address reg)
287     else if (r == C67_SP)
288         return 15;              // set to SP (B15) (offset reg)
289     else if (r == C67_FP)
290         return 15;              // set to FP (A15) (offset reg)
291     else if (r == C67_CREG_ZERO)
292         return 0;               // Special code for no condition reg test
293     else
294         ALWAYS_ASSERT(FALSE);
295
296     return 0;
297 }
298
299 // mapping from tcc reg number to 
300 // C67 register to condition code field
301 //
302 // valid condition code regs are:
303 //
304 // tcc reg 2 ->B0 -> 1
305 // tcc reg 3 ->B1 -> 2
306 // tcc reg 0 -> A2 -> 5
307 // tcc reg 1 -> A3 -> X
308 // tcc reg      B2 -> 3
309
310 int C67_map_regc(int r)
311 {
312     if (r == 0)                 // normal tcc regs
313         return 0x5;
314     else if (r == 2)            // normal tcc regs
315         return 0x1;
316     else if (r == 3)            // normal tcc regs
317         return 0x2;
318     else if (r == C67_B2)       // normal tcc regs
319         return 0x3;
320     else if (r == C67_CREG_ZERO)
321         return 0;               // Special code for no condition reg test
322     else
323         ALWAYS_ASSERT(FALSE);
324
325     return 0;
326 }
327
328
329 // map TCC reg to C67 reg side A or B
330
331 int C67_map_regs(int r)
332 {
333     if (r == 0)                 // normal tcc regs
334         return 0x0;
335     else if (r == 1)            // normal tcc regs
336         return 0x0;
337     else if (r == 2)            // normal tcc regs
338         return 0x1;
339     else if (r == 3)            // normal tcc regs
340         return 0x1;
341     else if (r >= TREG_C67_A4 && r <= TREG_C67_B13)     // these form a pattern of alt pairs
342         return (r & 2) >> 1;
343     else if (r == C67_A0)
344         return 0;               // set to A side 
345     else if (r == C67_B2)
346         return 1;               // set to B side 
347     else if (r == C67_B3)
348         return 1;               // set to B side
349     else if (r == C67_SP)
350         return 0x1;             // set to SP (B15) B side 
351     else if (r == C67_FP)
352         return 0x0;             // set to FP (A15) A side 
353     else
354         ALWAYS_ASSERT(FALSE);
355
356     return 0;
357 }
358
359 int C67_map_S12(char *s)
360 {
361     if (strstr(s, ".S1") != NULL)
362         return 0;
363     else if (strcmp(s, ".S2"))
364         return 1;
365     else
366         ALWAYS_ASSERT(FALSE);
367
368     return 0;
369 }
370
371 int C67_map_D12(char *s)
372 {
373     if (strstr(s, ".D1") != NULL)
374         return 0;
375     else if (strcmp(s, ".D2"))
376         return 1;
377     else
378         ALWAYS_ASSERT(FALSE);
379
380     return 0;
381 }
382
383
384
385 void C67_asm(char *s, int a, int b, int c)
386 {
387     BOOL xpath;
388
389 #ifdef ASSEMBLY_LISTING_C67
390     if (!f) {
391         f = fopen("TCC67_out.txt", "wt");
392     }
393     fprintf(f, "%04X ", ind);
394 #endif
395
396     if (strstr(s, "MVKL") == s) {
397         C67_g((C67_map_regn(b) << 23) |
398               ((a & 0xffff) << 7) | (0x0a << 2) | (C67_map_regs(b) << 1));
399     } else if (strstr(s, "MVKH") == s) {
400         C67_g((C67_map_regn(b) << 23) |
401               (((a >> 16) & 0xffff) << 7) |
402               (0x1a << 2) | (C67_map_regs(b) << 1));
403     } else if (strstr(s, "STW.D SP POST DEC") == s) {
404         C67_g((C67_map_regn(a) << 23) | //src
405               (15 << 18) |      //SP B15
406               (2 << 13) |       //ucst5 (must keep 8 byte boundary !!)
407               (0xa << 9) |      //mode a = post dec ucst
408               (0 << 8) |        //r (LDDW bit 0)
409               (1 << 7) |        //y D1/D2 use B side
410               (7 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
411               (1 << 2) |        //opcode
412               (C67_map_regs(a) << 1) |  //side of src
413               (0 << 0));        //parallel
414     } else if (strstr(s, "STB.D *+SP[A0]") == s) {
415         C67_g((C67_map_regn(a) << 23) | //src
416               (15 << 18) |      //base reg A15
417               (0 << 13) |       //offset reg A0
418               (5 << 9) |        //mode 5 = pos offset, base reg + off reg
419               (0 << 8) |        //r (LDDW bit 0)
420               (0 << 7) |        //y D1/D2 A side
421               (3 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
422               (1 << 2) |        //opcode
423               (C67_map_regs(a) << 1) |  //side of src
424               (0 << 0));        //parallel
425     } else if (strstr(s, "STH.D *+SP[A0]") == s) {
426         C67_g((C67_map_regn(a) << 23) | //src
427               (15 << 18) |      //base reg A15
428               (0 << 13) |       //offset reg A0
429               (5 << 9) |        //mode 5 = pos offset, base reg + off reg
430               (0 << 8) |        //r (LDDW bit 0)
431               (0 << 7) |        //y D1/D2 A side
432               (5 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
433               (1 << 2) |        //opcode
434               (C67_map_regs(a) << 1) |  //side of src
435               (0 << 0));        //parallel
436     } else if (strstr(s, "STB.D *+SP[A0]") == s) {
437         C67_g((C67_map_regn(a) << 23) | //src
438               (15 << 18) |      //base reg A15
439               (0 << 13) |       //offset reg A0
440               (5 << 9) |        //mode 5 = pos offset, base reg + off reg
441               (0 << 8) |        //r (LDDW bit 0)
442               (0 << 7) |        //y D1/D2 A side
443               (3 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
444               (1 << 2) |        //opcode
445               (C67_map_regs(a) << 1) |  //side of src
446               (0 << 0));        //parallel
447     } else if (strstr(s, "STH.D *+SP[A0]") == s) {
448         C67_g((C67_map_regn(a) << 23) | //src
449               (15 << 18) |      //base reg A15
450               (0 << 13) |       //offset reg A0
451               (5 << 9) |        //mode 5 = pos offset, base reg + off reg
452               (0 << 8) |        //r (LDDW bit 0)
453               (0 << 7) |        //y D1/D2 A side
454               (5 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
455               (1 << 2) |        //opcode
456               (C67_map_regs(a) << 1) |  //side of src
457               (0 << 0));        //parallel
458     } else if (strstr(s, "STW.D *+SP[A0]") == s) {
459         C67_g((C67_map_regn(a) << 23) | //src
460               (15 << 18) |      //base reg A15
461               (0 << 13) |       //offset reg A0
462               (5 << 9) |        //mode 5 = pos offset, base reg + off reg
463               (0 << 8) |        //r (LDDW bit 0)
464               (0 << 7) |        //y D1/D2 A side
465               (7 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
466               (1 << 2) |        //opcode
467               (C67_map_regs(a) << 1) |  //side of src
468               (0 << 0));        //parallel
469     } else if (strstr(s, "STW.D *") == s) {
470         C67_g((C67_map_regn(a) << 23) | //src
471               (C67_map_regn(b) << 18) | //base reg A0
472               (0 << 13) |       //cst5
473               (1 << 9) |        //mode 1 = pos cst offset
474               (0 << 8) |        //r (LDDW bit 0)
475               (C67_map_regs(b) << 7) |  //y D1/D2 base reg side
476               (7 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
477               (1 << 2) |        //opcode
478               (C67_map_regs(a) << 1) |  //side of src
479               (0 << 0));        //parallel
480     } else if (strstr(s, "STH.D *") == s) {
481         C67_g((C67_map_regn(a) << 23) | //src
482               (C67_map_regn(b) << 18) | //base reg A0
483               (0 << 13) |       //cst5
484               (1 << 9) |        //mode 1 = pos cst offset
485               (0 << 8) |        //r (LDDW bit 0)
486               (C67_map_regs(b) << 7) |  //y D1/D2 base reg side
487               (5 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
488               (1 << 2) |        //opcode
489               (C67_map_regs(a) << 1) |  //side of src
490               (0 << 0));        //parallel
491     } else if (strstr(s, "STB.D *") == s) {
492         C67_g((C67_map_regn(a) << 23) | //src
493               (C67_map_regn(b) << 18) | //base reg A0
494               (0 << 13) |       //cst5
495               (1 << 9) |        //mode 1 = pos cst offset
496               (0 << 8) |        //r (LDDW bit 0)
497               (C67_map_regs(b) << 7) |  //y D1/D2 base reg side
498               (3 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
499               (1 << 2) |        //opcode
500               (C67_map_regs(a) << 1) |  //side of src
501               (0 << 0));        //parallel
502     } else if (strstr(s, "STW.D +*") == s) {
503         ALWAYS_ASSERT(c < 32);
504         C67_g((C67_map_regn(a) << 23) | //src
505               (C67_map_regn(b) << 18) | //base reg A0
506               (c << 13) |       //cst5
507               (1 << 9) |        //mode 1 = pos cst offset
508               (0 << 8) |        //r (LDDW bit 0)
509               (C67_map_regs(b) << 7) |  //y D1/D2 base reg side
510               (7 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
511               (1 << 2) |        //opcode
512               (C67_map_regs(a) << 1) |  //side of src
513               (0 << 0));        //parallel
514     } else if (strstr(s, "LDW.D SP PRE INC") == s) {
515         C67_g((C67_map_regn(a) << 23) | //dst
516               (15 << 18) |      //base reg B15
517               (2 << 13) |       //ucst5 (must keep 8 byte boundary)
518               (9 << 9) |        //mode 9 = pre inc ucst5
519               (0 << 8) |        //r (LDDW bit 0)
520               (1 << 7) |        //y D1/D2  B side
521               (6 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
522               (1 << 2) |        //opcode
523               (C67_map_regs(a) << 1) |  //side of dst
524               (0 << 0));        //parallel
525     } else if (strstr(s, "LDDW.D SP PRE INC") == s) {
526         C67_g((C67_map_regn(a) << 23) | //dst
527               (15 << 18) |      //base reg B15
528               (1 << 13) |       //ucst5 (must keep 8 byte boundary)
529               (9 << 9) |        //mode 9 = pre inc ucst5
530               (1 << 8) |        //r (LDDW bit 1)
531               (1 << 7) |        //y D1/D2  B side
532               (6 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
533               (1 << 2) |        //opcode
534               (C67_map_regs(a) << 1) |  //side of dst
535               (0 << 0));        //parallel
536     } else if (strstr(s, "LDW.D *+SP[A0]") == s) {
537         C67_g((C67_map_regn(a) << 23) | //dst
538               (15 << 18) |      //base reg A15
539               (0 << 13) |       //offset reg A0
540               (5 << 9) |        //mode 5 = pos offset, base reg + off reg
541               (0 << 8) |        //r (LDDW bit 0)
542               (0 << 7) |        //y D1/D2  A side
543               (6 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
544               (1 << 2) |        //opcode
545               (C67_map_regs(a) << 1) |  //side of dst
546               (0 << 0));        //parallel
547     } else if (strstr(s, "LDDW.D *+SP[A0]") == s) {
548         C67_g((C67_map_regn(a) << 23) | //dst
549               (15 << 18) |      //base reg A15
550               (0 << 13) |       //offset reg A0
551               (5 << 9) |        //mode 5 = pos offset, base reg + off reg
552               (1 << 8) |        //r (LDDW bit 1)
553               (0 << 7) |        //y D1/D2  A side
554               (6 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
555               (1 << 2) |        //opcode
556               (C67_map_regs(a) << 1) |  //side of dst
557               (0 << 0));        //parallel
558     } else if (strstr(s, "LDH.D *+SP[A0]") == s) {
559         C67_g((C67_map_regn(a) << 23) | //dst
560               (15 << 18) |      //base reg A15
561               (0 << 13) |       //offset reg A0
562               (5 << 9) |        //mode 5 = pos offset, base reg + off reg
563               (0 << 8) |        //r (LDDW bit 0)
564               (0 << 7) |        //y D1/D2  A side
565               (4 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
566               (1 << 2) |        //opcode
567               (C67_map_regs(a) << 1) |  //side of dst
568               (0 << 0));        //parallel
569     } else if (strstr(s, "LDB.D *+SP[A0]") == s) {
570         C67_g((C67_map_regn(a) << 23) | //dst
571               (15 << 18) |      //base reg A15
572               (0 << 13) |       //offset reg A0
573               (5 << 9) |        //mode 5 = pos offset, base reg + off reg
574               (0 << 8) |        //r (LDDW bit 0)
575               (0 << 7) |        //y D1/D2  A side
576               (2 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
577               (1 << 2) |        //opcode
578               (C67_map_regs(a) << 1) |  //side of dst
579               (0 << 0));        //parallel
580     } else if (strstr(s, "LDHU.D *+SP[A0]") == s) {
581         C67_g((C67_map_regn(a) << 23) | //dst
582               (15 << 18) |      //base reg A15
583               (0 << 13) |       //offset reg A0
584               (5 << 9) |        //mode 5 = pos offset, base reg + off reg
585               (0 << 8) |        //r (LDDW bit 0)
586               (0 << 7) |        //y D1/D2  A side
587               (0 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
588               (1 << 2) |        //opcode
589               (C67_map_regs(a) << 1) |  //side of dst
590               (0 << 0));        //parallel
591     } else if (strstr(s, "LDBU.D *+SP[A0]") == s) {
592         C67_g((C67_map_regn(a) << 23) | //dst
593               (15 << 18) |      //base reg A15
594               (0 << 13) |       //offset reg A0
595               (5 << 9) |        //mode 5 = pos offset, base reg + off reg
596               (0 << 8) |        //r (LDDW bit 0)
597               (0 << 7) |        //y D1/D2  A side
598               (1 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
599               (1 << 2) |        //opcode
600               (C67_map_regs(a) << 1) |  //side of dst
601               (0 << 0));        //parallel
602     } else if (strstr(s, "LDW.D *") == s) {
603         C67_g((C67_map_regn(b) << 23) | //dst
604               (C67_map_regn(a) << 18) | //base reg A15
605               (0 << 13) |       //cst5
606               (1 << 9) |        //mode 1 = pos cst offset
607               (0 << 8) |        //r (LDDW bit 0)
608               (C67_map_regs(a) << 7) |  //y D1/D2  src side
609               (6 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
610               (1 << 2) |        //opcode
611               (C67_map_regs(b) << 1) |  //side of dst
612               (0 << 0));        //parallel
613     } else if (strstr(s, "LDDW.D *") == s) {
614         C67_g((C67_map_regn(b) << 23) | //dst
615               (C67_map_regn(a) << 18) | //base reg A15
616               (0 << 13) |       //cst5
617               (1 << 9) |        //mode 1 = pos cst offset
618               (1 << 8) |        //r (LDDW bit 1)
619               (C67_map_regs(a) << 7) |  //y D1/D2  src side
620               (6 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
621               (1 << 2) |        //opcode
622               (C67_map_regs(b) << 1) |  //side of dst
623               (0 << 0));        //parallel
624     } else if (strstr(s, "LDH.D *") == s) {
625         C67_g((C67_map_regn(b) << 23) | //dst
626               (C67_map_regn(a) << 18) | //base reg A15
627               (0 << 13) |       //cst5
628               (1 << 9) |        //mode 1 = pos cst offset
629               (0 << 8) |        //r (LDDW bit 0)
630               (C67_map_regs(a) << 7) |  //y D1/D2  src side
631               (4 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
632               (1 << 2) |        //opcode
633               (C67_map_regs(b) << 1) |  //side of dst
634               (0 << 0));        //parallel
635     } else if (strstr(s, "LDB.D *") == s) {
636         C67_g((C67_map_regn(b) << 23) | //dst
637               (C67_map_regn(a) << 18) | //base reg A15
638               (0 << 13) |       //cst5
639               (1 << 9) |        //mode 1 = pos cst offset
640               (0 << 8) |        //r (LDDW bit 0)
641               (C67_map_regs(a) << 7) |  //y D1/D2  src side
642               (2 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
643               (1 << 2) |        //opcode
644               (C67_map_regs(b) << 1) |  //side of dst
645               (0 << 0));        //parallel
646     } else if (strstr(s, "LDHU.D *") == s) {
647         C67_g((C67_map_regn(b) << 23) | //dst
648               (C67_map_regn(a) << 18) | //base reg A15
649               (0 << 13) |       //cst5
650               (1 << 9) |        //mode 1 = pos cst offset
651               (0 << 8) |        //r (LDDW bit 0)
652               (C67_map_regs(a) << 7) |  //y D1/D2  src side
653               (0 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
654               (1 << 2) |        //opcode
655               (C67_map_regs(b) << 1) |  //side of dst
656               (0 << 0));        //parallel
657     } else if (strstr(s, "LDBU.D *") == s) {
658         C67_g((C67_map_regn(b) << 23) | //dst
659               (C67_map_regn(a) << 18) | //base reg A15
660               (0 << 13) |       //cst5
661               (1 << 9) |        //mode 1 = pos cst offset
662               (0 << 8) |        //r (LDDW bit 0)
663               (C67_map_regs(a) << 7) |  //y D1/D2  src side
664               (1 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
665               (1 << 2) |        //opcode
666               (C67_map_regs(b) << 1) |  //side of dst
667               (0 << 0));        //parallel
668     } else if (strstr(s, "LDW.D +*") == s) {
669         C67_g((C67_map_regn(b) << 23) | //dst
670               (C67_map_regn(a) << 18) | //base reg A15
671               (1 << 13) |       //cst5
672               (1 << 9) |        //mode 1 = pos cst offset
673               (0 << 8) |        //r (LDDW bit 0)
674               (C67_map_regs(a) << 7) |  //y D1/D2  src side
675               (6 << 4) |        //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
676               (1 << 2) |        //opcode
677               (C67_map_regs(b) << 1) |  //side of dst
678               (0 << 0));        //parallel
679     } else if (strstr(s, "CMPLTSP") == s) {
680         xpath = C67_map_regs(a) ^ C67_map_regs(b);
681         ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
682
683         C67_g((C67_map_regn(c) << 23) | //dst
684               (C67_map_regn(b) << 18) | //src2
685               (C67_map_regn(a) << 13) | //src1
686               (xpath << 12) |   //x use cross path for src2
687               (0x3a << 6) |     //opcode
688               (0x8 << 2) |      //opcode fixed
689               (C67_map_regs(c) << 1) |  //side for reg c
690               (0 << 0));        //parallel
691     } else if (strstr(s, "CMPGTSP") == s) {
692         xpath = C67_map_regs(a) ^ C67_map_regs(b);
693         ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
694
695         C67_g((C67_map_regn(c) << 23) | //dst
696               (C67_map_regn(b) << 18) | //src2
697               (C67_map_regn(a) << 13) | //src1
698               (xpath << 12) |   //x use cross path for src2
699               (0x39 << 6) |     //opcode
700               (0x8 << 2) |      //opcode fixed
701               (C67_map_regs(c) << 1) |  //side for reg c
702               (0 << 0));        //parallel
703     } else if (strstr(s, "CMPEQSP") == s) {
704         xpath = C67_map_regs(a) ^ C67_map_regs(b);
705         ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
706
707         C67_g((C67_map_regn(c) << 23) | //dst
708               (C67_map_regn(b) << 18) | //src2
709               (C67_map_regn(a) << 13) | //src1
710               (xpath << 12) |   //x use cross path for src2
711               (0x38 << 6) |     //opcode
712               (0x8 << 2) |      //opcode fixed
713               (C67_map_regs(c) << 1) |  //side for reg c
714               (0 << 0));        //parallel
715     }
716
717     else if (strstr(s, "CMPLTDP") == s) {
718         xpath = C67_map_regs(a) ^ C67_map_regs(b);
719         ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
720
721         C67_g((C67_map_regn(c) << 23) | //dst
722               (C67_map_regn(b) << 18) | //src2
723               (C67_map_regn(a) << 13) | //src1
724               (xpath << 12) |   //x use cross path for src2
725               (0x2a << 6) |     //opcode
726               (0x8 << 2) |      //opcode fixed
727               (C67_map_regs(c) << 1) |  //side for reg c
728               (0 << 0));        //parallel
729     } else if (strstr(s, "CMPGTDP") == s) {
730         xpath = C67_map_regs(a) ^ C67_map_regs(b);
731         ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
732
733         C67_g((C67_map_regn(c) << 23) | //dst
734               (C67_map_regn(b) << 18) | //src2
735               (C67_map_regn(a) << 13) | //src1
736               (xpath << 12) |   //x use cross path for src2
737               (0x29 << 6) |     //opcode
738               (0x8 << 2) |      //opcode fixed
739               (C67_map_regs(c) << 1) |  //side for reg c
740               (0 << 0));        //parallel
741     } else if (strstr(s, "CMPEQDP") == s) {
742         xpath = C67_map_regs(a) ^ C67_map_regs(b);
743         ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
744
745         C67_g((C67_map_regn(c) << 23) | //dst
746               (C67_map_regn(b) << 18) | //src2
747               (C67_map_regn(a) << 13) | //src1
748               (xpath << 12) |   //x use cross path for src2
749               (0x28 << 6) |     //opcode
750               (0x8 << 2) |      //opcode fixed
751               (C67_map_regs(c) << 1) |  //side for reg c
752               (0 << 0));        //parallel
753     } else if (strstr(s, "CMPLT") == s) {
754         xpath = C67_map_regs(a) ^ C67_map_regs(b);
755         ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
756
757         C67_g((C67_map_regn(c) << 23) | //dst
758               (C67_map_regn(b) << 18) | //src2
759               (C67_map_regn(a) << 13) | //src1
760               (xpath << 12) |   //x use cross path for src2
761               (0x57 << 5) |     //opcode
762               (0x6 << 2) |      //opcode fixed
763               (C67_map_regs(c) << 1) |  //side for reg c
764               (0 << 0));        //parallel
765     } else if (strstr(s, "CMPGT") == s) {
766         xpath = C67_map_regs(a) ^ C67_map_regs(b);
767         ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
768
769         C67_g((C67_map_regn(c) << 23) | //dst
770               (C67_map_regn(b) << 18) | //src2
771               (C67_map_regn(a) << 13) | //src1
772               (xpath << 12) |   //x use cross path for src2
773               (0x47 << 5) |     //opcode
774               (0x6 << 2) |      //opcode fixed
775               (C67_map_regs(c) << 1) |  //side for reg c
776               (0 << 0));        //parallel
777     } else if (strstr(s, "CMPEQ") == s) {
778         xpath = C67_map_regs(a) ^ C67_map_regs(b);
779         ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
780
781         C67_g((C67_map_regn(c) << 23) | //dst
782               (C67_map_regn(b) << 18) | //src2
783               (C67_map_regn(a) << 13) | //src1
784               (xpath << 12) |   //x use cross path for src2
785               (0x53 << 5) |     //opcode
786               (0x6 << 2) |      //opcode fixed
787               (C67_map_regs(c) << 1) |  //side for reg c
788               (0 << 0));        //parallel
789     } else if (strstr(s, "CMPLTU") == s) {
790         xpath = C67_map_regs(a) ^ C67_map_regs(b);
791         ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
792
793         C67_g((C67_map_regn(c) << 23) | //dst
794               (C67_map_regn(b) << 18) | //src2
795               (C67_map_regn(a) << 13) | //src1
796               (xpath << 12) |   //x use cross path for src2
797               (0x5f << 5) |     //opcode
798               (0x6 << 2) |      //opcode fixed
799               (C67_map_regs(c) << 1) |  //side for reg c
800               (0 << 0));        //parallel
801     } else if (strstr(s, "CMPGTU") == s) {
802         xpath = C67_map_regs(a) ^ C67_map_regs(b);
803         ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
804
805         C67_g((C67_map_regn(c) << 23) | //dst
806               (C67_map_regn(b) << 18) | //src2
807               (C67_map_regn(a) << 13) | //src1
808               (xpath << 12) |   //x use cross path for src2
809               (0x4f << 5) |     //opcode
810               (0x6 << 2) |      //opcode fixed
811               (C67_map_regs(c) << 1) |  //side for reg c
812               (0 << 0));        //parallel
813     } else if (strstr(s, "B DISP") == s) {
814         C67_g((0 << 29) |       //creg
815               (0 << 28) |       //z
816               (a << 7) |        //cnst
817               (0x4 << 2) |      //opcode fixed
818               (0 << 1) |        //S0/S1
819               (0 << 0));        //parallel
820     } else if (strstr(s, "B.") == s) {
821         xpath = C67_map_regs(c) ^ 1;
822
823         C67_g((C67_map_regc(b) << 29) | //creg
824               (a << 28) |       //inv
825               (0 << 23) |       //dst
826               (C67_map_regn(c) << 18) | //src2
827               (0 << 13) |       //
828               (xpath << 12) |   //x cross path if !B side
829               (0xd << 6) |      //opcode
830               (0x8 << 2) |      //opcode fixed
831               (1 << 1) |        //must be S2
832               (0 << 0));        //parallel
833     } else if (strstr(s, "MV.L") == s) {
834         xpath = C67_map_regs(b) ^ C67_map_regs(c);
835
836         C67_g((0 << 29) |       //creg
837               (0 << 28) |       //inv
838               (C67_map_regn(c) << 23) | //dst
839               (C67_map_regn(b) << 18) | //src2
840               (0 << 13) |       //src1 (cst5)
841               (xpath << 12) |   //x cross path if opposite sides
842               (0x2 << 5) |      //opcode
843               (0x6 << 2) |      //opcode fixed
844               (C67_map_regs(c) << 1) |  //side of dest
845               (0 << 0));        //parallel
846     } else if (strstr(s, "SPTRUNC.L") == s) {
847         xpath = C67_map_regs(b) ^ C67_map_regs(c);
848
849         C67_g((0 << 29) |       //creg
850               (0 << 28) |       //inv
851               (C67_map_regn(c) << 23) | //dst
852               (C67_map_regn(b) << 18) | //src2
853               (0 << 13) |       //src1 NA
854               (xpath << 12) |   //x cross path if opposite sides
855               (0xb << 5) |      //opcode
856               (0x6 << 2) |      //opcode fixed
857               (C67_map_regs(c) << 1) |  //side of dest
858               (0 << 0));        //parallel
859     } else if (strstr(s, "DPTRUNC.L") == s) {
860         xpath = C67_map_regs(b) ^ C67_map_regs(c);
861
862         C67_g((0 << 29) |       //creg
863               (0 << 28) |       //inv
864               (C67_map_regn(c) << 23) | //dst
865               ((C67_map_regn(b) + 1) << 18) |   //src2   WEIRD CPU must specify odd reg for some reason
866               (0 << 13) |       //src1 NA
867               (xpath << 12) |   //x cross path if opposite sides
868               (0x1 << 5) |      //opcode
869               (0x6 << 2) |      //opcode fixed
870               (C67_map_regs(c) << 1) |  //side of dest
871               (0 << 0));        //parallel
872     } else if (strstr(s, "INTSP.L") == s) {
873         xpath = C67_map_regs(b) ^ C67_map_regs(c);
874
875         C67_g((0 << 29) |       //creg
876               (0 << 28) |       //inv
877               (C67_map_regn(c) << 23) | //dst
878               (C67_map_regn(b) << 18) | //src2   
879               (0 << 13) |       //src1 NA
880               (xpath << 12) |   //x cross path if opposite sides
881               (0x4a << 5) |     //opcode
882               (0x6 << 2) |      //opcode fixed
883               (C67_map_regs(c) << 1) |  //side of dest
884               (0 << 0));        //parallel
885     } else if (strstr(s, "INTSPU.L") == s) {
886         xpath = C67_map_regs(b) ^ C67_map_regs(c);
887
888         C67_g((0 << 29) |       //creg
889               (0 << 28) |       //inv
890               (C67_map_regn(c) << 23) | //dst
891               (C67_map_regn(b) << 18) | //src2  
892               (0 << 13) |       //src1 NA
893               (xpath << 12) |   //x cross path if opposite sides
894               (0x49 << 5) |     //opcode
895               (0x6 << 2) |      //opcode fixed
896               (C67_map_regs(c) << 1) |  //side of dest
897               (0 << 0));        //parallel
898     } else if (strstr(s, "INTDP.L") == s) {
899         xpath = C67_map_regs(b) ^ C67_map_regs(c);
900
901         C67_g((0 << 29) |       //creg
902               (0 << 28) |       //inv
903               (C67_map_regn(c) << 23) | //dst
904               (C67_map_regn(b) << 18) | //src2  
905               (0 << 13) |       //src1 NA
906               (xpath << 12) |   //x cross path if opposite sides
907               (0x39 << 5) |     //opcode
908               (0x6 << 2) |      //opcode fixed
909               (C67_map_regs(c) << 1) |  //side of dest
910               (0 << 0));        //parallel
911     } else if (strstr(s, "INTDPU.L") == s) {
912         xpath = C67_map_regs(b) ^ C67_map_regs(c);
913
914         C67_g((0 << 29) |       //creg
915               (0 << 28) |       //inv
916               (C67_map_regn(c) << 23) | //dst
917               ((C67_map_regn(b) + 1) << 18) |   //src2   WEIRD CPU must specify odd reg for some reason
918               (0 << 13) |       //src1 NA
919               (xpath << 12) |   //x cross path if opposite sides
920               (0x3b << 5) |     //opcode
921               (0x6 << 2) |      //opcode fixed
922               (C67_map_regs(c) << 1) |  //side of dest
923               (0 << 0));        //parallel
924     } else if (strstr(s, "SPDP.L") == s) {
925         xpath = C67_map_regs(b) ^ C67_map_regs(c);
926
927         C67_g((0 << 29) |       //creg
928               (0 << 28) |       //inv
929               (C67_map_regn(c) << 23) | //dst
930               (C67_map_regn(b) << 18) | //src2
931               (0 << 13) |       //src1 NA
932               (xpath << 12) |   //x cross path if opposite sides
933               (0x2 << 6) |      //opcode
934               (0x8 << 2) |      //opcode fixed
935               (C67_map_regs(c) << 1) |  //side of dest
936               (0 << 0));        //parallel
937     } else if (strstr(s, "DPSP.L") == s) {
938         ALWAYS_ASSERT(C67_map_regs(b) == C67_map_regs(c));
939
940         C67_g((0 << 29) |       //creg
941               (0 << 28) |       //inv
942               (C67_map_regn(c) << 23) | //dst
943               ((C67_map_regn(b) + 1) << 18) |   //src2 WEIRD CPU must specify odd reg for some reason
944               (0 << 13) |       //src1 NA
945               (0 << 12) |       //x cross path if opposite sides
946               (0x9 << 5) |      //opcode
947               (0x6 << 2) |      //opcode fixed
948               (C67_map_regs(c) << 1) |  //side of dest
949               (0 << 0));        //parallel
950     } else if (strstr(s, "ADD.L") == s) {
951         xpath = C67_map_regs(b) ^ C67_map_regs(c);
952
953         ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
954
955         C67_g((0 << 29) |       //creg
956               (0 << 28) |       //inv
957               (C67_map_regn(c) << 23) | //dst
958               (C67_map_regn(b) << 18) | //src2 (possible x path)
959               (C67_map_regn(a) << 13) | //src1 
960               (xpath << 12) |   //x cross path if opposite sides
961               (0x3 << 5) |      //opcode
962               (0x6 << 2) |      //opcode fixed
963               (C67_map_regs(c) << 1) |  //side of dest
964               (0 << 0));        //parallel
965     } else if (strstr(s, "SUB.L") == s) {
966         xpath = C67_map_regs(b) ^ C67_map_regs(c);
967
968         ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
969
970         C67_g((0 << 29) |       //creg
971               (0 << 28) |       //inv
972               (C67_map_regn(c) << 23) | //dst
973               (C67_map_regn(b) << 18) | //src2 (possible x path)
974               (C67_map_regn(a) << 13) | //src1 
975               (xpath << 12) |   //x cross path if opposite sides
976               (0x7 << 5) |      //opcode
977               (0x6 << 2) |      //opcode fixed
978               (C67_map_regs(c) << 1) |  //side of dest
979               (0 << 0));        //parallel
980     } else if (strstr(s, "OR.L") == s) {
981         xpath = C67_map_regs(b) ^ C67_map_regs(c);
982
983         ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
984
985         C67_g((0 << 29) |       //creg
986               (0 << 28) |       //inv
987               (C67_map_regn(c) << 23) | //dst
988               (C67_map_regn(b) << 18) | //src2 (possible x path)
989               (C67_map_regn(a) << 13) | //src1 
990               (xpath << 12) |   //x cross path if opposite sides
991               (0x7f << 5) |     //opcode
992               (0x6 << 2) |      //opcode fixed
993               (C67_map_regs(c) << 1) |  //side of dest
994               (0 << 0));        //parallel
995     } else if (strstr(s, "AND.L") == s) {
996         xpath = C67_map_regs(b) ^ C67_map_regs(c);
997
998         ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
999
1000         C67_g((0 << 29) |       //creg
1001               (0 << 28) |       //inv
1002               (C67_map_regn(c) << 23) | //dst
1003               (C67_map_regn(b) << 18) | //src2 (possible x path)
1004               (C67_map_regn(a) << 13) | //src1 
1005               (xpath << 12) |   //x cross path if opposite sides
1006               (0x7b << 5) |     //opcode
1007               (0x6 << 2) |      //opcode fixed
1008               (C67_map_regs(c) << 1) |  //side of dest
1009               (0 << 0));        //parallel
1010     } else if (strstr(s, "XOR.L") == s) {
1011         xpath = C67_map_regs(b) ^ C67_map_regs(c);
1012
1013         ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
1014
1015         C67_g((0 << 29) |       //creg
1016               (0 << 28) |       //inv
1017               (C67_map_regn(c) << 23) | //dst
1018               (C67_map_regn(b) << 18) | //src2 (possible x path)
1019               (C67_map_regn(a) << 13) | //src1 
1020               (xpath << 12) |   //x cross path if opposite sides
1021               (0x6f << 5) |     //opcode
1022               (0x6 << 2) |      //opcode fixed
1023               (C67_map_regs(c) << 1) |  //side of dest
1024               (0 << 0));        //parallel
1025     } else if (strstr(s, "ADDSP.L") == s) {
1026         xpath = C67_map_regs(b) ^ C67_map_regs(c);
1027
1028         ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
1029
1030         C67_g((0 << 29) |       //creg
1031               (0 << 28) |       //inv
1032               (C67_map_regn(c) << 23) | //dst
1033               (C67_map_regn(b) << 18) | //src2 (possible x path)
1034               (C67_map_regn(a) << 13) | //src1 
1035               (xpath << 12) |   //x cross path if opposite sides
1036               (0x10 << 5) |     //opcode
1037               (0x6 << 2) |      //opcode fixed
1038               (C67_map_regs(c) << 1) |  //side of dest
1039               (0 << 0));        //parallel
1040     } else if (strstr(s, "ADDDP.L") == s) {
1041         xpath = C67_map_regs(b) ^ C67_map_regs(c);
1042
1043         ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
1044
1045         C67_g((0 << 29) |       //creg
1046               (0 << 28) |       //inv
1047               (C67_map_regn(c) << 23) | //dst
1048               (C67_map_regn(b) << 18) | //src2 (possible x path)
1049               (C67_map_regn(a) << 13) | //src1 
1050               (xpath << 12) |   //x cross path if opposite sides
1051               (0x18 << 5) |     //opcode
1052               (0x6 << 2) |      //opcode fixed
1053               (C67_map_regs(c) << 1) |  //side of dest
1054               (0 << 0));        //parallel
1055     } else if (strstr(s, "SUBSP.L") == s) {
1056         xpath = C67_map_regs(b) ^ C67_map_regs(c);
1057
1058         ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
1059
1060         C67_g((0 << 29) |       //creg
1061               (0 << 28) |       //inv
1062               (C67_map_regn(c) << 23) | //dst
1063               (C67_map_regn(b) << 18) | //src2 (possible x path)
1064               (C67_map_regn(a) << 13) | //src1 
1065               (xpath << 12) |   //x cross path if opposite sides
1066               (0x11 << 5) |     //opcode
1067               (0x6 << 2) |      //opcode fixed
1068               (C67_map_regs(c) << 1) |  //side of dest
1069               (0 << 0));        //parallel
1070     } else if (strstr(s, "SUBDP.L") == s) {
1071         xpath = C67_map_regs(b) ^ C67_map_regs(c);
1072
1073         ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
1074
1075         C67_g((0 << 29) |       //creg
1076               (0 << 28) |       //inv
1077               (C67_map_regn(c) << 23) | //dst
1078               (C67_map_regn(b) << 18) | //src2 (possible x path)
1079               (C67_map_regn(a) << 13) | //src1 
1080               (xpath << 12) |   //x cross path if opposite sides
1081               (0x19 << 5) |     //opcode
1082               (0x6 << 2) |      //opcode fixed
1083               (C67_map_regs(c) << 1) |  //side of dest
1084               (0 << 0));        //parallel
1085     } else if (strstr(s, "MPYSP.M") == s) {
1086         xpath = C67_map_regs(b) ^ C67_map_regs(c);
1087
1088         ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
1089
1090         C67_g((0 << 29) |       //creg
1091               (0 << 28) |       //inv
1092               (C67_map_regn(c) << 23) | //dst
1093               (C67_map_regn(b) << 18) | //src2 (possible x path)
1094               (C67_map_regn(a) << 13) | //src1 
1095               (xpath << 12) |   //x cross path if opposite sides
1096               (0x1c << 7) |     //opcode
1097               (0x0 << 2) |      //opcode fixed
1098               (C67_map_regs(c) << 1) |  //side of dest
1099               (0 << 0));        //parallel
1100     } else if (strstr(s, "MPYDP.M") == s) {
1101         xpath = C67_map_regs(b) ^ C67_map_regs(c);
1102
1103         ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
1104
1105         C67_g((0 << 29) |       //creg
1106               (0 << 28) |       //inv
1107               (C67_map_regn(c) << 23) | //dst
1108               (C67_map_regn(b) << 18) | //src2 (possible x path)
1109               (C67_map_regn(a) << 13) | //src1 
1110               (xpath << 12) |   //x cross path if opposite sides
1111               (0x0e << 7) |     //opcode
1112               (0x0 << 2) |      //opcode fixed
1113               (C67_map_regs(c) << 1) |  //side of dest
1114               (0 << 0));        //parallel
1115     } else if (strstr(s, "MPYI.M") == s) {
1116         xpath = C67_map_regs(b) ^ C67_map_regs(c);
1117
1118         ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
1119
1120         C67_g((0 << 29) |       //creg
1121               (0 << 28) |       //inv
1122               (C67_map_regn(c) << 23) | //dst
1123               (C67_map_regn(b) << 18) | //src2
1124               (C67_map_regn(a) << 13) | //src1 (cst5)
1125               (xpath << 12) |   //x cross path if opposite sides
1126               (0x4 << 7) |      //opcode
1127               (0x0 << 2) |      //opcode fixed
1128               (C67_map_regs(c) << 1) |  //side of dest
1129               (0 << 0));        //parallel
1130     } else if (strstr(s, "SHR.S") == s) {
1131         xpath = C67_map_regs(b) ^ C67_map_regs(c);
1132
1133         ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
1134
1135         C67_g((0 << 29) |       //creg
1136               (0 << 28) |       //inv
1137               (C67_map_regn(c) << 23) | //dst
1138               (C67_map_regn(b) << 18) | //src2
1139               (C67_map_regn(a) << 13) | //src1 
1140               (xpath << 12) |   //x cross path if opposite sides
1141               (0x37 << 6) |     //opcode
1142               (0x8 << 2) |      //opcode fixed
1143               (C67_map_regs(c) << 1) |  //side of dest
1144               (0 << 0));        //parallel
1145     } else if (strstr(s, "SHRU.S") == s) {
1146         xpath = C67_map_regs(b) ^ C67_map_regs(c);
1147
1148         ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
1149
1150         C67_g((0 << 29) |       //creg
1151               (0 << 28) |       //inv
1152               (C67_map_regn(c) << 23) | //dst
1153               (C67_map_regn(b) << 18) | //src2
1154               (C67_map_regn(a) << 13) | //src1 
1155               (xpath << 12) |   //x cross path if opposite sides
1156               (0x27 << 6) |     //opcode
1157               (0x8 << 2) |      //opcode fixed
1158               (C67_map_regs(c) << 1) |  //side of dest
1159               (0 << 0));        //parallel
1160     } else if (strstr(s, "SHL.S") == s) {
1161         xpath = C67_map_regs(b) ^ C67_map_regs(c);
1162
1163         ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
1164
1165         C67_g((0 << 29) |       //creg
1166               (0 << 28) |       //inv
1167               (C67_map_regn(c) << 23) | //dst
1168               (C67_map_regn(b) << 18) | //src2
1169               (C67_map_regn(a) << 13) | //src1 
1170               (xpath << 12) |   //x cross path if opposite sides
1171               (0x33 << 6) |     //opcode
1172               (0x8 << 2) |      //opcode fixed
1173               (C67_map_regs(c) << 1) |  //side of dest
1174               (0 << 0));        //parallel
1175     } else if (strstr(s, "||ADDK") == s) {
1176         xpath = 0;              // no xpath required just use the side of the src/dst
1177
1178         C67_g((0 << 29) |       //creg
1179               (0 << 28) |       //inv
1180               (C67_map_regn(b) << 23) | //dst
1181               (a << 07) |       //scst16
1182               (0x14 << 2) |     //opcode fixed
1183               (C67_map_regs(b) << 1) |  //side of dst
1184               (1 << 0));        //parallel
1185     } else if (strstr(s, "ADDK") == s) {
1186         xpath = 0;              // no xpath required just use the side of the src/dst
1187
1188         C67_g((0 << 29) |       //creg
1189               (0 << 28) |       //inv
1190               (C67_map_regn(b) << 23) | //dst
1191               (a << 07) |       //scst16
1192               (0x14 << 2) |     //opcode fixed
1193               (C67_map_regs(b) << 1) |  //side of dst
1194               (0 << 0));        //parallel
1195     } else if (strstr(s, "NOP") == s) {
1196         C67_g(((a - 1) << 13) | //no of cycles
1197               (0 << 0));        //parallel
1198     } else
1199         ALWAYS_ASSERT(FALSE);
1200
1201 #ifdef ASSEMBLY_LISTING_C67
1202     fprintf(f, " %s %d %d %d\n", s, a, b, c);
1203 #endif
1204
1205 }
1206
1207 //r=reg to load, fr=from reg, symbol for relocation, constant
1208
1209 void C67_MVKL(int r, int fc)
1210 {
1211     C67_asm("MVKL.", fc, r, 0);
1212 }
1213
1214 void C67_MVKH(int r, int fc)
1215 {
1216     C67_asm("MVKH.", fc, r, 0);
1217 }
1218
1219 void C67_STB_SP_A0(int r)
1220 {
1221     C67_asm("STB.D *+SP[A0]", r, 0, 0); // STB  r,*+SP[A0]
1222 }
1223
1224 void C67_STH_SP_A0(int r)
1225 {
1226     C67_asm("STH.D *+SP[A0]", r, 0, 0); // STH  r,*+SP[A0]
1227 }
1228
1229 void C67_STW_SP_A0(int r)
1230 {
1231     C67_asm("STW.D *+SP[A0]", r, 0, 0); // STW  r,*+SP[A0]
1232 }
1233
1234 void C67_STB_PTR(int r, int r2)
1235 {
1236     C67_asm("STB.D *", r, r2, 0);       // STB  r, *r2
1237 }
1238
1239 void C67_STH_PTR(int r, int r2)
1240 {
1241     C67_asm("STH.D *", r, r2, 0);       // STH  r, *r2
1242 }
1243
1244 void C67_STW_PTR(int r, int r2)
1245 {
1246     C67_asm("STW.D *", r, r2, 0);       // STW  r, *r2
1247 }
1248
1249 void C67_STW_PTR_PRE_INC(int r, int r2, int n)
1250 {
1251     C67_asm("STW.D +*", r, r2, n);      // STW  r, *+r2
1252 }
1253
1254 void C67_PUSH(int r)
1255 {
1256     C67_asm("STW.D SP POST DEC", r, 0, 0);      // STW  r,*SP--
1257 }
1258
1259 void C67_LDW_SP_A0(int r)
1260 {
1261     C67_asm("LDW.D *+SP[A0]", r, 0, 0); // LDW  *+SP[A0],r
1262 }
1263
1264 void C67_LDDW_SP_A0(int r)
1265 {
1266     C67_asm("LDDW.D *+SP[A0]", r, 0, 0);        // LDDW  *+SP[A0],r
1267 }
1268
1269 void C67_LDH_SP_A0(int r)
1270 {
1271     C67_asm("LDH.D *+SP[A0]", r, 0, 0); // LDH  *+SP[A0],r
1272 }
1273
1274 void C67_LDB_SP_A0(int r)
1275 {
1276     C67_asm("LDB.D *+SP[A0]", r, 0, 0); // LDB  *+SP[A0],r
1277 }
1278
1279 void C67_LDHU_SP_A0(int r)
1280 {
1281     C67_asm("LDHU.D *+SP[A0]", r, 0, 0);        // LDHU  *+SP[A0],r
1282 }
1283
1284 void C67_LDBU_SP_A0(int r)
1285 {
1286     C67_asm("LDBU.D *+SP[A0]", r, 0, 0);        // LDBU  *+SP[A0],r
1287 }
1288
1289 void C67_LDW_PTR(int r, int r2)
1290 {
1291     C67_asm("LDW.D *", r, r2, 0);       // LDW  *r,r2
1292 }
1293
1294 void C67_LDDW_PTR(int r, int r2)
1295 {
1296     C67_asm("LDDW.D *", r, r2, 0);      // LDDW  *r,r2
1297 }
1298
1299 void C67_LDH_PTR(int r, int r2)
1300 {
1301     C67_asm("LDH.D *", r, r2, 0);       // LDH  *r,r2
1302 }
1303
1304 void C67_LDB_PTR(int r, int r2)
1305 {
1306     C67_asm("LDB.D *", r, r2, 0);       // LDB  *r,r2
1307 }
1308
1309 void C67_LDHU_PTR(int r, int r2)
1310 {
1311     C67_asm("LDHU.D *", r, r2, 0);      // LDHU  *r,r2
1312 }
1313
1314 void C67_LDBU_PTR(int r, int r2)
1315 {
1316     C67_asm("LDBU.D *", r, r2, 0);      // LDBU  *r,r2
1317 }
1318
1319 void C67_LDW_PTR_PRE_INC(int r, int r2)
1320 {
1321     C67_asm("LDW.D +*", r, r2, 0);      // LDW  *+r,r2
1322 }
1323
1324 void C67_POP(int r)
1325 {
1326     C67_asm("LDW.D SP PRE INC", r, 0, 0);       // LDW  *++SP,r
1327 }
1328
1329 void C67_POP_DW(int r)
1330 {
1331     C67_asm("LDDW.D SP PRE INC", r, 0, 0);      // LDDW  *++SP,r
1332 }
1333
1334 void C67_CMPLT(int s1, int s2, int dst)
1335 {
1336     C67_asm("CMPLT.L1", s1, s2, dst);
1337 }
1338
1339 void C67_CMPGT(int s1, int s2, int dst)
1340 {
1341     C67_asm("CMPGT.L1", s1, s2, dst);
1342 }
1343
1344 void C67_CMPEQ(int s1, int s2, int dst)
1345 {
1346     C67_asm("CMPEQ.L1", s1, s2, dst);
1347 }
1348
1349 void C67_CMPLTU(int s1, int s2, int dst)
1350 {
1351     C67_asm("CMPLTU.L1", s1, s2, dst);
1352 }
1353
1354 void C67_CMPGTU(int s1, int s2, int dst)
1355 {
1356     C67_asm("CMPGTU.L1", s1, s2, dst);
1357 }
1358
1359
1360 void C67_CMPLTSP(int s1, int s2, int dst)
1361 {
1362     C67_asm("CMPLTSP.S1", s1, s2, dst);
1363 }
1364
1365 void C67_CMPGTSP(int s1, int s2, int dst)
1366 {
1367     C67_asm("CMPGTSP.S1", s1, s2, dst);
1368 }
1369
1370 void C67_CMPEQSP(int s1, int s2, int dst)
1371 {
1372     C67_asm("CMPEQSP.S1", s1, s2, dst);
1373 }
1374
1375 void C67_CMPLTDP(int s1, int s2, int dst)
1376 {
1377     C67_asm("CMPLTDP.S1", s1, s2, dst);
1378 }
1379
1380 void C67_CMPGTDP(int s1, int s2, int dst)
1381 {
1382     C67_asm("CMPGTDP.S1", s1, s2, dst);
1383 }
1384
1385 void C67_CMPEQDP(int s1, int s2, int dst)
1386 {
1387     C67_asm("CMPEQDP.S1", s1, s2, dst);
1388 }
1389
1390
1391 void C67_IREG_B_REG(int inv, int r1, int r2)    // [!R] B  r2
1392 {
1393     C67_asm("B.S2", inv, r1, r2);
1394 }
1395
1396
1397 // call with how many 32 bit words to skip
1398 // (0 would branch to the branch instruction)
1399
1400 void C67_B_DISP(int disp)       //  B  +2  Branch with constant displacement
1401 {
1402     // Branch point is relative to the 8 word fetch packet
1403     //
1404     // we will assume the text section always starts on an 8 word (32 byte boundary)
1405     //
1406     // so add in how many words into the fetch packet the branch is
1407
1408
1409     C67_asm("B DISP", disp + ((ind & 31) >> 2), 0, 0);
1410 }
1411
1412 void C67_NOP(int n)
1413 {
1414     C67_asm("NOP", n, 0, 0);
1415 }
1416
1417 void C67_ADDK(int n, int r)
1418 {
1419     ALWAYS_ASSERT(abs(n) < 32767);
1420
1421     C67_asm("ADDK", n, r, 0);
1422 }
1423
1424 void C67_ADDK_PARALLEL(int n, int r)
1425 {
1426     ALWAYS_ASSERT(abs(n) < 32767);
1427
1428     C67_asm("||ADDK", n, r, 0);
1429 }
1430
1431 void C67_Adjust_ADDK(int *inst, int n)
1432 {
1433     ALWAYS_ASSERT(abs(n) < 32767);
1434
1435     *inst = (*inst & (~(0xffff << 7))) | ((n & 0xffff) << 7);
1436 }
1437
1438 void C67_MV(int r, int v)
1439 {
1440     C67_asm("MV.L", 0, r, v);
1441 }
1442
1443
1444 void C67_DPTRUNC(int r, int v)
1445 {
1446     C67_asm("DPTRUNC.L", 0, r, v);
1447 }
1448
1449 void C67_SPTRUNC(int r, int v)
1450 {
1451     C67_asm("SPTRUNC.L", 0, r, v);
1452 }
1453
1454 void C67_INTSP(int r, int v)
1455 {
1456     C67_asm("INTSP.L", 0, r, v);
1457 }
1458
1459 void C67_INTDP(int r, int v)
1460 {
1461     C67_asm("INTDP.L", 0, r, v);
1462 }
1463
1464 void C67_INTSPU(int r, int v)
1465 {
1466     C67_asm("INTSPU.L", 0, r, v);
1467 }
1468
1469 void C67_INTDPU(int r, int v)
1470 {
1471     C67_asm("INTDPU.L", 0, r, v);
1472 }
1473
1474 void C67_SPDP(int r, int v)
1475 {
1476     C67_asm("SPDP.L", 0, r, v);
1477 }
1478
1479 void C67_DPSP(int r, int v)     // note regs must be on the same side
1480 {
1481     C67_asm("DPSP.L", 0, r, v);
1482 }
1483
1484 void C67_ADD(int r, int v)
1485 {
1486     C67_asm("ADD.L", v, r, v);
1487 }
1488
1489 void C67_SUB(int r, int v)
1490 {
1491     C67_asm("SUB.L", v, r, v);
1492 }
1493
1494 void C67_AND(int r, int v)
1495 {
1496     C67_asm("AND.L", v, r, v);
1497 }
1498
1499 void C67_OR(int r, int v)
1500 {
1501     C67_asm("OR.L", v, r, v);
1502 }
1503
1504 void C67_XOR(int r, int v)
1505 {
1506     C67_asm("XOR.L", v, r, v);
1507 }
1508
1509 void C67_ADDSP(int r, int v)
1510 {
1511     C67_asm("ADDSP.L", v, r, v);
1512 }
1513
1514 void C67_SUBSP(int r, int v)
1515 {
1516     C67_asm("SUBSP.L", v, r, v);
1517 }
1518
1519 void C67_MPYSP(int r, int v)
1520 {
1521     C67_asm("MPYSP.M", v, r, v);
1522 }
1523
1524 void C67_ADDDP(int r, int v)
1525 {
1526     C67_asm("ADDDP.L", v, r, v);
1527 }
1528
1529 void C67_SUBDP(int r, int v)
1530 {
1531     C67_asm("SUBDP.L", v, r, v);
1532 }
1533
1534 void C67_MPYDP(int r, int v)
1535 {
1536     C67_asm("MPYDP.M", v, r, v);
1537 }
1538
1539 void C67_MPYI(int r, int v)
1540 {
1541     C67_asm("MPYI.M", v, r, v);
1542 }
1543
1544 void C67_SHL(int r, int v)
1545 {
1546     C67_asm("SHL.S", r, v, v);
1547 }
1548
1549 void C67_SHRU(int r, int v)
1550 {
1551     C67_asm("SHRU.S", r, v, v);
1552 }
1553
1554 void C67_SHR(int r, int v)
1555 {
1556     C67_asm("SHR.S", r, v, v);
1557 }
1558
1559
1560
1561 /* load 'r' from value 'sv' */
1562 void load(int r, SValue * sv)
1563 {
1564     int v, t, ft, fc, fr, size = 0, element;
1565     BOOL Unsigned = FALSE;
1566     SValue v1;
1567
1568     fr = sv->r;
1569     ft = sv->type.t;
1570     fc = sv->c.ul;
1571
1572     v = fr & VT_VALMASK;
1573     if (fr & VT_LVAL) {
1574         if (v == VT_LLOCAL) {
1575             v1.type.t = VT_INT;
1576             v1.r = VT_LOCAL | VT_LVAL;
1577             v1.c.ul = fc;
1578             load(r, &v1);
1579             fr = r;
1580         } else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
1581             tcc_error("long double not supported");
1582         } else if ((ft & VT_TYPE) == VT_BYTE) {
1583             size = 1;
1584         } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {
1585             size = 1;
1586             Unsigned = TRUE;
1587         } else if ((ft & VT_TYPE) == VT_SHORT) {
1588             size = 2;
1589         } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) {
1590             size = 2;
1591             Unsigned = TRUE;
1592         } else if ((ft & VT_BTYPE) == VT_DOUBLE) {
1593             size = 8;
1594         } else {
1595             size = 4;
1596         }
1597
1598         // check if fc is a positive reference on the stack, 
1599         // if it is tcc is referencing what it thinks is a parameter
1600         // on the stack, so check if it is really in a register.
1601
1602
1603         if (v == VT_LOCAL && fc > 0) {
1604             int stack_pos = 8;
1605
1606             for (t = 0; t < NoCallArgsPassedOnStack; t++) {
1607                 if (fc == stack_pos)
1608                     break;
1609
1610                 stack_pos += TranslateStackToReg[t];
1611             }
1612
1613             // param has been pushed on stack, get it like a local var
1614
1615             fc = ParamLocOnStack[t] - 8;
1616         }
1617
1618         if ((fr & VT_VALMASK) < VT_CONST)       // check for pure indirect
1619         {
1620             if (size == 1) {
1621                 if (Unsigned)
1622                     C67_LDBU_PTR(v, r); // LDBU  *v,r
1623                 else
1624                     C67_LDB_PTR(v, r);  // LDB  *v,r
1625             } else if (size == 2) {
1626                 if (Unsigned)
1627                     C67_LDHU_PTR(v, r); // LDHU  *v,r
1628                 else
1629                     C67_LDH_PTR(v, r);  // LDH  *v,r
1630             } else if (size == 4) {
1631                 C67_LDW_PTR(v, r);      // LDW  *v,r
1632             } else if (size == 8) {
1633                 C67_LDDW_PTR(v, r);     // LDDW  *v,r
1634             }
1635
1636             C67_NOP(4);         // NOP 4
1637             return;
1638         } else if (fr & VT_SYM) {
1639             greloc(cur_text_section, sv->sym, ind, R_C60LO16);  // rem the inst need to be patched
1640             greloc(cur_text_section, sv->sym, ind + 4, R_C60HI16);
1641
1642
1643             C67_MVKL(C67_A0, fc);       //r=reg to load,  constant
1644             C67_MVKH(C67_A0, fc);       //r=reg to load,  constant
1645
1646
1647             if (size == 1) {
1648                 if (Unsigned)
1649                     C67_LDBU_PTR(C67_A0, r);    // LDBU  *A0,r
1650                 else
1651                     C67_LDB_PTR(C67_A0, r);     // LDB  *A0,r
1652             } else if (size == 2) {
1653                 if (Unsigned)
1654                     C67_LDHU_PTR(C67_A0, r);    // LDHU  *A0,r
1655                 else
1656                     C67_LDH_PTR(C67_A0, r);     // LDH  *A0,r
1657             } else if (size == 4) {
1658                 C67_LDW_PTR(C67_A0, r); // LDW  *A0,r
1659             } else if (size == 8) {
1660                 C67_LDDW_PTR(C67_A0, r);        // LDDW  *A0,r
1661             }
1662
1663             C67_NOP(4);         // NOP 4
1664             return;
1665         } else {
1666             element = size;
1667
1668             // divide offset in bytes to create element index
1669             C67_MVKL(C67_A0, (fc / element) + 8 / element);     //r=reg to load,  constant
1670             C67_MVKH(C67_A0, (fc / element) + 8 / element);     //r=reg to load,  constant
1671
1672             if (size == 1) {
1673                 if (Unsigned)
1674                     C67_LDBU_SP_A0(r);  // LDBU  r, SP[A0]
1675                 else
1676                     C67_LDB_SP_A0(r);   // LDB  r, SP[A0]
1677             } else if (size == 2) {
1678                 if (Unsigned)
1679                     C67_LDHU_SP_A0(r);  // LDHU  r, SP[A0]
1680                 else
1681                     C67_LDH_SP_A0(r);   // LDH  r, SP[A0]
1682             } else if (size == 4) {
1683                 C67_LDW_SP_A0(r);       // LDW  r, SP[A0]
1684             } else if (size == 8) {
1685                 C67_LDDW_SP_A0(r);      // LDDW  r, SP[A0]
1686             }
1687
1688
1689             C67_NOP(4);         // NOP 4
1690             return;
1691         }
1692     } else {
1693         if (v == VT_CONST) {
1694             if (fr & VT_SYM) {
1695                 greloc(cur_text_section, sv->sym, ind, R_C60LO16);      // rem the inst need to be patched
1696                 greloc(cur_text_section, sv->sym, ind + 4, R_C60HI16);
1697             }
1698             C67_MVKL(r, fc);    //r=reg to load, constant
1699             C67_MVKH(r, fc);    //r=reg to load, constant
1700         } else if (v == VT_LOCAL) {
1701             C67_MVKL(r, fc + 8);        //r=reg to load, constant C67 stack points to next free
1702             C67_MVKH(r, fc + 8);        //r=reg to load, constant
1703             C67_ADD(C67_FP, r); // MV v,r   v -> r
1704         } else if (v == VT_CMP) {
1705             C67_MV(C67_compare_reg, r); // MV v,r   v -> r
1706         } else if (v == VT_JMP || v == VT_JMPI) {
1707             t = v & 1;
1708             C67_B_DISP(4);      //  Branch with constant displacement, skip over this branch, load, nop, load
1709             C67_MVKL(r, t);     //  r=reg to load, 0 or 1 (do this while branching)
1710             C67_NOP(4);         //  NOP 4
1711             gsym(fc);           //  modifies other branches to branch here
1712             C67_MVKL(r, t ^ 1); //  r=reg to load, 0 or 1
1713         } else if (v != r) {
1714             C67_MV(v, r);       // MV v,r   v -> r
1715
1716             if ((ft & VT_BTYPE) == VT_DOUBLE)
1717                 C67_MV(v + 1, r + 1);   // MV v,r   v -> r
1718         }
1719     }
1720 }
1721
1722
1723 /* store register 'r' in lvalue 'v' */
1724 void store(int r, SValue * v)
1725 {
1726     int fr, bt, ft, fc, size, t, element;
1727
1728     ft = v->type.t;
1729     fc = v->c.ul;
1730     fr = v->r & VT_VALMASK;
1731     bt = ft & VT_BTYPE;
1732     /* XXX: incorrect if float reg to reg */
1733
1734     if (bt == VT_LDOUBLE) {
1735         tcc_error("long double not supported");
1736     } else {
1737         if (bt == VT_SHORT)
1738             size = 2;
1739         else if (bt == VT_BYTE)
1740             size = 1;
1741         else if (bt == VT_DOUBLE)
1742             size = 8;
1743         else
1744             size = 4;
1745
1746         if ((v->r & VT_VALMASK) == VT_CONST) {
1747             /* constant memory reference */
1748
1749             if (v->r & VT_SYM) {
1750                 greloc(cur_text_section, v->sym, ind, R_C60LO16);       // rem the inst need to be patched
1751                 greloc(cur_text_section, v->sym, ind + 4, R_C60HI16);
1752             }
1753             C67_MVKL(C67_A0, fc);       //r=reg to load,  constant
1754             C67_MVKH(C67_A0, fc);       //r=reg to load,  constant
1755
1756             if (size == 1)
1757                 C67_STB_PTR(r, C67_A0); // STB  r, *A0
1758             else if (size == 2)
1759                 C67_STH_PTR(r, C67_A0); // STH  r, *A0
1760             else if (size == 4 || size == 8)
1761                 C67_STW_PTR(r, C67_A0); // STW  r, *A0
1762
1763             if (size == 8)
1764                 C67_STW_PTR_PRE_INC(r + 1, C67_A0, 1);  // STW  r, *+A0[1]
1765         } else if ((v->r & VT_VALMASK) == VT_LOCAL) {
1766             // check case of storing to passed argument that
1767             // tcc thinks is on the stack but for C67 is
1768             // passed as a reg.  However it may have been
1769             // saved to the stack, if that reg was required
1770             // for a call to a child function
1771
1772             if (fc > 0)         // argument ??
1773             {
1774                 // walk through sizes and figure which param
1775
1776                 int stack_pos = 8;
1777
1778                 for (t = 0; t < NoCallArgsPassedOnStack; t++) {
1779                     if (fc == stack_pos)
1780                         break;
1781
1782                     stack_pos += TranslateStackToReg[t];
1783                 }
1784
1785                 // param has been pushed on stack, get it like a local var
1786                 fc = ParamLocOnStack[t] - 8;
1787             }
1788
1789             if (size == 8)
1790                 element = 4;
1791             else
1792                 element = size;
1793
1794             // divide offset in bytes to create word index
1795             C67_MVKL(C67_A0, (fc / element) + 8 / element);     //r=reg to load,  constant
1796             C67_MVKH(C67_A0, (fc / element) + 8 / element);     //r=reg to load,  constant
1797
1798
1799
1800             if (size == 1)
1801                 C67_STB_SP_A0(r);       // STB  r, SP[A0]
1802             else if (size == 2)
1803                 C67_STH_SP_A0(r);       // STH  r, SP[A0]
1804             else if (size == 4 || size == 8)
1805                 C67_STW_SP_A0(r);       // STW  r, SP[A0]
1806
1807             if (size == 8) {
1808                 C67_ADDK(1, C67_A0);    //  ADDK 1,A0
1809                 C67_STW_SP_A0(r + 1);   //  STW  r, SP[A0]
1810             }
1811         } else {
1812             if (size == 1)
1813                 C67_STB_PTR(r, fr);     // STB  r, *fr
1814             else if (size == 2)
1815                 C67_STH_PTR(r, fr);     // STH  r, *fr
1816             else if (size == 4 || size == 8)
1817                 C67_STW_PTR(r, fr);     // STW  r, *fr
1818
1819             if (size == 8) {
1820                 C67_STW_PTR_PRE_INC(r + 1, fr, 1);      // STW  r, *+fr[1]
1821             }
1822         }
1823     }
1824 }
1825
1826 /* 'is_jmp' is '1' if it is a jump */
1827 static void gcall_or_jmp(int is_jmp)
1828 {
1829     int r;
1830     Sym *sym;
1831
1832     if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
1833         /* constant case */
1834         if (vtop->r & VT_SYM) {
1835             /* relocation case */
1836
1837             // get add into A0, then start the jump B3
1838
1839             greloc(cur_text_section, vtop->sym, ind, R_C60LO16);        // rem the inst need to be patched
1840             greloc(cur_text_section, vtop->sym, ind + 4, R_C60HI16);
1841
1842             C67_MVKL(C67_A0, 0);        //r=reg to load, constant
1843             C67_MVKH(C67_A0, 0);        //r=reg to load, constant
1844             C67_IREG_B_REG(0, C67_CREG_ZERO, C67_A0);   //  B.S2x  A0
1845
1846             if (is_jmp) {
1847                 C67_NOP(5);     // simple jump, just put NOP
1848             } else {
1849                 // Call, must load return address into B3 during delay slots
1850
1851                 sym = get_sym_ref(&char_pointer_type, cur_text_section, ind + 12, 0);   // symbol for return address
1852                 greloc(cur_text_section, sym, ind, R_C60LO16);  // rem the inst need to be patched
1853                 greloc(cur_text_section, sym, ind + 4, R_C60HI16);
1854                 C67_MVKL(C67_B3, 0);    //r=reg to load, constant
1855                 C67_MVKH(C67_B3, 0);    //r=reg to load, constant
1856                 C67_NOP(3);     // put remaining NOPs
1857             }
1858         } else {
1859             /* put an empty PC32 relocation */
1860             ALWAYS_ASSERT(FALSE);
1861         }
1862     } else {
1863         /* otherwise, indirect call */
1864         r = gv(RC_INT);
1865         C67_IREG_B_REG(0, C67_CREG_ZERO, r);    //  B.S2x  r
1866
1867         if (is_jmp) {
1868             C67_NOP(5);         // simple jump, just put NOP
1869         } else {
1870             // Call, must load return address into B3 during delay slots
1871
1872             sym = get_sym_ref(&char_pointer_type, cur_text_section, ind + 12, 0);       // symbol for return address
1873             greloc(cur_text_section, sym, ind, R_C60LO16);      // rem the inst need to be patched
1874             greloc(cur_text_section, sym, ind + 4, R_C60HI16);
1875             C67_MVKL(C67_B3, 0);        //r=reg to load, constant
1876             C67_MVKH(C67_B3, 0);        //r=reg to load, constant
1877             C67_NOP(3);         // put remaining NOPs
1878         }
1879     }
1880 }
1881
1882 /* Return 1 if this function returns via an sret pointer, 0 otherwise */
1883 ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) {
1884     *ret_align = 1; // Never have to re-align return values for x86-64
1885     return 1;
1886 }
1887
1888 /* generate function call with address in (vtop->t, vtop->c) and free function
1889    context. Stack entry is popped */
1890 void gfunc_call(int nb_args)
1891 {
1892     int i, r, size = 0;
1893     int args_sizes[NoCallArgsPassedOnStack];
1894
1895     if (nb_args > NoCallArgsPassedOnStack) {
1896         tcc_error("more than 10 function params not currently supported");
1897         // handle more than 10, put some on the stack
1898     }
1899
1900     for (i = 0; i < nb_args; i++) {
1901         if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
1902             ALWAYS_ASSERT(FALSE);
1903         } else if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
1904             ALWAYS_ASSERT(FALSE);
1905         } else {
1906             /* simple type (currently always same size) */
1907             /* XXX: implicit cast ? */
1908
1909
1910             if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
1911                 tcc_error("long long not supported");
1912             } else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
1913                 tcc_error("long double not supported");
1914             } else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) {
1915                 size = 8;
1916             } else {
1917                 size = 4;
1918             }
1919
1920             // put the parameter into the corresponding reg (pair)
1921
1922             r = gv(RC_C67_A4 << (2 * i));
1923
1924             // must put on stack because with 1 pass compiler , no way to tell
1925             // if an up coming nested call might overwrite these regs
1926
1927             C67_PUSH(r);
1928
1929             if (size == 8) {
1930                 C67_STW_PTR_PRE_INC(r + 1, C67_SP, 3);  // STW  r, *+SP[3] (go back and put the other)
1931             }
1932             args_sizes[i] = size;
1933         }
1934         vtop--;
1935     }
1936     // POP all the params on the stack into registers for the
1937     // immediate call (in reverse order)
1938
1939     for (i = nb_args - 1; i >= 0; i--) {
1940
1941         if (args_sizes[i] == 8)
1942             C67_POP_DW(TREG_C67_A4 + i * 2);
1943         else
1944             C67_POP(TREG_C67_A4 + i * 2);
1945     }
1946     gcall_or_jmp(0);
1947     vtop--;
1948 }
1949
1950
1951 // to be compatible with Code Composer for the C67
1952 // the first 10 parameters must be passed in registers
1953 // (pairs for 64 bits) starting wit; A4:A5, then B4:B5 and
1954 // ending with B12:B13.
1955 //
1956 // When a call is made, if the caller has its parameters
1957 // in regs A4-B13 these must be saved before/as the call 
1958 // parameters are loaded and restored upon return (or if/when needed).
1959
1960 /* generate function prolog of type 't' */
1961 void gfunc_prolog(CType * func_type)
1962 {
1963     int addr, align, size, func_call, i;
1964     Sym *sym;
1965     CType *type;
1966
1967     sym = func_type->ref;
1968     func_call = sym->r;
1969     addr = 8;
1970     /* if the function returns a structure, then add an
1971        implicit pointer parameter */
1972     func_vt = sym->type;
1973     if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
1974         func_vc = addr;
1975         addr += 4;
1976     }
1977
1978     NoOfCurFuncArgs = 0;
1979
1980     /* define parameters */
1981     while ((sym = sym->next) != NULL) {
1982         type = &sym->type;
1983         sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr);
1984         size = type_size(type, &align);
1985         size = (size + 3) & ~3;
1986
1987         // keep track of size of arguments so
1988         // we can translate where tcc thinks they
1989         // are on the stack into the appropriate reg
1990
1991         TranslateStackToReg[NoOfCurFuncArgs] = size;
1992         NoOfCurFuncArgs++;
1993
1994 #ifdef FUNC_STRUCT_PARAM_AS_PTR
1995         /* structs are passed as pointer */
1996         if ((type->t & VT_BTYPE) == VT_STRUCT) {
1997             size = 4;
1998         }
1999 #endif
2000         addr += size;
2001     }
2002     func_ret_sub = 0;
2003     /* pascal type call ? */
2004     if (func_call == FUNC_STDCALL)
2005         func_ret_sub = addr - 8;
2006
2007     C67_MV(C67_FP, C67_A0);     //  move FP -> A0
2008     C67_MV(C67_SP, C67_FP);     //  move SP -> FP
2009
2010     // place all the args passed in regs onto the stack
2011
2012     loc = 0;
2013     for (i = 0; i < NoOfCurFuncArgs; i++) {
2014
2015         ParamLocOnStack[i] = loc;       // remember where the param is
2016         loc += -8;
2017
2018         C67_PUSH(TREG_C67_A4 + i * 2);
2019
2020         if (TranslateStackToReg[i] == 8) {
2021             C67_STW_PTR_PRE_INC(TREG_C67_A4 + i * 2 + 1, C67_SP, 3);    // STW  r, *+SP[1] (go back and put the other)
2022         }
2023     }
2024
2025     TotalBytesPushedOnStack = -loc;
2026
2027     func_sub_sp_offset = ind;   // remember where we put the stack instruction 
2028     C67_ADDK(0, C67_SP);        //  ADDK.L2 loc,SP  (just put zero temporarily)
2029
2030     C67_PUSH(C67_A0);
2031     C67_PUSH(C67_B3);
2032 }
2033
2034 /* generate function epilog */
2035 void gfunc_epilog(void)
2036 {
2037     {
2038         int local = (-loc + 7) & -8;    // stack must stay aligned to 8 bytes for LDDW instr
2039         C67_POP(C67_B3);
2040         C67_NOP(4);             // NOP wait for load
2041         C67_IREG_B_REG(0, C67_CREG_ZERO, C67_B3);       //  B.S2  B3
2042         C67_POP(C67_FP);
2043         C67_ADDK(local, C67_SP);        //  ADDK.L2 loc,SP  
2044         C67_Adjust_ADDK((int *) (cur_text_section->data +
2045                                  func_sub_sp_offset),
2046                         -local + TotalBytesPushedOnStack);
2047         C67_NOP(3);             // NOP 
2048     }
2049 }
2050
2051 /* generate a jump to a label */
2052 int gjmp(int t)
2053 {
2054     int ind1 = ind;
2055
2056     C67_MVKL(C67_A0, t);        //r=reg to load,  constant
2057     C67_MVKH(C67_A0, t);        //r=reg to load,  constant
2058     C67_IREG_B_REG(0, C67_CREG_ZERO, C67_A0);   // [!R] B.S2x  A0
2059     C67_NOP(5);
2060     return ind1;
2061 }
2062
2063 /* generate a jump to a fixed address */
2064 void gjmp_addr(int a)
2065 {
2066     Sym *sym;
2067     // I guess this routine is used for relative short
2068     // local jumps, for now just handle it as the general
2069     // case
2070
2071     // define a label that will be relocated
2072
2073     sym = get_sym_ref(&char_pointer_type, cur_text_section, a, 0);
2074     greloc(cur_text_section, sym, ind, R_C60LO16);
2075     greloc(cur_text_section, sym, ind + 4, R_C60HI16);
2076
2077     gjmp(0);                    // place a zero there later the symbol will be added to it
2078 }
2079
2080 /* generate a test. set 'inv' to invert test. Stack entry is popped */
2081 int gtst(int inv, int t)
2082 {
2083     int ind1, n;
2084     int v, *p;
2085
2086     v = vtop->r & VT_VALMASK;
2087     if (v == VT_CMP) {
2088         /* fast case : can jump directly since flags are set */
2089         // C67 uses B2 sort of as flags register
2090         ind1 = ind;
2091         C67_MVKL(C67_A0, t);    //r=reg to load, constant
2092         C67_MVKH(C67_A0, t);    //r=reg to load, constant
2093
2094         if (C67_compare_reg != TREG_EAX &&      // check if not already in a conditional test reg
2095             C67_compare_reg != TREG_EDX &&
2096             C67_compare_reg != TREG_ST0 && C67_compare_reg != C67_B2) {
2097             C67_MV(C67_compare_reg, C67_B2);
2098             C67_compare_reg = C67_B2;
2099         }
2100
2101         C67_IREG_B_REG(C67_invert_test ^ inv, C67_compare_reg, C67_A0); // [!R] B.S2x  A0
2102         C67_NOP(5);
2103         t = ind1;               //return where we need to patch
2104
2105     } else if (v == VT_JMP || v == VT_JMPI) {
2106         /* && or || optimization */
2107         if ((v & 1) == inv) {
2108             /* insert vtop->c jump list in t */
2109             p = &vtop->c.i;
2110
2111             // I guess the idea is to traverse to the
2112             // null at the end of the list and store t
2113             // there
2114
2115             n = *p;
2116             while (n != 0) {
2117                 p = (int *) (cur_text_section->data + n);
2118
2119                 // extract 32 bit address from MVKH/MVKL
2120                 n = ((*p >> 7) & 0xffff);
2121                 n |= ((*(p + 1) >> 7) & 0xffff) << 16;
2122             }
2123             *p |= (t & 0xffff) << 7;
2124             *(p + 1) |= ((t >> 16) & 0xffff) << 7;
2125             t = vtop->c.i;
2126
2127         } else {
2128             t = gjmp(t);
2129             gsym(vtop->c.i);
2130         }
2131     } else {
2132         if (is_float(vtop->type.t)) {
2133             vpushi(0);
2134             gen_op(TOK_NE);
2135         }
2136         if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
2137             /* constant jmp optimization */
2138             if ((vtop->c.i != 0) != inv)
2139                 t = gjmp(t);
2140         } else {
2141             // I think we need to get the value on the stack
2142             // into a register, test it, and generate a branch
2143             // return the address of the branch, so it can be
2144             // later patched
2145
2146             v = gv(RC_INT);     // get value into a reg 
2147             ind1 = ind;
2148             C67_MVKL(C67_A0, t);        //r=reg to load, constant
2149             C67_MVKH(C67_A0, t);        //r=reg to load, constant
2150
2151             if (v != TREG_EAX &&        // check if not already in a conditional test reg
2152                 v != TREG_EDX && v != TREG_ST0 && v != C67_B2) {
2153                 C67_MV(v, C67_B2);
2154                 v = C67_B2;
2155             }
2156
2157             C67_IREG_B_REG(inv, v, C67_A0);     // [!R] B.S2x  A0
2158             C67_NOP(5);
2159             t = ind1;           //return where we need to patch
2160             ind1 = ind;
2161         }
2162     }
2163     vtop--;
2164     return t;
2165 }
2166
2167 /* generate an integer binary operation */
2168 void gen_opi(int op)
2169 {
2170     int r, fr, opc, t;
2171
2172     switch (op) {
2173     case '+':
2174     case TOK_ADDC1:             /* add with carry generation */
2175         opc = 0;
2176       gen_op8:
2177
2178
2179 // C67 can't do const compares, must load into a reg
2180 // so just go to gv2 directly - tktk
2181
2182
2183
2184         if (op >= TOK_ULT && op <= TOK_GT)
2185             gv2(RC_INT_BSIDE, RC_INT);  // make sure r (src1) is on the B Side of CPU
2186         else
2187             gv2(RC_INT, RC_INT);
2188
2189         r = vtop[-1].r;
2190         fr = vtop[0].r;
2191
2192         C67_compare_reg = C67_B2;
2193
2194
2195         if (op == TOK_LT) {
2196             C67_CMPLT(r, fr, C67_B2);
2197             C67_invert_test = FALSE;
2198         } else if (op == TOK_GE) {
2199             C67_CMPLT(r, fr, C67_B2);
2200             C67_invert_test = TRUE;
2201         } else if (op == TOK_GT) {
2202             C67_CMPGT(r, fr, C67_B2);
2203             C67_invert_test = FALSE;
2204         } else if (op == TOK_LE) {
2205             C67_CMPGT(r, fr, C67_B2);
2206             C67_invert_test = TRUE;
2207         } else if (op == TOK_EQ) {
2208             C67_CMPEQ(r, fr, C67_B2);
2209             C67_invert_test = FALSE;
2210         } else if (op == TOK_NE) {
2211             C67_CMPEQ(r, fr, C67_B2);
2212             C67_invert_test = TRUE;
2213         } else if (op == TOK_ULT) {
2214             C67_CMPLTU(r, fr, C67_B2);
2215             C67_invert_test = FALSE;
2216         } else if (op == TOK_UGE) {
2217             C67_CMPLTU(r, fr, C67_B2);
2218             C67_invert_test = TRUE;
2219         } else if (op == TOK_UGT) {
2220             C67_CMPGTU(r, fr, C67_B2);
2221             C67_invert_test = FALSE;
2222         } else if (op == TOK_ULE) {
2223             C67_CMPGTU(r, fr, C67_B2);
2224             C67_invert_test = TRUE;
2225         } else if (op == '+')
2226             C67_ADD(fr, r);     // ADD  r,fr,r
2227         else if (op == '-')
2228             C67_SUB(fr, r);     // SUB  r,fr,r
2229         else if (op == '&')
2230             C67_AND(fr, r);     // AND  r,fr,r
2231         else if (op == '|')
2232             C67_OR(fr, r);      // OR  r,fr,r
2233         else if (op == '^')
2234             C67_XOR(fr, r);     // XOR  r,fr,r
2235         else
2236             ALWAYS_ASSERT(FALSE);
2237
2238         vtop--;
2239         if (op >= TOK_ULT && op <= TOK_GT) {
2240             vtop->r = VT_CMP;
2241             vtop->c.i = op;
2242         }
2243         break;
2244     case '-':
2245     case TOK_SUBC1:             /* sub with carry generation */
2246         opc = 5;
2247         goto gen_op8;
2248     case TOK_ADDC2:             /* add with carry use */
2249         opc = 2;
2250         goto gen_op8;
2251     case TOK_SUBC2:             /* sub with carry use */
2252         opc = 3;
2253         goto gen_op8;
2254     case '&':
2255         opc = 4;
2256         goto gen_op8;
2257     case '^':
2258         opc = 6;
2259         goto gen_op8;
2260     case '|':
2261         opc = 1;
2262         goto gen_op8;
2263     case '*':
2264     case TOK_UMULL:
2265         gv2(RC_INT, RC_INT);
2266         r = vtop[-1].r;
2267         fr = vtop[0].r;
2268         vtop--;
2269         C67_MPYI(fr, r);        // 32 bit bultiply  fr,r,fr
2270         C67_NOP(8);             // NOP 8 for worst case
2271         break;
2272     case TOK_SHL:
2273         gv2(RC_INT_BSIDE, RC_INT_BSIDE);        // shift amount must be on same side as dst
2274         r = vtop[-1].r;
2275         fr = vtop[0].r;
2276         vtop--;
2277         C67_SHL(fr, r);         // arithmetic/logical shift
2278         break;
2279
2280     case TOK_SHR:
2281         gv2(RC_INT_BSIDE, RC_INT_BSIDE);        // shift amount must be on same side as dst
2282         r = vtop[-1].r;
2283         fr = vtop[0].r;
2284         vtop--;
2285         C67_SHRU(fr, r);        // logical shift
2286         break;
2287
2288     case TOK_SAR:
2289         gv2(RC_INT_BSIDE, RC_INT_BSIDE);        // shift amount must be on same side as dst
2290         r = vtop[-1].r;
2291         fr = vtop[0].r;
2292         vtop--;
2293         C67_SHR(fr, r);         // arithmetic shift
2294         break;
2295
2296     case '/':
2297         t = TOK__divi;
2298       call_func:
2299         vswap();
2300         /* call generic idiv function */
2301         vpush_global_sym(&func_old_type, t);
2302         vrott(3);
2303         gfunc_call(2);
2304         vpushi(0);
2305         vtop->r = REG_IRET;
2306         vtop->r2 = VT_CONST;
2307         break;
2308     case TOK_UDIV:
2309     case TOK_PDIV:
2310         t = TOK__divu;
2311         goto call_func;
2312     case '%':
2313         t = TOK__remi;
2314         goto call_func;
2315     case TOK_UMOD:
2316         t = TOK__remu;
2317         goto call_func;
2318
2319     default:
2320         opc = 7;
2321         goto gen_op8;
2322     }
2323 }
2324
2325 /* generate a floating point operation 'v = t1 op t2' instruction. The
2326    two operands are guaranted to have the same floating point type */
2327 /* XXX: need to use ST1 too */
2328 void gen_opf(int op)
2329 {
2330     int ft, fc, fr, r;
2331
2332     if (op >= TOK_ULT && op <= TOK_GT)
2333         gv2(RC_EDX, RC_EAX);    // make sure src2 is on b side
2334     else
2335         gv2(RC_FLOAT, RC_FLOAT);        // make sure src2 is on b side
2336
2337     ft = vtop->type.t;
2338     fc = vtop->c.ul;
2339     r = vtop->r;
2340     fr = vtop[-1].r;
2341
2342
2343     if ((ft & VT_BTYPE) == VT_LDOUBLE)
2344         tcc_error("long doubles not supported");
2345
2346     if (op >= TOK_ULT && op <= TOK_GT) {
2347
2348         r = vtop[-1].r;
2349         fr = vtop[0].r;
2350
2351         C67_compare_reg = C67_B2;
2352
2353         if (op == TOK_LT) {
2354             if ((ft & VT_BTYPE) == VT_DOUBLE)
2355                 C67_CMPLTDP(r, fr, C67_B2);
2356             else
2357                 C67_CMPLTSP(r, fr, C67_B2);
2358
2359             C67_invert_test = FALSE;
2360         } else if (op == TOK_GE) {
2361             if ((ft & VT_BTYPE) == VT_DOUBLE)
2362                 C67_CMPLTDP(r, fr, C67_B2);
2363             else
2364                 C67_CMPLTSP(r, fr, C67_B2);
2365
2366             C67_invert_test = TRUE;
2367         } else if (op == TOK_GT) {
2368             if ((ft & VT_BTYPE) == VT_DOUBLE)
2369                 C67_CMPGTDP(r, fr, C67_B2);
2370             else
2371                 C67_CMPGTSP(r, fr, C67_B2);
2372
2373             C67_invert_test = FALSE;
2374         } else if (op == TOK_LE) {
2375             if ((ft & VT_BTYPE) == VT_DOUBLE)
2376                 C67_CMPGTDP(r, fr, C67_B2);
2377             else
2378                 C67_CMPGTSP(r, fr, C67_B2);
2379
2380             C67_invert_test = TRUE;
2381         } else if (op == TOK_EQ) {
2382             if ((ft & VT_BTYPE) == VT_DOUBLE)
2383                 C67_CMPEQDP(r, fr, C67_B2);
2384             else
2385                 C67_CMPEQSP(r, fr, C67_B2);
2386
2387             C67_invert_test = FALSE;
2388         } else if (op == TOK_NE) {
2389             if ((ft & VT_BTYPE) == VT_DOUBLE)
2390                 C67_CMPEQDP(r, fr, C67_B2);
2391             else
2392                 C67_CMPEQSP(r, fr, C67_B2);
2393
2394             C67_invert_test = TRUE;
2395         } else {
2396             ALWAYS_ASSERT(FALSE);
2397         }
2398         vtop->r = VT_CMP;       // tell TCC that result is in "flags" actually B2
2399     } else {
2400         if (op == '+') {
2401             if ((ft & VT_BTYPE) == VT_DOUBLE) {
2402                 C67_ADDDP(r, fr);       // ADD  fr,r,fr
2403                 C67_NOP(6);
2404             } else {
2405                 C67_ADDSP(r, fr);       // ADD  fr,r,fr
2406                 C67_NOP(3);
2407             }
2408             vtop--;
2409         } else if (op == '-') {
2410             if ((ft & VT_BTYPE) == VT_DOUBLE) {
2411                 C67_SUBDP(r, fr);       // SUB  fr,r,fr
2412                 C67_NOP(6);
2413             } else {
2414                 C67_SUBSP(r, fr);       // SUB  fr,r,fr
2415                 C67_NOP(3);
2416             }
2417             vtop--;
2418         } else if (op == '*') {
2419             if ((ft & VT_BTYPE) == VT_DOUBLE) {
2420                 C67_MPYDP(r, fr);       // MPY  fr,r,fr
2421                 C67_NOP(9);
2422             } else {
2423                 C67_MPYSP(r, fr);       // MPY  fr,r,fr
2424                 C67_NOP(3);
2425             }
2426             vtop--;
2427         } else if (op == '/') {
2428             if ((ft & VT_BTYPE) == VT_DOUBLE) {
2429                 // must call intrinsic DP floating point divide
2430                 vswap();
2431                 /* call generic idiv function */
2432                 vpush_global_sym(&func_old_type, TOK__divd);
2433                 vrott(3);
2434                 gfunc_call(2);
2435                 vpushi(0);
2436                 vtop->r = REG_FRET;
2437                 vtop->r2 = REG_LRET;
2438
2439             } else {
2440                 // must call intrinsic SP floating point divide
2441                 vswap();
2442                 /* call generic idiv function */
2443                 vpush_global_sym(&func_old_type, TOK__divf);
2444                 vrott(3);
2445                 gfunc_call(2);
2446                 vpushi(0);
2447                 vtop->r = REG_FRET;
2448                 vtop->r2 = VT_CONST;
2449             }
2450         } else
2451             ALWAYS_ASSERT(FALSE);
2452
2453
2454     }
2455 }
2456
2457
2458 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
2459    and 'long long' cases. */
2460 void gen_cvt_itof(int t)
2461 {
2462     int r;
2463
2464     gv(RC_INT);
2465     r = vtop->r;
2466
2467     if ((t & VT_BTYPE) == VT_DOUBLE) {
2468         if (t & VT_UNSIGNED)
2469             C67_INTDPU(r, r);
2470         else
2471             C67_INTDP(r, r);
2472
2473         C67_NOP(4);
2474         vtop->type.t = VT_DOUBLE;
2475     } else {
2476         if (t & VT_UNSIGNED)
2477             C67_INTSPU(r, r);
2478         else
2479             C67_INTSP(r, r);
2480         C67_NOP(3);
2481         vtop->type.t = VT_FLOAT;
2482     }
2483
2484 }
2485
2486 /* convert fp to int 't' type */
2487 /* XXX: handle long long case */
2488 void gen_cvt_ftoi(int t)
2489 {
2490     int r;
2491
2492     gv(RC_FLOAT);
2493     r = vtop->r;
2494
2495     if (t != VT_INT)
2496         tcc_error("long long not supported");
2497     else {
2498         if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) {
2499             C67_DPTRUNC(r, r);
2500             C67_NOP(3);
2501         } else {
2502             C67_SPTRUNC(r, r);
2503             C67_NOP(3);
2504         }
2505
2506         vtop->type.t = VT_INT;
2507
2508     }
2509 }
2510
2511 /* convert from one floating point type to another */
2512 void gen_cvt_ftof(int t)
2513 {
2514     int r, r2;
2515
2516     if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE &&
2517         (t & VT_BTYPE) == VT_FLOAT) {
2518         // convert double to float
2519
2520         gv(RC_FLOAT);           // get it in a register pair
2521
2522         r = vtop->r;
2523
2524         C67_DPSP(r, r);         // convert it to SP same register
2525         C67_NOP(3);
2526
2527         vtop->type.t = VT_FLOAT;
2528         vtop->r2 = VT_CONST;    // set this as unused
2529     } else if ((vtop->type.t & VT_BTYPE) == VT_FLOAT &&
2530                (t & VT_BTYPE) == VT_DOUBLE) {
2531         // convert float to double
2532
2533         gv(RC_FLOAT);           // get it in a register
2534
2535         r = vtop->r;
2536
2537         if (r == TREG_EAX) {    // make sure the paired reg is avail
2538             r2 = get_reg(RC_ECX);
2539         } else if (r == TREG_EDX) {
2540             r2 = get_reg(RC_ST0);
2541         } else {
2542             ALWAYS_ASSERT(FALSE);
2543             r2 = 0; /* avoid warning */
2544         }
2545
2546         C67_SPDP(r, r);         // convert it to DP same register
2547         C67_NOP(1);
2548
2549         vtop->type.t = VT_DOUBLE;
2550         vtop->r2 = r2;          // set this as unused
2551     } else {
2552         ALWAYS_ASSERT(FALSE);
2553     }
2554 }
2555
2556 /* computed goto support */
2557 void ggoto(void)
2558 {
2559     gcall_or_jmp(1);
2560     vtop--;
2561 }
2562
2563 /* Save the stack pointer onto the stack and return the location of its address */
2564 ST_FUNC void gen_vla_sp_save(int addr) {
2565     tcc_error("variable length arrays unsupported for this target");
2566 }
2567
2568 /* Restore the SP from a location on the stack */
2569 ST_FUNC void gen_vla_sp_restore(int addr) {
2570     tcc_error("variable length arrays unsupported for this target");
2571 }
2572
2573 /* Subtract from the stack pointer, and push the resulting value onto the stack */
2574 ST_FUNC void gen_vla_alloc(CType *type, int align) {
2575     tcc_error("variable length arrays unsupported for this target");
2576 }
2577
2578 /* end of C67 code generator */
2579 /*************************************************************/
2580 #endif
2581 /*************************************************************/