* as/mcs51/lkarea.c: removed old K&R style,
[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 (void)
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
151 /* Generate interrupt vector table. */
152 static int
153 _mcs51_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts)
154 {
155   int i;
156
157   fprintf (of, "\tljmp\t__sdcc_gsinit_startup\n");
158
159   /* now for the other interrupts */
160   for (i = 0; i < maxInterrupts; i++)
161     {
162       if (interrupts[i])
163         {
164           fprintf (of, "\tljmp\t%s\n", interrupts[i]->rname);
165           if ( i != maxInterrupts - 1 )
166             fprintf (of, "\t.ds\t5\n");
167         }
168       else
169         {
170           fprintf (of, "\treti\n");
171           if ( i != maxInterrupts - 1 )
172             fprintf (of, "\t.ds\t7\n");
173         }
174     }
175   return TRUE;
176 }
177
178 static void       
179 _mcs51_genExtraAreas(FILE *of, bool hasMain)
180 {
181   tfprintf (of, "\t!area\n", port->mem.code_name);
182   tfprintf (of, "\t!area\n", "GSINIT0 (CODE)");
183   tfprintf (of, "\t!area\n", "GSINIT1 (CODE)");
184   tfprintf (of, "\t!area\n", "GSINIT2 (CODE)");
185   tfprintf (of, "\t!area\n", "GSINIT3 (CODE)");
186   tfprintf (of, "\t!area\n", "GSINIT4 (CODE)");
187   tfprintf (of, "\t!area\n", "GSINIT5 (CODE)");
188 }
189
190 static void
191 _mcs51_genInitStartup (FILE *of)
192 {
193   tfprintf (of, "\t!global\n", "__sdcc_gsinit_startup");
194   tfprintf (of, "\t!global\n", "__sdcc_program_startup");
195   tfprintf (of, "\t!global\n", "__start__stack");
196   
197   if (options.useXstack)
198     {
199       tfprintf (of, "\t!global\n", "__sdcc_init_xstack");
200       tfprintf (of, "\t!global\n", "__start__xstack");
201     }
202
203   // if the port can copy the XINIT segment to XISEG
204   if (port->genXINIT)
205     {
206       port->genXINIT(of);
207     }
208   
209   if (!getenv("SDCC_NOGENRAMCLEAR"))
210     tfprintf (of, "\t!global\n", "__mcs51_genRAMCLEAR");
211 }
212
213
214 /* Generate code to copy XINIT to XISEG */
215 static void _mcs51_genXINIT (FILE * of) {
216   tfprintf (of, "\t!global\n", "__mcs51_genXINIT");
217   
218   if (!getenv("SDCC_NOGENRAMCLEAR"))
219     tfprintf (of, "\t!global\n", "__mcs51_genXRAMCLEAR");
220 }
221
222
223 /* Do CSE estimation */
224 static bool cseCostEstimation (iCode *ic, iCode *pdic)
225 {
226     operand *result = IC_RESULT(ic);
227     sym_link *result_type = operandType(result);
228
229     /* if it is a pointer then return ok for now */
230     if (IC_RESULT(ic) && IS_PTR(result_type)) return 1;
231     
232     /* if bitwise | add & subtract then no since mcs51 is pretty good at it 
233        so we will cse only if they are local (i.e. both ic & pdic belong to
234        the same basic block */
235     if (IS_BITWISE_OP(ic) || ic->op == '+' || ic->op == '-') {
236         /* then if they are the same Basic block then ok */
237         if (ic->eBBlockNum == pdic->eBBlockNum) return 1;
238         else return 0;
239     }
240         
241     /* for others it is cheaper to do the cse */
242     return 1;
243 }
244
245 /* Indicate which extended bit operations this port supports */
246 static bool
247 hasExtBitOp (int op, int size)
248 {
249   if (op == RRC
250       || op == RLC
251       || op == GETHBIT
252       || (op == SWAP && size <= 2)
253      )
254     return TRUE;
255   else
256     return FALSE;
257 }
258
259 /* Indicate the expense of an access to an output storage class */
260 static int
261 oclsExpense (struct memmap *oclass)
262 {
263   if (IN_FARSPACE(oclass))
264     return 1;
265     
266   return 0;
267 }
268
269
270
271 static int
272 instructionSize(char *inst, char *op1, char *op2)
273 {
274   #define ISINST(s) (strncmp(inst, (s), sizeof(s)-1) == 0)
275   #define IS_A(s) (*(s) == 'a' && *(s+1) == '\0')
276   #define IS_C(s) (*(s) == 'c' && *(s+1) == '\0')
277   #define IS_Rn(s) (*(s) == 'r' && *(s+1) >= '0' && *(s+1) <= '7')
278   #define IS_atRi(s) (*(s) == '@' && *(s+1) == 'r')
279
280   /* Based on the current (2003-08-22) code generation for the
281      small library, the top instruction probability is:
282    
283        57% mov/movx/movc
284         6% push
285         6% pop
286         4% inc
287         4% lcall
288         4% add
289         3% clr
290         2% subb
291   */
292   /* mov, push, & pop are the 69% of the cases. Check them first! */
293   if (ISINST ("mov"))
294     {
295       if (*(inst+3)=='x') return 1; /* movx */
296       if (*(inst+3)=='c') return 1; /* movc */
297       if (IS_C (op1) || IS_C (op2)) return 2;
298       if (IS_A (op1))
299         {
300           if (IS_Rn (op2) || IS_atRi (op2)) return 1;
301           return 2;
302         }
303       if (IS_Rn(op1) || IS_atRi(op1))
304         {
305           if (IS_A(op2)) return 1;
306           return 2;
307         }
308       if (strcmp (op1, "dptr") == 0) return 3;
309       if (IS_A (op2) || IS_Rn (op2) || IS_atRi (op2)) return 2;
310       return 3;
311     }
312   
313   if (ISINST ("push")) return 2;
314   if (ISINST ("pop")) return 2;
315
316   if (ISINST ("lcall")) return 3;
317   if (ISINST ("ret")) return 1;
318   if (ISINST ("ljmp")) return 3;
319   if (ISINST ("sjmp")) return 2;
320   if (ISINST ("rlc")) return 1;
321   if (ISINST ("rrc")) return 1;
322   if (ISINST ("rl")) return 1;
323   if (ISINST ("rr")) return 1;
324   if (ISINST ("swap")) return 1;
325   if (ISINST ("jc")) return 2;
326   if (ISINST ("jnc")) return 2;
327   if (ISINST ("jb")) return 3;
328   if (ISINST ("jnb")) return 3;
329   if (ISINST ("jbc")) return 3;
330   if (ISINST ("jmp")) return 1; // always jmp @a+dptr
331   if (ISINST ("jz")) return 2;
332   if (ISINST ("jnz")) return 2;
333   if (ISINST ("cjne")) return 3;
334   if (ISINST ("mul")) return 1;
335   if (ISINST ("div")) return 1;
336   if (ISINST ("da")) return 1;
337   if (ISINST ("xchd")) return 1;
338   if (ISINST ("reti")) return 1;
339   if (ISINST ("nop")) return 1;
340   if (ISINST ("acall")) return 2;
341   if (ISINST ("ajmp")) return 2;
342
343     
344   if (ISINST ("add") || ISINST ("addc") || ISINST ("subb") || ISINST ("xch"))
345     {
346       if (IS_Rn(op2) || IS_atRi(op2)) return 1;
347       return 2;
348     }
349   if (ISINST ("inc") || ISINST ("dec"))
350     {
351       if (IS_A(op1) || IS_Rn(op1) || IS_atRi(op1)) return 1;
352       if (strcmp(op1, "dptr") == 0) return 1;
353       return 2;
354     }
355   if (ISINST ("anl") || ISINST ("orl") || ISINST ("xrl"))
356     {
357       if (IS_C(op1)) return 2;
358       if (IS_A(op1))
359         {
360           if (IS_Rn(op2) || IS_atRi(op2)) return 1;
361           return 2;
362         }
363       else
364         {
365           if (IS_A(op2)) return 2;
366           return 3;
367         }
368     }
369   if (ISINST ("clr") || ISINST ("setb") || ISINST ("cpl"))
370     {
371       if (IS_A(op1) || IS_C(op1)) return 1;
372       return 2;
373     }
374   if (ISINST ("djnz"))
375     {
376       if (IS_Rn(op1)) return 2;
377       return 3;
378     }
379
380   /* If the instruction is unrecognized, we shouldn't try to optimize. */
381   /* Return a large value to discourage optimization.                  */
382   return 999;
383 }
384
385 static asmLineNode *
386 newAsmLineNode (void)
387 {
388   asmLineNode *aln;
389
390   aln = Safe_alloc ( sizeof (asmLineNode));
391   aln->size = 0;
392   aln->regsRead = NULL;
393   aln->regsWritten = NULL;
394   
395   return aln;
396 }
397
398
399 typedef struct mcs51operanddata
400   {
401     char name[6];
402     int regIdx1;
403     int regIdx2;
404   }
405 mcs51operanddata;
406
407 static mcs51operanddata mcs51operandDataTable[] =
408   {
409     {"a", A_IDX, -1},
410     {"ab", A_IDX, B_IDX},
411     {"ac", CND_IDX, -1},
412     {"acc", A_IDX, -1},
413     {"ar0", R0_IDX, -1},
414     {"ar1", R1_IDX, -1},
415     {"ar2", R2_IDX, -1},
416     {"ar3", R3_IDX, -1},
417     {"ar4", R4_IDX, -1},
418     {"ar5", R5_IDX, -1},
419     {"ar6", R6_IDX, -1},
420     {"ar7", R7_IDX, -1},
421     {"b", B_IDX, -1},
422     {"c", CND_IDX, -1},
423     {"cy", CND_IDX, -1},
424     {"dph", DPH_IDX, -1},
425     {"dpl", DPL_IDX, -1},
426     {"dptr", DPL_IDX, DPH_IDX},
427     {"f0", CND_IDX, -1},
428     {"f1", CND_IDX, -1},
429     {"ov", CND_IDX, -1},
430     {"p", CND_IDX, -1},
431     {"psw", CND_IDX, -1},
432     {"r0", R0_IDX, -1},
433     {"r1", R1_IDX, -1},
434     {"r2", R2_IDX, -1},
435     {"r3", R3_IDX, -1},
436     {"r4", R4_IDX, -1},
437     {"r5", R5_IDX, -1},
438     {"r6", R6_IDX, -1},
439     {"r7", R7_IDX, -1},
440   };
441
442 static int
443 mcs51operandCompare (const void *key, const void *member)
444 {
445   return strcmp((const char *)key, ((mcs51operanddata *)member)->name);
446 }
447
448 static void      
449 updateOpRW (asmLineNode *aln, char *op, char *optype)
450 {
451   mcs51operanddata *opdat;
452   char *dot;
453   
454   dot = strchr(op, '.');
455   if (dot)
456     *dot = '\0';
457
458   opdat = bsearch (op, mcs51operandDataTable,
459                    sizeof(mcs51operandDataTable)/sizeof(mcs51operanddata),
460                    sizeof(mcs51operanddata), mcs51operandCompare);
461   
462   if (opdat && strchr(optype,'r'))
463     {
464       if (opdat->regIdx1 >= 0)
465         aln->regsRead = bitVectSetBit (aln->regsRead, opdat->regIdx1);
466       if (opdat->regIdx2 >= 0)
467         aln->regsRead = bitVectSetBit (aln->regsRead, opdat->regIdx2);
468     }
469   if (opdat && strchr(optype,'w'))
470     {
471       if (opdat->regIdx1 >= 0)
472         aln->regsWritten = bitVectSetBit (aln->regsWritten, opdat->regIdx1);
473       if (opdat->regIdx2 >= 0)
474         aln->regsWritten = bitVectSetBit (aln->regsWritten, opdat->regIdx2);
475     }
476   if (op[0] == '@')
477     {
478       if (!strcmp(op, "@r0"))
479         aln->regsRead = bitVectSetBit (aln->regsRead, R0_IDX);
480       if (!strcmp(op, "@r1"))
481         aln->regsRead = bitVectSetBit (aln->regsRead, R1_IDX);
482       if (strstr(op, "dptr"))
483         {
484           aln->regsRead = bitVectSetBit (aln->regsRead, DPL_IDX);
485           aln->regsRead = bitVectSetBit (aln->regsRead, DPH_IDX);
486         }
487       if (strstr(op, "a+"))
488         aln->regsRead = bitVectSetBit (aln->regsRead, A_IDX);
489     }
490 }
491
492 typedef struct mcs51opcodedata
493   {
494     char name[6];
495     char class[3];
496     char pswtype[3];
497     char op1type[3];
498     char op2type[3];
499   }
500 mcs51opcodedata;
501
502 static mcs51opcodedata mcs51opcodeDataTable[] =
503   {
504     {"acall","j", "",   "",   ""},
505     {"add",  "",  "w",  "rw", "r"},
506     {"addc", "",  "rw", "rw", "r"},
507     {"ajmp", "j", "",   "",   ""},
508     {"anl",  "",  "",   "rw", "r"},
509     {"cjne", "j", "w",  "r",  "r"},
510     {"clr",  "",  "",   "w",  ""},
511     {"cpl",  "",  "",   "rw", ""},
512     {"da",   "",  "rw", "rw", ""},
513     {"dec",  "",  "",   "rw", ""},
514     {"div",  "",  "w",  "rw", ""},
515     {"djnz", "j", "",  "rw",  ""},
516     {"inc",  "",  "",   "rw", ""},
517     {"jb",   "j", "",   "r",  ""},
518     {"jbc",  "j", "",  "rw",  ""},
519     {"jc",   "j", "",   "",   ""},
520     {"jmp",  "j", "",  "",    ""},
521     {"jnb",  "j", "",   "r",  ""},
522     {"jnc",  "j", "",   "",   ""},
523     {"jnz",  "j", "",  "",    ""},
524     {"jz",   "j", "",  "",    ""},
525     {"lcall","j", "",   "",   ""},
526     {"ljmp", "j", "",   "",   ""},
527     {"mov",  "",  "",   "w",  "r"},
528     {"movc", "",  "",   "w",  "r"},
529     {"movx", "",  "",   "w",  "r"},
530     {"mul",  "",  "w",  "rw", ""},
531     {"nop",  "",  "",   "",   ""},
532     {"orl",  "",  "",   "rw", "r"},
533     {"pop",  "",  "",   "w",  ""},
534     {"push", "",  "",   "r",  ""},
535     {"ret",  "j", "",   "",   ""},
536     {"reti", "j", "",   "",   ""},
537     {"rl",   "",  "",   "rw", ""},
538     {"rlc",  "",  "rw", "rw", ""},
539     {"rr",   "",  "",   "rw", ""},
540     {"rrc",  "",  "rw", "rw", ""},
541     {"setb", "",  "",   "w",  ""},
542     {"sjmp", "j", "",   "",   ""},
543     {"subb", "",  "rw", "rw", "r"},
544     {"swap", "",  "",   "rw", ""},
545     {"xch",  "",  "",   "rw", "rw"},
546     {"xchd", "",  "",   "rw", "rw"},
547     {"xrl",  "",  "",   "rw", "r"},
548   };
549   
550 static int
551 mcs51opcodeCompare (const void *key, const void *member)
552 {
553   return strcmp((const char *)key, ((mcs51opcodedata *)member)->name);
554 }
555
556 static asmLineNode *
557 asmLineNodeFromLineNode (lineNode *ln)
558 {
559   asmLineNode *aln = newAsmLineNode();
560   char *op, op1[256], op2[256];
561   int opsize;
562   const char *p;
563   char inst[8];
564   mcs51opcodedata *opdat;
565
566   p = ln->line;
567   
568   while (*p && isspace(*p)) p++;
569   for (op = inst, opsize=1; *p; p++)
570     {
571       if (isspace(*p) || *p == ';' || *p == ':' || *p == '=')
572         break;
573       else
574         if (opsize < sizeof(inst))
575           *op++ = tolower(*p), opsize++;
576     }
577   *op = '\0';
578
579   if (*p == ';' || *p == ':' || *p == '=')
580     return aln;
581     
582   while (*p && isspace(*p)) p++;
583   if (*p == '=')
584     return aln;
585
586   for (op = op1, opsize=1; *p && *p != ','; p++)
587     {
588       if (!isspace(*p) && opsize < sizeof(op1))
589         *op++ = tolower(*p), opsize++;
590     }
591   *op = '\0';
592   
593   if (*p == ',') p++;
594   for (op = op2, opsize=1; *p && *p != ','; p++)
595     {
596       if (!isspace(*p) && opsize < sizeof(op2))
597         *op++ = tolower(*p), opsize++;
598     }
599   *op = '\0';
600
601   aln->size = instructionSize(inst, op1, op2);
602
603   aln->regsRead = newBitVect (END_IDX);
604   aln->regsWritten = newBitVect (END_IDX);
605
606   opdat = bsearch (inst, mcs51opcodeDataTable,
607                    sizeof(mcs51opcodeDataTable)/sizeof(mcs51opcodedata),
608                    sizeof(mcs51opcodedata), mcs51opcodeCompare);
609
610   if (opdat)
611     {
612       updateOpRW (aln, op1, opdat->op1type);
613       updateOpRW (aln, op2, opdat->op2type);
614       if (strchr(opdat->pswtype,'r'))
615         aln->regsRead = bitVectSetBit (aln->regsRead, CND_IDX);
616       if (strchr(opdat->pswtype,'w'))
617         aln->regsWritten = bitVectSetBit (aln->regsWritten, CND_IDX);
618     }
619
620   return aln;
621 }
622
623 static int
624 getInstructionSize (lineNode *line)
625 {
626   if (!line->aln)
627     line->aln = asmLineNodeFromLineNode (line);
628   
629   return line->aln->size;
630 }
631
632 static bitVect *
633 getRegsRead (lineNode *line)
634 {
635   if (!line->aln)
636     line->aln = asmLineNodeFromLineNode (line);
637   
638   return line->aln->regsRead;
639 }
640
641 static bitVect *
642 getRegsWritten (lineNode *line)
643 {
644   if (!line->aln)
645     line->aln = asmLineNodeFromLineNode (line);
646   
647   return line->aln->regsWritten;
648 }
649
650
651 /** $1 is always the basename.
652     $2 is always the output file.
653     $3 varies
654     $l is the list of extra options that should be there somewhere...
655     MUST be terminated with a NULL.
656 */
657 static const char *_linkCmd[] =
658 {
659   "aslink", "-nf", "\"$1\"", NULL
660 };
661
662 /* $3 is replaced by assembler.debug_opts resp. port->assembler.plain_opts */
663 static const char *_asmCmd[] =
664 {
665   "asx8051", "$l", "$3", "\"$1.asm\"", NULL
666 };
667
668 /* Globals */
669 PORT mcs51_port =
670 {
671   TARGET_ID_MCS51,
672   "mcs51",
673   "MCU 8051",                   /* Target name */
674   NULL,                         /* Processor name */
675   {
676     glue,
677     TRUE,                       /* Emit glue around main */
678     MODEL_SMALL | MODEL_LARGE,
679     MODEL_SMALL
680   },
681   {
682     _asmCmd,
683     NULL,
684     "-plosgffc",                /* Options with debug */
685     "-plosgff",                 /* Options without debug */
686     0,
687     ".asm",
688     NULL                        /* no do_assemble function */
689   },
690   {
691     _linkCmd,
692     NULL,
693     NULL,
694     ".rel",
695     1
696   },
697   {
698     _defaultRules,
699     getInstructionSize,
700     getRegsRead,
701     getRegsWritten
702   },
703   {
704         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
705     1, 2, 2, 4, 1, 2, 3, 1, 4, 4
706   },
707   {
708     "XSTK    (PAG,XDATA)",
709     "STACK   (DATA)",
710     "CSEG    (CODE)",
711     "DSEG    (DATA)",
712     "ISEG    (DATA)",
713     "PSEG    (PAG,XDATA)",
714     "XSEG    (XDATA)",
715     "BSEG    (BIT)",
716     "RSEG    (DATA)",
717     "GSINIT  (CODE)",
718     "OSEG    (OVR,DATA)",
719     "GSFINAL (CODE)",
720     "HOME    (CODE)",
721     "XISEG   (XDATA)", // initialized xdata
722     "XINIT   (CODE)", // a code copy of xiseg
723     NULL,
724     NULL,
725     1
726   },
727   { _mcs51_genExtraAreas, NULL },
728   {
729     +1, 0, 4, 1, 1, 0
730   },
731     /* mcs51 has an 8 bit mul */
732   {
733     1, -1
734   },
735   {
736     mcs51_emitDebuggerSymbol
737   },
738   {
739     255/3,      /* maxCount */
740     3,          /* sizeofElement */
741     {6,9,15},   /* sizeofMatchJump[] */
742     {9,18,36},  /* sizeofRangeCompare[] */
743     4,          /* sizeofSubtract */
744     7,          /* sizeofDispatch */
745   },
746   "_",
747   _mcs51_init,
748   _mcs51_parseOptions,
749   NULL,
750   NULL,
751   _mcs51_finaliseOptions,
752   _mcs51_setDefaultOptions,
753   mcs51_assignRegisters,
754   _mcs51_getRegName,
755   _mcs51_keywords,
756   _mcs51_genAssemblerPreamble,
757   NULL,                         /* no genAssemblerEnd */
758   _mcs51_genIVT,
759   _mcs51_genXINIT,
760   _mcs51_genInitStartup,
761   _mcs51_reset_regparm,
762   _mcs51_regparm,
763   NULL,
764   NULL,
765   NULL,
766   hasExtBitOp,                  /* hasExtBitOp */
767   oclsExpense,                  /* oclsExpense */
768   FALSE,
769   TRUE,                         /* little endian */
770   0,                            /* leave lt */
771   0,                            /* leave gt */
772   1,                            /* transform <= to ! > */
773   1,                            /* transform >= to ! < */
774   1,                            /* transform != to !(a == b) */
775   0,                            /* leave == */
776   FALSE,                        /* No array initializer support. */
777   cseCostEstimation,
778   NULL,                         /* no builtin functions */
779   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
780   1,                            /* reset labelKey to 1 */
781   1,                            /* globals & local static allowed */
782   PORT_MAGIC
783 };