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