a1ff41aa7e3e3468af083db56133437b1dffe2e5
[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     255/4,      /* maxCount */
875     4,          /* sizeofElement */
876     {8,12,20},  /* sizeofMatchJump[] */
877     {10,14,22}, /* sizeofRangeCompare[] */
878     4,          /* sizeofSubtract */
879     7,          /* sizeofDispatch */
880   },
881   "_",
882   _ds390_init,
883   _ds390_parseOptions,
884   NULL,
885   NULL,
886   _ds390_finaliseOptions,
887   _ds390_setDefaultOptions,
888   ds390_assignRegisters,
889   _ds390_getRegName,
890   _ds390_keywords,
891   _ds390_genAssemblerPreamble,
892   NULL,                         /* no genAssemblerEnd */
893   _ds390_genIVT,
894   _ds390_genXINIT,
895   NULL,                         /* genInitStartup */
896   _ds390_reset_regparm,
897   _ds390_regparm,
898   NULL,
899   NULL,
900   _ds390_nativeMulCheck,
901   hasExtBitOp,                  /* hasExtBitOp */
902   oclsExpense,                  /* oclsExpense */
903   FALSE,
904   TRUE,                         /* little endian */
905   0,                            /* leave lt */
906   0,                            /* leave gt */
907   1,                            /* transform <= to ! > */
908   1,                            /* transform >= to ! < */
909   1,                            /* transform != to !(a == b) */
910   0,                            /* leave == */
911 #if 0 // obsolete, and buggy for != xdata
912   TRUE,                         /* we support array initializers. */
913 #else
914   FALSE,                        /* No array initializer support. */
915 #endif
916   cseCostEstimation,
917   __ds390_builtins,             /* table of builtin functions */
918   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
919   1,                            /* reset labelKey to 1 */
920   1,                            /* globals & local static allowed */
921   PORT_MAGIC
922 };
923
924 /*---------------------------------------------------------------------------------*/
925 /*                               TININative specific                               */
926 /*---------------------------------------------------------------------------------*/
927 /* Globals */
928 static void _tininative_init (void)
929 {
930     asm_addTree (&asm_a390_mapping);
931 }
932
933 static void _tininative_setDefaultOptions (void)
934 {
935     options.model=MODEL_FLAT24;
936     options.stack10bit=1;
937     options.stackAuto = 1;
938 }
939
940 static void _tininative_finaliseOptions (void)
941 {
942     /* Hack-o-matic: if we are using the flat24 model,
943      * adjust pointer sizes.
944      */
945     if (options.model != MODEL_FLAT24)  {
946         options.model = MODEL_FLAT24 ;
947         fprintf(stderr,"TININative supports only MODEL FLAT24\n");
948     }
949     port->s.fptr_size = 3;
950     port->s.gptr_size = 4;
951
952     port->stack.isr_overhead += 2;      /* Will save dpx on ISR entry. */
953
954     port->stack.call_overhead += 2;     /* This acounts for the extra byte
955                                          * of return addres on the stack.
956                                          * but is ugly. There must be a
957                                          * better way.
958                                          */
959
960     port->mem.default_local_map = xdata;
961     port->mem.default_globl_map = xdata;
962
963     if (!options.stack10bit) {
964         options.stack10bit = 1;
965         fprintf(stderr,"TININative supports only stack10bit \n");
966     }
967
968     if (!options.stack_loc) options.stack_loc = 0x400008;
969
970     /* generate native code 16*16 mul/div */
971     if (options.useAccelerator)
972         port->support.muldiv=2;
973     else
974         port->support.muldiv=1;
975
976     /* Fixup the memory map for the stack; it is now in
977      * far space and requires a FPOINTER to access it.
978      */
979     istack->fmap = 1;
980     istack->ptrType = FPOINTER;
981     options.cc_only =1;
982 }
983
984 static int _tininative_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts)
985 {
986     return 1;
987 }
988 static void _tininative_genAssemblerPreamble (FILE * of)
989 {
990     fputs("$include(tini.inc)\n", of);
991     fputs("$include(ds80c390.inc)\n", of);
992     fputs("$include(tinimacro.inc)\n", of);
993     fputs("$include(apiequ.inc)\n", of);
994     fputs("_bpx EQU 01Eh \t\t; _bpx (frame pointer) mapped to R8_B3:R7_B3\n", of);
995     fputs("_ap  EQU 01Dh \t\t; _ap mapped to R6_B3\n", of);
996     /* Must be first and return 0 */
997     fputs("Lib_Native_Init:\n",of);
998     fputs("\tclr\ta\n",of);
999     fputs("\tret\n",of);
1000     fputs("LibraryID:\n",of);
1001     fputs("\tdb \"DS\"\n",of);
1002     if (options.tini_libid) {
1003         fprintf(of,"\tdb 0,0,0%02xh,0%02xh,0%02xh,0%02xh\n",
1004                 (options.tini_libid>>24 & 0xff),
1005                 (options.tini_libid>>16 & 0xff),
1006                 (options.tini_libid>>8 & 0xff),
1007                 (options.tini_libid  & 0xff));
1008     } else {
1009         fprintf(of,"\tdb 0,0,0,0,0,1\n");
1010     }
1011
1012 }
1013 static void _tininative_genAssemblerEnd (FILE * of)
1014 {
1015     fputs("\tend\n",of);
1016 }
1017 /* tininative assembler , calls "macro", if it succeeds calls "a390" */
1018 static void _tininative_do_assemble (set *asmOptions)
1019 {
1020     static const char *macroCmd[] = {
1021         "macro","$1.a51",NULL
1022     };
1023     static const char *a390Cmd[] = {
1024         "a390","$1.mpp",NULL
1025     };
1026     char buffer[100];
1027
1028     buildCmdLine(buffer,macroCmd,dstFileName,NULL,NULL,NULL);
1029     if (my_system(buffer)) {
1030         exit(1);
1031     }
1032     buildCmdLine(buffer,a390Cmd,dstFileName,NULL,NULL,asmOptions);
1033     if (my_system(buffer)) {
1034         exit(1);
1035     }
1036 }
1037
1038 /* list of key words used by TININative */
1039 static char *_tininative_keywords[] =
1040 {
1041   "at",
1042   "bit",
1043   "code",
1044   "critical",
1045   "data",
1046   "far",
1047   "idata",
1048   "interrupt",
1049   "near",
1050   "pdata",
1051   "reentrant",
1052   "sfr",
1053   "sbit",
1054   "using",
1055   "xdata",
1056   "_data",
1057   "_code",
1058   "_generic",
1059   "_near",
1060   "_xdata",
1061   "_pdata",
1062   "_idata",
1063   "_naked",
1064   "_JavaNative",
1065   NULL
1066 };
1067
1068 static builtins __tininative_builtins[] = {
1069     { "__builtin_memcpy_x2x","v",3,{"cx*","cx*","i"}}, /* void __builtin_memcpy_x2x (xdata char *,xdata char *,int) */
1070     { "__builtin_memcpy_c2x","v",3,{"cx*","cp*","i"}}, /* void __builtin_memcpy_c2x (xdata char *,code  char *,int) */
1071     { "__builtin_memset_x","v",3,{"cx*","c","i"}},     /* void __builtin_memset     (xdata char *,char,int)         */
1072     /* TINI NatLib */
1073     { "NatLib_LoadByte","c",1,{"c"}},                  /* char  Natlib_LoadByte  (0 based parameter number)         */
1074     { "NatLib_LoadShort","s",1,{"c"}},                 /* short Natlib_LoadShort (0 based parameter number)         */
1075     { "NatLib_LoadInt","l",1,{"c"}},                   /* long  Natlib_LoadLong  (0 based parameter number)         */
1076     { "NatLib_LoadPointer","cx*",1,{"c"}},             /* long  Natlib_LoadPointer  (0 based parameter number)      */
1077     /* TINI StateBlock related */
1078     { "NatLib_InstallImmutableStateBlock","c",2,{"vx*","us"}},/* char NatLib_InstallImmutableStateBlock(state block *,int handle) */
1079     { "NatLib_InstallEphemeralStateBlock","c",2,{"vx*","us"}},/* char NatLib_InstallEphemeralStateBlock(state block *,int handle) */
1080     { "NatLib_RemoveImmutableStateBlock","v",0,{NULL}},/* void NatLib_RemoveImmutableStateBlock() */
1081     { "NatLib_RemoveEphemeralStateBlock","v",0,{NULL}},/* void NatLib_RemoveEphemeralStateBlock() */
1082     { "NatLib_GetImmutableStateBlock","i",0,{NULL}},   /* int  NatLib_GetImmutableStateBlock () */
1083     { "NatLib_GetEphemeralStateBlock","i",0,{NULL}},   /* int  NatLib_GetEphemeralStateBlock () */
1084     /* Memory manager */
1085     { "MM_XMalloc","i",1,{"l"}},                       /* int  MM_XMalloc (long)                */
1086     { "MM_Malloc","i",1,{"i"}},                        /* int  MM_Malloc  (int)                 */
1087     { "MM_ApplicationMalloc","i",1,{"i"}},             /* int  MM_ApplicationMalloc  (int)      */
1088     { "MM_Free","i",1,{"i"}},                          /* int  MM_Free  (int)                   */
1089     { "MM_Deref","cx*",1,{"i"}},                       /* char *MM_Free  (int)                  */
1090     { "MM_UnrestrictedPersist","c",1,{"i"}},           /* char  MM_UnrestrictedPersist  (int)   */
1091     /* System functions */
1092     { "System_ExecJavaProcess","c",2,{"cx*","i"}},     /* char System_ExecJavaProcess (char *,int) */
1093     { "System_GetRTCRegisters","v",1,{"cx*"}},         /* void System_GetRTCRegisters (char *) */
1094     { "System_SetRTCRegisters","v",1,{"cx*"}},         /* void System_SetRTCRegisters (char *) */
1095     { "System_ThreadSleep","v",2,{"l","c"}},           /* void System_ThreadSleep (long,char)  */
1096     { "System_ThreadSleep_ExitCriticalSection","v",2,{"l","c"}},/* void System_ThreadSleep_ExitCriticalSection (long,char)  */
1097     { "System_ProcessSleep","v",2,{"l","c"}},           /* void System_ProcessSleep (long,char)  */
1098     { "System_ProcessSleep_ExitCriticalSection","v",2,{"l","c"}},/* void System_ProcessSleep_ExitCriticalSection (long,char)  */
1099     { "System_ThreadResume","c",2,{"c","c"}},          /* char System_ThreadResume(char,char)  */
1100     { "System_SaveJavaThreadState","v",0,{NULL}},      /* void System_SaveJavaThreadState()    */
1101     { "System_RestoreJavaThreadState","v",0,{NULL}},   /* void System_RestoreJavaThreadState() */
1102     { "System_ProcessYield","v",0,{NULL}},             /* void System_ProcessYield() */
1103     { "System_ProcessSuspend","v",0,{NULL}},           /* void System_ProcessSuspend() */
1104     { "System_ProcessResume","v",1,{"c"}},             /* void System_ProcessResume(char) */
1105     { "System_RegisterPoll","c",1,{"vF*"}},            /* char System_RegisterPoll ((void *func pointer)()) */
1106     { "System_RemovePoll","c",1,{"vF*"}},              /* char System_RemovePoll ((void *func pointer)()) */
1107     { "System_GetCurrentProcessId","c",0,{NULL}},      /* char System_GetCurrentProcessId() */
1108     { "System_GetCurrentThreadId","c",0,{NULL}},       /* char System_GetCurrentThreadId() */
1109     { NULL , NULL,0, {NULL}}                       /* mark end of table */
1110 };
1111
1112 static const char *_a390Cmd[] =
1113 {
1114   "macro", "$l", "$3", "$1.a51", NULL
1115 };
1116 PORT tininative_port =
1117 {
1118   TARGET_ID_DS390,
1119   "TININative",
1120   "DS80C390",                   /* Target name */
1121         NULL,                   /* processor */
1122   {
1123     glue,
1124     FALSE,                      /* Emit glue around main */
1125     MODEL_FLAT24,
1126     MODEL_FLAT24
1127   },
1128   {
1129     _a390Cmd,
1130     NULL,
1131     "-l",               /* Options with debug */
1132     "-l",               /* Options without debug */
1133     0,
1134     ".a51",
1135     _tininative_do_assemble
1136   },
1137   {
1138     NULL,
1139     NULL,
1140     NULL,
1141     ".tlib",
1142     1
1143   },
1144   {
1145     _defaultRules,
1146     getInstructionSize,
1147     getRegsRead,
1148     getRegsWritten
1149   },
1150   {
1151         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
1152     1, 2, 2, 4, 1, 3, 3, 1, 4, 4
1153   },
1154   {
1155     "XSEG    (XDATA)",
1156     "STACK   (DATA)",
1157     "CSEG    (CODE)",
1158     "DSEG    (DATA)",
1159     "ISEG    (DATA)",
1160     "XSEG    (XDATA)",
1161     "BSEG    (BIT)",
1162     "RSEG    (DATA)",
1163     "GSINIT  (CODE)",
1164     "OSEG    (OVR,DATA)",
1165     "GSFINAL (CODE)",
1166     "HOME        (CODE)",
1167     NULL,
1168     NULL,
1169     NULL,
1170     NULL,
1171     1
1172   },
1173   { NULL, NULL },
1174   {
1175     +1, 1, 4, 1, 1, 0
1176   },
1177     /* ds390 has an 16 bit mul & div */
1178   {
1179     2, -1
1180   },
1181   {
1182     ds390_emitDebuggerSymbol
1183   },
1184   {
1185     255/4,      /* maxCount */
1186     4,          /* sizeofElement */
1187     {8,12,20},  /* sizeofMatchJump[] */
1188     {10,14,22}, /* sizeofRangeCompare[] */
1189     4,          /* sizeofSubtract */
1190     7,          /* sizeofDispatch */
1191   },
1192   "",
1193   _tininative_init,
1194   _ds390_parseOptions,
1195   NULL,
1196   NULL,
1197   _tininative_finaliseOptions,
1198   _tininative_setDefaultOptions,
1199   ds390_assignRegisters,
1200   _ds390_getRegName,
1201   _tininative_keywords,
1202   _tininative_genAssemblerPreamble,
1203   _tininative_genAssemblerEnd,
1204   _tininative_genIVT,
1205   NULL,
1206   NULL,                         /* genInitStartup */
1207   _ds390_reset_regparm,
1208   _ds390_regparm,
1209   NULL,
1210   NULL,
1211   NULL,
1212   hasExtBitOp,                  /* hasExtBitOp */
1213   oclsExpense,                  /* oclsExpense */
1214   FALSE,
1215   TRUE,                         /* little endian */
1216   0,                            /* leave lt */
1217   0,                            /* leave gt */
1218   1,                            /* transform <= to ! > */
1219   1,                            /* transform >= to ! < */
1220   1,                            /* transform != to !(a == b) */
1221   0,                            /* leave == */
1222   TRUE,                         /* we support array initializers. */
1223   cseCostEstimation,
1224   __tininative_builtins,        /* table of builtin functions */
1225   FPOINTER,                     /* treat unqualified pointers as far pointers */
1226   0,                            /* DONOT reset labelKey */
1227   0,                            /* globals & local static NOT allowed */
1228   PORT_MAGIC
1229 };
1230
1231 static int
1232 _ds400_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts)
1233 {
1234     /* We can't generate a static IVT, since the boot rom creates one
1235      * for us in rom_init.
1236      *
1237      * we must patch it as part of the C startup.
1238      */
1239      fprintf (of, ";\tDS80C400 IVT must be generated at runtime.\n");
1240     fprintf (of, "\tsjmp\t__sdcc_400boot\n");
1241     fprintf (of, "\t.ascii\t'TINI'\t; required signature for 400 boot loader.\n");
1242     fprintf (of, "\t.db\t0\t; selected bank: zero *should* work...\n");
1243     fprintf (of, "\t__sdcc_400boot:\tljmp\t__sdcc_gsinit_startup\n");
1244      return TRUE;
1245 }
1246
1247
1248
1249 static void
1250 _ds400_finaliseOptions (void)
1251 {
1252   if (options.noXinitOpt) {
1253     port->genXINIT=0;
1254   }
1255
1256   // hackhack: we're a superset of the 390.
1257   addSet(&preArgvSet, Safe_strdup("-DSDCC_ds390"));
1258   addSet(&preArgvSet, Safe_strdup("-D__ds390"));
1259
1260   /* Hack-o-matic: if we are using the flat24 model,
1261    * adjust pointer sizes.
1262    */
1263   if (options.model != MODEL_FLAT24)  {
1264       fprintf (stderr,
1265                "*** warning: ds400 port small and large model experimental.\n");
1266       if (options.model == MODEL_LARGE)
1267       {
1268         port->mem.default_local_map = xdata;
1269         port->mem.default_globl_map = xdata;
1270       }
1271       else
1272       {
1273         port->mem.default_local_map = data;
1274         port->mem.default_globl_map = data;
1275       }
1276   }
1277   else {
1278     port->s.fptr_size = 3;
1279     port->s.gptr_size = 4;
1280
1281     port->stack.isr_overhead += 2;      /* Will save dpx on ISR entry. */
1282
1283     port->stack.call_overhead += 2;     /* This acounts for the extra byte
1284                                  * of return addres on the stack.
1285                                  * but is ugly. There must be a
1286                                  * better way.
1287                                  */
1288
1289     port->mem.default_local_map = xdata;
1290     port->mem.default_globl_map = xdata;
1291
1292     if (!options.stack10bit)
1293     {
1294     fprintf (stderr,
1295              "*** error: ds400 port only supports the 10 bit stack mode.\n");
1296     } else {
1297         if (!options.stack_loc) options.stack_loc = 0xffdc00;
1298         // assumes IDM1:0 = 1:0, CMA = 1.
1299     }
1300
1301     /* generate native code 16*16 mul/div */
1302     if (options.useAccelerator)
1303             port->support.muldiv=2;
1304     else
1305             port->support.muldiv=1;
1306
1307      /* Fixup the memory map for the stack; it is now in
1308      * far space and requires a FPOINTER to access it.
1309      */
1310     istack->fmap = 1;
1311     istack->ptrType = FPOINTER;
1312
1313     if (options.parms_in_bank1) {
1314         addSet(&preArgvSet, Safe_strdup("-DSDCC_PARMS_IN_BANK1"));
1315     }
1316
1317     // the DS400 rom calling interface uses register bank 3.
1318     RegBankUsed[3] = 1;
1319
1320   }  /* MODEL_FLAT24 */
1321 }
1322
1323 static void _ds400_generateRomDataArea(FILE *fp, bool isMain)
1324 {
1325     /* Only do this for the file containing main() */
1326     if (isMain)
1327     {
1328         fprintf(fp, "%s", iComments2);
1329         fprintf(fp, "; the direct data area used by the DS80c400 ROM code.\n");
1330         fprintf(fp, "%s", iComments2);
1331         fprintf(fp, ".area ROMSEG (ABS,CON,DATA)\n\n");
1332         fprintf(fp, ".ds 24 ; 24 bytes of directs used starting at 0x68\n\n");
1333     }
1334 }
1335
1336 static void _ds400_linkRomDataArea(FILE *fp)
1337 {
1338     fprintf(fp, "-b ROMSEG = 0x0068\n");
1339 }
1340
1341
1342 PORT ds400_port =
1343 {
1344   TARGET_ID_DS400,
1345   "ds400",
1346   "DS80C400",                   /* Target name */
1347   NULL,
1348   {
1349     glue,
1350     TRUE,                       /* Emit glue around main */
1351     MODEL_SMALL | MODEL_LARGE | MODEL_FLAT24,
1352     MODEL_SMALL
1353   },
1354   {
1355     _asmCmd,
1356     NULL,
1357     "-plosgffc",                /* Options with debug */
1358     "-plosgff",                 /* Options without debug */
1359     0,
1360     ".asm",
1361     NULL                        /* no do_assemble function */
1362   },
1363   {
1364     _linkCmd,
1365     NULL,
1366     NULL,
1367     ".rel",
1368     1
1369   },
1370   {
1371     _defaultRules,
1372     getInstructionSize,
1373     getRegsRead,
1374     getRegsWritten
1375   },
1376   {
1377         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
1378     1, 2, 2, 4, 1, 2, 3, 1, 4, 4
1379   },
1380   {
1381     "XSEG    (XDATA)",
1382     "STACK   (DATA)",
1383     "CSEG    (CODE)",
1384     "DSEG    (DATA)",
1385     "ISEG    (DATA)",
1386     "XSEG    (XDATA)",
1387     "BSEG    (BIT)",
1388     "RSEG    (DATA)",
1389     "GSINIT  (CODE)",
1390     "OSEG    (OVR,DATA)",
1391     "GSFINAL (CODE)",
1392     "HOME    (CODE)",
1393     "XISEG   (XDATA)", // initialized xdata
1394     "XINIT   (CODE)", // a code copy of xiseg
1395     NULL,
1396     NULL,
1397     1
1398   },
1399   { _ds400_generateRomDataArea, _ds400_linkRomDataArea },
1400   {
1401     +1, 1, 4, 1, 1, 0
1402   },
1403     /* ds390 has an 16 bit mul & div */
1404   {
1405     2, -1
1406   },
1407   {
1408     ds390_emitDebuggerSymbol
1409   },
1410   {
1411     255/4,      /* maxCount */
1412     4,          /* sizeofElement */
1413     {8,12,20},  /* sizeofMatchJump[] */
1414     {10,14,22}, /* sizeofRangeCompare[] */
1415     4,          /* sizeofSubtract */
1416     7,          /* sizeofDispatch */
1417   },
1418   "_",
1419   _ds390_init,
1420   _ds390_parseOptions,
1421   NULL,
1422   NULL,
1423   _ds400_finaliseOptions,
1424   _ds390_setDefaultOptions,
1425   ds390_assignRegisters,
1426   _ds390_getRegName,
1427   _ds390_keywords,
1428   _ds390_genAssemblerPreamble,
1429   NULL,                         /* no genAssemblerEnd */
1430   _ds400_genIVT,
1431   _ds390_genXINIT,
1432   NULL,                         /* genInitStartup */
1433   _ds390_reset_regparm,
1434   _ds390_regparm,
1435   NULL,
1436   NULL,
1437   _ds390_nativeMulCheck,
1438   hasExtBitOp,                  /* hasExtBitOp */
1439   oclsExpense,                  /* oclsExpense */
1440   FALSE,
1441   TRUE,                         /* little endian */
1442   0,                            /* leave lt */
1443   0,                            /* leave gt */
1444   1,                            /* transform <= to ! > */
1445   1,                            /* transform >= to ! < */
1446   1,                            /* transform != to !(a == b) */
1447   0,                            /* leave == */
1448   TRUE,                         /* we support array initializers. */
1449   cseCostEstimation,
1450   __ds390_builtins,             /* table of builtin functions */
1451   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
1452   1,                            /* reset labelKey to 1 */
1453   1,                            /* globals & local static allowed */
1454   PORT_MAGIC
1455 };