* device/lib/z80/printf.c (sprintf): Added.
[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 extern const char *preArgv[128];        /* pre-processor arguments  */
13
14 static char _defaultRules[] =
15 {
16 #include "peeph.rul"
17 };
18
19 /* list of key words used by msc51 */
20 static char *_mcs51_keywords[] =
21 {
22   "at",
23   "bit",
24   "code",
25   "critical",
26   "data",
27   "far",
28   "idata",
29   "interrupt",
30   "near",
31   "pdata",
32   "reentrant",
33   "sfr",
34   "sbit",
35   "using",
36   "xdata",
37   "_data",
38   "_code",
39   "_generic",
40   "_near",
41   "_xdata",
42   "_pdata",
43   "_idata",
44   "_naked",
45   "_overlay",
46   NULL
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 ()
62 {
63   regParmFlg = 0;
64 }
65
66 static int
67 _mcs51_regparm (sym_link * l)
68 {
69     if (options.parms_in_bank1 == 0) {
70         /* simple can pass only the first parameter in a register */
71         if (regParmFlg)
72             return 0;
73
74         regParmFlg = 1;
75         return 1;
76     } else {
77         int size = getSize(l);
78         int remain ;
79
80         /* first one goes the usual way to DPTR */
81         if (regParmFlg == 0) {
82             regParmFlg += 4 ;
83             return 1;
84         }
85         /* second one onwards goes to RB1_0 thru RB1_7 */
86         remain = regParmFlg - 4;
87         if (size > (8 - remain)) {
88             regParmFlg = 12 ;
89             return 0;
90         }
91         regParmFlg += size ;
92         return regParmFlg - size + 1;   
93     }
94 }
95
96 static bool
97 _mcs51_parseOptions (int *pargc, char **argv, int *i)
98 {
99   /* TODO: allow port-specific command line options to specify
100    * segment names here.
101    */
102   return FALSE;
103 }
104
105 static void
106 _mcs51_finaliseOptions (void)
107 {
108   if (options.model == MODEL_LARGE) {
109       port->mem.default_local_map = xdata;
110       port->mem.default_globl_map = xdata;
111     }
112   else
113     {
114       port->mem.default_local_map = data;
115       port->mem.default_globl_map = data;
116     }
117
118   if (options.parms_in_bank1) {
119       addToList (preArgv, "-DSDCC_PARMS_IN_BANK1");
120   }
121 }
122
123 static void
124 _mcs51_setDefaultOptions (void)
125 {
126 }
127
128 static const char *
129 _mcs51_getRegName (struct regs *reg)
130 {
131   if (reg)
132     return reg->name;
133   return "err";
134 }
135
136 static void
137 _mcs51_genAssemblerPreamble (FILE * of)
138 {
139     if (options.parms_in_bank1) {
140         int i ;
141         for (i=0; i < 8 ; i++ )
142             fprintf (of,"b1_%d = 0x%x \n",i,8+i);
143     }
144 }
145
146 /* Generate interrupt vector table. */
147 static int
148 _mcs51_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts)
149 {
150   return FALSE;
151 }
152
153 /* Generate code to copy XINIT to XISEG */
154 static void _mcs51_genXINIT (FILE * of) {
155   fprintf (of, ";       _mcs51_genXINIT() start\n");
156   fprintf (of, "        mov     a,#l_XINIT\n");
157   fprintf (of, "        orl     a,#l_XINIT>>8\n");
158   fprintf (of, "        jz      00003$\n");
159   fprintf (of, "        mov     a,#s_XINIT\n");
160   fprintf (of, "        add     a,#l_XINIT\n");
161   fprintf (of, "        mov     r1,a\n");
162   fprintf (of, "        mov     a,#s_XINIT>>8\n");
163   fprintf (of, "        addc    a,#l_XINIT>>8\n");
164   fprintf (of, "        mov     r2,a\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$: mov     a,dpl\n");
176   fprintf (of, "        cjne    a,ar1,00001$\n");
177   fprintf (of, "        mov     a,dph\n");
178   fprintf (of, "        cjne    a,ar2,00001$\n");
179   fprintf (of, "        mov     p2,#0xFF\n");
180   fprintf (of, "00003$:\n");
181   fprintf (of, ";       _mcs51_genXINIT() end\n");
182 }
183
184
185 /* Do CSE estimation */
186 static bool cseCostEstimation (iCode *ic, iCode *pdic)
187 {
188     operand *result = IC_RESULT(ic);
189     sym_link *result_type = operandType(result);
190
191     /* if it is a pointer then return ok for now */
192     if (IC_RESULT(ic) && IS_PTR(result_type)) return 1;
193     
194     /* if bitwise | add & subtract then no since mcs51 is pretty good at it 
195        so we will cse only if they are local (i.e. both ic & pdic belong to
196        the same basic block */
197     if (IS_BITWISE_OP(ic) || ic->op == '+' || ic->op == '-') {
198         /* then if they are the same Basic block then ok */
199         if (ic->eBBlockNum == pdic->eBBlockNum) return 1;
200         else return 0;
201     }
202         
203     /* for others it is cheaper to do the cse */
204     return 1;
205 }
206
207 /** $1 is always the basename.
208     $2 is always the output file.
209     $3 varies
210     $l is the list of extra options that should be there somewhere...
211     MUST be terminated with a NULL.
212 */
213 static const char *_linkCmd[] =
214 {
215   "{bindir}{sep}aslink", "-nf", "$1", NULL
216 };
217
218 /* $3 is replaced by assembler.debug_opts resp. port->assembler.plain_opts */
219 static const char *_asmCmd[] =
220 {
221   "asx8051", "$l", "$3", "$1.asm", NULL
222 };
223
224 /* Globals */
225 PORT mcs51_port =
226 {
227   TARGET_ID_MCS51,
228   "mcs51",
229   "MCU 8051",                   /* Target name */
230   NULL,                         /* Processor name */
231   {
232     TRUE,                       /* Emit glue around main */
233     MODEL_SMALL | MODEL_LARGE,
234     MODEL_SMALL
235   },
236   {
237     _asmCmd,
238     NULL,
239     "-plosgffc",                /* Options with debug */
240     "-plosgff",                 /* Options without debug */
241     0,
242     ".asm",
243     NULL                        /* no do_assemble function */
244   },
245   {
246     _linkCmd,
247     NULL,
248     NULL,
249     ".rel"
250   },
251   {
252     _defaultRules
253   },
254   {
255         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
256     1, 2, 2, 4, 1, 2, 3, 1, 4, 4
257   },
258   {
259     "XSEG    (XDATA)",
260     "STACK   (DATA)",
261     "CSEG    (CODE)",
262     "DSEG    (DATA)",
263     "ISEG    (DATA)",
264     "XSEG    (XDATA)",
265     "BSEG    (BIT)",
266     "RSEG    (DATA)",
267     "GSINIT  (CODE)",
268     "OSEG    (OVR,DATA)",
269     "GSFINAL (CODE)",
270     "HOME    (CODE)",
271     "XISEG   (XDATA)", // initialized xdata
272     "XINIT   (CODE)", // a code copy of xiseg
273     NULL,
274     NULL,
275     1
276   },
277   {
278     +1, 1, 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   0,                            /* leave lt */
304   0,                            /* leave gt */
305   1,                            /* transform <= to ! > */
306   1,                            /* transform >= to ! < */
307   1,                            /* transform != to !(a == b) */
308   0,                            /* leave == */
309   FALSE,                        /* No array initializer support. */
310   cseCostEstimation,
311   NULL,                         /* no builtin functions */
312   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
313   1,                            /* reset labelKey to 1 */
314   1,                            /* globals & local static allowed */
315   PORT_MAGIC
316 };