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