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