mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-19 13:11:30 +02:00
Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
6ea4bc031f | ||
|
676a3adbf7 | ||
|
b27e0a719d | ||
|
a62aa94b65 | ||
|
9762a092d2 | ||
|
05526571e7 | ||
|
3bd29088d1 | ||
|
26643a43de | ||
|
7e8958b102 | ||
|
edac93b800 | ||
|
0730f847e5 | ||
|
5ae0c80ee8 |
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
libco
|
||||
version: 0.15 (2009-10-12)
|
||||
version: 0.16 (2010-12-24)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
|
@@ -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
407
bsnes/libco/ppc.c
Executable 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 );
|
||||
}
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@@ -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);
|
||||
|
@@ -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
868
bsnes/nall/snes/cartridge.hpp
Executable 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
458
bsnes/nall/snes/cpu.hpp
Executable 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
639
bsnes/nall/snes/smp.hpp
Executable 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
|
@@ -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);
|
||||
|
@@ -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; }
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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"
|
||||
|
@@ -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
266
bsnes/phoenix/gtk/hexeditor.cpp
Executable 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);
|
||||
}
|
@@ -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);
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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!
|
||||
|
@@ -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/*
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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", "");
|
||||
|
@@ -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();
|
||||
|
@@ -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&);
|
||||
|
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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 {
|
||||
|
@@ -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>
|
||||
|
@@ -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) {}
|
||||
|
||||
}
|
@@ -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
@@ -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
|
||||
|
@@ -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
|
@@ -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) {}
|
||||
|
||||
}
|
@@ -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;
|
@@ -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
|
@@ -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
|
@@ -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();
|
||||
}
|
||||
|
||||
}
|
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -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
@@ -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
|
205
bsnes/snes/chip/upd77c25/disassembler.cpp
Executable file
205
bsnes/snes/chip/upd77c25/disassembler.cpp
Executable 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;
|
||||
}
|
52
bsnes/snes/chip/upd77c25/serialization.cpp
Executable file
52
bsnes/snes/chip/upd77c25/serialization.cpp
Executable 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
|
344
bsnes/snes/chip/upd77c25/upd77c25.cpp
Executable file
344
bsnes/snes/chip/upd77c25/upd77c25.cpp
Executable 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); }
|
||||
|
||||
}
|
98
bsnes/snes/chip/upd77c25/upd77c25.hpp
Executable file
98
bsnes/snes/chip/upd77c25/upd77c25.hpp
Executable 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;
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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]);
|
||||
|
@@ -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"); }
|
||||
};
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -11,6 +11,7 @@ public:
|
||||
};
|
||||
uint8 *usage;
|
||||
uint16 opcode_pc;
|
||||
bool opcode_edge;
|
||||
|
||||
void op_step();
|
||||
uint8 op_read(uint16 addr);
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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))
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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");
|
||||
|
@@ -12,6 +12,7 @@ struct Configuration : public configuration {
|
||||
string driver;
|
||||
bool synchronize;
|
||||
bool smooth;
|
||||
string filter;
|
||||
string shader;
|
||||
bool region;
|
||||
unsigned scale;
|
||||
|
84
bsnes/ui-phoenix/debugger/console.cpp
Executable file
84
bsnes/ui-phoenix/debugger/console.cpp
Executable 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);
|
||||
}
|
21
bsnes/ui-phoenix/debugger/console.hpp
Executable file
21
bsnes/ui-phoenix/debugger/console.hpp
Executable 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;
|
||||
|
107
bsnes/ui-phoenix/debugger/cpu/debugger.cpp
Executable file
107
bsnes/ui-phoenix/debugger/cpu/debugger.cpp
Executable 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);
|
||||
}
|
16
bsnes/ui-phoenix/debugger/cpu/debugger.hpp
Executable file
16
bsnes/ui-phoenix/debugger/cpu/debugger.hpp
Executable 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;
|
138
bsnes/ui-phoenix/debugger/debugger.cpp
Executable file
138
bsnes/ui-phoenix/debugger/debugger.cpp
Executable 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
|
31
bsnes/ui-phoenix/debugger/debugger.hpp
Executable file
31
bsnes/ui-phoenix/debugger/debugger.hpp
Executable 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;
|
106
bsnes/ui-phoenix/debugger/smp/debugger.cpp
Executable file
106
bsnes/ui-phoenix/debugger/smp/debugger.cpp
Executable 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);
|
||||
}
|
16
bsnes/ui-phoenix/debugger/smp/debugger.hpp
Executable file
16
bsnes/ui-phoenix/debugger/smp/debugger.hpp
Executable 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;
|
57
bsnes/ui-phoenix/debugger/tools/breakpoint-editor.cpp
Executable file
57
bsnes/ui-phoenix/debugger/tools/breakpoint-editor.cpp
Executable 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);
|
||||
}
|
15
bsnes/ui-phoenix/debugger/tools/breakpoint-editor.hpp
Executable file
15
bsnes/ui-phoenix/debugger/tools/breakpoint-editor.hpp
Executable 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;
|
78
bsnes/ui-phoenix/debugger/tools/memory-editor.cpp
Executable file
78
bsnes/ui-phoenix/debugger/tools/memory-editor.cpp
Executable 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);
|
||||
}
|
16
bsnes/ui-phoenix/debugger/tools/memory-editor.hpp
Executable file
16
bsnes/ui-phoenix/debugger/tools/memory-editor.hpp
Executable 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;
|
@@ -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");
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -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",
|
||||
|
@@ -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();
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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] = "";
|
||||
}
|
||||
|
@@ -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)
|
||||
});
|
||||
}
|
||||
|
@@ -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();
|
||||
|
@@ -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
Reference in New Issue
Block a user