Added IBM PCjr cartridge support.
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
# Copyright 2020,2021 David Hrdlička.
|
||||
#
|
||||
|
||||
add_library(dev OBJECT bugger.c cassette.c hasp.c hwm.c hwm_lm75.c hwm_lm78.c hwm_gl518sm.c
|
||||
add_library(dev OBJECT bugger.c cassette.c cartridge.c hasp.c hwm.c hwm_lm75.c hwm_lm78.c hwm_gl518sm.c
|
||||
hwm_vt82c686.c ibm_5161.c isamem.c isartc.c ../lpt.c pci_bridge.c
|
||||
postcard.c serial.c vpc2007.c clock_ics9xxx.c isapnp.c i2c.c i2c_gpio.c
|
||||
smbus_piix4.c keyboard.c keyboard_xt.c keyboard_at.c mouse.c mouse_bus.c
|
||||
|
||||
208
src/device/cartridge.c
Normal file
208
src/device/cartridge.c
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
uint8_t * buf;
|
||||
uint32_t base;
|
||||
} cart_t;
|
||||
|
||||
|
||||
char cart_fns[2][512];
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
cart_t *dev = (cart_t *) priv;
|
||||
|
||||
return dev->buf[addr - dev->base];
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cart_load_error(int drive, 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 *f;
|
||||
uint32_t size;
|
||||
uint32_t base = 0x00000000;
|
||||
|
||||
cart_image_close(drive);
|
||||
|
||||
f = fopen(fn, "rb");
|
||||
if (fseek(f, 0, SEEK_END) == -1)
|
||||
fatal("cart_image_load(): Error seeking to the end of the file\n");
|
||||
size = ftell(f);
|
||||
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(f, 0x000001ce, SEEK_SET);
|
||||
fread(&base, 1, 2, f);
|
||||
base <<= 4;
|
||||
fseek(f, 0x00000200, SEEK_SET);
|
||||
carts[drive].buf = (uint8_t *) malloc(size);
|
||||
memset(carts[drive].buf, 0x00, size);
|
||||
fread(carts[drive].buf, 1, size, f);
|
||||
fclose(f);
|
||||
} else {
|
||||
base = drive ? 0xe0000 : 0xd0000;
|
||||
fseek(f, 0x00000000, SEEK_SET);
|
||||
carts[drive].buf = (uint8_t *) malloc(size);
|
||||
memset(carts[drive].buf, 0x00, size);
|
||||
fread(carts[drive].buf, 1, size, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
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 *f;
|
||||
|
||||
cartridge_log("Cartridge: loading drive %d with '%s'\n", drive, fn);
|
||||
|
||||
if (!fn)
|
||||
return;
|
||||
f = plat_fopen(fn, "rb");
|
||||
if (f) {
|
||||
fclose(f);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cart_reset(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
cart_image_close(1);
|
||||
cart_image_close(0);
|
||||
|
||||
if (!(machines[machine].flags & MACHINE_CARTRIDGE))
|
||||
return;
|
||||
|
||||
for (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);
|
||||
}
|
||||
Reference in New Issue
Block a user