mirror of https://github.com/bsnes-emu/bsnes.git
Update to bsnes v044 release.
This release adds full SA-1 support, with no known issues. All 26 games have been tested by myself and others, and a few have been beaten from start to finish. The latter include Super Mario RPG, Kirby's Dreamland 3, Kirby Super Star and Jikkyou Oshaberi Parodius. Please understand that the SA-1 is essentially four times faster than the SNES' main CPU, so system requirements will be very high for these games. For example, on an E8400 @ 3.0GHz, I average ~160fps in ordinary games. But for SA-1 emulation, this drops to ~90fps, with the worst case being ~80fps. The following features are emulated: - 5a22 CPU core (bus-cycle accurate) - Memory access timing - SA-1 -> S-CPU interrupts (IRQ + CHDMA IRQ) - S-CPU -> SA-1 interrupts (IRQ + Timer IRQ + DMA IRQ + NMI) - SIV / SNV interrupt vector selection - Timer unit (linear and H/V) - Super MMC unit (ROM + BW-RAM) - BS-X flash cart slot mapping - Normal DMA - Character-conversion 1 DMA (2bpp + 4bpp + 8bpp) - Character-conversion 2 DMA (2bpp + 4bpp + 8bpp) - BW-RAM virtual bitmap mode (2bpp + 4bpp) - Arithmetic unit (multiplication + division + cumulative sum) - Variable-length bit processing (fixed and auto increment) While the following features are not currently emulated, mostly due to lack of information: - SA-1 bus conflict delays - Write protection (BW-RAM + I-RAM) - SA-1 CPU priority for DMA transfers - DMA access timing
This commit is contained in:
parent
b0a8de0208
commit
44b5f1bf27
|
@ -1,4 +1,4 @@
|
|||
#define BSNES_VERSION "0.043"
|
||||
#define BSNES_VERSION "0.044"
|
||||
#define BSNES_TITLE "bsnes v" BSNES_VERSION
|
||||
|
||||
#define BUSCORE sBus
|
||||
|
@ -9,12 +9,7 @@
|
|||
|
||||
//S-DSP can be encapsulated into a state machine using #define magic
|
||||
//this avoids ~2.048m co_switch() calls per second (~5% speedup)
|
||||
#define USE_STATE_MACHINE
|
||||
|
||||
//FAST_FRAMESKIP disables calculation of RTO during frameskip
|
||||
//frameskip offers near-zero speedup if RTO is calculated
|
||||
//accuracy is not affected by this define when frameskipping is off
|
||||
#define FAST_FRAMESKIP
|
||||
#define DSP_STATE_MACHINE
|
||||
|
||||
//game genie + pro action replay code support (~2% speed hit)
|
||||
#define CHEAT_SYSTEM
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#make platform=x compiler=gcc
|
||||
make platform=x compiler=gcc enable_gzip=true enable_jma=true
|
||||
make platform=x compiler=gcc
|
||||
#make platform=x compiler=gcc enable_gzip=true enable_jma=true
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
#ifdef SA1_CPP
|
||||
|
||||
namespace memory {
|
||||
namespace cpu {
|
||||
CPUIRAM iram;
|
||||
CPUBWRAM bwram;
|
||||
}
|
||||
|
||||
namespace sa1 {
|
||||
SA1IRAM iram;
|
||||
SA1BWRAM bwram;
|
||||
SA1BitmapRAM bitmapram;
|
||||
}
|
||||
VectorSelectionPage vectorsp;
|
||||
StaticRAM iram(2048);
|
||||
MappedRAM &bwram = memory::cartram;
|
||||
CC1BWRAM cc1bwram;
|
||||
BitmapRAM bitmapram;
|
||||
}
|
||||
|
||||
void SA1Bus::init() {
|
||||
|
@ -22,124 +17,103 @@ void SA1Bus::init() {
|
|||
memory::mmio.map(i, sa1);
|
||||
}
|
||||
|
||||
map(MapLinear, 0x00, 0x3f, 0x0000, 0x07ff, memory::sa1::iram);
|
||||
map(MapLinear, 0x00, 0x3f, 0x0000, 0x07ff, memory::iram);
|
||||
map(MapDirect, 0x00, 0x3f, 0x2200, 0x23ff, memory::mmio);
|
||||
map(MapLinear, 0x00, 0x3f, 0x3000, 0x37ff, memory::sa1::iram);
|
||||
map(MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::sa1::bwram);
|
||||
map(MapLinear, 0x00, 0x3f, 0x3000, 0x37ff, memory::iram);
|
||||
map(MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::bwram);
|
||||
map(MapLinear, 0x00, 0x3f, 0x8000, 0xffff, memory::cartrom);
|
||||
map(MapLinear, 0x40, 0x4f, 0x0000, 0xffff, memory::sa1::bwram, 0, 0x040000);
|
||||
map(MapLinear, 0x60, 0x6f, 0x0000, 0xffff, memory::sa1::bitmapram);
|
||||
map(MapLinear, 0x80, 0xbf, 0x0000, 0x07ff, memory::sa1::iram);
|
||||
map(MapLinear, 0x40, 0x4f, 0x0000, 0xffff, memory::bwram);
|
||||
map(MapLinear, 0x60, 0x6f, 0x0000, 0xffff, memory::bitmapram);
|
||||
map(MapLinear, 0x80, 0xbf, 0x0000, 0x07ff, memory::iram);
|
||||
map(MapDirect, 0x80, 0xbf, 0x2200, 0x23ff, memory::mmio);
|
||||
map(MapLinear, 0x80, 0xbf, 0x3000, 0x37ff, memory::sa1::iram);
|
||||
map(MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::sa1::bwram);
|
||||
map(MapLinear, 0x80, 0xbf, 0x3000, 0x37ff, memory::iram);
|
||||
map(MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::bwram);
|
||||
map(MapLinear, 0x80, 0xbf, 0x8000, 0xffff, memory::cartrom);
|
||||
map(MapLinear, 0xc0, 0xff, 0x0000, 0xffff, memory::cartrom);
|
||||
|
||||
bus.map(MapLinear, 0x00, 0x3f, 0x3000, 0x37ff, memory::cpu::iram);
|
||||
bus.map(MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::cpu::bwram);
|
||||
bus.map(MapLinear, 0x00, 0x3f, 0x3000, 0x37ff, memory::iram);
|
||||
bus.map(MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::cc1bwram);
|
||||
bus.map(MapLinear, 0x00, 0x3f, 0x8000, 0xffff, memory::cartrom);
|
||||
bus.map(MapLinear, 0x40, 0x4f, 0x0000, 0xffff, memory::cpu::bwram, 0, 0x040000);
|
||||
bus.map(MapLinear, 0x80, 0xbf, 0x3000, 0x37ff, memory::cpu::iram);
|
||||
bus.map(MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::cpu::bwram);
|
||||
bus.map(MapLinear, 0x40, 0x4f, 0x0000, 0xffff, memory::cc1bwram);
|
||||
bus.map(MapLinear, 0x80, 0xbf, 0x3000, 0x37ff, memory::iram);
|
||||
bus.map(MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::cc1bwram);
|
||||
bus.map(MapLinear, 0x80, 0xbf, 0x8000, 0xffff, memory::cartrom);
|
||||
bus.map(MapLinear, 0xc0, 0xff, 0x0000, 0xffff, memory::cartrom);
|
||||
|
||||
memory::vectorsp.sync();
|
||||
}
|
||||
|
||||
//=======
|
||||
//CPUIRAM
|
||||
//=======
|
||||
//===================
|
||||
//VectorSelectionPage
|
||||
//===================
|
||||
|
||||
unsigned CPUIRAM::size() const {
|
||||
return sizeof(sa1.iram);
|
||||
//this class maps $00:[ff00-ffff] for the purpose of supporting:
|
||||
//$2209.d6 IVSW (S-CPU IRQ vector selection) (0 = cart, 1 = SA-1)
|
||||
//$2209.d4 NVSW (S-CPU NMI vector selection) (0 = cart, 1 = SA-1)
|
||||
//when set, vector addresses are over-ridden with SA-1 register settings:
|
||||
//SIV = S-CPU IRQ vector address override
|
||||
//SNV = S-CPU NMI vector address override
|
||||
//
|
||||
//$00:[ffea-ffeb|ffee-ffef] are special cased on read;
|
||||
//all other addresses return original mapped data.
|
||||
|
||||
uint8_t VectorSelectionPage::read(unsigned addr) {
|
||||
switch(0xff00 | (addr & 0xff)) {
|
||||
case 0xffea: case 0xffeb: {
|
||||
if(sa1.mmio.cpu_nvsw == true) return (sa1.mmio.snv >> ((addr & 1) << 3));
|
||||
} break;
|
||||
|
||||
case 0xffee: case 0xffef: {
|
||||
if(sa1.mmio.cpu_ivsw == true) return (sa1.mmio.siv >> ((addr & 1) << 3));
|
||||
} break;
|
||||
}
|
||||
|
||||
return access->read(addr);
|
||||
}
|
||||
|
||||
uint8_t CPUIRAM::read(unsigned addr) {
|
||||
return sa1.iram[addr];
|
||||
void VectorSelectionPage::write(unsigned addr, uint8_t data) {
|
||||
return access->write(addr, data);
|
||||
}
|
||||
|
||||
void CPUIRAM::write(unsigned addr, uint8_t data) {
|
||||
uint8_t wpbit = (addr >> 8) & 7;
|
||||
if(1 || sa1.mmio.siwp & wpbit) {
|
||||
//allow only when write-protection is disabled
|
||||
sa1.iram[addr] = data;
|
||||
//call this whenever bus is remapped.
|
||||
//note: S-CPU and SA-1 bus always share $00:[ff00-ffff] as cartridge ROM data;
|
||||
//the SA-1 MMC does not allow mapping these independently between processors.
|
||||
//this allows this class to be shared for both, caching only ones' access class.
|
||||
void VectorSelectionPage::sync() {
|
||||
if(bus.page[0x00ff00 >> 8].access != this) {
|
||||
//bus was re-mapped, hook access routine
|
||||
access = bus.page[0x00ff00 >> 8].access;
|
||||
bus.page[0x00ff00 >> 8].access = this;
|
||||
sa1bus.page[0x00ff00 >> 8].access = this;
|
||||
}
|
||||
}
|
||||
|
||||
//========
|
||||
//CPUBWRAM
|
||||
//CC1BWRAM
|
||||
//========
|
||||
|
||||
unsigned CPUBWRAM::size() const {
|
||||
unsigned CC1BWRAM::size() const {
|
||||
return memory::cartram.size();
|
||||
}
|
||||
|
||||
uint8_t CPUBWRAM::read(unsigned addr) {
|
||||
if(cc1dma) return sa1.dma_cc1_read(addr);
|
||||
uint8_t CC1BWRAM::read(unsigned addr) {
|
||||
if(dma) return sa1.dma_cc1_read(addr);
|
||||
return memory::cartram.read(addr);
|
||||
}
|
||||
|
||||
void CPUBWRAM::write(unsigned addr, uint8_t data) {
|
||||
if(sa1.mmio.swen == false) {
|
||||
//write-protection enabled
|
||||
unsigned limit = 0x100 << sa1.mmio.bwp;
|
||||
//if(addr < limit) return;
|
||||
}
|
||||
|
||||
void CC1BWRAM::write(unsigned addr, uint8_t data) {
|
||||
memory::cartram.write(addr, data);
|
||||
}
|
||||
|
||||
//=======
|
||||
//SA1IRAM
|
||||
//=======
|
||||
//=========
|
||||
//BitmapRAM
|
||||
//=========
|
||||
|
||||
unsigned SA1IRAM::size() const {
|
||||
return sizeof(sa1.iram);
|
||||
}
|
||||
|
||||
uint8_t SA1IRAM::read(unsigned addr) {
|
||||
return sa1.iram[addr];
|
||||
}
|
||||
|
||||
void SA1IRAM::write(unsigned addr, uint8_t data) {
|
||||
uint8_t wpbit = (addr >> 8) & 7;
|
||||
if(1 || sa1.mmio.ciwp & wpbit) {
|
||||
//allow only when write-protection is disabled
|
||||
sa1.iram[addr] = data;
|
||||
}
|
||||
}
|
||||
|
||||
//========
|
||||
//SA1BWRAM
|
||||
//========
|
||||
|
||||
unsigned SA1BWRAM::size() const {
|
||||
return memory::cartram.size();
|
||||
}
|
||||
|
||||
uint8_t SA1BWRAM::read(unsigned addr) {
|
||||
return memory::cartram.read(addr);
|
||||
}
|
||||
|
||||
void SA1BWRAM::write(unsigned addr, uint8_t data) {
|
||||
if(sa1.mmio.cwen == false) {
|
||||
//write-protection enabled
|
||||
unsigned limit = 0x100 << sa1.mmio.bwp;
|
||||
//if(addr < limit) return;
|
||||
}
|
||||
|
||||
memory::cartram.write(addr, data);
|
||||
}
|
||||
|
||||
//============
|
||||
//SA1BitmapRAM
|
||||
//============
|
||||
|
||||
unsigned SA1BitmapRAM::size() const {
|
||||
unsigned BitmapRAM::size() const {
|
||||
return 0x100000;
|
||||
}
|
||||
|
||||
uint8_t SA1BitmapRAM::read(unsigned addr) {
|
||||
uint8_t BitmapRAM::read(unsigned addr) {
|
||||
if(sa1.mmio.bbf == 0) {
|
||||
//4bpp
|
||||
unsigned shift = addr & 1;
|
||||
|
@ -161,7 +135,7 @@ uint8_t SA1BitmapRAM::read(unsigned addr) {
|
|||
}
|
||||
}
|
||||
|
||||
void SA1BitmapRAM::write(unsigned addr, uint8_t data) {
|
||||
void BitmapRAM::write(unsigned addr, uint8_t data) {
|
||||
if(sa1.mmio.bbf == 0) {
|
||||
//4bpp
|
||||
uint8_t shift = addr & 1;
|
||||
|
|
|
@ -1,49 +1,31 @@
|
|||
class SA1Bus : public Bus {
|
||||
public:
|
||||
struct SA1Bus : Bus {
|
||||
void init();
|
||||
};
|
||||
|
||||
struct CPUIRAM : Memory {
|
||||
unsigned size() const;
|
||||
uint8_t read(unsigned);
|
||||
void write(unsigned, uint8_t);
|
||||
struct VectorSelectionPage : Memory {
|
||||
alwaysinline uint8_t read(unsigned);
|
||||
alwaysinline void write(unsigned, uint8_t);
|
||||
void sync();
|
||||
Memory *access;
|
||||
};
|
||||
|
||||
struct CPUBWRAM : Memory {
|
||||
bool cc1dma;
|
||||
|
||||
struct CC1BWRAM : Memory {
|
||||
unsigned size() const;
|
||||
uint8_t read(unsigned);
|
||||
void write(unsigned, uint8_t);
|
||||
alwaysinline uint8_t read(unsigned);
|
||||
alwaysinline void write(unsigned, uint8_t);
|
||||
bool dma;
|
||||
};
|
||||
|
||||
struct SA1IRAM : Memory {
|
||||
struct BitmapRAM : Memory {
|
||||
unsigned size() const;
|
||||
uint8_t read(unsigned);
|
||||
void write(unsigned, uint8_t);
|
||||
};
|
||||
|
||||
struct SA1BWRAM : Memory {
|
||||
unsigned size() const;
|
||||
uint8_t read(unsigned);
|
||||
void write(unsigned, uint8_t);
|
||||
};
|
||||
|
||||
struct SA1BitmapRAM : Memory {
|
||||
unsigned size() const;
|
||||
uint8_t read(unsigned);
|
||||
void write(unsigned, uint8_t);
|
||||
alwaysinline uint8_t read(unsigned);
|
||||
alwaysinline void write(unsigned, uint8_t);
|
||||
};
|
||||
|
||||
namespace memory {
|
||||
namespace cpu {
|
||||
extern CPUIRAM iram;
|
||||
extern CPUBWRAM bwram;
|
||||
}
|
||||
|
||||
namespace sa1 {
|
||||
extern SA1IRAM iram;
|
||||
extern SA1BWRAM bwram;
|
||||
extern SA1BitmapRAM bitmapram;
|
||||
}
|
||||
extern VectorSelectionPage vectorsp;
|
||||
extern StaticRAM iram;
|
||||
extern MappedRAM &bwram;
|
||||
extern CC1BWRAM cc1bwram;
|
||||
extern BitmapRAM bitmapram;
|
||||
}
|
||||
|
|
|
@ -9,9 +9,8 @@ void SA1::dma_normal() {
|
|||
uint8_t data = regs.mdr;
|
||||
uint32_t dsa = mmio.dsa++;
|
||||
uint32_t dda = mmio.dda++;
|
||||
add_clocks(4);
|
||||
scheduler.sync_copcpu();
|
||||
|
||||
//source and destination cannot be the same
|
||||
if(mmio.sd == DMA::SourceBWRAM && mmio.dd == DMA::DestBWRAM) continue;
|
||||
if(mmio.sd == DMA::SourceIRAM && mmio.dd == DMA::DestIRAM ) continue;
|
||||
|
||||
|
@ -29,7 +28,7 @@ void SA1::dma_normal() {
|
|||
} break;
|
||||
|
||||
case DMA::SourceIRAM: {
|
||||
data = iram[dsa & 0x07ff];
|
||||
data = memory::iram.read(dsa & 0x07ff);
|
||||
} break;
|
||||
}
|
||||
|
||||
|
@ -41,25 +40,26 @@ void SA1::dma_normal() {
|
|||
} break;
|
||||
|
||||
case DMA::DestIRAM: {
|
||||
iram[dda & 0x07ff] = data;
|
||||
memory::iram.write(dda & 0x07ff, data);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
dma.mode = DMA::Inactive;
|
||||
mmio.dma_irqfl = true;
|
||||
if(mmio.dma_irqen) mmio.dma_irqcl = 0;
|
||||
}
|
||||
|
||||
//((byte & 6) << 3) + (byte & 1) explanation:
|
||||
//transforms a byte index (0-7) into a planar index:
|
||||
//result[] = { 0, 1, 16, 17, 32, 33, 48, 49 };
|
||||
//works for 2bpp, 4bpp and 8bpp modes
|
||||
|
||||
//===========================
|
||||
//type-1 character conversion
|
||||
//===========================
|
||||
|
||||
void SA1::dma_cc1() {
|
||||
memory::cpu::bwram.cc1dma = true;
|
||||
|
||||
dma.tile = 0;
|
||||
dma.mode = DMA::Inactive;
|
||||
memory::cc1bwram.dma = true;
|
||||
mmio.chdma_irqfl = true;
|
||||
if(mmio.chdma_irqen) {
|
||||
mmio.chdma_irqcl = 0;
|
||||
|
@ -75,7 +75,7 @@ uint8_t SA1::dma_cc1_read(unsigned addr) {
|
|||
//buffer next character to I-RAM
|
||||
unsigned bpp = 2 << (2 - mmio.dmacb);
|
||||
unsigned bpl = (8 << mmio.dmasize) >> mmio.dmacb;
|
||||
unsigned bwmask = memory::sa1::bwram.size() - 1;
|
||||
unsigned bwmask = memory::bwram.size() - 1;
|
||||
unsigned tile = ((addr - mmio.dsa) & bwmask) >> (6 - mmio.dmacb);
|
||||
unsigned ty = (tile >> mmio.dmasize);
|
||||
unsigned tx = tile & ((1 << mmio.dmasize) - 1);
|
||||
|
@ -83,8 +83,8 @@ uint8_t SA1::dma_cc1_read(unsigned addr) {
|
|||
|
||||
for(unsigned y = 0; y < 8; y++) {
|
||||
uint64_t data = 0;
|
||||
for(unsigned n = 0; n < bpp; n++) {
|
||||
data |= (uint64_t)memory::sa1::bwram.read((bwaddr + n) & bwmask) << (n << 3);
|
||||
for(unsigned byte = 0; byte < bpp; byte++) {
|
||||
data |= (uint64_t)memory::bwram.read((bwaddr + byte) & bwmask) << (byte << 3);
|
||||
}
|
||||
bwaddr += bpl;
|
||||
|
||||
|
@ -102,15 +102,14 @@ uint8_t SA1::dma_cc1_read(unsigned addr) {
|
|||
out[7] |= (data & 1) << (7 - x); data >>= 1;
|
||||
}
|
||||
|
||||
for(unsigned n = 0; n < bpp; n++) {
|
||||
static const unsigned index[] = { 0, 1, 16, 17, 32, 33, 48, 49 };
|
||||
unsigned p = mmio.dda + (y << 1) + index[n];
|
||||
iram[p & 0x07ff] = out[n];
|
||||
for(unsigned byte = 0; byte < bpp; byte++) {
|
||||
unsigned p = mmio.dda + (y << 1) + ((byte & 6) << 3) + (byte & 1);
|
||||
memory::iram.write(p & 0x07ff, out[byte]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return iram[(mmio.dda + (addr & charmask)) & 0x07ff];
|
||||
return memory::iram.read((mmio.dda + (addr & charmask)) & 0x07ff);
|
||||
}
|
||||
|
||||
//===========================
|
||||
|
@ -118,7 +117,7 @@ uint8_t SA1::dma_cc1_read(unsigned addr) {
|
|||
//===========================
|
||||
|
||||
void SA1::dma_cc2() {
|
||||
//select register file index (0-7 or 8-F)
|
||||
//select register file index (0-7 or 8-15)
|
||||
const uint8_t *brf = &mmio.brf[(dma.line & 1) << 3];
|
||||
unsigned bpp = 2 << (2 - mmio.dmacb);
|
||||
unsigned addr = mmio.dda & 0x07ff;
|
||||
|
@ -131,14 +130,9 @@ void SA1::dma_cc2() {
|
|||
for(unsigned bit = 0; bit < 8; bit++) {
|
||||
output |= ((brf[bit] >> byte) & 1) << (7 - bit);
|
||||
}
|
||||
|
||||
static const unsigned index[] = { 0, 1, 16, 17, 32, 33, 48, 49 };
|
||||
iram[addr + index[byte]] = output;
|
||||
add_clocks(4);
|
||||
scheduler.sync_copcpu();
|
||||
memory::iram.write(addr + ((byte & 6) << 3) + (byte & 1), output);
|
||||
}
|
||||
|
||||
dma.mode = DMA::Inactive;
|
||||
dma.line = (dma.line + 1) & 15;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,10 +2,6 @@ struct DMA {
|
|||
enum CDEN { DmaNormal = 0, DmaCharConversion = 1 };
|
||||
enum SD { SourceROM = 0, SourceBWRAM = 1, SourceIRAM = 2 };
|
||||
enum DD { DestIRAM = 0, DestBWRAM = 1 };
|
||||
|
||||
enum Mode { Inactive, Normal, CC1, CC2 } mode;
|
||||
unsigned clocks;
|
||||
bool tile;
|
||||
unsigned line;
|
||||
} dma;
|
||||
|
||||
|
|
|
@ -5,55 +5,35 @@
|
|||
//==========================
|
||||
|
||||
void SA1::op_io() {
|
||||
add_clocks(2);
|
||||
tick();
|
||||
if(regs.wai) scheduler.sync_copcpu();
|
||||
cycle_edge();
|
||||
}
|
||||
|
||||
//ROM, I-RAM and MMIO registers are accessed at ~10.74MHz (2 clock ticks)
|
||||
//BW-RAM is accessed at ~5.37MHz (4 clock ticks)
|
||||
//tick() == 2 clock ticks
|
||||
//note: bus conflict delays are not emulated at this time
|
||||
|
||||
#define is_bwram(addr) (\
|
||||
((addr & 0x40e000) == 0x006000) \
|
||||
|| ((addr & 0xf00000) == 0x400000) \
|
||||
|| ((addr & 0xf00000) == 0x600000) \
|
||||
)
|
||||
|
||||
uint8_t SA1::op_read(unsigned addr) {
|
||||
add_clocks(bus_speed(addr));
|
||||
tick();
|
||||
if(is_bwram(addr)) tick();
|
||||
scheduler.sync_copcpu();
|
||||
regs.mdr = sa1bus.read(addr);
|
||||
cycle_edge();
|
||||
return regs.mdr;
|
||||
return sa1bus.read(addr);
|
||||
}
|
||||
|
||||
void SA1::op_write(unsigned addr, uint8_t data) {
|
||||
add_clocks(bus_speed(addr));
|
||||
tick();
|
||||
if(is_bwram(addr)) tick();
|
||||
scheduler.sync_copcpu();
|
||||
sa1bus.write(addr, regs.mdr = data);
|
||||
cycle_edge();
|
||||
sa1bus.write(addr, data);
|
||||
}
|
||||
|
||||
void SA1::cycle_edge() {
|
||||
switch(dma.mode) {
|
||||
case DMA::Normal: dma_normal(); break;
|
||||
case DMA::CC1: dma_cc1(); break;
|
||||
case DMA::CC2: dma_cc2(); break;
|
||||
}
|
||||
}
|
||||
|
||||
//$[00-3f:80-bf]:[8000-ffff]
|
||||
//$[c0-ff] :[0000-ffff]
|
||||
#define ROM(n) ( \
|
||||
((n & 0x408000) == 0x008000) \
|
||||
|| ((n & 0xc00000) == 0xc00000) \
|
||||
)
|
||||
|
||||
//$[00-3f|80-bf]:[0000-07ff]
|
||||
//$[00-3f|80-bf]:[3000-37ff]
|
||||
#define IRAM(n) ( \
|
||||
((n & 0x40f800) == 0x000000) \
|
||||
|| ((n & 0x40f800) == 0x003000) \
|
||||
)
|
||||
|
||||
unsigned SA1::bus_speed(unsigned addr) {
|
||||
if(IRAM(addr)) return 2;
|
||||
if(ROM(addr)) return (ROM(cpu.regs.bus) ? 4 : 2);
|
||||
return 4; //MMIO, BW-RAM
|
||||
}
|
||||
|
||||
#undef ROM
|
||||
#undef IRAM
|
||||
#undef is_bwram
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
void op_io();
|
||||
uint8_t op_read(unsigned addr);
|
||||
void op_write(unsigned addr, uint8_t data);
|
||||
void cycle_edge();
|
||||
unsigned bus_speed(unsigned addr);
|
||||
alwaysinline void op_io();
|
||||
alwaysinline uint8_t op_read(unsigned addr);
|
||||
alwaysinline void op_write(unsigned addr, uint8_t data);
|
||||
alwaysinline unsigned bus_speed(unsigned addr);
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
#ifdef SA1_CPP
|
||||
|
||||
//BS-X flash carts, when present, are mapped to 0x400000+
|
||||
Memory& SA1::mmio_access(unsigned &addr) {
|
||||
if(cartridge.bsx_flash_loaded() == false) return memory::cartrom;
|
||||
if(addr < 0x400000) return memory::cartrom;
|
||||
addr &= 0x3fffff;
|
||||
return bsxflash;
|
||||
}
|
||||
|
||||
//(CCNT) SA-1 control
|
||||
void SA1::mmio_w2200(uint8_t data) {
|
||||
if(mmio.sa1_resb && !(data & 0x80)) {
|
||||
|
@ -86,17 +94,10 @@ void SA1::mmio_w2209(uint8_t data) {
|
|||
|
||||
//(CIE) SA-1 interrupt enable
|
||||
void SA1::mmio_w220a(uint8_t data) {
|
||||
if(!mmio.sa1_irqen && (data & 0x80)) {
|
||||
if(mmio.sa1_irqfl) mmio.sa1_irqcl = 0;
|
||||
}
|
||||
|
||||
if(!mmio.dma_irqen && (data & 0x20)) {
|
||||
if(mmio.dma_irqfl) mmio.dma_irqcl = 0;
|
||||
}
|
||||
|
||||
if(!mmio.sa1_nmien && (data & 0x10)) {
|
||||
if(mmio.sa1_nmifl) mmio.sa1_nmicl = 0;
|
||||
}
|
||||
if(!mmio.sa1_irqen && (data & 0x80) && mmio.sa1_irqfl ) mmio.sa1_irqcl = 0;
|
||||
if(!mmio.timer_irqen && (data & 0x40) && mmio.timer_irqfl) mmio.timer_irqcl = 0;
|
||||
if(!mmio.dma_irqen && (data & 0x20) && mmio.dma_irqfl ) mmio.dma_irqcl = 0;
|
||||
if(!mmio.sa1_nmien && (data & 0x10) && mmio.sa1_nmifl ) mmio.sa1_nmicl = 0;
|
||||
|
||||
mmio.sa1_irqen = (data & 0x80);
|
||||
mmio.timer_irqen = (data & 0x40);
|
||||
|
@ -111,17 +112,18 @@ void SA1::mmio_w220b(uint8_t data) {
|
|||
mmio.dma_irqcl = (data & 0x20);
|
||||
mmio.sa1_nmicl = (data & 0x10);
|
||||
|
||||
if(mmio.sa1_irqcl) mmio.sa1_irqfl = false;
|
||||
if(mmio.dma_irqcl) mmio.dma_irqfl = false;
|
||||
if(mmio.sa1_nmicl) mmio.sa1_nmifl = false;
|
||||
if(mmio.sa1_irqcl) mmio.sa1_irqfl = false;
|
||||
if(mmio.timer_irqcl) mmio.timer_irqfl = false;
|
||||
if(mmio.dma_irqcl) mmio.dma_irqfl = false;
|
||||
if(mmio.sa1_nmicl) mmio.sa1_nmifl = false;
|
||||
}
|
||||
|
||||
//(SNV) S-CPU NMI vector
|
||||
void SA1::mmio_w220c(uint8_t data) { mmio.snv = (mmio.snv & 0xff00) | data; }
|
||||
void SA1::mmio_w220c(uint8_t data) { mmio.snv = (mmio.snv & 0xff00) | data; }
|
||||
void SA1::mmio_w220d(uint8_t data) { mmio.snv = (data << 8) | (mmio.snv & 0xff); }
|
||||
|
||||
//(SIV) S-CPU IRQ vector
|
||||
void SA1::mmio_w220e(uint8_t data) { mmio.siv = (mmio.siv & 0xff00) | data; }
|
||||
void SA1::mmio_w220e(uint8_t data) { mmio.siv = (mmio.siv & 0xff00) | data; }
|
||||
void SA1::mmio_w220f(uint8_t data) { mmio.siv = (data << 8) | (mmio.siv & 0xff); }
|
||||
|
||||
//(TMC) H/V timer control
|
||||
|
@ -150,10 +152,21 @@ void SA1::mmio_w2220(uint8_t data) {
|
|||
mmio.cbmode = (data & 0x80);
|
||||
mmio.cb = (data & 0x07);
|
||||
|
||||
bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom, (mmio.cbmode == 0) ? 0x000000 : (mmio.cb << 20));
|
||||
sa1bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom, (mmio.cbmode == 0) ? 0x000000 : (mmio.cb << 20));
|
||||
bus.map(Bus::MapLinear, 0xc0, 0xcf, 0x0000, 0xffff, memory::cartrom, mmio.cb << 20);
|
||||
sa1bus.map(Bus::MapLinear, 0xc0, 0xcf, 0x0000, 0xffff, memory::cartrom, mmio.cb << 20);
|
||||
unsigned addr = mmio.cb << 20;
|
||||
Memory &access = mmio_access(addr);
|
||||
|
||||
if(mmio.cbmode == 0) {
|
||||
bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom, 0x000000);
|
||||
sa1bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom, 0x000000);
|
||||
} else {
|
||||
bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, access, addr);
|
||||
sa1bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, access, addr);
|
||||
}
|
||||
|
||||
bus.map(Bus::MapLinear, 0xc0, 0xcf, 0x0000, 0xffff, access, addr);
|
||||
sa1bus.map(Bus::MapLinear, 0xc0, 0xcf, 0x0000, 0xffff, access, addr);
|
||||
|
||||
memory::vectorsp.sync();
|
||||
}
|
||||
|
||||
//(DXB) Super MMC bank D
|
||||
|
@ -161,10 +174,19 @@ void SA1::mmio_w2221(uint8_t data) {
|
|||
mmio.dbmode = (data & 0x80);
|
||||
mmio.db = (data & 0x07);
|
||||
|
||||
bus.map(Bus::MapLinear, 0x20, 0x3f, 0x8000, 0xffff, memory::cartrom, (mmio.dbmode == 0) ? 0x100000 : (mmio.db << 20));
|
||||
sa1bus.map(Bus::MapLinear, 0x20, 0x3f, 0x8000, 0xffff, memory::cartrom, (mmio.dbmode == 0) ? 0x100000 : (mmio.db << 20));
|
||||
bus.map(Bus::MapLinear, 0xd0, 0xdf, 0x0000, 0xffff, memory::cartrom, mmio.db << 20);
|
||||
sa1bus.map(Bus::MapLinear, 0xd0, 0xdf, 0x0000, 0xffff, memory::cartrom, mmio.db << 20);
|
||||
unsigned addr = mmio.db << 20;
|
||||
Memory &access = mmio_access(addr);
|
||||
|
||||
if(mmio.dbmode == 0) {
|
||||
bus.map(Bus::MapLinear, 0x20, 0x3f, 0x8000, 0xffff, memory::cartrom, 0x100000);
|
||||
sa1bus.map(Bus::MapLinear, 0x20, 0x3f, 0x8000, 0xffff, memory::cartrom, 0x100000);
|
||||
} else {
|
||||
bus.map(Bus::MapLinear, 0x20, 0x3f, 0x8000, 0xffff, access, addr);
|
||||
sa1bus.map(Bus::MapLinear, 0x20, 0x3f, 0x8000, 0xffff, access, addr);
|
||||
}
|
||||
|
||||
bus.map(Bus::MapLinear, 0xd0, 0xdf, 0x0000, 0xffff, access, addr);
|
||||
sa1bus.map(Bus::MapLinear, 0xd0, 0xdf, 0x0000, 0xffff, access, addr);
|
||||
}
|
||||
|
||||
//(EXB) Super MMC bank E
|
||||
|
@ -172,10 +194,19 @@ void SA1::mmio_w2222(uint8_t data) {
|
|||
mmio.ebmode = (data & 0x80);
|
||||
mmio.eb = (data & 0x07);
|
||||
|
||||
bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom, (mmio.ebmode == 0) ? 0x200000 : (mmio.eb << 20));
|
||||
sa1bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom, (mmio.ebmode == 0) ? 0x200000 : (mmio.eb << 20));
|
||||
bus.map(Bus::MapLinear, 0xe0, 0xef, 0x0000, 0xffff, memory::cartrom, mmio.eb << 20);
|
||||
sa1bus.map(Bus::MapLinear, 0xe0, 0xef, 0x0000, 0xffff, memory::cartrom, mmio.eb << 20);
|
||||
unsigned addr = mmio.eb << 20;
|
||||
Memory &access = mmio_access(addr);
|
||||
|
||||
if(mmio.ebmode == 0) {
|
||||
bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom, 0x200000);
|
||||
sa1bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom, 0x200000);
|
||||
} else {
|
||||
bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, access, addr);
|
||||
sa1bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, access, addr);
|
||||
}
|
||||
|
||||
bus.map(Bus::MapLinear, 0xe0, 0xef, 0x0000, 0xffff, access, addr);
|
||||
sa1bus.map(Bus::MapLinear, 0xe0, 0xef, 0x0000, 0xffff, access, addr);
|
||||
}
|
||||
|
||||
//(FXB) Super MMC bank F
|
||||
|
@ -183,18 +214,27 @@ void SA1::mmio_w2223(uint8_t data) {
|
|||
mmio.fbmode = (data & 0x80);
|
||||
mmio.fb = (data & 0x07);
|
||||
|
||||
bus.map(Bus::MapLinear, 0xa0, 0xbf, 0x8000, 0xffff, memory::cartrom, (mmio.fbmode == 0) ? 0x300000 : (mmio.fb << 20));
|
||||
sa1bus.map(Bus::MapLinear, 0xa0, 0xbf, 0x8000, 0xffff, memory::cartrom, (mmio.fbmode == 0) ? 0x300000 : (mmio.fb << 20));
|
||||
bus.map(Bus::MapLinear, 0xf0, 0xff, 0x0000, 0xffff, memory::cartrom, mmio.fb << 20);
|
||||
sa1bus.map(Bus::MapLinear, 0xf0, 0xff, 0x0000, 0xffff, memory::cartrom, mmio.fb << 20);
|
||||
unsigned addr = mmio.fb << 20;
|
||||
Memory &access = mmio_access(addr);
|
||||
|
||||
if(mmio.fbmode == 0) {
|
||||
bus.map(Bus::MapLinear, 0xa0, 0xbf, 0x8000, 0xffff, memory::cartrom, 0x300000);
|
||||
sa1bus.map(Bus::MapLinear, 0xa0, 0xbf, 0x8000, 0xffff, memory::cartrom, 0x300000);
|
||||
} else {
|
||||
bus.map(Bus::MapLinear, 0xa0, 0xbf, 0x8000, 0xffff, access, addr);
|
||||
sa1bus.map(Bus::MapLinear, 0xa0, 0xbf, 0x8000, 0xffff, access, addr);
|
||||
}
|
||||
|
||||
bus.map(Bus::MapLinear, 0xf0, 0xff, 0x0000, 0xffff, access, addr);
|
||||
sa1bus.map(Bus::MapLinear, 0xf0, 0xff, 0x0000, 0xffff, access, addr);
|
||||
}
|
||||
|
||||
//(BMAPS) S-CPU BW-RAM address mapping
|
||||
void SA1::mmio_w2224(uint8_t data) {
|
||||
mmio.sbm = (data & 0x1f);
|
||||
|
||||
bus.map(Bus::MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::cpu::bwram, mmio.sbm * 0x2000, 0x2000);
|
||||
bus.map(Bus::MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::cpu::bwram, mmio.sbm * 0x2000, 0x2000);
|
||||
bus.map(Bus::MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::cc1bwram, mmio.sbm * 0x2000, 0x2000);
|
||||
bus.map(Bus::MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::cc1bwram, mmio.sbm * 0x2000, 0x2000);
|
||||
}
|
||||
|
||||
//(BMAP) SA-1 BW-RAM address mapping
|
||||
|
@ -204,12 +244,12 @@ void SA1::mmio_w2225(uint8_t data) {
|
|||
|
||||
if(mmio.sw46 == 0) {
|
||||
//$[40-43]:[0000-ffff] x 32 projection
|
||||
sa1bus.map(Bus::MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::sa1::bwram, (mmio.cbm & 0x1f) * 0x2000, 0x2000);
|
||||
sa1bus.map(Bus::MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::sa1::bwram, (mmio.cbm & 0x1f) * 0x2000, 0x2000);
|
||||
sa1bus.map(Bus::MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::bwram, (mmio.cbm & 0x1f) * 0x2000, 0x2000);
|
||||
sa1bus.map(Bus::MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::bwram, (mmio.cbm & 0x1f) * 0x2000, 0x2000);
|
||||
} else {
|
||||
//$[60-6f]:[0000-ffff] x 128 projection
|
||||
sa1bus.map(Bus::MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::sa1::bitmapram, mmio.cbm * 0x2000, 0x2000);
|
||||
sa1bus.map(Bus::MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::sa1::bitmapram, mmio.cbm * 0x2000, 0x2000);
|
||||
sa1bus.map(Bus::MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::bitmapram, mmio.cbm * 0x2000, 0x2000);
|
||||
sa1bus.map(Bus::MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::bitmapram, mmio.cbm * 0x2000, 0x2000);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -256,7 +296,7 @@ void SA1::mmio_w2231(uint8_t data) {
|
|||
mmio.dmasize = (data >> 2) & 7;
|
||||
mmio.dmacb = (data & 0x03);
|
||||
|
||||
if(mmio.chdend) memory::cpu::bwram.cc1dma = false;
|
||||
if(mmio.chdend) memory::cc1bwram.dma = false;
|
||||
if(mmio.dmasize > 5) mmio.dmasize = 5;
|
||||
if(mmio.dmacb > 2) mmio.dmacb = 2;
|
||||
}
|
||||
|
@ -274,11 +314,11 @@ void SA1::mmio_w2235(uint8_t data) {
|
|||
void SA1::mmio_w2236(uint8_t data) {
|
||||
mmio.dda = (mmio.dda & 0xff00ff) | (data << 8);
|
||||
|
||||
if(dma.mode == DMA::Inactive) {
|
||||
if(mmio.dmaen == true) {
|
||||
if(mmio.cden == 0 && mmio.dd == DMA::DestIRAM) {
|
||||
dma.mode = DMA::Normal;
|
||||
dma_normal();
|
||||
} else if(mmio.cden == 1 && mmio.cdsel == 1) {
|
||||
dma.mode = DMA::CC1;
|
||||
dma_cc1();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -286,9 +326,9 @@ void SA1::mmio_w2236(uint8_t data) {
|
|||
void SA1::mmio_w2237(uint8_t data) {
|
||||
mmio.dda = (mmio.dda & 0x00ffff) | (data << 16);
|
||||
|
||||
if(dma.mode == DMA::Inactive) {
|
||||
if(mmio.dmaen == true) {
|
||||
if(mmio.cden == 0 && mmio.dd == DMA::DestBWRAM) {
|
||||
dma.mode = DMA::Normal;
|
||||
dma_normal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -311,9 +351,9 @@ void SA1::mmio_w2244(uint8_t data) { mmio.brf[ 4] = data; }
|
|||
void SA1::mmio_w2245(uint8_t data) { mmio.brf[ 5] = data; }
|
||||
void SA1::mmio_w2246(uint8_t data) { mmio.brf[ 6] = data; }
|
||||
void SA1::mmio_w2247(uint8_t data) { mmio.brf[ 7] = data;
|
||||
if(dma.mode == DMA::Inactive) {
|
||||
if(mmio.dmaen == true) {
|
||||
if(mmio.cden == 1 && mmio.cdsel == 0) {
|
||||
dma.mode = DMA::CC2;
|
||||
dma_cc2();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -326,9 +366,9 @@ void SA1::mmio_w224c(uint8_t data) { mmio.brf[12] = data; }
|
|||
void SA1::mmio_w224d(uint8_t data) { mmio.brf[13] = data; }
|
||||
void SA1::mmio_w224e(uint8_t data) { mmio.brf[14] = data; }
|
||||
void SA1::mmio_w224f(uint8_t data) { mmio.brf[15] = data;
|
||||
if(dma.mode == DMA::Inactive) {
|
||||
if(mmio.dmaen == true) {
|
||||
if(mmio.cden == 1 && mmio.cdsel == 0) {
|
||||
dma.mode = DMA::CC2;
|
||||
dma_cc2();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -384,7 +424,7 @@ void SA1::mmio_w2254(uint8_t data) {
|
|||
mmio.mr += (int16_t)mmio.ma * (int16_t)mmio.mb;
|
||||
mmio.overflow = (mmio.mr >= (1ULL << 40));
|
||||
mmio.mr &= (1ULL << 40) - 1;
|
||||
mmio.ma = 0;
|
||||
mmio.mb = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
uint8_t mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8_t data);
|
||||
Memory& mmio_access(unsigned &addr);
|
||||
|
||||
struct MMIO {
|
||||
//$2200 CCNT
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <../base.hpp>
|
||||
#include <../cart/cart.hpp>
|
||||
#include <../chip/bsx/bsx.hpp>
|
||||
#define SA1_CPP
|
||||
|
||||
#include "sa1.hpp"
|
||||
|
@ -12,17 +13,10 @@ void SA1::enter() {
|
|||
while(true) {
|
||||
while(mmio.sa1_rdyb || mmio.sa1_resb) {
|
||||
//SA-1 co-processor is asleep
|
||||
add_clocks(4);
|
||||
tick();
|
||||
scheduler.sync_copcpu();
|
||||
}
|
||||
|
||||
#if 0
|
||||
static FILE *fp = fopen("/home/byuu/Desktop/sa1log.txt", "wb");
|
||||
char t[1024];
|
||||
disassemble_opcode(t);
|
||||
fprintf(fp, "%s\n", t);
|
||||
#endif
|
||||
|
||||
if(status.interrupt_pending) {
|
||||
status.interrupt_pending = false;
|
||||
interrupt(status.interrupt_vector);
|
||||
|
@ -39,33 +33,23 @@ void SA1::last_cycle() {
|
|||
mmio.sa1_nmifl = true;
|
||||
mmio.sa1_nmicl = 1;
|
||||
regs.wai = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if(mmio.timer_irqen && !mmio.timer_irqcl) {
|
||||
status.interrupt_pending = true;
|
||||
status.interrupt_vector = mmio.civ;
|
||||
mmio.timer_irqfl = true;
|
||||
mmio.timer_irqcl = 1;
|
||||
regs.wai = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if(mmio.dma_irqen && !mmio.dma_irqcl) {
|
||||
status.interrupt_pending = true;
|
||||
status.interrupt_vector = mmio.civ;
|
||||
mmio.dma_irqfl = true;
|
||||
mmio.dma_irqcl = 1;
|
||||
regs.wai = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!regs.p.i && mmio.sa1_irq && !mmio.sa1_irqcl) {
|
||||
status.interrupt_pending = true;
|
||||
status.interrupt_vector = mmio.civ;
|
||||
mmio.sa1_irqfl = true;
|
||||
regs.wai = false;
|
||||
return;
|
||||
} else if(!regs.p.i) {
|
||||
if(mmio.timer_irqen && !mmio.timer_irqcl) {
|
||||
status.interrupt_pending = true;
|
||||
status.interrupt_vector = mmio.civ;
|
||||
mmio.timer_irqfl = true;
|
||||
regs.wai = false;
|
||||
} else if(mmio.dma_irqen && !mmio.dma_irqcl) {
|
||||
status.interrupt_pending = true;
|
||||
status.interrupt_vector = mmio.civ;
|
||||
mmio.dma_irqfl = true;
|
||||
regs.wai = false;
|
||||
} else if(mmio.sa1_irq && !mmio.sa1_irqcl) {
|
||||
status.interrupt_pending = true;
|
||||
status.interrupt_vector = mmio.civ;
|
||||
mmio.sa1_irqfl = true;
|
||||
regs.wai = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,7 +60,6 @@ void SA1::interrupt(uint16_t vector) {
|
|||
op_writestack(regs.pc.h);
|
||||
op_writestack(regs.pc.l);
|
||||
op_writestack(regs.e ? (regs.p & ~0x10) : regs.p);
|
||||
add_clocks(8);
|
||||
regs.pc.w = vector;
|
||||
regs.pc.b = 0x00;
|
||||
regs.p.i = 1;
|
||||
|
@ -87,47 +70,37 @@ bool SA1::interrupt_pending() {
|
|||
return status.interrupt_pending;
|
||||
}
|
||||
|
||||
void SA1::add_clocks(unsigned clocks) {
|
||||
scheduler.addclocks_cop(clocks);
|
||||
|
||||
uint16_t last_hcounter = status.hcounter;
|
||||
uint16_t last_vcounter = status.vcounter;
|
||||
void SA1::tick() {
|
||||
scheduler.addclocks_cop(2);
|
||||
|
||||
//adjust counters:
|
||||
//note that internally, status counters are in clocks;
|
||||
//whereas MMIO register counters are in dots (4 clocks = 1 dot)
|
||||
if(mmio.hvselb == 0) {
|
||||
//HV timer
|
||||
status.hcounter += clocks;
|
||||
status.hcounter += 2;
|
||||
if(status.hcounter >= 1364) {
|
||||
status.hcounter -= 1364;
|
||||
status.vcounter++;
|
||||
if(status.vcounter >= status.scanlines) {
|
||||
status.vcounter = 0;
|
||||
}
|
||||
status.hcounter = 0;
|
||||
if(++status.vcounter >= status.scanlines) status.vcounter = 0;
|
||||
}
|
||||
} else {
|
||||
//linear timer
|
||||
status.hcounter += clocks;
|
||||
status.hcounter += 2;
|
||||
status.vcounter += (status.hcounter >> 11);
|
||||
status.hcounter &= 0x07ff;
|
||||
status.vcounter &= 0x01ff;
|
||||
}
|
||||
|
||||
//test counters for timer IRQ
|
||||
uint32_t lo = (last_vcounter << 11) + last_hcounter;
|
||||
uint32_t hi = (status.vcounter << 11) + status.hcounter;
|
||||
uint32_t trigger = (mmio.vcnt << 11) + (mmio.hcnt << 2);
|
||||
|
||||
if(lo > hi) {
|
||||
if(trigger <= hi) goto trigger_irq;
|
||||
hi += 1 << 20;
|
||||
switch((mmio.ven << 1) + (mmio.hen << 0)) {
|
||||
case 0: break;
|
||||
case 1: if(status.hcounter == (mmio.hcnt << 2)) trigger_irq(); break;
|
||||
case 2: if(status.vcounter == mmio.vcnt && status.hcounter == 0) trigger_irq(); break;
|
||||
case 3: if(status.vcounter == mmio.hcnt && status.hcounter == (mmio.hcnt << 2)) trigger_irq(); break;
|
||||
}
|
||||
}
|
||||
|
||||
if(lo < trigger && trigger <= hi) goto trigger_irq;
|
||||
return;
|
||||
|
||||
trigger_irq:
|
||||
void SA1::trigger_irq() {
|
||||
mmio.timer_irqfl = true;
|
||||
if(mmio.timer_irqen) mmio.timer_irqcl = 0;
|
||||
}
|
||||
|
@ -146,6 +119,11 @@ void SA1::power() {
|
|||
}
|
||||
|
||||
void SA1::reset() {
|
||||
memory::vectorsp.access = 0;
|
||||
memory::cc1bwram.dma = false;
|
||||
for(unsigned addr = 0; addr < memory::iram.size(); addr++) {
|
||||
memory::iram.write(addr, 0x00);
|
||||
}
|
||||
sa1bus.init();
|
||||
|
||||
regs.pc.d = 0x000000;
|
||||
|
@ -160,19 +138,14 @@ void SA1::reset() {
|
|||
regs.wai = false;
|
||||
update_table();
|
||||
|
||||
memset(iram, 0, sizeof iram);
|
||||
|
||||
status.interrupt_pending = false;
|
||||
status.interrupt_vector = 0x0000;
|
||||
|
||||
status.scanlines = (snes.region() == SNES::NTSC ? 261 : 311);
|
||||
status.scanlines = (snes.region() == SNES::NTSC ? 262 : 312);
|
||||
status.vcounter = 0;
|
||||
status.hcounter = 0;
|
||||
|
||||
dma.mode = DMA::Inactive;
|
||||
dma.clocks = 4;
|
||||
dma.tile = 0;
|
||||
dma.line = 0;
|
||||
dma.line = 0;
|
||||
|
||||
//$2200 CCNT
|
||||
mmio.sa1_irq = false;
|
||||
|
|
|
@ -5,7 +5,6 @@ public:
|
|||
#include "dma/dma.hpp"
|
||||
#include "memory/memory.hpp"
|
||||
#include "mmio/mmio.hpp"
|
||||
uint8_t iram[2048];
|
||||
|
||||
struct Status {
|
||||
bool interrupt_pending;
|
||||
|
@ -18,10 +17,11 @@ public:
|
|||
|
||||
void enter();
|
||||
void interrupt(uint16_t vector);
|
||||
void add_clocks(unsigned);
|
||||
void tick();
|
||||
|
||||
void last_cycle();
|
||||
bool interrupt_pending();
|
||||
alwaysinline void trigger_irq();
|
||||
alwaysinline void last_cycle();
|
||||
alwaysinline bool interrupt_pending();
|
||||
|
||||
void init();
|
||||
void enable();
|
||||
|
|
|
@ -11,7 +11,7 @@ void SDD1::enable() {
|
|||
//hook S-CPU DMA MMIO registers to gather information for struct dma[];
|
||||
//buffer address and transfer size information for use in SDD1::read()
|
||||
for(unsigned i = 0x4300; i <= 0x437f; i++) {
|
||||
cpu_mmio[i & 0x7f] = memory::mmio.get(i);
|
||||
cpu_mmio[i & 0x7f] = memory::mmio.mmio[i];
|
||||
memory::mmio.map(i, *this);
|
||||
}
|
||||
|
||||
|
|
|
@ -71,10 +71,9 @@ struct regs_t {
|
|||
uint8_t db;
|
||||
bool e;
|
||||
|
||||
bool irq; //IRQ pin (0 = low, 1 = trigger)
|
||||
bool wai; //raised during wai, cleared after interrupt triggered
|
||||
uint32_t bus; //address on bus; -1U = I/O cycle
|
||||
uint8_t mdr; //memory data register
|
||||
bool irq; //IRQ pin (0 = low, 1 = trigger)
|
||||
bool wai; //raised during wai, cleared after interrupt triggered
|
||||
uint8_t mdr; //memory data register
|
||||
|
||||
regs_t() : db(0), e(false), irq(false), wai(false), bus(-1U), mdr(0) {}
|
||||
regs_t() : db(0), e(false), irq(false), wai(false), mdr(0) {}
|
||||
};
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifdef SCPU_CPP
|
||||
|
||||
void sCPU::op_io() {
|
||||
regs.bus = -1U;
|
||||
status.clock_count = 6;
|
||||
precycle_edge();
|
||||
add_clocks(6);
|
||||
|
@ -10,7 +9,7 @@ void sCPU::op_io() {
|
|||
}
|
||||
|
||||
uint8 sCPU::op_read(uint32 addr) {
|
||||
status.clock_count = speed(regs.bus = addr);
|
||||
status.clock_count = speed(addr);
|
||||
precycle_edge();
|
||||
add_clocks(status.clock_count - 4);
|
||||
|
||||
|
@ -23,7 +22,7 @@ uint8 sCPU::op_read(uint32 addr) {
|
|||
}
|
||||
|
||||
void sCPU::op_write(uint32 addr, uint8 data) {
|
||||
status.clock_count = speed(regs.bus = addr);
|
||||
status.clock_count = speed(addr);
|
||||
precycle_edge();
|
||||
add_clocks(status.clock_count);
|
||||
|
||||
|
|
|
@ -12,10 +12,6 @@ priority_queue<unsigned> event(512, bind(&sCPU::queue_event, &cpu));
|
|||
void sCPU::enter() {
|
||||
regs.pc.l = bus.read(0xfffc);
|
||||
regs.pc.h = bus.read(0xfffd);
|
||||
|
||||
//initial latch values for $213c/$213d
|
||||
//[x]0035 : [y]0000 (53.0 -> 212) [lda $2137]
|
||||
//[x]0038 : [y]0000 (56.5 -> 226) [nop : lda $2137]
|
||||
add_clocks(186);
|
||||
|
||||
while(true) {
|
||||
|
|
|
@ -26,12 +26,12 @@ void sCPU::scanline() {
|
|||
status.dma_counter = (status.dma_counter + status.line_clocks) & 7;
|
||||
status.line_clocks = ppu.lineclocks();
|
||||
|
||||
//forcefully sync S-CPU and S-SMP, in case chips are not communicating
|
||||
if((ppu.vcounter() & 7) == 0) scheduler.sync_cpusmp();
|
||||
|
||||
if(ppu.vcounter() == 0) {
|
||||
//hdma init triggers once every frame
|
||||
event.enqueue(cpu_version == 1 ? 12 + 8 - dma_counter() : 12 + dma_counter(), EventHdmaInit);
|
||||
|
||||
//forcefully sync S-CPU and S-SMP, in case chips are not communicating
|
||||
scheduler.sync_cpusmp();
|
||||
}
|
||||
|
||||
//dram refresh occurs once every scanline
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#define REG(n) state.regs[r_##n]
|
||||
#define VREG(n) state.regs[v.vidx + v_##n]
|
||||
|
||||
#if !defined(USE_STATE_MACHINE)
|
||||
#if !defined(DSP_STATE_MACHINE)
|
||||
#define phase_start() while(true) {
|
||||
#define phase(n)
|
||||
#define tick() scheduler.addclocks_dsp(3 * 8); scheduler.sync_dspsmp()
|
||||
|
|
|
@ -24,10 +24,6 @@ void MMIOAccess::map(unsigned addr, MMIO &access) {
|
|||
mmio[(addr - 0x2000) & 0x3fff] = &access;
|
||||
}
|
||||
|
||||
MMIO* MMIOAccess::get(unsigned addr) {
|
||||
return mmio[(addr - 0x2000) & 0x3fff];
|
||||
}
|
||||
|
||||
uint8 MMIOAccess::read(unsigned addr) {
|
||||
return mmio[(addr - 0x2000) & 0x3fff]->mmio_read(addr);
|
||||
}
|
||||
|
|
|
@ -56,16 +56,13 @@ private:
|
|||
|
||||
struct MMIOAccess : Memory {
|
||||
void map(unsigned addr, MMIO &access);
|
||||
MMIO* get(unsigned addr);
|
||||
uint8 read(unsigned addr);
|
||||
void write(unsigned addr, uint8 data);
|
||||
|
||||
private:
|
||||
MMIO *mmio[0x4000];
|
||||
};
|
||||
|
||||
class Bus {
|
||||
public:
|
||||
struct Bus {
|
||||
unsigned mirror(unsigned addr, unsigned size);
|
||||
void map(unsigned addr, Memory &access, unsigned offset);
|
||||
enum MapMode { MapDirect, MapLinear, MapShadow };
|
||||
|
@ -100,7 +97,6 @@ public:
|
|||
Bus() {}
|
||||
virtual ~Bus() {}
|
||||
|
||||
protected:
|
||||
struct Page {
|
||||
Memory *access;
|
||||
unsigned offset;
|
||||
|
|
|
@ -16,11 +16,11 @@ void sSMP::enter() {
|
|||
|
||||
//forcefully sync S-CPU and S-SMP, in case chips are not communicating
|
||||
static unsigned counter = 0;
|
||||
if(++counter & 4096) {
|
||||
if(++counter >= 128) {
|
||||
counter = 0;
|
||||
scheduler.sync_smpcpu();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif //ifdef SSMP_CPP
|
||||
#endif
|
||||
|
|
|
@ -6,12 +6,6 @@
|
|||
#include "timing/timing.cpp"
|
||||
|
||||
void sSMP::power() {
|
||||
for(unsigned i = 0; i < memory::apuram.size(); i++) {
|
||||
//SNES hardware APURAM contains pseudo-random data upon power up (exact formula is unknown.)
|
||||
//memory::apuram.write(i, (i & 32) ? 0xff : 0x00);
|
||||
memory::apuram.write(i, 0x00);
|
||||
}
|
||||
|
||||
//targets not initialized/changed upon reset
|
||||
t0.target = 0;
|
||||
t1.target = 0;
|
||||
|
@ -28,6 +22,10 @@ void sSMP::reset() {
|
|||
regs.sp = 0xef;
|
||||
regs.p = 0x02;
|
||||
|
||||
for(unsigned i = 0; i < memory::apuram.size(); i++) {
|
||||
memory::apuram.write(i, 0x00);
|
||||
}
|
||||
|
||||
status.clock_counter = 0;
|
||||
status.dsp_counter = 0;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
void sSMP::add_clocks(unsigned clocks) {
|
||||
scheduler.addclocks_smp(clocks);
|
||||
#if !defined(USE_STATE_MACHINE)
|
||||
#if !defined(DSP_STATE_MACHINE)
|
||||
scheduler.sync_smpdsp();
|
||||
#else
|
||||
while(scheduler.clock.smpdsp < 0) dsp.enter();
|
||||
|
|
Loading…
Reference in New Issue