made clearing of memory the default. There is an environment variable SDCC_NOGENRAMCL...
[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 clear XSEG and idata memory. 
157    This clears XSEG, DSEG, BSEG, OSEG, SSEG */
158 static void _mcs51_genRAMCLEAR (FILE * of) {
159   fprintf (of, ";       _mcs51_genRAMCLEAR() start\n");
160   fprintf (of, "        mov     r1,#l_XSEG\n");
161   fprintf (of, "        mov     a,r1\n");
162   fprintf (of, "        orl     a,#(l_XSEG >> 8)\n");
163   fprintf (of, "        jz      00005$\n");
164   fprintf (of, "        mov     r0,#((l_XSEG + 255) >> 8)\n");
165   fprintf (of, "        mov     dptr,#s_XSEG\n");
166   fprintf (of, "        clr     a\n");
167   fprintf (of, "00004$: movx    @dptr,a\n");
168   fprintf (of, "        inc     dptr\n");
169   fprintf (of, "        djnz    r1,00004$\n");
170   fprintf (of, "        djnz    r0,00004$\n");
171   /* r0 is zero now. Clearing 256 byte assuming 128 byte devices don't mind */
172   fprintf (of, "00005$: mov     @r0,a\n");   
173   fprintf (of, "        djnz    r0,00005$\n");
174   fprintf (of, ";       _mcs51_genRAMCLEAR() end\n");
175 }
176
177 /* Generate code to copy XINIT to XISEG */
178 static void _mcs51_genXINIT (FILE * of) {
179   fprintf (of, ";       _mcs51_genXINIT() start\n");
180   fprintf (of, "        mov     r1,#l_XINIT\n");
181   fprintf (of, "        mov     a,r1\n");
182   fprintf (of, "        orl     a,#(l_XINIT >> 8)\n");
183   fprintf (of, "        jz      00003$\n");
184   fprintf (of, "        mov     r2,#((l_XINIT+255) >> 8)\n");
185   fprintf (of, "        mov     dptr,#s_XINIT\n");
186   fprintf (of, "        mov     r0,#s_XISEG\n");
187   fprintf (of, "        mov     p2,#(s_XISEG >> 8)\n");
188   fprintf (of, "00001$: clr     a\n");
189   fprintf (of, "        movc    a,@a+dptr\n");
190   fprintf (of, "        movx    @r0,a\n");
191   fprintf (of, "        inc     dptr\n");
192   fprintf (of, "        inc     r0\n");
193   fprintf (of, "        cjne    r0,#0,00002$\n");
194   fprintf (of, "        inc     p2\n");
195   fprintf (of, "00002$: djnz    r1,00001$\n");
196   fprintf (of, "        djnz    r2,00001$\n");
197   fprintf (of, "        mov     p2,#0xFF\n");
198   fprintf (of, "00003$:\n");
199   fprintf (of, ";       _mcs51_genXINIT() end\n");
200   
201   if (!getenv("SDCC_NOGENRAMCLEAR")) _mcs51_genRAMCLEAR (of);
202 }
203
204
205 /* Do CSE estimation */
206 static bool cseCostEstimation (iCode *ic, iCode *pdic)
207 {
208     operand *result = IC_RESULT(ic);
209     sym_link *result_type = operandType(result);
210
211     /* if it is a pointer then return ok for now */
212     if (IC_RESULT(ic) && IS_PTR(result_type)) return 1;
213     
214     /* if bitwise | add & subtract then no since mcs51 is pretty good at it 
215        so we will cse only if they are local (i.e. both ic & pdic belong to
216        the same basic block */
217     if (IS_BITWISE_OP(ic) || ic->op == '+' || ic->op == '-') {
218         /* then if they are the same Basic block then ok */
219         if (ic->eBBlockNum == pdic->eBBlockNum) return 1;
220         else return 0;
221     }
222         
223     /* for others it is cheaper to do the cse */
224     return 1;
225 }
226
227 /* Indicate which extended bit operations this port supports */
228 static bool
229 hasExtBitOp (int op, int size)
230 {
231   if (op == RRC
232       || op == RLC
233       || op == GETHBIT
234       || (op == SWAP && size <= 2)
235      )
236     return TRUE;
237   else
238     return FALSE;
239 }
240
241 /* Indicate the expense of an access to an output storage class */
242 static int
243 oclsExpense (struct memmap *oclass)
244 {
245   if (IN_FARSPACE(oclass))
246     return 1;
247     
248   return 0;
249 }
250
251 /** $1 is always the basename.
252     $2 is always the output file.
253     $3 varies
254     $l is the list of extra options that should be there somewhere...
255     MUST be terminated with a NULL.
256 */
257 static const char *_linkCmd[] =
258 {
259   "aslink", "-nf", "\"$1\"", NULL
260 };
261
262 /* $3 is replaced by assembler.debug_opts resp. port->assembler.plain_opts */
263 static const char *_asmCmd[] =
264 {
265   "asx8051", "$l", "$3", "\"$1.asm\"", NULL
266 };
267
268 /* Globals */
269 PORT mcs51_port =
270 {
271   TARGET_ID_MCS51,
272   "mcs51",
273   "MCU 8051",                   /* Target name */
274   NULL,                         /* Processor name */
275   {
276     glue,
277     TRUE,                       /* Emit glue around main */
278     MODEL_SMALL | MODEL_LARGE,
279     MODEL_SMALL
280   },
281   {
282     _asmCmd,
283     NULL,
284     "-plosgffc",                /* Options with debug */
285     "-plosgff",                 /* Options without debug */
286     0,
287     ".asm",
288     NULL                        /* no do_assemble function */
289   },
290   {
291     _linkCmd,
292     NULL,
293     NULL,
294     ".rel"
295   },
296   {
297     _defaultRules
298   },
299   {
300         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
301     1, 2, 2, 4, 1, 2, 3, 1, 4, 4
302   },
303   {
304     "XSEG    (XDATA)",
305     "STACK   (DATA)",
306     "CSEG    (CODE)",
307     "DSEG    (DATA)",
308     "ISEG    (DATA)",
309     "XSEG    (XDATA)",
310     "BSEG    (BIT)",
311     "RSEG    (DATA)",
312     "GSINIT  (CODE)",
313     "OSEG    (OVR,DATA)",
314     "GSFINAL (CODE)",
315     "HOME    (CODE)",
316     "XISEG   (XDATA)", // initialized xdata
317     "XINIT   (CODE)", // a code copy of xiseg
318     NULL,
319     NULL,
320     1
321   },
322   { NULL, NULL },
323   {
324     +1, 0, 4, 1, 1, 0
325   },
326     /* mcs51 has an 8 bit mul */
327   {
328     1, -1
329   },
330   "_",
331   _mcs51_init,
332   _mcs51_parseOptions,
333   NULL,
334   _mcs51_finaliseOptions,
335   _mcs51_setDefaultOptions,
336   mcs51_assignRegisters,
337   _mcs51_getRegName,
338   _mcs51_keywords,
339   _mcs51_genAssemblerPreamble,
340   NULL,                         /* no genAssemblerEnd */
341   _mcs51_genIVT,
342   _mcs51_genXINIT,
343   _mcs51_reset_regparm,
344   _mcs51_regparm,
345   NULL,
346   NULL,
347   NULL,
348   hasExtBitOp,                  /* hasExtBitOp */
349   oclsExpense,                  /* oclsExpense */
350   FALSE,
351   TRUE,                         /* little endian */
352   0,                            /* leave lt */
353   0,                            /* leave gt */
354   1,                            /* transform <= to ! > */
355   1,                            /* transform >= to ! < */
356   1,                            /* transform != to !(a == b) */
357   0,                            /* leave == */
358   FALSE,                        /* No array initializer support. */
359   cseCostEstimation,
360   NULL,                         /* no builtin functions */
361   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
362   1,                            /* reset labelKey to 1 */
363   1,                            /* globals & local static allowed */
364   PORT_MAGIC
365 };