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