1 /*
2  * c64rom.c
3  *
4  * Written by
5  *  Andreas Boose <viceteam@t-online.de>
6  *
7  * This file is part of VICE, the Versatile Commodore Emulator.
8  * See README for copyright notice.
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23  *  02111-1307  USA.
24  *
25  */
26 
27 #include "vice.h"
28 
29 #include <stdio.h>
30 #include <string.h>
31 
32 #include "c64-resources.h"
33 #include "c64mem.h"
34 #include "c64memrom.h"
35 #include "c64rom.h"
36 #include "log.h"
37 #include "machine.h"
38 #include "mem.h"
39 #include "patchrom.h"
40 #include "resources.h"
41 #include "sysfile.h"
42 #include "types.h"
43 
44 int kernal_revision_cmdline = -1;
45 
46 static log_t c64rom_log = LOG_ERR;
47 
48 /* Flag: nonzero if the Kernal and BASIC ROMs have been loaded.  */
49 static int rom_loaded = 0;
50 
c64rom_isloaded(void)51 int c64rom_isloaded(void)
52 {
53     return rom_loaded;
54 }
55 
c64rom_get_kernal_chksum_id(uint16_t * sumout,int * idout)56 int c64rom_get_kernal_chksum_id(uint16_t *sumout, int *idout)
57 {
58     int i;
59     uint16_t sum;                   /* ROM checksum */
60     int id;                     /* ROM identification number */
61 
62     /* Check Kernal ROM.  */
63     for (i = 0, sum = 0; i < C64_KERNAL_ROM_SIZE; i++) {
64         sum += c64memrom_kernal64_rom[i];
65     }
66     /* get ID from Kernal ROM */
67     id = c64memrom_rom64_read(0xff80);
68     if (sumout) {
69         *sumout = sum;
70     }
71     if (idout) {
72         *idout = id;
73     }
74     /* check against known kernal versions */
75     if (((id == C64_KERNAL_ID_R01) && (sum == C64_KERNAL_CHECKSUM_R01)) ||
76         ((id == C64_KERNAL_ID_R02) && (sum == C64_KERNAL_CHECKSUM_R02)) ||
77         ((id == C64_KERNAL_ID_R03) && (sum == C64_KERNAL_CHECKSUM_R03)) ||
78         /* ((id == C64_KERNAL_ID_R03swe) && (sum == C64_KERNAL_CHECKSUM_R03swe)) || */
79         ((id == C64_KERNAL_ID_R43) && (sum == C64_KERNAL_CHECKSUM_R43)) ||
80         ((id == C64_KERNAL_ID_R64) && (sum == C64_KERNAL_CHECKSUM_R64))
81        ) {
82         /* known */
83         return 0;
84     }
85     return -1; /* unknown */
86 }
87 
88 /* FIXME: this function should perhaps not patch the kernal, but return -1 on
89           unknown kernals, like the respective vic-20 functions */
c64rom_get_kernal_checksum(void)90 int c64rom_get_kernal_checksum(void)
91 {
92     uint16_t sum;                   /* ROM checksum */
93     int id;                     /* ROM identification number */
94 
95     if (c64rom_get_kernal_chksum_id(&sum, &id) < 0) {
96         log_warning(c64rom_log, "Unknown Kernal image.  ID: %d ($%02X) Sum: %d ($%04X).", id, (unsigned int)id, sum, sum);
97         return -1;
98     } else {
99         log_message(c64rom_log, "Kernal rev #%d ($%02X) Sum: %d ($%04X).", id, (unsigned int)id, sum, sum);
100     }
101 
102     return 0;
103 }
104 
105 int c64rom_cartkernal_active = 0;
106 
107 /* the extra parameter cartkernal is used to replace the kernal
108    with a cartridge kernal rom image, if it is NULL normal kernal
109    is used */
c64rom_load_kernal(const char * rom_name,uint8_t * cartkernal)110 int c64rom_load_kernal(const char *rom_name, uint8_t *cartkernal)
111 {
112     int trapfl, rev;
113     uint16_t sum;                   /* ROM checksum */
114     int id;                     /* ROM identification number */
115 
116     if (!rom_loaded) {
117         return 0;
118     }
119 
120     /* disable traps before loading the ROM */
121     if (machine_class != VICE_MACHINE_VSID) {
122         resources_get_int("VirtualDevices", &trapfl);
123         resources_set_int("VirtualDevices", 0);
124     }
125 
126     /* Load Kernal ROM.  */
127     if (cartkernal == NULL) {
128         if (c64rom_cartkernal_active == 1) {
129             if (machine_class != VICE_MACHINE_VSID) {
130                 resources_set_int("VirtualDevices", trapfl);
131             }
132             return -1;
133         }
134 
135         if (sysfile_load(rom_name, c64memrom_kernal64_rom, C64_KERNAL_ROM_SIZE, C64_KERNAL_ROM_SIZE) < 0) {
136             log_error(c64rom_log, "Couldn't load kernal ROM `%s'.", rom_name);
137             if (machine_class != VICE_MACHINE_VSID) {
138                 resources_set_int("VirtualDevices", trapfl);
139             }
140             return -1;
141         }
142     } else {
143         memcpy(c64memrom_kernal64_rom, cartkernal, 0x2000);
144         c64rom_cartkernal_active = 1;
145     }
146 
147     if (machine_class != VICE_MACHINE_C64DTV) {
148         resources_get_int("KernalRev", &rev);
149     }
150     if (c64rom_get_kernal_chksum_id(&sum, &id) < 0) {
151         log_verbose("loaded unknown kernal revision:%d chksum: %d", id, sum);
152         rev =  C64_KERNAL_UNKNOWN;
153     } else {
154         log_verbose("loaded known kernal revision:%d chksum: %d", id, sum);
155         rev = id;
156     }
157     if (machine_class != VICE_MACHINE_C64DTV) {
158         /* patch kernal to revision given on cmdline */
159         if (kernal_revision_cmdline != -1) {
160             if (rev !=  C64_KERNAL_UNKNOWN) {
161                 log_verbose("patching kernal revision:%d to revision: %d", rev, kernal_revision_cmdline);
162                 if (patch_rom_idx(kernal_revision_cmdline) >= 0) {
163                     rev = kernal_revision_cmdline;
164                 }
165             }
166             /* do this only once */
167             kernal_revision_cmdline = -1;
168         }
169         resources_set_int("KernalRev", rev);
170     }
171     memcpy(c64memrom_kernal64_trap_rom, c64memrom_kernal64_rom, C64_KERNAL_ROM_SIZE);
172 
173     if (machine_class != VICE_MACHINE_VSID) {
174         resources_set_int("VirtualDevices", trapfl);
175     }
176 
177     return 0;
178 }
179 
c64rom_get_basic_checksum(void)180 int c64rom_get_basic_checksum(void)
181 {
182     int i;
183     uint16_t sum;
184 
185     /* Check Basic ROM.  */
186 
187     for (i = 0, sum = 0; i < C64_BASIC_ROM_SIZE; i++) {
188         sum += c64memrom_basic64_rom[i];
189     }
190 
191     if (sum != C64_BASIC_CHECKSUM) {
192         log_warning(c64rom_log, "Unknown Basic image.  Sum: %d ($%04X).", sum, sum);
193     }
194 
195     return 0;
196 }
197 
c64rom_load_basic(const char * rom_name)198 int c64rom_load_basic(const char *rom_name)
199 {
200     if (!rom_loaded) {
201         return 0;
202     }
203 
204     /* Load Basic ROM.  */
205     if (sysfile_load(rom_name, c64memrom_basic64_rom, C64_BASIC_ROM_SIZE, C64_BASIC_ROM_SIZE) < 0) {
206         log_error(c64rom_log, "Couldn't load basic ROM `%s'.", rom_name);
207         return -1;
208     }
209     return c64rom_get_basic_checksum();
210 }
211 
c64rom_load_chargen(const char * rom_name)212 int c64rom_load_chargen(const char *rom_name)
213 {
214     if (!rom_loaded) {
215         return 0;
216     }
217 
218     /* Load chargen ROM.  */
219 
220     if (sysfile_load(rom_name, mem_chargen_rom, C64_CHARGEN_ROM_SIZE, C64_CHARGEN_ROM_SIZE) < 0) {
221         log_error(c64rom_log, "Couldn't load character ROM `%s'.", rom_name);
222         return -1;
223     }
224 
225     return 0;
226 }
227 
mem_load(void)228 int mem_load(void)
229 {
230     const char *rom_name = NULL;
231 
232     if (c64rom_log == LOG_ERR) {
233         c64rom_log = log_open("C64MEM");
234     }
235 
236     rom_loaded = 1;
237 
238     if (resources_get_string("KernalName", &rom_name) < 0) {
239         return -1;
240     }
241     if (c64rom_load_kernal(rom_name, NULL) < 0) {
242         return -1;
243     }
244 
245     if (resources_get_string("BasicName", &rom_name) < 0) {
246         return -1;
247     }
248     if (c64rom_load_basic(rom_name) < 0) {
249         return -1;
250     }
251 
252     if (resources_get_string("ChargenName", &rom_name) < 0) {
253         return -1;
254     }
255     if (c64rom_load_chargen(rom_name) < 0) {
256         return -1;
257     }
258 
259     return 0;
260 }
261