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:
byuu 2007-06-03 00:20:00 +00:00
parent 5c3c872b78
commit 2cc7fe30b4
191 changed files with 10418 additions and 6887 deletions

BIN
bsnes.exe

Binary file not shown.

BIN
cart.db

Binary file not shown.

View File

@ -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.

View File

@ -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)

View File

@ -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 ###

View File

@ -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 {

Binary file not shown.

View File

@ -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"

View File

@ -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);

View File

@ -1,3 +1,3 @@
@make -r PLATFORM=win-visualc
@make -r PLATFORM=win-visualc-lui
@move bsnes.exe ../bsnes.exe>nul
@pause

View File

@ -1,2 +1,2 @@
#!/bin/sh
gmake PLATFORM=x-gcc-lui
make PLATFORM=x-gcc-lui

View File

@ -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);

View File

@ -28,6 +28,7 @@ understood.
************************************************************************/
typedef uint8_t bool8;
class SDD1_IM { //Input Manager

View File

@ -1 +1 @@
@make PLATFORM=win-visualc clean
@make PLATFORM=win-visualc-lui clean

View File

@ -1,2 +1,2 @@
#!/bin/sh
gmake PLATFORM=x-gcc-lui clean
make PLATFORM=x-gcc-lui clean

View File

@ -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);
};

View File

@ -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;
};

View File

@ -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);
};
};

View File

@ -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() {

View File

@ -1,4 +1,4 @@
//void (sCPU::*optbl[256])();
void (sCPU::*optbl[256])();
CPUReg24 aa, rd;
uint8 dp, sp;
@ -54,4 +54,4 @@ uint8 dp, sp;
void op_io_cond4(uint16 x, uint16 y);
void op_io_cond6(uint16 addr);
//#include "op.h"
#include "op.h"

256
src/cpu/scpu/core/op.h Normal file
View File

@ -0,0 +1,256 @@
void op_adc_const();
void op_and_const();
void op_cmp_const();
void op_cpx_const();
void op_cpy_const();
void op_eor_const();
void op_lda_const();
void op_ldx_const();
void op_ldy_const();
void op_ora_const();
void op_sbc_const();
void op_adc_addr();
void op_and_addr();
void op_bit_addr();
void op_cmp_addr();
void op_cpx_addr();
void op_cpy_addr();
void op_eor_addr();
void op_lda_addr();
void op_ldx_addr();
void op_ldy_addr();
void op_ora_addr();
void op_sbc_addr();
void op_adc_addrx();
void op_and_addrx();
void op_bit_addrx();
void op_cmp_addrx();
void op_eor_addrx();
void op_lda_addrx();
void op_ldy_addrx();
void op_ora_addrx();
void op_sbc_addrx();
void op_adc_addry();
void op_and_addry();
void op_cmp_addry();
void op_eor_addry();
void op_lda_addry();
void op_ldx_addry();
void op_ora_addry();
void op_sbc_addry();
void op_adc_long();
void op_and_long();
void op_cmp_long();
void op_eor_long();
void op_lda_long();
void op_ora_long();
void op_sbc_long();
void op_adc_longx();
void op_and_longx();
void op_cmp_longx();
void op_eor_longx();
void op_lda_longx();
void op_ora_longx();
void op_sbc_longx();
void op_adc_dp();
void op_and_dp();
void op_bit_dp();
void op_cmp_dp();
void op_cpx_dp();
void op_cpy_dp();
void op_eor_dp();
void op_lda_dp();
void op_ldx_dp();
void op_ldy_dp();
void op_ora_dp();
void op_sbc_dp();
void op_adc_dpx();
void op_and_dpx();
void op_bit_dpx();
void op_cmp_dpx();
void op_eor_dpx();
void op_lda_dpx();
void op_ldy_dpx();
void op_ora_dpx();
void op_sbc_dpx();
void op_ldx_dpy();
void op_adc_idp();
void op_and_idp();
void op_cmp_idp();
void op_eor_idp();
void op_lda_idp();
void op_ora_idp();
void op_sbc_idp();
void op_adc_idpx();
void op_and_idpx();
void op_cmp_idpx();
void op_eor_idpx();
void op_lda_idpx();
void op_ora_idpx();
void op_sbc_idpx();
void op_adc_idpy();
void op_and_idpy();
void op_cmp_idpy();
void op_eor_idpy();
void op_lda_idpy();
void op_ora_idpy();
void op_sbc_idpy();
void op_adc_ildp();
void op_and_ildp();
void op_cmp_ildp();
void op_eor_ildp();
void op_lda_ildp();
void op_ora_ildp();
void op_sbc_ildp();
void op_adc_ildpy();
void op_and_ildpy();
void op_cmp_ildpy();
void op_eor_ildpy();
void op_lda_ildpy();
void op_ora_ildpy();
void op_sbc_ildpy();
void op_adc_sr();
void op_and_sr();
void op_cmp_sr();
void op_eor_sr();
void op_lda_sr();
void op_ora_sr();
void op_sbc_sr();
void op_adc_isry();
void op_and_isry();
void op_cmp_isry();
void op_eor_isry();
void op_lda_isry();
void op_ora_isry();
void op_sbc_isry();
void op_bit_const();
void op_sta_addr();
void op_stx_addr();
void op_sty_addr();
void op_stz_addr();
void op_sta_addrx();
void op_stz_addrx();
void op_sta_addry();
void op_sta_long();
void op_sta_longx();
void op_sta_dp();
void op_stx_dp();
void op_sty_dp();
void op_stz_dp();
void op_sta_dpx();
void op_sty_dpx();
void op_stz_dpx();
void op_stx_dpy();
void op_sta_idp();
void op_sta_ildp();
void op_sta_idpx();
void op_sta_idpy();
void op_sta_ildpy();
void op_sta_sr();
void op_sta_isry();
void op_inc();
void op_inx();
void op_iny();
void op_dec();
void op_dex();
void op_dey();
void op_asl();
void op_lsr();
void op_rol();
void op_ror();
void op_inc_addr();
void op_dec_addr();
void op_asl_addr();
void op_lsr_addr();
void op_rol_addr();
void op_ror_addr();
void op_trb_addr();
void op_tsb_addr();
void op_inc_addrx();
void op_dec_addrx();
void op_asl_addrx();
void op_lsr_addrx();
void op_rol_addrx();
void op_ror_addrx();
void op_inc_dp();
void op_dec_dp();
void op_asl_dp();
void op_lsr_dp();
void op_rol_dp();
void op_ror_dp();
void op_trb_dp();
void op_tsb_dp();
void op_inc_dpx();
void op_dec_dpx();
void op_asl_dpx();
void op_lsr_dpx();
void op_rol_dpx();
void op_ror_dpx();
void op_bcc();
void op_bcs();
void op_bne();
void op_beq();
void op_bpl();
void op_bmi();
void op_bvc();
void op_bvs();
void op_bra();
void op_brl();
void op_jmp_addr();
void op_jmp_long();
void op_jmp_iaddr();
void op_jmp_iaddrx();
void op_jmp_iladdr();
void op_jsr_addr();
void op_jsr_long();
void op_jsr_iaddrx();
void op_rti();
void op_rts();
void op_rtl();
void op_nop();
void op_wdm();
void op_xba();
void op_mvn();
void op_mvp();
void op_brk();
void op_cop();
void op_stp();
void op_wai();
void op_xce();
void op_clc();
void op_cld();
void op_cli();
void op_clv();
void op_sec();
void op_sed();
void op_sei();
void op_rep();
void op_sep();
void op_tax();
void op_tay();
void op_txa();
void op_txy();
void op_tya();
void op_tyx();
void op_tcd();
void op_tcs();
void op_tdc();
void op_tsc();
void op_tsx();
void op_txs();
void op_pha();
void op_phx();
void op_phy();
void op_phd();
void op_phb();
void op_phk();
void op_php();
void op_pla();
void op_plx();
void op_ply();
void op_pld();
void op_plb();
void op_plp();
void op_pea();
void op_pei();
void op_per();

View File

@ -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) {

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -0,0 +1,256 @@
optbl[0x69] = &sCPU::op_adc_const;
optbl[0x29] = &sCPU::op_and_const;
optbl[0xc9] = &sCPU::op_cmp_const;
optbl[0xe0] = &sCPU::op_cpx_const;
optbl[0xc0] = &sCPU::op_cpy_const;
optbl[0x49] = &sCPU::op_eor_const;
optbl[0xa9] = &sCPU::op_lda_const;
optbl[0xa2] = &sCPU::op_ldx_const;
optbl[0xa0] = &sCPU::op_ldy_const;
optbl[0x09] = &sCPU::op_ora_const;
optbl[0xe9] = &sCPU::op_sbc_const;
optbl[0x6d] = &sCPU::op_adc_addr;
optbl[0x2d] = &sCPU::op_and_addr;
optbl[0x2c] = &sCPU::op_bit_addr;
optbl[0xcd] = &sCPU::op_cmp_addr;
optbl[0xec] = &sCPU::op_cpx_addr;
optbl[0xcc] = &sCPU::op_cpy_addr;
optbl[0x4d] = &sCPU::op_eor_addr;
optbl[0xad] = &sCPU::op_lda_addr;
optbl[0xae] = &sCPU::op_ldx_addr;
optbl[0xac] = &sCPU::op_ldy_addr;
optbl[0x0d] = &sCPU::op_ora_addr;
optbl[0xed] = &sCPU::op_sbc_addr;
optbl[0x7d] = &sCPU::op_adc_addrx;
optbl[0x3d] = &sCPU::op_and_addrx;
optbl[0x3c] = &sCPU::op_bit_addrx;
optbl[0xdd] = &sCPU::op_cmp_addrx;
optbl[0x5d] = &sCPU::op_eor_addrx;
optbl[0xbd] = &sCPU::op_lda_addrx;
optbl[0xbc] = &sCPU::op_ldy_addrx;
optbl[0x1d] = &sCPU::op_ora_addrx;
optbl[0xfd] = &sCPU::op_sbc_addrx;
optbl[0x79] = &sCPU::op_adc_addry;
optbl[0x39] = &sCPU::op_and_addry;
optbl[0xd9] = &sCPU::op_cmp_addry;
optbl[0x59] = &sCPU::op_eor_addry;
optbl[0xb9] = &sCPU::op_lda_addry;
optbl[0xbe] = &sCPU::op_ldx_addry;
optbl[0x19] = &sCPU::op_ora_addry;
optbl[0xf9] = &sCPU::op_sbc_addry;
optbl[0x6f] = &sCPU::op_adc_long;
optbl[0x2f] = &sCPU::op_and_long;
optbl[0xcf] = &sCPU::op_cmp_long;
optbl[0x4f] = &sCPU::op_eor_long;
optbl[0xaf] = &sCPU::op_lda_long;
optbl[0x0f] = &sCPU::op_ora_long;
optbl[0xef] = &sCPU::op_sbc_long;
optbl[0x7f] = &sCPU::op_adc_longx;
optbl[0x3f] = &sCPU::op_and_longx;
optbl[0xdf] = &sCPU::op_cmp_longx;
optbl[0x5f] = &sCPU::op_eor_longx;
optbl[0xbf] = &sCPU::op_lda_longx;
optbl[0x1f] = &sCPU::op_ora_longx;
optbl[0xff] = &sCPU::op_sbc_longx;
optbl[0x65] = &sCPU::op_adc_dp;
optbl[0x25] = &sCPU::op_and_dp;
optbl[0x24] = &sCPU::op_bit_dp;
optbl[0xc5] = &sCPU::op_cmp_dp;
optbl[0xe4] = &sCPU::op_cpx_dp;
optbl[0xc4] = &sCPU::op_cpy_dp;
optbl[0x45] = &sCPU::op_eor_dp;
optbl[0xa5] = &sCPU::op_lda_dp;
optbl[0xa6] = &sCPU::op_ldx_dp;
optbl[0xa4] = &sCPU::op_ldy_dp;
optbl[0x05] = &sCPU::op_ora_dp;
optbl[0xe5] = &sCPU::op_sbc_dp;
optbl[0x75] = &sCPU::op_adc_dpx;
optbl[0x35] = &sCPU::op_and_dpx;
optbl[0x34] = &sCPU::op_bit_dpx;
optbl[0xd5] = &sCPU::op_cmp_dpx;
optbl[0x55] = &sCPU::op_eor_dpx;
optbl[0xb5] = &sCPU::op_lda_dpx;
optbl[0xb4] = &sCPU::op_ldy_dpx;
optbl[0x15] = &sCPU::op_ora_dpx;
optbl[0xf5] = &sCPU::op_sbc_dpx;
optbl[0xb6] = &sCPU::op_ldx_dpy;
optbl[0x72] = &sCPU::op_adc_idp;
optbl[0x32] = &sCPU::op_and_idp;
optbl[0xd2] = &sCPU::op_cmp_idp;
optbl[0x52] = &sCPU::op_eor_idp;
optbl[0xb2] = &sCPU::op_lda_idp;
optbl[0x12] = &sCPU::op_ora_idp;
optbl[0xf2] = &sCPU::op_sbc_idp;
optbl[0x61] = &sCPU::op_adc_idpx;
optbl[0x21] = &sCPU::op_and_idpx;
optbl[0xc1] = &sCPU::op_cmp_idpx;
optbl[0x41] = &sCPU::op_eor_idpx;
optbl[0xa1] = &sCPU::op_lda_idpx;
optbl[0x01] = &sCPU::op_ora_idpx;
optbl[0xe1] = &sCPU::op_sbc_idpx;
optbl[0x71] = &sCPU::op_adc_idpy;
optbl[0x31] = &sCPU::op_and_idpy;
optbl[0xd1] = &sCPU::op_cmp_idpy;
optbl[0x51] = &sCPU::op_eor_idpy;
optbl[0xb1] = &sCPU::op_lda_idpy;
optbl[0x11] = &sCPU::op_ora_idpy;
optbl[0xf1] = &sCPU::op_sbc_idpy;
optbl[0x67] = &sCPU::op_adc_ildp;
optbl[0x27] = &sCPU::op_and_ildp;
optbl[0xc7] = &sCPU::op_cmp_ildp;
optbl[0x47] = &sCPU::op_eor_ildp;
optbl[0xa7] = &sCPU::op_lda_ildp;
optbl[0x07] = &sCPU::op_ora_ildp;
optbl[0xe7] = &sCPU::op_sbc_ildp;
optbl[0x77] = &sCPU::op_adc_ildpy;
optbl[0x37] = &sCPU::op_and_ildpy;
optbl[0xd7] = &sCPU::op_cmp_ildpy;
optbl[0x57] = &sCPU::op_eor_ildpy;
optbl[0xb7] = &sCPU::op_lda_ildpy;
optbl[0x17] = &sCPU::op_ora_ildpy;
optbl[0xf7] = &sCPU::op_sbc_ildpy;
optbl[0x63] = &sCPU::op_adc_sr;
optbl[0x23] = &sCPU::op_and_sr;
optbl[0xc3] = &sCPU::op_cmp_sr;
optbl[0x43] = &sCPU::op_eor_sr;
optbl[0xa3] = &sCPU::op_lda_sr;
optbl[0x03] = &sCPU::op_ora_sr;
optbl[0xe3] = &sCPU::op_sbc_sr;
optbl[0x73] = &sCPU::op_adc_isry;
optbl[0x33] = &sCPU::op_and_isry;
optbl[0xd3] = &sCPU::op_cmp_isry;
optbl[0x53] = &sCPU::op_eor_isry;
optbl[0xb3] = &sCPU::op_lda_isry;
optbl[0x13] = &sCPU::op_ora_isry;
optbl[0xf3] = &sCPU::op_sbc_isry;
optbl[0x89] = &sCPU::op_bit_const;
optbl[0x8d] = &sCPU::op_sta_addr;
optbl[0x8e] = &sCPU::op_stx_addr;
optbl[0x8c] = &sCPU::op_sty_addr;
optbl[0x9c] = &sCPU::op_stz_addr;
optbl[0x9d] = &sCPU::op_sta_addrx;
optbl[0x9e] = &sCPU::op_stz_addrx;
optbl[0x99] = &sCPU::op_sta_addry;
optbl[0x8f] = &sCPU::op_sta_long;
optbl[0x9f] = &sCPU::op_sta_longx;
optbl[0x85] = &sCPU::op_sta_dp;
optbl[0x86] = &sCPU::op_stx_dp;
optbl[0x84] = &sCPU::op_sty_dp;
optbl[0x64] = &sCPU::op_stz_dp;
optbl[0x95] = &sCPU::op_sta_dpx;
optbl[0x94] = &sCPU::op_sty_dpx;
optbl[0x74] = &sCPU::op_stz_dpx;
optbl[0x96] = &sCPU::op_stx_dpy;
optbl[0x92] = &sCPU::op_sta_idp;
optbl[0x87] = &sCPU::op_sta_ildp;
optbl[0x81] = &sCPU::op_sta_idpx;
optbl[0x91] = &sCPU::op_sta_idpy;
optbl[0x97] = &sCPU::op_sta_ildpy;
optbl[0x83] = &sCPU::op_sta_sr;
optbl[0x93] = &sCPU::op_sta_isry;
optbl[0x1a] = &sCPU::op_inc;
optbl[0xe8] = &sCPU::op_inx;
optbl[0xc8] = &sCPU::op_iny;
optbl[0x3a] = &sCPU::op_dec;
optbl[0xca] = &sCPU::op_dex;
optbl[0x88] = &sCPU::op_dey;
optbl[0x0a] = &sCPU::op_asl;
optbl[0x4a] = &sCPU::op_lsr;
optbl[0x2a] = &sCPU::op_rol;
optbl[0x6a] = &sCPU::op_ror;
optbl[0xee] = &sCPU::op_inc_addr;
optbl[0xce] = &sCPU::op_dec_addr;
optbl[0x0e] = &sCPU::op_asl_addr;
optbl[0x4e] = &sCPU::op_lsr_addr;
optbl[0x2e] = &sCPU::op_rol_addr;
optbl[0x6e] = &sCPU::op_ror_addr;
optbl[0x1c] = &sCPU::op_trb_addr;
optbl[0x0c] = &sCPU::op_tsb_addr;
optbl[0xfe] = &sCPU::op_inc_addrx;
optbl[0xde] = &sCPU::op_dec_addrx;
optbl[0x1e] = &sCPU::op_asl_addrx;
optbl[0x5e] = &sCPU::op_lsr_addrx;
optbl[0x3e] = &sCPU::op_rol_addrx;
optbl[0x7e] = &sCPU::op_ror_addrx;
optbl[0xe6] = &sCPU::op_inc_dp;
optbl[0xc6] = &sCPU::op_dec_dp;
optbl[0x06] = &sCPU::op_asl_dp;
optbl[0x46] = &sCPU::op_lsr_dp;
optbl[0x26] = &sCPU::op_rol_dp;
optbl[0x66] = &sCPU::op_ror_dp;
optbl[0x14] = &sCPU::op_trb_dp;
optbl[0x04] = &sCPU::op_tsb_dp;
optbl[0xf6] = &sCPU::op_inc_dpx;
optbl[0xd6] = &sCPU::op_dec_dpx;
optbl[0x16] = &sCPU::op_asl_dpx;
optbl[0x56] = &sCPU::op_lsr_dpx;
optbl[0x36] = &sCPU::op_rol_dpx;
optbl[0x76] = &sCPU::op_ror_dpx;
optbl[0x90] = &sCPU::op_bcc;
optbl[0xb0] = &sCPU::op_bcs;
optbl[0xd0] = &sCPU::op_bne;
optbl[0xf0] = &sCPU::op_beq;
optbl[0x10] = &sCPU::op_bpl;
optbl[0x30] = &sCPU::op_bmi;
optbl[0x50] = &sCPU::op_bvc;
optbl[0x70] = &sCPU::op_bvs;
optbl[0x80] = &sCPU::op_bra;
optbl[0x82] = &sCPU::op_brl;
optbl[0x4c] = &sCPU::op_jmp_addr;
optbl[0x5c] = &sCPU::op_jmp_long;
optbl[0x6c] = &sCPU::op_jmp_iaddr;
optbl[0x7c] = &sCPU::op_jmp_iaddrx;
optbl[0xdc] = &sCPU::op_jmp_iladdr;
optbl[0x20] = &sCPU::op_jsr_addr;
optbl[0x22] = &sCPU::op_jsr_long;
optbl[0xfc] = &sCPU::op_jsr_iaddrx;
optbl[0x40] = &sCPU::op_rti;
optbl[0x60] = &sCPU::op_rts;
optbl[0x6b] = &sCPU::op_rtl;
optbl[0xea] = &sCPU::op_nop;
optbl[0x42] = &sCPU::op_wdm;
optbl[0xeb] = &sCPU::op_xba;
optbl[0x54] = &sCPU::op_mvn;
optbl[0x44] = &sCPU::op_mvp;
optbl[0x00] = &sCPU::op_brk;
optbl[0x02] = &sCPU::op_cop;
optbl[0xdb] = &sCPU::op_stp;
optbl[0xcb] = &sCPU::op_wai;
optbl[0xfb] = &sCPU::op_xce;
optbl[0x18] = &sCPU::op_clc;
optbl[0xd8] = &sCPU::op_cld;
optbl[0x58] = &sCPU::op_cli;
optbl[0xb8] = &sCPU::op_clv;
optbl[0x38] = &sCPU::op_sec;
optbl[0xf8] = &sCPU::op_sed;
optbl[0x78] = &sCPU::op_sei;
optbl[0xc2] = &sCPU::op_rep;
optbl[0xe2] = &sCPU::op_sep;
optbl[0xaa] = &sCPU::op_tax;
optbl[0xa8] = &sCPU::op_tay;
optbl[0x8a] = &sCPU::op_txa;
optbl[0x9b] = &sCPU::op_txy;
optbl[0x98] = &sCPU::op_tya;
optbl[0xbb] = &sCPU::op_tyx;
optbl[0x5b] = &sCPU::op_tcd;
optbl[0x1b] = &sCPU::op_tcs;
optbl[0x7b] = &sCPU::op_tdc;
optbl[0x3b] = &sCPU::op_tsc;
optbl[0xba] = &sCPU::op_tsx;
optbl[0x9a] = &sCPU::op_txs;
optbl[0x48] = &sCPU::op_pha;
optbl[0xda] = &sCPU::op_phx;
optbl[0x5a] = &sCPU::op_phy;
optbl[0x0b] = &sCPU::op_phd;
optbl[0x8b] = &sCPU::op_phb;
optbl[0x4b] = &sCPU::op_phk;
optbl[0x08] = &sCPU::op_php;
optbl[0x68] = &sCPU::op_pla;
optbl[0xfa] = &sCPU::op_plx;
optbl[0x7a] = &sCPU::op_ply;
optbl[0x2b] = &sCPU::op_pld;
optbl[0xab] = &sCPU::op_plb;
optbl[0x28] = &sCPU::op_plp;
optbl[0xf4] = &sCPU::op_pea;
optbl[0xd4] = &sCPU::op_pei;
optbl[0x62] = &sCPU::op_per;

View File

@ -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;
}

View File

@ -48,5 +48,9 @@ void sCPU::reset() {
apu_port[3] = 0x00;
}
sCPU::sCPU() {}
sCPU::~sCPU() {}
sCPU::sCPU() {
#include "core/optable.cpp"
}
sCPU::~sCPU() {
}

View File

@ -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

586
src/dsp/adsp/adsp.cpp Normal file
View File

@ -0,0 +1,586 @@
#include "../../base.h"
#include "adsp_tables.cpp"
void aDSP::enter() { loop:
run();
goto loop;
}
uint8 aDSP::readb(uint16 addr) {
return spcram[addr];
}
void aDSP::writeb(uint16 addr, uint8 data) {
spcram[addr] = data;
}
uint16 aDSP::readw(uint16 addr) {
return (readb(addr + 0)) | (readb(addr + 1) << 8);
}
void aDSP::writew(uint16 addr, uint16 data) {
writeb(addr + 0, data);
writeb(addr + 1, data >> 8);
}
uint8 aDSP::read(uint8 addr) {
addr &= 127;
int v = addr >> 4;
int n = addr & 15;
switch(addr) {
case 0x00: case 0x10: case 0x20: case 0x30:
case 0x40: case 0x50: case 0x60: case 0x70:
return voice[v].VOLL;
case 0x01: case 0x11: case 0x21: case 0x31:
case 0x41: case 0x51: case 0x61: case 0x71:
return voice[v].VOLR;
case 0x02: case 0x12: case 0x22: case 0x32:
case 0x42: case 0x52: case 0x62: case 0x72:
return voice[v].PITCH;
case 0x03: case 0x13: case 0x23: case 0x33:
case 0x43: case 0x53: case 0x63: case 0x73:
return voice[v].PITCH >> 8;
case 0x04: case 0x14: case 0x24: case 0x34:
case 0x44: case 0x54: case 0x64: case 0x74:
return voice[v].SRCN;
case 0x05: case 0x15: case 0x25: case 0x35:
case 0x45: case 0x55: case 0x65: case 0x75:
return voice[v].ADSR1;
case 0x06: case 0x16: case 0x26: case 0x36:
case 0x46: case 0x56: case 0x66: case 0x76:
return voice[v].ADSR2;
case 0x07: case 0x17: case 0x27: case 0x37:
case 0x47: case 0x57: case 0x67: case 0x77:
return voice[v].GAIN;
case 0x08: case 0x18: case 0x28: case 0x38:
case 0x48: case 0x58: case 0x68: case 0x78:
return voice[v].ENVX;
case 0x09: case 0x19: case 0x29: case 0x39:
case 0x49: case 0x59: case 0x69: case 0x79:
return voice[v].OUTX;
case 0x0f: case 0x1f: case 0x2f: case 0x3f:
case 0x4f: case 0x5f: case 0x6f: case 0x7f:
return status.FIR[v];
case 0x0c: return status.MVOLL;
case 0x1c: return status.MVOLR;
case 0x2c: return status.EVOLL;
case 0x3c: return status.EVOLR;
case 0x4c: return status.KON;
case 0x5c: return status.KOFF;
case 0x6c: return status.FLG;
case 0x7c: return status.ENDX;
case 0x0d: return status.EFB;
case 0x2d: return status.PMON;
case 0x3d: return status.NON;
case 0x4d: return status.EON;
case 0x5d: return status.DIR;
case 0x6d: return status.ESA;
case 0x7d: return status.EDL;
}
return dspram[addr];
}
void aDSP::write(uint8 addr, uint8 data) {
//0x80-0xff is a read-only mirror of 0x00-0x7f
if(addr & 0x80)return;
int v = addr >> 4;
int n = addr & 15;
switch(addr) {
case 0x00: case 0x10: case 0x20: case 0x30:
case 0x40: case 0x50: case 0x60: case 0x70:
voice[v].VOLL = data;
break;
case 0x01: case 0x11: case 0x21: case 0x31:
case 0x41: case 0x51: case 0x61: case 0x71:
voice[v].VOLR = data;
break;
case 0x02: case 0x12: case 0x22: case 0x32:
case 0x42: case 0x52: case 0x62: case 0x72:
voice[v].PITCH &= 0xff00;
voice[v].PITCH |= data;
break;
case 0x03: case 0x13: case 0x23: case 0x33:
case 0x43: case 0x53: case 0x63: case 0x73:
voice[v].PITCH &= 0x00ff;
voice[v].PITCH |= data << 8;
break;
case 0x04: case 0x14: case 0x24: case 0x34:
case 0x44: case 0x54: case 0x64: case 0x74:
voice[v].SRCN = data;
break;
case 0x05: case 0x15: case 0x25: case 0x35:
case 0x45: case 0x55: case 0x65: case 0x75:
voice[v].ADSR1 = data;
voice[v].AdjustEnvelope();
break;
case 0x06: case 0x16: case 0x26: case 0x36:
case 0x46: case 0x56: case 0x66: case 0x76:
voice[v].ADSR2 = data;
//sustain_level = 0-7, 7 is a special case handled by ATTACK envx mode
voice[v].env_sustain = (voice[v].ADSR_sus_level() + 1) << 8;
voice[v].AdjustEnvelope();
break;
case 0x07: case 0x17: case 0x27: case 0x37:
case 0x47: case 0x57: case 0x67: case 0x77:
voice[v].GAIN = data;
voice[v].AdjustEnvelope();
break;
case 0x08: case 0x18: case 0x28: case 0x38:
case 0x48: case 0x58: case 0x68: case 0x78:
voice[v].ENVX = data;
break;
case 0x09: case 0x19: case 0x29: case 0x39:
case 0x49: case 0x59: case 0x69: case 0x79:
voice[v].OUTX = data;
break;
case 0x0f: case 0x1f: case 0x2f: case 0x3f:
case 0x4f: case 0x5f: case 0x6f: case 0x7f:
status.FIR[v] = data;
break;
case 0x0c: status.MVOLL = data; break;
case 0x1c: status.MVOLR = data; break;
case 0x2c: status.EVOLL = data; break;
case 0x3c: status.EVOLR = data; break;
case 0x4c:
status.KON = data;
status.kon = data;
break;
case 0x5c:
status.KOFF = data;
break;
case 0x6c:
status.FLG = data;
status.noise_rate = rate_table[data & 0x1f];
break;
case 0x7c:
//read-only register, writes clear all bits of ENDX
status.ENDX = 0;
break;
case 0x0d: status.EFB = data; break;
case 0x2d: status.PMON = data; break;
case 0x3d: status.NON = data; break;
case 0x4d: status.EON = data; break;
case 0x5d: status.DIR = data; break;
case 0x6d: status.ESA = data; break;
case 0x7d: status.EDL = data; break;
}
dspram[addr] = data;
}
void aDSP::power() {
spcram = r_smp->get_spcram_handle();
memset(dspram, 0x00, 128);
for(int v = 0; v < 8; v++) {
voice[v].VOLL = 0;
voice[v].VOLR = 0;
voice[v].PITCH = 0;
voice[v].SRCN = 0;
voice[v].ADSR1 = 0;
voice[v].ADSR2 = 0;
voice[v].GAIN = 0;
status.FIR[v] = 0;
}
status.FLG = 0xe0;
status.MVOLL = status.MVOLR = 0;
status.EVOLL = status.EVOLR = 0;
status.ENDX = 0;
status.EFB = 0;
status.PMON = 0;
status.NON = 0;
status.EON = 0;
status.DIR = 0;
status.ESA = 0;
status.EDL = 0;
status.echo_length = 0;
reset();
}
void aDSP::reset() {
status.KON = 0x00;
status.KOFF = 0x00;
status.FLG |= 0xe0;
status.kon = 0x00;
status.esa = 0x00;
status.noise_ctr = 0;
status.noise_rate = 0;
status.noise_sample = 0x4000;
status.echo_index = 0;
status.fir_buffer_index = 0;
for(int v = 0; v < 8; v++) {
voice[v].ENVX = 0;
voice[v].OUTX = 0;
voice[v].pitch_ctr = 0;
voice[v].brr_index = 0;
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2));
voice[v].brr_looped = false;
voice[v].brr_data[0] = 0;
voice[v].brr_data[1] = 0;
voice[v].brr_data[2] = 0;
voice[v].brr_data[3] = 0;
voice[v].brr_data_index = 0;
voice[v].envx = 0;
voice[v].env_ctr = 0;
voice[v].env_rate = 0;
voice[v].env_state = SILENCE;
voice[v].env_mode = DIRECT;
status.fir_buffer[0][v] = 0;
status.fir_buffer[1][v] = 0;
}
dsp_counter = 0;
}
void aDSP::run() {
uint8 pmon;
int32 sample;
int32 msamplel, msampler;
int32 esamplel, esampler;
int32 fir_samplel, fir_sampler;
pmon = status.PMON & ~status.NON & ~1;
if((dsp_counter++ & 1) == 0) {
for(uint v = 0; v < 8; v++) {
if(status.soft_reset()) {
if(voice[v].env_state != SILENCE) {
voice[v].env_state = SILENCE;
voice[v].AdjustEnvelope();
}
}
if(status.KOFF & (1 << v)) {
if(voice[v].env_state != SILENCE && voice[v].env_state != RELEASE) {
voice[v].env_state = RELEASE;
voice[v].AdjustEnvelope();
}
}
if(status.kon & (1 << v)) {
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2));
voice[v].brr_index = -9;
voice[v].brr_looped = false;
voice[v].brr_data[0] = 0;
voice[v].brr_data[1] = 0;
voice[v].brr_data[2] = 0;
voice[v].brr_data[3] = 0;
voice[v].envx = 0;
voice[v].env_state = ATTACK;
voice[v].AdjustEnvelope();
}
}
status.ENDX &= ~status.kon;
status.kon = 0;
}
/*****
* update noise
*****/
status.noise_ctr += status.noise_rate;
if(status.noise_ctr >= 0x7800) {
status.noise_ctr -= 0x7800;
status.noise_sample = (status.noise_sample >> 1) | (((status.noise_sample << 14) ^ (status.noise_sample << 13)) & 0x4000);
}
msamplel = msampler = 0;
esamplel = esampler = 0;
/*****
* process voice channels
*****/
for(int v = 0; v < 8; v++) {
if(voice[v].brr_index < -1) {
voice[v].brr_index++;
voice[v].OUTX = voice[v].outx = 0;
voice[v].ENVX = 0;
continue;
}
if(voice[v].brr_index >= 0) {
if(pmon & (1 << v)) {
voice[v].pitch_ctr += (voice[v].pitch_rate() * (voice[v - 1].outx + 0x8000)) >> 15;
} else {
voice[v].pitch_ctr += voice[v].pitch_rate();
}
} else {
voice[v].pitch_ctr = 0x3000;
voice[v].brr_index = 0;
}
/*****
* decode BRR samples
*****/
while(voice[v].pitch_ctr >= 0) {
voice[v].pitch_ctr -= 0x1000;
voice[v].brr_data_index++;
voice[v].brr_data_index &= 3;
if(voice[v].brr_index == 0) {
voice[v].brr_header = readb(voice[v].brr_ptr);
if(voice[v].brr_header_flags() == BRR_END) {
status.ENDX |= (1 << v);
voice[v].env_state = SILENCE;
voice[v].AdjustEnvelope();
}
}
#define S(x) voice[v].brr_data[(voice[v].brr_data_index + (x)) & 3]
if(voice[v].env_state != SILENCE) {
sample = readb(voice[v].brr_ptr + 1 + (voice[v].brr_index >> 1));
if(voice[v].brr_index & 1) {
sample = sclip<4>(sample);
} else {
sample = sclip<4>(sample >> 4);
}
if(voice[v].brr_header_shift() <= 12) {
sample = (sample << voice[v].brr_header_shift() >> 1);
} else {
sample &= ~0x7ff;
}
switch(voice[v].brr_header_filter()) {
case 0: //direct
break;
case 1: //15/16
sample += S(-1) + ((-S(-1)) >> 4);
break;
case 2: //61/32 - 15/16
sample += (S(-1) << 1) + ((-((S(-1) << 1) + S(-1))) >> 5)
- S(-2) + (S(-2) >> 4);
break;
case 3: //115/64 - 13/16
sample += (S(-1) << 1) + ((-(S(-1) + (S(-1) << 2) + (S(-1) << 3))) >> 6)
- S(-2) + (((S(-2) << 1) + S(-2)) >> 4);
break;
}
S(0) = sample = sclip<15>(sclamp<16>(sample));
} else {
S(0) = sample = 0;
}
if(++voice[v].brr_index > 15) {
voice[v].brr_index = 0;
if(voice[v].brr_header_flags() & BRR_END) {
if(voice[v].brr_header_flags() & BRR_LOOP) {
status.ENDX |= (1 << v);
}
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2) + 2);
voice[v].brr_looped = true;
} else {
voice[v].brr_ptr += 9;
}
}
}
/*****
* volume envelope adjust
*****/
voice[v].env_ctr += voice[v].env_rate;
if(voice[v].env_ctr >= 0x7800) {
voice[v].env_ctr -= 0x7800;
switch(voice[v].env_mode) {
case DIRECT:
voice[v].env_rate = 0;
break;
case LINEAR_DEC:
voice[v].envx -= 32;
if(voice[v].envx <= 0) {
voice[v].envx = 0;
voice[v].env_rate = 0;
voice[v].env_mode = DIRECT;
}
break;
case LINEAR_INC:
voice[v].envx += 32;
if(voice[v].envx >= 0x7ff) {
voice[v].envx = 0x7ff;
voice[v].env_rate = 0;
voice[v].env_mode = DIRECT;
if(voice[v].ADSR_enabled() && voice[v].env_state == ATTACK) {
voice[v].env_state = ((voice[v].env_sustain == 0x800) ? SUSTAIN : DECAY);
voice[v].AdjustEnvelope();
}
}
break;
case EXP_DEC:
//multiply by 255/256ths
voice[v].envx -= ((voice[v].envx - 1) >> 8) + 1;
if(voice[v].ADSR_enabled() && voice[v].env_state == DECAY && voice[v].envx <= voice[v].env_sustain) {
voice[v].env_state = SUSTAIN;
voice[v].AdjustEnvelope();
} else if(voice[v].envx <= 0) {
voice[v].envx = 0;
voice[v].env_rate = 0;
voice[v].env_mode = DIRECT;
}
break;
case BENT_INC:
if(voice[v].envx < 0x600) {
voice[v].envx += 32;
} else {
voice[v].envx += 8;
if(voice[v].envx >= 0x7ff) {
voice[v].envx = 0x7ff;
voice[v].env_rate = 0;
voice[v].env_mode = DIRECT;
}
}
break;
case FAST_ATTACK:
voice[v].envx += 0x400;
if(voice[v].envx >= 0x7ff) {
voice[v].envx = 0x7ff;
//attack raises to max envx. if sustain is also set to max envx, skip decay phase
voice[v].env_state = ((voice[v].env_sustain == 0x800) ? SUSTAIN : DECAY);
voice[v].AdjustEnvelope();
}
break;
case RELEASE_DEC:
voice[v].envx -= 8;
if(voice[v].envx <= 0) {
voice[v].env_state = SILENCE;
voice[v].AdjustEnvelope();
}
break;
}
}
voice[v].ENVX = voice[v].envx >> 4;
/*****
* gaussian interpolation / noise
*****/
if(status.NON & (1 << v)) {
sample = sclip<15>(status.noise_sample);
} else {
int32 d = voice[v].pitch_ctr >> 4; //-256 <= sample <= -1
sample = ((gaussian_table[ -1 - d] * S(-3)) >> 11);
sample += ((gaussian_table[255 - d] * S(-2)) >> 11);
sample += ((gaussian_table[512 + d] * S(-1)) >> 11);
sample = sclip <15>(sample);
sample += ((gaussian_table[256 + d] * S( 0)) >> 11);
sample = sclamp<15>(sample);
}
#undef S
/*****
* envelope / volume adjust
*****/
sample = (sample * voice[v].envx) >> 11;
voice[v].outx = sample << 1;
voice[v].OUTX = sample >> 7;
if(!status.mute()) {
msamplel += ((sample * voice[v].VOLL) >> 7) << 1;
msampler += ((sample * voice[v].VOLR) >> 7) << 1;
}
if((status.EON & (1 << v)) && status.echo_write()) {
esamplel += ((sample * voice[v].VOLL) >> 7) << 1;
esampler += ((sample * voice[v].VOLR) >> 7) << 1;
}
}
/*****
* echo (FIR) adjust
*****/
#define F(c,x) status.fir_buffer[c][(status.fir_buffer_index + (x)) & 7]
status.fir_buffer_index++;
F(0,0) = readw((status.esa << 8) + status.echo_index + 0);
F(1,0) = readw((status.esa << 8) + status.echo_index + 2);
fir_samplel = (F(0,-0) * status.FIR[7] +
F(0,-1) * status.FIR[6] +
F(0,-2) * status.FIR[5] +
F(0,-3) * status.FIR[4] +
F(0,-4) * status.FIR[3] +
F(0,-5) * status.FIR[2] +
F(0,-6) * status.FIR[1] +
F(0,-7) * status.FIR[0]);
fir_sampler = (F(1,-0) * status.FIR[7] +
F(1,-1) * status.FIR[6] +
F(1,-2) * status.FIR[5] +
F(1,-3) * status.FIR[4] +
F(1,-4) * status.FIR[3] +
F(1,-5) * status.FIR[2] +
F(1,-6) * status.FIR[1] +
F(1,-7) * status.FIR[0]);
#undef F
/*****
* update echo buffer
*****/
if(status.echo_write()) {
esamplel += (fir_samplel * status.EFB) >> 14;
esampler += (fir_sampler * status.EFB) >> 14;
esamplel = sclamp<16>(esamplel);
esampler = sclamp<16>(esampler);
writew((status.esa << 8) + status.echo_index + 0, esamplel);
writew((status.esa << 8) + status.echo_index + 2, esampler);
}
status.echo_index += 4;
if(status.echo_index >= status.echo_length) {
status.echo_index = 0;
status.echo_length = (status.EDL & 0x0f) << 11;
}
//ESA read occurs at roughly 22/32th sample
//ESA fetch occurs at roughly 29/32th sample
//as this is not a subsample-level S-DSP emulator,
//simulate ~25/32th delay by caching ESA for one
//complete sample ...
status.esa = status.ESA;
/*****
* main output adjust
*****/
if(!status.mute()) {
msamplel = (msamplel * status.MVOLL) >> 7;
msampler = (msampler * status.MVOLR) >> 7;
msamplel += (fir_samplel * status.EVOLL) >> 14;
msampler += (fir_sampler * status.EVOLR) >> 14;
msamplel = sclamp<16>(msamplel);
msampler = sclamp<16>(msampler);
}
snes.audio_update(msamplel, msampler);
scheduler.addclocks_dsp(32 * 3);
}
aDSP::aDSP() {}
aDSP::~aDSP() {}

172
src/dsp/adsp/adsp.h Normal file
View File

@ -0,0 +1,172 @@
class aDSP : public DSP {
private:
uint8 dspram[128];
uint8 *spcram;
uint32 dsp_counter;
enum { BRR_END = 1, BRR_LOOP = 2 };
uint8 readb (uint16 addr);
uint16 readw (uint16 addr);
void writeb(uint16 addr, uint8 data);
void writew(uint16 addr, uint16 data);
public:
static const uint16 rate_table[32];
static const int16 gaussian_table[512];
enum EnvelopeStates {
ATTACK,
DECAY,
SUSTAIN,
RELEASE,
SILENCE
};
enum EnvelopeModes {
DIRECT,
LINEAR_DEC,
EXP_DEC,
LINEAR_INC,
BENT_INC,
FAST_ATTACK,
RELEASE_DEC
};
private:
struct Status {
//$0c,$1c
int8 MVOLL, MVOLR;
//$2c,$3c
int8 EVOLL, EVOLR;
//$4c,$5c
uint8 KON, KOFF;
//$6c
uint8 FLG;
//$7c
uint8 ENDX;
//$0d
int8 EFB;
//$2d,$3d,$4d
uint8 PMON, NON, EON;
//$5d
uint8 DIR;
//$6d,$7d
uint8 ESA, EDL;
//$xf
int8 FIR[8];
//internal variables
uint8 kon, esa;
int16 noise_ctr, noise_rate;
uint16 noise_sample;
uint16 echo_index, echo_length;
int16 fir_buffer[2][8];
uint8 fir_buffer_index;
//functions
bool soft_reset() { return !!(FLG & 0x80); }
bool mute() { return !!(FLG & 0x40); }
bool echo_write() { return !(FLG & 0x20); }
} status;
struct Voice {
//$x0-$x1
int8 VOLL, VOLR;
//$x2-$x3
int16 PITCH;
//$x4
uint8 SRCN;
//$x5-$x7
uint8 ADSR1, ADSR2, GAIN;
//$x8-$x9
uint8 ENVX, OUTX;
//internal variables
int16 pitch_ctr;
int8 brr_index;
uint16 brr_ptr;
uint8 brr_header;
bool brr_looped;
int16 brr_data[4];
uint8 brr_data_index;
int16 envx;
uint16 env_ctr, env_rate, env_sustain;
enum EnvelopeStates env_state;
enum EnvelopeModes env_mode;
int16 outx;
//functions
int16 pitch_rate() { return PITCH & 0x3fff; }
uint8 brr_header_shift() { return brr_header >> 4; }
uint8 brr_header_filter() { return (brr_header >> 2) & 3; }
uint8 brr_header_flags() { return brr_header & 3; }
bool ADSR_enabled() { return !!(ADSR1 & 0x80); }
uint8 ADSR_decay() { return (ADSR1 >> 4) & 7; }
uint8 ADSR_attack() { return ADSR1 & 15; }
uint8 ADSR_sus_level() { return ADSR2 >> 5; }
uint8 ADSR_sus_rate() { return ADSR2 & 31; }
void AdjustEnvelope() {
if(env_state == SILENCE) {
env_mode = DIRECT;
env_rate = 0;
envx = 0;
} else if(env_state == RELEASE) {
env_mode = RELEASE_DEC;
env_rate = 0x7800;
} else if(ADSR_enabled()) {
switch(env_state) {
case ATTACK:
env_rate = rate_table[(ADSR_attack() << 1) + 1];
env_mode = (env_rate == 0x7800) ? FAST_ATTACK : LINEAR_INC;
break;
case DECAY:
env_rate = rate_table[(ADSR_decay() << 1) + 0x10];
env_mode = EXP_DEC;
break;
case SUSTAIN:
env_rate = rate_table[ADSR_sus_rate()];
env_mode = (env_rate == 0) ? DIRECT : EXP_DEC;
break;
}
} else if(GAIN & 0x80) {
switch(GAIN & 0x60) {
case 0x00: env_mode = LINEAR_DEC; break;
case 0x20: env_mode = EXP_DEC; break;
case 0x40: env_mode = LINEAR_INC; break;
case 0x60: env_mode = BENT_INC; break;
}
env_rate = rate_table[GAIN & 0x1f];
} else {
env_mode = DIRECT;
env_rate = 0;
envx = (GAIN & 0x7f) << 4;
}
}
} voice[8];
public:
void enter();
void run();
uint8 read (uint8 addr);
void write(uint8 addr, uint8 data);
void power();
void reset();
aDSP();
~aDSP();
};

View File

@ -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

View File

@ -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;
}
}

View File

@ -0,0 +1,32 @@
#include "../../base.h"
#include "spc_dsp.h"
void bDSP::power() {
spc_dsp_init(r_smp->get_spcram_handle());
spc_dsp_reset();
}
void bDSP::reset() {
spc_dsp_soft_reset();
}
uint8 bDSP::read(uint8 addr) {
return spc_dsp_read(addr);
}
void bDSP::write(uint8 addr, uint8 data) {
spc_dsp_write(addr, data);
}
#define SPC_DSP_CUSTOM_RUN 1 //causes spc_dsp_run() to not be defined since it's huge and we don't need it
#define SPC_DSP_OUT_HOOK(left, right) snes.audio_update(left, right);
#include "spc_dsp.cpp"
void bDSP::enter() { loop:
#define PHASE(n) scheduler.addclocks_dsp(3);
#include "spc_dsp_timing.h"
goto loop;
}
bDSP::bDSP() {}
bDSP::~bDSP() {}

View File

@ -0,0 +1,10 @@
class bDSP : public DSP { public:
void enter();
uint8 read(uint8 addr);
void write(uint8 addr, uint8 data);
void power();
void reset();
bDSP();
~bDSP();
};

View File

@ -0,0 +1,64 @@
Overall operation
-----------------
This DSP emulator fundamentally emulates the different options the DSP
performs on each clock. The pattern of operations repeats every 32
clocks (except one minor detail, which repeats every 64 clocks instead).
There are three main types of operations:
- Miscellaneous processing
- Voice processing
- Echo processing
Each is done over several clocks, and several operations are done on
each clock. Each clock is defined as a separate function, then called
from a large switch block in a loop.
Many times a value is read on one clock but not used until a later
clock, so many non-local temporary variables are used in the code to
store these values. These are named with t_ to make it clear that they
don't store long-term state.
Circular buffers
----------------
Two circular buffers are used in the code (echo history and BRR decode).
Both need efficient index-based access with wrap-around. Things are
greatly simplified by repeating the contents of buffer twice, so instead
of
0 1 2 3 4 5 6 7
it stores
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
The position in this case would always be 0 to 7, so reading up to +8
won't go outside buffer. This duplication is maintained by simply
writing data twice when filling buffer:
0 1 2 3 4 # 6 7 0 1 2 3 4 # 6 7
new data -----^---------------^
No wrap checking needs to be done when writing either, since the above
reasoning holds. When making a state snapshot, only the first copy needs
to be saved. When restoring, simply duplicate the data twice.
Code
----
- Currently all state is in static variables. They have either a t_ or
m_ prefix to allow easy migration to a structure.
- Static state that persists over several samples or more is prefixed
with m_.
- State which is temporary to the current sample is prefixed with t_.
These are usually just overwritten with new data on the next sample.
These generally correspond to temporaries/registers in actual DSP
itself.
- Minimal stdint.h included in case your system doesn't have one.
--
Shay Green <gblargg@gmail.com>

View File

@ -0,0 +1,828 @@
// http://www.slack.net/~ant/
#include "spc_dsp.h"
#include <limits.h>
#include <string.h>
/* Copyright (C) 2007 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
// Volume registers and efb are signed! Easy to forget int8_t cast.
// Prefixes are to avoid accidental use of locals with same names.
// Global registers
enum {
r_mvoll = 0x0C, r_mvolr = 0x1C,
r_evoll = 0x2C, r_evolr = 0x3C,
r_kon = 0x4C, r_koff = 0x5C,
r_flg = 0x6C, r_endx = 0x7C,
r_efb = 0x0D, r_pmon = 0x2D,
r_non = 0x3D, r_eon = 0x4D,
r_dir = 0x5D, r_esa = 0x6D,
r_edl = 0x7D,
r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F
};
// Voice registers
enum {
v_voll = 0x00, v_volr = 0x01,
v_pitchl = 0x02, v_pitchh = 0x03,
v_srcn = 0x04, v_adsr0 = 0x05,
v_adsr1 = 0x06, v_gain = 0x07,
v_envx = 0x08, v_outx = 0x09
};
// Internal envelope modes
enum env_mode_t { env_release, env_attack, env_decay, env_sustain };
// Internal voice state
enum { brr_buf_size = 12 };
enum { brr_block_size = 9 };
typedef struct voice_t
{
int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling)
int buf_pos; // place in buffer where next samples will be decoded
int interp_pos; // relative fractional position in sample (0x1000 = 1.0)
int brr_addr; // address of current BRR block
int brr_offset; // current decoding offset in BRR block
uint8_t* regs; // pointer to voice's DSP registers
int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc.
int kon_delay; // KON delay/current setup phase
enum env_mode_t env_mode;
int env; // current envelope level
int t_envx_out;
int hidden_env; // used by GAIN mode 7, very obscure quirk
} voice_t;
static voice_t m_voice_state [spc_dsp_voice_count];
static uint8_t* m_ram; // 64K shared RAM between DSP and SMP
spc_dsp_t m_spc_dsp;
spc_dsp_sample_t* m_spc_dsp_out_begin;
spc_dsp_sample_t* m_spc_dsp_out;
spc_dsp_sample_t* m_spc_dsp_out_end;
// "Member" access
#define m m_spc_dsp
// Access global DSP register
#define REG(n) m.regs [r_##n]
// Access voice DSP register
#define VREG(r,n) r [v_##n]
// if ( io < -32768 ) io = -32768;
// if ( io > 32767 ) io = 32767;
#define CLAMP16( io )\
{\
if ( (int16_t) io != io )\
io = 0x7FFF ^ (io >> 31);\
}
// Gaussian interpolation
static short const gauss [512] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5,
6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17,
18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27,
28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77,
78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102,
104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132,
134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168,
171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210,
212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257,
260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311,
314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370,
374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434,
439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504,
508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577,
582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654,
659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732,
737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811,
816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889,
894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965,
969, 974, 978, 983, 988, 992, 997,1001,1005,1010,1014,1019,1023,1027,1032,1036,
1040,1045,1049,1053,1057,1061,1066,1070,1074,1078,1082,1086,1090,1094,1098,1102,
1106,1109,1113,1117,1121,1125,1128,1132,1136,1139,1143,1146,1150,1153,1157,1160,
1164,1167,1170,1174,1177,1180,1183,1186,1190,1193,1196,1199,1202,1205,1207,1210,
1213,1216,1219,1221,1224,1227,1229,1232,1234,1237,1239,1241,1244,1246,1248,1251,
1253,1255,1257,1259,1261,1263,1265,1267,1269,1270,1272,1274,1275,1277,1279,1280,
1282,1283,1284,1286,1287,1288,1290,1291,1292,1293,1294,1295,1296,1297,1297,1298,
1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305,
};
static inline int interpolate( voice_t const* const v )
{
// Make pointers into gaussian based on fractional position between samples
int offset = v->interp_pos >> 4 & 0xFF;
short const* fwd = gauss + 255 - offset;
short const* rev = gauss + offset; // mirror left half of gaussian
int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos];
int out;
out = (fwd [ 0] * in [0]) >> 11;
out += (fwd [256] * in [1]) >> 11;
out += (rev [256] * in [2]) >> 11;
out = (int16_t) out;
out += (rev [ 0] * in [3]) >> 11;
CLAMP16( out );
out &= ~1;
return out;
}
//// Counters
enum { simple_counter_range = 2048 * 5 * 3 }; // 30720
static unsigned short const counter_rates [32] =
{
simple_counter_range + 1, // never fires
2048, 1536,
1280, 1024, 768,
640, 512, 384,
320, 256, 192,
160, 128, 96,
80, 64, 48,
40, 32, 24,
20, 16, 12,
10, 8, 6,
5, 4, 3,
2,
1
};
static unsigned short const counter_offsets [32] =
{
1, 0, 1040,
536, 0, 1040,
536, 0, 1040,
536, 0, 1040,
536, 0, 1040,
536, 0, 1040,
536, 0, 1040,
536, 0, 1040,
536, 0, 1040,
536, 0, 1040,
0,
0
};
static inline void init_counters( void ) { }
static inline void run_counters( void )
{
if ( --m.counter < 0 )
m.counter = simple_counter_range - 1;
}
static inline unsigned read_counter( int rate )
{
return ((unsigned) m.counter + counter_offsets [rate]) % counter_rates [rate];
}
//// Envelope
static inline void run_envelope( voice_t* const v )
{
int env = v->env;
if ( v->env_mode == env_release ) // 60%
{
if ( (env -= 0x8) < 0 )
env = 0;
v->env = env;
}
else
{
int rate;
int env_data = VREG(v->regs,adsr1);
if ( m.t_adsr0 & 0x80 ) // 99% ADSR
{
if ( v->env_mode >= env_decay ) // 99%
{
env--;
env -= env >> 8;
rate = env_data & 0x1F;
if ( v->env_mode == env_decay ) // 1%
rate = (m.t_adsr0 >> 3 & 0x0E) + 0x10;
}
else // env_attack
{
rate = (m.t_adsr0 & 0x0F) * 2 + 1;
env += rate < 31 ? 0x20 : 0x400;
}
}
else // GAIN
{
env_data = VREG(v->regs,gain);
int mode = env_data >> 5;
if ( mode < 4 ) // direct
{
env = env_data * 0x10;
rate = 31;
}
else
{
rate = env_data & 0x1F;
if ( mode == 4 ) // 4: linear decrease
{
env -= 0x20;
}
else if ( mode < 6 ) // 5: exponential decrease
{
env--;
env -= env >> 8;
}
else // 6,7: linear increase
{
env += 0x20;
if ( mode > 6 && (unsigned) v->hidden_env >= 0x600 )
env += 0x8 - 0x20; // 7: two-slope linear increase
}
}
}
// Sustain level
if ( (env >> 8) == (env_data >> 5) && v->env_mode == env_decay )
v->env_mode = env_sustain;
v->hidden_env = env;
// unsigned cast because linear decrease going negative also triggers this
if ( (unsigned) env > 0x7FF )
{
env = (env < 0 ? 0 : 0x7FF);
if ( v->env_mode == env_attack )
v->env_mode = env_decay;
}
if ( !read_counter( rate ) )
v->env = env; // nothing else is controlled by the counter
}
}
//// BRR Decoding
static inline void decode_brr( voice_t* v )
{
// Arrange the four input nybbles in 0xABCD order for easy decoding
int nybbles = m.t_brr_byte * 0x100 + m_ram [(v->brr_addr + v->brr_offset + 1) & 0xFFFF];
int const header = m.t_brr_header;
// 0: >>1 1: <<0 2: <<1 ... 12: <<11 13-15: >>4 <<11
static unsigned char const shifts [16 * 2] = {
13,12,12,12,12,12,12,12,12,12,12, 12, 12, 16, 16, 16,
0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11, 11, 11
};
int const scale = header >> 4;
int const right_shift = shifts [scale];
int const left_shift = shifts [scale + 16];
// Write to next four samples in circular buffer
int* pos = &v->buf [v->buf_pos];
if ( (v->buf_pos += 4) >= brr_buf_size )
v->buf_pos = 0;
// Decode four samples
for ( int* end = pos + 4; pos < end; pos++ )
{
// Extract upper nybble and scale appropriately
int s = ((int16_t) nybbles >> right_shift) << left_shift;
nybbles <<= 4;
// Apply IIR filter (8 is the most commonly used)
int const filter = header & 0x0C;
int const p1 = pos [brr_buf_size - 1];
int const p2 = pos [brr_buf_size - 2] >> 1;
if ( filter >= 8 )
{
s += p1;
s -= p2;
if ( filter == 8 ) // s += p1 * 0.953125 - p2 * 0.46875
{
s += p2 >> 4;
s += (p1 * -3) >> 6;
}
else // s += p1 * 0.8984375 - p2 * 0.40625
{
s += (p1 * -13) >> 7;
s += (p2 * 3) >> 4;
}
}
else if ( filter ) // s += p1 * 0.46875
{
s += p1 >> 1;
s += (-p1) >> 5;
}
// Adjust and write sample
CLAMP16( s );
s = (int16_t) (s * 2);
pos [brr_buf_size] = pos [0] = s; // second copy simplifies wrap-around
}
}
//// Misc
#define MISC_CLOCK( n ) inline static void misc_##n( void )
MISC_CLOCK( 27 )
{
m.t_pmon = REG(pmon) & 0xFE; // voice 0 doesn't support PMON
}
MISC_CLOCK( 28 )
{
m.t_non = REG(non);
m.t_eon = REG(eon);
m.t_dir = REG(dir);
}
MISC_CLOCK( 29 )
{
if ( (m.every_other_sample ^= 1) != 0 )
m.new_kon &= ~m.kon; // clears KON 63 clocks after it was last read
}
MISC_CLOCK( 30 )
{
if ( m.every_other_sample )
{
m.kon = m.new_kon;
m.t_koff = REG(koff) | m.mute_mask;
}
run_counters();
// Noise
if ( !read_counter( REG(flg) & 0x1F ) )
{
int feedback = (m.noise << 13) ^ (m.noise << 14);
m.noise = (feedback & 0x4000) ^ (m.noise >> 1);
}
}
//// Voices
#define VOICE_CLOCK( n ) static void voice_##n( voice_t* const v )
inline VOICE_CLOCK( V1 )
{
m.t_dir_addr = m.t_dir * 0x100 + m.t_srcn * 4;
m.t_srcn = VREG(v->regs,srcn);
}
inline VOICE_CLOCK( V2 )
{
// Read sample pointer (ignored if not needed)
uint8_t const* entry = &m_ram [m.t_dir_addr];
if ( !v->kon_delay )
entry += 2;
m.t_brr_next_addr = entry [1] * 0x100 + entry [0];
m.t_adsr0 = VREG(v->regs,adsr0);
// Read pitch, spread over two clocks
m.t_pitch = VREG(v->regs,pitchl);
}
inline VOICE_CLOCK( V3a )
{
m.t_pitch += (VREG(v->regs,pitchh) & 0x3F) << 8;
}
inline VOICE_CLOCK( V3b )
{
// Read BRR header and byte
m.t_brr_byte = m_ram [(v->brr_addr + v->brr_offset) & 0xFFFF];
m.t_brr_header = m_ram [v->brr_addr]; // brr_addr doesn't need masking
}
VOICE_CLOCK( V3c )
{
// Pitch modulation using previous voice's output
if ( m.t_pmon & v->vbit )
m.t_pitch += ((m.t_output >> 5) * m.t_pitch) >> 10;
if ( v->kon_delay )
{
// Get ready to start BRR decoding on next sample
if ( v->kon_delay == 5 )
{
v->brr_addr = m.t_brr_next_addr;
v->brr_offset = 1;
v->buf_pos = 0;
m.t_brr_header = 0; // header is ignored on this sample
}
// Envelope is never run during KON
v->env = 0;
v->hidden_env = 0;
// Disable BRR decoding until last three samples
v->interp_pos = 0;
if ( --v->kon_delay & 3 )
v->interp_pos = 0x4000;
// Pitch is never added during KON
m.t_pitch = 0;
}
// Gaussian interpolation
int output = interpolate( v );
// Noise
if ( m.t_non & v->vbit )
output = (int16_t) (m.noise * 2);
// Apply envelope
m.t_output = (output * v->env) >> 11 & ~1;
v->t_envx_out = v->env >> 4;
// Immediate silence due to end of sample or soft reset
if ( REG(flg) & 0x80 || (m.t_brr_header & 3) == 1 )
{
v->env_mode = env_release;
v->env = 0;
}
if ( m.every_other_sample )
{
// KOFF
if ( m.t_koff & v->vbit )
v->env_mode = env_release;
// KON
if ( m.kon & v->vbit )
{
v->kon_delay = 5;
v->env_mode = env_attack;
}
}
// Run envelope for next sample
if ( !v->kon_delay )
run_envelope( v );
}
static inline void voice_output( voice_t const* v, int ch )
{
// Apply left/right volume
int amp = (m.t_output * (int8_t) VREG(v->regs,voll + ch)) >> 7;
// Add to output total
m.t_main_out [ch] += amp;
CLAMP16( m.t_main_out [ch] );
// Optionally add to echo total
if ( m.t_eon & v->vbit )
{
m.t_echo_out [ch] += amp;
CLAMP16( m.t_echo_out [ch] );
}
}
VOICE_CLOCK( V4 )
{
// Decode BRR
m.t_looped = 0;
if ( v->interp_pos >= 0x4000 )
{
decode_brr( v );
if ( (v->brr_offset += 2) >= brr_block_size )
{
// Start decoding next BRR block
assert( v->brr_offset == brr_block_size );
v->brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF;
if ( m.t_brr_header & 1 )
{
v->brr_addr = m.t_brr_next_addr;
m.t_looped = v->vbit;
}
v->brr_offset = 1;
}
}
// Apply pitch
v->interp_pos = (v->interp_pos & 0x3FFF) + m.t_pitch;
// Keep from getting too far ahead (when using pitch modulation)
if ( v->interp_pos > 0x7FFF )
v->interp_pos = 0x7FFF;
// Output left
voice_output( v, 0 );
}
inline VOICE_CLOCK( V5 )
{
// Output right
voice_output( v, 1 );
// ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier
m.endx_buf = REG(endx) | m.t_looped;
// Clear bit in ENDX if KON just began
if ( v->kon_delay == 5 )
m.endx_buf &= ~v->vbit;
}
inline VOICE_CLOCK( V6 )
{
m.outx_buf = m.t_output >> 8;
}
inline VOICE_CLOCK( V7 )
{
// Update ENDX
REG(endx) = (uint8_t) m.endx_buf;
m.envx_buf = v->t_envx_out;
}
inline VOICE_CLOCK( V8 )
{
// Update OUTX
VREG(v->regs,outx) = (uint8_t) m.outx_buf;
}
inline VOICE_CLOCK( V9 )
{
// Update ENVX
VREG(v->regs,envx) = (uint8_t) m.envx_buf;
}
// Most voices do all these in one clock, so make a handy composite
inline VOICE_CLOCK( V3 )
{
voice_V3a( v );
voice_V3b( v );
voice_V3c( v );
}
// Common combinations of voice steps on different voices. This greatly reduces
// code size and allows everything to be inlined in these functions.
VOICE_CLOCK(V7_V4_V1) { voice_V7(v); voice_V1(v+3); voice_V4(v+1); }
VOICE_CLOCK(V8_V5_V2) { voice_V8(v); voice_V5(v+1); voice_V2(v+2); }
VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); }
//// Echo
// Current echo buffer pointer for left/right channel
#define ECHO_PTR( ch ) (&m_ram [m.t_echo_ptr + ch * 2])
// Sample in echo history buffer, where 0 is the oldest
#define ECHO_FIR( i ) (m.echo_hist_pos [i])
// Calculate FIR point for left/right channel
#define CALC_FIR( i, ch ) ((ECHO_FIR( i + 1 ) [ch] * (int8_t) REG(fir + i * 0x10)) >> 6)
#define ECHO_CLOCK( n ) inline static void echo_##n( void )
static inline void echo_read( int ch )
{
uint8_t const* in = ECHO_PTR( ch );
int s = (int8_t) in [1] * 0x100 + in [0];
// second copy simplifies wrap-around handling
ECHO_FIR( 0 ) [ch] = ECHO_FIR( 8 ) [ch] = s >> 1;
}
ECHO_CLOCK( 22 )
{
// History
if ( ++m.echo_hist_pos >= &m.echo_hist [spc_dsp_echo_hist_size] )
m.echo_hist_pos = m.echo_hist;
m.t_echo_ptr = (m.t_esa * 0x100 + m.echo_offset) & 0xFFFF;
echo_read( 0 );
// FIR (using l and r temporaries below helps compiler optimize)
int l = CALC_FIR( 0, 0 );
int r = CALC_FIR( 0, 1 );
m.t_echo_in [0] = l;
m.t_echo_in [1] = r;
}
ECHO_CLOCK( 23 )
{
int l = CALC_FIR( 1, 0 ) + CALC_FIR( 2, 0 );
int r = CALC_FIR( 1, 1 ) + CALC_FIR( 2, 1 );
m.t_echo_in [0] += l;
m.t_echo_in [1] += r;
echo_read( 1 );
}
ECHO_CLOCK( 24 )
{
int l = CALC_FIR( 3, 0 ) + CALC_FIR( 4, 0 ) + CALC_FIR( 5, 0 );
int r = CALC_FIR( 3, 1 ) + CALC_FIR( 4, 1 ) + CALC_FIR( 5, 1 );
m.t_echo_in [0] += l;
m.t_echo_in [1] += r;
}
ECHO_CLOCK( 25 )
{
int l = m.t_echo_in [0] + CALC_FIR( 6, 0 );
int r = m.t_echo_in [1] + CALC_FIR( 6, 1 );
l = (int16_t) l;
r = (int16_t) r;
l += (int16_t) CALC_FIR( 7, 0 );
r += (int16_t) CALC_FIR( 7, 1 );
CLAMP16( l );
CLAMP16( r );
m.t_echo_in [0] = l & ~1;
m.t_echo_in [1] = r & ~1;
}
static inline int echo_output( int ch )
{
int out = (int16_t) ((m.t_main_out [ch] * (int8_t) REG(mvoll + ch * 0x10)) >> 7) +
(int16_t) ((m.t_echo_in [ch] * (int8_t) REG(evoll + ch * 0x10)) >> 7);
CLAMP16( out );
return out;
}
ECHO_CLOCK( 26 )
{
// Left output volumes
// (save sample for next clock so we can output both together)
m.t_main_out [0] = echo_output( 0 );
// Echo feedback
int l = m.t_echo_out [0] + (int16_t) ((m.t_echo_in [0] * (int8_t) REG(efb)) >> 7);
int r = m.t_echo_out [1] + (int16_t) ((m.t_echo_in [1] * (int8_t) REG(efb)) >> 7);
CLAMP16( l );
CLAMP16( r );
m.t_echo_out [0] = l & ~1;
m.t_echo_out [1] = r & ~1;
}
ECHO_CLOCK( 27 )
{
// Output
int outl = m.t_main_out [0];
int outr = echo_output( 1 );
m.t_main_out [0] = 0;
m.t_main_out [1] = 0;
// TODO: global muting isn't this simple (turns DAC on and off
// or something, causing small ~37-sample pulse when first muted)
if ( REG(flg) & 0x40 )
{
outl = 0;
outr = 0;
}
// Output sample to DAC
#ifdef SPC_DSP_OUT_HOOK
SPC_DSP_OUT_HOOK( outl, outr );
#else
spc_dsp_sample_t* out = m_spc_dsp_out;
assert( !out || out < m_spc_dsp_out_end ); // fails if output buffer is too small
if ( out != m_spc_dsp_out_end )
{
out [0] = outl;
out [1] = outr;
m_spc_dsp_out = out + 2;
}
#endif
}
ECHO_CLOCK( 28 )
{
m.t_echo_enabled = REG(flg);
}
static inline void echo_write( int ch )
{
if ( !(m.t_echo_enabled & 0x20) )
{
uint8_t* out = ECHO_PTR( ch );
int s = m.t_echo_out [ch];
out [0] = (uint8_t) s;
out [1] = (uint8_t) (s >> 8);
}
m.t_echo_out [ch] = 0;
}
ECHO_CLOCK( 29 )
{
m.t_esa = REG(esa);
if ( !m.echo_offset )
m.echo_length = (REG(edl) & 0x0F) * 0x800;
m.echo_offset += 4;
if ( m.echo_offset >= m.echo_length )
m.echo_offset = 0;
// Write left echo
echo_write( 0 );
m.t_echo_enabled = REG(flg);
}
ECHO_CLOCK( 30 )
{
// Write right echo
echo_write( 1 );
}
//// Timing
#if !SPC_DSP_CUSTOM_RUN
void spc_dsp_run( int clocks_remain )
{
assert( clocks_remain > 0 );
int const phase = m.phase;
m.phase = (phase + clocks_remain) & 31;
switch ( phase )
{
loop:
#define PHASE( n ) if ( n && !--clocks_remain ) break; case n:
#include "spc_dsp_timing.h"
#undef PHASE
if ( --clocks_remain )
goto loop;
}
}
#endif
//// Setup
void spc_dsp_reset( void )
{
// Clear everything to zero, then set things which must be non-zero
memset( m_voice_state, 0, sizeof m_voice_state );
memset( &m_spc_dsp, 0, sizeof m_spc_dsp );
m.noise = 1;
m.echo_hist_pos = m.echo_hist;
m.every_other_sample = 1;
init_counters();
int i;
for ( i = spc_dsp_voice_count; --i >= 0; )
{
voice_t* v = &m_voice_state [i];
v->regs = &m.regs [i * 0x10];
v->vbit = 1 << i;
v->brr_offset = 1;
}
REG(flg) = 0xE0;
}
void spc_dsp_soft_reset( void )
{
// TODO: doesn't reset everything
spc_dsp_reset();
}
void spc_dsp_init( void* ram_64k )
{
m_ram = (uint8_t*) ram_64k;
spc_dsp_reset();
#if INT_MAX < 0x7FFFFFFF
#error "Requires that int have at least 32 bits"
#endif
#ifndef NDEBUG
// be sure this sign-extends
assert( (int16_t) 0x8000 == -0x8000 );
// be sure right shift preserves sign
assert( (-1 >> 1) == -1 );
// check clamp macro
int i;
i = +0x8000; CLAMP16( i ); assert( i == +0x7FFF );
i = -0x8001; CLAMP16( i ); assert( i == -0x8000 );
#endif
}
void spc_dsp_load( uint8_t const regs [spc_dsp_register_count] )
{
int i;
for ( i = 0; i < 0x80; i++ )
spc_dsp_write( i, regs [i] );
m.t_esa = regs [r_esa];
m.t_dir = regs [r_dir];
}

View File

@ -0,0 +1,162 @@
// SNES SPC-700 DSP emulator
#ifndef SPC_DSP_H
#define SPC_DSP_H
#include <assert.h>
#include <stdint.h>
//// Setup
// Initializes DSP and has it use the 64K RAM provided
void spc_dsp_init( void* ram_64k );
// Restores DSP registers using supplied values
enum { spc_dsp_register_count = 128 };
void spc_dsp_load( uint8_t const regs [spc_dsp_register_count] );
// Mutes voice n if bit 1<<b is set
enum { spc_dsp_voice_count = 8 };
static void spc_dsp_mute_voices( int mask );
// Sets destination for output samples. If out is NULL or out_size is 0,
// doesn't generate any.
typedef short spc_dsp_sample_t;
static void spc_dsp_set_output( spc_dsp_sample_t* out, int out_size );
// Number of samples written to output since it was last set, always
// a multiple of 2
static int spc_dsp_sample_count( void );
//// Emulation
// Resets DSP to power-on state. Does not affect anything set by above functions.
void spc_dsp_reset( void );
// Emulates pressing reset switch on SNES
void spc_dsp_soft_reset( void );
// Reads/writes DSP registers. For accuracy, you must first call spc_run_dsp()
// to catch the DSP up to present.
static int spc_dsp_read( int addr );
static void spc_dsp_write( int addr, int data );
// Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks
// a pair of samples will be generated.
void spc_dsp_run( int clock_count );
//// private
enum { spc_dsp_echo_hist_size = 8 };
extern spc_dsp_sample_t* m_spc_dsp_out_begin;
extern spc_dsp_sample_t* m_spc_dsp_out;
extern spc_dsp_sample_t* m_spc_dsp_out_end;
typedef struct spc_dsp_t
{
uint8_t regs [spc_dsp_register_count];
// Echo history keeps most recent 8 samples (twice the size to simplify wrap handling)
int echo_hist [spc_dsp_echo_hist_size * 2] [2];
int (*echo_hist_pos) [2]; // &echo_hist [0 to 7]
int mute_mask;
int every_other_sample; // toggles every sample
int kon; // KON value when last checked
int noise;
int counter;
int echo_offset; // offset from ESA in echo buffer
int echo_length; // number of bytes that echo_offset will stop at
int phase; // next clock cycle to run (0-31)
// Hidden registers also written to when main register is written to
int new_kon;
int endx_buf;
int envx_buf;
int outx_buf;
// Temporary state between clocks
// read once per sample
int t_pmon;
int t_non;
int t_eon;
int t_dir;
int t_koff;
// read a few clocks ahead then used
int t_brr_next_addr;
int t_adsr0;
int t_brr_header;
int t_brr_byte;
int t_srcn;
int t_esa;
int t_echo_enabled;
// internal state that is recalculated every sample
int t_dir_addr;
int t_pitch;
int t_output;
int t_looped;
int t_echo_ptr;
// left/right sums
int t_main_out [2];
int t_echo_out [2];
int t_echo_in [2];
} spc_dsp_t;
extern spc_dsp_t m_spc_dsp;
static inline int spc_dsp_read( int addr )
{
assert( (unsigned) addr < spc_dsp_register_count );
return m_spc_dsp.regs [addr];
}
static inline void spc_dsp_write( int addr, int data )
{
assert( (unsigned) addr < spc_dsp_register_count );
m_spc_dsp.regs [addr] = data;
switch ( addr & 0x0F )
{
case 0x08:
m_spc_dsp.envx_buf = data;
break;
case 0x09:
m_spc_dsp.outx_buf = data;
break;
case 0x0C:
if ( addr == 0x4C ) // KON
m_spc_dsp.new_kon = data;
if ( addr == 0x7C ) // ENDX, write always clears it regardless of data
{
m_spc_dsp.endx_buf = 0;
m_spc_dsp.regs [0x7C] = 0;
}
break;
}
}
static inline void spc_dsp_mute_voices( int mask ) { m_spc_dsp.mute_mask = mask; }
static inline void spc_dsp_set_output( spc_dsp_sample_t* out, int out_size )
{
assert( out_size % 2 == 0 ); // must be even
m_spc_dsp_out_begin = out;
m_spc_dsp_out = out;
if ( out )
out += out_size;
m_spc_dsp_out_end = out;
}
static inline int spc_dsp_sample_count( void ) { return m_spc_dsp_out - m_spc_dsp_out_begin; }
#endif

View File

@ -0,0 +1,46 @@
// Execute clock for a particular voice
#define V( clock, voice ) voice_##clock( &m_voice_state [voice] );
/* The most common sequence of clocks uses composite operations
for efficiency. For example, the following are equivalent to the
individual steps on the right:
V(2_31 ,2) -> V( 2,2) V(31,3)
V(3_0_29,2) -> V( 3,2) V( 0,3) V(29,4)
V(4_1_30,2) -> V( 4,2) V( 1,3) V(30,4) */
// Voice 0 1 2 3 4 5 6 7
PHASE( 0) V(V5,0)V(V2,1)
PHASE( 1) V(V6,0)V(V3,1)
PHASE( 2) V(V7_V4_V1,0)
PHASE( 3) V(V8_V5_V2,0)
PHASE( 4) V(V9_V6_V3,0)
PHASE( 5) V(V7_V4_V1,1)
PHASE( 6) V(V8_V5_V2,1)
PHASE( 7) V(V9_V6_V3,1)
PHASE( 8) V(V7_V4_V1,2)
PHASE( 9) V(V8_V5_V2,2)
PHASE(10) V(V9_V6_V3,2)
PHASE(11) V(V7_V4_V1,3)
PHASE(12) V(V8_V5_V2,3)
PHASE(13) V(V9_V6_V3,3)
PHASE(14) V(V7_V4_V1,4)
PHASE(15) V(V8_V5_V2,4)
PHASE(16) V(V9_V6_V3,4)
PHASE(17) V(V1,0) V(V7,5)V(V4,6)
PHASE(18) V(V8_V5_V2,5)
PHASE(19) V(V9_V6_V3,5)
PHASE(20) V(V1,1) V(V7,6)V(V4,7)
PHASE(21) V(V8,6)V(V5,7) V(V2,0) // t_brr_next_addr order dependency
PHASE(22) V(V3a,0) V(V9,6)V(V6,7) echo_22();
PHASE(23) V(V7,7) echo_23();
PHASE(24) V(V8,7) echo_24();
PHASE(25) V(V3b,0) V(V9,7) echo_25();
PHASE(26) echo_26();
PHASE(27) misc_27(); echo_27();
PHASE(28) misc_28(); echo_28();
PHASE(29) misc_29(); echo_29();
PHASE(30) misc_30();V(V3c,0) echo_30();
PHASE(31) V(V4,0) V(V1,2)
#undef V

View File

@ -0,0 +1,43 @@
// Byte order handling
#ifndef SPC_ENDIAN_H
#define SPC_ENDIAN_H
//#include <stdint.h>
static inline unsigned get_le16( void const* p )
{
return ((uint8_t const*) p) [1] * 0x100u +
((uint8_t const*) p) [0];
}
static inline int get_le16s( void const* p )
{
return ((int8_t const*) p) [1] * 0x100 +
((uint8_t const*) p) [0];
}
static inline void set_le16( void* p, unsigned n )
{
((uint8_t*) p) [1] = (uint8_t) (n >> 8);
((uint8_t*) p) [0] = (uint8_t) n;
}
// *A versions are used where data is aligned
// Sometimes BIG_ENDIAN is defined to 0x1234 or something, so treat values
// other than 1 as false.
#if BIG_ENDIAN != 1
#define GET_LE16A( addr ) (*(uint16_t const*) (addr))
#define GET_LE16SA( addr ) (*( int16_t const*) (addr))
#define SET_LE16A( addr, data ) (void) (*(uint16_t*) (addr) = (data))
#else
#define GET_LE16A( addr ) get_le16 ( addr )
#define GET_LE16SA( addr ) get_le16s( addr )
#define SET_LE16A( addr, data ) set_le16 ( addr, data )
#endif
#define GET_LE16( addr ) GET_LE16A( addr )
#define SET_LE16( addr, data ) SET_LE16A( addr, data )
#endif

View File

@ -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() {}

View File

@ -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"

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

455
src/lib/libfile.h Normal file
View File

@ -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

73
src/lib/libinterp.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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)); }

View File

@ -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;

View File

@ -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

View File

@ -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;
}
};

View File

@ -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;
}
};

View File

@ -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) {

View File

@ -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;
};

View File

@ -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);

View File

@ -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;
}
};

View File

@ -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

View File

@ -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) {

View File

@ -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;
};

View File

@ -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;
}
};

View File

@ -1,4 +1,5 @@
#include "libbase.h"
#include "libstring.h"
#include "libstring.cpp"
FILE *fp;

View File

@ -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();

View File

@ -200,5 +200,5 @@ bMemBus::bMemBus() {
}
bMemBus::~bMemBus() {
SafeFree(wram);
safe_free(wram);
}

View File

@ -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);
}

View File

@ -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();

View File

@ -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);

View File

@ -46,5 +46,5 @@ PPU::PPU() {
}
PPU::~PPU() {
SafeFree(output);
safe_free(output);
}

View File

@ -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);
};
};

View File

@ -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;
}

View File

@ -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"

256
src/smp/ssmp/core/op.h Normal file
View File

@ -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();

View File

@ -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),

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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();

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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() {
}

View File

@ -25,6 +25,9 @@ struct {
//$00f2
uint8 dsp_addr;
//$00f8,$00f9
uint8 smp_f8, smp_f9;
} status;
//ssmp.cpp

View File

@ -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