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