Compare commits

..

12 Commits
v072 ... v073

Author SHA1 Message Date
Tim Allen
6ea4bc031f Update to v073 release.
byuu says:

This release marks a major step forward, offering full low-level
emulation of all four DSP coprocessors based on the NEC uPD77C25
processor core. Many people were responsible for this milestone: Dr.
Decapitator for the actual decapping and extraction; Lord Nightmare for
the cartridges and some special analysis tools; myself, Jonas Quinn and
Cydrak for the uPD77C25 emulation; and all of the donors who raised the
necessary $1,000 for the necessary hardware and equipment needed to pull
this all off. To say thanks to the donors, I am releasing the uPD77C25
emulation core to the public domain, so that everyone can benefit from
it.

All four DSP emulations will be improved by this by way of having
realistic timing; the DSP-4 will benefit further as the high-level
emulation was incomplete and somewhat buggy; and the DSP-3 will benefit
the most as the high-levle emulation there was not complete enough to be
playable. As a result, most notably, this means bsnes v073 is the first
emulator to fully be able to play SD Gundam GX (J)!

As bsnes' primary goal is accuracy, the LLE DSP support renders the old
HLE DSP support obsolete. Ergo, I have removed the 166KB of HLE source
code, and replaced it with the uPD77C25 core, which comprises a mere
20KB of source code. As this LLE module supports save states, this also
means that for the first time, DSP-3 and DSP-4 games have save state
support.

On the other hand, this also means that to run any DSP game, you will
need the appropriate program ROM. As these are copyrighted, I cannot
distribute them nor tell you where to get them. All I can do is provide
you with the necessary filenames and hashes.

Changelog (since v072 release):
* added NEC uPD77C25 emulation core
* added low-level emulation of the DSP-1, DSP-1B, DSP-2, DSP-3, DSP-4
  coprocessors
* removed high-level emulation of the DSP-n coprocessors
* added blargg's libco::ppc.c module, which is far more portable, even
  running on the PS3
* added software filter support via binary plugins
* added debugger (currently Linux-only); but it is as yet unstable
* added pause shortcut
* updated mightymo's cheat code database
2010-12-26 23:24:34 +11:00
Tim Allen
676a3adbf7 Update to v072r14 release.
byuu says:

Changelog:
* added SNES::interface.message(const string&) so that the core can send
  messages for the GUI to display
* failing to load a DSP-n ROM, or failing the DSP-n SHA256 hash (if
  there is one) will result in a warning message
* all DSP-1 games by default once again use the DSP-1B program, now that
  it has been redumped and reverified
* fixed bugs in uPD77C25 SHL2 and SHL4 opcodes; fixes DSP-2 and DSP-4
  emulation
* removed all DSP HLE (DSP-1, DSP-2, DSP-3, DSP-4)
* as a result of LLE, DSP-3 and DSP-4 games can now load and save states
2010-12-26 23:11:31 +11:00
Tim Allen
b27e0a719d Update to v072r13 release.
byuu says:

The DSP-1 and DSP-3 emulation appears to be great.
However, there are bugs in the other two.
DSP-2, Dungeon Master: the graphics in-game appear corrupt. It looks
like the first two pixels have the right color, the next six have the
wrong color, resulting in vertical stripes.
DSP-4, Top Gear 3000: the car sprites appear to be showing 8x8 tiles
instead of 16x16 files, resulting in 3/4ths of the cars being invisible,
but only up close.
Dr. Decapitator and Lord Nightmare are supremely confident that our
dumps are 100% accurate, there was no bus wavering at all this time.
We believe they are bugs in the uPD77C25 emulation.
I desperately need help! I have spent the past several hours trying to
ascertain what the problem is, to no avail.
I've tried messing with just about every flag, every register, checking
for use of OV1, S1, custom opcodes, etc ... I am having no luck.
I'm going to keep trying with even more sophisticated cross-analysis.
But Cydrak, if you would please rework that magic of yours, I'd be
eternally grateful :D
2010-12-26 23:08:43 +11:00
Tim Allen
a62aa94b65 Update to v072r12 release.
byuu says:

This release defaults DSP-3 loading to use the uPD77C25 core. It also
pre-emptively does the same for the DSP-2 and DSP-4. v072r11 did this
for the DSP-1.

I've also renamed my string<>integer conversion function names:

strhex -> hex
strsigned -> integer
strunsigned -> decimal
strbin -> binary
strdouble -> fp (this one will no doubt be trouble since 'file fp' is
    a common idiom. floatingpoint is too long, float and double are
    already reserved.)
2010-12-23 01:13:14 +11:00
Tim Allen
9762a092d2 Update to v072r11 release.
A number of changes in this release were contributed by Cydrak in the
WIP thread, who described his changes from r09/r10 thusly:

- Call cpu.synchronize_coprocessor() on external R/W to avoid missing data
- Sign-extend K, L before multiplying
- Load IDB before ALU. Supports the MOV A, d; XOR A, A idiom which is
  all over the place
- Use 16-bit types in flag checks (notably Z)
- Flags mostly unified; hopefully at least OV0 and SGN work
- Carry-in comes from the *other* accumulator's flags, this is used for
  long arithmetic
- CMP is ~q (see the many CMP A; INC A where values get negated)
- SHR1 is arithmetic shift and retains the sign bit (Mario Kart sprites
  and physics are broken without it)
- SHL1 has carry-in per the datasheet, it doesn't seem to be used though
- XCHG probably byteswaps, but it's not used either
- Reversed DR external R/W order again, big-endian seems to break it

byuu described the remaining changes:

You do not need the XML files anymore, bsnes will automatically choose
the new uPD module, and look for dsp1b.bin.
If you make your own XML file, you can force the old HLE mode, or use
a differently-named PROM.
If and when we get the DSP-2,3,4 modules, bsnes v072.11 and above should
already be able to run them, assuming no more emulation core bugs.
2010-12-23 01:07:36 +11:00
Tim Allen
05526571e7 Update to v072r10 release.
byuu says:

Current code.
2010-12-23 01:05:21 +11:00
Tim Allen
3bd29088d1 Update to v072r09 release.
Unfortunately, I missed the v072r08 release; it was taken down before
I saw the announcement.

byuu says (about v072r08):

This WIP adds NEC uPD77C25 emulation. Unfortunately it's not at all functional yet, there are way too many things I don't understand about the chip.
I'm absolutely going to need help to complete this.

[...]

For now, you need the included PCB XML to manually map the program/data ROM in, which are included with the archive. You'll have to rewrite the map yourself to run other DSP-1 games, unless they have the same layout as Mario Kart. I am using the US [!] version, name it mariokart.sfc and put all the archive files and the ROM together.

From here, bsnes will load up the ROMs, and start executing instructions. Since the emulation is so incomplete, it just deadlocks on the "Nintendo" logo as if there were no DSP on the cart at all, but if you enable tracing, you'll see it actually starts doing a lot of stuff before getting stuck in a really long and confusing loop.

[Note: the DSP-1B program and data ROMs are not included in this commit.
The PCB XML file mentioned above looks like this:

<?xml version='1.0' encoding='UTF-8'?>
<cartridge region='NTSC'>
  <rom>
    <map mode='shadow' address='00-3f:8000-ffff'/>
    <map mode='linear' address='40-7f:0000-ffff'/>
    <map mode='shadow' address='80-bf:8000-ffff'/>
    <map mode='linear' address='c0-ff:0000-ffff'/>
  </rom>
  <ram size='800'>
    <map mode='linear' address='20-3f:6000-7fff'/>
    <map mode='linear' address='a0-bf:6000-7fff'/>
    <map mode='linear' address='70-7f:0000-ffff'/>
  </ram>
  <upd77c25 program="dsp1b-program.bin" data="dsp1b-data.bin">
    <dr>
      <map address='00-1f:6000-6fff'/>
      <map address='80-9f:6000-6fff'/>
    </dr>
    <sr>
      <map address='00-1f:7000-7fff'/>
      <map address='80-9f:7000-7fff'/>
    </sr>
  </upd77c25>
</cartridge>

Save it as 'mariokart.xml']

byuu says (about v072r09):

Fixes OP/LD RQM=1 on DR modify, Mario Kart can get in-game, but the
track is completely corrupted.
Reorders order of operations for OP, in an attempt to mimic parallelism.
Added support for OP KLM DST.
Added S1 flag setting, probably not correct.
2010-12-17 21:54:28 +11:00
Tim Allen
26643a43de Update to v070r07 release.
byuu says:

I'm happy enough with the debugger now. Not 100% up to par with the old
one, but it also does some new things the old one didn't.
- step into / step over are disabled unless they can be done safely
- this means step over is usually grayed unless you hit step into first,
  due to bsnes not being opcode-based (you can't skip an opcode that is
  half-executed)
- you can now trace console output to disk
- stepping the CPU will print stepped SMP opcodes if the checkbox for it
  is on and vice versa
- button added to clear the console log
2010-11-03 00:08:00 +11:00
Tim Allen
7e8958b102 Update to v072r06 release.
(there was no r05 release posted to the WIP thread)

byuu says:

Updated libsnes to use new file and function names.
Also added EditBox::setCursorPosition for GTK+ and Qt, only used by the
debugger so far so that when text is added, it auto-scrolls to the
bottom.
2010-11-01 23:00:46 +11:00
Tim Allen
edac93b800 Update to v072r04 release.
(there was no r03 release posted to the WIP thread)

byuu says:

nall/snes/smp.hpp created, ~68 addressing modes compared to the CPU's
~27, ugh. All hooked up, you can step into / step over / trace the S-SMP
now as well.
2010-10-30 19:18:43 +11:00
Tim Allen
0730f847e5 Update to v072r02 release.
byuu says:

Just debugger work here. About three or four hours to write
nall/snes/cpu.hpp, which is basically opcode encoding information for
disassembly.
2010-10-27 20:49:18 +11:00
Tim Allen
5ae0c80ee8 Update to v072r01 release.
byuu says:

- added pause shortcut ('P' key, as pause/break is too finicky)
- pause and auto-pause show on status bar
- added a debugger skeleton, very very primitive and completely unusable
  - don't try it yet
- added software filter support

Also included is the new snesfilter library. It has all of the filters
the old one had, as well as scanline filters since that's not in my GUI
anymore
If you want scanlines and other software filters, then you can either
make your own hybrid two-in-one software filter, or make a pixel shader
(I don't have one of those yet.)
2010-10-26 23:01:41 +11:00
371 changed files with 24889 additions and 10393 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -8,8 +8,8 @@
#include "x86.c"
#elif defined(__GNUC__) && defined(__amd64__)
#include "amd64.c"
#elif defined(__GNUC__) && defined(__powerpc__) && defined(__ELF__)
#include "ppc-elf.c"
#elif defined(__GNUC__) && defined(_ARCH_PPC)
#include "ppc.c"
#elif defined(__GNUC__)
#include "sjlj.c"
#elif defined(_MSC_VER) && defined(_M_IX86)

View File

@@ -1,6 +1,6 @@
/*
libco
version: 0.15 (2009-10-12)
version: 0.16 (2010-12-24)
license: public domain
*/

View File

@@ -1,325 +0,0 @@
/*
* libco.ppc-elf
* author: Kernigh
* license: public domain
*
* PowerPC 32-bit ELF implementation of libco (for compile with GCC),
* ported from PowerPC Mac OS X implementation (ppc.s) by Vas Crabb.
* This ELF version works for OpenBSD, and might also work for FreeBSD,
* NetBSD and Linux.
*
* Note 1: This implementation does not handle the AltiVec/VMX
* registers, because the ELF ABI does not mention them,
* and my OpenBSD system is not using them.
*
* Note 2: If you want position-independent code, then you must
* define __PIC__. gcc -fpic or -fPIC defines __PIC__, but
* gcc -fpie or -fPIE might not. If you want to use -fpie
* or -fPIE, then you might need a manual definition:
* gcc -fpie -D__PIC__=1
* gcc -fPIE -D__PIC__=2
*
* The ELF ABI is "System V Application Binary Interface, PowerPC
* Processor Supplement", which you can get from
* <http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf>
* (PDF file, hosted by Linux Foundation).
*
* ELF and Mac OS X use similar conventions to allocate the registers,
* and to pass arguments and return values through registers. The main
* differences are that ELF has a slightly different stack format, that
* symbols are different (and without an extra underscore at the start),
* and that the assembly syntax is different.
*
* A function may destroy the values of volatile registers, but must
* preserve the values of nonvolatile registers. So the co_switch()
* function only saves the nonvolatile registers.
*
* [nonvolatile registers in ELF]
* %r1, %r14..%r31
* %f14..%f31
* %cr2..%cr4 in cr
*
* [volatile registers in ELF]
* %r0, %r3..%r10
* %f0..%f13
* %cr0, %cr1, %cr5..%cr7 in cr
* ctr, lr, xer
*
* lr (link register) is volatile, but it contains the return address,
* so co_switch must save lr.
*
* %r13 is the small data pointer. This is constant across threads, so
* co_switch() does not touch %r13.
*
* %r2 is a reserved register, so co_switch() does not touch %r2. Some
* systems might borrow an idea from the PowerPC Embedded ABI, and might
* use %r2 as a small read-only data pointer, which is constant across
* threads.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef void * cothread_t;
/*
* co_active_context is either in a global offset table (if we are
* compiling -fPIC or -fPIE) or has an absolute position.
*/
static void *co_main_stack_pointer;
static cothread_t co_active_context = &co_main_stack_pointer;
extern cothread_t co_active() {
return co_active_context;
}
/*
* Embedded assembly.
*
* We are not using the percent-sign substitution feature,
* so we must write "%r1", not "%%r1".
*
* We always write 'bl malloc@plt', not 'bl malloc'. The '@plt'
* is necessary in position-indepent code and seems to have no
* significant effect in fixed-position code.
*
* We never use the 'lmw' or 'stmw' instructions. The ELF ABI
* mentions that these instructions "are usually slower than
* a sequence of other instructions that have the same effect."
* We instead use sequences of 'lwz' or 'stz' instructions.
*/
__asm__("\n"
"### embedded assembly \n"
".section \".text\" \n"
" .balign 4 \n"
" \n"
/*
* void co_switch(co_thread to %r3)
*
* Allocate our stack frame of 240 bytes:
* Old New Value
* 4(%r1) 244(%r1) return address, used by us
* 0(%r1) 240(%r1) frame pointer
* 232(%r1) %f31
* 224(%r1) %f30
* ...
* 96(%r1) %f14
* 92(%r1) %r31
* 88(%r1) %r30
* ...
* 24(%r1) %r14
* 20(%r1) condition register
* 8(%r1) padding of 12 bytes
* 4(%r1) return address, never used
* 0(%r1) frame pointer
*
* Save our registers in our stack frame.
* Save our stack pointer in 0(%r4).
* Switch to the stack of the other thread.
* Restore registers and return.
*/
" .globl co_switch \n"
" .type co_switch, @function \n"
"co_switch: \n"
" mflr %r0 # %r0 = return address \n"
" mfcr %r9 # %r9 = condition register \n"
" stwu %r1, -240(%r1) # allocate stack frame \n"
" \n"
" stw %r0, 244(%r1) # save return address \n"
" stfd %f31, 232(%r1) # save floating-point regs \n"
" stfd %f30, 224(%r1) \n"
" stfd %f29, 216(%r1) \n"
" stfd %f28, 208(%r1) \n"
" stfd %f27, 200(%r1) \n"
" stfd %f26, 192(%r1) \n"
" stfd %f25, 184(%r1) \n"
" stfd %f24, 176(%r1) \n"
" stfd %f23, 168(%r1) \n"
" stfd %f22, 160(%r1) \n"
" stfd %f21, 152(%r1) \n"
" stfd %f20, 144(%r1) \n"
" stfd %f19, 136(%r1) \n"
" stfd %f18, 128(%r1) \n"
" stfd %f17, 120(%r1) \n"
" stfd %f16, 112(%r1) \n"
" stfd %f16, 104(%r1) \n"
" stfd %f14, 96(%r1) \n"
" stw %r31, 92(%r1) # save general-purpose regs \n"
" stw %r30, 88(%r1) \n"
" stw %r29, 84(%r1) \n"
" stw %r28, 80(%r1) \n"
" stw %r27, 76(%r1) \n"
" stw %r26, 72(%r1) \n"
" stw %r25, 68(%r1) \n"
" stw %r24, 64(%r1) \n"
" stw %r23, 60(%r1) \n"
" stw %r22, 56(%r1) \n"
" stw %r21, 52(%r1) \n"
" stw %r20, 48(%r1) \n"
" stw %r19, 44(%r1) \n"
" stw %r18, 40(%r1) \n"
" stw %r17, 36(%r1) \n"
" stw %r16, 32(%r1) \n"
" stw %r15, 28(%r1) \n"
" stw %r14, 24(%r1) \n"
" stw %r9, 20(%r1) # save condition reg \n"
" \n"
" # save current context, set new context \n"
" # %r4 = co_active_context \n"
" # co_active_context = %r3 \n"
#if __PIC__ == 2
" # position-independent code, large model (-fPIC) \n"
" bl _GLOBAL_OFFSET_TABLE_@local-4 \n"
" mflr %r8 # %r8 = address of got \n"
" addis %r7, %r8, co_active_context@got@ha \n"
" lwz %r6, co_active_context@got@l(%r7) \n"
" lwz %r4, 0(%r6) \n"
" stw %r3, 0(%r6) \n"
#elif __PIC__ == 1
" # position-independent code, small model (-fpic) \n"
" bl _GLOBAL_OFFSET_TABLE_@local-4 \n"
" mflr %r8 # %r8 = address of got \n"
" lwz %r7, co_active_context@got(%r8) \n"
" lwz %r4, 0(%r7) \n"
" stw %r3, 0(%r7) \n"
#else
" # fixed-position code \n"
" lis %r8, co_active_context@ha \n"
" lwz %r4, co_active_context@l(%r8) \n"
" stw %r3, co_active_context@l(%r8) \n"
#endif
" \n"
" # save current stack pointer \n"
" stw %r1, 0(%r4) \n"
" # get new stack pointer \n"
" lwz %r1, 0(%r3) \n"
" \n"
" lwz %r0, 244(%r1) # get return address \n"
" lfd %f31, 232(%r1) # restore floating-point regs \n"
" lfd %f30, 224(%r1) \n"
" lfd %f29, 216(%r1) \n"
" lfd %f28, 208(%r1) \n"
" lfd %f27, 200(%r1) \n"
" lfd %f26, 192(%r1) \n"
" lfd %f25, 184(%r1) \n"
" lfd %f24, 176(%r1) \n"
" lfd %f23, 168(%r1) \n"
" lfd %f22, 160(%r1) \n"
" lfd %f21, 152(%r1) \n"
" lfd %f20, 144(%r1) \n"
" lfd %f19, 136(%r1) \n"
" lfd %f18, 128(%r1) \n"
" lfd %f17, 120(%r1) \n"
" lfd %f16, 112(%r1) \n"
" lfd %f16, 104(%r1) \n"
" lfd %f14, 96(%r1) \n"
" lwz %r31, 92(%r1) # restore general-purpose regs \n"
" lwz %r30, 88(%r1) \n"
" lwz %r29, 84(%r1) \n"
" lwz %r28, 80(%r1) \n"
" lwz %r27, 76(%r1) \n"
" lwz %r26, 72(%r1) \n"
" lwz %r25, 68(%r1) \n"
" lwz %r24, 64(%r1) \n"
" lwz %r23, 60(%r1) \n"
" lwz %r22, 56(%r1) \n"
" lwz %r21, 52(%r1) \n"
" lwz %r20, 48(%r1) \n"
" lwz %r19, 44(%r1) \n"
" lwz %r18, 40(%r1) \n"
" lwz %r17, 36(%r1) \n"
" lwz %r16, 32(%r1) \n"
" lwz %r15, 28(%r1) \n"
" lwz %r14, 24(%r1) \n"
" lwz %r9, 20(%r1) # get condition reg \n"
" \n"
" addi %r1, %r1, 240 # free stack frame \n"
" mtlr %r0 # restore return address \n"
" mtcr %r9 # restore condition register \n"
" blr # return \n"
" .size co_switch, . - co_switch \n"
" \n"
/*
* cothread_t %r3 co_create(unsigned int stack_size %r3,
* void (*coentry %r4)())
*
* Allocate a new stack, such that when you co_switch to that
* stack, then co_switch returns to coentry.
*/
" .globl co_create \n"
" .type co_create, @function \n"
"co_create: \n"
" mflr %r0 # %r0 = return address \n"
" stwu %r1, -16(%r1) # allocate my stack frame \n"
" stw %r0, 20(%r1) # save return address \n"
" stw %r31, 12(%r1) # save %r31 \n"
" stw %r30, 8(%r1) # save %r30 \n"
" \n"
" mr %r30, %r3 # %r30 = stack_size \n"
" mr %r31, %r4 # %r31 = coentry \n"
" \n"
" # Call malloc(stack_size %r3) to allocate stack; \n"
" # malloc() probably uses good alignment. \n"
" # \n"
" bl malloc@plt # returns %r3 = low end \n"
" cmpwi %r3, 0 # if returned NULL, \n"
" beq- 1f # then abort \n"
" \n"
" # we return %r3 = low end of stack \n"
" add %r4, %r3, %r30 # %r4 = high end of stack \n"
" \n"
" # uncomment if malloc() uses wrong alignment \n"
" #rlwinm %r4,%r4,0,0,27 # force 16-byte alignment \n"
" \n"
/*
* Allocate two stack frames:
* 16 bytes for stack frame with return address
* 240 bytes for co_switch stack frame
*
* Old New Value
* -8(%r4) 248(%r5) padding of 8 bytes
* -12(%r4) 244(%r5) return address = coentry
* -16(%r4) 240(%r5) frame pointer = NULL
* 232(%r5) %f31 = 0
* ...
* 20(%r5) condition register = 0
* 0(%r5) frame pointer
*/
" li %r9, (240-20)/4+1 \n"
" addi %r5, %r4, -16 # allocate first stack frame \n"
" li %r0, 0 \n"
" stwu %r5, -240(%r5) # allocate second stack frame \n"
" li %r8, 20 \n"
" mtctr %r9 # loop %r9 times \n"
"2: # loop to store zero to 20(%r5) through 240(%r5) \n"
" stwx %r0, %r5, %r8 \n"
" addi %r8, %r8, 4 # index += 4 \n"
" bdnz+ 2b # ctr -= 1, branch if nonzero \n"
" \n"
" stw %r31, 244(%r5) # return address = coentry \n"
" stw %r5, 0(%r3) # save stack pointer \n"
" \n"
" lwz %r0, 20(%r1) # get return address \n"
" lwz %r31, 12(%r1) # restore %r31 \n"
" lwz %r30, 8(%r1) # restore %r30 \n"
" mtlr %r0 # restore return address \n"
" addi %r1, %r1, 16 # free stack frame \n"
" blr # return \n"
" \n"
"1: b abort@plt # branch 1f to abort \n"
" .size co_create, . - co_create \n"
" \n"
/*
* void co_delete(cothread_t) => void free(void *)
*/
" .globl co_delete \n"
" .type co_delete, @function \n"
"co_delete: \n"
" b free@plt \n"
" \n"
);
#ifdef __cplusplus
}
#endif

407
bsnes/libco/ppc.c Executable file
View File

@@ -0,0 +1,407 @@
/*
libco.ppc (2010-10-17)
author: blargg
license: public domain
*/
/* PowerPC 32/64 using embedded or external asm, with optional
floating-point and AltiVec save/restore */
#define LIBCO_C
#include "libco.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#define LIBCO_MPROTECT (__unix__ && !LIBCO_PPC_ASM)
#if LIBCO_MPROTECT
#include <unistd.h>
#include <sys/mman.h>
#endif
/* State format (offsets in 32-bit words)
+0 Pointer to swap code
Rest of function descriptor for entry function
+8 PC
+10 SP
Special regs
GPRs
FPRs
VRs
stack
*/
enum { state_size = 1024 };
enum { above_stack = 2048 };
enum { stack_align = 256 };
static thread_local cothread_t co_active_handle = 0;
/**** Determine environment ****/
#define LIBCO_PPC64 (_ARCH_PPC64 || __PPC64__ || __ppc64__ || __powerpc64__)
/* Whether function calls are indirect through a descriptor,
or are directly to function */
#ifndef LIBCO_PPCDESC
#if !_CALL_SYSV && (_CALL_AIX || _CALL_AIXDESC || LIBCO_PPC64)
#define LIBCO_PPCDESC 1
#endif
#endif
#ifdef LIBCO_PPC_ASM
#ifdef __cplusplus
extern "C"
#endif
/* Swap code is in ppc.S */
void co_swap_asm( cothread_t, cothread_t );
#define CO_SWAP_ASM( x, y ) co_swap_asm( x, y )
#else
/* Swap code is here in array. Please leave dieassembly comments,
as they make it easy to see what it does, and reorder instructions
if one wants to see whether that improves performance. */
static const uint32_t libco_ppc_code [] = {
#if LIBCO_PPC64
0x7d000026, /* mfcr r8 */
0xf8240028, /* std r1,40(r4) */
0x7d2802a6, /* mflr r9 */
0xf9c40048, /* std r14,72(r4) */
0xf9e40050, /* std r15,80(r4) */
0xfa040058, /* std r16,88(r4) */
0xfa240060, /* std r17,96(r4) */
0xfa440068, /* std r18,104(r4) */
0xfa640070, /* std r19,112(r4) */
0xfa840078, /* std r20,120(r4) */
0xfaa40080, /* std r21,128(r4) */
0xfac40088, /* std r22,136(r4) */
0xfae40090, /* std r23,144(r4) */
0xfb040098, /* std r24,152(r4) */
0xfb2400a0, /* std r25,160(r4) */
0xfb4400a8, /* std r26,168(r4) */
0xfb6400b0, /* std r27,176(r4) */
0xfb8400b8, /* std r28,184(r4) */
0xfba400c0, /* std r29,192(r4) */
0xfbc400c8, /* std r30,200(r4) */
0xfbe400d0, /* std r31,208(r4) */
0xf9240020, /* std r9,32(r4) */
0xe8e30020, /* ld r7,32(r3) */
0xe8230028, /* ld r1,40(r3) */
0x48000009, /* bl 1 */
0x7fe00008, /* trap */
0x91040030,/*1:stw r8,48(r4) */
0x80c30030, /* lwz r6,48(r3) */
0x7ce903a6, /* mtctr r7 */
0xe9c30048, /* ld r14,72(r3) */
0xe9e30050, /* ld r15,80(r3) */
0xea030058, /* ld r16,88(r3) */
0xea230060, /* ld r17,96(r3) */
0xea430068, /* ld r18,104(r3) */
0xea630070, /* ld r19,112(r3) */
0xea830078, /* ld r20,120(r3) */
0xeaa30080, /* ld r21,128(r3) */
0xeac30088, /* ld r22,136(r3) */
0xeae30090, /* ld r23,144(r3) */
0xeb030098, /* ld r24,152(r3) */
0xeb2300a0, /* ld r25,160(r3) */
0xeb4300a8, /* ld r26,168(r3) */
0xeb6300b0, /* ld r27,176(r3) */
0xeb8300b8, /* ld r28,184(r3) */
0xeba300c0, /* ld r29,192(r3) */
0xebc300c8, /* ld r30,200(r3) */
0xebe300d0, /* ld r31,208(r3) */
0x7ccff120, /* mtcr r6 */
#else
0x7d000026, /* mfcr r8 */
0x90240028, /* stw r1,40(r4) */
0x7d2802a6, /* mflr r9 */
0x91a4003c, /* stw r13,60(r4) */
0x91c40040, /* stw r14,64(r4) */
0x91e40044, /* stw r15,68(r4) */
0x92040048, /* stw r16,72(r4) */
0x9224004c, /* stw r17,76(r4) */
0x92440050, /* stw r18,80(r4) */
0x92640054, /* stw r19,84(r4) */
0x92840058, /* stw r20,88(r4) */
0x92a4005c, /* stw r21,92(r4) */
0x92c40060, /* stw r22,96(r4) */
0x92e40064, /* stw r23,100(r4) */
0x93040068, /* stw r24,104(r4) */
0x9324006c, /* stw r25,108(r4) */
0x93440070, /* stw r26,112(r4) */
0x93640074, /* stw r27,116(r4) */
0x93840078, /* stw r28,120(r4) */
0x93a4007c, /* stw r29,124(r4) */
0x93c40080, /* stw r30,128(r4) */
0x93e40084, /* stw r31,132(r4) */
0x91240020, /* stw r9,32(r4) */
0x80e30020, /* lwz r7,32(r3) */
0x80230028, /* lwz r1,40(r3) */
0x48000009, /* bl 1 */
0x7fe00008, /* trap */
0x91040030,/*1:stw r8,48(r4) */
0x80c30030, /* lwz r6,48(r3) */
0x7ce903a6, /* mtctr r7 */
0x81a3003c, /* lwz r13,60(r3) */
0x81c30040, /* lwz r14,64(r3) */
0x81e30044, /* lwz r15,68(r3) */
0x82030048, /* lwz r16,72(r3) */
0x8223004c, /* lwz r17,76(r3) */
0x82430050, /* lwz r18,80(r3) */
0x82630054, /* lwz r19,84(r3) */
0x82830058, /* lwz r20,88(r3) */
0x82a3005c, /* lwz r21,92(r3) */
0x82c30060, /* lwz r22,96(r3) */
0x82e30064, /* lwz r23,100(r3) */
0x83030068, /* lwz r24,104(r3) */
0x8323006c, /* lwz r25,108(r3) */
0x83430070, /* lwz r26,112(r3) */
0x83630074, /* lwz r27,116(r3) */
0x83830078, /* lwz r28,120(r3) */
0x83a3007c, /* lwz r29,124(r3) */
0x83c30080, /* lwz r30,128(r3) */
0x83e30084, /* lwz r31,132(r3) */
0x7ccff120, /* mtcr r6 */
#endif
#ifndef LIBCO_PPC_NOFP
0xd9c400e0, /* stfd f14,224(r4) */
0xd9e400e8, /* stfd f15,232(r4) */
0xda0400f0, /* stfd f16,240(r4) */
0xda2400f8, /* stfd f17,248(r4) */
0xda440100, /* stfd f18,256(r4) */
0xda640108, /* stfd f19,264(r4) */
0xda840110, /* stfd f20,272(r4) */
0xdaa40118, /* stfd f21,280(r4) */
0xdac40120, /* stfd f22,288(r4) */
0xdae40128, /* stfd f23,296(r4) */
0xdb040130, /* stfd f24,304(r4) */
0xdb240138, /* stfd f25,312(r4) */
0xdb440140, /* stfd f26,320(r4) */
0xdb640148, /* stfd f27,328(r4) */
0xdb840150, /* stfd f28,336(r4) */
0xdba40158, /* stfd f29,344(r4) */
0xdbc40160, /* stfd f30,352(r4) */
0xdbe40168, /* stfd f31,360(r4) */
0xc9c300e0, /* lfd f14,224(r3) */
0xc9e300e8, /* lfd f15,232(r3) */
0xca0300f0, /* lfd f16,240(r3) */
0xca2300f8, /* lfd f17,248(r3) */
0xca430100, /* lfd f18,256(r3) */
0xca630108, /* lfd f19,264(r3) */
0xca830110, /* lfd f20,272(r3) */
0xcaa30118, /* lfd f21,280(r3) */
0xcac30120, /* lfd f22,288(r3) */
0xcae30128, /* lfd f23,296(r3) */
0xcb030130, /* lfd f24,304(r3) */
0xcb230138, /* lfd f25,312(r3) */
0xcb430140, /* lfd f26,320(r3) */
0xcb630148, /* lfd f27,328(r3) */
0xcb830150, /* lfd f28,336(r3) */
0xcba30158, /* lfd f29,344(r3) */
0xcbc30160, /* lfd f30,352(r3) */
0xcbe30168, /* lfd f31,360(r3) */
#endif
#ifdef __ALTIVEC__
0x7ca042a6, /* mfvrsave r5 */
0x39040180, /* addi r8,r4,384 */
0x39240190, /* addi r9,r4,400 */
0x70a00fff, /* andi. r0,r5,4095 */
0x90a40034, /* stw r5,52(r4) */
0x4182005c, /* beq- 2 */
0x7e8041ce, /* stvx v20,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7ea049ce, /* stvx v21,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7ec041ce, /* stvx v22,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7ee049ce, /* stvx v23,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7f0041ce, /* stvx v24,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7f2049ce, /* stvx v25,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7f4041ce, /* stvx v26,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7f6049ce, /* stvx v27,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7f8041ce, /* stvx v28,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7fa049ce, /* stvx v29,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7fc041ce, /* stvx v30,r0,r8 */
0x7fe049ce, /* stvx v31,r0,r9 */
0x80a30034,/*2:lwz r5,52(r3) */
0x39030180, /* addi r8,r3,384 */
0x39230190, /* addi r9,r3,400 */
0x70a00fff, /* andi. r0,r5,4095 */
0x7ca043a6, /* mtvrsave r5 */
0x4d820420, /* beqctr */
0x7e8040ce, /* lvx v20,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7ea048ce, /* lvx v21,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7ec040ce, /* lvx v22,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7ee048ce, /* lvx v23,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7f0040ce, /* lvx v24,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7f2048ce, /* lvx v25,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7f4040ce, /* lvx v26,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7f6048ce, /* lvx v27,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7f8040ce, /* lvx v28,r0,r8 */
0x39080020, /* addi r8,r8,32 */
0x7fa048ce, /* lvx v29,r0,r9 */
0x39290020, /* addi r9,r9,32 */
0x7fc040ce, /* lvx v30,r0,r8 */
0x7fe048ce, /* lvx v31,r0,r9 */
#endif
0x4e800420, /* bctr */
};
#if LIBCO_PPCDESC
/* Function call goes through indirect descriptor */
#define CO_SWAP_ASM( x, y ) \
((void (*)( cothread_t, cothread_t )) (uintptr_t) x)( x, y )
#else
/* Function call goes directly to code */
#define CO_SWAP_ASM( x, y ) \
((void (*)( cothread_t, cothread_t )) (uintptr_t) libco_ppc_code)( x, y )
#endif
#endif
static uint32_t* co_create_( unsigned size, uintptr_t entry )
{
uint32_t* t = (uint32_t*) malloc( size );
(void) entry;
#if LIBCO_PPCDESC
if ( t )
{
/* Copy entry's descriptor */
memcpy( t, (void*) entry, sizeof (void*) * 3 );
/* Set function pointer to swap routine */
#ifdef LIBCO_PPC_ASM
*(const void**) t = *(void**) &co_swap_asm;
#else
*(const void**) t = libco_ppc_code;
#endif
}
#endif
return t;
}
cothread_t co_create( unsigned int size, void (*entry_)( void ) )
{
uintptr_t entry = (uintptr_t) entry_;
uint32_t* t = NULL;
/* Be sure main thread was successfully allocated */
if ( co_active() )
{
size += state_size + above_stack + stack_align;
t = co_create_( size, entry );
}
if ( t )
{
uintptr_t sp;
int shift;
/* Save current registers into new thread, so that any special ones will
have proper values when thread is begun */
CO_SWAP_ASM( t, t );
#if LIBCO_PPCDESC
/* Get real address */
entry = (uintptr_t) *(void**) entry;
#endif
/* Put stack near end of block, and align */
sp = (uintptr_t) t + size - above_stack;
sp -= sp % stack_align;
/* On PPC32, we save and restore GPRs as 32 bits. For PPC64, we
save and restore them as 64 bits, regardless of the size the ABI
uses. So, we manually write pointers at the proper size. We always
save and restore at the same address, and since PPC is big-endian,
we must put the low byte first on PPC32. */
/* If uintptr_t is 32 bits, >>32 is undefined behavior, so we do two shifts
and don't have to care how many bits uintptr_t is. */
#if LIBCO_PPC64
shift = 16;
#else
shift = 0;
#endif
/* Set up so entry will be called on next swap */
t [8] = (uint32_t) (entry >> shift >> shift);
t [9] = (uint32_t) entry;
t [10] = (uint32_t) (sp >> shift >> shift);
t [11] = (uint32_t) sp;
}
return t;
}
void co_delete( cothread_t t )
{
free( t );
}
static void co_init_( void )
{
#if LIBCO_MPROTECT
/* TODO: pre- and post-pad PPC code so that this doesn't make other
data executable and writable */
long page_size = sysconf( _SC_PAGESIZE );
if ( page_size > 0 )
{
uintptr_t align = page_size;
uintptr_t begin = (uintptr_t) libco_ppc_code;
uintptr_t end = begin + sizeof libco_ppc_code;
/* Align beginning and end */
end += align - 1;
end -= end % align;
begin -= begin % align;
mprotect( (void*) begin, end - begin, PROT_READ | PROT_WRITE | PROT_EXEC );
}
#endif
co_active_handle = co_create_( state_size, (uintptr_t) &co_switch );
}
cothread_t co_active()
{
if ( !co_active_handle )
co_init_();
return co_active_handle;
}
void co_switch( cothread_t t )
{
cothread_t old = co_active_handle;
co_active_handle = t;
CO_SWAP_ASM( t, old );
}

View File

@@ -1,478 +0,0 @@
;*****
;libco.ppc (2007-11-29)
;author: Vas Crabb
;license: public domain
;
;cross-platform PowerPC implementation of libco
;special thanks to byuu for writing the original version
;
;[ABI compatibility]
;- gcc; mac os x; ppc
;
;[nonvolatile registers]
;- GPR1, GPR13 - GPR31
;- FPR14 - FPR31
;- V20 - V31
;- VRSAVE, CR2 - CR4
;
;[volatile registers]
;- GPR0, GPR2 - GPR12
;- FPR0 - FPR13
;- V0 - V19
;- LR, CTR, XER, CR0, CR1, CR5 - CR7
;*****
;Declare some target-specific stuff
.section __TEXT,__text,regular,pure_instructions
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
.machine ppc
;Constants
.cstring
.align 2
_sysctl_altivec:
.ascii "hw.optional.altivec\0"
;Declare space for variables
.lcomm _co_environ,4,2 ;bit 0 = initialised, bit 1 = have Altivec/VMX
.lcomm _co_primary_buffer,1024,2 ;buffer (will be zeroed by loader)
.data
.align 2
_co_active_context:
.long _co_primary_buffer
.text
.align 2
;Declare exported names
.globl _co_active
.globl _co_create
.globl _co_delete
.globl _co_switch
;*****
;extern "C" cothread_t co_active();
;return = GPR3
;*****
_co_active:
mflr r0 ;GPR0 = return address
bcl 20,31,L_co_active$spb
L_co_active$spb:
mflr r2 ;GPR2 set for position-independance
addis r3,r2,ha16(_co_active_context-L_co_active$spb) ;get value in GPR3
lwz r3,lo16(_co_active_context-L_co_active$spb)(r3)
mtlr r0 ;LR = return address
blr ;return
;*****
;extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)());
;GPR3 = heapsize
;GPR4 = coentry
;return = GPR3
;*****
_co_create:
mflr r0 ;GPR0 = return address
stmw r30,-8(r1) ;save GPR30 and GPR31
stw r0,8(r1) ;save return address
stwu r1,-(2*4+16+24)(r1) ;allocate 16 bytes for locals/parameters
;create heap space (stack + register storage)
addi r31,r3,1024-24 ;subtract space for linkage
mr r30,r4 ;GPR30 = coentry
addi r3,r3,1024 ;allocate extra memory for contextual info
bl L_malloc$stub ;GPR3 = malloc(heapsize + 1024)
add r4,r3,r31 ;GPR4 points to top-of-stack
rlwinm r5,r4,0,0,27 ;force 16-byte alignment
;store thread entry point + registers, so that first call to co_switch will execute coentry
stw r30,8(r5) ;store entry point
addi r6,0,2+19+18*2+12*4+1 ;clear for CR, old GPR1, 19 GPRs, 18 FPRs, 12 VRs, VRSAVE
addi r0,0,0
addi r7,0,4 ;start at 4(GPR5)
mtctr r6
L_co_create$clear_loop:
stwx r0,r5,r7 ;clear a word
addi r7,r7,-4 ;increment pointer
bdnz L_co_create$clear_loop ;loop
stwu r5,-448(r5) ;store top of stack
;initialize context memory heap and return
stw r5,0(r3) ;*cothread_t = stack heap pointer (GPR1)
lwz r1,0(r1) ;deallocate stack frame
lwz r8,8(r1) ;fetch return address
lmw r30,-8(r1) ;restore GPR30 and GPR31
mtlr r8 ;return address in LR
blr ;return
;*****
;extern "C" void co_delete(cothread_t cothread);
;GPR3 = cothread
;*****
_co_delete:
b L_free$stub ;free(GPR3)
;*****
;extern "C" void co_switch(cothread_t cothread);
;GPR3 = cothread
;*****
;
;Frame looks like:
;
;Old New Value
; 8(r1) 456(r1) Saved LR
; 4(r1) 452(r1) Saved CR
; 0(r1) 448(r1) Old GPR1
; -4(r1) 444(r1) Saved GPR31
; -8(r1) 440(r1) Saved GPR30
;... ... ...
; -72(r1) 376(r1) Saved GPR14
; -76(r1) 372(r1) Saved GPR13
; -80(r1) 368(r1) Saved VRSAVE
; -84(r1) 364(r1) +++
; -88(r1) 360(r1) Saved FPR31
; -92(r1) 356(r1) +++
; -96(r1) 352(r1) Saved FPR30
;... ... ...
;-212(r1) 236(r1) +++
;-216(r1) 232(r1) Saved FPR15
;-220(r1) 228(r1) +++
;-224(r1) 224(r1) Saved FPR14
;-228(r1) 220(r1) +++ value
;-232(r1) 216(r1) +++ len
;-236(r1) 212(r1) +++
;-240(r1) 208(r1) Saved VR31
;-244(r1) 204(r1) +++
;-248(r1) 200(r1) +++
;-252(r1) 196(r1) +++
;-256(r1) 192(r1) Saved VR30
;... ... ...
;-388(r1) 60(r1) +++
;-392(r1) 56(r1) +++
;-396(r1) 52(r1) +++
;-400(r1) 48(r1) Saved VR21
;-404(r1) 44(r1) +++
;-408(r1) 40(r1) +++ Param 5 (GPR7)
;-412(r1) 36(r1) +++ Param 4 (GPR6)
;-416(r1) 32(r1) Saved VR20 Param 3 (GPR5)
;-420(r1) 28(r1) - Param 2 (GPR4)
;-424(r1) 24(r1) - Param 1 (GPR3)
;-428(r1) 20(r1) - Reserved
;-432(r1) 16(r1) - Reserved
;-436(r1) 12(r1) - Reserved
;-440(r1) 8(r1) - New LR
;-444(r1) 4(r1) - New CR
;-448(r1) 0(r1) Saved GPR1
_co_switch:
stmw r13,-76(r1) ;save preserved GPRs
stfd f14,-224(r1) ;save preserved FPRs
stfd f15,-216(r1)
stfd f16,-208(r1)
stfd f17,-200(r1)
stfd f18,-192(r1)
stfd f19,-184(r1)
stfd f20,-176(r1)
stfd f21,-168(r1)
stfd f22,-160(r1)
stfd f23,-152(r1)
stfd f24,-144(r1)
stfd f25,-136(r1)
stfd f26,-128(r1)
stfd f27,-120(r1)
stfd f28,-112(r1)
stfd f29,-104(r1)
stfd f30,-96(r1)
stfd f31,-88(r1)
mflr r0 ;save return address
stw r0,8(r1)
mfcr r2 ;save condition codes
stw r2,4(r1)
stwu r1,-448(r1) ;create stack frame (save 19 GPRs, 18 FRPs, 12 VRs, VRSAVE)
mr r30,r3 ;save new context pointer
bcl 20,31,L_co_switch$spb ;get address of co_active_context
L_co_switch$spb:
mflr r31
addis r29,r31,ha16(_co_environ-L_co_switch$spb) ;get environment flags
lwz r8,lo16(_co_environ-L_co_switch$spb)(r29)
andis. r9,r8,0x8000 ;is it initialised?
bne+ L_co_switch$initialised
addi r0,0,4 ;len = sizeof(int)
stw r0,216(r1)
addis r3,r31,ha16(_sysctl_altivec-L_co_switch$spb) ;GPR3 = "hw.optional.altivec"
addi r3,r3,lo16(_sysctl_altivec-L_co_switch$spb)
addi r4,r1,220 ;GPR4 = &value
addi r5,r1,216 ;GPR5 = &len
addi r6,0,0 ;newp = 0
addi r7,0,0 ;newlen = 0
bl L_sysctlbyname$stub ;call sysctlbyname
lwz r2,220(r1) ;fetch result
addis r8,0,0x8000 ;set initialised bit
cmpwi cr5,r3,0 ;assume error means not present
cmpwi cr6,r2,0 ;test result
blt- cr5,L_co_switch$store_environ
beq cr6,L_co_switch$store_environ
oris r8,r8,0x4000 ;set the flag to say we have it!
L_co_switch$store_environ:
stw r8,lo16(_co_environ-L_co_switch$spb)(r29) ;store environment flags
L_co_switch$initialised:
andis. r10,r8,0x4000 ;do we have Altivec/VMX?
beq L_co_switch$save_no_vmx
mfspr r11,256 ;save VRSAVE
andi. r0,r11,0x0FFF ;short-circuit if it's zero
stw r11,368(r1)
beq L_co_switch$save_no_vmx
andi. r0,r11,0x0800 ;check bit 20
addi r2,0,32 ;starting index
beq L_co_switch$save_skip_vr20
stvx v20,r1,r2 ;save VR20
L_co_switch$save_skip_vr20:
addi r2,r2,16 ;stride
andi. r0,r11,0x0400 ;check bit 21
beq L_co_switch$save_skip_vr21
stvx v21,r1,r2 ;save VR21
L_co_switch$save_skip_vr21:
addi r2,r2,16 ;stride
andi. r0,r11,0x0200 ;check bit 22
beq L_co_switch$save_skip_vr22
stvx v22,r1,r2 ;save VR22
L_co_switch$save_skip_vr22:
addi r2,r2,16 ;stride
andi. r0,r11,0x0100 ;check bit 23
beq L_co_switch$save_skip_vr23
stvx v23,r1,r2 ;save VR23
L_co_switch$save_skip_vr23:
addi r2,r2,16 ;stride
andi. r0,r11,0x0080 ;check bit 24
beq L_co_switch$save_skip_vr24
stvx v24,r1,r2 ;save VR24
L_co_switch$save_skip_vr24:
addi r2,r2,16 ;stride
andi. r0,r11,0x0040 ;check bit 25
beq L_co_switch$save_skip_vr25
stvx v25,r1,r2 ;save VR25
L_co_switch$save_skip_vr25:
addi r2,r2,16 ;stride
andi. r0,r11,0x0020 ;check bit 26
beq L_co_switch$save_skip_vr26
stvx v26,r1,r2 ;save VR26
L_co_switch$save_skip_vr26:
addi r2,r2,16 ;stride
andi. r0,r11,0x0010 ;check bit 27
beq L_co_switch$save_skip_vr27
stvx v27,r1,r2 ;save VR27
L_co_switch$save_skip_vr27:
addi r2,r2,16 ;stride
andi. r0,r11,0x0008 ;check bit 28
beq L_co_switch$save_skip_vr28
stvx v28,r1,r2 ;save VR28
L_co_switch$save_skip_vr28:
addi r2,r2,16 ;stride
andi. r0,r11,0x0004 ;check bit 29
beq L_co_switch$save_skip_vr29
stvx v29,r1,r2 ;save VR29
L_co_switch$save_skip_vr29:
addi r2,r2,16 ;stride
andi. r0,r11,0x0002 ;check bit 30
beq L_co_switch$save_skip_vr30
stvx v30,r1,r2 ;save VR30
L_co_switch$save_skip_vr30:
addi r2,r2,16 ;stride
andi. r0,r11,0x0001 ;check bit 31
beq L_co_switch$save_skip_vr31
stvx v31,r1,r2 ;save VR31
L_co_switch$save_skip_vr31:
L_co_switch$save_no_vmx:
addis r4,r31,ha16(_co_active_context-L_co_switch$spb) ;save current context
lwz r5,lo16(_co_active_context-L_co_switch$spb)(r4)
stw r30,lo16(_co_active_context-L_co_switch$spb)(r4);set new context
stw r1,0(r5) ;save current stack pointer
lwz r1,0(r30) ;get new stack pointer
andis. r10,r8,0x4000 ;do we have Altivec/VMX?
beq L_co_switch$restore_no_vmx
lwz r11,368(r1) ;restore VRSAVE
andi. r0,r11,0x0FFF ;short-circuit if it's zero
mtspr 256,r11
beq L_co_switch$restore_no_vmx
andi. r0,r11,0x0800 ;check bit 20
addi r2,0,32 ;starting index
beq L_co_switch$restore_skip_vr20
lvx v20,r1,r2 ;restore VR20
L_co_switch$restore_skip_vr20:
addi r2,r2,16 ;stride
andi. r0,r11,0x0400 ;check bit 21
beq L_co_switch$restore_skip_vr21
lvx v21,r1,r2 ;restore VR21
L_co_switch$restore_skip_vr21:
addi r2,r2,16 ;stride
andi. r0,r11,0x0200 ;check bit 22
beq L_co_switch$restore_skip_vr22
lvx v22,r1,r2 ;restore VR22
L_co_switch$restore_skip_vr22:
addi r2,r2,16 ;stride
andi. r0,r11,0x0100 ;check bit 23
beq L_co_switch$restore_skip_vr23
lvx v23,r1,r2 ;restore VR23
L_co_switch$restore_skip_vr23:
addi r2,r2,16 ;stride
andi. r0,r11,0x0080 ;check bit 24
beq L_co_switch$restore_skip_vr24
lvx v24,r1,r2 ;restore VR24
L_co_switch$restore_skip_vr24:
addi r2,r2,16 ;stride
andi. r0,r11,0x0040 ;check bit 25
beq L_co_switch$restore_skip_vr25
lvx v25,r1,r2 ;restore VR25
L_co_switch$restore_skip_vr25:
addi r2,r2,16 ;stride
andi. r0,r11,0x0020 ;check bit 26
beq L_co_switch$restore_skip_vr26
lvx v26,r1,r2 ;restore VR26
L_co_switch$restore_skip_vr26:
addi r2,r2,16 ;stride
andi. r0,r11,0x0010 ;check bit 27
beq L_co_switch$restore_skip_vr27
lvx v27,r1,r2 ;restore VR27
L_co_switch$restore_skip_vr27:
addi r2,r2,16 ;stride
andi. r0,r11,0x0008 ;check bit 28
beq L_co_switch$restore_skip_vr28
lvx v28,r1,r2 ;restore VR28
L_co_switch$restore_skip_vr28:
addi r2,r2,16 ;stride
andi. r0,r11,0x0004 ;check bit 29
beq L_co_switch$restore_skip_vr29
lvx v29,r1,r2 ;restore VR29
L_co_switch$restore_skip_vr29:
addi r2,r2,16 ;stride
andi. r0,r11,0x0002 ;check bit 30
beq L_co_switch$restore_skip_vr30
lvx v30,r1,r2 ;restore VR30
L_co_switch$restore_skip_vr30:
addi r2,r2,16 ;stride
andi. r0,r11,0x0001 ;check bit 31
beq L_co_switch$restore_skip_vr31
lvx v31,r1,r2 ;restore VR31
L_co_switch$restore_skip_vr31:
L_co_switch$restore_no_vmx:
lwz r1,0(r1) ;deallocate stack frame
lwz r6,8(r1) ;return address in GPR6
lwz r7,4(r1) ;condition codes in GPR7
addi r0,0,0 ;make thread main crash if it returns
lmw r13,-76(r1) ;restore preserved GPRs
lfd f14,-224(r1) ;restore preserved FPRs
lfd f15,-216(r1)
lfd f16,-208(r1)
lfd f17,-200(r1)
lfd f18,-192(r1)
lfd f19,-184(r1)
lfd f20,-176(r1)
lfd f21,-168(r1)
lfd f22,-160(r1)
lfd f23,-152(r1)
lfd f24,-144(r1)
lfd f25,-136(r1)
lfd f26,-128(r1)
lfd f27,-120(r1)
lfd f28,-112(r1)
lfd f29,-104(r1)
lfd f30,-96(r1)
lfd f31,-88(r1)
mtlr r0
mtctr r6 ;restore return address
mtcrf 32,r7 ;restore preserved condition codes
mtcrf 16,r7
mtcrf 8,r7
bctr ;return
;Import external functions
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
.align 5
L_malloc$stub:
.indirect_symbol _malloc
mflr r0
bcl 20,31,L_malloc$spb
L_malloc$spb:
mflr r11
addis r11,r11,ha16(L_malloc$lazy_ptr-L_malloc$spb)
mtlr r0
lwzu r12,lo16(L_malloc$lazy_ptr-L_malloc$spb)(r11)
mtctr r12
bctr
.lazy_symbol_pointer
L_malloc$lazy_ptr:
.indirect_symbol _malloc
.long dyld_stub_binding_helper
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
.align 5
L_free$stub:
.indirect_symbol _free
mflr r0
bcl 20,31,L_free$spb
L_free$spb:
mflr r11
addis r11,r11,ha16(L_free$lazy_ptr-L_free$spb)
mtlr r0
lwzu r12,lo16(L_free$lazy_ptr-L_free$spb)(r11)
mtctr r12
bctr
.lazy_symbol_pointer
L_free$lazy_ptr:
.indirect_symbol _free
.long dyld_stub_binding_helper
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
.align 5
L_sysctlbyname$stub:
.indirect_symbol _sysctlbyname
mflr r0
bcl 20,31,L_sysctlbyname$spb
L_sysctlbyname$spb:
mflr r11
addis r11,r11,ha16(L_sysctlbyname$lazy_ptr-L_sysctlbyname$spb)
mtlr r0
lwzu r12,lo16(L_sysctlbyname$lazy_ptr-L_sysctlbyname$spb)(r11)
mtctr r12
bctr
.lazy_symbol_pointer
L_sysctlbyname$lazy_ptr:
.indirect_symbol _sysctlbyname
.long dyld_stub_binding_helper
;This needs to be here!
.subsections_via_symbols

View File

@@ -1,513 +0,0 @@
;*****
;libco.ppc64 (2007-12-05)
;author: Vas Crabb
;license: public domain
;
;cross-platform 64-bit PowerPC implementation of libco
;special thanks to byuu for writing the original version
;
;[ABI compatibility]
;- gcc; mac os x; ppc64
;
;[nonvolatile registers]
;- GPR1, GPR13 - GPR31
;- FPR14 - FPR31
;- V20 - V31
;- VRSAVE, CR2 - CR4
;
;[volatile registers]
;- GPR0, GPR2 - GPR12
;- FPR0 - FPR13
;- V0 - V19
;- LR, CTR, XER, CR0, CR1, CR5 - CR7
;*****
;Declare some target-specific stuff
.section __TEXT,__text,regular,pure_instructions
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
.machine ppc64
;Constants
.cstring
.align 3
_sysctl_altivec:
.ascii "hw.optional.altivec\0"
;Declare space for variables
.lcomm _co_environ,4,2 ;bit 0 = initialised, bit 1 = have Altivec/VMX
.lcomm _co_primary_buffer,1024,3 ;buffer (will be zeroed by loader)
.data
.align 3
_co_active_context:
.quad _co_primary_buffer
.text
.align 2
;Declare exported names
.globl _co_active
.globl _co_create
.globl _co_delete
.globl _co_switch
;*****
;extern "C" cothread_t co_active();
;return = GPR3
;*****
_co_active:
mflr r0 ;GPR0 = return address
bcl 20,31,L_co_active$spb
L_co_active$spb:
mflr r2 ;GPR2 set for position-independance
addis r3,r2,ha16(_co_active_context-L_co_active$spb) ;get value in GPR3
ld r3,lo16(_co_active_context-L_co_active$spb)(r3)
mtlr r0 ;LR = return address
blr ;return
;*****
;extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)());
;GPR3 = heapsize
;GPR4 = coentry
;return = GPR3
;*****
_co_create:
mflr r0 ;GPR0 = return address
std r30,-16(r1) ;save GPR30 and GPR31
std r31,-8(r1)
std r0,16(r1) ;save return address
stdu r1,-(2*8+16+48)(r1) ;allocate 16 bytes for locals/parameters
;create heap space (stack + register storage)
addi r31,r3,1024-48 ;subtract space for linkage
mr r30,r4 ;GPR30 = coentry
addi r3,r3,1024 ;allocate extra memory for contextual info
bl L_malloc$stub ;GPR3 = malloc(heapsize + 1024)
add r4,r3,r31 ;GPR4 points to top-of-stack
rldicr r5,r4,0,59 ;force 16-byte alignment
;store thread entry point + registers, so that first call to co_switch will execute coentry
std r30,16(r5) ;store entry point
addi r6,0,2+19+18+12*2+1 ;clear for CR, old GPR1, 19 GPRs, 18 FPRs, 12 VRs, VRSAVE
addi r0,0,0
addi r7,0,8 ;start at 8(GPR5)
mtctr r6
L_co_create$clear_loop:
stdx r0,r5,r7 ;clear a double
addi r7,r7,-8 ;increment pointer
bdnz L_co_create$clear_loop ;loop
stdu r5,-544(r5) ;store top of stack
;initialize context memory heap and return
addis r9,0,0x8000 ;GPR13 not set (system TLS)
std r5,0(r3) ;*cothread_t = stack heap pointer (GPR1)
stw r9,8(r3) ;this is a flag word
ld r1,0(r1) ;deallocate stack frame
ld r8,16(r1) ;fetch return address
ld r30,-16(r1) ;restore GPR30 and GPR31
ld r31,-8(r1)
mtlr r8 ;return address in LR
blr ;return
;*****
;extern "C" void co_delete(cothread_t cothread);
;GPR3 = cothread
;*****
_co_delete:
b L_free$stub ;free(GPR3)
;*****
;extern "C" void co_switch(cothread_t cothread);
;GPR3 = cothread
;*****
;
;Frame looks like:
;
;Old New Value
; 16(r1) 560(r1) Saved LR
; 8(r1) 552(r1) Saved CR
; 0(r1) 544(r1) Old GPR1
; -8(r1) 536(r1) Saved GPR31
; -16(r1) 528(r1) Saved GPR30
;... ... ...
;-144(r1) 400(r1) Saved GPR14
;-152(r1) 392(r1) Saved GPR13
;-160(r1) 384(r1) Saved FPR31
;-168(r1) 376(r1) Saved FPR30
;... ... ...
;-288(r1) 256(r1) Saved FPR15
;-296(r1) 248(r1) Saved FPR14
;-304(r1) 240(r1) Saved VRSAVE
;-312(r1) 232(r1) +++ value
;-320(r1) 224(r1) Saved VR31 len
;-328(r1) 216(r1) +++
;-336(r1) 208(r1) Saved VR30
;... ... ...
;-456(r1) 88(r1) +++
;-464(r1) 80(r1) Saved VR22 Param 5 (GPR7)
;-472(r1) 72(r1) +++ Param 4 (GPR6)
;-480(r1) 64(r1) Saved VR21 Param 3 (GPR5)
;-488(r1) 56(r1) +++ Param 2 (GPR4)
;-496(r1) 48(r1) Saved VR20 Param 1 (GPR3)
;-504(r1) 40(r1) - Reserved
;-512(r1) 32(r1) - Reserved
;-520(r1) 24(r1) - Reserved
;-528(r1) 16(r1) - New LR
;-536(r1) 8(r1) - New CR
;-544(r1) 0(r1) Saved GPR1
_co_switch:
std r13,-152(r1) ;save preserved GPRs
std r14,-144(r1)
std r15,-136(r1)
std r16,-128(r1)
std r17,-120(r1)
std r18,-112(r1)
std r19,-104(r1)
std r20,-96(r1)
std r21,-88(r1)
std r22,-80(r1)
std r23,-72(r1)
std r24,-64(r1)
std r25,-56(r1)
std r26,-48(r1)
std r27,-40(r1)
std r28,-32(r1)
std r29,-24(r1)
std r30,-16(r1)
std r31,-8(r1)
mflr r0 ;save return address
std r0,16(r1)
mfcr r2 ;save condition codes
stw r2,8(r1)
stdu r1,-544(r1) ;create stack frame (save 19 GPRs, 18 FRPs, 12 VRs, VRSAVE)
stfd f14,248(r1) ;save preserved FPRs
stfd f15,256(r1)
stfd f16,264(r1)
stfd f17,272(r1)
stfd f18,280(r1)
stfd f19,288(r1)
stfd f20,296(r1)
stfd f21,304(r1)
stfd f22,312(r1)
stfd f23,320(r1)
stfd f24,328(r1)
stfd f25,336(r1)
stfd f26,344(r1)
stfd f27,352(r1)
stfd f28,360(r1)
stfd f29,368(r1)
stfd f30,376(r1)
stfd f31,384(r1)
mr r30,r3 ;save new context pointer
bcl 20,31,L_co_switch$spb ;get address of co_active_context
L_co_switch$spb:
mflr r31
addis r29,r31,ha16(_co_environ-L_co_switch$spb) ;get environment flags
lwz r8,lo16(_co_environ-L_co_switch$spb)(r29)
andis. r9,r8,0x8000 ;is it initialised?
bne+ L_co_switch$initialised
addi r0,0,4 ;len = sizeof(int)
std r0,224(r1)
addis r3,r31,ha16(_sysctl_altivec-L_co_switch$spb) ;GPR3 = "hw.optional.altivec"
addi r3,r3,lo16(_sysctl_altivec-L_co_switch$spb)
addi r4,r1,232 ;GPR4 = &value
addi r5,r1,224 ;GPR5 = &len
addi r6,0,0 ;newp = 0
addi r7,0,0 ;newlen = 0
bl L_sysctlbyname$stub ;call sysctlbyname
lwz r2,232(r1) ;fetch result
addis r8,0,0x8000 ;set initialised bit
cmpdi cr5,r3,0 ;assume error means not present
cmpwi cr6,r2,0 ;test result
blt- cr5,L_co_switch$store_environ
beq cr6,L_co_switch$store_environ
oris r8,r8,0x4000 ;set the flag to say we have it!
L_co_switch$store_environ:
stw r8,lo16(_co_environ-L_co_switch$spb)(r29) ;store environment flags
L_co_switch$initialised:
andis. r10,r8,0x4000 ;do we have Altivec/VMX?
beq L_co_switch$save_no_vmx
mfspr r11,256 ;save VRSAVE
andi. r0,r11,0x0FFF ;short-circuit if it's zero
stw r11,240(r1)
beq L_co_switch$save_no_vmx
andi. r0,r11,0x0800 ;check bit 20
addi r2,0,48 ;starting index
beq L_co_switch$save_skip_vr20
stvx v20,r1,r2 ;save VR20
L_co_switch$save_skip_vr20:
addi r2,r2,16 ;stride
andi. r0,r11,0x0400 ;check bit 21
beq L_co_switch$save_skip_vr21
stvx v21,r1,r2 ;save VR21
L_co_switch$save_skip_vr21:
addi r2,r2,16 ;stride
andi. r0,r11,0x0200 ;check bit 22
beq L_co_switch$save_skip_vr22
stvx v22,r1,r2 ;save VR22
L_co_switch$save_skip_vr22:
addi r2,r2,16 ;stride
andi. r0,r11,0x0100 ;check bit 23
beq L_co_switch$save_skip_vr23
stvx v23,r1,r2 ;save VR23
L_co_switch$save_skip_vr23:
addi r2,r2,16 ;stride
andi. r0,r11,0x0080 ;check bit 24
beq L_co_switch$save_skip_vr24
stvx v24,r1,r2 ;save VR24
L_co_switch$save_skip_vr24:
addi r2,r2,16 ;stride
andi. r0,r11,0x0040 ;check bit 25
beq L_co_switch$save_skip_vr25
stvx v25,r1,r2 ;save VR25
L_co_switch$save_skip_vr25:
addi r2,r2,16 ;stride
andi. r0,r11,0x0020 ;check bit 26
beq L_co_switch$save_skip_vr26
stvx v26,r1,r2 ;save VR26
L_co_switch$save_skip_vr26:
addi r2,r2,16 ;stride
andi. r0,r11,0x0010 ;check bit 27
beq L_co_switch$save_skip_vr27
stvx v27,r1,r2 ;save VR27
L_co_switch$save_skip_vr27:
addi r2,r2,16 ;stride
andi. r0,r11,0x0008 ;check bit 28
beq L_co_switch$save_skip_vr28
stvx v28,r1,r2 ;save VR28
L_co_switch$save_skip_vr28:
addi r2,r2,16 ;stride
andi. r0,r11,0x0004 ;check bit 29
beq L_co_switch$save_skip_vr29
stvx v29,r1,r2 ;save VR29
L_co_switch$save_skip_vr29:
addi r2,r2,16 ;stride
andi. r0,r11,0x0002 ;check bit 30
beq L_co_switch$save_skip_vr30
stvx v30,r1,r2 ;save VR30
L_co_switch$save_skip_vr30:
addi r2,r2,16 ;stride
andi. r0,r11,0x0001 ;check bit 31
beq L_co_switch$save_skip_vr31
stvx v31,r1,r2 ;save VR31
L_co_switch$save_skip_vr31:
L_co_switch$save_no_vmx:
addis r4,r31,ha16(_co_active_context-L_co_switch$spb) ;save current context
ld r5,lo16(_co_active_context-L_co_switch$spb)(r4)
std r30,lo16(_co_active_context-L_co_switch$spb)(r4);set new context
std r1,0(r5) ;save current stack pointer
ld r1,0(r30) ;get new stack pointer
lwz r12,8(r30) ;have we already set GPR13 (system TLS)?
andis. r0,r12,0x8000
beq+ L_co_switch$gpr13_set
std r13,392(r1)
xoris r12,r12,0x8000
stw r12,8(r30)
L_co_switch$gpr13_set:
andis. r10,r8,0x4000 ;do we have Altivec/VMX?
beq L_co_switch$restore_no_vmx
lwz r11,240(r1) ;restore VRSAVE
andi. r0,r11,0x0FFF ;short-circuit if it's zero
mtspr 256,r11
beq L_co_switch$restore_no_vmx
andi. r0,r11,0x0800 ;check bit 20
addi r2,0,48 ;starting index
beq L_co_switch$restore_skip_vr20
lvx v20,r1,r2 ;restore VR20
L_co_switch$restore_skip_vr20:
addi r2,r2,16 ;stride
andi. r0,r11,0x0400 ;check bit 21
beq L_co_switch$restore_skip_vr21
lvx v21,r1,r2 ;restore VR21
L_co_switch$restore_skip_vr21:
addi r2,r2,16 ;stride
andi. r0,r11,0x0200 ;check bit 22
beq L_co_switch$restore_skip_vr22
lvx v22,r1,r2 ;restore VR22
L_co_switch$restore_skip_vr22:
addi r2,r2,16 ;stride
andi. r0,r11,0x0100 ;check bit 23
beq L_co_switch$restore_skip_vr23
lvx v23,r1,r2 ;restore VR23
L_co_switch$restore_skip_vr23:
addi r2,r2,16 ;stride
andi. r0,r11,0x0080 ;check bit 24
beq L_co_switch$restore_skip_vr24
lvx v24,r1,r2 ;restore VR24
L_co_switch$restore_skip_vr24:
addi r2,r2,16 ;stride
andi. r0,r11,0x0040 ;check bit 25
beq L_co_switch$restore_skip_vr25
lvx v25,r1,r2 ;restore VR25
L_co_switch$restore_skip_vr25:
addi r2,r2,16 ;stride
andi. r0,r11,0x0020 ;check bit 26
beq L_co_switch$restore_skip_vr26
lvx v26,r1,r2 ;restore VR26
L_co_switch$restore_skip_vr26:
addi r2,r2,16 ;stride
andi. r0,r11,0x0010 ;check bit 27
beq L_co_switch$restore_skip_vr27
lvx v27,r1,r2 ;restore VR27
L_co_switch$restore_skip_vr27:
addi r2,r2,16 ;stride
andi. r0,r11,0x0008 ;check bit 28
beq L_co_switch$restore_skip_vr28
lvx v28,r1,r2 ;restore VR28
L_co_switch$restore_skip_vr28:
addi r2,r2,16 ;stride
andi. r0,r11,0x0004 ;check bit 29
beq L_co_switch$restore_skip_vr29
lvx v29,r1,r2 ;restore VR29
L_co_switch$restore_skip_vr29:
addi r2,r2,16 ;stride
andi. r0,r11,0x0002 ;check bit 30
beq L_co_switch$restore_skip_vr30
lvx v30,r1,r2 ;restore VR30
L_co_switch$restore_skip_vr30:
addi r2,r2,16 ;stride
andi. r0,r11,0x0001 ;check bit 31
beq L_co_switch$restore_skip_vr31
lvx v31,r1,r2 ;restore VR31
L_co_switch$restore_skip_vr31:
L_co_switch$restore_no_vmx:
lfd f14,248(r1) ;restore preserved FPRs
lfd f15,256(r1)
lfd f16,264(r1)
lfd f17,272(r1)
lfd f18,280(r1)
lfd f19,288(r1)
lfd f20,296(r1)
lfd f21,304(r1)
lfd f22,312(r1)
lfd f23,320(r1)
lfd f24,328(r1)
lfd f25,336(r1)
lfd f26,344(r1)
lfd f27,352(r1)
lfd f28,360(r1)
lfd f29,368(r1)
lfd f30,376(r1)
lfd f31,384(r1)
addi r0,0,0 ;make thread main crash if it returns
ld r1,0(r1) ;deallocate stack frame
ld r6,16(r1) ;return address in GPR6
lwz r7,8(r1) ;condition codes in GPR7
ld r13,-152(r1) ;restore preserved GPRs
ld r14,-144(r1)
ld r15,-136(r1)
ld r16,-128(r1)
ld r17,-120(r1)
ld r18,-112(r1)
ld r19,-104(r1)
ld r20,-96(r1)
ld r21,-88(r1)
ld r22,-80(r1)
ld r23,-72(r1)
ld r24,-64(r1)
ld r25,-56(r1)
ld r26,-48(r1)
ld r27,-40(r1)
ld r28,-32(r1)
ld r29,-24(r1)
ld r30,-16(r1)
ld r31,-8(r1)
mtlr r0
mtctr r6 ;restore return address
mtcrf 32,r7 ;restore preserved condition codes
mtcrf 16,r7
mtcrf 8,r7
bctr ;return
;Import external functions
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
.align 5
L_malloc$stub:
.indirect_symbol _malloc
mflr r0
bcl 20,31,L_malloc$spb
L_malloc$spb:
mflr r11
addis r11,r11,ha16(L_malloc$lazy_ptr-L_malloc$spb)
mtlr r0
ldu r12,lo16(L_malloc$lazy_ptr-L_malloc$spb)(r11)
mtctr r12
bctr
.lazy_symbol_pointer
L_malloc$lazy_ptr:
.indirect_symbol _malloc
.quad dyld_stub_binding_helper
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
.align 5
L_free$stub:
.indirect_symbol _free
mflr r0
bcl 20,31,L_free$spb
L_free$spb:
mflr r11
addis r11,r11,ha16(L_free$lazy_ptr-L_free$spb)
mtlr r0
ldu r12,lo16(L_free$lazy_ptr-L_free$spb)(r11)
mtctr r12
bctr
.lazy_symbol_pointer
L_free$lazy_ptr:
.indirect_symbol _free
.quad dyld_stub_binding_helper
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
.align 5
L_sysctlbyname$stub:
.indirect_symbol _sysctlbyname
mflr r0
bcl 20,31,L_sysctlbyname$spb
L_sysctlbyname$spb:
mflr r11
addis r11,r11,ha16(L_sysctlbyname$lazy_ptr-L_sysctlbyname$spb)
mtlr r0
ldu r12,lo16(L_sysctlbyname$lazy_ptr-L_sysctlbyname$spb)(r11)
mtctr r12
bctr
.lazy_symbol_pointer
L_sysctlbyname$lazy_ptr:
.indirect_symbol _sysctlbyname
.quad dyld_stub_binding_helper
;This needs to be here!
.subsections_via_symbols

View File

@@ -45,11 +45,11 @@ namespace nall {
void set(string s) {
switch(type) {
case boolean_t: *(bool*)data = (s == "true"); break;
case signed_t: *(signed*)data = strsigned(s); break;
case unsigned_t: *(unsigned*)data = strunsigned(s); break;
case double_t: *(double*)data = strdouble(s); break;
case string_t: s.trim("\""); *(string*)data = s; break;
case boolean_t: *(bool*)data = (s == "true"); break;
case signed_t: *(signed*)data = integer(s); break;
case unsigned_t: *(unsigned*)data = decimal(s); break;
case double_t: *(double*)data = fp(s); break;
case string_t: s.trim("\""); *(string*)data = s; break;
}
}
};

View File

@@ -19,6 +19,7 @@ namespace nall {
struct library {
bool opened() const { return handle; }
bool open(const char*, const char* = "");
bool open_absolute(const char*);
void* sym(const char*);
void close();
@@ -40,6 +41,12 @@ namespace nall {
return handle;
}
inline bool library::open_absolute(const char *name) {
if(handle) close();
handle = (uintptr_t)dlopen(name, RTLD_LAZY);
return handle;
}
inline void* library::sym(const char *name) {
if(!handle) return 0;
return dlsym((void*)handle, name);
@@ -58,6 +65,12 @@ namespace nall {
return handle;
}
inline bool library::open_absolute(const char *name) {
if(handle) close();
handle = (uintptr_t)dlopen(name, RTLD_LAZY);
return handle;
}
inline void* library::sym(const char *name) {
if(!handle) return 0;
return dlsym((void*)handle, name);
@@ -76,6 +89,12 @@ namespace nall {
return handle;
}
inline bool library::open_absolute(const char *name) {
if(handle) close();
handle = (uintptr_t)LoadLibraryW(utf16_t(name));
return handle;
}
inline void* library::sym(const char *name) {
if(!handle) return 0;
return (void*)GetProcAddress((HMODULE)handle, name);

View File

@@ -92,7 +92,7 @@ struct Keyboard {
string s(name);
if(!strbegin(name, "KB")) return 0;
s.ltrim("KB");
unsigned id = strunsigned(s);
unsigned id = decimal(s);
auto pos = strpos(s, "::");
if(!pos) return 0;
s = substr(s, pos() + 2);
@@ -189,7 +189,7 @@ struct Mouse {
string s(name);
if(!strbegin(name, "MS")) return 0;
s.ltrim("MS");
unsigned id = strunsigned(s);
unsigned id = decimal(s);
auto pos = strpos(s, "::");
if(!pos) return 0;
s = substr(s, pos() + 2);
@@ -313,7 +313,7 @@ struct Joypad {
string s(name);
if(!strbegin(name, "JP")) return 0;
s.ltrim("JP");
unsigned id = strunsigned(s);
unsigned id = decimal(s);
auto pos = strpos(s, "::");
if(!pos) return 0;
s = substr(s, pos() + 2);

868
bsnes/nall/snes/cartridge.hpp Executable file
View File

@@ -0,0 +1,868 @@
#ifndef NALL_SNES_CARTRIDGE_HPP
#define NALL_SNES_CARTRIDGE_HPP
namespace nall {
class SNESCartridge {
public:
string xmlMemoryMap;
inline SNESCartridge(const uint8_t *data, unsigned size);
//private:
inline void read_header(const uint8_t *data, unsigned size);
inline unsigned find_header(const uint8_t *data, unsigned size);
inline unsigned score_header(const uint8_t *data, unsigned size, unsigned addr);
inline unsigned gameboy_ram_size(const uint8_t *data, unsigned size);
inline bool gameboy_has_rtc(const uint8_t *data, unsigned size);
enum HeaderField {
CartName = 0x00,
Mapper = 0x15,
RomType = 0x16,
RomSize = 0x17,
RamSize = 0x18,
CartRegion = 0x19,
Company = 0x1a,
Version = 0x1b,
Complement = 0x1c, //inverse checksum
Checksum = 0x1e,
ResetVector = 0x3c,
};
enum Mode {
ModeNormal,
ModeBsxSlotted,
ModeBsx,
ModeSufamiTurbo,
ModeSuperGameBoy,
};
enum Type {
TypeNormal,
TypeBsxSlotted,
TypeBsxBios,
TypeBsx,
TypeSufamiTurboBios,
TypeSufamiTurbo,
TypeSuperGameBoy1Bios,
TypeSuperGameBoy2Bios,
TypeGameBoy,
TypeUnknown,
};
enum Region {
NTSC,
PAL,
};
enum MemoryMapper {
LoROM,
HiROM,
ExLoROM,
ExHiROM,
SuperFXROM,
SA1ROM,
SPC7110ROM,
BSCLoROM,
BSCHiROM,
BSXROM,
STROM,
};
enum DSP1MemoryMapper {
DSP1Unmapped,
DSP1LoROM1MB,
DSP1LoROM2MB,
DSP1HiROM,
};
bool loaded; //is a base cartridge inserted?
unsigned crc32; //crc32 of all cartridges (base+slot(s))
unsigned rom_size;
unsigned ram_size;
Mode mode;
Type type;
Region region;
MemoryMapper mapper;
DSP1MemoryMapper dsp1_mapper;
bool has_bsx_slot;
bool has_superfx;
bool has_sa1;
bool has_srtc;
bool has_sdd1;
bool has_spc7110;
bool has_spc7110rtc;
bool has_cx4;
bool has_dsp1;
bool has_dsp2;
bool has_dsp3;
bool has_dsp4;
bool has_obc1;
bool has_st010;
bool has_st011;
bool has_st018;
};
SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
read_header(data, size);
string xml = "<?xml version='1.0' encoding='UTF-8'?>\n";
if(type == TypeBsx) {
xml << "<cartridge/>";
xmlMemoryMap = xml;
return;
}
if(type == TypeSufamiTurbo) {
xml << "<cartridge/>";
xmlMemoryMap = xml;
return;
}
if(type == TypeGameBoy) {
xml << "<cartridge rtc='" << gameboy_has_rtc(data, size) << "'>\n";
if(gameboy_ram_size(data, size) > 0) {
xml << " <ram size='" << hex(gameboy_ram_size(data, size)) << "'/>\n";
}
xml << "</cartridge>\n";
xmlMemoryMap = xml;
return;
}
xml << "<cartridge";
if(region == NTSC) {
xml << " region='NTSC'";
} else {
xml << " region='PAL'";
}
xml << ">\n";
if(type == TypeSuperGameBoy1Bios) {
xml << " <rom>\n";
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <supergameboy revision='1'>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:6000-7fff'/>\n";
xml << " <map address='80-bf:6000-7fff'/>\n";
xml << " </mmio>\n";
xml << " </supergameboy>\n";
} else if(type == TypeSuperGameBoy2Bios) {
xml << " <rom>\n";
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <supergameboy revision='2'>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:6000-7fff'/>\n";
xml << " <map address='80-bf:6000-7fff'/>\n";
xml << " </mmio>\n";
xml << " </supergameboy>\n";
} else if(has_spc7110) {
xml << " <rom>\n";
xml << " <map mode='shadow' address='00-0f:8000-ffff'/>\n";
xml << " <map mode='shadow' address='80-bf:8000-ffff'/>\n";
xml << " <map mode='linear' address='c0-cf:0000-ffff'/>\n";
xml << " </rom>\n";
xml << " <spc7110>\n";
xml << " <mcu>\n";
xml << " <map address='d0-ff:0000-ffff' offset='100000' size='" << hex(size - 0x100000) << "'/>\n";
xml << " </mcu>\n";
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='00:6000-7fff'/>\n";
xml << " <map mode='linear' address='30:6000-7fff'/>\n";
xml << " </ram>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:4800-483f'/>\n";
xml << " <map address='80-bf:4800-483f'/>\n";
xml << " </mmio>\n";
if(has_spc7110rtc) {
xml << " <rtc>\n";
xml << " <map address='00-3f:4840-4842'/>\n";
xml << " <map address='80-bf:4840-4842'/>\n";
xml << " </rtc>\n";
}
xml << " <dcu>\n";
xml << " <map address='50:0000-ffff'/>\n";
xml << " </dcu>\n";
xml << " </spc7110>\n";
} else if(mapper == LoROM) {
xml << " <rom>\n";
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
xml << " </rom>\n";
if(ram_size > 0) {
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
xml << " <map mode='linear' address='f0-ff:0000-7fff'/>\n";
} else {
xml << " <map mode='linear' address='70-7f:0000-ffff'/>\n";
xml << " <map mode='linear' address='f0-ff:0000-ffff'/>\n";
}
xml << " </ram>\n";
}
} else if(mapper == HiROM) {
xml << " <rom>\n";
xml << " <map mode='shadow' address='00-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='40-7f:0000-ffff'/>\n";
xml << " <map mode='shadow' address='80-bf:8000-ffff'/>\n";
xml << " <map mode='linear' address='c0-ff:0000-ffff'/>\n";
xml << " </rom>\n";
if(ram_size > 0) {
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
} else {
xml << " <map mode='linear' address='70-7f:0000-ffff'/>\n";
}
xml << " </ram>\n";
}
} else if(mapper == ExLoROM) {
xml << " <rom>\n";
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='40-7f:0000-ffff'/>\n";
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
xml << " </rom>\n";
if(ram_size > 0) {
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
xml << " </ram>\n";
}
} else if(mapper == ExHiROM) {
xml << " <rom>\n";
xml << " <map mode='shadow' address='00-3f:8000-ffff' offset='400000'/>\n";
xml << " <map mode='linear' address='40-7f:0000-ffff' offset='400000'/>\n";
xml << " <map mode='shadow' address='80-bf:8000-ffff' offset='000000'/>\n";
xml << " <map mode='linear' address='c0-ff:0000-ffff' offset='000000'/>\n";
xml << " </rom>\n";
if(ram_size > 0) {
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
} else {
xml << " <map mode='linear' address='70-7f:0000-ffff'/>\n";
}
xml << " </ram>\n";
}
} else if(mapper == SuperFXROM) {
xml << " <superfx revision='2'>\n";
xml << " <rom>\n";
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='40-5f:0000-ffff'/>\n";
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
xml << " <map mode='linear' address='c0-df:0000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='00-3f:6000-7fff' size='2000'/>\n";
xml << " <map mode='linear' address='60-7f:0000-ffff'/>\n";
xml << " <map mode='linear' address='80-bf:6000-7fff' size='2000'/>\n";
xml << " <map mode='linear' address='e0-ff:0000-ffff'/>\n";
xml << " </ram>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:3000-32ff'/>\n";
xml << " <map address='80-bf:3000-32ff'/>\n";
xml << " </mmio>\n";
xml << " </superfx>\n";
} else if(mapper == SA1ROM) {
xml << " <sa1>\n";
xml << " <rom>\n";
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
xml << " <map mode='linear' address='c0-ff:0000-ffff'/>\n";
xml << " </rom>\n";
xml << " <iram size='800'>\n";
xml << " <map mode='linear' address='00-3f:3000-37ff'/>\n";
xml << " <map mode='linear' address='80-bf:3000-37ff'/>\n";
xml << " </iram>\n";
xml << " <bwram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='00-3f:6000-7fff'/>\n";
xml << " <map mode='linear' address='40-4f:0000-ffff'/>\n";
xml << " <map mode='linear' address='80-bf:6000-7fff'/>\n";
xml << " </bwram>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:2200-23ff'/>\n";
xml << " <map address='80-bf:2200-23ff'/>\n";
xml << " </mmio>\n";
xml << " </sa1>\n";
} else if(mapper == BSCLoROM) {
xml << " <rom>\n";
xml << " <map mode='linear' address='00-1f:8000-ffff' offset='000000'/>\n";
xml << " <map mode='linear' address='20-3f:8000-ffff' offset='100000'/>\n";
xml << " <map mode='linear' address='80-9f:8000-ffff' offset='200000'/>\n";
xml << " <map mode='linear' address='a0-bf:8000-ffff' offset='100000'/>\n";
xml << " </rom>\n";
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
xml << " <map mode='linear' address='f0-ff:0000-7fff'/>\n";
xml << " </ram>\n";
xml << " <bsx>\n";
xml << " <slot>\n";
xml << " <map mode='linear' address='c0-ef:0000-ffff'/>\n";
xml << " </slot>\n";
xml << " </bsx>\n";
} else if(mapper == BSCHiROM) {
xml << " <rom>\n";
xml << " <map mode='shadow' address='00-1f:8000-ffff'/>\n";
xml << " <map mode='linear' address='40-5f:0000-ffff'/>\n";
xml << " <map mode='shadow' address='80-9f:8000-ffff'/>\n";
xml << " <map mode='linear' address='c0-df:0000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
xml << " </ram>\n";
xml << " <bsx>\n";
xml << " <slot>\n";
xml << " <map mode='shadow' address='20-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='60-7f:0000-ffff'/>\n";
xml << " <map mode='shadow' address='a0-bf:8000-ffff'/>\n";
xml << " <map mode='linear' address='e0-ff:0000-ffff'/>\n";
xml << " </slot>\n";
xml << " </bsx>\n";
} else if(mapper == BSXROM) {
xml << " <rom>\n";
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <bsx>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:5000-5fff'/>\n";
xml << " <map address='80-bf:5000-5fff'/>\n";
xml << " </mmio>\n";
xml << " </bsx>\n";
} else if(mapper == STROM) {
xml << " <rom>\n";
xml << " <map mode='linear' address='00-1f:8000-ffff'/>\n";
xml << " <map mode='linear' address='80-9f:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <sufamiturbo>\n";
xml << " <slot id='A'>\n";
xml << " <rom>\n";
xml << " <map mode='linear' address='20-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='a0-bf:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram>\n";
xml << " <map mode='linear' address='60-63:8000-ffff'/>\n";
xml << " <map mode='linear' address='e0-e3:8000-ffff'/>\n";
xml << " </ram>\n";
xml << " </slot>\n";
xml << " <slot id='B'>\n";
xml << " <rom>\n";
xml << " <map mode='linear' address='40-5f:8000-ffff'/>\n";
xml << " <map mode='linear' address='c0-df:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram>\n";
xml << " <map mode='linear' address='70-73:8000-ffff'/>\n";
xml << " <map mode='linear' address='f0-f3:8000-ffff'/>\n";
xml << " </ram>\n";
xml << " </slot>\n";
xml << " </sufamiturbo>\n";
}
if(has_srtc) {
xml << " <srtc>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:2800-2801'/>\n";
xml << " <map address='80-bf:2800-2801'/>\n";
xml << " </mmio>\n";
xml << " </srtc>\n";
}
if(has_sdd1) {
xml << " <sdd1>\n";
xml << " <mcu>\n";
xml << " <map address='c0-ff:0000-ffff'/>\n";
xml << " </mcu>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:4800-4807'/>\n";
xml << " <map address='80-bf:4800-4807'/>\n";
xml << " </mmio>\n";
xml << " </sdd1>\n";
}
if(has_cx4) {
xml << " <cx4>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:6000-7fff'/>\n";
xml << " <map address='80-bf:6000-7fff'/>\n";
xml << " </mmio>\n";
xml << " </cx4>\n";
}
if(has_dsp1) {
xml << " <upd77c25 program='dsp1b.bin' sha256='4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c'>\n";
if(dsp1_mapper == DSP1LoROM1MB) {
xml << " <dr>\n";
xml << " <map address='20-3f:8000-bfff'/>\n";
xml << " <map address='a0-bf:8000-bfff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='20-3f:c000-ffff'/>\n";
xml << " <map address='a0-bf:c000-ffff'/>\n";
xml << " </sr>\n";
} else if(dsp1_mapper == DSP1LoROM2MB) {
xml << " <dr>\n";
xml << " <map address='60-6f:0000-3fff'/>\n";
xml << " <map address='e0-ef:0000-3fff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='60-6f:4000-7fff'/>\n";
xml << " <map address='e0-ef:4000-7fff'/>\n";
xml << " </sr>\n";
} else if(dsp1_mapper == DSP1HiROM) {
xml << " <dr>\n";
xml << " <map address='00-1f:6000-6fff'/>\n";
xml << " <map address='80-9f:6000-6fff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='00-1f:7000-7fff'/>\n";
xml << " <map address='80-9f:7000-7fff'/>\n";
xml << " </sr>\n";
}
xml << " </upd77c25>\n";
}
if(has_dsp2) {
xml << " <upd77c25 program='dsp2.bin' sha256='5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1'>\n";
xml << " <dr>\n";
xml << " <map address='20-3f:8000-bfff'/>\n";
xml << " <map address='a0-bf:8000-bfff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='20-3f:c000-ffff'/>\n";
xml << " <map address='a0-bf:c000-ffff'/>\n";
xml << " </sr>\n";
xml << " </upd77c25>\n";
}
if(has_dsp3) {
xml << " <upd77c25 program='dsp3.bin' sha256='2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90'>\n";
xml << " <dr>\n";
xml << " <map address='20-3f:8000-bfff'/>\n";
xml << " <map address='a0-bf:8000-bfff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='20-3f:c000-ffff'/>\n";
xml << " <map address='a0-bf:c000-ffff'/>\n";
xml << " </sr>\n";
xml << " </upd77c25>\n";
}
if(has_dsp4) {
xml << " <upd77c25 program='dsp4.bin' sha256='63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a'>\n";
xml << " <dr>\n";
xml << " <map address='30-3f:8000-bfff'/>\n";
xml << " <map address='b0-bf:8000-bfff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='30-3f:c000-ffff'/>\n";
xml << " <map address='b0-bf:c000-ffff'/>\n";
xml << " </sr>\n";
xml << " </upd77c25>\n";
}
if(has_obc1) {
xml << " <obc1>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:6000-7fff'/>\n";
xml << " <map address='80-bf:6000-7fff'/>\n";
xml << " </mmio>\n";
xml << " </obc1>\n";
}
if(has_st010) {
xml << " <setadsp program='ST-0010'>\n";
xml << " <mmio>\n";
xml << " <map address='68-6f:0000-0fff'/>\n";
xml << " <map address='e8-ef:0000-0fff'/>\n";
xml << " </mmio>\n";
xml << " </setadsp>\n";
}
if(has_st011) {
//ST-0011 addresses not verified; chip is unsupported
xml << " <setadsp program='ST-0011'>\n";
xml << " <mmio>\n";
xml << " <map address='68-6f:0000-0fff'/>\n";
xml << " <map address='e8-ef:0000-0fff'/>\n";
xml << " </mmio>\n";
xml << " </setadsp>\n";
}
if(has_st018) {
xml << " <setarisc program='ST-0018'>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:3800-38ff'/>\n";
xml << " <map address='80-bf:3800-38ff'/>\n";
xml << " </mmio>\n";
xml << " </setarisc>\n";
}
xml << "</cartridge>\n";
xmlMemoryMap = xml;
}
void SNESCartridge::read_header(const uint8_t *data, unsigned size) {
type = TypeUnknown;
mapper = LoROM;
dsp1_mapper = DSP1Unmapped;
region = NTSC;
rom_size = size;
ram_size = 0;
has_bsx_slot = false;
has_superfx = false;
has_sa1 = false;
has_srtc = false;
has_sdd1 = false;
has_spc7110 = false;
has_spc7110rtc = false;
has_cx4 = false;
has_dsp1 = false;
has_dsp2 = false;
has_dsp3 = false;
has_dsp4 = false;
has_obc1 = false;
has_st010 = false;
has_st011 = false;
has_st018 = false;
//=====================
//detect Game Boy carts
//=====================
if(size >= 0x0140) {
if(data[0x0104] == 0xce && data[0x0105] == 0xed && data[0x0106] == 0x66 && data[0x0107] == 0x66
&& data[0x0108] == 0xcc && data[0x0109] == 0x0d && data[0x010a] == 0x00 && data[0x010b] == 0x0b) {
type = TypeGameBoy;
return;
}
}
if(size < 32768) {
type = TypeUnknown;
return;
}
const unsigned index = find_header(data, size);
const uint8_t mapperid = data[index + Mapper];
const uint8_t rom_type = data[index + RomType];
const uint8_t rom_size = data[index + RomSize];
const uint8_t company = data[index + Company];
const uint8_t regionid = data[index + CartRegion] & 0x7f;
ram_size = 1024 << (data[index + RamSize] & 7);
if(ram_size == 1024) ram_size = 0; //no RAM present
//0, 1, 13 = NTSC; 2 - 12 = PAL
region = (regionid <= 1 || regionid >= 13) ? NTSC : PAL;
//=======================
//detect BS-X flash carts
//=======================
if(data[index + 0x13] == 0x00 || data[index + 0x13] == 0xff) {
if(data[index + 0x14] == 0x00) {
const uint8_t n15 = data[index + 0x15];
if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) {
if(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) {
type = TypeBsx;
mapper = BSXROM;
region = NTSC; //BS-X only released in Japan
return;
}
}
}
}
//=========================
//detect Sufami Turbo carts
//=========================
if(!memcmp(data, "BANDAI SFC-ADX", 14)) {
if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) {
type = TypeSufamiTurboBios;
} else {
type = TypeSufamiTurbo;
}
mapper = STROM;
region = NTSC; //Sufami Turbo only released in Japan
return; //RAM size handled outside this routine
}
//==========================
//detect Super Game Boy BIOS
//==========================
if(!memcmp(data + index, "Super GAMEBOY2", 14)) {
type = TypeSuperGameBoy2Bios;
return;
}
if(!memcmp(data + index, "Super GAMEBOY", 13)) {
type = TypeSuperGameBoy1Bios;
return;
}
//=====================
//detect standard carts
//=====================
//detect presence of BS-X flash cartridge connector (reads extended header information)
if(data[index - 14] == 'Z') {
if(data[index - 11] == 'J') {
uint8_t n13 = data[index - 13];
if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) {
if(company == 0x33 || (data[index - 10] == 0x00 && data[index - 4] == 0x00)) {
has_bsx_slot = true;
}
}
}
}
if(has_bsx_slot) {
if(!memcmp(data + index, "Satellaview BS-X ", 21)) {
//BS-X base cart
type = TypeBsxBios;
mapper = BSXROM;
region = NTSC; //BS-X only released in Japan
return; //RAM size handled internally by load_cart_bsx() -> BSXCart class
} else {
type = TypeBsxSlotted;
mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM);
region = NTSC; //BS-X slotted cartridges only released in Japan
}
} else {
//standard cart
type = TypeNormal;
if(index == 0x7fc0 && size >= 0x401000) {
mapper = ExLoROM;
} else if(index == 0x7fc0 && mapperid == 0x32) {
mapper = ExLoROM;
} else if(index == 0x7fc0) {
mapper = LoROM;
} else if(index == 0xffc0) {
mapper = HiROM;
} else { //index == 0x40ffc0
mapper = ExHiROM;
}
}
if(mapperid == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
has_superfx = true;
mapper = SuperFXROM;
ram_size = 1024 << (data[index - 3] & 7);
if(ram_size == 1024) ram_size = 0;
}
if(mapperid == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) {
has_sa1 = true;
mapper = SA1ROM;
}
if(mapperid == 0x35 && rom_type == 0x55) {
has_srtc = true;
}
if(mapperid == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
has_sdd1 = true;
}
if(mapperid == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) {
has_spc7110 = true;
has_spc7110rtc = (rom_type == 0xf9);
mapper = SPC7110ROM;
}
if(mapperid == 0x20 && rom_type == 0xf3) {
has_cx4 = true;
}
if((mapperid == 0x20 || mapperid == 0x21) && rom_type == 0x03) {
has_dsp1 = true;
}
if(mapperid == 0x30 && rom_type == 0x05 && company != 0xb2) {
has_dsp1 = true;
}
if(mapperid == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) {
has_dsp1 = true;
}
if(has_dsp1 == true) {
if((mapperid & 0x2f) == 0x20 && size <= 0x100000) {
dsp1_mapper = DSP1LoROM1MB;
} else if((mapperid & 0x2f) == 0x20) {
dsp1_mapper = DSP1LoROM2MB;
} else if((mapperid & 0x2f) == 0x21) {
dsp1_mapper = DSP1HiROM;
}
}
if(mapperid == 0x20 && rom_type == 0x05) {
has_dsp2 = true;
}
if(mapperid == 0x30 && rom_type == 0x05 && company == 0xb2) {
has_dsp3 = true;
}
if(mapperid == 0x30 && rom_type == 0x03) {
has_dsp4 = true;
}
if(mapperid == 0x30 && rom_type == 0x25) {
has_obc1 = true;
}
if(mapperid == 0x30 && rom_type == 0xf6 && rom_size >= 10) {
has_st010 = true;
}
if(mapperid == 0x30 && rom_type == 0xf6 && rom_size < 10) {
has_st011 = true;
}
if(mapperid == 0x30 && rom_type == 0xf5) {
has_st018 = true;
}
}
unsigned SNESCartridge::find_header(const uint8_t *data, unsigned size) {
unsigned score_lo = score_header(data, size, 0x007fc0);
unsigned score_hi = score_header(data, size, 0x00ffc0);
unsigned score_ex = score_header(data, size, 0x40ffc0);
if(score_ex) score_ex += 4; //favor ExHiROM on images > 32mbits
if(score_lo >= score_hi && score_lo >= score_ex) {
return 0x007fc0;
} else if(score_hi >= score_ex) {
return 0x00ffc0;
} else {
return 0x40ffc0;
}
}
unsigned SNESCartridge::score_header(const uint8_t *data, unsigned size, unsigned addr) {
if(size < addr + 64) return 0; //image too small to contain header at this location?
int score = 0;
uint16_t resetvector = data[addr + ResetVector] | (data[addr + ResetVector + 1] << 8);
uint16_t checksum = data[addr + Checksum ] | (data[addr + Checksum + 1] << 8);
uint16_t complement = data[addr + Complement ] | (data[addr + Complement + 1] << 8);
uint8_t resetop = data[(addr & ~0x7fff) | (resetvector & 0x7fff)]; //first opcode executed upon reset
uint8_t mapper = data[addr + Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit
//$00:[000-7fff] contains uninitialized RAM and MMIO.
//reset vector must point to ROM at $00:[8000-ffff] to be considered valid.
if(resetvector < 0x8000) return 0;
//some images duplicate the header in multiple locations, and others have completely
//invalid header information that cannot be relied upon.
//below code will analyze the first opcode executed at the specified reset vector to
//determine the probability that this is the correct header.
//most likely opcodes
if(resetop == 0x78 //sei
|| resetop == 0x18 //clc (clc; xce)
|| resetop == 0x38 //sec (sec; xce)
|| resetop == 0x9c //stz $nnnn (stz $4200)
|| resetop == 0x4c //jmp $nnnn
|| resetop == 0x5c //jml $nnnnnn
) score += 8;
//plausible opcodes
if(resetop == 0xc2 //rep #$nn
|| resetop == 0xe2 //sep #$nn
|| resetop == 0xad //lda $nnnn
|| resetop == 0xae //ldx $nnnn
|| resetop == 0xac //ldy $nnnn
|| resetop == 0xaf //lda $nnnnnn
|| resetop == 0xa9 //lda #$nn
|| resetop == 0xa2 //ldx #$nn
|| resetop == 0xa0 //ldy #$nn
|| resetop == 0x20 //jsr $nnnn
|| resetop == 0x22 //jsl $nnnnnn
) score += 4;
//implausible opcodes
if(resetop == 0x40 //rti
|| resetop == 0x60 //rts
|| resetop == 0x6b //rtl
|| resetop == 0xcd //cmp $nnnn
|| resetop == 0xec //cpx $nnnn
|| resetop == 0xcc //cpy $nnnn
) score -= 4;
//least likely opcodes
if(resetop == 0x00 //brk #$nn
|| resetop == 0x02 //cop #$nn
|| resetop == 0xdb //stp
|| resetop == 0x42 //wdm
|| resetop == 0xff //sbc $nnnnnn,x
) score -= 8;
//at times, both the header and reset vector's first opcode will match ...
//fallback and rely on info validity in these cases to determine more likely header.
//a valid checksum is the biggest indicator of a valid header.
if((checksum + complement) == 0xffff && (checksum != 0) && (complement != 0)) score += 4;
if(addr == 0x007fc0 && mapper == 0x20) score += 2; //0x20 is usually LoROM
if(addr == 0x00ffc0 && mapper == 0x21) score += 2; //0x21 is usually HiROM
if(addr == 0x007fc0 && mapper == 0x22) score += 2; //0x22 is usually ExLoROM
if(addr == 0x40ffc0 && mapper == 0x25) score += 2; //0x25 is usually ExHiROM
if(data[addr + Company] == 0x33) score += 2; //0x33 indicates extended header
if(data[addr + RomType] < 0x08) score++;
if(data[addr + RomSize] < 0x10) score++;
if(data[addr + RamSize] < 0x08) score++;
if(data[addr + CartRegion] < 14) score++;
if(score < 0) score = 0;
return score;
}
unsigned SNESCartridge::gameboy_ram_size(const uint8_t *data, unsigned size) {
if(size < 512) return 0;
switch(data[0x0149]) {
case 0x00: return 0 * 1024;
case 0x01: return 8 * 1024;
case 0x02: return 8 * 1024;
case 0x03: return 32 * 1024;
case 0x04: return 128 * 1024;
case 0x05: return 128 * 1024;
default: return 128 * 1024;
}
}
bool SNESCartridge::gameboy_has_rtc(const uint8_t *data, unsigned size) {
if(size < 512) return false;
if(data[0x0147] == 0x0f ||data[0x0147] == 0x10) return true;
return false;
}
}
#endif

458
bsnes/nall/snes/cpu.hpp Executable file
View File

@@ -0,0 +1,458 @@
#ifndef NALL_SNES_CPU_HPP
#define NALL_SNES_CPU_HPP
namespace nall {
struct SNESCPU {
enum : unsigned {
Implied, //
Constant, //#$00
AccumConstant, //#$00
IndexConstant, //#$00
Direct, //$00
DirectX, //$00,x
DirectY, //$00,y
IDirect, //($00)
IDirectX, //($00,x)
IDirectY, //($00),y
ILDirect, //[$00]
ILDirectY, //[$00],y
Address, //$0000
AddressX, //$0000,x
AddressY, //$0000,y
IAddressX, //($0000,x)
ILAddress, //[$0000]
PAddress, //PBR:$0000
PIAddress, //PBR:($0000)
Long, //$000000
LongX, //$000000,x
Stack, //$00,s
IStackY, //($00,s),y
BlockMove, //$00,$00
RelativeShort, //+/- $00
RelativeLong, //+/- $0000
};
struct OpcodeInfo {
char name[4];
unsigned mode;
};
static const OpcodeInfo opcodeInfo[256];
static unsigned getOpcodeLength(bool accum, bool index, uint8_t opcode);
static string disassemble(unsigned pc, bool accum, bool index, uint8_t opcode, uint8_t pl, uint8_t ph, uint8_t pb);
};
const SNESCPU::OpcodeInfo SNESCPU::opcodeInfo[256] = {
//0x00 - 0x0f
{ "brk", Constant },
{ "ora", IDirectX },
{ "cop", Constant },
{ "ora", Stack },
{ "tsb", Direct },
{ "ora", Direct },
{ "asl", Direct },
{ "ora", ILDirect },
{ "php", Implied },
{ "ora", AccumConstant },
{ "asl", Implied },
{ "phd", Implied },
{ "tsb", Address },
{ "ora", Address },
{ "asl", Address },
{ "ora", Long },
//0x10 - 0x1f
{ "bpl", RelativeShort },
{ "ora", IDirectY },
{ "ora", IDirect },
{ "ora", IStackY },
{ "trb", Direct },
{ "ora", DirectX },
{ "asl", DirectX },
{ "ora", ILDirectY },
{ "clc", Implied },
{ "ora", AddressY },
{ "inc", Implied },
{ "tcs", Implied },
{ "trb", Address },
{ "ora", AddressX },
{ "asl", AddressX },
{ "ora", LongX },
//0x20 - 0x2f
{ "jsr", Address },
{ "and", IDirectX },
{ "jsl", Long },
{ "and", Stack },
{ "bit", Direct },
{ "and", Direct },
{ "rol", Direct },
{ "and", ILDirect },
{ "plp", Implied },
{ "and", AccumConstant },
{ "rol", Implied },
{ "pld", Implied },
{ "bit", Address },
{ "and", Address },
{ "rol", Address },
{ "and", Long },
//0x30 - 0x3f
{ "bmi", RelativeShort },
{ "and", IDirectY },
{ "and", IDirect },
{ "and", IStackY },
{ "bit", DirectX },
{ "and", DirectX },
{ "rol", DirectX },
{ "and", ILDirectY },
{ "sec", Implied },
{ "and", AddressY },
{ "dec", Implied },
{ "tsc", Implied },
{ "bit", AddressX },
{ "and", AddressX },
{ "rol", AddressX },
{ "and", LongX },
//0x40 - 0x4f
{ "rti", Implied },
{ "eor", IDirectX },
{ "wdm", Constant },
{ "eor", Stack },
{ "mvp", BlockMove },
{ "eor", Direct },
{ "lsr", Direct },
{ "eor", ILDirect },
{ "pha", Implied },
{ "eor", AccumConstant },
{ "lsr", Implied },
{ "phk", Implied },
{ "jmp", PAddress },
{ "eor", Address },
{ "lsr", Address },
{ "eor", Long },
//0x50 - 0x5f
{ "bvc", RelativeShort },
{ "eor", IDirectY },
{ "eor", IDirect },
{ "eor", IStackY },
{ "mvn", BlockMove },
{ "eor", DirectX },
{ "lsr", DirectX },
{ "eor", ILDirectY },
{ "cli", Implied },
{ "eor", AddressY },
{ "phy", Implied },
{ "tcd", Implied },
{ "jml", Long },
{ "eor", AddressX },
{ "lsr", AddressX },
{ "eor", LongX },
//0x60 - 0x6f
{ "rts", Implied },
{ "adc", IDirectX },
{ "per", Address },
{ "adc", Stack },
{ "stz", Direct },
{ "adc", Direct },
{ "ror", Direct },
{ "adc", ILDirect },
{ "pla", Implied },
{ "adc", AccumConstant },
{ "ror", Implied },
{ "rtl", Implied },
{ "jmp", PIAddress },
{ "adc", Address },
{ "ror", Address },
{ "adc", Long },
//0x70 - 0x7f
{ "bvs", RelativeShort },
{ "adc", IDirectY },
{ "adc", IDirect },
{ "adc", IStackY },
{ "stz", DirectX },
{ "adc", DirectX },
{ "ror", DirectX },
{ "adc", ILDirectY },
{ "sei", Implied },
{ "adc", AddressY },
{ "ply", Implied },
{ "tdc", Implied },
{ "jmp", IAddressX },
{ "adc", AddressX },
{ "ror", AddressX },
{ "adc", LongX },
//0x80 - 0x8f
{ "bra", RelativeShort },
{ "sta", IDirectX },
{ "brl", RelativeLong },
{ "sta", Stack },
{ "sty", Direct },
{ "sta", Direct },
{ "stx", Direct },
{ "sta", ILDirect },
{ "dey", Implied },
{ "bit", AccumConstant },
{ "txa", Implied },
{ "phb", Implied },
{ "sty", Address },
{ "sta", Address },
{ "stx", Address },
{ "sta", Long },
//0x90 - 0x9f
{ "bcc", RelativeShort },
{ "sta", IDirectY },
{ "sta", IDirect },
{ "sta", IStackY },
{ "sty", DirectX },
{ "sta", DirectX },
{ "stx", DirectY },
{ "sta", ILDirectY },
{ "tya", Implied },
{ "sta", AddressY },
{ "txs", Implied },
{ "txy", Implied },
{ "stz", Address },
{ "sta", AddressX },
{ "stz", AddressX },
{ "sta", LongX },
//0xa0 - 0xaf
{ "ldy", IndexConstant },
{ "lda", IDirectX },
{ "ldx", IndexConstant },
{ "lda", Stack },
{ "ldy", Direct },
{ "lda", Direct },
{ "ldx", Direct },
{ "lda", ILDirect },
{ "tay", Implied },
{ "lda", AccumConstant },
{ "tax", Implied },
{ "plb", Implied },
{ "ldy", Address },
{ "lda", Address },
{ "ldx", Address },
{ "lda", Long },
//0xb0 - 0xbf
{ "bcs", RelativeShort },
{ "lda", IDirectY },
{ "lda", IDirect },
{ "lda", IStackY },
{ "ldy", DirectX },
{ "lda", DirectX },
{ "ldx", DirectY },
{ "lda", ILDirectY },
{ "clv", Implied },
{ "lda", AddressY },
{ "tsx", Implied },
{ "tyx", Implied },
{ "ldy", AddressX },
{ "lda", AddressX },
{ "ldx", AddressY },
{ "lda", LongX },
//0xc0 - 0xcf
{ "cpy", IndexConstant },
{ "cmp", IDirectX },
{ "rep", Constant },
{ "cmp", Stack },
{ "cpy", Direct },
{ "cmp", Direct },
{ "dec", Direct },
{ "cmp", ILDirect },
{ "iny", Implied },
{ "cmp", AccumConstant },
{ "dex", Implied },
{ "wai", Implied },
{ "cpy", Address },
{ "cmp", Address },
{ "dec", Address },
{ "cmp", Long },
//0xd0 - 0xdf
{ "bne", RelativeShort },
{ "cmp", IDirectY },
{ "cmp", IDirect },
{ "cmp", IStackY },
{ "pei", IDirect },
{ "cmp", DirectX },
{ "dec", DirectX },
{ "cmp", ILDirectY },
{ "cld", Implied },
{ "cmp", AddressY },
{ "phx", Implied },
{ "stp", Implied },
{ "jmp", ILAddress },
{ "cmp", AddressX },
{ "dec", AddressX },
{ "cmp", LongX },
//0xe0 - 0xef
{ "cpx", IndexConstant },
{ "sbc", IDirectX },
{ "sep", Constant },
{ "sbc", Stack },
{ "cpx", Direct },
{ "sbc", Direct },
{ "inc", Direct },
{ "sbc", ILDirect },
{ "inx", Implied },
{ "sbc", AccumConstant },
{ "nop", Implied },
{ "xba", Implied },
{ "cpx", Address },
{ "sbc", Address },
{ "inc", Address },
{ "sbc", Long },
//0xf0 - 0xff
{ "beq", RelativeShort },
{ "sbc", IDirectY },
{ "sbc", IDirect },
{ "sbc", IStackY },
{ "pea", Address },
{ "sbc", DirectX },
{ "inc", DirectX },
{ "sbc", ILDirectY },
{ "sed", Implied },
{ "sbc", AddressY },
{ "plx", Implied },
{ "xce", Implied },
{ "jsr", IAddressX },
{ "sbc", AddressX },
{ "inc", AddressX },
{ "sbc", LongX },
};
inline unsigned SNESCPU::getOpcodeLength(bool accum, bool index, uint8_t opcode) {
switch(opcodeInfo[opcode].mode) { default:
case Implied: return 1;
case Constant: return 2;
case AccumConstant: return 3 - accum;
case IndexConstant: return 3 - index;
case Direct: return 2;
case DirectX: return 2;
case DirectY: return 2;
case IDirect: return 2;
case IDirectX: return 2;
case IDirectY: return 2;
case ILDirect: return 2;
case ILDirectY: return 2;
case Address: return 3;
case AddressX: return 3;
case AddressY: return 3;
case IAddressX: return 3;
case ILAddress: return 3;
case PAddress: return 3;
case PIAddress: return 3;
case Long: return 4;
case LongX: return 4;
case Stack: return 2;
case IStackY: return 2;
case BlockMove: return 3;
case RelativeShort: return 2;
case RelativeLong: return 3;
}
}
inline string SNESCPU::disassemble(unsigned pc, bool accum, bool index, uint8_t opcode, uint8_t pl, uint8_t ph, uint8_t pb) {
string name = opcodeInfo[opcode].name;
unsigned mode = opcodeInfo[opcode].mode;
if(mode == Implied) return name;
if(mode == Constant) return { name, " #$", hex<2>(pl) };
if(mode == AccumConstant) return { name, " #$", accum ? "" : hex<2>(ph), hex<2>(pl) };
if(mode == IndexConstant) return { name, " #$", index ? "" : hex<2>(ph), hex<2>(pl) };
if(mode == Direct) return { name, " $", hex<2>(pl) };
if(mode == DirectX) return { name, " $", hex<2>(pl), ",x" };
if(mode == DirectY) return { name, " $", hex<2>(pl), ",y" };
if(mode == IDirect) return { name, " ($", hex<2>(pl), ")" };
if(mode == IDirectX) return { name, " ($", hex<2>(pl), ",x)" };
if(mode == IDirectY) return { name, " ($", hex<2>(pl), "),y" };
if(mode == ILDirect) return { name, " [$", hex<2>(pl), "]" };
if(mode == ILDirectY) return { name, " [$", hex<2>(pl), "],y" };
if(mode == Address) return { name, " $", hex<2>(ph), hex<2>(pl) };
if(mode == AddressX) return { name, " $", hex<2>(ph), hex<2>(pl), ",x" };
if(mode == AddressY) return { name, " $", hex<2>(ph), hex<2>(pl), ",y" };
if(mode == IAddressX) return { name, " ($", hex<2>(ph), hex<2>(pl), ",x)" };
if(mode == ILAddress) return { name, " [$", hex<2>(ph), hex<2>(pl), "]" };
if(mode == PAddress) return { name, " $", hex<2>(ph), hex<2>(pl) };
if(mode == PIAddress) return { name, " ($", hex<2>(ph), hex<2>(pl), ")" };
if(mode == Long) return { name, " $", hex<2>(pb), hex<2>(ph), hex<2>(pl) };
if(mode == LongX) return { name, " $", hex<2>(pb), hex<2>(ph), hex<2>(pl), ",x" };
if(mode == Stack) return { name, " $", hex<2>(pl), ",s" };
if(mode == IStackY) return { name, " ($", hex<2>(pl), ",s),y" };
if(mode == BlockMove) return { name, " $", hex<2>(ph), ",$", hex<2>(pl) };
if(mode == RelativeShort) {
unsigned addr = (pc + 2) + (int8_t)(pl << 0);
return { name, " $", hex<4>(addr) };
}
if(mode == RelativeLong) {
unsigned addr = (pc + 3) + (int16_t)((ph << 8) + (pl << 0));
return { name, " $", hex<4>(addr) };
}
return "";
}
}
#endif

639
bsnes/nall/snes/smp.hpp Executable file
View File

@@ -0,0 +1,639 @@
#ifndef NALL_SNES_SMP_HPP
#define NALL_SNES_SMP_HPP
namespace nall {
struct SNESSMP {
enum : unsigned {
Implied, //
TVector, //0
Direct, //$00
DirectRelative, //$00,+/-$00
ADirect, //a,$00
AAbsolute, //a,$0000
AIX, //a,(x)
AIDirectX, //a,($00+x)
AConstant, //a,#$00
DirectDirect, //$00,$00
CAbsoluteBit, //c,$0000:0
Absolute, //$0000
P, //p
AbsoluteA, //$0000,a
Relative, //+/-$00
ADirectX, //a,$00+x
AAbsoluteX, //a,$0000+x
AAbsoluteY, //a,$0000+y
AIDirectY, //a,($00)+y
DirectConstant, //$00,#$00
IXIY, //(x),(y)
DirectX, //$00+x
A, //a
X, //x
XAbsolute, //x,$0000
IAbsoluteX, //($0000+x)
CNAbsoluteBit, //c,!$0000:0
XDirect, //x,$00
PVector, //$ff00
YaDirect, //ya,$00
XA, //x,a
YAbsolute, //y,$0000
Y, //y
AX, //a,x
YDirect, //y,$00
YConstant, //y,#$00
XSp, //x,sp
YaX, //ya,x
IXPA, //(x)+,a
SpX, //sp,x
AIXP, //a,(x)+
DirectA, //$00,a
IXA, //(x),a
IDirectXA, //($00+x),a
XConstant, //x,#$00
AbsoluteX, //$0000,x
AbsoluteBitC, //$0000:0,c
DirectY, //$00,y
AbsoluteY, //$0000,y
Ya, //ya
DirectXA, //$00+x,a
AbsoluteXA, //$0000+x,a
AbsoluteYA, //$0000+y,a
IDirectYA, //($00)+y,a
DirectYX, //$00+y,x
DirectYa, //$00,ya
DirectXY, //$00+x,y
AY, //a,y
DirectXRelative, //$00+x,+/-$00
XDirectY, //x,$00+y
YDirectX, //y,$00+x
YA, //y,a
YRelative, //y,+/-$00
};
struct OpcodeInfo {
char name[6];
unsigned mode;
};
static const OpcodeInfo opcodeInfo[256];
static unsigned getOpcodeLength(uint8_t opcode);
static string disassemble(uint16_t pc, uint8_t opcode, uint8_t pl, uint8_t ph);
static string disassemble(uint16_t pc, bool p, uint8_t opcode, uint8_t pl, uint8_t ph);
};
const SNESSMP::OpcodeInfo SNESSMP::opcodeInfo[256] = {
//0x00 - 0x0f
{ "nop ", Implied },
{ "tcall", TVector },
{ "set0 ", Direct },
{ "bbs0 ", DirectRelative },
{ "or ", ADirect },
{ "or ", AAbsolute },
{ "or ", AIX },
{ "or ", AIDirectX },
{ "or ", AConstant },
{ "or ", DirectDirect },
{ "or1 ", CAbsoluteBit },
{ "asl ", Direct },
{ "asl ", Absolute },
{ "push ", P },
{ "tset ", AbsoluteA },
{ "brk ", Implied },
//0x10 - 0x1f
{ "bpl ", Relative },
{ "tcall", TVector },
{ "clr0 ", Direct },
{ "bbc0 ", DirectRelative },
{ "or ", ADirectX },
{ "or ", AAbsoluteX },
{ "or ", AAbsoluteY },
{ "or ", AIDirectY },
{ "or ", DirectConstant },
{ "or ", IXIY },
{ "decw ", Direct },
{ "asl ", DirectX },
{ "asl ", A },
{ "dec ", X },
{ "cmp ", XAbsolute },
{ "jmp ", IAbsoluteX },
//0x20 - 0x2f
{ "clrp ", Implied },
{ "tcall", TVector },
{ "set1 ", Direct },
{ "bbs1 ", DirectRelative },
{ "and ", ADirect },
{ "and ", AAbsolute },
{ "and ", AIX },
{ "and ", AIDirectX },
{ "and ", AConstant },
{ "and ", DirectDirect },
{ "or1 ", CNAbsoluteBit },
{ "rol ", Direct },
{ "rol ", Absolute },
{ "push ", A },
{ "cbne ", DirectRelative },
{ "bra ", Relative },
//0x30 - 0x3f
{ "bmi ", Relative },
{ "tcall", TVector },
{ "clr1 ", Direct },
{ "bbc1 ", DirectRelative },
{ "and ", ADirectX },
{ "and ", AAbsoluteX },
{ "and ", AAbsoluteY },
{ "and ", AIDirectY },
{ "and ", DirectConstant },
{ "and ", IXIY },
{ "incw ", Direct },
{ "rol ", DirectX },
{ "rol ", A },
{ "inc ", X },
{ "cmp ", XDirect },
{ "call ", Absolute },
//0x40 - 0x4f
{ "setp ", Implied },
{ "tcall", TVector },
{ "set2 ", Direct },
{ "bbs2 ", DirectRelative },
{ "eor ", ADirect },
{ "eor ", AAbsolute },
{ "eor ", AIX },
{ "eor ", AIDirectX },
{ "eor ", AConstant },
{ "eor ", DirectDirect },
{ "and1 ", CAbsoluteBit },
{ "lsr ", Direct },
{ "lsr ", Absolute },
{ "push ", X },
{ "tclr ", AbsoluteA },
{ "pcall", PVector },
//0x50 - 0x5f
{ "bvc ", Relative },
{ "tcall", TVector },
{ "clr2 ", Direct },
{ "bbc2 ", DirectRelative },
{ "eor ", ADirectX },
{ "eor ", AAbsoluteX },
{ "eor ", AAbsoluteY },
{ "eor ", AIDirectY },
{ "eor ", DirectConstant },
{ "eor ", IXIY },
{ "cmpw ", YaDirect },
{ "lsr ", DirectX },
{ "lsr ", A },
{ "mov ", XA },
{ "cmp ", YAbsolute },
{ "jmp ", Absolute },
//0x60 - 0x6f
{ "clrc ", Implied },
{ "tcall", TVector },
{ "set3 ", Direct },
{ "bbs3 ", DirectRelative },
{ "cmp ", ADirect },
{ "cmp ", AAbsolute },
{ "cmp ", AIX },
{ "cmp ", AIDirectX },
{ "cmp ", AConstant },
{ "cmp ", DirectDirect },
{ "and1 ", CNAbsoluteBit },
{ "ror ", Direct },
{ "ror ", Absolute },
{ "push ", Y },
{ "dbnz ", DirectRelative },
{ "ret ", Implied },
//0x70 - 0x7f
{ "bvs ", Relative },
{ "tcall", TVector },
{ "clr3 ", Direct },
{ "bbc3 ", DirectRelative },
{ "cmp ", ADirectX },
{ "cmp ", AAbsoluteX },
{ "cmp ", AAbsoluteY },
{ "cmp ", AIDirectY },
{ "cmp ", DirectConstant },
{ "cmp ", IXIY },
{ "addw ", YaDirect },
{ "ror ", DirectX },
{ "ror ", A },
{ "mov ", AX },
{ "cmp ", YDirect },
{ "reti ", Implied },
//0x80 - 0x8f
{ "setc ", Implied },
{ "tcall", TVector },
{ "set4 ", Direct },
{ "bbs4 ", DirectRelative },
{ "adc ", ADirect },
{ "adc ", AAbsolute },
{ "adc ", AIX },
{ "adc ", AIDirectX },
{ "adc ", AConstant },
{ "adc ", DirectDirect },
{ "eor1 ", CAbsoluteBit },
{ "dec ", Direct },
{ "dec ", Absolute },
{ "mov ", YConstant },
{ "pop ", P },
{ "mov ", DirectConstant },
//0x90 - 0x9f
{ "bcc ", Relative },
{ "tcall", TVector },
{ "clr4 ", Direct },
{ "bbc4 ", DirectRelative },
{ "adc ", ADirectX },
{ "adc ", AAbsoluteX },
{ "adc ", AAbsoluteY },
{ "adc ", AIDirectY },
{ "adc ", DirectRelative },
{ "adc ", IXIY },
{ "subw ", YaDirect },
{ "dec ", DirectX },
{ "dec ", A },
{ "mov ", XSp },
{ "div ", YaX },
{ "xcn ", A },
//0xa0 - 0xaf
{ "ei ", Implied },
{ "tcall", TVector },
{ "set5 ", Direct },
{ "bbs5 ", DirectRelative },
{ "sbc ", ADirect },
{ "sbc ", AAbsolute },
{ "sbc ", AIX },
{ "sbc ", AIDirectX },
{ "sbc ", AConstant },
{ "sbc ", DirectDirect },
{ "mov1 ", CAbsoluteBit },
{ "inc ", Direct },
{ "inc ", Absolute },
{ "cmp ", YConstant },
{ "pop ", A },
{ "mov ", IXPA },
//0xb0 - 0xbf
{ "bcs ", Relative },
{ "tcall", TVector },
{ "clr5 ", Direct },
{ "bbc5 ", DirectRelative },
{ "sbc ", ADirectX },
{ "sbc ", AAbsoluteX },
{ "sbc ", AAbsoluteY },
{ "sbc ", AIDirectY },
{ "sbc ", DirectConstant },
{ "sbc ", IXIY },
{ "movw ", YaDirect },
{ "inc ", DirectX },
{ "inc ", A },
{ "mov ", SpX },
{ "das ", A },
{ "mov ", AIXP },
//0xc0 - 0xcf
{ "di ", Implied },
{ "tcall", TVector },
{ "set6 ", Direct },
{ "bbs6 ", DirectRelative },
{ "mov ", DirectA },
{ "mov ", AbsoluteA },
{ "mov ", IXA },
{ "mov ", IDirectXA },
{ "cmp ", XConstant },
{ "mov ", AbsoluteX },
{ "mov1 ", AbsoluteBitC },
{ "mov ", DirectY },
{ "mov ", AbsoluteY },
{ "mov ", XConstant },
{ "pop ", X },
{ "mul ", Ya },
//0xd0 - 0xdf
{ "bne ", Relative },
{ "tcall", TVector },
{ "clr6 ", Relative },
{ "bbc6 ", DirectRelative },
{ "mov ", DirectXA },
{ "mov ", AbsoluteXA },
{ "mov ", AbsoluteYA },
{ "mov ", IDirectYA },
{ "mov ", DirectX },
{ "mov ", DirectYX },
{ "movw ", DirectYa },
{ "mov ", DirectXY },
{ "dec ", Y },
{ "mov ", AY },
{ "cbne ", DirectXRelative },
{ "daa ", A },
//0xe0 - 0xef
{ "clrv ", Implied },
{ "tcall", TVector },
{ "set7 ", Direct },
{ "bbs7 ", DirectRelative },
{ "mov ", ADirect },
{ "mov ", AAbsolute },
{ "mov ", AIX },
{ "mov ", AIDirectX },
{ "mov ", AConstant },
{ "mov ", XAbsolute },
{ "not1 ", CAbsoluteBit },
{ "mov ", YDirect },
{ "mov ", YAbsolute },
{ "notc ", Implied },
{ "pop ", Y },
{ "sleep", Implied },
//0xf0 - 0xff
{ "beq ", Relative },
{ "tcall", TVector },
{ "clr7 ", Direct },
{ "bbc7 ", DirectRelative },
{ "mov ", ADirectX },
{ "mov ", AAbsoluteX },
{ "mov ", AAbsoluteY },
{ "mov ", AIDirectY },
{ "mov ", XDirect },
{ "mov ", XDirectY },
{ "mov ", DirectDirect },
{ "mov ", YDirectX },
{ "inc ", Y },
{ "mov ", YA },
{ "dbz ", YRelative },
{ "stop ", Implied },
};
inline unsigned SNESSMP::getOpcodeLength(uint8_t opcode) {
switch(opcodeInfo[opcode].mode) { default:
case Implied: return 1; //
case TVector: return 1; //0
case Direct: return 2; //$00
case DirectRelative: return 3; //$00,+/-$00
case ADirect: return 2; //a,$00
case AAbsolute: return 3; //a,$0000
case AIX: return 1; //a,(x)
case AIDirectX: return 2; //a,($00+x)
case AConstant: return 2; //a,#$00
case DirectDirect: return 3; //$00,$00
case CAbsoluteBit: return 3; //c,$0000:0
case Absolute: return 3; //$0000
case P: return 1; //p
case AbsoluteA: return 3; //$0000,a
case Relative: return 2; //+/-$00
case ADirectX: return 2; //a,$00+x
case AAbsoluteX: return 3; //a,$0000+x
case AAbsoluteY: return 3; //a,$0000+y
case AIDirectY: return 2; //a,($00)+y
case DirectConstant: return 3; //$00,#$00
case IXIY: return 1; //(x),(y)
case DirectX: return 2; //$00+x
case A: return 1; //a
case X: return 1; //x
case XAbsolute: return 3; //x,$0000
case IAbsoluteX: return 3; //($0000+x)
case CNAbsoluteBit: return 3; //c,!$0000:0
case XDirect: return 2; //x,$00
case PVector: return 2; //$ff00
case YaDirect: return 2; //ya,$00
case XA: return 1; //x,a
case YAbsolute: return 3; //y,$0000
case Y: return 1; //y
case AX: return 1; //a,x
case YDirect: return 2; //y,$00
case YConstant: return 2; //y,#$00
case XSp: return 1; //x,sp
case YaX: return 1; //ya,x
case IXPA: return 1; //(x)+,a
case SpX: return 1; //sp,x
case AIXP: return 1; //a,(x)+
case DirectA: return 2; //$00,a
case IXA: return 1; //(x),a
case IDirectXA: return 2; //($00+x),a
case XConstant: return 2; //x,#$00
case AbsoluteX: return 3; //$0000,x
case AbsoluteBitC: return 3; //$0000:0,c
case DirectY: return 2; //$00,y
case AbsoluteY: return 3; //$0000,y
case Ya: return 1; //ya
case DirectXA: return 2; //$00+x,a
case AbsoluteXA: return 3; //$0000+x,a
case AbsoluteYA: return 3; //$0000+y,a
case IDirectYA: return 2; //($00)+y,a
case DirectYX: return 2; //$00+y,x
case DirectYa: return 2; //$00,ya
case DirectXY: return 2; //$00+x,y
case AY: return 1; //a,y
case DirectXRelative: return 3; //$00+x,+/-$00
case XDirectY: return 2; //x,$00+y
case YDirectX: return 2; //y,$00+x
case YA: return 1; //y,a
case YRelative: return 2; //y,+/-$00
}
}
inline string SNESSMP::disassemble(uint16_t pc, uint8_t opcode, uint8_t pl, uint8_t ph) {
string name = opcodeInfo[opcode].name;
unsigned mode = opcodeInfo[opcode].mode;
unsigned pa = (ph << 8) + pl;
if(mode == Implied) return name;
if(mode == TVector) return { name, " ", opcode >> 4 };
if(mode == Direct) return { name, " $", hex<2>(pl) };
if(mode == DirectRelative) return { name, " $", hex<2>(pl), ",$", hex<4>(pc + 3 + (int8_t)ph) };
if(mode == ADirect) return { name, " a,$", hex<2>(pl) };
if(mode == AAbsolute) return { name, " a,$", hex<4>(pa) };
if(mode == AIX) return { name, "a,(x)" };
if(mode == AIDirectX) return { name, " a,($", hex<2>(pl), "+x)" };
if(mode == AConstant) return { name, " a,#$", hex<2>(pl) };
if(mode == DirectDirect) return { name, " $", hex<2>(ph), ",$", hex<2>(pl) };
if(mode == CAbsoluteBit) return { name, " c,$", hex<4>(pa & 0x1fff), ":", pa >> 13 };
if(mode == Absolute) return { name, " $", hex<4>(pa) };
if(mode == P) return { name, " p" };
if(mode == AbsoluteA) return { name, " $", hex<4>(pa), ",a" };
if(mode == Relative) return { name, " $", hex<4>(pc + 2 + (int8_t)pl) };
if(mode == ADirectX) return { name, " a,$", hex<2>(pl), "+x" };
if(mode == AAbsoluteX) return { name, " a,$", hex<4>(pa), "+x" };
if(mode == AAbsoluteY) return { name, " a,$", hex<4>(pa), "+y" };
if(mode == AIDirectY) return { name, " a,($", hex<2>(pl), ")+y" };
if(mode == DirectConstant) return { name, " $", hex<2>(ph), ",#$", hex<2>(pl) };
if(mode == IXIY) return { name, " (x),(y)" };
if(mode == DirectX) return { name, " $", hex<2>(pl), "+x" };
if(mode == A) return { name, " a" };
if(mode == X) return { name, " x" };
if(mode == XAbsolute) return { name, " x,$", hex<4>(pa) };
if(mode == IAbsoluteX) return { name, " ($", hex<4>(pa), "+x)" };
if(mode == CNAbsoluteBit) return { name, " c,!$", hex<4>(pa & 0x1fff), ":", pa >> 13 };
if(mode == XDirect) return { name, " x,$", hex<2>(pl) };
if(mode == PVector) return { name, " $ff", hex<2>(pl) };
if(mode == YaDirect) return { name, " ya,$", hex<2>(pl) };
if(mode == XA) return { name, " x,a" };
if(mode == YAbsolute) return { name, " y,$", hex<4>(pa) };
if(mode == Y) return { name, " y" };
if(mode == AX) return { name, " a,x" };
if(mode == YDirect) return { name, " y,$", hex<2>(pl) };
if(mode == YConstant) return { name, " y,#$", hex<2>(pl) };
if(mode == XSp) return { name, " x,sp" };
if(mode == YaX) return { name, " ya,x" };
if(mode == IXPA) return { name, " (x)+,a" };
if(mode == SpX) return { name, " sp,x" };
if(mode == AIXP) return { name, " a,(x)+" };
if(mode == DirectA) return { name, " $", hex<2>(pl), ",a" };
if(mode == IXA) return { name, " (x),a" };
if(mode == IDirectXA) return { name, " ($", hex<2>(pl), "+x),a" };
if(mode == XConstant) return { name, " x,#$", hex<2>(pl) };
if(mode == AbsoluteX) return { name, " $", hex<4>(pa), ",x" };
if(mode == AbsoluteBitC) return { name, " $", hex<4>(pa & 0x1fff), ":", pa >> 13, ",c" };
if(mode == DirectY) return { name, " $", hex<2>(pl), ",y" };
if(mode == AbsoluteY) return { name, " $", hex<4>(pa), ",y" };
if(mode == Ya) return { name, " ya" };
if(mode == DirectXA) return { name, " $", hex<2>(pl), "+x,a" };
if(mode == AbsoluteXA) return { name, " $", hex<4>(pa), "+x,a" };
if(mode == AbsoluteYA) return { name, " $", hex<4>(pa), "+y,a" };
if(mode == IDirectYA) return { name, " ($", hex<2>(pl), ")+y,a" };
if(mode == DirectYX) return { name, " $", hex<2>(pl), "+y,x" };
if(mode == DirectYa) return { name, " $", hex<2>(pl), ",ya" };
if(mode == DirectXY) return { name, " $", hex<2>(pl), "+x,y" };
if(mode == AY) return { name, " a,y" };
if(mode == DirectXRelative) return { name, " $", hex<2>(pl), ",$", hex<4>(pc + 3 + (int8_t)ph) };
if(mode == XDirectY) return { name, " x,$", hex<2>(pl), "+y" };
if(mode == YDirectX) return { name, " y,$", hex<2>(pl), "+x" };
if(mode == YA) return { name, " y,a" };
if(mode == YRelative) return { name, " y,$", hex<4>(pc + 2 + (int8_t)pl) };
return "";
}
inline string SNESSMP::disassemble(uint16_t pc, bool p, uint8_t opcode, uint8_t pl, uint8_t ph) {
string name = opcodeInfo[opcode].name;
unsigned mode = opcodeInfo[opcode].mode;
unsigned pdl = (p << 8) + pl;
unsigned pdh = (p << 8) + ph;
unsigned pa = (ph << 8) + pl;
if(mode == Implied) return name;
if(mode == TVector) return { name, " ", opcode >> 4 };
if(mode == Direct) return { name, " $", hex<3>(pdl) };
if(mode == DirectRelative) return { name, " $", hex<3>(pdl), ",$", hex<4>(pc + 3 + (int8_t)ph) };
if(mode == ADirect) return { name, " a,$", hex<3>(pdl) };
if(mode == AAbsolute) return { name, " a,$", hex<4>(pa) };
if(mode == AIX) return { name, "a,(x)" };
if(mode == AIDirectX) return { name, " a,($", hex<3>(pdl), "+x)" };
if(mode == AConstant) return { name, " a,#$", hex<2>(pl) };
if(mode == DirectDirect) return { name, " $", hex<3>(pdh), ",$", hex<3>(pdl) };
if(mode == CAbsoluteBit) return { name, " c,$", hex<4>(pa & 0x1fff), ":", pa >> 13 };
if(mode == Absolute) return { name, " $", hex<4>(pa) };
if(mode == P) return { name, " p" };
if(mode == AbsoluteA) return { name, " $", hex<4>(pa), ",a" };
if(mode == Relative) return { name, " $", hex<4>(pc + 2 + (int8_t)pl) };
if(mode == ADirectX) return { name, " a,$", hex<3>(pdl), "+x" };
if(mode == AAbsoluteX) return { name, " a,$", hex<4>(pa), "+x" };
if(mode == AAbsoluteY) return { name, " a,$", hex<4>(pa), "+y" };
if(mode == AIDirectY) return { name, " a,($", hex<3>(pdl), ")+y" };
if(mode == DirectConstant) return { name, " $", hex<3>(pdh), ",#$", hex<2>(pl) };
if(mode == IXIY) return { name, " (x),(y)" };
if(mode == DirectX) return { name, " $", hex<3>(pdl), "+x" };
if(mode == A) return { name, " a" };
if(mode == X) return { name, " x" };
if(mode == XAbsolute) return { name, " x,$", hex<4>(pa) };
if(mode == IAbsoluteX) return { name, " ($", hex<4>(pa), "+x)" };
if(mode == CNAbsoluteBit) return { name, " c,!$", hex<4>(pa & 0x1fff), ":", pa >> 13 };
if(mode == XDirect) return { name, " x,$", hex<3>(pdl) };
if(mode == PVector) return { name, " $ff", hex<2>(pl) };
if(mode == YaDirect) return { name, " ya,$", hex<3>(pdl) };
if(mode == XA) return { name, " x,a" };
if(mode == YAbsolute) return { name, " y,$", hex<4>(pa) };
if(mode == Y) return { name, " y" };
if(mode == AX) return { name, " a,x" };
if(mode == YDirect) return { name, " y,$", hex<3>(pdl) };
if(mode == YConstant) return { name, " y,#$", hex<2>(pl) };
if(mode == XSp) return { name, " x,sp" };
if(mode == YaX) return { name, " ya,x" };
if(mode == IXPA) return { name, " (x)+,a" };
if(mode == SpX) return { name, " sp,x" };
if(mode == AIXP) return { name, " a,(x)+" };
if(mode == DirectA) return { name, " $", hex<3>(pdl), ",a" };
if(mode == IXA) return { name, " (x),a" };
if(mode == IDirectXA) return { name, " ($", hex<3>(pdl), "+x),a" };
if(mode == XConstant) return { name, " x,#$", hex<2>(pl) };
if(mode == AbsoluteX) return { name, " $", hex<4>(pa), ",x" };
if(mode == AbsoluteBitC) return { name, " $", hex<4>(pa & 0x1fff), ":", pa >> 13, ",c" };
if(mode == DirectY) return { name, " $", hex<3>(pdl), ",y" };
if(mode == AbsoluteY) return { name, " $", hex<4>(pa), ",y" };
if(mode == Ya) return { name, " ya" };
if(mode == DirectXA) return { name, " $", hex<3>(pdl), "+x,a" };
if(mode == AbsoluteXA) return { name, " $", hex<4>(pa), "+x,a" };
if(mode == AbsoluteYA) return { name, " $", hex<4>(pa), "+y,a" };
if(mode == IDirectYA) return { name, " ($", hex<3>(pdl), ")+y,a" };
if(mode == DirectYX) return { name, " $", hex<3>(pdl), "+y,x" };
if(mode == DirectYa) return { name, " $", hex<3>(pdl), ",ya" };
if(mode == DirectXY) return { name, " $", hex<3>(pdl), "+x,y" };
if(mode == AY) return { name, " a,y" };
if(mode == DirectXRelative) return { name, " $", hex<3>(pdl), ",$", hex<4>(pc + 3 + (int8_t)ph) };
if(mode == XDirectY) return { name, " x,$", hex<3>(pdl), "+y" };
if(mode == YDirectX) return { name, " y,$", hex<3>(pdl), "+x" };
if(mode == YA) return { name, " y,a" };
if(mode == YRelative) return { name, " y,$", hex<4>(pc + 2 + (int8_t)pl) };
return "";
}
}
#endif

View File

@@ -113,11 +113,11 @@ namespace nall {
inline char* strlower(char *str);
inline char* strupper(char *str);
inline char* strtr(char *dest, const char *before, const char *after);
inline uintmax_t strhex (const char *str);
inline intmax_t strsigned (const char *str);
inline uintmax_t strunsigned(const char *str);
inline uintmax_t strbin (const char *str);
inline double strdouble (const char *str);
inline uintmax_t hex (const char *str);
inline intmax_t integer(const char *str);
inline uintmax_t decimal(const char *str);
inline uintmax_t binary (const char *str);
inline double fp (const char *str);
//math.hpp
inline bool strint (const char *str, int &result);
@@ -145,12 +145,12 @@ namespace nall {
inline unsigned strlcpy(string &dest, const char *src, unsigned length);
inline unsigned strlcat(string &dest, const char *src, unsigned length);
inline string substr(const char *src, unsigned start = 0, unsigned length = 0);
template<unsigned length = 0, char padding = '0'> inline string strhex(uintmax_t value);
template<unsigned length = 0, char padding = '0'> inline string strsigned(intmax_t value);
template<unsigned length = 0, char padding = '0'> inline string strunsigned(uintmax_t value);
template<unsigned length = 0, char padding = '0'> inline string strbin(uintmax_t value);
inline unsigned strdouble(char *str, double value);
inline string strdouble(double value);
template<unsigned length = 0, char padding = '0'> inline string hex(uintmax_t value);
template<unsigned length = 0, char padding = '0'> inline string integer(intmax_t value);
template<unsigned length = 0, char padding = '0'> inline string decimal(uintmax_t value);
template<unsigned length = 0, char padding = '0'> inline string binary(uintmax_t value);
inline unsigned fp(char *str, double value);
inline string fp(double value);
//variadic.hpp
template<typename... Args> inline void print(Args&&... args);

View File

@@ -5,9 +5,9 @@ namespace nall {
//this is needed, as C++0x does not support explicit template specialization inside classes
template<> inline string to_string<bool> (bool v) { return v ? "true" : "false"; }
template<> inline string to_string<signed int> (signed int v) { return strsigned(v); }
template<> inline string to_string<unsigned int> (unsigned int v) { return strunsigned(v); }
template<> inline string to_string<double> (double v) { return strdouble(v); }
template<> inline string to_string<signed int> (signed int v) { return integer(v); }
template<> inline string to_string<unsigned int> (unsigned int v) { return decimal(v); }
template<> inline string to_string<double> (double v) { return fp(v); }
template<> inline string to_string<char*> (char *v) { return v; }
template<> inline string to_string<const char*> (const char *v) { return v; }
template<> inline string to_string<string> (string v) { return v; }

View File

@@ -40,7 +40,7 @@ char* strtr(char *dest, const char *before, const char *after) {
return dest;
}
uintmax_t strhex(const char *str) {
uintmax_t hex(const char *str) {
if(!str) return 0;
uintmax_t result = 0;
@@ -60,7 +60,7 @@ uintmax_t strhex(const char *str) {
return result;
}
intmax_t strsigned(const char *str) {
intmax_t integer(const char *str) {
if(!str) return 0;
intmax_t result = 0;
bool negate = false;
@@ -81,7 +81,7 @@ intmax_t strsigned(const char *str) {
return !negate ? result : -result;
}
uintmax_t strunsigned(const char *str) {
uintmax_t decimal(const char *str) {
if(!str) return 0;
uintmax_t result = 0;
@@ -95,7 +95,7 @@ uintmax_t strunsigned(const char *str) {
return result;
}
uintmax_t strbin(const char *str) {
uintmax_t binary(const char *str) {
if(!str) return 0;
uintmax_t result = 0;
@@ -113,7 +113,7 @@ uintmax_t strbin(const char *str) {
return result;
}
double strdouble(const char *str) {
double fp(const char *str) {
if(!str) return 0.0;
bool negate = false;

View File

@@ -26,9 +26,9 @@ string& string::append(const char *s) {
}
string& string::append(bool value) { append(value ? "true" : "false"); return *this; }
string& string::append(signed int value) { append(strsigned(value)); return *this; }
string& string::append(unsigned int value) { append(strunsigned(value)); return *this; }
string& string::append(double value) { append(strdouble(value)); return *this; }
string& string::append(signed int value) { append(integer(value)); return *this; }
string& string::append(unsigned int value) { append(decimal(value)); return *this; }
string& string::append(double value) { append(fp(value)); return *this; }
string::operator const char*() const {
return data;

View File

@@ -27,7 +27,7 @@ string substr(const char *src, unsigned start, unsigned length) {
/* arithmetic <> string */
template<unsigned length, char padding> string strhex(uintmax_t value) {
template<unsigned length, char padding> string hex(uintmax_t value) {
string output;
unsigned offset = 0;
@@ -51,7 +51,7 @@ template<unsigned length, char padding> string strhex(uintmax_t value) {
return output;
}
template<unsigned length, char padding> string strsigned(intmax_t value) {
template<unsigned length, char padding> string integer(intmax_t value) {
string output;
unsigned offset = 0;
@@ -77,7 +77,7 @@ template<unsigned length, char padding> string strsigned(intmax_t value) {
return output;
}
template<unsigned length, char padding> string strunsigned(uintmax_t value) {
template<unsigned length, char padding> string decimal(uintmax_t value) {
string output;
unsigned offset = 0;
@@ -99,7 +99,7 @@ template<unsigned length, char padding> string strunsigned(uintmax_t value) {
return output;
}
template<unsigned length, char padding> string strbin(uintmax_t value) {
template<unsigned length, char padding> string binary(uintmax_t value) {
string output;
unsigned offset = 0;
@@ -124,7 +124,7 @@ template<unsigned length, char padding> string strbin(uintmax_t value) {
//using sprintf is certainly not the most ideal method to convert
//a double to a string ... but attempting to parse a double by
//hand, digit-by-digit, results in subtle rounding errors.
unsigned strdouble(char *str, double value) {
unsigned fp(char *str, double value) {
char buffer[256];
sprintf(buffer, "%f", value);
@@ -145,10 +145,10 @@ unsigned strdouble(char *str, double value) {
return length + 1;
}
string strdouble(double value) {
string fp(double value) {
string temp;
temp.reserve(strdouble(0, value));
strdouble(temp(), value);
temp.reserve(fp(0, value));
fp(temp(), value);
return temp;
}

View File

@@ -47,3 +47,12 @@ void EditBox::setText(const string &text) {
gtk_text_buffer_set_text(object->textBuffer, text, -1);
object->locked = false;
}
void EditBox::setCursorPosition(unsigned position) {
GtkTextMark *mark = gtk_text_buffer_get_mark(object->textBuffer, "insert");
GtkTextIter iter;
gtk_text_buffer_get_end_iter(object->textBuffer, &iter);
gtk_text_iter_set_offset(&iter, min(position, gtk_text_iter_get_offset(&iter)));
gtk_text_buffer_place_cursor(object->textBuffer, &iter);
gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(object->subWidget), mark);
}

View File

@@ -27,6 +27,7 @@ namespace phoenix {
#include "checkbox.cpp"
#include "combobox.cpp"
#include "editbox.cpp"
#include "hexeditor.cpp"
#include "horizontalslider.cpp"
#include "label.cpp"
#include "listbox.cpp"

View File

@@ -157,6 +157,28 @@ struct EditBox : Widget {
void setWordWrap(bool wordWrap = true);
nall::string text();
void setText(const nall::string &text);
void setCursorPosition(unsigned position);
};
struct HexEditor : Widget {
nall::function<uint8_t (unsigned)> onRead;
nall::function<void (unsigned, uint8_t)> onWrite;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
void setSize(unsigned size);
void setOffset(unsigned offset);
void setColumns(unsigned columns);
void setRows(unsigned rows);
void update();
HexEditor();
//private:
struct Data;
Data *hexEditor;
bool keyPress(unsigned scancode);
void scroll(unsigned position);
void setScroll();
void updateScroll();
unsigned cursorPosition();
void setCursorPosition(unsigned position);
};
struct HorizontalSlider : Widget {

266
bsnes/phoenix/gtk/hexeditor.cpp Executable file
View File

@@ -0,0 +1,266 @@
static bool HexEditor_keyPress(GtkWidget *widget, GdkEventKey *event, HexEditor *self) {
return self->keyPress(event->keyval);
}
static bool HexEditor_scroll(GtkRange *range, GtkScrollType scroll, gdouble value, HexEditor *self) {
self->scroll((unsigned)value);
return false;
}
void HexEditor::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
widget->parent = &parent;
hexEditor->size = 0;
hexEditor->offset = 0;
hexEditor->columns = 16;
hexEditor->rows = 16;
object->widget = gtk_hbox_new(false, 0);
gtk_widget_set_size_request(object->widget, width, height);
hexEditor->container = gtk_scrolled_window_new(0, 0);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(hexEditor->container), GTK_POLICY_NEVER, GTK_POLICY_NEVER);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(hexEditor->container), GTK_SHADOW_ETCHED_IN);
hexEditor->widget = gtk_text_view_new();
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(hexEditor->widget), GTK_WRAP_NONE);
gtk_container_add(GTK_CONTAINER(hexEditor->container), hexEditor->widget);
g_signal_connect(G_OBJECT(hexEditor->widget), "key-press-event", G_CALLBACK(HexEditor_keyPress), (gpointer)this);
hexEditor->scroll = gtk_vscrollbar_new((GtkAdjustment*)0);
gtk_range_set_range(GTK_RANGE(hexEditor->scroll), 0, 256);
gtk_range_set_increments(GTK_RANGE(hexEditor->scroll), 1, 16);
gtk_widget_set_sensitive(hexEditor->scroll, false);
g_signal_connect(G_OBJECT(hexEditor->scroll), "change-value", G_CALLBACK(HexEditor_scroll), (gpointer)this);
gtk_box_pack_start(GTK_BOX(object->widget), hexEditor->container, true, true, 0);
gtk_box_pack_start(GTK_BOX(object->widget), hexEditor->scroll, false, false, 1);
object->textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(hexEditor->widget));
hexEditor->cursor = gtk_text_buffer_get_mark(object->textBuffer, "insert");
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
gtk_widget_show(hexEditor->scroll);
gtk_widget_show(hexEditor->widget);
gtk_widget_show(hexEditor->container);
gtk_widget_show(object->widget);
}
void HexEditor::setSize(unsigned size) {
hexEditor->size = size;
setScroll();
}
void HexEditor::setOffset(unsigned offset) {
hexEditor->offset = offset;
setScroll();
updateScroll();
}
void HexEditor::setColumns(unsigned columns) {
hexEditor->columns = columns;
setScroll();
}
void HexEditor::setRows(unsigned rows) {
hexEditor->rows = rows;
setScroll();
}
void HexEditor::update() {
if(!onRead) {
gtk_text_buffer_set_text(object->textBuffer, "", -1);
return;
}
unsigned position = cursorPosition();
string output;
unsigned offset = hexEditor->offset;
for(unsigned row = 0; row < hexEditor->rows; row++) {
output.append(hex<8>(offset));
output.append(" ");
string hexdata;
string ansidata = " ";
for(unsigned column = 0; column < hexEditor->columns; column++) {
if(offset < hexEditor->size) {
uint8_t data = onRead(offset++);
hexdata.append(hex<2>(data));
hexdata.append(" ");
char buffer[2] = { data >= 0x20 && data <= 0x7e ? (char)data : '.', 0 };
ansidata.append(buffer);
} else {
hexdata.append(" ");
ansidata.append(" ");
}
}
output.append(hexdata);
output.append(ansidata);
if(offset >= hexEditor->size) break;
if(row != hexEditor->rows - 1) output.append("\n");
}
gtk_text_buffer_set_text(object->textBuffer, output, -1);
if(position == 0) position = 10; //start at first position where hex values can be entered
setCursorPosition(position);
}
HexEditor::HexEditor() {
hexEditor = new HexEditor::Data;
}
//internal
bool HexEditor::keyPress(unsigned scancode) {
if(!onRead && !onWrite) return false;
unsigned position = cursorPosition();
unsigned lineWidth = 10 + (hexEditor->columns * 3) + 1 + (hexEditor->columns) + 1;
unsigned cursorY = position / lineWidth;
unsigned cursorX = position % lineWidth;
if(scancode == GDK_Home) {
setCursorPosition(cursorY * lineWidth + 10);
return true;
}
if(scancode == GDK_End) {
setCursorPosition(cursorY * lineWidth + 10 + (hexEditor->columns * 3 - 1));
return true;
}
if(scancode == GDK_Up) {
if(cursorY != 0) return false;
signed newOffset = hexEditor->offset - hexEditor->columns;
if(newOffset >= 0) {
setOffset(newOffset);
update();
}
return true;
}
if(scancode == GDK_Down) {
if(cursorY != hexEditor->rows - 1) return false;
signed newOffset = hexEditor->offset + hexEditor->columns;
if(newOffset + hexEditor->columns * hexEditor->rows - (hexEditor->columns - 1) <= hexEditor->size) {
setOffset(newOffset);
update();
}
return true;
}
if(scancode == GDK_Page_Up) {
signed newOffset = hexEditor->offset - hexEditor->columns * hexEditor->rows;
if(newOffset >= 0) {
setOffset(newOffset);
update();
} else {
setOffset(0);
update();
}
return true;
}
if(scancode == GDK_Page_Down) {
signed newOffset = hexEditor->offset + hexEditor->columns * hexEditor->rows;
for(unsigned n = 0; n < hexEditor->rows; n++) {
if(newOffset + hexEditor->columns * hexEditor->rows - (hexEditor->columns - 1) <= hexEditor->size) {
setOffset(newOffset);
update();
break;
}
newOffset -= hexEditor->columns;
}
return true;
}
//convert scancode to hex nibble
if(scancode >= '0' && scancode <= '9') scancode = scancode - '0';
else if(scancode >= 'A' && scancode <= 'F') scancode = scancode - 'A' + 10;
else if(scancode >= 'a' && scancode <= 'f') scancode = scancode - 'a' + 10;
else return false; //not a valid hex value
if(cursorX >= 10) {
//not on an offset
cursorX -= 10;
if((cursorX % 3) != 2) {
//not on a space
bool cursorNibble = (cursorX % 3) == 1; //0 = high, 1 = low
cursorX /= 3;
if(cursorX < hexEditor->columns) {
//not in ANSI region
unsigned offset = hexEditor->offset + (cursorY * hexEditor->columns + cursorX);
if(offset >= hexEditor->size) return false; //do not edit past end of file
uint8_t data = onRead(offset);
//write modified value
if(cursorNibble == 1) {
data = (data & 0xf0) | (scancode << 0);
} else {
data = (data & 0x0f) | (scancode << 4);
}
onWrite(offset, data);
//auto-advance cursor to next nibble/byte
position++;
if(cursorNibble && cursorX != hexEditor->columns - 1) position++;
setCursorPosition(position);
//refresh output to reflect modified data
update();
}
}
}
return true;
}
void HexEditor::scroll(unsigned position) {
unsigned rows = hexEditor->size / hexEditor->columns;
if(position >= rows) position = rows - 1;
setOffset(position * hexEditor->columns);
update();
}
void HexEditor::setScroll() {
unsigned rows = hexEditor->size / hexEditor->columns;
if(rows) rows--;
if(rows) {
gtk_range_set_range(GTK_RANGE(hexEditor->scroll), 0, rows);
gtk_widget_set_sensitive(hexEditor->scroll, true);
} else {
gtk_widget_set_sensitive(hexEditor->scroll, false);
}
}
void HexEditor::updateScroll() {
unsigned row = hexEditor->offset / hexEditor->columns;
gtk_range_set_value(GTK_RANGE(hexEditor->scroll), row);
}
unsigned HexEditor::cursorPosition() {
GtkTextIter iter;
gtk_text_buffer_get_iter_at_mark(object->textBuffer, &iter, hexEditor->cursor);
return gtk_text_iter_get_offset(&iter);
}
void HexEditor::setCursorPosition(unsigned position) {
GtkTextIter iter;
gtk_text_buffer_get_iter_at_mark(object->textBuffer, &iter, hexEditor->cursor);
//GTK+ will throw a hundred errors on the terminal
//if you set an iterator past the end of the text buffer
GtkTextIter endIter;
gtk_text_buffer_get_end_iter(object->textBuffer, &iter);
unsigned endPosition = gtk_text_iter_get_offset(&iter);
gtk_text_iter_set_offset(&iter, min(position, endPosition));
gtk_text_buffer_place_cursor(object->textBuffer, &iter);
}

View File

@@ -14,7 +14,7 @@ static void ListBox_change(ListBox *self) {
}
static void ListBox_tick(GtkCellRendererToggle *cell, gchar *path_string, ListBox *self) {
unsigned index = strunsigned(path_string);
unsigned index = decimal(path_string);
self->setChecked(index, !self->checked(index));
if(self->onTick) self->onTick(index);
}

View File

@@ -35,6 +35,18 @@ struct Canvas::Data {
unsigned pitch;
};
struct HexEditor::Data {
GtkWidget *container;
GtkWidget *widget;
GtkWidget *scroll;
GtkTextMark *cursor;
unsigned size;
unsigned offset;
unsigned columns;
unsigned rows;
};
struct ListBox::Data {
GtkListStore *store;
struct GtkColumn {

View File

@@ -23,6 +23,13 @@ void EditBox::setText(const string &text) {
editBox->setPlainText(QString::fromUtf8(text));
}
void EditBox::setCursorPosition(unsigned position) {
QTextCursor cursor = editBox->textCursor();
unsigned lastchar = strlen(editBox->toPlainText().toUtf8().constData());
cursor.setPosition(min(position, lastchar));
editBox->setTextCursor(cursor);
}
EditBox::EditBox() {
editBox = new EditBox::Data(*this);
widget->widget = editBox;

View File

@@ -199,6 +199,7 @@ struct EditBox : Widget {
void setWordWrap(bool wordWrap = true);
nall::string text();
void setText(const nall::string &text);
void setCursorPosition(unsigned position);
EditBox();
//private:
struct Data;

View File

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

View File

@@ -3,9 +3,8 @@ snes_objects += snes-system
snes_objects += snes-cartridge snes-cheat
snes_objects += snes-memory snes-cpucore snes-smpcore
snes_objects += snes-cpu snes-smp snes-dsp snes-ppu
snes_objects += snes-supergameboy snes-superfx snes-sa1
snes_objects += snes-bsx snes-srtc snes-sdd1 snes-spc7110
snes_objects += snes-cx4 snes-dsp1 snes-dsp2 snes-dsp3 snes-dsp4
snes_objects += snes-supergameboy snes-superfx snes-sa1 snes-upd77c25
snes_objects += snes-bsx snes-srtc snes-sdd1 snes-spc7110 snes-cx4
snes_objects += snes-obc1 snes-st0010 snes-st0011 snes-st0018
snes_objects += snes-msu1 snes-serial
objects += $(snes_objects)
@@ -47,15 +46,12 @@ obj/snes-cheat.o : $(snes)/cheat/cheat.cpp $(call rwildcard,$(snes)/cheat/)
obj/snes-supergameboy.o: $(snes)/chip/supergameboy/supergameboy.cpp $(call rwildcard,$(snes)/chip/supergameboy/)
obj/snes-superfx.o : $(snes)/chip/superfx/superfx.cpp $(call rwildcard,$(snes)/chip/superfx/)
obj/snes-sa1.o : $(snes)/chip/sa1/sa1.cpp $(call rwildcard,$(snes)/chip/sa1/)
obj/snes-upd77c25.o : $(snes)/chip/upd77c25/upd77c25.cpp $(call rwildcard,$(snes)/chip/upd77c25/)
obj/snes-bsx.o : $(snes)/chip/bsx/bsx.cpp $(snes)/chip/bsx/*
obj/snes-srtc.o : $(snes)/chip/srtc/srtc.cpp $(snes)/chip/srtc/*
obj/snes-sdd1.o : $(snes)/chip/sdd1/sdd1.cpp $(snes)/chip/sdd1/*
obj/snes-spc7110.o : $(snes)/chip/spc7110/spc7110.cpp $(snes)/chip/spc7110/*
obj/snes-cx4.o : $(snes)/chip/cx4/cx4.cpp $(snes)/chip/cx4/*
obj/snes-dsp1.o : $(snes)/chip/dsp1/dsp1.cpp $(snes)/chip/dsp1/*
obj/snes-dsp2.o : $(snes)/chip/dsp2/dsp2.cpp $(snes)/chip/dsp2/*
obj/snes-dsp3.o : $(snes)/chip/dsp3/dsp3.cpp $(snes)/chip/dsp3/*
obj/snes-dsp4.o : $(snes)/chip/dsp4/dsp4.cpp $(snes)/chip/dsp4/*
obj/snes-obc1.o : $(snes)/chip/obc1/obc1.cpp $(snes)/chip/obc1/*
obj/snes-st0010.o : $(snes)/chip/st0010/st0010.cpp $(snes)/chip/st0010/*
obj/snes-st0011.o : $(snes)/chip/st0011/st0011.cpp $(snes)/chip/st0011/*

View File

@@ -7,14 +7,16 @@ void CPUDebugger::op_step() {
usage[regs.pc] |= UsageExec | (regs.p.m << 1) | (regs.p.x << 0);
opcode_pc = regs.pc;
opcode_edge = true;
if(debugger.step_cpu) {
debugger.break_event = Debugger::BreakEvent::CPUStep;
scheduler.exit(Scheduler::ExitReason::DebuggerEvent);
} else {
debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00);
}
if(step_event) step_event();
opcode_edge = false;
CPU::op_step();
synchronize_smp();
}
@@ -36,6 +38,7 @@ void CPUDebugger::op_write(uint32 addr, uint8 data) {
CPUDebugger::CPUDebugger() {
usage = new uint8[1 << 24]();
opcode_pc = 0x8000;
opcode_edge = false;
}
CPUDebugger::~CPUDebugger() {
@@ -53,11 +56,11 @@ bool CPUDebugger::property(unsigned id, string &name, string &value) {
}
//internal
item("S-CPU MDR", string("0x", strhex<2>(regs.mdr)));
item("S-CPU MDR", string("0x", hex<2>(regs.mdr)));
//$2181-2183
item("$2181-$2183", "");
item("WRAM Address", string("0x", strhex<6>(status.wram_addr)));
item("WRAM Address", string("0x", hex<6>(status.wram_addr)));
//$4016
item("$4016", "");
@@ -72,45 +75,45 @@ bool CPUDebugger::property(unsigned id, string &name, string &value) {
//$4201
item("$4201", "");
item("PIO", string("0x", strhex<2>(status.pio)));
item("PIO", string("0x", hex<2>(status.pio)));
//$4202
item("$4202", "");
item("Multiplicand", string("0x", strhex<2>(status.wrmpya)));
item("Multiplicand", string("0x", hex<2>(status.wrmpya)));
//$4203
item("$4203", "");
item("Multiplier", string("0x", strhex<2>(status.wrmpyb)));
item("Multiplier", string("0x", hex<2>(status.wrmpyb)));
//$4204-$4205
item("$4204-$4205", "");
item("Dividend", string("0x", strhex<4>(status.wrdiva)));
item("Dividend", string("0x", hex<4>(status.wrdiva)));
//$4206
item("$4206", "");
item("Divisor", string("0x", strhex<2>(status.wrdivb)));
item("Divisor", string("0x", hex<2>(status.wrdivb)));
//$4207-$4208
item("$4207-$4208", "");
item("H-Time", string("0x", strhex<4>(status.htime)));
item("H-Time", string("0x", hex<4>(status.htime)));
//$4209-$420a
item("$4209-$420a", "");
item("V-Time", string("0x", strhex<4>(status.vtime)));
item("V-Time", string("0x", hex<4>(status.vtime)));
//$420b
unsigned dma_enable = 0;
for(unsigned n = 0; n < 8; n++) dma_enable |= channel[n].dma_enabled << n;
item("$420b", "");
item("DMA Enable", string("0x", strhex<2>(dma_enable)));
item("DMA Enable", string("0x", hex<2>(dma_enable)));
//$420c
unsigned hdma_enable = 0;
for(unsigned n = 0; n < 8; n++) hdma_enable |= channel[n].hdma_enabled << n;
item("$420c", "");
item("HDMA Enable", string("0x", strhex<2>(hdma_enable)));
item("HDMA Enable", string("0x", hex<2>(hdma_enable)));
//$420d
item("$420d", "");
@@ -127,25 +130,25 @@ bool CPUDebugger::property(unsigned id, string &name, string &value) {
item("Transfer Mode", (unsigned)channel[i].transfer_mode);
//$43x1
item("B-Bus Address", string("0x", strhex<4>(channel[i].dest_addr)));
item("B-Bus Address", string("0x", hex<4>(channel[i].dest_addr)));
//$43x2-$43x3
item("A-Bus Address", string("0x", strhex<4>(channel[i].source_addr)));
item("A-Bus Address", string("0x", hex<4>(channel[i].source_addr)));
//$43x4
item("A-Bus Bank", string("0x", strhex<2>(channel[i].source_bank)));
item("A-Bus Bank", string("0x", hex<2>(channel[i].source_bank)));
//$43x5-$43x6
item("Transfer Size / Indirect Address", string("0x", strhex<4>(channel[i].transfer_size)));
item("Transfer Size / Indirect Address", string("0x", hex<4>(channel[i].transfer_size)));
//$43x7
item("Indirect Bank", string("0x", strhex<2>(channel[i].indirect_bank)));
item("Indirect Bank", string("0x", hex<2>(channel[i].indirect_bank)));
//$43x8-$43x9
item("Table Address", string("0x", strhex<4>(channel[i].hdma_addr)));
item("Table Address", string("0x", hex<4>(channel[i].hdma_addr)));
//$43xa
item("Line Counter", string("0x", strhex<2>(channel[i].line_counter)));
item("Line Counter", string("0x", hex<2>(channel[i].line_counter)));
}
#undef item

View File

@@ -12,7 +12,8 @@ public:
UsageFlagX = 0x01,
};
uint8 *usage;
uint32 opcode_pc; //points to the current opcode, used to backtrace on read/write breakpoints
uint32 opcode_pc;
bool opcode_edge;
void op_step();
uint8 op_read(uint32 addr);

View File

@@ -47,8 +47,8 @@ bool PPUDebugger::property(unsigned id, string &name, string &value) {
}
//internal
item("S-PPU1 MDR", string("0x", strhex<2>(regs.ppu1_mdr)));
item("S-PPU2 MDR", string("0x", strhex<2>(regs.ppu2_mdr)));
item("S-PPU1 MDR", string("0x", hex<2>(regs.ppu1_mdr)));
item("S-PPU2 MDR", string("0x", hex<2>(regs.ppu2_mdr)));
//$2100
item("$2100", "");
@@ -59,11 +59,11 @@ bool PPUDebugger::property(unsigned id, string &name, string &value) {
item("$2101", "");
item("OAM Base Size", (unsigned)regs.oam_basesize);
item("OAM Name Select", (unsigned)regs.oam_nameselect);
item("OAM Name Base Address", string("0x", strhex<4>(regs.oam_tdaddr)));
item("OAM Name Base Address", string("0x", hex<4>(regs.oam_tdaddr)));
//$2102-$2103
item("$2102-$2103", "");
item("OAM Base Address", string("0x", strhex<4>(regs.oam_baseaddr)));
item("OAM Base Address", string("0x", hex<4>(regs.oam_baseaddr)));
item("OAM Priority", regs.oam_priority);
//$2105
@@ -87,33 +87,33 @@ bool PPUDebugger::property(unsigned id, string &name, string &value) {
//$2107
item("$2107", "");
item("BG1 Screen Address", string("0x", strhex<4>(regs.bg_scaddr[BG1])));
item("BG1 Screen Address", string("0x", hex<4>(regs.bg_scaddr[BG1])));
item("BG1 Screen Size", screen_size[regs.bg_scsize[BG1]]);
//$2108
item("$2108", "");
item("BG2 Screen Address", string("0x", strhex<4>(regs.bg_scaddr[BG2])));
item("BG2 Screen Address", string("0x", hex<4>(regs.bg_scaddr[BG2])));
item("BG2 Screen Size", screen_size[regs.bg_scsize[BG2]]);
//$2109
item("$2109", "");
item("BG3 Screen Address", string("0x", strhex<4>(regs.bg_scaddr[BG3])));
item("BG3 Screen Address", string("0x", hex<4>(regs.bg_scaddr[BG3])));
item("BG3 Screen Size", screen_size[regs.bg_scsize[BG3]]);
//$210a
item("$210a", "");
item("BG4 Screen Address", string("0x", strhex<4>(regs.bg_scaddr[BG4])));
item("BG4 Screen Address", string("0x", hex<4>(regs.bg_scaddr[BG4])));
item("BG4 Screen Size", screen_size[regs.bg_scsize[BG4]]);
//$210b
item("$210b", "");
item("BG1 Name Base Address", string("0x", strhex<4>(regs.bg_tdaddr[BG1])));
item("BG2 Name Base Address", string("0x", strhex<4>(regs.bg_tdaddr[BG2])));
item("BG1 Name Base Address", string("0x", hex<4>(regs.bg_tdaddr[BG1])));
item("BG2 Name Base Address", string("0x", hex<4>(regs.bg_tdaddr[BG2])));
//$210c
item("$210c", "");
item("BG3 Name Base Address", string("0x", strhex<4>(regs.bg_tdaddr[BG3])));
item("BG4 Name Base Address", string("0x", strhex<4>(regs.bg_tdaddr[BG4])));
item("BG3 Name Base Address", string("0x", hex<4>(regs.bg_tdaddr[BG3])));
item("BG4 Name Base Address", string("0x", hex<4>(regs.bg_tdaddr[BG4])));
//$210d
item("$210d", "");
@@ -157,7 +157,7 @@ bool PPUDebugger::property(unsigned id, string &name, string &value) {
//$2116-$2117
item("$2116-$2117", "");
item("VRAM Address", string("0x", strhex<4>(regs.vram_addr)));
item("VRAM Address", string("0x", hex<4>(regs.vram_addr)));
//$211a
item("$211a", "");
@@ -191,7 +191,7 @@ bool PPUDebugger::property(unsigned id, string &name, string &value) {
//$2121
item("$2121", "");
item("CGRAM Address", string("0x", strhex<4>(regs.cgram_addr)));
item("CGRAM Address", string("0x", hex<4>(regs.cgram_addr)));
//$2123
item("$2123", "");

View File

@@ -31,15 +31,12 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
has_bsx_slot = false;
has_superfx = false;
has_sa1 = false;
has_upd77c25 = false;
has_srtc = false;
has_sdd1 = false;
has_spc7110 = false;
has_spc7110rtc = false;
has_cx4 = false;
has_dsp1 = false;
has_dsp2 = false;
has_dsp3 = false;
has_dsp4 = false;
has_obc1 = false;
has_st0010 = false;
has_st0011 = false;
@@ -48,6 +45,7 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
has_serial = false;
parse_xml(xml_list);
//print(xml_list[0], "\n");
if(ram_size > 0) {
memory::cartram.map(allocate<uint8_t>(ram_size, 0xff), ram_size);
@@ -103,7 +101,7 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
sha256_hash(&sha, shahash);
string hash;
foreach(n, shahash) hash << strhex<2>(n);
foreach(n, shahash) hash << hex<2>(n);
sha256 = hash;
bus.load_cart();

View File

@@ -37,15 +37,12 @@ public:
readonly<bool> has_bsx_slot;
readonly<bool> has_superfx;
readonly<bool> has_sa1;
readonly<bool> has_upd77c25;
readonly<bool> has_srtc;
readonly<bool> has_sdd1;
readonly<bool> has_spc7110;
readonly<bool> has_spc7110rtc;
readonly<bool> has_cx4;
readonly<bool> has_dsp1;
readonly<bool> has_dsp2;
readonly<bool> has_dsp3;
readonly<bool> has_dsp4;
readonly<bool> has_obc1;
readonly<bool> has_st0010;
readonly<bool> has_st0011;
@@ -88,6 +85,7 @@ private:
void xml_parse_ram(xml_element&);
void xml_parse_superfx(xml_element&);
void xml_parse_sa1(xml_element&);
void xml_parse_upd77c25(xml_element&);
void xml_parse_bsx(xml_element&);
void xml_parse_sufamiturbo(xml_element&);
void xml_parse_supergameboy(xml_element&);

View File

@@ -34,6 +34,7 @@ void Cartridge::parse_xml_cartridge(const char *data) {
if(node.name == "ram") xml_parse_ram(node);
if(node.name == "superfx") xml_parse_superfx(node);
if(node.name == "sa1") xml_parse_sa1(node);
if(node.name == "upd77c25") xml_parse_upd77c25(node);
if(node.name == "bsx") xml_parse_bsx(node);
if(node.name == "sufamiturbo") xml_parse_sufamiturbo(node);
if(node.name == "supergameboy") xml_parse_supergameboy(node);
@@ -41,7 +42,6 @@ void Cartridge::parse_xml_cartridge(const char *data) {
if(node.name == "sdd1") xml_parse_sdd1(node);
if(node.name == "spc7110") xml_parse_spc7110(node);
if(node.name == "cx4") xml_parse_cx4(node);
if(node.name == "necdsp") xml_parse_necdsp(node);
if(node.name == "obc1") xml_parse_obc1(node);
if(node.name == "setadsp") xml_parse_setadsp(node);
if(node.name == "setarisc") xml_parse_setarisc(node);
@@ -74,7 +74,7 @@ void Cartridge::parse_xml_gameboy(const char *data) {
if(leaf.name == "ram") {
foreach(attr, leaf.attribute) {
if(attr.name == "size") {
supergameboy_ram_size = strhex(attr.content);
supergameboy_ram_size = hex(attr.content);
}
}
}
@@ -90,8 +90,8 @@ void Cartridge::xml_parse_rom(xml_element &root) {
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = strhex(attr.content);
if(attr.name == "size") m.size = strhex(attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
mapping.append(m);
}
@@ -100,7 +100,7 @@ void Cartridge::xml_parse_rom(xml_element &root) {
void Cartridge::xml_parse_ram(xml_element &root) {
foreach(attr, root.attribute) {
if(attr.name == "size") ram_size = strhex(attr.content);
if(attr.name == "size") ram_size = hex(attr.content);
}
foreach(leaf, root.element) {
@@ -109,8 +109,8 @@ void Cartridge::xml_parse_ram(xml_element &root) {
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = strhex(attr.content);
if(attr.name == "size") m.size = strhex(attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
mapping.append(m);
}
@@ -128,15 +128,15 @@ void Cartridge::xml_parse_superfx(xml_element &root) {
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = strhex(attr.content);
if(attr.name == "size") m.size = strhex(attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
mapping.append(m);
}
}
} else if(node.name == "ram") {
foreach(attr, node.attribute) {
if(attr.name == "size") ram_size = strhex(attr.content);
if(attr.name == "size") ram_size = hex(attr.content);
}
foreach(leaf, node.element) {
@@ -145,8 +145,8 @@ void Cartridge::xml_parse_superfx(xml_element &root) {
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = strhex(attr.content);
if(attr.name == "size") m.size = strhex(attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
mapping.append(m);
}
@@ -176,8 +176,8 @@ void Cartridge::xml_parse_sa1(xml_element &root) {
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = strhex(attr.content);
if(attr.name == "size") m.size = strhex(attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
mapping.append(m);
}
@@ -189,15 +189,15 @@ void Cartridge::xml_parse_sa1(xml_element &root) {
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = strhex(attr.content);
if(attr.name == "size") m.size = strhex(attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
mapping.append(m);
}
}
} else if(node.name == "bwram") {
foreach(attr, node.attribute) {
if(attr.name == "size") ram_size = strhex(attr.content);
if(attr.name == "size") ram_size = hex(attr.content);
}
foreach(leaf, node.element) {
@@ -206,8 +206,8 @@ void Cartridge::xml_parse_sa1(xml_element &root) {
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = strhex(attr.content);
if(attr.name == "size") m.size = strhex(attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
mapping.append(m);
}
@@ -226,6 +226,85 @@ void Cartridge::xml_parse_sa1(xml_element &root) {
}
}
void Cartridge::xml_parse_upd77c25(xml_element &root) {
has_upd77c25 = true;
bool program = false;
bool sha256 = false;
string xml_hash;
string rom_hash;
for(unsigned n = 0; n < 2048; n++) upd77c25.programROM[n] = 0;
for(unsigned n = 0; n < 1024; n++) upd77c25.dataROM[n] = 0;
foreach(attr, root.attribute) {
if(attr.name == "program") {
file fp;
fp.open(string(dir(basename()), attr.content), file::mode::read);
if(fp.open() && fp.size() == 8192) {
program = true;
for(unsigned n = 0; n < 2048; n++) {
upd77c25.programROM[n] = fp.readm(3);
}
for(unsigned n = 0; n < 1024; n++) {
upd77c25.dataROM[n] = fp.readm(2);
}
fp.seek(0);
uint8 data[8192];
fp.read(data, 8192);
fp.close();
sha256_ctx sha;
uint8 shahash[32];
sha256_init(&sha);
sha256_chunk(&sha, data, 8192);
sha256_final(&sha);
sha256_hash(&sha, shahash);
foreach(n, shahash) rom_hash.append(hex<2>(n));
}
} else if(attr.name == "sha256") {
sha256 = true;
xml_hash = attr.content;
}
}
foreach(node, root.element) {
if(node.name == "dr") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(upd77c25dr);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
} else if(node.name == "sr") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(upd77c25sr);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
}
if(program == false) {
system.interface->message("Warning: uPD77C25 program is missing.");
} else if(sha256 == true && xml_hash != rom_hash) {
system.interface->message({
"Warning: uPD77C25 program SHA256 is incorrect.\n\n"
"Expected:\n", xml_hash, "\n\n"
"Actual:\n", rom_hash
});
}
}
void Cartridge::xml_parse_bsx(xml_element &root) {
if(mode != Mode::BsxSlotted && mode != Mode::Bsx) return;
@@ -237,8 +316,8 @@ void Cartridge::xml_parse_bsx(xml_element &root) {
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = strhex(attr.content);
if(attr.name == "size") m.size = strhex(attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
mapping.append(m);
}
@@ -278,8 +357,8 @@ void Cartridge::xml_parse_sufamiturbo(xml_element &root) {
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = strhex(attr.content);
if(attr.name == "size") m.size = strhex(attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
if(m.memory->size() > 0) mapping.append(m);
}
@@ -291,8 +370,8 @@ void Cartridge::xml_parse_sufamiturbo(xml_element &root) {
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = strhex(attr.content);
if(attr.name == "size") m.size = strhex(attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
if(m.memory->size() > 0) mapping.append(m);
}
@@ -394,7 +473,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
Mapping m(spc7110mcu);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "offset") spc7110_data_rom_offset = strhex(attr.content);
if(attr.name == "offset") spc7110_data_rom_offset = hex(attr.content);
}
mapping.append(m);
}
@@ -411,7 +490,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
}
} else if(node.name == "ram") {
foreach(attr, node.attribute) {
if(attr.name == "size") ram_size = strhex(attr.content);
if(attr.name == "size") ram_size = hex(attr.content);
}
foreach(leaf, node.element) {
@@ -420,8 +499,8 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = strhex(attr.content);
if(attr.name == "size") m.size = strhex(attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
mapping.append(m);
}
@@ -460,55 +539,6 @@ void Cartridge::xml_parse_cx4(xml_element &root) {
}
}
void Cartridge::xml_parse_necdsp(xml_element &root) {
unsigned program = 0;
foreach(attr, root.attribute) {
if(attr.name == "program") {
if(attr.content == "DSP-1" || attr.content == "DSP-1A" || attr.content == "DSP-1B") {
program = 1;
has_dsp1 = true;
} else if(attr.content == "DSP-2") {
program = 2;
has_dsp2 = true;
} else if(attr.content == "DSP-3") {
program = 3;
has_dsp3 = true;
} else if(attr.content == "DSP-4") {
program = 4;
has_dsp4 = true;
}
}
}
Memory *dr[5] = { 0, &dsp1dr, &dsp2dr, &dsp3, &dsp4 };
Memory *sr[5] = { 0, &dsp1sr, &dsp2sr, &dsp3, &dsp4 };
foreach(node, root.element) {
if(node.name == "dr" && dr[program]) {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(*dr[program]);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
} else if(node.name == "sr" && sr[program]) {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(*sr[program]);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
}
}
void Cartridge::xml_parse_obc1(xml_element &root) {
has_obc1 = true;
@@ -618,20 +648,20 @@ void Cartridge::xml_parse_address(Mapping &m, const string &data) {
lstring subpart;
subpart.split("-", part[0]);
if(subpart.size() == 1) {
m.banklo = strhex(subpart[0]);
m.banklo = hex(subpart[0]);
m.bankhi = m.banklo;
} else if(subpart.size() == 2) {
m.banklo = strhex(subpart[0]);
m.bankhi = strhex(subpart[1]);
m.banklo = hex(subpart[0]);
m.bankhi = hex(subpart[1]);
}
subpart.split("-", part[1]);
if(subpart.size() == 1) {
m.addrlo = strhex(subpart[0]);
m.addrlo = hex(subpart[0]);
m.addrhi = m.addrlo;
} else if(subpart.size() == 2) {
m.addrlo = strhex(subpart[0]);
m.addrhi = strhex(subpart[1]);
m.addrlo = hex(subpart[0]);
m.addrhi = hex(subpart[1]);
}
}

View File

@@ -84,7 +84,7 @@ bool Cheat::decode(const char *s, unsigned &addr, uint8 &data, Type &type) {
for(unsigned i = 0; i < 8; i++) if(!ischr(t[i])) return false;
type = Type::ProActionReplay;
unsigned r = strhex((const char*)t);
unsigned r = hex((const char*)t);
addr = r >> 8;
data = r & 0xff;
return true;
@@ -96,7 +96,7 @@ bool Cheat::decode(const char *s, unsigned &addr, uint8 &data, Type &type) {
type = Type::GameGenie;
t.transform("df4709156bc8a23e", "0123456789abcdef");
unsigned r = strhex((const char*)t);
unsigned r = hex((const char*)t);
//8421 8421 8421 8421 8421 8421
//abcd efgh ijkl mnop qrst uvwx
//ijkl qrst opab cduv wxef ghmn
@@ -125,7 +125,7 @@ bool Cheat::encode(string &s, unsigned addr, uint8 data, Type type) {
char t[16];
if(type == Type::ProActionReplay) {
s = string(strhex<6>(addr), strhex<2>(data));
s = string(hex<6>(addr), hex<2>(data));
return true;
} else if(type == Type::GameGenie) {
unsigned r = addr;
@@ -141,7 +141,7 @@ bool Cheat::encode(string &s, unsigned addr, uint8 data, Type type) {
| (!!(r & 0x080000) << 5) | (!!(r & 0x040000) << 4)
| (!!(r & 0x020000) << 3) | (!!(r & 0x010000) << 2)
| (!!(r & 0x000800) << 1) | (!!(r & 0x000400) << 0);
s = string(strhex<2>(data), strhex<2>(addr >> 16), "-", strhex<4>(addr & 0xffff));
s = string(hex<2>(data), hex<2>(addr >> 16), "-", hex<4>(addr & 0xffff));
s.transform("0123456789abcdef", "df4709156bc8a23e");
return true;
} else {

View File

@@ -6,15 +6,12 @@ struct Coprocessor : Processor {
#include <chip/supergameboy/supergameboy.hpp>
#include <chip/superfx/superfx.hpp>
#include <chip/sa1/sa1.hpp>
#include <chip/upd77c25/upd77c25.hpp>
#include <chip/bsx/bsx.hpp>
#include <chip/srtc/srtc.hpp>
#include <chip/sdd1/sdd1.hpp>
#include <chip/spc7110/spc7110.hpp>
#include <chip/cx4/cx4.hpp>
#include <chip/dsp1/dsp1.hpp>
#include <chip/dsp2/dsp2.hpp>
#include <chip/dsp3/dsp3.hpp>
#include <chip/dsp4/dsp4.hpp>
#include <chip/obc1/obc1.hpp>
#include <chip/st0010/st0010.hpp>
#include <chip/st0011/st0011.hpp>

View File

@@ -1,33 +0,0 @@
#include <snes.hpp>
#define DSP1_CPP
namespace SNES {
DSP1 dsp1;
DSP1DR dsp1dr;
DSP1SR dsp1sr;
#include "serialization.cpp"
#include "dsp1emu.cpp"
void DSP1::init() {
}
void DSP1::enable() {
}
void DSP1::power() {
reset();
}
void DSP1::reset() {
dsp1.reset();
}
uint8 DSP1DR::read(unsigned addr) { return dsp1.dsp1.getDr(); }
void DSP1DR::write(unsigned addr, uint8 data) { dsp1.dsp1.setDr(data); }
uint8 DSP1SR::read(unsigned addr) { return dsp1.dsp1.getSr(); }
void DSP1SR::write(unsigned addr, uint8 data) {}
}

View File

@@ -1,30 +0,0 @@
#include "dsp1emu.hpp"
class DSP1 {
public:
void init();
void enable();
void power();
void reset();
void serialize(serializer&);
private:
Dsp1 dsp1;
friend class DSP1DR;
friend class DSP1SR;
};
class DSP1DR : public Memory {
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
};
class DSP1SR : public Memory {
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
};
extern DSP1 dsp1;
extern DSP1DR dsp1dr;
extern DSP1SR dsp1sr;

File diff suppressed because it is too large Load Diff

View File

@@ -1,129 +0,0 @@
// DSP-1's emulation code
//
// Based on research by Overload, The Dumper, Neviksti and Andreas Naive
// Date: June 2006
#ifndef __DSP1EMUL_H
#define __DSP1EMUL_H
#define DSP1_VERSION 0x0102
class Dsp1
{
public:
// The DSP-1 status register has 16 bits, but only
// the upper 8 bits can be accessed from an external device, so all these
// positions are referred to the upper byte (bits D8 to D15)
enum SrFlags {DRC=0x04, DRS=0x10, RQM=0x80};
// According to Overload's docs, these are the meanings of the flags:
// DRC: The Data Register Control (DRC) bit specifies the data transfer length to and from the host CPU.
// 0: Data transfer to and from the DSP-1 is 16 bits.
// 1: Data transfer to and from the DSP-1 is 8 bits.
// DRS: The Data Register Status (DRS) bit indicates the data transfer status in the case of transfering 16-bit data.
// 0: Data transfer has terminated.
// 1: Data transfer in progress.
// RQM: The Request for Master (RQM) indicates that the DSP1 is requesting host CPU for data read/write.
// 0: Internal Data Register Transfer.
// 1: External Data Register Transfer.
Dsp1();
uint8 getSr(); // return the status register's high byte
uint8 getDr();
void setDr(uint8 iDr);
void reset();
void serialize(serializer&);
private:
enum FsmMajorState {WAIT_COMMAND, READ_DATA, WRITE_DATA};
enum MaxDataAccesses {MAX_READS=7, MAX_WRITES=1024};
struct Command {
void (Dsp1::*callback)(int16 *, int16 *);
unsigned int reads;
unsigned int writes;
};
static const Command mCommandTable[];
static const int16 MaxAZS_Exp[16];
static const int16 SinTable[];
static const int16 MulTable[];
static const uint16 DataRom[];
struct SharedData { // some RAM variables shared between commands
int16 MatrixA[3][3]; // attitude matrix A
int16 MatrixB[3][3];
int16 MatrixC[3][3];
int16 CentreX, CentreY, CentreZ; // center of projection
int16 CentreZ_C, CentreZ_E;
int16 VOffset; // vertical offset of the screen with regard to the centre of projection
int16 Les, C_Les, E_Les;
int16 SinAas, CosAas;
int16 SinAzs, CosAzs;
int16 SinAZS, CosAZS;
int16 SecAZS_C1, SecAZS_E1;
int16 SecAZS_C2, SecAZS_E2;
int16 Nx, Ny, Nz; // normal vector to the screen (norm 1, points toward the center of projection)
int16 Gx, Gy, Gz; // center of the screen (global coordinates)
int16 Hx, Hy; // horizontal vector of the screen (Hz=0, norm 1, points toward the right of the screen)
int16 Vx, Vy, Vz; // vertical vector of the screen (norm 1, points toward the top of the screen)
} shared;
uint8 mSr; // status register
int mSrLowByteAccess;
uint16 mDr; // "internal" representation of the data register
unsigned mFsmMajorState; // current major state of the FSM
uint8 mCommand; // current command processed by the FSM
uint8 mDataCounter; // #uint16 read/writes counter used by the FSM
int16 mReadBuffer[MAX_READS];
int16 mWriteBuffer[MAX_WRITES];
bool mFreeze; // need explanation? ;)
void fsmStep(bool read, uint8 &data); // FSM logic
// commands
void memoryTest(int16 *input, int16 *output);
void memoryDump(int16 *input, int16 *output);
void memorySize(int16 *input, int16 *output);
void multiply(int16* input, int16* output);
void multiply2(int16* input, int16* output);
void inverse(int16 *input, int16 *output);
void triangle(int16 *input, int16 *output);
void radius(int16 *input, int16 *output);
void range(int16 *input, int16 *output);
void range2(int16 *input, int16 *output);
void distance(int16 *input, int16 *output);
void rotate(int16 *input, int16 *output);
void polar(int16 *input, int16 *output);
void attitudeA(int16 *input, int16 *output);
void attitudeB(int16 *input, int16 *output);
void attitudeC(int16 *input, int16 *output);
void objectiveA(int16 *input, int16 *output);
void objectiveB(int16 *input, int16 *output);
void objectiveC(int16 *input, int16 *output);
void subjectiveA(int16 *input, int16 *output);
void subjectiveB(int16 *input, int16 *output);
void subjectiveC(int16 *input, int16 *output);
void scalarA(int16 *input, int16 *output);
void scalarB(int16 *input, int16 *output);
void scalarC(int16 *input, int16 *output);
void gyrate(int16 *input, int16 *output);
void parameter(int16 *input, int16 *output);
void raster(int16 *input, int16 *output);
void target(int16 *input, int16 *output);
void project(int16 *input, int16 *output);
// auxiliar functions
int16 sin(int16 Angle);
int16 cos(int16 Angle);
void inverse(int16 Coefficient, int16 Exponent, int16 &iCoefficient, int16 &iExponent);
int16 denormalizeAndClip(int16 C, int16 E);
void normalize(int16 m, int16 &Coefficient, int16 &Exponent);
void normalizeDouble(int32 Product, int16 &Coefficient, int16 &Exponent);
int16 shiftR(int16 C, int16 E);
};
#endif

View File

@@ -1,56 +0,0 @@
#ifdef DSP1_CPP
void DSP1::serialize(serializer &s) {
dsp1.serialize(s);
}
void Dsp1::serialize(serializer &s) {
for(unsigned i = 0; i < 3; i++) {
s.array(shared.MatrixA[i]);
s.array(shared.MatrixB[i]);
s.array(shared.MatrixC[i]);
}
s.integer(shared.CentreX);
s.integer(shared.CentreY);
s.integer(shared.CentreZ);
s.integer(shared.CentreZ_C);
s.integer(shared.CentreZ_E);
s.integer(shared.VOffset);
s.integer(shared.Les);
s.integer(shared.C_Les);
s.integer(shared.E_Les);
s.integer(shared.SinAas);
s.integer(shared.CosAas);
s.integer(shared.SinAzs);
s.integer(shared.CosAzs);
s.integer(shared.SinAZS);
s.integer(shared.CosAZS);
s.integer(shared.SecAZS_C1);
s.integer(shared.SecAZS_E1);
s.integer(shared.SecAZS_C2);
s.integer(shared.SecAZS_E2);
s.integer(shared.Nx);
s.integer(shared.Ny);
s.integer(shared.Nz);
s.integer(shared.Gx);
s.integer(shared.Gy);
s.integer(shared.Gz);
s.integer(shared.Hx);
s.integer(shared.Hy);
s.integer(shared.Vx);
s.integer(shared.Vy);
s.integer(shared.Vz);
s.integer(mSr);
s.integer(mSrLowByteAccess);
s.integer(mDr);
s.integer(mFsmMajorState);
s.integer(mCommand);
s.integer(mDataCounter);
s.array(mReadBuffer);
s.array(mWriteBuffer);
s.integer(mFreeze);
}
#endif

View File

@@ -1,153 +0,0 @@
#include <snes.hpp>
#define DSP2_CPP
namespace SNES {
DSP2 dsp2;
DSP2DR dsp2dr;
DSP2SR dsp2sr;
#include "serialization.cpp"
#include "opcodes.cpp"
void DSP2::init() {
}
void DSP2::enable() {
}
void DSP2::power() {
reset();
}
void DSP2::reset() {
status.waiting_for_command = true;
status.in_count = 0;
status.in_index = 0;
status.out_count = 0;
status.out_index = 0;
status.op05transparent = 0;
status.op05haslen = false;
status.op05len = 0;
status.op06haslen = false;
status.op06len = 0;
status.op09word1 = 0;
status.op09word2 = 0;
status.op0dhaslen = false;
status.op0doutlen = 0;
status.op0dinlen = 0;
}
uint8 DSP2::read(unsigned addr) {
uint8 r = 0xff;
if(status.out_count) {
r = status.output[status.out_index++];
status.out_index &= 511;
if(status.out_count == status.out_index) {
status.out_count = 0;
}
}
return r;
}
void DSP2::write(unsigned addr, uint8 data) {
if(status.waiting_for_command) {
status.command = data;
status.in_index = 0;
status.waiting_for_command = false;
switch(data) {
case 0x01: status.in_count = 32; break;
case 0x03: status.in_count = 1; break;
case 0x05: status.in_count = 1; break;
case 0x06: status.in_count = 1; break;
case 0x07: break;
case 0x08: break;
case 0x09: status.in_count = 4; break;
case 0x0d: status.in_count = 2; break;
case 0x0f: status.in_count = 0; break;
}
} else {
status.parameters[status.in_index++] = data;
status.in_index &= 511;
}
if(status.in_count == status.in_index) {
status.waiting_for_command = true;
status.out_index = 0;
switch(status.command) {
case 0x01: {
status.out_count = 32;
op01();
} break;
case 0x03: {
op03();
} break;
case 0x05: {
if(status.op05haslen) {
status.op05haslen = false;
status.out_count = status.op05len;
op05();
} else {
status.op05len = status.parameters[0];
status.in_index = 0;
status.in_count = status.op05len * 2;
status.op05haslen = true;
if(data)status.waiting_for_command = false;
}
} break;
case 0x06: {
if(status.op06haslen) {
status.op06haslen = false;
status.out_count = status.op06len;
op06();
} else {
status.op06len = status.parameters[0];
status.in_index = 0;
status.in_count = status.op06len;
status.op06haslen = true;
if(data)status.waiting_for_command = false;
}
} break;
case 0x07: break;
case 0x08: break;
case 0x09: {
op09();
} break;
case 0x0d: {
if(status.op0dhaslen) {
status.op0dhaslen = false;
status.out_count = status.op0doutlen;
op0d();
} else {
status.op0dinlen = status.parameters[0];
status.op0doutlen = status.parameters[1];
status.in_index = 0;
status.in_count = (status.op0dinlen + 1) >> 1;
status.op0dhaslen = true;
if(data)status.waiting_for_command = false;
}
} break;
case 0x0f: break;
}
}
}
DSP2::DSP2() {}
DSP2::~DSP2() {}
uint8 DSP2DR::read(unsigned addr) { return dsp2.read(addr); }
void DSP2DR::write(unsigned addr, uint8 data) { dsp2.write(addr, data); }
uint8 DSP2SR::read(unsigned addr) { return 0x00; }
void DSP2SR::write(unsigned addr, uint8 data) {}
}

View File

@@ -1,57 +0,0 @@
class DSP2 {
public:
struct {
bool waiting_for_command;
unsigned command;
unsigned in_count, in_index;
unsigned out_count, out_index;
uint8 parameters[512];
uint8 output[512];
uint8 op05transparent;
bool op05haslen;
int op05len;
bool op06haslen;
int op06len;
uint16 op09word1;
uint16 op09word2;
bool op0dhaslen;
int op0doutlen;
int op0dinlen;
} status;
void init();
void enable();
void power();
void reset();
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
void serialize(serializer&);
DSP2();
~DSP2();
protected:
void op01();
void op03();
void op05();
void op06();
void op09();
void op0d();
};
class DSP2DR : public Memory {
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
};
class DSP2SR : public Memory {
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
};
extern DSP2 dsp2;
extern DSP2DR dsp2dr;
extern DSP2SR dsp2sr;

View File

@@ -1,177 +0,0 @@
#ifdef DSP2_CPP
//convert bitmap to bitplane tile
void DSP2::op01() {
//op01 size is always 32 bytes input and output
//the hardware does strange things if you vary the size
unsigned char c0, c1, c2, c3;
unsigned char *p1 = status.parameters;
unsigned char *p2a = status.output;
unsigned char *p2b = status.output + 16; //halfway
//process 8 blocks of 4 bytes each
for(int j = 0; j < 8; j++) {
c0 = *p1++;
c1 = *p1++;
c2 = *p1++;
c3 = *p1++;
*p2a++ = (c0 & 0x10) << 3 |
(c0 & 0x01) << 6 |
(c1 & 0x10) << 1 |
(c1 & 0x01) << 4 |
(c2 & 0x10) >> 1 |
(c2 & 0x01) << 2 |
(c3 & 0x10) >> 3 |
(c3 & 0x01);
*p2a++ = (c0 & 0x20) << 2 |
(c0 & 0x02) << 5 |
(c1 & 0x20) |
(c1 & 0x02) << 3 |
(c2 & 0x20) >> 2 |
(c2 & 0x02) << 1 |
(c3 & 0x20) >> 4 |
(c3 & 0x02) >> 1;
*p2b++ = (c0 & 0x40) << 1 |
(c0 & 0x04) << 4 |
(c1 & 0x40) >> 1 |
(c1 & 0x04) << 2 |
(c2 & 0x40) >> 3 |
(c2 & 0x04) |
(c3 & 0x40) >> 5 |
(c3 & 0x04) >> 2;
*p2b++ = (c0 & 0x80) |
(c0 & 0x08) << 3 |
(c1 & 0x80) >> 2 |
(c1 & 0x08) << 1 |
(c2 & 0x80) >> 4 |
(c2 & 0x08) >> 1 |
(c3 & 0x80) >> 6 |
(c3 & 0x08) >> 3;
}
}
//set transparent color
void DSP2::op03() {
status.op05transparent = status.parameters[0];
}
//replace bitmap using transparent color
void DSP2::op05() {
uint8 color;
// Overlay bitmap with transparency.
// Input:
//
// Bitmap 1: i[0] <=> i[size-1]
// Bitmap 2: i[size] <=> i[2*size-1]
//
// Output:
//
// Bitmap 3: o[0] <=> o[size-1]
//
// Processing:
//
// Process all 4-bit pixels (nibbles) in the bitmap
//
// if ( BM2_pixel == transparent_color )
// pixelout = BM1_pixel
// else
// pixelout = BM2_pixel
// The max size bitmap is limited to 255 because the size parameter is a byte
// I think size=0 is an error. The behavior of the chip on size=0 is to
// return the last value written to DR if you read DR on Op05 with
// size = 0. I don't think it's worth implementing this quirk unless it's
// proven necessary.
unsigned char c1, c2;
unsigned char *p1 = status.parameters;
unsigned char *p2 = status.parameters + status.op05len;
unsigned char *p3 = status.output;
color = status.op05transparent & 0x0f;
for(int n = 0; n < status.op05len; n++) {
c1 = *p1++;
c2 = *p2++;
*p3++ = ( ((c2 >> 4) == color ) ? c1 & 0xf0 : c2 & 0xf0 ) |
( ((c2 & 0x0f) == color ) ? c1 & 0x0f : c2 & 0x0f );
}
}
//reverse bitmap
void DSP2::op06() {
// Input:
// size
// bitmap
int i, j;
for(i = 0, j = status.op06len - 1; i < status.op06len; i++, j--) {
status.output[j] = (status.parameters[i] << 4) | (status.parameters[i] >> 4);
}
}
//multiply
void DSP2::op09() {
status.out_count = 4;
status.op09word1 = status.parameters[0] | (status.parameters[1] << 8);
status.op09word2 = status.parameters[2] | (status.parameters[3] << 8);
uint32 r;
r = status.op09word1 * status.op09word2;
status.output[0] = r;
status.output[1] = r >> 8;
status.output[2] = r >> 16;
status.output[3] = r >> 24;
}
//scale bitmap
void DSP2::op0d() {
// Bit accurate hardware algorithm - uses fixed point math
// This should match the DSP2 Op0D output exactly
// I wouldn't recommend using this unless you're doing hardware debug.
// In some situations it has small visual artifacts that
// are not readily apparent on a TV screen but show up clearly
// on a monitor. Use Overload's scaling instead.
// This is for hardware verification testing.
//
// One note: the HW can do odd byte scaling but since we divide
// by two to get the count of bytes this won't work well for
// odd byte scaling (in any of the current algorithm implementations).
// So far I haven't seen Dungeon Master use it.
// If it does we can adjust the parameters and code to work with it
uint32 multiplier; // Any size int >= 32-bits
uint32 pixloc; // match size of multiplier
int i, j;
uint8 pixelarray[512];
if(status.op0dinlen <= status.op0doutlen) {
multiplier = 0x10000; // In our self defined fixed point 0x10000 == 1
} else {
multiplier = (status.op0dinlen << 17) / ((status.op0doutlen << 1) + 1);
}
pixloc = 0;
for(i = 0; i < status.op0doutlen * 2; i++) {
j = pixloc >> 16;
if(j & 1) {
pixelarray[i] = (status.parameters[j >> 1] & 0x0f);
} else {
pixelarray[i] = (status.parameters[j >> 1] & 0xf0) >> 4;
}
pixloc += multiplier;
}
for(i = 0; i < status.op0doutlen; i++) {
status.output[i] = (pixelarray[i << 1] << 4) | pixelarray[(i << 1) + 1];
}
}
#endif

View File

@@ -1,26 +0,0 @@
#ifdef DSP2_CPP
void DSP2::serialize(serializer &s) {
s.integer(status.waiting_for_command);
s.integer(status.command);
s.integer(status.in_count);
s.integer(status.in_index);
s.integer(status.out_count);
s.integer(status.out_index);
s.array(status.parameters);
s.array(status.output);
s.integer(status.op05transparent);
s.integer(status.op05haslen);
s.integer(status.op05len);
s.integer(status.op06haslen);
s.integer(status.op06len);
s.integer(status.op09word1);
s.integer(status.op09word2);
s.integer(status.op0dhaslen);
s.integer(status.op0doutlen);
s.integer(status.op0dinlen);
}
#endif

View File

@@ -1,40 +0,0 @@
#include <snes.hpp>
#define DSP3_CPP
namespace SNES {
DSP3 dsp3;
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(unsigned addr) {
DSP3i::dsp3_address = addr & 0xffff;
DSP3i::DSP3GetByte();
return DSP3i::dsp3_byte;
}
void DSP3::write(unsigned addr, uint8 data) {
DSP3i::dsp3_address = addr & 0xffff;
DSP3i::dsp3_byte = data;
DSP3i::DSP3SetByte();
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,60 +0,0 @@
#include <snes.hpp>
#define DSP4_CPP
namespace SNES {
DSP4 dsp4;
void DSP4::init() {
}
void DSP4::enable() {
}
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::power() {
reset();
}
void DSP4::reset() {
DSP4i::InitDSP4();
}
uint8 DSP4::read(unsigned addr) {
addr &= 0xffff;
if(addr < 0xc000) {
DSP4i::dsp4_address = addr;
DSP4i::DSP4GetByte();
return DSP4i::dsp4_byte;
}
return 0x80;
}
void DSP4::write(unsigned addr, uint8 data) {
addr &= 0xffff;
if(addr < 0xc000) {
DSP4i::dsp4_address = addr;
DSP4i::dsp4_byte = data;
DSP4i::DSP4SetByte();
}
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,108 +0,0 @@
//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

@@ -0,0 +1,205 @@
string UPD77C25::disassemble(uint11 ip) {
string output = { hex<3>(ip), " " };
uint24 opcode = programROM[ip];
uint2 type = opcode >> 22;
if(type == 0 || type == 1) { //OP,RT
uint2 pselect = opcode >> 20;
uint4 alu = opcode >> 16;
uint1 asl = opcode >> 15;
uint2 dpl = opcode >> 13;
uint4 dphm = opcode >> 9;
uint1 rpdcr = opcode >> 8;
uint4 src = opcode >> 4;
uint4 dst = opcode >> 0;
switch(alu) {
case 0: output << "nop "; break;
case 1: output << "or "; break;
case 2: output << "and "; break;
case 3: output << "xor "; break;
case 4: output << "sub "; break;
case 5: output << "add "; break;
case 6: output << "sbb "; break;
case 7: output << "adc "; break;
case 8: output << "dec "; break;
case 9: output << "inc "; break;
case 10: output << "cmp "; break;
case 11: output << "shr1 "; break;
case 12: output << "shl1 "; break;
case 13: output << "shl2 "; break;
case 14: output << "shl4 "; break;
case 15: output << "xchg "; break;
}
if(alu < 8) {
switch(pselect) {
case 0: output << "ram,"; break;
case 1: output << "idb,"; break;
case 2: output << "m,"; break;
case 3: output << "n,"; break;
}
}
switch(asl) {
case 0: output << "a"; break;
case 1: output << "b"; break;
}
if(dst) {
output << "\n mov ";
switch(src) {
case 0: output << "trb,"; break;
case 1: output << "a,"; break;
case 2: output << "b,"; break;
case 3: output << "tr,"; break;
case 4: output << "dp,"; break;
case 5: output << "rp,"; break;
case 6: output << "ro,"; break;
case 7: output << "sgn,"; break;
case 8: output << "dr,"; break;
case 9: output << "drnf,"; break;
case 10: output << "sr,"; break;
case 11: output << "sim,"; break;
case 12: output << "sil,"; break;
case 13: output << "k,"; break;
case 14: output << "l,"; break;
case 15: output << "mem,"; break;
}
switch(dst) {
case 0: output << "non"; break;
case 1: output << "a"; break;
case 2: output << "b"; break;
case 3: output << "tr"; break;
case 4: output << "dp"; break;
case 5: output << "rp"; break;
case 6: output << "dr"; break;
case 7: output << "sr"; break;
case 8: output << "sol"; break;
case 9: output << "som"; break;
case 10: output << "k"; break;
case 11: output << "klr"; break;
case 12: output << "klm"; break;
case 13: output << "l"; break;
case 14: output << "trb"; break;
case 15: output << "mem"; break;
}
}
if(dpl) {
switch(dpl) {
case 0: output << "\n dpnop"; break;
case 1: output << "\n dpinc"; break;
case 2: output << "\n dpdec"; break;
case 3: output << "\n dpclr"; break;
}
}
if(dphm) {
switch(dphm) {
case 0: output << "\n m0"; break;
case 1: output << "\n m1"; break;
case 2: output << "\n m2"; break;
case 3: output << "\n m3"; break;
case 4: output << "\n m4"; break;
case 5: output << "\n m5"; break;
case 6: output << "\n m6"; break;
case 7: output << "\n m7"; break;
case 8: output << "\n m8"; break;
case 9: output << "\n m9"; break;
case 10: output << "\n ma"; break;
case 11: output << "\n mb"; break;
case 12: output << "\n mc"; break;
case 13: output << "\n md"; break;
case 14: output << "\n me"; break;
case 15: output << "\n mf"; break;
}
}
if(rpdcr == 1) {
output << "\n rpdec";
}
if(type == 1) {
output << "\n ret";
}
}
if(type == 2) { //JP
uint9 brch = opcode >> 13;
uint11 na = opcode >> 2;
switch(brch) {
case 0x080: output << "jnca "; break;
case 0x082: output << "jca "; break;
case 0x084: output << "jncb "; break;
case 0x086: output << "jcb "; break;
case 0x088: output << "jnza "; break;
case 0x08a: output << "jza "; break;
case 0x08c: output << "jnzb "; break;
case 0x08e: output << "jzb "; break;
case 0x090: output << "jnova0 "; break;
case 0x092: output << "jova0 "; break;
case 0x094: output << "jnovb0 "; break;
case 0x096: output << "jovb0 "; break;
case 0x098: output << "jnova1 "; break;
case 0x09a: output << "jova1 "; break;
case 0x09c: output << "jnovb1 "; break;
case 0x09e: output << "jovb1 "; break;
case 0x0a0: output << "jnsa0 "; break;
case 0x0a2: output << "jsa0 "; break;
case 0x0a4: output << "jnsb0 "; break;
case 0x0a6: output << "jsb0 "; break;
case 0x0a8: output << "jnsa1 "; break;
case 0x0aa: output << "jsa1 "; break;
case 0x0ac: output << "jnsb1 "; break;
case 0x0ae: output << "jsb1 "; break;
case 0x0b0: output << "jdpl0 "; break;
case 0x0b1: output << "jdpln0 "; break;
case 0x0b2: output << "jdplf "; break;
case 0x0b3: output << "jdplnf "; break;
case 0x0b4: output << "jnsiak "; break;
case 0x0b6: output << "jsiak "; break;
case 0x0b8: output << "jnsoak "; break;
case 0x0ba: output << "jsoak "; break;
case 0x0bc: output << "jnrqm "; break;
case 0x0be: output << "jrqm "; break;
case 0x100: output << "jmp "; break;
case 0x140: output << "call "; break;
default: output << "?????? "; break;
}
output << "$" << hex<3>(na);
}
if(type == 3) { //LD
output << "ld ";
uint16 id = opcode >> 6;
uint4 dst = opcode >> 0;
output << "$" << hex<4>(id) << ",";
switch(dst) {
case 0: output << "non"; break;
case 1: output << "a"; break;
case 2: output << "b"; break;
case 3: output << "tr"; break;
case 4: output << "dp"; break;
case 5: output << "rp"; break;
case 6: output << "dr"; break;
case 7: output << "sr"; break;
case 8: output << "sol"; break;
case 9: output << "som"; break;
case 10: output << "k"; break;
case 11: output << "klr"; break;
case 12: output << "klm"; break;
case 13: output << "l"; break;
case 14: output << "trb"; break;
case 15: output << "mem"; break;
}
}
return output;
}

View File

@@ -0,0 +1,52 @@
#ifdef UPD77C25_CPP
void UPD77C25::serialize(serializer &s) {
s.array(dataRAM);
s.integer(regs.pc);
for(unsigned n = 0; n < 4; n++) s.integer(regs.stack[n]);
s.integer(regs.rp);
s.integer(regs.dp);
s.integer(regs.k);
s.integer(regs.l);
s.integer(regs.m);
s.integer(regs.n);
s.integer(regs.a);
s.integer(regs.b);
s.integer(regs.flaga.s1);
s.integer(regs.flaga.s0);
s.integer(regs.flaga.c);
s.integer(regs.flaga.z);
s.integer(regs.flaga.ov1);
s.integer(regs.flaga.ov0);
s.integer(regs.flagb.s1);
s.integer(regs.flagb.s0);
s.integer(regs.flagb.c);
s.integer(regs.flagb.z);
s.integer(regs.flagb.ov1);
s.integer(regs.flagb.ov0);
s.integer(regs.tr);
s.integer(regs.trb);
s.integer(regs.sr.rqm);
s.integer(regs.sr.usf1);
s.integer(regs.sr.usf0);
s.integer(regs.sr.drs);
s.integer(regs.sr.dma);
s.integer(regs.sr.drc);
s.integer(regs.sr.soc);
s.integer(regs.sr.sic);
s.integer(regs.sr.ei);
s.integer(regs.sr.p1);
s.integer(regs.sr.p0);
s.integer(regs.dr);
s.integer(regs.siack);
s.integer(regs.soack);
s.integer(regs.idb);
}
#endif

View File

@@ -0,0 +1,344 @@
//NEC uPD77C25 emulation core
//author: byuu
//license: public domain
//unsupported components:
//* serial input/output
//* interrupts
//* DMA
#include <snes.hpp>
#define UPD77C25_CPP
namespace SNES {
#include "serialization.cpp"
#include "disassembler.cpp"
UPD77C25 upd77c25;
UPD77C25SR upd77c25sr;
UPD77C25DR upd77c25dr;
void UPD77C25::Enter() { upd77c25.enter(); }
void UPD77C25::enter() {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
uint24 opcode = programROM[regs.pc++];
switch(opcode >> 22) {
case 0: exec_op(opcode); break;
case 1: exec_rt(opcode); break;
case 2: exec_jp(opcode); break;
case 3: exec_ld(opcode); break;
}
int32 result = (int32)regs.k * regs.l; //sign + 30-bit result
regs.m = result >> 15; //store sign + top 15-bits
regs.n = result << 1; //store low 15-bits + zero
step(1);
synchronize_cpu();
}
}
void UPD77C25::exec_op(uint24 opcode) {
uint2 pselect = opcode >> 20; //P select
uint4 alu = opcode >> 16; //ALU operation mode
uint1 asl = opcode >> 15; //accumulator select
uint2 dpl = opcode >> 13; //DP low modify
uint4 dphm = opcode >> 9; //DP high XOR modify
uint1 rpdcr = opcode >> 8; //RP decrement
uint4 src = opcode >> 4; //move source
uint4 dst = opcode >> 0; //move destination
switch(src) {
case 0: regs.idb = regs.trb; break;
case 1: regs.idb = regs.a; break;
case 2: regs.idb = regs.b; break;
case 3: regs.idb = regs.tr; break;
case 4: regs.idb = regs.dp; break;
case 5: regs.idb = regs.rp; break;
case 6: regs.idb = dataROM[regs.rp]; break;
case 7: regs.idb = 0x8000 - regs.flaga.s1; break;
case 8: regs.idb = regs.dr; regs.sr.rqm = 1; break;
case 9: regs.idb = regs.dr; break;
case 10: regs.idb = regs.sr; break;
//case 11: regs.idb = regs.sim; break;
//case 12: regs.idb = regs.sil; break;
case 13: regs.idb = regs.k; break;
case 14: regs.idb = regs.l; break;
case 15: regs.idb = dataRAM[regs.dp]; break;
}
if(alu) {
uint16 p, q, r;
Flag flag;
bool c;
switch(pselect) {
case 0: p = dataRAM[regs.dp]; break;
case 1: p = regs.idb; break;
case 2: p = regs.m; break;
case 3: p = regs.n; break;
}
switch(asl) {
case 0: q = regs.a; flag = regs.flaga; c = regs.flagb.c; break;
case 1: q = regs.b; flag = regs.flagb; c = regs.flaga.c; break;
}
switch(alu) {
case 1: r = q | p; break; //OR
case 2: r = q & p; break; //AND
case 3: r = q ^ p; break; //XOR
case 4: r = q - p; break; //SUB
case 5: r = q + p; break; //ADD
case 6: r = q - p - c; break; //SBB
case 7: r = q + p + c; break; //ADC
case 8: r = q - 1; p = 1; break; //DEC
case 9: r = q + 1; p = 1; break; //INC
case 10: r = ~q; break; //CMP
case 11: r = (q >> 1) | (q & 0x8000); break; //SHR1 (ASR)
case 12: r = (q << 1) | c; break; //SHL1 (ROL)
case 13: r = (q << 2) | 3; break; //SHL2
case 14: r = (q << 4) | 15; break; //SHL4
case 15: r = (q << 8) | (q >> 8); break; //XCHG
}
flag.s0 = (r & 0x8000);
flag.z = (r == 0);
switch(alu) {
case 1: case 2: case 3: case 10: case 13: case 14: case 15: {
flag.c = 0;
flag.ov0 = 0;
flag.ov1 = 0;
break;
}
case 4: case 5: case 6: case 7: case 8: case 9: {
if(alu & 1) {
//addition
flag.ov0 = (q ^ r) & ~(q ^ p) & 0x8000;
flag.c = (r < q);
} else {
//subtraction
flag.ov0 = (q ^ r) & (q ^ p) & 0x8000;
flag.c = (r > q);
}
if(flag.ov0) {
flag.s1 = flag.ov1 ^ !(r & 0x8000);
flag.ov1 = !flag.ov1;
}
break;
}
case 11: {
flag.c = q & 1;
flag.ov0 = 0;
flag.ov1 = 0;
break;
}
case 12: {
flag.c = q >> 15;
flag.ov0 = 0;
flag.ov1 = 0;
break;
}
}
switch(asl) {
case 0: regs.a = r; regs.flaga = flag; break;
case 1: regs.b = r; regs.flagb = flag; break;
}
}
exec_ld((regs.idb << 6) + dst);
switch(dpl) {
case 1: regs.dp = (regs.dp & 0xf0) + ((regs.dp + 1) & 0x0f); break; //DPINC
case 2: regs.dp = (regs.dp & 0xf0) + ((regs.dp - 1) & 0x0f); break; //DPDEC
case 3: regs.dp = (regs.dp & 0xf0); break; //DPCLR
}
regs.dp ^= dphm << 4;
if(rpdcr) regs.rp--;
}
void UPD77C25::exec_rt(uint24 opcode) {
exec_op(opcode);
stack_pull();
}
void UPD77C25::exec_jp(uint24 opcode) {
uint9 brch = opcode >> 13; //branch
uint11 na = opcode >> 2; //next address
bool r = false;
switch(brch) {
case 0x080: r = (regs.flaga.c == 0); break; //JNCA
case 0x082: r = (regs.flaga.c == 1); break; //JCA
case 0x084: r = (regs.flagb.c == 0); break; //JNCB
case 0x086: r = (regs.flagb.c == 1); break; //JCB
case 0x088: r = (regs.flaga.z == 0); break; //JNZA
case 0x08a: r = (regs.flaga.z == 1); break; //JZA
case 0x08c: r = (regs.flagb.z == 0); break; //JNZB
case 0x08e: r = (regs.flagb.z == 1); break; //JZB
case 0x090: r = (regs.flaga.ov0 == 0); break; //JNOVA0
case 0x092: r = (regs.flaga.ov0 == 1); break; //JOVA0
case 0x094: r = (regs.flagb.ov0 == 0); break; //JNOVB0
case 0x096: r = (regs.flagb.ov0 == 1); break; //JOVB0
case 0x098: r = (regs.flaga.ov1 == 0); break; //JNOVA1
case 0x09a: r = (regs.flaga.ov1 == 1); break; //JOVA1
case 0x09c: r = (regs.flagb.ov1 == 0); break; //JNOVB1
case 0x09e: r = (regs.flagb.ov1 == 1); break; //JOVB1
case 0x0a0: r = (regs.flaga.s0 == 0); break; //JNSA0
case 0x0a2: r = (regs.flaga.s0 == 1); break; //JSA0
case 0x0a4: r = (regs.flagb.s0 == 0); break; //JNSB0
case 0x0a6: r = (regs.flagb.s0 == 1); break; //JSB0
case 0x0a8: r = (regs.flaga.s1 == 0); break; //JNSA1
case 0x0aa: r = (regs.flaga.s1 == 1); break; //JSA1
case 0x0ac: r = (regs.flagb.s1 == 0); break; //JNSB1
case 0x0ae: r = (regs.flagb.s1 == 1); break; //JSB1
case 0x0b0: r = (regs.dp & 0x0f) == 0x00; break; //JDPL0
case 0x0b1: r = (regs.dp & 0x0f) != 0x00; break; //JDPLN0
case 0x0b2: r = (regs.dp & 0x0f) == 0x0f; break; //JDPLF
case 0x0b3: r = (regs.dp & 0x0f) != 0x0f; break; //JDPLNF
case 0x0b4: r = (regs.siack == 0); break; //JNSIAK
case 0x0b6: r = (regs.siack == 1); break; //JSIAK
case 0x0b8: r = (regs.soack == 0); break; //JNSOAK
case 0x0ba: r = (regs.soack == 1); break; //JSOAK
case 0x0bc: r = (regs.sr.rqm == 0); break; //JNRQM
case 0x0be: r = (regs.sr.rqm == 1); break; //JRQM
case 0x100: r = true; break; //JMP
case 0x140: r = true; stack_push(); break; //CALL
}
if(r) regs.pc = na;
}
void UPD77C25::exec_ld(uint24 opcode) {
uint16 id = opcode >> 6; //immediate data
uint4 dst = opcode >> 0; //destination
regs.idb = id;
switch(dst) {
case 0: break;
case 1: regs.a = id; break;
case 2: regs.b = id; break;
case 3: regs.tr = id; break;
case 4: regs.dp = id; break;
case 5: regs.rp = id; break;
case 6: regs.dr = id; regs.sr.rqm = 1; break;
case 7: regs.sr = (regs.sr & 0x907c) | (id & ~0x907c); break;
//case 8: regs.sol = id; break;
//case 9: regs.som = id; break;
case 10: regs.k = id; break;
case 11: regs.k = id; regs.l = dataROM[regs.rp]; break;
case 12: regs.l = id; regs.k = dataRAM[regs.dp | 0x40]; break;
case 13: regs.l = id; break;
case 14: regs.trb = id; break;
case 15: dataRAM[regs.dp] = id; break;
}
}
void UPD77C25::stack_push() {
regs.stack[3] = regs.stack[2];
regs.stack[2] = regs.stack[1];
regs.stack[1] = regs.stack[0];
regs.stack[0] = regs.pc;
}
void UPD77C25::stack_pull() {
regs.pc = regs.stack[0];
regs.stack[0] = regs.stack[1];
regs.stack[1] = regs.stack[2];
regs.stack[2] = regs.stack[3];
regs.stack[3] = 0x000;
}
uint8 UPD77C25::read(bool mode) {
cpu.synchronize_coprocessor();
if(mode == 0) return regs.sr >> 8;
if(regs.sr.drc == 0) {
//16-bit
if(regs.sr.drs == 0) {
regs.sr.drs = 1;
return regs.dr >> 0;
} else {
regs.sr.rqm = 0;
regs.sr.drs = 0;
return regs.dr >> 8;
}
} else {
//8-bit
regs.sr.rqm = 0;
return regs.dr >> 0;
}
}
void UPD77C25::write(bool mode, uint8 data) {
cpu.synchronize_coprocessor();
if(mode == 0) return;
if(regs.sr.drc == 0) {
//16-bit
if(regs.sr.drs == 0) {
regs.sr.drs = 1;
regs.dr = (regs.dr & 0xff00) | (data << 0);
} else {
regs.sr.rqm = 0;
regs.sr.drs = 0;
regs.dr = (data << 8) | (regs.dr & 0x00ff);
}
} else {
//8-bit
regs.sr.rqm = 0;
regs.dr = (regs.dr & 0xff00) | (data << 0);
}
}
void UPD77C25::init() {
}
void UPD77C25::enable() {
}
void UPD77C25::power() {
for(unsigned i = 0; i < 256; i++) dataRAM[i] = 0x0000;
reset();
}
void UPD77C25::reset() {
create(UPD77C25::Enter, 8 * 1024 * 1024); //8.192MHz
regs.pc = 0x000;
regs.stack[0] = 0x000;
regs.stack[1] = 0x000;
regs.stack[2] = 0x000;
regs.stack[3] = 0x000;
regs.flaga = 0x00;
regs.flagb = 0x00;
regs.sr = 0x0000;
regs.rp = 0x3ff;
regs.siack = 0;
regs.soack = 0;
}
uint8 UPD77C25SR::read(unsigned) { return upd77c25.read(0); }
void UPD77C25SR::write(unsigned, uint8 data) { upd77c25.write(0, data); }
uint8 UPD77C25DR::read(unsigned) { return upd77c25.read(1); }
void UPD77C25DR::write(unsigned, uint8 data) { upd77c25.write(1, data); }
}

View File

@@ -0,0 +1,98 @@
class UPD77C25 : public Coprocessor {
public:
static void Enter();
void enter();
void init();
void enable();
void power();
void reset();
void serialize(serializer &s);
uint24 programROM[2048];
uint16 dataROM[1024];
uint16 dataRAM[256];
string disassemble(uint11 ip);
private:
struct Flag {
bool s1, s0, c, z, ov1, ov0;
inline operator unsigned() const {
return (s1 << 5) + (s0 << 4) + (c << 3) + (z << 2) + (ov1 << 1) + (ov0 << 0);
}
inline unsigned operator=(unsigned d) {
s1 = d & 0x20; s0 = d & 0x10; c = d & 0x08; z = d & 0x04; ov1 = d & 0x02; ov0 = d & 0x01;
return d;
}
};
struct Status {
bool rqm, usf1, usf0, drs, dma, drc, soc, sic, ei, p1, p0;
inline operator unsigned() const {
return (rqm << 15) + (usf1 << 14) + (usf0 << 13) + (drs << 12)
+ (dma << 11) + (drc << 10) + (soc << 9) + (sic << 8)
+ (ei << 7) + (p1 << 1) + (p0 << 0);
}
inline unsigned operator=(unsigned d) {
rqm = d & 0x8000; usf1 = d & 0x4000; usf0 = d & 0x2000; drs = d & 0x1000;
dma = d & 0x0800; drc = d & 0x0400; soc = d & 0x0200; sic = d & 0x0100;
ei = d & 0x0080; p1 = d & 0x0002; p0 = d & 0x0001;
return d;
}
};
struct Regs {
uint11 pc; //program counter
uint11 stack[4]; //LIFO
uint10 rp; //ROM pointer
uint8 dp; //data pointer
int16 k;
int16 l;
int16 m;
int16 n;
int16 a; //accumulator
int16 b; //accumulator
Flag flaga;
Flag flagb;
uint16 tr; //temporary register
uint16 trb; //temporary register
Status sr; //status register
uint16 dr; //data register
bool siack;
bool soack;
uint16 idb;
} regs;
void exec_op(uint24 opcode);
void exec_rt(uint24 opcode);
void exec_jp(uint24 opcode);
void exec_ld(uint24 opcode);
void stack_push();
void stack_pull();
uint8 read(bool mode);
void write(bool mode, uint8 data);
friend class UPD77C25SR;
friend class UPD77C25DR;
};
class UPD77C25SR : public Memory {
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
};
class UPD77C25DR : public Memory {
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
};
extern UPD77C25 upd77c25;
extern UPD77C25SR upd77c25sr;
extern UPD77C25DR upd77c25dr;

View File

@@ -7,14 +7,16 @@ void CPUDebugger::op_step() {
usage[regs.pc] |= UsageExec | (regs.p.m << 1) | (regs.p.x << 0);
opcode_pc = regs.pc;
opcode_edge = true;
if(debugger.step_cpu) {
debugger.break_event = Debugger::BreakEvent::CPUStep;
scheduler.exit(Scheduler::ExitReason::DebuggerEvent);
} else {
debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00);
}
if(step_event) step_event();
opcode_edge = false;
CPU::op_step();
synchronize_smp();
}
@@ -36,6 +38,7 @@ void CPUDebugger::op_write(uint32 addr, uint8 data) {
CPUDebugger::CPUDebugger() {
usage = new uint8[1 << 24]();
opcode_pc = 0x8000;
opcode_edge = false;
}
CPUDebugger::~CPUDebugger() {
@@ -53,11 +56,11 @@ bool CPUDebugger::property(unsigned id, string &name, string &value) {
}
//internal
item("S-CPU MDR", string("0x", strhex<2>(regs.mdr)));
item("S-CPU MDR", string("0x", hex<2>(regs.mdr)));
//$2181-2183
item("$2181-$2183", "");
item("WRAM Address", string("0x", strhex<6>(status.wram_addr)));
item("WRAM Address", string("0x", hex<6>(status.wram_addr)));
//$4016
item("$4016", "");
@@ -72,45 +75,45 @@ bool CPUDebugger::property(unsigned id, string &name, string &value) {
//$4201
item("$4201", "");
item("PIO", string("0x", strhex<2>(status.pio)));
item("PIO", string("0x", hex<2>(status.pio)));
//$4202
item("$4202", "");
item("Multiplicand", string("0x", strhex<2>(status.wrmpya)));
item("Multiplicand", string("0x", hex<2>(status.wrmpya)));
//$4203
item("$4203", "");
item("Multiplier", string("0x", strhex<2>(status.wrmpyb)));
item("Multiplier", string("0x", hex<2>(status.wrmpyb)));
//$4204-$4205
item("$4204-$4205", "");
item("Dividend", string("0x", strhex<4>(status.wrdiva)));
item("Dividend", string("0x", hex<4>(status.wrdiva)));
//$4206
item("$4206", "");
item("Divisor", string("0x", strhex<2>(status.wrdivb)));
item("Divisor", string("0x", hex<2>(status.wrdivb)));
//$4207-$4208
item("$4207-$4208", "");
item("H-Time", string("0x", strhex<4>(status.hirq_pos)));
item("H-Time", string("0x", hex<4>(status.hirq_pos)));
//$4209-$420a
item("$4209-$420a", "");
item("V-Time", string("0x", strhex<4>(status.virq_pos)));
item("V-Time", string("0x", hex<4>(status.virq_pos)));
//$420b
unsigned dma_enable = 0;
for(unsigned n = 0; n < 8; n++) dma_enable |= channel[n].dma_enabled << n;
item("$420b", "");
item("DMA Enable", string("0x", strhex<2>(dma_enable)));
item("DMA Enable", string("0x", hex<2>(dma_enable)));
//$420c
unsigned hdma_enable = 0;
for(unsigned n = 0; n < 8; n++) hdma_enable |= channel[n].hdma_enabled << n;
item("$420c", "");
item("HDMA Enable", string("0x", strhex<2>(hdma_enable)));
item("HDMA Enable", string("0x", hex<2>(hdma_enable)));
//$420d
item("$420d", "");
@@ -127,25 +130,25 @@ bool CPUDebugger::property(unsigned id, string &name, string &value) {
item("Transfer Mode", (unsigned)channel[i].transfer_mode);
//$43x1
item("B-Bus Address", string("0x", strhex<4>(channel[i].dest_addr)));
item("B-Bus Address", string("0x", hex<4>(channel[i].dest_addr)));
//$43x2-$43x3
item("A-Bus Address", string("0x", strhex<4>(channel[i].source_addr)));
item("A-Bus Address", string("0x", hex<4>(channel[i].source_addr)));
//$43x4
item("A-Bus Bank", string("0x", strhex<2>(channel[i].source_bank)));
item("A-Bus Bank", string("0x", hex<2>(channel[i].source_bank)));
//$43x5-$43x6
item("Transfer Size / Indirect Address", string("0x", strhex<4>(channel[i].transfer_size)));
item("Transfer Size / Indirect Address", string("0x", hex<4>(channel[i].transfer_size)));
//$43x7
item("Indirect Bank", string("0x", strhex<2>(channel[i].indirect_bank)));
item("Indirect Bank", string("0x", hex<2>(channel[i].indirect_bank)));
//$43x8-$43x9
item("Table Address", string("0x", strhex<4>(channel[i].hdma_addr)));
item("Table Address", string("0x", hex<4>(channel[i].hdma_addr)));
//$43xa
item("Line Counter", string("0x", strhex<2>(channel[i].line_counter)));
item("Line Counter", string("0x", hex<2>(channel[i].line_counter)));
}
#undef item

View File

@@ -12,7 +12,8 @@ public:
UsageFlagX = 0x01,
};
uint8 *usage;
uint32 opcode_pc; //points to the current opcode, used to backtrace on read/write breakpoints
uint24 opcode_pc; //points to the current opcode, used to backtrace on read/write breakpoints
bool opcode_edge; //true right before an opcode execues, used to skip over opcodes
void op_step();
uint8 op_read(uint32 addr);

View File

@@ -36,6 +36,11 @@ uint8 Debugger::read(Debugger::MemorySource source, unsigned addr) {
return bus.read(addr & 0xffffff);
} break;
case MemorySource::APUBus: {
if((addr & 0xffc0) == 0xffc0) return smp.iplrom[addr & 0x3f];
return memory::apuram.read(addr & 0xffff);
} break;
case MemorySource::APURAM: {
return memory::apuram.read(addr & 0xffff);
} break;

View File

@@ -22,7 +22,7 @@ public:
bool step_cpu;
bool step_smp;
enum class MemorySource : unsigned { CPUBus, APURAM, VRAM, OAM, CGRAM };
enum class MemorySource : unsigned { CPUBus, APUBus, APURAM, VRAM, OAM, CGRAM };
uint8 read(MemorySource, unsigned addr);
void write(MemorySource, unsigned addr, uint8 data);

View File

@@ -14,30 +14,30 @@ bool DSPDebugger::property(unsigned id, string &name, string &value) {
item("Main Volume - Right", (unsigned)state.regs[0x1c]);
item("Echo Volume - Left", (unsigned)state.regs[0x2c]);
item("Echo Volume - Right", (unsigned)state.regs[0x3c]);
item("Key On", string("0x", strhex<2>(state.regs[0x4c])));
item("Key Off", string("0x", strhex<2>(state.regs[0x5c])));
item("Key On", string("0x", hex<2>(state.regs[0x4c])));
item("Key Off", string("0x", hex<2>(state.regs[0x5c])));
item("Flag - Reset", (bool)(state.regs[0x6c] & 0x80));
item("Flag - Mute", (bool)(state.regs[0x6c] & 0x40));
item("Flag - Echo Disable", (bool)(state.regs[0x6c] & 0x20));
item("Flag - Noise Clock", (unsigned)state.regs[0x6c] & 0x1f);
item("Source End Block", (unsigned)state.regs[0x7c]);
item("Echo Feedback", (unsigned)state.regs[0x0d]);
item("Pitch Modulation Enable", string("0x", strhex<2>(state.regs[0x2d])));
item("Noise Enable", string("0x", strhex<2>(state.regs[0x3d])));
item("Echo Enable", string("0x", strhex<2>(state.regs[0x4d])));
item("Pitch Modulation Enable", string("0x", hex<2>(state.regs[0x2d])));
item("Noise Enable", string("0x", hex<2>(state.regs[0x3d])));
item("Echo Enable", string("0x", hex<2>(state.regs[0x4d])));
item("Source Directory", (unsigned)state.regs[0x5d]);
item("Echo Start Address", (unsigned)state.regs[0x6d]);
item("Echo Directory", (unsigned)state.regs[0x7d]);
for(unsigned i = 0; i < 8; i++) {
item(string("Coefficient ", i), string("0x", strhex<2>(state.regs[(i << 4) + 0x0f])));
item(string("Coefficient ", i), string("0x", hex<2>(state.regs[(i << 4) + 0x0f])));
}
for(unsigned i = 0; i < 8; i++) {
item(string("Voice ", i), "");
item("Volume - Left", (unsigned)state.regs[(i << 4) + 0x00]);
item("Volume - Right", (unsigned)state.regs[(i << 4) + 0x01]);
item("Pitch Height", string("0x", strhex<4>(state.regs[(i << 4) + 0x02] + (state.regs[(i << 4) + 0x03] << 8))));
item("Pitch Height", string("0x", hex<4>(state.regs[(i << 4) + 0x02] + (state.regs[(i << 4) + 0x03] << 8))));
item("Source Number", (unsigned)state.regs[(i << 4) + 0x04]);
item("ADSR1", (unsigned)state.regs[(i << 4) + 0x05]);
item("ADSR2", (unsigned)state.regs[(i << 4) + 0x06]);

View File

@@ -4,4 +4,6 @@ public:
virtual void audio_sample(uint16_t l_sample, uint16_t r_sample) {}
virtual void input_poll() {}
virtual int16_t input_poll(bool port, Input::Device device, unsigned index, unsigned id) { return 0; }
virtual void message(const string &text) { print(text, "\n"); }
};

View File

@@ -1,7 +1,7 @@
#include "libsnes.hpp"
#include <snes.hpp>
#include <nall/snes/info.hpp>
#include <nall/snes/cartridge.hpp>
using namespace nall;
struct Interface : public SNES::Interface {
@@ -120,7 +120,7 @@ bool snes_load_cartridge_normal(
) {
snes_cheat_reset();
if(rom_data) SNES::memory::cartrom.copy(rom_data, rom_size);
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : snes_information(rom_data, rom_size).xml_memory_map;
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SNESCartridge(rom_data, rom_size).xmlMemoryMap;
SNES::cartridge.load(SNES::Cartridge::Mode::Normal, { xmlrom });
SNES::system.power();
return true;
@@ -132,9 +132,9 @@ bool snes_load_cartridge_bsx_slotted(
) {
snes_cheat_reset();
if(rom_data) SNES::memory::cartrom.copy(rom_data, rom_size);
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : snes_information(rom_data, rom_size).xml_memory_map;
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SNESCartridge(rom_data, rom_size).xmlMemoryMap;
if(bsx_data) SNES::memory::bsxflash.copy(bsx_data, bsx_size);
string xmlbsx = (bsx_xml && *bsx_xml) ? string(bsx_xml) : snes_information(bsx_data, bsx_size).xml_memory_map;
string xmlbsx = (bsx_xml && *bsx_xml) ? string(bsx_xml) : SNESCartridge(bsx_data, bsx_size).xmlMemoryMap;
SNES::cartridge.load(SNES::Cartridge::Mode::BsxSlotted, { xmlrom, xmlbsx });
SNES::system.power();
return true;
@@ -146,9 +146,9 @@ bool snes_load_cartridge_bsx(
) {
snes_cheat_reset();
if(rom_data) SNES::memory::cartrom.copy(rom_data, rom_size);
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : snes_information(rom_data, rom_size).xml_memory_map;
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SNESCartridge(rom_data, rom_size).xmlMemoryMap;
if(bsx_data) SNES::memory::bsxflash.copy(bsx_data, bsx_size);
string xmlbsx = (bsx_xml && *bsx_xml) ? string(bsx_xml) : snes_information(bsx_data, bsx_size).xml_memory_map;
string xmlbsx = (bsx_xml && *bsx_xml) ? string(bsx_xml) : SNESCartridge(bsx_data, bsx_size).xmlMemoryMap;
SNES::cartridge.load(SNES::Cartridge::Mode::Bsx, { xmlrom, xmlbsx });
SNES::system.power();
return true;
@@ -161,11 +161,11 @@ bool snes_load_cartridge_sufami_turbo(
) {
snes_cheat_reset();
if(rom_data) SNES::memory::cartrom.copy(rom_data, rom_size);
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : snes_information(rom_data, rom_size).xml_memory_map;
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SNESCartridge(rom_data, rom_size).xmlMemoryMap;
if(sta_data) SNES::memory::stArom.copy(sta_data, sta_size);
string xmlsta = (sta_xml && *sta_xml) ? string(sta_xml) : snes_information(sta_data, sta_size).xml_memory_map;
string xmlsta = (sta_xml && *sta_xml) ? string(sta_xml) : SNESCartridge(sta_data, sta_size).xmlMemoryMap;
if(stb_data) SNES::memory::stBrom.copy(stb_data, stb_size);
string xmlstb = (stb_xml && *stb_xml) ? string(stb_xml) : snes_information(stb_data, stb_size).xml_memory_map;
string xmlstb = (stb_xml && *stb_xml) ? string(stb_xml) : SNESCartridge(stb_data, stb_size).xmlMemoryMap;
SNES::cartridge.load(SNES::Cartridge::Mode::SufamiTurbo, { xmlrom, xmlsta, xmlstb });
SNES::system.power();
return true;
@@ -177,9 +177,9 @@ bool snes_load_cartridge_super_game_boy(
) {
snes_cheat_reset();
if(rom_data) SNES::memory::cartrom.copy(rom_data, rom_size);
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : snes_information(rom_data, rom_size).xml_memory_map;
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SNESCartridge(rom_data, rom_size).xmlMemoryMap;
if(dmg_data) SNES::memory::gbrom.copy(dmg_data, dmg_size);
string xmldmg = (dmg_xml && *dmg_xml) ? string(dmg_xml) : snes_information(dmg_data, dmg_size).xml_memory_map;
string xmldmg = (dmg_xml && *dmg_xml) ? string(dmg_xml) : SNESCartridge(dmg_data, dmg_size).xmlMemoryMap;
SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, { xmlrom, xmldmg });
SNES::system.power();
return true;

View File

@@ -6,14 +6,16 @@ void SMPDebugger::op_step() {
usage[regs.pc] |= UsageExec;
opcode_pc = regs.pc;
opcode_edge = true;
if(debugger.step_smp) {
debugger.break_event = Debugger::BreakEvent::SMPStep;
scheduler.exit(Scheduler::ExitReason::DebuggerEvent);
} else {
debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00);
}
if(step_event) step_event();
opcode_edge = false;
SMP::op_step();
synchronize_cpu();
}
@@ -35,6 +37,7 @@ void SMPDebugger::op_write(uint16 addr, uint8 data) {
SMPDebugger::SMPDebugger() {
usage = new uint8[1 << 16]();
opcode_pc = 0xffc0;
opcode_edge = false;
}
SMPDebugger::~SMPDebugger() {
@@ -65,7 +68,7 @@ bool SMPDebugger::property(unsigned id, string &name, string &value) {
//$00f2
item("$00f2", "");
item("DSP Address", string("0x", strhex<2>(status.dsp_addr)));
item("DSP Address", string("0x", hex<2>(status.dsp_addr)));
#undef item
return false;

View File

@@ -11,6 +11,7 @@ public:
};
uint8 *usage;
uint16 opcode_pc;
bool opcode_edge;
void op_step();
uint8 op_read(uint16 addr);

View File

@@ -16,12 +16,12 @@ public:
SMP();
~SMP();
static const uint8 iplrom[64];
private:
#include "memory/memory.hpp"
#include "timing/timing.hpp"
static const uint8 iplrom[64];
struct {
//timing
unsigned clock_counter;

View File

@@ -1,8 +1,8 @@
namespace SNES {
namespace Info {
static const char Name[] = "bsnes";
static const char Version[] = "072";
static const unsigned SerializerVersion = 14;
static const char Version[] = "073";
static const unsigned SerializerVersion = 15;
}
}
@@ -39,21 +39,51 @@ using namespace nall;
#endif
namespace SNES {
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef uint8_t uint8;
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef uint_t<2> uint2;
typedef uint_t<3> uint3;
typedef uint_t<9> uint9;
typedef uint_t< 1> uint1;
typedef uint_t< 2> uint2;
typedef uint_t< 3> uint3;
typedef uint_t< 4> uint4;
typedef uint_t< 5> uint5;
typedef uint_t< 6> uint6;
typedef uint_t< 7> uint7;
typedef uint_t< 9> uint9;
typedef uint_t<10> uint10;
typedef uint_t<11> uint11;
typedef uint_t<12> uint12;
typedef uint_t<13> uint13;
typedef uint_t<14> uint14;
typedef uint_t<15> uint15;
typedef uint_t<17> uint17;
typedef uint_t<18> uint18;
typedef uint_t<19> uint19;
typedef uint_t<20> uint20;
typedef uint_t<21> uint21;
typedef uint_t<22> uint22;
typedef uint_t<23> uint23;
typedef uint_t<24> uint24;
typedef uint_t<25> uint25;
typedef uint_t<26> uint26;
typedef uint_t<27> uint27;
typedef uint_t<28> uint28;
typedef uint_t<29> uint29;
typedef uint_t<30> uint30;
typedef uint_t<31> uint31;
typedef uint_t<40> uint40;
typedef uint_t<48> uint48;
typedef uint_t<56> uint56;
struct Processor {
cothread_t thread;

View File

@@ -60,12 +60,11 @@ void System::serialize_all(serializer &s) {
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) supergameboy.serialize(s);
if(cartridge.has_superfx()) superfx.serialize(s);
if(cartridge.has_sa1()) sa1.serialize(s);
if(cartridge.has_upd77c25()) upd77c25.serialize(s);
if(cartridge.has_srtc()) srtc.serialize(s);
if(cartridge.has_sdd1()) sdd1.serialize(s);
if(cartridge.has_spc7110()) spc7110.serialize(s);
if(cartridge.has_cx4()) cx4.serialize(s);
if(cartridge.has_dsp1()) dsp1.serialize(s);
if(cartridge.has_dsp2()) dsp2.serialize(s);
if(cartridge.has_obc1()) obc1.serialize(s);
if(cartridge.has_st0010()) st0010.serialize(s);
if(cartridge.has_msu1()) msu1.serialize(s);

View File

@@ -71,6 +71,7 @@ void System::init(Interface *interface_) {
supergameboy.init();
superfx.init();
sa1.init();
upd77c25.init();
bsxbase.init();
bsxcart.init();
bsxflash.init();
@@ -78,10 +79,6 @@ void System::init(Interface *interface_) {
sdd1.init();
spc7110.init();
cx4.init();
dsp1.init();
dsp2.init();
dsp3.init();
dsp4.init();
obc1.init();
st0010.init();
st0011.init();
@@ -126,14 +123,11 @@ void System::power() {
if(cartridge.has_superfx()) superfx.enable();
if(cartridge.has_sa1()) sa1.enable();
if(cartridge.has_upd77c25()) upd77c25.enable();
if(cartridge.has_srtc()) srtc.enable();
if(cartridge.has_sdd1()) sdd1.enable();
if(cartridge.has_spc7110()) spc7110.enable();
if(cartridge.has_cx4()) cx4.enable();
if(cartridge.has_dsp1()) dsp1.enable();
if(cartridge.has_dsp2()) dsp2.enable();
if(cartridge.has_dsp3()) dsp3.enable();
if(cartridge.has_dsp4()) dsp4.enable();
if(cartridge.has_obc1()) obc1.enable();
if(cartridge.has_st0010()) st0010.enable();
if(cartridge.has_st0011()) st0011.enable();
@@ -153,14 +147,11 @@ void System::power() {
if(cartridge.has_superfx()) superfx.power();
if(cartridge.has_sa1()) sa1.power();
if(cartridge.has_upd77c25()) upd77c25.power();
if(cartridge.has_srtc()) srtc.power();
if(cartridge.has_sdd1()) sdd1.power();
if(cartridge.has_spc7110()) spc7110.power();
if(cartridge.has_cx4()) cx4.power();
if(cartridge.has_dsp1()) dsp1.power();
if(cartridge.has_dsp2()) dsp2.power();
if(cartridge.has_dsp3()) dsp3.power();
if(cartridge.has_dsp4()) dsp4.power();
if(cartridge.has_obc1()) obc1.power();
if(cartridge.has_st0010()) st0010.power();
if(cartridge.has_st0011()) st0011.power();
@@ -171,6 +162,7 @@ void System::power() {
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&supergameboy);
if(cartridge.has_superfx()) cpu.coprocessors.append(&superfx);
if(cartridge.has_sa1()) cpu.coprocessors.append(&sa1);
if(cartridge.has_upd77c25()) cpu.coprocessors.append(&upd77c25);
if(cartridge.has_msu1()) cpu.coprocessors.append(&msu1);
if(cartridge.has_serial()) cpu.coprocessors.append(&serial);
@@ -194,14 +186,11 @@ void System::reset() {
if(cartridge.has_superfx()) superfx.reset();
if(cartridge.has_sa1()) sa1.reset();
if(cartridge.has_upd77c25()) upd77c25.reset();
if(cartridge.has_srtc()) srtc.reset();
if(cartridge.has_sdd1()) sdd1.reset();
if(cartridge.has_spc7110()) spc7110.reset();
if(cartridge.has_cx4()) cx4.reset();
if(cartridge.has_dsp1()) dsp1.reset();
if(cartridge.has_dsp2()) dsp2.reset();
if(cartridge.has_dsp3()) dsp3.reset();
if(cartridge.has_dsp4()) dsp4.reset();
if(cartridge.has_obc1()) obc1.reset();
if(cartridge.has_st0010()) st0010.reset();
if(cartridge.has_st0011()) st0011.reset();
@@ -212,6 +201,7 @@ void System::reset() {
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&supergameboy);
if(cartridge.has_superfx()) cpu.coprocessors.append(&superfx);
if(cartridge.has_sa1()) cpu.coprocessors.append(&sa1);
if(cartridge.has_upd77c25()) cpu.coprocessors.append(&upd77c25);
if(cartridge.has_msu1()) cpu.coprocessors.append(&msu1);
if(cartridge.has_serial()) cpu.coprocessors.append(&serial);

View File

@@ -1,4 +1,4 @@
ui_objects := ui-main ui-general ui-settings ui-tools ui-input ui-utility ui-cartridge
ui_objects := ui-main ui-general ui-settings ui-tools ui-input ui-utility ui-cartridge ui-debugger
ui_objects += ruby phoenix
ui_objects += $(if $(call streq,$(platform),win),resource)
@@ -64,6 +64,7 @@ obj/ui-settings.o: $(ui)/settings/settings.cpp $(call rwildcard,$(ui)/*.hpp) $(c
obj/ui-input.o: $(ui)/input/input.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/input/*); $(phoenix_compile)
obj/ui-utility.o: $(ui)/utility/utility.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/utility/*); $(phoenix_compile)
obj/ui-cartridge.o: $(ui)/cartridge/cartridge.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/cartridge/*); $(phoenix_compile)
obj/ui-debugger.o: $(ui)/debugger/debugger.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/debugger/*); $(phoenix_compile)
obj/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/*)
$(call compile,$(rubydef) $(rubyflags))

View File

@@ -6,7 +6,7 @@
#include <nall/filemap.hpp>
#include <nall/input.hpp>
#include <nall/ups.hpp>
#include <nall/snes/info.hpp>
#include <nall/snes/cartridge.hpp>
using namespace nall;
#include <ruby/ruby.hpp>
@@ -29,15 +29,21 @@ struct TopLevelWindow : Window {
#include "utility/utility.hpp"
#include "cartridge/cartridge.hpp"
#if defined(DEBUGGER)
#include "debugger/debugger.hpp"
#endif
struct Application {
Font proportionalFont;
Font proportionalFontBold;
Font monospaceFont;
bool pause;
bool quit;
void main(int argc, char **argv);
void addWindow(TopLevelWindow *window, const string &name, const string &position);
Application();
private:
array<TopLevelWindow*> windows;

View File

@@ -4,7 +4,7 @@ Cartridge cartridge;
bool Cartridge::loadNormal(const char *basename) {
unload();
if(loadCartridge(SNES::memory::cartrom, baseXML, basename) == false) return false;
baseName = nall::basename(basename);
SNES::cartridge.basename = baseName = nall::basename(basename);
SNES::cartridge.load(SNES::Cartridge::Mode::Normal, { baseXML });
loadMemory(SNES::memory::cartram, baseName, ".srm");
loadMemory(SNES::memory::cartrtc, baseName, ".rtc");
@@ -16,7 +16,7 @@ bool Cartridge::loadBsxSlotted(const char *basename, const char *slotname) {
unload();
if(loadCartridge(SNES::memory::cartrom, baseXML, basename) == false) return false;
loadCartridge(SNES::memory::bsxflash, slotAXML, slotname);
baseName = nall::basename(basename);
SNES::cartridge.basename = baseName = nall::basename(basename);
slotAName = nall::basename(slotname);
SNES::cartridge.load(SNES::Cartridge::Mode::BsxSlotted, { baseXML, slotAXML });
loadMemory(SNES::memory::cartram, baseName, ".srm");
@@ -29,7 +29,7 @@ bool Cartridge::loadBsx(const char *basename, const char *slotname) {
unload();
if(loadCartridge(SNES::memory::cartrom, baseXML, basename) == false) return false;
loadCartridge(SNES::memory::bsxflash, slotAXML, slotname);
baseName = nall::basename(basename);
SNES::cartridge.basename = baseName = nall::basename(basename);
slotAName = nall::basename(slotname);
SNES::cartridge.load(SNES::Cartridge::Mode::Bsx, { baseXML, slotAXML });
loadMemory(SNES::memory::bsxram, baseName, ".srm");
@@ -43,7 +43,7 @@ bool Cartridge::loadSufamiTurbo(const char *basename, const char *slotAname, con
if(loadCartridge(SNES::memory::cartrom, baseXML, basename) == false) return false;
loadCartridge(SNES::memory::stArom, slotAXML, slotAname);
loadCartridge(SNES::memory::stBrom, slotBXML, slotBname);
baseName = nall::basename(basename);
SNES::cartridge.basename = baseName = nall::basename(basename);
slotAName = nall::basename(slotAname);
slotBName = nall::basename(slotBname);
SNES::cartridge.load(SNES::Cartridge::Mode::SufamiTurbo, { baseXML, slotAXML, slotBXML });
@@ -57,7 +57,7 @@ bool Cartridge::loadSuperGameBoy(const char *basename, const char *slotname) {
unload();
if(loadCartridge(SNES::memory::cartrom, baseXML, basename) == false) return false;
loadCartridge(SNES::memory::gbrom, slotAXML, slotname);
baseName = nall::basename(basename);
SNES::cartridge.basename = baseName = nall::basename(basename);
slotAName = nall::basename(slotname);
SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, { baseXML, slotAXML });
loadMemory(SNES::memory::gbram, slotAName, ".sav");
@@ -107,7 +107,7 @@ bool Cartridge::loadCartridge(SNES::MappedRAM &memory, string &XML, const char *
}
}
if(XML == "") XML = snes_information(data, size).xml_memory_map;
if(XML == "") XML = SNESCartridge(data, size).xmlMemoryMap;
memory.copy(data, size);
delete[] data;
return true;

View File

@@ -18,6 +18,7 @@ void Configuration::create() {
attach(video.driver = "", "video.driver");
attach(video.synchronize = false, "video.synchronize");
attach(video.smooth = true, "video.smooth");
attach(video.filter = "", "video.filter");
attach(video.shader = "", "video.shader");
attach(video.region = 0, "video.region");
attach(video.scale = 2, "video.scale");

View File

@@ -12,6 +12,7 @@ struct Configuration : public configuration {
string driver;
bool synchronize;
bool smooth;
string filter;
string shader;
bool region;
unsigned scale;

View File

@@ -0,0 +1,84 @@
Console console;
void Console::create() {
Window::create(0, 0, 256, 256, "Console");
application.addWindow(this, "Debugger.Console", "192,192");
unsigned x = 5, y = 5;
output.create(*this, x, y, 580, 328); x += 580 + 5;
output.setFont(application.monospaceFont);
output.setEditable(false);
traceToConsole.create(*this, x, y, 120, Style::CheckBoxHeight, "Trace to console"); y += Style::CheckBoxHeight;
traceToConsole.setChecked(true);
traceToFile.create(*this, x, y, 120, Style::CheckBoxHeight, "Trace to file"); y += Style::CheckBoxHeight;
traceCPU.create(*this, x, y, 120, Style::CheckBoxHeight, "Trace S-CPU"); y += Style::CheckBoxHeight;
traceCPU.setChecked(true);
traceSMP.create(*this, x, y, 120, Style::CheckBoxHeight, "Trace S-SMP"); y += Style::CheckBoxHeight;
clearConsole.create(*this, x, 338 - Style::ButtonHeight - 5, 120, Style::ButtonHeight, "Clear console");
setGeometry(0, 0, 710, 338);
onClose = []() {
debugger.showConsole.setChecked(false);
return true;
};
traceToFile.onTick = []() { console.tracerEnable(console.traceToFile.checked()); };
clearConsole.onTick = []() {
console.buffer = "";
console.output.setText(console.buffer);
};
}
void Console::write(const string &text) {
if(traceToConsole.checked()) {
if(buffer != "") buffer.append("\n");
buffer.append(text);
output.setText(buffer);
output.setCursorPosition(~0);
}
if(traceToFile.checked() && logfile.open()) {
logfile.print(string(text, "\n"));
}
}
void Console::tracerEnable(bool state) {
if(state == true) {
string filename = { cartridge.baseName, ".log" };
logfile.open(filename, file::mode::write);
} else {
logfile.close();
}
}
void Console::eventBreakpoint() {
if(traceToConsole.checked() == false) return;
unsigned n = SNES::debugger.breakpoint_hit;
write({ "Breakpoint ", n + 1, " hit." });
if(SNES::debugger.breakpoint[n].source == SNES::Debugger::Breakpoint::Source::CPUBus) {
eventTraceCPU();
} else if(SNES::debugger.breakpoint[n].source == SNES::Debugger::Breakpoint::Source::APURAM) {
eventTraceSMP();
}
}
void Console::eventTraceCPU() {
if(traceCPU.checked() == false) return;
char text[256];
SNES::cpu.disassemble_opcode(text, SNES::cpu.regs.pc);
write(text);
}
void Console::eventTraceSMP() {
if(traceSMP.checked() == false) return;
char text[256];
SNES::smp.disassemble_opcode(text, SNES::smp.regs.pc);
write(text);
}

View File

@@ -0,0 +1,21 @@
struct Console : TopLevelWindow {
EditBox output;
CheckBox traceToConsole;
CheckBox traceToFile;
CheckBox traceCPU;
CheckBox traceSMP;
Button clearConsole;
string buffer;
file logfile;
void create();
void write(const string &text);
void tracerEnable(bool state);
void eventBreakpoint();
void eventTraceCPU();
void eventTraceSMP();
};
extern Console console;

View File

@@ -0,0 +1,107 @@
CPUDebugger cpuDebugger;
void CPUDebugger::create() {
Window::create(0, 0, 256, 256, "CPU Debugger");
application.addWindow(this, "Debugger.CPUdebugger", "192,192");
unsigned x = 5, y = 5;
output.create(*this, x, y, 400, 200); x += 400 + 5;
output.setFont(application.monospaceFont);
output.setEditable(false);
stepInto.create(*this, x, y, 80, Style::ButtonHeight, "Step Into"); y += Style::ButtonHeight;
stepOver.create(*this, x, y, 80, Style::ButtonHeight, "Step Over"); y += Style::ButtonHeight;
proceed.create(*this, x, y, 80, Style::ButtonHeight, "Proceed"); y += Style::ButtonHeight;
proceed.setEnabled(false);
setGeometry(0, 0, 490, 205);
onClose = []() {
debugger.showCPUDebugger.setChecked(false);
return true;
};
stepInto.onTick = []() {
debugger.debugMode = Debugger::DebugMode::StepIntoCPU;
};
stepOver.onTick = { &CPUDebugger::eventStepOver, this };
}
void CPUDebugger::synchronize() {
stepInto.setEnabled(SNES::cartridge.loaded() && debugger.enableDebugger.checked());
stepOver.setEnabled(stepInto.enabled() && SNES::cpu.opcode_edge);
}
void CPUDebugger::refreshDisassembly() {
unsigned addr = SNES::cpu.regs.pc;
uint8_t *usage = SNES::cpu.usage;
signed offset[15];
foreach(n, offset) n = -1;
offset[7] = addr;
//reverse disassembly
for(signed n = 6; n >= 0; n--) {
signed base = offset[n + 1];
if(base == -1) break;
for(unsigned r = 1; r <= 4; r++) {
if(usage[(base - r) & 0xffffff] & 0x20) {
offset[n] = base - r;
break;
}
}
}
//forward disassembly
for(signed n = 8; n <= 14; n++) {
signed base = offset[n - 1];
if(base == -1) break;
for(unsigned r = 1; r <= 4; r++) {
if(usage[(base + r) & 0xffffff] & 0x20) {
offset[n] = base + r;
break;
}
}
}
string buffer;
for(unsigned n = 0; n < 15; n++) {
buffer.append(n == 7 ? "> " : " ");
if(offset[n] == -1) {
buffer.append("...\n");
} else {
unsigned addr = offset[n];
buffer.append(hex<6>(addr));
buffer.append(" ");
string text = SNESCPU::disassemble(
addr, usage[addr] & 2, usage[addr] & 1,
read(addr + 0), read(addr + 1), read(addr + 2), read(addr + 3)
);
buffer.append(text);
buffer.append("\n");
}
}
buffer.rtrim<1>("\n");
output.setText(buffer);
}
void CPUDebugger::eventStepInto() {
refreshDisassembly();
}
void CPUDebugger::eventStepOver() {
uint8_t opcode = read(SNES::cpu.regs.pc);
unsigned length = SNESCPU::getOpcodeLength(SNES::cpu.regs.p.m, SNES::cpu.regs.p.x, opcode);
SNES::cpu.regs.pc += length;
refreshDisassembly();
console.eventTraceCPU();
}
uint8_t CPUDebugger::read(unsigned addr) {
return SNES::debugger.read(SNES::Debugger::MemorySource::CPUBus, addr);
}

View File

@@ -0,0 +1,16 @@
struct CPUDebugger : TopLevelWindow {
EditBox output;
Button stepInto;
Button stepOver;
Button proceed;
void create();
void synchronize();
void refreshDisassembly();
void eventStepInto();
void eventStepOver();
uint8_t read(unsigned addr);
};
extern CPUDebugger cpuDebugger;

View File

@@ -0,0 +1,138 @@
#include "../base.hpp"
#if defined(DEBUGGER)
#include <nall/snes/cpu.hpp>
#include <nall/snes/smp.hpp>
#include "console.cpp"
#include "cpu/debugger.cpp"
#include "smp/debugger.cpp"
#include "tools/breakpoint-editor.cpp"
#include "tools/memory-editor.cpp"
Debugger debugger;
void Debugger::create() {
console.create();
cpuDebugger.create();
smpDebugger.create();
breakpointEditor.create();
memoryEditor.create();
Window::create(0, 0, 256, 256, "Debugger");
application.addWindow(this, "Debugger", "160,160");
unsigned x = 5, y = 5;
enableDebugger.create(*this, x, y, 240, Style::CheckBoxHeight, "Enable debugger"); y += Style::CheckBoxHeight;
showConsole.create(*this, x, y, 240, Style::CheckBoxHeight, "Console"); y += Style::CheckBoxHeight;
showCPUDebugger.create(*this, x, y, 240, Style::CheckBoxHeight, "CPU debugger"); y += Style::CheckBoxHeight;
showSMPDebugger.create(*this, x, y, 240, Style::CheckBoxHeight, "SMP debugger"); y += Style::CheckBoxHeight;
showBreakpointEditor.create(*this, x, y, 240, Style::CheckBoxHeight, "Breakpoint editor"); y += Style::CheckBoxHeight;
showMemoryEditor.create(*this, x, y, 240, Style::CheckBoxHeight, "Memory editor"); y += Style::CheckBoxHeight;
//windows shown by default
showConsole.setChecked();
showCPUDebugger.setChecked();
showSMPDebugger.setChecked();
showBreakpointEditor.setChecked();
setGeometry(0, 0, 250, y);
enableDebugger.onTick = []() {
debugger.enable(debugger.enableDebugger.checked());
};
showConsole.onTick = []() {
console.setVisible(debugger.showConsole.checked());
};
showCPUDebugger.onTick = []() {
cpuDebugger.setVisible(debugger.showCPUDebugger.checked());
};
showSMPDebugger.onTick = []() {
smpDebugger.setVisible(debugger.showSMPDebugger.checked());
};
showBreakpointEditor.onTick = []() {
breakpointEditor.setVisible(debugger.showBreakpointEditor.checked());
};
showMemoryEditor.onTick = []() {
memoryEditor.setVisible(debugger.showMemoryEditor.checked());
};
onClose = []() {
debugger.enable(false);
return true;
};
synchronize();
}
void Debugger::synchronize() {
cpuDebugger.synchronize();
smpDebugger.synchronize();
}
void Debugger::setVisible(bool visible) {
Window::setVisible(visible);
console.setVisible(showConsole.checked() & visible);
cpuDebugger.setVisible(showCPUDebugger.checked() & visible);
smpDebugger.setVisible(showSMPDebugger.checked() & visible);
breakpointEditor.setVisible(showBreakpointEditor.checked() & visible);
memoryEditor.setVisible(showMemoryEditor.checked() & visible);
}
void Debugger::enable(bool state) {
enableDebugger.setChecked(state);
SNES::debugger.step_cpu = state;
SNES::debugger.step_smp = state;
}
void Debugger::run() {
synchronize();
if(enableDebugger.checked() == false) {
SNES::system.run();
return;
}
if(debugMode == DebugMode::None) {
usleep(20 * 1000);
return;
}
SNES::system.run();
if(debugMode == DebugMode::WaitForBreakpoint) {
if(SNES::debugger.break_event == SNES::Debugger::BreakEvent::BreakpointHit) {
debugMode = DebugMode::None;
console.eventBreakpoint();
breakpointEditor.eventBreakpoint();
}
}
if(SNES::debugger.break_event == SNES::Debugger::BreakEvent::CPUStep) {
if(debugMode == DebugMode::StepIntoCPU) {
debugMode = DebugMode::None;
cpuDebugger.eventStepInto();
}
console.eventTraceCPU();
}
if(SNES::debugger.break_event == SNES::Debugger::BreakEvent::SMPStep) {
if(debugMode == DebugMode::StepIntoSMP) {
debugMode = DebugMode::None;
smpDebugger.eventStepInto();
}
console.eventTraceSMP();
}
SNES::debugger.break_event = SNES::Debugger::BreakEvent::None;
}
Debugger::Debugger() {
debugMode = DebugMode::None;
}
#endif

View File

@@ -0,0 +1,31 @@
#include "console.hpp"
#include "cpu/debugger.hpp"
#include "smp/debugger.hpp"
#include "tools/breakpoint-editor.hpp"
#include "tools/memory-editor.hpp"
struct Debugger : TopLevelWindow {
enum class DebugMode : unsigned {
None,
WaitForBreakpoint,
StepIntoCPU,
StepIntoSMP,
} debugMode;
CheckBox enableDebugger;
CheckBox showConsole;
CheckBox showCPUDebugger;
CheckBox showSMPDebugger;
CheckBox showBreakpointEditor;
CheckBox showMemoryEditor;
void create();
void synchronize();
void setVisible(bool visible = true);
void enable(bool state);
void run();
Debugger();
};
extern Debugger debugger;

View File

@@ -0,0 +1,106 @@
SMPDebugger smpDebugger;
void SMPDebugger::create() {
Window::create(0, 0, 256, 256, "SMP Debugger");
application.addWindow(this, "Debugger.SMPDebugger", "192,192");
unsigned x = 5, y = 5;
output.create(*this, x, y, 400, 200); x += 400 + 5;
output.setFont(application.monospaceFont);
output.setEditable(false);
stepInto.create(*this, x, y, 80, Style::ButtonHeight, "Step Into"); y += Style::ButtonHeight;
stepOver.create(*this, x, y, 80, Style::ButtonHeight, "Step Over"); y += Style::ButtonHeight;
proceed.create(*this, x, y, 80, Style::ButtonHeight, "Proceed"); y += Style::ButtonHeight;
proceed.setEnabled(false);
setGeometry(0, 0, 490, 205);
onClose = []() {
debugger.showSMPDebugger.setChecked(false);
return true;
};
stepInto.onTick = []() {
debugger.debugMode = Debugger::DebugMode::StepIntoSMP;
};
stepOver.onTick = { &SMPDebugger::eventStepOver, this };
}
void SMPDebugger::synchronize() {
stepInto.setEnabled(SNES::cartridge.loaded() && debugger.enableDebugger.checked());
stepOver.setEnabled(stepInto.enabled() && SNES::smp.opcode_edge);
}
void SMPDebugger::refreshDisassembly() {
uint16_t addr = SNES::smp.regs.pc;
uint8_t *usage = SNES::smp.usage;
signed offset[15];
foreach(n, offset) n = -1;
offset[7] = addr;
//reverse disassembly
for(signed n = 6; n >= 0; n--) {
signed base = offset[n + 1];
if(base == -1) break;
for(unsigned r = 1; r <= 3; r++) {
if(usage[(base - r) & 0xffff] & 0x20) {
offset[n] = base - r;
break;
}
}
}
//forward disassembly
for(signed n = 8; n <= 14; n++) {
signed base = offset[n - 1];
if(base == -1) break;
for(unsigned r = 1; r <= 3; r++) {
if(usage[(base + r) & 0xffff] & 0x20) {
offset[n] = base + r;
break;
}
}
}
string buffer;
for(unsigned n = 0; n < 15; n++) {
buffer.append(n == 7 ? "> " : " ");
if(offset[n] == -1) {
buffer.append("...\n");
} else {
uint16_t addr = offset[n];
buffer.append(hex<4>(addr));
buffer.append(" ");
string text = SNESSMP::disassemble(
addr, read(addr + 0), read(addr + 1), read(addr + 2)
);
buffer.append(text);
buffer.append("\n");
}
}
buffer.rtrim<1>("\n");
output.setText(buffer);
}
void SMPDebugger::eventStepInto() {
refreshDisassembly();
}
void SMPDebugger::eventStepOver() {
uint8_t opcode = read(SNES::smp.regs.pc);
unsigned length = SNESSMP::getOpcodeLength(opcode);
SNES::smp.regs.pc += length;
refreshDisassembly();
console.eventTraceSMP();
}
uint8_t SMPDebugger::read(uint16_t addr) {
return SNES::debugger.read(SNES::Debugger::MemorySource::APUBus, addr);
}

View File

@@ -0,0 +1,16 @@
struct SMPDebugger : TopLevelWindow {
EditBox output;
Button stepInto;
Button stepOver;
Button proceed;
void create();
void synchronize();
void refreshDisassembly();
void eventStepInto();
void eventStepOver();
uint8_t read(uint16_t addr);
};
extern SMPDebugger smpDebugger;

View File

@@ -0,0 +1,57 @@
BreakpointEditor breakpointEditor;
void BreakpointEditor::create() {
Window::create(0, 0, 256, 256, "Breakpoint Editor");
application.addWindow(this, "Debugger.BreakpointEditor", "192,192");
unsigned x = 5, y = 5;
runToBreakpoint.create(*this, x, y, 295, Style::CheckBoxHeight, "Run to breakpoint");
y += Style::CheckBoxHeight + 5;
for(unsigned n = 0; n < Breakpoints; n++) {
enableBox[n].create(*this, x, y, 35, Style::EditBoxHeight, { n + 1 });
addressBox[n].create(*this, x + 35, y, 60, Style::EditBoxHeight);
valueBox[n].create(*this, x + 100, y, 30, Style::EditBoxHeight);
typeBox[n].create(*this, x + 135, y, 80, Style::EditBoxHeight, "Exec\nRead\nWrite");
sourceBox[n].create(*this, x + 220, y, 80, Style::EditBoxHeight, "CPU\nAPU\nVRAM\nOAM\nCGRAM");
y += Style::EditBoxHeight + 5;
enableBox[n].onTick = [n]() { breakpointEditor.toggleBreakpoint(n); };
}
setGeometry(0, 0, 305, y);
runToBreakpoint.onTick = []() {
if(breakpointEditor.runToBreakpoint.checked()) {
debugger.debugMode = Debugger::DebugMode::WaitForBreakpoint;
} else {
debugger.debugMode = Debugger::DebugMode::None;
}
};
}
void BreakpointEditor::toggleBreakpoint(unsigned n) {
bool enabled = enableBox[n].checked();
if(enabled == false) {
SNES::debugger.breakpoint[n].enabled = false;
} else {
SNES::debugger.breakpoint[n].enabled = true;
SNES::debugger.breakpoint[n].addr = hex(addressBox[n].text());
SNES::debugger.breakpoint[n].data = hex(valueBox[n].text());
if(valueBox[n].text() == "") SNES::debugger.breakpoint[n].data = -1; //break on any value
SNES::debugger.breakpoint[n].mode = (SNES::Debugger::Breakpoint::Mode)typeBox[n].selection();
SNES::debugger.breakpoint[n].source = (SNES::Debugger::Breakpoint::Source)sourceBox[n].selection();
SNES::debugger.breakpoint[n].counter = 0;
}
//do not allow values to be edited while breakpoint is enabled
addressBox[n].setEnabled(!enabled);
valueBox[n].setEnabled(!enabled);
typeBox[n].setEnabled(!enabled);
sourceBox[n].setEnabled(!enabled);
}
void BreakpointEditor::eventBreakpoint() {
runToBreakpoint.setChecked(false);
}

View File

@@ -0,0 +1,15 @@
struct BreakpointEditor : TopLevelWindow {
enum : unsigned { Breakpoints = SNES::Debugger::Breakpoints };
CheckBox runToBreakpoint;
CheckBox enableBox[Breakpoints];
TextBox addressBox[Breakpoints];
TextBox valueBox[Breakpoints];
ComboBox typeBox[Breakpoints];
ComboBox sourceBox[Breakpoints];
void create();
void toggleBreakpoint(unsigned breakpoint);
void eventBreakpoint();
};
extern BreakpointEditor breakpointEditor;

View File

@@ -0,0 +1,78 @@
MemoryEditor memoryEditor;
void MemoryEditor::create() {
Window::create(0, 0, 256, 256, "Memory Editor");
application.addWindow(this, "Debugger.MemoryEditor", "192,192");
unsigned x = 5, y = 5;
editor.create(*this, x, y, 470, 210); x += 470 + 5;
editor.setFont(application.monospaceFont);
editor.setColumns(16);
editor.setRows(16);
sourceBox.create(*this, x, y, 80, Style::ComboBoxHeight); y += Style::ComboBoxHeight;
sourceBox.addItem("CPU");
sourceBox.addItem("APU");
sourceBox.addItem("VRAM");
sourceBox.addItem("OAM");
sourceBox.addItem("CGRAM");
gotoBox.create(*this, x, y, 80, Style::TextBoxHeight); y += Style::TextBoxHeight;
refreshButton.create(*this, x, y, 80, Style::ButtonHeight, "Refresh"); y += Style::ButtonHeight;
setGeometry(0, 0, 560, 220);
onClose = []() {
debugger.showMemoryEditor.setChecked(false);
return true;
};
editor.onRead = { &MemoryEditor::read, this };
editor.onWrite = { &MemoryEditor::write, this };
sourceBox.onChange = []() {
switch(memoryEditor.sourceBox.selection()) {
case 0: memoryEditor.setSource(SNES::Debugger::MemorySource::CPUBus); break;
case 1: memoryEditor.setSource(SNES::Debugger::MemorySource::APURAM); break;
case 2: memoryEditor.setSource(SNES::Debugger::MemorySource::VRAM); break;
case 3: memoryEditor.setSource(SNES::Debugger::MemorySource::OAM); break;
case 4: memoryEditor.setSource(SNES::Debugger::MemorySource::CGRAM); break;
}
};
gotoBox.onChange = []() {
unsigned addr = hex(memoryEditor.gotoBox.text());
memoryEditor.editor.setOffset(addr % memoryEditor.size);
memoryEditor.editor.update();
};
refreshButton.onTick = []() {
memoryEditor.editor.update();
};
setSource(SNES::Debugger::MemorySource::CPUBus);
}
void MemoryEditor::setSource(SNES::Debugger::MemorySource source_) {
switch(source = source_) {
case SNES::Debugger::MemorySource::CPUBus: size = 1 << 24; break;
case SNES::Debugger::MemorySource::APURAM: size = 1 << 16; break;
case SNES::Debugger::MemorySource::VRAM: size = 1 << 16; break;
case SNES::Debugger::MemorySource::OAM: size = 544; break;
case SNES::Debugger::MemorySource::CGRAM: size = 512; break;
}
editor.setSize(size);
editor.setOffset(0);
editor.update();
}
uint8_t MemoryEditor::read(unsigned addr) {
if(SNES::cartridge.loaded() == false) return 0x00;
return SNES::debugger.read(source, addr % size);
}
void MemoryEditor::write(unsigned addr, uint8_t data) {
if(SNES::cartridge.loaded() == false) return;
SNES::debugger.write(source, addr % size, data);
}

View File

@@ -0,0 +1,16 @@
struct MemoryEditor : TopLevelWindow {
HexEditor editor;
ComboBox sourceBox;
TextBox gotoBox;
Button refreshButton;
SNES::Debugger::MemorySource source;
unsigned size;
void create();
void setSource(SNES::Debugger::MemorySource source);
uint8_t read(unsigned addr);
void write(unsigned addr, uint8_t data);
};
extern MemoryEditor memoryEditor;

View File

@@ -58,6 +58,11 @@ void FileBrowser::fileOpen(FileBrowser::Mode requestedMode, function<void (strin
filters.append(".sgb");
break;
}
case Mode::Filter: {
setTitle("Load Video Filter");
filters.append(".filter");
break;
}
case Mode::Shader: {
setTitle("Load Pixel Shader");
filters.append(".shader");

View File

@@ -4,7 +4,7 @@ struct FileBrowser : TopLevelWindow {
Button upButton;
ListBox contentsBox;
enum class Mode : unsigned { Cartridge, Satellaview, SufamiTurbo, GameBoy, Shader } mode;
enum class Mode : unsigned { Cartridge, Satellaview, SufamiTurbo, GameBoy, Filter, Shader } mode;
void fileOpen(Mode mode, function<void (string)> callback);
void create();

View File

@@ -96,6 +96,10 @@ void MainWindow::create() {
toolsSeparator2.create(tools);
toolsCheatEditor.create(tools, "Cheat Editor ...");
toolsStateManager.create(tools, "State Manager ...");
#if defined(DEBUGGER)
toolsSeparator3.create(tools);
toolsDebugger.create(tools, "Debugger ...");
#endif
help.create(*this, "Help");
helpAbout.create(help, "About ...");
@@ -192,6 +196,10 @@ void MainWindow::create() {
toolsCheatEditor.onTick = []() { cheatEditor.setVisible(); };
toolsStateManager.onTick = []() { stateManager.setVisible(); };
#if defined(DEBUGGER)
toolsDebugger.onTick = []() { debugger.setVisible(); };
#endif
helpAbout.onTick = []() {
MessageWindow::information(mainWindow, {
"bsnes\n\n",

View File

@@ -23,6 +23,7 @@ struct MainWindow : TopLevelWindow {
MenuRadioItem systemPort2SuperScope;
MenuRadioItem systemPort2Justifier;
MenuRadioItem systemPort2Justifiers;
Menu settings;
Menu settingsVideoMode;
MenuRadioItem settingsVideoMode1x;
@@ -45,6 +46,7 @@ struct MainWindow : TopLevelWindow {
MenuItem settingsAudio;
MenuItem settingsInput;
MenuItem settingsAdvanced;
Menu tools;
Menu toolsStateSave;
MenuItem toolsStateSave1;
@@ -63,8 +65,14 @@ struct MainWindow : TopLevelWindow {
MenuSeparator toolsSeparator2;
MenuItem toolsCheatEditor;
MenuItem toolsStateManager;
#if defined(DEBUGGER)
MenuSeparator toolsSeparator3;
MenuItem toolsDebugger;
#endif
Menu help;
MenuItem helpAbout;
Viewport viewport;
void create();

View File

@@ -28,6 +28,11 @@ void InputMapper::poll_hotkeys(unsigned scancode, int16_t value) {
utility.showMessage({ "Slot ", activeSlot, " selected" });
}
//pause
if(scancode == keyboard(0)[Keyboard::P]) {
application.pause = !application.pause;
}
//fast forward
if(scancode == keyboard(0)[Keyboard::Tilde]) {
videoSync = config.video.synchronize;

View File

@@ -1,4 +1,5 @@
Palette palette;
Filter filter;
Interface interface;
const uint8_t Palette::gammaRamp[32] = {
@@ -63,6 +64,20 @@ void Palette::update() {
}
}
void Filter::size(unsigned &width, unsigned &height) {
if(opened() && dl_size) return dl_size(width, height);
}
void Filter::render(uint32_t *output, unsigned outpitch, const uint16_t *input, unsigned pitch, unsigned width, unsigned height) {
if(opened() && dl_render) return dl_render(palette.color, output, outpitch, input, pitch, width, height);
for(unsigned y = 0; y < height; y++) {
uint32_t *outputLine = output + y * (outpitch >> 2);
const uint16_t *inputLine = input + y * (pitch >> 1);
for(unsigned x = 0; x < width; x++) *outputLine++ = palette.color[*inputLine++];
}
}
void Interface::video_refresh(const uint16_t *data, unsigned width, unsigned height) {
bool interlace = (height >= 240);
bool overscan = (height == 239 || height == 478);
@@ -85,12 +100,11 @@ void Interface::video_refresh(const uint16_t *data, unsigned width, unsigned hei
if(height == 448) height = 478;
}
if(video.lock(buffer, outpitch, width, height)) {
for(unsigned y = 0; y < height; y++) {
uint32_t *output = buffer + y * (outpitch >> 2);
const uint16_t *input = data + y * (inpitch >> 1);
for(unsigned x = 0; x < width; x++) *output++ = palette.color[*input++];
}
unsigned outwidth = width, outheight = height;
filter.size(outwidth, outheight);
if(video.lock(buffer, outpitch, outwidth, outheight)) {
filter.render(buffer, outpitch, data, inpitch, width, height);
video.unlock();
video.refresh();
}
@@ -119,3 +133,7 @@ int16_t Interface::input_poll(bool port, SNES::Input::Device device, unsigned in
if(config.settings.focusPolicy == 1 && mainWindow.focused() == false) return 0;
return inputMapper.poll(port, device, index, id);
}
void Interface::message(const string &text) {
MessageWindow::information(mainWindow, text);
}

View File

@@ -7,12 +7,22 @@ struct Palette {
void update();
};
struct Filter : public library {
function<void (unsigned&, unsigned&)> dl_size;
function<void (uint32_t*, uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned)> dl_render;
void size(unsigned &width, unsigned &height);
void render(uint32_t *output, unsigned outpitch, const uint16_t *input, unsigned pitch, unsigned width, unsigned height);
};
struct Interface : public SNES::Interface {
void video_refresh(const uint16_t *data, unsigned width, unsigned height);
void audio_sample(uint16_t left, uint16_t right);
void input_poll();
int16_t input_poll(bool port, SNES::Input::Device device, unsigned index, unsigned id);
void message(const string &text);
};
extern Palette palette;
extern Filter filter;
extern Interface interface;

View File

@@ -46,6 +46,10 @@ void Application::main(int argc, char **argv) {
advancedSettings.create();
cheatEditor.create();
stateManager.create();
#if defined(DEBUGGER)
debugger.create();
#endif
loadGeometry();
saveGeometry();
@@ -86,6 +90,7 @@ void Application::main(int argc, char **argv) {
}
utility.setControllers();
utility.setFilter();
utility.setShader();
if(argc == 2) cartridge.loadNormal(argv[1]);
@@ -96,14 +101,15 @@ void Application::main(int argc, char **argv) {
utility.updateStatus();
if(SNES::cartridge.loaded()) {
//pause emulator when main window is inactive?
if(config.settings.focusPolicy == 0) {
if(mainWindow.focused() == false) {
usleep(20 * 1000);
continue;
}
if(application.pause == true || (config.settings.focusPolicy == 0 && mainWindow.focused() == false)) {
usleep(20 * 1000);
continue;
}
#if defined(DEBUGGER)
debugger.run();
#else
SNES::system.run();
#endif
} else {
usleep(20 * 1000);
}
@@ -129,6 +135,11 @@ void Application::addWindow(TopLevelWindow *window, const string &name, const st
geometryConfig.attach(window->position, window->name);
}
Application::Application() {
pause = false;
quit = false;
}
int main(int argc, char **argv) {
application.main(argc, argv);
return 0;
@@ -140,7 +151,7 @@ void Application::loadGeometry() {
lstring position;
position.split(",", window->position);
Geometry geom = window->geometry();
window->setGeometry(strunsigned(position[0]), strunsigned(position[1]), geom.width, geom.height);
window->setGeometry(decimal(position[0]), decimal(position[1]), geom.width, geom.height);
}
}

View File

@@ -23,6 +23,15 @@ void VideoSettings::create() {
gammaRampCheck.create (*this, x, y, 430, Style::CheckBoxHeight, "Enable NTSC gamma ramp simulation"); y += Style::CheckBoxHeight + 5;
filterLabel.create(*this, x, y, 340, Style::LabelHeight, "Video Filter :."); y += Style::LabelHeight + 5;
filterLabel.setFont(application.proportionalFontBold);
filterPath.create(*this, x, y, 430 - height - height - 10, height);
filterPath.setEditable(false);
filterPath.setText(config.video.filter);
filterClear.create(*this, x + 430 - height - height - 5, y, height, height, "");
filterSelect.create(*this, x + 430 - height, y, height, height, "..."); y += height + 5;
shaderLabel.create(*this, x, y, 340, Style::LabelHeight, "Pixel Shader :."); y += Style::LabelHeight + 5;
shaderLabel.setFont(application.proportionalFontBold);
@@ -42,6 +51,20 @@ void VideoSettings::create() {
contrastSlider.onChange = brightnessSlider.onChange = gammaSlider.onChange = gammaRampCheck.onTick =
{ &VideoSettings::adjust, this };
filterClear.onTick = []() {
config.video.filter = "";
videoSettings.filterPath.setText(config.video.filter);
utility.setFilter();
};
filterSelect.onTick = []() {
fileBrowser.fileOpen(FileBrowser::Mode::Filter, [](string filename) {
config.video.filter = filename;
videoSettings.filterPath.setText(config.video.filter);
utility.setFilter();
});
};
shaderClear.onTick = []() {
config.video.shader = "";
videoSettings.shaderPath.setText(config.video.shader);

View File

@@ -10,6 +10,12 @@ struct VideoSettings : TopLevelWindow {
Label gammaValue;
HorizontalSlider gammaSlider;
CheckBox gammaRampCheck;
Label filterLabel;
TextBox filterPath;
Button filterClear;
Button filterSelect;
Label shaderLabel;
TextBox shaderPath;
Button shaderClear;

View File

@@ -5,7 +5,7 @@ void CheatEditor::load(string filename) {
cheatList.reset();
for(unsigned i = 0; i < 128; i++) {
cheatList.addItem("");
cheatText[i][CheatSlot] = strunsigned<3, ' '>(i + 1);
cheatText[i][CheatSlot] = decimal<3, ' '>(i + 1);
cheatText[i][CheatCode] = "";
cheatText[i][CheatDesc] = "";
}

View File

@@ -41,7 +41,7 @@ void StateManager::synchronize() {
void StateManager::refresh() {
for(unsigned i = 0; i < 32; i++) {
stateList.setItem(i, {
strunsigned<2, ' '>(i + 1), "\t",
decimal<2, ' '>(i + 1), "\t",
slotLoadDescription(i)
});
}

View File

@@ -16,6 +16,10 @@ void Utility::updateStatus() {
text = statusMessage;
} else if(SNES::cartridge.loaded() == false) {
text = "No cartridge loaded";
} else if(application.pause) {
text = "Paused";
} else if(config.settings.focusPolicy == 0 && mainWindow.focused() == false) {
text = "Auto-paused";
} else {
text = statusText;
}
@@ -71,6 +75,16 @@ void Utility::setScale(unsigned scale) {
mainWindow.setGeometry(geom.x, geom.y, width, height);
}
void Utility::setFilter() {
if(filter.opened()) filter.close();
if(config.video.filter == "") return;
if(filter.open_absolute(config.video.filter)) {
filter.dl_size = filter.sym("filter_size");
filter.dl_render = filter.sym("filter_render");
if(!filter.dl_size || !filter.dl_render) filter.close();
}
}
void Utility::setShader() {
string data;
data.readfile(config.video.shader);
@@ -78,7 +92,6 @@ void Utility::setShader() {
}
void Utility::cartridgeLoaded() {
SNES::cartridge.basename = cartridge.baseName;
SNES::system.power();
cheatEditor.load(cartridge.baseName);
stateManager.load();

View File

@@ -6,6 +6,7 @@ struct Utility : property<Utility> {
void setControllers();
void setScale(unsigned scale = 0);
void setFilter();
void setShader();
void cartridgeLoaded();

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