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