Replaced cast (void **) with (void *) to avoid gcc 3 warning:
[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
318 /** $1 is always the basename.
319     $2 is always the output file.
320     $3 varies
321     $l is the list of extra options that should be there somewhere...
322     MUST be terminated with a NULL.
323 */
324 static const char *_linkCmd[] =
325 {
326   "aslink", "-nf", "\"$1\"", NULL
327 };
328
329 /* $3 is replaced by assembler.debug_opts resp. port->assembler.plain_opts */   static const char *_asmCmd[] =
330 {
331   "asx8051", "$l", "$3", "\"$1.asm\"", NULL
332 };
333
334 /* Globals */
335 PORT ds390_port =
336 {
337   TARGET_ID_DS390,
338   "ds390",
339   "DS80C390",                   /* Target name */
340   NULL,
341   {
342     glue,
343     TRUE,                       /* Emit glue around main */
344     MODEL_SMALL | MODEL_LARGE | MODEL_FLAT24,
345     MODEL_SMALL
346   },
347   {
348     _asmCmd,
349     NULL,
350     "-plosgffc",                /* Options with debug */
351     "-plosgff",                 /* Options without debug */
352     0,
353     ".asm",
354     NULL                        /* no do_assemble function */
355   },
356   {
357     _linkCmd,
358     NULL,
359     NULL,
360     ".rel"
361   },
362   {
363     _defaultRules
364   },
365   {
366         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
367     1, 2, 2, 4, 1, 2, 3, 1, 4, 4
368   },
369   {
370     "XSEG    (XDATA)",
371     "STACK   (DATA)",
372     "CSEG    (CODE)",
373     "DSEG    (DATA)",
374     "ISEG    (DATA)",
375     "XSEG    (XDATA)",
376     "BSEG    (BIT)",
377     "RSEG    (DATA)",
378     "GSINIT  (CODE)",
379     "OSEG    (OVR,DATA)",
380     "GSFINAL (CODE)",
381     "HOME    (CODE)",
382     "XISEG   (XDATA)", // initialized xdata
383     "XINIT   (CODE)", // a code copy of xiseg
384     NULL,
385     NULL,
386     1
387   },
388   { NULL, NULL },
389   {
390     +1, 1, 4, 1, 1, 0
391   },
392     /* ds390 has an 16 bit mul & div */
393   {
394     2, -1
395   },
396   "_",
397   _ds390_init,
398   _ds390_parseOptions,
399   NULL,
400   _ds390_finaliseOptions,
401   _ds390_setDefaultOptions,
402   ds390_assignRegisters,
403   _ds390_getRegName,
404   _ds390_keywords,
405   _ds390_genAssemblerPreamble,
406   NULL,                         /* no genAssemblerEnd */
407   _ds390_genIVT,
408   _ds390_genXINIT,
409   _ds390_reset_regparm,
410   _ds390_regparm,
411   NULL,
412   NULL,
413   _ds390_nativeMulCheck,
414   FALSE,
415   TRUE,                         /* little endian */
416   0,                            /* leave lt */
417   0,                            /* leave gt */
418   1,                            /* transform <= to ! > */
419   1,                            /* transform >= to ! < */
420   1,                            /* transform != to !(a == b) */
421   0,                            /* leave == */
422 #if 0 // obsolete, and buggy for != xdata
423   TRUE,                         /* we support array initializers. */
424 #else
425   FALSE,                        /* No array initializer support. */
426 #endif
427   cseCostEstimation,
428   __ds390_builtins,             /* table of builtin functions */
429   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
430   1,                            /* reset labelKey to 1 */
431   1,                            /* globals & local static allowed */
432   PORT_MAGIC
433 };
434
435 /*---------------------------------------------------------------------------------*/
436 /*                               TININative specific                               */
437 /*---------------------------------------------------------------------------------*/
438 /* Globals */
439 static void _tininative_init (void)
440 {
441     asm_addTree (&asm_a390_mapping);
442 }
443
444 static void _tininative_setDefaultOptions (void)
445 {
446     options.model=MODEL_FLAT24;
447     options.stack10bit=1;
448     options.stackAuto = 1;
449 }
450
451 static void _tininative_finaliseOptions (void)
452 {
453     /* Hack-o-matic: if we are using the flat24 model,
454      * adjust pointer sizes.
455      */
456     if (options.model != MODEL_FLAT24)  {
457         options.model = MODEL_FLAT24 ;
458         fprintf(stderr,"TININative supports only MODEL FLAT24\n");
459     }
460     port->s.fptr_size = 3;
461     port->s.gptr_size = 4;
462     
463     port->stack.isr_overhead += 2;      /* Will save dpx on ISR entry. */
464     
465     port->stack.call_overhead += 2;     /* This acounts for the extra byte 
466                                          * of return addres on the stack.
467                                          * but is ugly. There must be a 
468                                          * better way.
469                                          */
470     
471     port->mem.default_local_map = xdata;
472     port->mem.default_globl_map = xdata;
473     
474     if (!options.stack10bit) {
475         options.stack10bit = 1;
476         fprintf(stderr,"TININative supports only stack10bit \n");
477     }
478     
479     if (!options.stack_loc) options.stack_loc = 0x400008;
480     
481     /* generate native code 16*16 mul/div */
482     if (options.useAccelerator) 
483         port->support.muldiv=2;
484     else 
485         port->support.muldiv=1;
486     
487     /* Fixup the memory map for the stack; it is now in
488      * far space and requires a FPOINTER to access it.
489      */
490     istack->fmap = 1;
491     istack->ptrType = FPOINTER;
492     options.cc_only =1;
493 }
494
495 static int _tininative_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts) 
496 {
497     return 1;
498 }
499 static void _tininative_genAssemblerPreamble (FILE * of)
500 {
501     fputs("$include(tini.inc)\n", of);
502     fputs("$include(ds80c390.inc)\n", of);
503     fputs("$include(tinimacro.inc)\n", of);
504     fputs("$include(apiequ.inc)\n", of);
505     fputs("_bpx EQU 01Eh \t\t; _bpx (frame pointer) mapped to R8_B3:R7_B3\n", of);
506     fputs("_ap  EQU 01Dh \t\t; _ap mapped to R6_B3\n", of);
507     /* Must be first and return 0 */
508     fputs("Lib_Native_Init:\n",of);
509     fputs("\tclr\ta\n",of);
510     fputs("\tret\n",of);
511     fputs("LibraryID:\n",of);
512     fputs("\tdb \"DS\"\n",of);
513     if (options.tini_libid) {
514         fprintf(of,"\tdb 0,0,0%02xh,0%02xh,0%02xh,0%02xh\n",
515                 (options.tini_libid>>24 & 0xff),
516                 (options.tini_libid>>16 & 0xff),
517                 (options.tini_libid>>8 & 0xff),
518                 (options.tini_libid  & 0xff));
519     } else {
520         fprintf(of,"\tdb 0,0,0,0,0,1\n");
521     }
522
523 }
524 static void _tininative_genAssemblerEnd (FILE * of)
525 {
526     fputs("\tend\n",of);
527 }
528 /* tininative assembler , calls "macro", if it succeeds calls "a390" */
529 static void _tininative_do_assemble (set *asmOptions)
530 {
531     static const char *macroCmd[] = {
532         "macro","$1.a51",NULL
533     };
534     static const char *a390Cmd[] = {
535         "a390","$1.mpp",NULL
536     };
537     char buffer[100];
538
539     buildCmdLine(buffer,macroCmd,dstFileName,NULL,NULL,NULL);
540     if (my_system(buffer)) {
541         exit(1);
542     }
543     buildCmdLine(buffer,a390Cmd,dstFileName,NULL,NULL,asmOptions);
544     if (my_system(buffer)) {
545         exit(1);
546     }    
547 }
548
549 /* list of key words used by TININative */
550 static char *_tininative_keywords[] =
551 {
552   "at",
553   "bit",
554   "code",
555   "critical",
556   "data",
557   "far",
558   "idata",
559   "interrupt",
560   "near",
561   "pdata",
562   "reentrant",
563   "sfr",
564   "sbit",
565   "using",
566   "xdata",
567   "_data",
568   "_code",
569   "_generic",
570   "_near",
571   "_xdata",
572   "_pdata",
573   "_idata",
574   "_naked",
575   "_JavaNative",
576   NULL
577 };
578
579 static builtins __tininative_builtins[] = {
580     { "__builtin_memcpy_x2x","v",3,{"cx*","cx*","i"}}, /* void __builtin_memcpy_x2x (xdata char *,xdata char *,int) */
581     { "__builtin_memcpy_c2x","v",3,{"cx*","cp*","i"}}, /* void __builtin_memcpy_c2x (xdata char *,code  char *,int) */
582     { "__builtin_memset_x","v",3,{"cx*","c","i"}},     /* void __builtin_memset     (xdata char *,char,int)         */
583     /* TINI NatLib */
584     { "NatLib_LoadByte","c",1,{"c"}},                  /* char  Natlib_LoadByte  (0 based parameter number)         */
585     { "NatLib_LoadShort","s",1,{"c"}},                 /* short Natlib_LoadShort (0 based parameter number)         */
586     { "NatLib_LoadInt","l",1,{"c"}},                   /* long  Natlib_LoadLong  (0 based parameter number)         */
587     { "NatLib_LoadPointer","cx*",1,{"c"}},             /* long  Natlib_LoadPointer  (0 based parameter number)      */
588     /* TINI StateBlock related */
589     { "NatLib_InstallImmutableStateBlock","c",2,{"vx*","us"}},/* char NatLib_InstallImmutableStateBlock(state block *,int handle) */
590     { "NatLib_InstallEphemeralStateBlock","c",2,{"vx*","us"}},/* char NatLib_InstallEphemeralStateBlock(state block *,int handle) */
591     { "NatLib_RemoveImmutableStateBlock","v",0,{NULL}},/* void NatLib_RemoveImmutableStateBlock() */
592     { "NatLib_RemoveEphemeralStateBlock","v",0,{NULL}},/* void NatLib_RemoveEphemeralStateBlock() */
593     { "NatLib_GetImmutableStateBlock","i",0,{NULL}},   /* int  NatLib_GetImmutableStateBlock () */
594     { "NatLib_GetEphemeralStateBlock","i",0,{NULL}},   /* int  NatLib_GetEphemeralStateBlock () */
595     /* Memory manager */
596     { "MM_XMalloc","i",1,{"l"}},                       /* int  MM_XMalloc (long)                */
597     { "MM_Malloc","i",1,{"i"}},                        /* int  MM_Malloc  (int)                 */
598     { "MM_ApplicationMalloc","i",1,{"i"}},             /* int  MM_ApplicationMalloc  (int)      */
599     { "MM_Free","i",1,{"i"}},                          /* int  MM_Free  (int)                   */
600     { "MM_Deref","cx*",1,{"i"}},                       /* char *MM_Free  (int)                  */
601     { "MM_UnrestrictedPersist","c",1,{"i"}},           /* char  MM_UnrestrictedPersist  (int)   */
602     /* System functions */
603     { "System_ExecJavaProcess","c",2,{"cx*","i"}},     /* char System_ExecJavaProcess (char *,int) */
604     { "System_GetRTCRegisters","v",1,{"cx*"}},         /* void System_GetRTCRegisters (char *) */
605     { "System_SetRTCRegisters","v",1,{"cx*"}},         /* void System_SetRTCRegisters (char *) */
606     { "System_ThreadSleep","v",2,{"l","c"}},           /* void System_ThreadSleep (long,char)  */
607     { "System_ThreadSleep_ExitCriticalSection","v",2,{"l","c"}},/* void System_ThreadSleep_ExitCriticalSection (long,char)  */
608     { "System_ProcessSleep","v",2,{"l","c"}},           /* void System_ProcessSleep (long,char)  */
609     { "System_ProcessSleep_ExitCriticalSection","v",2,{"l","c"}},/* void System_ProcessSleep_ExitCriticalSection (long,char)  */
610     { "System_ThreadResume","c",2,{"c","c"}},          /* char System_ThreadResume(char,char)  */
611     { "System_SaveJavaThreadState","v",0,{NULL}},      /* void System_SaveJavaThreadState()    */
612     { "System_RestoreJavaThreadState","v",0,{NULL}},   /* void System_RestoreJavaThreadState() */
613     { "System_ProcessYield","v",0,{NULL}},             /* void System_ProcessYield() */
614     { "System_ProcessSuspend","v",0,{NULL}},           /* void System_ProcessSuspend() */
615     { "System_ProcessResume","v",1,{"c"}},             /* void System_ProcessResume(char) */
616     { "System_RegisterPoll","c",1,{"vF*"}},            /* char System_RegisterPoll ((void *func pointer)()) */
617     { "System_RemovePoll","c",1,{"vF*"}},              /* char System_RemovePoll ((void *func pointer)()) */
618     { "System_GetCurrentProcessId","c",0,{NULL}},      /* char System_GetCurrentProcessId() */
619     { "System_GetCurrentThreadId","c",0,{NULL}},       /* char System_GetCurrentThreadId() */
620     { NULL , NULL,0, {NULL}}                       /* mark end of table */
621 };    
622
623 static const char *_a390Cmd[] =
624 {
625   "macro", "$l", "$3", "$1.a51", NULL
626 };
627 PORT tininative_port =
628 {
629   TARGET_ID_DS390,
630   "TININative",
631   "DS80C390",                   /* Target name */
632         NULL,                   /* processor */
633   {
634     FALSE,                      /* Emit glue around main */
635     MODEL_FLAT24,
636     MODEL_FLAT24
637   },
638   {
639     _a390Cmd,
640     NULL,
641     "-l",               /* Options with debug */
642     "-l",               /* Options without debug */
643     0,
644     ".a51",
645     _tininative_do_assemble
646   },
647   {
648     NULL,
649     NULL,
650     NULL,
651     ".tlib",
652   },
653   {
654     _defaultRules
655   },
656   {
657         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
658     1, 2, 2, 4, 1, 3, 3, 1, 4, 4
659   },
660   {
661     "XSEG    (XDATA)",
662     "STACK   (DATA)",
663     "CSEG    (CODE)",
664     "DSEG    (DATA)",
665     "ISEG    (DATA)",
666     "XSEG    (XDATA)",
667     "BSEG    (BIT)",
668     "RSEG    (DATA)",
669     "GSINIT  (CODE)",
670     "OSEG    (OVR,DATA)",
671     "GSFINAL (CODE)",
672     "HOME        (CODE)",
673     NULL,
674     NULL,
675     NULL,
676     NULL,
677     1
678   },
679   { NULL, NULL },
680   {
681     +1, 1, 4, 1, 1, 0
682   },
683     /* ds390 has an 16 bit mul & div */
684   {
685     2, -1
686   },
687   "",
688   _tininative_init,
689   _ds390_parseOptions,
690   NULL,
691   _tininative_finaliseOptions,
692   _tininative_setDefaultOptions,
693   ds390_assignRegisters,
694   _ds390_getRegName,
695   _tininative_keywords,
696   _tininative_genAssemblerPreamble,
697   _tininative_genAssemblerEnd,
698   _tininative_genIVT,
699   NULL,
700   _ds390_reset_regparm,
701   _ds390_regparm,
702   NULL,
703   NULL,
704   NULL,
705   FALSE,
706   TRUE,                         /* little endian */
707   0,                            /* leave lt */
708   0,                            /* leave gt */
709   1,                            /* transform <= to ! > */
710   1,                            /* transform >= to ! < */
711   1,                            /* transform != to !(a == b) */
712   0,                            /* leave == */
713   TRUE,                         /* we support array initializers. */
714   cseCostEstimation,
715   __tininative_builtins,        /* table of builtin functions */
716   FPOINTER,                     /* treat unqualified pointers as far pointers */
717   0,                            /* DONOT reset labelKey */
718   0,                            /* globals & local static NOT allowed */
719   PORT_MAGIC
720 };
721
722 static int
723 _ds400_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts)
724 {
725     /* We can't generate a static IVT, since the boot rom creates one
726      * for us in rom_init.
727      * 
728      * we must patch it as part of the C startup.
729      */
730      fprintf (of, ";\tDS80C400 IVT must be generated at runtime.\n");
731     fprintf (of, "\tsjmp\t__sdcc_400boot\n");
732     fprintf (of, "\t.ascii\t'TINI'\t; required signature for 400 boot loader.\n");
733     fprintf (of, "\t.db\t0\t; selected bank: zero *should* work...\n");
734     fprintf (of, "\t__sdcc_400boot:\tljmp\t__sdcc_gsinit_startup\n");
735      return TRUE;
736 }
737
738     
739
740 static void
741 _ds400_finaliseOptions (void)
742 {
743   if (options.noXinitOpt) {
744     port->genXINIT=0;
745   }
746
747   // hackhack: we're a superset of the 390.
748   addSet(&preArgvSet, Safe_strdup("-DSDCC_ds390"));
749   addSet(&preArgvSet, Safe_strdup("-D__ds390"));
750     
751   /* Hack-o-matic: if we are using the flat24 model,
752    * adjust pointer sizes.
753    */
754   if (options.model != MODEL_FLAT24)  {
755       fprintf (stderr,
756                "*** warning: ds400 port small and large model experimental.\n");
757       if (options.model == MODEL_LARGE)
758       {
759         port->mem.default_local_map = xdata;
760         port->mem.default_globl_map = xdata;
761       }
762       else
763       {
764         port->mem.default_local_map = data;
765         port->mem.default_globl_map = data;
766       }
767   }
768   else {
769     port->s.fptr_size = 3;
770     port->s.gptr_size = 4;
771
772     port->stack.isr_overhead += 2;      /* Will save dpx on ISR entry. */
773
774     port->stack.call_overhead += 2;     /* This acounts for the extra byte 
775                                  * of return addres on the stack.
776                                  * but is ugly. There must be a 
777                                  * better way.
778                                  */
779
780     port->mem.default_local_map = xdata;
781     port->mem.default_globl_map = xdata;
782
783     if (!options.stack10bit)
784     {
785     fprintf (stderr,
786              "*** error: ds400 port only supports the 10 bit stack mode.\n");
787     } else {
788         if (!options.stack_loc) options.stack_loc = 0xffdc00;
789         // assumes IDM1:0 = 1:0, CMA = 1.
790     }
791     
792     /* generate native code 16*16 mul/div */
793     if (options.useAccelerator) 
794             port->support.muldiv=2;
795     else 
796             port->support.muldiv=1;
797
798      /* Fixup the memory map for the stack; it is now in
799      * far space and requires a FPOINTER to access it.
800      */
801     istack->fmap = 1;
802     istack->ptrType = FPOINTER;
803
804     if (options.parms_in_bank1) {
805         addSet(&preArgvSet, Safe_strdup("-DSDCC_PARMS_IN_BANK1"));
806     }
807      
808     // the DS400 rom calling interface uses register bank 3.
809     RegBankUsed[3] = 1;
810       
811   }  /* MODEL_FLAT24 */
812 }
813
814 extern char * iComments2;
815
816 static void _ds400_generateRomDataArea(FILE *fp, bool isMain)
817 {
818     /* Only do this for the file containing main() */
819     if (isMain)
820     {
821         fprintf(fp, "%s", iComments2);
822         fprintf(fp, "; the direct data area used by the DS80c400 ROM code.\n");
823         fprintf(fp, "%s", iComments2);
824         fprintf(fp, ".area ROMSEG (ABS,CON,DATA)\n\n");
825         fprintf(fp, ".ds 24 ; 24 bytes of directs used starting at 0x68\n\n");
826     }
827 }
828
829 static void _ds400_linkRomDataArea(FILE *fp)
830 {
831     fprintf(fp, "-b ROMSEG = 0x0068\n");
832 }
833
834
835 PORT ds400_port =
836 {
837   TARGET_ID_DS400,
838   "ds400",
839   "DS80C400",                   /* Target name */
840   NULL,
841   {
842     glue,
843     TRUE,                       /* Emit glue around main */
844     MODEL_SMALL | MODEL_LARGE | MODEL_FLAT24,
845     MODEL_SMALL
846   },
847   {
848     _asmCmd,
849     NULL,
850     "-plosgffc",                /* Options with debug */
851     "-plosgff",                 /* Options without debug */
852     0,
853     ".asm",
854     NULL                        /* no do_assemble function */
855   },
856   {
857     _linkCmd,
858     NULL,
859     NULL,
860     ".rel"
861   },
862   {
863     _defaultRules
864   },
865   {
866         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
867     1, 2, 2, 4, 1, 2, 3, 1, 4, 4
868   },
869   {
870     "XSEG    (XDATA)",
871     "STACK   (DATA)",
872     "CSEG    (CODE)",
873     "DSEG    (DATA)",
874     "ISEG    (DATA)",
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     NULL,
885     NULL,
886     1
887   },
888   { _ds400_generateRomDataArea, _ds400_linkRomDataArea },
889   {
890     +1, 1, 4, 1, 1, 0
891   },
892     /* ds390 has an 16 bit mul & div */
893   {
894     2, -1
895   },
896   "_",
897   _ds390_init,
898   _ds390_parseOptions,
899   NULL,
900   _ds400_finaliseOptions,
901   _ds390_setDefaultOptions,
902   ds390_assignRegisters,
903   _ds390_getRegName,
904   _ds390_keywords,
905   _ds390_genAssemblerPreamble,
906   NULL,                         /* no genAssemblerEnd */
907   _ds400_genIVT,
908   _ds390_genXINIT,
909   _ds390_reset_regparm,
910   _ds390_regparm,
911   NULL,
912   NULL,
913   _ds390_nativeMulCheck,
914   FALSE,
915   TRUE,                         /* little endian */
916   0,                            /* leave lt */
917   0,                            /* leave gt */
918   1,                            /* transform <= to ! > */
919   1,                            /* transform >= to ! < */
920   1,                            /* transform != to !(a == b) */
921   0,                            /* leave == */
922   TRUE,                         /* we support array initializers. */
923   cseCostEstimation,
924   __ds390_builtins,             /* table of builtin functions */
925   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
926   1,                            /* reset labelKey to 1 */
927   1,                            /* globals & local static allowed */
928   PORT_MAGIC
929 };