_mcs51_genXINIT: xdata initialization is 13 bytes shorter now
[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 void mcs51_assignRegisters (eBBlock ** ebbs, int count);
50
51 static int regParmFlg = 0;      /* determine if we can register a parameter */
52
53 static void
54 _mcs51_init (void)
55 {
56   asm_addTree (&asm_asxxxx_mapping);
57 }
58
59 static void
60 _mcs51_reset_regparm ()
61 {
62   regParmFlg = 0;
63 }
64
65 static int
66 _mcs51_regparm (sym_link * l)
67 {
68     if (options.parms_in_bank1 == 0) {
69         /* simple can pass only the first parameter in a register */
70         if (regParmFlg)
71             return 0;
72
73         regParmFlg = 1;
74         return 1;
75     } else {
76         int size = getSize(l);
77         int remain ;
78
79         /* first one goes the usual way to DPTR */
80         if (regParmFlg == 0) {
81             regParmFlg += 4 ;
82             return 1;
83         }
84         /* second one onwards goes to RB1_0 thru RB1_7 */
85         remain = regParmFlg - 4;
86         if (size > (8 - remain)) {
87             regParmFlg = 12 ;
88             return 0;
89         }
90         regParmFlg += size ;
91         return regParmFlg - size + 1;   
92     }
93 }
94
95 static bool
96 _mcs51_parseOptions (int *pargc, char **argv, int *i)
97 {
98   /* TODO: allow port-specific command line options to specify
99    * segment names here.
100    */
101   return FALSE;
102 }
103
104 static void
105 _mcs51_finaliseOptions (void)
106 {
107   if (options.noXinitOpt) {
108     port->genXINIT=0;
109   }
110
111   if (options.model == MODEL_LARGE) {
112       port->mem.default_local_map = xdata;
113       port->mem.default_globl_map = xdata;
114     }
115   else
116     {
117       port->mem.default_local_map = data;
118       port->mem.default_globl_map = data;
119     }
120
121   if (options.parms_in_bank1) {
122       addSet(&preArgvSet, Safe_strdup("-DSDCC_PARMS_IN_BANK1"));
123   }
124 }
125
126 static void
127 _mcs51_setDefaultOptions (void)
128 {
129 }
130
131 static const char *
132 _mcs51_getRegName (struct regs *reg)
133 {
134   if (reg)
135     return reg->name;
136   return "err";
137 }
138
139 static void
140 _mcs51_genAssemblerPreamble (FILE * of)
141 {
142     if (options.parms_in_bank1) {
143         int i ;
144         for (i=0; i < 8 ; i++ )
145             fprintf (of,"b1_%d = 0x%x \n",i,8+i);
146     }
147 }
148
149 /* Generate interrupt vector table. */
150 static int
151 _mcs51_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts)
152 {
153   return FALSE;
154 }
155
156 /* Generate code to copy XINIT to XISEG */
157 static void _mcs51_genXINIT (FILE * of) {
158   fprintf (of, ";       _mcs51_genXINIT() start\n");
159   fprintf (of, "        mov     a,#l_XINIT\n");
160   fprintf (of, "        mov     r1,a\n");
161   fprintf (of, "        mov     r2,#(l_XINIT >> 8)\n");
162   fprintf (of, "        orl     a,r2\n");
163   fprintf (of, "        jz      00003$\n");
164   fprintf (of, "        inc     r2\n");  
165   fprintf (of, "        mov     dptr,#s_XINIT\n");
166   fprintf (of, "        mov     r0,#s_XISEG\n");
167   fprintf (of, "        mov     p2,#(s_XISEG >> 8)\n");
168   fprintf (of, "00001$: clr     a\n");
169   fprintf (of, "        movc    a,@a+dptr\n");
170   fprintf (of, "        movx    @r0,a\n");
171   fprintf (of, "        inc     dptr\n");
172   fprintf (of, "        inc     r0\n");
173   fprintf (of, "        cjne    r0,#0,00002$\n");
174   fprintf (of, "        inc     p2\n");
175   fprintf (of, "00002$: djnz    r1,00001$\n");
176   fprintf (of, "        djnz    r2,00001$\n");
177   fprintf (of, "        mov     p2,#0xFF\n");
178   fprintf (of, "00003$:\n");
179   fprintf (of, ";       _mcs51_genXINIT() end\n");
180 }
181
182
183 /* Do CSE estimation */
184 static bool cseCostEstimation (iCode *ic, iCode *pdic)
185 {
186     operand *result = IC_RESULT(ic);
187     sym_link *result_type = operandType(result);
188
189     /* if it is a pointer then return ok for now */
190     if (IC_RESULT(ic) && IS_PTR(result_type)) return 1;
191     
192     /* if bitwise | add & subtract then no since mcs51 is pretty good at it 
193        so we will cse only if they are local (i.e. both ic & pdic belong to
194        the same basic block */
195     if (IS_BITWISE_OP(ic) || ic->op == '+' || ic->op == '-') {
196         /* then if they are the same Basic block then ok */
197         if (ic->eBBlockNum == pdic->eBBlockNum) return 1;
198         else return 0;
199     }
200         
201     /* for others it is cheaper to do the cse */
202     return 1;
203 }
204
205 /** $1 is always the basename.
206     $2 is always the output file.
207     $3 varies
208     $l is the list of extra options that should be there somewhere...
209     MUST be terminated with a NULL.
210 */
211 static const char *_linkCmd[] =
212 {
213   "aslink", "-nf", "\"$1\"", NULL
214 };
215
216 /* $3 is replaced by assembler.debug_opts resp. port->assembler.plain_opts */
217 static const char *_asmCmd[] =
218 {
219   "asx8051", "$l", "$3", "\"$1.asm\"", NULL
220 };
221
222 /* Globals */
223 PORT mcs51_port =
224 {
225   TARGET_ID_MCS51,
226   "mcs51",
227   "MCU 8051",                   /* Target name */
228   NULL,                         /* Processor name */
229   {
230     glue,
231     TRUE,                       /* Emit glue around main */
232     MODEL_SMALL | MODEL_LARGE,
233     MODEL_SMALL
234   },
235   {
236     _asmCmd,
237     NULL,
238     "-plosgffc",                /* Options with debug */
239     "-plosgff",                 /* Options without debug */
240     0,
241     ".asm",
242     NULL                        /* no do_assemble function */
243   },
244   {
245     _linkCmd,
246     NULL,
247     NULL,
248     ".rel"
249   },
250   {
251     _defaultRules
252   },
253   {
254         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
255     1, 2, 2, 4, 1, 2, 3, 1, 4, 4
256   },
257   {
258     "XSEG    (XDATA)",
259     "STACK   (DATA)",
260     "CSEG    (CODE)",
261     "DSEG    (DATA)",
262     "ISEG    (DATA)",
263     "XSEG    (XDATA)",
264     "BSEG    (BIT)",
265     "RSEG    (DATA)",
266     "GSINIT  (CODE)",
267     "OSEG    (OVR,DATA)",
268     "GSFINAL (CODE)",
269     "HOME    (CODE)",
270     "XISEG   (XDATA)", // initialized xdata
271     "XINIT   (CODE)", // a code copy of xiseg
272     NULL,
273     NULL,
274     1
275   },
276   { NULL, NULL },
277   {
278     +1, 0, 4, 1, 1, 0
279   },
280     /* mcs51 has an 8 bit mul */
281   {
282     1, -1
283   },
284   "_",
285   _mcs51_init,
286   _mcs51_parseOptions,
287   NULL,
288   _mcs51_finaliseOptions,
289   _mcs51_setDefaultOptions,
290   mcs51_assignRegisters,
291   _mcs51_getRegName,
292   _mcs51_keywords,
293   _mcs51_genAssemblerPreamble,
294   NULL,                         /* no genAssemblerEnd */
295   _mcs51_genIVT,
296   _mcs51_genXINIT,
297   _mcs51_reset_regparm,
298   _mcs51_regparm,
299   NULL,
300   NULL,
301   NULL,
302   FALSE,
303   TRUE,                         /* little endian */
304   0,                            /* leave lt */
305   0,                            /* leave gt */
306   1,                            /* transform <= to ! > */
307   1,                            /* transform >= to ! < */
308   1,                            /* transform != to !(a == b) */
309   0,                            /* leave == */
310   FALSE,                        /* No array initializer support. */
311   cseCostEstimation,
312   NULL,                         /* no builtin functions */
313   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
314   1,                            /* reset labelKey to 1 */
315   1,                            /* globals & local static allowed */
316   PORT_MAGIC
317 };