347 lines
7.7 KiB
C++
347 lines
7.7 KiB
C++
//
|
|
// JERRY Core
|
|
//
|
|
// Originally by David Raingeard
|
|
// GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Carwin Jones (BeOS)
|
|
// Cleanups/rewrites/fixes by James Hammons
|
|
//
|
|
// JLH = James Hammons <jlhamm@acm.org>
|
|
//
|
|
// WHO WHEN WHAT
|
|
// --- ---------- -----------------------------------------------------------
|
|
// JLH 11/25/2009 Major rewrite of memory subsystem and handlers
|
|
//
|
|
|
|
#include "jerry.h"
|
|
|
|
#include <string.h>
|
|
#include "cdrom.h"
|
|
#include "dac.h"
|
|
#include "dsp.h"
|
|
#include "eeprom.h"
|
|
#include "event.h"
|
|
#include "jaguar.h"
|
|
#include "joystick.h"
|
|
#include "m68000/m68kinterface.h"
|
|
#include "memtrack.h"
|
|
#include "settings.h"
|
|
#include "tom.h"
|
|
#include "wavetable.h"
|
|
#include "cdhle.h"
|
|
|
|
uint8_t jerry_ram_8[0x10000];
|
|
|
|
// JERRY Registers (write, offset from $F10000)
|
|
#define JPIT1 0x00
|
|
#define JPIT2 0x02
|
|
#define JPIT3 0x04
|
|
#define JPIT4 0x08
|
|
#define CLK1 0x10
|
|
#define CLK2 0x12
|
|
#define CLK3 0x14
|
|
#define JINTCTRL 0x20
|
|
#define ASIDATA 0x30
|
|
#define ASICTRL 0x32
|
|
#define ASICLK 0x34
|
|
#define SCLK 0xA150
|
|
#define SMODE 0xA154
|
|
|
|
static uint32_t JERRYPIT1Prescaler;
|
|
static uint32_t JERRYPIT1Divider;
|
|
static uint32_t JERRYPIT2Prescaler;
|
|
static uint32_t JERRYPIT2Divider;
|
|
static int32_t jerry_timer_1_counter;
|
|
static int32_t jerry_timer_2_counter;
|
|
|
|
int32_t JERRYI2SInterruptTimer = -1;
|
|
static uint32_t jerryI2SCycles;
|
|
|
|
static uint16_t jerryInterruptMask = 0;
|
|
static uint16_t jerryPendingInterrupt = 0;
|
|
|
|
static void JERRYResetPIT1(void);
|
|
static void JERRYResetPIT2(void);
|
|
static void JERRYResetI2S(void);
|
|
|
|
static void JERRYPIT1Callback(void);
|
|
static void JERRYPIT2Callback(void);
|
|
|
|
void JERRYResetI2S(void)
|
|
{
|
|
sclk = 8;
|
|
JERRYI2SInterruptTimer = -1;
|
|
}
|
|
|
|
void JERRYResetPIT1(void)
|
|
{
|
|
RemoveCallback(JERRYPIT1Callback);
|
|
|
|
if (JERRYPIT1Prescaler | JERRYPIT1Divider)
|
|
{
|
|
double usecs = (float)(JERRYPIT1Prescaler + 1) * (float)(JERRYPIT1Divider + 1) * RISC_CYCLE_IN_USEC;
|
|
SetCallbackTime(JERRYPIT1Callback, usecs);
|
|
}
|
|
}
|
|
|
|
void JERRYResetPIT2(void)
|
|
{
|
|
RemoveCallback(JERRYPIT2Callback);
|
|
|
|
if (JERRYPIT1Prescaler | JERRYPIT1Divider)
|
|
{
|
|
double usecs = (float)(JERRYPIT2Prescaler + 1) * (float)(JERRYPIT2Divider + 1) * RISC_CYCLE_IN_USEC;
|
|
SetCallbackTime(JERRYPIT2Callback, usecs);
|
|
}
|
|
}
|
|
|
|
void JERRYPIT1Callback(void)
|
|
{
|
|
if (TOMIRQEnabled(IRQ_DSP))
|
|
{
|
|
if (jerryInterruptMask & IRQ2_TIMER1)
|
|
{
|
|
jerryPendingInterrupt |= IRQ2_TIMER1;
|
|
m68k_set_irq(2);
|
|
}
|
|
}
|
|
|
|
DSPSetIRQLine(DSPIRQ_TIMER0, ASSERT_LINE);
|
|
JERRYResetPIT1();
|
|
}
|
|
|
|
void JERRYPIT2Callback(void)
|
|
{
|
|
if (TOMIRQEnabled(IRQ_DSP))
|
|
{
|
|
if (jerryInterruptMask & IRQ2_TIMER2)
|
|
{
|
|
jerryPendingInterrupt |= IRQ2_TIMER2;
|
|
m68k_set_irq(2);
|
|
}
|
|
}
|
|
|
|
DSPSetIRQLine(DSPIRQ_TIMER1, ASSERT_LINE);
|
|
JERRYResetPIT2();
|
|
}
|
|
|
|
void JERRYI2SCallback(void)
|
|
{
|
|
jerryI2SCycles = 32 * (2 * (sclk + 1));
|
|
|
|
if (smode & SMODE_INTERNAL)
|
|
{
|
|
DSPSetIRQLine(DSPIRQ_SSI, ASSERT_LINE);
|
|
double usecs = (float)jerryI2SCycles * (vjs.hardwareTypeNTSC ? RISC_CYCLE_IN_USEC : RISC_CYCLE_PAL_IN_USEC);
|
|
SetCallbackTime(JERRYI2SCallback, usecs);
|
|
}
|
|
else
|
|
{
|
|
if (CDHLEJerryCallback())
|
|
{
|
|
DSPSetIRQLine(DSPIRQ_SSI, ASSERT_LINE);
|
|
}
|
|
SetCallbackTime(JERRYI2SCallback, 22.675737);
|
|
}
|
|
}
|
|
|
|
void JERRYInit(void)
|
|
{
|
|
JoystickInit();
|
|
MTInit();
|
|
memcpy(&jerry_ram_8[0xD000], waveTableROM, 0x1000);
|
|
|
|
JERRYPIT1Prescaler = 0xFFFF;
|
|
JERRYPIT2Prescaler = 0xFFFF;
|
|
JERRYPIT1Divider = 0xFFFF;
|
|
JERRYPIT2Divider = 0xFFFF;
|
|
jerryInterruptMask = 0x0000;
|
|
jerryPendingInterrupt = 0x0000;
|
|
|
|
DACInit();
|
|
}
|
|
|
|
void JERRYReset(void)
|
|
{
|
|
JoystickReset();
|
|
EepromReset();
|
|
MTReset();
|
|
JERRYResetI2S();
|
|
|
|
memset(jerry_ram_8, 0x00, 0xD000);
|
|
JERRYPIT1Prescaler = 0xFFFF;
|
|
JERRYPIT2Prescaler = 0xFFFF;
|
|
JERRYPIT1Divider = 0xFFFF;
|
|
JERRYPIT2Divider = 0xFFFF;
|
|
jerry_timer_1_counter = 0;
|
|
jerry_timer_2_counter = 0;
|
|
jerryInterruptMask = 0x0000;
|
|
jerryPendingInterrupt = 0x0000;
|
|
|
|
DACReset();
|
|
}
|
|
|
|
bool JERRYIRQEnabled(int irq)
|
|
{
|
|
return jerryInterruptMask & irq;
|
|
}
|
|
|
|
void JERRYSetPendingIRQ(int irq)
|
|
{
|
|
jerryPendingInterrupt |= irq;
|
|
}
|
|
|
|
//
|
|
// JERRY byte access (read)
|
|
//
|
|
uint8_t JERRYReadByte(uint32_t offset, uint32_t who)
|
|
{
|
|
if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
|
|
return DSPReadByte(offset, who);
|
|
else if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
|
|
return DSPReadByte(offset, who);
|
|
else if (offset >= 0xF1A148 && offset <= 0xF1A153)
|
|
return DACReadByte(offset, who);
|
|
else if (offset >= 0xF14000 && offset <= 0xF14003)
|
|
{
|
|
uint16_t value = JoystickReadWord(offset & 0xFE);
|
|
|
|
if (offset & 0x01)
|
|
value &= 0xFF;
|
|
else
|
|
value >>= 8;
|
|
|
|
return value | EepromReadByte(offset);
|
|
}
|
|
else if (offset >= 0xF14000 && offset <= 0xF1A0FF)
|
|
return EepromReadByte(offset);
|
|
|
|
return jerry_ram_8[offset & 0xFFFF];
|
|
}
|
|
|
|
//
|
|
// JERRY word access (read)
|
|
//
|
|
uint16_t JERRYReadWord(uint32_t offset, uint32_t who)
|
|
{
|
|
if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
|
|
return DSPReadWord(offset, who);
|
|
else if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
|
|
return DSPReadWord(offset, who);
|
|
else if (offset >= 0xF1A148 && offset <= 0xF1A153)
|
|
return DACReadWord(offset, who);
|
|
else if (offset == 0xF10020)
|
|
return jerryPendingInterrupt;
|
|
else if (offset == 0xF14000)
|
|
return (JoystickReadWord(offset) & 0xFFFE) | EepromReadWord(offset);
|
|
else if ((offset >= 0xF14002) && (offset < 0xF14003))
|
|
return JoystickReadWord(offset);
|
|
else if ((offset >= 0xF14000) && (offset <= 0xF1A0FF))
|
|
return EepromReadWord(offset);
|
|
|
|
offset &= 0xFFFF;
|
|
return ((uint16_t)jerry_ram_8[offset+0] << 8) | jerry_ram_8[offset+1];
|
|
}
|
|
|
|
//
|
|
// JERRY byte access (write)
|
|
//
|
|
void JERRYWriteByte(uint32_t offset, uint8_t data, uint32_t who)
|
|
{
|
|
if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE + 0x20))
|
|
{
|
|
DSPWriteByte(offset, data, who);
|
|
}
|
|
else if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE + 0x2000))
|
|
{
|
|
DSPWriteByte(offset, data, who);
|
|
}
|
|
else if (offset >= 0xF1A148 && offset <= 0xF1A157)
|
|
{
|
|
DACWriteByte(offset, data, who);
|
|
}
|
|
else if (offset >= 0xF10020 && offset <= 0xF10021)
|
|
{
|
|
if (offset == 0xF10020)
|
|
{
|
|
jerryPendingInterrupt &= ~data;
|
|
}
|
|
else if (offset == 0xF10021)
|
|
jerryInterruptMask = data;
|
|
}
|
|
else if ((offset >= 0xF14000) && (offset <= 0xF14003))
|
|
{
|
|
JoystickWriteWord(offset & 0xFE, (uint16_t)data);
|
|
EepromWriteByte(offset, data);
|
|
}
|
|
else if ((offset >= 0xF14000) && (offset <= 0xF1A0FF))
|
|
{
|
|
EepromWriteByte(offset, data);
|
|
}
|
|
|
|
if (offset >= 0xF1D000 && offset <= 0xF1DFFF)
|
|
return;
|
|
|
|
jerry_ram_8[offset & 0xFFFF] = data;
|
|
}
|
|
|
|
//
|
|
// JERRY word access (write)
|
|
//
|
|
void JERRYWriteWord(uint32_t offset, uint16_t data, uint32_t who)
|
|
{
|
|
if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE + 0x20))
|
|
{
|
|
DSPWriteWord(offset, data, who);
|
|
}
|
|
else if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE + 0x2000))
|
|
{
|
|
DSPWriteWord(offset, data, who);
|
|
}
|
|
else if (offset >= 0xF1A148 && offset <= 0xF1A156)
|
|
{
|
|
DACWriteWord(offset, data, who);
|
|
}
|
|
else if (offset >= 0xF10000 && offset <= 0xF10007)
|
|
{
|
|
switch(offset & 0x07)
|
|
{
|
|
case 0:
|
|
JERRYPIT1Prescaler = data;
|
|
JERRYResetPIT1();
|
|
break;
|
|
case 2:
|
|
JERRYPIT1Divider = data;
|
|
JERRYResetPIT1();
|
|
break;
|
|
case 4:
|
|
JERRYPIT2Prescaler = data;
|
|
JERRYResetPIT2();
|
|
break;
|
|
case 6:
|
|
JERRYPIT2Divider = data;
|
|
JERRYResetPIT2();
|
|
break;
|
|
}
|
|
}
|
|
else if (offset >= 0xF10020 && offset <= 0xF10022)
|
|
{
|
|
jerryInterruptMask = data & 0xFF;
|
|
jerryPendingInterrupt &= ~(data >> 8);
|
|
}
|
|
else if (offset >= 0xF14000 && offset < 0xF14003)
|
|
{
|
|
JoystickWriteWord(offset, data);
|
|
EepromWriteWord(offset, data);
|
|
}
|
|
else if (offset >= 0xF14000 && offset <= 0xF1A0FF)
|
|
{
|
|
EepromWriteWord(offset, data);
|
|
}
|
|
|
|
if (offset >= 0xF1D000 && offset <= 0xF1DFFF)
|
|
return;
|
|
|
|
jerry_ram_8[(offset+0) & 0xFFFF] = (data >> 8) & 0xFF;
|
|
jerry_ram_8[(offset+1) & 0xFFFF] = data & 0xFF;
|
|
}
|