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