* src/port.h,
[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 /* Indicate which extended bit operations this port supports */
206 static bool
207 hasExtBitOp (int op, int size)
208 {
209   if (op == RRC
210       || op == RLC
211       || op == GETHBIT
212       || (op == SWAP && size <= 2)
213      )
214     return TRUE;
215   else
216     return FALSE;
217 }
218
219 /* Indicate the expense of an access to an output storage class */
220 static int
221 oclsExpense (struct memmap *oclass)
222 {
223   if (IN_FARSPACE(oclass))
224     return 1;
225     
226   return 0;
227 }
228
229 /** $1 is always the basename.
230     $2 is always the output file.
231     $3 varies
232     $l is the list of extra options that should be there somewhere...
233     MUST be terminated with a NULL.
234 */
235 static const char *_linkCmd[] =
236 {
237   "aslink", "-nf", "\"$1\"", NULL
238 };
239
240 /* $3 is replaced by assembler.debug_opts resp. port->assembler.plain_opts */
241 static const char *_asmCmd[] =
242 {
243   "asx8051", "$l", "$3", "\"$1.asm\"", NULL
244 };
245
246 /* Globals */
247 PORT mcs51_port =
248 {
249   TARGET_ID_MCS51,
250   "mcs51",
251   "MCU 8051",                   /* Target name */
252   NULL,                         /* Processor name */
253   {
254     glue,
255     TRUE,                       /* Emit glue around main */
256     MODEL_SMALL | MODEL_LARGE,
257     MODEL_SMALL
258   },
259   {
260     _asmCmd,
261     NULL,
262     "-plosgffc",                /* Options with debug */
263     "-plosgff",                 /* Options without debug */
264     0,
265     ".asm",
266     NULL                        /* no do_assemble function */
267   },
268   {
269     _linkCmd,
270     NULL,
271     NULL,
272     ".rel"
273   },
274   {
275     _defaultRules
276   },
277   {
278         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
279     1, 2, 2, 4, 1, 2, 3, 1, 4, 4
280   },
281   {
282     "XSEG    (XDATA)",
283     "STACK   (DATA)",
284     "CSEG    (CODE)",
285     "DSEG    (DATA)",
286     "ISEG    (DATA)",
287     "XSEG    (XDATA)",
288     "BSEG    (BIT)",
289     "RSEG    (DATA)",
290     "GSINIT  (CODE)",
291     "OSEG    (OVR,DATA)",
292     "GSFINAL (CODE)",
293     "HOME    (CODE)",
294     "XISEG   (XDATA)", // initialized xdata
295     "XINIT   (CODE)", // a code copy of xiseg
296     NULL,
297     NULL,
298     1
299   },
300   { NULL, NULL },
301   {
302     +1, 0, 4, 1, 1, 0
303   },
304     /* mcs51 has an 8 bit mul */
305   {
306     1, -1
307   },
308   "_",
309   _mcs51_init,
310   _mcs51_parseOptions,
311   NULL,
312   _mcs51_finaliseOptions,
313   _mcs51_setDefaultOptions,
314   mcs51_assignRegisters,
315   _mcs51_getRegName,
316   _mcs51_keywords,
317   _mcs51_genAssemblerPreamble,
318   NULL,                         /* no genAssemblerEnd */
319   _mcs51_genIVT,
320   _mcs51_genXINIT,
321   _mcs51_reset_regparm,
322   _mcs51_regparm,
323   NULL,
324   NULL,
325   NULL,
326   hasExtBitOp,                  /* hasExtBitOp */
327   oclsExpense,                  /* oclsExpense */
328   FALSE,
329   TRUE,                         /* little endian */
330   0,                            /* leave lt */
331   0,                            /* leave gt */
332   1,                            /* transform <= to ! > */
333   1,                            /* transform >= to ! < */
334   1,                            /* transform != to !(a == b) */
335   0,                            /* leave == */
336   FALSE,                        /* No array initializer support. */
337   cseCostEstimation,
338   NULL,                         /* no builtin functions */
339   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
340   1,                            /* reset labelKey to 1 */
341   1,                            /* globals & local static allowed */
342   PORT_MAGIC
343 };