Compare commits

...

24 Commits
v019 ... v025

Author SHA1 Message Date
byuu
85fa3cc968 Update to bsnes v025 release.
bsnes is exactly three years old today. I've posted a new version which adds DSP-3 and DSP-4 special chip support. The DSP-3 is used by SD Gundam GX, and the DSP-4 is used by Top Gear 3000. Please note that the DSP-3 is not fully emulated, thusly SD Gundam GX is not fully playable. Also, due to lack of timing emulation with the DSP-4, the Top Gear 3000 track sometimes flickers in split screen mode. However, it is believed that Top Gear 3000 is fully playable.
I should also note that I have started on SuperFX emulation, as some will inevitably see said code in my source releases. What I have now is nothing more than a skeleton implementation, and absolutely nothing using it is playable yet. I am making absolutely no promises that I will ever be able to emulate this chip. It will take at least several months of work, and even then, the speed will probably be too slow to reach 60fps on any system, but ... I'm working on it. While I have no way to run tests on the actual SuperFX hardware, I will do the best I can to emulate the chip accurately. I will be emulating the caching and cycle delays as best I can, but the information I have on this chip is extremely limited, so don't expect miracles.
Lastly, as promised, I have released the special chips I have personally emulated to the public domain. See license.txt for more information if interested. I cannot release the special chips whose code I did not write to the public domain, but all of that is already available under the GPLv2 (from ZSNES) or the SNES9x license.
Changelog:
    - Added DSP-3 support, thanks to John Weidman, Kris Bleakley, Lancer, z80 gaiden
    - Added DSP-4 support, thanks to Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden
    - Started on support for SuperFX, no games playable as chip emulation is less than 1% complete
    - Unsupported special chips will now display an alert
    - Missing stbios.bin file when loading Sufami Turbo cartridges will now display an alert
    - Video settings now saved separately for windowed and fullscreen mode
    - Advanced option video<.mode>.synchronize can be enabled for vsync, but will cause sound crackling
    - Added menu option to toggle FPS counter
    - Minor source code cleanup
2007-10-15 10:03:36 +00:00
byuu
d1fcddee9c Update to bsnes v024r01? release.
New WIP up.

 This one merges the most recent DSP-3 / DSP-4 work. Not sure if it
fixes any bugs or not, but good to be up to date, right? Testing would
be appreciated.

             I also cleaned up the cart stuff a bit. Nicer enums,
removed some unused variables and such.

 Then I turned all of the special chip class object pointers into
actual objects. It was kind of stupid to dynamically create them all,
and was just wasting performance.

 I also finished adding all of the SuperFX registers, and mapped them
all to the GSU interface range ($3000-$32ff). Fixed an oversight with
the mapping, and added a new PCB database entry to get the memory map
for Yoshi's Island perfect. If you want to hear something nice, try
loading the USA version in this WIP with sound + speed regulation
enabled.

 Then I added a 'Show FPS' option to the misc menu. I also didn't
realize I was still embedding the SNES controller bitmap even though
it wasn't displayed anywhere, so for now that's been removed. Makes
the EXE and archive a bit smaller.

 Lastly, I redid the bsnes section of my site to look a little more
polished. Getting ready for 10/14. I've always hated the way SNES
emulator authors always cherry picked most of their screenshots to
show off their special chip support (jealousy because I didn't have
any for a long time), so I decided I'd do the exact same thing myself
this time :P
 Ripped off Overload yet again, this time I stole his screenshot
layout style. Sorry, Overload ... but imitation is the sincerest form
of flattery, right? :)

 Also, note that all of the ?page=bsnes_* URIs have changed to
?page=bsnes/* ... so if you get redirected to the main page from a
bookmark or something, that's why.

             Whew, busy day today ...

[No archive available]
2007-10-12 06:55:00 +00:00
byuu
9fd379613a Update to bsnes v024 release.
This is an interim release between some major changes to the video mode support, which may take a long time to complete. It also fixes a bug with CGRAM access timing, re-adds the Sufami Turbo load menu, and adds support for the ST-010 coprocessor, used by F1 Race of Champions.
To load Sufami Turbo cartridges, stbios.bin must be placed inside a folder named bios in the bsnes folder. There is not currently a warning if this file is missing.
2007-10-01 09:03:44 +00:00
byuu
aabf52d678 Update to bsnes v023r01? release.
Alright, I've posted the new WIP.

             Changelog:
             - CGRAM fix for WWF Super Wrestlemania
             - Updated to blargg's snes_ntsc library to version 0.2.2
             - Added ST and ST dual cart loading menu options (*)
             - Redesigned the video mode configuration panel a bit --
let me know what you think (**)

 (*) - You have to set path.bios to an -absolute- path, ./ is
currently broken and I need to fix that. So, set it to eg
"c:/path/to/bsnes/bios" where stbios.bin is inside that folder.
             (**) - The video menu obviously doesn't do anything, it's
just there for design advice / suggestions for now.

 You'll notice the icon is gone. This is because I built this version
with MinGW 4, and I'm not sure how to add the icon to MinGW apps.
You'll also notice it's ~6% faster on Core 2 processors as a result.

 The 16% speedup was only when PGO was enabled. But I can't enable
that, because it causes bsnes to crash randomly. GCC gets too risky
with its optimizations and ends up generating bad code (the GCC manual
states as much, I'm not just trying to blame problems in my app on GCC
here.)

 So, 6% is the best speedup we can do for now. Compare to v0.023
official if you like. You probably won't see the speedup on older
processors like the Pentium IV.

 EDIT: it seems like that MinGW vsnprintf problem is based on DLL
files on the local computer. Probably the MS VisualC runtime files.
The WIP works fine on my home PC (WinXP Pro), but not on my work PC
(Win2k). I'm going to have to stick with Visual C++ builds until I am
able to completely remove all sprintf-style calls from the emulator.

 If you get an error about memory at 0xffffffff which cannot be read,
you know why. Try building with Visual C++ if you have it, or maybe
there's some way to upgrade libc DLLs that the app is binding to.
Whatever DLL has vsnprintf is the one that needs to be updated, if at
all possible.

             Here's what the video config screen looks like at the
moment.

             [image]

 I tried putting the text at the top, that way there won't be any odd
gaps between the text and combo box dropdown, due to different sized
fonts on different platforms.

[No archive available]
2007-09-25 14:20:00 +00:00
byuu
c9ca01fe20 Update to bsnes v023 release.
I've recently fixed a bug in bsnes that I feel is serious enough to warrant a new release, even though little else has changed.
I attempted to build this release with MinGW, but ran into problems with profiling and JMA support, so this release was built with Visual C++ once again.
Changelog:
    - Fixed serious bug in S-SMP incw and decw instructions -- fixes sound bug in Emerald Dragon
    - Added Nach's MinGW fixes -- can now be compiled with MinGW/GCC3 or MinGW/GCC4
    - Fixed const char* cast warnings in GCC 4.2, thanks to [vEX] for the feedback
    - Updated source to use latest libraries for libco, libui, etc.
    - Added new advanced options to adjust aspect ratio correction
    - Cleaned up source code a bit
2007-09-16 19:30:35 +00:00
byuu
becf122aaa Update to bsnes v022r04? release.
Ok, I've posted a new WIP with the Emerald Dragon bug
fix. This time, I'm not posting the WIP publically. My last request
not to link directly to the file elsewhere was ignored, and ended up
on at least two emulation news sites (I won't mention names.) I'm not
trying to be a jerk about it, I really can't spare that kind of
bandwidth.

 If anyone has contributed any code or bug fixes, reported any
confirmed bugs, or is an emulator author I've spoken to in the past,
feel free to request a link to the WIP page from me in PM if desired.

               Sorry to everyone else. I'll have the new version out
as soon as possible.







> As for the AR advanced option, I think option 2 looks perfect.




 Done. I didn't add any sanity checks, so that people can have a
little fun with it. It's not going to be a GUI option, so only
advanced users can play with it anyway. Try setting a crazy aspect
like 3:1 and play a platform game. It's guaranteed to mess with your
mind.

 I also added the ... stuff, but I did not add the pause support back
in yet. Not sure if that'll make the next release, because it requires
some changes to the main loop functions that have been missing for a
while now. I usually like to leave more of a beta testing window
before messing with that stuff.







> byuu, you may know this, but on the front page of your web site, the
> link to your Philosophical Ramblings page is
> "http://localhost/index.php?page=articles/philosophy".




               Hahah, oops. No, I didn't notice that. I must have
copied the link from my browser instead of typing it manually.

 It's a stupid article, anyway. Didn't come out like I planned. I was
also reading some comments by Miguel de Icaza (supporting patent
pacts) and Linus Torvalds (bashing the hell out of C++ programmers),
and came across an interesting comment that got me thinking. Basically
that people who have any kind of notability really shouldn't go around
talking about things outside their specific expertise, because it
makes them look foolish when people take them too seriously (and
people do) as those two comments by de Icaza and Torvalds did. Lucky
for me I really _don't_ have any kind of notability, but it's a good
principle to adhere to anyway. Stick to talking about what I know
best. That goes against my whole personality though, so I probably
won't change at all anyway.

[No archive available]
2007-09-12 10:08:00 +00:00
byuu
1e130d7872 Update to bsnes v022r03 release.
Double post!

 I've uploaded a new WIP, which I'll make public (only to this forum,
please don't post about it anywhere else unless you mirror the file):







    http://byuu.org/files/bsnes_v022_wip03.zip




 This version adds all of Nach's MinGW fixes, updated libco, libui and
libfunctor, cleans up the code that detects if the main window has
focus or not (if not, ignore keyboard input), adds the new makefile
target win-mingw-lui, finally fixes all of the char* conversion
warnings with GCC 4.2.x (thanks [vEX]), and I'm sure there's more, but
I don't remember.

 The ZIP includes a Visual C++ generated binary, but it also works
with MinGW GCC4. It won't work with MinGW GCC3 because that one lacks
a C99-compliant vsnprintf function. You can hack your way around that
by editing src/lib/libstring_sprintf.cpp if you really want to use
MinGW GCC3.

 You may also need to change the CC / CPP variable names. I went with
the generic names mingw32-gcc and mingw32-g++, but the GCC4 binaries
have -sjlj or -dw2 appended to them. You'll also need to set
-I/path/to/directxheaders, or copy them all into
/path/to/mingw/include, since MinGW seems to ignore the include
environment variable.

 And finally, a bit of good news. It appears that MinGW GCC4 builds
binaries that are ~6% faster than Visual C++. That means with PGO
enabled, they should be at least ~16% faster than v0.022 official. If
I can figure out how to hide the ugly terminal window in the
background, I'll start making official releases with MinGW GCC4 from
now on.
2007-09-08 08:41:18 +00:00
byuu
c57c733d7d Update to bsnes v022 release.
Today marks a milestone for bsnes, and possibly for SNES emulation as a whole. With this new release, bsnes' compatibility has now reached 100.0%, with zero game-specific hacks. With every last commercially released game tested by both FitzRoy and tetsuo55 for at least five minutes each, all known bugs have been resolved.
Now, needless to say, I am referring to the emulation of the base SNES unit. As many SNES cartridges contain additional coprocessors on their PCBs, there are still unplayable titles. So how can I claim compatibility of 100%? Because I don't consider special chips inside game cartridges as part of the base SNES hardware. I realize that many people enjoy these games, and I do actively attempt to emulate as many coprocessors as possible (six are supported thus far). However, coprocessors such as the SuperFX and SA-1 continue to pose very significant challenges.
So, after nearly three years of development, I've finally achieved my primary goal. But it wasn't a complete victory ... I've learned a lot over the years. Emulation accuracy is not black and white -- there are heavy costs to pay and forced tradeoffs to achieve it. I no longer believe there is only one absolute path for emulation, as I did in 2004.
So does this mean bsnes is now perfect? Of course not. There are many technical details that are not emulated correctly. This also does mean that there are no bugs, merely that there are no bugs that we are aware of. While absolute verification of 100% compatibility is obvioulsy impossible, even by actually beating every single game from start to finish, this very well should be the first time any SNES emulator could claim zero known bugs with all known games tested. I very much expect this announcement to entice many new users to begin actively searching for bugs, in an effort to discredit my above claim. My response? Go for it! I would very much appreciate any and all discovered bugs to be posted here, so that they can be verified and addressed.
One major thing that needs to be said, is that there consists of one major hack in all SNES emulators, including bsnes: the use of scanline-based PPU renderers. This necessitates global hacks in all emulators to minimize their inaccuracies. I was going to write up a very long post here, going into specifics, but I've decided an article would be a better place for that. I will hopefully be writing up this article in a few days to post here.
In the meantime, one very important issue does need to be addressed. This version fixes a bug in Uniracers 2-player mode, where the game writes to OAM during active display. Like other PPU global hacks, Uniracers required a special consession. But because this hack only affects one game, it can very fairly be seen as cheating. Suffice to say, bsnes does not contain a game-specific hack, and the change made to fix Uniracers affects all games, but I do still very much consider it to be a hack. The fix I have added is quite literally and honestly more accurate than the behavior of bsnes v0.021. Before, writes to OAM and CGRAM during active display went where a programmer would expect, which would cause bugs when ran on real hardware. Uniracers is the only game known to do this, and it is very dangerous to do so. The writes do go through, but not where one would expect. The access address basically changes as the screen is rendered. With a scanline-based PPU, it is not possible to emulate the individual 
steppings of the PPU, as there is not enough precision. Further, the entire SNES emulation community has virtually no information on how active display OAM and CGRAM writes work. Now, as Uniracers is the only game known to do this, I had the choice of either intentionally remapping the writes to an arbitrary location, or change it to the address Uniracers expects. Neither would be more accurate than the other, as both are completely wrong from a haradware standpoint. So the decision was to either fix Uniracers and deal with some calling it a game-specific hack, or to leave it broken with absolutely no gain to accuracy. Rather than decide for myself, I asked those who have supported me over the past three years for their opinions. The decision was unanimous to fix Uniracers. You can read the discussion, along with a more technical explanation of the issue, here. I will be addressing this topic in much greater detail in the article I will be writing up shortly.
Changelog:
    - Fixed buffer overflow that was manifesting as corrupted tiles in Lemmings 2
    - OAM and CGRAM addresses are now invalidated during active display, however the algorithms for how this address invalidation occurs is currently still unknown, so reads/writes are mapped to static addresses for now
    - Re-added cheat code editor.
    - Windows only: keypresses when main emulation window is not active are ignored once again
2007-08-04 19:54:35 +00:00
byuu
e41aa25887 Update to bsnes v021r02? release.
I've posted a new private WIP. This one just adds the
cheat code editor back in again. Feedback on how it works is
appreciated. You'll notice it's a lot simpler than v0.019's cheat
editor ... I was going for simplicity this time. Editing a code means
deleting and re-adding it (or edit the text file directly). Yes, I
realize it's damn annoying entering codes because the emulator detects
your keypresses as controller presses (unless you're using a joypad).
Sorry, I still need to add code to determine if the active window is
the main emulator window or not for GTK+ before I can fix this on both
ports.

 Hopefully I can get that in before v0.022, but no promises. Worst
case, I'll add a dummy Window::active() function that always returns
true for GTK+ if needed.

 The cheat editor works the exact same on Windows and Linux, so this
should be the first release to allow Linux users to use it.

 Looking more at how useful bsnes is in its' current form ... I'm
simply not going to be able to walk away from it. Fuck it, I'll just
have to split the emulator and maintain two separate versions. It may
cost me some time, but whatever. It'll be good practice in trying to
streamline things to share as much code as possible. I'll keep them
together in one version as long as possible, too (using #defines and
such).

 If I do this, any suggestions on how to differentiate the two
versions? Different names? Different acronyms after bsnes (eg bsnes/AE
and bsnes/SE ...)? Different icons?







> One important point imo is the potential for "code longetivity".
> That is, I'd like the original, untouched code to continue to exist
> (while permitting derivative works) many decades from now.




 No matter the license, that won't change. People can close derived
works with PD, but it's their code that they added which becomes
closed, not mine. It won't make my code cease to be.

 It's not like it all matters that much. Regardless of license, anyone
is always free to get PD access to my code by asking. This is just me
trying to get a public consensus on whether or not I should allow
people to use my code without my permission, and to what extent I
should allow it.

 I was hoping the votes would be less 'all over the board' like the
Uniracers fix ... this vote isn't going very well. Sigh.

 It'd be annoying specifying licenses on everything. Maybe I'll just
bundle the core components (cpu, smp, ppu, dsp, memory, chip sans c4
(I don't own the rights to that)) and stick them in a separate
downloadable archive that's PD [or GPL w/permission exception]. That
way, I'm giving away the stuff that's important and can help others
the most, the emulation core. If someone can't be bothered to ask me
for mine, then they can write their own GUI. Call the package
something like 'libbsnes'. Meh.

[No archive available]
2007-08-03 08:23:00 +00:00
byuu
435f7d4371 Update to bsnes v021r01? release.
Alright, I've posted the new WIP.

             This one's really important, so please test it
thoroughly! :D
 I've ran it through my usual list of troublesome games, and
everything looks good, but it's possible I've overlooked something.

             The new config file settings are:
             ppu.hack.oam_address_invalidation
             ppu.hack.cgram_address_invalidation

 Set to true, OAM goes to 0x0218 (for Uniracers), CGRAM to 0x0000
(address is insignificant, we know of zero examples of this behavior,
so the address chosen does not matter for now). Set to false, the
writes are allowed and go where 'expected' (by programmers, not by
hardware).

 There's a slight difference in that OAM access is invalid even during
hblank, whereas CGRAM is obviously not (that's how games draw those
gradient fades and such).

             This WIP also has the Lemmings II fix.

             ---

 Now, I know I said I wouldn't bring this up again, but meh. So,
assuming I decide to go full force at this PPU renderer ... I still
want to let bsnes live on in its' current form, even if that means
losing my userbase to a competitor :(
 I'm planning for the next release to allow derivative works, in hopes
that someone will continue it. Does anyone have any objections to
that? Would it be better to use GPLv2/3 to ensure source availability
(even though I disagree with the notion of 'freedom through
restrictions' -- I liken it to becoming your enemies to defeat them),
or better to use PD to ensure the widest possible use of the code
(even if that means the source can be closed off to the public, and
the binary sold for profit -- which I also detest as immoral)? I
realize the latter means the value of all of my work will be lost, but
I never intended to profit from any of this anyway, so ...

 If you prefer GPL, please specify either v2 only, v2+ or v3. I can
use v3 and grant ZSNES an exception to use it under v2, so their v2
only license won't be a problem.

             Some examples:
             ZSNES is GPLv2, which got them the source to Zsnexbox.
 PocketNES is PD, which got the emulator used in commercial software
by Atlus, Hudson and Jaleco (though the assholes couldn't even be
bothered to send a thank you letter to the PocketNES devs).

 EDIT: I can also stick with the current license, a no-derivative one,
and do my best to maintain bsnes' old PPU renderer, if you like. But I
won't lie ... the pace of development _will_ slow down a lot on the
older version (it shouldn't affect my new PPU development speed much)
if we go with this option.

             Once again, I'll go with community opinion this time. I'm
personally not casting a vote for either.

[No archive available]
2007-08-02 08:46:00 +00:00
byuu
a1980fab09 Update to bsnes v021 release.
This is a maintainence release. I am mostly releasing this for the sake of the recently released Der Langrisser translation.
Changelog:
Windows port can once again map joypads through the Input Configuration panel
Using enter or spacebar to assign a key should no longer instantly map those keys
F11 now toggles fullscreen mode
Esc now toggles menu on and off (use F11+Esc combined to hide UI completely)
Fixed a bug in King of Dragons (J, U, E), KOFF was not cleared during S-DSP power(), thanks to FitzRoy for the report, and blargg for assistance fixing the bug
Fixed serious crashing error with File->Load on Linux/amd64 port
Hopefully fixed min/max undefined error on GCC 4.2.0, but I am unable to test to verify
Fixed many cast const char* to char* warnings for GCC 4.2.0, but some probably remain, as again, I am unable to test as I lack GCC 4.2.0
Set XV_AUTO_COLORKEY to 1 for Video/Xv renderer. Should fix some video drivers where there was no output, especially after running mplayer, etc. Thanks to sinimas for the fix
Added clear_video() to Video/Xv renderer. Green edges at the bottom and right sides of the video output are now gone, and unloading a ROM will clear video
I have finally figured out how to poll the keyboard status in real-time through Xorg: the XQueryKeymap function. I will be rewriting the Linux key capture system to use this, instead of capturing window key up / down messages through GTK+. This will finally allow me to completely abstract the UI from the hardware video, audio and input interfaces: a necessary step toward Linux joypad support.
2007-06-10 19:27:46 +00:00
byuu
ebb234ba5f Update to bsnes v020 01 release.
[No changelog available]
2007-06-05 15:50:59 +00:00
byuu
2cc7fe30b4 Update to bsnes v020 release.
Five months and 43 WIP releases in the making, today I am releasing bsnes v0.020. I'd really like to express my thanks to blargg, for he has written a new S-DSP emulator that is an impressive 32 times more precise than all existing S-DSP emulators. It is now bus-accurate, and should produce bit-perfect sound output to that of a real SNES, excepting very minor, very extreme edge cases. Not only did he do this, he went out of his way to develop a special version exclusively for bsnes to ease licensing concerns and take advantage of bsnes' unique features, notably cothreads. I can't thank him enough. Unfortunately, bsnes has taken a ~10% speed hit over v0.019 by using this new S-DSP emulator, but I must stress the speed hit is entirely due to the way bsnes is implemented. blargg's standalone S-DSP emulator is very, very fast. Anyone is free to take a look at his S-DSP emulator, as he has released it as open source under the LGPL, by visiting his homepage, here.
Unfortunately, the new cross-platform UI is not entirely finished. Some sacrifices had to be made to support libui. Specifically, the following features are missing from v0.019, but will hopefully be added back in future releases:
    - Fullscreen support
    - Input Configuration panel cannot capture joypad input. Joypad support is still present, but it must be mapped manually through the Advanced panel or through editing bsnes.cfg by hand
    - The Cheat Code Editor is missing, but cht files can still be used from bsnes v0.019, and created by hand
    - Sufami Turbo support is not accessible from the UI
    - The UI on Windows is slightly less polished due to compromises to allow the UI to be readable on Linux.
I am sorry for the rough edges listed above, but I wanted to get a new release out, as it has been over five months since the last release, and I really want the world to be able to experience blargg's new S-DSP emulator.
Changelog:
    - Added blargg's new S-DSP emulator, runs at 1.024mhz. Many thanks to blargg for this, as this puts all portions of SNES emulation except for the S-PPU at bus-accuracy
    - blargg's S-DSP core fixes bugs in both Koushien 2 (J) and Toy Story (U)
    - Corrected all S-SMP cycle timings to be hardware accurate. Thanks to blargg for creating an amazing test ROM that tested every possible opcode
    - Corrected S-CPU wai instruction timing, fixes Mortal Kombat II
    - Reverted HDMA sync emulation once more to fix Breath of Fire II (G) and Secret of Mana (U)
    - Completely rewrote user interface to use libui, which is a wrapper that allows the same code to produce the same UI on both Windows (through the Win32 API) and Linux (through the GTK+ API)
    - Corrected $2100.d7 OAM reset behavior, thanks to research from anomie
    - Massively revamped the Linux port, should compile with no warnings or errors now
    - Added 64-bit support to libco, tested on FreeBSD/amd64, should work on Linux as well
    - Revamped makefile with suggestions from Nach
    - Improved Linux Xv renderer to use the far more common YUY2 format, which should work on most Xorg drivers, allowing hardware accelerated video scaling
    - Completely rewrote config file system. bsnes.cfg is now saved to user's profile folder on both Windows and Linux, allowing multi-user support
    - A lot more work has been done behind the scenes, including massive code cleanups and portability improvements
You may download the new version on the main bsnes page.
2007-06-03 00:20:00 +00:00
byuu
5c3c872b78 Update to bsnes v019r41? release.
New WIP up.

 I've replaced the interface::input setup, since Visual C++ was having
problems with it. I wanted something that wasn't so seemingly directly
linked to SNESInterface, anyway. Now I have InputManager, which will
handle not only all of the joypad mappings, but the GUI shortcut keys
as well. Yes -- I finally have all the code in place to support user-
defined shortcut keys. See? Something good did come out of the rewrite
after all. Dynamic keyboard mapping works on Windows now, but there
probably won't be joypad capture support until v0.021.

 Further, I have added SHGetFolderPath to the Windows port. libbase.h
sadly requires shell32.lib now. I haven't tested this on 9x, but I
don't believe bsnes has worked on 9x in a long, long time now. I've
also heard you can copy shfolder.dll or something to use it on 9x
anyway.

 Anyway, the config file now saves in your 'Application Data' folder
on Windows, and in your local directory on Linux. There's no need to
worry about what happens when you update bsnes and don't delete the
file ... as I use a text-based config file, like ZSNES / PSR, no harm
will come of it. Old variables will be flushed out, new variables will
be added with default values upon first load of the new version.
Thanks again to Nach for the code and help with this.

             Lastly, I've added a bsnes license page. So instead of
debating whether to look up four letter English words in Perens',
Stallman's or Webster's dictionary, you can just link to that page
instead :)

Again, the license applies to current and previous versions of bsnes.
If and when it forks, the fork will likely be licensed in a way that
others can take over the old version.

 Opinions on how to fix contradictions / loopholes welcome, blanket
statements that it's totally flawed without describing why or how are
not. Thanks in advance.

[No archive available]
2007-05-30 05:00:00 +00:00
byuu
36bf915244 Update to bsnes v019r40 release.
Ok, here's a public WIP for everyone:







    http://byuu.cinnamonpirate.com/files/bsnes_v019_wip40.zip




               Please ... if you link to this post or file elsewhere,
please mirror it.

               Fixes since wip39:
               - menu enter event captured, audio no longer hangs when
entering the menu.
 - multiple click problems resolved for all menu items plus list box
controls. Behavior should now be the same on both Windows and Linux,
but further polish is definitely needed here.
               - buttons to set values on input config and advanced
panels are now disabled when no item is selected.

               Known problems:
 - Windows/VC++ port is still complaining about that
interface::input.bind() thing. I believe it is a compiler problem. I
am not working around it, as I prefer a real fix. If anyone can help,
please see src/ui/lui/settings/ui_inputconfig.cpp, look for that line.
It is #if !defined(_MSC_VER) blocked at the moment. Until this is
resolved, you must restart before input settings take effect.
 - Joypads cannot be auto polled on input config screen. You can set
the values manually on the advanced tab, they use the same values as
bsnes v019, IIRC.
 - When pressing enter (or spacebar on Linux) on the input config
panel, the dialog pops up and closes right away assigning that key. I
have no easy way to fix this, since I can't poll the realtime status
of those keys on Linux to wait for them to clear before showing the
input capture window. It would really be immensely useful to be able
to do that.
 - Linux with ati driver requires you to move the window one time to
make the image visible ... I have no idea why this is needed. nv and
nvidia drivers work fine. Use the gtk renderer if you don't like the
chroma blending that using YUY2 mode requires.
               - Linux port does not focus properly to panel list when
opening config screen.
 - Config file still saves to startup working directory, rather than
the user folder. Still planning to work on that.
 - UI is still pretty ugly on Windows, but overall it's not too bad.
Looks beautiful on Linux, though ... maybe if I could find a way to
enable theme support for Windows. I tried making a .manifest file and
using mt, and setting WINVER + _WIN32_WINNT to 0x0500, none of those
did anything.
 - Cheat code editor has not been reimplemented yet. Really the last
major thing holding back a new release, but the above are pretty
important, too.

               Let me know if anything else major pops up.







> Plus it prevents a smart user/admin from making their program
> directory read-only.




               Once again, blargg has the most convincing argument :)
               Wouldn't want that config file on a read-only medium,
eg CD-ROM.
               I was wanting to implement this on Windows anyway, but
this makes it something I simply have to do.

[No archive available]
2007-05-29 08:37:00 +00:00
byuu
045a0f7e79 Update to bsnes v019r24? release.
New WIP. This one adds a GDI renderer for windows. If
anyone wants to test it, edit bsnes.cfg and set system.video to "gdi".
It will be very slow, obviously. It's just there for the hell of it,
as another fallback I guess. I'd be interested if it didn't work for
someone.
I had to add the code to libui to support pixel buffer images, so now
I can add things like the controller art into the new lui port, and
it'll work on Windows and Linux. The best part is that I can make
these image buffers anywhere, so things like PPU VRAM / OAM / CGRAM
viewers in the debugger will now not only be possible, but trivial, to
add in the future.

 Refined libui a lot more, but I did not merge that into this bsnes
WIP, because it would break the source pretty bad. Still working on
the API, too, so I'll probably hold off a bit longer. After I get the
new libui merged in, I can start working on that configuration
settings window. That window is the only thing holding up a new
official release.

 I'm trying to figure out how the hell you enable WinXP themes now. I
tried making a manifest file, even attaching the manifest to the EXE
directly with the mt tool, but it's still drawing the controls using
the old win32 compatibility mode.







> I can see that he hesitates to add "MAXI" codes and has no multiple
> codes for any game, despite how prevalent I've found them to be.




 You have cartridges where it's the exact same game (eg bit-for-bit
identical ROM dumps), with the only difference being the PCB codes?
Care to cite an example? The last two digits may change for revisions
of the same game, obviously.

 That complicates things, but there's no harm in just picking one in
that case. If the game didn't work with that PCB, it wouldn't have
been released with it, so ...

[No archive available]
2007-04-11 12:51:00 +00:00
byuu
a209e6ffbe Update to bsnes v019r23 release.
Ok, this is a very important WIP release. Note that
this file is rather large, please mirror it if you must link to it
elsewhere.







    http://byuu.cinnamonpirate.com/files/bsnes_v019_wip23.zip




               Included are two executables:
               bsnes_adsp.exe - This version uses anomie's S-DSP
emulator, clocked at 32khz
               bsnes_bdsp.exe - This version uses blargg's S-DSP
emulator, clocked at 1.024mhz

 Please note that blargg's code is experimental and in-progress. That
said, I have been unable to find any errors with it so far. I hope I
haven't missed anything blargg wanted me to do before release.
Everyone, please give your thanks to blargg for creating this emulator
and allowing me to use his code :)

 This day marks an important milestone, at least in bsnes, possibly in
the SNES emulation scene: the addition of a subsample-accurate S-DSP
emulator brings us one major step closer to the most faithful SNES
emulation that will ever be possible. Excepting bugs, this now gives
us bus-accurate S-CPU, S-SMP and S-DSP cores. It is not possible (nor
desirable) in software to get more precise than bus-level accesses.
The only core component remaining using an older, less faithful
approach is the S-PPU[1/2], and is not so coincidentally the source of
the only remaining bugs in bsnes. This will very likely be the biggest
leap forward in accuracy that will ever be seen for S-DSP emulation
from this date on.

 The old win32 interface is now completely broken, so I am forced to
distribute using lui. As such, I've fixed the NTSC/PAL mode switches,
and added software video filter selection to the UI. Any configuration
changes that are not in the menu will have to be done via the config
file for the time being. I have also added the log audio data option
back to the misc menu. If you are not able to get 60fps in bsnes, or
would like to analyze the audio output between adsp and bdsp in
another program, you can use this option. Also, I'm aware of the lui-
specific issues, such as audio repeating when entering menus. lui is
still a work in progress.

 Please test all of the games you can, and look for subtle audio
differences and the like. Bugs, improvements, whatever, would be very
useful to know. Please keep in mind that every commercial game ever
released was tested by both FitzRoy and tetsuo55, and there are
currently zero known problems with anomie's S-DSP emulator. Also note
that blargg's emulator will be slower, by nature of being more low-
level. I'll leave the decision on which core to enable by default to
you guys. Eventually, I'll have polymorphism fully functional, and
this will be a runtime-selectable option, and not require two separate
builds. But still, we unfortunately have to pick one to be the default
setting, which I hope does not offend anyone :(

 I'm very appreciative and in debt to both anomie and blargg for their
help with S-DSP emulation. They have both done a very large service to
us all by creating these cores, so I thank both of them again for all
their hard work, and for allowing me to use their work in bsnes.

[No archive available]
2007-03-07 10:27:00 +00:00
byuu
3bf672dd97 Update to bsnes v019r19? release.
Ok, added blargg's changes. Played four levels, seems to be working
fine.

 Posted a new WIP with this change. I also replaced libkeymap with a
new implementation of it, this one is designed to work with window key
messages, meaning we can finally have input configuration for GUI
events and such in the future, and Linux users will finally have input
support shortly.

             Still not now, though. Input on Windows might be a little
sketchy, as well.

             Just need to create an InputWM class for Linux.

[No archive available]
2007-03-06 10:15:00 +00:00
byuu
157ddf3e8f Update to bsnes v019r18? release.
Unfortunately, even an S/PDIF link from a real SNES isn't good enough,
as we can't verify/match its' CPU<>SMP communications. Our best bet
for verification is still the echo buffer.

I uploaded a new private WIP. This build is just demonstrating part of
the new UI. I'm trying to move back to putting everything commonly
used in the menubar, and moving all of the obscure/complex stuff out
into separate windows.

             So far, lots of stuff is still missing, and the speed
setting (not enable) doesn't work.

 How does the video mode configuration feel in this WIP compared to
v0.019's video settings panel? Easier, better, worse? I realize it
loses a bit of flexibility (eg with custom resolutions), but eh. I'd
rather go back to simplicity than feature bloat.

[No archive available]
2007-02-19 03:37:00 +00:00
byuu
ea23bf53ae Update to bsnes v019r17 release.
Ok, as promised, a public WIP build:







    http://byuu.cinnamonpirate.com/files/bsnes_v019_wip17.zip




               As always, please be generous with this one. If you
must link to it elsewhere, please at least mirror it.

 This should finally take care of the Toy Story bug. Yes, the audio
should halt roughly. The developers felt the need to use an evil trick
to force the audio to release faster than it normally should.

[No archive available]
2007-02-18 04:29:00 +00:00
byuu
d4598e1d01 Update to bsnes v019r13a release.
(Repost, since this got bumped by another page, but
updated message.)

 Ok, this build has TRAC's and my idea for an S-DSP EDL fix applied.
EDL writes take effect immediately, and echo index bounds checking
occurs before FIR filtering and echo buffer writes. Please test this
with all of the really really picky/sensitive audio games you're aware
of, and see if you notice a difference between this and v0.019
official. Obviously, the sound differences should only exist in echo
effects, but luckily just about every game out there uses the echo
buffer. Note any differences you find either way, but I'm particularly
interested if things get worse, which will imply this fix is incorrect
(assuming the difference is verified in hardware as being correct in
v0.019 official), and we can try out the fix idea suggested by DMV27.
If no one finds any new audio bugs, we'll assume the fix was correct.

 And no, there's no audio resampling in this. I think log audio data
might still work, if that'll make it easier. It might not, the win32
port is falling apart as I rewrite the cross-platform port.







    http://byuu.cinnamonpirate.com/files/bsnes_v019_wip13.zip




 If anyone insists on posting about this on some other site (I'd
prefer not, as always), please at least mirror the file.

 Update: audio logger works. I binary compared two files. The only
difference is that audio is being output four samples sooner now,
they're otherwise exact matches. Doesn't seem to be a bad thing by any
means.

[No archive available]
2007-02-09 08:50:00 +00:00
byuu
f9a8564af0 Update to bsnes v019r11 release.
Ok, I tried my best to add the audio synchronization
method (drop video frames) yet again, and once again failed
completely.

 The below WIP is completely unusuable as it stands, so please don't
link to it, host it anywhere else, or even download it unless you can
help with the programming. I'm not going to be able to fix this myself
as I've tried countless times over the last two years in vain to fix
it.







    http://byuu.cinnamonpirate.com/files/bsnes_v019_wip11.zip




 The included config file is important: it uses the DirectDraw
renderer instead of the D3D renderer, and has triple buffering
enabled.

               The relevant code is in src/ui/video/ddraw.cpp and
src/ui/audio/dsound.cpp.

               The most important code is below, but obviously any
tests would need the above WIP to build and try out.







    void AudioDS::run(uint32 sample) {
                       uiVideo->tick();
                       data.buffer[data.buffer_pos++] = sample;

                       if(data.buffer_pos < latency)return;

                       uint32 ring_pos, pos, size;
                       do {
                       Sleep(1);
                       uiVideo->tick();
                       dsb_b->GetCurrentPosition(&pos, 0);
                       ring_pos = pos / data.ring_size;
                       } while(config::system.regulate_speed == true
    && ring_pos == data.ring_pos);

                       data.ring_pos = ring_pos;
                       void *output;
                       if(dsb_b->Lock(((data.ring_pos + 2) % 3) *
    data.ring_size,
                       data.ring_size, &output, &size, 0, 0, 0) ==
    DS_OK) {
                       //Audio::resample_hermite((uint32*)output,
    data.buffer, latency, data.buffer_pos);
                       memcpy(output, data.buffer, data.ring_size);
                       dsb_b->Unlock(output, size, 0, 0);
                       }

                       data.buffer_pos = 0;
                       }

                       bool VideoDD::lock(uint16 *&data, uint &pitch)
    {
                       if(video_buffer[video_active]->Lock(0, &ddsd,
    DDLOCK_WAIT, 0) != DD_OK) return false;
                       video_valid[video_active] = false;
                       pitch = ddsd.lPitch;
                       data = (uint16*)ddsd.lpSurface;
                       return data;
                       }

                       void VideoDD::unlock() {
                       video_buffer[video_active]->Unlock(0);
                       }

                       void VideoDD::refresh() {
                       video_valid[video_active] = true;
                       video_active ^= 1;
                       tick();
                       }

                       void VideoDD::tick() {
                       if(video_valid[0] == false && video_valid[1] ==
    false) return; //nothing to render
                       uint idx = video_valid[!video_active] == true ?
    !video_active : video_active;
                       // if(video_valid[!video_active] == false)
    return;
                       //uint idx = !video_active;

                       if(settings.triple_buffering == true) {
                       BOOL in_vblank;
                       lpdd7->GetVerticalBlankStatus(&in_vblank);
                       if(in_vblank == false) return;

                       //DWORD scanline;
                       // lpdd7->GetScanLine(&scanline);
                       // if(scanline < screen_height()) return;

                       //
    lpdd7->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, 0);
                       }

                       HRESULT hr;
                       RECT rd, rs;
                       snes.get_video_info(&vi);
                       SetRect(&rs, 0, 0, vi.width, vi.height);

                       POINT p = { 0, 0 };
                       ClientToScreen(hwnd, &p);
                       GetClientRect(hwnd, &rd);
                       OffsetRect(&rd, p.x, p.y);

                       hr = screen->Blt(&rd, video_buffer[idx], &rs,
    DDBLT_WAIT, 0);
                       video_valid[idx] = false;

                       if(hr == DDERR_SURFACELOST) {
                       screen->Restore();
                       video_buffer[0]->Restore();
                       video_buffer[1]->Restore();
                       }
                       }




               What I'm basically doing is:
 Audio keeps a ring buffer, and waits until the temporary buffer fills
up before forcing the emulator to sleep until the audio playback
catches up. Every time an audio sample is generated, and every time
the emulator sleeps for one millisecond, it gives Video a chance to
run.

 Video has two backbuffers (a poor man's triple buffering, since that
doesn't work in windowed mode for DDraw). The PPU renders the entire
screen line by line, but it doesn't go from the PPU to the video card
until Video::video_lock is called. At this time, the current buffer
sets a flag to say it's contents are invalid, then it draws to the
frame, then sets a flag saying the current contents are again valid.
Finally, it calls the Video tick function to finish.

 Every time the Video tick function is called from Audio (well over
32,000 times a second, so it should have good precision for detecting
vblank edges).

 First, it will see if any frames have completely rendered. If not, it
will give up and return. Next, it will see if "triple buffering"
(really a vsync now, but emulates triple buffering at least) is
enabled. If so, it will return and do nothing if not in vblank.
Otherwise, or if triple buffering is disabled, it will continue. Next,
it finds the most recently rendered video frame that was valid and
blits that to the screen, and then sets that frame to invalid, so that
it is not rendered again (though it wouldn't hurt, it wastes CPU time
to blit the same image twice).

 I've tried even adding in a 1ms interrupt timer to try and help with
any emulation code that might be freezing the emulator for over an
entire vblank (nothing in bsnes should be that intensive), and this
did not help either.

 Basically, it's like I'm missing an unbelievable amount of frames,
like five out of six end up never getting drawn at all, so the video
is so choppy it's completely unusable. In reality, only one frame
should be dropped every 11 seconds. And when I enable the resampler,
that should change to only one frame every 66 seconds.

 As a side note, I added a four-tap hermite resampler in. It sounds
good too, but I have no idea if it's better or worse than cubic.

[No archive available]
2007-02-03 13:10:00 +00:00
byuu
6d66b1136d Update to bsnes v019r09 release.
Alright, I'm in a semi-good mood.







    http://byuu.cinnamonpirate.com/files/bsnes_v019_wip9.zip




 This one uses the old win32 interface, and adds a new feature I'd
like people with sound troubles to try out. The config file now
contains "audio.latency". Don't mess with "audio.frequency", it won't
do you any good and gets overridden by the speed regulation settings
for now.

 The audio.latency is a precise measurement of the millisecond delay
between sound being output by a real SNES and hearing that same sound
in bsnes. It takes into account the current playback frequency, as
well as the three-ring buffering system used by bsnes' audio system.
 Formula: sample_latency = CURRENT_playback_frequency / 1000 *
config_file_latency * 3 (so 32khz + 75ms latency means each ring
buffer is 800 samples long). The new formula should make latency sound
better (it's consistent now) on fast / slow emulation speed throttling
settings as well.
 I also cut out the fourth ring, since it was redundant. This should
make bsnes appear ~25% more responsive to sound with the same buffer
latency. As a result, I increased the latency to 75ms (it was at ~45
before).
 I'd like to know what the lowest good value is that works on 95% of
sound cards, so I can use that. I'll let people with cheap sound cards
increase their latency setting manually (eventually it will be an
option in the GUI).

               **NOTE:** this version does nothing for triple
buffering/vsync/whatever. You must _disable_ triple buffering to try
out the latency settings. This version is strictly to test audio
playback support.

 I also added in my audio point resampler. Good god, it sounds
terrible. Regardless of the latency setting (either really high or
really low), the pitch difference between each audio ring is
_extremely_ noticeable. The code is there now in
src/ui/audio/dsound.cpp : AudioDS::run_videosync(), if anyone would
like to take a look. I'll hold my breath ;)

               -----

 Comparisons against ZSNES at this point are rather silly. Aside from
much more flexible timings, it probably has a nice audio resampler,
which I don't. If I faked CPU/SMP clock timings, I could get the SNES
spitting out 60 frames a second and 32khz audio a second. I'm not
going to do that, so I have to figure out how to resample the two. All
of my attempts at resampling video _and_ audio have both failed
miserably to date. I really only need one of those to work to get
smooth video+audio, but both would be nice so the user can decide
what's more important to them.

I don't care to add 2xSaI. I'm planning on redoing the filter stuff
soon to support 32-bit output for Xv, so if someone wants to add 2xSaI
support to bsnes after that, I'll add it in. Otherwise, HQ2x is
superior and Scale2x looks about the same, yet is way faster.

 Regarding the IPS thing, exactly. As I said, IPS is a bad format. You
can't tell if you need to patch against a headered or unheadered ROM
unless you read the documentation that fuckheads like Cowering remove
in their ROM sets ("at least it's already prepatched"), or try
patching twice to see which one works. UPS will eliminate both of
these problems. Readmes will be included inside the patches, and UPS
will work regardless if your ROM has a header or not. It will also be
reversible. It'll be better in every regard over IPS, so I have no
reason to support IPS.

 Lastly, I don't have any intention of working on fixing DeJap's
patch, regardless of where the problem is, as I have no way to run the
game on my copier. Maybe when and if the last two serious bugs
(Uniracers and Koushien 2) get fixed, I'll take a look at it then.
2007-01-31 00:00:24 +00:00
byuu
b01f18c34c Update to bsnes v019r01? release.
First screenshots of libui in bsnes:

             [image] [image]

 Same exact codebase. The current WIP is obviously missing any
semblance of a GUI, other than the menubar and a ROM file loader.

 Lots of issues on both ports, of course. I'm aware of the audio
repeating issue on the Windows port and already know how to fix it
(had the same problem with the old Windows UI). Linux of course simply
has no audio or input.

 I'm planning on moving the framerate counter to display inside the
image, rather than on the titlebar this time. That of course won't
happen anytime soon. I don't expect to be adding fullscreen support
back in anytime soon, either.

 Once this port gets stable enough, I intend to remove the "ui/win"
and "ui/sdl" ports completely. After that, I'm going to have to start
seriously rewriting a lot of internal stuff.

 I'm also planning to go with a simpler user interface this time
around. bsnes v0.019 had too many options and features. I think I may
scale back this time and make things a lot simpler. Move a lot of the
control settings back into the menubar, rather than in the custom
options panel (which will most likely still exist).

[No archive available]
2007-01-15 04:25:00 +00:00
301 changed files with 18964 additions and 8331 deletions

BIN
cart.db Normal file

Binary file not shown.

View File

@@ -1,35 +1,86 @@
bsnes License:
--------------
You are free to redistribute this software, and its source code; provided
there is no charge for the software, nor any charge for the medium used to
distribute the software. You are also free to use and modify the source code
as you desire for personal use only. No publically-released derivative works
of this program nor its source code are permitted without my permission,
though I will likely grant you permission if you ask me. You must also abide
by the terms of any additional source code licenses contained within this
program.
bsnes (TM) Open Source Reference License
Copyright (C) 2004 - 2007 byuu
All rights reserved
Simple DirectMedia Layer License:
---------------------------------
The Simple DirectMedia Layer (SDL for short) is a cross-platform library
designed to make it easy to write multi-media software, such as games and
emulators.
1. Definitions
The Simple DirectMedia Layer library source code is available from:
http://www.libsdl.org/
The terms "reproduce", "reproduction", "distribute" and "distribution" have the
same meaning here as under U.S. copyright law.
This library is distributed under the terms of the GNU LGPL:
http://www.gnu.org/copyleft/lesser.html
"The software" means this software package as a whole, including, but not
limited to, this license, binaries, source code, documentation, and data.
JMA License:
------------
JMA is licensed under the GNU GPL. I have received special exemption from
Nach to use this library in bsnes.
"You" means the licensee of the software.
Licensing Exemptions:
---------------------
libco, the cooperative multithreading library used by bsnes, is public domain.
You may obtain the latest version at: http://byuu.org/
"The licensor" means the copyright holder of the software, byuu.
Richard Bannister has asked for and received my permission to distribute
a binary-only port of bsnes on the Mac OS X platform.
2. Grant of Rights
Subject to the terms of this license, the licensor grants you a
non-transferable, non-exclusive, worldwide, royalty-free copyright license to
reproduce the software for non-commercial use only, provided the software
remains unmodified, and there is no charge for the software itself, its' use,
nor for the medium upon which the software is distributed. The reproduction of
modified or derivative works of the software is strictly prohibited, except when
transmitted solely to the licensor.
3. Limitations
This license does not grant you any rights to use the licensor's name, logo or
trademarks.
The software is provided "as is", and any express or implied warranties,
including, but not limited to, the implied warranties of merchantability and
fitness for a particular purpose are disclaimed. In no event shall the licensor
be liable for any direct, indirect, incidental, special, exemplary, or
consequential damages (including, but not limited to, procurement of substitute
goods or services; loss of use, data, or profits; or business interruption)
however caused and on any theory of liability, whether in contract, strict
liability, or tort (including negligence or otherwise) arising in any way out of
the use of the software, even if advised of the possibility of such damage.
In the event that this license is determined to be invalid or unenforceable, the
Grant of Rights will become null and void, and no rights shall be granted to the
licensee, within the scope of U.S. copyright law.
4. Exemptions
The software includes the work of other copyright holders, which is licensed
under different agreements, and exempt from this license. Below is a complete
list of all such software, and their respective copyright holders and licenses.
Further, respective source code files are labeled with their correct licensing
information in the header. The lack of such a header indicates said file falls
under the bsnes license.
HQ2x filter, author: MaxST, license: LGPL
JMA decompressor, author: NSRT Team, license: GPL (*)
NTSC filter, author: blargg, license: LGPL
zlib decompressor, license: zlib license
(*) bsnes has received an exemption from the copyright holder to use this work.
The software also includes works which have been released to the public domain,
which are not bound to any licensing agreements. Below is a complete list of all
such software.
libco, author: byuu
libui, author: byuu
OBC-1 emu, author: byuu
S-DD1 emu, author: Andreas Naive
S-RTC emu, author: byuu
Any software listed above as exemptions may be relicensed individually from
bsnes under their respective terms. However, no bsnes licensed portions can be
combined with such a derivative work.
The software also includes the work of other copyright holders, which is
licensed under the terms of the bsnes license, with permission to do so from the
respective authors. Below is a complete list of all such software.
Cx4 emu, authors: anomie, Overload, zsKnight, Nach
DSP-1 emu, authors: Overload, John Weidman, Neviksti, Andreas Naive
DSP-2 emu, author: Overload
DSP-3 emu, authors: John Weidman, Kris Bleakley, Lancer, z80 gaiden
DSP-4 emu, authors: Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden
S-DSP emu, author: blargg
ST-010 emu, authors: John Weidman, Matthew Kendora, Overload, Feather

View File

@@ -1,10 +1,10 @@
bsnes
Version 0.019
Version 0.025
Author: byuu
General
-------
--------
General:
--------
bsnes is a Super Nintendo / Super Famicom emulator that began on
October 14th, 2004.
@@ -13,19 +13,22 @@ http://byuu.org/
Please see license.txt for important licensing information.
--------------
Shortcut Keys:
--------------
Esc - Toggle menubar visibility
F11 - Toggle fullscreen mode
Known Limitations
-----------------
------------------
Known Limitations:
------------------
S-CPU
- Invalid DMA / HDMA transfers (eg WRAM<>WRAM) not fully emulated
- Invalid DMA / HDMA transfers not fully emulated
- Multiply / Divide register delays not implemented
S-SMP
- Cycle breakdown of opcodes is theoretical, but mostly correct
S-PPU
- Uses scanline-based renderer. This is very inaccurate, but very
few games rely on mid-scanline writes to function correctly
- Uses scanline-based renderer. This is very inaccurate, but few (if any)
games rely on mid-scanline writes to function correctly
- Does not support FirstSprite+Y priority
- OAM / CGRAM accesses during active display not supported correctly
- RTO flags are not calculated on frames that are skipped when frameskipping
@@ -33,18 +36,13 @@ S-PPU
in games that test these flags, eg the SNES Test Program Electronics Test.
Turning frameskipping off will allow RTO flag calculation on every frame
S-DSP
- Runs at 32khz. Hardware S-DSP likely runs at 1.024mhz to perform
multiple reads / writes per sample. Sound is still output at 32khz,
of course
Hardware Bugs
- CPUr1 HDMA crashing bug not emulated
- CPU<>APU communication bus conflicts not emulated
- S-CPU.r1 HDMA crashing bug not emulated
- S-CPU<>S-SMP communication bus conflicts not emulated
Unsupported Hardware
--------------------
---------------------
Unsupported Hardware:
---------------------
SA-1
Coprocessor used in many popular games, including:
- Dragon Ball Z Hyper Dimension
@@ -68,31 +66,26 @@ Coprocessor used only by the following games:
- Momotarou Densetsu Happy
- Super Power League 4
DSP-3
Coprocessor used only by SD Gundam GX
ST-011
SETA DSP used only by Quick-move Shogi Match with Nidan Rank-holder Morita
DSP-4
Coprocessor used only by Top Gear 3000
ST010 / ST011 / ST018
SETA coprocessors used by very few games
ST-018
SETA RISC CPU used only by Quick-move Shogi Match with Nidan Rank-holder Morita 2
BS-X (Broadcast Satellite)
Add-on unit sold only in Japan that played specially-made games that
were downloaded via satellite
Add-on unit sold only in Japan that played specially-made games that were
downloaded via satellite
BS-X Flashcart
Flash cartridge used by BS-X, as well as some standalone games by
Asciisoft
Flash cartridge used by BS-X, as well as some standalone games by Asciisoft
Super Gameboy
Cartridge passthrough used for playing Gameboy games
Unsupported controllers
-----------------------
------------------------
Unsupported Controllers:
------------------------
Mouse
Super Scope
Justifier
Multitap (4-port)
Multitap (5-port)
Multitap (4-port and 5-port)

315
src/Makefile Normal file
View File

@@ -0,0 +1,315 @@
######################
### bsnes makefile ###
######################
ifeq ($(PLATFORM),)
_null_: help
endif
##################################
### platform-specific settings ###
##################################
ifeq ($(PLATFORM),x-gcc-lui)
OS = unix
CC = gcc
CFLAGS = -O3 -fomit-frame-pointer -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_LUI `pkg-config --cflags gtk+-2.0`
AS = nasm
ASFLAGS = -f elf
LIBS = `pkg-config --libs gtk+-2.0` -lXv -lao
LIBCO = libco_x86
LIBUI = libui_gtk
endif
ifeq ($(PLATFORM),x-gcc-lui-x64)
OS = unix
CC = gcc
CFLAGS = -O3 -fomit-frame-pointer -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86_64 -DUI_LUI `pkg-config --cflags gtk+-2.0`
AS = yasm
ASFLAGS = -f elf64
LIBS = `pkg-config --libs gtk+-2.0` -lXv -lao
LIBCO = libco_x86_64
LIBUI = libui_gtk
endif
ifeq ($(PLATFORM),win-visualc-lui)
OS = win
CC = cl
CFLAGS = /nologo /wd4996 /O2 /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_LUI
AS = nasm
ASFLAGS = -f win32 -DWIN32
LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib kernel32.lib user32.lib gdi32.lib shell32.lib winmm.lib comdlg32.lib comctl32.lib
LIBCO = libco_x86
LIBUI = libui_win
endif
ifeq ($(PLATFORM),win-visualc-lui-pgi)
OS = win
CC = cl
CFLAGS = /nologo /wd4996 /O2 /GL /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_LUI
AS = nasm
ASFLAGS = -f win32 -DWIN32
LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib kernel32.lib user32.lib gdi32.lib shell32.lib winmm.lib comdlg32.lib comctl32.lib
LINK = /link /PGD:bsnes.pgd /LTCG:PGINSTRUMENT
LIBCO = libco_x86
LIBUI = libui_win
endif
ifeq ($(PLATFORM),win-visualc-lui-pgo)
OS = win
CC = cl
CFLAGS = /nologo /wd4996 /O2 /GL /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_LUI
AS = nasm
ASFLAGS = -f win32 -DWIN32
LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib kernel32.lib user32.lib gdi32.lib shell32.lib winmm.lib comdlg32.lib comctl32.lib
LINK = /link /PGD:bsnes.pgd /LTCG:PGOPTIMIZE
LIBCO = libco_x86
LIBUI = libui_win
endif
ifeq ($(PLATFORM),win-mingw-lui)
OS = win
CC = mingw32-gcc
CFLAGS = -mwindows -O3 -fomit-frame-pointer -DPLATFORM_WIN -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_LUI
AS = nasm
ASFLAGS = -f win32 -DWIN32
LIBS = -ld3d9 -lddraw -ldsound -ldinput8 -ldxguid -luuid -lkernel32 -luser32 -lgdi32 -lshell32 -lwinmm -lcomdlg32 -lcomctl32
LIBCO = libco_x86
LIBUI = libui_win
endif
ifeq ($(PLATFORM),win-mingw4-lui)
OS = win
CC = mingw32-gcc-sjlj
CFLAGS = -mconsole -O3 -fomit-frame-pointer -DPLATFORM_WIN -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_LUI
AS = nasm
ASFLAGS = -f win32 -DWIN32
LIBS = -ld3d9 -lddraw -ldsound -ldinput8 -ldxguid -luuid -lkernel32 -luser32 -lgdi32 -lshell32 -lwinmm -lcomdlg32 -lcomctl32
LIBCO = libco_x86
LIBUI = libui_win
endif
#####################################
### compiler / assembler switches ###
#####################################
ifeq ($(CC),gcc)
OUT = -obsnes
CPP = g++
OBJ = o
CARGS = -c $< -o $@
DEFINE = -D
endif
ifeq ($(CC),mingw32-gcc)
OUT = -obsnes
CPP = mingw32-g++
OBJ = o
CARGS = -c $< -o $@
DEFINE = -D
endif
ifeq ($(CC),mingw32-gcc-sjlj)
OUT = -obsnes
CPP = mingw32-g++-sjlj
OBJ = o
CARGS = -c $< -o $@
DEFINE = -D
endif
ifeq ($(CC),cl)
OUT = /Febsnes
CPP = cl
OBJ = obj
CARGS = /c $< /Fo$@
DEFINE = /D
endif
ifeq ($(AS),nasm)
ASARGS = $< -o $@
endif
ifeq ($(AS),yasm)
ASARGS = $< -o $@
endif
###################
### OS switches ###
###################
ifeq ($(OS),unix)
RM = rm -f
endif
ifeq ($(OS),win)
OUT := $(OUT).exe
RM = del
endif
####################################
### main target and dependencies ###
####################################
OBJECTS = main.$(OBJ) $(LIBCO).$(OBJ) $(LIBUI).$(OBJ) \
libstring.$(OBJ) \
reader.$(OBJ) cart.$(OBJ) cheat.$(OBJ) memory.$(OBJ) bmemory.$(OBJ) \
cpu.$(OBJ) scpu.$(OBJ) smp.$(OBJ) ssmp.$(OBJ) bdsp.$(OBJ) ppu.$(OBJ) \
bppu.$(OBJ) snes.$(OBJ) superfx.$(OBJ) srtc.$(OBJ) sdd1.$(OBJ) c4.$(OBJ) \
dsp1.$(OBJ) dsp2.$(OBJ) dsp3.$(OBJ) dsp4.$(OBJ) obc1.$(OBJ) st010.$(OBJ)
ifeq ($(GZIP_SUPPORT),true)
OBJECTS += adler32.$(OBJ) compress.$(OBJ) crc32.$(OBJ) deflate.$(OBJ) \
gzio.$(OBJ) inffast.$(OBJ) inflate.$(OBJ) inftrees.$(OBJ) ioapi.$(OBJ) \
trees.$(OBJ) unzip.$(OBJ) zip.$(OBJ) zutil.$(OBJ)
CFLAGS += $(DEFINE)GZIP_SUPPORT
endif
ifeq ($(JMA_SUPPORT),true)
OBJECTS += jma.$(OBJ) jcrc32.$(OBJ) lzmadec.$(OBJ) 7zlzma.$(OBJ) \
iiostrm.$(OBJ) inbyte.$(OBJ) lzma.$(OBJ) winout.$(OBJ)
CFLAGS += $(DEFINE)JMA_SUPPORT
endif
ifeq ($(OS),win)
ifeq ($(CC),cl)
OBJECTS += bsnes.res
endif
endif
all: $(OBJECTS)
$(CPP) $(OUT) $(CFLAGS) $(OBJECTS) $(LIBS) $(LINK)
# mt -nologo -manifest bsnes.exe.manifest -outputresource:bsnes.exe;1
######################
### implicit rules ###
######################
%.$(OBJ): $<
$(if $(filter %.asm,$<),$(AS) $(ASFLAGS) $(ASARGS))
$(if $(filter %.c,$<),$(CC) $(CFLAGS) $(CARGS))
$(if $(filter %.cpp,$<),$(CPP) $(CFLAGS) $(CARGS))
#########################
### platform-specific ###
#########################
main.$(OBJ): ui/main.cpp config/* ui/* ui/video/* ui/audio/* ui/input/* \
ui/lui/* ui/lui/settings/* \
ui/win/* ui/win/settings/* ui/win/debugger/*
bsnes.res : ui/bsnes.rc ; rc /r /fobsnes.res ui/bsnes.rc
#############
### libco ###
#############
libco_x86.$(OBJ) : lib/libco_x86.asm lib/*
libco_x86_64.$(OBJ): lib/libco_x86_64.asm lib/*
#############
### libui ###
#############
libui_gtk.$(OBJ): lib/libui_gtk.cpp lib/*
libui_win.$(OBJ): lib/libui_win.cpp lib/*
#################
### libraries ###
#################
libstring.$(OBJ): lib/libstring.cpp lib/*
#################
### utilities ###
#################
reader.$(OBJ): reader/reader.cpp reader/*
cart.$(OBJ) : cart/cart.cpp cart/*
cheat.$(OBJ) : cheat/cheat.cpp cheat/*
##############
### memory ###
##############
memory.$(OBJ) : memory/memory.cpp memory/*
bmemory.$(OBJ): memory/bmemory/bmemory.cpp memory/bmemory/* memory/bmemory/mapper/*
###########
### cpu ###
###########
cpu.$(OBJ) : cpu/cpu.cpp cpu/*
scpu.$(OBJ): cpu/scpu/scpu.cpp cpu/scpu/* cpu/scpu/core/* cpu/scpu/dma/* cpu/scpu/memory/* cpu/scpu/mmio/* cpu/scpu/timing/*
###########
### smp ###
###########
smp.$(OBJ) : smp/smp.cpp smp/*
ssmp.$(OBJ): smp/ssmp/ssmp.cpp smp/ssmp/* smp/ssmp/core/* smp/ssmp/memory/* smp/ssmp/timing/*
###########
### dsp ###
###########
adsp.$(OBJ): dsp/adsp/adsp.cpp dsp/adsp/*
bdsp.$(OBJ): dsp/bdsp/bdsp.cpp dsp/bdsp/*
###########
### ppu ###
###########
ppu.$(OBJ) : ppu/ppu.cpp ppu/*
bppu.$(OBJ): ppu/bppu/bppu.cpp ppu/bppu/*
############
### snes ###
############
snes.$(OBJ): snes/snes.cpp snes/* snes/scheduler/* snes/video/* snes/audio/* snes/input/*
#####################
### special chips ###
#####################
superfx.$(OBJ): chip/superfx/superfx.cpp chip/superfx/* chip/superfx/core/* chip/superfx/memory/*
srtc.$(OBJ) : chip/srtc/srtc.cpp chip/srtc/*
sdd1.$(OBJ) : chip/sdd1/sdd1.cpp chip/sdd1/*
c4.$(OBJ) : chip/c4/c4.cpp chip/c4/*
dsp1.$(OBJ) : chip/dsp1/dsp1.cpp chip/dsp1/*
dsp2.$(OBJ) : chip/dsp2/dsp2.cpp chip/dsp2/*
dsp3.$(OBJ) : chip/dsp3/dsp3.cpp chip/dsp3/*
dsp4.$(OBJ) : chip/dsp4/dsp4.cpp chip/dsp4/*
obc1.$(OBJ) : chip/obc1/obc1.cpp chip/obc1/*
st010.$(OBJ) : chip/st010/st010.cpp chip/st010/*
############
### zlib ###
############
adler32.$(OBJ) : reader/zlib/adler32.c reader/zlib/*
compress.$(OBJ): reader/zlib/compress.c reader/zlib/*
crc32.$(OBJ) : reader/zlib/crc32.c reader/zlib/*
deflate.$(OBJ) : reader/zlib/deflate.c reader/zlib/*
gzio.$(OBJ) : reader/zlib/gzio.c reader/zlib/*
inffast.$(OBJ) : reader/zlib/inffast.c reader/zlib/*
inflate.$(OBJ) : reader/zlib/inflate.c reader/zlib/*
inftrees.$(OBJ): reader/zlib/inftrees.c reader/zlib/*
ioapi.$(OBJ) : reader/zlib/ioapi.c reader/zlib/*
trees.$(OBJ) : reader/zlib/trees.c reader/zlib/*
unzip.$(OBJ) : reader/zlib/unzip.c reader/zlib/*
zip.$(OBJ) : reader/zlib/zip.c reader/zlib/*
zutil.$(OBJ) : reader/zlib/zutil.c reader/zlib/*
###########
### jma ###
###########
jma.$(OBJ) : reader/jma/jma.cpp reader/jma/*
jcrc32.$(OBJ) : reader/jma/jcrc32.cpp reader/jma/*
lzmadec.$(OBJ): reader/jma/lzmadec.cpp reader/jma/*
7zlzma.$(OBJ) : reader/jma/7zlzma.cpp reader/jma/*
iiostrm.$(OBJ): reader/jma/iiostrm.cpp reader/jma/*
inbyte.$(OBJ) : reader/jma/inbyte.cpp reader/jma/*
lzma.$(OBJ) : reader/jma/lzma.cpp reader/jma/*
winout.$(OBJ) : reader/jma/winout.cpp reader/jma/*
####################
### misc targets ###
####################
clean:
-@$(RM) *.$(OBJ)
-@$(RM) *.res
-@$(RM) *.pgd
-@$(RM) *.pgc
-@$(RM) *.ilk
-@$(RM) *.pdb
-@$(RM) *.manifest
help:
@echo Please specify which platform to compile for with PLATFORM=platform_name

View File

@@ -1,4 +1,4 @@
#define BSNES_VERSION "0.019"
#define BSNES_VERSION "0.025"
#define BSNES_TITLE "bsnes v" BSNES_VERSION
#define MEMCORE bMemBus
@@ -13,48 +13,35 @@
//game genie + pro action replay code support (~1-3% speed hit)
#define CHEAT_SYSTEM
//enable GZ, ZIP format support
//#define GZIP_SUPPORT
//enable JMA support
//#define JMA_SUPPORT
//snes core polymorphism
//(allow runtime cpu/smp/dsp/ppu/bus selection, ~10% speed hit)
//#define POLYMORPHISM
#include "lib/libbase.h"
#if defined(PROCESSOR_X86)
#define ARCH_LSB
#include "lib/libco_x86.h"
#elif defined(PROCESSOR_X86_64)
#define ARCH_LSB
#include "lib/libco_x86_64.h"
#elif defined(PROCESSOR_G5)
#define ARCH_MSB
#else
#error "unsupported processor"
#endif
#include "lib/libbase.h"
#include "lib/libfunctor.h"
#include "lib/libsort.h"
#include "lib/libco_x86.h"
#include "lib/libarray.h"
#include "lib/libvector.h"
#include "lib/libfile.h"
#include "lib/libups.h"
#include "lib/libstring.h"
#include "lib/libconfig.h"
inline uint16 read16(uint8 *addr, uint pos) {
#ifdef ARCH_LSB
return *((uint16*)(addr + pos));
#else
return (addr[pos]) | (addr[pos + 1] << 8);
#endif
}
//platform-specific global functions
void alert(char *, ...);
void dprintf(char *, ...);
void dprintf(uint, char *, ...);
void alert(const char*, ...);
void dprintf(const char*, ...);
void dprintf(uint, const char*, ...);
namespace source {
enum {

BIN
src/bsnes.lnk Normal file

Binary file not shown.

View File

@@ -1,26 +1,33 @@
#include "../base.h"
#include "database.cpp"
#include "cart_normal.cpp"
#include "cart_st.cpp"
#include "cart_stdual.cpp"
#include "cart_file.cpp"
#include "cart_header.cpp"
Cartridge cartridge;
#include "cart_normal.cpp"
#include "cart_st.cpp"
#include "cart_stdual.cpp"
void Cartridge::load_begin(uint cart_type) {
void Cartridge::load_begin(CartridgeType cart_type) {
if(loaded() == true)return;
info.type = cart_type;
info.srtc = false;
info.sdd1 = false;
info.c4 = false;
info.dsp1 = false;
info.dsp2 = false;
info.obc1 = false;
info.superfx = false;
info.sa1 = false;
info.srtc = false;
info.sdd1 = false;
info.c4 = false;
info.dsp1 = false;
info.dsp2 = false;
info.dsp3 = false;
info.dsp4 = false;
info.obc1 = false;
info.st010 = false;
info.st011 = false;
info.st018 = false;
info.dsp1_mapper = 0;
@@ -29,7 +36,6 @@ void Cartridge::load_begin(uint cart_type) {
strcpy(info.name, "");
strcpy(info.pcb, "");
info.region = NTSC;
info.cart_mmio = false;
info.rom_size = 0;
info.ram_size = 0;
@@ -92,15 +98,15 @@ bool Cartridge::load_end() {
}
switch(info.type) {
case CART_NORMAL: {
case CartridgeNormal: {
load_rom_normal();
load_ram_normal();
} break;
case CART_ST: {
case CartridgeSufamiTurbo: {
load_rom_st();
load_ram_st();
} break;
case CART_STDUAL: {
case CartridgeSufamiTurboDual: {
load_rom_stdual();
load_ram_stdual();
} break;
@@ -117,19 +123,19 @@ bool Cartridge::unload() {
r_mem->unload_cart();
switch(info.type) {
case CART_NORMAL: {
case CartridgeNormal: {
save_ram_normal();
} break;
case CART_ST: {
case CartridgeSufamiTurbo: {
save_ram_st();
} break;
case CART_STDUAL: {
case CartridgeSufamiTurboDual: {
save_ram_stdual();
} break;
}
SafeFree(rom);
SafeFree(ram);
safe_free(rom);
safe_free(ram);
if(cheat.count() > 0 || fexists(file.cheat_name) == true) {
cheat.save(file.cheat_name);

View File

@@ -15,10 +15,10 @@ db_item dbi;
//
enum {
CART_NORMAL,
CART_ST,
CART_STDUAL,
enum CartridgeType {
CartridgeNormal,
CartridgeSufamiTurbo,
CartridgeSufamiTurboDual,
};
bool cart_loaded;
@@ -33,7 +33,7 @@ enum {
ROM_SIZE = 0x17,
RAM_SIZE = 0x18,
REGION = 0x19,
LICENSE = 0x1a,
COMPANY = 0x1a,
VERSION = 0x1b,
ICKSUM = 0x1c,
CKSUM = 0x1e,
@@ -78,15 +78,19 @@ struct {
uint rom_size;
uint ram_size;
//set to true for games that need cart MMIO mapping (c4, dsp-n, ...),
//for games that map outside the standard MMIO range of $2000-$5fff
bool cart_mmio;
bool superfx;
bool sa1;
bool srtc;
bool sdd1;
bool c4;
bool dsp1;
bool dsp2;
bool dsp3;
bool dsp4;
bool obc1;
bool st010;
bool st011;
bool st018;
uint dsp1_mapper;
@@ -113,7 +117,7 @@ struct {
void read_header();
bool loaded() { return cart_loaded; }
void load_begin(uint cart_type);
void load_begin(CartridgeType cart_type);
void load(const char *rom_fn);
bool load_end();
bool unload();

View File

@@ -1,7 +1,19 @@
#include "../reader/filereader.h"
#if defined(GZIP_SUPPORT)
#include "../reader/gzreader.h"
#include "../reader/zipreader.h"
#endif
#if defined(JMA_SUPPORT)
#include "../reader/jmareader.h"
#endif
bool Cartridge::load_file(const char *fn, uint8 *&data, uint &size) {
dprintf("* Loading \"%s\"...", fn);
if(fexists(fn) == false) {
alert("Error: file '%s' not found!", fn);
return false;
}

View File

@@ -1,13 +1,4 @@
void Cartridge::read_header() {
info.srtc = false;
info.sdd1 = false;
info.c4 = false;
info.dsp1 = false;
info.dsp2 = false;
info.obc1 = false;
info.dsp1_mapper = 0;
if(info.header_index == 0x7fc0 && info.rom_size >= 0x401000) {
info.mapper = EXLOROM;
strcpy(info.pcb, "UNL-EXLOROM");
@@ -27,6 +18,16 @@ void Cartridge::read_header() {
uint8 mapper = rom[info.header_index + MAPPER];
uint8 rom_type = rom[info.header_index + ROM_TYPE];
uint8 company = rom[info.header_index + COMPANY];
if(mapper == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
info.superfx = true;
}
if(mapper == 0x23 && (rom_type == 0x34 || rom_type == 0x35)) {
info.sa1 = true;
}
if(mapper == 0x35 && rom_type == 0x55) {
info.srtc = true;
}
@@ -43,7 +44,7 @@ uint8 rom_type = rom[info.header_index + ROM_TYPE];
info.dsp1 = true;
}
if(mapper == 0x30 && rom_type == 0x05) {
if(mapper == 0x30 && rom_type == 0x05 && company != 0xb2) {
info.dsp1 = true;
}
@@ -65,11 +66,28 @@ uint8 rom_type = rom[info.header_index + ROM_TYPE];
info.dsp2 = true;
}
if(mapper == 0x30 && rom_type == 0x05 && company == 0xb2) {
info.dsp3 = true;
}
if(mapper == 0x30 && rom_type == 0x03) {
info.dsp4 = true;
}
if(mapper == 0x30 && rom_type == 0x25) {
info.obc1 = true;
}
info.cart_mmio = info.c4 | info.dsp1 | info.dsp2 | info.obc1;
if(mapper == 0x30 && rom_type == 0xf6) {
//TODO: both ST010 and ST011 share the same mapper + rom_type
//need way to determine which is which
//for now, default to supported ST010
info.st010 = true;
}
if(mapper == 0x30 && rom_type == 0xf5) {
info.st018 = true;
}
if(rom[info.header_index + RAM_SIZE] & 7) {
info.ram_size = 1024 << (rom[info.header_index + RAM_SIZE] & 7);
@@ -113,8 +131,8 @@ int32 score_lo = 0,
if(rom[0x7fc0 + REGION] < 14)score_lo++;
if(rom[0xffc0 + REGION] < 14)score_hi++;
if(rom[0x7fc0 + LICENSE] < 3)score_lo++;
if(rom[0xffc0 + LICENSE] < 3)score_hi++;
if(rom[0x7fc0 + COMPANY] < 3)score_lo++;
if(rom[0xffc0 + COMPANY] < 3)score_hi++;
if(rom[0x7fc0 + RESH] & 0x80)score_lo += 2;
if(rom[0xffc0 + RESH] & 0x80)score_hi += 2;

View File

@@ -20,21 +20,11 @@ uint offset = 0;
info.crc32 = crc32_calculate(rom, info.rom_size);
if(read_database() == true) {
info.srtc = false;
info.sdd1 = false;
info.c4 = false;
info.dsp1 = false;
info.dsp2 = false;
info.obc1 = false;
info.dsp1_mapper = 0;
info.header_index = 0xffc0;
info.mapper = PCB;
strcpy(info.name, dbi.name);
strcpy(info.pcb, dbi.pcb);
info.region = NTSC;
info.cart_mmio = false;
info.rom_size = dbi.rom;
info.ram_size = dbi.ram;

Binary file not shown.

View File

@@ -106,6 +106,12 @@ pcb = "BSC-1A7M-10"
rom = 24mbit
ram = 512kbit
[0xcf98ddaa]
name = "Super Mario World 2: Yoshi's Island (USA)"
pcb = "SHVC-1CB5B-01"
rom = 16mbit
ram = 256kbit
[0x64a91e64]
name = "Wanderers from Ys (USA) [!]"
pcb = "SHVC-1A3B-12"

View File

@@ -53,9 +53,9 @@ db_item dbi;
dbi.ram = 0;
for(int i = 1; i < count(line); i++) {
uint pos;
if(strpos(line[i], ";", pos) == true) {
strset(line[i], pos, 0);
int pos = strpos(line[i], ";");
if(pos >= 0) {
strptr(line[i])[pos] = 0;
}
if(line[i] == "")continue;

5
src/cc.bat Normal file
View File

@@ -0,0 +1,5 @@
::@make -r PLATFORM=win-mingw4-lui
::@make -r PLATFORM=win-visualc-lui
@make -r PLATFORM=win-visualc-lui GZIP_SUPPORT=true JMA_SUPPORT=true
@move bsnes.exe ../bsnes.exe>nul
@pause

2
src/cc.sh Normal file
View File

@@ -0,0 +1,2 @@
#!/bin/sh
make PLATFORM=x-gcc-lui

View File

@@ -1,4 +1,5 @@
#include "../base.h"
#include "../reader/filereader.h"
Cheat cheat;
@@ -276,7 +277,7 @@ uint8 *raw_data = rf.read();
stringarray data, line;
raw_data[rf.size()] = 0;
strcpy(data, (char*)raw_data);
SafeFree(raw_data);
safe_free(raw_data);
replace(data, "\r\n", "\n");
split(line, "\n", data);

View File

@@ -7,8 +7,6 @@
#include "../../base.h"
C4 *c4;
#include "c4data.cpp"
#include "c4fn.cpp"
#include "c4oam.cpp"

View File

@@ -93,4 +93,4 @@ public:
C4();
};
extern C4 *c4;
extern C4 c4;

View File

@@ -1,7 +1,5 @@
#include "../../base.h"
DSP1 *dsp1;
#include "dsp1emu.cpp"
void DSP1::init() {}

View File

@@ -15,4 +15,4 @@ public:
void write(uint16 addr, uint8 data);
};
extern DSP1 *dsp1;
extern DSP1 dsp1;

View File

@@ -1,7 +1,5 @@
#include "../../base.h"
DSP2 *dsp2;
#include "dsp2_op.cpp"
void DSP2::init() {}

View File

@@ -1,5 +1,4 @@
class DSP2 {
public:
class DSP2 { public:
struct {
bool waiting_for_command;
uint command;
@@ -40,4 +39,4 @@ struct {
~DSP2();
};
extern DSP2 *dsp2;
extern DSP2 dsp2;

33
src/chip/dsp3/dsp3.cpp Normal file
View File

@@ -0,0 +1,33 @@
#include "../../base.h"
namespace DSP3i {
#define bool8 bool
#include "dsp3emu.c"
#undef bool8
};
void DSP3::init() {
}
void DSP3::enable() {
}
void DSP3::power() {
reset();
}
void DSP3::reset() {
DSP3i::DSP3_Reset();
}
uint8 DSP3::read(uint16 addr) {
DSP3i::dsp3_address = addr;
DSP3i::DSP3GetByte();
return DSP3i::dsp3_byte;
}
void DSP3::write(uint16 addr, uint8 data) {
DSP3i::dsp3_address = addr;
DSP3i::dsp3_byte = data;
DSP3i::DSP3SetByte();
}

11
src/chip/dsp3/dsp3.h Normal file
View File

@@ -0,0 +1,11 @@
class DSP3 { public:
void init();
void enable();
void power();
void reset();
uint8 read (uint16 addr);
void write(uint16 addr, uint8 data);
};
extern DSP3 dsp3;

1142
src/chip/dsp3/dsp3emu.c Normal file

File diff suppressed because it is too large Load Diff

51
src/chip/dsp4/dsp4.cpp Normal file
View File

@@ -0,0 +1,51 @@
#include "../../base.h"
namespace DSP4i {
inline uint16 READ_WORD(uint8 *addr) {
return (addr[0]) + (addr[1] << 8);
}
inline uint32 READ_DWORD(uint8 *addr) {
return (addr[0]) + (addr[1] << 8) + (addr[2] << 16) + (addr[3] << 24);
}
inline void WRITE_WORD(uint8 *addr, uint16 data) {
addr[0] = data;
addr[1] = data >> 8;
}
#define bool8 bool
#include "dsp4emu.c"
#undef bool8
};
void DSP4::init() {
}
void DSP4::enable() {
}
void DSP4::power() {
reset();
}
void DSP4::reset() {
DSP4i::InitDSP4();
}
uint8 DSP4::read(uint16 addr) {
if(addr < 0xc000) {
DSP4i::dsp4_address = addr;
DSP4i::DSP4GetByte();
return DSP4i::dsp4_byte;
}
return 0x80;
}
void DSP4::write(uint16 addr, uint8 data) {
if(addr < 0xc000) {
DSP4i::dsp4_address = addr;
DSP4i::dsp4_byte = data;
DSP4i::DSP4SetByte();
}
}

11
src/chip/dsp4/dsp4.h Normal file
View File

@@ -0,0 +1,11 @@
class DSP4 { public:
void init();
void enable();
void power();
void reset();
uint8 read (uint16 addr);
void write(uint16 addr, uint8 data);
};
extern DSP4 dsp4;

2146
src/chip/dsp4/dsp4emu.c Normal file

File diff suppressed because it is too large Load Diff

108
src/chip/dsp4/dsp4emu.h Normal file
View File

@@ -0,0 +1,108 @@
//DSP-4 emulator code
//Copyright (c) 2004-2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden
#ifndef DSP4EMU_H
#define DSP4EMU_H
#undef TRUE
#undef FALSE
#define TRUE true
#define FALSE false
struct DSP4_t
{
bool8 waiting4command;
bool8 half_command;
uint16 command;
uint32 in_count;
uint32 in_index;
uint32 out_count;
uint32 out_index;
uint8 parameters[512];
uint8 output[512];
};
extern struct DSP4_t DSP4;
struct DSP4_vars_t
{
// op control
int8 DSP4_Logic; // controls op flow
// projection format
int16 lcv; // loop-control variable
int16 distance; // z-position into virtual world
int16 raster; // current raster line
int16 segments; // number of raster lines drawn
// 1.15.16 or 1.15.0 [sign, integer, fraction]
int32 world_x; // line of x-projection in world
int32 world_y; // line of y-projection in world
int32 world_dx; // projection line x-delta
int32 world_dy; // projection line y-delta
int16 world_ddx; // x-delta increment
int16 world_ddy; // y-delta increment
int32 world_xenv; // world x-shaping factor
int16 world_yofs; // world y-vertical scroll
int16 view_x1; // current viewer-x
int16 view_y1; // current viewer-y
int16 view_x2; // future viewer-x
int16 view_y2; // future viewer-y
int16 view_dx; // view x-delta factor
int16 view_dy; // view y-delta factor
int16 view_xofs1; // current viewer x-vertical scroll
int16 view_yofs1; // current viewer y-vertical scroll
int16 view_xofs2; // future viewer x-vertical scroll
int16 view_yofs2; // future viewer y-vertical scroll
int16 view_yofsenv; // y-scroll shaping factor
int16 view_turnoff_x; // road turnoff data
int16 view_turnoff_dx; // road turnoff delta factor
// drawing area
int16 viewport_cx; // x-center of viewport window
int16 viewport_cy; // y-center of render window
int16 viewport_left; // x-left of viewport
int16 viewport_right; // x-right of viewport
int16 viewport_top; // y-top of viewport
int16 viewport_bottom; // y-bottom of viewport
// sprite structure
int16 sprite_x; // projected x-pos of sprite
int16 sprite_y; // projected y-pos of sprite
int16 sprite_attr; // obj attributes
bool8 sprite_size; // sprite size: 8x8 or 16x16
int16 sprite_clipy; // visible line to clip pixels off
int16 sprite_count;
// generic projection variables designed for
// two solid polygons + two polygon sides
int16 poly_clipLf[2][2]; // left clip boundary
int16 poly_clipRt[2][2]; // right clip boundary
int16 poly_ptr[2][2]; // HDMA structure pointers
int16 poly_raster[2][2]; // current raster line below horizon
int16 poly_top[2][2]; // top clip boundary
int16 poly_bottom[2][2]; // bottom clip boundary
int16 poly_cx[2][2]; // center for left/right points
int16 poly_start[2]; // current projection points
int16 poly_plane[2]; // previous z-plane distance
// OAM
int16 OAM_attr[16]; // OAM (size,MSB) data
int16 OAM_index; // index into OAM table
int16 OAM_bits; // offset into OAM table
int16 OAM_RowMax; // maximum number of tiles per 8 aligned pixels (row)
int16 OAM_Row[32]; // current number of tiles per row
};
extern struct DSP4_vars_t DSP4_vars;
#endif

View File

@@ -1,7 +1,5 @@
#include "../../base.h"
OBC1 *obc1;
void OBC1::init() {}
void OBC1::enable() {}

View File

@@ -17,4 +17,4 @@ struct {
~OBC1();
};
extern OBC1 *obc1;
extern OBC1 obc1;

View File

@@ -1,7 +1,5 @@
#include "../../base.h"
SDD1 *sdd1;
#include "sdd1emu.cpp"
void SDD1::init() {}
@@ -43,10 +41,10 @@ uint8 b = (addr >> 16) & 0xff;
uint8 SDD1::mmio_read(uint16 addr) {
switch(addr) {
//>>20 == 0x100000 == 1mb
case 0x4804:return (sdd1.index[0] >> 20) & 7;
case 0x4805:return (sdd1.index[1] >> 20) & 7;
case 0x4806:return (sdd1.index[2] >> 20) & 7;
case 0x4807:return (sdd1.index[3] >> 20) & 7;
case 0x4804: return (sdd1.index[0] >> 20) & 7;
case 0x4805: return (sdd1.index[1] >> 20) & 7;
case 0x4806: return (sdd1.index[2] >> 20) & 7;
case 0x4807: return (sdd1.index[3] >> 20) & 7;
}
return r_cpu->regs.mdr;
@@ -60,10 +58,10 @@ void SDD1::mmio_write(uint16 addr, uint8 data) {
}
break;
//<<20 == 0x100000 == 1mb
case 0x4804:sdd1.index[0] = (data & 7) << 20;break;
case 0x4805:sdd1.index[1] = (data & 7) << 20;break;
case 0x4806:sdd1.index[2] = (data & 7) << 20;break;
case 0x4807:sdd1.index[3] = (data & 7) << 20;break;
case 0x4804: sdd1.index[0] = (data & 7) << 20; break;
case 0x4805: sdd1.index[1] = (data & 7) << 20; break;
case 0x4806: sdd1.index[2] = (data & 7) << 20; break;
case 0x4807: sdd1.index[3] = (data & 7) << 20; break;
}
}

View File

@@ -29,4 +29,4 @@ struct {
SDD1();
};
extern SDD1 *sdd1;
extern SDD1 sdd1;

View File

@@ -28,6 +28,7 @@ understood.
************************************************************************/
typedef uint8_t bool8;
class SDD1_IM { //Input Manager

View File

@@ -52,8 +52,6 @@
#include "../../base.h"
SRTC *srtc;
void SRTC::set_time() {
time_t rawtime;
tm *t;

View File

@@ -49,4 +49,4 @@ struct {
SRTC();
};
extern SRTC *srtc;
extern SRTC srtc;

84
src/chip/st010/st010.cpp Normal file
View File

@@ -0,0 +1,84 @@
#include "../../base.h"
#include "st010_data.h"
#include "st010_op.cpp"
int16 ST010::sin(int16 theta) {
return sin_table[(theta >> 8) & 0xff];
}
int16 ST010::cos(int16 theta) {
return sin_table[((theta + 0x4000) >> 8) & 0xff];
}
uint8 ST010::readb(uint16 addr) {
return ram[addr & 0xfff];
}
uint16 ST010::readw(uint16 addr) {
return (readb(addr + 0) << 0) |
(readb(addr + 1) << 8);
}
uint32 ST010::readd(uint16 addr) {
return (readb(addr + 0) << 0) |
(readb(addr + 1) << 8) |
(readb(addr + 2) << 16) |
(readb(addr + 3) << 24);
}
void ST010::writeb(uint16 addr, uint8 data) {
ram[addr & 0xfff] = data;
}
void ST010::writew(uint16 addr, uint16 data) {
writeb(addr + 0, data);
writeb(addr + 1, data >> 8);
}
void ST010::writed(uint16 addr, uint32 data) {
writeb(addr + 0, data);
writeb(addr + 1, data >> 8);
writeb(addr + 2, data >> 16);
writeb(addr + 3, data >> 24);
}
//
void ST010::init() {
}
void ST010::enable() {
}
void ST010::power() {
reset();
}
void ST010::reset() {
memset(ram, 0x00, sizeof ram);
}
//
uint8 ST010::read(uint16 addr) {
return readb(addr);
}
void ST010::write(uint16 addr, uint8 data) {
writeb(addr, data);
if(addr == 0x0021 && data & 0x80) {
switch(ram[0x0020]) {
case 0x01: op_01(); break;
case 0x02: op_02(); break;
case 0x03: op_03(); break;
case 0x04: op_04(); break;
case 0x05: op_05(); break;
case 0x06: op_06(); break;
case 0x07: op_07(); break;
case 0x08: op_08(); break;
}
ram[0x0021] &= ~0x80;
}
}

40
src/chip/st010/st010.h Normal file
View File

@@ -0,0 +1,40 @@
class ST010 { public:
uint8 ram[0x1000];
static const int16 sin_table[256];
static const int16 mode7_scale[176];
static const uint8 arctan[32][32];
//interfaces to sin table
int16 sin(int16 theta);
int16 cos(int16 theta);
//interfaces to ram buffer
uint8 readb (uint16 addr);
uint16 readw (uint16 addr);
uint32 readd (uint16 addr);
void writeb(uint16 addr, uint8 data);
void writew(uint16 addr, uint16 data);
void writed(uint16 addr, uint32 data);
//opcodes
void op_01();
void op_02();
void op_03();
void op_04();
void op_05();
void op_06();
void op_07();
void op_08();
void op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta);
//base
void init();
void enable();
void power();
void reset();
uint8 read (uint16 addr);
void write(uint16 addr, uint8 data);
};
extern ST010 st010;

126
src/chip/st010/st010_data.h Normal file
View File

@@ -0,0 +1,126 @@
const int16 ST010::sin_table[256] = {
0x0000, 0x0324, 0x0648, 0x096a, 0x0c8c, 0x0fab, 0x12c8, 0x15e2,
0x18f9, 0x1c0b, 0x1f1a, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11,
0x30fb, 0x33df, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a,
0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842,
0x5a82, 0x5cb3, 0x5ed7, 0x60eb, 0x62f1, 0x64e8, 0x66cf, 0x68a6,
0x6a6d, 0x6c23, 0x6dc9, 0x6f5e, 0x70e2, 0x7254, 0x73b5, 0x7504,
0x7641, 0x776b, 0x7884, 0x7989, 0x7a7c, 0x7b5c, 0x7c29, 0x7ce3,
0x7d89, 0x7e1d, 0x7e9c, 0x7f09, 0x7f61, 0x7fa6, 0x7fd8, 0x7ff5,
0x7fff, 0x7ff5, 0x7fd8, 0x7fa6, 0x7f61, 0x7f09, 0x7e9c, 0x7e1d,
0x7d89, 0x7ce3, 0x7c29, 0x7b5c, 0x7a7c, 0x7989, 0x7884, 0x776b,
0x7641, 0x7504, 0x73b5, 0x7254, 0x70e2, 0x6f5e, 0x6dc9, 0x6c23,
0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f1, 0x60eb, 0x5ed7, 0x5cb3,
0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4,
0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33df,
0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f1a, 0x1c0b,
0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8c, 0x096a, 0x0648, 0x0324,
0x0000, -0x0324, -0x0648, -0x096b, -0x0c8c, -0x0fab, -0x12c8, -0x15e2,
-0x18f9, -0x1c0b, -0x1f1a, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11,
-0x30fb, -0x33df, -0x36ba, -0x398d, -0x3c56, -0x3f17, -0x41ce, -0x447a,
-0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842,
-0x5a82, -0x5cb3, -0x5ed7, -0x60ec, -0x62f1, -0x64e8, -0x66cf, -0x68a6,
-0x6a6d, -0x6c23, -0x6dc9, -0x6f5e, -0x70e2, -0x7254, -0x73b5, -0x7504,
-0x7641, -0x776b, -0x7884, -0x7989, -0x7a7c, -0x7b5c, -0x7c29, -0x7ce3,
-0x7d89, -0x7e1d, -0x7e9c, -0x7f09, -0x7f61, -0x7fa6, -0x7fd8, -0x7ff5,
-0x7fff, -0x7ff5, -0x7fd8, -0x7fa6, -0x7f61, -0x7f09, -0x7e9c, -0x7e1d,
-0x7d89, -0x7ce3, -0x7c29, -0x7b5c, -0x7a7c, -0x7989, -0x7883, -0x776b,
-0x7641, -0x7504, -0x73b5, -0x7254, -0x70e2, -0x6f5e, -0x6dc9, -0x6c23,
-0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f1, -0x60eb, -0x5ed7, -0x5cb3,
-0x5a82, -0x5842, -0x55f5, -0x539a, -0x5133, -0x4ebf, -0x4c3f, -0x49b3,
-0x471c, -0x447a, -0x41cd, -0x3f17, -0x3c56, -0x398c, -0x36b9, -0x33de,
-0x30fb, -0x2e10, -0x2b1f, -0x2826, -0x2527, -0x2223, -0x1f19, -0x1c0b,
-0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324
};
const int16 ST010::mode7_scale[176] = {
0x0380, 0x0325, 0x02da, 0x029c, 0x0268, 0x023b, 0x0215, 0x01f3,
0x01d5, 0x01bb, 0x01a3, 0x018e, 0x017b, 0x016a, 0x015a, 0x014b,
0x013e, 0x0132, 0x0126, 0x011c, 0x0112, 0x0109, 0x0100, 0x00f8,
0x00f0, 0x00e9, 0x00e3, 0x00dc, 0x00d6, 0x00d1, 0x00cb, 0x00c6,
0x00c1, 0x00bd, 0x00b8, 0x00b4, 0x00b0, 0x00ac, 0x00a8, 0x00a5,
0x00a2, 0x009e, 0x009b, 0x0098, 0x0095, 0x0093, 0x0090, 0x008d,
0x008b, 0x0088, 0x0086, 0x0084, 0x0082, 0x0080, 0x007e, 0x007c,
0x007a, 0x0078, 0x0076, 0x0074, 0x0073, 0x0071, 0x006f, 0x006e,
0x006c, 0x006b, 0x0069, 0x0068, 0x0067, 0x0065, 0x0064, 0x0063,
0x0062, 0x0060, 0x005f, 0x005e, 0x005d, 0x005c, 0x005b, 0x005a,
0x0059, 0x0058, 0x0057, 0x0056, 0x0055, 0x0054, 0x0053, 0x0052,
0x0051, 0x0051, 0x0050, 0x004f, 0x004e, 0x004d, 0x004d, 0x004c,
0x004b, 0x004b, 0x004a, 0x0049, 0x0048, 0x0048, 0x0047, 0x0047,
0x0046, 0x0045, 0x0045, 0x0044, 0x0044, 0x0043, 0x0042, 0x0042,
0x0041, 0x0041, 0x0040, 0x0040, 0x003f, 0x003f, 0x003e, 0x003e,
0x003d, 0x003d, 0x003c, 0x003c, 0x003b, 0x003b, 0x003a, 0x003a,
0x003a, 0x0039, 0x0039, 0x0038, 0x0038, 0x0038, 0x0037, 0x0037,
0x0036, 0x0036, 0x0036, 0x0035, 0x0035, 0x0035, 0x0034, 0x0034,
0x0034, 0x0033, 0x0033, 0x0033, 0x0032, 0x0032, 0x0032, 0x0031,
0x0031, 0x0031, 0x0030, 0x0030, 0x0030, 0x0030, 0x002f, 0x002f,
0x002f, 0x002e, 0x002e, 0x002e, 0x002e, 0x002d, 0x002d, 0x002d,
0x002d, 0x002c, 0x002c, 0x002c, 0x002c, 0x002b, 0x002b, 0x002b
};
const uint8 ST010::arctan[32][32] = {
{ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
{ 0x80, 0xa0, 0xad, 0xb3, 0xb6, 0xb8, 0xb9, 0xba, 0xbb, 0xbb, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd,
0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf },
{ 0x80, 0x93, 0xa0, 0xa8, 0xad, 0xb0, 0xb3, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xbb,
0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd },
{ 0x80, 0x8d, 0x98, 0xa0, 0xa6, 0xaa, 0xad, 0xb0, 0xb1, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb7, 0xb8,
0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc },
{ 0x80, 0x8a, 0x93, 0x9a, 0xa0, 0xa5, 0xa8, 0xab, 0xad, 0xaf, 0xb0, 0xb2, 0xb3, 0xb4, 0xb5, 0xb5,
0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb },
{ 0x80, 0x88, 0x90, 0x96, 0x9b, 0xa0, 0xa4, 0xa7, 0xa9, 0xab, 0xad, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
0xb4, 0xb4, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9 },
{ 0x80, 0x87, 0x8d, 0x93, 0x98, 0x9c, 0xa0, 0xa3, 0xa6, 0xa8, 0xaa, 0xac, 0xad, 0xae, 0xb0, 0xb0,
0xb1, 0xb2, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8 },
{ 0x80, 0x86, 0x8b, 0x90, 0x95, 0x99, 0x9d, 0xa0, 0xa3, 0xa5, 0xa7, 0xa9, 0xaa, 0xac, 0xad, 0xae,
0xaf, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7 },
{ 0x80, 0x85, 0x8a, 0x8f, 0x93, 0x97, 0x9a, 0x9d, 0xa0, 0xa2, 0xa5, 0xa6, 0xa8, 0xaa, 0xab, 0xac,
0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, 0xb5 },
{ 0x80, 0x85, 0x89, 0x8d, 0x91, 0x95, 0x98, 0x9b, 0x9e, 0xa0, 0xa0, 0xa4, 0xa6, 0xa7, 0xa9, 0xaa,
0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb4 },
{ 0x80, 0x84, 0x88, 0x8c, 0x90, 0x93, 0x96, 0x99, 0x9b, 0x9e, 0xa0, 0xa2, 0xa4, 0xa5, 0xa7, 0xa8,
0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3 },
{ 0x80, 0x84, 0x87, 0x8b, 0x8e, 0x91, 0x94, 0x97, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5, 0xa6,
0xa7, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2 },
{ 0x80, 0x83, 0x87, 0x8a, 0x8d, 0x90, 0x93, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5,
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1 },
{ 0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x94, 0x96, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa2, 0xa3,
0xa4, 0xa5, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xaf, 0xb0 },
{ 0x80, 0x83, 0x86, 0x89, 0x8b, 0x8e, 0x90, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa1,
0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac, 0xad, 0xad, 0xae, 0xae, 0xaf },
{ 0x80, 0x83, 0x85, 0x88, 0x8b, 0x8d, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9b, 0x9d, 0x9f, 0xa0,
0xa1, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xab, 0xab, 0xac, 0xad, 0xad, 0xae },
{ 0x80, 0x83, 0x85, 0x88, 0x8a, 0x8c, 0x8f, 0x91, 0x93, 0x95, 0x97, 0x99, 0x9a, 0x9c, 0x9d, 0x9f,
0xa0, 0xa1, 0xa2, 0xa3, 0xa5, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xab, 0xac, 0xad },
{ 0x80, 0x82, 0x85, 0x87, 0x89, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x97, 0x99, 0x9b, 0x9c, 0x9d,
0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac },
{ 0x80, 0x82, 0x85, 0x87, 0x89, 0x8b, 0x8d, 0x8f, 0x91, 0x93, 0x95, 0x96, 0x98, 0x99, 0x9b, 0x9c,
0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab },
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x9a, 0x9b,
0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa },
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x99, 0x9a,
0x9b, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9 },
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8f, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x99,
0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8 },
{ 0x80, 0x82, 0x84, 0x86, 0x87, 0x89, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x98,
0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7 },
{ 0x80, 0x82, 0x84, 0x85, 0x87, 0x89, 0x8a, 0x8c, 0x8e, 0x8f, 0x91, 0x92, 0x94, 0x95, 0x96, 0x98,
0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6 },
{ 0x80, 0x82, 0x83, 0x85, 0x87, 0x88, 0x8a, 0x8c, 0x8d, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x96, 0x97,
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5 },
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x94, 0x95, 0x96,
0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa4 },
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x89, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x95,
0x96, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4 },
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x87, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93, 0x95,
0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2, 0xa3 },
{ 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x89, 0x8a, 0x8b, 0x8d, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94,
0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2 },
{ 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x88, 0x8a, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93,
0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1, 0xa1 },
{ 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8b, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93,
0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1 },
{ 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92,
0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0 }
};

257
src/chip/st010/st010_op.cpp Normal file
View File

@@ -0,0 +1,257 @@
//ST-010 emulation code - Copyright (C) 2003 The Dumper, Matthew Kendora, Overload, Feather
//bsnes port - Copyright (C) 2007 byuu
void ST010::op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta) {
if((x0 < 0) && (y0 < 0)) {
x1 = -x0;
y1 = -y0;
quadrant = -0x8000;
} else if(x0 < 0) {
x1 = y0;
y1 = -x0;
quadrant = -0x4000;
} else if(y0 < 0) {
x1 = -y0;
y1 = x0;
quadrant = 0x4000;
} else {
x1 = x0;
y1 = y0;
quadrant = 0x0000;
}
while((x1 > 0x1f) || (y1 > 0x1f)) {
if(x1 > 1) { x1 >>= 1; }
if(y1 > 1) { y1 >>= 1; }
}
if(y1 == 0) { quadrant += 0x4000; }
theta = (arctan[y1][x1] << 8) ^ quadrant;
}
//
void ST010::op_01() {
int16 x0 = readw(0x0000);
int16 y0 = readw(0x0002);
int16 x1, y1, quadrant, theta;
op_01(x0, y0, x1, y1, quadrant, theta);
writew(0x0000, x1);
writew(0x0002, y1);
writew(0x0004, quadrant);
//writew(0x0006, y0); //Overload's docs note this write occurs, SNES9x disagrees
writew(0x0010, theta);
}
void ST010::op_02() {
int16 positions = readw(0x0024);
uint16 *places = (uint16*)(ram + 0x0040);
uint16 *drivers = (uint16*)(ram + 0x0080);
bool sorted;
uint16 temp;
if(positions > 1) {
do {
sorted = true;
for(int i = 0; i < positions - 1; i++) {
if(places[i] < places[i + 1]) {
temp = places[i + 1];
places[i + 1] = places[i];
places[i] = temp;
temp = drivers[i + 1];
drivers[i + 1] = drivers[i];
drivers[i] = temp;
sorted = false;
}
}
positions--;
} while(!sorted);
}
}
void ST010::op_03() {
int16 x0 = readw(0x0000);
int16 y0 = readw(0x0002);
int16 multiplier = readw(0x0004);
int32 x1, y1;
x1 = x0 * multiplier << 1;
y1 = y0 * multiplier << 1;
writed(0x0010, x1);
writed(0x0014, y1);
}
void ST010::op_04() {
int16 x = readw(0x0000);
int16 y = readw(0x0002);
int16 square;
//calculate the vector length of (x,y)
square = (int16)sqrt((double)(y * y + x * x));
writew(0x0010, square);
}
void ST010::op_05() {
int32 dx, dy;
int16 a1, b1, c1;
uint16 o1;
bool wrap = false;
//target (x,y) coordinates
int16 ypos_max = readw(0x00c0);
int16 xpos_max = readw(0x00c2);
//current coordinates and direction
int32 ypos = readd(0x00c4);
int32 xpos = readd(0x00c8);
uint16 rot = readw(0x00cc);
//physics
uint16 speed = readw(0x00d4);
uint16 accel = readw(0x00d6);
uint16 speed_max = readw(0x00d8);
//special condition acknowledgement
int16 system = readw(0x00da);
int16 flags = readw(0x00dc);
//new target coordinates
int16 ypos_new = readw(0x00de);
int16 xpos_new = readw(0x00e0);
//mask upper bit
xpos_new &= 0x7fff;
//get the current distance
dx = xpos_max - (xpos >> 16);
dy = ypos_max - (ypos >> 16);
//quirk: clear and move in9
writew(0x00d2, 0xffff);
writew(0x00da, 0x0000);
//grab the target angle
op_01(dy, dx, a1, b1, c1, (int16&)o1);
//check for wrapping
if(abs(o1 - rot) > 0x8000) {
o1 += 0x8000;
rot += 0x8000;
wrap = true;
}
uint16 old_speed = speed;
//special case
if(abs(o1 - rot) == 0x8000) {
speed = 0x100;
}
//slow down for sharp curves
else if(abs(o1 - rot) >= 0x1000) {
uint32 slow = abs(o1 - rot);
slow >>= 4; //scaling
speed -= slow;
}
//otherwise accelerate
else {
speed += accel;
if(speed > speed_max) {
speed = speed_max; //clip speed
}
}
//prevent negative/positive overflow
if(abs(old_speed - speed) > 0x8000) {
if(old_speed < speed) { speed = 0; }
else speed = 0xff00;
}
//adjust direction by so many degrees
//be careful of negative adjustments
if((o1 > rot && (o1 - rot) > 0x80) || (o1 < rot && (rot - o1) >= 0x80)) {
if(o1 < rot) { rot -= 0x280; }
else if(o1 > rot) { rot += 0x280; }
}
//turn of wrapping
if(wrap) { rot -= 0x8000; }
//now check the distances (store for later)
dx = (xpos_max << 16) - xpos;
dy = (ypos_max << 16) - ypos;
dx >>= 16;
dy >>= 16;
//if we're in so many units of the target, signal it
if((system && (dy <= 6 && dy >= -8) && (dx <= 126 && dx >= -128)) || (!system && (dx <= 6 && dx >= -8) && (dy <= 126 && dy >= -128))) {
//announce our new destination and flag it
xpos_max = xpos_new & 0x7fff;
ypos_max = ypos_new;
flags |= 0x08;
}
//update position
xpos -= (cos(rot) * 0x400 >> 15) * (speed >> 8) << 1;
ypos -= (sin(rot) * 0x400 >> 15) * (speed >> 8) << 1;
//quirk: mask upper byte
xpos &= 0x1fffffff;
ypos &= 0x1fffffff;
writew(0x00c0, ypos_max);
writew(0x00c2, xpos_max);
writed(0x00c4, ypos);
writed(0x00c8, xpos);
writew(0x00cc, rot);
writew(0x00d4, speed);
writew(0x00dc, flags);
}
void ST010::op_06() {
int16 multiplicand = readw(0x0000);
int16 multiplier = readw(0x0002);
int32 product;
product = multiplicand * multiplier << 1;
writed(0x0010, product);
}
void ST010::op_07() {
int16 theta = readw(0x0000);
int16 data;
for(int i = 0, offset = 0; i < 176; i++) {
data = mode7_scale[i] * cos(theta) >> 15;
writew(0x00f0 + offset, data);
writew(0x0510 + offset, data);
data = mode7_scale[i] * sin(theta) >> 15;
writew(0x0250 + offset, data);
if(data) { data = ~data; }
writew(0x03b0 + offset, data);
offset += 2;
}
}
void ST010::op_08() {
int16 x0 = readw(0x0000);
int16 y0 = readw(0x0002);
int16 theta = readw(0x0004);
int16 x1, y1;
x1 = (y0 * sin(theta) >> 15) + (x0 * cos(theta) >> 15);
y1 = (y0 * cos(theta) >> 15) - (x0 * sin(theta) >> 15);
writew(0x0010, x1);
writew(0x0012, y1);
}

View File

@@ -0,0 +1,3 @@
void op_unknown() {}
void op_00();

View File

@@ -0,0 +1,7 @@
//STOP
void SuperFX::op_00() {
regs.sfr.g = 0;
regs.sfr.b = 0;
regs.sfr.alt1 = 0;
regs.sfr.alt2 = 0;
}

View File

@@ -0,0 +1,64 @@
uint8 SuperFX::mmio_read(uint16 addr) {
switch(addr) {
case 0x3000: return regs.r0.l;
case 0x3001: return regs.r0.h;
case 0x3002: return regs.r1.l;
case 0x3003: return regs.r1.h;
case 0x3004: return regs.r2.l;
case 0x3005: return regs.r2.h;
case 0x3006: return regs.r3.l;
case 0x3007: return regs.r3.h;
case 0x3008: return regs.r4.l;
case 0x3009: return regs.r4.h;
case 0x300a: return regs.r5.l;
case 0x300b: return regs.r5.h;
case 0x300c: return regs.r6.l;
case 0x300d: return regs.r6.h;
case 0x300e: return regs.r7.l;
case 0x300f: return regs.r7.h;
case 0x3010: return regs.r8.l;
case 0x3011: return regs.r8.h;
case 0x3012: return regs.r9.l;
case 0x3013: return regs.r9.h;
case 0x3014: return regs.r10.l;
case 0x3015: return regs.r10.h;
case 0x3016: return regs.r11.l;
case 0x3017: return regs.r11.h;
case 0x3018: return regs.r12.l;
case 0x3019: return regs.r12.h;
case 0x301a: return regs.r13.l;
case 0x301b: return regs.r13.h;
case 0x301c: return regs.r14.l;
case 0x301d: return regs.r14.h;
case 0x301e: return regs.r15.l;
case 0x301f: return regs.r15.h;
//0x3020 - 0x302f unused
case 0x3030: return regs.sfr;
case 0x3031: return regs.sfr >> 8;
case 0x3032: return 0x00; //unused
case 0x3033: return 0x00; //BRAMR (write only)
case 0x3034: return regs.pbr;
case 0x3035: return 0x00; //unused
case 0x3036: return regs.rombr;
case 0x3037: return 0x00; //CFGR (write only)
case 0x3038: return 0x00; //SCBR (write only)
case 0x3039: return 0x00; //CLSR (write only)
case 0x303a: return 0x00; //SCMR (write only)
case 0x303b: return regs.vcr;
case 0x303c: return regs.rambr;
case 0x303d: return 0x00; //unused
case 0x303e: return regs.cbr;
case 0x303f: return regs.cbr >> 8;
//0x3040 - 0x30ff unused
}
if(addr >= 0x3100 && addr <= 0x32ff) {
return cache[addr - 0x3100];
}
return 0x00;
}

View File

@@ -0,0 +1,63 @@
void SuperFX::mmio_write(uint16 addr, uint8 data) {
switch(addr) {
case 0x3000: regs.r0.l = data; return;
case 0x3001: regs.r0.h = data; return;
case 0x3002: regs.r1.l = data; return;
case 0x3003: regs.r1.h = data; return;
case 0x3004: regs.r2.l = data; return;
case 0x3005: regs.r2.h = data; return;
case 0x3006: regs.r3.l = data; return;
case 0x3007: regs.r3.h = data; return;
case 0x3008: regs.r4.l = data; return;
case 0x3009: regs.r4.h = data; return;
case 0x300a: regs.r5.l = data; return;
case 0x300b: regs.r5.h = data; return;
case 0x300c: regs.r6.l = data; return;
case 0x300d: regs.r6.h = data; return;
case 0x300e: regs.r7.l = data; return;
case 0x300f: regs.r7.h = data; return;
case 0x3010: regs.r8.l = data; return;
case 0x3011: regs.r8.h = data; return;
case 0x3012: regs.r9.l = data; return;
case 0x3013: regs.r9.h = data; return;
case 0x3014: regs.r10.l = data; return;
case 0x3015: regs.r10.h = data; return;
case 0x3016: regs.r11.l = data; return;
case 0x3017: regs.r11.h = data; return;
case 0x3018: regs.r12.l = data; return;
case 0x3019: regs.r12.h = data; return;
case 0x301a: regs.r13.l = data; return;
case 0x301b: regs.r13.h = data; return;
case 0x301c: regs.r14.l = data; return;
case 0x301d: regs.r14.h = data; return;
case 0x301e: regs.r15.l = data; return;
case 0x301f: regs.r15.h = data; return;
//0x3020 - 0x302f unused
case 0x3030: regs.sfr.l = data & 0x7e; return; //mask invalid bits
case 0x3031: regs.sfr.h = data & 0x9f; return; //mask invalid bits
case 0x3032: return; //unused
case 0x3033: regs.bramr = data; return;
case 0x3034: regs.pbr = data; return;
case 0x3035: return; //unused
case 0x3036: return; //ROMBR (read only)
case 0x3037: regs.cfgr = data; return;
case 0x3038: regs.scbr = data; return;
case 0x3039: regs.clsr = data; return;
case 0x303a: regs.scmr = data; return;
case 0x303b: return; //VCR (read only)
case 0x303c: return; //RAMBR (read only)
case 0x303d: return; //unused
case 0x303e: return; //CBR low (read only)
case 0x303f: return; //CBR high (read only)
//0x3040 - 0x30ff unused
}
if(addr >= 0x3100 && addr <= 0x32ff) {
cache[addr - 0x3100] = data;
return;
}
}

174
src/chip/superfx/regs.h Normal file
View File

@@ -0,0 +1,174 @@
struct Reg16 {
union {
uint16 w;
struct { uint8 order_lsb2(l, h); };
};
inline operator unsigned() const { return w; }
inline unsigned operator=(const unsigned i) { return w = i; }
Reg16() : w(0) {}
};
template<int bit> struct RegFlag8 {
uint8 data;
inline operator bool() const { return data & bit; }
inline bool operator=(const bool i) { i ? data |= bit : data &= ~bit; return i; }
};
template<int bit> struct RegFlag16 {
uint16 data;
inline operator bool() const { return data & bit; }
inline bool operator=(const bool i) { i ? data |= bit : data &= ~bit; return i; }
};
struct SFR {
union {
uint16 w;
struct { uint8 order_lsb2(l, h); };
RegFlag16<0x0002> z; //zero flag
RegFlag16<0x0004> c; //carry flag
RegFlag16<0x0008> s; //sign flag
RegFlag16<0x0010> v; //overflow flag
RegFlag16<0x0020> g; //go flag
RegFlag16<0x0040> r; //ROM read using r14 flag
RegFlag16<0x0100> alt1; //alternate instruction 1 flag
RegFlag16<0x0200> alt2; //alternate instruction 2 flag
RegFlag16<0x0400> il; //immediate lower 8-bit flag
RegFlag16<0x0800> ih; //immediate upper 8-bit flag
RegFlag16<0x1000> b; //WITH instruction flag
RegFlag16<0x8000> irq; //interrupt flag
};
inline operator unsigned() const { return w & 0x9f7e; } //invalid flag bits always return 0 when read
inline unsigned operator=(const unsigned i) { return w = i & 0x9f7e; }
SFR() : w(0) {}
};
struct RAMBR {
union {
uint8 b;
RegFlag8<0x01> bank;
};
inline operator unsigned() const { return b & 0x01; }
inline unsigned operator=(const unsigned i) { return b = i & 0x01; }
RAMBR() : b(0) {}
};
struct CBR {
uint16 w;
inline operator unsigned() const { return w & 0xfff0; }
inline unsigned operator=(const unsigned i) { return w = i & 0xfff0; }
CBR() : w(0) {}
};
struct SCMR {
union {
uint8 b;
RegFlag8<0x01> md0; //color mode low
RegFlag8<0x02> md1; //color mode high
RegFlag8<0x04> ht0; //height low
RegFlag8<0x08> ran; //ram enable
RegFlag8<0x10> ron; //rom enable
RegFlag8<0x20> ht1; //height high
};
inline operator unsigned() const { return b; }
inline unsigned operator=(const unsigned i) { return b = i; }
SCMR() : b(0) {}
};
struct BRAMR {
union {
uint8 b;
RegFlag8<0x01> flag;
};
inline operator unsigned() const { return b; }
inline unsigned operator=(const unsigned i) { return b = i; }
BRAMR() : b(0) {}
};
struct CFGR {
union {
uint8 b;
RegFlag8<0x20> ms0; //multiplier speed selection
RegFlag8<0x80> irq; //irq mask flag
};
inline operator unsigned() const { return b; }
inline unsigned operator=(const unsigned i) { return b = i; }
CFGR() : b(0) {}
};
struct CLSR {
union {
uint8 b;
RegFlag8<0x01> flag;
};
inline operator unsigned() const { return b; }
inline unsigned operator=(const unsigned i) { return b = i; }
CLSR() : b(0) {}
};
struct POR {
union {
uint8 b;
RegFlag8<0x01> transparent; //transparent flag
RegFlag8<0x02> dither; //dither flag
RegFlag8<0x04> highnibble; //high nibble flag
RegFlag8<0x08> freezehigh; //freeze high flag
RegFlag8<0x10> obj; //OBJ flag
};
inline operator unsigned() const { return b; }
inline unsigned operator=(const unsigned i) { return b = i; }
POR() : b(0) {}
};
struct Regs {
Reg16 r0; //default source/destination register
Reg16 r1; //pixel plot X position register
Reg16 r2; //pixel plot Y position register
Reg16 r3;
Reg16 r4; //lower 16-bit result of lmult
Reg16 r5;
Reg16 r6; //multiplier for fmult and lmult
Reg16 r7; //fixed point texel X position for merge
Reg16 r8; //fixed point texel Y position for merge
Reg16 r9;
Reg16 r10;
Reg16 r11; //return address set by link
Reg16 r12; //loop counter
Reg16 r13; //loop point address
Reg16 r14; //rom address for getb, getbh, getbl, getbs
Reg16 r15; //program counter
SFR sfr; //status/flag register
uint8 pbr; //program bank register
uint8 rombr; //rom bank register
RAMBR rambr; //ram bank register
CBR cbr; //cache base register
uint8 scbr; //screen base register
SCMR scmr; //screen mode register
BRAMR bramr; //backup ram register
uint8 vcr; //version code register
CFGR cfgr; //config register
CLSR clsr; //clock select register
uint8 colr; //color register
POR por; //plot option register
} regs;

View File

@@ -0,0 +1,42 @@
#include "../../base.h"
#include "core/op0x.cpp"
#include "memory/read.cpp"
#include "memory/write.cpp"
void SuperFX::init() {
}
void SuperFX::enable() {
for(uint i = 0x3000; i <= 0x32ff; i++) {
r_mem->set_mmio_mapper(i, this);
}
}
void SuperFX::power() {
reset();
}
void SuperFX::reset() {
regs.r0 = 0;
regs.r1 = 0;
regs.r2 = 0;
regs.r3 = 0;
regs.r4 = 0;
regs.r5 = 0;
regs.r6 = 0;
regs.r7 = 0;
regs.r8 = 0;
regs.r9 = 0;
regs.r10 = 0;
regs.r11 = 0;
regs.r12 = 0;
regs.r13 = 0;
regs.r14 = 0;
regs.r15 = 0;
regs.sfr = 0;
memset(cache, 0, sizeof cache);
}

View File

@@ -0,0 +1,17 @@
class SuperFX : public MMIO { public:
#include "core/core.h"
void init();
void enable();
void power();
void reset();
uint8 mmio_read (uint16 addr);
void mmio_write(uint16 addr, uint8 data);
private:
#include "regs.h"
uint8 cache[512]; //cache RAM
};
extern SuperFX superfx;

2
src/clean.bat Normal file
View File

@@ -0,0 +1,2 @@
::@make PLATFORM=win-mingw4-lui clean
@make PLATFORM=win-visualc-lui clean

2
src/clean.sh Normal file
View File

@@ -0,0 +1,2 @@
#!/bin/sh
make PLATFORM=x-gcc-lui clean

View File

@@ -1,7 +1,10 @@
Config config_file;
namespace config {
Config& config() {
static Config config;
return config;
}
string file_updatepath(const char *req_file, const char *req_path) {
string file(req_file);
replace(file, "\\", "/");
@@ -25,83 +28,98 @@ stringarray part;
return path;
}
Setting Path::base(0, "fs.base_path",
StringSetting Path::base(0, "fs.base_path",
"Path that bsnes resides in", "");
Setting Path::rom(&config_file, "path.rom",
StringSetting Path::rom(&config(), "path.rom",
"Default path to look for ROM files in (\"\" = use default directory)", "");
Setting Path::save(&config_file, "path.save",
StringSetting Path::save(&config(), "path.save",
"Default path for all save RAM and cheat files (\"\" = use current directory)", "");
Setting Path::bios(&config_file, "path.bios",
StringSetting Path::bios(&config(), "path.bios",
"Path where BIOS file(s) are located\n"
"Supported BIOS files:\n"
"stbios.bin - Bandai Sufami Turbo"
"", "./bios");
Setting Path::save_ext(&config_file, "path.save_ext",
StringSetting Path::save_ext(&config(), "path.save_ext",
"Extension to be used for all save RAM files", "srm");
Setting SNES::gamma_ramp(&config_file, "snes.colorfilter.gamma_ramp",
"Use precalculated TV-style gamma ramp", true, Setting::BOOL);
Setting SNES::sepia(&config_file, "snes.colorfilter.sepia",
"Convert color to sepia tone", false, Setting::BOOL);
Setting SNES::grayscale(&config_file, "snes.colorfilter.grayscale",
"Convert color to grayscale tone", false, Setting::BOOL);
Setting SNES::invert(&config_file, "snes.colorfilter.invert",
"Invert output image colors", false, Setting::BOOL);
Setting SNES::contrast(&config_file, "snes.colorfilter.contrast",
"Contrast", 0, Setting::DEC);
Setting SNES::brightness(&config_file, "snes.colorfilter.brightness",
"Brightness", 0, Setting::DEC);
Setting SNES::gamma(&config_file, "snes.colorfilter.gamma",
"Gamma", 80, Setting::DEC);
IntegerSetting SNES::gamma_ramp(&config(), "snes.colorfilter.gamma_ramp",
"Use precalculated TV-style gamma ramp", IntegerSetting::Boolean, true);
IntegerSetting SNES::sepia(&config(), "snes.colorfilter.sepia",
"Convert color to sepia tone", IntegerSetting::Boolean, false);
IntegerSetting SNES::grayscale(&config(), "snes.colorfilter.grayscale",
"Convert color to grayscale tone", IntegerSetting::Boolean, false);
IntegerSetting SNES::invert(&config(), "snes.colorfilter.invert",
"Invert output image colors", IntegerSetting::Boolean, false);
IntegerSetting SNES::contrast(&config(), "snes.colorfilter.contrast",
"Contrast", IntegerSetting::Decimal, 0);
IntegerSetting SNES::brightness(&config(), "snes.colorfilter.brightness",
"Brightness", IntegerSetting::Decimal, 0);
IntegerSetting SNES::gamma(&config(), "snes.colorfilter.gamma",
"Gamma", IntegerSetting::Decimal, 80);
Setting SNES::ntsc_merge_fields(&config_file, "snes.ntsc_merge_fields",
IntegerSetting SNES::ntsc_merge_fields(&config(), "snes.ntsc_merge_fields",
"Merge fields in NTSC video filter\n"
"Set to true if using filter at any refresh rate other than 60hz\n"
"", true, Setting::BOOL);
"", IntegerSetting::Boolean, true);
Setting SNES::mute(&config_file, "snes.mute", "Mutes SNES audio output when enabled",
false, Setting::BOOL);
IntegerSetting SNES::mute(&config(), "snes.mute", "Mutes SNES audio output when enabled",
IntegerSetting::Boolean, false);
Setting SNES::controller_port0(&config_file, "snes.controller_port_1",
"Controller attached to SNES port 1", ::SNES::DEVICEID_JOYPAD1, Setting::DEC);
Setting SNES::controller_port1(&config_file, "snes.controller_port_2",
"Controller attached to SNES port 2", ::SNES::DEVICEID_JOYPAD2, Setting::DEC);
IntegerSetting SNES::controller_port0(&config(), "snes.controller_port_1",
"Controller attached to SNES port 1", IntegerSetting::Decimal, ::SNES::DEVICEID_JOYPAD1);
IntegerSetting SNES::controller_port1(&config(), "snes.controller_port_2",
"Controller attached to SNES port 2", IntegerSetting::Decimal, ::SNES::DEVICEID_JOYPAD2);
Setting CPU::ntsc_clock_rate(&config_file, "cpu.ntsc_clock_rate",
"NTSC S-CPU clock rate (in hz)", 21477272, Setting::DEC);
Setting CPU::pal_clock_rate(&config_file, "cpu.pal_clock_rate",
"PAL S-CPU clock rate (in hz)", 21281370, Setting::DEC);
IntegerSetting CPU::ntsc_clock_rate(&config(), "cpu.ntsc_clock_rate",
"NTSC S-CPU clock rate (in hz)", IntegerSetting::Decimal, 21477272);
IntegerSetting CPU::pal_clock_rate(&config(), "cpu.pal_clock_rate",
"PAL S-CPU clock rate (in hz)", IntegerSetting::Decimal, 21281370);
Setting CPU::hdma_enable(0, "cpu.hdma_enable",
"Enable HDMA effects", true, Setting::BOOL);
IntegerSetting CPU::hdma_enable(0, "cpu.hdma_enable",
"Enable HDMA effects", IntegerSetting::Boolean, true);
Setting SMP::ntsc_clock_rate(&config_file, "smp.ntsc_clock_rate",
"NTSC S-SMP clock rate (in hz)", 24606720, Setting::DEC);
Setting SMP::pal_clock_rate(&config_file, "smp.pal_clock_rate",
"PAL S-SMP clock rate (in hz)", 24606720, Setting::DEC);
IntegerSetting SMP::ntsc_clock_rate(&config(), "smp.ntsc_clock_rate",
"NTSC S-SMP clock rate (in hz)", IntegerSetting::Decimal, 24606720);
IntegerSetting SMP::pal_clock_rate(&config(), "smp.pal_clock_rate",
"PAL S-SMP clock rate (in hz)", IntegerSetting::Decimal, 24606720);
Setting PPU::Hack::render_scanline_position(&config_file, "ppu.hack.render_scanline_position",
IntegerSetting PPU::Hack::render_scanline_position(&config(), "ppu.hack.render_scanline_position",
"Approximate HCLOCK position to render at for scanline-based renderers",
512, Setting::DEC);
Setting PPU::Hack::obj_cache(&config_file, "ppu.hack.obj_cache",
IntegerSetting::Decimal, 512);
IntegerSetting PPU::Hack::obj_cache(&config(), "ppu.hack.obj_cache",
"Cache OAM OBJ attributes one scanline before rendering\n"
"This is technically closer to the actual operation of the SNES,\n"
"but can cause problems in many games if enabled",
false, Setting::BOOL);
"but can cause problems in some games if enabled",
IntegerSetting::Boolean, false);
IntegerSetting PPU::Hack::oam_address_invalidation(&config(), "ppu.hack.oam_address_invalidation",
"OAM access address changes during active display, as the S-PPU reads\n"
"data to render the display. Thusly, the address retrieved when accessing\n"
"OAM during active display is unpredictable. Unfortunately, the exact\n"
"algorithm for this is completely unknown at this time. It is more hardware\n"
"accurate to enable this setting, but one must *not* rely on the actual\n"
"address to match hardware under emulation.",
IntegerSetting::Boolean, true);
IntegerSetting PPU::Hack::cgram_address_invalidation(&config(), "ppu.hack.cgram_address_invalidation",
"CGRAM access address changes during active display (excluding hblank), as\n"
"the S-PPU reads data to render the display. Thusly, as with OAM, the access\n"
"address is unpredictable. Again, enabling this setting is more hardware\n"
"accurate, but one must *not* rely on the actual address to match hardware\n"
"under emulation.",
IntegerSetting::Boolean, true);
Setting PPU::opt_enable(0, "ppu.opt_enable", "Enable offset-per-tile effects", true, Setting::BOOL);
Setting PPU::bg1_pri0_enable(0, "ppu.bg1_pri0_enable", "Enable BG1 Priority 0", true, Setting::BOOL);
Setting PPU::bg1_pri1_enable(0, "ppu.bg1_pri1_enable", "Enable BG1 Priority 1", true, Setting::BOOL);
Setting PPU::bg2_pri0_enable(0, "ppu.bg2_pri0_enable", "Enable BG2 Priority 0", true, Setting::BOOL);
Setting PPU::bg2_pri1_enable(0, "ppu.bg2_pri1_enable", "Enable BG2 Priority 1", true, Setting::BOOL);
Setting PPU::bg3_pri0_enable(0, "ppu.bg3_pri0_enable", "Enable BG3 Priority 0", true, Setting::BOOL);
Setting PPU::bg3_pri1_enable(0, "ppu.bg3_pri1_enable", "Enable BG3 Priority 1", true, Setting::BOOL);
Setting PPU::bg4_pri0_enable(0, "ppu.bg4_pri0_enable", "Enable BG4 Priority 0", true, Setting::BOOL);
Setting PPU::bg4_pri1_enable(0, "ppu.bg4_pri1_enable", "Enable BG4 Priority 1", true, Setting::BOOL);
Setting PPU::oam_pri0_enable(0, "ppu.oam_pri0_enable", "Enable OAM Priority 0", true, Setting::BOOL);
Setting PPU::oam_pri1_enable(0, "ppu.oam_pri1_enable", "Enable OAM Priority 1", true, Setting::BOOL);
Setting PPU::oam_pri2_enable(0, "ppu.oam_pri2_enable", "Enable OAM Priority 2", true, Setting::BOOL);
Setting PPU::oam_pri3_enable(0, "ppu.oam_pri3_enable", "Enable OAM Priority 3", true, Setting::BOOL);
IntegerSetting PPU::opt_enable(0, "ppu.opt_enable", "Enable offset-per-tile effects", IntegerSetting::Boolean, true);
IntegerSetting PPU::bg1_pri0_enable(0, "ppu.bg1_pri0_enable", "Enable BG1 Priority 0", IntegerSetting::Boolean, true);
IntegerSetting PPU::bg1_pri1_enable(0, "ppu.bg1_pri1_enable", "Enable BG1 Priority 1", IntegerSetting::Boolean, true);
IntegerSetting PPU::bg2_pri0_enable(0, "ppu.bg2_pri0_enable", "Enable BG2 Priority 0", IntegerSetting::Boolean, true);
IntegerSetting PPU::bg2_pri1_enable(0, "ppu.bg2_pri1_enable", "Enable BG2 Priority 1", IntegerSetting::Boolean, true);
IntegerSetting PPU::bg3_pri0_enable(0, "ppu.bg3_pri0_enable", "Enable BG3 Priority 0", IntegerSetting::Boolean, true);
IntegerSetting PPU::bg3_pri1_enable(0, "ppu.bg3_pri1_enable", "Enable BG3 Priority 1", IntegerSetting::Boolean, true);
IntegerSetting PPU::bg4_pri0_enable(0, "ppu.bg4_pri0_enable", "Enable BG4 Priority 0", IntegerSetting::Boolean, true);
IntegerSetting PPU::bg4_pri1_enable(0, "ppu.bg4_pri1_enable", "Enable BG4 Priority 1", IntegerSetting::Boolean, true);
IntegerSetting PPU::oam_pri0_enable(0, "ppu.oam_pri0_enable", "Enable OAM Priority 0", IntegerSetting::Boolean, true);
IntegerSetting PPU::oam_pri1_enable(0, "ppu.oam_pri1_enable", "Enable OAM Priority 1", IntegerSetting::Boolean, true);
IntegerSetting PPU::oam_pri2_enable(0, "ppu.oam_pri2_enable", "Enable OAM Priority 2", IntegerSetting::Boolean, true);
IntegerSetting PPU::oam_pri3_enable(0, "ppu.oam_pri3_enable", "Enable OAM Priority 3", IntegerSetting::Boolean, true);
};

View File

@@ -1,44 +1,46 @@
extern Config config_file;
namespace config {
extern Config& config();
string file_updatepath(const char *, const char *);
extern struct Path {
static Setting base, rom, save, bios;
static Setting save_ext;
static StringSetting base, rom, save, bios;
static StringSetting save_ext;
} path;
extern struct SNES {
static Setting gamma_ramp, sepia, grayscale, invert, contrast, brightness, gamma;
static Setting ntsc_merge_fields;
static Setting mute;
static Setting controller_port0;
static Setting controller_port1;
static IntegerSetting gamma_ramp, sepia, grayscale, invert, contrast, brightness, gamma;
static IntegerSetting ntsc_merge_fields;
static IntegerSetting mute;
static IntegerSetting controller_port0;
static IntegerSetting controller_port1;
} snes;
extern struct CPU {
static Setting ntsc_clock_rate, pal_clock_rate;
static Setting hdma_enable;
static IntegerSetting ntsc_clock_rate, pal_clock_rate;
static IntegerSetting hdma_enable;
} cpu;
extern struct SMP {
static Setting ntsc_clock_rate, pal_clock_rate;
static IntegerSetting ntsc_clock_rate, pal_clock_rate;
} smp;
extern struct PPU {
struct Hack {
static Setting render_scanline_position;
static Setting obj_cache;
static IntegerSetting render_scanline_position;
static IntegerSetting obj_cache;
static IntegerSetting oam_address_invalidation;
static IntegerSetting cgram_address_invalidation;
} hack;
static Setting opt_enable;
static Setting bg1_pri0_enable, bg1_pri1_enable;
static Setting bg2_pri0_enable, bg2_pri1_enable;
static Setting bg3_pri0_enable, bg3_pri1_enable;
static Setting bg4_pri0_enable, bg4_pri1_enable;
static Setting oam_pri0_enable, oam_pri1_enable;
static Setting oam_pri2_enable, oam_pri3_enable;
static IntegerSetting opt_enable;
static IntegerSetting bg1_pri0_enable, bg1_pri1_enable;
static IntegerSetting bg2_pri0_enable, bg2_pri1_enable;
static IntegerSetting bg3_pri0_enable, bg3_pri1_enable;
static IntegerSetting bg4_pri0_enable, bg4_pri1_enable;
static IntegerSetting oam_pri0_enable, oam_pri1_enable;
static IntegerSetting oam_pri2_enable, oam_pri3_enable;
} ppu;
};

View File

@@ -3,7 +3,7 @@ public:
union {
uint8 data;
struct {
uint8 order_msb8(n:1, v:1, m:1, x:1, d:1, i:1, z:1, c:1);
bool order_msb8(n:1, v:1, m:1, x:1, d:1, i:1, z:1, c:1);
};
};

View File

@@ -1,33 +1,31 @@
#include "opfn.cpp"
void sCPU::enter() {
for(;;) {
if(event.irq) {
event.irq = false;
if(status.nmi_pending == true) {
status.nmi_pending = false;
event.irq_vector = (regs.e == false) ? 0xffea : 0xfffa;
} else if(status.irq_pending == true) {
status.irq_pending = false;
event.irq_vector = (regs.e == false) ? 0xffee : 0xfffe;
}
op_irq();
#include "op_read.cpp"
#include "op_write.cpp"
#include "op_rmw.cpp"
#include "op_pc.cpp"
#include "op_misc.cpp"
void sCPU::enter() { loop:
if(event.irq) {
event.irq = false;
if(status.nmi_pending == true) {
status.nmi_pending = false;
event.irq_vector = (regs.e == false) ? 0xffea : 0xfffa;
} else if(status.irq_pending == true) {
status.irq_pending = false;
event.irq_vector = (regs.e == false) ? 0xffee : 0xfffe;
}
tracer.trace_cpuop(); //traces CPU opcode (only if tracer is enabled)
status.in_opcode = true;
switch(op_readpc()) {
#include "op_read.cpp"
#include "op_write.cpp"
#include "op_rmw.cpp"
#include "op_pc.cpp"
#include "op_misc.cpp"
}
status.in_opcode = false;
op_irq();
}
tracer.trace_cpuop(); //traces CPU opcode (only if tracer is enabled)
status.in_opcode = true;
(this->*optbl[op_readpc()])();
status.in_opcode = false;
goto loop;
}
void sCPU::op_irq() {

View File

@@ -1,4 +1,4 @@
//void (sCPU::*optbl[256])();
void (sCPU::*optbl[256])();
CPUReg24 aa, rd;
uint8 dp, sp;
@@ -54,4 +54,4 @@ uint8 dp, sp;
void op_io_cond4(uint16 x, uint16 y);
void op_io_cond6(uint16 addr);
//#include "op.h"
#include "op.h"

256
src/cpu/scpu/core/op.h Normal file
View File

@@ -0,0 +1,256 @@
void op_adc_const();
void op_and_const();
void op_cmp_const();
void op_cpx_const();
void op_cpy_const();
void op_eor_const();
void op_lda_const();
void op_ldx_const();
void op_ldy_const();
void op_ora_const();
void op_sbc_const();
void op_adc_addr();
void op_and_addr();
void op_bit_addr();
void op_cmp_addr();
void op_cpx_addr();
void op_cpy_addr();
void op_eor_addr();
void op_lda_addr();
void op_ldx_addr();
void op_ldy_addr();
void op_ora_addr();
void op_sbc_addr();
void op_adc_addrx();
void op_and_addrx();
void op_bit_addrx();
void op_cmp_addrx();
void op_eor_addrx();
void op_lda_addrx();
void op_ldy_addrx();
void op_ora_addrx();
void op_sbc_addrx();
void op_adc_addry();
void op_and_addry();
void op_cmp_addry();
void op_eor_addry();
void op_lda_addry();
void op_ldx_addry();
void op_ora_addry();
void op_sbc_addry();
void op_adc_long();
void op_and_long();
void op_cmp_long();
void op_eor_long();
void op_lda_long();
void op_ora_long();
void op_sbc_long();
void op_adc_longx();
void op_and_longx();
void op_cmp_longx();
void op_eor_longx();
void op_lda_longx();
void op_ora_longx();
void op_sbc_longx();
void op_adc_dp();
void op_and_dp();
void op_bit_dp();
void op_cmp_dp();
void op_cpx_dp();
void op_cpy_dp();
void op_eor_dp();
void op_lda_dp();
void op_ldx_dp();
void op_ldy_dp();
void op_ora_dp();
void op_sbc_dp();
void op_adc_dpx();
void op_and_dpx();
void op_bit_dpx();
void op_cmp_dpx();
void op_eor_dpx();
void op_lda_dpx();
void op_ldy_dpx();
void op_ora_dpx();
void op_sbc_dpx();
void op_ldx_dpy();
void op_adc_idp();
void op_and_idp();
void op_cmp_idp();
void op_eor_idp();
void op_lda_idp();
void op_ora_idp();
void op_sbc_idp();
void op_adc_idpx();
void op_and_idpx();
void op_cmp_idpx();
void op_eor_idpx();
void op_lda_idpx();
void op_ora_idpx();
void op_sbc_idpx();
void op_adc_idpy();
void op_and_idpy();
void op_cmp_idpy();
void op_eor_idpy();
void op_lda_idpy();
void op_ora_idpy();
void op_sbc_idpy();
void op_adc_ildp();
void op_and_ildp();
void op_cmp_ildp();
void op_eor_ildp();
void op_lda_ildp();
void op_ora_ildp();
void op_sbc_ildp();
void op_adc_ildpy();
void op_and_ildpy();
void op_cmp_ildpy();
void op_eor_ildpy();
void op_lda_ildpy();
void op_ora_ildpy();
void op_sbc_ildpy();
void op_adc_sr();
void op_and_sr();
void op_cmp_sr();
void op_eor_sr();
void op_lda_sr();
void op_ora_sr();
void op_sbc_sr();
void op_adc_isry();
void op_and_isry();
void op_cmp_isry();
void op_eor_isry();
void op_lda_isry();
void op_ora_isry();
void op_sbc_isry();
void op_bit_const();
void op_sta_addr();
void op_stx_addr();
void op_sty_addr();
void op_stz_addr();
void op_sta_addrx();
void op_stz_addrx();
void op_sta_addry();
void op_sta_long();
void op_sta_longx();
void op_sta_dp();
void op_stx_dp();
void op_sty_dp();
void op_stz_dp();
void op_sta_dpx();
void op_sty_dpx();
void op_stz_dpx();
void op_stx_dpy();
void op_sta_idp();
void op_sta_ildp();
void op_sta_idpx();
void op_sta_idpy();
void op_sta_ildpy();
void op_sta_sr();
void op_sta_isry();
void op_inc();
void op_inx();
void op_iny();
void op_dec();
void op_dex();
void op_dey();
void op_asl();
void op_lsr();
void op_rol();
void op_ror();
void op_inc_addr();
void op_dec_addr();
void op_asl_addr();
void op_lsr_addr();
void op_rol_addr();
void op_ror_addr();
void op_trb_addr();
void op_tsb_addr();
void op_inc_addrx();
void op_dec_addrx();
void op_asl_addrx();
void op_lsr_addrx();
void op_rol_addrx();
void op_ror_addrx();
void op_inc_dp();
void op_dec_dp();
void op_asl_dp();
void op_lsr_dp();
void op_rol_dp();
void op_ror_dp();
void op_trb_dp();
void op_tsb_dp();
void op_inc_dpx();
void op_dec_dpx();
void op_asl_dpx();
void op_lsr_dpx();
void op_rol_dpx();
void op_ror_dpx();
void op_bcc();
void op_bcs();
void op_bne();
void op_beq();
void op_bpl();
void op_bmi();
void op_bvc();
void op_bvs();
void op_bra();
void op_brl();
void op_jmp_addr();
void op_jmp_long();
void op_jmp_iaddr();
void op_jmp_iaddrx();
void op_jmp_iladdr();
void op_jsr_addr();
void op_jsr_long();
void op_jsr_iaddrx();
void op_rti();
void op_rts();
void op_rtl();
void op_nop();
void op_wdm();
void op_xba();
void op_mvn();
void op_mvp();
void op_brk();
void op_cop();
void op_stp();
void op_wai();
void op_xce();
void op_clc();
void op_cld();
void op_cli();
void op_clv();
void op_sec();
void op_sed();
void op_sei();
void op_rep();
void op_sep();
void op_tax();
void op_tay();
void op_txa();
void op_txy();
void op_tya();
void op_tyx();
void op_tcd();
void op_tcs();
void op_tdc();
void op_tsc();
void op_tsx();
void op_txs();
void op_pha();
void op_phx();
void op_phy();
void op_phd();
void op_phb();
void op_phk();
void op_php();
void op_pla();
void op_plx();
void op_ply();
void op_pld();
void op_plb();
void op_plp();
void op_pea();
void op_pei();
void op_per();

View File

@@ -62,14 +62,14 @@ stp(0xdb) {
}
wai(0xcb) {
1:op_io();
event.wai = true;
2:last_cycle();
op_io();
3:while(event.wai) {
//last_cycle() will set event.wai to false
//once an NMI / IRQ edge is reached
1:event.wai = true;
while(event.wai) {
last_cycle();
op_io();
}
2:op_io();
}
xce(0xfb) {

View File

@@ -1,17 +1,14 @@
//nop
case 0xea: {
void sCPU::op_nop() {
last_cycle();
op_io();
} break;
}
//wdm
case 0x42: {
void sCPU::op_wdm() {
last_cycle();
op_readpc();
} break;
}
//xba
case 0xeb: {
void sCPU::op_xba() {
op_io();
last_cycle();
op_io();
@@ -20,10 +17,9 @@ case 0xeb: {
regs.a.l ^= regs.a.h;
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} break;
}
//mvn
case 0x54: {
void sCPU::op_mvn() {
dp = op_readpc();
sp = op_readpc();
regs.db = dp;
@@ -40,10 +36,9 @@ case 0x54: {
last_cycle();
op_io();
if(regs.a.w--)regs.pc.w -= 3;
} break;
}
//mvp
case 0x44: {
void sCPU::op_mvp() {
dp = op_readpc();
sp = op_readpc();
regs.db = dp;
@@ -60,10 +55,9 @@ case 0x44: {
last_cycle();
op_io();
if(regs.a.w--)regs.pc.w -= 3;
} break;
}
//brk
case 0x00: {
void sCPU::op_brk() {
op_readpc();
if(!regs.e)op_writestack(regs.pc.b);
op_writestack(regs.pc.h);
@@ -76,10 +70,9 @@ case 0x00: {
last_cycle();
rd.h = op_readlong((regs.e) ? 0xffff : 0xffe7);
regs.pc.w = rd.w;
} break;
}
//cop
case 0x02: {
void sCPU::op_cop() {
op_readpc();
if(!regs.e)op_writestack(regs.pc.b);
op_writestack(regs.pc.h);
@@ -92,29 +85,26 @@ case 0x02: {
last_cycle();
rd.h = op_readlong((regs.e) ? 0xfff5 : 0xffe5);
regs.pc.w = rd.w;
} break;
}
//stp
case 0xdb: {
void sCPU::op_stp() {
op_io();
last_cycle();
while(1) { op_io(); }
} break;
}
//wai
case 0xcb: {
op_io();
void sCPU::op_wai() {
//last_cycle() will set event.wai to false
//once an NMI / IRQ edge is reached
event.wai = true;
last_cycle();
op_io();
while(event.wai) {
last_cycle();
op_io();
}
} break;
op_io();
}
//xce
case 0xfb: {
void sCPU::op_xce() {
last_cycle();
op_io();
bool carry = regs.p.c;
@@ -128,59 +118,51 @@ bool carry = regs.p.c;
regs.x.h = 0x00;
regs.y.h = 0x00;
}
} break;
}
//clc
case 0x18: {
void sCPU::op_clc() {
last_cycle();
op_io();
regs.p.c = 0;
} break;
}
//cld
case 0xd8: {
void sCPU::op_cld() {
last_cycle();
op_io();
regs.p.d = 0;
} break;
}
//cli
case 0x58: {
void sCPU::op_cli() {
last_cycle();
op_io();
regs.p.i = 0;
} break;
}
//clv
case 0xb8: {
void sCPU::op_clv() {
last_cycle();
op_io();
regs.p.v = 0;
} break;
}
//sec
case 0x38: {
void sCPU::op_sec() {
last_cycle();
op_io();
regs.p.c = 1;
} break;
}
//sed
case 0xf8: {
void sCPU::op_sed() {
last_cycle();
op_io();
regs.p.d = 1;
} break;
}
//sei
case 0x78: {
void sCPU::op_sei() {
last_cycle();
op_io();
regs.p.i = 1;
} break;
}
//rep
case 0xc2: {
void sCPU::op_rep() {
rd.l = op_readpc();
last_cycle();
op_io();
@@ -190,10 +172,9 @@ case 0xc2: {
regs.x.h = 0x00;
regs.y.h = 0x00;
}
} break;
}
//sep
case 0xe2: {
void sCPU::op_sep() {
rd.l = op_readpc();
last_cycle();
op_io();
@@ -203,10 +184,9 @@ case 0xe2: {
regs.x.h = 0x00;
regs.y.h = 0x00;
}
} break;
}
//tax
case 0xaa: {
void sCPU::op_tax() {
last_cycle();
op_io();
if(regs.p.x) {
@@ -218,10 +198,9 @@ case 0xaa: {
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
}
} break;
}
//tay
case 0xa8: {
void sCPU::op_tay() {
last_cycle();
op_io();
if(regs.p.x) {
@@ -233,10 +212,9 @@ case 0xa8: {
regs.p.n = !!(regs.y.w & 0x8000);
regs.p.z = (regs.y.w == 0);
}
} break;
}
//txa
case 0x8a: {
void sCPU::op_txa() {
last_cycle();
op_io();
if(regs.p.m) {
@@ -248,10 +226,9 @@ case 0x8a: {
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
} break;
}
//txy
case 0x9b: {
void sCPU::op_txy() {
last_cycle();
op_io();
if(regs.p.x) {
@@ -263,10 +240,9 @@ case 0x9b: {
regs.p.n = !!(regs.y.w & 0x8000);
regs.p.z = (regs.y.w == 0);
}
} break;
}
//tya
case 0x98: {
void sCPU::op_tya() {
last_cycle();
op_io();
if(regs.p.m) {
@@ -278,10 +254,9 @@ case 0x98: {
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
} break;
}
//tyx
case 0xbb: {
void sCPU::op_tyx() {
last_cycle();
op_io();
if(regs.p.x) {
@@ -293,36 +268,32 @@ case 0xbb: {
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
}
} break;
}
//tcd
case 0x5b: {
void sCPU::op_tcd() {
last_cycle();
op_io();
regs.d.w = regs.a.w;
regs.p.n = !!(regs.d.w & 0x8000);
regs.p.z = (regs.d.w == 0);
} break;
}
//tcs
case 0x1b: {
void sCPU::op_tcs() {
last_cycle();
op_io();
regs.s.w = regs.a.w;
if(regs.e)regs.s.h = 0x01;
} break;
}
//tdc
case 0x7b: {
void sCPU::op_tdc() {
last_cycle();
op_io();
regs.a.w = regs.d.w;
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
} break;
}
//tsc
case 0x3b: {
void sCPU::op_tsc() {
last_cycle();
op_io();
regs.a.w = regs.s.w;
@@ -333,10 +304,9 @@ case 0x3b: {
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
} break;
}
//tsx
case 0xba: {
void sCPU::op_tsx() {
last_cycle();
op_io();
if(regs.p.x) {
@@ -348,10 +318,9 @@ case 0xba: {
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
}
} break;
}
//txs
case 0x9a: {
void sCPU::op_txs() {
last_cycle();
op_io();
if(regs.e) {
@@ -359,64 +328,56 @@ case 0x9a: {
} else {
regs.s.w = regs.x.w;
}
} break;
}
//pha
case 0x48: {
void sCPU::op_pha() {
op_io();
if(!regs.p.m)op_writestack(regs.a.h);
last_cycle();
op_writestack(regs.a.l);
} break;
}
//phx
case 0xda: {
void sCPU::op_phx() {
op_io();
if(!regs.p.x)op_writestack(regs.x.h);
last_cycle();
op_writestack(regs.x.l);
} break;
}
//phy
case 0x5a: {
void sCPU::op_phy() {
op_io();
if(!regs.p.x)op_writestack(regs.y.h);
last_cycle();
op_writestack(regs.y.l);
} break;
}
//phd
case 0x0b: {
void sCPU::op_phd() {
op_io();
op_writestackn(regs.d.h);
last_cycle();
op_writestackn(regs.d.l);
if(regs.e)regs.s.h = 0x01;
} break;
}
//phb
case 0x8b: {
void sCPU::op_phb() {
op_io();
last_cycle();
op_writestack(regs.db);
} break;
}
//phk
case 0x4b: {
void sCPU::op_phk() {
op_io();
last_cycle();
op_writestack(regs.pc.b);
} break;
}
//php
case 0x08: {
void sCPU::op_php() {
op_io();
last_cycle();
op_writestack(regs.p);
} break;
}
//pla
case 0x68: {
void sCPU::op_pla() {
op_io();
op_io();
if(regs.p.m)last_cycle();
@@ -424,16 +385,15 @@ case 0x68: {
if(regs.p.m) {
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
break;
return;
}
last_cycle();
regs.a.h = op_readstack();
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
} break;
}
//plx
case 0xfa: {
void sCPU::op_plx() {
op_io();
op_io();
if(regs.p.x)last_cycle();
@@ -441,16 +401,15 @@ case 0xfa: {
if(regs.p.x) {
regs.p.n = !!(regs.x.l & 0x80);
regs.p.z = (regs.x.l == 0);
break;
return;
}
last_cycle();
regs.x.h = op_readstack();
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
} break;
}
//ply
case 0x7a: {
void sCPU::op_ply() {
op_io();
op_io();
if(regs.p.x)last_cycle();
@@ -458,16 +417,15 @@ case 0x7a: {
if(regs.p.x) {
regs.p.n = !!(regs.y.l & 0x80);
regs.p.z = (regs.y.l == 0);
break;
return;
}
last_cycle();
regs.y.h = op_readstack();
regs.p.n = !!(regs.y.w & 0x8000);
regs.p.z = (regs.y.w == 0);
} break;
}
//pld
case 0x2b: {
void sCPU::op_pld() {
op_io();
op_io();
regs.d.l = op_readstackn();
@@ -476,20 +434,18 @@ case 0x2b: {
regs.p.n = !!(regs.d.w & 0x8000);
regs.p.z = (regs.d.w == 0);
if(regs.e)regs.s.h = 0x01;
} break;
}
//plb
case 0xab: {
void sCPU::op_plb() {
op_io();
op_io();
last_cycle();
regs.db = op_readstack();
regs.p.n = !!(regs.db & 0x80);
regs.p.z = (regs.db == 0);
} break;
}
//plp
case 0x28: {
void sCPU::op_plp() {
op_io();
op_io();
last_cycle();
@@ -499,20 +455,18 @@ case 0x28: {
regs.x.h = 0x00;
regs.y.h = 0x00;
}
} break;
}
//pea
case 0xf4: {
void sCPU::op_pea() {
aa.l = op_readpc();
aa.h = op_readpc();
op_writestackn(aa.h);
last_cycle();
op_writestackn(aa.l);
if(regs.e)regs.s.h = 0x01;
} break;
}
//pei
case 0xd4: {
void sCPU::op_pei() {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp);
@@ -521,10 +475,9 @@ case 0xd4: {
last_cycle();
op_writestackn(aa.l);
if(regs.e)regs.s.h = 0x01;
} break;
}
//per
case 0x62: {
void sCPU::op_per() {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
@@ -533,5 +486,5 @@ case 0x62: {
last_cycle();
op_writestackn(rd.l);
if(regs.e)regs.s.h = 0x01;
} break;
}

View File

@@ -1,171 +1,157 @@
//bcc
case 0x90: {
void sCPU::op_bcc() {
if(!!regs.p.c)last_cycle();
rd.l = op_readpc();
if(!regs.p.c) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
break;
return;
}
op_io_cond6(aa.w);
last_cycle();
op_io();
} break;
}
//bcs
case 0xb0: {
void sCPU::op_bcs() {
if(!regs.p.c)last_cycle();
rd.l = op_readpc();
if(regs.p.c) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
break;
return;
}
op_io_cond6(aa.w);
last_cycle();
op_io();
} break;
}
//bne
case 0xd0: {
void sCPU::op_bne() {
if(!!regs.p.z)last_cycle();
rd.l = op_readpc();
if(!regs.p.z) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
break;
return;
}
op_io_cond6(aa.w);
last_cycle();
op_io();
} break;
}
//beq
case 0xf0: {
void sCPU::op_beq() {
if(!regs.p.z)last_cycle();
rd.l = op_readpc();
if(regs.p.z) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
break;
return;
}
op_io_cond6(aa.w);
last_cycle();
op_io();
} break;
}
//bpl
case 0x10: {
void sCPU::op_bpl() {
if(!!regs.p.n)last_cycle();
rd.l = op_readpc();
if(!regs.p.n) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
break;
return;
}
op_io_cond6(aa.w);
last_cycle();
op_io();
} break;
}
//bmi
case 0x30: {
void sCPU::op_bmi() {
if(!regs.p.n)last_cycle();
rd.l = op_readpc();
if(regs.p.n) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
break;
return;
}
op_io_cond6(aa.w);
last_cycle();
op_io();
} break;
}
//bvc
case 0x50: {
void sCPU::op_bvc() {
if(!!regs.p.v)last_cycle();
rd.l = op_readpc();
if(!regs.p.v) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
break;
return;
}
op_io_cond6(aa.w);
last_cycle();
op_io();
} break;
}
//bvs
case 0x70: {
void sCPU::op_bvs() {
if(!regs.p.v)last_cycle();
rd.l = op_readpc();
if(regs.p.v) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
break;
return;
}
op_io_cond6(aa.w);
last_cycle();
op_io();
} break;
}
//bra
case 0x80: {
void sCPU::op_bra() {
rd.l = op_readpc();
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
op_io_cond6(aa.w);
last_cycle();
op_io();
} break;
}
//brl
case 0x82: {
void sCPU::op_brl() {
rd.l = op_readpc();
rd.h = op_readpc();
last_cycle();
op_io();
regs.pc.w = regs.pc.d + (int16)rd.w;
} break;
}
//jmp_addr
case 0x4c: {
void sCPU::op_jmp_addr() {
rd.l = op_readpc();
last_cycle();
rd.h = op_readpc();
regs.pc.w = rd.w;
} break;
}
//jmp_long
case 0x5c: {
void sCPU::op_jmp_long() {
rd.l = op_readpc();
rd.h = op_readpc();
last_cycle();
rd.b = op_readpc();
regs.pc.d = rd.d & 0xffffff;
} break;
}
//jmp_iaddr
case 0x6c: {
void sCPU::op_jmp_iaddr() {
aa.l = op_readpc();
aa.h = op_readpc();
rd.l = op_readaddr(aa.w);
last_cycle();
rd.h = op_readaddr(aa.w + 1);
regs.pc.w = rd.w;
} break;
}
//jmp_iaddrx
case 0x7c: {
void sCPU::op_jmp_iaddrx() {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
@@ -173,10 +159,9 @@ case 0x7c: {
last_cycle();
rd.h = op_readpbr(aa.w + regs.x.w + 1);
regs.pc.w = rd.w;
} break;
}
//jmp_iladdr
case 0xdc: {
void sCPU::op_jmp_iladdr() {
aa.l = op_readpc();
aa.h = op_readpc();
rd.l = op_readaddr(aa.w);
@@ -184,10 +169,9 @@ case 0xdc: {
last_cycle();
rd.b = op_readaddr(aa.w + 2);
regs.pc.d = rd.d & 0xffffff;
} break;
}
//jsr_addr
case 0x20: {
void sCPU::op_jsr_addr() {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
@@ -196,10 +180,9 @@ case 0x20: {
last_cycle();
op_writestack(regs.pc.l);
regs.pc.w = aa.w;
} break;
}
//jsr_long
case 0x22: {
void sCPU::op_jsr_long() {
aa.l = op_readpc();
aa.h = op_readpc();
op_writestackn(regs.pc.b);
@@ -211,10 +194,9 @@ case 0x22: {
op_writestackn(regs.pc.l);
regs.pc.d = aa.d & 0xffffff;
if(regs.e)regs.s.h = 0x01;
} break;
}
//jsr_iaddrx
case 0xfc: {
void sCPU::op_jsr_iaddrx() {
aa.l = op_readpc();
op_writestackn(regs.pc.h);
op_writestackn(regs.pc.l);
@@ -225,10 +207,9 @@ case 0xfc: {
rd.h = op_readpbr(aa.w + regs.x.w + 1);
regs.pc.w = rd.w;
if(regs.e)regs.s.h = 0x01;
} break;
}
//rti
case 0x40: {
void sCPU::op_rti() {
op_io();
op_io();
regs.p = op_readstack();
@@ -242,15 +223,14 @@ case 0x40: {
rd.h = op_readstack();
if(regs.e) {
regs.pc.w = rd.w;
break;
return;
}
last_cycle();
rd.b = op_readstack();
regs.pc.d = rd.d & 0xffffff;
} break;
}
//rts
case 0x60: {
void sCPU::op_rts() {
op_io();
op_io();
rd.l = op_readstack();
@@ -259,10 +239,9 @@ case 0x60: {
op_io();
regs.pc.w = rd.w;
regs.pc.w++;
} break;
}
//rtl
case 0x6b: {
void sCPU::op_rtl() {
op_io();
op_io();
rd.l = op_readstackn();
@@ -272,5 +251,5 @@ case 0x6b: {
regs.pc.d = rd.d & 0xffffff;
regs.pc.w++;
if(regs.e)regs.s.h = 0x01;
} break;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,4 @@
//inc
case 0x1a: {
void sCPU::op_inc() {
last_cycle();
op_io();
if(regs.p.m) {
@@ -11,10 +10,9 @@ case 0x1a: {
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
} break;
}
//inx
case 0xe8: {
void sCPU::op_inx() {
last_cycle();
op_io();
if(regs.p.x) {
@@ -26,10 +24,9 @@ case 0xe8: {
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
}
} break;
}
//iny
case 0xc8: {
void sCPU::op_iny() {
last_cycle();
op_io();
if(regs.p.x) {
@@ -41,10 +38,9 @@ case 0xc8: {
regs.p.n = !!(regs.y.w & 0x8000);
regs.p.z = (regs.y.w == 0);
}
} break;
}
//dec
case 0x3a: {
void sCPU::op_dec() {
last_cycle();
op_io();
if(regs.p.m) {
@@ -56,10 +52,9 @@ case 0x3a: {
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
} break;
}
//dex
case 0xca: {
void sCPU::op_dex() {
last_cycle();
op_io();
if(regs.p.x) {
@@ -71,10 +66,9 @@ case 0xca: {
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
}
} break;
}
//dey
case 0x88: {
void sCPU::op_dey() {
last_cycle();
op_io();
if(regs.p.x) {
@@ -86,10 +80,9 @@ case 0x88: {
regs.p.n = !!(regs.y.w & 0x8000);
regs.p.z = (regs.y.w == 0);
}
} break;
}
//asl
case 0x0a: {
void sCPU::op_asl() {
last_cycle();
op_io();
if(regs.p.m) {
@@ -103,10 +96,9 @@ case 0x0a: {
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
} break;
}
//lsr
case 0x4a: {
void sCPU::op_lsr() {
last_cycle();
op_io();
if(regs.p.m) {
@@ -120,10 +112,9 @@ case 0x4a: {
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
} break;
}
//rol
case 0x2a: {
void sCPU::op_rol() {
last_cycle();
op_io();
uint16 c = regs.p.c;
@@ -140,10 +131,9 @@ case 0x2a: {
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
} break;
}
//ror
case 0x6a: {
void sCPU::op_ror() {
last_cycle();
op_io();
uint16 c;
@@ -162,10 +152,9 @@ case 0x6a: {
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
} break;
}
//inc_addr
case 0xee: {
void sCPU::op_inc_addr() {
aa.l = op_readpc();
aa.h = op_readpc();
rd.l = op_readdbr(aa.w);
@@ -176,10 +165,9 @@ case 0xee: {
op_writedbr(aa.w + 1, rd.h); }
last_cycle();
op_writedbr(aa.w, rd.l);
} break;
}
//dec_addr
case 0xce: {
void sCPU::op_dec_addr() {
aa.l = op_readpc();
aa.h = op_readpc();
rd.l = op_readdbr(aa.w);
@@ -190,10 +178,9 @@ case 0xce: {
op_writedbr(aa.w + 1, rd.h); }
last_cycle();
op_writedbr(aa.w, rd.l);
} break;
}
//asl_addr
case 0x0e: {
void sCPU::op_asl_addr() {
aa.l = op_readpc();
aa.h = op_readpc();
rd.l = op_readdbr(aa.w);
@@ -204,10 +191,9 @@ case 0x0e: {
op_writedbr(aa.w + 1, rd.h); }
last_cycle();
op_writedbr(aa.w, rd.l);
} break;
}
//lsr_addr
case 0x4e: {
void sCPU::op_lsr_addr() {
aa.l = op_readpc();
aa.h = op_readpc();
rd.l = op_readdbr(aa.w);
@@ -218,10 +204,9 @@ case 0x4e: {
op_writedbr(aa.w + 1, rd.h); }
last_cycle();
op_writedbr(aa.w, rd.l);
} break;
}
//rol_addr
case 0x2e: {
void sCPU::op_rol_addr() {
aa.l = op_readpc();
aa.h = op_readpc();
rd.l = op_readdbr(aa.w);
@@ -232,10 +217,9 @@ case 0x2e: {
op_writedbr(aa.w + 1, rd.h); }
last_cycle();
op_writedbr(aa.w, rd.l);
} break;
}
//ror_addr
case 0x6e: {
void sCPU::op_ror_addr() {
aa.l = op_readpc();
aa.h = op_readpc();
rd.l = op_readdbr(aa.w);
@@ -246,10 +230,9 @@ case 0x6e: {
op_writedbr(aa.w + 1, rd.h); }
last_cycle();
op_writedbr(aa.w, rd.l);
} break;
}
//trb_addr
case 0x1c: {
void sCPU::op_trb_addr() {
aa.l = op_readpc();
aa.h = op_readpc();
rd.l = op_readdbr(aa.w);
@@ -260,10 +243,9 @@ case 0x1c: {
op_writedbr(aa.w + 1, rd.h); }
last_cycle();
op_writedbr(aa.w, rd.l);
} break;
}
//tsb_addr
case 0x0c: {
void sCPU::op_tsb_addr() {
aa.l = op_readpc();
aa.h = op_readpc();
rd.l = op_readdbr(aa.w);
@@ -274,10 +256,9 @@ case 0x0c: {
op_writedbr(aa.w + 1, rd.h); }
last_cycle();
op_writedbr(aa.w, rd.l);
} break;
}
//inc_addrx
case 0xfe: {
void sCPU::op_inc_addrx() {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
@@ -289,10 +270,9 @@ case 0xfe: {
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
last_cycle();
op_writedbr(aa.w + regs.x.w, rd.l);
} break;
}
//dec_addrx
case 0xde: {
void sCPU::op_dec_addrx() {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
@@ -304,10 +284,9 @@ case 0xde: {
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
last_cycle();
op_writedbr(aa.w + regs.x.w, rd.l);
} break;
}
//asl_addrx
case 0x1e: {
void sCPU::op_asl_addrx() {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
@@ -319,10 +298,9 @@ case 0x1e: {
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
last_cycle();
op_writedbr(aa.w + regs.x.w, rd.l);
} break;
}
//lsr_addrx
case 0x5e: {
void sCPU::op_lsr_addrx() {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
@@ -334,10 +312,9 @@ case 0x5e: {
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
last_cycle();
op_writedbr(aa.w + regs.x.w, rd.l);
} break;
}
//rol_addrx
case 0x3e: {
void sCPU::op_rol_addrx() {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
@@ -349,10 +326,9 @@ case 0x3e: {
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
last_cycle();
op_writedbr(aa.w + regs.x.w, rd.l);
} break;
}
//ror_addrx
case 0x7e: {
void sCPU::op_ror_addrx() {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
@@ -364,10 +340,9 @@ case 0x7e: {
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
last_cycle();
op_writedbr(aa.w + regs.x.w, rd.l);
} break;
}
//inc_dp
case 0xe6: {
void sCPU::op_inc_dp() {
dp = op_readpc();
op_io_cond2();
rd.l = op_readdp(dp);
@@ -378,10 +353,9 @@ case 0xe6: {
op_writedp(dp + 1, rd.h); }
last_cycle();
op_writedp(dp, rd.l);
} break;
}
//dec_dp
case 0xc6: {
void sCPU::op_dec_dp() {
dp = op_readpc();
op_io_cond2();
rd.l = op_readdp(dp);
@@ -392,10 +366,9 @@ case 0xc6: {
op_writedp(dp + 1, rd.h); }
last_cycle();
op_writedp(dp, rd.l);
} break;
}
//asl_dp
case 0x06: {
void sCPU::op_asl_dp() {
dp = op_readpc();
op_io_cond2();
rd.l = op_readdp(dp);
@@ -406,10 +379,9 @@ case 0x06: {
op_writedp(dp + 1, rd.h); }
last_cycle();
op_writedp(dp, rd.l);
} break;
}
//lsr_dp
case 0x46: {
void sCPU::op_lsr_dp() {
dp = op_readpc();
op_io_cond2();
rd.l = op_readdp(dp);
@@ -420,10 +392,9 @@ case 0x46: {
op_writedp(dp + 1, rd.h); }
last_cycle();
op_writedp(dp, rd.l);
} break;
}
//rol_dp
case 0x26: {
void sCPU::op_rol_dp() {
dp = op_readpc();
op_io_cond2();
rd.l = op_readdp(dp);
@@ -434,10 +405,9 @@ case 0x26: {
op_writedp(dp + 1, rd.h); }
last_cycle();
op_writedp(dp, rd.l);
} break;
}
//ror_dp
case 0x66: {
void sCPU::op_ror_dp() {
dp = op_readpc();
op_io_cond2();
rd.l = op_readdp(dp);
@@ -448,10 +418,9 @@ case 0x66: {
op_writedp(dp + 1, rd.h); }
last_cycle();
op_writedp(dp, rd.l);
} break;
}
//trb_dp
case 0x14: {
void sCPU::op_trb_dp() {
dp = op_readpc();
op_io_cond2();
rd.l = op_readdp(dp);
@@ -462,10 +431,9 @@ case 0x14: {
op_writedp(dp + 1, rd.h); }
last_cycle();
op_writedp(dp, rd.l);
} break;
}
//tsb_dp
case 0x04: {
void sCPU::op_tsb_dp() {
dp = op_readpc();
op_io_cond2();
rd.l = op_readdp(dp);
@@ -476,10 +444,9 @@ case 0x04: {
op_writedp(dp + 1, rd.h); }
last_cycle();
op_writedp(dp, rd.l);
} break;
}
//inc_dpx
case 0xf6: {
void sCPU::op_inc_dpx() {
dp = op_readpc();
op_io_cond2();
op_io();
@@ -491,10 +458,9 @@ case 0xf6: {
op_writedp(dp + regs.x.w + 1, rd.h); }
last_cycle();
op_writedp(dp + regs.x.w, rd.l);
} break;
}
//dec_dpx
case 0xd6: {
void sCPU::op_dec_dpx() {
dp = op_readpc();
op_io_cond2();
op_io();
@@ -506,10 +472,9 @@ case 0xd6: {
op_writedp(dp + regs.x.w + 1, rd.h); }
last_cycle();
op_writedp(dp + regs.x.w, rd.l);
} break;
}
//asl_dpx
case 0x16: {
void sCPU::op_asl_dpx() {
dp = op_readpc();
op_io_cond2();
op_io();
@@ -521,10 +486,9 @@ case 0x16: {
op_writedp(dp + regs.x.w + 1, rd.h); }
last_cycle();
op_writedp(dp + regs.x.w, rd.l);
} break;
}
//lsr_dpx
case 0x56: {
void sCPU::op_lsr_dpx() {
dp = op_readpc();
op_io_cond2();
op_io();
@@ -536,10 +500,9 @@ case 0x56: {
op_writedp(dp + regs.x.w + 1, rd.h); }
last_cycle();
op_writedp(dp + regs.x.w, rd.l);
} break;
}
//rol_dpx
case 0x36: {
void sCPU::op_rol_dpx() {
dp = op_readpc();
op_io_cond2();
op_io();
@@ -551,10 +514,9 @@ case 0x36: {
op_writedp(dp + regs.x.w + 1, rd.h); }
last_cycle();
op_writedp(dp + regs.x.w, rd.l);
} break;
}
//ror_dpx
case 0x76: {
void sCPU::op_ror_dpx() {
dp = op_readpc();
op_io_cond2();
op_io();
@@ -566,5 +528,5 @@ case 0x76: {
op_writedp(dp + regs.x.w + 1, rd.h); }
last_cycle();
op_writedp(dp + regs.x.w, rd.l);
} break;
}

View File

@@ -1,214 +1,195 @@
//sta_addr
case 0x8d: {
void sCPU::op_sta_addr() {
aa.l = op_readpc();
aa.h = op_readpc();
if(regs.p.m)last_cycle();
op_writedbr(aa.w, regs.a.w);
if(regs.p.m)break;
if(regs.p.m)return;
last_cycle();
op_writedbr(aa.w + 1, regs.a.w >> 8);
} break;
}
//stx_addr
case 0x8e: {
void sCPU::op_stx_addr() {
aa.l = op_readpc();
aa.h = op_readpc();
if(regs.p.x)last_cycle();
op_writedbr(aa.w, regs.x.w);
if(regs.p.x)break;
if(regs.p.x)return;
last_cycle();
op_writedbr(aa.w + 1, regs.x.w >> 8);
} break;
}
//sty_addr
case 0x8c: {
void sCPU::op_sty_addr() {
aa.l = op_readpc();
aa.h = op_readpc();
if(regs.p.x)last_cycle();
op_writedbr(aa.w, regs.y.w);
if(regs.p.x)break;
if(regs.p.x)return;
last_cycle();
op_writedbr(aa.w + 1, regs.y.w >> 8);
} break;
}
//stz_addr
case 0x9c: {
void sCPU::op_stz_addr() {
aa.l = op_readpc();
aa.h = op_readpc();
if(regs.p.m)last_cycle();
op_writedbr(aa.w, 0x0000);
if(regs.p.m)break;
if(regs.p.m)return;
last_cycle();
op_writedbr(aa.w + 1, 0x0000 >> 8);
} break;
}
//sta_addrx
case 0x9d: {
void sCPU::op_sta_addrx() {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
if(regs.p.m)last_cycle();
op_writedbr(aa.w + regs.x.w, regs.a.w);
if(regs.p.m)break;
if(regs.p.m)return;
last_cycle();
op_writedbr(aa.w + regs.x.w + 1, regs.a.w >> 8);
} break;
}
//stz_addrx
case 0x9e: {
void sCPU::op_stz_addrx() {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
if(regs.p.m)last_cycle();
op_writedbr(aa.w + regs.x.w, 0x0000);
if(regs.p.m)break;
if(regs.p.m)return;
last_cycle();
op_writedbr(aa.w + regs.x.w + 1, 0x0000 >> 8);
} break;
}
//sta_addry
case 0x99: {
void sCPU::op_sta_addry() {
aa.l = op_readpc();
aa.h = op_readpc();
op_io();
if(regs.p.m)last_cycle();
op_writedbr(aa.w + regs.y.w, regs.a.l);
if(regs.p.m)break;
if(regs.p.m)return;
last_cycle();
op_writedbr(aa.w + regs.y.w + 1, regs.a.h);
} break;
}
//sta_long
case 0x8f: {
void sCPU::op_sta_long() {
aa.l = op_readpc();
aa.h = op_readpc();
aa.b = op_readpc();
if(regs.p.m)last_cycle();
op_writelong(aa.d, regs.a.l);
if(regs.p.m)break;
if(regs.p.m)return;
last_cycle();
op_writelong(aa.d + 1, regs.a.h);
} break;
}
//sta_longx
case 0x9f: {
void sCPU::op_sta_longx() {
aa.l = op_readpc();
aa.h = op_readpc();
aa.b = op_readpc();
if(regs.p.m)last_cycle();
op_writelong(aa.d + regs.x.w, regs.a.l);
if(regs.p.m)break;
if(regs.p.m)return;
last_cycle();
op_writelong(aa.d + regs.x.w + 1, regs.a.h);
} break;
}
//sta_dp
case 0x85: {
void sCPU::op_sta_dp() {
dp = op_readpc();
op_io_cond2();
if(regs.p.m)last_cycle();
op_writedp(dp, regs.a.w);
if(regs.p.m)break;
if(regs.p.m)return;
last_cycle();
op_writedp(dp + 1, regs.a.w >> 8);
} break;
}
//stx_dp
case 0x86: {
void sCPU::op_stx_dp() {
dp = op_readpc();
op_io_cond2();
if(regs.p.x)last_cycle();
op_writedp(dp, regs.x.w);
if(regs.p.x)break;
if(regs.p.x)return;
last_cycle();
op_writedp(dp + 1, regs.x.w >> 8);
} break;
}
//sty_dp
case 0x84: {
void sCPU::op_sty_dp() {
dp = op_readpc();
op_io_cond2();
if(regs.p.x)last_cycle();
op_writedp(dp, regs.y.w);
if(regs.p.x)break;
if(regs.p.x)return;
last_cycle();
op_writedp(dp + 1, regs.y.w >> 8);
} break;
}
//stz_dp
case 0x64: {
void sCPU::op_stz_dp() {
dp = op_readpc();
op_io_cond2();
if(regs.p.m)last_cycle();
op_writedp(dp, 0x0000);
if(regs.p.m)break;
if(regs.p.m)return;
last_cycle();
op_writedp(dp + 1, 0x0000 >> 8);
} break;
}
//sta_dpx
case 0x95: {
void sCPU::op_sta_dpx() {
dp = op_readpc();
op_io_cond2();
op_io();
if(regs.p.m)last_cycle();
op_writedp(dp + regs.x.w, regs.a.w);
if(regs.p.m)break;
if(regs.p.m)return;
last_cycle();
op_writedp(dp + regs.x.w + 1, regs.a.w >> 8);
} break;
}
//sty_dpx
case 0x94: {
void sCPU::op_sty_dpx() {
dp = op_readpc();
op_io_cond2();
op_io();
if(regs.p.x)last_cycle();
op_writedp(dp + regs.x.w, regs.y.w);
if(regs.p.x)break;
if(regs.p.x)return;
last_cycle();
op_writedp(dp + regs.x.w + 1, regs.y.w >> 8);
} break;
}
//stz_dpx
case 0x74: {
void sCPU::op_stz_dpx() {
dp = op_readpc();
op_io_cond2();
op_io();
if(regs.p.m)last_cycle();
op_writedp(dp + regs.x.w, 0x0000);
if(regs.p.m)break;
if(regs.p.m)return;
last_cycle();
op_writedp(dp + regs.x.w + 1, 0x0000 >> 8);
} break;
}
//stx_dpy
case 0x96: {
void sCPU::op_stx_dpy() {
dp = op_readpc();
op_io_cond2();
op_io();
if(regs.p.x)last_cycle();
op_writedp(dp + regs.y.w, regs.x.l);
if(regs.p.x)break;
if(regs.p.x)return;
last_cycle();
op_writedp(dp + regs.y.w + 1, regs.x.h);
} break;
}
//sta_idp
case 0x92: {
void sCPU::op_sta_idp() {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp);
aa.h = op_readdp(dp + 1);
if(regs.p.m)last_cycle();
op_writedbr(aa.w, regs.a.l);
if(regs.p.m)break;
if(regs.p.m)return;
last_cycle();
op_writedbr(aa.w + 1, regs.a.h);
} break;
}
//sta_ildp
case 0x87: {
void sCPU::op_sta_ildp() {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp);
@@ -216,13 +197,12 @@ case 0x87: {
aa.b = op_readdp(dp + 2);
if(regs.p.m)last_cycle();
op_writelong(aa.d, regs.a.l);
if(regs.p.m)break;
if(regs.p.m)return;
last_cycle();
op_writelong(aa.d + 1, regs.a.h);
} break;
}
//sta_idpx
case 0x81: {
void sCPU::op_sta_idpx() {
dp = op_readpc();
op_io_cond2();
op_io();
@@ -230,13 +210,12 @@ case 0x81: {
aa.h = op_readdp(dp + regs.x.w + 1);
if(regs.p.m)last_cycle();
op_writedbr(aa.w, regs.a.l);
if(regs.p.m)break;
if(regs.p.m)return;
last_cycle();
op_writedbr(aa.w + 1, regs.a.h);
} break;
}
//sta_idpy
case 0x91: {
void sCPU::op_sta_idpy() {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp);
@@ -244,13 +223,12 @@ case 0x91: {
op_io();
if(regs.p.m)last_cycle();
op_writedbr(aa.w + regs.y.w, regs.a.l);
if(regs.p.m)break;
if(regs.p.m)return;
last_cycle();
op_writedbr(aa.w + regs.y.w + 1, regs.a.h);
} break;
}
//sta_ildpy
case 0x97: {
void sCPU::op_sta_ildpy() {
dp = op_readpc();
op_io_cond2();
aa.l = op_readdp(dp);
@@ -258,24 +236,22 @@ case 0x97: {
aa.b = op_readdp(dp + 2);
if(regs.p.m)last_cycle();
op_writelong(aa.d + regs.y.w, regs.a.l);
if(regs.p.m)break;
if(regs.p.m)return;
last_cycle();
op_writelong(aa.d + regs.y.w + 1, regs.a.h);
} break;
}
//sta_sr
case 0x83: {
void sCPU::op_sta_sr() {
sp = op_readpc();
op_io();
if(regs.p.m)last_cycle();
op_writesp(sp, regs.a.l);
if(regs.p.m)break;
if(regs.p.m)return;
last_cycle();
op_writesp(sp + 1, regs.a.h);
} break;
}
//sta_isry
case 0x93: {
void sCPU::op_sta_isry() {
sp = op_readpc();
op_io();
aa.l = op_readsp(sp);
@@ -283,8 +259,8 @@ case 0x93: {
op_io();
if(regs.p.m)last_cycle();
op_writedbr(aa.w + regs.y.w, regs.a.l);
if(regs.p.m)break;
if(regs.p.m)return;
last_cycle();
op_writedbr(aa.w + regs.y.w + 1, regs.a.h);
} break;
}

View File

@@ -0,0 +1,256 @@
optbl[0x69] = &sCPU::op_adc_const;
optbl[0x29] = &sCPU::op_and_const;
optbl[0xc9] = &sCPU::op_cmp_const;
optbl[0xe0] = &sCPU::op_cpx_const;
optbl[0xc0] = &sCPU::op_cpy_const;
optbl[0x49] = &sCPU::op_eor_const;
optbl[0xa9] = &sCPU::op_lda_const;
optbl[0xa2] = &sCPU::op_ldx_const;
optbl[0xa0] = &sCPU::op_ldy_const;
optbl[0x09] = &sCPU::op_ora_const;
optbl[0xe9] = &sCPU::op_sbc_const;
optbl[0x6d] = &sCPU::op_adc_addr;
optbl[0x2d] = &sCPU::op_and_addr;
optbl[0x2c] = &sCPU::op_bit_addr;
optbl[0xcd] = &sCPU::op_cmp_addr;
optbl[0xec] = &sCPU::op_cpx_addr;
optbl[0xcc] = &sCPU::op_cpy_addr;
optbl[0x4d] = &sCPU::op_eor_addr;
optbl[0xad] = &sCPU::op_lda_addr;
optbl[0xae] = &sCPU::op_ldx_addr;
optbl[0xac] = &sCPU::op_ldy_addr;
optbl[0x0d] = &sCPU::op_ora_addr;
optbl[0xed] = &sCPU::op_sbc_addr;
optbl[0x7d] = &sCPU::op_adc_addrx;
optbl[0x3d] = &sCPU::op_and_addrx;
optbl[0x3c] = &sCPU::op_bit_addrx;
optbl[0xdd] = &sCPU::op_cmp_addrx;
optbl[0x5d] = &sCPU::op_eor_addrx;
optbl[0xbd] = &sCPU::op_lda_addrx;
optbl[0xbc] = &sCPU::op_ldy_addrx;
optbl[0x1d] = &sCPU::op_ora_addrx;
optbl[0xfd] = &sCPU::op_sbc_addrx;
optbl[0x79] = &sCPU::op_adc_addry;
optbl[0x39] = &sCPU::op_and_addry;
optbl[0xd9] = &sCPU::op_cmp_addry;
optbl[0x59] = &sCPU::op_eor_addry;
optbl[0xb9] = &sCPU::op_lda_addry;
optbl[0xbe] = &sCPU::op_ldx_addry;
optbl[0x19] = &sCPU::op_ora_addry;
optbl[0xf9] = &sCPU::op_sbc_addry;
optbl[0x6f] = &sCPU::op_adc_long;
optbl[0x2f] = &sCPU::op_and_long;
optbl[0xcf] = &sCPU::op_cmp_long;
optbl[0x4f] = &sCPU::op_eor_long;
optbl[0xaf] = &sCPU::op_lda_long;
optbl[0x0f] = &sCPU::op_ora_long;
optbl[0xef] = &sCPU::op_sbc_long;
optbl[0x7f] = &sCPU::op_adc_longx;
optbl[0x3f] = &sCPU::op_and_longx;
optbl[0xdf] = &sCPU::op_cmp_longx;
optbl[0x5f] = &sCPU::op_eor_longx;
optbl[0xbf] = &sCPU::op_lda_longx;
optbl[0x1f] = &sCPU::op_ora_longx;
optbl[0xff] = &sCPU::op_sbc_longx;
optbl[0x65] = &sCPU::op_adc_dp;
optbl[0x25] = &sCPU::op_and_dp;
optbl[0x24] = &sCPU::op_bit_dp;
optbl[0xc5] = &sCPU::op_cmp_dp;
optbl[0xe4] = &sCPU::op_cpx_dp;
optbl[0xc4] = &sCPU::op_cpy_dp;
optbl[0x45] = &sCPU::op_eor_dp;
optbl[0xa5] = &sCPU::op_lda_dp;
optbl[0xa6] = &sCPU::op_ldx_dp;
optbl[0xa4] = &sCPU::op_ldy_dp;
optbl[0x05] = &sCPU::op_ora_dp;
optbl[0xe5] = &sCPU::op_sbc_dp;
optbl[0x75] = &sCPU::op_adc_dpx;
optbl[0x35] = &sCPU::op_and_dpx;
optbl[0x34] = &sCPU::op_bit_dpx;
optbl[0xd5] = &sCPU::op_cmp_dpx;
optbl[0x55] = &sCPU::op_eor_dpx;
optbl[0xb5] = &sCPU::op_lda_dpx;
optbl[0xb4] = &sCPU::op_ldy_dpx;
optbl[0x15] = &sCPU::op_ora_dpx;
optbl[0xf5] = &sCPU::op_sbc_dpx;
optbl[0xb6] = &sCPU::op_ldx_dpy;
optbl[0x72] = &sCPU::op_adc_idp;
optbl[0x32] = &sCPU::op_and_idp;
optbl[0xd2] = &sCPU::op_cmp_idp;
optbl[0x52] = &sCPU::op_eor_idp;
optbl[0xb2] = &sCPU::op_lda_idp;
optbl[0x12] = &sCPU::op_ora_idp;
optbl[0xf2] = &sCPU::op_sbc_idp;
optbl[0x61] = &sCPU::op_adc_idpx;
optbl[0x21] = &sCPU::op_and_idpx;
optbl[0xc1] = &sCPU::op_cmp_idpx;
optbl[0x41] = &sCPU::op_eor_idpx;
optbl[0xa1] = &sCPU::op_lda_idpx;
optbl[0x01] = &sCPU::op_ora_idpx;
optbl[0xe1] = &sCPU::op_sbc_idpx;
optbl[0x71] = &sCPU::op_adc_idpy;
optbl[0x31] = &sCPU::op_and_idpy;
optbl[0xd1] = &sCPU::op_cmp_idpy;
optbl[0x51] = &sCPU::op_eor_idpy;
optbl[0xb1] = &sCPU::op_lda_idpy;
optbl[0x11] = &sCPU::op_ora_idpy;
optbl[0xf1] = &sCPU::op_sbc_idpy;
optbl[0x67] = &sCPU::op_adc_ildp;
optbl[0x27] = &sCPU::op_and_ildp;
optbl[0xc7] = &sCPU::op_cmp_ildp;
optbl[0x47] = &sCPU::op_eor_ildp;
optbl[0xa7] = &sCPU::op_lda_ildp;
optbl[0x07] = &sCPU::op_ora_ildp;
optbl[0xe7] = &sCPU::op_sbc_ildp;
optbl[0x77] = &sCPU::op_adc_ildpy;
optbl[0x37] = &sCPU::op_and_ildpy;
optbl[0xd7] = &sCPU::op_cmp_ildpy;
optbl[0x57] = &sCPU::op_eor_ildpy;
optbl[0xb7] = &sCPU::op_lda_ildpy;
optbl[0x17] = &sCPU::op_ora_ildpy;
optbl[0xf7] = &sCPU::op_sbc_ildpy;
optbl[0x63] = &sCPU::op_adc_sr;
optbl[0x23] = &sCPU::op_and_sr;
optbl[0xc3] = &sCPU::op_cmp_sr;
optbl[0x43] = &sCPU::op_eor_sr;
optbl[0xa3] = &sCPU::op_lda_sr;
optbl[0x03] = &sCPU::op_ora_sr;
optbl[0xe3] = &sCPU::op_sbc_sr;
optbl[0x73] = &sCPU::op_adc_isry;
optbl[0x33] = &sCPU::op_and_isry;
optbl[0xd3] = &sCPU::op_cmp_isry;
optbl[0x53] = &sCPU::op_eor_isry;
optbl[0xb3] = &sCPU::op_lda_isry;
optbl[0x13] = &sCPU::op_ora_isry;
optbl[0xf3] = &sCPU::op_sbc_isry;
optbl[0x89] = &sCPU::op_bit_const;
optbl[0x8d] = &sCPU::op_sta_addr;
optbl[0x8e] = &sCPU::op_stx_addr;
optbl[0x8c] = &sCPU::op_sty_addr;
optbl[0x9c] = &sCPU::op_stz_addr;
optbl[0x9d] = &sCPU::op_sta_addrx;
optbl[0x9e] = &sCPU::op_stz_addrx;
optbl[0x99] = &sCPU::op_sta_addry;
optbl[0x8f] = &sCPU::op_sta_long;
optbl[0x9f] = &sCPU::op_sta_longx;
optbl[0x85] = &sCPU::op_sta_dp;
optbl[0x86] = &sCPU::op_stx_dp;
optbl[0x84] = &sCPU::op_sty_dp;
optbl[0x64] = &sCPU::op_stz_dp;
optbl[0x95] = &sCPU::op_sta_dpx;
optbl[0x94] = &sCPU::op_sty_dpx;
optbl[0x74] = &sCPU::op_stz_dpx;
optbl[0x96] = &sCPU::op_stx_dpy;
optbl[0x92] = &sCPU::op_sta_idp;
optbl[0x87] = &sCPU::op_sta_ildp;
optbl[0x81] = &sCPU::op_sta_idpx;
optbl[0x91] = &sCPU::op_sta_idpy;
optbl[0x97] = &sCPU::op_sta_ildpy;
optbl[0x83] = &sCPU::op_sta_sr;
optbl[0x93] = &sCPU::op_sta_isry;
optbl[0x1a] = &sCPU::op_inc;
optbl[0xe8] = &sCPU::op_inx;
optbl[0xc8] = &sCPU::op_iny;
optbl[0x3a] = &sCPU::op_dec;
optbl[0xca] = &sCPU::op_dex;
optbl[0x88] = &sCPU::op_dey;
optbl[0x0a] = &sCPU::op_asl;
optbl[0x4a] = &sCPU::op_lsr;
optbl[0x2a] = &sCPU::op_rol;
optbl[0x6a] = &sCPU::op_ror;
optbl[0xee] = &sCPU::op_inc_addr;
optbl[0xce] = &sCPU::op_dec_addr;
optbl[0x0e] = &sCPU::op_asl_addr;
optbl[0x4e] = &sCPU::op_lsr_addr;
optbl[0x2e] = &sCPU::op_rol_addr;
optbl[0x6e] = &sCPU::op_ror_addr;
optbl[0x1c] = &sCPU::op_trb_addr;
optbl[0x0c] = &sCPU::op_tsb_addr;
optbl[0xfe] = &sCPU::op_inc_addrx;
optbl[0xde] = &sCPU::op_dec_addrx;
optbl[0x1e] = &sCPU::op_asl_addrx;
optbl[0x5e] = &sCPU::op_lsr_addrx;
optbl[0x3e] = &sCPU::op_rol_addrx;
optbl[0x7e] = &sCPU::op_ror_addrx;
optbl[0xe6] = &sCPU::op_inc_dp;
optbl[0xc6] = &sCPU::op_dec_dp;
optbl[0x06] = &sCPU::op_asl_dp;
optbl[0x46] = &sCPU::op_lsr_dp;
optbl[0x26] = &sCPU::op_rol_dp;
optbl[0x66] = &sCPU::op_ror_dp;
optbl[0x14] = &sCPU::op_trb_dp;
optbl[0x04] = &sCPU::op_tsb_dp;
optbl[0xf6] = &sCPU::op_inc_dpx;
optbl[0xd6] = &sCPU::op_dec_dpx;
optbl[0x16] = &sCPU::op_asl_dpx;
optbl[0x56] = &sCPU::op_lsr_dpx;
optbl[0x36] = &sCPU::op_rol_dpx;
optbl[0x76] = &sCPU::op_ror_dpx;
optbl[0x90] = &sCPU::op_bcc;
optbl[0xb0] = &sCPU::op_bcs;
optbl[0xd0] = &sCPU::op_bne;
optbl[0xf0] = &sCPU::op_beq;
optbl[0x10] = &sCPU::op_bpl;
optbl[0x30] = &sCPU::op_bmi;
optbl[0x50] = &sCPU::op_bvc;
optbl[0x70] = &sCPU::op_bvs;
optbl[0x80] = &sCPU::op_bra;
optbl[0x82] = &sCPU::op_brl;
optbl[0x4c] = &sCPU::op_jmp_addr;
optbl[0x5c] = &sCPU::op_jmp_long;
optbl[0x6c] = &sCPU::op_jmp_iaddr;
optbl[0x7c] = &sCPU::op_jmp_iaddrx;
optbl[0xdc] = &sCPU::op_jmp_iladdr;
optbl[0x20] = &sCPU::op_jsr_addr;
optbl[0x22] = &sCPU::op_jsr_long;
optbl[0xfc] = &sCPU::op_jsr_iaddrx;
optbl[0x40] = &sCPU::op_rti;
optbl[0x60] = &sCPU::op_rts;
optbl[0x6b] = &sCPU::op_rtl;
optbl[0xea] = &sCPU::op_nop;
optbl[0x42] = &sCPU::op_wdm;
optbl[0xeb] = &sCPU::op_xba;
optbl[0x54] = &sCPU::op_mvn;
optbl[0x44] = &sCPU::op_mvp;
optbl[0x00] = &sCPU::op_brk;
optbl[0x02] = &sCPU::op_cop;
optbl[0xdb] = &sCPU::op_stp;
optbl[0xcb] = &sCPU::op_wai;
optbl[0xfb] = &sCPU::op_xce;
optbl[0x18] = &sCPU::op_clc;
optbl[0xd8] = &sCPU::op_cld;
optbl[0x58] = &sCPU::op_cli;
optbl[0xb8] = &sCPU::op_clv;
optbl[0x38] = &sCPU::op_sec;
optbl[0xf8] = &sCPU::op_sed;
optbl[0x78] = &sCPU::op_sei;
optbl[0xc2] = &sCPU::op_rep;
optbl[0xe2] = &sCPU::op_sep;
optbl[0xaa] = &sCPU::op_tax;
optbl[0xa8] = &sCPU::op_tay;
optbl[0x8a] = &sCPU::op_txa;
optbl[0x9b] = &sCPU::op_txy;
optbl[0x98] = &sCPU::op_tya;
optbl[0xbb] = &sCPU::op_tyx;
optbl[0x5b] = &sCPU::op_tcd;
optbl[0x1b] = &sCPU::op_tcs;
optbl[0x7b] = &sCPU::op_tdc;
optbl[0x3b] = &sCPU::op_tsc;
optbl[0xba] = &sCPU::op_tsx;
optbl[0x9a] = &sCPU::op_txs;
optbl[0x48] = &sCPU::op_pha;
optbl[0xda] = &sCPU::op_phx;
optbl[0x5a] = &sCPU::op_phy;
optbl[0x0b] = &sCPU::op_phd;
optbl[0x8b] = &sCPU::op_phb;
optbl[0x4b] = &sCPU::op_phk;
optbl[0x08] = &sCPU::op_php;
optbl[0x68] = &sCPU::op_pla;
optbl[0xfa] = &sCPU::op_plx;
optbl[0x7a] = &sCPU::op_ply;
optbl[0x2b] = &sCPU::op_pld;
optbl[0xab] = &sCPU::op_plb;
optbl[0x28] = &sCPU::op_plp;
optbl[0xf4] = &sCPU::op_pea;
optbl[0xd4] = &sCPU::op_pei;
optbl[0x62] = &sCPU::op_per;

View File

@@ -1,9 +1,9 @@
#define CLASS_NAME "sCPU"
#include "../../../lib/opgen_s.cpp"
#include "../../../lib/opgen_so.cpp"
int main() {
//fph = fopen("op.h", "wb");
//fpt = fopen("optable.cpp", "wb");
fph = fopen("op.h", "wb");
fpt = fopen("optable.cpp", "wb");
generate("op_read.cpp", "op_read.b");
generate("op_write.cpp", "op_write.b");
@@ -11,8 +11,8 @@ int main() {
generate("op_pc.cpp", "op_pc.b");
generate("op_misc.cpp", "op_misc.b");
//fclose(fph);
//fclose(fpt);
fclose(fph);
fclose(fpt);
return 0;
}

View File

@@ -83,8 +83,8 @@ inline uint32 sCPU::hdma_iaddr(uint8 i) {
*****/
void sCPU::dma_transfertobusb(uint8 i, uint8 bbus) {
if(cartridge.info.sdd1 == true && sdd1->dma_active() == true) {
r_mem->write(0x2100 | bbus, sdd1->dma_read());
if(cartridge.info.sdd1 == true && sdd1.dma_active() == true) {
r_mem->write(0x2100 | bbus, sdd1.dma_read());
} else {
dma_transfer(0, bbus, dma_addr(i));
}
@@ -111,8 +111,7 @@ void sCPU::dma_run() {
dma_add_clocks(8);
if(cartridge.info.sdd1 == true) {
sdd1->dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr),
channel[i].xfersize);
sdd1.dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr), channel[i].xfersize);
}
if(tracer.enabled() == true && tracer.cpudma_enabled() == true) {

View File

@@ -48,5 +48,9 @@ void sCPU::reset() {
apu_port[3] = 0x00;
}
sCPU::sCPU() {}
sCPU::~sCPU() {}
sCPU::sCPU() {
#include "core/optable.cpp"
}
sCPU::~sCPU() {
}

View File

@@ -1,8 +1,6 @@
class sCPU : public CPU {
public:
class sCPU : public CPU { public:
void enter();
public:
#include "core/core.h"
#include "dma/dma.h"
#include "memory/memory.h"

View File

@@ -172,7 +172,7 @@ void sCPU::cycle_edge() {
status.hdmainit_triggered = true;
hdma_init_reset();
if(hdma_enabled_channels()) {
add_clocks(12);
add_clocks(18);
hdma_init();
//if(status.dma_state == DMASTATE_INACTIVE) {
// status.dma_state = DMASTATE_DMASYNC;
@@ -188,7 +188,7 @@ void sCPU::cycle_edge() {
if(status.hclock >= 1106) {
status.hdma_triggered = true;
if(hdma_active_channels()) {
add_clocks(12);
add_clocks(18);
hdma_run();
//if(status.dma_state == DMASTATE_INACTIVE) {
// status.dma_state = DMASTATE_DMASYNC;
@@ -250,7 +250,7 @@ void sCPU::timing_reset() {
status.prev_line_clocks = 1364;
status.line_rendered = false;
status.line_render_position = minmax<0, 1112>((uint16)config::ppu.hack.render_scanline_position);
status.line_render_position = min(1112, (uint16)config::ppu.hack.render_scanline_position);
status.dram_refreshed = false;
status.dram_refresh_position = (cpu_version == 1) ? 530 : 538;
@@ -283,7 +283,7 @@ void sCPU::timing_reset() {
//initial latch values for $213c/$213d
//[x]0035 : [y]0000 (53.0 -> 212) [lda $2137]
//[x]0038 : [y]0000 (56.5 -> 226) [nop : lda $2137]
add_clocks(186);
//add_clocks(186);
}
#undef ntsc_color_burst_phase_shift_scanline

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

586
src/dsp/adsp/adsp.cpp Normal file
View File

@@ -0,0 +1,586 @@
#include "../../base.h"
#include "adsp_tables.cpp"
void aDSP::enter() { loop:
run();
goto loop;
}
uint8 aDSP::readb(uint16 addr) {
return spcram[addr];
}
void aDSP::writeb(uint16 addr, uint8 data) {
spcram[addr] = data;
}
uint16 aDSP::readw(uint16 addr) {
return (readb(addr + 0)) | (readb(addr + 1) << 8);
}
void aDSP::writew(uint16 addr, uint16 data) {
writeb(addr + 0, data);
writeb(addr + 1, data >> 8);
}
uint8 aDSP::read(uint8 addr) {
addr &= 127;
int v = addr >> 4;
int n = addr & 15;
switch(addr) {
case 0x00: case 0x10: case 0x20: case 0x30:
case 0x40: case 0x50: case 0x60: case 0x70:
return voice[v].VOLL;
case 0x01: case 0x11: case 0x21: case 0x31:
case 0x41: case 0x51: case 0x61: case 0x71:
return voice[v].VOLR;
case 0x02: case 0x12: case 0x22: case 0x32:
case 0x42: case 0x52: case 0x62: case 0x72:
return voice[v].PITCH;
case 0x03: case 0x13: case 0x23: case 0x33:
case 0x43: case 0x53: case 0x63: case 0x73:
return voice[v].PITCH >> 8;
case 0x04: case 0x14: case 0x24: case 0x34:
case 0x44: case 0x54: case 0x64: case 0x74:
return voice[v].SRCN;
case 0x05: case 0x15: case 0x25: case 0x35:
case 0x45: case 0x55: case 0x65: case 0x75:
return voice[v].ADSR1;
case 0x06: case 0x16: case 0x26: case 0x36:
case 0x46: case 0x56: case 0x66: case 0x76:
return voice[v].ADSR2;
case 0x07: case 0x17: case 0x27: case 0x37:
case 0x47: case 0x57: case 0x67: case 0x77:
return voice[v].GAIN;
case 0x08: case 0x18: case 0x28: case 0x38:
case 0x48: case 0x58: case 0x68: case 0x78:
return voice[v].ENVX;
case 0x09: case 0x19: case 0x29: case 0x39:
case 0x49: case 0x59: case 0x69: case 0x79:
return voice[v].OUTX;
case 0x0f: case 0x1f: case 0x2f: case 0x3f:
case 0x4f: case 0x5f: case 0x6f: case 0x7f:
return status.FIR[v];
case 0x0c: return status.MVOLL;
case 0x1c: return status.MVOLR;
case 0x2c: return status.EVOLL;
case 0x3c: return status.EVOLR;
case 0x4c: return status.KON;
case 0x5c: return status.KOFF;
case 0x6c: return status.FLG;
case 0x7c: return status.ENDX;
case 0x0d: return status.EFB;
case 0x2d: return status.PMON;
case 0x3d: return status.NON;
case 0x4d: return status.EON;
case 0x5d: return status.DIR;
case 0x6d: return status.ESA;
case 0x7d: return status.EDL;
}
return dspram[addr];
}
void aDSP::write(uint8 addr, uint8 data) {
//0x80-0xff is a read-only mirror of 0x00-0x7f
if(addr & 0x80)return;
int v = addr >> 4;
int n = addr & 15;
switch(addr) {
case 0x00: case 0x10: case 0x20: case 0x30:
case 0x40: case 0x50: case 0x60: case 0x70:
voice[v].VOLL = data;
break;
case 0x01: case 0x11: case 0x21: case 0x31:
case 0x41: case 0x51: case 0x61: case 0x71:
voice[v].VOLR = data;
break;
case 0x02: case 0x12: case 0x22: case 0x32:
case 0x42: case 0x52: case 0x62: case 0x72:
voice[v].PITCH &= 0xff00;
voice[v].PITCH |= data;
break;
case 0x03: case 0x13: case 0x23: case 0x33:
case 0x43: case 0x53: case 0x63: case 0x73:
voice[v].PITCH &= 0x00ff;
voice[v].PITCH |= data << 8;
break;
case 0x04: case 0x14: case 0x24: case 0x34:
case 0x44: case 0x54: case 0x64: case 0x74:
voice[v].SRCN = data;
break;
case 0x05: case 0x15: case 0x25: case 0x35:
case 0x45: case 0x55: case 0x65: case 0x75:
voice[v].ADSR1 = data;
voice[v].AdjustEnvelope();
break;
case 0x06: case 0x16: case 0x26: case 0x36:
case 0x46: case 0x56: case 0x66: case 0x76:
voice[v].ADSR2 = data;
//sustain_level = 0-7, 7 is a special case handled by ATTACK envx mode
voice[v].env_sustain = (voice[v].ADSR_sus_level() + 1) << 8;
voice[v].AdjustEnvelope();
break;
case 0x07: case 0x17: case 0x27: case 0x37:
case 0x47: case 0x57: case 0x67: case 0x77:
voice[v].GAIN = data;
voice[v].AdjustEnvelope();
break;
case 0x08: case 0x18: case 0x28: case 0x38:
case 0x48: case 0x58: case 0x68: case 0x78:
voice[v].ENVX = data;
break;
case 0x09: case 0x19: case 0x29: case 0x39:
case 0x49: case 0x59: case 0x69: case 0x79:
voice[v].OUTX = data;
break;
case 0x0f: case 0x1f: case 0x2f: case 0x3f:
case 0x4f: case 0x5f: case 0x6f: case 0x7f:
status.FIR[v] = data;
break;
case 0x0c: status.MVOLL = data; break;
case 0x1c: status.MVOLR = data; break;
case 0x2c: status.EVOLL = data; break;
case 0x3c: status.EVOLR = data; break;
case 0x4c:
status.KON = data;
status.kon = data;
break;
case 0x5c:
status.KOFF = data;
break;
case 0x6c:
status.FLG = data;
status.noise_rate = rate_table[data & 0x1f];
break;
case 0x7c:
//read-only register, writes clear all bits of ENDX
status.ENDX = 0;
break;
case 0x0d: status.EFB = data; break;
case 0x2d: status.PMON = data; break;
case 0x3d: status.NON = data; break;
case 0x4d: status.EON = data; break;
case 0x5d: status.DIR = data; break;
case 0x6d: status.ESA = data; break;
case 0x7d: status.EDL = data; break;
}
dspram[addr] = data;
}
void aDSP::power() {
spcram = r_smp->get_spcram_handle();
memset(dspram, 0x00, 128);
for(int v = 0; v < 8; v++) {
voice[v].VOLL = 0;
voice[v].VOLR = 0;
voice[v].PITCH = 0;
voice[v].SRCN = 0;
voice[v].ADSR1 = 0;
voice[v].ADSR2 = 0;
voice[v].GAIN = 0;
status.FIR[v] = 0;
}
status.FLG = 0xe0;
status.MVOLL = status.MVOLR = 0;
status.EVOLL = status.EVOLR = 0;
status.ENDX = 0;
status.EFB = 0;
status.PMON = 0;
status.NON = 0;
status.EON = 0;
status.DIR = 0;
status.ESA = 0;
status.EDL = 0;
status.echo_length = 0;
reset();
}
void aDSP::reset() {
status.KON = 0x00;
status.KOFF = 0x00;
status.FLG |= 0xe0;
status.kon = 0x00;
status.esa = 0x00;
status.noise_ctr = 0;
status.noise_rate = 0;
status.noise_sample = 0x4000;
status.echo_index = 0;
status.fir_buffer_index = 0;
for(int v = 0; v < 8; v++) {
voice[v].ENVX = 0;
voice[v].OUTX = 0;
voice[v].pitch_ctr = 0;
voice[v].brr_index = 0;
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2));
voice[v].brr_looped = false;
voice[v].brr_data[0] = 0;
voice[v].brr_data[1] = 0;
voice[v].brr_data[2] = 0;
voice[v].brr_data[3] = 0;
voice[v].brr_data_index = 0;
voice[v].envx = 0;
voice[v].env_ctr = 0;
voice[v].env_rate = 0;
voice[v].env_state = SILENCE;
voice[v].env_mode = DIRECT;
status.fir_buffer[0][v] = 0;
status.fir_buffer[1][v] = 0;
}
dsp_counter = 0;
}
void aDSP::run() {
uint8 pmon;
int32 sample;
int32 msamplel, msampler;
int32 esamplel, esampler;
int32 fir_samplel, fir_sampler;
pmon = status.PMON & ~status.NON & ~1;
if((dsp_counter++ & 1) == 0) {
for(uint v = 0; v < 8; v++) {
if(status.soft_reset()) {
if(voice[v].env_state != SILENCE) {
voice[v].env_state = SILENCE;
voice[v].AdjustEnvelope();
}
}
if(status.KOFF & (1 << v)) {
if(voice[v].env_state != SILENCE && voice[v].env_state != RELEASE) {
voice[v].env_state = RELEASE;
voice[v].AdjustEnvelope();
}
}
if(status.kon & (1 << v)) {
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2));
voice[v].brr_index = -9;
voice[v].brr_looped = false;
voice[v].brr_data[0] = 0;
voice[v].brr_data[1] = 0;
voice[v].brr_data[2] = 0;
voice[v].brr_data[3] = 0;
voice[v].envx = 0;
voice[v].env_state = ATTACK;
voice[v].AdjustEnvelope();
}
}
status.ENDX &= ~status.kon;
status.kon = 0;
}
/*****
* update noise
*****/
status.noise_ctr += status.noise_rate;
if(status.noise_ctr >= 0x7800) {
status.noise_ctr -= 0x7800;
status.noise_sample = (status.noise_sample >> 1) | (((status.noise_sample << 14) ^ (status.noise_sample << 13)) & 0x4000);
}
msamplel = msampler = 0;
esamplel = esampler = 0;
/*****
* process voice channels
*****/
for(int v = 0; v < 8; v++) {
if(voice[v].brr_index < -1) {
voice[v].brr_index++;
voice[v].OUTX = voice[v].outx = 0;
voice[v].ENVX = 0;
continue;
}
if(voice[v].brr_index >= 0) {
if(pmon & (1 << v)) {
voice[v].pitch_ctr += (voice[v].pitch_rate() * (voice[v - 1].outx + 0x8000)) >> 15;
} else {
voice[v].pitch_ctr += voice[v].pitch_rate();
}
} else {
voice[v].pitch_ctr = 0x3000;
voice[v].brr_index = 0;
}
/*****
* decode BRR samples
*****/
while(voice[v].pitch_ctr >= 0) {
voice[v].pitch_ctr -= 0x1000;
voice[v].brr_data_index++;
voice[v].brr_data_index &= 3;
if(voice[v].brr_index == 0) {
voice[v].brr_header = readb(voice[v].brr_ptr);
if(voice[v].brr_header_flags() == BRR_END) {
status.ENDX |= (1 << v);
voice[v].env_state = SILENCE;
voice[v].AdjustEnvelope();
}
}
#define S(x) voice[v].brr_data[(voice[v].brr_data_index + (x)) & 3]
if(voice[v].env_state != SILENCE) {
sample = readb(voice[v].brr_ptr + 1 + (voice[v].brr_index >> 1));
if(voice[v].brr_index & 1) {
sample = sclip<4>(sample);
} else {
sample = sclip<4>(sample >> 4);
}
if(voice[v].brr_header_shift() <= 12) {
sample = (sample << voice[v].brr_header_shift() >> 1);
} else {
sample &= ~0x7ff;
}
switch(voice[v].brr_header_filter()) {
case 0: //direct
break;
case 1: //15/16
sample += S(-1) + ((-S(-1)) >> 4);
break;
case 2: //61/32 - 15/16
sample += (S(-1) << 1) + ((-((S(-1) << 1) + S(-1))) >> 5)
- S(-2) + (S(-2) >> 4);
break;
case 3: //115/64 - 13/16
sample += (S(-1) << 1) + ((-(S(-1) + (S(-1) << 2) + (S(-1) << 3))) >> 6)
- S(-2) + (((S(-2) << 1) + S(-2)) >> 4);
break;
}
S(0) = sample = sclip<15>(sclamp<16>(sample));
} else {
S(0) = sample = 0;
}
if(++voice[v].brr_index > 15) {
voice[v].brr_index = 0;
if(voice[v].brr_header_flags() & BRR_END) {
if(voice[v].brr_header_flags() & BRR_LOOP) {
status.ENDX |= (1 << v);
}
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2) + 2);
voice[v].brr_looped = true;
} else {
voice[v].brr_ptr += 9;
}
}
}
/*****
* volume envelope adjust
*****/
voice[v].env_ctr += voice[v].env_rate;
if(voice[v].env_ctr >= 0x7800) {
voice[v].env_ctr -= 0x7800;
switch(voice[v].env_mode) {
case DIRECT:
voice[v].env_rate = 0;
break;
case LINEAR_DEC:
voice[v].envx -= 32;
if(voice[v].envx <= 0) {
voice[v].envx = 0;
voice[v].env_rate = 0;
voice[v].env_mode = DIRECT;
}
break;
case LINEAR_INC:
voice[v].envx += 32;
if(voice[v].envx >= 0x7ff) {
voice[v].envx = 0x7ff;
voice[v].env_rate = 0;
voice[v].env_mode = DIRECT;
if(voice[v].ADSR_enabled() && voice[v].env_state == ATTACK) {
voice[v].env_state = ((voice[v].env_sustain == 0x800) ? SUSTAIN : DECAY);
voice[v].AdjustEnvelope();
}
}
break;
case EXP_DEC:
//multiply by 255/256ths
voice[v].envx -= ((voice[v].envx - 1) >> 8) + 1;
if(voice[v].ADSR_enabled() && voice[v].env_state == DECAY && voice[v].envx <= voice[v].env_sustain) {
voice[v].env_state = SUSTAIN;
voice[v].AdjustEnvelope();
} else if(voice[v].envx <= 0) {
voice[v].envx = 0;
voice[v].env_rate = 0;
voice[v].env_mode = DIRECT;
}
break;
case BENT_INC:
if(voice[v].envx < 0x600) {
voice[v].envx += 32;
} else {
voice[v].envx += 8;
if(voice[v].envx >= 0x7ff) {
voice[v].envx = 0x7ff;
voice[v].env_rate = 0;
voice[v].env_mode = DIRECT;
}
}
break;
case FAST_ATTACK:
voice[v].envx += 0x400;
if(voice[v].envx >= 0x7ff) {
voice[v].envx = 0x7ff;
//attack raises to max envx. if sustain is also set to max envx, skip decay phase
voice[v].env_state = ((voice[v].env_sustain == 0x800) ? SUSTAIN : DECAY);
voice[v].AdjustEnvelope();
}
break;
case RELEASE_DEC:
voice[v].envx -= 8;
if(voice[v].envx <= 0) {
voice[v].env_state = SILENCE;
voice[v].AdjustEnvelope();
}
break;
}
}
voice[v].ENVX = voice[v].envx >> 4;
/*****
* gaussian interpolation / noise
*****/
if(status.NON & (1 << v)) {
sample = sclip<15>(status.noise_sample);
} else {
int32 d = voice[v].pitch_ctr >> 4; //-256 <= sample <= -1
sample = ((gaussian_table[ -1 - d] * S(-3)) >> 11);
sample += ((gaussian_table[255 - d] * S(-2)) >> 11);
sample += ((gaussian_table[512 + d] * S(-1)) >> 11);
sample = sclip <15>(sample);
sample += ((gaussian_table[256 + d] * S( 0)) >> 11);
sample = sclamp<15>(sample);
}
#undef S
/*****
* envelope / volume adjust
*****/
sample = (sample * voice[v].envx) >> 11;
voice[v].outx = sample << 1;
voice[v].OUTX = sample >> 7;
if(!status.mute()) {
msamplel += ((sample * voice[v].VOLL) >> 7) << 1;
msampler += ((sample * voice[v].VOLR) >> 7) << 1;
}
if((status.EON & (1 << v)) && status.echo_write()) {
esamplel += ((sample * voice[v].VOLL) >> 7) << 1;
esampler += ((sample * voice[v].VOLR) >> 7) << 1;
}
}
/*****
* echo (FIR) adjust
*****/
#define F(c,x) status.fir_buffer[c][(status.fir_buffer_index + (x)) & 7]
status.fir_buffer_index++;
F(0,0) = readw((status.esa << 8) + status.echo_index + 0);
F(1,0) = readw((status.esa << 8) + status.echo_index + 2);
fir_samplel = (F(0,-0) * status.FIR[7] +
F(0,-1) * status.FIR[6] +
F(0,-2) * status.FIR[5] +
F(0,-3) * status.FIR[4] +
F(0,-4) * status.FIR[3] +
F(0,-5) * status.FIR[2] +
F(0,-6) * status.FIR[1] +
F(0,-7) * status.FIR[0]);
fir_sampler = (F(1,-0) * status.FIR[7] +
F(1,-1) * status.FIR[6] +
F(1,-2) * status.FIR[5] +
F(1,-3) * status.FIR[4] +
F(1,-4) * status.FIR[3] +
F(1,-5) * status.FIR[2] +
F(1,-6) * status.FIR[1] +
F(1,-7) * status.FIR[0]);
#undef F
/*****
* update echo buffer
*****/
if(status.echo_write()) {
esamplel += (fir_samplel * status.EFB) >> 14;
esampler += (fir_sampler * status.EFB) >> 14;
esamplel = sclamp<16>(esamplel);
esampler = sclamp<16>(esampler);
writew((status.esa << 8) + status.echo_index + 0, esamplel);
writew((status.esa << 8) + status.echo_index + 2, esampler);
}
status.echo_index += 4;
if(status.echo_index >= status.echo_length) {
status.echo_index = 0;
status.echo_length = (status.EDL & 0x0f) << 11;
}
//ESA read occurs at roughly 22/32th sample
//ESA fetch occurs at roughly 29/32th sample
//as this is not a subsample-level S-DSP emulator,
//simulate ~25/32th delay by caching ESA for one
//complete sample ...
status.esa = status.ESA;
/*****
* main output adjust
*****/
if(!status.mute()) {
msamplel = (msamplel * status.MVOLL) >> 7;
msampler = (msampler * status.MVOLR) >> 7;
msamplel += (fir_samplel * status.EVOLL) >> 14;
msampler += (fir_sampler * status.EVOLR) >> 14;
msamplel = sclamp<16>(msamplel);
msampler = sclamp<16>(msampler);
}
snes.audio_update(msamplel, msampler);
scheduler.addclocks_dsp(32 * 3);
}
aDSP::aDSP() {}
aDSP::~aDSP() {}

172
src/dsp/adsp/adsp.h Normal file
View File

@@ -0,0 +1,172 @@
class aDSP : public DSP {
private:
uint8 dspram[128];
uint8 *spcram;
uint32 dsp_counter;
enum { BRR_END = 1, BRR_LOOP = 2 };
uint8 readb (uint16 addr);
uint16 readw (uint16 addr);
void writeb(uint16 addr, uint8 data);
void writew(uint16 addr, uint16 data);
public:
static const uint16 rate_table[32];
static const int16 gaussian_table[512];
enum EnvelopeStates {
ATTACK,
DECAY,
SUSTAIN,
RELEASE,
SILENCE
};
enum EnvelopeModes {
DIRECT,
LINEAR_DEC,
EXP_DEC,
LINEAR_INC,
BENT_INC,
FAST_ATTACK,
RELEASE_DEC
};
private:
struct Status {
//$0c,$1c
int8 MVOLL, MVOLR;
//$2c,$3c
int8 EVOLL, EVOLR;
//$4c,$5c
uint8 KON, KOFF;
//$6c
uint8 FLG;
//$7c
uint8 ENDX;
//$0d
int8 EFB;
//$2d,$3d,$4d
uint8 PMON, NON, EON;
//$5d
uint8 DIR;
//$6d,$7d
uint8 ESA, EDL;
//$xf
int8 FIR[8];
//internal variables
uint8 kon, esa;
int16 noise_ctr, noise_rate;
uint16 noise_sample;
uint16 echo_index, echo_length;
int16 fir_buffer[2][8];
uint8 fir_buffer_index;
//functions
bool soft_reset() { return !!(FLG & 0x80); }
bool mute() { return !!(FLG & 0x40); }
bool echo_write() { return !(FLG & 0x20); }
} status;
struct Voice {
//$x0-$x1
int8 VOLL, VOLR;
//$x2-$x3
int16 PITCH;
//$x4
uint8 SRCN;
//$x5-$x7
uint8 ADSR1, ADSR2, GAIN;
//$x8-$x9
uint8 ENVX, OUTX;
//internal variables
int16 pitch_ctr;
int8 brr_index;
uint16 brr_ptr;
uint8 brr_header;
bool brr_looped;
int16 brr_data[4];
uint8 brr_data_index;
int16 envx;
uint16 env_ctr, env_rate, env_sustain;
enum EnvelopeStates env_state;
enum EnvelopeModes env_mode;
int16 outx;
//functions
int16 pitch_rate() { return PITCH & 0x3fff; }
uint8 brr_header_shift() { return brr_header >> 4; }
uint8 brr_header_filter() { return (brr_header >> 2) & 3; }
uint8 brr_header_flags() { return brr_header & 3; }
bool ADSR_enabled() { return !!(ADSR1 & 0x80); }
uint8 ADSR_decay() { return (ADSR1 >> 4) & 7; }
uint8 ADSR_attack() { return ADSR1 & 15; }
uint8 ADSR_sus_level() { return ADSR2 >> 5; }
uint8 ADSR_sus_rate() { return ADSR2 & 31; }
void AdjustEnvelope() {
if(env_state == SILENCE) {
env_mode = DIRECT;
env_rate = 0;
envx = 0;
} else if(env_state == RELEASE) {
env_mode = RELEASE_DEC;
env_rate = 0x7800;
} else if(ADSR_enabled()) {
switch(env_state) {
case ATTACK:
env_rate = rate_table[(ADSR_attack() << 1) + 1];
env_mode = (env_rate == 0x7800) ? FAST_ATTACK : LINEAR_INC;
break;
case DECAY:
env_rate = rate_table[(ADSR_decay() << 1) + 0x10];
env_mode = EXP_DEC;
break;
case SUSTAIN:
env_rate = rate_table[ADSR_sus_rate()];
env_mode = (env_rate == 0) ? DIRECT : EXP_DEC;
break;
}
} else if(GAIN & 0x80) {
switch(GAIN & 0x60) {
case 0x00: env_mode = LINEAR_DEC; break;
case 0x20: env_mode = EXP_DEC; break;
case 0x40: env_mode = LINEAR_INC; break;
case 0x60: env_mode = BENT_INC; break;
}
env_rate = rate_table[GAIN & 0x1f];
} else {
env_mode = DIRECT;
env_rate = 0;
envx = (GAIN & 0x7f) << 4;
}
}
} voice[8];
public:
void enter();
void run();
uint8 read (uint8 addr);
void write(uint8 addr, uint8 data);
void power();
void reset();
aDSP();
~aDSP();
};

View File

@@ -1,11 +1,11 @@
const uint16 bDSP::RateTable[32] = {
const uint16 aDSP::rate_table[32] = {
0x0000, 0x000F, 0x0014, 0x0018, 0x001E, 0x0028, 0x0030, 0x003C,
0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180,
0x01E0, 0x0280, 0x0300, 0x03C0, 0x0500, 0x0600, 0x0780, 0x0A00,
0x0C00, 0x0F00, 0x1400, 0x1800, 0x1E00, 0x2800, 0x3C00, 0x7800
};
const int16 bDSP::GaussTable[512] = {
const int16 aDSP::gaussian_table[512] = {
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001,

File diff suppressed because it is too large Load Diff

View File

@@ -1,171 +1,167 @@
class bDSP : public DSP {
private:
uint8 dspram[128];
uint8 *spcram;
uint32 dsp_counter;
enum { BRR_END = 1, BRR_LOOP = 2 };
uint8 readb (uint16 addr);
uint16 readw (uint16 addr);
void writeb(uint16 addr, uint8 data);
void writew(uint16 addr, uint16 data);
public:
static const uint16 RateTable[32];
static const int16 GaussTable[512];
enum EnvelopeStates {
ATTACK,
DECAY,
SUSTAIN,
RELEASE,
SILENCE
};
enum EnvelopeModes {
DIRECT,
LINEAR_DEC,
EXP_DEC,
LINEAR_INC,
BENT_INC,
FAST_ATTACK,
RELEASE_DEC
};
private:
struct Status {
//$0c,$1c
int8 MVOLL, MVOLR;
//$2c,$3c
int8 EVOLL, EVOLR;
//$4c,$5c
uint8 KON, KOFF;
//$6c
uint8 FLG;
//$7c
uint8 ENDX;
//$0d
int8 EFB;
//$2d,$3d,$4d
uint8 PMON, NON, EON;
//$5d
uint8 DIR;
//$6d,$7d
uint8 ESA, EDL;
//$xf
int8 FIR[8];
//internal variables
uint8 kon;
bool key_flag;
int16 noise_ctr, noise_rate;
uint16 noise_sample;
uint16 echo_index, echo_size, echo_target;
int16 fir_buffer[2][8];
uint8 fir_buffer_index;
//functions
bool soft_reset() { return bool(FLG & 0x80); }
bool mute() { return bool(FLG & 0x40); }
bool echo_write() { return !(FLG & 0x20); }
} status;
struct Voice {
//$x0-$x1
int8 VOLL, VOLR;
//$x2-$x3
int16 PITCH;
//$x4
uint8 SRCN;
//$x5-$x7
uint8 ADSR1, ADSR2, GAIN;
//$x8-$x9
uint8 ENVX, OUTX;
//internal variables
int16 pitch_ctr;
int8 brr_index;
uint16 brr_ptr;
uint8 brr_header;
bool brr_looped;
int16 brr_data[4];
uint8 brr_data_index;
int16 envx;
uint16 env_ctr, env_rate, env_sustain;
enum EnvelopeStates env_state;
enum EnvelopeModes env_mode;
int16 outx;
//functions
int16 pitch_rate() { return PITCH & 0x3fff; }
uint8 brr_header_shift() { return brr_header >> 4; }
uint8 brr_header_filter() { return (brr_header >> 2) & 3; }
uint8 brr_header_flags() { return brr_header & 3; }
bool ADSR_enabled() { return bool(ADSR1 & 0x80); }
uint8 ADSR_decay() { return (ADSR1 >> 4) & 7; }
uint8 ADSR_attack() { return ADSR1 & 15; }
uint8 ADSR_sus_level() { return ADSR2 >> 5; }
uint8 ADSR_sus_rate() { return ADSR2 & 31; }
void AdjustEnvelope() {
if(env_state == SILENCE) {
env_mode = DIRECT;
env_rate = 0;
envx = 0;
} else if(env_state == RELEASE) {
env_mode = RELEASE_DEC;
env_rate = 0x7800;
} else if(ADSR_enabled()) {
switch(env_state) {
case ATTACK:
env_rate = RateTable[(ADSR_attack() << 1) + 1];
env_mode = (env_rate == 0x7800) ? FAST_ATTACK : LINEAR_INC;
break;
case DECAY:
env_rate = RateTable[(ADSR_decay() << 1) + 0x10];
env_mode = EXP_DEC;
break;
case SUSTAIN:
env_rate = RateTable[ADSR_sus_rate()];
env_mode = (env_rate == 0) ? DIRECT : EXP_DEC;
break;
}
} else if(GAIN & 0x80) {
switch(GAIN & 0x60) {
case 0x00: env_mode = LINEAR_DEC; break;
case 0x20: env_mode = EXP_DEC; break;
case 0x40: env_mode = LINEAR_INC; break;
case 0x60: env_mode = BENT_INC; break;
}
env_rate = RateTable[GAIN & 0x1f];
} else {
env_mode = DIRECT;
env_rate = 0;
envx = (GAIN & 0x7f) << 4;
}
}
} voice[8];
void enter();
uint8 read( uint8 addr );
void write( uint8 addr, uint8 data );
void power();
void reset();
bDSP();
~bDSP();
public:
uint8 read (uint8 addr);
void write(uint8 addr, uint8 data);
void power();
void reset();
uint32 run();
enum { echo_hist_size = 8 };
enum { register_count = 128 };
enum { voice_count = 8 };
enum env_mode_t { env_release, env_attack, env_decay, env_sustain };
enum { brr_buf_size = 12 };
struct voice_t
{
int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling)
int buf_pos; // place in buffer where next samples will be decoded
int interp_pos; // relative fractional position in sample (0x1000 = 1.0)
int brr_addr; // address of current BRR block
int brr_offset; // current decoding offset in BRR block
uint8* regs; // pointer to voice's DSP registers
int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc.
int kon_delay; // KON delay/current setup phase
env_mode_t env_mode;
int env; // current envelope level
int hidden_env; // used by GAIN mode 7, very obscure quirk
uint8 t_envx_out;
};
private:
struct state_t
{
uint8 regs [register_count];
// Echo history keeps most recent 8 samples
int echo_hist [echo_hist_size] [2];
int echo_hist_pos;
int every_other_sample; // toggles every sample
int kon; // KON value when last checked
int noise;
int counter;
int echo_offset; // offset from ESA in echo buffer
int echo_length; // number of bytes that echo_offset will stop at
// Hidden registers also written to when main register is written to
int new_kon;
uint8 endx_buf;
uint8 envx_buf;
uint8 outx_buf;
// Temporary state between clocks
// read once per sample
int t_pmon;
int t_non;
int t_eon;
int t_dir;
int t_koff;
// read a few clocks ahead then used
int t_brr_next_addr;
int t_adsr0;
int t_brr_header;
int t_brr_byte;
int t_srcn;
// internal state that is recalculated every sample
int t_dir_addr;
int t_pitch;
int t_output;
int t_looped;
// left/right sums
int t_main_out [2];
int t_echo_out [2];
voice_t voices [voice_count];
};
state_t m;
uint8* ram;
unsigned read_counter( int rate );
void run_envelope( voice_t* const v );
void decode_brr( voice_t* v );
bDSP();
~bDSP();
void voice_output( voice_t const* v, int ch );
void voice_V1( voice_t* const );
void voice_V2( voice_t* const );
void voice_V3( voice_t* const );
void voice_V3a( voice_t* const );
void voice_V3b( voice_t* const );
void voice_V3c( voice_t* const );
void voice_V4( voice_t* const );
void voice_V5( voice_t* const );
void voice_V6( voice_t* const );
void voice_V7( voice_t* const );
void voice_V8( voice_t* const );
void voice_V9( voice_t* const );
void voice_V7_V4_V1( voice_t* const );
void voice_V8_V5_V2( voice_t* const );
void voice_V9_V6_V3( voice_t* const );
int calc_echo_output( int ch, int sample );
// Global registers
enum {
r_mvoll = 0x0C, r_mvolr = 0x1C,
r_evoll = 0x2C, r_evolr = 0x3C,
r_kon = 0x4C, r_koff = 0x5C,
r_flg = 0x6C, r_endx = 0x7C,
r_efb = 0x0D, r_pmon = 0x2D,
r_non = 0x3D, r_eon = 0x4D,
r_dir = 0x5D, r_esa = 0x6D,
r_edl = 0x7D,
r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F
};
// Voice registers
enum {
v_voll = 0x00, v_volr = 0x01,
v_pitchl = 0x02, v_pitchh = 0x03,
v_srcn = 0x04, v_adsr0 = 0x05,
v_adsr1 = 0x06, v_gain = 0x07,
v_envx = 0x08, v_outx = 0x09
};
};
inline uint8 bDSP::read( uint8 addr )
{
return m.regs [addr];
}
inline void bDSP::write( uint8 addr, uint8 data )
{
m.regs [addr] = data;
switch ( addr & 0x0F )
{
case v_envx:
m.envx_buf = data;
break;
case v_outx:
m.outx_buf = data;
break;
case 0x0C:
if ( addr == r_kon )
m.new_kon = data;
if ( addr == r_endx ) // always cleared, regardless of data written
{
m.endx_buf = 0;
m.regs [r_endx] = 0;
}
break;
}
}

View File

@@ -0,0 +1,32 @@
#include "../../base.h"
#include "spc_dsp.h"
void bDSP::power() {
spc_dsp_init(r_smp->get_spcram_handle());
spc_dsp_reset();
}
void bDSP::reset() {
spc_dsp_soft_reset();
}
uint8 bDSP::read(uint8 addr) {
return spc_dsp_read(addr);
}
void bDSP::write(uint8 addr, uint8 data) {
spc_dsp_write(addr, data);
}
#define SPC_DSP_CUSTOM_RUN 1 //causes spc_dsp_run() to not be defined since it's huge and we don't need it
#define SPC_DSP_OUT_HOOK(left, right) snes.audio_update(left, right);
#include "spc_dsp.cpp"
void bDSP::enter() { loop:
#define PHASE(n) scheduler.addclocks_dsp(3);
#include "spc_dsp_timing.h"
goto loop;
}
bDSP::bDSP() {}
bDSP::~bDSP() {}

View File

@@ -0,0 +1,10 @@
class bDSP : public DSP { public:
void enter();
uint8 read(uint8 addr);
void write(uint8 addr, uint8 data);
void power();
void reset();
bDSP();
~bDSP();
};

View File

@@ -0,0 +1,64 @@
Overall operation
-----------------
This DSP emulator fundamentally emulates the different options the DSP
performs on each clock. The pattern of operations repeats every 32
clocks (except one minor detail, which repeats every 64 clocks instead).
There are three main types of operations:
- Miscellaneous processing
- Voice processing
- Echo processing
Each is done over several clocks, and several operations are done on
each clock. Each clock is defined as a separate function, then called
from a large switch block in a loop.
Many times a value is read on one clock but not used until a later
clock, so many non-local temporary variables are used in the code to
store these values. These are named with t_ to make it clear that they
don't store long-term state.
Circular buffers
----------------
Two circular buffers are used in the code (echo history and BRR decode).
Both need efficient index-based access with wrap-around. Things are
greatly simplified by repeating the contents of buffer twice, so instead
of
0 1 2 3 4 5 6 7
it stores
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
The position in this case would always be 0 to 7, so reading up to +8
won't go outside buffer. This duplication is maintained by simply
writing data twice when filling buffer:
0 1 2 3 4 # 6 7 0 1 2 3 4 # 6 7
new data -----^---------------^
No wrap checking needs to be done when writing either, since the above
reasoning holds. When making a state snapshot, only the first copy needs
to be saved. When restoring, simply duplicate the data twice.
Code
----
- Currently all state is in static variables. They have either a t_ or
m_ prefix to allow easy migration to a structure.
- Static state that persists over several samples or more is prefixed
with m_.
- State which is temporary to the current sample is prefixed with t_.
These are usually just overwritten with new data on the next sample.
These generally correspond to temporaries/registers in actual DSP
itself.
- Minimal stdint.h included in case your system doesn't have one.
--
Shay Green <gblargg@gmail.com>

View File

@@ -0,0 +1,828 @@
// http://www.slack.net/~ant/
#include "spc_dsp.h"
#include <limits.h>
#include <string.h>
/* Copyright (C) 2007 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
// Volume registers and efb are signed! Easy to forget int8_t cast.
// Prefixes are to avoid accidental use of locals with same names.
// Global registers
enum {
r_mvoll = 0x0C, r_mvolr = 0x1C,
r_evoll = 0x2C, r_evolr = 0x3C,
r_kon = 0x4C, r_koff = 0x5C,
r_flg = 0x6C, r_endx = 0x7C,
r_efb = 0x0D, r_pmon = 0x2D,
r_non = 0x3D, r_eon = 0x4D,
r_dir = 0x5D, r_esa = 0x6D,
r_edl = 0x7D,
r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F
};
// Voice registers
enum {
v_voll = 0x00, v_volr = 0x01,
v_pitchl = 0x02, v_pitchh = 0x03,
v_srcn = 0x04, v_adsr0 = 0x05,
v_adsr1 = 0x06, v_gain = 0x07,
v_envx = 0x08, v_outx = 0x09
};
// Internal envelope modes
enum env_mode_t { env_release, env_attack, env_decay, env_sustain };
// Internal voice state
enum { brr_buf_size = 12 };
enum { brr_block_size = 9 };
typedef struct voice_t
{
int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling)
int buf_pos; // place in buffer where next samples will be decoded
int interp_pos; // relative fractional position in sample (0x1000 = 1.0)
int brr_addr; // address of current BRR block
int brr_offset; // current decoding offset in BRR block
uint8_t* regs; // pointer to voice's DSP registers
int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc.
int kon_delay; // KON delay/current setup phase
enum env_mode_t env_mode;
int env; // current envelope level
int t_envx_out;
int hidden_env; // used by GAIN mode 7, very obscure quirk
} voice_t;
static voice_t m_voice_state [spc_dsp_voice_count];
static uint8_t* m_ram; // 64K shared RAM between DSP and SMP
spc_dsp_t m_spc_dsp;
spc_dsp_sample_t* m_spc_dsp_out_begin;
spc_dsp_sample_t* m_spc_dsp_out;
spc_dsp_sample_t* m_spc_dsp_out_end;
// "Member" access
#define m m_spc_dsp
// Access global DSP register
#define REG(n) m.regs [r_##n]
// Access voice DSP register
#define VREG(r,n) r [v_##n]
// if ( io < -32768 ) io = -32768;
// if ( io > 32767 ) io = 32767;
#define CLAMP16( io )\
{\
if ( (int16_t) io != io )\
io = 0x7FFF ^ (io >> 31);\
}
// Gaussian interpolation
static short const gauss [512] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5,
6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17,
18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27,
28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77,
78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102,
104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132,
134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168,
171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210,
212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257,
260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311,
314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370,
374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434,
439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504,
508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577,
582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654,
659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732,
737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811,
816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889,
894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965,
969, 974, 978, 983, 988, 992, 997,1001,1005,1010,1014,1019,1023,1027,1032,1036,
1040,1045,1049,1053,1057,1061,1066,1070,1074,1078,1082,1086,1090,1094,1098,1102,
1106,1109,1113,1117,1121,1125,1128,1132,1136,1139,1143,1146,1150,1153,1157,1160,
1164,1167,1170,1174,1177,1180,1183,1186,1190,1193,1196,1199,1202,1205,1207,1210,
1213,1216,1219,1221,1224,1227,1229,1232,1234,1237,1239,1241,1244,1246,1248,1251,
1253,1255,1257,1259,1261,1263,1265,1267,1269,1270,1272,1274,1275,1277,1279,1280,
1282,1283,1284,1286,1287,1288,1290,1291,1292,1293,1294,1295,1296,1297,1297,1298,
1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305,
};
static inline int interpolate( voice_t const* const v )
{
// Make pointers into gaussian based on fractional position between samples
int offset = v->interp_pos >> 4 & 0xFF;
short const* fwd = gauss + 255 - offset;
short const* rev = gauss + offset; // mirror left half of gaussian
int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos];
int out;
out = (fwd [ 0] * in [0]) >> 11;
out += (fwd [256] * in [1]) >> 11;
out += (rev [256] * in [2]) >> 11;
out = (int16_t) out;
out += (rev [ 0] * in [3]) >> 11;
CLAMP16( out );
out &= ~1;
return out;
}
//// Counters
enum { simple_counter_range = 2048 * 5 * 3 }; // 30720
static unsigned short const counter_rates [32] =
{
simple_counter_range + 1, // never fires
2048, 1536,
1280, 1024, 768,
640, 512, 384,
320, 256, 192,
160, 128, 96,
80, 64, 48,
40, 32, 24,
20, 16, 12,
10, 8, 6,
5, 4, 3,
2,
1
};
static unsigned short const counter_offsets [32] =
{
1, 0, 1040,
536, 0, 1040,
536, 0, 1040,
536, 0, 1040,
536, 0, 1040,
536, 0, 1040,
536, 0, 1040,
536, 0, 1040,
536, 0, 1040,
536, 0, 1040,
0,
0
};
static inline void init_counters( void ) { }
static inline void run_counters( void )
{
if ( --m.counter < 0 )
m.counter = simple_counter_range - 1;
}
static inline unsigned read_counter( int rate )
{
return ((unsigned) m.counter + counter_offsets [rate]) % counter_rates [rate];
}
//// Envelope
static inline void run_envelope( voice_t* const v )
{
int env = v->env;
if ( v->env_mode == env_release ) // 60%
{
if ( (env -= 0x8) < 0 )
env = 0;
v->env = env;
}
else
{
int rate;
int env_data = VREG(v->regs,adsr1);
if ( m.t_adsr0 & 0x80 ) // 99% ADSR
{
if ( v->env_mode >= env_decay ) // 99%
{
env--;
env -= env >> 8;
rate = env_data & 0x1F;
if ( v->env_mode == env_decay ) // 1%
rate = (m.t_adsr0 >> 3 & 0x0E) + 0x10;
}
else // env_attack
{
rate = (m.t_adsr0 & 0x0F) * 2 + 1;
env += rate < 31 ? 0x20 : 0x400;
}
}
else // GAIN
{
env_data = VREG(v->regs,gain);
int mode = env_data >> 5;
if ( mode < 4 ) // direct
{
env = env_data * 0x10;
rate = 31;
}
else
{
rate = env_data & 0x1F;
if ( mode == 4 ) // 4: linear decrease
{
env -= 0x20;
}
else if ( mode < 6 ) // 5: exponential decrease
{
env--;
env -= env >> 8;
}
else // 6,7: linear increase
{
env += 0x20;
if ( mode > 6 && (unsigned) v->hidden_env >= 0x600 )
env += 0x8 - 0x20; // 7: two-slope linear increase
}
}
}
// Sustain level
if ( (env >> 8) == (env_data >> 5) && v->env_mode == env_decay )
v->env_mode = env_sustain;
v->hidden_env = env;
// unsigned cast because linear decrease going negative also triggers this
if ( (unsigned) env > 0x7FF )
{
env = (env < 0 ? 0 : 0x7FF);
if ( v->env_mode == env_attack )
v->env_mode = env_decay;
}
if ( !read_counter( rate ) )
v->env = env; // nothing else is controlled by the counter
}
}
//// BRR Decoding
static inline void decode_brr( voice_t* v )
{
// Arrange the four input nybbles in 0xABCD order for easy decoding
int nybbles = m.t_brr_byte * 0x100 + m_ram [(v->brr_addr + v->brr_offset + 1) & 0xFFFF];
int const header = m.t_brr_header;
// 0: >>1 1: <<0 2: <<1 ... 12: <<11 13-15: >>4 <<11
static unsigned char const shifts [16 * 2] = {
13,12,12,12,12,12,12,12,12,12,12, 12, 12, 16, 16, 16,
0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11, 11, 11
};
int const scale = header >> 4;
int const right_shift = shifts [scale];
int const left_shift = shifts [scale + 16];
// Write to next four samples in circular buffer
int* pos = &v->buf [v->buf_pos];
if ( (v->buf_pos += 4) >= brr_buf_size )
v->buf_pos = 0;
// Decode four samples
for ( int* end = pos + 4; pos < end; pos++ )
{
// Extract upper nybble and scale appropriately
int s = ((int16_t) nybbles >> right_shift) << left_shift;
nybbles <<= 4;
// Apply IIR filter (8 is the most commonly used)
int const filter = header & 0x0C;
int const p1 = pos [brr_buf_size - 1];
int const p2 = pos [brr_buf_size - 2] >> 1;
if ( filter >= 8 )
{
s += p1;
s -= p2;
if ( filter == 8 ) // s += p1 * 0.953125 - p2 * 0.46875
{
s += p2 >> 4;
s += (p1 * -3) >> 6;
}
else // s += p1 * 0.8984375 - p2 * 0.40625
{
s += (p1 * -13) >> 7;
s += (p2 * 3) >> 4;
}
}
else if ( filter ) // s += p1 * 0.46875
{
s += p1 >> 1;
s += (-p1) >> 5;
}
// Adjust and write sample
CLAMP16( s );
s = (int16_t) (s * 2);
pos [brr_buf_size] = pos [0] = s; // second copy simplifies wrap-around
}
}
//// Misc
#define MISC_CLOCK( n ) inline static void misc_##n( void )
MISC_CLOCK( 27 )
{
m.t_pmon = REG(pmon) & 0xFE; // voice 0 doesn't support PMON
}
MISC_CLOCK( 28 )
{
m.t_non = REG(non);
m.t_eon = REG(eon);
m.t_dir = REG(dir);
}
MISC_CLOCK( 29 )
{
if ( (m.every_other_sample ^= 1) != 0 )
m.new_kon &= ~m.kon; // clears KON 63 clocks after it was last read
}
MISC_CLOCK( 30 )
{
if ( m.every_other_sample )
{
m.kon = m.new_kon;
m.t_koff = REG(koff) | m.mute_mask;
}
run_counters();
// Noise
if ( !read_counter( REG(flg) & 0x1F ) )
{
int feedback = (m.noise << 13) ^ (m.noise << 14);
m.noise = (feedback & 0x4000) ^ (m.noise >> 1);
}
}
//// Voices
#define VOICE_CLOCK( n ) static void voice_##n( voice_t* const v )
inline VOICE_CLOCK( V1 )
{
m.t_dir_addr = m.t_dir * 0x100 + m.t_srcn * 4;
m.t_srcn = VREG(v->regs,srcn);
}
inline VOICE_CLOCK( V2 )
{
// Read sample pointer (ignored if not needed)
uint8_t const* entry = &m_ram [m.t_dir_addr];
if ( !v->kon_delay )
entry += 2;
m.t_brr_next_addr = entry [1] * 0x100 + entry [0];
m.t_adsr0 = VREG(v->regs,adsr0);
// Read pitch, spread over two clocks
m.t_pitch = VREG(v->regs,pitchl);
}
inline VOICE_CLOCK( V3a )
{
m.t_pitch += (VREG(v->regs,pitchh) & 0x3F) << 8;
}
inline VOICE_CLOCK( V3b )
{
// Read BRR header and byte
m.t_brr_byte = m_ram [(v->brr_addr + v->brr_offset) & 0xFFFF];
m.t_brr_header = m_ram [v->brr_addr]; // brr_addr doesn't need masking
}
VOICE_CLOCK( V3c )
{
// Pitch modulation using previous voice's output
if ( m.t_pmon & v->vbit )
m.t_pitch += ((m.t_output >> 5) * m.t_pitch) >> 10;
if ( v->kon_delay )
{
// Get ready to start BRR decoding on next sample
if ( v->kon_delay == 5 )
{
v->brr_addr = m.t_brr_next_addr;
v->brr_offset = 1;
v->buf_pos = 0;
m.t_brr_header = 0; // header is ignored on this sample
}
// Envelope is never run during KON
v->env = 0;
v->hidden_env = 0;
// Disable BRR decoding until last three samples
v->interp_pos = 0;
if ( --v->kon_delay & 3 )
v->interp_pos = 0x4000;
// Pitch is never added during KON
m.t_pitch = 0;
}
// Gaussian interpolation
int output = interpolate( v );
// Noise
if ( m.t_non & v->vbit )
output = (int16_t) (m.noise * 2);
// Apply envelope
m.t_output = (output * v->env) >> 11 & ~1;
v->t_envx_out = v->env >> 4;
// Immediate silence due to end of sample or soft reset
if ( REG(flg) & 0x80 || (m.t_brr_header & 3) == 1 )
{
v->env_mode = env_release;
v->env = 0;
}
if ( m.every_other_sample )
{
// KOFF
if ( m.t_koff & v->vbit )
v->env_mode = env_release;
// KON
if ( m.kon & v->vbit )
{
v->kon_delay = 5;
v->env_mode = env_attack;
}
}
// Run envelope for next sample
if ( !v->kon_delay )
run_envelope( v );
}
static inline void voice_output( voice_t const* v, int ch )
{
// Apply left/right volume
int amp = (m.t_output * (int8_t) VREG(v->regs,voll + ch)) >> 7;
// Add to output total
m.t_main_out [ch] += amp;
CLAMP16( m.t_main_out [ch] );
// Optionally add to echo total
if ( m.t_eon & v->vbit )
{
m.t_echo_out [ch] += amp;
CLAMP16( m.t_echo_out [ch] );
}
}
VOICE_CLOCK( V4 )
{
// Decode BRR
m.t_looped = 0;
if ( v->interp_pos >= 0x4000 )
{
decode_brr( v );
if ( (v->brr_offset += 2) >= brr_block_size )
{
// Start decoding next BRR block
assert( v->brr_offset == brr_block_size );
v->brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF;
if ( m.t_brr_header & 1 )
{
v->brr_addr = m.t_brr_next_addr;
m.t_looped = v->vbit;
}
v->brr_offset = 1;
}
}
// Apply pitch
v->interp_pos = (v->interp_pos & 0x3FFF) + m.t_pitch;
// Keep from getting too far ahead (when using pitch modulation)
if ( v->interp_pos > 0x7FFF )
v->interp_pos = 0x7FFF;
// Output left
voice_output( v, 0 );
}
inline VOICE_CLOCK( V5 )
{
// Output right
voice_output( v, 1 );
// ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier
m.endx_buf = REG(endx) | m.t_looped;
// Clear bit in ENDX if KON just began
if ( v->kon_delay == 5 )
m.endx_buf &= ~v->vbit;
}
inline VOICE_CLOCK( V6 )
{
m.outx_buf = m.t_output >> 8;
}
inline VOICE_CLOCK( V7 )
{
// Update ENDX
REG(endx) = (uint8_t) m.endx_buf;
m.envx_buf = v->t_envx_out;
}
inline VOICE_CLOCK( V8 )
{
// Update OUTX
VREG(v->regs,outx) = (uint8_t) m.outx_buf;
}
inline VOICE_CLOCK( V9 )
{
// Update ENVX
VREG(v->regs,envx) = (uint8_t) m.envx_buf;
}
// Most voices do all these in one clock, so make a handy composite
inline VOICE_CLOCK( V3 )
{
voice_V3a( v );
voice_V3b( v );
voice_V3c( v );
}
// Common combinations of voice steps on different voices. This greatly reduces
// code size and allows everything to be inlined in these functions.
VOICE_CLOCK(V7_V4_V1) { voice_V7(v); voice_V1(v+3); voice_V4(v+1); }
VOICE_CLOCK(V8_V5_V2) { voice_V8(v); voice_V5(v+1); voice_V2(v+2); }
VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); }
//// Echo
// Current echo buffer pointer for left/right channel
#define ECHO_PTR( ch ) (&m_ram [m.t_echo_ptr + ch * 2])
// Sample in echo history buffer, where 0 is the oldest
#define ECHO_FIR( i ) (m.echo_hist_pos [i])
// Calculate FIR point for left/right channel
#define CALC_FIR( i, ch ) ((ECHO_FIR( i + 1 ) [ch] * (int8_t) REG(fir + i * 0x10)) >> 6)
#define ECHO_CLOCK( n ) inline static void echo_##n( void )
static inline void echo_read( int ch )
{
uint8_t const* in = ECHO_PTR( ch );
int s = (int8_t) in [1] * 0x100 + in [0];
// second copy simplifies wrap-around handling
ECHO_FIR( 0 ) [ch] = ECHO_FIR( 8 ) [ch] = s >> 1;
}
ECHO_CLOCK( 22 )
{
// History
if ( ++m.echo_hist_pos >= &m.echo_hist [spc_dsp_echo_hist_size] )
m.echo_hist_pos = m.echo_hist;
m.t_echo_ptr = (m.t_esa * 0x100 + m.echo_offset) & 0xFFFF;
echo_read( 0 );
// FIR (using l and r temporaries below helps compiler optimize)
int l = CALC_FIR( 0, 0 );
int r = CALC_FIR( 0, 1 );
m.t_echo_in [0] = l;
m.t_echo_in [1] = r;
}
ECHO_CLOCK( 23 )
{
int l = CALC_FIR( 1, 0 ) + CALC_FIR( 2, 0 );
int r = CALC_FIR( 1, 1 ) + CALC_FIR( 2, 1 );
m.t_echo_in [0] += l;
m.t_echo_in [1] += r;
echo_read( 1 );
}
ECHO_CLOCK( 24 )
{
int l = CALC_FIR( 3, 0 ) + CALC_FIR( 4, 0 ) + CALC_FIR( 5, 0 );
int r = CALC_FIR( 3, 1 ) + CALC_FIR( 4, 1 ) + CALC_FIR( 5, 1 );
m.t_echo_in [0] += l;
m.t_echo_in [1] += r;
}
ECHO_CLOCK( 25 )
{
int l = m.t_echo_in [0] + CALC_FIR( 6, 0 );
int r = m.t_echo_in [1] + CALC_FIR( 6, 1 );
l = (int16_t) l;
r = (int16_t) r;
l += (int16_t) CALC_FIR( 7, 0 );
r += (int16_t) CALC_FIR( 7, 1 );
CLAMP16( l );
CLAMP16( r );
m.t_echo_in [0] = l & ~1;
m.t_echo_in [1] = r & ~1;
}
static inline int echo_output( int ch )
{
int out = (int16_t) ((m.t_main_out [ch] * (int8_t) REG(mvoll + ch * 0x10)) >> 7) +
(int16_t) ((m.t_echo_in [ch] * (int8_t) REG(evoll + ch * 0x10)) >> 7);
CLAMP16( out );
return out;
}
ECHO_CLOCK( 26 )
{
// Left output volumes
// (save sample for next clock so we can output both together)
m.t_main_out [0] = echo_output( 0 );
// Echo feedback
int l = m.t_echo_out [0] + (int16_t) ((m.t_echo_in [0] * (int8_t) REG(efb)) >> 7);
int r = m.t_echo_out [1] + (int16_t) ((m.t_echo_in [1] * (int8_t) REG(efb)) >> 7);
CLAMP16( l );
CLAMP16( r );
m.t_echo_out [0] = l & ~1;
m.t_echo_out [1] = r & ~1;
}
ECHO_CLOCK( 27 )
{
// Output
int outl = m.t_main_out [0];
int outr = echo_output( 1 );
m.t_main_out [0] = 0;
m.t_main_out [1] = 0;
// TODO: global muting isn't this simple (turns DAC on and off
// or something, causing small ~37-sample pulse when first muted)
if ( REG(flg) & 0x40 )
{
outl = 0;
outr = 0;
}
// Output sample to DAC
#ifdef SPC_DSP_OUT_HOOK
SPC_DSP_OUT_HOOK( outl, outr );
#else
spc_dsp_sample_t* out = m_spc_dsp_out;
assert( !out || out < m_spc_dsp_out_end ); // fails if output buffer is too small
if ( out != m_spc_dsp_out_end )
{
out [0] = outl;
out [1] = outr;
m_spc_dsp_out = out + 2;
}
#endif
}
ECHO_CLOCK( 28 )
{
m.t_echo_enabled = REG(flg);
}
static inline void echo_write( int ch )
{
if ( !(m.t_echo_enabled & 0x20) )
{
uint8_t* out = ECHO_PTR( ch );
int s = m.t_echo_out [ch];
out [0] = (uint8_t) s;
out [1] = (uint8_t) (s >> 8);
}
m.t_echo_out [ch] = 0;
}
ECHO_CLOCK( 29 )
{
m.t_esa = REG(esa);
if ( !m.echo_offset )
m.echo_length = (REG(edl) & 0x0F) * 0x800;
m.echo_offset += 4;
if ( m.echo_offset >= m.echo_length )
m.echo_offset = 0;
// Write left echo
echo_write( 0 );
m.t_echo_enabled = REG(flg);
}
ECHO_CLOCK( 30 )
{
// Write right echo
echo_write( 1 );
}
//// Timing
#if !SPC_DSP_CUSTOM_RUN
void spc_dsp_run( int clocks_remain )
{
assert( clocks_remain > 0 );
int const phase = m.phase;
m.phase = (phase + clocks_remain) & 31;
switch ( phase )
{
loop:
#define PHASE( n ) if ( n && !--clocks_remain ) break; case n:
#include "spc_dsp_timing.h"
#undef PHASE
if ( --clocks_remain )
goto loop;
}
}
#endif
//// Setup
void spc_dsp_reset( void )
{
// Clear everything to zero, then set things which must be non-zero
memset( m_voice_state, 0, sizeof m_voice_state );
memset( &m_spc_dsp, 0, sizeof m_spc_dsp );
m.noise = 1;
m.echo_hist_pos = m.echo_hist;
m.every_other_sample = 1;
init_counters();
int i;
for ( i = spc_dsp_voice_count; --i >= 0; )
{
voice_t* v = &m_voice_state [i];
v->regs = &m.regs [i * 0x10];
v->vbit = 1 << i;
v->brr_offset = 1;
}
REG(flg) = 0xE0;
}
void spc_dsp_soft_reset( void )
{
// TODO: doesn't reset everything
spc_dsp_reset();
}
void spc_dsp_init( void* ram_64k )
{
m_ram = (uint8_t*) ram_64k;
spc_dsp_reset();
#if INT_MAX < 0x7FFFFFFF
#error "Requires that int have at least 32 bits"
#endif
#ifndef NDEBUG
// be sure this sign-extends
assert( (int16_t) 0x8000 == -0x8000 );
// be sure right shift preserves sign
assert( (-1 >> 1) == -1 );
// check clamp macro
int i;
i = +0x8000; CLAMP16( i ); assert( i == +0x7FFF );
i = -0x8001; CLAMP16( i ); assert( i == -0x8000 );
#endif
}
void spc_dsp_load( uint8_t const regs [spc_dsp_register_count] )
{
int i;
for ( i = 0; i < 0x80; i++ )
spc_dsp_write( i, regs [i] );
m.t_esa = regs [r_esa];
m.t_dir = regs [r_dir];
}

View File

@@ -0,0 +1,162 @@
// SNES SPC-700 DSP emulator
#ifndef SPC_DSP_H
#define SPC_DSP_H
#include <assert.h>
#include <stdint.h>
//// Setup
// Initializes DSP and has it use the 64K RAM provided
void spc_dsp_init( void* ram_64k );
// Restores DSP registers using supplied values
enum { spc_dsp_register_count = 128 };
void spc_dsp_load( uint8_t const regs [spc_dsp_register_count] );
// Mutes voice n if bit 1<<b is set
enum { spc_dsp_voice_count = 8 };
static void spc_dsp_mute_voices( int mask );
// Sets destination for output samples. If out is NULL or out_size is 0,
// doesn't generate any.
typedef short spc_dsp_sample_t;
static void spc_dsp_set_output( spc_dsp_sample_t* out, int out_size );
// Number of samples written to output since it was last set, always
// a multiple of 2
static int spc_dsp_sample_count( void );
//// Emulation
// Resets DSP to power-on state. Does not affect anything set by above functions.
void spc_dsp_reset( void );
// Emulates pressing reset switch on SNES
void spc_dsp_soft_reset( void );
// Reads/writes DSP registers. For accuracy, you must first call spc_run_dsp()
// to catch the DSP up to present.
static int spc_dsp_read( int addr );
static void spc_dsp_write( int addr, int data );
// Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks
// a pair of samples will be generated.
void spc_dsp_run( int clock_count );
//// private
enum { spc_dsp_echo_hist_size = 8 };
extern spc_dsp_sample_t* m_spc_dsp_out_begin;
extern spc_dsp_sample_t* m_spc_dsp_out;
extern spc_dsp_sample_t* m_spc_dsp_out_end;
typedef struct spc_dsp_t
{
uint8_t regs [spc_dsp_register_count];
// Echo history keeps most recent 8 samples (twice the size to simplify wrap handling)
int echo_hist [spc_dsp_echo_hist_size * 2] [2];
int (*echo_hist_pos) [2]; // &echo_hist [0 to 7]
int mute_mask;
int every_other_sample; // toggles every sample
int kon; // KON value when last checked
int noise;
int counter;
int echo_offset; // offset from ESA in echo buffer
int echo_length; // number of bytes that echo_offset will stop at
int phase; // next clock cycle to run (0-31)
// Hidden registers also written to when main register is written to
int new_kon;
int endx_buf;
int envx_buf;
int outx_buf;
// Temporary state between clocks
// read once per sample
int t_pmon;
int t_non;
int t_eon;
int t_dir;
int t_koff;
// read a few clocks ahead then used
int t_brr_next_addr;
int t_adsr0;
int t_brr_header;
int t_brr_byte;
int t_srcn;
int t_esa;
int t_echo_enabled;
// internal state that is recalculated every sample
int t_dir_addr;
int t_pitch;
int t_output;
int t_looped;
int t_echo_ptr;
// left/right sums
int t_main_out [2];
int t_echo_out [2];
int t_echo_in [2];
} spc_dsp_t;
extern spc_dsp_t m_spc_dsp;
static inline int spc_dsp_read( int addr )
{
assert( (unsigned) addr < spc_dsp_register_count );
return m_spc_dsp.regs [addr];
}
static inline void spc_dsp_write( int addr, int data )
{
assert( (unsigned) addr < spc_dsp_register_count );
m_spc_dsp.regs [addr] = data;
switch ( addr & 0x0F )
{
case 0x08:
m_spc_dsp.envx_buf = data;
break;
case 0x09:
m_spc_dsp.outx_buf = data;
break;
case 0x0C:
if ( addr == 0x4C ) // KON
m_spc_dsp.new_kon = data;
if ( addr == 0x7C ) // ENDX, write always clears it regardless of data
{
m_spc_dsp.endx_buf = 0;
m_spc_dsp.regs [0x7C] = 0;
}
break;
}
}
static inline void spc_dsp_mute_voices( int mask ) { m_spc_dsp.mute_mask = mask; }
static inline void spc_dsp_set_output( spc_dsp_sample_t* out, int out_size )
{
assert( out_size % 2 == 0 ); // must be even
m_spc_dsp_out_begin = out;
m_spc_dsp_out = out;
if ( out )
out += out_size;
m_spc_dsp_out_end = out;
}
static inline int spc_dsp_sample_count( void ) { return m_spc_dsp_out - m_spc_dsp_out_begin; }
#endif

View File

@@ -0,0 +1,46 @@
// Execute clock for a particular voice
#define V( clock, voice ) voice_##clock( &m_voice_state [voice] );
/* The most common sequence of clocks uses composite operations
for efficiency. For example, the following are equivalent to the
individual steps on the right:
V(2_31 ,2) -> V( 2,2) V(31,3)
V(3_0_29,2) -> V( 3,2) V( 0,3) V(29,4)
V(4_1_30,2) -> V( 4,2) V( 1,3) V(30,4) */
// Voice 0 1 2 3 4 5 6 7
PHASE( 0) V(V5,0)V(V2,1)
PHASE( 1) V(V6,0)V(V3,1)
PHASE( 2) V(V7_V4_V1,0)
PHASE( 3) V(V8_V5_V2,0)
PHASE( 4) V(V9_V6_V3,0)
PHASE( 5) V(V7_V4_V1,1)
PHASE( 6) V(V8_V5_V2,1)
PHASE( 7) V(V9_V6_V3,1)
PHASE( 8) V(V7_V4_V1,2)
PHASE( 9) V(V8_V5_V2,2)
PHASE(10) V(V9_V6_V3,2)
PHASE(11) V(V7_V4_V1,3)
PHASE(12) V(V8_V5_V2,3)
PHASE(13) V(V9_V6_V3,3)
PHASE(14) V(V7_V4_V1,4)
PHASE(15) V(V8_V5_V2,4)
PHASE(16) V(V9_V6_V3,4)
PHASE(17) V(V1,0) V(V7,5)V(V4,6)
PHASE(18) V(V8_V5_V2,5)
PHASE(19) V(V9_V6_V3,5)
PHASE(20) V(V1,1) V(V7,6)V(V4,7)
PHASE(21) V(V8,6)V(V5,7) V(V2,0) // t_brr_next_addr order dependency
PHASE(22) V(V3a,0) V(V9,6)V(V6,7) echo_22();
PHASE(23) V(V7,7) echo_23();
PHASE(24) V(V8,7) echo_24();
PHASE(25) V(V3b,0) V(V9,7) echo_25();
PHASE(26) echo_26();
PHASE(27) misc_27(); echo_27();
PHASE(28) misc_28(); echo_28();
PHASE(29) misc_29(); echo_29();
PHASE(30) misc_30();V(V3c,0) echo_30();
PHASE(31) V(V4,0) V(V1,2)
#undef V

View File

@@ -0,0 +1,43 @@
// Byte order handling
#ifndef SPC_ENDIAN_H
#define SPC_ENDIAN_H
//#include <stdint.h>
static inline unsigned get_le16( void const* p )
{
return ((uint8_t const*) p) [1] * 0x100u +
((uint8_t const*) p) [0];
}
static inline int get_le16s( void const* p )
{
return ((int8_t const*) p) [1] * 0x100 +
((uint8_t const*) p) [0];
}
static inline void set_le16( void* p, unsigned n )
{
((uint8_t*) p) [1] = (uint8_t) (n >> 8);
((uint8_t*) p) [0] = (uint8_t) n;
}
// *A versions are used where data is aligned
// Sometimes BIG_ENDIAN is defined to 0x1234 or something, so treat values
// other than 1 as false.
#if BIG_ENDIAN != 1
#define GET_LE16A( addr ) (*(uint16_t const*) (addr))
#define GET_LE16SA( addr ) (*( int16_t const*) (addr))
#define SET_LE16A( addr, data ) (void) (*(uint16_t*) (addr) = (data))
#else
#define GET_LE16A( addr ) get_le16 ( addr )
#define GET_LE16SA( addr ) get_le16s( addr )
#define SET_LE16A( addr, data ) set_le16 ( addr, data )
#endif
#define GET_LE16( addr ) GET_LE16A( addr )
#define SET_LE16( addr, data ) SET_LE16A( addr, data )
#endif

View File

@@ -1,11 +1,11 @@
class DSP {
public:
class DSP { public:
virtual void enter() = 0;
virtual uint8 read (uint8 addr) = 0;
virtual void write(uint8 addr, uint8 data) = 0;
virtual void power() = 0;
virtual void reset() = 0;
virtual uint32 run() = 0;
DSP() {}
virtual ~DSP() {}

View File

@@ -25,6 +25,7 @@
#include "smp/ssmp/ssmp.h"
#include "dsp/dsp.h"
//#include "dsp/adsp/adsp.h"
#include "dsp/bdsp/bdsp.h"
#include "ppu/ppu.h"
@@ -32,12 +33,16 @@
#include "snes/snes.h"
#include "chip/superfx/superfx.h"
#include "chip/srtc/srtc.h"
#include "chip/sdd1/sdd1.h"
#include "chip/c4/c4.h"
#include "chip/dsp1/dsp1.h"
#include "chip/dsp2/dsp2.h"
#include "chip/dsp3/dsp3.h"
#include "chip/dsp4/dsp4.h"
#include "chip/obc1/obc1.h"
#include "chip/st010/st010.h"
extern MMIO mmio_unmapped;
#ifdef POLYMORPHISM

View File

@@ -1,9 +1,9 @@
/*
libarray : version 0.07 ~byuu (10/14/06)
libarray : version 0.09 ~byuu (2007-03-06)
*/
#ifndef __LIBARRAY
#define __LIBARRAY
#ifndef LIBARRAY_H
#define LIBARRAY_H
template<typename T> class array {
protected:
@@ -25,14 +25,10 @@ protected:
public:
uint size() { return buffersize; }
uint capacity() { return buffersize; }
uint capacity() { return poolsize; }
void reset() {
if(pool) {
free(pool);
pool = 0;
}
safe_free(pool);
poolsize = 0;
buffersize = 0;
}
@@ -44,7 +40,7 @@ public:
buffersize = size;
}
pool = static_cast<T*>(realloc(pool, sizeof(T) * size));
pool = (T*)realloc(pool, sizeof(T) * size);
poolsize = size;
}
@@ -69,6 +65,17 @@ public:
~array() { reset(); }
array &operator=(array &source) {
safe_free(pool);
buffersize = source.buffersize;
poolsize = source.poolsize;
//allocate entire pool size ...
pool = (T*)realloc(pool, sizeof(T) * poolsize);
//... but only copy used pool objects
memcpy(pool, source.pool, sizeof(T) * buffersize);
return *this;
}
inline T &operator[](int index) {
if(index >= buffersize)resize(index + 1);
if(index >= buffersize)throw "array[] out of bounds";

View File

@@ -1,17 +1,55 @@
/*
libbase : version 0.08f ~byuu (2006-11-07)
libbase : version 0.11 ~byuu (2007-09-08)
license: public domain
*/
#ifndef __LIBBASE
#define __LIBBASE
#ifndef LIBBASE_H
#define LIBBASE_H
#include <assert.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <new>
#if defined(_MSC_VER) || defined(__MINGW32__)
#include <io.h>
#include <direct.h>
#include <shlobj.h>
#else
#include <unistd.h>
#include <pwd.h>
#include <sys/stat.h>
#endif
#if defined(_MSC_VER)
//disable libc deprecation warnings in MSVC 2k5+
#pragma warning(disable:4996)
#define NOMINMAX
#define PATH_MAX _MAX_PATH
#define va_copy(dst, src) ((dst) = (src))
#endif
#if defined(_MSC_VER) || defined(__MINGW32__)
#define getcwd _getcwd
#define ftruncate _chsize
#define mkdir _mkdir
#define putenv _putenv
#define rmdir _rmdir
#define vsnprintf _vsnprintf
static char *realpath(const char *file_name, char *resolved_name) {
return _fullpath(resolved_name, file_name, PATH_MAX);
}
#else
#define mkdir(path) (mkdir)(path, 0755);
#endif
/*****
@@ -22,62 +60,53 @@
#define noinline __declspec(noinline)
#define inline inline
#define alwaysinline __forceinline
#define fastcall __fastcall
#elif defined(__GNUC__)
#define noinline
#define noinline __attribute__((noinline))
#define inline inline
#define alwaysinline inline
#define fastcall __attribute__((fastcall))
#define alwaysinline __attribute__((always_inline))
#else
#define noinline
#define inline inline
#define alwaysinline inline
#define fastcall
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <io.h>
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE !FALSE
#endif
//deprecated
#define SafeFree(__n) if(__n) { free(__n); __n = 0; }
#define SafeDelete(__n) if(__n) { delete(__n); __n = 0; }
#define SafeRelease(__n) if(__n) { __n->Release(); __n = 0; }
/*****
* typedefs
*****/
typedef unsigned int uint;
typedef signed int sint;
typedef unsigned int uint;
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long ulong;
typedef unsigned long long uquad;
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef unsigned char bool8;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned long uint32;
typedef unsigned long long uint64;
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef signed char int8;
typedef signed short int16;
typedef signed long int32;
typedef signed long long int64;
/*****
* OS localization
*****/
//userpath(output) retrieves path to user's home folder
//output must be at least as large as PATH_MAX
#if defined(_MSC_VER) || defined(__MINGW32__)
static char *userpath(char *output) {
strcpy(output, "."); //failsafe
SHGetFolderPath(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, output);
return output;
}
#else
static char *userpath(char *output) {
strcpy(output, "."); //failsafe
struct passwd *userinfo = getpwuid(getuid());
if(userinfo) { strcpy(output, userinfo->pw_dir); }
return output;
}
#endif
/*****
* templates
@@ -110,133 +139,66 @@ T z = x;
y = z;
}
#ifdef min
#undef min
#endif
#define min(x, y) ((x < y) ? x : y)
#define min(x, y) (((x) < (y)) ? (x) : (y))
#ifdef max
#undef max
#endif
#define max(x, y) ((x > y) ? x : y)
#define max(x, y) (((x) > (y)) ? (x) : (y))
template<int min, int max, typename T> inline T minmax(const T x) {
return (x < (T)min) ? (T)min : (x > (T)max) ? (T)max : x;
}
template<int bits> inline unsigned uclamp(const unsigned x) {
enum { m = (1 << bits) - 1 };
return (x > m) ? m : x;
enum { y = (1U << bits) - 1 };
return y + ((x - y) & -(x < y)); //min(x, y);
}
template<int bits> inline unsigned uclip(const unsigned x) {
enum { m = (1 << bits) - 1 };
enum { m = (1U << bits) - 1 };
return (x & m);
}
template<int bits> inline signed sclamp(const signed x) {
enum { b = 1 << (bits - 1), m = (1 << (bits - 1)) - 1 };
enum { b = 1U << (bits - 1), m = (1U << (bits - 1)) - 1 };
return (x > m) ? m : (x < -b) ? -b : x;
}
template<int bits> inline signed sclip(const signed x) {
enum { b = 1 << (bits - 1), m = (1 << (bits - 1)) - 1 };
return (x & b) ? (x | ~m) : (x & m);
enum { b = 1U << (bits - 1), m = (1U << bits) - 1 };
return ((x & m) ^ b) - b;
}
//requires compiler arithmetic shift right support
//c++ standard does not define whether >> is arithmetic or logical
//template<int bits> inline signed sclip(const signed x) {
//enum { s = sizeof(x) * 8 - bits };
// return (x << s) >> s;
//}
//bit shifting functions are deprecated
template<int bits, typename T> inline T rol(const T x) {
enum { s = (sizeof(T) << 3) - bits };
return (x << bits) | (x >> s);
template<int n, typename T> inline T rol(const T x) {
enum { s = (sizeof(T) << 3) - n };
return (x << n) | (x >> s);
}
template<int bits, typename T> inline T ror(const T x) {
enum { s = (sizeof(T) << 3) - bits };
return (x >> bits) | (x << s);
template<int n, typename T> inline T ror(const T x) {
enum { s = (sizeof(T) << 3) - n };
return (x >> n) | (x << s);
}
template<int bits, typename T> inline T asl(const T x) {
return (x << bits);
template<int n, typename T> inline T asl(const T x) {
return (x << n);
}
template<int bits, typename T> inline T asr(const T x) {
enum { h = 1 << ((sizeof(T) << 3) - 1) };
enum { m = ~((1 << ((sizeof(T) << 3) - bits)) - 1) };
return (x >> bits) | ((0 - !!(x & h)) & m);
template<int n, typename T> inline T asr(const T x) {
enum { bits = (sizeof(T) << 3) - n };
return sclip<bits>(x >> n);
}
template<int bits, typename T> inline T lsl(const T x) {
return (x << bits);
template<int n, typename T> inline T lsl(const T x) {
return (x << n);
}
template<int bits, typename T> inline T lsr(const T x) {
enum { m = ((1 << ((sizeof(T) << 3) - bits)) - 1) };
return (x >> bits) & m;
template<int n, typename T> inline T lsr(const T x) {
enum { bits = (sizeof(T) << 3) - n };
return uclip<bits>(x >> n);
}
template<unsigned bits, typename base = uint> class uint_t {
private:
base data;
public:
inline operator unsigned() const { return data; }
inline unsigned operator ++(int) { base r = data; data = uclip<bits>(data + 1); return r; }
inline unsigned operator --(int) { base r = data; data = uclip<bits>(data - 1); return r; }
inline unsigned operator ++() { data = uclip<bits>(data + 1); return data; }
inline unsigned operator --() { data = uclip<bits>(data - 1); return data; }
template<typename T> inline unsigned operator =(const T i) { data = uclip<bits>(i); return data; }
template<typename T> inline unsigned operator |=(const T i) { data = uclip<bits>(data | i); return data; }
template<typename T> inline unsigned operator ^=(const T i) { data = uclip<bits>(data ^ i); return data; }
template<typename T> inline unsigned operator &=(const T i) { data = uclip<bits>(data & i); return data; }
template<typename T> inline unsigned operator<<=(const T i) { data = uclip<bits>(data << i); return data; }
template<typename T> inline unsigned operator>>=(const T i) { data = uclip<bits>(data >> i); return data; }
template<typename T> inline unsigned operator +=(const T i) { data = uclip<bits>(data + i); return data; }
template<typename T> inline unsigned operator -=(const T i) { data = uclip<bits>(data - i); return data; }
template<typename T> inline unsigned operator *=(const T i) { data = uclip<bits>(data * i); return data; }
template<typename T> inline unsigned operator /=(const T i) { data = uclip<bits>(data / i); return data; }
template<typename T> inline unsigned operator %=(const T i) { data = uclip<bits>(data % i); return data; }
inline uint_t() : data(0) {}
inline uint_t(const base i) : data(uclip<bits>(i)) {}
};
template<unsigned bits, typename base = int> class int_t {
private:
base data;
public:
inline operator signed() const { return data; }
inline signed operator ++(int) { base r = data; data = sclip<bits>(data + 1); return r; }
inline signed operator --(int) { base r = data; data = sclip<bits>(data - 1); return r; }
inline signed operator ++() { data = sclip<bits>(data + 1); return data; }
inline signed operator --() { data = sclip<bits>(data - 1); return data; }
template<typename T> inline signed operator =(const T i) { data = sclip<bits>(i); return data; }
template<typename T> inline signed operator |=(const T i) { data = sclip<bits>(data | i); return data; }
template<typename T> inline signed operator ^=(const T i) { data = sclip<bits>(data ^ i); return data; }
template<typename T> inline signed operator &=(const T i) { data = sclip<bits>(data & i); return data; }
template<typename T> inline signed operator<<=(const T i) { data = sclip<bits>(data << i); return data; }
template<typename T> inline signed operator>>=(const T i) { data = sclip<bits>(data >> i); return data; }
template<typename T> inline signed operator +=(const T i) { data = sclip<bits>(data + i); return data; }
template<typename T> inline signed operator -=(const T i) { data = sclip<bits>(data - i); return data; }
template<typename T> inline signed operator *=(const T i) { data = sclip<bits>(data * i); return data; }
template<typename T> inline signed operator /=(const T i) { data = sclip<bits>(data / i); return data; }
template<typename T> inline signed operator %=(const T i) { data = sclip<bits>(data % i); return data; }
inline int_t() : data(0) {}
inline int_t(const base i) : data(sclip<bits>(i)) {}
};
typedef uint_t<24> uint24;
typedef int_t<24> int24;
typedef uint_t<48, uint64> uint48;
typedef int_t<48, int64> int48;
/*****
* endian wrappers
*****/
@@ -279,88 +241,18 @@ typedef int_t<48, int64> int48;
* libc extensions
*****/
static uint8 fgetb(FILE *fp) { return fgetc(fp); }
static uint8 fgetlb(FILE *fp) { return fgetc(fp); }
static uint8 fgetmb(FILE *fp) { return fgetc(fp); }
static uint16 fgetlw(FILE *fp) {
return (fgetc(fp)) | (fgetc(fp) << 8);
static uint64 fget(FILE *fp, uint length = 1) {
uint64 data = 0;
for(uint i = 0; i < length; i++) {
data |= fgetc(fp) << (i << 3);
}
return data;
}
static uint16 fgetmw(FILE *fp) {
return (fgetc(fp) << 8) | (fgetc(fp) << 8);
}
static uint32 fgetld(FILE *fp) {
return (fgetc(fp)) | (fgetc(fp) << 8) | (fgetc(fp) << 16) | (fgetc(fp) << 24);
}
static uint32 fgetmd(FILE *fp) {
return (fgetc(fp) << 24) | (fgetc(fp) << 16) | (fgetc(fp) << 8) | (fgetc(fp));
}
static uint64 fgetlq(FILE *fp) {
return ((uint64)fgetc(fp) << 0) | ((uint64)fgetc(fp) << 8) |
((uint64)fgetc(fp) << 16) | ((uint64)fgetc(fp) << 24) |
((uint64)fgetc(fp) << 32) | ((uint64)fgetc(fp) << 40) |
((uint64)fgetc(fp) << 48) | ((uint64)fgetc(fp) << 56);
}
static uint64 fgetmq(FILE *fp) {
return ((uint64)fgetc(fp) << 56) | ((uint64)fgetc(fp) << 48) |
((uint64)fgetc(fp) << 40) | ((uint64)fgetc(fp) << 32) |
((uint64)fgetc(fp) << 24) | ((uint64)fgetc(fp) << 16) |
((uint64)fgetc(fp) << 8) | ((uint64)fgetc(fp) << 0);
}
static void fputb(FILE *fp, uint8 data) { fputc(data, fp); }
static void fputlb(FILE *fp, uint8 data) { fputc(data, fp); }
static void fputmb(FILE *fp, uint8 data) { fputc(data, fp); }
static void fputlw(FILE *fp, uint16 data) {
fputc(data >> 0, fp);
fputc(data >> 8, fp);
}
static void fputmw(FILE *fp, uint16 data) {
fputc(data >> 8, fp);
fputc(data >> 0, fp);
}
static void fputld(FILE *fp, uint32 data) {
fputc(data >> 0, fp);
fputc(data >> 8, fp);
fputc(data >> 16, fp);
fputc(data >> 24, fp);
}
static void fputmd(FILE *fp, uint32 data) {
fputc(data >> 24, fp);
fputc(data >> 16, fp);
fputc(data >> 8, fp);
fputc(data >> 0, fp);
}
static void fputlq(FILE *fp, uint64 data) {
fputc(data >> 0, fp);
fputc(data >> 8, fp);
fputc(data >> 16, fp);
fputc(data >> 24, fp);
fputc(data >> 32, fp);
fputc(data >> 40, fp);
fputc(data >> 48, fp);
fputc(data >> 56, fp);
}
static void fputmq(FILE *fp, uint64 data) {
fputc(data >> 56, fp);
fputc(data >> 48, fp);
fputc(data >> 40, fp);
fputc(data >> 32, fp);
fputc(data >> 24, fp);
fputc(data >> 16, fp);
fputc(data >> 8, fp);
fputc(data >> 0, fp);
static void fput(FILE *fp, uint64 data, uint length = 1) {
for(uint i = 0; i < length; i++) {
fputc(data >> (i << 3), fp);
}
}
static bool fexists(const char *fn) {
@@ -390,7 +282,9 @@ uint32 size = ftell(fp);
return size;
}
static int ftruncate(FILE *fp, long size) { return ftruncate(fileno(fp), size); }
static int fresize(FILE *fp, long size) {
return ftruncate(fileno(fp), size);
}
/*****
* crc32 calculation

View File

@@ -1,70 +0,0 @@
/*
libco_win32 : version 0.08 ~byuu (10/21/06)
win32-x86 implementation of libco
*/
#define WINVER 0x0400
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include "libco_win32.h"
struct cothread_struct {
void *cohandle;
cothread_p coentry;
cothread_t colink;
};
cothread_t __co_active = 0, __co_primary = 0;
void __stdcall co_entryproc(void *coentry) {
cothread_struct *s = static_cast<cothread_struct*>(coentry);
s->coentry();
co_exit(0);
}
cothread_t co_init() {
ConvertThreadToFiber(0);
cothread_struct *s = static_cast<cothread_struct*>(malloc(sizeof(cothread_struct)));
s->colink = 0;
s->coentry = 0;
s->cohandle = GetCurrentFiber();
__co_active = __co_primary = static_cast<cothread_t>(s);
return __co_active;
}
void co_term() {
//primary fiber cannot be deleted; free memory used by handle to fiber only
free(__co_primary);
//ConvertFiberToThread(); //only exists on WinXP+
}
cothread_t co_active() {
return __co_active;
}
cothread_t co_create(cothread_p coentry, unsigned int heapsize) {
cothread_struct *s = static_cast<cothread_struct*>(malloc(sizeof(cothread_struct)));
s->colink = co_active();
s->coentry = coentry;
s->cohandle = CreateFiber(heapsize + 512, co_entryproc, static_cast<void*>(s));
return static_cast<cothread_t>(s);
}
void co_delete(cothread_t cothread) {
cothread_struct *s = static_cast<cothread_struct*>(cothread);
DeleteFiber(s->cohandle);
free(cothread);
}
void co_switch(cothread_t cothread) {
__co_active = cothread;
cothread_struct *s = static_cast<cothread_struct*>(cothread);
SwitchToFiber(s->cohandle);
}
void co_exit(cothread_t cothread) {
if(cothread != 0) { co_switch(cothread); }
cothread_struct *s = static_cast<cothread_struct*>(__co_active);
co_switch(s->colink);
}

View File

@@ -1,20 +0,0 @@
/*
libco_win32 : version 0.08 ~byuu (10/21/2006)
*/
#define COTHREAD_STACKSIZE_TINY 0x1000
#define COTHREAD_STACKSIZE_SMALL 0x4000
#define COTHREAD_STACKSIZE_NORMAL 0x10000
#define COTHREAD_STACKSIZE_LARGE 0x40000
#define COTHREAD_STACKSIZE_HUGE 0x100000
typedef void (*cothread_t);
typedef void (*cothread_p)(void);
cothread_t co_init();
void co_term();
cothread_t co_active();
cothread_t co_create(cothread_p coentry, unsigned int heapsize);
void co_delete(cothread_t cothread);
void co_switch(cothread_t cothread);
void co_exit(cothread_t cothread);

View File

@@ -1,88 +1,69 @@
;*****
;libco_x86 : version 0.08 ~byuu (10/21/06)
;libco_x86 : version 0.10 ~byuu (2007-09-08)
;cross-platform x86 implementation of libco
;special thanks to Aaron Giles and Joel Yliluoma for various optimizations
;
;context save/restore adheres to c/c++ ABI
;for x86 windows, osx, linux and freebsd
;[ABI compatibility]
;- visual c++; windows; x86
;- mingw; windows; x86
;- gcc; mac os x; x86
;- gcc; linux; x86
;- gcc; freebsd; x86
;
;context saves esp+ebp+esi+edi+ebx
;context ignores eax+ecx+edx
;context ignores st([0-7])+xmm[0-15]
;context ignores all else
;[nonvolatile registers]
;- esp, ebp, edi, esi, ebx
;
;[volatile registers]
;- eax, ecx, edx
;- st0 - st7
;- xmm0 - xmm15
;*****
section .data
align 4
co_active_context dd 0
co_primary_context dd 0
section .code
;*****
;linker-specific name decorations
;*****
%ifdef WIN32
%define malloc _malloc
%define free _free
%define co_init @co_init@0
%define co_term @co_term@0
%define co_active @co_active@0
%define co_create @co_create@8
%define co_delete @co_delete@4
%define co_switch @co_switch@4
%define co_exit @co_exit@4
%endif
%ifdef OSX86
%define malloc _malloc
%define free _free
%define co_init _co_init
%define co_term _co_term
%define co_active _co_active
%define co_create _co_create
%define co_delete _co_delete
%define co_switch _co_switch
%define co_exit _co_exit
%endif
bits 32
section .bss
align 4
co_primary_buffer resb 512
section .data
align 4
co_active_context dd co_primary_buffer
section .text
extern malloc
extern free
global co_init
global co_term
global co_active
global co_create
global co_delete
global co_switch
global co_exit
;*****
;extern "C" cothread_t fastcall co_init();
;return = eax
;*****
align 16
co_init:
;create context for main cothread
mov ecx,0 ;entry point for main thread is not needed
mov edx,512 ;main cothread uses default program stack
call co_create
mov dword[co_active_context],eax
mov dword[co_primary_context],eax
ret
;*****
;extern "C" void fastcall co_term();
;*****
align 16
co_term:
mov ecx,dword[co_primary_context]
call co_delete
ret
;*****
;extern "C" cothread_t fastcall co_active();
@@ -91,47 +72,43 @@ co_term:
align 16
co_active:
mov eax,dword[co_active_context]
mov eax,[co_active_context]
ret
;*****
;extern "C" cothread_t fastcall co_create(cothread_p coentry, unsigned int heapsize);
;ecx = coentry
;edx = heapsize
;extern "C" cothread_t fastcall co_create(unsigned int heapsize, void (*coentry)());
;ecx = heapsize
;edx = coentry
;return = eax
;*****
align 16
co_create:
;create heap space (stack + register storage)
add edx,512 ;+4(esp)+4(coentry)+4(colink)+256(stack_align)
add ecx,512 ;allocate extra memory for contextual info
push ecx
push edx
push edx
call malloc
push ecx
call malloc ;eax = malloc(edx)
add esp,4
pop edx
pop ecx
add edx,eax ;set edx to point to top of stack heap
and edx,0xffffff00 ;force 256-byte alignment of stack heap
add ecx,eax ;set edx to point to top of stack heap
and ecx,-16 ;force 16-byte alignment of stack heap
;store thread entry point + registers so that first call to co_switch will execute coentry
mov dword[edx-4],co_entrypoint ;edx=*stack
mov dword[edx-8],0
mov dword[edx-12],0
mov dword[edx-16],0
mov dword[edx-20],0
sub edx,20
;initialize context memory heap
mov dword[eax],edx ;cothread_t[ 0- 3] = stack heap pointer (esp)
mov dword[eax+4],ecx ;cothread_t[ 4- 7] = entry point
mov ecx,dword[co_active_context]
mov dword[eax+8],ecx ;cothread_t[ 8-11] = return context
;store thread entry point + registers, so that first call to co_switch will execute coentry
mov dword[ecx-4],edx ;entry point
mov dword[ecx-8],0 ;ebp
mov dword[ecx-12],0 ;esi
mov dword[ecx-16],0 ;edi
mov dword[ecx-20],0 ;ebx
sub ecx,20
;initialize context memory heap and return
mov [eax],ecx ;*cothread_t = stack heap pointer (esp)
ret ;return allocated memory block as thread handle
;*****
@@ -142,7 +119,7 @@ co_create:
align 16
co_delete:
push ecx
call free
call free ;free(ecx)
add esp,4
ret
@@ -153,45 +130,19 @@ co_delete:
align 16
co_switch:
mov eax,dword[co_active_context] ;backup current context
mov dword[co_active_context],ecx ;set new active context
mov eax,[co_active_context] ;backup current context
mov [co_active_context],ecx ;set new active context
push ebp
push esi
push edi
push ebx
mov dword[eax],esp
mov [eax],esp
mov esp,dword[ecx]
mov esp,[ecx]
pop ebx
pop edi
pop esi
pop ebp
ret
;*****
;extern "C" void fastcall co_exit(cothread_t cothread);
;ecx = cothread
;*****
align 16
co_exit:
cmp ecx,0
jne co_switch
;if cothread is null, switch to context that created current context
mov eax,dword[co_active_context]
mov ecx,dword[eax+8]
jmp co_switch
;*****
;void fastcall co_entrypoint();
;*****
align 16
co_entrypoint:
mov eax,dword[co_active_context]
call dword[eax+4]
xor ecx,ecx
jmp co_exit

View File

@@ -1,20 +1,26 @@
/*
libco_x86 : version 0.08 ~byuu (10/21/2006)
libco_x86 : version 0.10 ~byuu (2007-09-08)
license: public domain
*/
#define COTHREAD_STACKSIZE_TINY 0x1000
#define COTHREAD_STACKSIZE_SMALL 0x4000
#define COTHREAD_STACKSIZE_NORMAL 0x10000
#define COTHREAD_STACKSIZE_LARGE 0x40000
#define COTHREAD_STACKSIZE_HUGE 0x100000
#ifndef LIBCO_H
#define LIBCO_H
typedef void (*cothread_t);
typedef void (*cothread_p)(void);
#if !defined(fastcall)
#if defined(_MSC_VER)
#define fastcall __fastcall
#elif defined(__GNUC__)
#define fastcall __attribute__((fastcall))
#else
#error "fastcall undefined"
#endif
#endif
typedef void *cothread_t;
extern "C" cothread_t fastcall co_init();
extern "C" void fastcall co_term();
extern "C" cothread_t fastcall co_active();
extern "C" cothread_t fastcall co_create(cothread_p coentry, unsigned int heapsize);
extern "C" cothread_t fastcall co_create(unsigned int heapsize, void (*coentry)());
extern "C" void fastcall co_delete(cothread_t cothread);
extern "C" void fastcall co_switch(cothread_t cothread);
extern "C" void fastcall co_exit(cothread_t cothread);
#endif

123
src/lib/libco_x86_64.asm Normal file
View File

@@ -0,0 +1,123 @@
;*****
;libco_x86_64 : version 0.10 ~byuu (2007-09-08)
;cross-platform x86-64 implementation of libco
;special thanks to Aaron Giles and Joel Yliluoma for various optimizations
;
;[ABI compatibility]
;- SystemV ( http://refspecs.freestandards.org/elf/x86_64-SysV-psABI.pdf )
;- gcc; linux; x86-64
;- gcc; freebsd; x86-64
;
;[nonvolatile registers]
;- rsp, rbp, rbx, r12, r13, r14, r15
;
;[volatile registers]
;- rax, rcx, rdx, r8, r9, r10, r11, rdi, rsi
;- st0 - st7
;- xmm0 - xmm15
;*****
bits 64
section .bss
align 8
co_primary_buffer resb 512
section .data
align 8
co_active_context dq co_primary_buffer
section .text
extern malloc
extern free
global co_active
global co_create
global co_delete
global co_switch
;*****
;extern "C" cothread_t co_active();
;return = rax
;*****
align 16
co_active:
mov rax,[co_active_context wrt rip]
ret
;*****
;extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)());
;rdi = heapsize
;rsi = coentry
;return = rax
;*****
align 16
co_create:
;create heap space (stack + register storage)
add rdi,512 ;allocate extra memory for contextual info
push rdi
push rsi
call malloc ;rax = malloc(rdi)
pop rsi
pop rdi
add rdi,rax ;set rsi to point to top of stack heap
and rdi,-16 ;force 16-byte alignment of stack heap
;store thread entry point + registers, so that first call to co_switch will execute coentry
mov qword[rdi-8],rsi ;entry point
mov qword[rdi-16],0 ;r15
mov qword[rdi-24],0 ;r14
mov qword[rdi-32],0 ;r13
mov qword[rdi-40],0 ;r12
mov qword[rdi-48],0 ;rbx
mov qword[rdi-56],0 ;rbp
sub rdi,56
;initialize context memory heap and return
mov [rax],rdi ;*cothread_t = stack heap pointer (rsp)
ret ;return allocated memory block as thread handle
;*****
;extern "C" void co_delete(cothread_t cothread);
;rdi = cothread
;*****
align 16
co_delete:
jmp free ;free(rdi)
;*****
;extern "C" void co_switch(cothread_t cothread);
;rdi = cothread
;*****
align 16
co_switch:
mov rax,[co_active_context wrt rip] ;backup current context
mov [co_active_context wrt rip],rdi ;set new active context
push rbp
push rbx
push r12
push r13
push r14
push r15
mov [rax],rsp
mov rsp,[rdi]
pop r15
pop r14
pop r13
pop r12
pop rbx
pop rbp
ret

16
src/lib/libco_x86_64.h Normal file
View File

@@ -0,0 +1,16 @@
/*
libco_x86_64 : version 0.10 ~byuu (2007-09-08)
license: public domain
*/
#ifndef LIBCO_H
#define LIBCO_H
typedef void *cothread_t;
extern "C" cothread_t co_active();
extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)());
extern "C" void co_delete(cothread_t cothread);
extern "C" void co_switch(cothread_t cothread);
#endif

View File

@@ -1,215 +0,0 @@
#include "libbase.h"
#include "libconfig.h"
void Setting::toggle() {
data ^= 1;
set(data);
}
uint Setting::get() {
return data;
}
void Setting::set(uint _data) {
data = _data;
switch(type) {
case BOOL:
case ENABLED_DISABLED:
case ON_OFF:
case YES_NO:
data &= 1;
break;
case HEX8:
data &= 0xff;
break;
case HEX16:
data &= 0xffff;
break;
case HEX24:
data &= 0xffffff;
break;
}
}
char *Setting::strget() {
return strptr(char_data);
}
void Setting::strset(const char *_data) {
strcpy(char_data, _data);
}
Setting::Setting(Config *_parent, char *_name, char *_desc, uint _data, uint _type) {
if(_parent) {
_parent->add(this);
}
uint s = strlen(_name);
name = (char*)malloc(s + 1);
strcpy(name, _name);
if(_desc) {
s = strlen(_desc);
desc = (char*)malloc(s + 1);
strcpy(desc, _desc);
} else {
desc = (char*)malloc(1);
*desc = 0;
}
data = _data;
def = _data;
type = _type;
}
Setting::Setting(Config *_parent, char *_name, char *_desc, char *_data) {
if(_parent) {
_parent->add(this);
}
uint s = strlen(_name);
name = (char*)malloc(s + 1);
strcpy(name, _name);
if(_desc) {
s = strlen(_desc);
desc = (char*)malloc(s + 1);
strcpy(desc, _desc);
} else {
desc = (char*)malloc(1);
*desc = 0;
}
strcpy(char_data, _data);
strcpy(char_def, _data);
type = STRING;
}
void Config::add(Setting *setting) {
list[list_count++] = setting;
}
uint Config::string_to_uint(uint type, char *input) {
if(!strcmp(input, "true") ||
!strcmp(input, "enabled") ||
!strcmp(input, "on") ||
!strcmp(input, "yes")
) {
return (uint)true;
}
if(!strcmp(input, "false") ||
!strcmp(input, "disabled") ||
!strcmp(input, "off") ||
!strcmp(input, "no")
) {
return (uint)false;
}
if(strbegin(input, "0x") || strbegin(input, "-0x")) {
return sstrhex(input + 2);
}
return sstrdec(input);
}
char *Config::uint_to_string(uint type, uint input) {
static char output[512];
switch(type) {
case Setting::BOOL:
sprintf(output, "%s", (input & 1) ? "true" : "false");
break;
case Setting::ENABLED_DISABLED:
sprintf(output, "%s", (input & 1) ? "enabled" : "disabled");
break;
case Setting::ON_OFF:
sprintf(output, "%s", (input & 1) ? "on" : "off");
break;
case Setting::YES_NO:
sprintf(output, "%s", (input & 1) ? "yes" : "no");
break;
case Setting::DEC: sprintf(output, "%d", input); break;
case Setting::HEX: sprintf(output, "0x%x", input); break;
case Setting::HEX8: sprintf(output, "0x%0.2x", input & 0xff); break;
case Setting::HEX16: sprintf(output, "0x%0.4x", input & 0xffff); break;
case Setting::HEX24: sprintf(output, "0x%0.6x", input & 0xffffff); break;
case Setting::HEX32: sprintf(output, "0x%0.8x", input); break;
}
return output;
}
bool Config::load(const char *fn) {
FILE *fp;
fp = fopen(fn, "rb");
if(!fp)return false;
//load the config file into memory
fseek(fp, 0, SEEK_END);
int fsize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *buffer = (char*)malloc(fsize + 1);
fread(buffer, 1, fsize, fp);
fclose(fp);
*(buffer + fsize) = 0;
strcpy(data, buffer);
free(buffer);
//split the file into lines
replace(data, "\r\n", "\n");
qreplace(data, "\t", "");
qreplace(data, " ", "");
split(line, "\n", data);
for(int i = 0; i < count(line); i++) {
if(strlen(line[i]) == 0)continue;
if(*strptr(line[i]) == '#')continue;
qsplit(part, "=", line[i]);
for(int l = 0; l < list_count; l++) {
if(!strcmp(list[l]->name, part[0])) {
if(list[l]->type != Setting::STR) {
list[l]->set(string_to_uint(list[l]->type, strptr(part[1])));
} else {
list[l]->strset(strptr(part[1]));
strunquote(list[l]->char_data);
}
}
}
}
return true;
}
bool Config::load(string &fn) { return load(strptr(fn)); }
bool Config::save(const char *fn) {
FILE *fp;
fp = fopen(fn, "wb");
if(!fp)return false;
for(int i = 0; i < list_count; i++) {
strcpy(data, list[i]->desc);
replace(data, "\r\n", "\n");
split(line, "\n", data);
for(int l = 0; l < count(line); l++) {
fprintf(fp, "# %s\r\n", strptr(line[l]));
}
if(list[i]->type != Setting::STRING) {
fprintf(fp, "# (default = %s)\r\n", uint_to_string(list[i]->type, list[i]->def));
fprintf(fp, "%s = %s\r\n\r\n", list[i]->name, uint_to_string(list[i]->type, list[i]->data));
} else {
fprintf(fp, "# (default = \"%s\")\r\n", strptr(list[i]->char_def));
fprintf(fp, "%s = \"%s\"\r\n\r\n", list[i]->name, strptr(list[i]->char_data));
}
}
fclose(fp);
return true;
}
bool Config::save(string &fn) { return save(strptr(fn)); }
Config::Config() {
list_count = 0;
}

View File

@@ -1,85 +1,185 @@
/*
libconfig : version 0.11 ~byuu (2006/11/12)
libconfig : version 0.14 ~byuu (2007-06-12)
license: public domain
*/
#ifndef __LIBCONFIG
#define __LIBCONFIG
#ifndef LIBCONFIG_H
#define LIBCONFIG_H
#include "libbase.h"
#include "libarray.h"
#include "libstring.h"
class Config;
class Setting;
class Setting {
friend class Config;
protected:
uint data, type, def;
public:
enum {
BOOL = 0,
BOOLEAN = 0,
TRUE_FALSE = 0,
ENABLED_DISABLED = 1,
ON_OFF = 2,
YES_NO = 3,
DEC = 4,
HEX = 5,
HEX8 = 6,
HEX16 = 7,
HEX24 = 8,
HEX32 = 9,
STRING = 10,
STR = 10,
};
char *name, *desc;
string char_data, char_def;
virtual void toggle();
virtual uint get();
virtual void set(uint _data);
virtual char *strget();
virtual void strset(const char *_data);
Setting(Config *_parent, char *_name, char *_desc, uint _data, uint _type);
Setting(Config *_parent, char *_name, char *_desc, char *_data);
template<typename T> inline operator T() { return (T)get(); }
template<typename T> inline Setting &operator=(const T &x) { set(x); return *this; }
template<typename T> inline bool operator==(const T &x) { return (T)get() == x; }
template<typename T> inline bool operator!=(const T &x) { return (T)get() != x; }
template<typename T> inline bool operator>=(const T &x) { return (T)get() >= x; }
template<typename T> inline bool operator> (const T &x) { return (T)get() > x; }
template<typename T> inline bool operator<=(const T &x) { return (T)get() <= x; }
template<typename T> inline bool operator< (const T &x) { return (T)get() < x; }
inline operator char*() { return strget(); }
inline Setting &operator=(char *x) { strset(x); return *this; }
inline Setting &operator=(const char *x) { strset(x); return *this; }
inline bool operator==(const char *x) { return !strcmp(strget(), x); }
inline bool operator!=(const char *x) { return strcmp(strget(), x); }
};
class Config {
protected:
class Config { public:
array<Setting*> list;
uint list_count;
string data;
stringarray line, part, subpart;
uint string_to_uint(uint type, char *input);
char *uint_to_string(uint type, uint input);
public:
void add(Setting *setting);
bool load(const char *fn);
bool load(string &fn);
bool save(const char *fn);
bool save(string &fn);
Config();
bool load(const string &fn) { return load(strptr(fn)); }
bool save(const string &fn) { return save(strptr(fn)); }
void add(Setting *setting) { list[list_count++] = setting; }
Config() : list_count(0) {}
};
class Setting { public:
uint type;
char *name, *desc, *def;
enum Type {
Integer,
String,
};
virtual void set(const char *input) = 0;
virtual void get(string &output) = 0;
};
class IntegerSetting : public Setting { public:
uint ifmt, data, idef;
enum Format {
Boolean,
Decimal,
Hex,
};
void set(const char *input) {
if(ifmt == Boolean) { data = !strcmp(input, "true"); }
if(ifmt == Decimal) { data = strdec(input); }
if(ifmt == Hex) { data = strhex(input + (stribegin(input, "0x") ? 2 : 0)); }
}
void get(string &output) {
if(ifmt == Boolean) { sprintf(output, "%s", data ? "true" : "false"); }
if(ifmt == Decimal) { sprintf(output, "%d", data); }
if(ifmt == Hex) { sprintf(output, "%x", data); }
}
uint operator()() { return data; }
operator uint() { return data; }
template<typename T> IntegerSetting &operator=(T x) { data = uint(x); return *this; }
template<typename T> bool operator==(T x) { return (T(data) == x); }
template<typename T> bool operator!=(T x) { return (T(data) != x); }
template<typename T> bool operator>=(T x) { return (T(data) >= x); }
template<typename T> bool operator> (T x) { return (T(data) > x); }
template<typename T> bool operator<=(T x) { return (T(data) <= x); }
template<typename T> bool operator< (T x) { return (T(data) < x); }
IntegerSetting(Config *parent, const char *r_name, const char *r_desc, uint r_format, uint r_data) {
type = Setting::Integer;
name = strdup(r_name);
desc = strdup(r_desc);
ifmt = r_format;
data = idef = r_data;
string t;
get(t);
def = strdup(strptr(t));
if(parent) { parent->add(this); }
}
~IntegerSetting() {
free(name);
free(desc);
free(def);
}
};
class StringSetting : public Setting { public:
string data;
void set(const char *input) { data = input; strunquote(data); }
void get(string &output) { output = data; strquote(output); }
const char* operator()() { return strptr(data); }
operator const char*() { return strptr(data); }
StringSetting &operator=(const char *x) { data = x; return *this; }
bool operator==(const char *x) { return !strcmp(data, x); }
bool operator!=(const char *x) { return strcmp(data, x); }
StringSetting(Config *parent, const char *r_name, const char *r_desc, const char *r_data) {
type = Setting::String;
name = strdup(r_name);
desc = strdup(r_desc);
data = r_data;
string t;
get(t);
def = strdup(strptr(t));
if(parent) { parent->add(this); }
}
~StringSetting() {
free(name);
free(desc);
free(def);
}
};
inline bool Config::load(const char *fn) {
FILE *fp = fopen(fn, "rb");
if(!fp)return false;
//load the config file into memory
fseek(fp, 0, SEEK_END);
int fsize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *buffer = (char*)malloc(fsize + 1);
fread(buffer, 1, fsize, fp);
fclose(fp);
*(buffer + fsize) = 0;
strcpy(data, buffer);
free(buffer);
//split the file into lines
replace(data, "\r\n", "\n");
qreplace(data, "\t", "");
qreplace(data, " ", "");
split(line, "\n", data);
for(int i = 0; i < count(line); i++) {
if(strlen(line[i]) == 0)continue;
if(*strptr(line[i]) == '#')continue;
qsplit(part, "=", line[i]);
for(int l = 0; l < list_count; l++) {
if(!strcmp(list[l]->name, part[0])) {
list[l]->set(strptr(part[1]));
break;
}
}
}
return true;
}
inline bool Config::save(const char *fn) {
FILE *fp;
string t;
fp = fopen(fn, "wb");
if(!fp)return false;
for(int i = 0; i < list_count; i++) {
strcpy(data, list[i]->desc);
replace(data, "\r\n", "\n");
split(line, "\n", data);
for(int l = 0; l < count(line); l++) {
if(line[l] != "") { fprintf(fp, "# %s\r\n", strptr(line[l])); }
}
fprintf(fp, "# (default = %s)\r\n", list[i]->def);
list[i]->get(t);
fprintf(fp, "%s = %s\r\n\r\n", list[i]->name, strptr(t));
}
fclose(fp);
return true;
}
#endif

View File

@@ -1,451 +0,0 @@
/*
libfile : version 0.05a ~byuu (10/26/06)
*/
#ifndef __LIBFILE
#define __LIBFILE
/*****
* file object
*****/
class file {
public:
enum { mode_read, mode_write, mode_readwrite, mode_writeread };
enum { seek_start, seek_end, seek_back, seek_forward };
virtual void read(uint8 *data, uint length) = 0;
virtual uint8 read() = 0;
virtual void write(uint8 *data, uint length) = 0;
virtual void write(uint8 data) = 0;
virtual uint32 crc32();
virtual void seek(uint offset, uint mode = seek_start) = 0;
virtual void truncate(uint size) = 0;
virtual uint offset() = 0;
virtual uint size() = 0;
virtual bool eof() = 0;
virtual bool open(const char *filename, uint mode) = 0;
virtual bool open() = 0;
virtual bool flush() = 0;
virtual bool close() = 0;
};
inline uint32 file::crc32() {
uint pos = offset(), i = size();
seek(0);
uint32 crc32 = 0xffffffff;
while(i--) {
crc32 = crc32_adjust(crc32, read());
}
seek(pos);
return ~crc32;
}
/*****
* c++ wrappers
*****/
inline void fread(file &s, uint8 *data, uint length) { s.read(data, length); }
inline uint8 fread(file &s) { return s.read(); }
inline uint8 fgetc(file &s) { return s.read(); }
inline uint fgetb(file &s) { return s.read(); }
inline void fwrite(file &s, uint8 *data, uint length) { s.write(data, length); }
inline void fwrite(file &s, uint8 data) { s.write(data); }
inline void fputc(uint8 data, file &s) { s.write(data); }
inline void fputb(file &s, uint8 data) { s.write(data); }
inline uint32 fcrc32(file &s) { return s.crc32(); }
inline void fseek(file &s, uint offset, uint mode = file::seek_start) { s.seek(offset, mode); }
inline void ftruncate(file &s, uint size) { s.truncate(size); }
inline uint ftell(file &s) { return s.offset(); }
inline uint fsize(file &s) { return s.size(); }
inline bool feof(file &s) { return s.eof(); }
inline bool fopen(file &s, const char *filename, uint mode) { return s.open(filename, mode); }
inline bool fopen(file &s) { return s.open(); }
inline bool fflush(file &s) { return s.flush(); }
inline bool fclose(file &s) { return s.close(); }
/*****
* endian wrappers
*****/
inline uint8 fgetlb(file &s) { return fgetc(s); }
inline uint8 fgetmb(file &s) { return fgetc(s); }
inline uint16 fgetlw(file &s) {
return (fgetc(s)) | (fgetc(s) << 8);
}
inline uint16 fgetmw(file &s) {
return (fgetc(s) << 8) | (fgetc(s) << 8);
}
inline uint32 fgetld(file &s) {
return (fgetc(s)) | (fgetc(s) << 8) | (fgetc(s) << 16) | (fgetc(s) << 24);
}
inline uint32 fgetmd(file &s) {
return (fgetc(s) << 24) | (fgetc(s) << 16) | (fgetc(s) << 8) | (fgetc(s));
}
inline uint64 fgetlq(file &s) {
return ((uint64)fgetc(s) << 0) | ((uint64)fgetc(s) << 8) |
((uint64)fgetc(s) << 16) | ((uint64)fgetc(s) << 24) |
((uint64)fgetc(s) << 32) | ((uint64)fgetc(s) << 40) |
((uint64)fgetc(s) << 48) | ((uint64)fgetc(s) << 56);
}
inline uint64 fgetmq(file &s) {
return ((uint64)fgetc(s) << 56) | ((uint64)fgetc(s) << 48) |
((uint64)fgetc(s) << 40) | ((uint64)fgetc(s) << 32) |
((uint64)fgetc(s) << 24) | ((uint64)fgetc(s) << 16) |
((uint64)fgetc(s) << 8) | ((uint64)fgetc(s) << 0);
}
inline void fputlb(file &s, uint8 data) { fputc(data, s); }
inline void fputmb(file &s, uint8 data) { fputc(data, s); }
inline void fputlw(file &s, uint16 data) {
fputc(data >> 0, s);
fputc(data >> 8, s);
}
inline void fputmw(file &s, uint16 data) {
fputc(data >> 8, s);
fputc(data >> 0, s);
}
inline void fputld(file &s, uint32 data) {
fputc(data >> 0, s);
fputc(data >> 8, s);
fputc(data >> 16, s);
fputc(data >> 24, s);
}
inline void fputmd(file &s, uint32 data) {
fputc(data >> 24, s);
fputc(data >> 16, s);
fputc(data >> 8, s);
fputc(data >> 0, s);
}
inline void fputlq(file &s, uint64 data) {
fputc(data >> 0, s);
fputc(data >> 8, s);
fputc(data >> 16, s);
fputc(data >> 24, s);
fputc(data >> 32, s);
fputc(data >> 40, s);
fputc(data >> 48, s);
fputc(data >> 56, s);
}
inline void fputmq(file &s, uint64 data) {
fputc(data >> 56, s);
fputc(data >> 48, s);
fputc(data >> 40, s);
fputc(data >> 32, s);
fputc(data >> 24, s);
fputc(data >> 16, s);
fputc(data >> 8, s);
fputc(data >> 0, s);
}
/*****
* ramfile
*****/
class ramfile : public file {
private:
FILE *fp;
array<uint8> filedata;
char filename[1024];
uint filepos;
uint filesize;
uint filemode;
bool fileopen;
bool filevirtual;
public:
void read(uint8 *data, uint length) {
if(!fileopen || filemode == mode_write) { return; }
memcpy(data, filedata.get(filepos + length) + filepos, length);
filepos += length;
if(filepos > filesize)filepos = filesize;
}
uint8 read() {
if(!fileopen || filemode == mode_write) { return 0; }
if(eof() == true) { return 0xff; }
return filedata[filepos++];
}
void write(uint8 *data, uint length) {
if(!fileopen || filemode == mode_read) { return; }
memcpy(filedata.get(filepos + length) + filepos, data, length);
filepos += length;
if(filepos > filesize)filesize = filepos;
}
void write(uint8 data) {
if(!fileopen || filemode == mode_read) { return; }
filedata[filepos++] = data;
if(filepos > filesize)filesize = filepos;
}
void seek(uint offset, uint mode = seek_start) {
if(!fileopen) { return; }
switch(mode) {
case seek_start: filepos = offset; break;
case seek_end: filepos = filesize + offset; break;
case seek_back: filepos -= offset; break;
case seek_forward: filepos += offset; break;
}
if(filemode == mode_read) {
if(filepos > filesize)filepos = filesize;
} else {
if(filepos > filesize)filesize = filepos;
}
}
void truncate(uint size) {
filesize = size;
if(filepos > filesize)filepos = filesize;
}
uint offset() {
if(!fileopen) { return 0; }
return filepos;
}
uint size() {
if(!fileopen) { return 0; }
return filesize;
}
bool eof() {
if(!fileopen) { return true; }
return (filepos >= filesize);
}
bool open(const char *fn, uint mode) {
if(fileopen) { return false; }
strcpy(filename, fn ? fn : "");
filevirtual = (*filename == 0);
filemode = mode;
switch(filemode) {
case mode_read:
case mode_readwrite:
if(filevirtual == true) {
filesize = 0;
} else {
fp = fopen(filename, "rb");
if(!fp) { return false; }
filesize = fsize(fp);
fread(filedata.get(filesize), 1, filesize, fp);
fclose(fp);
}
break;
default:
filesize = 0;
break;
}
filepos = 0;
fileopen = true;
return true;
}
bool open() {
return fileopen;
}
bool flush() {
if(!fileopen) { return false; }
switch(filemode) {
case mode_readwrite:
case mode_write:
case mode_writeread:
if(filevirtual == false) {
fp = fopen(filename, "wb");
if(!fp) { return false; }
fwrite(filedata.get(filesize), 1, filesize, fp);
fclose(fp);
}
break;
}
return true;
}
bool close() {
if(!fileopen) { return false; }
bool result = flush();
fileopen = false;
filedata.reset();
return result;
}
ramfile() {
fileopen = false;
}
~ramfile() {
if(fileopen) { close(); }
}
};
/*****
* diskfile
*****/
class diskfile : public file {
private:
FILE *fp;
uint filemode;
public:
void read(uint8 *data, uint length) {
if(!fp || filemode == mode_write) { return; }
fread(data, 1, length, fp);
}
uint8 read() {
if(!fp || filemode == mode_write) { return 0; }
if(eof() == true) { return 0xff; }
return fgetc(fp);
}
void write(uint8 *data, uint length) {
if(!fp || filemode == mode_read) { return; }
fwrite(data, 1, length, fp);
}
void write(uint8 data) {
if(!fp || filemode == mode_read) { return; }
fputc(data, fp);
}
void seek(uint offset, uint mode = seek_start) {
if(!fp) { return; }
switch(mode) {
default:
case seek_start: fseek(fp, offset, SEEK_SET); break;
case seek_end: fseek(fp, offset, SEEK_END); break;
case seek_back: fseek(fp, offset, SEEK_CUR); break;
case seek_forward: fseek(fp, offset, SEEK_CUR); break;
}
}
void truncate(uint size) {
if(!fp) { return; }
ftruncate(fp, size);
}
uint offset() {
if(!fp) { return 0; }
return ftell(fp);
}
uint size() {
if(!fp) { return 0; }
uint pos = ftell(fp);
fseek(fp, 0, SEEK_END);
uint filesize = ftell(fp);
fseek(fp, pos, SEEK_SET);
return filesize;
}
bool eof() {
if(!fp) { return true; }
if(feof(fp)) {
seek(size(), seek_start);
return true;
}
return false;
}
bool open(const char *filename, uint mode) {
if(fp) { return false; }
filemode = mode;
char m[8];
switch(filemode) {
default:
case mode_read: strcpy(m, "rb"); break;
case mode_write: strcpy(m, "wb"); break;
case mode_readwrite: strcpy(m, "rb+"); break;
case mode_writeread: strcpy(m, "wb+"); break;
}
fp = fopen(filename, m);
if(!fp) { return false; }
return true;
}
bool open() {
return (fp != 0);
}
bool flush() {
if(!fp) { return false; }
fflush(fp);
return true;
}
bool close() {
if(!fp) { return false; }
fclose(fp);
fp = 0;
return true;
}
diskfile() {
fp = 0;
}
~diskfile() {
if(fp) { fclose(fp); }
}
};
/*****
* directory object
*****/
class directory {
public:
void open(const char *path) {}
void close() {}
uint read(char *filename, uint maxlength) { return 0; }
};
#endif

100
src/lib/libfunctor.h Normal file
View File

@@ -0,0 +1,100 @@
/*
libfunctor : version 0.05 ~byuu (2007-09-08)
license: public domain
*/
#ifndef LIBFUNCTOR_H
#define LIBFUNCTOR_H
//prologue
#define TN typename
template<typename T> class functor;
//parameters = 0
#define cat(n) n
#define TL typename R
#define PL
#define CL
#include "libfunctor_impl.h"
//parameters = 1
#define cat(n) , n
#define TL TN R, TN P1
#define PL P1 p1
#define CL p1
#include "libfunctor_impl.h"
//parameters = 2
#define cat(n) , n
#define TL TN R, TN P1, TN P2
#define PL P1 p1, P2 p2
#define CL p1, p2
#include "libfunctor_impl.h"
//parameters = 3
#define cat(n) , n
#define TL TN R, TN P1, TN P2, TN P3
#define PL P1 p1, P2 p2, P3 p3
#define CL p1, p2, p3
#include "libfunctor_impl.h"
//parameters = 4
#define cat(n) , n
#define TL TN R, TN P1, TN P2, TN P3, TN P4
#define PL P1 p1, P2 p2, P3 p3, P4 p4
#define CL p1, p2, p3, p4
#include "libfunctor_impl.h"
//parameters = 5
#define cat(n) , n
#define TL TN R, TN P1, TN P2, TN P3, TN P4, TN P5
#define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5
#define CL p1, p2, p3, p4, p5
#include "libfunctor_impl.h"
//parameters = 6
#define cat(n) , n
#define TL TN R, TN P1, TN P2, TN P3, TN P4, TN P5, TN P6
#define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6
#define CL p1, p2, p3, p4, p5, p6
#include "libfunctor_impl.h"
//parameters = 7
#define cat(n) , n
#define TL TN R, TN P1, TN P2, TN P3, TN P4, TN P5, TN P6, TN P7
#define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7
#define CL p1, p2, p3, p4, p5, p6, p7
#include "libfunctor_impl.h"
//parameters = 8
#define cat(n) , n
#define TL TN R, TN P1, TN P2, TN P3, TN P4, TN P5, TN P6, TN P7, TN P8
#define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8
#define CL p1, p2, p3, p4, p5, p6, p7, p8
#include "libfunctor_impl.h"
//epilogue
#undef TN
#endif

81
src/lib/libfunctor_impl.h Normal file
View File

@@ -0,0 +1,81 @@
#ifdef LIBFUNCTOR_H
template<TL>
class functor<R (PL)> {
private:
struct base1 { virtual void func1(PL) {} };
struct base2 { virtual void func2(PL) {} };
struct derived : base1, virtual base2 {};
struct data_t {
R (*fn_call)(const data_t& cat(PL));
union {
R (*fn_global)(PL);
struct {
R (derived::*fn_member)(PL);
void *object;
};
};
} data;
static R fn_call_global(const data_t &d cat(PL)) {
return d.fn_global(CL);
}
template<typename C>
static R fn_call_member(const data_t &d cat(PL)) {
return (((C*)d.object)->*((R (C::*&)(PL))d.fn_member))(CL);
}
public:
R operator()(PL) const { return data.fn_call(data cat(CL)); }
operator bool() const { return data.fn_call; }
functor() { data.fn_call = 0; }
functor(R (*fn)(PL)) {
data.fn_call = &fn_call_global;
data.fn_global = fn;
}
template<typename C>
functor(R (C::*fn)(PL), C *obj) {
data.fn_call = &fn_call_member<C>;
(R (C::*&)(PL))data.fn_member = fn;
assert(sizeof data.fn_member >= sizeof fn);
data.object = obj;
}
template<typename C>
functor(R (C::*fn)(PL) const, C *obj) {
data.fn_call = &fn_call_member<C>;
(R (C::*&)(PL))data.fn_member = (R (C::*&)(PL))fn;
assert(sizeof data.fn_member >= sizeof fn);
data.object = obj;
}
functor &operator=(const functor &source) { memcpy(&data, &source.data, sizeof(data_t)); return *this; }
functor(const functor &source) { memcpy(&data, &source.data, sizeof(data_t)); }
};
template<TL>
functor<R (PL)> bind(R (*fn)(PL)) {
return functor<R (PL)>(fn);
}
template<typename C, TL>
functor<R (PL)> bind(R (C::*fn)(PL), C *obj) {
return functor<R (PL)>(fn, obj);
}
template<typename C, TL>
functor<R (PL)> bind(R (C::*fn)(PL) const, C *obj) {
return functor<R (PL)>(fn, obj);
}
#undef cat
#undef TL
#undef PL
#undef CL
#endif

View File

@@ -1,182 +1,309 @@
/*
libkeymap : version 0.02 ~byuu (07/30/06)
libkeymap : version 0.02 ~byuu (2007-05-28)
*/
#ifndef __LIBKEYMAP
#define __LIBKEYMAP
#ifndef LIBKEYMAP_H
#define LIBKEYMAP_H
class keymap {
private:
char tmp[32];
namespace keymap {
public:
//TODO: use lookup table for find() functions
static char keytable[][64] = {
"none",
"esc",
"f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12",
"print_screen", "sys_req", "scroll_lock", "pause", "brk",
"grave", "tilde",
"num_1", "exclamation",
"num_2", "at",
"num_3", "pound",
"num_4", "dollar",
"num_5", "percent",
"num_6", "power",
"num_7", "ampersand",
"num_8", "asterisk",
"num_9", "lparenthesis",
"num_0", "rparenthesis",
"minus", "underscore",
"equal", "plus",
"backspace",
};
uint null;
uint esc;
uint f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12;
uint print_screen, scroll_lock, pause;
uint tilde;
uint num_0, num_1, num_2, num_3, num_4;
uint num_5, num_6, num_7, num_8, num_9;
uint minus, plus, backspace;
uint ins, del, home, end, page_up, page_down;
uint a, b, c, d, e, f, g, h, i, j, k, l, m;
uint n, o, p, q, r, s, t, u, v, w, x, y, z;
uint lbracket, rbracket;
uint pipe, colon, quote, comma, period, question;
uint numpad_0, numpad_1, numpad_2, numpad_3, numpad_4;
uint numpad_5, numpad_6, numpad_7, numpad_8, numpad_9;
uint numpad_plus, numpad_minus, numpad_mul;
uint numpad_div, numpad_enter, numpad_point;
uint numlock, capslock;
uint up, down, left, right;
uint tab, enter, space;
uint lctrl, rctrl, lalt, ralt, lshift, rshift;
uint lwin, rwin, menu;
enum {
none = 0x0000,
struct {
uint up, down, left, right;
uint button[128];
} joypad[16];
esc,
uint find(const char *key) {
#define match(n) if(!strcmp(#n, key))return n;
match(null)
match(esc)
match(f1) match(f2) match(f3) match(f4) match(f5) match(f6)
match(f7) match(f8) match(f9) match(f10) match(f11) match(f12)
match(print_screen) match(scroll_lock) match(pause)
match(tilde)
match(num_0) match(num_1) match(num_2) match(num_3) match(num_4)
match(num_5) match(num_6) match(num_7) match(num_8) match(num_9)
match(minus) match(plus) match(backspace)
match(ins) match(del) match(home)
match(end) match(page_up) match(page_down)
match(a) match(b) match(c) match(d) match(e) match(f)
match(g) match(h) match(i) match(j) match(k) match(l)
match(m) match(n) match(o) match(p) match(q) match(r)
match(s) match(t) match(u) match(v) match(w) match(x)
match(y) match(z)
match(lbracket) match(rbracket)
match(pipe) match(colon) match(quote)
match(comma) match(period) match(question)
match(numpad_0) match(numpad_1) match(numpad_2) match(numpad_3)
match(numpad_4) match(numpad_5) match(numpad_6) match(numpad_7)
match(numpad_8) match(numpad_9)
match(numpad_plus) match(numpad_minus) match(numpad_mul)
match(numpad_div) match(numpad_enter) match(numpad_point)
match(numlock) match(capslock)
match(up) match(down) match(left) match(right)
match(tab) match(enter) match(space)
match(lctrl) match(rctrl) match(lalt)
match(ralt) match(lshift) match(rshift)
match(lwin) match(rwin) match(menu)
#undef match
f1,
f2,
f3,
f4,
f5,
f6,
f7,
f8,
f9,
f10,
f11,
f12,
if(!memcmp(key, "joypad", 6)) {
const char *p = key + 6;
int joy, bn, n;
sscanf(p, "%d%n", &joy, &n);
p += n;
if(*p == '.') {
p++;
if(!strcmp(p, "up")) { return joypad[joy].up; }
if(!strcmp(p, "down")) { return joypad[joy].down; }
if(!strcmp(p, "left")) { return joypad[joy].left; }
if(!strcmp(p, "right")) { return joypad[joy].right; }
if(!memcmp(p, "button", 6)) {
p += 6;
sscanf(p, "%d", &bn);
return joypad[joy].button[bn];
}
}
}
print_screen, sys_req,
scroll_lock,
pause, brk,
return 0;
}
grave, tilde,
const char *find(uint key) {
#define match(n) if(n == key)return #n;
match(null)
match(esc)
match(f1) match(f2) match(f3) match(f4) match(f5) match(f6)
match(f7) match(f8) match(f9) match(f10) match(f11) match(f12)
match(print_screen) match(scroll_lock) match(pause)
match(tilde)
match(num_0) match(num_1) match(num_2) match(num_3) match(num_4)
match(num_5) match(num_6) match(num_7) match(num_8) match(num_9)
match(minus) match(plus) match(backspace)
match(ins) match(del) match(home)
match(end) match(page_up) match(page_down)
match(a) match(b) match(c) match(d) match(e) match(f)
match(g) match(h) match(i) match(j) match(k) match(l)
match(m) match(n) match(o) match(p) match(q) match(r)
match(s) match(t) match(u) match(v) match(w) match(x)
match(y) match(z)
match(lbracket) match(rbracket)
match(pipe) match(colon) match(quote)
match(comma) match(period) match(question)
match(numpad_0) match(numpad_1) match(numpad_2) match(numpad_3)
match(numpad_4) match(numpad_5) match(numpad_6) match(numpad_7)
match(numpad_8) match(numpad_9)
match(numpad_plus) match(numpad_minus) match(numpad_mul)
match(numpad_div) match(numpad_enter) match(numpad_point)
match(numlock) match(capslock)
match(up) match(down) match(left) match(right)
match(tab) match(enter) match(space)
match(lctrl) match(rctrl) match(lalt)
match(ralt) match(lshift) match(rshift)
match(lwin) match(rwin) match(menu)
#undef match
num_1, exclamation,
num_2, at,
num_3, pound,
num_4, dollar,
num_5, percent,
num_6, power,
num_7, ampersand,
num_8, asterisk,
num_9, lparenthesis,
num_0, rparenthesis,
for(int joy = 0; joy < 16; joy++) {
if(joypad[joy].up == key) { sprintf(tmp, "joypad%d.up", joy); return tmp; }
if(joypad[joy].down == key) { sprintf(tmp, "joypad%d.down", joy); return tmp; }
if(joypad[joy].left == key) { sprintf(tmp, "joypad%d.left", joy); return tmp; }
if(joypad[joy].right == key) { sprintf(tmp, "joypad%d.right", joy); return tmp; }
for(int bn = 0; bn < 128; bn++) {
if(joypad[joy].button[bn] == key) { sprintf(tmp, "joypad%d.button%d", joy, bn); return tmp; }
}
}
minus, underscore,
equal, plus,
backspace,
return "null";
}
ins,
del,
home,
end,
page_up,
page_down,
keymap() {
null = 0;
esc = 0;
f1 = f2 = f3 = f4 = f5 = f6 = 0;
f7 = f8 = f9 = f10 = f11 = f12 = 0;
print_screen = scroll_lock = pause = 0;
tilde = 0;
num_0 = num_1 = num_2 = num_3 = num_4 = 0;
num_5 = num_6 = num_7 = num_8 = num_9 = 0;
minus = plus = backspace = 0;
ins = del = home = end = page_up = page_down = 0;
a = b = c = d = e = f = g = h = i = 0;
j = k = l = m = n = o = p = q = r = 0;
s = t = u = v = w = x = y = z = 0;
lbracket = rbracket = 0;
pipe = colon = quote = comma = period = question = 0;
numpad_0 = numpad_1 = numpad_2 = numpad_3 = numpad_4 = 0;
numpad_5 = numpad_6 = numpad_7 = numpad_8 = numpad_9 = 0;
numpad_plus = numpad_minus = numpad_mul = 0;
numpad_div = numpad_enter = numpad_point = 0;
numlock = capslock = 0;
up = down = left = right = 0;
tab = enter = space = 0;
lctrl = rctrl = lalt = ralt = lshift = rshift = 0;
lwin = rwin = menu = 0;
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,
for(int joy = 0; joy < 16; joy++) {
joypad[joy].up = 0;
joypad[joy].down = 0;
joypad[joy].left = 0;
joypad[joy].right = 0;
memset(joypad[joy].button, 0, sizeof(joypad[joy].button));
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,
lbracket, lbrace,
rbracket, rbrace,
backslash, pipe,
semicolon, colon,
apostrophe, quote,
comma, lcaret,
period, rcaret,
slash, question,
kp_1, kp_end,
kp_2, kp_down,
kp_3, kp_page_down,
kp_4, kp_left,
kp_5, kp_center,
kp_6, kp_right,
kp_7, kp_home,
kp_8, kp_up,
kp_9, kp_page_up,
kp_0, kp_insert,
kp_decimal, kp_delete,
kp_plus,
kp_minus,
kp_mul,
kp_div,
kp_enter,
num_lock,
caps_lock,
up,
down,
left,
right,
tab,
enter,
space,
lctrl,
rctrl,
lalt,
ralt,
lshift,
rshift,
lsuper,
rsuper,
menu,
limit, //not an actual key -- marks the end of linear key entries
joypad_flag = 0x8000,
joypad_nummask = 0x7f00,
joypad_keymask = 0x00ff,
joypad_up = 0x0080,
joypad_down = 0x0081,
joypad_left = 0x0082,
joypad_right = 0x0083,
};
static uint16 find(const char *key) {
#define match(_n) if(!strcmp(#_n, key)) { return _n; }
match(none)
match(esc)
match(f1) match(f2) match(f3) match(f4) match(f5) match(f6)
match(f7) match(f8) match(f9) match(f10) match(f11) match(f12)
match(print_screen) match(sys_req) match(scroll_lock) match(pause) match(brk)
match(grave) match(tilde)
match(num_1) match(exclamation)
match(num_2) match(at)
match(num_3) match(pound)
match(num_4) match(dollar)
match(num_5) match(percent)
match(num_6) match(power)
match(num_7) match(ampersand)
match(num_8) match(asterisk)
match(num_9) match(lparenthesis)
match(num_0) match(rparenthesis)
match(minus) match(underscore) match(equal) match(plus) match(backspace)
match(ins) match(del) match(home) match(end) match(page_up) match(page_down)
match(a) match(b) match(c) match(d) match(e) match(f)
match(g) match(h) match(i) match(j) match(k) match(l)
match(m) match(n) match(o) match(p) match(q) match(r)
match(s) match(t) match(u) match(v) match(w) match(x)
match(y) match(z)
match(A) match(B) match(C) match(D) match(E) match(F)
match(G) match(H) match(I) match(J) match(K) match(L)
match(M) match(N) match(O) match(P) match(Q) match(R)
match(S) match(T) match(U) match(V) match(W) match(X)
match(Y) match(Z)
match(lbracket) match(lbrace)
match(rbracket) match(rbrace)
match(backslash) match(pipe)
match(semicolon) match(colon)
match(apostrophe) match(quote)
match(comma) match(lcaret)
match(period) match(rcaret)
match(slash) match(question)
match(kp_1) match(kp_end)
match(kp_2) match(kp_down)
match(kp_3) match(kp_page_down)
match(kp_4) match(kp_left)
match(kp_5) match(kp_center)
match(kp_6) match(kp_right)
match(kp_7) match(kp_home)
match(kp_8) match(kp_up)
match(kp_9) match(kp_page_up)
match(kp_0) match(kp_insert)
match(kp_decimal) match(kp_delete)
match(kp_plus) match(kp_minus) match(kp_mul) match(kp_div) match(kp_enter)
match(num_lock) match(caps_lock)
match(up) match(down) match(left) match(right)
match(tab) match(enter) match(space)
match(lctrl) match(rctrl)
match(lalt) match(ralt)
match(lshift) match(rshift)
match(lsuper) match(rsuper)
match(menu)
#undef match
if(!memcmp(key, "joypad", 6)) {
const char *p = key + 6;
uint joypad, button, n;
sscanf(p, "%u%n", &joypad, &n);
joypad &= 127;
p += n;
if(!strcmp(p, ".up")) { return joypad_flag | (joypad << 8) | joypad_up; }
if(!strcmp(p, ".down")) { return joypad_flag | (joypad << 8) | joypad_down; }
if(!strcmp(p, ".left")) { return joypad_flag | (joypad << 8) | joypad_left; }
if(!strcmp(p, ".right")) { return joypad_flag | (joypad << 8) | joypad_right; }
if(!memcmp(p, ".button", 7)) {
sscanf(p + 7, "%u", &button);
button &= 127;
return joypad_flag | (joypad << 8) | button;
}
}
return none;
}
static char *find(char *out, uint16 key) {
#define match(_n) if(_n == key) { strcpy(out, #_n); return out; }
match(none)
match(esc)
match(f1) match(f2) match(f3) match(f4) match(f5) match(f6)
match(f7) match(f8) match(f9) match(f10) match(f11) match(f12)
match(print_screen) match(sys_req) match(scroll_lock) match(pause) match(brk)
match(grave) match(tilde)
match(num_1) match(exclamation)
match(num_2) match(at)
match(num_3) match(pound)
match(num_4) match(dollar)
match(num_5) match(percent)
match(num_6) match(power)
match(num_7) match(ampersand)
match(num_8) match(asterisk)
match(num_9) match(lparenthesis)
match(num_0) match(rparenthesis)
match(minus) match(underscore) match(equal) match(plus) match(backspace)
match(ins) match(del) match(home) match(end) match(page_up) match(page_down)
match(a) match(b) match(c) match(d) match(e) match(f)
match(g) match(h) match(i) match(j) match(k) match(l)
match(m) match(n) match(o) match(p) match(q) match(r)
match(s) match(t) match(u) match(v) match(w) match(x)
match(y) match(z)
match(A) match(B) match(C) match(D) match(E) match(F)
match(G) match(H) match(I) match(J) match(K) match(L)
match(M) match(N) match(O) match(P) match(Q) match(R)
match(S) match(T) match(U) match(V) match(W) match(X)
match(Y) match(Z)
match(lbracket) match(lbrace)
match(rbracket) match(rbrace)
match(backslash) match(pipe)
match(semicolon) match(colon)
match(apostrophe) match(quote)
match(comma) match(lcaret)
match(period) match(rcaret)
match(slash) match(question)
match(kp_1) match(kp_end)
match(kp_2) match(kp_down)
match(kp_3) match(kp_page_down)
match(kp_4) match(kp_left)
match(kp_5) match(kp_center)
match(kp_6) match(kp_right)
match(kp_7) match(kp_home)
match(kp_8) match(kp_up)
match(kp_9) match(kp_page_up)
match(kp_0) match(kp_insert)
match(kp_decimal) match(kp_delete)
match(kp_plus) match(kp_minus) match(kp_mul) match(kp_div) match(kp_enter)
match(num_lock) match(caps_lock)
match(up) match(down) match(left) match(right)
match(tab) match(enter) match(space)
match(lctrl) match(rctrl)
match(lalt) match(ralt)
match(lshift) match(rshift)
match(lsuper) match(rsuper)
match(menu)
#undef match
if(key & joypad_flag) {
uint joypad = (key & joypad_nummask) >> 8;
uint button = (key & joypad_keymask);
if(button == joypad_up) { sprintf(out, "joypad%d.up", joypad); return out; }
if(button == joypad_down) { sprintf(out, "joypad%d.down", joypad); return out; }
if(button == joypad_left) { sprintf(out, "joypad%d.left", joypad); return out; }
if(button == joypad_right) { sprintf(out, "joypad%d.right", joypad); return out; }
sprintf(out, "joypad%d.button%d", joypad, button & 127);
return out;
}
strcpy(out, "none");
return out;
}
static char find_t[256];
static const char *find(uint16 key) {
find(find_t, key);
return find_t;
}
};
#endif

View File

@@ -2,8 +2,8 @@
libsort : version 0.01 ~byuu (2006-11-15)
*/
#ifndef __LIBSORT
#define __LIBSORT
#ifndef LIBSORT_H
#define LIBSORT_H
template<typename T>
void sort(T list[], uint length) {
@@ -31,4 +31,4 @@ void sort(T list[], uint length, Tcmp comparator) {
}
}
#endif __LIBSORT
#endif

View File

@@ -2,7 +2,7 @@
#include "libstring.h"
#include "libstring_oo.cpp"
uint count(stringarray &str) { return str.size(); }
#include "libstring_array.cpp"
char chrlower(char c) {
if(c >= 'A' && c <= 'Z')return c + ('a' - 'A');
@@ -14,13 +14,12 @@ char chrupper(char c) {
return c;
}
char *strptr(string &str) { return str.s; }
char *strptr(const string &str) { return str.s; }
uint strlen(const string &str) { return strlen(strptr(str)); }
uint strlen(string &str) { return strlen(strptr(str)); }
int strcmp(string &dest, const char *src) { return strcmp(strptr(dest), src); }
int strcmp(const char *dest, string &src) { return strcmp(dest, strptr(src)); }
int strcmp(string &dest, string &src) { return strcmp(strptr(dest), strptr(src)); }
int strcmp(const string &dest, const char *src) { return strcmp(strptr(dest), src); }
int strcmp(const char *dest, const string &src) { return strcmp(dest, strptr(src)); }
int strcmp(const string &dest, const string &src) { return strcmp(strptr(dest), strptr(src)); }
int __stricmp(const char *dest, const char *src) {
while(*dest) {
@@ -30,22 +29,16 @@ int __stricmp(const char *dest, const char *src) {
}
return (int)chrlower(*dest) - (int)chrlower(*src);
}
int stricmp(string &dest, const char *src) { return __stricmp(strptr(dest), src); }
int stricmp(const char *dest, string &src) { return __stricmp(dest, strptr(src)); }
int stricmp(string &dest, string &src) { return __stricmp(strptr(dest), strptr(src)); }
void strcpy(string &dest, const char src) {
dest.reserve(2);
dest.s[0] = src;
dest.s[1] = 0;
}
int stricmp(const string &dest, const char *src) { return __stricmp(strptr(dest), src); }
int stricmp(const char *dest, const string &src) { return __stricmp(dest, strptr(src)); }
int stricmp(const string &dest, const string &src) { return __stricmp(strptr(dest), strptr(src)); }
void strcpy(string &dest, const char *src) {
int srclen = strlen(src);
dest.reserve(srclen);
strcpy(dest.s, src);
}
void strcpy(string &dest, string &src) { strcpy(dest, strptr(src)); }
void strcpy(string &dest, const string &src) { strcpy(dest, strptr(src)); }
uint strlcpy(char *dest, const char *src, uint length) {
uint srclen = strlen(src);
@@ -61,25 +54,18 @@ uint strlcpy(string &dest, const char *src, uint length) {
return strlcpy(strptr(dest), src, length);
}
uint strlcpy(string &dest, string &src, uint length) {
uint strlcpy(string &dest, const string &src, uint length) {
dest.reserve(length);
return strlcpy(strptr(dest), strptr(src), length);
}
void strcat(string &dest, const char src) {
int length = strlen(dest);
dest.reserve(length + 1);
dest.s[length] = src;
dest.s[length + 1] = 0;
}
void strcat(string &dest, const char *src) {
int srclen = strlen(src);
int destlen = strlen(dest);
dest.reserve(srclen + destlen);
strcat(dest.s, src);
}
void strcat(string &dest, string &src) { strcat(dest, strptr(src)); }
void strcat(string &dest, const string &src) { strcat(dest, strptr(src)); }
uint strlcat(char *dest, const char *src, uint length) {
uint destlen = strlen(dest), srclen = strlen(src);
@@ -95,7 +81,7 @@ uint strlcat(string &dest, const char *src, uint length) {
return strlcat(strptr(dest), src, length);
}
uint strlcat(string &dest, string &src, uint length) {
uint strlcat(string &dest, const string &src, uint length) {
dest.reserve(length);
return strlcat(strptr(dest), strptr(src), length);
}
@@ -111,8 +97,7 @@ string temp;
}
return temp;
}
string substr(string &dest, string &src, uint start, uint length) { return substr(dest, strptr(src), start, length); }
string substr(string &dest, const string &src, uint start, uint length) { return substr(dest, strptr(src), start, length); }
void strinsert(string &dest, const char *src, uint pos) {
string temp;
@@ -121,7 +106,7 @@ string temp;
strcat(dest, src);
strcat(dest, temp);
}
void strinsert(string &dest, string &src, uint pos) { strinsert(dest, strptr(src), pos); }
void strinsert(string &dest, const string &src, uint pos) { strinsert(dest, strptr(src), pos); }
void strremove(string &dest, uint start, uint length) {
int i, destlen = strlen(dest);
@@ -154,24 +139,23 @@ uint i = 0;
}
string &strupper(string &str) { strupper(strptr(str)); return str; }
bool strpos(const char *str, const char *key, uint &pos) {
int strpos(const char *str, const char *key) {
int ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return false;
if(ksl > ssl)return -1;
for(int i = 0; i <= ssl - ksl; i++) {
if(!memcmp(str + i, key, ksl)) {
pos = i;
return true;
return i;
}
}
return false;
return -1;
}
bool strpos(string &str, const char *key, uint &pos) { return strpos(strptr(str), key, pos); }
bool strpos(const char *str, string &key, uint &pos) { return strpos(str, strptr(key), pos); }
bool strpos(string &str, string &key, uint &pos) { return strpos(strptr(str), strptr(key), pos); }
int strpos(const string &str, const char *key) { return strpos(strptr(str), key); }
int strpos(const char *str, const string &key) { return strpos(str, strptr(key)); }
int strpos(const string &str, const string &key) { return strpos(strptr(str), strptr(key)); }
bool qstrpos(const char *str, const char *key, uint &pos) {
int qstrpos(const char *str, const char *key) {
int ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return false;
if(ksl > ssl)return -1;
for(int i = 0; i <= ssl - ksl;) {
uint8 x = str[i];
if(x == '\"' || x == '\'') {
@@ -180,17 +164,16 @@ int ssl = strlen(str), ksl = strlen(key);
if(i >= ssl)i = z;
}
if(!memcmp(str + i, key, ksl)) {
pos = i;
return true;
return i;
} else {
i++;
}
}
return false;
return -1;
}
bool qstrpos(string &str, const char *key, uint &pos) { return qstrpos(strptr(str), key, pos); }
bool qstrpos(const char *str, string &key, uint &pos) { return qstrpos(str, strptr(key), pos); }
bool qstrpos(string &str, string &key, uint &pos) { return qstrpos(strptr(str), strptr(key), pos); }
int qstrpos(const string &str, const char *key) { return qstrpos(strptr(str), key); }
int qstrpos(const char *str, const string &key) { return qstrpos(str, strptr(key)); }
int qstrpos(const string &str, const string &key) { return qstrpos(strptr(str), strptr(key)); }
void strtr(char *dest, const char *before, const char *after) {
int sl = strlen(dest), bsl = strlen(before), asl = strlen(after);
@@ -211,7 +194,7 @@ int i, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return false;
return (!memcmp(str, key, ksl));
}
bool strbegin(string &str, const char *key) { return strbegin(strptr(str), key); }
bool strbegin(const string &str, const char *key) { return strbegin(strptr(str), key); }
bool stribegin(const char *str, const char *key) {
int ssl = strlen(str), ksl = strlen(key);
@@ -227,14 +210,14 @@ int ssl = strlen(str), ksl = strlen(key);
}
return true;
}
bool stribegin(string &str, const char *key) { return stribegin(strptr(str), key); }
bool stribegin(const string &str, const char *key) { return stribegin(strptr(str), key); }
bool strend(const char *str, const char *key) {
int ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return false;
return (!memcmp(str + ssl - ksl, key, ksl));
}
bool strend(string &str, const char *key) { return strend(strptr(str), key); }
bool strend(const string &str, const char *key) { return strend(strptr(str), key); }
bool striend(const char *str, const char *key) {
int ssl = strlen(str), ksl = strlen(key);
@@ -250,7 +233,7 @@ int ssl = strlen(str), ksl = strlen(key);
}
return true;
}
bool striend(string &str, const char *key) { return striend(strptr(str), key); }
bool striend(const string &str, const char *key) { return striend(strptr(str), key); }
void strltrim(char *str, const char *key) {
int i, ssl = strlen(str), ksl = strlen(key);
@@ -290,9 +273,21 @@ int ssl = strlen(str), ksl = strlen(key);
}
void strirtrim(string &str, const char *key) { strirtrim(strptr(str), key); }
//does not work on type char* because function increases string length
void strtrim(char *str, const char *key) {
strltrim(str, key);
strrtrim(str, key);
}
void strtrim(string &str, const char *key) { strtrim(strptr(str), key); }
void stritrim(char *str, const char *key) {
striltrim(str, key);
strirtrim(str, key);
}
void stritrim(string &str, const char *key) { stritrim(strptr(str), key); }
//does not support char* type because function increases string length
void strquote(string &str) {
static string t;
string t;
strcpy(t, "\"");
strcat(t, str);
strcat(t, "\"");
@@ -321,9 +316,11 @@ bool strunquote(string &str) { return strunquote(strptr(str)); }
uint strhex(const char *str) {
uint r = 0, m = 0;
int i, ssl = strlen(str);
int i = 0, ssl = strlen(str);
uint8 x;
for(i = 0; i < ssl; i++) {
bool negate = (str[0] == '-');
if(negate)i++;
for(; i < ssl; i++) {
if(str[i] >= '0' && str[i] <= '9');
else if(str[i] >= 'A' && str[i] <= 'F');
else if(str[i] >= 'a' && str[i] <= 'f');
@@ -334,87 +331,56 @@ uint8 x;
if(x >= '0' && x <= '9')x -= '0';
else if(x >= 'A' && x <= 'F')x -= 'A' - 0x0a;
else if(x >= 'a' && x <= 'f')x -= 'a' - 0x0a;
else return r;
else break;
r |= x << m;
}
return r;
return !negate ? r : (uint)-r;
}
uint strhex(string &str) { return strhex(strptr(str)); }
int sstrhex(const char *str) {
if(str[0] == '-') {
return -strhex(str + 1);
}
return strhex(str);
}
int sstrhex(string &str) { return sstrhex(strptr(str)); }
uint strhex(const string &str) { return strhex(strptr(str)); }
uint strdec(const char *str) {
uint m = 1;
int i, r = 0, ssl = strlen(str);
int i = 0, r = 0, ssl = strlen(str);
uint8 x;
for(i = 0; i < ssl; i++) {
bool negate = (str[0] == '-');
if(negate)i++;
for(; i < ssl; i++) {
if(str[i] >= '0' && str[i] <= '9');
else break;
}
for(--i; i >= 0; i--, m *= 10) {
x = str[i];
if(x >= '0' && x <= '9')x -= '0';
else return r;
else break;
r += x * m;
}
return r;
return !negate ? r : (uint)-r;
}
uint strdec(string &str) { return strdec(strptr(str)); }
int sstrdec(const char *str) {
if(str[0] == '-') {
return -strdec(str + 1);
}
return strdec(str);
}
int sstrdec(string &str) { return sstrdec(strptr(str)); }
uint strdec(const string &str) { return strdec(strptr(str)); }
uint strbin(const char *str) {
uint r = 0, m = 0;
int i, ssl = strlen(str);
int i = 0, ssl = strlen(str);
uint8 x;
for(i = 0; i < ssl; i++) {
bool negate = (str[0] == '-');
if(negate)i++;
for(; i < ssl; i++) {
if(str[i] == '0' || str[i] == '1');
else break;
}
for(--i; i >= 0; i--, m++) {
x = str[i];
if(str[i] == '0' || str[i] == '1')x -= '0';
else return r;
else break;
r |= x << m;
}
return r;
return !negate ? r : (uint)-r;
}
uint strbin(string &str) { return strbin(strptr(str)); }
int sstrbin(const char *str) {
if(str[0] == '-') {
return -strbin(str + 1);
}
return strbin(str);
}
int sstrbin(string &str) { return sstrbin(strptr(str)); }
uint strbin(const string &str) { return strbin(strptr(str)); }
char *utoa(char *str, uint num) {
char *pstr = str;
uint mask = 1000000000;
while(mask > num)mask /= 10;
while(mask > 1) {
str[0] = '0';
while(num >= mask) { str[0]++; num -= mask; }
str++;
mask /= 10;
}
str[0] = '0' + num;
str++;
str[0] = 0;
return pstr;
sprintf(str, "%u", num);
return str;
}
string &utoa(string &str, uint num) {
@@ -424,14 +390,8 @@ string &utoa(string &str, uint num) {
}
char *itoa(char *str, uint num) {
char *pstr = str;
if(num < 0) {
str[0] = '-';
str++;
num = abs(int(num));
}
utoa(str, num);
return pstr;
sprintf(str, "%d", num);
return str;
}
string &itoa(string &str, uint num) {
@@ -441,20 +401,8 @@ string &itoa(string &str, uint num) {
}
char *htoa(char *str, uint num) {
char *pstr = str;
uint mask = 28, r;
while(mask && ((num >> mask) & 15) == 0)mask -= 4;
while(mask) {
r = (num >> mask) & 15;
str[0] = (r < 10) ? ('0' + r) : ('a' + r - 10);
str++;
mask -= 4;
}
r = num & 15;
str[0] = (r < 10) ? ('0' + r) : ('a' + r - 10);
str++;
str[0] = 0;
return pstr;
sprintf(str, "%x", num);
return str;
}
string &htoa(string &str, uint num) {
@@ -463,29 +411,6 @@ string &htoa(string &str, uint num) {
return str;
}
char *uhtoa(char *str, uint num) {
char *pstr = str;
uint mask = 28, r;
while(mask && ((num >> mask) & 15) == 0)mask -= 4;
while(mask) {
r = (num >> mask) & 15;
str[0] = (r < 10) ? ('0' + r) : ('A' + r - 10);
str++;
mask -= 4;
}
r = num & 15;
str[0] = (r < 10) ? ('0' + r) : ('A' + r - 10);
str++;
str[0] = 0;
return pstr;
}
string &uhtoa(string &str, uint num) {
str.reserve(16);
uhtoa(strptr(str), num);
return str;
}
char *btoa(char *str, uint num) {
char *pstr = str;
uint mask = 0x80000000;
@@ -502,7 +427,7 @@ uint mask = 0x80000000;
}
string &btoa(string &str, uint num) {
str.reserve(48);
str.reserve(64);
btoa(strptr(str), num);
return str;
}

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