mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-17 01:02:01 +02:00
Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
85fa3cc968 | ||
|
d1fcddee9c | ||
|
9fd379613a | ||
|
aabf52d678 | ||
|
c9ca01fe20 | ||
|
becf122aaa | ||
|
1e130d7872 | ||
|
c57c733d7d | ||
|
e41aa25887 | ||
|
435f7d4371 | ||
|
a1980fab09 | ||
|
ebb234ba5f | ||
|
2cc7fe30b4 | ||
|
5c3c872b78 | ||
|
36bf915244 | ||
|
045a0f7e79 | ||
|
a209e6ffbe | ||
|
3bf672dd97 | ||
|
157ddf3e8f | ||
|
ea23bf53ae | ||
|
d4598e1d01 | ||
|
f9a8564af0 | ||
|
6d66b1136d | ||
|
b01f18c34c |
109
license.txt
109
license.txt
@@ -1,35 +1,86 @@
|
||||
bsnes License:
|
||||
--------------
|
||||
You are free to redistribute this software, and its source code; provided
|
||||
there is no charge for the software, nor any charge for the medium used to
|
||||
distribute the software. You are also free to use and modify the source code
|
||||
as you desire for personal use only. No publically-released derivative works
|
||||
of this program nor its source code are permitted without my permission,
|
||||
though I will likely grant you permission if you ask me. You must also abide
|
||||
by the terms of any additional source code licenses contained within this
|
||||
program.
|
||||
bsnes (TM) Open Source Reference License
|
||||
Copyright (C) 2004 - 2007 byuu
|
||||
All rights reserved
|
||||
|
||||
Simple DirectMedia Layer License:
|
||||
---------------------------------
|
||||
The Simple DirectMedia Layer (SDL for short) is a cross-platform library
|
||||
designed to make it easy to write multi-media software, such as games and
|
||||
emulators.
|
||||
1. Definitions
|
||||
|
||||
The Simple DirectMedia Layer library source code is available from:
|
||||
http://www.libsdl.org/
|
||||
The terms "reproduce", "reproduction", "distribute" and "distribution" have the
|
||||
same meaning here as under U.S. copyright law.
|
||||
|
||||
This library is distributed under the terms of the GNU LGPL:
|
||||
http://www.gnu.org/copyleft/lesser.html
|
||||
"The software" means this software package as a whole, including, but not
|
||||
limited to, this license, binaries, source code, documentation, and data.
|
||||
|
||||
JMA License:
|
||||
------------
|
||||
JMA is licensed under the GNU GPL. I have received special exemption from
|
||||
Nach to use this library in bsnes.
|
||||
"You" means the licensee of the software.
|
||||
|
||||
Licensing Exemptions:
|
||||
---------------------
|
||||
libco, the cooperative multithreading library used by bsnes, is public domain.
|
||||
You may obtain the latest version at: http://byuu.org/
|
||||
"The licensor" means the copyright holder of the software, byuu.
|
||||
|
||||
Richard Bannister has asked for and received my permission to distribute
|
||||
a binary-only port of bsnes on the Mac OS X platform.
|
||||
2. Grant of Rights
|
||||
|
||||
Subject to the terms of this license, the licensor grants you a
|
||||
non-transferable, non-exclusive, worldwide, royalty-free copyright license to
|
||||
reproduce the software for non-commercial use only, provided the software
|
||||
remains unmodified, and there is no charge for the software itself, its' use,
|
||||
nor for the medium upon which the software is distributed. The reproduction of
|
||||
modified or derivative works of the software is strictly prohibited, except when
|
||||
transmitted solely to the licensor.
|
||||
|
||||
3. Limitations
|
||||
|
||||
This license does not grant you any rights to use the licensor's name, logo or
|
||||
trademarks.
|
||||
|
||||
The software is provided "as is", and any express or implied warranties,
|
||||
including, but not limited to, the implied warranties of merchantability and
|
||||
fitness for a particular purpose are disclaimed. In no event shall the licensor
|
||||
be liable for any direct, indirect, incidental, special, exemplary, or
|
||||
consequential damages (including, but not limited to, procurement of substitute
|
||||
goods or services; loss of use, data, or profits; or business interruption)
|
||||
however caused and on any theory of liability, whether in contract, strict
|
||||
liability, or tort (including negligence or otherwise) arising in any way out of
|
||||
the use of the software, even if advised of the possibility of such damage.
|
||||
|
||||
In the event that this license is determined to be invalid or unenforceable, the
|
||||
Grant of Rights will become null and void, and no rights shall be granted to the
|
||||
licensee, within the scope of U.S. copyright law.
|
||||
|
||||
4. Exemptions
|
||||
|
||||
The software includes the work of other copyright holders, which is licensed
|
||||
under different agreements, and exempt from this license. Below is a complete
|
||||
list of all such software, and their respective copyright holders and licenses.
|
||||
Further, respective source code files are labeled with their correct licensing
|
||||
information in the header. The lack of such a header indicates said file falls
|
||||
under the bsnes license.
|
||||
|
||||
HQ2x filter, author: MaxST, license: LGPL
|
||||
JMA decompressor, author: NSRT Team, license: GPL (*)
|
||||
NTSC filter, author: blargg, license: LGPL
|
||||
zlib decompressor, license: zlib license
|
||||
|
||||
(*) bsnes has received an exemption from the copyright holder to use this work.
|
||||
|
||||
The software also includes works which have been released to the public domain,
|
||||
which are not bound to any licensing agreements. Below is a complete list of all
|
||||
such software.
|
||||
|
||||
libco, author: byuu
|
||||
libui, author: byuu
|
||||
OBC-1 emu, author: byuu
|
||||
S-DD1 emu, author: Andreas Naive
|
||||
S-RTC emu, author: byuu
|
||||
|
||||
Any software listed above as exemptions may be relicensed individually from
|
||||
bsnes under their respective terms. However, no bsnes licensed portions can be
|
||||
combined with such a derivative work.
|
||||
|
||||
The software also includes the work of other copyright holders, which is
|
||||
licensed under the terms of the bsnes license, with permission to do so from the
|
||||
respective authors. Below is a complete list of all such software.
|
||||
|
||||
Cx4 emu, authors: anomie, Overload, zsKnight, Nach
|
||||
DSP-1 emu, authors: Overload, John Weidman, Neviksti, Andreas Naive
|
||||
DSP-2 emu, author: Overload
|
||||
DSP-3 emu, authors: John Weidman, Kris Bleakley, Lancer, z80 gaiden
|
||||
DSP-4 emu, authors: Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden
|
||||
S-DSP emu, author: blargg
|
||||
ST-010 emu, authors: John Weidman, Matthew Kendora, Overload, Feather
|
||||
|
69
readme.txt
69
readme.txt
@@ -1,10 +1,10 @@
|
||||
bsnes
|
||||
Version 0.019
|
||||
Version 0.025
|
||||
Author: byuu
|
||||
|
||||
|
||||
General
|
||||
-------
|
||||
--------
|
||||
General:
|
||||
--------
|
||||
bsnes is a Super Nintendo / Super Famicom emulator that began on
|
||||
October 14th, 2004.
|
||||
|
||||
@@ -13,19 +13,22 @@ http://byuu.org/
|
||||
|
||||
Please see license.txt for important licensing information.
|
||||
|
||||
--------------
|
||||
Shortcut Keys:
|
||||
--------------
|
||||
Esc - Toggle menubar visibility
|
||||
F11 - Toggle fullscreen mode
|
||||
|
||||
Known Limitations
|
||||
-----------------
|
||||
------------------
|
||||
Known Limitations:
|
||||
------------------
|
||||
S-CPU
|
||||
- Invalid DMA / HDMA transfers (eg WRAM<>WRAM) not fully emulated
|
||||
- Invalid DMA / HDMA transfers not fully emulated
|
||||
- Multiply / Divide register delays not implemented
|
||||
|
||||
S-SMP
|
||||
- Cycle breakdown of opcodes is theoretical, but mostly correct
|
||||
|
||||
S-PPU
|
||||
- Uses scanline-based renderer. This is very inaccurate, but very
|
||||
few games rely on mid-scanline writes to function correctly
|
||||
- Uses scanline-based renderer. This is very inaccurate, but few (if any)
|
||||
games rely on mid-scanline writes to function correctly
|
||||
- Does not support FirstSprite+Y priority
|
||||
- OAM / CGRAM accesses during active display not supported correctly
|
||||
- RTO flags are not calculated on frames that are skipped when frameskipping
|
||||
@@ -33,18 +36,13 @@ S-PPU
|
||||
in games that test these flags, eg the SNES Test Program Electronics Test.
|
||||
Turning frameskipping off will allow RTO flag calculation on every frame
|
||||
|
||||
S-DSP
|
||||
- Runs at 32khz. Hardware S-DSP likely runs at 1.024mhz to perform
|
||||
multiple reads / writes per sample. Sound is still output at 32khz,
|
||||
of course
|
||||
|
||||
Hardware Bugs
|
||||
- CPUr1 HDMA crashing bug not emulated
|
||||
- CPU<>APU communication bus conflicts not emulated
|
||||
- S-CPU.r1 HDMA crashing bug not emulated
|
||||
- S-CPU<>S-SMP communication bus conflicts not emulated
|
||||
|
||||
|
||||
Unsupported Hardware
|
||||
--------------------
|
||||
---------------------
|
||||
Unsupported Hardware:
|
||||
---------------------
|
||||
SA-1
|
||||
Coprocessor used in many popular games, including:
|
||||
- Dragon Ball Z Hyper Dimension
|
||||
@@ -68,31 +66,26 @@ Coprocessor used only by the following games:
|
||||
- Momotarou Densetsu Happy
|
||||
- Super Power League 4
|
||||
|
||||
DSP-3
|
||||
Coprocessor used only by SD Gundam GX
|
||||
ST-011
|
||||
SETA DSP used only by Quick-move Shogi Match with Nidan Rank-holder Morita
|
||||
|
||||
DSP-4
|
||||
Coprocessor used only by Top Gear 3000
|
||||
|
||||
ST010 / ST011 / ST018
|
||||
SETA coprocessors used by very few games
|
||||
ST-018
|
||||
SETA RISC CPU used only by Quick-move Shogi Match with Nidan Rank-holder Morita 2
|
||||
|
||||
BS-X (Broadcast Satellite)
|
||||
Add-on unit sold only in Japan that played specially-made games that
|
||||
were downloaded via satellite
|
||||
Add-on unit sold only in Japan that played specially-made games that were
|
||||
downloaded via satellite
|
||||
|
||||
BS-X Flashcart
|
||||
Flash cartridge used by BS-X, as well as some standalone games by
|
||||
Asciisoft
|
||||
Flash cartridge used by BS-X, as well as some standalone games by Asciisoft
|
||||
|
||||
Super Gameboy
|
||||
Cartridge passthrough used for playing Gameboy games
|
||||
|
||||
|
||||
Unsupported controllers
|
||||
-----------------------
|
||||
------------------------
|
||||
Unsupported Controllers:
|
||||
------------------------
|
||||
Mouse
|
||||
Super Scope
|
||||
Justifier
|
||||
Multitap (4-port)
|
||||
Multitap (5-port)
|
||||
Multitap (4-port and 5-port)
|
||||
|
315
src/Makefile
Normal file
315
src/Makefile
Normal file
@@ -0,0 +1,315 @@
|
||||
######################
|
||||
### bsnes makefile ###
|
||||
######################
|
||||
|
||||
ifeq ($(PLATFORM),)
|
||||
_null_: help
|
||||
endif
|
||||
|
||||
##################################
|
||||
### platform-specific settings ###
|
||||
##################################
|
||||
|
||||
ifeq ($(PLATFORM),x-gcc-lui)
|
||||
OS = unix
|
||||
CC = gcc
|
||||
CFLAGS = -O3 -fomit-frame-pointer -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_LUI `pkg-config --cflags gtk+-2.0`
|
||||
AS = nasm
|
||||
ASFLAGS = -f elf
|
||||
LIBS = `pkg-config --libs gtk+-2.0` -lXv -lao
|
||||
LIBCO = libco_x86
|
||||
LIBUI = libui_gtk
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),x-gcc-lui-x64)
|
||||
OS = unix
|
||||
CC = gcc
|
||||
CFLAGS = -O3 -fomit-frame-pointer -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86_64 -DUI_LUI `pkg-config --cflags gtk+-2.0`
|
||||
AS = yasm
|
||||
ASFLAGS = -f elf64
|
||||
LIBS = `pkg-config --libs gtk+-2.0` -lXv -lao
|
||||
LIBCO = libco_x86_64
|
||||
LIBUI = libui_gtk
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),win-visualc-lui)
|
||||
OS = win
|
||||
CC = cl
|
||||
CFLAGS = /nologo /wd4996 /O2 /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_LUI
|
||||
AS = nasm
|
||||
ASFLAGS = -f win32 -DWIN32
|
||||
LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib kernel32.lib user32.lib gdi32.lib shell32.lib winmm.lib comdlg32.lib comctl32.lib
|
||||
LIBCO = libco_x86
|
||||
LIBUI = libui_win
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),win-visualc-lui-pgi)
|
||||
OS = win
|
||||
CC = cl
|
||||
CFLAGS = /nologo /wd4996 /O2 /GL /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_LUI
|
||||
AS = nasm
|
||||
ASFLAGS = -f win32 -DWIN32
|
||||
LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib kernel32.lib user32.lib gdi32.lib shell32.lib winmm.lib comdlg32.lib comctl32.lib
|
||||
LINK = /link /PGD:bsnes.pgd /LTCG:PGINSTRUMENT
|
||||
LIBCO = libco_x86
|
||||
LIBUI = libui_win
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),win-visualc-lui-pgo)
|
||||
OS = win
|
||||
CC = cl
|
||||
CFLAGS = /nologo /wd4996 /O2 /GL /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_LUI
|
||||
AS = nasm
|
||||
ASFLAGS = -f win32 -DWIN32
|
||||
LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib kernel32.lib user32.lib gdi32.lib shell32.lib winmm.lib comdlg32.lib comctl32.lib
|
||||
LINK = /link /PGD:bsnes.pgd /LTCG:PGOPTIMIZE
|
||||
LIBCO = libco_x86
|
||||
LIBUI = libui_win
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),win-mingw-lui)
|
||||
OS = win
|
||||
CC = mingw32-gcc
|
||||
CFLAGS = -mwindows -O3 -fomit-frame-pointer -DPLATFORM_WIN -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_LUI
|
||||
AS = nasm
|
||||
ASFLAGS = -f win32 -DWIN32
|
||||
LIBS = -ld3d9 -lddraw -ldsound -ldinput8 -ldxguid -luuid -lkernel32 -luser32 -lgdi32 -lshell32 -lwinmm -lcomdlg32 -lcomctl32
|
||||
LIBCO = libco_x86
|
||||
LIBUI = libui_win
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),win-mingw4-lui)
|
||||
OS = win
|
||||
CC = mingw32-gcc-sjlj
|
||||
CFLAGS = -mconsole -O3 -fomit-frame-pointer -DPLATFORM_WIN -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_LUI
|
||||
AS = nasm
|
||||
ASFLAGS = -f win32 -DWIN32
|
||||
LIBS = -ld3d9 -lddraw -ldsound -ldinput8 -ldxguid -luuid -lkernel32 -luser32 -lgdi32 -lshell32 -lwinmm -lcomdlg32 -lcomctl32
|
||||
LIBCO = libco_x86
|
||||
LIBUI = libui_win
|
||||
endif
|
||||
|
||||
#####################################
|
||||
### compiler / assembler switches ###
|
||||
#####################################
|
||||
|
||||
ifeq ($(CC),gcc)
|
||||
OUT = -obsnes
|
||||
CPP = g++
|
||||
OBJ = o
|
||||
CARGS = -c $< -o $@
|
||||
DEFINE = -D
|
||||
endif
|
||||
|
||||
ifeq ($(CC),mingw32-gcc)
|
||||
OUT = -obsnes
|
||||
CPP = mingw32-g++
|
||||
OBJ = o
|
||||
CARGS = -c $< -o $@
|
||||
DEFINE = -D
|
||||
endif
|
||||
|
||||
ifeq ($(CC),mingw32-gcc-sjlj)
|
||||
OUT = -obsnes
|
||||
CPP = mingw32-g++-sjlj
|
||||
OBJ = o
|
||||
CARGS = -c $< -o $@
|
||||
DEFINE = -D
|
||||
endif
|
||||
|
||||
ifeq ($(CC),cl)
|
||||
OUT = /Febsnes
|
||||
CPP = cl
|
||||
OBJ = obj
|
||||
CARGS = /c $< /Fo$@
|
||||
DEFINE = /D
|
||||
endif
|
||||
|
||||
ifeq ($(AS),nasm)
|
||||
ASARGS = $< -o $@
|
||||
endif
|
||||
|
||||
ifeq ($(AS),yasm)
|
||||
ASARGS = $< -o $@
|
||||
endif
|
||||
|
||||
###################
|
||||
### OS switches ###
|
||||
###################
|
||||
|
||||
ifeq ($(OS),unix)
|
||||
RM = rm -f
|
||||
endif
|
||||
|
||||
ifeq ($(OS),win)
|
||||
OUT := $(OUT).exe
|
||||
RM = del
|
||||
endif
|
||||
|
||||
####################################
|
||||
### main target and dependencies ###
|
||||
####################################
|
||||
|
||||
OBJECTS = main.$(OBJ) $(LIBCO).$(OBJ) $(LIBUI).$(OBJ) \
|
||||
libstring.$(OBJ) \
|
||||
reader.$(OBJ) cart.$(OBJ) cheat.$(OBJ) memory.$(OBJ) bmemory.$(OBJ) \
|
||||
cpu.$(OBJ) scpu.$(OBJ) smp.$(OBJ) ssmp.$(OBJ) bdsp.$(OBJ) ppu.$(OBJ) \
|
||||
bppu.$(OBJ) snes.$(OBJ) superfx.$(OBJ) srtc.$(OBJ) sdd1.$(OBJ) c4.$(OBJ) \
|
||||
dsp1.$(OBJ) dsp2.$(OBJ) dsp3.$(OBJ) dsp4.$(OBJ) obc1.$(OBJ) st010.$(OBJ)
|
||||
|
||||
ifeq ($(GZIP_SUPPORT),true)
|
||||
OBJECTS += adler32.$(OBJ) compress.$(OBJ) crc32.$(OBJ) deflate.$(OBJ) \
|
||||
gzio.$(OBJ) inffast.$(OBJ) inflate.$(OBJ) inftrees.$(OBJ) ioapi.$(OBJ) \
|
||||
trees.$(OBJ) unzip.$(OBJ) zip.$(OBJ) zutil.$(OBJ)
|
||||
CFLAGS += $(DEFINE)GZIP_SUPPORT
|
||||
endif
|
||||
|
||||
ifeq ($(JMA_SUPPORT),true)
|
||||
OBJECTS += jma.$(OBJ) jcrc32.$(OBJ) lzmadec.$(OBJ) 7zlzma.$(OBJ) \
|
||||
iiostrm.$(OBJ) inbyte.$(OBJ) lzma.$(OBJ) winout.$(OBJ)
|
||||
CFLAGS += $(DEFINE)JMA_SUPPORT
|
||||
endif
|
||||
|
||||
ifeq ($(OS),win)
|
||||
ifeq ($(CC),cl)
|
||||
OBJECTS += bsnes.res
|
||||
endif
|
||||
endif
|
||||
|
||||
all: $(OBJECTS)
|
||||
$(CPP) $(OUT) $(CFLAGS) $(OBJECTS) $(LIBS) $(LINK)
|
||||
# mt -nologo -manifest bsnes.exe.manifest -outputresource:bsnes.exe;1
|
||||
|
||||
######################
|
||||
### implicit rules ###
|
||||
######################
|
||||
|
||||
%.$(OBJ): $<
|
||||
$(if $(filter %.asm,$<),$(AS) $(ASFLAGS) $(ASARGS))
|
||||
$(if $(filter %.c,$<),$(CC) $(CFLAGS) $(CARGS))
|
||||
$(if $(filter %.cpp,$<),$(CPP) $(CFLAGS) $(CARGS))
|
||||
|
||||
#########################
|
||||
### platform-specific ###
|
||||
#########################
|
||||
main.$(OBJ): ui/main.cpp config/* ui/* ui/video/* ui/audio/* ui/input/* \
|
||||
ui/lui/* ui/lui/settings/* \
|
||||
ui/win/* ui/win/settings/* ui/win/debugger/*
|
||||
bsnes.res : ui/bsnes.rc ; rc /r /fobsnes.res ui/bsnes.rc
|
||||
|
||||
#############
|
||||
### libco ###
|
||||
#############
|
||||
libco_x86.$(OBJ) : lib/libco_x86.asm lib/*
|
||||
libco_x86_64.$(OBJ): lib/libco_x86_64.asm lib/*
|
||||
|
||||
#############
|
||||
### libui ###
|
||||
#############
|
||||
libui_gtk.$(OBJ): lib/libui_gtk.cpp lib/*
|
||||
libui_win.$(OBJ): lib/libui_win.cpp lib/*
|
||||
|
||||
#################
|
||||
### libraries ###
|
||||
#################
|
||||
libstring.$(OBJ): lib/libstring.cpp lib/*
|
||||
|
||||
#################
|
||||
### utilities ###
|
||||
#################
|
||||
reader.$(OBJ): reader/reader.cpp reader/*
|
||||
cart.$(OBJ) : cart/cart.cpp cart/*
|
||||
cheat.$(OBJ) : cheat/cheat.cpp cheat/*
|
||||
|
||||
##############
|
||||
### memory ###
|
||||
##############
|
||||
memory.$(OBJ) : memory/memory.cpp memory/*
|
||||
bmemory.$(OBJ): memory/bmemory/bmemory.cpp memory/bmemory/* memory/bmemory/mapper/*
|
||||
|
||||
###########
|
||||
### cpu ###
|
||||
###########
|
||||
cpu.$(OBJ) : cpu/cpu.cpp cpu/*
|
||||
scpu.$(OBJ): cpu/scpu/scpu.cpp cpu/scpu/* cpu/scpu/core/* cpu/scpu/dma/* cpu/scpu/memory/* cpu/scpu/mmio/* cpu/scpu/timing/*
|
||||
|
||||
###########
|
||||
### smp ###
|
||||
###########
|
||||
smp.$(OBJ) : smp/smp.cpp smp/*
|
||||
ssmp.$(OBJ): smp/ssmp/ssmp.cpp smp/ssmp/* smp/ssmp/core/* smp/ssmp/memory/* smp/ssmp/timing/*
|
||||
|
||||
###########
|
||||
### dsp ###
|
||||
###########
|
||||
adsp.$(OBJ): dsp/adsp/adsp.cpp dsp/adsp/*
|
||||
bdsp.$(OBJ): dsp/bdsp/bdsp.cpp dsp/bdsp/*
|
||||
|
||||
###########
|
||||
### ppu ###
|
||||
###########
|
||||
ppu.$(OBJ) : ppu/ppu.cpp ppu/*
|
||||
bppu.$(OBJ): ppu/bppu/bppu.cpp ppu/bppu/*
|
||||
|
||||
############
|
||||
### snes ###
|
||||
############
|
||||
snes.$(OBJ): snes/snes.cpp snes/* snes/scheduler/* snes/video/* snes/audio/* snes/input/*
|
||||
|
||||
#####################
|
||||
### special chips ###
|
||||
#####################
|
||||
superfx.$(OBJ): chip/superfx/superfx.cpp chip/superfx/* chip/superfx/core/* chip/superfx/memory/*
|
||||
srtc.$(OBJ) : chip/srtc/srtc.cpp chip/srtc/*
|
||||
sdd1.$(OBJ) : chip/sdd1/sdd1.cpp chip/sdd1/*
|
||||
c4.$(OBJ) : chip/c4/c4.cpp chip/c4/*
|
||||
dsp1.$(OBJ) : chip/dsp1/dsp1.cpp chip/dsp1/*
|
||||
dsp2.$(OBJ) : chip/dsp2/dsp2.cpp chip/dsp2/*
|
||||
dsp3.$(OBJ) : chip/dsp3/dsp3.cpp chip/dsp3/*
|
||||
dsp4.$(OBJ) : chip/dsp4/dsp4.cpp chip/dsp4/*
|
||||
obc1.$(OBJ) : chip/obc1/obc1.cpp chip/obc1/*
|
||||
st010.$(OBJ) : chip/st010/st010.cpp chip/st010/*
|
||||
|
||||
############
|
||||
### zlib ###
|
||||
############
|
||||
adler32.$(OBJ) : reader/zlib/adler32.c reader/zlib/*
|
||||
compress.$(OBJ): reader/zlib/compress.c reader/zlib/*
|
||||
crc32.$(OBJ) : reader/zlib/crc32.c reader/zlib/*
|
||||
deflate.$(OBJ) : reader/zlib/deflate.c reader/zlib/*
|
||||
gzio.$(OBJ) : reader/zlib/gzio.c reader/zlib/*
|
||||
inffast.$(OBJ) : reader/zlib/inffast.c reader/zlib/*
|
||||
inflate.$(OBJ) : reader/zlib/inflate.c reader/zlib/*
|
||||
inftrees.$(OBJ): reader/zlib/inftrees.c reader/zlib/*
|
||||
ioapi.$(OBJ) : reader/zlib/ioapi.c reader/zlib/*
|
||||
trees.$(OBJ) : reader/zlib/trees.c reader/zlib/*
|
||||
unzip.$(OBJ) : reader/zlib/unzip.c reader/zlib/*
|
||||
zip.$(OBJ) : reader/zlib/zip.c reader/zlib/*
|
||||
zutil.$(OBJ) : reader/zlib/zutil.c reader/zlib/*
|
||||
|
||||
###########
|
||||
### jma ###
|
||||
###########
|
||||
jma.$(OBJ) : reader/jma/jma.cpp reader/jma/*
|
||||
jcrc32.$(OBJ) : reader/jma/jcrc32.cpp reader/jma/*
|
||||
lzmadec.$(OBJ): reader/jma/lzmadec.cpp reader/jma/*
|
||||
7zlzma.$(OBJ) : reader/jma/7zlzma.cpp reader/jma/*
|
||||
iiostrm.$(OBJ): reader/jma/iiostrm.cpp reader/jma/*
|
||||
inbyte.$(OBJ) : reader/jma/inbyte.cpp reader/jma/*
|
||||
lzma.$(OBJ) : reader/jma/lzma.cpp reader/jma/*
|
||||
winout.$(OBJ) : reader/jma/winout.cpp reader/jma/*
|
||||
|
||||
####################
|
||||
### misc targets ###
|
||||
####################
|
||||
clean:
|
||||
-@$(RM) *.$(OBJ)
|
||||
-@$(RM) *.res
|
||||
-@$(RM) *.pgd
|
||||
-@$(RM) *.pgc
|
||||
-@$(RM) *.ilk
|
||||
-@$(RM) *.pdb
|
||||
-@$(RM) *.manifest
|
||||
|
||||
help:
|
||||
@echo Please specify which platform to compile for with PLATFORM=platform_name
|
31
src/base.h
31
src/base.h
@@ -1,4 +1,4 @@
|
||||
#define BSNES_VERSION "0.019"
|
||||
#define BSNES_VERSION "0.025"
|
||||
#define BSNES_TITLE "bsnes v" BSNES_VERSION
|
||||
|
||||
#define MEMCORE bMemBus
|
||||
@@ -13,48 +13,35 @@
|
||||
//game genie + pro action replay code support (~1-3% speed hit)
|
||||
#define CHEAT_SYSTEM
|
||||
|
||||
//enable GZ, ZIP format support
|
||||
//#define GZIP_SUPPORT
|
||||
|
||||
//enable JMA support
|
||||
//#define JMA_SUPPORT
|
||||
|
||||
//snes core polymorphism
|
||||
//(allow runtime cpu/smp/dsp/ppu/bus selection, ~10% speed hit)
|
||||
//#define POLYMORPHISM
|
||||
|
||||
#include "lib/libbase.h"
|
||||
|
||||
#if defined(PROCESSOR_X86)
|
||||
#define ARCH_LSB
|
||||
#include "lib/libco_x86.h"
|
||||
#elif defined(PROCESSOR_X86_64)
|
||||
#define ARCH_LSB
|
||||
#include "lib/libco_x86_64.h"
|
||||
#elif defined(PROCESSOR_G5)
|
||||
#define ARCH_MSB
|
||||
#else
|
||||
#error "unsupported processor"
|
||||
#endif
|
||||
|
||||
#include "lib/libbase.h"
|
||||
#include "lib/libfunctor.h"
|
||||
#include "lib/libsort.h"
|
||||
#include "lib/libco_x86.h"
|
||||
#include "lib/libarray.h"
|
||||
#include "lib/libvector.h"
|
||||
#include "lib/libfile.h"
|
||||
#include "lib/libups.h"
|
||||
#include "lib/libstring.h"
|
||||
#include "lib/libconfig.h"
|
||||
|
||||
inline uint16 read16(uint8 *addr, uint pos) {
|
||||
#ifdef ARCH_LSB
|
||||
return *((uint16*)(addr + pos));
|
||||
#else
|
||||
return (addr[pos]) | (addr[pos + 1] << 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
//platform-specific global functions
|
||||
void alert(char *, ...);
|
||||
void dprintf(char *, ...);
|
||||
void dprintf(uint, char *, ...);
|
||||
void alert(const char*, ...);
|
||||
void dprintf(const char*, ...);
|
||||
void dprintf(uint, const char*, ...);
|
||||
|
||||
namespace source {
|
||||
enum {
|
||||
|
BIN
src/bsnes.lnk
Normal file
BIN
src/bsnes.lnk
Normal file
Binary file not shown.
@@ -1,26 +1,33 @@
|
||||
#include "../base.h"
|
||||
#include "database.cpp"
|
||||
|
||||
#include "cart_normal.cpp"
|
||||
#include "cart_st.cpp"
|
||||
#include "cart_stdual.cpp"
|
||||
|
||||
#include "cart_file.cpp"
|
||||
#include "cart_header.cpp"
|
||||
|
||||
Cartridge cartridge;
|
||||
|
||||
#include "cart_normal.cpp"
|
||||
#include "cart_st.cpp"
|
||||
#include "cart_stdual.cpp"
|
||||
|
||||
void Cartridge::load_begin(uint cart_type) {
|
||||
void Cartridge::load_begin(CartridgeType cart_type) {
|
||||
if(loaded() == true)return;
|
||||
|
||||
info.type = cart_type;
|
||||
|
||||
info.srtc = false;
|
||||
info.sdd1 = false;
|
||||
info.c4 = false;
|
||||
info.dsp1 = false;
|
||||
info.dsp2 = false;
|
||||
info.obc1 = false;
|
||||
info.superfx = false;
|
||||
info.sa1 = false;
|
||||
info.srtc = false;
|
||||
info.sdd1 = false;
|
||||
info.c4 = false;
|
||||
info.dsp1 = false;
|
||||
info.dsp2 = false;
|
||||
info.dsp3 = false;
|
||||
info.dsp4 = false;
|
||||
info.obc1 = false;
|
||||
info.st010 = false;
|
||||
info.st011 = false;
|
||||
info.st018 = false;
|
||||
|
||||
info.dsp1_mapper = 0;
|
||||
|
||||
@@ -29,7 +36,6 @@ void Cartridge::load_begin(uint cart_type) {
|
||||
strcpy(info.name, "");
|
||||
strcpy(info.pcb, "");
|
||||
info.region = NTSC;
|
||||
info.cart_mmio = false;
|
||||
|
||||
info.rom_size = 0;
|
||||
info.ram_size = 0;
|
||||
@@ -92,15 +98,15 @@ bool Cartridge::load_end() {
|
||||
}
|
||||
|
||||
switch(info.type) {
|
||||
case CART_NORMAL: {
|
||||
case CartridgeNormal: {
|
||||
load_rom_normal();
|
||||
load_ram_normal();
|
||||
} break;
|
||||
case CART_ST: {
|
||||
case CartridgeSufamiTurbo: {
|
||||
load_rom_st();
|
||||
load_ram_st();
|
||||
} break;
|
||||
case CART_STDUAL: {
|
||||
case CartridgeSufamiTurboDual: {
|
||||
load_rom_stdual();
|
||||
load_ram_stdual();
|
||||
} break;
|
||||
@@ -117,19 +123,19 @@ bool Cartridge::unload() {
|
||||
r_mem->unload_cart();
|
||||
|
||||
switch(info.type) {
|
||||
case CART_NORMAL: {
|
||||
case CartridgeNormal: {
|
||||
save_ram_normal();
|
||||
} break;
|
||||
case CART_ST: {
|
||||
case CartridgeSufamiTurbo: {
|
||||
save_ram_st();
|
||||
} break;
|
||||
case CART_STDUAL: {
|
||||
case CartridgeSufamiTurboDual: {
|
||||
save_ram_stdual();
|
||||
} break;
|
||||
}
|
||||
|
||||
SafeFree(rom);
|
||||
SafeFree(ram);
|
||||
safe_free(rom);
|
||||
safe_free(ram);
|
||||
|
||||
if(cheat.count() > 0 || fexists(file.cheat_name) == true) {
|
||||
cheat.save(file.cheat_name);
|
||||
|
@@ -15,10 +15,10 @@ db_item dbi;
|
||||
|
||||
//
|
||||
|
||||
enum {
|
||||
CART_NORMAL,
|
||||
CART_ST,
|
||||
CART_STDUAL,
|
||||
enum CartridgeType {
|
||||
CartridgeNormal,
|
||||
CartridgeSufamiTurbo,
|
||||
CartridgeSufamiTurboDual,
|
||||
};
|
||||
|
||||
bool cart_loaded;
|
||||
@@ -33,7 +33,7 @@ enum {
|
||||
ROM_SIZE = 0x17,
|
||||
RAM_SIZE = 0x18,
|
||||
REGION = 0x19,
|
||||
LICENSE = 0x1a,
|
||||
COMPANY = 0x1a,
|
||||
VERSION = 0x1b,
|
||||
ICKSUM = 0x1c,
|
||||
CKSUM = 0x1e,
|
||||
@@ -78,15 +78,19 @@ struct {
|
||||
uint rom_size;
|
||||
uint ram_size;
|
||||
|
||||
//set to true for games that need cart MMIO mapping (c4, dsp-n, ...),
|
||||
//for games that map outside the standard MMIO range of $2000-$5fff
|
||||
bool cart_mmio;
|
||||
bool superfx;
|
||||
bool sa1;
|
||||
bool srtc;
|
||||
bool sdd1;
|
||||
bool c4;
|
||||
bool dsp1;
|
||||
bool dsp2;
|
||||
bool dsp3;
|
||||
bool dsp4;
|
||||
bool obc1;
|
||||
bool st010;
|
||||
bool st011;
|
||||
bool st018;
|
||||
|
||||
uint dsp1_mapper;
|
||||
|
||||
@@ -113,7 +117,7 @@ struct {
|
||||
void read_header();
|
||||
|
||||
bool loaded() { return cart_loaded; }
|
||||
void load_begin(uint cart_type);
|
||||
void load_begin(CartridgeType cart_type);
|
||||
void load(const char *rom_fn);
|
||||
bool load_end();
|
||||
bool unload();
|
||||
|
@@ -1,7 +1,19 @@
|
||||
#include "../reader/filereader.h"
|
||||
|
||||
#if defined(GZIP_SUPPORT)
|
||||
#include "../reader/gzreader.h"
|
||||
#include "../reader/zipreader.h"
|
||||
#endif
|
||||
|
||||
#if defined(JMA_SUPPORT)
|
||||
#include "../reader/jmareader.h"
|
||||
#endif
|
||||
|
||||
bool Cartridge::load_file(const char *fn, uint8 *&data, uint &size) {
|
||||
dprintf("* Loading \"%s\"...", fn);
|
||||
|
||||
if(fexists(fn) == false) {
|
||||
alert("Error: file '%s' not found!", fn);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -1,13 +1,4 @@
|
||||
void Cartridge::read_header() {
|
||||
info.srtc = false;
|
||||
info.sdd1 = false;
|
||||
info.c4 = false;
|
||||
info.dsp1 = false;
|
||||
info.dsp2 = false;
|
||||
info.obc1 = false;
|
||||
|
||||
info.dsp1_mapper = 0;
|
||||
|
||||
if(info.header_index == 0x7fc0 && info.rom_size >= 0x401000) {
|
||||
info.mapper = EXLOROM;
|
||||
strcpy(info.pcb, "UNL-EXLOROM");
|
||||
@@ -27,6 +18,16 @@ void Cartridge::read_header() {
|
||||
|
||||
uint8 mapper = rom[info.header_index + MAPPER];
|
||||
uint8 rom_type = rom[info.header_index + ROM_TYPE];
|
||||
uint8 company = rom[info.header_index + COMPANY];
|
||||
|
||||
if(mapper == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
|
||||
info.superfx = true;
|
||||
}
|
||||
|
||||
if(mapper == 0x23 && (rom_type == 0x34 || rom_type == 0x35)) {
|
||||
info.sa1 = true;
|
||||
}
|
||||
|
||||
if(mapper == 0x35 && rom_type == 0x55) {
|
||||
info.srtc = true;
|
||||
}
|
||||
@@ -43,7 +44,7 @@ uint8 rom_type = rom[info.header_index + ROM_TYPE];
|
||||
info.dsp1 = true;
|
||||
}
|
||||
|
||||
if(mapper == 0x30 && rom_type == 0x05) {
|
||||
if(mapper == 0x30 && rom_type == 0x05 && company != 0xb2) {
|
||||
info.dsp1 = true;
|
||||
}
|
||||
|
||||
@@ -65,11 +66,28 @@ uint8 rom_type = rom[info.header_index + ROM_TYPE];
|
||||
info.dsp2 = true;
|
||||
}
|
||||
|
||||
if(mapper == 0x30 && rom_type == 0x05 && company == 0xb2) {
|
||||
info.dsp3 = true;
|
||||
}
|
||||
|
||||
if(mapper == 0x30 && rom_type == 0x03) {
|
||||
info.dsp4 = true;
|
||||
}
|
||||
|
||||
if(mapper == 0x30 && rom_type == 0x25) {
|
||||
info.obc1 = true;
|
||||
}
|
||||
|
||||
info.cart_mmio = info.c4 | info.dsp1 | info.dsp2 | info.obc1;
|
||||
if(mapper == 0x30 && rom_type == 0xf6) {
|
||||
//TODO: both ST010 and ST011 share the same mapper + rom_type
|
||||
//need way to determine which is which
|
||||
//for now, default to supported ST010
|
||||
info.st010 = true;
|
||||
}
|
||||
|
||||
if(mapper == 0x30 && rom_type == 0xf5) {
|
||||
info.st018 = true;
|
||||
}
|
||||
|
||||
if(rom[info.header_index + RAM_SIZE] & 7) {
|
||||
info.ram_size = 1024 << (rom[info.header_index + RAM_SIZE] & 7);
|
||||
@@ -113,8 +131,8 @@ int32 score_lo = 0,
|
||||
if(rom[0x7fc0 + REGION] < 14)score_lo++;
|
||||
if(rom[0xffc0 + REGION] < 14)score_hi++;
|
||||
|
||||
if(rom[0x7fc0 + LICENSE] < 3)score_lo++;
|
||||
if(rom[0xffc0 + LICENSE] < 3)score_hi++;
|
||||
if(rom[0x7fc0 + COMPANY] < 3)score_lo++;
|
||||
if(rom[0xffc0 + COMPANY] < 3)score_hi++;
|
||||
|
||||
if(rom[0x7fc0 + RESH] & 0x80)score_lo += 2;
|
||||
if(rom[0xffc0 + RESH] & 0x80)score_hi += 2;
|
||||
|
@@ -20,21 +20,11 @@ uint offset = 0;
|
||||
info.crc32 = crc32_calculate(rom, info.rom_size);
|
||||
|
||||
if(read_database() == true) {
|
||||
info.srtc = false;
|
||||
info.sdd1 = false;
|
||||
info.c4 = false;
|
||||
info.dsp1 = false;
|
||||
info.dsp2 = false;
|
||||
info.obc1 = false;
|
||||
|
||||
info.dsp1_mapper = 0;
|
||||
|
||||
info.header_index = 0xffc0;
|
||||
info.mapper = PCB;
|
||||
strcpy(info.name, dbi.name);
|
||||
strcpy(info.pcb, dbi.pcb);
|
||||
info.region = NTSC;
|
||||
info.cart_mmio = false;
|
||||
|
||||
info.rom_size = dbi.rom;
|
||||
info.ram_size = dbi.ram;
|
||||
|
Binary file not shown.
@@ -106,6 +106,12 @@ pcb = "BSC-1A7M-10"
|
||||
rom = 24mbit
|
||||
ram = 512kbit
|
||||
|
||||
[0xcf98ddaa]
|
||||
name = "Super Mario World 2: Yoshi's Island (USA)"
|
||||
pcb = "SHVC-1CB5B-01"
|
||||
rom = 16mbit
|
||||
ram = 256kbit
|
||||
|
||||
[0x64a91e64]
|
||||
name = "Wanderers from Ys (USA) [!]"
|
||||
pcb = "SHVC-1A3B-12"
|
||||
|
@@ -53,9 +53,9 @@ db_item dbi;
|
||||
dbi.ram = 0;
|
||||
|
||||
for(int i = 1; i < count(line); i++) {
|
||||
uint pos;
|
||||
if(strpos(line[i], ";", pos) == true) {
|
||||
strset(line[i], pos, 0);
|
||||
int pos = strpos(line[i], ";");
|
||||
if(pos >= 0) {
|
||||
strptr(line[i])[pos] = 0;
|
||||
}
|
||||
|
||||
if(line[i] == "")continue;
|
||||
|
5
src/cc.bat
Normal file
5
src/cc.bat
Normal file
@@ -0,0 +1,5 @@
|
||||
::@make -r PLATFORM=win-mingw4-lui
|
||||
::@make -r PLATFORM=win-visualc-lui
|
||||
@make -r PLATFORM=win-visualc-lui GZIP_SUPPORT=true JMA_SUPPORT=true
|
||||
@move bsnes.exe ../bsnes.exe>nul
|
||||
@pause
|
@@ -1,4 +1,5 @@
|
||||
#include "../base.h"
|
||||
#include "../reader/filereader.h"
|
||||
|
||||
Cheat cheat;
|
||||
|
||||
@@ -276,7 +277,7 @@ uint8 *raw_data = rf.read();
|
||||
stringarray data, line;
|
||||
raw_data[rf.size()] = 0;
|
||||
strcpy(data, (char*)raw_data);
|
||||
SafeFree(raw_data);
|
||||
safe_free(raw_data);
|
||||
replace(data, "\r\n", "\n");
|
||||
|
||||
split(line, "\n", data);
|
||||
|
@@ -7,8 +7,6 @@
|
||||
|
||||
#include "../../base.h"
|
||||
|
||||
C4 *c4;
|
||||
|
||||
#include "c4data.cpp"
|
||||
#include "c4fn.cpp"
|
||||
#include "c4oam.cpp"
|
||||
|
@@ -93,4 +93,4 @@ public:
|
||||
C4();
|
||||
};
|
||||
|
||||
extern C4 *c4;
|
||||
extern C4 c4;
|
||||
|
@@ -1,7 +1,5 @@
|
||||
#include "../../base.h"
|
||||
|
||||
DSP1 *dsp1;
|
||||
|
||||
#include "dsp1emu.cpp"
|
||||
|
||||
void DSP1::init() {}
|
||||
|
@@ -15,4 +15,4 @@ public:
|
||||
void write(uint16 addr, uint8 data);
|
||||
};
|
||||
|
||||
extern DSP1 *dsp1;
|
||||
extern DSP1 dsp1;
|
||||
|
@@ -1,7 +1,5 @@
|
||||
#include "../../base.h"
|
||||
|
||||
DSP2 *dsp2;
|
||||
|
||||
#include "dsp2_op.cpp"
|
||||
|
||||
void DSP2::init() {}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
class DSP2 {
|
||||
public:
|
||||
class DSP2 { public:
|
||||
struct {
|
||||
bool waiting_for_command;
|
||||
uint command;
|
||||
@@ -40,4 +39,4 @@ struct {
|
||||
~DSP2();
|
||||
};
|
||||
|
||||
extern DSP2 *dsp2;
|
||||
extern DSP2 dsp2;
|
||||
|
33
src/chip/dsp3/dsp3.cpp
Normal file
33
src/chip/dsp3/dsp3.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "../../base.h"
|
||||
|
||||
namespace DSP3i {
|
||||
#define bool8 bool
|
||||
#include "dsp3emu.c"
|
||||
#undef bool8
|
||||
};
|
||||
|
||||
void DSP3::init() {
|
||||
}
|
||||
|
||||
void DSP3::enable() {
|
||||
}
|
||||
|
||||
void DSP3::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void DSP3::reset() {
|
||||
DSP3i::DSP3_Reset();
|
||||
}
|
||||
|
||||
uint8 DSP3::read(uint16 addr) {
|
||||
DSP3i::dsp3_address = addr;
|
||||
DSP3i::DSP3GetByte();
|
||||
return DSP3i::dsp3_byte;
|
||||
}
|
||||
|
||||
void DSP3::write(uint16 addr, uint8 data) {
|
||||
DSP3i::dsp3_address = addr;
|
||||
DSP3i::dsp3_byte = data;
|
||||
DSP3i::DSP3SetByte();
|
||||
}
|
11
src/chip/dsp3/dsp3.h
Normal file
11
src/chip/dsp3/dsp3.h
Normal file
@@ -0,0 +1,11 @@
|
||||
class DSP3 { public:
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 read (uint16 addr);
|
||||
void write(uint16 addr, uint8 data);
|
||||
};
|
||||
|
||||
extern DSP3 dsp3;
|
1142
src/chip/dsp3/dsp3emu.c
Normal file
1142
src/chip/dsp3/dsp3emu.c
Normal file
File diff suppressed because it is too large
Load Diff
51
src/chip/dsp4/dsp4.cpp
Normal file
51
src/chip/dsp4/dsp4.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
#include "../../base.h"
|
||||
|
||||
namespace DSP4i {
|
||||
inline uint16 READ_WORD(uint8 *addr) {
|
||||
return (addr[0]) + (addr[1] << 8);
|
||||
}
|
||||
|
||||
inline uint32 READ_DWORD(uint8 *addr) {
|
||||
return (addr[0]) + (addr[1] << 8) + (addr[2] << 16) + (addr[3] << 24);
|
||||
}
|
||||
|
||||
inline void WRITE_WORD(uint8 *addr, uint16 data) {
|
||||
addr[0] = data;
|
||||
addr[1] = data >> 8;
|
||||
}
|
||||
|
||||
#define bool8 bool
|
||||
#include "dsp4emu.c"
|
||||
#undef bool8
|
||||
};
|
||||
|
||||
void DSP4::init() {
|
||||
}
|
||||
|
||||
void DSP4::enable() {
|
||||
}
|
||||
|
||||
void DSP4::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void DSP4::reset() {
|
||||
DSP4i::InitDSP4();
|
||||
}
|
||||
|
||||
uint8 DSP4::read(uint16 addr) {
|
||||
if(addr < 0xc000) {
|
||||
DSP4i::dsp4_address = addr;
|
||||
DSP4i::DSP4GetByte();
|
||||
return DSP4i::dsp4_byte;
|
||||
}
|
||||
return 0x80;
|
||||
}
|
||||
|
||||
void DSP4::write(uint16 addr, uint8 data) {
|
||||
if(addr < 0xc000) {
|
||||
DSP4i::dsp4_address = addr;
|
||||
DSP4i::dsp4_byte = data;
|
||||
DSP4i::DSP4SetByte();
|
||||
}
|
||||
}
|
11
src/chip/dsp4/dsp4.h
Normal file
11
src/chip/dsp4/dsp4.h
Normal file
@@ -0,0 +1,11 @@
|
||||
class DSP4 { public:
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 read (uint16 addr);
|
||||
void write(uint16 addr, uint8 data);
|
||||
};
|
||||
|
||||
extern DSP4 dsp4;
|
2146
src/chip/dsp4/dsp4emu.c
Normal file
2146
src/chip/dsp4/dsp4emu.c
Normal file
File diff suppressed because it is too large
Load Diff
108
src/chip/dsp4/dsp4emu.h
Normal file
108
src/chip/dsp4/dsp4emu.h
Normal file
@@ -0,0 +1,108 @@
|
||||
//DSP-4 emulator code
|
||||
//Copyright (c) 2004-2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden
|
||||
|
||||
#ifndef DSP4EMU_H
|
||||
#define DSP4EMU_H
|
||||
|
||||
#undef TRUE
|
||||
#undef FALSE
|
||||
#define TRUE true
|
||||
#define FALSE false
|
||||
|
||||
struct DSP4_t
|
||||
{
|
||||
bool8 waiting4command;
|
||||
bool8 half_command;
|
||||
uint16 command;
|
||||
uint32 in_count;
|
||||
uint32 in_index;
|
||||
uint32 out_count;
|
||||
uint32 out_index;
|
||||
uint8 parameters[512];
|
||||
uint8 output[512];
|
||||
};
|
||||
|
||||
extern struct DSP4_t DSP4;
|
||||
|
||||
struct DSP4_vars_t
|
||||
{
|
||||
// op control
|
||||
int8 DSP4_Logic; // controls op flow
|
||||
|
||||
|
||||
// projection format
|
||||
int16 lcv; // loop-control variable
|
||||
int16 distance; // z-position into virtual world
|
||||
int16 raster; // current raster line
|
||||
int16 segments; // number of raster lines drawn
|
||||
|
||||
// 1.15.16 or 1.15.0 [sign, integer, fraction]
|
||||
int32 world_x; // line of x-projection in world
|
||||
int32 world_y; // line of y-projection in world
|
||||
int32 world_dx; // projection line x-delta
|
||||
int32 world_dy; // projection line y-delta
|
||||
int16 world_ddx; // x-delta increment
|
||||
int16 world_ddy; // y-delta increment
|
||||
int32 world_xenv; // world x-shaping factor
|
||||
int16 world_yofs; // world y-vertical scroll
|
||||
|
||||
int16 view_x1; // current viewer-x
|
||||
int16 view_y1; // current viewer-y
|
||||
int16 view_x2; // future viewer-x
|
||||
int16 view_y2; // future viewer-y
|
||||
int16 view_dx; // view x-delta factor
|
||||
int16 view_dy; // view y-delta factor
|
||||
int16 view_xofs1; // current viewer x-vertical scroll
|
||||
int16 view_yofs1; // current viewer y-vertical scroll
|
||||
int16 view_xofs2; // future viewer x-vertical scroll
|
||||
int16 view_yofs2; // future viewer y-vertical scroll
|
||||
int16 view_yofsenv; // y-scroll shaping factor
|
||||
int16 view_turnoff_x; // road turnoff data
|
||||
int16 view_turnoff_dx; // road turnoff delta factor
|
||||
|
||||
|
||||
// drawing area
|
||||
|
||||
int16 viewport_cx; // x-center of viewport window
|
||||
int16 viewport_cy; // y-center of render window
|
||||
int16 viewport_left; // x-left of viewport
|
||||
int16 viewport_right; // x-right of viewport
|
||||
int16 viewport_top; // y-top of viewport
|
||||
int16 viewport_bottom; // y-bottom of viewport
|
||||
|
||||
|
||||
// sprite structure
|
||||
|
||||
int16 sprite_x; // projected x-pos of sprite
|
||||
int16 sprite_y; // projected y-pos of sprite
|
||||
int16 sprite_attr; // obj attributes
|
||||
bool8 sprite_size; // sprite size: 8x8 or 16x16
|
||||
int16 sprite_clipy; // visible line to clip pixels off
|
||||
int16 sprite_count;
|
||||
|
||||
// generic projection variables designed for
|
||||
// two solid polygons + two polygon sides
|
||||
|
||||
int16 poly_clipLf[2][2]; // left clip boundary
|
||||
int16 poly_clipRt[2][2]; // right clip boundary
|
||||
int16 poly_ptr[2][2]; // HDMA structure pointers
|
||||
int16 poly_raster[2][2]; // current raster line below horizon
|
||||
int16 poly_top[2][2]; // top clip boundary
|
||||
int16 poly_bottom[2][2]; // bottom clip boundary
|
||||
int16 poly_cx[2][2]; // center for left/right points
|
||||
int16 poly_start[2]; // current projection points
|
||||
int16 poly_plane[2]; // previous z-plane distance
|
||||
|
||||
|
||||
// OAM
|
||||
int16 OAM_attr[16]; // OAM (size,MSB) data
|
||||
int16 OAM_index; // index into OAM table
|
||||
int16 OAM_bits; // offset into OAM table
|
||||
|
||||
int16 OAM_RowMax; // maximum number of tiles per 8 aligned pixels (row)
|
||||
int16 OAM_Row[32]; // current number of tiles per row
|
||||
};
|
||||
|
||||
extern struct DSP4_vars_t DSP4_vars;
|
||||
|
||||
#endif
|
@@ -1,7 +1,5 @@
|
||||
#include "../../base.h"
|
||||
|
||||
OBC1 *obc1;
|
||||
|
||||
void OBC1::init() {}
|
||||
void OBC1::enable() {}
|
||||
|
||||
|
@@ -17,4 +17,4 @@ struct {
|
||||
~OBC1();
|
||||
};
|
||||
|
||||
extern OBC1 *obc1;
|
||||
extern OBC1 obc1;
|
||||
|
@@ -1,7 +1,5 @@
|
||||
#include "../../base.h"
|
||||
|
||||
SDD1 *sdd1;
|
||||
|
||||
#include "sdd1emu.cpp"
|
||||
|
||||
void SDD1::init() {}
|
||||
@@ -43,10 +41,10 @@ uint8 b = (addr >> 16) & 0xff;
|
||||
uint8 SDD1::mmio_read(uint16 addr) {
|
||||
switch(addr) {
|
||||
//>>20 == 0x100000 == 1mb
|
||||
case 0x4804:return (sdd1.index[0] >> 20) & 7;
|
||||
case 0x4805:return (sdd1.index[1] >> 20) & 7;
|
||||
case 0x4806:return (sdd1.index[2] >> 20) & 7;
|
||||
case 0x4807:return (sdd1.index[3] >> 20) & 7;
|
||||
case 0x4804: return (sdd1.index[0] >> 20) & 7;
|
||||
case 0x4805: return (sdd1.index[1] >> 20) & 7;
|
||||
case 0x4806: return (sdd1.index[2] >> 20) & 7;
|
||||
case 0x4807: return (sdd1.index[3] >> 20) & 7;
|
||||
}
|
||||
|
||||
return r_cpu->regs.mdr;
|
||||
@@ -60,10 +58,10 @@ void SDD1::mmio_write(uint16 addr, uint8 data) {
|
||||
}
|
||||
break;
|
||||
//<<20 == 0x100000 == 1mb
|
||||
case 0x4804:sdd1.index[0] = (data & 7) << 20;break;
|
||||
case 0x4805:sdd1.index[1] = (data & 7) << 20;break;
|
||||
case 0x4806:sdd1.index[2] = (data & 7) << 20;break;
|
||||
case 0x4807:sdd1.index[3] = (data & 7) << 20;break;
|
||||
case 0x4804: sdd1.index[0] = (data & 7) << 20; break;
|
||||
case 0x4805: sdd1.index[1] = (data & 7) << 20; break;
|
||||
case 0x4806: sdd1.index[2] = (data & 7) << 20; break;
|
||||
case 0x4807: sdd1.index[3] = (data & 7) << 20; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -29,4 +29,4 @@ struct {
|
||||
SDD1();
|
||||
};
|
||||
|
||||
extern SDD1 *sdd1;
|
||||
extern SDD1 sdd1;
|
||||
|
@@ -28,6 +28,7 @@ understood.
|
||||
|
||||
************************************************************************/
|
||||
|
||||
typedef uint8_t bool8;
|
||||
|
||||
class SDD1_IM { //Input Manager
|
||||
|
||||
|
@@ -52,8 +52,6 @@
|
||||
|
||||
#include "../../base.h"
|
||||
|
||||
SRTC *srtc;
|
||||
|
||||
void SRTC::set_time() {
|
||||
time_t rawtime;
|
||||
tm *t;
|
||||
|
@@ -49,4 +49,4 @@ struct {
|
||||
SRTC();
|
||||
};
|
||||
|
||||
extern SRTC *srtc;
|
||||
extern SRTC srtc;
|
||||
|
84
src/chip/st010/st010.cpp
Normal file
84
src/chip/st010/st010.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#include "../../base.h"
|
||||
#include "st010_data.h"
|
||||
#include "st010_op.cpp"
|
||||
|
||||
int16 ST010::sin(int16 theta) {
|
||||
return sin_table[(theta >> 8) & 0xff];
|
||||
}
|
||||
|
||||
int16 ST010::cos(int16 theta) {
|
||||
return sin_table[((theta + 0x4000) >> 8) & 0xff];
|
||||
}
|
||||
|
||||
uint8 ST010::readb(uint16 addr) {
|
||||
return ram[addr & 0xfff];
|
||||
}
|
||||
|
||||
uint16 ST010::readw(uint16 addr) {
|
||||
return (readb(addr + 0) << 0) |
|
||||
(readb(addr + 1) << 8);
|
||||
}
|
||||
|
||||
uint32 ST010::readd(uint16 addr) {
|
||||
return (readb(addr + 0) << 0) |
|
||||
(readb(addr + 1) << 8) |
|
||||
(readb(addr + 2) << 16) |
|
||||
(readb(addr + 3) << 24);
|
||||
}
|
||||
|
||||
void ST010::writeb(uint16 addr, uint8 data) {
|
||||
ram[addr & 0xfff] = data;
|
||||
}
|
||||
|
||||
void ST010::writew(uint16 addr, uint16 data) {
|
||||
writeb(addr + 0, data);
|
||||
writeb(addr + 1, data >> 8);
|
||||
}
|
||||
|
||||
void ST010::writed(uint16 addr, uint32 data) {
|
||||
writeb(addr + 0, data);
|
||||
writeb(addr + 1, data >> 8);
|
||||
writeb(addr + 2, data >> 16);
|
||||
writeb(addr + 3, data >> 24);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void ST010::init() {
|
||||
}
|
||||
|
||||
void ST010::enable() {
|
||||
}
|
||||
|
||||
void ST010::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void ST010::reset() {
|
||||
memset(ram, 0x00, sizeof ram);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
uint8 ST010::read(uint16 addr) {
|
||||
return readb(addr);
|
||||
}
|
||||
|
||||
void ST010::write(uint16 addr, uint8 data) {
|
||||
writeb(addr, data);
|
||||
|
||||
if(addr == 0x0021 && data & 0x80) {
|
||||
switch(ram[0x0020]) {
|
||||
case 0x01: op_01(); break;
|
||||
case 0x02: op_02(); break;
|
||||
case 0x03: op_03(); break;
|
||||
case 0x04: op_04(); break;
|
||||
case 0x05: op_05(); break;
|
||||
case 0x06: op_06(); break;
|
||||
case 0x07: op_07(); break;
|
||||
case 0x08: op_08(); break;
|
||||
}
|
||||
|
||||
ram[0x0021] &= ~0x80;
|
||||
}
|
||||
}
|
40
src/chip/st010/st010.h
Normal file
40
src/chip/st010/st010.h
Normal file
@@ -0,0 +1,40 @@
|
||||
class ST010 { public:
|
||||
uint8 ram[0x1000];
|
||||
static const int16 sin_table[256];
|
||||
static const int16 mode7_scale[176];
|
||||
static const uint8 arctan[32][32];
|
||||
//interfaces to sin table
|
||||
int16 sin(int16 theta);
|
||||
int16 cos(int16 theta);
|
||||
|
||||
//interfaces to ram buffer
|
||||
uint8 readb (uint16 addr);
|
||||
uint16 readw (uint16 addr);
|
||||
uint32 readd (uint16 addr);
|
||||
void writeb(uint16 addr, uint8 data);
|
||||
void writew(uint16 addr, uint16 data);
|
||||
void writed(uint16 addr, uint32 data);
|
||||
|
||||
//opcodes
|
||||
void op_01();
|
||||
void op_02();
|
||||
void op_03();
|
||||
void op_04();
|
||||
void op_05();
|
||||
void op_06();
|
||||
void op_07();
|
||||
void op_08();
|
||||
|
||||
void op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta);
|
||||
|
||||
//base
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 read (uint16 addr);
|
||||
void write(uint16 addr, uint8 data);
|
||||
};
|
||||
|
||||
extern ST010 st010;
|
126
src/chip/st010/st010_data.h
Normal file
126
src/chip/st010/st010_data.h
Normal file
@@ -0,0 +1,126 @@
|
||||
const int16 ST010::sin_table[256] = {
|
||||
0x0000, 0x0324, 0x0648, 0x096a, 0x0c8c, 0x0fab, 0x12c8, 0x15e2,
|
||||
0x18f9, 0x1c0b, 0x1f1a, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11,
|
||||
0x30fb, 0x33df, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a,
|
||||
0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842,
|
||||
0x5a82, 0x5cb3, 0x5ed7, 0x60eb, 0x62f1, 0x64e8, 0x66cf, 0x68a6,
|
||||
0x6a6d, 0x6c23, 0x6dc9, 0x6f5e, 0x70e2, 0x7254, 0x73b5, 0x7504,
|
||||
0x7641, 0x776b, 0x7884, 0x7989, 0x7a7c, 0x7b5c, 0x7c29, 0x7ce3,
|
||||
0x7d89, 0x7e1d, 0x7e9c, 0x7f09, 0x7f61, 0x7fa6, 0x7fd8, 0x7ff5,
|
||||
0x7fff, 0x7ff5, 0x7fd8, 0x7fa6, 0x7f61, 0x7f09, 0x7e9c, 0x7e1d,
|
||||
0x7d89, 0x7ce3, 0x7c29, 0x7b5c, 0x7a7c, 0x7989, 0x7884, 0x776b,
|
||||
0x7641, 0x7504, 0x73b5, 0x7254, 0x70e2, 0x6f5e, 0x6dc9, 0x6c23,
|
||||
0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f1, 0x60eb, 0x5ed7, 0x5cb3,
|
||||
0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4,
|
||||
0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33df,
|
||||
0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f1a, 0x1c0b,
|
||||
0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8c, 0x096a, 0x0648, 0x0324,
|
||||
0x0000, -0x0324, -0x0648, -0x096b, -0x0c8c, -0x0fab, -0x12c8, -0x15e2,
|
||||
-0x18f9, -0x1c0b, -0x1f1a, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11,
|
||||
-0x30fb, -0x33df, -0x36ba, -0x398d, -0x3c56, -0x3f17, -0x41ce, -0x447a,
|
||||
-0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842,
|
||||
-0x5a82, -0x5cb3, -0x5ed7, -0x60ec, -0x62f1, -0x64e8, -0x66cf, -0x68a6,
|
||||
-0x6a6d, -0x6c23, -0x6dc9, -0x6f5e, -0x70e2, -0x7254, -0x73b5, -0x7504,
|
||||
-0x7641, -0x776b, -0x7884, -0x7989, -0x7a7c, -0x7b5c, -0x7c29, -0x7ce3,
|
||||
-0x7d89, -0x7e1d, -0x7e9c, -0x7f09, -0x7f61, -0x7fa6, -0x7fd8, -0x7ff5,
|
||||
-0x7fff, -0x7ff5, -0x7fd8, -0x7fa6, -0x7f61, -0x7f09, -0x7e9c, -0x7e1d,
|
||||
-0x7d89, -0x7ce3, -0x7c29, -0x7b5c, -0x7a7c, -0x7989, -0x7883, -0x776b,
|
||||
-0x7641, -0x7504, -0x73b5, -0x7254, -0x70e2, -0x6f5e, -0x6dc9, -0x6c23,
|
||||
-0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f1, -0x60eb, -0x5ed7, -0x5cb3,
|
||||
-0x5a82, -0x5842, -0x55f5, -0x539a, -0x5133, -0x4ebf, -0x4c3f, -0x49b3,
|
||||
-0x471c, -0x447a, -0x41cd, -0x3f17, -0x3c56, -0x398c, -0x36b9, -0x33de,
|
||||
-0x30fb, -0x2e10, -0x2b1f, -0x2826, -0x2527, -0x2223, -0x1f19, -0x1c0b,
|
||||
-0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324
|
||||
};
|
||||
|
||||
const int16 ST010::mode7_scale[176] = {
|
||||
0x0380, 0x0325, 0x02da, 0x029c, 0x0268, 0x023b, 0x0215, 0x01f3,
|
||||
0x01d5, 0x01bb, 0x01a3, 0x018e, 0x017b, 0x016a, 0x015a, 0x014b,
|
||||
0x013e, 0x0132, 0x0126, 0x011c, 0x0112, 0x0109, 0x0100, 0x00f8,
|
||||
0x00f0, 0x00e9, 0x00e3, 0x00dc, 0x00d6, 0x00d1, 0x00cb, 0x00c6,
|
||||
0x00c1, 0x00bd, 0x00b8, 0x00b4, 0x00b0, 0x00ac, 0x00a8, 0x00a5,
|
||||
0x00a2, 0x009e, 0x009b, 0x0098, 0x0095, 0x0093, 0x0090, 0x008d,
|
||||
0x008b, 0x0088, 0x0086, 0x0084, 0x0082, 0x0080, 0x007e, 0x007c,
|
||||
0x007a, 0x0078, 0x0076, 0x0074, 0x0073, 0x0071, 0x006f, 0x006e,
|
||||
0x006c, 0x006b, 0x0069, 0x0068, 0x0067, 0x0065, 0x0064, 0x0063,
|
||||
0x0062, 0x0060, 0x005f, 0x005e, 0x005d, 0x005c, 0x005b, 0x005a,
|
||||
0x0059, 0x0058, 0x0057, 0x0056, 0x0055, 0x0054, 0x0053, 0x0052,
|
||||
0x0051, 0x0051, 0x0050, 0x004f, 0x004e, 0x004d, 0x004d, 0x004c,
|
||||
0x004b, 0x004b, 0x004a, 0x0049, 0x0048, 0x0048, 0x0047, 0x0047,
|
||||
0x0046, 0x0045, 0x0045, 0x0044, 0x0044, 0x0043, 0x0042, 0x0042,
|
||||
0x0041, 0x0041, 0x0040, 0x0040, 0x003f, 0x003f, 0x003e, 0x003e,
|
||||
0x003d, 0x003d, 0x003c, 0x003c, 0x003b, 0x003b, 0x003a, 0x003a,
|
||||
0x003a, 0x0039, 0x0039, 0x0038, 0x0038, 0x0038, 0x0037, 0x0037,
|
||||
0x0036, 0x0036, 0x0036, 0x0035, 0x0035, 0x0035, 0x0034, 0x0034,
|
||||
0x0034, 0x0033, 0x0033, 0x0033, 0x0032, 0x0032, 0x0032, 0x0031,
|
||||
0x0031, 0x0031, 0x0030, 0x0030, 0x0030, 0x0030, 0x002f, 0x002f,
|
||||
0x002f, 0x002e, 0x002e, 0x002e, 0x002e, 0x002d, 0x002d, 0x002d,
|
||||
0x002d, 0x002c, 0x002c, 0x002c, 0x002c, 0x002b, 0x002b, 0x002b
|
||||
};
|
||||
|
||||
const uint8 ST010::arctan[32][32] = {
|
||||
{ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
|
||||
{ 0x80, 0xa0, 0xad, 0xb3, 0xb6, 0xb8, 0xb9, 0xba, 0xbb, 0xbb, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd,
|
||||
0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf },
|
||||
{ 0x80, 0x93, 0xa0, 0xa8, 0xad, 0xb0, 0xb3, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xbb,
|
||||
0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd },
|
||||
{ 0x80, 0x8d, 0x98, 0xa0, 0xa6, 0xaa, 0xad, 0xb0, 0xb1, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb7, 0xb8,
|
||||
0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc },
|
||||
{ 0x80, 0x8a, 0x93, 0x9a, 0xa0, 0xa5, 0xa8, 0xab, 0xad, 0xaf, 0xb0, 0xb2, 0xb3, 0xb4, 0xb5, 0xb5,
|
||||
0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb },
|
||||
{ 0x80, 0x88, 0x90, 0x96, 0x9b, 0xa0, 0xa4, 0xa7, 0xa9, 0xab, 0xad, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
|
||||
0xb4, 0xb4, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9 },
|
||||
{ 0x80, 0x87, 0x8d, 0x93, 0x98, 0x9c, 0xa0, 0xa3, 0xa6, 0xa8, 0xaa, 0xac, 0xad, 0xae, 0xb0, 0xb0,
|
||||
0xb1, 0xb2, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8 },
|
||||
{ 0x80, 0x86, 0x8b, 0x90, 0x95, 0x99, 0x9d, 0xa0, 0xa3, 0xa5, 0xa7, 0xa9, 0xaa, 0xac, 0xad, 0xae,
|
||||
0xaf, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7 },
|
||||
{ 0x80, 0x85, 0x8a, 0x8f, 0x93, 0x97, 0x9a, 0x9d, 0xa0, 0xa2, 0xa5, 0xa6, 0xa8, 0xaa, 0xab, 0xac,
|
||||
0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, 0xb5 },
|
||||
{ 0x80, 0x85, 0x89, 0x8d, 0x91, 0x95, 0x98, 0x9b, 0x9e, 0xa0, 0xa0, 0xa4, 0xa6, 0xa7, 0xa9, 0xaa,
|
||||
0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb4 },
|
||||
{ 0x80, 0x84, 0x88, 0x8c, 0x90, 0x93, 0x96, 0x99, 0x9b, 0x9e, 0xa0, 0xa2, 0xa4, 0xa5, 0xa7, 0xa8,
|
||||
0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3 },
|
||||
{ 0x80, 0x84, 0x87, 0x8b, 0x8e, 0x91, 0x94, 0x97, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5, 0xa6,
|
||||
0xa7, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2 },
|
||||
{ 0x80, 0x83, 0x87, 0x8a, 0x8d, 0x90, 0x93, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5,
|
||||
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1 },
|
||||
{ 0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x94, 0x96, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa2, 0xa3,
|
||||
0xa4, 0xa5, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xaf, 0xb0 },
|
||||
{ 0x80, 0x83, 0x86, 0x89, 0x8b, 0x8e, 0x90, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa1,
|
||||
0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac, 0xad, 0xad, 0xae, 0xae, 0xaf },
|
||||
{ 0x80, 0x83, 0x85, 0x88, 0x8b, 0x8d, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9b, 0x9d, 0x9f, 0xa0,
|
||||
0xa1, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xab, 0xab, 0xac, 0xad, 0xad, 0xae },
|
||||
{ 0x80, 0x83, 0x85, 0x88, 0x8a, 0x8c, 0x8f, 0x91, 0x93, 0x95, 0x97, 0x99, 0x9a, 0x9c, 0x9d, 0x9f,
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa5, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xab, 0xac, 0xad },
|
||||
{ 0x80, 0x82, 0x85, 0x87, 0x89, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x97, 0x99, 0x9b, 0x9c, 0x9d,
|
||||
0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac },
|
||||
{ 0x80, 0x82, 0x85, 0x87, 0x89, 0x8b, 0x8d, 0x8f, 0x91, 0x93, 0x95, 0x96, 0x98, 0x99, 0x9b, 0x9c,
|
||||
0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab },
|
||||
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x9a, 0x9b,
|
||||
0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa },
|
||||
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x99, 0x9a,
|
||||
0x9b, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9 },
|
||||
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8f, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x99,
|
||||
0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8 },
|
||||
{ 0x80, 0x82, 0x84, 0x86, 0x87, 0x89, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x98,
|
||||
0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7 },
|
||||
{ 0x80, 0x82, 0x84, 0x85, 0x87, 0x89, 0x8a, 0x8c, 0x8e, 0x8f, 0x91, 0x92, 0x94, 0x95, 0x96, 0x98,
|
||||
0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6 },
|
||||
{ 0x80, 0x82, 0x83, 0x85, 0x87, 0x88, 0x8a, 0x8c, 0x8d, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5 },
|
||||
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x94, 0x95, 0x96,
|
||||
0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa4 },
|
||||
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x89, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x95,
|
||||
0x96, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4 },
|
||||
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x87, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93, 0x95,
|
||||
0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2, 0xa3 },
|
||||
{ 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x89, 0x8a, 0x8b, 0x8d, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94,
|
||||
0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2 },
|
||||
{ 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x88, 0x8a, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93,
|
||||
0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1, 0xa1 },
|
||||
{ 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8b, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93,
|
||||
0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1 },
|
||||
{ 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92,
|
||||
0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0 }
|
||||
};
|
257
src/chip/st010/st010_op.cpp
Normal file
257
src/chip/st010/st010_op.cpp
Normal file
@@ -0,0 +1,257 @@
|
||||
//ST-010 emulation code - Copyright (C) 2003 The Dumper, Matthew Kendora, Overload, Feather
|
||||
//bsnes port - Copyright (C) 2007 byuu
|
||||
|
||||
void ST010::op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta) {
|
||||
if((x0 < 0) && (y0 < 0)) {
|
||||
x1 = -x0;
|
||||
y1 = -y0;
|
||||
quadrant = -0x8000;
|
||||
} else if(x0 < 0) {
|
||||
x1 = y0;
|
||||
y1 = -x0;
|
||||
quadrant = -0x4000;
|
||||
} else if(y0 < 0) {
|
||||
x1 = -y0;
|
||||
y1 = x0;
|
||||
quadrant = 0x4000;
|
||||
} else {
|
||||
x1 = x0;
|
||||
y1 = y0;
|
||||
quadrant = 0x0000;
|
||||
}
|
||||
|
||||
while((x1 > 0x1f) || (y1 > 0x1f)) {
|
||||
if(x1 > 1) { x1 >>= 1; }
|
||||
if(y1 > 1) { y1 >>= 1; }
|
||||
}
|
||||
|
||||
if(y1 == 0) { quadrant += 0x4000; }
|
||||
|
||||
theta = (arctan[y1][x1] << 8) ^ quadrant;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void ST010::op_01() {
|
||||
int16 x0 = readw(0x0000);
|
||||
int16 y0 = readw(0x0002);
|
||||
int16 x1, y1, quadrant, theta;
|
||||
|
||||
op_01(x0, y0, x1, y1, quadrant, theta);
|
||||
|
||||
writew(0x0000, x1);
|
||||
writew(0x0002, y1);
|
||||
writew(0x0004, quadrant);
|
||||
//writew(0x0006, y0); //Overload's docs note this write occurs, SNES9x disagrees
|
||||
writew(0x0010, theta);
|
||||
}
|
||||
|
||||
void ST010::op_02() {
|
||||
int16 positions = readw(0x0024);
|
||||
uint16 *places = (uint16*)(ram + 0x0040);
|
||||
uint16 *drivers = (uint16*)(ram + 0x0080);
|
||||
|
||||
bool sorted;
|
||||
uint16 temp;
|
||||
if(positions > 1) {
|
||||
do {
|
||||
sorted = true;
|
||||
for(int i = 0; i < positions - 1; i++) {
|
||||
if(places[i] < places[i + 1]) {
|
||||
temp = places[i + 1];
|
||||
places[i + 1] = places[i];
|
||||
places[i] = temp;
|
||||
|
||||
temp = drivers[i + 1];
|
||||
drivers[i + 1] = drivers[i];
|
||||
drivers[i] = temp;
|
||||
|
||||
sorted = false;
|
||||
}
|
||||
}
|
||||
positions--;
|
||||
} while(!sorted);
|
||||
}
|
||||
}
|
||||
|
||||
void ST010::op_03() {
|
||||
int16 x0 = readw(0x0000);
|
||||
int16 y0 = readw(0x0002);
|
||||
int16 multiplier = readw(0x0004);
|
||||
int32 x1, y1;
|
||||
|
||||
x1 = x0 * multiplier << 1;
|
||||
y1 = y0 * multiplier << 1;
|
||||
|
||||
writed(0x0010, x1);
|
||||
writed(0x0014, y1);
|
||||
}
|
||||
|
||||
void ST010::op_04() {
|
||||
int16 x = readw(0x0000);
|
||||
int16 y = readw(0x0002);
|
||||
int16 square;
|
||||
//calculate the vector length of (x,y)
|
||||
square = (int16)sqrt((double)(y * y + x * x));
|
||||
|
||||
writew(0x0010, square);
|
||||
}
|
||||
|
||||
void ST010::op_05() {
|
||||
int32 dx, dy;
|
||||
int16 a1, b1, c1;
|
||||
uint16 o1;
|
||||
bool wrap = false;
|
||||
|
||||
//target (x,y) coordinates
|
||||
int16 ypos_max = readw(0x00c0);
|
||||
int16 xpos_max = readw(0x00c2);
|
||||
|
||||
//current coordinates and direction
|
||||
int32 ypos = readd(0x00c4);
|
||||
int32 xpos = readd(0x00c8);
|
||||
uint16 rot = readw(0x00cc);
|
||||
|
||||
//physics
|
||||
uint16 speed = readw(0x00d4);
|
||||
uint16 accel = readw(0x00d6);
|
||||
uint16 speed_max = readw(0x00d8);
|
||||
|
||||
//special condition acknowledgement
|
||||
int16 system = readw(0x00da);
|
||||
int16 flags = readw(0x00dc);
|
||||
|
||||
//new target coordinates
|
||||
int16 ypos_new = readw(0x00de);
|
||||
int16 xpos_new = readw(0x00e0);
|
||||
|
||||
//mask upper bit
|
||||
xpos_new &= 0x7fff;
|
||||
|
||||
//get the current distance
|
||||
dx = xpos_max - (xpos >> 16);
|
||||
dy = ypos_max - (ypos >> 16);
|
||||
|
||||
//quirk: clear and move in9
|
||||
writew(0x00d2, 0xffff);
|
||||
writew(0x00da, 0x0000);
|
||||
|
||||
//grab the target angle
|
||||
op_01(dy, dx, a1, b1, c1, (int16&)o1);
|
||||
|
||||
//check for wrapping
|
||||
if(abs(o1 - rot) > 0x8000) {
|
||||
o1 += 0x8000;
|
||||
rot += 0x8000;
|
||||
wrap = true;
|
||||
}
|
||||
|
||||
uint16 old_speed = speed;
|
||||
|
||||
//special case
|
||||
if(abs(o1 - rot) == 0x8000) {
|
||||
speed = 0x100;
|
||||
}
|
||||
|
||||
//slow down for sharp curves
|
||||
else if(abs(o1 - rot) >= 0x1000) {
|
||||
uint32 slow = abs(o1 - rot);
|
||||
slow >>= 4; //scaling
|
||||
speed -= slow;
|
||||
}
|
||||
|
||||
//otherwise accelerate
|
||||
else {
|
||||
speed += accel;
|
||||
if(speed > speed_max) {
|
||||
speed = speed_max; //clip speed
|
||||
}
|
||||
}
|
||||
|
||||
//prevent negative/positive overflow
|
||||
if(abs(old_speed - speed) > 0x8000) {
|
||||
if(old_speed < speed) { speed = 0; }
|
||||
else speed = 0xff00;
|
||||
}
|
||||
|
||||
//adjust direction by so many degrees
|
||||
//be careful of negative adjustments
|
||||
if((o1 > rot && (o1 - rot) > 0x80) || (o1 < rot && (rot - o1) >= 0x80)) {
|
||||
if(o1 < rot) { rot -= 0x280; }
|
||||
else if(o1 > rot) { rot += 0x280; }
|
||||
}
|
||||
|
||||
//turn of wrapping
|
||||
if(wrap) { rot -= 0x8000; }
|
||||
|
||||
//now check the distances (store for later)
|
||||
dx = (xpos_max << 16) - xpos;
|
||||
dy = (ypos_max << 16) - ypos;
|
||||
dx >>= 16;
|
||||
dy >>= 16;
|
||||
|
||||
//if we're in so many units of the target, signal it
|
||||
if((system && (dy <= 6 && dy >= -8) && (dx <= 126 && dx >= -128)) || (!system && (dx <= 6 && dx >= -8) && (dy <= 126 && dy >= -128))) {
|
||||
//announce our new destination and flag it
|
||||
xpos_max = xpos_new & 0x7fff;
|
||||
ypos_max = ypos_new;
|
||||
flags |= 0x08;
|
||||
}
|
||||
|
||||
//update position
|
||||
xpos -= (cos(rot) * 0x400 >> 15) * (speed >> 8) << 1;
|
||||
ypos -= (sin(rot) * 0x400 >> 15) * (speed >> 8) << 1;
|
||||
|
||||
//quirk: mask upper byte
|
||||
xpos &= 0x1fffffff;
|
||||
ypos &= 0x1fffffff;
|
||||
|
||||
writew(0x00c0, ypos_max);
|
||||
writew(0x00c2, xpos_max);
|
||||
writed(0x00c4, ypos);
|
||||
writed(0x00c8, xpos);
|
||||
writew(0x00cc, rot);
|
||||
writew(0x00d4, speed);
|
||||
writew(0x00dc, flags);
|
||||
}
|
||||
|
||||
void ST010::op_06() {
|
||||
int16 multiplicand = readw(0x0000);
|
||||
int16 multiplier = readw(0x0002);
|
||||
int32 product;
|
||||
|
||||
product = multiplicand * multiplier << 1;
|
||||
|
||||
writed(0x0010, product);
|
||||
}
|
||||
|
||||
void ST010::op_07() {
|
||||
int16 theta = readw(0x0000);
|
||||
|
||||
int16 data;
|
||||
for(int i = 0, offset = 0; i < 176; i++) {
|
||||
data = mode7_scale[i] * cos(theta) >> 15;
|
||||
writew(0x00f0 + offset, data);
|
||||
writew(0x0510 + offset, data);
|
||||
|
||||
data = mode7_scale[i] * sin(theta) >> 15;
|
||||
writew(0x0250 + offset, data);
|
||||
if(data) { data = ~data; }
|
||||
writew(0x03b0 + offset, data);
|
||||
|
||||
offset += 2;
|
||||
}
|
||||
}
|
||||
|
||||
void ST010::op_08() {
|
||||
int16 x0 = readw(0x0000);
|
||||
int16 y0 = readw(0x0002);
|
||||
int16 theta = readw(0x0004);
|
||||
int16 x1, y1;
|
||||
|
||||
x1 = (y0 * sin(theta) >> 15) + (x0 * cos(theta) >> 15);
|
||||
y1 = (y0 * cos(theta) >> 15) - (x0 * sin(theta) >> 15);
|
||||
|
||||
writew(0x0010, x1);
|
||||
writew(0x0012, y1);
|
||||
}
|
3
src/chip/superfx/core/core.h
Normal file
3
src/chip/superfx/core/core.h
Normal file
@@ -0,0 +1,3 @@
|
||||
void op_unknown() {}
|
||||
|
||||
void op_00();
|
7
src/chip/superfx/core/op0x.cpp
Normal file
7
src/chip/superfx/core/op0x.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
//STOP
|
||||
void SuperFX::op_00() {
|
||||
regs.sfr.g = 0;
|
||||
regs.sfr.b = 0;
|
||||
regs.sfr.alt1 = 0;
|
||||
regs.sfr.alt2 = 0;
|
||||
}
|
64
src/chip/superfx/memory/read.cpp
Normal file
64
src/chip/superfx/memory/read.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
uint8 SuperFX::mmio_read(uint16 addr) {
|
||||
switch(addr) {
|
||||
case 0x3000: return regs.r0.l;
|
||||
case 0x3001: return regs.r0.h;
|
||||
case 0x3002: return regs.r1.l;
|
||||
case 0x3003: return regs.r1.h;
|
||||
case 0x3004: return regs.r2.l;
|
||||
case 0x3005: return regs.r2.h;
|
||||
case 0x3006: return regs.r3.l;
|
||||
case 0x3007: return regs.r3.h;
|
||||
case 0x3008: return regs.r4.l;
|
||||
case 0x3009: return regs.r4.h;
|
||||
case 0x300a: return regs.r5.l;
|
||||
case 0x300b: return regs.r5.h;
|
||||
case 0x300c: return regs.r6.l;
|
||||
case 0x300d: return regs.r6.h;
|
||||
case 0x300e: return regs.r7.l;
|
||||
case 0x300f: return regs.r7.h;
|
||||
|
||||
case 0x3010: return regs.r8.l;
|
||||
case 0x3011: return regs.r8.h;
|
||||
case 0x3012: return regs.r9.l;
|
||||
case 0x3013: return regs.r9.h;
|
||||
case 0x3014: return regs.r10.l;
|
||||
case 0x3015: return regs.r10.h;
|
||||
case 0x3016: return regs.r11.l;
|
||||
case 0x3017: return regs.r11.h;
|
||||
case 0x3018: return regs.r12.l;
|
||||
case 0x3019: return regs.r12.h;
|
||||
case 0x301a: return regs.r13.l;
|
||||
case 0x301b: return regs.r13.h;
|
||||
case 0x301c: return regs.r14.l;
|
||||
case 0x301d: return regs.r14.h;
|
||||
case 0x301e: return regs.r15.l;
|
||||
case 0x301f: return regs.r15.h;
|
||||
|
||||
//0x3020 - 0x302f unused
|
||||
|
||||
case 0x3030: return regs.sfr;
|
||||
case 0x3031: return regs.sfr >> 8;
|
||||
case 0x3032: return 0x00; //unused
|
||||
case 0x3033: return 0x00; //BRAMR (write only)
|
||||
case 0x3034: return regs.pbr;
|
||||
case 0x3035: return 0x00; //unused
|
||||
case 0x3036: return regs.rombr;
|
||||
case 0x3037: return 0x00; //CFGR (write only)
|
||||
case 0x3038: return 0x00; //SCBR (write only)
|
||||
case 0x3039: return 0x00; //CLSR (write only)
|
||||
case 0x303a: return 0x00; //SCMR (write only)
|
||||
case 0x303b: return regs.vcr;
|
||||
case 0x303c: return regs.rambr;
|
||||
case 0x303d: return 0x00; //unused
|
||||
case 0x303e: return regs.cbr;
|
||||
case 0x303f: return regs.cbr >> 8;
|
||||
|
||||
//0x3040 - 0x30ff unused
|
||||
}
|
||||
|
||||
if(addr >= 0x3100 && addr <= 0x32ff) {
|
||||
return cache[addr - 0x3100];
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
63
src/chip/superfx/memory/write.cpp
Normal file
63
src/chip/superfx/memory/write.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
void SuperFX::mmio_write(uint16 addr, uint8 data) {
|
||||
switch(addr) {
|
||||
case 0x3000: regs.r0.l = data; return;
|
||||
case 0x3001: regs.r0.h = data; return;
|
||||
case 0x3002: regs.r1.l = data; return;
|
||||
case 0x3003: regs.r1.h = data; return;
|
||||
case 0x3004: regs.r2.l = data; return;
|
||||
case 0x3005: regs.r2.h = data; return;
|
||||
case 0x3006: regs.r3.l = data; return;
|
||||
case 0x3007: regs.r3.h = data; return;
|
||||
case 0x3008: regs.r4.l = data; return;
|
||||
case 0x3009: regs.r4.h = data; return;
|
||||
case 0x300a: regs.r5.l = data; return;
|
||||
case 0x300b: regs.r5.h = data; return;
|
||||
case 0x300c: regs.r6.l = data; return;
|
||||
case 0x300d: regs.r6.h = data; return;
|
||||
case 0x300e: regs.r7.l = data; return;
|
||||
case 0x300f: regs.r7.h = data; return;
|
||||
|
||||
case 0x3010: regs.r8.l = data; return;
|
||||
case 0x3011: regs.r8.h = data; return;
|
||||
case 0x3012: regs.r9.l = data; return;
|
||||
case 0x3013: regs.r9.h = data; return;
|
||||
case 0x3014: regs.r10.l = data; return;
|
||||
case 0x3015: regs.r10.h = data; return;
|
||||
case 0x3016: regs.r11.l = data; return;
|
||||
case 0x3017: regs.r11.h = data; return;
|
||||
case 0x3018: regs.r12.l = data; return;
|
||||
case 0x3019: regs.r12.h = data; return;
|
||||
case 0x301a: regs.r13.l = data; return;
|
||||
case 0x301b: regs.r13.h = data; return;
|
||||
case 0x301c: regs.r14.l = data; return;
|
||||
case 0x301d: regs.r14.h = data; return;
|
||||
case 0x301e: regs.r15.l = data; return;
|
||||
case 0x301f: regs.r15.h = data; return;
|
||||
|
||||
//0x3020 - 0x302f unused
|
||||
|
||||
case 0x3030: regs.sfr.l = data & 0x7e; return; //mask invalid bits
|
||||
case 0x3031: regs.sfr.h = data & 0x9f; return; //mask invalid bits
|
||||
case 0x3032: return; //unused
|
||||
case 0x3033: regs.bramr = data; return;
|
||||
case 0x3034: regs.pbr = data; return;
|
||||
case 0x3035: return; //unused
|
||||
case 0x3036: return; //ROMBR (read only)
|
||||
case 0x3037: regs.cfgr = data; return;
|
||||
case 0x3038: regs.scbr = data; return;
|
||||
case 0x3039: regs.clsr = data; return;
|
||||
case 0x303a: regs.scmr = data; return;
|
||||
case 0x303b: return; //VCR (read only)
|
||||
case 0x303c: return; //RAMBR (read only)
|
||||
case 0x303d: return; //unused
|
||||
case 0x303e: return; //CBR low (read only)
|
||||
case 0x303f: return; //CBR high (read only)
|
||||
|
||||
//0x3040 - 0x30ff unused
|
||||
}
|
||||
|
||||
if(addr >= 0x3100 && addr <= 0x32ff) {
|
||||
cache[addr - 0x3100] = data;
|
||||
return;
|
||||
}
|
||||
}
|
174
src/chip/superfx/regs.h
Normal file
174
src/chip/superfx/regs.h
Normal file
@@ -0,0 +1,174 @@
|
||||
struct Reg16 {
|
||||
union {
|
||||
uint16 w;
|
||||
struct { uint8 order_lsb2(l, h); };
|
||||
};
|
||||
|
||||
inline operator unsigned() const { return w; }
|
||||
inline unsigned operator=(const unsigned i) { return w = i; }
|
||||
|
||||
Reg16() : w(0) {}
|
||||
};
|
||||
|
||||
template<int bit> struct RegFlag8 {
|
||||
uint8 data;
|
||||
|
||||
inline operator bool() const { return data & bit; }
|
||||
inline bool operator=(const bool i) { i ? data |= bit : data &= ~bit; return i; }
|
||||
};
|
||||
|
||||
template<int bit> struct RegFlag16 {
|
||||
uint16 data;
|
||||
|
||||
inline operator bool() const { return data & bit; }
|
||||
inline bool operator=(const bool i) { i ? data |= bit : data &= ~bit; return i; }
|
||||
};
|
||||
|
||||
struct SFR {
|
||||
union {
|
||||
uint16 w;
|
||||
struct { uint8 order_lsb2(l, h); };
|
||||
RegFlag16<0x0002> z; //zero flag
|
||||
RegFlag16<0x0004> c; //carry flag
|
||||
RegFlag16<0x0008> s; //sign flag
|
||||
RegFlag16<0x0010> v; //overflow flag
|
||||
RegFlag16<0x0020> g; //go flag
|
||||
RegFlag16<0x0040> r; //ROM read using r14 flag
|
||||
RegFlag16<0x0100> alt1; //alternate instruction 1 flag
|
||||
RegFlag16<0x0200> alt2; //alternate instruction 2 flag
|
||||
RegFlag16<0x0400> il; //immediate lower 8-bit flag
|
||||
RegFlag16<0x0800> ih; //immediate upper 8-bit flag
|
||||
RegFlag16<0x1000> b; //WITH instruction flag
|
||||
RegFlag16<0x8000> irq; //interrupt flag
|
||||
};
|
||||
|
||||
inline operator unsigned() const { return w & 0x9f7e; } //invalid flag bits always return 0 when read
|
||||
inline unsigned operator=(const unsigned i) { return w = i & 0x9f7e; }
|
||||
|
||||
SFR() : w(0) {}
|
||||
};
|
||||
|
||||
struct RAMBR {
|
||||
union {
|
||||
uint8 b;
|
||||
RegFlag8<0x01> bank;
|
||||
};
|
||||
|
||||
inline operator unsigned() const { return b & 0x01; }
|
||||
inline unsigned operator=(const unsigned i) { return b = i & 0x01; }
|
||||
|
||||
RAMBR() : b(0) {}
|
||||
};
|
||||
|
||||
struct CBR {
|
||||
uint16 w;
|
||||
|
||||
inline operator unsigned() const { return w & 0xfff0; }
|
||||
inline unsigned operator=(const unsigned i) { return w = i & 0xfff0; }
|
||||
|
||||
CBR() : w(0) {}
|
||||
};
|
||||
|
||||
struct SCMR {
|
||||
union {
|
||||
uint8 b;
|
||||
RegFlag8<0x01> md0; //color mode low
|
||||
RegFlag8<0x02> md1; //color mode high
|
||||
RegFlag8<0x04> ht0; //height low
|
||||
RegFlag8<0x08> ran; //ram enable
|
||||
RegFlag8<0x10> ron; //rom enable
|
||||
RegFlag8<0x20> ht1; //height high
|
||||
};
|
||||
|
||||
inline operator unsigned() const { return b; }
|
||||
inline unsigned operator=(const unsigned i) { return b = i; }
|
||||
|
||||
SCMR() : b(0) {}
|
||||
};
|
||||
|
||||
struct BRAMR {
|
||||
union {
|
||||
uint8 b;
|
||||
RegFlag8<0x01> flag;
|
||||
};
|
||||
|
||||
inline operator unsigned() const { return b; }
|
||||
inline unsigned operator=(const unsigned i) { return b = i; }
|
||||
|
||||
BRAMR() : b(0) {}
|
||||
};
|
||||
|
||||
struct CFGR {
|
||||
union {
|
||||
uint8 b;
|
||||
RegFlag8<0x20> ms0; //multiplier speed selection
|
||||
RegFlag8<0x80> irq; //irq mask flag
|
||||
};
|
||||
|
||||
inline operator unsigned() const { return b; }
|
||||
inline unsigned operator=(const unsigned i) { return b = i; }
|
||||
|
||||
CFGR() : b(0) {}
|
||||
};
|
||||
|
||||
struct CLSR {
|
||||
union {
|
||||
uint8 b;
|
||||
RegFlag8<0x01> flag;
|
||||
};
|
||||
|
||||
inline operator unsigned() const { return b; }
|
||||
inline unsigned operator=(const unsigned i) { return b = i; }
|
||||
|
||||
CLSR() : b(0) {}
|
||||
};
|
||||
|
||||
struct POR {
|
||||
union {
|
||||
uint8 b;
|
||||
RegFlag8<0x01> transparent; //transparent flag
|
||||
RegFlag8<0x02> dither; //dither flag
|
||||
RegFlag8<0x04> highnibble; //high nibble flag
|
||||
RegFlag8<0x08> freezehigh; //freeze high flag
|
||||
RegFlag8<0x10> obj; //OBJ flag
|
||||
};
|
||||
|
||||
inline operator unsigned() const { return b; }
|
||||
inline unsigned operator=(const unsigned i) { return b = i; }
|
||||
|
||||
POR() : b(0) {}
|
||||
};
|
||||
|
||||
struct Regs {
|
||||
Reg16 r0; //default source/destination register
|
||||
Reg16 r1; //pixel plot X position register
|
||||
Reg16 r2; //pixel plot Y position register
|
||||
Reg16 r3;
|
||||
Reg16 r4; //lower 16-bit result of lmult
|
||||
Reg16 r5;
|
||||
Reg16 r6; //multiplier for fmult and lmult
|
||||
Reg16 r7; //fixed point texel X position for merge
|
||||
Reg16 r8; //fixed point texel Y position for merge
|
||||
Reg16 r9;
|
||||
Reg16 r10;
|
||||
Reg16 r11; //return address set by link
|
||||
Reg16 r12; //loop counter
|
||||
Reg16 r13; //loop point address
|
||||
Reg16 r14; //rom address for getb, getbh, getbl, getbs
|
||||
Reg16 r15; //program counter
|
||||
|
||||
SFR sfr; //status/flag register
|
||||
uint8 pbr; //program bank register
|
||||
uint8 rombr; //rom bank register
|
||||
RAMBR rambr; //ram bank register
|
||||
CBR cbr; //cache base register
|
||||
uint8 scbr; //screen base register
|
||||
SCMR scmr; //screen mode register
|
||||
BRAMR bramr; //backup ram register
|
||||
uint8 vcr; //version code register
|
||||
CFGR cfgr; //config register
|
||||
CLSR clsr; //clock select register
|
||||
|
||||
uint8 colr; //color register
|
||||
POR por; //plot option register
|
||||
} regs;
|
42
src/chip/superfx/superfx.cpp
Normal file
42
src/chip/superfx/superfx.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#include "../../base.h"
|
||||
|
||||
#include "core/op0x.cpp"
|
||||
|
||||
#include "memory/read.cpp"
|
||||
#include "memory/write.cpp"
|
||||
|
||||
void SuperFX::init() {
|
||||
}
|
||||
|
||||
void SuperFX::enable() {
|
||||
for(uint i = 0x3000; i <= 0x32ff; i++) {
|
||||
r_mem->set_mmio_mapper(i, this);
|
||||
}
|
||||
}
|
||||
|
||||
void SuperFX::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void SuperFX::reset() {
|
||||
regs.r0 = 0;
|
||||
regs.r1 = 0;
|
||||
regs.r2 = 0;
|
||||
regs.r3 = 0;
|
||||
regs.r4 = 0;
|
||||
regs.r5 = 0;
|
||||
regs.r6 = 0;
|
||||
regs.r7 = 0;
|
||||
regs.r8 = 0;
|
||||
regs.r9 = 0;
|
||||
regs.r10 = 0;
|
||||
regs.r11 = 0;
|
||||
regs.r12 = 0;
|
||||
regs.r13 = 0;
|
||||
regs.r14 = 0;
|
||||
regs.r15 = 0;
|
||||
|
||||
regs.sfr = 0;
|
||||
|
||||
memset(cache, 0, sizeof cache);
|
||||
}
|
17
src/chip/superfx/superfx.h
Normal file
17
src/chip/superfx/superfx.h
Normal file
@@ -0,0 +1,17 @@
|
||||
class SuperFX : public MMIO { public:
|
||||
#include "core/core.h"
|
||||
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 mmio_read (uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
private:
|
||||
#include "regs.h"
|
||||
uint8 cache[512]; //cache RAM
|
||||
};
|
||||
|
||||
extern SuperFX superfx;
|
2
src/clean.bat
Normal file
2
src/clean.bat
Normal file
@@ -0,0 +1,2 @@
|
||||
::@make PLATFORM=win-mingw4-lui clean
|
||||
@make PLATFORM=win-visualc-lui clean
|
2
src/clean.sh
Normal file
2
src/clean.sh
Normal file
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
make PLATFORM=x-gcc-lui clean
|
@@ -1,7 +1,10 @@
|
||||
Config config_file;
|
||||
|
||||
namespace config {
|
||||
|
||||
Config& config() {
|
||||
static Config config;
|
||||
return config;
|
||||
}
|
||||
|
||||
string file_updatepath(const char *req_file, const char *req_path) {
|
||||
string file(req_file);
|
||||
replace(file, "\\", "/");
|
||||
@@ -25,83 +28,98 @@ stringarray part;
|
||||
return path;
|
||||
}
|
||||
|
||||
Setting Path::base(0, "fs.base_path",
|
||||
StringSetting Path::base(0, "fs.base_path",
|
||||
"Path that bsnes resides in", "");
|
||||
Setting Path::rom(&config_file, "path.rom",
|
||||
StringSetting Path::rom(&config(), "path.rom",
|
||||
"Default path to look for ROM files in (\"\" = use default directory)", "");
|
||||
Setting Path::save(&config_file, "path.save",
|
||||
StringSetting Path::save(&config(), "path.save",
|
||||
"Default path for all save RAM and cheat files (\"\" = use current directory)", "");
|
||||
Setting Path::bios(&config_file, "path.bios",
|
||||
StringSetting Path::bios(&config(), "path.bios",
|
||||
"Path where BIOS file(s) are located\n"
|
||||
"Supported BIOS files:\n"
|
||||
"stbios.bin - Bandai Sufami Turbo"
|
||||
"", "./bios");
|
||||
|
||||
Setting Path::save_ext(&config_file, "path.save_ext",
|
||||
StringSetting Path::save_ext(&config(), "path.save_ext",
|
||||
"Extension to be used for all save RAM files", "srm");
|
||||
|
||||
Setting SNES::gamma_ramp(&config_file, "snes.colorfilter.gamma_ramp",
|
||||
"Use precalculated TV-style gamma ramp", true, Setting::BOOL);
|
||||
Setting SNES::sepia(&config_file, "snes.colorfilter.sepia",
|
||||
"Convert color to sepia tone", false, Setting::BOOL);
|
||||
Setting SNES::grayscale(&config_file, "snes.colorfilter.grayscale",
|
||||
"Convert color to grayscale tone", false, Setting::BOOL);
|
||||
Setting SNES::invert(&config_file, "snes.colorfilter.invert",
|
||||
"Invert output image colors", false, Setting::BOOL);
|
||||
Setting SNES::contrast(&config_file, "snes.colorfilter.contrast",
|
||||
"Contrast", 0, Setting::DEC);
|
||||
Setting SNES::brightness(&config_file, "snes.colorfilter.brightness",
|
||||
"Brightness", 0, Setting::DEC);
|
||||
Setting SNES::gamma(&config_file, "snes.colorfilter.gamma",
|
||||
"Gamma", 80, Setting::DEC);
|
||||
IntegerSetting SNES::gamma_ramp(&config(), "snes.colorfilter.gamma_ramp",
|
||||
"Use precalculated TV-style gamma ramp", IntegerSetting::Boolean, true);
|
||||
IntegerSetting SNES::sepia(&config(), "snes.colorfilter.sepia",
|
||||
"Convert color to sepia tone", IntegerSetting::Boolean, false);
|
||||
IntegerSetting SNES::grayscale(&config(), "snes.colorfilter.grayscale",
|
||||
"Convert color to grayscale tone", IntegerSetting::Boolean, false);
|
||||
IntegerSetting SNES::invert(&config(), "snes.colorfilter.invert",
|
||||
"Invert output image colors", IntegerSetting::Boolean, false);
|
||||
IntegerSetting SNES::contrast(&config(), "snes.colorfilter.contrast",
|
||||
"Contrast", IntegerSetting::Decimal, 0);
|
||||
IntegerSetting SNES::brightness(&config(), "snes.colorfilter.brightness",
|
||||
"Brightness", IntegerSetting::Decimal, 0);
|
||||
IntegerSetting SNES::gamma(&config(), "snes.colorfilter.gamma",
|
||||
"Gamma", IntegerSetting::Decimal, 80);
|
||||
|
||||
Setting SNES::ntsc_merge_fields(&config_file, "snes.ntsc_merge_fields",
|
||||
IntegerSetting SNES::ntsc_merge_fields(&config(), "snes.ntsc_merge_fields",
|
||||
"Merge fields in NTSC video filter\n"
|
||||
"Set to true if using filter at any refresh rate other than 60hz\n"
|
||||
"", true, Setting::BOOL);
|
||||
"", IntegerSetting::Boolean, true);
|
||||
|
||||
Setting SNES::mute(&config_file, "snes.mute", "Mutes SNES audio output when enabled",
|
||||
false, Setting::BOOL);
|
||||
IntegerSetting SNES::mute(&config(), "snes.mute", "Mutes SNES audio output when enabled",
|
||||
IntegerSetting::Boolean, false);
|
||||
|
||||
Setting SNES::controller_port0(&config_file, "snes.controller_port_1",
|
||||
"Controller attached to SNES port 1", ::SNES::DEVICEID_JOYPAD1, Setting::DEC);
|
||||
Setting SNES::controller_port1(&config_file, "snes.controller_port_2",
|
||||
"Controller attached to SNES port 2", ::SNES::DEVICEID_JOYPAD2, Setting::DEC);
|
||||
IntegerSetting SNES::controller_port0(&config(), "snes.controller_port_1",
|
||||
"Controller attached to SNES port 1", IntegerSetting::Decimal, ::SNES::DEVICEID_JOYPAD1);
|
||||
IntegerSetting SNES::controller_port1(&config(), "snes.controller_port_2",
|
||||
"Controller attached to SNES port 2", IntegerSetting::Decimal, ::SNES::DEVICEID_JOYPAD2);
|
||||
|
||||
Setting CPU::ntsc_clock_rate(&config_file, "cpu.ntsc_clock_rate",
|
||||
"NTSC S-CPU clock rate (in hz)", 21477272, Setting::DEC);
|
||||
Setting CPU::pal_clock_rate(&config_file, "cpu.pal_clock_rate",
|
||||
"PAL S-CPU clock rate (in hz)", 21281370, Setting::DEC);
|
||||
IntegerSetting CPU::ntsc_clock_rate(&config(), "cpu.ntsc_clock_rate",
|
||||
"NTSC S-CPU clock rate (in hz)", IntegerSetting::Decimal, 21477272);
|
||||
IntegerSetting CPU::pal_clock_rate(&config(), "cpu.pal_clock_rate",
|
||||
"PAL S-CPU clock rate (in hz)", IntegerSetting::Decimal, 21281370);
|
||||
|
||||
Setting CPU::hdma_enable(0, "cpu.hdma_enable",
|
||||
"Enable HDMA effects", true, Setting::BOOL);
|
||||
IntegerSetting CPU::hdma_enable(0, "cpu.hdma_enable",
|
||||
"Enable HDMA effects", IntegerSetting::Boolean, true);
|
||||
|
||||
Setting SMP::ntsc_clock_rate(&config_file, "smp.ntsc_clock_rate",
|
||||
"NTSC S-SMP clock rate (in hz)", 24606720, Setting::DEC);
|
||||
Setting SMP::pal_clock_rate(&config_file, "smp.pal_clock_rate",
|
||||
"PAL S-SMP clock rate (in hz)", 24606720, Setting::DEC);
|
||||
IntegerSetting SMP::ntsc_clock_rate(&config(), "smp.ntsc_clock_rate",
|
||||
"NTSC S-SMP clock rate (in hz)", IntegerSetting::Decimal, 24606720);
|
||||
IntegerSetting SMP::pal_clock_rate(&config(), "smp.pal_clock_rate",
|
||||
"PAL S-SMP clock rate (in hz)", IntegerSetting::Decimal, 24606720);
|
||||
|
||||
Setting PPU::Hack::render_scanline_position(&config_file, "ppu.hack.render_scanline_position",
|
||||
IntegerSetting PPU::Hack::render_scanline_position(&config(), "ppu.hack.render_scanline_position",
|
||||
"Approximate HCLOCK position to render at for scanline-based renderers",
|
||||
512, Setting::DEC);
|
||||
Setting PPU::Hack::obj_cache(&config_file, "ppu.hack.obj_cache",
|
||||
IntegerSetting::Decimal, 512);
|
||||
IntegerSetting PPU::Hack::obj_cache(&config(), "ppu.hack.obj_cache",
|
||||
"Cache OAM OBJ attributes one scanline before rendering\n"
|
||||
"This is technically closer to the actual operation of the SNES,\n"
|
||||
"but can cause problems in many games if enabled",
|
||||
false, Setting::BOOL);
|
||||
"but can cause problems in some games if enabled",
|
||||
IntegerSetting::Boolean, false);
|
||||
IntegerSetting PPU::Hack::oam_address_invalidation(&config(), "ppu.hack.oam_address_invalidation",
|
||||
"OAM access address changes during active display, as the S-PPU reads\n"
|
||||
"data to render the display. Thusly, the address retrieved when accessing\n"
|
||||
"OAM during active display is unpredictable. Unfortunately, the exact\n"
|
||||
"algorithm for this is completely unknown at this time. It is more hardware\n"
|
||||
"accurate to enable this setting, but one must *not* rely on the actual\n"
|
||||
"address to match hardware under emulation.",
|
||||
IntegerSetting::Boolean, true);
|
||||
IntegerSetting PPU::Hack::cgram_address_invalidation(&config(), "ppu.hack.cgram_address_invalidation",
|
||||
"CGRAM access address changes during active display (excluding hblank), as\n"
|
||||
"the S-PPU reads data to render the display. Thusly, as with OAM, the access\n"
|
||||
"address is unpredictable. Again, enabling this setting is more hardware\n"
|
||||
"accurate, but one must *not* rely on the actual address to match hardware\n"
|
||||
"under emulation.",
|
||||
IntegerSetting::Boolean, true);
|
||||
|
||||
Setting PPU::opt_enable(0, "ppu.opt_enable", "Enable offset-per-tile effects", true, Setting::BOOL);
|
||||
Setting PPU::bg1_pri0_enable(0, "ppu.bg1_pri0_enable", "Enable BG1 Priority 0", true, Setting::BOOL);
|
||||
Setting PPU::bg1_pri1_enable(0, "ppu.bg1_pri1_enable", "Enable BG1 Priority 1", true, Setting::BOOL);
|
||||
Setting PPU::bg2_pri0_enable(0, "ppu.bg2_pri0_enable", "Enable BG2 Priority 0", true, Setting::BOOL);
|
||||
Setting PPU::bg2_pri1_enable(0, "ppu.bg2_pri1_enable", "Enable BG2 Priority 1", true, Setting::BOOL);
|
||||
Setting PPU::bg3_pri0_enable(0, "ppu.bg3_pri0_enable", "Enable BG3 Priority 0", true, Setting::BOOL);
|
||||
Setting PPU::bg3_pri1_enable(0, "ppu.bg3_pri1_enable", "Enable BG3 Priority 1", true, Setting::BOOL);
|
||||
Setting PPU::bg4_pri0_enable(0, "ppu.bg4_pri0_enable", "Enable BG4 Priority 0", true, Setting::BOOL);
|
||||
Setting PPU::bg4_pri1_enable(0, "ppu.bg4_pri1_enable", "Enable BG4 Priority 1", true, Setting::BOOL);
|
||||
Setting PPU::oam_pri0_enable(0, "ppu.oam_pri0_enable", "Enable OAM Priority 0", true, Setting::BOOL);
|
||||
Setting PPU::oam_pri1_enable(0, "ppu.oam_pri1_enable", "Enable OAM Priority 1", true, Setting::BOOL);
|
||||
Setting PPU::oam_pri2_enable(0, "ppu.oam_pri2_enable", "Enable OAM Priority 2", true, Setting::BOOL);
|
||||
Setting PPU::oam_pri3_enable(0, "ppu.oam_pri3_enable", "Enable OAM Priority 3", true, Setting::BOOL);
|
||||
IntegerSetting PPU::opt_enable(0, "ppu.opt_enable", "Enable offset-per-tile effects", IntegerSetting::Boolean, true);
|
||||
IntegerSetting PPU::bg1_pri0_enable(0, "ppu.bg1_pri0_enable", "Enable BG1 Priority 0", IntegerSetting::Boolean, true);
|
||||
IntegerSetting PPU::bg1_pri1_enable(0, "ppu.bg1_pri1_enable", "Enable BG1 Priority 1", IntegerSetting::Boolean, true);
|
||||
IntegerSetting PPU::bg2_pri0_enable(0, "ppu.bg2_pri0_enable", "Enable BG2 Priority 0", IntegerSetting::Boolean, true);
|
||||
IntegerSetting PPU::bg2_pri1_enable(0, "ppu.bg2_pri1_enable", "Enable BG2 Priority 1", IntegerSetting::Boolean, true);
|
||||
IntegerSetting PPU::bg3_pri0_enable(0, "ppu.bg3_pri0_enable", "Enable BG3 Priority 0", IntegerSetting::Boolean, true);
|
||||
IntegerSetting PPU::bg3_pri1_enable(0, "ppu.bg3_pri1_enable", "Enable BG3 Priority 1", IntegerSetting::Boolean, true);
|
||||
IntegerSetting PPU::bg4_pri0_enable(0, "ppu.bg4_pri0_enable", "Enable BG4 Priority 0", IntegerSetting::Boolean, true);
|
||||
IntegerSetting PPU::bg4_pri1_enable(0, "ppu.bg4_pri1_enable", "Enable BG4 Priority 1", IntegerSetting::Boolean, true);
|
||||
IntegerSetting PPU::oam_pri0_enable(0, "ppu.oam_pri0_enable", "Enable OAM Priority 0", IntegerSetting::Boolean, true);
|
||||
IntegerSetting PPU::oam_pri1_enable(0, "ppu.oam_pri1_enable", "Enable OAM Priority 1", IntegerSetting::Boolean, true);
|
||||
IntegerSetting PPU::oam_pri2_enable(0, "ppu.oam_pri2_enable", "Enable OAM Priority 2", IntegerSetting::Boolean, true);
|
||||
IntegerSetting PPU::oam_pri3_enable(0, "ppu.oam_pri3_enable", "Enable OAM Priority 3", IntegerSetting::Boolean, true);
|
||||
|
||||
};
|
||||
|
@@ -1,44 +1,46 @@
|
||||
extern Config config_file;
|
||||
|
||||
namespace config {
|
||||
|
||||
extern Config& config();
|
||||
|
||||
string file_updatepath(const char *, const char *);
|
||||
|
||||
extern struct Path {
|
||||
static Setting base, rom, save, bios;
|
||||
static Setting save_ext;
|
||||
static StringSetting base, rom, save, bios;
|
||||
static StringSetting save_ext;
|
||||
} path;
|
||||
|
||||
extern struct SNES {
|
||||
static Setting gamma_ramp, sepia, grayscale, invert, contrast, brightness, gamma;
|
||||
static Setting ntsc_merge_fields;
|
||||
static Setting mute;
|
||||
static Setting controller_port0;
|
||||
static Setting controller_port1;
|
||||
static IntegerSetting gamma_ramp, sepia, grayscale, invert, contrast, brightness, gamma;
|
||||
static IntegerSetting ntsc_merge_fields;
|
||||
static IntegerSetting mute;
|
||||
static IntegerSetting controller_port0;
|
||||
static IntegerSetting controller_port1;
|
||||
} snes;
|
||||
|
||||
extern struct CPU {
|
||||
static Setting ntsc_clock_rate, pal_clock_rate;
|
||||
static Setting hdma_enable;
|
||||
static IntegerSetting ntsc_clock_rate, pal_clock_rate;
|
||||
static IntegerSetting hdma_enable;
|
||||
} cpu;
|
||||
|
||||
extern struct SMP {
|
||||
static Setting ntsc_clock_rate, pal_clock_rate;
|
||||
static IntegerSetting ntsc_clock_rate, pal_clock_rate;
|
||||
} smp;
|
||||
|
||||
extern struct PPU {
|
||||
struct Hack {
|
||||
static Setting render_scanline_position;
|
||||
static Setting obj_cache;
|
||||
static IntegerSetting render_scanline_position;
|
||||
static IntegerSetting obj_cache;
|
||||
static IntegerSetting oam_address_invalidation;
|
||||
static IntegerSetting cgram_address_invalidation;
|
||||
} hack;
|
||||
|
||||
static Setting opt_enable;
|
||||
static Setting bg1_pri0_enable, bg1_pri1_enable;
|
||||
static Setting bg2_pri0_enable, bg2_pri1_enable;
|
||||
static Setting bg3_pri0_enable, bg3_pri1_enable;
|
||||
static Setting bg4_pri0_enable, bg4_pri1_enable;
|
||||
static Setting oam_pri0_enable, oam_pri1_enable;
|
||||
static Setting oam_pri2_enable, oam_pri3_enable;
|
||||
static IntegerSetting opt_enable;
|
||||
static IntegerSetting bg1_pri0_enable, bg1_pri1_enable;
|
||||
static IntegerSetting bg2_pri0_enable, bg2_pri1_enable;
|
||||
static IntegerSetting bg3_pri0_enable, bg3_pri1_enable;
|
||||
static IntegerSetting bg4_pri0_enable, bg4_pri1_enable;
|
||||
static IntegerSetting oam_pri0_enable, oam_pri1_enable;
|
||||
static IntegerSetting oam_pri2_enable, oam_pri3_enable;
|
||||
} ppu;
|
||||
|
||||
};
|
||||
|
@@ -3,7 +3,7 @@ public:
|
||||
union {
|
||||
uint8 data;
|
||||
struct {
|
||||
uint8 order_msb8(n:1, v:1, m:1, x:1, d:1, i:1, z:1, c:1);
|
||||
bool order_msb8(n:1, v:1, m:1, x:1, d:1, i:1, z:1, c:1);
|
||||
};
|
||||
};
|
||||
|
||||
|
@@ -1,33 +1,31 @@
|
||||
#include "opfn.cpp"
|
||||
|
||||
void sCPU::enter() {
|
||||
for(;;) {
|
||||
if(event.irq) {
|
||||
event.irq = false;
|
||||
if(status.nmi_pending == true) {
|
||||
status.nmi_pending = false;
|
||||
event.irq_vector = (regs.e == false) ? 0xffea : 0xfffa;
|
||||
} else if(status.irq_pending == true) {
|
||||
status.irq_pending = false;
|
||||
event.irq_vector = (regs.e == false) ? 0xffee : 0xfffe;
|
||||
}
|
||||
op_irq();
|
||||
#include "op_read.cpp"
|
||||
#include "op_write.cpp"
|
||||
#include "op_rmw.cpp"
|
||||
#include "op_pc.cpp"
|
||||
#include "op_misc.cpp"
|
||||
|
||||
void sCPU::enter() { loop:
|
||||
if(event.irq) {
|
||||
event.irq = false;
|
||||
if(status.nmi_pending == true) {
|
||||
status.nmi_pending = false;
|
||||
event.irq_vector = (regs.e == false) ? 0xffea : 0xfffa;
|
||||
} else if(status.irq_pending == true) {
|
||||
status.irq_pending = false;
|
||||
event.irq_vector = (regs.e == false) ? 0xffee : 0xfffe;
|
||||
}
|
||||
|
||||
tracer.trace_cpuop(); //traces CPU opcode (only if tracer is enabled)
|
||||
|
||||
status.in_opcode = true;
|
||||
|
||||
switch(op_readpc()) {
|
||||
#include "op_read.cpp"
|
||||
#include "op_write.cpp"
|
||||
#include "op_rmw.cpp"
|
||||
#include "op_pc.cpp"
|
||||
#include "op_misc.cpp"
|
||||
}
|
||||
|
||||
status.in_opcode = false;
|
||||
op_irq();
|
||||
}
|
||||
|
||||
tracer.trace_cpuop(); //traces CPU opcode (only if tracer is enabled)
|
||||
|
||||
status.in_opcode = true;
|
||||
(this->*optbl[op_readpc()])();
|
||||
status.in_opcode = false;
|
||||
|
||||
goto loop;
|
||||
}
|
||||
|
||||
void sCPU::op_irq() {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
//void (sCPU::*optbl[256])();
|
||||
void (sCPU::*optbl[256])();
|
||||
|
||||
CPUReg24 aa, rd;
|
||||
uint8 dp, sp;
|
||||
@@ -54,4 +54,4 @@ uint8 dp, sp;
|
||||
void op_io_cond4(uint16 x, uint16 y);
|
||||
void op_io_cond6(uint16 addr);
|
||||
|
||||
//#include "op.h"
|
||||
#include "op.h"
|
||||
|
256
src/cpu/scpu/core/op.h
Normal file
256
src/cpu/scpu/core/op.h
Normal file
@@ -0,0 +1,256 @@
|
||||
void op_adc_const();
|
||||
void op_and_const();
|
||||
void op_cmp_const();
|
||||
void op_cpx_const();
|
||||
void op_cpy_const();
|
||||
void op_eor_const();
|
||||
void op_lda_const();
|
||||
void op_ldx_const();
|
||||
void op_ldy_const();
|
||||
void op_ora_const();
|
||||
void op_sbc_const();
|
||||
void op_adc_addr();
|
||||
void op_and_addr();
|
||||
void op_bit_addr();
|
||||
void op_cmp_addr();
|
||||
void op_cpx_addr();
|
||||
void op_cpy_addr();
|
||||
void op_eor_addr();
|
||||
void op_lda_addr();
|
||||
void op_ldx_addr();
|
||||
void op_ldy_addr();
|
||||
void op_ora_addr();
|
||||
void op_sbc_addr();
|
||||
void op_adc_addrx();
|
||||
void op_and_addrx();
|
||||
void op_bit_addrx();
|
||||
void op_cmp_addrx();
|
||||
void op_eor_addrx();
|
||||
void op_lda_addrx();
|
||||
void op_ldy_addrx();
|
||||
void op_ora_addrx();
|
||||
void op_sbc_addrx();
|
||||
void op_adc_addry();
|
||||
void op_and_addry();
|
||||
void op_cmp_addry();
|
||||
void op_eor_addry();
|
||||
void op_lda_addry();
|
||||
void op_ldx_addry();
|
||||
void op_ora_addry();
|
||||
void op_sbc_addry();
|
||||
void op_adc_long();
|
||||
void op_and_long();
|
||||
void op_cmp_long();
|
||||
void op_eor_long();
|
||||
void op_lda_long();
|
||||
void op_ora_long();
|
||||
void op_sbc_long();
|
||||
void op_adc_longx();
|
||||
void op_and_longx();
|
||||
void op_cmp_longx();
|
||||
void op_eor_longx();
|
||||
void op_lda_longx();
|
||||
void op_ora_longx();
|
||||
void op_sbc_longx();
|
||||
void op_adc_dp();
|
||||
void op_and_dp();
|
||||
void op_bit_dp();
|
||||
void op_cmp_dp();
|
||||
void op_cpx_dp();
|
||||
void op_cpy_dp();
|
||||
void op_eor_dp();
|
||||
void op_lda_dp();
|
||||
void op_ldx_dp();
|
||||
void op_ldy_dp();
|
||||
void op_ora_dp();
|
||||
void op_sbc_dp();
|
||||
void op_adc_dpx();
|
||||
void op_and_dpx();
|
||||
void op_bit_dpx();
|
||||
void op_cmp_dpx();
|
||||
void op_eor_dpx();
|
||||
void op_lda_dpx();
|
||||
void op_ldy_dpx();
|
||||
void op_ora_dpx();
|
||||
void op_sbc_dpx();
|
||||
void op_ldx_dpy();
|
||||
void op_adc_idp();
|
||||
void op_and_idp();
|
||||
void op_cmp_idp();
|
||||
void op_eor_idp();
|
||||
void op_lda_idp();
|
||||
void op_ora_idp();
|
||||
void op_sbc_idp();
|
||||
void op_adc_idpx();
|
||||
void op_and_idpx();
|
||||
void op_cmp_idpx();
|
||||
void op_eor_idpx();
|
||||
void op_lda_idpx();
|
||||
void op_ora_idpx();
|
||||
void op_sbc_idpx();
|
||||
void op_adc_idpy();
|
||||
void op_and_idpy();
|
||||
void op_cmp_idpy();
|
||||
void op_eor_idpy();
|
||||
void op_lda_idpy();
|
||||
void op_ora_idpy();
|
||||
void op_sbc_idpy();
|
||||
void op_adc_ildp();
|
||||
void op_and_ildp();
|
||||
void op_cmp_ildp();
|
||||
void op_eor_ildp();
|
||||
void op_lda_ildp();
|
||||
void op_ora_ildp();
|
||||
void op_sbc_ildp();
|
||||
void op_adc_ildpy();
|
||||
void op_and_ildpy();
|
||||
void op_cmp_ildpy();
|
||||
void op_eor_ildpy();
|
||||
void op_lda_ildpy();
|
||||
void op_ora_ildpy();
|
||||
void op_sbc_ildpy();
|
||||
void op_adc_sr();
|
||||
void op_and_sr();
|
||||
void op_cmp_sr();
|
||||
void op_eor_sr();
|
||||
void op_lda_sr();
|
||||
void op_ora_sr();
|
||||
void op_sbc_sr();
|
||||
void op_adc_isry();
|
||||
void op_and_isry();
|
||||
void op_cmp_isry();
|
||||
void op_eor_isry();
|
||||
void op_lda_isry();
|
||||
void op_ora_isry();
|
||||
void op_sbc_isry();
|
||||
void op_bit_const();
|
||||
void op_sta_addr();
|
||||
void op_stx_addr();
|
||||
void op_sty_addr();
|
||||
void op_stz_addr();
|
||||
void op_sta_addrx();
|
||||
void op_stz_addrx();
|
||||
void op_sta_addry();
|
||||
void op_sta_long();
|
||||
void op_sta_longx();
|
||||
void op_sta_dp();
|
||||
void op_stx_dp();
|
||||
void op_sty_dp();
|
||||
void op_stz_dp();
|
||||
void op_sta_dpx();
|
||||
void op_sty_dpx();
|
||||
void op_stz_dpx();
|
||||
void op_stx_dpy();
|
||||
void op_sta_idp();
|
||||
void op_sta_ildp();
|
||||
void op_sta_idpx();
|
||||
void op_sta_idpy();
|
||||
void op_sta_ildpy();
|
||||
void op_sta_sr();
|
||||
void op_sta_isry();
|
||||
void op_inc();
|
||||
void op_inx();
|
||||
void op_iny();
|
||||
void op_dec();
|
||||
void op_dex();
|
||||
void op_dey();
|
||||
void op_asl();
|
||||
void op_lsr();
|
||||
void op_rol();
|
||||
void op_ror();
|
||||
void op_inc_addr();
|
||||
void op_dec_addr();
|
||||
void op_asl_addr();
|
||||
void op_lsr_addr();
|
||||
void op_rol_addr();
|
||||
void op_ror_addr();
|
||||
void op_trb_addr();
|
||||
void op_tsb_addr();
|
||||
void op_inc_addrx();
|
||||
void op_dec_addrx();
|
||||
void op_asl_addrx();
|
||||
void op_lsr_addrx();
|
||||
void op_rol_addrx();
|
||||
void op_ror_addrx();
|
||||
void op_inc_dp();
|
||||
void op_dec_dp();
|
||||
void op_asl_dp();
|
||||
void op_lsr_dp();
|
||||
void op_rol_dp();
|
||||
void op_ror_dp();
|
||||
void op_trb_dp();
|
||||
void op_tsb_dp();
|
||||
void op_inc_dpx();
|
||||
void op_dec_dpx();
|
||||
void op_asl_dpx();
|
||||
void op_lsr_dpx();
|
||||
void op_rol_dpx();
|
||||
void op_ror_dpx();
|
||||
void op_bcc();
|
||||
void op_bcs();
|
||||
void op_bne();
|
||||
void op_beq();
|
||||
void op_bpl();
|
||||
void op_bmi();
|
||||
void op_bvc();
|
||||
void op_bvs();
|
||||
void op_bra();
|
||||
void op_brl();
|
||||
void op_jmp_addr();
|
||||
void op_jmp_long();
|
||||
void op_jmp_iaddr();
|
||||
void op_jmp_iaddrx();
|
||||
void op_jmp_iladdr();
|
||||
void op_jsr_addr();
|
||||
void op_jsr_long();
|
||||
void op_jsr_iaddrx();
|
||||
void op_rti();
|
||||
void op_rts();
|
||||
void op_rtl();
|
||||
void op_nop();
|
||||
void op_wdm();
|
||||
void op_xba();
|
||||
void op_mvn();
|
||||
void op_mvp();
|
||||
void op_brk();
|
||||
void op_cop();
|
||||
void op_stp();
|
||||
void op_wai();
|
||||
void op_xce();
|
||||
void op_clc();
|
||||
void op_cld();
|
||||
void op_cli();
|
||||
void op_clv();
|
||||
void op_sec();
|
||||
void op_sed();
|
||||
void op_sei();
|
||||
void op_rep();
|
||||
void op_sep();
|
||||
void op_tax();
|
||||
void op_tay();
|
||||
void op_txa();
|
||||
void op_txy();
|
||||
void op_tya();
|
||||
void op_tyx();
|
||||
void op_tcd();
|
||||
void op_tcs();
|
||||
void op_tdc();
|
||||
void op_tsc();
|
||||
void op_tsx();
|
||||
void op_txs();
|
||||
void op_pha();
|
||||
void op_phx();
|
||||
void op_phy();
|
||||
void op_phd();
|
||||
void op_phb();
|
||||
void op_phk();
|
||||
void op_php();
|
||||
void op_pla();
|
||||
void op_plx();
|
||||
void op_ply();
|
||||
void op_pld();
|
||||
void op_plb();
|
||||
void op_plp();
|
||||
void op_pea();
|
||||
void op_pei();
|
||||
void op_per();
|
@@ -62,14 +62,14 @@ stp(0xdb) {
|
||||
}
|
||||
|
||||
wai(0xcb) {
|
||||
1:op_io();
|
||||
event.wai = true;
|
||||
2:last_cycle();
|
||||
op_io();
|
||||
3:while(event.wai) {
|
||||
//last_cycle() will set event.wai to false
|
||||
//once an NMI / IRQ edge is reached
|
||||
1:event.wai = true;
|
||||
while(event.wai) {
|
||||
last_cycle();
|
||||
op_io();
|
||||
}
|
||||
2:op_io();
|
||||
}
|
||||
|
||||
xce(0xfb) {
|
||||
|
@@ -1,17 +1,14 @@
|
||||
//nop
|
||||
case 0xea: {
|
||||
void sCPU::op_nop() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//wdm
|
||||
case 0x42: {
|
||||
void sCPU::op_wdm() {
|
||||
last_cycle();
|
||||
op_readpc();
|
||||
} break;
|
||||
}
|
||||
|
||||
//xba
|
||||
case 0xeb: {
|
||||
void sCPU::op_xba() {
|
||||
op_io();
|
||||
last_cycle();
|
||||
op_io();
|
||||
@@ -20,10 +17,9 @@ case 0xeb: {
|
||||
regs.a.l ^= regs.a.h;
|
||||
regs.p.n = !!(regs.a.l & 0x80);
|
||||
regs.p.z = (regs.a.l == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mvn
|
||||
case 0x54: {
|
||||
void sCPU::op_mvn() {
|
||||
dp = op_readpc();
|
||||
sp = op_readpc();
|
||||
regs.db = dp;
|
||||
@@ -40,10 +36,9 @@ case 0x54: {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.a.w--)regs.pc.w -= 3;
|
||||
} break;
|
||||
}
|
||||
|
||||
//mvp
|
||||
case 0x44: {
|
||||
void sCPU::op_mvp() {
|
||||
dp = op_readpc();
|
||||
sp = op_readpc();
|
||||
regs.db = dp;
|
||||
@@ -60,10 +55,9 @@ case 0x44: {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.a.w--)regs.pc.w -= 3;
|
||||
} break;
|
||||
}
|
||||
|
||||
//brk
|
||||
case 0x00: {
|
||||
void sCPU::op_brk() {
|
||||
op_readpc();
|
||||
if(!regs.e)op_writestack(regs.pc.b);
|
||||
op_writestack(regs.pc.h);
|
||||
@@ -76,10 +70,9 @@ case 0x00: {
|
||||
last_cycle();
|
||||
rd.h = op_readlong((regs.e) ? 0xffff : 0xffe7);
|
||||
regs.pc.w = rd.w;
|
||||
} break;
|
||||
}
|
||||
|
||||
//cop
|
||||
case 0x02: {
|
||||
void sCPU::op_cop() {
|
||||
op_readpc();
|
||||
if(!regs.e)op_writestack(regs.pc.b);
|
||||
op_writestack(regs.pc.h);
|
||||
@@ -92,29 +85,26 @@ case 0x02: {
|
||||
last_cycle();
|
||||
rd.h = op_readlong((regs.e) ? 0xfff5 : 0xffe5);
|
||||
regs.pc.w = rd.w;
|
||||
} break;
|
||||
}
|
||||
|
||||
//stp
|
||||
case 0xdb: {
|
||||
void sCPU::op_stp() {
|
||||
op_io();
|
||||
last_cycle();
|
||||
while(1) { op_io(); }
|
||||
} break;
|
||||
}
|
||||
|
||||
//wai
|
||||
case 0xcb: {
|
||||
op_io();
|
||||
void sCPU::op_wai() {
|
||||
//last_cycle() will set event.wai to false
|
||||
//once an NMI / IRQ edge is reached
|
||||
event.wai = true;
|
||||
last_cycle();
|
||||
op_io();
|
||||
while(event.wai) {
|
||||
last_cycle();
|
||||
op_io();
|
||||
}
|
||||
} break;
|
||||
op_io();
|
||||
}
|
||||
|
||||
//xce
|
||||
case 0xfb: {
|
||||
void sCPU::op_xce() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
bool carry = regs.p.c;
|
||||
@@ -128,59 +118,51 @@ bool carry = regs.p.c;
|
||||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//clc
|
||||
case 0x18: {
|
||||
void sCPU::op_clc() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.p.c = 0;
|
||||
} break;
|
||||
}
|
||||
|
||||
//cld
|
||||
case 0xd8: {
|
||||
void sCPU::op_cld() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.p.d = 0;
|
||||
} break;
|
||||
}
|
||||
|
||||
//cli
|
||||
case 0x58: {
|
||||
void sCPU::op_cli() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.p.i = 0;
|
||||
} break;
|
||||
}
|
||||
|
||||
//clv
|
||||
case 0xb8: {
|
||||
void sCPU::op_clv() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.p.v = 0;
|
||||
} break;
|
||||
}
|
||||
|
||||
//sec
|
||||
case 0x38: {
|
||||
void sCPU::op_sec() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.p.c = 1;
|
||||
} break;
|
||||
}
|
||||
|
||||
//sed
|
||||
case 0xf8: {
|
||||
void sCPU::op_sed() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.p.d = 1;
|
||||
} break;
|
||||
}
|
||||
|
||||
//sei
|
||||
case 0x78: {
|
||||
void sCPU::op_sei() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.p.i = 1;
|
||||
} break;
|
||||
}
|
||||
|
||||
//rep
|
||||
case 0xc2: {
|
||||
void sCPU::op_rep() {
|
||||
rd.l = op_readpc();
|
||||
last_cycle();
|
||||
op_io();
|
||||
@@ -190,10 +172,9 @@ case 0xc2: {
|
||||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//sep
|
||||
case 0xe2: {
|
||||
void sCPU::op_sep() {
|
||||
rd.l = op_readpc();
|
||||
last_cycle();
|
||||
op_io();
|
||||
@@ -203,10 +184,9 @@ case 0xe2: {
|
||||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//tax
|
||||
case 0xaa: {
|
||||
void sCPU::op_tax() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.x) {
|
||||
@@ -218,10 +198,9 @@ case 0xaa: {
|
||||
regs.p.n = !!(regs.x.w & 0x8000);
|
||||
regs.p.z = (regs.x.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//tay
|
||||
case 0xa8: {
|
||||
void sCPU::op_tay() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.x) {
|
||||
@@ -233,10 +212,9 @@ case 0xa8: {
|
||||
regs.p.n = !!(regs.y.w & 0x8000);
|
||||
regs.p.z = (regs.y.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//txa
|
||||
case 0x8a: {
|
||||
void sCPU::op_txa() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.m) {
|
||||
@@ -248,10 +226,9 @@ case 0x8a: {
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//txy
|
||||
case 0x9b: {
|
||||
void sCPU::op_txy() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.x) {
|
||||
@@ -263,10 +240,9 @@ case 0x9b: {
|
||||
regs.p.n = !!(regs.y.w & 0x8000);
|
||||
regs.p.z = (regs.y.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//tya
|
||||
case 0x98: {
|
||||
void sCPU::op_tya() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.m) {
|
||||
@@ -278,10 +254,9 @@ case 0x98: {
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//tyx
|
||||
case 0xbb: {
|
||||
void sCPU::op_tyx() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.x) {
|
||||
@@ -293,36 +268,32 @@ case 0xbb: {
|
||||
regs.p.n = !!(regs.x.w & 0x8000);
|
||||
regs.p.z = (regs.x.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcd
|
||||
case 0x5b: {
|
||||
void sCPU::op_tcd() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.d.w = regs.a.w;
|
||||
regs.p.n = !!(regs.d.w & 0x8000);
|
||||
regs.p.z = (regs.d.w == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcs
|
||||
case 0x1b: {
|
||||
void sCPU::op_tcs() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.s.w = regs.a.w;
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
} break;
|
||||
}
|
||||
|
||||
//tdc
|
||||
case 0x7b: {
|
||||
void sCPU::op_tdc() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.a.w = regs.d.w;
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//tsc
|
||||
case 0x3b: {
|
||||
void sCPU::op_tsc() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.a.w = regs.s.w;
|
||||
@@ -333,10 +304,9 @@ case 0x3b: {
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//tsx
|
||||
case 0xba: {
|
||||
void sCPU::op_tsx() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.x) {
|
||||
@@ -348,10 +318,9 @@ case 0xba: {
|
||||
regs.p.n = !!(regs.x.w & 0x8000);
|
||||
regs.p.z = (regs.x.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//txs
|
||||
case 0x9a: {
|
||||
void sCPU::op_txs() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.e) {
|
||||
@@ -359,64 +328,56 @@ case 0x9a: {
|
||||
} else {
|
||||
regs.s.w = regs.x.w;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//pha
|
||||
case 0x48: {
|
||||
void sCPU::op_pha() {
|
||||
op_io();
|
||||
if(!regs.p.m)op_writestack(regs.a.h);
|
||||
last_cycle();
|
||||
op_writestack(regs.a.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//phx
|
||||
case 0xda: {
|
||||
void sCPU::op_phx() {
|
||||
op_io();
|
||||
if(!regs.p.x)op_writestack(regs.x.h);
|
||||
last_cycle();
|
||||
op_writestack(regs.x.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//phy
|
||||
case 0x5a: {
|
||||
void sCPU::op_phy() {
|
||||
op_io();
|
||||
if(!regs.p.x)op_writestack(regs.y.h);
|
||||
last_cycle();
|
||||
op_writestack(regs.y.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//phd
|
||||
case 0x0b: {
|
||||
void sCPU::op_phd() {
|
||||
op_io();
|
||||
op_writestackn(regs.d.h);
|
||||
last_cycle();
|
||||
op_writestackn(regs.d.l);
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
} break;
|
||||
}
|
||||
|
||||
//phb
|
||||
case 0x8b: {
|
||||
void sCPU::op_phb() {
|
||||
op_io();
|
||||
last_cycle();
|
||||
op_writestack(regs.db);
|
||||
} break;
|
||||
}
|
||||
|
||||
//phk
|
||||
case 0x4b: {
|
||||
void sCPU::op_phk() {
|
||||
op_io();
|
||||
last_cycle();
|
||||
op_writestack(regs.pc.b);
|
||||
} break;
|
||||
}
|
||||
|
||||
//php
|
||||
case 0x08: {
|
||||
void sCPU::op_php() {
|
||||
op_io();
|
||||
last_cycle();
|
||||
op_writestack(regs.p);
|
||||
} break;
|
||||
}
|
||||
|
||||
//pla
|
||||
case 0x68: {
|
||||
void sCPU::op_pla() {
|
||||
op_io();
|
||||
op_io();
|
||||
if(regs.p.m)last_cycle();
|
||||
@@ -424,16 +385,15 @@ case 0x68: {
|
||||
if(regs.p.m) {
|
||||
regs.p.n = !!(regs.a.l & 0x80);
|
||||
regs.p.z = (regs.a.l == 0);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
last_cycle();
|
||||
regs.a.h = op_readstack();
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//plx
|
||||
case 0xfa: {
|
||||
void sCPU::op_plx() {
|
||||
op_io();
|
||||
op_io();
|
||||
if(regs.p.x)last_cycle();
|
||||
@@ -441,16 +401,15 @@ case 0xfa: {
|
||||
if(regs.p.x) {
|
||||
regs.p.n = !!(regs.x.l & 0x80);
|
||||
regs.p.z = (regs.x.l == 0);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
last_cycle();
|
||||
regs.x.h = op_readstack();
|
||||
regs.p.n = !!(regs.x.w & 0x8000);
|
||||
regs.p.z = (regs.x.w == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//ply
|
||||
case 0x7a: {
|
||||
void sCPU::op_ply() {
|
||||
op_io();
|
||||
op_io();
|
||||
if(regs.p.x)last_cycle();
|
||||
@@ -458,16 +417,15 @@ case 0x7a: {
|
||||
if(regs.p.x) {
|
||||
regs.p.n = !!(regs.y.l & 0x80);
|
||||
regs.p.z = (regs.y.l == 0);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
last_cycle();
|
||||
regs.y.h = op_readstack();
|
||||
regs.p.n = !!(regs.y.w & 0x8000);
|
||||
regs.p.z = (regs.y.w == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//pld
|
||||
case 0x2b: {
|
||||
void sCPU::op_pld() {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.d.l = op_readstackn();
|
||||
@@ -476,20 +434,18 @@ case 0x2b: {
|
||||
regs.p.n = !!(regs.d.w & 0x8000);
|
||||
regs.p.z = (regs.d.w == 0);
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
} break;
|
||||
}
|
||||
|
||||
//plb
|
||||
case 0xab: {
|
||||
void sCPU::op_plb() {
|
||||
op_io();
|
||||
op_io();
|
||||
last_cycle();
|
||||
regs.db = op_readstack();
|
||||
regs.p.n = !!(regs.db & 0x80);
|
||||
regs.p.z = (regs.db == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//plp
|
||||
case 0x28: {
|
||||
void sCPU::op_plp() {
|
||||
op_io();
|
||||
op_io();
|
||||
last_cycle();
|
||||
@@ -499,20 +455,18 @@ case 0x28: {
|
||||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//pea
|
||||
case 0xf4: {
|
||||
void sCPU::op_pea() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_writestackn(aa.h);
|
||||
last_cycle();
|
||||
op_writestackn(aa.l);
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
} break;
|
||||
}
|
||||
|
||||
//pei
|
||||
case 0xd4: {
|
||||
void sCPU::op_pei() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
aa.l = op_readdp(dp);
|
||||
@@ -521,10 +475,9 @@ case 0xd4: {
|
||||
last_cycle();
|
||||
op_writestackn(aa.l);
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
} break;
|
||||
}
|
||||
|
||||
//per
|
||||
case 0x62: {
|
||||
void sCPU::op_per() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
@@ -533,5 +486,5 @@ case 0x62: {
|
||||
last_cycle();
|
||||
op_writestackn(rd.l);
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
} break;
|
||||
}
|
||||
|
||||
|
@@ -1,171 +1,157 @@
|
||||
//bcc
|
||||
case 0x90: {
|
||||
void sCPU::op_bcc() {
|
||||
if(!!regs.p.c)last_cycle();
|
||||
rd.l = op_readpc();
|
||||
if(!regs.p.c) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
op_io_cond6(aa.w);
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//bcs
|
||||
case 0xb0: {
|
||||
void sCPU::op_bcs() {
|
||||
if(!regs.p.c)last_cycle();
|
||||
rd.l = op_readpc();
|
||||
if(regs.p.c) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
op_io_cond6(aa.w);
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//bne
|
||||
case 0xd0: {
|
||||
void sCPU::op_bne() {
|
||||
if(!!regs.p.z)last_cycle();
|
||||
rd.l = op_readpc();
|
||||
if(!regs.p.z) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
op_io_cond6(aa.w);
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//beq
|
||||
case 0xf0: {
|
||||
void sCPU::op_beq() {
|
||||
if(!regs.p.z)last_cycle();
|
||||
rd.l = op_readpc();
|
||||
if(regs.p.z) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
op_io_cond6(aa.w);
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//bpl
|
||||
case 0x10: {
|
||||
void sCPU::op_bpl() {
|
||||
if(!!regs.p.n)last_cycle();
|
||||
rd.l = op_readpc();
|
||||
if(!regs.p.n) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
op_io_cond6(aa.w);
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//bmi
|
||||
case 0x30: {
|
||||
void sCPU::op_bmi() {
|
||||
if(!regs.p.n)last_cycle();
|
||||
rd.l = op_readpc();
|
||||
if(regs.p.n) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
op_io_cond6(aa.w);
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//bvc
|
||||
case 0x50: {
|
||||
void sCPU::op_bvc() {
|
||||
if(!!regs.p.v)last_cycle();
|
||||
rd.l = op_readpc();
|
||||
if(!regs.p.v) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
op_io_cond6(aa.w);
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//bvs
|
||||
case 0x70: {
|
||||
void sCPU::op_bvs() {
|
||||
if(!regs.p.v)last_cycle();
|
||||
rd.l = op_readpc();
|
||||
if(regs.p.v) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
op_io_cond6(aa.w);
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//bra
|
||||
case 0x80: {
|
||||
void sCPU::op_bra() {
|
||||
rd.l = op_readpc();
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
op_io_cond6(aa.w);
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//brl
|
||||
case 0x82: {
|
||||
void sCPU::op_brl() {
|
||||
rd.l = op_readpc();
|
||||
rd.h = op_readpc();
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.pc.w = regs.pc.d + (int16)rd.w;
|
||||
} break;
|
||||
}
|
||||
|
||||
//jmp_addr
|
||||
case 0x4c: {
|
||||
void sCPU::op_jmp_addr() {
|
||||
rd.l = op_readpc();
|
||||
last_cycle();
|
||||
rd.h = op_readpc();
|
||||
regs.pc.w = rd.w;
|
||||
} break;
|
||||
}
|
||||
|
||||
//jmp_long
|
||||
case 0x5c: {
|
||||
void sCPU::op_jmp_long() {
|
||||
rd.l = op_readpc();
|
||||
rd.h = op_readpc();
|
||||
last_cycle();
|
||||
rd.b = op_readpc();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
} break;
|
||||
}
|
||||
|
||||
//jmp_iaddr
|
||||
case 0x6c: {
|
||||
void sCPU::op_jmp_iaddr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readaddr(aa.w);
|
||||
last_cycle();
|
||||
rd.h = op_readaddr(aa.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
} break;
|
||||
}
|
||||
|
||||
//jmp_iaddrx
|
||||
case 0x7c: {
|
||||
void sCPU::op_jmp_iaddrx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
@@ -173,10 +159,9 @@ case 0x7c: {
|
||||
last_cycle();
|
||||
rd.h = op_readpbr(aa.w + regs.x.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
} break;
|
||||
}
|
||||
|
||||
//jmp_iladdr
|
||||
case 0xdc: {
|
||||
void sCPU::op_jmp_iladdr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readaddr(aa.w);
|
||||
@@ -184,10 +169,9 @@ case 0xdc: {
|
||||
last_cycle();
|
||||
rd.b = op_readaddr(aa.w + 2);
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
} break;
|
||||
}
|
||||
|
||||
//jsr_addr
|
||||
case 0x20: {
|
||||
void sCPU::op_jsr_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
@@ -196,10 +180,9 @@ case 0x20: {
|
||||
last_cycle();
|
||||
op_writestack(regs.pc.l);
|
||||
regs.pc.w = aa.w;
|
||||
} break;
|
||||
}
|
||||
|
||||
//jsr_long
|
||||
case 0x22: {
|
||||
void sCPU::op_jsr_long() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_writestackn(regs.pc.b);
|
||||
@@ -211,10 +194,9 @@ case 0x22: {
|
||||
op_writestackn(regs.pc.l);
|
||||
regs.pc.d = aa.d & 0xffffff;
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
} break;
|
||||
}
|
||||
|
||||
//jsr_iaddrx
|
||||
case 0xfc: {
|
||||
void sCPU::op_jsr_iaddrx() {
|
||||
aa.l = op_readpc();
|
||||
op_writestackn(regs.pc.h);
|
||||
op_writestackn(regs.pc.l);
|
||||
@@ -225,10 +207,9 @@ case 0xfc: {
|
||||
rd.h = op_readpbr(aa.w + regs.x.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
} break;
|
||||
}
|
||||
|
||||
//rti
|
||||
case 0x40: {
|
||||
void sCPU::op_rti() {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.p = op_readstack();
|
||||
@@ -242,15 +223,14 @@ case 0x40: {
|
||||
rd.h = op_readstack();
|
||||
if(regs.e) {
|
||||
regs.pc.w = rd.w;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
last_cycle();
|
||||
rd.b = op_readstack();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
} break;
|
||||
}
|
||||
|
||||
//rts
|
||||
case 0x60: {
|
||||
void sCPU::op_rts() {
|
||||
op_io();
|
||||
op_io();
|
||||
rd.l = op_readstack();
|
||||
@@ -259,10 +239,9 @@ case 0x60: {
|
||||
op_io();
|
||||
regs.pc.w = rd.w;
|
||||
regs.pc.w++;
|
||||
} break;
|
||||
}
|
||||
|
||||
//rtl
|
||||
case 0x6b: {
|
||||
void sCPU::op_rtl() {
|
||||
op_io();
|
||||
op_io();
|
||||
rd.l = op_readstackn();
|
||||
@@ -272,5 +251,5 @@ case 0x6b: {
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
regs.pc.w++;
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
} break;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,4 @@
|
||||
//inc
|
||||
case 0x1a: {
|
||||
void sCPU::op_inc() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.m) {
|
||||
@@ -11,10 +10,9 @@ case 0x1a: {
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//inx
|
||||
case 0xe8: {
|
||||
void sCPU::op_inx() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.x) {
|
||||
@@ -26,10 +24,9 @@ case 0xe8: {
|
||||
regs.p.n = !!(regs.x.w & 0x8000);
|
||||
regs.p.z = (regs.x.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//iny
|
||||
case 0xc8: {
|
||||
void sCPU::op_iny() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.x) {
|
||||
@@ -41,10 +38,9 @@ case 0xc8: {
|
||||
regs.p.n = !!(regs.y.w & 0x8000);
|
||||
regs.p.z = (regs.y.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//dec
|
||||
case 0x3a: {
|
||||
void sCPU::op_dec() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.m) {
|
||||
@@ -56,10 +52,9 @@ case 0x3a: {
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//dex
|
||||
case 0xca: {
|
||||
void sCPU::op_dex() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.x) {
|
||||
@@ -71,10 +66,9 @@ case 0xca: {
|
||||
regs.p.n = !!(regs.x.w & 0x8000);
|
||||
regs.p.z = (regs.x.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//dey
|
||||
case 0x88: {
|
||||
void sCPU::op_dey() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.x) {
|
||||
@@ -86,10 +80,9 @@ case 0x88: {
|
||||
regs.p.n = !!(regs.y.w & 0x8000);
|
||||
regs.p.z = (regs.y.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//asl
|
||||
case 0x0a: {
|
||||
void sCPU::op_asl() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.m) {
|
||||
@@ -103,10 +96,9 @@ case 0x0a: {
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//lsr
|
||||
case 0x4a: {
|
||||
void sCPU::op_lsr() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.m) {
|
||||
@@ -120,10 +112,9 @@ case 0x4a: {
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//rol
|
||||
case 0x2a: {
|
||||
void sCPU::op_rol() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
uint16 c = regs.p.c;
|
||||
@@ -140,10 +131,9 @@ case 0x2a: {
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//ror
|
||||
case 0x6a: {
|
||||
void sCPU::op_ror() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
uint16 c;
|
||||
@@ -162,10 +152,9 @@ case 0x6a: {
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//inc_addr
|
||||
case 0xee: {
|
||||
void sCPU::op_inc_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readdbr(aa.w);
|
||||
@@ -176,10 +165,9 @@ case 0xee: {
|
||||
op_writedbr(aa.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//dec_addr
|
||||
case 0xce: {
|
||||
void sCPU::op_dec_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readdbr(aa.w);
|
||||
@@ -190,10 +178,9 @@ case 0xce: {
|
||||
op_writedbr(aa.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//asl_addr
|
||||
case 0x0e: {
|
||||
void sCPU::op_asl_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readdbr(aa.w);
|
||||
@@ -204,10 +191,9 @@ case 0x0e: {
|
||||
op_writedbr(aa.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//lsr_addr
|
||||
case 0x4e: {
|
||||
void sCPU::op_lsr_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readdbr(aa.w);
|
||||
@@ -218,10 +204,9 @@ case 0x4e: {
|
||||
op_writedbr(aa.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//rol_addr
|
||||
case 0x2e: {
|
||||
void sCPU::op_rol_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readdbr(aa.w);
|
||||
@@ -232,10 +217,9 @@ case 0x2e: {
|
||||
op_writedbr(aa.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//ror_addr
|
||||
case 0x6e: {
|
||||
void sCPU::op_ror_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readdbr(aa.w);
|
||||
@@ -246,10 +230,9 @@ case 0x6e: {
|
||||
op_writedbr(aa.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//trb_addr
|
||||
case 0x1c: {
|
||||
void sCPU::op_trb_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readdbr(aa.w);
|
||||
@@ -260,10 +243,9 @@ case 0x1c: {
|
||||
op_writedbr(aa.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//tsb_addr
|
||||
case 0x0c: {
|
||||
void sCPU::op_tsb_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readdbr(aa.w);
|
||||
@@ -274,10 +256,9 @@ case 0x0c: {
|
||||
op_writedbr(aa.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//inc_addrx
|
||||
case 0xfe: {
|
||||
void sCPU::op_inc_addrx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
@@ -289,10 +270,9 @@ case 0xfe: {
|
||||
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//dec_addrx
|
||||
case 0xde: {
|
||||
void sCPU::op_dec_addrx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
@@ -304,10 +284,9 @@ case 0xde: {
|
||||
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//asl_addrx
|
||||
case 0x1e: {
|
||||
void sCPU::op_asl_addrx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
@@ -319,10 +298,9 @@ case 0x1e: {
|
||||
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//lsr_addrx
|
||||
case 0x5e: {
|
||||
void sCPU::op_lsr_addrx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
@@ -334,10 +312,9 @@ case 0x5e: {
|
||||
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//rol_addrx
|
||||
case 0x3e: {
|
||||
void sCPU::op_rol_addrx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
@@ -349,10 +326,9 @@ case 0x3e: {
|
||||
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//ror_addrx
|
||||
case 0x7e: {
|
||||
void sCPU::op_ror_addrx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
@@ -364,10 +340,9 @@ case 0x7e: {
|
||||
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//inc_dp
|
||||
case 0xe6: {
|
||||
void sCPU::op_inc_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
rd.l = op_readdp(dp);
|
||||
@@ -378,10 +353,9 @@ case 0xe6: {
|
||||
op_writedp(dp + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//dec_dp
|
||||
case 0xc6: {
|
||||
void sCPU::op_dec_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
rd.l = op_readdp(dp);
|
||||
@@ -392,10 +366,9 @@ case 0xc6: {
|
||||
op_writedp(dp + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//asl_dp
|
||||
case 0x06: {
|
||||
void sCPU::op_asl_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
rd.l = op_readdp(dp);
|
||||
@@ -406,10 +379,9 @@ case 0x06: {
|
||||
op_writedp(dp + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//lsr_dp
|
||||
case 0x46: {
|
||||
void sCPU::op_lsr_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
rd.l = op_readdp(dp);
|
||||
@@ -420,10 +392,9 @@ case 0x46: {
|
||||
op_writedp(dp + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//rol_dp
|
||||
case 0x26: {
|
||||
void sCPU::op_rol_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
rd.l = op_readdp(dp);
|
||||
@@ -434,10 +405,9 @@ case 0x26: {
|
||||
op_writedp(dp + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//ror_dp
|
||||
case 0x66: {
|
||||
void sCPU::op_ror_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
rd.l = op_readdp(dp);
|
||||
@@ -448,10 +418,9 @@ case 0x66: {
|
||||
op_writedp(dp + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//trb_dp
|
||||
case 0x14: {
|
||||
void sCPU::op_trb_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
rd.l = op_readdp(dp);
|
||||
@@ -462,10 +431,9 @@ case 0x14: {
|
||||
op_writedp(dp + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//tsb_dp
|
||||
case 0x04: {
|
||||
void sCPU::op_tsb_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
rd.l = op_readdp(dp);
|
||||
@@ -476,10 +444,9 @@ case 0x04: {
|
||||
op_writedp(dp + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//inc_dpx
|
||||
case 0xf6: {
|
||||
void sCPU::op_inc_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
@@ -491,10 +458,9 @@ case 0xf6: {
|
||||
op_writedp(dp + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//dec_dpx
|
||||
case 0xd6: {
|
||||
void sCPU::op_dec_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
@@ -506,10 +472,9 @@ case 0xd6: {
|
||||
op_writedp(dp + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//asl_dpx
|
||||
case 0x16: {
|
||||
void sCPU::op_asl_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
@@ -521,10 +486,9 @@ case 0x16: {
|
||||
op_writedp(dp + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//lsr_dpx
|
||||
case 0x56: {
|
||||
void sCPU::op_lsr_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
@@ -536,10 +500,9 @@ case 0x56: {
|
||||
op_writedp(dp + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//rol_dpx
|
||||
case 0x36: {
|
||||
void sCPU::op_rol_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
@@ -551,10 +514,9 @@ case 0x36: {
|
||||
op_writedp(dp + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//ror_dpx
|
||||
case 0x76: {
|
||||
void sCPU::op_ror_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
@@ -566,5 +528,5 @@ case 0x76: {
|
||||
op_writedp(dp + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
|
@@ -1,214 +1,195 @@
|
||||
//sta_addr
|
||||
case 0x8d: {
|
||||
void sCPU::op_sta_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w, regs.a.w);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + 1, regs.a.w >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//stx_addr
|
||||
case 0x8e: {
|
||||
void sCPU::op_stx_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
if(regs.p.x)last_cycle();
|
||||
op_writedbr(aa.w, regs.x.w);
|
||||
if(regs.p.x)break;
|
||||
if(regs.p.x)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + 1, regs.x.w >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sty_addr
|
||||
case 0x8c: {
|
||||
void sCPU::op_sty_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
if(regs.p.x)last_cycle();
|
||||
op_writedbr(aa.w, regs.y.w);
|
||||
if(regs.p.x)break;
|
||||
if(regs.p.x)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + 1, regs.y.w >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//stz_addr
|
||||
case 0x9c: {
|
||||
void sCPU::op_stz_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w, 0x0000);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + 1, 0x0000 >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_addrx
|
||||
case 0x9d: {
|
||||
void sCPU::op_sta_addrx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, regs.a.w);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w + 1, regs.a.w >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//stz_addrx
|
||||
case 0x9e: {
|
||||
void sCPU::op_stz_addrx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, 0x0000);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w + 1, 0x0000 >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_addry
|
||||
case 0x99: {
|
||||
void sCPU::op_sta_addry() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.y.w + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_long
|
||||
case 0x8f: {
|
||||
void sCPU::op_sta_long() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
aa.b = op_readpc();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writelong(aa.d, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writelong(aa.d + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_longx
|
||||
case 0x9f: {
|
||||
void sCPU::op_sta_longx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
aa.b = op_readpc();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writelong(aa.d + regs.x.w, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writelong(aa.d + regs.x.w + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_dp
|
||||
case 0x85: {
|
||||
void sCPU::op_sta_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedp(dp, regs.a.w);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedp(dp + 1, regs.a.w >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//stx_dp
|
||||
case 0x86: {
|
||||
void sCPU::op_stx_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
if(regs.p.x)last_cycle();
|
||||
op_writedp(dp, regs.x.w);
|
||||
if(regs.p.x)break;
|
||||
if(regs.p.x)return;
|
||||
last_cycle();
|
||||
op_writedp(dp + 1, regs.x.w >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sty_dp
|
||||
case 0x84: {
|
||||
void sCPU::op_sty_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
if(regs.p.x)last_cycle();
|
||||
op_writedp(dp, regs.y.w);
|
||||
if(regs.p.x)break;
|
||||
if(regs.p.x)return;
|
||||
last_cycle();
|
||||
op_writedp(dp + 1, regs.y.w >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//stz_dp
|
||||
case 0x64: {
|
||||
void sCPU::op_stz_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedp(dp, 0x0000);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedp(dp + 1, 0x0000 >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_dpx
|
||||
case 0x95: {
|
||||
void sCPU::op_sta_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedp(dp + regs.x.w, regs.a.w);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.x.w + 1, regs.a.w >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sty_dpx
|
||||
case 0x94: {
|
||||
void sCPU::op_sty_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
if(regs.p.x)last_cycle();
|
||||
op_writedp(dp + regs.x.w, regs.y.w);
|
||||
if(regs.p.x)break;
|
||||
if(regs.p.x)return;
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.x.w + 1, regs.y.w >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//stz_dpx
|
||||
case 0x74: {
|
||||
void sCPU::op_stz_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedp(dp + regs.x.w, 0x0000);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.x.w + 1, 0x0000 >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//stx_dpy
|
||||
case 0x96: {
|
||||
void sCPU::op_stx_dpy() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
if(regs.p.x)last_cycle();
|
||||
op_writedp(dp + regs.y.w, regs.x.l);
|
||||
if(regs.p.x)break;
|
||||
if(regs.p.x)return;
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.y.w + 1, regs.x.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_idp
|
||||
case 0x92: {
|
||||
void sCPU::op_sta_idp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
aa.l = op_readdp(dp);
|
||||
aa.h = op_readdp(dp + 1);
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_ildp
|
||||
case 0x87: {
|
||||
void sCPU::op_sta_ildp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
aa.l = op_readdp(dp);
|
||||
@@ -216,13 +197,12 @@ case 0x87: {
|
||||
aa.b = op_readdp(dp + 2);
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writelong(aa.d, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writelong(aa.d + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_idpx
|
||||
case 0x81: {
|
||||
void sCPU::op_sta_idpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
@@ -230,13 +210,12 @@ case 0x81: {
|
||||
aa.h = op_readdp(dp + regs.x.w + 1);
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_idpy
|
||||
case 0x91: {
|
||||
void sCPU::op_sta_idpy() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
aa.l = op_readdp(dp);
|
||||
@@ -244,13 +223,12 @@ case 0x91: {
|
||||
op_io();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.y.w + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_ildpy
|
||||
case 0x97: {
|
||||
void sCPU::op_sta_ildpy() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
aa.l = op_readdp(dp);
|
||||
@@ -258,24 +236,22 @@ case 0x97: {
|
||||
aa.b = op_readdp(dp + 2);
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writelong(aa.d + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writelong(aa.d + regs.y.w + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_sr
|
||||
case 0x83: {
|
||||
void sCPU::op_sta_sr() {
|
||||
sp = op_readpc();
|
||||
op_io();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writesp(sp, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writesp(sp + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_isry
|
||||
case 0x93: {
|
||||
void sCPU::op_sta_isry() {
|
||||
sp = op_readpc();
|
||||
op_io();
|
||||
aa.l = op_readsp(sp);
|
||||
@@ -283,8 +259,8 @@ case 0x93: {
|
||||
op_io();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.y.w + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
|
256
src/cpu/scpu/core/optable.cpp
Normal file
256
src/cpu/scpu/core/optable.cpp
Normal file
@@ -0,0 +1,256 @@
|
||||
optbl[0x69] = &sCPU::op_adc_const;
|
||||
optbl[0x29] = &sCPU::op_and_const;
|
||||
optbl[0xc9] = &sCPU::op_cmp_const;
|
||||
optbl[0xe0] = &sCPU::op_cpx_const;
|
||||
optbl[0xc0] = &sCPU::op_cpy_const;
|
||||
optbl[0x49] = &sCPU::op_eor_const;
|
||||
optbl[0xa9] = &sCPU::op_lda_const;
|
||||
optbl[0xa2] = &sCPU::op_ldx_const;
|
||||
optbl[0xa0] = &sCPU::op_ldy_const;
|
||||
optbl[0x09] = &sCPU::op_ora_const;
|
||||
optbl[0xe9] = &sCPU::op_sbc_const;
|
||||
optbl[0x6d] = &sCPU::op_adc_addr;
|
||||
optbl[0x2d] = &sCPU::op_and_addr;
|
||||
optbl[0x2c] = &sCPU::op_bit_addr;
|
||||
optbl[0xcd] = &sCPU::op_cmp_addr;
|
||||
optbl[0xec] = &sCPU::op_cpx_addr;
|
||||
optbl[0xcc] = &sCPU::op_cpy_addr;
|
||||
optbl[0x4d] = &sCPU::op_eor_addr;
|
||||
optbl[0xad] = &sCPU::op_lda_addr;
|
||||
optbl[0xae] = &sCPU::op_ldx_addr;
|
||||
optbl[0xac] = &sCPU::op_ldy_addr;
|
||||
optbl[0x0d] = &sCPU::op_ora_addr;
|
||||
optbl[0xed] = &sCPU::op_sbc_addr;
|
||||
optbl[0x7d] = &sCPU::op_adc_addrx;
|
||||
optbl[0x3d] = &sCPU::op_and_addrx;
|
||||
optbl[0x3c] = &sCPU::op_bit_addrx;
|
||||
optbl[0xdd] = &sCPU::op_cmp_addrx;
|
||||
optbl[0x5d] = &sCPU::op_eor_addrx;
|
||||
optbl[0xbd] = &sCPU::op_lda_addrx;
|
||||
optbl[0xbc] = &sCPU::op_ldy_addrx;
|
||||
optbl[0x1d] = &sCPU::op_ora_addrx;
|
||||
optbl[0xfd] = &sCPU::op_sbc_addrx;
|
||||
optbl[0x79] = &sCPU::op_adc_addry;
|
||||
optbl[0x39] = &sCPU::op_and_addry;
|
||||
optbl[0xd9] = &sCPU::op_cmp_addry;
|
||||
optbl[0x59] = &sCPU::op_eor_addry;
|
||||
optbl[0xb9] = &sCPU::op_lda_addry;
|
||||
optbl[0xbe] = &sCPU::op_ldx_addry;
|
||||
optbl[0x19] = &sCPU::op_ora_addry;
|
||||
optbl[0xf9] = &sCPU::op_sbc_addry;
|
||||
optbl[0x6f] = &sCPU::op_adc_long;
|
||||
optbl[0x2f] = &sCPU::op_and_long;
|
||||
optbl[0xcf] = &sCPU::op_cmp_long;
|
||||
optbl[0x4f] = &sCPU::op_eor_long;
|
||||
optbl[0xaf] = &sCPU::op_lda_long;
|
||||
optbl[0x0f] = &sCPU::op_ora_long;
|
||||
optbl[0xef] = &sCPU::op_sbc_long;
|
||||
optbl[0x7f] = &sCPU::op_adc_longx;
|
||||
optbl[0x3f] = &sCPU::op_and_longx;
|
||||
optbl[0xdf] = &sCPU::op_cmp_longx;
|
||||
optbl[0x5f] = &sCPU::op_eor_longx;
|
||||
optbl[0xbf] = &sCPU::op_lda_longx;
|
||||
optbl[0x1f] = &sCPU::op_ora_longx;
|
||||
optbl[0xff] = &sCPU::op_sbc_longx;
|
||||
optbl[0x65] = &sCPU::op_adc_dp;
|
||||
optbl[0x25] = &sCPU::op_and_dp;
|
||||
optbl[0x24] = &sCPU::op_bit_dp;
|
||||
optbl[0xc5] = &sCPU::op_cmp_dp;
|
||||
optbl[0xe4] = &sCPU::op_cpx_dp;
|
||||
optbl[0xc4] = &sCPU::op_cpy_dp;
|
||||
optbl[0x45] = &sCPU::op_eor_dp;
|
||||
optbl[0xa5] = &sCPU::op_lda_dp;
|
||||
optbl[0xa6] = &sCPU::op_ldx_dp;
|
||||
optbl[0xa4] = &sCPU::op_ldy_dp;
|
||||
optbl[0x05] = &sCPU::op_ora_dp;
|
||||
optbl[0xe5] = &sCPU::op_sbc_dp;
|
||||
optbl[0x75] = &sCPU::op_adc_dpx;
|
||||
optbl[0x35] = &sCPU::op_and_dpx;
|
||||
optbl[0x34] = &sCPU::op_bit_dpx;
|
||||
optbl[0xd5] = &sCPU::op_cmp_dpx;
|
||||
optbl[0x55] = &sCPU::op_eor_dpx;
|
||||
optbl[0xb5] = &sCPU::op_lda_dpx;
|
||||
optbl[0xb4] = &sCPU::op_ldy_dpx;
|
||||
optbl[0x15] = &sCPU::op_ora_dpx;
|
||||
optbl[0xf5] = &sCPU::op_sbc_dpx;
|
||||
optbl[0xb6] = &sCPU::op_ldx_dpy;
|
||||
optbl[0x72] = &sCPU::op_adc_idp;
|
||||
optbl[0x32] = &sCPU::op_and_idp;
|
||||
optbl[0xd2] = &sCPU::op_cmp_idp;
|
||||
optbl[0x52] = &sCPU::op_eor_idp;
|
||||
optbl[0xb2] = &sCPU::op_lda_idp;
|
||||
optbl[0x12] = &sCPU::op_ora_idp;
|
||||
optbl[0xf2] = &sCPU::op_sbc_idp;
|
||||
optbl[0x61] = &sCPU::op_adc_idpx;
|
||||
optbl[0x21] = &sCPU::op_and_idpx;
|
||||
optbl[0xc1] = &sCPU::op_cmp_idpx;
|
||||
optbl[0x41] = &sCPU::op_eor_idpx;
|
||||
optbl[0xa1] = &sCPU::op_lda_idpx;
|
||||
optbl[0x01] = &sCPU::op_ora_idpx;
|
||||
optbl[0xe1] = &sCPU::op_sbc_idpx;
|
||||
optbl[0x71] = &sCPU::op_adc_idpy;
|
||||
optbl[0x31] = &sCPU::op_and_idpy;
|
||||
optbl[0xd1] = &sCPU::op_cmp_idpy;
|
||||
optbl[0x51] = &sCPU::op_eor_idpy;
|
||||
optbl[0xb1] = &sCPU::op_lda_idpy;
|
||||
optbl[0x11] = &sCPU::op_ora_idpy;
|
||||
optbl[0xf1] = &sCPU::op_sbc_idpy;
|
||||
optbl[0x67] = &sCPU::op_adc_ildp;
|
||||
optbl[0x27] = &sCPU::op_and_ildp;
|
||||
optbl[0xc7] = &sCPU::op_cmp_ildp;
|
||||
optbl[0x47] = &sCPU::op_eor_ildp;
|
||||
optbl[0xa7] = &sCPU::op_lda_ildp;
|
||||
optbl[0x07] = &sCPU::op_ora_ildp;
|
||||
optbl[0xe7] = &sCPU::op_sbc_ildp;
|
||||
optbl[0x77] = &sCPU::op_adc_ildpy;
|
||||
optbl[0x37] = &sCPU::op_and_ildpy;
|
||||
optbl[0xd7] = &sCPU::op_cmp_ildpy;
|
||||
optbl[0x57] = &sCPU::op_eor_ildpy;
|
||||
optbl[0xb7] = &sCPU::op_lda_ildpy;
|
||||
optbl[0x17] = &sCPU::op_ora_ildpy;
|
||||
optbl[0xf7] = &sCPU::op_sbc_ildpy;
|
||||
optbl[0x63] = &sCPU::op_adc_sr;
|
||||
optbl[0x23] = &sCPU::op_and_sr;
|
||||
optbl[0xc3] = &sCPU::op_cmp_sr;
|
||||
optbl[0x43] = &sCPU::op_eor_sr;
|
||||
optbl[0xa3] = &sCPU::op_lda_sr;
|
||||
optbl[0x03] = &sCPU::op_ora_sr;
|
||||
optbl[0xe3] = &sCPU::op_sbc_sr;
|
||||
optbl[0x73] = &sCPU::op_adc_isry;
|
||||
optbl[0x33] = &sCPU::op_and_isry;
|
||||
optbl[0xd3] = &sCPU::op_cmp_isry;
|
||||
optbl[0x53] = &sCPU::op_eor_isry;
|
||||
optbl[0xb3] = &sCPU::op_lda_isry;
|
||||
optbl[0x13] = &sCPU::op_ora_isry;
|
||||
optbl[0xf3] = &sCPU::op_sbc_isry;
|
||||
optbl[0x89] = &sCPU::op_bit_const;
|
||||
optbl[0x8d] = &sCPU::op_sta_addr;
|
||||
optbl[0x8e] = &sCPU::op_stx_addr;
|
||||
optbl[0x8c] = &sCPU::op_sty_addr;
|
||||
optbl[0x9c] = &sCPU::op_stz_addr;
|
||||
optbl[0x9d] = &sCPU::op_sta_addrx;
|
||||
optbl[0x9e] = &sCPU::op_stz_addrx;
|
||||
optbl[0x99] = &sCPU::op_sta_addry;
|
||||
optbl[0x8f] = &sCPU::op_sta_long;
|
||||
optbl[0x9f] = &sCPU::op_sta_longx;
|
||||
optbl[0x85] = &sCPU::op_sta_dp;
|
||||
optbl[0x86] = &sCPU::op_stx_dp;
|
||||
optbl[0x84] = &sCPU::op_sty_dp;
|
||||
optbl[0x64] = &sCPU::op_stz_dp;
|
||||
optbl[0x95] = &sCPU::op_sta_dpx;
|
||||
optbl[0x94] = &sCPU::op_sty_dpx;
|
||||
optbl[0x74] = &sCPU::op_stz_dpx;
|
||||
optbl[0x96] = &sCPU::op_stx_dpy;
|
||||
optbl[0x92] = &sCPU::op_sta_idp;
|
||||
optbl[0x87] = &sCPU::op_sta_ildp;
|
||||
optbl[0x81] = &sCPU::op_sta_idpx;
|
||||
optbl[0x91] = &sCPU::op_sta_idpy;
|
||||
optbl[0x97] = &sCPU::op_sta_ildpy;
|
||||
optbl[0x83] = &sCPU::op_sta_sr;
|
||||
optbl[0x93] = &sCPU::op_sta_isry;
|
||||
optbl[0x1a] = &sCPU::op_inc;
|
||||
optbl[0xe8] = &sCPU::op_inx;
|
||||
optbl[0xc8] = &sCPU::op_iny;
|
||||
optbl[0x3a] = &sCPU::op_dec;
|
||||
optbl[0xca] = &sCPU::op_dex;
|
||||
optbl[0x88] = &sCPU::op_dey;
|
||||
optbl[0x0a] = &sCPU::op_asl;
|
||||
optbl[0x4a] = &sCPU::op_lsr;
|
||||
optbl[0x2a] = &sCPU::op_rol;
|
||||
optbl[0x6a] = &sCPU::op_ror;
|
||||
optbl[0xee] = &sCPU::op_inc_addr;
|
||||
optbl[0xce] = &sCPU::op_dec_addr;
|
||||
optbl[0x0e] = &sCPU::op_asl_addr;
|
||||
optbl[0x4e] = &sCPU::op_lsr_addr;
|
||||
optbl[0x2e] = &sCPU::op_rol_addr;
|
||||
optbl[0x6e] = &sCPU::op_ror_addr;
|
||||
optbl[0x1c] = &sCPU::op_trb_addr;
|
||||
optbl[0x0c] = &sCPU::op_tsb_addr;
|
||||
optbl[0xfe] = &sCPU::op_inc_addrx;
|
||||
optbl[0xde] = &sCPU::op_dec_addrx;
|
||||
optbl[0x1e] = &sCPU::op_asl_addrx;
|
||||
optbl[0x5e] = &sCPU::op_lsr_addrx;
|
||||
optbl[0x3e] = &sCPU::op_rol_addrx;
|
||||
optbl[0x7e] = &sCPU::op_ror_addrx;
|
||||
optbl[0xe6] = &sCPU::op_inc_dp;
|
||||
optbl[0xc6] = &sCPU::op_dec_dp;
|
||||
optbl[0x06] = &sCPU::op_asl_dp;
|
||||
optbl[0x46] = &sCPU::op_lsr_dp;
|
||||
optbl[0x26] = &sCPU::op_rol_dp;
|
||||
optbl[0x66] = &sCPU::op_ror_dp;
|
||||
optbl[0x14] = &sCPU::op_trb_dp;
|
||||
optbl[0x04] = &sCPU::op_tsb_dp;
|
||||
optbl[0xf6] = &sCPU::op_inc_dpx;
|
||||
optbl[0xd6] = &sCPU::op_dec_dpx;
|
||||
optbl[0x16] = &sCPU::op_asl_dpx;
|
||||
optbl[0x56] = &sCPU::op_lsr_dpx;
|
||||
optbl[0x36] = &sCPU::op_rol_dpx;
|
||||
optbl[0x76] = &sCPU::op_ror_dpx;
|
||||
optbl[0x90] = &sCPU::op_bcc;
|
||||
optbl[0xb0] = &sCPU::op_bcs;
|
||||
optbl[0xd0] = &sCPU::op_bne;
|
||||
optbl[0xf0] = &sCPU::op_beq;
|
||||
optbl[0x10] = &sCPU::op_bpl;
|
||||
optbl[0x30] = &sCPU::op_bmi;
|
||||
optbl[0x50] = &sCPU::op_bvc;
|
||||
optbl[0x70] = &sCPU::op_bvs;
|
||||
optbl[0x80] = &sCPU::op_bra;
|
||||
optbl[0x82] = &sCPU::op_brl;
|
||||
optbl[0x4c] = &sCPU::op_jmp_addr;
|
||||
optbl[0x5c] = &sCPU::op_jmp_long;
|
||||
optbl[0x6c] = &sCPU::op_jmp_iaddr;
|
||||
optbl[0x7c] = &sCPU::op_jmp_iaddrx;
|
||||
optbl[0xdc] = &sCPU::op_jmp_iladdr;
|
||||
optbl[0x20] = &sCPU::op_jsr_addr;
|
||||
optbl[0x22] = &sCPU::op_jsr_long;
|
||||
optbl[0xfc] = &sCPU::op_jsr_iaddrx;
|
||||
optbl[0x40] = &sCPU::op_rti;
|
||||
optbl[0x60] = &sCPU::op_rts;
|
||||
optbl[0x6b] = &sCPU::op_rtl;
|
||||
optbl[0xea] = &sCPU::op_nop;
|
||||
optbl[0x42] = &sCPU::op_wdm;
|
||||
optbl[0xeb] = &sCPU::op_xba;
|
||||
optbl[0x54] = &sCPU::op_mvn;
|
||||
optbl[0x44] = &sCPU::op_mvp;
|
||||
optbl[0x00] = &sCPU::op_brk;
|
||||
optbl[0x02] = &sCPU::op_cop;
|
||||
optbl[0xdb] = &sCPU::op_stp;
|
||||
optbl[0xcb] = &sCPU::op_wai;
|
||||
optbl[0xfb] = &sCPU::op_xce;
|
||||
optbl[0x18] = &sCPU::op_clc;
|
||||
optbl[0xd8] = &sCPU::op_cld;
|
||||
optbl[0x58] = &sCPU::op_cli;
|
||||
optbl[0xb8] = &sCPU::op_clv;
|
||||
optbl[0x38] = &sCPU::op_sec;
|
||||
optbl[0xf8] = &sCPU::op_sed;
|
||||
optbl[0x78] = &sCPU::op_sei;
|
||||
optbl[0xc2] = &sCPU::op_rep;
|
||||
optbl[0xe2] = &sCPU::op_sep;
|
||||
optbl[0xaa] = &sCPU::op_tax;
|
||||
optbl[0xa8] = &sCPU::op_tay;
|
||||
optbl[0x8a] = &sCPU::op_txa;
|
||||
optbl[0x9b] = &sCPU::op_txy;
|
||||
optbl[0x98] = &sCPU::op_tya;
|
||||
optbl[0xbb] = &sCPU::op_tyx;
|
||||
optbl[0x5b] = &sCPU::op_tcd;
|
||||
optbl[0x1b] = &sCPU::op_tcs;
|
||||
optbl[0x7b] = &sCPU::op_tdc;
|
||||
optbl[0x3b] = &sCPU::op_tsc;
|
||||
optbl[0xba] = &sCPU::op_tsx;
|
||||
optbl[0x9a] = &sCPU::op_txs;
|
||||
optbl[0x48] = &sCPU::op_pha;
|
||||
optbl[0xda] = &sCPU::op_phx;
|
||||
optbl[0x5a] = &sCPU::op_phy;
|
||||
optbl[0x0b] = &sCPU::op_phd;
|
||||
optbl[0x8b] = &sCPU::op_phb;
|
||||
optbl[0x4b] = &sCPU::op_phk;
|
||||
optbl[0x08] = &sCPU::op_php;
|
||||
optbl[0x68] = &sCPU::op_pla;
|
||||
optbl[0xfa] = &sCPU::op_plx;
|
||||
optbl[0x7a] = &sCPU::op_ply;
|
||||
optbl[0x2b] = &sCPU::op_pld;
|
||||
optbl[0xab] = &sCPU::op_plb;
|
||||
optbl[0x28] = &sCPU::op_plp;
|
||||
optbl[0xf4] = &sCPU::op_pea;
|
||||
optbl[0xd4] = &sCPU::op_pei;
|
||||
optbl[0x62] = &sCPU::op_per;
|
@@ -1,9 +1,9 @@
|
||||
#define CLASS_NAME "sCPU"
|
||||
#include "../../../lib/opgen_s.cpp"
|
||||
#include "../../../lib/opgen_so.cpp"
|
||||
|
||||
int main() {
|
||||
//fph = fopen("op.h", "wb");
|
||||
//fpt = fopen("optable.cpp", "wb");
|
||||
fph = fopen("op.h", "wb");
|
||||
fpt = fopen("optable.cpp", "wb");
|
||||
|
||||
generate("op_read.cpp", "op_read.b");
|
||||
generate("op_write.cpp", "op_write.b");
|
||||
@@ -11,8 +11,8 @@ int main() {
|
||||
generate("op_pc.cpp", "op_pc.b");
|
||||
generate("op_misc.cpp", "op_misc.b");
|
||||
|
||||
//fclose(fph);
|
||||
//fclose(fpt);
|
||||
fclose(fph);
|
||||
fclose(fpt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -83,8 +83,8 @@ inline uint32 sCPU::hdma_iaddr(uint8 i) {
|
||||
*****/
|
||||
|
||||
void sCPU::dma_transfertobusb(uint8 i, uint8 bbus) {
|
||||
if(cartridge.info.sdd1 == true && sdd1->dma_active() == true) {
|
||||
r_mem->write(0x2100 | bbus, sdd1->dma_read());
|
||||
if(cartridge.info.sdd1 == true && sdd1.dma_active() == true) {
|
||||
r_mem->write(0x2100 | bbus, sdd1.dma_read());
|
||||
} else {
|
||||
dma_transfer(0, bbus, dma_addr(i));
|
||||
}
|
||||
@@ -111,8 +111,7 @@ void sCPU::dma_run() {
|
||||
dma_add_clocks(8);
|
||||
|
||||
if(cartridge.info.sdd1 == true) {
|
||||
sdd1->dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr),
|
||||
channel[i].xfersize);
|
||||
sdd1.dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr), channel[i].xfersize);
|
||||
}
|
||||
|
||||
if(tracer.enabled() == true && tracer.cpudma_enabled() == true) {
|
||||
|
@@ -48,5 +48,9 @@ void sCPU::reset() {
|
||||
apu_port[3] = 0x00;
|
||||
}
|
||||
|
||||
sCPU::sCPU() {}
|
||||
sCPU::~sCPU() {}
|
||||
sCPU::sCPU() {
|
||||
#include "core/optable.cpp"
|
||||
}
|
||||
|
||||
sCPU::~sCPU() {
|
||||
}
|
||||
|
@@ -1,8 +1,6 @@
|
||||
class sCPU : public CPU {
|
||||
public:
|
||||
class sCPU : public CPU { public:
|
||||
void enter();
|
||||
|
||||
public:
|
||||
#include "core/core.h"
|
||||
#include "dma/dma.h"
|
||||
#include "memory/memory.h"
|
||||
|
@@ -172,7 +172,7 @@ void sCPU::cycle_edge() {
|
||||
status.hdmainit_triggered = true;
|
||||
hdma_init_reset();
|
||||
if(hdma_enabled_channels()) {
|
||||
add_clocks(12);
|
||||
add_clocks(18);
|
||||
hdma_init();
|
||||
//if(status.dma_state == DMASTATE_INACTIVE) {
|
||||
// status.dma_state = DMASTATE_DMASYNC;
|
||||
@@ -188,7 +188,7 @@ void sCPU::cycle_edge() {
|
||||
if(status.hclock >= 1106) {
|
||||
status.hdma_triggered = true;
|
||||
if(hdma_active_channels()) {
|
||||
add_clocks(12);
|
||||
add_clocks(18);
|
||||
hdma_run();
|
||||
//if(status.dma_state == DMASTATE_INACTIVE) {
|
||||
// status.dma_state = DMASTATE_DMASYNC;
|
||||
@@ -250,7 +250,7 @@ void sCPU::timing_reset() {
|
||||
status.prev_line_clocks = 1364;
|
||||
|
||||
status.line_rendered = false;
|
||||
status.line_render_position = minmax<0, 1112>((uint16)config::ppu.hack.render_scanline_position);
|
||||
status.line_render_position = min(1112, (uint16)config::ppu.hack.render_scanline_position);
|
||||
|
||||
status.dram_refreshed = false;
|
||||
status.dram_refresh_position = (cpu_version == 1) ? 530 : 538;
|
||||
@@ -283,7 +283,7 @@ void sCPU::timing_reset() {
|
||||
//initial latch values for $213c/$213d
|
||||
//[x]0035 : [y]0000 (53.0 -> 212) [lda $2137]
|
||||
//[x]0038 : [y]0000 (56.5 -> 226) [nop : lda $2137]
|
||||
add_clocks(186);
|
||||
//add_clocks(186);
|
||||
}
|
||||
|
||||
#undef ntsc_color_burst_phase_shift_scanline
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 4.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 20 KiB |
586
src/dsp/adsp/adsp.cpp
Normal file
586
src/dsp/adsp/adsp.cpp
Normal file
@@ -0,0 +1,586 @@
|
||||
#include "../../base.h"
|
||||
#include "adsp_tables.cpp"
|
||||
|
||||
void aDSP::enter() { loop:
|
||||
run();
|
||||
goto loop;
|
||||
}
|
||||
|
||||
uint8 aDSP::readb(uint16 addr) {
|
||||
return spcram[addr];
|
||||
}
|
||||
|
||||
void aDSP::writeb(uint16 addr, uint8 data) {
|
||||
spcram[addr] = data;
|
||||
}
|
||||
|
||||
uint16 aDSP::readw(uint16 addr) {
|
||||
return (readb(addr + 0)) | (readb(addr + 1) << 8);
|
||||
}
|
||||
|
||||
void aDSP::writew(uint16 addr, uint16 data) {
|
||||
writeb(addr + 0, data);
|
||||
writeb(addr + 1, data >> 8);
|
||||
}
|
||||
|
||||
uint8 aDSP::read(uint8 addr) {
|
||||
addr &= 127;
|
||||
int v = addr >> 4;
|
||||
int n = addr & 15;
|
||||
|
||||
switch(addr) {
|
||||
case 0x00: case 0x10: case 0x20: case 0x30:
|
||||
case 0x40: case 0x50: case 0x60: case 0x70:
|
||||
return voice[v].VOLL;
|
||||
case 0x01: case 0x11: case 0x21: case 0x31:
|
||||
case 0x41: case 0x51: case 0x61: case 0x71:
|
||||
return voice[v].VOLR;
|
||||
case 0x02: case 0x12: case 0x22: case 0x32:
|
||||
case 0x42: case 0x52: case 0x62: case 0x72:
|
||||
return voice[v].PITCH;
|
||||
case 0x03: case 0x13: case 0x23: case 0x33:
|
||||
case 0x43: case 0x53: case 0x63: case 0x73:
|
||||
return voice[v].PITCH >> 8;
|
||||
case 0x04: case 0x14: case 0x24: case 0x34:
|
||||
case 0x44: case 0x54: case 0x64: case 0x74:
|
||||
return voice[v].SRCN;
|
||||
case 0x05: case 0x15: case 0x25: case 0x35:
|
||||
case 0x45: case 0x55: case 0x65: case 0x75:
|
||||
return voice[v].ADSR1;
|
||||
case 0x06: case 0x16: case 0x26: case 0x36:
|
||||
case 0x46: case 0x56: case 0x66: case 0x76:
|
||||
return voice[v].ADSR2;
|
||||
case 0x07: case 0x17: case 0x27: case 0x37:
|
||||
case 0x47: case 0x57: case 0x67: case 0x77:
|
||||
return voice[v].GAIN;
|
||||
case 0x08: case 0x18: case 0x28: case 0x38:
|
||||
case 0x48: case 0x58: case 0x68: case 0x78:
|
||||
return voice[v].ENVX;
|
||||
case 0x09: case 0x19: case 0x29: case 0x39:
|
||||
case 0x49: case 0x59: case 0x69: case 0x79:
|
||||
return voice[v].OUTX;
|
||||
|
||||
case 0x0f: case 0x1f: case 0x2f: case 0x3f:
|
||||
case 0x4f: case 0x5f: case 0x6f: case 0x7f:
|
||||
return status.FIR[v];
|
||||
|
||||
case 0x0c: return status.MVOLL;
|
||||
case 0x1c: return status.MVOLR;
|
||||
case 0x2c: return status.EVOLL;
|
||||
case 0x3c: return status.EVOLR;
|
||||
case 0x4c: return status.KON;
|
||||
case 0x5c: return status.KOFF;
|
||||
case 0x6c: return status.FLG;
|
||||
case 0x7c: return status.ENDX;
|
||||
|
||||
case 0x0d: return status.EFB;
|
||||
case 0x2d: return status.PMON;
|
||||
case 0x3d: return status.NON;
|
||||
case 0x4d: return status.EON;
|
||||
case 0x5d: return status.DIR;
|
||||
case 0x6d: return status.ESA;
|
||||
case 0x7d: return status.EDL;
|
||||
}
|
||||
|
||||
return dspram[addr];
|
||||
}
|
||||
|
||||
void aDSP::write(uint8 addr, uint8 data) {
|
||||
//0x80-0xff is a read-only mirror of 0x00-0x7f
|
||||
if(addr & 0x80)return;
|
||||
|
||||
int v = addr >> 4;
|
||||
int n = addr & 15;
|
||||
|
||||
switch(addr) {
|
||||
case 0x00: case 0x10: case 0x20: case 0x30:
|
||||
case 0x40: case 0x50: case 0x60: case 0x70:
|
||||
voice[v].VOLL = data;
|
||||
break;
|
||||
case 0x01: case 0x11: case 0x21: case 0x31:
|
||||
case 0x41: case 0x51: case 0x61: case 0x71:
|
||||
voice[v].VOLR = data;
|
||||
break;
|
||||
case 0x02: case 0x12: case 0x22: case 0x32:
|
||||
case 0x42: case 0x52: case 0x62: case 0x72:
|
||||
voice[v].PITCH &= 0xff00;
|
||||
voice[v].PITCH |= data;
|
||||
break;
|
||||
case 0x03: case 0x13: case 0x23: case 0x33:
|
||||
case 0x43: case 0x53: case 0x63: case 0x73:
|
||||
voice[v].PITCH &= 0x00ff;
|
||||
voice[v].PITCH |= data << 8;
|
||||
break;
|
||||
case 0x04: case 0x14: case 0x24: case 0x34:
|
||||
case 0x44: case 0x54: case 0x64: case 0x74:
|
||||
voice[v].SRCN = data;
|
||||
break;
|
||||
case 0x05: case 0x15: case 0x25: case 0x35:
|
||||
case 0x45: case 0x55: case 0x65: case 0x75:
|
||||
voice[v].ADSR1 = data;
|
||||
voice[v].AdjustEnvelope();
|
||||
break;
|
||||
case 0x06: case 0x16: case 0x26: case 0x36:
|
||||
case 0x46: case 0x56: case 0x66: case 0x76:
|
||||
voice[v].ADSR2 = data;
|
||||
//sustain_level = 0-7, 7 is a special case handled by ATTACK envx mode
|
||||
voice[v].env_sustain = (voice[v].ADSR_sus_level() + 1) << 8;
|
||||
voice[v].AdjustEnvelope();
|
||||
break;
|
||||
case 0x07: case 0x17: case 0x27: case 0x37:
|
||||
case 0x47: case 0x57: case 0x67: case 0x77:
|
||||
voice[v].GAIN = data;
|
||||
voice[v].AdjustEnvelope();
|
||||
break;
|
||||
case 0x08: case 0x18: case 0x28: case 0x38:
|
||||
case 0x48: case 0x58: case 0x68: case 0x78:
|
||||
voice[v].ENVX = data;
|
||||
break;
|
||||
case 0x09: case 0x19: case 0x29: case 0x39:
|
||||
case 0x49: case 0x59: case 0x69: case 0x79:
|
||||
voice[v].OUTX = data;
|
||||
break;
|
||||
|
||||
case 0x0f: case 0x1f: case 0x2f: case 0x3f:
|
||||
case 0x4f: case 0x5f: case 0x6f: case 0x7f:
|
||||
status.FIR[v] = data;
|
||||
break;
|
||||
|
||||
case 0x0c: status.MVOLL = data; break;
|
||||
case 0x1c: status.MVOLR = data; break;
|
||||
case 0x2c: status.EVOLL = data; break;
|
||||
case 0x3c: status.EVOLR = data; break;
|
||||
|
||||
case 0x4c:
|
||||
status.KON = data;
|
||||
status.kon = data;
|
||||
break;
|
||||
case 0x5c:
|
||||
status.KOFF = data;
|
||||
break;
|
||||
case 0x6c:
|
||||
status.FLG = data;
|
||||
status.noise_rate = rate_table[data & 0x1f];
|
||||
break;
|
||||
|
||||
case 0x7c:
|
||||
//read-only register, writes clear all bits of ENDX
|
||||
status.ENDX = 0;
|
||||
break;
|
||||
|
||||
case 0x0d: status.EFB = data; break;
|
||||
case 0x2d: status.PMON = data; break;
|
||||
case 0x3d: status.NON = data; break;
|
||||
case 0x4d: status.EON = data; break;
|
||||
case 0x5d: status.DIR = data; break;
|
||||
case 0x6d: status.ESA = data; break;
|
||||
case 0x7d: status.EDL = data; break;
|
||||
}
|
||||
|
||||
dspram[addr] = data;
|
||||
}
|
||||
|
||||
void aDSP::power() {
|
||||
spcram = r_smp->get_spcram_handle();
|
||||
memset(dspram, 0x00, 128);
|
||||
|
||||
for(int v = 0; v < 8; v++) {
|
||||
voice[v].VOLL = 0;
|
||||
voice[v].VOLR = 0;
|
||||
voice[v].PITCH = 0;
|
||||
voice[v].SRCN = 0;
|
||||
voice[v].ADSR1 = 0;
|
||||
voice[v].ADSR2 = 0;
|
||||
voice[v].GAIN = 0;
|
||||
|
||||
status.FIR[v] = 0;
|
||||
}
|
||||
|
||||
status.FLG = 0xe0;
|
||||
status.MVOLL = status.MVOLR = 0;
|
||||
status.EVOLL = status.EVOLR = 0;
|
||||
status.ENDX = 0;
|
||||
status.EFB = 0;
|
||||
status.PMON = 0;
|
||||
status.NON = 0;
|
||||
status.EON = 0;
|
||||
status.DIR = 0;
|
||||
status.ESA = 0;
|
||||
status.EDL = 0;
|
||||
|
||||
status.echo_length = 0;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void aDSP::reset() {
|
||||
status.KON = 0x00;
|
||||
status.KOFF = 0x00;
|
||||
status.FLG |= 0xe0;
|
||||
|
||||
status.kon = 0x00;
|
||||
status.esa = 0x00;
|
||||
|
||||
status.noise_ctr = 0;
|
||||
status.noise_rate = 0;
|
||||
status.noise_sample = 0x4000;
|
||||
|
||||
status.echo_index = 0;
|
||||
status.fir_buffer_index = 0;
|
||||
|
||||
for(int v = 0; v < 8; v++) {
|
||||
voice[v].ENVX = 0;
|
||||
voice[v].OUTX = 0;
|
||||
|
||||
voice[v].pitch_ctr = 0;
|
||||
|
||||
voice[v].brr_index = 0;
|
||||
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2));
|
||||
voice[v].brr_looped = false;
|
||||
voice[v].brr_data[0] = 0;
|
||||
voice[v].brr_data[1] = 0;
|
||||
voice[v].brr_data[2] = 0;
|
||||
voice[v].brr_data[3] = 0;
|
||||
voice[v].brr_data_index = 0;
|
||||
|
||||
voice[v].envx = 0;
|
||||
voice[v].env_ctr = 0;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_state = SILENCE;
|
||||
voice[v].env_mode = DIRECT;
|
||||
|
||||
status.fir_buffer[0][v] = 0;
|
||||
status.fir_buffer[1][v] = 0;
|
||||
}
|
||||
|
||||
dsp_counter = 0;
|
||||
}
|
||||
|
||||
void aDSP::run() {
|
||||
uint8 pmon;
|
||||
int32 sample;
|
||||
int32 msamplel, msampler;
|
||||
int32 esamplel, esampler;
|
||||
int32 fir_samplel, fir_sampler;
|
||||
pmon = status.PMON & ~status.NON & ~1;
|
||||
|
||||
if((dsp_counter++ & 1) == 0) {
|
||||
for(uint v = 0; v < 8; v++) {
|
||||
if(status.soft_reset()) {
|
||||
if(voice[v].env_state != SILENCE) {
|
||||
voice[v].env_state = SILENCE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
}
|
||||
if(status.KOFF & (1 << v)) {
|
||||
if(voice[v].env_state != SILENCE && voice[v].env_state != RELEASE) {
|
||||
voice[v].env_state = RELEASE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
}
|
||||
if(status.kon & (1 << v)) {
|
||||
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2));
|
||||
voice[v].brr_index = -9;
|
||||
voice[v].brr_looped = false;
|
||||
voice[v].brr_data[0] = 0;
|
||||
voice[v].brr_data[1] = 0;
|
||||
voice[v].brr_data[2] = 0;
|
||||
voice[v].brr_data[3] = 0;
|
||||
voice[v].envx = 0;
|
||||
voice[v].env_state = ATTACK;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
}
|
||||
status.ENDX &= ~status.kon;
|
||||
status.kon = 0;
|
||||
}
|
||||
|
||||
/*****
|
||||
* update noise
|
||||
*****/
|
||||
status.noise_ctr += status.noise_rate;
|
||||
if(status.noise_ctr >= 0x7800) {
|
||||
status.noise_ctr -= 0x7800;
|
||||
status.noise_sample = (status.noise_sample >> 1) | (((status.noise_sample << 14) ^ (status.noise_sample << 13)) & 0x4000);
|
||||
}
|
||||
|
||||
msamplel = msampler = 0;
|
||||
esamplel = esampler = 0;
|
||||
|
||||
/*****
|
||||
* process voice channels
|
||||
*****/
|
||||
for(int v = 0; v < 8; v++) {
|
||||
if(voice[v].brr_index < -1) {
|
||||
voice[v].brr_index++;
|
||||
voice[v].OUTX = voice[v].outx = 0;
|
||||
voice[v].ENVX = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(voice[v].brr_index >= 0) {
|
||||
if(pmon & (1 << v)) {
|
||||
voice[v].pitch_ctr += (voice[v].pitch_rate() * (voice[v - 1].outx + 0x8000)) >> 15;
|
||||
} else {
|
||||
voice[v].pitch_ctr += voice[v].pitch_rate();
|
||||
}
|
||||
} else {
|
||||
voice[v].pitch_ctr = 0x3000;
|
||||
voice[v].brr_index = 0;
|
||||
}
|
||||
|
||||
/*****
|
||||
* decode BRR samples
|
||||
*****/
|
||||
while(voice[v].pitch_ctr >= 0) {
|
||||
voice[v].pitch_ctr -= 0x1000;
|
||||
|
||||
voice[v].brr_data_index++;
|
||||
voice[v].brr_data_index &= 3;
|
||||
|
||||
if(voice[v].brr_index == 0) {
|
||||
voice[v].brr_header = readb(voice[v].brr_ptr);
|
||||
|
||||
if(voice[v].brr_header_flags() == BRR_END) {
|
||||
status.ENDX |= (1 << v);
|
||||
voice[v].env_state = SILENCE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
}
|
||||
|
||||
#define S(x) voice[v].brr_data[(voice[v].brr_data_index + (x)) & 3]
|
||||
if(voice[v].env_state != SILENCE) {
|
||||
sample = readb(voice[v].brr_ptr + 1 + (voice[v].brr_index >> 1));
|
||||
if(voice[v].brr_index & 1) {
|
||||
sample = sclip<4>(sample);
|
||||
} else {
|
||||
sample = sclip<4>(sample >> 4);
|
||||
}
|
||||
|
||||
if(voice[v].brr_header_shift() <= 12) {
|
||||
sample = (sample << voice[v].brr_header_shift() >> 1);
|
||||
} else {
|
||||
sample &= ~0x7ff;
|
||||
}
|
||||
|
||||
switch(voice[v].brr_header_filter()) {
|
||||
case 0: //direct
|
||||
break;
|
||||
case 1: //15/16
|
||||
sample += S(-1) + ((-S(-1)) >> 4);
|
||||
break;
|
||||
case 2: //61/32 - 15/16
|
||||
sample += (S(-1) << 1) + ((-((S(-1) << 1) + S(-1))) >> 5)
|
||||
- S(-2) + (S(-2) >> 4);
|
||||
break;
|
||||
case 3: //115/64 - 13/16
|
||||
sample += (S(-1) << 1) + ((-(S(-1) + (S(-1) << 2) + (S(-1) << 3))) >> 6)
|
||||
- S(-2) + (((S(-2) << 1) + S(-2)) >> 4);
|
||||
break;
|
||||
}
|
||||
|
||||
S(0) = sample = sclip<15>(sclamp<16>(sample));
|
||||
} else {
|
||||
S(0) = sample = 0;
|
||||
}
|
||||
|
||||
if(++voice[v].brr_index > 15) {
|
||||
voice[v].brr_index = 0;
|
||||
if(voice[v].brr_header_flags() & BRR_END) {
|
||||
if(voice[v].brr_header_flags() & BRR_LOOP) {
|
||||
status.ENDX |= (1 << v);
|
||||
}
|
||||
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2) + 2);
|
||||
voice[v].brr_looped = true;
|
||||
} else {
|
||||
voice[v].brr_ptr += 9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****
|
||||
* volume envelope adjust
|
||||
*****/
|
||||
voice[v].env_ctr += voice[v].env_rate;
|
||||
|
||||
if(voice[v].env_ctr >= 0x7800) {
|
||||
voice[v].env_ctr -= 0x7800;
|
||||
switch(voice[v].env_mode) {
|
||||
case DIRECT:
|
||||
voice[v].env_rate = 0;
|
||||
break;
|
||||
case LINEAR_DEC:
|
||||
voice[v].envx -= 32;
|
||||
if(voice[v].envx <= 0) {
|
||||
voice[v].envx = 0;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_mode = DIRECT;
|
||||
}
|
||||
break;
|
||||
case LINEAR_INC:
|
||||
voice[v].envx += 32;
|
||||
if(voice[v].envx >= 0x7ff) {
|
||||
voice[v].envx = 0x7ff;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_mode = DIRECT;
|
||||
if(voice[v].ADSR_enabled() && voice[v].env_state == ATTACK) {
|
||||
voice[v].env_state = ((voice[v].env_sustain == 0x800) ? SUSTAIN : DECAY);
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EXP_DEC:
|
||||
//multiply by 255/256ths
|
||||
voice[v].envx -= ((voice[v].envx - 1) >> 8) + 1;
|
||||
if(voice[v].ADSR_enabled() && voice[v].env_state == DECAY && voice[v].envx <= voice[v].env_sustain) {
|
||||
voice[v].env_state = SUSTAIN;
|
||||
voice[v].AdjustEnvelope();
|
||||
} else if(voice[v].envx <= 0) {
|
||||
voice[v].envx = 0;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_mode = DIRECT;
|
||||
}
|
||||
break;
|
||||
case BENT_INC:
|
||||
if(voice[v].envx < 0x600) {
|
||||
voice[v].envx += 32;
|
||||
} else {
|
||||
voice[v].envx += 8;
|
||||
|
||||
if(voice[v].envx >= 0x7ff) {
|
||||
voice[v].envx = 0x7ff;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_mode = DIRECT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FAST_ATTACK:
|
||||
voice[v].envx += 0x400;
|
||||
if(voice[v].envx >= 0x7ff) {
|
||||
voice[v].envx = 0x7ff;
|
||||
|
||||
//attack raises to max envx. if sustain is also set to max envx, skip decay phase
|
||||
voice[v].env_state = ((voice[v].env_sustain == 0x800) ? SUSTAIN : DECAY);
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
break;
|
||||
case RELEASE_DEC:
|
||||
voice[v].envx -= 8;
|
||||
if(voice[v].envx <= 0) {
|
||||
voice[v].env_state = SILENCE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
voice[v].ENVX = voice[v].envx >> 4;
|
||||
|
||||
/*****
|
||||
* gaussian interpolation / noise
|
||||
*****/
|
||||
if(status.NON & (1 << v)) {
|
||||
sample = sclip<15>(status.noise_sample);
|
||||
} else {
|
||||
int32 d = voice[v].pitch_ctr >> 4; //-256 <= sample <= -1
|
||||
sample = ((gaussian_table[ -1 - d] * S(-3)) >> 11);
|
||||
sample += ((gaussian_table[255 - d] * S(-2)) >> 11);
|
||||
sample += ((gaussian_table[512 + d] * S(-1)) >> 11);
|
||||
sample = sclip <15>(sample);
|
||||
sample += ((gaussian_table[256 + d] * S( 0)) >> 11);
|
||||
sample = sclamp<15>(sample);
|
||||
}
|
||||
#undef S
|
||||
|
||||
/*****
|
||||
* envelope / volume adjust
|
||||
*****/
|
||||
sample = (sample * voice[v].envx) >> 11;
|
||||
voice[v].outx = sample << 1;
|
||||
voice[v].OUTX = sample >> 7;
|
||||
|
||||
if(!status.mute()) {
|
||||
msamplel += ((sample * voice[v].VOLL) >> 7) << 1;
|
||||
msampler += ((sample * voice[v].VOLR) >> 7) << 1;
|
||||
}
|
||||
|
||||
if((status.EON & (1 << v)) && status.echo_write()) {
|
||||
esamplel += ((sample * voice[v].VOLL) >> 7) << 1;
|
||||
esampler += ((sample * voice[v].VOLR) >> 7) << 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*****
|
||||
* echo (FIR) adjust
|
||||
*****/
|
||||
#define F(c,x) status.fir_buffer[c][(status.fir_buffer_index + (x)) & 7]
|
||||
status.fir_buffer_index++;
|
||||
F(0,0) = readw((status.esa << 8) + status.echo_index + 0);
|
||||
F(1,0) = readw((status.esa << 8) + status.echo_index + 2);
|
||||
|
||||
fir_samplel = (F(0,-0) * status.FIR[7] +
|
||||
F(0,-1) * status.FIR[6] +
|
||||
F(0,-2) * status.FIR[5] +
|
||||
F(0,-3) * status.FIR[4] +
|
||||
F(0,-4) * status.FIR[3] +
|
||||
F(0,-5) * status.FIR[2] +
|
||||
F(0,-6) * status.FIR[1] +
|
||||
F(0,-7) * status.FIR[0]);
|
||||
|
||||
fir_sampler = (F(1,-0) * status.FIR[7] +
|
||||
F(1,-1) * status.FIR[6] +
|
||||
F(1,-2) * status.FIR[5] +
|
||||
F(1,-3) * status.FIR[4] +
|
||||
F(1,-4) * status.FIR[3] +
|
||||
F(1,-5) * status.FIR[2] +
|
||||
F(1,-6) * status.FIR[1] +
|
||||
F(1,-7) * status.FIR[0]);
|
||||
#undef F
|
||||
|
||||
/*****
|
||||
* update echo buffer
|
||||
*****/
|
||||
if(status.echo_write()) {
|
||||
esamplel += (fir_samplel * status.EFB) >> 14;
|
||||
esampler += (fir_sampler * status.EFB) >> 14;
|
||||
|
||||
esamplel = sclamp<16>(esamplel);
|
||||
esampler = sclamp<16>(esampler);
|
||||
|
||||
writew((status.esa << 8) + status.echo_index + 0, esamplel);
|
||||
writew((status.esa << 8) + status.echo_index + 2, esampler);
|
||||
}
|
||||
|
||||
status.echo_index += 4;
|
||||
if(status.echo_index >= status.echo_length) {
|
||||
status.echo_index = 0;
|
||||
status.echo_length = (status.EDL & 0x0f) << 11;
|
||||
}
|
||||
|
||||
//ESA read occurs at roughly 22/32th sample
|
||||
//ESA fetch occurs at roughly 29/32th sample
|
||||
//as this is not a subsample-level S-DSP emulator,
|
||||
//simulate ~25/32th delay by caching ESA for one
|
||||
//complete sample ...
|
||||
status.esa = status.ESA;
|
||||
|
||||
/*****
|
||||
* main output adjust
|
||||
*****/
|
||||
if(!status.mute()) {
|
||||
msamplel = (msamplel * status.MVOLL) >> 7;
|
||||
msampler = (msampler * status.MVOLR) >> 7;
|
||||
|
||||
msamplel += (fir_samplel * status.EVOLL) >> 14;
|
||||
msampler += (fir_sampler * status.EVOLR) >> 14;
|
||||
|
||||
msamplel = sclamp<16>(msamplel);
|
||||
msampler = sclamp<16>(msampler);
|
||||
}
|
||||
|
||||
snes.audio_update(msamplel, msampler);
|
||||
scheduler.addclocks_dsp(32 * 3);
|
||||
}
|
||||
|
||||
aDSP::aDSP() {}
|
||||
aDSP::~aDSP() {}
|
172
src/dsp/adsp/adsp.h
Normal file
172
src/dsp/adsp/adsp.h
Normal file
@@ -0,0 +1,172 @@
|
||||
class aDSP : public DSP {
|
||||
private:
|
||||
uint8 dspram[128];
|
||||
uint8 *spcram;
|
||||
|
||||
uint32 dsp_counter;
|
||||
|
||||
enum { BRR_END = 1, BRR_LOOP = 2 };
|
||||
|
||||
uint8 readb (uint16 addr);
|
||||
uint16 readw (uint16 addr);
|
||||
void writeb(uint16 addr, uint8 data);
|
||||
void writew(uint16 addr, uint16 data);
|
||||
|
||||
public:
|
||||
static const uint16 rate_table[32];
|
||||
static const int16 gaussian_table[512];
|
||||
|
||||
enum EnvelopeStates {
|
||||
ATTACK,
|
||||
DECAY,
|
||||
SUSTAIN,
|
||||
RELEASE,
|
||||
SILENCE
|
||||
};
|
||||
|
||||
enum EnvelopeModes {
|
||||
DIRECT,
|
||||
LINEAR_DEC,
|
||||
EXP_DEC,
|
||||
LINEAR_INC,
|
||||
BENT_INC,
|
||||
|
||||
FAST_ATTACK,
|
||||
RELEASE_DEC
|
||||
};
|
||||
|
||||
private:
|
||||
struct Status {
|
||||
//$0c,$1c
|
||||
int8 MVOLL, MVOLR;
|
||||
//$2c,$3c
|
||||
int8 EVOLL, EVOLR;
|
||||
//$4c,$5c
|
||||
uint8 KON, KOFF;
|
||||
//$6c
|
||||
uint8 FLG;
|
||||
//$7c
|
||||
uint8 ENDX;
|
||||
//$0d
|
||||
int8 EFB;
|
||||
//$2d,$3d,$4d
|
||||
uint8 PMON, NON, EON;
|
||||
//$5d
|
||||
uint8 DIR;
|
||||
//$6d,$7d
|
||||
uint8 ESA, EDL;
|
||||
|
||||
//$xf
|
||||
int8 FIR[8];
|
||||
|
||||
//internal variables
|
||||
uint8 kon, esa;
|
||||
|
||||
int16 noise_ctr, noise_rate;
|
||||
uint16 noise_sample;
|
||||
|
||||
uint16 echo_index, echo_length;
|
||||
int16 fir_buffer[2][8];
|
||||
uint8 fir_buffer_index;
|
||||
|
||||
//functions
|
||||
bool soft_reset() { return !!(FLG & 0x80); }
|
||||
bool mute() { return !!(FLG & 0x40); }
|
||||
bool echo_write() { return !(FLG & 0x20); }
|
||||
} status;
|
||||
|
||||
struct Voice {
|
||||
//$x0-$x1
|
||||
int8 VOLL, VOLR;
|
||||
//$x2-$x3
|
||||
int16 PITCH;
|
||||
//$x4
|
||||
uint8 SRCN;
|
||||
//$x5-$x7
|
||||
uint8 ADSR1, ADSR2, GAIN;
|
||||
//$x8-$x9
|
||||
uint8 ENVX, OUTX;
|
||||
|
||||
//internal variables
|
||||
int16 pitch_ctr;
|
||||
|
||||
int8 brr_index;
|
||||
uint16 brr_ptr;
|
||||
uint8 brr_header;
|
||||
bool brr_looped;
|
||||
|
||||
int16 brr_data[4];
|
||||
uint8 brr_data_index;
|
||||
|
||||
int16 envx;
|
||||
uint16 env_ctr, env_rate, env_sustain;
|
||||
enum EnvelopeStates env_state;
|
||||
enum EnvelopeModes env_mode;
|
||||
|
||||
int16 outx;
|
||||
|
||||
//functions
|
||||
int16 pitch_rate() { return PITCH & 0x3fff; }
|
||||
|
||||
uint8 brr_header_shift() { return brr_header >> 4; }
|
||||
uint8 brr_header_filter() { return (brr_header >> 2) & 3; }
|
||||
uint8 brr_header_flags() { return brr_header & 3; }
|
||||
|
||||
bool ADSR_enabled() { return !!(ADSR1 & 0x80); }
|
||||
uint8 ADSR_decay() { return (ADSR1 >> 4) & 7; }
|
||||
uint8 ADSR_attack() { return ADSR1 & 15; }
|
||||
uint8 ADSR_sus_level() { return ADSR2 >> 5; }
|
||||
uint8 ADSR_sus_rate() { return ADSR2 & 31; }
|
||||
|
||||
void AdjustEnvelope() {
|
||||
if(env_state == SILENCE) {
|
||||
env_mode = DIRECT;
|
||||
env_rate = 0;
|
||||
envx = 0;
|
||||
} else if(env_state == RELEASE) {
|
||||
env_mode = RELEASE_DEC;
|
||||
env_rate = 0x7800;
|
||||
} else if(ADSR_enabled()) {
|
||||
switch(env_state) {
|
||||
case ATTACK:
|
||||
env_rate = rate_table[(ADSR_attack() << 1) + 1];
|
||||
env_mode = (env_rate == 0x7800) ? FAST_ATTACK : LINEAR_INC;
|
||||
break;
|
||||
case DECAY:
|
||||
env_rate = rate_table[(ADSR_decay() << 1) + 0x10];
|
||||
env_mode = EXP_DEC;
|
||||
break;
|
||||
case SUSTAIN:
|
||||
env_rate = rate_table[ADSR_sus_rate()];
|
||||
env_mode = (env_rate == 0) ? DIRECT : EXP_DEC;
|
||||
break;
|
||||
}
|
||||
} else if(GAIN & 0x80) {
|
||||
switch(GAIN & 0x60) {
|
||||
case 0x00: env_mode = LINEAR_DEC; break;
|
||||
case 0x20: env_mode = EXP_DEC; break;
|
||||
case 0x40: env_mode = LINEAR_INC; break;
|
||||
case 0x60: env_mode = BENT_INC; break;
|
||||
}
|
||||
env_rate = rate_table[GAIN & 0x1f];
|
||||
} else {
|
||||
env_mode = DIRECT;
|
||||
env_rate = 0;
|
||||
envx = (GAIN & 0x7f) << 4;
|
||||
}
|
||||
}
|
||||
} voice[8];
|
||||
|
||||
public:
|
||||
void enter();
|
||||
void run();
|
||||
|
||||
uint8 read (uint8 addr);
|
||||
void write(uint8 addr, uint8 data);
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
aDSP();
|
||||
~aDSP();
|
||||
};
|
@@ -1,11 +1,11 @@
|
||||
const uint16 bDSP::RateTable[32] = {
|
||||
const uint16 aDSP::rate_table[32] = {
|
||||
0x0000, 0x000F, 0x0014, 0x0018, 0x001E, 0x0028, 0x0030, 0x003C,
|
||||
0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180,
|
||||
0x01E0, 0x0280, 0x0300, 0x03C0, 0x0500, 0x0600, 0x0780, 0x0A00,
|
||||
0x0C00, 0x0F00, 0x1400, 0x1800, 0x1E00, 0x2800, 0x3C00, 0x7800
|
||||
};
|
||||
|
||||
const int16 bDSP::GaussTable[512] = {
|
||||
const int16 aDSP::gaussian_table[512] = {
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001,
|
File diff suppressed because it is too large
Load Diff
@@ -1,171 +1,167 @@
|
||||
class bDSP : public DSP {
|
||||
private:
|
||||
uint8 dspram[128];
|
||||
uint8 *spcram;
|
||||
|
||||
uint32 dsp_counter;
|
||||
|
||||
enum { BRR_END = 1, BRR_LOOP = 2 };
|
||||
|
||||
uint8 readb (uint16 addr);
|
||||
uint16 readw (uint16 addr);
|
||||
void writeb(uint16 addr, uint8 data);
|
||||
void writew(uint16 addr, uint16 data);
|
||||
|
||||
public:
|
||||
static const uint16 RateTable[32];
|
||||
static const int16 GaussTable[512];
|
||||
|
||||
enum EnvelopeStates {
|
||||
ATTACK,
|
||||
DECAY,
|
||||
SUSTAIN,
|
||||
RELEASE,
|
||||
SILENCE
|
||||
};
|
||||
|
||||
enum EnvelopeModes {
|
||||
DIRECT,
|
||||
LINEAR_DEC,
|
||||
EXP_DEC,
|
||||
LINEAR_INC,
|
||||
BENT_INC,
|
||||
|
||||
FAST_ATTACK,
|
||||
RELEASE_DEC
|
||||
};
|
||||
|
||||
private:
|
||||
struct Status {
|
||||
//$0c,$1c
|
||||
int8 MVOLL, MVOLR;
|
||||
//$2c,$3c
|
||||
int8 EVOLL, EVOLR;
|
||||
//$4c,$5c
|
||||
uint8 KON, KOFF;
|
||||
//$6c
|
||||
uint8 FLG;
|
||||
//$7c
|
||||
uint8 ENDX;
|
||||
//$0d
|
||||
int8 EFB;
|
||||
//$2d,$3d,$4d
|
||||
uint8 PMON, NON, EON;
|
||||
//$5d
|
||||
uint8 DIR;
|
||||
//$6d,$7d
|
||||
uint8 ESA, EDL;
|
||||
|
||||
//$xf
|
||||
int8 FIR[8];
|
||||
|
||||
//internal variables
|
||||
uint8 kon;
|
||||
bool key_flag;
|
||||
|
||||
int16 noise_ctr, noise_rate;
|
||||
uint16 noise_sample;
|
||||
|
||||
uint16 echo_index, echo_size, echo_target;
|
||||
int16 fir_buffer[2][8];
|
||||
uint8 fir_buffer_index;
|
||||
|
||||
//functions
|
||||
bool soft_reset() { return bool(FLG & 0x80); }
|
||||
bool mute() { return bool(FLG & 0x40); }
|
||||
bool echo_write() { return !(FLG & 0x20); }
|
||||
} status;
|
||||
|
||||
struct Voice {
|
||||
//$x0-$x1
|
||||
int8 VOLL, VOLR;
|
||||
//$x2-$x3
|
||||
int16 PITCH;
|
||||
//$x4
|
||||
uint8 SRCN;
|
||||
//$x5-$x7
|
||||
uint8 ADSR1, ADSR2, GAIN;
|
||||
//$x8-$x9
|
||||
uint8 ENVX, OUTX;
|
||||
|
||||
//internal variables
|
||||
int16 pitch_ctr;
|
||||
|
||||
int8 brr_index;
|
||||
uint16 brr_ptr;
|
||||
uint8 brr_header;
|
||||
bool brr_looped;
|
||||
|
||||
int16 brr_data[4];
|
||||
uint8 brr_data_index;
|
||||
|
||||
int16 envx;
|
||||
uint16 env_ctr, env_rate, env_sustain;
|
||||
enum EnvelopeStates env_state;
|
||||
enum EnvelopeModes env_mode;
|
||||
|
||||
int16 outx;
|
||||
|
||||
//functions
|
||||
int16 pitch_rate() { return PITCH & 0x3fff; }
|
||||
|
||||
uint8 brr_header_shift() { return brr_header >> 4; }
|
||||
uint8 brr_header_filter() { return (brr_header >> 2) & 3; }
|
||||
uint8 brr_header_flags() { return brr_header & 3; }
|
||||
|
||||
bool ADSR_enabled() { return bool(ADSR1 & 0x80); }
|
||||
uint8 ADSR_decay() { return (ADSR1 >> 4) & 7; }
|
||||
uint8 ADSR_attack() { return ADSR1 & 15; }
|
||||
uint8 ADSR_sus_level() { return ADSR2 >> 5; }
|
||||
uint8 ADSR_sus_rate() { return ADSR2 & 31; }
|
||||
|
||||
void AdjustEnvelope() {
|
||||
if(env_state == SILENCE) {
|
||||
env_mode = DIRECT;
|
||||
env_rate = 0;
|
||||
envx = 0;
|
||||
} else if(env_state == RELEASE) {
|
||||
env_mode = RELEASE_DEC;
|
||||
env_rate = 0x7800;
|
||||
} else if(ADSR_enabled()) {
|
||||
switch(env_state) {
|
||||
case ATTACK:
|
||||
env_rate = RateTable[(ADSR_attack() << 1) + 1];
|
||||
env_mode = (env_rate == 0x7800) ? FAST_ATTACK : LINEAR_INC;
|
||||
break;
|
||||
case DECAY:
|
||||
env_rate = RateTable[(ADSR_decay() << 1) + 0x10];
|
||||
env_mode = EXP_DEC;
|
||||
break;
|
||||
case SUSTAIN:
|
||||
env_rate = RateTable[ADSR_sus_rate()];
|
||||
env_mode = (env_rate == 0) ? DIRECT : EXP_DEC;
|
||||
break;
|
||||
}
|
||||
} else if(GAIN & 0x80) {
|
||||
switch(GAIN & 0x60) {
|
||||
case 0x00: env_mode = LINEAR_DEC; break;
|
||||
case 0x20: env_mode = EXP_DEC; break;
|
||||
case 0x40: env_mode = LINEAR_INC; break;
|
||||
case 0x60: env_mode = BENT_INC; break;
|
||||
}
|
||||
env_rate = RateTable[GAIN & 0x1f];
|
||||
} else {
|
||||
env_mode = DIRECT;
|
||||
env_rate = 0;
|
||||
envx = (GAIN & 0x7f) << 4;
|
||||
}
|
||||
}
|
||||
} voice[8];
|
||||
void enter();
|
||||
|
||||
uint8 read( uint8 addr );
|
||||
void write( uint8 addr, uint8 data );
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
bDSP();
|
||||
~bDSP();
|
||||
|
||||
public:
|
||||
uint8 read (uint8 addr);
|
||||
void write(uint8 addr, uint8 data);
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
uint32 run();
|
||||
enum { echo_hist_size = 8 };
|
||||
enum { register_count = 128 };
|
||||
enum { voice_count = 8 };
|
||||
|
||||
enum env_mode_t { env_release, env_attack, env_decay, env_sustain };
|
||||
enum { brr_buf_size = 12 };
|
||||
struct voice_t
|
||||
{
|
||||
int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling)
|
||||
int buf_pos; // place in buffer where next samples will be decoded
|
||||
int interp_pos; // relative fractional position in sample (0x1000 = 1.0)
|
||||
int brr_addr; // address of current BRR block
|
||||
int brr_offset; // current decoding offset in BRR block
|
||||
uint8* regs; // pointer to voice's DSP registers
|
||||
int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc.
|
||||
int kon_delay; // KON delay/current setup phase
|
||||
env_mode_t env_mode;
|
||||
int env; // current envelope level
|
||||
int hidden_env; // used by GAIN mode 7, very obscure quirk
|
||||
uint8 t_envx_out;
|
||||
};
|
||||
private:
|
||||
|
||||
struct state_t
|
||||
{
|
||||
uint8 regs [register_count];
|
||||
|
||||
// Echo history keeps most recent 8 samples
|
||||
int echo_hist [echo_hist_size] [2];
|
||||
int echo_hist_pos;
|
||||
|
||||
int every_other_sample; // toggles every sample
|
||||
int kon; // KON value when last checked
|
||||
int noise;
|
||||
int counter;
|
||||
int echo_offset; // offset from ESA in echo buffer
|
||||
int echo_length; // number of bytes that echo_offset will stop at
|
||||
|
||||
// Hidden registers also written to when main register is written to
|
||||
int new_kon;
|
||||
uint8 endx_buf;
|
||||
uint8 envx_buf;
|
||||
uint8 outx_buf;
|
||||
|
||||
// Temporary state between clocks
|
||||
|
||||
// read once per sample
|
||||
int t_pmon;
|
||||
int t_non;
|
||||
int t_eon;
|
||||
int t_dir;
|
||||
int t_koff;
|
||||
|
||||
// read a few clocks ahead then used
|
||||
int t_brr_next_addr;
|
||||
int t_adsr0;
|
||||
int t_brr_header;
|
||||
int t_brr_byte;
|
||||
int t_srcn;
|
||||
|
||||
// internal state that is recalculated every sample
|
||||
int t_dir_addr;
|
||||
int t_pitch;
|
||||
int t_output;
|
||||
int t_looped;
|
||||
|
||||
// left/right sums
|
||||
int t_main_out [2];
|
||||
int t_echo_out [2];
|
||||
|
||||
voice_t voices [voice_count];
|
||||
};
|
||||
state_t m;
|
||||
uint8* ram;
|
||||
|
||||
unsigned read_counter( int rate );
|
||||
|
||||
void run_envelope( voice_t* const v );
|
||||
void decode_brr( voice_t* v );
|
||||
|
||||
bDSP();
|
||||
~bDSP();
|
||||
void voice_output( voice_t const* v, int ch );
|
||||
void voice_V1( voice_t* const );
|
||||
void voice_V2( voice_t* const );
|
||||
void voice_V3( voice_t* const );
|
||||
void voice_V3a( voice_t* const );
|
||||
void voice_V3b( voice_t* const );
|
||||
void voice_V3c( voice_t* const );
|
||||
void voice_V4( voice_t* const );
|
||||
void voice_V5( voice_t* const );
|
||||
void voice_V6( voice_t* const );
|
||||
void voice_V7( voice_t* const );
|
||||
void voice_V8( voice_t* const );
|
||||
void voice_V9( voice_t* const );
|
||||
void voice_V7_V4_V1( voice_t* const );
|
||||
void voice_V8_V5_V2( voice_t* const );
|
||||
void voice_V9_V6_V3( voice_t* const );
|
||||
|
||||
int calc_echo_output( int ch, int sample );
|
||||
|
||||
// Global registers
|
||||
enum {
|
||||
r_mvoll = 0x0C, r_mvolr = 0x1C,
|
||||
r_evoll = 0x2C, r_evolr = 0x3C,
|
||||
r_kon = 0x4C, r_koff = 0x5C,
|
||||
r_flg = 0x6C, r_endx = 0x7C,
|
||||
r_efb = 0x0D, r_pmon = 0x2D,
|
||||
r_non = 0x3D, r_eon = 0x4D,
|
||||
r_dir = 0x5D, r_esa = 0x6D,
|
||||
r_edl = 0x7D,
|
||||
r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F
|
||||
};
|
||||
|
||||
// Voice registers
|
||||
enum {
|
||||
v_voll = 0x00, v_volr = 0x01,
|
||||
v_pitchl = 0x02, v_pitchh = 0x03,
|
||||
v_srcn = 0x04, v_adsr0 = 0x05,
|
||||
v_adsr1 = 0x06, v_gain = 0x07,
|
||||
v_envx = 0x08, v_outx = 0x09
|
||||
};
|
||||
};
|
||||
|
||||
inline uint8 bDSP::read( uint8 addr )
|
||||
{
|
||||
return m.regs [addr];
|
||||
}
|
||||
|
||||
inline void bDSP::write( uint8 addr, uint8 data )
|
||||
{
|
||||
m.regs [addr] = data;
|
||||
switch ( addr & 0x0F )
|
||||
{
|
||||
case v_envx:
|
||||
m.envx_buf = data;
|
||||
break;
|
||||
|
||||
case v_outx:
|
||||
m.outx_buf = data;
|
||||
break;
|
||||
|
||||
case 0x0C:
|
||||
if ( addr == r_kon )
|
||||
m.new_kon = data;
|
||||
|
||||
if ( addr == r_endx ) // always cleared, regardless of data written
|
||||
{
|
||||
m.endx_buf = 0;
|
||||
m.regs [r_endx] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
32
src/dsp/bdsp_official/bdsp.cpp
Normal file
32
src/dsp/bdsp_official/bdsp.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#include "../../base.h"
|
||||
#include "spc_dsp.h"
|
||||
|
||||
void bDSP::power() {
|
||||
spc_dsp_init(r_smp->get_spcram_handle());
|
||||
spc_dsp_reset();
|
||||
}
|
||||
|
||||
void bDSP::reset() {
|
||||
spc_dsp_soft_reset();
|
||||
}
|
||||
|
||||
uint8 bDSP::read(uint8 addr) {
|
||||
return spc_dsp_read(addr);
|
||||
}
|
||||
|
||||
void bDSP::write(uint8 addr, uint8 data) {
|
||||
spc_dsp_write(addr, data);
|
||||
}
|
||||
|
||||
#define SPC_DSP_CUSTOM_RUN 1 //causes spc_dsp_run() to not be defined since it's huge and we don't need it
|
||||
#define SPC_DSP_OUT_HOOK(left, right) snes.audio_update(left, right);
|
||||
#include "spc_dsp.cpp"
|
||||
|
||||
void bDSP::enter() { loop:
|
||||
#define PHASE(n) scheduler.addclocks_dsp(3);
|
||||
#include "spc_dsp_timing.h"
|
||||
goto loop;
|
||||
}
|
||||
|
||||
bDSP::bDSP() {}
|
||||
bDSP::~bDSP() {}
|
10
src/dsp/bdsp_official/bdsp.h
Normal file
10
src/dsp/bdsp_official/bdsp.h
Normal file
@@ -0,0 +1,10 @@
|
||||
class bDSP : public DSP { public:
|
||||
void enter();
|
||||
uint8 read(uint8 addr);
|
||||
void write(uint8 addr, uint8 data);
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
bDSP();
|
||||
~bDSP();
|
||||
};
|
64
src/dsp/bdsp_official/readme.txt
Normal file
64
src/dsp/bdsp_official/readme.txt
Normal file
@@ -0,0 +1,64 @@
|
||||
Overall operation
|
||||
-----------------
|
||||
This DSP emulator fundamentally emulates the different options the DSP
|
||||
performs on each clock. The pattern of operations repeats every 32
|
||||
clocks (except one minor detail, which repeats every 64 clocks instead).
|
||||
There are three main types of operations:
|
||||
|
||||
- Miscellaneous processing
|
||||
- Voice processing
|
||||
- Echo processing
|
||||
|
||||
Each is done over several clocks, and several operations are done on
|
||||
each clock. Each clock is defined as a separate function, then called
|
||||
from a large switch block in a loop.
|
||||
|
||||
Many times a value is read on one clock but not used until a later
|
||||
clock, so many non-local temporary variables are used in the code to
|
||||
store these values. These are named with t_ to make it clear that they
|
||||
don't store long-term state.
|
||||
|
||||
|
||||
Circular buffers
|
||||
----------------
|
||||
Two circular buffers are used in the code (echo history and BRR decode).
|
||||
Both need efficient index-based access with wrap-around. Things are
|
||||
greatly simplified by repeating the contents of buffer twice, so instead
|
||||
of
|
||||
|
||||
0 1 2 3 4 5 6 7
|
||||
|
||||
it stores
|
||||
|
||||
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
|
||||
|
||||
The position in this case would always be 0 to 7, so reading up to +8
|
||||
won't go outside buffer. This duplication is maintained by simply
|
||||
writing data twice when filling buffer:
|
||||
|
||||
0 1 2 3 4 # 6 7 0 1 2 3 4 # 6 7
|
||||
new data -----^---------------^
|
||||
|
||||
No wrap checking needs to be done when writing either, since the above
|
||||
reasoning holds. When making a state snapshot, only the first copy needs
|
||||
to be saved. When restoring, simply duplicate the data twice.
|
||||
|
||||
|
||||
Code
|
||||
----
|
||||
- Currently all state is in static variables. They have either a t_ or
|
||||
m_ prefix to allow easy migration to a structure.
|
||||
|
||||
- Static state that persists over several samples or more is prefixed
|
||||
with m_.
|
||||
|
||||
- State which is temporary to the current sample is prefixed with t_.
|
||||
These are usually just overwritten with new data on the next sample.
|
||||
These generally correspond to temporaries/registers in actual DSP
|
||||
itself.
|
||||
|
||||
- Minimal stdint.h included in case your system doesn't have one.
|
||||
|
||||
|
||||
--
|
||||
Shay Green <gblargg@gmail.com>
|
828
src/dsp/bdsp_official/spc_dsp.cpp
Normal file
828
src/dsp/bdsp_official/spc_dsp.cpp
Normal file
@@ -0,0 +1,828 @@
|
||||
// http://www.slack.net/~ant/
|
||||
|
||||
#include "spc_dsp.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Copyright (C) 2007 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
// Volume registers and efb are signed! Easy to forget int8_t cast.
|
||||
// Prefixes are to avoid accidental use of locals with same names.
|
||||
|
||||
// Global registers
|
||||
enum {
|
||||
r_mvoll = 0x0C, r_mvolr = 0x1C,
|
||||
r_evoll = 0x2C, r_evolr = 0x3C,
|
||||
r_kon = 0x4C, r_koff = 0x5C,
|
||||
r_flg = 0x6C, r_endx = 0x7C,
|
||||
r_efb = 0x0D, r_pmon = 0x2D,
|
||||
r_non = 0x3D, r_eon = 0x4D,
|
||||
r_dir = 0x5D, r_esa = 0x6D,
|
||||
r_edl = 0x7D,
|
||||
r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F
|
||||
};
|
||||
|
||||
// Voice registers
|
||||
enum {
|
||||
v_voll = 0x00, v_volr = 0x01,
|
||||
v_pitchl = 0x02, v_pitchh = 0x03,
|
||||
v_srcn = 0x04, v_adsr0 = 0x05,
|
||||
v_adsr1 = 0x06, v_gain = 0x07,
|
||||
v_envx = 0x08, v_outx = 0x09
|
||||
};
|
||||
|
||||
// Internal envelope modes
|
||||
enum env_mode_t { env_release, env_attack, env_decay, env_sustain };
|
||||
|
||||
// Internal voice state
|
||||
enum { brr_buf_size = 12 };
|
||||
enum { brr_block_size = 9 };
|
||||
typedef struct voice_t
|
||||
{
|
||||
int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling)
|
||||
int buf_pos; // place in buffer where next samples will be decoded
|
||||
int interp_pos; // relative fractional position in sample (0x1000 = 1.0)
|
||||
int brr_addr; // address of current BRR block
|
||||
int brr_offset; // current decoding offset in BRR block
|
||||
uint8_t* regs; // pointer to voice's DSP registers
|
||||
int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc.
|
||||
int kon_delay; // KON delay/current setup phase
|
||||
enum env_mode_t env_mode;
|
||||
int env; // current envelope level
|
||||
int t_envx_out;
|
||||
int hidden_env; // used by GAIN mode 7, very obscure quirk
|
||||
} voice_t;
|
||||
|
||||
static voice_t m_voice_state [spc_dsp_voice_count];
|
||||
static uint8_t* m_ram; // 64K shared RAM between DSP and SMP
|
||||
spc_dsp_t m_spc_dsp;
|
||||
spc_dsp_sample_t* m_spc_dsp_out_begin;
|
||||
spc_dsp_sample_t* m_spc_dsp_out;
|
||||
spc_dsp_sample_t* m_spc_dsp_out_end;
|
||||
|
||||
// "Member" access
|
||||
#define m m_spc_dsp
|
||||
|
||||
// Access global DSP register
|
||||
#define REG(n) m.regs [r_##n]
|
||||
|
||||
// Access voice DSP register
|
||||
#define VREG(r,n) r [v_##n]
|
||||
|
||||
// if ( io < -32768 ) io = -32768;
|
||||
// if ( io > 32767 ) io = 32767;
|
||||
#define CLAMP16( io )\
|
||||
{\
|
||||
if ( (int16_t) io != io )\
|
||||
io = 0x7FFF ^ (io >> 31);\
|
||||
}
|
||||
|
||||
// Gaussian interpolation
|
||||
|
||||
static short const gauss [512] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
|
||||
2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5,
|
||||
6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
|
||||
11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17,
|
||||
18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27,
|
||||
28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
|
||||
58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77,
|
||||
78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102,
|
||||
104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132,
|
||||
134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168,
|
||||
171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210,
|
||||
212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257,
|
||||
260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311,
|
||||
314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370,
|
||||
374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434,
|
||||
439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504,
|
||||
508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577,
|
||||
582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654,
|
||||
659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732,
|
||||
737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811,
|
||||
816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889,
|
||||
894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965,
|
||||
969, 974, 978, 983, 988, 992, 997,1001,1005,1010,1014,1019,1023,1027,1032,1036,
|
||||
1040,1045,1049,1053,1057,1061,1066,1070,1074,1078,1082,1086,1090,1094,1098,1102,
|
||||
1106,1109,1113,1117,1121,1125,1128,1132,1136,1139,1143,1146,1150,1153,1157,1160,
|
||||
1164,1167,1170,1174,1177,1180,1183,1186,1190,1193,1196,1199,1202,1205,1207,1210,
|
||||
1213,1216,1219,1221,1224,1227,1229,1232,1234,1237,1239,1241,1244,1246,1248,1251,
|
||||
1253,1255,1257,1259,1261,1263,1265,1267,1269,1270,1272,1274,1275,1277,1279,1280,
|
||||
1282,1283,1284,1286,1287,1288,1290,1291,1292,1293,1294,1295,1296,1297,1297,1298,
|
||||
1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305,
|
||||
};
|
||||
|
||||
static inline int interpolate( voice_t const* const v )
|
||||
{
|
||||
// Make pointers into gaussian based on fractional position between samples
|
||||
int offset = v->interp_pos >> 4 & 0xFF;
|
||||
short const* fwd = gauss + 255 - offset;
|
||||
short const* rev = gauss + offset; // mirror left half of gaussian
|
||||
|
||||
int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos];
|
||||
int out;
|
||||
out = (fwd [ 0] * in [0]) >> 11;
|
||||
out += (fwd [256] * in [1]) >> 11;
|
||||
out += (rev [256] * in [2]) >> 11;
|
||||
out = (int16_t) out;
|
||||
out += (rev [ 0] * in [3]) >> 11;
|
||||
|
||||
CLAMP16( out );
|
||||
out &= ~1;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
//// Counters
|
||||
|
||||
enum { simple_counter_range = 2048 * 5 * 3 }; // 30720
|
||||
|
||||
static unsigned short const counter_rates [32] =
|
||||
{
|
||||
simple_counter_range + 1, // never fires
|
||||
2048, 1536,
|
||||
1280, 1024, 768,
|
||||
640, 512, 384,
|
||||
320, 256, 192,
|
||||
160, 128, 96,
|
||||
80, 64, 48,
|
||||
40, 32, 24,
|
||||
20, 16, 12,
|
||||
10, 8, 6,
|
||||
5, 4, 3,
|
||||
2,
|
||||
1
|
||||
};
|
||||
|
||||
static unsigned short const counter_offsets [32] =
|
||||
{
|
||||
1, 0, 1040,
|
||||
536, 0, 1040,
|
||||
536, 0, 1040,
|
||||
536, 0, 1040,
|
||||
536, 0, 1040,
|
||||
536, 0, 1040,
|
||||
536, 0, 1040,
|
||||
536, 0, 1040,
|
||||
536, 0, 1040,
|
||||
536, 0, 1040,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
static inline void init_counters( void ) { }
|
||||
|
||||
static inline void run_counters( void )
|
||||
{
|
||||
if ( --m.counter < 0 )
|
||||
m.counter = simple_counter_range - 1;
|
||||
}
|
||||
|
||||
static inline unsigned read_counter( int rate )
|
||||
{
|
||||
return ((unsigned) m.counter + counter_offsets [rate]) % counter_rates [rate];
|
||||
}
|
||||
|
||||
|
||||
//// Envelope
|
||||
|
||||
static inline void run_envelope( voice_t* const v )
|
||||
{
|
||||
int env = v->env;
|
||||
if ( v->env_mode == env_release ) // 60%
|
||||
{
|
||||
if ( (env -= 0x8) < 0 )
|
||||
env = 0;
|
||||
v->env = env;
|
||||
}
|
||||
else
|
||||
{
|
||||
int rate;
|
||||
int env_data = VREG(v->regs,adsr1);
|
||||
if ( m.t_adsr0 & 0x80 ) // 99% ADSR
|
||||
{
|
||||
if ( v->env_mode >= env_decay ) // 99%
|
||||
{
|
||||
env--;
|
||||
env -= env >> 8;
|
||||
rate = env_data & 0x1F;
|
||||
if ( v->env_mode == env_decay ) // 1%
|
||||
rate = (m.t_adsr0 >> 3 & 0x0E) + 0x10;
|
||||
}
|
||||
else // env_attack
|
||||
{
|
||||
rate = (m.t_adsr0 & 0x0F) * 2 + 1;
|
||||
env += rate < 31 ? 0x20 : 0x400;
|
||||
}
|
||||
}
|
||||
else // GAIN
|
||||
{
|
||||
env_data = VREG(v->regs,gain);
|
||||
int mode = env_data >> 5;
|
||||
if ( mode < 4 ) // direct
|
||||
{
|
||||
env = env_data * 0x10;
|
||||
rate = 31;
|
||||
}
|
||||
else
|
||||
{
|
||||
rate = env_data & 0x1F;
|
||||
if ( mode == 4 ) // 4: linear decrease
|
||||
{
|
||||
env -= 0x20;
|
||||
}
|
||||
else if ( mode < 6 ) // 5: exponential decrease
|
||||
{
|
||||
env--;
|
||||
env -= env >> 8;
|
||||
}
|
||||
else // 6,7: linear increase
|
||||
{
|
||||
env += 0x20;
|
||||
if ( mode > 6 && (unsigned) v->hidden_env >= 0x600 )
|
||||
env += 0x8 - 0x20; // 7: two-slope linear increase
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sustain level
|
||||
if ( (env >> 8) == (env_data >> 5) && v->env_mode == env_decay )
|
||||
v->env_mode = env_sustain;
|
||||
|
||||
v->hidden_env = env;
|
||||
|
||||
// unsigned cast because linear decrease going negative also triggers this
|
||||
if ( (unsigned) env > 0x7FF )
|
||||
{
|
||||
env = (env < 0 ? 0 : 0x7FF);
|
||||
if ( v->env_mode == env_attack )
|
||||
v->env_mode = env_decay;
|
||||
}
|
||||
|
||||
if ( !read_counter( rate ) )
|
||||
v->env = env; // nothing else is controlled by the counter
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// BRR Decoding
|
||||
|
||||
static inline void decode_brr( voice_t* v )
|
||||
{
|
||||
// Arrange the four input nybbles in 0xABCD order for easy decoding
|
||||
int nybbles = m.t_brr_byte * 0x100 + m_ram [(v->brr_addr + v->brr_offset + 1) & 0xFFFF];
|
||||
|
||||
int const header = m.t_brr_header;
|
||||
|
||||
// 0: >>1 1: <<0 2: <<1 ... 12: <<11 13-15: >>4 <<11
|
||||
static unsigned char const shifts [16 * 2] = {
|
||||
13,12,12,12,12,12,12,12,12,12,12, 12, 12, 16, 16, 16,
|
||||
0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11, 11, 11
|
||||
};
|
||||
int const scale = header >> 4;
|
||||
int const right_shift = shifts [scale];
|
||||
int const left_shift = shifts [scale + 16];
|
||||
|
||||
// Write to next four samples in circular buffer
|
||||
int* pos = &v->buf [v->buf_pos];
|
||||
if ( (v->buf_pos += 4) >= brr_buf_size )
|
||||
v->buf_pos = 0;
|
||||
|
||||
// Decode four samples
|
||||
for ( int* end = pos + 4; pos < end; pos++ )
|
||||
{
|
||||
// Extract upper nybble and scale appropriately
|
||||
int s = ((int16_t) nybbles >> right_shift) << left_shift;
|
||||
nybbles <<= 4;
|
||||
|
||||
// Apply IIR filter (8 is the most commonly used)
|
||||
int const filter = header & 0x0C;
|
||||
int const p1 = pos [brr_buf_size - 1];
|
||||
int const p2 = pos [brr_buf_size - 2] >> 1;
|
||||
if ( filter >= 8 )
|
||||
{
|
||||
s += p1;
|
||||
s -= p2;
|
||||
if ( filter == 8 ) // s += p1 * 0.953125 - p2 * 0.46875
|
||||
{
|
||||
s += p2 >> 4;
|
||||
s += (p1 * -3) >> 6;
|
||||
}
|
||||
else // s += p1 * 0.8984375 - p2 * 0.40625
|
||||
{
|
||||
s += (p1 * -13) >> 7;
|
||||
s += (p2 * 3) >> 4;
|
||||
}
|
||||
}
|
||||
else if ( filter ) // s += p1 * 0.46875
|
||||
{
|
||||
s += p1 >> 1;
|
||||
s += (-p1) >> 5;
|
||||
}
|
||||
|
||||
// Adjust and write sample
|
||||
CLAMP16( s );
|
||||
s = (int16_t) (s * 2);
|
||||
pos [brr_buf_size] = pos [0] = s; // second copy simplifies wrap-around
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// Misc
|
||||
|
||||
#define MISC_CLOCK( n ) inline static void misc_##n( void )
|
||||
|
||||
MISC_CLOCK( 27 )
|
||||
{
|
||||
m.t_pmon = REG(pmon) & 0xFE; // voice 0 doesn't support PMON
|
||||
}
|
||||
MISC_CLOCK( 28 )
|
||||
{
|
||||
m.t_non = REG(non);
|
||||
m.t_eon = REG(eon);
|
||||
m.t_dir = REG(dir);
|
||||
}
|
||||
MISC_CLOCK( 29 )
|
||||
{
|
||||
if ( (m.every_other_sample ^= 1) != 0 )
|
||||
m.new_kon &= ~m.kon; // clears KON 63 clocks after it was last read
|
||||
}
|
||||
MISC_CLOCK( 30 )
|
||||
{
|
||||
if ( m.every_other_sample )
|
||||
{
|
||||
m.kon = m.new_kon;
|
||||
m.t_koff = REG(koff) | m.mute_mask;
|
||||
}
|
||||
|
||||
run_counters();
|
||||
|
||||
// Noise
|
||||
if ( !read_counter( REG(flg) & 0x1F ) )
|
||||
{
|
||||
int feedback = (m.noise << 13) ^ (m.noise << 14);
|
||||
m.noise = (feedback & 0x4000) ^ (m.noise >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// Voices
|
||||
|
||||
#define VOICE_CLOCK( n ) static void voice_##n( voice_t* const v )
|
||||
|
||||
inline VOICE_CLOCK( V1 )
|
||||
{
|
||||
m.t_dir_addr = m.t_dir * 0x100 + m.t_srcn * 4;
|
||||
m.t_srcn = VREG(v->regs,srcn);
|
||||
}
|
||||
inline VOICE_CLOCK( V2 )
|
||||
{
|
||||
// Read sample pointer (ignored if not needed)
|
||||
uint8_t const* entry = &m_ram [m.t_dir_addr];
|
||||
if ( !v->kon_delay )
|
||||
entry += 2;
|
||||
m.t_brr_next_addr = entry [1] * 0x100 + entry [0];
|
||||
|
||||
m.t_adsr0 = VREG(v->regs,adsr0);
|
||||
|
||||
// Read pitch, spread over two clocks
|
||||
m.t_pitch = VREG(v->regs,pitchl);
|
||||
}
|
||||
inline VOICE_CLOCK( V3a )
|
||||
{
|
||||
m.t_pitch += (VREG(v->regs,pitchh) & 0x3F) << 8;
|
||||
}
|
||||
inline VOICE_CLOCK( V3b )
|
||||
{
|
||||
// Read BRR header and byte
|
||||
m.t_brr_byte = m_ram [(v->brr_addr + v->brr_offset) & 0xFFFF];
|
||||
m.t_brr_header = m_ram [v->brr_addr]; // brr_addr doesn't need masking
|
||||
}
|
||||
VOICE_CLOCK( V3c )
|
||||
{
|
||||
// Pitch modulation using previous voice's output
|
||||
if ( m.t_pmon & v->vbit )
|
||||
m.t_pitch += ((m.t_output >> 5) * m.t_pitch) >> 10;
|
||||
|
||||
if ( v->kon_delay )
|
||||
{
|
||||
// Get ready to start BRR decoding on next sample
|
||||
if ( v->kon_delay == 5 )
|
||||
{
|
||||
v->brr_addr = m.t_brr_next_addr;
|
||||
v->brr_offset = 1;
|
||||
v->buf_pos = 0;
|
||||
m.t_brr_header = 0; // header is ignored on this sample
|
||||
}
|
||||
|
||||
// Envelope is never run during KON
|
||||
v->env = 0;
|
||||
v->hidden_env = 0;
|
||||
|
||||
// Disable BRR decoding until last three samples
|
||||
v->interp_pos = 0;
|
||||
if ( --v->kon_delay & 3 )
|
||||
v->interp_pos = 0x4000;
|
||||
|
||||
// Pitch is never added during KON
|
||||
m.t_pitch = 0;
|
||||
}
|
||||
|
||||
// Gaussian interpolation
|
||||
int output = interpolate( v );
|
||||
|
||||
// Noise
|
||||
if ( m.t_non & v->vbit )
|
||||
output = (int16_t) (m.noise * 2);
|
||||
|
||||
// Apply envelope
|
||||
m.t_output = (output * v->env) >> 11 & ~1;
|
||||
v->t_envx_out = v->env >> 4;
|
||||
|
||||
// Immediate silence due to end of sample or soft reset
|
||||
if ( REG(flg) & 0x80 || (m.t_brr_header & 3) == 1 )
|
||||
{
|
||||
v->env_mode = env_release;
|
||||
v->env = 0;
|
||||
}
|
||||
|
||||
if ( m.every_other_sample )
|
||||
{
|
||||
// KOFF
|
||||
if ( m.t_koff & v->vbit )
|
||||
v->env_mode = env_release;
|
||||
|
||||
// KON
|
||||
if ( m.kon & v->vbit )
|
||||
{
|
||||
v->kon_delay = 5;
|
||||
v->env_mode = env_attack;
|
||||
}
|
||||
}
|
||||
|
||||
// Run envelope for next sample
|
||||
if ( !v->kon_delay )
|
||||
run_envelope( v );
|
||||
}
|
||||
static inline void voice_output( voice_t const* v, int ch )
|
||||
{
|
||||
// Apply left/right volume
|
||||
int amp = (m.t_output * (int8_t) VREG(v->regs,voll + ch)) >> 7;
|
||||
|
||||
// Add to output total
|
||||
m.t_main_out [ch] += amp;
|
||||
CLAMP16( m.t_main_out [ch] );
|
||||
|
||||
// Optionally add to echo total
|
||||
if ( m.t_eon & v->vbit )
|
||||
{
|
||||
m.t_echo_out [ch] += amp;
|
||||
CLAMP16( m.t_echo_out [ch] );
|
||||
}
|
||||
}
|
||||
VOICE_CLOCK( V4 )
|
||||
{
|
||||
// Decode BRR
|
||||
m.t_looped = 0;
|
||||
if ( v->interp_pos >= 0x4000 )
|
||||
{
|
||||
decode_brr( v );
|
||||
|
||||
if ( (v->brr_offset += 2) >= brr_block_size )
|
||||
{
|
||||
// Start decoding next BRR block
|
||||
assert( v->brr_offset == brr_block_size );
|
||||
v->brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF;
|
||||
if ( m.t_brr_header & 1 )
|
||||
{
|
||||
v->brr_addr = m.t_brr_next_addr;
|
||||
m.t_looped = v->vbit;
|
||||
}
|
||||
v->brr_offset = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply pitch
|
||||
v->interp_pos = (v->interp_pos & 0x3FFF) + m.t_pitch;
|
||||
|
||||
// Keep from getting too far ahead (when using pitch modulation)
|
||||
if ( v->interp_pos > 0x7FFF )
|
||||
v->interp_pos = 0x7FFF;
|
||||
|
||||
// Output left
|
||||
voice_output( v, 0 );
|
||||
}
|
||||
inline VOICE_CLOCK( V5 )
|
||||
{
|
||||
// Output right
|
||||
voice_output( v, 1 );
|
||||
|
||||
// ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier
|
||||
|
||||
m.endx_buf = REG(endx) | m.t_looped;
|
||||
|
||||
// Clear bit in ENDX if KON just began
|
||||
if ( v->kon_delay == 5 )
|
||||
m.endx_buf &= ~v->vbit;
|
||||
}
|
||||
inline VOICE_CLOCK( V6 )
|
||||
{
|
||||
m.outx_buf = m.t_output >> 8;
|
||||
}
|
||||
inline VOICE_CLOCK( V7 )
|
||||
{
|
||||
// Update ENDX
|
||||
REG(endx) = (uint8_t) m.endx_buf;
|
||||
|
||||
m.envx_buf = v->t_envx_out;
|
||||
}
|
||||
inline VOICE_CLOCK( V8 )
|
||||
{
|
||||
// Update OUTX
|
||||
VREG(v->regs,outx) = (uint8_t) m.outx_buf;
|
||||
}
|
||||
inline VOICE_CLOCK( V9 )
|
||||
{
|
||||
// Update ENVX
|
||||
VREG(v->regs,envx) = (uint8_t) m.envx_buf;
|
||||
}
|
||||
|
||||
// Most voices do all these in one clock, so make a handy composite
|
||||
inline VOICE_CLOCK( V3 )
|
||||
{
|
||||
voice_V3a( v );
|
||||
voice_V3b( v );
|
||||
voice_V3c( v );
|
||||
}
|
||||
|
||||
// Common combinations of voice steps on different voices. This greatly reduces
|
||||
// code size and allows everything to be inlined in these functions.
|
||||
VOICE_CLOCK(V7_V4_V1) { voice_V7(v); voice_V1(v+3); voice_V4(v+1); }
|
||||
VOICE_CLOCK(V8_V5_V2) { voice_V8(v); voice_V5(v+1); voice_V2(v+2); }
|
||||
VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); }
|
||||
|
||||
|
||||
//// Echo
|
||||
|
||||
// Current echo buffer pointer for left/right channel
|
||||
#define ECHO_PTR( ch ) (&m_ram [m.t_echo_ptr + ch * 2])
|
||||
|
||||
// Sample in echo history buffer, where 0 is the oldest
|
||||
#define ECHO_FIR( i ) (m.echo_hist_pos [i])
|
||||
|
||||
// Calculate FIR point for left/right channel
|
||||
#define CALC_FIR( i, ch ) ((ECHO_FIR( i + 1 ) [ch] * (int8_t) REG(fir + i * 0x10)) >> 6)
|
||||
|
||||
#define ECHO_CLOCK( n ) inline static void echo_##n( void )
|
||||
|
||||
static inline void echo_read( int ch )
|
||||
{
|
||||
uint8_t const* in = ECHO_PTR( ch );
|
||||
int s = (int8_t) in [1] * 0x100 + in [0];
|
||||
// second copy simplifies wrap-around handling
|
||||
ECHO_FIR( 0 ) [ch] = ECHO_FIR( 8 ) [ch] = s >> 1;
|
||||
}
|
||||
|
||||
ECHO_CLOCK( 22 )
|
||||
{
|
||||
// History
|
||||
if ( ++m.echo_hist_pos >= &m.echo_hist [spc_dsp_echo_hist_size] )
|
||||
m.echo_hist_pos = m.echo_hist;
|
||||
|
||||
m.t_echo_ptr = (m.t_esa * 0x100 + m.echo_offset) & 0xFFFF;
|
||||
echo_read( 0 );
|
||||
|
||||
// FIR (using l and r temporaries below helps compiler optimize)
|
||||
int l = CALC_FIR( 0, 0 );
|
||||
int r = CALC_FIR( 0, 1 );
|
||||
|
||||
m.t_echo_in [0] = l;
|
||||
m.t_echo_in [1] = r;
|
||||
}
|
||||
ECHO_CLOCK( 23 )
|
||||
{
|
||||
int l = CALC_FIR( 1, 0 ) + CALC_FIR( 2, 0 );
|
||||
int r = CALC_FIR( 1, 1 ) + CALC_FIR( 2, 1 );
|
||||
|
||||
m.t_echo_in [0] += l;
|
||||
m.t_echo_in [1] += r;
|
||||
|
||||
echo_read( 1 );
|
||||
}
|
||||
ECHO_CLOCK( 24 )
|
||||
{
|
||||
int l = CALC_FIR( 3, 0 ) + CALC_FIR( 4, 0 ) + CALC_FIR( 5, 0 );
|
||||
int r = CALC_FIR( 3, 1 ) + CALC_FIR( 4, 1 ) + CALC_FIR( 5, 1 );
|
||||
|
||||
m.t_echo_in [0] += l;
|
||||
m.t_echo_in [1] += r;
|
||||
}
|
||||
ECHO_CLOCK( 25 )
|
||||
{
|
||||
int l = m.t_echo_in [0] + CALC_FIR( 6, 0 );
|
||||
int r = m.t_echo_in [1] + CALC_FIR( 6, 1 );
|
||||
|
||||
l = (int16_t) l;
|
||||
r = (int16_t) r;
|
||||
|
||||
l += (int16_t) CALC_FIR( 7, 0 );
|
||||
r += (int16_t) CALC_FIR( 7, 1 );
|
||||
|
||||
CLAMP16( l );
|
||||
CLAMP16( r );
|
||||
|
||||
m.t_echo_in [0] = l & ~1;
|
||||
m.t_echo_in [1] = r & ~1;
|
||||
}
|
||||
static inline int echo_output( int ch )
|
||||
{
|
||||
int out = (int16_t) ((m.t_main_out [ch] * (int8_t) REG(mvoll + ch * 0x10)) >> 7) +
|
||||
(int16_t) ((m.t_echo_in [ch] * (int8_t) REG(evoll + ch * 0x10)) >> 7);
|
||||
CLAMP16( out );
|
||||
return out;
|
||||
}
|
||||
ECHO_CLOCK( 26 )
|
||||
{
|
||||
// Left output volumes
|
||||
// (save sample for next clock so we can output both together)
|
||||
m.t_main_out [0] = echo_output( 0 );
|
||||
|
||||
// Echo feedback
|
||||
int l = m.t_echo_out [0] + (int16_t) ((m.t_echo_in [0] * (int8_t) REG(efb)) >> 7);
|
||||
int r = m.t_echo_out [1] + (int16_t) ((m.t_echo_in [1] * (int8_t) REG(efb)) >> 7);
|
||||
|
||||
CLAMP16( l );
|
||||
CLAMP16( r );
|
||||
|
||||
m.t_echo_out [0] = l & ~1;
|
||||
m.t_echo_out [1] = r & ~1;
|
||||
}
|
||||
ECHO_CLOCK( 27 )
|
||||
{
|
||||
// Output
|
||||
int outl = m.t_main_out [0];
|
||||
int outr = echo_output( 1 );
|
||||
m.t_main_out [0] = 0;
|
||||
m.t_main_out [1] = 0;
|
||||
|
||||
// TODO: global muting isn't this simple (turns DAC on and off
|
||||
// or something, causing small ~37-sample pulse when first muted)
|
||||
if ( REG(flg) & 0x40 )
|
||||
{
|
||||
outl = 0;
|
||||
outr = 0;
|
||||
}
|
||||
|
||||
// Output sample to DAC
|
||||
#ifdef SPC_DSP_OUT_HOOK
|
||||
SPC_DSP_OUT_HOOK( outl, outr );
|
||||
#else
|
||||
spc_dsp_sample_t* out = m_spc_dsp_out;
|
||||
assert( !out || out < m_spc_dsp_out_end ); // fails if output buffer is too small
|
||||
if ( out != m_spc_dsp_out_end )
|
||||
{
|
||||
out [0] = outl;
|
||||
out [1] = outr;
|
||||
m_spc_dsp_out = out + 2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
ECHO_CLOCK( 28 )
|
||||
{
|
||||
m.t_echo_enabled = REG(flg);
|
||||
}
|
||||
static inline void echo_write( int ch )
|
||||
{
|
||||
if ( !(m.t_echo_enabled & 0x20) )
|
||||
{
|
||||
uint8_t* out = ECHO_PTR( ch );
|
||||
int s = m.t_echo_out [ch];
|
||||
out [0] = (uint8_t) s;
|
||||
out [1] = (uint8_t) (s >> 8);
|
||||
}
|
||||
m.t_echo_out [ch] = 0;
|
||||
}
|
||||
ECHO_CLOCK( 29 )
|
||||
{
|
||||
m.t_esa = REG(esa);
|
||||
|
||||
if ( !m.echo_offset )
|
||||
m.echo_length = (REG(edl) & 0x0F) * 0x800;
|
||||
|
||||
m.echo_offset += 4;
|
||||
if ( m.echo_offset >= m.echo_length )
|
||||
m.echo_offset = 0;
|
||||
|
||||
// Write left echo
|
||||
echo_write( 0 );
|
||||
|
||||
m.t_echo_enabled = REG(flg);
|
||||
}
|
||||
ECHO_CLOCK( 30 )
|
||||
{
|
||||
// Write right echo
|
||||
echo_write( 1 );
|
||||
}
|
||||
|
||||
|
||||
//// Timing
|
||||
|
||||
#if !SPC_DSP_CUSTOM_RUN
|
||||
|
||||
void spc_dsp_run( int clocks_remain )
|
||||
{
|
||||
assert( clocks_remain > 0 );
|
||||
|
||||
int const phase = m.phase;
|
||||
m.phase = (phase + clocks_remain) & 31;
|
||||
switch ( phase )
|
||||
{
|
||||
loop:
|
||||
|
||||
#define PHASE( n ) if ( n && !--clocks_remain ) break; case n:
|
||||
#include "spc_dsp_timing.h"
|
||||
#undef PHASE
|
||||
|
||||
if ( --clocks_remain )
|
||||
goto loop;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//// Setup
|
||||
|
||||
void spc_dsp_reset( void )
|
||||
{
|
||||
// Clear everything to zero, then set things which must be non-zero
|
||||
memset( m_voice_state, 0, sizeof m_voice_state );
|
||||
memset( &m_spc_dsp, 0, sizeof m_spc_dsp );
|
||||
|
||||
m.noise = 1;
|
||||
m.echo_hist_pos = m.echo_hist;
|
||||
m.every_other_sample = 1;
|
||||
init_counters();
|
||||
|
||||
int i;
|
||||
for ( i = spc_dsp_voice_count; --i >= 0; )
|
||||
{
|
||||
voice_t* v = &m_voice_state [i];
|
||||
v->regs = &m.regs [i * 0x10];
|
||||
v->vbit = 1 << i;
|
||||
v->brr_offset = 1;
|
||||
}
|
||||
|
||||
REG(flg) = 0xE0;
|
||||
}
|
||||
|
||||
void spc_dsp_soft_reset( void )
|
||||
{
|
||||
// TODO: doesn't reset everything
|
||||
spc_dsp_reset();
|
||||
}
|
||||
|
||||
void spc_dsp_init( void* ram_64k )
|
||||
{
|
||||
m_ram = (uint8_t*) ram_64k;
|
||||
spc_dsp_reset();
|
||||
|
||||
#if INT_MAX < 0x7FFFFFFF
|
||||
#error "Requires that int have at least 32 bits"
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
// be sure this sign-extends
|
||||
assert( (int16_t) 0x8000 == -0x8000 );
|
||||
|
||||
// be sure right shift preserves sign
|
||||
assert( (-1 >> 1) == -1 );
|
||||
|
||||
// check clamp macro
|
||||
int i;
|
||||
i = +0x8000; CLAMP16( i ); assert( i == +0x7FFF );
|
||||
i = -0x8001; CLAMP16( i ); assert( i == -0x8000 );
|
||||
#endif
|
||||
}
|
||||
|
||||
void spc_dsp_load( uint8_t const regs [spc_dsp_register_count] )
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i < 0x80; i++ )
|
||||
spc_dsp_write( i, regs [i] );
|
||||
m.t_esa = regs [r_esa];
|
||||
m.t_dir = regs [r_dir];
|
||||
}
|
162
src/dsp/bdsp_official/spc_dsp.h
Normal file
162
src/dsp/bdsp_official/spc_dsp.h
Normal file
@@ -0,0 +1,162 @@
|
||||
// SNES SPC-700 DSP emulator
|
||||
|
||||
#ifndef SPC_DSP_H
|
||||
#define SPC_DSP_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
//// Setup
|
||||
|
||||
// Initializes DSP and has it use the 64K RAM provided
|
||||
void spc_dsp_init( void* ram_64k );
|
||||
|
||||
// Restores DSP registers using supplied values
|
||||
enum { spc_dsp_register_count = 128 };
|
||||
void spc_dsp_load( uint8_t const regs [spc_dsp_register_count] );
|
||||
|
||||
// Mutes voice n if bit 1<<b is set
|
||||
enum { spc_dsp_voice_count = 8 };
|
||||
static void spc_dsp_mute_voices( int mask );
|
||||
|
||||
// Sets destination for output samples. If out is NULL or out_size is 0,
|
||||
// doesn't generate any.
|
||||
typedef short spc_dsp_sample_t;
|
||||
static void spc_dsp_set_output( spc_dsp_sample_t* out, int out_size );
|
||||
|
||||
// Number of samples written to output since it was last set, always
|
||||
// a multiple of 2
|
||||
static int spc_dsp_sample_count( void );
|
||||
|
||||
|
||||
//// Emulation
|
||||
|
||||
// Resets DSP to power-on state. Does not affect anything set by above functions.
|
||||
void spc_dsp_reset( void );
|
||||
|
||||
// Emulates pressing reset switch on SNES
|
||||
void spc_dsp_soft_reset( void );
|
||||
|
||||
// Reads/writes DSP registers. For accuracy, you must first call spc_run_dsp()
|
||||
// to catch the DSP up to present.
|
||||
static int spc_dsp_read( int addr );
|
||||
static void spc_dsp_write( int addr, int data );
|
||||
|
||||
// Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks
|
||||
// a pair of samples will be generated.
|
||||
void spc_dsp_run( int clock_count );
|
||||
|
||||
|
||||
//// private
|
||||
|
||||
enum { spc_dsp_echo_hist_size = 8 };
|
||||
|
||||
extern spc_dsp_sample_t* m_spc_dsp_out_begin;
|
||||
extern spc_dsp_sample_t* m_spc_dsp_out;
|
||||
extern spc_dsp_sample_t* m_spc_dsp_out_end;
|
||||
|
||||
typedef struct spc_dsp_t
|
||||
{
|
||||
uint8_t regs [spc_dsp_register_count];
|
||||
|
||||
// Echo history keeps most recent 8 samples (twice the size to simplify wrap handling)
|
||||
int echo_hist [spc_dsp_echo_hist_size * 2] [2];
|
||||
int (*echo_hist_pos) [2]; // &echo_hist [0 to 7]
|
||||
int mute_mask;
|
||||
|
||||
int every_other_sample; // toggles every sample
|
||||
int kon; // KON value when last checked
|
||||
int noise;
|
||||
int counter;
|
||||
int echo_offset; // offset from ESA in echo buffer
|
||||
int echo_length; // number of bytes that echo_offset will stop at
|
||||
int phase; // next clock cycle to run (0-31)
|
||||
|
||||
// Hidden registers also written to when main register is written to
|
||||
int new_kon;
|
||||
int endx_buf;
|
||||
int envx_buf;
|
||||
int outx_buf;
|
||||
|
||||
// Temporary state between clocks
|
||||
|
||||
// read once per sample
|
||||
int t_pmon;
|
||||
int t_non;
|
||||
int t_eon;
|
||||
int t_dir;
|
||||
int t_koff;
|
||||
|
||||
// read a few clocks ahead then used
|
||||
int t_brr_next_addr;
|
||||
int t_adsr0;
|
||||
int t_brr_header;
|
||||
int t_brr_byte;
|
||||
int t_srcn;
|
||||
int t_esa;
|
||||
int t_echo_enabled;
|
||||
|
||||
// internal state that is recalculated every sample
|
||||
int t_dir_addr;
|
||||
int t_pitch;
|
||||
int t_output;
|
||||
int t_looped;
|
||||
int t_echo_ptr;
|
||||
|
||||
// left/right sums
|
||||
int t_main_out [2];
|
||||
int t_echo_out [2];
|
||||
int t_echo_in [2];
|
||||
|
||||
} spc_dsp_t;
|
||||
extern spc_dsp_t m_spc_dsp;
|
||||
|
||||
static inline int spc_dsp_read( int addr )
|
||||
{
|
||||
assert( (unsigned) addr < spc_dsp_register_count );
|
||||
return m_spc_dsp.regs [addr];
|
||||
}
|
||||
|
||||
static inline void spc_dsp_write( int addr, int data )
|
||||
{
|
||||
assert( (unsigned) addr < spc_dsp_register_count );
|
||||
|
||||
m_spc_dsp.regs [addr] = data;
|
||||
switch ( addr & 0x0F )
|
||||
{
|
||||
case 0x08:
|
||||
m_spc_dsp.envx_buf = data;
|
||||
break;
|
||||
|
||||
case 0x09:
|
||||
m_spc_dsp.outx_buf = data;
|
||||
break;
|
||||
|
||||
case 0x0C:
|
||||
if ( addr == 0x4C ) // KON
|
||||
m_spc_dsp.new_kon = data;
|
||||
|
||||
if ( addr == 0x7C ) // ENDX, write always clears it regardless of data
|
||||
{
|
||||
m_spc_dsp.endx_buf = 0;
|
||||
m_spc_dsp.regs [0x7C] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void spc_dsp_mute_voices( int mask ) { m_spc_dsp.mute_mask = mask; }
|
||||
|
||||
static inline void spc_dsp_set_output( spc_dsp_sample_t* out, int out_size )
|
||||
{
|
||||
assert( out_size % 2 == 0 ); // must be even
|
||||
m_spc_dsp_out_begin = out;
|
||||
m_spc_dsp_out = out;
|
||||
if ( out )
|
||||
out += out_size;
|
||||
m_spc_dsp_out_end = out;
|
||||
}
|
||||
|
||||
static inline int spc_dsp_sample_count( void ) { return m_spc_dsp_out - m_spc_dsp_out_begin; }
|
||||
|
||||
#endif
|
46
src/dsp/bdsp_official/spc_dsp_timing.h
Normal file
46
src/dsp/bdsp_official/spc_dsp_timing.h
Normal file
@@ -0,0 +1,46 @@
|
||||
// Execute clock for a particular voice
|
||||
#define V( clock, voice ) voice_##clock( &m_voice_state [voice] );
|
||||
|
||||
/* The most common sequence of clocks uses composite operations
|
||||
for efficiency. For example, the following are equivalent to the
|
||||
individual steps on the right:
|
||||
|
||||
V(2_31 ,2) -> V( 2,2) V(31,3)
|
||||
V(3_0_29,2) -> V( 3,2) V( 0,3) V(29,4)
|
||||
V(4_1_30,2) -> V( 4,2) V( 1,3) V(30,4) */
|
||||
|
||||
// Voice 0 1 2 3 4 5 6 7
|
||||
PHASE( 0) V(V5,0)V(V2,1)
|
||||
PHASE( 1) V(V6,0)V(V3,1)
|
||||
PHASE( 2) V(V7_V4_V1,0)
|
||||
PHASE( 3) V(V8_V5_V2,0)
|
||||
PHASE( 4) V(V9_V6_V3,0)
|
||||
PHASE( 5) V(V7_V4_V1,1)
|
||||
PHASE( 6) V(V8_V5_V2,1)
|
||||
PHASE( 7) V(V9_V6_V3,1)
|
||||
PHASE( 8) V(V7_V4_V1,2)
|
||||
PHASE( 9) V(V8_V5_V2,2)
|
||||
PHASE(10) V(V9_V6_V3,2)
|
||||
PHASE(11) V(V7_V4_V1,3)
|
||||
PHASE(12) V(V8_V5_V2,3)
|
||||
PHASE(13) V(V9_V6_V3,3)
|
||||
PHASE(14) V(V7_V4_V1,4)
|
||||
PHASE(15) V(V8_V5_V2,4)
|
||||
PHASE(16) V(V9_V6_V3,4)
|
||||
PHASE(17) V(V1,0) V(V7,5)V(V4,6)
|
||||
PHASE(18) V(V8_V5_V2,5)
|
||||
PHASE(19) V(V9_V6_V3,5)
|
||||
PHASE(20) V(V1,1) V(V7,6)V(V4,7)
|
||||
PHASE(21) V(V8,6)V(V5,7) V(V2,0) // t_brr_next_addr order dependency
|
||||
PHASE(22) V(V3a,0) V(V9,6)V(V6,7) echo_22();
|
||||
PHASE(23) V(V7,7) echo_23();
|
||||
PHASE(24) V(V8,7) echo_24();
|
||||
PHASE(25) V(V3b,0) V(V9,7) echo_25();
|
||||
PHASE(26) echo_26();
|
||||
PHASE(27) misc_27(); echo_27();
|
||||
PHASE(28) misc_28(); echo_28();
|
||||
PHASE(29) misc_29(); echo_29();
|
||||
PHASE(30) misc_30();V(V3c,0) echo_30();
|
||||
PHASE(31) V(V4,0) V(V1,2)
|
||||
|
||||
#undef V
|
43
src/dsp/bdsp_official/spc_endian.h
Normal file
43
src/dsp/bdsp_official/spc_endian.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// Byte order handling
|
||||
|
||||
#ifndef SPC_ENDIAN_H
|
||||
#define SPC_ENDIAN_H
|
||||
|
||||
//#include <stdint.h>
|
||||
|
||||
static inline unsigned get_le16( void const* p )
|
||||
{
|
||||
return ((uint8_t const*) p) [1] * 0x100u +
|
||||
((uint8_t const*) p) [0];
|
||||
}
|
||||
|
||||
static inline int get_le16s( void const* p )
|
||||
{
|
||||
return ((int8_t const*) p) [1] * 0x100 +
|
||||
((uint8_t const*) p) [0];
|
||||
}
|
||||
|
||||
static inline void set_le16( void* p, unsigned n )
|
||||
{
|
||||
((uint8_t*) p) [1] = (uint8_t) (n >> 8);
|
||||
((uint8_t*) p) [0] = (uint8_t) n;
|
||||
}
|
||||
|
||||
// *A versions are used where data is aligned
|
||||
// Sometimes BIG_ENDIAN is defined to 0x1234 or something, so treat values
|
||||
// other than 1 as false.
|
||||
#if BIG_ENDIAN != 1
|
||||
#define GET_LE16A( addr ) (*(uint16_t const*) (addr))
|
||||
#define GET_LE16SA( addr ) (*( int16_t const*) (addr))
|
||||
#define SET_LE16A( addr, data ) (void) (*(uint16_t*) (addr) = (data))
|
||||
|
||||
#else
|
||||
#define GET_LE16A( addr ) get_le16 ( addr )
|
||||
#define GET_LE16SA( addr ) get_le16s( addr )
|
||||
#define SET_LE16A( addr, data ) set_le16 ( addr, data )
|
||||
#endif
|
||||
|
||||
#define GET_LE16( addr ) GET_LE16A( addr )
|
||||
#define SET_LE16( addr, data ) SET_LE16A( addr, data )
|
||||
|
||||
#endif
|
@@ -1,11 +1,11 @@
|
||||
class DSP {
|
||||
public:
|
||||
class DSP { public:
|
||||
virtual void enter() = 0;
|
||||
|
||||
virtual uint8 read (uint8 addr) = 0;
|
||||
virtual void write(uint8 addr, uint8 data) = 0;
|
||||
|
||||
virtual void power() = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual uint32 run() = 0;
|
||||
|
||||
DSP() {}
|
||||
virtual ~DSP() {}
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include "smp/ssmp/ssmp.h"
|
||||
|
||||
#include "dsp/dsp.h"
|
||||
//#include "dsp/adsp/adsp.h"
|
||||
#include "dsp/bdsp/bdsp.h"
|
||||
|
||||
#include "ppu/ppu.h"
|
||||
@@ -32,12 +33,16 @@
|
||||
|
||||
#include "snes/snes.h"
|
||||
|
||||
#include "chip/superfx/superfx.h"
|
||||
#include "chip/srtc/srtc.h"
|
||||
#include "chip/sdd1/sdd1.h"
|
||||
#include "chip/c4/c4.h"
|
||||
#include "chip/dsp1/dsp1.h"
|
||||
#include "chip/dsp2/dsp2.h"
|
||||
#include "chip/dsp3/dsp3.h"
|
||||
#include "chip/dsp4/dsp4.h"
|
||||
#include "chip/obc1/obc1.h"
|
||||
#include "chip/st010/st010.h"
|
||||
|
||||
extern MMIO mmio_unmapped;
|
||||
#ifdef POLYMORPHISM
|
||||
|
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
libarray : version 0.07 ~byuu (10/14/06)
|
||||
libarray : version 0.09 ~byuu (2007-03-06)
|
||||
*/
|
||||
|
||||
#ifndef __LIBARRAY
|
||||
#define __LIBARRAY
|
||||
#ifndef LIBARRAY_H
|
||||
#define LIBARRAY_H
|
||||
|
||||
template<typename T> class array {
|
||||
protected:
|
||||
@@ -25,14 +25,10 @@ protected:
|
||||
|
||||
public:
|
||||
uint size() { return buffersize; }
|
||||
uint capacity() { return buffersize; }
|
||||
uint capacity() { return poolsize; }
|
||||
|
||||
void reset() {
|
||||
if(pool) {
|
||||
free(pool);
|
||||
pool = 0;
|
||||
}
|
||||
|
||||
safe_free(pool);
|
||||
poolsize = 0;
|
||||
buffersize = 0;
|
||||
}
|
||||
@@ -44,7 +40,7 @@ public:
|
||||
buffersize = size;
|
||||
}
|
||||
|
||||
pool = static_cast<T*>(realloc(pool, sizeof(T) * size));
|
||||
pool = (T*)realloc(pool, sizeof(T) * size);
|
||||
poolsize = size;
|
||||
}
|
||||
|
||||
@@ -69,6 +65,17 @@ public:
|
||||
|
||||
~array() { reset(); }
|
||||
|
||||
array &operator=(array &source) {
|
||||
safe_free(pool);
|
||||
buffersize = source.buffersize;
|
||||
poolsize = source.poolsize;
|
||||
//allocate entire pool size ...
|
||||
pool = (T*)realloc(pool, sizeof(T) * poolsize);
|
||||
//... but only copy used pool objects
|
||||
memcpy(pool, source.pool, sizeof(T) * buffersize);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline T &operator[](int index) {
|
||||
if(index >= buffersize)resize(index + 1);
|
||||
if(index >= buffersize)throw "array[] out of bounds";
|
||||
|
@@ -1,17 +1,55 @@
|
||||
/*
|
||||
libbase : version 0.08f ~byuu (2006-11-07)
|
||||
libbase : version 0.11 ~byuu (2007-09-08)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#ifndef __LIBBASE
|
||||
#define __LIBBASE
|
||||
#ifndef LIBBASE_H
|
||||
#define LIBBASE_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
#include <shlobj.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
//disable libc deprecation warnings in MSVC 2k5+
|
||||
#pragma warning(disable:4996)
|
||||
|
||||
#define NOMINMAX
|
||||
#define PATH_MAX _MAX_PATH
|
||||
#define va_copy(dst, src) ((dst) = (src))
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#define getcwd _getcwd
|
||||
#define ftruncate _chsize
|
||||
#define mkdir _mkdir
|
||||
#define putenv _putenv
|
||||
#define rmdir _rmdir
|
||||
#define vsnprintf _vsnprintf
|
||||
|
||||
static char *realpath(const char *file_name, char *resolved_name) {
|
||||
return _fullpath(resolved_name, file_name, PATH_MAX);
|
||||
}
|
||||
#else
|
||||
#define mkdir(path) (mkdir)(path, 0755);
|
||||
#endif
|
||||
|
||||
/*****
|
||||
@@ -22,62 +60,53 @@
|
||||
#define noinline __declspec(noinline)
|
||||
#define inline inline
|
||||
#define alwaysinline __forceinline
|
||||
#define fastcall __fastcall
|
||||
#elif defined(__GNUC__)
|
||||
#define noinline
|
||||
#define noinline __attribute__((noinline))
|
||||
#define inline inline
|
||||
#define alwaysinline inline
|
||||
#define fastcall __attribute__((fastcall))
|
||||
#define alwaysinline __attribute__((always_inline))
|
||||
#else
|
||||
#define noinline
|
||||
#define inline inline
|
||||
#define alwaysinline inline
|
||||
#define fastcall
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#include <io.h>
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE !FALSE
|
||||
#endif
|
||||
|
||||
//deprecated
|
||||
#define SafeFree(__n) if(__n) { free(__n); __n = 0; }
|
||||
#define SafeDelete(__n) if(__n) { delete(__n); __n = 0; }
|
||||
#define SafeRelease(__n) if(__n) { __n->Release(); __n = 0; }
|
||||
|
||||
/*****
|
||||
* typedefs
|
||||
*****/
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef signed int sint;
|
||||
typedef unsigned int uint;
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short word;
|
||||
typedef unsigned long ulong;
|
||||
typedef unsigned long long uquad;
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
typedef unsigned char bool8;
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned long uint32;
|
||||
typedef unsigned long long uint64;
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
|
||||
typedef signed char int8;
|
||||
typedef signed short int16;
|
||||
typedef signed long int32;
|
||||
typedef signed long long int64;
|
||||
/*****
|
||||
* OS localization
|
||||
*****/
|
||||
|
||||
//userpath(output) retrieves path to user's home folder
|
||||
//output must be at least as large as PATH_MAX
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
static char *userpath(char *output) {
|
||||
strcpy(output, "."); //failsafe
|
||||
SHGetFolderPath(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, output);
|
||||
return output;
|
||||
}
|
||||
#else
|
||||
static char *userpath(char *output) {
|
||||
strcpy(output, "."); //failsafe
|
||||
struct passwd *userinfo = getpwuid(getuid());
|
||||
if(userinfo) { strcpy(output, userinfo->pw_dir); }
|
||||
return output;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****
|
||||
* templates
|
||||
@@ -110,133 +139,66 @@ T z = x;
|
||||
y = z;
|
||||
}
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
#define min(x, y) ((x < y) ? x : y)
|
||||
#define min(x, y) (((x) < (y)) ? (x) : (y))
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
#define max(x, y) ((x > y) ? x : y)
|
||||
#define max(x, y) (((x) > (y)) ? (x) : (y))
|
||||
|
||||
template<int min, int max, typename T> inline T minmax(const T x) {
|
||||
return (x < (T)min) ? (T)min : (x > (T)max) ? (T)max : x;
|
||||
}
|
||||
|
||||
template<int bits> inline unsigned uclamp(const unsigned x) {
|
||||
enum { m = (1 << bits) - 1 };
|
||||
return (x > m) ? m : x;
|
||||
enum { y = (1U << bits) - 1 };
|
||||
return y + ((x - y) & -(x < y)); //min(x, y);
|
||||
}
|
||||
|
||||
template<int bits> inline unsigned uclip(const unsigned x) {
|
||||
enum { m = (1 << bits) - 1 };
|
||||
enum { m = (1U << bits) - 1 };
|
||||
return (x & m);
|
||||
}
|
||||
|
||||
template<int bits> inline signed sclamp(const signed x) {
|
||||
enum { b = 1 << (bits - 1), m = (1 << (bits - 1)) - 1 };
|
||||
enum { b = 1U << (bits - 1), m = (1U << (bits - 1)) - 1 };
|
||||
return (x > m) ? m : (x < -b) ? -b : x;
|
||||
}
|
||||
|
||||
template<int bits> inline signed sclip(const signed x) {
|
||||
enum { b = 1 << (bits - 1), m = (1 << (bits - 1)) - 1 };
|
||||
return (x & b) ? (x | ~m) : (x & m);
|
||||
enum { b = 1U << (bits - 1), m = (1U << bits) - 1 };
|
||||
return ((x & m) ^ b) - b;
|
||||
}
|
||||
|
||||
//requires compiler arithmetic shift right support
|
||||
//c++ standard does not define whether >> is arithmetic or logical
|
||||
//template<int bits> inline signed sclip(const signed x) {
|
||||
//enum { s = sizeof(x) * 8 - bits };
|
||||
// return (x << s) >> s;
|
||||
//}
|
||||
//bit shifting functions are deprecated
|
||||
|
||||
template<int bits, typename T> inline T rol(const T x) {
|
||||
enum { s = (sizeof(T) << 3) - bits };
|
||||
return (x << bits) | (x >> s);
|
||||
template<int n, typename T> inline T rol(const T x) {
|
||||
enum { s = (sizeof(T) << 3) - n };
|
||||
return (x << n) | (x >> s);
|
||||
}
|
||||
|
||||
template<int bits, typename T> inline T ror(const T x) {
|
||||
enum { s = (sizeof(T) << 3) - bits };
|
||||
return (x >> bits) | (x << s);
|
||||
template<int n, typename T> inline T ror(const T x) {
|
||||
enum { s = (sizeof(T) << 3) - n };
|
||||
return (x >> n) | (x << s);
|
||||
}
|
||||
|
||||
template<int bits, typename T> inline T asl(const T x) {
|
||||
return (x << bits);
|
||||
template<int n, typename T> inline T asl(const T x) {
|
||||
return (x << n);
|
||||
}
|
||||
|
||||
template<int bits, typename T> inline T asr(const T x) {
|
||||
enum { h = 1 << ((sizeof(T) << 3) - 1) };
|
||||
enum { m = ~((1 << ((sizeof(T) << 3) - bits)) - 1) };
|
||||
return (x >> bits) | ((0 - !!(x & h)) & m);
|
||||
template<int n, typename T> inline T asr(const T x) {
|
||||
enum { bits = (sizeof(T) << 3) - n };
|
||||
return sclip<bits>(x >> n);
|
||||
}
|
||||
|
||||
template<int bits, typename T> inline T lsl(const T x) {
|
||||
return (x << bits);
|
||||
template<int n, typename T> inline T lsl(const T x) {
|
||||
return (x << n);
|
||||
}
|
||||
|
||||
template<int bits, typename T> inline T lsr(const T x) {
|
||||
enum { m = ((1 << ((sizeof(T) << 3) - bits)) - 1) };
|
||||
return (x >> bits) & m;
|
||||
template<int n, typename T> inline T lsr(const T x) {
|
||||
enum { bits = (sizeof(T) << 3) - n };
|
||||
return uclip<bits>(x >> n);
|
||||
}
|
||||
|
||||
template<unsigned bits, typename base = uint> class uint_t {
|
||||
private:
|
||||
base data;
|
||||
|
||||
public:
|
||||
inline operator unsigned() const { return data; }
|
||||
inline unsigned operator ++(int) { base r = data; data = uclip<bits>(data + 1); return r; }
|
||||
inline unsigned operator --(int) { base r = data; data = uclip<bits>(data - 1); return r; }
|
||||
inline unsigned operator ++() { data = uclip<bits>(data + 1); return data; }
|
||||
inline unsigned operator --() { data = uclip<bits>(data - 1); return data; }
|
||||
template<typename T> inline unsigned operator =(const T i) { data = uclip<bits>(i); return data; }
|
||||
template<typename T> inline unsigned operator |=(const T i) { data = uclip<bits>(data | i); return data; }
|
||||
template<typename T> inline unsigned operator ^=(const T i) { data = uclip<bits>(data ^ i); return data; }
|
||||
template<typename T> inline unsigned operator &=(const T i) { data = uclip<bits>(data & i); return data; }
|
||||
template<typename T> inline unsigned operator<<=(const T i) { data = uclip<bits>(data << i); return data; }
|
||||
template<typename T> inline unsigned operator>>=(const T i) { data = uclip<bits>(data >> i); return data; }
|
||||
template<typename T> inline unsigned operator +=(const T i) { data = uclip<bits>(data + i); return data; }
|
||||
template<typename T> inline unsigned operator -=(const T i) { data = uclip<bits>(data - i); return data; }
|
||||
template<typename T> inline unsigned operator *=(const T i) { data = uclip<bits>(data * i); return data; }
|
||||
template<typename T> inline unsigned operator /=(const T i) { data = uclip<bits>(data / i); return data; }
|
||||
template<typename T> inline unsigned operator %=(const T i) { data = uclip<bits>(data % i); return data; }
|
||||
|
||||
inline uint_t() : data(0) {}
|
||||
inline uint_t(const base i) : data(uclip<bits>(i)) {}
|
||||
};
|
||||
|
||||
template<unsigned bits, typename base = int> class int_t {
|
||||
private:
|
||||
base data;
|
||||
|
||||
public:
|
||||
inline operator signed() const { return data; }
|
||||
inline signed operator ++(int) { base r = data; data = sclip<bits>(data + 1); return r; }
|
||||
inline signed operator --(int) { base r = data; data = sclip<bits>(data - 1); return r; }
|
||||
inline signed operator ++() { data = sclip<bits>(data + 1); return data; }
|
||||
inline signed operator --() { data = sclip<bits>(data - 1); return data; }
|
||||
template<typename T> inline signed operator =(const T i) { data = sclip<bits>(i); return data; }
|
||||
template<typename T> inline signed operator |=(const T i) { data = sclip<bits>(data | i); return data; }
|
||||
template<typename T> inline signed operator ^=(const T i) { data = sclip<bits>(data ^ i); return data; }
|
||||
template<typename T> inline signed operator &=(const T i) { data = sclip<bits>(data & i); return data; }
|
||||
template<typename T> inline signed operator<<=(const T i) { data = sclip<bits>(data << i); return data; }
|
||||
template<typename T> inline signed operator>>=(const T i) { data = sclip<bits>(data >> i); return data; }
|
||||
template<typename T> inline signed operator +=(const T i) { data = sclip<bits>(data + i); return data; }
|
||||
template<typename T> inline signed operator -=(const T i) { data = sclip<bits>(data - i); return data; }
|
||||
template<typename T> inline signed operator *=(const T i) { data = sclip<bits>(data * i); return data; }
|
||||
template<typename T> inline signed operator /=(const T i) { data = sclip<bits>(data / i); return data; }
|
||||
template<typename T> inline signed operator %=(const T i) { data = sclip<bits>(data % i); return data; }
|
||||
|
||||
inline int_t() : data(0) {}
|
||||
inline int_t(const base i) : data(sclip<bits>(i)) {}
|
||||
};
|
||||
|
||||
typedef uint_t<24> uint24;
|
||||
typedef int_t<24> int24;
|
||||
typedef uint_t<48, uint64> uint48;
|
||||
typedef int_t<48, int64> int48;
|
||||
|
||||
/*****
|
||||
* endian wrappers
|
||||
*****/
|
||||
@@ -279,88 +241,18 @@ typedef int_t<48, int64> int48;
|
||||
* libc extensions
|
||||
*****/
|
||||
|
||||
static uint8 fgetb(FILE *fp) { return fgetc(fp); }
|
||||
static uint8 fgetlb(FILE *fp) { return fgetc(fp); }
|
||||
static uint8 fgetmb(FILE *fp) { return fgetc(fp); }
|
||||
|
||||
static uint16 fgetlw(FILE *fp) {
|
||||
return (fgetc(fp)) | (fgetc(fp) << 8);
|
||||
static uint64 fget(FILE *fp, uint length = 1) {
|
||||
uint64 data = 0;
|
||||
for(uint i = 0; i < length; i++) {
|
||||
data |= fgetc(fp) << (i << 3);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static uint16 fgetmw(FILE *fp) {
|
||||
return (fgetc(fp) << 8) | (fgetc(fp) << 8);
|
||||
}
|
||||
|
||||
static uint32 fgetld(FILE *fp) {
|
||||
return (fgetc(fp)) | (fgetc(fp) << 8) | (fgetc(fp) << 16) | (fgetc(fp) << 24);
|
||||
}
|
||||
|
||||
static uint32 fgetmd(FILE *fp) {
|
||||
return (fgetc(fp) << 24) | (fgetc(fp) << 16) | (fgetc(fp) << 8) | (fgetc(fp));
|
||||
}
|
||||
|
||||
static uint64 fgetlq(FILE *fp) {
|
||||
return ((uint64)fgetc(fp) << 0) | ((uint64)fgetc(fp) << 8) |
|
||||
((uint64)fgetc(fp) << 16) | ((uint64)fgetc(fp) << 24) |
|
||||
((uint64)fgetc(fp) << 32) | ((uint64)fgetc(fp) << 40) |
|
||||
((uint64)fgetc(fp) << 48) | ((uint64)fgetc(fp) << 56);
|
||||
}
|
||||
|
||||
static uint64 fgetmq(FILE *fp) {
|
||||
return ((uint64)fgetc(fp) << 56) | ((uint64)fgetc(fp) << 48) |
|
||||
((uint64)fgetc(fp) << 40) | ((uint64)fgetc(fp) << 32) |
|
||||
((uint64)fgetc(fp) << 24) | ((uint64)fgetc(fp) << 16) |
|
||||
((uint64)fgetc(fp) << 8) | ((uint64)fgetc(fp) << 0);
|
||||
}
|
||||
|
||||
static void fputb(FILE *fp, uint8 data) { fputc(data, fp); }
|
||||
static void fputlb(FILE *fp, uint8 data) { fputc(data, fp); }
|
||||
static void fputmb(FILE *fp, uint8 data) { fputc(data, fp); }
|
||||
|
||||
static void fputlw(FILE *fp, uint16 data) {
|
||||
fputc(data >> 0, fp);
|
||||
fputc(data >> 8, fp);
|
||||
}
|
||||
|
||||
static void fputmw(FILE *fp, uint16 data) {
|
||||
fputc(data >> 8, fp);
|
||||
fputc(data >> 0, fp);
|
||||
}
|
||||
|
||||
static void fputld(FILE *fp, uint32 data) {
|
||||
fputc(data >> 0, fp);
|
||||
fputc(data >> 8, fp);
|
||||
fputc(data >> 16, fp);
|
||||
fputc(data >> 24, fp);
|
||||
}
|
||||
|
||||
static void fputmd(FILE *fp, uint32 data) {
|
||||
fputc(data >> 24, fp);
|
||||
fputc(data >> 16, fp);
|
||||
fputc(data >> 8, fp);
|
||||
fputc(data >> 0, fp);
|
||||
}
|
||||
|
||||
static void fputlq(FILE *fp, uint64 data) {
|
||||
fputc(data >> 0, fp);
|
||||
fputc(data >> 8, fp);
|
||||
fputc(data >> 16, fp);
|
||||
fputc(data >> 24, fp);
|
||||
fputc(data >> 32, fp);
|
||||
fputc(data >> 40, fp);
|
||||
fputc(data >> 48, fp);
|
||||
fputc(data >> 56, fp);
|
||||
}
|
||||
|
||||
static void fputmq(FILE *fp, uint64 data) {
|
||||
fputc(data >> 56, fp);
|
||||
fputc(data >> 48, fp);
|
||||
fputc(data >> 40, fp);
|
||||
fputc(data >> 32, fp);
|
||||
fputc(data >> 24, fp);
|
||||
fputc(data >> 16, fp);
|
||||
fputc(data >> 8, fp);
|
||||
fputc(data >> 0, fp);
|
||||
static void fput(FILE *fp, uint64 data, uint length = 1) {
|
||||
for(uint i = 0; i < length; i++) {
|
||||
fputc(data >> (i << 3), fp);
|
||||
}
|
||||
}
|
||||
|
||||
static bool fexists(const char *fn) {
|
||||
@@ -390,7 +282,9 @@ uint32 size = ftell(fp);
|
||||
return size;
|
||||
}
|
||||
|
||||
static int ftruncate(FILE *fp, long size) { return ftruncate(fileno(fp), size); }
|
||||
static int fresize(FILE *fp, long size) {
|
||||
return ftruncate(fileno(fp), size);
|
||||
}
|
||||
|
||||
/*****
|
||||
* crc32 calculation
|
||||
|
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
libco_win32 : version 0.08 ~byuu (10/21/06)
|
||||
win32-x86 implementation of libco
|
||||
*/
|
||||
|
||||
#define WINVER 0x0400
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#include <windows.h>
|
||||
|
||||
#include "libco_win32.h"
|
||||
|
||||
struct cothread_struct {
|
||||
void *cohandle;
|
||||
cothread_p coentry;
|
||||
cothread_t colink;
|
||||
};
|
||||
|
||||
cothread_t __co_active = 0, __co_primary = 0;
|
||||
|
||||
void __stdcall co_entryproc(void *coentry) {
|
||||
cothread_struct *s = static_cast<cothread_struct*>(coentry);
|
||||
s->coentry();
|
||||
co_exit(0);
|
||||
}
|
||||
|
||||
cothread_t co_init() {
|
||||
ConvertThreadToFiber(0);
|
||||
cothread_struct *s = static_cast<cothread_struct*>(malloc(sizeof(cothread_struct)));
|
||||
s->colink = 0;
|
||||
s->coentry = 0;
|
||||
s->cohandle = GetCurrentFiber();
|
||||
__co_active = __co_primary = static_cast<cothread_t>(s);
|
||||
return __co_active;
|
||||
}
|
||||
|
||||
void co_term() {
|
||||
//primary fiber cannot be deleted; free memory used by handle to fiber only
|
||||
free(__co_primary);
|
||||
//ConvertFiberToThread(); //only exists on WinXP+
|
||||
}
|
||||
|
||||
cothread_t co_active() {
|
||||
return __co_active;
|
||||
}
|
||||
|
||||
cothread_t co_create(cothread_p coentry, unsigned int heapsize) {
|
||||
cothread_struct *s = static_cast<cothread_struct*>(malloc(sizeof(cothread_struct)));
|
||||
s->colink = co_active();
|
||||
s->coentry = coentry;
|
||||
s->cohandle = CreateFiber(heapsize + 512, co_entryproc, static_cast<void*>(s));
|
||||
return static_cast<cothread_t>(s);
|
||||
}
|
||||
|
||||
void co_delete(cothread_t cothread) {
|
||||
cothread_struct *s = static_cast<cothread_struct*>(cothread);
|
||||
DeleteFiber(s->cohandle);
|
||||
free(cothread);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t cothread) {
|
||||
__co_active = cothread;
|
||||
cothread_struct *s = static_cast<cothread_struct*>(cothread);
|
||||
SwitchToFiber(s->cohandle);
|
||||
}
|
||||
|
||||
void co_exit(cothread_t cothread) {
|
||||
if(cothread != 0) { co_switch(cothread); }
|
||||
cothread_struct *s = static_cast<cothread_struct*>(__co_active);
|
||||
co_switch(s->colink);
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
libco_win32 : version 0.08 ~byuu (10/21/2006)
|
||||
*/
|
||||
|
||||
#define COTHREAD_STACKSIZE_TINY 0x1000
|
||||
#define COTHREAD_STACKSIZE_SMALL 0x4000
|
||||
#define COTHREAD_STACKSIZE_NORMAL 0x10000
|
||||
#define COTHREAD_STACKSIZE_LARGE 0x40000
|
||||
#define COTHREAD_STACKSIZE_HUGE 0x100000
|
||||
|
||||
typedef void (*cothread_t);
|
||||
typedef void (*cothread_p)(void);
|
||||
|
||||
cothread_t co_init();
|
||||
void co_term();
|
||||
cothread_t co_active();
|
||||
cothread_t co_create(cothread_p coentry, unsigned int heapsize);
|
||||
void co_delete(cothread_t cothread);
|
||||
void co_switch(cothread_t cothread);
|
||||
void co_exit(cothread_t cothread);
|
@@ -1,88 +1,69 @@
|
||||
;*****
|
||||
;libco_x86 : version 0.08 ~byuu (10/21/06)
|
||||
;libco_x86 : version 0.10 ~byuu (2007-09-08)
|
||||
;cross-platform x86 implementation of libco
|
||||
;special thanks to Aaron Giles and Joel Yliluoma for various optimizations
|
||||
;
|
||||
;context save/restore adheres to c/c++ ABI
|
||||
;for x86 windows, osx, linux and freebsd
|
||||
;[ABI compatibility]
|
||||
;- visual c++; windows; x86
|
||||
;- mingw; windows; x86
|
||||
;- gcc; mac os x; x86
|
||||
;- gcc; linux; x86
|
||||
;- gcc; freebsd; x86
|
||||
;
|
||||
;context saves esp+ebp+esi+edi+ebx
|
||||
;context ignores eax+ecx+edx
|
||||
;context ignores st([0-7])+xmm[0-15]
|
||||
;context ignores all else
|
||||
;[nonvolatile registers]
|
||||
;- esp, ebp, edi, esi, ebx
|
||||
;
|
||||
;[volatile registers]
|
||||
;- eax, ecx, edx
|
||||
;- st0 - st7
|
||||
;- xmm0 - xmm15
|
||||
;*****
|
||||
|
||||
section .data
|
||||
|
||||
align 4
|
||||
co_active_context dd 0
|
||||
co_primary_context dd 0
|
||||
|
||||
section .code
|
||||
|
||||
;*****
|
||||
;linker-specific name decorations
|
||||
;*****
|
||||
|
||||
%ifdef WIN32
|
||||
%define malloc _malloc
|
||||
%define free _free
|
||||
|
||||
%define co_init @co_init@0
|
||||
%define co_term @co_term@0
|
||||
%define co_active @co_active@0
|
||||
%define co_create @co_create@8
|
||||
%define co_delete @co_delete@4
|
||||
%define co_switch @co_switch@4
|
||||
%define co_exit @co_exit@4
|
||||
%endif
|
||||
|
||||
%ifdef OSX86
|
||||
%define malloc _malloc
|
||||
%define free _free
|
||||
|
||||
%define co_init _co_init
|
||||
%define co_term _co_term
|
||||
%define co_active _co_active
|
||||
%define co_create _co_create
|
||||
%define co_delete _co_delete
|
||||
%define co_switch _co_switch
|
||||
%define co_exit _co_exit
|
||||
%endif
|
||||
|
||||
bits 32
|
||||
|
||||
section .bss
|
||||
|
||||
align 4
|
||||
co_primary_buffer resb 512
|
||||
|
||||
section .data
|
||||
|
||||
align 4
|
||||
co_active_context dd co_primary_buffer
|
||||
|
||||
section .text
|
||||
|
||||
extern malloc
|
||||
extern free
|
||||
|
||||
global co_init
|
||||
global co_term
|
||||
global co_active
|
||||
global co_create
|
||||
global co_delete
|
||||
global co_switch
|
||||
global co_exit
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t fastcall co_init();
|
||||
;return = eax
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_init:
|
||||
;create context for main cothread
|
||||
mov ecx,0 ;entry point for main thread is not needed
|
||||
mov edx,512 ;main cothread uses default program stack
|
||||
call co_create
|
||||
mov dword[co_active_context],eax
|
||||
mov dword[co_primary_context],eax
|
||||
ret
|
||||
|
||||
;*****
|
||||
;extern "C" void fastcall co_term();
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_term:
|
||||
mov ecx,dword[co_primary_context]
|
||||
call co_delete
|
||||
ret
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t fastcall co_active();
|
||||
@@ -91,47 +72,43 @@ co_term:
|
||||
|
||||
align 16
|
||||
co_active:
|
||||
mov eax,dword[co_active_context]
|
||||
mov eax,[co_active_context]
|
||||
ret
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t fastcall co_create(cothread_p coentry, unsigned int heapsize);
|
||||
;ecx = coentry
|
||||
;edx = heapsize
|
||||
;extern "C" cothread_t fastcall co_create(unsigned int heapsize, void (*coentry)());
|
||||
;ecx = heapsize
|
||||
;edx = coentry
|
||||
;return = eax
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_create:
|
||||
;create heap space (stack + register storage)
|
||||
add edx,512 ;+4(esp)+4(coentry)+4(colink)+256(stack_align)
|
||||
add ecx,512 ;allocate extra memory for contextual info
|
||||
push ecx
|
||||
push edx
|
||||
|
||||
push edx
|
||||
call malloc
|
||||
push ecx
|
||||
call malloc ;eax = malloc(edx)
|
||||
add esp,4
|
||||
|
||||
pop edx
|
||||
pop ecx
|
||||
|
||||
add edx,eax ;set edx to point to top of stack heap
|
||||
and edx,0xffffff00 ;force 256-byte alignment of stack heap
|
||||
add ecx,eax ;set edx to point to top of stack heap
|
||||
and ecx,-16 ;force 16-byte alignment of stack heap
|
||||
|
||||
;store thread entry point + registers so that first call to co_switch will execute coentry
|
||||
mov dword[edx-4],co_entrypoint ;edx=*stack
|
||||
mov dword[edx-8],0
|
||||
mov dword[edx-12],0
|
||||
mov dword[edx-16],0
|
||||
mov dword[edx-20],0
|
||||
sub edx,20
|
||||
|
||||
;initialize context memory heap
|
||||
mov dword[eax],edx ;cothread_t[ 0- 3] = stack heap pointer (esp)
|
||||
mov dword[eax+4],ecx ;cothread_t[ 4- 7] = entry point
|
||||
mov ecx,dword[co_active_context]
|
||||
mov dword[eax+8],ecx ;cothread_t[ 8-11] = return context
|
||||
;store thread entry point + registers, so that first call to co_switch will execute coentry
|
||||
mov dword[ecx-4],edx ;entry point
|
||||
mov dword[ecx-8],0 ;ebp
|
||||
mov dword[ecx-12],0 ;esi
|
||||
mov dword[ecx-16],0 ;edi
|
||||
mov dword[ecx-20],0 ;ebx
|
||||
sub ecx,20
|
||||
|
||||
;initialize context memory heap and return
|
||||
mov [eax],ecx ;*cothread_t = stack heap pointer (esp)
|
||||
ret ;return allocated memory block as thread handle
|
||||
|
||||
;*****
|
||||
@@ -142,7 +119,7 @@ co_create:
|
||||
align 16
|
||||
co_delete:
|
||||
push ecx
|
||||
call free
|
||||
call free ;free(ecx)
|
||||
add esp,4
|
||||
ret
|
||||
|
||||
@@ -153,45 +130,19 @@ co_delete:
|
||||
|
||||
align 16
|
||||
co_switch:
|
||||
mov eax,dword[co_active_context] ;backup current context
|
||||
mov dword[co_active_context],ecx ;set new active context
|
||||
mov eax,[co_active_context] ;backup current context
|
||||
mov [co_active_context],ecx ;set new active context
|
||||
|
||||
push ebp
|
||||
push esi
|
||||
push edi
|
||||
push ebx
|
||||
mov dword[eax],esp
|
||||
mov [eax],esp
|
||||
|
||||
mov esp,dword[ecx]
|
||||
mov esp,[ecx]
|
||||
pop ebx
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebp
|
||||
|
||||
ret
|
||||
|
||||
;*****
|
||||
;extern "C" void fastcall co_exit(cothread_t cothread);
|
||||
;ecx = cothread
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_exit:
|
||||
cmp ecx,0
|
||||
jne co_switch
|
||||
|
||||
;if cothread is null, switch to context that created current context
|
||||
mov eax,dword[co_active_context]
|
||||
mov ecx,dword[eax+8]
|
||||
jmp co_switch
|
||||
|
||||
;*****
|
||||
;void fastcall co_entrypoint();
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_entrypoint:
|
||||
mov eax,dword[co_active_context]
|
||||
call dword[eax+4]
|
||||
xor ecx,ecx
|
||||
jmp co_exit
|
||||
|
@@ -1,20 +1,26 @@
|
||||
/*
|
||||
libco_x86 : version 0.08 ~byuu (10/21/2006)
|
||||
libco_x86 : version 0.10 ~byuu (2007-09-08)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#define COTHREAD_STACKSIZE_TINY 0x1000
|
||||
#define COTHREAD_STACKSIZE_SMALL 0x4000
|
||||
#define COTHREAD_STACKSIZE_NORMAL 0x10000
|
||||
#define COTHREAD_STACKSIZE_LARGE 0x40000
|
||||
#define COTHREAD_STACKSIZE_HUGE 0x100000
|
||||
#ifndef LIBCO_H
|
||||
#define LIBCO_H
|
||||
|
||||
typedef void (*cothread_t);
|
||||
typedef void (*cothread_p)(void);
|
||||
#if !defined(fastcall)
|
||||
#if defined(_MSC_VER)
|
||||
#define fastcall __fastcall
|
||||
#elif defined(__GNUC__)
|
||||
#define fastcall __attribute__((fastcall))
|
||||
#else
|
||||
#error "fastcall undefined"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef void *cothread_t;
|
||||
|
||||
extern "C" cothread_t fastcall co_init();
|
||||
extern "C" void fastcall co_term();
|
||||
extern "C" cothread_t fastcall co_active();
|
||||
extern "C" cothread_t fastcall co_create(cothread_p coentry, unsigned int heapsize);
|
||||
extern "C" cothread_t fastcall co_create(unsigned int heapsize, void (*coentry)());
|
||||
extern "C" void fastcall co_delete(cothread_t cothread);
|
||||
extern "C" void fastcall co_switch(cothread_t cothread);
|
||||
extern "C" void fastcall co_exit(cothread_t cothread);
|
||||
|
||||
#endif
|
||||
|
123
src/lib/libco_x86_64.asm
Normal file
123
src/lib/libco_x86_64.asm
Normal file
@@ -0,0 +1,123 @@
|
||||
;*****
|
||||
;libco_x86_64 : version 0.10 ~byuu (2007-09-08)
|
||||
;cross-platform x86-64 implementation of libco
|
||||
;special thanks to Aaron Giles and Joel Yliluoma for various optimizations
|
||||
;
|
||||
;[ABI compatibility]
|
||||
;- SystemV ( http://refspecs.freestandards.org/elf/x86_64-SysV-psABI.pdf )
|
||||
;- gcc; linux; x86-64
|
||||
;- gcc; freebsd; x86-64
|
||||
;
|
||||
;[nonvolatile registers]
|
||||
;- rsp, rbp, rbx, r12, r13, r14, r15
|
||||
;
|
||||
;[volatile registers]
|
||||
;- rax, rcx, rdx, r8, r9, r10, r11, rdi, rsi
|
||||
;- st0 - st7
|
||||
;- xmm0 - xmm15
|
||||
;*****
|
||||
|
||||
bits 64
|
||||
|
||||
section .bss
|
||||
|
||||
align 8
|
||||
co_primary_buffer resb 512
|
||||
|
||||
section .data
|
||||
|
||||
align 8
|
||||
co_active_context dq co_primary_buffer
|
||||
|
||||
section .text
|
||||
|
||||
extern malloc
|
||||
extern free
|
||||
|
||||
global co_active
|
||||
global co_create
|
||||
global co_delete
|
||||
global co_switch
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t co_active();
|
||||
;return = rax
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_active:
|
||||
mov rax,[co_active_context wrt rip]
|
||||
ret
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)());
|
||||
;rdi = heapsize
|
||||
;rsi = coentry
|
||||
;return = rax
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_create:
|
||||
;create heap space (stack + register storage)
|
||||
add rdi,512 ;allocate extra memory for contextual info
|
||||
push rdi
|
||||
push rsi
|
||||
|
||||
call malloc ;rax = malloc(rdi)
|
||||
|
||||
pop rsi
|
||||
pop rdi
|
||||
|
||||
add rdi,rax ;set rsi to point to top of stack heap
|
||||
and rdi,-16 ;force 16-byte alignment of stack heap
|
||||
|
||||
;store thread entry point + registers, so that first call to co_switch will execute coentry
|
||||
mov qword[rdi-8],rsi ;entry point
|
||||
mov qword[rdi-16],0 ;r15
|
||||
mov qword[rdi-24],0 ;r14
|
||||
mov qword[rdi-32],0 ;r13
|
||||
mov qword[rdi-40],0 ;r12
|
||||
mov qword[rdi-48],0 ;rbx
|
||||
mov qword[rdi-56],0 ;rbp
|
||||
sub rdi,56
|
||||
|
||||
;initialize context memory heap and return
|
||||
mov [rax],rdi ;*cothread_t = stack heap pointer (rsp)
|
||||
ret ;return allocated memory block as thread handle
|
||||
|
||||
;*****
|
||||
;extern "C" void co_delete(cothread_t cothread);
|
||||
;rdi = cothread
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_delete:
|
||||
jmp free ;free(rdi)
|
||||
|
||||
;*****
|
||||
;extern "C" void co_switch(cothread_t cothread);
|
||||
;rdi = cothread
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_switch:
|
||||
mov rax,[co_active_context wrt rip] ;backup current context
|
||||
mov [co_active_context wrt rip],rdi ;set new active context
|
||||
|
||||
push rbp
|
||||
push rbx
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
mov [rax],rsp
|
||||
|
||||
mov rsp,[rdi]
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop rbx
|
||||
pop rbp
|
||||
|
||||
ret
|
16
src/lib/libco_x86_64.h
Normal file
16
src/lib/libco_x86_64.h
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
libco_x86_64 : version 0.10 ~byuu (2007-09-08)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#ifndef LIBCO_H
|
||||
#define LIBCO_H
|
||||
|
||||
typedef void *cothread_t;
|
||||
|
||||
extern "C" cothread_t co_active();
|
||||
extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)());
|
||||
extern "C" void co_delete(cothread_t cothread);
|
||||
extern "C" void co_switch(cothread_t cothread);
|
||||
|
||||
#endif
|
@@ -1,215 +0,0 @@
|
||||
#include "libbase.h"
|
||||
#include "libconfig.h"
|
||||
|
||||
void Setting::toggle() {
|
||||
data ^= 1;
|
||||
set(data);
|
||||
}
|
||||
|
||||
uint Setting::get() {
|
||||
return data;
|
||||
}
|
||||
|
||||
void Setting::set(uint _data) {
|
||||
data = _data;
|
||||
|
||||
switch(type) {
|
||||
case BOOL:
|
||||
case ENABLED_DISABLED:
|
||||
case ON_OFF:
|
||||
case YES_NO:
|
||||
data &= 1;
|
||||
break;
|
||||
case HEX8:
|
||||
data &= 0xff;
|
||||
break;
|
||||
case HEX16:
|
||||
data &= 0xffff;
|
||||
break;
|
||||
case HEX24:
|
||||
data &= 0xffffff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char *Setting::strget() {
|
||||
return strptr(char_data);
|
||||
}
|
||||
|
||||
void Setting::strset(const char *_data) {
|
||||
strcpy(char_data, _data);
|
||||
}
|
||||
|
||||
Setting::Setting(Config *_parent, char *_name, char *_desc, uint _data, uint _type) {
|
||||
if(_parent) {
|
||||
_parent->add(this);
|
||||
}
|
||||
|
||||
uint s = strlen(_name);
|
||||
name = (char*)malloc(s + 1);
|
||||
strcpy(name, _name);
|
||||
|
||||
if(_desc) {
|
||||
s = strlen(_desc);
|
||||
desc = (char*)malloc(s + 1);
|
||||
strcpy(desc, _desc);
|
||||
} else {
|
||||
desc = (char*)malloc(1);
|
||||
*desc = 0;
|
||||
}
|
||||
|
||||
data = _data;
|
||||
def = _data;
|
||||
type = _type;
|
||||
}
|
||||
|
||||
Setting::Setting(Config *_parent, char *_name, char *_desc, char *_data) {
|
||||
if(_parent) {
|
||||
_parent->add(this);
|
||||
}
|
||||
|
||||
uint s = strlen(_name);
|
||||
name = (char*)malloc(s + 1);
|
||||
strcpy(name, _name);
|
||||
|
||||
if(_desc) {
|
||||
s = strlen(_desc);
|
||||
desc = (char*)malloc(s + 1);
|
||||
strcpy(desc, _desc);
|
||||
} else {
|
||||
desc = (char*)malloc(1);
|
||||
*desc = 0;
|
||||
}
|
||||
|
||||
strcpy(char_data, _data);
|
||||
strcpy(char_def, _data);
|
||||
|
||||
type = STRING;
|
||||
}
|
||||
|
||||
void Config::add(Setting *setting) {
|
||||
list[list_count++] = setting;
|
||||
}
|
||||
|
||||
uint Config::string_to_uint(uint type, char *input) {
|
||||
if(!strcmp(input, "true") ||
|
||||
!strcmp(input, "enabled") ||
|
||||
!strcmp(input, "on") ||
|
||||
!strcmp(input, "yes")
|
||||
) {
|
||||
return (uint)true;
|
||||
}
|
||||
|
||||
if(!strcmp(input, "false") ||
|
||||
!strcmp(input, "disabled") ||
|
||||
!strcmp(input, "off") ||
|
||||
!strcmp(input, "no")
|
||||
) {
|
||||
return (uint)false;
|
||||
}
|
||||
|
||||
if(strbegin(input, "0x") || strbegin(input, "-0x")) {
|
||||
return sstrhex(input + 2);
|
||||
}
|
||||
|
||||
return sstrdec(input);
|
||||
}
|
||||
|
||||
char *Config::uint_to_string(uint type, uint input) {
|
||||
static char output[512];
|
||||
switch(type) {
|
||||
case Setting::BOOL:
|
||||
sprintf(output, "%s", (input & 1) ? "true" : "false");
|
||||
break;
|
||||
case Setting::ENABLED_DISABLED:
|
||||
sprintf(output, "%s", (input & 1) ? "enabled" : "disabled");
|
||||
break;
|
||||
case Setting::ON_OFF:
|
||||
sprintf(output, "%s", (input & 1) ? "on" : "off");
|
||||
break;
|
||||
case Setting::YES_NO:
|
||||
sprintf(output, "%s", (input & 1) ? "yes" : "no");
|
||||
break;
|
||||
case Setting::DEC: sprintf(output, "%d", input); break;
|
||||
case Setting::HEX: sprintf(output, "0x%x", input); break;
|
||||
case Setting::HEX8: sprintf(output, "0x%0.2x", input & 0xff); break;
|
||||
case Setting::HEX16: sprintf(output, "0x%0.4x", input & 0xffff); break;
|
||||
case Setting::HEX24: sprintf(output, "0x%0.6x", input & 0xffffff); break;
|
||||
case Setting::HEX32: sprintf(output, "0x%0.8x", input); break;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
bool Config::load(const char *fn) {
|
||||
FILE *fp;
|
||||
fp = fopen(fn, "rb");
|
||||
if(!fp)return false;
|
||||
|
||||
//load the config file into memory
|
||||
fseek(fp, 0, SEEK_END);
|
||||
int fsize = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
char *buffer = (char*)malloc(fsize + 1);
|
||||
fread(buffer, 1, fsize, fp);
|
||||
fclose(fp);
|
||||
*(buffer + fsize) = 0;
|
||||
strcpy(data, buffer);
|
||||
free(buffer);
|
||||
|
||||
//split the file into lines
|
||||
replace(data, "\r\n", "\n");
|
||||
qreplace(data, "\t", "");
|
||||
qreplace(data, " ", "");
|
||||
split(line, "\n", data);
|
||||
|
||||
for(int i = 0; i < count(line); i++) {
|
||||
if(strlen(line[i]) == 0)continue;
|
||||
if(*strptr(line[i]) == '#')continue;
|
||||
|
||||
qsplit(part, "=", line[i]);
|
||||
for(int l = 0; l < list_count; l++) {
|
||||
if(!strcmp(list[l]->name, part[0])) {
|
||||
if(list[l]->type != Setting::STR) {
|
||||
list[l]->set(string_to_uint(list[l]->type, strptr(part[1])));
|
||||
} else {
|
||||
list[l]->strset(strptr(part[1]));
|
||||
strunquote(list[l]->char_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool Config::load(string &fn) { return load(strptr(fn)); }
|
||||
|
||||
bool Config::save(const char *fn) {
|
||||
FILE *fp;
|
||||
fp = fopen(fn, "wb");
|
||||
if(!fp)return false;
|
||||
|
||||
for(int i = 0; i < list_count; i++) {
|
||||
strcpy(data, list[i]->desc);
|
||||
replace(data, "\r\n", "\n");
|
||||
split(line, "\n", data);
|
||||
for(int l = 0; l < count(line); l++) {
|
||||
fprintf(fp, "# %s\r\n", strptr(line[l]));
|
||||
}
|
||||
if(list[i]->type != Setting::STRING) {
|
||||
fprintf(fp, "# (default = %s)\r\n", uint_to_string(list[i]->type, list[i]->def));
|
||||
fprintf(fp, "%s = %s\r\n\r\n", list[i]->name, uint_to_string(list[i]->type, list[i]->data));
|
||||
} else {
|
||||
fprintf(fp, "# (default = \"%s\")\r\n", strptr(list[i]->char_def));
|
||||
fprintf(fp, "%s = \"%s\"\r\n\r\n", list[i]->name, strptr(list[i]->char_data));
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
bool Config::save(string &fn) { return save(strptr(fn)); }
|
||||
|
||||
Config::Config() {
|
||||
list_count = 0;
|
||||
}
|
@@ -1,85 +1,185 @@
|
||||
/*
|
||||
libconfig : version 0.11 ~byuu (2006/11/12)
|
||||
libconfig : version 0.14 ~byuu (2007-06-12)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#ifndef __LIBCONFIG
|
||||
#define __LIBCONFIG
|
||||
#ifndef LIBCONFIG_H
|
||||
#define LIBCONFIG_H
|
||||
|
||||
#include "libbase.h"
|
||||
#include "libarray.h"
|
||||
#include "libstring.h"
|
||||
|
||||
class Config;
|
||||
class Setting;
|
||||
|
||||
class Setting {
|
||||
friend class Config;
|
||||
|
||||
protected:
|
||||
uint data, type, def;
|
||||
|
||||
public:
|
||||
enum {
|
||||
BOOL = 0,
|
||||
BOOLEAN = 0,
|
||||
TRUE_FALSE = 0,
|
||||
ENABLED_DISABLED = 1,
|
||||
ON_OFF = 2,
|
||||
YES_NO = 3,
|
||||
DEC = 4,
|
||||
HEX = 5,
|
||||
HEX8 = 6,
|
||||
HEX16 = 7,
|
||||
HEX24 = 8,
|
||||
HEX32 = 9,
|
||||
STRING = 10,
|
||||
STR = 10,
|
||||
};
|
||||
|
||||
char *name, *desc;
|
||||
string char_data, char_def;
|
||||
virtual void toggle();
|
||||
virtual uint get();
|
||||
virtual void set(uint _data);
|
||||
|
||||
virtual char *strget();
|
||||
virtual void strset(const char *_data);
|
||||
|
||||
Setting(Config *_parent, char *_name, char *_desc, uint _data, uint _type);
|
||||
Setting(Config *_parent, char *_name, char *_desc, char *_data);
|
||||
|
||||
template<typename T> inline operator T() { return (T)get(); }
|
||||
template<typename T> inline Setting &operator=(const T &x) { set(x); return *this; }
|
||||
template<typename T> inline bool operator==(const T &x) { return (T)get() == x; }
|
||||
template<typename T> inline bool operator!=(const T &x) { return (T)get() != x; }
|
||||
template<typename T> inline bool operator>=(const T &x) { return (T)get() >= x; }
|
||||
template<typename T> inline bool operator> (const T &x) { return (T)get() > x; }
|
||||
template<typename T> inline bool operator<=(const T &x) { return (T)get() <= x; }
|
||||
template<typename T> inline bool operator< (const T &x) { return (T)get() < x; }
|
||||
|
||||
inline operator char*() { return strget(); }
|
||||
inline Setting &operator=(char *x) { strset(x); return *this; }
|
||||
inline Setting &operator=(const char *x) { strset(x); return *this; }
|
||||
inline bool operator==(const char *x) { return !strcmp(strget(), x); }
|
||||
inline bool operator!=(const char *x) { return strcmp(strget(), x); }
|
||||
};
|
||||
|
||||
class Config {
|
||||
protected:
|
||||
class Config { public:
|
||||
array<Setting*> list;
|
||||
uint list_count;
|
||||
|
||||
string data;
|
||||
stringarray line, part, subpart;
|
||||
|
||||
uint string_to_uint(uint type, char *input);
|
||||
char *uint_to_string(uint type, uint input);
|
||||
|
||||
public:
|
||||
void add(Setting *setting);
|
||||
bool load(const char *fn);
|
||||
bool load(string &fn);
|
||||
bool save(const char *fn);
|
||||
bool save(string &fn);
|
||||
Config();
|
||||
bool load(const string &fn) { return load(strptr(fn)); }
|
||||
bool save(const string &fn) { return save(strptr(fn)); }
|
||||
void add(Setting *setting) { list[list_count++] = setting; }
|
||||
|
||||
Config() : list_count(0) {}
|
||||
};
|
||||
|
||||
class Setting { public:
|
||||
uint type;
|
||||
char *name, *desc, *def;
|
||||
|
||||
enum Type {
|
||||
Integer,
|
||||
String,
|
||||
};
|
||||
|
||||
virtual void set(const char *input) = 0;
|
||||
virtual void get(string &output) = 0;
|
||||
};
|
||||
|
||||
class IntegerSetting : public Setting { public:
|
||||
uint ifmt, data, idef;
|
||||
|
||||
enum Format {
|
||||
Boolean,
|
||||
Decimal,
|
||||
Hex,
|
||||
};
|
||||
|
||||
void set(const char *input) {
|
||||
if(ifmt == Boolean) { data = !strcmp(input, "true"); }
|
||||
if(ifmt == Decimal) { data = strdec(input); }
|
||||
if(ifmt == Hex) { data = strhex(input + (stribegin(input, "0x") ? 2 : 0)); }
|
||||
}
|
||||
|
||||
void get(string &output) {
|
||||
if(ifmt == Boolean) { sprintf(output, "%s", data ? "true" : "false"); }
|
||||
if(ifmt == Decimal) { sprintf(output, "%d", data); }
|
||||
if(ifmt == Hex) { sprintf(output, "%x", data); }
|
||||
}
|
||||
|
||||
uint operator()() { return data; }
|
||||
operator uint() { return data; }
|
||||
template<typename T> IntegerSetting &operator=(T x) { data = uint(x); return *this; }
|
||||
template<typename T> bool operator==(T x) { return (T(data) == x); }
|
||||
template<typename T> bool operator!=(T x) { return (T(data) != x); }
|
||||
template<typename T> bool operator>=(T x) { return (T(data) >= x); }
|
||||
template<typename T> bool operator> (T x) { return (T(data) > x); }
|
||||
template<typename T> bool operator<=(T x) { return (T(data) <= x); }
|
||||
template<typename T> bool operator< (T x) { return (T(data) < x); }
|
||||
|
||||
IntegerSetting(Config *parent, const char *r_name, const char *r_desc, uint r_format, uint r_data) {
|
||||
type = Setting::Integer;
|
||||
name = strdup(r_name);
|
||||
desc = strdup(r_desc);
|
||||
ifmt = r_format;
|
||||
data = idef = r_data;
|
||||
string t;
|
||||
get(t);
|
||||
def = strdup(strptr(t));
|
||||
|
||||
if(parent) { parent->add(this); }
|
||||
}
|
||||
|
||||
~IntegerSetting() {
|
||||
free(name);
|
||||
free(desc);
|
||||
free(def);
|
||||
}
|
||||
};
|
||||
|
||||
class StringSetting : public Setting { public:
|
||||
string data;
|
||||
void set(const char *input) { data = input; strunquote(data); }
|
||||
void get(string &output) { output = data; strquote(output); }
|
||||
|
||||
const char* operator()() { return strptr(data); }
|
||||
operator const char*() { return strptr(data); }
|
||||
StringSetting &operator=(const char *x) { data = x; return *this; }
|
||||
bool operator==(const char *x) { return !strcmp(data, x); }
|
||||
bool operator!=(const char *x) { return strcmp(data, x); }
|
||||
|
||||
StringSetting(Config *parent, const char *r_name, const char *r_desc, const char *r_data) {
|
||||
type = Setting::String;
|
||||
name = strdup(r_name);
|
||||
desc = strdup(r_desc);
|
||||
data = r_data;
|
||||
string t;
|
||||
get(t);
|
||||
def = strdup(strptr(t));
|
||||
|
||||
if(parent) { parent->add(this); }
|
||||
}
|
||||
|
||||
~StringSetting() {
|
||||
free(name);
|
||||
free(desc);
|
||||
free(def);
|
||||
}
|
||||
};
|
||||
|
||||
inline bool Config::load(const char *fn) {
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
if(!fp)return false;
|
||||
|
||||
//load the config file into memory
|
||||
fseek(fp, 0, SEEK_END);
|
||||
int fsize = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
char *buffer = (char*)malloc(fsize + 1);
|
||||
fread(buffer, 1, fsize, fp);
|
||||
fclose(fp);
|
||||
*(buffer + fsize) = 0;
|
||||
strcpy(data, buffer);
|
||||
free(buffer);
|
||||
|
||||
//split the file into lines
|
||||
replace(data, "\r\n", "\n");
|
||||
qreplace(data, "\t", "");
|
||||
qreplace(data, " ", "");
|
||||
split(line, "\n", data);
|
||||
|
||||
for(int i = 0; i < count(line); i++) {
|
||||
if(strlen(line[i]) == 0)continue;
|
||||
if(*strptr(line[i]) == '#')continue;
|
||||
|
||||
qsplit(part, "=", line[i]);
|
||||
for(int l = 0; l < list_count; l++) {
|
||||
if(!strcmp(list[l]->name, part[0])) {
|
||||
list[l]->set(strptr(part[1]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Config::save(const char *fn) {
|
||||
FILE *fp;
|
||||
string t;
|
||||
fp = fopen(fn, "wb");
|
||||
if(!fp)return false;
|
||||
|
||||
for(int i = 0; i < list_count; i++) {
|
||||
strcpy(data, list[i]->desc);
|
||||
replace(data, "\r\n", "\n");
|
||||
split(line, "\n", data);
|
||||
for(int l = 0; l < count(line); l++) {
|
||||
if(line[l] != "") { fprintf(fp, "# %s\r\n", strptr(line[l])); }
|
||||
}
|
||||
|
||||
fprintf(fp, "# (default = %s)\r\n", list[i]->def);
|
||||
list[i]->get(t);
|
||||
fprintf(fp, "%s = %s\r\n\r\n", list[i]->name, strptr(t));
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,451 +0,0 @@
|
||||
/*
|
||||
libfile : version 0.05a ~byuu (10/26/06)
|
||||
*/
|
||||
|
||||
#ifndef __LIBFILE
|
||||
#define __LIBFILE
|
||||
|
||||
/*****
|
||||
* file object
|
||||
*****/
|
||||
|
||||
class file {
|
||||
public:
|
||||
enum { mode_read, mode_write, mode_readwrite, mode_writeread };
|
||||
enum { seek_start, seek_end, seek_back, seek_forward };
|
||||
virtual void read(uint8 *data, uint length) = 0;
|
||||
virtual uint8 read() = 0;
|
||||
|
||||
virtual void write(uint8 *data, uint length) = 0;
|
||||
virtual void write(uint8 data) = 0;
|
||||
|
||||
virtual uint32 crc32();
|
||||
|
||||
virtual void seek(uint offset, uint mode = seek_start) = 0;
|
||||
virtual void truncate(uint size) = 0;
|
||||
virtual uint offset() = 0;
|
||||
virtual uint size() = 0;
|
||||
virtual bool eof() = 0;
|
||||
|
||||
virtual bool open(const char *filename, uint mode) = 0;
|
||||
virtual bool open() = 0;
|
||||
virtual bool flush() = 0;
|
||||
virtual bool close() = 0;
|
||||
};
|
||||
|
||||
inline uint32 file::crc32() {
|
||||
uint pos = offset(), i = size();
|
||||
seek(0);
|
||||
uint32 crc32 = 0xffffffff;
|
||||
while(i--) {
|
||||
crc32 = crc32_adjust(crc32, read());
|
||||
}
|
||||
seek(pos);
|
||||
return ~crc32;
|
||||
}
|
||||
|
||||
/*****
|
||||
* c++ wrappers
|
||||
*****/
|
||||
|
||||
inline void fread(file &s, uint8 *data, uint length) { s.read(data, length); }
|
||||
inline uint8 fread(file &s) { return s.read(); }
|
||||
inline uint8 fgetc(file &s) { return s.read(); }
|
||||
inline uint fgetb(file &s) { return s.read(); }
|
||||
|
||||
inline void fwrite(file &s, uint8 *data, uint length) { s.write(data, length); }
|
||||
inline void fwrite(file &s, uint8 data) { s.write(data); }
|
||||
inline void fputc(uint8 data, file &s) { s.write(data); }
|
||||
inline void fputb(file &s, uint8 data) { s.write(data); }
|
||||
|
||||
inline uint32 fcrc32(file &s) { return s.crc32(); }
|
||||
|
||||
inline void fseek(file &s, uint offset, uint mode = file::seek_start) { s.seek(offset, mode); }
|
||||
inline void ftruncate(file &s, uint size) { s.truncate(size); }
|
||||
inline uint ftell(file &s) { return s.offset(); }
|
||||
inline uint fsize(file &s) { return s.size(); }
|
||||
inline bool feof(file &s) { return s.eof(); }
|
||||
|
||||
inline bool fopen(file &s, const char *filename, uint mode) { return s.open(filename, mode); }
|
||||
inline bool fopen(file &s) { return s.open(); }
|
||||
inline bool fflush(file &s) { return s.flush(); }
|
||||
inline bool fclose(file &s) { return s.close(); }
|
||||
|
||||
|
||||
/*****
|
||||
* endian wrappers
|
||||
*****/
|
||||
|
||||
inline uint8 fgetlb(file &s) { return fgetc(s); }
|
||||
inline uint8 fgetmb(file &s) { return fgetc(s); }
|
||||
|
||||
inline uint16 fgetlw(file &s) {
|
||||
return (fgetc(s)) | (fgetc(s) << 8);
|
||||
}
|
||||
|
||||
inline uint16 fgetmw(file &s) {
|
||||
return (fgetc(s) << 8) | (fgetc(s) << 8);
|
||||
}
|
||||
|
||||
inline uint32 fgetld(file &s) {
|
||||
return (fgetc(s)) | (fgetc(s) << 8) | (fgetc(s) << 16) | (fgetc(s) << 24);
|
||||
}
|
||||
|
||||
inline uint32 fgetmd(file &s) {
|
||||
return (fgetc(s) << 24) | (fgetc(s) << 16) | (fgetc(s) << 8) | (fgetc(s));
|
||||
}
|
||||
|
||||
inline uint64 fgetlq(file &s) {
|
||||
return ((uint64)fgetc(s) << 0) | ((uint64)fgetc(s) << 8) |
|
||||
((uint64)fgetc(s) << 16) | ((uint64)fgetc(s) << 24) |
|
||||
((uint64)fgetc(s) << 32) | ((uint64)fgetc(s) << 40) |
|
||||
((uint64)fgetc(s) << 48) | ((uint64)fgetc(s) << 56);
|
||||
}
|
||||
|
||||
inline uint64 fgetmq(file &s) {
|
||||
return ((uint64)fgetc(s) << 56) | ((uint64)fgetc(s) << 48) |
|
||||
((uint64)fgetc(s) << 40) | ((uint64)fgetc(s) << 32) |
|
||||
((uint64)fgetc(s) << 24) | ((uint64)fgetc(s) << 16) |
|
||||
((uint64)fgetc(s) << 8) | ((uint64)fgetc(s) << 0);
|
||||
}
|
||||
|
||||
inline void fputlb(file &s, uint8 data) { fputc(data, s); }
|
||||
inline void fputmb(file &s, uint8 data) { fputc(data, s); }
|
||||
|
||||
inline void fputlw(file &s, uint16 data) {
|
||||
fputc(data >> 0, s);
|
||||
fputc(data >> 8, s);
|
||||
}
|
||||
|
||||
inline void fputmw(file &s, uint16 data) {
|
||||
fputc(data >> 8, s);
|
||||
fputc(data >> 0, s);
|
||||
}
|
||||
|
||||
inline void fputld(file &s, uint32 data) {
|
||||
fputc(data >> 0, s);
|
||||
fputc(data >> 8, s);
|
||||
fputc(data >> 16, s);
|
||||
fputc(data >> 24, s);
|
||||
}
|
||||
|
||||
inline void fputmd(file &s, uint32 data) {
|
||||
fputc(data >> 24, s);
|
||||
fputc(data >> 16, s);
|
||||
fputc(data >> 8, s);
|
||||
fputc(data >> 0, s);
|
||||
}
|
||||
|
||||
inline void fputlq(file &s, uint64 data) {
|
||||
fputc(data >> 0, s);
|
||||
fputc(data >> 8, s);
|
||||
fputc(data >> 16, s);
|
||||
fputc(data >> 24, s);
|
||||
fputc(data >> 32, s);
|
||||
fputc(data >> 40, s);
|
||||
fputc(data >> 48, s);
|
||||
fputc(data >> 56, s);
|
||||
}
|
||||
|
||||
inline void fputmq(file &s, uint64 data) {
|
||||
fputc(data >> 56, s);
|
||||
fputc(data >> 48, s);
|
||||
fputc(data >> 40, s);
|
||||
fputc(data >> 32, s);
|
||||
fputc(data >> 24, s);
|
||||
fputc(data >> 16, s);
|
||||
fputc(data >> 8, s);
|
||||
fputc(data >> 0, s);
|
||||
}
|
||||
|
||||
/*****
|
||||
* ramfile
|
||||
*****/
|
||||
|
||||
class ramfile : public file {
|
||||
private:
|
||||
FILE *fp;
|
||||
array<uint8> filedata;
|
||||
char filename[1024];
|
||||
uint filepos;
|
||||
uint filesize;
|
||||
uint filemode;
|
||||
bool fileopen;
|
||||
bool filevirtual;
|
||||
|
||||
public:
|
||||
void read(uint8 *data, uint length) {
|
||||
if(!fileopen || filemode == mode_write) { return; }
|
||||
|
||||
memcpy(data, filedata.get(filepos + length) + filepos, length);
|
||||
filepos += length;
|
||||
if(filepos > filesize)filepos = filesize;
|
||||
}
|
||||
|
||||
uint8 read() {
|
||||
if(!fileopen || filemode == mode_write) { return 0; }
|
||||
|
||||
if(eof() == true) { return 0xff; }
|
||||
return filedata[filepos++];
|
||||
}
|
||||
|
||||
void write(uint8 *data, uint length) {
|
||||
if(!fileopen || filemode == mode_read) { return; }
|
||||
|
||||
memcpy(filedata.get(filepos + length) + filepos, data, length);
|
||||
filepos += length;
|
||||
if(filepos > filesize)filesize = filepos;
|
||||
}
|
||||
|
||||
void write(uint8 data) {
|
||||
if(!fileopen || filemode == mode_read) { return; }
|
||||
|
||||
filedata[filepos++] = data;
|
||||
if(filepos > filesize)filesize = filepos;
|
||||
}
|
||||
|
||||
void seek(uint offset, uint mode = seek_start) {
|
||||
if(!fileopen) { return; }
|
||||
|
||||
switch(mode) {
|
||||
case seek_start: filepos = offset; break;
|
||||
case seek_end: filepos = filesize + offset; break;
|
||||
case seek_back: filepos -= offset; break;
|
||||
case seek_forward: filepos += offset; break;
|
||||
}
|
||||
|
||||
if(filemode == mode_read) {
|
||||
if(filepos > filesize)filepos = filesize;
|
||||
} else {
|
||||
if(filepos > filesize)filesize = filepos;
|
||||
}
|
||||
}
|
||||
|
||||
void truncate(uint size) {
|
||||
filesize = size;
|
||||
if(filepos > filesize)filepos = filesize;
|
||||
}
|
||||
|
||||
uint offset() {
|
||||
if(!fileopen) { return 0; }
|
||||
|
||||
return filepos;
|
||||
}
|
||||
|
||||
uint size() {
|
||||
if(!fileopen) { return 0; }
|
||||
|
||||
return filesize;
|
||||
}
|
||||
|
||||
bool eof() {
|
||||
if(!fileopen) { return true; }
|
||||
|
||||
return (filepos >= filesize);
|
||||
}
|
||||
|
||||
bool open(const char *fn, uint mode) {
|
||||
if(fileopen) { return false; }
|
||||
|
||||
strcpy(filename, fn ? fn : "");
|
||||
filevirtual = (*filename == 0);
|
||||
filemode = mode;
|
||||
switch(filemode) {
|
||||
case mode_read:
|
||||
case mode_readwrite:
|
||||
if(filevirtual == true) {
|
||||
filesize = 0;
|
||||
} else {
|
||||
fp = fopen(filename, "rb");
|
||||
if(!fp) { return false; }
|
||||
filesize = fsize(fp);
|
||||
fread(filedata.get(filesize), 1, filesize, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
filesize = 0;
|
||||
break;
|
||||
}
|
||||
filepos = 0;
|
||||
fileopen = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool open() {
|
||||
return fileopen;
|
||||
}
|
||||
|
||||
bool flush() {
|
||||
if(!fileopen) { return false; }
|
||||
|
||||
switch(filemode) {
|
||||
case mode_readwrite:
|
||||
case mode_write:
|
||||
case mode_writeread:
|
||||
if(filevirtual == false) {
|
||||
fp = fopen(filename, "wb");
|
||||
if(!fp) { return false; }
|
||||
fwrite(filedata.get(filesize), 1, filesize, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool close() {
|
||||
if(!fileopen) { return false; }
|
||||
|
||||
bool result = flush();
|
||||
fileopen = false;
|
||||
filedata.reset();
|
||||
return result;
|
||||
}
|
||||
|
||||
ramfile() {
|
||||
fileopen = false;
|
||||
}
|
||||
|
||||
~ramfile() {
|
||||
if(fileopen) { close(); }
|
||||
}
|
||||
};
|
||||
|
||||
/*****
|
||||
* diskfile
|
||||
*****/
|
||||
|
||||
class diskfile : public file {
|
||||
private:
|
||||
FILE *fp;
|
||||
uint filemode;
|
||||
|
||||
public:
|
||||
void read(uint8 *data, uint length) {
|
||||
if(!fp || filemode == mode_write) { return; }
|
||||
|
||||
fread(data, 1, length, fp);
|
||||
}
|
||||
|
||||
uint8 read() {
|
||||
if(!fp || filemode == mode_write) { return 0; }
|
||||
|
||||
if(eof() == true) { return 0xff; }
|
||||
return fgetc(fp);
|
||||
}
|
||||
|
||||
void write(uint8 *data, uint length) {
|
||||
if(!fp || filemode == mode_read) { return; }
|
||||
|
||||
fwrite(data, 1, length, fp);
|
||||
}
|
||||
|
||||
void write(uint8 data) {
|
||||
if(!fp || filemode == mode_read) { return; }
|
||||
|
||||
fputc(data, fp);
|
||||
}
|
||||
|
||||
void seek(uint offset, uint mode = seek_start) {
|
||||
if(!fp) { return; }
|
||||
|
||||
switch(mode) {
|
||||
default:
|
||||
case seek_start: fseek(fp, offset, SEEK_SET); break;
|
||||
case seek_end: fseek(fp, offset, SEEK_END); break;
|
||||
case seek_back: fseek(fp, offset, SEEK_CUR); break;
|
||||
case seek_forward: fseek(fp, offset, SEEK_CUR); break;
|
||||
}
|
||||
}
|
||||
|
||||
void truncate(uint size) {
|
||||
if(!fp) { return; }
|
||||
|
||||
ftruncate(fp, size);
|
||||
}
|
||||
|
||||
uint offset() {
|
||||
if(!fp) { return 0; }
|
||||
|
||||
return ftell(fp);
|
||||
}
|
||||
|
||||
uint size() {
|
||||
if(!fp) { return 0; }
|
||||
|
||||
uint pos = ftell(fp);
|
||||
fseek(fp, 0, SEEK_END);
|
||||
uint filesize = ftell(fp);
|
||||
fseek(fp, pos, SEEK_SET);
|
||||
return filesize;
|
||||
}
|
||||
|
||||
bool eof() {
|
||||
if(!fp) { return true; }
|
||||
|
||||
if(feof(fp)) {
|
||||
seek(size(), seek_start);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool open(const char *filename, uint mode) {
|
||||
if(fp) { return false; }
|
||||
|
||||
filemode = mode;
|
||||
char m[8];
|
||||
switch(filemode) {
|
||||
default:
|
||||
case mode_read: strcpy(m, "rb"); break;
|
||||
case mode_write: strcpy(m, "wb"); break;
|
||||
case mode_readwrite: strcpy(m, "rb+"); break;
|
||||
case mode_writeread: strcpy(m, "wb+"); break;
|
||||
}
|
||||
fp = fopen(filename, m);
|
||||
if(!fp) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool open() {
|
||||
return (fp != 0);
|
||||
}
|
||||
|
||||
bool flush() {
|
||||
if(!fp) { return false; }
|
||||
|
||||
fflush(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool close() {
|
||||
if(!fp) { return false; }
|
||||
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
diskfile() {
|
||||
fp = 0;
|
||||
}
|
||||
|
||||
~diskfile() {
|
||||
if(fp) { fclose(fp); }
|
||||
}
|
||||
};
|
||||
|
||||
/*****
|
||||
* directory object
|
||||
*****/
|
||||
|
||||
class directory {
|
||||
public:
|
||||
void open(const char *path) {}
|
||||
void close() {}
|
||||
uint read(char *filename, uint maxlength) { return 0; }
|
||||
};
|
||||
|
||||
#endif
|
100
src/lib/libfunctor.h
Normal file
100
src/lib/libfunctor.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
libfunctor : version 0.05 ~byuu (2007-09-08)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#ifndef LIBFUNCTOR_H
|
||||
#define LIBFUNCTOR_H
|
||||
|
||||
//prologue
|
||||
|
||||
#define TN typename
|
||||
|
||||
template<typename T> class functor;
|
||||
|
||||
//parameters = 0
|
||||
|
||||
#define cat(n) n
|
||||
#define TL typename R
|
||||
#define PL
|
||||
#define CL
|
||||
|
||||
#include "libfunctor_impl.h"
|
||||
|
||||
//parameters = 1
|
||||
|
||||
#define cat(n) , n
|
||||
#define TL TN R, TN P1
|
||||
#define PL P1 p1
|
||||
#define CL p1
|
||||
|
||||
#include "libfunctor_impl.h"
|
||||
|
||||
//parameters = 2
|
||||
|
||||
#define cat(n) , n
|
||||
#define TL TN R, TN P1, TN P2
|
||||
#define PL P1 p1, P2 p2
|
||||
#define CL p1, p2
|
||||
|
||||
#include "libfunctor_impl.h"
|
||||
|
||||
//parameters = 3
|
||||
|
||||
#define cat(n) , n
|
||||
#define TL TN R, TN P1, TN P2, TN P3
|
||||
#define PL P1 p1, P2 p2, P3 p3
|
||||
#define CL p1, p2, p3
|
||||
|
||||
#include "libfunctor_impl.h"
|
||||
|
||||
//parameters = 4
|
||||
|
||||
#define cat(n) , n
|
||||
#define TL TN R, TN P1, TN P2, TN P3, TN P4
|
||||
#define PL P1 p1, P2 p2, P3 p3, P4 p4
|
||||
#define CL p1, p2, p3, p4
|
||||
|
||||
#include "libfunctor_impl.h"
|
||||
|
||||
//parameters = 5
|
||||
|
||||
#define cat(n) , n
|
||||
#define TL TN R, TN P1, TN P2, TN P3, TN P4, TN P5
|
||||
#define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5
|
||||
#define CL p1, p2, p3, p4, p5
|
||||
|
||||
#include "libfunctor_impl.h"
|
||||
|
||||
//parameters = 6
|
||||
|
||||
#define cat(n) , n
|
||||
#define TL TN R, TN P1, TN P2, TN P3, TN P4, TN P5, TN P6
|
||||
#define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6
|
||||
#define CL p1, p2, p3, p4, p5, p6
|
||||
|
||||
#include "libfunctor_impl.h"
|
||||
|
||||
//parameters = 7
|
||||
|
||||
#define cat(n) , n
|
||||
#define TL TN R, TN P1, TN P2, TN P3, TN P4, TN P5, TN P6, TN P7
|
||||
#define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7
|
||||
#define CL p1, p2, p3, p4, p5, p6, p7
|
||||
|
||||
#include "libfunctor_impl.h"
|
||||
|
||||
//parameters = 8
|
||||
|
||||
#define cat(n) , n
|
||||
#define TL TN R, TN P1, TN P2, TN P3, TN P4, TN P5, TN P6, TN P7, TN P8
|
||||
#define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8
|
||||
#define CL p1, p2, p3, p4, p5, p6, p7, p8
|
||||
|
||||
#include "libfunctor_impl.h"
|
||||
|
||||
//epilogue
|
||||
|
||||
#undef TN
|
||||
|
||||
#endif
|
81
src/lib/libfunctor_impl.h
Normal file
81
src/lib/libfunctor_impl.h
Normal file
@@ -0,0 +1,81 @@
|
||||
#ifdef LIBFUNCTOR_H
|
||||
|
||||
template<TL>
|
||||
class functor<R (PL)> {
|
||||
private:
|
||||
struct base1 { virtual void func1(PL) {} };
|
||||
struct base2 { virtual void func2(PL) {} };
|
||||
struct derived : base1, virtual base2 {};
|
||||
|
||||
struct data_t {
|
||||
R (*fn_call)(const data_t& cat(PL));
|
||||
union {
|
||||
R (*fn_global)(PL);
|
||||
struct {
|
||||
R (derived::*fn_member)(PL);
|
||||
void *object;
|
||||
};
|
||||
};
|
||||
} data;
|
||||
|
||||
static R fn_call_global(const data_t &d cat(PL)) {
|
||||
return d.fn_global(CL);
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
static R fn_call_member(const data_t &d cat(PL)) {
|
||||
return (((C*)d.object)->*((R (C::*&)(PL))d.fn_member))(CL);
|
||||
}
|
||||
|
||||
public:
|
||||
R operator()(PL) const { return data.fn_call(data cat(CL)); }
|
||||
operator bool() const { return data.fn_call; }
|
||||
|
||||
functor() { data.fn_call = 0; }
|
||||
|
||||
functor(R (*fn)(PL)) {
|
||||
data.fn_call = &fn_call_global;
|
||||
data.fn_global = fn;
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
functor(R (C::*fn)(PL), C *obj) {
|
||||
data.fn_call = &fn_call_member<C>;
|
||||
(R (C::*&)(PL))data.fn_member = fn;
|
||||
assert(sizeof data.fn_member >= sizeof fn);
|
||||
data.object = obj;
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
functor(R (C::*fn)(PL) const, C *obj) {
|
||||
data.fn_call = &fn_call_member<C>;
|
||||
(R (C::*&)(PL))data.fn_member = (R (C::*&)(PL))fn;
|
||||
assert(sizeof data.fn_member >= sizeof fn);
|
||||
data.object = obj;
|
||||
}
|
||||
|
||||
functor &operator=(const functor &source) { memcpy(&data, &source.data, sizeof(data_t)); return *this; }
|
||||
functor(const functor &source) { memcpy(&data, &source.data, sizeof(data_t)); }
|
||||
};
|
||||
|
||||
template<TL>
|
||||
functor<R (PL)> bind(R (*fn)(PL)) {
|
||||
return functor<R (PL)>(fn);
|
||||
}
|
||||
|
||||
template<typename C, TL>
|
||||
functor<R (PL)> bind(R (C::*fn)(PL), C *obj) {
|
||||
return functor<R (PL)>(fn, obj);
|
||||
}
|
||||
|
||||
template<typename C, TL>
|
||||
functor<R (PL)> bind(R (C::*fn)(PL) const, C *obj) {
|
||||
return functor<R (PL)>(fn, obj);
|
||||
}
|
||||
|
||||
#undef cat
|
||||
#undef TL
|
||||
#undef PL
|
||||
#undef CL
|
||||
|
||||
#endif
|
@@ -1,182 +1,309 @@
|
||||
/*
|
||||
libkeymap : version 0.02 ~byuu (07/30/06)
|
||||
libkeymap : version 0.02 ~byuu (2007-05-28)
|
||||
*/
|
||||
|
||||
#ifndef __LIBKEYMAP
|
||||
#define __LIBKEYMAP
|
||||
#ifndef LIBKEYMAP_H
|
||||
#define LIBKEYMAP_H
|
||||
|
||||
class keymap {
|
||||
private:
|
||||
char tmp[32];
|
||||
namespace keymap {
|
||||
|
||||
public:
|
||||
//TODO: use lookup table for find() functions
|
||||
static char keytable[][64] = {
|
||||
"none",
|
||||
"esc",
|
||||
"f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12",
|
||||
"print_screen", "sys_req", "scroll_lock", "pause", "brk",
|
||||
"grave", "tilde",
|
||||
"num_1", "exclamation",
|
||||
"num_2", "at",
|
||||
"num_3", "pound",
|
||||
"num_4", "dollar",
|
||||
"num_5", "percent",
|
||||
"num_6", "power",
|
||||
"num_7", "ampersand",
|
||||
"num_8", "asterisk",
|
||||
"num_9", "lparenthesis",
|
||||
"num_0", "rparenthesis",
|
||||
"minus", "underscore",
|
||||
"equal", "plus",
|
||||
"backspace",
|
||||
};
|
||||
|
||||
uint null;
|
||||
uint esc;
|
||||
uint f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12;
|
||||
uint print_screen, scroll_lock, pause;
|
||||
uint tilde;
|
||||
uint num_0, num_1, num_2, num_3, num_4;
|
||||
uint num_5, num_6, num_7, num_8, num_9;
|
||||
uint minus, plus, backspace;
|
||||
uint ins, del, home, end, page_up, page_down;
|
||||
uint a, b, c, d, e, f, g, h, i, j, k, l, m;
|
||||
uint n, o, p, q, r, s, t, u, v, w, x, y, z;
|
||||
uint lbracket, rbracket;
|
||||
uint pipe, colon, quote, comma, period, question;
|
||||
uint numpad_0, numpad_1, numpad_2, numpad_3, numpad_4;
|
||||
uint numpad_5, numpad_6, numpad_7, numpad_8, numpad_9;
|
||||
uint numpad_plus, numpad_minus, numpad_mul;
|
||||
uint numpad_div, numpad_enter, numpad_point;
|
||||
uint numlock, capslock;
|
||||
uint up, down, left, right;
|
||||
uint tab, enter, space;
|
||||
uint lctrl, rctrl, lalt, ralt, lshift, rshift;
|
||||
uint lwin, rwin, menu;
|
||||
enum {
|
||||
none = 0x0000,
|
||||
|
||||
struct {
|
||||
uint up, down, left, right;
|
||||
uint button[128];
|
||||
} joypad[16];
|
||||
esc,
|
||||
|
||||
uint find(const char *key) {
|
||||
#define match(n) if(!strcmp(#n, key))return n;
|
||||
match(null)
|
||||
match(esc)
|
||||
match(f1) match(f2) match(f3) match(f4) match(f5) match(f6)
|
||||
match(f7) match(f8) match(f9) match(f10) match(f11) match(f12)
|
||||
match(print_screen) match(scroll_lock) match(pause)
|
||||
match(tilde)
|
||||
match(num_0) match(num_1) match(num_2) match(num_3) match(num_4)
|
||||
match(num_5) match(num_6) match(num_7) match(num_8) match(num_9)
|
||||
match(minus) match(plus) match(backspace)
|
||||
match(ins) match(del) match(home)
|
||||
match(end) match(page_up) match(page_down)
|
||||
match(a) match(b) match(c) match(d) match(e) match(f)
|
||||
match(g) match(h) match(i) match(j) match(k) match(l)
|
||||
match(m) match(n) match(o) match(p) match(q) match(r)
|
||||
match(s) match(t) match(u) match(v) match(w) match(x)
|
||||
match(y) match(z)
|
||||
match(lbracket) match(rbracket)
|
||||
match(pipe) match(colon) match(quote)
|
||||
match(comma) match(period) match(question)
|
||||
match(numpad_0) match(numpad_1) match(numpad_2) match(numpad_3)
|
||||
match(numpad_4) match(numpad_5) match(numpad_6) match(numpad_7)
|
||||
match(numpad_8) match(numpad_9)
|
||||
match(numpad_plus) match(numpad_minus) match(numpad_mul)
|
||||
match(numpad_div) match(numpad_enter) match(numpad_point)
|
||||
match(numlock) match(capslock)
|
||||
match(up) match(down) match(left) match(right)
|
||||
match(tab) match(enter) match(space)
|
||||
match(lctrl) match(rctrl) match(lalt)
|
||||
match(ralt) match(lshift) match(rshift)
|
||||
match(lwin) match(rwin) match(menu)
|
||||
#undef match
|
||||
f1,
|
||||
f2,
|
||||
f3,
|
||||
f4,
|
||||
f5,
|
||||
f6,
|
||||
f7,
|
||||
f8,
|
||||
f9,
|
||||
f10,
|
||||
f11,
|
||||
f12,
|
||||
|
||||
if(!memcmp(key, "joypad", 6)) {
|
||||
const char *p = key + 6;
|
||||
int joy, bn, n;
|
||||
sscanf(p, "%d%n", &joy, &n);
|
||||
p += n;
|
||||
if(*p == '.') {
|
||||
p++;
|
||||
if(!strcmp(p, "up")) { return joypad[joy].up; }
|
||||
if(!strcmp(p, "down")) { return joypad[joy].down; }
|
||||
if(!strcmp(p, "left")) { return joypad[joy].left; }
|
||||
if(!strcmp(p, "right")) { return joypad[joy].right; }
|
||||
if(!memcmp(p, "button", 6)) {
|
||||
p += 6;
|
||||
sscanf(p, "%d", &bn);
|
||||
return joypad[joy].button[bn];
|
||||
}
|
||||
}
|
||||
}
|
||||
print_screen, sys_req,
|
||||
scroll_lock,
|
||||
pause, brk,
|
||||
|
||||
return 0;
|
||||
}
|
||||
grave, tilde,
|
||||
|
||||
const char *find(uint key) {
|
||||
#define match(n) if(n == key)return #n;
|
||||
match(null)
|
||||
match(esc)
|
||||
match(f1) match(f2) match(f3) match(f4) match(f5) match(f6)
|
||||
match(f7) match(f8) match(f9) match(f10) match(f11) match(f12)
|
||||
match(print_screen) match(scroll_lock) match(pause)
|
||||
match(tilde)
|
||||
match(num_0) match(num_1) match(num_2) match(num_3) match(num_4)
|
||||
match(num_5) match(num_6) match(num_7) match(num_8) match(num_9)
|
||||
match(minus) match(plus) match(backspace)
|
||||
match(ins) match(del) match(home)
|
||||
match(end) match(page_up) match(page_down)
|
||||
match(a) match(b) match(c) match(d) match(e) match(f)
|
||||
match(g) match(h) match(i) match(j) match(k) match(l)
|
||||
match(m) match(n) match(o) match(p) match(q) match(r)
|
||||
match(s) match(t) match(u) match(v) match(w) match(x)
|
||||
match(y) match(z)
|
||||
match(lbracket) match(rbracket)
|
||||
match(pipe) match(colon) match(quote)
|
||||
match(comma) match(period) match(question)
|
||||
match(numpad_0) match(numpad_1) match(numpad_2) match(numpad_3)
|
||||
match(numpad_4) match(numpad_5) match(numpad_6) match(numpad_7)
|
||||
match(numpad_8) match(numpad_9)
|
||||
match(numpad_plus) match(numpad_minus) match(numpad_mul)
|
||||
match(numpad_div) match(numpad_enter) match(numpad_point)
|
||||
match(numlock) match(capslock)
|
||||
match(up) match(down) match(left) match(right)
|
||||
match(tab) match(enter) match(space)
|
||||
match(lctrl) match(rctrl) match(lalt)
|
||||
match(ralt) match(lshift) match(rshift)
|
||||
match(lwin) match(rwin) match(menu)
|
||||
#undef match
|
||||
num_1, exclamation,
|
||||
num_2, at,
|
||||
num_3, pound,
|
||||
num_4, dollar,
|
||||
num_5, percent,
|
||||
num_6, power,
|
||||
num_7, ampersand,
|
||||
num_8, asterisk,
|
||||
num_9, lparenthesis,
|
||||
num_0, rparenthesis,
|
||||
|
||||
for(int joy = 0; joy < 16; joy++) {
|
||||
if(joypad[joy].up == key) { sprintf(tmp, "joypad%d.up", joy); return tmp; }
|
||||
if(joypad[joy].down == key) { sprintf(tmp, "joypad%d.down", joy); return tmp; }
|
||||
if(joypad[joy].left == key) { sprintf(tmp, "joypad%d.left", joy); return tmp; }
|
||||
if(joypad[joy].right == key) { sprintf(tmp, "joypad%d.right", joy); return tmp; }
|
||||
for(int bn = 0; bn < 128; bn++) {
|
||||
if(joypad[joy].button[bn] == key) { sprintf(tmp, "joypad%d.button%d", joy, bn); return tmp; }
|
||||
}
|
||||
}
|
||||
minus, underscore,
|
||||
equal, plus,
|
||||
backspace,
|
||||
|
||||
return "null";
|
||||
}
|
||||
ins,
|
||||
del,
|
||||
home,
|
||||
end,
|
||||
page_up,
|
||||
page_down,
|
||||
|
||||
keymap() {
|
||||
null = 0;
|
||||
esc = 0;
|
||||
f1 = f2 = f3 = f4 = f5 = f6 = 0;
|
||||
f7 = f8 = f9 = f10 = f11 = f12 = 0;
|
||||
print_screen = scroll_lock = pause = 0;
|
||||
tilde = 0;
|
||||
num_0 = num_1 = num_2 = num_3 = num_4 = 0;
|
||||
num_5 = num_6 = num_7 = num_8 = num_9 = 0;
|
||||
minus = plus = backspace = 0;
|
||||
ins = del = home = end = page_up = page_down = 0;
|
||||
a = b = c = d = e = f = g = h = i = 0;
|
||||
j = k = l = m = n = o = p = q = r = 0;
|
||||
s = t = u = v = w = x = y = z = 0;
|
||||
lbracket = rbracket = 0;
|
||||
pipe = colon = quote = comma = period = question = 0;
|
||||
numpad_0 = numpad_1 = numpad_2 = numpad_3 = numpad_4 = 0;
|
||||
numpad_5 = numpad_6 = numpad_7 = numpad_8 = numpad_9 = 0;
|
||||
numpad_plus = numpad_minus = numpad_mul = 0;
|
||||
numpad_div = numpad_enter = numpad_point = 0;
|
||||
numlock = capslock = 0;
|
||||
up = down = left = right = 0;
|
||||
tab = enter = space = 0;
|
||||
lctrl = rctrl = lalt = ralt = lshift = rshift = 0;
|
||||
lwin = rwin = menu = 0;
|
||||
a, b, c, d, e, f, g, h, i, j, k, l, m,
|
||||
n, o, p, q, r, s, t, u, v, w, x, y, z,
|
||||
|
||||
for(int joy = 0; joy < 16; joy++) {
|
||||
joypad[joy].up = 0;
|
||||
joypad[joy].down = 0;
|
||||
joypad[joy].left = 0;
|
||||
joypad[joy].right = 0;
|
||||
memset(joypad[joy].button, 0, sizeof(joypad[joy].button));
|
||||
A, B, C, D, E, F, G, H, I, J, K, L, M,
|
||||
N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
|
||||
|
||||
lbracket, lbrace,
|
||||
rbracket, rbrace,
|
||||
backslash, pipe,
|
||||
semicolon, colon,
|
||||
apostrophe, quote,
|
||||
comma, lcaret,
|
||||
period, rcaret,
|
||||
slash, question,
|
||||
|
||||
kp_1, kp_end,
|
||||
kp_2, kp_down,
|
||||
kp_3, kp_page_down,
|
||||
kp_4, kp_left,
|
||||
kp_5, kp_center,
|
||||
kp_6, kp_right,
|
||||
kp_7, kp_home,
|
||||
kp_8, kp_up,
|
||||
kp_9, kp_page_up,
|
||||
kp_0, kp_insert,
|
||||
kp_decimal, kp_delete,
|
||||
|
||||
kp_plus,
|
||||
kp_minus,
|
||||
kp_mul,
|
||||
kp_div,
|
||||
kp_enter,
|
||||
|
||||
num_lock,
|
||||
caps_lock,
|
||||
|
||||
up,
|
||||
down,
|
||||
left,
|
||||
right,
|
||||
|
||||
tab,
|
||||
enter,
|
||||
space,
|
||||
|
||||
lctrl,
|
||||
rctrl,
|
||||
lalt,
|
||||
ralt,
|
||||
lshift,
|
||||
rshift,
|
||||
lsuper,
|
||||
rsuper,
|
||||
menu,
|
||||
|
||||
limit, //not an actual key -- marks the end of linear key entries
|
||||
|
||||
joypad_flag = 0x8000,
|
||||
joypad_nummask = 0x7f00,
|
||||
joypad_keymask = 0x00ff,
|
||||
|
||||
joypad_up = 0x0080,
|
||||
joypad_down = 0x0081,
|
||||
joypad_left = 0x0082,
|
||||
joypad_right = 0x0083,
|
||||
};
|
||||
|
||||
static uint16 find(const char *key) {
|
||||
#define match(_n) if(!strcmp(#_n, key)) { return _n; }
|
||||
match(none)
|
||||
match(esc)
|
||||
match(f1) match(f2) match(f3) match(f4) match(f5) match(f6)
|
||||
match(f7) match(f8) match(f9) match(f10) match(f11) match(f12)
|
||||
match(print_screen) match(sys_req) match(scroll_lock) match(pause) match(brk)
|
||||
match(grave) match(tilde)
|
||||
match(num_1) match(exclamation)
|
||||
match(num_2) match(at)
|
||||
match(num_3) match(pound)
|
||||
match(num_4) match(dollar)
|
||||
match(num_5) match(percent)
|
||||
match(num_6) match(power)
|
||||
match(num_7) match(ampersand)
|
||||
match(num_8) match(asterisk)
|
||||
match(num_9) match(lparenthesis)
|
||||
match(num_0) match(rparenthesis)
|
||||
match(minus) match(underscore) match(equal) match(plus) match(backspace)
|
||||
match(ins) match(del) match(home) match(end) match(page_up) match(page_down)
|
||||
match(a) match(b) match(c) match(d) match(e) match(f)
|
||||
match(g) match(h) match(i) match(j) match(k) match(l)
|
||||
match(m) match(n) match(o) match(p) match(q) match(r)
|
||||
match(s) match(t) match(u) match(v) match(w) match(x)
|
||||
match(y) match(z)
|
||||
match(A) match(B) match(C) match(D) match(E) match(F)
|
||||
match(G) match(H) match(I) match(J) match(K) match(L)
|
||||
match(M) match(N) match(O) match(P) match(Q) match(R)
|
||||
match(S) match(T) match(U) match(V) match(W) match(X)
|
||||
match(Y) match(Z)
|
||||
match(lbracket) match(lbrace)
|
||||
match(rbracket) match(rbrace)
|
||||
match(backslash) match(pipe)
|
||||
match(semicolon) match(colon)
|
||||
match(apostrophe) match(quote)
|
||||
match(comma) match(lcaret)
|
||||
match(period) match(rcaret)
|
||||
match(slash) match(question)
|
||||
match(kp_1) match(kp_end)
|
||||
match(kp_2) match(kp_down)
|
||||
match(kp_3) match(kp_page_down)
|
||||
match(kp_4) match(kp_left)
|
||||
match(kp_5) match(kp_center)
|
||||
match(kp_6) match(kp_right)
|
||||
match(kp_7) match(kp_home)
|
||||
match(kp_8) match(kp_up)
|
||||
match(kp_9) match(kp_page_up)
|
||||
match(kp_0) match(kp_insert)
|
||||
match(kp_decimal) match(kp_delete)
|
||||
match(kp_plus) match(kp_minus) match(kp_mul) match(kp_div) match(kp_enter)
|
||||
match(num_lock) match(caps_lock)
|
||||
match(up) match(down) match(left) match(right)
|
||||
match(tab) match(enter) match(space)
|
||||
match(lctrl) match(rctrl)
|
||||
match(lalt) match(ralt)
|
||||
match(lshift) match(rshift)
|
||||
match(lsuper) match(rsuper)
|
||||
match(menu)
|
||||
#undef match
|
||||
|
||||
if(!memcmp(key, "joypad", 6)) {
|
||||
const char *p = key + 6;
|
||||
uint joypad, button, n;
|
||||
sscanf(p, "%u%n", &joypad, &n);
|
||||
joypad &= 127;
|
||||
p += n;
|
||||
if(!strcmp(p, ".up")) { return joypad_flag | (joypad << 8) | joypad_up; }
|
||||
if(!strcmp(p, ".down")) { return joypad_flag | (joypad << 8) | joypad_down; }
|
||||
if(!strcmp(p, ".left")) { return joypad_flag | (joypad << 8) | joypad_left; }
|
||||
if(!strcmp(p, ".right")) { return joypad_flag | (joypad << 8) | joypad_right; }
|
||||
if(!memcmp(p, ".button", 7)) {
|
||||
sscanf(p + 7, "%u", &button);
|
||||
button &= 127;
|
||||
return joypad_flag | (joypad << 8) | button;
|
||||
}
|
||||
}
|
||||
|
||||
return none;
|
||||
}
|
||||
|
||||
static char *find(char *out, uint16 key) {
|
||||
#define match(_n) if(_n == key) { strcpy(out, #_n); return out; }
|
||||
match(none)
|
||||
match(esc)
|
||||
match(f1) match(f2) match(f3) match(f4) match(f5) match(f6)
|
||||
match(f7) match(f8) match(f9) match(f10) match(f11) match(f12)
|
||||
match(print_screen) match(sys_req) match(scroll_lock) match(pause) match(brk)
|
||||
match(grave) match(tilde)
|
||||
match(num_1) match(exclamation)
|
||||
match(num_2) match(at)
|
||||
match(num_3) match(pound)
|
||||
match(num_4) match(dollar)
|
||||
match(num_5) match(percent)
|
||||
match(num_6) match(power)
|
||||
match(num_7) match(ampersand)
|
||||
match(num_8) match(asterisk)
|
||||
match(num_9) match(lparenthesis)
|
||||
match(num_0) match(rparenthesis)
|
||||
match(minus) match(underscore) match(equal) match(plus) match(backspace)
|
||||
match(ins) match(del) match(home) match(end) match(page_up) match(page_down)
|
||||
match(a) match(b) match(c) match(d) match(e) match(f)
|
||||
match(g) match(h) match(i) match(j) match(k) match(l)
|
||||
match(m) match(n) match(o) match(p) match(q) match(r)
|
||||
match(s) match(t) match(u) match(v) match(w) match(x)
|
||||
match(y) match(z)
|
||||
match(A) match(B) match(C) match(D) match(E) match(F)
|
||||
match(G) match(H) match(I) match(J) match(K) match(L)
|
||||
match(M) match(N) match(O) match(P) match(Q) match(R)
|
||||
match(S) match(T) match(U) match(V) match(W) match(X)
|
||||
match(Y) match(Z)
|
||||
match(lbracket) match(lbrace)
|
||||
match(rbracket) match(rbrace)
|
||||
match(backslash) match(pipe)
|
||||
match(semicolon) match(colon)
|
||||
match(apostrophe) match(quote)
|
||||
match(comma) match(lcaret)
|
||||
match(period) match(rcaret)
|
||||
match(slash) match(question)
|
||||
match(kp_1) match(kp_end)
|
||||
match(kp_2) match(kp_down)
|
||||
match(kp_3) match(kp_page_down)
|
||||
match(kp_4) match(kp_left)
|
||||
match(kp_5) match(kp_center)
|
||||
match(kp_6) match(kp_right)
|
||||
match(kp_7) match(kp_home)
|
||||
match(kp_8) match(kp_up)
|
||||
match(kp_9) match(kp_page_up)
|
||||
match(kp_0) match(kp_insert)
|
||||
match(kp_decimal) match(kp_delete)
|
||||
match(kp_plus) match(kp_minus) match(kp_mul) match(kp_div) match(kp_enter)
|
||||
match(num_lock) match(caps_lock)
|
||||
match(up) match(down) match(left) match(right)
|
||||
match(tab) match(enter) match(space)
|
||||
match(lctrl) match(rctrl)
|
||||
match(lalt) match(ralt)
|
||||
match(lshift) match(rshift)
|
||||
match(lsuper) match(rsuper)
|
||||
match(menu)
|
||||
#undef match
|
||||
|
||||
if(key & joypad_flag) {
|
||||
uint joypad = (key & joypad_nummask) >> 8;
|
||||
uint button = (key & joypad_keymask);
|
||||
if(button == joypad_up) { sprintf(out, "joypad%d.up", joypad); return out; }
|
||||
if(button == joypad_down) { sprintf(out, "joypad%d.down", joypad); return out; }
|
||||
if(button == joypad_left) { sprintf(out, "joypad%d.left", joypad); return out; }
|
||||
if(button == joypad_right) { sprintf(out, "joypad%d.right", joypad); return out; }
|
||||
sprintf(out, "joypad%d.button%d", joypad, button & 127);
|
||||
return out;
|
||||
}
|
||||
|
||||
strcpy(out, "none");
|
||||
return out;
|
||||
}
|
||||
|
||||
static char find_t[256];
|
||||
|
||||
static const char *find(uint16 key) {
|
||||
find(find_t, key);
|
||||
return find_t;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -2,8 +2,8 @@
|
||||
libsort : version 0.01 ~byuu (2006-11-15)
|
||||
*/
|
||||
|
||||
#ifndef __LIBSORT
|
||||
#define __LIBSORT
|
||||
#ifndef LIBSORT_H
|
||||
#define LIBSORT_H
|
||||
|
||||
template<typename T>
|
||||
void sort(T list[], uint length) {
|
||||
@@ -31,4 +31,4 @@ void sort(T list[], uint length, Tcmp comparator) {
|
||||
}
|
||||
}
|
||||
|
||||
#endif __LIBSORT
|
||||
#endif
|
||||
|
@@ -2,7 +2,7 @@
|
||||
#include "libstring.h"
|
||||
#include "libstring_oo.cpp"
|
||||
|
||||
uint count(stringarray &str) { return str.size(); }
|
||||
#include "libstring_array.cpp"
|
||||
|
||||
char chrlower(char c) {
|
||||
if(c >= 'A' && c <= 'Z')return c + ('a' - 'A');
|
||||
@@ -14,13 +14,12 @@ char chrupper(char c) {
|
||||
return c;
|
||||
}
|
||||
|
||||
char *strptr(string &str) { return str.s; }
|
||||
char *strptr(const string &str) { return str.s; }
|
||||
uint strlen(const string &str) { return strlen(strptr(str)); }
|
||||
|
||||
uint strlen(string &str) { return strlen(strptr(str)); }
|
||||
|
||||
int strcmp(string &dest, const char *src) { return strcmp(strptr(dest), src); }
|
||||
int strcmp(const char *dest, string &src) { return strcmp(dest, strptr(src)); }
|
||||
int strcmp(string &dest, string &src) { return strcmp(strptr(dest), strptr(src)); }
|
||||
int strcmp(const string &dest, const char *src) { return strcmp(strptr(dest), src); }
|
||||
int strcmp(const char *dest, const string &src) { return strcmp(dest, strptr(src)); }
|
||||
int strcmp(const string &dest, const string &src) { return strcmp(strptr(dest), strptr(src)); }
|
||||
|
||||
int __stricmp(const char *dest, const char *src) {
|
||||
while(*dest) {
|
||||
@@ -30,22 +29,16 @@ int __stricmp(const char *dest, const char *src) {
|
||||
}
|
||||
return (int)chrlower(*dest) - (int)chrlower(*src);
|
||||
}
|
||||
int stricmp(string &dest, const char *src) { return __stricmp(strptr(dest), src); }
|
||||
int stricmp(const char *dest, string &src) { return __stricmp(dest, strptr(src)); }
|
||||
int stricmp(string &dest, string &src) { return __stricmp(strptr(dest), strptr(src)); }
|
||||
|
||||
void strcpy(string &dest, const char src) {
|
||||
dest.reserve(2);
|
||||
dest.s[0] = src;
|
||||
dest.s[1] = 0;
|
||||
}
|
||||
int stricmp(const string &dest, const char *src) { return __stricmp(strptr(dest), src); }
|
||||
int stricmp(const char *dest, const string &src) { return __stricmp(dest, strptr(src)); }
|
||||
int stricmp(const string &dest, const string &src) { return __stricmp(strptr(dest), strptr(src)); }
|
||||
|
||||
void strcpy(string &dest, const char *src) {
|
||||
int srclen = strlen(src);
|
||||
dest.reserve(srclen);
|
||||
strcpy(dest.s, src);
|
||||
}
|
||||
void strcpy(string &dest, string &src) { strcpy(dest, strptr(src)); }
|
||||
void strcpy(string &dest, const string &src) { strcpy(dest, strptr(src)); }
|
||||
|
||||
uint strlcpy(char *dest, const char *src, uint length) {
|
||||
uint srclen = strlen(src);
|
||||
@@ -61,25 +54,18 @@ uint strlcpy(string &dest, const char *src, uint length) {
|
||||
return strlcpy(strptr(dest), src, length);
|
||||
}
|
||||
|
||||
uint strlcpy(string &dest, string &src, uint length) {
|
||||
uint strlcpy(string &dest, const string &src, uint length) {
|
||||
dest.reserve(length);
|
||||
return strlcpy(strptr(dest), strptr(src), length);
|
||||
}
|
||||
|
||||
void strcat(string &dest, const char src) {
|
||||
int length = strlen(dest);
|
||||
dest.reserve(length + 1);
|
||||
dest.s[length] = src;
|
||||
dest.s[length + 1] = 0;
|
||||
}
|
||||
|
||||
void strcat(string &dest, const char *src) {
|
||||
int srclen = strlen(src);
|
||||
int destlen = strlen(dest);
|
||||
dest.reserve(srclen + destlen);
|
||||
strcat(dest.s, src);
|
||||
}
|
||||
void strcat(string &dest, string &src) { strcat(dest, strptr(src)); }
|
||||
void strcat(string &dest, const string &src) { strcat(dest, strptr(src)); }
|
||||
|
||||
uint strlcat(char *dest, const char *src, uint length) {
|
||||
uint destlen = strlen(dest), srclen = strlen(src);
|
||||
@@ -95,7 +81,7 @@ uint strlcat(string &dest, const char *src, uint length) {
|
||||
return strlcat(strptr(dest), src, length);
|
||||
}
|
||||
|
||||
uint strlcat(string &dest, string &src, uint length) {
|
||||
uint strlcat(string &dest, const string &src, uint length) {
|
||||
dest.reserve(length);
|
||||
return strlcat(strptr(dest), strptr(src), length);
|
||||
}
|
||||
@@ -111,8 +97,7 @@ string temp;
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
string substr(string &dest, string &src, uint start, uint length) { return substr(dest, strptr(src), start, length); }
|
||||
string substr(string &dest, const string &src, uint start, uint length) { return substr(dest, strptr(src), start, length); }
|
||||
|
||||
void strinsert(string &dest, const char *src, uint pos) {
|
||||
string temp;
|
||||
@@ -121,7 +106,7 @@ string temp;
|
||||
strcat(dest, src);
|
||||
strcat(dest, temp);
|
||||
}
|
||||
void strinsert(string &dest, string &src, uint pos) { strinsert(dest, strptr(src), pos); }
|
||||
void strinsert(string &dest, const string &src, uint pos) { strinsert(dest, strptr(src), pos); }
|
||||
|
||||
void strremove(string &dest, uint start, uint length) {
|
||||
int i, destlen = strlen(dest);
|
||||
@@ -154,24 +139,23 @@ uint i = 0;
|
||||
}
|
||||
string &strupper(string &str) { strupper(strptr(str)); return str; }
|
||||
|
||||
bool strpos(const char *str, const char *key, uint &pos) {
|
||||
int strpos(const char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return false;
|
||||
if(ksl > ssl)return -1;
|
||||
for(int i = 0; i <= ssl - ksl; i++) {
|
||||
if(!memcmp(str + i, key, ksl)) {
|
||||
pos = i;
|
||||
return true;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
bool strpos(string &str, const char *key, uint &pos) { return strpos(strptr(str), key, pos); }
|
||||
bool strpos(const char *str, string &key, uint &pos) { return strpos(str, strptr(key), pos); }
|
||||
bool strpos(string &str, string &key, uint &pos) { return strpos(strptr(str), strptr(key), pos); }
|
||||
int strpos(const string &str, const char *key) { return strpos(strptr(str), key); }
|
||||
int strpos(const char *str, const string &key) { return strpos(str, strptr(key)); }
|
||||
int strpos(const string &str, const string &key) { return strpos(strptr(str), strptr(key)); }
|
||||
|
||||
bool qstrpos(const char *str, const char *key, uint &pos) {
|
||||
int qstrpos(const char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return false;
|
||||
if(ksl > ssl)return -1;
|
||||
for(int i = 0; i <= ssl - ksl;) {
|
||||
uint8 x = str[i];
|
||||
if(x == '\"' || x == '\'') {
|
||||
@@ -180,17 +164,16 @@ int ssl = strlen(str), ksl = strlen(key);
|
||||
if(i >= ssl)i = z;
|
||||
}
|
||||
if(!memcmp(str + i, key, ksl)) {
|
||||
pos = i;
|
||||
return true;
|
||||
return i;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
bool qstrpos(string &str, const char *key, uint &pos) { return qstrpos(strptr(str), key, pos); }
|
||||
bool qstrpos(const char *str, string &key, uint &pos) { return qstrpos(str, strptr(key), pos); }
|
||||
bool qstrpos(string &str, string &key, uint &pos) { return qstrpos(strptr(str), strptr(key), pos); }
|
||||
int qstrpos(const string &str, const char *key) { return qstrpos(strptr(str), key); }
|
||||
int qstrpos(const char *str, const string &key) { return qstrpos(str, strptr(key)); }
|
||||
int qstrpos(const string &str, const string &key) { return qstrpos(strptr(str), strptr(key)); }
|
||||
|
||||
void strtr(char *dest, const char *before, const char *after) {
|
||||
int sl = strlen(dest), bsl = strlen(before), asl = strlen(after);
|
||||
@@ -211,7 +194,7 @@ int i, ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return false;
|
||||
return (!memcmp(str, key, ksl));
|
||||
}
|
||||
bool strbegin(string &str, const char *key) { return strbegin(strptr(str), key); }
|
||||
bool strbegin(const string &str, const char *key) { return strbegin(strptr(str), key); }
|
||||
|
||||
bool stribegin(const char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
@@ -227,14 +210,14 @@ int ssl = strlen(str), ksl = strlen(key);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool stribegin(string &str, const char *key) { return stribegin(strptr(str), key); }
|
||||
bool stribegin(const string &str, const char *key) { return stribegin(strptr(str), key); }
|
||||
|
||||
bool strend(const char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return false;
|
||||
return (!memcmp(str + ssl - ksl, key, ksl));
|
||||
}
|
||||
bool strend(string &str, const char *key) { return strend(strptr(str), key); }
|
||||
bool strend(const string &str, const char *key) { return strend(strptr(str), key); }
|
||||
|
||||
bool striend(const char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
@@ -250,7 +233,7 @@ int ssl = strlen(str), ksl = strlen(key);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool striend(string &str, const char *key) { return striend(strptr(str), key); }
|
||||
bool striend(const string &str, const char *key) { return striend(strptr(str), key); }
|
||||
|
||||
void strltrim(char *str, const char *key) {
|
||||
int i, ssl = strlen(str), ksl = strlen(key);
|
||||
@@ -290,9 +273,21 @@ int ssl = strlen(str), ksl = strlen(key);
|
||||
}
|
||||
void strirtrim(string &str, const char *key) { strirtrim(strptr(str), key); }
|
||||
|
||||
//does not work on type char* because function increases string length
|
||||
void strtrim(char *str, const char *key) {
|
||||
strltrim(str, key);
|
||||
strrtrim(str, key);
|
||||
}
|
||||
void strtrim(string &str, const char *key) { strtrim(strptr(str), key); }
|
||||
|
||||
void stritrim(char *str, const char *key) {
|
||||
striltrim(str, key);
|
||||
strirtrim(str, key);
|
||||
}
|
||||
void stritrim(string &str, const char *key) { stritrim(strptr(str), key); }
|
||||
|
||||
//does not support char* type because function increases string length
|
||||
void strquote(string &str) {
|
||||
static string t;
|
||||
string t;
|
||||
strcpy(t, "\"");
|
||||
strcat(t, str);
|
||||
strcat(t, "\"");
|
||||
@@ -321,9 +316,11 @@ bool strunquote(string &str) { return strunquote(strptr(str)); }
|
||||
|
||||
uint strhex(const char *str) {
|
||||
uint r = 0, m = 0;
|
||||
int i, ssl = strlen(str);
|
||||
int i = 0, ssl = strlen(str);
|
||||
uint8 x;
|
||||
for(i = 0; i < ssl; i++) {
|
||||
bool negate = (str[0] == '-');
|
||||
if(negate)i++;
|
||||
for(; i < ssl; i++) {
|
||||
if(str[i] >= '0' && str[i] <= '9');
|
||||
else if(str[i] >= 'A' && str[i] <= 'F');
|
||||
else if(str[i] >= 'a' && str[i] <= 'f');
|
||||
@@ -334,87 +331,56 @@ uint8 x;
|
||||
if(x >= '0' && x <= '9')x -= '0';
|
||||
else if(x >= 'A' && x <= 'F')x -= 'A' - 0x0a;
|
||||
else if(x >= 'a' && x <= 'f')x -= 'a' - 0x0a;
|
||||
else return r;
|
||||
else break;
|
||||
r |= x << m;
|
||||
}
|
||||
return r;
|
||||
return !negate ? r : (uint)-r;
|
||||
}
|
||||
uint strhex(string &str) { return strhex(strptr(str)); }
|
||||
|
||||
int sstrhex(const char *str) {
|
||||
if(str[0] == '-') {
|
||||
return -strhex(str + 1);
|
||||
}
|
||||
return strhex(str);
|
||||
}
|
||||
int sstrhex(string &str) { return sstrhex(strptr(str)); }
|
||||
uint strhex(const string &str) { return strhex(strptr(str)); }
|
||||
|
||||
uint strdec(const char *str) {
|
||||
uint m = 1;
|
||||
int i, r = 0, ssl = strlen(str);
|
||||
int i = 0, r = 0, ssl = strlen(str);
|
||||
uint8 x;
|
||||
for(i = 0; i < ssl; i++) {
|
||||
bool negate = (str[0] == '-');
|
||||
if(negate)i++;
|
||||
for(; i < ssl; i++) {
|
||||
if(str[i] >= '0' && str[i] <= '9');
|
||||
else break;
|
||||
}
|
||||
for(--i; i >= 0; i--, m *= 10) {
|
||||
x = str[i];
|
||||
if(x >= '0' && x <= '9')x -= '0';
|
||||
else return r;
|
||||
else break;
|
||||
r += x * m;
|
||||
}
|
||||
return r;
|
||||
return !negate ? r : (uint)-r;
|
||||
}
|
||||
uint strdec(string &str) { return strdec(strptr(str)); }
|
||||
|
||||
int sstrdec(const char *str) {
|
||||
if(str[0] == '-') {
|
||||
return -strdec(str + 1);
|
||||
}
|
||||
return strdec(str);
|
||||
}
|
||||
int sstrdec(string &str) { return sstrdec(strptr(str)); }
|
||||
uint strdec(const string &str) { return strdec(strptr(str)); }
|
||||
|
||||
uint strbin(const char *str) {
|
||||
uint r = 0, m = 0;
|
||||
int i, ssl = strlen(str);
|
||||
int i = 0, ssl = strlen(str);
|
||||
uint8 x;
|
||||
for(i = 0; i < ssl; i++) {
|
||||
bool negate = (str[0] == '-');
|
||||
if(negate)i++;
|
||||
for(; i < ssl; i++) {
|
||||
if(str[i] == '0' || str[i] == '1');
|
||||
else break;
|
||||
}
|
||||
for(--i; i >= 0; i--, m++) {
|
||||
x = str[i];
|
||||
if(str[i] == '0' || str[i] == '1')x -= '0';
|
||||
else return r;
|
||||
else break;
|
||||
r |= x << m;
|
||||
}
|
||||
return r;
|
||||
return !negate ? r : (uint)-r;
|
||||
}
|
||||
uint strbin(string &str) { return strbin(strptr(str)); }
|
||||
|
||||
int sstrbin(const char *str) {
|
||||
if(str[0] == '-') {
|
||||
return -strbin(str + 1);
|
||||
}
|
||||
return strbin(str);
|
||||
}
|
||||
int sstrbin(string &str) { return sstrbin(strptr(str)); }
|
||||
uint strbin(const string &str) { return strbin(strptr(str)); }
|
||||
|
||||
char *utoa(char *str, uint num) {
|
||||
char *pstr = str;
|
||||
uint mask = 1000000000;
|
||||
while(mask > num)mask /= 10;
|
||||
while(mask > 1) {
|
||||
str[0] = '0';
|
||||
while(num >= mask) { str[0]++; num -= mask; }
|
||||
str++;
|
||||
mask /= 10;
|
||||
}
|
||||
str[0] = '0' + num;
|
||||
str++;
|
||||
str[0] = 0;
|
||||
return pstr;
|
||||
sprintf(str, "%u", num);
|
||||
return str;
|
||||
}
|
||||
|
||||
string &utoa(string &str, uint num) {
|
||||
@@ -424,14 +390,8 @@ string &utoa(string &str, uint num) {
|
||||
}
|
||||
|
||||
char *itoa(char *str, uint num) {
|
||||
char *pstr = str;
|
||||
if(num < 0) {
|
||||
str[0] = '-';
|
||||
str++;
|
||||
num = abs(int(num));
|
||||
}
|
||||
utoa(str, num);
|
||||
return pstr;
|
||||
sprintf(str, "%d", num);
|
||||
return str;
|
||||
}
|
||||
|
||||
string &itoa(string &str, uint num) {
|
||||
@@ -441,20 +401,8 @@ string &itoa(string &str, uint num) {
|
||||
}
|
||||
|
||||
char *htoa(char *str, uint num) {
|
||||
char *pstr = str;
|
||||
uint mask = 28, r;
|
||||
while(mask && ((num >> mask) & 15) == 0)mask -= 4;
|
||||
while(mask) {
|
||||
r = (num >> mask) & 15;
|
||||
str[0] = (r < 10) ? ('0' + r) : ('a' + r - 10);
|
||||
str++;
|
||||
mask -= 4;
|
||||
}
|
||||
r = num & 15;
|
||||
str[0] = (r < 10) ? ('0' + r) : ('a' + r - 10);
|
||||
str++;
|
||||
str[0] = 0;
|
||||
return pstr;
|
||||
sprintf(str, "%x", num);
|
||||
return str;
|
||||
}
|
||||
|
||||
string &htoa(string &str, uint num) {
|
||||
@@ -463,29 +411,6 @@ string &htoa(string &str, uint num) {
|
||||
return str;
|
||||
}
|
||||
|
||||
char *uhtoa(char *str, uint num) {
|
||||
char *pstr = str;
|
||||
uint mask = 28, r;
|
||||
while(mask && ((num >> mask) & 15) == 0)mask -= 4;
|
||||
while(mask) {
|
||||
r = (num >> mask) & 15;
|
||||
str[0] = (r < 10) ? ('0' + r) : ('A' + r - 10);
|
||||
str++;
|
||||
mask -= 4;
|
||||
}
|
||||
r = num & 15;
|
||||
str[0] = (r < 10) ? ('0' + r) : ('A' + r - 10);
|
||||
str++;
|
||||
str[0] = 0;
|
||||
return pstr;
|
||||
}
|
||||
|
||||
string &uhtoa(string &str, uint num) {
|
||||
str.reserve(16);
|
||||
uhtoa(strptr(str), num);
|
||||
return str;
|
||||
}
|
||||
|
||||
char *btoa(char *str, uint num) {
|
||||
char *pstr = str;
|
||||
uint mask = 0x80000000;
|
||||
@@ -502,7 +427,7 @@ uint mask = 0x80000000;
|
||||
}
|
||||
|
||||
string &btoa(string &str, uint num) {
|
||||
str.reserve(48);
|
||||
str.reserve(64);
|
||||
btoa(strptr(str), num);
|
||||
return str;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user