Imported Upstream version 2.9.0
[debian/cc1111] / as / link / z80 / lkgb.c
1 /* lkgb.c
2
3    Copyright (C) 1989-1995 Alan R. Baldwin
4    721 Berkeley St., Kent, Ohio 44240
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 3, or (at your option) any
9 later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
18
19 /*
20  * P. Felber
21  */
22
23 #ifdef GAMEBOY
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include "aslink.h"
30
31 /* Value used to fill the unused portions of the image */
32 /* FFh puts less stress on a EPROM/Flash */
33 #define FILLVALUE       0xFF
34
35 #define CARTSIZE ((unsigned long)nb_rom_banks*16UL*1024UL)
36 #define NBSEG 8UL
37 #define SEGSIZE (CARTSIZE/NBSEG)
38
39 #define ROMSIZE 0x8000UL
40 #define BANKSTART 0x4000UL
41 #define BANKSIZE 0x4000UL
42
43 unsigned char *cart[NBSEG];
44
45 int nb_rom_banks;
46 int nb_ram_banks;
47 int current_rom_bank;
48 int mbc_type;
49 char cart_name[16] = "";
50
51 patch* patches = NULL;
52
53 VOID gb(int in)
54 {
55   static int first = 1;
56   unsigned long pos, chk;
57   int i;
58   patch *p;
59
60   if(first) {
61     for(i = 0; i < NBSEG; i++) {
62       if((cart[i] = malloc(SEGSIZE)) == NULL) {
63         fprintf(stderr, "ERROR: can't allocate %dth segment of memory (%d bytes)\n", i, (int)SEGSIZE);
64         exit(EXIT_FAILURE);
65       }
66       memset(cart[i], FILLVALUE, SEGSIZE);
67     }
68     first = 0;
69   }
70   if(in) {
71     if(rtcnt > 2) {
72       if(hilo == 0)
73         pos = rtval[0] | (rtval[1]<<8);
74       else
75         pos = rtval[1] | (rtval[0]<<8);
76
77       /* Perform some validity checks */
78       if(pos >= ROMSIZE) {
79         fprintf(stderr, "ERROR: address overflow (addr %lx >= %lx)\n", pos, ROMSIZE);
80         exit(EXIT_FAILURE);
81       }
82       if(current_rom_bank >= nb_rom_banks) {
83         fprintf(stderr, "ERROR: bank overflow (addr %x > %x)\n", current_rom_bank, nb_rom_banks);
84         exit(EXIT_FAILURE);
85       }
86       if(current_rom_bank > 0 && pos < BANKSTART) {
87         fprintf(stderr, "ERROR: address underflow (addr %lx < %lx)\n", pos, BANKSTART);
88         exit(EXIT_FAILURE);
89       }
90       if(nb_rom_banks == 2 && current_rom_bank > 0) {
91         fprintf(stderr, "ERROR: only 1 32kB segment with 2 bank\n");
92         exit(EXIT_FAILURE);
93       }
94       if(current_rom_bank > 1)
95         pos += (current_rom_bank-1)*BANKSIZE;
96       for(i = 2; i < rtcnt; i++) {
97         if(rtflg[i]) {
98           if(pos < CARTSIZE) {
99             if(cart[pos/SEGSIZE][pos%SEGSIZE] != FILLVALUE)
100               fprintf(stderr, "WARNING: possibly wrote twice at addr %lx (%02X->%02X)\n", pos, rtval[i], cart[pos/SEGSIZE][pos%SEGSIZE]);
101             cart[pos/SEGSIZE][pos%SEGSIZE] = rtval[i];
102           } else {
103             fprintf(stderr, "ERROR: cartridge size overflow (addr %lx >= %lx)\n", pos, CARTSIZE);
104             exit(EXIT_FAILURE);
105           }
106           pos++;
107         }
108       }
109     }
110   } else {
111     /* EOF */
112     if(cart_name[0] == 0 && linkp->f_idp != NULL) {
113       for(i = strlen(linkp->f_idp);
114           i > 0 && (isalnum((unsigned char)linkp->f_idp[i-1]) || linkp->f_idp[i-1] == '.');
115           i--)
116         ;
117       for(pos = 0; pos < 16 && linkp->f_idp[i] != '.'; pos++, i++)
118         cart_name[pos] = toupper((unsigned char)linkp->f_idp[i]);
119       if(pos < 16)
120         cart_name[pos] = 0;
121     }
122     for(pos = 0x0134, i = 0;
123         pos < 0x0144 && cart_name[i];
124         pos++, i++)
125       cart[pos/SEGSIZE][pos%SEGSIZE] = cart_name[i];
126     for(; pos < 0x0144; pos++)
127       cart[pos/SEGSIZE][pos%SEGSIZE] = 0;
128     cart[0x147/SEGSIZE][0x147%SEGSIZE] = mbc_type;
129     switch(nb_rom_banks) {
130     case 2:
131       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 0;
132       break;
133     case 4:
134       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 1;
135       break;
136     case 8:
137       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 2;
138       break;
139     case 16:
140       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 3;
141       break;
142     case 32:
143       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 4;
144       break;
145     case 64:
146       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 5;
147       break;
148     case 128:
149       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 6;
150       break;
151     case 256:
152       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 7;
153       break;
154     case 512:
155       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 8;
156       break;
157     default:
158       fprintf(stderr, "WARNING: unsupported number of ROM banks (%d)\n", nb_rom_banks);
159       cart[0x148/SEGSIZE][0x148%SEGSIZE] = 0;
160       break;
161     }
162     switch(nb_ram_banks) {
163     case 0:
164       cart[0x149/SEGSIZE][0x149%SEGSIZE] = 0;
165       break;
166     case 1:
167       cart[0x149/SEGSIZE][0x149%SEGSIZE] = 2;
168       break;
169     case 4:
170       cart[0x149/SEGSIZE][0x149%SEGSIZE] = 3;
171       break;
172     case 16:
173       cart[0x149/SEGSIZE][0x149%SEGSIZE] = 4;
174       break;
175     default:
176       fprintf(stderr, "WARNING: unsupported number of RAM banks (%d)\n", nb_ram_banks);
177       cart[0x149/SEGSIZE][0x149%SEGSIZE] = 0;
178       break;
179     }
180
181     /* Patch before calculating the checksum */
182     if(patches)
183       for(p = patches; p; p = p->next)
184         cart[p->addr/SEGSIZE][p->addr%SEGSIZE] = p->value;
185
186     /* Update complement checksum */
187     chk = 0;
188     for(pos = 0x0134; pos < 0x014D; pos++)
189       chk += cart[pos/SEGSIZE][pos%SEGSIZE];
190     cart[0x014D/SEGSIZE][0x014D%SEGSIZE] = (unsigned char)(0xE7 - (chk&0xFF));
191     /* Update checksum */
192     chk = 0;
193     cart[0x014E/SEGSIZE][0x014E%SEGSIZE] = 0;
194     cart[0x014F/SEGSIZE][0x014F%SEGSIZE] = 0;
195     for(i = 0; i < NBSEG; i++)
196       for(pos = 0; pos < SEGSIZE; pos++)
197         chk += cart[i][pos];
198     cart[0x014E/SEGSIZE][0x014E%SEGSIZE] = (unsigned char)((chk>>8)&0xFF);
199     cart[0x014F/SEGSIZE][0x014F%SEGSIZE] = (unsigned char)(chk&0xFF);
200
201     for(i = 0; i < NBSEG; i++)
202       fwrite(cart[i], 1, SEGSIZE, ofp);
203   }
204 }
205
206 #endif /* GAMEBOY */