2015-11-10 11:02:29 +00:00
|
|
|
alwaysinline auto SMP::ramRead(uint16 addr) -> uint8 {
|
|
|
|
if(addr >= 0xffc0 && status.iplromEnable) return iplrom[addr & 0x3f];
|
|
|
|
if(status.ramDisable) return 0x5a; //0xff on mini-SNES
|
Update to v074r11 release.
byuu says:
Changelog:
- debugger compiles on all three profiles
- libsnes compiles on all three platforms (no API changes to libsnes)
- memory.cpp : namespace memory removed (wram -> cpu, apuram -> smp,
vram, oam, cgram -> ppu)
- sa1.cpp : namespace memory removed (SA-1 specific functions merged
inline to SA1::bus_read,write)
- GameBoy: added serial link support with interrupts and proper 8192hz
timing, but obviously it acts as if no other GB is connected to it
- GameBoy: added STAT OAM interrupt, and better STAT d1,d0 mode values
- UI: since Qt is dead, I've renamed the config files back to bsnes.cfg
and bsnes-geometry.cfg
- SA1: IRAM was not syncing to CPU on SA-1 side
- PPU/Accuracy and PPU/Performance needed Sprite oam renamed to Sprite
sprite; so that I could add uint8 oam[544]
- makes more sense anyway, OAM = object attribute memory, obj or
sprite are better names for Sprite rendering class
- more cleanup
2011-01-24 09:03:17 +00:00
|
|
|
return apuram[addr];
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-11-10 11:02:29 +00:00
|
|
|
alwaysinline auto SMP::ramWrite(uint16 addr, uint8 data) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
//writes to $ffc0-$ffff always go to apuram, even if the iplrom is enabled
|
2015-11-10 11:02:29 +00:00
|
|
|
if(status.ramWritable && !status.ramDisable) apuram[addr] = data;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-11-10 11:02:29 +00:00
|
|
|
auto SMP::portRead(uint2 port) const -> uint8 {
|
Update to v074r11 release.
byuu says:
Changelog:
- debugger compiles on all three profiles
- libsnes compiles on all three platforms (no API changes to libsnes)
- memory.cpp : namespace memory removed (wram -> cpu, apuram -> smp,
vram, oam, cgram -> ppu)
- sa1.cpp : namespace memory removed (SA-1 specific functions merged
inline to SA1::bus_read,write)
- GameBoy: added serial link support with interrupts and proper 8192hz
timing, but obviously it acts as if no other GB is connected to it
- GameBoy: added STAT OAM interrupt, and better STAT d1,d0 mode values
- UI: since Qt is dead, I've renamed the config files back to bsnes.cfg
and bsnes-geometry.cfg
- SA1: IRAM was not syncing to CPU on SA-1 side
- PPU/Accuracy and PPU/Performance needed Sprite oam renamed to Sprite
sprite; so that I could add uint8 oam[544]
- makes more sense anyway, OAM = object attribute memory, obj or
sprite are better names for Sprite rendering class
- more cleanup
2011-01-24 09:03:17 +00:00
|
|
|
return apuram[0xf4 + port];
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-11-10 11:02:29 +00:00
|
|
|
auto SMP::portWrite(uint2 port, uint8 data) -> void {
|
Update to v074r11 release.
byuu says:
Changelog:
- debugger compiles on all three profiles
- libsnes compiles on all three platforms (no API changes to libsnes)
- memory.cpp : namespace memory removed (wram -> cpu, apuram -> smp,
vram, oam, cgram -> ppu)
- sa1.cpp : namespace memory removed (SA-1 specific functions merged
inline to SA1::bus_read,write)
- GameBoy: added serial link support with interrupts and proper 8192hz
timing, but obviously it acts as if no other GB is connected to it
- GameBoy: added STAT OAM interrupt, and better STAT d1,d0 mode values
- UI: since Qt is dead, I've renamed the config files back to bsnes.cfg
and bsnes-geometry.cfg
- SA1: IRAM was not syncing to CPU on SA-1 side
- PPU/Accuracy and PPU/Performance needed Sprite oam renamed to Sprite
sprite; so that I could add uint8 oam[544]
- makes more sense anyway, OAM = object attribute memory, obj or
sprite are better names for Sprite rendering class
- more cleanup
2011-01-24 09:03:17 +00:00
|
|
|
apuram[0xf4 + port] = data;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-11-10 11:02:29 +00:00
|
|
|
auto SMP::busRead(uint16 addr) -> uint8 {
|
|
|
|
uint result;
|
2011-05-05 11:40:22 +00:00
|
|
|
|
|
|
|
switch(addr) {
|
|
|
|
case 0xf0: //TEST -- write-only register
|
|
|
|
return 0x00;
|
|
|
|
|
|
|
|
case 0xf1: //CONTROL -- write-only register
|
|
|
|
return 0x00;
|
|
|
|
|
|
|
|
case 0xf2: //DSPADDR
|
2015-11-10 11:02:29 +00:00
|
|
|
return status.dspAddr;
|
2011-05-05 11:40:22 +00:00
|
|
|
|
|
|
|
case 0xf3: //DSPDATA
|
|
|
|
//0x80-0xff are read-only mirrors of 0x00-0x7f
|
2015-11-10 11:02:29 +00:00
|
|
|
return dsp.read(status.dspAddr & 0x7f);
|
2011-05-05 11:40:22 +00:00
|
|
|
|
|
|
|
case 0xf4: //CPUIO0
|
|
|
|
case 0xf5: //CPUIO1
|
|
|
|
case 0xf6: //CPUIO2
|
|
|
|
case 0xf7: //CPUIO3
|
2015-11-10 11:02:29 +00:00
|
|
|
synchronizeCPU();
|
Update to v095r05 release.
byuu says:
Changelog:
- GBA: lots of emulation improvements
- PPU PRAM is 16-bits wide
- DMA masks &~1/Half, &~3/Word
- VRAM OBJ 8-bit writes are ignored
- OAM 8-bit writes are ignored
- BGnCNT unused bits are writable*
- BG(0,1)CNT can't set the d13
- BLDALPHA is readable (fixes Donkey Kong Country, etc)
- SNES: lots of code cleanups
- sfc/chip => sfc/coprocessor
- UI: save most recent controller selection
GBA test scores: 1552/1552, 37/38, 1020/1260
(* forgot to add the value to the read function, so endrift's I/O tests
for them will fail. Fixed locally.)
Note: SNES is the only system with multiple controller/expansion port
options, and as such is the only one with a "None" option. Because it's
shared by the controller and expansion port, it ends up sorted first in
the list. This means that on your first run, you'll need to go to Super
Famicom->Controller Port 1 and select "Gamepad", otherwise input won't
work.
Also note that changing the expansion port device requires loading a new
cart. Unlike controllers, you aren't meant to hotplug expansion port
devices.
2015-11-12 10:15:03 +00:00
|
|
|
return cpu.portRead(addr);
|
2011-05-05 11:40:22 +00:00
|
|
|
|
|
|
|
case 0xf8: //RAM0
|
|
|
|
return status.ram00f8;
|
|
|
|
|
|
|
|
case 0xf9: //RAM1
|
|
|
|
return status.ram00f9;
|
|
|
|
|
|
|
|
case 0xfa: //T0TARGET
|
|
|
|
case 0xfb: //T1TARGET
|
|
|
|
case 0xfc: //T2TARGET -- write-only registers
|
|
|
|
return 0x00;
|
|
|
|
|
|
|
|
case 0xfd: //T0OUT -- 4-bit counter value
|
2015-11-10 11:02:29 +00:00
|
|
|
result = timer0.stage3;
|
|
|
|
timer0.stage3 = 0;
|
2011-05-05 11:40:22 +00:00
|
|
|
return result;
|
|
|
|
|
|
|
|
case 0xfe: //T1OUT -- 4-bit counter value
|
2015-11-10 11:02:29 +00:00
|
|
|
result = timer1.stage3;
|
|
|
|
timer1.stage3 = 0;
|
2011-05-05 11:40:22 +00:00
|
|
|
return result;
|
|
|
|
|
|
|
|
case 0xff: //T2OUT -- 4-bit counter value
|
2015-11-10 11:02:29 +00:00
|
|
|
result = timer2.stage3;
|
|
|
|
timer2.stage3 = 0;
|
2011-05-05 11:40:22 +00:00
|
|
|
return result;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-11-10 11:02:29 +00:00
|
|
|
return ramRead(addr);
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-11-10 11:02:29 +00:00
|
|
|
auto SMP::busWrite(uint16 addr, uint8 data) -> void {
|
2011-05-05 11:40:22 +00:00
|
|
|
switch(addr) {
|
|
|
|
case 0xf0: //TEST
|
|
|
|
if(regs.p.p) break; //writes only valid when P flag is clear
|
|
|
|
|
2015-11-10 11:02:29 +00:00
|
|
|
status.clockSpeed = (data >> 6) & 3;
|
|
|
|
status.timerSpeed = (data >> 4) & 3;
|
|
|
|
status.timersEnable = data & 0x08;
|
|
|
|
status.ramDisable = data & 0x04;
|
|
|
|
status.ramWritable = data & 0x02;
|
|
|
|
status.timersDisable = data & 0x01;
|
2011-05-05 11:40:22 +00:00
|
|
|
|
2015-11-10 11:02:29 +00:00
|
|
|
status.timerStep = (1 << status.clockSpeed) + (2 << status.timerSpeed);
|
2011-05-05 11:40:22 +00:00
|
|
|
|
2015-11-10 11:02:29 +00:00
|
|
|
timer0.synchronizeStage1();
|
|
|
|
timer1.synchronizeStage1();
|
|
|
|
timer2.synchronizeStage1();
|
2011-05-05 11:40:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xf1: //CONTROL
|
2015-11-10 11:02:29 +00:00
|
|
|
status.iplromEnable = data & 0x80;
|
2011-05-05 11:40:22 +00:00
|
|
|
|
|
|
|
if(data & 0x30) {
|
|
|
|
//one-time clearing of APU port read registers,
|
|
|
|
//emulated by simulating CPU writes of 0x00
|
2015-11-10 11:02:29 +00:00
|
|
|
synchronizeCPU();
|
2011-05-05 11:40:22 +00:00
|
|
|
if(data & 0x20) {
|
Update to v095r05 release.
byuu says:
Changelog:
- GBA: lots of emulation improvements
- PPU PRAM is 16-bits wide
- DMA masks &~1/Half, &~3/Word
- VRAM OBJ 8-bit writes are ignored
- OAM 8-bit writes are ignored
- BGnCNT unused bits are writable*
- BG(0,1)CNT can't set the d13
- BLDALPHA is readable (fixes Donkey Kong Country, etc)
- SNES: lots of code cleanups
- sfc/chip => sfc/coprocessor
- UI: save most recent controller selection
GBA test scores: 1552/1552, 37/38, 1020/1260
(* forgot to add the value to the read function, so endrift's I/O tests
for them will fail. Fixed locally.)
Note: SNES is the only system with multiple controller/expansion port
options, and as such is the only one with a "None" option. Because it's
shared by the controller and expansion port, it ends up sorted first in
the list. This means that on your first run, you'll need to go to Super
Famicom->Controller Port 1 and select "Gamepad", otherwise input won't
work.
Also note that changing the expansion port device requires loading a new
cart. Unlike controllers, you aren't meant to hotplug expansion port
devices.
2015-11-12 10:15:03 +00:00
|
|
|
cpu.portWrite(2, 0x00);
|
|
|
|
cpu.portWrite(3, 0x00);
|
2011-05-05 11:40:22 +00:00
|
|
|
}
|
|
|
|
if(data & 0x10) {
|
Update to v095r05 release.
byuu says:
Changelog:
- GBA: lots of emulation improvements
- PPU PRAM is 16-bits wide
- DMA masks &~1/Half, &~3/Word
- VRAM OBJ 8-bit writes are ignored
- OAM 8-bit writes are ignored
- BGnCNT unused bits are writable*
- BG(0,1)CNT can't set the d13
- BLDALPHA is readable (fixes Donkey Kong Country, etc)
- SNES: lots of code cleanups
- sfc/chip => sfc/coprocessor
- UI: save most recent controller selection
GBA test scores: 1552/1552, 37/38, 1020/1260
(* forgot to add the value to the read function, so endrift's I/O tests
for them will fail. Fixed locally.)
Note: SNES is the only system with multiple controller/expansion port
options, and as such is the only one with a "None" option. Because it's
shared by the controller and expansion port, it ends up sorted first in
the list. This means that on your first run, you'll need to go to Super
Famicom->Controller Port 1 and select "Gamepad", otherwise input won't
work.
Also note that changing the expansion port device requires loading a new
cart. Unlike controllers, you aren't meant to hotplug expansion port
devices.
2015-11-12 10:15:03 +00:00
|
|
|
cpu.portWrite(0, 0x00);
|
|
|
|
cpu.portWrite(1, 0x00);
|
2011-05-05 11:40:22 +00:00
|
|
|
}
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2011-05-05 11:40:22 +00:00
|
|
|
//0->1 transistion resets timers
|
2015-11-10 11:02:29 +00:00
|
|
|
if(!timer2.enable && (data & 0x04)) {
|
|
|
|
timer2.stage2 = 0;
|
|
|
|
timer2.stage3 = 0;
|
2011-05-05 11:40:22 +00:00
|
|
|
}
|
|
|
|
timer2.enable = data & 0x04;
|
|
|
|
|
2015-11-10 11:02:29 +00:00
|
|
|
if(!timer1.enable && (data & 0x02)) {
|
|
|
|
timer1.stage2 = 0;
|
|
|
|
timer1.stage3 = 0;
|
2011-05-05 11:40:22 +00:00
|
|
|
}
|
|
|
|
timer1.enable = data & 0x02;
|
|
|
|
|
2015-11-10 11:02:29 +00:00
|
|
|
if(!timer0.enable && (data & 0x01)) {
|
|
|
|
timer0.stage2 = 0;
|
|
|
|
timer0.stage3 = 0;
|
2011-05-05 11:40:22 +00:00
|
|
|
}
|
|
|
|
timer0.enable = data & 0x01;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xf2: //DSPADDR
|
2015-11-10 11:02:29 +00:00
|
|
|
status.dspAddr = data;
|
2011-05-05 11:40:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xf3: //DSPDATA
|
2015-11-10 11:02:29 +00:00
|
|
|
if(status.dspAddr & 0x80) break; //0x80-0xff are read-only mirrors of 0x00-0x7f
|
|
|
|
dsp.write(status.dspAddr & 0x7f, data);
|
2011-05-05 11:40:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xf4: //CPUIO0
|
|
|
|
case 0xf5: //CPUIO1
|
|
|
|
case 0xf6: //CPUIO2
|
|
|
|
case 0xf7: //CPUIO3
|
2015-11-10 11:02:29 +00:00
|
|
|
synchronizeCPU();
|
|
|
|
portWrite(addr, data);
|
2011-05-05 11:40:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xf8: //RAM0
|
|
|
|
status.ram00f8 = data;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xf9: //RAM1
|
|
|
|
status.ram00f9 = data;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xfa: //T0TARGET
|
|
|
|
timer0.target = data;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xfb: //T1TARGET
|
|
|
|
timer1.target = data;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xfc: //T2TARGET
|
|
|
|
timer2.target = data;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xfd: //T0OUT
|
|
|
|
case 0xfe: //T1OUT
|
|
|
|
case 0xff: //T2OUT -- read-only registers
|
|
|
|
break;
|
|
|
|
}
|
2011-06-11 09:14:47 +00:00
|
|
|
|
2015-11-10 11:02:29 +00:00
|
|
|
ramWrite(addr, data); //all writes, even to MMIO registers, appear on bus
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2016-06-05 04:52:43 +00:00
|
|
|
auto SMP::io() -> void {
|
2015-11-10 11:02:29 +00:00
|
|
|
addClocks(24);
|
|
|
|
cycleEdge();
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2016-06-05 04:52:43 +00:00
|
|
|
auto SMP::read(uint16 addr) -> uint8 {
|
2015-11-10 11:02:29 +00:00
|
|
|
addClocks(12);
|
|
|
|
uint8 data = busRead(addr);
|
|
|
|
addClocks(12);
|
|
|
|
cycleEdge();
|
Update to v094r05 release.
byuu says:
Commands can be prefixed with: (cpu|smp|ppu|dsp|apu|vram|oam|cgram)/ to
set their source. Eg "vram/hex 0800" or "smp/breakpoints.append execute
ffc0"; default is cpu.
These overlap a little bit in odd ways, but that's just the way the SNES
works: it's not a very orthogonal system. CPU is both a processor and
the main bus (ROM, RAM, WRAM, etc), APU is the shared memory by the
SMP+DSP (eg use it to catch writes from either chip); PPU probably won't
ever be used since it's broken down into three separate buses (VRAM,
OAM, CGRAM), but DSP could be useful for tracking bugs like we found in
Koushien 2 with the DSP echo buffer corrupting SMP opcodes. Technically
the PPU memory pools are only ever tripped by the CPU poking at them, as
the PPU doesn't ever write.
I now have run.for, run.to, step.for, step.to. The difference is that
run only prints the next instruction after running, whereas step prints
all of the instructions along the way as well. run.to acts the same as
"step over" here. Although it's not quite as nice, since you have to
specify the address of the next instruction.
Logging the Field/Vcounter/Hcounter on instruction listings now, good
for timing information.
Added in the tracer mask, as well as memory export, as well as
VRAM/OAM/CGRAM/SMP read/write/execute breakpoints, as well as an APU
usage map (it tracks DSP reads/writes separately, although I don't
currently have debugger callbacks on DSP accesses just yet.)
Have not hooked up actual SMP debugging just yet, but I plan to soon.
Still thinking about how I want to allow / block interleaving of
instructions (terminal output and tracing.)
So ... remaining tasks at this point:
- full SMP debugging
- CPU+SMP interleave support
- aliases
- hotkeys
- save states (will be kind of tricky ... will have to suppress
breakpoints during synchronization, or abort a save in a break event.)
- keep track of window geometry between runs
2014-02-05 11:30:08 +00:00
|
|
|
debugger.op_read(addr, data);
|
|
|
|
return data;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2016-06-05 04:52:43 +00:00
|
|
|
auto SMP::write(uint16 addr, uint8 data) -> void {
|
2015-11-10 11:02:29 +00:00
|
|
|
addClocks(24);
|
|
|
|
busWrite(addr, data);
|
|
|
|
cycleEdge();
|
Update to v094r05 release.
byuu says:
Commands can be prefixed with: (cpu|smp|ppu|dsp|apu|vram|oam|cgram)/ to
set their source. Eg "vram/hex 0800" or "smp/breakpoints.append execute
ffc0"; default is cpu.
These overlap a little bit in odd ways, but that's just the way the SNES
works: it's not a very orthogonal system. CPU is both a processor and
the main bus (ROM, RAM, WRAM, etc), APU is the shared memory by the
SMP+DSP (eg use it to catch writes from either chip); PPU probably won't
ever be used since it's broken down into three separate buses (VRAM,
OAM, CGRAM), but DSP could be useful for tracking bugs like we found in
Koushien 2 with the DSP echo buffer corrupting SMP opcodes. Technically
the PPU memory pools are only ever tripped by the CPU poking at them, as
the PPU doesn't ever write.
I now have run.for, run.to, step.for, step.to. The difference is that
run only prints the next instruction after running, whereas step prints
all of the instructions along the way as well. run.to acts the same as
"step over" here. Although it's not quite as nice, since you have to
specify the address of the next instruction.
Logging the Field/Vcounter/Hcounter on instruction listings now, good
for timing information.
Added in the tracer mask, as well as memory export, as well as
VRAM/OAM/CGRAM/SMP read/write/execute breakpoints, as well as an APU
usage map (it tracks DSP reads/writes separately, although I don't
currently have debugger callbacks on DSP accesses just yet.)
Have not hooked up actual SMP debugging just yet, but I plan to soon.
Still thinking about how I want to allow / block interleaving of
instructions (terminal output and tracing.)
So ... remaining tasks at this point:
- full SMP debugging
- CPU+SMP interleave support
- aliases
- hotkeys
- save states (will be kind of tricky ... will have to suppress
breakpoints during synchronization, or abort a save in a break event.)
- keep track of window geometry between runs
2014-02-05 11:30:08 +00:00
|
|
|
debugger.op_write(addr, data);
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2016-06-05 04:52:43 +00:00
|
|
|
auto SMP::disassemblerRead(uint16 addr) -> uint8 {
|
2012-04-29 06:16:44 +00:00
|
|
|
if((addr & 0xfff0) == 0x00f0) return 0x00;
|
2015-11-10 11:02:29 +00:00
|
|
|
if((addr & 0xffc0) == 0xffc0 && status.iplromEnable) return iplrom[addr & 0x3f];
|
2012-04-29 06:16:44 +00:00
|
|
|
return apuram[addr];
|
|
|
|
}
|