Compare commits

...

12 Commits
v074 ... v075

Author SHA1 Message Date
Tim Allen
6b4104867f 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 19:52:34 +11:00
Tim Allen
53fe43afd8 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 20:03:17 +11:00
Tim Allen
054bdd4094 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 19:59:45 +11:00
Tim Allen
ecf96726f9 Update to v074r09 release.
byuu says:

This WIP fixes up the last bit from the old memory mapping system, the
BS-X Satellaview town cartridge now has a static memory mapper that is
dynamically decoded based on register settings. Tested with BS Town + BS
Zelda, and I can get in-game just fine. The mapping code is actually
a lot more readable this way, too.
2011-01-22 19:18:03 +11:00
Tim Allen
cab5917806 Update to v074r08 release.
byuu says:

The nall::function binding for the memory map apparently breaks when the
debugger is enabled, as PPU:: becomes PPUdebugger::, etc; and C++ isn't
smart enough to upconvert for us.
Not sure how I am going to work around that yet ...

Changelog:
- improved GameBoy::CPU::Halt emulation, fixes Legend of Zelda intro
  water+world-map scrolling at the same time
- added GameBoy::APU skeleton, and hooked up MMIO read/write for all
  registers
- modified nall integer->string functions
2011-01-22 19:15:49 +11:00
Tim Allen
c833b69087 Update to v074r07 release.
byuu says:

Fullscreen works on all ports, but Qt is in general pretty wonky at the
moment. Don't really care right now.

F11 toggles fullscreen, there is no menu or status in fullscreen, and it
auto-scales to the highest even multiple that it can.
It copies all other settings (filter, shader, aspect correction, video
region, vsync, async) from your windowed mode settings.
You cannot enable the menu or status bars, because those are a major
pain in the ass to support with both GTK+ and Qt returning nonsense
geometries.
Combine with each platform treating whether or not to handle menus
and/or statuses as part of the geometry or not, and it's a recipe for
pain.
It is pseudo-fullscreen for now, but if we have some spiffy code in the
future to set a true fullscreen that works on Linux (and hopefully OS
X), I'll add a true-FS option to ruby later.
2011-01-18 21:20:05 +11:00
Tim Allen
1a065bafb1 Update to v074r06 release.
byuu says:

This WIP uses the 16MB+64MB memory tables for 1:1 mapping of the S-CPU
bus.
Minimum RAM requirement goes up to 128MB, dare I be bold here and
recommend you have 256MB.

I also hooked up the basic bindings for making pseudo-fullscreen windows
in phoenix/Windows and phoenix/GTK+, but both have some serious issues.
- GTK+ won't resize my form container, even though it's the same code
  I used successfully in bsnes v039 and prior with hiro
- Windows scale selection breaks the faux-fullscreen effects
- I am intending to write off the menu/status bars and just auto-size
  the video to fill the screen, nice and simple
2011-01-18 21:17:48 +11:00
Tim Allen
ea077a7d96 Update to v074r05 release.
byuu says:

Oh good, that turned out to be a lot easier than I expected.
Almost all of the work was already done yesterday in porting the SA-1
over to a static map.
2011-01-17 00:22:51 +11:00
Tim Allen
a937f9b79b Update to v074r04 release.
byuu says:

SuperFXBus was inheriting from Bus, in other words using a copy of the
same memory mapping subsystem.
I've removed that and made it a simple mask, since only ROM+RAM are
mapped there.
2011-01-17 00:17:45 +11:00
Tim Allen
2d73086569 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 15:30:29 +11:00
Tim Allen
5810e69be3 Update to v074r02 release.
byuu says:

Changelog:
- updated/fixed st0011.bin SHA256 sum
- removed launcher/
- building ui-gameboy only builds the Game Boy core, not the SNES core
- binary name output is bgameboy for ui-gameboy
- make install/make uninstall work as expected with the extra data files

[Editor's note - those last three changes seem to have been made in
v074r01]
2011-01-13 21:08:27 +11:00
Tim Allen
a198e555dc Update to v074r01 release.
byuu says:

Changelog:
- fixed libsnes to compile again, the GB RTC constant is there but
  doesn't do anything just yet (no serialize support in GameBoy core)
- libsnes: added SNES_MEMORY_(WRAM,APURAM,VRAM,OAM,CGRAM) -- really only
  for the first one, it allows libsnes users to implement their own
  cheat search
- you can now load the SGB BIOS without a game!! please be sure to enjoy
  the blinking cartridge icon emulation :D
- necdsp (uPD7725,96050) - simplified code a bit: removed persistent
  regs.idb, simplified jumps, merged exec() with main loop, etc.
- nall::function - fixed an initialization bug when copy-constructing
  objects
- nall::vector - use calloc instead of malloc to help safeguard against
  uninitialized class data (potentially hides errors, but better than
  crashing in production)
2011-01-13 21:07:04 +11:00
201 changed files with 9888 additions and 8310 deletions

View File

@@ -48,39 +48,10 @@ all: build;
obj/libco.o: libco/libco.c libco/*
include $(snes)/Makefile
include $(gameboy)/Makefile
include $(ui)/Makefile
objects := $(patsubst %,obj/%.o,$(objects))
# targets
build: ui_build $(objects)
ifeq ($(platform),osx)
test -d ../bsnes.app || mkdir -p ../bsnes.app/Contents/MacOS
$(strip $(cpp) -o ../bsnes.app/Contents/MacOS/bsnes $(objects) $(link))
else
$(strip $(cpp) -o out/bsnes $(objects) $(link))
endif
install:
ifeq ($(platform),x)
install -D -m 755 out/bsnes $(DESTDIR)$(prefix)/bin/bsnes
install -D -m 644 data/bsnes.png $(DESTDIR)$(prefix)/share/pixmaps/bsnes.png
install -D -m 644 data/bsnes.desktop $(DESTDIR)$(prefix)/share/applications/bsnes.desktop
test -d ~/.bsnes || mkdir ~/.bsnes
cp data/cheats.xml ~/.bsnes/cheats.xml
chmod 777 ~/.bsnes ~/.bsnes/cheats.xml
endif
uninstall:
ifeq ($(platform),x)
rm $(DESTDIR)$(prefix)/bin/bsnes
rm $(DESTDIR)$(prefix)/share/pixmaps/bsnes.png
rm $(DESTDIR)$(prefix)/share/applications/bsnes.desktop
endif
clean: ui_clean
clean:
-@$(call delete,obj/*.o)
-@$(call delete,obj/*.a)
-@$(call delete,obj/*.so)
@@ -94,6 +65,6 @@ clean: ui_clean
-@$(call delete,*.manifest)
archive-all:
tar -cjf bsnes.tar.bz2 data gameboy launcher libco nall obj out phoenix ruby snes ui ui-gameboy Makefile cc.bat clean.bat sync.sh
tar -cjf bsnes.tar.bz2 data gameboy libco nall obj out phoenix ruby snes ui ui-gameboy Makefile cc.bat clean.bat sync.sh
help:;

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
gameboy_objects := gameboy-system gameboy-scheduler
gameboy_objects += gameboy-memory gameboy-cartridge
gameboy_objects += gameboy-cpu gameboy-lcd
gameboy_objects += gameboy-cpu gameboy-apu gameboy-lcd
objects += $(gameboy_objects)
obj/gameboy-system.o: $(gameboy)/system/system.cpp $(call rwildcard,$(gameboy)/system/)
@@ -8,4 +8,5 @@ obj/gameboy-scheduler.o: $(gameboy)/scheduler/scheduler.cpp $(call rwildcard,$(g
obj/gameboy-cartridge.o: $(gameboy)/cartridge/cartridge.cpp $(call rwildcard,$(gameboy)/cartridge/)
obj/gameboy-memory.o: $(gameboy)/memory/memory.cpp $(call rwildcard,$(gameboy)/memory/)
obj/gameboy-cpu.o: $(gameboy)/cpu/cpu.cpp $(call rwildcard,$(gameboy)/cpu/)
obj/gameboy-apu.o: $(gameboy)/apu/apu.cpp $(call rwildcard,$(gameboy)/apu/)
obj/gameboy-lcd.o: $(gameboy)/lcd/lcd.cpp $(call rwildcard,$(gameboy)/lcd/)

85
bsnes/gameboy/apu/apu.cpp Executable file
View File

@@ -0,0 +1,85 @@
#include <gameboy/gameboy.hpp>
#define APU_CPP
namespace GameBoy {
#include "mmio/mmio.cpp"
#include "serialization.cpp"
APU apu;
void APU::power() {
for(unsigned n = 0xff10; n <= 0xff3f; n++) bus.mmio[n] = this;
channel1.sweep_time = 0;
channel1.sweep_direction = 0;
channel1.sweep_shift = 0;
channel1.wave_pattern_duty = 0;
channel1.sound_length = 0;
channel1.initial_envelope_volume = 0;
channel1.envelope_direction = 0;
channel1.envelope_sweep = 0;
channel1.frequency = 0;
channel1.initialize = 0;
channel1.consecutive_selection = 0;
channel2.wave_pattern_duty = 0;
channel2.sound_length = 0;
channel2.initial_envelope_volume = 0;
channel2.envelope_direction = 0;
channel2.envelope_sweep = 0;
channel2.frequency = 0;
channel2.initialize = 0;
channel2.consecutive_selection = 0;
channel3.off = 0;
channel3.sound_length = 0;
channel3.output_level = 0;
channel3.frequency = 0;
channel3.initialize = 0;
channel3.consecutive_selection = 0;
for(unsigned n = 0; n < 16; n++) channel3.pattern[n] = 0;
channel4.sound_length = 0;
channel4.initial_envelope_volume = 0;
channel4.envelope_direction = 0;
channel4.envelope_sweep = 0;
channel4.shift_clock_frequency = 0;
channel4.counter_step_width = 0;
channel4.dividing_ratio = 0;
channel4.initialize = 0;
channel4.consecutive_selection = 0;
control.output_vin_to_so2 = 0;
control.so2_output_level = 0;
control.output_vin_to_so1 = 0;
control.so1_output_level = 0;
control.output_channel4_to_so2 = 0;
control.output_channel3_to_so2 = 0;
control.output_channel2_to_so2 = 0;
control.output_channel1_to_so2 = 0;
control.output_channel4_to_so1 = 0;
control.output_channel3_to_so1 = 0;
control.output_channel2_to_so1 = 0;
control.output_channel1_to_so1 = 0;
control.sound_on = 0;
control.channel4_on = 0;
control.channel3_on = 0;
control.channel2_on = 0;
control.channel1_on = 0;
}
}

9
bsnes/gameboy/apu/apu.hpp Executable file
View File

@@ -0,0 +1,9 @@
struct APU : Processor, MMIO {
#include "mmio/mmio.hpp"
void power();
void serialize(serializer&);
};
extern APU apu;

248
bsnes/gameboy/apu/mmio/mmio.cpp Executable file
View File

@@ -0,0 +1,248 @@
#ifdef APU_CPP
uint8 APU::mmio_read(uint16 addr) {
if(addr == 0xff10) { //NR10
return (channel1.sweep_time << 4)
| (channel1.sweep_direction << 3)
| (channel1.sweep_shift << 0);
}
if(addr == 0xff11) { //NR11
return (channel1.wave_pattern_duty << 6);
}
if(addr == 0xff12) { //NR12
return (channel1.initial_envelope_volume << 4)
| (channel1.envelope_direction << 3)
| (channel1.envelope_sweep << 0);
}
if(addr == 0xff14) { //NR14
return (channel1.consecutive_selection << 6);
}
if(addr == 0xff16) { //NR21
return (channel2.wave_pattern_duty << 6);
}
if(addr == 0xff17) { //NR22
return (channel2.initial_envelope_volume << 4)
| (channel2.envelope_direction << 3)
| (channel2.envelope_sweep << 0);
}
if(addr == 0xff19) { //NR24
return (channel2.consecutive_selection << 6);
}
if(addr == 0xff1a) { //NR30
return (channel3.off << 7);
}
if(addr == 0xff1b) { //NR31
return (channel3.sound_length << 0);
}
if(addr == 0xff1c) { //NR32
return (channel3.output_level << 5);
}
if(addr == 0xff1e) { //NR34
return (channel3.consecutive_selection << 6);
}
if(addr == 0xff20) { //NR41
return (channel4.sound_length << 0);
}
if(addr == 0xff21) { //NR42
return (channel4.initial_envelope_volume << 4)
| (channel4.envelope_direction << 3)
| (channel4.envelope_sweep << 0);
}
if(addr == 0xff22) { //NR43
return (channel4.shift_clock_frequency << 4)
| (channel4.counter_step_width << 3)
| (channel4.dividing_ratio << 0);
}
if(addr == 0xff23) { //NR44
return (channel4.consecutive_selection << 6);
}
if(addr == 0xff24) { //NR50
return (control.output_vin_to_so2 << 7)
| (control.so2_output_level << 4)
| (control.output_vin_to_so1 << 3)
| (control.so1_output_level << 0);
}
if(addr == 0xff25) { //NR51
return (control.output_channel4_to_so2 << 7)
| (control.output_channel3_to_so2 << 6)
| (control.output_channel2_to_so2 << 5)
| (control.output_channel1_to_so2 << 4)
| (control.output_channel4_to_so1 << 3)
| (control.output_channel3_to_so1 << 2)
| (control.output_channel2_to_so1 << 1)
| (control.output_channel1_to_so1 << 0);
}
if(addr == 0xff26) { //NR52
return (control.sound_on << 7);
}
if(addr >= 0xff30 && addr <= 0xff3f) {
return channel3.pattern[addr & 15];
}
return 0x00;
}
void APU::mmio_write(uint16 addr, uint8 data) {
if(addr == 0xff10) { //NR10
channel1.sweep_time = (data >> 4) & 7;
channel1.sweep_direction = data & 0x08;
channel1.sweep_shift = data & 0x07;
return;
}
if(addr == 0xff11) { //NR11
channel1.wave_pattern_duty = (data >> 6) & 3;
channel1.sound_length = data & 0x3f;
return;
}
if(addr == 0xff12) { //NR12
channel1.initial_envelope_volume = (data >> 4) & 15;
channel1.envelope_direction = data & 0x08;
channel1.envelope_sweep = data & 0x07;
return;
}
if(addr == 0xff13) { //NR13
channel1.frequency = (channel1.frequency & 0x0700) | (data << 0);
return;
}
if(addr == 0xff14) { //NR14
channel1.initialize = data & 0x80;
channel1.consecutive_selection = data & 0x40;
channel1.frequency = ((data & 7) << 8) | (channel1.frequency & 0x00ff);
return;
}
if(addr == 0xff16) { //NR21
channel2.wave_pattern_duty = (data >> 6) & 3;
channel2.sound_length = data & 0x3f;
return;
}
if(addr == 0xff17) { //NR22
channel2.initial_envelope_volume = (data >> 4) & 15;
channel2.envelope_direction = data & 0x08;
channel2.envelope_sweep = data & 0x07;
return;
}
if(addr == 0xff18) { //NR23
channel2.frequency = (channel2.frequency & 0x0700) | (data << 0);
return;
}
if(addr == 0xff19) { //NR24
channel2.initialize = data & 0x80;
channel2.consecutive_selection = data & 0x40;
channel2.frequency = ((data & 7) << 8) | (channel2.frequency & 0x00ff);
return;
}
if(addr == 0xff1a) { //NR30
channel3.off = data & 0x80;
return;
}
if(addr == 0xff1b) { //NR31
channel3.sound_length = data;
return;
}
if(addr == 0xff1c) { //NR32
channel3.output_level = (data >> 5) & 3;
return;
}
if(addr == 0xff1d) { //NR33
channel3.frequency = (channel3.frequency & 0x0700) | (data << 0);
return;
}
if(addr == 0xff1e) { //NR34
channel3.initialize = data & 0x80;
channel3.consecutive_selection = data & 0x40;
channel3.frequency = ((data & 7) << 8) | (channel3.frequency & 0x00ff);
return;
}
if(addr == 0xff20) { //NR41
channel4.sound_length = data & 0x3f;
return;
}
if(addr == 0xff21) { //NR42
channel4.initial_envelope_volume = (data >> 3) & 15;
channel4.envelope_direction = data & 0x08;
channel4.envelope_sweep = data & 0x07;
return;
}
if(addr == 0xff22) { //NR43
channel4.shift_clock_frequency = (data >> 4) & 15;
channel4.counter_step_width = data & 0x08;
channel4.dividing_ratio = data & 0x07;
return;
}
if(addr == 0xff23) { //NR44
channel4.initialize = data & 0x80;
channel4.consecutive_selection = data & 0x40;
return;
}
if(addr == 0xff24) { //NR50
control.output_vin_to_so2 = data & 0x80;
control.so2_output_level = (data >> 4) & 7;
control.output_vin_to_so1 = data & 0x08;
control.so1_output_level = (data >> 0) & 7;
return;
}
if(addr == 0xff25) { //NR51
control.output_channel4_to_so2 = data & 0x80;
control.output_channel3_to_so2 = data & 0x40;
control.output_channel2_to_so2 = data & 0x20;
control.output_channel1_to_so2 = data & 0x10;
control.output_channel4_to_so1 = data & 0x08;
control.output_channel3_to_so1 = data & 0x04;
control.output_channel2_to_so1 = data & 0x02;
control.output_channel1_to_so1 = data & 0x01;
return;
}
if(addr == 0xff26) { //NR52
control.sound_on = data & 0x80;
control.channel4_on = data & 0x08;
control.channel3_on = data & 0x04;
control.channel2_on = data & 0x02;
control.channel1_on = data & 0x01;
return;
}
if(addr >= 0xff30 && addr <= 0xff3f) {
channel3.pattern[addr & 15] = data;
return;
}
}
#endif

102
bsnes/gameboy/apu/mmio/mmio.hpp Executable file
View File

@@ -0,0 +1,102 @@
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
struct Channel1 { //tone and sweep
//$ff10 NR10
unsigned sweep_time;
bool sweep_direction;
unsigned sweep_shift;
//$ff11 NR11
unsigned wave_pattern_duty;
unsigned sound_length;
//$ff12 NR12
unsigned initial_envelope_volume;
bool envelope_direction;
unsigned envelope_sweep;
//$ff13,$ff14 NR13,NR14
unsigned frequency;
bool initialize;
bool consecutive_selection;
} channel1;
struct Channel2 { //tone
//$ff16 NR21
unsigned wave_pattern_duty;
unsigned sound_length;
//$ff17 NR22
unsigned initial_envelope_volume;
bool envelope_direction;
unsigned envelope_sweep;
//$ff18,$ff19 NR23,NR24
unsigned frequency;
bool initialize;
bool consecutive_selection;
} channel2;
struct Channel3 { //wave output
//$ff1a NR30
bool off;
//$ff1b NR31
unsigned sound_length;
//$ff1c NR32
unsigned output_level;
//$ff1d,$ff1e NR33,NR34
unsigned frequency;
bool initialize;
bool consecutive_selection;
//$ff30-ff3f
uint8 pattern[16];
} channel3;
struct Channel4 { //noise
//$ff20 NR41
unsigned sound_length;
//$ff21 NR42
unsigned initial_envelope_volume;
bool envelope_direction;
unsigned envelope_sweep;
//$ff22 NR43
unsigned shift_clock_frequency;
bool counter_step_width;
unsigned dividing_ratio;
//$ff23 NR44
bool initialize;
bool consecutive_selection;
} channel4;
struct Control {
//$ff24 NR50
bool output_vin_to_so2;
unsigned so2_output_level;
bool output_vin_to_so1;
unsigned so1_output_level;
//$ff25 NR51
bool output_channel4_to_so2;
bool output_channel3_to_so2;
bool output_channel2_to_so2;
bool output_channel1_to_so2;
bool output_channel4_to_so1;
bool output_channel3_to_so1;
bool output_channel2_to_so1;
bool output_channel1_to_so1;
//$ff26 NR52
bool sound_on;
bool channel4_on;
bool channel3_on;
bool channel2_on;
bool channel1_on;
} control;

View File

@@ -0,0 +1,6 @@
#ifdef APU_CPP
void APU::serialize(serializer &s) {
}
#endif

View File

@@ -16,13 +16,14 @@ namespace GameBoy {
#include "serialization.cpp"
Cartridge cartridge;
void Cartridge::load(const string &xml, uint8_t *data, unsigned size) {
void Cartridge::load(const string &xml, const uint8_t *data, unsigned size) {
if(size == 0) size = 32768;
romdata = allocate<uint8>(romsize = size, 0xff);
if(data) memcpy(romdata, data, size);
//uint32_t crc = crc32_calculate(data, size);
//print("CRC32 = ", hex<4>(crc), "\n");
romdata = new uint8[romsize = size];
memcpy(romdata, data, size);
info.mapper = Mapper::Unknown;
info.ram = false;
info.battery = false;

View File

@@ -41,7 +41,7 @@ struct Cartridge : property<Cartridge> {
uint8_t *ramdata;
unsigned ramsize;
void load(const string &xml, uint8_t *data, unsigned size);
void load(const string &xml, const uint8_t *data, unsigned size);
void unload();
uint8 rom_read(unsigned addr);

View File

@@ -1,15 +1,15 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::HuC1::mmio_read(uint16 addr) {
if((addr & 0xc000) == 0x0000) { //0000-3fff
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x4000) { //4000-7fff
if(within<0x4000, 0x7fff>(addr)) {
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
return 0x00;
}
@@ -18,27 +18,27 @@ uint8 Cartridge::HuC1::mmio_read(uint16 addr) {
}
void Cartridge::HuC1::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0x0000) { //0000-1fff
if(within<0x0000, 0x1fff>(addr)) {
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xe000) == 0x2000) { //2000-3fff
if(within<0x2000, 0x3fff>(addr)) {
rom_select = data;
return;
}
if((addr & 0xe000) == 0x4000) { //4000-5fff
if(within<0x4000, 0x5fff>(addr)) {
ram_select = data;
return;
}
if((addr & 0xe000) == 0x6000) { //6000-7fff
if(within<0x6000, 0x7fff>(addr)) {
//unknown purpose
return;
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
return;
}

View File

@@ -1,15 +1,15 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::HuC3::mmio_read(uint16 addr) {
if((addr & 0xc000) == 0x0000) { //0000-3fff
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x4000) { //4000-7fff
if(within<0x4000, 0x7fff>(addr)) {
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
return 0x00;
}
@@ -18,27 +18,27 @@ uint8 Cartridge::HuC3::mmio_read(uint16 addr) {
}
void Cartridge::HuC3::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0x0000) { //0000-1fff
if(within<0x0000, 0x1fff>(addr)) {
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xe000) == 0x2000) { //2000-3fff
if(within<0x2000, 0x3fff>(addr)) {
rom_select = data;
return;
}
if((addr & 0xe000) == 0x4000) { //4000-5fff
if(within<0x4000, 0x5fff>(addr)) {
ram_select = data;
return;
}
if((addr & 0xe000) == 0x6000) { //6000-7fff
if(within<0x6000, 0x7fff>(addr)) {
//unknown purpose
return;
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
return;
}

View File

@@ -1,11 +1,11 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC0::mmio_read(uint16 addr) {
if((addr & 0x8000) == 0x0000) { //0000-7fff
if(within<0x0000, 0x7fff>(addr)) {
return cartridge.rom_read(addr);
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
return cartridge.ram_read(addr & 0x1fff);
}
@@ -13,7 +13,7 @@ uint8 Cartridge::MBC0::mmio_read(uint16 addr) {
}
void Cartridge::MBC0::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
cartridge.ram_write(addr & 0x1fff, data);
return;
}

View File

@@ -1,11 +1,11 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC1::mmio_read(uint16 addr) {
if((addr & 0xc000) == 0x0000) { //0000-3fff
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x4000) { //4000-7fff
if(within<0x4000, 0x7fff>(addr)) {
if(mode_select == 0) {
return cartridge.rom_read((ram_select << 19) | (rom_select << 14) | (addr & 0x3fff));
} else {
@@ -13,7 +13,7 @@ uint8 Cartridge::MBC1::mmio_read(uint16 addr) {
}
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) {
if(mode_select == 0) {
return cartridge.ram_read(addr & 0x1fff);
@@ -28,27 +28,27 @@ uint8 Cartridge::MBC1::mmio_read(uint16 addr) {
}
void Cartridge::MBC1::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0x0000) { //0000-1fff
if(within<0x0000, 0x1fff>(addr)) {
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xe000) == 0x2000) { //2000-3fff
if(within<0x2000, 0x3fff>(addr)) {
rom_select = (data & 0x1f) + ((data & 0x1f) == 0);
return;
}
if((addr & 0xe000) == 0x4000) { //4000-5fff
if(within<0x4000, 0x5fff>(addr)) {
ram_select = data & 0x03;
return;
}
if((addr & 0xe000) == 0x6000) { //6000-7fff
if(within<0x6000, 0x7fff>(addr)) {
mode_select = data & 0x01;
return;
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) {
if(mode_select == 0) {
cartridge.ram_write(addr & 0x1fff, data);

View File

@@ -1,15 +1,15 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC2::mmio_read(uint16 addr) {
if((addr & 0xc000) == 0x0000) { //0000-3fff
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x4000) { //4000-7fff
if(within<0x4000, 0x7fff>(addr)) {
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if((addr & 0xfe00) == 0xa000) { //a000-a1ff
if(within<0xa000, 0xa1ff>(addr)) {
if(ram_enable) return cartridge.ram_read(addr & 0x1ff);
return 0x00;
}
@@ -18,17 +18,17 @@ uint8 Cartridge::MBC2::mmio_read(uint16 addr) {
}
void Cartridge::MBC2::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe100) == 0x0000) { //0000-1fff [d8=0]
ram_enable = (data & 0x0f) == 0x0a;
if(within<0x0000, 0x1fff>(addr)) {
if(!(addr & 0x0100)) ram_enable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xe100) == 0x2100) { //2000-3fff [d8=1]
rom_select = (data & 0x0f) + ((data & 0x0f) == 0);
if(within<0x2000, 0x3fff>(addr)) {
if( (addr & 0x0100)) rom_select = (data & 0x0f) + ((data & 0x0f) == 0);
return;
}
if((addr & 0xfe00) == 0xa000) { //a000-a1ff
if(within<0xa000, 0xa1ff>(addr)) {
if(ram_enable) cartridge.ram_write(addr & 0x1ff, data & 0x0f);
return;
}

View File

@@ -19,15 +19,15 @@ void Cartridge::MBC3::second() {
}
uint8 Cartridge::MBC3::mmio_read(uint16 addr) {
if((addr & 0xc000) == 0x0000) { //0000-3fff
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x4000) { //4000-7fff
if(within<0x4000, 0x7fff>(addr)) {
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) {
if(ram_select >= 0x00 && ram_select <= 0x03) {
return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
@@ -45,22 +45,22 @@ uint8 Cartridge::MBC3::mmio_read(uint16 addr) {
}
void Cartridge::MBC3::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0x0000) { //0000-1fff
if(within<0x0000, 0x1fff>(addr)) {
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xe000) == 0x2000) { //2000-3fff
if(within<0x2000, 0x3fff>(addr)) {
rom_select = (data & 0x7f) + ((data & 0x7f) == 0);
return;
}
if((addr & 0xe000) == 0x4000) { //4000-5fff
if(within<0x4000, 0x5fff>(addr)) {
ram_select = data;
return;
}
if((addr & 0xe000) == 0x6000) { //6000-7fff
if(within<0x6000, 0x7fff>(addr)) {
if(rtc_latch == 0 && data == 1) {
rtc_latch_second = rtc_second;
rtc_latch_minute = rtc_minute;
@@ -72,7 +72,7 @@ void Cartridge::MBC3::mmio_write(uint16 addr, uint8 data) {
return;
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) {
if(ram_select >= 0x00 && ram_select <= 0x03) {
cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);

View File

@@ -1,15 +1,15 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC5::mmio_read(uint16 addr) {
if((addr & 0xc000) == 0x0000) { //0000-3fff
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x4000) { //4000-7fff
if(within<0x4000, 0x7fff>(addr)) {
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
return 0x00;
}
@@ -18,27 +18,27 @@ uint8 Cartridge::MBC5::mmio_read(uint16 addr) {
}
void Cartridge::MBC5::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0x0000) { //0000-1fff
if(within<0x0000, 0x1fff>(addr)) {
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xf000) == 0x2000) { //2000-2fff
if(within<0x2000, 0x2fff>(addr)) {
rom_select = (rom_select & 0x0100) | data;
return;
}
if((addr & 0xf000) == 0x3000) { //3000-3fff
if(within<0x3000, 0x3fff>(addr)) {
rom_select = ((data & 1) << 8) | (rom_select & 0x00ff);
return;
}
if((addr & 0xe000) == 0x4000) { //4000-5fff
if(within<0x4000, 0x5fff>(addr)) {
ram_select = data & 0x0f;
return;
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
return;
}

View File

@@ -1,19 +1,19 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MMM01::mmio_read(uint16 addr) {
if((addr & 0x8000) == 0x0000) {
if(within<0x0000, 0x7fff>(addr)) {
if(rom_mode == 0) return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x0000) {
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(0x8000 + (rom_base << 14) + (addr & 0x3fff));
}
if((addr & 0xc000) == 0x4000) {
if(within<0x4000, 0x7fff>(addr)) {
return cartridge.rom_read(0x8000 + (rom_base << 14) + (rom_select << 14) + (addr & 0x3fff));
}
if((addr & 0xe000) == 0xa000) {
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) return cartridge.ram_read((ram_select << 13) + (addr & 0x1fff));
return 0x00;
}
@@ -22,7 +22,7 @@ uint8 Cartridge::MMM01::mmio_read(uint16 addr) {
}
void Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0x0000) { //0000-1fff
if(within<0x0000, 0x1fff>(addr)) {
if(rom_mode == 0) {
rom_mode = 1;
} else {
@@ -30,7 +30,7 @@ void Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) {
}
}
if((addr & 0xe000) == 0x2000) { //2000-3fff
if(within<0x2000, 0x3fff>(addr)) {
if(rom_mode == 0) {
rom_base = data & 0x3f;
} else {
@@ -38,17 +38,17 @@ void Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) {
}
}
if((addr & 0xe000) == 0x4000) { //4000-5fff
if(within<0x4000, 0x5fff>(addr)) {
if(rom_mode == 1) {
ram_select = data;
}
}
if((addr & 0xe000) == 0x6000) { //6000-7fff
if(within<0x6000, 0x7fff>(addr)) {
//unknown purpose
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) cartridge.ram_write((ram_select << 13) + (addr & 0x1fff), data);
}
}

View File

@@ -28,14 +28,30 @@ void CPU::main() {
}
void CPU::interrupt_raise(CPU::Interrupt id) {
switch(id) {
case Interrupt::Vblank: status.interrupt_request_vblank = 1; break;
case Interrupt::Stat : status.interrupt_request_stat = 1; break;
case Interrupt::Timer : status.interrupt_request_timer = 1; break;
case Interrupt::Serial: status.interrupt_request_serial = 1; break;
case Interrupt::Joypad: status.interrupt_request_joypad = 1; status.stop = false; break;
if(id == Interrupt::Vblank) {
status.interrupt_request_vblank = 1;
if(status.interrupt_enable_vblank) status.halt = false;
}
if(id == Interrupt::Stat) {
status.interrupt_request_stat = 1;
if(status.interrupt_enable_stat) status.halt = false;
}
if(id == Interrupt::Timer) {
status.interrupt_request_timer = 1;
if(status.interrupt_enable_timer) status.halt = false;
}
if(id == Interrupt::Serial) {
status.interrupt_request_serial = 1;
if(status.interrupt_enable_serial) status.halt = false;
}
if(id == Interrupt::Joypad) {
status.interrupt_request_joypad = 1;
if(status.interrupt_enable_joypad) status.halt = status.stop = false;
}
status.halt = false;
}
void CPU::interrupt_test() {
@@ -104,12 +120,19 @@ void CPU::power() {
status.timer1 = 0;
status.timer2 = 0;
status.timer3 = 0;
status.timer4 = 0;
status.p15 = 0;
status.p14 = 0;
status.joyp = 0;
status.mlt_req = 0;
status.serial_data = 0;
status.serial_bits = 0;
status.serial_transfer = 0;
status.serial_clock = 0;
status.div = 0;
status.tima = 0;

View File

@@ -23,6 +23,7 @@ struct CPU : Processor, MMIO {
unsigned timer1;
unsigned timer2;
unsigned timer3;
unsigned timer4;
//$ff00 JOYP
bool p15;
@@ -30,6 +31,14 @@ struct CPU : Processor, MMIO {
uint8 joyp;
uint8 mlt_req;
//$ff01 SB
uint8 serial_data;
unsigned serial_bits;
//$ff02 SC
bool serial_transfer;
bool serial_clock;
//$ff04 DIV
uint8 div;
@@ -72,4 +81,4 @@ struct CPU : Processor, MMIO {
CPU();
};
extern CPU cpu;
extern CPU cpu;

View File

@@ -31,6 +31,15 @@ uint8 CPU::mmio_read(uint16 addr) {
| (status.joyp << 0);
}
if(addr == 0xff01) { //SB
return 0xff;
}
if(addr == 0xff02) { //SC
return (status.serial_transfer << 7)
| (status.serial_clock << 0);
}
if(addr == 0xff04) { //DIV
return status.div;
}
@@ -81,10 +90,14 @@ void CPU::mmio_write(uint16 addr, uint8 data) {
}
if(addr == 0xff01) { //SB
status.serial_data = data;
return;
}
if(addr == 0xff02) { //SC
status.serial_transfer = data & 0x80;
status.serial_clock = data & 0x01;
if(status.serial_transfer) status.serial_bits = 8;
return;
}

View File

@@ -27,12 +27,19 @@ void CPU::serialize(serializer &s) {
s.integer(status.timer1);
s.integer(status.timer2);
s.integer(status.timer3);
s.integer(status.timer4);
s.integer(status.p15);
s.integer(status.p14);
s.integer(status.joyp);
s.integer(status.mlt_req);
s.integer(status.serial_data);
s.integer(status.serial_bits);
s.integer(status.serial_transfer);
s.integer(status.serial_clock);
s.integer(status.div);
s.integer(status.tima);
s.integer(status.tma);

View File

@@ -64,10 +64,22 @@ void CPU::timer_stage2() { // 16384hz
status.div++;
status.timer2 -= 4;
if(++status.timer3 >= 4) timer_stage3();
if(++status.timer3 >= 2) timer_stage3();
}
void CPU::timer_stage3() { // 4096hz
void CPU::timer_stage3() { // 8192hz
if(status.serial_transfer && status.serial_clock) {
if(--status.serial_bits == 0) {
status.serial_transfer = 0;
interrupt_raise(Interrupt::Serial);
}
}
status.timer3 -= 2;
if(++status.timer4 >= 2) timer_stage4();
}
void CPU::timer_stage4() { // 4096hz
if(status.timer_enable && status.timer_clock == 0) {
if(++status.tima == 0) {
status.tima = status.tma;
@@ -75,7 +87,7 @@ void CPU::timer_stage3() { // 4096hz
}
}
status.timer3 -= 4;
status.timer4 -= 2;
}
#endif

View File

@@ -3,6 +3,7 @@ void timer_stage0();
void timer_stage1();
void timer_stage2();
void timer_stage3();
void timer_stage4();
//opcode.cpp
void op_io();

View File

@@ -5,7 +5,7 @@
namespace GameBoy {
namespace Info {
static const char Name[] = "bgameboy";
static const char Version[] = "000.11";
static const char Version[] = "000.13";
static unsigned SerializerVersion = 1;
}
}
@@ -31,6 +31,12 @@ namespace GameBoy {
typedef uint32_t uint32;
typedef uint64_t uint64;
template<uint16 lo, uint16 hi>
alwaysinline bool within(uint16 addr) {
static const uint16 mask = ~(hi ^ lo);
return (addr & mask) == lo;
}
struct Processor {
cothread_t thread;
unsigned frequency;
@@ -51,5 +57,6 @@ namespace GameBoy {
#include <gameboy/scheduler/scheduler.hpp>
#include <gameboy/cartridge/cartridge.hpp>
#include <gameboy/cpu/cpu.hpp>
#include <gameboy/apu/apu.hpp>
#include <gameboy/lcd/lcd.hpp>
};

View File

@@ -19,7 +19,11 @@ void LCD::main() {
add_clocks(4);
if(status.lx == 320) {
if(status.lx == 0) {
if(status.interrupt_oam) cpu.interrupt_raise(CPU::Interrupt::Stat);
}
if(status.lx == 252) {
if(status.interrupt_hblank) cpu.interrupt_raise(CPU::Interrupt::Stat);
}
}

View File

@@ -17,9 +17,10 @@ uint8 LCD::mmio_read(uint16 addr) {
if(addr == 0xff41) { //STAT
unsigned mode;
if(status.ly >= 144) mode = 1; //Vblank
else if(status.lx >= 320) mode = 0; //Hblank
else mode = 3; //LCD transfer
if(status.ly >= 144) mode = 1; //Vblank
else if(status.lx < 80) mode = 2; //OAM
else if(status.lx < 252) mode = 3; //LCD
else mode = 0; //Hblank
return (status.interrupt_lyc << 6)
| (status.interrupt_oam << 5)

View File

@@ -41,6 +41,7 @@ void System::serialize_all(serializer &s) {
cartridge.serialize(s);
system.serialize(s);
cpu.serialize(s);
apu.serialize(s);
lcd.serialize(s);
}

View File

@@ -54,6 +54,7 @@ void System::power() {
bus.power();
cartridge.power();
cpu.power();
apu.power();
lcd.power();
scheduler.init();

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="bsnes" version="1.0.0.0" processorArchitecture="x86"/>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*"/>
</dependentAssembly>
</dependency>
</assembly>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -1,4 +0,0 @@
@windres resource.rc resource.o
@mingw32-g++ -std=gnu++0x -mwindows -s -O3 -fomit-frame-pointer -I.. -o ../out/bsnes launcher.cpp resource.o
@del *.o
@pause

View File

@@ -1,2 +0,0 @@
clear
g++ -std=gnu++0x -s -O3 -fomit-frame-pointer -I.. -o ../out/bsnes launcher.cpp

View File

@@ -1,54 +0,0 @@
#include <nall/config.hpp>
#include <nall/detect.hpp>
#include <nall/file.hpp>
#include <nall/foreach.hpp>
#include <nall/platform.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
using namespace nall;
int main(int argc, char **argv) {
char path[PATH_MAX], *unused;
#if !defined(PLATFORM_WIN)
unused = realpath(argv[0], path);
#else
wchar_t **argw = CommandLineToArgvW(GetCommandLineW(), &argc);
unused = realpath(nall::utf8_t(argw[0]), path);
#endif
string realPath = dir(path);
string basePath = string(dir(path), "bsnes-qt.cfg");
unused = userpath(path);
if(!strend(path, "/") && !strend(path, "\\")) strcat(path, "/");
string userPath = string(path, ".bsnes/bsnes-qt.cfg");
configuration config;
string profile;
config.attach(profile = "", "system.profile");
if(config.load(userPath) == false) config.load(basePath);
if(profile == "") profile = "compatibility";
string binaryName = string("bsnes-", profile);
#if defined(PLATFORM_WIN)
binaryName << ".dll";
#endif
string fileName = string(realPath, binaryName);
#if !defined(PLATFORM_WIN)
char **args = new char*[argc + 1];
args[0] = strdup(binaryName);
for(unsigned i = 1; i < argc; i++) args[i] = strdup(argv[i]);
args[argc] = 0;
execvp(args[0], args);
execv(fileName, args);
print("[bsnes] Error: unable to locate binary file: ", binaryName, "\n");
#else
STARTUPINFOW si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(STARTUPINFOW));
if(!CreateProcessW(nall::utf16_t(fileName), GetCommandLineW(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
MessageBoxA(0, string("Error: unable to locate binary file: ", binaryName), "bsnes", MB_OK);
}
#endif
return 0;
}

View File

@@ -1,2 +0,0 @@
1 24 "bsnes.Manifest"
IDI_ICON1 ICON DISCARDABLE "bsnes.ico"

View File

@@ -27,7 +27,7 @@ namespace nall {
};
template<typename L> struct lambda : container {
L object;
mutable L object;
R operator()(P... p) const { return object(std::forward<P>(p)...); }
container* copy() const { return new lambda(object); }
lambda(const L& object) : object(object) {}
@@ -46,7 +46,7 @@ namespace nall {
return *this;
}
function(const function &source) { operator=(source); }
function(const function &source) : callback(0) { operator=(source); }
function() : callback(0) {}
function(void *function) : callback(0) { if(function) callback = new global((R (*)(P...))function); }
function(R (*function)(P...)) { callback = new global(function); }

View File

@@ -22,7 +22,7 @@ public:
};
GameBoyCartridge::GameBoyCartridge(const uint8_t *romdata, unsigned romsize) {
xml = "<?xml version='1.0' encoding='UTF-8'?>\n";
xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
if(romsize < 0x4000) return;
info.mapper = "unknown";
@@ -97,6 +97,7 @@ GameBoyCartridge::GameBoyCartridge(const uint8_t *romdata, unsigned romsize) {
xml << " <ram size='" << hex(info.ramsize) << "' battery='" << info.battery << "'/>\n";
xml << "</cartridge>\n";
xml.transform("'", "\"");
}
}

View File

@@ -112,13 +112,13 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
if(type == TypeBsx) {
xml << "<cartridge/>";
xmlMemoryMap = xml;
xmlMemoryMap = xml.transform("'", "\"");
return;
}
if(type == TypeSufamiTurbo) {
xml << "<cartridge/>";
xmlMemoryMap = xml;
xmlMemoryMap = xml.transform("'", "\"");
return;
}
@@ -128,7 +128,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
xml << " <ram size='" << hex(gameboy_ram_size(data, size)) << "'/>\n";
}
xml << "</cartridge>\n";
xmlMemoryMap = xml;
xmlMemoryMap = xml.transform("'", "\"");
return;
}
@@ -279,19 +279,23 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
xml << " </superfx>\n";
} else if(mapper == SA1ROM) {
xml << " <sa1>\n";
xml << " <rom>\n";
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
xml << " <map mode='linear' address='c0-ff:0000-ffff'/>\n";
xml << " </rom>\n";
xml << " <mcu>\n";
xml << " <rom>\n";
xml << " <map mode='direct' address='00-3f:8000-ffff'/>\n";
xml << " <map mode='direct' address='80-bf:8000-ffff'/>\n";
xml << " <map mode='direct' address='c0-ff:0000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram>\n";
xml << " <map mode='direct' address='00-3f:6000-7fff'/>\n";
xml << " <map mode='direct' address='80-bf:6000-7fff'/>\n";
xml << " </ram>\n";
xml << " </mcu>\n";
xml << " <iram size='800'>\n";
xml << " <map mode='linear' address='00-3f:3000-37ff'/>\n";
xml << " <map mode='linear' address='80-bf:3000-37ff'/>\n";
xml << " </iram>\n";
xml << " <bwram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='00-3f:6000-7fff'/>\n";
xml << " <map mode='linear' address='40-4f:0000-ffff'/>\n";
xml << " <map mode='linear' address='80-bf:6000-7fff'/>\n";
xml << " </bwram>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:2200-23ff'/>\n";
@@ -334,11 +338,14 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
xml << " </slot>\n";
xml << " </bsx>\n";
} else if(mapper == BSXROM) {
xml << " <rom>\n";
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <bsx>\n";
xml << " <mcu>\n";
xml << " <map address='00-3f:8000-ffff'/>\n";
xml << " <map address='80-bf:8000-ffff'/>\n";
xml << " <map address='40-7f:0000-ffff'/>\n";
xml << " <map address='c0-ff:0000-ffff'/>\n";
xml << " <map address='20-3f:6000-7fff'/>\n";
xml << " </mcu>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:5000-5fff'/>\n";
xml << " <map address='80-bf:5000-5fff'/>\n";
@@ -402,48 +409,72 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
if(has_dsp1) {
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp1b.bin' sha256='4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c'>\n";
if(dsp1_mapper == DSP1LoROM1MB) {
xml << " <dr mask='004000' test='000000'/>\n";
xml << " <sr mask='004000' test='004000'/>\n";
xml << " <map address='20-3f:8000-ffff'/>\n";
xml << " <map address='a0-bf:8000-ffff'/>\n";
xml << " <dr>\n";
xml << " <map address='20-3f:8000-bfff'/>\n";
xml << " <map address='a0-bf:8000-bfff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='20-3f:c000-ffff'/>\n";
xml << " <map address='a0-bf:c000-ffff'/>\n";
xml << " </sr>\n";
} else if(dsp1_mapper == DSP1LoROM2MB) {
xml << " <dr mask='004000' test='000000'/>\n";
xml << " <sr mask='004000' test='004000'/>\n";
xml << " <map address='60-6f:0000-7fff'/>\n";
xml << " <map address='e0-ef:0000-7fff'/>\n";
xml << " <dr>\n";
xml << " <map address='60-6f:0000-3fff'/>\n";
xml << " <map address='e0-ef:0000-3fff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='60-6f:4000-7fff'/>\n";
xml << " <map address='e0-ef:4000-7fff'/>\n";
xml << " </sr>\n";
} else if(dsp1_mapper == DSP1HiROM) {
xml << " <dr mask='001000' test='000000'/>\n";
xml << " <sr mask='001000' test='001000'/>\n";
xml << " <map address='00-1f:6000-7fff'/>\n";
xml << " <map address='80-9f:6000-7fff'/>\n";
xml << " <dr>\n";
xml << " <map address='00-1f:6000-6fff'/>\n";
xml << " <map address='80-9f:6000-6fff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='00-1f:7000-7fff'/>\n";
xml << " <map address='80-9f:7000-7fff'/>\n";
xml << " </sr>\n";
}
xml << " </necdsp>\n";
}
if(has_dsp2) {
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp2.bin' sha256='5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1'>\n";
xml << " <dr mask='004000' test='000000'/>\n";
xml << " <sr mask='004000' test='004000'/>\n";
xml << " <map address='20-3f:8000-ffff'/>\n";
xml << " <map address='a0-bf:8000-ffff'/>\n";
xml << " <dr>\n";
xml << " <map address='20-3f:8000-bfff'/>\n";
xml << " <map address='a0-bf:8000-bfff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='20-3f:c000-ffff'/>\n";
xml << " <map address='a0-bf:c000-ffff'/>\n";
xml << " </sr>\n";
xml << " </necdsp>\n";
}
if(has_dsp3) {
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp3.bin' sha256='2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90'>\n";
xml << " <dr mask='004000' test='000000'/>\n";
xml << " <sr mask='004000' test='004000'/>\n";
xml << " <map address='20-3f:8000-ffff'/>\n";
xml << " <map address='a0-bf:8000-ffff'/>\n";
xml << " <dr>\n";
xml << " <map address='20-3f:8000-bfff'/>\n";
xml << " <map address='a0-bf:8000-bfff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='20-3f:c000-ffff'/>\n";
xml << " <map address='a0-bf:c000-ffff'/>\n";
xml << " </sr>\n";
xml << " </necdsp>\n";
}
if(has_dsp4) {
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp4.bin' sha256='63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a'>\n";
xml << " <dr mask='004000' test='000000'/>\n";
xml << " <sr mask='004000' test='004000'/>\n";
xml << " <map address='30-3f:8000-ffff'/>\n";
xml << " <map address='b0-bf:8000-ffff'/>\n";
xml << " <dr>\n";
xml << " <map address='30-3f:8000-bfff'/>\n";
xml << " <map address='b0-bf:8000-bfff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='30-3f:c000-ffff'/>\n";
xml << " <map address='b0-bf:c000-ffff'/>\n";
xml << " </sr>\n";
xml << " </necdsp>\n";
}
@@ -456,21 +487,35 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
if(has_st010) {
xml << " <necdsp revision='upd96050' frequency='10000000' program='st0010.bin' sha256='55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e'>\n";
xml << " <dr mask='080001' test='000000'/>\n";
xml << " <sr mask='080001' test='000001'/>\n";
xml << " <dp mask='080000' test='080000'/>\n";
xml << " <map address='60-6f:0000-0fff'/>\n";
xml << " <map address='e0-ef:0000-0fff'/>\n";
xml << " <dr>\n";
xml << " <map address='60:0000'/>\n";
xml << " <map address='e0:0000'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='60:0001'/>\n";
xml << " <map address='e0:0001'/>\n";
xml << " </sr>\n";
xml << " <dp>\n";
xml << " <map address='68-6f:0000-0fff'/>\n";
xml << " <map address='e8-ef:0000-0fff'/>\n";
xml << " </dp>\n";
xml << " </necdsp>\n";
}
if(has_st011) {
xml << " <necdsp revision='upd96050' frequency='15000000' program='st0011.bin' sha256='b71d71fa5f18ff39b2b3688e914a04d1286b613002ddde827529fdc54650a130'>\n";
xml << " <dr mask='080001' test='000000'/>\n";
xml << " <sr mask='080001' test='000001'/>\n";
xml << " <dp mask='080000' test='080000'/>\n";
xml << " <map address='60-6f:0000-0fff'/>\n";
xml << " <map address='e0-ef:0000-0fff'/>\n";
xml << " <necdsp revision='upd96050' frequency='15000000' program='st0011.bin' sha256='651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e'>\n";
xml << " <dr>\n";
xml << " <map address='60:0000'/>\n";
xml << " <map address='e0:0000'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='60:0001'/>\n";
xml << " <map address='e0:0001'/>\n";
xml << " </sr>\n";
xml << " <dp>\n";
xml << " <map address='68-6f:0000-0fff'/>\n";
xml << " <map address='e8-ef:0000-0fff'/>\n";
xml << " </dp>\n";
xml << " </necdsp>\n";
}
@@ -482,7 +527,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
}
xml << "</cartridge>\n";
xmlMemoryMap = xml;
xmlMemoryMap = xml.transform("'", "\"");
}
void SNESCartridge::read_header(const uint8_t *data, unsigned size) {

View File

@@ -145,10 +145,15 @@ namespace nall {
inline unsigned strlcpy(string &dest, const char *src, unsigned length);
inline unsigned strlcat(string &dest, const char *src, unsigned length);
inline string substr(const char *src, unsigned start = 0, unsigned length = 0);
template<unsigned length = 0, char padding = '0'> inline string hex(uintmax_t value);
template<unsigned length = 0, char padding = '0'> inline string integer(intmax_t value);
template<unsigned length = 0, char padding = '0'> inline string decimal(uintmax_t value);
template<unsigned length = 0, char padding = '0'> inline string binary(uintmax_t value);
inline string integer(intmax_t value);
template<unsigned length = 0> inline string linteger(intmax_t value);
template<unsigned length = 0> inline string rinteger(intmax_t value);
inline string decimal(uintmax_t value);
template<unsigned length = 0> inline string ldecimal(uintmax_t value);
template<unsigned length = 0> inline string rdecimal(uintmax_t value);
template<unsigned length = 0> inline string hex(uintmax_t value);
template<unsigned length = 0> inline string binary(uintmax_t value);
inline unsigned fp(char *str, double value);
inline string fp(double value);

View File

@@ -27,7 +27,151 @@ string substr(const char *src, unsigned start, unsigned length) {
/* arithmetic <> string */
template<unsigned length, char padding> string hex(uintmax_t value) {
string integer(intmax_t value) {
bool negative = value < 0;
if(negative) value = abs(value);
char buffer[64];
unsigned size = 0;
do {
unsigned n = value % 10;
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size++] = negative ? '-' : '+';
buffer[size] = 0;
char result[size + 1];
memset(result, '0', size);
result[size] = 0;
for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) {
result[x] = buffer[y];
}
return result;
}
template<unsigned length> string linteger(intmax_t value) {
bool negative = value < 0;
if(negative) value = abs(value);
char buffer[64];
unsigned size = 0;
do {
unsigned n = value % 10;
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size++] = negative ? '-' : '+';
buffer[size] = 0;
char result[length + 1];
memset(result, ' ', length);
result[length] = 0;
for(signed x = 0, y = size - 1; x < length && y >= 0; x++, y--) {
result[x] = buffer[y];
}
return result;
}
template<unsigned length> string rinteger(intmax_t value) {
bool negative = value < 0;
if(negative) value = abs(value);
char buffer[64];
unsigned size = 0;
do {
unsigned n = value % 10;
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size++] = negative ? '-' : '+';
buffer[size] = 0;
char result[length + 1];
memset(result, ' ', length);
result[length] = 0;
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
result[x] = buffer[y];
}
return result;
}
string decimal(uintmax_t value) {
char buffer[64];
unsigned size = 0;
do {
unsigned n = value % 10;
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size] = 0;
char result[size + 1];
memset(result, '0', size);
result[size] = 0;
for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) {
result[x] = buffer[y];
}
return result;
}
template<unsigned length> string ldecimal(uintmax_t value) {
char buffer[64];
unsigned size = 0;
do {
unsigned n = value % 10;
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size] = 0;
char result[length + 1];
memset(result, ' ', length);
result[length] = 0;
for(signed x = 0, y = size - 1; x < length && y >= 0; x++, y--) {
result[x] = buffer[y];
}
return result;
}
template<unsigned length> string rdecimal(uintmax_t value) {
char buffer[64];
unsigned size = 0;
do {
unsigned n = value % 10;
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size] = 0;
char result[length + 1];
memset(result, ' ', length);
result[length] = 0;
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
result[x] = buffer[y];
}
return result;
}
template<unsigned length> string hex(uintmax_t value) {
string output;
unsigned offset = 0;
@@ -38,7 +182,7 @@ template<unsigned length, char padding> string hex(uintmax_t value) {
value >>= 4;
} while(value);
while(offset < length) output[offset++] = padding;
while(offset < length) output[offset++] = '0';
output[offset--] = 0;
//reverse the string in-place
@@ -51,55 +195,7 @@ template<unsigned length, char padding> string hex(uintmax_t value) {
return output;
}
template<unsigned length, char padding> string integer(intmax_t value) {
string output;
unsigned offset = 0;
bool negative = value < 0;
if(negative) value = abs(value);
do {
unsigned n = value % 10;
output[offset++] = '0' + n;
value /= 10;
} while(value);
while(offset < length) output[offset++] = padding;
if(negative) output[offset++] = '-';
output[offset--] = 0;
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
char temp = output[i];
output[i] = output[offset - i];
output[offset - i] = temp;
}
return output;
}
template<unsigned length, char padding> string decimal(uintmax_t value) {
string output;
unsigned offset = 0;
do {
unsigned n = value % 10;
output[offset++] = '0' + n;
value /= 10;
} while(value);
while(offset < length) output[offset++] = padding;
output[offset--] = 0;
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
char temp = output[i];
output[i] = output[offset - i];
output[offset - i] = temp;
}
return output;
}
template<unsigned length, char padding> string binary(uintmax_t value) {
template<unsigned length> string binary(uintmax_t value) {
string output;
unsigned offset = 0;
@@ -109,7 +205,7 @@ template<unsigned length, char padding> string binary(uintmax_t value) {
value >>= 1;
} while(value);
while(offset < length) output[offset++] = padding;
while(offset < length) output[offset++] = '0';
output[offset--] = 0;
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {

View File

@@ -46,7 +46,7 @@ namespace nall {
void reserve(unsigned newsize) {
newsize = bit::round(newsize); //round to nearest power of two (for amortized growth)
T *poolcopy = (T*)malloc(newsize * sizeof(T));
T *poolcopy = (T*)calloc(newsize, sizeof(T));
for(unsigned i = 0; i < min(objectsize, newsize); i++) new(poolcopy + i) T(pool[i]);
for(unsigned i = 0; i < objectsize; i++) pool[i].~T();
free(pool);

View File

@@ -107,6 +107,8 @@ struct Window : Widget {
void setStatusText(const nall::string &text);
void setMenuVisible(bool visible = true);
void setStatusVisible(bool visible = true);
bool fullscreen();
void setFullscreen(bool fullscreen = true);
Window();
//private:
struct Data;

View File

@@ -27,6 +27,11 @@ struct Widget::Data {
struct Window::Data {
Font *defaultFont;
bool isFullscreen;
unsigned x;
unsigned y;
unsigned width;
unsigned height;
};
struct Canvas::Data {

View File

@@ -8,6 +8,11 @@ static gint Window_close(Window *window) {
}
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
window->x = x;
window->y = y;
window->width = width;
window->height = height;
object->widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_move(GTK_WINDOW(object->widget), x, y);
@@ -55,8 +60,8 @@ Geometry Window::geometry() {
}
void Window::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
gtk_window_move(GTK_WINDOW(object->widget), x, y);
gtk_widget_set_size_request(object->formContainer, width, height);
gtk_window_move(GTK_WINDOW(object->widget), window->x = x, window->y = y);
gtk_widget_set_size_request(object->formContainer, window->width = width, window->height = height);
}
void Window::setDefaultFont(Font &font) {
@@ -93,7 +98,40 @@ void Window::setStatusVisible(bool visible) {
gtk_widget_set_visible(object->status, visible);
}
bool Window::fullscreen() {
return window->isFullscreen;
}
void Window::setFullscreen(bool fullscreen) {
window->isFullscreen = fullscreen;
if(fullscreen == true) {
gtk_window_fullscreen(GTK_WINDOW(object->widget));
gtk_window_set_decorated(GTK_WINDOW(object->widget), false);
gtk_widget_set_size_request(object->widget, gdk_screen_width(), gdk_screen_height());
} else {
gtk_widget_set_size_request(object->widget, -1, -1);
gtk_window_set_decorated(GTK_WINDOW(object->widget), true);
gtk_window_unfullscreen(GTK_WINDOW(object->widget));
//at this point, GTK+ has not updated window geometry
//this causes Window::geometry() calls to return incorrect info
//thus, wait until the geometry has changed before continuing
Geometry geom;
time_t startTime = time(0);
do {
OS::run();
Geometry geom = geometry();
if(startTime - time(0) > 3) break; //prevent application from freezing
} while(geom.x == 0 && geom.y == 0 && geom.width == gdk_screen_width() && geom.height == gdk_screen_height());
}
}
Window::Window() {
window = new Window::Data;
window->defaultFont = 0;
window->isFullscreen = false;
window->x = 0;
window->y = 0;
window->width = 0;
window->height = 0;
}

View File

@@ -140,6 +140,8 @@ struct Window : Widget {
void setMenuVisible(bool visible = true);
void setStatusVisible(bool visible = true);
bool focused();
bool fullscreen();
void setFullscreen(bool fullscreen = true);
Window();
//private:
struct Data;

View File

@@ -1,7 +1,7 @@
/****************************************************************************
** Meta object code from reading C++ file 'qt.moc.hpp'
**
** Created: Mon Nov 1 06:26:59 2010
** Created: Tue Jan 18 03:30:57 2011
** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2)
**
** WARNING! All changes made in this file will be lost!

View File

@@ -3,6 +3,7 @@ void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, con
window->move(x, y);
window->layout = new QVBoxLayout(window);
window->layout->setAlignment(Qt::AlignTop);
window->layout->setMargin(0);
window->layout->setSpacing(0);
window->layout->setSizeConstraint(QLayout::SetFixedSize);
@@ -70,6 +71,28 @@ bool Window::focused() {
return window->isActiveWindow() && !window->isMinimized();
}
bool Window::fullscreen() {
return window->isFullScreen();
}
void Window::setFullscreen(bool fullscreen) {
if(fullscreen == false) {
window->showNormal();
} else {
window->showFullScreen();
}
//Qt returns negative coordinates for x,y immediately after setFullscreen(false)
//wait for Qt to return sane values, or until timeout occurs
Geometry geom;
time_t startTime = time(0);
do {
OS::run();
geom = geometry();
if(startTime - time(0) > 3) break;
} while((signed)geom.x < 0 || (signed)geom.y < 0);
}
Window::Window() {
window = new Window::Data(*this);
window->defaultFont = 0;

View File

@@ -26,6 +26,9 @@ struct Window::Data {
COLORREF brushColor;
HMENU menu;
HWND status;
bool isFullscreen;
unsigned x;
unsigned y;
unsigned width;
unsigned height;
};

View File

@@ -2,7 +2,7 @@ void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, con
widget->window = CreateWindowEx(
0, L"phoenix_window", utf16_t(text),
WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
x, y, width, height,
window->x = x, window->y = y, window->width = width, window->height = height,
0, 0, GetModuleHandle(0), 0
);
window->menu = CreateMenu();
@@ -39,6 +39,13 @@ Geometry Window::geometry() {
}
void Window::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
if(window->isFullscreen == false) {
window->x = x;
window->y = y;
window->width = width;
window->height = height;
}
bool isVisible = visible();
if(isVisible) setVisible(false);
SetWindowPos(widget->window, NULL, x, y, width, height, SWP_NOZORDER | SWP_FRAMECHANGED);
@@ -70,16 +77,33 @@ void Window::setStatusVisible(bool visible) {
resize(window->width, window->height);
}
bool Window::fullscreen() {
return window->isFullscreen;
}
void Window::setFullscreen(bool fullscreen) {
window->isFullscreen = fullscreen;
if(fullscreen == false) {
SetWindowLong(widget->window, GWL_STYLE, WS_VISIBLE | WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX);
setGeometry(window->x, window->y, window->width, window->height);
} else {
SetWindowLong(widget->window, GWL_STYLE, WS_VISIBLE | WS_POPUP);
setGeometry(0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
}
}
Window::Window() {
window = new Window::Data;
window->defaultFont = 0;
window->brush = 0;
window->isFullscreen = false;
window->x = 0;
window->y = 0;
window->width = 0;
window->height = 0;
}
void Window::resize(unsigned width, unsigned height) {
window->width = width;
window->height = height;
SetWindowPos(widget->window, NULL, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE | SWP_FRAMECHANGED);
RECT rc;
GetClientRect(widget->window, &rc);

View File

@@ -112,6 +112,8 @@ struct Window : Widget {
void setStatusText(const nall::string &text);
void setMenuVisible(bool visible = true);
void setStatusVisible(bool visible = true);
bool fullscreen();
void setFullscreen(bool fullscreen = true);
Window();
//private:
struct Data;

View File

@@ -4,7 +4,7 @@ snes_objects += snes-memory snes-cpucore snes-smpcore
snes_objects += snes-cpu snes-smp snes-dsp snes-ppu
snes_objects += snes-icd2 snes-superfx snes-sa1 snes-necdsp
snes_objects += snes-bsx snes-srtc snes-sdd1 snes-spc7110 snes-cx4
snes_objects += snes-obc1 snes-st0018
snes_objects += snes-obc1 snes-st0018 snes-sufamiturbo
snes_objects += snes-msu1 snes-serial
objects += $(snes_objects)
@@ -28,8 +28,6 @@ else ifeq ($(profile),performance)
snesppu := $(snes)/alt/ppu-performance
endif
obj/libsnes.o: $(snes)/libsnes/libsnes.cpp $(snes)/libsnes/*
obj/snes-system.o : $(snes)/system/system.cpp $(call rwildcard,$(snes)/system/) $(call rwildcard,$(snes)/video/)
obj/snes-memory.o : $(snes)/memory/memory.cpp $(call rwildcard,$(snes)/memory/)
obj/snes-cpucore.o : $(snes)/cpu/core/core.cpp $(call rwildcard,$(snes)/cpu/core/)
@@ -41,50 +39,17 @@ obj/snes-ppu.o : $(snesppu)/ppu.cpp $(call rwildcard,$(snesppu)/)
obj/snes-cartridge.o: $(snes)/cartridge/cartridge.cpp $(snes)/cartridge/*
obj/snes-cheat.o : $(snes)/cheat/cheat.cpp $(snes)/cheat/*
obj/snes-icd2.o : $(snes)/chip/icd2/icd2.cpp $(call rwildcard,$(snes)/chip/icd2/)
obj/snes-superfx.o : $(snes)/chip/superfx/superfx.cpp $(call rwildcard,$(snes)/chip/superfx/)
obj/snes-sa1.o : $(snes)/chip/sa1/sa1.cpp $(call rwildcard,$(snes)/chip/sa1/)
obj/snes-necdsp.o : $(snes)/chip/necdsp/necdsp.cpp $(call rwildcard,$(snes)/chip/necdsp/)
obj/snes-bsx.o : $(snes)/chip/bsx/bsx.cpp $(snes)/chip/bsx/*
obj/snes-srtc.o : $(snes)/chip/srtc/srtc.cpp $(snes)/chip/srtc/*
obj/snes-sdd1.o : $(snes)/chip/sdd1/sdd1.cpp $(snes)/chip/sdd1/*
obj/snes-spc7110.o : $(snes)/chip/spc7110/spc7110.cpp $(snes)/chip/spc7110/*
obj/snes-cx4.o : $(snes)/chip/cx4/cx4.cpp $(snes)/chip/cx4/*
obj/snes-obc1.o : $(snes)/chip/obc1/obc1.cpp $(snes)/chip/obc1/*
obj/snes-st0018.o : $(snes)/chip/st0018/st0018.cpp $(snes)/chip/st0018/*
obj/snes-msu1.o : $(snes)/chip/msu1/msu1.cpp $(snes)/chip/msu1/*
obj/snes-serial.o : $(snes)/chip/serial/serial.cpp $(snes)/chip/serial/*
###########
# library #
###########
snes_objects := $(patsubst %,obj/%.o,$(snes_objects))
library: $(snes_objects) obj/libsnes.o
ifeq ($(platform),x)
ar rcs out/libsnes.a $(snes_objects) obj/libsnes.o
$(cpp) -o out/libsnes.so -shared -Wl,-soname,libsnes.so.1 $(snes_objects) obj/libsnes.o
else ifeq ($(platform),osx)
ar rcs out/libsnes.a $(snes_objects) obj/libsnes.o
$(cpp) -o out/libsnes.dylib -install_name @executable_path/../Libraries/libsnes.dylib -shared -dynamiclib $(snes_objects) obj/libsnes.o
else ifeq ($(platform),win)
$(cpp) -o out/snes.dll -shared -Wl,--out-implib,libsnes.a $(snes_objects) obj/libsnes.o
endif
library-install:
ifeq ($(platform),x)
install -D -m 755 out/libsnes.a $(DESTDIR)$(prefix)/lib/libsnes.a
install -D -m 755 out/libsnes.so $(DESTDIR)$(prefix)/lib/libsnes.so
ldconfig -n $(DESTDIR)$(prefix)/lib
else ifeq ($(platform),osx)
cp out/libsnes.dylib /usr/local/lib/libsnes.dylib
endif
library-uninstall:
ifeq ($(platform),x)
rm $(DESTDIR)$(prefix)/lib/libsnes.a
rm $(DESTDIR)$(prefix)/lib/libsnes.so
else ifeq ($(platform),osx)
rm /usr/local/lib/libsnes.dylib
endif
obj/snes-icd2.o : $(snes)/chip/icd2/icd2.cpp $(call rwildcard,$(snes)/chip/icd2/)
obj/snes-superfx.o : $(snes)/chip/superfx/superfx.cpp $(call rwildcard,$(snes)/chip/superfx/)
obj/snes-sa1.o : $(snes)/chip/sa1/sa1.cpp $(call rwildcard,$(snes)/chip/sa1/)
obj/snes-necdsp.o : $(snes)/chip/necdsp/necdsp.cpp $(call rwildcard,$(snes)/chip/necdsp/)
obj/snes-bsx.o : $(snes)/chip/bsx/bsx.cpp $(call rwildcard,$(snes)/chip/bsx/)
obj/snes-srtc.o : $(snes)/chip/srtc/srtc.cpp $(snes)/chip/srtc/*
obj/snes-sdd1.o : $(snes)/chip/sdd1/sdd1.cpp $(snes)/chip/sdd1/*
obj/snes-spc7110.o : $(snes)/chip/spc7110/spc7110.cpp $(snes)/chip/spc7110/*
obj/snes-cx4.o : $(snes)/chip/cx4/cx4.cpp $(snes)/chip/cx4/*
obj/snes-obc1.o : $(snes)/chip/obc1/obc1.cpp $(snes)/chip/obc1/*
obj/snes-st0018.o : $(snes)/chip/st0018/st0018.cpp $(snes)/chip/st0018/*
obj/snes-sufamiturbo.o: $(snes)/chip/sufamiturbo/sufamiturbo.cpp $(snes)/chip/sufamiturbo/*
obj/snes-msu1.o : $(snes)/chip/msu1/msu1.cpp $(snes)/chip/msu1/*
obj/snes-serial.o : $(snes)/chip/serial/serial.cpp $(snes)/chip/serial/*

View File

@@ -90,6 +90,30 @@ void CPU::op_irq(uint16 vector) {
regs.pc.w = rd.w;
}
void CPU::enable() {
function<uint8 (unsigned)> read = { &CPU::mmio_read, (CPU*)&cpu };
function<void (unsigned, uint8)> write = { &CPU::mmio_write, (CPU*)&cpu };
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, read, write);
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, read, write);
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, read, write);
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, read, write);
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4200, 0x421f, read, write);
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, read, write);
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, read, write);
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, read, write);
read = [](unsigned addr) { return cpu.wram[addr]; };
write = [](unsigned addr, uint8 data) { cpu.wram[addr] = data; };
bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
bus.map(Bus::MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff, read, write);
}
void CPU::power() {
regs.a = 0x0000;
regs.x = 0x0000;

View File

@@ -1,5 +1,7 @@
class CPU : public Processor, public CPUcore, public PPUcounter, public MMIO {
class CPU : public Processor, public CPUcore, public PPUcounter {
public:
uint8 wram[128 * 1024];
enum : bool { Threaded = true };
array<Processor*> coprocessors;
alwaysinline void step(unsigned clocks);
@@ -20,6 +22,7 @@ public:
debugvirtual void op_write(unsigned addr, uint8 data);
void enter();
void enable();
void power();
void reset();

View File

@@ -8,13 +8,11 @@ void CPUDebugger::op_step() {
opcode_pc = regs.pc;
opcode_edge = true;
if(debugger.step_cpu) {
debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00);
if(step_event && step_event()) {
debugger.break_event = Debugger::BreakEvent::CPUStep;
scheduler.exit(Scheduler::ExitReason::DebuggerEvent);
} else {
debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00);
}
if(step_event) step_event();
opcode_edge = false;
CPU::op_step();

View File

@@ -2,7 +2,7 @@ class CPUDebugger : public CPU, public ChipDebugger {
public:
bool property(unsigned id, string &name, string &value);
function<void ()> step_event;
function<bool ()> step_event;
enum Usage {
UsageRead = 0x80,

View File

@@ -5,6 +5,8 @@ void CPU::serialize(serializer &s) {
CPUcore::core_serialize(s);
PPUcounter::serialize(s);
s.array(wram);
queue.serialize(s);
s.array(port_data);

View File

@@ -40,7 +40,7 @@ void DSP::write(uint8 addr, uint8 data) {
}
void DSP::power() {
spc_dsp.init(memory::apuram.data());
spc_dsp.init(smp.apuram);
spc_dsp.reset();
spc_dsp.set_output(samplebuffer, 8192);
}

View File

@@ -26,7 +26,7 @@ uint8 PPU::vram_mmio_read(uint16 addr) {
uint8 data;
if(regs.display_disabled == true) {
data = memory::vram[addr];
data = vram[addr];
} else {
uint16 v = cpu.vcounter();
uint16 h = cpu.hcounter();
@@ -39,12 +39,12 @@ uint8 PPU::vram_mmio_read(uint16 addr) {
data = 0x00;
} else if(v == (!overscan() ? 224 : 239)) {
if(h == 1362) {
data = memory::vram[addr];
data = vram[addr];
} else {
data = 0x00;
}
} else {
data = memory::vram[addr];
data = vram[addr];
}
}
@@ -53,15 +53,15 @@ uint8 PPU::vram_mmio_read(uint16 addr) {
void PPU::vram_mmio_write(uint16 addr, uint8 data) {
if(regs.display_disabled == true) {
memory::vram[addr] = data;
vram[addr] = data;
} else {
uint16 v = cpu.vcounter();
uint16 h = cpu.hcounter();
if(v == 0) {
if(h <= 4) {
memory::vram[addr] = data;
vram[addr] = data;
} else if(h == 6) {
memory::vram[addr] = cpu.regs.mdr;
vram[addr] = cpu.regs.mdr;
} else {
//no write
}
@@ -71,10 +71,10 @@ void PPU::vram_mmio_write(uint16 addr, uint8 data) {
if(h <= 4) {
//no write
} else {
memory::vram[addr] = data;
vram[addr] = data;
}
} else {
memory::vram[addr] = data;
vram[addr] = data;
}
}
}
@@ -85,12 +85,12 @@ uint8 PPU::oam_mmio_read(uint16 addr) {
uint8 data;
if(regs.display_disabled == true) {
data = memory::oam[addr];
data = oam[addr];
} else {
if(cpu.vcounter() < (!overscan() ? 225 : 240)) {
data = memory::oam[regs.ioamaddr];
data = oam[regs.ioamaddr];
} else {
data = memory::oam[addr];
data = oam[addr];
}
}
@@ -104,14 +104,14 @@ void PPU::oam_mmio_write(uint16 addr, uint8 data) {
sprite_list_valid = false;
if(regs.display_disabled == true) {
memory::oam[addr] = data;
oam[addr] = data;
update_sprite_list(addr, data);
} else {
if(cpu.vcounter() < (!overscan() ? 225 : 240)) {
memory::oam[regs.ioamaddr] = data;
oam[regs.ioamaddr] = data;
update_sprite_list(regs.ioamaddr, data);
} else {
memory::oam[addr] = data;
oam[addr] = data;
update_sprite_list(addr, data);
}
}
@@ -122,14 +122,14 @@ uint8 PPU::cgram_mmio_read(uint16 addr) {
uint8 data;
if(1 || regs.display_disabled == true) {
data = memory::cgram[addr];
data = cgram[addr];
} else {
uint16 v = cpu.vcounter();
uint16 h = cpu.hcounter();
if(v < (!overscan() ? 225 : 240) && h >= 128 && h < 1096) {
data = memory::cgram[regs.icgramaddr] & 0x7f;
data = cgram[regs.icgramaddr] & 0x7f;
} else {
data = memory::cgram[addr];
data = cgram[addr];
}
}
@@ -142,14 +142,14 @@ void PPU::cgram_mmio_write(uint16 addr, uint8 data) {
if(addr & 1) data &= 0x7f;
if(1 || regs.display_disabled == true) {
memory::cgram[addr] = data;
cgram[addr] = data;
} else {
uint16 v = cpu.vcounter();
uint16 h = cpu.hcounter();
if(v < (!overscan() ? 225 : 240) && h >= 128 && h < 1096) {
memory::cgram[regs.icgramaddr] = data & 0x7f;
cgram[regs.icgramaddr] = data & 0x7f;
} else {
memory::cgram[addr] = data;
cgram[addr] = data;
}
}
}

View File

@@ -122,13 +122,21 @@ void PPU::frame() {
framecounter = (frameskip == 0 ? 0 : (framecounter + 1) % frameskip);
}
void PPU::enable() {
function<uint8 (unsigned)> read = { &PPU::mmio_read, (PPU*)&ppu };
function<void (unsigned, uint8)> write = { &PPU::mmio_write, (PPU*)&ppu };
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, read, write);
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, read, write);
}
void PPU::power() {
ppu1_version = config.ppu1.version;
ppu2_version = config.ppu2.version;
for(unsigned i = 0; i < memory::vram.size(); i++) memory::vram[i] = 0x00;
for(unsigned i = 0; i < memory::oam.size(); i++) memory::oam[i] = 0x00;
for(unsigned i = 0; i < memory::cgram.size(); i++) memory::cgram[i] = 0x00;
foreach(n, vram) n = 0x00;
foreach(n, oam) n = 0x00;
foreach(n, cgram) n = 0x00;
flush_tiledata_cache();
region = (system.region() == System::Region::NTSC ? 0 : 1); //0 = NTSC, 1 = PAL

View File

@@ -1,5 +1,9 @@
class PPU : public Processor, public PPUcounter, public MMIO {
class PPU : public Processor, public PPUcounter {
public:
uint8 vram[128 * 1024];
uint8 oam[544];
uint8 cgram[512];
enum : bool { Threaded = true };
alwaysinline void step(unsigned clocks);
alwaysinline void synchronize_cpu();
@@ -56,6 +60,7 @@ public:
void render_scanline();
void frame();
void enter();
void enable();
void power();
void reset();

View File

@@ -32,7 +32,7 @@ uint16 PPU::bg_get_tile(uint16 x, uint16 y) {
if(x & 0x20) pos += bg_info[bg].scx;
const uint16 addr = regs.bg_scaddr[bg] + (pos << 1);
return memory::vram[addr] + (memory::vram[addr + 1] << 8);
return vram[addr] + (vram[addr + 1] << 8);
}
#define setpixel_main(x) \

View File

@@ -32,8 +32,8 @@ void PPU::render_bg_tile(uint16 tile_num) {
unsigned pos = tile_num * 16;
unsigned y = 8;
while(y--) {
d0 = memory::vram[pos ];
d1 = memory::vram[pos + 1];
d0 = vram[pos ];
d1 = vram[pos + 1];
render_bg_tile_line_2bpp(0x80);
render_bg_tile_line_2bpp(0x40);
render_bg_tile_line_2bpp(0x20);
@@ -52,10 +52,10 @@ void PPU::render_bg_tile(uint16 tile_num) {
unsigned pos = tile_num * 32;
unsigned y = 8;
while(y--) {
d0 = memory::vram[pos ];
d1 = memory::vram[pos + 1];
d2 = memory::vram[pos + 16];
d3 = memory::vram[pos + 17];
d0 = vram[pos ];
d1 = vram[pos + 1];
d2 = vram[pos + 16];
d3 = vram[pos + 17];
render_bg_tile_line_4bpp(0x80);
render_bg_tile_line_4bpp(0x40);
render_bg_tile_line_4bpp(0x20);
@@ -74,14 +74,14 @@ void PPU::render_bg_tile(uint16 tile_num) {
unsigned pos = tile_num * 64;
unsigned y = 8;
while(y--) {
d0 = memory::vram[pos ];
d1 = memory::vram[pos + 1];
d2 = memory::vram[pos + 16];
d3 = memory::vram[pos + 17];
d4 = memory::vram[pos + 32];
d5 = memory::vram[pos + 33];
d6 = memory::vram[pos + 48];
d7 = memory::vram[pos + 49];
d0 = vram[pos ];
d1 = vram[pos + 1];
d2 = vram[pos + 16];
d3 = vram[pos + 17];
d4 = vram[pos + 32];
d5 = vram[pos + 33];
d6 = vram[pos + 48];
d7 = vram[pos + 49];
render_bg_tile_line_8bpp(0x80);
render_bg_tile_line_8bpp(0x40);
render_bg_tile_line_8bpp(0x20);

View File

@@ -2,7 +2,7 @@
inline uint16 PPU::get_palette(uint8 index) {
const unsigned addr = index << 1;
return memory::cgram[addr] + (memory::cgram[addr + 1] << 8);
return cgram[addr] + (cgram[addr + 1] << 8);
}
//p = 00000bgr <palette data>

View File

@@ -71,8 +71,8 @@ void PPU::render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) {
py &= 1023;
tx = ((px >> 3) & 127);
ty = ((py >> 3) & 127);
tile = memory::vram[(ty * 128 + tx) << 1];
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
tile = vram[(ty * 128 + tx) << 1];
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
} break;
case 2: { //palette color 0 outside of screen area
if((px | py) & ~1023) {
@@ -82,8 +82,8 @@ void PPU::render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) {
py &= 1023;
tx = ((px >> 3) & 127);
ty = ((py >> 3) & 127);
tile = memory::vram[(ty * 128 + tx) << 1];
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
tile = vram[(ty * 128 + tx) << 1];
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
}
} break;
case 3: { //character 0 repetition outside of screen area
@@ -94,9 +94,9 @@ void PPU::render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) {
py &= 1023;
tx = ((px >> 3) & 127);
ty = ((py >> 3) & 127);
tile = memory::vram[(ty * 128 + tx) << 1];
tile = vram[(ty * 128 + tx) << 1];
}
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
} break;
}

View File

@@ -16,6 +16,10 @@ void PPU::serialize(serializer &s) {
Processor::serialize(s);
PPUcounter::serialize(s);
s.array(vram);
s.array(oam);
s.array(cgram);
s.integer(ppu1_version);
s.integer(ppu2_version);

View File

@@ -11,7 +11,7 @@ unsigned PPU::Background::get_tile(unsigned hoffset, unsigned voffset) {
if(tile_x & 0x20) tile_pos += scx;
const uint16 tiledata_addr = regs.screen_addr + (tile_pos << 1);
return (memory::vram[tiledata_addr + 0] << 0) + (memory::vram[tiledata_addr + 1] << 8);
return (ppu.vram[tiledata_addr + 0] << 0) + (ppu.vram[tiledata_addr + 1] << 8);
}
void PPU::Background::offset_per_tile(unsigned x, unsigned y, unsigned &hoffset, unsigned &voffset) {

View File

@@ -43,8 +43,8 @@ void PPU::Background::render_mode7() {
py &= 1023;
tx = ((px >> 3) & 127);
ty = ((py >> 3) & 127);
tile = memory::vram[(ty * 128 + tx) << 1];
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
tile = ppu.vram[(ty * 128 + tx) << 1];
palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
break;
}
@@ -56,8 +56,8 @@ void PPU::Background::render_mode7() {
py &= 1023;
tx = ((px >> 3) & 127);
ty = ((py >> 3) & 127);
tile = memory::vram[(ty * 128 + tx) << 1];
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
tile = ppu.vram[(ty * 128 + tx) << 1];
palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
}
break;
}
@@ -70,9 +70,9 @@ void PPU::Background::render_mode7() {
py &= 1023;
tx = ((px >> 3) & 127);
ty = ((py >> 3) & 127);
tile = memory::vram[(ty * 128 + tx) << 1];
tile = ppu.vram[(ty * 128 + tx) << 1];
}
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
break;
}
}

View File

@@ -8,8 +8,8 @@ uint8* PPU::Cache::tile_2bpp(unsigned tile) {
unsigned y = 8;
unsigned color, d0, d1;
while(y--) {
d0 = memory::vram[offset + 0];
d1 = memory::vram[offset + 1];
d0 = ppu.vram[offset + 0];
d1 = ppu.vram[offset + 1];
#define render_line(mask) \
color = !!(d0 & mask) << 0; \
color |= !!(d1 & mask) << 1; \
@@ -37,10 +37,10 @@ uint8* PPU::Cache::tile_4bpp(unsigned tile) {
unsigned y = 8;
unsigned color, d0, d1, d2, d3;
while(y--) {
d0 = memory::vram[offset + 0];
d1 = memory::vram[offset + 1];
d2 = memory::vram[offset + 16];
d3 = memory::vram[offset + 17];
d0 = ppu.vram[offset + 0];
d1 = ppu.vram[offset + 1];
d2 = ppu.vram[offset + 16];
d3 = ppu.vram[offset + 17];
#define render_line(mask) \
color = !!(d0 & mask) << 0; \
color |= !!(d1 & mask) << 1; \
@@ -70,14 +70,14 @@ uint8* PPU::Cache::tile_8bpp(unsigned tile) {
unsigned y = 8;
unsigned color, d0, d1, d2, d3, d4, d5, d6, d7;
while(y--) {
d0 = memory::vram[offset + 0];
d1 = memory::vram[offset + 1];
d2 = memory::vram[offset + 16];
d3 = memory::vram[offset + 17];
d4 = memory::vram[offset + 32];
d5 = memory::vram[offset + 33];
d6 = memory::vram[offset + 48];
d7 = memory::vram[offset + 49];
d0 = ppu.vram[offset + 0];
d1 = ppu.vram[offset + 1];
d2 = ppu.vram[offset + 16];
d3 = ppu.vram[offset + 17];
d4 = ppu.vram[offset + 32];
d5 = ppu.vram[offset + 33];
d6 = ppu.vram[offset + 48];
d7 = ppu.vram[offset + 49];
#define render_line(mask) \
color = !!(d0 & mask) << 0; \
color |= !!(d1 & mask) << 1; \

View File

@@ -22,14 +22,14 @@ uint16 PPU::get_vram_addr() {
}
uint8 PPU::vram_read(unsigned addr) {
if(regs.display_disable) return memory::vram[addr];
if(cpu.vcounter() >= display.height) return memory::vram[addr];
if(regs.display_disable) return vram[addr];
if(cpu.vcounter() >= display.height) return vram[addr];
return 0x00;
}
void PPU::vram_write(unsigned addr, uint8 data) {
if(regs.display_disable || cpu.vcounter() >= display.height) {
memory::vram[addr] = data;
vram[addr] = data;
cache.tilevalid[0][addr >> 4] = false;
cache.tilevalid[1][addr >> 5] = false;
cache.tilevalid[2][addr >> 6] = false;
@@ -39,24 +39,24 @@ void PPU::vram_write(unsigned addr, uint8 data) {
uint8 PPU::oam_read(unsigned addr) {
if(addr & 0x0200) addr &= 0x021f;
if(regs.display_disable) return memory::oam[addr];
if(cpu.vcounter() >= display.height) return memory::oam[addr];
return memory::oam[0x0218];
if(regs.display_disable) return oam[addr];
if(cpu.vcounter() >= display.height) return oam[addr];
return oam[0x0218];
}
void PPU::oam_write(unsigned addr, uint8 data) {
if(addr & 0x0200) addr &= 0x021f;
if(!regs.display_disable && cpu.vcounter() < display.height) addr = 0x0218;
memory::oam[addr] = data;
oam.update_list(addr, data);
oam[addr] = data;
sprite.update_list(addr, data);
}
uint8 PPU::cgram_read(unsigned addr) {
return memory::cgram[addr];
return cgram[addr];
}
void PPU::cgram_write(unsigned addr, uint8 data) {
memory::cgram[addr] = data;
cgram[addr] = data;
}
void PPU::mmio_update_video_mode() {
@@ -66,7 +66,7 @@ void PPU::mmio_update_video_mode() {
bg2.regs.mode = Background::Mode::BPP2; bg2.regs.priority0 = 7; bg2.regs.priority1 = 10;
bg3.regs.mode = Background::Mode::BPP2; bg3.regs.priority0 = 2; bg3.regs.priority1 = 5;
bg4.regs.mode = Background::Mode::BPP2; bg4.regs.priority0 = 1; bg4.regs.priority1 = 4;
oam.regs.priority0 = 3; oam.regs.priority1 = 6; oam.regs.priority2 = 9; oam.regs.priority3 = 12;
sprite.regs.priority0 = 3; sprite.regs.priority1 = 6; sprite.regs.priority2 = 9; sprite.regs.priority3 = 12;
} break;
case 1: {
@@ -78,12 +78,12 @@ void PPU::mmio_update_video_mode() {
bg1.regs.priority0 = 5; bg1.regs.priority1 = 8;
bg2.regs.priority0 = 4; bg2.regs.priority1 = 7;
bg3.regs.priority0 = 1; bg3.regs.priority1 = 10;
oam.regs.priority0 = 2; oam.regs.priority1 = 3; oam.regs.priority2 = 6; oam.regs.priority3 = 9;
sprite.regs.priority0 = 2; sprite.regs.priority1 = 3; sprite.regs.priority2 = 6; sprite.regs.priority3 = 9;
} else {
bg1.regs.priority0 = 6; bg1.regs.priority1 = 9;
bg2.regs.priority0 = 5; bg2.regs.priority1 = 8;
bg3.regs.priority0 = 1; bg3.regs.priority1 = 3;
oam.regs.priority0 = 2; oam.regs.priority1 = 4; oam.regs.priority2 = 7; oam.regs.priority3 = 10;
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 7; sprite.regs.priority3 = 10;
}
} break;
@@ -94,7 +94,7 @@ void PPU::mmio_update_video_mode() {
bg4.regs.mode = Background::Mode::Inactive;
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
oam.regs.priority0 = 2; oam.regs.priority1 = 4; oam.regs.priority2 = 6; oam.regs.priority3 = 8;
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8;
} break;
case 3: {
@@ -104,7 +104,7 @@ void PPU::mmio_update_video_mode() {
bg4.regs.mode = Background::Mode::Inactive;
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
oam.regs.priority0 = 2; oam.regs.priority1 = 4; oam.regs.priority2 = 6; oam.regs.priority3 = 8;
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8;
} break;
case 4: {
@@ -114,7 +114,7 @@ void PPU::mmio_update_video_mode() {
bg4.regs.mode = Background::Mode::Inactive;
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
oam.regs.priority0 = 2; oam.regs.priority1 = 4; oam.regs.priority2 = 6; oam.regs.priority3 = 8;
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8;
} break;
case 5: {
@@ -124,7 +124,7 @@ void PPU::mmio_update_video_mode() {
bg4.regs.mode = Background::Mode::Inactive;
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
oam.regs.priority0 = 2; oam.regs.priority1 = 4; oam.regs.priority2 = 6; oam.regs.priority3 = 8;
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8;
} break;
case 6: {
@@ -133,7 +133,7 @@ void PPU::mmio_update_video_mode() {
bg3.regs.mode = Background::Mode::Inactive;
bg4.regs.mode = Background::Mode::Inactive;
bg1.regs.priority0 = 2; bg1.regs.priority1 = 5;
oam.regs.priority0 = 1; oam.regs.priority1 = 3; oam.regs.priority2 = 4; oam.regs.priority3 = 6;
sprite.regs.priority0 = 1; sprite.regs.priority1 = 3; sprite.regs.priority2 = 4; sprite.regs.priority3 = 6;
} break;
case 7: {
@@ -143,7 +143,7 @@ void PPU::mmio_update_video_mode() {
bg3.regs.mode = Background::Mode::Inactive;
bg4.regs.mode = Background::Mode::Inactive;
bg1.regs.priority0 = 2; bg1.regs.priority1 = 2;
oam.regs.priority0 = 1; oam.regs.priority1 = 3; oam.regs.priority2 = 4; oam.regs.priority3 = 5;
sprite.regs.priority0 = 1; sprite.regs.priority1 = 3; sprite.regs.priority2 = 4; sprite.regs.priority3 = 5;
} else {
bg1.regs.mode = Background::Mode::Mode7;
bg2.regs.mode = Background::Mode::Mode7;
@@ -151,7 +151,7 @@ void PPU::mmio_update_video_mode() {
bg4.regs.mode = Background::Mode::Inactive;
bg1.regs.priority0 = 3; bg1.regs.priority1 = 3;
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
oam.regs.priority0 = 2; oam.regs.priority1 = 4; oam.regs.priority2 = 6; oam.regs.priority3 = 7;
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 7;
}
} break;
}
@@ -193,7 +193,7 @@ uint8 PPU::mmio_read(unsigned addr) {
case 0x2138: { //OAMDATAREAD
regs.ppu1_mdr = oam_read(regs.oam_addr);
regs.oam_addr = (regs.oam_addr + 1) & 0x03ff;
oam.set_first();
sprite.set_first();
return regs.ppu1_mdr;
}
@@ -251,8 +251,8 @@ uint8 PPU::mmio_read(unsigned addr) {
case 0x213e: { //STAT77
regs.ppu1_mdr &= 0x10;
regs.ppu1_mdr |= oam.regs.time_over << 7;
regs.ppu1_mdr |= oam.regs.range_over << 6;
regs.ppu1_mdr |= sprite.regs.time_over << 7;
regs.ppu1_mdr |= sprite.regs.range_over << 6;
regs.ppu1_mdr |= 0x01; //version
return regs.ppu1_mdr;
}
@@ -283,30 +283,30 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
switch(addr & 0xffff) {
case 0x2100: { //INIDISP
if(regs.display_disable && cpu.vcounter() == display.height) oam.address_reset();
if(regs.display_disable && cpu.vcounter() == display.height) sprite.address_reset();
regs.display_disable = data & 0x80;
regs.display_brightness = data & 0x0f;
return;
}
case 0x2101: { //OBSEL
oam.regs.base_size = (data >> 5) & 7;
oam.regs.nameselect = (data >> 3) & 3;
oam.regs.tiledata_addr = (data & 3) << 14;
oam.list_valid = false;
sprite.regs.base_size = (data >> 5) & 7;
sprite.regs.nameselect = (data >> 3) & 3;
sprite.regs.tiledata_addr = (data & 3) << 14;
sprite.list_valid = false;
return;
}
case 0x2102: { //OAMADDL
regs.oam_baseaddr = (regs.oam_baseaddr & 0x0100) | (data << 0);
oam.address_reset();
sprite.address_reset();
return;
}
case 0x2103: { //OAMADDH
regs.oam_priority = data & 0x80;
regs.oam_baseaddr = ((data & 1) << 8) | (regs.oam_baseaddr & 0x00ff);
oam.address_reset();
sprite.address_reset();
return;
}
@@ -319,7 +319,7 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
oam_write((regs.oam_addr & ~1) + 1, data);
}
regs.oam_addr = (regs.oam_addr + 1) & 0x03ff;
oam.set_first();
sprite.set_first();
return;
}
@@ -561,10 +561,10 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
screen.window.two_invert = data & 0x40;
screen.window.one_enable = data & 0x20;
screen.window.one_invert = data & 0x10;
oam.window.two_enable = data & 0x08;
oam.window.two_invert = data & 0x04;
oam.window.one_enable = data & 0x02;
oam.window.one_invert = data & 0x01;
sprite.window.two_enable = data & 0x08;
sprite.window.two_invert = data & 0x04;
sprite.window.one_enable = data & 0x02;
sprite.window.one_invert = data & 0x01;
return;
}
@@ -598,12 +598,12 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
case 0x212b: { //WOBJLOG
screen.window.mask = (data >> 2) & 3;
oam.window.mask = (data >> 0) & 3;
sprite.window.mask = (data >> 0) & 3;
return;
}
case 0x212c: { //TM
oam.regs.main_enable = data & 0x10;
sprite.regs.main_enable = data & 0x10;
bg4.regs.main_enable = data & 0x08;
bg3.regs.main_enable = data & 0x04;
bg2.regs.main_enable = data & 0x02;
@@ -612,7 +612,7 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
}
case 0x212d: { //TS
oam.regs.sub_enable = data & 0x10;
sprite.regs.sub_enable = data & 0x10;
bg4.regs.sub_enable = data & 0x08;
bg3.regs.sub_enable = data & 0x04;
bg2.regs.sub_enable = data & 0x02;
@@ -621,7 +621,7 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
}
case 0x212e: { //TMW
oam.window.main_enable = data & 0x10;
sprite.window.main_enable = data & 0x10;
bg4.window.main_enable = data & 0x08;
bg3.window.main_enable = data & 0x04;
bg2.window.main_enable = data & 0x02;
@@ -630,7 +630,7 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
}
case 0x212f: { //TSW
oam.window.sub_enable = data & 0x10;
sprite.window.sub_enable = data & 0x10;
bg4.window.sub_enable = data & 0x08;
bg3.window.sub_enable = data & 0x04;
bg2.window.sub_enable = data & 0x02;
@@ -671,10 +671,10 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
regs.mode7_extbg = data & 0x40;
regs.pseudo_hires = data & 0x08;
regs.overscan = data & 0x04;
oam.regs.interlace = data & 0x02;
sprite.regs.interlace = data & 0x02;
regs.interlace = data & 0x01;
mmio_update_video_mode();
oam.list_valid = false;
sprite.list_valid = false;
return;
}
}
@@ -695,17 +695,17 @@ void PPU::mmio_reset() {
regs.latch_hcounter = 0;
regs.latch_vcounter = 0;
oam.regs.first_sprite = 0;
oam.list_valid = false;
sprite.regs.first_sprite = 0;
sprite.list_valid = false;
//$2100
regs.display_disable = true;
regs.display_brightness = 0;
//$2101
oam.regs.base_size = 0;
oam.regs.nameselect = 0;
oam.regs.tiledata_addr = 0;
sprite.regs.base_size = 0;
sprite.regs.nameselect = 0;
sprite.regs.tiledata_addr = 0;
//$2102-$2103
regs.oam_baseaddr = 0;
@@ -799,10 +799,10 @@ void PPU::mmio_reset() {
bg4.window.two_enable = 0;
bg4.window.two_invert = 0;
oam.window.one_enable = 0;
oam.window.one_invert = 0;
oam.window.two_enable = 0;
oam.window.two_invert = 0;
sprite.window.one_enable = 0;
sprite.window.one_invert = 0;
sprite.window.two_enable = 0;
sprite.window.two_invert = 0;
screen.window.one_enable = 0;
screen.window.one_invert = 0;
@@ -820,7 +820,7 @@ void PPU::mmio_reset() {
bg2.window.mask = 0;
bg3.window.mask = 0;
bg4.window.mask = 0;
oam.window.mask = 0;
sprite.window.mask = 0;
screen.window.mask = 0;
//$212c
@@ -828,28 +828,28 @@ void PPU::mmio_reset() {
bg2.regs.main_enable = 0;
bg3.regs.main_enable = 0;
bg4.regs.main_enable = 0;
oam.regs.main_enable = 0;
sprite.regs.main_enable = 0;
//$212d
bg1.regs.sub_enable = 0;
bg2.regs.sub_enable = 0;
bg3.regs.sub_enable = 0;
bg4.regs.sub_enable = 0;
oam.regs.sub_enable = 0;
sprite.regs.sub_enable = 0;
//$212e
bg1.window.main_enable = 0;
bg2.window.main_enable = 0;
bg3.window.main_enable = 0;
bg4.window.main_enable = 0;
oam.window.main_enable = 0;
sprite.window.main_enable = 0;
//$212f
bg1.window.sub_enable = 0;
bg2.window.sub_enable = 0;
bg3.window.sub_enable = 0;
bg4.window.sub_enable = 0;
oam.window.sub_enable = 0;
sprite.window.sub_enable = 0;
//$2130
screen.window.main_mask = 0;
@@ -878,12 +878,12 @@ void PPU::mmio_reset() {
regs.mode7_extbg = 0;
regs.pseudo_hires = 0;
regs.overscan = 0;
oam.regs.interlace = 0;
sprite.regs.interlace = 0;
regs.interlace = 0;
//$213e
oam.regs.time_over = 0;
oam.regs.range_over = 0;
sprite.regs.time_over = 0;
sprite.regs.range_over = 0;
mmio_update_video_mode();
}

View File

@@ -1,3 +1,9 @@
public:
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
private:
struct Regs {
//internal
uint8 ppu1_mdr;
@@ -86,6 +92,4 @@ uint8 cgram_read(unsigned addr);
void cgram_write(unsigned addr, uint8 data);
void mmio_update_video_mode();
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
void mmio_reset();

View File

@@ -67,7 +67,7 @@ void PPU::render_scanline() {
bg2.render();
bg3.render();
bg4.render();
oam.render();
sprite.render();
screen.render();
}
@@ -75,21 +75,29 @@ void PPU::scanline() {
display.width = !hires() ? 256 : 512;
display.height = !overscan() ? 225 : 240;
if(vcounter() == 0) frame();
if(vcounter() == display.height && regs.display_disable == false) oam.address_reset();
if(vcounter() == display.height && regs.display_disable == false) sprite.address_reset();
}
void PPU::frame() {
oam.frame();
sprite.frame();
system.frame();
display.interlace = regs.interlace;
display.overscan = regs.overscan;
display.framecounter = display.frameskip == 0 ? 0 : (display.framecounter + 1) % display.frameskip;
}
void PPU::enable() {
function<uint8 (unsigned)> read = { &PPU::mmio_read, (PPU*)&ppu };
function<void (unsigned, uint8)> write = { &PPU::mmio_write, (PPU*)&ppu };
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, read, write);
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, read, write);
}
void PPU::power() {
foreach(n, memory::vram) n = 0;
foreach(n, memory::oam) n = 0;
foreach(n, memory::cgram) n = 0;
foreach(n, vram) n = 0;
foreach(n, oam) n = 0;
foreach(n, cgram) n = 0;
reset();
}
@@ -112,10 +120,10 @@ void PPU::layer_enable(unsigned layer, unsigned priority, bool enable) {
case 9: bg3.priority1_enable = enable; break;
case 12: bg4.priority0_enable = enable; break;
case 13: bg4.priority1_enable = enable; break;
case 16: oam.priority0_enable = enable; break;
case 17: oam.priority1_enable = enable; break;
case 18: oam.priority2_enable = enable; break;
case 19: oam.priority3_enable = enable; break;
case 16: sprite.priority0_enable = enable; break;
case 17: sprite.priority1_enable = enable; break;
case 18: sprite.priority2_enable = enable; break;
case 19: sprite.priority3_enable = enable; break;
}
}
@@ -130,7 +138,7 @@ bg1(*this, Background::ID::BG1),
bg2(*this, Background::ID::BG2),
bg3(*this, Background::ID::BG3),
bg4(*this, Background::ID::BG4),
oam(*this),
sprite(*this),
screen(*this) {
surface = new uint16[512 * 512];
output = surface + 16 * 512;

View File

@@ -1,5 +1,9 @@
class PPU : public Processor, public PPUcounter, public MMIO {
class PPU : public Processor, public PPUcounter {
public:
uint8 vram[64 * 1024];
uint8 oam[544];
uint8 cgram[512];
enum : bool { Threaded = true };
alwaysinline void step(unsigned clocks);
alwaysinline void synchronize_cpu();
@@ -10,6 +14,7 @@ public:
bool hires() const;
void enter();
void enable();
void power();
void reset();
void scanline();
@@ -38,7 +43,7 @@ private:
Background bg2;
Background bg3;
Background bg4;
Sprite oam;
Sprite sprite;
Screen screen;
struct Display {

View File

@@ -2,11 +2,10 @@
unsigned PPU::Screen::get_palette(unsigned color) {
#if defined(ARCH_LSB)
static uint16 *cgram = (uint16*)memory::cgram.data();
return cgram[color];
return ((uint16*)ppu.cgram)[color];
#else
color <<= 1;
return (memory::cgram[color + 0] << 0) + (memory::cgram[color + 1] << 8);
return (ppu.cgram[color + 0] << 0) + (ppu.cgram[color + 1] << 8);
#endif
}

View File

@@ -16,12 +16,16 @@ void PPU::serialize(serializer &s) {
Processor::serialize(s);
PPUcounter::serialize(s);
s.array(vram);
s.array(oam);
s.array(cgram);
cache.serialize(s);
bg1.serialize(s);
bg2.serialize(s);
bg3.serialize(s);
bg4.serialize(s);
oam.serialize(s);
sprite.serialize(s);
screen.serialize(s);
s.integer(display.interlace);

View File

@@ -9,13 +9,6 @@ namespace SNES {
#include "xml.cpp"
#include "serialization.cpp"
namespace memory {
MappedRAM cartrom, cartram, cartrtc;
MappedRAM bsxflash, bsxram, bsxpram;
MappedRAM stArom, stAram;
MappedRAM stBrom, stBram;
};
Cartridge cartridge;
void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
@@ -37,48 +30,25 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
has_msu1 = false;
has_serial = false;
nvram.reset();
parse_xml(xml_list);
//print(xml_list[0], "\n\n");
if(ram_size > 0) {
memory::cartram.map(allocate<uint8_t>(ram_size, 0xff), ram_size);
ram.map(allocate<uint8>(ram_size, 0xff), ram_size);
nvram.append({ "srm", ram.data(), ram.size() });
}
if(has_srtc || has_spc7110rtc) {
memory::cartrtc.map(allocate<uint8_t>(20, 0xff), 20);
}
rom.write_protect(true);
ram.write_protect(false);
if(mode == Mode::Bsx) {
memory::bsxram.map (allocate<uint8_t>( 32 * 1024, 0xff), 32 * 1024);
memory::bsxpram.map(allocate<uint8_t>(512 * 1024, 0xff), 512 * 1024);
}
if(mode == Mode::SufamiTurbo) {
if(memory::stArom.data()) memory::stAram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
if(memory::stBrom.data()) memory::stBram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
}
memory::cartrom.write_protect(true);
memory::cartram.write_protect(false);
memory::cartrtc.write_protect(false);
memory::bsxflash.write_protect(true);
memory::bsxram.write_protect(false);
memory::bsxpram.write_protect(false);
memory::stArom.write_protect(true);
memory::stAram.write_protect(false);
memory::stBrom.write_protect(true);
memory::stBram.write_protect(false);
unsigned checksum = ~0; foreach(n, memory::cartrom ) checksum = crc32_adjust(checksum, n);
if(memory::bsxflash.size() != 0 && memory::bsxflash.size() != ~0) foreach(n, memory::bsxflash) checksum = crc32_adjust(checksum, n);
if(memory::stArom.size() != 0 && memory::stArom.size() != ~0) foreach(n, memory::stArom ) checksum = crc32_adjust(checksum, n);
if(memory::stBrom.size() != 0 && memory::stBrom.size() != ~0) foreach(n, memory::stBrom ) checksum = crc32_adjust(checksum, n);
crc32 = ~checksum;
crc32 = crc32_calculate(rom.data(), rom.size());
sha256_ctx sha;
uint8_t shahash[32];
sha256_init(&sha);
sha256_chunk(&sha, memory::cartrom.data(), memory::cartrom.size());
sha256_chunk(&sha, rom.data(), rom.size());
sha256_final(&sha);
sha256_hash(&sha, shahash);
@@ -86,24 +56,17 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
foreach(n, shahash) hash << hex<2>(n);
sha256 = hash;
bus.load_cart();
system.load();
loaded = true;
}
void Cartridge::unload() {
memory::cartrom.reset();
memory::cartram.reset();
memory::cartrtc.reset();
memory::bsxflash.reset();
memory::bsxram.reset();
memory::bsxpram.reset();
memory::stArom.reset();
memory::stAram.reset();
memory::stBrom.reset();
memory::stBram.reset();
if(loaded == false) return;
bus.unload_cart();
system.unload();
rom.reset();
ram.reset();
loaded = false;
}

View File

@@ -13,6 +13,9 @@ public:
PAL,
};
MappedRAM rom;
MappedRAM ram;
//assigned externally to point to file-system datafiles (msu1 and serial)
//example: "/path/to/filename.sfc" would set this to "/path/to/filename"
readwrite<string> basename;
@@ -39,9 +42,20 @@ public:
readonly<bool> has_msu1;
readonly<bool> has_serial;
struct NonVolatileRAM {
const string id;
uint8_t *data;
unsigned size;
unsigned slot;
NonVolatileRAM() : id(""), data(0), size(0), slot(0) {}
NonVolatileRAM(const string id, uint8_t *data, unsigned size, unsigned slot = 0)
: id(id), data(data), size(size), slot(slot) {}
};
linear_vector<NonVolatileRAM> nvram;
struct Mapping {
Memory *memory;
MMIO *mmio;
function<uint8 (unsigned)> read;
function<void (unsigned, uint8)> write;
Bus::MapMode mode;
unsigned banklo;
unsigned bankhi;
@@ -51,10 +65,10 @@ public:
unsigned size;
Mapping();
Mapping(const function<uint8 (unsigned)>&, const function<void (unsigned, uint8)>&);
Mapping(Memory&);
Mapping(MMIO&);
};
array<Mapping> mapping;
linear_vector<Mapping> mapping;
void load(Mode, const lstring&);
void unload();
@@ -92,11 +106,4 @@ private:
void xml_parse_mode(Mapping&, const string&);
};
namespace memory {
extern MappedRAM cartrom, cartram, cartrtc;
extern MappedRAM bsxflash, bsxram, bsxpram;
extern MappedRAM stArom, stAram;
extern MappedRAM stBrom, stBram;
};
extern Cartridge cartridge;

View File

@@ -1,29 +1,7 @@
#ifdef CARTRIDGE_CPP
void Cartridge::serialize(serializer &s) {
if(memory::cartram.size() != 0 && memory::cartram.size() != ~0) {
s.array(memory::cartram.data(), memory::cartram.size());
}
if(memory::cartrtc.size() != 0 && memory::cartrtc.size() != ~0) {
s.array(memory::cartrtc.data(), memory::cartrtc.size());
}
if(memory::bsxram.size() != 0 && memory::bsxram.size() != ~0) {
s.array(memory::bsxram.data(), memory::bsxram.size());
}
if(memory::bsxpram.size() != 0 && memory::bsxpram.size() != ~0) {
s.array(memory::bsxpram.data(), memory::bsxpram.size());
}
if(memory::stAram.size() != 0 && memory::stAram.size() != ~0) {
s.array(memory::stAram.data(), memory::stAram.size());
}
if(memory::stBram.size() != 0 && memory::stBram.size() != ~0) {
s.array(memory::stBram.data(), memory::stBram.size());
}
if(ram.data()) s.array(ram.data(), ram.size());
}
#endif

View File

@@ -52,6 +52,7 @@ void Cartridge::parse_xml_cartridge(const char *data) {
}
void Cartridge::parse_xml_bsx(const char *data) {
has_bsx_slot = true;
}
void Cartridge::parse_xml_sufami_turbo(const char *data, bool slot) {
@@ -63,13 +64,14 @@ void Cartridge::parse_xml_gameboy(const char *data) {
void Cartridge::xml_parse_rom(xml_element &root) {
foreach(leaf, root.element) {
if(leaf.name == "map") {
Mapping m(memory::cartrom);
Mapping m(rom);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
if(m.size == 0) m.size = rom.size();
mapping.append(m);
}
}
@@ -82,13 +84,14 @@ void Cartridge::xml_parse_ram(xml_element &root) {
foreach(leaf, root.element) {
if(leaf.name == "map") {
Mapping m(memory::cartram);
Mapping m(ram);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
if(m.size == 0) m.size = ram_size;
mapping.append(m);
}
}
@@ -107,7 +110,7 @@ void Cartridge::xml_parse_icd2(xml_element &root) {
foreach(node, root.element) {
if(node.name == "map") {
Mapping m((Memory&)icd2);
Mapping m({ &ICD2::read, &icd2 }, { &ICD2::write, &icd2 });
foreach(attr, node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@@ -123,7 +126,7 @@ void Cartridge::xml_parse_superfx(xml_element &root) {
if(node.name == "rom") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(memory::fxrom);
Mapping m(superfx.rom);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
@@ -140,20 +143,21 @@ void Cartridge::xml_parse_superfx(xml_element &root) {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(memory::fxram);
Mapping m(superfx.ram);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
if(m.size == 0) m.size = ram_size;
mapping.append(m);
}
}
} else if(node.name == "mmio") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(superfx);
Mapping m({ &SuperFX::mmio_read, &superfx }, { &SuperFX::mmio_write, &superfx });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@@ -168,29 +172,44 @@ void Cartridge::xml_parse_sa1(xml_element &root) {
has_sa1 = true;
foreach(node, root.element) {
if(node.name == "rom") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(memory::vsprom);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
if(node.name == "mcu") {
foreach(subnode, node.element) {
if(subnode.name == "rom") {
foreach(leaf, subnode.element) {
if(leaf.name == "map") {
Mapping m({ &SA1::mmc_read, &sa1 }, { &SA1::mmc_write, &sa1 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
mapping.append(m);
}
}
} else if(subnode.name == "ram") {
foreach(leaf, subnode.element) {
if(leaf.name == "map") {
Mapping m({ &SA1::mmc_cpu_read, &sa1 }, { &SA1::mmc_cpu_write, &sa1 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
mapping.append(m);
}
}
} else if(node.name == "iram") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(memory::cpuiram);
Mapping m(sa1.cpuiram);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
if(m.size == 0) m.size = 2048;
mapping.append(m);
}
}
@@ -201,20 +220,21 @@ void Cartridge::xml_parse_sa1(xml_element &root) {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(memory::cc1bwram);
Mapping m(sa1.cpubwram);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
if(m.size == 0) m.size = ram_size;
mapping.append(m);
}
}
} else if(node.name == "mmio") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(sa1);
Mapping m({ &SA1::mmio_read, &sa1 }, { &SA1::mmio_write, &sa1 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@@ -276,33 +296,36 @@ void Cartridge::xml_parse_necdsp(xml_element &root) {
foreach(node, root.element) {
if(node.name == "dr") {
foreach(attr, node.attribute) {
if(attr.name == "mask") necdsp.drmask = hex(attr.content);
if(attr.name == "test") necdsp.drtest = hex(attr.content);
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m({ &NECDSP::dr_read, &necdsp }, { &NECDSP::dr_write, &necdsp });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
if(node.name == "sr") {
foreach(attr, node.attribute) {
if(attr.name == "mask") necdsp.srmask = hex(attr.content);
if(attr.name == "test") necdsp.srtest = hex(attr.content);
} else if(node.name == "sr") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m({ &NECDSP::sr_read, &necdsp }, { &NECDSP::sr_write, &necdsp });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
if(node.name == "dp") {
foreach(attr, node.attribute) {
if(attr.name == "mask") necdsp.dpmask = hex(attr.content);
if(attr.name == "test") necdsp.dptest = hex(attr.content);
} else if(node.name == "dp") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m({ &NECDSP::dp_read, &necdsp }, { &NECDSP::dp_write, &necdsp });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
if(node.name == "map") {
Mapping m(necdsp);
foreach(attr, node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
if(program == "") {
@@ -323,7 +346,7 @@ void Cartridge::xml_parse_bsx(xml_element &root) {
if(node.name == "slot") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(memory::bsxflash);
Mapping m(bsxflash.memory);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
@@ -333,10 +356,20 @@ void Cartridge::xml_parse_bsx(xml_element &root) {
mapping.append(m);
}
}
} else if(node.name == "mcu") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m({ &BSXCartridge::mcu_read, &bsxcartridge }, { &BSXCartridge::mcu_write, &bsxcartridge });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
} else if(node.name == "mmio") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(bsxcart);
Mapping m({ &BSXCartridge::mmio_read, &bsxcartridge }, { &BSXCartridge::mmio_write, &bsxcartridge });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@@ -364,27 +397,29 @@ void Cartridge::xml_parse_sufamiturbo(xml_element &root) {
if(slot.name == "rom") {
foreach(leaf, slot.element) {
if(leaf.name == "map") {
Mapping m(slotid == 0 ? memory::stArom : memory::stBrom);
Memory &memory = slotid == 0 ? sufamiturbo.slotA.rom : sufamiturbo.slotB.rom;
Mapping m(memory);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
if(m.memory->size() > 0) mapping.append(m);
if(memory.size() > 0) mapping.append(m);
}
}
} else if(slot.name == "ram") {
foreach(leaf, slot.element) {
if(leaf.name == "map") {
Mapping m(slotid == 0 ? memory::stAram : memory::stBram);
Memory &memory = slotid == 0 ? sufamiturbo.slotA.ram : sufamiturbo.slotB.ram;
Mapping m(memory);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
if(m.memory->size() > 0) mapping.append(m);
if(memory.size() > 0) mapping.append(m);
}
}
}
@@ -398,7 +433,7 @@ void Cartridge::xml_parse_srtc(xml_element &root) {
foreach(node, root.element) {
if(node.name == "map") {
Mapping m(srtc);
Mapping m({ &SRTC::read, &srtc }, { &SRTC::write, &srtc });
foreach(attr, node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@@ -414,7 +449,7 @@ void Cartridge::xml_parse_sdd1(xml_element &root) {
if(node.name == "mcu") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m((Memory&)sdd1);
Mapping m({ &SDD1::mcu_read, &sdd1 }, { &SDD1::mcu_write, &sdd1 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@@ -424,7 +459,7 @@ void Cartridge::xml_parse_sdd1(xml_element &root) {
} else if(node.name == "mmio") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m((MMIO&)sdd1);
Mapping m({ &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@@ -443,7 +478,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
if(node.name == "dcu") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(spc7110dcu);
Mapping m({ &SPC7110::dcu_read, &spc7110 }, { &SPC7110::dcu_write, &spc7110 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@@ -453,7 +488,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
} else if(node.name == "mcu") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(spc7110mcu);
Mapping m({ &SPC7110::mcu_read, &spc7110 }, { &SPC7110::mcu_write, &spc7110 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "offset") spc7110.data_rom_offset = hex(attr.content);
@@ -464,7 +499,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
} else if(node.name == "mmio") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(spc7110);
Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@@ -478,7 +513,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(spc7110ram);
Mapping m({ &SPC7110::ram_read, &spc7110 }, { &SPC7110::ram_write, &spc7110 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
@@ -493,7 +528,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(spc7110);
Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@@ -509,7 +544,7 @@ void Cartridge::xml_parse_cx4(xml_element &root) {
foreach(node, root.element) {
if(node.name == "map") {
Mapping m(cx4);
Mapping m({ &Cx4::read, &cx4 }, { &Cx4::write, &cx4 });
foreach(attr, node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@@ -523,7 +558,7 @@ void Cartridge::xml_parse_obc1(xml_element &root) {
foreach(node, root.element) {
if(node.name == "map") {
Mapping m(obc1);
Mapping m({ &OBC1::read, &obc1 }, { &OBC1::write, &obc1 });
foreach(attr, node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@@ -533,22 +568,11 @@ void Cartridge::xml_parse_obc1(xml_element &root) {
}
void Cartridge::xml_parse_setarisc(xml_element &root) {
unsigned program = 0;
foreach(attr, root.attribute) {
if(attr.name == "program") {
if(attr.content == "ST-0018") {
program = 1;
has_st0018 = true;
}
}
}
MMIO *map[2] = { 0, &st0018 };
has_st0018 = true;
foreach(node, root.element) {
if(node.name == "map" && map[program]) {
Mapping m(*map[program]);
if(node.name == "map") {
Mapping m({ &ST0018::mmio_read, &st0018 }, { &ST0018::mmio_write, &st0018 });
foreach(attr, node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@@ -561,16 +585,12 @@ void Cartridge::xml_parse_msu1(xml_element &root) {
has_msu1 = true;
foreach(node, root.element) {
if(node.name == "mmio") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(msu1);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
if(node.name == "map") {
Mapping m({ &MSU1::mmio_read, &msu1 }, { &MSU1::mmio_write, &msu1 });
foreach(attr, node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
@@ -611,22 +631,20 @@ void Cartridge::xml_parse_mode(Mapping &m, const string& data) {
}
Cartridge::Mapping::Mapping() {
memory = 0;
mmio = 0;
mode = Bus::MapMode::Direct;
banklo = bankhi = addrlo = addrhi = offset = size = 0;
}
Cartridge::Mapping::Mapping(Memory &memory_) {
memory = &memory_;
mmio = 0;
Cartridge::Mapping::Mapping(Memory &memory) {
read = { &Memory::read, &memory };
write = { &Memory::write, &memory };
mode = Bus::MapMode::Direct;
banklo = bankhi = addrlo = addrhi = offset = size = 0;
}
Cartridge::Mapping::Mapping(MMIO &mmio_) {
memory = 0;
mmio = &mmio_;
Cartridge::Mapping::Mapping(const function<uint8 (unsigned)> &read_, const function<void (unsigned, uint8)> &write_) {
read = read_;
write = write_;
mode = Bus::MapMode::Direct;
banklo = bankhi = addrlo = addrhi = offset = size = 0;
}

View File

@@ -1,2 +0,0 @@
bool Cheat::active() const { return cheat_enabled; }
bool Cheat::exists(unsigned addr) const { return bitmask[addr >> 3] & 1 << (addr & 7); }

View File

@@ -15,7 +15,7 @@ void Cheat::enable(bool state) {
}
void Cheat::synchronize() {
memset(bitmask, 0x00, sizeof bitmask);
memcpy(bus.lookup, lookup, 16 * 1024 * 1024);
code_enabled = false;
for(unsigned i = 0; i < size(); i++) {
@@ -26,16 +26,16 @@ void Cheat::synchronize() {
code_enabled = true;
unsigned addr = mirror(code.addr[n]);
bitmask[addr >> 3] |= 1 << (addr & 7);
bus.lookup[addr] = 0xff;
if((addr & 0xffe000) == 0x7e0000) {
//mirror $7e:0000-1fff to $00-3f|80-bf:0000-1fff
unsigned mirroraddr;
for(unsigned x = 0; x <= 0x3f; x++) {
mirroraddr = ((0x00 + x) << 16) + (addr & 0x1fff);
bitmask[mirroraddr >> 3] |= 1 << (mirroraddr & 7);
bus.lookup[mirroraddr] = 0xff;
mirroraddr = ((0x80 + x) << 16) + (addr & 0x1fff);
bitmask[mirroraddr >> 3] |= 1 << (mirroraddr & 7);
bus.lookup[mirroraddr] = 0xff;
}
}
}
@@ -44,7 +44,7 @@ void Cheat::synchronize() {
cheat_enabled = system_enabled && code_enabled;
}
bool Cheat::read(unsigned addr, uint8 &data) const {
uint8 Cheat::read(unsigned addr) const {
addr = mirror(addr);
for(unsigned i = 0; i < size(); i++) {
@@ -53,20 +53,37 @@ bool Cheat::read(unsigned addr, uint8 &data) const {
for(unsigned n = 0; n < code.addr.size(); n++) {
if(addr == mirror(code.addr[n])) {
data = code.data[n];
return true;
return code.data[n];
}
}
}
return false;
return 0x00;
}
void Cheat::init() {
bus.reader[0xff] = [](unsigned addr) {
bus.reader[cheat.lookup[addr]](bus.target[addr]);
return cheat.read(addr);
};
bus.writer[0xff] = [](unsigned addr, uint8 data) {
return bus.writer[cheat.lookup[addr]](bus.target[addr], data);
};
memcpy(lookup, bus.lookup, 16 * 1024 * 1024);
}
Cheat::Cheat() {
lookup = new uint8[16 * 1024 * 1024];
system_enabled = true;
synchronize();
}
Cheat::~Cheat() {
delete[] lookup;
}
//===============
//encode / decode
//===============

View File

@@ -14,18 +14,17 @@ public:
bool enabled() const;
void enable(bool);
void synchronize();
bool read(unsigned, uint8&) const;
inline bool active() const;
inline bool exists(unsigned addr) const;
uint8 read(unsigned) const;
void init();
Cheat();
~Cheat();
static bool decode(const char*, unsigned&, uint8&, Type&);
static bool encode(string&, unsigned, uint8, Type);
private:
uint8 bitmask[0x200000];
uint8 *lookup;
bool system_enabled;
bool code_enabled;
bool cheat_enabled;

View File

@@ -2,7 +2,7 @@
#define BSX_CPP
namespace SNES {
#include "bsx_base.cpp"
#include "bsx_cart.cpp"
#include "bsx_flash.cpp"
#include "satellaview/satellaview.cpp"
#include "cartridge/cartridge.cpp"
#include "flash/flash.cpp"
}

View File

@@ -1,71 +1,3 @@
class BSXBase : public MMIO {
public:
void init();
void enable();
void power();
void reset();
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
private:
struct {
uint8 r2188, r2189, r218a, r218b;
uint8 r218c, r218d, r218e, r218f;
uint8 r2190, r2191, r2192, r2193;
uint8 r2194, r2195, r2196, r2197;
uint8 r2198, r2199, r219a, r219b;
uint8 r219c, r219d, r219e, r219f;
uint8 r2192_counter;
uint8 r2192_hour, r2192_minute, r2192_second;
} regs;
};
class BSXCart : public MMIO {
public:
void init();
void enable();
void power();
void reset();
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
BSXCart();
~BSXCart();
private:
struct {
uint8 r[16];
} regs;
void update_memory_map();
};
class BSXFlash : public Memory {
public:
void init();
void enable();
void power();
void reset();
unsigned size() const;
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
private:
struct {
unsigned command;
uint8 write_old;
uint8 write_new;
bool flash_enable;
bool read_enable;
bool write_enable;
} regs;
};
extern BSXBase bsxbase;
extern BSXCart bsxcart;
extern BSXFlash bsxflash;
#include "satellaview/satellaview.hpp"
#include "cartridge/cartridge.hpp"
#include "flash/flash.hpp"

View File

@@ -1,96 +0,0 @@
#ifdef BSX_CPP
BSXCart bsxcart;
void BSXCart::init() {
}
void BSXCart::enable() {
}
void BSXCart::power() {
reset();
}
void BSXCart::reset() {
for(unsigned i = 0; i < 16; i++) regs.r[i] = 0x00;
regs.r[0x07] = 0x80;
regs.r[0x08] = 0x80;
update_memory_map();
}
void BSXCart::update_memory_map() {
Memory &cart = (regs.r[0x01] & 0x80) == 0x00 ? (Memory&)bsxflash : (Memory&)memory::bsxpram;
if((regs.r[0x02] & 0x80) == 0x00) {
//LoROM mapping
bus.map(Bus::MapMode::Linear, 0x00, 0x7d, 0x8000, 0xffff, cart);
bus.map(Bus::MapMode::Linear, 0x80, 0xff, 0x8000, 0xffff, cart);
} else {
//HiROM mapping
bus.map(Bus::MapMode::Shadow, 0x00, 0x3f, 0x8000, 0xffff, cart);
bus.map(Bus::MapMode::Linear, 0x40, 0x7d, 0x0000, 0xffff, cart);
bus.map(Bus::MapMode::Shadow, 0x80, 0xbf, 0x8000, 0xffff, cart);
bus.map(Bus::MapMode::Linear, 0xc0, 0xff, 0x0000, 0xffff, cart);
}
if(regs.r[0x03] & 0x80) {
bus.map(Bus::MapMode::Linear, 0x60, 0x6f, 0x0000, 0xffff, memory::bsxpram);
//bus.map(Bus::MapMode::Linear, 0x70, 0x77, 0x0000, 0xffff, memory::bsxpram);
}
if((regs.r[0x05] & 0x80) == 0x00) {
bus.map(Bus::MapMode::Linear, 0x40, 0x4f, 0x0000, 0xffff, memory::bsxpram);
}
if((regs.r[0x06] & 0x80) == 0x00) {
bus.map(Bus::MapMode::Linear, 0x50, 0x5f, 0x0000, 0xffff, memory::bsxpram);
}
if(regs.r[0x07] & 0x80) {
bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom);
}
if(regs.r[0x08] & 0x80) {
bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom);
}
bus.map(Bus::MapMode::Shadow, 0x20, 0x3f, 0x6000, 0x7fff, memory::bsxpram);
bus.map(Bus::MapMode::Linear, 0x70, 0x77, 0x0000, 0xffff, memory::bsxpram);
}
uint8 BSXCart::mmio_read(unsigned addr) {
if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO
uint8 n = (addr >> 16) & 15;
return regs.r[n];
}
if((addr & 0xf8f000) == 0x105000) { //$[10-17]:[5000-5fff] SRAM
return memory::bsxram.read(((addr >> 16) & 7) * 0x1000 + (addr & 0xfff));
}
return 0x00;
}
void BSXCart::mmio_write(unsigned addr, uint8 data) {
if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO
uint8 n = (addr >> 16) & 15;
regs.r[n] = data;
if(n == 0x0e && data & 0x80) update_memory_map();
return;
}
if((addr & 0xf8f000) == 0x105000) { //$[10-17]:[5000-5fff] SRAM
return memory::bsxram.write(((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data);
}
}
BSXCart::BSXCart() {
}
BSXCart::~BSXCart() {
}
#endif

View File

@@ -0,0 +1,149 @@
#ifdef BSX_CPP
BSXCartridge bsxcartridge;
void BSXCartridge::init() {
}
void BSXCartridge::load() {
sram.map(allocate<uint8>(32 * 1024, 0xff), 32 * 1024);
sram.write_protect(false);
cartridge.nvram.append({ "bss", sram.data(), sram.size() });
psram.map(allocate<uint8>(512 * 1024, 0xff), 512 * 1024);
psram.write_protect(false);
cartridge.nvram.append({ "bsp", psram.data(), psram.size() });
}
void BSXCartridge::unload() {
}
void BSXCartridge::power() {
reset();
}
void BSXCartridge::reset() {
for(unsigned i = 0; i < 16; i++) r[i] = 0x00;
r[0x07] = 0x80;
r[0x08] = 0x80;
mmio_commit();
}
uint8 BSXCartridge::memory_access(bool write, Memory &memory, unsigned addr, uint8 data) {
if(write == 0) return memory_read(memory, addr);
memory_write(memory, addr, data);
}
uint8 BSXCartridge::memory_read(Memory &memory, unsigned addr) {
addr = bus.mirror(addr, memory.size());
return memory.read(addr);
}
void BSXCartridge::memory_write(Memory &memory, unsigned addr, uint8 data) {
addr = bus.mirror(addr, memory.size());
return memory.write(addr, data);
}
//mcu_access() allows mcu_read() and mcu_write() to share decoding logic
uint8 BSXCartridge::mcu_access(bool write, unsigned addr, uint8 data) {
if(within<0x00, 0x1f, 0x8000, 0xffff>(addr)) {
if(r07 == 1) {
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff);
return memory_access(write, cartridge.rom, addr, data);
}
}
if(within<0x80, 0x9f, 0x8000, 0xffff>(addr)) {
if(r08 == 1) {
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff);
return memory_access(write, cartridge.rom, addr, data);
}
}
if(within<0x20, 0x3f, 0x6000, 0x7fff>(addr)) {
return memory_access(write, psram, addr, data);
}
if(within<0x40, 0x4f, 0x0000, 0xffff>(addr)) {
if(r05 == 0) return memory_access(write, psram, addr & 0x0fffff, data);
}
if(within<0x50, 0x5f, 0x0000, 0xffff>(addr)) {
if(r06 == 0) return memory_access(write, psram, addr & 0x0fffff, data);
}
if(within<0x60, 0x6f, 0x0000, 0xffff>(addr)) {
if(r03 == 1) return memory_access(write, psram, addr & 0x0fffff, data);
}
if(within<0x70, 0x77, 0x0000, 0xffff>(addr)) {
return memory_access(write, psram, addr & 0x07ffff, data);
}
if(within<0x00, 0x3f, 0x8000, 0xffff>(addr)
|| within<0x40, 0x7f, 0x0000, 0xffff>(addr)
|| within<0x80, 0xbf, 0x8000, 0xffff>(addr)
|| within<0xc0, 0xff, 0x0000, 0xffff>(addr)
) {
if(r02 == 0) addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff);
Memory &memory = (r01 == 0 ? (Memory&)bsxflash : (Memory&)psram);
return memory_access(write, memory, addr & 0x7fffff, data);
}
return cpu.regs.mdr;
}
uint8 BSXCartridge::mcu_read(unsigned addr) {
return mcu_access(0, addr);
}
void BSXCartridge::mcu_write(unsigned addr, uint8 data) {
mcu_access(1, addr, data);
}
uint8 BSXCartridge::mmio_read(unsigned addr) {
if(within<0x00, 0x0f, 0x5000, 0x5000>(addr)) {
uint8 n = (addr >> 16) & 15;
return r[n];
}
if(within<0x10, 0x17, 0x5000, 0x5fff>(addr)) {
return memory_read(sram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff));
}
return 0x00;
}
void BSXCartridge::mmio_write(unsigned addr, uint8 data) {
if(within<0x00, 0x0f, 0x5000, 0x5000>(addr)) {
uint8 n = (addr >> 16) & 15;
r[n] = data;
if(n == 0x0e && data & 0x80) mmio_commit();
return;
}
if(within<0x10, 0x17, 0x5000, 0x5fff>(addr)) {
return memory_write(sram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data);
}
}
void BSXCartridge::mmio_commit() {
r00 = r[0x00] & 0x80;
r01 = r[0x01] & 0x80;
r02 = r[0x02] & 0x80;
r03 = r[0x03] & 0x80;
r04 = r[0x04] & 0x80;
r05 = r[0x05] & 0x80;
r06 = r[0x06] & 0x80;
r07 = r[0x07] & 0x80;
r08 = r[0x08] & 0x80;
r09 = r[0x09] & 0x80;
r0a = r[0x0a] & 0x80;
r0b = r[0x0b] & 0x80;
r0c = r[0x0c] & 0x80;
r0d = r[0x0d] & 0x80;
r0e = r[0x0e] & 0x80;
r0f = r[0x0f] & 0x80;
}
#endif

View File

@@ -0,0 +1,32 @@
class BSXCartridge {
public:
MappedRAM sram;
MappedRAM psram;
void init();
void load();
void unload();
void power();
void reset();
uint8 memory_access(bool write, Memory &memory, unsigned addr, uint8 data);
uint8 memory_read(Memory &memory, unsigned addr);
void memory_write(Memory &memory, unsigned addr, uint8 data);
uint8 mcu_access(bool write, unsigned addr, uint8 data = 0x00);
uint8 mcu_read(unsigned addr);
void mcu_write(unsigned addr, uint8 data);
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
void mmio_commit();
private:
uint8 r[16];
bool r00, r01, r02, r03;
bool r04, r05, r06, r07;
bool r08, r09, r0a, r0b;
bool r0c, r0d, r0e, r0f;
};
extern BSXCartridge bsxcartridge;

View File

@@ -2,8 +2,18 @@
BSXFlash bsxflash;
void BSXFlash::init() {}
void BSXFlash::enable() {}
void BSXFlash::init() {
}
void BSXFlash::load() {
if(memory.size() == 0) {
memory.map(allocate<uint8>(1024 * 1024, 0xff), 1024 * 1024);
}
}
void BSXFlash::unload() {
memory.reset();
}
void BSXFlash::power() {
reset();
@@ -17,11 +27,11 @@ void BSXFlash::reset() {
regs.flash_enable = false;
regs.read_enable = false;
regs.write_enable = false;
memory::bsxflash.write_protect(!regs.write_enable);
memory.write_protect(!regs.write_enable);
}
unsigned BSXFlash::size() const {
return memory::bsxflash.size();
return memory.size();
}
uint8 BSXFlash::read(unsigned addr) {
@@ -48,7 +58,7 @@ uint8 BSXFlash::read(unsigned addr) {
}
}
return memory::bsxflash.read(addr);
return memory.read(addr);
}
void BSXFlash::write(unsigned addr, uint8 data) {
@@ -67,11 +77,11 @@ void BSXFlash::write(unsigned addr, uint8 data) {
regs.write_new = data;
if(regs.write_enable && regs.write_old == regs.write_new) {
return memory::bsxflash.write(addr, data);
return memory.write(addr, data);
}
} else {
if(regs.write_enable) {
return memory::bsxflash.write(addr, data);
return memory.write(addr, data);
}
}
@@ -111,9 +121,8 @@ void BSXFlash::write(unsigned addr, uint8 data) {
regs.write_enable = false;
}
memory::bsxflash.write_protect(!regs.write_enable);
memory.write_protect(!regs.write_enable);
}
}
#endif

View File

@@ -0,0 +1,27 @@
class BSXFlash : public Memory {
public:
MappedRAM memory;
void init();
void load();
void unload();
void power();
void reset();
unsigned size() const;
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
private:
struct {
unsigned command;
uint8 write_old;
uint8 write_new;
bool flash_enable;
bool read_enable;
bool write_enable;
} regs;
};
extern BSXFlash bsxflash;

View File

@@ -1,23 +1,27 @@
#ifdef BSX_CPP
BSXBase bsxbase;
BSXSatellaview bsxsatellaview;
void BSXBase::init() {
void BSXSatellaview::init() {
}
void BSXBase::enable() {
for(uint16 i = 0x2188; i <= 0x219f; i++) memory::mmio.map(i, *this);
void BSXSatellaview::load() {
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2188, 0x219f, { &BSXSatellaview::mmio_read, &bsxsatellaview }, { &BSXSatellaview::mmio_write, &bsxsatellaview });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2188, 0x219f, { &BSXSatellaview::mmio_read, &bsxsatellaview }, { &BSXSatellaview::mmio_write, &bsxsatellaview });
}
void BSXBase::power() {
void BSXSatellaview::unload() {
}
void BSXSatellaview::power() {
reset();
}
void BSXBase::reset() {
void BSXSatellaview::reset() {
memset(&regs, 0x00, sizeof regs);
}
uint8 BSXBase::mmio_read(unsigned addr) {
uint8 BSXSatellaview::mmio_read(unsigned addr) {
addr &= 0xffff;
switch(addr) {
@@ -75,7 +79,7 @@ uint8 BSXBase::mmio_read(unsigned addr) {
return cpu.regs.mdr;
}
void BSXBase::mmio_write(unsigned addr, uint8 data) {
void BSXSatellaview::mmio_write(unsigned addr, uint8 data) {
addr &= 0xffff;
switch(addr) {
@@ -137,4 +141,3 @@ void BSXBase::mmio_write(unsigned addr, uint8 data) {
}
#endif

View File

@@ -0,0 +1,26 @@
class BSXSatellaview {
public:
void init();
void load();
void unload();
void power();
void reset();
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
private:
struct {
uint8 r2188, r2189, r218a, r218b;
uint8 r218c, r218d, r218e, r218f;
uint8 r2190, r2191, r2192, r2193;
uint8 r2194, r2195, r2196, r2197;
uint8 r2198, r2199, r219a, r219b;
uint8 r219c, r219d, r219e, r219f;
uint8 r2192_counter;
uint8 r2192_hour, r2192_minute, r2192_second;
} regs;
};
extern BSXSatellaview bsxsatellaview;

View File

@@ -14,6 +14,7 @@ struct Coprocessor : Processor {
#include <snes/chip/cx4/cx4.hpp>
#include <snes/chip/obc1/obc1.hpp>
#include <snes/chip/st0018/st0018.hpp>
#include <snes/chip/sufamiturbo/sufamiturbo.hpp>
#include <snes/chip/msu1/msu1.hpp>
#include <snes/chip/serial/serial.hpp>

View File

@@ -20,7 +20,10 @@ Cx4 cx4;
void Cx4::init() {
}
void Cx4::enable() {
void Cx4::load() {
}
void Cx4::unload() {
}
uint32 Cx4::ldr(uint8 r) {

View File

@@ -1,7 +1,8 @@
class Cx4 : public Memory {
class Cx4 {
public:
void init();
void enable();
void load();
void unload();
void power();
void reset();

View File

@@ -31,13 +31,14 @@ void ICD2::enter() {
void ICD2::init() {
}
void ICD2::enable() {
mmio[0] = memory::mmio.handle(0x2181);
mmio[1] = memory::mmio.handle(0x2182);
mmio[2] = memory::mmio.handle(0x420b);
memory::mmio.map(0x2181, *this);
memory::mmio.map(0x2182, *this);
memory::mmio.map(0x420b, *this);
void ICD2::load() {
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2181, 0x2182, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x420b, 0x420b, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2181, 0x2182, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x420b, 0x420b, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
}
void ICD2::unload() {
}
void ICD2::power() {

View File

@@ -1,4 +1,4 @@
class ICD2 : public GameBoy::Interface, public Coprocessor, public MMIO, public Memory {
class ICD2 : public GameBoy::Interface, public Coprocessor {
public:
unsigned revision;
@@ -6,10 +6,14 @@ public:
void enter();
void init();
void enable();
void load();
void unload();
void power();
void reset();
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
void serialize(serializer&);
private:

View File

@@ -1,9 +1,9 @@
#ifdef ICD2_CPP
uint8 ICD2::mmio_read(unsigned addr) {
if((uint16)addr == 0x2181) return mmio[0]->mmio_read(addr);
if((uint16)addr == 0x2182) return mmio[1]->mmio_read(addr);
if((uint16)addr == 0x420b) return mmio[2]->mmio_read(addr);
if((uint16)addr == 0x2181) return cpu.mmio_read(addr);
if((uint16)addr == 0x2182) return cpu.mmio_read(addr);
if((uint16)addr == 0x420b) return cpu.mmio_read(addr);
return 0x00;
}
@@ -30,9 +30,9 @@ void ICD2::mmio_write(unsigned addr, uint8 data) {
}
}
if((uint16)addr == 0x2181) return mmio[0]->mmio_write(addr, r2181 = data);
if((uint16)addr == 0x2182) return mmio[1]->mmio_write(addr, r2182 = data);
if((uint16)addr == 0x420b) return mmio[2]->mmio_write(addr, data);
if((uint16)addr == 0x2181) return cpu.mmio_write(addr, r2181 = data);
if((uint16)addr == 0x2182) return cpu.mmio_write(addr, r2182 = data);
if((uint16)addr == 0x420b) return cpu.mmio_write(addr, data);
}
uint8 ICD2::read(unsigned addr) {

View File

@@ -1,6 +1,5 @@
uint8 r2181;
uint8 r2182;
MMIO *mmio[3];
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
@@ -13,7 +12,5 @@ uint8 r6007;
uint8 r7000[16];
unsigned r7800;
uint8 mlt_req;
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
uint8 vram[320];

View File

@@ -48,15 +48,19 @@ void MSU1::enter() {
void MSU1::init() {
}
void MSU1::enable() {
audio.coprocessor_enable(true);
audio.coprocessor_frequency(44100.0);
void MSU1::load() {
if(datafile.open()) datafile.close();
datafile.open(string(cartridge.basename(), ".msu"), file::mode::read);
}
void MSU1::unload() {
if(datafile.open()) datafile.close();
}
void MSU1::power() {
audio.coprocessor_enable(true);
audio.coprocessor_frequency(44100.0);
reset();
}
@@ -129,7 +133,7 @@ void MSU1::mmio_write(unsigned addr, uint8 data) {
if(addr == 0x2005) {
mmio.audio_track = (mmio.audio_track & 0x00ff) | (data << 8);
if(audiofile.open()) audiofile.close();
if(audiofile.open(string(cartridge.basename(), "-", mmio.audio_track, ".pcm"), file::mode::read)) {
if(audiofile.open(string(cartridge.basename(), "-", (unsigned)mmio.audio_track, ".pcm"), file::mode::read)) {
uint32 header = audiofile.readm(4);
if(header != 0x4d535531) { //verify 'MSU1' header
audiofile.close();

View File

@@ -1,9 +1,10 @@
class MSU1 : public Coprocessor, public MMIO {
class MSU1 : public Coprocessor {
public:
static void Enter();
void enter();
void init();
void enable();
void load();
void unload();
void power();
void reset();

View File

@@ -21,7 +21,7 @@ void MSU1::serialize(serializer &s) {
}
if(audiofile.open()) audiofile.close();
if(audiofile.open(string(cartridge.basename(), "-", mmio.audio_track, ".pcm"), file::mode::read)) {
if(audiofile.open(string(cartridge.basename(), "-", (unsigned)mmio.audio_track, ".pcm"), file::mode::read)) {
audiofile.seek(mmio.audio_offset);
}
}

Some files were not shown because too many files have changed in this diff Show More