Compare commits

..

43 Commits
v019 ... v027

Author SHA1 Message Date
byuu
4c43e85141 Update to bsnes v027 release.
This version replaces libui with miu -- a new GUI wrapper library, and cleans up large portions of the source code.
Unfortunately, the GUI rewrite took far, far longer than I ever imagined. As a result, no work has gone into the core emulation for this version. But with the GUI rewrite out of the way, that should change in the near future. And thanks to the new UI library, I can now begin work on adding a cross-platform debugger to bsnes, at long last.
Changelog:
    - Major source code cleanup (lib/, ui/miu/, ui/vai/)
    - Cheat code editor was broken in v0.026, this is now fixed
    - Cheat code file format simplified for human readability
    - Makefile install target improvements [belegdol]
    - libui replaced with miu GUI library
    - Custom video / audio / input drivers replaced with vai HW library
    - ppc and ppc64 libco targets added [Vas Crabb]
    - x86 and x86-64 libco targets now work on OS X [Lucas Newman]
2007-12-22 18:26:54 +00:00
byuu
9da42c18c3 Update to bsnes v026r04? release.
Another WIP. Consider this one v0.027 RC1.

             Bugs fixed:
 - cheat code editor works once again -- cart/ was not loading or
saving the files, and memory/ was not reading from it. Yeah, it was
completely broken in v0.026
 - miu/Win supports window.set_background_color(). The trick was to
capture WM_ERASEBKGND and use FillRect to draw the background myself.
 - miu/Win menubar toggle in fullscreen mode works as expected now for
me. Testing would be appreciated. A total shot in the dark, I tried
using SWP_FRAMECHANGED when resizing the windows, and it worked. It
seems to be an issue due to having two windows that are both set to
use the same menu (I have a hidden window I use for resize-purposes
only, because AdjustWindowRect doesn't work right on multi-line menus,
but the resize window is never visible.) I'm not sure exactly why
SWP_FRAMECHANGED fixed the problem, or why it wasn't needed in libui,
but it works, so I'll take it.
 - make install target uses "install" rather than cp+chmod, but
belegdol unfortunately removed his makefile patch, and I don't recall
where $(DESTDIR) and $(PREFIX) are supposed to go, so those aren't in
there yet ... belegdol, could you please repost that? You're of course
free to change my makefile with your packages as always in case it
gets missed before v027.

             Bugs remaining:
 - D3D renderer is still acting weird. If you start at 256x224 window
size, then the point video filter never works. If you resize to a
larger window and back to 256x224, the video image is linear filtered
no matter what. I tried to fix this tonight, but I had no luck. I'm
really not sure what's wrong, I don't think it's ever really worked
right. Should I fallback on the DDraw renderer for the next release?
It lacks the point filter mode (DDraw lacks an API to control mag
filtering), but that's it. Also, mudlord, PM me if I haven't given you
my WIP URL and you wanted to look at the latest stuff. I can never
remember who I gave the link to or not.
 - system.video / audio / input are not checked, so you get the
compiled defaults only. All vai drivers have now been ported, however.

             I changed the cheat code format. It is now:
             code = status, "description" \r\n

             Or for an example:
             7e1234:56 = enabled, "Infinite Lives"
             7e1235:67 = disabled, "Infinite Health"

 A little easier to read. But maybe still not perfect. I'd really like
to unify the .cht file format with other SNES emu devs ... I don't
want to use a binary file format like ZSNES and SNES9x does.

 I tried testing log audio data -- it seems to be working for me both
on Windows and Linux. FitzRoy, maybe the file isn't going to the
folder you are expecting? Or maybe I fixed it and didn't realize it?
Hmm ...

             Anything else I'm forgetting before a new release? Anyone
see any new / show stopping bugs?

[No archive available]
2007-12-20 10:43:00 +00:00
byuu
d115c7f6aa Update to bsnes v026r03? release.
Another WIP. This one builds on Windows and Linux, and the binary has
the terminal window disabled.

             Bugs fixed:
             - Added WM_ENTERMENULOOP message. Fixes audio looping for
the 37th time since I started on bsnes.
             - Esc toggles menu properly
 - F11 fullscreen centers, but only to the screen, not to the window
(meaning when the menubar is visible, it isn't really centered) --
this is because GTK+ does not return the correct widget size after
calling gtk_window_fullscreen() for up to ~200ms after processing all
messages via gtk_main_iteration_do(), and thus I can't make a
window.get_size() function. I really hope
GetSystemMetrics(SM_CXSCREEN) and gdk_screen_width() only return the
width of the active monitor, and not both for multi-monitor setups
 - Background of main window is black on Linux only. Only one
background brush per class for Windows. It may end up staying gray on
Windows for the next release ...
 - miu/Win enable/disable works. Even for menu items now, so I can
disable features that aren't supported by certain drivers now.

             Bugs remaining:
             - bsnes/Win background in fullscreen mode is gray --
quite ugly
             - D3D still blurring images even with perfect multiplier
             - cheat code editor still doesn't load .cht files on ROM
load

             New bugs:
             - bsnes/Win menubar is ultrafucked in fullscreen mode if
you toggle it on and off with esc. I have _no_ idea what the hell is
up with that. Code to show and hide the menu is identical to
libui/bsnes v026. Not sure I can fix this one. Basically, when the
menu gets toggled back on, clicking it does nothing, and if you press
alt, it will pop up the menu, but it will be _below_ the visible
menubar, so you end up seeing two of them. And you can only access the
new menubar via keyboard. Weird stuff ... could use some help here.
Anyone ever seen or heard of anything like this before?
             - I still need to work on that makefile cp+chmod ->
install thing for belegdol, I think ...

[No archive available]
2007-12-19 14:39:00 +00:00
byuu
2efce0fd83 Update to bsnes v026r02? release.
New WIP. Much, much closer to release quality. Linux port (probably)
won't compile at the moment due to minor changes to miu and vai. I
left the console enabled for this WIP.

             Bugs fixed:
             - Windows always appear at 0,0 instead of centered
 - Input capture window doesn't actually read anything. I actually can
get this working now, I just don't like the hacky way I did it before.
             - miu doesn't send Key events, so no F11 / esc shortcut
keys.
 - miu/Win is still missing some event messages, so some controls may
appear unresponsive. miu/Linux should be complete.
             - miu/Win may still send duplicate messages in some
cases, like that old log audio option bug was doing
             - miu lacks an on_show event, so the config window can't
set focus to the listbox on show just yet
 - bsnes will no longer crash when you try and load a GZ / ZIP / JMA
file with the support not built in (it obviously won't play the games
either) [Richard Bannister]

             Bugs remaining:
             - D3D still blurring image, haven't looked at it yet
 - Cheat code list never populates when loading ROM, probably doesn't
save either (I probably removed that code when rewriting cart/ and
memory/ a while back)
 - miu doesn't emit WM_ENTERMENULOOP, meaning audio cycles when going
into the menu. I wish there were a way to make it pre-emptive like
GTK+ without needing multiple threads ...

             New bugs:
             - Esc doesn't toggle menu yet
 - F11 fullscreen doesn't center, and window background is gray. This
will be tricky, as I only have one RegisterClass() in miu, but you can
only have one HBRUSH per class. Hopefully there's a window message I
can hijack to add back window.set_background_color().
             - miu/Win enable() / disable() doesn't work -- input
config dropdowns active, despite them not working yet

 Other than that, any new bug reports would be appreciated. I hope to
have v027 out by Sunday, but I may not make it in time.

[No archive available]
2007-12-18 12:29:00 +00:00
byuu
f6732133e7 Update to bsnes v026r01? release.
Alright, it's been a full month now since the last private WIP.

 I have Direct3D, DirectSound and DirectInput all working on the
Windows port now; and Xv, GTK+ Video, libao and XInput working on the
Linux port, so now's a good time for a beta.

             Note that countless things are broken, still.
             - D3D still blurring image, haven't looked at it yet
 - Cheat code list never populates when loading ROM, probably doesn't
save either (I probably removed that code when rewriting cart/ and
memory/ a while back)
             - Windows always appear at 0,0 instead of centered
 - miu doesn't emit WM_ENTERMENULOOP, meaning audio cycles when going
into the menu. I wish there were a way to make it pre-emptive like
GTK+ without needing multiple threads ...
 - Input capture window doesn't actually read anything. I actually can
get this working now, I just don't like the hacky way I did it before.
             - miu doesn't send Key events, so no F11 / esc shortcut
keys.
 - miu/Win is still missing some event messages, so some controls may
appear unresponsive. miu/Linux should be complete.
             - miu/Win may still send duplicate messages in some
cases, like that old log audio option bug was doing
             - miu lacks an on_show event, so the config window can't
set focus to the listbox on show just yet

             Any bugs outside of this that seem serious, please tell
me about. Otherwise, I'm working on the rest still :/

[No archive available]
2007-12-16 10:08:00 +00:00
byuu
95547f4ff8 Update to bsnes v026 release.
- Major source code cleanup
    - Completely rewrote memory mapper to support runtime MMCs
    - Updated S-DD1 MMC to use new memory mapping interface
    - Improved S-DD1 emulation, thanks to information from orwannon
    - Added support for SameGame -- load via "Load Special -> Load BS-X Slotted Cart" menu option
    - Completely rewrote cartridge loader to support BS-X, BS-X slotted carts and ST carts
    - Created custom dialog windows for multicart loading
    - Improved generic memory mapper, which eliminates the need for cart.db [Nach]
    - Added BS-X slotted cart detection to generic memory mapper [Nach]
    - Linux port will now ignore keypresses when window is inactive
    - Linux port will use much less CPU power when idle
    - Added detailed compilation instructions to Makefile for Linux port
    - Added "make install" target and PNG program icon for Linux port
    - Switched Windows compiler to MinGW/GCC4
    - Windows executable is now packed with UPX to decrease filesize
    - Removed .ufo, .gd7 and .078 ROM extensions; added .bs extension
    - Added preliminary support for the BS-X base unit, BS-X base cartridge + MMC, and BS-X flash I/O
2007-11-18 21:49:20 +00:00
byuu
4f5bdfe347 Update to bsnes v025r12? release.
New WIP is up.

 I fixed PSRAM size, it's now 512kbytes. SRAM was correct before at
32kbytes. I also now save these files to "bsxbios.psr" (PSRAM) and
"bsxbios.srm" (SRAM). I honestly don't know if the PSRAM is supposed
to be battery backed or not. If it's not, it'll be easy enough to
remove. I imagine it is, because that's where you'd store your games
on if you lacked a flash cart. Would be pretty lousy to have it wiped
every time you power cycle.

 I also save the PSRAM+SRAM data only once, just as a real BS-X cart
would work, and it also makes the Ancient Tablets series work with no
file renaming needed. I may add an option later to save these files
separately per-game.

 BS-X support overall is still pitiful. bs-x.txt doc says $03 has to
be set to mirror PSRAM, SNES9x thinks it needs to be clear. Neither
know whether it affects just $60-6f or also $70-77. bs-x.txt doesn't
say to mirror hi/lo on PSRAM based on $02 setting, but SNES9x seems to
try it. LoROM doesn't map well into 64k granularity banks. Still don't
emulate $0c/$0d flash i/o register enable. Base unit is still
completely unsupported, and it's apparently needed for some games. And
I have no intentions of including an internal database of times to
manually hack the clock (even while the system is running!) ala
SNESGT. I'm just going to map the BS-X base unit RTC to the PC clock.
Some stuff like Dragon Slayer Eiyuu Densetsu work fine under regular
mapping, yet don't work with BS-X mapping. No idea why. Still don't
hack-enable headers during load, so that has to be done manually still
(do this if the game doesn't show up in cart menu. Make a backup if
you care.)

 Added SameGame support. Load it with "Load BS-X Slotted Cartridge"
(that's what it is, after all.) Unfortunately, I don't know what the
memory map is supposed to be, so the add-on cart doesn't appear to be
working. Or maybe I just can't figure out how to tell.
 Nach or anyone else, would you mind sharing that info with me? The
code in SNES9x looks identical to what I have, but loading the FEoEZ
512kbyte cart doesn't seem to do anything. Well, at least the game
itself works under this menu option now.

 Fixed config::path.save, and added realpath() for the Linux port, so
./ paths work too. Of course it won't be useful at all if you
"install" bsnes to /usr/bin, but if you keep it in its own folder,
it's helpful.

 Fixed the SRAM mapping bug affecting Fire Emblem 776. Also optimized
the file loading stuff a little more, removing a couple redundant ROM
memcpy's. Still far from perfect.

             If possible, please test this WIP a lot. I'd like to post
a new public release this weekend.

[No archive available]
2007-11-17 10:09:00 +00:00
byuu
49b0bed1a6 Update to bsnes v025r11? release.
New WIP up. Has a Windows binary this time.

 I completed the BSX cart MMIO registers. It definitely doesn't work
too well. For one, I don't override the header bit in the emulator, so
anyone testing will have to modify the bit as discussed first. It also
doesn't work on my only other BS game, BS Dragon Quest. I don't know
why, it throws a St. GIGA error (09). Maybe it needs base unit
emulation ... who knows. There's probably bugs in the cart and flash
reg support, too.







> My notes on the subject tell me it's the year of download or'd with
> other data. I haven't entirely figured out everything it's or'd with
> though.




 Well, Lancer said the BIOS makes sure d15 of $ffd5,$ffd4 is not set.
If it is, the game does not appear in the list of games you can start.
I'm guessing certain (all?) games expired after a certain date. If
that's true, then we're quite fortunate that only a header bit was
set, rather than the entire cart erased. So then, most likely all of
these games with $80 in $ffd5 appeared "blank", but were dumped and
the games retrieved.

 Sigh, such a sad fate. Really makes you wonder why Nintendo hates
their fanbase so much to go out of their way to destroy these games.

[No archive available]
2007-11-15 10:43:00 +00:00
byuu
1554170312 Update to bsnes v025r10? release.
Yeah, even if we still don't have the S-DD1 100% understood, we can at
least get all known software working properly. And now we at least
have all the registers understood, just the edge cases that need to be
tested. I'm honestly glad I was incorrect in that the original patch
worked on hardware. Given it will never be updated again, this means I
won't have to get bug reports from now unto infinity about it.

 I posted a new binary WIP. If anyone wants to play through a few
levels of SFA2 or dungeons in SO and look for corrupted graphics, it'd
be appreciated. I'm sure it'll be fine, though. Oh, and the speedhit I
reported a few days ago was wrong. The old builds ran at the same
speed. Seems I have a ~6-8fps variance in that game per reboot.

 New WIP also starts the BS-X mapping. You can map in a cart now, but
it immediately freezes because the flash I/O registers do not respond.

             ---

             Also, I'd like to get serious about emulating the
SPC7110. But to do that, I need custom-made hardware.

 I asked someone about this already, but I may as well throw it out
there publicly in case anyone else would like to help.

             Here is the PCB for one of the SPC7110 games:
             http://nsrt.edgeemu.com/INFO/chip-pix/SPC7110.JPG

 What I would need is for the top two ICs to be desoldered, and socket
IC connectors to be placed on them instead. I would also obviously
need lots of compatible EEPROMs to connect to it (just two would
suffice, more would be better as it's quite possible I'd wear out the
write cycles with lots of intense testing, or bend up the pins like I
usually do when removing socket ICs).

             I would also need software+hardware to actually flash the
EEPROMs, as I don't have anything like this presently.

 More complex solutions, such as a ROM emulator with a parallel/USB
interface to the PC would be acceptable as well. So long as it's
something I can reprogram at my relatively low skill level.

 One cart would suffice, but again, the more carts the better in case
of failure. And I'd also like to see about sending one to another
person who's been interested in the SPC7110 for a while. So, three or
four preferred.

             I can supply the cartridges and money for time +
shipping. I'd prefer someone who _knows_ they can do this well try, so
that we don't ruin any unnecessary cartridges and so that the test
cartridges are as durable as possible. Especially since they most
likely won't be encased anymore.

             So, any takers?

[No archive available]
2007-11-13 16:08:00 +00:00
byuu
ec137d6fb9 Update to bsnes v025r09? release.
I posted a new WIP last night. No binary this time,
sorry.
 It redoes the memory mapping of the cartridge and moves it into the
cartridge class -- forking each slotted cart away from the base cart
memory.
 This allows me to determine the proper sizes for each individual cart
again, so I can now map RPG Tsukuru II again correctly.

               EDIT:

               Ahahahahahah!! Finally! I figured out how the S-DD1
$4800 and $4801 registers work! :D

               Original game transfer (should transfer
compressed->decompressed):







    CC2418 LDA #$4000 A:00DA X:F458 Y:1C00 S:01FA DB:00 D:0000 P:01 e
                       CC241B PEA $00DB [0000DB] A:4000 X:F458 Y:1C00
    S:01FA DB:00 D:0000 P:01 e
                       CC241E LDX #$E8ED A:4000 X:F458 Y:1C00 S:01F8
    DB:00 D:0000 P:01 e
                       CC2421 LDY #$0800 A:4000 X:E8ED Y:1C00 S:01F8
    DB:00 D:0000 P:81 e
                       CC2424 JSR $2470 [CC2470] A:4000 X:E8ED Y:0800
    S:01F8 DB:00 D:0000 P:01 e
                       CC2470 STA $2116 [002116] A:4000 X:E8ED Y:0800
    S:01F6 DB:00 D:0000 P:01 e
                       CC2473 SEP #$20 A:4000 X:E8ED Y:0800 S:01F6
    DB:00 D:0000 P:01 e
                       ;* enable $4800 *
                       CC2475 LDA #$01 A:4000 X:E8ED Y:0800 S:01F6
    DB:00 D:0000 P:21 e
                       CC2477 STA $4800 [004800] A:4001 X:E8ED Y:0800
    S:01F6 DB:00 D:0000 P:21 e
                       CC247A LDA #$09 A:4001 X:E8ED Y:0800 S:01F6
    DB:00 D:0000 P:21 e
                       CC247C STA $4300 [004300] A:4009 X:E8ED Y:0800
    S:01F6 DB:00 D:0000 P:21 e
                       CC247F LDA #$18 A:4009 X:E8ED Y:0800 S:01F6
    DB:00 D:0000 P:21 e
                       CC2481 STA $4301 [004301] A:4018 X:E8ED Y:0800
    S:01F6 DB:00 D:0000 P:21 e
                       CC2484 STX $4302 [004302] A:4018 X:E8ED Y:0800
    S:01F6 DB:00 D:0000 P:21 e
                       CC2487 LDA $03,S [0001F9] A:4018 X:E8ED Y:0800
    S:01F6 DB:00 D:0000 P:21 e
                       CC2489 STA $4304 [004304] A:40DB X:E8ED Y:0800
    S:01F6 DB:00 D:0000 P:A1 e
                       CC248C STY $4305 [004305] A:40DB X:E8ED Y:0800
    S:01F6 DB:00 D:0000 P:A1 e
                       CC248F LDA #$01 A:40DB X:E8ED Y:0800 S:01F6
    DB:00 D:0000 P:A1 e
                       CC2491 STA $4801 [004801] A:4001 X:E8ED Y:0800
    S:01F6 DB:00 D:0000 P:21 e
                       CC2494 PHA A:4001 X:E8ED Y:0800 S:01F6 DB:00
    D:0000 P:21 e
                       CC2495 PLA A:4001 X:E8ED Y:0800 S:01F5 DB:00
    D:0000 P:21 e
                       CC2496 STA $420B [00420B] A:4001 X:E8ED Y:0800
    S:01F6 DB:00 D:0000 P:21 e
                       CC2499 STZ $4800 [004800] A:4001 X:E8ED Y:0800
    S:01F6 DB:00 D:0000 P:21 e
                       CC249C REP #$20 A:4001 X:E8ED Y:0800 S:01F6
    DB:00 D:0000 P:21 e
                       CC249E RTS A:4001 X:E8ED Y:0800 S:01F6 DB:00
    D:0000 P:01 e




               Custom transfer (should transfer
decompressed->decompressed):







    CC2428 LDA #$5008 A:00DB X:E8ED Y:0800 S:01FA DB:00 D:0000 P:01 e
                       CC242B PEA $00E9 [0000E9] A:5008 X:E8ED Y:0800
    S:01FA DB:00 D:0000 P:01 e
                       CC242E LDX #$0400 A:5008 X:E8ED Y:0800 S:01F8
    DB:00 D:0000 P:01 e
                       CC2431 LDY #$04E0 A:5008 X:0400 Y:0800 S:01F8
    DB:00 D:0000 P:01 e
                       CC2434 JSR $244C [CC244C] A:5008 X:0400 Y:04E0
    S:01F8 DB:00 D:0000 P:01 e
                       CC244C STA $2116 [002116] A:5008 X:0400 Y:04E0
    S:01F6 DB:00 D:0000 P:01 e
                       CC244F SEP #$20 A:5008 X:0400 Y:04E0 S:01F6
    DB:00 D:0000 P:01 e
                       ;* disable $4800 *
                       CC2451 STZ $4800 [004800] A:5008 X:0400 Y:04E0
    S:01F6 DB:00 D:0000 P:21 e
                       ;* $43x0.d3 (fixed transfer flag) is irrelevent
    to S-DD1 *
                       ;* can be #$01 or #$09 here *
                       CC2454 LDA #$09 A:5008 X:0400 Y:04E0 S:01F6
    DB:00 D:0000 P:21 e
                       CC2456 BRA $247C [CC247C] A:5009 X:0400 Y:04E0
    S:01F6 DB:00 D:0000 P:21 e
                       CC247C STA $4300 [004300] A:5009 X:0400 Y:04E0
    S:01F6 DB:00 D:0000 P:21 e
                       CC247F LDA #$18 A:5009 X:0400 Y:04E0 S:01F6
    DB:00 D:0000 P:21 e
                       CC2481 STA $4301 [004301] A:5018 X:0400 Y:04E0
    S:01F6 DB:00 D:0000 P:21 e
                       CC2484 STX $4302 [004302] A:5018 X:0400 Y:04E0
    S:01F6 DB:00 D:0000 P:21 e
                       CC2487 LDA $03,S [0001F9] A:5018 X:0400 Y:04E0
    S:01F6 DB:00 D:0000 P:21 e
                       CC2489 STA $4304 [004304] A:50E9 X:0400 Y:04E0
    S:01F6 DB:00 D:0000 P:A1 e
                       CC248C STY $4305 [004305] A:50E9 X:0400 Y:04E0
    S:01F6 DB:00 D:0000 P:A1 e
                       CC248F LDA #$01 A:50E9 X:0400 Y:04E0 S:01F6
    DB:00 D:0000 P:A1 e
                       CC2491 STA $4801 [004801] A:5001 X:0400 Y:04E0
    S:01F6 DB:00 D:0000 P:21 e
                       CC2494 PHA A:5001 X:0400 Y:04E0 S:01F6 DB:00
    D:0000 P:21 e
                       CC2495 PLA A:5001 X:0400 Y:04E0 S:01F5 DB:00
    D:0000 P:21 e
                       CC2496 STA $420B [00420B] A:5001 X:0400 Y:04E0
    S:01F6 DB:00 D:0000 P:21 e
                       CC2499 STZ $4800 [004800] A:5001 X:0400 Y:04E0
    S:01F6 DB:00 D:0000 P:21 e
                       CC249C REP #$20 A:5001 X:0400 Y:04E0 S:01F6
    DB:00 D:0000 P:21 e
                       CC249E RTS A:5001 X:0400 Y:04E0 S:01F6 DB:00
    D:0000 P:01 e




               Original transfer right after custom transfer:







    CC2438 LDA #$4000 A:00E9 X:0400 Y:04E0 S:01FA DB:00 D:0000 P:01 e
                       CC243B PEA $00DC [0000DC] A:4000 X:0400 Y:04E0
    S:01FA DB:00 D:0000 P:01 e
                       CC243E LDX #$E0E8 A:4000 X:0400 Y:04E0 S:01F8
    DB:00 D:0000 P:01 e
                       CC2441 LDY #$1080 A:4000 X:E0E8 Y:04E0 S:01F8
    DB:00 D:0000 P:81 e
                       CC2444 JSR $2458 [CC2458] A:4000 X:E0E8 Y:1080
    S:01F8 DB:00 D:0000 P:01 e
                       CC2458 STA $2181 [002181] A:4000 X:E0E8 Y:1080
    S:01F6 DB:00 D:0000 P:01 e
                       CC245B SEP #$20 A:4000 X:E0E8 Y:1080 S:01F6
    DB:00 D:0000 P:01 e
                       CC245D LDA #$7F A:4000 X:E0E8 Y:1080 S:01F6
    DB:00 D:0000 P:21 e
                       CC245F STA $2183 [002183] A:407F X:E0E8 Y:1080
    S:01F6 DB:00 D:0000 P:21 e
                       CC2462 LDA #$01 A:407F X:E0E8 Y:1080 S:01F6
    DB:00 D:0000 P:21 e
                       ;* $4800 enabled again *
                       CC2464 STA $4800 [004800] A:4001 X:E0E8 Y:1080
    S:01F6 DB:00 D:0000 P:21 e
                       CC2467 LDA #$08 A:4001 X:E0E8 Y:1080 S:01F6
    DB:00 D:0000 P:21 e
                       CC2469 STA $4300 [004300] A:4008 X:E0E8 Y:1080
    S:01F6 DB:00 D:0000 P:21 e
                       CC246C LDA #$80 A:4008 X:E0E8 Y:1080 S:01F6
    DB:00 D:0000 P:21 e
                       CC246E BRA $2481 [CC2481] A:4080 X:E0E8 Y:1080
    S:01F6 DB:00 D:0000 P:A1 e
                       CC2481 STA $4301 [004301] A:4080 X:E0E8 Y:1080
    S:01F6 DB:00 D:0000 P:A1 e
                       CC2484 STX $4302 [004302] A:4080 X:E0E8 Y:1080
    S:01F6 DB:00 D:0000 P:A1 e
                       CC2487 LDA $03,S [0001F9] A:4080 X:E0E8 Y:1080
    S:01F6 DB:00 D:0000 P:A1 e
                       CC2489 STA $4304 [004304] A:40DC X:E0E8 Y:1080
    S:01F6 DB:00 D:0000 P:A1 e
                       CC248C STY $4305 [004305] A:40DC X:E0E8 Y:1080
    S:01F6 DB:00 D:0000 P:A1 e
                       CC248F LDA #$01 A:40DC X:E0E8 Y:1080 S:01F6
    DB:00 D:0000 P:A1 e
                       CC2491 STA $4801 [004801] A:4001 X:E0E8 Y:1080
    S:01F6 DB:00 D:0000 P:21 e
                       CC2494 PHA A:4001 X:E0E8 Y:1080 S:01F6 DB:00
    D:0000 P:21 e
                       CC2495 PLA A:4001 X:E0E8 Y:1080 S:01F5 DB:00
    D:0000 P:21 e
                       CC2496 STA $420B [00420B] A:4001 X:E0E8 Y:1080
    S:01F6 DB:00 D:0000 P:21 e
                       CC2499 STZ $4800 [004800] A:4001 X:E0E8 Y:1080
    S:01F6 DB:00 D:0000 P:21 e
                       CC249C REP #$20 A:4001 X:E0E8 Y:1080 S:01F6
    DB:00 D:0000 P:21 e
                       CC249E RTS A:4001 X:E0E8 Y:1080 S:01F6 DB:00
    D:0000 P:01 e




 I was completely wrong, and was thrown off by ZSNES' memory remapping
magic that worked due to an oversight with $43x0.d3, or the fixed
transfer flag. I never added a check for the fixed transfer flag
because it quite honestly made no sense. Why would the S-DD1 care
about that?

               Turns out, it doesn't. What really matters is $4800.
The register everyone currently ignores completely.

               I figured out what purpose it serves: it's a sticky
toggle, whereas $4801 is a loose toggle.

 It works like this: in order for the S-DD1 to decompress a DMA
transfer, both $4800 and $4801 have to be set. Upon completion of the
transfer, $4801 is cleared. But $4800 is not.

 If you look at the above logs, it becomes clear. And it's all
contained inside the S-DD1 code. It has nothing to do with $43x0.

 Now, how can I verify this? orwannon made a flash cart for Star Ocean
and ran my old title screen patch on it. Sure enough, it did not try
and decompress the graphics data, despite the fixed transfer flag
being set. That tells us that the fixed transfer flag has nothing to
do with this.

 What's interesting is that every single S-DD1 supporting emulator
works just fine with my title screen patch. Meaning that they've all
implemented these two registers wrong.

 What was also interesting is that it's supposedly been confirmed that
the patched SO works on real hardware. That means the bug was in bsnes
after all. No excuses, I was flat out wrong. My sincere apologies.

 I've added the above changes, and bsnes now works with the original
patch, and fails with my custom patch. This mimics the behavior of
real hardware.

 Huge thanks to orwannon for the screenshot of my patch running on
real hardware. This fix wouldn't have been possible without that.

[No archive available]
2007-11-12 21:52:00 +00:00
byuu
aee683a475 Update to bsnes v025r08? release.
New WIP up.

 I spent four hours completely rewriting everything but the generic
header parsing code in src/cart. I'm now happy with the code both in
src/memory and src/cart. Hoorah.

 With the new load_cart() functionality, I made the "Load Special"
menu entries functional. For those of you stuck on Windows or without
WIP access, you can see how nice the load menus look on Linux below :)

             http://byuu.cinnamonpirate.com/bsnes/images/ui_bsx.png
             http://byuu.cinnamonpirate.com/bsnes/images/ui_st.png

 There is one bug: because of the way I map the slotted carts into one
contigious chunk of ROM (and hence update the size accordingly), it
throws off the memory mirroring on some of the BS-X slotted cart games
(like RPG Tsukuru II). I need to work on that a bit. For now, you can
play it through the normal load cartridge menu option.

 And of course, there's still that annoying Windows issue where the
main window steals focus after loading a ROM. Haven't looked into that
yet.

 And I still need to rework the file extension stuff per previous
discussions. It'd be nice to have the BS-X / ST windows only show .bs
/ .st ROMs by default.

[No archive available]
2007-11-05 07:22:00 +00:00
byuu
cdbf07b642 Update to bsnes v025r07? release.
Ok, posted the new WIP with the LoROM map corrections. This one also
modified the load special menu. They now bring up a new window that
lets you select the base cart + slot cart(s). However, the menus do
not work yet. There's also some odd issue that it loses focus when you
select a ROM from the browse button, but only on Windows. Hitting load
just hides the window. I also need to add code to automatically load /
save the BIOS filenames where applicable.

Also, forgot to mention last time, but I added a new config file
option, cpu.wram_initial_value or something like that. It's purpose
should be pretty obvious.

[No archive available]
2007-11-04 11:36:00 +00:00
byuu
8a857dada3 Update to bsnes v025r06? release.
Ok, new WIP up. Pretty much all of the credit goes to others, this
time.

             Changelog:
             - I forgot to set the region, so PAL games were running
as NTSC; this is fixed
             - Added Nach's BS-X slotted flashcart detection (added
his Ys'3 SRAM detection earlier)
 - Used BSC-1A7M-10 PCB mapper from Overload's documentation for the
generic BS-X slotted cart games; Derby Stallion '96, Sound Novel
Tsukuru and RPG Tsukuru II are all playable once again; hopefully the
rest of the slotted games work, too (sans the SA-1 game(s)). Please
test if you can
 - Added krom's (and I suppose Nach's earlier submitted) MinGW32 icon
support; so FitzRoy's wonderful icon is there now on the EXE -- still
need to add it to the window titlebar (easy on Windows), and to Linux
in general, ugh
 - Removed win-mingw4-lui target, simplifying Makefile. Use win-mingw-
lui now. Thanks again to krom's suggestion to just copy the MinGW4
-sjlj files, that worked great
             - Some more cleanup work to src/cart. Still a lot to go
here.

 Everything that was playable in the last release should now be
playable, excepting Yoshi's Island music. Please let me know if
anything is broken that wasn't before now.

 As always, I'm really thankful to everyone for their contributions.
My program would be useless if not for all the help I've gotten from
everyone else.

             ---

 Now then, I aim to support those BS-X slotted cart games as well. But
one thing I did not know until today was that you could actually
exchange those carts between games. That ruins the model I planned to
use for them (eg make romname.smc -> romname.bsf files).

 Thinking about it -- I really need to completely redesign file
loading. BS-X and Sufami Turbo stuff really throws off the "Load ROM"
paradigm that is so popular amongst emulators.

 I'm thinking ... remove the "Load Special" menu completely. Modify
the main ROM loading routine to parse what exactly is being loaded.

 If it's a BS-X slotted cart, pop up a menu that lets one optionally
select to load an additional flash cart, or cancel the menu to load
nothing in the slot. This won't be hot-swappable in-game.

 If it's a Sufami Turbo cart, assume Slot A for the cart. If this game
supports dual slotting*, pop up an additional menu to select the Slot
B game, which can also be left empty. (* perhaps popup the menu no
matter what, to more closely simulate that with real hardware, you
could stick incompatible games in both slots anyway?)

             Same deal for Same Game, G-Next, and all that other crap,
if or whenever I end up supporting those.

 I think it's best to keep the BIOS stuff in the config file, rather
than giving an optional popup menu to modify which BIOS to load. The
reason being that it will allow direct loading of BS-X games with no
need to ever show a popup menu.

 Lastly, I will have to add a new Misc menu option to generate empty
BS-X flashcart files. Though it's really easy to make one, I imagine
end users might have trouble doing that.

             Ideas or suggestions welcome.

[No archive available]
2007-11-02 09:30:00 +00:00
byuu
ab1975a6cb Update to bsnes v025r05? release.
I mentioned that it wasn't there. Exact reason was because I reloaded
Ubuntu and Windows, and I really hate installing Visual C++. It takes
forever. I posted a new WIP, and built it with MinGW4. Need to figure
out how to get the icon into the binary with MinGW.

             Anyway, new stuff in the WIP:

 - Much, much faster mirror() function; thanks to lots of help from
Nach (doesn't speed anything up, but might help with BS-X MMIO
registers)
             - Removed cart.db and all database-related code, now that
Ys3 works
             - Lots of code cleanups everywhere
             - New help information for trying to run ./configure or
make by itself
             - Cheap temporary MinGW fix for non-C99 vsnprintf

 The BS-X slot games (Derby Stallion et al) won't work on this
release. Nach gave me the code to detect those, and I'll get that
mapper in eventually before the next release. Also, Yoshi's Island
won't play audio anymore most likely.

 If anything else is broken, it's due to mapping. Please let me know
so I can fix it. If there are more than three broken games, that's
good -- please don't overwhelm me with a list of 500+ broken games in
the morning :)

             EDIT: fixed the Windows issues I was having. The Realtek
HD Audio driver software is fucking stupid. You _have_ to unplug your
speakers, reconnect them, and then select line out (rather than the
option for speakers) to get audio. This is the _only_ way to get
audio. And apparently both regular Winamp (without visualization) and
Mozilla Firefox now need DEP turned off not to crash the fuck all over
themselves constantly. Wonderful.

 EDIT2: forgot to set the region, so PAL games will run as though they
are NTSC. Most will probably give you an error splash screen. I'll fix
that.

[No archive available]
2007-10-31 10:18:00 +00:00
byuu
476a1c819a Update to bsnes v025r04? release.
New WIP up. This one's a bit better than last, but I
don't want bug reports yet. This one only maps generic LoROM and HiROM
games.

 Took about four or five hours, but I reworked most of the new memory
mapper yet again. SRAM should be working now, and I managed to gain
back the speed lost by dropping the address masking and forcing Visual
C++ to inline (__forceinline). The masking was no good anyway, because
the ROM file loaded in is definitely not always a power of two, which
means I'd have to use modulus and holy fuck no I'm not adding a
division for every memory access.

 The old memory mapper didn't have this either, as it stored a bunch
of pointers into memory chunks. The new one just stores one pointer
plus integer offsets into that pointer (a bit slower but cleaner and
necessary for abstraction), so it's really mostly the same thing.

 Man, I was looking at my old generic LoROM / HiROM mapper, and the
difference from that and what I have now is astounding ... it would
seem I've certainly gotten better at programming since then.







    /* new */
                       void sBus::map_generic() {
                       switch(cartridge.info.mapper) {
                       case Cartridge::LOROM: {
                       map(MapLinear, 0x00, 0x3f, 0x8000, 0xffff,
    memory::rom);
                       map(MapLinear, 0x80, 0xbf, 0x8000, 0xffff,
    memory::rom);
                       map(MapLinear, 0x40, 0x7f, 0x0000, 0xffff,
    memory::rom);
                       map(MapLinear, 0xc0, 0xff, 0x0000, 0xffff,
    memory::rom);
                       } break;
                       case Cartridge::HIROM: {
                       map(MapShadow, 0x00, 0x3f, 0x8000, 0xffff,
    memory::rom);
                       map(MapShadow, 0x80, 0xbf, 0x8000, 0xffff,
    memory::rom);
                       map(MapLinear, 0x40, 0x7f, 0x0000, 0xffff,
    memory::rom);
                       map(MapLinear, 0xc0, 0xff, 0x0000, 0xffff,
    memory::rom);
                       } break;
                       }

                       if(memory::sram.size() == 0) { return; }
                       map(MapLinear, 0x20, 0x3f, 0x6000, 0x7fff,
    memory::sram);
                       map(MapLinear, 0xa0, 0xbf, 0x6000, 0x7fff,
    memory::sram);
                       map(MapLinear, 0x70, 0x7f, 0x0000, 0x7fff,
    memory::sram);

                       if(cartridge.info.mapper != Cartridge::LOROM) {
    return; }
                       map(MapLinear, 0xf0, 0xff, 0x0000, 0x7fff,
    memory::sram);
                       }

                       /* old */
                       void bMemBus::cart_map_generic(uint type) {
                       uint rom_size = cartridge.info.rom_size;
                       uint ram_size = cartridge.info.ram_size;

                       for(uint page = 0x0000; page <= 0xffff; page++)
    {
                       if(memory_type(page << 8) !=
    TYPE_CART)continue;

                       uint addr = page << 8;
                       uint bank = page >> 8;

                       //RAM mapping is incorrect in several games,
    this is the most compatible
                       //layout I can create using only ROM header
    information. Additional accuracy
                       //requires PCB identification.

                       //Unmapped region
                       //$[00-1f|80-9f]:[6000-7fff]
     if((bank & 0x7f) >= 0x00 && (bank & 0x7f) <= 0x1f && (addr &
    0xe000) == 0x6000) {
                       continue;
                       }

                       //HiROM RAM region
                       //$[20-3f|a0-bf]:[6000-7fff]
     if((bank & 0x7f) >= 0x20 && (bank & 0x7f) <= 0x3f && (addr &
    0xe000) == 0x6000) {
                       if(ram_size == 0)continue;

                       addr = ((bank & 0x7f) - 0x20) * 0x2000 + ((addr
    & 0xffff) - 0x6000);
                       addr %= ram_size;
                       page_handle[page] = cartridge.ram + addr;
                       page_read [page] = &bMemBus::read_ram;
                       page_write [page] = &bMemBus::write_ram;
                       continue;
                       }

                       //LoROM RAM region
                       //$[70-7f|f0-ff]:[0000-7fff]
                       //Note: WRAM is remapped over
    $[7e-7f]:[0000-ffff]
     if((bank & 0x7f) >= 0x70 && (bank & 0x7f) <= 0x7f && (addr &
    0x8000) == 0x0000) {
                       if(!(bank & 0x80) || type == Cartridge::LOROM)
    {
                       //HiROM maps $[f0-ff]:[0000-7fff] to ROM
                       if(ram_size == 0)continue;

                       addr = ((bank & 0x7f) - 0x70) * 0x8000 + (addr
    & 0x7fff);
                       addr %= ram_size;
                       page_handle[page] = cartridge.ram + addr;
                       page_read [page] = &bMemBus::read_ram;
                       page_write [page] = &bMemBus::write_ram;
                       continue;
                       }
                       }

                       //ROM region
                       switch(type) {

                       case Cartridge::LOROM: {
                       addr = (bank & 0x7f) * 0x8000 + (addr &
    0x7fff);
                       addr = mirror(rom_size, addr);
                       } break;

                       case Cartridge::HIROM: {
                       addr = mirror(rom_size, addr);
                       } break;

                       }

                       page_handle[page] = cartridge.rom + addr;
                       page_read [page] = &bMemBus::read_rom;
                       page_write [page] = &bMemBus::write_rom;
                       }
                       }




 Note that those two certainly aren't identical in function, and I'll
no doubt have some memory mapping bugs again (probably with Final
Fight, SFII and such), but it should only require minor changes to fix
that.







> byuu: is it possible there's supposed to be steam appearing there to
> create the illusion, but isn't?




               That's a lot more likely, honestly. Hopefully someone
can make it to level 5, heh. I know I sure as hell can't.

[No archive available]
2007-10-18 09:40:00 +00:00
byuu
42d3f2a37f Update to bsnes v025r03? release.
New WIP up, and this one is _not_ for playing games on.

 I replaced the memory mapper entirely with a new system that should
be infinitely easier to remap dynamically. This is a necessary step
for BS-X MMIO register emulation. It should also speed up S-DD1
emulation by eliminating the need for a special address conversion
routine to simulate its memory mapper.

 However, the new bus memory mapper is anything but complete. Right
now, it only loads really, really basic LoROM games. Stick to Super
Mario World and Zelda 3.

 Some good news is that it's ~1-2% faster with MinGW4, but the bad
news is that it's ~10% slower with Visual C++, and MS' compiler is
stupidly storing my 128kb array directly into the EXE, making the file
size bigger. And yet the ZIP of the whole thing is smaller! >_<

 Bah. I think I can fine tune most of the performance lost back out of
Visual C++ with some forced inlining, and I'll make that WRAM array
allocate at runtime.

 Surprised I was able to get any games playable in less than three
hours, replacing the entire memory mapping system like that. Lucky me.







> -O8 -mtune=prescott -ffloat-store -fforce-addr -finline-functions
> -fexpensive-optimizations -funroll-all-loops -ffast-math -fomit-
> frame-pointer




 I didn't realize you could go above -O3 ... interesting. If you want,
try building with profile guided optimizations for another ~15% speed
boost. It's pretty unstable like that, though. Maybe you'll have
better luck than me.

               The warning message is in src/cart/cart_file.cpp at the
top.

[No archive available]
2007-10-17 04:51:00 +00:00
byuu
c58e3af1b5 Update to bsnes v025r02? release.
Alright, posted a new WIP with the BS-X skeleton. The
BIOS needs to be named bsxbios.bin, and it can't have a header.

 There's also "Load Special -> Load BS-X Cartridge ...", but it
doesn't work yet. It maps the flash cart into $[c0-ff]:[0000-ffff],
but that doesn't do much good. The BIOS then detects the flash cart
and starts probing the memory mapping registers and eventually
deadlocks.

               To emulate the MMIO registers, I will have to
_completely_ rework my memory mapping code to support dynamic
remapping. Not necessarily a bad thing, I was planning to rewrite all
of that anyway (per my diagram yesterday). Might as well kill two
birds with one stone.

 Gonna take at least a few days of planning before I go at that. I
want to get it right this time, so I don't have to do this again.

               In the meantime, have fun walking around the dead St.
GIGA ghost town ;)







> Byuu, that's some sweet ass shiz. You are a man on a mission this
> week. Let me know when you feel you've supported it enough to remove
> it from the list.




 Yeah, not sure what's up. I rarely have motivation to do anything
anymore, but it always comes in bursts. So I'll take advantage of it
now, and hope it doesn't burn out soon.

 I've a long way to go with BS-X before we can remove it, sadly. I
think we can remove when I get >50-75% of games loading. I doubt we
can reach 100%. There's missing info, corrupted / hacked BS ROMs
galore, and I don't even have BS-X hardware to test with.







> byuu, you always show something cool in a new version RIGHT after
> your official releases




 Sorry about that, it's not intentional. The thing is that no BS-X
games are even playable yet. I suppose when it's stable, I'll post
another public version, assuming the core is still stable with all the
plans I have for it.







> I really enjoy following your development of bsnes. I can't wait for
> the day I have a computer that is actually fast enough to play games
> with it (I'm currently using an Athlon 1.1 GHz).




               Sorry about that :(

               ---

 Side note: I also posted v0.025a, which removes the warning message
when SRM files don't exist. Nothing else is different, though.

[No archive available]
2007-10-16 05:50:00 +00:00
byuu
8226e243b8 Update to bsnes v025a release.
My apologies, I added code to display an alert when the Sufami Turbo BIOS was not present at the last minute before the recent release. What I failed to realize was that I added the alert to the same routine that loads save RAM files. Meaning that whenever one loads a game that has not yet created a .srm file, one will get a warning that the save RAM file does not exist. Oops.
You'll never see the warning more than once, and it's harmless, but for those it annoys, and for people who haven't upgraded yet, I've posted bsnes v0.025a. This version changes absolutely nothing other than disabling the warning box in question. I'll be sure to get a proper, tested fix into the next release. Again, I apologize for any inconveniece this may have caused.

[No archive available]
2007-10-16 00:00:00 +00:00
byuu
9ab3fa6227 Update to bsnes v025r01? release.
I'll bet this will surprise you all, I already have a
private WIP for the v0.025 series up :P
 Absolutely no emulation changes, just lots of major code changes I
held off on as I didn't want to break anything last minute.

 - Polymorphism through pointers using compile-time flag is dead. It
took a ~10% speed hit, so it was never feasible to use anyway. This is
also a required step to encapsulating the entire emulator inside a
single class which can support multiple instances. r_cpu-> becomes
cpu. , r_smp-> becomes smp. , etc.
 - Greatly cleaned up interface.h as much as possible for now. Right
now, bsnes takes a lot longer than it should to compile because every
single object includes every last header for all objects. In the
future, I want to move headers so that only objects that need others
include those headers. Will increase compile speed a good bit.
               - Created chip/chip.h to start on the above.
               - Finally renamed chip/c4 to chip/cx4. Class name also
changed from C4 to Cx4.
               - Removed libsort, as it's not used (yet?). Was
needlessly slowing down compile time.
 - Created src/doc. This will be a folder that contains source code
documentation, diagrams, maps, to-do lists, etc. Started things off by
creating a _very_ basic overview of bsnes as a whole.

 Much more radical stuff to come. I don't anticipate making another
public release for quite a long time, so I should be able to go wild
here with restructuring things.







> I just checked out the new bsnes version 0.025, but I could not find
> any option in the config file to change the memory / mem via PRNG
> initialization byte, that we were talking about earlier to help get
> some old pd stuff working...




 Oh, I'm sorry about that. Didn't get a chance to add it this time. I
need to work a PRNG with a consistent seed value into the core first.
Not sure how I want to do that.

 For what it's worth, initializing RAM to 0x00 unfortunately did not
fix Sidmania's graphical issues as I had hoped. Given FitzRoy reports
the glitches occur on real hardware as well, I'm afraid there's not a
whole lot I can do about it. I will pay attention to it when working
on my cycle-based PPU in the future, though.







> On another note your emulator has inspired me to do my first
> translation for the snes "Albert Odyssey", and has been very useful
> for this purpose.




 Neat! Be sure to check out bsnes v0.013 on RHDN for its debugger.
It's the only SNES emulator with VRAM breakpoints, as far as I know.
Also be sure to try out xkas for your cross assembler :D </shameless
self-promotion>







> Oct. 14 also happens to be the 10th anniversary of the first public
> release of ZSNES, interestingly enough.




               o.O
 Holy crap, why didn't I ever hear about this before? That's really,
really interesting ... of course, the difference is that bsnes was
started on 10-14, ZSNES was first released then but obviously started
much sooner. Still cool, though.

 I wonder if anyone knows the exact date zsKnight started on ZSNES, or
Jeremy Koot on SNES9x. It would be really cool to have a history of
the SNES emulation scene. So many emulators most have never even heard
of ... RSRSNES, GrimSNES, TrepSNES, Moonlit Coalition's emulator (that
played one game, heh), Simkin's simulator thing ... heh, I wonder if
anyone here knows the name of the SNES emulator I tried (and failed)
making way before bsnes, back in 2001. Google doesn't even know of it
:)

[No archive available]
2007-10-15 05:21:00 +00:00
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
442 changed files with 25050 additions and 12783 deletions

View File

@@ -1,35 +1,86 @@
bsnes License: bsnes (TM) Reference License
-------------- Copyright (C) 2004 - 2007 byuu
You are free to redistribute this software, and its source code; provided All rights reserved
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.
Simple DirectMedia Layer License: 1. Definitions
---------------------------------
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.
The Simple DirectMedia Layer library source code is available from: The terms "reproduce", "reproduction", "distribute" and "distribution" have the
http://www.libsdl.org/ same meaning here as under U.S. copyright law.
This library is distributed under the terms of the GNU LGPL: "The software" means this software package as a whole, including, but not
http://www.gnu.org/copyleft/lesser.html limited to, this license, binaries, source code, documentation, and data.
JMA License: "You" means the licensee of the software.
------------
JMA is licensed under the GNU GPL. I have received special exemption from
Nach to use this library in bsnes.
Licensing Exemptions: "The licensor" means the copyright holder of the software, byuu.
---------------------
libco, the cooperative multithreading library used by bsnes, is public domain.
You may obtain the latest version at: http://byuu.org/
Richard Bannister has asked for and received my permission to distribute 2. Grant of Rights
a binary-only port of bsnes on the Mac OS X platform.
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 bsnes
Version 0.019 Version 0.027
Author: byuu Author: byuu
--------
General General:
------- --------
bsnes is a Super Nintendo / Super Famicom emulator that began on bsnes is a Super Nintendo / Super Famicom emulator that began on
October 14th, 2004. October 14th, 2004.
@@ -13,19 +13,22 @@ http://byuu.org/
Please see license.txt for important licensing information. Please see license.txt for important licensing information.
--------------
Shortcut Keys:
--------------
Esc - Toggle menubar visibility
F11 - Toggle fullscreen mode
Known Limitations ------------------
----------------- Known Limitations:
------------------
S-CPU 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 - Multiply / Divide register delays not implemented
S-SMP
- Cycle breakdown of opcodes is theoretical, but mostly correct
S-PPU S-PPU
- Uses scanline-based renderer. This is very inaccurate, but very - Uses scanline-based renderer. This is very inaccurate, but few (if any)
few games rely on mid-scanline writes to function correctly games rely on mid-scanline writes to function correctly
- Does not support FirstSprite+Y priority - Does not support FirstSprite+Y priority
- OAM / CGRAM accesses during active display not supported correctly - OAM / CGRAM accesses during active display not supported correctly
- RTO flags are not calculated on frames that are skipped when frameskipping - 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. in games that test these flags, eg the SNES Test Program Electronics Test.
Turning frameskipping off will allow RTO flag calculation on every frame 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 Hardware Bugs
- CPUr1 HDMA crashing bug not emulated - S-CPU.r1 HDMA crashing bug not emulated
- CPU<>APU communication bus conflicts not emulated - S-CPU<>S-SMP communication bus conflicts not emulated
---------------------
Unsupported Hardware Unsupported Hardware:
-------------------- ---------------------
SA-1 SA-1
Coprocessor used in many popular games, including: Coprocessor used in many popular games, including:
- Dragon Ball Z Hyper Dimension - Dragon Ball Z Hyper Dimension
@@ -68,31 +66,19 @@ Coprocessor used only by the following games:
- Momotarou Densetsu Happy - Momotarou Densetsu Happy
- Super Power League 4 - Super Power League 4
DSP-3 ST-011
Coprocessor used only by SD Gundam GX SETA DSP used only by Quick-move Shogi Match with Nidan Rank-holder Morita
DSP-4 ST-018
Coprocessor used only by Top Gear 3000 SETA RISC CPU used only by Quick-move Shogi Match with Nidan Rank-holder Morita 2
ST010 / ST011 / ST018
SETA coprocessors used by very few games
BS-X (Broadcast 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
Super Gameboy Super Gameboy
Cartridge passthrough used for playing Gameboy games Cartridge passthrough used for playing Gameboy games
------------------------
Unsupported controllers Unsupported Controllers:
----------------------- ------------------------
Mouse Mouse
Super Scope Super Scope
Justifier Justifier
Multitap (4-port) Multitap (4-port and 5-port)
Multitap (5-port)

333
src/Makefile Normal file
View File

@@ -0,0 +1,333 @@
######################
### bsnes makefile ###
######################
ifeq ($(PLATFORM),)
null_: help
endif
##################################
### platform-specific settings ###
##################################
PREFIX = /usr/local
ifeq ($(PLATFORM),x-gcc-x86)
OS = unix
CC = gcc
CFLAGS = -O3 -fomit-frame-pointer -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_MIU `pkg-config --cflags gtk+-2.0`
AS = yasm
ASFLAGS = -f elf
LIBS = `pkg-config --libs gtk+-2.0` -lXv -lao
LIBCO = libco.x86
MIU = miu.gtk
VAI = video.xv.$(OBJ) video.gtk.$(OBJ) audio.ao.$(OBJ) input.x.$(OBJ)
endif
ifeq ($(PLATFORM),x-gcc-x86-64)
OS = unix
CC = gcc
CFLAGS = -O3 -fomit-frame-pointer -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86_64 -DUI_MIU `pkg-config --cflags gtk+-2.0`
AS = yasm
ASFLAGS = -f elf64
LIBS = `pkg-config --libs gtk+-2.0` -lXv -lao
LIBCO = libco.x86-64
MIU = miu.gtk
VAI = video.xv.$(OBJ) video.gtk.$(OBJ) audio.ao.$(OBJ) input.x.$(OBJ)
endif
ifeq ($(PLATFORM),win-mingw-x86)
OS = win
CC = mingw32-gcc
CFLAGS = -mwindows -O3 -fomit-frame-pointer -DPLATFORM_WIN -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_MIU
AS = nasm
ASFLAGS = -f win32 -DWIN
LIBS = -ld3d9 -lddraw -ldsound -ldinput8 -ldxguid -luuid -lkernel32 -luser32 -lgdi32 -lshell32 -lwinmm -lcomdlg32 -lcomctl32
LIBCO = libco.x86
MIU = miu.win
VAI = video.direct3d.$(OBJ) video.directdraw.$(OBJ) video.gdi.$(OBJ) audio.directsound.$(OBJ) input.directinput.$(OBJ)
endif
ifeq ($(PLATFORM),win-visualc-x86)
OS = win
CC = cl
CFLAGS = /nologo /wd4996 /O2 /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_MIU
AS = nasm
ASFLAGS = -f win32 -DWIN
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
MIU = miu.win
VAI = video.direct3d.$(OBJ) video.directdraw.$(OBJ) video.gdi.$(OBJ) audio.directsound.$(OBJ) input.directinput.$(OBJ)
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),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) $(MIU).$(OBJ) $(VAI) bstring.$(OBJ) \
reader.$(OBJ) cart.$(OBJ) cheat.$(OBJ) memory.$(OBJ) smemory.$(OBJ) \
cpu.$(OBJ) scpu.$(OBJ) smp.$(OBJ) ssmp.$(OBJ) bdsp.$(OBJ) ppu.$(OBJ) \
bppu.$(OBJ) snes.$(OBJ) bsx.$(OBJ) superfx.$(OBJ) srtc.$(OBJ) \
sdd1.$(OBJ) cx4.$(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
ifeq ($(CC),mingw32-gcc)
OBJECTS += bsnesrc.o
endif
endif
all: $(OBJECTS)
$(CPP) $(OUT) $(CFLAGS) $(OBJECTS) $(LIBS) $(LINK)
######################
### implicit rules ###
######################
%.$(OBJ): $<
$(if $(filter %.asm,$<),$(AS) $(ASFLAGS) $(ASARGS))
$(if $(filter %.s,$<),$(AS) $(ASFLAGS) $(ASARGS))
$(if $(filter %.c,$<),$(CC) $(CFLAGS) $(CARGS))
$(if $(filter %.cpp,$<),$(CPP) $(CFLAGS) $(CARGS))
############
### main ###
############
main.$(OBJ): ui/main.cpp config/* \
ui/* ui/vai/* \
ui/miu/* ui/miu/loader/* ui/miu/settings/*
bsnes.res: ui/bsnes.rc ; rc /r /fobsnes.res ui/bsnes.rc
bsnesrc.o: ui/bsnes.rc ; windres -I data ui/bsnes.rc bsnesrc.o
##########
### ui ###
##########
video.direct3d.$(OBJ) : ui/vai/video/video.direct3d.cpp ui/vai/video/*
video.directdraw.$(OBJ) : ui/vai/video/video.directdraw.cpp ui/vai/video/*
video.gdi.$(OBJ) : ui/vai/video/video.gdi.cpp ui/vai/video/*
video.gtk.$(OBJ) : ui/vai/video/video.gtk.cpp ui/vai/video/*
video.xv.$(OBJ) : ui/vai/video/video.xv.cpp ui/vai/video/*
audio.ao.$(OBJ) : ui/vai/audio/audio.ao.cpp ui/vai/audio/*
audio.directsound.$(OBJ): ui/vai/audio/audio.directsound.cpp ui/vai/audio/*
input.directinput.$(OBJ): ui/vai/input/input.directinput.cpp ui/vai/input/*
input.x.$(OBJ) : ui/vai/input/input.x.cpp ui/vai/input/*
#############
### libco ###
#############
libco.x86.$(OBJ) : lib/libco/libco.x86.asm lib/libco/*
libco.x86-64.$(OBJ): lib/libco/libco.x86-64.asm lib/libco/*
libco.pcc.$(OBJ) : lib/libco/libco.ppc.s lib/libco/*
libco.ppc64.$(OBJ) : lib/libco/libco.ppc64.s lib/libco/*
###########
### miu ###
###########
miu.gtk.$(OBJ): lib/miu.gtk/miu.gtk.cpp lib/miu.gtk/*
miu.win.$(OBJ): lib/miu.win/miu.win.cpp lib/miu.win/*
#################
### libraries ###
#################
bstring.$(OBJ): lib/bstring.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/*
smemory.$(OBJ): memory/smemory/smemory.cpp memory/smemory/* memory/smemory/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 ###
#####################
bsx.$(OBJ) : chip/bsx/bsx.cpp chip/bsx/*
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/*
cx4.$(OBJ) : chip/cx4/cx4.cpp chip/cx4/*
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 ###
####################
install:
install -m 775 bsnes $(PREFIX)/bin/bsnes
install -m 775 data/bsnes.png $(PREFIX)/share/icons/bsnes.png
clean:
-@$(RM) *.$(OBJ)
-@$(RM) *.res
-@$(RM) *.pgd
-@$(RM) *.pgc
-@$(RM) *.ilk
-@$(RM) *.pdb
-@$(RM) *.manifest
help:
@echo "Usage: $(MAKE) PLATFORM=platform [options]"
@echo ""
@echo "Available platform targets:"
@echo " x-gcc-x86 - Linux / BSD (x86) (requires yasm)"
@echo " x-gcc-x86-64 - Linux / BSD (x86-64) (requires yasm)"
@echo " win-mingw-x86 - Windows (x86) (requires nasm)"
@echo " win-visualc-x86 - Windows (x86) (requires nasm)"
@echo ""
@echo "Available options:"
@echo " GZIP_SUPPORT=[true|false] - Enable ZIP / GZ support (default=false)"
@echo " JMA_SUPPORT=[true|false] - Enable JMA support (default=false)"
@echo ""
@echo "Example: $(MAKE) PLATFORM=x-gcc-lui GZIP_SUPPORT=true"
@echo ""

View File

@@ -1,60 +1,43 @@
#define BSNES_VERSION "0.019" #define BSNES_VERSION "0.027"
#define BSNES_TITLE "bsnes v" BSNES_VERSION #define BSNES_TITLE "bsnes v" BSNES_VERSION
#define MEMCORE bMemBus #define BUSCORE sBus
#define CPUCORE sCPU #define CPUCORE sCPU
#define SMPCORE sSMP #define SMPCORE sSMP
#define DSPCORE bDSP #define DSPCORE bDSP
#define PPUCORE bPPU #define PPUCORE bPPU
//FAVOR_ACCURACY calculates RTO during frameskip, whereas FAVOR_SPEED does not
//frameskip offers near-zero speedup if RTO is calculated
//accuracy is not affected by this define when frameskipping is off
//#define FAVOR_ACCURACY //#define FAVOR_ACCURACY
#define FAVOR_SPEED #define FAVOR_SPEED
//game genie + pro action replay code support (~1-3% speed hit) //game genie + pro action replay code support (~1-3% speed hit)
#define CHEAT_SYSTEM #define CHEAT_SYSTEM
//enable GZ, ZIP format support #if defined(PROCESSOR_X86) || defined(PROCESSOR_X86_64)
//#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
#if defined(PROCESSOR_X86)
#define ARCH_LSB #define ARCH_LSB
#elif defined(PROCESSOR_X86_64) #elif defined(PROCESSOR_PPC) || defined(PROCESSOR_PPC64)
#define ARCH_LSB
#elif defined(PROCESSOR_G5)
#define ARCH_MSB #define ARCH_MSB
#else #else //guess
#error "unsupported processor" #define ARCH_LSB
#endif #endif
#include "lib/libbase.h" #include "lib/libco.h"
#include "lib/libsort.h" #include "lib/bbase.h"
#include "lib/libco_x86.h" #include "lib/bfunction.h"
#include "lib/libarray.h" #include "lib/barray.h"
#include "lib/libvector.h" #include "lib/bvector.h"
#include "lib/libfile.h" #include "lib/bkeymap.h"
#include "lib/libups.h" #include "lib/bstring.h"
#include "lib/libstring.h" #include "lib/bconfig.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 //platform-specific global functions
void alert(char *, ...); void alert(const char*, ...);
void dprintf(char *, ...); void dprintf(const char*, ...);
void dprintf(uint, char *, ...); void dprintf(uint, const char*, ...);
namespace source { namespace source {
enum { enum {
@@ -68,5 +51,4 @@ namespace source {
}; };
}; };
//various class interfaces
#include "interface.h" #include "interface.h"

BIN
src/bsnes.lnk Normal file

Binary file not shown.

View File

@@ -1,156 +1,135 @@
#include "../base.h" #include "../base.h"
#include "database.cpp"
#include "cart_normal.cpp"
#include "cart_bsx.cpp"
#include "cart_bsc.cpp"
#include "cart_st.cpp"
#include "cart_file.cpp" #include "cart_file.cpp"
#include "cart_header.cpp" #include "cart_header.cpp"
namespace memory {
MappedRAM cartrom, cartram;
MappedRAM bscram;
MappedRAM stArom, stAram;
MappedRAM stBrom, stBram;
};
Cartridge cartridge; Cartridge cartridge;
#include "cart_normal.cpp" Cartridge::MemoryMapper Cartridge::mapper() { return info.mapper; }
#include "cart_st.cpp" Cartridge::Region Cartridge::region() { return info.region; }
#include "cart_stdual.cpp"
void Cartridge::load_begin(uint cart_type) { bool Cartridge::loaded() { return cart.loaded; }
if(loaded() == true)return;
void Cartridge::load_begin(CartridgeType cart_type) {
cart.rom = cart.ram = 0;
bs.ram = 0;
stA.rom = stA.ram = 0;
stB.rom = stB.ram = 0;
cart.rom_size = cart.ram_size = 0;
bs.ram_size = 0;
stA.rom_size = stA.ram_size = 0;
stB.rom_size = stB.ram_size = 0;
info.type = cart_type; info.type = cart_type;
info.bsxbase = false;
info.bsxcart = false;
info.bsxflash = false;
info.st = false;
info.superfx = false;
info.sa1 = false;
info.srtc = false; info.srtc = false;
info.sdd1 = false; info.sdd1 = false;
info.c4 = false; info.cx4 = false;
info.dsp1 = false; info.dsp1 = false;
info.dsp2 = false; info.dsp2 = false;
info.dsp3 = false;
info.dsp4 = false;
info.obc1 = false; info.obc1 = false;
info.st010 = false;
info.st011 = false;
info.st018 = false;
info.dsp1_mapper = 0; info.dsp1_mapper = DSP1Unmapped;
info.header_index = 0xffc0; info.header_index = 0xffc0;
info.mapper = PCB; info.mapper = LoROM;
strcpy(info.name, ""); info.name[0] = 0;
strcpy(info.pcb, "");
info.region = NTSC; info.region = NTSC;
info.cart_mmio = false;
info.rom_size = 0; info.rom_size = 0;
info.ram_size = 0; info.ram_size = 0;
file.count = 0;
for(int i = 0; i < 8; i++) {
strcpy(file.rom_name[i], "");
strcpy(file.ram_name[i], "");
file.rom_size[i] = 0;
file.ram_size[i] = 0;
file.rom_data[i] = 0;
file.ram_data[i] = 0;
}
} }
void Cartridge::load(const char *rom_fn) { void Cartridge::load_end() {
if(!rom_fn || !*rom_fn)return; memory::cartrom.map(cart.rom, cart.rom_size);
memory::cartram.map(cart.ram, cart.ram_size);
memory::bscram.map(bs.ram, bs.ram_size);
memory::stArom.map(stA.rom, stA.rom_size);
memory::stAram.map(stA.ram, stA.ram_size);
memory::stBrom.map(stB.rom, stB.rom_size);
memory::stBram.map(stB.ram, stB.ram_size);
char fn[4096], ram_fn[4096]; memory::cartrom.write_protect(true);
strcpy(fn, rom_fn); memory::cartram.write_protect(false);
//correct folder slashes memory::bscram.write_protect(true);
for(int i = strlen(fn) - 1; i >= 0; i--) { memory::stArom.write_protect(true);
if(fn[i] == '\\')fn[i] = '/'; memory::stAram.write_protect(false);
} memory::stBrom.write_protect(true);
memory::stBram.write_protect(false);
uint i = file.count++; char fn[PATH_MAX];
strcpy(file.rom_name[i], fn); strcpy(fn, cart.fn);
modify_extension(fn, "cht");
strcpy(fn, rom_fn); if(fexists(fn)) {
//remove ROM extension
for(int i = strlen(fn) - 1; i >= 0; i--) {
if(fn[i] == '.') {
fn[i] = 0;
break;
}
}
if(i == 0) {
strcpy(file.patch_name, fn);
strcat(file.patch_name, ".ups");
}
strcpy(fn, strptr(config::file_updatepath(fn, config::path.save)));
if(i == 0) {
strcpy(file.cheat_name, fn);
strcat(file.cheat_name, ".cht");
}
strcpy(file.ram_name[i], fn);
strcat(file.ram_name[i], ".");
strcat(file.ram_name[i], config::path.save_ext);
}
bool Cartridge::load_end() {
for(int i = 0; i < file.count; i++) {
load_file(file.rom_name[i], file.rom_data[i], file.rom_size[i]);
}
if(fexists(file.cheat_name) == true) {
cheat.clear(); cheat.clear();
cheat.load(file.cheat_name); cheat.load(fn);
} }
switch(info.type) { cart.loaded = true;
case CART_NORMAL: { bus.load_cart();
load_rom_normal();
load_ram_normal();
} break;
case CART_ST: {
load_rom_st();
load_ram_st();
} break;
case CART_STDUAL: {
load_rom_stdual();
load_ram_stdual();
} break;
}
cart_loaded = true;
r_mem->load_cart();
return true;
} }
bool Cartridge::unload() { bool Cartridge::unload() {
if(cart_loaded == false)return false; if(cart.loaded == false) return false;
r_mem->unload_cart(); bus.unload_cart();
switch(info.type) { switch(info.type) {
case CART_NORMAL: { case CartridgeNormal: unload_cart_normal(); break;
save_ram_normal(); case CartridgeBSX: unload_cart_bsx(); break;
} break; case CartridgeBSC: unload_cart_bsc(); break;
case CART_ST: { case CartridgeSufamiTurbo: unload_cart_st(); break;
save_ram_st();
} break;
case CART_STDUAL: {
save_ram_stdual();
} break;
} }
SafeFree(rom); safe_free(cart.rom);
SafeFree(ram); safe_free(cart.ram);
safe_free(bs.ram);
safe_free(stA.rom);
safe_free(stA.ram);
safe_free(stB.rom);
safe_free(stB.ram);
if(cheat.count() > 0 || fexists(file.cheat_name) == true) { char fn[PATH_MAX];
cheat.save(file.cheat_name); strcpy(fn, cart.fn);
modify_extension(fn, "cht");
if(cheat.count() > 0 || fexists(fn)) {
cheat.save(fn);
cheat.clear(); cheat.clear();
} }
cart_loaded = false; cart.loaded = false;
return true; return true;
} }
Cartridge::Cartridge() { Cartridge::Cartridge() {
load_database(); cart.loaded = false;
cart_loaded = false;
rom = 0;
ram = 0;
} }
Cartridge::~Cartridge() { Cartridge::~Cartridge() {
if(cart_loaded == true) { if(cart.loaded == true) unload();
unload();
}
} }

View File

@@ -1,125 +1,142 @@
class Cartridge { class Cartridge {
public: public:
enum CartridgeType {
CartridgeNormal,
CartridgeBSX,
CartridgeBSC,
CartridgeSufamiTurbo,
};
/***** enum HeaderField {
* cart database
*****/
#include "db/db.h"
db_item dbi;
uint8 *database;
uint database_size;
uint database_blocksize;
void load_database();
bool read_database();
//
enum {
CART_NORMAL,
CART_ST,
CART_STDUAL,
};
bool cart_loaded;
uint8 rom_header[512], *rom, *ram;
enum {
//header fields
CART_NAME = 0x00, CART_NAME = 0x00,
MAPPER = 0x15, MAPPER = 0x15,
ROM_TYPE = 0x16, ROM_TYPE = 0x16,
ROM_SIZE = 0x17, ROM_SIZE = 0x17,
RAM_SIZE = 0x18, RAM_SIZE = 0x18,
REGION = 0x19, REGION = 0x19,
LICENSE = 0x1a, COMPANY = 0x1a,
VERSION = 0x1b, VERSION = 0x1b,
ICKSUM = 0x1c, ICKSUM = 0x1c,
CKSUM = 0x1e, CKSUM = 0x1e,
RESL = 0x3c, RESL = 0x3c,
RESH = 0x3d, RESH = 0x3d,
};
//regions enum Region {
NTSC = 0, NTSC,
PAL = 1, PAL,
};
//memory mappers enum MemoryMapper {
PCB = 0x00, LoROM,
LOROM = 0x20, HiROM,
HIROM = 0x21, ExLoROM,
EXLOROM = 0x22, ExHiROM,
EXHIROM = 0x25, BSXROM,
BSCLoROM,
BSCHiROM,
STROM,
};
//special chip memory mappers enum DSP1MemoryMapper {
DSP1_LOROM_1MB = 1, DSP1Unmapped,
DSP1_LOROM_2MB = 2, DSP1LoROM1MB,
DSP1_HIROM = 3, DSP1LoROM2MB,
}; DSP1HiROM,
};
struct { struct {
uint count; bool loaded;
char cheat_name[4096], patch_name[4096]; char fn[PATH_MAX];
char rom_name[8][4096], ram_name[8][4096]; uint8 *rom, *ram;
uint rom_size[8], ram_size[8]; uint rom_size, ram_size;
uint8 *rom_data[8], *ram_data[8]; } cart;
} file;
struct { struct {
uint type; char fn[PATH_MAX];
uint8 *ram;
uint ram_size;
} bs;
struct {
char fn[PATH_MAX];
uint8 *rom, *ram;
uint rom_size, ram_size;
} stA, stB;
struct {
CartridgeType type;
//cart information
uint32 crc32; uint32 crc32;
char name[128]; char name[128];
char pcb[32];
uint region; Region region;
uint mapper; MemoryMapper mapper;
uint rom_size; uint rom_size;
uint ram_size; uint ram_size;
//set to true for games that need cart MMIO mapping (c4, dsp-n, ...), bool bsxbase;
//for games that map outside the standard MMIO range of $2000-$5fff bool bsxcart;
bool cart_mmio; bool bsxflash;
bool st;
bool superfx;
bool sa1;
bool srtc; bool srtc;
bool sdd1; bool sdd1;
bool c4; bool cx4;
bool dsp1; bool dsp1;
bool dsp2; bool dsp2;
bool dsp3;
bool dsp4;
bool obc1; bool obc1;
bool st010;
bool st011;
bool st018;
uint dsp1_mapper; DSP1MemoryMapper dsp1_mapper;
//HiROM / LoROM specific code
uint header_index; uint header_index;
} info; } info;
bool load_file(const char *fn, uint8 *&data, uint &size); MemoryMapper mapper();
bool save_file(const char *fn, uint8 *data, uint size); Region region();
void load_rom_normal(); void load_cart_normal(const char*);
void load_ram_normal(); void load_cart_bsx(const char*, const char*);
void save_ram_normal(); void load_cart_bsc(const char*, const char*);
void load_cart_st(const char*, const char*, const char*);
void load_rom_st(); void unload_cart_normal();
void load_ram_st(); void unload_cart_bsx();
void save_ram_st(); void unload_cart_bsc();
void unload_cart_st();
void load_rom_stdual(); bool loaded();
void load_ram_stdual(); void load_begin(CartridgeType);
void save_ram_stdual(); void load_end();
bool unload();
void find_header(); void find_header();
void read_header(); void read_header();
void read_extended_header();
bool loaded() { return cart_loaded; } bool load_file(const char *fn, uint8 *&data, uint &size);
void load_begin(uint cart_type); bool save_file(const char *fn, uint8 *data, uint size);
void load(const char *rom_fn); char* modify_extension(char *filename, const char *extension);
bool load_end(); char* get_save_filename(const char *source, const char *extension);
bool unload();
Cartridge(); Cartridge();
~Cartridge(); ~Cartridge();
private:
char savefn[PATH_MAX];
};
namespace memory {
extern MappedRAM cartrom, cartram;
extern MappedRAM bscram;
extern MappedRAM stArom, stAram;
extern MappedRAM stBrom, stBram;
}; };
extern Cartridge cartridge; extern Cartridge cartridge;

41
src/cart/cart_bsc.cpp Normal file
View File

@@ -0,0 +1,41 @@
void Cartridge::load_cart_bsc(const char *base, const char *slot) {
if(!base || !*base) return;
strcpy(cart.fn, base);
strcpy(bs.fn, slot ? slot : "");
load_begin(CartridgeBSC);
uint8 *data;
uint size;
load_file(cart.fn, data, size);
cart.rom = data, cart.rom_size = size;
if(*bs.fn) {
if(load_file(bs.fn, data, size) == true) {
info.bsxflash = true;
bs.ram = data, bs.ram_size = size;
}
}
find_header();
read_header();
info.mapper = cartridge.info.header_index == 0x7fc0 ? BSCLoROM : BSCHiROM;
info.region = NTSC;
if(info.ram_size > 0) {
cart.ram = (uint8*)malloc(cart.ram_size = info.ram_size);
memset(cart.ram, 0xff, cart.ram_size);
if(load_file(get_save_filename(cart.fn, "srm"), data, size) == true) {
memcpy(cart.ram, data, min(size, cart.ram_size));
safe_free(data);
}
}
load_end();
}
void Cartridge::unload_cart_bsc() {
if(cart.ram) save_file(get_save_filename(cart.fn, "srm"), cart.ram, cart.ram_size);
}

45
src/cart/cart_bsx.cpp Normal file
View File

@@ -0,0 +1,45 @@
void Cartridge::load_cart_bsx(const char *base, const char *slot) {
if(!base || !*base) return;
strcpy(cart.fn, base);
strcpy(bs.fn, slot ? slot : "");
load_begin(CartridgeBSX);
info.bsxbase = true;
info.bsxcart = true;
info.mapper = BSXROM;
info.region = NTSC;
uint8 *data;
uint size;
load_file(cart.fn, data, size);
cart.rom = data, cart.rom_size = size;
cart.ram = 0, cart.ram_size = 0;
memset(bsxcart.sram.handle (), 0x00, bsxcart.sram.size ());
memset(bsxcart.psram.handle(), 0x00, bsxcart.psram.size());
if(load_file(get_save_filename(cart.fn, "srm"), data, size) == true) {
memcpy(bsxcart.sram.handle (), data, min(bsxcart.sram.size (), size));
safe_free(data);
}
if(load_file(get_save_filename(cart.fn, "psr"), data, size) == true) {
memcpy(bsxcart.psram.handle(), data, min(bsxcart.psram.size(), size));
safe_free(data);
}
if(*bs.fn) {
if(load_file(bs.fn, data, size) == true) {
info.bsxflash = true;
bs.ram = data, bs.ram_size = size;
}
}
load_end();
}
void Cartridge::unload_cart_bsx() {
save_file(get_save_filename(cart.fn, "srm"), bsxcart.sram.handle (), bsxcart.sram.size ());
save_file(get_save_filename(cart.fn, "psr"), bsxcart.psram.handle(), bsxcart.psram.size());
}

View File

@@ -1,12 +1,59 @@
#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
char* Cartridge::modify_extension(char *filename, const char *extension) {
int i;
for(i = strlen(filename); i >= 0; i--) {
if(filename[i] == '.') break;
if(filename[i] == '/') break;
if(filename[i] == '\\') break;
}
if(i > 0 && filename[i] == '.') filename[i] = 0;
strcat(filename, ".");
strcat(filename, extension);
return filename;
}
char* Cartridge::get_save_filename(const char *source, const char *extension) {
strcpy(savefn, source);
for(char *p = savefn; *p; p++) { if(*p == '\\') *p = '/'; }
modify_extension(savefn, extension);
//override path with user-specified folder, if one was defined
if(config::path.save != "") {
lstring part;
split(part, "/", savefn);
string fn = config::path.save();
if(strend(fn, "/") == false) strcat(fn, "/");
strcat(fn, part[count(part) - 1]);
strcpy(savefn, fn);
//resolve relative path, if found
if(strbegin(fn, "./") == true) {
ltrim(fn, "./");
strcpy(savefn, config::path.base);
strcat(savefn, fn);
}
}
return savefn;
}
bool Cartridge::load_file(const char *fn, uint8 *&data, uint &size) { bool Cartridge::load_file(const char *fn, uint8 *&data, uint &size) {
dprintf("* Loading \"%s\"...", fn); dprintf("* Loading \"%s\"...", fn);
if(fexists(fn) == false) { if(fexists(fn) == false) return false;
return false;
}
switch(Reader::detect(fn)) { switch(Reader::detect(fn)) {
default:
case Reader::RF_NORMAL: { case Reader::RF_NORMAL: {
FileReader ff(fn); FileReader ff(fn);
if(!ff.ready()) { if(!ff.ready()) {
@@ -17,7 +64,7 @@ bool Cartridge::load_file(const char *fn, uint8 *&data, uint &size) {
data = ff.read(); data = ff.read();
} break; } break;
#ifdef GZIP_SUPPORT #ifdef GZIP_SUPPORT
case Reader::RF_GZ: { case Reader::RF_GZ: {
GZReader gf(fn); GZReader gf(fn);
if(!gf.ready()) { if(!gf.ready()) {
@@ -33,9 +80,9 @@ bool Cartridge::load_file(const char *fn, uint8 *&data, uint &size) {
size = zf.size(); size = zf.size();
data = zf.read(); data = zf.read();
} break; } break;
#endif #endif
#ifdef JMA_SUPPORT #ifdef JMA_SUPPORT
case Reader::RF_JMA: { case Reader::RF_JMA: {
try { try {
JMAReader jf(fn); JMAReader jf(fn);
@@ -46,8 +93,7 @@ bool Cartridge::load_file(const char *fn, uint8 *&data, uint &size) {
return false; return false;
} }
} break; } break;
#endif #endif
} }
return true; return true;

View File

@@ -1,32 +1,46 @@
void Cartridge::read_header() { void Cartridge::read_header() {
info.srtc = false; uint8 *rom = cart.rom;
info.sdd1 = false; uint index = info.header_index;
info.c4 = false; uint8 mapper = rom[index + MAPPER];
info.dsp1 = false; uint8 rom_type = rom[index + ROM_TYPE];
info.dsp2 = false; uint8 company = rom[index + COMPANY];
info.obc1 = false; uint8 region = rom[index + REGION] & 0x7f;
info.dsp1_mapper = 0; //detect presence of BS-X flash cartridge connector (reads extended header information)
bool has_bsxflash = false;
if(info.header_index == 0x7fc0 && info.rom_size >= 0x401000) { if(rom[index - 14] == 'Z') {
info.mapper = EXLOROM; if(rom[index - 11] == 'J') {
strcpy(info.pcb, "UNL-EXLOROM"); uint8 n13 = rom[index - 13];
} else if(info.header_index == 0x7fc0 && rom[info.header_index + MAPPER] == 0x32) { if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) {
info.mapper = EXLOROM; if(company == 0x33 || (rom[index - 10] == 0x00 && rom[index - 4] == 0x00)) {
strcpy(info.pcb, "UNL-EXLOROM"); has_bsxflash = true;
} else if(info.header_index == 0x7fc0) { }
info.mapper = LOROM; }
strcpy(info.pcb, "UNL-LOROM"); }
} else if(info.header_index == 0xffc0) { }
info.mapper = HIROM;
strcpy(info.pcb, "UNL-HIROM"); if(has_bsxflash == true) {
} else { //info.header_index == 0x40ffc0 info.mapper = index == 0x7fc0 ? BSCLoROM : BSCHiROM;
info.mapper = EXHIROM; } else if(index == 0x7fc0 && cart.rom_size >= 0x401000) {
strcpy(info.pcb, "UNL-EXHIROM"); info.mapper = ExLoROM;
} else if(index == 0x7fc0 && mapper == 0x32) {
info.mapper = ExLoROM;
} else if(index == 0x7fc0) {
info.mapper = LoROM;
} else if(index == 0xffc0) {
info.mapper = HiROM;
} else { //index == 0x40ffc0
info.mapper = ExHiROM;
}
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;
} }
uint8 mapper = rom[info.header_index + MAPPER];
uint8 rom_type = rom[info.header_index + ROM_TYPE];
if(mapper == 0x35 && rom_type == 0x55) { if(mapper == 0x35 && rom_type == 0x55) {
info.srtc = true; info.srtc = true;
} }
@@ -36,14 +50,14 @@ uint8 rom_type = rom[info.header_index + ROM_TYPE];
} }
if(mapper == 0x20 && rom_type == 0xf3) { if(mapper == 0x20 && rom_type == 0xf3) {
info.c4 = true; info.cx4 = true;
} }
if((mapper == 0x20 || mapper == 0x21) && rom_type == 0x03) { if((mapper == 0x20 || mapper == 0x21) && rom_type == 0x03) {
info.dsp1 = true; info.dsp1 = true;
} }
if(mapper == 0x30 && rom_type == 0x05) { if(mapper == 0x30 && rom_type == 0x05 && company != 0xb2) {
info.dsp1 = true; info.dsp1 = true;
} }
@@ -52,12 +66,12 @@ uint8 rom_type = rom[info.header_index + ROM_TYPE];
} }
if(info.dsp1 == true) { if(info.dsp1 == true) {
if((mapper & 0x2f) == 0x20 && info.rom_size <= 0x100000) { if((mapper & 0x2f) == 0x20 && cart.rom_size <= 0x100000) {
info.dsp1_mapper = DSP1_LOROM_1MB; info.dsp1_mapper = DSP1LoROM1MB;
} else if((mapper & 0x2f) == 0x20) { } else if((mapper & 0x2f) == 0x20) {
info.dsp1_mapper = DSP1_LOROM_2MB; info.dsp1_mapper = DSP1LoROM2MB;
} else if((mapper & 0x2f) == 0x21) { } else if((mapper & 0x2f) == 0x21) {
info.dsp1_mapper = DSP1_HIROM; info.dsp1_mapper = DSP1HiROM;
} }
} }
@@ -65,11 +79,28 @@ uint8 rom_type = rom[info.header_index + ROM_TYPE];
info.dsp2 = true; 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) { if(mapper == 0x30 && rom_type == 0x25) {
info.obc1 = true; 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) { if(rom[info.header_index + RAM_SIZE] & 7) {
info.ram_size = 1024 << (rom[info.header_index + RAM_SIZE] & 7); info.ram_size = 1024 << (rom[info.header_index + RAM_SIZE] & 7);
@@ -77,6 +108,9 @@ uint8 rom_type = rom[info.header_index + ROM_TYPE];
info.ram_size = 0; info.ram_size = 0;
} }
//0, 1, 13 = NTSC; 2 - 12 = PAL
info.region = (region <= 1 || region >= 13) ? NTSC : PAL;
memcpy(&info.name, &rom[info.header_index + CART_NAME], 21); memcpy(&info.name, &rom[info.header_index + CART_NAME], 21);
info.name[21] = 0; info.name[21] = 0;
@@ -91,8 +125,9 @@ void Cartridge::find_header() {
int32 score_lo = 0, int32 score_lo = 0,
score_hi = 0, score_hi = 0,
score_ex = 0; score_ex = 0;
uint8 *rom = cart.rom;
if(info.rom_size < 0x010000) { if(cart.rom_size < 0x010000) {
//cart too small to be anything but lorom //cart too small to be anything but lorom
info.header_index = 0x007fc0; info.header_index = 0x007fc0;
return; return;
@@ -113,8 +148,8 @@ int32 score_lo = 0,
if(rom[0x7fc0 + REGION] < 14)score_lo++; if(rom[0x7fc0 + REGION] < 14)score_lo++;
if(rom[0xffc0 + REGION] < 14)score_hi++; if(rom[0xffc0 + REGION] < 14)score_hi++;
if(rom[0x7fc0 + LICENSE] < 3)score_lo++; if(rom[0x7fc0 + COMPANY] < 3)score_lo++;
if(rom[0xffc0 + LICENSE] < 3)score_hi++; if(rom[0xffc0 + COMPANY] < 3)score_hi++;
if(rom[0x7fc0 + RESH] & 0x80)score_lo += 2; if(rom[0x7fc0 + RESH] & 0x80)score_lo += 2;
if(rom[0xffc0 + RESH] & 0x80)score_hi += 2; if(rom[0xffc0 + RESH] & 0x80)score_hi += 2;
@@ -132,7 +167,7 @@ uint16 cksum, icksum;
score_hi += 8; score_hi += 8;
} }
if(info.rom_size < 0x401000) { if(cart.rom_size < 0x401000) {
score_ex = 0; score_ex = 0;
} else { } else {
if(rom[0x7fc0 + MAPPER] == 0x32)score_lo++; if(rom[0x7fc0 + MAPPER] == 0x32)score_lo++;

View File

@@ -1,66 +1,41 @@
void Cartridge::load_rom_normal() { void Cartridge::load_cart_normal(const char *filename) {
uint size = 0; if(!filename || !*filename) return;
for(int i = 0; i < file.count; i++) {
size += file.rom_size[i] - (((file.rom_size[i] & 0x7fff) == 512) ? 512 : 0);
}
info.rom_size = size; uint8 *data;
rom = (uint8*)malloc(info.rom_size); uint size;
memset(rom, 0, info.rom_size); if(load_file(filename, data, size) == false) return;
strcpy(cart.fn, filename);
uint offset = 0; load_begin(CartridgeNormal);
for(int i = 0; i < file.count; i++) {
uint8 *data = file.rom_data[i] + (((file.rom_size[i] & 0x7fff) == 512) ? 512 : 0);
uint size = file.rom_size[i] - (((file.rom_size[i] & 0x7fff) == 512) ? 512 : 0);
memcpy(rom + offset, data, size);
offset += size;
safe_free(file.rom_data[i]);
}
info.crc32 = crc32_calculate(rom, info.rom_size); //load ROM data, ignore 512-byte header if detected
if((size & 0x7fff) != 512) {
if(read_database() == true) { cart.rom = (uint8*)malloc(cart.rom_size = size);
info.srtc = false; memcpy(cart.rom, data, size);
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;
} else { } else {
cart.rom = (uint8*)malloc(cart.rom_size = size - 512);
memcpy(cart.rom, data + 512, size - 512);
}
safe_free(data);
info.crc32 = crc32_calculate(cart.rom, cart.rom_size);
find_header(); find_header();
read_header(); read_header();
}
}
void Cartridge::load_ram_normal() { if(info.ram_size > 0) {
if(info.ram_size == 0) { cart.ram = (uint8*)malloc(cart.ram_size = info.ram_size);
ram = 0; memset(cart.ram, 0xff, cart.ram_size);
return;
if(load_file(get_save_filename(cart.fn, "srm"), data, size) == true) {
memcpy(cart.ram, data, min(size, cart.ram_size));
safe_free(data);
}
} }
ram = (uint8*)malloc(info.ram_size); load_end();
memset(ram, 0xff, info.ram_size);
if(load_file(file.ram_name[0], file.ram_data[0], file.ram_size[0]) == true) {
memcpy(ram, file.ram_data[0], min(info.ram_size, file.ram_size[0]));
safe_free(file.ram_data[0]);
}
} }
void Cartridge::save_ram_normal() { void Cartridge::unload_cart_normal() {
if(info.ram_size == 0)return; if(cart.ram) save_file(get_save_filename(cart.fn, "srm"), cart.ram, cart.ram_size);
save_file(file.ram_name[0], ram, info.ram_size);
} }

View File

@@ -1,45 +1,59 @@
void Cartridge::load_rom_st() { void Cartridge::load_cart_st(const char *base, const char *slotA, const char *slotB) {
uint8 *data; if(!base || !*base) return;
uint size;
string bios = config::file_updatepath("stbios.bin", config::path.bios);
info.rom_size = 0x200000;
rom = (uint8*)malloc(info.rom_size);
memset(rom, 0, info.rom_size);
load_file(strptr(bios), data, size); strcpy(cart.fn, base);
memcpy(rom, data, min(size, 0x040000)); strcpy(stA.fn, slotA ? slotA : "");
safe_free(data); strcpy(stB.fn, slotB ? slotB : "");
memcpy(rom + 0x100000, file.rom_data[0], min(file.rom_size[0], 0x100000)); load_begin(CartridgeSufamiTurbo);
safe_free(file.rom_data[0]); info.st = true;
info.mapper = STROM;
//
strcpy(info.name, "???");
strcpy(info.pcb, "STC-SOLO");
info.mapper = PCB;
info.region = NTSC; info.region = NTSC;
info.rom_size = 0x200000; uint8 *data;
info.ram_size = 0x020000; uint size;
// if(load_file(cart.fn, data, size) == true) {
cart.rom = (uint8*)malloc(cart.rom_size = 0x040000);
info.crc32 = crc32_calculate(rom + 0x100000, file.rom_size[0]); memcpy(cart.rom, data, min(size, cart.rom_size));
if(read_database() == true) { safe_free(data);
strcpy(info.name, dbi.name);
} }
}
void Cartridge::load_ram_st() { if(*stA.fn) {
ram = (uint8*)malloc(info.ram_size); if(load_file(stA.fn, data, size) == true) {
memset(ram, 0xff, info.ram_size); stA.rom = (uint8*)malloc(stA.rom_size = 0x100000);
memcpy(stA.rom, data, min(size, stA.rom_size));
safe_free(data);
if(load_file(file.ram_name[0], file.ram_data[0], file.ram_size[0]) == true) { stA.ram = (uint8*)malloc(stA.ram_size = 0x020000);
memcpy(ram, file.ram_data[0], min(file.ram_size[0], 0x020000)); memset(stA.ram, 0xff, stA.ram_size);
safe_free(file.ram_data[0]);
if(load_file(get_save_filename(stA.fn, "srm"), data, size) == true) {
memcpy(stA.ram, data, min(size, 0x020000));
safe_free(data);
} }
}
}
if(*stB.fn) {
if(load_file(stB.fn, data, size) == true) {
stB.rom = (uint8*)malloc(stB.rom_size = 0x100000);
memcpy(stB.rom, data, min(size, stB.rom_size));
safe_free(data);
stB.ram = (uint8*)malloc(stB.ram_size = 0x020000);
memset(stB.ram, 0xff, stB.ram_size);
if(load_file(get_save_filename(stB.fn, "srm"), data, size) == true) {
memcpy(stB.ram, data, min(size, 0x020000));
safe_free(data);
}
}
}
load_end();
} }
void Cartridge::save_ram_st() { void Cartridge::unload_cart_st() {
save_file(file.ram_name[0], ram, 0x020000); if(stA.ram) save_file(get_save_filename(stA.fn, "srm"), stA.ram, stA.ram_size);
if(stB.ram) save_file(get_save_filename(stB.fn, "srm"), stB.ram, stB.ram_size);
} }

View File

@@ -1,66 +0,0 @@
void Cartridge::load_rom_stdual() {
uint8 *data;
uint size;
string bios = config::file_updatepath("stbios.bin", config::path.bios);
info.rom_size = 0x300000;
rom = (uint8*)malloc(info.rom_size);
memset(rom, 0, info.rom_size);
load_file(strptr(bios), data, size);
memcpy(rom, data, min(size, 0x040000));
safe_free(data);
memcpy(rom + 0x100000, file.rom_data[0], min(file.rom_size[0], 0x100000));
safe_free(file.rom_data[0]);
memcpy(rom + 0x200000, file.rom_data[1], min(file.rom_size[1], 0x100000));
safe_free(file.rom_data[1]);
char name_a[4096], name_b[4096];
strcpy(name_a, "???");
strcpy(name_b, "???");
//
info.mapper = PCB;
info.region = NTSC;
info.rom_size = 0x300000;
info.ram_size = 0x040000;
//
info.crc32 = crc32_calculate(rom + 0x100000, file.rom_size[0]);
if(read_database() == true) {
strcpy(name_a, dbi.name);
}
info.crc32 = crc32_calculate(rom + 0x200000, file.rom_size[1]);
if(read_database() == true) {
strcpy(name_b, dbi.name);
}
//
info.crc32 = 0;
strcpy(info.name, name_a);
strcat(info.name, " + ");
strcat(info.name, name_b);
strcpy(info.pcb, "STC-DUAL");
}
void Cartridge::load_ram_stdual() {
ram = (uint8*)malloc(info.ram_size);
memset(ram, 0xff, info.ram_size);
if(load_file(file.ram_name[0], file.ram_data[0], file.ram_size[0]) == true) {
memcpy(ram + 0x000000, file.ram_data[0], min(file.ram_size[0], 0x020000));
safe_free(file.ram_data[0]);
}
if(load_file(file.ram_name[1], file.ram_data[1], file.ram_size[1]) == true) {
memcpy(ram + 0x020000, file.ram_data[1], min(file.ram_size[1], 0x020000));
safe_free(file.ram_data[1]);
}
}
void Cartridge::save_ram_stdual() {
save_file(file.ram_name[0], ram + 0x000000, 0x020000);
save_file(file.ram_name[1], ram + 0x020000, 0x020000);
}

View File

@@ -1,37 +0,0 @@
void Cartridge::load_database() {
database = 0;
database_size = 0;
FILE *fp;
fp = fopen("cart.db", "rb");
if(!fp)return;
uint size = fsize(fp);
if(size < 8) {
fclose(fp);
return;
}
database = (uint8*)malloc(size);
fread(database, 1, size, fp);
fclose(fp);
database_blocksize = (database[6] << 0) | (database[7] << 8);
database_size = (size - 8) / database_blocksize;
}
bool Cartridge::read_database() {
uint i, crc32;
for(i = 0; i < database_size; i++) {
uint8 *p = database + 8 + (i * database_blocksize);
crc32 = *(p++) << 0;
crc32 |= *(p++) << 8;
crc32 |= *(p++) << 16;
crc32 |= *(p++) << 24;
if(crc32 == cartridge.info.crc32)break;
}
if(i >= database_size)return false;
db_read(dbi, database + 8 + (i * database_blocksize));
return true;
}

Binary file not shown.

View File

@@ -1,113 +0,0 @@
[0xbb5c4238]
name = "Bishoujo Senshi Sailor Moon Sailor Stars - Fuwa Fuwa Panic 2 (Japan)"
pcb = "STC-????"
rom = 8mbit
ram = 32kbit
[0x8eb753f3]
name = "Crayon Shin-chan - Nagagutsu Dobon!! (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0x7aedd703]
name = "Der Langrisser (Japan) [!]"
pcb = "SHVC-1A3M-30"
rom = 16mbit
ram = 64kbit
[0x19bdcb19]
name = "Derby Stallion '96 (Japan) [!]"
pcb = "BSC-1A5M-01"
rom = 24mbit
ram = 256kbit
[0x4296500d]
name = "Gegege no Kitarou - Youkai Donjara (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 16kbit
[0x14c66fca]
name = "Gekisou Sentai Car Rangers (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0x32b2b3dd]
name = "Poi Poi Ninja World (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0x9684526d]
name = "Romancing SaGa (Japan) (V1.1) [!]"
pcb = "SHVC-1A3B-12"
rom = 8mbit
ram = 64kbit
[0xafd74dcb]
name = "SD Gundam Generation A - Ichinen Sensouki (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0x48ecae44]
name = "SD Gundam Generation B - Grips Senki (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0x72b4235f]
name = "SD Gundam Generation C - Axis Senki (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0x792d884c]
name = "SD Gundam Generation D - Babylonia Kenkoku Senki (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0xefd3a865]
name = "SD Gundam Generation E - Zanskar Senki (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0xc5dfa8fd]
name = "SD Gundam Generation F - Colony Kakutouki (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0x43ad5a45]
name = "SD Ultra Battle - Seven Densetsu (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0x04939d14]
name = "SD Ultra Battle - Ultra Densetsu (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0xa5c0045e]
name = "Secret of Evermore (USA) [!]"
pcb = "SHVC-1J3M-20"
rom = 32mbit
ram = 64kbit
[0x5ebf7246]
name = "Sound Novel Tsukuru (Japan) [!]"
pcb = "BSC-1A7M-10"
rom = 24mbit
ram = 512kbit
[0x64a91e64]
name = "Wanderers from Ys (USA) [!]"
pcb = "SHVC-1A3B-12"
rom = 8mbit
ram = 64kbit

View File

@@ -1,3 +0,0 @@
cl /nologo /O2 dbcreate.cpp
@pause
@del *.obj

View File

@@ -1 +0,0 @@
@del *.exe

View File

@@ -1,2 +0,0 @@
dbcreate
@copy cart.db ..\..\..\cart.db

View File

@@ -1,47 +0,0 @@
struct db_item {
uint32 crc32;
char name[128];
char pcb [32];
uint32 rom;
uint32 ram;
};
void db_write(FILE *fp, db_item &dbi) {
fputc(dbi.crc32 >> 0, fp);
fputc(dbi.crc32 >> 8, fp);
fputc(dbi.crc32 >> 16, fp);
fputc(dbi.crc32 >> 24, fp);
fwrite(dbi.name, 1, 128, fp);
fwrite(dbi.pcb, 1, 32, fp);
fputc(dbi.rom >> 0, fp);
fputc(dbi.rom >> 8, fp);
fputc(dbi.rom >> 16, fp);
fputc(dbi.rom >> 24, fp);
fputc(dbi.ram >> 0, fp);
fputc(dbi.ram >> 8, fp);
fputc(dbi.ram >> 16, fp);
fputc(dbi.ram >> 24, fp);
}
void db_read(db_item &dbi, uint8 *data) {
dbi.crc32 = (*data++) << 0;
dbi.crc32 |= (*data++) << 8;
dbi.crc32 |= (*data++) << 16;
dbi.crc32 |= (*data++) << 24;
memcpy(dbi.name, data, 128); dbi.name[127] = 0; data += 128;
memcpy(dbi.pcb, data, 32); dbi.pcb [ 31] = 0; data += 32;
dbi.rom = (*data++) << 0;
dbi.rom |= (*data++) << 8;
dbi.rom |= (*data++) << 16;
dbi.rom |= (*data++) << 24;
dbi.ram = (*data++) << 0;
dbi.ram |= (*data++) << 8;
dbi.ram |= (*data++) << 16;
dbi.ram |= (*data++) << 24;
}

View File

@@ -1,117 +0,0 @@
#include "../../lib/libbase.h"
#include "../../lib/libvector.h"
#include "../../lib/libstring.h"
#include "../../lib/libstring.cpp"
#include "db.h"
FILE *fp;
uint decode_size(string &str) {
//hex encoding
if(strbegin(str, "0x")) {
strltrim(str, "0x");
return strhex(str);
}
//mbit encoding
if(strend(str, "mbit")) {
strrtrim(str, "mbit");
return strdec(str) * 1024 * 1024 / 8;
}
//kbit encoding
if(strend(str, "kbit")) {
strrtrim(str, "kbit");
return strdec(str) * 1024 / 8;
}
//decimal encoding
return strdec(str);
}
void build_block(string &block) {
stringarray line, hashpart, part;
split(line, "\n", block);
if(strbegin(line[0], "[") == false) {
printf("error: invalid block detected: '%s'\n", strptr(line[0]));
return;
}
strltrim(line[0], "[");
strrtrim(line[0], "]");
replace(line[0], "0x", "");
split(hashpart, ",", line[0]);
db_item dbi;
dbi.crc32 = 0;
*dbi.name = 0;
*dbi.pcb = 0;
dbi.rom = 0;
dbi.ram = 0;
for(int i = 1; i < count(line); i++) {
uint pos;
if(strpos(line[i], ";", pos) == true) {
strset(line[i], pos, 0);
}
if(line[i] == "")continue;
split(part, "=", line[i]);
strunquote(part[1]);
if(part[0] == "name") {
strncpy(dbi.name, strptr(part[1]), 128);
dbi.name[128] = 0;
}
if(part[0] == "pcb") {
strncpy(dbi.pcb, strptr(part[1]), 32);
dbi.pcb[31] = 0;
}
if(part[0] == "rom") {
dbi.rom = decode_size(part[1]);
}
if(part[0] == "ram") {
dbi.ram = decode_size(part[1]);
}
}
for(int i = 0; i < count(hashpart); i++) {
dbi.crc32 = strhex(hashpart[i]);
db_write(fp, dbi);
}
}
void build_database() {
stringarray data, block;
if(strfread(data, "cartdb.txt") == false)return;
fp = fopen("cart.db", "wb");
fprintf(fp, "SNESDB");
uint blocksize = 4 + 128 + 32 + 4 + 4;
fputc(blocksize >> 0, fp);
fputc(blocksize >> 8, fp);
replace (data, "\r", "");
qreplace(data, " ", "");
qreplace(data, "\t", "");
split(block, "\n\n", data);
for(int i = 0; i < count(block); i++) {
build_block(block[i]);
}
fclose(fp);
}
int main() {
build_database();
return 0;
}

6
src/cc.bat Normal file
View File

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

1
src/cc.sh Normal file
View File

@@ -0,0 +1 @@
make PLATFORM=x-gcc-x86

View File

@@ -1,4 +1,5 @@
#include "../base.h" #include "../base.h"
#include "../reader/filereader.h"
Cheat cheat; Cheat cheat;
@@ -9,17 +10,17 @@ Cheat cheat;
*****/ *****/
bool Cheat::decode(char *str, uint32 &addr, uint8 &data, uint8 &type) { bool Cheat::decode(char *str, uint32 &addr, uint8 &data, uint8 &type) {
stringarray t, part; string t, part;
strcpy(t, str); strcpy(t, str);
strlower(t); strlower(t());
if(strlen(t) == 8 || (strlen(t) == 9 && strptr(t)[6] == ':')) { if(strlen(t) == 8 || (strlen(t) == 9 && t()[6] == ':')) {
type = CT_PRO_ACTION_REPLAY; type = CT_PRO_ACTION_REPLAY;
replace(t, ":", ""); replace(t, ":", "");
uint32 r = strhex(t); uint32 r = strhex(t);
addr = r >> 8; addr = r >> 8;
data = r & 0xff; data = r & 0xff;
return true; return true;
} else if(strlen(t) == 9 && strptr(t)[4] == '-') { } else if(strlen(t) == 9 && t()[4] == '-') {
type = CT_GAME_GENIE; type = CT_GAME_GENIE;
replace(t, "-", ""); replace(t, "-", "");
strtr(t, "df4709156bc8a23e", "0123456789abcdef"); strtr(t, "df4709156bc8a23e", "0123456789abcdef");
@@ -268,51 +269,40 @@ void Cheat::disable(uint32 n) {
* cheat file manipulation routines * cheat file manipulation routines
*****/ *****/
/* file format: */
/* nnnn-nnnn = status, "description" \r\n */
/* ... */
bool Cheat::load(const char *fn) { bool Cheat::load(const char *fn) {
FileReader rf(fn); string data;
if(!rf.ready())return false; if(!fread(data, fn)) return false;
uint8 *raw_data = rf.read();
stringarray data, line;
raw_data[rf.size()] = 0;
strcpy(data, (char*)raw_data);
SafeFree(raw_data);
replace(data, "\r\n", "\n"); replace(data, "\r\n", "\n");
qreplace(data, "=", ",");
qreplace(data, " ", "");
lstring line;
split(line, "\n", data); split(line, "\n", data);
for(int i = 0; i < ::count(line); i++) { for(int i = 0; i < ::count(line); i++) {
stringarray part; lstring part;
uint8 en = *(strptr(line[i])); split(part, ",", line[i]);
if(en == '+') { if(::count(part) != 3) continue;
strltrim(line[i], "+"); trim(part[2], "\"");
} else if(en == '-') { add(part[1] == "enabled", part[0](), part[2]());
strltrim(line[i], "-");
} else {
continue;
}
qreplace(line[i], " ", "");
qsplit(part, ",", line[i]);
if(::count(part) != 2)continue;
strunquote(part[1]);
add(en == '+', strptr(part[0]), strptr(part[1]));
} }
return true; return true;
} }
bool Cheat::save(const char *fn) { bool Cheat::save(const char *fn) {
FileWriter wf(fn); FILE *fp = fopen(fn, "wb");
if(!wf.ready())return false; if(!fp) return false;
string data;
char t[4096];
strcpy(data, "");
for(int i = 0; i < cheat_count; i++) { for(int i = 0; i < cheat_count; i++) {
sprintf(t, "%c%s, \"%s\"\r\n", index[i].enabled ? '+' : '-', index[i].code, index[i].desc); fprintf(fp, "%9s = %8s, \"%s\"\r\n",
strcat(data, t); index[i].code,
index[i].enabled ? "enabled" : "disabled",
index[i].desc);
} }
fclose(fp);
wf.write((uint8*)strptr(data), strlen(data));
return true; return true;
} }
@@ -324,7 +314,7 @@ void Cheat::clear() {
cheat_enabled = false; cheat_enabled = false;
cheat_count = 0; cheat_count = 0;
memset(mask, 0, 0x200000); memset(mask, 0, 0x200000);
for(int i = 0; i < CHEAT_LIMIT + 1; i++) { for(int i = 0; i <= CHEAT_LIMIT; i++) {
index[i].enabled = false; index[i].enabled = false;
index[i].addr = 0x000000; index[i].addr = 0x000000;
index[i].data = 0x00; index[i].data = 0x00;

5
src/chip/bsx/bsx.cpp Normal file
View File

@@ -0,0 +1,5 @@
#include "../../base.h"
#include "bsx_base.cpp"
#include "bsx_cart.cpp"
#include "bsx_flash.cpp"

77
src/chip/bsx/bsx.h Normal file
View File

@@ -0,0 +1,77 @@
class BSXBase : public MMIO {
public:
void init();
void enable();
void power();
void reset();
uint8 mmio_read(uint addr);
void mmio_write(uint addr, uint8 data);
private:
struct {
uint8 r2188, r2189, r218a, r218b;
uint8 r218c, r218d, r218e, r218f;
uint8 r2190, r2191, r2192, r2193;
uint8 r2194, r2195, r2196, r2197;
uint8 r2198, r2199, r219a, r219b;
uint8 r219c, r219d, r219e, r219f;
uint8 r2192_counter;
uint8 r2192_hour, r2192_minute, r2192_second;
} regs;
};
class BSXCart : public MMIO {
public:
void init();
void enable();
void power();
void reset();
uint8 mmio_read(uint addr);
void mmio_write(uint addr, uint8 data);
MappedRAM sram;
MappedRAM psram;
BSXCart();
~BSXCart();
private:
uint8 *sram_data; //256kbit SRAM
uint8 *psram_data; // 4mbit PSRAM
struct {
uint8 r[16];
} regs;
void update_memory_map();
};
class BSXFlash : public Memory {
public:
void init();
void enable();
void power();
void reset();
uint size();
uint8 read(uint addr);
void write(uint addr, uint8 data);
private:
struct {
uint command;
uint8 write_old;
uint8 write_new;
bool flash_enable;
bool read_enable;
bool write_enable;
} regs;
};
extern BSXBase bsxbase;
extern BSXCart bsxcart;
extern BSXFlash bsxflash;

133
src/chip/bsx/bsx_base.cpp Normal file
View File

@@ -0,0 +1,133 @@
void BSXBase::init() {
}
void BSXBase::enable() {
for(uint16 i = 0x2188; i <= 0x219f; i++) memory::mmio.map(i, *this);
}
void BSXBase::power() {
reset();
}
void BSXBase::reset() {
memset(&regs, 0x00, sizeof regs);
}
uint8 BSXBase::mmio_read(uint addr) {
addr &= 0xffff;
switch(addr) {
case 0x2188: return regs.r2188;
case 0x2189: return regs.r2189;
case 0x218a: return regs.r218a;
case 0x218c: return regs.r218c;
case 0x218e: return regs.r218e;
case 0x218f: return regs.r218f;
case 0x2190: return regs.r2190;
case 0x2192: {
uint counter = regs.r2192_counter++;
if(regs.r2192_counter >= 18) regs.r2192_counter = 0;
if(counter == 0) {
time_t rawtime;
time(&rawtime);
tm *t = localtime(&rawtime);
regs.r2192_hour = t->tm_hour;
regs.r2192_minute = t->tm_min;
regs.r2192_second = t->tm_sec;
}
switch(counter) {
case 0: return 0x00; //???
case 1: return 0x00; //???
case 2: return 0x00; //???
case 3: return 0x00; //???
case 4: return 0x00; //???
case 5: return 0x01;
case 6: return 0x01;
case 7: return 0x00;
case 8: return 0x00;
case 9: return 0x00;
case 10: return regs.r2192_second;
case 11: return regs.r2192_minute;
case 12: return regs.r2192_hour;
case 13: return 0x00; //???
case 14: return 0x00; //???
case 15: return 0x00; //???
case 16: return 0x00; //???
case 17: return 0x00; //???
}
} break;
case 0x2193: return regs.r2193 & ~0x0c;
case 0x2194: return regs.r2194;
case 0x2196: return regs.r2196;
case 0x2197: return regs.r2197;
case 0x2199: return regs.r2199;
}
return cpu.regs.mdr;
}
void BSXBase::mmio_write(uint addr, uint8 data) {
addr &= 0xffff;
switch(addr) {
case 0x2188: {
regs.r2188 = data;
} break;
case 0x2189: {
regs.r2189 = data;
} break;
case 0x218a: {
regs.r218a = data;
} break;
case 0x218b: {
regs.r218b = data;
} break;
case 0x218c: {
regs.r218c = data;
} break;
case 0x218e: {
regs.r218e = data;
} break;
case 0x218f: {
regs.r218e >>= 1;
regs.r218e = regs.r218f - regs.r218e;
regs.r218f >>= 1;
} break;
case 0x2191: {
regs.r2191 = data;
regs.r2192_counter = 0;
} break;
case 0x2192: {
regs.r2190 = 0x80;
} break;
case 0x2193: {
regs.r2193 = data;
} break;
case 0x2194: {
regs.r2194 = data;
} break;
case 0x2197: {
regs.r2197 = data;
} break;
case 0x2199: {
regs.r2199 = data;
} break;
}
}

95
src/chip/bsx/bsx_cart.cpp Normal file
View File

@@ -0,0 +1,95 @@
void BSXCart::init() {
}
void BSXCart::enable() {
for(uint16 i = 0x5000; i <= 0x5fff; i++) memory::mmio.map(i, *this);
}
void BSXCart::power() {
reset();
}
void BSXCart::reset() {
for(uint i = 0; i < 16; i++) regs.r[i] = 0x00;
regs.r[0x07] = 0x80;
regs.r[0x08] = 0x80;
update_memory_map();
}
void BSXCart::update_memory_map() {
Memory &cart = (regs.r[0x01] & 0x80) == 0x00 ? (Memory&)bsxflash : (Memory&)psram;
if((regs.r[0x02] & 0x80) == 0x00) { //LoROM mapping
bus.map(Bus::MapLinear, 0x00, 0x7d, 0x8000, 0xffff, cart);
bus.map(Bus::MapLinear, 0x80, 0xff, 0x8000, 0xffff, cart);
} else { //HiROM mapping
bus.map(Bus::MapShadow, 0x00, 0x3f, 0x8000, 0xffff, cart);
bus.map(Bus::MapLinear, 0x40, 0x7d, 0x0000, 0xffff, cart);
bus.map(Bus::MapShadow, 0x80, 0xbf, 0x8000, 0xffff, cart);
bus.map(Bus::MapLinear, 0xc0, 0xff, 0x0000, 0xffff, cart);
}
if(regs.r[0x03] & 0x80) {
bus.map(Bus::MapLinear, 0x60, 0x6f, 0x0000, 0xffff, psram);
//bus.map(Bus::MapLinear, 0x70, 0x77, 0x0000, 0xffff, psram);
}
if((regs.r[0x05] & 0x80) == 0x00) {
bus.map(Bus::MapLinear, 0x40, 0x4f, 0x0000, 0xffff, psram);
}
if((regs.r[0x06] & 0x80) == 0x00) {
bus.map(Bus::MapLinear, 0x50, 0x5f, 0x0000, 0xffff, psram);
}
if(regs.r[0x07] & 0x80) {
bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom);
}
if(regs.r[0x08] & 0x80) {
bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom);
}
bus.map(Bus::MapShadow, 0x20, 0x3f, 0x6000, 0x7fff, psram);
bus.map(Bus::MapLinear, 0x70, 0x77, 0x0000, 0xffff, psram);
}
uint8 BSXCart::mmio_read(uint addr) {
if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO
uint8 n = (addr >> 16) & 15;
return regs.r[n];
}
if((addr & 0xf8f000) == 0x105000) { //$[10-17]:[5000-5fff] SRAM
return sram.read(((addr >> 16) & 7) * 0x1000 + (addr & 0xfff));
}
return 0x00;
}
void BSXCart::mmio_write(uint addr, uint8 data) {
if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO
uint8 n = (addr >> 16) & 15;
regs.r[n] = data;
if(n == 0x0e && data & 0x80) update_memory_map();
return;
}
if((addr & 0xf8f000) == 0x105000) { //$[10-17]:[5000-5fff] SRAM
return sram.write(((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data);
}
}
BSXCart::BSXCart() {
sram_data = (uint8*)malloc( 32 * 1024);
psram_data = (uint8*)malloc(512 * 1024);
sram.map (sram_data, 32 * 1024);
psram.map(psram_data, 512 * 1024);
}
BSXCart::~BSXCart() {
safe_free(sram_data);
safe_free(psram_data);
}

109
src/chip/bsx/bsx_flash.cpp Normal file
View File

@@ -0,0 +1,109 @@
void BSXFlash::init() {}
void BSXFlash::enable() {}
void BSXFlash::power() {
reset();
}
void BSXFlash::reset() {
regs.command = 0;
regs.write_old = 0x00;
regs.write_new = 0x00;
regs.flash_enable = false;
regs.read_enable = false;
regs.write_enable = false;
}
uint BSXFlash::size() {
return memory::bscram.size();
}
uint8 BSXFlash::read(uint addr) {
if(addr == 0x0002) {
if(regs.flash_enable) return 0x80;
}
if(addr == 0x5555) {
if(regs.flash_enable) return 0x80;
}
if(regs.read_enable && addr >= 0xff00 && addr <= 0xff13) {
//read flash cartridge vendor information
switch(addr - 0xff00) {
case 0x00: return 0x4d;
case 0x01: return 0x00;
case 0x02: return 0x50;
case 0x03: return 0x00;
case 0x04: return 0x00;
case 0x05: return 0x00;
case 0x06: return 0x2a; //0x2a = 8mbit, 0x2b = 16mbit (not known to exist, though BIOS recognizes ID)
case 0x07: return 0x00;
default: return 0x00;
}
}
return memory::bscram.read(addr);
}
void BSXFlash::write(uint addr, uint8 data) {
//there exist both read-only and read-write BS-X flash cartridges ...
//unfortunately, the vendor info is not stored inside memory dumps
//of BS-X flashcarts, so it is impossible to determine whether a
//given flashcart is writeable.
//however, it has been observed that LoROM-mapped BS-X carts always
//use read-write flashcarts, and HiROM-mapped BS-X carts always use
//read-only flashcarts.
//below is an unfortunately necessary workaround to this problem.
if(cartridge.mapper() == Cartridge::BSCHiROM) return;
if((addr & 0xff0000) == 0) {
regs.write_old = regs.write_new;
regs.write_new = data;
if(regs.write_enable && regs.write_old == regs.write_new) {
return memory::bscram.write(addr, data);
}
} else {
if(regs.write_enable) {
return memory::bscram.write(addr, data);
}
}
if(addr == 0x0000) {
regs.command <<= 8;
regs.command |= data;
if((regs.command & 0xffff) == 0x38d0) {
regs.flash_enable = true;
regs.read_enable = true;
}
}
if(addr == 0x2aaa) {
regs.command <<= 8;
regs.command |= data;
}
if(addr == 0x5555) {
regs.command <<= 8;
regs.command |= data;
if((regs.command & 0xffffff) == 0xaa5570) {
regs.write_enable = false;
}
if((regs.command & 0xffffff) == 0xaa55a0) {
regs.write_old = 0x00;
regs.write_new = 0x00;
regs.flash_enable = true;
regs.write_enable = true;
}
if((regs.command & 0xffffff) == 0xaa55f0) {
regs.flash_enable = false;
regs.read_enable = false;
regs.write_enable = false;
}
}
}

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

@@ -0,0 +1,11 @@
#include "bsx/bsx.h"
#include "superfx/superfx.h"
#include "srtc/srtc.h"
#include "sdd1/sdd1.h"
#include "cx4/cx4.h"
#include "dsp1/dsp1.h"
#include "dsp2/dsp2.h"
#include "dsp3/dsp3.h"
#include "dsp4/dsp4.h"
#include "obc1/obc1.h"
#include "st010/st010.h"

View File

@@ -7,29 +7,27 @@
#include "../../base.h" #include "../../base.h"
C4 *c4; #include "cx4data.cpp"
#include "cx4fn.cpp"
#include "cx4oam.cpp"
#include "cx4ops.cpp"
#include "c4data.cpp" void Cx4::init() {}
#include "c4fn.cpp" void Cx4::enable() {}
#include "c4oam.cpp"
#include "c4ops.cpp"
void C4::init() {} uint32 Cx4::ldr(uint8 r) {
void C4::enable() {}
uint32 C4::ldr(uint8 r) {
uint16 addr = 0x0080 + (r * 3); uint16 addr = 0x0080 + (r * 3);
return (reg[addr]) | (reg[addr + 1] << 8) | (reg[addr + 2] << 16); return (reg[addr]) | (reg[addr + 1] << 8) | (reg[addr + 2] << 16);
} }
void C4::str(uint8 r, uint32 data) { void Cx4::str(uint8 r, uint32 data) {
uint16 addr = 0x0080 + (r * 3); uint16 addr = 0x0080 + (r * 3);
reg[addr ] = (data); reg[addr ] = (data);
reg[addr + 1] = (data >> 8); reg[addr + 1] = (data >> 8);
reg[addr + 2] = (data >> 16); reg[addr + 2] = (data >> 16);
} }
void C4::mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh) { void Cx4::mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh) {
int64 rx = x & 0xffffff; int64 rx = x & 0xffffff;
int64 ry = y & 0xffffff; int64 ry = y & 0xffffff;
if(rx & 0x800000)rx |= ~0x7fffff; if(rx & 0x800000)rx |= ~0x7fffff;
@@ -41,7 +39,7 @@ int64 ry = y & 0xffffff;
rh = (rx >> 24) & 0xffffff; rh = (rx >> 24) & 0xffffff;
} }
uint32 C4::sin(uint32 rx) { uint32 Cx4::sin(uint32 rx) {
r0 = rx & 0x1ff; r0 = rx & 0x1ff;
if(r0 & 0x100)r0 ^= 0x1ff; if(r0 & 0x100)r0 ^= 0x1ff;
if(r0 & 0x080)r0 ^= 0x0ff; if(r0 & 0x080)r0 ^= 0x0ff;
@@ -52,13 +50,13 @@ uint32 C4::sin(uint32 rx) {
} }
} }
uint32 C4::cos(uint32 rx) { uint32 Cx4::cos(uint32 rx) {
return sin(rx + 0x080); return sin(rx + 0x080);
} }
void C4::immediate_reg(uint32 start) { void Cx4::immediate_reg(uint32 start) {
r0 = ldr(0); r0 = ldr(0);
for(uint32 i=start;i<48;i++) { for(uint32 i = start; i < 48; i++) {
if((r0 & 0x0fff) < 0x0c00) { if((r0 & 0x0fff) < 0x0c00) {
ram[r0 & 0x0fff] = immediate_data[i]; ram[r0 & 0x0fff] = immediate_data[i];
} }
@@ -67,7 +65,7 @@ void C4::immediate_reg(uint32 start) {
str(0, r0); str(0, r0);
} }
void C4::transfer_data() { void Cx4::transfer_data() {
uint32 src; uint32 src;
uint16 dest, count; uint16 dest, count;
src = (reg[0x40]) | (reg[0x41] << 8) | (reg[0x42] << 16); src = (reg[0x40]) | (reg[0x41] << 8) | (reg[0x42] << 16);
@@ -75,11 +73,11 @@ uint16 dest, count;
dest = (reg[0x45]) | (reg[0x46] << 8); dest = (reg[0x45]) | (reg[0x46] << 8);
for(uint32 i=0;i<count;i++) { for(uint32 i=0;i<count;i++) {
write(dest++, r_mem->read(src++)); write(dest++, bus.read(src++));
} }
} }
void C4::write(uint16 addr, uint8 data) { void Cx4::write(uint addr, uint8 data) {
addr &= 0x1fff; addr &= 0x1fff;
if(addr < 0x0c00) { if(addr < 0x0c00) {
@@ -111,57 +109,57 @@ void C4::write(uint16 addr, uint8 data) {
} }
switch(data) { switch(data) {
case 0x00:op00();break; case 0x00: op00(); break;
case 0x01:op01();break; case 0x01: op01(); break;
case 0x05:op05();break; case 0x05: op05(); break;
case 0x0d:op0d();break; case 0x0d: op0d(); break;
case 0x10:op10();break; case 0x10: op10(); break;
case 0x13:op13();break; case 0x13: op13(); break;
case 0x15:op15();break; case 0x15: op15(); break;
case 0x1f:op1f();break; case 0x1f: op1f(); break;
case 0x22:op22();break; case 0x22: op22(); break;
case 0x25:op25();break; case 0x25: op25(); break;
case 0x2d:op2d();break; case 0x2d: op2d(); break;
case 0x40:op40();break; case 0x40: op40(); break;
case 0x54:op54();break; case 0x54: op54(); break;
case 0x5c:op5c();break; case 0x5c: op5c(); break;
case 0x5e:op5e();break; case 0x5e: op5e(); break;
case 0x60:op60();break; case 0x60: op60(); break;
case 0x62:op62();break; case 0x62: op62(); break;
case 0x64:op64();break; case 0x64: op64(); break;
case 0x66:op66();break; case 0x66: op66(); break;
case 0x68:op68();break; case 0x68: op68(); break;
case 0x6a:op6a();break; case 0x6a: op6a(); break;
case 0x6c:op6c();break; case 0x6c: op6c(); break;
case 0x6e:op6e();break; case 0x6e: op6e(); break;
case 0x70:op70();break; case 0x70: op70(); break;
case 0x72:op72();break; case 0x72: op72(); break;
case 0x74:op74();break; case 0x74: op74(); break;
case 0x76:op76();break; case 0x76: op76(); break;
case 0x78:op78();break; case 0x78: op78(); break;
case 0x7a:op7a();break; case 0x7a: op7a(); break;
case 0x7c:op7c();break; case 0x7c: op7c(); break;
case 0x89:op89();break; case 0x89: op89(); break;
} }
} }
} }
void C4::writeb(uint16 addr, uint8 data) { void Cx4::writeb(uint16 addr, uint8 data) {
write(addr, data); write(addr, data);
} }
void C4::writew(uint16 addr, uint16 data) { void Cx4::writew(uint16 addr, uint16 data) {
write(addr, data); write(addr, data);
write(addr + 1, data >> 8); write(addr + 1, data >> 8);
} }
void C4::writel(uint16 addr, uint32 data) { void Cx4::writel(uint16 addr, uint32 data) {
write(addr, data); write(addr, data);
write(addr + 1, data >> 8); write(addr + 1, data >> 8);
write(addr + 2, data >> 16); write(addr + 2, data >> 16);
} }
uint8 C4::read(uint16 addr) { uint8 Cx4::read(uint addr) {
addr &= 0x1fff; addr &= 0x1fff;
if(addr < 0x0c00) { if(addr < 0x0c00) {
@@ -172,28 +170,26 @@ uint8 C4::read(uint16 addr) {
return reg[addr & 0xff]; return reg[addr & 0xff];
} }
return r_cpu->regs.mdr; return cpu.regs.mdr;
} }
uint8 C4::readb(uint16 addr) { uint8 Cx4::readb(uint16 addr) {
return read(addr); return read(addr);
} }
uint16 C4::readw(uint16 addr) { uint16 Cx4::readw(uint16 addr) {
return read(addr) | (read(addr + 1) << 8); return read(addr) | (read(addr + 1) << 8);
} }
uint32 C4::readl(uint16 addr) { uint32 Cx4::readl(uint16 addr) {
return read(addr) | (read(addr + 1) << 8) + (read(addr + 2) << 16); return read(addr) | (read(addr + 1) << 8) + (read(addr + 2) << 16);
} }
void C4::power() { void Cx4::power() {
reset(); reset();
} }
void C4::reset() { void Cx4::reset() {
memset(ram, 0, 0x0c00); memset(ram, 0, 0x0c00);
memset(reg, 0, 0x0100); memset(reg, 0, 0x0100);
} }
C4::C4() {}

View File

@@ -1,29 +1,29 @@
class C4 { class Cx4 : public Memory {
private: private:
uint8 ram[0x0c00]; uint8 ram[0x0c00];
uint8 reg[0x0100]; uint8 reg[0x0100];
uint32 r0, r1, r2, r3, r4, r5, r6, r7, uint32 r0, r1, r2, r3, r4, r5, r6, r7,
r8, r9, r10, r11, r12, r13, r14, r15; r8, r9, r10, r11, r12, r13, r14, r15;
static const uint8 immediate_data[48]; static const uint8 immediate_data[48];
static const uint16 wave_data[40]; static const uint16 wave_data[40];
static const uint32 sin_table[256]; static const uint32 sin_table[256];
static const int16 SinTable[512]; static const int16 SinTable[512];
static const int16 CosTable[512]; static const int16 CosTable[512];
int16 C4WFXVal, C4WFYVal, C4WFZVal, C4WFX2Val, C4WFY2Val, C4WFDist, C4WFScale; int16 C4WFXVal, C4WFYVal, C4WFZVal, C4WFX2Val, C4WFY2Val, C4WFDist, C4WFScale;
int16 C41FXVal, C41FYVal, C41FAngleRes, C41FDist, C41FDistVal; int16 C41FXVal, C41FYVal, C41FAngleRes, C41FDist, C41FDistVal;
double tanval; double tanval;
double c4x,c4y,c4z, c4x2,c4y2,c4z2; double c4x,c4y,c4z, c4x2,c4y2,c4z2;
void C4TransfWireFrame(); void C4TransfWireFrame();
void C4TransfWireFrame2(); void C4TransfWireFrame2();
void C4CalcWireFrame(); void C4CalcWireFrame();
void C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color); void C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color);
void C4DrawWireFrame(); void C4DrawWireFrame();
void C4DoScaleRotate(int row_padding); void C4DoScaleRotate(int row_padding);
public: public:
uint32 ldr(uint8 r); uint32 ldr(uint8 r);
@@ -75,22 +75,23 @@ public:
void op7c(); void op7c();
void op89(); void op89();
uint8 readb(uint16 addr);
uint16 readw(uint16 addr);
uint32 readl(uint16 addr);
void writeb(uint16 addr, uint8 data);
void writew(uint16 addr, uint16 data);
void writel(uint16 addr, uint32 data);
//
void init(); void init();
void enable(); void enable();
void power(); void power();
void reset(); void reset();
void write (uint16 addr, uint8 data); uint8 read (uint addr);
void writeb(uint16 addr, uint8 data); void write(uint addr, uint8 data);
void writew(uint16 addr, uint16 data);
void writel(uint16 addr, uint32 data);
uint8 read (uint16 addr);
uint8 readb(uint16 addr);
uint16 readw(uint16 addr);
uint32 readl(uint16 addr);
C4();
}; };
extern C4 *c4; extern Cx4 cx4;

View File

@@ -1,11 +1,11 @@
const uint8 C4::immediate_data[48] = { const uint8 Cx4::immediate_data[48] = {
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f,
0x00, 0x80, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff, 0x00, 0x80, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff,
0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00 0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00
}; };
const uint16 C4::wave_data[40] = { const uint16 Cx4::wave_data[40] = {
0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e, 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020a, 0x020c, 0x020e, 0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020a, 0x020c, 0x020e,
0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e, 0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e,
@@ -13,7 +13,7 @@ const uint16 C4::wave_data[40] = {
0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080a, 0x080c, 0x080e 0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080a, 0x080c, 0x080e
}; };
const uint32 C4::sin_table[256] = { const uint32 Cx4::sin_table[256] = {
0x000000, 0x000324, 0x000648, 0x00096c, 0x000c8f, 0x000fb2, 0x0012d5, 0x0015f6, 0x000000, 0x000324, 0x000648, 0x00096c, 0x000c8f, 0x000fb2, 0x0012d5, 0x0015f6,
0x001917, 0x001c37, 0x001f56, 0x002273, 0x002590, 0x0028aa, 0x002bc4, 0x002edb, 0x001917, 0x001c37, 0x001f56, 0x002273, 0x002590, 0x0028aa, 0x002bc4, 0x002edb,
0x0031f1, 0x003505, 0x003817, 0x003b26, 0x003e33, 0x00413e, 0x004447, 0x00474d, 0x0031f1, 0x003505, 0x003817, 0x003b26, 0x003e33, 0x00413e, 0x004447, 0x00474d,
@@ -48,7 +48,7 @@ const uint32 C4::sin_table[256] = {
0xff013b, 0xff00f1, 0xff00b1, 0xff007b, 0xff004e, 0xff002c, 0xff0013, 0xff0004 0xff013b, 0xff00f1, 0xff00b1, 0xff007b, 0xff004e, 0xff002c, 0xff0013, 0xff0004
}; };
const int16 C4::SinTable[512] = { const int16 Cx4::SinTable[512] = {
0, 402, 804, 1206, 1607, 2009, 2410, 2811, 0, 402, 804, 1206, 1607, 2009, 2410, 2811,
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997, 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126, 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
@@ -115,7 +115,7 @@ const int16 C4::SinTable[512] = {
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402 -3211, -2811, -2410, -2009, -1607, -1206, -804, -402
}; };
const int16 C4::CosTable[512] = { const int16 Cx4::CosTable[512] = {
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647, 32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214, 32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471, 32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,

View File

@@ -7,7 +7,7 @@
#define PI 3.1415926535897932384626433832795 #define PI 3.1415926535897932384626433832795
//Wireframe Helpers //Wireframe Helpers
void C4::C4TransfWireFrame() { void Cx4::C4TransfWireFrame() {
c4x = (double)C4WFXVal; c4x = (double)C4WFXVal;
c4y = (double)C4WFYVal; c4y = (double)C4WFYVal;
c4z = (double)C4WFZVal - 0x95; c4z = (double)C4WFZVal - 0x95;
@@ -32,7 +32,7 @@ void C4::C4TransfWireFrame() {
C4WFYVal = (int16)(c4y * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95); C4WFYVal = (int16)(c4y * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
} }
void C4::C4CalcWireFrame() { void Cx4::C4CalcWireFrame() {
C4WFXVal = C4WFX2Val - C4WFXVal; C4WFXVal = C4WFX2Val - C4WFXVal;
C4WFYVal = C4WFY2Val - C4WFYVal; C4WFYVal = C4WFY2Val - C4WFYVal;
@@ -49,7 +49,7 @@ void C4::C4CalcWireFrame() {
} }
} }
void C4::C4TransfWireFrame2() { void Cx4::C4TransfWireFrame2() {
c4x = (double)C4WFXVal; c4x = (double)C4WFXVal;
c4y = (double)C4WFYVal; c4y = (double)C4WFYVal;
c4z = (double)C4WFZVal; c4z = (double)C4WFZVal;
@@ -74,34 +74,34 @@ void C4::C4TransfWireFrame2() {
C4WFYVal = (int16)(c4y * C4WFScale / 0x100); C4WFYVal = (int16)(c4y * C4WFScale / 0x100);
} }
void C4::C4DrawWireFrame() { void Cx4::C4DrawWireFrame() {
uint32 line = readl(0x1f80); uint32 line = readl(0x1f80);
uint32 point1, point2; uint32 point1, point2;
int16 X1, Y1, Z1; int16 X1, Y1, Z1;
int16 X2, Y2, Z2; int16 X2, Y2, Z2;
uint8 Color; uint8 Color;
for(int32 i = ram[0x0295]; i > 0; i--, line += 5) { for(int32 i = ram[0x0295]; i > 0; i--, line += 5) {
if(r_mem->read(line) == 0xff && r_mem->read(line + 1) == 0xff) { if(bus.read(line) == 0xff && bus.read(line + 1) == 0xff) {
int32 tmp = line - 5; int32 tmp = line - 5;
while(r_mem->read(tmp + 2) == 0xff && r_mem->read(tmp + 3) == 0xff && (tmp + 2) >= 0) { tmp -= 5; } while(bus.read(tmp + 2) == 0xff && bus.read(tmp + 3) == 0xff && (tmp + 2) >= 0) { tmp -= 5; }
point1 = (read(0x1f82) << 16) | (r_mem->read(tmp + 2) << 8) | r_mem->read(tmp + 3); point1 = (read(0x1f82) << 16) | (bus.read(tmp + 2) << 8) | bus.read(tmp + 3);
} else { } else {
point1 = (read(0x1f82) << 16) | (r_mem->read(line) << 8) | r_mem->read(line + 1); point1 = (read(0x1f82) << 16) | (bus.read(line) << 8) | bus.read(line + 1);
} }
point2 = (read(0x1f82) << 16) | (r_mem->read(line + 2) << 8) | r_mem->read(line + 3); point2 = (read(0x1f82) << 16) | (bus.read(line + 2) << 8) | bus.read(line + 3);
X1=(r_mem->read(point1 + 0) << 8) | r_mem->read(point1 + 1); X1=(bus.read(point1 + 0) << 8) | bus.read(point1 + 1);
Y1=(r_mem->read(point1 + 2) << 8) | r_mem->read(point1 + 3); Y1=(bus.read(point1 + 2) << 8) | bus.read(point1 + 3);
Z1=(r_mem->read(point1 + 4) << 8) | r_mem->read(point1 + 5); Z1=(bus.read(point1 + 4) << 8) | bus.read(point1 + 5);
X2=(r_mem->read(point2 + 0) << 8) | r_mem->read(point2 + 1); X2=(bus.read(point2 + 0) << 8) | bus.read(point2 + 1);
Y2=(r_mem->read(point2 + 2) << 8) | r_mem->read(point2 + 3); Y2=(bus.read(point2 + 2) << 8) | bus.read(point2 + 3);
Z2=(r_mem->read(point2 + 4) << 8) | r_mem->read(point2 + 5); Z2=(bus.read(point2 + 4) << 8) | bus.read(point2 + 5);
Color = r_mem->read(line + 4); Color = bus.read(line + 4);
C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color); C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color);
} }
} }
void C4::C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color) { void Cx4::C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color) {
//Transform coordinates //Transform coordinates
C4WFXVal = (int16)X1; C4WFXVal = (int16)X1;
C4WFYVal = (int16)Y1; C4WFYVal = (int16)Y1;
@@ -145,7 +145,7 @@ void C4::C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2,
} }
} }
void C4::C4DoScaleRotate(int row_padding) { void Cx4::C4DoScaleRotate(int row_padding) {
int16 A, B, C, D; int16 A, B, C, D;
//Calculate matrix //Calculate matrix

View File

@@ -1,5 +1,5 @@
//Build OAM //Build OAM
void C4::op00_00() { void Cx4::op00_00() {
uint32 oamptr = ram[0x626] << 2; uint32 oamptr = ram[0x626] << 2;
for(int32 i = 0x1fd; i > oamptr && i >= 0; i -= 4) { for(int32 i = 0x1fd; i > oamptr && i >= 0; i -= 4) {
//clear oam-to-be //clear oam-to-be
@@ -27,28 +27,28 @@ uint32 srcptr = 0x220;
sprattr = ram[srcptr + 4] | ram[srcptr + 6]; sprattr = ram[srcptr + 4] | ram[srcptr + 6];
uint32 spraddr = readl(srcptr + 7); uint32 spraddr = readl(srcptr + 7);
if(r_mem->read(spraddr)) { if(bus.read(spraddr)) {
int16 x, y; int16 x, y;
for(int sprcnt = r_mem->read(spraddr++); sprcnt > 0 && sprcount > 0; sprcnt--, spraddr += 4) { for(int sprcnt = bus.read(spraddr++); sprcnt > 0 && sprcount > 0; sprcnt--, spraddr += 4) {
x = (int8)r_mem->read(spraddr + 1); x = (int8)bus.read(spraddr + 1);
if(sprattr & 0x40) { if(sprattr & 0x40) {
x = -x - ((r_mem->read(spraddr) & 0x20) ? 16 : 8); x = -x - ((bus.read(spraddr) & 0x20) ? 16 : 8);
} }
x += sprx; x += sprx;
if(x >= -16 && x <= 272) { if(x >= -16 && x <= 272) {
y = (int8)r_mem->read(spraddr + 2); y = (int8)bus.read(spraddr + 2);
if(sprattr & 0x80) { if(sprattr & 0x80) {
y = -y - ((r_mem->read(spraddr) & 0x20) ? 16 : 8); y = -y - ((bus.read(spraddr) & 0x20) ? 16 : 8);
} }
y += spry; y += spry;
if(y >= -16 && y <= 224) { if(y >= -16 && y <= 224) {
ram[oamptr ] = (uint8)x; ram[oamptr ] = (uint8)x;
ram[oamptr + 1] = (uint8)y; ram[oamptr + 1] = (uint8)y;
ram[oamptr + 2] = sprname + r_mem->read(spraddr + 3); ram[oamptr + 2] = sprname + bus.read(spraddr + 3);
ram[oamptr + 3] = sprattr ^ (r_mem->read(spraddr) & 0xc0); ram[oamptr + 3] = sprattr ^ (bus.read(spraddr) & 0xc0);
ram[oamptr2] &= ~(3 << offset); ram[oamptr2] &= ~(3 << offset);
if(x & 0x100)ram[oamptr2] |= 1 << offset; if(x & 0x100)ram[oamptr2] |= 1 << offset;
if(r_mem->read(spraddr) & 0x20)ram[oamptr2] |= 2 << offset; if(bus.read(spraddr) & 0x20)ram[oamptr2] |= 2 << offset;
oamptr += 4; oamptr += 4;
sprcount--; sprcount--;
offset = (offset + 2) & 6; offset = (offset + 2) & 6;
@@ -73,12 +73,12 @@ uint32 srcptr = 0x220;
} }
//Scale and Rotate //Scale and Rotate
void C4::op00_03() { void Cx4::op00_03() {
C4DoScaleRotate(0); C4DoScaleRotate(0);
} }
//Transform Lines //Transform Lines
void C4::op00_05() { void Cx4::op00_05() {
C4WFX2Val = read(0x1f83); C4WFX2Val = read(0x1f83);
C4WFY2Val = read(0x1f86); C4WFY2Val = read(0x1f86);
C4WFDist = read(0x1f89); C4WFDist = read(0x1f89);
@@ -119,17 +119,17 @@ uint32 ptr2 = 0;
} }
//Scale and Rotate //Scale and Rotate
void C4::op00_07() { void Cx4::op00_07() {
C4DoScaleRotate(64); C4DoScaleRotate(64);
} }
//Draw Wireframe //Draw Wireframe
void C4::op00_08() { void Cx4::op00_08() {
C4DrawWireFrame(); C4DrawWireFrame();
} }
//Disintegrate //Disintegrate
void C4::op00_0b() { void Cx4::op00_0b() {
uint8 width, height; uint8 width, height;
uint32 startx, starty; uint32 startx, starty;
uint32 srcptr; uint32 srcptr;
@@ -169,7 +169,7 @@ int32 i, j;
} }
//Bitplane Wave //Bitplane Wave
void C4::op00_0c() { void Cx4::op00_0c() {
uint32 destptr = 0; uint32 destptr = 0;
uint32 waveptr = read(0x1f83); uint32 waveptr = read(0x1f83);
uint16 mask1 = 0xc0c0; uint16 mask1 = 0xc0c0;

View File

@@ -1,5 +1,5 @@
//Sprite Functions //Sprite Functions
void C4::op00() { void Cx4::op00() {
switch(reg[0x4d]) { switch(reg[0x4d]) {
case 0x00:op00_00();break; case 0x00:op00_00();break;
case 0x03:op00_03();break; case 0x03:op00_03();break;
@@ -12,13 +12,13 @@ void C4::op00() {
} }
//Draw Wireframe //Draw Wireframe
void C4::op01() { void Cx4::op01() {
memset(ram + 0x300, 0, 2304); memset(ram + 0x300, 0, 2304);
C4DrawWireFrame(); C4DrawWireFrame();
} }
//Propulsion //Propulsion
void C4::op05() { void Cx4::op05() {
int32 temp = 0x10000; int32 temp = 0x10000;
if(readw(0x1f83)) { if(readw(0x1f83)) {
temp = sar((temp / readw(0x1f83)) * readw(0x1f81), 8); temp = sar((temp / readw(0x1f83)) * readw(0x1f81), 8);
@@ -27,7 +27,7 @@ int32 temp = 0x10000;
} }
//Set Vector length //Set Vector length
void C4::op0d() { void Cx4::op0d() {
C41FXVal = readw(0x1f80); C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83); C41FYVal = readw(0x1f83);
C41FDistVal = readw(0x1f86); C41FDistVal = readw(0x1f86);
@@ -40,7 +40,7 @@ void C4::op0d() {
} }
//Triangle //Triangle
void C4::op10() { void Cx4::op10() {
r0 = ldr(0); r0 = ldr(0);
r1 = ldr(1); r1 = ldr(1);
@@ -64,7 +64,7 @@ void C4::op10() {
} }
//Triangle //Triangle
void C4::op13() { void Cx4::op13() {
r0 = ldr(0); r0 = ldr(0);
r1 = ldr(1); r1 = ldr(1);
@@ -87,7 +87,7 @@ void C4::op13() {
} }
//Pythagorean //Pythagorean
void C4::op15() { void Cx4::op15() {
C41FXVal = readw(0x1f80); C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83); C41FYVal = readw(0x1f83);
C41FDist = (int16)sqrt((double)C41FXVal * (double)C41FXVal + (double)C41FYVal * (double)C41FYVal); C41FDist = (int16)sqrt((double)C41FXVal * (double)C41FXVal + (double)C41FYVal * (double)C41FYVal);
@@ -95,7 +95,7 @@ void C4::op15() {
} }
//Calculate distance //Calculate distance
void C4::op1f() { void Cx4::op1f() {
C41FXVal = readw(0x1f80); C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83); C41FYVal = readw(0x1f83);
if(!C41FXVal) { if(!C41FXVal) {
@@ -113,7 +113,7 @@ void C4::op1f() {
} }
//Trapezoid //Trapezoid
void C4::op22() { void Cx4::op22() {
int16 angle1 = readw(0x1f8c) & 0x1ff; int16 angle1 = readw(0x1f8c) & 0x1ff;
int16 angle2 = readw(0x1f8f) & 0x1ff; int16 angle2 = readw(0x1f8f) & 0x1ff;
int32 tan1 = Tan(angle1); int32 tan1 = Tan(angle1);
@@ -152,7 +152,7 @@ int16 left, right;
} }
//Multiply //Multiply
void C4::op25() { void Cx4::op25() {
r0 = ldr(0); r0 = ldr(0);
r1 = ldr(1); r1 = ldr(1);
mul(r0, r1, r0, r1); mul(r0, r1, r0, r1);
@@ -161,7 +161,7 @@ void C4::op25() {
} }
//Transform Coords //Transform Coords
void C4::op2d() { void Cx4::op2d() {
C4WFXVal = readw(0x1f81); C4WFXVal = readw(0x1f81);
C4WFYVal = readw(0x1f84); C4WFYVal = readw(0x1f84);
C4WFZVal = readw(0x1f87); C4WFZVal = readw(0x1f87);
@@ -175,7 +175,7 @@ void C4::op2d() {
} }
//Sum //Sum
void C4::op40() { void Cx4::op40() {
r0 = 0; r0 = 0;
for(uint32 i=0;i<0x800;i++) { for(uint32 i=0;i<0x800;i++) {
r0 += ram[i]; r0 += ram[i];
@@ -184,7 +184,7 @@ void C4::op40() {
} }
//Square //Square
void C4::op54() { void Cx4::op54() {
r0 = ldr(0); r0 = ldr(0);
mul(r0, r0, r1, r2); mul(r0, r0, r1, r2);
str(1, r1); str(1, r1);
@@ -192,31 +192,31 @@ void C4::op54() {
} }
//Immediate Register //Immediate Register
void C4::op5c() { void Cx4::op5c() {
str(0, 0x000000); str(0, 0x000000);
immediate_reg(0); immediate_reg(0);
} }
//Immediate Register (Multiple) //Immediate Register (Multiple)
void C4::op5e() { immediate_reg( 0); } void Cx4::op5e() { immediate_reg( 0); }
void C4::op60() { immediate_reg( 3); } void Cx4::op60() { immediate_reg( 3); }
void C4::op62() { immediate_reg( 6); } void Cx4::op62() { immediate_reg( 6); }
void C4::op64() { immediate_reg( 9); } void Cx4::op64() { immediate_reg( 9); }
void C4::op66() { immediate_reg(12); } void Cx4::op66() { immediate_reg(12); }
void C4::op68() { immediate_reg(15); } void Cx4::op68() { immediate_reg(15); }
void C4::op6a() { immediate_reg(18); } void Cx4::op6a() { immediate_reg(18); }
void C4::op6c() { immediate_reg(21); } void Cx4::op6c() { immediate_reg(21); }
void C4::op6e() { immediate_reg(24); } void Cx4::op6e() { immediate_reg(24); }
void C4::op70() { immediate_reg(27); } void Cx4::op70() { immediate_reg(27); }
void C4::op72() { immediate_reg(30); } void Cx4::op72() { immediate_reg(30); }
void C4::op74() { immediate_reg(33); } void Cx4::op74() { immediate_reg(33); }
void C4::op76() { immediate_reg(36); } void Cx4::op76() { immediate_reg(36); }
void C4::op78() { immediate_reg(39); } void Cx4::op78() { immediate_reg(39); }
void C4::op7a() { immediate_reg(42); } void Cx4::op7a() { immediate_reg(42); }
void C4::op7c() { immediate_reg(45); } void Cx4::op7c() { immediate_reg(45); }
//Immediate ROM //Immediate ROM
void C4::op89() { void Cx4::op89() {
str(0, 0x054336); str(0, 0x054336);
str(1, 0xffffff); str(1, 0xffffff);
} }

View File

@@ -1,7 +1,5 @@
#include "../../base.h" #include "../../base.h"
DSP1 *dsp1;
#include "dsp1emu.cpp" #include "dsp1emu.cpp"
void DSP1::init() {} void DSP1::init() {}
@@ -28,29 +26,30 @@ void DSP1::reset() {
*****/ *****/
bool DSP1::addr_decode(uint16 addr) { bool DSP1::addr_decode(uint16 addr) {
switch(cartridge.info.dsp1_mapper) { switch(cartridge.info.dsp1_mapper) {
case Cartridge::DSP1LoROM1MB: {
case Cartridge::DSP1_LOROM_1MB:
//$[20-3f]:[8000-bfff] = DR, $[20-3f]:[c000-ffff] = SR //$[20-3f]:[8000-bfff] = DR, $[20-3f]:[c000-ffff] = SR
return (addr >= 0xc000); return (addr >= 0xc000);
}
case Cartridge::DSP1_LOROM_2MB: case Cartridge::DSP1LoROM2MB: {
//$[60-6f]:[0000-3fff] = DR, $[60-6f]:[4000-7fff] = SR //$[60-6f]:[0000-3fff] = DR, $[60-6f]:[4000-7fff] = SR
return (addr >= 0x4000); return (addr >= 0x4000);
}
case Cartridge::DSP1_HIROM: case Cartridge::DSP1HiROM: {
//$[00-1f]:[6000-6fff] = DR, $[00-1f]:[7000-7fff] = SR //$[00-1f]:[6000-6fff] = DR, $[00-1f]:[7000-7fff] = SR
return (addr >= 0x7000); return (addr >= 0x7000);
}
} }
return 0; return 0;
} }
uint8 DSP1::read(uint16 addr) { uint8 DSP1::read(uint addr) {
return (addr_decode(addr) == 0) ? dsp1.getDr() : dsp1.getSr(); return (addr_decode(addr) == 0) ? dsp1.getDr() : dsp1.getSr();
} }
void DSP1::write(uint16 addr, uint8 data) { void DSP1::write(uint addr, uint8 data) {
if(addr_decode(addr) == 0) { if(addr_decode(addr) == 0) {
dsp1.setDr(data); dsp1.setDr(data);
} }

View File

@@ -1,8 +1,9 @@
#include "dsp1emu.h" #include "dsp1emu.h"
class DSP1 { class DSP1 : public Memory {
private: private:
Dsp1 dsp1; Dsp1 dsp1;
bool addr_decode(uint16 addr);
public: public:
void init(); void init();
@@ -10,9 +11,8 @@ public:
void power(); void power();
void reset(); void reset();
bool addr_decode(uint16 addr); uint8 read(uint addr);
uint8 read (uint16 addr); void write(uint addr, uint8 data);
void write(uint16 addr, uint8 data);
}; };
extern DSP1 *dsp1; extern DSP1 dsp1;

View File

@@ -1,7 +1,5 @@
#include "../../base.h" #include "../../base.h"
DSP2 *dsp2;
#include "dsp2_op.cpp" #include "dsp2_op.cpp"
void DSP2::init() {} void DSP2::init() {}
@@ -30,7 +28,7 @@ void DSP2::reset() {
status.op0dinlen = 0; status.op0dinlen = 0;
} }
uint8 DSP2::read(uint16 addr) { uint8 DSP2::read(uint addr) {
uint8 r = 0xff; uint8 r = 0xff;
if(status.out_count) { if(status.out_count) {
r = status.output[status.out_index++]; r = status.output[status.out_index++];
@@ -42,7 +40,7 @@ uint8 r = 0xff;
return r; return r;
} }
void DSP2::write(uint16 addr, uint8 data) { void DSP2::write(uint addr, uint8 data) {
if(status.waiting_for_command) { if(status.waiting_for_command) {
status.command = data; status.command = data;
status.in_index = 0; status.in_index = 0;

View File

@@ -1,6 +1,6 @@
class DSP2 { class DSP2 : public Memory {
public: public:
struct { struct {
bool waiting_for_command; bool waiting_for_command;
uint command; uint command;
uint in_count, in_index; uint in_count, in_index;
@@ -19,25 +19,26 @@ struct {
bool op0dhaslen; bool op0dhaslen;
int op0doutlen; int op0doutlen;
int op0dinlen; int op0dinlen;
} status; } status;
void init(); void init();
void enable(); void enable();
void power(); void power();
void reset(); void reset();
uint8 read(uint addr);
void write(uint addr, uint8 data);
DSP2();
~DSP2();
protected:
void op01(); void op01();
void op03(); void op03();
void op05(); void op05();
void op06(); void op06();
void op09(); void op09();
void op0d(); void op0d();
uint8 read (uint16 addr);
void write(uint16 addr, uint8 data);
DSP2();
~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 uint8
#include "dsp3emu.c"
#undef bool8
};
void DSP3::init() {
}
void DSP3::enable() {
}
void DSP3::power() {
reset();
}
void DSP3::reset() {
DSP3i::DSP3_Reset();
}
uint8 DSP3::read(uint addr) {
DSP3i::dsp3_address = addr & 0xffff;
DSP3i::DSP3GetByte();
return DSP3i::dsp3_byte;
}
void DSP3::write(uint addr, uint8 data) {
DSP3i::dsp3_address = addr & 0xffff;
DSP3i::dsp3_byte = data;
DSP3i::DSP3SetByte();
}

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

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

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

File diff suppressed because it is too large Load Diff

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

@@ -0,0 +1,53 @@
#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 uint8
#include "dsp4emu.c"
#undef bool8
};
void DSP4::init() {
}
void DSP4::enable() {
}
void DSP4::power() {
reset();
}
void DSP4::reset() {
DSP4i::InitDSP4();
}
uint8 DSP4::read(uint addr) {
addr &= 0xffff;
if(addr < 0xc000) {
DSP4i::dsp4_address = addr;
DSP4i::DSP4GetByte();
return DSP4i::dsp4_byte;
}
return 0x80;
}
void DSP4::write(uint addr, uint8 data) {
addr &= 0xffff;
if(addr < 0xc000) {
DSP4i::dsp4_address = addr;
DSP4i::dsp4_byte = data;
DSP4i::DSP4SetByte();
}
}

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

@@ -0,0 +1,12 @@
class DSP4 : public Memory {
public:
void init();
void enable();
void power();
void reset();
uint8 read (uint addr);
void write(uint 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" #include "../../base.h"
OBC1 *obc1;
void OBC1::init() {} void OBC1::init() {}
void OBC1::enable() {} void OBC1::enable() {}
@@ -10,81 +8,82 @@ void OBC1::power() {
} }
void OBC1::reset() { void OBC1::reset() {
memset(cartridge.ram, 0xff, 0x2000); for(uint i = 0x0000; i <= 0x1fff; i++) ram_write(i, 0xff);
status.baseptr = (cartridge.ram[0x1ff5] & 1) ? 0x1800 : 0x1c00;
status.address = (cartridge.ram[0x1ff6] & 0x7f); status.baseptr = (ram_read(0x1ff5) & 1) ? 0x1800 : 0x1c00;
status.shift = (cartridge.ram[0x1ff6] & 3) << 1; status.address = (ram_read(0x1ff6) & 0x7f);
status.shift = (ram_read(0x1ff6) & 3) << 1;
} }
uint8 OBC1::read(uint16 addr) { uint8 OBC1::read(uint addr) {
addr &= 0x1fff; addr &= 0x1fff;
if((addr & 0x1ff8) != 0x1ff0) return ram_read(addr);
if((addr & 0x1ff8) != 0x1ff0) {
return cartridge.ram[addr];
}
switch(addr) { switch(addr) {
case 0x1ff0: case 0x1ff0:
return cartridge.ram[status.baseptr + (status.address << 2) + 0]; return ram_read(status.baseptr + (status.address << 2) + 0);
case 0x1ff1: case 0x1ff1:
return cartridge.ram[status.baseptr + (status.address << 2) + 1]; return ram_read(status.baseptr + (status.address << 2) + 1);
case 0x1ff2: case 0x1ff2:
return cartridge.ram[status.baseptr + (status.address << 2) + 2]; return ram_read(status.baseptr + (status.address << 2) + 2);
case 0x1ff3: case 0x1ff3:
return cartridge.ram[status.baseptr + (status.address << 2) + 3]; return ram_read(status.baseptr + (status.address << 2) + 3);
case 0x1ff4: case 0x1ff4:
return cartridge.ram[status.baseptr + (status.address >> 2) + 0x200]; return ram_read(status.baseptr + (status.address >> 2) + 0x200);
case 0x1ff5: case 0x1ff5:
case 0x1ff6: case 0x1ff6:
case 0x1ff7: case 0x1ff7:
return cartridge.ram[addr]; return ram_read(addr);
} }
//never used, blocks compiler warning return 0x00; //never used, avoids compiler warning
return 0x00;
} }
void OBC1::write(uint16 addr, uint8 data) { void OBC1::write(uint addr, uint8 data) {
addr &= 0x1fff; addr &= 0x1fff;
if((addr & 0x1ff8) != 0x1ff0) return ram_write(addr, data);
if((addr & 0x1ff8) != 0x1ff0) {
cartridge.ram[addr] = data;
return;
}
switch(addr) { switch(addr) {
case 0x1ff0: case 0x1ff0:
cartridge.ram[status.baseptr + (status.address << 2) + 0] = data; ram_write(status.baseptr + (status.address << 2) + 0, data);
break; break;
case 0x1ff1: case 0x1ff1:
cartridge.ram[status.baseptr + (status.address << 2) + 1] = data; ram_write(status.baseptr + (status.address << 2) + 1, data);
break; break;
case 0x1ff2: case 0x1ff2:
cartridge.ram[status.baseptr + (status.address << 2) + 2] = data; ram_write(status.baseptr + (status.address << 2) + 2, data);
break; break;
case 0x1ff3: case 0x1ff3:
cartridge.ram[status.baseptr + (status.address << 2) + 3] = data; ram_write(status.baseptr + (status.address << 2) + 3, data);
break; break;
case 0x1ff4: { case 0x1ff4: {
uint8 temp; uint8 temp;
temp = cartridge.ram[status.baseptr + (status.address >> 2) + 0x200]; temp = ram_read(status.baseptr + (status.address >> 2) + 0x200);
temp = (temp & ~(3 << status.shift)) | ((data & 3) << status.shift); temp = (temp & ~(3 << status.shift)) | ((data & 3) << status.shift);
cartridge.ram[status.baseptr + (status.address >> 2) + 0x200] = temp; ram_write(status.baseptr + (status.address >> 2) + 0x200, temp);
} break; } break;
case 0x1ff5: case 0x1ff5:
status.baseptr = (data & 1) ? 0x1800 : 0x1c00; status.baseptr = (data & 1) ? 0x1800 : 0x1c00;
cartridge.ram[addr] = data; ram_write(addr, data);
break; break;
case 0x1ff6: case 0x1ff6:
status.address = (data & 0x7f); status.address = (data & 0x7f);
status.shift = (data & 3) << 1; status.shift = (data & 3) << 1;
cartridge.ram[addr] = data; ram_write(addr, data);
break; break;
case 0x1ff7: case 0x1ff7:
cartridge.ram[addr] = data; ram_write(addr, data);
break; break;
} }
} }
uint8 OBC1::ram_read(uint addr) {
return memory::cartram.read(addr & 0x1fff);
}
void OBC1::ram_write(uint addr, uint8 data) {
memory::cartram.write(addr & 0x1fff, data);
}
OBC1::OBC1() {} OBC1::OBC1() {}
OBC1::~OBC1() {} OBC1::~OBC1() {}

View File

@@ -1,20 +1,25 @@
class OBC1 { class OBC1 : public Memory {
public: public:
struct {
uint16 address;
uint16 baseptr;
uint16 shift;
} status;
void init(); void init();
void enable(); void enable();
void power(); void power();
void reset(); void reset();
uint8 read (uint16 addr); uint8 read(uint addr);
void write(uint16 addr, uint8 data); void write(uint addr, uint8 data);
OBC1(); OBC1();
~OBC1(); ~OBC1();
private:
uint8 ram_read(uint addr);
void ram_write(uint addr, uint8 data);
struct {
uint16 address;
uint16 baseptr;
uint16 shift;
} status;
}; };
extern OBC1 *obc1; extern OBC1 obc1;

View File

@@ -1,15 +1,11 @@
#include "../../base.h" #include "../../base.h"
SDD1 *sdd1;
#include "sdd1emu.cpp" #include "sdd1emu.cpp"
void SDD1::init() {} void SDD1::init() {}
void SDD1::enable() { void SDD1::enable() {
for(int i = 0x4800; i <= 0x4807; i++) { for(int i = 0x4800; i <= 0x4807; i++) memory::mmio.map(i, *this);
r_mem->set_mmio_mapper(i, this);
}
} }
void SDD1::power() { void SDD1::power() {
@@ -17,59 +13,80 @@ void SDD1::power() {
} }
void SDD1::reset() { void SDD1::reset() {
sdd1.index[0] = 0x000000;
sdd1.index[1] = 0x100000;
sdd1.index[2] = 0x200000;
sdd1.index[3] = 0x300000;
for(int i=0;i<8;i++) {
sdd1.active[i] = false;
}
sdd1.dma_active = false; sdd1.dma_active = false;
regs.r4800 = 0x00;
regs.r4801 = 0x00;
regs.r4804 = 0x00;
regs.r4805 = 0x01;
regs.r4806 = 0x02;
regs.r4807 = 0x03;
bus.map(Bus::MapLinear, 0xc0, 0xcf, 0x0000, 0xffff, memory::cartrom, (regs.r4804 & 7) << 20);
bus.map(Bus::MapLinear, 0xd0, 0xdf, 0x0000, 0xffff, memory::cartrom, (regs.r4805 & 7) << 20);
bus.map(Bus::MapLinear, 0xe0, 0xef, 0x0000, 0xffff, memory::cartrom, (regs.r4806 & 7) << 20);
bus.map(Bus::MapLinear, 0xf0, 0xff, 0x0000, 0xffff, memory::cartrom, (regs.r4807 & 7) << 20);
} }
uint32 SDD1::offset(uint32 addr) { uint8 SDD1::mmio_read(uint addr) {
uint8 b = (addr >> 16) & 0xff; switch(addr & 0xffff) {
if(b <= 0xbf)return 0; case 0x4804: return regs.r4804;
case 0x4805: return regs.r4805;
b -= 0xc0; //b = 0x00-0x3f case 0x4806: return regs.r4806;
b >>= 4; //b = 0-3 case 0x4807: return regs.r4807;
b &= 3; //bitmask
return sdd1.index[b] + (addr & 0x0fffff);
}
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;
} }
return r_cpu->regs.mdr; return cpu.regs.mdr;
} }
void SDD1::mmio_write(uint16 addr, uint8 data) { void SDD1::mmio_write(uint addr, uint8 data) {
switch(addr) { switch(addr & 0xffff) {
case 0x4801: case 0x4800: {
for(int i = 0; i < 8; i++) { regs.r4800 = data;
sdd1.active[i] = !!(data & (1 << i)); } break;
case 0x4801: {
regs.r4801 = data;
} break;
case 0x4804: {
if(regs.r4804 != data) {
regs.r4804 = data;
bus.map(Bus::MapLinear, 0xc0, 0xcf, 0x0000, 0xffff,
memory::cartrom, (regs.r4804 & 7) << 20);
} }
break; } break;
//<<20 == 0x100000 == 1mb
case 0x4804:sdd1.index[0] = (data & 7) << 20;break; case 0x4805: {
case 0x4805:sdd1.index[1] = (data & 7) << 20;break; if(regs.r4805 != data) {
case 0x4806:sdd1.index[2] = (data & 7) << 20;break; regs.r4805 = data;
case 0x4807:sdd1.index[3] = (data & 7) << 20;break; bus.map(Bus::MapLinear, 0xd0, 0xdf, 0x0000, 0xffff,
memory::cartrom, (regs.r4805 & 7) << 20);
}
} break;
case 0x4806: {
if(regs.r4806 != data) {
regs.r4806 = data;
bus.map(Bus::MapLinear, 0xe0, 0xef, 0x0000, 0xffff,
memory::cartrom, (regs.r4806 & 7) << 20);
}
} break;
case 0x4807: {
if(regs.r4807 != data) {
regs.r4807 = data;
bus.map(Bus::MapLinear, 0xf0, 0xff, 0x0000, 0xffff,
memory::cartrom, (regs.r4807 & 7) << 20);
}
} break;
} }
} }
void SDD1::dma_begin(uint8 channel, uint32 addr, uint16 length) { void SDD1::dma_begin(uint8 channel, uint32 addr, uint16 length) {
if(sdd1.active[channel] == true) { if(regs.r4800 & (1 << channel) && regs.r4801 & (1 << channel)) {
sdd1.active[channel] = false; regs.r4801 &= ~(1 << channel);
sdd1.dma_active = true; sdd1.dma_active = true;
sdd1.buffer_index = 0; sdd1.buffer_index = 0;
sdd1.buffer_size = length; sdd1.buffer_size = length;
@@ -82,9 +99,7 @@ bool SDD1::dma_active() {
} }
uint8 SDD1::dma_read() { uint8 SDD1::dma_read() {
if(--sdd1.buffer_size == 0) { if(--sdd1.buffer_size == 0) sdd1.dma_active = false;
sdd1.dma_active = false;
}
//sdd1.buffer[] is 65536 bytes, and sdd1.buffer_index //sdd1.buffer[] is 65536 bytes, and sdd1.buffer_index
//is of type uint16, so no buffer overflow is possible //is of type uint16, so no buffer overflow is possible

View File

@@ -2,31 +2,38 @@
class SDD1 : public MMIO { class SDD1 : public MMIO {
public: public:
SDD1emu sdd1emu;
struct {
uint32 index[4]; //memory mapping registers
uint8 buffer[65536]; //pointer to decompressed S-DD1 data,
//max. DMA length is 65536
uint16 buffer_index; //DMA read index into S-DD1 decompression buffer
uint16 buffer_size;
bool active[8]; //true when DMA channel should pass through S-DD1
bool dma_active;
} sdd1;
void init(); void init();
void enable(); void enable();
void power(); void power();
void reset(); void reset();
uint32 offset(uint32 addr);
uint8 mmio_read (uint addr);
void mmio_write(uint addr, uint8 data);
void dma_begin(uint8 channel, uint32 addr, uint16 length); void dma_begin(uint8 channel, uint32 addr, uint16 length);
bool dma_active(); bool dma_active();
uint8 dma_read(); uint8 dma_read();
uint8 mmio_read (uint16 addr);
void mmio_write(uint16 addr, uint8 data);
SDD1(); SDD1();
private:
SDD1emu sdd1emu;
struct {
uint8 buffer[65536]; //pointer to decompressed S-DD1 data, max DMA length is 65536
uint16 buffer_index; //DMA read index into S-DD1 decompression buffer
uint16 buffer_size;
bool dma_active;
} sdd1;
struct {
uint8 r4800;
uint8 r4801;
uint8 r4804;
uint8 r4805;
uint8 r4806;
uint8 r4807;
} regs;
}; };
extern SDD1 *sdd1; extern SDD1 sdd1;

View File

@@ -28,7 +28,7 @@ understood.
************************************************************************/ ************************************************************************/
#define SDD1_read(__addr) (r_mem->read(__addr)) #define SDD1_read(__addr) (bus.read(__addr))
//////////////////////////////////////////////////// ////////////////////////////////////////////////////

View File

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

View File

@@ -52,8 +52,6 @@
#include "../../base.h" #include "../../base.h"
SRTC *srtc;
void SRTC::set_time() { void SRTC::set_time() {
time_t rawtime; time_t rawtime;
tm *t; tm *t;
@@ -79,8 +77,8 @@ tm *t;
void SRTC::init() {} void SRTC::init() {}
void SRTC::enable() { void SRTC::enable() {
r_mem->set_mmio_mapper(0x2800, this); memory::mmio.map(0x2800, *this);
r_mem->set_mmio_mapper(0x2801, this); memory::mmio.map(0x2801, *this);
} }
void SRTC::power() { void SRTC::power() {
@@ -93,8 +91,8 @@ void SRTC::reset() {
srtc.mode = SRTC_READ; srtc.mode = SRTC_READ;
} }
uint8 SRTC::mmio_read(uint16 addr) { uint8 SRTC::mmio_read(uint addr) {
switch(addr) { switch(addr & 0xffff) {
case 0x2800: { case 0x2800: {
if(srtc.mode == SRTC_READ) { if(srtc.mode == SRTC_READ) {
@@ -118,7 +116,7 @@ uint8 SRTC::mmio_read(uint16 addr) {
} }
return r_cpu->regs.mdr; return cpu.regs.mdr;
} }
//Please see notes above about the implementation of the S-RTC //Please see notes above about the implementation of the S-RTC
@@ -126,8 +124,8 @@ uint8 SRTC::mmio_read(uint16 addr) {
//as reads will refresh the data array with the current system //as reads will refresh the data array with the current system
//time. The write method is only here for the sake of faux //time. The write method is only here for the sake of faux
//emulation of the real hardware. //emulation of the real hardware.
void SRTC::mmio_write(uint16 addr, uint8 data) { void SRTC::mmio_write(uint addr, uint8 data) {
switch(addr) { switch(addr & 0xffff) {
case 0x2800: { case 0x2800: {
} break; } break;

View File

@@ -43,10 +43,10 @@ struct {
void power(); void power();
void reset(); void reset();
uint8 mmio_read (uint16 addr); uint8 mmio_read (uint addr);
void mmio_write(uint16 addr, uint8 data); void mmio_write(uint addr, uint8 data);
SRTC(); 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(uint addr) {
return readb(addr);
}
void ST010::write(uint addr, uint8 data) {
writeb(addr, data);
if((addr & 0xfff) == 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;
}
}

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

@@ -0,0 +1,42 @@
class ST010 : public Memory {
public:
void init();
void enable();
void power();
void reset();
uint8 read (uint addr);
void write(uint addr, uint8 data);
private:
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);
};
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,66 @@
uint8 SuperFX::mmio_read(uint addr) {
addr &= 0xffff;
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,65 @@
void SuperFX::mmio_write(uint addr, uint8 data) {
addr &= 0xffff;
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++) {
memory::mmio.map(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 (uint addr);
void mmio_write(uint 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-mingw-x86 clean
::@make PLATFORM=win-visualc-x86 clean

1
src/clean.sh Normal file
View File

@@ -0,0 +1 @@
make PLATFORM=x-gcc-x86 clean

View File

@@ -1,7 +1,10 @@
Config config_file;
namespace config { namespace config {
Config& config() {
static Config config;
return config;
}
string file_updatepath(const char *req_file, const char *req_path) { string file_updatepath(const char *req_file, const char *req_path) {
string file(req_file); string file(req_file);
replace(file, "\\", "/"); replace(file, "\\", "/");
@@ -12,96 +15,118 @@ string path(req_path);
if(!strend(path, "/")) { strcat(path, "/"); } if(!strend(path, "/")) { strcat(path, "/"); }
if(strbegin(path, "./")) { if(strbegin(path, "./")) {
strltrim(path, "./"); ltrim(path(), "./");
string temp; string temp;
strcpy(temp, config::path.base); strcpy(temp, config::path.base);
strcat(temp, path); strcat(temp, path);
strcpy(path, temp); strcpy(path, temp);
} }
stringarray part; lstring part;
split(part, "/", file); split(part, "/", file);
strcat(path, part[count(part) - 1]); strcat(path, part[count(part) - 1]);
return path; return path;
} }
Setting Path::base(0, "fs.base_path", StringSetting Path::base(0, "path.base",
"Path that bsnes resides in", ""); "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)", ""); "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)", ""); "Default path for all save RAM and cheat files (\"\" = use current directory)", "");
Setting Path::bios(&config_file, "path.bios", StringSetting Path::bsx(&config(), "path.bsx", "", "");
"Path where BIOS file(s) are located\n" StringSetting Path::st(&config(), "path.st", "", "");
"Supported BIOS files:\n"
"stbios.bin - Bandai Sufami Turbo"
"", "./bios");
Setting Path::save_ext(&config_file, "path.save_ext", IntegerSetting SNES::gamma_ramp(&config(), "snes.colorfilter.gamma_ramp",
"Extension to be used for all save RAM files", "srm"); "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::gamma_ramp(&config_file, "snes.colorfilter.gamma_ramp", IntegerSetting SNES::ntsc_merge_fields(&config(), "snes.ntsc_merge_fields",
"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);
Setting SNES::ntsc_merge_fields(&config_file, "snes.ntsc_merge_fields",
"Merge fields in NTSC video filter\n" "Merge fields in NTSC video filter\n"
"Set to true if using filter at any refresh rate other than 60hz\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", IntegerSetting SNES::mute(&config(), "snes.mute", "Mutes SNES audio output when enabled",
false, Setting::BOOL); IntegerSetting::Boolean, false);
Setting SNES::controller_port0(&config_file, "snes.controller_port_1", IntegerSetting SNES::controller_port0(&config(), "snes.controller_port_1",
"Controller attached to SNES port 1", ::SNES::DEVICEID_JOYPAD1, Setting::DEC); "Controller attached to SNES port 1", IntegerSetting::Decimal, ::SNES::DEVICEID_JOYPAD1);
Setting SNES::controller_port1(&config_file, "snes.controller_port_2", IntegerSetting SNES::controller_port1(&config(), "snes.controller_port_2",
"Controller attached to SNES port 2", ::SNES::DEVICEID_JOYPAD2, Setting::DEC); "Controller attached to SNES port 2", IntegerSetting::Decimal, ::SNES::DEVICEID_JOYPAD2);
Setting CPU::ntsc_clock_rate(&config_file, "cpu.ntsc_clock_rate", IntegerSetting CPU::ntsc_clock_rate(&config(), "cpu.ntsc_clock_rate",
"NTSC S-CPU clock rate (in hz)", 21477272, Setting::DEC); "NTSC S-CPU clock rate (in hz)", IntegerSetting::Decimal, 21477272);
Setting CPU::pal_clock_rate(&config_file, "cpu.pal_clock_rate", IntegerSetting CPU::pal_clock_rate(&config(), "cpu.pal_clock_rate",
"PAL S-CPU clock rate (in hz)", 21281370, Setting::DEC); "PAL S-CPU clock rate (in hz)", IntegerSetting::Decimal, 21281370);
IntegerSetting CPU::wram_init_value(&config(), "cpu.wram_init_value",
"Value to initialize 128k WRAM to upon power cycle.\n"
"Note that on real hardware, this value is undefined; meaning it can vary\n"
"per power-on, and per SNES unit. Such randomness is undesirable for an\n"
"emulator, so a static value is needed. There is also some form of pattern\n"
"to the randomness that has yet to be determined, which some games rely upon.\n"
"A value of 0x55 is safe for all known commercial software, and should be used.\n"
"However, some software written for SNES copiers, or backup units, relies on\n"
"WRAM being initialized to 0x00; which was a side-effect of the BIOS program\n"
"which executed on these copiers. Using 0x00 will therefore fix many homebrew\n"
"programs, but *will* break some poorly programmed commercial software titles,\n"
"which do not properly initialize WRAM upon power cycle.\n",
IntegerSetting::Hex, 0x55);
Setting CPU::hdma_enable(0, "cpu.hdma_enable", IntegerSetting CPU::hdma_enable(0, "cpu.hdma_enable",
"Enable HDMA effects", true, Setting::BOOL); "Enable HDMA effects", IntegerSetting::Boolean, true);
Setting SMP::ntsc_clock_rate(&config_file, "smp.ntsc_clock_rate", IntegerSetting SMP::ntsc_clock_rate(&config(), "smp.ntsc_clock_rate",
"NTSC S-SMP clock rate (in hz)", 24606720, Setting::DEC); "NTSC S-SMP clock rate (in hz)", IntegerSetting::Decimal, 24606720);
Setting SMP::pal_clock_rate(&config_file, "smp.pal_clock_rate", IntegerSetting SMP::pal_clock_rate(&config(), "smp.pal_clock_rate",
"PAL S-SMP clock rate (in hz)", 24606720, Setting::DEC); "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", "Approximate HCLOCK position to render at for scanline-based renderers",
512, Setting::DEC); IntegerSetting::Decimal, 512);
Setting PPU::Hack::obj_cache(&config_file, "ppu.hack.obj_cache", IntegerSetting PPU::Hack::obj_cache(&config(), "ppu.hack.obj_cache",
"Cache OAM OBJ attributes one scanline before rendering\n" "Cache OAM OBJ attributes one scanline before rendering\n"
"This is technically closer to the actual operation of the SNES,\n" "This is technically closer to the actual operation of the SNES,\n"
"but can cause problems in many games if enabled", "but can cause problems in some games if enabled",
false, Setting::BOOL); 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); IntegerSetting PPU::opt_enable(0, "ppu.opt_enable", "Enable offset-per-tile effects", IntegerSetting::Boolean, true);
Setting PPU::bg1_pri0_enable(0, "ppu.bg1_pri0_enable", "Enable BG1 Priority 0", true, Setting::BOOL); IntegerSetting PPU::bg1_pri0_enable(0, "ppu.bg1_pri0_enable", "Enable BG1 Priority 0", IntegerSetting::Boolean, true);
Setting PPU::bg1_pri1_enable(0, "ppu.bg1_pri1_enable", "Enable BG1 Priority 1", true, Setting::BOOL); IntegerSetting PPU::bg1_pri1_enable(0, "ppu.bg1_pri1_enable", "Enable BG1 Priority 1", IntegerSetting::Boolean, true);
Setting PPU::bg2_pri0_enable(0, "ppu.bg2_pri0_enable", "Enable BG2 Priority 0", true, Setting::BOOL); IntegerSetting PPU::bg2_pri0_enable(0, "ppu.bg2_pri0_enable", "Enable BG2 Priority 0", IntegerSetting::Boolean, true);
Setting PPU::bg2_pri1_enable(0, "ppu.bg2_pri1_enable", "Enable BG2 Priority 1", true, Setting::BOOL); IntegerSetting PPU::bg2_pri1_enable(0, "ppu.bg2_pri1_enable", "Enable BG2 Priority 1", IntegerSetting::Boolean, true);
Setting PPU::bg3_pri0_enable(0, "ppu.bg3_pri0_enable", "Enable BG3 Priority 0", true, Setting::BOOL); IntegerSetting PPU::bg3_pri0_enable(0, "ppu.bg3_pri0_enable", "Enable BG3 Priority 0", IntegerSetting::Boolean, true);
Setting PPU::bg3_pri1_enable(0, "ppu.bg3_pri1_enable", "Enable BG3 Priority 1", true, Setting::BOOL); IntegerSetting PPU::bg3_pri1_enable(0, "ppu.bg3_pri1_enable", "Enable BG3 Priority 1", IntegerSetting::Boolean, true);
Setting PPU::bg4_pri0_enable(0, "ppu.bg4_pri0_enable", "Enable BG4 Priority 0", true, Setting::BOOL); IntegerSetting PPU::bg4_pri0_enable(0, "ppu.bg4_pri0_enable", "Enable BG4 Priority 0", IntegerSetting::Boolean, true);
Setting PPU::bg4_pri1_enable(0, "ppu.bg4_pri1_enable", "Enable BG4 Priority 1", true, Setting::BOOL); IntegerSetting PPU::bg4_pri1_enable(0, "ppu.bg4_pri1_enable", "Enable BG4 Priority 1", IntegerSetting::Boolean, true);
Setting PPU::oam_pri0_enable(0, "ppu.oam_pri0_enable", "Enable OAM Priority 0", true, Setting::BOOL); IntegerSetting PPU::oam_pri0_enable(0, "ppu.oam_pri0_enable", "Enable OAM Priority 0", IntegerSetting::Boolean, true);
Setting PPU::oam_pri1_enable(0, "ppu.oam_pri1_enable", "Enable OAM Priority 1", true, Setting::BOOL); IntegerSetting PPU::oam_pri1_enable(0, "ppu.oam_pri1_enable", "Enable OAM Priority 1", IntegerSetting::Boolean, true);
Setting PPU::oam_pri2_enable(0, "ppu.oam_pri2_enable", "Enable OAM Priority 2", true, Setting::BOOL); IntegerSetting PPU::oam_pri2_enable(0, "ppu.oam_pri2_enable", "Enable OAM Priority 2", IntegerSetting::Boolean, true);
Setting PPU::oam_pri3_enable(0, "ppu.oam_pri3_enable", "Enable OAM Priority 3", true, Setting::BOOL); IntegerSetting PPU::oam_pri3_enable(0, "ppu.oam_pri3_enable", "Enable OAM Priority 3", IntegerSetting::Boolean, true);
}; };

View File

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

View File

@@ -3,7 +3,7 @@ public:
union { union {
uint8 data; uint8 data;
struct { 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

@@ -4,7 +4,7 @@ uint8 CPU::dreadb(uint32 addr) {
//do not read MMIO registers within debugger //do not read MMIO registers within debugger
return 0x00; return 0x00;
} }
return r_mem->read(addr); return bus.read(addr);
} }
uint16 CPU::dreadw(uint32 addr) { uint16 CPU::dreadw(uint32 addr) {

View File

@@ -1,7 +1,12 @@
#include "opfn.cpp" #include "opfn.cpp"
void sCPU::enter() { #include "op_read.cpp"
for(;;) { #include "op_write.cpp"
#include "op_rmw.cpp"
#include "op_pc.cpp"
#include "op_misc.cpp"
void sCPU::enter() { loop:
if(event.irq) { if(event.irq) {
event.irq = false; event.irq = false;
if(status.nmi_pending == true) { if(status.nmi_pending == true) {
@@ -17,17 +22,10 @@ void sCPU::enter() {
tracer.trace_cpuop(); //traces CPU opcode (only if tracer is enabled) tracer.trace_cpuop(); //traces CPU opcode (only if tracer is enabled)
status.in_opcode = true; status.in_opcode = true;
(this->*optbl[op_readpc()])();
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; status.in_opcode = false;
}
goto loop;
} }
void sCPU::op_irq() { void sCPU::op_irq() {

View File

@@ -1,4 +1,4 @@
//void (sCPU::*optbl[256])(); void (sCPU::*optbl[256])();
CPUReg24 aa, rd; CPUReg24 aa, rd;
uint8 dp, sp; uint8 dp, sp;
@@ -54,4 +54,4 @@ uint8 dp, sp;
void op_io_cond4(uint16 x, uint16 y); void op_io_cond4(uint16 x, uint16 y);
void op_io_cond6(uint16 addr); 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) { wai(0xcb) {
1:op_io(); //last_cycle() will set event.wai to false
event.wai = true; //once an NMI / IRQ edge is reached
2:last_cycle(); 1:event.wai = true;
op_io(); while(event.wai) {
3:while(event.wai) {
last_cycle(); last_cycle();
op_io(); op_io();
} }
2:op_io();
} }
xce(0xfb) { xce(0xfb) {

View File

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

View File

@@ -1,171 +1,157 @@
//bcc void sCPU::op_bcc() {
case 0x90: {
if(!!regs.p.c)last_cycle(); if(!!regs.p.c)last_cycle();
rd.l = op_readpc(); rd.l = op_readpc();
if(!regs.p.c) { if(!regs.p.c) {
aa.w = regs.pc.d + (int8)rd.l; aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w; regs.pc.w = aa.w;
} else { } else {
break; return;
} }
op_io_cond6(aa.w); op_io_cond6(aa.w);
last_cycle(); last_cycle();
op_io(); op_io();
} break; }
//bcs void sCPU::op_bcs() {
case 0xb0: {
if(!regs.p.c)last_cycle(); if(!regs.p.c)last_cycle();
rd.l = op_readpc(); rd.l = op_readpc();
if(regs.p.c) { if(regs.p.c) {
aa.w = regs.pc.d + (int8)rd.l; aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w; regs.pc.w = aa.w;
} else { } else {
break; return;
} }
op_io_cond6(aa.w); op_io_cond6(aa.w);
last_cycle(); last_cycle();
op_io(); op_io();
} break; }
//bne void sCPU::op_bne() {
case 0xd0: {
if(!!regs.p.z)last_cycle(); if(!!regs.p.z)last_cycle();
rd.l = op_readpc(); rd.l = op_readpc();
if(!regs.p.z) { if(!regs.p.z) {
aa.w = regs.pc.d + (int8)rd.l; aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w; regs.pc.w = aa.w;
} else { } else {
break; return;
} }
op_io_cond6(aa.w); op_io_cond6(aa.w);
last_cycle(); last_cycle();
op_io(); op_io();
} break; }
//beq void sCPU::op_beq() {
case 0xf0: {
if(!regs.p.z)last_cycle(); if(!regs.p.z)last_cycle();
rd.l = op_readpc(); rd.l = op_readpc();
if(regs.p.z) { if(regs.p.z) {
aa.w = regs.pc.d + (int8)rd.l; aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w; regs.pc.w = aa.w;
} else { } else {
break; return;
} }
op_io_cond6(aa.w); op_io_cond6(aa.w);
last_cycle(); last_cycle();
op_io(); op_io();
} break; }
//bpl void sCPU::op_bpl() {
case 0x10: {
if(!!regs.p.n)last_cycle(); if(!!regs.p.n)last_cycle();
rd.l = op_readpc(); rd.l = op_readpc();
if(!regs.p.n) { if(!regs.p.n) {
aa.w = regs.pc.d + (int8)rd.l; aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w; regs.pc.w = aa.w;
} else { } else {
break; return;
} }
op_io_cond6(aa.w); op_io_cond6(aa.w);
last_cycle(); last_cycle();
op_io(); op_io();
} break; }
//bmi void sCPU::op_bmi() {
case 0x30: {
if(!regs.p.n)last_cycle(); if(!regs.p.n)last_cycle();
rd.l = op_readpc(); rd.l = op_readpc();
if(regs.p.n) { if(regs.p.n) {
aa.w = regs.pc.d + (int8)rd.l; aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w; regs.pc.w = aa.w;
} else { } else {
break; return;
} }
op_io_cond6(aa.w); op_io_cond6(aa.w);
last_cycle(); last_cycle();
op_io(); op_io();
} break; }
//bvc void sCPU::op_bvc() {
case 0x50: {
if(!!regs.p.v)last_cycle(); if(!!regs.p.v)last_cycle();
rd.l = op_readpc(); rd.l = op_readpc();
if(!regs.p.v) { if(!regs.p.v) {
aa.w = regs.pc.d + (int8)rd.l; aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w; regs.pc.w = aa.w;
} else { } else {
break; return;
} }
op_io_cond6(aa.w); op_io_cond6(aa.w);
last_cycle(); last_cycle();
op_io(); op_io();
} break; }
//bvs void sCPU::op_bvs() {
case 0x70: {
if(!regs.p.v)last_cycle(); if(!regs.p.v)last_cycle();
rd.l = op_readpc(); rd.l = op_readpc();
if(regs.p.v) { if(regs.p.v) {
aa.w = regs.pc.d + (int8)rd.l; aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w; regs.pc.w = aa.w;
} else { } else {
break; return;
} }
op_io_cond6(aa.w); op_io_cond6(aa.w);
last_cycle(); last_cycle();
op_io(); op_io();
} break; }
//bra void sCPU::op_bra() {
case 0x80: {
rd.l = op_readpc(); rd.l = op_readpc();
aa.w = regs.pc.d + (int8)rd.l; aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w; regs.pc.w = aa.w;
op_io_cond6(aa.w); op_io_cond6(aa.w);
last_cycle(); last_cycle();
op_io(); op_io();
} break; }
//brl void sCPU::op_brl() {
case 0x82: {
rd.l = op_readpc(); rd.l = op_readpc();
rd.h = op_readpc(); rd.h = op_readpc();
last_cycle(); last_cycle();
op_io(); op_io();
regs.pc.w = regs.pc.d + (int16)rd.w; regs.pc.w = regs.pc.d + (int16)rd.w;
} break; }
//jmp_addr void sCPU::op_jmp_addr() {
case 0x4c: {
rd.l = op_readpc(); rd.l = op_readpc();
last_cycle(); last_cycle();
rd.h = op_readpc(); rd.h = op_readpc();
regs.pc.w = rd.w; regs.pc.w = rd.w;
} break; }
//jmp_long void sCPU::op_jmp_long() {
case 0x5c: {
rd.l = op_readpc(); rd.l = op_readpc();
rd.h = op_readpc(); rd.h = op_readpc();
last_cycle(); last_cycle();
rd.b = op_readpc(); rd.b = op_readpc();
regs.pc.d = rd.d & 0xffffff; regs.pc.d = rd.d & 0xffffff;
} break; }
//jmp_iaddr void sCPU::op_jmp_iaddr() {
case 0x6c: {
aa.l = op_readpc(); aa.l = op_readpc();
aa.h = op_readpc(); aa.h = op_readpc();
rd.l = op_readaddr(aa.w); rd.l = op_readaddr(aa.w);
last_cycle(); last_cycle();
rd.h = op_readaddr(aa.w + 1); rd.h = op_readaddr(aa.w + 1);
regs.pc.w = rd.w; regs.pc.w = rd.w;
} break; }
//jmp_iaddrx void sCPU::op_jmp_iaddrx() {
case 0x7c: {
aa.l = op_readpc(); aa.l = op_readpc();
aa.h = op_readpc(); aa.h = op_readpc();
op_io(); op_io();
@@ -173,10 +159,9 @@ case 0x7c: {
last_cycle(); last_cycle();
rd.h = op_readpbr(aa.w + regs.x.w + 1); rd.h = op_readpbr(aa.w + regs.x.w + 1);
regs.pc.w = rd.w; regs.pc.w = rd.w;
} break; }
//jmp_iladdr void sCPU::op_jmp_iladdr() {
case 0xdc: {
aa.l = op_readpc(); aa.l = op_readpc();
aa.h = op_readpc(); aa.h = op_readpc();
rd.l = op_readaddr(aa.w); rd.l = op_readaddr(aa.w);
@@ -184,10 +169,9 @@ case 0xdc: {
last_cycle(); last_cycle();
rd.b = op_readaddr(aa.w + 2); rd.b = op_readaddr(aa.w + 2);
regs.pc.d = rd.d & 0xffffff; regs.pc.d = rd.d & 0xffffff;
} break; }
//jsr_addr void sCPU::op_jsr_addr() {
case 0x20: {
aa.l = op_readpc(); aa.l = op_readpc();
aa.h = op_readpc(); aa.h = op_readpc();
op_io(); op_io();
@@ -196,10 +180,9 @@ case 0x20: {
last_cycle(); last_cycle();
op_writestack(regs.pc.l); op_writestack(regs.pc.l);
regs.pc.w = aa.w; regs.pc.w = aa.w;
} break; }
//jsr_long void sCPU::op_jsr_long() {
case 0x22: {
aa.l = op_readpc(); aa.l = op_readpc();
aa.h = op_readpc(); aa.h = op_readpc();
op_writestackn(regs.pc.b); op_writestackn(regs.pc.b);
@@ -211,10 +194,9 @@ case 0x22: {
op_writestackn(regs.pc.l); op_writestackn(regs.pc.l);
regs.pc.d = aa.d & 0xffffff; regs.pc.d = aa.d & 0xffffff;
if(regs.e)regs.s.h = 0x01; if(regs.e)regs.s.h = 0x01;
} break; }
//jsr_iaddrx void sCPU::op_jsr_iaddrx() {
case 0xfc: {
aa.l = op_readpc(); aa.l = op_readpc();
op_writestackn(regs.pc.h); op_writestackn(regs.pc.h);
op_writestackn(regs.pc.l); op_writestackn(regs.pc.l);
@@ -225,10 +207,9 @@ case 0xfc: {
rd.h = op_readpbr(aa.w + regs.x.w + 1); rd.h = op_readpbr(aa.w + regs.x.w + 1);
regs.pc.w = rd.w; regs.pc.w = rd.w;
if(regs.e)regs.s.h = 0x01; if(regs.e)regs.s.h = 0x01;
} break; }
//rti void sCPU::op_rti() {
case 0x40: {
op_io(); op_io();
op_io(); op_io();
regs.p = op_readstack(); regs.p = op_readstack();
@@ -242,15 +223,14 @@ case 0x40: {
rd.h = op_readstack(); rd.h = op_readstack();
if(regs.e) { if(regs.e) {
regs.pc.w = rd.w; regs.pc.w = rd.w;
break; return;
} }
last_cycle(); last_cycle();
rd.b = op_readstack(); rd.b = op_readstack();
regs.pc.d = rd.d & 0xffffff; regs.pc.d = rd.d & 0xffffff;
} break; }
//rts void sCPU::op_rts() {
case 0x60: {
op_io(); op_io();
op_io(); op_io();
rd.l = op_readstack(); rd.l = op_readstack();
@@ -259,10 +239,9 @@ case 0x60: {
op_io(); op_io();
regs.pc.w = rd.w; regs.pc.w = rd.w;
regs.pc.w++; regs.pc.w++;
} break; }
//rtl void sCPU::op_rtl() {
case 0x6b: {
op_io(); op_io();
op_io(); op_io();
rd.l = op_readstackn(); rd.l = op_readstackn();
@@ -272,5 +251,5 @@ case 0x6b: {
regs.pc.d = rd.d & 0xffffff; regs.pc.d = rd.d & 0xffffff;
regs.pc.w++; regs.pc.w++;
if(regs.e)regs.s.h = 0x01; 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 void sCPU::op_inc() {
case 0x1a: {
last_cycle(); last_cycle();
op_io(); op_io();
if(regs.p.m) { if(regs.p.m) {
@@ -11,10 +10,9 @@ case 0x1a: {
regs.p.n = !!(regs.a.w & 0x8000); regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0); regs.p.z = (regs.a.w == 0);
} }
} break; }
//inx void sCPU::op_inx() {
case 0xe8: {
last_cycle(); last_cycle();
op_io(); op_io();
if(regs.p.x) { if(regs.p.x) {
@@ -26,10 +24,9 @@ case 0xe8: {
regs.p.n = !!(regs.x.w & 0x8000); regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0); regs.p.z = (regs.x.w == 0);
} }
} break; }
//iny void sCPU::op_iny() {
case 0xc8: {
last_cycle(); last_cycle();
op_io(); op_io();
if(regs.p.x) { if(regs.p.x) {
@@ -41,10 +38,9 @@ case 0xc8: {
regs.p.n = !!(regs.y.w & 0x8000); regs.p.n = !!(regs.y.w & 0x8000);
regs.p.z = (regs.y.w == 0); regs.p.z = (regs.y.w == 0);
} }
} break; }
//dec void sCPU::op_dec() {
case 0x3a: {
last_cycle(); last_cycle();
op_io(); op_io();
if(regs.p.m) { if(regs.p.m) {
@@ -56,10 +52,9 @@ case 0x3a: {
regs.p.n = !!(regs.a.w & 0x8000); regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0); regs.p.z = (regs.a.w == 0);
} }
} break; }
//dex void sCPU::op_dex() {
case 0xca: {
last_cycle(); last_cycle();
op_io(); op_io();
if(regs.p.x) { if(regs.p.x) {
@@ -71,10 +66,9 @@ case 0xca: {
regs.p.n = !!(regs.x.w & 0x8000); regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0); regs.p.z = (regs.x.w == 0);
} }
} break; }
//dey void sCPU::op_dey() {
case 0x88: {
last_cycle(); last_cycle();
op_io(); op_io();
if(regs.p.x) { if(regs.p.x) {
@@ -86,10 +80,9 @@ case 0x88: {
regs.p.n = !!(regs.y.w & 0x8000); regs.p.n = !!(regs.y.w & 0x8000);
regs.p.z = (regs.y.w == 0); regs.p.z = (regs.y.w == 0);
} }
} break; }
//asl void sCPU::op_asl() {
case 0x0a: {
last_cycle(); last_cycle();
op_io(); op_io();
if(regs.p.m) { if(regs.p.m) {
@@ -103,10 +96,9 @@ case 0x0a: {
regs.p.n = !!(regs.a.w & 0x8000); regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0); regs.p.z = (regs.a.w == 0);
} }
} break; }
//lsr void sCPU::op_lsr() {
case 0x4a: {
last_cycle(); last_cycle();
op_io(); op_io();
if(regs.p.m) { if(regs.p.m) {
@@ -120,10 +112,9 @@ case 0x4a: {
regs.p.n = !!(regs.a.w & 0x8000); regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0); regs.p.z = (regs.a.w == 0);
} }
} break; }
//rol void sCPU::op_rol() {
case 0x2a: {
last_cycle(); last_cycle();
op_io(); op_io();
uint16 c = regs.p.c; uint16 c = regs.p.c;
@@ -140,10 +131,9 @@ case 0x2a: {
regs.p.n = !!(regs.a.w & 0x8000); regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0); regs.p.z = (regs.a.w == 0);
} }
} break; }
//ror void sCPU::op_ror() {
case 0x6a: {
last_cycle(); last_cycle();
op_io(); op_io();
uint16 c; uint16 c;
@@ -162,10 +152,9 @@ case 0x6a: {
regs.p.n = !!(regs.a.w & 0x8000); regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0); regs.p.z = (regs.a.w == 0);
} }
} break; }
//inc_addr void sCPU::op_inc_addr() {
case 0xee: {
aa.l = op_readpc(); aa.l = op_readpc();
aa.h = op_readpc(); aa.h = op_readpc();
rd.l = op_readdbr(aa.w); rd.l = op_readdbr(aa.w);
@@ -176,10 +165,9 @@ case 0xee: {
op_writedbr(aa.w + 1, rd.h); } op_writedbr(aa.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedbr(aa.w, rd.l); op_writedbr(aa.w, rd.l);
} break; }
//dec_addr void sCPU::op_dec_addr() {
case 0xce: {
aa.l = op_readpc(); aa.l = op_readpc();
aa.h = op_readpc(); aa.h = op_readpc();
rd.l = op_readdbr(aa.w); rd.l = op_readdbr(aa.w);
@@ -190,10 +178,9 @@ case 0xce: {
op_writedbr(aa.w + 1, rd.h); } op_writedbr(aa.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedbr(aa.w, rd.l); op_writedbr(aa.w, rd.l);
} break; }
//asl_addr void sCPU::op_asl_addr() {
case 0x0e: {
aa.l = op_readpc(); aa.l = op_readpc();
aa.h = op_readpc(); aa.h = op_readpc();
rd.l = op_readdbr(aa.w); rd.l = op_readdbr(aa.w);
@@ -204,10 +191,9 @@ case 0x0e: {
op_writedbr(aa.w + 1, rd.h); } op_writedbr(aa.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedbr(aa.w, rd.l); op_writedbr(aa.w, rd.l);
} break; }
//lsr_addr void sCPU::op_lsr_addr() {
case 0x4e: {
aa.l = op_readpc(); aa.l = op_readpc();
aa.h = op_readpc(); aa.h = op_readpc();
rd.l = op_readdbr(aa.w); rd.l = op_readdbr(aa.w);
@@ -218,10 +204,9 @@ case 0x4e: {
op_writedbr(aa.w + 1, rd.h); } op_writedbr(aa.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedbr(aa.w, rd.l); op_writedbr(aa.w, rd.l);
} break; }
//rol_addr void sCPU::op_rol_addr() {
case 0x2e: {
aa.l = op_readpc(); aa.l = op_readpc();
aa.h = op_readpc(); aa.h = op_readpc();
rd.l = op_readdbr(aa.w); rd.l = op_readdbr(aa.w);
@@ -232,10 +217,9 @@ case 0x2e: {
op_writedbr(aa.w + 1, rd.h); } op_writedbr(aa.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedbr(aa.w, rd.l); op_writedbr(aa.w, rd.l);
} break; }
//ror_addr void sCPU::op_ror_addr() {
case 0x6e: {
aa.l = op_readpc(); aa.l = op_readpc();
aa.h = op_readpc(); aa.h = op_readpc();
rd.l = op_readdbr(aa.w); rd.l = op_readdbr(aa.w);
@@ -246,10 +230,9 @@ case 0x6e: {
op_writedbr(aa.w + 1, rd.h); } op_writedbr(aa.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedbr(aa.w, rd.l); op_writedbr(aa.w, rd.l);
} break; }
//trb_addr void sCPU::op_trb_addr() {
case 0x1c: {
aa.l = op_readpc(); aa.l = op_readpc();
aa.h = op_readpc(); aa.h = op_readpc();
rd.l = op_readdbr(aa.w); rd.l = op_readdbr(aa.w);
@@ -260,10 +243,9 @@ case 0x1c: {
op_writedbr(aa.w + 1, rd.h); } op_writedbr(aa.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedbr(aa.w, rd.l); op_writedbr(aa.w, rd.l);
} break; }
//tsb_addr void sCPU::op_tsb_addr() {
case 0x0c: {
aa.l = op_readpc(); aa.l = op_readpc();
aa.h = op_readpc(); aa.h = op_readpc();
rd.l = op_readdbr(aa.w); rd.l = op_readdbr(aa.w);
@@ -274,10 +256,9 @@ case 0x0c: {
op_writedbr(aa.w + 1, rd.h); } op_writedbr(aa.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedbr(aa.w, rd.l); op_writedbr(aa.w, rd.l);
} break; }
//inc_addrx void sCPU::op_inc_addrx() {
case 0xfe: {
aa.l = op_readpc(); aa.l = op_readpc();
aa.h = op_readpc(); aa.h = op_readpc();
op_io(); op_io();
@@ -289,10 +270,9 @@ case 0xfe: {
op_writedbr(aa.w + regs.x.w + 1, rd.h); } op_writedbr(aa.w + regs.x.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedbr(aa.w + regs.x.w, rd.l); op_writedbr(aa.w + regs.x.w, rd.l);
} break; }
//dec_addrx void sCPU::op_dec_addrx() {
case 0xde: {
aa.l = op_readpc(); aa.l = op_readpc();
aa.h = op_readpc(); aa.h = op_readpc();
op_io(); op_io();
@@ -304,10 +284,9 @@ case 0xde: {
op_writedbr(aa.w + regs.x.w + 1, rd.h); } op_writedbr(aa.w + regs.x.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedbr(aa.w + regs.x.w, rd.l); op_writedbr(aa.w + regs.x.w, rd.l);
} break; }
//asl_addrx void sCPU::op_asl_addrx() {
case 0x1e: {
aa.l = op_readpc(); aa.l = op_readpc();
aa.h = op_readpc(); aa.h = op_readpc();
op_io(); op_io();
@@ -319,10 +298,9 @@ case 0x1e: {
op_writedbr(aa.w + regs.x.w + 1, rd.h); } op_writedbr(aa.w + regs.x.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedbr(aa.w + regs.x.w, rd.l); op_writedbr(aa.w + regs.x.w, rd.l);
} break; }
//lsr_addrx void sCPU::op_lsr_addrx() {
case 0x5e: {
aa.l = op_readpc(); aa.l = op_readpc();
aa.h = op_readpc(); aa.h = op_readpc();
op_io(); op_io();
@@ -334,10 +312,9 @@ case 0x5e: {
op_writedbr(aa.w + regs.x.w + 1, rd.h); } op_writedbr(aa.w + regs.x.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedbr(aa.w + regs.x.w, rd.l); op_writedbr(aa.w + regs.x.w, rd.l);
} break; }
//rol_addrx void sCPU::op_rol_addrx() {
case 0x3e: {
aa.l = op_readpc(); aa.l = op_readpc();
aa.h = op_readpc(); aa.h = op_readpc();
op_io(); op_io();
@@ -349,10 +326,9 @@ case 0x3e: {
op_writedbr(aa.w + regs.x.w + 1, rd.h); } op_writedbr(aa.w + regs.x.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedbr(aa.w + regs.x.w, rd.l); op_writedbr(aa.w + regs.x.w, rd.l);
} break; }
//ror_addrx void sCPU::op_ror_addrx() {
case 0x7e: {
aa.l = op_readpc(); aa.l = op_readpc();
aa.h = op_readpc(); aa.h = op_readpc();
op_io(); op_io();
@@ -364,10 +340,9 @@ case 0x7e: {
op_writedbr(aa.w + regs.x.w + 1, rd.h); } op_writedbr(aa.w + regs.x.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedbr(aa.w + regs.x.w, rd.l); op_writedbr(aa.w + regs.x.w, rd.l);
} break; }
//inc_dp void sCPU::op_inc_dp() {
case 0xe6: {
dp = op_readpc(); dp = op_readpc();
op_io_cond2(); op_io_cond2();
rd.l = op_readdp(dp); rd.l = op_readdp(dp);
@@ -378,10 +353,9 @@ case 0xe6: {
op_writedp(dp + 1, rd.h); } op_writedp(dp + 1, rd.h); }
last_cycle(); last_cycle();
op_writedp(dp, rd.l); op_writedp(dp, rd.l);
} break; }
//dec_dp void sCPU::op_dec_dp() {
case 0xc6: {
dp = op_readpc(); dp = op_readpc();
op_io_cond2(); op_io_cond2();
rd.l = op_readdp(dp); rd.l = op_readdp(dp);
@@ -392,10 +366,9 @@ case 0xc6: {
op_writedp(dp + 1, rd.h); } op_writedp(dp + 1, rd.h); }
last_cycle(); last_cycle();
op_writedp(dp, rd.l); op_writedp(dp, rd.l);
} break; }
//asl_dp void sCPU::op_asl_dp() {
case 0x06: {
dp = op_readpc(); dp = op_readpc();
op_io_cond2(); op_io_cond2();
rd.l = op_readdp(dp); rd.l = op_readdp(dp);
@@ -406,10 +379,9 @@ case 0x06: {
op_writedp(dp + 1, rd.h); } op_writedp(dp + 1, rd.h); }
last_cycle(); last_cycle();
op_writedp(dp, rd.l); op_writedp(dp, rd.l);
} break; }
//lsr_dp void sCPU::op_lsr_dp() {
case 0x46: {
dp = op_readpc(); dp = op_readpc();
op_io_cond2(); op_io_cond2();
rd.l = op_readdp(dp); rd.l = op_readdp(dp);
@@ -420,10 +392,9 @@ case 0x46: {
op_writedp(dp + 1, rd.h); } op_writedp(dp + 1, rd.h); }
last_cycle(); last_cycle();
op_writedp(dp, rd.l); op_writedp(dp, rd.l);
} break; }
//rol_dp void sCPU::op_rol_dp() {
case 0x26: {
dp = op_readpc(); dp = op_readpc();
op_io_cond2(); op_io_cond2();
rd.l = op_readdp(dp); rd.l = op_readdp(dp);
@@ -434,10 +405,9 @@ case 0x26: {
op_writedp(dp + 1, rd.h); } op_writedp(dp + 1, rd.h); }
last_cycle(); last_cycle();
op_writedp(dp, rd.l); op_writedp(dp, rd.l);
} break; }
//ror_dp void sCPU::op_ror_dp() {
case 0x66: {
dp = op_readpc(); dp = op_readpc();
op_io_cond2(); op_io_cond2();
rd.l = op_readdp(dp); rd.l = op_readdp(dp);
@@ -448,10 +418,9 @@ case 0x66: {
op_writedp(dp + 1, rd.h); } op_writedp(dp + 1, rd.h); }
last_cycle(); last_cycle();
op_writedp(dp, rd.l); op_writedp(dp, rd.l);
} break; }
//trb_dp void sCPU::op_trb_dp() {
case 0x14: {
dp = op_readpc(); dp = op_readpc();
op_io_cond2(); op_io_cond2();
rd.l = op_readdp(dp); rd.l = op_readdp(dp);
@@ -462,10 +431,9 @@ case 0x14: {
op_writedp(dp + 1, rd.h); } op_writedp(dp + 1, rd.h); }
last_cycle(); last_cycle();
op_writedp(dp, rd.l); op_writedp(dp, rd.l);
} break; }
//tsb_dp void sCPU::op_tsb_dp() {
case 0x04: {
dp = op_readpc(); dp = op_readpc();
op_io_cond2(); op_io_cond2();
rd.l = op_readdp(dp); rd.l = op_readdp(dp);
@@ -476,10 +444,9 @@ case 0x04: {
op_writedp(dp + 1, rd.h); } op_writedp(dp + 1, rd.h); }
last_cycle(); last_cycle();
op_writedp(dp, rd.l); op_writedp(dp, rd.l);
} break; }
//inc_dpx void sCPU::op_inc_dpx() {
case 0xf6: {
dp = op_readpc(); dp = op_readpc();
op_io_cond2(); op_io_cond2();
op_io(); op_io();
@@ -491,10 +458,9 @@ case 0xf6: {
op_writedp(dp + regs.x.w + 1, rd.h); } op_writedp(dp + regs.x.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedp(dp + regs.x.w, rd.l); op_writedp(dp + regs.x.w, rd.l);
} break; }
//dec_dpx void sCPU::op_dec_dpx() {
case 0xd6: {
dp = op_readpc(); dp = op_readpc();
op_io_cond2(); op_io_cond2();
op_io(); op_io();
@@ -506,10 +472,9 @@ case 0xd6: {
op_writedp(dp + regs.x.w + 1, rd.h); } op_writedp(dp + regs.x.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedp(dp + regs.x.w, rd.l); op_writedp(dp + regs.x.w, rd.l);
} break; }
//asl_dpx void sCPU::op_asl_dpx() {
case 0x16: {
dp = op_readpc(); dp = op_readpc();
op_io_cond2(); op_io_cond2();
op_io(); op_io();
@@ -521,10 +486,9 @@ case 0x16: {
op_writedp(dp + regs.x.w + 1, rd.h); } op_writedp(dp + regs.x.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedp(dp + regs.x.w, rd.l); op_writedp(dp + regs.x.w, rd.l);
} break; }
//lsr_dpx void sCPU::op_lsr_dpx() {
case 0x56: {
dp = op_readpc(); dp = op_readpc();
op_io_cond2(); op_io_cond2();
op_io(); op_io();
@@ -536,10 +500,9 @@ case 0x56: {
op_writedp(dp + regs.x.w + 1, rd.h); } op_writedp(dp + regs.x.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedp(dp + regs.x.w, rd.l); op_writedp(dp + regs.x.w, rd.l);
} break; }
//rol_dpx void sCPU::op_rol_dpx() {
case 0x36: {
dp = op_readpc(); dp = op_readpc();
op_io_cond2(); op_io_cond2();
op_io(); op_io();
@@ -551,10 +514,9 @@ case 0x36: {
op_writedp(dp + regs.x.w + 1, rd.h); } op_writedp(dp + regs.x.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedp(dp + regs.x.w, rd.l); op_writedp(dp + regs.x.w, rd.l);
} break; }
//ror_dpx void sCPU::op_ror_dpx() {
case 0x76: {
dp = op_readpc(); dp = op_readpc();
op_io_cond2(); op_io_cond2();
op_io(); op_io();
@@ -566,5 +528,5 @@ case 0x76: {
op_writedp(dp + regs.x.w + 1, rd.h); } op_writedp(dp + regs.x.w + 1, rd.h); }
last_cycle(); last_cycle();
op_writedp(dp + regs.x.w, rd.l); op_writedp(dp + regs.x.w, rd.l);
} break; }

View File

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

View File

@@ -19,19 +19,19 @@ uint8 r;
(abus & 0x40ffff) == 0x420b || (abus & 0x40ffff) == 0x420c) { (abus & 0x40ffff) == 0x420b || (abus & 0x40ffff) == 0x420c) {
r = regs.mdr; r = regs.mdr;
} else { } else {
r = r_mem->read(abus); r = bus.read(abus);
} }
r_mem->write(0x2100 | bbus, r); bus.write(0x2100 | bbus, r);
} else { //b->a } else { //b->a
if(bbus == 0x80 && ((abus & 0x7e0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000)) { if(bbus == 0x80 && ((abus & 0x7e0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000)) {
//prevent WRAM->WRAM transfers //prevent WRAM->WRAM transfers
r = regs.mdr; r = regs.mdr;
} else { } else {
r = r_mem->read(0x2100 | bbus); r = bus.read(0x2100 | bbus);
} }
if((abus & 0x40ff00) == 0x2100 || (abus & 0x40ff80) == 0x4300 || if((abus & 0x40ff00) == 0x2100 || (abus & 0x40ff80) == 0x4300 ||
(abus & 0x40ffff) == 0x420b || (abus & 0x40ffff) == 0x420c)return; (abus & 0x40ffff) == 0x420b || (abus & 0x40ffff) == 0x420c)return;
r_mem->write(abus, r); bus.write(abus, r);
} }
dma_add_clocks(8); dma_add_clocks(8);
@@ -83,8 +83,8 @@ inline uint32 sCPU::hdma_iaddr(uint8 i) {
*****/ *****/
void sCPU::dma_transfertobusb(uint8 i, uint8 bbus) { void sCPU::dma_transfertobusb(uint8 i, uint8 bbus) {
if(cartridge.info.sdd1 == true && sdd1->dma_active() == true) { if(cartridge.info.sdd1 == true && sdd1.dma_active() == true) {
r_mem->write(0x2100 | bbus, sdd1->dma_read()); bus.write(0x2100 | bbus, sdd1.dma_read());
} else { } else {
dma_transfer(0, bbus, dma_addr(i)); dma_transfer(0, bbus, dma_addr(i));
} }
@@ -111,8 +111,7 @@ void sCPU::dma_run() {
dma_add_clocks(8); dma_add_clocks(8);
if(cartridge.info.sdd1 == true) { if(cartridge.info.sdd1 == true) {
sdd1->dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr), sdd1.dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr), channel[i].xfersize);
channel[i].xfersize);
} }
if(tracer.enabled() == true && tracer.cpudma_enabled() == true) { if(tracer.enabled() == true && tracer.cpudma_enabled() == true) {
@@ -168,19 +167,19 @@ uint8 r = 0;
} }
void sCPU::hdma_update(uint8 i) { void sCPU::hdma_update(uint8 i) {
channel[i].hdma_line_counter = r_mem->read(hdma_addr(i)); channel[i].hdma_line_counter = bus.read(hdma_addr(i));
dma_add_clocks(8); dma_add_clocks(8);
channel[i].hdma_completed = (channel[i].hdma_line_counter == 0); channel[i].hdma_completed = (channel[i].hdma_line_counter == 0);
channel[i].hdma_do_transfer = !channel[i].hdma_completed; channel[i].hdma_do_transfer = !channel[i].hdma_completed;
if(channel[i].hdma_indirect) { if(channel[i].hdma_indirect) {
channel[i].hdma_iaddr = r_mem->read(hdma_addr(i)) << 8; channel[i].hdma_iaddr = bus.read(hdma_addr(i)) << 8;
dma_add_clocks(8); dma_add_clocks(8);
if(!channel[i].hdma_completed || hdma_active_after(i)) { if(!channel[i].hdma_completed || hdma_active_after(i)) {
channel[i].hdma_iaddr >>= 8; channel[i].hdma_iaddr >>= 8;
channel[i].hdma_iaddr |= r_mem->read(hdma_addr(i)) << 8; channel[i].hdma_iaddr |= bus.read(hdma_addr(i)) << 8;
dma_add_clocks(8); dma_add_clocks(8);
} }
} }

View File

@@ -14,21 +14,21 @@ void sCPU::op_io() {
} }
uint8 sCPU::op_read(uint32 addr) { uint8 sCPU::op_read(uint32 addr) {
status.clock_count = r_mem->speed(addr); status.clock_count = bus.speed(addr);
precycle_edge(); precycle_edge();
add_clocks(status.clock_count - 4); add_clocks(status.clock_count - 4);
regs.mdr = r_mem->read(addr); regs.mdr = bus.read(addr);
add_clocks(4); add_clocks(4);
cycle_edge(); cycle_edge();
return regs.mdr; return regs.mdr;
} }
void sCPU::op_write(uint32 addr, uint8 data) { void sCPU::op_write(uint32 addr, uint8 data) {
status.clock_count = r_mem->speed(addr); status.clock_count = bus.speed(addr);
precycle_edge(); precycle_edge();
add_clocks(status.clock_count); add_clocks(status.clock_count);
regs.mdr = data; regs.mdr = data;
r_mem->write(addr, regs.mdr); bus.write(addr, regs.mdr);
cycle_edge(); cycle_edge();
} }

View File

@@ -4,14 +4,14 @@ uint8 sCPU::pio_status() {
//WMDATA //WMDATA
uint8 sCPU::mmio_r2180() { uint8 sCPU::mmio_r2180() {
uint8 r = r_mem->read(0x7e0000 | status.wram_addr); uint8 r = bus.read(0x7e0000 | status.wram_addr);
status.wram_addr = (status.wram_addr + 1) & 0x01ffff; status.wram_addr = (status.wram_addr + 1) & 0x01ffff;
return r; return r;
} }
//WMDATA //WMDATA
void sCPU::mmio_w2180(uint8 data) { void sCPU::mmio_w2180(uint8 data) {
r_mem->write(0x7e0000 | status.wram_addr, data); bus.write(0x7e0000 | status.wram_addr, data);
status.wram_addr = (status.wram_addr + 1) & 0x01ffff; status.wram_addr = (status.wram_addr + 1) & 0x01ffff;
} }
@@ -76,7 +76,7 @@ void sCPU::mmio_w4200(uint8 data) {
//WRIO //WRIO
void sCPU::mmio_w4201(uint8 data) { void sCPU::mmio_w4201(uint8 data) {
if((status.pio & 0x80) && !(data & 0x80)) { if((status.pio & 0x80) && !(data & 0x80)) {
r_ppu->latch_counters(); ppu.latch_counters();
} }
status.pio = data; status.pio = data;
} }
@@ -159,7 +159,7 @@ void sCPU::mmio_w420c(uint8 data) {
//MEMSEL //MEMSEL
void sCPU::mmio_w420d(uint8 data) { void sCPU::mmio_w420d(uint8 data) {
r_mem->set_speed(data & 1); bus.set_speed(data & 1);
} }
//RDNMI //RDNMI
@@ -419,11 +419,13 @@ void sCPU::mmio_reset() {
status.joy4h = 0x00; status.joy4h = 0x00;
} }
uint8 sCPU::mmio_read(uint16 addr) { uint8 sCPU::mmio_read(uint addr) {
addr &= 0xffff;
//APU //APU
if((addr & 0xffc0) == 0x2140) { //$2140-$217f if((addr & 0xffc0) == 0x2140) { //$2140-$217f
scheduler.sync_cpusmp(); scheduler.sync_cpusmp();
return r_smp->port_read(addr & 3); return smp.port_read(addr & 3);
} }
//DMA //DMA
@@ -474,7 +476,9 @@ uint8 sCPU::mmio_read(uint16 addr) {
return regs.mdr; return regs.mdr;
} }
void sCPU::mmio_write(uint16 addr, uint8 data) { void sCPU::mmio_write(uint addr, uint8 data) {
addr &= 0xffff;
//APU //APU
if((addr & 0xffc0) == 0x2140) { //$2140-$217f if((addr & 0xffc0) == 0x2140) { //$2140-$217f
scheduler.sync_cpusmp(); scheduler.sync_cpusmp();

View File

@@ -1,7 +1,7 @@
void mmio_power(); void mmio_power();
void mmio_reset(); void mmio_reset();
uint8 mmio_read (uint16 addr); uint8 mmio_read (uint addr);
void mmio_write(uint16 addr, uint8 data); void mmio_write(uint addr, uint8 data);
uint8 pio_status(); uint8 pio_status();

View File

@@ -21,8 +21,8 @@ void sCPU::power() {
void sCPU::reset() { void sCPU::reset() {
regs.pc.d = 0x000000; regs.pc.d = 0x000000;
regs.pc.l = r_mem->read(0xfffc); regs.pc.l = bus.read(0xfffc);
regs.pc.h = r_mem->read(0xfffd); regs.pc.h = bus.read(0xfffd);
//note: some registers are not fully reset by SNES //note: some registers are not fully reset by SNES
regs.x.h = 0x00; regs.x.h = 0x00;
@@ -48,5 +48,9 @@ void sCPU::reset() {
apu_port[3] = 0x00; 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 { class sCPU : public CPU { public:
public:
void enter(); void enter();
public:
#include "core/core.h" #include "core/core.h"
#include "dma/dma.h" #include "dma/dma.h"
#include "memory/memory.h" #include "memory/memory.h"

View File

@@ -90,7 +90,7 @@ void sCPU::scanline() {
status.line_rendered = false; status.line_rendered = false;
status.hdma_triggered = (status.vcounter <= (!overscan() ? 224 : 239)) ? false : true; status.hdma_triggered = (status.vcounter <= (!overscan() ? 224 : 239)) ? false : true;
r_ppu->scanline(); ppu.scanline();
snes.scanline(); snes.scanline();
update_interrupts(); update_interrupts();
@@ -117,7 +117,7 @@ void sCPU::frame() {
status.hdmainit_trigger_position = 12 + dma_counter(); status.hdmainit_trigger_position = 12 + dma_counter();
} }
r_ppu->frame(); ppu.frame();
snes.frame(); snes.frame();
} }
@@ -143,7 +143,7 @@ void sCPU::cycle_edge() {
if(status.line_rendered == false) { if(status.line_rendered == false) {
if(status.hclock >= status.line_render_position) { if(status.hclock >= status.line_render_position) {
status.line_rendered = true; status.line_rendered = true;
r_ppu->render_scanline(); ppu.render_scanline();
} }
} }
@@ -172,7 +172,7 @@ void sCPU::cycle_edge() {
status.hdmainit_triggered = true; status.hdmainit_triggered = true;
hdma_init_reset(); hdma_init_reset();
if(hdma_enabled_channels()) { if(hdma_enabled_channels()) {
add_clocks(12); add_clocks(18);
hdma_init(); hdma_init();
//if(status.dma_state == DMASTATE_INACTIVE) { //if(status.dma_state == DMASTATE_INACTIVE) {
// status.dma_state = DMASTATE_DMASYNC; // status.dma_state = DMASTATE_DMASYNC;
@@ -188,7 +188,7 @@ void sCPU::cycle_edge() {
if(status.hclock >= 1106) { if(status.hclock >= 1106) {
status.hdma_triggered = true; status.hdma_triggered = true;
if(hdma_active_channels()) { if(hdma_active_channels()) {
add_clocks(12); add_clocks(18);
hdma_run(); hdma_run();
//if(status.dma_state == DMASTATE_INACTIVE) { //if(status.dma_state == DMASTATE_INACTIVE) {
// status.dma_state = DMASTATE_DMASYNC; // status.dma_state = DMASTATE_DMASYNC;
@@ -250,7 +250,7 @@ void sCPU::timing_reset() {
status.prev_line_clocks = 1364; status.prev_line_clocks = 1364;
status.line_rendered = false; 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_refreshed = false;
status.dram_refresh_position = (cpu_version == 1) ? 530 : 538; status.dram_refresh_position = (cpu_version == 1) ? 530 : 538;
@@ -283,7 +283,7 @@ void sCPU::timing_reset() {
//initial latch values for $213c/$213d //initial latch values for $213c/$213d
//[x]0035 : [y]0000 (53.0 -> 212) [lda $2137] //[x]0035 : [y]0000 (53.0 -> 212) [lda $2137]
//[x]0038 : [y]0000 (56.5 -> 226) [nop : 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 #undef ntsc_color_burst_phase_shift_scanline

BIN
src/data/bsnes.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

BIN
src/doc/base.dia Normal file

Binary file not shown.

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, 0x0000, 0x000F, 0x0014, 0x0018, 0x001E, 0x0028, 0x0030, 0x003C,
0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180, 0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180,
0x01E0, 0x0280, 0x0300, 0x03C0, 0x0500, 0x0600, 0x0780, 0x0A00, 0x01E0, 0x0280, 0x0300, 0x03C0, 0x0500, 0x0600, 0x0780, 0x0A00,
0x0C00, 0x0F00, 0x1400, 0x1800, 0x1E00, 0x2800, 0x3C00, 0x7800 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,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001,

File diff suppressed because it is too large Load Diff

View File

@@ -1,171 +1,172 @@
class bDSP : public DSP { 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: public:
static const uint16 RateTable[32]; void enter();
static const int16 GaussTable[512];
enum EnvelopeStates { uint8 read( uint8 addr );
ATTACK, void write( uint8 addr, uint8 data );
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];
public:
uint8 read (uint8 addr);
void write(uint8 addr, uint8 data);
void power(); void power();
void reset(); void reset();
uint32 run();
bDSP(); bDSP();
~bDSP(); ~bDSP();
template<int n, typename T> inline T asr(const T x) {
enum { bits = (sizeof(T) << 3) - n };
return sclip<bits>(x >> n);
}
public:
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 );
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;
}
}

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