2004-01-08 Vangelis Rokas <vrokas@otenet.gr>
[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   "sbit",
36   "using",
37   "xdata",
38   "_data",
39   "_code",
40   "_generic",
41   "_near",
42   "_xdata",
43   "_pdata",
44   "_idata",
45   "_naked",
46   NULL
47 };
48
49 static builtins __ds390_builtins[] = {
50     { "__builtin_memcpy_x2x","v",3,{"cx*","cx*","i"}}, /* void __builtin_memcpy_x2x (xdata char *,xdata char *,int) */
51     { "__builtin_memcpy_c2x","v",3,{"cx*","cp*","i"}}, /* void __builtin_memcpy_c2x (xdata char *,code  char *,int) */
52     { "__builtin_memset_x","v",3,{"cx*","c","i"}},     /* void __builtin_memset     (xdata char *,char,int)         */
53     /* __builtin_inp - used to read from a memory mapped port, increment first pointer */
54     { "__builtin_inp","v",3,{"cx*","cx*","i"}},        /* void __builtin_inp        (xdata char *,xdata char *,int) */
55     /* __builtin_inp - used to write to a memory mapped port, increment first pointer */
56     { "__builtin_outp","v",3,{"cx*","cx*","i"}},       /* void __builtin_outp       (xdata char *,xdata char *,int) */
57     { "__builtin_swapw","us",1,{"us"}},                /* unsigned short __builtin_swapw (unsigned short) */
58     { "__builtin_memcmp_x2x","c",3,{"cx*","cx*","i"}}, /* void __builtin_memcmp_x2x (xdata char *,xdata char *,int) */
59     { "__builtin_memcmp_c2x","c",3,{"cx*","cp*","i"}}, /* void __builtin_memcmp_c2x (xdata char *,code  char *,int) */
60     { NULL , NULL,0, {NULL}}                       /* mark end of table */
61 };    
62 void ds390_assignRegisters (eBBlock ** ebbs, int count);
63
64 static int regParmFlg = 0;      /* determine if we can register a parameter */
65
66 static void
67 _ds390_init (void)
68 {
69   asm_addTree (&asm_asxxxx_mapping);
70 }
71
72 static void
73 _ds390_reset_regparm ()
74 {
75   regParmFlg = 0;
76 }
77
78 static int
79 _ds390_regparm (sym_link * l)
80 {
81
82     if (options.parms_in_bank1 == 0) {
83         /* simple can pass only the first parameter in a register */
84         if (regParmFlg)
85             return 0;
86
87         regParmFlg = 1;
88         return 1;
89     } else {
90         int size = getSize(l);
91         int remain ;
92
93         /* first one goes the usual way to DPTR */
94         if (regParmFlg == 0) {
95             regParmFlg += 4 ;
96             return 1;
97         }
98         /* second one onwards goes to RB1_0 thru RB1_7 */
99         remain = regParmFlg - 4;
100         if (size > (8 - remain)) {
101             regParmFlg = 12 ;
102             return 0;
103         }
104         regParmFlg += size ;
105         return regParmFlg - size + 1;   
106     }
107 }
108
109 static bool
110 _ds390_parseOptions (int *pargc, char **argv, int *i)
111 {
112   /* TODO: allow port-specific command line options to specify
113    * segment names here.
114    */
115   return FALSE;
116 }
117
118 static void
119 _ds390_finaliseOptions (void)
120 {
121   if (options.noXinitOpt) {
122     port->genXINIT=0;
123   }
124
125   /* Hack-o-matic: if we are using the flat24 model,
126    * adjust pointer sizes.
127    */
128   if (options.model != MODEL_FLAT24)  {
129       fprintf (stderr,
130                "*** warning: ds390 port small and large model experimental.\n");
131       if (options.model == MODEL_LARGE)
132       {
133         port->mem.default_local_map = xdata;
134         port->mem.default_globl_map = xdata;
135       }
136       else
137       {
138         port->mem.default_local_map = data;
139         port->mem.default_globl_map = data;
140       }
141   }
142   else {
143     port->s.fptr_size = 3;
144     port->s.gptr_size = 4;
145
146     port->stack.isr_overhead += 2;      /* Will save dpx on ISR entry. */
147
148     port->stack.call_overhead += 2;     /* This acounts for the extra byte 
149                                  * of return addres on the stack.
150                                  * but is ugly. There must be a 
151                                  * better way.
152                                  */
153
154     port->mem.default_local_map = xdata;
155     port->mem.default_globl_map = xdata;
156
157     if (!options.stack10bit)
158     {
159     fprintf (stderr,
160              "*** error: ds390 port only supports the 10 bit stack mode.\n");
161     } else {
162         if (!options.stack_loc) options.stack_loc = 0x400008;
163     }
164     
165     /* generate native code 16*16 mul/div */
166     if (options.useAccelerator) 
167             port->support.muldiv=2;
168     else 
169             port->support.muldiv=1;
170
171      /* Fixup the memory map for the stack; it is now in
172      * far space and requires a FPOINTER to access it.
173      */
174     istack->fmap = 1;
175     istack->ptrType = FPOINTER;
176
177     if (options.parms_in_bank1) {
178         addSet(&preArgvSet, Safe_strdup("-DSDCC_PARMS_IN_BANK1"));
179     }
180   }  /* MODEL_FLAT24 */
181 }
182
183 static void
184 _ds390_setDefaultOptions (void)
185 {
186   options.model=MODEL_FLAT24;
187   options.stack10bit=1;
188 }
189
190 static const char *
191 _ds390_getRegName (struct regs *reg)
192 {
193   if (reg)
194     return reg->name;
195   return "err";
196 }
197
198 static void
199 _ds390_genAssemblerPreamble (FILE * of)
200 {
201       if (options.model == MODEL_FLAT24)
202         fputs (".flat24 on\t\t; 24 bit flat addressing\n", of);
203
204       fputs ("dpx = 0x93\t\t; dpx register unknown to assembler\n", of);
205       fputs ("dps = 0x86\t\t; dps register unknown to assembler\n", of);
206       fputs ("dpl1 = 0x84\t\t; dpl1 register unknown to assembler\n", of);
207       fputs ("dph1 = 0x85\t\t; dph1 register unknown to assembler\n", of);
208       fputs ("dpx1 = 0x95\t\t; dpx1 register unknown to assembler\n", of);
209       fputs ("ap = 0x9C\t\t; ap register unknown to assembler\n", of);
210       fputs ("_ap = 0x9C\t\t; _ap register unknown to assembler\n", of);
211       fputs ("mcnt0 = 0xD1\t\t; mcnt0 register unknown to assembler\n", of);
212       fputs ("mcnt1 = 0xD2\t\t; mcnt1 register unknown to assembler\n", of);
213       fputs ("ma = 0xD3\t\t; ma register unknown to assembler\n", of);
214       fputs ("mb = 0xD4\t\t; mb register unknown to assembler\n", of);
215       fputs ("mc = 0xD5\t\t; mc register unknown to assembler\n", of);
216       fputs ("F1 = 0xD1\t\t; F1 user flag unknown to assembler\n", of);
217       fputs ("esp = 0x9B\t\t; ESP user flag unknown to assembler\n", of);
218       if (options.parms_in_bank1) {
219           int i ;
220           for (i=0; i < 8 ; i++ )
221               fprintf (of,"b1_%d = 0x%x \n",i,8+i);
222       }
223 }
224
225 /* Generate interrupt vector table. */
226 static int
227 _ds390_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts)
228 {
229   int i;
230
231   if (options.model != MODEL_FLAT24)
232     {
233       /* Let the default code handle it. */
234       return FALSE;
235     }
236
237   fprintf (of, "\tajmp\t__reset_vect\n");
238
239   /* now for the other interrupts */
240   for (i = 0; i < maxInterrupts; i++)
241     {
242       if (interrupts[i])
243         {
244           fprintf (of, "\tljmp\t%s\n\t.ds\t4\n", interrupts[i]->rname);
245         }
246       else
247         {
248           fprintf (of, "\treti\n\t.ds\t7\n");
249         }
250     }
251
252   fprintf (of, "__reset_vect:\n\tljmp\t__sdcc_gsinit_startup\n");
253
254   return TRUE;
255 }
256
257 /* Generate code to copy XINIT to XISEG */
258 static void _ds390_genXINIT (FILE * of) {
259   fprintf (of, ";       _ds390_genXINIT() start\n");
260   fprintf (of, "        mov     a,#l_XINIT\n");
261   fprintf (of, "        orl     a,#l_XINIT>>8\n");
262   fprintf (of, "        jz      00003$\n");
263   fprintf (of, "        mov     a,#s_XINIT\n");
264   fprintf (of, "        add     a,#l_XINIT\n");
265   fprintf (of, "        mov     r1,a\n");
266   fprintf (of, "        mov     a,#s_XINIT>>8\n");
267   fprintf (of, "        addc    a,#l_XINIT>>8\n");
268   fprintf (of, "        mov     r2,a\n");
269   fprintf (of, "        mov     dptr,#s_XINIT\n");
270   fprintf (of, "        mov     dps,#0x21\n");
271   fprintf (of, "        mov     dptr,#s_XISEG\n");
272   fprintf (of, "00001$: clr     a\n");
273   fprintf (of, "        movc    a,@a+dptr\n");
274   fprintf (of, "        movx    @dptr,a\n");
275   fprintf (of, "        inc     dptr\n");
276   fprintf (of, "        inc     dptr\n");
277   fprintf (of, "00002$: mov     a,dpl\n");
278   fprintf (of, "        cjne    a,ar1,00001$\n");
279   fprintf (of, "        mov     a,dph\n");
280   fprintf (of, "        cjne    a,ar2,00001$\n");
281   fprintf (of, "        mov     dps,#0\n");
282   fprintf (of, "00003$:\n");
283   fprintf (of, ";       _ds390_genXINIT() end\n");
284 }
285
286 /* Do CSE estimation */
287 static bool cseCostEstimation (iCode *ic, iCode *pdic)
288 {
289     operand *result = IC_RESULT(ic);
290     //operand *right  = IC_RIGHT(ic);
291     //operand *left   = IC_LEFT(ic);
292     sym_link *result_type = operandType(result);
293     //sym_link *right_type  = (right ? operandType(right) : 0);
294     //sym_link *left_type   = (left  ? operandType(left)  : 0);
295     
296     /* if it is a pointer then return ok for now */
297     if (IC_RESULT(ic) && IS_PTR(result_type)) return 1;
298     
299     /* if bitwise | add & subtract then no since mcs51 is pretty good at it 
300        so we will cse only if they are local (i.e. both ic & pdic belong to
301        the same basic block */
302     if (IS_BITWISE_OP(ic) || ic->op == '+' || ic->op == '-') {
303         /* then if they are the same Basic block then ok */
304         if (ic->eBBlockNum == pdic->eBBlockNum) return 1;
305         else return 0;
306     }
307         
308     /* for others it is cheaper to do the cse */
309     return 1;
310 }
311
312 bool _ds390_nativeMulCheck(iCode *ic, sym_link *left, sym_link *right)
313 {
314     return FALSE; // #STUB
315 }
316
317 /* Indicate which extended bit operations this port supports */
318 static bool
319 hasExtBitOp (int op, int size)
320 {
321   if (op == RRC
322       || op == RLC
323       || op == GETHBIT
324       || (op == SWAP && size <= 2)
325      )
326     return TRUE;
327   else
328     return FALSE;
329 }
330
331 /* Indicate the expense of an access to an output storage class */
332 static int
333 oclsExpense (struct memmap *oclass)
334 {
335   if (IN_FARSPACE(oclass))
336     return 1;
337     
338   return 0;
339 }
340
341
342 /** $1 is always the basename.
343     $2 is always the output file.
344     $3 varies
345     $l is the list of extra options that should be there somewhere...
346     MUST be terminated with a NULL.
347 */
348 static const char *_linkCmd[] =
349 {
350   "aslink", "-nf", "\"$1\"", NULL
351 };
352
353 /* $3 is replaced by assembler.debug_opts resp. port->assembler.plain_opts */   static const char *_asmCmd[] =
354 {
355   "asx8051", "$l", "$3", "\"$1.asm\"", NULL
356 };
357
358 /* Globals */
359 PORT ds390_port =
360 {
361   TARGET_ID_DS390,
362   "ds390",
363   "DS80C390",                   /* Target name */
364   NULL,
365   {
366     glue,
367     TRUE,                       /* Emit glue around main */
368     MODEL_SMALL | MODEL_LARGE | MODEL_FLAT24,
369     MODEL_SMALL
370   },
371   {
372     _asmCmd,
373     NULL,
374     "-plosgffc",                /* Options with debug */
375     "-plosgff",                 /* Options without debug */
376     0,
377     ".asm",
378     NULL                        /* no do_assemble function */
379   },
380   {
381     _linkCmd,
382     NULL,
383     NULL,
384     ".rel"
385   },
386   {
387     _defaultRules
388   },
389   {
390         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
391     1, 2, 2, 4, 1, 2, 3, 1, 4, 4
392   },
393   {
394     "XSEG    (XDATA)",
395     "STACK   (DATA)",
396     "CSEG    (CODE)",
397     "DSEG    (DATA)",
398     "ISEG    (DATA)",
399     "XSEG    (XDATA)",
400     "BSEG    (BIT)",
401     "RSEG    (DATA)",
402     "GSINIT  (CODE)",
403     "OSEG    (OVR,DATA)",
404     "GSFINAL (CODE)",
405     "HOME    (CODE)",
406     "XISEG   (XDATA)", // initialized xdata
407     "XINIT   (CODE)", // a code copy of xiseg
408     NULL,
409     NULL,
410     1
411   },
412   { NULL, NULL },
413   {
414     +1, 1, 4, 1, 1, 0
415   },
416     /* ds390 has an 16 bit mul & div */
417   {
418     2, -1
419   },
420   "_",
421   _ds390_init,
422   _ds390_parseOptions,
423   NULL,
424   _ds390_finaliseOptions,
425   _ds390_setDefaultOptions,
426   ds390_assignRegisters,
427   _ds390_getRegName,
428   _ds390_keywords,
429   _ds390_genAssemblerPreamble,
430   NULL,                         /* no genAssemblerEnd */
431   _ds390_genIVT,
432   _ds390_genXINIT,
433   _ds390_reset_regparm,
434   _ds390_regparm,
435   NULL,
436   NULL,
437   _ds390_nativeMulCheck,
438   hasExtBitOp,                  /* hasExtBitOp */
439   oclsExpense,                  /* oclsExpense */
440   FALSE,
441   TRUE,                         /* little endian */
442   0,                            /* leave lt */
443   0,                            /* leave gt */
444   1,                            /* transform <= to ! > */
445   1,                            /* transform >= to ! < */
446   1,                            /* transform != to !(a == b) */
447   0,                            /* leave == */
448 #if 0 // obsolete, and buggy for != xdata
449   TRUE,                         /* we support array initializers. */
450 #else
451   FALSE,                        /* No array initializer support. */
452 #endif
453   cseCostEstimation,
454   __ds390_builtins,             /* table of builtin functions */
455   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
456   1,                            /* reset labelKey to 1 */
457   1,                            /* globals & local static allowed */
458   PORT_MAGIC
459 };
460
461 /*---------------------------------------------------------------------------------*/
462 /*                               TININative specific                               */
463 /*---------------------------------------------------------------------------------*/
464 /* Globals */
465 static void _tininative_init (void)
466 {
467     asm_addTree (&asm_a390_mapping);
468 }
469
470 static void _tininative_setDefaultOptions (void)
471 {
472     options.model=MODEL_FLAT24;
473     options.stack10bit=1;
474     options.stackAuto = 1;
475 }
476
477 static void _tininative_finaliseOptions (void)
478 {
479     /* Hack-o-matic: if we are using the flat24 model,
480      * adjust pointer sizes.
481      */
482     if (options.model != MODEL_FLAT24)  {
483         options.model = MODEL_FLAT24 ;
484         fprintf(stderr,"TININative supports only MODEL FLAT24\n");
485     }
486     port->s.fptr_size = 3;
487     port->s.gptr_size = 4;
488     
489     port->stack.isr_overhead += 2;      /* Will save dpx on ISR entry. */
490     
491     port->stack.call_overhead += 2;     /* This acounts for the extra byte 
492                                          * of return addres on the stack.
493                                          * but is ugly. There must be a 
494                                          * better way.
495                                          */
496     
497     port->mem.default_local_map = xdata;
498     port->mem.default_globl_map = xdata;
499     
500     if (!options.stack10bit) {
501         options.stack10bit = 1;
502         fprintf(stderr,"TININative supports only stack10bit \n");
503     }
504     
505     if (!options.stack_loc) options.stack_loc = 0x400008;
506     
507     /* generate native code 16*16 mul/div */
508     if (options.useAccelerator) 
509         port->support.muldiv=2;
510     else 
511         port->support.muldiv=1;
512     
513     /* Fixup the memory map for the stack; it is now in
514      * far space and requires a FPOINTER to access it.
515      */
516     istack->fmap = 1;
517     istack->ptrType = FPOINTER;
518     options.cc_only =1;
519 }
520
521 static int _tininative_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts) 
522 {
523     return 1;
524 }
525 static void _tininative_genAssemblerPreamble (FILE * of)
526 {
527     fputs("$include(tini.inc)\n", of);
528     fputs("$include(ds80c390.inc)\n", of);
529     fputs("$include(tinimacro.inc)\n", of);
530     fputs("$include(apiequ.inc)\n", of);
531     fputs("_bpx EQU 01Eh \t\t; _bpx (frame pointer) mapped to R8_B3:R7_B3\n", of);
532     fputs("_ap  EQU 01Dh \t\t; _ap mapped to R6_B3\n", of);
533     /* Must be first and return 0 */
534     fputs("Lib_Native_Init:\n",of);
535     fputs("\tclr\ta\n",of);
536     fputs("\tret\n",of);
537     fputs("LibraryID:\n",of);
538     fputs("\tdb \"DS\"\n",of);
539     if (options.tini_libid) {
540         fprintf(of,"\tdb 0,0,0%02xh,0%02xh,0%02xh,0%02xh\n",
541                 (options.tini_libid>>24 & 0xff),
542                 (options.tini_libid>>16 & 0xff),
543                 (options.tini_libid>>8 & 0xff),
544                 (options.tini_libid  & 0xff));
545     } else {
546         fprintf(of,"\tdb 0,0,0,0,0,1\n");
547     }
548
549 }
550 static void _tininative_genAssemblerEnd (FILE * of)
551 {
552     fputs("\tend\n",of);
553 }
554 /* tininative assembler , calls "macro", if it succeeds calls "a390" */
555 static void _tininative_do_assemble (set *asmOptions)
556 {
557     static const char *macroCmd[] = {
558         "macro","$1.a51",NULL
559     };
560     static const char *a390Cmd[] = {
561         "a390","$1.mpp",NULL
562     };
563     char buffer[100];
564
565     buildCmdLine(buffer,macroCmd,dstFileName,NULL,NULL,NULL);
566     if (my_system(buffer)) {
567         exit(1);
568     }
569     buildCmdLine(buffer,a390Cmd,dstFileName,NULL,NULL,asmOptions);
570     if (my_system(buffer)) {
571         exit(1);
572     }    
573 }
574
575 /* list of key words used by TININative */
576 static char *_tininative_keywords[] =
577 {
578   "at",
579   "bit",
580   "code",
581   "critical",
582   "data",
583   "far",
584   "idata",
585   "interrupt",
586   "near",
587   "pdata",
588   "reentrant",
589   "sfr",
590   "sbit",
591   "using",
592   "xdata",
593   "_data",
594   "_code",
595   "_generic",
596   "_near",
597   "_xdata",
598   "_pdata",
599   "_idata",
600   "_naked",
601   "_JavaNative",
602   NULL
603 };
604
605 static builtins __tininative_builtins[] = {
606     { "__builtin_memcpy_x2x","v",3,{"cx*","cx*","i"}}, /* void __builtin_memcpy_x2x (xdata char *,xdata char *,int) */
607     { "__builtin_memcpy_c2x","v",3,{"cx*","cp*","i"}}, /* void __builtin_memcpy_c2x (xdata char *,code  char *,int) */
608     { "__builtin_memset_x","v",3,{"cx*","c","i"}},     /* void __builtin_memset     (xdata char *,char,int)         */
609     /* TINI NatLib */
610     { "NatLib_LoadByte","c",1,{"c"}},                  /* char  Natlib_LoadByte  (0 based parameter number)         */
611     { "NatLib_LoadShort","s",1,{"c"}},                 /* short Natlib_LoadShort (0 based parameter number)         */
612     { "NatLib_LoadInt","l",1,{"c"}},                   /* long  Natlib_LoadLong  (0 based parameter number)         */
613     { "NatLib_LoadPointer","cx*",1,{"c"}},             /* long  Natlib_LoadPointer  (0 based parameter number)      */
614     /* TINI StateBlock related */
615     { "NatLib_InstallImmutableStateBlock","c",2,{"vx*","us"}},/* char NatLib_InstallImmutableStateBlock(state block *,int handle) */
616     { "NatLib_InstallEphemeralStateBlock","c",2,{"vx*","us"}},/* char NatLib_InstallEphemeralStateBlock(state block *,int handle) */
617     { "NatLib_RemoveImmutableStateBlock","v",0,{NULL}},/* void NatLib_RemoveImmutableStateBlock() */
618     { "NatLib_RemoveEphemeralStateBlock","v",0,{NULL}},/* void NatLib_RemoveEphemeralStateBlock() */
619     { "NatLib_GetImmutableStateBlock","i",0,{NULL}},   /* int  NatLib_GetImmutableStateBlock () */
620     { "NatLib_GetEphemeralStateBlock","i",0,{NULL}},   /* int  NatLib_GetEphemeralStateBlock () */
621     /* Memory manager */
622     { "MM_XMalloc","i",1,{"l"}},                       /* int  MM_XMalloc (long)                */
623     { "MM_Malloc","i",1,{"i"}},                        /* int  MM_Malloc  (int)                 */
624     { "MM_ApplicationMalloc","i",1,{"i"}},             /* int  MM_ApplicationMalloc  (int)      */
625     { "MM_Free","i",1,{"i"}},                          /* int  MM_Free  (int)                   */
626     { "MM_Deref","cx*",1,{"i"}},                       /* char *MM_Free  (int)                  */
627     { "MM_UnrestrictedPersist","c",1,{"i"}},           /* char  MM_UnrestrictedPersist  (int)   */
628     /* System functions */
629     { "System_ExecJavaProcess","c",2,{"cx*","i"}},     /* char System_ExecJavaProcess (char *,int) */
630     { "System_GetRTCRegisters","v",1,{"cx*"}},         /* void System_GetRTCRegisters (char *) */
631     { "System_SetRTCRegisters","v",1,{"cx*"}},         /* void System_SetRTCRegisters (char *) */
632     { "System_ThreadSleep","v",2,{"l","c"}},           /* void System_ThreadSleep (long,char)  */
633     { "System_ThreadSleep_ExitCriticalSection","v",2,{"l","c"}},/* void System_ThreadSleep_ExitCriticalSection (long,char)  */
634     { "System_ProcessSleep","v",2,{"l","c"}},           /* void System_ProcessSleep (long,char)  */
635     { "System_ProcessSleep_ExitCriticalSection","v",2,{"l","c"}},/* void System_ProcessSleep_ExitCriticalSection (long,char)  */
636     { "System_ThreadResume","c",2,{"c","c"}},          /* char System_ThreadResume(char,char)  */
637     { "System_SaveJavaThreadState","v",0,{NULL}},      /* void System_SaveJavaThreadState()    */
638     { "System_RestoreJavaThreadState","v",0,{NULL}},   /* void System_RestoreJavaThreadState() */
639     { "System_ProcessYield","v",0,{NULL}},             /* void System_ProcessYield() */
640     { "System_ProcessSuspend","v",0,{NULL}},           /* void System_ProcessSuspend() */
641     { "System_ProcessResume","v",1,{"c"}},             /* void System_ProcessResume(char) */
642     { "System_RegisterPoll","c",1,{"vF*"}},            /* char System_RegisterPoll ((void *func pointer)()) */
643     { "System_RemovePoll","c",1,{"vF*"}},              /* char System_RemovePoll ((void *func pointer)()) */
644     { "System_GetCurrentProcessId","c",0,{NULL}},      /* char System_GetCurrentProcessId() */
645     { "System_GetCurrentThreadId","c",0,{NULL}},       /* char System_GetCurrentThreadId() */
646     { NULL , NULL,0, {NULL}}                       /* mark end of table */
647 };    
648
649 static const char *_a390Cmd[] =
650 {
651   "macro", "$l", "$3", "$1.a51", NULL
652 };
653 PORT tininative_port =
654 {
655   TARGET_ID_DS390,
656   "TININative",
657   "DS80C390",                   /* Target name */
658         NULL,                   /* processor */
659   {
660     glue,
661     FALSE,                      /* Emit glue around main */
662     MODEL_FLAT24,
663     MODEL_FLAT24
664   },
665   {
666     _a390Cmd,
667     NULL,
668     "-l",               /* Options with debug */
669     "-l",               /* Options without debug */
670     0,
671     ".a51",
672     _tininative_do_assemble
673   },
674   {
675     NULL,
676     NULL,
677     NULL,
678     ".tlib",
679   },
680   {
681     _defaultRules
682   },
683   {
684         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
685     1, 2, 2, 4, 1, 3, 3, 1, 4, 4
686   },
687   {
688     "XSEG    (XDATA)",
689     "STACK   (DATA)",
690     "CSEG    (CODE)",
691     "DSEG    (DATA)",
692     "ISEG    (DATA)",
693     "XSEG    (XDATA)",
694     "BSEG    (BIT)",
695     "RSEG    (DATA)",
696     "GSINIT  (CODE)",
697     "OSEG    (OVR,DATA)",
698     "GSFINAL (CODE)",
699     "HOME        (CODE)",
700     NULL,
701     NULL,
702     NULL,
703     NULL,
704     1
705   },
706   { NULL, NULL },
707   {
708     +1, 1, 4, 1, 1, 0
709   },
710     /* ds390 has an 16 bit mul & div */
711   {
712     2, -1
713   },
714   "",
715   _tininative_init,
716   _ds390_parseOptions,
717   NULL,
718   _tininative_finaliseOptions,
719   _tininative_setDefaultOptions,
720   ds390_assignRegisters,
721   _ds390_getRegName,
722   _tininative_keywords,
723   _tininative_genAssemblerPreamble,
724   _tininative_genAssemblerEnd,
725   _tininative_genIVT,
726   NULL,
727   _ds390_reset_regparm,
728   _ds390_regparm,
729   NULL,
730   NULL,
731   NULL,
732   hasExtBitOp,                  /* hasExtBitOp */
733   oclsExpense,                  /* oclsExpense */
734   FALSE,
735   TRUE,                         /* little endian */
736   0,                            /* leave lt */
737   0,                            /* leave gt */
738   1,                            /* transform <= to ! > */
739   1,                            /* transform >= to ! < */
740   1,                            /* transform != to !(a == b) */
741   0,                            /* leave == */
742   TRUE,                         /* we support array initializers. */
743   cseCostEstimation,
744   __tininative_builtins,        /* table of builtin functions */
745   FPOINTER,                     /* treat unqualified pointers as far pointers */
746   0,                            /* DONOT reset labelKey */
747   0,                            /* globals & local static NOT allowed */
748   PORT_MAGIC
749 };
750
751 static int
752 _ds400_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts)
753 {
754     /* We can't generate a static IVT, since the boot rom creates one
755      * for us in rom_init.
756      * 
757      * we must patch it as part of the C startup.
758      */
759      fprintf (of, ";\tDS80C400 IVT must be generated at runtime.\n");
760     fprintf (of, "\tsjmp\t__sdcc_400boot\n");
761     fprintf (of, "\t.ascii\t'TINI'\t; required signature for 400 boot loader.\n");
762     fprintf (of, "\t.db\t0\t; selected bank: zero *should* work...\n");
763     fprintf (of, "\t__sdcc_400boot:\tljmp\t__sdcc_gsinit_startup\n");
764      return TRUE;
765 }
766
767     
768
769 static void
770 _ds400_finaliseOptions (void)
771 {
772   if (options.noXinitOpt) {
773     port->genXINIT=0;
774   }
775
776   // hackhack: we're a superset of the 390.
777   addSet(&preArgvSet, Safe_strdup("-DSDCC_ds390"));
778   addSet(&preArgvSet, Safe_strdup("-D__ds390"));
779     
780   /* Hack-o-matic: if we are using the flat24 model,
781    * adjust pointer sizes.
782    */
783   if (options.model != MODEL_FLAT24)  {
784       fprintf (stderr,
785                "*** warning: ds400 port small and large model experimental.\n");
786       if (options.model == MODEL_LARGE)
787       {
788         port->mem.default_local_map = xdata;
789         port->mem.default_globl_map = xdata;
790       }
791       else
792       {
793         port->mem.default_local_map = data;
794         port->mem.default_globl_map = data;
795       }
796   }
797   else {
798     port->s.fptr_size = 3;
799     port->s.gptr_size = 4;
800
801     port->stack.isr_overhead += 2;      /* Will save dpx on ISR entry. */
802
803     port->stack.call_overhead += 2;     /* This acounts for the extra byte 
804                                  * of return addres on the stack.
805                                  * but is ugly. There must be a 
806                                  * better way.
807                                  */
808
809     port->mem.default_local_map = xdata;
810     port->mem.default_globl_map = xdata;
811
812     if (!options.stack10bit)
813     {
814     fprintf (stderr,
815              "*** error: ds400 port only supports the 10 bit stack mode.\n");
816     } else {
817         if (!options.stack_loc) options.stack_loc = 0xffdc00;
818         // assumes IDM1:0 = 1:0, CMA = 1.
819     }
820     
821     /* generate native code 16*16 mul/div */
822     if (options.useAccelerator) 
823             port->support.muldiv=2;
824     else 
825             port->support.muldiv=1;
826
827      /* Fixup the memory map for the stack; it is now in
828      * far space and requires a FPOINTER to access it.
829      */
830     istack->fmap = 1;
831     istack->ptrType = FPOINTER;
832
833     if (options.parms_in_bank1) {
834         addSet(&preArgvSet, Safe_strdup("-DSDCC_PARMS_IN_BANK1"));
835     }
836      
837     // the DS400 rom calling interface uses register bank 3.
838     RegBankUsed[3] = 1;
839       
840   }  /* MODEL_FLAT24 */
841 }
842
843 extern char * iComments2;
844
845 static void _ds400_generateRomDataArea(FILE *fp, bool isMain)
846 {
847     /* Only do this for the file containing main() */
848     if (isMain)
849     {
850         fprintf(fp, "%s", iComments2);
851         fprintf(fp, "; the direct data area used by the DS80c400 ROM code.\n");
852         fprintf(fp, "%s", iComments2);
853         fprintf(fp, ".area ROMSEG (ABS,CON,DATA)\n\n");
854         fprintf(fp, ".ds 24 ; 24 bytes of directs used starting at 0x68\n\n");
855     }
856 }
857
858 static void _ds400_linkRomDataArea(FILE *fp)
859 {
860     fprintf(fp, "-b ROMSEG = 0x0068\n");
861 }
862
863
864 PORT ds400_port =
865 {
866   TARGET_ID_DS400,
867   "ds400",
868   "DS80C400",                   /* Target name */
869   NULL,
870   {
871     glue,
872     TRUE,                       /* Emit glue around main */
873     MODEL_SMALL | MODEL_LARGE | MODEL_FLAT24,
874     MODEL_SMALL
875   },
876   {
877     _asmCmd,
878     NULL,
879     "-plosgffc",                /* Options with debug */
880     "-plosgff",                 /* Options without debug */
881     0,
882     ".asm",
883     NULL                        /* no do_assemble function */
884   },
885   {
886     _linkCmd,
887     NULL,
888     NULL,
889     ".rel",
890     1
891   },
892   {
893     _defaultRules
894   },
895   {
896         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
897     1, 2, 2, 4, 1, 2, 3, 1, 4, 4
898   },
899   {
900     "XSEG    (XDATA)",
901     "STACK   (DATA)",
902     "CSEG    (CODE)",
903     "DSEG    (DATA)",
904     "ISEG    (DATA)",
905     "XSEG    (XDATA)",
906     "BSEG    (BIT)",
907     "RSEG    (DATA)",
908     "GSINIT  (CODE)",
909     "OSEG    (OVR,DATA)",
910     "GSFINAL (CODE)",
911     "HOME    (CODE)",
912     "XISEG   (XDATA)", // initialized xdata
913     "XINIT   (CODE)", // a code copy of xiseg
914     NULL,
915     NULL,
916     1
917   },
918   { _ds400_generateRomDataArea, _ds400_linkRomDataArea },
919   {
920     +1, 1, 4, 1, 1, 0
921   },
922     /* ds390 has an 16 bit mul & div */
923   {
924     2, -1
925   },
926   "_",
927   _ds390_init,
928   _ds390_parseOptions,
929   NULL,
930   _ds400_finaliseOptions,
931   _ds390_setDefaultOptions,
932   ds390_assignRegisters,
933   _ds390_getRegName,
934   _ds390_keywords,
935   _ds390_genAssemblerPreamble,
936   NULL,                         /* no genAssemblerEnd */
937   _ds400_genIVT,
938   _ds390_genXINIT,
939   _ds390_reset_regparm,
940   _ds390_regparm,
941   NULL,
942   NULL,
943   _ds390_nativeMulCheck,
944   hasExtBitOp,                  /* hasExtBitOp */
945   oclsExpense,                  /* oclsExpense */
946   FALSE,
947   TRUE,                         /* little endian */
948   0,                            /* leave lt */
949   0,                            /* leave gt */
950   1,                            /* transform <= to ! > */
951   1,                            /* transform >= to ! < */
952   1,                            /* transform != to !(a == b) */
953   0,                            /* leave == */
954   TRUE,                         /* we support array initializers. */
955   cseCostEstimation,
956   __ds390_builtins,             /* table of builtin functions */
957   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
958   1,                            /* reset labelKey to 1 */
959   1,                            /* globals & local static allowed */
960   PORT_MAGIC
961 };