mirror of
https://github.com/ares-emulator/ares.git
synced 2026-11-07 17:01:59 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fd379613a | ||
|
|
aabf52d678 | ||
|
|
c9ca01fe20 | ||
|
|
becf122aaa | ||
|
|
1e130d7872 | ||
|
|
c57c733d7d | ||
|
|
e41aa25887 | ||
|
|
435f7d4371 | ||
|
|
a1980fab09 | ||
|
|
ebb234ba5f | ||
|
|
2cc7fe30b4 | ||
|
|
5c3c872b78 | ||
|
|
36bf915244 | ||
|
|
045a0f7e79 | ||
|
|
a209e6ffbe | ||
|
|
3bf672dd97 | ||
|
|
157ddf3e8f | ||
|
|
ea23bf53ae | ||
|
|
d4598e1d01 | ||
|
|
f9a8564af0 | ||
|
|
6d66b1136d | ||
|
|
b01f18c34c |
No files matched your search
+57
-29
@@ -1,35 +1,63 @@
|
||||
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, author: NSRT Team, license: GPL (*)
|
||||
libco, author: byuu, license: public domain
|
||||
libui, author: byuu, license: public domain
|
||||
NTSC Filter, author: blargg, license: LGPL
|
||||
S-DD1, author: Andreas Naive, license: public domain
|
||||
zlib, license: zlib license
|
||||
|
||||
(*) bsnes has received an exemption from the copyright holder to use this work.
|
||||
+32
-33
@@ -1,10 +1,10 @@
|
||||
bsnes
|
||||
Version 0.019
|
||||
Version 0.024
|
||||
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
|
||||
|
||||
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
|
||||
@@ -74,25 +72,26 @@ Coprocessor used only by SD Gundam GX
|
||||
DSP-4
|
||||
Coprocessor used only by Top Gear 3000
|
||||
|
||||
ST010 / ST011 / ST018
|
||||
SETA coprocessors used by very few games
|
||||
ST011
|
||||
SETA DSP used only by Quick-move Shogi Match with Nidan Rank-holder Morita
|
||||
|
||||
ST018
|
||||
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)
|
||||
+312
@@ -0,0 +1,312 @@
|
||||
######################
|
||||
### 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 = -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
|
||||
|
||||
#####################################
|
||||
### 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) srtc.$(OBJ) sdd1.$(OBJ) c4.$(OBJ) dsp1.$(OBJ) \
|
||||
dsp2.$(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 ###
|
||||
#####################
|
||||
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/*
|
||||
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
|
||||
+9
-22
@@ -1,4 +1,4 @@
|
||||
#define BSNES_VERSION "0.019"
|
||||
#define BSNES_VERSION "0.024"
|
||||
#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 {
|
||||
|
||||
Binary file not shown.
+13
-12
@@ -1,26 +1,27 @@
|
||||
#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) {
|
||||
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.srtc = false;
|
||||
info.sdd1 = false;
|
||||
info.c4 = false;
|
||||
info.dsp1 = false;
|
||||
info.dsp2 = false;
|
||||
info.obc1 = false;
|
||||
info.st010 = false;
|
||||
|
||||
info.dsp1_mapper = 0;
|
||||
|
||||
@@ -128,8 +129,8 @@ bool Cartridge::unload() {
|
||||
} 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);
|
||||
|
||||
@@ -87,6 +87,7 @@ struct {
|
||||
bool dsp1;
|
||||
bool dsp2;
|
||||
bool obc1;
|
||||
bool st010;
|
||||
|
||||
uint dsp1_mapper;
|
||||
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
#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);
|
||||
|
||||
|
||||
@@ -69,6 +69,10 @@ uint8 rom_type = rom[info.header_index + ROM_TYPE];
|
||||
info.obc1 = true;
|
||||
}
|
||||
|
||||
if(mapper == 0x30 && rom_type == 0xf6) {
|
||||
info.st010 = true;
|
||||
}
|
||||
|
||||
info.cart_mmio = info.c4 | info.dsp1 | info.dsp2 | info.obc1;
|
||||
|
||||
if(rom[info.header_index + RAM_SIZE] & 7) {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
::@make -r PLATFORM=win-visualc-lui
|
||||
@make -r PLATFORM=win-visualc-lui GZIP_SUPPORT=true JMA_SUPPORT=true
|
||||
@move bsnes.exe ../bsnes.exe>nul
|
||||
@pause
|
||||
+2
-1
@@ -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);
|
||||
|
||||
@@ -43,10 +43,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 +60,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ understood.
|
||||
|
||||
************************************************************************/
|
||||
|
||||
typedef uint8_t bool8;
|
||||
|
||||
class SDD1_IM { //Input Manager
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
#include "../../base.h"
|
||||
#include "st010_data.h"
|
||||
#include "st010_op.cpp"
|
||||
|
||||
ST010 *st010;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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 }
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
@make PLATFORM=win-visualc-lui clean
|
||||
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
make PLATFORM=x-gcc-lui clean
|
||||
+75
-57
@@ -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);
|
||||
|
||||
};
|
||||
+23
-21
@@ -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;
|
||||
|
||||
};
|
||||
+1
-1
@@ -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);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
+24
-26
@@ -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"
|
||||
@@ -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) {
|
||||
|
||||
+100
-147
@@ -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;
|
||||
}
|
||||
|
||||
+51
-72
@@ -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;
|
||||
}
|
||||
|
||||
+378
-504
File diff suppressed because it is too large.
Load diff
+76
-114
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -48,5 +48,9 @@ void sCPU::reset() {
|
||||
apu_port[3] = 0x00;
|
||||
}
|
||||
|
||||
sCPU::sCPU() {}
|
||||
sCPU::~sCPU() {}
|
||||
sCPU::sCPU() {
|
||||
#include "core/optable.cpp"
|
||||
}
|
||||
|
||||
sCPU::~sCPU() {
|
||||
}
|
||||
@@ -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
|
||||
@@ -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() {}
|
||||
@@ -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,
|
||||
+650
-534
File diff suppressed because it is too large.
Load diff
+160
-164
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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() {}
|
||||
@@ -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();
|
||||
};
|
||||
@@ -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 <[email protected]>
|
||||
@@ -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];
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
+3
-3
@@ -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"
|
||||
@@ -38,6 +39,7 @@
|
||||
#include "chip/dsp1/dsp1.h"
|
||||
#include "chip/dsp2/dsp2.h"
|
||||
#include "chip/obc1/obc1.h"
|
||||
#include "chip/st010/st010.h"
|
||||
|
||||
extern MMIO mmio_unmapped;
|
||||
#ifdef POLYMORPHISM
|
||||
|
||||
+17
-10
@@ -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";
|
||||
|
||||
+111
-217
@@ -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);
|
||||
+53
-102
@@ -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
|
||||
+18
-12
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
+166
-66
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
+288
-161
@@ -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
|
||||
+3
-3
@@ -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
|
||||
+75
-150
@@ -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;
|
||||
}
|
||||
|
||||
+116
-122
@@ -1,159 +1,156 @@
|
||||
/*
|
||||
libstring : version 0.14b ~byuu (2006/11/17)
|
||||
libstring : version 0.18 ~byuu (2007-06-06)
|
||||
*/
|
||||
|
||||
#ifndef __LIBSTRING
|
||||
#define __LIBSTRING
|
||||
#ifndef LIBSTRING_H
|
||||
#define LIBSTRING_H
|
||||
|
||||
#include "libbase.h"
|
||||
#include "libvector.h"
|
||||
|
||||
class string;
|
||||
typedef linear_vector<string> stringarray;
|
||||
|
||||
char chrlower(char c);
|
||||
char chrupper(char c);
|
||||
char chrlower(char c);
|
||||
char chrupper(char c);
|
||||
|
||||
uint count(stringarray &str);
|
||||
uint count(stringarray &str);
|
||||
|
||||
char *strptr(string &str);
|
||||
uint strlen(string &str);
|
||||
int find(stringarray &str, const char *key);
|
||||
int find(stringarray &str, const string &key);
|
||||
|
||||
int strcmp(string &dest, const char *src);
|
||||
int strcmp(const char *dest, string &src);
|
||||
int strcmp(string &dest, string &src);
|
||||
char *strptr(const string &str);
|
||||
uint strlen(const string &str);
|
||||
|
||||
int strcmp(const string &dest, const char *src);
|
||||
int strcmp(const char *dest, const string &src);
|
||||
int strcmp(const string &dest, const string &src);
|
||||
|
||||
//vc6/win32 and gcc/dos only support stricmp, whereas
|
||||
//gcc/unix only supports strcasecmp. this is an attempt
|
||||
//to avoid platform-specific defines...
|
||||
#define stricmp __stricmp
|
||||
int __stricmp(const char *dest, const char *src);
|
||||
int stricmp(string &dest, const char *src);
|
||||
int stricmp(const char *dest, string &src);
|
||||
int stricmp(string &dest, string &src);
|
||||
int __stricmp(const char *dest, const char *src);
|
||||
int stricmp(const string &dest, const char *src);
|
||||
int stricmp(const char *dest, const string &src);
|
||||
int stricmp(const string &dest, const string &src);
|
||||
|
||||
void strcpy(string &dest, const char *src);
|
||||
void strcpy(string &dest, string &src);
|
||||
uint strlcpy(char *dest, const char *src, uint length);
|
||||
uint strlcpy(string &dest, const char *src, uint length);
|
||||
uint strlcpy(string &dest, string &src, uint length);
|
||||
void strcpy(string &dest, const char *src);
|
||||
void strcpy(string &dest, const string &src);
|
||||
uint strlcpy(char *dest, const char *src, uint length);
|
||||
uint strlcpy(string &dest, const char *src, uint length);
|
||||
uint strlcpy(string &dest, const string &src, uint length);
|
||||
|
||||
void strcat(string &dest, const char src);
|
||||
void strcat(string &dest, const char *src);
|
||||
void strcat(string &dest, string &src);
|
||||
uint strlcat(char *dest, const char *src, uint length);
|
||||
uint strlcat(string &dest, const char *src, uint length);
|
||||
uint strlcat(string &dest, string &src, uint length);
|
||||
void strcat(string &dest, const char *src);
|
||||
void strcat(string &dest, const string &src);
|
||||
uint strlcat(char *dest, const char *src, uint length);
|
||||
uint strlcat(string &dest, const char *src, uint length);
|
||||
uint strlcat(string &dest, const string &src, uint length);
|
||||
|
||||
string substr(string &dest, const char *src, uint start = 0, uint length = 0);
|
||||
string substr(string &dest, string &src, uint start = 0, uint length = 0);
|
||||
string substr(string &dest, const string &src, uint start = 0, uint length = 0);
|
||||
|
||||
void strinsert(string &dest, const char *src, uint pos);
|
||||
void strinsert(string &dest, string &src, uint pos);
|
||||
void strinsert(string &dest, const char *src, uint pos);
|
||||
void strinsert(string &dest, const string &src, uint pos);
|
||||
|
||||
void strremove(string &dest, uint start, uint length = 0);
|
||||
void strremove(string &dest, uint start, uint length = 0);
|
||||
|
||||
char *strlower(char *str);
|
||||
char *strlower(char *str);
|
||||
string &strlower(string &str);
|
||||
|
||||
char *strupper(char *str);
|
||||
char *strupper(char *str);
|
||||
string &strupper(string &str);
|
||||
|
||||
bool strpos(const char *str, const char *key, uint &pos);
|
||||
bool strpos(string &str, const char *key, uint &pos);
|
||||
bool strpos(const char *str, string &key, uint &pos);
|
||||
bool strpos(string &str, string &key, uint &pos);
|
||||
int strpos(const char *str, const char *key);
|
||||
int strpos(const string &str, const char *key);
|
||||
int strpos(const char *str, const string &key);
|
||||
int strpos(const string &str, const string &key);
|
||||
|
||||
bool qstrpos(const char *str, const char *key, uint &pos);
|
||||
bool qstrpos(string &str, const char *key, uint &pos);
|
||||
bool qstrpos(const char *str, string &key, uint &pos);
|
||||
bool qstrpos(string &str, string &key, uint &pos);
|
||||
int qstrpos(const char *str, const char *key);
|
||||
int qstrpos(const string &str, const char *key);
|
||||
int qstrpos(const char *str, const string &key);
|
||||
int qstrpos(const string &str, const string &key);
|
||||
|
||||
void strtr(char *dest, const char *before, const char *after);
|
||||
void strtr(string &dest, const char *before, const char *after);
|
||||
void strtr(char *dest, const char *before, const char *after);
|
||||
void strtr(string &dest, const char *before, const char *after);
|
||||
|
||||
bool strbegin(const char *str, const char *key);
|
||||
bool strbegin(string &str, const char *key);
|
||||
bool strbegin(const char *str, const char *key);
|
||||
bool strbegin(const string &str, const char *key);
|
||||
|
||||
bool stribegin(const char *str, const char *key);
|
||||
bool stribegin(string &str, const char *key);
|
||||
bool stribegin(const char *str, const char *key);
|
||||
bool stribegin(const string &str, const char *key);
|
||||
|
||||
bool strend(const char *str, const char *key);
|
||||
bool strend(string &str, const char *key);
|
||||
bool strend(const char *str, const char *key);
|
||||
bool strend(const string &str, const char *key);
|
||||
|
||||
bool striend(const char *str, const char *key);
|
||||
bool striend(string &str, const char *key);
|
||||
bool striend(const char *str, const char *key);
|
||||
bool striend(const string &str, const char *key);
|
||||
|
||||
void strltrim(char *str, const char *key);
|
||||
void strltrim(string &str, const char *key);
|
||||
void strltrim(char *str, const char *key);
|
||||
void strltrim(string &str, const char *key);
|
||||
|
||||
void striltrim(char *str, const char *key);
|
||||
void striltrim(string &str, const char *key);
|
||||
void striltrim(char *str, const char *key);
|
||||
void striltrim(string &str, const char *key);
|
||||
|
||||
void strrtrim(char *str, const char *key);
|
||||
void strrtrim(string &str, const char *key);
|
||||
void strrtrim(char *str, const char *key);
|
||||
void strrtrim(string &str, const char *key);
|
||||
|
||||
void strirtrim(char *str, const char *key);
|
||||
void strirtrim(string &str, const char *key);
|
||||
void strirtrim(char *str, const char *key);
|
||||
void strirtrim(string &str, const char *key);
|
||||
|
||||
void strquote(string &str);
|
||||
void strtrim(char *str, const char *key);
|
||||
void strtrim(string &str, const char *key);
|
||||
|
||||
bool strunquote(char *str);
|
||||
bool strunquote(string &str);
|
||||
void stritrim(char *str, const char *key);
|
||||
void stritrim(string &str, const char *key);
|
||||
|
||||
uint strhex(const char *str);
|
||||
uint strhex(string &str);
|
||||
void strquote(string &str);
|
||||
|
||||
int sstrhex(const char *str);
|
||||
int sstrhex(string &str);
|
||||
bool strunquote(char *str);
|
||||
bool strunquote(string &str);
|
||||
|
||||
uint strdec(const char *str);
|
||||
uint strdec(string &str);
|
||||
uint strhex(const char *str);
|
||||
uint strhex(const string &str);
|
||||
|
||||
int sstrdec(const char *str);
|
||||
int sstrdec(string &str);
|
||||
uint strdec(const char *str);
|
||||
uint strdec(const string &str);
|
||||
|
||||
uint strbin(const char *str);
|
||||
uint strbin(string &str);
|
||||
uint strbin(const char *str);
|
||||
uint strbin(const string &str);
|
||||
|
||||
int sstrbin(const char *str);
|
||||
int sstrbin(string &str);
|
||||
|
||||
char *utoa(char *str, uint num);
|
||||
char *utoa(char *str, uint num);
|
||||
string &utoa(string &str, uint num);
|
||||
|
||||
char *itoa(char *str, uint num);
|
||||
char *itoa(char *str, uint num);
|
||||
string &itoa(string &str, uint num);
|
||||
|
||||
char *htoa(char *str, uint num);
|
||||
char *htoa(char *str, uint num);
|
||||
string &htoa(string &str, uint num);
|
||||
|
||||
char *uhtoa(char *str, uint num);
|
||||
string &uhtoa(string &str, uint num);
|
||||
|
||||
char *btoa(char *str, uint num);
|
||||
char *btoa(char *str, uint num);
|
||||
string &btoa(string &str, uint num);
|
||||
|
||||
bool strfread(string &str, const char *filename);
|
||||
bool strfread(string &str, const char *filename);
|
||||
|
||||
string strfmt(const char *fmt, int num);
|
||||
|
||||
int strmath(const char *in_str);
|
||||
int strmath(string &in_str);
|
||||
int strmath(const char *str);
|
||||
int strmath(const string &str);
|
||||
|
||||
string &replace(string &str, const char *key, const char *token);
|
||||
string &replace(string &str, const char *key, string &token);
|
||||
string &replace(string &str, const char *key, const char *token);
|
||||
string &replace(string &str, const char *key, const string &token);
|
||||
|
||||
string &qreplace(string &str, const char *key, const char *token);
|
||||
string &qreplace(string &str, const char *key, string &token);
|
||||
string &qreplace(string &str, const char *key, const char *token);
|
||||
string &qreplace(string &str, const char *key, const string &token);
|
||||
|
||||
void split(stringarray &dest, const char *key, const char *src);
|
||||
void split(stringarray &dest, const char *key, string &src);
|
||||
void split(stringarray &dest, const char *key, const char *src);
|
||||
void split(stringarray &dest, const char *key, const string &src);
|
||||
|
||||
void qsplit(stringarray &dest, const char *key, const char *src);
|
||||
void qsplit(stringarray &dest, const char *key, string &src);
|
||||
void qsplit(stringarray &dest, const char *key, const char *src);
|
||||
void qsplit(stringarray &dest, const char *key, const string &src);
|
||||
|
||||
uint vsprintf(string &str, const char *s, va_list args);
|
||||
uint sprintf(string &str, const char *s, ...);
|
||||
uint vsprintf(string &str, const char *s, va_list args);
|
||||
uint sprintf(string &str, const char *s, ...);
|
||||
|
||||
class string {
|
||||
public:
|
||||
@@ -184,7 +181,7 @@ uint size;
|
||||
strcpy(s, str);
|
||||
}
|
||||
|
||||
string(string &str) {
|
||||
string(const string &str) {
|
||||
size = strlen(str);
|
||||
s = (char*)malloc(size + 1);
|
||||
strcpy(s, strptr(str));
|
||||
@@ -192,35 +189,32 @@ uint size;
|
||||
|
||||
~string() { safe_free(s); }
|
||||
|
||||
const char *operator()();
|
||||
char &operator[](uint);
|
||||
string &operator=(int);
|
||||
string &operator=(const char *);
|
||||
string &operator=(string &);
|
||||
string &operator+=(int);
|
||||
string &operator+=(const char *);
|
||||
string &operator+=(string &);
|
||||
bool operator==(const char *);
|
||||
bool operator==(string &);
|
||||
bool operator!=(const char *);
|
||||
bool operator!=(string &);
|
||||
bool operator<(const char *);
|
||||
bool operator<(string &);
|
||||
bool operator<=(const char *);
|
||||
bool operator<=(string &);
|
||||
bool operator>(const char *);
|
||||
bool operator>(string &);
|
||||
bool operator>=(const char *);
|
||||
bool operator>=(string &);
|
||||
operator const char*() const { return s; }
|
||||
const char* operator()() const { return s; }
|
||||
char& operator[](const uint);
|
||||
|
||||
string operator+(int);
|
||||
string operator+(const char *);
|
||||
string operator+(string &);
|
||||
string& operator=(const int);
|
||||
string& operator=(const char*);
|
||||
string& operator=(const string&);
|
||||
|
||||
string& operator<<(const int);
|
||||
string& operator<<(const char*);
|
||||
string& operator<<(const string&);
|
||||
|
||||
bool operator==(const char*);
|
||||
bool operator==(const string&);
|
||||
bool operator!=(const char*);
|
||||
bool operator!=(const string&);
|
||||
bool operator< (const char*);
|
||||
bool operator< (const string&);
|
||||
bool operator<=(const char*);
|
||||
bool operator<=(const string&);
|
||||
bool operator> (const char*);
|
||||
bool operator> (const string&);
|
||||
bool operator>=(const char*);
|
||||
bool operator>=(const string&);
|
||||
};
|
||||
|
||||
string operator+(int, string &);
|
||||
string operator+(const char *, string &);
|
||||
|
||||
inline void swap(string &x, string &y) { x.swap(y); }
|
||||
|
||||
#endif //__LIBSTRING
|
||||
#endif //LIBSTRING_H
|
||||
@@ -0,0 +1,11 @@
|
||||
uint count(stringarray &str) {
|
||||
return str.size();
|
||||
}
|
||||
|
||||
int find(stringarray &str, const char *key) {
|
||||
for(uint i = 0; i < count(str); i++) {
|
||||
if(str[i] == key) { return i; }
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
int find(stringarray &str, const string &key) { return find(str, strptr(key)); }
|
||||
@@ -110,12 +110,12 @@ int lhs = strmath_rdp(s, level + 1);
|
||||
}
|
||||
#undef maxlevel
|
||||
|
||||
int strmath(const char *s) {
|
||||
return strmath_rdp(s);
|
||||
int strmath(const char *str) {
|
||||
return strmath_rdp(str);
|
||||
}
|
||||
|
||||
#ifdef __LIBSTRING
|
||||
int strmath(string &s) {
|
||||
return strmath(strptr(s));
|
||||
int strmath(const string &str) {
|
||||
return strmath(strptr(str));
|
||||
}
|
||||
#endif
|
||||
+17
-53
@@ -1,13 +1,9 @@
|
||||
const char *string::operator()() {
|
||||
return s;
|
||||
}
|
||||
|
||||
char &string::operator[](const uint index) {
|
||||
reserve(index);
|
||||
return s[index];
|
||||
}
|
||||
|
||||
string &string::operator=(int num) {
|
||||
string &string::operator=(const int num) {
|
||||
strcpy(*this, strfmt("%d", num));
|
||||
return *this;
|
||||
}
|
||||
@@ -17,67 +13,35 @@ string &string::operator=(const char *str) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
string &string::operator=(string &str) {
|
||||
string &string::operator=(const string &str) {
|
||||
strcpy(*this, str);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string &string::operator+=(int num) {
|
||||
string& string::operator<<(const int num) {
|
||||
strcat(*this, strfmt("%d", num));
|
||||
return *this;
|
||||
}
|
||||
|
||||
string &string::operator+=(const char *str) {
|
||||
string& string::operator<<(const char* str) {
|
||||
strcat(*this, str);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string &string::operator+=(string &str) {
|
||||
string& string::operator<<(const string& str) {
|
||||
strcat(*this, str);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool string::operator==(const char *str) { return strcmp(strptr(*this), str) == 0; }
|
||||
bool string::operator==(string &str) { return strcmp(strptr(*this), strptr(str)) == 0; }
|
||||
bool string::operator!=(const char *str) { return strcmp(strptr(*this), str) != 0; }
|
||||
bool string::operator!=(string &str) { return strcmp(strptr(*this), strptr(str)) != 0; }
|
||||
bool string::operator<(const char *str) { return strcmp(strptr(*this), str) < 0; }
|
||||
bool string::operator<(string &str) { return strcmp(strptr(*this), strptr(str)) < 0; }
|
||||
bool string::operator<=(const char *str) { return strcmp(strptr(*this), str) <= 0; }
|
||||
bool string::operator<=(string &str) { return strcmp(strptr(*this), strptr(str)) <= 0; }
|
||||
bool string::operator>(const char *str) { return strcmp(strptr(*this), str) > 0; }
|
||||
bool string::operator>(string &str) { return strcmp(strptr(*this), strptr(str)) > 0; }
|
||||
bool string::operator>=(const char *str) { return strcmp(strptr(*this), str) >= 0; }
|
||||
bool string::operator>=(string &str) { return strcmp(strptr(*this), strptr(str)) >= 0; }
|
||||
|
||||
string string::operator+(int num) {
|
||||
string temp(*this);
|
||||
strcat(temp, strfmt("%d", num));
|
||||
return temp;
|
||||
}
|
||||
|
||||
string string::operator+(const char *str) {
|
||||
string temp(*this);
|
||||
strcat(temp, str);
|
||||
return temp;
|
||||
}
|
||||
|
||||
string string::operator+(string &str) {
|
||||
string temp(*this);
|
||||
strcat(temp, str);
|
||||
return temp;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
string operator+(int x, string &y) {
|
||||
string temp(strfmt("%d", x));
|
||||
strcat(temp, y);
|
||||
return temp;
|
||||
}
|
||||
|
||||
string operator+(const char *x, string &y) {
|
||||
string temp(x);
|
||||
strcat(temp, y);
|
||||
return temp;
|
||||
}
|
||||
bool string::operator==(const char *str) { return strcmp(strptr(*this), str) == 0; }
|
||||
bool string::operator==(const string &str) { return strcmp(strptr(*this), strptr(str)) == 0; }
|
||||
bool string::operator!=(const char *str) { return strcmp(strptr(*this), str) != 0; }
|
||||
bool string::operator!=(const string &str) { return strcmp(strptr(*this), strptr(str)) != 0; }
|
||||
bool string::operator< (const char *str) { return strcmp(strptr(*this), str) < 0; }
|
||||
bool string::operator< (const string &str) { return strcmp(strptr(*this), strptr(str)) < 0; }
|
||||
bool string::operator<=(const char *str) { return strcmp(strptr(*this), str) <= 0; }
|
||||
bool string::operator<=(const string &str) { return strcmp(strptr(*this), strptr(str)) <= 0; }
|
||||
bool string::operator> (const char *str) { return strcmp(strptr(*this), str) > 0; }
|
||||
bool string::operator> (const string &str) { return strcmp(strptr(*this), strptr(str)) > 0; }
|
||||
bool string::operator>=(const char *str) { return strcmp(strptr(*this), str) >= 0; }
|
||||
bool string::operator>=(const string &str) { return strcmp(strptr(*this), strptr(str)) >= 0; }
|
||||
@@ -28,7 +28,7 @@ char *data;
|
||||
free(data);
|
||||
return str;
|
||||
}
|
||||
string &replace(string &str, const char *key, string &token) { return replace(str, key, strptr(token)); }
|
||||
string &replace(string &str, const char *key, const string &token) { return replace(str, key, strptr(token)); }
|
||||
|
||||
string &qreplace(string &str, const char *key, const char *token) {
|
||||
int i, l, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str);
|
||||
@@ -83,4 +83,4 @@ char *data;
|
||||
free(data);
|
||||
return str;
|
||||
}
|
||||
string &qreplace(string &str, const char *key, string &token) { return qreplace(str, key, strptr(token)); }
|
||||
string &qreplace(string &str, const char *key, const string &token) { return qreplace(str, key, strptr(token)); }
|
||||
@@ -12,7 +12,7 @@ int lp = 0, split_count = 0;
|
||||
}
|
||||
strcpy(dest[split_count++], src + lp);
|
||||
}
|
||||
void split(stringarray &dest, const char *key, string &src) { split(dest, key, strptr(src)); }
|
||||
void split(stringarray &dest, const char *key, const string &src) { split(dest, key, strptr(src)); }
|
||||
|
||||
void qsplit(stringarray &dest, const char *key, const char *src) {
|
||||
dest.reset();
|
||||
@@ -34,4 +34,4 @@ int lp = 0, split_count = 0;
|
||||
}
|
||||
strcpy(dest[split_count++], src + lp);
|
||||
}
|
||||
void qsplit(stringarray &dest, const char *key, string &src) { qsplit(dest, key, strptr(src)); }
|
||||
void qsplit(stringarray &dest, const char *key, const string &src) { qsplit(dest, key, strptr(src)); }
|
||||
@@ -1,3 +1,18 @@
|
||||
uint vsprintf(string &str, const char *s, va_list args) {
|
||||
va_list temp;
|
||||
va_copy(temp, args);
|
||||
uint length = vsnprintf(0, 0, s, temp);
|
||||
va_end(temp);
|
||||
|
||||
str.reserve(length);
|
||||
|
||||
va_copy(temp, args);
|
||||
length = vsprintf(strptr(str), s, temp);
|
||||
va_end(temp);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
uint sprintf(string &str, const char *s, ...) {
|
||||
va_list args;
|
||||
va_start(args, s);
|
||||
@@ -6,12 +21,6 @@ uint length = vsprintf(str, s, args);
|
||||
return length;
|
||||
}
|
||||
|
||||
uint vsprintf(string &str, const char *s, va_list args) {
|
||||
uint length = vsnprintf(0, 0, s, args);
|
||||
str.reserve(length + 1);
|
||||
return vsprintf(strptr(str), s, args);
|
||||
}
|
||||
|
||||
/*
|
||||
uint vsprintf(string &str, const char *s, va_list args) {
|
||||
bool leftalign;
|
||||
|
||||
@@ -0,0 +1,283 @@
|
||||
#include <gdk/gdkx.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include "libui_gtk.h"
|
||||
#include "libui_gtk_window.cpp"
|
||||
#include "libui_gtk_control.cpp"
|
||||
|
||||
namespace libui {
|
||||
|
||||
void init() {
|
||||
int argc = 1;
|
||||
char **argv;
|
||||
argv = (char**)malloc(1 * sizeof(char*));
|
||||
argv[0] = (char*)malloc(64 * sizeof(char));
|
||||
strcpy(argv[0], "./libui");
|
||||
//GTK+ insists you provide main()'s argc, argv parameters for
|
||||
//some special command-line processing options that are likely
|
||||
//never used by anything.
|
||||
//However, I insist on libui_init() not requiring arguments so
|
||||
//that it can be called from anywhere, including a global
|
||||
//constructor that is invoked before main() is reached.
|
||||
gtk_init(&argc, &argv);
|
||||
safe_free(argv[0]);
|
||||
safe_free(argv);
|
||||
}
|
||||
|
||||
void term() {
|
||||
}
|
||||
|
||||
bool run() {
|
||||
gtk_main_iteration_do(false);
|
||||
return events_pending();
|
||||
}
|
||||
|
||||
bool events_pending() {
|
||||
return gtk_events_pending();
|
||||
}
|
||||
|
||||
uint get_screen_width() { return gdk_screen_width(); }
|
||||
uint get_screen_height() { return gdk_screen_height(); }
|
||||
|
||||
//
|
||||
|
||||
bool file_load(Window *owner, char *filename, const char *filter, const char *path) {
|
||||
strcpy(filename, "");
|
||||
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new("Load File",
|
||||
owner ? GTK_WINDOW(owner->info.window) : (GtkWindow*)0,
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, (const gchar*)0);
|
||||
|
||||
if(path && strcmp(path, "")) {
|
||||
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
|
||||
}
|
||||
|
||||
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
char *fn = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
strcpy(filename, fn);
|
||||
g_free(fn);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
return strcmp(filename, ""); //return true if filename != ""
|
||||
}
|
||||
|
||||
bool file_save(Window *owner, char *filename, const char *filter, const char *path) {
|
||||
strcpy(filename, "");
|
||||
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new("Save File",
|
||||
owner ? GTK_WINDOW(owner->info.window) : (GtkWindow*)0,
|
||||
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, (const gchar*)0);
|
||||
|
||||
if(path && strcmp(path, "")) {
|
||||
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
|
||||
}
|
||||
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
|
||||
|
||||
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
char *fn = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
strcpy(filename, fn);
|
||||
g_free(fn);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
return strcmp(filename, ""); //return true if filename != ""
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
uint16 translate_key(uint key) {
|
||||
switch(key) {
|
||||
|
||||
case GDK_Escape: return keymap::esc;
|
||||
|
||||
case GDK_F1: return keymap::f1;
|
||||
case GDK_F2: return keymap::f2;
|
||||
case GDK_F3: return keymap::f3;
|
||||
case GDK_F4: return keymap::f4;
|
||||
case GDK_F5: return keymap::f5;
|
||||
case GDK_F6: return keymap::f6;
|
||||
case GDK_F7: return keymap::f7;
|
||||
case GDK_F8: return keymap::f8;
|
||||
case GDK_F9: return keymap::f9;
|
||||
case GDK_F10: return keymap::f10;
|
||||
case GDK_F11: return keymap::f11;
|
||||
case GDK_F12: return keymap::f12;
|
||||
|
||||
case GDK_Print: return keymap::print_screen;
|
||||
case GDK_Sys_Req: return keymap::sys_req;
|
||||
case GDK_Scroll_Lock: return keymap::scroll_lock;
|
||||
case GDK_Pause: return keymap::pause;
|
||||
case GDK_Break: return keymap::brk;
|
||||
|
||||
case GDK_grave: return keymap::grave;
|
||||
case GDK_asciitilde: return keymap::tilde;
|
||||
|
||||
case GDK_1: return keymap::num_1;
|
||||
case GDK_2: return keymap::num_2;
|
||||
case GDK_3: return keymap::num_3;
|
||||
case GDK_4: return keymap::num_4;
|
||||
case GDK_5: return keymap::num_5;
|
||||
case GDK_6: return keymap::num_6;
|
||||
case GDK_7: return keymap::num_7;
|
||||
case GDK_8: return keymap::num_8;
|
||||
case GDK_9: return keymap::num_9;
|
||||
case GDK_0: return keymap::num_0;
|
||||
|
||||
case GDK_exclam: return keymap::exclamation;
|
||||
case GDK_at: return keymap::at;
|
||||
case GDK_numbersign: return keymap::pound;
|
||||
case GDK_dollar: return keymap::dollar;
|
||||
case GDK_percent: return keymap::percent;
|
||||
case GDK_asciicircum: return keymap::power;
|
||||
case GDK_ampersand: return keymap::ampersand;
|
||||
case GDK_asterisk: return keymap::asterisk;
|
||||
case GDK_parenleft: return keymap::lparenthesis;
|
||||
case GDK_parenright: return keymap::rparenthesis;
|
||||
|
||||
case GDK_minus: return keymap::minus;
|
||||
case GDK_underscore: return keymap::underscore;
|
||||
case GDK_equal: return keymap::equal;
|
||||
case GDK_plus: return keymap::plus;
|
||||
case GDK_BackSpace: return keymap::backspace;
|
||||
|
||||
case GDK_Insert: return keymap::ins;
|
||||
case GDK_Delete: return keymap::del;
|
||||
case GDK_Home: return keymap::home;
|
||||
case GDK_End: return keymap::end;
|
||||
case GDK_Page_Up: return keymap::page_up;
|
||||
case GDK_Page_Down: return keymap::page_down;
|
||||
|
||||
case GDK_a: return keymap::a;
|
||||
case GDK_b: return keymap::b;
|
||||
case GDK_c: return keymap::c;
|
||||
case GDK_d: return keymap::d;
|
||||
case GDK_e: return keymap::e;
|
||||
case GDK_f: return keymap::f;
|
||||
case GDK_g: return keymap::g;
|
||||
case GDK_h: return keymap::h;
|
||||
case GDK_i: return keymap::i;
|
||||
case GDK_j: return keymap::j;
|
||||
case GDK_k: return keymap::k;
|
||||
case GDK_l: return keymap::l;
|
||||
case GDK_m: return keymap::m;
|
||||
case GDK_n: return keymap::n;
|
||||
case GDK_o: return keymap::o;
|
||||
case GDK_p: return keymap::p;
|
||||
case GDK_q: return keymap::q;
|
||||
case GDK_r: return keymap::r;
|
||||
case GDK_s: return keymap::s;
|
||||
case GDK_t: return keymap::t;
|
||||
case GDK_u: return keymap::u;
|
||||
case GDK_v: return keymap::v;
|
||||
case GDK_w: return keymap::w;
|
||||
case GDK_x: return keymap::x;
|
||||
case GDK_y: return keymap::y;
|
||||
case GDK_z: return keymap::z;
|
||||
|
||||
case GDK_A: return keymap::A;
|
||||
case GDK_B: return keymap::B;
|
||||
case GDK_C: return keymap::C;
|
||||
case GDK_D: return keymap::D;
|
||||
case GDK_E: return keymap::E;
|
||||
case GDK_F: return keymap::F;
|
||||
case GDK_G: return keymap::G;
|
||||
case GDK_H: return keymap::H;
|
||||
case GDK_I: return keymap::I;
|
||||
case GDK_J: return keymap::J;
|
||||
case GDK_K: return keymap::K;
|
||||
case GDK_L: return keymap::L;
|
||||
case GDK_M: return keymap::M;
|
||||
case GDK_N: return keymap::N;
|
||||
case GDK_O: return keymap::O;
|
||||
case GDK_P: return keymap::P;
|
||||
case GDK_Q: return keymap::Q;
|
||||
case GDK_R: return keymap::R;
|
||||
case GDK_S: return keymap::S;
|
||||
case GDK_T: return keymap::T;
|
||||
case GDK_U: return keymap::U;
|
||||
case GDK_V: return keymap::V;
|
||||
case GDK_W: return keymap::W;
|
||||
case GDK_X: return keymap::X;
|
||||
case GDK_Y: return keymap::Y;
|
||||
case GDK_Z: return keymap::Z;
|
||||
|
||||
case GDK_bracketleft: return keymap::lbracket;
|
||||
case GDK_bracketright: return keymap::rbracket;
|
||||
case GDK_backslash: return keymap::backslash;
|
||||
case GDK_semicolon: return keymap::semicolon;
|
||||
case GDK_apostrophe: return keymap::apostrophe;
|
||||
case GDK_comma: return keymap::comma;
|
||||
case GDK_period: return keymap::period;
|
||||
case GDK_slash: return keymap::slash;
|
||||
|
||||
case GDK_braceleft: return keymap::lbrace;
|
||||
case GDK_braceright: return keymap::rbrace;
|
||||
case GDK_bar: return keymap::pipe;
|
||||
case GDK_colon: return keymap::colon;
|
||||
case GDK_quotedbl: return keymap::quote;
|
||||
case GDK_less: return keymap::lcaret;
|
||||
case GDK_greater: return keymap::rcaret;
|
||||
case GDK_question: return keymap::question;
|
||||
|
||||
case GDK_KP_1: return keymap::kp_1;
|
||||
case GDK_KP_2: return keymap::kp_2;
|
||||
case GDK_KP_3: return keymap::kp_3;
|
||||
case GDK_KP_4: return keymap::kp_4;
|
||||
case GDK_KP_5: return keymap::kp_5;
|
||||
case GDK_KP_6: return keymap::kp_6;
|
||||
case GDK_KP_7: return keymap::kp_7;
|
||||
case GDK_KP_8: return keymap::kp_8;
|
||||
case GDK_KP_9: return keymap::kp_9;
|
||||
case GDK_KP_0: return keymap::kp_0;
|
||||
case GDK_KP_Decimal: return keymap::kp_decimal;
|
||||
|
||||
case GDK_KP_End: return keymap::kp_end;
|
||||
case GDK_KP_Down: return keymap::kp_down;
|
||||
case GDK_KP_Page_Down: return keymap::kp_page_down;
|
||||
case GDK_KP_Left: return keymap::kp_left;
|
||||
case GDK_KP_Begin: return keymap::kp_center;
|
||||
case GDK_KP_Right: return keymap::kp_right;
|
||||
case GDK_KP_Home: return keymap::kp_home;
|
||||
case GDK_KP_Up: return keymap::kp_up;
|
||||
case GDK_KP_Page_Up: return keymap::kp_page_up;
|
||||
case GDK_KP_Insert: return keymap::kp_insert;
|
||||
case GDK_KP_Delete: return keymap::kp_delete;
|
||||
|
||||
case GDK_KP_Add: return keymap::kp_plus;
|
||||
case GDK_KP_Subtract: return keymap::kp_minus;
|
||||
case GDK_KP_Multiply: return keymap::kp_mul;
|
||||
case GDK_KP_Divide: return keymap::kp_div;
|
||||
case GDK_KP_Enter: return keymap::kp_enter;
|
||||
|
||||
case GDK_Num_Lock: return keymap::num_lock;
|
||||
case GDK_Caps_Lock: return keymap::caps_lock;
|
||||
|
||||
case GDK_Up: return keymap::up;
|
||||
case GDK_Down: return keymap::down;
|
||||
case GDK_Left: return keymap::left;
|
||||
case GDK_Right: return keymap::right;
|
||||
|
||||
case GDK_Tab: return keymap::tab;
|
||||
case GDK_Return: return keymap::enter;
|
||||
case GDK_space: return keymap::space;
|
||||
|
||||
case GDK_Control_L: return keymap::lctrl;
|
||||
case GDK_Control_R: return keymap::rctrl;
|
||||
case GDK_Alt_L: return keymap::lalt;
|
||||
case GDK_Alt_R: return keymap::ralt;
|
||||
case GDK_Shift_L: return keymap::lshift;
|
||||
case GDK_Shift_R: return keymap::rshift;
|
||||
case GDK_Super_L: return keymap::lsuper;
|
||||
case GDK_Super_R: return keymap::rsuper;
|
||||
case GDK_Menu: return keymap::menu;
|
||||
|
||||
}
|
||||
|
||||
return keymap::none;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
libui_gtk ~byuu (2007-06-06)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#ifndef LIBUI_H
|
||||
#define LIBUI_H
|
||||
|
||||
#include "libbase.h"
|
||||
#include "libarray.h"
|
||||
#include "libvector.h"
|
||||
#include "libstring.h"
|
||||
#include "libkeymap.h"
|
||||
|
||||
//TODO: hide this if possible
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
namespace libui {
|
||||
|
||||
class Window;
|
||||
#include "libui_gtk_control.h"
|
||||
|
||||
void init();
|
||||
void term();
|
||||
bool run();
|
||||
bool events_pending();
|
||||
|
||||
uint get_screen_width();
|
||||
uint get_screen_height();
|
||||
|
||||
bool file_load(Window *owner, char *filename, const char *filter, const char *path = "");
|
||||
bool file_save(Window *owner, char *filename, const char *filter, const char *path = "");
|
||||
|
||||
uint16 translate_key(uint key);
|
||||
|
||||
namespace Message {
|
||||
enum {
|
||||
Invalid = 0,
|
||||
Close,
|
||||
Block,
|
||||
KeyUp,
|
||||
KeyDown,
|
||||
Clicked,
|
||||
DoubleClicked,
|
||||
Changed,
|
||||
};
|
||||
};
|
||||
|
||||
class Window { public:
|
||||
enum Style {
|
||||
Center = 1,
|
||||
};
|
||||
|
||||
MenuBar menu;
|
||||
void create(uint style, uint width, uint height, const char *caption = "");
|
||||
void set_text(const char *str);
|
||||
void set_background_color(uint8 r, uint8 g, uint8 b);
|
||||
void focus();
|
||||
bool focused();
|
||||
void move(uint x, uint y);
|
||||
void resize(uint width, uint height);
|
||||
virtual void show();
|
||||
virtual void hide();
|
||||
void show(bool state);
|
||||
bool visible();
|
||||
void fullscreen();
|
||||
void unfullscreen();
|
||||
void fullscreen(bool state);
|
||||
bool is_fullscreen();
|
||||
|
||||
virtual bool message(uint id, uintptr_t param = 0) { return true; }
|
||||
|
||||
//private:
|
||||
struct {
|
||||
GtkWidget *window, *menubar;
|
||||
GtkWidget *vcontainer, *container;
|
||||
} info;
|
||||
|
||||
public:
|
||||
Window() {
|
||||
info.menubar = 0;
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,676 @@
|
||||
namespace libui {
|
||||
|
||||
/*****
|
||||
* Control
|
||||
*****/
|
||||
|
||||
void Control::move(uint x, uint y) {
|
||||
gtk_fixed_move(GTK_FIXED(owner->info.container), widget, x, y);
|
||||
}
|
||||
|
||||
void Control::resize(uint width, uint height) {
|
||||
gtk_widget_set_size_request(widget, width, height);
|
||||
}
|
||||
|
||||
void Control::focus() {
|
||||
gtk_widget_grab_focus(widget);
|
||||
}
|
||||
|
||||
void Control::show() {
|
||||
gtk_widget_show(widget);
|
||||
}
|
||||
|
||||
void Control::hide() {
|
||||
gtk_widget_hide(widget);
|
||||
}
|
||||
|
||||
void Control::show(bool state) {
|
||||
(state == true) ? show() : hide();
|
||||
}
|
||||
|
||||
bool Control::visible() {
|
||||
return GTK_WIDGET_VISIBLE(widget);
|
||||
}
|
||||
|
||||
void Control::enable() {
|
||||
gtk_widget_set_sensitive(widget, true);
|
||||
}
|
||||
|
||||
void Control::disable() {
|
||||
gtk_widget_set_sensitive(widget, false);
|
||||
}
|
||||
|
||||
void Control::enable(bool state) {
|
||||
(state == true) ? enable() : disable();
|
||||
}
|
||||
|
||||
bool Control::enabled() {
|
||||
return GTK_WIDGET_SENSITIVE(widget);
|
||||
}
|
||||
|
||||
/*****
|
||||
* MenuBar
|
||||
*****/
|
||||
|
||||
void MenuBar::create(Window &r_owner) {
|
||||
type = ControlType::MenuBar;
|
||||
widget = r_owner.info.menubar;
|
||||
owner = &r_owner;
|
||||
show();
|
||||
}
|
||||
|
||||
void MenuBar::finish() {
|
||||
}
|
||||
|
||||
/*****
|
||||
* MenuGroup
|
||||
*****/
|
||||
|
||||
void MenuGroup::create(MenuBar &r_owner, const char *caption) {
|
||||
type = ControlType::MenuGroup;
|
||||
widget = gtk_menu_new();
|
||||
item = gtk_menu_item_new_with_label(caption ? caption : "?");
|
||||
owner = r_owner.owner;
|
||||
parent = r_owner.widget;
|
||||
}
|
||||
|
||||
void MenuGroup::create(MenuGroup &r_owner, const char *caption) {
|
||||
type = ControlType::MenuGroup;
|
||||
widget = gtk_menu_new();
|
||||
item = gtk_menu_item_new_with_label(caption ? caption : "?");
|
||||
owner = r_owner.owner;
|
||||
parent = r_owner.widget;
|
||||
}
|
||||
|
||||
void MenuGroup::finish() {
|
||||
gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), widget);
|
||||
gtk_menu_bar_append(parent, item);
|
||||
gtk_widget_show(item);
|
||||
}
|
||||
|
||||
/*****
|
||||
* MenuItem
|
||||
*****/
|
||||
|
||||
void MenuItem::create(MenuGroup &r_owner, const char *caption) {
|
||||
type = ControlType::MenuItem;
|
||||
widget = gtk_menu_item_new_with_label(caption ? caption : "?");
|
||||
owner = r_owner.owner;
|
||||
parent = r_owner.widget;
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget);
|
||||
g_signal_connect_swapped(G_OBJECT(widget), "activate",
|
||||
G_CALLBACK(libui_control_clicked), (gpointer)this);
|
||||
gtk_widget_show(widget);
|
||||
}
|
||||
|
||||
/*****
|
||||
* MenuCheckItem
|
||||
*****/
|
||||
|
||||
void MenuCheckItem::create(MenuGroup &r_owner, const char *caption) {
|
||||
type = ControlType::MenuCheckItem;
|
||||
widget = gtk_check_menu_item_new_with_label(caption ? caption : "?");
|
||||
owner = r_owner.owner;
|
||||
parent = r_owner.widget;
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget);
|
||||
g_signal_connect_swapped(G_OBJECT(widget), "activate",
|
||||
G_CALLBACK(libui_control_clicked), (gpointer)this);
|
||||
gtk_widget_show(widget);
|
||||
}
|
||||
|
||||
void MenuCheckItem::check() {
|
||||
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), TRUE);
|
||||
}
|
||||
|
||||
void MenuCheckItem::uncheck() {
|
||||
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), FALSE);
|
||||
}
|
||||
|
||||
void MenuCheckItem::check(bool state) {
|
||||
(state == true) ? check() : uncheck();
|
||||
}
|
||||
|
||||
bool MenuCheckItem::checked() {
|
||||
return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
|
||||
}
|
||||
|
||||
/*****
|
||||
* MenuRadioItem
|
||||
*****/
|
||||
|
||||
void MenuRadioItem::create(MenuGroup &r_owner, ControlGroup &list, const char *caption) {
|
||||
if(list.count() == 0)throw;
|
||||
type = ControlType::MenuRadioItem;
|
||||
widget = (&list[0] == this) ?
|
||||
gtk_radio_menu_item_new_with_label(0, caption ? caption : "?") :
|
||||
gtk_radio_menu_item_new_with_label_from_widget(GTK_RADIO_MENU_ITEM(list[0].widget), caption ? caption : "");
|
||||
owner = r_owner.owner;
|
||||
parent = r_owner.widget;
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget);
|
||||
g_signal_connect_swapped(G_OBJECT(widget), "activate",
|
||||
G_CALLBACK(libui_control_clicked), (gpointer)this);
|
||||
gtk_widget_show(widget);
|
||||
}
|
||||
|
||||
void MenuRadioItem::check() {
|
||||
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), TRUE);
|
||||
}
|
||||
|
||||
bool MenuRadioItem::checked() {
|
||||
return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
|
||||
}
|
||||
|
||||
/*****
|
||||
* MenuSeparator
|
||||
*****/
|
||||
|
||||
void MenuSeparator::create(MenuGroup &r_owner) {
|
||||
type = ControlType::MenuSeparator;
|
||||
widget = gtk_separator_menu_item_new();
|
||||
owner = r_owner.owner;
|
||||
parent = r_owner.widget;
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget);
|
||||
gtk_widget_show(widget);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Panel
|
||||
*****/
|
||||
|
||||
void Panel::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) {
|
||||
type = ControlType::Panel;
|
||||
widget = gtk_fixed_new();
|
||||
owner = &r_owner;
|
||||
gtk_widget_set_size_request(widget, width, height);
|
||||
gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y);
|
||||
gtk_widget_show(widget);
|
||||
}
|
||||
|
||||
void Panel::attach(Window &window) {
|
||||
if(attached) { //detach existing child window, return to toplevel window
|
||||
gtk_widget_reparent(attached->info.vcontainer, attached->info.window);
|
||||
}
|
||||
attached = &window;
|
||||
window.hide();
|
||||
gtk_widget_reparent(window.info.vcontainer, widget);
|
||||
}
|
||||
|
||||
void Panel::detach() {
|
||||
if(attached) {
|
||||
gtk_widget_reparent(attached->info.vcontainer, attached->info.window);
|
||||
}
|
||||
attached = 0;
|
||||
}
|
||||
|
||||
/*****
|
||||
* Container
|
||||
*****/
|
||||
|
||||
void Container::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) {
|
||||
type = ControlType::Container;
|
||||
widget = gtk_drawing_area_new();
|
||||
owner = &r_owner;
|
||||
gtk_widget_set_size_request(widget, width, height);
|
||||
gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y);
|
||||
gtk_widget_show(widget);
|
||||
}
|
||||
|
||||
void Container::set_background_color(uint8 r, uint8 g, uint8 b) {
|
||||
GdkColor color;
|
||||
color.pixel = (r << 16) | (g << 8) | (b);
|
||||
color.red = (r << 8) | (r);
|
||||
color.green = (g << 8) | (g);
|
||||
color.blue = (b << 8) | (b);
|
||||
gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &color);
|
||||
}
|
||||
|
||||
unsigned long Container::x_handle() {
|
||||
return GDK_WINDOW_XWINDOW(widget->window);
|
||||
}
|
||||
|
||||
GtkWidget *Container::handle() {
|
||||
return widget;
|
||||
}
|
||||
|
||||
/*****
|
||||
* Canvas
|
||||
*
|
||||
* Note: for reasons that defy any notion of logic, the GTK+ developers decided to
|
||||
* store color in semi-reversed format (XBGR) rather than conventional format (XRGB).
|
||||
* This is not an endian issue.
|
||||
* As a result, we are forced to perform manual conversion to XBGR format, at the
|
||||
* cost of significant overhead.
|
||||
*****/
|
||||
|
||||
void libui_canvas_expose(GtkWidget *widget, GdkEventAny *any, Canvas *canvas) {
|
||||
uint32 *d = canvas->rbuffer;
|
||||
uint32 *s = canvas->buffer;
|
||||
for(uint y = widget->allocation.height; y; y--) {
|
||||
for(uint x = widget->allocation.width; x; x--) {
|
||||
uint32 p = *s++;
|
||||
*d++ = ((p << 16) & 0xff0000) + (p & 0x00ff00) + ((p >> 16) & 0x0000ff);
|
||||
}
|
||||
}
|
||||
|
||||
gdk_draw_rgb_32_image(widget->window,
|
||||
widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
|
||||
0, 0, widget->allocation.width, widget->allocation.height,
|
||||
GDK_RGB_DITHER_NONE, (guchar*)canvas->rbuffer, canvas->pitch);
|
||||
}
|
||||
|
||||
void Canvas::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) {
|
||||
type = ControlType::Canvas;
|
||||
widget = gtk_drawing_area_new();
|
||||
owner = &r_owner;
|
||||
gtk_widget_set_size_request(widget, width, height);
|
||||
gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y);
|
||||
gtk_widget_show(widget);
|
||||
|
||||
pitch = width * sizeof(uint32);
|
||||
rbuffer = (uint32*)malloc(pitch * height);
|
||||
buffer = (uint32*)malloc(pitch * height);
|
||||
memset(buffer, 0, pitch * height);
|
||||
memset(rbuffer, 0, pitch * height);
|
||||
g_signal_connect(G_OBJECT(widget), "expose_event", G_CALLBACK(libui_canvas_expose), this);
|
||||
}
|
||||
|
||||
void Canvas::redraw() {
|
||||
if(!widget->window)return;
|
||||
|
||||
GdkRectangle rect;
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.width = widget->allocation.width;
|
||||
rect.height = widget->allocation.height;
|
||||
gdk_window_invalidate_rect(widget->window, &rect, true);
|
||||
}
|
||||
|
||||
Canvas::Canvas() {
|
||||
buffer = 0;
|
||||
}
|
||||
|
||||
Canvas::~Canvas() {
|
||||
safe_free(rbuffer);
|
||||
safe_free(buffer);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Frame
|
||||
*****/
|
||||
|
||||
void Frame::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) {
|
||||
type = ControlType::Frame;
|
||||
widget = gtk_frame_new(caption ? caption : "");
|
||||
owner = &r_owner;
|
||||
gtk_widget_set_size_request(widget, width, height);
|
||||
gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y);
|
||||
gtk_widget_show(widget);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Label
|
||||
*****/
|
||||
|
||||
void Label::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) {
|
||||
type = ControlType::Label;
|
||||
widget = gtk_label_new(caption ? caption : "");
|
||||
owner = &r_owner;
|
||||
gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.0);
|
||||
gtk_widget_set_size_request(widget, width, height);
|
||||
gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y);
|
||||
gtk_widget_show(widget);
|
||||
}
|
||||
|
||||
void Label::set_text(const char *str) {
|
||||
gtk_label_set_label(GTK_LABEL(widget), str);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Button
|
||||
*****/
|
||||
|
||||
void Button::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) {
|
||||
type = ControlType::Button;
|
||||
widget = gtk_button_new_with_label(caption ? caption : "");
|
||||
owner = &r_owner;
|
||||
gtk_widget_set_size_request(widget, width, height);
|
||||
gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y);
|
||||
gtk_widget_show(widget);
|
||||
|
||||
g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(libui_control_clicked), (gpointer)this);
|
||||
}
|
||||
|
||||
void Button::set_text(const char *str) {
|
||||
gtk_button_set_label(GTK_BUTTON(widget), str);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Checkbox
|
||||
*****/
|
||||
|
||||
void Checkbox::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) {
|
||||
type = ControlType::Checkbox;
|
||||
widget = gtk_check_button_new_with_label(caption ? caption : "");
|
||||
owner = &r_owner;
|
||||
gtk_widget_set_size_request(widget, width, height);
|
||||
gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y);
|
||||
gtk_widget_show(widget);
|
||||
|
||||
g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(libui_control_clicked), (gpointer)this);
|
||||
}
|
||||
|
||||
void Checkbox::check() {
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
|
||||
}
|
||||
|
||||
void Checkbox::uncheck() {
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), FALSE);
|
||||
}
|
||||
|
||||
void Checkbox::check(bool state) {
|
||||
(state == true) ? check() : uncheck();
|
||||
}
|
||||
|
||||
bool Checkbox::checked() {
|
||||
return (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)) == TRUE) ? true : false;
|
||||
}
|
||||
|
||||
/*****
|
||||
* Radiobox
|
||||
*****/
|
||||
|
||||
void Radiobox::create(Window &r_owner, ControlGroup &group, uint style, uint x, uint y, uint width, uint height, const char *caption) {
|
||||
if(group.count() == 0)throw;
|
||||
type = ControlType::Radiobox;
|
||||
widget = (&group[0] == this) ?
|
||||
gtk_radio_button_new_with_label(0, caption ? caption : "") :
|
||||
gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(group[0].widget), caption ? caption : "");
|
||||
owner = &r_owner;
|
||||
gtk_widget_set_size_request(widget, width, height);
|
||||
gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y);
|
||||
gtk_widget_show(widget);
|
||||
|
||||
g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(libui_control_clicked), (gpointer)this);
|
||||
}
|
||||
|
||||
void Radiobox::check() {
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
|
||||
}
|
||||
|
||||
bool Radiobox::checked() {
|
||||
return (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)) == TRUE) ? true : false;
|
||||
}
|
||||
|
||||
/*****
|
||||
* Editbox
|
||||
*****/
|
||||
|
||||
void Editbox::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) {
|
||||
owner = &r_owner;
|
||||
type = ControlType::Editbox;
|
||||
multiline = bool(style & Multiline);
|
||||
|
||||
if(multiline == false) {
|
||||
widget = gtk_entry_new();
|
||||
if(style & Editbox::Readonly) { gtk_entry_set_editable(GTK_ENTRY(widget), false); }
|
||||
gtk_entry_set_text(GTK_ENTRY(widget), caption ? caption : "");
|
||||
} else {
|
||||
GtkPolicyType hscroll = (style & Editbox::HorizontalScrollAlways) ? GTK_POLICY_ALWAYS :
|
||||
(style & Editbox::HorizontalScrollNever) ? GTK_POLICY_NEVER :
|
||||
GTK_POLICY_AUTOMATIC;
|
||||
GtkPolicyType vscroll = (style & Editbox::VerticalScrollAlways) ? GTK_POLICY_ALWAYS :
|
||||
(style & Editbox::VerticalScrollNever) ? GTK_POLICY_NEVER :
|
||||
GTK_POLICY_AUTOMATIC;
|
||||
widget = gtk_scrolled_window_new(0, 0);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), hscroll, vscroll);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(widget), GTK_SHADOW_ETCHED_IN);
|
||||
subwidget = gtk_text_view_new();
|
||||
gtk_container_add(GTK_CONTAINER(widget), subwidget);
|
||||
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(subwidget));
|
||||
if(style & Editbox::Readonly) { gtk_text_view_set_editable(GTK_TEXT_VIEW(subwidget), false); }
|
||||
gtk_text_buffer_set_text(buffer, caption ? caption : "", -1);
|
||||
gtk_widget_show(subwidget);
|
||||
}
|
||||
|
||||
gtk_widget_set_size_request(widget, width, height);
|
||||
gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y);
|
||||
gtk_widget_show(widget);
|
||||
}
|
||||
|
||||
void Editbox::set_text(const char *str) {
|
||||
if(multiline == false) {
|
||||
gtk_entry_set_text(GTK_ENTRY(widget), str);
|
||||
} else {
|
||||
gtk_text_buffer_set_text(buffer, str, -1);
|
||||
}
|
||||
}
|
||||
|
||||
uint Editbox::get_text(char *str, uint length) {
|
||||
if(multiline == false) {
|
||||
const char *temp = gtk_entry_get_text(GTK_ENTRY(widget));
|
||||
return strlcpy(str, temp ? temp : "", length);
|
||||
} else {
|
||||
GtkTextIter start, end;
|
||||
gtk_text_buffer_get_start_iter(buffer, &start);
|
||||
gtk_text_buffer_get_end_iter(buffer, &end);
|
||||
return strlcpy(str, gtk_text_buffer_get_text(buffer, &start, &end, true), length);
|
||||
}
|
||||
}
|
||||
|
||||
/*****
|
||||
* Listbox
|
||||
*****/
|
||||
|
||||
/*****
|
||||
* GTK+'s implementation of list boxes was apparently someone's idea of a very, very cruel joke ...
|
||||
* Attempt to understand the below code at the risk of your own sanity.
|
||||
*****/
|
||||
|
||||
void Listbox::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *columns) {
|
||||
owner = &r_owner;
|
||||
type = ControlType::Listbox;
|
||||
|
||||
bool header = bool(style & Header);
|
||||
|
||||
stringarray list, part;
|
||||
split(part, "|", columns);
|
||||
|
||||
GType *v = (GType*)malloc(count(part) * sizeof(GType));
|
||||
for(uint i = 0; i < count(part); i++) { v[i] = G_TYPE_STRING; }
|
||||
store = gtk_list_store_newv(count(part), v);
|
||||
safe_free(v);
|
||||
|
||||
widget = gtk_scrolled_window_new(0, 0);
|
||||
GtkPolicyType hscroll = (style & Listbox::HorizontalScrollAlways) ? GTK_POLICY_ALWAYS :
|
||||
(style & Listbox::HorizontalScrollNever) ? GTK_POLICY_NEVER :
|
||||
GTK_POLICY_AUTOMATIC;
|
||||
GtkPolicyType vscroll = (style & Listbox::VerticalScrollAlways) ? GTK_POLICY_ALWAYS :
|
||||
(style & Listbox::VerticalScrollNever) ? GTK_POLICY_NEVER :
|
||||
GTK_POLICY_AUTOMATIC;
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), hscroll, vscroll);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(widget), GTK_SHADOW_ETCHED_IN);
|
||||
subwidget = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
|
||||
gtk_container_add(GTK_CONTAINER(widget), subwidget);
|
||||
g_object_unref(G_OBJECT(store));
|
||||
gtk_widget_set_size_request(widget, width, height);
|
||||
gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y);
|
||||
gtk_widget_show(subwidget);
|
||||
gtk_widget_show(widget);
|
||||
|
||||
split(list, "|", columns);
|
||||
//alternate colors for each listbox entry if there are multiple columns ...
|
||||
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(subwidget), (count(list) >= 2) ? true : false);
|
||||
for(uint i = 0; i < count(list); i++) {
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
column = gtk_tree_view_column_new_with_attributes(strptr(list[i]), renderer, "text", i, 0);
|
||||
column_list[column_list.size()] = column;
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(subwidget), column);
|
||||
}
|
||||
|
||||
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(subwidget), header);
|
||||
autosize_columns();
|
||||
|
||||
g_signal_connect_swapped(G_OBJECT(subwidget), "cursor-changed", G_CALLBACK(libui_control_changed), (gpointer)this);
|
||||
g_signal_connect_swapped(G_OBJECT(subwidget), "row-activated", G_CALLBACK(libui_control_double_clicked), (gpointer)this);
|
||||
}
|
||||
|
||||
void Listbox::autosize_columns() {
|
||||
gtk_tree_view_columns_autosize(GTK_TREE_VIEW(subwidget));
|
||||
}
|
||||
|
||||
void Listbox::set_column_width(uint column, uint width) {
|
||||
gtk_tree_view_column_set_min_width(column_list[column], width);
|
||||
gtk_tree_view_column_set_max_width(column_list[column], width);
|
||||
}
|
||||
|
||||
void Listbox::add_item(const char *data) {
|
||||
stringarray part;
|
||||
split(part, "|", data);
|
||||
gtk_list_store_append(store, &iter);
|
||||
for(uint i = 0; i < count(part); i++) {
|
||||
gtk_list_store_set(store, &iter, i, strptr(part[i]), -1);
|
||||
}
|
||||
}
|
||||
|
||||
void Listbox::set_item(uint index, const char *data) {
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subwidget));
|
||||
for(uint i = 0; i <= index; i++) {
|
||||
(i == 0) ?
|
||||
gtk_tree_model_get_iter_first(model, &iter) :
|
||||
gtk_tree_model_iter_next(model, &iter);
|
||||
}
|
||||
|
||||
stringarray part;
|
||||
split(part, "|", data);
|
||||
for(uint i = 0; i < count(part); i++) {
|
||||
gtk_list_store_set(store, &iter, i, strptr(part[i]), -1);
|
||||
}
|
||||
}
|
||||
|
||||
//... because gtk_tree_view_get_selected_row(GTK_TREE_VIEW(subwidget)) would be too easy ...
|
||||
int Listbox::get_selection() {
|
||||
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subwidget));
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subwidget));
|
||||
if(gtk_tree_model_get_iter_first(model, &iter) == false) { return -1; }
|
||||
if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) { return 0; }
|
||||
for(uint i = 1; i < 100000; i++) {
|
||||
if(gtk_tree_model_iter_next(model, &iter) == false) { return -1; }
|
||||
if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) { return i; }
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//... because gtk_tree_view_set_selected_row(GTK_TREE_VIEW(subwidget), index) would be too easy ...
|
||||
void Listbox::set_selection(int index) {
|
||||
int current = get_selection();
|
||||
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subwidget));
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subwidget));
|
||||
gtk_tree_selection_unselect_all(selection);
|
||||
if(index < 0) { goto end; }
|
||||
if(gtk_tree_model_get_iter_first(model, &iter) == false) { goto end; }
|
||||
if(index == 0) { gtk_tree_selection_select_iter(selection, &iter); goto end; }
|
||||
for(uint i = 1; i < 100000; i++) {
|
||||
if(gtk_tree_model_iter_next(model, &iter) == false) { goto end; }
|
||||
if(index == i) { gtk_tree_selection_select_iter(selection, &iter); goto end; }
|
||||
}
|
||||
end:
|
||||
if(current != index) { owner->message(Message::Changed, (uintptr_t)this); }
|
||||
}
|
||||
|
||||
void Listbox::reset() {
|
||||
gtk_list_store_clear(GTK_LIST_STORE(store));
|
||||
gtk_tree_view_set_model(GTK_TREE_VIEW(subwidget), GTK_TREE_MODEL(store));
|
||||
}
|
||||
|
||||
/*****
|
||||
* Combobox
|
||||
*****/
|
||||
|
||||
void Combobox::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) {
|
||||
type = ControlType::Combobox;
|
||||
widget = gtk_combo_box_new_text(); //gtk_combo_box_entry_new_text(); /* alternate style */
|
||||
owner = &r_owner;
|
||||
counter = 0;
|
||||
gtk_widget_set_size_request(widget, width, height);
|
||||
gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y);
|
||||
gtk_widget_show(widget);
|
||||
}
|
||||
|
||||
void Combobox::add_item(const char *data) {
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(widget), data);
|
||||
if(counter++ == 0) { set_selection(0); }
|
||||
}
|
||||
|
||||
int Combobox::get_selection() {
|
||||
return gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
|
||||
}
|
||||
|
||||
void Combobox::set_selection(int index) {
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(widget), index);
|
||||
}
|
||||
|
||||
void Combobox::reset() {
|
||||
if(counter == 0) { return; }
|
||||
for(int i = (counter - 1); i >= 0; i--) {
|
||||
gtk_combo_box_remove_text(GTK_COMBO_BOX(widget), i);
|
||||
}
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
/*****
|
||||
* Progressbar
|
||||
*****/
|
||||
|
||||
void Progressbar::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) {
|
||||
type = ControlType::Progressbar;
|
||||
widget = gtk_progress_bar_new();
|
||||
owner = &r_owner;
|
||||
gtk_widget_set_size_request(widget, width, height);
|
||||
gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y);
|
||||
gtk_widget_show(widget);
|
||||
}
|
||||
|
||||
void Progressbar::set_progress(uint progress) {
|
||||
progress = minmax<0, 100>(progress);
|
||||
double p = (double)progress / 100.0;
|
||||
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(widget), p);
|
||||
}
|
||||
|
||||
uint Progressbar::get_progress() {
|
||||
uint p = (uint)(gtk_progress_bar_get_fraction(GTK_PROGRESS_BAR(widget)) * 100.0);
|
||||
return (uint)minmax<0, 100>(p);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Slider
|
||||
*****/
|
||||
|
||||
void Slider::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, uint range) {
|
||||
type = ControlType::Slider;
|
||||
orientation = (style & Vertical) ? 1 : 0;
|
||||
|
||||
if(range < 1)range = 1;
|
||||
if(orientation == 0) {
|
||||
widget = gtk_hscale_new_with_range(0, range - 1, 1);
|
||||
} else {
|
||||
widget = gtk_vscale_new_with_range(0, range - 1, 1);
|
||||
}
|
||||
|
||||
owner = &r_owner;
|
||||
gtk_scale_set_draw_value(GTK_SCALE(widget), FALSE);
|
||||
gtk_widget_set_size_request(widget, width, height);
|
||||
gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y);
|
||||
gtk_widget_show(widget);
|
||||
|
||||
g_signal_connect_swapped(G_OBJECT(widget), "value-changed", G_CALLBACK(libui_control_changed), (gpointer)this);
|
||||
}
|
||||
|
||||
void Slider::set_position(uint position) {
|
||||
gtk_range_set_value(GTK_RANGE(widget), position);
|
||||
}
|
||||
|
||||
uint Slider::get_position() {
|
||||
return (int)gtk_range_get_value(GTK_RANGE(widget));
|
||||
}
|
||||
|
||||
};
|
||||
@@ -0,0 +1,265 @@
|
||||
namespace ControlType {
|
||||
enum {
|
||||
Invalid,
|
||||
MenuBar,
|
||||
MenuGroup,
|
||||
MenuItem,
|
||||
MenuCheckItem,
|
||||
MenuRadioItem,
|
||||
MenuSeparator,
|
||||
Panel,
|
||||
Container,
|
||||
Canvas,
|
||||
Frame,
|
||||
Label,
|
||||
Button,
|
||||
Checkbox,
|
||||
Radiobox,
|
||||
Editbox,
|
||||
Listbox,
|
||||
Combobox,
|
||||
Progressbar,
|
||||
Slider,
|
||||
};
|
||||
};
|
||||
|
||||
class Control { public:
|
||||
uint type;
|
||||
void move(uint x, uint y);
|
||||
void resize(uint width, uint height);
|
||||
|
||||
void focus();
|
||||
|
||||
void show(bool state);
|
||||
void show();
|
||||
void hide();
|
||||
bool visible();
|
||||
|
||||
void enable(bool state);
|
||||
void enable();
|
||||
void disable();
|
||||
bool enabled();
|
||||
|
||||
//protected:
|
||||
Window *owner;
|
||||
GtkWidget *widget;
|
||||
uint id;
|
||||
|
||||
public:
|
||||
Control() : owner(0), widget(0), id(0), type(ControlType::Invalid) {}
|
||||
};
|
||||
|
||||
class ControlGroup { public:
|
||||
uint count() { return list.size(); }
|
||||
void add(Control &control) { list[list.size()] = &control; }
|
||||
void reset() { list.reset(); }
|
||||
ControlGroup &operator=(ControlGroup &source) { list = source.list; return *this; }
|
||||
Control &operator[](int index) { return *list[index]; }
|
||||
|
||||
private:
|
||||
array<Control*> list;
|
||||
};
|
||||
|
||||
class MenuBar : public Control { public:
|
||||
void create(Window &owner);
|
||||
void finish();
|
||||
};
|
||||
|
||||
class MenuGroup : public Control { public:
|
||||
void create(MenuBar &owner, const char *caption);
|
||||
void create(MenuGroup &owner, const char *caption);
|
||||
void finish();
|
||||
|
||||
private:
|
||||
GtkWidget *parent, *item;
|
||||
};
|
||||
|
||||
class MenuItem : public Control { public:
|
||||
void create(MenuGroup &owner, const char *caption);
|
||||
|
||||
private:
|
||||
GtkWidget *parent;
|
||||
};
|
||||
|
||||
class MenuCheckItem : public Control { public:
|
||||
void create(MenuGroup &owner, const char *caption);
|
||||
void check();
|
||||
void uncheck();
|
||||
void check(bool state);
|
||||
bool checked();
|
||||
|
||||
private:
|
||||
GtkWidget *parent;
|
||||
};
|
||||
|
||||
class MenuRadioItem : public Control { public:
|
||||
void create(MenuGroup &owner, ControlGroup &list, const char *caption);
|
||||
void check();
|
||||
bool checked();
|
||||
|
||||
private:
|
||||
GtkWidget *parent;
|
||||
};
|
||||
|
||||
class MenuSeparator : public Control { public:
|
||||
void create(MenuGroup &owner);
|
||||
|
||||
private:
|
||||
GtkWidget *parent;
|
||||
};
|
||||
|
||||
class Panel : public Control { public:
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height);
|
||||
void attach(Window &window);
|
||||
void detach();
|
||||
|
||||
private:
|
||||
Window *attached;
|
||||
|
||||
public:
|
||||
Panel() : attached(0) {}
|
||||
};
|
||||
|
||||
class Container : public Control { public:
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height);
|
||||
void set_background_color(uint8 r, uint8 g, uint8 b);
|
||||
|
||||
//platform-dependent:
|
||||
unsigned long x_handle();
|
||||
GtkWidget *handle();
|
||||
};
|
||||
|
||||
class Canvas : public Control { public:
|
||||
uint32 *buffer;
|
||||
uint pitch;
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height);
|
||||
void redraw();
|
||||
Canvas();
|
||||
~Canvas();
|
||||
|
||||
private:
|
||||
uint32 *rbuffer;
|
||||
friend void libui_canvas_expose(GtkWidget *widget, GdkEventAny *any, Canvas *canvas);
|
||||
};
|
||||
|
||||
class Frame : public Control { public:
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
};
|
||||
|
||||
class Label : public Control { public:
|
||||
enum { ideal_height = 18 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
void set_text(const char *str);
|
||||
};
|
||||
|
||||
class Button : public Control { public:
|
||||
enum { ideal_height = 30 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
void set_text(const char *str);
|
||||
};
|
||||
|
||||
class Checkbox : public Control { public:
|
||||
enum { ideal_height = 18 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
void check();
|
||||
void uncheck();
|
||||
void check(bool state);
|
||||
bool checked();
|
||||
};
|
||||
|
||||
class Radiobox : public Control { public:
|
||||
enum { ideal_height = 18 };
|
||||
void create(Window &owner, ControlGroup &group, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
void check();
|
||||
bool checked();
|
||||
};
|
||||
|
||||
class Editbox : public Control { public:
|
||||
enum { ideal_height = 30 };
|
||||
enum {
|
||||
Multiline = (1 << 1),
|
||||
Readonly = (1 << 2),
|
||||
|
||||
HorizontalScrollAuto = 0,
|
||||
HorizontalScrollAlways = (1 << 3),
|
||||
HorizontalScrollNever = (1 << 4),
|
||||
|
||||
VerticalScrollAuto = 0,
|
||||
VerticalScrollAlways = (1 << 5),
|
||||
VerticalScrollNever = (1 << 6),
|
||||
};
|
||||
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
void set_text(const char *str);
|
||||
uint get_text(char *str, uint length);
|
||||
|
||||
private:
|
||||
GtkWidget *subwidget;
|
||||
GtkTextBuffer *buffer;
|
||||
bool multiline;
|
||||
};
|
||||
|
||||
class Listbox : public Control { public:
|
||||
enum {
|
||||
Header = (1 << 1),
|
||||
|
||||
HorizontalScrollAuto = 0,
|
||||
HorizontalScrollAlways = (1 << 2),
|
||||
HorizontalScrollNever = (1 << 3),
|
||||
|
||||
VerticalScrollAuto = 0,
|
||||
VerticalScrollAlways = (1 << 4),
|
||||
VerticalScrollNever = (1 << 5),
|
||||
};
|
||||
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *columns = "");
|
||||
void autosize_columns();
|
||||
void set_column_width(uint column, uint width);
|
||||
void add_item(const char *data);
|
||||
void set_item(uint index, const char *data);
|
||||
int get_selection();
|
||||
void set_selection(int index);
|
||||
void reset();
|
||||
|
||||
private:
|
||||
GtkWidget *subwidget;
|
||||
GtkListStore *store;
|
||||
GtkCellRenderer *renderer;
|
||||
GtkTreeViewColumn *column;
|
||||
array<GtkTreeViewColumn*> column_list;
|
||||
GtkTreeIter iter;
|
||||
};
|
||||
|
||||
class Combobox : public Control { public:
|
||||
enum { ideal_height = 30 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height);
|
||||
void add_item(const char *data);
|
||||
int get_selection();
|
||||
void set_selection(int index);
|
||||
void reset();
|
||||
|
||||
private:
|
||||
uint counter;
|
||||
};
|
||||
|
||||
class Progressbar : public Control { public:
|
||||
enum { ideal_height = 30 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height);
|
||||
void set_progress(uint progress);
|
||||
uint get_progress();
|
||||
};
|
||||
|
||||
class Slider : public Control { public:
|
||||
enum { ideal_height = 25 };
|
||||
enum {
|
||||
Horizontal = 0,
|
||||
Vertical = 1,
|
||||
};
|
||||
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, uint range);
|
||||
void set_position(uint position);
|
||||
uint get_position();
|
||||
|
||||
private:
|
||||
bool orientation;
|
||||
};
|
||||
@@ -0,0 +1,119 @@
|
||||
namespace libui {
|
||||
|
||||
gint libui_window_close(GtkWidget *w, GdkEventAny *any, Window *window) {
|
||||
if(window) { return !window->message(Message::Close); }
|
||||
return FALSE; //destroy window by default
|
||||
}
|
||||
|
||||
gint libui_window_keydown(GtkWidget *w, GdkEventKey *key, Window *window) {
|
||||
if(window) { window->message(Message::KeyDown, libui::translate_key(key->keyval)); }
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gint libui_window_keyup(GtkWidget *w, GdkEventKey *key, Window *window) {
|
||||
if(window) { window->message(Message::KeyUp, libui::translate_key(key->keyval)); }
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void libui_control_clicked(Control *control) {
|
||||
if(control && control->owner) { control->owner->message(Message::Clicked, (uintptr_t)control); }
|
||||
}
|
||||
|
||||
void libui_control_changed(Control *control) {
|
||||
if(control && control->owner) { control->owner->message(Message::Changed, (uintptr_t)control); }
|
||||
}
|
||||
|
||||
void libui_control_double_clicked(Control *control) {
|
||||
if(control && control->owner) { control->owner->message(Message::DoubleClicked, (uintptr_t)control); }
|
||||
}
|
||||
|
||||
void Window::create(uint style, uint width, uint height, const char *caption) {
|
||||
info.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title(GTK_WINDOW(info.window), caption ? caption : "");
|
||||
gtk_window_set_resizable(GTK_WINDOW(info.window), false);
|
||||
g_signal_connect(G_OBJECT(info.window), "delete_event", G_CALLBACK(libui_window_close), (gpointer)this);
|
||||
g_signal_connect(G_OBJECT(info.window), "key_press_event", G_CALLBACK(libui_window_keydown), (gpointer)this);
|
||||
g_signal_connect(G_OBJECT(info.window), "key_release_event", G_CALLBACK(libui_window_keyup), (gpointer)this);
|
||||
|
||||
if(style & Center) { gtk_window_set_position(GTK_WINDOW(info.window), GTK_WIN_POS_CENTER_ALWAYS); }
|
||||
|
||||
info.vcontainer = gtk_vbox_new(false, 0);
|
||||
gtk_container_add(GTK_CONTAINER(info.window), info.vcontainer);
|
||||
gtk_widget_show(info.vcontainer);
|
||||
|
||||
//always create menubar, only display it when MenuBar type is created
|
||||
//this is needed to setup box packing before menubar is defined
|
||||
info.menubar = gtk_menu_bar_new();
|
||||
gtk_box_pack_start(GTK_BOX(info.vcontainer), info.menubar, false, false, 0);
|
||||
|
||||
info.container = gtk_fixed_new();
|
||||
gtk_widget_set_size_request(info.container, width, height);
|
||||
gtk_box_pack_end(GTK_BOX(info.vcontainer), info.container, true, true, 0);
|
||||
gtk_widget_show(info.container);
|
||||
}
|
||||
|
||||
void Window::focus() {
|
||||
gtk_window_present(GTK_WINDOW(info.window));
|
||||
}
|
||||
|
||||
bool Window::focused() {
|
||||
return GTK_WIDGET_HAS_FOCUS(info.window);
|
||||
}
|
||||
|
||||
void Window::move(uint x, uint y) {
|
||||
//if window was centered before, GTK+ will ignore move requests,
|
||||
//therfore we must turn off auto-centering.
|
||||
gtk_window_set_position(GTK_WINDOW(info.window), GTK_WIN_POS_NONE);
|
||||
gtk_window_move(GTK_WINDOW(info.window), x, y);
|
||||
}
|
||||
|
||||
void Window::resize(uint width, uint height) {
|
||||
gtk_widget_set_size_request(info.container, width, height);
|
||||
}
|
||||
|
||||
void Window::show() {
|
||||
gtk_widget_show(info.window);
|
||||
}
|
||||
|
||||
void Window::hide() {
|
||||
gtk_widget_hide(info.window);
|
||||
}
|
||||
|
||||
void Window::show(bool state) {
|
||||
(state == true) ? show() : hide();
|
||||
}
|
||||
|
||||
bool Window::visible() {
|
||||
return GTK_WIDGET_VISIBLE(info.window);
|
||||
}
|
||||
|
||||
void Window::fullscreen() {
|
||||
gtk_window_fullscreen(GTK_WINDOW(info.window));
|
||||
}
|
||||
|
||||
void Window::unfullscreen() {
|
||||
gtk_window_unfullscreen(GTK_WINDOW(info.window));
|
||||
}
|
||||
|
||||
void Window::fullscreen(bool state) {
|
||||
(state == true) ? fullscreen() : unfullscreen();
|
||||
}
|
||||
|
||||
bool Window::is_fullscreen() {
|
||||
return false;
|
||||
};
|
||||
|
||||
void Window::set_text(const char *str) {
|
||||
gtk_window_set_title(GTK_WINDOW(info.window), str);
|
||||
}
|
||||
|
||||
void Window::set_background_color(uint8 r, uint8 g, uint8 b) {
|
||||
GdkColor color;
|
||||
color.pixel = (r << 16) | (g << 8) | (b);
|
||||
color.red = (r << 8) | (r);
|
||||
color.green = (g << 8) | (g);
|
||||
color.blue = (b << 8) | (b);
|
||||
gtk_widget_modify_bg(info.window, GTK_STATE_NORMAL, &color);
|
||||
}
|
||||
|
||||
};
|
||||
@@ -0,0 +1,239 @@
|
||||
#define _WIN32_IE 0x0600
|
||||
|
||||
#include "libui_win.h"
|
||||
#include "libui_win_window.cpp"
|
||||
#include "libui_win_control.cpp"
|
||||
|
||||
namespace libui {
|
||||
|
||||
long __stdcall canvas_wndproc(HWND, UINT, WPARAM, LPARAM);
|
||||
long __stdcall label_wndproc (HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
HFONT create_font(const char *name, uint size) {
|
||||
HDC hdc = GetDC(0);
|
||||
HFONT font = CreateFont(-MulDiv(size, GetDeviceCaps(hdc, LOGPIXELSY), 72),
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, name);
|
||||
ReleaseDC(0, hdc);
|
||||
return font;
|
||||
}
|
||||
|
||||
void init() {
|
||||
InitCommonControls();
|
||||
|
||||
WNDCLASS wc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
|
||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = libui_wndproc;
|
||||
wc.lpszClassName = "libui_class";
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&wc);
|
||||
|
||||
font.variable = create_font("Tahoma", 8);
|
||||
font.fixed = create_font("Courier New", 8);
|
||||
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
|
||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = canvas_wndproc;
|
||||
wc.lpszClassName = "canvas_class";
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&wc);
|
||||
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
|
||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = label_wndproc;
|
||||
wc.lpszClassName = "label_class";
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&wc);
|
||||
}
|
||||
|
||||
void term() {
|
||||
}
|
||||
|
||||
bool run() {
|
||||
MSG msg;
|
||||
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
return events_pending();
|
||||
}
|
||||
|
||||
bool events_pending() {
|
||||
MSG msg;
|
||||
return PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE);
|
||||
}
|
||||
|
||||
uint get_screen_width() { return GetSystemMetrics(SM_CXSCREEN); }
|
||||
uint get_screen_height() { return GetSystemMetrics(SM_CYSCREEN); }
|
||||
|
||||
//
|
||||
|
||||
bool file_load(Window *owner, char *filename, const char *filter, const char *path) {
|
||||
string dir, f;
|
||||
strcpy(dir, path ? path : "");
|
||||
replace(dir, "/", "\\");
|
||||
|
||||
stringarray type, part;
|
||||
strcpy(f, "");
|
||||
split(type, "|", filter);
|
||||
for(int i = 0; i < count(type); i++) {
|
||||
split(part, ";", type[i]);
|
||||
if(count(part) != 2)continue;
|
||||
|
||||
strcat(f, part[0]);
|
||||
strcat(f, " (");
|
||||
strcat(f, part[1]);
|
||||
strcat(f, ")|");
|
||||
replace(part[1], ",", ";");
|
||||
strcat(f, part[1]);
|
||||
strcat(f, "|");
|
||||
}
|
||||
|
||||
char *pf = strptr(f);
|
||||
for(int i = strlen(pf) - 1; i >= 0; i--) {
|
||||
if(pf[i] == '|')pf[i] = '\0';
|
||||
}
|
||||
|
||||
OPENFILENAME ofn;
|
||||
strcpy(filename, "");
|
||||
memset(&ofn, 0, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = owner ? owner->info.hwnd : 0;
|
||||
ofn.lpstrFilter = pf;
|
||||
ofn.lpstrInitialDir = strptr(dir);
|
||||
ofn.lpstrFile = filename;
|
||||
ofn.nMaxFile = MAX_PATH;
|
||||
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST;
|
||||
ofn.lpstrDefExt = "";
|
||||
|
||||
return GetOpenFileName(&ofn);
|
||||
}
|
||||
|
||||
bool file_save(Window *owner, char *filename, const char *filter, const char *path) {
|
||||
string dir, f;
|
||||
strcpy(dir, path ? path : "");
|
||||
replace(dir, "/", "\\");
|
||||
|
||||
stringarray type, part;
|
||||
strcpy(f, "");
|
||||
split(type, "|", filter);
|
||||
for(int i = 0; i < count(type); i++) {
|
||||
split(part, ";", type[i]);
|
||||
if(count(part) != 2)continue;
|
||||
|
||||
strcat(f, part[0]);
|
||||
strcat(f, " (");
|
||||
strcat(f, part[1]);
|
||||
strcat(f, ")|");
|
||||
replace(part[1], ",", ";");
|
||||
strcat(f, part[1]);
|
||||
strcat(f, "|");
|
||||
}
|
||||
|
||||
char *pf = strptr(f);
|
||||
for(int i = strlen(pf) - 1; i >= 0; i--) {
|
||||
if(pf[i] == '|')pf[i] = '\0';
|
||||
}
|
||||
|
||||
OPENFILENAME ofn;
|
||||
strcpy(filename, "");
|
||||
memset(&ofn, 0, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = owner ? owner->info.hwnd : 0;
|
||||
ofn.lpstrFilter = pf;
|
||||
ofn.lpstrInitialDir = strptr(dir);
|
||||
ofn.lpstrFile = filename;
|
||||
ofn.nMaxFile = MAX_PATH;
|
||||
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST;
|
||||
ofn.lpstrDefExt = "";
|
||||
|
||||
return GetSaveFileName(&ofn);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
uint16 translate_key(uint key) {
|
||||
switch(key) {
|
||||
|
||||
case VK_ESCAPE: return keymap::esc;
|
||||
|
||||
case VK_F1: return keymap::f1;
|
||||
case VK_F2: return keymap::f2;
|
||||
case VK_F3: return keymap::f3;
|
||||
case VK_F4: return keymap::f4;
|
||||
case VK_F5: return keymap::f5;
|
||||
case VK_F6: return keymap::f6;
|
||||
case VK_F7: return keymap::f7;
|
||||
case VK_F8: return keymap::f8;
|
||||
case VK_F9: return keymap::f9;
|
||||
case VK_F10: return keymap::f10;
|
||||
case VK_F11: return keymap::f11;
|
||||
case VK_F12: return keymap::f12;
|
||||
|
||||
case VK_TAB: return keymap::tab;
|
||||
case VK_RETURN: return keymap::enter;
|
||||
case VK_SPACE: return keymap::space;
|
||||
|
||||
case '0': return keymap::num_0;
|
||||
case '1': return keymap::num_1;
|
||||
case '2': return keymap::num_2;
|
||||
case '3': return keymap::num_3;
|
||||
case '4': return keymap::num_4;
|
||||
case '5': return keymap::num_5;
|
||||
case '6': return keymap::num_6;
|
||||
case '7': return keymap::num_7;
|
||||
case '8': return keymap::num_8;
|
||||
case '9': return keymap::num_9;
|
||||
|
||||
case 'A': return keymap::a;
|
||||
case 'B': return keymap::b;
|
||||
case 'C': return keymap::c;
|
||||
case 'D': return keymap::d;
|
||||
case 'E': return keymap::e;
|
||||
case 'F': return keymap::f;
|
||||
case 'G': return keymap::g;
|
||||
case 'H': return keymap::h;
|
||||
case 'I': return keymap::i;
|
||||
case 'J': return keymap::j;
|
||||
case 'K': return keymap::k;
|
||||
case 'L': return keymap::l;
|
||||
case 'M': return keymap::m;
|
||||
case 'N': return keymap::n;
|
||||
case 'O': return keymap::o;
|
||||
case 'P': return keymap::p;
|
||||
case 'Q': return keymap::q;
|
||||
case 'R': return keymap::r;
|
||||
case 'S': return keymap::s;
|
||||
case 'T': return keymap::t;
|
||||
case 'U': return keymap::u;
|
||||
case 'V': return keymap::v;
|
||||
case 'W': return keymap::w;
|
||||
case 'X': return keymap::x;
|
||||
case 'Y': return keymap::y;
|
||||
case 'Z': return keymap::z;
|
||||
|
||||
case VK_UP: return keymap::up;
|
||||
case VK_DOWN: return keymap::down;
|
||||
case VK_LEFT: return keymap::left;
|
||||
case VK_RIGHT: return keymap::right;
|
||||
|
||||
}
|
||||
return keymap::none;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
libui_win ~byuu (2007-06-10)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#ifndef LIBUI_H
|
||||
#define LIBUI_H
|
||||
|
||||
#include "libbase.h"
|
||||
#include "libarray.h"
|
||||
#include "libvector.h"
|
||||
#include "libstring.h"
|
||||
#include "libkeymap.h"
|
||||
|
||||
#undef WINVER
|
||||
#undef _WIN32_WINNT
|
||||
#define WINVER 0x0500
|
||||
#define _WIN32_WINNT 0x0500
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
|
||||
namespace libui {
|
||||
|
||||
class Window;
|
||||
#include "libui_win_control.h"
|
||||
|
||||
void init();
|
||||
void term();
|
||||
bool run();
|
||||
bool events_pending();
|
||||
|
||||
uint get_screen_width();
|
||||
uint get_screen_height();
|
||||
|
||||
bool file_load(Window *owner, char *filename, const char *filter, const char *path = "");
|
||||
bool file_save(Window *owner, char *filename, const char *filter, const char *path = "");
|
||||
|
||||
uint16 translate_key(uint key);
|
||||
|
||||
namespace Message {
|
||||
enum {
|
||||
Invalid = 0,
|
||||
Close,
|
||||
Block,
|
||||
KeyUp,
|
||||
KeyDown,
|
||||
Clicked,
|
||||
DoubleClicked,
|
||||
Changed,
|
||||
};
|
||||
};
|
||||
|
||||
class Window { public:
|
||||
enum Style {
|
||||
Center = 1,
|
||||
};
|
||||
|
||||
MenuBar menu;
|
||||
void create(uint style, uint width, uint height, const char *caption = "");
|
||||
void set_text(const char *str, ...);
|
||||
void set_background_color(uint8 r, uint8 g, uint8 b);
|
||||
void focus();
|
||||
bool focused();
|
||||
void move(uint x, uint y);
|
||||
void resize(uint width, uint height);
|
||||
virtual void show();
|
||||
virtual void hide();
|
||||
void show(bool state);
|
||||
bool visible();
|
||||
void fullscreen();
|
||||
void unfullscreen();
|
||||
void fullscreen(bool state);
|
||||
bool is_fullscreen();
|
||||
|
||||
virtual bool message(uint id, uintptr_t param = 0) { return true; }
|
||||
|
||||
void move(Control &control, uint x, uint y);
|
||||
void attach(Control &control);
|
||||
|
||||
Window();
|
||||
|
||||
//platform-dependent:
|
||||
HWND handle();
|
||||
|
||||
//private:
|
||||
struct {
|
||||
uint width, height;
|
||||
bool fullscreen;
|
||||
|
||||
HWND hwnd;
|
||||
HWND hwnd_resize;
|
||||
HBRUSH background;
|
||||
HMENU menubar;
|
||||
bool center;
|
||||
array<Control*> control;
|
||||
uint control_index;
|
||||
|
||||
array<MenuRadioItem*> menu_check_list;
|
||||
} info;
|
||||
long wndproc(HWND hwnd, uint msg, WPARAM wparam, LPARAM lparam);
|
||||
};
|
||||
|
||||
//platform-dependent:
|
||||
|
||||
static uint window_count = 0;
|
||||
|
||||
static struct {
|
||||
HFONT variable;
|
||||
HFONT fixed;
|
||||
} font;
|
||||
|
||||
HFONT create_font(const char *name, uint size);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,710 @@
|
||||
namespace libui {
|
||||
|
||||
/*****
|
||||
* Control
|
||||
*****/
|
||||
|
||||
void Control::move(uint x, uint y) {
|
||||
SetWindowPos(hwnd, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
|
||||
}
|
||||
|
||||
void Control::resize(uint width, uint height) {
|
||||
SetWindowPos(hwnd, 0, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE);
|
||||
}
|
||||
|
||||
void Control::focus() {
|
||||
if(hwnd) { SetFocus(hwnd); }
|
||||
}
|
||||
|
||||
void Control::show() {
|
||||
ShowWindow(hwnd, SW_NORMAL);
|
||||
}
|
||||
|
||||
void Control::hide() {
|
||||
ShowWindow(hwnd, SW_HIDE);
|
||||
}
|
||||
|
||||
void Control::show(bool state) {
|
||||
(state == true) ? show() : hide();
|
||||
}
|
||||
|
||||
bool Control::visible() {
|
||||
return (GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE) ? true : false;
|
||||
}
|
||||
|
||||
void Control::enable() {
|
||||
EnableWindow(hwnd, true);
|
||||
}
|
||||
|
||||
void Control::disable() {
|
||||
EnableWindow(hwnd, false);
|
||||
}
|
||||
|
||||
void Control::enable(bool state) {
|
||||
(state == true) ? enable() : disable();
|
||||
}
|
||||
|
||||
bool Control::enabled() {
|
||||
return !(GetWindowLong(hwnd, GWL_STYLE) & WS_DISABLED);
|
||||
}
|
||||
|
||||
/*****
|
||||
* MenuBar
|
||||
*****/
|
||||
|
||||
void MenuBar::create(Window &r_owner) {
|
||||
type = ControlType::MenuBar;
|
||||
group = CreateMenu();
|
||||
r_owner.attach(*this);
|
||||
owner->info.menu_check_list.reset();
|
||||
}
|
||||
|
||||
void MenuBar::finish() {
|
||||
show();
|
||||
|
||||
//check all menu radio items that need to be ...
|
||||
for(uint i = 0; i < owner->info.menu_check_list.size(); i++) {
|
||||
CheckMenuItem(owner->info.menu_check_list[i]->parent, owner->info.menu_check_list[i]->id, MF_CHECKED);
|
||||
}
|
||||
owner->info.menu_check_list.reset();
|
||||
}
|
||||
|
||||
void MenuBar::show() {
|
||||
SetMenu(owner->info.hwnd_resize, group);
|
||||
SetMenu(owner->info.hwnd, group);
|
||||
owner->resize(owner->info.width, owner->info.height);
|
||||
}
|
||||
|
||||
void MenuBar::hide() {
|
||||
SetMenu(owner->info.hwnd_resize, 0);
|
||||
SetMenu(owner->info.hwnd, 0);
|
||||
owner->resize(owner->info.width, owner->info.height);
|
||||
}
|
||||
|
||||
void MenuBar::show(bool state) {
|
||||
(state == true) ? show() : hide();
|
||||
}
|
||||
|
||||
bool MenuBar::visible() {
|
||||
return GetMenu(owner->info.hwnd);
|
||||
}
|
||||
|
||||
/*****
|
||||
* MenuGroup
|
||||
*****/
|
||||
|
||||
void MenuGroup::create(MenuBar &r_owner, const char *_caption) {
|
||||
type = ControlType::MenuGroup;
|
||||
owner = r_owner.owner;
|
||||
parent = r_owner.group;
|
||||
group = CreatePopupMenu();
|
||||
caption = strdup(_caption);
|
||||
owner->attach(*this);
|
||||
}
|
||||
|
||||
void MenuGroup::create(MenuGroup &r_owner, const char *_caption) {
|
||||
type = ControlType::MenuGroup;
|
||||
owner = r_owner.owner;
|
||||
parent = r_owner.group;
|
||||
group = CreatePopupMenu();
|
||||
caption = strdup(_caption);
|
||||
owner->attach(*this);
|
||||
}
|
||||
|
||||
void MenuGroup::finish() {
|
||||
AppendMenu(parent, MF_STRING | MF_POPUP, (uint)group, caption);
|
||||
}
|
||||
|
||||
/*****
|
||||
* MenuItem
|
||||
*****/
|
||||
|
||||
void MenuItem::create(MenuGroup &r_owner, const char *caption) {
|
||||
type = ControlType::MenuItem;
|
||||
owner = r_owner.owner;
|
||||
owner->attach(*this);
|
||||
AppendMenu(r_owner.group, MF_STRING, (uint)id, caption);
|
||||
}
|
||||
|
||||
/*****
|
||||
* MenuCheckItem
|
||||
*****/
|
||||
|
||||
void MenuCheckItem::create(MenuGroup &r_owner, const char *caption) {
|
||||
type = ControlType::MenuCheckItem;
|
||||
owner = r_owner.owner;
|
||||
parent = r_owner.group;
|
||||
owner->attach(*this);
|
||||
AppendMenu(r_owner.group, MF_STRING, (uint)id, caption);
|
||||
}
|
||||
|
||||
void MenuCheckItem::check() {
|
||||
if(checked() == true)return;
|
||||
CheckMenuItem(parent, id, MF_CHECKED);
|
||||
owner->message(Message::Clicked, (uintptr_t)this);
|
||||
}
|
||||
|
||||
void MenuCheckItem::uncheck() {
|
||||
if(checked() == false)return;
|
||||
CheckMenuItem(parent, id, MF_UNCHECKED);
|
||||
owner->message(Message::Clicked, (uintptr_t)this);
|
||||
}
|
||||
|
||||
void MenuCheckItem::check(bool state) {
|
||||
(state == true) ? check() : uncheck();
|
||||
}
|
||||
|
||||
bool MenuCheckItem::checked() {
|
||||
MENUITEMINFO info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.cbSize = sizeof(info);
|
||||
info.fMask = MIIM_STATE;
|
||||
GetMenuItemInfo(parent, id, false, &info);
|
||||
return (info.fState & MFS_CHECKED);
|
||||
}
|
||||
|
||||
/*****
|
||||
* MenuRadioItem
|
||||
*****/
|
||||
|
||||
void MenuRadioItem::create(MenuGroup &r_owner, ControlGroup &list, const char *caption) {
|
||||
if(list.count() == 0)throw;
|
||||
type = ControlType::MenuRadioItem;
|
||||
owner = r_owner.owner;
|
||||
parent = r_owner.group;
|
||||
owner->attach(*this);
|
||||
AppendMenu(r_owner.group, MF_STRING, (uint)id, caption);
|
||||
group = list;
|
||||
if(&group[0] == this) { owner->info.menu_check_list[owner->info.menu_check_list.size()] = this; }
|
||||
}
|
||||
|
||||
void MenuRadioItem::check() {
|
||||
if(checked() == true)return;
|
||||
//uncheck all items in group except for current item ...
|
||||
for(uint i = 0; i < group.count(); i++) {
|
||||
CheckMenuItem(parent, group[i].id, (id == group[i].id) ? MF_CHECKED : MF_UNCHECKED);
|
||||
}
|
||||
owner->message(Message::Clicked, (uintptr_t)this);
|
||||
}
|
||||
|
||||
bool MenuRadioItem::checked() {
|
||||
MENUITEMINFO info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.cbSize = sizeof(info);
|
||||
info.fMask = MIIM_STATE;
|
||||
GetMenuItemInfo(parent, id, false, &info);
|
||||
return (info.fState & MFS_CHECKED);
|
||||
}
|
||||
|
||||
/*****
|
||||
* MenuSeparator
|
||||
*****/
|
||||
|
||||
void MenuSeparator::create(MenuGroup &r_owner) {
|
||||
AppendMenu(r_owner.group, MF_SEPARATOR, 0, "");
|
||||
}
|
||||
|
||||
/*****
|
||||
* Panel
|
||||
*****/
|
||||
|
||||
void Panel::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) {
|
||||
type = ControlType::Panel;
|
||||
hwnd = CreateWindow("libui_class", "", WS_CHILD | WS_VISIBLE,
|
||||
x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0);
|
||||
r_owner.attach(*this);
|
||||
}
|
||||
|
||||
void Panel::attach(Window &window) {
|
||||
if(attached) { detach(); }
|
||||
attached = &window;
|
||||
SetParent(attached->info.hwnd, hwnd);
|
||||
SetWindowLong(attached->info.hwnd, GWL_STYLE, WS_CHILD);
|
||||
SetWindowPos(attached->info.hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOSIZE);
|
||||
ShowWindow(attached->info.hwnd, SW_NORMAL);
|
||||
}
|
||||
|
||||
void Panel::detach() {
|
||||
if(!attached) { return; }
|
||||
ShowWindow(attached->info.hwnd, SW_HIDE);
|
||||
SetWindowLong(attached->info.hwnd, GWL_STYLE, WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX);
|
||||
SetParent(attached->info.hwnd, NULL);
|
||||
attached = 0;
|
||||
}
|
||||
|
||||
/*****
|
||||
* Container
|
||||
*****/
|
||||
|
||||
void Container::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) {
|
||||
type = ControlType::Container;
|
||||
|
||||
char classname[4096];
|
||||
sprintf(classname, "libui_class_%d", window_count++);
|
||||
WNDCLASS wc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
|
||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = libui_wndproc;
|
||||
wc.lpszClassName = classname;
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
|
||||
RegisterClass(&wc);
|
||||
|
||||
hwnd = CreateWindow(classname, "", WS_CHILD | WS_VISIBLE,
|
||||
0, 0, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0);
|
||||
}
|
||||
|
||||
void Container::set_background_color(uint8 r, uint8 g, uint8 b) {
|
||||
HBRUSH old_brush = background;
|
||||
background = (HBRUSH)CreateSolidBrush(RGB(r, g, b));
|
||||
SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG)background);
|
||||
InvalidateRect(hwnd, 0, TRUE);
|
||||
if(old_brush) { DeleteObject((HGDIOBJ)old_brush); }
|
||||
}
|
||||
|
||||
HWND Container::handle() {
|
||||
return hwnd;
|
||||
}
|
||||
|
||||
Container::Container() {
|
||||
background = 0;
|
||||
}
|
||||
|
||||
/*****
|
||||
* Canvas
|
||||
*****/
|
||||
|
||||
long __stdcall canvas_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
switch(msg) {
|
||||
|
||||
case WM_PAINT: {
|
||||
Canvas *canvas = (Canvas*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
if(canvas) { canvas->blit(); }
|
||||
} break;
|
||||
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
void Canvas::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) {
|
||||
_w = width;
|
||||
_h = height;
|
||||
|
||||
type = ControlType::Canvas;
|
||||
hwnd = CreateWindow("canvas_class", "", WS_CHILD | WS_VISIBLE,
|
||||
x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0);
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
|
||||
|
||||
pitch = width * sizeof(uint32);
|
||||
buffer = (uint32*)malloc(pitch * height);
|
||||
memset(buffer, 0, pitch * height);
|
||||
|
||||
memset(&bmi, 0, sizeof(BITMAPINFO));
|
||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.bmiHeader.biWidth = width;
|
||||
bmi.bmiHeader.biHeight = -height; //use negative height to tell GDI not to flip bitmap vertically
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biBitCount = 32;
|
||||
bmi.bmiHeader.biCompression = BI_RGB;
|
||||
bmi.bmiHeader.biSizeImage = pitch * height;
|
||||
|
||||
r_owner.attach(*this);
|
||||
}
|
||||
|
||||
void Canvas::blit() {
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint(hwnd, &ps);
|
||||
SetDIBitsToDevice(ps.hdc, 0, 0, _w, _h, 0, 0, 0, _h, (void*)buffer, &bmi, DIB_RGB_COLORS);
|
||||
EndPaint(hwnd, &ps);
|
||||
}
|
||||
|
||||
void Canvas::redraw() {
|
||||
InvalidateRect(hwnd, 0, FALSE);
|
||||
}
|
||||
|
||||
Canvas::Canvas() {
|
||||
buffer = 0;
|
||||
}
|
||||
|
||||
Canvas::~Canvas() {
|
||||
safe_free(buffer);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Frame
|
||||
*****/
|
||||
|
||||
void Frame::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) {
|
||||
type = ControlType::Frame;
|
||||
hwnd = CreateWindow("BUTTON", caption ? caption : "", WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
|
||||
x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)libui::font.variable, 0);
|
||||
r_owner.attach(*this);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Label
|
||||
*****/
|
||||
|
||||
long __stdcall label_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
switch(msg) {
|
||||
|
||||
case WM_PAINT: {
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint(hwnd, &ps);
|
||||
RECT rc;
|
||||
char t[4096];
|
||||
GetWindowText(hwnd, t, 4095); //TODO: use internal buffer, so length is not limited ...
|
||||
GetClientRect(hwnd, &rc);
|
||||
SetTextColor(ps.hdc, RGB(0, 0, 0));
|
||||
SetBkMode(ps.hdc, TRANSPARENT);
|
||||
SelectObject(ps.hdc, (HGDIOBJ)libui::font.variable);
|
||||
//center text if text height < control height, otherwise draw from top left corner
|
||||
RECT trc;
|
||||
GetClientRect(hwnd, &trc);
|
||||
DrawText(ps.hdc, t, strlen(t), &trc, DT_CALCRECT);
|
||||
if(trc.bottom < rc.bottom) {
|
||||
rc.top = (rc.bottom - trc.bottom) / 2;
|
||||
rc.bottom = rc.top + trc.bottom;
|
||||
}
|
||||
//
|
||||
DrawText(ps.hdc, t, strlen(t), &rc, DT_END_ELLIPSIS | DT_NOPREFIX);
|
||||
EndPaint(hwnd, &ps);
|
||||
} break;
|
||||
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
void Label::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) {
|
||||
string t;
|
||||
strcpy(t, caption ? caption : "");
|
||||
replace(t, "\r", "");
|
||||
replace(t, "\n", "\r\n");
|
||||
|
||||
type = ControlType::Label;
|
||||
hwnd = CreateWindow("label_class", strptr(t), WS_CHILD | WS_VISIBLE,
|
||||
x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)libui::font.variable, 0);
|
||||
r_owner.attach(*this);
|
||||
}
|
||||
|
||||
void Label::set_text(const char *str, ...) {
|
||||
va_list args;
|
||||
va_start(args, str);
|
||||
string temp;
|
||||
vsprintf(temp, str, args);
|
||||
va_end(args);
|
||||
SetWindowText(hwnd, strptr(temp));
|
||||
InvalidateRect(hwnd, 0, TRUE);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Button
|
||||
*****/
|
||||
|
||||
void Button::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) {
|
||||
type = ControlType::Button;
|
||||
hwnd = CreateWindow("BUTTON", caption ? caption : "", WS_CHILD | WS_VISIBLE,
|
||||
x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)libui::font.variable, 0);
|
||||
r_owner.attach(*this);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Checkbox
|
||||
*****/
|
||||
|
||||
void Checkbox::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) {
|
||||
type = ControlType::Checkbox;
|
||||
hwnd = CreateWindow("BUTTON", caption ? caption : "", WS_CHILD | WS_VISIBLE | BS_CHECKBOX,
|
||||
x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)libui::font.variable, 0);
|
||||
r_owner.attach(*this);
|
||||
}
|
||||
|
||||
void Checkbox::check() {
|
||||
if(checked() == true)return;
|
||||
SendMessage(hwnd, BM_SETCHECK, (WPARAM)TRUE, 0);
|
||||
owner->message(Message::Clicked, (uintptr_t)this);
|
||||
}
|
||||
|
||||
void Checkbox::uncheck() {
|
||||
if(checked() == false)return;
|
||||
SendMessage(hwnd, BM_SETCHECK, (WPARAM)FALSE, 0);
|
||||
owner->message(Message::Clicked, (uintptr_t)this);
|
||||
}
|
||||
|
||||
void Checkbox::check(bool state) {
|
||||
(state == true) ? check() : uncheck();
|
||||
}
|
||||
|
||||
bool Checkbox::checked() {
|
||||
return SendMessage(hwnd, BM_GETCHECK, 0, 0);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Radiobox
|
||||
*****/
|
||||
|
||||
void Radiobox::create(Window &r_owner, ControlGroup &list, uint style, uint x, uint y, uint width, uint height, const char *caption) {
|
||||
if(list.count() == 0)throw;
|
||||
type = ControlType::Radiobox;
|
||||
group = list;
|
||||
hwnd = CreateWindow("BUTTON", caption ? caption : "", WS_CHILD | WS_VISIBLE | BS_RADIOBUTTON,
|
||||
x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)libui::font.variable, 0);
|
||||
r_owner.attach(*this);
|
||||
if(this == &group[0])check();
|
||||
}
|
||||
|
||||
void Radiobox::check() {
|
||||
if(checked() == true)return;
|
||||
for(uint i = 0; i < group.count(); i++) {
|
||||
SendMessage(group[i].hwnd, BM_SETCHECK, (group[i].hwnd == hwnd) ? (WPARAM)TRUE : (WPARAM)FALSE, 0);
|
||||
}
|
||||
owner->message(Message::Clicked, (uintptr_t)this);
|
||||
}
|
||||
|
||||
bool Radiobox::checked() {
|
||||
return SendMessage(hwnd, BM_GETCHECK, 0, 0);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Editbox
|
||||
*****/
|
||||
|
||||
void Editbox::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) {
|
||||
type = ControlType::Editbox;
|
||||
multiline = (style & Multiline);
|
||||
readonly = (style & Readonly);
|
||||
vscroll = false;
|
||||
hscroll = false;
|
||||
|
||||
uint hscroll = (style & HorizontalScrollAlways) ? WS_HSCROLL :
|
||||
(style & HorizontalScrollNever) ? 0 :
|
||||
ES_AUTOHSCROLL;
|
||||
uint vscroll = (style & VerticalScrollAlways) ? WS_VSCROLL :
|
||||
(style & VerticalScrollNever) ? 0 :
|
||||
ES_AUTOVSCROLL;
|
||||
|
||||
string data = caption;
|
||||
replace(data, "\r", "");
|
||||
replace(data, "\n", "\r\n");
|
||||
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", strptr(data),
|
||||
WS_CHILD | WS_VISIBLE | vscroll | hscroll |
|
||||
(multiline == true ? ES_MULTILINE : 0) |
|
||||
(readonly == true ? ES_READONLY : 0),
|
||||
x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)libui::font.variable, 0);
|
||||
r_owner.attach(*this);
|
||||
}
|
||||
|
||||
void Editbox::set_text(const char *str, ...) {
|
||||
va_list args;
|
||||
va_start(args, str);
|
||||
string data;
|
||||
vsprintf(data, str, args);
|
||||
va_end(args);
|
||||
|
||||
replace(data, "\r", "");
|
||||
replace(data, "\n", "\r\n");
|
||||
SetWindowText(hwnd, strptr(data));
|
||||
}
|
||||
|
||||
uint Editbox::get_text(char *str, uint length) {
|
||||
GetWindowText(hwnd, str, length);
|
||||
return strlen(str);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Listbox
|
||||
*****/
|
||||
|
||||
void Listbox::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *columns) {
|
||||
stringarray part;
|
||||
header = (style & Header);
|
||||
|
||||
uint hscroll = (style & HorizontalScrollAlways) ? WS_HSCROLL :
|
||||
(style & HorizontalScrollNever) ? 0 :
|
||||
0;
|
||||
uint vscroll = (style & VerticalScrollAlways) ? WS_VSCROLL :
|
||||
(style & VerticalScrollNever) ? 0 :
|
||||
0;
|
||||
|
||||
type = ControlType::Listbox;
|
||||
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, "",
|
||||
WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | vscroll | hscroll |
|
||||
(header == true ? 0 : LVS_NOCOLUMNHEADER),
|
||||
x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)libui::font.variable, 0);
|
||||
ListView_SetExtendedListViewStyle(hwnd, LVS_EX_FULLROWSELECT);
|
||||
|
||||
split(part, "|", columns);
|
||||
column_count = count(part);
|
||||
for(uint i = 0; i < column_count; i++) {
|
||||
LVCOLUMN column;
|
||||
column.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM;
|
||||
column.fmt = LVCFMT_LEFT;
|
||||
column.iSubItem = count(part);
|
||||
column.pszText = (LPSTR)strptr(part[i]);
|
||||
ListView_InsertColumn(hwnd, i, &column);
|
||||
}
|
||||
|
||||
autosize_columns();
|
||||
r_owner.attach(*this);
|
||||
}
|
||||
|
||||
void Listbox::autosize_columns() {
|
||||
for(uint i = 0; i < column_count; i++) {
|
||||
ListView_SetColumnWidth(hwnd, i, LVSCW_AUTOSIZE_USEHEADER);
|
||||
}
|
||||
}
|
||||
|
||||
void Listbox::set_column_width(uint column, uint width) {
|
||||
ListView_SetColumnWidth(hwnd, column, width);
|
||||
}
|
||||
|
||||
void Listbox::add_item(const char *data, ...) {
|
||||
va_list args;
|
||||
va_start(args, data);
|
||||
string temp;
|
||||
vsprintf(temp, data, args);
|
||||
va_end(args);
|
||||
|
||||
stringarray part;
|
||||
split(part, "|", temp);
|
||||
|
||||
LVITEM item;
|
||||
uint pos = ListView_GetItemCount(hwnd);
|
||||
item.mask = LVIF_TEXT;
|
||||
item.iItem = pos;
|
||||
item.iSubItem = 0;
|
||||
item.pszText = (LPSTR)strptr(part[0]);
|
||||
ListView_InsertItem(hwnd, &item);
|
||||
|
||||
for(uint i = 1; i < count(part); i++) {
|
||||
ListView_SetItemText(hwnd, pos, i, (LPSTR)strptr(part[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void Listbox::set_item(uint index, const char *data, ...) {
|
||||
va_list args;
|
||||
va_start(args, data);
|
||||
string temp;
|
||||
vsprintf(temp, data, args);
|
||||
va_end(args);
|
||||
|
||||
stringarray part;
|
||||
split(part, "|", temp);
|
||||
|
||||
for(uint i = 0; i < count(part); i++) {
|
||||
ListView_SetItemText(hwnd, index, i, strptr(part[i]));
|
||||
}
|
||||
}
|
||||
|
||||
int Listbox::get_selection() {
|
||||
uint count = ListView_GetItemCount(hwnd);
|
||||
for(uint i = 0; i < count; i++) {
|
||||
if(ListView_GetItemState(hwnd, i, LVIS_SELECTED))return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Listbox::set_selection(int index) {
|
||||
uint count = ListView_GetItemCount(hwnd);
|
||||
for(uint i = 0; i < count; i++) {
|
||||
ListView_SetItemState(hwnd, i, LVIS_FOCUSED, (i == index) ? LVIS_FOCUSED : 0);
|
||||
ListView_SetItemState(hwnd, i, LVIS_SELECTED, (i == index) ? LVIS_SELECTED : 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Listbox::reset() {
|
||||
ListView_DeleteAllItems(hwnd);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Combobox
|
||||
*****/
|
||||
|
||||
void Combobox::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) {
|
||||
type = ControlType::Combobox;
|
||||
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "COMBOBOX", "",
|
||||
WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
|
||||
x, y, width, 200, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)libui::font.variable, 0);
|
||||
r_owner.attach(*this);
|
||||
}
|
||||
|
||||
void Combobox::add_item(const char *data) {
|
||||
SendMessage(hwnd, CB_ADDSTRING, 0, (LPARAM)data);
|
||||
if(SendMessage(hwnd, CB_GETCOUNT, 0, 0) == 1) { set_selection(0); }
|
||||
}
|
||||
|
||||
void Combobox::set_selection(int index) {
|
||||
SendMessage(hwnd, CB_SETCURSEL, index, 0);
|
||||
}
|
||||
|
||||
int Combobox::get_selection() {
|
||||
return SendMessage(hwnd, CB_GETCURSEL, 0, 0);
|
||||
}
|
||||
|
||||
void Combobox::reset() {
|
||||
SendMessage(hwnd, CB_RESETCONTENT, 0, 0);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Progressbar
|
||||
*****/
|
||||
|
||||
void Progressbar::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) {
|
||||
type = ControlType::Progressbar;
|
||||
hwnd = CreateWindow(PROGRESS_CLASS, "", WS_CHILD | WS_VISIBLE | PBS_SMOOTH,
|
||||
x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
|
||||
SendMessage(hwnd, PBM_SETSTEP, MAKEWPARAM(1, 0), 0);
|
||||
r_owner.attach(*this);
|
||||
}
|
||||
|
||||
void Progressbar::set_progress(uint progress) {
|
||||
progress = minmax<0, 100>(progress);
|
||||
SendMessage(hwnd, PBM_SETPOS, (WPARAM)progress, 0);
|
||||
}
|
||||
|
||||
uint Progressbar::get_progress() {
|
||||
return minmax<0, 100>(SendMessage(hwnd, PBM_GETPOS, 0, 0));
|
||||
}
|
||||
|
||||
/*****
|
||||
* Slider
|
||||
*****/
|
||||
|
||||
void Slider::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, uint range) {
|
||||
type = ControlType::Slider;
|
||||
orientation = (style & Vertical) ? 1 : 0;
|
||||
if(range < 1)range = 1;
|
||||
|
||||
hwnd = CreateWindow(TRACKBAR_CLASS, "",
|
||||
WS_CHILD | WS_VISIBLE | TBS_NOTICKS | TBS_BOTH | (orientation == 0 ? TBS_HORZ : TBS_VERT),
|
||||
x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, TBM_SETRANGE, (WPARAM)true, (LPARAM)MAKELONG(0, range - 1));
|
||||
SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM)(range >> 3));
|
||||
SendMessage(hwnd, TBM_SETPOS, (WPARAM)true, (LPARAM)0);
|
||||
r_owner.attach(*this);
|
||||
}
|
||||
|
||||
void Slider::set_position(uint position) {
|
||||
SendMessage(hwnd, TBM_SETPOS, (WPARAM)true, (LPARAM)position);
|
||||
}
|
||||
|
||||
uint Slider::get_position() {
|
||||
return SendMessage(hwnd, TBM_GETPOS, 0, 0);
|
||||
}
|
||||
|
||||
};
|
||||
@@ -0,0 +1,271 @@
|
||||
namespace ControlType {
|
||||
enum {
|
||||
Invalid,
|
||||
MenuBar,
|
||||
MenuGroup,
|
||||
MenuItem,
|
||||
MenuCheckItem,
|
||||
MenuRadioItem,
|
||||
MenuSeparator,
|
||||
Panel,
|
||||
Container,
|
||||
Canvas,
|
||||
Frame,
|
||||
Label,
|
||||
Button,
|
||||
Checkbox,
|
||||
Radiobox,
|
||||
Editbox,
|
||||
Listbox,
|
||||
Combobox,
|
||||
Progressbar,
|
||||
Slider,
|
||||
};
|
||||
};
|
||||
|
||||
class Control { public:
|
||||
uint type;
|
||||
void move(uint x, uint y);
|
||||
void resize(uint width, uint height);
|
||||
|
||||
void focus();
|
||||
|
||||
virtual void show();
|
||||
virtual void hide();
|
||||
virtual void show(bool state);
|
||||
virtual bool visible();
|
||||
|
||||
void enable();
|
||||
void disable();
|
||||
void enable(bool state);
|
||||
bool enabled();
|
||||
|
||||
//private:
|
||||
Window *owner;
|
||||
HWND hwnd;
|
||||
uint id;
|
||||
|
||||
public:
|
||||
Control() : owner(0), hwnd(0), id(0), type(ControlType::Invalid) {}
|
||||
};
|
||||
|
||||
class ControlGroup { public:
|
||||
uint count() { return list.size(); }
|
||||
void add(Control &control) { list[list.size()] = &control; }
|
||||
void reset() { list.reset(); }
|
||||
ControlGroup &operator=(ControlGroup &source) { list = source.list; return *this; }
|
||||
Control &operator[](int index) { return *list[index]; }
|
||||
|
||||
//private:
|
||||
array<Control*> list;
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
class MenuBar : public Control { public:
|
||||
void create(Window &owner);
|
||||
void finish();
|
||||
|
||||
void show();
|
||||
void hide();
|
||||
void show(bool state);
|
||||
bool visible();
|
||||
|
||||
//private:
|
||||
HMENU group;
|
||||
};
|
||||
|
||||
class MenuGroup : public Control { public:
|
||||
void create(MenuBar &owner, const char *caption);
|
||||
void create(MenuGroup &owner, const char *caption);
|
||||
void finish();
|
||||
|
||||
//private:
|
||||
HMENU parent, group;
|
||||
char *caption;
|
||||
~MenuGroup() { safe_free(caption); }
|
||||
};
|
||||
|
||||
class MenuItem : public Control { public:
|
||||
void create(MenuGroup &owner, const char *caption);
|
||||
};
|
||||
|
||||
class MenuCheckItem : public Control { public:
|
||||
void create(MenuGroup &owner, const char *caption);
|
||||
void check();
|
||||
void uncheck();
|
||||
void check(bool state);
|
||||
bool checked();
|
||||
|
||||
//private:
|
||||
HMENU parent;
|
||||
};
|
||||
|
||||
class MenuRadioItem : public Control { public:
|
||||
void create(MenuGroup &owner, ControlGroup &list, const char *caption);
|
||||
void check();
|
||||
bool checked();
|
||||
|
||||
//private:
|
||||
HMENU parent;
|
||||
ControlGroup group;
|
||||
};
|
||||
|
||||
class MenuSeparator : public Control { public:
|
||||
void create(MenuGroup &owner);
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
class Panel : public Control { public:
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height);
|
||||
void attach(Window &window);
|
||||
void detach();
|
||||
|
||||
//private:
|
||||
Window *attached;
|
||||
Panel() : attached(0) {}
|
||||
};
|
||||
|
||||
class Container : public Control { public:
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height);
|
||||
void set_background_color(uint8 r, uint8 g, uint8 b);
|
||||
|
||||
//platform-dependent:
|
||||
HWND handle();
|
||||
|
||||
//private:
|
||||
HBRUSH background;
|
||||
Container();
|
||||
};
|
||||
|
||||
class Canvas : public Control { public:
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height);
|
||||
void redraw();
|
||||
|
||||
//private:
|
||||
BITMAPINFO bmi;
|
||||
uint32 *buffer;
|
||||
uint pitch, _w, _h;
|
||||
void blit();
|
||||
Canvas();
|
||||
~Canvas();
|
||||
};
|
||||
|
||||
class Frame : public Control { public:
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
};
|
||||
|
||||
class Label : public Control { public:
|
||||
enum { ideal_height = 16 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
void set_text(const char *str, ...);
|
||||
};
|
||||
|
||||
class Button : public Control { public:
|
||||
enum { ideal_height = 21 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
};
|
||||
|
||||
class Checkbox : public Control { public:
|
||||
enum { ideal_height = 15 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
void check();
|
||||
void uncheck();
|
||||
void check(bool state);
|
||||
bool checked();
|
||||
};
|
||||
|
||||
class Radiobox : public Control { public:
|
||||
enum { ideal_height = 15 };
|
||||
void create(Window &owner, ControlGroup &list, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
void check();
|
||||
bool checked();
|
||||
|
||||
//private:
|
||||
ControlGroup group;
|
||||
};
|
||||
|
||||
class Editbox : public Control { public:
|
||||
enum { ideal_height = 21 };
|
||||
enum {
|
||||
Multiline = (1 << 1),
|
||||
Readonly = (1 << 2),
|
||||
|
||||
HorizontalScrollAuto = 0,
|
||||
HorizontalScrollAlways = (1 << 3),
|
||||
HorizontalScrollNever = (1 << 4),
|
||||
|
||||
VerticalScrollAuto = 0,
|
||||
VerticalScrollAlways = (1 << 5),
|
||||
VerticalScrollNever = (1 << 6),
|
||||
};
|
||||
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
void set_text(const char *str, ...);
|
||||
uint get_text(char *str, uint length);
|
||||
|
||||
//private:
|
||||
bool multiline;
|
||||
bool readonly;
|
||||
bool vscroll;
|
||||
bool hscroll;
|
||||
};
|
||||
|
||||
class Listbox : public Control { public:
|
||||
enum {
|
||||
Header = (1 << 1),
|
||||
|
||||
HorizontalScrollAuto = 0,
|
||||
HorizontalScrollAlways = (1 << 2),
|
||||
HorizontalScrollNever = (1 << 3),
|
||||
|
||||
VerticalScrollAuto = 0,
|
||||
VerticalScrollAlways = (1 << 4),
|
||||
VerticalScrollNever = (1 << 5),
|
||||
};
|
||||
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *columns = "");
|
||||
void autosize_columns();
|
||||
void set_column_width(uint column, uint width);
|
||||
void add_item(const char *data, ...);
|
||||
void set_item(uint index, const char *data, ...);
|
||||
int get_selection();
|
||||
void set_selection(int index);
|
||||
void reset();
|
||||
|
||||
//private:
|
||||
bool header;
|
||||
uint column_count;
|
||||
};
|
||||
|
||||
class Combobox : public Control { public:
|
||||
enum { ideal_height = 21 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height);
|
||||
void add_item(const char *data);
|
||||
void set_selection(int index);
|
||||
int get_selection();
|
||||
void reset();
|
||||
};
|
||||
|
||||
class Progressbar : public Control { public:
|
||||
enum { ideal_height = 30 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height);
|
||||
void set_progress(uint progress);
|
||||
uint get_progress();
|
||||
};
|
||||
|
||||
class Slider : public Control { public:
|
||||
enum { ideal_height = 25 };
|
||||
enum Style {
|
||||
Horizontal = 0,
|
||||
Vertical = 1,
|
||||
};
|
||||
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, uint range);
|
||||
void set_position(uint position);
|
||||
uint get_position();
|
||||
|
||||
//private:
|
||||
bool orientation;
|
||||
};
|
||||
@@ -0,0 +1,290 @@
|
||||
namespace libui {
|
||||
|
||||
long __stdcall libui_wndproc(HWND hwnd, uint msg, WPARAM wparam, LPARAM lparam) {
|
||||
Window *window = reinterpret_cast<Window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
|
||||
if(window) { return window->wndproc(hwnd, msg, wparam, lparam); }
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
long Window::wndproc(HWND hwnd, uint msg, WPARAM wparam, LPARAM lparam) {
|
||||
switch(msg) {
|
||||
|
||||
case WM_CLOSE: {
|
||||
if(message(Message::Close) == false) { return TRUE; }
|
||||
} break;
|
||||
|
||||
case WM_ENTERMENULOOP: {
|
||||
message(Message::Block);
|
||||
}
|
||||
|
||||
case WM_PAINT: {
|
||||
uint16 i = LOWORD(wparam);
|
||||
if(!i || !info.control[i])break;
|
||||
Control &control = *info.control[i];
|
||||
if(control.id != i)break; //this should never happen
|
||||
|
||||
switch(control.type) {
|
||||
|
||||
case ControlType::Canvas: {
|
||||
((Canvas&)control).redraw();
|
||||
} break;
|
||||
|
||||
}
|
||||
} break;
|
||||
|
||||
case WM_KEYDOWN: {
|
||||
message(Message::KeyDown, libui::translate_key(wparam));
|
||||
} break;
|
||||
|
||||
case WM_KEYUP: {
|
||||
message(Message::KeyUp, libui::translate_key(wparam));
|
||||
} break;
|
||||
|
||||
case WM_COMMAND: {
|
||||
uint16 i = LOWORD(wparam);
|
||||
if(!i || !info.control[i])break;
|
||||
Control &control = *info.control[i];
|
||||
if(control.id != i)break; //this should never happen
|
||||
|
||||
switch(control.type) {
|
||||
|
||||
//emit Message::Clicked message indirectly, through control.check()
|
||||
case ControlType::MenuCheckItem: {
|
||||
((MenuCheckItem&)control).check(!((MenuCheckItem&)control).checked()); //toggle checked status
|
||||
} break;
|
||||
|
||||
case ControlType::MenuRadioItem: {
|
||||
((MenuRadioItem&)control).check();
|
||||
} break;
|
||||
|
||||
case ControlType::Checkbox: {
|
||||
((Checkbox&)control).check(!((Checkbox&)control).checked()); //toggle checked status
|
||||
} break;
|
||||
|
||||
case ControlType::Radiobox: {
|
||||
((Radiobox&)control).check();
|
||||
} break;
|
||||
|
||||
//emit Message::Clicked message directly
|
||||
case ControlType::MenuItem:
|
||||
case ControlType::Button: {
|
||||
message(Message::Clicked, (uintptr_t)&control);
|
||||
} break;
|
||||
|
||||
}
|
||||
} break;
|
||||
|
||||
case WM_HSCROLL:
|
||||
case WM_VSCROLL: {
|
||||
uint16 i = GetDlgCtrlID((HWND)lparam);
|
||||
if(!i || !info.control[i])break;
|
||||
Control &control = *info.control[i];
|
||||
if(control.id != i)break;
|
||||
|
||||
switch(control.type) {
|
||||
|
||||
case ControlType::Slider: {
|
||||
message(Message::Changed, (uintptr_t)&control);
|
||||
} break;
|
||||
|
||||
}
|
||||
} break;
|
||||
|
||||
case WM_NOTIFY: {
|
||||
uint16 i = (uint16)wparam;
|
||||
if(!i || !info.control[i])break;
|
||||
Control &control = *info.control[i];
|
||||
if(control.id != i)break;
|
||||
|
||||
switch(control.type) {
|
||||
|
||||
case ControlType::Listbox: {
|
||||
Listbox &listbox = ((Listbox&)control);
|
||||
if(((LPNMHDR)lparam)->code == LVN_ITEMCHANGED) {
|
||||
if(((LPNMLISTVIEW)lparam)->uChanged & LVIF_STATE) {
|
||||
if(ListView_GetItemState(listbox.hwnd, ((LPNMLISTVIEW)lparam)->iItem, LVIS_FOCUSED)) {
|
||||
if(ListView_GetItemState(listbox.hwnd, ((LPNMLISTVIEW)lparam)->iItem, LVIS_SELECTED)) {
|
||||
message(Message::Changed, (uintptr_t)&control);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(((LPNMHDR)lparam)->code == LVN_ITEMACTIVATE) {
|
||||
message(Message::DoubleClicked, (uintptr_t)&control);
|
||||
}
|
||||
} break;
|
||||
|
||||
}
|
||||
} break;
|
||||
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
void Window::attach(Control &control) {
|
||||
info.control[info.control_index] = &control;
|
||||
control.id = info.control_index++;
|
||||
control.owner = this;
|
||||
|
||||
//menu items will not have HWND, and do not require GWL_ID to be set
|
||||
if(control.hwnd) { SetWindowLong(control.hwnd, GWL_ID, control.id); }
|
||||
}
|
||||
|
||||
void Window::focus() {
|
||||
if(!visible()) { show(); }
|
||||
SetFocus(info.hwnd);
|
||||
}
|
||||
|
||||
bool Window::focused() {
|
||||
return (GetForegroundWindow() == info.hwnd);
|
||||
}
|
||||
|
||||
void Window::move(Control &control, uint x, uint y) {
|
||||
SetWindowPos(control.hwnd, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
|
||||
}
|
||||
|
||||
void Window::create(uint style, uint width, uint height, const char *caption) {
|
||||
info.center = bool(style & Center);
|
||||
|
||||
char classname[4096];
|
||||
sprintf(classname, "libui_class_%d", window_count++);
|
||||
WNDCLASS wc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
|
||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = libui_wndproc;
|
||||
wc.lpszClassName = classname;
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&wc);
|
||||
|
||||
RECT rc;
|
||||
SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
|
||||
|
||||
info.hwnd = CreateWindowEx(0, classname, caption ? caption : "",
|
||||
WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
|
||||
rc.left, rc.top, width, height, 0, 0, GetModuleHandle(0), 0);
|
||||
info.hwnd_resize = CreateWindowEx(0, "libui_class", "",
|
||||
WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
|
||||
rc.left, rc.top, width, height, 0, 0, GetModuleHandle(0), 0);
|
||||
SetWindowLongPtr(info.hwnd, GWLP_USERDATA, (LONG_PTR)this);
|
||||
|
||||
resize(width, height);
|
||||
}
|
||||
|
||||
void Window::move(uint x, uint y) {
|
||||
RECT rc;
|
||||
SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
|
||||
if(x < rc.left) { x = rc.left; }
|
||||
if(y < rc.top ) { y = rc.top; }
|
||||
SetWindowPos(info.hwnd, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
|
||||
}
|
||||
|
||||
void Window::resize(uint width, uint height) {
|
||||
if(info.fullscreen == true) {
|
||||
info.width = GetSystemMetrics(SM_CXSCREEN);
|
||||
info.height = GetSystemMetrics(SM_CYSCREEN);
|
||||
SetWindowPos(info.hwnd, 0, 0, 0, info.width, info.height, SWP_NOZORDER);
|
||||
return;
|
||||
}
|
||||
|
||||
info.width = width;
|
||||
info.height = height;
|
||||
|
||||
//set requested window size to hidden window, calculate the difference between requested and actual client
|
||||
//size area, and then adjust width so that new width, height values will set requested client area size.
|
||||
//AdjustWindowRect() does not properly calculate the height of multi-line menus, and thusly is not used.
|
||||
SetWindowPos(info.hwnd_resize, 0, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE);
|
||||
RECT rc;
|
||||
GetClientRect(info.hwnd_resize, &rc);
|
||||
width += width - (rc.right - rc.left);
|
||||
height += height - (rc.bottom - rc.top);
|
||||
|
||||
int x = (GetSystemMetrics(SM_CXSCREEN) - int(width)) / 2;
|
||||
int y = (GetSystemMetrics(SM_CYSCREEN) - int(height)) / 2;
|
||||
|
||||
//do not allow window to be placed offscreen, force to top-left if window is larger than screen size
|
||||
SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
|
||||
if(x < rc.left) { x = rc.left; }
|
||||
if(y < rc.top) { y = rc.top; }
|
||||
|
||||
SetWindowPos(info.hwnd, 0, x, y, width, height, SWP_NOZORDER | (info.center == true ? 0 : SWP_NOMOVE));
|
||||
}
|
||||
|
||||
void Window::show() {
|
||||
ShowWindow(info.hwnd, SW_NORMAL);
|
||||
SetFocus(info.hwnd);
|
||||
}
|
||||
|
||||
void Window::hide() {
|
||||
ShowWindow(info.hwnd, SW_HIDE);
|
||||
}
|
||||
|
||||
void Window::show(bool state) {
|
||||
(state == true) ? show() : hide();
|
||||
}
|
||||
|
||||
bool Window::visible() {
|
||||
return GetWindowLong(info.hwnd, GWL_STYLE) & WS_VISIBLE;
|
||||
}
|
||||
|
||||
void Window::fullscreen() {
|
||||
if(info.fullscreen)return;
|
||||
info.fullscreen = true;
|
||||
SetWindowLong(info.hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
|
||||
resize(get_screen_width(), get_screen_height());
|
||||
}
|
||||
|
||||
void Window::unfullscreen() {
|
||||
if(!info.fullscreen)return;
|
||||
info.fullscreen = false;
|
||||
SetWindowLong(info.hwnd, GWL_STYLE, WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_VISIBLE);
|
||||
resize(info.width, info.height);
|
||||
}
|
||||
|
||||
void Window::fullscreen(bool state) {
|
||||
(state == true) ? fullscreen() : unfullscreen();
|
||||
}
|
||||
|
||||
bool Window::is_fullscreen() {
|
||||
return info.fullscreen;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void Window::set_text(const char *str, ...) {
|
||||
va_list args;
|
||||
va_start(args, str);
|
||||
string temp;
|
||||
vsprintf(temp, str, args);
|
||||
va_end(args);
|
||||
SetWindowText(info.hwnd, strptr(temp));
|
||||
}
|
||||
|
||||
void Window::set_background_color(uint8 r, uint8 g, uint8 b) {
|
||||
HBRUSH old_brush = info.background;
|
||||
info.background = (HBRUSH)CreateSolidBrush(RGB(r, g, b));
|
||||
SetClassLong(info.hwnd, GCL_HBRBACKGROUND, (LONG)info.background);
|
||||
InvalidateRect(info.hwnd, 0, TRUE);
|
||||
if(old_brush) { DeleteObject((HGDIOBJ)old_brush); }
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
Window::Window() {
|
||||
info.fullscreen = false;
|
||||
info.background = 0;
|
||||
info.center = false;
|
||||
info.control_index = 1;
|
||||
}
|
||||
|
||||
//platform-dependent:
|
||||
|
||||
HWND Window::handle() {
|
||||
return info.hwnd;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -1,430 +0,0 @@
|
||||
/*
|
||||
libups : version 0.01 ~byuu, Nach (09/30/06)
|
||||
*/
|
||||
|
||||
#ifndef __LIBUPS
|
||||
#define __LIBUPS
|
||||
|
||||
template<typename FT>
|
||||
class UPSPatch {
|
||||
public:
|
||||
|
||||
enum {
|
||||
FLAG_INFO = 0x00000001,
|
||||
};
|
||||
|
||||
uint32 sig;
|
||||
uint16 version;
|
||||
uint32 format;
|
||||
uint32 flags;
|
||||
uint64 original_filesize;
|
||||
uint64 modified_filesize;
|
||||
|
||||
uint8 info_author[64 + 8];
|
||||
uint8 info_version[16 + 8];
|
||||
uint8 info_title[128 + 8];
|
||||
uint8 info_genre[32 + 8];
|
||||
uint8 info_language[32 + 8];
|
||||
uint8 info_date[8 + 8];
|
||||
uint8 info_website[256 + 8];
|
||||
uint8 info_description[1024 + 8];
|
||||
|
||||
FT fp;
|
||||
|
||||
uint32 xmlsize;
|
||||
uint32 original_crc32;
|
||||
uint32 modified_crc32;
|
||||
uint32 patch_crc32;
|
||||
|
||||
bool load();
|
||||
void save_header();
|
||||
void save_footer();
|
||||
void close();
|
||||
|
||||
UPSPatch();
|
||||
};
|
||||
|
||||
template<typename FTO, typename FTM, typename FTP>
|
||||
class UPS {
|
||||
public:
|
||||
|
||||
FTO original;
|
||||
FTM modified;
|
||||
UPSPatch<FTP> patch;
|
||||
|
||||
uint64 original_filesize;
|
||||
uint64 modified_filesize;
|
||||
uint64 largest_filesize;
|
||||
|
||||
uint32 original_crc32;
|
||||
uint32 modified_crc32;
|
||||
uint32 patch_crc32;
|
||||
|
||||
bool patch_eof;
|
||||
|
||||
uint ptr_read();
|
||||
void ptr_write(uint ptr);
|
||||
|
||||
void create(const char *original_filename,
|
||||
const char *modified_filename,
|
||||
const char *patch_filename);
|
||||
void create_linear();
|
||||
|
||||
bool apply(const char *original_filename,
|
||||
const char *modified_filename,
|
||||
const char *patch_filename);
|
||||
bool apply();
|
||||
void apply_linear();
|
||||
};
|
||||
|
||||
/*****
|
||||
* UPSPatch
|
||||
*****/
|
||||
|
||||
template<typename FT>
|
||||
bool UPSPatch<FT>::load() {
|
||||
fseek(fp, 0, file::seek_start);
|
||||
|
||||
patch_crc32 = 0xffffffff;
|
||||
while(ftell(fp) < fsize(fp) - 4) {
|
||||
patch_crc32 = crc32_adjust(patch_crc32, fgetc(fp));
|
||||
}
|
||||
patch_crc32 = ~patch_crc32;
|
||||
|
||||
fseek(fp, -16, file::seek_end);
|
||||
|
||||
xmlsize = fgetld(fp);
|
||||
original_crc32 = fgetld(fp);
|
||||
modified_crc32 = fgetld(fp);
|
||||
|
||||
if(patch_crc32 != fgetld(fp)) {
|
||||
fprintf(stdout, "error: patch checksum failure\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
fseek(fp, 0, file::seek_start);
|
||||
|
||||
sig = fgetld(fp);
|
||||
version = fgetlw(fp);
|
||||
format = fgetld(fp);
|
||||
flags = fgetld(fp);
|
||||
original_filesize = fgetlq(fp);
|
||||
modified_filesize = fgetlq(fp);
|
||||
|
||||
memset(info_author, 0, 64 + 8);
|
||||
memset(info_version, 0, 16 + 8);
|
||||
memset(info_title, 0, 128 + 8);
|
||||
memset(info_genre, 0, 32 + 8);
|
||||
memset(info_language, 0, 32 + 8);
|
||||
memset(info_date, 0, 8 + 8);
|
||||
memset(info_website, 0, 256 + 8);
|
||||
memset(info_description, 0, 1024 + 8);
|
||||
|
||||
if(flags & FLAG_INFO) {
|
||||
fread(fp, info_author, 64);
|
||||
fread(fp, info_version, 16);
|
||||
fread(fp, info_title, 128);
|
||||
fread(fp, info_genre, 32);
|
||||
fread(fp, info_language, 32);
|
||||
fread(fp, info_date, 8);
|
||||
fread(fp, info_website, 256);
|
||||
fread(fp, info_description, 1024);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename FT>
|
||||
void UPSPatch<FT>::save_header() {
|
||||
fputld(fp, sig);
|
||||
fputlw(fp, version);
|
||||
fputld(fp, format);
|
||||
fputld(fp, flags);
|
||||
fputlq(fp, original_filesize);
|
||||
fputlq(fp, modified_filesize);
|
||||
|
||||
if(flags & FLAG_INFO) {
|
||||
fwrite(fp, info_author, 64);
|
||||
fwrite(fp, info_version, 16);
|
||||
fwrite(fp, info_title, 128);
|
||||
fwrite(fp, info_genre, 32);
|
||||
fwrite(fp, info_language, 32);
|
||||
fwrite(fp, info_date, 8);
|
||||
fwrite(fp, info_website, 256);
|
||||
fwrite(fp, info_description, 1024);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename FT>
|
||||
void UPSPatch<FT>::save_footer() {
|
||||
fputld(fp, xmlsize);
|
||||
fputld(fp, original_crc32);
|
||||
fputld(fp, modified_crc32);
|
||||
|
||||
patch_crc32 = fcrc32(fp);
|
||||
fputld(fp, patch_crc32);
|
||||
}
|
||||
|
||||
template<typename FT>
|
||||
void UPSPatch<FT>::close() {
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
template<typename FT>
|
||||
UPSPatch<FT>::UPSPatch() {
|
||||
sig = 0x00737075; //'ups\0'
|
||||
version = 0x0001; //1.0
|
||||
format = 0x00000000; //linear
|
||||
flags = 0;
|
||||
original_filesize = 0;
|
||||
modified_filesize = 0;
|
||||
|
||||
memset(info_author, 0, 64 + 8);
|
||||
memset(info_version, 0, 16 + 8);
|
||||
memset(info_title, 0, 128 + 8);
|
||||
memset(info_genre, 0, 32 + 8);
|
||||
memset(info_language, 0, 32 + 8);
|
||||
memset(info_date, 0, 8 + 8);
|
||||
memset(info_website, 0, 256 + 8);
|
||||
memset(info_description, 0, 1024 + 8);
|
||||
|
||||
xmlsize = 0;
|
||||
original_crc32 = 0;
|
||||
modified_crc32 = 0;
|
||||
patch_crc32 = 0;
|
||||
}
|
||||
|
||||
/*****
|
||||
* UPS
|
||||
*****/
|
||||
|
||||
template<typename FTO, typename FTM, typename FTP>
|
||||
uint UPS<FTO, FTM, FTP>::ptr_read() {
|
||||
uint len = fgetc(patch.fp);
|
||||
if(len == 0xff) {
|
||||
patch_eof = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(len <= 0xf7) {
|
||||
return len;
|
||||
}
|
||||
|
||||
len -= 0xf8;
|
||||
uint ptr = 0;
|
||||
for(int i = 0; i < (len + 2); i++) {
|
||||
ptr |= fgetc(patch.fp) << (i << 3);
|
||||
}
|
||||
|
||||
ptr += 0xf8;
|
||||
if(len >= 1) { ptr += 0x10000; }
|
||||
if(len >= 2) { ptr += 0x1000000; }
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template<typename FTO, typename FTM, typename FTP>
|
||||
void UPS<FTO, FTM, FTP>::ptr_write(uint ptr) {
|
||||
if(ptr <= 0xf7) {
|
||||
fputb(patch.fp, ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
ptr -= 0xf8;
|
||||
if(ptr <= 0xffff) {
|
||||
fputb(patch.fp, 0xf8);
|
||||
fputb(patch.fp, ptr);
|
||||
fputb(patch.fp, ptr >> 8);
|
||||
return;
|
||||
}
|
||||
|
||||
ptr -= 0x10000;
|
||||
if(ptr <= 0xffffff) {
|
||||
fputb(patch.fp, 0xf9);
|
||||
fputb(patch.fp, ptr);
|
||||
fputb(patch.fp, ptr >> 8);
|
||||
fputb(patch.fp, ptr >> 16);
|
||||
return;
|
||||
}
|
||||
|
||||
ptr -= 0x1000000;
|
||||
fputb(patch.fp, 0xfa);
|
||||
fputb(patch.fp, ptr);
|
||||
fputb(patch.fp, ptr >> 8);
|
||||
fputb(patch.fp, ptr >> 16);
|
||||
fputb(patch.fp, ptr >> 24);
|
||||
}
|
||||
|
||||
template<typename FTO, typename FTM, typename FTP>
|
||||
void UPS<FTO, FTM, FTP>::create(
|
||||
const char *original_filename,
|
||||
const char *modified_filename,
|
||||
const char *patch_filename
|
||||
) {
|
||||
fopen(original, original_filename, file::mode_read);
|
||||
fopen(modified, modified_filename, file::mode_read);
|
||||
fopen(patch.fp, patch_filename, file::mode_writeread);
|
||||
|
||||
patch.original_filesize = original_filesize = fsize(original);
|
||||
patch.modified_filesize = modified_filesize = fsize(modified);
|
||||
largest_filesize = (original_filesize >= modified_filesize) ?
|
||||
original_filesize : modified_filesize;
|
||||
|
||||
patch.save_header();
|
||||
|
||||
switch(patch.format) {
|
||||
case 0x00000000: create_linear(); break;
|
||||
}
|
||||
|
||||
patch.original_crc32 = original_crc32 = fcrc32(original);
|
||||
patch.modified_crc32 = modified_crc32 = fcrc32(modified);
|
||||
|
||||
patch.save_footer();
|
||||
patch.close();
|
||||
}
|
||||
|
||||
template<typename FTO, typename FTM, typename FTP>
|
||||
void UPS<FTO, FTM, FTP>::create_linear() {
|
||||
fseek(original, 0, file::seek_start);
|
||||
fseek(modified, 0, file::seek_start);
|
||||
|
||||
uint last_ptr = 0, rle_count, last_out, rep_count;
|
||||
for(int i = 0; i < largest_filesize;) {
|
||||
uint8 r = fgetc(original) ^ fgetc(modified);
|
||||
i++;
|
||||
if(r == 0x00)continue;
|
||||
|
||||
//ptr
|
||||
ptr_write((i - 1) - last_ptr);
|
||||
|
||||
//data
|
||||
fputb(patch.fp, r);
|
||||
last_out = r;
|
||||
rep_count = 0;
|
||||
|
||||
do {
|
||||
r = fgetc(original) ^ fgetc(modified);
|
||||
i++;
|
||||
fputb(patch.fp, r);
|
||||
|
||||
if(last_out != r) {
|
||||
rep_count = 0;
|
||||
} else {
|
||||
if(++rep_count == (3 - 1)) {
|
||||
rle_count = 0;
|
||||
do {
|
||||
r = fgetc(original) ^ fgetc(modified);
|
||||
if(r != last_out || r == 0x00) { break; }
|
||||
rle_count++;
|
||||
} while(i < largest_filesize);
|
||||
|
||||
ptr_write(rle_count);
|
||||
if(i < largest_filesize) { fputb(patch.fp, r); }
|
||||
rep_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
last_out = r;
|
||||
if(r == 0x00) { break; }
|
||||
} while(i < largest_filesize);
|
||||
|
||||
last_ptr = i;
|
||||
}
|
||||
|
||||
fputb(patch.fp, 0xff);
|
||||
}
|
||||
|
||||
template<typename FTO, typename FTM, typename FTP>
|
||||
bool UPS<FTO, FTM, FTP>::apply(
|
||||
const char *original_filename,
|
||||
const char *modified_filename,
|
||||
const char *patch_filename
|
||||
) {
|
||||
fopen(original, original_filename, file::mode_read);
|
||||
fopen(modified, modified_filename, file::mode_writeread);
|
||||
fopen(patch.fp, patch_filename, file::mode_read);
|
||||
|
||||
return apply();
|
||||
}
|
||||
|
||||
template<typename FTO, typename FTM, typename FTP>
|
||||
bool UPS<FTO, FTM, FTP>::apply() {
|
||||
patch.load();
|
||||
patch_eof = false;
|
||||
|
||||
original_filesize = fsize(original);
|
||||
original_crc32 = fcrc32(original);
|
||||
|
||||
if(original_filesize == patch.original_filesize &&
|
||||
original_crc32 == patch.original_crc32) {
|
||||
modified_filesize = patch.modified_filesize;
|
||||
modified_crc32 = patch.modified_crc32;
|
||||
} else if(original_filesize == patch.modified_filesize &&
|
||||
original_crc32 == patch.modified_crc32) {
|
||||
modified_filesize = patch.original_filesize;
|
||||
modified_crc32 = patch.original_crc32;
|
||||
} else {
|
||||
fprintf(stdout, "error: input checksum failure\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
patch_crc32 = patch.patch_crc32;
|
||||
|
||||
apply_linear();
|
||||
patch.close();
|
||||
|
||||
if(modified_crc32 != fcrc32(modified)) {
|
||||
fprintf(stdout, "error: output checksum failure\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename FTO, typename FTM, typename FTP>
|
||||
void UPS<FTO, FTM, FTP>::apply_linear() {
|
||||
fseek(original, 0, file::seek_start);
|
||||
fseek(modified, 0, file::seek_start);
|
||||
for(uint i = 0; i < modified_filesize; i++) {
|
||||
fputb(modified, fgetc(original));
|
||||
}
|
||||
|
||||
fseek(original, 0, file::seek_start);
|
||||
fseek(modified, 0, file::seek_start);
|
||||
|
||||
uint rle_count, last_in, rep_count;
|
||||
while(!feof(patch.fp) && patch_eof == false && ftell(modified) < modified_filesize) {
|
||||
//ptr
|
||||
uint ptr = ptr_read();
|
||||
if(patch_eof == true) { break; }
|
||||
|
||||
//data
|
||||
fseek(original, ftell(original) + ptr, file::seek_start);
|
||||
fseek(modified, ftell(modified) + ptr, file::seek_start);
|
||||
|
||||
last_in = 0;
|
||||
rep_count = 0;
|
||||
|
||||
do {
|
||||
if(ftell(modified) >= modified_filesize) { break; }
|
||||
|
||||
uint8 r = fgetc(patch.fp);
|
||||
fputb(modified, r ^ fgetc(original));
|
||||
if(r != last_in) {
|
||||
rep_count = 0;
|
||||
} else {
|
||||
if(++rep_count == (3 - 1)) {
|
||||
rle_count = ptr_read();
|
||||
while(rle_count-- && ftell(modified) < modified_filesize) {
|
||||
fputb(modified, r ^ fgetc(original));
|
||||
}
|
||||
rep_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
last_in = r;
|
||||
if(r == 0x00) { break; }
|
||||
} while(!feof(patch.fp) && patch_eof == false && ftell(modified) < modified_filesize);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
+5
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
libvector : version 0.04 ~byuu (10/14/06)
|
||||
libvector : version 0.05 ~byuu (2006-12-16)
|
||||
*/
|
||||
|
||||
/*****
|
||||
@@ -64,10 +64,8 @@
|
||||
* and speed is less critical.
|
||||
*****/
|
||||
|
||||
#ifndef __LIBVECTOR
|
||||
#define __LIBVECTOR
|
||||
|
||||
#include <new>
|
||||
#ifndef LIBVECTOR_H
|
||||
#define LIBVECTOR_H
|
||||
|
||||
template<typename T> class linear_vector {
|
||||
protected:
|
||||
@@ -98,7 +96,7 @@ public:
|
||||
objectsize = size;
|
||||
}
|
||||
|
||||
pool = static_cast<T*>(realloc(pool, sizeof(T) * size));
|
||||
pool = (T*)realloc(pool, sizeof(T) * size);
|
||||
poolsize = size;
|
||||
}
|
||||
|
||||
@@ -165,7 +163,7 @@ public:
|
||||
objectsize = size;
|
||||
}
|
||||
|
||||
pool = static_cast<T**>(realloc(pool, sizeof(T*) * size));
|
||||
pool = (T**)realloc(pool, sizeof(T*) * size);
|
||||
if(size > poolsize) {
|
||||
memset(pool + poolsize, 0, sizeof(T*) * (size - poolsize));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "libbase.h"
|
||||
#include "libstring.h"
|
||||
#include "libstring.cpp"
|
||||
|
||||
FILE *fp;
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
FILE *fp, *fph, *fpt;
|
||||
|
||||
string data, line, part, subpart;
|
||||
string output_table, output_header, output_op;
|
||||
stringarray data, line, part, subpart;
|
||||
stringarray output_table, output_header, output_op;
|
||||
|
||||
struct _op_list {
|
||||
string name, arg;
|
||||
stringarray name, arg;
|
||||
} op_list[64];
|
||||
|
||||
int32 op_count, line_num;
|
||||
@@ -58,7 +58,7 @@ void gen_op() {
|
||||
int i = line_num, n, c;
|
||||
char t[4096];
|
||||
while(1) {
|
||||
if(strmatch(line[i], "}"))break;
|
||||
if(!strcmp(line[i], "}"))break;
|
||||
|
||||
n = strdec(line[i]);
|
||||
sprintf(t, "%d:", n);
|
||||
@@ -67,7 +67,7 @@ char t[4096];
|
||||
//strcat(output_op, t);
|
||||
|
||||
update_line(i);
|
||||
if(!strmatch(line[i], "")) {
|
||||
if(strcmp(line[i], "")) {
|
||||
strcat(output_op, " ");
|
||||
strcat(output_op, line[i]);
|
||||
strcat(output_op, "\r\n");
|
||||
@@ -75,7 +75,7 @@ char t[4096];
|
||||
|
||||
i++;
|
||||
while(1) {
|
||||
if(strptr(line[i])[1] == ':' || strptr(line[i])[2] == ':' || strmatch(line[i], "}"))break;
|
||||
if(strptr(line[i])[1] == ':' || strptr(line[i])[2] == ':' || !strcmp(line[i], "}"))break;
|
||||
|
||||
update_line(i);
|
||||
strcat(output_op, line[i]);
|
||||
@@ -135,7 +135,7 @@ char *buf = (char*)malloc(fsize + 1);
|
||||
|
||||
line_num = 0;
|
||||
while(line_num < count(line)) {
|
||||
while(strmatch(line[line_num], "") && line_num < count(line))line_num++;
|
||||
while(line_num < count(line) && !strcmp(line[line_num], ""))line_num++;
|
||||
if(line_num >= count(line))break;
|
||||
|
||||
gen_header();
|
||||
|
||||
@@ -27,11 +27,12 @@ void bMemBus::load_cart() {
|
||||
return;
|
||||
}
|
||||
|
||||
if(cartridge.info.sdd1)cart_map_sdd1();
|
||||
if(cartridge.info.c4) cart_map_c4();
|
||||
if(cartridge.info.dsp1)cart_map_dsp1();
|
||||
if(cartridge.info.dsp2)cart_map_dsp2();
|
||||
if(cartridge.info.obc1)cart_map_obc1();
|
||||
if(cartridge.info.sdd1) cart_map_sdd1();
|
||||
if(cartridge.info.c4) cart_map_c4();
|
||||
if(cartridge.info.dsp1) cart_map_dsp1();
|
||||
if(cartridge.info.dsp2) cart_map_dsp2();
|
||||
if(cartridge.info.obc1) cart_map_obc1();
|
||||
if(cartridge.info.st010)cart_map_st010();
|
||||
|
||||
cart_map_system();
|
||||
|
||||
@@ -57,12 +58,13 @@ char t[256];
|
||||
dprintf("* Region : %s", (cartridge.info.region == Cartridge::NTSC) ? "NTSC" : "PAL");
|
||||
|
||||
strcpy(t, "");
|
||||
if(cartridge.info.srtc)strcat(t, "S-RTC, ");
|
||||
if(cartridge.info.sdd1)strcat(t, "S-DD1, ");
|
||||
if(cartridge.info.c4) strcat(t, "Cx4, ");
|
||||
if(cartridge.info.dsp1)strcat(t, "DSP-1, ");
|
||||
if(cartridge.info.dsp2)strcat(t, "DSP-2, ");
|
||||
if(cartridge.info.obc1)strcat(t, "OBC-1, ");
|
||||
if(cartridge.info.srtc) strcat(t, "S-RTC, ");
|
||||
if(cartridge.info.sdd1) strcat(t, "S-DD1, ");
|
||||
if(cartridge.info.c4) strcat(t, "Cx4, ");
|
||||
if(cartridge.info.dsp1) strcat(t, "DSP-1, ");
|
||||
if(cartridge.info.dsp2) strcat(t, "DSP-2, ");
|
||||
if(cartridge.info.obc1) strcat(t, "OBC-1, ");
|
||||
if(cartridge.info.st010)strcat(t, "ST010, ");
|
||||
strrtrim(t, ", ");
|
||||
dprintf("* Coprocessor(s) : %s", (strlen(t) == 0) ? "None" : t);
|
||||
dprintf("* Reset:%0.4x NMI[n]:%0.4x IRQ[n]:%0.4x BRK[n]:%0.4x COP[n]:%0.4x",
|
||||
@@ -200,5 +202,5 @@ bMemBus::bMemBus() {
|
||||
}
|
||||
|
||||
bMemBus::~bMemBus() {
|
||||
SafeFree(wram);
|
||||
safe_free(wram);
|
||||
}
|
||||
@@ -41,6 +41,8 @@ enum { TYPE_WRAM, TYPE_MMIO, TYPE_CART };
|
||||
void write_dsp2 (uint32 addr, uint8 data);
|
||||
uint8 read_obc1 (uint32 addr);
|
||||
void write_obc1 (uint32 addr, uint8 data);
|
||||
uint8 read_st010 (uint32 addr);
|
||||
void write_st010 (uint32 addr, uint8 data);
|
||||
|
||||
void cart_map_reset();
|
||||
void cart_map_system();
|
||||
@@ -51,6 +53,7 @@ enum { TYPE_WRAM, TYPE_MMIO, TYPE_CART };
|
||||
void cart_map_dsp1();
|
||||
void cart_map_dsp2();
|
||||
void cart_map_obc1();
|
||||
void cart_map_st010();
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
@@ -178,3 +178,15 @@ void bMemBus::cart_map_obc1() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bMemBus::cart_map_st010() {
|
||||
//$[68-6f|e8-ef]:[0000-0fff]
|
||||
for(uint bank = 0x68; bank <= 0x6f; bank++) {
|
||||
for(uint page = 0x00; page <= 0x0f; page++) {
|
||||
page_read [0x0000 + (bank << 8) + page] = &bMemBus::read_st010;
|
||||
page_read [0x8000 + (bank << 8) + page] = &bMemBus::read_st010;
|
||||
page_write[0x0000 + (bank << 8) + page] = &bMemBus::write_st010;
|
||||
page_write[0x8000 + (bank << 8) + page] = &bMemBus::write_st010;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,3 +62,6 @@ void bMemBus::write_dsp2(uint32 addr, uint8 data) { dsp2->write(addr, data); }
|
||||
|
||||
uint8 bMemBus::read_obc1 (uint32 addr) { return obc1->read(addr); }
|
||||
void bMemBus::write_obc1(uint32 addr, uint8 data) { obc1->write(addr, data); }
|
||||
|
||||
uint8 bMemBus::read_st010 (uint32 addr) { return st010->read(addr); }
|
||||
void bMemBus::write_st010(uint32 addr, uint8 data) { st010->write(addr, data); }
|
||||
@@ -42,6 +42,7 @@ void bPPU::scanline() {
|
||||
if(regs.display_disabled == false) {
|
||||
//OAM address reset
|
||||
regs.oam_addr = regs.oam_baseaddr << 1;
|
||||
regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,7 +376,7 @@ bPPU::bPPU() {
|
||||
}
|
||||
|
||||
bPPU::~bPPU() {
|
||||
SafeFree(vram);
|
||||
SafeFree(oam);
|
||||
SafeFree(cgram);
|
||||
safe_free(vram);
|
||||
safe_free(oam);
|
||||
safe_free(cgram);
|
||||
}
|
||||
+15
-3
@@ -148,8 +148,12 @@ struct {
|
||||
void cgram_write(uint16 addr, uint8 value);
|
||||
|
||||
uint16 get_vram_address();
|
||||
uint8 vram_mmio_read (uint16 addr);
|
||||
void vram_mmio_write(uint16 addr, uint8 data);
|
||||
uint8 vram_mmio_read (uint16 addr);
|
||||
void vram_mmio_write (uint16 addr, uint8 data);
|
||||
uint8 oam_mmio_read (uint16 addr);
|
||||
void oam_mmio_write (uint16 addr, uint8 data);
|
||||
uint8 cgram_mmio_read (uint16 addr);
|
||||
void cgram_mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
void mmio_w2100(uint8 value); //INIDISP
|
||||
void mmio_w2101(uint8 value); //OBSEL
|
||||
@@ -239,7 +243,15 @@ uint16 mosaic_table[16][4096];
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
bool scanline_is_hires() { return (regs.pseudo_hires || regs.bg_mode == 5 || regs.bg_mode == 6); }
|
||||
bool scanline_is_hires() { return (regs.pseudo_hires || regs.bg_mode == 5 || regs.bg_mode == 6); }
|
||||
|
||||
inline uint16 read16(uint8 *addr, uint pos) {
|
||||
#if defined(ARCH_LSB)
|
||||
return *((uint16*)(addr + pos));
|
||||
#else
|
||||
return (addr[pos]) | (addr[pos + 1] << 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
bPPU();
|
||||
~bPPU();
|
||||
|
||||
+95
-18
@@ -8,7 +8,7 @@ uint16 bPPU::get_vram_address() {
|
||||
uint16 addr;
|
||||
addr = regs.vram_addr;
|
||||
switch(regs.vram_mapping) {
|
||||
case 0: break;
|
||||
case 0: break; //direct
|
||||
case 1: addr = (addr & 0xff00) | ((addr & 0x001f) << 3) | ((addr >> 5) & 7); break;
|
||||
case 2: addr = (addr & 0xfe00) | ((addr & 0x003f) << 3) | ((addr >> 6) & 7); break;
|
||||
case 3: addr = (addr & 0xfc00) | ((addr & 0x007f) << 3) | ((addr >> 7) & 7); break;
|
||||
@@ -16,6 +16,11 @@ uint16 addr;
|
||||
return (addr << 1);
|
||||
}
|
||||
|
||||
//NOTE: all VRAM writes during active display are invalid. Unlike OAM and CGRAM, they will
|
||||
//not be written anywhere at all. The below address ranges for where writes are invalid have
|
||||
//been validated on hardware, as has the edge case where the S-CPU MDR can be written if the
|
||||
//write occurs during the very last clock cycle of vblank.
|
||||
|
||||
uint8 bPPU::vram_mmio_read(uint16 addr) {
|
||||
if(regs.display_disabled == true) {
|
||||
return vram_read(addr);
|
||||
@@ -46,20 +51,17 @@ uint16 ls = (r_cpu->region_scanlines() >> 1) - 1;
|
||||
|
||||
void bPPU::vram_mmio_write(uint16 addr, uint8 data) {
|
||||
if(regs.display_disabled == true) {
|
||||
vram_write(addr, data);
|
||||
return;
|
||||
return vram_write(addr, data);
|
||||
}
|
||||
|
||||
uint16 v = r_cpu->vcounter();
|
||||
uint16 hc = r_cpu->hclock();
|
||||
if(v == 0) {
|
||||
if(hc <= 4) {
|
||||
vram_write(addr, data);
|
||||
return;
|
||||
return vram_write(addr, data);
|
||||
}
|
||||
if(hc == 6) {
|
||||
vram_write(addr, r_cpu->regs.mdr);
|
||||
return;
|
||||
return vram_write(addr, r_cpu->regs.mdr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -72,17 +74,92 @@ uint16 hc = r_cpu->hclock();
|
||||
if(hc <= 4) {
|
||||
return;
|
||||
}
|
||||
vram_write(addr, data);
|
||||
return;
|
||||
return vram_write(addr, data);
|
||||
}
|
||||
|
||||
vram_write(addr, data);
|
||||
}
|
||||
|
||||
//NOTE: OAM accesses during active display are rerouted to 0x0218 ... this can be considered
|
||||
//a hack. The actual address varies during rendering, as the S-PPU reads in data itself for
|
||||
//processing. Unfortunately, we have yet to determine how this works. The algorithm cannot be
|
||||
//reverse engineered using a scanline renderer such as this, and at this time, there does not
|
||||
//exist a more accurate SNES PPU emulator to work from. The only known game to actually access
|
||||
//OAM during active display is Uniracers. It expects accesses to map to offset 0x0218.
|
||||
//It was decided by public consensus to map writes to this address to match Uniracers, primarily
|
||||
//because it is the only game observed to do this, but also because mapping to this address does
|
||||
//not contradict any of our findings, because we have no findings whatsoever on this behavior.
|
||||
//Think of this what you will, I openly admit that this is a hack. But it is more accurate than
|
||||
//writing to the 'expected' address set by $2102,$2103, and will catch problems in software that
|
||||
//accidentally accesses OAM during active display by virtue of not returning the expected data.
|
||||
//You may disable this behavior by setting config::ppu.hack.oam_address_invalidation to false,
|
||||
//or by changing the address from 0x0218 to 0x0000 below if it bothers you that greatly.
|
||||
|
||||
uint8 bPPU::oam_mmio_read(uint16 addr) {
|
||||
if(config::ppu.hack.oam_address_invalidation == false || regs.display_disabled == true) {
|
||||
return oam_read(addr);
|
||||
}
|
||||
|
||||
uint16 v = r_cpu->vcounter();
|
||||
if(v < (!r_cpu->overscan() ? 225 : 240)) {
|
||||
return oam_read(0x0218);
|
||||
}
|
||||
|
||||
return oam_read(addr);
|
||||
}
|
||||
|
||||
void bPPU::oam_mmio_write(uint16 addr, uint8 data) {
|
||||
if(config::ppu.hack.oam_address_invalidation == false || regs.display_disabled == true) {
|
||||
return oam_write(addr, data);
|
||||
}
|
||||
|
||||
uint16 v = r_cpu->vcounter();
|
||||
if(v < (!r_cpu->overscan() ? 225 : 240)) {
|
||||
return oam_write(0x0218, data);
|
||||
}
|
||||
|
||||
oam_write(addr, data);
|
||||
}
|
||||
|
||||
//NOTE: CGRAM writes during hblank are valid. During active display, the actual address the
|
||||
//data is written to varies, as the S-PPU itself changes the address. Like OAM, we do not know
|
||||
//the exact algorithm used, but we have zero known examples of any commercial software that
|
||||
//attempts to do this. Therefore, the addresses are mapped to 0x01ff. There is nothing special
|
||||
//about this address, it is simply more accurate to invalidate the 'expected' address than not.
|
||||
|
||||
uint8 bPPU::cgram_mmio_read(uint16 addr) {
|
||||
if(config::ppu.hack.cgram_address_invalidation == false || regs.display_disabled == true) {
|
||||
return cgram_read(addr);
|
||||
}
|
||||
|
||||
uint16 v = r_cpu->vcounter();
|
||||
uint16 hc = r_cpu->hclock();
|
||||
if(v < (!r_cpu->overscan() ? 225 : 240) && hc >= 72 && hc < 1096) {
|
||||
return cgram_read(0x01ff);
|
||||
}
|
||||
|
||||
return cgram_read(addr);
|
||||
}
|
||||
|
||||
void bPPU::cgram_mmio_write(uint16 addr, uint8 data) {
|
||||
if(config::ppu.hack.cgram_address_invalidation == false || regs.display_disabled == true) {
|
||||
return cgram_write(addr, data);
|
||||
}
|
||||
|
||||
uint16 v = r_cpu->vcounter();
|
||||
uint16 hc = r_cpu->hclock();
|
||||
if(v < (!r_cpu->overscan() ? 225 : 240) && hc >= 72 && hc < 1096) {
|
||||
return cgram_write(0x01ff, data);
|
||||
}
|
||||
|
||||
cgram_write(addr, data);
|
||||
}
|
||||
|
||||
//INIDISP
|
||||
void bPPU::mmio_w2100(uint8 value) {
|
||||
if(regs.display_disabled == true && !!(value & 0x80) == false) {
|
||||
if(regs.display_disabled == true && r_cpu->vcounter() == (!r_cpu->overscan() ? 225 : 240)) {
|
||||
regs.oam_addr = regs.oam_baseaddr << 1;
|
||||
regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
|
||||
}
|
||||
|
||||
regs.display_disabled = !!(value & 0x80);
|
||||
@@ -116,12 +193,12 @@ void bPPU::mmio_w2103(uint8 data) {
|
||||
//OAMDATA
|
||||
void bPPU::mmio_w2104(uint8 data) {
|
||||
if(regs.oam_addr & 0x0200) {
|
||||
oam_write(regs.oam_addr, data);
|
||||
oam_mmio_write(regs.oam_addr, data);
|
||||
} else if((regs.oam_addr & 1) == 0) {
|
||||
regs.oam_latchdata = data;
|
||||
} else {
|
||||
oam_write((regs.oam_addr & ~1) + 0, regs.oam_latchdata);
|
||||
oam_write((regs.oam_addr & ~1) + 1, data);
|
||||
oam_mmio_write((regs.oam_addr & ~1) + 0, regs.oam_latchdata);
|
||||
oam_mmio_write((regs.oam_addr & ~1) + 1, data);
|
||||
}
|
||||
|
||||
regs.oam_addr++;
|
||||
@@ -352,8 +429,8 @@ void bPPU::mmio_w2122(uint8 value) {
|
||||
if(!(regs.cgram_addr & 1)) {
|
||||
regs.cgram_latchdata = value;
|
||||
} else {
|
||||
cgram_write((regs.cgram_addr & 0x01fe), regs.cgram_latchdata);
|
||||
cgram_write((regs.cgram_addr & 0x01fe) + 1, value & 0x7f);
|
||||
cgram_mmio_write((regs.cgram_addr & 0x01fe), regs.cgram_latchdata);
|
||||
cgram_mmio_write((regs.cgram_addr & 0x01fe) + 1, value & 0x7f);
|
||||
}
|
||||
regs.cgram_addr++;
|
||||
regs.cgram_addr &= 0x01ff;
|
||||
@@ -539,7 +616,7 @@ uint8 bPPU::mmio_r2137() {
|
||||
|
||||
//OAMDATAREAD
|
||||
uint8 bPPU::mmio_r2138() {
|
||||
regs.ppu1_mdr = oam_read(regs.oam_addr);
|
||||
regs.ppu1_mdr = oam_mmio_read(regs.oam_addr);
|
||||
|
||||
regs.oam_addr++;
|
||||
regs.oam_addr &= 0x03ff;
|
||||
@@ -580,10 +657,10 @@ uint16 addr = get_vram_address() + 1;
|
||||
//update bit 7 of the PPU2 MDR.
|
||||
uint8 bPPU::mmio_r213b() {
|
||||
if(!(regs.cgram_addr & 1)) {
|
||||
regs.ppu2_mdr = cgram_read(regs.cgram_addr) & 0xff;
|
||||
regs.ppu2_mdr = cgram_mmio_read(regs.cgram_addr) & 0xff;
|
||||
} else {
|
||||
regs.ppu2_mdr &= 0x80;
|
||||
regs.ppu2_mdr |= cgram_read(regs.cgram_addr) & 0x7f;
|
||||
regs.ppu2_mdr |= cgram_mmio_read(regs.cgram_addr) & 0x7f;
|
||||
}
|
||||
regs.cgram_addr++;
|
||||
regs.cgram_addr &= 0x01ff;
|
||||
|
||||
@@ -27,7 +27,9 @@ uint16 bPPU::bg_get_tile(uint8 bg, uint16 x, uint16 y) {
|
||||
uint16 pos = ((y & 0x1f) << 5) + (x & 0x1f);
|
||||
if(y & 0x20)pos += bg_info[bg].scy;
|
||||
if(x & 0x20)pos += bg_info[bg].scx;
|
||||
return read16(vram, regs.bg_scaddr[bg] + (pos << 1));
|
||||
|
||||
uint16 addr = regs.bg_scaddr[bg] + (pos << 1);
|
||||
return (vram_read(addr + 0) << 0) | (vram_read(addr + 1) << 8);
|
||||
}
|
||||
|
||||
#define setpixel_main(x) \
|
||||
|
||||
+1
-1
@@ -46,5 +46,5 @@ PPU::PPU() {
|
||||
}
|
||||
|
||||
PPU::~PPU() {
|
||||
SafeFree(output);
|
||||
safe_free(output);
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
#include "filereader.h"
|
||||
|
||||
uint32 FileReader::size() {
|
||||
return fsize;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#include "gzreader.h"
|
||||
|
||||
uint32 GZReader::size() {
|
||||
return fsize;
|
||||
}
|
||||
|
||||
+2
-3
@@ -1,11 +1,10 @@
|
||||
/*
|
||||
Copyright (C) 2005 NSRT Team ( http://nsrt.edgeemu.com )
|
||||
Copyright (C) 2005-2007 NSRT Team ( http://nsrt.edgeemu.com )
|
||||
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
|
||||
|
||||
This library 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.
|
||||
License version 2.1 as published by the Free Software Foundation.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
|
||||
Loaded 100 of 264 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user