Merge out from the z80 far branch
[fw/sdcc] / src / z80 / main.c
1 #include "z80.h"
2
3 static char _z80_defaultRules[] =
4 {
5 #include "peeph.rul"
6 #include "peeph-z80.rul"
7 };
8
9 static char _gbz80_defaultRules[] =
10 {
11 #include "peeph.rul"
12 #include "peeph-gbz80.rul"
13 };
14
15 Z80_OPTS z80_opts;
16
17 static struct {
18     bool fsetAsmType;
19 } _G;
20
21 static char *_keywords[] = {
22     "sfr",
23     "banked",
24     NULL 
25 };
26
27 extern PORT gbz80_port;
28 extern PORT z80_port;
29
30 #include "mappings.i"
31
32 static void _z80_init(void)
33 {
34     z80_opts.sub = SUB_Z80;
35     asm_addTree(&_asxxxx_z80);
36 }
37
38 static void _gbz80_init(void)
39 {
40     z80_opts.sub = SUB_GBZ80;
41 }
42
43 static int regParmFlg = 0; /* determine if we can register a parameter */
44
45 static void _reset_regparm()
46 {
47     regParmFlg = 0;
48 }
49
50 static int _reg_parm(link *l)
51 {
52     if (regParmFlg == 2)
53         return 0;
54     
55     regParmFlg++;
56     return 1;
57 }
58
59 static bool _startsWith(const char *sz, const char *key)
60 {
61     return !strncmp(sz, key, strlen(key));
62 }
63
64 static void _chomp(char *sz)
65 {
66     char *nl;
67     while ((nl = strrchr(sz, '\n'))) 
68         *nl = '\0';
69 }
70
71 static int _process_pragma(const char *sz)
72 {
73     if (_startsWith(sz, "bank=")) {
74         char buffer[128];
75         sprintf(buffer, "%s", sz+5);
76         _chomp(buffer);
77         if (!strcmp(buffer, "BASE")) {
78             strcpy(buffer, "HOME");
79         }
80         gbz80_port.mem.code_name = gc_strdup(buffer);
81         code->sname = gbz80_port.mem.code_name;
82         return 0;
83     }
84     return 1;
85 }
86
87 static const char *_gbz80_rgbasmCmd[] = {
88     "rgbasm", "-o$1.o", "$1.asm", NULL
89 };
90
91 static const char *_gbz80_rgblinkCmd[] = {
92     "xlink", "-tg", "-n$1.sym", "-m$1.map", "-zFF", "$1.lnk", NULL
93 };
94
95 static void _gbz80_rgblink(void)
96 {
97     FILE *lnkfile;
98     const char *sz;
99     char *argv[128];
100
101     int i;
102     sz = srcFileName;
103     if (!sz)
104         sz = "a";
105
106     /* first we need to create the <filename>.lnk file */
107     sprintf(buffer,"%s.lnk", sz);
108     if (!(lnkfile = fopen(buffer,"w"))) {
109         werror(E_FILE_OPEN_ERR, buffer);
110         exit(1);
111     }
112
113     fprintf(lnkfile, "[Objects]\n");
114
115     if (srcFileName)
116         fprintf(lnkfile, "%s.o\n", sz);
117
118     for (i = 0 ; i < nrelFiles ; i++ )
119         fprintf (lnkfile,"%s\n",relFiles[i]);
120
121     fprintf(lnkfile, "\n[Libraries]\n");
122     /* additional libraries if any */
123     for (i = 0 ; i < nlibFiles; i++)
124         fprintf (lnkfile,"%s\n",libFiles[i]);
125
126
127     fprintf(lnkfile,"\n[Output]\n" "%s.gb",sz);
128
129     fclose(lnkfile);
130
131     buildCmdLine(buffer, argv, port->linker.cmd, sz, NULL, NULL, NULL);
132     /* call the linker */
133     if (my_system(argv[0], argv)) {
134         perror("Cannot exec linker");
135         exit(1);
136     }
137 }
138
139 static bool _parseOptions(int *pargc, char **argv, int *i)
140 {
141     if (argv[*i][0] == '-') {
142         if (argv[*i][1] == 'b' && IS_GB) {
143             int bank = atoi(argv[*i] + 3);
144             char buffer[128];
145             switch (argv[*i][2]) {
146             case 'o':
147                 /* ROM bank */
148                 sprintf(buffer, "CODE_%u", bank);
149                 gbz80_port.mem.code_name = gc_strdup(buffer);
150                 return TRUE;
151             case 'a':
152                 /* RAM bank */
153                 sprintf(buffer, "DATA_%u", bank);
154                 gbz80_port.mem.data_name = gc_strdup(buffer);
155                 return TRUE;
156             }
157         }
158         else if (!strncmp(argv[*i], "--asm=", 6)) {
159             if (!strcmp(argv[*i], "--asm=rgbds")) {
160                 asm_addTree(&_rgbds_gb);
161                 gbz80_port.assembler.cmd = _gbz80_rgbasmCmd;
162                 gbz80_port.linker.cmd = _gbz80_rgblinkCmd;
163                 gbz80_port.linker.do_link = _gbz80_rgblink;
164                 _G.fsetAsmType = TRUE;
165                 return TRUE;
166             }
167             else if (!strcmp(argv[*i], "--asm=asxxxx")) {
168                 asm_addTree(&_asxxxx_gb);
169                 _G.fsetAsmType = TRUE;
170                 return TRUE;
171             }
172             else if (!strcmp(argv[*i], "--asm=isas")) {
173                 asm_addTree(&_isas_gb);
174                 /* Munge the function prefix */
175                 gbz80_port.fun_prefix = "";
176                 _G.fsetAsmType = TRUE;
177                 return TRUE;
178             }
179         }
180     }
181     return FALSE;
182 }
183
184 static void _finaliseOptions(void)
185 {
186     port->mem.default_local_map = data;
187     port->mem.default_globl_map = data;
188     if (!_G.fsetAsmType && IS_GB)
189         asm_addTree(&_asxxxx_gb);
190 }
191
192 static void _setDefaultOptions(void)
193 {    
194     options.genericPtr = 1;   /* default on */
195     options.nopeep    = 0;
196     options.stackAuto = 1;
197     options.mainreturn = 1;
198     options.noregparms = 1;
199     options.nodebug = 1;
200     /* first the options part */
201     options.intlong_rent = 1;
202
203     optimize.global_cse = 1;    
204     optimize.label1 = 1;
205     optimize.label2 = 1;
206     optimize.label3 = 1;
207     optimize.label4 = 1;    
208     optimize.loopInvariant = 1;
209     optimize.loopInduction = 0;
210 }
211
212 static const char *_getRegName(struct regs *reg)
213 {
214     if (reg)
215         return reg->name;
216     assert(0);
217     return "err";
218 }
219
220 /** $1 is always the basename.
221     $2 is always the output file.
222     $3 varies
223     $l is the list of extra options that should be there somewhere...
224     MUST be terminated with a NULL.
225 */
226 static const char *_z80_linkCmd[] = {
227     "link-z80", "-nf", "$1", NULL
228 };
229
230 static const char *_z80_asmCmd[] = {
231     "as-z80", "-plosgff", "$1.asm", NULL
232 };
233
234 /** $1 is always the basename.
235     $2 is always the output file.
236     $3 varies
237     $l is the list of extra options that should be there somewhere...
238     MUST be terminated with a NULL.
239 */
240 static const char *_gbz80_linkCmd[] = {
241     "link-gbz80", "-nf", "$1", NULL
242 };
243
244 static const char *_gbz80_asmCmd[] = {
245     "as-gbz80", "-plosgff", "$1.o", "$1.asm", NULL
246 };
247
248 /* Globals */
249 PORT z80_port = {
250     "z80",
251     "Zilog Z80",                /* Target name */
252     {
253         FALSE,
254     },
255     {   
256         _z80_asmCmd,
257         "-plosgff",             /* Options with debug */
258         "-plosgff",             /* Options without debug */
259     },
260     {
261         _z80_linkCmd,
262         NULL,
263         ".o"
264     },
265     {
266         _z80_defaultRules
267     },
268     {
269         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
270         1, 1, 2, 4, 2, 2, 2, 1, 4, 4
271     },
272     {
273         "XSEG",
274         "STACK",
275         "CODE",
276         "DATA",
277         "ISEG",
278         "XSEG",
279         "BSEG",
280         "RSEG",
281         "GSINIT",
282         "OVERLAY",
283         "GSFINAL",
284         NULL,
285         NULL,
286         1
287     },
288     { 
289         -1, 0, 0, 4, 0, 2
290     },
291     /* Z80 has no native mul/div commands */
292     {  
293         0
294     },
295     "_",
296     _z80_init,
297     _parseOptions,
298     _finaliseOptions,
299     _setDefaultOptions,
300     z80_assignRegisters,
301     _getRegName,
302     _keywords,
303     0,  /* no assembler preamble */
304     0,  /* no local IVT generation code */
305     _reset_regparm,
306     _reg_parm,
307     _process_pragma,
308     TRUE
309 };
310
311 /* Globals */
312 PORT gbz80_port = {
313     "gbz80",
314     "Gameboy Z80-like",         /* Target name */
315     {
316         FALSE,
317     },
318     {   
319         _gbz80_asmCmd,
320         "-plosgff",             /* Options with debug */
321         "-plosgff",             /* Options without debug */
322         1
323     },
324     {
325         _gbz80_linkCmd,
326         NULL,
327         ".o"
328     },
329     {
330         _gbz80_defaultRules
331     },
332     {
333         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
334         1, 1, 2, 4, 2, 2, 2, 1, 4, 4
335     },
336     {
337         "XSEG",
338         "STACK",
339         "CODE",
340         "DATA",
341         "ISEG",
342         "XSEG",
343         "BSEG",
344         "RSEG",
345         "GSINIT",
346         "OVERLAY",
347         "GSFINAL",
348         NULL,
349         NULL,
350         1
351     },
352     { 
353         -1, 0, 0, 2, 0, 4
354     },
355     /* gbZ80 has no native mul/div commands */
356     {  
357         0
358     },
359     "_",
360     _gbz80_init,
361     _parseOptions,
362     _finaliseOptions,
363     _setDefaultOptions,
364     z80_assignRegisters,
365     _getRegName,
366     _keywords,
367     0,  /* no assembler preamble */
368     0,  /* no local IVT generation code */
369     _reset_regparm,
370     _reg_parm,
371     _process_pragma,
372     TRUE
373 };