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