mirror of
https://github.com/libretro/blueMSX-libretro.git
synced 2024-11-27 10:40:23 +00:00
402 lines
10 KiB
C
Executable File
402 lines
10 KiB
C
Executable File
/*****************************************************************************
|
|
** $Source: /cygdrive/d/Private/_SVNROOT/bluemsx/blueMSX/Src/Board/SVI.c,v $
|
|
**
|
|
** $Revision: 1.64 $
|
|
**
|
|
** $Date: 2009-07-01 21:13:04 $
|
|
**
|
|
** More info: http://www.bluemsx.com
|
|
**
|
|
** Copyright (C) 2003-2006 Daniel Vik, Tomas Karlsson
|
|
**
|
|
** This program is free software; you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation; either version 2 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program; if not, write to the Free Software
|
|
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
**
|
|
******************************************************************************
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "SVI.h"
|
|
|
|
#include "R800.h"
|
|
#include "R800Dasm.h"
|
|
#include "R800SaveState.h"
|
|
#include "R800Debug.h"
|
|
|
|
#include "AY8910.h"
|
|
#include "SviPPI.h"
|
|
#include "DeviceManager.h"
|
|
#include "SaveState.h"
|
|
#include "Led.h"
|
|
#include "KeyClick.h"
|
|
#include "Casette.h"
|
|
#include "Disk.h"
|
|
#include "IoPort.h"
|
|
#include "MegaromCartridge.h"
|
|
#include "SlotManager.h"
|
|
#include "RomLoader.h"
|
|
#include "romMapperSvi80Col.h"
|
|
#include "SviJoyIo.h"
|
|
|
|
/* Hardware */
|
|
static AY8910* ay8910;
|
|
static AudioKeyClick* keyClick;
|
|
static R800* r800;
|
|
static SviJoyIo* joyIO;
|
|
static UInt8 KeyboardMap[16];
|
|
static UInt32 sviRamSize;
|
|
static UInt32 sviRamStart;
|
|
static UInt8* sviRam;
|
|
static UInt8 psgAYReg15;
|
|
static int svi328Col80Enabled;
|
|
static UInt8 lastJoystickValue;
|
|
|
|
extern void PatchZ80(void* ref, CpuRegs* cpu);
|
|
|
|
static void sviMemWrite(void* ref, UInt16 address, UInt8 value)
|
|
{
|
|
if ((svi328Col80Enabled && svi328Col80MemBankCtrlStatus()) && (address & 0xf800) == 0xf000)
|
|
{
|
|
svi328Col80MemWrite(address & 0xfff, value);
|
|
}
|
|
else
|
|
slotWrite(ref, address, value);
|
|
}
|
|
|
|
static UInt8 sviMemRead(void* ref, UInt16 address)
|
|
{
|
|
if ((svi328Col80Enabled && svi328Col80MemBankCtrlStatus()) && (address & 0xf800) == 0xf000)
|
|
return svi328Col80MemRead(address & 0xfff);
|
|
else
|
|
return slotRead(ref, address);
|
|
}
|
|
|
|
/*
|
|
SLOT 0 SLOT 1 SLOT 2 SLOT 3
|
|
FFFF +---------+---------+---------+---------+
|
|
| BANK 02 | BANK 12 | BANK 22 | BANK 32 | PAGE 3
|
|
| RAM |ROM CART | RAM | RAM |
|
|
8000 |00000000 |01010000 |10100000 |11110000 | PAGE 2
|
|
+---------+---------+---------+---------+
|
|
7FFF | BANK 01 | BANK 11 | BANK 21 | BANK 31 | PAGE 1
|
|
|ROM BASIC|ROM CART | RAM | RAM |
|
|
|00000000 |00000101 |00001010 |00001111 | PAGE 0
|
|
0000 +---------+---------+---------+---------+
|
|
*/
|
|
|
|
static void sviMemSetBank(UInt8 value)
|
|
{
|
|
UInt8 psreg;
|
|
int i;
|
|
psgAYReg15 = value;
|
|
|
|
// Default to bank 1 and 2
|
|
psreg = 0;
|
|
|
|
switch (~value & 0x14) {
|
|
case 4: // bk22
|
|
psreg = 0xa0;
|
|
break;
|
|
case 16: // bk32
|
|
psreg = 0xf0;
|
|
break;
|
|
}
|
|
|
|
switch (~value & 0x0B) {
|
|
case 1: // bk12 (cart)?
|
|
if ((~value & 0x80) || (~value & 0x40)) {
|
|
psreg = 0x50;
|
|
}
|
|
// bk11 (cart)
|
|
psreg |= 0x05;
|
|
break;
|
|
case 2: // bk21
|
|
psreg |= 0x0a;
|
|
break;
|
|
case 8: // bk31
|
|
psreg |= 0x0f;
|
|
break;
|
|
}
|
|
|
|
/* Map the SVI-328 bank to slot and page */
|
|
for (i = 0; i < 4; i++) {
|
|
slotSetRamSlot(i, psreg & 3);
|
|
psreg >>= 2;
|
|
}
|
|
}
|
|
|
|
/*
|
|
PSG Port A Input
|
|
Bit Name Description
|
|
1 FWD1 Joystick 1, Forward
|
|
2 BACK1 Joystick 1, Back
|
|
3 LEFT1 Joystick 1, Left
|
|
4 RIGHT1 Joystick 1, Right
|
|
5 FWD2 Joystick 2, Forward
|
|
6 BACK2 Joystick 2, Back
|
|
7 LEFT2 Joystick 2, Left
|
|
8 RIGHT2 Joystick 2, Right
|
|
|
|
PSG Port B Output
|
|
Bit Name Description
|
|
1 /CART Memory bank 11, ROM 0000-7FFF (Cartridge /CCS1, /CCS2)
|
|
2 /BK21 Memory bank 21, RAM 0000-7FFF
|
|
3 /BK22 Memory bank 22, RAM 8000-FFFF
|
|
4 /BK31 Memory bank 31, RAM 0000-7FFF
|
|
5 /BK32 Memory bank 32, RAM 8000-7FFF
|
|
6 CAPS Caps-Lock diod
|
|
7 /ROMEN0 Memory bank 12, ROM 8000-BFFF* (Cartridge /CCS3)
|
|
8 /ROMEN1 Memory bank 12, ROM C000-FFFF* (Cartridge /CCS4)
|
|
|
|
* The /CART signal must be active for any effect,
|
|
then all banks of RAM are disabled. */
|
|
|
|
static UInt8 sviPsgReadHandler(void* arg, UInt16 address)
|
|
{
|
|
UInt8 value = 0xff;
|
|
|
|
switch (address) {
|
|
case 0:
|
|
value = boardCaptureUInt8(17, sviJoyIoRead(joyIO));
|
|
lastJoystickValue = value;
|
|
break;
|
|
case 1:
|
|
value = psgAYReg15;
|
|
break;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
static UInt8 sviPsgPollHandler(void* arg, UInt16 address)
|
|
{
|
|
UInt8 value = 0xff;
|
|
|
|
switch (address) {
|
|
case 0:
|
|
value = lastJoystickValue;
|
|
break;
|
|
case 1:
|
|
value = psgAYReg15;
|
|
break;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
static void sviPsgWriteHandler(void* arg, UInt16 address, UInt8 value)
|
|
{
|
|
switch (address) {
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
ledSetCapslock(value & 0x20 ? 1 : 0);
|
|
if ((psgAYReg15 & 0xDF) != (value & 0xDF))
|
|
sviMemSetBank(value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int sviLoad80Col(Machine* machine, VdpSyncMode vdpSyncMode)
|
|
{
|
|
// The 80 column cart has a memory mapping that doesn't fit
|
|
// the blueMSX memory management yet, so it needs special
|
|
// handling. When supported this should be moved to Machine.c
|
|
|
|
int success = 1;
|
|
int i;
|
|
|
|
for (i = 0; i < machine->slotInfoCount; i++) {
|
|
if (!machine->slotInfo[i].error) {
|
|
int size;
|
|
UInt8* buf = romLoad(machine->slotInfo[i].name, machine->slotInfo[i].inZipName, &size);
|
|
|
|
if (buf != NULL) {
|
|
if (machine->slotInfo[i].romType == ROM_SVI328COL80) {
|
|
int frameRate = (vdpSyncMode == VDP_SYNC_60HZ) ? 60 : 50;
|
|
svi328Col80Enabled = romMapperSvi328Col80Create(frameRate, buf, size);
|
|
success &= svi328Col80Enabled;
|
|
}
|
|
free(buf);
|
|
}
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
static void reset()
|
|
{
|
|
UInt32 systemTime = boardSystemTime();
|
|
|
|
slotManagerReset();
|
|
|
|
if (r800 != NULL) {
|
|
r800Reset(r800, systemTime);
|
|
}
|
|
if (ay8910 != NULL) {
|
|
ay8910Reset(ay8910);
|
|
}
|
|
|
|
sviMemSetBank(0xDF);
|
|
|
|
ledSetCapslock(0);
|
|
|
|
deviceManagerReset();
|
|
}
|
|
|
|
static void destroy()
|
|
{
|
|
boardRemoveExternalDevices();
|
|
ay8910SetIoPort(ay8910, NULL, NULL, NULL, NULL);
|
|
ay8910Destroy(ay8910);
|
|
ay8910 = NULL;
|
|
audioKeyClickDestroy(keyClick);
|
|
r800DebugDestroy();
|
|
slotManagerDestroy();
|
|
deviceManagerDestroy();
|
|
r800Destroy(r800);
|
|
}
|
|
|
|
static int getRefreshRate()
|
|
{
|
|
return vdpGetRefreshRate();
|
|
}
|
|
|
|
static UInt32 getTimeTrace(int offset) {
|
|
return r800GetTimeTrace(r800, offset);
|
|
}
|
|
|
|
static void saveState()
|
|
{
|
|
SaveState* state = saveStateOpenForWrite("svi");
|
|
|
|
saveStateSet(state, "svi328Col80Enabled", svi328Col80Enabled);
|
|
saveStateSet(state, "psgAYReg15", psgAYReg15);
|
|
|
|
saveStateClose(state);
|
|
|
|
r800SaveState(r800);
|
|
deviceManagerSaveState();
|
|
slotSaveState();
|
|
ay8910SaveState(ay8910);
|
|
}
|
|
|
|
static void loadState()
|
|
{
|
|
SaveState* state = saveStateOpenForRead("svi");
|
|
|
|
svi328Col80Enabled = saveStateGet(state, "svi328Col80Enabled", 0);
|
|
psgAYReg15 = (UInt8)saveStateGet(state, "psgAYReg15", 0);
|
|
|
|
saveStateClose(state);
|
|
|
|
r800LoadState(r800);
|
|
boardInit(&r800->systemTime);
|
|
deviceManagerLoadState();
|
|
slotLoadState();
|
|
ay8910LoadState(ay8910);
|
|
}
|
|
|
|
int sviCreate(Machine* machine,
|
|
VdpSyncMode vdpSyncMode,
|
|
BoardInfo* boardInfo)
|
|
{
|
|
int success;
|
|
int i;
|
|
|
|
r800 = r800Create(CPU_ENABLE_M1, sviMemRead, sviMemWrite, ioPortRead, ioPortWrite, PatchZ80, boardTimerCheckTimeout, NULL, NULL, NULL, NULL, NULL, NULL);
|
|
|
|
boardInfo->cartridgeCount = 1;
|
|
boardInfo->diskdriveCount = 2;
|
|
boardInfo->casetteCount = 1;
|
|
boardInfo->cpuRef = r800;
|
|
|
|
boardInfo->destroy = destroy;
|
|
boardInfo->softReset = reset;
|
|
boardInfo->loadState = loadState;
|
|
boardInfo->saveState = saveState;
|
|
boardInfo->getRefreshRate = getRefreshRate;
|
|
boardInfo->getRamPage = NULL;
|
|
|
|
boardInfo->run = r800Execute;
|
|
boardInfo->stop = r800StopExecution;
|
|
boardInfo->setInt = r800SetInt;
|
|
boardInfo->clearInt = r800ClearInt;
|
|
boardInfo->setCpuTimeout = r800SetTimeoutAt;
|
|
boardInfo->setBreakpoint = r800SetBreakpoint;
|
|
boardInfo->clearBreakpoint = r800ClearBreakpoint;
|
|
boardInfo->setDataBus = r800SetDataBus;
|
|
|
|
boardInfo->getTimeTrace = getTimeTrace;
|
|
|
|
deviceManagerCreate();
|
|
boardInit(&r800->systemTime);
|
|
ioPortReset();
|
|
r800Reset(r800, 0);
|
|
mixerReset(boardGetMixer());
|
|
|
|
r800DebugCreate(r800);
|
|
|
|
ay8910 = ay8910Create(boardGetMixer(), AY8910_SVI, PSGTYPE_AY8910, 0, machine->audio.psgpan);
|
|
ay8910SetIoPort(ay8910, sviPsgReadHandler, sviPsgPollHandler, sviPsgWriteHandler, NULL);
|
|
|
|
keyClick = audioKeyClickCreate(boardGetMixer());
|
|
|
|
joyIO = sviJoyIoCreate();
|
|
|
|
sviPPICreate(joyIO);
|
|
slotManagerCreate();
|
|
|
|
svi328Col80Enabled = 0;
|
|
|
|
/* Initialize VDP */
|
|
vdpCreate(VDP_SVI, machine->video.vdpVersion, vdpSyncMode, machine->video.vramSize / 0x4000);
|
|
|
|
/* Initialize memory */
|
|
for (i = 0; i < 4; i++) {
|
|
slotSetSubslotted(i, 0);
|
|
}
|
|
for (i = 0; i < 2; i++) {
|
|
cartridgeSetSlotInfo(i, machine->cart[i].slot, 0);
|
|
}
|
|
|
|
success = machineInitialize(machine, &sviRam, &sviRamSize, &sviRamStart);
|
|
success &= sviLoad80Col(machine, vdpSyncMode);
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
slotMapRamPage(0, 0, i);
|
|
}
|
|
|
|
sviMemSetBank(0xDF);
|
|
ledSetCapslock(0);
|
|
|
|
if (success) {
|
|
success = boardInsertExternalDevices();
|
|
}
|
|
|
|
memset(KeyboardMap, 0xff, 16);
|
|
|
|
r800SetFrequency(r800, CPU_Z80, machine->cpu.freqZ80);
|
|
r800SetFrequency(r800, CPU_R800, machine->cpu.freqR800);
|
|
|
|
diskEnable(0, machine->fdc.count > 0);
|
|
diskEnable(1, machine->fdc.count > 1);
|
|
|
|
if (!success) {
|
|
destroy();
|
|
}
|
|
|
|
return success;
|
|
}
|