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 BSNES_TITLE "bsnes v" BSNES_VERSION
|
||||||
|
|
||||||
#define BUSCORE sBus
|
#define BUSCORE sBus
|
||||||
|
@ -9,12 +9,7 @@
|
||||||
|
|
||||||
//S-DSP can be encapsulated into a state machine using #define magic
|
//S-DSP can be encapsulated into a state machine using #define magic
|
||||||
//this avoids ~2.048m co_switch() calls per second (~5% speedup)
|
//this avoids ~2.048m co_switch() calls per second (~5% speedup)
|
||||||
#define USE_STATE_MACHINE
|
#define DSP_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
|
|
||||||
|
|
||||||
//game genie + pro action replay code support (~2% speed hit)
|
//game genie + pro action replay code support (~2% speed hit)
|
||||||
#define CHEAT_SYSTEM
|
#define CHEAT_SYSTEM
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#make platform=x compiler=gcc
|
make platform=x compiler=gcc
|
||||||
make platform=x compiler=gcc enable_gzip=true enable_jma=true
|
#make platform=x compiler=gcc enable_gzip=true enable_jma=true
|
||||||
|
|
|
@ -1,16 +1,11 @@
|
||||||
#ifdef SA1_CPP
|
#ifdef SA1_CPP
|
||||||
|
|
||||||
namespace memory {
|
namespace memory {
|
||||||
namespace cpu {
|
VectorSelectionPage vectorsp;
|
||||||
CPUIRAM iram;
|
StaticRAM iram(2048);
|
||||||
CPUBWRAM bwram;
|
MappedRAM &bwram = memory::cartram;
|
||||||
}
|
CC1BWRAM cc1bwram;
|
||||||
|
BitmapRAM bitmapram;
|
||||||
namespace sa1 {
|
|
||||||
SA1IRAM iram;
|
|
||||||
SA1BWRAM bwram;
|
|
||||||
SA1BitmapRAM bitmapram;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SA1Bus::init() {
|
void SA1Bus::init() {
|
||||||
|
@ -22,124 +17,103 @@ void SA1Bus::init() {
|
||||||
memory::mmio.map(i, sa1);
|
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(MapDirect, 0x00, 0x3f, 0x2200, 0x23ff, memory::mmio);
|
||||||
map(MapLinear, 0x00, 0x3f, 0x3000, 0x37ff, memory::sa1::iram);
|
map(MapLinear, 0x00, 0x3f, 0x3000, 0x37ff, memory::iram);
|
||||||
map(MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::sa1::bwram);
|
map(MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::bwram);
|
||||||
map(MapLinear, 0x00, 0x3f, 0x8000, 0xffff, memory::cartrom);
|
map(MapLinear, 0x00, 0x3f, 0x8000, 0xffff, memory::cartrom);
|
||||||
map(MapLinear, 0x40, 0x4f, 0x0000, 0xffff, memory::sa1::bwram, 0, 0x040000);
|
map(MapLinear, 0x40, 0x4f, 0x0000, 0xffff, memory::bwram);
|
||||||
map(MapLinear, 0x60, 0x6f, 0x0000, 0xffff, memory::sa1::bitmapram);
|
map(MapLinear, 0x60, 0x6f, 0x0000, 0xffff, memory::bitmapram);
|
||||||
map(MapLinear, 0x80, 0xbf, 0x0000, 0x07ff, memory::sa1::iram);
|
map(MapLinear, 0x80, 0xbf, 0x0000, 0x07ff, memory::iram);
|
||||||
map(MapDirect, 0x80, 0xbf, 0x2200, 0x23ff, memory::mmio);
|
map(MapDirect, 0x80, 0xbf, 0x2200, 0x23ff, memory::mmio);
|
||||||
map(MapLinear, 0x80, 0xbf, 0x3000, 0x37ff, memory::sa1::iram);
|
map(MapLinear, 0x80, 0xbf, 0x3000, 0x37ff, memory::iram);
|
||||||
map(MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::sa1::bwram);
|
map(MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::bwram);
|
||||||
map(MapLinear, 0x80, 0xbf, 0x8000, 0xffff, memory::cartrom);
|
map(MapLinear, 0x80, 0xbf, 0x8000, 0xffff, memory::cartrom);
|
||||||
map(MapLinear, 0xc0, 0xff, 0x0000, 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, 0x3000, 0x37ff, memory::iram);
|
||||||
bus.map(MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::cpu::bwram);
|
bus.map(MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::cc1bwram);
|
||||||
bus.map(MapLinear, 0x00, 0x3f, 0x8000, 0xffff, memory::cartrom);
|
bus.map(MapLinear, 0x00, 0x3f, 0x8000, 0xffff, memory::cartrom);
|
||||||
bus.map(MapLinear, 0x40, 0x4f, 0x0000, 0xffff, memory::cpu::bwram, 0, 0x040000);
|
bus.map(MapLinear, 0x40, 0x4f, 0x0000, 0xffff, memory::cc1bwram);
|
||||||
bus.map(MapLinear, 0x80, 0xbf, 0x3000, 0x37ff, memory::cpu::iram);
|
bus.map(MapLinear, 0x80, 0xbf, 0x3000, 0x37ff, memory::iram);
|
||||||
bus.map(MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::cpu::bwram);
|
bus.map(MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::cc1bwram);
|
||||||
bus.map(MapLinear, 0x80, 0xbf, 0x8000, 0xffff, memory::cartrom);
|
bus.map(MapLinear, 0x80, 0xbf, 0x8000, 0xffff, memory::cartrom);
|
||||||
bus.map(MapLinear, 0xc0, 0xff, 0x0000, 0xffff, memory::cartrom);
|
bus.map(MapLinear, 0xc0, 0xff, 0x0000, 0xffff, memory::cartrom);
|
||||||
|
|
||||||
|
memory::vectorsp.sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
//=======
|
//===================
|
||||||
//CPUIRAM
|
//VectorSelectionPage
|
||||||
//=======
|
//===================
|
||||||
|
|
||||||
unsigned CPUIRAM::size() const {
|
//this class maps $00:[ff00-ffff] for the purpose of supporting:
|
||||||
return sizeof(sa1.iram);
|
//$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) {
|
void VectorSelectionPage::write(unsigned addr, uint8_t data) {
|
||||||
return sa1.iram[addr];
|
return access->write(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPUIRAM::write(unsigned addr, uint8_t data) {
|
//call this whenever bus is remapped.
|
||||||
uint8_t wpbit = (addr >> 8) & 7;
|
//note: S-CPU and SA-1 bus always share $00:[ff00-ffff] as cartridge ROM data;
|
||||||
if(1 || sa1.mmio.siwp & wpbit) {
|
//the SA-1 MMC does not allow mapping these independently between processors.
|
||||||
//allow only when write-protection is disabled
|
//this allows this class to be shared for both, caching only ones' access class.
|
||||||
sa1.iram[addr] = data;
|
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();
|
return memory::cartram.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CPUBWRAM::read(unsigned addr) {
|
uint8_t CC1BWRAM::read(unsigned addr) {
|
||||||
if(cc1dma) return sa1.dma_cc1_read(addr);
|
if(dma) return sa1.dma_cc1_read(addr);
|
||||||
return memory::cartram.read(addr);
|
return memory::cartram.read(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPUBWRAM::write(unsigned addr, uint8_t data) {
|
void CC1BWRAM::write(unsigned addr, uint8_t data) {
|
||||||
if(sa1.mmio.swen == false) {
|
|
||||||
//write-protection enabled
|
|
||||||
unsigned limit = 0x100 << sa1.mmio.bwp;
|
|
||||||
//if(addr < limit) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memory::cartram.write(addr, data);
|
memory::cartram.write(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
//=======
|
//=========
|
||||||
//SA1IRAM
|
//BitmapRAM
|
||||||
//=======
|
//=========
|
||||||
|
|
||||||
unsigned SA1IRAM::size() const {
|
unsigned BitmapRAM::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 {
|
|
||||||
return 0x100000;
|
return 0x100000;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t SA1BitmapRAM::read(unsigned addr) {
|
uint8_t BitmapRAM::read(unsigned addr) {
|
||||||
if(sa1.mmio.bbf == 0) {
|
if(sa1.mmio.bbf == 0) {
|
||||||
//4bpp
|
//4bpp
|
||||||
unsigned shift = addr & 1;
|
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) {
|
if(sa1.mmio.bbf == 0) {
|
||||||
//4bpp
|
//4bpp
|
||||||
uint8_t shift = addr & 1;
|
uint8_t shift = addr & 1;
|
||||||
|
|
|
@ -1,49 +1,31 @@
|
||||||
class SA1Bus : public Bus {
|
struct SA1Bus : Bus {
|
||||||
public:
|
|
||||||
void init();
|
void init();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CPUIRAM : Memory {
|
struct VectorSelectionPage : Memory {
|
||||||
unsigned size() const;
|
alwaysinline uint8_t read(unsigned);
|
||||||
uint8_t read(unsigned);
|
alwaysinline void write(unsigned, uint8_t);
|
||||||
void write(unsigned, uint8_t);
|
void sync();
|
||||||
|
Memory *access;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CPUBWRAM : Memory {
|
struct CC1BWRAM : Memory {
|
||||||
bool cc1dma;
|
|
||||||
|
|
||||||
unsigned size() const;
|
unsigned size() const;
|
||||||
uint8_t read(unsigned);
|
alwaysinline uint8_t read(unsigned);
|
||||||
void write(unsigned, uint8_t);
|
alwaysinline void write(unsigned, uint8_t);
|
||||||
|
bool dma;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SA1IRAM : Memory {
|
struct BitmapRAM : Memory {
|
||||||
unsigned size() const;
|
unsigned size() const;
|
||||||
uint8_t read(unsigned);
|
alwaysinline uint8_t read(unsigned);
|
||||||
void write(unsigned, uint8_t);
|
alwaysinline 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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace memory {
|
namespace memory {
|
||||||
namespace cpu {
|
extern VectorSelectionPage vectorsp;
|
||||||
extern CPUIRAM iram;
|
extern StaticRAM iram;
|
||||||
extern CPUBWRAM bwram;
|
extern MappedRAM &bwram;
|
||||||
}
|
extern CC1BWRAM cc1bwram;
|
||||||
|
extern BitmapRAM bitmapram;
|
||||||
namespace sa1 {
|
|
||||||
extern SA1IRAM iram;
|
|
||||||
extern SA1BWRAM bwram;
|
|
||||||
extern SA1BitmapRAM bitmapram;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,8 @@ void SA1::dma_normal() {
|
||||||
uint8_t data = regs.mdr;
|
uint8_t data = regs.mdr;
|
||||||
uint32_t dsa = mmio.dsa++;
|
uint32_t dsa = mmio.dsa++;
|
||||||
uint32_t dda = mmio.dda++;
|
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::SourceBWRAM && mmio.dd == DMA::DestBWRAM) continue;
|
||||||
if(mmio.sd == DMA::SourceIRAM && mmio.dd == DMA::DestIRAM ) continue;
|
if(mmio.sd == DMA::SourceIRAM && mmio.dd == DMA::DestIRAM ) continue;
|
||||||
|
|
||||||
|
@ -29,7 +28,7 @@ void SA1::dma_normal() {
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case DMA::SourceIRAM: {
|
case DMA::SourceIRAM: {
|
||||||
data = iram[dsa & 0x07ff];
|
data = memory::iram.read(dsa & 0x07ff);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,25 +40,26 @@ void SA1::dma_normal() {
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case DMA::DestIRAM: {
|
case DMA::DestIRAM: {
|
||||||
iram[dda & 0x07ff] = data;
|
memory::iram.write(dda & 0x07ff, data);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dma.mode = DMA::Inactive;
|
|
||||||
mmio.dma_irqfl = true;
|
mmio.dma_irqfl = true;
|
||||||
if(mmio.dma_irqen) mmio.dma_irqcl = 0;
|
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
|
//type-1 character conversion
|
||||||
//===========================
|
//===========================
|
||||||
|
|
||||||
void SA1::dma_cc1() {
|
void SA1::dma_cc1() {
|
||||||
memory::cpu::bwram.cc1dma = true;
|
memory::cc1bwram.dma = true;
|
||||||
|
|
||||||
dma.tile = 0;
|
|
||||||
dma.mode = DMA::Inactive;
|
|
||||||
mmio.chdma_irqfl = true;
|
mmio.chdma_irqfl = true;
|
||||||
if(mmio.chdma_irqen) {
|
if(mmio.chdma_irqen) {
|
||||||
mmio.chdma_irqcl = 0;
|
mmio.chdma_irqcl = 0;
|
||||||
|
@ -75,7 +75,7 @@ uint8_t SA1::dma_cc1_read(unsigned addr) {
|
||||||
//buffer next character to I-RAM
|
//buffer next character to I-RAM
|
||||||
unsigned bpp = 2 << (2 - mmio.dmacb);
|
unsigned bpp = 2 << (2 - mmio.dmacb);
|
||||||
unsigned bpl = (8 << mmio.dmasize) >> 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 tile = ((addr - mmio.dsa) & bwmask) >> (6 - mmio.dmacb);
|
||||||
unsigned ty = (tile >> mmio.dmasize);
|
unsigned ty = (tile >> mmio.dmasize);
|
||||||
unsigned tx = tile & ((1 << mmio.dmasize) - 1);
|
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++) {
|
for(unsigned y = 0; y < 8; y++) {
|
||||||
uint64_t data = 0;
|
uint64_t data = 0;
|
||||||
for(unsigned n = 0; n < bpp; n++) {
|
for(unsigned byte = 0; byte < bpp; byte++) {
|
||||||
data |= (uint64_t)memory::sa1::bwram.read((bwaddr + n) & bwmask) << (n << 3);
|
data |= (uint64_t)memory::bwram.read((bwaddr + byte) & bwmask) << (byte << 3);
|
||||||
}
|
}
|
||||||
bwaddr += bpl;
|
bwaddr += bpl;
|
||||||
|
|
||||||
|
@ -102,15 +102,14 @@ uint8_t SA1::dma_cc1_read(unsigned addr) {
|
||||||
out[7] |= (data & 1) << (7 - x); data >>= 1;
|
out[7] |= (data & 1) << (7 - x); data >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(unsigned n = 0; n < bpp; n++) {
|
for(unsigned byte = 0; byte < bpp; byte++) {
|
||||||
static const unsigned index[] = { 0, 1, 16, 17, 32, 33, 48, 49 };
|
unsigned p = mmio.dda + (y << 1) + ((byte & 6) << 3) + (byte & 1);
|
||||||
unsigned p = mmio.dda + (y << 1) + index[n];
|
memory::iram.write(p & 0x07ff, out[byte]);
|
||||||
iram[p & 0x07ff] = out[n];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
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];
|
const uint8_t *brf = &mmio.brf[(dma.line & 1) << 3];
|
||||||
unsigned bpp = 2 << (2 - mmio.dmacb);
|
unsigned bpp = 2 << (2 - mmio.dmacb);
|
||||||
unsigned addr = mmio.dda & 0x07ff;
|
unsigned addr = mmio.dda & 0x07ff;
|
||||||
|
@ -131,14 +130,9 @@ void SA1::dma_cc2() {
|
||||||
for(unsigned bit = 0; bit < 8; bit++) {
|
for(unsigned bit = 0; bit < 8; bit++) {
|
||||||
output |= ((brf[bit] >> byte) & 1) << (7 - bit);
|
output |= ((brf[bit] >> byte) & 1) << (7 - bit);
|
||||||
}
|
}
|
||||||
|
memory::iram.write(addr + ((byte & 6) << 3) + (byte & 1), output);
|
||||||
static const unsigned index[] = { 0, 1, 16, 17, 32, 33, 48, 49 };
|
|
||||||
iram[addr + index[byte]] = output;
|
|
||||||
add_clocks(4);
|
|
||||||
scheduler.sync_copcpu();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dma.mode = DMA::Inactive;
|
|
||||||
dma.line = (dma.line + 1) & 15;
|
dma.line = (dma.line + 1) & 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,6 @@ struct DMA {
|
||||||
enum CDEN { DmaNormal = 0, DmaCharConversion = 1 };
|
enum CDEN { DmaNormal = 0, DmaCharConversion = 1 };
|
||||||
enum SD { SourceROM = 0, SourceBWRAM = 1, SourceIRAM = 2 };
|
enum SD { SourceROM = 0, SourceBWRAM = 1, SourceIRAM = 2 };
|
||||||
enum DD { DestIRAM = 0, DestBWRAM = 1 };
|
enum DD { DestIRAM = 0, DestBWRAM = 1 };
|
||||||
|
|
||||||
enum Mode { Inactive, Normal, CC1, CC2 } mode;
|
|
||||||
unsigned clocks;
|
|
||||||
bool tile;
|
|
||||||
unsigned line;
|
unsigned line;
|
||||||
} dma;
|
} dma;
|
||||||
|
|
||||||
|
|
|
@ -5,55 +5,35 @@
|
||||||
//==========================
|
//==========================
|
||||||
|
|
||||||
void SA1::op_io() {
|
void SA1::op_io() {
|
||||||
add_clocks(2);
|
tick();
|
||||||
if(regs.wai) scheduler.sync_copcpu();
|
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) {
|
uint8_t SA1::op_read(unsigned addr) {
|
||||||
add_clocks(bus_speed(addr));
|
tick();
|
||||||
|
if(is_bwram(addr)) tick();
|
||||||
scheduler.sync_copcpu();
|
scheduler.sync_copcpu();
|
||||||
regs.mdr = sa1bus.read(addr);
|
return sa1bus.read(addr);
|
||||||
cycle_edge();
|
|
||||||
return regs.mdr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SA1::op_write(unsigned addr, uint8_t data) {
|
void SA1::op_write(unsigned addr, uint8_t data) {
|
||||||
add_clocks(bus_speed(addr));
|
tick();
|
||||||
|
if(is_bwram(addr)) tick();
|
||||||
scheduler.sync_copcpu();
|
scheduler.sync_copcpu();
|
||||||
sa1bus.write(addr, regs.mdr = data);
|
sa1bus.write(addr, data);
|
||||||
cycle_edge();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SA1::cycle_edge() {
|
#undef is_bwram
|
||||||
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
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
void op_io();
|
alwaysinline void op_io();
|
||||||
uint8_t op_read(unsigned addr);
|
alwaysinline uint8_t op_read(unsigned addr);
|
||||||
void op_write(unsigned addr, uint8_t data);
|
alwaysinline void op_write(unsigned addr, uint8_t data);
|
||||||
void cycle_edge();
|
alwaysinline unsigned bus_speed(unsigned addr);
|
||||||
unsigned bus_speed(unsigned addr);
|
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
#ifdef SA1_CPP
|
#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
|
//(CCNT) SA-1 control
|
||||||
void SA1::mmio_w2200(uint8_t data) {
|
void SA1::mmio_w2200(uint8_t data) {
|
||||||
if(mmio.sa1_resb && !(data & 0x80)) {
|
if(mmio.sa1_resb && !(data & 0x80)) {
|
||||||
|
@ -86,17 +94,10 @@ void SA1::mmio_w2209(uint8_t data) {
|
||||||
|
|
||||||
//(CIE) SA-1 interrupt enable
|
//(CIE) SA-1 interrupt enable
|
||||||
void SA1::mmio_w220a(uint8_t data) {
|
void SA1::mmio_w220a(uint8_t data) {
|
||||||
if(!mmio.sa1_irqen && (data & 0x80)) {
|
if(!mmio.sa1_irqen && (data & 0x80) && mmio.sa1_irqfl ) mmio.sa1_irqcl = 0;
|
||||||
if(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;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
mmio.sa1_irqen = (data & 0x80);
|
mmio.sa1_irqen = (data & 0x80);
|
||||||
mmio.timer_irqen = (data & 0x40);
|
mmio.timer_irqen = (data & 0x40);
|
||||||
|
@ -112,6 +113,7 @@ void SA1::mmio_w220b(uint8_t data) {
|
||||||
mmio.sa1_nmicl = (data & 0x10);
|
mmio.sa1_nmicl = (data & 0x10);
|
||||||
|
|
||||||
if(mmio.sa1_irqcl) mmio.sa1_irqfl = 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.dma_irqcl) mmio.dma_irqfl = false;
|
||||||
if(mmio.sa1_nmicl) mmio.sa1_nmifl = false;
|
if(mmio.sa1_nmicl) mmio.sa1_nmifl = false;
|
||||||
}
|
}
|
||||||
|
@ -150,10 +152,21 @@ void SA1::mmio_w2220(uint8_t data) {
|
||||||
mmio.cbmode = (data & 0x80);
|
mmio.cbmode = (data & 0x80);
|
||||||
mmio.cb = (data & 0x07);
|
mmio.cb = (data & 0x07);
|
||||||
|
|
||||||
bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom, (mmio.cbmode == 0) ? 0x000000 : (mmio.cb << 20));
|
unsigned addr = mmio.cb << 20;
|
||||||
sa1bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom, (mmio.cbmode == 0) ? 0x000000 : (mmio.cb << 20));
|
Memory &access = mmio_access(addr);
|
||||||
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);
|
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
|
//(DXB) Super MMC bank D
|
||||||
|
@ -161,10 +174,19 @@ void SA1::mmio_w2221(uint8_t data) {
|
||||||
mmio.dbmode = (data & 0x80);
|
mmio.dbmode = (data & 0x80);
|
||||||
mmio.db = (data & 0x07);
|
mmio.db = (data & 0x07);
|
||||||
|
|
||||||
bus.map(Bus::MapLinear, 0x20, 0x3f, 0x8000, 0xffff, memory::cartrom, (mmio.dbmode == 0) ? 0x100000 : (mmio.db << 20));
|
unsigned addr = mmio.db << 20;
|
||||||
sa1bus.map(Bus::MapLinear, 0x20, 0x3f, 0x8000, 0xffff, memory::cartrom, (mmio.dbmode == 0) ? 0x100000 : (mmio.db << 20));
|
Memory &access = mmio_access(addr);
|
||||||
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);
|
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
|
//(EXB) Super MMC bank E
|
||||||
|
@ -172,10 +194,19 @@ void SA1::mmio_w2222(uint8_t data) {
|
||||||
mmio.ebmode = (data & 0x80);
|
mmio.ebmode = (data & 0x80);
|
||||||
mmio.eb = (data & 0x07);
|
mmio.eb = (data & 0x07);
|
||||||
|
|
||||||
bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom, (mmio.ebmode == 0) ? 0x200000 : (mmio.eb << 20));
|
unsigned addr = mmio.eb << 20;
|
||||||
sa1bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom, (mmio.ebmode == 0) ? 0x200000 : (mmio.eb << 20));
|
Memory &access = mmio_access(addr);
|
||||||
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);
|
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
|
//(FXB) Super MMC bank F
|
||||||
|
@ -183,18 +214,27 @@ void SA1::mmio_w2223(uint8_t data) {
|
||||||
mmio.fbmode = (data & 0x80);
|
mmio.fbmode = (data & 0x80);
|
||||||
mmio.fb = (data & 0x07);
|
mmio.fb = (data & 0x07);
|
||||||
|
|
||||||
bus.map(Bus::MapLinear, 0xa0, 0xbf, 0x8000, 0xffff, memory::cartrom, (mmio.fbmode == 0) ? 0x300000 : (mmio.fb << 20));
|
unsigned addr = mmio.fb << 20;
|
||||||
sa1bus.map(Bus::MapLinear, 0xa0, 0xbf, 0x8000, 0xffff, memory::cartrom, (mmio.fbmode == 0) ? 0x300000 : (mmio.fb << 20));
|
Memory &access = mmio_access(addr);
|
||||||
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);
|
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
|
//(BMAPS) S-CPU BW-RAM address mapping
|
||||||
void SA1::mmio_w2224(uint8_t data) {
|
void SA1::mmio_w2224(uint8_t data) {
|
||||||
mmio.sbm = (data & 0x1f);
|
mmio.sbm = (data & 0x1f);
|
||||||
|
|
||||||
bus.map(Bus::MapLinear, 0x00, 0x3f, 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::cpu::bwram, 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
|
//(BMAP) SA-1 BW-RAM address mapping
|
||||||
|
@ -204,12 +244,12 @@ void SA1::mmio_w2225(uint8_t data) {
|
||||||
|
|
||||||
if(mmio.sw46 == 0) {
|
if(mmio.sw46 == 0) {
|
||||||
//$[40-43]:[0000-ffff] x 32 projection
|
//$[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, 0x00, 0x3f, 0x6000, 0x7fff, memory::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, 0x80, 0xbf, 0x6000, 0x7fff, memory::bwram, (mmio.cbm & 0x1f) * 0x2000, 0x2000);
|
||||||
} else {
|
} else {
|
||||||
//$[60-6f]:[0000-ffff] x 128 projection
|
//$[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, 0x00, 0x3f, 0x6000, 0x7fff, memory::bitmapram, mmio.cbm * 0x2000, 0x2000);
|
||||||
sa1bus.map(Bus::MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::sa1::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.dmasize = (data >> 2) & 7;
|
||||||
mmio.dmacb = (data & 0x03);
|
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.dmasize > 5) mmio.dmasize = 5;
|
||||||
if(mmio.dmacb > 2) mmio.dmacb = 2;
|
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) {
|
void SA1::mmio_w2236(uint8_t data) {
|
||||||
mmio.dda = (mmio.dda & 0xff00ff) | (data << 8);
|
mmio.dda = (mmio.dda & 0xff00ff) | (data << 8);
|
||||||
|
|
||||||
if(dma.mode == DMA::Inactive) {
|
if(mmio.dmaen == true) {
|
||||||
if(mmio.cden == 0 && mmio.dd == DMA::DestIRAM) {
|
if(mmio.cden == 0 && mmio.dd == DMA::DestIRAM) {
|
||||||
dma.mode = DMA::Normal;
|
dma_normal();
|
||||||
} else if(mmio.cden == 1 && mmio.cdsel == 1) {
|
} 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) {
|
void SA1::mmio_w2237(uint8_t data) {
|
||||||
mmio.dda = (mmio.dda & 0x00ffff) | (data << 16);
|
mmio.dda = (mmio.dda & 0x00ffff) | (data << 16);
|
||||||
|
|
||||||
if(dma.mode == DMA::Inactive) {
|
if(mmio.dmaen == true) {
|
||||||
if(mmio.cden == 0 && mmio.dd == DMA::DestBWRAM) {
|
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_w2245(uint8_t data) { mmio.brf[ 5] = data; }
|
||||||
void SA1::mmio_w2246(uint8_t data) { mmio.brf[ 6] = data; }
|
void SA1::mmio_w2246(uint8_t data) { mmio.brf[ 6] = data; }
|
||||||
void SA1::mmio_w2247(uint8_t data) { mmio.brf[ 7] = 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) {
|
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_w224d(uint8_t data) { mmio.brf[13] = data; }
|
||||||
void SA1::mmio_w224e(uint8_t data) { mmio.brf[14] = data; }
|
void SA1::mmio_w224e(uint8_t data) { mmio.brf[14] = data; }
|
||||||
void SA1::mmio_w224f(uint8_t data) { mmio.brf[15] = 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) {
|
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.mr += (int16_t)mmio.ma * (int16_t)mmio.mb;
|
||||||
mmio.overflow = (mmio.mr >= (1ULL << 40));
|
mmio.overflow = (mmio.mr >= (1ULL << 40));
|
||||||
mmio.mr &= (1ULL << 40) - 1;
|
mmio.mr &= (1ULL << 40) - 1;
|
||||||
mmio.ma = 0;
|
mmio.mb = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
uint8_t mmio_read(unsigned addr);
|
uint8_t mmio_read(unsigned addr);
|
||||||
void mmio_write(unsigned addr, uint8_t data);
|
void mmio_write(unsigned addr, uint8_t data);
|
||||||
|
Memory& mmio_access(unsigned &addr);
|
||||||
|
|
||||||
struct MMIO {
|
struct MMIO {
|
||||||
//$2200 CCNT
|
//$2200 CCNT
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <../base.hpp>
|
#include <../base.hpp>
|
||||||
#include <../cart/cart.hpp>
|
#include <../cart/cart.hpp>
|
||||||
|
#include <../chip/bsx/bsx.hpp>
|
||||||
#define SA1_CPP
|
#define SA1_CPP
|
||||||
|
|
||||||
#include "sa1.hpp"
|
#include "sa1.hpp"
|
||||||
|
@ -12,17 +13,10 @@ void SA1::enter() {
|
||||||
while(true) {
|
while(true) {
|
||||||
while(mmio.sa1_rdyb || mmio.sa1_resb) {
|
while(mmio.sa1_rdyb || mmio.sa1_resb) {
|
||||||
//SA-1 co-processor is asleep
|
//SA-1 co-processor is asleep
|
||||||
add_clocks(4);
|
tick();
|
||||||
scheduler.sync_copcpu();
|
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) {
|
if(status.interrupt_pending) {
|
||||||
status.interrupt_pending = false;
|
status.interrupt_pending = false;
|
||||||
interrupt(status.interrupt_vector);
|
interrupt(status.interrupt_vector);
|
||||||
|
@ -39,33 +33,23 @@ void SA1::last_cycle() {
|
||||||
mmio.sa1_nmifl = true;
|
mmio.sa1_nmifl = true;
|
||||||
mmio.sa1_nmicl = 1;
|
mmio.sa1_nmicl = 1;
|
||||||
regs.wai = false;
|
regs.wai = false;
|
||||||
return;
|
} else if(!regs.p.i) {
|
||||||
}
|
|
||||||
|
|
||||||
if(mmio.timer_irqen && !mmio.timer_irqcl) {
|
if(mmio.timer_irqen && !mmio.timer_irqcl) {
|
||||||
status.interrupt_pending = true;
|
status.interrupt_pending = true;
|
||||||
status.interrupt_vector = mmio.civ;
|
status.interrupt_vector = mmio.civ;
|
||||||
mmio.timer_irqfl = true;
|
mmio.timer_irqfl = true;
|
||||||
mmio.timer_irqcl = 1;
|
|
||||||
regs.wai = false;
|
regs.wai = false;
|
||||||
return;
|
} else if(mmio.dma_irqen && !mmio.dma_irqcl) {
|
||||||
}
|
|
||||||
|
|
||||||
if(mmio.dma_irqen && !mmio.dma_irqcl) {
|
|
||||||
status.interrupt_pending = true;
|
status.interrupt_pending = true;
|
||||||
status.interrupt_vector = mmio.civ;
|
status.interrupt_vector = mmio.civ;
|
||||||
mmio.dma_irqfl = true;
|
mmio.dma_irqfl = true;
|
||||||
mmio.dma_irqcl = 1;
|
|
||||||
regs.wai = false;
|
regs.wai = false;
|
||||||
return;
|
} else if(mmio.sa1_irq && !mmio.sa1_irqcl) {
|
||||||
}
|
|
||||||
|
|
||||||
if(!regs.p.i && mmio.sa1_irq && !mmio.sa1_irqcl) {
|
|
||||||
status.interrupt_pending = true;
|
status.interrupt_pending = true;
|
||||||
status.interrupt_vector = mmio.civ;
|
status.interrupt_vector = mmio.civ;
|
||||||
mmio.sa1_irqfl = true;
|
mmio.sa1_irqfl = true;
|
||||||
regs.wai = false;
|
regs.wai = false;
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +60,6 @@ void SA1::interrupt(uint16_t vector) {
|
||||||
op_writestack(regs.pc.h);
|
op_writestack(regs.pc.h);
|
||||||
op_writestack(regs.pc.l);
|
op_writestack(regs.pc.l);
|
||||||
op_writestack(regs.e ? (regs.p & ~0x10) : regs.p);
|
op_writestack(regs.e ? (regs.p & ~0x10) : regs.p);
|
||||||
add_clocks(8);
|
|
||||||
regs.pc.w = vector;
|
regs.pc.w = vector;
|
||||||
regs.pc.b = 0x00;
|
regs.pc.b = 0x00;
|
||||||
regs.p.i = 1;
|
regs.p.i = 1;
|
||||||
|
@ -87,47 +70,37 @@ bool SA1::interrupt_pending() {
|
||||||
return status.interrupt_pending;
|
return status.interrupt_pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SA1::add_clocks(unsigned clocks) {
|
void SA1::tick() {
|
||||||
scheduler.addclocks_cop(clocks);
|
scheduler.addclocks_cop(2);
|
||||||
|
|
||||||
uint16_t last_hcounter = status.hcounter;
|
|
||||||
uint16_t last_vcounter = status.vcounter;
|
|
||||||
|
|
||||||
//adjust counters:
|
//adjust counters:
|
||||||
//note that internally, status counters are in clocks;
|
//note that internally, status counters are in clocks;
|
||||||
//whereas MMIO register counters are in dots (4 clocks = 1 dot)
|
//whereas MMIO register counters are in dots (4 clocks = 1 dot)
|
||||||
if(mmio.hvselb == 0) {
|
if(mmio.hvselb == 0) {
|
||||||
//HV timer
|
//HV timer
|
||||||
status.hcounter += clocks;
|
status.hcounter += 2;
|
||||||
if(status.hcounter >= 1364) {
|
if(status.hcounter >= 1364) {
|
||||||
status.hcounter -= 1364;
|
status.hcounter = 0;
|
||||||
status.vcounter++;
|
if(++status.vcounter >= status.scanlines) status.vcounter = 0;
|
||||||
if(status.vcounter >= status.scanlines) {
|
|
||||||
status.vcounter = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//linear timer
|
//linear timer
|
||||||
status.hcounter += clocks;
|
status.hcounter += 2;
|
||||||
status.vcounter += (status.hcounter >> 11);
|
status.vcounter += (status.hcounter >> 11);
|
||||||
status.hcounter &= 0x07ff;
|
status.hcounter &= 0x07ff;
|
||||||
status.vcounter &= 0x01ff;
|
status.vcounter &= 0x01ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
//test counters for timer IRQ
|
//test counters for timer IRQ
|
||||||
uint32_t lo = (last_vcounter << 11) + last_hcounter;
|
switch((mmio.ven << 1) + (mmio.hen << 0)) {
|
||||||
uint32_t hi = (status.vcounter << 11) + status.hcounter;
|
case 0: break;
|
||||||
uint32_t trigger = (mmio.vcnt << 11) + (mmio.hcnt << 2);
|
case 1: if(status.hcounter == (mmio.hcnt << 2)) trigger_irq(); break;
|
||||||
|
case 2: if(status.vcounter == mmio.vcnt && status.hcounter == 0) trigger_irq(); break;
|
||||||
if(lo > hi) {
|
case 3: if(status.vcounter == mmio.hcnt && status.hcounter == (mmio.hcnt << 2)) trigger_irq(); break;
|
||||||
if(trigger <= hi) goto trigger_irq;
|
|
||||||
hi += 1 << 20;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(lo < trigger && trigger <= hi) goto trigger_irq;
|
void SA1::trigger_irq() {
|
||||||
return;
|
|
||||||
|
|
||||||
trigger_irq:
|
|
||||||
mmio.timer_irqfl = true;
|
mmio.timer_irqfl = true;
|
||||||
if(mmio.timer_irqen) mmio.timer_irqcl = 0;
|
if(mmio.timer_irqen) mmio.timer_irqcl = 0;
|
||||||
}
|
}
|
||||||
|
@ -146,6 +119,11 @@ void SA1::power() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SA1::reset() {
|
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();
|
sa1bus.init();
|
||||||
|
|
||||||
regs.pc.d = 0x000000;
|
regs.pc.d = 0x000000;
|
||||||
|
@ -160,18 +138,13 @@ void SA1::reset() {
|
||||||
regs.wai = false;
|
regs.wai = false;
|
||||||
update_table();
|
update_table();
|
||||||
|
|
||||||
memset(iram, 0, sizeof iram);
|
|
||||||
|
|
||||||
status.interrupt_pending = false;
|
status.interrupt_pending = false;
|
||||||
status.interrupt_vector = 0x0000;
|
status.interrupt_vector = 0x0000;
|
||||||
|
|
||||||
status.scanlines = (snes.region() == SNES::NTSC ? 261 : 311);
|
status.scanlines = (snes.region() == SNES::NTSC ? 262 : 312);
|
||||||
status.vcounter = 0;
|
status.vcounter = 0;
|
||||||
status.hcounter = 0;
|
status.hcounter = 0;
|
||||||
|
|
||||||
dma.mode = DMA::Inactive;
|
|
||||||
dma.clocks = 4;
|
|
||||||
dma.tile = 0;
|
|
||||||
dma.line = 0;
|
dma.line = 0;
|
||||||
|
|
||||||
//$2200 CCNT
|
//$2200 CCNT
|
||||||
|
|
|
@ -5,7 +5,6 @@ public:
|
||||||
#include "dma/dma.hpp"
|
#include "dma/dma.hpp"
|
||||||
#include "memory/memory.hpp"
|
#include "memory/memory.hpp"
|
||||||
#include "mmio/mmio.hpp"
|
#include "mmio/mmio.hpp"
|
||||||
uint8_t iram[2048];
|
|
||||||
|
|
||||||
struct Status {
|
struct Status {
|
||||||
bool interrupt_pending;
|
bool interrupt_pending;
|
||||||
|
@ -18,10 +17,11 @@ public:
|
||||||
|
|
||||||
void enter();
|
void enter();
|
||||||
void interrupt(uint16_t vector);
|
void interrupt(uint16_t vector);
|
||||||
void add_clocks(unsigned);
|
void tick();
|
||||||
|
|
||||||
void last_cycle();
|
alwaysinline void trigger_irq();
|
||||||
bool interrupt_pending();
|
alwaysinline void last_cycle();
|
||||||
|
alwaysinline bool interrupt_pending();
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void enable();
|
void enable();
|
||||||
|
|
|
@ -11,7 +11,7 @@ void SDD1::enable() {
|
||||||
//hook S-CPU DMA MMIO registers to gather information for struct dma[];
|
//hook S-CPU DMA MMIO registers to gather information for struct dma[];
|
||||||
//buffer address and transfer size information for use in SDD1::read()
|
//buffer address and transfer size information for use in SDD1::read()
|
||||||
for(unsigned i = 0x4300; i <= 0x437f; i++) {
|
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);
|
memory::mmio.map(i, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,8 +73,7 @@ struct regs_t {
|
||||||
|
|
||||||
bool irq; //IRQ pin (0 = low, 1 = trigger)
|
bool irq; //IRQ pin (0 = low, 1 = trigger)
|
||||||
bool wai; //raised during wai, cleared after interrupt triggered
|
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
|
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
|
#ifdef SCPU_CPP
|
||||||
|
|
||||||
void sCPU::op_io() {
|
void sCPU::op_io() {
|
||||||
regs.bus = -1U;
|
|
||||||
status.clock_count = 6;
|
status.clock_count = 6;
|
||||||
precycle_edge();
|
precycle_edge();
|
||||||
add_clocks(6);
|
add_clocks(6);
|
||||||
|
@ -10,7 +9,7 @@ void sCPU::op_io() {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 sCPU::op_read(uint32 addr) {
|
uint8 sCPU::op_read(uint32 addr) {
|
||||||
status.clock_count = speed(regs.bus = addr);
|
status.clock_count = speed(addr);
|
||||||
precycle_edge();
|
precycle_edge();
|
||||||
add_clocks(status.clock_count - 4);
|
add_clocks(status.clock_count - 4);
|
||||||
|
|
||||||
|
@ -23,7 +22,7 @@ uint8 sCPU::op_read(uint32 addr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void sCPU::op_write(uint32 addr, uint8 data) {
|
void sCPU::op_write(uint32 addr, uint8 data) {
|
||||||
status.clock_count = speed(regs.bus = addr);
|
status.clock_count = speed(addr);
|
||||||
precycle_edge();
|
precycle_edge();
|
||||||
add_clocks(status.clock_count);
|
add_clocks(status.clock_count);
|
||||||
|
|
||||||
|
|
|
@ -12,10 +12,6 @@ priority_queue<unsigned> event(512, bind(&sCPU::queue_event, &cpu));
|
||||||
void sCPU::enter() {
|
void sCPU::enter() {
|
||||||
regs.pc.l = bus.read(0xfffc);
|
regs.pc.l = bus.read(0xfffc);
|
||||||
regs.pc.h = bus.read(0xfffd);
|
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);
|
add_clocks(186);
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
|
|
|
@ -26,12 +26,12 @@ void sCPU::scanline() {
|
||||||
status.dma_counter = (status.dma_counter + status.line_clocks) & 7;
|
status.dma_counter = (status.dma_counter + status.line_clocks) & 7;
|
||||||
status.line_clocks = ppu.lineclocks();
|
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) {
|
if(ppu.vcounter() == 0) {
|
||||||
//hdma init triggers once every frame
|
//hdma init triggers once every frame
|
||||||
event.enqueue(cpu_version == 1 ? 12 + 8 - dma_counter() : 12 + dma_counter(), EventHdmaInit);
|
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
|
//dram refresh occurs once every scanline
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#define REG(n) state.regs[r_##n]
|
#define REG(n) state.regs[r_##n]
|
||||||
#define VREG(n) state.regs[v.vidx + v_##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_start() while(true) {
|
||||||
#define phase(n)
|
#define phase(n)
|
||||||
#define tick() scheduler.addclocks_dsp(3 * 8); scheduler.sync_dspsmp()
|
#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[(addr - 0x2000) & 0x3fff] = &access;
|
||||||
}
|
}
|
||||||
|
|
||||||
MMIO* MMIOAccess::get(unsigned addr) {
|
|
||||||
return mmio[(addr - 0x2000) & 0x3fff];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8 MMIOAccess::read(unsigned addr) {
|
uint8 MMIOAccess::read(unsigned addr) {
|
||||||
return mmio[(addr - 0x2000) & 0x3fff]->mmio_read(addr);
|
return mmio[(addr - 0x2000) & 0x3fff]->mmio_read(addr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,16 +56,13 @@ private:
|
||||||
|
|
||||||
struct MMIOAccess : Memory {
|
struct MMIOAccess : Memory {
|
||||||
void map(unsigned addr, MMIO &access);
|
void map(unsigned addr, MMIO &access);
|
||||||
MMIO* get(unsigned addr);
|
|
||||||
uint8 read(unsigned addr);
|
uint8 read(unsigned addr);
|
||||||
void write(unsigned addr, uint8 data);
|
void write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
private:
|
|
||||||
MMIO *mmio[0x4000];
|
MMIO *mmio[0x4000];
|
||||||
};
|
};
|
||||||
|
|
||||||
class Bus {
|
struct Bus {
|
||||||
public:
|
|
||||||
unsigned mirror(unsigned addr, unsigned size);
|
unsigned mirror(unsigned addr, unsigned size);
|
||||||
void map(unsigned addr, Memory &access, unsigned offset);
|
void map(unsigned addr, Memory &access, unsigned offset);
|
||||||
enum MapMode { MapDirect, MapLinear, MapShadow };
|
enum MapMode { MapDirect, MapLinear, MapShadow };
|
||||||
|
@ -100,7 +97,6 @@ public:
|
||||||
Bus() {}
|
Bus() {}
|
||||||
virtual ~Bus() {}
|
virtual ~Bus() {}
|
||||||
|
|
||||||
protected:
|
|
||||||
struct Page {
|
struct Page {
|
||||||
Memory *access;
|
Memory *access;
|
||||||
unsigned offset;
|
unsigned offset;
|
||||||
|
|
|
@ -16,11 +16,11 @@ void sSMP::enter() {
|
||||||
|
|
||||||
//forcefully sync S-CPU and S-SMP, in case chips are not communicating
|
//forcefully sync S-CPU and S-SMP, in case chips are not communicating
|
||||||
static unsigned counter = 0;
|
static unsigned counter = 0;
|
||||||
if(++counter & 4096) {
|
if(++counter >= 128) {
|
||||||
counter = 0;
|
counter = 0;
|
||||||
scheduler.sync_smpcpu();
|
scheduler.sync_smpcpu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //ifdef SSMP_CPP
|
#endif
|
||||||
|
|
|
@ -6,12 +6,6 @@
|
||||||
#include "timing/timing.cpp"
|
#include "timing/timing.cpp"
|
||||||
|
|
||||||
void sSMP::power() {
|
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
|
//targets not initialized/changed upon reset
|
||||||
t0.target = 0;
|
t0.target = 0;
|
||||||
t1.target = 0;
|
t1.target = 0;
|
||||||
|
@ -28,6 +22,10 @@ void sSMP::reset() {
|
||||||
regs.sp = 0xef;
|
regs.sp = 0xef;
|
||||||
regs.p = 0x02;
|
regs.p = 0x02;
|
||||||
|
|
||||||
|
for(unsigned i = 0; i < memory::apuram.size(); i++) {
|
||||||
|
memory::apuram.write(i, 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
status.clock_counter = 0;
|
status.clock_counter = 0;
|
||||||
status.dsp_counter = 0;
|
status.dsp_counter = 0;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
void sSMP::add_clocks(unsigned clocks) {
|
void sSMP::add_clocks(unsigned clocks) {
|
||||||
scheduler.addclocks_smp(clocks);
|
scheduler.addclocks_smp(clocks);
|
||||||
#if !defined(USE_STATE_MACHINE)
|
#if !defined(DSP_STATE_MACHINE)
|
||||||
scheduler.sync_smpdsp();
|
scheduler.sync_smpdsp();
|
||||||
#else
|
#else
|
||||||
while(scheduler.clock.smpdsp < 0) dsp.enter();
|
while(scheduler.clock.smpdsp < 0) dsp.enter();
|
||||||
|
|
Loading…
Reference in New Issue