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