65af1a65c5f4c308b656b5d64cf2706c8dbcdbe6
[fw/sdcc] / src / ds390 / main.c
1 /** @file main.c
2     ds390 specific general functions.
3
4     Note that mlh prepended _ds390_ on the static functions.  Makes
5     it easier to set a breakpoint using the debugger.
6 */
7 #include "common.h"
8 #include "main.h"
9 #include "ralloc.h"
10 #include "gen.h"
11 #include "BuildCmd.h"
12 #include "MySystem.h"
13 #include "../SDCCutil.h"
14 #include "../SDCCglobl.h"
15 static char _defaultRules[] =
16 {
17 #include "peeph.rul"
18 };
19
20 /* list of key words used by msc51 */
21 static char *_ds390_keywords[] =
22 {
23   "at",
24   "bit",
25   "code",
26   "critical",
27   "data",
28   "far",
29   "idata",
30   "interrupt",
31   "near",
32   "pdata",
33   "reentrant",
34   "sfr",
35   "sbit",
36   "using",
37   "xdata",
38   "_data",
39   "_code",
40   "_generic",
41   "_near",
42   "_xdata",
43   "_pdata",
44   "_idata",
45   "_naked",
46   NULL
47 };
48
49 static builtins __ds390_builtins[] = {
50     { "__builtin_memcpy_x2x","v",3,{"cx*","cx*","i"}}, /* void __builtin_memcpy_x2x (xdata char *,xdata char *,int) */
51     { "__builtin_memcpy_c2x","v",3,{"cx*","cp*","i"}}, /* void __builtin_memcpy_c2x (xdata char *,code  char *,int) */
52     { "__builtin_memset_x","v",3,{"cx*","c","i"}},     /* void __builtin_memset     (xdata char *,char,int)         */
53     /* __builtin_inp - used to read from a memory mapped port, increment first pointer */
54     { "__builtin_inp","v",3,{"cx*","cx*","i"}},        /* void __builtin_inp        (xdata char *,xdata char *,int) */
55     /* __builtin_inp - used to write to a memory mapped port, increment first pointer */
56     { "__builtin_outp","v",3,{"cx*","cx*","i"}},       /* void __builtin_outp       (xdata char *,xdata char *,int) */
57     { "__builtin_swapw","us",1,{"us"}},                /* unsigned short __builtin_swapw (unsigned short) */
58     { "__builtin_memcmp_x2x","c",3,{"cx*","cx*","i"}}, /* void __builtin_memcmp_x2x (xdata char *,xdata char *,int) */
59     { "__builtin_memcmp_c2x","c",3,{"cx*","cp*","i"}}, /* void __builtin_memcmp_c2x (xdata char *,code  char *,int) */
60     { NULL , NULL,0, {NULL}}                       /* mark end of table */
61 };
62 void ds390_assignRegisters (eBBlock ** ebbs, int count);
63
64 static int regParmFlg = 0;      /* determine if we can register a parameter */
65
66 static void
67 _ds390_init (void)
68 {
69   asm_addTree (&asm_asxxxx_mapping);
70 }
71
72 static void
73 _ds390_reset_regparm ()
74 {
75   regParmFlg = 0;
76 }
77
78 static int
79 _ds390_regparm (sym_link * l)
80 {
81     if (options.parms_in_bank1 == 0) {
82         /* simple can pass only the first parameter in a register */
83         if (regParmFlg)
84             return 0;
85
86         regParmFlg = 1;
87         return 1;
88     } else {
89         int size = getSize(l);
90         int remain ;
91
92         /* first one goes the usual way to DPTR */
93         if (regParmFlg == 0) {
94             regParmFlg += 4 ;
95             return 1;
96         }
97         /* second one onwards goes to RB1_0 thru RB1_7 */
98         remain = regParmFlg - 4;
99         if (size > (8 - remain)) {
100             regParmFlg = 12 ;
101             return 0;
102         }
103         regParmFlg += size ;
104         return regParmFlg - size + 1;
105     }
106 }
107
108 static bool
109 _ds390_parseOptions (int *pargc, char **argv, int *i)
110 {
111   /* TODO: allow port-specific command line options to specify
112    * segment names here.
113    */
114   return FALSE;
115 }
116
117 static void
118 _ds390_finaliseOptions (void)
119 {
120   if (options.noXinitOpt) {
121     port->genXINIT=0;
122   }
123
124   /* Hack-o-matic: if we are using the flat24 model,
125    * adjust pointer sizes.
126    */
127   if (options.model != MODEL_FLAT24)  {
128       fprintf (stderr,
129                "*** warning: ds390 port small and large model experimental.\n");
130       if (options.model == MODEL_LARGE)
131       {
132         port->mem.default_local_map = xdata;
133         port->mem.default_globl_map = xdata;
134       }
135       else
136       {
137         port->mem.default_local_map = data;
138         port->mem.default_globl_map = data;
139       }
140   }
141   else {
142     port->s.fptr_size = 3;
143     port->s.gptr_size = 4;
144
145     port->stack.isr_overhead += 2;      /* Will save dpx on ISR entry. */
146
147     port->stack.call_overhead += 2;     /* This acounts for the extra byte
148                                  * of return addres on the stack.
149                                  * but is ugly. There must be a
150                                  * better way.
151                                  */
152
153     port->mem.default_local_map = xdata;
154     port->mem.default_globl_map = xdata;
155
156     if (!options.stack10bit)
157     {
158     fprintf (stderr,
159              "*** error: ds390 port only supports the 10 bit stack mode.\n");
160     } else {
161         if (!options.stack_loc) options.stack_loc = 0x400008;
162     }
163
164     /* generate native code 16*16 mul/div */
165     if (options.useAccelerator)
166             port->support.muldiv=2;
167     else
168             port->support.muldiv=1;
169
170      /* Fixup the memory map for the stack; it is now in
171      * far space and requires a FPOINTER to access it.
172      */
173     istack->fmap = 1;
174     istack->ptrType = FPOINTER;
175
176     if (options.parms_in_bank1) {
177         addSet(&preArgvSet, Safe_strdup("-DSDCC_PARMS_IN_BANK1"));
178     }
179   }  /* MODEL_FLAT24 */
180 }
181
182 static void
183 _ds390_setDefaultOptions (void)
184 {
185   options.model=MODEL_FLAT24;
186   options.stack10bit=1;
187 }
188
189 static const char *
190 _ds390_getRegName (struct regs *reg)
191 {
192   if (reg)
193     return reg->name;
194   return "err";
195 }
196
197 extern char * iComments2;
198
199 static void
200 _ds390_genAssemblerPreamble (FILE * of)
201 {
202       fputs (iComments2, of);
203       fputs ("; CPU specific extensions\n",of);
204       fputs (iComments2, of);
205
206       if (options.model == MODEL_FLAT24)
207         fputs (".flat24 on\t\t; 24 bit flat addressing\n", of);
208
209       fputs ("dpl1\t=\t0x84\n", of);
210       fputs ("dph1\t=\t0x85\n", of);
211       fputs ("dps\t=\t0x86\n", of);
212       fputs ("dpx\t=\t0x93\n", of);
213       fputs ("dpx1\t=\t0x95\n", of);
214       fputs ("esp\t=\t0x9B\n", of);
215       fputs ("ap\t=\t0x9C\n", of);
216       fputs ("_ap\t=\t0x9C\n", of);
217       fputs ("mcnt0\t=\t0xD1\n", of);
218       fputs ("mcnt1\t=\t0xD2\n", of);
219       fputs ("ma\t=\t0xD3\n", of);
220       fputs ("mb\t=\t0xD4\n", of);
221       fputs ("mc\t=\t0xD5\n", of);
222       fputs ("F1\t=\t0xD1\t; user flag\n", of);
223       if (options.parms_in_bank1) {
224           int i ;
225           for (i=0; i < 8 ; i++ )
226               fprintf (of,"b1_%d\t=\t0x%02X\n",i,8+i);
227       }
228 }
229
230 /* Generate interrupt vector table. */
231 static int
232 _ds390_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts)
233 {
234   int i;
235
236   if (options.model != MODEL_FLAT24)
237     {
238       /* Let the default code handle it. */
239       return FALSE;
240     }
241
242   fprintf (of, "\tajmp\t__reset_vect\n");
243
244   /* now for the other interrupts */
245   for (i = 0; i < maxInterrupts; i++)
246     {
247       if (interrupts[i])
248         {
249           fprintf (of, "\tljmp\t%s\n\t.ds\t4\n", interrupts[i]->rname);
250         }
251       else
252         {
253           fprintf (of, "\treti\n\t.ds\t7\n");
254         }
255     }
256
257   fprintf (of, "__reset_vect:\n\tljmp\t__sdcc_gsinit_startup\n");
258
259   return TRUE;
260 }
261
262 /* Generate code to copy XINIT to XISEG */
263 static void _ds390_genXINIT (FILE * of) {
264   fprintf (of, ";       _ds390_genXINIT() start\n");
265   fprintf (of, "        mov     a,#l_XINIT\n");
266   fprintf (of, "        orl     a,#l_XINIT>>8\n");
267   fprintf (of, "        jz      00003$\n");
268   fprintf (of, "        mov     a,#s_XINIT\n");
269   fprintf (of, "        add     a,#l_XINIT\n");
270   fprintf (of, "        mov     r1,a\n");
271   fprintf (of, "        mov     a,#s_XINIT>>8\n");
272   fprintf (of, "        addc    a,#l_XINIT>>8\n");
273   fprintf (of, "        mov     r2,a\n");
274   fprintf (of, "        mov     dptr,#s_XINIT\n");
275   fprintf (of, "        mov     dps,#0x21\n");
276   fprintf (of, "        mov     dptr,#s_XISEG\n");
277   fprintf (of, "00001$: clr     a\n");
278   fprintf (of, "        movc    a,@a+dptr\n");
279   fprintf (of, "        movx    @dptr,a\n");
280   fprintf (of, "        inc     dptr\n");
281   fprintf (of, "        inc     dptr\n");
282   fprintf (of, "00002$: mov     a,dpl\n");
283   fprintf (of, "        cjne    a,ar1,00001$\n");
284   fprintf (of, "        mov     a,dph\n");
285   fprintf (of, "        cjne    a,ar2,00001$\n");
286   fprintf (of, "        mov     dps,#0\n");
287   fprintf (of, "00003$:\n");
288   fprintf (of, ";       _ds390_genXINIT() end\n");
289 }
290
291 /* Do CSE estimation */
292 static bool cseCostEstimation (iCode *ic, iCode *pdic)
293 {
294     operand *result = IC_RESULT(ic);
295     //operand *right  = IC_RIGHT(ic);
296     //operand *left   = IC_LEFT(ic);
297     sym_link *result_type = operandType(result);
298     //sym_link *right_type  = (right ? operandType(right) : 0);
299     //sym_link *left_type   = (left  ? operandType(left)  : 0);
300
301     /* if it is a pointer then return ok for now */
302     if (IC_RESULT(ic) && IS_PTR(result_type)) return 1;
303
304     /* if bitwise | add & subtract then no since mcs51 is pretty good at it
305        so we will cse only if they are local (i.e. both ic & pdic belong to
306        the same basic block */
307     if (IS_BITWISE_OP(ic) || ic->op == '+' || ic->op == '-') {
308         /* then if they are the same Basic block then ok */
309         if (ic->eBBlockNum == pdic->eBBlockNum) return 1;
310         else return 0;
311     }
312
313     /* for others it is cheaper to do the cse */
314     return 1;
315 }
316
317 bool _ds390_nativeMulCheck(iCode *ic, sym_link *left, sym_link *right)
318 {
319     return FALSE; // #STUB
320 }
321
322 /* Indicate which extended bit operations this port supports */
323 static bool
324 hasExtBitOp (int op, int size)
325 {
326   if (op == RRC
327       || op == RLC
328       || op == GETHBIT
329       || (op == SWAP && size <= 2)
330      )
331     return TRUE;
332   else
333     return FALSE;
334 }
335
336 /* Indicate the expense of an access to an output storage class */
337 static int
338 oclsExpense (struct memmap *oclass)
339 {
340   if (IN_FARSPACE(oclass))
341     return 1;
342
343   return 0;
344 }
345
346 static int
347 instructionSize(char *inst, char *op1, char *op2)
348 {
349   int isflat24 = (options.model == MODEL_FLAT24);
350
351   #define ISINST(s) (strncmp(inst, (s), sizeof(s)-1) == 0)
352   #define IS_A(s) (*(s) == 'a' && *(s+1) == '\0')
353   #define IS_C(s) (*(s) == 'c' && *(s+1) == '\0')
354   #define IS_Rn(s) (*(s) == 'r' && *(s+1) >= '0' && *(s+1) <= '7')
355   #define IS_atRi(s) (*(s) == '@' && *(s+1) == 'r')
356
357   /* Based on the current (2003-08-22) code generation for the
358      small library, the top instruction probability is:
359
360        57% mov/movx/movc
361         6% push
362         6% pop
363         4% inc
364         4% lcall
365         4% add
366         3% clr
367         2% subb
368   */
369   /* mov, push, & pop are the 69% of the cases. Check them first! */
370   if (ISINST ("mov"))
371     {
372       if (*(inst+3)=='x') return 1; /* movx */
373       if (*(inst+3)=='c') return 1; /* movc */
374       if (IS_C (op1) || IS_C (op2)) return 2;
375       if (IS_A (op1))
376         {
377           if (IS_Rn (op2) || IS_atRi (op2)) return 1;
378           return 2;
379         }
380       if (IS_Rn(op1) || IS_atRi(op1))
381         {
382           if (IS_A(op2)) return 1;
383           return 2;
384         }
385       if (strcmp (op1, "dptr") == 0) return 3+isflat24;
386       if (IS_A (op2) || IS_Rn (op2) || IS_atRi (op2)) return 2;
387       return 3;
388     }
389
390   if (ISINST ("push")) return 2;
391   if (ISINST ("pop")) return 2;
392
393   if (ISINST ("lcall")) return 3+isflat24;
394   if (ISINST ("ret")) return 1;
395   if (ISINST ("ljmp")) return 3+isflat24;
396   if (ISINST ("sjmp")) return 2;
397   if (ISINST ("rlc")) return 1;
398   if (ISINST ("rrc")) return 1;
399   if (ISINST ("rl")) return 1;
400   if (ISINST ("rr")) return 1;
401   if (ISINST ("swap")) return 1;
402   if (ISINST ("jc")) return 2;
403   if (ISINST ("jnc")) return 2;
404   if (ISINST ("jb")) return 3;
405   if (ISINST ("jnb")) return 3;
406   if (ISINST ("jbc")) return 3;
407   if (ISINST ("jmp")) return 1; // always jmp @a+dptr
408   if (ISINST ("jz")) return 2;
409   if (ISINST ("jnz")) return 2;
410   if (ISINST ("cjne")) return 3;
411   if (ISINST ("mul")) return 1;
412   if (ISINST ("div")) return 1;
413   if (ISINST ("da")) return 1;
414   if (ISINST ("xchd")) return 1;
415   if (ISINST ("reti")) return 1;
416   if (ISINST ("nop")) return 1;
417   if (ISINST ("acall")) return 2+isflat24;
418   if (ISINST ("ajmp")) return 2+isflat24;
419
420
421   if (ISINST ("add") || ISINST ("addc") || ISINST ("subb") || ISINST ("xch"))
422     {
423       if (IS_Rn(op2) || IS_atRi(op2)) return 1;
424       return 2;
425     }
426   if (ISINST ("inc") || ISINST ("dec"))
427     {
428       if (IS_A(op1) || IS_Rn(op1) || IS_atRi(op1)) return 1;
429       if (strcmp(op1, "dptr") == 0) return 1;
430       return 2;
431     }
432   if (ISINST ("anl") || ISINST ("orl") || ISINST ("xrl"))
433     {
434       if (IS_C(op1)) return 2;
435       if (IS_A(op1))
436         {
437           if (IS_Rn(op2) || IS_atRi(op2)) return 1;
438           return 2;
439         }
440       else
441         {
442           if (IS_A(op2)) return 2;
443           return 3;
444         }
445     }
446   if (ISINST ("clr") || ISINST ("setb") || ISINST ("cpl"))
447     {
448       if (IS_A(op1) || IS_C(op1)) return 1;
449       return 2;
450     }
451   if (ISINST ("djnz"))
452     {
453       if (IS_Rn(op1)) return 2;
454       return 3;
455     }
456
457   /* If the instruction is unrecognized, we shouldn't try to optimize. */
458   /* Return a large value to discourage optimization.                  */
459   return 999;
460 }
461
462 asmLineNode *
463 ds390newAsmLineNode (int currentDPS)
464 {
465   asmLineNode *aln;
466
467   aln = Safe_alloc ( sizeof (asmLineNode));
468   aln->size = 0;
469   aln->regsRead = NULL;
470   aln->regsWritten = NULL;
471   aln->initialized = 0;
472   aln->currentDPS = currentDPS;
473
474   return aln;
475 }
476
477
478 typedef struct ds390operanddata
479   {
480     char name[6];
481     int regIdx1;
482     int regIdx2;
483   }
484 ds390operanddata;
485
486 static ds390operanddata ds390operandDataTable[] =
487   {
488     {"_ap", AP_IDX, -1},
489     {"a", A_IDX, -1},
490     {"ab", A_IDX, B_IDX},
491     {"ac", CND_IDX, -1},
492     {"ap", AP_IDX, -1},
493     {"acc", A_IDX, -1},
494     {"ar0", R0_IDX, -1},
495     {"ar1", R1_IDX, -1},
496     {"ar2", R2_IDX, -1},
497     {"ar3", R3_IDX, -1},
498     {"ar4", R4_IDX, -1},
499     {"ar5", R5_IDX, -1},
500     {"ar6", R6_IDX, -1},
501     {"ar7", R7_IDX, -1},
502     {"b", B_IDX, -1},
503     {"c", CND_IDX, -1},
504     {"cy", CND_IDX, -1},
505     {"dph", DPH_IDX, -1},
506     {"dph0", DPH_IDX, -1},
507     {"dph1", DPH1_IDX, -1},
508     {"dpl", DPL_IDX, -1},
509     {"dpl0", DPL_IDX, -1},
510     {"dpl1", DPL1_IDX, -1},
511 /*  {"dptr", DPL_IDX, DPH_IDX}, */ /* dptr is special, based on currentDPS */
512     {"dps", DPS_IDX, -1},
513     {"dpx", DPX_IDX, -1},
514     {"dpx0", DPX_IDX, -1},
515     {"dpx1", DPX1_IDX, -1},
516     {"f0", CND_IDX, -1},
517     {"f1", CND_IDX, -1},
518     {"ov", CND_IDX, -1},
519     {"p", CND_IDX, -1},
520     {"psw", CND_IDX, -1},
521     {"r0", R0_IDX, -1},
522     {"r1", R1_IDX, -1},
523     {"r2", R2_IDX, -1},
524     {"r3", R3_IDX, -1},
525     {"r4", R4_IDX, -1},
526     {"r5", R5_IDX, -1},
527     {"r6", R6_IDX, -1},
528     {"r7", R7_IDX, -1},
529   };
530
531 static int
532 ds390operandCompare (const void *key, const void *member)
533 {
534   return strcmp((const char *)key, ((ds390operanddata *)member)->name);
535 }
536
537 static void
538 updateOpRW (asmLineNode *aln, char *op, char *optype, int currentDPS)
539 {
540   ds390operanddata *opdat;
541   char *dot;
542   int regIdx1 = -1;
543   int regIdx2 = -1;
544   int regIdx3 = -1;
545
546   dot = strchr(op, '.');
547   if (dot)
548     *dot = '\0';
549
550   opdat = bsearch (op, ds390operandDataTable,
551                    sizeof(ds390operandDataTable)/sizeof(ds390operanddata),
552                    sizeof(ds390operanddata), ds390operandCompare);
553
554   if (opdat)
555     {
556       regIdx1 = opdat->regIdx1;
557       regIdx2 = opdat->regIdx2;
558     }
559   if (!strcmp(op, "dptr"))
560     {
561       if (!currentDPS)
562         {
563           regIdx1 = DPL_IDX;
564           regIdx2 = DPH_IDX;
565           regIdx3 = DPX_IDX;
566         }
567       else
568         {
569           regIdx1 = DPL1_IDX;
570           regIdx2 = DPH1_IDX;
571           regIdx3 = DPX1_IDX;
572         }
573     }
574
575   if (strchr(optype,'r'))
576     {
577       if (regIdx1 >= 0)
578         aln->regsRead = bitVectSetBit (aln->regsRead, regIdx1);
579       if (regIdx2 >= 0)
580         aln->regsRead = bitVectSetBit (aln->regsRead, regIdx2);
581       if (regIdx3 >= 0)
582         aln->regsRead = bitVectSetBit (aln->regsRead, regIdx3);
583     }
584   if (strchr(optype,'w'))
585     {
586       if (regIdx1 >= 0)
587         aln->regsWritten = bitVectSetBit (aln->regsWritten, regIdx1);
588       if (regIdx2 >= 0)
589         aln->regsWritten = bitVectSetBit (aln->regsWritten, regIdx2);
590       if (regIdx3 >= 0)
591         aln->regsWritten = bitVectSetBit (aln->regsWritten, regIdx3);
592     }
593   if (op[0] == '@')
594     {
595       if (!strcmp(op, "@r0"))
596         aln->regsRead = bitVectSetBit (aln->regsRead, R0_IDX);
597       if (!strcmp(op, "@r1"))
598         aln->regsRead = bitVectSetBit (aln->regsRead, R1_IDX);
599       if (strstr(op, "dptr"))
600         {
601           if (!currentDPS)
602             {
603               aln->regsRead = bitVectSetBit (aln->regsRead, DPL_IDX);
604               aln->regsRead = bitVectSetBit (aln->regsRead, DPH_IDX);
605               aln->regsRead = bitVectSetBit (aln->regsRead, DPX_IDX);
606             }
607           else
608             {
609               aln->regsRead = bitVectSetBit (aln->regsRead, DPL1_IDX);
610               aln->regsRead = bitVectSetBit (aln->regsRead, DPH1_IDX);
611               aln->regsRead = bitVectSetBit (aln->regsRead, DPX1_IDX);
612             }
613         }
614       if (strstr(op, "a+"))
615         aln->regsRead = bitVectSetBit (aln->regsRead, A_IDX);
616     }
617 }
618
619 typedef struct ds390opcodedata
620   {
621     char name[6];
622     char class[3];
623     char pswtype[3];
624     char op1type[3];
625     char op2type[3];
626   }
627 ds390opcodedata;
628
629 static ds390opcodedata ds390opcodeDataTable[] =
630   {
631     {"acall","j", "",   "",   ""},
632     {"add",  "",  "w",  "rw", "r"},
633     {"addc", "",  "rw", "rw", "r"},
634     {"ajmp", "j", "",   "",   ""},
635     {"anl",  "",  "",   "rw", "r"},
636     {"cjne", "j", "w",  "r",  "r"},
637     {"clr",  "",  "",   "w",  ""},
638     {"cpl",  "",  "",   "rw", ""},
639     {"da",   "",  "rw", "rw", ""},
640     {"dec",  "",  "",   "rw", ""},
641     {"div",  "",  "w",  "rw", ""},
642     {"djnz", "j", "",  "rw",  ""},
643     {"inc",  "",  "",   "rw", ""},
644     {"jb",   "j", "",   "r",  ""},
645     {"jbc",  "j", "",  "rw",  ""},
646     {"jc",   "j", "",   "",   ""},
647     {"jmp",  "j", "",  "",    ""},
648     {"jnb",  "j", "",   "r",  ""},
649     {"jnc",  "j", "",   "",   ""},
650     {"jnz",  "j", "",  "",    ""},
651     {"jz",   "j", "",  "",    ""},
652     {"lcall","j", "",   "",   ""},
653     {"ljmp", "j", "",   "",   ""},
654     {"mov",  "",  "",   "w",  "r"},
655     {"movc", "",  "",   "w",  "r"},
656     {"movx", "",  "",   "w",  "r"},
657     {"mul",  "",  "w",  "rw", ""},
658     {"nop",  "",  "",   "",   ""},
659     {"orl",  "",  "",   "rw", "r"},
660     {"pop",  "",  "",   "w",  ""},
661     {"push", "",  "",   "r",  ""},
662     {"ret",  "j", "",   "",   ""},
663     {"reti", "j", "",   "",   ""},
664     {"rl",   "",  "",   "rw", ""},
665     {"rlc",  "",  "rw", "rw", ""},
666     {"rr",   "",  "",   "rw", ""},
667     {"rrc",  "",  "rw", "rw", ""},
668     {"setb", "",  "",   "w",  ""},
669     {"sjmp", "j", "",   "",   ""},
670     {"subb", "",  "rw", "rw", "r"},
671     {"swap", "",  "",   "rw", ""},
672     {"xch",  "",  "",   "rw", "rw"},
673     {"xchd", "",  "",   "rw", "rw"},
674     {"xrl",  "",  "",   "rw", "r"},
675   };
676
677 static int
678 ds390opcodeCompare (const void *key, const void *member)
679 {
680   return strcmp((const char *)key, ((ds390opcodedata *)member)->name);
681 }
682
683 static asmLineNode *
684 asmLineNodeFromLineNode (lineNode *ln, int currentDPS)
685 {
686   asmLineNode *aln = ds390newAsmLineNode(currentDPS);
687   char *op, op1[256], op2[256];
688   int opsize;
689   const char *p;
690   char inst[8];
691   ds390opcodedata *opdat;
692
693   aln->initialized = 1;
694
695   p = ln->line;
696
697   while (*p && isspace(*p)) p++;
698   for (op = inst, opsize=1; *p; p++)
699     {
700       if (isspace(*p) || *p == ';' || *p == ':' || *p == '=')
701         break;
702       else
703         if (opsize < sizeof(inst))
704           *op++ = tolower(*p), opsize++;
705     }
706   *op = '\0';
707
708   if (*p == ';' || *p == ':' || *p == '=')
709     return aln;
710
711   while (*p && isspace(*p)) p++;
712   if (*p == '=')
713     return aln;
714
715   for (op = op1, opsize=1; *p && *p != ','; p++)
716     {
717       if (!isspace(*p) && opsize < sizeof(op1))
718         *op++ = tolower(*p), opsize++;
719     }
720   *op = '\0';
721
722   if (*p == ',') p++;
723   for (op = op2, opsize=1; *p && *p != ','; p++)
724     {
725       if (!isspace(*p) && opsize < sizeof(op2))
726         *op++ = tolower(*p), opsize++;
727     }
728   *op = '\0';
729
730   aln->size = instructionSize(inst, op1, op2);
731
732   aln->regsRead = newBitVect (END_IDX);
733   aln->regsWritten = newBitVect (END_IDX);
734
735   opdat = bsearch (inst, ds390opcodeDataTable,
736                    sizeof(ds390opcodeDataTable)/sizeof(ds390opcodedata),
737                    sizeof(ds390opcodedata), ds390opcodeCompare);
738
739   if (opdat)
740     {
741       updateOpRW (aln, op1, opdat->op1type, currentDPS);
742       updateOpRW (aln, op2, opdat->op2type, currentDPS);
743       if (strchr(opdat->pswtype,'r'))
744         aln->regsRead = bitVectSetBit (aln->regsRead, CND_IDX);
745       if (strchr(opdat->pswtype,'w'))
746         aln->regsWritten = bitVectSetBit (aln->regsWritten, CND_IDX);
747     }
748
749   return aln;
750 }
751
752 static void
753 initializeAsmLineNode (lineNode *line)
754 {
755   if (!line->aln)
756     line->aln = asmLineNodeFromLineNode (line, 0);
757   else if (line->aln && !line->aln->initialized)
758     {
759       int currentDPS = line->aln->currentDPS;
760       free(line->aln);
761       line->aln = asmLineNodeFromLineNode (line, currentDPS);
762     }
763 }
764
765 static int
766 getInstructionSize (lineNode *line)
767 {
768   initializeAsmLineNode (line);
769   return line->aln->size;
770 }
771
772 static bitVect *
773 getRegsRead (lineNode *line)
774 {
775   initializeAsmLineNode (line);
776   return line->aln->regsRead;
777 }
778
779 static bitVect *
780 getRegsWritten (lineNode *line)
781 {
782   initializeAsmLineNode (line);
783   return line->aln->regsWritten;
784 }
785
786
787 /** $1 is always the basename.
788     $2 is always the output file.
789     $3 varies
790     $l is the list of extra options that should be there somewhere...
791     MUST be terminated with a NULL.
792 */
793 static const char *_linkCmd[] =
794 {
795   "aslink", "-nf", "\"$1\"", NULL
796 };
797
798 /* $3 is replaced by assembler.debug_opts resp. port->assembler.plain_opts */
799 static const char *_asmCmd[] =
800 {
801   "asx8051", "$l", "$3", "\"$1.asm\"", NULL
802 };
803
804 /* Globals */
805 PORT ds390_port =
806 {
807   TARGET_ID_DS390,
808   "ds390",
809   "DS80C390",                   /* Target name */
810   NULL,
811   {
812     glue,
813     TRUE,                       /* Emit glue around main */
814     MODEL_SMALL | MODEL_LARGE | MODEL_FLAT24,
815     MODEL_SMALL
816   },
817   {
818     _asmCmd,
819     NULL,
820     "-plosgffc",                /* Options with debug */
821     "-plosgff",                 /* Options without debug */
822     0,
823     ".asm",
824     NULL                        /* no do_assemble function */
825   },
826   {
827     _linkCmd,
828     NULL,
829     NULL,
830     ".rel",
831     1
832   },
833   {
834     _defaultRules,
835     getInstructionSize,
836     getRegsRead,
837     getRegsWritten
838   },
839   {
840         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
841     1, 2, 2, 4, 1, 2, 3, 1, 4, 4
842   },
843   {
844     "XSEG    (XDATA)",
845     "STACK   (DATA)",
846     "CSEG    (CODE)",
847     "DSEG    (DATA)",
848     "ISEG    (DATA)",
849     "XSEG    (XDATA)",
850     "BSEG    (BIT)",
851     "RSEG    (DATA)",
852     "GSINIT  (CODE)",
853     "OSEG    (OVR,DATA)",
854     "GSFINAL (CODE)",
855     "HOME    (CODE)",
856     "XISEG   (XDATA)", // initialized xdata
857     "XINIT   (CODE)", // a code copy of xiseg
858     NULL,
859     NULL,
860     1
861   },
862   { NULL, NULL },
863   {
864     +1, 1, 4, 1, 1, 0
865   },
866     /* ds390 has an 16 bit mul & div */
867   {
868     2, -1
869   },
870   {
871     ds390_emitDebuggerSymbol
872   },
873   "_",
874   _ds390_init,
875   _ds390_parseOptions,
876   NULL,
877   NULL,
878   _ds390_finaliseOptions,
879   _ds390_setDefaultOptions,
880   ds390_assignRegisters,
881   _ds390_getRegName,
882   _ds390_keywords,
883   _ds390_genAssemblerPreamble,
884   NULL,                         /* no genAssemblerEnd */
885   _ds390_genIVT,
886   _ds390_genXINIT,
887   NULL,                         /* genInitStartup */
888   _ds390_reset_regparm,
889   _ds390_regparm,
890   NULL,
891   NULL,
892   _ds390_nativeMulCheck,
893   hasExtBitOp,                  /* hasExtBitOp */
894   oclsExpense,                  /* oclsExpense */
895   FALSE,
896   TRUE,                         /* little endian */
897   0,                            /* leave lt */
898   0,                            /* leave gt */
899   1,                            /* transform <= to ! > */
900   1,                            /* transform >= to ! < */
901   1,                            /* transform != to !(a == b) */
902   0,                            /* leave == */
903 #if 0 // obsolete, and buggy for != xdata
904   TRUE,                         /* we support array initializers. */
905 #else
906   FALSE,                        /* No array initializer support. */
907 #endif
908   cseCostEstimation,
909   __ds390_builtins,             /* table of builtin functions */
910   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
911   1,                            /* reset labelKey to 1 */
912   1,                            /* globals & local static allowed */
913   PORT_MAGIC
914 };
915
916 /*---------------------------------------------------------------------------------*/
917 /*                               TININative specific                               */
918 /*---------------------------------------------------------------------------------*/
919 /* Globals */
920 static void _tininative_init (void)
921 {
922     asm_addTree (&asm_a390_mapping);
923 }
924
925 static void _tininative_setDefaultOptions (void)
926 {
927     options.model=MODEL_FLAT24;
928     options.stack10bit=1;
929     options.stackAuto = 1;
930 }
931
932 static void _tininative_finaliseOptions (void)
933 {
934     /* Hack-o-matic: if we are using the flat24 model,
935      * adjust pointer sizes.
936      */
937     if (options.model != MODEL_FLAT24)  {
938         options.model = MODEL_FLAT24 ;
939         fprintf(stderr,"TININative supports only MODEL FLAT24\n");
940     }
941     port->s.fptr_size = 3;
942     port->s.gptr_size = 4;
943
944     port->stack.isr_overhead += 2;      /* Will save dpx on ISR entry. */
945
946     port->stack.call_overhead += 2;     /* This acounts for the extra byte
947                                          * of return addres on the stack.
948                                          * but is ugly. There must be a
949                                          * better way.
950                                          */
951
952     port->mem.default_local_map = xdata;
953     port->mem.default_globl_map = xdata;
954
955     if (!options.stack10bit) {
956         options.stack10bit = 1;
957         fprintf(stderr,"TININative supports only stack10bit \n");
958     }
959
960     if (!options.stack_loc) options.stack_loc = 0x400008;
961
962     /* generate native code 16*16 mul/div */
963     if (options.useAccelerator)
964         port->support.muldiv=2;
965     else
966         port->support.muldiv=1;
967
968     /* Fixup the memory map for the stack; it is now in
969      * far space and requires a FPOINTER to access it.
970      */
971     istack->fmap = 1;
972     istack->ptrType = FPOINTER;
973     options.cc_only =1;
974 }
975
976 static int _tininative_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts)
977 {
978     return 1;
979 }
980 static void _tininative_genAssemblerPreamble (FILE * of)
981 {
982     fputs("$include(tini.inc)\n", of);
983     fputs("$include(ds80c390.inc)\n", of);
984     fputs("$include(tinimacro.inc)\n", of);
985     fputs("$include(apiequ.inc)\n", of);
986     fputs("_bpx EQU 01Eh \t\t; _bpx (frame pointer) mapped to R8_B3:R7_B3\n", of);
987     fputs("_ap  EQU 01Dh \t\t; _ap mapped to R6_B3\n", of);
988     /* Must be first and return 0 */
989     fputs("Lib_Native_Init:\n",of);
990     fputs("\tclr\ta\n",of);
991     fputs("\tret\n",of);
992     fputs("LibraryID:\n",of);
993     fputs("\tdb \"DS\"\n",of);
994     if (options.tini_libid) {
995         fprintf(of,"\tdb 0,0,0%02xh,0%02xh,0%02xh,0%02xh\n",
996                 (options.tini_libid>>24 & 0xff),
997                 (options.tini_libid>>16 & 0xff),
998                 (options.tini_libid>>8 & 0xff),
999                 (options.tini_libid  & 0xff));
1000     } else {
1001         fprintf(of,"\tdb 0,0,0,0,0,1\n");
1002     }
1003
1004 }
1005 static void _tininative_genAssemblerEnd (FILE * of)
1006 {
1007     fputs("\tend\n",of);
1008 }
1009 /* tininative assembler , calls "macro", if it succeeds calls "a390" */
1010 static void _tininative_do_assemble (set *asmOptions)
1011 {
1012     static const char *macroCmd[] = {
1013         "macro","$1.a51",NULL
1014     };
1015     static const char *a390Cmd[] = {
1016         "a390","$1.mpp",NULL
1017     };
1018     char buffer[100];
1019
1020     buildCmdLine(buffer,macroCmd,dstFileName,NULL,NULL,NULL);
1021     if (my_system(buffer)) {
1022         exit(1);
1023     }
1024     buildCmdLine(buffer,a390Cmd,dstFileName,NULL,NULL,asmOptions);
1025     if (my_system(buffer)) {
1026         exit(1);
1027     }
1028 }
1029
1030 /* list of key words used by TININative */
1031 static char *_tininative_keywords[] =
1032 {
1033   "at",
1034   "bit",
1035   "code",
1036   "critical",
1037   "data",
1038   "far",
1039   "idata",
1040   "interrupt",
1041   "near",
1042   "pdata",
1043   "reentrant",
1044   "sfr",
1045   "sbit",
1046   "using",
1047   "xdata",
1048   "_data",
1049   "_code",
1050   "_generic",
1051   "_near",
1052   "_xdata",
1053   "_pdata",
1054   "_idata",
1055   "_naked",
1056   "_JavaNative",
1057   NULL
1058 };
1059
1060 static builtins __tininative_builtins[] = {
1061     { "__builtin_memcpy_x2x","v",3,{"cx*","cx*","i"}}, /* void __builtin_memcpy_x2x (xdata char *,xdata char *,int) */
1062     { "__builtin_memcpy_c2x","v",3,{"cx*","cp*","i"}}, /* void __builtin_memcpy_c2x (xdata char *,code  char *,int) */
1063     { "__builtin_memset_x","v",3,{"cx*","c","i"}},     /* void __builtin_memset     (xdata char *,char,int)         */
1064     /* TINI NatLib */
1065     { "NatLib_LoadByte","c",1,{"c"}},                  /* char  Natlib_LoadByte  (0 based parameter number)         */
1066     { "NatLib_LoadShort","s",1,{"c"}},                 /* short Natlib_LoadShort (0 based parameter number)         */
1067     { "NatLib_LoadInt","l",1,{"c"}},                   /* long  Natlib_LoadLong  (0 based parameter number)         */
1068     { "NatLib_LoadPointer","cx*",1,{"c"}},             /* long  Natlib_LoadPointer  (0 based parameter number)      */
1069     /* TINI StateBlock related */
1070     { "NatLib_InstallImmutableStateBlock","c",2,{"vx*","us"}},/* char NatLib_InstallImmutableStateBlock(state block *,int handle) */
1071     { "NatLib_InstallEphemeralStateBlock","c",2,{"vx*","us"}},/* char NatLib_InstallEphemeralStateBlock(state block *,int handle) */
1072     { "NatLib_RemoveImmutableStateBlock","v",0,{NULL}},/* void NatLib_RemoveImmutableStateBlock() */
1073     { "NatLib_RemoveEphemeralStateBlock","v",0,{NULL}},/* void NatLib_RemoveEphemeralStateBlock() */
1074     { "NatLib_GetImmutableStateBlock","i",0,{NULL}},   /* int  NatLib_GetImmutableStateBlock () */
1075     { "NatLib_GetEphemeralStateBlock","i",0,{NULL}},   /* int  NatLib_GetEphemeralStateBlock () */
1076     /* Memory manager */
1077     { "MM_XMalloc","i",1,{"l"}},                       /* int  MM_XMalloc (long)                */
1078     { "MM_Malloc","i",1,{"i"}},                        /* int  MM_Malloc  (int)                 */
1079     { "MM_ApplicationMalloc","i",1,{"i"}},             /* int  MM_ApplicationMalloc  (int)      */
1080     { "MM_Free","i",1,{"i"}},                          /* int  MM_Free  (int)                   */
1081     { "MM_Deref","cx*",1,{"i"}},                       /* char *MM_Free  (int)                  */
1082     { "MM_UnrestrictedPersist","c",1,{"i"}},           /* char  MM_UnrestrictedPersist  (int)   */
1083     /* System functions */
1084     { "System_ExecJavaProcess","c",2,{"cx*","i"}},     /* char System_ExecJavaProcess (char *,int) */
1085     { "System_GetRTCRegisters","v",1,{"cx*"}},         /* void System_GetRTCRegisters (char *) */
1086     { "System_SetRTCRegisters","v",1,{"cx*"}},         /* void System_SetRTCRegisters (char *) */
1087     { "System_ThreadSleep","v",2,{"l","c"}},           /* void System_ThreadSleep (long,char)  */
1088     { "System_ThreadSleep_ExitCriticalSection","v",2,{"l","c"}},/* void System_ThreadSleep_ExitCriticalSection (long,char)  */
1089     { "System_ProcessSleep","v",2,{"l","c"}},           /* void System_ProcessSleep (long,char)  */
1090     { "System_ProcessSleep_ExitCriticalSection","v",2,{"l","c"}},/* void System_ProcessSleep_ExitCriticalSection (long,char)  */
1091     { "System_ThreadResume","c",2,{"c","c"}},          /* char System_ThreadResume(char,char)  */
1092     { "System_SaveJavaThreadState","v",0,{NULL}},      /* void System_SaveJavaThreadState()    */
1093     { "System_RestoreJavaThreadState","v",0,{NULL}},   /* void System_RestoreJavaThreadState() */
1094     { "System_ProcessYield","v",0,{NULL}},             /* void System_ProcessYield() */
1095     { "System_ProcessSuspend","v",0,{NULL}},           /* void System_ProcessSuspend() */
1096     { "System_ProcessResume","v",1,{"c"}},             /* void System_ProcessResume(char) */
1097     { "System_RegisterPoll","c",1,{"vF*"}},            /* char System_RegisterPoll ((void *func pointer)()) */
1098     { "System_RemovePoll","c",1,{"vF*"}},              /* char System_RemovePoll ((void *func pointer)()) */
1099     { "System_GetCurrentProcessId","c",0,{NULL}},      /* char System_GetCurrentProcessId() */
1100     { "System_GetCurrentThreadId","c",0,{NULL}},       /* char System_GetCurrentThreadId() */
1101     { NULL , NULL,0, {NULL}}                       /* mark end of table */
1102 };
1103
1104 static const char *_a390Cmd[] =
1105 {
1106   "macro", "$l", "$3", "$1.a51", NULL
1107 };
1108 PORT tininative_port =
1109 {
1110   TARGET_ID_DS390,
1111   "TININative",
1112   "DS80C390",                   /* Target name */
1113         NULL,                   /* processor */
1114   {
1115     glue,
1116     FALSE,                      /* Emit glue around main */
1117     MODEL_FLAT24,
1118     MODEL_FLAT24
1119   },
1120   {
1121     _a390Cmd,
1122     NULL,
1123     "-l",               /* Options with debug */
1124     "-l",               /* Options without debug */
1125     0,
1126     ".a51",
1127     _tininative_do_assemble
1128   },
1129   {
1130     NULL,
1131     NULL,
1132     NULL,
1133     ".tlib",
1134     1
1135   },
1136   {
1137     _defaultRules,
1138     getInstructionSize,
1139     getRegsRead,
1140     getRegsWritten
1141   },
1142   {
1143         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
1144     1, 2, 2, 4, 1, 3, 3, 1, 4, 4
1145   },
1146   {
1147     "XSEG    (XDATA)",
1148     "STACK   (DATA)",
1149     "CSEG    (CODE)",
1150     "DSEG    (DATA)",
1151     "ISEG    (DATA)",
1152     "XSEG    (XDATA)",
1153     "BSEG    (BIT)",
1154     "RSEG    (DATA)",
1155     "GSINIT  (CODE)",
1156     "OSEG    (OVR,DATA)",
1157     "GSFINAL (CODE)",
1158     "HOME        (CODE)",
1159     NULL,
1160     NULL,
1161     NULL,
1162     NULL,
1163     1
1164   },
1165   { NULL, NULL },
1166   {
1167     +1, 1, 4, 1, 1, 0
1168   },
1169     /* ds390 has an 16 bit mul & div */
1170   {
1171     2, -1
1172   },
1173   {
1174     ds390_emitDebuggerSymbol
1175   },
1176   "",
1177   _tininative_init,
1178   _ds390_parseOptions,
1179   NULL,
1180   NULL,
1181   _tininative_finaliseOptions,
1182   _tininative_setDefaultOptions,
1183   ds390_assignRegisters,
1184   _ds390_getRegName,
1185   _tininative_keywords,
1186   _tininative_genAssemblerPreamble,
1187   _tininative_genAssemblerEnd,
1188   _tininative_genIVT,
1189   NULL,
1190   NULL,                         /* genInitStartup */
1191   _ds390_reset_regparm,
1192   _ds390_regparm,
1193   NULL,
1194   NULL,
1195   NULL,
1196   hasExtBitOp,                  /* hasExtBitOp */
1197   oclsExpense,                  /* oclsExpense */
1198   FALSE,
1199   TRUE,                         /* little endian */
1200   0,                            /* leave lt */
1201   0,                            /* leave gt */
1202   1,                            /* transform <= to ! > */
1203   1,                            /* transform >= to ! < */
1204   1,                            /* transform != to !(a == b) */
1205   0,                            /* leave == */
1206   TRUE,                         /* we support array initializers. */
1207   cseCostEstimation,
1208   __tininative_builtins,        /* table of builtin functions */
1209   FPOINTER,                     /* treat unqualified pointers as far pointers */
1210   0,                            /* DONOT reset labelKey */
1211   0,                            /* globals & local static NOT allowed */
1212   PORT_MAGIC
1213 };
1214
1215 static int
1216 _ds400_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts)
1217 {
1218     /* We can't generate a static IVT, since the boot rom creates one
1219      * for us in rom_init.
1220      *
1221      * we must patch it as part of the C startup.
1222      */
1223      fprintf (of, ";\tDS80C400 IVT must be generated at runtime.\n");
1224     fprintf (of, "\tsjmp\t__sdcc_400boot\n");
1225     fprintf (of, "\t.ascii\t'TINI'\t; required signature for 400 boot loader.\n");
1226     fprintf (of, "\t.db\t0\t; selected bank: zero *should* work...\n");
1227     fprintf (of, "\t__sdcc_400boot:\tljmp\t__sdcc_gsinit_startup\n");
1228      return TRUE;
1229 }
1230
1231
1232
1233 static void
1234 _ds400_finaliseOptions (void)
1235 {
1236   if (options.noXinitOpt) {
1237     port->genXINIT=0;
1238   }
1239
1240   // hackhack: we're a superset of the 390.
1241   addSet(&preArgvSet, Safe_strdup("-DSDCC_ds390"));
1242   addSet(&preArgvSet, Safe_strdup("-D__ds390"));
1243
1244   /* Hack-o-matic: if we are using the flat24 model,
1245    * adjust pointer sizes.
1246    */
1247   if (options.model != MODEL_FLAT24)  {
1248       fprintf (stderr,
1249                "*** warning: ds400 port small and large model experimental.\n");
1250       if (options.model == MODEL_LARGE)
1251       {
1252         port->mem.default_local_map = xdata;
1253         port->mem.default_globl_map = xdata;
1254       }
1255       else
1256       {
1257         port->mem.default_local_map = data;
1258         port->mem.default_globl_map = data;
1259       }
1260   }
1261   else {
1262     port->s.fptr_size = 3;
1263     port->s.gptr_size = 4;
1264
1265     port->stack.isr_overhead += 2;      /* Will save dpx on ISR entry. */
1266
1267     port->stack.call_overhead += 2;     /* This acounts for the extra byte
1268                                  * of return addres on the stack.
1269                                  * but is ugly. There must be a
1270                                  * better way.
1271                                  */
1272
1273     port->mem.default_local_map = xdata;
1274     port->mem.default_globl_map = xdata;
1275
1276     if (!options.stack10bit)
1277     {
1278     fprintf (stderr,
1279              "*** error: ds400 port only supports the 10 bit stack mode.\n");
1280     } else {
1281         if (!options.stack_loc) options.stack_loc = 0xffdc00;
1282         // assumes IDM1:0 = 1:0, CMA = 1.
1283     }
1284
1285     /* generate native code 16*16 mul/div */
1286     if (options.useAccelerator)
1287             port->support.muldiv=2;
1288     else
1289             port->support.muldiv=1;
1290
1291      /* Fixup the memory map for the stack; it is now in
1292      * far space and requires a FPOINTER to access it.
1293      */
1294     istack->fmap = 1;
1295     istack->ptrType = FPOINTER;
1296
1297     if (options.parms_in_bank1) {
1298         addSet(&preArgvSet, Safe_strdup("-DSDCC_PARMS_IN_BANK1"));
1299     }
1300
1301     // the DS400 rom calling interface uses register bank 3.
1302     RegBankUsed[3] = 1;
1303
1304   }  /* MODEL_FLAT24 */
1305 }
1306
1307 static void _ds400_generateRomDataArea(FILE *fp, bool isMain)
1308 {
1309     /* Only do this for the file containing main() */
1310     if (isMain)
1311     {
1312         fprintf(fp, "%s", iComments2);
1313         fprintf(fp, "; the direct data area used by the DS80c400 ROM code.\n");
1314         fprintf(fp, "%s", iComments2);
1315         fprintf(fp, ".area ROMSEG (ABS,CON,DATA)\n\n");
1316         fprintf(fp, ".ds 24 ; 24 bytes of directs used starting at 0x68\n\n");
1317     }
1318 }
1319
1320 static void _ds400_linkRomDataArea(FILE *fp)
1321 {
1322     fprintf(fp, "-b ROMSEG = 0x0068\n");
1323 }
1324
1325
1326 PORT ds400_port =
1327 {
1328   TARGET_ID_DS400,
1329   "ds400",
1330   "DS80C400",                   /* Target name */
1331   NULL,
1332   {
1333     glue,
1334     TRUE,                       /* Emit glue around main */
1335     MODEL_SMALL | MODEL_LARGE | MODEL_FLAT24,
1336     MODEL_SMALL
1337   },
1338   {
1339     _asmCmd,
1340     NULL,
1341     "-plosgffc",                /* Options with debug */
1342     "-plosgff",                 /* Options without debug */
1343     0,
1344     ".asm",
1345     NULL                        /* no do_assemble function */
1346   },
1347   {
1348     _linkCmd,
1349     NULL,
1350     NULL,
1351     ".rel",
1352     1
1353   },
1354   {
1355     _defaultRules,
1356     getInstructionSize,
1357     getRegsRead,
1358     getRegsWritten
1359   },
1360   {
1361         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
1362     1, 2, 2, 4, 1, 2, 3, 1, 4, 4
1363   },
1364   {
1365     "XSEG    (XDATA)",
1366     "STACK   (DATA)",
1367     "CSEG    (CODE)",
1368     "DSEG    (DATA)",
1369     "ISEG    (DATA)",
1370     "XSEG    (XDATA)",
1371     "BSEG    (BIT)",
1372     "RSEG    (DATA)",
1373     "GSINIT  (CODE)",
1374     "OSEG    (OVR,DATA)",
1375     "GSFINAL (CODE)",
1376     "HOME    (CODE)",
1377     "XISEG   (XDATA)", // initialized xdata
1378     "XINIT   (CODE)", // a code copy of xiseg
1379     NULL,
1380     NULL,
1381     1
1382   },
1383   { _ds400_generateRomDataArea, _ds400_linkRomDataArea },
1384   {
1385     +1, 1, 4, 1, 1, 0
1386   },
1387     /* ds390 has an 16 bit mul & div */
1388   {
1389     2, -1
1390   },
1391   {
1392     ds390_emitDebuggerSymbol
1393   },
1394   "_",
1395   _ds390_init,
1396   _ds390_parseOptions,
1397   NULL,
1398   NULL,
1399   _ds400_finaliseOptions,
1400   _ds390_setDefaultOptions,
1401   ds390_assignRegisters,
1402   _ds390_getRegName,
1403   _ds390_keywords,
1404   _ds390_genAssemblerPreamble,
1405   NULL,                         /* no genAssemblerEnd */
1406   _ds400_genIVT,
1407   _ds390_genXINIT,
1408   NULL,                         /* genInitStartup */
1409   _ds390_reset_regparm,
1410   _ds390_regparm,
1411   NULL,
1412   NULL,
1413   _ds390_nativeMulCheck,
1414   hasExtBitOp,                  /* hasExtBitOp */
1415   oclsExpense,                  /* oclsExpense */
1416   FALSE,
1417   TRUE,                         /* little endian */
1418   0,                            /* leave lt */
1419   0,                            /* leave gt */
1420   1,                            /* transform <= to ! > */
1421   1,                            /* transform >= to ! < */
1422   1,                            /* transform != to !(a == b) */
1423   0,                            /* leave == */
1424   TRUE,                         /* we support array initializers. */
1425   cseCostEstimation,
1426   __ds390_builtins,             /* table of builtin functions */
1427   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
1428   1,                            /* reset labelKey to 1 */
1429   1,                            /* globals & local static allowed */
1430   PORT_MAGIC
1431 };