* debugger/mcs51/break.c, debugger/mcs51/cmd.c,
[fw/sdcc] / as / link / z80 / lkgb.c
1 /* lkgb.c */
2
3 /*
4  * P. Felber
5  */
6
7 #ifdef GAMEBOY
8
9 #include <assert.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <ctype.h>
14 #include "aslink.h"
15
16 /* Value used to fill the unused portions of the image */
17 /* FFh puts less stress on a EPROM/Flash */
18 #define FILLVALUE       0xFF
19
20 #define CARTSIZE ((unsigned long)nb_rom_banks*16UL*1024UL)
21 #define NBSEG 8UL
22 #define SEGSIZE (CARTSIZE/NBSEG)
23
24 #define ROMSIZE 0x8000UL
25 #define BANKSTART 0x4000UL
26 #define BANKSIZE 0x4000UL
27
28 unsigned char *cart[NBSEG];
29
30 int nb_rom_banks;
31 int nb_ram_banks;
32 int current_rom_bank;
33 int mbc_type;
34 char cart_name[16] = "";
35
36 patch* patches = NULL;
37
38 VOID gb(int in)
39 {
40   static int first = 1;
41   unsigned long pos, chk;
42   int i;
43   patch *p;
44
45   if(first) {
46     for(i = 0; i < NBSEG; i++) {
47       if((cart[i] = malloc(SEGSIZE)) == NULL) {
48         fprintf(stderr, "ERROR: can't allocate %dth segment of memory (%d bytes)\n", i, (int)SEGSIZE);
49         exit(EXIT_FAILURE);
50       }
51       memset(cart[i], FILLVALUE, SEGSIZE);
52     }
53     first = 0;
54   }
55   if(in) {
56     if(rtcnt > 2) {
57       if(hilo == 0)
58         pos = rtval[0] | (rtval[1]<<8);
59       else
60         pos = rtval[1] | (rtval[0]<<8);
61
62       /* Perform some validity checks */
63       if(pos >= ROMSIZE) {
64         fprintf(stderr, "ERROR: address overflow (addr %lx >= %lx)\n", pos, ROMSIZE);
65         exit(EXIT_FAILURE);
66       }
67       if(current_rom_bank >= nb_rom_banks) {
68         fprintf(stderr, "ERROR: bank overflow (addr %x > %x)\n", current_rom_bank, nb_rom_banks);
69         exit(EXIT_FAILURE);
70       }
71       if(current_rom_bank > 0 && pos < BANKSTART) {
72         fprintf(stderr, "ERROR: address underflow (addr %lx < %lx)\n", pos, BANKSTART);
73         exit(EXIT_FAILURE);
74       }
75       if(nb_rom_banks == 2 && current_rom_bank > 0) {
76         fprintf(stderr, "ERROR: only 1 32kB segment with 2 bank\n");
77         exit(EXIT_FAILURE);
78       }
79       if(current_rom_bank > 1)
80         pos += (current_rom_bank-1)*BANKSIZE;
81       for(i = 2; i < rtcnt; i++) {
82         if(rtflg[i]) {
83           if(pos < CARTSIZE) {
84             if(cart[pos/SEGSIZE][pos%SEGSIZE] != FILLVALUE)
85               fprintf(stderr, "WARNING: possibly wrote twice at addr %lx (%02X->%02X)\n", pos, rtval[i], cart[pos/SEGSIZE][pos%SEGSIZE]);
86             cart[pos/SEGSIZE][pos%SEGSIZE] = rtval[i];
87           } else {
88             fprintf(stderr, "ERROR: cartridge size overflow (addr %lx >= %lx)\n", pos, CARTSIZE);
89             exit(EXIT_FAILURE);
90           }
91           pos++;
92         }
93       }
94     }
95   } else {
96     /* EOF */
97     if(cart_name[0] == 0 && linkp->f_idp != NULL) {
98       for(i = strlen(linkp->f_idp);
99           i > 0 && (isalnum((unsigned char)linkp->f_idp[i-1]) || linkp->f_idp[i-1] == '.');
100           i--)
101         ;
102       for(pos = 0; pos < 16 && linkp->f_idp[i] != '.'; pos++, i++)
103         cart_name[pos] = toupper((unsigned char)linkp->f_idp[i]);
104       if(pos < 16)
105         cart_name[pos] = 0;
106     }
107     for(pos = 0x0134, i = 0;
108         pos < 0x0144 && cart_name[i];
109         pos++, i++)
110       cart[pos/SEGSIZE][pos%SEGSIZE] = cart_name[i];
111     for(; pos < 0x0144; pos++)
112       cart[pos/SEGSIZE][pos%SEGSIZE] = 0;
113     cart[0x147/SEGSIZE][0x147%SEGSIZE] = mbc_type;
114     switch(nb_rom_banks) {
115     case 2:
116       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 0;
117       break;
118     case 4:
119       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 1;
120       break;
121     case 8:
122       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 2;
123       break;
124     case 16:
125       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 3;
126       break;
127     case 32:
128       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 4;
129       break;
130     case 64:
131       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 5;
132       break;
133     case 128:
134       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 6;
135       break;
136     case 256:
137       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 7;
138       break;
139     case 512:
140       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 8;
141       break;
142     default:
143       fprintf(stderr, "WARNING: unsupported number of ROM banks (%d)\n", nb_rom_banks);
144       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 0;
145       break;
146     }
147     switch(nb_ram_banks) {
148     case 0:
149       cart[0x149/SEGSIZE][0x149%SEGSIZE] = 0;
150       break;
151     case 1:
152       cart[0x149/SEGSIZE][0x149%SEGSIZE] = 2;
153       break;
154     case 4:
155       cart[0x149/SEGSIZE][0x149%SEGSIZE] = 3;
156       break;
157     case 16:
158       cart[0x149/SEGSIZE][0x149%SEGSIZE] = 4;
159       break;
160     default:
161       fprintf(stderr, "WARNING: unsupported number of RAM banks (%d)\n", nb_ram_banks);
162       cart[0x149/SEGSIZE][0x149%SEGSIZE] = 0;
163       break;
164     }
165
166     /* Patch before calculating the checksum */
167     if(patches)
168       for(p = patches; p; p = p->next)
169         cart[p->addr/SEGSIZE][p->addr%SEGSIZE] = p->value;
170
171     /* Update complement checksum */
172     chk = 0;
173     for(pos = 0x0134; pos < 0x014D; pos++)
174       chk += cart[pos/SEGSIZE][pos%SEGSIZE];
175     cart[0x014D/SEGSIZE][0x014D%SEGSIZE] = (unsigned char)(0xE7 - (chk&0xFF));
176     /* Update checksum */
177     chk = 0;
178     cart[0x014E/SEGSIZE][0x014E%SEGSIZE] = 0;
179     cart[0x014F/SEGSIZE][0x014F%SEGSIZE] = 0;
180     for(i = 0; i < NBSEG; i++)
181       for(pos = 0; pos < SEGSIZE; pos++)
182         chk += cart[i][pos];
183     cart[0x014E/SEGSIZE][0x014E%SEGSIZE] = (unsigned char)((chk>>8)&0xFF);
184     cart[0x014F/SEGSIZE][0x014F%SEGSIZE] = (unsigned char)(chk&0xFF);
185
186     for(i = 0; i < NBSEG; i++) {
187       size_t res;
188       res = fwrite(cart[i], 1, SEGSIZE, ofp);
189       assert(res == SEGSIZE);
190     }
191   }
192 }
193
194 #endif /* GAMEBOY */