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