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