mirror of https://github.com/bsnes-emu/bsnes.git
Update to bsnes v020 release.
Five months and 43 WIP releases in the making, today I am releasing bsnes v0.020. I'd really like to express my thanks to blargg, for he has written a new S-DSP emulator that is an impressive 32 times more precise than all existing S-DSP emulators. It is now bus-accurate, and should produce bit-perfect sound output to that of a real SNES, excepting very minor, very extreme edge cases. Not only did he do this, he went out of his way to develop a special version exclusively for bsnes to ease licensing concerns and take advantage of bsnes' unique features, notably cothreads. I can't thank him enough. Unfortunately, bsnes has taken a ~10% speed hit over v0.019 by using this new S-DSP emulator, but I must stress the speed hit is entirely due to the way bsnes is implemented. blargg's standalone S-DSP emulator is very, very fast. Anyone is free to take a look at his S-DSP emulator, as he has released it as open source under the LGPL, by visiting his homepage, here. Unfortunately, the new cross-platform UI is not entirely finished. Some sacrifices had to be made to support libui. Specifically, the following features are missing from v0.019, but will hopefully be added back in future releases: - Fullscreen support - Input Configuration panel cannot capture joypad input. Joypad support is still present, but it must be mapped manually through the Advanced panel or through editing bsnes.cfg by hand - The Cheat Code Editor is missing, but cht files can still be used from bsnes v0.019, and created by hand - Sufami Turbo support is not accessible from the UI - The UI on Windows is slightly less polished due to compromises to allow the UI to be readable on Linux. I am sorry for the rough edges listed above, but I wanted to get a new release out, as it has been over five months since the last release, and I really want the world to be able to experience blargg's new S-DSP emulator. Changelog: - Added blargg's new S-DSP emulator, runs at 1.024mhz. Many thanks to blargg for this, as this puts all portions of SNES emulation except for the S-PPU at bus-accuracy - blargg's S-DSP core fixes bugs in both Koushien 2 (J) and Toy Story (U) - Corrected all S-SMP cycle timings to be hardware accurate. Thanks to blargg for creating an amazing test ROM that tested every possible opcode - Corrected S-CPU wai instruction timing, fixes Mortal Kombat II - Reverted HDMA sync emulation once more to fix Breath of Fire II (G) and Secret of Mana (U) - Completely rewrote user interface to use libui, which is a wrapper that allows the same code to produce the same UI on both Windows (through the Win32 API) and Linux (through the GTK+ API) - Corrected $2100.d7 OAM reset behavior, thanks to research from anomie - Massively revamped the Linux port, should compile with no warnings or errors now - Added 64-bit support to libco, tested on FreeBSD/amd64, should work on Linux as well - Revamped makefile with suggestions from Nach - Improved Linux Xv renderer to use the far more common YUY2 format, which should work on most Xorg drivers, allowing hardware accelerated video scaling - Completely rewrote config file system. bsnes.cfg is now saved to user's profile folder on both Windows and Linux, allowing multi-user support - A lot more work has been done behind the scenes, including massive code cleanups and portability improvements You may download the new version on the main bsnes page.
This commit is contained in:
parent
5c3c872b78
commit
2cc7fe30b4
35
license.txt
35
license.txt
|
@ -1,35 +0,0 @@
|
|||
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.
|
||||
|
||||
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.
|
||||
|
||||
The Simple DirectMedia Layer library source code is available from:
|
||||
http://www.libsdl.org/
|
||||
|
||||
This library is distributed under the terms of the GNU LGPL:
|
||||
http://www.gnu.org/copyleft/lesser.html
|
||||
|
||||
JMA License:
|
||||
------------
|
||||
JMA is licensed under the GNU GPL. I have received special exemption from
|
||||
Nach to use this library in bsnes.
|
||||
|
||||
Licensing Exemptions:
|
||||
---------------------
|
||||
libco, the cooperative multithreading library used by bsnes, is public domain.
|
||||
You may obtain the latest version at: http://byuu.org/
|
||||
|
||||
Richard Bannister has asked for and received my permission to distribute
|
||||
a binary-only port of bsnes on the Mac OS X platform.
|
98
readme.txt
98
readme.txt
|
@ -1,98 +0,0 @@
|
|||
bsnes
|
||||
Version 0.019
|
||||
Author: byuu
|
||||
|
||||
|
||||
General
|
||||
-------
|
||||
bsnes is a Super Nintendo / Super Famicom emulator that began on
|
||||
October 14th, 2004.
|
||||
|
||||
The latest version can be downloaded from:
|
||||
http://byuu.org/
|
||||
|
||||
Please see license.txt for important licensing information.
|
||||
|
||||
|
||||
Known Limitations
|
||||
-----------------
|
||||
S-CPU
|
||||
- Invalid DMA / HDMA transfers (eg WRAM<>WRAM) 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
|
||||
- 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
|
||||
is enabled. This provides a major speedup, however it will cause in issues
|
||||
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
|
||||
|
||||
|
||||
Unsupported Hardware
|
||||
--------------------
|
||||
SA-1
|
||||
Coprocessor used in many popular games, including:
|
||||
- Dragon Ball Z Hyper Dimension
|
||||
- Kirby Super Star
|
||||
- Kirby's Dreamland 3
|
||||
- Marvelous
|
||||
- SD Gundam G-NEXT
|
||||
- Super Mario RPG
|
||||
|
||||
Super FX
|
||||
Coprocessor used in many popular games, including:
|
||||
- Doom
|
||||
- Star Fox
|
||||
- Star Fox 2 (unreleased beta)
|
||||
- Super Mario World 2: Yoshi's Island
|
||||
|
||||
SPC7110
|
||||
Coprocessor used only by the following games:
|
||||
- Far East of Eden Zero
|
||||
- Far East of Eden Zero: Shounen Jump no Shou
|
||||
- Momotarou Densetsu Happy
|
||||
- Super Power League 4
|
||||
|
||||
DSP-3
|
||||
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
|
||||
|
||||
BS-X (Broadcast Satellite)
|
||||
Add-on unit sold only in Japan that played specially-made games that
|
||||
were downloaded via satellite
|
||||
|
||||
BS-X Flashcart
|
||||
Flash cartridge used by BS-X, as well as some standalone games by
|
||||
Asciisoft
|
||||
|
||||
Super Gameboy
|
||||
Cartridge passthrough used for playing Gameboy games
|
||||
|
||||
|
||||
Unsupported controllers
|
||||
-----------------------
|
||||
Mouse
|
||||
Super Scope
|
||||
Justifier
|
||||
Multitap (4-port)
|
||||
Multitap (5-port)
|
79
src/Makefile
79
src/Makefile
|
@ -13,19 +13,23 @@ endif
|
|||
ifeq ($(PLATFORM),x-gcc-lui)
|
||||
OS = unix
|
||||
CC = gcc
|
||||
CFLAGS = -O3 -fomit-frame-pointer -ffast-math -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_LUI `pkg-config --cflags gtk+-2.0` `sdl-config --cflags`
|
||||
CFLAGS = -O3 -fomit-frame-pointer -ffast-math -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` `sdl-config --libs` -lXv -lao
|
||||
LIBS = `pkg-config --libs gtk+-2.0` -lXv -lao
|
||||
LIBCO = libco_x86
|
||||
LIBUI = libui_gtk
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),x-gcc-sdl)
|
||||
ifeq ($(PLATFORM),x-gcc-lui-x64)
|
||||
OS = unix
|
||||
CC = gcc
|
||||
CFLAGS = -O3 -fomit-frame-pointer -ffast-math -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_SDL `sdl-config --cflags`
|
||||
AS = nasm
|
||||
ASFLAGS = -f elf
|
||||
LIBS = `sdl-config --libs` -lao
|
||||
CFLAGS = -O3 -fomit-frame-pointer -ffast-math -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)
|
||||
|
@ -35,44 +39,32 @@ CFLAGS = /nologo /wd4996 /O2 /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR
|
|||
AS = nasm
|
||||
ASFLAGS = -f win32 -DWIN32
|
||||
LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib
|
||||
LIBCO = libco_x86
|
||||
LIBUI = libui_win
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),win-visualc)
|
||||
ifeq ($(PLATFORM),win-visualc-lui-pgi)
|
||||
OS = win
|
||||
CC = cl
|
||||
CFLAGS = /nologo /wd4996 /O2 /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_WIN
|
||||
AS = nasm
|
||||
ASFLAGS = -f win32 -DWIN32
|
||||
LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),win-visualc-pgi)
|
||||
OS = win
|
||||
CC = cl
|
||||
CFLAGS = /nologo /wd4996 /O2 /GL /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_WIN
|
||||
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
|
||||
LINK = /link /PGD:bsnes.pgd /LTCG:PGINSTRUMENT
|
||||
LIBCO = libco_x86
|
||||
LIBUI = libui_win
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),win-visualc-pgo)
|
||||
ifeq ($(PLATFORM),win-visualc-lui-pgo)
|
||||
OS = win
|
||||
CC = cl
|
||||
CFLAGS = /nologo /wd4996 /O2 /GL /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_WIN
|
||||
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
|
||||
LINK = /link /PGD:bsnes.pgd /LTCG:PGOPTIMIZE
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),win-visualc-sdl)
|
||||
OS = win
|
||||
CC = cl
|
||||
CFLAGS = /nologo /wd4996 /O2 /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_SDL
|
||||
AS = nasm
|
||||
ASFLAGS = -f win32 -DWIN32
|
||||
LIBS = sdlmain.lib sdl.lib dsound.lib
|
||||
LIBCO = libco_x86
|
||||
LIBUI = libui_win
|
||||
endif
|
||||
|
||||
#####################################
|
||||
|
@ -99,6 +91,10 @@ ifeq ($(AS),nasm)
|
|||
ASARGS = $< -o $@
|
||||
endif
|
||||
|
||||
ifeq ($(AS),yasm)
|
||||
ASARGS = $< -o $@
|
||||
endif
|
||||
|
||||
###################
|
||||
### OS switches ###
|
||||
###################
|
||||
|
@ -110,14 +106,15 @@ endif
|
|||
ifeq ($(OS),win)
|
||||
OUT := $(OUT).exe
|
||||
RM = del
|
||||
LIBS += kernel32.lib user32.lib gdi32.lib winmm.lib comdlg32.lib comctl32.lib
|
||||
LIBS += kernel32.lib user32.lib gdi32.lib shell32.lib winmm.lib comdlg32.lib comctl32.lib
|
||||
endif
|
||||
|
||||
####################################
|
||||
### main target and dependencies ###
|
||||
####################################
|
||||
|
||||
OBJECTS = main.$(OBJ) libco_x86.$(OBJ) libstring.$(OBJ) libconfig.$(OBJ) \
|
||||
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) \
|
||||
|
@ -160,16 +157,25 @@ all: $(OBJECTS)
|
|||
#########################
|
||||
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/* \
|
||||
ui/sdl/*
|
||||
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 ###
|
||||
#################
|
||||
libco_x86.$(OBJ): lib/libco_x86.asm lib/*
|
||||
libstring.$(OBJ): lib/libstring.cpp lib/*
|
||||
libconfig.$(OBJ): lib/libconfig.cpp lib/*
|
||||
|
||||
#################
|
||||
### utilities ###
|
||||
|
@ -199,6 +205,7 @@ ssmp.$(OBJ): smp/ssmp/ssmp.cpp smp/ssmp/* smp/ssmp/core/* smp/ssmp/memory/* smp/
|
|||
###########
|
||||
### dsp ###
|
||||
###########
|
||||
adsp.$(OBJ): dsp/adsp/adsp.cpp dsp/adsp/*
|
||||
bdsp.$(OBJ): dsp/bdsp/bdsp.cpp dsp/bdsp/*
|
||||
|
||||
###########
|
||||
|
@ -210,7 +217,7 @@ bppu.$(OBJ): ppu/bppu/bppu.cpp ppu/bppu/*
|
|||
############
|
||||
### snes ###
|
||||
############
|
||||
snes.$(OBJ): snes/snes.cpp snes/* snes/video/* snes/audio/* snes/input/*
|
||||
snes.$(OBJ): snes/snes.cpp snes/* snes/scheduler/* snes/video/* snes/audio/* snes/input/*
|
||||
|
||||
#####################
|
||||
### special chips ###
|
||||
|
|
24
src/base.h
24
src/base.h
|
@ -1,4 +1,4 @@
|
|||
#define BSNES_VERSION "0.019.09"
|
||||
#define BSNES_VERSION "0.020"
|
||||
#define BSNES_TITLE "bsnes v" BSNES_VERSION
|
||||
|
||||
#define MEMCORE bMemBus
|
||||
|
@ -17,36 +17,32 @@
|
|||
//(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/libinterp.h"
|
||||
#include "lib/libsort.h"
|
||||
#include "lib/libco_x86.h"
|
||||
#include "lib/libarray.h"
|
||||
#include "lib/libvector.h"
|
||||
#include "lib/libfile.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(char*, ...);
|
||||
void dprintf(char*, ...);
|
||||
void dprintf(uint, char*, ...);
|
||||
|
||||
namespace source {
|
||||
enum {
|
||||
|
|
BIN
src/bsnes.lnk
BIN
src/bsnes.lnk
Binary file not shown.
|
@ -1,181 +0,0 @@
|
|||
# Default path to look for ROM files in ("" = use default directory)
|
||||
# (default = "")
|
||||
path.rom = "/dos/Documents and Settings/byuu/Desktop/snes_testroms"
|
||||
|
||||
# Default path for all save RAM and cheat files ("" = use current directory)
|
||||
# (default = "")
|
||||
path.save = ""
|
||||
|
||||
# Path where BIOS file(s) are located
|
||||
# Supported BIOS files:
|
||||
# stbios.bin - Bandai Sufami Turbo
|
||||
# (default = "./bios")
|
||||
path.bios = "./bios"
|
||||
|
||||
# Extension to be used for all save RAM files
|
||||
# (default = "srm")
|
||||
path.save_ext = "srm"
|
||||
|
||||
# Use precalculated TV-style gamma ramp
|
||||
# (default = true)
|
||||
snes.colorfilter.gamma_ramp = true
|
||||
|
||||
# Convert color to sepia tone
|
||||
# (default = false)
|
||||
snes.colorfilter.sepia = false
|
||||
|
||||
# Convert color to grayscale tone
|
||||
# (default = false)
|
||||
snes.colorfilter.grayscale = false
|
||||
|
||||
# Invert output image colors
|
||||
# (default = false)
|
||||
snes.colorfilter.invert = false
|
||||
|
||||
# Contrast
|
||||
# (default = 0)
|
||||
snes.colorfilter.contrast = 0
|
||||
|
||||
# Brightness
|
||||
# (default = 0)
|
||||
snes.colorfilter.brightness = 0
|
||||
|
||||
# Gamma
|
||||
# (default = 80)
|
||||
snes.colorfilter.gamma = 80
|
||||
|
||||
# Merge fields in NTSC video filter
|
||||
# Set to true if using filter at any refresh rate other than 60hz
|
||||
#
|
||||
# (default = true)
|
||||
snes.ntsc_merge_fields = true
|
||||
|
||||
# Mutes SNES audio output when enabled
|
||||
# (default = false)
|
||||
snes.mute = false
|
||||
|
||||
# Controller attached to SNES port 1
|
||||
# (default = 1)
|
||||
snes.controller_port_1 = 1
|
||||
|
||||
# Controller attached to SNES port 2
|
||||
# (default = 2)
|
||||
snes.controller_port_2 = 2
|
||||
|
||||
# NTSC S-CPU clock rate (in hz)
|
||||
# (default = 21477272)
|
||||
cpu.ntsc_clock_rate = 21477272
|
||||
|
||||
# PAL S-CPU clock rate (in hz)
|
||||
# (default = 21281370)
|
||||
cpu.pal_clock_rate = 21281370
|
||||
|
||||
# NTSC S-SMP clock rate (in hz)
|
||||
# (default = 24606720)
|
||||
smp.ntsc_clock_rate = 24606720
|
||||
|
||||
# PAL S-SMP clock rate (in hz)
|
||||
# (default = 24606720)
|
||||
smp.pal_clock_rate = 24606720
|
||||
|
||||
# Approximate HCLOCK position to render at for scanline-based renderers
|
||||
# (default = 512)
|
||||
ppu.hack.render_scanline_position = 512
|
||||
|
||||
# Cache OAM OBJ attributes one scanline before rendering
|
||||
# This is technically closer to the actual operation of the SNES,
|
||||
# but can cause problems in many games if enabled
|
||||
# (default = false)
|
||||
ppu.hack.obj_cache = false
|
||||
|
||||
# Video hardware interface
|
||||
# (default = "")
|
||||
system.video = ""
|
||||
|
||||
# Audio hardware interface
|
||||
# (default = "")
|
||||
system.audio = ""
|
||||
|
||||
# Input hardware interface
|
||||
# (default = "")
|
||||
system.input = ""
|
||||
|
||||
# Regulate speed to 60hz (NTSC) / 50hz (PAL)
|
||||
# (default = true)
|
||||
system.regulate_speed = true
|
||||
|
||||
# Slowest speed setting (in hz)
|
||||
# (default = 16000)
|
||||
system.speed_slowest = 16000
|
||||
|
||||
# Slow speed setting
|
||||
# (default = 24000)
|
||||
system.speed_slow = 24000
|
||||
|
||||
# Normal speed setting
|
||||
# (default = 32000)
|
||||
system.speed_normal = 32000
|
||||
|
||||
# Fast speed setting
|
||||
# (default = 48000)
|
||||
system.speed_fast = 48000
|
||||
|
||||
# Fastest speed setting
|
||||
# (default = 64000)
|
||||
system.speed_fastest = 64000
|
||||
|
||||
# Windowed video profile configuration
|
||||
# If available, please use bsnes GUI configuration editor to modify video profile settings
|
||||
# Format: software_filter;hardware_filter;video_standard;multiplier;correct_aspect_ratio;
|
||||
# enable_scanlines;manual_render_size;render_width;render_height;
|
||||
# triple_buffering;resolution_width;resolution_height;refresh_rate
|
||||
# (default = "0;1;0;2;true;false;false;595;448;false;0;0;0")
|
||||
video.profile_win = "0;1;0;2;true;false;false;595;448;false;0;0;0"
|
||||
|
||||
# Fullscreen video profile configuration
|
||||
# (default = "0;1;0;2;true;false;false;595;448;false;0;0;0")
|
||||
video.profile_full = "0;1;0;2;true;false;false;595;448;false;0;0;0"
|
||||
|
||||
# Use Video RAM instead of System RAM
|
||||
# (default = true)
|
||||
video.use_vram = true
|
||||
|
||||
# Progressive scanline intensity
|
||||
# Value is percentage of intensity from 0 to 100
|
||||
# (default = 30)
|
||||
video.pscanline_intensity = 30
|
||||
|
||||
# Interlace scanline intensity
|
||||
# (default = 50)
|
||||
video.iscanline_intensity = 50
|
||||
|
||||
# Axis resistance for all analog joypads
|
||||
# Affects responsiveness of analog stick movement by specifying what percentage
|
||||
# in any given direction the axis must be pressed to trigger a button press.
|
||||
# In other words, this determines how hard you have to press the analog stick to
|
||||
# simulate pressing e.g. left or right on a digital joypad.
|
||||
# Value is a percentage, from 0 (axis will trigger with virtually any axis movement)
|
||||
# up to 100 (axis must be pressed fully to given corner).
|
||||
# Value affects all four directions of the axis equally.
|
||||
# Note: Values below 10 or above 90 are not recommended and may not work at all.
|
||||
# (default = 75)
|
||||
input.axis_resistance = 75
|
||||
|
||||
# Allow up+down and left+right key combinations for joypad 1 (not recommended)
|
||||
# (default = false)
|
||||
input.joypad1.allow_invalid_input = false
|
||||
|
||||
# Joypad 1 button map
|
||||
# Format: Up; Down; Left; Right; A; B; X; Y; L; R; Select; Start
|
||||
# (default = "up | joypad0.up; down | joypad0.down; left | joypad0.left; right | joypad0.right; x | joypad0.button3; z | joypad0.button2; s | joypad0.button1; a | joypad0.button0; d | joypad0.button6; c | joypad0.button7; rshift | joypad0.button4; enter | joypad0.button5")
|
||||
input.joypad1.map = "up | joypad0.up; down | joypad0.down; left | joypad0.left; right | joypad0.right; x | joypad0.button3; z | joypad0.button2; s | joypad0.button1; a | joypad0.button0; d | joypad0.button6; c | joypad0.button7; rshift | joypad0.button4; enter | joypad0.button5"
|
||||
|
||||
# Allow up+down and left+right key combinations for joypad 2 (not recommended)
|
||||
# (default = false)
|
||||
input.joypad2.allow_invalid_input = false
|
||||
|
||||
# Joypad 2 button map
|
||||
# Format: Up; Down; Left; Right; A; B; X; Y; L; R; Select; Start
|
||||
# (default = "t | joypad1.up; g | joypad1.down; f | joypad1.left; h | joypad1.right; k | joypad1.button3; j | joypad1.button2; i | joypad1.button1; u | joypad1.button0; o | joypad1.button6; l | joypad1.button7; lbracket | joypad1.button4; rbracket | joypad1.button5")
|
||||
input.joypad2.map = "t | joypad1.up; g | joypad1.down; f | joypad1.left; h | joypad1.right; k | joypad1.button3; j | joypad1.button2; i | joypad1.button1; u | joypad1.button0; o | joypad1.button6; l | joypad1.button7; lbracket | joypad1.button4; rbracket | joypad1.button5"
|
||||
|
|
@ -128,8 +128,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);
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
@make -r PLATFORM=win-visualc
|
||||
@make -r PLATFORM=win-visualc-lui
|
||||
@move bsnes.exe ../bsnes.exe>nul
|
||||
@pause
|
|
@ -277,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);
|
||||
|
|
|
@ -28,6 +28,7 @@ understood.
|
|||
|
||||
************************************************************************/
|
||||
|
||||
typedef uint8_t bool8;
|
||||
|
||||
class SDD1_IM { //Input Manager
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
@make PLATFORM=win-visualc clean
|
||||
@make PLATFORM=win-visualc-lui clean
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#!/bin/sh
|
||||
gmake PLATFORM=x-gcc-lui clean
|
||||
make PLATFORM=x-gcc-lui clean
|
|
@ -25,83 +25,83 @@ 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_file, "path.rom",
|
||||
"Default path to look for ROM files in (\"\" = use default directory)", "");
|
||||
Setting Path::save(&config_file, "path.save",
|
||||
StringSetting Path::save(&config_file, "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_file, "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_file, "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_file, "snes.colorfilter.gamma_ramp",
|
||||
"Use precalculated TV-style gamma ramp", IntegerSetting::Boolean, true);
|
||||
IntegerSetting SNES::sepia(&config_file, "snes.colorfilter.sepia",
|
||||
"Convert color to sepia tone", IntegerSetting::Boolean, false);
|
||||
IntegerSetting SNES::grayscale(&config_file, "snes.colorfilter.grayscale",
|
||||
"Convert color to grayscale tone", IntegerSetting::Boolean, false);
|
||||
IntegerSetting SNES::invert(&config_file, "snes.colorfilter.invert",
|
||||
"Invert output image colors", IntegerSetting::Boolean, false);
|
||||
IntegerSetting SNES::contrast(&config_file, "snes.colorfilter.contrast",
|
||||
"Contrast", IntegerSetting::Decimal, 0);
|
||||
IntegerSetting SNES::brightness(&config_file, "snes.colorfilter.brightness",
|
||||
"Brightness", IntegerSetting::Decimal, 0);
|
||||
IntegerSetting SNES::gamma(&config_file, "snes.colorfilter.gamma",
|
||||
"Gamma", IntegerSetting::Decimal, 80);
|
||||
|
||||
Setting SNES::ntsc_merge_fields(&config_file, "snes.ntsc_merge_fields",
|
||||
IntegerSetting SNES::ntsc_merge_fields(&config_file, "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_file, "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_file, "snes.controller_port_1",
|
||||
"Controller attached to SNES port 1", IntegerSetting::Decimal, ::SNES::DEVICEID_JOYPAD1);
|
||||
IntegerSetting SNES::controller_port1(&config_file, "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_file, "cpu.ntsc_clock_rate",
|
||||
"NTSC S-CPU clock rate (in hz)", IntegerSetting::Decimal, 21477272);
|
||||
IntegerSetting CPU::pal_clock_rate(&config_file, "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_file, "smp.ntsc_clock_rate",
|
||||
"NTSC S-SMP clock rate (in hz)", IntegerSetting::Decimal, 24606720);
|
||||
IntegerSetting SMP::pal_clock_rate(&config_file, "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_file, "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_file, "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);
|
||||
|
||||
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);
|
||||
|
||||
};
|
||||
|
|
|
@ -5,40 +5,40 @@ namespace 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;
|
||||
} hack;
|
||||
|
||||
static Setting opt_enable;
|
||||
static Setting bg1_pri0_enable, bg1_pri1_enable;
|
||||
static Setting bg2_pri0_enable, bg2_pri1_enable;
|
||||
static Setting bg3_pri0_enable, bg3_pri1_enable;
|
||||
static Setting bg4_pri0_enable, bg4_pri1_enable;
|
||||
static Setting oam_pri0_enable, oam_pri1_enable;
|
||||
static Setting oam_pri2_enable, oam_pri3_enable;
|
||||
static IntegerSetting opt_enable;
|
||||
static IntegerSetting bg1_pri0_enable, bg1_pri1_enable;
|
||||
static IntegerSetting bg2_pri0_enable, bg2_pri1_enable;
|
||||
static IntegerSetting bg3_pri0_enable, bg3_pri1_enable;
|
||||
static IntegerSetting bg4_pri0_enable, bg4_pri1_enable;
|
||||
static IntegerSetting oam_pri0_enable, oam_pri1_enable;
|
||||
static IntegerSetting oam_pri2_enable, oam_pri3_enable;
|
||||
} ppu;
|
||||
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ public:
|
|||
union {
|
||||
uint8 data;
|
||||
struct {
|
||||
uint8 order_msb8(n:1, v:1, m:1, x:1, d:1, i:1, z:1, c:1);
|
||||
bool order_msb8(n:1, v:1, m:1, x:1, d:1, i:1, z:1, c:1);
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -1,33 +1,31 @@
|
|||
#include "opfn.cpp"
|
||||
|
||||
void sCPU::enter() {
|
||||
for(;;) {
|
||||
if(event.irq) {
|
||||
event.irq = false;
|
||||
if(status.nmi_pending == true) {
|
||||
status.nmi_pending = false;
|
||||
event.irq_vector = (regs.e == false) ? 0xffea : 0xfffa;
|
||||
} else if(status.irq_pending == true) {
|
||||
status.irq_pending = false;
|
||||
event.irq_vector = (regs.e == false) ? 0xffee : 0xfffe;
|
||||
}
|
||||
op_irq();
|
||||
#include "op_read.cpp"
|
||||
#include "op_write.cpp"
|
||||
#include "op_rmw.cpp"
|
||||
#include "op_pc.cpp"
|
||||
#include "op_misc.cpp"
|
||||
|
||||
void sCPU::enter() { loop:
|
||||
if(event.irq) {
|
||||
event.irq = false;
|
||||
if(status.nmi_pending == true) {
|
||||
status.nmi_pending = false;
|
||||
event.irq_vector = (regs.e == false) ? 0xffea : 0xfffa;
|
||||
} else if(status.irq_pending == true) {
|
||||
status.irq_pending = false;
|
||||
event.irq_vector = (regs.e == false) ? 0xffee : 0xfffe;
|
||||
}
|
||||
|
||||
tracer.trace_cpuop(); //traces CPU opcode (only if tracer is enabled)
|
||||
|
||||
status.in_opcode = true;
|
||||
|
||||
switch(op_readpc()) {
|
||||
#include "op_read.cpp"
|
||||
#include "op_write.cpp"
|
||||
#include "op_rmw.cpp"
|
||||
#include "op_pc.cpp"
|
||||
#include "op_misc.cpp"
|
||||
}
|
||||
|
||||
status.in_opcode = false;
|
||||
op_irq();
|
||||
}
|
||||
|
||||
tracer.trace_cpuop(); //traces CPU opcode (only if tracer is enabled)
|
||||
|
||||
status.in_opcode = true;
|
||||
(this->*optbl[op_readpc()])();
|
||||
status.in_opcode = false;
|
||||
|
||||
goto loop;
|
||||
}
|
||||
|
||||
void sCPU::op_irq() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//void (sCPU::*optbl[256])();
|
||||
void (sCPU::*optbl[256])();
|
||||
|
||||
CPUReg24 aa, rd;
|
||||
uint8 dp, sp;
|
||||
|
@ -54,4 +54,4 @@ uint8 dp, sp;
|
|||
void op_io_cond4(uint16 x, uint16 y);
|
||||
void op_io_cond6(uint16 addr);
|
||||
|
||||
//#include "op.h"
|
||||
#include "op.h"
|
||||
|
|
|
@ -0,0 +1,256 @@
|
|||
void op_adc_const();
|
||||
void op_and_const();
|
||||
void op_cmp_const();
|
||||
void op_cpx_const();
|
||||
void op_cpy_const();
|
||||
void op_eor_const();
|
||||
void op_lda_const();
|
||||
void op_ldx_const();
|
||||
void op_ldy_const();
|
||||
void op_ora_const();
|
||||
void op_sbc_const();
|
||||
void op_adc_addr();
|
||||
void op_and_addr();
|
||||
void op_bit_addr();
|
||||
void op_cmp_addr();
|
||||
void op_cpx_addr();
|
||||
void op_cpy_addr();
|
||||
void op_eor_addr();
|
||||
void op_lda_addr();
|
||||
void op_ldx_addr();
|
||||
void op_ldy_addr();
|
||||
void op_ora_addr();
|
||||
void op_sbc_addr();
|
||||
void op_adc_addrx();
|
||||
void op_and_addrx();
|
||||
void op_bit_addrx();
|
||||
void op_cmp_addrx();
|
||||
void op_eor_addrx();
|
||||
void op_lda_addrx();
|
||||
void op_ldy_addrx();
|
||||
void op_ora_addrx();
|
||||
void op_sbc_addrx();
|
||||
void op_adc_addry();
|
||||
void op_and_addry();
|
||||
void op_cmp_addry();
|
||||
void op_eor_addry();
|
||||
void op_lda_addry();
|
||||
void op_ldx_addry();
|
||||
void op_ora_addry();
|
||||
void op_sbc_addry();
|
||||
void op_adc_long();
|
||||
void op_and_long();
|
||||
void op_cmp_long();
|
||||
void op_eor_long();
|
||||
void op_lda_long();
|
||||
void op_ora_long();
|
||||
void op_sbc_long();
|
||||
void op_adc_longx();
|
||||
void op_and_longx();
|
||||
void op_cmp_longx();
|
||||
void op_eor_longx();
|
||||
void op_lda_longx();
|
||||
void op_ora_longx();
|
||||
void op_sbc_longx();
|
||||
void op_adc_dp();
|
||||
void op_and_dp();
|
||||
void op_bit_dp();
|
||||
void op_cmp_dp();
|
||||
void op_cpx_dp();
|
||||
void op_cpy_dp();
|
||||
void op_eor_dp();
|
||||
void op_lda_dp();
|
||||
void op_ldx_dp();
|
||||
void op_ldy_dp();
|
||||
void op_ora_dp();
|
||||
void op_sbc_dp();
|
||||
void op_adc_dpx();
|
||||
void op_and_dpx();
|
||||
void op_bit_dpx();
|
||||
void op_cmp_dpx();
|
||||
void op_eor_dpx();
|
||||
void op_lda_dpx();
|
||||
void op_ldy_dpx();
|
||||
void op_ora_dpx();
|
||||
void op_sbc_dpx();
|
||||
void op_ldx_dpy();
|
||||
void op_adc_idp();
|
||||
void op_and_idp();
|
||||
void op_cmp_idp();
|
||||
void op_eor_idp();
|
||||
void op_lda_idp();
|
||||
void op_ora_idp();
|
||||
void op_sbc_idp();
|
||||
void op_adc_idpx();
|
||||
void op_and_idpx();
|
||||
void op_cmp_idpx();
|
||||
void op_eor_idpx();
|
||||
void op_lda_idpx();
|
||||
void op_ora_idpx();
|
||||
void op_sbc_idpx();
|
||||
void op_adc_idpy();
|
||||
void op_and_idpy();
|
||||
void op_cmp_idpy();
|
||||
void op_eor_idpy();
|
||||
void op_lda_idpy();
|
||||
void op_ora_idpy();
|
||||
void op_sbc_idpy();
|
||||
void op_adc_ildp();
|
||||
void op_and_ildp();
|
||||
void op_cmp_ildp();
|
||||
void op_eor_ildp();
|
||||
void op_lda_ildp();
|
||||
void op_ora_ildp();
|
||||
void op_sbc_ildp();
|
||||
void op_adc_ildpy();
|
||||
void op_and_ildpy();
|
||||
void op_cmp_ildpy();
|
||||
void op_eor_ildpy();
|
||||
void op_lda_ildpy();
|
||||
void op_ora_ildpy();
|
||||
void op_sbc_ildpy();
|
||||
void op_adc_sr();
|
||||
void op_and_sr();
|
||||
void op_cmp_sr();
|
||||
void op_eor_sr();
|
||||
void op_lda_sr();
|
||||
void op_ora_sr();
|
||||
void op_sbc_sr();
|
||||
void op_adc_isry();
|
||||
void op_and_isry();
|
||||
void op_cmp_isry();
|
||||
void op_eor_isry();
|
||||
void op_lda_isry();
|
||||
void op_ora_isry();
|
||||
void op_sbc_isry();
|
||||
void op_bit_const();
|
||||
void op_sta_addr();
|
||||
void op_stx_addr();
|
||||
void op_sty_addr();
|
||||
void op_stz_addr();
|
||||
void op_sta_addrx();
|
||||
void op_stz_addrx();
|
||||
void op_sta_addry();
|
||||
void op_sta_long();
|
||||
void op_sta_longx();
|
||||
void op_sta_dp();
|
||||
void op_stx_dp();
|
||||
void op_sty_dp();
|
||||
void op_stz_dp();
|
||||
void op_sta_dpx();
|
||||
void op_sty_dpx();
|
||||
void op_stz_dpx();
|
||||
void op_stx_dpy();
|
||||
void op_sta_idp();
|
||||
void op_sta_ildp();
|
||||
void op_sta_idpx();
|
||||
void op_sta_idpy();
|
||||
void op_sta_ildpy();
|
||||
void op_sta_sr();
|
||||
void op_sta_isry();
|
||||
void op_inc();
|
||||
void op_inx();
|
||||
void op_iny();
|
||||
void op_dec();
|
||||
void op_dex();
|
||||
void op_dey();
|
||||
void op_asl();
|
||||
void op_lsr();
|
||||
void op_rol();
|
||||
void op_ror();
|
||||
void op_inc_addr();
|
||||
void op_dec_addr();
|
||||
void op_asl_addr();
|
||||
void op_lsr_addr();
|
||||
void op_rol_addr();
|
||||
void op_ror_addr();
|
||||
void op_trb_addr();
|
||||
void op_tsb_addr();
|
||||
void op_inc_addrx();
|
||||
void op_dec_addrx();
|
||||
void op_asl_addrx();
|
||||
void op_lsr_addrx();
|
||||
void op_rol_addrx();
|
||||
void op_ror_addrx();
|
||||
void op_inc_dp();
|
||||
void op_dec_dp();
|
||||
void op_asl_dp();
|
||||
void op_lsr_dp();
|
||||
void op_rol_dp();
|
||||
void op_ror_dp();
|
||||
void op_trb_dp();
|
||||
void op_tsb_dp();
|
||||
void op_inc_dpx();
|
||||
void op_dec_dpx();
|
||||
void op_asl_dpx();
|
||||
void op_lsr_dpx();
|
||||
void op_rol_dpx();
|
||||
void op_ror_dpx();
|
||||
void op_bcc();
|
||||
void op_bcs();
|
||||
void op_bne();
|
||||
void op_beq();
|
||||
void op_bpl();
|
||||
void op_bmi();
|
||||
void op_bvc();
|
||||
void op_bvs();
|
||||
void op_bra();
|
||||
void op_brl();
|
||||
void op_jmp_addr();
|
||||
void op_jmp_long();
|
||||
void op_jmp_iaddr();
|
||||
void op_jmp_iaddrx();
|
||||
void op_jmp_iladdr();
|
||||
void op_jsr_addr();
|
||||
void op_jsr_long();
|
||||
void op_jsr_iaddrx();
|
||||
void op_rti();
|
||||
void op_rts();
|
||||
void op_rtl();
|
||||
void op_nop();
|
||||
void op_wdm();
|
||||
void op_xba();
|
||||
void op_mvn();
|
||||
void op_mvp();
|
||||
void op_brk();
|
||||
void op_cop();
|
||||
void op_stp();
|
||||
void op_wai();
|
||||
void op_xce();
|
||||
void op_clc();
|
||||
void op_cld();
|
||||
void op_cli();
|
||||
void op_clv();
|
||||
void op_sec();
|
||||
void op_sed();
|
||||
void op_sei();
|
||||
void op_rep();
|
||||
void op_sep();
|
||||
void op_tax();
|
||||
void op_tay();
|
||||
void op_txa();
|
||||
void op_txy();
|
||||
void op_tya();
|
||||
void op_tyx();
|
||||
void op_tcd();
|
||||
void op_tcs();
|
||||
void op_tdc();
|
||||
void op_tsc();
|
||||
void op_tsx();
|
||||
void op_txs();
|
||||
void op_pha();
|
||||
void op_phx();
|
||||
void op_phy();
|
||||
void op_phd();
|
||||
void op_phb();
|
||||
void op_phk();
|
||||
void op_php();
|
||||
void op_pla();
|
||||
void op_plx();
|
||||
void op_ply();
|
||||
void op_pld();
|
||||
void op_plb();
|
||||
void op_plp();
|
||||
void op_pea();
|
||||
void op_pei();
|
||||
void op_per();
|
|
@ -62,14 +62,14 @@ stp(0xdb) {
|
|||
}
|
||||
|
||||
wai(0xcb) {
|
||||
1:op_io();
|
||||
event.wai = true;
|
||||
2:last_cycle();
|
||||
op_io();
|
||||
3:while(event.wai) {
|
||||
//last_cycle() will set event.wai to false
|
||||
//once an NMI / IRQ edge is reached
|
||||
1:event.wai = true;
|
||||
while(event.wai) {
|
||||
last_cycle();
|
||||
op_io();
|
||||
}
|
||||
2:op_io();
|
||||
}
|
||||
|
||||
xce(0xfb) {
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
//nop
|
||||
case 0xea: {
|
||||
void sCPU::op_nop() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//wdm
|
||||
case 0x42: {
|
||||
void sCPU::op_wdm() {
|
||||
last_cycle();
|
||||
op_readpc();
|
||||
} break;
|
||||
}
|
||||
|
||||
//xba
|
||||
case 0xeb: {
|
||||
void sCPU::op_xba() {
|
||||
op_io();
|
||||
last_cycle();
|
||||
op_io();
|
||||
|
@ -20,10 +17,9 @@ case 0xeb: {
|
|||
regs.a.l ^= regs.a.h;
|
||||
regs.p.n = !!(regs.a.l & 0x80);
|
||||
regs.p.z = (regs.a.l == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mvn
|
||||
case 0x54: {
|
||||
void sCPU::op_mvn() {
|
||||
dp = op_readpc();
|
||||
sp = op_readpc();
|
||||
regs.db = dp;
|
||||
|
@ -40,10 +36,9 @@ case 0x54: {
|
|||
last_cycle();
|
||||
op_io();
|
||||
if(regs.a.w--)regs.pc.w -= 3;
|
||||
} break;
|
||||
}
|
||||
|
||||
//mvp
|
||||
case 0x44: {
|
||||
void sCPU::op_mvp() {
|
||||
dp = op_readpc();
|
||||
sp = op_readpc();
|
||||
regs.db = dp;
|
||||
|
@ -60,10 +55,9 @@ case 0x44: {
|
|||
last_cycle();
|
||||
op_io();
|
||||
if(regs.a.w--)regs.pc.w -= 3;
|
||||
} break;
|
||||
}
|
||||
|
||||
//brk
|
||||
case 0x00: {
|
||||
void sCPU::op_brk() {
|
||||
op_readpc();
|
||||
if(!regs.e)op_writestack(regs.pc.b);
|
||||
op_writestack(regs.pc.h);
|
||||
|
@ -76,10 +70,9 @@ case 0x00: {
|
|||
last_cycle();
|
||||
rd.h = op_readlong((regs.e) ? 0xffff : 0xffe7);
|
||||
regs.pc.w = rd.w;
|
||||
} break;
|
||||
}
|
||||
|
||||
//cop
|
||||
case 0x02: {
|
||||
void sCPU::op_cop() {
|
||||
op_readpc();
|
||||
if(!regs.e)op_writestack(regs.pc.b);
|
||||
op_writestack(regs.pc.h);
|
||||
|
@ -92,29 +85,26 @@ case 0x02: {
|
|||
last_cycle();
|
||||
rd.h = op_readlong((regs.e) ? 0xfff5 : 0xffe5);
|
||||
regs.pc.w = rd.w;
|
||||
} break;
|
||||
}
|
||||
|
||||
//stp
|
||||
case 0xdb: {
|
||||
void sCPU::op_stp() {
|
||||
op_io();
|
||||
last_cycle();
|
||||
while(1) { op_io(); }
|
||||
} break;
|
||||
}
|
||||
|
||||
//wai
|
||||
case 0xcb: {
|
||||
op_io();
|
||||
void sCPU::op_wai() {
|
||||
//last_cycle() will set event.wai to false
|
||||
//once an NMI / IRQ edge is reached
|
||||
event.wai = true;
|
||||
last_cycle();
|
||||
op_io();
|
||||
while(event.wai) {
|
||||
last_cycle();
|
||||
op_io();
|
||||
}
|
||||
} break;
|
||||
op_io();
|
||||
}
|
||||
|
||||
//xce
|
||||
case 0xfb: {
|
||||
void sCPU::op_xce() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
bool carry = regs.p.c;
|
||||
|
@ -128,59 +118,51 @@ bool carry = regs.p.c;
|
|||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//clc
|
||||
case 0x18: {
|
||||
void sCPU::op_clc() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.p.c = 0;
|
||||
} break;
|
||||
}
|
||||
|
||||
//cld
|
||||
case 0xd8: {
|
||||
void sCPU::op_cld() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.p.d = 0;
|
||||
} break;
|
||||
}
|
||||
|
||||
//cli
|
||||
case 0x58: {
|
||||
void sCPU::op_cli() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.p.i = 0;
|
||||
} break;
|
||||
}
|
||||
|
||||
//clv
|
||||
case 0xb8: {
|
||||
void sCPU::op_clv() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.p.v = 0;
|
||||
} break;
|
||||
}
|
||||
|
||||
//sec
|
||||
case 0x38: {
|
||||
void sCPU::op_sec() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.p.c = 1;
|
||||
} break;
|
||||
}
|
||||
|
||||
//sed
|
||||
case 0xf8: {
|
||||
void sCPU::op_sed() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.p.d = 1;
|
||||
} break;
|
||||
}
|
||||
|
||||
//sei
|
||||
case 0x78: {
|
||||
void sCPU::op_sei() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.p.i = 1;
|
||||
} break;
|
||||
}
|
||||
|
||||
//rep
|
||||
case 0xc2: {
|
||||
void sCPU::op_rep() {
|
||||
rd.l = op_readpc();
|
||||
last_cycle();
|
||||
op_io();
|
||||
|
@ -190,10 +172,9 @@ case 0xc2: {
|
|||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//sep
|
||||
case 0xe2: {
|
||||
void sCPU::op_sep() {
|
||||
rd.l = op_readpc();
|
||||
last_cycle();
|
||||
op_io();
|
||||
|
@ -203,10 +184,9 @@ case 0xe2: {
|
|||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//tax
|
||||
case 0xaa: {
|
||||
void sCPU::op_tax() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.x) {
|
||||
|
@ -218,10 +198,9 @@ case 0xaa: {
|
|||
regs.p.n = !!(regs.x.w & 0x8000);
|
||||
regs.p.z = (regs.x.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//tay
|
||||
case 0xa8: {
|
||||
void sCPU::op_tay() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.x) {
|
||||
|
@ -233,10 +212,9 @@ case 0xa8: {
|
|||
regs.p.n = !!(regs.y.w & 0x8000);
|
||||
regs.p.z = (regs.y.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//txa
|
||||
case 0x8a: {
|
||||
void sCPU::op_txa() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.m) {
|
||||
|
@ -248,10 +226,9 @@ case 0x8a: {
|
|||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//txy
|
||||
case 0x9b: {
|
||||
void sCPU::op_txy() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.x) {
|
||||
|
@ -263,10 +240,9 @@ case 0x9b: {
|
|||
regs.p.n = !!(regs.y.w & 0x8000);
|
||||
regs.p.z = (regs.y.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//tya
|
||||
case 0x98: {
|
||||
void sCPU::op_tya() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.m) {
|
||||
|
@ -278,10 +254,9 @@ case 0x98: {
|
|||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//tyx
|
||||
case 0xbb: {
|
||||
void sCPU::op_tyx() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.x) {
|
||||
|
@ -293,36 +268,32 @@ case 0xbb: {
|
|||
regs.p.n = !!(regs.x.w & 0x8000);
|
||||
regs.p.z = (regs.x.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcd
|
||||
case 0x5b: {
|
||||
void sCPU::op_tcd() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.d.w = regs.a.w;
|
||||
regs.p.n = !!(regs.d.w & 0x8000);
|
||||
regs.p.z = (regs.d.w == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcs
|
||||
case 0x1b: {
|
||||
void sCPU::op_tcs() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.s.w = regs.a.w;
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
} break;
|
||||
}
|
||||
|
||||
//tdc
|
||||
case 0x7b: {
|
||||
void sCPU::op_tdc() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.a.w = regs.d.w;
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//tsc
|
||||
case 0x3b: {
|
||||
void sCPU::op_tsc() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.a.w = regs.s.w;
|
||||
|
@ -333,10 +304,9 @@ case 0x3b: {
|
|||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//tsx
|
||||
case 0xba: {
|
||||
void sCPU::op_tsx() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.x) {
|
||||
|
@ -348,10 +318,9 @@ case 0xba: {
|
|||
regs.p.n = !!(regs.x.w & 0x8000);
|
||||
regs.p.z = (regs.x.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//txs
|
||||
case 0x9a: {
|
||||
void sCPU::op_txs() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.e) {
|
||||
|
@ -359,64 +328,56 @@ case 0x9a: {
|
|||
} else {
|
||||
regs.s.w = regs.x.w;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//pha
|
||||
case 0x48: {
|
||||
void sCPU::op_pha() {
|
||||
op_io();
|
||||
if(!regs.p.m)op_writestack(regs.a.h);
|
||||
last_cycle();
|
||||
op_writestack(regs.a.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//phx
|
||||
case 0xda: {
|
||||
void sCPU::op_phx() {
|
||||
op_io();
|
||||
if(!regs.p.x)op_writestack(regs.x.h);
|
||||
last_cycle();
|
||||
op_writestack(regs.x.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//phy
|
||||
case 0x5a: {
|
||||
void sCPU::op_phy() {
|
||||
op_io();
|
||||
if(!regs.p.x)op_writestack(regs.y.h);
|
||||
last_cycle();
|
||||
op_writestack(regs.y.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//phd
|
||||
case 0x0b: {
|
||||
void sCPU::op_phd() {
|
||||
op_io();
|
||||
op_writestackn(regs.d.h);
|
||||
last_cycle();
|
||||
op_writestackn(regs.d.l);
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
} break;
|
||||
}
|
||||
|
||||
//phb
|
||||
case 0x8b: {
|
||||
void sCPU::op_phb() {
|
||||
op_io();
|
||||
last_cycle();
|
||||
op_writestack(regs.db);
|
||||
} break;
|
||||
}
|
||||
|
||||
//phk
|
||||
case 0x4b: {
|
||||
void sCPU::op_phk() {
|
||||
op_io();
|
||||
last_cycle();
|
||||
op_writestack(regs.pc.b);
|
||||
} break;
|
||||
}
|
||||
|
||||
//php
|
||||
case 0x08: {
|
||||
void sCPU::op_php() {
|
||||
op_io();
|
||||
last_cycle();
|
||||
op_writestack(regs.p);
|
||||
} break;
|
||||
}
|
||||
|
||||
//pla
|
||||
case 0x68: {
|
||||
void sCPU::op_pla() {
|
||||
op_io();
|
||||
op_io();
|
||||
if(regs.p.m)last_cycle();
|
||||
|
@ -424,16 +385,15 @@ case 0x68: {
|
|||
if(regs.p.m) {
|
||||
regs.p.n = !!(regs.a.l & 0x80);
|
||||
regs.p.z = (regs.a.l == 0);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
last_cycle();
|
||||
regs.a.h = op_readstack();
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//plx
|
||||
case 0xfa: {
|
||||
void sCPU::op_plx() {
|
||||
op_io();
|
||||
op_io();
|
||||
if(regs.p.x)last_cycle();
|
||||
|
@ -441,16 +401,15 @@ case 0xfa: {
|
|||
if(regs.p.x) {
|
||||
regs.p.n = !!(regs.x.l & 0x80);
|
||||
regs.p.z = (regs.x.l == 0);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
last_cycle();
|
||||
regs.x.h = op_readstack();
|
||||
regs.p.n = !!(regs.x.w & 0x8000);
|
||||
regs.p.z = (regs.x.w == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//ply
|
||||
case 0x7a: {
|
||||
void sCPU::op_ply() {
|
||||
op_io();
|
||||
op_io();
|
||||
if(regs.p.x)last_cycle();
|
||||
|
@ -458,16 +417,15 @@ case 0x7a: {
|
|||
if(regs.p.x) {
|
||||
regs.p.n = !!(regs.y.l & 0x80);
|
||||
regs.p.z = (regs.y.l == 0);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
last_cycle();
|
||||
regs.y.h = op_readstack();
|
||||
regs.p.n = !!(regs.y.w & 0x8000);
|
||||
regs.p.z = (regs.y.w == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//pld
|
||||
case 0x2b: {
|
||||
void sCPU::op_pld() {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.d.l = op_readstackn();
|
||||
|
@ -476,20 +434,18 @@ case 0x2b: {
|
|||
regs.p.n = !!(regs.d.w & 0x8000);
|
||||
regs.p.z = (regs.d.w == 0);
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
} break;
|
||||
}
|
||||
|
||||
//plb
|
||||
case 0xab: {
|
||||
void sCPU::op_plb() {
|
||||
op_io();
|
||||
op_io();
|
||||
last_cycle();
|
||||
regs.db = op_readstack();
|
||||
regs.p.n = !!(regs.db & 0x80);
|
||||
regs.p.z = (regs.db == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//plp
|
||||
case 0x28: {
|
||||
void sCPU::op_plp() {
|
||||
op_io();
|
||||
op_io();
|
||||
last_cycle();
|
||||
|
@ -499,20 +455,18 @@ case 0x28: {
|
|||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//pea
|
||||
case 0xf4: {
|
||||
void sCPU::op_pea() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_writestackn(aa.h);
|
||||
last_cycle();
|
||||
op_writestackn(aa.l);
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
} break;
|
||||
}
|
||||
|
||||
//pei
|
||||
case 0xd4: {
|
||||
void sCPU::op_pei() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
aa.l = op_readdp(dp);
|
||||
|
@ -521,10 +475,9 @@ case 0xd4: {
|
|||
last_cycle();
|
||||
op_writestackn(aa.l);
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
} break;
|
||||
}
|
||||
|
||||
//per
|
||||
case 0x62: {
|
||||
void sCPU::op_per() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
|
@ -533,5 +486,5 @@ case 0x62: {
|
|||
last_cycle();
|
||||
op_writestackn(rd.l);
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
} break;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,171 +1,157 @@
|
|||
//bcc
|
||||
case 0x90: {
|
||||
void sCPU::op_bcc() {
|
||||
if(!!regs.p.c)last_cycle();
|
||||
rd.l = op_readpc();
|
||||
if(!regs.p.c) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
op_io_cond6(aa.w);
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//bcs
|
||||
case 0xb0: {
|
||||
void sCPU::op_bcs() {
|
||||
if(!regs.p.c)last_cycle();
|
||||
rd.l = op_readpc();
|
||||
if(regs.p.c) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
op_io_cond6(aa.w);
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//bne
|
||||
case 0xd0: {
|
||||
void sCPU::op_bne() {
|
||||
if(!!regs.p.z)last_cycle();
|
||||
rd.l = op_readpc();
|
||||
if(!regs.p.z) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
op_io_cond6(aa.w);
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//beq
|
||||
case 0xf0: {
|
||||
void sCPU::op_beq() {
|
||||
if(!regs.p.z)last_cycle();
|
||||
rd.l = op_readpc();
|
||||
if(regs.p.z) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
op_io_cond6(aa.w);
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//bpl
|
||||
case 0x10: {
|
||||
void sCPU::op_bpl() {
|
||||
if(!!regs.p.n)last_cycle();
|
||||
rd.l = op_readpc();
|
||||
if(!regs.p.n) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
op_io_cond6(aa.w);
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//bmi
|
||||
case 0x30: {
|
||||
void sCPU::op_bmi() {
|
||||
if(!regs.p.n)last_cycle();
|
||||
rd.l = op_readpc();
|
||||
if(regs.p.n) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
op_io_cond6(aa.w);
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//bvc
|
||||
case 0x50: {
|
||||
void sCPU::op_bvc() {
|
||||
if(!!regs.p.v)last_cycle();
|
||||
rd.l = op_readpc();
|
||||
if(!regs.p.v) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
op_io_cond6(aa.w);
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//bvs
|
||||
case 0x70: {
|
||||
void sCPU::op_bvs() {
|
||||
if(!regs.p.v)last_cycle();
|
||||
rd.l = op_readpc();
|
||||
if(regs.p.v) {
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
} else {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
op_io_cond6(aa.w);
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//bra
|
||||
case 0x80: {
|
||||
void sCPU::op_bra() {
|
||||
rd.l = op_readpc();
|
||||
aa.w = regs.pc.d + (int8)rd.l;
|
||||
regs.pc.w = aa.w;
|
||||
op_io_cond6(aa.w);
|
||||
last_cycle();
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//brl
|
||||
case 0x82: {
|
||||
void sCPU::op_brl() {
|
||||
rd.l = op_readpc();
|
||||
rd.h = op_readpc();
|
||||
last_cycle();
|
||||
op_io();
|
||||
regs.pc.w = regs.pc.d + (int16)rd.w;
|
||||
} break;
|
||||
}
|
||||
|
||||
//jmp_addr
|
||||
case 0x4c: {
|
||||
void sCPU::op_jmp_addr() {
|
||||
rd.l = op_readpc();
|
||||
last_cycle();
|
||||
rd.h = op_readpc();
|
||||
regs.pc.w = rd.w;
|
||||
} break;
|
||||
}
|
||||
|
||||
//jmp_long
|
||||
case 0x5c: {
|
||||
void sCPU::op_jmp_long() {
|
||||
rd.l = op_readpc();
|
||||
rd.h = op_readpc();
|
||||
last_cycle();
|
||||
rd.b = op_readpc();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
} break;
|
||||
}
|
||||
|
||||
//jmp_iaddr
|
||||
case 0x6c: {
|
||||
void sCPU::op_jmp_iaddr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readaddr(aa.w);
|
||||
last_cycle();
|
||||
rd.h = op_readaddr(aa.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
} break;
|
||||
}
|
||||
|
||||
//jmp_iaddrx
|
||||
case 0x7c: {
|
||||
void sCPU::op_jmp_iaddrx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
|
@ -173,10 +159,9 @@ case 0x7c: {
|
|||
last_cycle();
|
||||
rd.h = op_readpbr(aa.w + regs.x.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
} break;
|
||||
}
|
||||
|
||||
//jmp_iladdr
|
||||
case 0xdc: {
|
||||
void sCPU::op_jmp_iladdr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readaddr(aa.w);
|
||||
|
@ -184,10 +169,9 @@ case 0xdc: {
|
|||
last_cycle();
|
||||
rd.b = op_readaddr(aa.w + 2);
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
} break;
|
||||
}
|
||||
|
||||
//jsr_addr
|
||||
case 0x20: {
|
||||
void sCPU::op_jsr_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
|
@ -196,10 +180,9 @@ case 0x20: {
|
|||
last_cycle();
|
||||
op_writestack(regs.pc.l);
|
||||
regs.pc.w = aa.w;
|
||||
} break;
|
||||
}
|
||||
|
||||
//jsr_long
|
||||
case 0x22: {
|
||||
void sCPU::op_jsr_long() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_writestackn(regs.pc.b);
|
||||
|
@ -211,10 +194,9 @@ case 0x22: {
|
|||
op_writestackn(regs.pc.l);
|
||||
regs.pc.d = aa.d & 0xffffff;
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
} break;
|
||||
}
|
||||
|
||||
//jsr_iaddrx
|
||||
case 0xfc: {
|
||||
void sCPU::op_jsr_iaddrx() {
|
||||
aa.l = op_readpc();
|
||||
op_writestackn(regs.pc.h);
|
||||
op_writestackn(regs.pc.l);
|
||||
|
@ -225,10 +207,9 @@ case 0xfc: {
|
|||
rd.h = op_readpbr(aa.w + regs.x.w + 1);
|
||||
regs.pc.w = rd.w;
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
} break;
|
||||
}
|
||||
|
||||
//rti
|
||||
case 0x40: {
|
||||
void sCPU::op_rti() {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.p = op_readstack();
|
||||
|
@ -242,15 +223,14 @@ case 0x40: {
|
|||
rd.h = op_readstack();
|
||||
if(regs.e) {
|
||||
regs.pc.w = rd.w;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
last_cycle();
|
||||
rd.b = op_readstack();
|
||||
regs.pc.d = rd.d & 0xffffff;
|
||||
} break;
|
||||
}
|
||||
|
||||
//rts
|
||||
case 0x60: {
|
||||
void sCPU::op_rts() {
|
||||
op_io();
|
||||
op_io();
|
||||
rd.l = op_readstack();
|
||||
|
@ -259,10 +239,9 @@ case 0x60: {
|
|||
op_io();
|
||||
regs.pc.w = rd.w;
|
||||
regs.pc.w++;
|
||||
} break;
|
||||
}
|
||||
|
||||
//rtl
|
||||
case 0x6b: {
|
||||
void sCPU::op_rtl() {
|
||||
op_io();
|
||||
op_io();
|
||||
rd.l = op_readstackn();
|
||||
|
@ -272,5 +251,5 @@ case 0x6b: {
|
|||
regs.pc.d = rd.d & 0xffffff;
|
||||
regs.pc.w++;
|
||||
if(regs.e)regs.s.h = 0x01;
|
||||
} break;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,4 @@
|
|||
//inc
|
||||
case 0x1a: {
|
||||
void sCPU::op_inc() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.m) {
|
||||
|
@ -11,10 +10,9 @@ case 0x1a: {
|
|||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//inx
|
||||
case 0xe8: {
|
||||
void sCPU::op_inx() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.x) {
|
||||
|
@ -26,10 +24,9 @@ case 0xe8: {
|
|||
regs.p.n = !!(regs.x.w & 0x8000);
|
||||
regs.p.z = (regs.x.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//iny
|
||||
case 0xc8: {
|
||||
void sCPU::op_iny() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.x) {
|
||||
|
@ -41,10 +38,9 @@ case 0xc8: {
|
|||
regs.p.n = !!(regs.y.w & 0x8000);
|
||||
regs.p.z = (regs.y.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//dec
|
||||
case 0x3a: {
|
||||
void sCPU::op_dec() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.m) {
|
||||
|
@ -56,10 +52,9 @@ case 0x3a: {
|
|||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//dex
|
||||
case 0xca: {
|
||||
void sCPU::op_dex() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.x) {
|
||||
|
@ -71,10 +66,9 @@ case 0xca: {
|
|||
regs.p.n = !!(regs.x.w & 0x8000);
|
||||
regs.p.z = (regs.x.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//dey
|
||||
case 0x88: {
|
||||
void sCPU::op_dey() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.x) {
|
||||
|
@ -86,10 +80,9 @@ case 0x88: {
|
|||
regs.p.n = !!(regs.y.w & 0x8000);
|
||||
regs.p.z = (regs.y.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//asl
|
||||
case 0x0a: {
|
||||
void sCPU::op_asl() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.m) {
|
||||
|
@ -103,10 +96,9 @@ case 0x0a: {
|
|||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//lsr
|
||||
case 0x4a: {
|
||||
void sCPU::op_lsr() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
if(regs.p.m) {
|
||||
|
@ -120,10 +112,9 @@ case 0x4a: {
|
|||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//rol
|
||||
case 0x2a: {
|
||||
void sCPU::op_rol() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
uint16 c = regs.p.c;
|
||||
|
@ -140,10 +131,9 @@ case 0x2a: {
|
|||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//ror
|
||||
case 0x6a: {
|
||||
void sCPU::op_ror() {
|
||||
last_cycle();
|
||||
op_io();
|
||||
uint16 c;
|
||||
|
@ -162,10 +152,9 @@ case 0x6a: {
|
|||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//inc_addr
|
||||
case 0xee: {
|
||||
void sCPU::op_inc_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readdbr(aa.w);
|
||||
|
@ -176,10 +165,9 @@ case 0xee: {
|
|||
op_writedbr(aa.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//dec_addr
|
||||
case 0xce: {
|
||||
void sCPU::op_dec_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readdbr(aa.w);
|
||||
|
@ -190,10 +178,9 @@ case 0xce: {
|
|||
op_writedbr(aa.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//asl_addr
|
||||
case 0x0e: {
|
||||
void sCPU::op_asl_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readdbr(aa.w);
|
||||
|
@ -204,10 +191,9 @@ case 0x0e: {
|
|||
op_writedbr(aa.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//lsr_addr
|
||||
case 0x4e: {
|
||||
void sCPU::op_lsr_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readdbr(aa.w);
|
||||
|
@ -218,10 +204,9 @@ case 0x4e: {
|
|||
op_writedbr(aa.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//rol_addr
|
||||
case 0x2e: {
|
||||
void sCPU::op_rol_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readdbr(aa.w);
|
||||
|
@ -232,10 +217,9 @@ case 0x2e: {
|
|||
op_writedbr(aa.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//ror_addr
|
||||
case 0x6e: {
|
||||
void sCPU::op_ror_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readdbr(aa.w);
|
||||
|
@ -246,10 +230,9 @@ case 0x6e: {
|
|||
op_writedbr(aa.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//trb_addr
|
||||
case 0x1c: {
|
||||
void sCPU::op_trb_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readdbr(aa.w);
|
||||
|
@ -260,10 +243,9 @@ case 0x1c: {
|
|||
op_writedbr(aa.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//tsb_addr
|
||||
case 0x0c: {
|
||||
void sCPU::op_tsb_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
rd.l = op_readdbr(aa.w);
|
||||
|
@ -274,10 +256,9 @@ case 0x0c: {
|
|||
op_writedbr(aa.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//inc_addrx
|
||||
case 0xfe: {
|
||||
void sCPU::op_inc_addrx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
|
@ -289,10 +270,9 @@ case 0xfe: {
|
|||
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//dec_addrx
|
||||
case 0xde: {
|
||||
void sCPU::op_dec_addrx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
|
@ -304,10 +284,9 @@ case 0xde: {
|
|||
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//asl_addrx
|
||||
case 0x1e: {
|
||||
void sCPU::op_asl_addrx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
|
@ -319,10 +298,9 @@ case 0x1e: {
|
|||
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//lsr_addrx
|
||||
case 0x5e: {
|
||||
void sCPU::op_lsr_addrx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
|
@ -334,10 +312,9 @@ case 0x5e: {
|
|||
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//rol_addrx
|
||||
case 0x3e: {
|
||||
void sCPU::op_rol_addrx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
|
@ -349,10 +326,9 @@ case 0x3e: {
|
|||
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//ror_addrx
|
||||
case 0x7e: {
|
||||
void sCPU::op_ror_addrx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
|
@ -364,10 +340,9 @@ case 0x7e: {
|
|||
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//inc_dp
|
||||
case 0xe6: {
|
||||
void sCPU::op_inc_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
rd.l = op_readdp(dp);
|
||||
|
@ -378,10 +353,9 @@ case 0xe6: {
|
|||
op_writedp(dp + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//dec_dp
|
||||
case 0xc6: {
|
||||
void sCPU::op_dec_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
rd.l = op_readdp(dp);
|
||||
|
@ -392,10 +366,9 @@ case 0xc6: {
|
|||
op_writedp(dp + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//asl_dp
|
||||
case 0x06: {
|
||||
void sCPU::op_asl_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
rd.l = op_readdp(dp);
|
||||
|
@ -406,10 +379,9 @@ case 0x06: {
|
|||
op_writedp(dp + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//lsr_dp
|
||||
case 0x46: {
|
||||
void sCPU::op_lsr_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
rd.l = op_readdp(dp);
|
||||
|
@ -420,10 +392,9 @@ case 0x46: {
|
|||
op_writedp(dp + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//rol_dp
|
||||
case 0x26: {
|
||||
void sCPU::op_rol_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
rd.l = op_readdp(dp);
|
||||
|
@ -434,10 +405,9 @@ case 0x26: {
|
|||
op_writedp(dp + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//ror_dp
|
||||
case 0x66: {
|
||||
void sCPU::op_ror_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
rd.l = op_readdp(dp);
|
||||
|
@ -448,10 +418,9 @@ case 0x66: {
|
|||
op_writedp(dp + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//trb_dp
|
||||
case 0x14: {
|
||||
void sCPU::op_trb_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
rd.l = op_readdp(dp);
|
||||
|
@ -462,10 +431,9 @@ case 0x14: {
|
|||
op_writedp(dp + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//tsb_dp
|
||||
case 0x04: {
|
||||
void sCPU::op_tsb_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
rd.l = op_readdp(dp);
|
||||
|
@ -476,10 +444,9 @@ case 0x04: {
|
|||
op_writedp(dp + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//inc_dpx
|
||||
case 0xf6: {
|
||||
void sCPU::op_inc_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
|
@ -491,10 +458,9 @@ case 0xf6: {
|
|||
op_writedp(dp + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//dec_dpx
|
||||
case 0xd6: {
|
||||
void sCPU::op_dec_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
|
@ -506,10 +472,9 @@ case 0xd6: {
|
|||
op_writedp(dp + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//asl_dpx
|
||||
case 0x16: {
|
||||
void sCPU::op_asl_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
|
@ -521,10 +486,9 @@ case 0x16: {
|
|||
op_writedp(dp + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//lsr_dpx
|
||||
case 0x56: {
|
||||
void sCPU::op_lsr_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
|
@ -536,10 +500,9 @@ case 0x56: {
|
|||
op_writedp(dp + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//rol_dpx
|
||||
case 0x36: {
|
||||
void sCPU::op_rol_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
|
@ -551,10 +514,9 @@ case 0x36: {
|
|||
op_writedp(dp + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
//ror_dpx
|
||||
case 0x76: {
|
||||
void sCPU::op_ror_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
|
@ -566,5 +528,5 @@ case 0x76: {
|
|||
op_writedp(dp + regs.x.w + 1, rd.h); }
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.x.w, rd.l);
|
||||
} break;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,214 +1,195 @@
|
|||
//sta_addr
|
||||
case 0x8d: {
|
||||
void sCPU::op_sta_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w, regs.a.w);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + 1, regs.a.w >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//stx_addr
|
||||
case 0x8e: {
|
||||
void sCPU::op_stx_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
if(regs.p.x)last_cycle();
|
||||
op_writedbr(aa.w, regs.x.w);
|
||||
if(regs.p.x)break;
|
||||
if(regs.p.x)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + 1, regs.x.w >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sty_addr
|
||||
case 0x8c: {
|
||||
void sCPU::op_sty_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
if(regs.p.x)last_cycle();
|
||||
op_writedbr(aa.w, regs.y.w);
|
||||
if(regs.p.x)break;
|
||||
if(regs.p.x)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + 1, regs.y.w >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//stz_addr
|
||||
case 0x9c: {
|
||||
void sCPU::op_stz_addr() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w, 0x0000);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + 1, 0x0000 >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_addrx
|
||||
case 0x9d: {
|
||||
void sCPU::op_sta_addrx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, regs.a.w);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w + 1, regs.a.w >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//stz_addrx
|
||||
case 0x9e: {
|
||||
void sCPU::op_stz_addrx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w, 0x0000);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.x.w + 1, 0x0000 >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_addry
|
||||
case 0x99: {
|
||||
void sCPU::op_sta_addry() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
op_io();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.y.w + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_long
|
||||
case 0x8f: {
|
||||
void sCPU::op_sta_long() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
aa.b = op_readpc();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writelong(aa.d, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writelong(aa.d + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_longx
|
||||
case 0x9f: {
|
||||
void sCPU::op_sta_longx() {
|
||||
aa.l = op_readpc();
|
||||
aa.h = op_readpc();
|
||||
aa.b = op_readpc();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writelong(aa.d + regs.x.w, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writelong(aa.d + regs.x.w + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_dp
|
||||
case 0x85: {
|
||||
void sCPU::op_sta_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedp(dp, regs.a.w);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedp(dp + 1, regs.a.w >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//stx_dp
|
||||
case 0x86: {
|
||||
void sCPU::op_stx_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
if(regs.p.x)last_cycle();
|
||||
op_writedp(dp, regs.x.w);
|
||||
if(regs.p.x)break;
|
||||
if(regs.p.x)return;
|
||||
last_cycle();
|
||||
op_writedp(dp + 1, regs.x.w >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sty_dp
|
||||
case 0x84: {
|
||||
void sCPU::op_sty_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
if(regs.p.x)last_cycle();
|
||||
op_writedp(dp, regs.y.w);
|
||||
if(regs.p.x)break;
|
||||
if(regs.p.x)return;
|
||||
last_cycle();
|
||||
op_writedp(dp + 1, regs.y.w >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//stz_dp
|
||||
case 0x64: {
|
||||
void sCPU::op_stz_dp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedp(dp, 0x0000);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedp(dp + 1, 0x0000 >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_dpx
|
||||
case 0x95: {
|
||||
void sCPU::op_sta_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedp(dp + regs.x.w, regs.a.w);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.x.w + 1, regs.a.w >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sty_dpx
|
||||
case 0x94: {
|
||||
void sCPU::op_sty_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
if(regs.p.x)last_cycle();
|
||||
op_writedp(dp + regs.x.w, regs.y.w);
|
||||
if(regs.p.x)break;
|
||||
if(regs.p.x)return;
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.x.w + 1, regs.y.w >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//stz_dpx
|
||||
case 0x74: {
|
||||
void sCPU::op_stz_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedp(dp + regs.x.w, 0x0000);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.x.w + 1, 0x0000 >> 8);
|
||||
} break;
|
||||
}
|
||||
|
||||
//stx_dpy
|
||||
case 0x96: {
|
||||
void sCPU::op_stx_dpy() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
if(regs.p.x)last_cycle();
|
||||
op_writedp(dp + regs.y.w, regs.x.l);
|
||||
if(regs.p.x)break;
|
||||
if(regs.p.x)return;
|
||||
last_cycle();
|
||||
op_writedp(dp + regs.y.w + 1, regs.x.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_idp
|
||||
case 0x92: {
|
||||
void sCPU::op_sta_idp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
aa.l = op_readdp(dp);
|
||||
aa.h = op_readdp(dp + 1);
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_ildp
|
||||
case 0x87: {
|
||||
void sCPU::op_sta_ildp() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
aa.l = op_readdp(dp);
|
||||
|
@ -216,13 +197,12 @@ case 0x87: {
|
|||
aa.b = op_readdp(dp + 2);
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writelong(aa.d, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writelong(aa.d + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_idpx
|
||||
case 0x81: {
|
||||
void sCPU::op_sta_idpx() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
op_io();
|
||||
|
@ -230,13 +210,12 @@ case 0x81: {
|
|||
aa.h = op_readdp(dp + regs.x.w + 1);
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_idpy
|
||||
case 0x91: {
|
||||
void sCPU::op_sta_idpy() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
aa.l = op_readdp(dp);
|
||||
|
@ -244,13 +223,12 @@ case 0x91: {
|
|||
op_io();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.y.w + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_ildpy
|
||||
case 0x97: {
|
||||
void sCPU::op_sta_ildpy() {
|
||||
dp = op_readpc();
|
||||
op_io_cond2();
|
||||
aa.l = op_readdp(dp);
|
||||
|
@ -258,24 +236,22 @@ case 0x97: {
|
|||
aa.b = op_readdp(dp + 2);
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writelong(aa.d + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writelong(aa.d + regs.y.w + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_sr
|
||||
case 0x83: {
|
||||
void sCPU::op_sta_sr() {
|
||||
sp = op_readpc();
|
||||
op_io();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writesp(sp, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writesp(sp + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sta_isry
|
||||
case 0x93: {
|
||||
void sCPU::op_sta_isry() {
|
||||
sp = op_readpc();
|
||||
op_io();
|
||||
aa.l = op_readsp(sp);
|
||||
|
@ -283,8 +259,8 @@ case 0x93: {
|
|||
op_io();
|
||||
if(regs.p.m)last_cycle();
|
||||
op_writedbr(aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)break;
|
||||
if(regs.p.m)return;
|
||||
last_cycle();
|
||||
op_writedbr(aa.w + regs.y.w + 1, regs.a.h);
|
||||
} break;
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
|
|
|
@ -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,
|
File diff suppressed because it is too large
Load Diff
|
@ -1,171 +1,167 @@
|
|||
class bDSP : public DSP {
|
||||
private:
|
||||
uint8 dspram[128];
|
||||
uint8 *spcram;
|
||||
|
||||
uint32 dsp_counter;
|
||||
|
||||
enum { BRR_END = 1, BRR_LOOP = 2 };
|
||||
|
||||
uint8 readb (uint16 addr);
|
||||
uint16 readw (uint16 addr);
|
||||
void writeb(uint16 addr, uint8 data);
|
||||
void writew(uint16 addr, uint16 data);
|
||||
|
||||
public:
|
||||
static const uint16 RateTable[32];
|
||||
static const int16 GaussTable[512];
|
||||
|
||||
enum EnvelopeStates {
|
||||
ATTACK,
|
||||
DECAY,
|
||||
SUSTAIN,
|
||||
RELEASE,
|
||||
SILENCE
|
||||
};
|
||||
|
||||
enum EnvelopeModes {
|
||||
DIRECT,
|
||||
LINEAR_DEC,
|
||||
EXP_DEC,
|
||||
LINEAR_INC,
|
||||
BENT_INC,
|
||||
|
||||
FAST_ATTACK,
|
||||
RELEASE_DEC
|
||||
};
|
||||
|
||||
private:
|
||||
struct Status {
|
||||
//$0c,$1c
|
||||
int8 MVOLL, MVOLR;
|
||||
//$2c,$3c
|
||||
int8 EVOLL, EVOLR;
|
||||
//$4c,$5c
|
||||
uint8 KON, KOFF;
|
||||
//$6c
|
||||
uint8 FLG;
|
||||
//$7c
|
||||
uint8 ENDX;
|
||||
//$0d
|
||||
int8 EFB;
|
||||
//$2d,$3d,$4d
|
||||
uint8 PMON, NON, EON;
|
||||
//$5d
|
||||
uint8 DIR;
|
||||
//$6d,$7d
|
||||
uint8 ESA, EDL;
|
||||
|
||||
//$xf
|
||||
int8 FIR[8];
|
||||
|
||||
//internal variables
|
||||
uint8 kon;
|
||||
bool key_flag;
|
||||
|
||||
int16 noise_ctr, noise_rate;
|
||||
uint16 noise_sample;
|
||||
|
||||
uint16 echo_index, echo_size, echo_target;
|
||||
int16 fir_buffer[2][8];
|
||||
uint8 fir_buffer_index;
|
||||
|
||||
//functions
|
||||
bool soft_reset() { return bool(FLG & 0x80); }
|
||||
bool mute() { return bool(FLG & 0x40); }
|
||||
bool echo_write() { return !(FLG & 0x20); }
|
||||
} status;
|
||||
|
||||
struct Voice {
|
||||
//$x0-$x1
|
||||
int8 VOLL, VOLR;
|
||||
//$x2-$x3
|
||||
int16 PITCH;
|
||||
//$x4
|
||||
uint8 SRCN;
|
||||
//$x5-$x7
|
||||
uint8 ADSR1, ADSR2, GAIN;
|
||||
//$x8-$x9
|
||||
uint8 ENVX, OUTX;
|
||||
|
||||
//internal variables
|
||||
int16 pitch_ctr;
|
||||
|
||||
int8 brr_index;
|
||||
uint16 brr_ptr;
|
||||
uint8 brr_header;
|
||||
bool brr_looped;
|
||||
|
||||
int16 brr_data[4];
|
||||
uint8 brr_data_index;
|
||||
|
||||
int16 envx;
|
||||
uint16 env_ctr, env_rate, env_sustain;
|
||||
enum EnvelopeStates env_state;
|
||||
enum EnvelopeModes env_mode;
|
||||
|
||||
int16 outx;
|
||||
|
||||
//functions
|
||||
int16 pitch_rate() { return PITCH & 0x3fff; }
|
||||
|
||||
uint8 brr_header_shift() { return brr_header >> 4; }
|
||||
uint8 brr_header_filter() { return (brr_header >> 2) & 3; }
|
||||
uint8 brr_header_flags() { return brr_header & 3; }
|
||||
|
||||
bool ADSR_enabled() { return bool(ADSR1 & 0x80); }
|
||||
uint8 ADSR_decay() { return (ADSR1 >> 4) & 7; }
|
||||
uint8 ADSR_attack() { return ADSR1 & 15; }
|
||||
uint8 ADSR_sus_level() { return ADSR2 >> 5; }
|
||||
uint8 ADSR_sus_rate() { return ADSR2 & 31; }
|
||||
|
||||
void AdjustEnvelope() {
|
||||
if(env_state == SILENCE) {
|
||||
env_mode = DIRECT;
|
||||
env_rate = 0;
|
||||
envx = 0;
|
||||
} else if(env_state == RELEASE) {
|
||||
env_mode = RELEASE_DEC;
|
||||
env_rate = 0x7800;
|
||||
} else if(ADSR_enabled()) {
|
||||
switch(env_state) {
|
||||
case ATTACK:
|
||||
env_rate = RateTable[(ADSR_attack() << 1) + 1];
|
||||
env_mode = (env_rate == 0x7800) ? FAST_ATTACK : LINEAR_INC;
|
||||
break;
|
||||
case DECAY:
|
||||
env_rate = RateTable[(ADSR_decay() << 1) + 0x10];
|
||||
env_mode = EXP_DEC;
|
||||
break;
|
||||
case SUSTAIN:
|
||||
env_rate = RateTable[ADSR_sus_rate()];
|
||||
env_mode = (env_rate == 0) ? DIRECT : EXP_DEC;
|
||||
break;
|
||||
}
|
||||
} else if(GAIN & 0x80) {
|
||||
switch(GAIN & 0x60) {
|
||||
case 0x00: env_mode = LINEAR_DEC; break;
|
||||
case 0x20: env_mode = EXP_DEC; break;
|
||||
case 0x40: env_mode = LINEAR_INC; break;
|
||||
case 0x60: env_mode = BENT_INC; break;
|
||||
}
|
||||
env_rate = RateTable[GAIN & 0x1f];
|
||||
} else {
|
||||
env_mode = DIRECT;
|
||||
env_rate = 0;
|
||||
envx = (GAIN & 0x7f) << 4;
|
||||
}
|
||||
}
|
||||
} voice[8];
|
||||
void enter();
|
||||
|
||||
uint8 read( uint8 addr );
|
||||
void write( uint8 addr, uint8 data );
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
bDSP();
|
||||
~bDSP();
|
||||
|
||||
public:
|
||||
uint8 read (uint8 addr);
|
||||
void write(uint8 addr, uint8 data);
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
uint32 run();
|
||||
enum { echo_hist_size = 8 };
|
||||
enum { register_count = 128 };
|
||||
enum { voice_count = 8 };
|
||||
|
||||
enum env_mode_t { env_release, env_attack, env_decay, env_sustain };
|
||||
enum { brr_buf_size = 12 };
|
||||
struct voice_t
|
||||
{
|
||||
int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling)
|
||||
int buf_pos; // place in buffer where next samples will be decoded
|
||||
int interp_pos; // relative fractional position in sample (0x1000 = 1.0)
|
||||
int brr_addr; // address of current BRR block
|
||||
int brr_offset; // current decoding offset in BRR block
|
||||
uint8* regs; // pointer to voice's DSP registers
|
||||
int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc.
|
||||
int kon_delay; // KON delay/current setup phase
|
||||
env_mode_t env_mode;
|
||||
int env; // current envelope level
|
||||
int hidden_env; // used by GAIN mode 7, very obscure quirk
|
||||
uint8 t_envx_out;
|
||||
};
|
||||
private:
|
||||
|
||||
struct state_t
|
||||
{
|
||||
uint8 regs [register_count];
|
||||
|
||||
// Echo history keeps most recent 8 samples
|
||||
int echo_hist [echo_hist_size] [2];
|
||||
int echo_hist_pos;
|
||||
|
||||
int every_other_sample; // toggles every sample
|
||||
int kon; // KON value when last checked
|
||||
int noise;
|
||||
int counter;
|
||||
int echo_offset; // offset from ESA in echo buffer
|
||||
int echo_length; // number of bytes that echo_offset will stop at
|
||||
|
||||
// Hidden registers also written to when main register is written to
|
||||
int new_kon;
|
||||
uint8 endx_buf;
|
||||
uint8 envx_buf;
|
||||
uint8 outx_buf;
|
||||
|
||||
// Temporary state between clocks
|
||||
|
||||
// read once per sample
|
||||
int t_pmon;
|
||||
int t_non;
|
||||
int t_eon;
|
||||
int t_dir;
|
||||
int t_koff;
|
||||
|
||||
// read a few clocks ahead then used
|
||||
int t_brr_next_addr;
|
||||
int t_adsr0;
|
||||
int t_brr_header;
|
||||
int t_brr_byte;
|
||||
int t_srcn;
|
||||
|
||||
// internal state that is recalculated every sample
|
||||
int t_dir_addr;
|
||||
int t_pitch;
|
||||
int t_output;
|
||||
int t_looped;
|
||||
|
||||
// left/right sums
|
||||
int t_main_out [2];
|
||||
int t_echo_out [2];
|
||||
|
||||
voice_t voices [voice_count];
|
||||
};
|
||||
state_t m;
|
||||
uint8* ram;
|
||||
|
||||
unsigned read_counter( int rate );
|
||||
|
||||
void run_envelope( voice_t* const v );
|
||||
void decode_brr( voice_t* v );
|
||||
|
||||
bDSP();
|
||||
~bDSP();
|
||||
void voice_output( voice_t const* v, int ch );
|
||||
void voice_V1( voice_t* const );
|
||||
void voice_V2( voice_t* const );
|
||||
void voice_V3( voice_t* const );
|
||||
void voice_V3a( voice_t* const );
|
||||
void voice_V3b( voice_t* const );
|
||||
void voice_V3c( voice_t* const );
|
||||
void voice_V4( voice_t* const );
|
||||
void voice_V5( voice_t* const );
|
||||
void voice_V6( voice_t* const );
|
||||
void voice_V7( voice_t* const );
|
||||
void voice_V8( voice_t* const );
|
||||
void voice_V9( voice_t* const );
|
||||
void voice_V7_V4_V1( voice_t* const );
|
||||
void voice_V8_V5_V2( voice_t* const );
|
||||
void voice_V9_V6_V3( voice_t* const );
|
||||
|
||||
int calc_echo_output( int ch, int sample );
|
||||
|
||||
// Global registers
|
||||
enum {
|
||||
r_mvoll = 0x0C, r_mvolr = 0x1C,
|
||||
r_evoll = 0x2C, r_evolr = 0x3C,
|
||||
r_kon = 0x4C, r_koff = 0x5C,
|
||||
r_flg = 0x6C, r_endx = 0x7C,
|
||||
r_efb = 0x0D, r_pmon = 0x2D,
|
||||
r_non = 0x3D, r_eon = 0x4D,
|
||||
r_dir = 0x5D, r_esa = 0x6D,
|
||||
r_edl = 0x7D,
|
||||
r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F
|
||||
};
|
||||
|
||||
// Voice registers
|
||||
enum {
|
||||
v_voll = 0x00, v_volr = 0x01,
|
||||
v_pitchl = 0x02, v_pitchh = 0x03,
|
||||
v_srcn = 0x04, v_adsr0 = 0x05,
|
||||
v_adsr1 = 0x06, v_gain = 0x07,
|
||||
v_envx = 0x08, v_outx = 0x09
|
||||
};
|
||||
};
|
||||
|
||||
inline uint8 bDSP::read( uint8 addr )
|
||||
{
|
||||
return m.regs [addr];
|
||||
}
|
||||
|
||||
inline void bDSP::write( uint8 addr, uint8 data )
|
||||
{
|
||||
m.regs [addr] = data;
|
||||
switch ( addr & 0x0F )
|
||||
{
|
||||
case v_envx:
|
||||
m.envx_buf = data;
|
||||
break;
|
||||
|
||||
case v_outx:
|
||||
m.outx_buf = data;
|
||||
break;
|
||||
|
||||
case 0x0C:
|
||||
if ( addr == r_kon )
|
||||
m.new_kon = data;
|
||||
|
||||
if ( addr == r_endx ) // always cleared, regardless of data written
|
||||
{
|
||||
m.endx_buf = 0;
|
||||
m.regs [r_endx] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <gblargg@gmail.com>
|
|
@ -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
|
|
@ -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"
|
||||
|
|
|
@ -1,18 +1,50 @@
|
|||
/*
|
||||
libbase : version 0.09 ~byuu (2007-01-12)
|
||||
libbase : version 0.10 ~byuu (2007-05-27)
|
||||
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>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#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 getcwd _getcwd
|
||||
#define ftruncate _chsize
|
||||
#define mkdir _mkdir
|
||||
#define putenv _putenv
|
||||
#define rmdir _rmdir
|
||||
#define vsnprintf _vsnprintf
|
||||
|
||||
#define va_copy(dst, src) ((dst) = (src))
|
||||
static char *realpath(const char *file_name, char *resolved_name) {
|
||||
return _fullpath(resolved_name, file_name, PATH_MAX);
|
||||
}
|
||||
#elif defined(__GNUC__)
|
||||
#define mkdir(path) (mkdir)(path, 0755);
|
||||
#endif
|
||||
|
||||
/*****
|
||||
|
@ -25,9 +57,9 @@
|
|||
#define alwaysinline __forceinline
|
||||
#define fastcall __fastcall
|
||||
#elif defined(__GNUC__)
|
||||
#define noinline
|
||||
#define noinline __attribute__((noinline))
|
||||
#define inline inline
|
||||
#define alwaysinline inline
|
||||
#define alwaysinline __attribute__((always_inline))
|
||||
#define fastcall __attribute__((fastcall))
|
||||
#else
|
||||
#define noinline
|
||||
|
@ -36,85 +68,43 @@
|
|||
#define fastcall
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#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; }
|
||||
|
||||
/*****
|
||||
* template traits
|
||||
*****/
|
||||
|
||||
template<typename T> struct is_reference { enum { value = false }; };
|
||||
template<typename T> struct is_reference<T&> { enum { value = true }; };
|
||||
|
||||
template<typename T> struct is_pointer { enum { value = false }; };
|
||||
template<typename T> struct is_pointer<T*> { enum { value = true }; };
|
||||
|
||||
template<typename T> struct is_const { enum { value = false }; };
|
||||
template<typename T> struct is_const<const T> { enum { value = true }; };
|
||||
template<typename T> struct is_const<const T&> { enum { value = true }; };
|
||||
|
||||
/*****
|
||||
* null_t
|
||||
*****/
|
||||
|
||||
struct null_t {
|
||||
alwaysinline bool operator==(const null_t&) { return true; }
|
||||
alwaysinline bool operator>=(const null_t&) { return true; }
|
||||
alwaysinline bool operator<=(const null_t&) { return true; }
|
||||
alwaysinline bool operator!=(const null_t&) { return false; }
|
||||
alwaysinline bool operator> (const null_t&) { return false; }
|
||||
alwaysinline bool operator< (const null_t&) { return false; }
|
||||
alwaysinline null_t &operator=(const null_t&) { return *this; }
|
||||
};
|
||||
|
||||
template<typename T> struct is_null_t { enum { value = false }; };
|
||||
template<> struct is_null_t<null_t> { enum { value = true }; };
|
||||
|
||||
/*****
|
||||
* 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)
|
||||
static char *userpath(char *output) {
|
||||
strcpy(output, "."); //failsafe
|
||||
SHGetFolderPath(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, output);
|
||||
return output;
|
||||
}
|
||||
#elif defined(__GNUC__)
|
||||
static char *userpath(char *output) {
|
||||
strcpy(output, "."); //failsafe
|
||||
struct passwd *userinfo = getpwuid(getuid());
|
||||
if(userinfo) { strcpy(output, userinfo->pw_dir); }
|
||||
return output;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****
|
||||
* templates
|
||||
|
@ -162,118 +152,53 @@ template<int min, int max, typename T> inline T minmax(const T 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;
|
||||
//}
|
||||
|
||||
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
|
||||
*****/
|
||||
|
@ -316,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) {
|
||||
|
@ -427,7 +282,9 @@ uint32 size = ftell(fp);
|
|||
return size;
|
||||
}
|
||||
|
||||
static int fresize(FILE *fp, long size) { return ftruncate(fileno(fp), size); }
|
||||
static int fresize(FILE *fp, long size) {
|
||||
return ftruncate(fileno(fp), size);
|
||||
}
|
||||
|
||||
/*****
|
||||
* crc32 calculation
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
libco_win32 : version 0.09 ~byuu (2007-01-19)
|
||||
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_t co_init();
|
||||
|
||||
cothread_t co_active() {
|
||||
if(__co_primary == 0)co_init();
|
||||
return __co_active;
|
||||
}
|
||||
|
||||
cothread_t co_create(cothread_p coentry, unsigned int heapsize) {
|
||||
if(__co_primary == 0)co_init();
|
||||
cothread_struct *s = (cothread_struct*)malloc(sizeof(cothread_struct));
|
||||
s->colink = co_active();
|
||||
s->coentry = coentry;
|
||||
s->cohandle = CreateFiber(heapsize + 512, co_entryproc, (void*)s);
|
||||
return (cothread_t)s;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t cothread) {
|
||||
cothread_struct *s = (cothread_struct*)cothread;
|
||||
DeleteFiber(s->cohandle);
|
||||
free(cothread);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t cothread) {
|
||||
__co_active = cothread;
|
||||
cothread_struct *s = (cothread_struct*)cothread;
|
||||
SwitchToFiber(s->cohandle);
|
||||
}
|
||||
|
||||
void co_exit(cothread_t cothread) {
|
||||
if(cothread != 0) { co_switch(cothread); }
|
||||
cothread_struct *s = (cothread_struct*)__co_active;
|
||||
co_switch(s->colink);
|
||||
}
|
||||
|
||||
/*****
|
||||
* internal functions
|
||||
*****/
|
||||
|
||||
void __stdcall co_entryproc(void *coentry) {
|
||||
cothread_struct *s = (cothread_struct*)coentry;
|
||||
s->coentry();
|
||||
co_exit(0);
|
||||
}
|
||||
|
||||
cothread_t co_init() {
|
||||
ConvertThreadToFiber(0);
|
||||
cothread_struct *s = (cothread_struct*)malloc(sizeof(cothread_struct));
|
||||
s->colink = 0;
|
||||
s->coentry = 0;
|
||||
s->cohandle = GetCurrentFiber();
|
||||
__co_active = __co_primary = (cothread_t)s;
|
||||
return __co_active;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
libco_win32 : version 0.09 ~byuu (2007-01-19)
|
||||
*/
|
||||
|
||||
#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_active();
|
||||
cothread_t co_create(cothread_p coentry, unsigned int heapsize);
|
||||
void co_delete(cothread_t cothread);
|
||||
void co_switch(cothread_t cothread);
|
||||
void co_exit(cothread_t cothread);
|
|
@ -1,5 +1,5 @@
|
|||
;*****
|
||||
;libco_x86 : version 0.09 ~byuu (2007-01-19)
|
||||
;libco_x86 : version 0.10 ~byuu (2007-04-18)
|
||||
;cross-platform x86 implementation of libco
|
||||
;special thanks to Aaron Giles and Joel Yliluoma for various optimizations
|
||||
;
|
||||
|
@ -19,34 +19,18 @@
|
|||
;- xmm0 - xmm15
|
||||
;*****
|
||||
|
||||
bits 32
|
||||
|
||||
section .bss
|
||||
|
||||
align 4
|
||||
co_primary_buffer resb 512
|
||||
|
||||
section .data
|
||||
|
||||
align 4
|
||||
co_active_context dd 0
|
||||
co_primary_context dd 0
|
||||
|
||||
section .text
|
||||
|
||||
;*****
|
||||
;linker-specific name decorations
|
||||
;*****
|
||||
|
||||
%ifdef WIN32
|
||||
%define malloc _malloc
|
||||
%define free _free
|
||||
|
||||
%define co_active @co_active@0
|
||||
%define co_create @co_create@8
|
||||
%define co_create @co_create@12
|
||||
%define co_delete @co_delete@4
|
||||
%define co_switch @co_switch@4
|
||||
%define co_exit @co_exit@4
|
||||
%define co_init @co_init@0
|
||||
%endif
|
||||
|
||||
%ifdef OSX86
|
||||
|
@ -57,10 +41,22 @@ section .text
|
|||
%define co_create _co_create
|
||||
%define co_delete _co_delete
|
||||
%define co_switch _co_switch
|
||||
%define co_exit _co_exit
|
||||
%define co_init _co_init
|
||||
%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
|
||||
|
||||
|
@ -68,7 +64,6 @@ global co_active
|
|||
global co_create
|
||||
global co_delete
|
||||
global co_switch
|
||||
global co_exit
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t fastcall co_active();
|
||||
|
@ -77,56 +72,48 @@ global co_exit
|
|||
|
||||
align 16
|
||||
co_active:
|
||||
cmp dword[co_active_context],0
|
||||
jnz .initialized
|
||||
jmp co_init
|
||||
.initialized
|
||||
mov eax,[co_active_context]
|
||||
ret
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t fastcall co_create(cothread_p coentry, unsigned int heapsize);
|
||||
;ecx = coentry
|
||||
;edx = heapsize
|
||||
;return = eax
|
||||
;extern "C" cothread_t fastcall co_create(unsigned int heapsize, void (*coentry)(void *data), void *data);
|
||||
;ecx = heapsize
|
||||
;edx = coentry
|
||||
;[esp+4] = data
|
||||
;return = eax
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_create:
|
||||
cmp dword[co_active_context],0
|
||||
jnz .initialized
|
||||
call co_init
|
||||
.initialized
|
||||
;create heap space (stack + register storage)
|
||||
add edx,512 ;allocate extra memory for contextual info
|
||||
add ecx,512 ;allocate extra memory for contextual info
|
||||
push ecx
|
||||
push edx
|
||||
|
||||
push edx
|
||||
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,-16 ;force 16-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
|
||||
mov dword[edx-8],0 ;ebp
|
||||
mov dword[edx-12],0 ;esi
|
||||
mov dword[edx-16],0 ;edi
|
||||
mov dword[edx-20],0 ;ebx
|
||||
sub edx,20
|
||||
mov dword[ecx-4],co_entrypoint ;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
|
||||
mov [eax],edx ;cothread_t[ 0- 3] = stack heap pointer (esp)
|
||||
mov [eax+4],ecx ;cothread_t[ 4- 7] = entry point (coentry)
|
||||
mov ecx,[co_active_context]
|
||||
mov [eax+8],ecx ;cothread_t[ 8-11] = return context
|
||||
|
||||
ret ;return allocated memory block as thread handle
|
||||
;initialize context memory heap and return
|
||||
mov [eax],ecx ;cothread_t[ 0- 3] = stack heap pointer (esp)
|
||||
mov [eax+4],edx ;cothread_t[ 4- 7] = coentry
|
||||
mov ecx,[esp+4]
|
||||
mov [eax+8],ecx ;cothread_t[ 8-11] = data
|
||||
ret 4 ;return allocated memory block as thread handle
|
||||
|
||||
;*****
|
||||
;extern "C" void fastcall co_delete(cothread_t cothread);
|
||||
|
@ -164,40 +151,17 @@ co_switch:
|
|||
|
||||
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,[co_active_context]
|
||||
mov ecx,[eax+8]
|
||||
jmp co_switch
|
||||
|
||||
;*****
|
||||
;void fastcall co_entrypoint();
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_entrypoint:
|
||||
mov ebp,esp
|
||||
.loop
|
||||
mov eax,[co_active_context]
|
||||
mov ecx,[eax+8] ;fastcall
|
||||
push ecx ;stdcall
|
||||
call [eax+4]
|
||||
xor ecx,ecx
|
||||
jmp co_exit
|
||||
|
||||
;*****
|
||||
;cothread_t fastcall co_init();
|
||||
;return = eax
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_init:
|
||||
mov eax,co_primary_buffer ;use pre-allocated memory for primary context
|
||||
mov [co_active_context],eax
|
||||
mov [co_primary_context],eax
|
||||
ret
|
||||
mov esp,ebp ;cdecl
|
||||
jmp .loop
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
/*
|
||||
libco_x86 : version 0.09 ~byuu (2007-01-13)
|
||||
libco_x86 : version 0.10 ~byuu (2007-04-18)
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
#define cocall fastcall
|
||||
typedef void (*cothread_t);
|
||||
typedef void (*cothread_p)(void);
|
||||
|
||||
extern "C" cothread_t fastcall co_active();
|
||||
extern "C" cothread_t fastcall co_create(cothread_p coentry, unsigned int heapsize);
|
||||
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);
|
||||
extern "C" cothread_t cocall co_active();
|
||||
extern "C" cothread_t cocall co_create(unsigned int heapsize, void (cocall *coentry)(void *data), void *data);
|
||||
extern "C" void cocall co_delete(cothread_t cothread);
|
||||
extern "C" void cocall co_switch(cothread_t cothread);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
;*****
|
||||
;libco_x86_64 : version 0.09 ~byuu (2007-01-19)
|
||||
;libco_x86_64 : version 0.10 ~byuu (2007-04-18)
|
||||
;cross-platform x86-64 implementation of libco
|
||||
;special thanks to Aaron Giles and Joel Yliluoma for various optimizations
|
||||
;
|
||||
|
@ -27,8 +27,7 @@ co_primary_buffer resb 512
|
|||
section .data
|
||||
|
||||
align 8
|
||||
co_active_context dq 0
|
||||
co_primary_context dq 0
|
||||
co_active_context dq co_primary_buffer
|
||||
|
||||
section .text
|
||||
|
||||
|
@ -39,7 +38,6 @@ global co_active
|
|||
global co_create
|
||||
global co_delete
|
||||
global co_switch
|
||||
global co_exit
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t co_active();
|
||||
|
@ -48,57 +46,48 @@ global co_exit
|
|||
|
||||
align 16
|
||||
co_active:
|
||||
cmp qword[co_active_context wrt rip],0
|
||||
jnz .initialized
|
||||
jmp co_init
|
||||
.initialized
|
||||
mov rax,[co_active_context wrt rip]
|
||||
ret
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t co_create(cothread_p coentry, unsigned int heapsize);
|
||||
;rdi = coentry
|
||||
;rsi = heapsize
|
||||
;extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)(void *data), void *data);
|
||||
;rdi = heapsize
|
||||
;rsi = coentry
|
||||
;rdx = data
|
||||
;return = rax
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_create:
|
||||
cmp qword[co_active_context wrt rip],0
|
||||
jnz .initialized
|
||||
call co_init
|
||||
.initialized
|
||||
;create heap space (stack + register storage)
|
||||
add rsi,512 ;allocate extra memory for contextual info
|
||||
add rdi,512 ;allocate extra memory for contextual info
|
||||
push rdi
|
||||
push rsi
|
||||
push rdx
|
||||
|
||||
mov rdi,rsi
|
||||
call malloc ;rax = malloc(rdi)
|
||||
|
||||
pop rdx
|
||||
pop rsi
|
||||
pop rdi
|
||||
|
||||
add rsi,rax ;set rsi to point to top of stack heap
|
||||
and rsi,-16 ;force 16-byte alignment of stack heap
|
||||
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[rsi-8],co_entrypoint
|
||||
mov qword[rsi-16],0 ;r15
|
||||
mov qword[rsi-24],0 ;r14
|
||||
mov qword[rsi-32],0 ;r13
|
||||
mov qword[rsi-40],0 ;r12
|
||||
mov qword[rsi-48],0 ;rbx
|
||||
mov qword[rsi-56],0 ;rbp
|
||||
mov qword[rsi-64],0 ;rsp
|
||||
sub rsi,64
|
||||
|
||||
;initialize context memory heap
|
||||
mov [rax],rsi ;cothread_t[ 0- 7] = stack heap pointer (rsp)
|
||||
mov [rax+8],rdi ;cothread_t[ 8-15] = entry point (coentry)
|
||||
mov rdi,[co_active_context wrt rip]
|
||||
mov [rax+16],rdi ;cothread_t[16-23] = return context
|
||||
mov qword[rdi-8],co_entrypoint ;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[ 0- 7] = stack heap pointer (rsp)
|
||||
mov [rax+8],rsi ;cothread_t[ 8-15] = coentry
|
||||
mov [rax+16],rdx ;cothread_t[16-23] = data
|
||||
ret ;return allocated memory block as thread handle
|
||||
|
||||
;*****
|
||||
|
@ -138,21 +127,6 @@ co_switch:
|
|||
|
||||
ret
|
||||
|
||||
;*****
|
||||
;extern "C" void co_exit(cothread_t cothread);
|
||||
;rdi = cothread
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_exit:
|
||||
cmp rdi,0
|
||||
jne co_switch
|
||||
|
||||
;if cothread is null, switch to context that created current context
|
||||
mov rax,[co_active_context wrt rip]
|
||||
mov rdi,[rax+16]
|
||||
jmp co_switch
|
||||
|
||||
;*****
|
||||
;void co_entrypoint();
|
||||
;*****
|
||||
|
@ -160,18 +134,6 @@ co_exit:
|
|||
align 16
|
||||
co_entrypoint:
|
||||
mov rax,[co_active_context wrt rip]
|
||||
mov rdi,[rax+16]
|
||||
call [rax+8]
|
||||
xor rdi,rdi
|
||||
jmp co_exit
|
||||
|
||||
;*****
|
||||
;cothread_t co_init();
|
||||
;return = rax
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_init:
|
||||
mov rax,co_primary_buffer ;use pre-allocated memory for primary context
|
||||
mov [co_active_context wrt rip],rax
|
||||
mov [co_primary_context wrt rip],rax
|
||||
ret
|
||||
jmp co_entrypoint
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
/*
|
||||
libco_x86_64 : version 0.09 ~byuu (2007-01-19)
|
||||
libco_x86_64 : version 0.10 ~byuu (2007-04-18)
|
||||
*/
|
||||
|
||||
#define COTHREAD_STACKSIZE_TINY 0x2000
|
||||
#define COTHREAD_STACKSIZE_SMALL 0x8000
|
||||
#define COTHREAD_STACKSIZE_NORMAL 0x20000
|
||||
#define COTHREAD_STACKSIZE_LARGE 0x80000
|
||||
#define COTHREAD_STACKSIZE_HUGE 0x200000
|
||||
#ifndef LIBCO_H
|
||||
#define LIBCO_H
|
||||
|
||||
#define cocall
|
||||
typedef void (*cothread_t);
|
||||
typedef void (*cothread_p)(void);
|
||||
|
||||
extern "C" cothread_t co_active();
|
||||
extern "C" cothread_t co_create(cothread_p coentry, unsigned int heapsize);
|
||||
extern "C" cothread_t co_create(unsigned int heapsize, void (cocall *coentry)(void *data), void *data);
|
||||
extern "C" void co_delete(cothread_t cothread);
|
||||
extern "C" void co_switch(cothread_t cothread);
|
||||
extern "C" void co_exit(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(stribegin(input, "0x")) {
|
||||
return strhex(input + 2);
|
||||
}
|
||||
|
||||
return strdec(input);
|
||||
}
|
||||
|
||||
char *Config::uint_to_string(uint type, uint input) {
|
||||
static char output[512];
|
||||
switch(type) {
|
||||
case Setting::BOOL:
|
||||
sprintf(output, "%s", (input & 1) ? "true" : "false");
|
||||
break;
|
||||
case Setting::ENABLED_DISABLED:
|
||||
sprintf(output, "%s", (input & 1) ? "enabled" : "disabled");
|
||||
break;
|
||||
case Setting::ON_OFF:
|
||||
sprintf(output, "%s", (input & 1) ? "on" : "off");
|
||||
break;
|
||||
case Setting::YES_NO:
|
||||
sprintf(output, "%s", (input & 1) ? "yes" : "no");
|
||||
break;
|
||||
case Setting::DEC: sprintf(output, "%d", input); break;
|
||||
case Setting::HEX: sprintf(output, "0x%x", input); break;
|
||||
case Setting::HEX8: sprintf(output, "0x%0.2x", input & 0xff); break;
|
||||
case Setting::HEX16: sprintf(output, "0x%0.4x", input & 0xffff); break;
|
||||
case Setting::HEX24: sprintf(output, "0x%0.6x", input & 0xffffff); break;
|
||||
case Setting::HEX32: sprintf(output, "0x%0.8x", input); break;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
bool Config::load(const char *fn) {
|
||||
FILE *fp;
|
||||
fp = fopen(fn, "rb");
|
||||
if(!fp)return false;
|
||||
|
||||
//load the config file into memory
|
||||
fseek(fp, 0, SEEK_END);
|
||||
int fsize = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
char *buffer = (char*)malloc(fsize + 1);
|
||||
fread(buffer, 1, fsize, fp);
|
||||
fclose(fp);
|
||||
*(buffer + fsize) = 0;
|
||||
strcpy(data, buffer);
|
||||
free(buffer);
|
||||
|
||||
//split the file into lines
|
||||
replace(data, "\r\n", "\n");
|
||||
qreplace(data, "\t", "");
|
||||
qreplace(data, " ", "");
|
||||
split(line, "\n", data);
|
||||
|
||||
for(int i = 0; i < count(line); i++) {
|
||||
if(strlen(line[i]) == 0)continue;
|
||||
if(*strptr(line[i]) == '#')continue;
|
||||
|
||||
qsplit(part, "=", line[i]);
|
||||
for(int l = 0; l < list_count; l++) {
|
||||
if(!strcmp(list[l]->name, part[0])) {
|
||||
if(list[l]->type != Setting::STR) {
|
||||
list[l]->set(string_to_uint(list[l]->type, strptr(part[1])));
|
||||
} else {
|
||||
list[l]->strset(strptr(part[1]));
|
||||
strunquote(list[l]->char_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool Config::load(string &fn) { return load(strptr(fn)); }
|
||||
|
||||
bool Config::save(const char *fn) {
|
||||
FILE *fp;
|
||||
fp = fopen(fn, "wb");
|
||||
if(!fp)return false;
|
||||
|
||||
for(int i = 0; i < list_count; i++) {
|
||||
strcpy(data, list[i]->desc);
|
||||
replace(data, "\r\n", "\n");
|
||||
split(line, "\n", data);
|
||||
for(int l = 0; l < count(line); l++) {
|
||||
fprintf(fp, "# %s\r\n", strptr(line[l]));
|
||||
}
|
||||
if(list[i]->type != Setting::STRING) {
|
||||
fprintf(fp, "# (default = %s)\r\n", uint_to_string(list[i]->type, list[i]->def));
|
||||
fprintf(fp, "%s = %s\r\n\r\n", list[i]->name, uint_to_string(list[i]->type, list[i]->data));
|
||||
} else {
|
||||
fprintf(fp, "# (default = \"%s\")\r\n", strptr(list[i]->char_def));
|
||||
fprintf(fp, "%s = \"%s\"\r\n\r\n", list[i]->name, strptr(list[i]->char_data));
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
bool Config::save(string &fn) { return save(strptr(fn)); }
|
||||
|
||||
Config::Config() {
|
||||
list_count = 0;
|
||||
}
|
|
@ -1,95 +1,185 @@
|
|||
/*
|
||||
libconfig : version 0.12 ~byuu (2007-01-13)
|
||||
libconfig : version 0.14 ~byuu (2007-05-27)
|
||||
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);
|
||||
|
||||
inline operator uint() { return get(); }
|
||||
inline operator char*() { return strget(); }
|
||||
|
||||
template<typename T>
|
||||
inline Setting &operator=(T x) {
|
||||
(type != STR) ? set((uint)x) : strset((const char*)x);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool operator==(T x) {
|
||||
return (type != STR) ? get() == (uint)x : !strcmp(strget(), (const char*)x);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool operator!=(T x) {
|
||||
return (type != STR) ? get() != (uint)x : strcmp(strget(), (const char*)x);
|
||||
}
|
||||
|
||||
//numerical operations only
|
||||
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; }
|
||||
};
|
||||
|
||||
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, char *r_name, 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, char *r_name, char *r_desc, 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
|
||||
|
|
|
@ -0,0 +1,455 @@
|
|||
/*
|
||||
libfile : version 0.07 ~byuu (2007-03-01)
|
||||
*/
|
||||
|
||||
#ifndef __LIBFILE
|
||||
#define __LIBFILE
|
||||
|
||||
//FreeBSD fix: do not use defines for libc functions
|
||||
#undef feof
|
||||
#undef ferror
|
||||
|
||||
/*****
|
||||
* 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 resize(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 fresize(file &s, uint size) { s.resize(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 resize(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 resize(uint size) {
|
||||
if(!fp) { return; }
|
||||
|
||||
fresize(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,73 @@
|
|||
/*
|
||||
libinterp : version 0.01 ~byuu (2007-02-03)
|
||||
*/
|
||||
|
||||
#ifndef __LIBINTERP
|
||||
#define __LIBINTERP
|
||||
|
||||
static inline
|
||||
double interpolate_point(
|
||||
double mu,
|
||||
double y0, double y1
|
||||
) {
|
||||
return mu < 0.5 ? y0 : y1;
|
||||
}
|
||||
|
||||
static inline
|
||||
double interpolate_linear(
|
||||
double mu,
|
||||
double y0, double y1
|
||||
) {
|
||||
return y0 + mu * (y1 - y0);
|
||||
}
|
||||
|
||||
static inline
|
||||
double interpolate_cosine(
|
||||
double mu,
|
||||
double y0, double y1
|
||||
) {
|
||||
mu = (1.0 - cos(mu * 3.14159265)) / 2.0;
|
||||
return y0 + mu * (y1 - y0);
|
||||
}
|
||||
|
||||
static inline
|
||||
double interpolate_cubic(
|
||||
double mu,
|
||||
double y0, double y1, double y2, double y3
|
||||
) {
|
||||
double a0 = y3 - y2 - y0 + y1;
|
||||
double a1 = y0 - y1 - a0;
|
||||
double a2 = y2 - y0;
|
||||
double a3 = y1;
|
||||
return a0 * mu * mu * mu +
|
||||
a1 * mu * mu +
|
||||
a2 * mu +
|
||||
a3;
|
||||
}
|
||||
|
||||
/*
|
||||
tension: (0 = normal, -1 = low, +1 = high)
|
||||
bias: (0 = even, -n = left, +n = right)
|
||||
*/
|
||||
static inline
|
||||
double interpolate_hermite(
|
||||
double mu, double tension, double bias,
|
||||
double y0, double y1, double y2, double y3
|
||||
) {
|
||||
double mu0 = ( (y1 - y0) * (1.0 + bias) * (1.0 - tension) / 2.0 ) +
|
||||
( (y2 - y1) * (1.0 - bias) * (1.0 - tension) / 2.0 );
|
||||
double mu1 = ( (y2 - y1) * (1.0 + bias) * (1.0 - tension) / 2.0 ) +
|
||||
( (y3 - y2) * (1.0 - bias) * (1.0 - tension) / 2.0 );
|
||||
double mu2 = mu * mu;
|
||||
double mu3 = mu * mu * mu;
|
||||
double a0 = 2.0 * mu3 - 3.0 * mu2 + 1.0;
|
||||
double a1 = mu3 - 2.0 * mu2 + mu;
|
||||
double a2 = mu3 - mu2;
|
||||
double a3 = -2.0 * mu3 + 3.0 * mu2;
|
||||
return a0 * y1 +
|
||||
a1 * mu0 +
|
||||
a2 * mu1 +
|
||||
a3 * y2;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,182 +1,285 @@
|
|||
/*
|
||||
libkeymap : version 0.02 ~byuu (2006-07-30)
|
||||
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:
|
||||
enum {
|
||||
none = 0x0000,
|
||||
|
||||
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;
|
||||
esc,
|
||||
|
||||
struct {
|
||||
uint up, down, left, right;
|
||||
uint button[128];
|
||||
} joypad[16];
|
||||
f1,
|
||||
f2,
|
||||
f3,
|
||||
f4,
|
||||
f5,
|
||||
f6,
|
||||
f7,
|
||||
f8,
|
||||
f9,
|
||||
f10,
|
||||
f11,
|
||||
f12,
|
||||
|
||||
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
|
||||
print_screen, sys_req,
|
||||
scroll_lock,
|
||||
pause, brk,
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
grave, tilde,
|
||||
|
||||
return 0;
|
||||
}
|
||||
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,
|
||||
|
||||
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
|
||||
minus, underscore,
|
||||
equal, plus,
|
||||
backspace,
|
||||
|
||||
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; }
|
||||
}
|
||||
}
|
||||
ins,
|
||||
del,
|
||||
home,
|
||||
end,
|
||||
page_up,
|
||||
page_down,
|
||||
|
||||
return "null";
|
||||
}
|
||||
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,
|
||||
|
||||
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));
|
||||
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,
|
||||
|
||||
joypad_flag = 0x8000,
|
||||
joypad_nummask = 0x7f00,
|
||||
joypad_keymask = 0x00ff,
|
||||
|
||||
joypad_up = 0x0080,
|
||||
joypad_down = 0x0081,
|
||||
joypad_left = 0x0082,
|
||||
joypad_right = 0x0083,
|
||||
};
|
||||
|
||||
static uint16 find(const char *key) {
|
||||
#define match(_n) if(!strcmp(#_n, key)) { return _n; }
|
||||
match(none)
|
||||
match(esc)
|
||||
match(f1) match(f2) match(f3) match(f4) match(f5) match(f6)
|
||||
match(f7) match(f8) match(f9) match(f10) match(f11) match(f12)
|
||||
match(print_screen) match(sys_req) match(scroll_lock) match(pause) match(brk)
|
||||
match(grave) match(tilde)
|
||||
match(num_1) match(exclamation)
|
||||
match(num_2) match(at)
|
||||
match(num_3) match(pound)
|
||||
match(num_4) match(dollar)
|
||||
match(num_5) match(percent)
|
||||
match(num_6) match(power)
|
||||
match(num_7) match(ampersand)
|
||||
match(num_8) match(asterisk)
|
||||
match(num_9) match(lparenthesis)
|
||||
match(num_0) match(rparenthesis)
|
||||
match(minus) match(underscore) match(equal) match(plus) match(backspace)
|
||||
match(ins) match(del) match(home) match(end) match(page_up) match(page_down)
|
||||
match(a) match(b) match(c) match(d) match(e) match(f)
|
||||
match(g) match(h) match(i) match(j) match(k) match(l)
|
||||
match(m) match(n) match(o) match(p) match(q) match(r)
|
||||
match(s) match(t) match(u) match(v) match(w) match(x)
|
||||
match(y) match(z)
|
||||
match(A) match(B) match(C) match(D) match(E) match(F)
|
||||
match(G) match(H) match(I) match(J) match(K) match(L)
|
||||
match(M) match(N) match(O) match(P) match(Q) match(R)
|
||||
match(S) match(T) match(U) match(V) match(W) match(X)
|
||||
match(Y) match(Z)
|
||||
match(lbracket) match(lbrace)
|
||||
match(rbracket) match(rbrace)
|
||||
match(backslash) match(pipe)
|
||||
match(semicolon) match(colon)
|
||||
match(apostrophe) match(quote)
|
||||
match(comma) match(lcaret)
|
||||
match(period) match(rcaret)
|
||||
match(slash) match(question)
|
||||
match(kp_1) match(kp_end)
|
||||
match(kp_2) match(kp_down)
|
||||
match(kp_3) match(kp_page_down)
|
||||
match(kp_4) match(kp_left)
|
||||
match(kp_5) match(kp_center)
|
||||
match(kp_6) match(kp_right)
|
||||
match(kp_7) match(kp_home)
|
||||
match(kp_8) match(kp_up)
|
||||
match(kp_9) match(kp_page_up)
|
||||
match(kp_0) match(kp_insert)
|
||||
match(kp_decimal) match(kp_delete)
|
||||
match(kp_plus) match(kp_minus) match(kp_mul) match(kp_div) match(kp_enter)
|
||||
match(num_lock) match(caps_lock)
|
||||
match(up) match(down) match(left) match(right)
|
||||
match(tab) match(enter) match(space)
|
||||
match(lctrl) match(rctrl)
|
||||
match(lalt) match(ralt)
|
||||
match(lshift) match(rshift)
|
||||
match(lsuper) match(rsuper)
|
||||
match(menu)
|
||||
#undef match
|
||||
|
||||
if(!memcmp(key, "joypad", 6)) {
|
||||
const char *p = key + 6;
|
||||
uint joypad, button, n;
|
||||
sscanf(p, "%u%n", &joypad, &n);
|
||||
joypad &= 127;
|
||||
p += n;
|
||||
if(!strcmp(p, ".up")) { return joypad_flag | (joypad << 8) | joypad_up; }
|
||||
if(!strcmp(p, ".down")) { return joypad_flag | (joypad << 8) | joypad_down; }
|
||||
if(!strcmp(p, ".left")) { return joypad_flag | (joypad << 8) | joypad_left; }
|
||||
if(!strcmp(p, ".right")) { return joypad_flag | (joypad << 8) | joypad_right; }
|
||||
if(!memcmp(p, ".button", 7)) {
|
||||
sscanf(p + 7, "%u", &button);
|
||||
button &= 127;
|
||||
return joypad_flag | (joypad << 8) | button;
|
||||
}
|
||||
}
|
||||
|
||||
return none;
|
||||
}
|
||||
|
||||
static char *find(char *out, uint16 key) {
|
||||
#define match(_n) if(_n == key) { strcpy(out, #_n); return out; }
|
||||
match(none)
|
||||
match(esc)
|
||||
match(f1) match(f2) match(f3) match(f4) match(f5) match(f6)
|
||||
match(f7) match(f8) match(f9) match(f10) match(f11) match(f12)
|
||||
match(print_screen) match(sys_req) match(scroll_lock) match(pause) match(brk)
|
||||
match(grave) match(tilde)
|
||||
match(num_1) match(exclamation)
|
||||
match(num_2) match(at)
|
||||
match(num_3) match(pound)
|
||||
match(num_4) match(dollar)
|
||||
match(num_5) match(percent)
|
||||
match(num_6) match(power)
|
||||
match(num_7) match(ampersand)
|
||||
match(num_8) match(asterisk)
|
||||
match(num_9) match(lparenthesis)
|
||||
match(num_0) match(rparenthesis)
|
||||
match(minus) match(underscore) match(equal) match(plus) match(backspace)
|
||||
match(ins) match(del) match(home) match(end) match(page_up) match(page_down)
|
||||
match(a) match(b) match(c) match(d) match(e) match(f)
|
||||
match(g) match(h) match(i) match(j) match(k) match(l)
|
||||
match(m) match(n) match(o) match(p) match(q) match(r)
|
||||
match(s) match(t) match(u) match(v) match(w) match(x)
|
||||
match(y) match(z)
|
||||
match(A) match(B) match(C) match(D) match(E) match(F)
|
||||
match(G) match(H) match(I) match(J) match(K) match(L)
|
||||
match(M) match(N) match(O) match(P) match(Q) match(R)
|
||||
match(S) match(T) match(U) match(V) match(W) match(X)
|
||||
match(Y) match(Z)
|
||||
match(lbracket) match(lbrace)
|
||||
match(rbracket) match(rbrace)
|
||||
match(backslash) match(pipe)
|
||||
match(semicolon) match(colon)
|
||||
match(apostrophe) match(quote)
|
||||
match(comma) match(lcaret)
|
||||
match(period) match(rcaret)
|
||||
match(slash) match(question)
|
||||
match(kp_1) match(kp_end)
|
||||
match(kp_2) match(kp_down)
|
||||
match(kp_3) match(kp_page_down)
|
||||
match(kp_4) match(kp_left)
|
||||
match(kp_5) match(kp_center)
|
||||
match(kp_6) match(kp_right)
|
||||
match(kp_7) match(kp_home)
|
||||
match(kp_8) match(kp_up)
|
||||
match(kp_9) match(kp_page_up)
|
||||
match(kp_0) match(kp_insert)
|
||||
match(kp_decimal) match(kp_delete)
|
||||
match(kp_plus) match(kp_minus) match(kp_mul) match(kp_div) match(kp_enter)
|
||||
match(num_lock) match(caps_lock)
|
||||
match(up) match(down) match(left) match(right)
|
||||
match(tab) match(enter) match(space)
|
||||
match(lctrl) match(rctrl)
|
||||
match(lalt) match(ralt)
|
||||
match(lshift) match(rshift)
|
||||
match(lsuper) match(rsuper)
|
||||
match(menu)
|
||||
#undef match
|
||||
|
||||
if(key & joypad_flag) {
|
||||
uint joypad = (key & joypad_nummask) >> 8;
|
||||
uint button = (key & joypad_keymask);
|
||||
if(button == joypad_up) { sprintf(out, "joypad%d.up", joypad); return out; }
|
||||
if(button == joypad_down) { sprintf(out, "joypad%d.down", joypad); return out; }
|
||||
if(button == joypad_left) { sprintf(out, "joypad%d.left", joypad); return out; }
|
||||
if(button == joypad_right) { sprintf(out, "joypad%d.right", joypad); return out; }
|
||||
sprintf(out, "joypad%d.button%d", joypad, button & 127);
|
||||
return out;
|
||||
}
|
||||
|
||||
strcpy(out, "none");
|
||||
return out;
|
||||
}
|
||||
|
||||
static char find_t[256];
|
||||
|
||||
static const char *find(uint16 key) {
|
||||
find(find_t, key);
|
||||
return find_t;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,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');
|
||||
|
@ -139,23 +139,23 @@ uint i = 0;
|
|||
}
|
||||
string &strupper(string &str) { strupper(strptr(str)); return str; }
|
||||
|
||||
index_t strpos(const char *str, const char *key) {
|
||||
int strpos(const char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return index_t(false);
|
||||
if(ksl > ssl)return -1;
|
||||
for(int i = 0; i <= ssl - ksl; i++) {
|
||||
if(!memcmp(str + i, key, ksl)) {
|
||||
return index_t(true, i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return index_t(false);
|
||||
return -1;
|
||||
}
|
||||
index_t strpos(const string &str, const char *key) { return strpos(strptr(str), key); }
|
||||
index_t strpos(const char *str, const string &key) { return strpos(str, strptr(key)); }
|
||||
index_t strpos(const string &str, const string &key) { return strpos(strptr(str), strptr(key)); }
|
||||
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)); }
|
||||
|
||||
index_t qstrpos(const char *str, const char *key) {
|
||||
int qstrpos(const char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return index_t(false);
|
||||
if(ksl > ssl)return -1;
|
||||
for(int i = 0; i <= ssl - ksl;) {
|
||||
uint8 x = str[i];
|
||||
if(x == '\"' || x == '\'') {
|
||||
|
@ -164,16 +164,16 @@ int ssl = strlen(str), ksl = strlen(key);
|
|||
if(i >= ssl)i = z;
|
||||
}
|
||||
if(!memcmp(str + i, key, ksl)) {
|
||||
return index_t(true, i);
|
||||
return i;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return index_t(false);
|
||||
return -1;
|
||||
}
|
||||
index_t qstrpos(const string &str, const char *key) { return qstrpos(strptr(str), key); }
|
||||
index_t qstrpos(const char *str, const string &key) { return qstrpos(str, strptr(key)); }
|
||||
index_t qstrpos(const string &str, const string &key) { return qstrpos(strptr(str), strptr(key)); }
|
||||
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);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
libstring : version 0.15 ~byuu (2007-01-13)
|
||||
libstring : version 0.17 ~byuu (2007-05-20)
|
||||
*/
|
||||
|
||||
#ifndef __LIBSTRING
|
||||
|
@ -7,7 +7,6 @@
|
|||
|
||||
#include "libbase.h"
|
||||
#include "libvector.h"
|
||||
#include "libtuple.h"
|
||||
|
||||
class string;
|
||||
typedef linear_vector<string> stringarray;
|
||||
|
@ -17,6 +16,9 @@ char chrupper(char c);
|
|||
|
||||
uint count(stringarray &str);
|
||||
|
||||
int find(stringarray &str, const char *key);
|
||||
int find(stringarray &str, const string &key);
|
||||
|
||||
char *strptr(const string &str);
|
||||
uint strlen(const string &str);
|
||||
|
||||
|
@ -59,16 +61,15 @@ string &strlower(string &str);
|
|||
char *strupper(char *str);
|
||||
string &strupper(string &str);
|
||||
|
||||
typedef tuple<bool, uint> index_t;
|
||||
index_t strpos(const char *str, const char *key);
|
||||
index_t strpos(const string &str, const char *key);
|
||||
index_t strpos(const char *str, const string &key);
|
||||
index_t strpos(const string &str, const string &key);
|
||||
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);
|
||||
|
||||
index_t qstrpos(const char *str, const char *key);
|
||||
index_t qstrpos(const string &str, const char *key);
|
||||
index_t qstrpos(const char *str, const string &key);
|
||||
index_t qstrpos(const string &str, const string &key);
|
||||
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);
|
||||
|
|
|
@ -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)); }
|
|
@ -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;
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
libtuple : version 0.01 ~byuu (2007-01-04)
|
||||
|
||||
dependencies:
|
||||
- libbase
|
||||
*/
|
||||
|
||||
#ifndef __LIBTUPLE
|
||||
#define __LIBTUPLE
|
||||
|
||||
/*****
|
||||
* tuple definitions
|
||||
*****/
|
||||
|
||||
template<
|
||||
typename = null_t, typename = null_t, typename = null_t, typename = null_t,
|
||||
typename = null_t, typename = null_t, typename = null_t, typename = null_t
|
||||
> struct tuple;
|
||||
template<int, typename> struct tuple_traits;
|
||||
|
||||
/*****
|
||||
* tuple_traits
|
||||
*****/
|
||||
|
||||
#define make_tuple_traits(n) \
|
||||
template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> \
|
||||
struct tuple_traits< n, tuple<T0, T1, T2, T3, T4, T5, T6, T7> > { \
|
||||
typedef T##n type; \
|
||||
static inline T##n &get(tuple<T0, T1, T2, T3, T4, T5, T6, T7> &t) { return t.t##n; } \
|
||||
};
|
||||
|
||||
make_tuple_traits(0)
|
||||
make_tuple_traits(1)
|
||||
make_tuple_traits(2)
|
||||
make_tuple_traits(3)
|
||||
make_tuple_traits(4)
|
||||
make_tuple_traits(5)
|
||||
make_tuple_traits(6)
|
||||
make_tuple_traits(7)
|
||||
|
||||
#undef make_tuple_traits
|
||||
|
||||
/*****
|
||||
* tuple
|
||||
*****/
|
||||
|
||||
template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
|
||||
struct tuple {
|
||||
T0 t0;
|
||||
T1 t1;
|
||||
T2 t2;
|
||||
T3 t3;
|
||||
T4 t4;
|
||||
T5 t5;
|
||||
T6 t6;
|
||||
T7 t7;
|
||||
template<int index>
|
||||
typename tuple_traits<index, tuple>::type &get() {
|
||||
return tuple_traits<index, tuple>::get(*this);
|
||||
}
|
||||
bool operator==(const tuple &source) {
|
||||
return (t0 == source.t0 && t1 == source.t1 && t2 == source.t2 && t3 == source.t3 &&
|
||||
t4 == source.t4 && t5 == source.t5 && t6 == source.t6 && t7 == source.t7);
|
||||
}
|
||||
bool operator!=(const tuple &source) {
|
||||
return (t0 != source.t0 && t1 != source.t1 && t2 != source.t2 && t3 != source.t3 &&
|
||||
t4 != source.t4 && t5 != source.t5 && t6 != source.t6 && t7 != source.t7);
|
||||
}
|
||||
tuple(const tuple &t) { operator=(t); }
|
||||
tuple(const T0 &_t0 = T0(), const T1 &_t1 = T1(), const T2 &_t2 = T2(), const T3 &_t3 = T3(),
|
||||
const T4 &_t4 = T4(), const T5 &_t5 = T5(), const T6 &_t6 = T6(), const T7 &_t7 = T7()) :
|
||||
t0(_t0), t1(_t1), t2(_t2), t3(_t3), t4(_t4), t5(_t5), t6(_t6), t7(_t7) {}
|
||||
};
|
||||
|
||||
template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
|
||||
tuple<T0, T1, T2, T3, T4, T5, T6, T7> make_tuple(
|
||||
const T0 &t0 = T0(), const T1 &t1 = T1(), const T2 &t2 = T2(), const T3 &t3 = T3(),
|
||||
const T4 &t4 = T4(), const T5 &t5 = T5(), const T6 &t6 = T6(), const T7 &t7 = T7()) {
|
||||
return tuple<T0, T1, T2, T3, T4, T5, T6, T7>(t0, t1, t2, t3, t4, t5, t6, t7);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,3 +1,5 @@
|
|||
#include <gdk/gdkx.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include "libui_gtk.h"
|
||||
#include "libui_gtk_window.cpp"
|
||||
#include "libui_gtk_control.cpp"
|
||||
|
@ -36,4 +38,257 @@ bool events_pending() {
|
|||
uint get_screen_width() { return gdk_screen_width(); }
|
||||
uint get_screen_height() { return gdk_screen_height(); }
|
||||
|
||||
//
|
||||
|
||||
noinline bool gtk_file_load(Window &owner, char *filename, const char *filter, const char *path) {
|
||||
strcpy(filename, "");
|
||||
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new("Load File",
|
||||
GTK_WINDOW(owner.info.window), GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, 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 != ""
|
||||
}
|
||||
|
||||
noinline bool gtk_file_save(Window &owner, char *filename, const char *filter, const char *path) {
|
||||
strcpy(filename, "");
|
||||
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new("Save File",
|
||||
GTK_WINDOW(owner.info.window), GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, 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 != ""
|
||||
}
|
||||
|
||||
//FreeBSD 6.2-amd64 bug workaround for file_load() + file_save()
|
||||
//gdb reveals stack corruption when calling gtk_file_chooset_dialog_new() from inside
|
||||
//a member function. however, calling function with nesting sidesteps the bug ...
|
||||
//gdb shows that the corruption occurs inside a GTK+ internal library function ...
|
||||
|
||||
bool file_load(Window &owner, char *filename, const char *filter, const char *path) {
|
||||
return gtk_file_load(owner, filename, filter, path);
|
||||
}
|
||||
|
||||
bool file_save(Window &owner, char *filename, const char *filter, const char *path) {
|
||||
return gtk_file_save(owner, filename, filter, path);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -1,15 +1,25 @@
|
|||
/*
|
||||
libui_gtk ~byuu (2007-01-29)
|
||||
libui_gtk ~byuu (2007-05-27)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#ifndef __LIBUI
|
||||
#define __LIBUI
|
||||
#ifndef LIBUI_H
|
||||
#define LIBUI_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkx.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();
|
||||
|
@ -18,52 +28,55 @@ bool events_pending();
|
|||
uint get_screen_width();
|
||||
uint get_screen_height();
|
||||
|
||||
class Window;
|
||||
typedef unsigned long WindowHandle;
|
||||
#include "libui_gtk_control.h"
|
||||
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:
|
||||
struct {
|
||||
GtkWidget *window;
|
||||
GtkWidget *vcontainer, *container;
|
||||
array<Control*> control;
|
||||
uint control_index;
|
||||
enum Style {
|
||||
Center = 1,
|
||||
};
|
||||
|
||||
bool has_menu;
|
||||
array<MenuGroup*> menu_group;
|
||||
uint menu_group_index;
|
||||
} info;
|
||||
|
||||
WindowHandle handle();
|
||||
void create(const char *style, uint width, uint height, const char *caption = "");
|
||||
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();
|
||||
void move(uint x, uint y);
|
||||
void resize(uint width, uint height);
|
||||
virtual void show();
|
||||
virtual void hide();
|
||||
virtual bool close() { return true; }
|
||||
virtual void keydown(uint key) {}
|
||||
virtual void keyup(uint key) {}
|
||||
virtual void keydown(uint16 key) {}
|
||||
virtual void keyup(uint16 key) {}
|
||||
|
||||
void set_background_color(uint8 r, uint8 g, uint8 b);
|
||||
virtual int message(uint id, void *param = 0) {}
|
||||
virtual void clicked(Control&) {}
|
||||
virtual void changed(Control&) {}
|
||||
|
||||
bool file_load(char *filename, const char *filter, const char *path = "");
|
||||
bool file_save(char *filename, const char *filter, const char *path = "");
|
||||
|
||||
void menu_begin();
|
||||
void menu_end();
|
||||
void menu_group_begin(MenuGroup &group);
|
||||
void menu_group_end();
|
||||
void menu_add_item(Control &item);
|
||||
void menu_add_separator();
|
||||
|
||||
void attach(Control &control, uint x, uint y, bool attach_to_window = true);
|
||||
virtual void clicked(Control*) {}
|
||||
//private:
|
||||
struct {
|
||||
GtkWidget *window, *menubar;
|
||||
GtkWidget *vcontainer, *container;
|
||||
} info;
|
||||
|
||||
public:
|
||||
Window() {
|
||||
info.control_index = 1;
|
||||
info.has_menu = false;
|
||||
info.menu_group_index = 1;
|
||||
info.menubar = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,56 +1,5 @@
|
|||
namespace libui {
|
||||
|
||||
/*****
|
||||
* FileLoad
|
||||
*****/
|
||||
|
||||
bool Window::file_load(char *filename, const char *filter, const char *path) {
|
||||
strcpy(filename, "");
|
||||
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new("Load File",
|
||||
GTK_WINDOW(info.window), GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, 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 != ""
|
||||
}
|
||||
|
||||
/*****
|
||||
* FileSave
|
||||
*****/
|
||||
|
||||
bool Window::file_save(char *filename, const char *filter, const char *path) {
|
||||
strcpy(filename, "");
|
||||
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new("Save File",
|
||||
GTK_WINDOW(info.window), GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, 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 != ""
|
||||
}
|
||||
|
||||
/*****
|
||||
* Control
|
||||
*****/
|
||||
|
@ -63,6 +12,10 @@ 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);
|
||||
}
|
||||
|
@ -96,84 +49,73 @@ bool Control::enabled() {
|
|||
}
|
||||
|
||||
/*****
|
||||
* Menu
|
||||
* MenuBar
|
||||
*****/
|
||||
|
||||
void Window::menu_begin() {}
|
||||
void Window::menu_end() {}
|
||||
|
||||
/*****
|
||||
* Menu
|
||||
*****/
|
||||
|
||||
void Window::menu_group_begin(MenuGroup &group) {
|
||||
info.control[info.control_index] = &group;
|
||||
group.id = info.control_index++;
|
||||
group.owner = this;
|
||||
info.menu_group[++info.menu_group_index] = &group;
|
||||
void MenuBar::create(Window &r_owner) {
|
||||
type = ControlType::MenuBar;
|
||||
widget = r_owner.info.menubar;
|
||||
owner = &r_owner;
|
||||
show();
|
||||
}
|
||||
|
||||
void Window::menu_group_end() {
|
||||
MenuGroup *group = info.menu_group[info.menu_group_index--];
|
||||
MenuGroup *owner = info.menu_group[info.menu_group_index];
|
||||
gtk_menu_item_set_submenu(GTK_MENU_ITEM(group->item), group->widget);
|
||||
gtk_menu_bar_append(owner->widget, group->item);
|
||||
gtk_widget_show(group->item);
|
||||
}
|
||||
|
||||
void Window::menu_add_item(Control &item) {
|
||||
info.control[info.control_index] = &item;
|
||||
MenuGroup &group = *info.menu_group[info.menu_group_index];
|
||||
item.id = info.control_index++;
|
||||
item.owner = this;
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(group.widget), item.widget);
|
||||
g_signal_connect_swapped(G_OBJECT(item.widget), "activate",
|
||||
G_CALLBACK(libui_control_clicked), (gpointer)&item);
|
||||
}
|
||||
|
||||
void Window::menu_add_separator() {
|
||||
MenuItem *item = new MenuItem();
|
||||
info.control[info.control_index] = item;
|
||||
MenuGroup *group = info.menu_group[info.menu_group_index];
|
||||
item->id = info.control_index++;
|
||||
item->owner = this;
|
||||
item->type = Control::MenuItem;
|
||||
item->widget = gtk_separator_menu_item_new();
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(group->widget), item->widget);
|
||||
gtk_widget_show(item->widget);
|
||||
void MenuBar::finish() {
|
||||
}
|
||||
|
||||
/*****
|
||||
* MenuGroup
|
||||
*****/
|
||||
|
||||
MenuGroup& MenuGroup::create(const char *caption) {
|
||||
type = Control::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 : "?");
|
||||
return *this;
|
||||
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
|
||||
*****/
|
||||
|
||||
MenuItem& MenuItem::create(const char *caption) {
|
||||
type = Control::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);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*****
|
||||
* MenuCheckItem
|
||||
*****/
|
||||
|
||||
MenuCheckItem& MenuCheckItem::create(const char *caption) {
|
||||
type = Control::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);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void MenuCheckItem::check() {
|
||||
|
@ -196,14 +138,18 @@ bool MenuCheckItem::checked() {
|
|||
* MenuRadioItem
|
||||
*****/
|
||||
|
||||
MenuRadioItem& MenuRadioItem::create(ControlGroup &list, const char *caption) {
|
||||
void MenuRadioItem::create(MenuGroup &r_owner, ControlGroup &list, const char *caption) {
|
||||
if(list.count() == 0)throw;
|
||||
type = Control::MenuRadioItem;
|
||||
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);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void MenuRadioItem::check() {
|
||||
|
@ -215,39 +161,61 @@ bool MenuRadioItem::checked() {
|
|||
}
|
||||
|
||||
/*****
|
||||
* Container
|
||||
* MenuSeparator
|
||||
*****/
|
||||
|
||||
Container &Container::create(const char *style, uint width, uint height) {
|
||||
type = Control::Container;
|
||||
widget = gtk_fixed_new();
|
||||
gtk_widget_set_size_request(widget, width, height);
|
||||
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);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Container::attach(Control &control, uint x, uint y) {
|
||||
owner->attach(control, x, y, false);
|
||||
gtk_fixed_put(GTK_FIXED(widget), control.widget, x, y);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Canvas
|
||||
* Panel
|
||||
*****/
|
||||
|
||||
Canvas &Canvas::create(const char *style, uint width, uint height) {
|
||||
type = Control::Canvas;
|
||||
widget = gtk_drawing_area_new();
|
||||
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);
|
||||
return *this;
|
||||
}
|
||||
|
||||
WindowHandle Canvas::handle() {
|
||||
return (WindowHandle)(GDK_WINDOW_XWINDOW(widget->window));
|
||||
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 Canvas::set_background_color(uint8 r, uint8 g, uint8 b) {
|
||||
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);
|
||||
|
@ -256,29 +224,101 @@ GdkColor color;
|
|||
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
|
||||
*****/
|
||||
|
||||
Frame& Frame::create(const char *style, uint width, uint height, const char *caption) {
|
||||
type = Control::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);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*****
|
||||
* Label
|
||||
*****/
|
||||
|
||||
Label& Label::create(const char *style, uint width, uint height, const char *caption) {
|
||||
type = Control::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);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Label::set_text(const char *str, ...) {
|
||||
|
@ -290,21 +330,19 @@ string temp;
|
|||
gtk_label_set_label(GTK_LABEL(widget), strptr(temp));
|
||||
}
|
||||
|
||||
uint Label::get_text(char *str, uint length) {
|
||||
const char *temp = gtk_label_get_text(GTK_LABEL(widget));
|
||||
return strlcpy(str, temp ? temp : "", length);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Button
|
||||
*****/
|
||||
|
||||
Button& Button::create(const char *style, uint width, uint height, const char *caption) {
|
||||
type = Control::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);
|
||||
return *this;
|
||||
|
||||
g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(libui_control_clicked), (gpointer)this);
|
||||
}
|
||||
|
||||
void Button::set_text(const char *str, ...) {
|
||||
|
@ -316,21 +354,19 @@ string temp;
|
|||
gtk_button_set_label(GTK_BUTTON(widget), strptr(temp));
|
||||
}
|
||||
|
||||
uint Button::get_text(char *str, uint length) {
|
||||
const char *temp = gtk_button_get_label(GTK_BUTTON(widget));
|
||||
return strlcpy(str, temp ? temp : "", length);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Checkbox
|
||||
*****/
|
||||
|
||||
Checkbox& Checkbox::create(const char *style, uint width, uint height, const char *caption) {
|
||||
type = Control::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);
|
||||
return *this;
|
||||
|
||||
g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(libui_control_clicked), (gpointer)this);
|
||||
}
|
||||
|
||||
void Checkbox::check() {
|
||||
|
@ -353,15 +389,18 @@ bool Checkbox::checked() {
|
|||
* Radiobox
|
||||
*****/
|
||||
|
||||
Radiobox& Radiobox::create(ControlGroup &group, const char *style, uint width, uint height, const char *caption) {
|
||||
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 = Control::Radiobox;
|
||||
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);
|
||||
return *this;
|
||||
|
||||
g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(libui_control_clicked), (gpointer)this);
|
||||
}
|
||||
|
||||
void Radiobox::check() {
|
||||
|
@ -376,27 +415,36 @@ bool Radiobox::checked() {
|
|||
* Editbox
|
||||
*****/
|
||||
|
||||
Editbox& Editbox::create(const char *style, uint width, uint height, const char *caption) {
|
||||
type = Control::Editbox;
|
||||
multiline = false;
|
||||
stringarray part;
|
||||
split(part, "|", style);
|
||||
for(uint i = 0; i < count(part); i++) {
|
||||
if(part[i] == "multiline")multiline = true;
|
||||
}
|
||||
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 {
|
||||
widget = gtk_text_view_new();
|
||||
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
|
||||
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);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Editbox::set_text(const char *str, ...) {
|
||||
|
@ -418,9 +466,10 @@ uint Editbox::get_text(char *str, uint length) {
|
|||
const char *temp = gtk_entry_get_text(GTK_ENTRY(widget));
|
||||
return strlcpy(str, temp ? temp : "", length);
|
||||
} else {
|
||||
//not sure how to use GtkTextIter* to retrieve editbox text buffer ...
|
||||
strcpy(str, "");
|
||||
return 0;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -433,15 +482,13 @@ uint Editbox::get_text(char *str, uint length) {
|
|||
* Attempt to understand the below code at the risk of your own sanity.
|
||||
*****/
|
||||
|
||||
Listbox& Listbox::create(const char *style, uint width, uint height, const char *columns, const char *data) {
|
||||
type = Control::Listbox;
|
||||
stringarray list, part;
|
||||
split(part, "|", style);
|
||||
bool header = false;
|
||||
for(uint i = 0; i < count(part); i++) {
|
||||
if(part[i] == "header")header = true;
|
||||
}
|
||||
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));
|
||||
|
@ -449,37 +496,42 @@ GType *v = (GType*)malloc(count(part) * sizeof(GType));
|
|||
store = gtk_list_store_newv(count(part), v);
|
||||
safe_free(v);
|
||||
|
||||
if(data && strcmp(data, "")) {
|
||||
split(list, "||", data);
|
||||
for(uint l = 0; l < count(list); l++) {
|
||||
gtk_list_store_append(store, &iter);
|
||||
split(part, "|", list[l]);
|
||||
for(uint i = 0; i < count(part); i++) {
|
||||
gtk_list_store_set(store, &iter, i, strptr(part[i]), -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
widget = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
|
||||
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(widget), column);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(subwidget), column);
|
||||
}
|
||||
|
||||
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(widget), header);
|
||||
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(subwidget), header);
|
||||
autosize_columns();
|
||||
return *this;
|
||||
|
||||
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(widget));
|
||||
gtk_tree_view_columns_autosize(GTK_TREE_VIEW(subwidget));
|
||||
}
|
||||
|
||||
void Listbox::set_column_width(uint column, uint width) {
|
||||
|
@ -487,19 +539,46 @@ void Listbox::set_column_width(uint column, uint width) {
|
|||
gtk_tree_view_column_set_max_width(column_list[column], width);
|
||||
}
|
||||
|
||||
void Listbox::add_item(const char *data) {
|
||||
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, "|", data);
|
||||
split(part, "|", temp);
|
||||
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, ...) {
|
||||
va_list args;
|
||||
va_start(args, data);
|
||||
string temp;
|
||||
vsprintf(temp, data, args);
|
||||
va_end(args);
|
||||
|
||||
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, "|", temp);
|
||||
for(uint i = 0; i < count(part); i++) {
|
||||
gtk_list_store_set(store, &iter, i, strptr(part[i]), -1);
|
||||
}
|
||||
}
|
||||
|
||||
int Listbox::get_selection() {
|
||||
//... because gtk_tree_view_get_selected_row(GTK_TREE_VIEW(widget)) would be too easy ...
|
||||
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
|
||||
//... because gtk_tree_view_get_selected_row(GTK_TREE_VIEW(subwidget)) would be too easy ...
|
||||
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++) {
|
||||
|
@ -510,9 +589,9 @@ GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
|
|||
}
|
||||
|
||||
void Listbox::set_selection(int index) {
|
||||
//... because gtk_tree_view_set_selected_row(GTK_TREE_VIEW(widget), index) would be too easy ...
|
||||
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
|
||||
//... because gtk_tree_view_set_selected_row(GTK_TREE_VIEW(subwidget), index) would be too easy ...
|
||||
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) { return; }
|
||||
if(gtk_tree_model_get_iter_first(model, &iter) == false) { return; }
|
||||
|
@ -525,31 +604,21 @@ GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
|
|||
|
||||
void Listbox::reset() {
|
||||
gtk_list_store_clear(GTK_LIST_STORE(store));
|
||||
gtk_tree_view_set_model(GTK_TREE_VIEW(widget), GTK_TREE_MODEL(store));
|
||||
gtk_tree_view_set_model(GTK_TREE_VIEW(subwidget), GTK_TREE_MODEL(store));
|
||||
}
|
||||
|
||||
/*****
|
||||
* Combobox
|
||||
*****/
|
||||
|
||||
Combobox& Combobox::create(const char *style, uint width, uint height, const char *data) {
|
||||
type = Control::Combobox;
|
||||
widget = gtk_combo_box_new_text(); //gtk_combo_box_entry_new_text();
|
||||
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);
|
||||
|
||||
if(data && strcmp(data, "")) {
|
||||
stringarray temp;
|
||||
split(temp, "|", data);
|
||||
for(int i = 0; i < count(temp); i++) {
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(widget), strptr(temp[i]));
|
||||
counter++;
|
||||
}
|
||||
set_selection(0);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Combobox::add_item(const char *data) {
|
||||
|
@ -577,12 +646,13 @@ void Combobox::reset() {
|
|||
* Progressbar
|
||||
*****/
|
||||
|
||||
Progressbar& Progressbar::create(const char *style, uint width, uint height) {
|
||||
type = Control::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);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Progressbar::set_progress(uint progress) {
|
||||
|
@ -600,27 +670,24 @@ uint p = (uint)(gtk_progress_bar_get_fraction(GTK_PROGRESS_BAR(widget)) * 100.0)
|
|||
* Slider
|
||||
*****/
|
||||
|
||||
Slider& Slider::create(const char *style, uint width, uint height, uint min, uint max) {
|
||||
type = Control::Slider;
|
||||
orientation = 0;
|
||||
|
||||
stringarray part;
|
||||
split(part, "|", style);
|
||||
for(uint i = 0; i < count(part); i++) {
|
||||
if(part[i] == "horizontal")orientation = 0;
|
||||
if(part[i] == "vertical")orientation = 1;
|
||||
}
|
||||
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(min, max, 1);
|
||||
widget = gtk_hscale_new_with_range(0, range - 1, 1);
|
||||
} else {
|
||||
widget = gtk_vscale_new_with_range(min, max, 1);
|
||||
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);
|
||||
return *this;
|
||||
|
||||
g_signal_connect_swapped(G_OBJECT(widget), "value-changed", G_CALLBACK(libui_control_changed), (gpointer)this);
|
||||
}
|
||||
|
||||
void Slider::set_position(uint position) {
|
||||
|
|
|
@ -1,146 +1,257 @@
|
|||
class Control { public:
|
||||
Window *owner;
|
||||
GtkWidget *widget;
|
||||
uint id;
|
||||
uint type;
|
||||
|
||||
enum {
|
||||
Invalid,
|
||||
MenuGroup,
|
||||
MenuItem,
|
||||
MenuCheckItem,
|
||||
MenuRadioItem,
|
||||
Container,
|
||||
Canvas,
|
||||
Frame,
|
||||
Label,
|
||||
Button,
|
||||
Checkbox,
|
||||
Radiobox,
|
||||
Editbox,
|
||||
Listbox,
|
||||
Combobox,
|
||||
Progressbar,
|
||||
Slider,
|
||||
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();
|
||||
void show(bool state);
|
||||
bool visible();
|
||||
|
||||
void enable(bool state);
|
||||
void enable();
|
||||
void disable();
|
||||
void enable(bool state);
|
||||
bool enabled();
|
||||
|
||||
Control() : owner(0), widget(0), id(0), type(Invalid) {}
|
||||
//protected:
|
||||
Window *owner;
|
||||
GtkWidget *widget;
|
||||
uint id;
|
||||
|
||||
public:
|
||||
Control() : owner(0), widget(0), id(0), type(ControlType::Invalid) {}
|
||||
};
|
||||
|
||||
class ControlGroup { public:
|
||||
array<Control*> list;
|
||||
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:
|
||||
bool master;
|
||||
GtkWidget *item;
|
||||
MenuGroup &create(const char *caption);
|
||||
MenuGroup() : master(false) {}
|
||||
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:
|
||||
MenuItem &create(const char *caption);
|
||||
void create(MenuGroup &owner, const char *caption);
|
||||
|
||||
private:
|
||||
GtkWidget *parent;
|
||||
};
|
||||
|
||||
class MenuCheckItem : public Control { public:
|
||||
MenuCheckItem &create(const char *caption);
|
||||
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:
|
||||
MenuRadioItem &create(ControlGroup &list, const char *caption);
|
||||
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:
|
||||
Container &create(const char *style, uint width, uint height);
|
||||
void attach(Control &control, uint x, uint y);
|
||||
};
|
||||
class Canvas : public Control { public:
|
||||
Canvas &create(const char *style, uint width, uint height);
|
||||
WindowHandle handle();
|
||||
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:
|
||||
Frame &create(const char *style, uint width, uint height, const char *caption = "");
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
};
|
||||
|
||||
class Label : public Control { public:
|
||||
Label &create(const char *style, uint width, uint height, const char *caption = "");
|
||||
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);
|
||||
};
|
||||
|
||||
class Button : public Control { public:
|
||||
Button &create(const char *style, uint width, uint height, const char *caption = "");
|
||||
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);
|
||||
};
|
||||
|
||||
class Checkbox : public Control { public:
|
||||
Checkbox &create(const char *style, uint width, uint height, const char *caption = "");
|
||||
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:
|
||||
Radiobox &create(ControlGroup &group, const char *style, uint width, uint height, const char *caption = "");
|
||||
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 {
|
||||
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;
|
||||
Editbox &create(const char *style, uint width, uint height, const char *caption = "");
|
||||
void set_text(const char *str, ...);
|
||||
uint get_text(char *str, uint length);
|
||||
};
|
||||
|
||||
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;
|
||||
Listbox &create(const char *style, uint width, uint height, const char *columns = "", const char *data = "");
|
||||
void autosize_columns();
|
||||
void set_column_width(uint column, uint width);
|
||||
void add_item(const char *data);
|
||||
int get_selection();
|
||||
void set_selection(int index);
|
||||
void reset();
|
||||
};
|
||||
|
||||
class Combobox : public Control { public:
|
||||
uint counter;
|
||||
Combobox &create(const char *style, uint width, uint height, const char *caption = "");
|
||||
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:
|
||||
Progressbar &create(const char *style, uint width, uint height);
|
||||
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:
|
||||
bool orientation;
|
||||
Slider &create(const char *style, uint width, uint height, uint min, uint max);
|
||||
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;
|
||||
};
|
||||
|
|
|
@ -1,49 +1,33 @@
|
|||
namespace libui {
|
||||
|
||||
gint libui_window_close(GtkWidget *w, GdkEventAny *any, Window *window) {
|
||||
if(window) { return !window->close(); }
|
||||
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->keydown(key->keyval); }
|
||||
if(window) { window->message(Message::KeyDown, (void*)libui::translate_key(key->keyval)); }
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gint libui_window_keyup(GtkWidget *w, GdkEventKey *key, Window *window) {
|
||||
if(window) { window->keyup(key->keyval); }
|
||||
if(window) { window->message(Message::KeyUp, (void*)libui::translate_key(key->keyval)); }
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void libui_control_clicked(Control *control) {
|
||||
if(control && control->owner) { control->owner->clicked(control); }
|
||||
if(control && control->owner) { control->owner->message(Message::Clicked, control); }
|
||||
}
|
||||
|
||||
WindowHandle Window::handle() {
|
||||
return (WindowHandle)(GDK_WINDOW_XWINDOW(info.window->window));
|
||||
void libui_control_changed(Control *control) {
|
||||
if(control && control->owner) { control->owner->message(Message::Changed, control); }
|
||||
}
|
||||
|
||||
void Window::attach(Control &control, uint x, uint y, bool attach_to_window) {
|
||||
info.control[info.control_index] = &control;
|
||||
control.id = info.control_index++;
|
||||
control.owner = this;
|
||||
if(attach_to_window == true) {
|
||||
gtk_fixed_put(GTK_FIXED(info.container), control.widget, x, y);
|
||||
}
|
||||
|
||||
switch(control.type) {
|
||||
|
||||
case Control::Button:
|
||||
case Control::Checkbox:
|
||||
case Control::Radiobox: {
|
||||
g_signal_connect_swapped(G_OBJECT(control.widget), "clicked",
|
||||
G_CALLBACK(libui_control_clicked), (gpointer)&control);
|
||||
} break;
|
||||
|
||||
}
|
||||
void libui_control_double_clicked(Control *control) {
|
||||
if(control && control->owner) { control->owner->message(Message::DoubleClicked, control); }
|
||||
}
|
||||
|
||||
void Window::create(const char *style, uint width, uint height, const char *caption) {
|
||||
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);
|
||||
|
@ -51,31 +35,16 @@ void Window::create(const char *style, uint width, uint height, const char *capt
|
|||
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);
|
||||
|
||||
stringarray part;
|
||||
split(part, "|", style);
|
||||
for(int i = 0; i < count(part); i++) {
|
||||
if(part[i] == "menu") { info.has_menu = true; }
|
||||
if(part[i] == "center") { gtk_window_set_position(GTK_WINDOW(info.window), GTK_WIN_POS_CENTER_ALWAYS); }
|
||||
}
|
||||
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);
|
||||
|
||||
if(info.has_menu == true) {
|
||||
MenuGroup *group = new MenuGroup();
|
||||
info.control[info.control_index] = group;
|
||||
|
||||
group->id = info.control_index++;
|
||||
group->owner = this;
|
||||
group->type = Control::MenuGroup;
|
||||
group->master = true;
|
||||
group->widget = gtk_menu_bar_new();
|
||||
gtk_box_pack_start(GTK_BOX(info.vcontainer), group->widget, false, false, 0);
|
||||
gtk_widget_show(group->widget);
|
||||
|
||||
info.menu_group[++info.menu_group_index] = group;
|
||||
}
|
||||
//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);
|
||||
|
@ -106,6 +75,15 @@ void Window::hide() {
|
|||
gtk_widget_hide(info.window);
|
||||
}
|
||||
|
||||
void Window::set_text(const char *str, ...) {
|
||||
va_list args;
|
||||
va_start(args, str);
|
||||
string temp;
|
||||
vsprintf(temp, str, args);
|
||||
va_end(args);
|
||||
gtk_window_set_title(GTK_WINDOW(info.window), strptr(temp));
|
||||
}
|
||||
|
||||
void Window::set_background_color(uint8 r, uint8 g, uint8 b) {
|
||||
GdkColor color;
|
||||
color.pixel = (r << 16) | (g << 8) | (b);
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
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),
|
||||
|
@ -28,12 +31,32 @@ WNDCLASS wc;
|
|||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&wc);
|
||||
|
||||
message_window = CreateWindow("libui_class", "", WS_POPUP,
|
||||
0, 0, 64, 64, 0, 0, GetModuleHandle(0), 0);
|
||||
SetWindowLongPtr(message_window, GWLP_USERDATA, 0);
|
||||
|
||||
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() {
|
||||
|
@ -56,4 +79,146 @@ MSG msg;
|
|||
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.info.hwnd;
|
||||
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.info.hwnd;
|
||||
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_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;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -1,10 +1,19 @@
|
|||
/*
|
||||
libui_win ~byuu (2006-01-29)
|
||||
libui_win ~byuu (2007-05-28)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#ifndef __LIBUI
|
||||
#define __LIBUI
|
||||
#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>
|
||||
|
@ -12,6 +21,9 @@
|
|||
|
||||
namespace libui {
|
||||
|
||||
class Window;
|
||||
#include "libui_win_control.h"
|
||||
|
||||
void init();
|
||||
void term();
|
||||
bool run();
|
||||
|
@ -20,71 +32,77 @@ bool events_pending();
|
|||
uint get_screen_width();
|
||||
uint get_screen_height();
|
||||
|
||||
class Window;
|
||||
typedef HWND WindowHandle;
|
||||
#include "libui_win_control.h"
|
||||
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();
|
||||
void move(uint x, uint y);
|
||||
void resize(uint width, uint height);
|
||||
virtual void show();
|
||||
virtual void hide();
|
||||
|
||||
virtual int message(uint id, void *param = 0) { return 0; }
|
||||
|
||||
void move(Control &control, uint x, uint y);
|
||||
void attach(Control &control);
|
||||
|
||||
Window();
|
||||
|
||||
//platform-dependent:
|
||||
HWND handle();
|
||||
|
||||
//private:
|
||||
struct {
|
||||
uint width, height;
|
||||
|
||||
HWND hwnd;
|
||||
HWND hwnd_resize;
|
||||
HBRUSH background;
|
||||
HMENU menubar;
|
||||
bool center;
|
||||
array<Control*> control;
|
||||
uint control_index;
|
||||
|
||||
bool has_menu;
|
||||
MenuGroup menu_owner;
|
||||
array<MenuGroup*> menu_group;
|
||||
uint menu_group_index;
|
||||
array<MenuRadioItem*> menu_check_list;
|
||||
} info;
|
||||
long wndproc(HWND hwnd, uint msg, WPARAM wparam, LPARAM lparam);
|
||||
|
||||
WindowHandle handle();
|
||||
void create(const char *style, uint width, uint height, const char *caption);
|
||||
void focus();
|
||||
void move(uint x, uint y);
|
||||
void resize(uint width, uint height);
|
||||
virtual void show();
|
||||
virtual void hide();
|
||||
virtual bool close() { return true; }
|
||||
virtual void keydown(uint key) {}
|
||||
virtual void keyup(uint key) {}
|
||||
|
||||
void set_background_color(uint8 r, uint8 g, uint8 b);
|
||||
|
||||
bool file_load(char *filename, const char *filter, const char *path = "");
|
||||
bool file_save(char *filename, const char *filter, const char *path = "");
|
||||
|
||||
void menu_begin();
|
||||
void menu_end();
|
||||
void menu_group_begin(MenuGroup &group);
|
||||
void menu_group_end();
|
||||
void menu_add_item(Control &item);
|
||||
void menu_add_separator();
|
||||
|
||||
void move(Control &control, uint x, uint y);
|
||||
void attach(Control &control, uint x, uint y, bool attach_to_window = true);
|
||||
virtual void clicked(Control*) {}
|
||||
|
||||
Window();
|
||||
};
|
||||
|
||||
//platform dependent
|
||||
//platform-dependent:
|
||||
|
||||
static uint window_count = 0;
|
||||
|
||||
HFONT create_font(const char *name, uint size);
|
||||
HWND message_window;
|
||||
|
||||
struct {
|
||||
static struct {
|
||||
HFONT variable;
|
||||
HFONT fixed;
|
||||
} font;
|
||||
|
||||
HFONT create_font(const char *name, uint size);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,95 +1,5 @@
|
|||
namespace libui {
|
||||
|
||||
/*****
|
||||
* FileLoad
|
||||
*****/
|
||||
|
||||
bool Window::file_load(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 = info.hwnd;
|
||||
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);
|
||||
}
|
||||
|
||||
/*****
|
||||
* FileSave
|
||||
*****/
|
||||
|
||||
bool Window::file_save(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 = info.hwnd;
|
||||
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);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Control
|
||||
*****/
|
||||
|
@ -98,6 +8,10 @@ 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);
|
||||
}
|
||||
|
@ -131,104 +45,105 @@ bool Control::enabled() {
|
|||
}
|
||||
|
||||
/*****
|
||||
* Menu
|
||||
* MenuBar
|
||||
*****/
|
||||
|
||||
void Window::menu_begin() {
|
||||
info.menu_check_list.reset();
|
||||
void MenuBar::create(Window &r_owner) {
|
||||
type = ControlType::MenuBar;
|
||||
group = CreateMenu();
|
||||
r_owner.attach(*this);
|
||||
owner->info.menu_check_list.reset();
|
||||
}
|
||||
|
||||
void Window::menu_end() {
|
||||
SetMenu(info.hwnd_resize, info.menu_owner.group);
|
||||
SetMenu(info.hwnd, info.menu_owner.group);
|
||||
resize(info.width, info.height);
|
||||
void MenuBar::finish() {
|
||||
show();
|
||||
|
||||
//check all menu radio items that need to be ...
|
||||
for(uint i = 0; i < info.menu_check_list.size(); i++) {
|
||||
info.menu_check_list[i]->check();
|
||||
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);
|
||||
}
|
||||
info.menu_check_list.reset();
|
||||
owner->info.menu_check_list.reset();
|
||||
}
|
||||
|
||||
void Window::menu_group_begin(MenuGroup &group) {
|
||||
info.control[info.control_index] = &group;
|
||||
group.id = info.control_index++;
|
||||
group.owner = this;
|
||||
info.menu_group[++info.menu_group_index] = &group;
|
||||
void MenuBar::show() {
|
||||
SetMenu(owner->info.hwnd_resize, group);
|
||||
SetMenu(owner->info.hwnd, group);
|
||||
owner->resize(owner->info.width, owner->info.height);
|
||||
}
|
||||
|
||||
void Window::menu_group_end() {
|
||||
MenuGroup *group = info.menu_group[info.menu_group_index--];
|
||||
MenuGroup *owner = info.menu_group[info.menu_group_index];
|
||||
AppendMenu(owner->group, MF_STRING | MF_POPUP, (uint)group->group, group->caption);
|
||||
void MenuBar::hide() {
|
||||
SetMenu(owner->info.hwnd_resize, 0);
|
||||
SetMenu(owner->info.hwnd, 0);
|
||||
owner->resize(owner->info.width, owner->info.height);
|
||||
}
|
||||
|
||||
void Window::menu_add_item(Control &item) {
|
||||
info.control[info.control_index] = &item;
|
||||
MenuGroup *group = info.menu_group[info.menu_group_index];
|
||||
item.id = info.control_index++;
|
||||
item.owner = this;
|
||||
|
||||
switch(item.type) {
|
||||
|
||||
case Control::MenuItem: {
|
||||
AppendMenu(group->group, MF_STRING, (uint)item.id, static_cast<MenuItem&>(item).caption);
|
||||
} break;
|
||||
|
||||
case Control::MenuCheckItem: {
|
||||
AppendMenu(group->group, MF_STRING, (uint)item.id, static_cast<MenuCheckItem&>(item).caption);
|
||||
} break;
|
||||
|
||||
case Control::MenuRadioItem: {
|
||||
AppendMenu(group->group, MF_STRING, (uint)item.id, static_cast<MenuRadioItem&>(item).caption);
|
||||
MenuRadioItem &radio = static_cast<MenuRadioItem&>(item);
|
||||
if(&radio == &radio.group[0]) { info.menu_check_list[info.menu_check_list.size()] = &radio; }
|
||||
} break;
|
||||
|
||||
};
|
||||
void MenuBar::show(bool state) {
|
||||
(state == true) ? show() : hide();
|
||||
}
|
||||
|
||||
void Window::menu_add_separator() {
|
||||
MenuGroup *group = info.menu_group[info.menu_group_index];
|
||||
AppendMenu(group->group, MF_SEPARATOR, 0, "");
|
||||
bool MenuBar::visible() {
|
||||
return GetMenu(owner->info.hwnd);
|
||||
}
|
||||
|
||||
/*****
|
||||
* MenuGroup
|
||||
*****/
|
||||
|
||||
MenuGroup& MenuGroup::create(const char *_caption) {
|
||||
type = Control::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);
|
||||
return *this;
|
||||
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
|
||||
*****/
|
||||
|
||||
MenuItem& MenuItem::create(const char *_caption) {
|
||||
type = Control::MenuItem;
|
||||
caption = strdup(_caption);
|
||||
return *this;
|
||||
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
|
||||
*****/
|
||||
|
||||
MenuCheckItem& MenuCheckItem::create(const char *_caption) {
|
||||
type = Control::MenuCheckItem;
|
||||
caption = strdup(_caption);
|
||||
return *this;
|
||||
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() {
|
||||
CheckMenuItem(owner->info.menu_owner.group, id, MF_CHECKED);
|
||||
if(checked() == true)return;
|
||||
CheckMenuItem(parent, id, MF_CHECKED);
|
||||
owner->message(Message::Clicked, this);
|
||||
}
|
||||
|
||||
void MenuCheckItem::uncheck() {
|
||||
CheckMenuItem(owner->info.menu_owner.group, id, MF_UNCHECKED);
|
||||
if(checked() == false)return;
|
||||
CheckMenuItem(parent, id, MF_UNCHECKED);
|
||||
owner->message(Message::Clicked, this);
|
||||
}
|
||||
|
||||
void MenuCheckItem::check(bool state) {
|
||||
|
@ -240,7 +155,7 @@ MENUITEMINFO info;
|
|||
memset(&info, 0, sizeof(info));
|
||||
info.cbSize = sizeof(info);
|
||||
info.fMask = MIIM_STATE;
|
||||
GetMenuItemInfo(owner->info.menu_owner.group, id, false, &info);
|
||||
GetMenuItemInfo(parent, id, false, &info);
|
||||
return (info.fState & MFS_CHECKED);
|
||||
}
|
||||
|
||||
|
@ -248,19 +163,24 @@ MENUITEMINFO info;
|
|||
* MenuRadioItem
|
||||
*****/
|
||||
|
||||
MenuRadioItem& MenuRadioItem::create(ControlGroup &list, const char *_caption) {
|
||||
void MenuRadioItem::create(MenuGroup &r_owner, ControlGroup &list, const char *caption) {
|
||||
if(list.count() == 0)throw;
|
||||
type = Control::MenuRadioItem;
|
||||
caption = strdup(_caption);
|
||||
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;
|
||||
return *this;
|
||||
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(group[i].owner->info.menu_owner.group, group[i].id, MF_UNCHECKED);
|
||||
CheckMenuItem(parent, group[i].id, (id == group[i].id) ? MF_CHECKED : MF_UNCHECKED);
|
||||
}
|
||||
CheckMenuItem(owner->info.menu_owner.group, id, MF_CHECKED);
|
||||
owner->message(Message::Clicked, this);
|
||||
}
|
||||
|
||||
bool MenuRadioItem::checked() {
|
||||
|
@ -268,36 +188,52 @@ MENUITEMINFO info;
|
|||
memset(&info, 0, sizeof(info));
|
||||
info.cbSize = sizeof(info);
|
||||
info.fMask = MIIM_STATE;
|
||||
GetMenuItemInfo(owner->info.menu_owner.group, id, false, &info);
|
||||
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
|
||||
*****/
|
||||
|
||||
Container& Container::create(const char *style, uint width, uint height) {
|
||||
type = Control::Container;
|
||||
hwnd = CreateWindow("libui_class", "", WS_CHILD | WS_VISIBLE,
|
||||
0, 0, width, height, libui::message_window, (HMENU)100, GetModuleHandle(0), 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Container::attach(Control &control, uint x, uint y) {
|
||||
owner->attach(control, x, y);
|
||||
SetParent(control.hwnd, hwnd);
|
||||
}
|
||||
|
||||
void Container::move(Control &control, uint x, uint y) {
|
||||
SetWindowPos(control.hwnd, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Canvas
|
||||
*****/
|
||||
|
||||
Canvas &Canvas::create(const char *style, uint width, uint height) {
|
||||
type = Control::Canvas;
|
||||
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++);
|
||||
|
@ -315,15 +251,10 @@ WNDCLASS wc;
|
|||
RegisterClass(&wc);
|
||||
|
||||
hwnd = CreateWindow(classname, "", WS_CHILD | WS_VISIBLE,
|
||||
0, 0, width, height, libui::message_window, (HMENU)100, GetModuleHandle(0), 0);
|
||||
return *this;
|
||||
0, 0, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0);
|
||||
}
|
||||
|
||||
WindowHandle Canvas::handle() {
|
||||
return (WindowHandle)hwnd;
|
||||
}
|
||||
|
||||
void Canvas::set_background_color(uint8 r, uint8 g, uint8 b) {
|
||||
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);
|
||||
|
@ -331,60 +262,170 @@ HBRUSH old_brush = background;
|
|||
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
|
||||
*****/
|
||||
|
||||
Frame& Frame::create(const char *style, uint width, uint height, const char *caption) {
|
||||
type = Control::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,
|
||||
0, 0, width, height, libui::message_window, (HMENU)100, GetModuleHandle(0), 0);
|
||||
x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)libui::font.variable, 0);
|
||||
return *this;
|
||||
r_owner.attach(*this);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Label
|
||||
*****/
|
||||
|
||||
Label& Label::create(const char *style, uint width, uint height, const char *caption) {
|
||||
type = Control::Label;
|
||||
hwnd = CreateWindow("STATIC", caption ? caption : "", WS_CHILD | WS_VISIBLE | SS_NOPREFIX | SS_ENDELLIPSIS,
|
||||
0, 0, width, height, libui::message_window, (HMENU)100, GetModuleHandle(0), 0);
|
||||
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);
|
||||
GetClientRect(hwnd, &rc);
|
||||
SetTextColor(ps.hdc, RGB(0, 0, 0));
|
||||
SetBkMode(ps.hdc, TRANSPARENT);
|
||||
SelectObject(ps.hdc, (HGDIOBJ)libui::font.variable);
|
||||
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);
|
||||
return *this;
|
||||
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
|
||||
*****/
|
||||
|
||||
Button& Button::create(const char *style, uint width, uint height, const char *caption) {
|
||||
type = Control::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,
|
||||
0, 0, width, height, libui::message_window, (HMENU)100, GetModuleHandle(0), 0);
|
||||
x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)libui::font.variable, 0);
|
||||
return *this;
|
||||
r_owner.attach(*this);
|
||||
}
|
||||
|
||||
/*****
|
||||
* Checkbox
|
||||
*****/
|
||||
|
||||
Checkbox& Checkbox::create(const char *style, uint width, uint height, const char *caption) {
|
||||
type = Control::Checkbox;
|
||||
hwnd = CreateWindow("BUTTON", caption ? caption : "", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
|
||||
0, 0, width, height, libui::message_window, (HMENU)100, GetModuleHandle(0), 0);
|
||||
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);
|
||||
return *this;
|
||||
r_owner.attach(*this);
|
||||
}
|
||||
|
||||
void Checkbox::check() {
|
||||
if(checked() == true)return;
|
||||
SendMessage(hwnd, BM_SETCHECK, (WPARAM)TRUE, 0);
|
||||
owner->message(Message::Clicked, this);
|
||||
}
|
||||
|
||||
void Checkbox::uncheck() {
|
||||
if(checked() == false)return;
|
||||
SendMessage(hwnd, BM_SETCHECK, (WPARAM)FALSE, 0);
|
||||
owner->message(Message::Clicked, this);
|
||||
}
|
||||
|
||||
void Checkbox::check(bool state) {
|
||||
|
@ -399,22 +440,23 @@ bool Checkbox::checked() {
|
|||
* Radiobox
|
||||
*****/
|
||||
|
||||
Radiobox& Radiobox::create(ControlGroup &list, const char *style, uint width, uint height, const char *caption) {
|
||||
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 = Control::Radiobox;
|
||||
type = ControlType::Radiobox;
|
||||
group = list;
|
||||
hwnd = CreateWindow("BUTTON", caption ? caption : "", WS_CHILD | WS_VISIBLE | BS_RADIOBUTTON,
|
||||
0, 0, width, height, libui::message_window, (HMENU)100, GetModuleHandle(0), 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);
|
||||
if(this == &group[0])check();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Radiobox::check() {
|
||||
if(checked() == true)return;
|
||||
for(uint i = 0; i < group.count(); i++) {
|
||||
SendMessage(group[i].hwnd, BM_SETCHECK, (WPARAM)FALSE, 0);
|
||||
SendMessage(group[i].hwnd, BM_SETCHECK, (group[i].hwnd == hwnd) ? (WPARAM)TRUE : (WPARAM)FALSE, 0);
|
||||
}
|
||||
SendMessage(hwnd, BM_SETCHECK, (WPARAM)TRUE, 0);
|
||||
owner->message(Message::Clicked, this);
|
||||
}
|
||||
|
||||
bool Radiobox::checked() {
|
||||
|
@ -425,48 +467,69 @@ bool Radiobox::checked() {
|
|||
* Editbox
|
||||
*****/
|
||||
|
||||
Editbox& Editbox::create(const char *style, uint width, uint height, const char *caption) {
|
||||
type = Control::Editbox;
|
||||
multiline = readonly = vscroll = hscroll = false;
|
||||
stringarray part;
|
||||
split(part, "|", style);
|
||||
for(uint i = 0; i < count(part); i++) {
|
||||
if(part[i] == "multiline")multiline = true;
|
||||
if(part[i] == "readonly")readonly = true;
|
||||
if(part[i] == "vscroll")vscroll = true;
|
||||
if(part[i] == "hscroll")hscroll = true;
|
||||
}
|
||||
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 |
|
||||
WS_CHILD | WS_VISIBLE | vscroll | hscroll |
|
||||
(multiline == true ? ES_MULTILINE : 0) |
|
||||
(readonly == true ? ES_READONLY : 0) |
|
||||
(vscroll == true ? WS_VSCROLL : ES_AUTOVSCROLL) |
|
||||
(hscroll == true ? WS_HSCROLL : ES_AUTOHSCROLL),
|
||||
0, 0, width, height, libui::message_window, (HMENU)100, GetModuleHandle(0), 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);
|
||||
return *this;
|
||||
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
|
||||
*****/
|
||||
|
||||
Listbox& Listbox::create(const char *style, uint width, uint height, const char *columns, const char *data) {
|
||||
void Listbox::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *columns) {
|
||||
stringarray part;
|
||||
header = false;
|
||||
split(part, "|", style);
|
||||
for(uint i = 0; i < count(part); i++) {
|
||||
if(part[i] == "header")header = true;
|
||||
}
|
||||
header = (style & Header);
|
||||
|
||||
type = Control::Listbox;
|
||||
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 |
|
||||
WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | vscroll | hscroll |
|
||||
(header == true ? 0 : LVS_NOCOLUMNHEADER),
|
||||
0, 0, width, height, libui::message_window, (HMENU)100, GetModuleHandle(0), 0);
|
||||
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);
|
||||
|
||||
|
@ -481,15 +544,8 @@ stringarray part;
|
|||
ListView_InsertColumn(hwnd, i, &column);
|
||||
}
|
||||
|
||||
if(strcmp(data, "")) {
|
||||
split(part, "||", data);
|
||||
for(uint i = 0; i < count(part); i++) {
|
||||
add_item(strptr(part[i]));
|
||||
}
|
||||
}
|
||||
|
||||
autosize_columns();
|
||||
return *this;
|
||||
r_owner.attach(*this);
|
||||
}
|
||||
|
||||
void Listbox::autosize_columns() {
|
||||
|
@ -502,9 +558,15 @@ void Listbox::set_column_width(uint column, uint width) {
|
|||
ListView_SetColumnWidth(hwnd, column, width);
|
||||
}
|
||||
|
||||
void Listbox::add_item(const char *data) {
|
||||
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, "|", data);
|
||||
split(part, "|", temp);
|
||||
|
||||
LVITEM item;
|
||||
uint pos = ListView_GetItemCount(hwnd);
|
||||
|
@ -519,6 +581,21 @@ uint pos = ListView_GetItemCount(hwnd);
|
|||
}
|
||||
}
|
||||
|
||||
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++) {
|
||||
|
@ -530,7 +607,6 @@ uint count = ListView_GetItemCount(hwnd);
|
|||
void Listbox::set_selection(int index) {
|
||||
uint count = ListView_GetItemCount(hwnd);
|
||||
for(uint i = 0; i < count; i++) {
|
||||
uint state = ListView_GetItemState(hwnd, i, LVIS_FOCUSED);
|
||||
ListView_SetItemState(hwnd, i, LVIS_FOCUSED, (i == index) ? LVIS_FOCUSED : 0);
|
||||
ListView_SetItemState(hwnd, i, LVIS_SELECTED, (i == index) ? LVIS_SELECTED : 0);
|
||||
}
|
||||
|
@ -544,23 +620,18 @@ void Listbox::reset() {
|
|||
* Combobox
|
||||
*****/
|
||||
|
||||
Combobox& Combobox::create(const char *style, uint width, uint height, const char *caption) {
|
||||
type = Control::Combobox;
|
||||
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "COMBOBOX", caption ? caption : "",
|
||||
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,
|
||||
0, 0, width, 200, libui::message_window, (HMENU)100, GetModuleHandle(0), 0);
|
||||
x, y, width, 200, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)libui::font.variable, 0);
|
||||
if(strcmp(caption, "")) {
|
||||
stringarray temp;
|
||||
split(temp, "|", caption);
|
||||
for(uint i = 0; i < count(temp); i++) { add_item(strptr(temp[i])); }
|
||||
set_selection(0);
|
||||
}
|
||||
return *this;
|
||||
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) {
|
||||
|
@ -579,13 +650,13 @@ void Combobox::reset() {
|
|||
* Progressbar
|
||||
*****/
|
||||
|
||||
Progressbar& Progressbar::create(const char *style, uint width, uint height) {
|
||||
type = Control::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,
|
||||
0, 0, width, height, libui::message_window, (HMENU)100, GetModuleHandle(0), 0);
|
||||
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);
|
||||
return *this;
|
||||
r_owner.attach(*this);
|
||||
}
|
||||
|
||||
void Progressbar::set_progress(uint progress) {
|
||||
|
@ -601,22 +672,18 @@ uint Progressbar::get_progress() {
|
|||
* Slider
|
||||
*****/
|
||||
|
||||
Slider& Slider::create(const char *style, uint width, uint height, uint min, uint max) {
|
||||
type = Control::Slider;
|
||||
orientation = 0;
|
||||
stringarray part;
|
||||
split(part, "|", style);
|
||||
for(uint i = 0; i < count(part); i++) {
|
||||
if(part[i] == "horizontal")orientation = 0;
|
||||
if(part[i] == "vertical")orientation = 1;
|
||||
}
|
||||
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),
|
||||
0, 0, width, height, libui::message_window, (HMENU)100, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, TBM_SETRANGE, (WPARAM)true, (LPARAM)MAKELONG(min, max));
|
||||
SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM)((max - min) >> 3));
|
||||
SendMessage(hwnd, TBM_SETPOS, (WPARAM)true, (LPARAM)min);
|
||||
return *this;
|
||||
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) {
|
||||
|
|
|
@ -1,151 +1,262 @@
|
|||
class Control { public:
|
||||
Window *owner;
|
||||
HWND hwnd;
|
||||
uint id;
|
||||
uint type;
|
||||
|
||||
enum {
|
||||
Invalid,
|
||||
MenuGroup,
|
||||
MenuItem,
|
||||
MenuCheckItem,
|
||||
MenuRadioItem,
|
||||
Container,
|
||||
Canvas,
|
||||
Frame,
|
||||
Label,
|
||||
Button,
|
||||
Checkbox,
|
||||
Radiobox,
|
||||
Editbox,
|
||||
Listbox,
|
||||
Combobox,
|
||||
Progressbar,
|
||||
Slider,
|
||||
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 resize(uint width, uint height);
|
||||
|
||||
void show();
|
||||
void hide();
|
||||
void show(bool state);
|
||||
bool visible();
|
||||
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();
|
||||
|
||||
Control() : owner(0), hwnd(0), id(0), type(Invalid) {}
|
||||
//private:
|
||||
Window *owner;
|
||||
HWND hwnd;
|
||||
uint id;
|
||||
|
||||
public:
|
||||
Control() : owner(0), hwnd(0), id(0), type(ControlType::Invalid) {}
|
||||
};
|
||||
|
||||
class ControlGroup { public:
|
||||
array<Control*> list;
|
||||
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:
|
||||
bool master;
|
||||
HMENU group;
|
||||
void create(MenuBar &owner, const char *caption);
|
||||
void create(MenuGroup &owner, const char *caption);
|
||||
void finish();
|
||||
|
||||
//private:
|
||||
HMENU parent, group;
|
||||
char *caption;
|
||||
MenuGroup &create(const char *caption);
|
||||
MenuGroup() : master(false) {}
|
||||
~MenuGroup() { safe_free(caption); }
|
||||
};
|
||||
|
||||
class MenuItem : public Control { public:
|
||||
char *caption;
|
||||
MenuItem &create(const char *caption);
|
||||
~MenuItem() { safe_free(caption); }
|
||||
void create(MenuGroup &owner, const char *caption);
|
||||
};
|
||||
|
||||
class MenuCheckItem : public Control { public:
|
||||
char *caption;
|
||||
MenuCheckItem &create(const char *caption);
|
||||
void create(MenuGroup &owner, const char *caption);
|
||||
void check();
|
||||
void uncheck();
|
||||
void check(bool state);
|
||||
bool checked();
|
||||
~MenuCheckItem() { safe_free(caption); }
|
||||
|
||||
//private:
|
||||
HMENU parent;
|
||||
};
|
||||
|
||||
class MenuRadioItem : public Control { public:
|
||||
ControlGroup group;
|
||||
char *caption;
|
||||
MenuRadioItem &create(ControlGroup &list, const char *caption);
|
||||
void create(MenuGroup &owner, ControlGroup &list, const char *caption);
|
||||
void check();
|
||||
bool checked();
|
||||
~MenuRadioItem() { safe_free(caption); }
|
||||
|
||||
//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:
|
||||
Container &create(const char *style, uint width, uint height);
|
||||
void attach(Control &control, uint x, uint y);
|
||||
void move(Control &control, uint x, uint y);
|
||||
};
|
||||
class Canvas : public Control { public:
|
||||
HBRUSH background;
|
||||
Canvas &create(const char *style, uint width, uint height);
|
||||
WindowHandle handle();
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height);
|
||||
void set_background_color(uint8 r, uint8 g, uint8 b);
|
||||
Canvas() : background(0) {}
|
||||
|
||||
//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:
|
||||
Frame &create(const char *style, uint width, uint height, const char *caption = "");
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
};
|
||||
|
||||
class Label : public Control { public:
|
||||
Label &create(const char *style, uint width, uint height, const char *caption = "");
|
||||
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:
|
||||
Button &create(const char *style, uint width, uint height, const char *caption = "");
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
};
|
||||
|
||||
class Checkbox : public Control { public:
|
||||
Checkbox &create(const char *style, uint width, uint height, const char *caption = "");
|
||||
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:
|
||||
ControlGroup group;
|
||||
Radiobox &create(ControlGroup &list, const char *style, uint width, uint height, const char *caption = "");
|
||||
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 {
|
||||
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;
|
||||
Editbox &create(const char *style, uint width, uint height, const char *caption = "");
|
||||
};
|
||||
|
||||
class Listbox : public Control { public:
|
||||
bool header;
|
||||
uint column_count;
|
||||
Listbox &create(const char *style, uint width, uint height, const char *columns = "", const char *data = "");
|
||||
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 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:
|
||||
Combobox &create(const char *style, uint width, uint height, const char *caption = "");
|
||||
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:
|
||||
Progressbar &create(const char *style, uint width, uint height);
|
||||
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:
|
||||
bool orientation;
|
||||
Slider &create(const char *style, uint width, uint height, uint min, uint max);
|
||||
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;
|
||||
};
|
||||
|
|
|
@ -10,41 +10,110 @@ long Window::wndproc(HWND hwnd, uint msg, WPARAM wparam, LPARAM lparam) {
|
|||
switch(msg) {
|
||||
|
||||
case WM_CLOSE: {
|
||||
if(close() == false) { return TRUE; }
|
||||
if(message(Message::Close) == false) { return TRUE; }
|
||||
} break;
|
||||
|
||||
case WM_KEYDOWN: {
|
||||
keydown((int)wparam);
|
||||
} break;
|
||||
case WM_ENTERMENULOOP: {
|
||||
message(Message::Block);
|
||||
}
|
||||
|
||||
case WM_KEYUP: {
|
||||
keyup((int)wparam);
|
||||
} break;
|
||||
|
||||
case WM_COMMAND: {
|
||||
uint i = LOWORD(wparam);
|
||||
if(!info.control[i])break;
|
||||
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 Control::MenuCheckItem: { //need to simulate auto check event
|
||||
MenuCheckItem &item = static_cast<MenuCheckItem&>(control);
|
||||
item.check(!item.checked()); //toggle checked status
|
||||
} break;
|
||||
|
||||
case Control::MenuRadioItem: { //need to simulate auto radio check event
|
||||
static_cast<MenuRadioItem&>(control).check();
|
||||
} break;
|
||||
|
||||
case Control::Radiobox: {
|
||||
static_cast<Radiobox&>(control).check();
|
||||
case ControlType::Canvas: {
|
||||
((Canvas&)control).redraw();
|
||||
} break;
|
||||
|
||||
}
|
||||
} break;
|
||||
|
||||
clicked(&control);
|
||||
case WM_KEYDOWN: {
|
||||
message(Message::KeyDown, (void*)libui::translate_key(wparam));
|
||||
} break;
|
||||
|
||||
case WM_KEYUP: {
|
||||
message(Message::KeyUp, (void*)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, &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, &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, &control);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(((LPNMHDR)lparam)->code == LVN_ITEMACTIVATE) {
|
||||
message(Message::DoubleClicked, &control);
|
||||
}
|
||||
} break;
|
||||
|
||||
}
|
||||
} break;
|
||||
|
||||
}
|
||||
|
@ -52,21 +121,13 @@ long Window::wndproc(HWND hwnd, uint msg, WPARAM wparam, LPARAM lparam) {
|
|||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
WindowHandle Window::handle() {
|
||||
return (WindowHandle)info.hwnd;
|
||||
}
|
||||
|
||||
void Window::attach(Control &control, uint x, uint y, bool attach_to_window) {
|
||||
void Window::attach(Control &control) {
|
||||
info.control[info.control_index] = &control;
|
||||
control.id = info.control_index++;
|
||||
control.owner = this;
|
||||
SetWindowLong(control.hwnd, GWL_ID, control.id);
|
||||
SetWindowPos(control.hwnd, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
|
||||
if(attach_to_window == true) { SetParent(control.hwnd, info.hwnd); }
|
||||
|
||||
if(control.type == Control::Container) {
|
||||
SetWindowLongPtr(control.hwnd, GWLP_USERDATA, (LONG_PTR)GetWindowLongPtr(info.hwnd, GWLP_USERDATA));
|
||||
}
|
||||
//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() {
|
||||
|
@ -78,13 +139,8 @@ void Window::move(Control &control, uint x, uint y) {
|
|||
SetWindowPos(control.hwnd, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
|
||||
}
|
||||
|
||||
void Window::create(const char *style, uint width, uint height, const char *caption) {
|
||||
stringarray part;
|
||||
split(part, "|", style);
|
||||
for(int i = 0; i < count(part); i++) {
|
||||
if(part[i] == "center") { info.center = true; }
|
||||
if(part[i] == "menu") { info.has_menu = true; }
|
||||
}
|
||||
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++);
|
||||
|
@ -108,29 +164,18 @@ RECT rc;
|
|||
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);
|
||||
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);
|
||||
|
||||
if(info.has_menu == true) {
|
||||
info.control[info.control_index] = &info.menu_owner;
|
||||
|
||||
info.menu_owner.id = info.control_index++;
|
||||
info.menu_owner.owner = this;
|
||||
info.menu_owner.type = Control::MenuGroup;
|
||||
info.menu_owner.master = true;
|
||||
info.menu_owner.group = CreateMenu();
|
||||
|
||||
info.menu_group[++info.menu_group_index] = &info.menu_owner;
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -138,18 +183,29 @@ void Window::resize(uint width, uint height) {
|
|||
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);
|
||||
uint x = (GetSystemMetrics(SM_CXSCREEN) - width) >> 1;
|
||||
uint y = (GetSystemMetrics(SM_CYSCREEN) - height) >> 1;
|
||||
|
||||
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() {
|
||||
|
@ -158,6 +214,15 @@ void Window::hide() {
|
|||
|
||||
//
|
||||
|
||||
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));
|
||||
|
@ -169,11 +234,15 @@ HBRUSH old_brush = info.background;
|
|||
//
|
||||
|
||||
Window::Window() {
|
||||
info.background = 0;
|
||||
info.center = false;
|
||||
info.control_index = 1;
|
||||
info.has_menu = false;
|
||||
info.menu_group_index = 1;
|
||||
info.background = 0;
|
||||
info.center = false;
|
||||
info.control_index = 1;
|
||||
}
|
||||
|
||||
//platform-dependent:
|
||||
|
||||
HWND Window::handle() {
|
||||
return info.hwnd;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -200,5 +200,5 @@ bMemBus::bMemBus() {
|
|||
}
|
||||
|
||||
bMemBus::~bMemBus() {
|
||||
SafeFree(wram);
|
||||
safe_free(wram);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -239,7 +239,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();
|
||||
|
|
|
@ -81,8 +81,9 @@ uint16 hc = r_cpu->hclock();
|
|||
|
||||
//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);
|
||||
|
|
|
@ -46,5 +46,5 @@ PPU::PPU() {
|
|||
}
|
||||
|
||||
PPU::~PPU() {
|
||||
SafeFree(output);
|
||||
safe_free(output);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ public:
|
|||
union {
|
||||
uint8 data;
|
||||
struct {
|
||||
uint8 order_msb8(n:1, v:1, p:1, b:1, h:1, i:1, z:1, c:1);
|
||||
bool order_msb8(n:1, v:1, p:1, b:1, h:1, i:1, z:1, c:1);
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -1,19 +1,17 @@
|
|||
#include "opfn.cpp"
|
||||
|
||||
void sSMP::enter() {
|
||||
for(;;) {
|
||||
tracer.trace_smpop(); //traces SMP opcode (only if tracer is enabled)
|
||||
#include "op_mov.cpp"
|
||||
#include "op_pc.cpp"
|
||||
#include "op_read.cpp"
|
||||
#include "op_rmw.cpp"
|
||||
#include "op_misc.cpp"
|
||||
|
||||
status.in_opcode = true;
|
||||
void sSMP::enter() { loop:
|
||||
tracer.trace_smpop(); //traces SMP opcode (only if tracer is enabled)
|
||||
|
||||
switch(op_readpc()) {
|
||||
#include "op_mov.cpp"
|
||||
#include "op_pc.cpp"
|
||||
#include "op_read.cpp"
|
||||
#include "op_rmw.cpp"
|
||||
#include "op_misc.cpp"
|
||||
}
|
||||
status.in_opcode = true;
|
||||
(this->*optbl[op_readpc()])();
|
||||
status.in_opcode = false;
|
||||
|
||||
status.in_opcode = false;
|
||||
}
|
||||
goto loop;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
void (sSMP::*optbl[256])();
|
||||
|
||||
uint16 dp, sp, rd, wr, bit, ya;
|
||||
bool in_opcode() { return status.in_opcode; }
|
||||
|
||||
|
@ -8,9 +10,7 @@ uint16 dp, sp, rd, wr, bit, ya;
|
|||
uint16 op_cmpw(uint16 x, uint16 y);
|
||||
uint8 op_eor (uint8 x, uint8 y);
|
||||
uint8 op_inc (uint8 x);
|
||||
uint16 op_incw(uint16 x);
|
||||
uint8 op_dec (uint8 x);
|
||||
uint16 op_decw(uint16 x);
|
||||
uint8 op_or (uint8 x, uint8 y);
|
||||
uint8 op_sbc (uint8 x, uint8 y);
|
||||
uint16 op_subw(uint16 x, uint16 y);
|
||||
|
@ -18,3 +18,5 @@ uint16 dp, sp, rd, wr, bit, ya;
|
|||
uint8 op_lsr (uint8 x);
|
||||
uint8 op_rol (uint8 x);
|
||||
uint8 op_ror (uint8 x);
|
||||
|
||||
#include "op.h"
|
||||
|
|
|
@ -0,0 +1,256 @@
|
|||
void op_mov_a_x();
|
||||
void op_mov_a_y();
|
||||
void op_mov_x_a();
|
||||
void op_mov_y_a();
|
||||
void op_mov_x_sp();
|
||||
void op_mov_sp_x();
|
||||
void op_mov_a_const();
|
||||
void op_mov_x_const();
|
||||
void op_mov_y_const();
|
||||
void op_mov_a_ix();
|
||||
void op_mov_a_ixinc();
|
||||
void op_mov_a_dp();
|
||||
void op_mov_x_dp();
|
||||
void op_mov_y_dp();
|
||||
void op_mov_a_dpx();
|
||||
void op_mov_x_dpy();
|
||||
void op_mov_y_dpx();
|
||||
void op_mov_a_addr();
|
||||
void op_mov_x_addr();
|
||||
void op_mov_y_addr();
|
||||
void op_mov_a_addrx();
|
||||
void op_mov_a_addry();
|
||||
void op_mov_a_idpx();
|
||||
void op_mov_a_idpy();
|
||||
void op_mov_dp_dp();
|
||||
void op_mov_dp_const();
|
||||
void op_mov_ix_a();
|
||||
void op_mov_ixinc_a();
|
||||
void op_mov_dp_a();
|
||||
void op_mov_dp_x();
|
||||
void op_mov_dp_y();
|
||||
void op_mov_dpx_a();
|
||||
void op_mov_dpy_x();
|
||||
void op_mov_dpx_y();
|
||||
void op_mov_addr_a();
|
||||
void op_mov_addr_x();
|
||||
void op_mov_addr_y();
|
||||
void op_mov_addrx_a();
|
||||
void op_mov_addry_a();
|
||||
void op_mov_idpx_a();
|
||||
void op_mov_idpy_a();
|
||||
void op_movw_ya_dp();
|
||||
void op_movw_dp_ya();
|
||||
void op_mov1_c_bit();
|
||||
void op_mov1_bit_c();
|
||||
void op_bra();
|
||||
void op_beq();
|
||||
void op_bne();
|
||||
void op_bcs();
|
||||
void op_bcc();
|
||||
void op_bvs();
|
||||
void op_bvc();
|
||||
void op_bmi();
|
||||
void op_bpl();
|
||||
void op_bbs0();
|
||||
void op_bbc0();
|
||||
void op_bbs1();
|
||||
void op_bbc1();
|
||||
void op_bbs2();
|
||||
void op_bbc2();
|
||||
void op_bbs3();
|
||||
void op_bbc3();
|
||||
void op_bbs4();
|
||||
void op_bbc4();
|
||||
void op_bbs5();
|
||||
void op_bbc5();
|
||||
void op_bbs6();
|
||||
void op_bbc6();
|
||||
void op_bbs7();
|
||||
void op_bbc7();
|
||||
void op_cbne_dp();
|
||||
void op_cbne_dpx();
|
||||
void op_dbnz_dp();
|
||||
void op_dbnz_y();
|
||||
void op_jmp_addr();
|
||||
void op_jmp_iaddrx();
|
||||
void op_call();
|
||||
void op_pcall();
|
||||
void op_tcall_0();
|
||||
void op_tcall_1();
|
||||
void op_tcall_2();
|
||||
void op_tcall_3();
|
||||
void op_tcall_4();
|
||||
void op_tcall_5();
|
||||
void op_tcall_6();
|
||||
void op_tcall_7();
|
||||
void op_tcall_8();
|
||||
void op_tcall_9();
|
||||
void op_tcall_10();
|
||||
void op_tcall_11();
|
||||
void op_tcall_12();
|
||||
void op_tcall_13();
|
||||
void op_tcall_14();
|
||||
void op_tcall_15();
|
||||
void op_brk();
|
||||
void op_ret();
|
||||
void op_reti();
|
||||
void op_adc_a_const();
|
||||
void op_and_a_const();
|
||||
void op_cmp_a_const();
|
||||
void op_cmp_x_const();
|
||||
void op_cmp_y_const();
|
||||
void op_eor_a_const();
|
||||
void op_or_a_const();
|
||||
void op_sbc_a_const();
|
||||
void op_adc_a_ix();
|
||||
void op_and_a_ix();
|
||||
void op_cmp_a_ix();
|
||||
void op_eor_a_ix();
|
||||
void op_or_a_ix();
|
||||
void op_sbc_a_ix();
|
||||
void op_adc_a_dp();
|
||||
void op_and_a_dp();
|
||||
void op_cmp_a_dp();
|
||||
void op_cmp_x_dp();
|
||||
void op_cmp_y_dp();
|
||||
void op_eor_a_dp();
|
||||
void op_or_a_dp();
|
||||
void op_sbc_a_dp();
|
||||
void op_adc_a_dpx();
|
||||
void op_and_a_dpx();
|
||||
void op_cmp_a_dpx();
|
||||
void op_eor_a_dpx();
|
||||
void op_or_a_dpx();
|
||||
void op_sbc_a_dpx();
|
||||
void op_adc_a_addr();
|
||||
void op_and_a_addr();
|
||||
void op_cmp_a_addr();
|
||||
void op_cmp_x_addr();
|
||||
void op_cmp_y_addr();
|
||||
void op_eor_a_addr();
|
||||
void op_or_a_addr();
|
||||
void op_sbc_a_addr();
|
||||
void op_adc_a_addrx();
|
||||
void op_adc_a_addry();
|
||||
void op_and_a_addrx();
|
||||
void op_and_a_addry();
|
||||
void op_cmp_a_addrx();
|
||||
void op_cmp_a_addry();
|
||||
void op_eor_a_addrx();
|
||||
void op_eor_a_addry();
|
||||
void op_or_a_addrx();
|
||||
void op_or_a_addry();
|
||||
void op_sbc_a_addrx();
|
||||
void op_sbc_a_addry();
|
||||
void op_adc_a_idpx();
|
||||
void op_and_a_idpx();
|
||||
void op_cmp_a_idpx();
|
||||
void op_eor_a_idpx();
|
||||
void op_or_a_idpx();
|
||||
void op_sbc_a_idpx();
|
||||
void op_adc_a_idpy();
|
||||
void op_and_a_idpy();
|
||||
void op_cmp_a_idpy();
|
||||
void op_eor_a_idpy();
|
||||
void op_or_a_idpy();
|
||||
void op_sbc_a_idpy();
|
||||
void op_adc_ix_iy();
|
||||
void op_and_ix_iy();
|
||||
void op_cmp_ix_iy();
|
||||
void op_eor_ix_iy();
|
||||
void op_or_ix_iy();
|
||||
void op_sbc_ix_iy();
|
||||
void op_adc_dp_dp();
|
||||
void op_and_dp_dp();
|
||||
void op_cmp_dp_dp();
|
||||
void op_eor_dp_dp();
|
||||
void op_or_dp_dp();
|
||||
void op_sbc_dp_dp();
|
||||
void op_adc_dp_const();
|
||||
void op_and_dp_const();
|
||||
void op_cmp_dp_const();
|
||||
void op_eor_dp_const();
|
||||
void op_or_dp_const();
|
||||
void op_sbc_dp_const();
|
||||
void op_addw_ya_dp();
|
||||
void op_subw_ya_dp();
|
||||
void op_cmpw_ya_dp();
|
||||
void op_and1_bit();
|
||||
void op_and1_notbit();
|
||||
void op_eor1_bit();
|
||||
void op_not1_bit();
|
||||
void op_or1_bit();
|
||||
void op_or1_notbit();
|
||||
void op_inc_a();
|
||||
void op_inc_x();
|
||||
void op_inc_y();
|
||||
void op_dec_a();
|
||||
void op_dec_x();
|
||||
void op_dec_y();
|
||||
void op_asl_a();
|
||||
void op_lsr_a();
|
||||
void op_rol_a();
|
||||
void op_ror_a();
|
||||
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_inc_dpx();
|
||||
void op_dec_dpx();
|
||||
void op_asl_dpx();
|
||||
void op_lsr_dpx();
|
||||
void op_rol_dpx();
|
||||
void op_ror_dpx();
|
||||
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_tset_addr_a();
|
||||
void op_tclr_addr_a();
|
||||
void op_incw_dp();
|
||||
void op_decw_dp();
|
||||
void op_nop();
|
||||
void op_sleep();
|
||||
void op_stop();
|
||||
void op_xcn();
|
||||
void op_daa();
|
||||
void op_das();
|
||||
void op_clrc();
|
||||
void op_clrp();
|
||||
void op_setc();
|
||||
void op_setp();
|
||||
void op_clrv();
|
||||
void op_notc();
|
||||
void op_ei();
|
||||
void op_di();
|
||||
void op_set0_dp();
|
||||
void op_clr0_dp();
|
||||
void op_set1_dp();
|
||||
void op_clr1_dp();
|
||||
void op_set2_dp();
|
||||
void op_clr2_dp();
|
||||
void op_set3_dp();
|
||||
void op_clr3_dp();
|
||||
void op_set4_dp();
|
||||
void op_clr4_dp();
|
||||
void op_set5_dp();
|
||||
void op_clr5_dp();
|
||||
void op_set6_dp();
|
||||
void op_clr6_dp();
|
||||
void op_set7_dp();
|
||||
void op_clr7_dp();
|
||||
void op_push_a();
|
||||
void op_push_x();
|
||||
void op_push_y();
|
||||
void op_push_p();
|
||||
void op_pop_a();
|
||||
void op_pop_x();
|
||||
void op_pop_y();
|
||||
void op_pop_p();
|
||||
void op_mul_ya();
|
||||
void op_div_ya_x();
|
|
@ -96,18 +96,6 @@ clr7_dp(0xf2, rd &= ~0x80) {
|
|||
op_writedp(dp, rd);
|
||||
}
|
||||
|
||||
tset_addr_a(0x0e, |=),
|
||||
tclr_addr_a(0x4e, &=~) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:rd = op_readaddr(dp);
|
||||
4:op_io();
|
||||
regs.p.n = !!((rd & regs.a) & 0x80);
|
||||
regs.p.z = ((rd & regs.a) == 0);
|
||||
rd $1 regs.a;
|
||||
5:op_writeaddr(dp, rd);
|
||||
}
|
||||
|
||||
push_a(0x2d, a),
|
||||
push_x(0x4d, x),
|
||||
push_y(0x6d, y),
|
||||
|
|
|
@ -1,24 +1,20 @@
|
|||
//nop
|
||||
case 0x00: {
|
||||
void sSMP::op_nop() {
|
||||
op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//sleep
|
||||
case 0xef: {
|
||||
void sSMP::op_sleep() {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc--;
|
||||
} break;
|
||||
}
|
||||
|
||||
//stop
|
||||
case 0xff: {
|
||||
void sSMP::op_stop() {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc--;
|
||||
} break;
|
||||
}
|
||||
|
||||
//xcn
|
||||
case 0x9f: {
|
||||
void sSMP::op_xcn() {
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
|
@ -26,10 +22,9 @@ case 0x9f: {
|
|||
regs.a = (regs.a >> 4) | (regs.a << 4);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//daa
|
||||
case 0xdf: {
|
||||
void sSMP::op_daa() {
|
||||
op_io();
|
||||
op_io();
|
||||
if(regs.p.c || (regs.a) > 0x99) {
|
||||
|
@ -41,10 +36,9 @@ case 0xdf: {
|
|||
}
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//das
|
||||
case 0xbe: {
|
||||
void sSMP::op_das() {
|
||||
op_io();
|
||||
op_io();
|
||||
if(!regs.p.c || (regs.a) > 0x99) {
|
||||
|
@ -56,270 +50,213 @@ case 0xbe: {
|
|||
}
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//clrc
|
||||
case 0x60: {
|
||||
void sSMP::op_clrc() {
|
||||
op_io();
|
||||
regs.p.c = 0;
|
||||
} break;
|
||||
}
|
||||
|
||||
//clrp
|
||||
case 0x20: {
|
||||
void sSMP::op_clrp() {
|
||||
op_io();
|
||||
regs.p.p = 0;
|
||||
} break;
|
||||
}
|
||||
|
||||
//setc
|
||||
case 0x80: {
|
||||
void sSMP::op_setc() {
|
||||
op_io();
|
||||
regs.p.c = 1;
|
||||
} break;
|
||||
}
|
||||
|
||||
//setp
|
||||
case 0x40: {
|
||||
void sSMP::op_setp() {
|
||||
op_io();
|
||||
regs.p.p = 1;
|
||||
} break;
|
||||
}
|
||||
|
||||
//clrv
|
||||
case 0xe0: {
|
||||
void sSMP::op_clrv() {
|
||||
op_io();
|
||||
regs.p.v = 0;
|
||||
regs.p.h = 0;
|
||||
} break;
|
||||
}
|
||||
|
||||
//notc
|
||||
case 0xed: {
|
||||
void sSMP::op_notc() {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.p.c ^= 1;
|
||||
} break;
|
||||
}
|
||||
|
||||
//ei
|
||||
case 0xa0: {
|
||||
void sSMP::op_ei() {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.p.i = 1;
|
||||
} break;
|
||||
}
|
||||
|
||||
//di
|
||||
case 0xc0: {
|
||||
void sSMP::op_di() {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.p.i = 0;
|
||||
} break;
|
||||
}
|
||||
|
||||
//set0_dp
|
||||
case 0x02: {
|
||||
void sSMP::op_set0_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x01;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//clr0_dp
|
||||
case 0x12: {
|
||||
void sSMP::op_clr0_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x01;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//set1_dp
|
||||
case 0x22: {
|
||||
void sSMP::op_set1_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x02;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//clr1_dp
|
||||
case 0x32: {
|
||||
void sSMP::op_clr1_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x02;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//set2_dp
|
||||
case 0x42: {
|
||||
void sSMP::op_set2_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x04;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//clr2_dp
|
||||
case 0x52: {
|
||||
void sSMP::op_clr2_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x04;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//set3_dp
|
||||
case 0x62: {
|
||||
void sSMP::op_set3_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x08;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//clr3_dp
|
||||
case 0x72: {
|
||||
void sSMP::op_clr3_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x08;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//set4_dp
|
||||
case 0x82: {
|
||||
void sSMP::op_set4_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x10;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//clr4_dp
|
||||
case 0x92: {
|
||||
void sSMP::op_clr4_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x10;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//set5_dp
|
||||
case 0xa2: {
|
||||
void sSMP::op_set5_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x20;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//clr5_dp
|
||||
case 0xb2: {
|
||||
void sSMP::op_clr5_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x20;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//set6_dp
|
||||
case 0xc2: {
|
||||
void sSMP::op_set6_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x40;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//clr6_dp
|
||||
case 0xd2: {
|
||||
void sSMP::op_clr6_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x40;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//set7_dp
|
||||
case 0xe2: {
|
||||
void sSMP::op_set7_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= 0x80;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//clr7_dp
|
||||
case 0xf2: {
|
||||
void sSMP::op_clr7_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd &= ~0x80;
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//tset_addr_a
|
||||
case 0x0e: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
op_io();
|
||||
regs.p.n = !!((rd & regs.a) & 0x80);
|
||||
regs.p.z = ((rd & regs.a) == 0);
|
||||
rd |= regs.a;
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
|
||||
//tclr_addr_a
|
||||
case 0x4e: {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
op_io();
|
||||
regs.p.n = !!((rd & regs.a) & 0x80);
|
||||
regs.p.z = ((rd & regs.a) == 0);
|
||||
rd &=~ regs.a;
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
|
||||
//push_a
|
||||
case 0x2d: {
|
||||
void sSMP::op_push_a() {
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.a);
|
||||
} break;
|
||||
}
|
||||
|
||||
//push_x
|
||||
case 0x4d: {
|
||||
void sSMP::op_push_x() {
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.x);
|
||||
} break;
|
||||
}
|
||||
|
||||
//push_y
|
||||
case 0x6d: {
|
||||
void sSMP::op_push_y() {
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.y);
|
||||
} break;
|
||||
}
|
||||
|
||||
//push_p
|
||||
case 0x0d: {
|
||||
void sSMP::op_push_p() {
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.p);
|
||||
} break;
|
||||
}
|
||||
|
||||
//pop_a
|
||||
case 0xae: {
|
||||
void sSMP::op_pop_a() {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.a = op_readstack();
|
||||
} break;
|
||||
}
|
||||
|
||||
//pop_x
|
||||
case 0xce: {
|
||||
void sSMP::op_pop_x() {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.x = op_readstack();
|
||||
} break;
|
||||
}
|
||||
|
||||
//pop_y
|
||||
case 0xee: {
|
||||
void sSMP::op_pop_y() {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.y = op_readstack();
|
||||
} break;
|
||||
}
|
||||
|
||||
//pop_p
|
||||
case 0x8e: {
|
||||
void sSMP::op_pop_p() {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.p = op_readstack();
|
||||
} break;
|
||||
}
|
||||
|
||||
//mul_ya
|
||||
case 0xcf: {
|
||||
void sSMP::op_mul_ya() {
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
|
@ -334,10 +271,9 @@ case 0xcf: {
|
|||
//result is set based on y (high-byte) only
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//div_ya_x
|
||||
case 0x9e: {
|
||||
void sSMP::op_div_ya_x() {
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
|
@ -366,5 +302,5 @@ case 0x9e: {
|
|||
//result is set based on a (quotient) only
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,8 +31,8 @@ mov_a_ix(0xe6) {
|
|||
|
||||
mov_a_ixinc(0xbf) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
3:regs.a = op_readdp(regs.x++);
|
||||
2:regs.a = op_readdp(regs.x++);
|
||||
3:op_io();
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
@ -98,8 +98,8 @@ mov_a_idpy(0xf7) {
|
|||
|
||||
mov_dp_dp(0xfa) {
|
||||
1:sp = op_readpc();
|
||||
2:dp = op_readpc();
|
||||
3:rd = op_readdp(sp);
|
||||
2:rd = op_readdp(sp);
|
||||
3:dp = op_readpc();
|
||||
4:op_writedp(dp, rd);
|
||||
}
|
||||
|
||||
|
@ -181,8 +181,8 @@ mov_idpy_a(0xd7) {
|
|||
|
||||
movw_ya_dp(0xba) {
|
||||
1:sp = op_readpc();
|
||||
2:op_io();
|
||||
3:regs.a = op_readdp(sp);
|
||||
2:regs.a = op_readdp(sp);
|
||||
3:op_io();
|
||||
4:regs.y = op_readdp(sp + 1);
|
||||
regs.p.n = !!(regs.ya & 0x8000);
|
||||
regs.p.z = (regs.ya == 0);
|
||||
|
@ -212,5 +212,6 @@ mov1_bit_c(0xca) {
|
|||
rd = op_readaddr(dp);
|
||||
if(regs.p.c)rd |= (1 << bit);
|
||||
else rd &= ~(1 << bit);
|
||||
4:op_writeaddr(dp, rd);
|
||||
4:op_io();
|
||||
5:op_writeaddr(dp, rd);
|
||||
}
|
||||
|
|
|
@ -1,187 +1,164 @@
|
|||
//mov_a_x
|
||||
case 0x7d: {
|
||||
void sSMP::op_mov_a_x() {
|
||||
op_io();
|
||||
regs.a = regs.x;
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_a_y
|
||||
case 0xdd: {
|
||||
void sSMP::op_mov_a_y() {
|
||||
op_io();
|
||||
regs.a = regs.y;
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_x_a
|
||||
case 0x5d: {
|
||||
void sSMP::op_mov_x_a() {
|
||||
op_io();
|
||||
regs.x = regs.a;
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_y_a
|
||||
case 0xfd: {
|
||||
void sSMP::op_mov_y_a() {
|
||||
op_io();
|
||||
regs.y = regs.a;
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_x_sp
|
||||
case 0x9d: {
|
||||
void sSMP::op_mov_x_sp() {
|
||||
op_io();
|
||||
regs.x = regs.sp;
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_sp_x
|
||||
case 0xbd: {
|
||||
void sSMP::op_mov_sp_x() {
|
||||
op_io();
|
||||
regs.sp = regs.x;
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_a_const
|
||||
case 0xe8: {
|
||||
void sSMP::op_mov_a_const() {
|
||||
regs.a = op_readpc();
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_x_const
|
||||
case 0xcd: {
|
||||
void sSMP::op_mov_x_const() {
|
||||
regs.x = op_readpc();
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_y_const
|
||||
case 0x8d: {
|
||||
void sSMP::op_mov_y_const() {
|
||||
regs.y = op_readpc();
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_a_ix
|
||||
case 0xe6: {
|
||||
void sSMP::op_mov_a_ix() {
|
||||
op_io();
|
||||
regs.a = op_readdp(regs.x);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_a_ixinc
|
||||
case 0xbf: {
|
||||
op_io();
|
||||
void sSMP::op_mov_a_ixinc() {
|
||||
op_io();
|
||||
regs.a = op_readdp(regs.x++);
|
||||
op_io();
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_a_dp
|
||||
case 0xe4: {
|
||||
void sSMP::op_mov_a_dp() {
|
||||
sp = op_readpc();
|
||||
regs.a = op_readdp(sp);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_x_dp
|
||||
case 0xf8: {
|
||||
void sSMP::op_mov_x_dp() {
|
||||
sp = op_readpc();
|
||||
regs.x = op_readdp(sp);
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_y_dp
|
||||
case 0xeb: {
|
||||
void sSMP::op_mov_y_dp() {
|
||||
sp = op_readpc();
|
||||
regs.y = op_readdp(sp);
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_a_dpx
|
||||
case 0xf4: {
|
||||
void sSMP::op_mov_a_dpx() {
|
||||
sp = op_readpc();
|
||||
op_io();
|
||||
regs.a = op_readdp(sp + regs.x);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_x_dpy
|
||||
case 0xf9: {
|
||||
void sSMP::op_mov_x_dpy() {
|
||||
sp = op_readpc();
|
||||
op_io();
|
||||
regs.x = op_readdp(sp + regs.y);
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_y_dpx
|
||||
case 0xfb: {
|
||||
void sSMP::op_mov_y_dpx() {
|
||||
sp = op_readpc();
|
||||
op_io();
|
||||
regs.y = op_readdp(sp + regs.x);
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_a_addr
|
||||
case 0xe5: {
|
||||
void sSMP::op_mov_a_addr() {
|
||||
sp = op_readpc();
|
||||
sp |= op_readpc() << 8;
|
||||
regs.a = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_x_addr
|
||||
case 0xe9: {
|
||||
void sSMP::op_mov_x_addr() {
|
||||
sp = op_readpc();
|
||||
sp |= op_readpc() << 8;
|
||||
regs.x = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_y_addr
|
||||
case 0xec: {
|
||||
void sSMP::op_mov_y_addr() {
|
||||
sp = op_readpc();
|
||||
sp |= op_readpc() << 8;
|
||||
regs.y = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_a_addrx
|
||||
case 0xf5: {
|
||||
void sSMP::op_mov_a_addrx() {
|
||||
sp = op_readpc();
|
||||
sp |= op_readpc() << 8;
|
||||
op_io();
|
||||
regs.a = op_readaddr(sp + regs.x);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_a_addry
|
||||
case 0xf6: {
|
||||
void sSMP::op_mov_a_addry() {
|
||||
sp = op_readpc();
|
||||
sp |= op_readpc() << 8;
|
||||
op_io();
|
||||
regs.a = op_readaddr(sp + regs.y);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_a_idpx
|
||||
case 0xe7: {
|
||||
void sSMP::op_mov_a_idpx() {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
|
@ -189,10 +166,9 @@ case 0xe7: {
|
|||
regs.a = op_readaddr(sp);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_a_idpy
|
||||
case 0xf7: {
|
||||
void sSMP::op_mov_a_idpy() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
|
@ -200,132 +176,116 @@ case 0xf7: {
|
|||
regs.a = op_readaddr(sp + regs.y);
|
||||
regs.p.n = !!(regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_dp_dp
|
||||
case 0xfa: {
|
||||
void sSMP::op_mov_dp_dp() {
|
||||
sp = op_readpc();
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(sp);
|
||||
dp = op_readpc();
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_dp_const
|
||||
case 0x8f: {
|
||||
void sSMP::op_mov_dp_const() {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
op_readdp(dp);
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_ix_a
|
||||
case 0xc6: {
|
||||
void sSMP::op_mov_ix_a() {
|
||||
op_io();
|
||||
op_readdp(regs.x);
|
||||
op_writedp(regs.x, regs.a);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_ixinc_a
|
||||
case 0xaf: {
|
||||
void sSMP::op_mov_ixinc_a() {
|
||||
op_io();
|
||||
op_io();
|
||||
op_writedp(regs.x++, regs.a);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_dp_a
|
||||
case 0xc4: {
|
||||
void sSMP::op_mov_dp_a() {
|
||||
dp = op_readpc();
|
||||
op_readdp(dp);
|
||||
op_writedp(dp, regs.a);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_dp_x
|
||||
case 0xd8: {
|
||||
void sSMP::op_mov_dp_x() {
|
||||
dp = op_readpc();
|
||||
op_readdp(dp);
|
||||
op_writedp(dp, regs.x);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_dp_y
|
||||
case 0xcb: {
|
||||
void sSMP::op_mov_dp_y() {
|
||||
dp = op_readpc();
|
||||
op_readdp(dp);
|
||||
op_writedp(dp, regs.y);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_dpx_a
|
||||
case 0xd4: {
|
||||
void sSMP::op_mov_dpx_a() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
dp += regs.x;
|
||||
op_readdp(dp);
|
||||
op_writedp(dp, regs.a);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_dpy_x
|
||||
case 0xd9: {
|
||||
void sSMP::op_mov_dpy_x() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
dp += regs.y;
|
||||
op_readdp(dp);
|
||||
op_writedp(dp, regs.x);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_dpx_y
|
||||
case 0xdb: {
|
||||
void sSMP::op_mov_dpx_y() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
dp += regs.x;
|
||||
op_readdp(dp);
|
||||
op_writedp(dp, regs.y);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_addr_a
|
||||
case 0xc5: {
|
||||
void sSMP::op_mov_addr_a() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_readaddr(dp);
|
||||
op_writeaddr(dp, regs.a);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_addr_x
|
||||
case 0xc9: {
|
||||
void sSMP::op_mov_addr_x() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_readaddr(dp);
|
||||
op_writeaddr(dp, regs.x);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_addr_y
|
||||
case 0xcc: {
|
||||
void sSMP::op_mov_addr_y() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_readaddr(dp);
|
||||
op_writeaddr(dp, regs.y);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_addrx_a
|
||||
case 0xd5: {
|
||||
void sSMP::op_mov_addrx_a() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
dp += regs.x;
|
||||
op_readaddr(dp);
|
||||
op_writeaddr(dp, regs.a);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_addry_a
|
||||
case 0xd6: {
|
||||
void sSMP::op_mov_addry_a() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
dp += regs.y;
|
||||
op_readaddr(dp);
|
||||
op_writeaddr(dp, regs.a);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_idpx_a
|
||||
case 0xc7: {
|
||||
void sSMP::op_mov_idpx_a() {
|
||||
sp = op_readpc();
|
||||
op_io();
|
||||
sp += regs.x;
|
||||
|
@ -333,10 +293,9 @@ case 0xc7: {
|
|||
dp |= op_readdp(sp + 1) << 8;
|
||||
op_readaddr(dp);
|
||||
op_writeaddr(dp, regs.a);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov_idpy_a
|
||||
case 0xd7: {
|
||||
void sSMP::op_mov_idpy_a() {
|
||||
sp = op_readpc();
|
||||
dp = op_readdp(sp);
|
||||
dp |= op_readdp(sp + 1) << 8;
|
||||
|
@ -344,38 +303,34 @@ case 0xd7: {
|
|||
dp += regs.y;
|
||||
op_readaddr(dp);
|
||||
op_writeaddr(dp, regs.a);
|
||||
} break;
|
||||
}
|
||||
|
||||
//movw_ya_dp
|
||||
case 0xba: {
|
||||
void sSMP::op_movw_ya_dp() {
|
||||
sp = op_readpc();
|
||||
op_io();
|
||||
regs.a = op_readdp(sp);
|
||||
op_io();
|
||||
regs.y = op_readdp(sp + 1);
|
||||
regs.p.n = !!(regs.ya & 0x8000);
|
||||
regs.p.z = (regs.ya == 0);
|
||||
} break;
|
||||
}
|
||||
|
||||
//movw_dp_ya
|
||||
case 0xda: {
|
||||
void sSMP::op_movw_dp_ya() {
|
||||
dp = op_readpc();
|
||||
op_readdp(dp);
|
||||
op_writedp(dp, regs.a);
|
||||
op_writedp(dp + 1, regs.y);
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov1_c_bit
|
||||
case 0xaa: {
|
||||
void sSMP::op_mov1_c_bit() {
|
||||
sp = op_readpc();
|
||||
sp |= op_readpc() << 8;
|
||||
bit = sp >> 13;
|
||||
sp &= 0x1fff;
|
||||
rd = op_readaddr(sp);
|
||||
regs.p.c = !!(rd & (1 << bit));
|
||||
} break;
|
||||
}
|
||||
|
||||
//mov1_bit_c
|
||||
case 0xca: {
|
||||
void sSMP::op_mov1_bit_c() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
|
@ -383,6 +338,7 @@ case 0xca: {
|
|||
rd = op_readaddr(dp);
|
||||
if(regs.p.c)rd |= (1 << bit);
|
||||
else rd &= ~(1 << bit);
|
||||
op_io();
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,8 +31,8 @@ bbc6(0xd3, 0x40, ==),
|
|||
bbs7(0xe3, 0x80, !=),
|
||||
bbc7(0xf3, 0x80, ==) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readpc();
|
||||
3:sp = op_readdp(dp);
|
||||
2:sp = op_readdp(dp);
|
||||
3:rd = op_readpc();
|
||||
4:op_io();
|
||||
if((sp & $1) $2 $1)end;
|
||||
5:op_io();
|
||||
|
@ -42,8 +42,8 @@ bbc7(0xf3, 0x80, ==) {
|
|||
|
||||
cbne_dp(0x2e) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readpc();
|
||||
3:sp = op_readdp(dp);
|
||||
2:sp = op_readdp(dp);
|
||||
3:rd = op_readpc();
|
||||
4:op_io();
|
||||
if(regs.a == sp)end;
|
||||
5:op_io();
|
||||
|
@ -53,9 +53,9 @@ cbne_dp(0x2e) {
|
|||
|
||||
cbne_dpx(0xde) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readpc();
|
||||
3:op_io();
|
||||
4:sp = op_readdp(dp + regs.x);
|
||||
2:op_io();
|
||||
3:sp = op_readdp(dp + regs.x);
|
||||
4:rd = op_readpc();
|
||||
5:op_io();
|
||||
if(regs.a == sp)end;
|
||||
6:op_io();
|
||||
|
@ -65,10 +65,9 @@ cbne_dpx(0xde) {
|
|||
|
||||
dbnz_dp(0x6e) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readpc();
|
||||
3:wr = op_readdp(dp);
|
||||
wr--;
|
||||
4:op_writedp(dp, wr);
|
||||
2:wr = op_readdp(dp);
|
||||
3:op_writedp(dp, --wr);
|
||||
4:rd = op_readpc();
|
||||
if(wr == 0x00)end;
|
||||
5:op_io();
|
||||
6:op_io();
|
||||
|
|
|
@ -1,335 +1,303 @@
|
|||
//bra
|
||||
case 0x2f: {
|
||||
void sSMP::op_bra() {
|
||||
rd = op_readpc();
|
||||
if(0)break;
|
||||
if(0)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//beq
|
||||
case 0xf0: {
|
||||
void sSMP::op_beq() {
|
||||
rd = op_readpc();
|
||||
if(!regs.p.z)break;
|
||||
if(!regs.p.z)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bne
|
||||
case 0xd0: {
|
||||
void sSMP::op_bne() {
|
||||
rd = op_readpc();
|
||||
if(regs.p.z)break;
|
||||
if(regs.p.z)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bcs
|
||||
case 0xb0: {
|
||||
void sSMP::op_bcs() {
|
||||
rd = op_readpc();
|
||||
if(!regs.p.c)break;
|
||||
if(!regs.p.c)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bcc
|
||||
case 0x90: {
|
||||
void sSMP::op_bcc() {
|
||||
rd = op_readpc();
|
||||
if(regs.p.c)break;
|
||||
if(regs.p.c)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bvs
|
||||
case 0x70: {
|
||||
void sSMP::op_bvs() {
|
||||
rd = op_readpc();
|
||||
if(!regs.p.v)break;
|
||||
if(!regs.p.v)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bvc
|
||||
case 0x50: {
|
||||
void sSMP::op_bvc() {
|
||||
rd = op_readpc();
|
||||
if(regs.p.v)break;
|
||||
if(regs.p.v)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bmi
|
||||
case 0x30: {
|
||||
void sSMP::op_bmi() {
|
||||
rd = op_readpc();
|
||||
if(!regs.p.n)break;
|
||||
if(!regs.p.n)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bpl
|
||||
case 0x10: {
|
||||
void sSMP::op_bpl() {
|
||||
rd = op_readpc();
|
||||
if(regs.p.n)break;
|
||||
if(regs.p.n)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bbs0
|
||||
case 0x03: {
|
||||
void sSMP::op_bbs0() {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x01) != 0x01)break;
|
||||
if((sp & 0x01) != 0x01)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bbc0
|
||||
case 0x13: {
|
||||
void sSMP::op_bbc0() {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x01) == 0x01)break;
|
||||
if((sp & 0x01) == 0x01)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bbs1
|
||||
case 0x23: {
|
||||
void sSMP::op_bbs1() {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x02) != 0x02)break;
|
||||
if((sp & 0x02) != 0x02)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bbc1
|
||||
case 0x33: {
|
||||
void sSMP::op_bbc1() {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x02) == 0x02)break;
|
||||
if((sp & 0x02) == 0x02)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bbs2
|
||||
case 0x43: {
|
||||
void sSMP::op_bbs2() {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x04) != 0x04)break;
|
||||
if((sp & 0x04) != 0x04)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bbc2
|
||||
case 0x53: {
|
||||
void sSMP::op_bbc2() {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x04) == 0x04)break;
|
||||
if((sp & 0x04) == 0x04)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bbs3
|
||||
case 0x63: {
|
||||
void sSMP::op_bbs3() {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x08) != 0x08)break;
|
||||
if((sp & 0x08) != 0x08)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bbc3
|
||||
case 0x73: {
|
||||
void sSMP::op_bbc3() {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x08) == 0x08)break;
|
||||
if((sp & 0x08) == 0x08)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bbs4
|
||||
case 0x83: {
|
||||
void sSMP::op_bbs4() {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x10) != 0x10)break;
|
||||
if((sp & 0x10) != 0x10)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bbc4
|
||||
case 0x93: {
|
||||
void sSMP::op_bbc4() {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x10) == 0x10)break;
|
||||
if((sp & 0x10) == 0x10)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bbs5
|
||||
case 0xa3: {
|
||||
void sSMP::op_bbs5() {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x20) != 0x20)break;
|
||||
if((sp & 0x20) != 0x20)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bbc5
|
||||
case 0xb3: {
|
||||
void sSMP::op_bbc5() {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x20) == 0x20)break;
|
||||
if((sp & 0x20) == 0x20)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bbs6
|
||||
case 0xc3: {
|
||||
void sSMP::op_bbs6() {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x40) != 0x40)break;
|
||||
if((sp & 0x40) != 0x40)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bbc6
|
||||
case 0xd3: {
|
||||
void sSMP::op_bbc6() {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x40) == 0x40)break;
|
||||
if((sp & 0x40) == 0x40)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bbs7
|
||||
case 0xe3: {
|
||||
void sSMP::op_bbs7() {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x80) != 0x80)break;
|
||||
if((sp & 0x80) != 0x80)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//bbc7
|
||||
case 0xf3: {
|
||||
void sSMP::op_bbc7() {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if((sp & 0x80) == 0x80)break;
|
||||
if((sp & 0x80) == 0x80)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//cbne_dp
|
||||
case 0x2e: {
|
||||
void sSMP::op_cbne_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
if(regs.a == sp)break;
|
||||
if(regs.a == sp)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//cbne_dpx
|
||||
case 0xde: {
|
||||
void sSMP::op_cbne_dpx() {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp + regs.x);
|
||||
op_io();
|
||||
if(regs.a == sp)break;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
|
||||
//dbnz_dp
|
||||
case 0x6e: {
|
||||
dp = op_readpc();
|
||||
rd = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr--;
|
||||
op_writedp(dp, wr);
|
||||
if(wr == 0x00)break;
|
||||
op_io();
|
||||
if(regs.a == sp)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//dbnz_y
|
||||
case 0xfe: {
|
||||
void sSMP::op_dbnz_dp() {
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
op_writedp(dp, --wr);
|
||||
rd = op_readpc();
|
||||
if(wr == 0x00)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
void sSMP::op_dbnz_y() {
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
regs.y--;
|
||||
op_io();
|
||||
if(regs.y == 0x00)break;
|
||||
if(regs.y == 0x00)return;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc += (int8)rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//jmp_addr
|
||||
case 0x5f: {
|
||||
void sSMP::op_jmp_addr() {
|
||||
rd = op_readpc();
|
||||
rd |= op_readpc() << 8;
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//jmp_iaddrx
|
||||
case 0x1f: {
|
||||
void sSMP::op_jmp_iaddrx() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
|
@ -337,10 +305,9 @@ case 0x1f: {
|
|||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//call
|
||||
case 0x3f: {
|
||||
void sSMP::op_call() {
|
||||
rd = op_readpc();
|
||||
rd |= op_readpc() << 8;
|
||||
op_io();
|
||||
|
@ -349,20 +316,18 @@ case 0x3f: {
|
|||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//pcall
|
||||
case 0x4f: {
|
||||
void sSMP::op_pcall() {
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
op_io();
|
||||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = 0xff00 | rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcall_0
|
||||
case 0x01: {
|
||||
void sSMP::op_tcall_0() {
|
||||
dp = 0xffde - (0 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
|
@ -372,10 +337,9 @@ case 0x01: {
|
|||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcall_1
|
||||
case 0x11: {
|
||||
void sSMP::op_tcall_1() {
|
||||
dp = 0xffde - (1 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
|
@ -385,10 +349,9 @@ case 0x11: {
|
|||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcall_2
|
||||
case 0x21: {
|
||||
void sSMP::op_tcall_2() {
|
||||
dp = 0xffde - (2 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
|
@ -398,10 +361,9 @@ case 0x21: {
|
|||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcall_3
|
||||
case 0x31: {
|
||||
void sSMP::op_tcall_3() {
|
||||
dp = 0xffde - (3 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
|
@ -411,10 +373,9 @@ case 0x31: {
|
|||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcall_4
|
||||
case 0x41: {
|
||||
void sSMP::op_tcall_4() {
|
||||
dp = 0xffde - (4 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
|
@ -424,10 +385,9 @@ case 0x41: {
|
|||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcall_5
|
||||
case 0x51: {
|
||||
void sSMP::op_tcall_5() {
|
||||
dp = 0xffde - (5 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
|
@ -437,10 +397,9 @@ case 0x51: {
|
|||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcall_6
|
||||
case 0x61: {
|
||||
void sSMP::op_tcall_6() {
|
||||
dp = 0xffde - (6 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
|
@ -450,10 +409,9 @@ case 0x61: {
|
|||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcall_7
|
||||
case 0x71: {
|
||||
void sSMP::op_tcall_7() {
|
||||
dp = 0xffde - (7 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
|
@ -463,10 +421,9 @@ case 0x71: {
|
|||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcall_8
|
||||
case 0x81: {
|
||||
void sSMP::op_tcall_8() {
|
||||
dp = 0xffde - (8 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
|
@ -476,10 +433,9 @@ case 0x81: {
|
|||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcall_9
|
||||
case 0x91: {
|
||||
void sSMP::op_tcall_9() {
|
||||
dp = 0xffde - (9 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
|
@ -489,10 +445,9 @@ case 0x91: {
|
|||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcall_10
|
||||
case 0xa1: {
|
||||
void sSMP::op_tcall_10() {
|
||||
dp = 0xffde - (10 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
|
@ -502,10 +457,9 @@ case 0xa1: {
|
|||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcall_11
|
||||
case 0xb1: {
|
||||
void sSMP::op_tcall_11() {
|
||||
dp = 0xffde - (11 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
|
@ -515,10 +469,9 @@ case 0xb1: {
|
|||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcall_12
|
||||
case 0xc1: {
|
||||
void sSMP::op_tcall_12() {
|
||||
dp = 0xffde - (12 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
|
@ -528,10 +481,9 @@ case 0xc1: {
|
|||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcall_13
|
||||
case 0xd1: {
|
||||
void sSMP::op_tcall_13() {
|
||||
dp = 0xffde - (13 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
|
@ -541,10 +493,9 @@ case 0xd1: {
|
|||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcall_14
|
||||
case 0xe1: {
|
||||
void sSMP::op_tcall_14() {
|
||||
dp = 0xffde - (14 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
|
@ -554,10 +505,9 @@ case 0xe1: {
|
|||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//tcall_15
|
||||
case 0xf1: {
|
||||
void sSMP::op_tcall_15() {
|
||||
dp = 0xffde - (15 << 1);
|
||||
rd = op_readaddr(dp);
|
||||
rd |= op_readaddr(dp + 1) << 8;
|
||||
|
@ -567,10 +517,9 @@ case 0xf1: {
|
|||
op_writestack(regs.pc >> 8);
|
||||
op_writestack(regs.pc);
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//brk
|
||||
case 0x0f: {
|
||||
void sSMP::op_brk() {
|
||||
rd = op_readaddr(0xffde);
|
||||
rd |= op_readaddr(0xffdf) << 8;
|
||||
op_io();
|
||||
|
@ -581,24 +530,22 @@ case 0x0f: {
|
|||
regs.pc = rd;
|
||||
regs.p.b = 1;
|
||||
regs.p.i = 0;
|
||||
} break;
|
||||
}
|
||||
|
||||
//ret
|
||||
case 0x6f: {
|
||||
void sSMP::op_ret() {
|
||||
rd = op_readstack();
|
||||
rd |= op_readstack() << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
//reti
|
||||
case 0x7f: {
|
||||
void sSMP::op_reti() {
|
||||
regs.p = op_readstack();
|
||||
rd = op_readstack();
|
||||
rd |= op_readstack() << 8;
|
||||
op_io();
|
||||
op_io();
|
||||
regs.pc = rd;
|
||||
} break;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@ cmp_a_ix(0x66, cmp),
|
|||
eor_a_ix(0x46, eor),
|
||||
or_a_ix(0x06, or),
|
||||
sbc_a_ix(0xa6, sbc) {
|
||||
1:rd = op_readdp(regs.x);
|
||||
2:op_io();
|
||||
1:op_io();
|
||||
2:rd = op_readdp(regs.x);
|
||||
regs.a = op_$1(regs.a, rd);
|
||||
}
|
||||
|
||||
|
@ -113,9 +113,9 @@ cmp_ix_iy(0x79, cmp, 0),
|
|||
eor_ix_iy(0x59, eor, 1),
|
||||
or_ix_iy(0x19, or, 1),
|
||||
sbc_ix_iy(0xb9, sbc, 1) {
|
||||
1:wr = op_readdp(regs.x);
|
||||
1:op_io();
|
||||
2:rd = op_readdp(regs.y);
|
||||
3:op_io();
|
||||
3:wr = op_readdp(regs.x);
|
||||
wr = op_$1(wr, rd);
|
||||
4:($2) ? op_writedp(regs.x, wr) : op_io();
|
||||
}
|
||||
|
@ -127,9 +127,9 @@ eor_dp_dp(0x49, eor, 1),
|
|||
or_dp_dp(0x09, or, 1),
|
||||
sbc_dp_dp(0xa9, sbc, 1) {
|
||||
1:sp = op_readpc();
|
||||
2:dp = op_readpc();
|
||||
3:wr = op_readdp(dp);
|
||||
4:rd = op_readdp(sp);
|
||||
2:rd = op_readdp(sp);
|
||||
3:dp = op_readpc();
|
||||
4:wr = op_readdp(dp);
|
||||
5:wr = op_$1(wr, rd);
|
||||
($2) ? op_writedp(dp, wr) : op_io();
|
||||
}
|
||||
|
@ -151,8 +151,8 @@ addw_ya_dp(0x7a, addw),
|
|||
subw_ya_dp(0x9a, subw) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readdp(dp);
|
||||
3:rd |= op_readdp(dp + 1) << 8;
|
||||
4:op_io();
|
||||
3:op_io();
|
||||
4:rd |= op_readdp(dp + 1) << 8;
|
||||
regs.ya = op_$1(regs.ya, rd);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,705 +1,621 @@
|
|||
//adc_a_const
|
||||
case 0x88: {
|
||||
void sSMP::op_adc_a_const() {
|
||||
rd = op_readpc();
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//and_a_const
|
||||
case 0x28: {
|
||||
void sSMP::op_and_a_const() {
|
||||
rd = op_readpc();
|
||||
regs.a = op_and(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//cmp_a_const
|
||||
case 0x68: {
|
||||
void sSMP::op_cmp_a_const() {
|
||||
rd = op_readpc();
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//cmp_x_const
|
||||
case 0xc8: {
|
||||
void sSMP::op_cmp_x_const() {
|
||||
rd = op_readpc();
|
||||
regs.x = op_cmp(regs.x, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//cmp_y_const
|
||||
case 0xad: {
|
||||
void sSMP::op_cmp_y_const() {
|
||||
rd = op_readpc();
|
||||
regs.y = op_cmp(regs.y, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//eor_a_const
|
||||
case 0x48: {
|
||||
void sSMP::op_eor_a_const() {
|
||||
rd = op_readpc();
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//or_a_const
|
||||
case 0x08: {
|
||||
void sSMP::op_or_a_const() {
|
||||
rd = op_readpc();
|
||||
regs.a = op_or(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sbc_a_const
|
||||
case 0xa8: {
|
||||
void sSMP::op_sbc_a_const() {
|
||||
rd = op_readpc();
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//adc_a_ix
|
||||
case 0x86: {
|
||||
rd = op_readdp(regs.x);
|
||||
void sSMP::op_adc_a_ix() {
|
||||
op_io();
|
||||
rd = op_readdp(regs.x);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//and_a_ix
|
||||
case 0x26: {
|
||||
rd = op_readdp(regs.x);
|
||||
void sSMP::op_and_a_ix() {
|
||||
op_io();
|
||||
rd = op_readdp(regs.x);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//cmp_a_ix
|
||||
case 0x66: {
|
||||
rd = op_readdp(regs.x);
|
||||
void sSMP::op_cmp_a_ix() {
|
||||
op_io();
|
||||
rd = op_readdp(regs.x);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//eor_a_ix
|
||||
case 0x46: {
|
||||
rd = op_readdp(regs.x);
|
||||
void sSMP::op_eor_a_ix() {
|
||||
op_io();
|
||||
rd = op_readdp(regs.x);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//or_a_ix
|
||||
case 0x06: {
|
||||
rd = op_readdp(regs.x);
|
||||
void sSMP::op_or_a_ix() {
|
||||
op_io();
|
||||
rd = op_readdp(regs.x);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sbc_a_ix
|
||||
case 0xa6: {
|
||||
rd = op_readdp(regs.x);
|
||||
void sSMP::op_sbc_a_ix() {
|
||||
op_io();
|
||||
rd = op_readdp(regs.x);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//adc_a_dp
|
||||
case 0x84: {
|
||||
void sSMP::op_adc_a_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//and_a_dp
|
||||
case 0x24: {
|
||||
void sSMP::op_and_a_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//cmp_a_dp
|
||||
case 0x64: {
|
||||
void sSMP::op_cmp_a_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//cmp_x_dp
|
||||
case 0x3e: {
|
||||
void sSMP::op_cmp_x_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.x = op_cmp(regs.x, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//cmp_y_dp
|
||||
case 0x7e: {
|
||||
void sSMP::op_cmp_y_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.y = op_cmp(regs.y, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//eor_a_dp
|
||||
case 0x44: {
|
||||
void sSMP::op_eor_a_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//or_a_dp
|
||||
case 0x04: {
|
||||
void sSMP::op_or_a_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sbc_a_dp
|
||||
case 0xa4: {
|
||||
void sSMP::op_sbc_a_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//adc_a_dpx
|
||||
case 0x94: {
|
||||
void sSMP::op_adc_a_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//and_a_dpx
|
||||
case 0x34: {
|
||||
void sSMP::op_and_a_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//cmp_a_dpx
|
||||
case 0x74: {
|
||||
void sSMP::op_cmp_a_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//eor_a_dpx
|
||||
case 0x54: {
|
||||
void sSMP::op_eor_a_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//or_a_dpx
|
||||
case 0x14: {
|
||||
void sSMP::op_or_a_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sbc_a_dpx
|
||||
case 0xb4: {
|
||||
void sSMP::op_sbc_a_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//adc_a_addr
|
||||
case 0x85: {
|
||||
void sSMP::op_adc_a_addr() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//and_a_addr
|
||||
case 0x25: {
|
||||
void sSMP::op_and_a_addr() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//cmp_a_addr
|
||||
case 0x65: {
|
||||
void sSMP::op_cmp_a_addr() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//cmp_x_addr
|
||||
case 0x1e: {
|
||||
void sSMP::op_cmp_x_addr() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.x = op_cmp(regs.x, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//cmp_y_addr
|
||||
case 0x5e: {
|
||||
void sSMP::op_cmp_y_addr() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.y = op_cmp(regs.y, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//eor_a_addr
|
||||
case 0x45: {
|
||||
void sSMP::op_eor_a_addr() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//or_a_addr
|
||||
case 0x05: {
|
||||
void sSMP::op_or_a_addr() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sbc_a_addr
|
||||
case 0xa5: {
|
||||
void sSMP::op_sbc_a_addr() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//adc_a_addrx
|
||||
case 0x95: {
|
||||
void sSMP::op_adc_a_addrx() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.x);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//adc_a_addry
|
||||
case 0x96: {
|
||||
void sSMP::op_adc_a_addry() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.y);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//and_a_addrx
|
||||
case 0x35: {
|
||||
void sSMP::op_and_a_addrx() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.x);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//and_a_addry
|
||||
case 0x36: {
|
||||
void sSMP::op_and_a_addry() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.y);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//cmp_a_addrx
|
||||
case 0x75: {
|
||||
void sSMP::op_cmp_a_addrx() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.x);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//cmp_a_addry
|
||||
case 0x76: {
|
||||
void sSMP::op_cmp_a_addry() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.y);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//eor_a_addrx
|
||||
case 0x55: {
|
||||
void sSMP::op_eor_a_addrx() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.x);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//eor_a_addry
|
||||
case 0x56: {
|
||||
void sSMP::op_eor_a_addry() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.y);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//or_a_addrx
|
||||
case 0x15: {
|
||||
void sSMP::op_or_a_addrx() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.x);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//or_a_addry
|
||||
case 0x16: {
|
||||
void sSMP::op_or_a_addry() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.y);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sbc_a_addrx
|
||||
case 0xb5: {
|
||||
void sSMP::op_sbc_a_addrx() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.x);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sbc_a_addry
|
||||
case 0xb6: {
|
||||
void sSMP::op_sbc_a_addry() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
op_io();
|
||||
rd = op_readaddr(dp + regs.y);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//adc_a_idpx
|
||||
case 0x87: {
|
||||
void sSMP::op_adc_a_idpx() {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//and_a_idpx
|
||||
case 0x27: {
|
||||
void sSMP::op_and_a_idpx() {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//cmp_a_idpx
|
||||
case 0x67: {
|
||||
void sSMP::op_cmp_a_idpx() {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//eor_a_idpx
|
||||
case 0x47: {
|
||||
void sSMP::op_eor_a_idpx() {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//or_a_idpx
|
||||
case 0x07: {
|
||||
void sSMP::op_or_a_idpx() {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sbc_a_idpx
|
||||
case 0xa7: {
|
||||
void sSMP::op_sbc_a_idpx() {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//adc_a_idpy
|
||||
case 0x97: {
|
||||
void sSMP::op_adc_a_idpy() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_adc(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//and_a_idpy
|
||||
case 0x37: {
|
||||
void sSMP::op_and_a_idpy() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_and(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//cmp_a_idpy
|
||||
case 0x77: {
|
||||
void sSMP::op_cmp_a_idpy() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_cmp(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//eor_a_idpy
|
||||
case 0x57: {
|
||||
void sSMP::op_eor_a_idpy() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_eor(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//or_a_idpy
|
||||
case 0x17: {
|
||||
void sSMP::op_or_a_idpy() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_or(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//sbc_a_idpy
|
||||
case 0xb7: {
|
||||
void sSMP::op_sbc_a_idpy() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp);
|
||||
sp |= op_readdp(dp + 1) << 8;
|
||||
rd = op_readaddr(sp + regs.y);
|
||||
regs.a = op_sbc(regs.a, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//adc_ix_iy
|
||||
case 0x99: {
|
||||
wr = op_readdp(regs.x);
|
||||
void sSMP::op_adc_ix_iy() {
|
||||
op_io();
|
||||
rd = op_readdp(regs.y);
|
||||
op_io();
|
||||
wr = op_readdp(regs.x);
|
||||
wr = op_adc(wr, rd);
|
||||
(1) ? op_writedp(regs.x, wr) : op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//and_ix_iy
|
||||
case 0x39: {
|
||||
wr = op_readdp(regs.x);
|
||||
rd = op_readdp(regs.y);
|
||||
void sSMP::op_and_ix_iy() {
|
||||
op_io();
|
||||
rd = op_readdp(regs.y);
|
||||
wr = op_readdp(regs.x);
|
||||
wr = op_and(wr, rd);
|
||||
(1) ? op_writedp(regs.x, wr) : op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//cmp_ix_iy
|
||||
case 0x79: {
|
||||
wr = op_readdp(regs.x);
|
||||
rd = op_readdp(regs.y);
|
||||
void sSMP::op_cmp_ix_iy() {
|
||||
op_io();
|
||||
rd = op_readdp(regs.y);
|
||||
wr = op_readdp(regs.x);
|
||||
wr = op_cmp(wr, rd);
|
||||
(0) ? op_writedp(regs.x, wr) : op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//eor_ix_iy
|
||||
case 0x59: {
|
||||
wr = op_readdp(regs.x);
|
||||
rd = op_readdp(regs.y);
|
||||
void sSMP::op_eor_ix_iy() {
|
||||
op_io();
|
||||
rd = op_readdp(regs.y);
|
||||
wr = op_readdp(regs.x);
|
||||
wr = op_eor(wr, rd);
|
||||
(1) ? op_writedp(regs.x, wr) : op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//or_ix_iy
|
||||
case 0x19: {
|
||||
wr = op_readdp(regs.x);
|
||||
rd = op_readdp(regs.y);
|
||||
void sSMP::op_or_ix_iy() {
|
||||
op_io();
|
||||
rd = op_readdp(regs.y);
|
||||
wr = op_readdp(regs.x);
|
||||
wr = op_or(wr, rd);
|
||||
(1) ? op_writedp(regs.x, wr) : op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//sbc_ix_iy
|
||||
case 0xb9: {
|
||||
wr = op_readdp(regs.x);
|
||||
rd = op_readdp(regs.y);
|
||||
void sSMP::op_sbc_ix_iy() {
|
||||
op_io();
|
||||
rd = op_readdp(regs.y);
|
||||
wr = op_readdp(regs.x);
|
||||
wr = op_sbc(wr, rd);
|
||||
(1) ? op_writedp(regs.x, wr) : op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//adc_dp_dp
|
||||
case 0x89: {
|
||||
void sSMP::op_adc_dp_dp() {
|
||||
sp = op_readpc();
|
||||
rd = op_readdp(sp);
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
rd = op_readdp(sp);
|
||||
wr = op_adc(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//and_dp_dp
|
||||
case 0x29: {
|
||||
void sSMP::op_and_dp_dp() {
|
||||
sp = op_readpc();
|
||||
rd = op_readdp(sp);
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
rd = op_readdp(sp);
|
||||
wr = op_and(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//cmp_dp_dp
|
||||
case 0x69: {
|
||||
void sSMP::op_cmp_dp_dp() {
|
||||
sp = op_readpc();
|
||||
rd = op_readdp(sp);
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
rd = op_readdp(sp);
|
||||
wr = op_cmp(wr, rd);
|
||||
(0) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//eor_dp_dp
|
||||
case 0x49: {
|
||||
void sSMP::op_eor_dp_dp() {
|
||||
sp = op_readpc();
|
||||
rd = op_readdp(sp);
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
rd = op_readdp(sp);
|
||||
wr = op_eor(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//or_dp_dp
|
||||
case 0x09: {
|
||||
void sSMP::op_or_dp_dp() {
|
||||
sp = op_readpc();
|
||||
rd = op_readdp(sp);
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
rd = op_readdp(sp);
|
||||
wr = op_or(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//sbc_dp_dp
|
||||
case 0xa9: {
|
||||
void sSMP::op_sbc_dp_dp() {
|
||||
sp = op_readpc();
|
||||
rd = op_readdp(sp);
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
rd = op_readdp(sp);
|
||||
wr = op_sbc(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//adc_dp_const
|
||||
case 0x98: {
|
||||
void sSMP::op_adc_dp_const() {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_adc(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//and_dp_const
|
||||
case 0x38: {
|
||||
void sSMP::op_and_dp_const() {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_and(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//cmp_dp_const
|
||||
case 0x78: {
|
||||
void sSMP::op_cmp_dp_const() {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_cmp(wr, rd);
|
||||
(0) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//eor_dp_const
|
||||
case 0x58: {
|
||||
void sSMP::op_eor_dp_const() {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_eor(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//or_dp_const
|
||||
case 0x18: {
|
||||
void sSMP::op_or_dp_const() {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_or(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//sbc_dp_const
|
||||
case 0xb8: {
|
||||
void sSMP::op_sbc_dp_const() {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
wr = op_sbc(wr, rd);
|
||||
(1) ? op_writedp(dp, wr) : op_io();
|
||||
} break;
|
||||
}
|
||||
|
||||
//addw_ya_dp
|
||||
case 0x7a: {
|
||||
void sSMP::op_addw_ya_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= op_readdp(dp + 1) << 8;
|
||||
op_io();
|
||||
rd |= op_readdp(dp + 1) << 8;
|
||||
regs.ya = op_addw(regs.ya, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//subw_ya_dp
|
||||
case 0x9a: {
|
||||
void sSMP::op_subw_ya_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= op_readdp(dp + 1) << 8;
|
||||
op_io();
|
||||
rd |= op_readdp(dp + 1) << 8;
|
||||
regs.ya = op_subw(regs.ya, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//cmpw_ya_dp
|
||||
case 0x5a: {
|
||||
void sSMP::op_cmpw_ya_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= op_readdp(dp + 1) << 8;
|
||||
op_cmpw(regs.ya, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//and1_bit
|
||||
case 0x4a: {
|
||||
void sSMP::op_and1_bit() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
regs.p.c = regs.p.c & !!(rd & (1 << bit));
|
||||
} break;
|
||||
}
|
||||
|
||||
//and1_notbit
|
||||
case 0x6a: {
|
||||
void sSMP::op_and1_notbit() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
dp &= 0x1fff;
|
||||
rd = op_readaddr(dp);
|
||||
regs.p.c = regs.p.c & !(rd & (1 << bit));
|
||||
} break;
|
||||
}
|
||||
|
||||
//eor1_bit
|
||||
case 0x8a: {
|
||||
void sSMP::op_eor1_bit() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
|
@ -707,10 +623,9 @@ case 0x8a: {
|
|||
rd = op_readaddr(dp);
|
||||
op_io();
|
||||
regs.p.c = regs.p.c ^ !!(rd & (1 << bit));
|
||||
} break;
|
||||
}
|
||||
|
||||
//not1_bit
|
||||
case 0xea: {
|
||||
void sSMP::op_not1_bit() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
|
@ -718,10 +633,9 @@ case 0xea: {
|
|||
rd = op_readaddr(dp);
|
||||
rd ^= (1 << bit);
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//or1_bit
|
||||
case 0x0a: {
|
||||
void sSMP::op_or1_bit() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
|
@ -729,10 +643,9 @@ case 0x0a: {
|
|||
rd = op_readaddr(dp);
|
||||
op_io();
|
||||
regs.p.c = regs.p.c | !!(rd & (1 << bit));
|
||||
} break;
|
||||
}
|
||||
|
||||
//or1_notbit
|
||||
case 0x2a: {
|
||||
void sSMP::op_or1_notbit() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
bit = dp >> 13;
|
||||
|
@ -740,5 +653,5 @@ case 0x2a: {
|
|||
rd = op_readaddr(dp);
|
||||
op_io();
|
||||
regs.p.c = regs.p.c | !(rd & (1 << bit));
|
||||
} break;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,12 +50,25 @@ ror_addr(0x6c, ror) {
|
|||
op_writeaddr(dp, rd);
|
||||
}
|
||||
|
||||
incw_dp(0x3a, incw),
|
||||
decw_dp(0x1a, decw) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readdp(dp);
|
||||
3:rd |= op_readdp(dp + 1) << 8;
|
||||
4:rd = op_$1(rd);
|
||||
op_writedp(dp + 1, rd >> 8);
|
||||
5:op_writedp(dp, rd);
|
||||
tset_addr_a(0x0e, |),
|
||||
tclr_addr_a(0x4e, &~) {
|
||||
1:dp = op_readpc();
|
||||
2:dp |= op_readpc() << 8;
|
||||
3:rd = op_readaddr(dp);
|
||||
regs.p.n = !!((regs.a - rd) & 0x80);
|
||||
regs.p.z = ((regs.a - rd) == 0);
|
||||
4:op_readaddr(dp);
|
||||
5:op_writeaddr(dp, rd $1 regs.a);
|
||||
}
|
||||
|
||||
incw_dp(0x3a, rd++),
|
||||
decw_dp(0x1a, rd--) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readdp(dp);
|
||||
$1;
|
||||
3:op_writedp(dp++, rd);
|
||||
4:rd += op_readdp(dp) << 8;
|
||||
5:op_write(dp, rd >> 8);
|
||||
regs.p.n = !!(rd & 0x8000);
|
||||
regs.p.z = (rd == 0);
|
||||
}
|
||||
|
|
|
@ -1,236 +1,230 @@
|
|||
//inc_a
|
||||
case 0xbc: {
|
||||
void sSMP::op_inc_a() {
|
||||
op_io();
|
||||
regs.a = op_inc(regs.a);
|
||||
} break;
|
||||
}
|
||||
|
||||
//inc_x
|
||||
case 0x3d: {
|
||||
void sSMP::op_inc_x() {
|
||||
op_io();
|
||||
regs.x = op_inc(regs.x);
|
||||
} break;
|
||||
}
|
||||
|
||||
//inc_y
|
||||
case 0xfc: {
|
||||
void sSMP::op_inc_y() {
|
||||
op_io();
|
||||
regs.y = op_inc(regs.y);
|
||||
} break;
|
||||
}
|
||||
|
||||
//dec_a
|
||||
case 0x9c: {
|
||||
void sSMP::op_dec_a() {
|
||||
op_io();
|
||||
regs.a = op_dec(regs.a);
|
||||
} break;
|
||||
}
|
||||
|
||||
//dec_x
|
||||
case 0x1d: {
|
||||
void sSMP::op_dec_x() {
|
||||
op_io();
|
||||
regs.x = op_dec(regs.x);
|
||||
} break;
|
||||
}
|
||||
|
||||
//dec_y
|
||||
case 0xdc: {
|
||||
void sSMP::op_dec_y() {
|
||||
op_io();
|
||||
regs.y = op_dec(regs.y);
|
||||
} break;
|
||||
}
|
||||
|
||||
//asl_a
|
||||
case 0x1c: {
|
||||
void sSMP::op_asl_a() {
|
||||
op_io();
|
||||
regs.a = op_asl(regs.a);
|
||||
} break;
|
||||
}
|
||||
|
||||
//lsr_a
|
||||
case 0x5c: {
|
||||
void sSMP::op_lsr_a() {
|
||||
op_io();
|
||||
regs.a = op_lsr(regs.a);
|
||||
} break;
|
||||
}
|
||||
|
||||
//rol_a
|
||||
case 0x3c: {
|
||||
void sSMP::op_rol_a() {
|
||||
op_io();
|
||||
regs.a = op_rol(regs.a);
|
||||
} break;
|
||||
}
|
||||
|
||||
//ror_a
|
||||
case 0x7c: {
|
||||
void sSMP::op_ror_a() {
|
||||
op_io();
|
||||
regs.a = op_ror(regs.a);
|
||||
} break;
|
||||
}
|
||||
|
||||
//inc_dp
|
||||
case 0xab: {
|
||||
void sSMP::op_inc_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd = op_inc(rd);
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//dec_dp
|
||||
case 0x8b: {
|
||||
void sSMP::op_dec_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd = op_dec(rd);
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//asl_dp
|
||||
case 0x0b: {
|
||||
void sSMP::op_asl_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd = op_asl(rd);
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//lsr_dp
|
||||
case 0x4b: {
|
||||
void sSMP::op_lsr_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd = op_lsr(rd);
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//rol_dp
|
||||
case 0x2b: {
|
||||
void sSMP::op_rol_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd = op_rol(rd);
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//ror_dp
|
||||
case 0x6b: {
|
||||
void sSMP::op_ror_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd = op_ror(rd);
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//inc_dpx
|
||||
case 0xbb: {
|
||||
void sSMP::op_inc_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
rd = op_inc(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//dec_dpx
|
||||
case 0x9b: {
|
||||
void sSMP::op_dec_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
rd = op_dec(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//asl_dpx
|
||||
case 0x1b: {
|
||||
void sSMP::op_asl_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
rd = op_asl(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//lsr_dpx
|
||||
case 0x5b: {
|
||||
void sSMP::op_lsr_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
rd = op_lsr(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//rol_dpx
|
||||
case 0x3b: {
|
||||
void sSMP::op_rol_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
rd = op_rol(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//ror_dpx
|
||||
case 0x7b: {
|
||||
void sSMP::op_ror_dpx() {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
rd = op_ror(rd);
|
||||
op_writedp(dp + regs.x, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//inc_addr
|
||||
case 0xac: {
|
||||
void sSMP::op_inc_addr() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
rd = op_inc(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//dec_addr
|
||||
case 0x8c: {
|
||||
void sSMP::op_dec_addr() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
rd = op_dec(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//asl_addr
|
||||
case 0x0c: {
|
||||
void sSMP::op_asl_addr() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
rd = op_asl(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//lsr_addr
|
||||
case 0x4c: {
|
||||
void sSMP::op_lsr_addr() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
rd = op_lsr(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//rol_addr
|
||||
case 0x2c: {
|
||||
void sSMP::op_rol_addr() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
rd = op_rol(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//ror_addr
|
||||
case 0x6c: {
|
||||
void sSMP::op_ror_addr() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
rd = op_ror(rd);
|
||||
op_writeaddr(dp, rd);
|
||||
} break;
|
||||
}
|
||||
|
||||
//incw_dp
|
||||
case 0x3a: {
|
||||
void sSMP::op_tset_addr_a() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.p.n = !!((regs.a - rd) & 0x80);
|
||||
regs.p.z = ((regs.a - rd) == 0);
|
||||
op_readaddr(dp);
|
||||
op_writeaddr(dp, rd | regs.a);
|
||||
}
|
||||
|
||||
void sSMP::op_tclr_addr_a() {
|
||||
dp = op_readpc();
|
||||
dp |= op_readpc() << 8;
|
||||
rd = op_readaddr(dp);
|
||||
regs.p.n = !!((regs.a - rd) & 0x80);
|
||||
regs.p.z = ((regs.a - rd) == 0);
|
||||
op_readaddr(dp);
|
||||
op_writeaddr(dp, rd &~ regs.a);
|
||||
}
|
||||
|
||||
void sSMP::op_incw_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= op_readdp(dp + 1) << 8;
|
||||
rd = op_incw(rd);
|
||||
op_writedp(dp + 1, rd >> 8);
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
rd = op_readdp(dp);
|
||||
rd++;
|
||||
op_writedp(dp++, rd);
|
||||
rd += op_readdp(dp) << 8;
|
||||
op_write(dp, rd >> 8);
|
||||
regs.p.n = !!(rd & 0x8000);
|
||||
regs.p.z = (rd == 0);
|
||||
}
|
||||
|
||||
//decw_dp
|
||||
case 0x1a: {
|
||||
void sSMP::op_decw_dp() {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd |= op_readdp(dp + 1) << 8;
|
||||
rd = op_decw(rd);
|
||||
op_writedp(dp + 1, rd >> 8);
|
||||
op_writedp(dp, rd);
|
||||
} break;
|
||||
rd = op_readdp(dp);
|
||||
rd--;
|
||||
op_writedp(dp++, rd);
|
||||
rd += op_readdp(dp) << 8;
|
||||
op_write(dp, rd >> 8);
|
||||
regs.p.n = !!(rd & 0x8000);
|
||||
regs.p.z = (rd == 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -80,13 +80,6 @@ uint8 sSMP::op_inc(uint8 x) {
|
|||
return x;
|
||||
}
|
||||
|
||||
uint16 sSMP::op_incw(uint16 x) {
|
||||
x++;
|
||||
regs.p.n = !!(x & 0x8000);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sSMP::op_dec(uint8 x) {
|
||||
x--;
|
||||
regs.p.n = !!(x & 0x80);
|
||||
|
@ -94,13 +87,6 @@ uint8 sSMP::op_dec(uint8 x) {
|
|||
return x;
|
||||
}
|
||||
|
||||
uint16 sSMP::op_decw(uint16 x) {
|
||||
x--;
|
||||
regs.p.n = !!(x & 0x8000);
|
||||
regs.p.z = (x == 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sSMP::op_asl(uint8 x) {
|
||||
regs.p.c = !!(x & 0x80);
|
||||
x <<= 1;
|
||||
|
|
|
@ -0,0 +1,256 @@
|
|||
optbl[0x7d] = &sSMP::op_mov_a_x;
|
||||
optbl[0xdd] = &sSMP::op_mov_a_y;
|
||||
optbl[0x5d] = &sSMP::op_mov_x_a;
|
||||
optbl[0xfd] = &sSMP::op_mov_y_a;
|
||||
optbl[0x9d] = &sSMP::op_mov_x_sp;
|
||||
optbl[0xbd] = &sSMP::op_mov_sp_x;
|
||||
optbl[0xe8] = &sSMP::op_mov_a_const;
|
||||
optbl[0xcd] = &sSMP::op_mov_x_const;
|
||||
optbl[0x8d] = &sSMP::op_mov_y_const;
|
||||
optbl[0xe6] = &sSMP::op_mov_a_ix;
|
||||
optbl[0xbf] = &sSMP::op_mov_a_ixinc;
|
||||
optbl[0xe4] = &sSMP::op_mov_a_dp;
|
||||
optbl[0xf8] = &sSMP::op_mov_x_dp;
|
||||
optbl[0xeb] = &sSMP::op_mov_y_dp;
|
||||
optbl[0xf4] = &sSMP::op_mov_a_dpx;
|
||||
optbl[0xf9] = &sSMP::op_mov_x_dpy;
|
||||
optbl[0xfb] = &sSMP::op_mov_y_dpx;
|
||||
optbl[0xe5] = &sSMP::op_mov_a_addr;
|
||||
optbl[0xe9] = &sSMP::op_mov_x_addr;
|
||||
optbl[0xec] = &sSMP::op_mov_y_addr;
|
||||
optbl[0xf5] = &sSMP::op_mov_a_addrx;
|
||||
optbl[0xf6] = &sSMP::op_mov_a_addry;
|
||||
optbl[0xe7] = &sSMP::op_mov_a_idpx;
|
||||
optbl[0xf7] = &sSMP::op_mov_a_idpy;
|
||||
optbl[0xfa] = &sSMP::op_mov_dp_dp;
|
||||
optbl[0x8f] = &sSMP::op_mov_dp_const;
|
||||
optbl[0xc6] = &sSMP::op_mov_ix_a;
|
||||
optbl[0xaf] = &sSMP::op_mov_ixinc_a;
|
||||
optbl[0xc4] = &sSMP::op_mov_dp_a;
|
||||
optbl[0xd8] = &sSMP::op_mov_dp_x;
|
||||
optbl[0xcb] = &sSMP::op_mov_dp_y;
|
||||
optbl[0xd4] = &sSMP::op_mov_dpx_a;
|
||||
optbl[0xd9] = &sSMP::op_mov_dpy_x;
|
||||
optbl[0xdb] = &sSMP::op_mov_dpx_y;
|
||||
optbl[0xc5] = &sSMP::op_mov_addr_a;
|
||||
optbl[0xc9] = &sSMP::op_mov_addr_x;
|
||||
optbl[0xcc] = &sSMP::op_mov_addr_y;
|
||||
optbl[0xd5] = &sSMP::op_mov_addrx_a;
|
||||
optbl[0xd6] = &sSMP::op_mov_addry_a;
|
||||
optbl[0xc7] = &sSMP::op_mov_idpx_a;
|
||||
optbl[0xd7] = &sSMP::op_mov_idpy_a;
|
||||
optbl[0xba] = &sSMP::op_movw_ya_dp;
|
||||
optbl[0xda] = &sSMP::op_movw_dp_ya;
|
||||
optbl[0xaa] = &sSMP::op_mov1_c_bit;
|
||||
optbl[0xca] = &sSMP::op_mov1_bit_c;
|
||||
optbl[0x2f] = &sSMP::op_bra;
|
||||
optbl[0xf0] = &sSMP::op_beq;
|
||||
optbl[0xd0] = &sSMP::op_bne;
|
||||
optbl[0xb0] = &sSMP::op_bcs;
|
||||
optbl[0x90] = &sSMP::op_bcc;
|
||||
optbl[0x70] = &sSMP::op_bvs;
|
||||
optbl[0x50] = &sSMP::op_bvc;
|
||||
optbl[0x30] = &sSMP::op_bmi;
|
||||
optbl[0x10] = &sSMP::op_bpl;
|
||||
optbl[0x03] = &sSMP::op_bbs0;
|
||||
optbl[0x13] = &sSMP::op_bbc0;
|
||||
optbl[0x23] = &sSMP::op_bbs1;
|
||||
optbl[0x33] = &sSMP::op_bbc1;
|
||||
optbl[0x43] = &sSMP::op_bbs2;
|
||||
optbl[0x53] = &sSMP::op_bbc2;
|
||||
optbl[0x63] = &sSMP::op_bbs3;
|
||||
optbl[0x73] = &sSMP::op_bbc3;
|
||||
optbl[0x83] = &sSMP::op_bbs4;
|
||||
optbl[0x93] = &sSMP::op_bbc4;
|
||||
optbl[0xa3] = &sSMP::op_bbs5;
|
||||
optbl[0xb3] = &sSMP::op_bbc5;
|
||||
optbl[0xc3] = &sSMP::op_bbs6;
|
||||
optbl[0xd3] = &sSMP::op_bbc6;
|
||||
optbl[0xe3] = &sSMP::op_bbs7;
|
||||
optbl[0xf3] = &sSMP::op_bbc7;
|
||||
optbl[0x2e] = &sSMP::op_cbne_dp;
|
||||
optbl[0xde] = &sSMP::op_cbne_dpx;
|
||||
optbl[0x6e] = &sSMP::op_dbnz_dp;
|
||||
optbl[0xfe] = &sSMP::op_dbnz_y;
|
||||
optbl[0x5f] = &sSMP::op_jmp_addr;
|
||||
optbl[0x1f] = &sSMP::op_jmp_iaddrx;
|
||||
optbl[0x3f] = &sSMP::op_call;
|
||||
optbl[0x4f] = &sSMP::op_pcall;
|
||||
optbl[0x01] = &sSMP::op_tcall_0;
|
||||
optbl[0x11] = &sSMP::op_tcall_1;
|
||||
optbl[0x21] = &sSMP::op_tcall_2;
|
||||
optbl[0x31] = &sSMP::op_tcall_3;
|
||||
optbl[0x41] = &sSMP::op_tcall_4;
|
||||
optbl[0x51] = &sSMP::op_tcall_5;
|
||||
optbl[0x61] = &sSMP::op_tcall_6;
|
||||
optbl[0x71] = &sSMP::op_tcall_7;
|
||||
optbl[0x81] = &sSMP::op_tcall_8;
|
||||
optbl[0x91] = &sSMP::op_tcall_9;
|
||||
optbl[0xa1] = &sSMP::op_tcall_10;
|
||||
optbl[0xb1] = &sSMP::op_tcall_11;
|
||||
optbl[0xc1] = &sSMP::op_tcall_12;
|
||||
optbl[0xd1] = &sSMP::op_tcall_13;
|
||||
optbl[0xe1] = &sSMP::op_tcall_14;
|
||||
optbl[0xf1] = &sSMP::op_tcall_15;
|
||||
optbl[0x0f] = &sSMP::op_brk;
|
||||
optbl[0x6f] = &sSMP::op_ret;
|
||||
optbl[0x7f] = &sSMP::op_reti;
|
||||
optbl[0x88] = &sSMP::op_adc_a_const;
|
||||
optbl[0x28] = &sSMP::op_and_a_const;
|
||||
optbl[0x68] = &sSMP::op_cmp_a_const;
|
||||
optbl[0xc8] = &sSMP::op_cmp_x_const;
|
||||
optbl[0xad] = &sSMP::op_cmp_y_const;
|
||||
optbl[0x48] = &sSMP::op_eor_a_const;
|
||||
optbl[0x08] = &sSMP::op_or_a_const;
|
||||
optbl[0xa8] = &sSMP::op_sbc_a_const;
|
||||
optbl[0x86] = &sSMP::op_adc_a_ix;
|
||||
optbl[0x26] = &sSMP::op_and_a_ix;
|
||||
optbl[0x66] = &sSMP::op_cmp_a_ix;
|
||||
optbl[0x46] = &sSMP::op_eor_a_ix;
|
||||
optbl[0x06] = &sSMP::op_or_a_ix;
|
||||
optbl[0xa6] = &sSMP::op_sbc_a_ix;
|
||||
optbl[0x84] = &sSMP::op_adc_a_dp;
|
||||
optbl[0x24] = &sSMP::op_and_a_dp;
|
||||
optbl[0x64] = &sSMP::op_cmp_a_dp;
|
||||
optbl[0x3e] = &sSMP::op_cmp_x_dp;
|
||||
optbl[0x7e] = &sSMP::op_cmp_y_dp;
|
||||
optbl[0x44] = &sSMP::op_eor_a_dp;
|
||||
optbl[0x04] = &sSMP::op_or_a_dp;
|
||||
optbl[0xa4] = &sSMP::op_sbc_a_dp;
|
||||
optbl[0x94] = &sSMP::op_adc_a_dpx;
|
||||
optbl[0x34] = &sSMP::op_and_a_dpx;
|
||||
optbl[0x74] = &sSMP::op_cmp_a_dpx;
|
||||
optbl[0x54] = &sSMP::op_eor_a_dpx;
|
||||
optbl[0x14] = &sSMP::op_or_a_dpx;
|
||||
optbl[0xb4] = &sSMP::op_sbc_a_dpx;
|
||||
optbl[0x85] = &sSMP::op_adc_a_addr;
|
||||
optbl[0x25] = &sSMP::op_and_a_addr;
|
||||
optbl[0x65] = &sSMP::op_cmp_a_addr;
|
||||
optbl[0x1e] = &sSMP::op_cmp_x_addr;
|
||||
optbl[0x5e] = &sSMP::op_cmp_y_addr;
|
||||
optbl[0x45] = &sSMP::op_eor_a_addr;
|
||||
optbl[0x05] = &sSMP::op_or_a_addr;
|
||||
optbl[0xa5] = &sSMP::op_sbc_a_addr;
|
||||
optbl[0x95] = &sSMP::op_adc_a_addrx;
|
||||
optbl[0x96] = &sSMP::op_adc_a_addry;
|
||||
optbl[0x35] = &sSMP::op_and_a_addrx;
|
||||
optbl[0x36] = &sSMP::op_and_a_addry;
|
||||
optbl[0x75] = &sSMP::op_cmp_a_addrx;
|
||||
optbl[0x76] = &sSMP::op_cmp_a_addry;
|
||||
optbl[0x55] = &sSMP::op_eor_a_addrx;
|
||||
optbl[0x56] = &sSMP::op_eor_a_addry;
|
||||
optbl[0x15] = &sSMP::op_or_a_addrx;
|
||||
optbl[0x16] = &sSMP::op_or_a_addry;
|
||||
optbl[0xb5] = &sSMP::op_sbc_a_addrx;
|
||||
optbl[0xb6] = &sSMP::op_sbc_a_addry;
|
||||
optbl[0x87] = &sSMP::op_adc_a_idpx;
|
||||
optbl[0x27] = &sSMP::op_and_a_idpx;
|
||||
optbl[0x67] = &sSMP::op_cmp_a_idpx;
|
||||
optbl[0x47] = &sSMP::op_eor_a_idpx;
|
||||
optbl[0x07] = &sSMP::op_or_a_idpx;
|
||||
optbl[0xa7] = &sSMP::op_sbc_a_idpx;
|
||||
optbl[0x97] = &sSMP::op_adc_a_idpy;
|
||||
optbl[0x37] = &sSMP::op_and_a_idpy;
|
||||
optbl[0x77] = &sSMP::op_cmp_a_idpy;
|
||||
optbl[0x57] = &sSMP::op_eor_a_idpy;
|
||||
optbl[0x17] = &sSMP::op_or_a_idpy;
|
||||
optbl[0xb7] = &sSMP::op_sbc_a_idpy;
|
||||
optbl[0x99] = &sSMP::op_adc_ix_iy;
|
||||
optbl[0x39] = &sSMP::op_and_ix_iy;
|
||||
optbl[0x79] = &sSMP::op_cmp_ix_iy;
|
||||
optbl[0x59] = &sSMP::op_eor_ix_iy;
|
||||
optbl[0x19] = &sSMP::op_or_ix_iy;
|
||||
optbl[0xb9] = &sSMP::op_sbc_ix_iy;
|
||||
optbl[0x89] = &sSMP::op_adc_dp_dp;
|
||||
optbl[0x29] = &sSMP::op_and_dp_dp;
|
||||
optbl[0x69] = &sSMP::op_cmp_dp_dp;
|
||||
optbl[0x49] = &sSMP::op_eor_dp_dp;
|
||||
optbl[0x09] = &sSMP::op_or_dp_dp;
|
||||
optbl[0xa9] = &sSMP::op_sbc_dp_dp;
|
||||
optbl[0x98] = &sSMP::op_adc_dp_const;
|
||||
optbl[0x38] = &sSMP::op_and_dp_const;
|
||||
optbl[0x78] = &sSMP::op_cmp_dp_const;
|
||||
optbl[0x58] = &sSMP::op_eor_dp_const;
|
||||
optbl[0x18] = &sSMP::op_or_dp_const;
|
||||
optbl[0xb8] = &sSMP::op_sbc_dp_const;
|
||||
optbl[0x7a] = &sSMP::op_addw_ya_dp;
|
||||
optbl[0x9a] = &sSMP::op_subw_ya_dp;
|
||||
optbl[0x5a] = &sSMP::op_cmpw_ya_dp;
|
||||
optbl[0x4a] = &sSMP::op_and1_bit;
|
||||
optbl[0x6a] = &sSMP::op_and1_notbit;
|
||||
optbl[0x8a] = &sSMP::op_eor1_bit;
|
||||
optbl[0xea] = &sSMP::op_not1_bit;
|
||||
optbl[0x0a] = &sSMP::op_or1_bit;
|
||||
optbl[0x2a] = &sSMP::op_or1_notbit;
|
||||
optbl[0xbc] = &sSMP::op_inc_a;
|
||||
optbl[0x3d] = &sSMP::op_inc_x;
|
||||
optbl[0xfc] = &sSMP::op_inc_y;
|
||||
optbl[0x9c] = &sSMP::op_dec_a;
|
||||
optbl[0x1d] = &sSMP::op_dec_x;
|
||||
optbl[0xdc] = &sSMP::op_dec_y;
|
||||
optbl[0x1c] = &sSMP::op_asl_a;
|
||||
optbl[0x5c] = &sSMP::op_lsr_a;
|
||||
optbl[0x3c] = &sSMP::op_rol_a;
|
||||
optbl[0x7c] = &sSMP::op_ror_a;
|
||||
optbl[0xab] = &sSMP::op_inc_dp;
|
||||
optbl[0x8b] = &sSMP::op_dec_dp;
|
||||
optbl[0x0b] = &sSMP::op_asl_dp;
|
||||
optbl[0x4b] = &sSMP::op_lsr_dp;
|
||||
optbl[0x2b] = &sSMP::op_rol_dp;
|
||||
optbl[0x6b] = &sSMP::op_ror_dp;
|
||||
optbl[0xbb] = &sSMP::op_inc_dpx;
|
||||
optbl[0x9b] = &sSMP::op_dec_dpx;
|
||||
optbl[0x1b] = &sSMP::op_asl_dpx;
|
||||
optbl[0x5b] = &sSMP::op_lsr_dpx;
|
||||
optbl[0x3b] = &sSMP::op_rol_dpx;
|
||||
optbl[0x7b] = &sSMP::op_ror_dpx;
|
||||
optbl[0xac] = &sSMP::op_inc_addr;
|
||||
optbl[0x8c] = &sSMP::op_dec_addr;
|
||||
optbl[0x0c] = &sSMP::op_asl_addr;
|
||||
optbl[0x4c] = &sSMP::op_lsr_addr;
|
||||
optbl[0x2c] = &sSMP::op_rol_addr;
|
||||
optbl[0x6c] = &sSMP::op_ror_addr;
|
||||
optbl[0x0e] = &sSMP::op_tset_addr_a;
|
||||
optbl[0x4e] = &sSMP::op_tclr_addr_a;
|
||||
optbl[0x3a] = &sSMP::op_incw_dp;
|
||||
optbl[0x1a] = &sSMP::op_decw_dp;
|
||||
optbl[0x00] = &sSMP::op_nop;
|
||||
optbl[0xef] = &sSMP::op_sleep;
|
||||
optbl[0xff] = &sSMP::op_stop;
|
||||
optbl[0x9f] = &sSMP::op_xcn;
|
||||
optbl[0xdf] = &sSMP::op_daa;
|
||||
optbl[0xbe] = &sSMP::op_das;
|
||||
optbl[0x60] = &sSMP::op_clrc;
|
||||
optbl[0x20] = &sSMP::op_clrp;
|
||||
optbl[0x80] = &sSMP::op_setc;
|
||||
optbl[0x40] = &sSMP::op_setp;
|
||||
optbl[0xe0] = &sSMP::op_clrv;
|
||||
optbl[0xed] = &sSMP::op_notc;
|
||||
optbl[0xa0] = &sSMP::op_ei;
|
||||
optbl[0xc0] = &sSMP::op_di;
|
||||
optbl[0x02] = &sSMP::op_set0_dp;
|
||||
optbl[0x12] = &sSMP::op_clr0_dp;
|
||||
optbl[0x22] = &sSMP::op_set1_dp;
|
||||
optbl[0x32] = &sSMP::op_clr1_dp;
|
||||
optbl[0x42] = &sSMP::op_set2_dp;
|
||||
optbl[0x52] = &sSMP::op_clr2_dp;
|
||||
optbl[0x62] = &sSMP::op_set3_dp;
|
||||
optbl[0x72] = &sSMP::op_clr3_dp;
|
||||
optbl[0x82] = &sSMP::op_set4_dp;
|
||||
optbl[0x92] = &sSMP::op_clr4_dp;
|
||||
optbl[0xa2] = &sSMP::op_set5_dp;
|
||||
optbl[0xb2] = &sSMP::op_clr5_dp;
|
||||
optbl[0xc2] = &sSMP::op_set6_dp;
|
||||
optbl[0xd2] = &sSMP::op_clr6_dp;
|
||||
optbl[0xe2] = &sSMP::op_set7_dp;
|
||||
optbl[0xf2] = &sSMP::op_clr7_dp;
|
||||
optbl[0x2d] = &sSMP::op_push_a;
|
||||
optbl[0x4d] = &sSMP::op_push_x;
|
||||
optbl[0x6d] = &sSMP::op_push_y;
|
||||
optbl[0x0d] = &sSMP::op_push_p;
|
||||
optbl[0xae] = &sSMP::op_pop_a;
|
||||
optbl[0xce] = &sSMP::op_pop_x;
|
||||
optbl[0xee] = &sSMP::op_pop_y;
|
||||
optbl[0x8e] = &sSMP::op_pop_p;
|
||||
optbl[0xcf] = &sSMP::op_mul_ya;
|
||||
optbl[0x9e] = &sSMP::op_div_ya_x;
|
|
@ -1,9 +1,9 @@
|
|||
#define CLASS_NAME "sSMP"
|
||||
#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_mov.cpp", "op_mov.b");
|
||||
generate("op_pc.cpp", "op_pc.b");
|
||||
|
@ -11,8 +11,8 @@ int main() {
|
|||
generate("op_rmw.cpp", "op_rmw.b");
|
||||
generate("op_misc.cpp", "op_misc.b");
|
||||
|
||||
//fclose(fph);
|
||||
//fclose(fpt);
|
||||
fclose(fph);
|
||||
fclose(fpt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -57,9 +57,12 @@ uint8 r;
|
|||
r = r_cpu->port_read(addr & 3);
|
||||
} break;
|
||||
|
||||
case 0xf8: //???
|
||||
case 0xf9: { //??? -- Mapped to SPCRAM
|
||||
r = ram_read(addr);
|
||||
case 0xf8: { //???
|
||||
r = status.smp_f8;
|
||||
} break;
|
||||
|
||||
case 0xf9: { //???
|
||||
r = status.smp_f9;
|
||||
} break;
|
||||
|
||||
case 0xfa: //T0TARGET
|
||||
|
@ -108,8 +111,9 @@ void sSMP::op_buswrite(uint16 addr, uint8 data) {
|
|||
case 0xf0: { //TEST
|
||||
if(regs.p.p)break; //writes only valid when P flag clear
|
||||
|
||||
//multiplier table may not be 100% accurate, some settings crash
|
||||
//the processor due to S-SMP <> S-DSP bus access misalignment
|
||||
static uint8 clock_speed_tbl[16] =
|
||||
//multiplier table may not be 100% accurate, some settings crash the processor
|
||||
{ 3, 5, 9, 17, 4, 6, 10, 18, 6, 8, 12, 20, 10, 12, 16, 24 };
|
||||
|
||||
status.clock_speed = 24 * clock_speed_tbl[data >> 4] / 3;
|
||||
|
@ -166,7 +170,7 @@ void sSMP::op_buswrite(uint16 addr, uint8 data) {
|
|||
|
||||
case 0xf3: { //DSPDATA
|
||||
//0x80-0xff is a read-only mirror of 0x00-0x7f
|
||||
if(status.dsp_addr < 0x80) {
|
||||
if(!(status.dsp_addr & 0x80)) {
|
||||
r_dsp->write(status.dsp_addr & 0x7f, data);
|
||||
}
|
||||
} break;
|
||||
|
@ -179,10 +183,12 @@ void sSMP::op_buswrite(uint16 addr, uint8 data) {
|
|||
port_write(addr & 3, data);
|
||||
} break;
|
||||
|
||||
case 0xf8: //???
|
||||
case 0xf9: { //??? - Mapped to SPCRAM
|
||||
//$00f1.d1 (ram_writable) has no effect on these two addresses
|
||||
ram_write(addr, data);
|
||||
case 0xf8: { //???
|
||||
status.smp_f8 = data;
|
||||
} break;
|
||||
|
||||
case 0xf9: { //???
|
||||
status.smp_f9 = data;
|
||||
} break;
|
||||
|
||||
case 0xfa: { //T0TARGET
|
||||
|
@ -203,7 +209,10 @@ void sSMP::op_buswrite(uint16 addr, uint8 data) {
|
|||
} break;
|
||||
|
||||
}
|
||||
} else if(status.ram_writable == true) {
|
||||
}
|
||||
|
||||
//all writes, even to MMIO registers, appear on bus
|
||||
if(status.ram_writable == true) {
|
||||
ram_write(addr, data);
|
||||
}
|
||||
}
|
||||
|
@ -211,19 +220,22 @@ void sSMP::op_buswrite(uint16 addr, uint8 data) {
|
|||
//
|
||||
|
||||
void sSMP::op_io() {
|
||||
add_clocks(status.clock_speed);
|
||||
add_clocks(24);
|
||||
tick_timers();
|
||||
}
|
||||
|
||||
uint8 sSMP::op_read(uint16 addr) {
|
||||
add_clocks(status.clock_speed >> 1);
|
||||
add_clocks(12);
|
||||
uint8 r = op_busread(addr);
|
||||
add_clocks(status.clock_speed >> 1);
|
||||
add_clocks(12);
|
||||
tick_timers();
|
||||
return r;
|
||||
}
|
||||
|
||||
void sSMP::op_write(uint16 addr, uint8 data) {
|
||||
add_clocks(status.clock_speed);
|
||||
add_clocks(24);
|
||||
op_buswrite(addr, data);
|
||||
tick_timers();
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -255,10 +267,10 @@ void sSMP::op_writeaddr(uint16 addr, uint8 data) {
|
|||
|
||||
alwaysinline
|
||||
uint8 sSMP::op_readdp(uint8 addr) {
|
||||
return op_read(((uint)regs.p.p << 8) + addr);
|
||||
return op_read((uint(regs.p.p) << 8) + addr);
|
||||
}
|
||||
|
||||
alwaysinline
|
||||
void sSMP::op_writedp(uint8 addr, uint8 data) {
|
||||
op_write(((uint)regs.p.p << 8) + addr, data);
|
||||
op_write((uint(regs.p.p) << 8) + addr, data);
|
||||
}
|
||||
|
|
|
@ -42,6 +42,10 @@ void sSMP::reset() {
|
|||
//$00f2
|
||||
status.dsp_addr = 0x00;
|
||||
|
||||
//$00f8,$00f9
|
||||
status.smp_f8 = 0x00;
|
||||
status.smp_f9 = 0x00;
|
||||
|
||||
t0.enabled = false;
|
||||
t1.enabled = false;
|
||||
t2.enabled = false;
|
||||
|
@ -59,5 +63,9 @@ void sSMP::reset() {
|
|||
t2.stage3_ticks = 0;
|
||||
}
|
||||
|
||||
sSMP::sSMP() {}
|
||||
sSMP::~sSMP() {}
|
||||
sSMP::sSMP() {
|
||||
#include "core/optable.cpp"
|
||||
}
|
||||
|
||||
sSMP::~sSMP() {
|
||||
}
|
||||
|
|
|
@ -25,6 +25,9 @@ struct {
|
|||
|
||||
//$00f2
|
||||
uint8 dsp_addr;
|
||||
|
||||
//$00f8,$00f9
|
||||
uint8 smp_f8, smp_f9;
|
||||
} status;
|
||||
|
||||
//ssmp.cpp
|
||||
|
|
|
@ -1,21 +1,11 @@
|
|||
alwaysinline void sSMP::add_clocks(uint clocks) {
|
||||
alwaysinline
|
||||
void sSMP::add_clocks(uint clocks) {
|
||||
scheduler.addclocks_smp(clocks);
|
||||
|
||||
status.clock_counter += clocks;
|
||||
|
||||
//update timers
|
||||
while(status.clock_counter >= 24) {
|
||||
status.clock_counter -= 24;
|
||||
t0.tick();
|
||||
t1.tick();
|
||||
t2.tick();
|
||||
|
||||
//24 * 32 = 768 clocks/DSP tick
|
||||
//1024000 / 768 = 32000 DSP ticks/second
|
||||
if(++status.dsp_counter == 32) {
|
||||
status.dsp_counter = 0;
|
||||
uint32 sample = r_dsp->run();
|
||||
snes.audio_update( (sample & 0xffff), (sample >> 16) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
alwaysinline
|
||||
void sSMP::tick_timers() {
|
||||
t0.tick();
|
||||
t1.tick();
|
||||
t2.tick();
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue