Files
86Box/src/device/cartridge.c
OBattler cd3f29f622 Part 2.
2024-08-27 03:29:37 +02:00

196 lines
4.7 KiB
C

/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Implementation of the PCjr cartridge emulation.
*
*
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2021 Miran Grca.
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/timer.h>
#include <86box/plat.h>
#include <86box/ui.h>
#include <86box/mem.h>
#include <86box/machine.h>
#include <86box/cartridge.h>
typedef struct cart_t {
uint8_t *buf;
uint32_t base;
} cart_t;
char cart_fns[2][512];
char *cart_image_history[2][CART_IMAGE_HISTORY];
static cart_t carts[2];
static mem_mapping_t cart_mappings[2];
#ifdef ENABLE_CARTRIDGE_LOG
int cartridge_do_log = ENABLE_CARTRIDGE_LOG;
static void
cartridge_log(const char *fmt, ...)
{
va_list ap;
if (cartridge_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define cartridge_log(fmt, ...)
#endif
static uint8_t
cart_read(uint32_t addr, void *priv)
{
const cart_t *dev = (cart_t *) priv;
return dev->buf[addr - dev->base];
}
static void
cart_load_error(int drive, UNUSED(char *fn))
{
cartridge_log("Cartridge: could not load '%s'\n", fn);
memset(cart_fns[drive], 0, sizeof(cart_fns[drive]));
ui_sb_update_icon_state(SB_CARTRIDGE | drive, 1);
}
static void
cart_image_close(int drive)
{
if (carts[drive].buf != NULL) {
free(carts[drive].buf);
carts[drive].buf = NULL;
}
carts[drive].base = 0x00000000;
mem_mapping_disable(&cart_mappings[drive]);
}
static void
cart_image_load(int drive, char *fn)
{
FILE *fp;
uint32_t size;
uint32_t base = 0x00000000;
cart_image_close(drive);
fp = fopen(fn, "rb");
if (fseek(fp, 0, SEEK_END) == -1)
fatal("cart_image_load(): Error seeking to the end of the file\n");
size = ftell(fp);
if (size < 0x1200) {
cartridge_log("cart_image_load(): File size %i is too small\n", size);
cart_load_error(drive, fn);
return;
}
if (size & 0x00000fff) {
size -= 0x00000200;
fseek(fp, 0x000001ce, SEEK_SET);
(void) !fread(&base, 1, 2, fp);
base <<= 4;
fseek(fp, 0x00000200, SEEK_SET);
carts[drive].buf = (uint8_t *) malloc(size);
memset(carts[drive].buf, 0x00, size);
(void) !fread(carts[drive].buf, 1, size, fp);
fclose(fp);
} else {
base = drive ? 0xe0000 : 0xd0000;
if (size == 32768)
base += 0x8000;
fseek(fp, 0x00000000, SEEK_SET);
carts[drive].buf = (uint8_t *) malloc(size);
memset(carts[drive].buf, 0x00, size);
(void) !fread(carts[drive].buf, 1, size, fp);
fclose(fp);
}
cartridge_log("cart_image_load(): %s at %08X-%08X\n", fn, base, base + size - 1);
carts[drive].base = base;
mem_mapping_set_addr(&cart_mappings[drive], base, size);
mem_mapping_set_exec(&cart_mappings[drive], carts[drive].buf);
mem_mapping_set_p(&cart_mappings[drive], &(carts[drive]));
}
static void
cart_load_common(int drive, char *fn, uint8_t hard_reset)
{
FILE *fp;
cartridge_log("Cartridge: loading drive %d with '%s'\n", drive, fn);
if (!fn)
return;
fp = plat_fopen(fn, "rb");
if (fp) {
fclose(fp);
strcpy(cart_fns[drive], fn);
cart_image_load(drive, cart_fns[drive]);
/* On the real PCjr, inserting a cartridge causes a reset
in order to boot from the cartridge. */
if (!hard_reset)
resetx86();
} else
cart_load_error(drive, fn);
}
void
cart_load(int drive, char *fn)
{
cart_load_common(drive, fn, 0);
}
void
cart_close(int drive)
{
cartridge_log("Cartridge: closing drive %d\n", drive);
cart_image_close(drive);
cart_fns[drive][0] = 0;
ui_sb_update_icon_state(SB_CARTRIDGE | drive, 1);
resetx86();
}
void
cart_reset(void)
{
cart_image_close(1);
cart_image_close(0);
if (!machine_has_cartridge(machine))
return;
for (uint8_t i = 0; i < 2; i++) {
mem_mapping_add(&cart_mappings[i], 0x000d0000, 0x00002000,
cart_read, NULL, NULL,
NULL, NULL, NULL,
NULL, MEM_MAPPING_EXTERNAL, NULL);
mem_mapping_disable(&cart_mappings[i]);
}
cart_load_common(0, cart_fns[0], 1);
cart_load_common(1, cart_fns[1], 1);
}