2012-04-29 06:16:44 +00:00
|
|
|
#include <sfc/sfc.hpp>
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
#define SDD1_CPP
|
2012-04-26 10:51:13 +00:00
|
|
|
namespace SuperFamicom {
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
SDD1 sdd1;
|
|
|
|
|
Update to v080r01 release.
byuu says:
There was one unfortunate aspect of the S-DD1 module: you had to give it
the DMA length and a target buffer, and it would do the entire
decompression at once. Real hardware would work by streaming the data
byte by byte. So with that, I went ahead and rewrote the code to handle
byte-based streaming.
This WIP is an important milestone for me personally. Up until now,
bsnes has always had code that was directly copy-pasted from other
authors. With all of the DSP and Cx4 chips rewritten in LLE, and the
SPC7110 algorithm already ported over from C, and archive decompression
code removed for a long time, the S-DD1 was the only module left like
this. It's obviously not that big of a deal. The code is basically still
a copy of the original. S-DD1 decomp from Andreas Naive, SPC7110 decomp
from neviksti, and S-DSP from blargg. And the rest of the emulator is of
course only possible because of code and research before it, although
everything else has no resemblance at all to code before it. The main
advantage, really, is absolute code consistency. I always use the same
variant of K&R, for instance. I dunno, I guess I just never really liked
the "Build-a-Bear Workshop" style of emulators, like is so prominent in
the Genesis scene: "My new Genesis emu (uses Starscream/Musashi 68K
core, Marat Fayzullin's Z80 core, YM2612 core from Game_Music_Emu, VDP
core from Gens, SVP core from picodrive)", sorry, but you wrote
a front-end, not an emulator :/
I also updated the SPC7110 decompression module: I merged the class
inside the SPC7110 class (not sure why it was separate before), and
replaced the morton lookup tables with for-loops. The morton tables were
added to be a tiny bit faster when I was more interested in speed than
code clarity. It may be a tiny bit slower (or faster due to less L2
cache usage), but you won't even notice an FPS drop, and it cuts out
a good chunk of code and some tables. Lastly, I added pinput_poll() to
video_refresh(). Forgot to remove Interface::input_poll() from the C++
side, will have to do that later.
2011-06-28 11:36:00 +00:00
|
|
|
#include "decomp.cpp"
|
2010-08-09 13:28:56 +00:00
|
|
|
#include "serialization.cpp"
|
|
|
|
|
Update to v074r10 release.
byuu says:
Major WIP, countless changes. I really went to town on cleaning up the
source today with all kinds of new ideas. I'll post the ones I remember,
use diff -ru to get the rest.
What I like the most is my new within template:
template<unsigned lo, unsigned hi>
alwaysinline bool within(unsigned addr) {
static const unsigned mask = ~(hi ^ lo);
return (addr & mask) == lo;
}
Before, you would see code like this:
if((addr & 0xe0e000) == 0x206000) { //$20-3f:6000-7fff
The comment is basically necessary, and you have to trust that the mask
is right, or do the math yourself.
Now, it looks like this:
if(within<0x20, 0x3f, 0x6000, 0x7fff>(addr)) {
That's the same as within<0x206000, 0x3f7fff>, I just made an
SNES-variant to more closely simulate my XML mapping style:
20-3f:6000-7fff.
Now obviously this has limitations, it only works in base-2 and it can't
manage some tricky edge cases like (addr & 0x408000) == 0x008000 for
00-3f|80-bf:8000-ffff. But for the most part, I'll be using this where
I can. The Game Boy is fully ported over to it (via the MBCs), but the
SNES only has the BS-X town cartridge moved over so far. SuperFX and
SA-1 at the very least could benefit.
Next up, since the memory map is now static, there's really no reason to
remap the entire thing at power-on and reset. So it is now set up at
cartridge load and that's it. I moved the CPU/PPU/WRAM mapping out of
memory.cpp and into their respective processors. A bit of duplication
only because there are multiple processor cores for the different
profiles, but I'm not worried about that. This is also going to be
necessary to fix the debugger.
Next, Coprocessor::enable() actually does what I initially intended it
to now: it is called once to turn a chip on after cartridge load. It's
not called on power cycle anymore. This should help fix power-cycle on
my serial simulation code, and was needed to map the bus exactly one
time. Although most stuff is mapped through XML, some chips still need
some manual hooks for monitoring and such (eg S-DD1.)
Next, I've started killing off memory::, it was initially an
over-reaction to the question of where to put APURAM (in the SMP or
DSP?). The idea was to have this namespace that contained all memory for
everything. But it was very annoying and tedious, and various chips
ignored the convention anyway like ST-0011 RAM, which couldn't work
anyway since it is natively uint16 and not uint8. Cx4 will need 24-bit
RAM eventually, too. There's 8->24-bit functions in there now, because
the HLE code is hideous.
So far, all the cartridge.cpp memory:: types have been destroyed.
memory::cartrom, memory::cartram become cartridge.rom and cartridge.ram.
memory::cartrtc was moved into the SRTC and SPC7110 classes directly.
memory::bsxflash was moved into BSXFlash. memory::bsxram and
memory::bsxpram were moved into BSXCartridge (the town cartridge).
memory::st[AB](rom|ram) were moved into a new area,
snes/chip/sufamiturbo. The snes/chip moniker really doesn't work so
well, since it also has base units, and the serial communications stuff
which is through the controller port, but oh well, now it also has the
base structure for the Sufami Turbo cartridge too. So now we have
sufamiturbo.slotA.rom, sufamiturbo.slotB.ram, etc.
Next, the ST-0010/ST-0011 actually save the data RAM to disk. This
wasn't at all compatible with my old system, and I didn't want to keep
adding memory types to check inside the main UI cartridge RAM loading
and saving routines.
So I built a NonVolatileRAM vector inside SNES::Cartridge, and any chip
that has memory it wants to save and load from disk can append onto it
: data, size, id ("srm", "rtc", "nec", etc) and slot (0 = cartridge,
1 = slot A, 2 = slot B)
To load and save memory, we just do a simple: foreach(memory,
SNES::cartridge.nvram) load/saveMemory(memory).
As a result, you can now keep your save games in F1 Race of Champions II
and Hayazashi Nidan Morita Shougi. Technically I think Metal Combat
should work this way as well, having the RAM being part of the chip
itself, but for now that chip just writes directly into cartridge.ram,
so it also technically saves to disk for now.
To avoid a potential conflict with a manipulated memory map, BS-X SRAM
and PSRAM are now .bss and .bsp, and not .srm and .psr. Honestly I don't
like .srm as an extension either, but it doesn't bother me enough to
break save RAM compatibility with other emulators, so don't worry about
that changing.
I finally killed off MappedRAM initializing size to ~0 (-1U). A size of
zero means there is no memory there just the same. This was an old
holdover for handling MMIO mapping, if I recall correctly. Something
about a size of zero on MMIO-Memory objects causing it to wrap the
address, so ~0 would let it map direct addresses ... or something.
Whatever, that's not needed at all anymore.
BSXBase becomes BSXSatellaview, and I've defaulted the device to being
attached since it won't affect non-BSX games anyway. Eventually the GUI
needs to make that an option. BSXCart becomes BSXCartridge. BSXFlash
remains unchanged.
I probably need to make Coprocessor::disable() functions now to free up
memory on unload, but it shouldn't hurt anything the way it is.
libsnes is most definitely broken to all hell and back now, and the
debugger is still shot. I suppose we'll need some tricky code to work
with the old ID system, and we'll need to add some more IDs for the new
memory types.
2011-01-24 08:59:45 +00:00
|
|
|
void SDD1::init() {
|
|
|
|
}
|
2010-08-09 13:28:56 +00:00
|
|
|
|
Update to v075 release.
byuu says:
This release brings improved Super Game Boy emulation, the final SHA256
hashes for the DSP-(1,1B,2,3,4) and ST-(0010,0011) coprocessors, user
interface improvements, and major internal code restructuring.
Changelog (since v074):
- completely rewrote memory sub-system to support 1-byte granularity in
XML mapping
- removed Memory inheritance and MMIO class completely, any address can
be mapped to any function now
- SuperFX: removed SuperFXBus : Bus, now implemented manually
- SA-1: removed SA1Bus : Bus, now implemented manually
- entire bus mapping is now static, happens once on cartridge load
- as a result, read/write handlers now handle MMC mapping; slower
average case, far faster worst case
- namespace memory is no more, RAM arrays are stored inside the chips
they are owned by now
- GameBoy: improved CPU HALT emulation, fixes Zelda: Link's Awakening
scrolling
- GameBoy: added serial emulation (cannot connect to another GB yet),
fixes Shin Megami Tensei - Devichil
- GameBoy: improved LCD STAT emulation, fixes Sagaia
- ui: added fullscreen support (F11 key), video settings allows for
three scale settings
- ui: fixed brightness, contrast, gamma, audio volume, input frequency
values on program startup
- ui: since Qt is dead, config file becomes bsnes.cfg once again
- Super Game Boy: you can now load the BIOS without a game inserted to
see a pretty white box
- ui-gameboy: can be built without SNES components now
- libsnes: now a UI target, compile with 'make ui=ui-libsnes'
- libsnes: added WRAM, APURAM, VRAM, OAM, CGRAM access (cheat search,
etc)
- source: removed launcher/, as the Qt port is now gone
- source: Makefile restructuring to better support new ui targets
- source: lots of other internal code cleanup work
2011-01-27 08:52:34 +00:00
|
|
|
void SDD1::load() {
|
Update to v074r10 release.
byuu says:
Major WIP, countless changes. I really went to town on cleaning up the
source today with all kinds of new ideas. I'll post the ones I remember,
use diff -ru to get the rest.
What I like the most is my new within template:
template<unsigned lo, unsigned hi>
alwaysinline bool within(unsigned addr) {
static const unsigned mask = ~(hi ^ lo);
return (addr & mask) == lo;
}
Before, you would see code like this:
if((addr & 0xe0e000) == 0x206000) { //$20-3f:6000-7fff
The comment is basically necessary, and you have to trust that the mask
is right, or do the math yourself.
Now, it looks like this:
if(within<0x20, 0x3f, 0x6000, 0x7fff>(addr)) {
That's the same as within<0x206000, 0x3f7fff>, I just made an
SNES-variant to more closely simulate my XML mapping style:
20-3f:6000-7fff.
Now obviously this has limitations, it only works in base-2 and it can't
manage some tricky edge cases like (addr & 0x408000) == 0x008000 for
00-3f|80-bf:8000-ffff. But for the most part, I'll be using this where
I can. The Game Boy is fully ported over to it (via the MBCs), but the
SNES only has the BS-X town cartridge moved over so far. SuperFX and
SA-1 at the very least could benefit.
Next up, since the memory map is now static, there's really no reason to
remap the entire thing at power-on and reset. So it is now set up at
cartridge load and that's it. I moved the CPU/PPU/WRAM mapping out of
memory.cpp and into their respective processors. A bit of duplication
only because there are multiple processor cores for the different
profiles, but I'm not worried about that. This is also going to be
necessary to fix the debugger.
Next, Coprocessor::enable() actually does what I initially intended it
to now: it is called once to turn a chip on after cartridge load. It's
not called on power cycle anymore. This should help fix power-cycle on
my serial simulation code, and was needed to map the bus exactly one
time. Although most stuff is mapped through XML, some chips still need
some manual hooks for monitoring and such (eg S-DD1.)
Next, I've started killing off memory::, it was initially an
over-reaction to the question of where to put APURAM (in the SMP or
DSP?). The idea was to have this namespace that contained all memory for
everything. But it was very annoying and tedious, and various chips
ignored the convention anyway like ST-0011 RAM, which couldn't work
anyway since it is natively uint16 and not uint8. Cx4 will need 24-bit
RAM eventually, too. There's 8->24-bit functions in there now, because
the HLE code is hideous.
So far, all the cartridge.cpp memory:: types have been destroyed.
memory::cartrom, memory::cartram become cartridge.rom and cartridge.ram.
memory::cartrtc was moved into the SRTC and SPC7110 classes directly.
memory::bsxflash was moved into BSXFlash. memory::bsxram and
memory::bsxpram were moved into BSXCartridge (the town cartridge).
memory::st[AB](rom|ram) were moved into a new area,
snes/chip/sufamiturbo. The snes/chip moniker really doesn't work so
well, since it also has base units, and the serial communications stuff
which is through the controller port, but oh well, now it also has the
base structure for the Sufami Turbo cartridge too. So now we have
sufamiturbo.slotA.rom, sufamiturbo.slotB.ram, etc.
Next, the ST-0010/ST-0011 actually save the data RAM to disk. This
wasn't at all compatible with my old system, and I didn't want to keep
adding memory types to check inside the main UI cartridge RAM loading
and saving routines.
So I built a NonVolatileRAM vector inside SNES::Cartridge, and any chip
that has memory it wants to save and load from disk can append onto it
: data, size, id ("srm", "rtc", "nec", etc) and slot (0 = cartridge,
1 = slot A, 2 = slot B)
To load and save memory, we just do a simple: foreach(memory,
SNES::cartridge.nvram) load/saveMemory(memory).
As a result, you can now keep your save games in F1 Race of Champions II
and Hayazashi Nidan Morita Shougi. Technically I think Metal Combat
should work this way as well, having the RAM being part of the chip
itself, but for now that chip just writes directly into cartridge.ram,
so it also technically saves to disk for now.
To avoid a potential conflict with a manipulated memory map, BS-X SRAM
and PSRAM are now .bss and .bsp, and not .srm and .psr. Honestly I don't
like .srm as an extension either, but it doesn't bother me enough to
break save RAM compatibility with other emulators, so don't worry about
that changing.
I finally killed off MappedRAM initializing size to ~0 (-1U). A size of
zero means there is no memory there just the same. This was an old
holdover for handling MMIO mapping, if I recall correctly. Something
about a size of zero on MMIO-Memory objects causing it to wrap the
address, so ~0 would let it map direct addresses ... or something.
Whatever, that's not needed at all anymore.
BSXBase becomes BSXSatellaview, and I've defaulted the device to being
attached since it won't affect non-BSX games anyway. Eventually the GUI
needs to make that an option. BSXCart becomes BSXCartridge. BSXFlash
remains unchanged.
I probably need to make Coprocessor::disable() functions now to free up
memory on unload, but it shouldn't hurt anything the way it is.
libsnes is most definitely broken to all hell and back now, and the
debugger is still shot. I suppose we'll need some tricky code to work
with the old ID system, and we'll need to add some more IDs for the new
memory types.
2011-01-24 08:59:45 +00:00
|
|
|
//hook S-CPU DMA MMIO registers to gather information for struct dma[];
|
|
|
|
//buffer address and transfer size information for use in SDD1::mcu_read()
|
Update to v091r05 release.
[No prior releases were posted to the WIP thread. -Ed.]
byuu says:
Super Famicom mapping system has been reworked as discussed with the
mask= changes. offset becomes base, mode is gone. Also added support for
comma-separated fields in the address fields, to reduce the number of
map lines needed.
<?xml version="1.0" encoding="UTF-8"?>
<cartridge region="NTSC">
<superfx revision="2">
<rom name="program.rom" size="0x200000"/>
<ram name="save.rwm" size="0x8000"/>
<map id="io" address="00-3f,80-bf:3000-32ff"/>
<map id="rom" address="00-3f:8000-ffff" mask="0x8000"/>
<map id="rom" address="40-5f:0000-ffff"/>
<map id="ram" address="00-3f,80-bf:6000-7fff" size="0x2000"/>
<map id="ram" address="70-71:0000-ffff"/>
</superfx>
</cartridge>
Or in BML:
cartridge region=NTSC
superfx revision=2
rom name=program.rom size=0x200000
ram name=save.rwm size=0x8000
map id=io address=00-3f,80-bf:3000-32ff
map id=rom address=00-3f:8000-ffff mask=0x8000
map id=rom address=40-5f:0000-ffff
map id=ram address=00-3f,80-bf:6000-7fff size=0x2000
map id=ram address=70-71:0000-ffff
As a result of the changes, old mappings will no longer work. The above
XML example will run Super Mario World 2: Yoshi's Island. Otherwise,
you'll have to write your own.
All that's left now is to work some sort of database mapping system in,
so I can start dumping carts en masse.
The NES changes that FitzRoy asked for are mostly in as well.
Also, part of the reason I haven't released a WIP ... but fuck it, I'm
not going to wait forever to post a new WIP.
I've added a skeleton driver to emulate Campus Challenge '92 and
Powerfest '94. There's no actual emulation, except for the stuff I can
glean from looking at the pictures of the board. It has a DSP-1 (so
SR/DR registers), four ROMs that map in and out, RAM, etc.
I've also added preliminary mapping to upload high scores to a website,
but obviously I need the ROMs first.
2012-10-09 08:25:32 +00:00
|
|
|
bus.map({&SDD1::read, &sdd1}, {&SDD1::write, &sdd1}, 0x00, 0x3f, 0x4300, 0x437f);
|
|
|
|
bus.map({&SDD1::read, &sdd1}, {&SDD1::write, &sdd1}, 0x80, 0xbf, 0x4300, 0x437f);
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
Update to v075 release.
byuu says:
This release brings improved Super Game Boy emulation, the final SHA256
hashes for the DSP-(1,1B,2,3,4) and ST-(0010,0011) coprocessors, user
interface improvements, and major internal code restructuring.
Changelog (since v074):
- completely rewrote memory sub-system to support 1-byte granularity in
XML mapping
- removed Memory inheritance and MMIO class completely, any address can
be mapped to any function now
- SuperFX: removed SuperFXBus : Bus, now implemented manually
- SA-1: removed SA1Bus : Bus, now implemented manually
- entire bus mapping is now static, happens once on cartridge load
- as a result, read/write handlers now handle MMC mapping; slower
average case, far faster worst case
- namespace memory is no more, RAM arrays are stored inside the chips
they are owned by now
- GameBoy: improved CPU HALT emulation, fixes Zelda: Link's Awakening
scrolling
- GameBoy: added serial emulation (cannot connect to another GB yet),
fixes Shin Megami Tensei - Devichil
- GameBoy: improved LCD STAT emulation, fixes Sagaia
- ui: added fullscreen support (F11 key), video settings allows for
three scale settings
- ui: fixed brightness, contrast, gamma, audio volume, input frequency
values on program startup
- ui: since Qt is dead, config file becomes bsnes.cfg once again
- Super Game Boy: you can now load the BIOS without a game inserted to
see a pretty white box
- ui-gameboy: can be built without SNES components now
- libsnes: now a UI target, compile with 'make ui=ui-libsnes'
- libsnes: added WRAM, APURAM, VRAM, OAM, CGRAM access (cheat search,
etc)
- source: removed launcher/, as the Qt port is now gone
- source: Makefile restructuring to better support new ui targets
- source: lots of other internal code cleanup work
2011-01-27 08:52:34 +00:00
|
|
|
void SDD1::unload() {
|
2012-07-08 02:57:34 +00:00
|
|
|
rom.reset();
|
|
|
|
ram.reset();
|
Update to v075 release.
byuu says:
This release brings improved Super Game Boy emulation, the final SHA256
hashes for the DSP-(1,1B,2,3,4) and ST-(0010,0011) coprocessors, user
interface improvements, and major internal code restructuring.
Changelog (since v074):
- completely rewrote memory sub-system to support 1-byte granularity in
XML mapping
- removed Memory inheritance and MMIO class completely, any address can
be mapped to any function now
- SuperFX: removed SuperFXBus : Bus, now implemented manually
- SA-1: removed SA1Bus : Bus, now implemented manually
- entire bus mapping is now static, happens once on cartridge load
- as a result, read/write handlers now handle MMC mapping; slower
average case, far faster worst case
- namespace memory is no more, RAM arrays are stored inside the chips
they are owned by now
- GameBoy: improved CPU HALT emulation, fixes Zelda: Link's Awakening
scrolling
- GameBoy: added serial emulation (cannot connect to another GB yet),
fixes Shin Megami Tensei - Devichil
- GameBoy: improved LCD STAT emulation, fixes Sagaia
- ui: added fullscreen support (F11 key), video settings allows for
three scale settings
- ui: fixed brightness, contrast, gamma, audio volume, input frequency
values on program startup
- ui: since Qt is dead, config file becomes bsnes.cfg once again
- Super Game Boy: you can now load the BIOS without a game inserted to
see a pretty white box
- ui-gameboy: can be built without SNES components now
- libsnes: now a UI target, compile with 'make ui=ui-libsnes'
- libsnes: added WRAM, APURAM, VRAM, OAM, CGRAM access (cheat search,
etc)
- source: removed launcher/, as the Qt port is now gone
- source: Makefile restructuring to better support new ui targets
- source: lots of other internal code cleanup work
2011-01-27 08:52:34 +00:00
|
|
|
}
|
|
|
|
|
2010-08-09 13:28:56 +00:00
|
|
|
void SDD1::power() {
|
|
|
|
}
|
|
|
|
|
|
|
|
void SDD1::reset() {
|
|
|
|
sdd1_enable = 0x00;
|
|
|
|
xfer_enable = 0x00;
|
Update to v080r01 release.
byuu says:
There was one unfortunate aspect of the S-DD1 module: you had to give it
the DMA length and a target buffer, and it would do the entire
decompression at once. Real hardware would work by streaming the data
byte by byte. So with that, I went ahead and rewrote the code to handle
byte-based streaming.
This WIP is an important milestone for me personally. Up until now,
bsnes has always had code that was directly copy-pasted from other
authors. With all of the DSP and Cx4 chips rewritten in LLE, and the
SPC7110 algorithm already ported over from C, and archive decompression
code removed for a long time, the S-DD1 was the only module left like
this. It's obviously not that big of a deal. The code is basically still
a copy of the original. S-DD1 decomp from Andreas Naive, SPC7110 decomp
from neviksti, and S-DSP from blargg. And the rest of the emulator is of
course only possible because of code and research before it, although
everything else has no resemblance at all to code before it. The main
advantage, really, is absolute code consistency. I always use the same
variant of K&R, for instance. I dunno, I guess I just never really liked
the "Build-a-Bear Workshop" style of emulators, like is so prominent in
the Genesis scene: "My new Genesis emu (uses Starscream/Musashi 68K
core, Marat Fayzullin's Z80 core, YM2612 core from Game_Music_Emu, VDP
core from Gens, SVP core from picodrive)", sorry, but you wrote
a front-end, not an emulator :/
I also updated the SPC7110 decompression module: I merged the class
inside the SPC7110 class (not sure why it was separate before), and
replaced the morton lookup tables with for-loops. The morton tables were
added to be a tiny bit faster when I was more interested in speed than
code clarity. It may be a tiny bit slower (or faster due to less L2
cache usage), but you won't even notice an FPS drop, and it cuts out
a good chunk of code and some tables. Lastly, I added pinput_poll() to
video_refresh(). Forgot to remove Interface::input_poll() from the C++
side, will have to do that later.
2011-06-28 11:36:00 +00:00
|
|
|
dma_ready = false;
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
mmc[0] = 0 << 20;
|
|
|
|
mmc[1] = 1 << 20;
|
|
|
|
mmc[2] = 2 << 20;
|
|
|
|
mmc[3] = 3 << 20;
|
|
|
|
|
|
|
|
for(unsigned i = 0; i < 8; i++) {
|
|
|
|
dma[i].addr = 0;
|
|
|
|
dma[i].size = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-15 09:47:35 +00:00
|
|
|
uint8 SDD1::read(unsigned addr) {
|
2010-08-09 13:28:56 +00:00
|
|
|
addr &= 0xffff;
|
|
|
|
|
|
|
|
if((addr & 0x4380) == 0x4300) {
|
Update to v074r03 release.
byuu says:
You guys are going to hate the hell out of this one. It's twenty hours
of non-stop work, no exaggeration at all. Started at 4AM, just wrapped
up now at 8PM.
I rewrote the entire memory subsystem.
Old system:
65536 pages that map 256 bytes each
Mapping a new page overwrites old page
Granularity capped at 256 bytes minimum, requiring ST-001x to map
60:0000-00ff instead of 60:0000,0001
Classes inherit from MMIO and Memory, forcing only one mappable function
per class, and fixed names
MMIO sub-mapper inside memory: 00-3f:2000-5fff for one-byte granularity
Can dynamically change the map at run-time, MMC register settings
perform dynamic remapping
New system:
XML mapping is still based around banklo-bankhi:addrlo-addrhi, as that
shapes almost everything on the SNES very well
Internally, 2048 pages that map 8192 bytes each
Pages are vectors, scans O(n) from last to first (O(log n) would not
help, n is never > 3)
Can multi-cast writes, but not reads [for the obvious reason of: which
read do you return?]
Can map reads and writes separately
Granularity of one for entire 24-bit address range, no need for MMIO
- whatever is in XML is exactly what you get
Read/Write tables bind function callbacks, so I can have any number of
functions with any names from any classes with no inheritance (no
more uPD7725DR, uPD7725SR helpers, etc)
Less memory usage overall due to less tables [ I tried 16 million tables
and it used 2GB of RAM >_o ]
Cannot dynamically change the map at run-time, MMC read/write functions
perform address translation [worse average case speed, better worst
case speed]
Now the hate me part, functors can't beat virtual functions for speed.
There are speed penalties involved:
-4.5% on average games
-11% on SuperFX games (SFX has its own bus)
-15% on SA-1 games (SA-1 has two buses)
Of course the two that need the speed the most get the biggest hits.
I'm afraid there's really not a lot of wiggle room to boost speed back
up.
I suppose one bright spot is that we can much more easily try out
entirely new mapping systems now, since the dynamic portions have been
eliminated.
2011-01-15 04:30:29 +00:00
|
|
|
return cpu.mmio_read(addr);
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch(addr) {
|
2013-05-05 09:21:30 +00:00
|
|
|
case 0x4804: return mmc[0] >> 20;
|
|
|
|
case 0x4805: return mmc[1] >> 20;
|
|
|
|
case 0x4806: return mmc[2] >> 20;
|
|
|
|
case 0x4807: return mmc[3] >> 20;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return cpu.regs.mdr;
|
|
|
|
}
|
|
|
|
|
2012-07-15 09:47:35 +00:00
|
|
|
void SDD1::write(unsigned addr, uint8 data) {
|
2010-08-09 13:28:56 +00:00
|
|
|
addr &= 0xffff;
|
|
|
|
|
|
|
|
if((addr & 0x4380) == 0x4300) {
|
|
|
|
unsigned channel = (addr >> 4) & 7;
|
|
|
|
switch(addr & 15) {
|
2013-05-05 09:21:30 +00:00
|
|
|
case 2: dma[channel].addr = (dma[channel].addr & 0xffff00) + (data << 0); break;
|
|
|
|
case 3: dma[channel].addr = (dma[channel].addr & 0xff00ff) + (data << 8); break;
|
|
|
|
case 4: dma[channel].addr = (dma[channel].addr & 0x00ffff) + (data << 16); break;
|
2010-08-09 13:28:56 +00:00
|
|
|
|
2013-05-05 09:21:30 +00:00
|
|
|
case 5: dma[channel].size = (dma[channel].size & 0xff00) + (data << 0); break;
|
|
|
|
case 6: dma[channel].size = (dma[channel].size & 0x00ff) + (data << 8); break;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
Update to v074r03 release.
byuu says:
You guys are going to hate the hell out of this one. It's twenty hours
of non-stop work, no exaggeration at all. Started at 4AM, just wrapped
up now at 8PM.
I rewrote the entire memory subsystem.
Old system:
65536 pages that map 256 bytes each
Mapping a new page overwrites old page
Granularity capped at 256 bytes minimum, requiring ST-001x to map
60:0000-00ff instead of 60:0000,0001
Classes inherit from MMIO and Memory, forcing only one mappable function
per class, and fixed names
MMIO sub-mapper inside memory: 00-3f:2000-5fff for one-byte granularity
Can dynamically change the map at run-time, MMC register settings
perform dynamic remapping
New system:
XML mapping is still based around banklo-bankhi:addrlo-addrhi, as that
shapes almost everything on the SNES very well
Internally, 2048 pages that map 8192 bytes each
Pages are vectors, scans O(n) from last to first (O(log n) would not
help, n is never > 3)
Can multi-cast writes, but not reads [for the obvious reason of: which
read do you return?]
Can map reads and writes separately
Granularity of one for entire 24-bit address range, no need for MMIO
- whatever is in XML is exactly what you get
Read/Write tables bind function callbacks, so I can have any number of
functions with any names from any classes with no inheritance (no
more uPD7725DR, uPD7725SR helpers, etc)
Less memory usage overall due to less tables [ I tried 16 million tables
and it used 2GB of RAM >_o ]
Cannot dynamically change the map at run-time, MMC read/write functions
perform address translation [worse average case speed, better worst
case speed]
Now the hate me part, functors can't beat virtual functions for speed.
There are speed penalties involved:
-4.5% on average games
-11% on SuperFX games (SFX has its own bus)
-15% on SA-1 games (SA-1 has two buses)
Of course the two that need the speed the most get the biggest hits.
I'm afraid there's really not a lot of wiggle room to boost speed back
up.
I suppose one bright spot is that we can much more easily try out
entirely new mapping systems now, since the dynamic portions have been
eliminated.
2011-01-15 04:30:29 +00:00
|
|
|
return cpu.mmio_write(addr, data);
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch(addr) {
|
2013-05-05 09:21:30 +00:00
|
|
|
case 0x4800: sdd1_enable = data; break;
|
|
|
|
case 0x4801: xfer_enable = data; break;
|
2010-08-09 13:28:56 +00:00
|
|
|
|
2013-05-05 09:21:30 +00:00
|
|
|
case 0x4804: mmc[0] = data << 20; break;
|
|
|
|
case 0x4805: mmc[1] = data << 20; break;
|
|
|
|
case 0x4806: mmc[2] = data << 20; break;
|
|
|
|
case 0x4807: mmc[3] = data << 20; break;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-08 02:57:34 +00:00
|
|
|
uint8 SDD1::mmc_read(unsigned addr) {
|
|
|
|
return rom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff));
|
Update to v080r01 release.
byuu says:
There was one unfortunate aspect of the S-DD1 module: you had to give it
the DMA length and a target buffer, and it would do the entire
decompression at once. Real hardware would work by streaming the data
byte by byte. So with that, I went ahead and rewrote the code to handle
byte-based streaming.
This WIP is an important milestone for me personally. Up until now,
bsnes has always had code that was directly copy-pasted from other
authors. With all of the DSP and Cx4 chips rewritten in LLE, and the
SPC7110 algorithm already ported over from C, and archive decompression
code removed for a long time, the S-DD1 was the only module left like
this. It's obviously not that big of a deal. The code is basically still
a copy of the original. S-DD1 decomp from Andreas Naive, SPC7110 decomp
from neviksti, and S-DSP from blargg. And the rest of the emulator is of
course only possible because of code and research before it, although
everything else has no resemblance at all to code before it. The main
advantage, really, is absolute code consistency. I always use the same
variant of K&R, for instance. I dunno, I guess I just never really liked
the "Build-a-Bear Workshop" style of emulators, like is so prominent in
the Genesis scene: "My new Genesis emu (uses Starscream/Musashi 68K
core, Marat Fayzullin's Z80 core, YM2612 core from Game_Music_Emu, VDP
core from Gens, SVP core from picodrive)", sorry, but you wrote
a front-end, not an emulator :/
I also updated the SPC7110 decompression module: I merged the class
inside the SPC7110 class (not sure why it was separate before), and
replaced the morton lookup tables with for-loops. The morton tables were
added to be a tiny bit faster when I was more interested in speed than
code clarity. It may be a tiny bit slower (or faster due to less L2
cache usage), but you won't even notice an FPS drop, and it cuts out
a good chunk of code and some tables. Lastly, I added pinput_poll() to
video_refresh(). Forgot to remove Interface::input_poll() from the C++
side, will have to do that later.
2011-06-28 11:36:00 +00:00
|
|
|
}
|
|
|
|
|
Update to v074r03 release.
byuu says:
You guys are going to hate the hell out of this one. It's twenty hours
of non-stop work, no exaggeration at all. Started at 4AM, just wrapped
up now at 8PM.
I rewrote the entire memory subsystem.
Old system:
65536 pages that map 256 bytes each
Mapping a new page overwrites old page
Granularity capped at 256 bytes minimum, requiring ST-001x to map
60:0000-00ff instead of 60:0000,0001
Classes inherit from MMIO and Memory, forcing only one mappable function
per class, and fixed names
MMIO sub-mapper inside memory: 00-3f:2000-5fff for one-byte granularity
Can dynamically change the map at run-time, MMC register settings
perform dynamic remapping
New system:
XML mapping is still based around banklo-bankhi:addrlo-addrhi, as that
shapes almost everything on the SNES very well
Internally, 2048 pages that map 8192 bytes each
Pages are vectors, scans O(n) from last to first (O(log n) would not
help, n is never > 3)
Can multi-cast writes, but not reads [for the obvious reason of: which
read do you return?]
Can map reads and writes separately
Granularity of one for entire 24-bit address range, no need for MMIO
- whatever is in XML is exactly what you get
Read/Write tables bind function callbacks, so I can have any number of
functions with any names from any classes with no inheritance (no
more uPD7725DR, uPD7725SR helpers, etc)
Less memory usage overall due to less tables [ I tried 16 million tables
and it used 2GB of RAM >_o ]
Cannot dynamically change the map at run-time, MMC read/write functions
perform address translation [worse average case speed, better worst
case speed]
Now the hate me part, functors can't beat virtual functions for speed.
There are speed penalties involved:
-4.5% on average games
-11% on SuperFX games (SFX has its own bus)
-15% on SA-1 games (SA-1 has two buses)
Of course the two that need the speed the most get the biggest hits.
I'm afraid there's really not a lot of wiggle room to boost speed back
up.
I suppose one bright spot is that we can much more easily try out
entirely new mapping systems now, since the dynamic portions have been
eliminated.
2011-01-15 04:30:29 +00:00
|
|
|
//SDD1::mcu_read() is mapped to $c0-ff:0000-ffff
|
2010-08-09 13:28:56 +00:00
|
|
|
//the design is meant to be as close to the hardware design as possible, thus this code
|
|
|
|
//avoids adding S-DD1 hooks inside S-CPU::DMA emulation.
|
|
|
|
//
|
|
|
|
//the real S-DD1 cannot see $420b (DMA enable) writes, as they are not placed on the bus.
|
|
|
|
//however, $43x0-$43xf writes (DMAx channel settings) most likely do appear on the bus.
|
|
|
|
//the S-DD1 also requires fixed addresses for transfers, which wouldn't be necessary if
|
|
|
|
//it could see $420b writes (eg it would know when the transfer should begin.)
|
|
|
|
//
|
|
|
|
//the hardware needs a way to distinguish program code after $4801 writes from DMA
|
|
|
|
//decompression that follows soon after.
|
|
|
|
//
|
|
|
|
//the only plausible design for hardware would be for the S-DD1 to spy on DMAx settings,
|
|
|
|
//and begin spooling decompression on writes to $4801 that activate a channel. after that,
|
|
|
|
//it feeds decompressed data only when the ROM read address matches the DMA channel address.
|
|
|
|
//
|
|
|
|
//the actual S-DD1 transfer can occur on any channel, but it is most likely limited to
|
|
|
|
//one transfer per $420b write (for spooling purposes). however, this is not known for certain.
|
Update to v089r17 release.
byuu says:
This implements the spec from the XML part 3 thread:
http://board.byuu.org/viewtopic.php?f=16&t=2998
It's also propagated the changes to nall and purify, so you can test
this one.
This is basically it, after years of effort I feel I finally have
a fully consistent and logical XML board format.
The only things left to change will be: modifications if emulation turns
out to be incorrect (eg we missed some MMIO mirrors, or mirrored too
much), and new additions.
And of course, I'm giving it a bit of time for good arguments against
the format.
Other than that, this release removes linear_vector and pointer_vector,
as vector is better than linear_vector and I've never used
pointer_vector.
vector also gets move(), which is a way to use move-semantics across
types. It lets you steal the underlying memory pool, effectively
destroying the vector without a copy.
This works really nicely with the move for read() functions to return
vector<uint8> instead of taking (uint8_t*&, unsigned&) parameters.
2012-07-15 13:02:27 +00:00
|
|
|
uint8 SDD1::mcurom_read(unsigned addr) {
|
2012-10-22 22:45:18 +00:00
|
|
|
if(addr < 0x400000) { //(addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff
|
2012-07-08 02:57:34 +00:00
|
|
|
return rom.read(addr);
|
2012-10-22 22:45:18 +00:00
|
|
|
//addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff);
|
|
|
|
//return rom.read(addr);
|
2012-07-08 02:57:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//$40-7f|c0-ff:0000-ffff (MMC)
|
2010-08-09 13:28:56 +00:00
|
|
|
if(sdd1_enable & xfer_enable) {
|
|
|
|
//at least one channel has S-DD1 decompression enabled ...
|
|
|
|
for(unsigned i = 0; i < 8; i++) {
|
|
|
|
if(sdd1_enable & xfer_enable & (1 << i)) {
|
|
|
|
//S-DD1 always uses fixed transfer mode, so address will not change during transfer
|
|
|
|
if(addr == dma[i].addr) {
|
Update to v080r01 release.
byuu says:
There was one unfortunate aspect of the S-DD1 module: you had to give it
the DMA length and a target buffer, and it would do the entire
decompression at once. Real hardware would work by streaming the data
byte by byte. So with that, I went ahead and rewrote the code to handle
byte-based streaming.
This WIP is an important milestone for me personally. Up until now,
bsnes has always had code that was directly copy-pasted from other
authors. With all of the DSP and Cx4 chips rewritten in LLE, and the
SPC7110 algorithm already ported over from C, and archive decompression
code removed for a long time, the S-DD1 was the only module left like
this. It's obviously not that big of a deal. The code is basically still
a copy of the original. S-DD1 decomp from Andreas Naive, SPC7110 decomp
from neviksti, and S-DSP from blargg. And the rest of the emulator is of
course only possible because of code and research before it, although
everything else has no resemblance at all to code before it. The main
advantage, really, is absolute code consistency. I always use the same
variant of K&R, for instance. I dunno, I guess I just never really liked
the "Build-a-Bear Workshop" style of emulators, like is so prominent in
the Genesis scene: "My new Genesis emu (uses Starscream/Musashi 68K
core, Marat Fayzullin's Z80 core, YM2612 core from Game_Music_Emu, VDP
core from Gens, SVP core from picodrive)", sorry, but you wrote
a front-end, not an emulator :/
I also updated the SPC7110 decompression module: I merged the class
inside the SPC7110 class (not sure why it was separate before), and
replaced the morton lookup tables with for-loops. The morton tables were
added to be a tiny bit faster when I was more interested in speed than
code clarity. It may be a tiny bit slower (or faster due to less L2
cache usage), but you won't even notice an FPS drop, and it cuts out
a good chunk of code and some tables. Lastly, I added pinput_poll() to
video_refresh(). Forgot to remove Interface::input_poll() from the C++
side, will have to do that later.
2011-06-28 11:36:00 +00:00
|
|
|
if(!dma_ready) {
|
|
|
|
//prepare streaming decompression
|
|
|
|
decomp.init(addr);
|
|
|
|
dma_ready = true;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
Update to v080r01 release.
byuu says:
There was one unfortunate aspect of the S-DD1 module: you had to give it
the DMA length and a target buffer, and it would do the entire
decompression at once. Real hardware would work by streaming the data
byte by byte. So with that, I went ahead and rewrote the code to handle
byte-based streaming.
This WIP is an important milestone for me personally. Up until now,
bsnes has always had code that was directly copy-pasted from other
authors. With all of the DSP and Cx4 chips rewritten in LLE, and the
SPC7110 algorithm already ported over from C, and archive decompression
code removed for a long time, the S-DD1 was the only module left like
this. It's obviously not that big of a deal. The code is basically still
a copy of the original. S-DD1 decomp from Andreas Naive, SPC7110 decomp
from neviksti, and S-DSP from blargg. And the rest of the emulator is of
course only possible because of code and research before it, although
everything else has no resemblance at all to code before it. The main
advantage, really, is absolute code consistency. I always use the same
variant of K&R, for instance. I dunno, I guess I just never really liked
the "Build-a-Bear Workshop" style of emulators, like is so prominent in
the Genesis scene: "My new Genesis emu (uses Starscream/Musashi 68K
core, Marat Fayzullin's Z80 core, YM2612 core from Game_Music_Emu, VDP
core from Gens, SVP core from picodrive)", sorry, but you wrote
a front-end, not an emulator :/
I also updated the SPC7110 decompression module: I merged the class
inside the SPC7110 class (not sure why it was separate before), and
replaced the morton lookup tables with for-loops. The morton tables were
added to be a tiny bit faster when I was more interested in speed than
code clarity. It may be a tiny bit slower (or faster due to less L2
cache usage), but you won't even notice an FPS drop, and it cuts out
a good chunk of code and some tables. Lastly, I added pinput_poll() to
video_refresh(). Forgot to remove Interface::input_poll() from the C++
side, will have to do that later.
2011-06-28 11:36:00 +00:00
|
|
|
//fetch a decompressed byte; once finished, disable channel and invalidate buffer
|
|
|
|
uint8 data = decomp.read();
|
|
|
|
if(--dma[i].size == 0) {
|
|
|
|
dma_ready = false;
|
2010-08-09 13:28:56 +00:00
|
|
|
xfer_enable &= ~(1 << i);
|
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
|
|
|
} //address matched
|
|
|
|
} //channel enabled
|
|
|
|
} //channel loop
|
|
|
|
} //S-DD1 decompressor enabled
|
|
|
|
|
|
|
|
//S-DD1 decompression mode inactive; return ROM data
|
2012-07-08 02:57:34 +00:00
|
|
|
return mmc_read(addr);
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
Update to v089r17 release.
byuu says:
This implements the spec from the XML part 3 thread:
http://board.byuu.org/viewtopic.php?f=16&t=2998
It's also propagated the changes to nall and purify, so you can test
this one.
This is basically it, after years of effort I feel I finally have
a fully consistent and logical XML board format.
The only things left to change will be: modifications if emulation turns
out to be incorrect (eg we missed some MMIO mirrors, or mirrored too
much), and new additions.
And of course, I'm giving it a bit of time for good arguments against
the format.
Other than that, this release removes linear_vector and pointer_vector,
as vector is better than linear_vector and I've never used
pointer_vector.
vector also gets move(), which is a way to use move-semantics across
types. It lets you steal the underlying memory pool, effectively
destroying the vector without a copy.
This works really nicely with the move for read() functions to return
vector<uint8> instead of taking (uint8_t*&, unsigned&) parameters.
2012-07-15 13:02:27 +00:00
|
|
|
void SDD1::mcurom_write(unsigned addr, uint8 data) {
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8 SDD1::mcuram_read(unsigned addr) {
|
|
|
|
if((addr & 0x60e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
|
|
|
|
return ram.read(addr & 0x1fff);
|
|
|
|
}
|
|
|
|
|
|
|
|
if((addr & 0xf08000) == 0x700000) { //$70-7f:0000-7fff
|
|
|
|
return ram.read(addr & 0x1fff);
|
|
|
|
}
|
|
|
|
|
|
|
|
return cpu.regs.mdr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SDD1::mcuram_write(unsigned addr, uint8 data) {
|
2012-07-08 02:57:34 +00:00
|
|
|
if((addr & 0x60e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
|
|
|
|
return ram.write(addr & 0x1fff, data);
|
|
|
|
}
|
2010-08-09 13:28:56 +00:00
|
|
|
|
2012-07-08 02:57:34 +00:00
|
|
|
if((addr & 0xf08000) == 0x700000) { //$70-7f:0000-7fff
|
|
|
|
return ram.write(addr & 0x1fff, data);
|
|
|
|
}
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|