mirror of
https://github.com/ares-emulator/ares.git
synced 2026-11-08 17:03:47 -10:00
n64: large refactoring to introduce timing in memory handlers
This very boring commit should basically produce no changes. It just make sure all devices can now step the CPU while the I/O is in progress, if needed.
This commit is contained in:
1 parent
21c985b3da
commit
ad16c4a67a
33 files changed
+363
-262
No files matched your search
+3
-3
@@ -1,6 +1,6 @@
|
||||
//Audio Interface
|
||||
|
||||
struct AI : Thread, Memory::IO<AI> {
|
||||
struct AI : Thread, Memory::RCP<AI> {
|
||||
Node::Object node;
|
||||
Node::Audio::Stream stream;
|
||||
|
||||
@@ -23,8 +23,8 @@ struct AI : Thread, Memory::IO<AI> {
|
||||
auto power(bool reset) -> void;
|
||||
|
||||
//io.cpp
|
||||
auto readWord(u32 address) -> u32;
|
||||
auto writeWord(u32 address, u32 data) -> void;
|
||||
auto readWord(u32 address, u32& cycles) -> u32;
|
||||
auto writeWord(u32 address, u32 data, u32& cycles) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
auto AI::readWord(u32 address) -> u32 {
|
||||
auto AI::readWord(u32 address, u32& cycles) -> u32 {
|
||||
address = (address & 0xfffff) >> 2;
|
||||
n32 data;
|
||||
|
||||
@@ -21,7 +21,7 @@ auto AI::readWord(u32 address) -> u32 {
|
||||
return data;
|
||||
}
|
||||
|
||||
auto AI::writeWord(u32 address, u32 data_) -> void {
|
||||
auto AI::writeWord(u32 address, u32 data_, u32& cycles) -> void {
|
||||
address = (address & 0xfffff) >> 2;
|
||||
n32 data = data_;
|
||||
|
||||
|
||||
@@ -38,10 +38,12 @@ struct Cartridge {
|
||||
u32 source = 0;
|
||||
u32 offset = 0;
|
||||
} flash;
|
||||
struct ISViewer : Memory::IO<ISViewer> {
|
||||
struct ISViewer : Memory::PI<ISViewer> {
|
||||
Memory::Writable ram; //unserialized
|
||||
|
||||
//isviewer.cpp
|
||||
auto readHalf(u32 address) -> u16;
|
||||
auto writeHalf(u32 address, u16 data) -> void;
|
||||
auto readWord(u32 address) -> u32;
|
||||
auto writeWord(u32 address, u32 data) -> void;
|
||||
} isviewer;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
auto Cartridge::ISViewer::readWord(u32 address) -> u32 {
|
||||
auto Cartridge::ISViewer::readHalf(u32 address) -> u16 {
|
||||
address = (address & 0xffff);
|
||||
u32 data = ram.read<Word>(address);
|
||||
return data;
|
||||
return ram.read<Half>(address);
|
||||
}
|
||||
|
||||
auto Cartridge::ISViewer::writeWord(u32 address, u32 data) -> void {
|
||||
auto Cartridge::ISViewer::writeHalf(u32 address, u16 data) -> void {
|
||||
address = (address & 0xffff);
|
||||
|
||||
if(address == 0x14) {
|
||||
@@ -17,12 +16,24 @@ auto Cartridge::ISViewer::writeWord(u32 address, u32 data) -> void {
|
||||
// In order to satisfy both libraries, we assume it behaves as libdragon
|
||||
// expects, and by forcing the write to never hit ram, libultra remains
|
||||
// functional.
|
||||
for(auto address : range(u16(data))) {
|
||||
for(auto address : range(data)) {
|
||||
char c = ram.read<Byte>(0x20 + address);
|
||||
fputc(c, stdout);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ram.write<Word>(address, data);
|
||||
ram.write<Half>(address, data);
|
||||
}
|
||||
|
||||
auto Cartridge::ISViewer::readWord(u32 address) -> u32 {
|
||||
address = (address & 0xffff);
|
||||
return ram.read<Word>(address);
|
||||
}
|
||||
|
||||
auto Cartridge::ISViewer::writeWord(u32 address, u32 data) -> void {
|
||||
address = (address & 0xffff);
|
||||
ram.write<Half>(address+0, data >> 16);
|
||||
ram.write<Word>(address+2, data & 0xffff);
|
||||
}
|
||||
|
||||
+18
-16
@@ -147,26 +147,26 @@ struct CPU : Thread {
|
||||
cpu.step(48);
|
||||
valid = 1;
|
||||
tag = address & ~0x0000'0fff;
|
||||
words[0] = bus.read<Word>(tag | index | 0x00);
|
||||
words[1] = bus.read<Word>(tag | index | 0x04);
|
||||
words[2] = bus.read<Word>(tag | index | 0x08);
|
||||
words[3] = bus.read<Word>(tag | index | 0x0c);
|
||||
words[4] = bus.read<Word>(tag | index | 0x10);
|
||||
words[5] = bus.read<Word>(tag | index | 0x14);
|
||||
words[6] = bus.read<Word>(tag | index | 0x18);
|
||||
words[7] = bus.read<Word>(tag | index | 0x1c);
|
||||
words[0] = cpu.busRead<Word>(tag | index | 0x00);
|
||||
words[1] = cpu.busRead<Word>(tag | index | 0x04);
|
||||
words[2] = cpu.busRead<Word>(tag | index | 0x08);
|
||||
words[3] = cpu.busRead<Word>(tag | index | 0x0c);
|
||||
words[4] = cpu.busRead<Word>(tag | index | 0x10);
|
||||
words[5] = cpu.busRead<Word>(tag | index | 0x14);
|
||||
words[6] = cpu.busRead<Word>(tag | index | 0x18);
|
||||
words[7] = cpu.busRead<Word>(tag | index | 0x1c);
|
||||
}
|
||||
|
||||
auto writeBack(CPU& cpu) -> void {
|
||||
cpu.step(48);
|
||||
bus.write<Word>(tag | index | 0x00, words[0]);
|
||||
bus.write<Word>(tag | index | 0x04, words[1]);
|
||||
bus.write<Word>(tag | index | 0x08, words[2]);
|
||||
bus.write<Word>(tag | index | 0x0c, words[3]);
|
||||
bus.write<Word>(tag | index | 0x10, words[4]);
|
||||
bus.write<Word>(tag | index | 0x14, words[5]);
|
||||
bus.write<Word>(tag | index | 0x18, words[6]);
|
||||
bus.write<Word>(tag | index | 0x1c, words[7]);
|
||||
cpu.busWrite<Word>(tag | index | 0x00, words[0]);
|
||||
cpu.busWrite<Word>(tag | index | 0x04, words[1]);
|
||||
cpu.busWrite<Word>(tag | index | 0x08, words[2]);
|
||||
cpu.busWrite<Word>(tag | index | 0x0c, words[3]);
|
||||
cpu.busWrite<Word>(tag | index | 0x10, words[4]);
|
||||
cpu.busWrite<Word>(tag | index | 0x14, words[5]);
|
||||
cpu.busWrite<Word>(tag | index | 0x18, words[6]);
|
||||
cpu.busWrite<Word>(tag | index | 0x1c, words[7]);
|
||||
}
|
||||
|
||||
auto read(u32 address) const -> u32 { return words[address >> 2 & 7]; }
|
||||
@@ -260,6 +260,8 @@ struct CPU : Thread {
|
||||
auto segment(u64 vaddr) -> Context::Segment;
|
||||
auto devirtualize(u64 vaddr) -> maybe<u64>;
|
||||
auto fetch(u64 vaddr) -> u32;
|
||||
template<u32 Size> auto busWrite(u32 address, u64 data) -> void;
|
||||
template<u32 Size> auto busRead(u32 address) -> u64;
|
||||
template<u32 Size> auto read(u64 vaddr) -> maybe<u64>;
|
||||
template<u32 Size> auto write(u64 vaddr, u64 data) -> bool;
|
||||
auto addressException(u64 vaddr) -> void;
|
||||
|
||||
+20
-20
@@ -11,21 +11,21 @@ template<u32 Size> auto CPU::DataCache::Line::fill(u32 address, u64 data) -> voi
|
||||
switch(address & 8) {
|
||||
case 0:
|
||||
if constexpr(Size != Dual) {
|
||||
words[0] = bus.read<Word>(tag | index | 0x0);
|
||||
words[1] = bus.read<Word>(tag | index | 0x4);
|
||||
words[0] = cpu.busRead<Word>(tag | index | 0x0);
|
||||
words[1] = cpu.busRead<Word>(tag | index | 0x4);
|
||||
}
|
||||
write<Size>(address, data);
|
||||
words[2] = bus.read<Word>(tag | index | 0x8);
|
||||
words[3] = bus.read<Word>(tag | index | 0xc);
|
||||
words[2] = cpu.busRead<Word>(tag | index | 0x8);
|
||||
words[3] = cpu.busRead<Word>(tag | index | 0xc);
|
||||
break;
|
||||
case 8:
|
||||
if constexpr(Size != Dual) {
|
||||
words[2] = bus.read<Word>(tag | index | 0x8);
|
||||
words[3] = bus.read<Word>(tag | index | 0xc);
|
||||
words[2] = cpu.busRead<Word>(tag | index | 0x8);
|
||||
words[3] = cpu.busRead<Word>(tag | index | 0xc);
|
||||
}
|
||||
write<Size>(address, data);
|
||||
words[0] = bus.read<Word>(tag | index | 0x0);
|
||||
words[1] = bus.read<Word>(tag | index | 0x4);
|
||||
words[0] = cpu.busRead<Word>(tag | index | 0x0);
|
||||
words[1] = cpu.busRead<Word>(tag | index | 0x4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -38,16 +38,16 @@ auto CPU::DataCache::Line::fill(u32 address) -> void {
|
||||
//read words according to critical doubleword first scheme
|
||||
switch(address & 8) {
|
||||
case 0:
|
||||
words[0] = bus.read<Word>(tag | index | 0x0);
|
||||
words[1] = bus.read<Word>(tag | index | 0x4);
|
||||
words[2] = bus.read<Word>(tag | index | 0x8);
|
||||
words[3] = bus.read<Word>(tag | index | 0xc);
|
||||
words[0] = cpu.busRead<Word>(tag | index | 0x0);
|
||||
words[1] = cpu.busRead<Word>(tag | index | 0x4);
|
||||
words[2] = cpu.busRead<Word>(tag | index | 0x8);
|
||||
words[3] = cpu.busRead<Word>(tag | index | 0xc);
|
||||
break;
|
||||
case 8:
|
||||
words[2] = bus.read<Word>(tag | index | 0x8);
|
||||
words[3] = bus.read<Word>(tag | index | 0xc);
|
||||
words[0] = bus.read<Word>(tag | index | 0x0);
|
||||
words[1] = bus.read<Word>(tag | index | 0x4);
|
||||
words[2] = cpu.busRead<Word>(tag | index | 0x8);
|
||||
words[3] = cpu.busRead<Word>(tag | index | 0xc);
|
||||
words[0] = cpu.busRead<Word>(tag | index | 0x0);
|
||||
words[1] = cpu.busRead<Word>(tag | index | 0x4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -55,10 +55,10 @@ auto CPU::DataCache::Line::fill(u32 address) -> void {
|
||||
auto CPU::DataCache::Line::writeBack() -> void {
|
||||
cpu.step(40);
|
||||
dirty = 0;
|
||||
bus.write<Word>(tag | index | 0x0, words[0]);
|
||||
bus.write<Word>(tag | index | 0x4, words[1]);
|
||||
bus.write<Word>(tag | index | 0x8, words[2]);
|
||||
bus.write<Word>(tag | index | 0xc, words[3]);
|
||||
cpu.busWrite<Word>(tag | index | 0x0, words[0]);
|
||||
cpu.busWrite<Word>(tag | index | 0x4, words[1]);
|
||||
cpu.busWrite<Word>(tag | index | 0x8, words[2]);
|
||||
cpu.busWrite<Word>(tag | index | 0xc, words[3]);
|
||||
}
|
||||
|
||||
auto CPU::DataCache::line(u32 address) -> Line& {
|
||||
|
||||
+23
-9
@@ -108,6 +108,20 @@ auto CPU::devirtualize(u64 vaddr) -> maybe<u64> {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
template<u32 Size>
|
||||
inline auto CPU::busWrite(u32 address, u64 data) -> void {
|
||||
u32 cycles = 0;
|
||||
bus.write<Size>(address, data, cycles);
|
||||
step(cycles);
|
||||
}
|
||||
|
||||
template<u32 Size>
|
||||
inline auto CPU::busRead(u32 address) -> u64 {
|
||||
u32 cycles = 0; u64 data;
|
||||
data = bus.read<Size>(address, cycles);
|
||||
return step(cycles), data;
|
||||
}
|
||||
|
||||
auto CPU::fetch(u64 vaddr) -> u32 {
|
||||
switch(segment(vaddr)) {
|
||||
case Context::Segment::Unused:
|
||||
@@ -119,7 +133,7 @@ auto CPU::fetch(u64 vaddr) -> u32 {
|
||||
if(auto match = tlb.load(vaddr)) {
|
||||
if(match.cache) return icache.fetch(match.address & context.physMask, cpu);
|
||||
step(1);
|
||||
return bus.read<Word>(match.address & context.physMask);
|
||||
return busRead<Word>(match.address & context.physMask);
|
||||
}
|
||||
step(1);
|
||||
addressException(vaddr);
|
||||
@@ -130,10 +144,10 @@ auto CPU::fetch(u64 vaddr) -> u32 {
|
||||
return icache.fetch(vaddr & 0xffff'ffff, cpu);
|
||||
case Context::Segment::Direct:
|
||||
step(1);
|
||||
return bus.read<Word>(vaddr & 0x1fff'ffff);
|
||||
return busRead<Word>(vaddr & 0x1fff'ffff);
|
||||
case Context::Segment::Direct32:
|
||||
step(1);
|
||||
return bus.read<Word>(vaddr & 0xffff'ffff);
|
||||
return busRead<Word>(vaddr & 0xffff'ffff);
|
||||
}
|
||||
|
||||
unreachable;
|
||||
@@ -166,7 +180,7 @@ auto CPU::read(u64 vaddr) -> maybe<u64> {
|
||||
if(auto match = tlb.load(vaddr)) {
|
||||
if(match.cache) return dcache.read<Size>(match.address & context.physMask);
|
||||
step(1);
|
||||
return bus.read<Size>(match.address & context.physMask);
|
||||
return busRead<Size>(match.address & context.physMask);
|
||||
}
|
||||
step(1);
|
||||
addressException(vaddr);
|
||||
@@ -177,10 +191,10 @@ auto CPU::read(u64 vaddr) -> maybe<u64> {
|
||||
return dcache.read<Size>(vaddr & 0xffff'ffff);
|
||||
case Context::Segment::Direct:
|
||||
step(1);
|
||||
return bus.read<Size>(vaddr & 0x1fff'ffff);
|
||||
return busRead<Size>(vaddr & 0x1fff'ffff);
|
||||
case Context::Segment::Direct32:
|
||||
step(1);
|
||||
return bus.read<Size>(vaddr & 0xffff'ffff);
|
||||
return busRead<Size>(vaddr & 0xffff'ffff);
|
||||
}
|
||||
|
||||
unreachable;
|
||||
@@ -213,7 +227,7 @@ auto CPU::write(u64 vaddr, u64 data) -> bool {
|
||||
if(auto match = tlb.store(vaddr)) {
|
||||
if(match.cache) return dcache.write<Size>(match.address & context.physMask, data), true;
|
||||
step(1);
|
||||
return bus.write<Size>(match.address & context.physMask, data), true;
|
||||
return busWrite<Size>(match.address & context.physMask, data), true;
|
||||
}
|
||||
step(1);
|
||||
addressException(vaddr);
|
||||
@@ -224,10 +238,10 @@ auto CPU::write(u64 vaddr, u64 data) -> bool {
|
||||
return dcache.write<Size>(vaddr & 0xffff'ffff, data), true;
|
||||
case Context::Segment::Direct:
|
||||
step(1);
|
||||
return bus.write<Size>(vaddr & 0x1fff'ffff, data), true;
|
||||
return busWrite<Size>(vaddr & 0x1fff'ffff, data), true;
|
||||
case Context::Segment::Direct32:
|
||||
step(1);
|
||||
return bus.write<Size>(vaddr & 0xffff'ffff, data), true;
|
||||
return busWrite<Size>(vaddr & 0xffff'ffff, data), true;
|
||||
}
|
||||
|
||||
unreachable;
|
||||
|
||||
@@ -24,9 +24,10 @@ auto CPU::Recompiler::emit(u32 address) -> Block* {
|
||||
auto block = (Block*)allocator.acquire(sizeof(Block));
|
||||
beginFunction(3);
|
||||
|
||||
u32 memCycles;
|
||||
bool hasBranched = 0;
|
||||
while(true) {
|
||||
u32 instruction = bus.read<Word>(address);
|
||||
u32 instruction = bus.read<Word>(address, memCycles);
|
||||
bool branched = emitEXECUTE(instruction);
|
||||
if(unlikely(instruction == 0x1000'ffff)) {
|
||||
//accelerate idle loops
|
||||
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
//Disk Drive
|
||||
|
||||
struct DD : Memory::IO<DD> {
|
||||
struct DD : Memory::PI<DD> {
|
||||
Node::Object obj;
|
||||
Node::Port port;
|
||||
Node::Peripheral node;
|
||||
@@ -65,6 +65,8 @@ struct DD : Memory::IO<DD> {
|
||||
auto rtcTickSecond() -> void;
|
||||
|
||||
//io.cpp
|
||||
auto readHalf(u32 address) -> u16;
|
||||
auto writeHalf(u32 address, u16 data) -> void;
|
||||
auto readWord(u32 address) -> u32;
|
||||
auto writeWord(u32 address, u32 data) -> void;
|
||||
|
||||
|
||||
+109
-97
@@ -1,31 +1,31 @@
|
||||
auto DD::readWord(u32 address) -> u32 {
|
||||
address = (address & 0x7f) >> 2;
|
||||
n32 data;
|
||||
auto DD::readHalf(u32 address) -> u16 {
|
||||
address = (address & 0x7f) >> 1;
|
||||
n16 data = 0;
|
||||
|
||||
//ASIC_DATA
|
||||
if(address == 0) {
|
||||
data.bit(16,31) = io.data;
|
||||
data.bit(0,15) = io.data;
|
||||
}
|
||||
|
||||
//ASIC_MISC_REG
|
||||
if(address == 1) {
|
||||
if(address == 2) {
|
||||
}
|
||||
|
||||
//ASIC_STATUS
|
||||
if(address == 2) {
|
||||
data.bit(16) = io.status.diskChanged;
|
||||
data.bit(17) = io.status.mechaError;
|
||||
data.bit(18) = io.status.writeProtect;
|
||||
data.bit(19) = io.status.headRetracted;
|
||||
data.bit(20) = io.status.spindleMotorStopped;
|
||||
data.bit(22) = io.status.resetState;
|
||||
data.bit(23) = io.status.busyState;
|
||||
data.bit(24) = (bool)disk; //disk present
|
||||
data.bit(25) = irq.mecha.line;
|
||||
data.bit(26) = irq.bm.line;
|
||||
data.bit(27) = io.bm.error;
|
||||
data.bit(28) = io.status.requestC2Sector;
|
||||
data.bit(30) = io.status.requestUserSector;
|
||||
if(address == 4) {
|
||||
data.bit(0) = io.status.diskChanged;
|
||||
data.bit(1) = io.status.mechaError;
|
||||
data.bit(2) = io.status.writeProtect;
|
||||
data.bit(3) = io.status.headRetracted;
|
||||
data.bit(4) = io.status.spindleMotorStopped;
|
||||
data.bit(6) = io.status.resetState;
|
||||
data.bit(7) = io.status.busyState;
|
||||
data.bit(8) = (bool)disk; //disk present
|
||||
data.bit(9) = irq.mecha.line;
|
||||
data.bit(10) = irq.bm.line;
|
||||
data.bit(11) = io.bm.error;
|
||||
data.bit(12) = io.status.requestC2Sector;
|
||||
data.bit(14) = io.status.requestUserSector;
|
||||
|
||||
//acknowledge bm interrupt (tested on real hardware)
|
||||
if(irq.bm.line) {
|
||||
@@ -36,133 +36,133 @@ auto DD::readWord(u32 address) -> u32 {
|
||||
}
|
||||
|
||||
//ASIC_CUR_TK
|
||||
if(address == 3) {
|
||||
data.bit(16,31) = io.currentTrack;
|
||||
if(address == 6) {
|
||||
data.bit(0,15) = io.currentTrack;
|
||||
}
|
||||
|
||||
//ASIC_BM_STATUS
|
||||
if(address == 4) {
|
||||
data.bit(16) = io.bm.c1Error;
|
||||
data.bit(21) = io.bm.c1Single;
|
||||
data.bit(22) = io.bm.c1Double;
|
||||
data.bit(23) = io.bm.c1Correct;
|
||||
data.bit(24) = io.bm.blockTransfer;
|
||||
data.bit(25) = io.micro.error;
|
||||
data.bit(26) = io.bm.error;
|
||||
data.bit(31) = io.bm.start;
|
||||
if(address == 8) {
|
||||
data.bit(0) = io.bm.c1Error;
|
||||
data.bit(5) = io.bm.c1Single;
|
||||
data.bit(6) = io.bm.c1Double;
|
||||
data.bit(7) = io.bm.c1Correct;
|
||||
data.bit(8) = io.bm.blockTransfer;
|
||||
data.bit(9) = io.micro.error;
|
||||
data.bit(10) = io.bm.error;
|
||||
data.bit(15) = io.bm.start;
|
||||
}
|
||||
|
||||
//ASIC_ERR_SECTOR
|
||||
if(address == 5) {
|
||||
data.bit(16,23) = io.error.sector;
|
||||
data.bit(24) = io.error.selfStop;
|
||||
data.bit(25) = io.error.clockUnlock;
|
||||
data.bit(26) = ~(bool)disk; //no disk
|
||||
data.bit(27) = io.error.offTrack;
|
||||
data.bit(28) = io.error.overrun;
|
||||
data.bit(29) = io.error.spindle;
|
||||
data.bit(30) = io.micro.error;
|
||||
data.bit(31) = io.error.am;
|
||||
if(address == 10) {
|
||||
data.bit(0,7) = io.error.sector;
|
||||
data.bit(8) = io.error.selfStop;
|
||||
data.bit(9) = io.error.clockUnlock;
|
||||
data.bit(10) = ~(bool)disk; //no disk
|
||||
data.bit(11) = io.error.offTrack;
|
||||
data.bit(12) = io.error.overrun;
|
||||
data.bit(13) = io.error.spindle;
|
||||
data.bit(14) = io.micro.error;
|
||||
data.bit(15) = io.error.am;
|
||||
}
|
||||
|
||||
//ASIC_SEQ_STATUS
|
||||
if(address == 6) {
|
||||
if(address == 12) {
|
||||
}
|
||||
|
||||
//ASIC_CUR_SECTOR
|
||||
if(address == 7) {
|
||||
data.bit(24,31) = io.currentSector;
|
||||
data.bit(16,23) = 0xc3;
|
||||
if(address == 14) {
|
||||
data.bit(8,15) = io.currentSector;
|
||||
data.bit(0,7) = 0xc3;
|
||||
}
|
||||
|
||||
//ASIC_HARD_RESET
|
||||
if(address == 8) {
|
||||
if(address == 16) {
|
||||
}
|
||||
|
||||
//ASIC_C1_S0
|
||||
if(address == 9) {
|
||||
if(address == 18) {
|
||||
}
|
||||
|
||||
//ASIC_HOST_SECBYTE
|
||||
if(address == 10) {
|
||||
data.bit(16,23) = io.sectorSizeBuf;
|
||||
if(address == 20) {
|
||||
data.bit(0,7) = io.sectorSizeBuf;
|
||||
}
|
||||
|
||||
//ASIC_C1_S2
|
||||
if(address == 11) {
|
||||
if(address == 22) {
|
||||
}
|
||||
|
||||
//ASIC_SEC_BYTE
|
||||
if(address == 12) {
|
||||
data.bit(16,23) = io.sectorSize;
|
||||
data.bit(24,31) = io.sectorBlock;
|
||||
if(address == 24) {
|
||||
data.bit(0,7) = io.sectorSize;
|
||||
data.bit(8,15) = io.sectorBlock;
|
||||
}
|
||||
|
||||
//ASIC_C1_S4
|
||||
if(address == 13) {
|
||||
if(address == 26) {
|
||||
}
|
||||
|
||||
//ASIC_C1_S6
|
||||
if(address == 14) {
|
||||
if(address == 28) {
|
||||
}
|
||||
|
||||
//ASIC_CUR_ADDRESS
|
||||
if(address == 15) {
|
||||
if(address == 30) {
|
||||
}
|
||||
|
||||
//ASIC_ID_REG
|
||||
if(address == 16) {
|
||||
data.bit(16,31) = io.id;
|
||||
if(address == 32) {
|
||||
data.bit(0,15) = io.id;
|
||||
}
|
||||
|
||||
//ASIC_TEST_REG
|
||||
if(address == 17) {
|
||||
if(address == 34) {
|
||||
}
|
||||
|
||||
//ASIC_TEST_PIN_SEL
|
||||
if(address == 18) {
|
||||
if(address == 36) {
|
||||
}
|
||||
|
||||
debugger.io(Read, address, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
auto DD::writeWord(u32 address, u32 data_) -> void {
|
||||
address = (address & 0x7f) >> 2;
|
||||
n32 data = data_;
|
||||
auto DD::writeHalf(u32 address, u16 data_) -> void {
|
||||
address = (address & 0x7f) >> 1;
|
||||
n16 data = data_;
|
||||
|
||||
//ASIC_DATA
|
||||
if(address == 0) {
|
||||
io.data = data.bit(16,31);
|
||||
io.data = data.bit(0,15);
|
||||
}
|
||||
|
||||
//ASIC_MISC_REG
|
||||
if(address == 1) {
|
||||
if(address == 2) {
|
||||
}
|
||||
|
||||
//ASIC_CMD
|
||||
if(address == 2) {
|
||||
command(data.bit(16,31));
|
||||
if(address == 4) {
|
||||
command(data.bit(0,15));
|
||||
}
|
||||
|
||||
//ASIC_CUR_TK
|
||||
if(address == 3) {
|
||||
if(address == 6) {
|
||||
}
|
||||
|
||||
//ASIC_BM_CTL
|
||||
if(address == 4) {
|
||||
io.bm.reset |= data.bit(28);
|
||||
io.bm.readMode = data.bit(30);
|
||||
//irq.bm.mask = ~data.bit(29);
|
||||
io.bm.disableORcheck = data.bit(27);
|
||||
io.bm.disableC1Correction = data.bit(26);
|
||||
io.bm.blockTransfer = data.bit(25);
|
||||
if (data.bit(24)) {
|
||||
if(address == 8) {
|
||||
io.bm.reset |= data.bit(12);
|
||||
io.bm.readMode = data.bit(14);
|
||||
//irq.bm.mask = ~data.bit(13);
|
||||
io.bm.disableORcheck = data.bit(11);
|
||||
io.bm.disableC1Correction = data.bit(10);
|
||||
io.bm.blockTransfer = data.bit(9);
|
||||
if (data.bit(8)) {
|
||||
//mecha int reset
|
||||
lower(IRQ::MECHA);
|
||||
}
|
||||
io.currentSector = data.bit(16,23);
|
||||
if (!data.bit(28) && io.bm.reset) {
|
||||
io.currentSector = data.bit(0,7);
|
||||
if (!data.bit(12) && io.bm.reset) {
|
||||
//BM reset
|
||||
io.bm.start = 0;
|
||||
io.bm.error = 0;
|
||||
@@ -172,76 +172,88 @@ auto DD::writeWord(u32 address, u32 data_) -> void {
|
||||
lower(IRQ::BM);
|
||||
}
|
||||
|
||||
if(data.bit(31) && disk) {
|
||||
if(data.bit(15) && disk) {
|
||||
//start BM
|
||||
io.bm.start |= data.bit(31);
|
||||
io.bm.start |= data.bit(15);
|
||||
//TODO: proper research into seek and access times
|
||||
queue.insert(Queue::DD_BM_Request, 50'000 + (io.currentTrack.bit(0,11) / 15));
|
||||
}
|
||||
}
|
||||
|
||||
//ASIC_ERR_SECTOR
|
||||
if(address == 5) {
|
||||
if(address == 10) {
|
||||
}
|
||||
|
||||
//ASIC_SEQ_CTL
|
||||
if(address == 6) {
|
||||
io.micro.enable = data.bit(30);
|
||||
if(address == 12) {
|
||||
io.micro.enable = data.bit(14);
|
||||
}
|
||||
|
||||
//ASIC_CUR_SECTOR
|
||||
if(address == 7) {
|
||||
if(address == 14) {
|
||||
}
|
||||
|
||||
//ASIC_HARD_RESET
|
||||
if(address == 8) {
|
||||
if(address == 16) {
|
||||
if((data >> 16) == 0xAAAA) {
|
||||
power(true);
|
||||
}
|
||||
}
|
||||
|
||||
//ASIC_C1_S0
|
||||
if(address == 9) {
|
||||
if(address == 18) {
|
||||
}
|
||||
|
||||
//ASIC_HOST_SECBYTE
|
||||
if(address == 10) {
|
||||
io.sectorSizeBuf = data.bit(16,23);
|
||||
if(address == 20) {
|
||||
io.sectorSizeBuf = data.bit(0,7);
|
||||
}
|
||||
|
||||
//ASIC_C1_S2
|
||||
if(address == 11) {
|
||||
io.sectorSize = data.bit(16,23);
|
||||
io.sectorBlock = data.bit(24,31);
|
||||
if(address == 22) {
|
||||
io.sectorSize = data.bit(0,7);
|
||||
io.sectorBlock = data.bit(8,15);
|
||||
}
|
||||
|
||||
//ASIC_SEC_BYTE
|
||||
if(address == 12) {
|
||||
if(address == 24) {
|
||||
}
|
||||
|
||||
//ASIC_C1_S4
|
||||
if(address == 13) {
|
||||
if(address == 26) {
|
||||
}
|
||||
|
||||
//ASIC_C1_S6
|
||||
if(address == 14) {
|
||||
if(address == 28) {
|
||||
}
|
||||
|
||||
//ASIC_CUR_ADDRESS
|
||||
if(address == 15) {
|
||||
if(address == 30) {
|
||||
}
|
||||
|
||||
//ASIC_ID_REG
|
||||
if(address == 16) {
|
||||
if(address == 32) {
|
||||
}
|
||||
|
||||
//ASIC_TEST_REG
|
||||
if(address == 17) {
|
||||
if(address == 34) {
|
||||
}
|
||||
|
||||
//ASIC_TEST_PIN_SEL
|
||||
if(address == 18) {
|
||||
if(address == 36) {
|
||||
}
|
||||
|
||||
debugger.io(Write, address, data);
|
||||
}
|
||||
|
||||
auto DD::readWord(u32 address) -> u32 {
|
||||
n32 data;
|
||||
data.bit(0,15) = readHalf(address + 0);
|
||||
data.bit(16,31) = readHalf(address + 2);
|
||||
return (u32)data;
|
||||
}
|
||||
|
||||
auto DD::writeWord(u32 address, u32 data) -> void {
|
||||
writeHalf(address + 0, data >> 16);
|
||||
writeHalf(address + 2, data & 0xffff);
|
||||
}
|
||||
+30
-30
@@ -1,30 +1,30 @@
|
||||
template<u32 Size>
|
||||
inline auto Bus::read(u32 address) -> u64 {
|
||||
inline auto Bus::read(u32 address, u32& cycles) -> u64 {
|
||||
static constexpr u64 unmapped = 0;
|
||||
address &= 0x1fff'ffff - (Size - 1);
|
||||
|
||||
if(address <= 0x007f'ffff) return rdram.ram.read<Size>(address);
|
||||
if(address <= 0x03ef'ffff) return unmapped;
|
||||
if(address <= 0x03ff'ffff) return rdram.read<Size>(address);
|
||||
if(address <= 0x0407'ffff) return rsp.read<Size>(address);
|
||||
if(address <= 0x040f'ffff) return rsp.status.read<Size>(address);
|
||||
if(address <= 0x041f'ffff) return rdp.read<Size>(address);
|
||||
if(address <= 0x042f'ffff) return rdp.io.read<Size>(address);
|
||||
if(address <= 0x043f'ffff) return mi.read<Size>(address);
|
||||
if(address <= 0x044f'ffff) return vi.read<Size>(address);
|
||||
if(address <= 0x045f'ffff) return ai.read<Size>(address);
|
||||
if(address <= 0x046f'ffff) return pi.read<Size>(address);
|
||||
if(address <= 0x047f'ffff) return ri.read<Size>(address);
|
||||
if(address <= 0x048f'ffff) return si.read<Size>(address);
|
||||
if(address <= 0x03ff'ffff) return rdram.read<Size>(address, cycles);
|
||||
if(address <= 0x0407'ffff) return rsp.read<Size>(address, cycles);
|
||||
if(address <= 0x040f'ffff) return rsp.status.read<Size>(address, cycles);
|
||||
if(address <= 0x041f'ffff) return rdp.read<Size>(address, cycles);
|
||||
if(address <= 0x042f'ffff) return rdp.io.read<Size>(address, cycles);
|
||||
if(address <= 0x043f'ffff) return mi.read<Size>(address, cycles);
|
||||
if(address <= 0x044f'ffff) return vi.read<Size>(address, cycles);
|
||||
if(address <= 0x045f'ffff) return ai.read<Size>(address, cycles);
|
||||
if(address <= 0x046f'ffff) return pi.read<Size>(address, cycles);
|
||||
if(address <= 0x047f'ffff) return ri.read<Size>(address, cycles);
|
||||
if(address <= 0x048f'ffff) return si.read<Size>(address, cycles);
|
||||
if(address <= 0x04ff'ffff) return unmapped;
|
||||
if(address <= 0x1fbf'ffff) return pi.read<Size>(address);
|
||||
if(address <= 0x1fcf'ffff) return si.read<Size>(address);
|
||||
if(address <= 0x7fff'ffff) return pi.read<Size>(address);
|
||||
if(address <= 0x1fbf'ffff) return pi.read<Size>(address, cycles);
|
||||
if(address <= 0x1fcf'ffff) return si.read<Size>(address, cycles);
|
||||
if(address <= 0x7fff'ffff) return pi.read<Size>(address, cycles);
|
||||
return unmapped;
|
||||
}
|
||||
|
||||
template<u32 Size>
|
||||
inline auto Bus::write(u32 address, u64 data) -> void {
|
||||
inline auto Bus::write(u32 address, u64 data, u32& cycles) -> void {
|
||||
address &= 0x1fff'ffff - (Size - 1);
|
||||
if constexpr(Accuracy::CPU::Recompiler) {
|
||||
cpu.recompiler.invalidate(address + 0); if constexpr(Size == Dual)
|
||||
@@ -33,20 +33,20 @@ inline auto Bus::write(u32 address, u64 data) -> void {
|
||||
|
||||
if(address <= 0x007f'ffff) return rdram.ram.write<Size>(address, data);
|
||||
if(address <= 0x03ef'ffff) return;
|
||||
if(address <= 0x03ff'ffff) return rdram.write<Size>(address, data);
|
||||
if(address <= 0x0407'ffff) return rsp.write<Size>(address, data);
|
||||
if(address <= 0x040f'ffff) return rsp.status.write<Size>(address, data);
|
||||
if(address <= 0x041f'ffff) return rdp.write<Size>(address, data);
|
||||
if(address <= 0x042f'ffff) return rdp.io.write<Size>(address, data);
|
||||
if(address <= 0x043f'ffff) return mi.write<Size>(address, data);
|
||||
if(address <= 0x044f'ffff) return vi.write<Size>(address, data);
|
||||
if(address <= 0x045f'ffff) return ai.write<Size>(address, data);
|
||||
if(address <= 0x046f'ffff) return pi.write<Size>(address, data);
|
||||
if(address <= 0x047f'ffff) return ri.write<Size>(address, data);
|
||||
if(address <= 0x048f'ffff) return si.write<Size>(address, data);
|
||||
if(address <= 0x03ff'ffff) return rdram.write<Size>(address, data, cycles);
|
||||
if(address <= 0x0407'ffff) return rsp.write<Size>(address, data, cycles);
|
||||
if(address <= 0x040f'ffff) return rsp.status.write<Size>(address, data, cycles);
|
||||
if(address <= 0x041f'ffff) return rdp.write<Size>(address, data, cycles);
|
||||
if(address <= 0x042f'ffff) return rdp.io.write<Size>(address, data, cycles);
|
||||
if(address <= 0x043f'ffff) return mi.write<Size>(address, data, cycles);
|
||||
if(address <= 0x044f'ffff) return vi.write<Size>(address, data, cycles);
|
||||
if(address <= 0x045f'ffff) return ai.write<Size>(address, data, cycles);
|
||||
if(address <= 0x046f'ffff) return pi.write<Size>(address, data, cycles);
|
||||
if(address <= 0x047f'ffff) return ri.write<Size>(address, data, cycles);
|
||||
if(address <= 0x048f'ffff) return si.write<Size>(address, data, cycles);
|
||||
if(address <= 0x04ff'ffff) return;
|
||||
if(address <= 0x1fbf'ffff) return pi.write<Size>(address, data);
|
||||
if(address <= 0x1fcf'ffff) return si.write<Size>(address, data);
|
||||
if(address <= 0x7fff'ffff) return pi.write<Size>(address, data);
|
||||
if(address <= 0x1fbf'ffff) return pi.write<Size>(address, data, cycles);
|
||||
if(address <= 0x1fcf'ffff) return si.write<Size>(address, data, cycles);
|
||||
if(address <= 0x7fff'ffff) return pi.write<Size>(address, data, cycles);
|
||||
return;
|
||||
}
|
||||
+69
-16
@@ -1,9 +1,13 @@
|
||||
template<typename T>
|
||||
struct IO {
|
||||
struct RCP { //A device which is part of RCP
|
||||
const u32 DefaultReadCycles = 0;
|
||||
const u32 DefaultWriteCycles = 0;
|
||||
|
||||
template<u32 Size>
|
||||
auto read(u32 address) -> u64 {
|
||||
auto read(u32 address, u32& cycles) -> u64 {
|
||||
cycles = DefaultReadCycles;
|
||||
if constexpr(Size == Byte) {
|
||||
auto data = ((T*)this)->readWord(address);
|
||||
auto data = ((T*)this)->readWord(address, cycles);
|
||||
switch(address & 3) {
|
||||
case 0: return data >> 24;
|
||||
case 1: return data >> 16;
|
||||
@@ -12,43 +16,92 @@ struct IO {
|
||||
}
|
||||
}
|
||||
if constexpr(Size == Half) {
|
||||
auto data = ((T*)this)->readWord(address);
|
||||
auto data = ((T*)this)->readWord(address, cycles);
|
||||
switch(address & 2) {
|
||||
case 0: return data >> 16;
|
||||
case 2: return data >> 0;
|
||||
}
|
||||
}
|
||||
if constexpr(Size == Word) {
|
||||
return ((T*)this)->readWord(address);
|
||||
return ((T*)this)->readWord(address, cycles);
|
||||
}
|
||||
if constexpr(Size == Dual) {
|
||||
u64 data = ((T*)this)->readWord(address);
|
||||
return data << 32 | ((T*)this)->readWord(address + 4);
|
||||
u64 data = ((T*)this)->readWord(address, cycles);
|
||||
return data << 32 | ((T*)this)->readWord(address + 4, cycles);
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
|
||||
template<u32 Size>
|
||||
auto write(u32 address, u64 data) -> void {
|
||||
auto write(u32 address, u64 data, u32& cycles) -> void {
|
||||
cycles = DefaultWriteCycles;
|
||||
if constexpr(Size == Byte) {
|
||||
switch(address & 3) {
|
||||
case 0: return ((T*)this)->writeWord(address, data << 24);
|
||||
case 1: return ((T*)this)->writeWord(address, data << 16);
|
||||
case 2: return ((T*)this)->writeWord(address, data << 8);
|
||||
case 3: return ((T*)this)->writeWord(address, data << 0);
|
||||
case 0: return ((T*)this)->writeWord(address, data << 24, cycles);
|
||||
case 1: return ((T*)this)->writeWord(address, data << 16, cycles);
|
||||
case 2: return ((T*)this)->writeWord(address, data << 8, cycles);
|
||||
case 3: return ((T*)this)->writeWord(address, data << 0, cycles);
|
||||
}
|
||||
}
|
||||
if constexpr(Size == Half) {
|
||||
switch(address & 2) {
|
||||
case 0: return ((T*)this)->writeWord(address, data << 16);
|
||||
case 2: return ((T*)this)->writeWord(address, data << 0);
|
||||
case 0: return ((T*)this)->writeWord(address, data << 16, cycles);
|
||||
case 2: return ((T*)this)->writeWord(address, data << 0, cycles);
|
||||
}
|
||||
}
|
||||
if constexpr(Size == Word) {
|
||||
((T*)this)->writeWord(address, data);
|
||||
((T*)this)->writeWord(address, data, cycles);
|
||||
}
|
||||
if constexpr(Size == Dual) {
|
||||
((T*)this)->writeWord(address, data >> 32);
|
||||
((T*)this)->writeWord(address, data >> 32, cycles);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct PI { //A device which is reachable only behind PI
|
||||
template<u32 Size>
|
||||
auto read(u32 address) -> u64 {
|
||||
static_assert(Size == Half || Size == Word); //PI bus will do 32-bit (CPU) or 16-bit (DMA) only
|
||||
if constexpr(Size == Half) {
|
||||
return ((T*)this)->readHalf(address);
|
||||
}
|
||||
if constexpr(Size == Word) {
|
||||
return ((T*)this)->readWord(address);
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
|
||||
template<u32 Size>
|
||||
auto write(u32 address, u64 data) -> void {
|
||||
static_assert(Size == Half || Size == Word); //PI bus will do 32-bit (CPU) or 16-bit (DMA) only
|
||||
if constexpr(Size == Half) {
|
||||
return ((T*)this)->writeHalf(address, data);
|
||||
}
|
||||
if constexpr(Size == Word) {
|
||||
return ((T*)this)->writeWord(address, data);
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct SI { //A device which is reachable only behind SI
|
||||
template<u32 Size>
|
||||
auto read(u32 address) -> u64 {
|
||||
static_assert(Size == Word); //SI bus will do 32-bit (CPU/DMA)
|
||||
if constexpr(Size == Word) {
|
||||
return ((T*)this)->readWord(address);
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
|
||||
template<u32 Size>
|
||||
auto write(u32 address, u64 data) -> void {
|
||||
static_assert(Size == Word); //PI bus will do 32-bit (CPU/DMA)
|
||||
if constexpr(Size == Word) {
|
||||
return ((T*)this)->writeWord(address, data);
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
};
|
||||
@@ -31,8 +31,8 @@ namespace Memory {
|
||||
|
||||
struct Bus {
|
||||
//bus.hpp
|
||||
template<u32 Size> auto read(u32 address) -> u64;
|
||||
template<u32 Size> auto write(u32 address, u64 data) -> void;
|
||||
template<u32 Size> auto read(u32 address, u32& cycles) -> u64;
|
||||
template<u32 Size> auto write(u32 address, u64 data, u32& cycles) -> void;
|
||||
};
|
||||
|
||||
extern Bus bus;
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
auto MI::readWord(u32 address) -> u32 {
|
||||
auto MI::readWord(u32 address, u32& cycles) -> u32 {
|
||||
address = (address & 0xfffff) >> 2;
|
||||
n32 data;
|
||||
|
||||
@@ -42,7 +42,7 @@ auto MI::readWord(u32 address) -> u32 {
|
||||
return data;
|
||||
}
|
||||
|
||||
auto MI::writeWord(u32 address, u32 data_) -> void {
|
||||
auto MI::writeWord(u32 address, u32 data_, u32& cycles) -> void {
|
||||
address = (address & 0xfffff) >> 2;
|
||||
n32 data = data_;
|
||||
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
//MIPS Interface
|
||||
|
||||
struct MI : Memory::IO<MI> {
|
||||
struct MI : Memory::RCP<MI> {
|
||||
Node::Object node;
|
||||
|
||||
struct Debugger {
|
||||
@@ -27,8 +27,8 @@ struct MI : Memory::IO<MI> {
|
||||
auto power(bool reset) -> void;
|
||||
|
||||
//io.cpp
|
||||
auto readWord(u32 address) -> u32;
|
||||
auto writeWord(u32 address, u32 data) -> void;
|
||||
auto readWord(u32 address, u32& cycles) -> u32;
|
||||
auto writeWord(u32 address, u32 data, u32& cycles) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
inline auto PI::readWord(u32 address) -> u32 {
|
||||
inline auto PI::readWord(u32 address, u32& cycles) -> u32 {
|
||||
if(address <= 0x046f'ffff) return ioRead(address);
|
||||
|
||||
if (unlikely(io.ioBusy)) {
|
||||
@@ -50,7 +50,7 @@ inline auto PI::busRead(u32 address) -> u32 {
|
||||
return unmapped; //accesses here actually lock out the RCP
|
||||
}
|
||||
|
||||
inline auto PI::writeWord(u32 address, u32 data) -> void {
|
||||
inline auto PI::writeWord(u32 address, u32 data, u32& cycles) -> void {
|
||||
if(address <= 0x046f'ffff) return ioWrite(address, data);
|
||||
|
||||
if(io.ioBusy) return;
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
//Peripheral Interface
|
||||
|
||||
struct PI : Memory::IO<PI> {
|
||||
struct PI : Memory::RCP<PI> {
|
||||
Node::Object node;
|
||||
|
||||
struct Debugger {
|
||||
@@ -28,8 +28,8 @@ struct PI : Memory::IO<PI> {
|
||||
auto ioWrite(u32 address, u32 data) -> void;
|
||||
|
||||
//bus.hpp
|
||||
auto readWord(u32 address) -> u32;
|
||||
auto writeWord(u32 address, u32 data) -> void;
|
||||
auto readWord(u32 address, u32& cycles) -> u32;
|
||||
auto writeWord(u32 address, u32 data, u32& cycles) -> void;
|
||||
auto writeFinished() -> void;
|
||||
auto writeForceFinish() -> void;
|
||||
template <u32 Size>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//PIF-NUS
|
||||
|
||||
struct PIF : Memory::IO<PIF> {
|
||||
struct PIF : Memory::SI<PIF> {
|
||||
Node::Object node;
|
||||
Memory::Readable rom;
|
||||
Memory::Writable ram;
|
||||
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
auto RDP::readWord(u32 address) -> u32 {
|
||||
auto RDP::readWord(u32 address, u32& cycles) -> u32 {
|
||||
address = (address & 0xfffff) >> 2;
|
||||
n32 data;
|
||||
|
||||
@@ -56,7 +56,7 @@ auto RDP::readWord(u32 address) -> u32 {
|
||||
return data;
|
||||
}
|
||||
|
||||
auto RDP::writeWord(u32 address, u32 data_) -> void {
|
||||
auto RDP::writeWord(u32 address, u32 data_, u32& cycles) -> void {
|
||||
address = (address & 0xfffff) >> 2;
|
||||
n32 data = data_;
|
||||
|
||||
@@ -113,7 +113,7 @@ auto RDP::writeWord(u32 address, u32 data_) -> void {
|
||||
debugger.ioDPC(Write, address, data);
|
||||
}
|
||||
|
||||
auto RDP::IO::readWord(u32 address) -> u32 {
|
||||
auto RDP::IO::readWord(u32 address, u32& cycles) -> u32 {
|
||||
address = (address & 0xfffff) >> 2;
|
||||
n32 data;
|
||||
|
||||
@@ -144,7 +144,7 @@ auto RDP::IO::readWord(u32 address) -> u32 {
|
||||
return data;
|
||||
}
|
||||
|
||||
auto RDP::IO::writeWord(u32 address, u32 data_) -> void {
|
||||
auto RDP::IO::writeWord(u32 address, u32 data_, u32& cycles) -> void {
|
||||
address = (address & 0xfffff) >> 2;
|
||||
n32 data = data_;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//Reality Display Processor
|
||||
|
||||
struct RDP : Thread, Memory::IO<RDP> {
|
||||
struct RDP : Thread, Memory::RCP<RDP> {
|
||||
Node::Object node;
|
||||
|
||||
struct Debugger {
|
||||
@@ -66,8 +66,8 @@ struct RDP : Thread, Memory::IO<RDP> {
|
||||
auto setColorImage() -> void;
|
||||
|
||||
//io.cpp
|
||||
auto readWord(u32 address) -> u32;
|
||||
auto writeWord(u32 address, u32 data) -> void;
|
||||
auto readWord(u32 address, u32& cycles) -> u32;
|
||||
auto writeWord(u32 address, u32 data, u32& cycles) -> void;
|
||||
auto flushCommands() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
@@ -333,13 +333,13 @@ struct RDP : Thread, Memory::IO<RDP> {
|
||||
} x, y;
|
||||
} fillRectangle_;
|
||||
|
||||
struct IO : Memory::IO<IO> {
|
||||
struct IO : Memory::RCP<IO> {
|
||||
RDP& self;
|
||||
IO(RDP& self) : self(self) {}
|
||||
|
||||
//io.cpp
|
||||
auto readWord(u32 address) -> u32;
|
||||
auto writeWord(u32 address, u32 data) -> void;
|
||||
auto readWord(u32 address, u32& cycles) -> u32;
|
||||
auto writeWord(u32 address, u32 data, u32& cycles) -> void;
|
||||
|
||||
struct BIST {
|
||||
n1 check;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
auto RDRAM::readWord(u32 address) -> u32 {
|
||||
auto RDRAM::readWord(u32 address, u32& cycles) -> u32 {
|
||||
u32 chipID = address >> 13 & 3;
|
||||
auto& chip = chips[chipID];
|
||||
address = (address & 0x3ff) >> 2;
|
||||
@@ -63,7 +63,7 @@ auto RDRAM::readWord(u32 address) -> u32 {
|
||||
return data;
|
||||
}
|
||||
|
||||
auto RDRAM::writeWord(u32 address, u32 data) -> void {
|
||||
auto RDRAM::writeWord(u32 address, u32 data, u32& cycles) -> void {
|
||||
u32 chipID = address >> 13 & 3;
|
||||
auto& chip = chips[chipID];
|
||||
address = (address & 0x3ff) >> 2;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//RAMBUS RAM
|
||||
|
||||
struct RDRAM : Memory::IO<RDRAM> {
|
||||
struct RDRAM : Memory::RCP<RDRAM> {
|
||||
Node::Object node;
|
||||
Memory::Writable ram;
|
||||
|
||||
@@ -24,8 +24,8 @@ struct RDRAM : Memory::IO<RDRAM> {
|
||||
auto power(bool reset) -> void;
|
||||
|
||||
//io.cpp
|
||||
auto readWord(u32 address) -> u32;
|
||||
auto writeWord(u32 address, u32 data) -> void;
|
||||
auto readWord(u32 address, u32& cycles) -> u32;
|
||||
auto writeWord(u32 address, u32 data, u32& cycles) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
auto RI::readWord(u32 address) -> u32 {
|
||||
auto RI::readWord(u32 address, u32& cycles) -> u32 {
|
||||
address = (address & 0xfffff) >> 2;
|
||||
n32 data = 0;
|
||||
|
||||
@@ -58,7 +58,7 @@ auto RI::readWord(u32 address) -> u32 {
|
||||
return data;
|
||||
}
|
||||
|
||||
auto RI::writeWord(u32 address, u32 data_) -> void {
|
||||
auto RI::writeWord(u32 address, u32 data_, u32& cycles) -> void {
|
||||
address = (address & 0xfffff) >> 2;
|
||||
n32 data = data_;
|
||||
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
//RDRAM Interface
|
||||
|
||||
struct RI : Memory::IO<RI> {
|
||||
struct RI : Memory::RCP<RI> {
|
||||
Node::Object node;
|
||||
|
||||
struct Debugger {
|
||||
@@ -19,8 +19,8 @@ struct RI : Memory::IO<RI> {
|
||||
auto power(bool reset) -> void;
|
||||
|
||||
//io.cpp
|
||||
auto readWord(u32 address) -> u32;
|
||||
auto writeWord(u32 address, u32 data) -> void;
|
||||
auto readWord(u32 address, u32& cycles) -> u32;
|
||||
auto writeWord(u32 address, u32 data, u32& cycles) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
@@ -490,10 +490,10 @@ auto RSP::Disassembler::sccRegisterName(u32 index) const -> string {
|
||||
}
|
||||
|
||||
auto RSP::Disassembler::sccRegisterValue(u32 index) const -> string {
|
||||
u32 value = 0;
|
||||
if(index <= 6) value = rsp.readWord((index & 7) << 2);
|
||||
u32 value = 0; u32 cycles;
|
||||
if(index <= 6) value = rsp.readWord((index & 7) << 2, cycles);
|
||||
if(index == 7) value = self.status.semaphore; //rsp.readSCC(7) has side-effects
|
||||
if(index >= 8) value = rdp.readWord((index & 7) << 2);
|
||||
if(index >= 8) value = rdp.readWord((index & 7) << 2, cycles);
|
||||
if(showValues) return {sccRegisterName(index), hint("{$", hex(value, 8L), "}")};
|
||||
return sccRegisterName(index);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
auto RSP::MFC0(r32& rt, u8 rd) -> void {
|
||||
u32 cycles = 0;
|
||||
if((rd & 8) == 0) rt.u32 = Nintendo64::rsp.ioRead ((rd & 7) << 2);
|
||||
if((rd & 8) != 0) rt.u32 = Nintendo64::rdp.readWord((rd & 7) << 2);
|
||||
if((rd & 8) != 0) rt.u32 = Nintendo64::rdp.readWord((rd & 7) << 2, cycles);
|
||||
step(cycles);
|
||||
}
|
||||
|
||||
auto RSP::MTC0(cr32& rt, u8 rd) -> void {
|
||||
u32 cycles = 0;
|
||||
if((rd & 8) == 0) Nintendo64::rsp.ioWrite ((rd & 7) << 2, rt.u32);
|
||||
if((rd & 8) != 0) Nintendo64::rdp.writeWord((rd & 7) << 2, rt.u32);
|
||||
if((rd & 8) != 0) Nintendo64::rdp.writeWord((rd & 7) << 2, rt.u32, cycles);
|
||||
step(cycles);
|
||||
}
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
auto RSP::readWord(u32 address) -> u32 {
|
||||
auto RSP::readWord(u32 address, u32& cycles) -> u32 {
|
||||
if(address <= 0x0403'ffff) {
|
||||
if(address & 0x1000) return imem.read<Word>(address);
|
||||
else return dmem.read<Word>(address);
|
||||
@@ -67,7 +67,7 @@ auto RSP::ioRead(u32 address) -> u32 {
|
||||
return data;
|
||||
}
|
||||
|
||||
auto RSP::writeWord(u32 address, u32 data) -> void {
|
||||
auto RSP::writeWord(u32 address, u32 data, u32& cycles) -> void {
|
||||
if(address <= 0x0403'ffff) {
|
||||
if(address & 0x1000) return recompiler.invalidate(address & 0xfff), imem.write<Word>(address, data);
|
||||
else return dmem.write<Word>(address, data);
|
||||
@@ -156,7 +156,7 @@ auto RSP::ioWrite(u32 address, u32 data_) -> void {
|
||||
debugger.ioSCC(Write, address, data);
|
||||
}
|
||||
|
||||
auto RSP::Status::readWord(u32 address) -> u32 {
|
||||
auto RSP::Status::readWord(u32 address, u32& cycles) -> u32 {
|
||||
address = (address & 0x7ffff) >> 2;
|
||||
n32 data;
|
||||
|
||||
@@ -177,7 +177,7 @@ auto RSP::Status::readWord(u32 address) -> u32 {
|
||||
return data;
|
||||
}
|
||||
|
||||
auto RSP::Status::writeWord(u32 address, u32 data_) -> void {
|
||||
auto RSP::Status::writeWord(u32 address, u32 data_, u32& cycles) -> void {
|
||||
address = (address & 0x7ffff) >> 2;
|
||||
n32 data = data_;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//Reality Signal Processor
|
||||
|
||||
struct RSP : Thread, Memory::IO<RSP> {
|
||||
struct RSP : Thread, Memory::RCP<RSP> {
|
||||
Node::Object node;
|
||||
Memory::Writable dmem;
|
||||
Memory::Writable imem;
|
||||
@@ -47,8 +47,8 @@ struct RSP : Thread, Memory::IO<RSP> {
|
||||
auto dmaTransferStep() -> void;
|
||||
|
||||
//io.cpp
|
||||
auto readWord(u32 address) -> u32;
|
||||
auto writeWord(u32 address, u32 data) -> void;
|
||||
auto readWord(u32 address, u32& cycles) -> u32;
|
||||
auto writeWord(u32 address, u32 data, u32& cycles) -> void;
|
||||
auto ioRead(u32 address) -> u32;
|
||||
auto ioWrite(u32 address, u32 data) -> void;
|
||||
|
||||
@@ -75,13 +75,13 @@ struct RSP : Thread, Memory::IO<RSP> {
|
||||
} busy, full;
|
||||
} dma;
|
||||
|
||||
struct Status : Memory::IO<Status> {
|
||||
struct Status : Memory::RCP<Status> {
|
||||
RSP& self;
|
||||
Status(RSP& self) : self(self) {}
|
||||
|
||||
//io.cpp
|
||||
auto readWord(u32 address) -> u32;
|
||||
auto writeWord(u32 address, u32 data) -> void;
|
||||
auto readWord(u32 address, u32& cycles) -> u32;
|
||||
auto writeWord(u32 address, u32 data, u32& cycles) -> void;
|
||||
|
||||
n1 semaphore;
|
||||
n1 halted = 1;
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
auto SI::readWord(u32 address) -> u32 {
|
||||
auto SI::readWord(u32 address, u32& cycles) -> u32 {
|
||||
if(address <= 0x048f'ffff) return ioRead(address);
|
||||
|
||||
if (unlikely(io.ioBusy)) {
|
||||
@@ -54,7 +54,7 @@ auto SI::ioRead(u32 address) -> u32 {
|
||||
return data;
|
||||
}
|
||||
|
||||
auto SI::writeWord(u32 address, u32 data) -> void {
|
||||
auto SI::writeWord(u32 address, u32 data, u32& cycles) -> void {
|
||||
if(address <= 0x048f'ffff) return ioWrite(address, data);
|
||||
|
||||
if(io.ioBusy) return;
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
//Serial Interface
|
||||
|
||||
struct SI : Memory::IO<SI> {
|
||||
struct SI : Memory::RCP<SI> {
|
||||
Node::Object node;
|
||||
|
||||
struct Debugger {
|
||||
@@ -25,8 +25,8 @@ struct SI : Memory::IO<SI> {
|
||||
//io.cpp
|
||||
auto ioRead(u32 address) -> u32;
|
||||
auto ioWrite(u32 address, u32 data) -> void;
|
||||
auto readWord(u32 address) -> u32;
|
||||
auto writeWord(u32 address, u32 data) -> void;
|
||||
auto readWord(u32 address, u32& cycles) -> u32;
|
||||
auto writeWord(u32 address, u32 data, u32& cycles) -> void;
|
||||
auto writeFinished() -> void;
|
||||
auto writeForceFinish() -> void;
|
||||
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
auto VI::readWord(u32 address) -> u32 {
|
||||
auto VI::readWord(u32 address, u32& cycles) -> u32 {
|
||||
address = (address & 0xfffff) >> 2;
|
||||
n32 data;
|
||||
|
||||
@@ -95,7 +95,7 @@ auto VI::readWord(u32 address) -> u32 {
|
||||
return data;
|
||||
}
|
||||
|
||||
auto VI::writeWord(u32 address, u32 data_) -> void {
|
||||
auto VI::writeWord(u32 address, u32 data_, u32& cycles) -> void {
|
||||
address = (address & 0xfffff) >> 2;
|
||||
n32 data = data_;
|
||||
|
||||
|
||||
+2
-2
@@ -147,7 +147,7 @@ auto VI::refresh() -> void {
|
||||
auto line = screen->pixels(1).data() + (dy - vscan_start) * hscan_len;
|
||||
u32 x0 = vi.io.xsubpixel + vi.io.xscale * (dx0 - vi.io.hstart);
|
||||
for(i32 dx = dx0; dx < dx1; dx++) {
|
||||
u16 data = bus.read<Half>(address + (x0 >> 10) * 2);
|
||||
u16 data = rdram.ram.read<Half>(address + (x0 >> 10) * 2);
|
||||
line[dx - hscan_start] = 1 << 24 | data >> 1;
|
||||
x0 += vi.io.xscale;
|
||||
}
|
||||
@@ -165,7 +165,7 @@ auto VI::refresh() -> void {
|
||||
auto line = screen->pixels(1).data() + (dy - vscan_start) * hscan_len;
|
||||
u32 x0 = vi.io.xsubpixel + vi.io.xscale * (dx0 - vi.io.hstart);
|
||||
for(i32 dx = dx0; dx < dx1; dx++) {
|
||||
u32 data = bus.read<Word>(address + (x0 >> 10) * 4);
|
||||
u32 data = rdram.ram.read<Word>(address + (x0 >> 10) * 4);
|
||||
line[dx - hscan_start] = data >> 8;
|
||||
x0 += vi.io.xscale;
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
//Video Interface
|
||||
|
||||
struct VI : Thread, Memory::IO<VI> {
|
||||
struct VI : Thread, Memory::RCP<VI> {
|
||||
Node::Object node;
|
||||
Node::Video::Screen screen;
|
||||
|
||||
@@ -24,8 +24,8 @@ struct VI : Thread, Memory::IO<VI> {
|
||||
auto power(bool reset) -> void;
|
||||
|
||||
//io.cpp
|
||||
auto readWord(u32 address) -> u32;
|
||||
auto writeWord(u32 address, u32 data) -> void;
|
||||
auto readWord(u32 address, u32& cycles) -> u32;
|
||||
auto writeWord(u32 address, u32 data, u32& cycles) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
Reference in new issue
Block a user