ee97d6883d355b38039c01f9bd71cd2c1c8ec01e
[fw/sdcc] / src / mcs51 / main.c
1 /** @file main.c
2     mcs51 specific general functions.
3
4     Note that mlh prepended _mcs51_ 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 "../SDCCutil.h"
12
13 static char _defaultRules[] =
14 {
15 #include "peeph.rul"
16 };
17
18 /* list of key words used by msc51 */
19 static char *_mcs51_keywords[] =
20 {
21   "at",
22   "bit",
23   "code",
24   "critical",
25   "data",
26   "far",
27   "idata",
28   "interrupt",
29   "near",
30   "pdata",
31   "reentrant",
32   "sfr",
33   "sbit",
34   "using",
35   "xdata",
36   "_data",
37   "_code",
38   "_generic",
39   "_near",
40   "_xdata",
41   "_pdata",
42   "_idata",
43   "_naked",
44   "_overlay",
45   NULL
46 };
47
48
49
50 void mcs51_assignRegisters (eBBlock ** ebbs, int count);
51
52 static int regParmFlg = 0;      /* determine if we can register a parameter */
53
54 static void
55 _mcs51_init (void)
56 {
57   asm_addTree (&asm_asxxxx_mapping);
58 }
59
60 static void
61 _mcs51_reset_regparm ()
62 {
63   regParmFlg = 0;
64 }
65
66 static int
67 _mcs51_regparm (sym_link * l)
68 {
69     if (options.parms_in_bank1 == 0) {
70         /* simple can pass only the first parameter in a register */
71         if (regParmFlg)
72             return 0;
73
74         regParmFlg = 1;
75         return 1;
76     } else {
77         int size = getSize(l);
78         int remain ;
79
80         /* first one goes the usual way to DPTR */
81         if (regParmFlg == 0) {
82             regParmFlg += 4 ;
83             return 1;
84         }
85         /* second one onwards goes to RB1_0 thru RB1_7 */
86         remain = regParmFlg - 4;
87         if (size > (8 - remain)) {
88             regParmFlg = 12 ;
89             return 0;
90         }
91         regParmFlg += size ;
92         return regParmFlg - size + 1;   
93     }
94 }
95
96 static bool
97 _mcs51_parseOptions (int *pargc, char **argv, int *i)
98 {
99   /* TODO: allow port-specific command line options to specify
100    * segment names here.
101    */
102   return FALSE;
103 }
104
105 static void
106 _mcs51_finaliseOptions (void)
107 {
108   if (options.noXinitOpt) {
109     port->genXINIT=0;
110   }
111
112   if (options.model == MODEL_LARGE) {
113       port->mem.default_local_map = xdata;
114       port->mem.default_globl_map = xdata;
115     }
116   else
117     {
118       port->mem.default_local_map = data;
119       port->mem.default_globl_map = data;
120     }
121
122   if (options.parms_in_bank1) {
123       addSet(&preArgvSet, Safe_strdup("-DSDCC_PARMS_IN_BANK1"));
124   }
125 }
126
127 static void
128 _mcs51_setDefaultOptions (void)
129 {
130 }
131
132 static const char *
133 _mcs51_getRegName (struct regs *reg)
134 {
135   if (reg)
136     return reg->name;
137   return "err";
138 }
139
140 static void
141 _mcs51_genAssemblerPreamble (FILE * of)
142 {
143     if (options.parms_in_bank1) {
144         int i ;
145         for (i=0; i < 8 ; i++ )
146             fprintf (of,"b1_%d = 0x%x \n",i,8+i);
147     }
148 }
149
150 /* Generate interrupt vector table. */
151 static int
152 _mcs51_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts)
153 {
154   return FALSE;
155 }
156
157 /* Generate code to clear XSEG and idata memory. 
158    This clears XSEG, DSEG, BSEG, OSEG, SSEG */
159 static void _mcs51_genRAMCLEAR (FILE * of) {
160   fprintf (of, ";       _mcs51_genRAMCLEAR() start\n");
161   fprintf (of, "        mov     r0,#l_XSEG\n");
162   fprintf (of, "        mov     a,r0\n");
163   fprintf (of, "        orl     a,#(l_XSEG >> 8)\n");
164   fprintf (of, "        jz      00005$\n");
165   fprintf (of, "        mov     r1,#((l_XSEG + 255) >> 8)\n");
166   fprintf (of, "        mov     dptr,#s_XSEG\n");
167   fprintf (of, "        clr     a\n");
168   fprintf (of, "00004$: movx    @dptr,a\n");
169   fprintf (of, "        inc     dptr\n");
170   fprintf (of, "        djnz    r0,00004$\n");
171   fprintf (of, "        djnz    r1,00004$\n");
172   /* r0 is zero now. Clearing 256 byte assuming 128 byte devices don't mind */
173   fprintf (of, "00005$: mov     @r0,a\n");   
174   fprintf (of, "        djnz    r0,00005$\n");
175   fprintf (of, ";       _mcs51_genRAMCLEAR() end\n");
176 }
177
178 /* Generate code to copy XINIT to XISEG */
179 static void _mcs51_genXINIT (FILE * of) {
180   fprintf (of, ";       _mcs51_genXINIT() start\n");
181   fprintf (of, "        mov     r1,#l_XINIT\n");
182   fprintf (of, "        mov     a,r1\n");
183   fprintf (of, "        orl     a,#(l_XINIT >> 8)\n");
184   fprintf (of, "        jz      00003$\n");
185   fprintf (of, "        mov     r2,#((l_XINIT+255) >> 8)\n");
186   fprintf (of, "        mov     dptr,#s_XINIT\n");
187   fprintf (of, "        mov     r0,#s_XISEG\n");
188   fprintf (of, "        mov     p2,#(s_XISEG >> 8)\n");
189   fprintf (of, "00001$: clr     a\n");
190   fprintf (of, "        movc    a,@a+dptr\n");
191   fprintf (of, "        movx    @r0,a\n");
192   fprintf (of, "        inc     dptr\n");
193   fprintf (of, "        inc     r0\n");
194   fprintf (of, "        cjne    r0,#0,00002$\n");
195   fprintf (of, "        inc     p2\n");
196   fprintf (of, "00002$: djnz    r1,00001$\n");
197   fprintf (of, "        djnz    r2,00001$\n");
198   fprintf (of, "        mov     p2,#0xFF\n");
199   fprintf (of, "00003$:\n");
200   fprintf (of, ";       _mcs51_genXINIT() end\n");
201   
202   if (!getenv("SDCC_NOGENRAMCLEAR")) _mcs51_genRAMCLEAR (of);
203 }
204
205
206 /* Do CSE estimation */
207 static bool cseCostEstimation (iCode *ic, iCode *pdic)
208 {
209     operand *result = IC_RESULT(ic);
210     sym_link *result_type = operandType(result);
211
212     /* if it is a pointer then return ok for now */
213     if (IC_RESULT(ic) && IS_PTR(result_type)) return 1;
214     
215     /* if bitwise | add & subtract then no since mcs51 is pretty good at it 
216        so we will cse only if they are local (i.e. both ic & pdic belong to
217        the same basic block */
218     if (IS_BITWISE_OP(ic) || ic->op == '+' || ic->op == '-') {
219         /* then if they are the same Basic block then ok */
220         if (ic->eBBlockNum == pdic->eBBlockNum) return 1;
221         else return 0;
222     }
223         
224     /* for others it is cheaper to do the cse */
225     return 1;
226 }
227
228 /* Indicate which extended bit operations this port supports */
229 static bool
230 hasExtBitOp (int op, int size)
231 {
232   if (op == RRC
233       || op == RLC
234       || op == GETHBIT
235       || (op == SWAP && size <= 2)
236      )
237     return TRUE;
238   else
239     return FALSE;
240 }
241
242 /* Indicate the expense of an access to an output storage class */
243 static int
244 oclsExpense (struct memmap *oclass)
245 {
246   if (IN_FARSPACE(oclass))
247     return 1;
248     
249   return 0;
250 }
251
252
253
254 static int
255 instructionSize(char *inst, char *op1, char *op2)
256 {
257   #define ISINST(s) (strncmp(inst, (s), sizeof(s)-1) == 0)
258   #define IS_A(s) (*(s) == 'a' && *(s+1) == '\0')
259   #define IS_C(s) (*(s) == 'c' && *(s+1) == '\0')
260   #define IS_Rn(s) (*(s) == 'r' && *(s+1) >= '0' && *(s+1) <= '7')
261   #define IS_atRi(s) (*(s) == '@' && *(s+1) == 'r')
262
263   /* Based on the current (2003-08-22) code generation for the
264      small library, the top instruction probability is:
265    
266        57% mov/movx/movc
267         6% push
268         6% pop
269         4% inc
270         4% lcall
271         4% add
272         3% clr
273         2% subb
274   */
275   /* mov, push, & pop are the 69% of the cases. Check them first! */
276   if (ISINST ("mov"))
277     {
278       if (*(inst+3)=='x') return 1; /* movx */
279       if (*(inst+3)=='c') return 1; /* movc */
280       if (IS_C (op1) || IS_C (op2)) return 2;
281       if (IS_A (op1))
282         {
283           if (IS_Rn (op2) || IS_atRi (op2)) return 1;
284           return 2;
285         }
286       if (IS_Rn(op1) || IS_atRi(op1))
287         {
288           if (IS_A(op2)) return 1;
289           return 2;
290         }
291       if (strcmp (op1, "dptr") == 0) return 3;
292       if (IS_A (op2) || IS_Rn (op2) || IS_atRi (op2)) return 2;
293       return 3;
294     }
295   
296   if (ISINST ("push")) return 2;
297   if (ISINST ("pop")) return 2;
298
299   if (ISINST ("lcall")) return 3;
300   if (ISINST ("ret")) return 1;
301   if (ISINST ("ljmp")) return 3;
302   if (ISINST ("sjmp")) return 2;
303   if (ISINST ("rlc")) return 1;
304   if (ISINST ("rrc")) return 1;
305   if (ISINST ("rl")) return 1;
306   if (ISINST ("rr")) return 1;
307   if (ISINST ("swap")) return 1;
308   if (ISINST ("jc")) return 2;
309   if (ISINST ("jnc")) return 2;
310   if (ISINST ("jb")) return 3;
311   if (ISINST ("jnb")) return 3;
312   if (ISINST ("jbc")) return 3;
313   if (ISINST ("jmp")) return 1; // always jmp @a+dptr
314   if (ISINST ("jz")) return 2;
315   if (ISINST ("jnz")) return 2;
316   if (ISINST ("cjne")) return 3;
317   if (ISINST ("mul")) return 1;
318   if (ISINST ("div")) return 1;
319   if (ISINST ("da")) return 1;
320   if (ISINST ("xchd")) return 1;
321   if (ISINST ("reti")) return 1;
322   if (ISINST ("nop")) return 1;
323   if (ISINST ("acall")) return 1;
324   if (ISINST ("ajmp")) return 2;
325
326     
327   if (ISINST ("add") || ISINST ("addc") || ISINST ("subb") || ISINST ("xch"))
328     {
329       if (IS_Rn(op2) || IS_atRi(op2)) return 1;
330       return 2;
331     }
332   if (ISINST ("inc") || ISINST ("dec"))
333     {
334       if (IS_A(op1) || IS_Rn(op1) || IS_atRi(op1)) return 1;
335       if (strcmp(op1, "dptr") == 0) return 1;
336       return 2;
337     }
338   if (ISINST ("anl") || ISINST ("orl") || ISINST ("xrl"))
339     {
340       if (IS_C(op1)) return 2;
341       if (IS_A(op1))
342         {
343           if (IS_Rn(op2) || IS_atRi(op2)) return 1;
344           return 2;
345         }
346       else
347         {
348           if (IS_A(op2)) return 2;
349           return 3;
350         }
351     }
352   if (ISINST ("clr") || ISINST ("setb") || ISINST ("cpl"))
353     {
354       if (IS_A(op1) || IS_C(op1)) return 1;
355       return 2;
356     }
357   if (ISINST ("djnz"))
358     {
359       if (IS_Rn(op1)) return 2;
360       return 3;
361     }
362
363   /* If the instruction is unrecognized, we shouldn't try to optimize. */
364   /* Return a large value to discourage optimization.                  */
365   return 999;
366 }
367
368 static asmLineNode *
369 newAsmLineNode (void)
370 {
371   asmLineNode *aln;
372
373   aln = Safe_alloc ( sizeof (asmLineNode));
374   aln->size = 0;
375   aln->regsRead = NULL;
376   aln->regsWritten = NULL;
377   
378   return aln;
379 }
380
381
382 typedef struct mcs51operanddata
383   {
384     char name[6];
385     int regIdx1;
386     int regIdx2;
387   }
388 mcs51operanddata;
389
390 static mcs51operanddata mcs51operandDataTable[] =
391   {
392     {"a", A_IDX, -1},
393     {"ab", A_IDX, B_IDX},
394     {"ac", CND_IDX, -1},
395     {"acc", A_IDX, -1},
396     {"ar0", R0_IDX, -1},
397     {"ar1", R1_IDX, -1},
398     {"ar2", R2_IDX, -1},
399     {"ar3", R3_IDX, -1},
400     {"ar4", R4_IDX, -1},
401     {"ar5", R5_IDX, -1},
402     {"ar6", R6_IDX, -1},
403     {"ar7", R7_IDX, -1},
404     {"b", B_IDX, -1},
405     {"c", CND_IDX, -1},
406     {"cy", CND_IDX, -1},
407     {"dph", DPH_IDX, -1},
408     {"dpl", DPL_IDX, -1},
409     {"dptr", DPL_IDX, DPH_IDX},
410     {"f0", CND_IDX, -1},
411     {"f1", CND_IDX, -1},
412     {"ov", CND_IDX, -1},
413     {"p", CND_IDX, -1},
414     {"psw", CND_IDX, -1},
415     {"r0", R0_IDX, -1},
416     {"r1", R1_IDX, -1},
417     {"r2", R2_IDX, -1},
418     {"r3", R3_IDX, -1},
419     {"r4", R4_IDX, -1},
420     {"r5", R5_IDX, -1},
421     {"r6", R6_IDX, -1},
422     {"r7", R7_IDX, -1},
423   };
424
425 static int
426 mcs51operandCompare (const void *key, const void *member)
427 {
428   return strcmp((const char *)key, ((mcs51operanddata *)member)->name);
429 }
430
431 static void      
432 updateOpRW (asmLineNode *aln, char *op, char *optype)
433 {
434   mcs51operanddata *opdat;
435   char *dot;
436   
437   dot = strchr(op, '.');
438   if (dot)
439     *dot = '\0';
440
441   opdat = bsearch (op, mcs51operandDataTable,
442                    sizeof(mcs51operandDataTable)/sizeof(mcs51operanddata),
443                    sizeof(mcs51operanddata), mcs51operandCompare);
444   
445   if (opdat && strchr(optype,'r'))
446     {
447       if (opdat->regIdx1 >= 0)
448         aln->regsRead = bitVectSetBit (aln->regsRead, opdat->regIdx1);
449       if (opdat->regIdx2 >= 0)
450         aln->regsRead = bitVectSetBit (aln->regsRead, opdat->regIdx2);
451     }
452   if (opdat && strchr(optype,'w'))
453     {
454       if (opdat->regIdx1 >= 0)
455         aln->regsWritten = bitVectSetBit (aln->regsWritten, opdat->regIdx1);
456       if (opdat->regIdx2 >= 0)
457         aln->regsWritten = bitVectSetBit (aln->regsWritten, opdat->regIdx2);
458     }
459   if (op[0] == '@')
460     {
461       if (!strcmp(op, "@r0"))
462         aln->regsRead = bitVectSetBit (aln->regsRead, R0_IDX);
463       if (!strcmp(op, "@r1"))
464         aln->regsRead = bitVectSetBit (aln->regsRead, R1_IDX);
465       if (!strstr(op, "dptr"))
466         {
467           aln->regsRead = bitVectSetBit (aln->regsRead, DPL_IDX);
468           aln->regsRead = bitVectSetBit (aln->regsRead, DPH_IDX);
469         }
470       if (!strstr(op, "a+"))
471         aln->regsRead = bitVectSetBit (aln->regsRead, A_IDX);
472     }
473 }
474
475 typedef struct mcs51opcodedata
476   {
477     char name[6];
478     char class[3];
479     char pswtype[3];
480     char op1type[3];
481     char op2type[3];
482   }
483 mcs51opcodedata;
484
485 static mcs51opcodedata mcs51opcodeDataTable[] =
486   {
487     {"acall","j", "",   "",   ""},
488     {"ajmp", "j", "",   "",   ""},
489     {"add",  "",  "w",  "rw", "r"},
490     {"addc", "",  "rw", "rw", "r"},
491     {"anl",  "",  "",   "rw", "r"},
492     {"cjne", "j", "w",  "r",  "r"},
493     {"clr",  "",  "",   "w",  ""},
494     {"cpl",  "",  "",   "rw", ""},
495     {"da",   "",  "rw", "rw", ""},
496     {"dec",  "",  "",   "rw", ""},
497     {"div",  "",  "w",  "rw", ""},
498     {"djnz", "j", "",  "rw",  ""},
499     {"inc",  "",  "",   "rw", ""},
500     {"jb",   "j", "",   "r",  ""},
501     {"jbc",  "j", "",  "rw",  ""},
502     {"jc",   "j", "",   "",   ""},
503     {"jmp",  "j", "",  "",    ""},
504     {"jnb",  "j", "",   "r",  ""},
505     {"jnc",  "j", "",   "",   ""},
506     {"jnz",  "j", "",  "",    ""},
507     {"jz",   "j", "",  "",    ""},
508     {"lcall","j", "",   "",   ""},
509     {"ljmp", "j", "",   "",   ""},
510     {"mov",  "",  "",   "w",  "r"},
511     {"movc", "",  "",   "w",  "r"},
512     {"movx", "",  "",   "w",  "r"},
513     {"mul",  "",  "w",  "rw", ""},
514     {"nop",  "",  "",   "",   ""},
515     {"orl",  "",  "",   "rw", "r"},
516     {"pop",  "",  "",   "w",  ""},
517     {"push", "",  "",   "r",  ""},
518     {"ret",  "j", "",   "",   ""},
519     {"reti", "j", "",   "",   ""},
520     {"rl",   "",  "",   "rw", ""},
521     {"rlc",  "",  "rw", "rw", ""},
522     {"rr",   "",  "",   "rw", ""},
523     {"rrc",  "",  "rw", "rw", ""},
524     {"setb", "",  "",   "w",  ""},
525     {"sjmp", "j", "",   "",   ""},
526     {"subb", "",  "rw", "rw", "r"},
527     {"swap", "",  "",   "rw", ""},
528     {"xch",  "",  "",   "rw", "rw"},
529     {"xchd", "",  "",   "rw", "rw"},
530     {"xrl",  "",  "",   "rw", "r"},
531   };
532   
533 static int
534 mcs51opcodeCompare (const void *key, const void *member)
535 {
536   return strcmp((const char *)key, ((mcs51opcodedata *)member)->name);
537 }
538
539 static asmLineNode *
540 asmLineNodeFromLineNode (lineNode *ln)
541 {
542   asmLineNode *aln = newAsmLineNode();
543   char *op, op1[256], op2[256];
544   int opsize;
545   const char *p;
546   char inst[8];
547   mcs51opcodedata *opdat;
548
549   p = ln->line;
550   
551   while (*p && isspace(*p)) p++;
552   for (op = inst, opsize=1; *p; p++)
553     {
554       if (isspace(*p) || *p == ';' || *p == ':' || *p == '=')
555         break;
556       else
557         if (opsize < sizeof(inst))
558           *op++ = tolower(*p), opsize++;
559     }
560   *op = '\0';
561
562   if (*p == ';' || *p == ':' || *p == '=')
563     return aln;
564     
565   while (*p && isspace(*p)) p++;
566   if (*p == '=')
567     return aln;
568
569   for (op = op1, opsize=1; *p && *p != ','; p++)
570     {
571       if (!isspace(*p) && opsize < sizeof(op1))
572         *op++ = tolower(*p), opsize++;
573     }
574   *op = '\0';
575   
576   if (*p == ',') p++;
577   for (op = op2, opsize=1; *p && *p != ','; p++)
578     {
579       if (!isspace(*p) && opsize < sizeof(op2))
580         *op++ = tolower(*p), opsize++;
581     }
582   *op = '\0';
583
584   aln->size = instructionSize(inst, op1, op2);
585
586   aln->regsRead = newBitVect (END_IDX);
587   aln->regsWritten = newBitVect (END_IDX);
588
589   opdat = bsearch (inst, mcs51opcodeDataTable,
590                    sizeof(mcs51opcodeDataTable)/sizeof(mcs51opcodedata),
591                    sizeof(mcs51opcodedata), mcs51opcodeCompare);
592
593   if (opdat)
594     {
595       updateOpRW (aln, op1, opdat->op1type);
596       updateOpRW (aln, op2, opdat->op2type);
597       if (strchr(opdat->pswtype,'r'))
598         aln->regsRead = bitVectSetBit (aln->regsRead, CND_IDX);
599       if (strchr(opdat->pswtype,'w'))
600         aln->regsWritten = bitVectSetBit (aln->regsWritten, CND_IDX);
601     }
602
603   return aln;
604 }
605
606 static int
607 getInstructionSize (lineNode *line)
608 {
609   if (!line->aln)
610     line->aln = asmLineNodeFromLineNode (line);
611   
612   return line->aln->size;
613 }
614
615 static bitVect *
616 getRegsRead (lineNode *line)
617 {
618   if (!line->aln)
619     line->aln = asmLineNodeFromLineNode (line);
620   
621   return line->aln->regsRead;
622 }
623
624 static bitVect *
625 getRegsWritten (lineNode *line)
626 {
627   if (!line->aln)
628     line->aln = asmLineNodeFromLineNode (line);
629   
630   return line->aln->regsWritten;
631 }
632
633
634 /** $1 is always the basename.
635     $2 is always the output file.
636     $3 varies
637     $l is the list of extra options that should be there somewhere...
638     MUST be terminated with a NULL.
639 */
640 static const char *_linkCmd[] =
641 {
642   "aslink", "-nf", "\"$1\"", NULL
643 };
644
645 /* $3 is replaced by assembler.debug_opts resp. port->assembler.plain_opts */
646 static const char *_asmCmd[] =
647 {
648   "asx8051", "$l", "$3", "\"$1.asm\"", NULL
649 };
650
651 /* Globals */
652 PORT mcs51_port =
653 {
654   TARGET_ID_MCS51,
655   "mcs51",
656   "MCU 8051",                   /* Target name */
657   NULL,                         /* Processor name */
658   {
659     glue,
660     TRUE,                       /* Emit glue around main */
661     MODEL_SMALL | MODEL_LARGE,
662     MODEL_SMALL
663   },
664   {
665     _asmCmd,
666     NULL,
667     "-plosgffc",                /* Options with debug */
668     "-plosgff",                 /* Options without debug */
669     0,
670     ".asm",
671     NULL                        /* no do_assemble function */
672   },
673   {
674     _linkCmd,
675     NULL,
676     NULL,
677     ".rel",
678     1
679   },
680   {
681     _defaultRules,
682     getInstructionSize,
683     getRegsRead,
684     getRegsWritten
685   },
686   {
687         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
688     1, 2, 2, 4, 1, 2, 3, 1, 4, 4
689   },
690   {
691     "XSEG    (XDATA)",
692     "STACK   (DATA)",
693     "CSEG    (CODE)",
694     "DSEG    (DATA)",
695     "ISEG    (DATA)",
696     "XSEG    (XDATA)",
697     "BSEG    (BIT)",
698     "RSEG    (DATA)",
699     "GSINIT  (CODE)",
700     "OSEG    (OVR,DATA)",
701     "GSFINAL (CODE)",
702     "HOME    (CODE)",
703     "XISEG   (XDATA)", // initialized xdata
704     "XINIT   (CODE)", // a code copy of xiseg
705     NULL,
706     NULL,
707     1
708   },
709   { NULL, NULL },
710   {
711     +1, 0, 4, 1, 1, 0
712   },
713     /* mcs51 has an 8 bit mul */
714   {
715     1, -1
716   },
717   "_",
718   _mcs51_init,
719   _mcs51_parseOptions,
720   NULL,
721   _mcs51_finaliseOptions,
722   _mcs51_setDefaultOptions,
723   mcs51_assignRegisters,
724   _mcs51_getRegName,
725   _mcs51_keywords,
726   _mcs51_genAssemblerPreamble,
727   NULL,                         /* no genAssemblerEnd */
728   _mcs51_genIVT,
729   _mcs51_genXINIT,
730   _mcs51_reset_regparm,
731   _mcs51_regparm,
732   NULL,
733   NULL,
734   NULL,
735   hasExtBitOp,                  /* hasExtBitOp */
736   oclsExpense,                  /* oclsExpense */
737   FALSE,
738   TRUE,                         /* little endian */
739   0,                            /* leave lt */
740   0,                            /* leave gt */
741   1,                            /* transform <= to ! > */
742   1,                            /* transform >= to ! < */
743   1,                            /* transform != to !(a == b) */
744   0,                            /* leave == */
745   FALSE,                        /* No array initializer support. */
746   cseCostEstimation,
747   NULL,                         /* no builtin functions */
748   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
749   1,                            /* reset labelKey to 1 */
750   1,                            /* globals & local static allowed */
751   PORT_MAGIC
752 };