Compare commits

..
22 Commits
Author SHA1 Message Date
byuu 7dec0b2a3c Update to bsnes v014 release.
This version adds speed regulation, greatly improves PPU rendering, and increases speed by ~30% over the previous version.
Changelog:
    - Rewrote offset-per-tile mode emulation, should be correct now. Fixes Chrono Trigger, Contra III, Tetris Attack, etc.
    - Fixed a bug with HDMA occuring during interrupts. Fixes Tales of Phantasia souond test screen
    - Updated compiler to Visual Studio 2005, and enabled profile guided optimizations
    - Added conditional compilation of debugging functions (faster without them)
    - Added conditional compilation of core classes as pointers (allowing polymorphism) or objects (allowing inlining). The latter results in a speed increase
    - Small fixes to BG and OAM rendering routines
    - Corrected sprite tile bounds wrapping
    - Corrected sprite rendering in hires video modes
    - Rewrote color add/sub routines, should be correct now. Fixes Illusion of Gaia menu, etc.
    - Optimized video blitting routines, will temporarilly break mixed video mode screenshots
    - Prevented selecting menu options via return key from being recognized as keypresses by the emulator
    - Added system speed regulation (60hz/NTSC or 50hz/PAL)! Many thanks to kode54, GIGO, and Richard Bannister for their assistance
I disabled the debugger and polymorphism, and enabled profile guided optimizations for this build, to maximize speed. The debugger and polymorphism can be re-enabled via uncommenting the respective #defines in src/base.h and recompiling, or bsnes v0.013 can be used. I may start releasing two separate builds in the future... not sure yet.
2005-11-12 16:49:26 +00:00
byuu f288280ceb Update to bsnes v013r02 release.
[No changelog available]
2005-10-25 23:25:28 +00:00
byuu c6c5f4669c Update to bsnes v013 release.
- Greatly improved HDMA timing and accuracy with help from anomie and DMV27 -- fixes bugs in Energy Breaker and Street Fighter Alpha 2
    - Fixed a problem with color add/sub code -- fixes opening battle in Tales of Phantasia and clouds in Energy Breaker
    - Temporarily added DMV27's bugfix for the DSP KON register -- fixes sound in Der Langrisser, but this is not a hardware-accurate fix
    - Disabled VRAM writes outside of vblank -- fixes Hook, but breaks many PD ROMs and fan translations (Roto's BS Zelda hack, Gideon Zhi's Ys 4 translation, etc). I might add an option in the future to toggle this behavior, but for now these games will no longer work. Please keep in mind these games will not run properly on real SNES hardware, either.
    - Improved frameskipping code thanks to a suggestion from Richard Bannister
    - Misc. other code cleanups and improvements (notably in the color table generation code)
    - bsnes is now endian-safe and runs on Mac OS X
    - Added caching support for window clipping tables resulting in a slight speedup. Please let me know if you spot any errors as a result of this change.
2005-10-23 23:32:30 +00:00
byuu 397b9c4505 Update to bsnes v012 release.
Changelog:
    - Added S-DSP emulation
    - Added sound output support via DirectSound -- no sound buffering though, so sound is muted by default
    - Added option to record raw sound output to WAV files
    - Added multiple color adjustment filters to the video output
    - Added mode3/4 direct color support
    - Added mode7 direct color and mosaic support
    - Greatly improved mode7 rendering algorithm thanks to anomie
    - Fixed mode7 screen repitition and EXTBG effects
    - Greatly increased accuracy of NMI and IRQ timing, and emulated many newly discovered hardware quirks involving the two
    - A few speed improvements courtesy of Nach for profiling the code for me
I'm now looking for assistance with sound buffering. Specifically, I need help modifying the DirectSound code to allow the emulator to be ran between 50%-400% normal speed, while keeping the sound output relatively good. If you have experience with this and can help, please get in touch with me (setsunakun0 at hotmail dot com).
2005-10-02 00:38:34 +00:00
byuu 7e2cfb6d40 Update to bsnes v011 release.
- Fixed Mode 0 color palette index problem. Fixes ToP, DQ5, etc.
    - Improved LoROM memory mapper to support 32mbit images. Fixes Tokimeki Memorial, etc.
    - Added full S-DD1 support, SFA2 and Star Ocean are now playable. Special thanks to Andreas Naive
    - Updated BGnxOFS / Mode7 registers with anomie's latest findings
    - Added basic ROM mirroring support. Fixes copy protection issues in MMX, etc.
    - Rewrote string library to work better on gcc/linux
    - Cleaned up S-RTC/S-DD1 emulation to make way for future add-on chip emulation
    - Rewrote DMA code, now runs cycle-by-cycle
    - Rewrote HDMA code, now allows HDMA to be enabled mid-frame, fixes many games
    - Fixed a bug in Mode7 vertical screen flip mode. Fixes FF5 title screen, etc.
    - Greatly improved IRQ triggering. Fixes Der Langrisser, etc.
    - Added full support for open bus. This includes PPU1 and PPU2 open bus support
    - Modified CPU core back to cycle-based system. Slower, but improves debugger
    - Implemented temporary fix for debugger to handle new cycle-based cores
    - Modified CGRAM to ignore highest bit, since it is not used at all by the SNES, and is impossible to read on real hardware. Lowers memory usage by ~1.2mb
    - Added mostly accurate PAL timing support. This should increase compatibility by ~30% or so
    - More stuff I'm forgetting at the moment...
2005-08-26 20:38:00 +00:00
byuu 970dcea0ac Update to bsnes v010 release.
bsnes now supports SPC700 emulation (no DSP or sound support, however), and has greatly improved compatibility. It also now contains a keyboard-only joypad configuration tool.
2005-08-03 21:22:42 +00:00
byuu 402c146a53 Update to bsnes v009 release.
- Fixed non-interlaced display modes from not drawing every other frame
    - Changed OAM halve to skip every other scanline in 224-height modes
    - Updated renderer to properly support games that switch resolutions mid-frame
    - Fixed VRAM address remapping modes, fixes DQ3R, FF: MQ
    - Fixed a bug in main color window clipping affecting BGs
    - Added video color curve option, thanks to Overload for the idea + color table
    - Added vblank, FPS counter, and DDraw surface memory options to settings menu
    - Added fullscreen modes 640x480 and 1024x768 to video modes
    - Added option to toggle the menubar on and off by pressing the escape key
    - Mode3 was not rendering sprites
    - Priorities were wrong for modes 2-4, thanks to anomie for info
    - Fixed a serious bug in IRQ interrupts. May not be perfect, but helps many games
2005-06-26 11:07:38 +00:00
byuu a471c150c9 Update to bsnes v008 release.
moving the window + main color window clipping into the bg/oam/mode7 rendering routines themselves, I was able to greatly simplify the most complicated part of rendering: the final pass where color add/sub effects are applied. As a result, the new PPU core is not only ~35% faster (on graphics intensive screens, even faster on simpler screens), but more accurate as well. Awesome.
In celebration, I´m releasing bsnes v0.008. I can actually run all games I have at >60fps on my Athlon 1.67ghz PC. Probably not something to brag about, though ...
Oh, and I also updated the keyboard polling code to only capture keypresses if the main window has focus. I´ve been meaning to do this for the better part of a year now, but never got around to it.
If, for some reason, you still want to use the old renderer, you can uncomment the first line in src/ppu/bppu/bppu.h and recompile the emulator yourself. Or you can use v0.007a, I´ll leave it up for a bit.
2005-06-21 09:13:40 +00:00
byuu ea38ea2537 Update to bsnes v007a release.
[No changelog available]
2005-06-13 04:34:10 +00:00
byuu 09b326ae86 Update to bsnes v007 release.
I have done quite a bit, so I´ll try my best to recap most of the fixes since the last release...
    - HDMA was not running during DMA transfers
    - Emulator did not recognize any filetype other than .smc
    - Added configuration file support and imported my vector/string/config libraries into bsnes
    - Added option to use system RAM instead of video RAM for display, this can greatly increase speed on certain video cards
    - Increased speed by ~15% by adding 256x224 renderer (still very buggy when the SNES mixes video modes mid-frame)
    - mvn/mvp opcodes were not setting the DB register
    - Fixed joypad input in many games (Super Mario: All Stars, Dragon Quest III, etc.)
    - Major speedup with frakeskip option
    - Fixed default aspect ratio when emulator is first started
There´s probably a lot more, but that´s all I remember offhand... this release should be a lot closer to the quality of v0.005a, but still needs a bit more polishing.
2005-06-12 08:15:22 +00:00
byuu a60f667b25 Update to bsnes v006 release.
The rewrite is now complete. I finished adding frameskip, and fixed some crashing issues with loading multiple ROMs. I wrapped all malloc/free calls with memalloc/memfree, which are custom functions that log each call, and let you pass sprintf-style arguments to them to debug memory leaks. Don´t see any, nor have I noticed any in bsnes; but it makes a nice test tool anyway.
I found out today that the mvn/mvp instructions actually set the DB register to the destination bank. Weird. This fixed Final Fantasy V, Chrono Trigger, and Dragon Quest III (which now runs as a result) graphics. Not all of them, but quite a few. I had also previously been setting the M/X flags of the P register when xce was executed. I never anticipated a game using xce while in native mode to switch to... native mode... but apparently, Chrono Trigger does. And my code was incorrect. So now Chrono Trigger gets past the name select screen, but dies a few screens after still.
The only really major flaw I am aware of that bsnes v0.005 did not have is with the battle screens in Squaresoft games. I get horrible flickering and "crushed scanlines" every other frame on them, for some reason. I´ll try and track that down for the next release, but I didn´t want to hold up a new release any longer. As a result, I´ll leave up v0.005a for the time being until I get this problem fixed.
2005-05-13 12:03:02 +00:00
byuu 6f7cf1bd31 Update to bsnes v005a release.
[No changelog available]
2005-02-06 04:04:32 +00:00
byuu 8751bc433f Update to bsnes v005 release.
Released a new version of bsnes today. Version 0.0.005 is up on the main page now.
The changes since .004 wip10 include: DRAM timing fix (now occurs mid-opcode), memory address speed fix, added CPU cycle condition 4 to all opcodes that use it, and fixed a bug where DRAM refresh was not changing start positions every other scanline.
With the new version, Chrono Trigger should get a little further, and Final Fantasy 5 should get in-game now. The only problem FF5 seems to have is sprite corrution in the menus. I´m too busy with the CPU timing to mess around with the PPU right now, though. Also, the APU is not bridged to the CPU in this release, so compatibility is (still) really low.
After I get the APU working fairly well, I´ll (try and) start keeping a what´s new file so that people can know what all changed between public releases of the emulator without having to follow this page. Sorry for the inconvenience in the mean time.

[No archive available]
2005-02-05 00:00:00 +00:00
byuu afbee40bc0 Update to bsnes v004 release.
[No changelog available]

[No archive available]
2004-12-24 00:00:00 +00:00
byuu 81e9be64d2 Update to bsnes v003r01 release.
[No changelog available]

[No archive available]
2004-12-13 00:00:00 +00:00
byuu 0cd4972d11 Update to bsnes v002 ir11 release.
Doubled the width of sprites when the width of the screen is 512. The SNES Test Program now runs through all of the character test correctly. The windows are off-by-one though.
Added the very bizarre 00:4300-00:437f memory region that is unique from 7e:4300-7e:437f. Then I added read support from $2180. This allowed the SNES Test Program to not crash after failing the electronics test, and it also fixed the horrible graphics corruption in Der Langrisser.
The fonts were still failing, so I went in with my tracer and found out what was causing it. The following code:
	gx816->regs.pc += (signed char)(arg + 2);
This is the code used to increment the pc counter after relative branches. The problem is that I had parinthesis around the + 2 as well as arg. Therefore, if arg was 0x7e, 0x7f, 0xfe, or 0xff, it would change the sign. This would in turn make the program counter off by 256 bytes. Very bad. Fixing this fixed the font in Der Langrisser, and also fixed Super Mario World, when Yoshi spits a turtle out, the game will no longer crash.
Next, via the Der Langrisser world map, I realized that anomie´s description of the BG/mode7 register latches was reversed: the BG registers (may) share a common latch between all of them, but the mode7 registers do not. I removed the common latches from the mode7 regs, but I haven´t added the latch to the BG registers yet.
I also realized that clearing the entire screen on a BG mode change would probably not be a good thing for games that change video modes mid-frame. So I tried working on getting the weird single-frame garble that pops up every minute or so to go away, but to no avail. I´m having a difficult time tracking down the exact cause of the error, but I believe it to be a buffer overflow, or something along those lines.

[No archive available]
2004-12-11 00:00:00 +00:00
byuu 938609818f Update to bsnes v002 ir9 release.
[No changelog available]
2004-12-07 01:12:32 +00:00
byuu 487491e6f2 Update to bsnes v002 ir7 release.
The bug in the Bahamut Lagoon mode7 screens turned out to be that I never added the dividend result to $4216/$4217. It always returned the multiplication of $4202/$4203. This also fixed the sprites in battles for Dai Kaijuu Monogatari. I added a bunch of window stuff, including a double size windowed mode, and a fullscreen mode. Lots of fixes to the interface, as well as code cleanup. It's still pretty buggy, there's a lot of variables to keep up with in the GUI at present...
I also added better tile caching, I just cache all tiles when they are rendered, for all 3 color depths (4, 16, 256). Seems to help a little. A portion of the speed gain was lost by fixing the dividend result, though. Very strange, since I wouldn't think much work would go into a simple line of code that's called 20 times a frame probably at best... oh well.

[No archive available]
2004-12-05 00:00:00 +00:00
byuu a6ccc7e5d2 Update to unreleased version.
First, I fixed some issues with the mode7 / scroll regs thanks to info from anomie. Qwertie's mode7 demo runs without modification now. Next, I fixed a small glitch with tiles getting cut off on the right edge of the screen, fixes some flickering on the edges in Zelda 3. Finally, I added tile caching to all 4 BG layers. It didn't really increase speed by much (~10%), and upped the RAM requirements by 1.2mb... I left the old code in case I need to fall back on it. My only guess (hope) is that the bottleneck lies somewhere else...

[No archive available]
2004-12-04 00:00:00 +00:00
byuu 39dd39cc09 Update to unreleased version.
Had a small glitch in the OAM $2102/$2103 register settings, fixed that and now both Zelda 3 and Super Mario World always show sprites perfectly. The only error to my knowledge in the below screenshots is that the large version of the mario sprite in the third pic is not shown at the top left of the screen. Which could be because I have no mosaic support. But at any rate, both games should be completely playable now, albeit very slowly. I tried to speed up things by caching some stuff in the PPU, but I couldn't find a nice way to implement it that would result in a significant speed increase. Oh yeah, Zelda won't follow you in Zelda 3, but you can just go to the throne room and push the picture to the right yourself, and she'll appear when you reach the sanctuary.
I also updated the debugger, it uses a smaller font, which is a bit harder to read, but saves a lot of screen space. This will definately be needed when I add in more of the debugging windows in the future, so it's better to get used to it now than later.

[No archive available]
2004-11-27 00:00:00 +00:00
byuu 1a017ff697 Update to unreleased version.
Added SRAM support. It's compatible with other emulators. It maps both the LoROM SRAM between $700000-$7dffff, and HiROM SRAM between $3n6000-$3n7fff (where n = 0 - f).
Modified the screen to redraw at scanline 224, instead of 0. Fixes some flickering between screens in some games.
Moved the lighting adjustment code ($2100 bits 0-3) directly into the PPU, rather than outside in the platform-specific code. This is because games have the ability to adjust this value per scanline. Also allowed the games to control the background enable ($2100 bit 7) flag per scanline now. This allowed Bahamut Lagoon's dragon intro to work.
I then added mode2 support, so now all that's missing is modes 5 and 6 (interlaced).
I also created an easy #define to select between the public domain mode7 code I wrote, and the snes9x mode7 code. I'll go through one of these days and rewrite the snes9x code in a clean environment (e.g. without using the current mode7 file as a reference) to avoid the issue altogether, but for now... the snes9x code is twice as fast, and that's good enough for me.
Lastly, I also added in a trace checkbox to enable tracing. As such, the zip file of my work up now has debug mode enabled by default. I really need an overhaul of the gui implementation, and a configuration file. I have a very nice string library system (that I wrote myself) that I would love to take advantage of in this project.
Here's some screenshots of the dragon intro. Lots of HDMA here, showing that I pretty much have HDMA down, now. I remember zsnes used to have a problem with these screens, and had to do something with an HDMA hack to get around it. They figured out what the problem was, eventually. I was actually quite surprised my emulator does not suffer from this same problem. Lucky for me, as they never did mention what the problem was to begin with. The HDMA is technically drawing too soon (at the start of the scanline instead of the end) which probably messes things up a bit, and I'm guessing the scroll registers are screwing up in one or two of the below pics. No mosaic support either.

[No archive available]
2004-11-21 00:00:00 +00:00
byuu 591adfcb25 Update to unreleased version.
Initial release

[No archive available]
2004-10-14 00:00:00 +00:00
1267 changed files with 30957 additions and 202330 deletions

No files matched your search

+139
View File
@@ -0,0 +1,139 @@
# Applies contrast adjust filter to video output when enabled
# Works by lowering the brightness of darker colors,
# while leaving brighter colors alone; thus reducing saturation
# (default = true)
snes.video_color_curve = true
# Selects color adjustment filter for video output
# 0 = Normal (no filter, rgb555)
# 1 = Grayscale mode (l5)
# 2 = VGA mode (rgb332)
# 3 = Genesis mode (rgb333)
# (default = 0)
snes.video_color_adjust_mode = 0
# Mutes SNES audio output when enabled
# (default = true)
snes.mute = false
# Regulate speed to 60hz (NTSC) / 50hz (PAL)
# (default = true)
system.regulate_speed = true
# Video mode
# 0 = 256x224w
# 1 = 512x448w
# 2 = 960x720w
# 3 = 640x480f
# 4 = 1024x768f
# (default = 1)
video.mode = 1
# Use Video RAM instead of System RAM
# (default = true)
video.use_vram = true
# Wait for vertical retrace when updating screen
# (default = false)
video.vblank = false
# Show framerate in window title
# (default = true)
gui.show_fps = true
# Joypad1 up
# (default = 0x26)
input.joypad1.up = 0x26
# Joypad1 down
# (default = 0x28)
input.joypad1.down = 0x28
# Joypad1 left
# (default = 0x25)
input.joypad1.left = 0x25
# Joypad1 right
# (default = 0x27)
input.joypad1.right = 0x27
# Joypad1 A
# (default = 0x58)
input.joypad1.a = 0x58
# Joypad1 B
# (default = 0x5a)
input.joypad1.b = 0x5a
# Joypad1 X
# (default = 0x53)
input.joypad1.x = 0x53
# Joypad1 Y
# (default = 0x41)
input.joypad1.y = 0x41
# Joypad1 L
# (default = 0x44)
input.joypad1.l = 0x44
# Joypad1 R
# (default = 0x43)
input.joypad1.r = 0x43
# Joypad1 select
# (default = 0x10)
input.joypad1.select = 0x10
# Joypad1 start
# (default = 0xd)
input.joypad1.start = 0xd
# Joypad2 up
# (default = 0x54)
input.joypad2.up = 0x54
# Joypad2 down
# (default = 0x47)
input.joypad2.down = 0x47
# Joypad2 left
# (default = 0x46)
input.joypad2.left = 0x46
# Joypad2 right
# (default = 0x48)
input.joypad2.right = 0x48
# Joypad2 A
# (default = 0x4b)
input.joypad2.a = 0x4b
# Joypad2 B
# (default = 0x4a)
input.joypad2.b = 0x4a
# Joypad2 X
# (default = 0x49)
input.joypad2.x = 0x49
# Joypad2 Y
# (default = 0x55)
input.joypad2.y = 0x55
# Joypad2 L
# (default = 0x4f)
input.joypad2.l = 0x4f
# Joypad2 R
# (default = 0x4c)
input.joypad2.r = 0x4c
# Joypad2 select
# (default = 0x5b)
input.joypad2.select = 0x5b
# Joypad2 start
# (default = 0x5d)
input.joypad2.start = 0x5d
BIN
View File
Binary file not shown.
-82
View File
@@ -1,82 +0,0 @@
include nall/Makefile
nes := nes
snes := snes
gameboy := gameboy
profile := accuracy
ui := ui
# options += console
# options += debugger
# compiler
c := $(compiler) -std=gnu99
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
flags := -O3 -fomit-frame-pointer -I.
link :=
objects := libco
# profile-guided optimization mode
# pgo := instrument
# pgo := optimize
ifeq ($(pgo),instrument)
flags += -fprofile-generate
link += -lgcov
else ifeq ($(pgo),optimize)
flags += -fprofile-use
endif
# platform
ifeq ($(platform),x)
# tree vectorization causes code generation errors with Linux/GCC 4.6.1
flags += -fno-tree-vectorize
link += -s -ldl -lX11 -lXext
else ifeq ($(platform),osx)
else ifeq ($(platform),win)
link += $(if $(findstring console,$(options)),-mconsole,-mwindows)
link += -mthreads -s -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 -lole32
link += -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc
else
unknown_platform: help;
endif
flags := $(flags) $(foreach o,$(call strupper,$(options)),-D$o)
# implicit rules
compile = \
$(strip \
$(if $(filter %.c,$<), \
$(c) $(flags) $1 -c $< -o $@, \
$(if $(filter %.cpp,$<), \
$(cpp) $(flags) $1 -c $< -o $@ \
) \
) \
)
%.o: $<; $(call compile)
all: build;
obj/libco.o: libco/libco.c libco/*
include $(ui)/Makefile
# targets
clean:
-@$(call delete,obj/*.o)
-@$(call delete,obj/*.a)
-@$(call delete,obj/*.so)
-@$(call delete,obj/*.dylib)
-@$(call delete,obj/*.dll)
-@$(call delete,*.res)
-@$(call delete,*.pgd)
-@$(call delete,*.pgc)
-@$(call delete,*.ilk)
-@$(call delete,*.pdb)
-@$(call delete,*.manifest)
archive-all:
tar -cjf bsnes.tar.bz2 data gameboy libco nall nes obj out phoenix ruby snes ui ui-libsnes Makefile cc.bat clean.bat sync.sh
help:;
-2
View File
@@ -1,2 +0,0 @@
@mingw32-make -j 8
@pause
-1
View File
@@ -1 +0,0 @@
@mingw32-make clean
-9
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="*"/>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
</dependentAssembly>
</dependency>
</assembly>
-8
View File
@@ -1,8 +0,0 @@
[Desktop Entry]
Name=bsnes
Comment=SNES emulator
Exec=bsnes
Icon=bsnes
Terminal=false
Type=Application
Categories=Game;Emulator;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

-79635
View File
File diff suppressed because it is too large. Load diff
-15
View File
@@ -1,15 +0,0 @@
gameboy_objects := gameboy-interface gameboy-system gameboy-scheduler
gameboy_objects += gameboy-memory gameboy-cartridge
gameboy_objects += gameboy-cpu gameboy-apu gameboy-lcd
gameboy_objects += gameboy-cheat
objects += $(gameboy_objects)
obj/gameboy-interface.o: $(gameboy)/interface/interface.cpp $(call rwildcard,$(gameboy)/interface/)
obj/gameboy-system.o: $(gameboy)/system/system.cpp $(call rwildcard,$(gameboy)/system/)
obj/gameboy-scheduler.o: $(gameboy)/scheduler/scheduler.cpp $(call rwildcard,$(gameboy)/scheduler/)
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/)
obj/gameboy-cheat.o: $(gameboy)/cheat/cheat.cpp $(call rwildcard,$(gameboy)/cheat/)
-105
View File
@@ -1,105 +0,0 @@
#include <gameboy/gameboy.hpp>
#define APU_CPP
namespace GameBoy {
#include "square1/square1.cpp"
#include "square2/square2.cpp"
#include "wave/wave.cpp"
#include "noise/noise.cpp"
#include "master/master.cpp"
#include "serialization.cpp"
APU apu;
void APU::Main() {
apu.main();
}
void APU::main() {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
if(sequencer_base == 0) { //512hz
if(sequencer_step == 0 || sequencer_step == 2 || sequencer_step == 4 || sequencer_step == 6) { //256hz
square1.clock_length();
square2.clock_length();
wave.clock_length();
noise.clock_length();
}
if(sequencer_step == 2 || sequencer_step == 6) { //128hz
square1.clock_sweep();
}
if(sequencer_step == 7) { //64hz
square1.clock_envelope();
square2.clock_envelope();
noise.clock_envelope();
}
sequencer_step++;
}
sequencer_base++;
square1.run();
square2.run();
wave.run();
noise.run();
master.run();
interface->audioSample(master.center, master.left, master.right);
if(++clock >= 0) co_switch(scheduler.active_thread = cpu.thread);
}
}
void APU::power() {
create(Main, 4194304);
for(unsigned n = 0xff10; n <= 0xff3f; n++) bus.mmio[n] = this;
for(auto &n : mmio_data) n = 0x00;
sequencer_base = 0;
sequencer_step = 0;
square1.power();
square2.power();
wave.power();
noise.power();
master.power();
}
uint8 APU::mmio_read(uint16 addr) {
static const uint8 table[48] = {
0x80, 0x3f, 0x00, 0xff, 0xbf, //square1
0xff, 0x3f, 0x00, 0xff, 0xbf, //square2
0x7f, 0xff, 0x9f, 0xff, 0xbf, //wave
0xff, 0xff, 0x00, 0x00, 0xbf, //noise
0x00, 0x00, 0x70, //master
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //unmapped
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //wave pattern
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //wave pattern
};
if(addr == 0xff26) {
uint8 data = master.enable << 7;
if(square1.enable) data |= 0x01;
if(square2.enable) data |= 0x02;
if( wave.enable) data |= 0x04;
if( noise.enable) data |= 0x08;
return data | table[addr - 0xff10];
}
if(addr >= 0xff10 && addr <= 0xff3f) return mmio_data[addr - 0xff10] | table[addr - 0xff10];
return 0xff;
}
void APU::mmio_write(uint16 addr, uint8 data) {
if(addr >= 0xff10 && addr <= 0xff3f) mmio_data[addr - 0xff10] = data;
if(addr >= 0xff10 && addr <= 0xff14) return square1.write (addr - 0xff10, data);
if(addr >= 0xff15 && addr <= 0xff19) return square2.write (addr - 0xff15, data);
if(addr >= 0xff1a && addr <= 0xff1e) return wave.write (addr - 0xff1a, data);
if(addr >= 0xff1f && addr <= 0xff23) return noise.write (addr - 0xff1f, data);
if(addr >= 0xff24 && addr <= 0xff26) return master.write (addr - 0xff24, data);
if(addr >= 0xff30 && addr <= 0xff3f) return wave.write_pattern(addr - 0xff30, data);
}
}
-28
View File
@@ -1,28 +0,0 @@
struct APU : Processor, MMIO {
#include "square1/square1.hpp"
#include "square2/square2.hpp"
#include "wave/wave.hpp"
#include "noise/noise.hpp"
#include "master/master.hpp"
uint8 mmio_data[48];
uint13 sequencer_base;
uint3 sequencer_step;
Square1 square1;
Square2 square2;
Wave wave;
Noise noise;
Master master;
static void Main();
void main();
void power();
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
void serialize(serializer&);
};
extern APU apu;
-129
View File
@@ -1,129 +0,0 @@
#ifdef APU_CPP
void APU::Master::run() {
static int16_t volume[] = {
-16384, -14336, -12288, -10240, -8192, -6144, -4096, -2048,
+2048, +4096, +6144, +8192, +10240, +12288, +14336, +16384,
};
if(enable == false) {
center = 0;
left = 0;
right = 0;
return;
}
signed sample = 0, channels;
sample += apu.square1.output;
sample += apu.square2.output;
sample += apu.wave.output;
sample += apu.noise.output;
sample >>= 2;
center = volume[sample];
sample = 0;
channels = 0;
if(channel1_left_enable) { sample += apu.square1.output; channels++; }
if(channel2_left_enable) { sample += apu.square2.output; channels++; }
if(channel3_left_enable) { sample += apu.wave.output; channels++; }
if(channel4_left_enable) { sample += apu.noise.output; channels++; }
if(channels) sample /= channels;
left = volume[sample];
switch(left_volume) {
case 0: left >>= 3; break; // 12.5%
case 1: left >>= 2; break; // 25.0%
case 2: left = (left >> 2) + (left >> 3); break; // 37.5%
case 3: left >>= 1; break; // 50.0%
case 4: left = (left >> 1) + (left >> 3); break; // 62.5%
case 5: left -= (left >> 2); break; // 75.0%
case 6: left -= (left >> 3); break; // 87.5%
//case 7: break; //100.0%
}
sample = 0;
channels = 0;
if(channel1_right_enable) { sample += apu.square1.output; channels++; }
if(channel2_right_enable) { sample += apu.square2.output; channels++; }
if(channel3_right_enable) { sample += apu.wave.output; channels++; }
if(channel4_right_enable) { sample += apu.noise.output; channels++; }
if(channels) sample /= channels;
right = volume[sample];
switch(right_volume) {
case 0: right >>= 3; break; // 12.5%
case 1: right >>= 2; break; // 25.0%
case 2: right = (right >> 2) + (right >> 3); break; // 37.5%
case 3: right >>= 1; break; // 50.0%
case 4: right = (right >> 1) + (right >> 3); break; // 62.5%
case 5: right -= (right >> 2); break; // 75.0%
case 6: right -= (right >> 3); break; // 87.5%
//case 7: break; //100.0%
}
}
void APU::Master::write(unsigned r, uint8 data) {
if(r == 0) { //$ff24 NR50
left_in_enable = data & 0x80;
left_volume = (data >> 4) & 7;
right_in_enable = data & 0x08;
right_volume = (data >> 0) & 7;
}
if(r == 1) { //$ff25 NR51
channel4_left_enable = data & 0x80;
channel3_left_enable = data & 0x40;
channel2_left_enable = data & 0x20;
channel1_left_enable = data & 0x10;
channel4_right_enable = data & 0x08;
channel3_right_enable = data & 0x04;
channel2_right_enable = data & 0x02;
channel1_right_enable = data & 0x01;
}
if(r == 2) { //$ff26 NR52
enable = data & 0x80;
}
}
void APU::Master::power() {
left_in_enable = 0;
left_volume = 0;
right_in_enable = 0;
right_volume = 0;
channel4_left_enable = 0;
channel3_left_enable = 0;
channel2_left_enable = 0;
channel1_left_enable = 0;
channel4_right_enable = 0;
channel3_right_enable = 0;
channel2_right_enable = 0;
channel1_right_enable = 0;
enable = 0;
center = 0;
left = 0;
right = 0;
}
void APU::Master::serialize(serializer &s) {
s.integer(left_in_enable);
s.integer(left_volume);
s.integer(right_in_enable);
s.integer(right_volume);
s.integer(channel4_left_enable);
s.integer(channel3_left_enable);
s.integer(channel2_left_enable);
s.integer(channel1_left_enable);
s.integer(channel4_right_enable);
s.integer(channel3_right_enable);
s.integer(channel2_right_enable);
s.integer(channel1_right_enable);
s.integer(enable);
s.integer(center);
s.integer(left);
s.integer(right);
}
#endif
-24
View File
@@ -1,24 +0,0 @@
struct Master {
bool left_in_enable;
uint3 left_volume;
bool right_in_enable;
uint3 right_volume;
bool channel4_left_enable;
bool channel3_left_enable;
bool channel2_left_enable;
bool channel1_left_enable;
bool channel4_right_enable;
bool channel3_right_enable;
bool channel2_right_enable;
bool channel1_right_enable;
bool enable;
int16 center;
int16 left;
int16 right;
void run();
void write(unsigned r, uint8 data);
void power();
void serialize(serializer&);
};
-108
View File
@@ -1,108 +0,0 @@
#ifdef APU_CPP
bool APU::Noise::dac_enable() {
return (envelope_volume || envelope_direction);
}
void APU::Noise::run() {
if(period && --period == 0) {
period = divisor << frequency;
if(frequency < 14) {
bool bit = (lfsr ^ (lfsr >> 1)) & 1;
lfsr = (lfsr >> 1) ^ (bit << (narrow_lfsr ? 6 : 14));
}
}
uint4 sample = (lfsr & 1) ? (uint4)0 : volume;
if(enable == false) sample = 0;
output = sample;
}
void APU::Noise::clock_length() {
if(counter && length) {
if(--length == 0) enable = false;
}
}
void APU::Noise::clock_envelope() {
if(enable && envelope_frequency && --envelope_period == 0) {
envelope_period = envelope_frequency;
if(envelope_direction == 0 && volume > 0) volume--;
if(envelope_direction == 1 && volume < 15) volume++;
}
}
void APU::Noise::write(unsigned r, uint8 data) {
if(r == 1) { //$ff20 NR41
length = 64 - (data & 0x3f);
}
if(r == 2) { //$ff21 NR42
envelope_volume = data >> 4;
envelope_direction = data & 0x08;
envelope_frequency = data & 0x07;
if(dac_enable() == false) enable = false;
}
if(r == 3) { //$ff22 NR43
frequency = data >> 4;
narrow_lfsr = data & 0x08;
divisor = (data & 0x07) << 4;
if(divisor == 0) divisor = 8;
period = divisor << frequency;
}
if(r == 4) { //$ff34 NR44
bool initialize = data & 0x80;
counter = data & 0x40;
if(initialize) {
enable = dac_enable();
lfsr = ~0U;
envelope_period = envelope_frequency;
volume = envelope_volume;
if(length == 0) length = 64;
}
}
}
void APU::Noise::power() {
enable = 0;
envelope_volume = 0;
envelope_direction = 0;
envelope_frequency = 0;
frequency = 0;
narrow_lfsr = 0;
divisor = 0;
counter = 0;
output = 0;
length = 0;
envelope_period = 0;
volume = 0;
period = 0;
lfsr = 0;
}
void APU::Noise::serialize(serializer &s) {
s.integer(enable);
s.integer(envelope_volume);
s.integer(envelope_direction);
s.integer(envelope_frequency);
s.integer(frequency);
s.integer(narrow_lfsr);
s.integer(divisor);
s.integer(counter);
s.integer(output);
s.integer(length);
s.integer(envelope_period);
s.integer(volume);
s.integer(period);
s.integer(lfsr);
}
#endif
-27
View File
@@ -1,27 +0,0 @@
struct Noise {
bool enable;
uint4 envelope_volume;
bool envelope_direction;
uint3 envelope_frequency;
uint4 frequency;
bool narrow_lfsr;
unsigned divisor;
bool counter;
int16 output;
unsigned length;
uint3 envelope_period;
uint4 volume;
unsigned period;
uint15 lfsr;
bool dac_enable();
void run();
void clock_length();
void clock_envelope();
void write(unsigned r, uint8 data);
void power();
void serialize(serializer&);
};
-15
View File
@@ -1,15 +0,0 @@
#ifdef APU_CPP
void APU::serialize(serializer &s) {
s.array(mmio_data);
s.integer(sequencer_base);
s.integer(sequencer_step);
square1.serialize(s);
square2.serialize(s);
wave.serialize(s);
noise.serialize(s);
master.serialize(s);
}
#endif
-160
View File
@@ -1,160 +0,0 @@
#ifdef APU_CPP
bool APU::Square1::dac_enable() {
return (envelope_volume || envelope_direction);
}
void APU::Square1::run() {
if(period && --period == 0) {
period = 4 * (2048 - frequency);
phase++;
switch(duty) {
case 0: duty_output = (phase == 6); break; //______-_
case 1: duty_output = (phase >= 6); break; //______--
case 2: duty_output = (phase >= 4); break; //____----
case 3: duty_output = (phase <= 5); break; //------__
}
}
uint4 sample = (duty_output ? volume : (uint4)0);
if(enable == false) sample = 0;
output = sample;
}
void APU::Square1::sweep(bool update) {
if(sweep_enable == false) return;
sweep_negate = sweep_direction;
unsigned delta = frequency_shadow >> sweep_shift;
signed freq = frequency_shadow + (sweep_negate ? -delta : delta);
if(freq > 2047) {
enable = false;
} else if(sweep_shift && update) {
frequency_shadow = freq;
frequency = freq & 2047;
period = 4 * (2048 - frequency);
}
}
void APU::Square1::clock_length() {
if(counter && length) {
if(--length == 0) enable = false;
}
}
void APU::Square1::clock_sweep() {
if(enable && sweep_frequency && --sweep_period == 0) {
sweep_period = sweep_frequency;
sweep(1);
sweep(0);
}
}
void APU::Square1::clock_envelope() {
if(enable && envelope_frequency && --envelope_period == 0) {
envelope_period = envelope_frequency;
if(envelope_direction == 0 && volume > 0) volume--;
if(envelope_direction == 1 && volume < 15) volume++;
}
}
void APU::Square1::write(unsigned r, uint8 data) {
if(r == 0) { //$ff10 NR10
if(sweep_negate && sweep_direction && !(data & 0x08)) enable = false;
sweep_frequency = (data >> 4) & 7;
sweep_direction = data & 0x08;
sweep_shift = data & 0x07;
}
if(r == 1) { //$ff11 NR11
duty = data >> 6;
length = 64 - (data & 0x3f);
}
if(r == 2) { //$ff12 NR12
envelope_volume = data >> 4;
envelope_direction = data & 0x08;
envelope_frequency = data & 0x07;
if(dac_enable() == false) enable = false;
}
if(r == 3) { //$ff13 NR13
frequency = (frequency & 0x0700) | data;
}
if(r == 4) { //$ff14 NR14
bool initialize = data & 0x80;
counter = data & 0x40;
frequency = ((data & 7) << 8) | (frequency & 0x00ff);
if(initialize) {
enable = dac_enable();
envelope_period = envelope_frequency;
volume = envelope_volume;
frequency_shadow = frequency;
sweep_period = sweep_frequency;
sweep_enable = sweep_period || sweep_shift;
sweep_negate = false;
if(sweep_shift) sweep(0);
if(length == 0) length = 64;
}
}
period = 4 * (2048 - frequency);
}
void APU::Square1::power() {
enable = 0;
sweep_frequency = 0;
sweep_direction = 0;
sweep_shift = 0;
sweep_negate = 0;
duty = 0;
length = 0;
envelope_volume = 0;
envelope_direction = 0;
envelope_frequency = 0;
frequency = 0;
counter = 0;
output = 0;
duty_output = 0;
phase = 0;
period = 0;
envelope_period = 0;
sweep_period = 0;
frequency_shadow = 0;
sweep_enable = 0;
volume = 0;
}
void APU::Square1::serialize(serializer &s) {
s.integer(enable);
s.integer(sweep_frequency);
s.integer(sweep_direction);
s.integer(sweep_shift);
s.integer(sweep_negate);
s.integer(duty);
s.integer(length);
s.integer(envelope_volume);
s.integer(envelope_direction);
s.integer(envelope_frequency);
s.integer(frequency);
s.integer(counter);
s.integer(output);
s.integer(duty_output);
s.integer(phase);
s.integer(period);
s.integer(envelope_period);
s.integer(sweep_period);
s.integer(frequency_shadow);
s.integer(sweep_enable);
s.integer(volume);
}
#endif
-36
View File
@@ -1,36 +0,0 @@
struct Square1 {
bool enable;
uint3 sweep_frequency;
bool sweep_direction;
uint3 sweep_shift;
bool sweep_negate;
uint2 duty;
unsigned length;
uint4 envelope_volume;
bool envelope_direction;
uint3 envelope_frequency;
uint11 frequency;
bool counter;
int16 output;
bool duty_output;
uint3 phase;
unsigned period;
uint3 envelope_period;
uint3 sweep_period;
signed frequency_shadow;
bool sweep_enable;
uint4 volume;
bool dac_enable();
void run();
void sweep(bool update);
void clock_length();
void clock_sweep();
void clock_envelope();
void write(unsigned r, uint8 data);
void power();
void serialize(serializer&);
};
-110
View File
@@ -1,110 +0,0 @@
#ifdef APU_CPP
bool APU::Square2::dac_enable() {
return (envelope_volume || envelope_direction);
}
void APU::Square2::run() {
if(period && --period == 0) {
period = 4 * (2048 - frequency);
phase++;
switch(duty) {
case 0: duty_output = (phase == 6); break; //______-_
case 1: duty_output = (phase >= 6); break; //______--
case 2: duty_output = (phase >= 4); break; //____----
case 3: duty_output = (phase <= 5); break; //------__
}
}
uint4 sample = (duty_output ? volume : (uint4)0);
if(enable == false) sample = 0;
output = sample;
}
void APU::Square2::clock_length() {
if(counter && length) {
if(--length == 0) enable = false;
}
}
void APU::Square2::clock_envelope() {
if(enable && envelope_frequency && --envelope_period == 0) {
envelope_period = envelope_frequency;
if(envelope_direction == 0 && volume > 0) volume--;
if(envelope_direction == 1 && volume < 15) volume++;
}
}
void APU::Square2::write(unsigned r, uint8 data) {
if(r == 1) { //$ff16 NR21
duty = data >> 6;
length = 64 - (data & 0x3f);
}
if(r == 2) { //$ff17 NR22
envelope_volume = data >> 4;
envelope_direction = data & 0x08;
envelope_frequency = data & 0x07;
if(dac_enable() == false) enable = false;
}
if(r == 3) { //$ff18 NR23
frequency = (frequency & 0x0700) | data;
}
if(r == 4) { //$ff19 NR24
bool initialize = data & 0x80;
counter = data & 0x40;
frequency = ((data & 7) << 8) | (frequency & 0x00ff);
if(initialize) {
enable = dac_enable();
envelope_period = envelope_frequency;
volume = envelope_volume;
if(length == 0) length = 64;
}
}
period = 4 * (2048 - frequency);
}
void APU::Square2::power() {
enable = 0;
duty = 0;
length = 0;
envelope_volume = 0;
envelope_direction = 0;
envelope_frequency = 0;
frequency = 0;
counter = 0;
output = 0;
duty_output = 0;
phase = 0;
period = 0;
envelope_period = 0;
volume = 0;
}
void APU::Square2::serialize(serializer &s) {
s.integer(enable);
s.integer(duty);
s.integer(length);
s.integer(envelope_volume);
s.integer(envelope_direction);
s.integer(envelope_frequency);
s.integer(frequency);
s.integer(counter);
s.integer(output);
s.integer(duty_output);
s.integer(phase);
s.integer(period);
s.integer(envelope_period);
s.integer(volume);
}
#endif
-27
View File
@@ -1,27 +0,0 @@
struct Square2 {
bool enable;
uint2 duty;
unsigned length;
uint4 envelope_volume;
bool envelope_direction;
uint3 envelope_frequency;
uint11 frequency;
bool counter;
int16 output;
bool duty_output;
uint3 phase;
unsigned period;
uint3 envelope_period;
uint4 volume;
bool dac_enable();
void run();
void clock_length();
void clock_envelope();
void write(unsigned r, uint8 data);
void power();
void serialize(serializer&);
};
-99
View File
@@ -1,99 +0,0 @@
#ifdef APU_CPP
void APU::Wave::run() {
if(period && --period == 0) {
period = 2 * (2048 - frequency);
pattern_sample = pattern[++pattern_offset];
}
uint4 sample = pattern_sample >> volume_shift;
if(enable == false) sample = 0;
output = sample;
}
void APU::Wave::clock_length() {
if(counter && length) {
if(--length == 0) enable = false;
}
}
void APU::Wave::write(unsigned r, uint8 data) {
if(r == 0) { //$ff1a NR30
dac_enable = data & 0x80;
if(dac_enable == false) enable = false;
}
if(r == 1) { //$ff1b NR31
length = 256 - data;
}
if(r == 2) { //$ff1c NR32
switch((data >> 5) & 3) {
case 0: volume_shift = 4; break; // 0%
case 1: volume_shift = 0; break; //100%
case 2: volume_shift = 1; break; // 50%
case 3: volume_shift = 2; break; // 25%
}
}
if(r == 3) { //$ff1d NR33
frequency = (frequency & 0x0700) | data;
}
if(r == 4) { //$ff1e NR34
bool initialize = data & 0x80;
counter = data & 0x40;
frequency = ((data & 7) << 8) | (frequency & 0x00ff);
if(initialize) {
enable = dac_enable;
pattern_offset = 0;
if(length == 0) length = 256;
}
}
period = 2 * (2048 - frequency);
}
void APU::Wave::write_pattern(unsigned p, uint8 data) {
p <<= 1;
pattern[p + 0] = (data >> 4) & 15;
pattern[p + 1] = (data >> 0) & 15;
}
void APU::Wave::power() {
enable = 0;
dac_enable = 0;
volume_shift = 0;
frequency = 0;
counter = 0;
random_lfsr r;
for(auto &n : pattern) n = r() & 15;
output = 0;
length = 0;
period = 0;
pattern_offset = 0;
pattern_sample = 0;
}
void APU::Wave::serialize(serializer &s) {
s.integer(enable);
s.integer(dac_enable);
s.integer(volume_shift);
s.integer(frequency);
s.integer(counter);
s.array(pattern);
s.integer(output);
s.integer(length);
s.integer(period);
s.integer(pattern_offset);
s.integer(pattern_sample);
}
#endif
-22
View File
@@ -1,22 +0,0 @@
struct Wave {
bool enable;
bool dac_enable;
unsigned volume_shift;
uint11 frequency;
bool counter;
uint8 pattern[32];
int16 output;
unsigned length;
unsigned period;
uint5 pattern_offset;
uint4 pattern_sample;
void run();
void clock_length();
void write(unsigned r, uint8 data);
void write_pattern(unsigned p, uint8 data);
void power();
void serialize(serializer&);
};
-140
View File
@@ -1,140 +0,0 @@
#include <gameboy/gameboy.hpp>
#include <nall/crc32.hpp>
#define CARTRIDGE_CPP
namespace GameBoy {
#include "mbc0/mbc0.cpp"
#include "mbc1/mbc1.cpp"
#include "mbc2/mbc2.cpp"
#include "mbc3/mbc3.cpp"
#include "mbc5/mbc5.cpp"
#include "mmm01/mmm01.cpp"
#include "huc1/huc1.cpp"
#include "huc3/huc3.cpp"
#include "serialization.cpp"
Cartridge cartridge;
void Cartridge::load(const string &markup, 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");
info.mapper = Mapper::Unknown;
info.ram = false;
info.battery = false;
info.rtc = false;
info.rumble = false;
info.romsize = 0;
info.ramsize = 0;
BML::Document document(markup);
auto &mapperid = document["cartridge"]["mapper"].value;
if(mapperid == "none" ) info.mapper = Mapper::MBC0;
if(mapperid == "MBC1" ) info.mapper = Mapper::MBC1;
if(mapperid == "MBC2" ) info.mapper = Mapper::MBC2;
if(mapperid == "MBC3" ) info.mapper = Mapper::MBC3;
if(mapperid == "MBC5" ) info.mapper = Mapper::MBC5;
if(mapperid == "MMM01") info.mapper = Mapper::MMM01;
if(mapperid == "HuC1" ) info.mapper = Mapper::HuC1;
if(mapperid == "HuC3" ) info.mapper = Mapper::HuC3;
info.rtc = document["cartridge"]["rtc"].exists();
info.rumble = document["cartridge"]["rumble"].exists();
info.romsize = hex(document["cartridge"]["rom"]["size"].value);
info.ramsize = hex(document["cartridge"]["ram"]["size"].value);
info.battery = document["cartridge"]["ram"]["non-volatile"].exists();
switch(info.mapper) { default:
case Mapper::MBC0: mapper = &mbc0; break;
case Mapper::MBC1: mapper = &mbc1; break;
case Mapper::MBC2: mapper = &mbc2; break;
case Mapper::MBC3: mapper = &mbc3; break;
case Mapper::MBC5: mapper = &mbc5; break;
case Mapper::MMM01: mapper = &mmm01; break;
case Mapper::HuC1: mapper = &huc1; break;
case Mapper::HuC3: mapper = &huc3; break;
}
ramdata = new uint8_t[ramsize = info.ramsize]();
system.load();
loaded = true;
sha256 = nall::sha256(romdata, romsize);
}
void Cartridge::unload() {
if(loaded == false) return;
if(romdata) { delete[] romdata; romdata = 0; }
if(ramdata) { delete[] ramdata; ramdata = 0; }
loaded = false;
}
uint8 Cartridge::rom_read(unsigned addr) {
if(addr >= romsize) addr %= romsize;
return romdata[addr];
}
void Cartridge::rom_write(unsigned addr, uint8 data) {
if(addr >= romsize) addr %= romsize;
romdata[addr] = data;
}
uint8 Cartridge::ram_read(unsigned addr) {
if(ramsize == 0) return 0x00;
if(addr >= ramsize) addr %= ramsize;
return ramdata[addr];
}
void Cartridge::ram_write(unsigned addr, uint8 data) {
if(ramsize == 0) return;
if(addr >= ramsize) addr %= ramsize;
ramdata[addr] = data;
}
uint8 Cartridge::mmio_read(uint16 addr) {
if(bootrom_enable && within<0x0000, 0x00ff>(addr)) return System::BootROM::sgb[addr];
return mapper->mmio_read(addr);
}
void Cartridge::mmio_write(uint16 addr, uint8 data) {
if(bootrom_enable && addr == 0xff50) bootrom_enable = false;
mapper->mmio_write(addr, data);
}
void Cartridge::power() {
bootrom_enable = true;
mbc0.power();
mbc1.power();
mbc2.power();
mbc3.power();
mbc5.power();
mmm01.power();
huc1.power();
huc3.power();
for(unsigned n = 0x0000; n <= 0x7fff; n++) bus.mmio[n] = this;
for(unsigned n = 0xa000; n <= 0xbfff; n++) bus.mmio[n] = this;
bus.mmio[0xff50] = this;
}
Cartridge::Cartridge() {
loaded = false;
romdata = 0;
ramdata = 0;
}
Cartridge::~Cartridge() {
unload();
}
}
-66
View File
@@ -1,66 +0,0 @@
struct Cartridge : MMIO, property<Cartridge> {
#include "mbc0/mbc0.hpp"
#include "mbc1/mbc1.hpp"
#include "mbc2/mbc2.hpp"
#include "mbc3/mbc3.hpp"
#include "mbc5/mbc5.hpp"
#include "mmm01/mmm01.hpp"
#include "huc1/huc1.hpp"
#include "huc3/huc3.hpp"
enum Mapper : unsigned {
MBC0,
MBC1,
MBC2,
MBC3,
MBC5,
MMM01,
HuC1,
HuC3,
Unknown,
};
struct Information {
string xml;
Mapper mapper;
bool ram;
bool battery;
bool rtc;
bool rumble;
unsigned romsize;
unsigned ramsize;
} info;
readonly<bool> loaded;
readonly<string> sha256;
uint8_t *romdata;
unsigned romsize;
uint8_t *ramdata;
unsigned ramsize;
MMIO *mapper;
bool bootrom_enable;
void load(const string &markup, const uint8_t *data, unsigned size);
void unload();
uint8 rom_read(unsigned addr);
void rom_write(unsigned addr, uint8 data);
uint8 ram_read(unsigned addr);
void ram_write(unsigned addr, uint8 data);
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
void power();
void serialize(serializer&);
Cartridge();
~Cartridge();
};
extern Cartridge cartridge;
-53
View File
@@ -1,53 +0,0 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::HuC1::mmio_read(uint16 addr) {
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(addr);
}
if(within<0x4000, 0x7fff>(addr)) {
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
return 0x00;
}
return 0x00;
}
void Cartridge::HuC1::mmio_write(uint16 addr, uint8 data) {
if(within<0x0000, 0x1fff>(addr)) {
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if(within<0x2000, 0x3fff>(addr)) {
rom_select = data;
return;
}
if(within<0x4000, 0x5fff>(addr)) {
ram_select = data;
return;
}
if(within<0x6000, 0x7fff>(addr)) {
//unknown purpose
return;
}
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
return;
}
}
void Cartridge::HuC1::power() {
ram_enable = false;
rom_select = 0x01;
ram_select = 0x00;
}
#endif
-9
View File
@@ -1,9 +0,0 @@
struct HuC1 : MMIO {
bool ram_enable; //0000-1fff
uint8 rom_select; //2000-3fff
uint8 ram_select; //4000-5fff
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
void power();
} huc1;
-53
View File
@@ -1,53 +0,0 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::HuC3::mmio_read(uint16 addr) {
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(addr);
}
if(within<0x4000, 0x7fff>(addr)) {
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
return 0x00;
}
return 0x00;
}
void Cartridge::HuC3::mmio_write(uint16 addr, uint8 data) {
if(within<0x0000, 0x1fff>(addr)) {
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if(within<0x2000, 0x3fff>(addr)) {
rom_select = data;
return;
}
if(within<0x4000, 0x5fff>(addr)) {
ram_select = data;
return;
}
if(within<0x6000, 0x7fff>(addr)) {
//unknown purpose
return;
}
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
return;
}
}
void Cartridge::HuC3::power() {
ram_enable = false;
rom_select = 0x01;
ram_select = 0x00;
}
#endif
-9
View File
@@ -1,9 +0,0 @@
struct HuC3 : MMIO {
bool ram_enable; //0000-1fff
uint8 rom_select; //2000-3fff
uint8 ram_select; //4000-5fff
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
void power();
} huc3;
-25
View File
@@ -1,25 +0,0 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC0::mmio_read(uint16 addr) {
if(within<0x0000, 0x7fff>(addr)) {
return cartridge.rom_read(addr);
}
if(within<0xa000, 0xbfff>(addr)) {
return cartridge.ram_read(addr & 0x1fff);
}
return 0x00;
}
void Cartridge::MBC0::mmio_write(uint16 addr, uint8 data) {
if(within<0xa000, 0xbfff>(addr)) {
cartridge.ram_write(addr & 0x1fff, data);
return;
}
}
void Cartridge::MBC0::power() {
}
#endif
-5
View File
@@ -1,5 +0,0 @@
struct MBC0 : MMIO {
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
void power();
} mbc0;
-70
View File
@@ -1,70 +0,0 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC1::mmio_read(uint16 addr) {
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(addr);
}
if(within<0x4000, 0x7fff>(addr)) {
if(mode_select == 0) {
return cartridge.rom_read((ram_select << 19) | (rom_select << 14) | (addr & 0x3fff));
} else {
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
}
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) {
if(mode_select == 0) {
return cartridge.ram_read(addr & 0x1fff);
} else {
return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
}
}
return 0x00;
}
return 0x00;
}
void Cartridge::MBC1::mmio_write(uint16 addr, uint8 data) {
if(within<0x0000, 0x1fff>(addr)) {
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if(within<0x2000, 0x3fff>(addr)) {
rom_select = (data & 0x1f) + ((data & 0x1f) == 0);
return;
}
if(within<0x4000, 0x5fff>(addr)) {
ram_select = data & 0x03;
return;
}
if(within<0x6000, 0x7fff>(addr)) {
mode_select = data & 0x01;
return;
}
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) {
if(mode_select == 0) {
cartridge.ram_write(addr & 0x1fff, data);
} else {
cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
}
}
return;
}
}
void Cartridge::MBC1::power() {
ram_enable = false;
rom_select = 0x01;
ram_select = 0x00;
mode_select = 0;
}
#endif
-10
View File
@@ -1,10 +0,0 @@
struct MBC1 : MMIO {
bool ram_enable; //0000-1fff
uint8 rom_select; //2000-3fff
uint8 ram_select; //4000-5fff
bool mode_select; //6000-7fff
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
void power();
} mbc1;
-42
View File
@@ -1,42 +0,0 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC2::mmio_read(uint16 addr) {
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(addr);
}
if(within<0x4000, 0x7fff>(addr)) {
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if(within<0xa000, 0xa1ff>(addr)) {
if(ram_enable) return cartridge.ram_read(addr & 0x1ff);
return 0x00;
}
return 0x00;
}
void Cartridge::MBC2::mmio_write(uint16 addr, uint8 data) {
if(within<0x0000, 0x1fff>(addr)) {
if(!(addr & 0x0100)) ram_enable = (data & 0x0f) == 0x0a;
return;
}
if(within<0x2000, 0x3fff>(addr)) {
if( (addr & 0x0100)) rom_select = (data & 0x0f) + ((data & 0x0f) == 0);
return;
}
if(within<0xa000, 0xa1ff>(addr)) {
if(ram_enable) cartridge.ram_write(addr & 0x1ff, data & 0x0f);
return;
}
}
void Cartridge::MBC2::power() {
ram_enable = false;
rom_select = 0x01;
}
#endif
-8
View File
@@ -1,8 +0,0 @@
struct MBC2 : MMIO {
bool ram_enable; //0000-1fff
uint8 rom_select; //2000-3fff
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
void power();
} mbc2;
-120
View File
@@ -1,120 +0,0 @@
#ifdef CARTRIDGE_CPP
void Cartridge::MBC3::second() {
if(rtc_halt == false) {
if(++rtc_second >= 60) {
rtc_second = 0;
if(++rtc_minute >= 60) {
rtc_minute = 0;
if(++rtc_hour >= 24) {
rtc_hour = 0;
if(++rtc_day >= 512) {
rtc_day = 0;
rtc_day_carry = true;
}
}
}
}
}
}
uint8 Cartridge::MBC3::mmio_read(uint16 addr) {
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(addr);
}
if(within<0x4000, 0x7fff>(addr)) {
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) {
if(ram_select >= 0x00 && ram_select <= 0x03) {
return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
}
if(ram_select == 0x08) return rtc_latch_second;
if(ram_select == 0x09) return rtc_latch_minute;
if(ram_select == 0x0a) return rtc_latch_hour;
if(ram_select == 0x0b) return rtc_latch_day;
if(ram_select == 0x0c) return (rtc_latch_day_carry << 7) | (rtc_latch_day >> 8);
}
return 0x00;
}
return 0x00;
}
void Cartridge::MBC3::mmio_write(uint16 addr, uint8 data) {
if(within<0x0000, 0x1fff>(addr)) {
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if(within<0x2000, 0x3fff>(addr)) {
rom_select = (data & 0x7f) + ((data & 0x7f) == 0);
return;
}
if(within<0x4000, 0x5fff>(addr)) {
ram_select = data;
return;
}
if(within<0x6000, 0x7fff>(addr)) {
if(rtc_latch == 0 && data == 1) {
rtc_latch_second = rtc_second;
rtc_latch_minute = rtc_minute;
rtc_latch_hour = rtc_hour;
rtc_latch_day = rtc_day;
rtc_latch_day_carry = rtc_day_carry;
}
rtc_latch = data;
return;
}
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) {
if(ram_select >= 0x00 && ram_select <= 0x03) {
cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
} else if(ram_select == 0x08) {
if(data >= 60) data = 0;
rtc_second = data;
} else if(ram_select == 0x09) {
if(data >= 60) data = 0;
rtc_minute = data;
} else if(ram_select == 0x0a) {
if(data >= 24) data = 0;
rtc_hour = data;
} else if(ram_select == 0x0b) {
rtc_day = (rtc_day & 0x0100) | data;
} else if(ram_select == 0x0c) {
rtc_day = ((data & 1) << 8) | (rtc_day & 0xff);
rtc_halt = data & 0x40;
rtc_day_carry = data & 0x80;
}
}
return;
}
}
void Cartridge::MBC3::power() {
ram_enable = false;
rom_select = 0x01;
ram_select = 0x00;
rtc_latch = 0;
rtc_halt = true;
rtc_second = 0;
rtc_minute = 0;
rtc_hour = 0;
rtc_day = 0;
rtc_day_carry = false;
rtc_latch_second = 0;
rtc_latch_minute = 0;
rtc_latch_hour = 0;
rtc_latch_day = 0;
rtc_latch_day_carry = false;
}
#endif
-24
View File
@@ -1,24 +0,0 @@
struct MBC3 : MMIO {
bool ram_enable; //0000-1fff
uint8 rom_select; //2000-3fff
uint8 ram_select; //4000-5fff
bool rtc_latch; //6000-7fff
bool rtc_halt;
unsigned rtc_second;
unsigned rtc_minute;
unsigned rtc_hour;
unsigned rtc_day;
bool rtc_day_carry;
unsigned rtc_latch_second;
unsigned rtc_latch_minute;
unsigned rtc_latch_hour;
unsigned rtc_latch_day;
unsigned rtc_latch_day_carry;
void second();
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
void power();
} mbc3;
-53
View File
@@ -1,53 +0,0 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC5::mmio_read(uint16 addr) {
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(addr);
}
if(within<0x4000, 0x7fff>(addr)) {
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
return 0x00;
}
return 0x00;
}
void Cartridge::MBC5::mmio_write(uint16 addr, uint8 data) {
if(within<0x0000, 0x1fff>(addr)) {
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if(within<0x2000, 0x2fff>(addr)) {
rom_select = (rom_select & 0x0100) | data;
return;
}
if(within<0x3000, 0x3fff>(addr)) {
rom_select = ((data & 1) << 8) | (rom_select & 0x00ff);
return;
}
if(within<0x4000, 0x5fff>(addr)) {
ram_select = data & 0x0f;
return;
}
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
return;
}
}
void Cartridge::MBC5::power() {
ram_enable = false;
rom_select = 0x001;
ram_select = 0x00;
}
#endif
-9
View File
@@ -1,9 +0,0 @@
struct MBC5 : MMIO {
bool ram_enable; //0000-1fff
uint16 rom_select; //2000-2fff + 3000-3fff
uint8 ram_select; //4000-5fff
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
void power();
} mbc5;
-65
View File
@@ -1,65 +0,0 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MMM01::mmio_read(uint16 addr) {
if(within<0x0000, 0x7fff>(addr)) {
if(rom_mode == 0) return cartridge.rom_read(addr);
}
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(0x8000 + (rom_base << 14) + (addr & 0x3fff));
}
if(within<0x4000, 0x7fff>(addr)) {
return cartridge.rom_read(0x8000 + (rom_base << 14) + (rom_select << 14) + (addr & 0x3fff));
}
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) return cartridge.ram_read((ram_select << 13) + (addr & 0x1fff));
return 0x00;
}
return 0x00;
}
void Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) {
if(within<0x0000, 0x1fff>(addr)) {
if(rom_mode == 0) {
rom_mode = 1;
} else {
ram_enable = (data & 0x0f) == 0x0a;
}
}
if(within<0x2000, 0x3fff>(addr)) {
if(rom_mode == 0) {
rom_base = data & 0x3f;
} else {
rom_select = data;
}
}
if(within<0x4000, 0x5fff>(addr)) {
if(rom_mode == 1) {
ram_select = data;
}
}
if(within<0x6000, 0x7fff>(addr)) {
//unknown purpose
}
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) cartridge.ram_write((ram_select << 13) + (addr & 0x1fff), data);
}
}
void Cartridge::MMM01::power() {
rom_mode = 0;
rom_base = 0;
ram_enable = false;
rom_select = 0x01;
ram_select = 0x00;
}
#endif
-12
View File
@@ -1,12 +0,0 @@
struct MMM01 : MMIO {
bool rom_mode;
uint8 rom_base;
bool ram_enable;
uint8 rom_select;
uint8 ram_select;
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
void power();
} mmm01;
-53
View File
@@ -1,53 +0,0 @@
#ifdef CARTRIDGE_CPP
void Cartridge::serialize(serializer &s) {
if(info.battery) s.array(ramdata, ramsize);
s.integer(bootrom_enable);
s.integer(mbc1.ram_enable);
s.integer(mbc1.rom_select);
s.integer(mbc1.ram_select);
s.integer(mbc1.mode_select);
s.integer(mbc2.ram_enable);
s.integer(mbc2.rom_select);
s.integer(mbc3.ram_enable);
s.integer(mbc3.rom_select);
s.integer(mbc3.ram_select);
s.integer(mbc3.rtc_latch);
s.integer(mbc3.rtc_halt);
s.integer(mbc3.rtc_second);
s.integer(mbc3.rtc_minute);
s.integer(mbc3.rtc_hour);
s.integer(mbc3.rtc_day);
s.integer(mbc3.rtc_day_carry);
s.integer(mbc3.rtc_latch_second);
s.integer(mbc3.rtc_latch_minute);
s.integer(mbc3.rtc_latch_hour);
s.integer(mbc3.rtc_latch_day);
s.integer(mbc3.rtc_latch_day_carry);
s.integer(mbc5.ram_enable);
s.integer(mbc5.rom_select);
s.integer(mbc5.ram_select);
s.integer(mmm01.rom_mode);
s.integer(mmm01.rom_base);
s.integer(mmm01.ram_enable);
s.integer(mmm01.rom_select);
s.integer(mmm01.ram_select);
s.integer(huc1.ram_enable);
s.integer(huc1.rom_select);
s.integer(huc1.ram_select);
s.integer(huc3.ram_enable);
s.integer(huc3.rom_select);
s.integer(huc3.ram_select);
}
#endif
-91
View File
@@ -1,91 +0,0 @@
#include <gameboy/gameboy.hpp>
namespace GameBoy {
Cheat cheat;
bool Cheat::decode(const string &code_, unsigned &addr, unsigned &data, unsigned &comp) {
static bool initialize = false;
static uint8 mapProActionReplay[256], mapGameGenie[256];
if(initialize == false) {
initialize = true;
for(auto &n : mapProActionReplay) n = ~0;
mapProActionReplay['0'] = 0; mapProActionReplay['1'] = 1; mapProActionReplay['2'] = 2; mapProActionReplay['3'] = 3;
mapProActionReplay['4'] = 4; mapProActionReplay['5'] = 5; mapProActionReplay['6'] = 6; mapProActionReplay['7'] = 7;
mapProActionReplay['8'] = 8; mapProActionReplay['9'] = 9; mapProActionReplay['A'] = 10; mapProActionReplay['B'] = 11;
mapProActionReplay['C'] = 12; mapProActionReplay['D'] = 13; mapProActionReplay['E'] = 14; mapProActionReplay['F'] = 15;
for(auto &n : mapGameGenie) n = ~0;
mapGameGenie['0'] = 0; mapGameGenie['1'] = 1; mapGameGenie['2'] = 2; mapGameGenie['3'] = 3;
mapGameGenie['4'] = 4; mapGameGenie['5'] = 5; mapGameGenie['6'] = 6; mapGameGenie['7'] = 7;
mapGameGenie['8'] = 8; mapGameGenie['9'] = 9; mapGameGenie['A'] = 10; mapGameGenie['B'] = 11;
mapGameGenie['C'] = 12; mapGameGenie['D'] = 13; mapGameGenie['E'] = 14; mapGameGenie['F'] = 15;
}
string code = code_;
code.upper();
unsigned length = code.length(), bits = 0;
if(code.wildcard("????:??")) {
code = { substr(code, 0, 4), substr(code, 5, 2) };
for(unsigned n = 0; n < 6; n++) if(mapProActionReplay[code[n]] > 15) return false;
bits = hex(code);
addr = (bits >> 8) & 0xffff;
data = (bits >> 0) & 0xff;
comp = ~0;
return true;
}
if(code.wildcard("????:??:??")) {
code = { substr(code, 0, 4), substr(code, 5, 2), substr(code, 8, 2) };
for(unsigned n = 0; n < 8; n++) if(mapProActionReplay[code[n]] > 15) return false;
bits = hex(code);
addr = (bits >> 16) & 0xffff;
data = (bits >> 8) & 0xff;
comp = (bits >> 0) & 0xff;
return true;
}
if(code.wildcard("???" "-" "???")) {
code = { substr(code, 0, 3), substr(code, 4, 3) };
for(unsigned n = 0; n < 6; n++) if(mapGameGenie[code[n]] > 15) return false;
for(unsigned n = 0; n < 6; n++) bits |= mapGameGenie[code[n]] << (20 - n * 4);
addr = (bits >> 0) & 0xffff;
data = (bits >> 16) & 0xff;
comp = ~0;
addr = (((addr >> 4) | (addr << 12)) & 0xffff) ^ 0xf000;
return true;
}
if(code.wildcard("???" "-" "???" "-" "???")) {
code = { substr(code, 0, 3), substr(code, 4, 3), substr(code, 8, 1), substr(code, 10, 1) };
for(unsigned n = 0; n < 8; n++) if(mapGameGenie[code[n]] > 15) return false;
for(unsigned n = 0; n < 8; n++) bits |= mapGameGenie[code[n]] << (28 - n * 4);
addr = (bits >> 8) & 0xffff;
data = (bits >> 24) & 0xff;
comp = (bits >> 0) & 0xff;
addr = (((addr >> 4) | (addr << 12)) & 0xffff) ^ 0xf000;
comp = (((comp >> 2) | (comp << 6)) & 0xff) ^ 0xba;
return true;
}
return false;
}
void Cheat::synchronize() {
for(auto &n : override) n = false;
for(unsigned n = 0; n < size(); n++) {
override[operator[](n).addr] = true;
}
}
}
-14
View File
@@ -1,14 +0,0 @@
struct CheatCode {
unsigned addr;
unsigned data;
unsigned comp;
};
struct Cheat : public linear_vector<CheatCode> {
static bool decode(const string &code, unsigned &addr, unsigned &data, unsigned &comp);
void synchronize();
bool override[65536];
};
extern Cheat cheat;
-675
View File
@@ -1,675 +0,0 @@
#ifdef CPU_CPP
#include "table.cpp"
#include "disassembler.cpp"
void CPU::op_xx() {
}
void CPU::op_cb() {
uint8 opcode = op_read(r[PC]++);
(this->*opcode_table_cb[opcode])();
}
//8-bit load commands
template<unsigned x, unsigned y> void CPU::op_ld_r_r() {
r[x] = r[y];
}
template<unsigned x> void CPU::op_ld_r_n() {
r[x] = op_read(r[PC]++);
}
template<unsigned x> void CPU::op_ld_r_hl() {
r[x] = op_read(r[HL]);
}
template<unsigned x> void CPU::op_ld_hl_r() {
op_write(r[HL], r[x]);
}
void CPU::op_ld_hl_n() {
op_write(r[HL], op_read(r[PC]++));
}
template<unsigned x> void CPU::op_ld_a_rr() {
r[A] = op_read(r[x]);
}
void CPU::op_ld_a_nn() {
uint8 lo = op_read(r[PC]++);
uint8 hi = op_read(r[PC]++);
r[A] = op_read((hi << 8) | (lo << 0));
}
template<unsigned x> void CPU::op_ld_rr_a() {
op_write(r[x], r[A]);
}
void CPU::op_ld_nn_a() {
uint8 lo = op_read(r[PC]++);
uint8 hi = op_read(r[PC]++);
op_write((hi << 8) | (lo << 0), r[A]);
}
void CPU::op_ld_a_ffn() {
r[A] = op_read(0xff00 + op_read(r[PC]++));
}
void CPU::op_ld_ffn_a() {
op_write(0xff00 + op_read(r[PC]++), r[A]);
}
void CPU::op_ld_a_ffc() {
r[A] = op_read(0xff00 + r[C]);
}
void CPU::op_ld_ffc_a() {
op_write(0xff00 + r[C], r[A]);
}
void CPU::op_ldi_hl_a() {
op_write(r[HL], r[A]);
r[HL]++;
}
void CPU::op_ldi_a_hl() {
r[A] = op_read(r[HL]);
r[HL]++;
}
void CPU::op_ldd_hl_a() {
op_write(r[HL], r[A]);
r[HL]--;
}
void CPU::op_ldd_a_hl() {
r[A] = op_read(r[HL]);
r[HL]--;
}
//16-bit load commands
template<unsigned x> void CPU::op_ld_rr_nn() {
r[x] = op_read(r[PC]++) << 0;
r[x] |= op_read(r[PC]++) << 8;
}
void CPU::op_ld_nn_sp() {
uint16 addr = op_read(r[PC]++) << 0;
addr |= op_read(r[PC]++) << 8;
op_write(addr + 0, r[SP] >> 0);
op_write(addr + 1, r[SP] >> 8);
}
void CPU::op_ld_sp_hl() {
r[SP] = r[HL];
op_io();
}
template<unsigned x> void CPU::op_push_rr() {
op_write(--r[SP], r[x] >> 8);
op_write(--r[SP], r[x] >> 0);
op_io();
}
template<unsigned x> void CPU::op_pop_rr() {
r[x] = op_read(r[SP]++) << 0;
r[x] |= op_read(r[SP]++) << 8;
}
//8-bit arithmetic commands
void CPU::opi_add_a(uint8 x) {
uint16 rh = r[A] + x;
uint16 rl = (r[A] & 0x0f) + (x & 0x0f);
r[A] = rh;
r.f.z = (uint8)rh == 0;
r.f.n = 0;
r.f.h = rl > 0x0f;
r.f.c = rh > 0xff;
}
template<unsigned x> void CPU::op_add_a_r() { opi_add_a(r[x]); }
void CPU::op_add_a_n() { opi_add_a(op_read(r[PC]++)); }
void CPU::op_add_a_hl() { opi_add_a(op_read(r[HL])); }
void CPU::opi_adc_a(uint8 x) {
uint16 rh = r[A] + x + r.f.c;
uint16 rl = (r[A] & 0x0f) + (x & 0x0f) + r.f.c;
r[A] = rh;
r.f.z = (uint8)rh == 0;
r.f.n = 0;
r.f.h = rl > 0x0f;
r.f.c = rh > 0xff;
}
template<unsigned x> void CPU::op_adc_a_r() { opi_adc_a(r[x]); }
void CPU::op_adc_a_n() { opi_adc_a(op_read(r[PC]++)); }
void CPU::op_adc_a_hl() { opi_adc_a(op_read(r[HL])); }
void CPU::opi_sub_a(uint8 x) {
uint16 rh = r[A] - x;
uint16 rl = (r[A] & 0x0f) - (x & 0x0f);
r[A] = rh;
r.f.z = (uint8)rh == 0;
r.f.n = 1;
r.f.h = rl > 0x0f;
r.f.c = rh > 0xff;
}
template<unsigned x> void CPU::op_sub_a_r() { opi_sub_a(r[x]); }
void CPU::op_sub_a_n() { opi_sub_a(op_read(r[PC]++)); }
void CPU::op_sub_a_hl() { opi_sub_a(op_read(r[HL])); }
void CPU::opi_sbc_a(uint8 x) {
uint16 rh = r[A] - x - r.f.c;
uint16 rl = (r[A] & 0x0f) - (x & 0x0f) - r.f.c;
r[A] = rh;
r.f.z = (uint8)rh == 0;
r.f.n = 1;
r.f.h = rl > 0x0f;
r.f.c = rh > 0xff;
}
template<unsigned x> void CPU::op_sbc_a_r() { opi_sbc_a(r[x]); }
void CPU::op_sbc_a_n() { opi_sbc_a(op_read(r[PC]++)); }
void CPU::op_sbc_a_hl() { opi_sbc_a(op_read(r[HL])); }
void CPU::opi_and_a(uint8 x) {
r[A] &= x;
r.f.z = r[A] == 0;
r.f.n = 0;
r.f.h = 1;
r.f.c = 0;
}
template<unsigned x> void CPU::op_and_a_r() { opi_and_a(r[x]); }
void CPU::op_and_a_n() { opi_and_a(op_read(r[PC]++)); }
void CPU::op_and_a_hl() { opi_and_a(op_read(r[HL])); }
void CPU::opi_xor_a(uint8 x) {
r[A] ^= x;
r.f.z = r[A] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = 0;
}
template<unsigned x> void CPU::op_xor_a_r() { opi_xor_a(r[x]); }
void CPU::op_xor_a_n() { opi_xor_a(op_read(r[PC]++)); }
void CPU::op_xor_a_hl() { opi_xor_a(op_read(r[HL])); }
void CPU::opi_or_a(uint8 x) {
r[A] |= x;
r.f.z = r[A] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = 0;
}
template<unsigned x> void CPU::op_or_a_r() { opi_or_a(r[x]); }
void CPU::op_or_a_n() { opi_or_a(op_read(r[PC]++)); }
void CPU::op_or_a_hl() { opi_or_a(op_read(r[HL])); }
void CPU::opi_cp_a(uint8 x) {
uint16 rh = r[A] - x;
uint16 rl = (r[A] & 0x0f) - (x & 0x0f);
r.f.z = (uint8)rh == 0;
r.f.n = 1;
r.f.h = rl > 0x0f;
r.f.c = rh > 0xff;
}
template<unsigned x> void CPU::op_cp_a_r() { opi_cp_a(r[x]); }
void CPU::op_cp_a_n() { opi_cp_a(op_read(r[PC]++)); }
void CPU::op_cp_a_hl() { opi_cp_a(op_read(r[HL])); }
template<unsigned x> void CPU::op_inc_r() {
r[x]++;
r.f.z = r[x] == 0;
r.f.n = 0;
r.f.h = (r[x] & 0x0f) == 0x00;
}
void CPU::op_inc_hl() {
uint8 n = op_read(r[HL]);
op_write(r[HL], ++n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = (n & 0x0f) == 0x00;
}
template<unsigned x> void CPU::op_dec_r() {
r[x]--;
r.f.z = r[x] == 0;
r.f.n = 1;
r.f.h = (r[x] & 0x0f) == 0x0f;
}
void CPU::op_dec_hl() {
uint8 n = op_read(r[HL]);
op_write(r[HL], --n);
r.f.z = n == 0;
r.f.n = 1;
r.f.h = (n & 0x0f) == 0x0f;
}
void CPU::op_daa() {
uint16 a = r[A];
if(r.f.n == 0) {
if(r.f.h || (a & 0x0f) > 0x09) a += 0x06;
if(r.f.c || (a ) > 0x9f) a += 0x60;
} else {
if(r.f.h) {
a -= 0x06;
if(r.f.c == 0) a &= 0xff;
}
if(r.f.c) a -= 0x60;
}
r[A] = a;
r.f.z = r[A] == 0;
r.f.h = 0;
r.f.c |= a & 0x100;
}
void CPU::op_cpl() {
r[A] ^= 0xff;
r.f.n = 1;
r.f.h = 1;
}
//16-bit arithmetic commands
template<unsigned x> void CPU::op_add_hl_rr() {
op_io();
uint32 rb = (r[HL] + r[x]);
uint32 rn = (r[HL] & 0xfff) + (r[x] & 0xfff);
r[HL] = rb;
r.f.n = 0;
r.f.h = rn > 0x0fff;
r.f.c = rb > 0xffff;
}
template<unsigned x> void CPU::op_inc_rr() {
op_io();
r[x]++;
}
template<unsigned x> void CPU::op_dec_rr() {
op_io();
r[x]--;
}
void CPU::op_add_sp_n() {
op_io();
op_io();
signed n = (int8)op_read(r[PC]++);
r.f.z = 0;
r.f.n = 0;
r.f.h = ((r[SP] & 0x0f) + (n & 0x0f)) > 0x0f;
r.f.c = ((r[SP] & 0xff) + (n & 0xff)) > 0xff;
r[SP] += n;
}
void CPU::op_ld_hl_sp_n() {
op_io();
signed n = (int8)op_read(r[PC]++);
r.f.z = 0;
r.f.n = 0;
r.f.h = ((r[SP] & 0x0f) + (n & 0x0f)) > 0x0f;
r.f.c = ((r[SP] & 0xff) + (n & 0xff)) > 0xff;
r[HL] = r[SP] + n;
}
//rotate/shift commands
void CPU::op_rlca() {
r[A] = (r[A] << 1) | (r[A] >> 7);
r.f.z = 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = r[A] & 0x01;
}
void CPU::op_rla() {
bool c = r[A] & 0x80;
r[A] = (r[A] << 1) | (r.f.c << 0);
r.f.z = 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
void CPU::op_rrca() {
r[A] = (r[A] >> 1) | (r[A] << 7);
r.f.z = 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = r[A] & 0x80;
}
void CPU::op_rra() {
bool c = r[A] & 0x01;
r[A] = (r[A] >> 1) | (r.f.c << 7);
r.f.z = 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
template<unsigned x> void CPU::op_rlc_r() {
r[x] = (r[x] << 1) | (r[x] >> 7);
r.f.z = r[x] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = r[x] & 0x01;
}
void CPU::op_rlc_hl() {
uint8 n = op_read(r[HL]);
n = (n << 1) | (n >> 7);
op_write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = n & 0x01;
}
template<unsigned x> void CPU::op_rl_r() {
bool c = r[x] & 0x80;
r[x] = (r[x] << 1) | (r.f.c << 0);
r.f.z = r[x] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
void CPU::op_rl_hl() {
uint8 n = op_read(r[HL]);
bool c = n & 0x80;
n = (n << 1) | (r.f.c << 0);
op_write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
template<unsigned x> void CPU::op_rrc_r() {
r[x] = (r[x] >> 1) | (r[x] << 7);
r.f.z = r[x] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = r[x] & 0x80;
}
void CPU::op_rrc_hl() {
uint8 n = op_read(r[HL]);
n = (n >> 1) | (n << 7);
op_write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = n & 0x80;
}
template<unsigned x> void CPU::op_rr_r() {
bool c = r[x] & 0x01;
r[x] = (r[x] >> 1) | (r.f.c << 7);
r.f.z = r[x] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
void CPU::op_rr_hl() {
uint8 n = op_read(r[HL]);
bool c = n & 0x01;
n = (n >> 1) | (r.f.c << 7);
op_write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
template<unsigned x> void CPU::op_sla_r() {
bool c = r[x] & 0x80;
r[x] <<= 1;
r.f.z = r[x] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
void CPU::op_sla_hl() {
uint8 n = op_read(r[HL]);
bool c = n & 0x80;
n <<= 1;
op_write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
template<unsigned x> void CPU::op_swap_r() {
r[x] = (r[x] << 4) | (r[x] >> 4);
r.f.z = r[x] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = 0;
}
void CPU::op_swap_hl() {
uint8 n = op_read(r[HL]);
n = (n << 4) | (n >> 4);
op_write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = 0;
}
template<unsigned x> void CPU::op_sra_r() {
bool c = r[x] & 0x01;
r[x] = (int8)r[x] >> 1;
r.f.z = r[x] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
void CPU::op_sra_hl() {
uint8 n = op_read(r[HL]);
bool c = n & 0x01;
n = (int8)n >> 1;
op_write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
template<unsigned x> void CPU::op_srl_r() {
bool c = r[x] & 0x01;
r[x] >>= 1;
r.f.z = r[x] == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
void CPU::op_srl_hl() {
uint8 n = op_read(r[HL]);
bool c = n & 0x01;
n >>= 1;
op_write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
r.f.c = c;
}
//single-bit commands
template<unsigned b, unsigned x> void CPU::op_bit_n_r() {
r.f.z = (r[x] & (1 << b)) == 0;
r.f.n = 0;
r.f.h = 1;
}
template<unsigned b> void CPU::op_bit_n_hl() {
uint8 n = op_read(r[HL]);
r.f.z = (n & (1 << b)) == 0;
r.f.n = 0;
r.f.h = 1;
}
template<unsigned b, unsigned x> void CPU::op_set_n_r() {
r[x] |= 1 << b;
}
template<unsigned b> void CPU::op_set_n_hl() {
uint8 n = op_read(r[HL]);
n |= 1 << b;
op_write(r[HL], n);
}
template<unsigned b, unsigned x> void CPU::op_res_n_r() {
r[x] &= ~(1 << b);
}
template<unsigned b> void CPU::op_res_n_hl() {
uint8 n = op_read(r[HL]);
n &= ~(1 << b);
op_write(r[HL], n);
}
//control commands
void CPU::op_ccf() {
r.f.n = 0;
r.f.h = 0;
r.f.c = !r.f.c;
}
void CPU::op_scf() {
r.f.n = 0;
r.f.h = 0;
r.f.c = 1;
}
void CPU::op_nop() {
}
void CPU::op_halt() {
status.halt = true;
while(status.halt == true) op_io();
}
void CPU::op_stop() {
status.stop = true;
while(status.stop == true) op_io();
}
void CPU::op_di() {
status.ime = 0;
}
void CPU::op_ei() {
status.ei = true;
//status.ime = 1;
}
//jump commands
void CPU::op_jp_nn() {
uint8 lo = op_read(r[PC]++);
uint8 hi = op_read(r[PC]++);
r[PC] = (hi << 8) | (lo << 0);
op_io();
}
void CPU::op_jp_hl() {
r[PC] = r[HL];
}
template<unsigned x, bool y> void CPU::op_jp_f_nn() {
uint8 lo = op_read(r[PC]++);
uint8 hi = op_read(r[PC]++);
if(r.f[x] == y) {
r[PC] = (hi << 8) | (lo << 0);
op_io();
}
}
void CPU::op_jr_n() {
int8 n = op_read(r[PC]++);
r[PC] += n;
op_io();
}
template<unsigned x, bool y> void CPU::op_jr_f_n() {
int8 n = op_read(r[PC]++);
if(r.f[x] == y) {
r[PC] += n;
op_io();
}
}
void CPU::op_call_nn() {
uint8 lo = op_read(r[PC]++);
uint8 hi = op_read(r[PC]++);
op_write(--r[SP], r[PC] >> 8);
op_write(--r[SP], r[PC] >> 0);
r[PC] = (hi << 8) | (lo << 0);
op_io();
}
template<unsigned x, bool y> void CPU::op_call_f_nn() {
uint8 lo = op_read(r[PC]++);
uint8 hi = op_read(r[PC]++);
if(r.f[x] == y) {
op_write(--r[SP], r[PC] >> 8);
op_write(--r[SP], r[PC] >> 0);
r[PC] = (hi << 8) | (lo << 0);
op_io();
}
}
void CPU::op_ret() {
uint8 lo = op_read(r[SP]++);
uint8 hi = op_read(r[SP]++);
r[PC] = (hi << 8) | (lo << 0);
op_io();
}
template<unsigned x, bool y> void CPU::op_ret_f() {
op_io();
if(r.f[x] == y) {
uint8 lo = op_read(r[SP]++);
uint8 hi = op_read(r[SP]++);
r[PC] = (hi << 8) | (lo << 0);
op_io();
}
}
void CPU::op_reti() {
uint8 lo = op_read(r[SP]++);
uint8 hi = op_read(r[SP]++);
r[PC] = (hi << 8) | (lo << 0);
op_io();
status.ime = 1;
}
template<unsigned n> void CPU::op_rst_n() {
op_write(--r[SP], r[PC] >> 8);
op_write(--r[SP], r[PC] >> 0);
r[PC] = n;
op_io();
}
#endif
-145
View File
@@ -1,145 +0,0 @@
#include "registers.hpp"
void (CPU::*opcode_table[256])();
void (CPU::*opcode_table_cb[256])();
void initialize_opcode_table();
void op_xx();
void op_cb();
//8-bit load commands
template<unsigned x, unsigned y> void op_ld_r_r();
template<unsigned x> void op_ld_r_n();
template<unsigned x> void op_ld_r_hl();
template<unsigned x> void op_ld_hl_r();
void op_ld_hl_n();
template<unsigned x> void op_ld_a_rr();
void op_ld_a_nn();
template<unsigned x> void op_ld_rr_a();
void op_ld_nn_a();
void op_ld_a_ffn();
void op_ld_ffn_a();
void op_ld_a_ffc();
void op_ld_ffc_a();
void op_ldi_hl_a();
void op_ldi_a_hl();
void op_ldd_hl_a();
void op_ldd_a_hl();
//16-bit load commands
template<unsigned x> void op_ld_rr_nn();
void op_ld_nn_sp();
void op_ld_sp_hl();
template<unsigned x> void op_push_rr();
template<unsigned x> void op_pop_rr();
//8-bit arithmetic commands
void opi_add_a(uint8 x);
template<unsigned x> void op_add_a_r();
void op_add_a_n();
void op_add_a_hl();
void opi_adc_a(uint8 x);
template<unsigned x> void op_adc_a_r();
void op_adc_a_n();
void op_adc_a_hl();
void opi_sub_a(uint8 x);
template<unsigned x> void op_sub_a_r();
void op_sub_a_n();
void op_sub_a_hl();
void opi_sbc_a(uint8 x);
template<unsigned x> void op_sbc_a_r();
void op_sbc_a_n();
void op_sbc_a_hl();
void opi_and_a(uint8 x);
template<unsigned x> void op_and_a_r();
void op_and_a_n();
void op_and_a_hl();
void opi_xor_a(uint8 x);
template<unsigned x> void op_xor_a_r();
void op_xor_a_n();
void op_xor_a_hl();
void opi_or_a(uint8 x);
template<unsigned x> void op_or_a_r();
void op_or_a_n();
void op_or_a_hl();
void opi_cp_a(uint8 x);
template<unsigned x> void op_cp_a_r();
void op_cp_a_n();
void op_cp_a_hl();
template<unsigned x> void op_inc_r();
void op_inc_hl();
template<unsigned x> void op_dec_r();
void op_dec_hl();
void op_daa();
void op_cpl();
//16-bit arithmetic commands
template<unsigned x> void op_add_hl_rr();
template<unsigned x> void op_inc_rr();
template<unsigned x> void op_dec_rr();
void op_add_sp_n();
void op_ld_hl_sp_n();
//rotate/shift commands
void op_rlca();
void op_rla();
void op_rrca();
void op_rra();
template<unsigned x> void op_rlc_r();
void op_rlc_hl();
template<unsigned x> void op_rl_r();
void op_rl_hl();
template<unsigned x> void op_rrc_r();
void op_rrc_hl();
template<unsigned x> void op_rr_r();
void op_rr_hl();
template<unsigned x> void op_sla_r();
void op_sla_hl();
template<unsigned x> void op_swap_r();
void op_swap_hl();
template<unsigned x> void op_sra_r();
void op_sra_hl();
template<unsigned x> void op_srl_r();
void op_srl_hl();
//single-bit commands
template<unsigned b, unsigned x> void op_bit_n_r();
template<unsigned b> void op_bit_n_hl();
template<unsigned b, unsigned x> void op_set_n_r();
template<unsigned b> void op_set_n_hl();
template<unsigned b, unsigned x> void op_res_n_r();
template<unsigned b> void op_res_n_hl();
//control commands
void op_ccf();
void op_scf();
void op_nop();
void op_halt();
void op_stop();
void op_di();
void op_ei();
//jump commands
void op_jp_nn();
void op_jp_hl();
template<unsigned x, bool y> void op_jp_f_nn();
void op_jr_n();
template<unsigned x, bool y> void op_jr_f_n();
void op_call_nn();
template<unsigned x, bool y> void op_call_f_nn();
void op_ret();
template<unsigned x, bool y> void op_ret_f();
void op_reti();
template<unsigned n> void op_rst_n();
//disassembler.cpp
string disassemble(uint16 pc);
string disassemble_opcode(uint16 pc);
string disassemble_opcode_cb(uint16 pc);
-560
View File
@@ -1,560 +0,0 @@
#ifdef CPU_CPP
string CPU::disassemble(uint16 pc) {
char output[80];
memset(output, ' ', sizeof output);
output[79] = 0;
string opcode = disassemble_opcode(pc);
string registers = {
" AF:", hex<4>(r[AF]),
" BC:", hex<4>(r[BC]),
" DE:", hex<4>(r[DE]),
" HL:", hex<4>(r[HL]),
" SP:", hex<4>(r[SP])
};
memcpy(output + 0, hex<4>(pc), 4);
memcpy(output + 6, opcode, opcode.length());
memcpy(output + 23, registers, registers.length());
output[63] = 0;
return output;
}
string CPU::disassemble_opcode(uint16 pc) {
uint8 opcode = bus.read(pc);
uint8 p0 = bus.read(pc + 1);
uint8 p1 = bus.read(pc + 2);
uint8 p2 = bus.read(pc + 3);
switch(opcode) {
case 0x00: return { "nop" };
case 0x01: return { "ld bc,$", hex<2>(p1), hex<2>(p0) };
case 0x02: return { "ld (bc),a" };
case 0x03: return { "inc bc" };
case 0x04: return { "inc b" };
case 0x05: return { "dec b" };
case 0x06: return { "ld b,$", hex<2>(p0) };
case 0x07: return { "rlc a" };
case 0x08: return { "ld ($", hex<2>(p1), hex<2>(p0), "),sp" };
case 0x09: return { "add hl,bc" };
case 0x0a: return { "ld a,(bc)" };
case 0x0b: return { "dec bc" };
case 0x0c: return { "inc c" };
case 0x0d: return { "dec c" };
case 0x0e: return { "ld c,$", hex<2>(p0) };
case 0x0f: return { "rrc a" };
case 0x10: return { "stop" };
case 0x11: return { "ld de,$", hex<2>(p1), hex<2>(p0) };
case 0x12: return { "ld (de),a" };
case 0x13: return { "inc de" };
case 0x14: return { "inc d" };
case 0x15: return { "dec d" };
case 0x16: return { "ld d,$", hex<2>(p0) };
case 0x17: return { "rl a" };
case 0x18: return { "jr $", hex<4>(r[PC] + 2 + (int8)p0) };
case 0x19: return { "add hl,de" };
case 0x1a: return { "ld a,(de)" };
case 0x1b: return { "dec de" };
case 0x1c: return { "inc e" };
case 0x1d: return { "dec e" };
case 0x1e: return { "ld e,$", hex<2>(p0) };
case 0x1f: return { "rr a" };
case 0x20: return { "jr nz,$", hex<4>(r[PC] + 2 + (int8)p0) };
case 0x21: return { "ld hl,$", hex<2>(p1), hex<2>(p0) };
case 0x22: return { "ldi (hl),a" };
case 0x23: return { "inc hl" };
case 0x24: return { "inc h" };
case 0x25: return { "dec h" };
case 0x26: return { "ld h,$", hex<2>(p0) };
case 0x27: return { "daa" };
case 0x28: return { "jr z,$", hex<4>(r[PC] + 2 + (int8)p0) };
case 0x29: return { "add hl,hl" };
case 0x2a: return { "ldi a,(hl)" };
case 0x2b: return { "dec hl" };
case 0x2c: return { "inc l" };
case 0x2d: return { "dec l" };
case 0x2e: return { "ld l,$", hex<2>(p0) };
case 0x2f: return { "cpl" };
case 0x30: return { "jr nc,$", hex<4>(r[PC] + 2 + (int8)p0) };
case 0x31: return { "ld sp,$", hex<2>(p1), hex<2>(p0) };
case 0x32: return { "ldd (hl),a" };
case 0x33: return { "inc sp" };
case 0x34: return { "inc (hl)" };
case 0x35: return { "dec (hl)" };
case 0x36: return { "ld (hl),$", hex<2>(p0) };
case 0x37: return { "scf" };
case 0x38: return { "jr c,$", hex<4>(r[PC] + 2 + (int8)p0) };
case 0x39: return { "add hl,sp" };
case 0x3a: return { "ldd a,(hl)" };
case 0x3b: return { "dec sp" };
case 0x3c: return { "inc a" };
case 0x3d: return { "dec a" };
case 0x3e: return { "ld a,$", hex<2>(p0) };
case 0x3f: return { "ccf" };
case 0x40: return { "ld b,b" };
case 0x41: return { "ld b,c" };
case 0x42: return { "ld b,d" };
case 0x43: return { "ld b,e" };
case 0x44: return { "ld b,h" };
case 0x45: return { "ld b,l" };
case 0x46: return { "ld b,(hl)" };
case 0x47: return { "ld b,a" };
case 0x48: return { "ld c,b" };
case 0x49: return { "ld c,c" };
case 0x4a: return { "ld c,d" };
case 0x4b: return { "ld c,e" };
case 0x4c: return { "ld c,h" };
case 0x4d: return { "ld c,l" };
case 0x4e: return { "ld c,(hl)" };
case 0x4f: return { "ld c,a" };
case 0x50: return { "ld d,b" };
case 0x51: return { "ld d,c" };
case 0x52: return { "ld d,d" };
case 0x53: return { "ld d,e" };
case 0x54: return { "ld d,h" };
case 0x55: return { "ld d,l" };
case 0x56: return { "ld d,(hl)" };
case 0x57: return { "ld d,a" };
case 0x58: return { "ld e,b" };
case 0x59: return { "ld e,c" };
case 0x5a: return { "ld e,d" };
case 0x5b: return { "ld e,e" };
case 0x5c: return { "ld e,h" };
case 0x5d: return { "ld e,l" };
case 0x5e: return { "ld e,(hl)" };
case 0x5f: return { "ld e,a" };
case 0x60: return { "ld h,b" };
case 0x61: return { "ld h,c" };
case 0x62: return { "ld h,d" };
case 0x63: return { "ld h,e" };
case 0x64: return { "ld h,h" };
case 0x65: return { "ld h,l" };
case 0x66: return { "ld h,(hl)" };
case 0x67: return { "ld h,a" };
case 0x68: return { "ld l,b" };
case 0x69: return { "ld l,c" };
case 0x6a: return { "ld l,d" };
case 0x6b: return { "ld l,e" };
case 0x6c: return { "ld l,h" };
case 0x6d: return { "ld l,l" };
case 0x6e: return { "ld l,(hl)" };
case 0x6f: return { "ld l,a" };
case 0x70: return { "ld (hl),b" };
case 0x71: return { "ld (hl),c" };
case 0x72: return { "ld (hl),d" };
case 0x73: return { "ld (hl),e" };
case 0x74: return { "ld (hl),h" };
case 0x75: return { "ld (hl),l" };
case 0x76: return { "halt" };
case 0x77: return { "ld (hl),a" };
case 0x78: return { "ld a,b" };
case 0x79: return { "ld a,c" };
case 0x7a: return { "ld a,d" };
case 0x7b: return { "ld a,e" };
case 0x7c: return { "ld a,h" };
case 0x7d: return { "ld a,l" };
case 0x7e: return { "ld a,(hl)" };
case 0x7f: return { "ld a,a" };
case 0x80: return { "add a,b" };
case 0x81: return { "add a,c" };
case 0x82: return { "add a,d" };
case 0x83: return { "add a,e" };
case 0x84: return { "add a,h" };
case 0x85: return { "add a,l" };
case 0x86: return { "add a,(hl)" };
case 0x87: return { "add a,a" };
case 0x88: return { "adc a,b" };
case 0x89: return { "adc a,c" };
case 0x8a: return { "adc a,d" };
case 0x8b: return { "adc a,e" };
case 0x8c: return { "adc a,h" };
case 0x8d: return { "adc a,l" };
case 0x8e: return { "adc a,(hl)" };
case 0x8f: return { "adc a,a" };
case 0x90: return { "sub a,b" };
case 0x91: return { "sub a,c" };
case 0x92: return { "sub a,d" };
case 0x93: return { "sub a,e" };
case 0x94: return { "sub a,h" };
case 0x95: return { "sub a,l" };
case 0x96: return { "sub a,(hl)" };
case 0x97: return { "sub a,a" };
case 0x98: return { "sbc a,b" };
case 0x99: return { "sbc a,c" };
case 0x9a: return { "sbc a,d" };
case 0x9b: return { "sbc a,e" };
case 0x9c: return { "sbc a,h" };
case 0x9d: return { "sbc a,l" };
case 0x9e: return { "sbc a,(hl)" };
case 0x9f: return { "sbc a,a" };
case 0xa0: return { "and a,b" };
case 0xa1: return { "and a,c" };
case 0xa2: return { "and a,d" };
case 0xa3: return { "and a,e" };
case 0xa4: return { "and a,h" };
case 0xa5: return { "and a,l" };
case 0xa6: return { "and a,(hl)" };
case 0xa7: return { "and a,a" };
case 0xa8: return { "xor a,b" };
case 0xa9: return { "xor a,c" };
case 0xaa: return { "xor a,d" };
case 0xab: return { "xor a,e" };
case 0xac: return { "xor a,h" };
case 0xad: return { "xor a,l" };
case 0xae: return { "xor a,(hl)" };
case 0xaf: return { "xor a,a" };
case 0xb0: return { "or a,b" };
case 0xb1: return { "or a,c" };
case 0xb2: return { "or a,d" };
case 0xb3: return { "or a,e" };
case 0xb4: return { "or a,h" };
case 0xb5: return { "or a,l" };
case 0xb6: return { "or a,(hl)" };
case 0xb7: return { "or a,a" };
case 0xb8: return { "cp a,b" };
case 0xb9: return { "cp a,c" };
case 0xba: return { "cp a,d" };
case 0xbb: return { "cp a,e" };
case 0xbc: return { "cp a,h" };
case 0xbd: return { "cp a,l" };
case 0xbe: return { "cp a,(hl)" };
case 0xbf: return { "cp a,a" };
case 0xc0: return { "ret nz" };
case 0xc1: return { "pop bc" };
case 0xc2: return { "jp nz,$", hex<2>(p1), hex<2>(p0) };
case 0xc3: return { "jp $", hex<2>(p1), hex<2>(p0) };
case 0xc4: return { "call nz,$", hex<2>(p1), hex<2>(p0) };
case 0xc5: return { "push bc" };
case 0xc6: return { "add a,$", hex<2>(p0) };
case 0xc7: return { "rst $0000" };
case 0xc8: return { "ret z" };
case 0xc9: return { "ret" };
case 0xca: return { "jp z,$", hex<2>(p1), hex<2>(p0) };
case 0xcb: return disassemble_opcode_cb(pc + 1);
case 0xcc: return { "call z,$", hex<2>(p1), hex<2>(p0) };
case 0xcd: return { "call $", hex<2>(p1), hex<2>(p0) };
case 0xce: return { "adc a,$", hex<2>(p0) };
case 0xcf: return { "rst $0008" };
case 0xd0: return { "ret nc" };
case 0xd1: return { "pop de" };
case 0xd2: return { "jp nc,$", hex<2>(p1), hex<2>(p0) };
case 0xd3: return { "xx" };
case 0xd4: return { "call nc,$", hex<2>(p1), hex<2>(p0) };
case 0xd5: return { "push de" };
case 0xd6: return { "sub a,$", hex<2>(p0) };
case 0xd7: return { "rst $0010" };
case 0xd8: return { "ret c" };
case 0xd9: return { "reti" };
case 0xda: return { "jp c,$", hex<2>(p1), hex<2>(p0) };
case 0xdb: return { "xx" };
case 0xdc: return { "call c,$", hex<2>(p1), hex<2>(p0) };
case 0xdd: return { "xx" };
case 0xde: return { "sbc a,$", hex<2>(p0) };
case 0xdf: return { "rst $0018" };
case 0xe0: return { "ld ($ff", hex<2>(p0), "),a" };
case 0xe1: return { "pop hl" };
case 0xe2: return { "ld ($ff00+c),a" };
case 0xe3: return { "xx" };
case 0xe4: return { "xx" };
case 0xe5: return { "push hl" };
case 0xe6: return { "and a,$", hex<2>(p0) };
case 0xe7: return { "rst $0020" };
case 0xe8: return { "add sp,$", hex<4>((int8)p0) };
case 0xe9: return { "jp hl" };
case 0xea: return { "ld ($", hex<2>(p1), hex<2>(p0), "),a" };
case 0xeb: return { "xx" };
case 0xec: return { "xx" };
case 0xed: return { "xx" };
case 0xee: return { "xor a,$", hex<2>(p0) };
case 0xef: return { "rst $0028" };
case 0xf0: return { "ld a,($ff", hex<2>(p0), ")" };
case 0xf1: return { "pop af" };
case 0xf2: return { "ld a,($ff00+c)" };
case 0xf3: return { "di" };
case 0xf4: return { "xx" };
case 0xf5: return { "push af" };
case 0xf6: return { "or a,$", hex<2>(p0) };
case 0xf7: return { "rst $0030" };
case 0xf8: return { "ld hl,sp+$", hex<4>((int8)p0) };
case 0xf9: return { "ld sp,hl" };
case 0xfa: return { "ld a,($", hex<2>(p1), hex<2>(p0), ")" };
case 0xfb: return { "ei" };
case 0xfc: return { "xx" };
case 0xfd: return { "xx" };
case 0xfe: return { "cp a,$", hex<2>(p0) };
case 0xff: return { "rst $0038" };
}
return "";
}
string CPU::disassemble_opcode_cb(uint16 pc) {
uint8 opcode = bus.read(pc);
uint8 p0 = bus.read(pc + 1);
uint8 p1 = bus.read(pc + 2);
uint8 p2 = bus.read(pc + 3);
switch(opcode) {
case 0x00: return { "rlc b" };
case 0x01: return { "rlc c" };
case 0x02: return { "rlc d" };
case 0x03: return { "rlc e" };
case 0x04: return { "rlc h" };
case 0x05: return { "rlc l" };
case 0x06: return { "rlc (hl)" };
case 0x07: return { "rlc a" };
case 0x08: return { "rrc b" };
case 0x09: return { "rrc c" };
case 0x0a: return { "rrc d" };
case 0x0b: return { "rrc e" };
case 0x0c: return { "rrc h" };
case 0x0d: return { "rrc l" };
case 0x0e: return { "rrc (hl)" };
case 0x0f: return { "rrc a" };
case 0x10: return { "rl b" };
case 0x11: return { "rl c" };
case 0x12: return { "rl d" };
case 0x13: return { "rl e" };
case 0x14: return { "rl h" };
case 0x15: return { "rl l" };
case 0x16: return { "rl (hl)" };
case 0x17: return { "rl a" };
case 0x18: return { "rr b" };
case 0x19: return { "rr c" };
case 0x1a: return { "rr d" };
case 0x1b: return { "rr e" };
case 0x1c: return { "rr h" };
case 0x1d: return { "rr l" };
case 0x1e: return { "rr (hl)" };
case 0x1f: return { "rr a" };
case 0x20: return { "sla b" };
case 0x21: return { "sla c" };
case 0x22: return { "sla d" };
case 0x23: return { "sla e" };
case 0x24: return { "sla h" };
case 0x25: return { "sla l" };
case 0x26: return { "sla (hl)" };
case 0x27: return { "sla a" };
case 0x28: return { "sra b" };
case 0x29: return { "sra c" };
case 0x2a: return { "sra d" };
case 0x2b: return { "sra e" };
case 0x2c: return { "sra h" };
case 0x2d: return { "sra l" };
case 0x2e: return { "sra (hl)" };
case 0x2f: return { "sra a" };
case 0x30: return { "swap b" };
case 0x31: return { "swap c" };
case 0x32: return { "swap d" };
case 0x33: return { "swap e" };
case 0x34: return { "swap h" };
case 0x35: return { "swap l" };
case 0x36: return { "swap (hl)" };
case 0x37: return { "swap a" };
case 0x38: return { "srl b" };
case 0x39: return { "srl c" };
case 0x3a: return { "srl d" };
case 0x3b: return { "srl e" };
case 0x3c: return { "srl h" };
case 0x3d: return { "srl l" };
case 0x3e: return { "srl (hl)" };
case 0x3f: return { "srl a" };
case 0x40: return { "bit 0,b" };
case 0x41: return { "bit 0,c" };
case 0x42: return { "bit 0,d" };
case 0x43: return { "bit 0,e" };
case 0x44: return { "bit 0,h" };
case 0x45: return { "bit 0,l" };
case 0x46: return { "bit 0,(hl)" };
case 0x47: return { "bit 0,a" };
case 0x48: return { "bit 1,b" };
case 0x49: return { "bit 1,c" };
case 0x4a: return { "bit 1,d" };
case 0x4b: return { "bit 1,e" };
case 0x4c: return { "bit 1,h" };
case 0x4d: return { "bit 1,l" };
case 0x4e: return { "bit 1,(hl)" };
case 0x4f: return { "bit 1,a" };
case 0x50: return { "bit 2,b" };
case 0x51: return { "bit 2,c" };
case 0x52: return { "bit 2,d" };
case 0x53: return { "bit 2,e" };
case 0x54: return { "bit 2,h" };
case 0x55: return { "bit 2,l" };
case 0x56: return { "bit 2,(hl)" };
case 0x57: return { "bit 2,a" };
case 0x58: return { "bit 3,b" };
case 0x59: return { "bit 3,c" };
case 0x5a: return { "bit 3,d" };
case 0x5b: return { "bit 3,e" };
case 0x5c: return { "bit 3,h" };
case 0x5d: return { "bit 3,l" };
case 0x5e: return { "bit 3,(hl)" };
case 0x5f: return { "bit 3,a" };
case 0x60: return { "bit 4,b" };
case 0x61: return { "bit 4,c" };
case 0x62: return { "bit 4,d" };
case 0x63: return { "bit 4,e" };
case 0x64: return { "bit 4,h" };
case 0x65: return { "bit 4,l" };
case 0x66: return { "bit 4,(hl)" };
case 0x67: return { "bit 4,a" };
case 0x68: return { "bit 5,b" };
case 0x69: return { "bit 5,c" };
case 0x6a: return { "bit 5,d" };
case 0x6b: return { "bit 5,e" };
case 0x6c: return { "bit 5,h" };
case 0x6d: return { "bit 5,l" };
case 0x6e: return { "bit 5,(hl)" };
case 0x6f: return { "bit 5,a" };
case 0x70: return { "bit 6,b" };
case 0x71: return { "bit 6,c" };
case 0x72: return { "bit 6,d" };
case 0x73: return { "bit 6,e" };
case 0x74: return { "bit 6,h" };
case 0x75: return { "bit 6,l" };
case 0x76: return { "bit 6,(hl)" };
case 0x77: return { "bit 6,a" };
case 0x78: return { "bit 7,b" };
case 0x79: return { "bit 7,c" };
case 0x7a: return { "bit 7,d" };
case 0x7b: return { "bit 7,e" };
case 0x7c: return { "bit 7,h" };
case 0x7d: return { "bit 7,l" };
case 0x7e: return { "bit 7,(hl)" };
case 0x7f: return { "bit 7,a" };
case 0x80: return { "res 0,b" };
case 0x81: return { "res 0,c" };
case 0x82: return { "res 0,d" };
case 0x83: return { "res 0,e" };
case 0x84: return { "res 0,h" };
case 0x85: return { "res 0,l" };
case 0x86: return { "res 0,(hl)" };
case 0x87: return { "res 0,a" };
case 0x88: return { "res 1,b" };
case 0x89: return { "res 1,c" };
case 0x8a: return { "res 1,d" };
case 0x8b: return { "res 1,e" };
case 0x8c: return { "res 1,h" };
case 0x8d: return { "res 1,l" };
case 0x8e: return { "res 1,(hl)" };
case 0x8f: return { "res 1,a" };
case 0x90: return { "res 2,b" };
case 0x91: return { "res 2,c" };
case 0x92: return { "res 2,d" };
case 0x93: return { "res 2,e" };
case 0x94: return { "res 2,h" };
case 0x95: return { "res 2,l" };
case 0x96: return { "res 2,(hl)" };
case 0x97: return { "res 2,a" };
case 0x98: return { "res 3,b" };
case 0x99: return { "res 3,c" };
case 0x9a: return { "res 3,d" };
case 0x9b: return { "res 3,e" };
case 0x9c: return { "res 3,h" };
case 0x9d: return { "res 3,l" };
case 0x9e: return { "res 3,(hl)" };
case 0x9f: return { "res 3,a" };
case 0xa0: return { "res 4,b" };
case 0xa1: return { "res 4,c" };
case 0xa2: return { "res 4,d" };
case 0xa3: return { "res 4,e" };
case 0xa4: return { "res 4,h" };
case 0xa5: return { "res 4,l" };
case 0xa6: return { "res 4,(hl)" };
case 0xa7: return { "res 4,a" };
case 0xa8: return { "res 5,b" };
case 0xa9: return { "res 5,c" };
case 0xaa: return { "res 5,d" };
case 0xab: return { "res 5,e" };
case 0xac: return { "res 5,h" };
case 0xad: return { "res 5,l" };
case 0xae: return { "res 5,(hl)" };
case 0xaf: return { "res 5,a" };
case 0xb0: return { "res 6,b" };
case 0xb1: return { "res 6,c" };
case 0xb2: return { "res 6,d" };
case 0xb3: return { "res 6,e" };
case 0xb4: return { "res 6,h" };
case 0xb5: return { "res 6,l" };
case 0xb6: return { "res 6,(hl)" };
case 0xb7: return { "res 6,a" };
case 0xb8: return { "res 7,b" };
case 0xb9: return { "res 7,c" };
case 0xba: return { "res 7,d" };
case 0xbb: return { "res 7,e" };
case 0xbc: return { "res 7,h" };
case 0xbd: return { "res 7,l" };
case 0xbe: return { "res 7,(hl)" };
case 0xbf: return { "res 7,a" };
case 0xc0: return { "set 0,b" };
case 0xc1: return { "set 0,c" };
case 0xc2: return { "set 0,d" };
case 0xc3: return { "set 0,e" };
case 0xc4: return { "set 0,h" };
case 0xc5: return { "set 0,l" };
case 0xc6: return { "set 0,(hl)" };
case 0xc7: return { "set 0,a" };
case 0xc8: return { "set 1,b" };
case 0xc9: return { "set 1,c" };
case 0xca: return { "set 1,d" };
case 0xcb: return { "set 1,e" };
case 0xcc: return { "set 1,h" };
case 0xcd: return { "set 1,l" };
case 0xce: return { "set 1,(hl)" };
case 0xcf: return { "set 1,a" };
case 0xd0: return { "set 2,b" };
case 0xd1: return { "set 2,c" };
case 0xd2: return { "set 2,d" };
case 0xd3: return { "set 2,e" };
case 0xd4: return { "set 2,h" };
case 0xd5: return { "set 2,l" };
case 0xd6: return { "set 2,(hl)" };
case 0xd7: return { "set 2,a" };
case 0xd8: return { "set 3,b" };
case 0xd9: return { "set 3,c" };
case 0xda: return { "set 3,d" };
case 0xdb: return { "set 3,e" };
case 0xdc: return { "set 3,h" };
case 0xdd: return { "set 3,l" };
case 0xde: return { "set 3,(hl)" };
case 0xdf: return { "set 3,a" };
case 0xe0: return { "set 4,b" };
case 0xe1: return { "set 4,c" };
case 0xe2: return { "set 4,d" };
case 0xe3: return { "set 4,e" };
case 0xe4: return { "set 4,h" };
case 0xe5: return { "set 4,l" };
case 0xe6: return { "set 4,(hl)" };
case 0xe7: return { "set 4,a" };
case 0xe8: return { "set 5,b" };
case 0xe9: return { "set 5,c" };
case 0xea: return { "set 5,d" };
case 0xeb: return { "set 5,e" };
case 0xec: return { "set 5,h" };
case 0xed: return { "set 5,l" };
case 0xee: return { "set 5,(hl)" };
case 0xef: return { "set 5,a" };
case 0xf0: return { "set 6,b" };
case 0xf1: return { "set 6,c" };
case 0xf2: return { "set 6,d" };
case 0xf3: return { "set 6,e" };
case 0xf4: return { "set 6,h" };
case 0xf5: return { "set 6,l" };
case 0xf6: return { "set 6,(hl)" };
case 0xf7: return { "set 6,a" };
case 0xf8: return { "set 7,b" };
case 0xf9: return { "set 7,c" };
case 0xfa: return { "set 7,d" };
case 0xfb: return { "set 7,e" };
case 0xfc: return { "set 7,h" };
case 0xfd: return { "set 7,l" };
case 0xfe: return { "set 7,(hl)" };
case 0xff: return { "set 7,a" };
}
return "";
}
#endif
-101
View File
@@ -1,101 +0,0 @@
enum {
A, F, AF,
B, C, BC,
D, E, DE,
H, L, HL,
SP, PC,
};
enum {
ZF, NF, HF, CF,
};
//register base class
//the idea here is to have all registers derive from a single base class.
//this allows construction of opcodes that can take any register as input or output,
//despite the fact that behind-the-scenes, special handling is done for eg: F, AF, HL, etc.
//registers can also be chained together: eg af = 0x0000 writes both a and f.
struct Register {
virtual operator unsigned() const = 0;
virtual unsigned operator=(unsigned x) = 0;
Register& operator=(const Register &x) { operator=((unsigned)x); return *this; }
unsigned operator++(int) { unsigned r = *this; operator=(*this + 1); return r; }
unsigned operator--(int) { unsigned r = *this; operator=(*this - 1); return r; }
unsigned operator++() { return operator=(*this + 1); }
unsigned operator--() { return operator=(*this - 1); }
unsigned operator |=(unsigned x) { return operator=(*this | x); }
unsigned operator ^=(unsigned x) { return operator=(*this ^ x); }
unsigned operator &=(unsigned x) { return operator=(*this & x); }
unsigned operator<<=(unsigned x) { return operator=(*this << x); }
unsigned operator>>=(unsigned x) { return operator=(*this >> x); }
unsigned operator +=(unsigned x) { return operator=(*this + x); }
unsigned operator -=(unsigned x) { return operator=(*this - x); }
unsigned operator *=(unsigned x) { return operator=(*this * x); }
unsigned operator /=(unsigned x) { return operator=(*this / x); }
unsigned operator %=(unsigned x) { return operator=(*this % x); }
};
struct Register8 : Register {
uint8 data;
operator unsigned() const { return data; }
unsigned operator=(unsigned x) { return data = x; }
};
struct RegisterF : Register {
bool z, n, h, c;
operator unsigned() const { return (z << 7) | (n << 6) | (h << 5) | (c << 4); }
unsigned operator=(unsigned x) { z = x & 0x80; n = x & 0x40; h = x & 0x20; c = x & 0x10; return *this; }
bool& operator[](unsigned r) {
static bool* table[] = { &z, &n, &h, &c };
return *table[r];
}
};
struct Register16 : Register {
uint16 data;
operator unsigned() const { return data; }
unsigned operator=(unsigned x) { return data = x; }
};
struct RegisterAF : Register {
Register8 &hi;
RegisterF &lo;
operator unsigned() const { return (hi << 8) | (lo << 0); }
unsigned operator=(unsigned x) { hi = x >> 8; lo = x >> 0; return *this; }
RegisterAF(Register8 &hi, RegisterF &lo) : hi(hi), lo(lo) {}
};
struct RegisterW : Register {
Register8 &hi, &lo;
operator unsigned() const { return (hi << 8) | (lo << 0); }
unsigned operator=(unsigned x) { hi = x >> 8; lo = x >> 0; return *this; }
RegisterW(Register8 &hi, Register8 &lo) : hi(hi), lo(lo) {}
};
struct Registers {
Register8 a;
RegisterF f;
RegisterAF af;
Register8 b;
Register8 c;
RegisterW bc;
Register8 d;
Register8 e;
RegisterW de;
Register8 h;
Register8 l;
RegisterW hl;
Register16 sp;
Register16 pc;
Register& operator[](unsigned r) {
static Register* table[] = { &a, &f, &af, &b, &c, &bc, &d, &e, &de, &h, &l, &hl, &sp, &pc };
return *table[r];
}
Registers() : af(a, f), bc(b, c), de(d, e), hl(h, l) {}
} r;
-519
View File
@@ -1,519 +0,0 @@
#ifdef CPU_CPP
void CPU::initialize_opcode_table() {
opcode_table[0x00] = &CPU::op_nop;
opcode_table[0x01] = &CPU::op_ld_rr_nn<BC>;
opcode_table[0x02] = &CPU::op_ld_rr_a<BC>;
opcode_table[0x03] = &CPU::op_inc_rr<BC>;
opcode_table[0x04] = &CPU::op_inc_r<B>;
opcode_table[0x05] = &CPU::op_dec_r<B>;
opcode_table[0x06] = &CPU::op_ld_r_n<B>;
opcode_table[0x07] = &CPU::op_rlca;
opcode_table[0x08] = &CPU::op_ld_nn_sp;
opcode_table[0x09] = &CPU::op_add_hl_rr<BC>;
opcode_table[0x0a] = &CPU::op_ld_a_rr<BC>;
opcode_table[0x0b] = &CPU::op_dec_rr<BC>;
opcode_table[0x0c] = &CPU::op_inc_r<C>;
opcode_table[0x0d] = &CPU::op_dec_r<C>;
opcode_table[0x0e] = &CPU::op_ld_r_n<C>;
opcode_table[0x0f] = &CPU::op_rrca;
opcode_table[0x10] = &CPU::op_stop;
opcode_table[0x11] = &CPU::op_ld_rr_nn<DE>;
opcode_table[0x12] = &CPU::op_ld_rr_a<DE>;
opcode_table[0x13] = &CPU::op_inc_rr<DE>;
opcode_table[0x14] = &CPU::op_inc_r<D>;
opcode_table[0x15] = &CPU::op_dec_r<D>;
opcode_table[0x16] = &CPU::op_ld_r_n<D>;
opcode_table[0x17] = &CPU::op_rla;
opcode_table[0x18] = &CPU::op_jr_n;
opcode_table[0x19] = &CPU::op_add_hl_rr<DE>;
opcode_table[0x1a] = &CPU::op_ld_a_rr<DE>;
opcode_table[0x1b] = &CPU::op_dec_rr<DE>;
opcode_table[0x1c] = &CPU::op_inc_r<E>;
opcode_table[0x1d] = &CPU::op_dec_r<E>;
opcode_table[0x1e] = &CPU::op_ld_r_n<E>;
opcode_table[0x1f] = &CPU::op_rra;
opcode_table[0x20] = &CPU::op_jr_f_n<ZF, 0>;
opcode_table[0x21] = &CPU::op_ld_rr_nn<HL>;
opcode_table[0x22] = &CPU::op_ldi_hl_a;
opcode_table[0x23] = &CPU::op_inc_rr<HL>;
opcode_table[0x24] = &CPU::op_inc_r<H>;
opcode_table[0x25] = &CPU::op_dec_r<H>;
opcode_table[0x26] = &CPU::op_ld_r_n<H>;
opcode_table[0x27] = &CPU::op_daa;
opcode_table[0x28] = &CPU::op_jr_f_n<ZF, 1>;
opcode_table[0x29] = &CPU::op_add_hl_rr<HL>;
opcode_table[0x2a] = &CPU::op_ldi_a_hl;
opcode_table[0x2b] = &CPU::op_dec_rr<HL>;
opcode_table[0x2c] = &CPU::op_inc_r<L>;
opcode_table[0x2d] = &CPU::op_dec_r<L>;
opcode_table[0x2e] = &CPU::op_ld_r_n<L>;
opcode_table[0x2f] = &CPU::op_cpl;
opcode_table[0x30] = &CPU::op_jr_f_n<CF, 0>;
opcode_table[0x31] = &CPU::op_ld_rr_nn<SP>;
opcode_table[0x32] = &CPU::op_ldd_hl_a;
opcode_table[0x33] = &CPU::op_inc_rr<SP>;
opcode_table[0x34] = &CPU::op_inc_hl;
opcode_table[0x35] = &CPU::op_dec_hl;
opcode_table[0x36] = &CPU::op_ld_hl_n;
opcode_table[0x37] = &CPU::op_scf;
opcode_table[0x38] = &CPU::op_jr_f_n<CF, 1>;
opcode_table[0x39] = &CPU::op_add_hl_rr<SP>;
opcode_table[0x3a] = &CPU::op_ldd_a_hl;
opcode_table[0x3b] = &CPU::op_dec_rr<SP>;
opcode_table[0x3c] = &CPU::op_inc_r<A>;
opcode_table[0x3d] = &CPU::op_dec_r<A>;
opcode_table[0x3e] = &CPU::op_ld_r_n<A>;
opcode_table[0x3f] = &CPU::op_ccf;
opcode_table[0x40] = &CPU::op_ld_r_r<B, B>;
opcode_table[0x41] = &CPU::op_ld_r_r<B, C>;
opcode_table[0x42] = &CPU::op_ld_r_r<B, D>;
opcode_table[0x43] = &CPU::op_ld_r_r<B, E>;
opcode_table[0x44] = &CPU::op_ld_r_r<B, H>;
opcode_table[0x45] = &CPU::op_ld_r_r<B, L>;
opcode_table[0x46] = &CPU::op_ld_r_hl<B>;
opcode_table[0x47] = &CPU::op_ld_r_r<B, A>;
opcode_table[0x48] = &CPU::op_ld_r_r<C, B>;
opcode_table[0x49] = &CPU::op_ld_r_r<C, C>;
opcode_table[0x4a] = &CPU::op_ld_r_r<C, D>;
opcode_table[0x4b] = &CPU::op_ld_r_r<C, E>;
opcode_table[0x4c] = &CPU::op_ld_r_r<C, H>;
opcode_table[0x4d] = &CPU::op_ld_r_r<C, L>;
opcode_table[0x4e] = &CPU::op_ld_r_hl<C>;
opcode_table[0x4f] = &CPU::op_ld_r_r<C, A>;
opcode_table[0x50] = &CPU::op_ld_r_r<D, B>;
opcode_table[0x51] = &CPU::op_ld_r_r<D, C>;
opcode_table[0x52] = &CPU::op_ld_r_r<D, D>;
opcode_table[0x53] = &CPU::op_ld_r_r<D, E>;
opcode_table[0x54] = &CPU::op_ld_r_r<D, H>;
opcode_table[0x55] = &CPU::op_ld_r_r<D, L>;
opcode_table[0x56] = &CPU::op_ld_r_hl<D>;
opcode_table[0x57] = &CPU::op_ld_r_r<D, A>;
opcode_table[0x58] = &CPU::op_ld_r_r<E, B>;
opcode_table[0x59] = &CPU::op_ld_r_r<E, C>;
opcode_table[0x5a] = &CPU::op_ld_r_r<E, D>;
opcode_table[0x5b] = &CPU::op_ld_r_r<E, E>;
opcode_table[0x5c] = &CPU::op_ld_r_r<E, H>;
opcode_table[0x5d] = &CPU::op_ld_r_r<E, L>;
opcode_table[0x5e] = &CPU::op_ld_r_hl<E>;
opcode_table[0x5f] = &CPU::op_ld_r_r<E, A>;
opcode_table[0x60] = &CPU::op_ld_r_r<H, B>;
opcode_table[0x61] = &CPU::op_ld_r_r<H, C>;
opcode_table[0x62] = &CPU::op_ld_r_r<H, D>;
opcode_table[0x63] = &CPU::op_ld_r_r<H, E>;
opcode_table[0x64] = &CPU::op_ld_r_r<H, H>;
opcode_table[0x65] = &CPU::op_ld_r_r<H, L>;
opcode_table[0x66] = &CPU::op_ld_r_hl<H>;
opcode_table[0x67] = &CPU::op_ld_r_r<H, A>;
opcode_table[0x68] = &CPU::op_ld_r_r<L, B>;
opcode_table[0x69] = &CPU::op_ld_r_r<L, C>;
opcode_table[0x6a] = &CPU::op_ld_r_r<L, D>;
opcode_table[0x6b] = &CPU::op_ld_r_r<L, E>;
opcode_table[0x6c] = &CPU::op_ld_r_r<L, H>;
opcode_table[0x6d] = &CPU::op_ld_r_r<L, L>;
opcode_table[0x6e] = &CPU::op_ld_r_hl<L>;
opcode_table[0x6f] = &CPU::op_ld_r_r<L, A>;
opcode_table[0x70] = &CPU::op_ld_hl_r<B>;
opcode_table[0x71] = &CPU::op_ld_hl_r<C>;
opcode_table[0x72] = &CPU::op_ld_hl_r<D>;
opcode_table[0x73] = &CPU::op_ld_hl_r<E>;
opcode_table[0x74] = &CPU::op_ld_hl_r<H>;
opcode_table[0x75] = &CPU::op_ld_hl_r<L>;
opcode_table[0x76] = &CPU::op_halt;
opcode_table[0x77] = &CPU::op_ld_hl_r<A>;
opcode_table[0x78] = &CPU::op_ld_r_r<A, B>;
opcode_table[0x79] = &CPU::op_ld_r_r<A, C>;
opcode_table[0x7a] = &CPU::op_ld_r_r<A, D>;
opcode_table[0x7b] = &CPU::op_ld_r_r<A, E>;
opcode_table[0x7c] = &CPU::op_ld_r_r<A, H>;
opcode_table[0x7d] = &CPU::op_ld_r_r<A, L>;
opcode_table[0x7e] = &CPU::op_ld_r_hl<A>;
opcode_table[0x7f] = &CPU::op_ld_r_r<A, A>;
opcode_table[0x80] = &CPU::op_add_a_r<B>;
opcode_table[0x81] = &CPU::op_add_a_r<C>;
opcode_table[0x82] = &CPU::op_add_a_r<D>;
opcode_table[0x83] = &CPU::op_add_a_r<E>;
opcode_table[0x84] = &CPU::op_add_a_r<H>;
opcode_table[0x85] = &CPU::op_add_a_r<L>;
opcode_table[0x86] = &CPU::op_add_a_hl;
opcode_table[0x87] = &CPU::op_add_a_r<A>;
opcode_table[0x88] = &CPU::op_adc_a_r<B>;
opcode_table[0x89] = &CPU::op_adc_a_r<C>;
opcode_table[0x8a] = &CPU::op_adc_a_r<D>;
opcode_table[0x8b] = &CPU::op_adc_a_r<E>;
opcode_table[0x8c] = &CPU::op_adc_a_r<H>;
opcode_table[0x8d] = &CPU::op_adc_a_r<L>;
opcode_table[0x8e] = &CPU::op_adc_a_hl;
opcode_table[0x8f] = &CPU::op_adc_a_r<A>;
opcode_table[0x90] = &CPU::op_sub_a_r<B>;
opcode_table[0x91] = &CPU::op_sub_a_r<C>;
opcode_table[0x92] = &CPU::op_sub_a_r<D>;
opcode_table[0x93] = &CPU::op_sub_a_r<E>;
opcode_table[0x94] = &CPU::op_sub_a_r<H>;
opcode_table[0x95] = &CPU::op_sub_a_r<L>;
opcode_table[0x96] = &CPU::op_sub_a_hl;
opcode_table[0x97] = &CPU::op_sub_a_r<A>;
opcode_table[0x98] = &CPU::op_sbc_a_r<B>;
opcode_table[0x99] = &CPU::op_sbc_a_r<C>;
opcode_table[0x9a] = &CPU::op_sbc_a_r<D>;
opcode_table[0x9b] = &CPU::op_sbc_a_r<E>;
opcode_table[0x9c] = &CPU::op_sbc_a_r<H>;
opcode_table[0x9d] = &CPU::op_sbc_a_r<L>;
opcode_table[0x9e] = &CPU::op_sbc_a_hl;
opcode_table[0x9f] = &CPU::op_sbc_a_r<A>;
opcode_table[0xa0] = &CPU::op_and_a_r<B>;
opcode_table[0xa1] = &CPU::op_and_a_r<C>;
opcode_table[0xa2] = &CPU::op_and_a_r<D>;
opcode_table[0xa3] = &CPU::op_and_a_r<E>;
opcode_table[0xa4] = &CPU::op_and_a_r<H>;
opcode_table[0xa5] = &CPU::op_and_a_r<L>;
opcode_table[0xa6] = &CPU::op_and_a_hl;
opcode_table[0xa7] = &CPU::op_and_a_r<A>;
opcode_table[0xa8] = &CPU::op_xor_a_r<B>;
opcode_table[0xa9] = &CPU::op_xor_a_r<C>;
opcode_table[0xaa] = &CPU::op_xor_a_r<D>;
opcode_table[0xab] = &CPU::op_xor_a_r<E>;
opcode_table[0xac] = &CPU::op_xor_a_r<H>;
opcode_table[0xad] = &CPU::op_xor_a_r<L>;
opcode_table[0xae] = &CPU::op_xor_a_hl;
opcode_table[0xaf] = &CPU::op_xor_a_r<A>;
opcode_table[0xb0] = &CPU::op_or_a_r<B>;
opcode_table[0xb1] = &CPU::op_or_a_r<C>;
opcode_table[0xb2] = &CPU::op_or_a_r<D>;
opcode_table[0xb3] = &CPU::op_or_a_r<E>;
opcode_table[0xb4] = &CPU::op_or_a_r<H>;
opcode_table[0xb5] = &CPU::op_or_a_r<L>;
opcode_table[0xb6] = &CPU::op_or_a_hl;
opcode_table[0xb7] = &CPU::op_or_a_r<A>;
opcode_table[0xb8] = &CPU::op_cp_a_r<B>;
opcode_table[0xb9] = &CPU::op_cp_a_r<C>;
opcode_table[0xba] = &CPU::op_cp_a_r<D>;
opcode_table[0xbb] = &CPU::op_cp_a_r<E>;
opcode_table[0xbc] = &CPU::op_cp_a_r<H>;
opcode_table[0xbd] = &CPU::op_cp_a_r<L>;
opcode_table[0xbe] = &CPU::op_cp_a_hl;
opcode_table[0xbf] = &CPU::op_cp_a_r<A>;
opcode_table[0xc0] = &CPU::op_ret_f<ZF, 0>;
opcode_table[0xc1] = &CPU::op_pop_rr<BC>;
opcode_table[0xc2] = &CPU::op_jp_f_nn<ZF, 0>;
opcode_table[0xc3] = &CPU::op_jp_nn;
opcode_table[0xc4] = &CPU::op_call_f_nn<ZF, 0>;
opcode_table[0xc5] = &CPU::op_push_rr<BC>;
opcode_table[0xc6] = &CPU::op_add_a_n;
opcode_table[0xc7] = &CPU::op_rst_n<0x00>;
opcode_table[0xc8] = &CPU::op_ret_f<ZF, 1>;
opcode_table[0xc9] = &CPU::op_ret;
opcode_table[0xca] = &CPU::op_jp_f_nn<ZF, 1>;
opcode_table[0xcb] = &CPU::op_cb;
opcode_table[0xcc] = &CPU::op_call_f_nn<ZF, 1>;
opcode_table[0xcd] = &CPU::op_call_nn;
opcode_table[0xce] = &CPU::op_adc_a_n;
opcode_table[0xcf] = &CPU::op_rst_n<0x08>;
opcode_table[0xd0] = &CPU::op_ret_f<CF, 0>;
opcode_table[0xd1] = &CPU::op_pop_rr<DE>;
opcode_table[0xd2] = &CPU::op_jp_f_nn<CF, 0>;
opcode_table[0xd3] = &CPU::op_xx;
opcode_table[0xd4] = &CPU::op_call_f_nn<CF, 0>;
opcode_table[0xd5] = &CPU::op_push_rr<DE>;
opcode_table[0xd6] = &CPU::op_sub_a_n;
opcode_table[0xd7] = &CPU::op_rst_n<0x10>;
opcode_table[0xd8] = &CPU::op_ret_f<CF, 1>;
opcode_table[0xd9] = &CPU::op_reti;
opcode_table[0xda] = &CPU::op_jp_f_nn<CF, 1>;
opcode_table[0xdb] = &CPU::op_xx;
opcode_table[0xdc] = &CPU::op_call_f_nn<CF, 1>;
opcode_table[0xdd] = &CPU::op_xx;
opcode_table[0xde] = &CPU::op_sbc_a_n;
opcode_table[0xdf] = &CPU::op_rst_n<0x18>;
opcode_table[0xe0] = &CPU::op_ld_ffn_a;
opcode_table[0xe1] = &CPU::op_pop_rr<HL>;
opcode_table[0xe2] = &CPU::op_ld_ffc_a;
opcode_table[0xe3] = &CPU::op_xx;
opcode_table[0xe4] = &CPU::op_xx;
opcode_table[0xe5] = &CPU::op_push_rr<HL>;
opcode_table[0xe6] = &CPU::op_and_a_n;
opcode_table[0xe7] = &CPU::op_rst_n<0x20>;
opcode_table[0xe8] = &CPU::op_add_sp_n;
opcode_table[0xe9] = &CPU::op_jp_hl;
opcode_table[0xea] = &CPU::op_ld_nn_a;
opcode_table[0xeb] = &CPU::op_xx;
opcode_table[0xec] = &CPU::op_xx;
opcode_table[0xed] = &CPU::op_xx;
opcode_table[0xee] = &CPU::op_xor_a_n;
opcode_table[0xef] = &CPU::op_rst_n<0x28>;
opcode_table[0xf0] = &CPU::op_ld_a_ffn;
opcode_table[0xf1] = &CPU::op_pop_rr<AF>;
opcode_table[0xf2] = &CPU::op_ld_a_ffc;
opcode_table[0xf3] = &CPU::op_di;
opcode_table[0xf4] = &CPU::op_xx;
opcode_table[0xf5] = &CPU::op_push_rr<AF>;
opcode_table[0xf6] = &CPU::op_or_a_n;
opcode_table[0xf7] = &CPU::op_rst_n<0x30>;
opcode_table[0xf8] = &CPU::op_ld_hl_sp_n;
opcode_table[0xf9] = &CPU::op_ld_sp_hl;
opcode_table[0xfa] = &CPU::op_ld_a_nn;
opcode_table[0xfb] = &CPU::op_ei;
opcode_table[0xfc] = &CPU::op_xx;
opcode_table[0xfd] = &CPU::op_xx;
opcode_table[0xfe] = &CPU::op_cp_a_n;
opcode_table[0xff] = &CPU::op_rst_n<0x38>;
opcode_table_cb[0x00] = &CPU::op_rlc_r<B>;
opcode_table_cb[0x01] = &CPU::op_rlc_r<C>;
opcode_table_cb[0x02] = &CPU::op_rlc_r<D>;
opcode_table_cb[0x03] = &CPU::op_rlc_r<E>;
opcode_table_cb[0x04] = &CPU::op_rlc_r<H>;
opcode_table_cb[0x05] = &CPU::op_rlc_r<L>;
opcode_table_cb[0x06] = &CPU::op_rlc_hl;
opcode_table_cb[0x07] = &CPU::op_rlc_r<A>;
opcode_table_cb[0x08] = &CPU::op_rrc_r<B>;
opcode_table_cb[0x09] = &CPU::op_rrc_r<C>;
opcode_table_cb[0x0a] = &CPU::op_rrc_r<D>;
opcode_table_cb[0x0b] = &CPU::op_rrc_r<E>;
opcode_table_cb[0x0c] = &CPU::op_rrc_r<H>;
opcode_table_cb[0x0d] = &CPU::op_rrc_r<L>;
opcode_table_cb[0x0e] = &CPU::op_rrc_hl;
opcode_table_cb[0x0f] = &CPU::op_rrc_r<A>;
opcode_table_cb[0x10] = &CPU::op_rl_r<B>;
opcode_table_cb[0x11] = &CPU::op_rl_r<C>;
opcode_table_cb[0x12] = &CPU::op_rl_r<D>;
opcode_table_cb[0x13] = &CPU::op_rl_r<E>;
opcode_table_cb[0x14] = &CPU::op_rl_r<H>;
opcode_table_cb[0x15] = &CPU::op_rl_r<L>;
opcode_table_cb[0x16] = &CPU::op_rl_hl;
opcode_table_cb[0x17] = &CPU::op_rl_r<A>;
opcode_table_cb[0x18] = &CPU::op_rr_r<B>;
opcode_table_cb[0x19] = &CPU::op_rr_r<C>;
opcode_table_cb[0x1a] = &CPU::op_rr_r<D>;
opcode_table_cb[0x1b] = &CPU::op_rr_r<E>;
opcode_table_cb[0x1c] = &CPU::op_rr_r<H>;
opcode_table_cb[0x1d] = &CPU::op_rr_r<L>;
opcode_table_cb[0x1e] = &CPU::op_rr_hl;
opcode_table_cb[0x1f] = &CPU::op_rr_r<A>;
opcode_table_cb[0x20] = &CPU::op_sla_r<B>;
opcode_table_cb[0x21] = &CPU::op_sla_r<C>;
opcode_table_cb[0x22] = &CPU::op_sla_r<D>;
opcode_table_cb[0x23] = &CPU::op_sla_r<E>;
opcode_table_cb[0x24] = &CPU::op_sla_r<H>;
opcode_table_cb[0x25] = &CPU::op_sla_r<L>;
opcode_table_cb[0x26] = &CPU::op_sla_hl;
opcode_table_cb[0x27] = &CPU::op_sla_r<A>;
opcode_table_cb[0x28] = &CPU::op_sra_r<B>;
opcode_table_cb[0x29] = &CPU::op_sra_r<C>;
opcode_table_cb[0x2a] = &CPU::op_sra_r<D>;
opcode_table_cb[0x2b] = &CPU::op_sra_r<E>;
opcode_table_cb[0x2c] = &CPU::op_sra_r<H>;
opcode_table_cb[0x2d] = &CPU::op_sra_r<L>;
opcode_table_cb[0x2e] = &CPU::op_sra_hl;
opcode_table_cb[0x2f] = &CPU::op_sra_r<A>;
opcode_table_cb[0x30] = &CPU::op_swap_r<B>;
opcode_table_cb[0x31] = &CPU::op_swap_r<C>;
opcode_table_cb[0x32] = &CPU::op_swap_r<D>;
opcode_table_cb[0x33] = &CPU::op_swap_r<E>;
opcode_table_cb[0x34] = &CPU::op_swap_r<H>;
opcode_table_cb[0x35] = &CPU::op_swap_r<L>;
opcode_table_cb[0x36] = &CPU::op_swap_hl;
opcode_table_cb[0x37] = &CPU::op_swap_r<A>;
opcode_table_cb[0x38] = &CPU::op_srl_r<B>;
opcode_table_cb[0x39] = &CPU::op_srl_r<C>;
opcode_table_cb[0x3a] = &CPU::op_srl_r<D>;
opcode_table_cb[0x3b] = &CPU::op_srl_r<E>;
opcode_table_cb[0x3c] = &CPU::op_srl_r<H>;
opcode_table_cb[0x3d] = &CPU::op_srl_r<L>;
opcode_table_cb[0x3e] = &CPU::op_srl_hl;
opcode_table_cb[0x3f] = &CPU::op_srl_r<A>;
opcode_table_cb[0x40] = &CPU::op_bit_n_r<0, B>;
opcode_table_cb[0x41] = &CPU::op_bit_n_r<0, C>;
opcode_table_cb[0x42] = &CPU::op_bit_n_r<0, D>;
opcode_table_cb[0x43] = &CPU::op_bit_n_r<0, E>;
opcode_table_cb[0x44] = &CPU::op_bit_n_r<0, H>;
opcode_table_cb[0x45] = &CPU::op_bit_n_r<0, L>;
opcode_table_cb[0x46] = &CPU::op_bit_n_hl<0>;
opcode_table_cb[0x47] = &CPU::op_bit_n_r<0, A>;
opcode_table_cb[0x48] = &CPU::op_bit_n_r<1, B>;
opcode_table_cb[0x49] = &CPU::op_bit_n_r<1, C>;
opcode_table_cb[0x4a] = &CPU::op_bit_n_r<1, D>;
opcode_table_cb[0x4b] = &CPU::op_bit_n_r<1, E>;
opcode_table_cb[0x4c] = &CPU::op_bit_n_r<1, H>;
opcode_table_cb[0x4d] = &CPU::op_bit_n_r<1, L>;
opcode_table_cb[0x4e] = &CPU::op_bit_n_hl<1>;
opcode_table_cb[0x4f] = &CPU::op_bit_n_r<1, A>;
opcode_table_cb[0x50] = &CPU::op_bit_n_r<2, B>;
opcode_table_cb[0x51] = &CPU::op_bit_n_r<2, C>;
opcode_table_cb[0x52] = &CPU::op_bit_n_r<2, D>;
opcode_table_cb[0x53] = &CPU::op_bit_n_r<2, E>;
opcode_table_cb[0x54] = &CPU::op_bit_n_r<2, H>;
opcode_table_cb[0x55] = &CPU::op_bit_n_r<2, L>;
opcode_table_cb[0x56] = &CPU::op_bit_n_hl<2>;
opcode_table_cb[0x57] = &CPU::op_bit_n_r<2, A>;
opcode_table_cb[0x58] = &CPU::op_bit_n_r<3, B>;
opcode_table_cb[0x59] = &CPU::op_bit_n_r<3, C>;
opcode_table_cb[0x5a] = &CPU::op_bit_n_r<3, D>;
opcode_table_cb[0x5b] = &CPU::op_bit_n_r<3, E>;
opcode_table_cb[0x5c] = &CPU::op_bit_n_r<3, H>;
opcode_table_cb[0x5d] = &CPU::op_bit_n_r<3, L>;
opcode_table_cb[0x5e] = &CPU::op_bit_n_hl<3>;
opcode_table_cb[0x5f] = &CPU::op_bit_n_r<3, A>;
opcode_table_cb[0x60] = &CPU::op_bit_n_r<4, B>;
opcode_table_cb[0x61] = &CPU::op_bit_n_r<4, C>;
opcode_table_cb[0x62] = &CPU::op_bit_n_r<4, D>;
opcode_table_cb[0x63] = &CPU::op_bit_n_r<4, E>;
opcode_table_cb[0x64] = &CPU::op_bit_n_r<4, H>;
opcode_table_cb[0x65] = &CPU::op_bit_n_r<4, L>;
opcode_table_cb[0x66] = &CPU::op_bit_n_hl<4>;
opcode_table_cb[0x67] = &CPU::op_bit_n_r<4, A>;
opcode_table_cb[0x68] = &CPU::op_bit_n_r<5, B>;
opcode_table_cb[0x69] = &CPU::op_bit_n_r<5, C>;
opcode_table_cb[0x6a] = &CPU::op_bit_n_r<5, D>;
opcode_table_cb[0x6b] = &CPU::op_bit_n_r<5, E>;
opcode_table_cb[0x6c] = &CPU::op_bit_n_r<5, H>;
opcode_table_cb[0x6d] = &CPU::op_bit_n_r<5, L>;
opcode_table_cb[0x6e] = &CPU::op_bit_n_hl<5>;
opcode_table_cb[0x6f] = &CPU::op_bit_n_r<5, A>;
opcode_table_cb[0x70] = &CPU::op_bit_n_r<6, B>;
opcode_table_cb[0x71] = &CPU::op_bit_n_r<6, C>;
opcode_table_cb[0x72] = &CPU::op_bit_n_r<6, D>;
opcode_table_cb[0x73] = &CPU::op_bit_n_r<6, E>;
opcode_table_cb[0x74] = &CPU::op_bit_n_r<6, H>;
opcode_table_cb[0x75] = &CPU::op_bit_n_r<6, L>;
opcode_table_cb[0x76] = &CPU::op_bit_n_hl<6>;
opcode_table_cb[0x77] = &CPU::op_bit_n_r<6, A>;
opcode_table_cb[0x78] = &CPU::op_bit_n_r<7, B>;
opcode_table_cb[0x79] = &CPU::op_bit_n_r<7, C>;
opcode_table_cb[0x7a] = &CPU::op_bit_n_r<7, D>;
opcode_table_cb[0x7b] = &CPU::op_bit_n_r<7, E>;
opcode_table_cb[0x7c] = &CPU::op_bit_n_r<7, H>;
opcode_table_cb[0x7d] = &CPU::op_bit_n_r<7, L>;
opcode_table_cb[0x7e] = &CPU::op_bit_n_hl<7>;
opcode_table_cb[0x7f] = &CPU::op_bit_n_r<7, A>;
opcode_table_cb[0x80] = &CPU::op_res_n_r<0, B>;
opcode_table_cb[0x81] = &CPU::op_res_n_r<0, C>;
opcode_table_cb[0x82] = &CPU::op_res_n_r<0, D>;
opcode_table_cb[0x83] = &CPU::op_res_n_r<0, E>;
opcode_table_cb[0x84] = &CPU::op_res_n_r<0, H>;
opcode_table_cb[0x85] = &CPU::op_res_n_r<0, L>;
opcode_table_cb[0x86] = &CPU::op_res_n_hl<0>;
opcode_table_cb[0x87] = &CPU::op_res_n_r<0, A>;
opcode_table_cb[0x88] = &CPU::op_res_n_r<1, B>;
opcode_table_cb[0x89] = &CPU::op_res_n_r<1, C>;
opcode_table_cb[0x8a] = &CPU::op_res_n_r<1, D>;
opcode_table_cb[0x8b] = &CPU::op_res_n_r<1, E>;
opcode_table_cb[0x8c] = &CPU::op_res_n_r<1, H>;
opcode_table_cb[0x8d] = &CPU::op_res_n_r<1, L>;
opcode_table_cb[0x8e] = &CPU::op_res_n_hl<1>;
opcode_table_cb[0x8f] = &CPU::op_res_n_r<1, A>;
opcode_table_cb[0x90] = &CPU::op_res_n_r<2, B>;
opcode_table_cb[0x91] = &CPU::op_res_n_r<2, C>;
opcode_table_cb[0x92] = &CPU::op_res_n_r<2, D>;
opcode_table_cb[0x93] = &CPU::op_res_n_r<2, E>;
opcode_table_cb[0x94] = &CPU::op_res_n_r<2, H>;
opcode_table_cb[0x95] = &CPU::op_res_n_r<2, L>;
opcode_table_cb[0x96] = &CPU::op_res_n_hl<2>;
opcode_table_cb[0x97] = &CPU::op_res_n_r<2, A>;
opcode_table_cb[0x98] = &CPU::op_res_n_r<3, B>;
opcode_table_cb[0x99] = &CPU::op_res_n_r<3, C>;
opcode_table_cb[0x9a] = &CPU::op_res_n_r<3, D>;
opcode_table_cb[0x9b] = &CPU::op_res_n_r<3, E>;
opcode_table_cb[0x9c] = &CPU::op_res_n_r<3, H>;
opcode_table_cb[0x9d] = &CPU::op_res_n_r<3, L>;
opcode_table_cb[0x9e] = &CPU::op_res_n_hl<3>;
opcode_table_cb[0x9f] = &CPU::op_res_n_r<3, A>;
opcode_table_cb[0xa0] = &CPU::op_res_n_r<4, B>;
opcode_table_cb[0xa1] = &CPU::op_res_n_r<4, C>;
opcode_table_cb[0xa2] = &CPU::op_res_n_r<4, D>;
opcode_table_cb[0xa3] = &CPU::op_res_n_r<4, E>;
opcode_table_cb[0xa4] = &CPU::op_res_n_r<4, H>;
opcode_table_cb[0xa5] = &CPU::op_res_n_r<4, L>;
opcode_table_cb[0xa6] = &CPU::op_res_n_hl<4>;
opcode_table_cb[0xa7] = &CPU::op_res_n_r<4, A>;
opcode_table_cb[0xa8] = &CPU::op_res_n_r<5, B>;
opcode_table_cb[0xa9] = &CPU::op_res_n_r<5, C>;
opcode_table_cb[0xaa] = &CPU::op_res_n_r<5, D>;
opcode_table_cb[0xab] = &CPU::op_res_n_r<5, E>;
opcode_table_cb[0xac] = &CPU::op_res_n_r<5, H>;
opcode_table_cb[0xad] = &CPU::op_res_n_r<5, L>;
opcode_table_cb[0xae] = &CPU::op_res_n_hl<5>;
opcode_table_cb[0xaf] = &CPU::op_res_n_r<5, A>;
opcode_table_cb[0xb0] = &CPU::op_res_n_r<6, B>;
opcode_table_cb[0xb1] = &CPU::op_res_n_r<6, C>;
opcode_table_cb[0xb2] = &CPU::op_res_n_r<6, D>;
opcode_table_cb[0xb3] = &CPU::op_res_n_r<6, E>;
opcode_table_cb[0xb4] = &CPU::op_res_n_r<6, H>;
opcode_table_cb[0xb5] = &CPU::op_res_n_r<6, L>;
opcode_table_cb[0xb6] = &CPU::op_res_n_hl<6>;
opcode_table_cb[0xb7] = &CPU::op_res_n_r<6, A>;
opcode_table_cb[0xb8] = &CPU::op_res_n_r<7, B>;
opcode_table_cb[0xb9] = &CPU::op_res_n_r<7, C>;
opcode_table_cb[0xba] = &CPU::op_res_n_r<7, D>;
opcode_table_cb[0xbb] = &CPU::op_res_n_r<7, E>;
opcode_table_cb[0xbc] = &CPU::op_res_n_r<7, H>;
opcode_table_cb[0xbd] = &CPU::op_res_n_r<7, L>;
opcode_table_cb[0xbe] = &CPU::op_res_n_hl<7>;
opcode_table_cb[0xbf] = &CPU::op_res_n_r<7, A>;
opcode_table_cb[0xc0] = &CPU::op_set_n_r<0, B>;
opcode_table_cb[0xc1] = &CPU::op_set_n_r<0, C>;
opcode_table_cb[0xc2] = &CPU::op_set_n_r<0, D>;
opcode_table_cb[0xc3] = &CPU::op_set_n_r<0, E>;
opcode_table_cb[0xc4] = &CPU::op_set_n_r<0, H>;
opcode_table_cb[0xc5] = &CPU::op_set_n_r<0, L>;
opcode_table_cb[0xc6] = &CPU::op_set_n_hl<0>;
opcode_table_cb[0xc7] = &CPU::op_set_n_r<0, A>;
opcode_table_cb[0xc8] = &CPU::op_set_n_r<1, B>;
opcode_table_cb[0xc9] = &CPU::op_set_n_r<1, C>;
opcode_table_cb[0xca] = &CPU::op_set_n_r<1, D>;
opcode_table_cb[0xcb] = &CPU::op_set_n_r<1, E>;
opcode_table_cb[0xcc] = &CPU::op_set_n_r<1, H>;
opcode_table_cb[0xcd] = &CPU::op_set_n_r<1, L>;
opcode_table_cb[0xce] = &CPU::op_set_n_hl<1>;
opcode_table_cb[0xcf] = &CPU::op_set_n_r<1, A>;
opcode_table_cb[0xd0] = &CPU::op_set_n_r<2, B>;
opcode_table_cb[0xd1] = &CPU::op_set_n_r<2, C>;
opcode_table_cb[0xd2] = &CPU::op_set_n_r<2, D>;
opcode_table_cb[0xd3] = &CPU::op_set_n_r<2, E>;
opcode_table_cb[0xd4] = &CPU::op_set_n_r<2, H>;
opcode_table_cb[0xd5] = &CPU::op_set_n_r<2, L>;
opcode_table_cb[0xd6] = &CPU::op_set_n_hl<2>;
opcode_table_cb[0xd7] = &CPU::op_set_n_r<2, A>;
opcode_table_cb[0xd8] = &CPU::op_set_n_r<3, B>;
opcode_table_cb[0xd9] = &CPU::op_set_n_r<3, C>;
opcode_table_cb[0xda] = &CPU::op_set_n_r<3, D>;
opcode_table_cb[0xdb] = &CPU::op_set_n_r<3, E>;
opcode_table_cb[0xdc] = &CPU::op_set_n_r<3, H>;
opcode_table_cb[0xdd] = &CPU::op_set_n_r<3, L>;
opcode_table_cb[0xde] = &CPU::op_set_n_hl<3>;
opcode_table_cb[0xdf] = &CPU::op_set_n_r<3, A>;
opcode_table_cb[0xe0] = &CPU::op_set_n_r<4, B>;
opcode_table_cb[0xe1] = &CPU::op_set_n_r<4, C>;
opcode_table_cb[0xe2] = &CPU::op_set_n_r<4, D>;
opcode_table_cb[0xe3] = &CPU::op_set_n_r<4, E>;
opcode_table_cb[0xe4] = &CPU::op_set_n_r<4, H>;
opcode_table_cb[0xe5] = &CPU::op_set_n_r<4, L>;
opcode_table_cb[0xe6] = &CPU::op_set_n_hl<4>;
opcode_table_cb[0xe7] = &CPU::op_set_n_r<4, A>;
opcode_table_cb[0xe8] = &CPU::op_set_n_r<5, B>;
opcode_table_cb[0xe9] = &CPU::op_set_n_r<5, C>;
opcode_table_cb[0xea] = &CPU::op_set_n_r<5, D>;
opcode_table_cb[0xeb] = &CPU::op_set_n_r<5, E>;
opcode_table_cb[0xec] = &CPU::op_set_n_r<5, H>;
opcode_table_cb[0xed] = &CPU::op_set_n_r<5, L>;
opcode_table_cb[0xee] = &CPU::op_set_n_hl<5>;
opcode_table_cb[0xef] = &CPU::op_set_n_r<5, A>;
opcode_table_cb[0xf0] = &CPU::op_set_n_r<6, B>;
opcode_table_cb[0xf1] = &CPU::op_set_n_r<6, C>;
opcode_table_cb[0xf2] = &CPU::op_set_n_r<6, D>;
opcode_table_cb[0xf3] = &CPU::op_set_n_r<6, E>;
opcode_table_cb[0xf4] = &CPU::op_set_n_r<6, H>;
opcode_table_cb[0xf5] = &CPU::op_set_n_r<6, L>;
opcode_table_cb[0xf6] = &CPU::op_set_n_hl<6>;
opcode_table_cb[0xf7] = &CPU::op_set_n_r<6, A>;
opcode_table_cb[0xf8] = &CPU::op_set_n_r<7, B>;
opcode_table_cb[0xf9] = &CPU::op_set_n_r<7, C>;
opcode_table_cb[0xfa] = &CPU::op_set_n_r<7, D>;
opcode_table_cb[0xfb] = &CPU::op_set_n_r<7, E>;
opcode_table_cb[0xfc] = &CPU::op_set_n_r<7, H>;
opcode_table_cb[0xfd] = &CPU::op_set_n_r<7, L>;
opcode_table_cb[0xfe] = &CPU::op_set_n_hl<7>;
opcode_table_cb[0xff] = &CPU::op_set_n_r<7, A>;
}
#endif
-157
View File
@@ -1,157 +0,0 @@
#include <gameboy/gameboy.hpp>
#define CPU_CPP
namespace GameBoy {
#include "core/core.cpp"
#include "mmio/mmio.cpp"
#include "timing/timing.cpp"
#include "serialization.cpp"
CPU cpu;
void CPU::Main() {
cpu.main();
}
void CPU::main() {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::CPU) {
scheduler.sync = Scheduler::SynchronizeMode::All;
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
if(trace) print(disassemble(r[PC]), "\n");
interrupt_test();
uint8 opcode = op_read(r[PC]++);
(this->*opcode_table[opcode])();
}
}
void CPU::interrupt_raise(CPU::Interrupt id) {
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;
}
}
void CPU::interrupt_test() {
if(status.ime) {
if(status.interrupt_request_vblank && status.interrupt_enable_vblank) {
status.interrupt_request_vblank = 0;
return interrupt_exec(0x0040);
}
if(status.interrupt_request_stat && status.interrupt_enable_stat) {
status.interrupt_request_stat = 0;
return interrupt_exec(0x0048);
}
if(status.interrupt_request_timer && status.interrupt_enable_timer) {
status.interrupt_request_timer = 0;
return interrupt_exec(0x0050);
}
if(status.interrupt_request_serial && status.interrupt_enable_serial) {
status.interrupt_request_serial = 0;
return interrupt_exec(0x0058);
}
if(status.interrupt_request_joypad && status.interrupt_enable_joypad) {
status.interrupt_request_joypad = 0;
return interrupt_exec(0x0060);
}
}
}
void CPU::interrupt_exec(uint16 pc) {
status.ime = 0;
op_write(--r[SP], r[PC] >> 8);
op_write(--r[SP], r[PC] >> 0);
r[PC] = pc;
op_io();
op_io();
op_io();
}
void CPU::power() {
create(Main, 4194304);
for(unsigned n = 0xc000; n <= 0xdfff; n++) bus.mmio[n] = this; //WRAM
for(unsigned n = 0xe000; n <= 0xfdff; n++) bus.mmio[n] = this; //WRAM (mirror)
for(unsigned n = 0xff00; n <= 0xff0f; n++) bus.mmio[n] = this; //MMIO
for(unsigned n = 0xff80; n <= 0xffff; n++) bus.mmio[n] = this; //HRAM+IE
for(unsigned n = 0; n < 8192; n++) wram[n] = 0x00;
for(unsigned n = 0; n < 128; n++) hram[n] = 0x00;
r[PC] = 0x0000;
r[SP] = 0x0000;
r[AF] = 0x0000;
r[BC] = 0x0000;
r[DE] = 0x0000;
r[HL] = 0x0000;
status.clock = 0;
status.halt = false;
status.stop = false;
status.ei = false;
status.ime = 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;
status.tma = 0;
status.timer_enable = 0;
status.timer_clock = 0;
status.interrupt_request_joypad = 0;
status.interrupt_request_serial = 0;
status.interrupt_request_timer = 0;
status.interrupt_request_stat = 0;
status.interrupt_request_vblank = 0;
status.interrupt_enable_joypad = 0;
status.interrupt_enable_serial = 0;
status.interrupt_enable_timer = 0;
status.interrupt_enable_stat = 0;
status.interrupt_enable_vblank = 0;
}
CPU::CPU() : trace(false) {
initialize_opcode_table();
}
}
-79
View File
@@ -1,79 +0,0 @@
struct CPU : Processor, MMIO {
#include "core/core.hpp"
#include "mmio/mmio.hpp"
#include "timing/timing.hpp"
bool trace;
enum class Interrupt : unsigned {
Vblank,
Stat,
Timer,
Serial,
Joypad,
};
struct Status {
unsigned clock;
bool halt;
bool stop;
bool ei;
bool ime;
//$ff00 JOYP
bool p15;
bool p14;
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;
//$ff05 TIMA
uint8 tima;
//$ff06 TMA
uint8 tma;
//$ff07 TAC
bool timer_enable;
unsigned timer_clock;
//$ff0f IF
bool interrupt_request_joypad;
bool interrupt_request_serial;
bool interrupt_request_timer;
bool interrupt_request_stat;
bool interrupt_request_vblank;
//$ffff IE
bool interrupt_enable_joypad;
bool interrupt_enable_serial;
bool interrupt_enable_timer;
bool interrupt_enable_stat;
bool interrupt_enable_vblank;
} status;
uint8 wram[8192];
uint8 hram[128];
static void Main();
void main();
void interrupt_raise(Interrupt id);
void interrupt_test();
void interrupt_exec(uint16 pc);
void power();
void serialize(serializer&);
CPU();
};
extern CPU cpu;
-144
View File
@@ -1,144 +0,0 @@
#ifdef CPU_CPP
void CPU::mmio_joyp_poll() {
unsigned button = 0, dpad = 0;
button |= interface->inputPoll((unsigned)Input::Start) << 3;
button |= interface->inputPoll((unsigned)Input::Select) << 2;
button |= interface->inputPoll((unsigned)Input::B) << 1;
button |= interface->inputPoll((unsigned)Input::A) << 0;
dpad |= interface->inputPoll((unsigned)Input::Down) << 3;
dpad |= interface->inputPoll((unsigned)Input::Up) << 2;
dpad |= interface->inputPoll((unsigned)Input::Left) << 1;
dpad |= interface->inputPoll((unsigned)Input::Right) << 0;
status.joyp = 0x0f;
if(status.p15 == 1 && status.p14 == 1) status.joyp -= status.mlt_req;
if(status.p15 == 0) status.joyp &= button ^ 0x0f;
if(status.p14 == 0) status.joyp &= dpad ^ 0x0f;
if(status.joyp != 0x0f) interrupt_raise(Interrupt::Joypad);
}
uint8 CPU::mmio_read(uint16 addr) {
if(addr >= 0xc000 && addr <= 0xdfff) return wram[addr & 0x1fff];
if(addr >= 0xe000 && addr <= 0xfdff) return wram[addr & 0x1fff];
if(addr >= 0xff80 && addr <= 0xfffe) return hram[addr & 0x7f];
if(addr == 0xff00) { //JOYP
return (status.p15 << 5)
| (status.p14 << 4)
| (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;
}
if(addr == 0xff05) { //TIMA
return status.tima;
}
if(addr == 0xff06) { //TMA
return status.tma;
}
if(addr == 0xff07) { //TAC
return (status.timer_enable << 2)
| (status.timer_clock << 0);
}
if(addr == 0xff0f) { //IF
return (status.interrupt_request_joypad << 4)
| (status.interrupt_request_serial << 3)
| (status.interrupt_request_timer << 2)
| (status.interrupt_request_stat << 1)
| (status.interrupt_request_vblank << 0);
}
if(addr == 0xffff) { //IE
return (status.interrupt_enable_joypad << 4)
| (status.interrupt_enable_serial << 3)
| (status.interrupt_enable_timer << 2)
| (status.interrupt_enable_stat << 1)
| (status.interrupt_enable_vblank << 0);
}
return 0x00;
}
void CPU::mmio_write(uint16 addr, uint8 data) {
if(addr >= 0xc000 && addr <= 0xdfff) { wram[addr & 0x1fff] = data; return; }
if(addr >= 0xe000 && addr <= 0xfdff) { wram[addr & 0x1fff] = data; return; }
if(addr >= 0xff80 && addr <= 0xfffe) { hram[addr & 0x7f] = data; return; }
if(addr == 0xff00) { //JOYP
status.p15 = data & 0x20;
status.p14 = data & 0x10;
interface->joypWrite(status.p15, status.p14);
mmio_joyp_poll();
return;
}
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;
}
if(addr == 0xff04) { //DIV
status.div = 0;
return;
}
if(addr == 0xff05) { //TIMA
status.tima = data;
return;
}
if(addr == 0xff06) { //TMA
status.tma = data;
return;
}
if(addr == 0xff07) { //TAC
status.timer_enable = data & 0x04;
status.timer_clock = data & 0x03;
return;
}
if(addr == 0xff0f) { //IF
status.interrupt_request_joypad = data & 0x10;
status.interrupt_request_serial = data & 0x08;
status.interrupt_request_timer = data & 0x04;
status.interrupt_request_stat = data & 0x02;
status.interrupt_request_vblank = data & 0x01;
return;
}
if(addr == 0xffff) { //IE
status.interrupt_enable_joypad = data & 0x10;
status.interrupt_enable_serial = data & 0x08;
status.interrupt_enable_timer = data & 0x04;
status.interrupt_enable_stat = data & 0x02;
status.interrupt_enable_vblank = data & 0x01;
return;
}
}
#endif
-3
View File
@@ -1,3 +0,0 @@
void mmio_joyp_poll();
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
-57
View File
@@ -1,57 +0,0 @@
#ifdef CPU_CPP
void CPU::serialize(serializer &s) {
s.array(wram);
s.array(hram);
s.integer(r.a.data);
s.integer(r.f.z);
s.integer(r.f.n);
s.integer(r.f.h);
s.integer(r.f.c);
s.integer(r.b.data);
s.integer(r.c.data);
s.integer(r.d.data);
s.integer(r.e.data);
s.integer(r.h.data);
s.integer(r.l.data);
s.integer(r.sp.data);
s.integer(r.pc.data);
s.integer(status.clock);
s.integer(status.halt);
s.integer(status.stop);
s.integer(status.ei);
s.integer(status.ime);
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);
s.integer(status.timer_enable);
s.integer(status.timer_clock);
s.integer(status.interrupt_request_joypad);
s.integer(status.interrupt_request_serial);
s.integer(status.interrupt_request_timer);
s.integer(status.interrupt_request_stat);
s.integer(status.interrupt_request_vblank);
s.integer(status.interrupt_enable_joypad);
s.integer(status.interrupt_enable_serial);
s.integer(status.interrupt_enable_timer);
s.integer(status.interrupt_enable_stat);
s.integer(status.interrupt_enable_vblank);
}
#endif
-28
View File
@@ -1,28 +0,0 @@
#ifdef CPU_CPP
void CPU::op_io() {
cycle_edge();
add_clocks(4);
}
uint8 CPU::op_read(uint16 addr) {
cycle_edge();
uint8 r = bus.read(addr);
add_clocks(4);
return r;
}
void CPU::op_write(uint16 addr, uint8 data) {
cycle_edge();
bus.write(addr, data);
add_clocks(4);
}
void CPU::cycle_edge() {
if(status.ei) {
status.ei = false;
status.ime = 1;
}
}
#endif
-82
View File
@@ -1,82 +0,0 @@
//4194304hz (4 * 1024 * 1024)
//70224 clocks/frame
// 456 clocks/scanline
// 154 scanlines/frame
#ifdef CPU_CPP
#include "opcode.cpp"
void CPU::add_clocks(unsigned clocks) {
system.clocks_executed += clocks;
scheduler.exit(Scheduler::ExitReason::StepEvent);
status.clock += clocks;
if(status.clock >= 4194304) {
status.clock -= 4194304;
cartridge.mbc3.second();
}
//4194304 / N(hz) - 1 = mask
if((status.clock & 15) == 0) timer_262144hz();
if((status.clock & 63) == 0) timer_65536hz();
if((status.clock & 255) == 0) timer_16384hz();
if((status.clock & 511) == 0) timer_8192hz();
if((status.clock & 1023) == 0) timer_4096hz();
lcd.clock -= clocks;
if(lcd.clock <= 0) co_switch(scheduler.active_thread = lcd.thread);
apu.clock -= clocks;
if(apu.clock <= 0) co_switch(scheduler.active_thread = apu.thread);
}
void CPU::timer_262144hz() {
if(status.timer_enable && status.timer_clock == 1) {
if(++status.tima == 0) {
status.tima = status.tma;
interrupt_raise(Interrupt::Timer);
}
}
}
void CPU::timer_65536hz() {
if(status.timer_enable && status.timer_clock == 2) {
if(++status.tima == 0) {
status.tima = status.tma;
interrupt_raise(Interrupt::Timer);
}
}
}
void CPU::timer_16384hz() {
if(status.timer_enable && status.timer_clock == 3) {
if(++status.tima == 0) {
status.tima = status.tma;
interrupt_raise(Interrupt::Timer);
}
}
status.div++;
}
void CPU::timer_8192hz() {
if(status.serial_transfer && status.serial_clock) {
if(--status.serial_bits == 0) {
status.serial_transfer = 0;
interrupt_raise(Interrupt::Serial);
}
}
}
void CPU::timer_4096hz() {
if(status.timer_enable && status.timer_clock == 0) {
if(++status.tima == 0) {
status.tima = status.tma;
interrupt_raise(Interrupt::Timer);
}
}
}
#endif
-12
View File
@@ -1,12 +0,0 @@
void add_clocks(unsigned clocks);
void timer_262144hz();
void timer_65536hz();
void timer_16384hz();
void timer_8192hz();
void timer_4096hz();
//opcode.cpp
void op_io();
uint8 op_read(uint16 addr);
void op_write(uint16 addr, uint8 data);
void cycle_edge();
-103
View File
@@ -1,103 +0,0 @@
#ifndef GAMEBOY_HPP
#define GAMEBOY_HPP
namespace GameBoy {
namespace Info {
static const char Name[] = "bgameboy";
static const unsigned SerializerVersion = 2;
}
}
/*
bgameboy - Game Boy emulator
author: byuu
license: GPLv3
project started: 2010-12-27
*/
#include <libco/libco.h>
#include <nall/platform.hpp>
#include <nall/property.hpp>
#include <nall/random.hpp>
#include <nall/serializer.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/varint.hpp>
using namespace nall;
namespace GameBoy {
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef uint_t< 1> uint1;
typedef uint_t< 2> uint2;
typedef uint_t< 3> uint3;
typedef uint_t< 4> uint4;
typedef uint_t< 5> uint5;
typedef uint_t< 6> uint6;
typedef uint_t< 7> uint7;
typedef uint_t< 9> uint9;
typedef uint_t<10> uint10;
typedef uint_t<11> uint11;
typedef uint_t<12> uint12;
typedef uint_t<13> uint13;
typedef uint_t<14> uint14;
typedef uint_t<15> uint15;
typedef uint_t<17> uint17;
typedef uint_t<18> uint18;
typedef uint_t<19> uint19;
typedef uint_t<20> uint20;
typedef uint_t<21> uint21;
typedef uint_t<22> uint22;
typedef uint_t<23> uint23;
typedef uint_t<24> uint24;
typedef uint_t<25> uint25;
typedef uint_t<26> uint26;
typedef uint_t<27> uint27;
typedef uint_t<28> uint28;
typedef uint_t<29> uint29;
typedef uint_t<30> uint30;
typedef uint_t<31> uint31;
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;
int64 clock;
inline void create(void (*entrypoint_)(), unsigned frequency_) {
if(thread) co_delete(thread);
thread = co_create(65536 * sizeof(void*), entrypoint_);
frequency = frequency_;
clock = 0;
}
inline Processor() : thread(nullptr) {}
};
#include <gameboy/memory/memory.hpp>
#include <gameboy/system/system.hpp>
#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>
#include <gameboy/cheat/cheat.hpp>
};
#endif
-89
View File
@@ -1,89 +0,0 @@
#include <gameboy/gameboy.hpp>
namespace GameBoy {
Interface *interface = 0;
void Interface::lcdScanline() {
}
void Interface::joypWrite(bool p15, bool p14) {
}
void Interface::videoRefresh(const uint8_t *data) {
}
void Interface::audioSample(int16_t center, int16_t left, int16_t right) {
}
bool Interface::inputPoll(unsigned id) {
return false;
}
void Interface::initialize(Interface *derived_interface) {
interface = derived_interface;
system.init();
}
bool Interface::cartridgeLoaded() {
return cartridge.loaded();
}
void Interface::loadCartridge(const string &markup, const uint8_t *data, unsigned size) {
cartridge.load(markup, data, size);
system.power();
}
void Interface::unloadCartridge() {
cartridge.unload();
}
unsigned Interface::memorySize(Memory memory) {
if(memory == Memory::RAM) return cartridge.ramsize;
return 0u;
}
uint8_t* Interface::memoryData(Memory memory) {
if(memory == Memory::RAM) return cartridge.ramdata;
return 0u;
}
void Interface::power() {
system.power();
}
void Interface::run() {
do {
system.run();
} while(scheduler.exit_reason() != Scheduler::ExitReason::FrameEvent);
}
serializer Interface::serialize() {
system.runtosave();
return system.serialize();
}
bool Interface::unserialize(serializer &s) {
return system.unserialize(s);
}
void Interface::setCheats(const lstring &list) {
cheat.reset();
for(auto &code : list) {
lstring codelist;
codelist.split("+", code);
for(auto &part : codelist) {
unsigned addr, data, comp;
if(Cheat::decode(part, addr, data, comp)) {
cheat.append({ addr, data, comp });
}
}
}
cheat.synchronize();
}
void Interface::message(const string &text) {
print(text, "\n");
}
}
-34
View File
@@ -1,34 +0,0 @@
class Interface {
public:
virtual void lcdScanline();
virtual void joypWrite(bool p15, bool p14);
virtual void videoRefresh(const uint8_t *data);
virtual void audioSample(int16_t center, int16_t left, int16_t right);
virtual bool inputPoll(unsigned id);
virtual void initialize(Interface*);
virtual bool cartridgeLoaded();
virtual void loadCartridge(const string &markup, const uint8_t *data, unsigned size);
virtual void unloadCartridge();
enum class Memory : unsigned {
RAM,
};
virtual unsigned memorySize(Memory);
virtual uint8_t* memoryData(Memory);
virtual void power();
virtual void run();
virtual serializer serialize();
virtual bool unserialize(serializer&);
virtual void setCheats(const lstring &list = lstring{});
virtual void message(const string &text);
};
extern Interface *interface;
-255
View File
@@ -1,255 +0,0 @@
#include <gameboy/gameboy.hpp>
#define LCD_CPP
namespace GameBoy {
#include "mmio/mmio.cpp"
#include "serialization.cpp"
LCD lcd;
static unsigned linectr;
void LCD::Main() {
lcd.main();
}
void LCD::main() {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
add_clocks(4);
status.lx += 4;
if(status.lx >= 456) scanline();
if(status.display_enable && status.lx == 0) {
if(status.interrupt_oam) cpu.interrupt_raise(CPU::Interrupt::Stat);
}
if(status.display_enable && status.lx == 252) {
if(status.interrupt_hblank) cpu.interrupt_raise(CPU::Interrupt::Stat);
}
}
}
void LCD::add_clocks(unsigned clocks) {
clock += clocks;
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) {
co_switch(scheduler.active_thread = cpu.thread);
}
}
void LCD::scanline() {
status.lx -= 456;
if(++status.ly == 154) frame();
if(status.display_enable && status.interrupt_lyc == true) {
if(status.ly == status.lyc) cpu.interrupt_raise(CPU::Interrupt::Stat);
}
if(status.ly < 144) render();
if(status.display_enable && status.ly == 144) {
cpu.interrupt_raise(CPU::Interrupt::Vblank);
if(status.interrupt_vblank) cpu.interrupt_raise(CPU::Interrupt::Stat);
}
}
void LCD::frame() {
interface->videoRefresh(screen);
cpu.mmio_joyp_poll();
status.ly = 0;
status.wyc = 0;
scheduler.exit(Scheduler::ExitReason::FrameEvent);
}
void LCD::render() {
for(unsigned n = 0; n < 160; n++) {
line[n] = 0x00;
origin[n] = Origin::None;
}
if(status.display_enable == true) {
if(status.bg_enable == true) render_bg();
if(status.window_display_enable == true) render_window();
if(status.obj_enable == true) render_obj();
}
uint8_t *output = screen + status.ly * 160;
for(unsigned n = 0; n < 160; n++) output[n] = line[n];
interface->lcdScanline();
}
uint16 LCD::read_tile(bool select, unsigned x, unsigned y) {
unsigned tmaddr = 0x1800 + (select << 10), tdaddr;
tmaddr += (((y >> 3) << 5) + (x >> 3)) & 0x03ff;
if(status.bg_tiledata_select == 0) {
tdaddr = 0x1000 + ((int8)vram[tmaddr] << 4);
} else {
tdaddr = 0x0000 + (vram[tmaddr] << 4);
}
tdaddr += (y & 7) << 1;
return (vram[tdaddr + 0] << 0) | (vram[tdaddr + 1] << 8);
}
void LCD::render_bg() {
unsigned iy = (status.ly + status.scy) & 255;
unsigned ix = status.scx, tx = ix & 7;
unsigned data = read_tile(status.bg_tilemap_select, ix, iy);
for(unsigned ox = 0; ox < 160; ox++) {
uint8 palette = ((data & (0x0080 >> tx)) ? 1 : 0)
| ((data & (0x8000 >> tx)) ? 2 : 0);
line[ox] = status.bgp[palette];
origin[ox] = Origin::BG;
ix = (ix + 1) & 255;
tx = (tx + 1) & 7;
if(tx == 0) data = read_tile(status.bg_tilemap_select, ix, iy);
}
}
void LCD::render_window() {
if(status.ly - status.wy >= 144u) return;
if(status.wx >= 167u) return;
unsigned iy = status.wyc++;
unsigned ix = (7 - status.wx) & 255, tx = ix & 7;
unsigned data = read_tile(status.window_tilemap_select, ix, iy);
for(unsigned ox = 0; ox < 160; ox++) {
uint8 palette = ((data & (0x0080 >> tx)) ? 1 : 0)
| ((data & (0x8000 >> tx)) ? 2 : 0);
if(ox - (status.wx - 7) < 160U) {
line[ox] = status.bgp[palette];
origin[ox] = Origin::Window;
}
ix = (ix + 1) & 255;
tx = (tx + 1) & 7;
if(tx == 0) data = read_tile(status.window_tilemap_select, ix, iy);
}
}
void LCD::render_obj() {
enum : unsigned { Priority = 0x80, YFlip = 0x40, XFlip = 0x20, Palette = 0x10 };
unsigned obj_size = (status.obj_size == 0 ? 8 : 16);
unsigned sprite[10], sprites = 0;
//find first ten sprites on this scanline
for(unsigned s = 0; s < 40; s++) {
unsigned sy = oam[(s << 2) + 0] - 16;
unsigned sx = oam[(s << 2) + 1] - 8;
sy = status.ly - sy;
if(sy >= obj_size) continue;
sprite[sprites++] = s;
if(sprites == 10) break;
}
//sort by X-coordinate, when equal, lower address comes first
for(unsigned x = 0; x < sprites; x++) {
for(unsigned y = x + 1; y < sprites; y++) {
signed sx = oam[(sprite[x] << 2) + 1] - 8;
signed sy = oam[(sprite[y] << 2) + 1] - 8;
if(sy < sx) {
sprite[x] ^= sprite[y];
sprite[y] ^= sprite[x];
sprite[x] ^= sprite[y];
}
}
}
//render backwards, so that first sprite has highest priority
for(signed s = sprites - 1; s >= 0; s--) {
unsigned n = sprite[s] << 2;
unsigned sy = oam[n + 0] - 16;
unsigned sx = oam[n + 1] - 8;
unsigned tile = oam[n + 2];
unsigned attribute = oam[n + 3];
sy = status.ly - sy;
if(sy >= obj_size) continue;
if(attribute & YFlip) sy ^= (obj_size - 1);
unsigned tdaddr = (tile << 4) + (sy << 1);
uint8 d0 = vram[tdaddr + 0];
uint8 d1 = vram[tdaddr + 1];
unsigned xflip = attribute & XFlip ? 7 : 0;
for(unsigned tx = 0; tx < 8; tx++) {
uint8 palette = ((d0 & (0x80 >> tx)) ? 1 : 0)
| ((d1 & (0x80 >> tx)) ? 2 : 0);
if(palette == 0) continue;
palette = status.obp[(bool)(attribute & Palette)][palette];
unsigned ox = sx + (tx ^ xflip);
if(ox <= 159) {
if(attribute & Priority) {
if(origin[ox] == Origin::BG || origin[ox] == Origin::Window) {
if(line[ox] > 0) continue;
}
}
line[ox] = palette;
origin[ox] = Origin::OBJ;
}
}
}
}
void LCD::power() {
create(Main, 4194304);
for(unsigned n = 0x8000; n <= 0x9fff; n++) bus.mmio[n] = this; //VRAM
for(unsigned n = 0xff40; n <= 0xff4b; n++) bus.mmio[n] = this; //MMIO
for(unsigned n = 0xfe00; n <= 0xfe9f; n++) bus.mmio[n] = this; //OAM
for(unsigned n = 0; n < 8192; n++) vram[n] = 0x00;
for(unsigned n = 0; n < 160; n++) oam [n] = 0x00;
for(unsigned n = 0; n < 160 * 144; n++) screen[n] = 0x00;
status.lx = 0;
status.wyc = 0;
status.display_enable = 0;
status.window_tilemap_select = 0;
status.window_display_enable = 0;
status.bg_tiledata_select = 0;
status.bg_tilemap_select = 0;
status.obj_size = 0;
status.obj_enable = 0;
status.bg_enable = 0;
status.interrupt_lyc = 0;
status.interrupt_oam = 0;
status.interrupt_vblank = 0;
status.interrupt_hblank = 0;
status.scy = 0;
status.scx = 0;
status.ly = 0;
status.lyc = 0;
for(unsigned n = 0; n < 4; n++) {
status.bgp[n] = n;
status.obp[0][n] = n;
status.obp[1][n] = n;
}
status.wy = 0;
status.wx = 0;
}
LCD::LCD() {
}
}
-75
View File
@@ -1,75 +0,0 @@
struct LCD : Processor, MMIO {
#include "mmio/mmio.hpp"
struct Status {
unsigned lx;
unsigned wyc;
//$ff40 LCDC
bool display_enable;
bool window_tilemap_select;
bool window_display_enable;
bool bg_tiledata_select;
bool bg_tilemap_select;
bool obj_size;
bool obj_enable;
bool bg_enable;
//$ff41 STAT
bool interrupt_lyc;
bool interrupt_oam;
bool interrupt_vblank;
bool interrupt_hblank;
//$ff42 SCY
uint8 scy;
//$ff43 SCX
uint8 scx;
//$ff44 LY
uint8 ly;
//$ff45 LYC
uint8 lyc;
//$ff47 BGP
uint8 bgp[4];
//$ff48 OBP0
//$ff49 OBP1
uint8 obp[2][4];
//$ff4a WY
uint8 wy;
//$ff4b WX
uint8 wx;
} status;
uint8 screen[160 * 144];
uint8 vram[8192];
uint8 oam[160];
uint8 line[160];
struct Origin { enum : unsigned { None, BG, Window, OBJ }; };
uint8 origin[160];
static void Main();
void main();
void add_clocks(unsigned clocks);
void scanline();
void frame();
void render();
uint16 read_tile(bool select, unsigned x, unsigned y);
void render_bg();
void render_window();
void render_obj();
void power();
void serialize(serializer&);
LCD();
};
extern LCD lcd;
-169
View File
@@ -1,169 +0,0 @@
#ifdef LCD_CPP
uint8 LCD::mmio_read(uint16 addr) {
if(addr >= 0x8000 && addr <= 0x9fff) return vram[addr & 0x1fff];
if(addr >= 0xfe00 && addr <= 0xfe9f) return oam[addr & 0xff];
if(addr == 0xff40) { //LCDC
return (status.display_enable << 7)
| (status.window_tilemap_select << 6)
| (status.window_display_enable << 5)
| (status.bg_tiledata_select << 4)
| (status.bg_tilemap_select << 3)
| (status.obj_size << 2)
| (status.obj_enable << 1)
| (status.bg_enable << 0);
}
if(addr == 0xff41) { //STAT
unsigned mode;
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)
| (status.interrupt_vblank << 4)
| (status.interrupt_hblank << 3)
| ((status.ly == status.lyc) << 2)
| (mode << 0);
}
if(addr == 0xff42) { //SCY
return status.scy;
}
if(addr == 0xff43) { //SCX
return status.scx;
}
if(addr == 0xff44) { //LY
return status.ly;
}
if(addr == 0xff45) { //LYC
return status.lyc;
}
if(addr == 0xff47) { //BGP
return (status.bgp[3] << 6)
| (status.bgp[2] << 4)
| (status.bgp[1] << 2)
| (status.bgp[0] << 0);
}
if(addr == 0xff48) { //OBP0
return (status.obp[0][3] << 6)
| (status.obp[0][2] << 4)
| (status.obp[0][1] << 2)
| (status.obp[0][0] << 0);
}
if(addr == 0xff49) { //OBP1
return (status.obp[1][3] << 6)
| (status.obp[1][2] << 4)
| (status.obp[1][1] << 2)
| (status.obp[1][0] << 0);
}
if(addr == 0xff4a) { //WY
return status.wy;
}
if(addr == 0xff4b) { //WX
return status.wx;
}
return 0x00;
}
void LCD::mmio_write(uint16 addr, uint8 data) {
if(addr >= 0x8000 && addr <= 0x9fff) { vram[addr & 0x1fff] = data; return; }
if(addr >= 0xfe00 && addr <= 0xfe9f) { oam[addr & 0xff] = data; return; }
if(addr == 0xff40) { //LCDC
if(status.display_enable == false && (data & 0x80)) {
status.lx = 0; //unverified behavior; fixes Super Mario Land 2 - Tree Zone
}
status.display_enable = data & 0x80;
status.window_tilemap_select = data & 0x40;
status.window_display_enable = data & 0x20;
status.bg_tiledata_select = data & 0x10;
status.bg_tilemap_select = data & 0x08;
status.obj_size = data & 0x04;
status.obj_enable = data & 0x02;
status.bg_enable = data & 0x01;
return;
}
if(addr == 0xff41) { //STAT
status.interrupt_lyc = data & 0x40;
status.interrupt_oam = data & 0x20;
status.interrupt_vblank = data & 0x10;
status.interrupt_hblank = data & 0x08;
return;
}
if(addr == 0xff42) { //SCY
status.scy = data;
return;
}
if(addr == 0xff43) { //SCX
status.scx = data;
return;
}
if(addr == 0xff44) { //LY
status.ly = 0;
return;
}
if(addr == 0xff45) { //LYC
status.lyc = data;
return;
}
if(addr == 0xff46) { //DMA
for(unsigned n = 0x00; n <= 0x9f; n++) bus.write(0xfe00 + n, bus.read((data << 8) + n));
return;
}
if(addr == 0xff47) { //BGP
status.bgp[3] = (data >> 6) & 3;
status.bgp[2] = (data >> 4) & 3;
status.bgp[1] = (data >> 2) & 3;
status.bgp[0] = (data >> 0) & 3;
return;
}
if(addr == 0xff48) { //OBP0
status.obp[0][3] = (data >> 6) & 3;
status.obp[0][2] = (data >> 4) & 3;
status.obp[0][1] = (data >> 2) & 3;
status.obp[0][0] = (data >> 0) & 3;
return;
}
if(addr == 0xff49) { //OBP1
status.obp[1][3] = (data >> 6) & 3;
status.obp[1][2] = (data >> 4) & 3;
status.obp[1][1] = (data >> 2) & 3;
status.obp[1][0] = (data >> 0) & 3;
return;
}
if(addr == 0xff4a) { //WY
status.wy = data;
return;
}
if(addr == 0xff4b) { //WX
status.wx = data;
return;
}
}
#endif
-2
View File
@@ -1,2 +0,0 @@
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);
-40
View File
@@ -1,40 +0,0 @@
#ifdef LCD_CPP
void LCD::serialize(serializer &s) {
s.integer(status.lx);
s.integer(status.wyc);
s.integer(status.display_enable);
s.integer(status.window_tilemap_select);
s.integer(status.window_display_enable);
s.integer(status.bg_tiledata_select);
s.integer(status.bg_tilemap_select);
s.integer(status.obj_size);
s.integer(status.obj_enable);
s.integer(status.bg_enable);
s.integer(status.interrupt_lyc);
s.integer(status.interrupt_oam);
s.integer(status.interrupt_vblank);
s.integer(status.interrupt_hblank);
s.integer(status.scy);
s.integer(status.scx);
s.integer(status.ly);
s.integer(status.lyc);
s.array(status.bgp);
s.array(status.obp[0]);
s.array(status.obp[1]);
s.integer(status.wy);
s.integer(status.wx);
s.array(screen);
s.array(vram);
s.array(oam);
s.array(line);
s.array(origin);
}
#endif
-69
View File
@@ -1,69 +0,0 @@
#include <gameboy/gameboy.hpp>
#define MEMORY_CPP
namespace GameBoy {
Unmapped unmapped;
Bus bus;
uint8_t& Memory::operator[](unsigned addr) {
return data[addr];
}
void Memory::allocate(unsigned size_) {
free();
size = size_;
data = new uint8_t[size]();
}
void Memory::copy(const uint8_t *data_, unsigned size_) {
free();
size = size_;
data = new uint8_t[size];
memcpy(data, data_, size);
}
void Memory::free() {
if(data) {
delete[] data;
data = 0;
}
}
Memory::Memory() {
data = 0;
size = 0;
}
Memory::~Memory() {
free();
}
//
uint8 Bus::read(uint16 addr) {
uint8 data = mmio[addr]->mmio_read(addr);
if(cheat.override[addr]) {
for(unsigned n = 0; n < cheat.size(); n++) {
if(cheat[n].addr == addr) {
if(cheat[n].comp > 255 || cheat[n].comp == data) {
data = cheat[n].data;
break;
}
}
}
}
return data;
}
void Bus::write(uint16 addr, uint8 data) {
mmio[addr]->mmio_write(addr, data);
}
void Bus::power() {
for(unsigned n = 0x0000; n <= 0xffff; n++) mmio[n] = &unmapped;
}
}
-32
View File
@@ -1,32 +0,0 @@
struct Memory {
uint8_t *data;
unsigned size;
uint8_t& operator[](unsigned addr);
void allocate(unsigned size);
void copy(const uint8_t *data, unsigned size);
void free();
Memory();
~Memory();
};
struct MMIO {
virtual uint8 mmio_read(uint16 addr) = 0;
virtual void mmio_write(uint16 addr, uint8 data) = 0;
};
struct Unmapped : MMIO {
uint8 mmio_read(uint16) { return 0x00; }
void mmio_write(uint16, uint8) {}
};
struct Bus {
MMIO *mmio[65536];
uint8 read(uint16 addr);
void write(uint16 addr, uint8 data);
void power();
};
extern Unmapped unmapped;
extern Bus bus;
-35
View File
@@ -1,35 +0,0 @@
#include <gameboy/gameboy.hpp>
#define SCHEDULER_CPP
namespace GameBoy {
Scheduler scheduler;
void Scheduler::enter() {
host_thread = co_active();
co_switch(active_thread);
}
void Scheduler::exit(ExitReason reason) {
exit_reason = reason;
active_thread = co_active();
co_switch(host_thread);
}
void Scheduler::swapto(Processor &p) {
active_thread = p.thread;
co_switch(active_thread);
}
void Scheduler::init() {
host_thread = co_active();
active_thread = cpu.thread;
}
Scheduler::Scheduler() {
exit_reason = ExitReason::UnknownEvent;
host_thread = 0;
active_thread = 0;
}
}
-17
View File
@@ -1,17 +0,0 @@
struct Scheduler : property<Scheduler> {
enum class SynchronizeMode : unsigned { None, CPU, All } sync;
enum class ExitReason : unsigned { UnknownEvent, StepEvent, FrameEvent, SynchronizeEvent };
readonly<ExitReason> exit_reason;
cothread_t host_thread;
cothread_t active_thread;
void enter();
void exit(ExitReason);
void swapto(Processor&);
void init();
Scheduler();
};
extern Scheduler scheduler;
-23
View File
@@ -1,23 +0,0 @@
#ifdef SYSTEM_CPP
//MD5SUM = 32fbbd84168d3482956eb3c5051637f5
const uint8_t System::BootROM::dmg[256] = {
0x31,0xfe,0xff,0xaf,0x21,0xff,0x9f,0x32,0xcb,0x7c,0x20,0xfb,0x21,0x26,0xff,0x0e,
0x11,0x3e,0x80,0x32,0xe2,0x0c,0x3e,0xf3,0xe2,0x32,0x3e,0x77,0x77,0x3e,0xfc,0xe0,
0x47,0x11,0x04,0x01,0x21,0x10,0x80,0x1a,0xcd,0x95,0x00,0xcd,0x96,0x00,0x13,0x7b,
0xfe,0x34,0x20,0xf3,0x11,0xd8,0x00,0x06,0x08,0x1a,0x13,0x22,0x23,0x05,0x20,0xf9,
0x3e,0x19,0xea,0x10,0x99,0x21,0x2f,0x99,0x0e,0x0c,0x3d,0x28,0x08,0x32,0x0d,0x20,
0xf9,0x2e,0x0f,0x18,0xf3,0x67,0x3e,0x64,0x57,0xe0,0x42,0x3e,0x91,0xe0,0x40,0x04,
0x1e,0x02,0x0e,0x0c,0xf0,0x44,0xfe,0x90,0x20,0xfa,0x0d,0x20,0xf7,0x1d,0x20,0xf2,
0x0e,0x13,0x24,0x7c,0x1e,0x83,0xfe,0x62,0x28,0x06,0x1e,0xc1,0xfe,0x64,0x20,0x06,
0x7b,0xe2,0x0c,0x3e,0x87,0xe2,0xf0,0x42,0x90,0xe0,0x42,0x15,0x20,0xd2,0x05,0x20,
0x4f,0x16,0x20,0x18,0xcb,0x4f,0x06,0x04,0xc5,0xcb,0x11,0x17,0xc1,0xcb,0x11,0x17,
0x05,0x20,0xf5,0x22,0x23,0x22,0x23,0xc9,0xce,0xed,0x66,0x66,0xcc,0x0d,0x00,0x0b,
0x03,0x73,0x00,0x83,0x00,0x0c,0x00,0x0d,0x00,0x08,0x11,0x1f,0x88,0x89,0x00,0x0e,
0xdc,0xcc,0x6e,0xe6,0xdd,0xdd,0xd9,0x99,0xbb,0xbb,0x67,0x63,0x6e,0x0e,0xec,0xcc,
0xdd,0xdc,0x99,0x9f,0xbb,0xb9,0x33,0x3e,0x3c,0x42,0xb9,0xa5,0xb9,0xa5,0x42,0x3c,
0x21,0x04,0x01,0x11,0xa8,0x00,0x1a,0x13,0xbe,0x20,0xfe,0x23,0x7d,0xfe,0x34,0x20,
0xf5,0x06,0x19,0x78,0x86,0x23,0x05,0x20,0xfb,0x86,0x20,0xfe,0x3e,0x01,0xe0,0x50,
};
#endif
-23
View File
@@ -1,23 +0,0 @@
#ifdef SYSTEM_CPP
//MD5SUM = d574d4f9c12f305074798f54c091a8b4
const uint8_t System::BootROM::sgb[256] = {
0x31,0xfe,0xff,0x3e,0x30,0xe0,0x00,0xaf,0x21,0xff,0x9f,0x32,0xcb,0x7c,0x20,0xfb,
0x21,0x26,0xff,0x0e,0x11,0x3e,0x80,0x32,0xe2,0x0c,0x3e,0xf3,0xe2,0x32,0x3e,0x77,
0x77,0x3e,0xfc,0xe0,0x47,0x21,0x5f,0xc0,0x0e,0x08,0xaf,0x32,0x0d,0x20,0xfc,0x11,
0x4f,0x01,0x3e,0xfb,0x0e,0x06,0xf5,0x06,0x00,0x1a,0x1b,0x32,0x80,0x47,0x0d,0x20,
0xf8,0x32,0xf1,0x32,0x0e,0x0e,0xd6,0x02,0xfe,0xef,0x20,0xea,0x11,0x04,0x01,0x21,
0x10,0x80,0x1a,0xcd,0xd3,0x00,0xcd,0xd4,0x00,0x13,0x7b,0xfe,0x34,0x20,0xf3,0x11,
0xe6,0x00,0x06,0x08,0x1a,0x13,0x22,0x23,0x05,0x20,0xf9,0x3e,0x19,0xea,0x10,0x99,
0x21,0x2f,0x99,0x0e,0x0c,0x3d,0x28,0x08,0x32,0x0d,0x20,0xf9,0x2e,0x0f,0x18,0xf3,
0x3e,0x91,0xe0,0x40,0x21,0x00,0xc0,0x0e,0x00,0x3e,0x00,0xe2,0x3e,0x30,0xe2,0x06,
0x10,0x1e,0x08,0x2a,0x57,0xcb,0x42,0x3e,0x10,0x20,0x02,0x3e,0x20,0xe2,0x3e,0x30,
0xe2,0xcb,0x1a,0x1d,0x20,0xef,0x05,0x20,0xe8,0x3e,0x20,0xe2,0x3e,0x30,0xe2,0xcd,
0xc2,0x00,0x7d,0xfe,0x60,0x20,0xd2,0x0e,0x13,0x3e,0xc1,0xe2,0x0c,0x3e,0x07,0xe2,
0x18,0x3a,0x16,0x04,0xf0,0x44,0xfe,0x90,0x20,0xfa,0x1e,0x00,0x1d,0x20,0xfd,0x15,
0x20,0xf2,0xc9,0x4f,0x06,0x04,0xc5,0xcb,0x11,0x17,0xc1,0xcb,0x11,0x17,0x05,0x20,
0xf5,0x22,0x23,0x22,0x23,0xc9,0x3c,0x42,0xb9,0xa5,0xb9,0xa5,0x42,0x3c,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x01,0xe0,0x50,
};
#endif
-63
View File
@@ -1,63 +0,0 @@
#ifdef SYSTEM_CPP
serializer System::serialize() {
serializer s(serialize_size);
unsigned signature = 0x31545342, version = Info::SerializerVersion, crc32 = 0;
char description[512];
memset(&description, 0, sizeof description);
s.integer(signature);
s.integer(version);
s.integer(crc32);
s.array(description);
serialize_all(s);
return s;
}
bool System::unserialize(serializer &s) {
unsigned signature, version, crc32;
char description[512];
s.integer(signature);
s.integer(version);
s.integer(crc32);
s.array(description);
if(signature != 0x31545342) return false;
if(version != Info::SerializerVersion) return false;
//if(crc32 != 0) return false;
serialize_all(s);
return true;
}
void System::serialize(serializer &s) {
s.integer(clocks_executed);
}
void System::serialize_all(serializer &s) {
cartridge.serialize(s);
system.serialize(s);
cpu.serialize(s);
apu.serialize(s);
lcd.serialize(s);
}
void System::serialize_init() {
serializer s;
unsigned signature = 0, version = 0, crc32 = 0;
char description[512];
s.integer(signature);
s.integer(version);
s.integer(crc32);
s.array(description);
serialize_all(s);
serialize_size = s.size();
}
#endif
-55
View File
@@ -1,55 +0,0 @@
#include <gameboy/gameboy.hpp>
#define SYSTEM_CPP
namespace GameBoy {
#include "bootrom-dmg.cpp"
#include "bootrom-sgb.cpp"
#include "serialization.cpp"
System system;
void System::run() {
scheduler.sync = Scheduler::SynchronizeMode::None;
scheduler.enter();
if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) {
}
}
void System::runtosave() {
scheduler.sync = Scheduler::SynchronizeMode::CPU;
runthreadtosave();
scheduler.active_thread = lcd.thread;
runthreadtosave();
}
void System::runthreadtosave() {
while(true) {
scheduler.enter();
if(scheduler.exit_reason() == Scheduler::ExitReason::SynchronizeEvent) break;
if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) {
}
}
}
void System::init() {
assert(interface != 0);
}
void System::load() {
serialize_init();
}
void System::power() {
bus.power();
cartridge.power();
cpu.power();
apu.power();
lcd.power();
scheduler.init();
clocks_executed = 0;
}
}
-36
View File
@@ -1,36 +0,0 @@
class Interface;
enum class Input : unsigned {
Up, Down, Left, Right, B, A, Select, Start,
};
struct System {
struct BootROM {
static const uint8 dmg[256];
static const uint8 sgb[256];
} bootROM;
void run();
void runtosave();
void runthreadtosave();
void init();
void load();
void power();
unsigned clocks_executed;
//serialization.cpp
unsigned serialize_size;
serializer serialize();
bool unserialize(serializer&);
void serialize(serializer&);
void serialize_all(serializer&);
void serialize_init();
};
#include <gameboy/interface/interface.hpp>
extern System system;
-104
View File
@@ -1,104 +0,0 @@
/*
libco.amd64 (2009-10-12)
author: byuu
license: public domain
*/
#define LIBCO_C
#include "libco.h"
#include <assert.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
static thread_local long long co_active_buffer[64];
static thread_local cothread_t co_active_handle = 0;
static void (*co_swap)(cothread_t, cothread_t) = 0;
#ifdef _WIN32
//ABI: Win64
static unsigned char co_swap_function[] = {
0x48, 0x89, 0x22, 0x48, 0x8B, 0x21, 0x58, 0x48, 0x89, 0x6A, 0x08, 0x48, 0x89, 0x72, 0x10, 0x48,
0x89, 0x7A, 0x18, 0x48, 0x89, 0x5A, 0x20, 0x4C, 0x89, 0x62, 0x28, 0x4C, 0x89, 0x6A, 0x30, 0x4C,
0x89, 0x72, 0x38, 0x4C, 0x89, 0x7A, 0x40, 0x48, 0x81, 0xC2, 0x80, 0x00, 0x00, 0x00, 0x48, 0x83,
0xE2, 0xF0, 0x0F, 0x29, 0x32, 0x0F, 0x29, 0x7A, 0x10, 0x44, 0x0F, 0x29, 0x42, 0x20, 0x44, 0x0F,
0x29, 0x4A, 0x30, 0x44, 0x0F, 0x29, 0x52, 0x40, 0x44, 0x0F, 0x29, 0x5A, 0x50, 0x44, 0x0F, 0x29,
0x62, 0x60, 0x44, 0x0F, 0x29, 0x6A, 0x70, 0x44, 0x0F, 0x29, 0xB2, 0x80, 0x00, 0x00, 0x00, 0x44,
0x0F, 0x29, 0xBA, 0x90, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x69, 0x08, 0x48, 0x8B, 0x71, 0x10, 0x48,
0x8B, 0x79, 0x18, 0x48, 0x8B, 0x59, 0x20, 0x4C, 0x8B, 0x61, 0x28, 0x4C, 0x8B, 0x69, 0x30, 0x4C,
0x8B, 0x71, 0x38, 0x4C, 0x8B, 0x79, 0x40, 0x48, 0x81, 0xC1, 0x80, 0x00, 0x00, 0x00, 0x48, 0x83,
0xE1, 0xF0, 0x0F, 0x29, 0x31, 0x0F, 0x29, 0x79, 0x10, 0x44, 0x0F, 0x29, 0x41, 0x20, 0x44, 0x0F,
0x29, 0x49, 0x30, 0x44, 0x0F, 0x29, 0x51, 0x40, 0x44, 0x0F, 0x29, 0x59, 0x50, 0x44, 0x0F, 0x29,
0x61, 0x60, 0x44, 0x0F, 0x29, 0x69, 0x70, 0x44, 0x0F, 0x29, 0xB1, 0x80, 0x00, 0x00, 0x00, 0x44,
0x0F, 0x29, 0xB9, 0x90, 0x00, 0x00, 0x00, 0xFF, 0xE0,
};
#include <windows.h>
void co_init() {
DWORD old_privileges;
VirtualProtect(co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READWRITE, &old_privileges);
}
#else
//ABI: SystemV
static unsigned char co_swap_function[] = {
0x48, 0x89, 0x26, 0x48, 0x8B, 0x27, 0x58, 0x48, 0x89, 0x6E, 0x08, 0x48, 0x89, 0x5E, 0x10, 0x4C,
0x89, 0x66, 0x18, 0x4C, 0x89, 0x6E, 0x20, 0x4C, 0x89, 0x76, 0x28, 0x4C, 0x89, 0x7E, 0x30, 0x48,
0x8B, 0x6F, 0x08, 0x48, 0x8B, 0x5F, 0x10, 0x4C, 0x8B, 0x67, 0x18, 0x4C, 0x8B, 0x6F, 0x20, 0x4C,
0x8B, 0x77, 0x28, 0x4C, 0x8B, 0x7F, 0x30, 0xFF, 0xE0,
};
#include <unistd.h>
#include <sys/mman.h>
void co_init() {
unsigned long long addr = (unsigned long long)co_swap_function;
unsigned long long base = addr - (addr % sysconf(_SC_PAGESIZE));
unsigned long long size = (addr - base) + sizeof co_swap_function;
mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);
}
#endif
static void crash() {
assert(0); /* called only if cothread_t entrypoint returns */
}
cothread_t co_active() {
if(!co_active_handle) co_active_handle = &co_active_buffer;
return co_active_handle;
}
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
cothread_t handle;
if(!co_swap) {
co_init();
co_swap = (void (*)(cothread_t, cothread_t))co_swap_function;
}
if(!co_active_handle) co_active_handle = &co_active_buffer;
size += 512; /* allocate additional space for storage */
size &= ~15; /* align stack to 16-byte boundary */
if(handle = (cothread_t)malloc(size)) {
long long *p = (long long*)((char*)handle + size); /* seek to top of stack */
*--p = (long long)crash; /* crash if entrypoint returns */
*--p = (long long)entrypoint; /* start of function */
*(long long*)handle = (long long)p; /* stack pointer */
}
return handle;
}
void co_delete(cothread_t handle) {
free(handle);
}
void co_switch(cothread_t handle) {
register cothread_t co_previous_handle = co_active_handle;
co_swap(co_active_handle = handle, co_previous_handle);
}
#ifdef __cplusplus
}
#endif
-51
View File
@@ -1,51 +0,0 @@
/*
libco.win (2008-01-28)
authors: Nach, byuu
license: public domain
*/
#define LIBCO_C
#include "libco.h"
#define WINVER 0x0400
#define _WIN32_WINNT 0x0400
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif
static thread_local cothread_t co_active_ = 0;
static void __stdcall co_thunk(void *coentry) {
((void (*)(void))coentry)();
}
cothread_t co_active() {
if(!co_active_) {
ConvertThreadToFiber(0);
co_active_ = GetCurrentFiber();
}
return co_active_;
}
cothread_t co_create(unsigned int heapsize, void (*coentry)(void)) {
if(!co_active_) {
ConvertThreadToFiber(0);
co_active_ = GetCurrentFiber();
}
return (cothread_t)CreateFiber(heapsize, co_thunk, (void*)coentry);
}
void co_delete(cothread_t cothread) {
DeleteFiber(cothread);
}
void co_switch(cothread_t cothread) {
co_active_ = cothread;
SwitchToFiber(cothread);
}
#ifdef __cplusplus
}
#endif
-23
View File
@@ -1,23 +0,0 @@
/*
libco
auto-selection module
license: public domain
*/
#if defined(__GNUC__) && defined(__i386__)
#include "x86.c"
#elif defined(__GNUC__) && defined(__amd64__)
#include "amd64.c"
#elif defined(__GNUC__) && defined(_ARCH_PPC)
#include "ppc.c"
#elif defined(__GNUC__)
#include "sjlj.c"
#elif defined(_MSC_VER) && defined(_M_IX86)
#include "x86.c"
#elif defined(_MSC_VER) && defined(_M_AMD64)
#include "amd64.c"
#elif defined(_MSC_VER)
#include "fiber.c"
#else
#error "libco: unsupported processor, compiler or operating system"
#endif
-34
View File
@@ -1,34 +0,0 @@
/*
libco
version: 0.16 (2010-12-24)
license: public domain
*/
#ifndef LIBCO_H
#define LIBCO_H
#ifdef LIBCO_C
#ifdef LIBCO_MP
#define thread_local __thread
#else
#define thread_local
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef void* cothread_t;
cothread_t co_active();
cothread_t co_create(unsigned int, void (*)(void));
void co_delete(cothread_t);
void co_switch(cothread_t);
#ifdef __cplusplus
}
#endif
/* ifndef LIBCO_H */
#endif
-407
View File
@@ -1,407 +0,0 @@
/*
libco.ppc (2010-10-17)
author: blargg
license: public domain
*/
/* PowerPC 32/64 using embedded or external asm, with optional
floating-point and AltiVec save/restore */
#define LIBCO_C
#include "libco.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#define LIBCO_MPROTECT (__unix__ && !LIBCO_PPC_ASM)
#if LIBCO_MPROTECT
#include <unistd.h>
#include <sys/mman.h>
#endif
/* State format (offsets in 32-bit words)
+0 Pointer to swap code
Rest of function descriptor for entry function
+8 PC
+10 SP
Special regs
GPRs
FPRs
VRs
stack
*/
enum { state_size = 1024 };
enum { above_stack = 2048 };
enum { stack_align = 256 };
static thread_local cothread_t co_active_handle = 0;
/**** Determine environment ****/
#define LIBCO_PPC64 (_ARCH_PPC64 || __PPC64__ || __ppc64__ || __powerpc64__)
/* Whether function calls are indirect through a descriptor,
or are directly to function */
#ifndef LIBCO_PPCDESC
#if !_CALL_SYSV && (_CALL_AIX || _CALL_AIXDESC || LIBCO_PPC64)
#define LIBCO_PPCDESC 1
#endif
#endif
#ifdef LIBCO_PPC_ASM
#ifdef __cplusplus
extern "C"
#endif
/* Swap code is in ppc.S */
void co_swap_asm( cothread_t, cothread_t );
#define CO_SWAP_ASM( x, y ) co_swap_asm( x, y )
#else
/* Swap code is here in array. Please leave dieassembly comments,
as they make it easy to see what it does, and reorder instructions
if one wants to see whether that improves performance. */
static const uint32_t libco_ppc_code [] = {
#if LIBCO_PPC64
0x7d000026, /* mfcr r8 */
0xf8240028, /* std r1,40(r4) */
0x7d2802a6, /* mflr r9 */
0xf9c40048, /* std r14,72(r4) */
0xf9e40050, /* std r15,80(r4) */
0xfa040058, /* std r16,88(r4) */
0xfa240060, /* std r17,96(r4) */
0xfa440068, /* std r18,104(r4) */
0xfa640070, /* std r19,112(r4) */
0xfa840078, /* std r20,120(r4) */
0xfaa40080, /* std r21,128(r4) */
0xfac40088, /* std r22,136(r4) */
0xfae40090, /* std r23,144(r4) */
0xfb040098, /* std r24,152(r4) */
0xfb2400a0, /* std r25,160(r4) */
0xfb4400a8, /* std r26,168(r4) */
0xfb6400b0, /* std r27,176(r4) */
0xfb8400b8, /* std r28,184(r4) */
0xfba400c0, /* std r29,192(r4) */
0xfbc400c8, /* std r30,200(r4) */
0xfbe400d0, /* std r31,208(r4) */
0xf9240020, /* std r9,32(r4) */
0xe8e30020, /* ld r7,32(r3) */
0xe8230028, /* ld r1,40(r3) */
0x48000009, /* bl 1 */
0x7fe00008, /* trap */
0x91040030,/*1:stw r8,48(r4) */
0x80c30030, /* lwz r6,48(r3) */
0x7ce903a6, /* mtctr r7 */
0xe9c30048, /* ld r14,72(r3) */
0xe9e30050, /* ld r15,80(r3) */
0xea030058, /* ld r16,88(r3) */
0xea230060, /* ld r17,96(r3) */
0xea430068, /* ld r18,104(r3) */
0xea630070, /* ld r19,112(r3) */
0xea830078, /* ld r20,120(r3) */
0xeaa30080, /* ld r21,128(r3) */
0xeac30088, /* ld r22,136(r3) */
0xeae30090, /* ld r23,144(r3) */
0xeb030098, /* ld r24,152(r3) */
0xeb2300a0, /* ld r25,160(r3) */
0xeb4300a8, /* ld r26,168(r3) */
0xeb6300b0, /* ld r27,176(r3) */
0xeb8300b8, /* ld r28,184(r3) */
0xeba300c0, /* ld r29,192(r3) */
0xebc300c8, /* ld r30,200(r3) */
0xebe300d0, /* ld r31,208(r3) */
0x7ccff120, /* mtcr r6 */
#else
0x7d000026, /* mfcr r8 */
0x90240028, /* stw r1,40(r4) */
0x7d2802a6, /* mflr r9 */
0x91a4003c, /* stw r13,60(r4) */
0x91c40040, /* stw r14,64(r4) */
0x91e40044, /* stw r15,68(r4) */
0x92040048, /* stw r16,72(r4) */
0x9224004c, /* stw r17,76(r4) */
0x92440050, /* stw r18,80(r4) */
0x92640054, /* stw r19,84(r4) */
0x92840058, /* stw r20,88(r4) */
0x92a4005c, /* stw r21,92(r4) */
0x92c40060, /* stw r22,96(r4) */
0x92e40064, /* stw r23,100(r4) */
0x93040068, /* stw r24,104(r4) */
0x9324006c, /* stw r25,108(r4) */
0x93440070, /* stw r26,112(r4) */
0x93640074, /* stw r27,116(r4) */
0x93840078, /* stw r28,120(r4) */
0x93a4007c, /* stw r29,124(r4) */
0x93c40080, /* stw r30,128(r4) */
0x93e40084, /* stw r31,132(r4) */
0x91240020, /* stw r9,32(r4) */
0x80e30020, /* lwz r7,32(r3) */
0x80230028, /* lwz r1,40(r3) */
0x48000009, /* bl 1 */
0x7fe00008, /* trap */
0x91040030,/*1:stw r8,48(r4) */
0x80c30030, /* lwz r6,48(r3) */
0x7ce903a6, /* mtctr r7 */
0x81a3003c, /* lwz r13,60(r3) */
0x81c30040, /* lwz r14,64(r3) */
0x81e30044, /* lwz r15,68(r3) */
0x82030048, /* lwz r16,72(r3) */
0x8223004c, /* lwz r17,76(r3) */
0x82430050, /* lwz r18,80(r3) */
0x82630054, /* lwz r19,84(r3) */
0x82830058, /* lwz r20,88(r3) */
0x82a3005c, /* lwz r21,92(r3) */
0x82c30060, /* lwz r22,96(r3) */
0x82e30064, /* lwz r23,100(r3) */
0x83030068, /* lwz r24,104(r3) */
0x8323006c, /* lwz r25,108(r3) */
0x83430070, /* lwz r26,112(r3) */
0x83630074, /* lwz r27,116(r3) */
0x83830078, /* lwz r28,120(r3) */
0x83a3007c, /* lwz r29,124(r3) */
0x83c30080, /* lwz r30,128(r3) */
0x83e30084, /* lwz r31,132(r3) */
0x7ccff120, /* mtcr r6 */
#endif
#ifndef LIBCO_PPC_NOFP
0xd9c400e0, /* stfd f14,224(r4) */
0xd9e400e8, /* stfd f15,232(r4) */
0xda0400f0, /* stfd f16,240(r4) */
0xda2400f8, /* stfd f17,248(r4) */
0xda440100, /* stfd f18,256(r4) */
0xda640108, /* stfd f19,264(r4) */
0xda840110, /* stfd f20,272(r4) */
0xdaa40118, /* stfd f21,280(r4) */
0xdac40120, /* stfd f22,288(r4) */
0xdae40128, /* stfd f23,296(r4) */
0xdb040130, /* stfd f24,304(r4) */
0xdb240138, /* stfd f25,312(r4) */
0xdb440140, /* stfd f26,320(r4) */
0xdb640148, /* stfd f27,328(r4) */
0xdb840150, /* stfd f28,336(r4) */
0xdba40158, /* stfd f29,344(r4) */
0xdbc40160, /* stfd f30,352(r4) */
0xdbe40168, /* stfd f31,360(r4) */
0xc9c300e0, /* lfd f14,224(r3) */
0xc9e300e8, /* lfd f15,232(r3) */
0xca0300f0, /* lfd f16,240(r3) */
0xca2300f8, /* lfd f17,248(r3) */
0xca430100, /* lfd f18,256(r3) */
0xca630108, /* lfd f19,264(r3) */
0xca830110, /* lfd f20,272(r3) */
0xcaa30118, /* lfd f21,280(r3) */
0xcac30120, /* lfd f22,288(r3) */
0xcae30128, /* lfd f23,296(r3) */
0xcb030130, /* lfd f24,304(r3) */
0xcb230138, /* lfd f25,312(r3) */
0xcb430140, /* lfd f26,320(r3) */
0xcb630148, /* lfd f27,328(r3) */
0xcb830150, /* lfd f28,336(r3) */
0xcba30158, /* lfd f29,344(r3) */
0xcbc30160, /* lfd f30,352(r3) */
0xcbe30168, /* lfd f31,360(r3) */
#endif
#ifdef __ALTIVEC__
0x7ca042a6, /* mfvrsave r5 */
0x39040180, /* addi r8,r4,384 */
0x39240190, /* addi r9,r4,400 */
0x70a00fff, /* andi. r0,r5,4095 */
0x90a40034, /* stw r5,52(r4) */
0x4182005c, /* beq- 2 */
0x7e8041ce, /* stvx v20,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7ea049ce, /* stvx v21,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7ec041ce, /* stvx v22,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7ee049ce, /* stvx v23,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7f0041ce, /* stvx v24,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7f2049ce, /* stvx v25,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7f4041ce, /* stvx v26,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7f6049ce, /* stvx v27,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7f8041ce, /* stvx v28,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7fa049ce, /* stvx v29,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7fc041ce, /* stvx v30,r0,r8 */
0x7fe049ce, /* stvx v31,r0,r9 */
0x80a30034,/*2:lwz r5,52(r3) */
0x39030180, /* addi r8,r3,384 */
0x39230190, /* addi r9,r3,400 */
0x70a00fff, /* andi. r0,r5,4095 */
0x7ca043a6, /* mtvrsave r5 */
0x4d820420, /* beqctr */
0x7e8040ce, /* lvx v20,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7ea048ce, /* lvx v21,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7ec040ce, /* lvx v22,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7ee048ce, /* lvx v23,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7f0040ce, /* lvx v24,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7f2048ce, /* lvx v25,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7f4040ce, /* lvx v26,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7f6048ce, /* lvx v27,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7f8040ce, /* lvx v28,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7fa048ce, /* lvx v29,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7fc040ce, /* lvx v30,r0,r8 */
0x7fe048ce, /* lvx v31,r0,r9 */
#endif
0x4e800420, /* bctr */
};
#if LIBCO_PPCDESC
/* Function call goes through indirect descriptor */
#define CO_SWAP_ASM( x, y ) \
((void (*)( cothread_t, cothread_t )) (uintptr_t) x)( x, y )
#else
/* Function call goes directly to code */
#define CO_SWAP_ASM( x, y ) \
((void (*)( cothread_t, cothread_t )) (uintptr_t) libco_ppc_code)( x, y )
#endif
#endif
static uint32_t* co_create_( unsigned size, uintptr_t entry )
{
uint32_t* t = (uint32_t*) malloc( size );
(void) entry;
#if LIBCO_PPCDESC
if ( t )
{
/* Copy entry's descriptor */
memcpy( t, (void*) entry, sizeof (void*) * 3 );
/* Set function pointer to swap routine */
#ifdef LIBCO_PPC_ASM
*(const void**) t = *(void**) &co_swap_asm;
#else
*(const void**) t = libco_ppc_code;
#endif
}
#endif
return t;
}
cothread_t co_create( unsigned int size, void (*entry_)( void ) )
{
uintptr_t entry = (uintptr_t) entry_;
uint32_t* t = NULL;
/* Be sure main thread was successfully allocated */
if ( co_active() )
{
size += state_size + above_stack + stack_align;
t = co_create_( size, entry );
}
if ( t )
{
uintptr_t sp;
int shift;
/* Save current registers into new thread, so that any special ones will
have proper values when thread is begun */
CO_SWAP_ASM( t, t );
#if LIBCO_PPCDESC
/* Get real address */
entry = (uintptr_t) *(void**) entry;
#endif
/* Put stack near end of block, and align */
sp = (uintptr_t) t + size - above_stack;
sp -= sp % stack_align;
/* On PPC32, we save and restore GPRs as 32 bits. For PPC64, we
save and restore them as 64 bits, regardless of the size the ABI
uses. So, we manually write pointers at the proper size. We always
save and restore at the same address, and since PPC is big-endian,
we must put the low byte first on PPC32. */
/* If uintptr_t is 32 bits, >>32 is undefined behavior, so we do two shifts
and don't have to care how many bits uintptr_t is. */
#if LIBCO_PPC64
shift = 16;
#else
shift = 0;
#endif
/* Set up so entry will be called on next swap */
t [8] = (uint32_t) (entry >> shift >> shift);
t [9] = (uint32_t) entry;
t [10] = (uint32_t) (sp >> shift >> shift);
t [11] = (uint32_t) sp;
}
return t;
}
void co_delete( cothread_t t )
{
free( t );
}
static void co_init_( void )
{
#if LIBCO_MPROTECT
/* TODO: pre- and post-pad PPC code so that this doesn't make other
data executable and writable */
long page_size = sysconf( _SC_PAGESIZE );
if ( page_size > 0 )
{
uintptr_t align = page_size;
uintptr_t begin = (uintptr_t) libco_ppc_code;
uintptr_t end = begin + sizeof libco_ppc_code;
/* Align beginning and end */
end += align - 1;
end -= end % align;
begin -= begin % align;
mprotect( (void*) begin, end - begin, PROT_READ | PROT_WRITE | PROT_EXEC );
}
#endif
co_active_handle = co_create_( state_size, (uintptr_t) &co_switch );
}
cothread_t co_active()
{
if ( !co_active_handle )
co_init_();
return co_active_handle;
}
void co_switch( cothread_t t )
{
cothread_t old = co_active_handle;
co_active_handle = t;
CO_SWAP_ASM( t, old );
}
-102
View File
@@ -1,102 +0,0 @@
/*
libco.sjlj (2008-01-28)
author: Nach
license: public domain
*/
/*
* Note this was designed for UNIX systems. Based on ideas expressed in a paper
* by Ralf Engelschall.
* For SJLJ on other systems, one would want to rewrite springboard() and
* co_create() and hack the jmb_buf stack pointer.
*/
#define LIBCO_C
#include "libco.h"
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
sigjmp_buf context;
void (*coentry)(void);
void *stack;
} cothread_struct;
static thread_local cothread_struct co_primary;
static thread_local cothread_struct *creating, *co_running = 0;
static void springboard(int ignored) {
if(sigsetjmp(creating->context, 0)) {
co_running->coentry();
}
}
cothread_t co_active() {
if(!co_running) co_running = &co_primary;
return (cothread_t)co_running;
}
cothread_t co_create(unsigned int size, void (*coentry)(void)) {
if(!co_running) co_running = &co_primary;
cothread_struct *thread = (cothread_struct*)malloc(sizeof(cothread_struct));
if(thread) {
struct sigaction handler;
struct sigaction old_handler;
stack_t stack;
stack_t old_stack;
thread->coentry = thread->stack = 0;
stack.ss_flags = 0;
stack.ss_size = size;
thread->stack = stack.ss_sp = malloc(size);
if(stack.ss_sp && !sigaltstack(&stack, &old_stack)) {
handler.sa_handler = springboard;
handler.sa_flags = SA_ONSTACK;
sigemptyset(&handler.sa_mask);
creating = thread;
if(!sigaction(SIGUSR1, &handler, &old_handler)) {
if(!raise(SIGUSR1)) {
thread->coentry = coentry;
}
sigaltstack(&old_stack, 0);
sigaction(SIGUSR1, &old_handler, 0);
}
}
if(thread->coentry != coentry) {
co_delete(thread);
thread = 0;
}
}
return (cothread_t)thread;
}
void co_delete(cothread_t cothread) {
if(cothread) {
if(((cothread_struct*)cothread)->stack) {
free(((cothread_struct*)cothread)->stack);
}
free(cothread);
}
}
void co_switch(cothread_t cothread) {
if(!sigsetjmp(co_running->context, 0)) {
co_running = (cothread_struct*)cothread;
siglongjmp(co_running->context, 1);
}
}
#ifdef __cplusplus
}
#endif
-67
View File
@@ -1,67 +0,0 @@
/*
libco.ucontext (2008-01-28)
author: Nach
license: public domain
*/
/*
* WARNING: the overhead of POSIX ucontext is very high,
* assembly versions of libco or libco_sjlj should be much faster
*
* This library only exists for two reasons:
* 1 - as an initial test for the viability of a ucontext implementation
* 2 - to demonstrate the power and speed of libco over existing implementations,
* such as pth (which defaults to wrapping ucontext on unix targets)
*
* Use this library only as a *last resort*
*/
#define LIBCO_C
#include "libco.h"
#include <stdlib.h>
#include <ucontext.h>
#ifdef __cplusplus
extern "C" {
#endif
static thread_local ucontext_t co_primary;
static thread_local ucontext_t *co_running = 0;
cothread_t co_active() {
if(!co_running) co_running = &co_primary;
return (cothread_t)co_running;
}
cothread_t co_create(unsigned int heapsize, void (*coentry)(void)) {
if(!co_running) co_running = &co_primary;
ucontext_t *thread = (ucontext_t*)malloc(sizeof(ucontext_t));
if(thread) {
if((!getcontext(thread) && !(thread->uc_stack.ss_sp = 0)) && (thread->uc_stack.ss_sp = malloc(heapsize))) {
thread->uc_link = co_running;
thread->uc_stack.ss_size = heapsize;
makecontext(thread, coentry, 0);
} else {
co_delete((cothread_t)thread);
thread = 0;
}
}
return (cothread_t)thread;
}
void co_delete(cothread_t cothread) {
if(cothread) {
if(((ucontext_t*)cothread)->uc_stack.ss_sp) { free(((ucontext_t*)cothread)->uc_stack.ss_sp); }
free(cothread);
}
}
void co_switch(cothread_t cothread) {
ucontext_t *old_thread = co_running;
co_running = (ucontext_t*)cothread;
swapcontext(old_thread, co_running);
}
#ifdef __cplusplus
}
#endif
-93
View File
@@ -1,93 +0,0 @@
/*
libco.x86 (2009-10-12)
author: byuu
license: public domain
*/
#define LIBCO_C
#include "libco.h"
#include <assert.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(_MSC_VER)
#define fastcall __fastcall
#elif defined(__GNUC__)
#define fastcall __attribute__((fastcall))
#else
#error "libco: please define fastcall macro"
#endif
static thread_local long co_active_buffer[64];
static thread_local cothread_t co_active_handle = 0;
static void (fastcall *co_swap)(cothread_t, cothread_t) = 0;
//ABI: fastcall
static unsigned char co_swap_function[] = {
0x89, 0x22, 0x8B, 0x21, 0x58, 0x89, 0x6A, 0x04, 0x89, 0x72, 0x08, 0x89, 0x7A, 0x0C, 0x89, 0x5A,
0x10, 0x8B, 0x69, 0x04, 0x8B, 0x71, 0x08, 0x8B, 0x79, 0x0C, 0x8B, 0x59, 0x10, 0xFF, 0xE0,
};
#ifdef _WIN32
#include <windows.h>
void co_init() {
DWORD old_privileges;
VirtualProtect(co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READWRITE, &old_privileges);
}
#else
#include <unistd.h>
#include <sys/mman.h>
void co_init() {
unsigned long addr = (unsigned long)co_swap_function;
unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE));
unsigned long size = (addr - base) + sizeof co_swap_function;
mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);
}
#endif
static void crash() {
assert(0); /* called only if cothread_t entrypoint returns */
}
cothread_t co_active() {
if(!co_active_handle) co_active_handle = &co_active_buffer;
return co_active_handle;
}
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
cothread_t handle;
if(!co_swap) {
co_init();
co_swap = (void (fastcall*)(cothread_t, cothread_t))co_swap_function;
}
if(!co_active_handle) co_active_handle = &co_active_buffer;
size += 256; /* allocate additional space for storage */
size &= ~15; /* align stack to 16-byte boundary */
if(handle = (cothread_t)malloc(size)) {
long *p = (long*)((char*)handle + size); /* seek to top of stack */
*--p = (long)crash; /* crash if entrypoint returns */
*--p = (long)entrypoint; /* start of function */
*(long*)handle = (long)p; /* stack pointer */
}
return handle;
}
void co_delete(cothread_t handle) {
free(handle);
}
void co_switch(cothread_t handle) {
register cothread_t co_previous_handle = co_active_handle;
co_swap(co_active_handle = handle, co_previous_handle);
}
#ifdef __cplusplus
}
#endif
-109
View File
@@ -1,109 +0,0 @@
# Makefile
# author: byuu
# license: public domain
[A-Z] = A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
[a-z] = a b c d e f g h i j k l m n o p q r s t u v w x y z
[0-9] = 0 1 2 3 4 5 6 7 8 9
[markup] = ` ~ ! @ \# $$ % ^ & * ( ) - _ = + [ { ] } \ | ; : ' " , < . > / ?
[all] = $([A-Z]) $([a-z]) $([0-9]) $([markup])
[space] :=
[space] +=
#####
# platform detection
#####
ifeq ($(platform),)
uname := $(shell uname -a)
ifeq ($(uname),)
platform := win
delete = del $(subst /,\,$1)
else ifneq ($(findstring Darwin,$(uname)),)
platform := osx
delete = rm -f $1
else
platform := x
delete = rm -f $1
endif
endif
ifeq ($(compiler),)
ifeq ($(platform),win)
compiler := gcc
else ifeq ($(platform),osx)
compiler := gcc-mp-4.6
else
compiler := gcc-4.6
endif
endif
ifeq ($(prefix),)
prefix := /usr/local
endif
#####
# function rwildcard(directory, pattern)
#####
rwildcard = \
$(strip \
$(filter $(if $2,$2,%), \
$(foreach f, \
$(wildcard $1*), \
$(eval t = $(call rwildcard,$f/)) \
$(if $t,$t,$f) \
) \
) \
)
#####
# function strtr(source, from, to)
#####
strtr = \
$(eval __temp := $1) \
$(strip \
$(foreach c, \
$(join $(addsuffix :,$2),$3), \
$(eval __temp := \
$(subst $(word 1,$(subst :, ,$c)),$(word 2,$(subst :, ,$c)),$(__temp)) \
) \
) \
$(__temp) \
)
#####
# function strupper(source)
#####
strupper = $(call strtr,$1,$([a-z]),$([A-Z]))
#####
# function strlower(source)
#####
strlower = $(call strtr,$1,$([A-Z]),$([a-z]))
#####
# function strlen(source)
#####
strlen = \
$(eval __temp := $(subst $([space]),_,$1)) \
$(words \
$(strip \
$(foreach c, \
$([all]), \
$(eval __temp := \
$(subst $c,$c ,$(__temp)) \
) \
) \
$(__temp) \
) \
)
#####
# function streq(source)
#####
streq = $(if $(filter-out xx,x$(subst $1,,$2)$(subst $2,,$1)x),,1)
#####
# function strne(source)
#####
strne = $(if $(filter-out xx,x$(subst $1,,$2)$(subst $2,,$1)x),1,)
-17
View File
@@ -1,17 +0,0 @@
#ifndef NALL_ALGORITHM_HPP
#define NALL_ALGORITHM_HPP
#undef min
#undef max
namespace nall {
template<typename T, typename U> T min(const T &t, const U &u) {
return t < u ? t : u;
}
template<typename T, typename U> T max(const T &t, const U &u) {
return t > u ? t : u;
}
}
#endif
-74
View File
@@ -1,74 +0,0 @@
#ifndef NALL_ANY_HPP
#define NALL_ANY_HPP
#include <typeinfo>
#include <type_traits>
#include <nall/static.hpp>
namespace nall {
class any {
public:
bool empty() const { return container; }
const std::type_info& type() const { return container ? container->type() : typeid(void); }
template<typename T> any& operator=(const T& value_) {
typedef typename static_if<
std::is_array<T>::value,
typename std::remove_extent<typename std::add_const<T>::type>::type*,
T
>::type auto_t;
if(type() == typeid(auto_t)) {
static_cast<holder<auto_t>*>(container)->value = (auto_t)value_;
} else {
if(container) delete container;
container = new holder<auto_t>((auto_t)value_);
}
return *this;
}
any() : container(0) {}
template<typename T> any(const T& value_) : container(0) { operator=(value_); }
private:
struct placeholder {
virtual const std::type_info& type() const = 0;
} *container;
template<typename T> struct holder : placeholder {
T value;
const std::type_info& type() const { return typeid(T); }
holder(const T& value_) : value(value_) {}
};
template<typename T> friend T any_cast(any&);
template<typename T> friend T any_cast(const any&);
template<typename T> friend T* any_cast(any*);
template<typename T> friend const T* any_cast(const any*);
};
template<typename T> T any_cast(any &value) {
typedef typename std::remove_reference<T>::type nonref;
if(value.type() != typeid(nonref)) throw;
return static_cast<any::holder<nonref>*>(value.container)->value;
}
template<typename T> T any_cast(const any &value) {
typedef const typename std::remove_reference<T>::type nonref;
if(value.type() != typeid(nonref)) throw;
return static_cast<any::holder<nonref>*>(value.container)->value;
}
template<typename T> T* any_cast(any *value) {
if(!value || value->type() != typeid(T)) return 0;
return &static_cast<any::holder<T>*>(value->container)->value;
}
template<typename T> const T* any_cast(const any *value) {
if(!value || value->type() != typeid(T)) return 0;
return &static_cast<any::holder<T>*>(value->container)->value;
}
}
#endif
-141
View File
@@ -1,141 +0,0 @@
#ifndef NALL_ARRAY_HPP
#define NALL_ARRAY_HPP
#include <stdlib.h>
#include <algorithm>
#include <initializer_list>
#include <type_traits>
#include <utility>
#include <nall/algorithm.hpp>
#include <nall/bit.hpp>
#include <nall/utility.hpp>
namespace nall {
//dynamic vector array
//neither constructor nor destructor is ever invoked;
//thus, this should only be used for POD objects.
template<typename T> class array {
protected:
T *pool;
unsigned poolsize, buffersize;
public:
unsigned size() const { return buffersize; }
unsigned capacity() const { return poolsize; }
void reset() {
if(pool) free(pool);
pool = nullptr;
poolsize = 0;
buffersize = 0;
}
void reserve(unsigned newsize) {
if(newsize == poolsize) return;
pool = (T*)realloc(pool, newsize * sizeof(T));
poolsize = newsize;
buffersize = min(buffersize, newsize);
}
void resize(unsigned newsize) {
if(newsize > poolsize) reserve(bit::round(newsize)); //round reserve size up to power of 2
buffersize = newsize;
}
T* get(unsigned minsize = 0) {
if(minsize > buffersize) resize(minsize);
if(minsize > buffersize) throw "array[] out of bounds";
return pool;
}
void append(const T data) {
operator[](buffersize) = data;
}
void append(const T data[], unsigned length) {
for(unsigned n = 0; n < length; n++) operator[](buffersize) = data[n];
}
void remove() {
if(size > 0) resize(size - 1); //remove last element only
}
void remove(unsigned index, unsigned count = 1) {
for(unsigned i = index; count + i < buffersize; i++) {
pool[i] = pool[count + i];
}
if(count + index >= buffersize) resize(index); //every element >= index was removed
else resize(buffersize - count);
}
optional<unsigned> find(const T data) {
for(unsigned i = 0; i < size(); i++) if(pool[i] == data) return { true, i };
return { false, 0 };
}
void clear() {
memset(pool, 0, buffersize * sizeof(T));
}
array() : pool(nullptr), poolsize(0), buffersize(0) {
}
array(std::initializer_list<T> list) : pool(nullptr), poolsize(0), buffersize(0) {
for(const T *p = list.begin(); p != list.end(); ++p) append(*p);
}
~array() {
reset();
}
//copy
array& operator=(const array &source) {
if(pool) free(pool);
buffersize = source.buffersize;
poolsize = source.poolsize;
pool = (T*)malloc(sizeof(T) * poolsize); //allocate entire pool size,
memcpy(pool, source.pool, sizeof(T) * buffersize); //... but only copy used pool objects
return *this;
}
array(const array &source) : pool(nullptr), poolsize(0), buffersize(0) {
operator=(source);
}
//move
array& operator=(array &&source) {
if(pool) free(pool);
pool = source.pool;
poolsize = source.poolsize;
buffersize = source.buffersize;
source.pool = nullptr;
source.reset();
return *this;
}
array(array &&source) : pool(nullptr), poolsize(0), buffersize(0) {
operator=(std::move(source));
}
//index
inline T& operator[](unsigned index) {
if(index >= buffersize) resize(index + 1);
if(index >= buffersize) throw "array[] out of bounds";
return pool[index];
}
inline const T& operator[](unsigned index) const {
if(index >= buffersize) throw "array[] out of bounds";
return pool[index];
}
//iteration
T* begin() { return &pool[0]; }
T* end() { return &pool[buffersize]; }
const T* begin() const { return &pool[0]; }
const T* end() const { return &pool[buffersize]; }
};
}
#endif
-88
View File
@@ -1,88 +0,0 @@
#ifndef NALL_ATOI_HPP
#define NALL_ATOI_HPP
namespace nall {
//note: this header is intended to form the base for user-defined literals;
//once they are supported by GCC. eg:
//unsigned operator "" b(const char *s) { return binary(s); }
//-> signed data = 1001b;
//(0b1001 is nicer, but is not part of the C++ standard)
constexpr inline uintmax_t binary_(const char *s, uintmax_t sum = 0) {
return (
*s == '0' || *s == '1' ? binary_(s + 1, (sum << 1) | *s - '0') :
sum
);
}
constexpr inline uintmax_t octal_(const char *s, uintmax_t sum = 0) {
return (
*s >= '0' && *s <= '7' ? octal_(s + 1, (sum << 3) | *s - '0') :
sum
);
}
constexpr inline uintmax_t decimal_(const char *s, uintmax_t sum = 0) {
return (
*s >= '0' && *s <= '9' ? decimal_(s + 1, (sum * 10) + *s - '0') :
sum
);
}
constexpr inline uintmax_t hex_(const char *s, uintmax_t sum = 0) {
return (
*s >= 'A' && *s <= 'F' ? hex_(s + 1, (sum << 4) | *s - 'A' + 10) :
*s >= 'a' && *s <= 'f' ? hex_(s + 1, (sum << 4) | *s - 'a' + 10) :
*s >= '0' && *s <= '9' ? hex_(s + 1, (sum << 4) | *s - '0') :
sum
);
}
//
constexpr inline uintmax_t binary(const char *s) {
return (
*s == '0' && *(s + 1) == 'B' ? binary_(s + 2) :
*s == '0' && *(s + 1) == 'b' ? binary_(s + 2) :
*s == '%' ? binary_(s + 1) :
binary_(s)
);
}
constexpr inline uintmax_t octal(const char *s) {
return (
octal_(s)
);
}
constexpr inline intmax_t integer(const char *s) {
return (
*s == '+' ? +decimal_(s + 1) :
*s == '-' ? -decimal_(s + 1) :
decimal_(s)
);
}
constexpr inline uintmax_t decimal(const char *s) {
return (
decimal_(s)
);
}
constexpr inline uintmax_t hex(const char *s) {
return (
*s == '0' && *(s + 1) == 'X' ? hex_(s + 2) :
*s == '0' && *(s + 1) == 'x' ? hex_(s + 2) :
*s == '$' ? hex_(s + 1) :
hex_(s)
);
}
inline double fp(const char *s) {
return atof(s);
}
}
#endif
-90
View File
@@ -1,90 +0,0 @@
#ifndef NALL_BASE64_HPP
#define NALL_BASE64_HPP
#include <string.h>
#include <nall/stdint.hpp>
namespace nall {
struct base64 {
static bool encode(char *&output, const uint8_t* input, unsigned inlength) {
output = new char[inlength * 8 / 6 + 6]();
unsigned i = 0, o = 0;
while(i < inlength) {
switch(i % 3) {
case 0: {
output[o++] = enc(input[i] >> 2);
output[o] = enc((input[i] & 3) << 4);
} break;
case 1: {
uint8_t prev = dec(output[o]);
output[o++] = enc(prev + (input[i] >> 4));
output[o] = enc((input[i] & 15) << 2);
} break;
case 2: {
uint8_t prev = dec(output[o]);
output[o++] = enc(prev + (input[i] >> 6));
output[o++] = enc(input[i] & 63);
} break;
}
i++;
}
return true;
}
static bool decode(uint8_t *&output, unsigned &outlength, const char *input) {
unsigned inlength = strlen(input), infix = 0;
output = new uint8_t[inlength]();
unsigned i = 0, o = 0;
while(i < inlength) {
uint8_t x = dec(input[i]);
switch(i++ & 3) {
case 0: {
output[o] = x << 2;
} break;
case 1: {
output[o++] |= x >> 4;
output[o] = (x & 15) << 4;
} break;
case 2: {
output[o++] |= x >> 2;
output[o] = (x & 3) << 6;
} break;
case 3: {
output[o++] |= x;
} break;
}
}
outlength = o;
return true;
}
private:
static char enc(uint8_t n) {
//base64 for URL encodings
static char lookup_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
return lookup_table[n & 63];
}
static uint8_t dec(char n) {
if(n >= 'A' && n <= 'Z') return n - 'A';
if(n >= 'a' && n <= 'z') return n - 'a' + 26;
if(n >= '0' && n <= '9') return n - '0' + 52;
if(n == '-') return 62;
if(n == '_') return 63;
return 0;
}
};
}
#endif
-51
View File
@@ -1,51 +0,0 @@
#ifndef NALL_BIT_HPP
#define NALL_BIT_HPP
namespace nall {
template<int bits> constexpr inline unsigned uclamp(const unsigned x) {
enum { y = (1U << (bits - 1)) + ((1U << (bits - 1)) - 1) };
return y + ((x - y) & -(x < y)); //min(x, y);
}
template<int bits> constexpr inline unsigned uclip(const unsigned x) {
enum { m = (1U << (bits - 1)) + ((1U << (bits - 1)) - 1) };
return (x & m);
}
template<int bits> constexpr inline signed sclamp(const signed x) {
enum { b = 1U << (bits - 1), m = (1U << (bits - 1)) - 1 };
return (x > m) ? m : (x < -b) ? -b : x;
}
template<int bits> constexpr inline signed sclip(const signed x) {
enum { b = 1U << (bits - 1), m = (1U << bits) - 1 };
return ((x & m) ^ b) - b;
}
namespace bit {
//lowest(0b1110) == 0b0010
template<typename T> constexpr inline T lowest(const T x) {
return x & -x;
}
//clear_lowest(0b1110) == 0b1100
template<typename T> constexpr inline T clear_lowest(const T x) {
return x & (x - 1);
}
//set_lowest(0b0101) == 0b0111
template<typename T> constexpr inline T set_lowest(const T x) {
return x | (x + 1);
}
//round up to next highest single bit:
//round(15) == 16, round(16) == 16, round(17) == 32
inline unsigned round(unsigned x) {
if((x & (x - 1)) == 0) return x;
while(x & (x - 1)) x &= x - 1;
return x << 1;
}
}
}
#endif
-101
View File
@@ -1,101 +0,0 @@
#ifndef NALL_BMP_HPP
#define NALL_BMP_HPP
#include <nall/file.hpp>
//BMP reader / writer
//author: byuu
//note: only 24-bit RGB and 32-bit ARGB uncompressed images supported
namespace nall {
struct bmp {
inline static bool read(const string &filename, uint32_t *&data, unsigned &width, unsigned &height);
inline static bool write(const string &filename, const uint32_t *data, unsigned width, unsigned height, unsigned pitch, bool alpha = false);
};
bool bmp::read(const string &filename, uint32_t *&data, unsigned &width, unsigned &height) {
file fp;
if(fp.open(filename, file::mode::read) == false) return false;
if(fp.size() < 0x36) return false;
if(fp.readm(2) != 0x424d) return false;
fp.seek(0x000a);
unsigned offset = fp.readl(4);
unsigned dibsize = fp.readl(4);
if(dibsize != 40) return false;
signed headerWidth = fp.readl(4);
if(headerWidth < 0) return false;
signed headerHeight = fp.readl(4);
fp.readl(2);
unsigned bitsPerPixel = fp.readl(2);
if(bitsPerPixel != 24 && bitsPerPixel != 32) return false;
unsigned compression = fp.readl(4);
if(compression != 0) return false;
fp.seek(offset);
bool noFlip = headerHeight < 0;
width = headerWidth, height = abs(headerHeight);
data = new uint32_t[width * height];
unsigned bytesPerPixel = bitsPerPixel / 8;
unsigned alignedWidth = width * bytesPerPixel;
unsigned paddingLength = 0;
while(alignedWidth % 4) alignedWidth++, paddingLength++;
for(unsigned y = 0; y < height; y++) {
uint32_t *p = noFlip ? data + y * width : data + (height - 1 - y) * width;
for(unsigned x = 0; x < width; x++, p++) {
*p = fp.readl(bytesPerPixel);
if(bytesPerPixel == 3) *p |= 255 << 24;
}
if(paddingLength) fp.readl(paddingLength);
}
fp.close();
return true;
}
bool bmp::write(const string &filename, const uint32_t *data, unsigned width, unsigned height, unsigned pitch, bool alpha) {
file fp;
if(fp.open(filename, file::mode::write) == false) return false;
unsigned bitsPerPixel = alpha ? 32 : 24;
unsigned bytesPerPixel = bitsPerPixel / 8;
unsigned alignedWidth = width * bytesPerPixel;
unsigned paddingLength = 0;
unsigned imageSize = alignedWidth * height;
unsigned fileSize = 0x36 + imageSize;
while(alignedWidth % 4) alignedWidth++, paddingLength++;
fp.writem(0x424d, 2); //signature
fp.writel(fileSize, 4); //file size
fp.writel(0, 2); //reserved
fp.writel(0, 2); //reserved
fp.writel(0x36, 4); //offset
fp.writel(40, 4); //DIB size
fp.writel(width, 4); //width
fp.writel(-height, 4); //height
fp.writel(1, 2); //color planes
fp.writel(bitsPerPixel, 2); //bits per pixel
fp.writel(0, 4); //compression method (BI_RGB)
fp.writel(imageSize, 4); //image data size
fp.writel(3780, 4); //horizontal resolution
fp.writel(3780, 4); //vertical resolution
fp.writel(0, 4); //palette size
fp.writel(0, 4); //important color count
for(unsigned y = 0; y < height; y++) {
const uint32_t *p = (const uint32_t*)((const uint8_t*)data + y * pitch);
for(unsigned x = 0; x < width; x++) fp.writel(*p++, bytesPerPixel);
if(paddingLength) fp.writel(0, paddingLength);
}
fp.close();
return true;
}
}
#endif
-214
View File
@@ -1,214 +0,0 @@
#ifndef NALL_BPS_DELTA_HPP
#define NALL_BPS_DELTA_HPP
#include <nall/crc32.hpp>
#include <nall/file.hpp>
#include <nall/filemap.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
namespace nall {
struct bpsdelta {
inline void source(const uint8_t *data, unsigned size);
inline void target(const uint8_t *data, unsigned size);
inline bool source(const string &filename);
inline bool target(const string &filename);
inline bool create(const string &filename, const string &metadata = "");
protected:
enum : unsigned { SourceRead, TargetRead, SourceCopy, TargetCopy };
enum : unsigned { Granularity = 1 };
struct Node {
unsigned offset;
Node *next;
inline Node() : offset(0), next(nullptr) {}
inline ~Node() { if(next) delete next; }
};
filemap sourceFile;
const uint8_t *sourceData;
unsigned sourceSize;
filemap targetFile;
const uint8_t *targetData;
unsigned targetSize;
};
void bpsdelta::source(const uint8_t *data, unsigned size) {
sourceData = data;
sourceSize = size;
}
void bpsdelta::target(const uint8_t *data, unsigned size) {
targetData = data;
targetSize = size;
}
bool bpsdelta::source(const string &filename) {
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
source(sourceFile.data(), sourceFile.size());
return true;
}
bool bpsdelta::target(const string &filename) {
if(targetFile.open(filename, filemap::mode::read) == false) return false;
target(targetFile.data(), targetFile.size());
return true;
}
bool bpsdelta::create(const string &filename, const string &metadata) {
file modifyFile;
if(modifyFile.open(filename, file::mode::write) == false) return false;
uint32_t sourceChecksum = ~0, modifyChecksum = ~0;
unsigned sourceRelativeOffset = 0, targetRelativeOffset = 0, outputOffset = 0;
auto write = [&](uint8_t data) {
modifyFile.write(data);
modifyChecksum = crc32_adjust(modifyChecksum, data);
};
auto encode = [&](uint64_t data) {
while(true) {
uint64_t x = data & 0x7f;
data >>= 7;
if(data == 0) {
write(0x80 | x);
break;
}
write(x);
data--;
}
};
write('B');
write('P');
write('S');
write('1');
encode(sourceSize);
encode(targetSize);
unsigned markupSize = metadata.length();
encode(markupSize);
for(unsigned n = 0; n < markupSize; n++) write(metadata[n]);
Node *sourceTree[65536], *targetTree[65536];
for(unsigned n = 0; n < 65536; n++) sourceTree[n] = 0, targetTree[n] = 0;
//source tree creation
for(unsigned offset = 0; offset < sourceSize; offset++) {
uint16_t symbol = sourceData[offset + 0];
sourceChecksum = crc32_adjust(sourceChecksum, symbol);
if(offset < sourceSize - 1) symbol |= sourceData[offset + 1] << 8;
Node *node = new Node;
node->offset = offset;
node->next = sourceTree[symbol];
sourceTree[symbol] = node;
}
unsigned targetReadLength = 0;
auto targetReadFlush = [&]() {
if(targetReadLength) {
encode(TargetRead | ((targetReadLength - 1) << 2));
unsigned offset = outputOffset - targetReadLength;
while(targetReadLength) write(targetData[offset++]), targetReadLength--;
}
};
while(outputOffset < targetSize) {
unsigned maxLength = 0, maxOffset = 0, mode = TargetRead;
uint16_t symbol = targetData[outputOffset + 0];
if(outputOffset < targetSize - 1) symbol |= targetData[outputOffset + 1] << 8;
{ //source read
unsigned length = 0, offset = outputOffset;
while(offset < sourceSize && offset < targetSize && sourceData[offset] == targetData[offset]) {
length++;
offset++;
}
if(length > maxLength) maxLength = length, mode = SourceRead;
}
{ //source copy
Node *node = sourceTree[symbol];
while(node) {
unsigned length = 0, x = node->offset, y = outputOffset;
while(x < sourceSize && y < targetSize && sourceData[x++] == targetData[y++]) length++;
if(length > maxLength) maxLength = length, maxOffset = node->offset, mode = SourceCopy;
node = node->next;
}
}
{ //target copy
Node *node = targetTree[symbol];
while(node) {
unsigned length = 0, x = node->offset, y = outputOffset;
while(y < targetSize && targetData[x++] == targetData[y++]) length++;
if(length > maxLength) maxLength = length, maxOffset = node->offset, mode = TargetCopy;
node = node->next;
}
//target tree append
node = new Node;
node->offset = outputOffset;
node->next = targetTree[symbol];
targetTree[symbol] = node;
}
{ //target read
if(maxLength < 4) {
maxLength = min((unsigned)Granularity, targetSize - outputOffset);
mode = TargetRead;
}
}
if(mode != TargetRead) targetReadFlush();
switch(mode) {
case SourceRead:
encode(SourceRead | ((maxLength - 1) << 2));
break;
case TargetRead:
//delay write to group sequential TargetRead commands into one
targetReadLength += maxLength;
break;
case SourceCopy:
case TargetCopy:
encode(mode | ((maxLength - 1) << 2));
signed relativeOffset;
if(mode == SourceCopy) {
relativeOffset = maxOffset - sourceRelativeOffset;
sourceRelativeOffset = maxOffset + maxLength;
} else {
relativeOffset = maxOffset - targetRelativeOffset;
targetRelativeOffset = maxOffset + maxLength;
}
encode((relativeOffset < 0) | (abs(relativeOffset) << 1));
break;
}
outputOffset += maxLength;
}
targetReadFlush();
sourceChecksum = ~sourceChecksum;
for(unsigned n = 0; n < 32; n += 8) write(sourceChecksum >> n);
uint32_t targetChecksum = crc32_calculate(targetData, targetSize);
for(unsigned n = 0; n < 32; n += 8) write(targetChecksum >> n);
uint32_t outputChecksum = ~modifyChecksum;
for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n);
modifyFile.close();
return true;
}
}
#endif
-152
View File
@@ -1,152 +0,0 @@
#ifndef NALL_BPS_LINEAR_HPP
#define NALL_BPS_LINEAR_HPP
#include <nall/crc32.hpp>
#include <nall/file.hpp>
#include <nall/filemap.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
namespace nall {
struct bpslinear {
inline void source(const uint8_t *data, unsigned size);
inline void target(const uint8_t *data, unsigned size);
inline bool source(const string &filename);
inline bool target(const string &filename);
inline bool create(const string &filename, const string &metadata = "");
protected:
enum : unsigned { SourceRead, TargetRead, SourceCopy, TargetCopy };
enum : unsigned { Granularity = 1 };
filemap sourceFile;
const uint8_t *sourceData;
unsigned sourceSize;
filemap targetFile;
const uint8_t *targetData;
unsigned targetSize;
};
void bpslinear::source(const uint8_t *data, unsigned size) {
sourceData = data;
sourceSize = size;
}
void bpslinear::target(const uint8_t *data, unsigned size) {
targetData = data;
targetSize = size;
}
bool bpslinear::source(const string &filename) {
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
source(sourceFile.data(), sourceFile.size());
return true;
}
bool bpslinear::target(const string &filename) {
if(targetFile.open(filename, filemap::mode::read) == false) return false;
target(targetFile.data(), targetFile.size());
return true;
}
bool bpslinear::create(const string &filename, const string &metadata) {
file modifyFile;
if(modifyFile.open(filename, file::mode::write) == false) return false;
uint32_t modifyChecksum = ~0;
unsigned targetRelativeOffset = 0, outputOffset = 0;
auto write = [&](uint8_t data) {
modifyFile.write(data);
modifyChecksum = crc32_adjust(modifyChecksum, data);
};
auto encode = [&](uint64_t data) {
while(true) {
uint64_t x = data & 0x7f;
data >>= 7;
if(data == 0) {
write(0x80 | x);
break;
}
write(x);
data--;
}
};
unsigned targetReadLength = 0;
auto targetReadFlush = [&]() {
if(targetReadLength) {
encode(TargetRead | ((targetReadLength - 1) << 2));
unsigned offset = outputOffset - targetReadLength;
while(targetReadLength) write(targetData[offset++]), targetReadLength--;
}
};
write('B');
write('P');
write('S');
write('1');
encode(sourceSize);
encode(targetSize);
unsigned markupSize = metadata.length();
encode(markupSize);
for(unsigned n = 0; n < markupSize; n++) write(metadata[n]);
while(outputOffset < targetSize) {
unsigned sourceLength = 0;
for(unsigned n = 0; outputOffset + n < min(sourceSize, targetSize); n++) {
if(sourceData[outputOffset + n] != targetData[outputOffset + n]) break;
sourceLength++;
}
unsigned rleLength = 0;
for(unsigned n = 1; outputOffset + n < targetSize; n++) {
if(targetData[outputOffset] != targetData[outputOffset + n]) break;
rleLength++;
}
if(rleLength >= 4) {
//write byte to repeat
targetReadLength++;
outputOffset++;
targetReadFlush();
//copy starting from repetition byte
encode(TargetCopy | ((rleLength - 1) << 2));
unsigned relativeOffset = (outputOffset - 1) - targetRelativeOffset;
encode(relativeOffset << 1);
outputOffset += rleLength;
targetRelativeOffset = outputOffset - 1;
} else if(sourceLength >= 4) {
targetReadFlush();
encode(SourceRead | ((sourceLength - 1) << 2));
outputOffset += sourceLength;
} else {
targetReadLength += Granularity;
outputOffset += Granularity;
}
}
targetReadFlush();
uint32_t sourceChecksum = crc32_calculate(sourceData, sourceSize);
for(unsigned n = 0; n < 32; n += 8) write(sourceChecksum >> n);
uint32_t targetChecksum = crc32_calculate(targetData, targetSize);
for(unsigned n = 0; n < 32; n += 8) write(targetChecksum >> n);
uint32_t outputChecksum = ~modifyChecksum;
for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n);
modifyFile.close();
return true;
}
}
#endif
-121
View File
@@ -1,121 +0,0 @@
#ifndef NALL_BPS_METADATA_HPP
#define NALL_BPS_METADATA_HPP
#include <nall/crc32.hpp>
#include <nall/file.hpp>
#include <nall/filemap.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
namespace nall {
struct bpsmetadata {
inline bool load(const string &filename);
inline bool save(const string &filename, const string &metadata);
inline string metadata() const;
protected:
file sourceFile;
string metadataString;
};
bool bpsmetadata::load(const string &filename) {
if(sourceFile.open(filename, file::mode::read) == false) return false;
auto read = [&]() -> uint8_t {
return sourceFile.read();
};
auto decode = [&]() -> uint64_t {
uint64_t data = 0, shift = 1;
while(true) {
uint8_t x = read();
data += (x & 0x7f) * shift;
if(x & 0x80) break;
shift <<= 7;
data += shift;
}
return data;
};
if(read() != 'B') return false;
if(read() != 'P') return false;
if(read() != 'S') return false;
if(read() != '1') return false;
decode();
decode();
unsigned metadataSize = decode();
char data[metadataSize + 1];
for(unsigned n = 0; n < metadataSize; n++) data[n] = read();
data[metadataSize] = 0;
metadataString = (const char*)data;
return true;
}
bool bpsmetadata::save(const string &filename, const string &metadata) {
file targetFile;
if(targetFile.open(filename, file::mode::write) == false) return false;
if(sourceFile.open() == false) return false;
sourceFile.seek(0);
auto read = [&]() -> uint8_t {
return sourceFile.read();
};
auto decode = [&]() -> uint64_t {
uint64_t data = 0, shift = 1;
while(true) {
uint8_t x = read();
data += (x & 0x7f) * shift;
if(x & 0x80) break;
shift <<= 7;
data += shift;
}
return data;
};
uint32_t checksum = ~0;
auto write = [&](uint8_t data) {
targetFile.write(data);
checksum = crc32_adjust(checksum, data);
};
auto encode = [&](uint64_t data) {
while(true) {
uint64_t x = data & 0x7f;
data >>= 7;
if(data == 0) {
write(0x80 | x);
break;
}
write(x);
data--;
}
};
for(unsigned n = 0; n < 4; n++) write(read());
encode(decode());
encode(decode());
unsigned sourceLength = decode();
unsigned targetLength = metadata.length();
encode(targetLength);
sourceFile.seek(sourceLength, file::index::relative);
for(unsigned n = 0; n < targetLength; n++) write(metadata[n]);
unsigned length = sourceFile.size() - sourceFile.offset() - 4;
for(unsigned n = 0; n < length; n++) write(read());
uint32_t outputChecksum = ~checksum;
for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n);
targetFile.close();
return true;
}
string bpsmetadata::metadata() const {
return metadataString;
}
}
#endif
-219
View File
@@ -1,219 +0,0 @@
#ifndef NALL_BPS_PATCH_HPP
#define NALL_BPS_PATCH_HPP
#include <nall/crc32.hpp>
#include <nall/file.hpp>
#include <nall/filemap.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
namespace nall {
struct bpspatch {
inline bool modify(const uint8_t *data, unsigned size);
inline void source(const uint8_t *data, unsigned size);
inline void target(uint8_t *data, unsigned size);
inline bool modify(const string &filename);
inline bool source(const string &filename);
inline bool target(const string &filename);
inline string metadata() const;
inline unsigned size() const;
enum result : unsigned {
unknown,
success,
patch_too_small,
patch_invalid_header,
source_too_small,
target_too_small,
source_checksum_invalid,
target_checksum_invalid,
patch_checksum_invalid,
};
inline result apply();
protected:
enum : unsigned { SourceRead, TargetRead, SourceCopy, TargetCopy };
filemap modifyFile;
const uint8_t *modifyData;
unsigned modifySize;
filemap sourceFile;
const uint8_t *sourceData;
unsigned sourceSize;
filemap targetFile;
uint8_t *targetData;
unsigned targetSize;
unsigned modifySourceSize;
unsigned modifyTargetSize;
unsigned modifyMarkupSize;
string metadataString;
};
bool bpspatch::modify(const uint8_t *data, unsigned size) {
if(size < 19) return false;
modifyData = data;
modifySize = size;
unsigned offset = 4;
auto decode = [&]() -> uint64_t {
uint64_t data = 0, shift = 1;
while(true) {
uint8_t x = modifyData[offset++];
data += (x & 0x7f) * shift;
if(x & 0x80) break;
shift <<= 7;
data += shift;
}
return data;
};
modifySourceSize = decode();
modifyTargetSize = decode();
modifyMarkupSize = decode();
char buffer[modifyMarkupSize + 1];
for(unsigned n = 0; n < modifyMarkupSize; n++) buffer[n] = modifyData[offset++];
buffer[modifyMarkupSize] = 0;
metadataString = (const char*)buffer;
return true;
}
void bpspatch::source(const uint8_t *data, unsigned size) {
sourceData = data;
sourceSize = size;
}
void bpspatch::target(uint8_t *data, unsigned size) {
targetData = data;
targetSize = size;
}
bool bpspatch::modify(const string &filename) {
if(modifyFile.open(filename, filemap::mode::read) == false) return false;
return modify(modifyFile.data(), modifyFile.size());
}
bool bpspatch::source(const string &filename) {
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
source(sourceFile.data(), sourceFile.size());
return true;
}
bool bpspatch::target(const string &filename) {
file fp;
if(fp.open(filename, file::mode::write) == false) return false;
fp.truncate(modifyTargetSize);
fp.close();
if(targetFile.open(filename, filemap::mode::readwrite) == false) return false;
target(targetFile.data(), targetFile.size());
return true;
}
string bpspatch::metadata() const {
return metadataString;
}
unsigned bpspatch::size() const {
return modifyTargetSize;
}
bpspatch::result bpspatch::apply() {
if(modifySize < 19) return result::patch_too_small;
uint32_t modifyChecksum = ~0, targetChecksum = ~0;
unsigned modifyOffset = 0, sourceRelativeOffset = 0, targetRelativeOffset = 0, outputOffset = 0;
auto read = [&]() -> uint8_t {
uint8_t data = modifyData[modifyOffset++];
modifyChecksum = crc32_adjust(modifyChecksum, data);
return data;
};
auto decode = [&]() -> uint64_t {
uint64_t data = 0, shift = 1;
while(true) {
uint8_t x = read();
data += (x & 0x7f) * shift;
if(x & 0x80) break;
shift <<= 7;
data += shift;
}
return data;
};
auto write = [&](uint8_t data) {
targetData[outputOffset++] = data;
targetChecksum = crc32_adjust(targetChecksum, data);
};
if(read() != 'B') return result::patch_invalid_header;
if(read() != 'P') return result::patch_invalid_header;
if(read() != 'S') return result::patch_invalid_header;
if(read() != '1') return result::patch_invalid_header;
modifySourceSize = decode();
modifyTargetSize = decode();
modifyMarkupSize = decode();
for(unsigned n = 0; n < modifyMarkupSize; n++) read();
if(modifySourceSize > sourceSize) return result::source_too_small;
if(modifyTargetSize > targetSize) return result::target_too_small;
while(modifyOffset < modifySize - 12) {
unsigned length = decode();
unsigned mode = length & 3;
length = (length >> 2) + 1;
switch(mode) {
case SourceRead:
while(length--) write(sourceData[outputOffset]);
break;
case TargetRead:
while(length--) write(read());
break;
case SourceCopy:
case TargetCopy:
signed offset = decode();
bool negative = offset & 1;
offset >>= 1;
if(negative) offset = -offset;
if(mode == SourceCopy) {
sourceRelativeOffset += offset;
while(length--) write(sourceData[sourceRelativeOffset++]);
} else {
targetRelativeOffset += offset;
while(length--) write(targetData[targetRelativeOffset++]);
}
break;
}
}
uint32_t modifySourceChecksum = 0, modifyTargetChecksum = 0, modifyModifyChecksum = 0;
for(unsigned n = 0; n < 32; n += 8) modifySourceChecksum |= read() << n;
for(unsigned n = 0; n < 32; n += 8) modifyTargetChecksum |= read() << n;
uint32_t checksum = ~modifyChecksum;
for(unsigned n = 0; n < 32; n += 8) modifyModifyChecksum |= read() << n;
uint32_t sourceChecksum = crc32_calculate(sourceData, modifySourceSize);
targetChecksum = ~targetChecksum;
if(sourceChecksum != modifySourceChecksum) return result::source_checksum_invalid;
if(targetChecksum != modifyTargetChecksum) return result::target_checksum_invalid;
if(checksum != modifyModifyChecksum) return result::patch_checksum_invalid;
return result::success;
}
}
#endif
-79
View File
@@ -1,79 +0,0 @@
#ifndef NALL_COMPOSITOR_HPP
#define NALL_COMPOSITOR_HPP
#include <nall/intrinsics.hpp>
namespace nall {
struct compositor {
inline static bool enabled();
inline static bool enable(bool status);
};
#if defined(PLATFORM_X)
bool compositor::enabled() {
FILE *fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing'", "r");
if(fp == 0) return false;
char buffer[512];
if(fgets(buffer, sizeof buffer, fp) == 0) return false;
if(!memcmp(buffer, "true", 4)) return true;
return false;
}
bool compositor::enable(bool status) {
FILE *fp;
if(status) {
fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'true'", "r");
} else {
fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'false'", "r");
}
if(fp == 0) return false;
pclose(fp);
return true;
}
#elif defined(PLATFORM_WINDOWS)
bool compositor::enabled() {
HMODULE module = GetModuleHandleW(L"dwmapi");
if(module == 0) module = LoadLibraryW(L"dwmapi");
if(module == 0) return false;
auto pDwmIsCompositionEnabled = (HRESULT (WINAPI*)(BOOL*))GetProcAddress(module, "DwmIsCompositionEnabled");
if(pDwmIsCompositionEnabled == 0) return false;
BOOL result;
if(pDwmIsCompositionEnabled(&result) != S_OK) return false;
return result;
}
bool compositor::enable(bool status) {
HMODULE module = GetModuleHandleW(L"dwmapi");
if(module == 0) module = LoadLibraryW(L"dwmapi");
if(module == 0) return false;
auto pDwmEnableComposition = (HRESULT (WINAPI*)(UINT))GetProcAddress(module, "DwmEnableComposition");
if(pDwmEnableComposition == 0) return false;
if(pDwmEnableComposition(status) != S_OK) return false;
return true;
}
#else
bool compositor::enabled() {
return false;
}
bool compositor::enable(bool) {
return false;
}
#endif
}
#endif
-123
View File
@@ -1,123 +0,0 @@
#ifndef NALL_CONFIG_HPP
#define NALL_CONFIG_HPP
#include <nall/file.hpp>
#include <nall/string.hpp>
#include <nall/vector.hpp>
namespace nall {
namespace configuration_traits {
template<typename T> struct is_boolean { enum { value = false }; };
template<> struct is_boolean<bool> { enum { value = true }; };
template<typename T> struct is_signed { enum { value = false }; };
template<> struct is_signed<signed> { enum { value = true }; };
template<typename T> struct is_unsigned { enum { value = false }; };
template<> struct is_unsigned<unsigned> { enum { value = true }; };
template<typename T> struct is_double { enum { value = false }; };
template<> struct is_double<double> { enum { value = true }; };
template<typename T> struct is_string { enum { value = false }; };
template<> struct is_string<string> { enum { value = true }; };
}
class configuration {
public:
enum type_t { boolean_t, signed_t, unsigned_t, double_t, string_t, unknown_t };
struct item_t {
uintptr_t data;
string name;
string desc;
type_t type;
string get() const {
switch(type) {
case boolean_t: return { *(bool*)data };
case signed_t: return { *(signed*)data };
case unsigned_t: return { *(unsigned*)data };
case double_t: return { *(double*)data };
case string_t: return { "\"", *(string*)data, "\"" };
}
return "???";
}
void set(string s) {
switch(type) {
case boolean_t: *(bool*)data = (s == "true"); break;
case signed_t: *(signed*)data = integer(s); break;
case unsigned_t: *(unsigned*)data = decimal(s); break;
case double_t: *(double*)data = fp(s); break;
case string_t: s.trim("\""); *(string*)data = s; break;
}
}
};
linear_vector<item_t> list;
template<typename T>
void attach(T &data, const char *name, const char *desc = "") {
unsigned n = list.size();
list[n].data = (uintptr_t)&data;
list[n].name = name;
list[n].desc = desc;
if(configuration_traits::is_boolean<T>::value) list[n].type = boolean_t;
else if(configuration_traits::is_signed<T>::value) list[n].type = signed_t;
else if(configuration_traits::is_unsigned<T>::value) list[n].type = unsigned_t;
else if(configuration_traits::is_double<T>::value) list[n].type = double_t;
else if(configuration_traits::is_string<T>::value) list[n].type = string_t;
else list[n].type = unknown_t;
}
virtual bool load(const string &filename) {
string data;
if(data.readfile(filename) == true) {
data.replace("\r", "");
lstring line;
line.split("\n", data);
for(unsigned i = 0; i < line.size(); i++) {
if(auto position = qstrpos(line[i], "#")) line[i][position()] = 0;
if(!qstrpos(line[i], " = ")) continue;
lstring part;
part.qsplit(" = ", line[i]);
part[0].trim();
part[1].trim();
for(unsigned n = 0; n < list.size(); n++) {
if(part[0] == list[n].name) {
list[n].set(part[1]);
break;
}
}
}
return true;
} else {
return false;
}
}
virtual bool save(const string &filename) const {
file fp;
if(fp.open(filename, file::mode::write)) {
for(unsigned i = 0; i < list.size(); i++) {
string output;
output.append(list[i].name, " = ", list[i].get());
if(list[i].desc != "") output.append(" # ", list[i].desc);
output.append("\r\n");
fp.print(output);
}
fp.close();
return true;
} else {
return false;
}
}
};
}
#endif
-66
View File
@@ -1,66 +0,0 @@
#ifndef NALL_CRC32_HPP
#define NALL_CRC32_HPP
#include <nall/stdint.hpp>
namespace nall {
const uint32_t crc32_table[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
inline uint32_t crc32_adjust(uint32_t crc32, uint8_t input) {
return ((crc32 >> 8) & 0x00ffffff) ^ crc32_table[(crc32 ^ input) & 0xff];
}
inline uint32_t crc32_calculate(const uint8_t *data, unsigned length) {
uint32_t crc32 = ~0;
for(unsigned i = 0; i < length; i++) {
crc32 = crc32_adjust(crc32, data[i]);
}
return ~crc32;
}
}
#endif
-153
View File
@@ -1,153 +0,0 @@
#ifndef NALL_DIRECTORY_HPP
#define NALL_DIRECTORY_HPP
#include <nall/intrinsics.hpp>
#include <nall/sort.hpp>
#include <nall/string.hpp>
#include <nall/vector.hpp>
#if defined(PLATFORM_WINDOWS)
#include <nall/windows/utf8.hpp>
#else
#include <dirent.h>
#include <stdio.h>
#include <sys/types.h>
#endif
namespace nall {
struct directory {
static bool exists(const string &pathname);
static lstring folders(const string &pathname, const string &pattern = "*");
static lstring files(const string &pathname, const string &pattern = "*");
static lstring contents(const string &pathname, const string &pattern = "*");
};
#if defined(PLATFORM_WINDOWS)
inline bool directory::exists(const string &pathname) {
DWORD result = GetFileAttributes(utf16_t(pathname));
if(result == INVALID_FILE_ATTRIBUTES) return false;
return (result & FILE_ATTRIBUTE_DIRECTORY);
}
inline lstring directory::folders(const string &pathname, const string &pattern) {
lstring list;
string path = pathname;
path.transform("/", "\\");
if(!strend(path, "\\")) path.append("\\");
path.append("*");
HANDLE handle;
WIN32_FIND_DATA data;
handle = FindFirstFile(utf16_t(path), &data);
if(handle != INVALID_HANDLE_VALUE) {
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
}
}
while(FindNextFile(handle, &data) != false) {
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
}
}
}
FindClose(handle);
}
if(list.size() > 0) sort(&list[0], list.size());
for(auto &name : list) name.append("/"); //must append after sorting
return list;
}
inline lstring directory::files(const string &pathname, const string &pattern) {
lstring list;
string path = pathname;
path.transform("/", "\\");
if(!strend(path, "\\")) path.append("\\");
path.append("*");
HANDLE handle;
WIN32_FIND_DATA data;
handle = FindFirstFile(utf16_t(path), &data);
if(handle != INVALID_HANDLE_VALUE) {
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
}
while(FindNextFile(handle, &data) != false) {
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
}
}
FindClose(handle);
}
if(list.size() > 0) sort(&list[0], list.size());
return list;
}
inline lstring directory::contents(const string &pathname, const string &pattern) {
lstring folders = directory::folders(pathname); //pattern search of contents() should only filter files
lstring files = directory::files(pathname, pattern);
for(auto &file : files) folders.append(file);
return folders;
}
#else
inline bool directory::exists(const string &pathname) {
DIR *dp = opendir(pathname);
if(!dp) return false;
closedir(dp);
return true;
}
inline lstring directory::folders(const string &pathname, const string &pattern) {
lstring list;
DIR *dp;
struct dirent *ep;
dp = opendir(pathname);
if(dp) {
while(ep = readdir(dp)) {
if(!strcmp(ep->d_name, ".")) continue;
if(!strcmp(ep->d_name, "..")) continue;
if(ep->d_type & DT_DIR) {
if(wildcard(ep->d_name, pattern)) list.append(ep->d_name);
}
}
closedir(dp);
}
if(list.size() > 0) sort(&list[0], list.size());
for(auto &name : list) name.append("/"); //must append after sorting
return list;
}
inline lstring directory::files(const string &pathname, const string &pattern) {
lstring list;
DIR *dp;
struct dirent *ep;
dp = opendir(pathname);
if(dp) {
while(ep = readdir(dp)) {
if(!strcmp(ep->d_name, ".")) continue;
if(!strcmp(ep->d_name, "..")) continue;
if((ep->d_type & DT_DIR) == 0) {
if(wildcard(ep->d_name, pattern)) list.append(ep->d_name);
}
}
closedir(dp);
}
if(list.size() > 0) sort(&list[0], list.size());
return list;
}
inline lstring directory::contents(const string &pathname, const string &pattern) {
lstring folders = directory::folders(pathname); //pattern search of contents() should only filter files
lstring files = directory::files(pathname, pattern);
for(auto &file : files) folders.append(file);
return folders;
}
#endif
}
#endif
-115
View File
@@ -1,115 +0,0 @@
#ifndef NALL_DL_HPP
#define NALL_DL_HPP
//dynamic linking support
#include <nall/intrinsics.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/utility.hpp>
#if defined(PLATFORM_X) || defined(PLATFORM_OSX)
#include <dlfcn.h>
#elif defined(PLATFORM_WINDOWS)
#include <windows.h>
#include <nall/windows/utf8.hpp>
#endif
namespace nall {
struct library {
bool opened() const { return handle; }
bool open(const char*, const char* = "");
bool open_absolute(const char*);
void* sym(const char*);
void close();
library() : handle(0) {}
~library() { close(); }
library& operator=(const library&) = delete;
library(const library&) = delete;
private:
uintptr_t handle;
};
#if defined(PLATFORM_X)
inline bool library::open(const char *name, const char *path) {
if(handle) close();
handle = (uintptr_t)dlopen(string(path, *path && !strend(path, "/") ? "/" : "", "lib", name, ".so"), RTLD_LAZY);
if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".so"), RTLD_LAZY);
return handle;
}
inline bool library::open_absolute(const char *name) {
if(handle) close();
handle = (uintptr_t)dlopen(name, RTLD_LAZY);
return handle;
}
inline void* library::sym(const char *name) {
if(!handle) return 0;
return dlsym((void*)handle, name);
}
inline void library::close() {
if(!handle) return;
dlclose((void*)handle);
handle = 0;
}
#elif defined(PLATFORM_OSX)
inline bool library::open(const char *name, const char *path) {
if(handle) close();
handle = (uintptr_t)dlopen(string(path, *path && !strend(path, "/") ? "/" : "", "lib", name, ".dylib"), RTLD_LAZY);
if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".dylib"), RTLD_LAZY);
return handle;
}
inline bool library::open_absolute(const char *name) {
if(handle) close();
handle = (uintptr_t)dlopen(name, RTLD_LAZY);
return handle;
}
inline void* library::sym(const char *name) {
if(!handle) return 0;
return dlsym((void*)handle, name);
}
inline void library::close() {
if(!handle) return;
dlclose((void*)handle);
handle = 0;
}
#elif defined(PLATFORM_WINDOWS)
inline bool library::open(const char *name, const char *path) {
if(handle) close();
string filepath(path, *path && !strend(path, "/") && !strend(path, "\\") ? "\\" : "", name, ".dll");
handle = (uintptr_t)LoadLibraryW(utf16_t(filepath));
return handle;
}
inline bool library::open_absolute(const char *name) {
if(handle) close();
handle = (uintptr_t)LoadLibraryW(utf16_t(name));
return handle;
}
inline void* library::sym(const char *name) {
if(!handle) return 0;
return (void*)GetProcAddress((HMODULE)handle, name);
}
inline void library::close() {
if(!handle) return;
FreeLibrary((HMODULE)handle);
handle = 0;
}
#else
inline bool library::open(const char*, const char*) { return false; }
inline void* library::sym(const char*) { return 0; }
inline void library::close() {}
#endif
};
#endif
Loaded 100 of 1267 files, more files were not shown because too many files have changed in this diff. Show more