* doc/sdccman.lyx: documented numeric ranges, WEBDOC #1442369
[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     "XSEG    (XDATA)",
866     "STACK   (DATA)",
867     "CSEG    (CODE)",
868     "DSEG    (DATA)",
869     "ISEG    (DATA)",
870     "PSEG    (PAG,XDATA)",
871     "XSEG    (XDATA)",
872     "BSEG    (BIT)",
873     "RSEG    (DATA)",
874     "GSINIT  (CODE)",
875     "OSEG    (OVR,DATA)",
876     "GSFINAL (CODE)",
877     "HOME    (CODE)",
878     "XISEG   (XDATA)", // initialized xdata
879     "XINIT   (CODE)", // a code copy of xiseg
880     "CONST   (CODE)",           // const_name - const data (code or not)
881     NULL,
882     NULL,
883     1
884   },
885   { NULL, NULL },
886   {
887     +1, 1, 4, 1, 1, 0
888   },
889     /* ds390 has an 16 bit mul & div */
890   {
891     2, -1
892   },
893   {
894     ds390_emitDebuggerSymbol
895   },
896   {
897     255/4,      /* maxCount */
898     4,          /* sizeofElement */
899     {8,12,20},  /* sizeofMatchJump[] */
900     {10,14,22}, /* sizeofRangeCompare[] */
901     4,          /* sizeofSubtract */
902     7,          /* sizeofDispatch */
903   },
904   "_",
905   _ds390_init,
906   _ds390_parseOptions,
907   NULL,
908   NULL,
909   _ds390_finaliseOptions,
910   _ds390_setDefaultOptions,
911   ds390_assignRegisters,
912   _ds390_getRegName,
913   _ds390_keywords,
914   _ds390_genAssemblerPreamble,
915   NULL,                         /* no genAssemblerEnd */
916   _ds390_genIVT,
917   _ds390_genXINIT,
918   NULL,                         /* genInitStartup */
919   _ds390_reset_regparm,
920   _ds390_regparm,
921   NULL,
922   NULL,
923   _ds390_nativeMulCheck,
924   hasExtBitOp,                  /* hasExtBitOp */
925   oclsExpense,                  /* oclsExpense */
926   FALSE,
927   TRUE,                         /* little endian */
928   0,                            /* leave lt */
929   0,                            /* leave gt */
930   1,                            /* transform <= to ! > */
931   1,                            /* transform >= to ! < */
932   1,                            /* transform != to !(a == b) */
933   0,                            /* leave == */
934 #if 0 // obsolete, and buggy for != xdata
935   TRUE,                         /* we support array initializers. */
936 #else
937   FALSE,                        /* No array initializer support. */
938 #endif
939   cseCostEstimation,
940   __ds390_builtins,             /* table of builtin functions */
941   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
942   1,                            /* reset labelKey to 1 */
943   1,                            /* globals & local static allowed */
944   PORT_MAGIC
945 };
946
947 /*---------------------------------------------------------------------------------*/
948 /*                               TININative specific                               */
949 /*---------------------------------------------------------------------------------*/
950 /* Globals */
951 static void _tininative_init (void)
952 {
953     asm_addTree (&asm_a390_mapping);
954 }
955
956 static void _tininative_setDefaultOptions (void)
957 {
958     options.model=MODEL_FLAT24;
959     options.stack10bit=1;
960     options.stackAuto = 1;
961 }
962
963 static void _tininative_finaliseOptions (void)
964 {
965     /* Hack-o-matic: if we are using the flat24 model,
966      * adjust pointer sizes.
967      */
968     if (options.model != MODEL_FLAT24)  {
969         options.model = MODEL_FLAT24 ;
970         fprintf(stderr,"TININative supports only MODEL FLAT24\n");
971     }
972     port->s.fptr_size = 3;
973     port->s.gptr_size = 4;
974
975     port->stack.isr_overhead += 2;      /* Will save dpx on ISR entry. */
976
977     port->stack.call_overhead += 2;     /* This acounts for the extra byte
978                                          * of return addres on the stack.
979                                          * but is ugly. There must be a
980                                          * better way.
981                                          */
982
983     port->mem.default_local_map = xdata;
984     port->mem.default_globl_map = xdata;
985
986     if (!options.stack10bit) {
987         options.stack10bit = 1;
988         fprintf(stderr,"TININative supports only stack10bit \n");
989     }
990
991     if (!options.stack_loc) options.stack_loc = 0x400008;
992
993     /* generate native code 16*16 mul/div */
994     if (options.useAccelerator)
995         port->support.muldiv=2;
996     else
997         port->support.muldiv=1;
998
999     /* Fixup the memory map for the stack; it is now in
1000      * far space and requires a FPOINTER to access it.
1001      */
1002     istack->fmap = 1;
1003     istack->ptrType = FPOINTER;
1004     options.cc_only =1;
1005 }
1006
1007 static int _tininative_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts)
1008 {
1009     return TRUE;
1010 }
1011 static void _tininative_genAssemblerPreamble (FILE * of)
1012 {
1013     fputs("$include(tini.inc)\n", of);
1014     fputs("$include(ds80c390.inc)\n", of);
1015     fputs("$include(tinimacro.inc)\n", of);
1016     fputs("$include(apiequ.inc)\n", of);
1017     fputs("_bpx EQU 01Eh \t\t; _bpx (frame pointer) mapped to R8_B3:R7_B3\n", of);
1018     fputs("_ap  EQU 01Dh \t\t; _ap mapped to R6_B3\n", of);
1019     /* Must be first and return 0 */
1020     fputs("Lib_Native_Init:\n",of);
1021     fputs("\tclr\ta\n",of);
1022     fputs("\tret\n",of);
1023     fputs("LibraryID:\n",of);
1024     fputs("\tdb \"DS\"\n",of);
1025     if (options.tini_libid) {
1026         fprintf(of,"\tdb 0,0,0%02xh,0%02xh,0%02xh,0%02xh\n",
1027                 (options.tini_libid>>24 & 0xff),
1028                 (options.tini_libid>>16 & 0xff),
1029                 (options.tini_libid>>8 & 0xff),
1030                 (options.tini_libid  & 0xff));
1031     } else {
1032         fprintf(of,"\tdb 0,0,0,0,0,1\n");
1033     }
1034
1035 }
1036 static void _tininative_genAssemblerEnd (FILE * of)
1037 {
1038     fputs("\tend\n",of);
1039 }
1040 /* tininative assembler , calls "macro", if it succeeds calls "a390" */
1041 static void _tininative_do_assemble (set *asmOptions)
1042 {
1043     static const char *macroCmd[] = {
1044         "macro","$1.a51",NULL
1045     };
1046     static const char *a390Cmd[] = {
1047         "a390","$1.mpp",NULL
1048     };
1049     char buffer[100];
1050
1051     buildCmdLine(buffer,macroCmd,dstFileName,NULL,NULL,NULL);
1052     if (my_system(buffer)) {
1053         exit(1);
1054     }
1055     buildCmdLine(buffer,a390Cmd,dstFileName,NULL,NULL,asmOptions);
1056     if (my_system(buffer)) {
1057         exit(1);
1058     }
1059 }
1060
1061 /* list of key words used by TININative */
1062 static char *_tininative_keywords[] =
1063 {
1064   "at",
1065   "bit",
1066   "code",
1067   "critical",
1068   "data",
1069   "far",
1070   "idata",
1071   "interrupt",
1072   "near",
1073   "pdata",
1074   "reentrant",
1075   "sfr",
1076   "sbit",
1077   "using",
1078   "xdata",
1079   "_data",
1080   "_code",
1081   "_generic",
1082   "_near",
1083   "_xdata",
1084   "_pdata",
1085   "_idata",
1086   "_naked",
1087   "_JavaNative",
1088   NULL
1089 };
1090
1091 static builtins __tininative_builtins[] = {
1092     { "__builtin_memcpy_x2x","v",3,{"cx*","cx*","i"}}, /* void __builtin_memcpy_x2x (xdata char *,xdata char *,int) */
1093     { "__builtin_memcpy_c2x","v",3,{"cx*","cp*","i"}}, /* void __builtin_memcpy_c2x (xdata char *,code  char *,int) */
1094     { "__builtin_memset_x","v",3,{"cx*","c","i"}},     /* void __builtin_memset     (xdata char *,char,int)         */
1095     /* TINI NatLib */
1096     { "NatLib_LoadByte","c",1,{"c"}},                  /* char  Natlib_LoadByte  (0 based parameter number)         */
1097     { "NatLib_LoadShort","s",1,{"c"}},                 /* short Natlib_LoadShort (0 based parameter number)         */
1098     { "NatLib_LoadInt","l",1,{"c"}},                   /* long  Natlib_LoadLong  (0 based parameter number)         */
1099     { "NatLib_LoadPointer","cx*",1,{"c"}},             /* long  Natlib_LoadPointer  (0 based parameter number)      */
1100     /* TINI StateBlock related */
1101     { "NatLib_InstallImmutableStateBlock","c",2,{"vx*","us"}},/* char NatLib_InstallImmutableStateBlock(state block *,int handle) */
1102     { "NatLib_InstallEphemeralStateBlock","c",2,{"vx*","us"}},/* char NatLib_InstallEphemeralStateBlock(state block *,int handle) */
1103     { "NatLib_RemoveImmutableStateBlock","v",0,{NULL}},/* void NatLib_RemoveImmutableStateBlock() */
1104     { "NatLib_RemoveEphemeralStateBlock","v",0,{NULL}},/* void NatLib_RemoveEphemeralStateBlock() */
1105     { "NatLib_GetImmutableStateBlock","i",0,{NULL}},   /* int  NatLib_GetImmutableStateBlock () */
1106     { "NatLib_GetEphemeralStateBlock","i",0,{NULL}},   /* int  NatLib_GetEphemeralStateBlock () */
1107     /* Memory manager */
1108     { "MM_XMalloc","i",1,{"l"}},                       /* int  MM_XMalloc (long)                */
1109     { "MM_Malloc","i",1,{"i"}},                        /* int  MM_Malloc  (int)                 */
1110     { "MM_ApplicationMalloc","i",1,{"i"}},             /* int  MM_ApplicationMalloc  (int)      */
1111     { "MM_Free","i",1,{"i"}},                          /* int  MM_Free  (int)                   */
1112     { "MM_Deref","cx*",1,{"i"}},                       /* char *MM_Free  (int)                  */
1113     { "MM_UnrestrictedPersist","c",1,{"i"}},           /* char  MM_UnrestrictedPersist  (int)   */
1114     /* System functions */
1115     { "System_ExecJavaProcess","c",2,{"cx*","i"}},     /* char System_ExecJavaProcess (char *,int) */
1116     { "System_GetRTCRegisters","v",1,{"cx*"}},         /* void System_GetRTCRegisters (char *) */
1117     { "System_SetRTCRegisters","v",1,{"cx*"}},         /* void System_SetRTCRegisters (char *) */
1118     { "System_ThreadSleep","v",2,{"l","c"}},           /* void System_ThreadSleep (long,char)  */
1119     { "System_ThreadSleep_ExitCriticalSection","v",2,{"l","c"}},/* void System_ThreadSleep_ExitCriticalSection (long,char)  */
1120     { "System_ProcessSleep","v",2,{"l","c"}},           /* void System_ProcessSleep (long,char)  */
1121     { "System_ProcessSleep_ExitCriticalSection","v",2,{"l","c"}},/* void System_ProcessSleep_ExitCriticalSection (long,char)  */
1122     { "System_ThreadResume","c",2,{"c","c"}},          /* char System_ThreadResume(char,char)  */
1123     { "System_SaveJavaThreadState","v",0,{NULL}},      /* void System_SaveJavaThreadState()    */
1124     { "System_RestoreJavaThreadState","v",0,{NULL}},   /* void System_RestoreJavaThreadState() */
1125     { "System_ProcessYield","v",0,{NULL}},             /* void System_ProcessYield() */
1126     { "System_ProcessSuspend","v",0,{NULL}},           /* void System_ProcessSuspend() */
1127     { "System_ProcessResume","v",1,{"c"}},             /* void System_ProcessResume(char) */
1128     { "System_RegisterPoll","c",1,{"vF*"}},            /* char System_RegisterPoll ((void *func pointer)()) */
1129     { "System_RemovePoll","c",1,{"vF*"}},              /* char System_RemovePoll ((void *func pointer)()) */
1130     { "System_GetCurrentProcessId","c",0,{NULL}},      /* char System_GetCurrentProcessId() */
1131     { "System_GetCurrentThreadId","c",0,{NULL}},       /* char System_GetCurrentThreadId() */
1132     { NULL , NULL,0, {NULL}}                       /* mark end of table */
1133 };
1134
1135 static const char *_a390Cmd[] =
1136 {
1137   "macro", "$l", "$3", "$1.a51", NULL
1138 };
1139 PORT tininative_port =
1140 {
1141   TARGET_ID_DS390,
1142   "TININative",
1143   "DS80C390",                   /* Target name */
1144         NULL,                   /* processor */
1145   {
1146     glue,
1147     FALSE,                      /* Emit glue around main */
1148     MODEL_FLAT24,
1149     MODEL_FLAT24
1150   },
1151   {
1152     _a390Cmd,
1153     NULL,
1154     "-l",               /* Options with debug */
1155     "-l",               /* Options without debug */
1156     0,
1157     ".a51",
1158     _tininative_do_assemble
1159   },
1160   {
1161     NULL,
1162     NULL,
1163     NULL,
1164     ".tlib",
1165     1
1166   },
1167   {
1168     _defaultRules,
1169     getInstructionSize,
1170     getRegsRead,
1171     getRegsWritten
1172   },
1173   {
1174         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
1175     1, 2, 2, 4, 1, 3, 3, 1, 4, 4
1176   },
1177   {
1178     "XSEG    (XDATA)",
1179     "STACK   (DATA)",
1180     "CSEG    (CODE)",
1181     "DSEG    (DATA)",
1182     "ISEG    (DATA)",
1183     "PSEG    (PAG,XDATA)",
1184     "XSEG    (XDATA)",
1185     "BSEG    (BIT)",
1186     "RSEG    (DATA)",
1187     "GSINIT  (CODE)",
1188     "OSEG    (OVR,DATA)",
1189     "GSFINAL (CODE)",
1190     "HOME    (CODE)",
1191     NULL,
1192     NULL,
1193     "CONST   (CODE)",           // const_name - const data (code or not)
1194     NULL,
1195     NULL,
1196     1
1197   },
1198   { NULL, NULL },
1199   {
1200     +1, 1, 4, 1, 1, 0
1201   },
1202     /* ds390 has an 16 bit mul & div */
1203   {
1204     2, -1
1205   },
1206   {
1207     ds390_emitDebuggerSymbol
1208   },
1209   {
1210     255/4,      /* maxCount */
1211     4,          /* sizeofElement */
1212     {8,12,20},  /* sizeofMatchJump[] */
1213     {10,14,22}, /* sizeofRangeCompare[] */
1214     4,          /* sizeofSubtract */
1215     7,          /* sizeofDispatch */
1216   },
1217   "",
1218   _tininative_init,
1219   _ds390_parseOptions,
1220   NULL,
1221   NULL,
1222   _tininative_finaliseOptions,
1223   _tininative_setDefaultOptions,
1224   ds390_assignRegisters,
1225   _ds390_getRegName,
1226   _tininative_keywords,
1227   _tininative_genAssemblerPreamble,
1228   _tininative_genAssemblerEnd,
1229   _tininative_genIVT,
1230   NULL,
1231   NULL,                         /* genInitStartup */
1232   _ds390_reset_regparm,
1233   _ds390_regparm,
1234   NULL,
1235   NULL,
1236   NULL,
1237   hasExtBitOp,                  /* hasExtBitOp */
1238   oclsExpense,                  /* oclsExpense */
1239   FALSE,
1240   TRUE,                         /* little endian */
1241   0,                            /* leave lt */
1242   0,                            /* leave gt */
1243   1,                            /* transform <= to ! > */
1244   1,                            /* transform >= to ! < */
1245   1,                            /* transform != to !(a == b) */
1246   0,                            /* leave == */
1247   TRUE,                         /* we support array initializers. */
1248   cseCostEstimation,
1249   __tininative_builtins,        /* table of builtin functions */
1250   FPOINTER,                     /* treat unqualified pointers as far pointers */
1251   0,                            /* DONOT reset labelKey */
1252   0,                            /* globals & local static NOT allowed */
1253   PORT_MAGIC
1254 };
1255
1256 static int
1257 _ds400_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts)
1258 {
1259     /* We can't generate a static IVT, since the boot rom creates one
1260      * for us in rom_init.
1261      *
1262      * we must patch it as part of the C startup.
1263      */
1264      fprintf (of, ";\tDS80C400 IVT must be generated at runtime.\n");
1265     fprintf (of, "\tsjmp\t__sdcc_400boot\n");
1266     fprintf (of, "\t.ascii\t'TINI'\t; required signature for 400 boot loader.\n");
1267     fprintf (of, "\t.db\t0\t; selected bank: zero *should* work...\n");
1268     fprintf (of, "\t__sdcc_400boot:\tljmp\t__sdcc_gsinit_startup\n");
1269      return TRUE;
1270 }
1271
1272
1273
1274 static void
1275 _ds400_finaliseOptions (void)
1276 {
1277   if (options.noXinitOpt) {
1278     port->genXINIT=0;
1279   }
1280
1281   // hackhack: we're a superset of the 390.
1282   addSet(&preArgvSet, Safe_strdup("-DSDCC_ds390"));
1283   addSet(&preArgvSet, Safe_strdup("-D__ds390"));
1284
1285   /* Hack-o-matic: if we are using the flat24 model,
1286    * adjust pointer sizes.
1287    */
1288   if (options.model != MODEL_FLAT24)  {
1289       fprintf (stderr,
1290                "*** warning: ds400 port small and large model experimental.\n");
1291       if (options.model == MODEL_LARGE)
1292       {
1293         port->mem.default_local_map = xdata;
1294         port->mem.default_globl_map = xdata;
1295       }
1296       else
1297       {
1298         port->mem.default_local_map = data;
1299         port->mem.default_globl_map = data;
1300       }
1301   }
1302   else {
1303     port->s.fptr_size = 3;
1304     port->s.gptr_size = 4;
1305
1306     port->stack.isr_overhead += 2;      /* Will save dpx on ISR entry. */
1307
1308     port->stack.call_overhead += 2;     /* This acounts for the extra byte
1309                                  * of return addres on the stack.
1310                                  * but is ugly. There must be a
1311                                  * better way.
1312                                  */
1313
1314     port->mem.default_local_map = xdata;
1315     port->mem.default_globl_map = xdata;
1316
1317     if (!options.stack10bit)
1318     {
1319     fprintf (stderr,
1320              "*** error: ds400 port only supports the 10 bit stack mode.\n");
1321     } else {
1322         if (!options.stack_loc) options.stack_loc = 0xffdc00;
1323         // assumes IDM1:0 = 1:0, CMA = 1.
1324     }
1325
1326     /* generate native code 16*16 mul/div */
1327     if (options.useAccelerator)
1328             port->support.muldiv=2;
1329     else
1330             port->support.muldiv=1;
1331
1332      /* Fixup the memory map for the stack; it is now in
1333      * far space and requires a FPOINTER to access it.
1334      */
1335     istack->fmap = 1;
1336     istack->ptrType = FPOINTER;
1337
1338     if (options.parms_in_bank1) {
1339         addSet(&preArgvSet, Safe_strdup("-DSDCC_PARMS_IN_BANK1"));
1340     }
1341
1342     // the DS400 rom calling interface uses register bank 3.
1343     RegBankUsed[3] = 1;
1344
1345   }  /* MODEL_FLAT24 */
1346 }
1347
1348 static void _ds400_generateRomDataArea(FILE *fp, bool isMain)
1349 {
1350     /* Only do this for the file containing main() */
1351     if (isMain)
1352     {
1353         fprintf(fp, "%s", iComments2);
1354         fprintf(fp, "; the direct data area used by the DS80c400 ROM code.\n");
1355         fprintf(fp, "%s", iComments2);
1356         fprintf(fp, ".area ROMSEG (ABS,CON,DATA)\n\n");
1357         fprintf(fp, ".ds 24 ; 24 bytes of directs used starting at 0x68\n\n");
1358     }
1359 }
1360
1361 static void _ds400_linkRomDataArea(FILE *fp)
1362 {
1363     fprintf(fp, "-b ROMSEG = 0x0068\n");
1364 }
1365
1366
1367 PORT ds400_port =
1368 {
1369   TARGET_ID_DS400,
1370   "ds400",
1371   "DS80C400",                   /* Target name */
1372   NULL,
1373   {
1374     glue,
1375     TRUE,                       /* Emit glue around main */
1376     MODEL_SMALL | MODEL_LARGE | MODEL_FLAT24,
1377     MODEL_SMALL
1378   },
1379   {
1380     _asmCmd,
1381     NULL,
1382     "-plosgffc",                /* Options with debug */
1383     "-plosgff",                 /* Options without debug */
1384     0,
1385     ".asm",
1386     NULL                        /* no do_assemble function */
1387   },
1388   {
1389     _linkCmd,
1390     NULL,
1391     NULL,
1392     ".rel",
1393     1
1394   },
1395   {
1396     _defaultRules,
1397     getInstructionSize,
1398     getRegsRead,
1399     getRegsWritten
1400   },
1401   {
1402         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
1403     1, 2, 2, 4, 1, 2, 3, 1, 4, 4
1404   },
1405   {
1406     "XSEG    (XDATA)",
1407     "STACK   (DATA)",
1408     "CSEG    (CODE)",
1409     "DSEG    (DATA)",
1410     "ISEG    (DATA)",
1411     "PSEG    (PAG,XDATA)",
1412     "XSEG    (XDATA)",
1413     "BSEG    (BIT)",
1414     "RSEG    (DATA)",
1415     "GSINIT  (CODE)",
1416     "OSEG    (OVR,DATA)",
1417     "GSFINAL (CODE)",
1418     "HOME    (CODE)",
1419     "XISEG   (XDATA)", // initialized xdata
1420     "XINIT   (CODE)", // a code copy of xiseg
1421     "CONST   (CODE)",           // const_name - const data (code or not)
1422     NULL,
1423     NULL,
1424     1
1425   },
1426   { _ds400_generateRomDataArea, _ds400_linkRomDataArea },
1427   {
1428     +1, 1, 4, 1, 1, 0
1429   },
1430     /* ds390 has an 16 bit mul & div */
1431   {
1432     2, -1
1433   },
1434   {
1435     ds390_emitDebuggerSymbol
1436   },
1437   {
1438     255/4,      /* maxCount */
1439     4,          /* sizeofElement */
1440     {8,12,20},  /* sizeofMatchJump[] */
1441     {10,14,22}, /* sizeofRangeCompare[] */
1442     4,          /* sizeofSubtract */
1443     7,          /* sizeofDispatch */
1444   },
1445   "_",
1446   _ds390_init,
1447   _ds390_parseOptions,
1448   NULL,
1449   NULL,
1450   _ds400_finaliseOptions,
1451   _ds390_setDefaultOptions,
1452   ds390_assignRegisters,
1453   _ds390_getRegName,
1454   _ds390_keywords,
1455   _ds390_genAssemblerPreamble,
1456   NULL,                         /* no genAssemblerEnd */
1457   _ds400_genIVT,
1458   _ds390_genXINIT,
1459   NULL,                         /* genInitStartup */
1460   _ds390_reset_regparm,
1461   _ds390_regparm,
1462   NULL,
1463   NULL,
1464   _ds390_nativeMulCheck,
1465   hasExtBitOp,                  /* hasExtBitOp */
1466   oclsExpense,                  /* oclsExpense */
1467   FALSE,
1468   TRUE,                         /* little endian */
1469   0,                            /* leave lt */
1470   0,                            /* leave gt */
1471   1,                            /* transform <= to ! > */
1472   1,                            /* transform >= to ! < */
1473   1,                            /* transform != to !(a == b) */
1474   0,                            /* leave == */
1475   TRUE,                         /* we support array initializers. */
1476   cseCostEstimation,
1477   __ds390_builtins,             /* table of builtin functions */
1478   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
1479   1,                            /* reset labelKey to 1 */
1480   1,                            /* globals & local static allowed */
1481   PORT_MAGIC
1482 };