mirror of
https://github.com/wavemotion-dave/NINTV-DS.git
synced 2025-06-18 13:55:33 -04:00
337 lines
9.6 KiB
C++
337 lines
9.6 KiB
C++
|
|
#include "Intellivision.h"
|
|
|
|
TYPEDEF_STRUCT_PACK( _IntellivisionState
|
|
{
|
|
StateHeader header;
|
|
StateChunk cpu;
|
|
CP1610State cpuState;
|
|
StateChunk stic;
|
|
AY38900State sticState;
|
|
StateChunk psg;
|
|
AY38914State psgState;
|
|
StateChunk RAM8bit;
|
|
RAMState RAM8bitState;
|
|
UINT16 RAM8bitImage[RAM8BIT_SIZE];
|
|
StateChunk RAM16bit;
|
|
RAMState RAM16bitState;
|
|
UINT16 RAM16bitImage[RAM16BIT_SIZE];
|
|
StateChunk GRAM;
|
|
RAMState GRAMState;
|
|
UINT16 GRAMImage[GRAM_SIZE];
|
|
StateChunk ivoice;
|
|
IntellivoiceState ivoiceState;
|
|
StateChunk ecs;
|
|
ECSState ecsState;
|
|
StateChunk eof;
|
|
} IntellivisionState; )
|
|
|
|
/**
|
|
* Initializes all of the basic hardware included in the Intellivision
|
|
* Master Component as well as the ECS and Intellivoice peripherals.
|
|
* This method is called only once when the Intellivision is constructed.
|
|
*/
|
|
Intellivision::Intellivision()
|
|
: Emulator("Intellivision"),
|
|
player1Controller(0, "Hand Controller #1"),
|
|
player2Controller(1, "Hand Controller #2"),
|
|
psg(0x01F0, &player1Controller, &player2Controller),
|
|
RAM8bit(RAM8BIT_SIZE, 0x0100, 8),
|
|
RAM16bit(RAM16BIT_SIZE, 0x0200, 16),
|
|
execROM("Executive ROM", "exec.bin", 0, 2, 0x1000, 0x1000),
|
|
grom("GROM", "grom.bin", 0, 1, 0x0800, 0x3000),
|
|
gram(),
|
|
cpu(&memoryBus, 0x1000, 0x1004),
|
|
stic(&memoryBus, &grom, &gram)
|
|
{
|
|
// define the video pixel dimensions
|
|
videoWidth = 160;
|
|
videoHeight = 192;
|
|
|
|
//make the pin connections from the CPU to the STIC
|
|
stic.connectPinOut(AY38900_PIN_OUT_SR1, &cpu, CP1610_PIN_IN_INTRM);
|
|
stic.connectPinOut(AY38900_PIN_OUT_SR2, &cpu, CP1610_PIN_IN_BUSRQ);
|
|
cpu.connectPinOut(CP1610_PIN_OUT_BUSAK, &stic, AY38900_PIN_IN_SST);
|
|
|
|
//add the player one hand controller
|
|
AddInputConsumer(&player1Controller);
|
|
|
|
//add the player two hand controller
|
|
AddInputConsumer(&player2Controller);
|
|
|
|
//add the 8-bit RAM
|
|
AddRAM(&RAM8bit);
|
|
|
|
//add the 16-bit RAM
|
|
AddRAM(&RAM16bit);
|
|
|
|
//add the executive ROM
|
|
AddROM(&execROM);
|
|
|
|
//add the GROM
|
|
AddROM(&grom);
|
|
|
|
//add the GRAM
|
|
AddRAM(&gram);
|
|
|
|
//add the backtab ram
|
|
AddRAM(&stic.backtab);
|
|
|
|
//add the CPU
|
|
AddProcessor(&cpu);
|
|
|
|
//add the STIC
|
|
AddProcessor(&stic);
|
|
AddVideoProducer(&stic);
|
|
|
|
//add the STIC registers
|
|
AddRAM(&stic.registers);
|
|
|
|
//add the PSG
|
|
AddProcessor(&psg);
|
|
AddAudioProducer(&psg);
|
|
|
|
//add the PSG registers
|
|
AddRAM(&psg.registers);
|
|
|
|
AddPeripheral(&ecs);
|
|
AddPeripheral(&intellivoice);
|
|
}
|
|
|
|
BOOL Intellivision::SaveState(const CHAR* filename)
|
|
{
|
|
BOOL didSave = FALSE;
|
|
IntellivisionState state = {9};
|
|
size_t totalStateSize = sizeof(IntellivisionState);
|
|
|
|
size_t hsize = sizeof(StateHeader);
|
|
size_t csize = sizeof(StateChunk);
|
|
size_t cpusize = sizeof(CP1610State);
|
|
size_t sticsize = sizeof(AY38900State);
|
|
size_t psgsize = sizeof(AY38914State);
|
|
size_t ivoicesize = sizeof(IntellivoiceState);
|
|
size_t ecssize = sizeof(ECSState);
|
|
size_t ramsize = sizeof(RAMState);
|
|
size_t ram8imgsize = sizeof(state.RAM8bitImage);
|
|
size_t ram16imgsize = sizeof(state.RAM16bitImage);
|
|
size_t gramimgsize = sizeof(state.GRAMImage);
|
|
|
|
state.header.emu = FOURCHAR('EMUS');
|
|
state.header.state = FOURCHAR('TATE');
|
|
state.header.emuID = ID_EMULATOR_BLISS;
|
|
state.header.version = FOURCHAR(EMU_STATE_VERSION);
|
|
state.header.sys = FOURCHAR('SYS\0');
|
|
state.header.sysID = ID_SYSTEM_INTELLIVISION;
|
|
state.header.cart = FOURCHAR('CART');
|
|
state.header.cartID = currentRip->GetCRC();
|
|
|
|
state.cpu.id = FOURCHAR('CPU\0');
|
|
state.cpu.size = sizeof(CP1610State);
|
|
state.cpuState = cpu.getState();
|
|
|
|
state.stic.id = FOURCHAR('STIC');
|
|
state.stic.size = sizeof(AY38900State);
|
|
state.sticState = stic.getState();
|
|
|
|
state.psg.id = FOURCHAR('PSG\0');
|
|
state.psg.size = sizeof(AY38914State);
|
|
state.psgState = psg.getState();
|
|
|
|
state.RAM8bit.id = FOURCHAR('RAM0');
|
|
state.RAM8bit.size = sizeof(RAMState) + sizeof(state.RAM8bitImage);
|
|
state.RAM8bitState = RAM8bit.getState(state.RAM8bitImage);
|
|
|
|
state.RAM16bit.id = FOURCHAR('RAM1');
|
|
state.RAM16bit.size = sizeof(RAMState) + sizeof(state.RAM16bitImage);
|
|
state.RAM16bitState = RAM16bit.getState(state.RAM16bitImage);
|
|
|
|
state.GRAM.id = FOURCHAR('GRAM');
|
|
state.GRAM.size = sizeof(RAMState) + sizeof(state.GRAMImage);
|
|
state.GRAMState = gram.getState(state.GRAMImage);
|
|
|
|
// TODO: only if ivoice is used for this cart?
|
|
state.ivoice.id = FOURCHAR('VOIC');
|
|
state.ivoice.size = sizeof(IntellivoiceState);
|
|
state.ivoiceState = intellivoice.getState();
|
|
|
|
// TODO: only if ecs is used for this cart?
|
|
state.ecs.id = FOURCHAR('ECS\0');
|
|
state.ecs.size = sizeof(ECSState);
|
|
state.ecsState = ecs.getState();
|
|
|
|
state.eof.id = FOURCHAR('EOF\0');
|
|
state.eof.size = sizeof(IntellivisionState);
|
|
|
|
FILE* file = fopen(filename, "wb");
|
|
|
|
if (file == NULL) {
|
|
printf("Error: Unable to create file %s\n", filename);
|
|
didSave = FALSE;
|
|
}
|
|
|
|
if (file != NULL && totalStateSize == fwrite(&state, 1, totalStateSize, file)) {
|
|
didSave = TRUE;
|
|
} else {
|
|
printf("Error: could not write %zu bytes to file %s\n", totalStateSize, filename);
|
|
didSave = FALSE;
|
|
}
|
|
|
|
if (file) {
|
|
fclose(file);
|
|
file = NULL;
|
|
}
|
|
|
|
return didSave;
|
|
}
|
|
|
|
BOOL Intellivision::LoadState(const CHAR* filename)
|
|
{
|
|
BOOL didLoadState = FALSE;
|
|
IntellivisionState state = {9};
|
|
size_t totalStateSize = sizeof(IntellivisionState);
|
|
|
|
FILE* file = fopen(filename, "rb");
|
|
|
|
if (file == NULL) {
|
|
printf("Error: Unable to open file %s\n", filename);
|
|
return FALSE;
|
|
}
|
|
#if 0
|
|
// read in the whole file
|
|
if (totalStateSize != fread(&state, 1, totalStateSize, file)) {
|
|
printf("Error: could not read state (%zu bytes) from file %s\n", totalStateSize, filename);
|
|
goto close;
|
|
}
|
|
#else
|
|
BOOL isParsing = FALSE;
|
|
StateChunk chunk = {0};
|
|
|
|
// read in the header
|
|
if (sizeof(StateHeader) != fread(&state, 1, sizeof(StateHeader), file)) {
|
|
printf("Error: could not read state header (%zu bytes) from file %s\n", totalStateSize, filename);
|
|
goto close;
|
|
}
|
|
|
|
// validate file header
|
|
if (state.header.emu != FOURCHAR('EMUS') || state.header.state != FOURCHAR('TATE')) {
|
|
printf("Error: invalid header in file %s\n", filename);
|
|
goto close;
|
|
}
|
|
|
|
if (state.header.emuID != ID_EMULATOR_BLISS) {
|
|
printf("Error: invalid emulator ID %x in file %s\n", state.header.emuID, filename);
|
|
goto close;
|
|
}
|
|
|
|
if (FOURCHAR(EMU_STATE_VERSION) != FOURCHAR('dev\0') && state.header.version != FOURCHAR('dev\0') && state.header.version != FOURCHAR(EMU_STATE_VERSION)) {
|
|
printf("Error: invalid emulator version 0x%08x (expected 0x%08x) in file %s\n", state.header.version, EMU_STATE_VERSION, filename);
|
|
goto close;
|
|
}
|
|
|
|
if (state.header.sys != FOURCHAR('SYS\0')) {
|
|
printf("Error: expected 'SYS ' chunk in file %s\n", filename);
|
|
goto close;
|
|
}
|
|
|
|
if (state.header.sysID != ID_SYSTEM_INTELLIVISION) {
|
|
printf("Error: invalid system ID %x in file %s\n", state.header.sysID, filename);
|
|
goto close;
|
|
}
|
|
|
|
if (state.header.cart != FOURCHAR('CART')) {
|
|
printf("Error: expected 'CART' chunk in file %s\n", filename);
|
|
goto close;
|
|
}
|
|
|
|
if (state.header.cartID != 0x00000000 && state.header.cartID != currentRip->GetCRC()) {
|
|
printf("Error: cartridge mismatch in file %s\n", filename);
|
|
goto close;
|
|
}
|
|
|
|
isParsing = TRUE;
|
|
while (isParsing) {
|
|
size_t fpos = ftell(file);
|
|
if (sizeof(StateChunk) != fread(&chunk, 1, sizeof(StateChunk), file)) {
|
|
isParsing = FALSE;
|
|
break;
|
|
}
|
|
|
|
switch (chunk.id) {
|
|
default:
|
|
fpos = ftell(file);
|
|
break;
|
|
case FOURCHAR('CPU\0'):
|
|
if (chunk.size == sizeof(state.cpuState)) {
|
|
state.cpu = chunk;
|
|
fread(&state.cpuState, 1, state.cpu.size, file);
|
|
}
|
|
break;
|
|
case FOURCHAR('STIC'):
|
|
if (chunk.size == sizeof(state.sticState)) {
|
|
state.stic = chunk;
|
|
fread(&state.sticState, 1, state.stic.size, file);
|
|
}
|
|
break;
|
|
case FOURCHAR('PSG\0'):
|
|
if (chunk.size == sizeof(state.psgState)) {
|
|
state.psg = chunk;
|
|
fread(&state.psgState, 1, state.psg.size, file);
|
|
}
|
|
break;
|
|
case FOURCHAR('RAM0'):
|
|
if (chunk.size == sizeof(state.RAM8bitState) + sizeof(state.RAM8bitImage)) {
|
|
state.RAM8bit = chunk;
|
|
fread(&state.RAM8bitState, 1, state.RAM8bit.size, file);
|
|
}
|
|
break;
|
|
case FOURCHAR('RAM1'):
|
|
if (chunk.size == sizeof(state.RAM16bitState) + sizeof(state.RAM16bitImage)) {
|
|
state.RAM16bit = chunk;
|
|
fread(&state.RAM16bitState, 1, state.RAM16bit.size, file);
|
|
}
|
|
break;
|
|
case FOURCHAR('GRAM'):
|
|
if (chunk.size == sizeof(state.GRAMState) + sizeof(state.GRAMImage)) {
|
|
state.GRAM = chunk;
|
|
fread(&state.GRAMState, 1, state.GRAM.size, file);
|
|
}
|
|
break;
|
|
case FOURCHAR('VOIC'):
|
|
// TODO: only if ivoice/ecs is used for this cart?
|
|
if (chunk.size == sizeof(state.ivoiceState)) {
|
|
state.ivoice = chunk;
|
|
fread(&state.ivoiceState, 1, state.ivoice.size, file);
|
|
}
|
|
break;
|
|
case FOURCHAR('ECS\0'):
|
|
// TODO: only if ivoice/ecs is used for this cart?
|
|
if (chunk.size == sizeof(state.ecsState)) {
|
|
state.ecs = chunk;
|
|
fread(&state.ecsState, 1, state.ecs.size, file);
|
|
}
|
|
break;
|
|
case FOURCHAR('EOF\0'):
|
|
state.eof = chunk;
|
|
isParsing = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
didLoadState = TRUE;
|
|
|
|
cpu.setState(state.cpuState);
|
|
stic.setState(state.sticState);
|
|
psg.setState(state.psgState);
|
|
RAM8bit.setState(state.RAM8bitState, state.RAM8bitImage);
|
|
RAM16bit.setState(state.RAM16bitState, state.RAM16bitImage);
|
|
gram.setState(state.GRAMState, state.GRAMImage);
|
|
intellivoice.setState(state.ivoiceState);
|
|
ecs.setState(state.ecsState);
|
|
|
|
close:
|
|
fclose(file);
|
|
file = NULL;
|
|
end:
|
|
return didLoadState;
|
|
}
|