Skip to content

Commit 66613f0

Browse files
committed
MEGA65: mainly cosmetic cartridge refinements #380
1 parent b53140b commit 66613f0

File tree

3 files changed

+97
-58
lines changed

3 files changed

+97
-58
lines changed

targets/mega65/cart.c

Lines changed: 87 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,22 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
2525

2626

2727
static struct {
28-
bool loaded;
28+
bool attached;
2929
bool autostart;
30+
bool is_raw;
3031
char *fn;
3132
char name[0x21];
3233
Uint8 mem[0x10000];
33-
int total_size;
34-
int sections;
34+
unsigned int total_size;
35+
unsigned int sections;
36+
unsigned int min_addr, max_addr;
3537
} cart;
3638

3739

3840
void cart_init ( void )
3941
{
4042
memset(cart.mem, 0xFF, sizeof cart.mem);
41-
cart.loaded = false;
43+
cart.attached = false;
4244
cart.autostart = false;
4345
cart.name[0] = 0;
4446
cart.fn = NULL;
@@ -50,32 +52,33 @@ Uint8 cart_read_byte ( unsigned int addr )
5052
Uint8 data = 0xFF;
5153
if (addr < sizeof(cart.mem))
5254
data = cart.mem[addr];
53-
//if (cart.loaded && addr != 0x3FFDF60) // see the comment about OPL at cart_write_byte()
55+
//if (cart.attached && addr != 0x3FFDF60) // see the comment about OPL at cart_write_byte()
5456
// DEBUGPRINT("CART: reading byte ($%02X) at $%X" NL, data, addr + 0x4000000);
5557
return data;
5658
}
5759

5860

5961
void cart_write_byte ( unsigned int addr, Uint8 data )
6062
{
61-
if (!cart.loaded) {
62-
// a hack OPL to be able to work in the "slow device area" [if no cartridge is loaded]
63-
static Uint8 opl_reg_sel = 0;
64-
if (addr == 0x3FFDF40) {
65-
opl_reg_sel = data;
66-
return;
67-
} else if (addr == 0x3FFDF50) {
68-
audio65_opl3_write(opl_reg_sel, data);
69-
return;
70-
}
63+
// FIXME: do we really care if cartridge is attached to handle OPL3?
64+
if (XEMU_UNLIKELY(!cart.attached))
65+
return;
66+
// a hack OPL to be able to work in the "slow device area" [if no cartridge is attached]
67+
static Uint8 opl_reg_sel = 0;
68+
if (addr == 0x3FFDF40) {
69+
opl_reg_sel = data;
70+
return;
71+
} else if (addr == 0x3FFDF50) {
72+
audio65_opl3_write(opl_reg_sel, data);
73+
return;
7174
}
7275
//DEBUGPRINT("CART: writing byte ($%02X) at $%X" NL, data, addr + 0x4000000);
7376
}
7477

7578

7679
bool cart_is_attached ( void )
7780
{
78-
return cart.loaded;
81+
return cart.attached;
7982
}
8083

8184

@@ -85,9 +88,9 @@ void cart_detach ( void )
8588
cart.autostart = false;
8689
free(cart.fn);
8790
cart.fn = NULL;
88-
if (cart.loaded) {
91+
if (cart.attached) {
8992
DEBUGPRINT("CART: cartridge has been detached" NL);
90-
cart.loaded = false;
93+
cart.attached = false;
9194
}
9295
}
9396

@@ -107,100 +110,127 @@ int cart_attach ( const char *fn )
107110
static const char m65_bytestr[] = { 'M', '6', '5' };
108111
static const char mega65_bytestr[] = { 'M', 'E', 'G', 'A', '6', '5' };
109112
static const char chip_bytestr[] = { 'C', 'H', 'I', 'P' };
113+
static const char error_head[] = "Cannot attach cartridge";
110114
cart_detach();
111115
if (!fn || !*fn)
112116
return -1;
113117
const int fd = xemu_open_file(fn, O_RDONLY, NULL, NULL);
114118
if (fd < 0) {
115-
ERROR_WINDOW("Cannot open cartridge file %s\nError: %s", fn, strerror(errno));
119+
ERROR_WINDOW("%s\nCannot open file %s\nError: %s", error_head, fn, strerror(errno));
116120
return -1;
117121
}
118-
cart.fn = xemu_realloc(cart.fn, strlen(fn) + 1);
119-
strcpy(cart.fn, fn);
122+
xemu_restrdup(&cart.fn, fn);
120123
Uint8 buf[0x40 + 1];
121-
if (xemu_safe_read(fd, buf, 0x40) != 0x40)
124+
ssize_t rr = xemu_safe_read(fd, buf, 0x40);
125+
if (rr != 0x40)
122126
goto read_error;
123127
if (!_check_cartridge_str(buf)) {
124128
// " CARTRIDGE" (with space) cannot be found in the first 0x10 bytes: not a VICE CRT format
125129
// let's check if it's a "raw ROM" with the "M65" mark
126130
if (memcmp(buf + 7, m65_bytestr, sizeof m65_bytestr)) {
127-
ERROR_WINDOW("Not a CRT/raw file: %s", fn); // not that either -> error
131+
ERROR_WINDOW("%s\nNot a CRT/raw file: %s", error_head, fn); // not that either -> error
128132
goto error;
129133
}
130134
// Raw binary file, with "M65" mark: the best I can do is loading from $8000
131135
memcpy(cart.mem + 0x8000, buf, 0x40); // copy what we have already
132-
const int ret = xemu_safe_read(fd, cart.mem + 0x8000 + 0x40, 0x10000 - 0x8000 - 0x40); // load the rest
133-
if (ret < 0)
136+
rr = xemu_safe_read(fd, cart.mem + 0x8000 + 0x40, 0x10000 - 0x8000 - 0x40); // load the rest (but within memory limits, not above $FFFF)
137+
if (rr < 0)
134138
goto read_error;
135-
cart.loaded = true;
139+
cart.name[0] = 0;
140+
cart.attached = true;
136141
cart.sections = 0;
137-
cart.total_size = ret + 0x40;
142+
cart.total_size = (unsigned int)rr + 0x40;
143+
cart.min_addr = 0x8000;
144+
cart.max_addr = cart.min_addr + cart.total_size - 1;
138145
cart.autostart = true; // raw image is always auto start as I detected with 'M65' signature ...
139-
DEBUGPRINT("CART: raw cartridge ROM image \"%s\" has been loaded to $8000-$%X" NL, fn, 0x8000 + cart.total_size - 1);
146+
cart.is_raw = true;
147+
DEBUGPRINT("CART: raw cartridge ROM image \"%s\" has been attached at $8000-$%X" NL, fn, 0x8000 + cart.total_size - 1);
140148
close(fd);
141149
return 1;
142150
}
143151
if (memcmp(buf, mega65_bytestr, sizeof mega65_bytestr)) {
144-
ERROR_WINDOW("Non-MEGA65 CRT file: %s", fn);
152+
ERROR_WINDOW("%s\nNon-MEGA65 CRT file: %s", error_head, fn);
145153
goto error;
146154
}
147155
// VICE-like CRT file (MEGA65-specific though)
148156
DEBUGPRINT("CART: trying to attach VICE-like CRT file %s" NL, fn);
149157
buf[0x40] = 0;
150158
strcpy(cart.name, (const char*)buf + 0x20);
159+
cart.is_raw = false;
151160
cart.sections = 0;
152161
cart.total_size = 0;
153-
for (;;) {
154-
const int ret = xemu_safe_read(fd, buf, 0x10); // read "CHIP" section header
155-
if (!ret)
162+
cart.min_addr = 0xFFFFFFFFU;
163+
cart.max_addr = 0;
164+
for (;;cart.sections++) {
165+
rr = xemu_safe_read(fd, buf, 0x10); // read "CHIP" section header
166+
if (!rr) {
167+
if (!cart.total_size) {
168+
ERROR_WINDOW("%s\nNo image data in the CRT file", error_head);
169+
goto error;
170+
}
156171
break;
157-
if (ret != 0x10)
172+
}
173+
if (rr != 0x10)
158174
goto read_error;
159175
if (memcmp(buf, chip_bytestr, sizeof chip_bytestr)) {
160-
ERROR_WINDOW("Bad CRT file, missing CHIP section ID");
176+
ERROR_WINDOW("%s\nBad CRT file, missing/bad CHIP section ID", error_head);
161177
goto error;
162178
}
163179
const unsigned int size = (buf[0xE] << 8) + buf[0xF];
180+
if (!size) {
181+
DEBUGPRINT("CART: ... new CHIP section (#%d), skipping zero length image", cart.sections);
182+
continue;
183+
}
164184
const unsigned int addr = (buf[0xC] << 8) + buf[0xD];
165-
DEBUGPRINT("CART: ... new CHIP section (#%d), $%04X-$%04X (%u bytes)" NL, cart.sections, addr, addr + size - 1, size);
166-
if (size + addr > 0x10000) {
167-
ERROR_WINDOW("Bad CRT file, CHIP section overflows memory");
185+
const unsigned int end_addr = addr + size - 1;
186+
DEBUGPRINT("CART: ... new CHIP section (#%d), $%04X-$%04X (%u bytes)" NL, cart.sections, addr, end_addr, size);
187+
if (end_addr > 0xFFFFU) {
188+
ERROR_WINDOW("%s\nBad CRT file, CHIP section overflows memory: $%X-$%X", error_head, addr, end_addr);
168189
goto error;
169190
}
170-
if (size) {
171-
if (xemu_safe_read(fd, cart.mem + addr, size) != size)
172-
goto read_error;
173-
}
174-
cart.sections++;
191+
if (addr < cart.min_addr)
192+
cart.min_addr = addr;
193+
if (end_addr > cart.max_addr)
194+
cart.max_addr = end_addr;
195+
rr = xemu_safe_read(fd, cart.mem + addr, size);
196+
if (rr != size)
197+
goto read_error;
175198
cart.total_size += size;
176199
}
177-
if (!cart.sections) {
178-
ERROR_WINDOW("No CHIP sections");
179-
goto error;
180-
}
181-
cart.loaded = true;
200+
cart.attached = true;
182201
cart.autostart = !memcmp(cart.mem + 0x8007, m65_bytestr, sizeof m65_bytestr);
183202
DEBUGPRINT("CART: attached, autostart = %d, name = \"%s\"" NL, (int)cart.autostart, cart.name);
184203
close(fd);
185204
return (int)cart.autostart;
186205
read_error:
187-
ERROR_WINDOW("Cannot read (or truncated/too small) cartridge file %s", fn);
206+
ERROR_WINDOW("%s\nCannot read %s\nError: %s", error_head, fn, rr < 0 ? strerror(errno) : "truncated or too small file");
188207
error:
189208
cart_detach();
190209
if (fd >= 0)
191210
close(fd);
211+
DEBUGPRINT("CART: attaching cartridge failed" NL);
192212
return -1;
193213
}
194214

195215

196-
void cart_info ( char *p, size_t size )
216+
const char *cart_get_fn ( void )
197217
{
198-
if (!cart.loaded) {
199-
snprintf(p, size, "No cartridge is attached");
200-
return;
201-
}
202-
snprintf(p, size, "Filename: %s\nCartridge: %s\nAuto-start: %d\nSections: %d\nTotal binary size: %d\nFormat: %s",
203-
cart.fn, cart.name, (int)cart.autostart, cart.sections, cart.total_size,
204-
cart.sections ? "CRT" : "RAW"
205-
);
218+
return (cart.attached && cart.fn && cart.fn[0]) ? cart.fn : "<N/A>";
219+
}
220+
221+
222+
int cart_info ( char *p, size_t size )
223+
{
224+
if (cart.attached)
225+
return snprintf(p, size, "Status: attached\nFilename: %s\nCartridge name: %s\nAuto-start: %c\nSections: %d\nTotal binary size: %d\nFormat: %s\nMin...max: $%04X-$%04X",
226+
cart.fn,
227+
cart.name[0] ? cart.name : "N/A",
228+
cart.autostart ? 'Y' : 'N',
229+
cart.sections,
230+
cart.total_size,
231+
cart.is_raw ? "RAW" : "CRT",
232+
cart.min_addr, cart.max_addr
233+
);
234+
else
235+
return snprintf(p, size, "Status: detached");
206236
}

targets/mega65/cart.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ extern void cart_write_byte ( unsigned int addr, Uint8 data );
2525
extern int cart_attach ( const char *fn );
2626
extern void cart_detach ( void );
2727
extern bool cart_is_attached ( void );
28-
extern void cart_info ( char *p, size_t size );
28+
extern int cart_info ( char *p, size_t size );
29+
extern const char *cart_get_fn( void );
2930

3031
#endif

targets/mega65/ui.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,11 @@ static void reset_via_hyppo ( void )
337337
reset_mega65(RESET_MEGA65_HYPPO | RESET_MEGA65_ASK);
338338
}
339339

340+
static void reset_without_cartridge ( void )
341+
{
342+
reset_mega65(RESET_MEGA65_HARD | RESET_MEGA65_ASK | RESET_MEGA65_NO_CART);
343+
}
344+
340345
static void reset_cpu_only ( void )
341346
{
342347
reset_mega65(RESET_MEGA65_CPU | RESET_MEGA65_ASK);
@@ -530,6 +535,7 @@ static void ui_emu_info ( void )
530535
"Hyppo version: %s (%s)\n"
531536
"HDOS virtualization: %s, root = %s\n"
532537
"Disk8 = %s\nDisk9 = %s\n"
538+
"Cartridge = %s\n"
533539
"C64 'CPU' I/O port (low 3 bits): DDR=%d OUT=%d\n"
534540
"Current PC: $%04X (linear: $%07X)\n"
535541
"Current VIC and I/O mode: %s %s, hot registers are %s\n"
@@ -544,6 +550,7 @@ static void ui_emu_info ( void )
544550
hyppo_version_string, hickup_is_overriden ? "OVERRIDEN" : "built-in",
545551
hdos_virt ? "ON" : "OFF", hdos_root,
546552
sdcard_get_mount_info(0, NULL), sdcard_get_mount_info(1, NULL),
553+
cart_get_fn(),
547554
memory_get_cpu_io_port(0) & 7, memory_get_cpu_io_port(1) & 7,
548555
cpu65.pc, memory_cpurd2linear_xlat(cpu65.pc),
549556
iomode_names[io_mode], videostd_name, (vic_registers[0x5D] & 0x80) ? "enabled" : "disabled",
@@ -891,6 +898,7 @@ static const struct menu_st menu_reset[] = {
891898
{ "Reset back to default ROM", XEMUGUI_MENUID_CALLABLE |
892899
XEMUGUI_MENUFLAG_QUERYBACK, ui_cb_use_default_rom, NULL },
893900
{ "Reset", XEMUGUI_MENUID_CALLABLE, xemugui_cb_call_user_data, reset_hard },
901+
{ "Reset + cartridge detach", XEMUGUI_MENUID_CALLABLE, xemugui_cb_call_user_data, reset_without_cartridge },
894902
{ "Reset without autoboot", XEMUGUI_MENUID_CALLABLE, xemugui_cb_call_user_data, reset_into_c65_mode_noboot },
895903
{ "Reset into utility menu", XEMUGUI_MENUID_CALLABLE, xemugui_cb_call_user_data, reset_into_utility_menu },
896904
{ "Reset into C64 mode", XEMUGUI_MENUID_CALLABLE, xemugui_cb_call_user_data, reset_into_c64_mode },

0 commit comments

Comments
 (0)