Compare commits

..

3 Commits
v015 ... v016

Author SHA1 Message Date
byuu
a3945e5772 Update to bsnes v016 release.
- Added Direct3D renderer with options for disabling hardware filtering and scanlines
    - Screenshots can now be captured in BMP, JPEG, or PNG format
    - Added config file option to specify default ROM and SRAM paths
    - Config file is always loaded from path to bsnes executable
    - Added support for analog mode joypad input
    - Up to 32 joypads can be used at once now
    - Fixed bug regarding enabling interlace mid-frame
    - Moved PPU rendering to V=240, from V=0
    - Started on new debugger. So far only debug messages and memory editor added
    - Added joypad axis resistance option for analog input mode
    - Added config file option to set window style attributes
    - Added color adjustment settings for brightness, contrast, gamma, and scanline intensity
    - Added grayscale, sepia, and invert color settings
    - Added NTSC filter by blargg, HQ2x filter by MaxSt, and Scale2x filter
    - PPU now renders scanline 224
    - Revampled about box
    - Added Game Genie / PAR cheat code support + editor, saves codes to .cht files
    - HDMA channels are no longer disabled when starting DMA, fixes Dracula X [DMV27]
    - Fixes to OAM priority mode (not perfect), fixes Final Fantasy: Mystic Quest [DMV27]
    - Fixed ENDX sound bug, fixes voices in Earthworm Jim 2 [DMV27]
    - bsnes should now compile with MinGW [DMV27]
    - Added DSP-2 support
    - Added OBC-1 support
    - Major rewrite of SNES address bus mirroring and MMIO handlers
    - Many address mirroring corrections, fixes Dezaemon, etc
    - Blocked invalid (H)DMA transfers, fixes Kirby's Super Funhouse
    - Wrote Win32 API wrapper and ported all GUI code to use it, should help to create Linux GUI later on
    - Revampled input system, should lead to customizable GUI shortcut keys later on
    - Fixed numerous bugs with input registers. Fixes many games that previous had their intro cut off (Super Conflict, etc), and many that never accepted input (Super Double Dragon, etc)
    - Moved auto joypad strobing from V=225 to V=227
    - Killed OAM table caching and window range caching, as they were actually hindering speed
    - Rewrote input configuration screen to show currently mapped keys
    - Greatly enhanced configuration options for each video profile
    - Modified fullscreen mode to exit to windowed mode when menu is activated, use F11 to toggle fullscreen mode
    - Fixed bugs in txs, wai, brk, cop, and rti opcodes [DMV27]
    - Fixed bug with emulation-mode IRQs [DMV27]
    - Initializing DMA registers to $ff [DMV27]
    - Memory writes now update CPU MDR register (open bus) [DMV27]
    - Improved ROM header detection, fixes Chou Jikuu Yousai Macross [DMV27]
    - Reading OAM no longer updates OAM latch
    - Writing to OAM high table no longer updates OAM latch
    - Writing CGRAM now updates CGRAM latch
    - Improved pseudo-hires rendering [blargg]
    - Much, much more
2006-04-25 15:51:10 +00:00
byuu
6b6233b3af Update to bsnes v015 rc3 release.
[No changelog available]
2006-04-22 01:02:32 +00:00
byuu
9f63cb1b99 Update to bsnes v015 rc2 release.
[No changelog available]
2006-04-20 00:26:54 +00:00
230 changed files with 18295 additions and 9427 deletions

202
bsnes.cfg
View File

@@ -1,202 +0,0 @@
# Applies contrast adjust filter to video output when enabled
# Works by lowering the brightness of darker colors,
# while leaving brighter colors alone; thus reducing saturation
# (default = true)
snes.video_color_curve = true
# Selects color adjustment filter for video output
# 0 = Normal (no filter, rgb555)
# 1 = Grayscale mode (l5)
# 2 = VGA mode (rgb332)
# 3 = Genesis mode (rgb333)
# (default = 0)
snes.video_color_adjust_mode = 0
# Mutes SNES audio output when enabled
# (default = false)
snes.mute = false
# 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
# Video mode at startup
# (default = 2)
video.mode = 2
# Video mode 0 (windowed)
# (default = "256x223")
video.mode_0 = "256x223"
# Video mode 1 (windowed)
# (default = "512x446")
video.mode_1 = "512x446"
# Video mode 2 (windowed)
# (default = "640x480")
video.mode_2 = "640x480"
# Video mode 3 (windowed)
# (default = "960x720")
video.mode_3 = "960x720"
# Video mode 4 (windowed)
# (default = "1152x864")
video.mode_4 = "1152x864"
# Video mode 5 (fullscreen)
# (default = "640x480@60:640x480")
video.mode_5 = "640x480@60:640x480"
# Video mode 6 (fullscreen)
# (default = "800x600@60:800x600")
video.mode_6 = "800x600@60:800x600"
# Video mode 7 (fullscreen)
# (default = "1024x768@60:1024x768")
video.mode_7 = "1024x768@60:1024x768"
# Video mode 8 (fullscreen)
# (default = "1280x960@60:1280x960")
video.mode_8 = "1280x960@60:1280x960"
# Video mode 9 (fullscreen)
# (default = "1600x1200@60:1600x1200")
video.mode_9 = "1600x1200@60:1600x1200"
# Use Video RAM instead of System RAM
# (default = true)
video.use_vram = true
# Use triple buffering
# (default = false)
video.triple_buffering = false
# Show framerate in window title
# (default = true)
gui.show_fps = true
# Allow "impossible" key combinations for joypad 1 (not recommended)
# (default = false)
input.joypad1.allow_invalid_input = false
# Joypad1 up
# (default = 0x80c8)
input.joypad1.up = 0x80c8
# Joypad1 down
# (default = 0x81d0)
input.joypad1.down = 0x81d0
# Joypad1 left
# (default = 0x82cb)
input.joypad1.left = 0x82cb
# Joypad1 right
# (default = 0x83cd)
input.joypad1.right = 0x83cd
# Joypad1 A
# (default = 0x42d)
input.joypad1.a = 0x42d
# Joypad1 B
# (default = 0x32c)
input.joypad1.b = 0x32c
# Joypad1 X
# (default = 0x11f)
input.joypad1.x = 0x11f
# Joypad1 Y
# (default = 0x1e)
input.joypad1.y = 0x1e
# Joypad1 L
# (default = 0x620)
input.joypad1.l = 0x620
# Joypad1 R
# (default = 0x72e)
input.joypad1.r = 0x72e
# Joypad1 select
# (default = 0x836)
input.joypad1.select = 0x836
# Joypad1 start
# (default = 0x91c)
input.joypad1.start = 0x91c
# Allow "impossible" key combinations for joypad 2 (not recommended)
# (default = false)
input.joypad2.allow_invalid_input = false
# Joypad2 up
# (default = 0xff14)
input.joypad2.up = 0xff14
# Joypad2 down
# (default = 0xff22)
input.joypad2.down = 0xff22
# Joypad2 left
# (default = 0xff21)
input.joypad2.left = 0xff21
# Joypad2 right
# (default = 0xff23)
input.joypad2.right = 0xff23
# Joypad2 A
# (default = 0xff25)
input.joypad2.a = 0xff25
# Joypad2 B
# (default = 0xff24)
input.joypad2.b = 0xff24
# Joypad2 X
# (default = 0xff17)
input.joypad2.x = 0xff17
# Joypad2 Y
# (default = 0xff16)
input.joypad2.y = 0xff16
# Joypad2 L
# (default = 0xff18)
input.joypad2.l = 0xff18
# Joypad2 R
# (default = 0xff26)
input.joypad2.r = 0xff26
# Joypad2 select
# (default = 0xff1a)
input.joypad2.select = 0xff1a
# Joypad2 start
# (default = 0xff1b)
input.joypad2.start = 0xff1b

BIN
bsnes.exe

Binary file not shown.

View File

@@ -1,230 +1,11 @@
#include "../../base.h"
#include "bapu_op_fn.cpp"
#include "bapu_op_mov.cpp"
#include "bapu_op_pc.cpp"
#include "bapu_op_read.cpp"
#include "bapu_op_rmw.cpp"
#include "bapu_op_misc.cpp"
#include "bapu_exec.cpp"
uint8 bAPU::spcram_read(uint16 addr) {
uint8 r;
if(addr >= 0x00f0 && addr <= 0x00ff) {
switch(addr) {
case 0xf0: //TEST -- operation unknown, supposedly returns 0x00
r = 0x00;
break;
case 0xf1: //CONTROL -- write-only register, always returns 0x00
r = 0x00;
break;
case 0xf2: //DSPADDR
r = status.dsp_addr;
break;
case 0xf3: //DSPDATA
//0x80-0xff is a read-only mirror of 0x00-0x7f
r = r_dsp->read(status.dsp_addr & 0x7f);
break;
case 0xf4: //CPUIO0
case 0xf5: //CPUIO1
case 0xf6: //CPUIO2
case 0xf7: //CPUIO3
r = r_cpu->port_read(addr & 3);
break;
case 0xf8: //???
case 0xf9: //??? -- Mapped to SPCRAM
r = spcram[addr];
break;
case 0xfa: //T0TARGET
case 0xfb: //T1TARGET
case 0xfc: //T2TARGET -- write-only registers, always return 0x00
r = 0x00;
break;
case 0xfd: //T0OUT -- 4-bit counter value
r = t0.stage3_ticks & 15;
t0.stage3_ticks = 0;
break;
case 0xfe: //T1OUT -- 4-bit counter value
r = t1.stage3_ticks & 15;
t1.stage3_ticks = 0;
break;
case 0xff: //T2OUT -- 4-bit counter value
r = t2.stage3_ticks & 15;
t2.stage3_ticks = 0;
break;
}
} else if(addr < 0xffc0) {
r = spcram[addr];
} else {
if(status.iplrom_enabled == true) {
r = iplrom[addr & 0x3f];
} else {
r = spcram[addr];
}
}
#ifdef DEBUGGER
snes->notify(SNES::SPCRAM_READ, addr, r);
#endif
return r;
}
void bAPU::spcram_write(uint16 addr, uint8 value) {
if(addr >= 0x00f0 && addr <= 0x00ff) {
switch(addr) {
case 0xf0: //TEST -- operation unknown
break;
case 0xf1: //CONTROL
status.iplrom_enabled = !!(value & 0x80);
//one-time clearing of APU port read registers,
//emulated by simulating CPU writes of 0x00
if(value & 0x20) {
r_cpu->port_write(2, 0x00);
r_cpu->port_write(3, 0x00);
}
if(value & 0x10) {
r_cpu->port_write(0, 0x00);
r_cpu->port_write(1, 0x00);
}
//0->1 transistion resets timers
if(t2.enabled == false && (value & 0x04)) {
t2.stage2_ticks = 0;
t2.stage3_ticks = 0;
}
t2.enabled = !!(value & 0x04);
if(t1.enabled == false && (value & 0x02)) {
t1.stage2_ticks = 0;
t1.stage3_ticks = 0;
}
t1.enabled = !!(value & 0x02);
if(t0.enabled == false && (value & 0x01)) {
t0.stage2_ticks = 0;
t0.stage3_ticks = 0;
}
t0.enabled = !!(value & 0x01);
break;
case 0xf2: //DSPADDR
status.dsp_addr = value;
break;
case 0xf3: //DSPDATA
//0x80-0xff is a read-only mirror of 0x00-0x7f
if(status.dsp_addr < 0x80) {
r_dsp->write(status.dsp_addr & 0x7f, value);
}
break;
case 0xf4: //CPUIO0
case 0xf5: //CPUIO1
case 0xf6: //CPUIO2
case 0xf7: //CPUIO3
port_write(addr & 3, value);
break;
case 0xf8: //???
case 0xf9: //??? - Mapped to SPCRAM
spcram[addr] = value;
break;
case 0xfa: //T0TARGET
t0.target = value;
break;
case 0xfb: //T1TARGET
t1.target = value;
break;
case 0xfc: //T2TARGET
t2.target = value;
break;
case 0xfd: //T0OUT
case 0xfe: //T1OUT
case 0xff: //T2OUT -- read-only registers
break;
}
} else {
//writes to $ffc0-$ffff always go to spcram,
//even if the iplrom is enabled.
spcram[addr] = value;
}
#ifdef DEBUGGER
snes->notify(SNES::SPCRAM_WRITE, addr, value);
#endif
}
uint8 bAPU::port_read(uint8 port) {
return spcram[0xf4 + (port & 3)];
}
void bAPU::port_write(uint8 port, uint8 value) {
spcram[0xf4 + (port & 0x03)] = value;
}
void bAPU::add_cycles(int cycles) {
status.cycles_executed += cycles;
t0.add_cycles(cycles);
t1.add_cycles(cycles);
t2.add_cycles(cycles);
}
uint32 bAPU::cycles_executed() {
uint32 r = status.cycles_executed;
status.cycles_executed = 0;
return (r << 4) + (r << 3);
}
uint8 bAPU::op_read() {
uint8 r;
r = spcram_read(regs.pc);
regs.pc++;
return r;
}
uint8 bAPU::op_read(uint8 mode, uint16 addr) {
uint8 r;
switch(mode) {
case OPMODE_ADDR:
r = spcram_read(addr);
break;
case OPMODE_DP:
r = spcram_read(((regs.p.p)?0x100:0x000) + (addr & 0xff));
break;
}
return r;
}
void bAPU::op_write(uint8 mode, uint16 addr, uint8 value) {
switch(mode) {
case OPMODE_ADDR:
spcram_write(addr, value);
break;
case OPMODE_DP:
spcram_write(((regs.p.p)?0x100:0x000) + (addr & 0xff), value);
break;
}
}
uint8 bAPU::stack_read() {
regs.sp++;
return spcram_read(0x0100 | regs.sp);
}
void bAPU::stack_write(uint8 value) {
spcram_write(0x0100 | regs.sp, value);
regs.sp--;
}
uint8 *bAPU::get_spcram_handle() {
if(!spcram) {
alert("bAPU::get_spcram_handle() -- spcram uninitialized");
}
return spcram;
}
#include "core/core.cpp"
#include "memory/memory.cpp"
#include "timing/timing.cpp"
void bAPU::run() {
exec_cycle();
exec();
}
void bAPU::power() {
@@ -281,25 +62,3 @@ bAPU::bAPU() {
bAPU::~bAPU() {
if(spcram)free(spcram);
}
//cycles should never be greater than 12. since the minimum
//cycle_frequency value is 16, we don't have to worry about
//two ticks occuring in one call to this function.
void bAPUTimer::add_cycles(int cycles) {
//stage 1 increment
stage1_ticks += cycles;
if(stage1_ticks < cycle_frequency)return;
stage1_ticks -= cycle_frequency;
if(enabled == false)return;
//stage 2 increment
stage2_ticks++;
if(stage2_ticks != target)return;
//stage 3 increment
stage2_ticks = 0;
stage3_ticks++;
stage3_ticks &= 15;
}

View File

@@ -1,20 +1,8 @@
class bAPU;
class bAPUTimer {
public:
uint8 cycle_frequency, target;
uint8 stage1_ticks, stage2_ticks, stage3_ticks;
bool enabled;
inline void add_cycles(int cycles);
};
class bAPU : public APU {
private:
typedef void (bAPU::*op)();
op optbl[256];
public:
uint16 dp, sp, rd, wr, bit, ya;
#include "core/core.h"
#include "memory/memory.h"
#include "timing/timing.h"
struct {
uint8 cycle_pos, opcode;
@@ -25,56 +13,11 @@ struct {
//$f2
uint8 dsp_addr;
}status;
} status;
bAPUTimer t0, t1, t2;
uint8 *spcram;
inline uint8 spcram_read (uint16 addr);
inline void spcram_write(uint16 addr, uint8 value);
inline uint8 port_read (uint8 port);
inline void port_write(uint8 port, uint8 value);
inline uint8 *get_spcram_handle();
inline void run();
inline uint32 cycles_executed();
inline void power();
inline void reset();
inline void add_cycles(int cycles);
enum {
OPMODE_ADDR = 0,
OPMODE_DP = 1
};
inline uint8 op_read();
inline uint8 op_read (uint8 mode, uint16 addr);
inline void op_write(uint8 mode, uint16 addr, uint8 value);
inline uint8 stack_read();
inline void stack_write(uint8 value);
inline void exec_cycle();
inline bool in_opcode();
inline void init_op_table();
inline uint8 op_adc (uint8 x, uint8 y);
inline uint16 op_addw(uint16 x, uint16 y);
inline uint8 op_and (uint8 x, uint8 y);
inline uint8 op_cmp (uint8 x, uint8 y);
inline uint16 op_cmpw(uint16 x, uint16 y);
inline uint8 op_eor (uint8 x, uint8 y);
inline uint8 op_inc (uint8 x);
inline uint16 op_incw(uint16 x);
inline uint8 op_dec (uint8 x);
inline uint16 op_decw(uint16 x);
inline uint8 op_or (uint8 x, uint8 y);
inline uint8 op_sbc (uint8 x, uint8 y);
inline uint16 op_subw(uint16 x, uint16 y);
inline uint8 op_asl (uint8 x);
inline uint8 op_lsr (uint8 x);
inline uint8 op_rol (uint8 x);
inline uint8 op_ror (uint8 x);
#include "bapu_op.h"
inline void run();
inline void power();
inline void reset();
bAPU();
~bAPU();

View File

@@ -1,168 +0,0 @@
#include "../../lib/libbase.h"
#include "../../lib/libstring.h"
#include "../../lib/libstring.cpp"
FILE *fp, *fph, *fpt;
string data, line, part, subpart;
string output_table, output_header, output_op;
int op_count;
struct _op_list {
string name;
string arg;
}op_list[64];
int line_num;
void clear_op_list() {
op_count = 0;
for(int i=0;i<64;i++) {
strcpy(op_list[i].name, "");
for(int l=0;l<8;l++) {
strcpy(op_list[i].arg[l], "");
}
}
}
void gen_header() {
int i = line_num, l, n, z;
char t[4096];
clear_op_list();
while(1) {
z = op_count++;
strcpy(part, line[i]);
strrtrim(part, "),");
strrtrim(part, ") {");
split(subpart, "(", part);
strcpy(op_list[z].name, subpart[0]);
split(part, ", ", subpart[1]);
for(l=0;l<count(part);l++) {
strcpy(op_list[z].arg[l], part[l]);
}
if(!strend(line[i], " {"))break;
i++;
}
sprintf(output_op, "void bAPU::op_$$() {\r\n switch(status.cycle_pos++) {\r\n");
sprintf(output_header, "void op_$$();\r\n");
sprintf(output_table, "optbl[$0] = &bAPU::op_$$;\r\n");
line_num = i + 1;
}
void update_line(int i, int n) {
replace(line[i], "end;", "status.cycle_pos = 0;");
}
void gen_op() {
int i = line_num, n;
char t[4096];
while(1) {
if(!strcmp(line[i], "}"))break;
n = strdec(line[i]);
sprintf(t, "%d:", n);
strltrim(line[i], t);
sprintf(t, " case %d:\r\n", n);
strcat(output_op, t);
update_line(i, n);
if(strcmp(line[i], "")) {
strcat(output_op, " ");
strcat(output_op, line[i]);
strcat(output_op, "\r\n");
}
i++;
while(1) {
if((strptr(line[i])[1]) == ':' || (strptr(line[i])[2]) == ':' || !strcmp(line[i], "}"))break;
update_line(i, n);
strcat(output_op, " ");
strcat(output_op, line[i]);
strcat(output_op, "\r\n");
i++;
}
if(!strcmp(line[i], "}"))strcat(output_op, " status.cycle_pos = 0;\r\n");
strcat(output_op, " break;\r\n");
}
strcat(output_op, " }\r\n}");
line_num = i + 1;
}
void gen_final() {
string t;
int i, l;
for(i=0;i<op_count;i++) {
strcpy(t, output_op);
replace(t, "$$", op_list[i].name);
replace(t, "$0", op_list[i].arg[0]);
replace(t, "$1", op_list[i].arg[1]);
replace(t, "$2", op_list[i].arg[2]);
replace(t, "$3", op_list[i].arg[3]);
replace(t, "$4", op_list[i].arg[4]);
replace(t, "$5", op_list[i].arg[5]);
replace(t, "$6", op_list[i].arg[6]);
replace(t, "$7", op_list[i].arg[7]);
fprintf(fp, "%s\r\n\r\n", strptr(t));
strcpy(t, output_header);
replace(t, "$$", op_list[i].name);
fprintf(fph, "%s", strptr(t));
strcpy(t, output_table);
replace(t, "$$", op_list[i].name);
replace(t, "$0", op_list[i].arg[0]);
fprintf(fpt, "%s", strptr(t));
}
}
void generate(char *dest, char *src) {
fp = fopen(src, "rb");
fseek(fp, 0, SEEK_END);
int fsize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *buf = (char*)malloc(fsize + 1);
fread(buf, 1, fsize, fp);
fclose(fp);
buf[fsize] = 0;
strcpy(data, buf);
free(buf);
replace(data, "\r\n", "\n");
split(line, "\n", data);
fp = fopen(dest, "wb");
line_num = 0;
while(line_num < count(line)) {
while(!strcmp(line[line_num], "") && line_num < count(line))line_num++;
if(line_num >= count(line))break;
gen_header();
gen_op();
gen_final();
}
fclose(fp);
}
int main() {
fph = fopen("bapu_op.h", "wb");
fpt = fopen("bapu_optable.cpp", "wb");
generate("bapu_op_mov.cpp", "op_mov.b");
generate("bapu_op_pc.cpp", "op_pc.b");
generate("bapu_op_read.cpp", "op_read.b");
generate("bapu_op_rmw.cpp", "op_rmw.b");
generate("bapu_op_misc.cpp", "op_misc.b");
fclose(fph);
fclose(fpt);
return 0;
}

View File

@@ -1,3 +0,0 @@
cl /ML /O2 bapugen.cpp
@pause
@del *.obj

View File

@@ -1 +0,0 @@
@del *.exe

View File

@@ -0,0 +1,18 @@
#define CLASS_NAME "bAPU"
#include "../../../lib/opgen.cpp"
int main() {
fph = fopen("op.h", "wb");
fpt = fopen("optable.cpp", "wb");
generate("op_mov.cpp", "op_mov.b");
generate("op_pc.cpp", "op_pc.b");
generate("op_read.cpp", "op_read.b");
generate("op_rmw.cpp", "op_rmw.b");
generate("op_misc.cpp", "op_misc.b");
fclose(fph);
fclose(fpt);
return 0;
}

3
src/apu/bapu/core/cc.bat Normal file
View File

@@ -0,0 +1,3 @@
cl /O2 /wd4996 bapugen.cpp
@pause
@del *.obj

View File

@@ -0,0 +1,8 @@
@del *.exe
@del op.h
@del optable.cpp
@del op_mov.cpp
@del op_pc.cpp
@del op_read.cpp
@del op_rmw.cpp
@del op_misc.cpp

View File

@@ -1,4 +1,11 @@
void bAPU::exec_cycle() {
#include "opfn.cpp"
#include "op_mov.cpp"
#include "op_pc.cpp"
#include "op_read.cpp"
#include "op_rmw.cpp"
#include "op_misc.cpp"
void bAPU::exec() {
if(status.cycle_pos) {
(this->*optbl[status.opcode])();
add_cycles(1);
@@ -25,5 +32,5 @@ bool bAPU::in_opcode() {
}
void bAPU::init_op_table() {
#include "bapu_optable.cpp"
#include "optable.cpp"
}

25
src/apu/bapu/core/core.h Normal file
View File

@@ -0,0 +1,25 @@
void (bAPU::*optbl[256])();
uint16 dp, sp, rd, wr, bit, ya;
inline uint8 op_adc (uint8 x, uint8 y);
inline uint16 op_addw(uint16 x, uint16 y);
inline uint8 op_and (uint8 x, uint8 y);
inline uint8 op_cmp (uint8 x, uint8 y);
inline uint16 op_cmpw(uint16 x, uint16 y);
inline uint8 op_eor (uint8 x, uint8 y);
inline uint8 op_inc (uint8 x);
inline uint16 op_incw(uint16 x);
inline uint8 op_dec (uint8 x);
inline uint16 op_decw(uint16 x);
inline uint8 op_or (uint8 x, uint8 y);
inline uint8 op_sbc (uint8 x, uint8 y);
inline uint16 op_subw(uint16 x, uint16 y);
inline uint8 op_asl (uint8 x);
inline uint8 op_lsr (uint8 x);
inline uint8 op_rol (uint8 x);
inline uint8 op_ror (uint8 x);
inline void exec();
inline bool in_opcode();
inline void init_op_table();
#include "op.h"

View File

@@ -1,55 +1,55 @@
void bAPU::op_nop() {
switch(status.cycle_pos++) {
case 1:
case 1: {
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_sleep() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
case 1: {
} break;
case 2: {
regs.pc--;
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_stop() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
case 1: {
} break;
case 2: {
regs.pc--;
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_xcn() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
case 1: {
} break;
case 2: {
} break;
case 3: {
} break;
case 4: {
regs.a = (regs.a >> 4) | (regs.a << 4);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_daa() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
case 1: {
} break;
case 2: {
if(regs.p.c || (regs.a) > 0x99) {
regs.a += 0x60;
regs.p.c = 1;
@@ -60,15 +60,15 @@ void bAPU::op_daa() {
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_das() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
case 1: {
} break;
case 2: {
if(!regs.p.c || (regs.a) > 0x99) {
regs.a -= 0x60;
regs.p.c = 0;
@@ -79,512 +79,512 @@ void bAPU::op_das() {
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_clrc() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.p.c = 0;
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_clrp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.p.p = 0;
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_setc() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.p.c = 1;
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_setp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.p.p = 1;
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_clrv() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.p.v = 0;
regs.p.h = 0;
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_notc() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
case 1: {
} break;
case 2: {
regs.p.c ^= 1;
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_ei() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
case 1: {
} break;
case 2: {
regs.p.i = 1;
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_di() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
case 1: {
} break;
case 2: {
regs.p.i = 0;
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_set0_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd |= 0x01;
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_clr0_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd &= ~0x01;
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_set1_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd |= 0x02;
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_clr1_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd &= ~0x02;
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_set2_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd |= 0x04;
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_clr2_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd &= ~0x04;
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_set3_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd |= 0x08;
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_clr3_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd &= ~0x08;
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_set4_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd |= 0x10;
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_clr4_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd &= ~0x10;
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_set5_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd |= 0x20;
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_clr5_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd &= ~0x20;
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_set6_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd |= 0x40;
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_clr6_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd &= ~0x40;
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_set7_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd |= 0x80;
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_clr7_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd &= ~0x80;
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_tset_addr_a() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
dp |= op_read() << 8;
break;
case 3:
} break;
case 3: {
rd = op_read(OPMODE_ADDR, dp);
break;
case 4:
} break;
case 4: {
regs.p.n = !!((rd & regs.a) & 0x80);
regs.p.z = ((rd & regs.a) == 0);
rd |= regs.a;
break;
case 5:
} break;
case 5: {
op_write(OPMODE_ADDR, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_tclr_addr_a() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
dp |= op_read() << 8;
break;
case 3:
} break;
case 3: {
rd = op_read(OPMODE_ADDR, dp);
break;
case 4:
} break;
case 4: {
regs.p.n = !!((rd & regs.a) & 0x80);
regs.p.z = ((rd & regs.a) == 0);
rd &=~ regs.a;
break;
case 5:
} break;
case 5: {
op_write(OPMODE_ADDR, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_push_a() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
break;
case 3:
case 1: {
} break;
case 2: {
} break;
case 3: {
stack_write(regs.a);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_push_x() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
break;
case 3:
case 1: {
} break;
case 2: {
} break;
case 3: {
stack_write(regs.x);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_push_y() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
break;
case 3:
case 1: {
} break;
case 2: {
} break;
case 3: {
stack_write(regs.y);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_push_p() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
break;
case 3:
case 1: {
} break;
case 2: {
} break;
case 3: {
stack_write(regs.p);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_pop_a() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
break;
case 3:
case 1: {
} break;
case 2: {
} break;
case 3: {
regs.a = stack_read();
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_pop_x() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
break;
case 3:
case 1: {
} break;
case 2: {
} break;
case 3: {
regs.x = stack_read();
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_pop_y() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
break;
case 3:
case 1: {
} break;
case 2: {
} break;
case 3: {
regs.y = stack_read();
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_pop_p() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
break;
case 3:
case 1: {
} break;
case 2: {
} break;
case 3: {
regs.p = stack_read();
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mul_ya() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7:
break;
case 8:
case 1: {
} break;
case 2: {
} break;
case 3: {
} break;
case 4: {
} break;
case 5: {
} break;
case 6: {
} break;
case 7: {
} break;
case 8: {
ya = regs.y * regs.a;
regs.a = ya;
regs.y = ya >> 8;
@@ -592,33 +592,33 @@ void bAPU::op_mul_ya() {
regs.p.n = !!(regs.y & 0x80);
regs.p.z = (regs.y == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_div_ya_x() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7:
break;
case 8:
break;
case 9:
break;
case 10:
break;
case 11:
case 1: {
} break;
case 2: {
} break;
case 3: {
} break;
case 4: {
} break;
case 5: {
} break;
case 6: {
} break;
case 7: {
} break;
case 8: {
} break;
case 9: {
} break;
case 10: {
} break;
case 11: {
ya = regs.ya;
//overflow set if quotient >= 256
regs.p.v = !!(regs.y >= regs.x);
@@ -637,7 +637,7 @@ void bAPU::op_div_ya_x() {
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
status.cycle_pos = 0;
break;
} break;
}
}

View File

@@ -1,710 +1,710 @@
void bAPU::op_mov_a_x() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.a = regs.x;
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_a_y() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.a = regs.y;
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_x_a() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.x = regs.a;
regs.p.n = !!(regs.x & 0x80);
regs.p.z = (regs.x == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_y_a() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.y = regs.a;
regs.p.n = !!(regs.y & 0x80);
regs.p.z = (regs.y == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_x_sp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.x = regs.sp;
regs.p.n = !!(regs.x & 0x80);
regs.p.z = (regs.x == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_sp_x() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.sp = regs.x;
regs.p.n = !!(regs.sp & 0x80);
regs.p.z = (regs.sp == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_a_const() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.a = op_read();
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_x_const() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.x = op_read();
regs.p.n = !!(regs.x & 0x80);
regs.p.z = (regs.x == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_y_const() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.y = op_read();
regs.p.n = !!(regs.y & 0x80);
regs.p.z = (regs.y == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_a_ix() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
case 1: {
} break;
case 2: {
regs.a = op_read(OPMODE_DP, regs.x);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_a_ixinc() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
break;
case 3:
case 1: {
} break;
case 2: {
} break;
case 3: {
regs.a = op_read(OPMODE_DP, regs.x++);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_a_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
sp = op_read();
break;
case 2:
} break;
case 2: {
regs.a = op_read(OPMODE_DP, sp);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_x_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
sp = op_read();
break;
case 2:
} break;
case 2: {
regs.x = op_read(OPMODE_DP, sp);
regs.p.n = !!(regs.x & 0x80);
regs.p.z = (regs.x == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_y_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
sp = op_read();
break;
case 2:
} break;
case 2: {
regs.y = op_read(OPMODE_DP, sp);
regs.p.n = !!(regs.y & 0x80);
regs.p.z = (regs.y == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_a_dpx() {
switch(status.cycle_pos++) {
case 1:
case 1: {
sp = op_read();
break;
case 2:
break;
case 3:
} break;
case 2: {
} break;
case 3: {
regs.a = op_read(OPMODE_DP, sp + regs.x);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_x_dpy() {
switch(status.cycle_pos++) {
case 1:
case 1: {
sp = op_read();
break;
case 2:
break;
case 3:
} break;
case 2: {
} break;
case 3: {
regs.x = op_read(OPMODE_DP, sp + regs.y);
regs.p.n = !!(regs.x & 0x80);
regs.p.z = (regs.x == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_y_dpx() {
switch(status.cycle_pos++) {
case 1:
case 1: {
sp = op_read();
break;
case 2:
break;
case 3:
} break;
case 2: {
} break;
case 3: {
regs.y = op_read(OPMODE_DP, sp + regs.x);
regs.p.n = !!(regs.y & 0x80);
regs.p.z = (regs.y == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_a_addr() {
switch(status.cycle_pos++) {
case 1:
case 1: {
sp = op_read();
break;
case 2:
} break;
case 2: {
sp |= op_read() << 8;
break;
case 3:
} break;
case 3: {
regs.a = op_read(OPMODE_ADDR, sp);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_x_addr() {
switch(status.cycle_pos++) {
case 1:
case 1: {
sp = op_read();
break;
case 2:
} break;
case 2: {
sp |= op_read() << 8;
break;
case 3:
} break;
case 3: {
regs.x = op_read(OPMODE_ADDR, sp);
regs.p.n = !!(regs.x & 0x80);
regs.p.z = (regs.x == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_y_addr() {
switch(status.cycle_pos++) {
case 1:
case 1: {
sp = op_read();
break;
case 2:
} break;
case 2: {
sp |= op_read() << 8;
break;
case 3:
} break;
case 3: {
regs.y = op_read(OPMODE_ADDR, sp);
regs.p.n = !!(regs.y & 0x80);
regs.p.z = (regs.y == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_a_addrx() {
switch(status.cycle_pos++) {
case 1:
case 1: {
sp = op_read();
break;
case 2:
} break;
case 2: {
sp |= op_read() << 8;
break;
case 3:
break;
case 4:
} break;
case 3: {
} break;
case 4: {
regs.a = op_read(OPMODE_ADDR, sp + regs.x);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_a_addry() {
switch(status.cycle_pos++) {
case 1:
case 1: {
sp = op_read();
break;
case 2:
} break;
case 2: {
sp |= op_read() << 8;
break;
case 3:
break;
case 4:
} break;
case 3: {
} break;
case 4: {
regs.a = op_read(OPMODE_ADDR, sp + regs.y);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_a_idpx() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read() + regs.x;
break;
case 2:
break;
case 3:
} break;
case 2: {
} break;
case 3: {
sp = op_read(OPMODE_DP, dp);
break;
case 4:
} break;
case 4: {
sp |= op_read(OPMODE_DP, dp + 1) << 8;
break;
case 5:
} break;
case 5: {
regs.a = op_read(OPMODE_ADDR, sp);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_a_idpy() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
break;
case 3:
} break;
case 2: {
} break;
case 3: {
sp = op_read(OPMODE_DP, dp);
break;
case 4:
} break;
case 4: {
sp |= op_read(OPMODE_DP, dp + 1) << 8;
break;
case 5:
} break;
case 5: {
regs.a = op_read(OPMODE_ADDR, sp + regs.y);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_dp_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
sp = op_read();
break;
case 2:
} break;
case 2: {
dp = op_read();
break;
case 3:
} break;
case 3: {
rd = op_read(OPMODE_DP, sp);
break;
case 4:
} break;
case 4: {
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_dp_const() {
switch(status.cycle_pos++) {
case 1:
case 1: {
rd = op_read();
break;
case 2:
} break;
case 2: {
dp = op_read();
break;
case 3:
break;
case 4:
} break;
case 3: {
} break;
case 4: {
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_ix_a() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
break;
case 3:
case 1: {
} break;
case 2: {
} break;
case 3: {
op_write(OPMODE_DP, regs.x, regs.a);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_ixinc_a() {
switch(status.cycle_pos++) {
case 1:
break;
case 2:
break;
case 3:
case 1: {
} break;
case 2: {
} break;
case 3: {
op_write(OPMODE_DP, regs.x++, regs.a);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_dp_a() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
break;
case 3:
} break;
case 2: {
} break;
case 3: {
op_write(OPMODE_DP, dp, regs.a);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_dp_x() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
break;
case 3:
} break;
case 2: {
} break;
case 3: {
op_write(OPMODE_DP, dp, regs.x);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_dp_y() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
break;
case 3:
} break;
case 2: {
} break;
case 3: {
op_write(OPMODE_DP, dp, regs.y);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_dpx_a() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
break;
case 3:
break;
case 4:
} break;
case 2: {
} break;
case 3: {
} break;
case 4: {
op_write(OPMODE_DP, dp + regs.x, regs.a);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_dpy_x() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
break;
case 3:
break;
case 4:
} break;
case 2: {
} break;
case 3: {
} break;
case 4: {
op_write(OPMODE_DP, dp + regs.y, regs.x);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_dpx_y() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
break;
case 3:
break;
case 4:
} break;
case 2: {
} break;
case 3: {
} break;
case 4: {
op_write(OPMODE_DP, dp + regs.x, regs.y);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_addr_a() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
dp |= op_read() << 8;
break;
case 3:
break;
case 4:
} break;
case 3: {
} break;
case 4: {
op_write(OPMODE_ADDR, dp, regs.a);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_addr_x() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
dp |= op_read() << 8;
break;
case 3:
break;
case 4:
} break;
case 3: {
} break;
case 4: {
op_write(OPMODE_ADDR, dp, regs.x);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_addr_y() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
dp |= op_read() << 8;
break;
case 3:
break;
case 4:
} break;
case 3: {
} break;
case 4: {
op_write(OPMODE_ADDR, dp, regs.y);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_addrx_a() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
dp |= op_read() << 8;
break;
case 3:
break;
case 4:
break;
case 5:
} break;
case 3: {
} break;
case 4: {
} break;
case 5: {
op_write(OPMODE_ADDR, dp + regs.x, regs.a);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_addry_a() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
dp |= op_read() << 8;
break;
case 3:
break;
case 4:
break;
case 5:
} break;
case 3: {
} break;
case 4: {
} break;
case 5: {
op_write(OPMODE_ADDR, dp + regs.y, regs.a);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_idpx_a() {
switch(status.cycle_pos++) {
case 1:
case 1: {
sp = op_read() + regs.x;
break;
case 2:
break;
case 3:
} break;
case 2: {
} break;
case 3: {
dp = op_read(OPMODE_DP, sp);
break;
case 4:
} break;
case 4: {
dp |= op_read(OPMODE_DP, sp + 1) << 8;
break;
case 5:
break;
case 6:
} break;
case 5: {
} break;
case 6: {
op_write(OPMODE_ADDR, dp, regs.a);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov_idpy_a() {
switch(status.cycle_pos++) {
case 1:
case 1: {
sp = op_read();
break;
case 2:
break;
case 3:
} break;
case 2: {
} break;
case 3: {
dp = op_read(OPMODE_DP, sp);
break;
case 4:
} break;
case 4: {
dp |= op_read(OPMODE_DP, sp + 1) << 8;
break;
case 5:
break;
case 6:
} break;
case 5: {
} break;
case 6: {
op_write(OPMODE_ADDR, dp + regs.y, regs.a);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_movw_ya_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
sp = op_read();
break;
case 2:
break;
case 3:
} break;
case 2: {
} break;
case 3: {
regs.a = op_read(OPMODE_DP, sp);
break;
case 4:
} break;
case 4: {
regs.y = op_read(OPMODE_DP, sp + 1);
regs.p.n = !!(regs.ya & 0x8000);
regs.p.z = (regs.ya == 0);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_movw_dp_ya() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
break;
case 3:
} break;
case 2: {
} break;
case 3: {
op_write(OPMODE_DP, dp, regs.a);
break;
case 4:
} break;
case 4: {
op_write(OPMODE_DP, dp + 1, regs.y);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov1_c_bit() {
switch(status.cycle_pos++) {
case 1:
case 1: {
sp = op_read();
break;
case 2:
} break;
case 2: {
sp |= op_read() << 8;
break;
case 3:
} break;
case 3: {
bit = sp >> 13;
sp &= 0x1fff;
rd = op_read(OPMODE_ADDR, sp);
regs.p.c = !!(rd & (1 << bit));
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_mov1_bit_c() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
dp |= op_read() << 8;
break;
case 3:
} break;
case 3: {
bit = dp >> 13;
dp &= 0x1fff;
rd = op_read(OPMODE_ADDR, dp);
if(regs.p.c)rd |= (1 << bit);
else rd &= ~(1 << bit);
break;
case 4:
} break;
case 4: {
op_write(OPMODE_ADDR, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,452 +1,452 @@
void bAPU::op_inc_a() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.a = op_inc(regs.a);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_inc_x() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.x = op_inc(regs.x);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_inc_y() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.y = op_inc(regs.y);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_dec_a() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.a = op_dec(regs.a);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_dec_x() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.x = op_dec(regs.x);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_dec_y() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.y = op_dec(regs.y);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_asl_a() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.a = op_asl(regs.a);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_lsr_a() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.a = op_lsr(regs.a);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_rol_a() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.a = op_rol(regs.a);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_ror_a() {
switch(status.cycle_pos++) {
case 1:
case 1: {
regs.a = op_ror(regs.a);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_inc_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd = op_inc(rd);
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_dec_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd = op_dec(rd);
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_asl_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd = op_asl(rd);
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_lsr_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd = op_lsr(rd);
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_rol_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd = op_rol(rd);
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_ror_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd = op_ror(rd);
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_inc_dpx() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
break;
case 3:
} break;
case 2: {
} break;
case 3: {
rd = op_read(OPMODE_DP, dp + regs.x);
break;
case 4:
} break;
case 4: {
rd = op_inc(rd);
op_write(OPMODE_DP, dp + regs.x, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_dec_dpx() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
break;
case 3:
} break;
case 2: {
} break;
case 3: {
rd = op_read(OPMODE_DP, dp + regs.x);
break;
case 4:
} break;
case 4: {
rd = op_dec(rd);
op_write(OPMODE_DP, dp + regs.x, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_asl_dpx() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
break;
case 3:
} break;
case 2: {
} break;
case 3: {
rd = op_read(OPMODE_DP, dp + regs.x);
break;
case 4:
} break;
case 4: {
rd = op_asl(rd);
op_write(OPMODE_DP, dp + regs.x, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_lsr_dpx() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
break;
case 3:
} break;
case 2: {
} break;
case 3: {
rd = op_read(OPMODE_DP, dp + regs.x);
break;
case 4:
} break;
case 4: {
rd = op_lsr(rd);
op_write(OPMODE_DP, dp + regs.x, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_rol_dpx() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
break;
case 3:
} break;
case 2: {
} break;
case 3: {
rd = op_read(OPMODE_DP, dp + regs.x);
break;
case 4:
} break;
case 4: {
rd = op_rol(rd);
op_write(OPMODE_DP, dp + regs.x, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_ror_dpx() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
break;
case 3:
} break;
case 2: {
} break;
case 3: {
rd = op_read(OPMODE_DP, dp + regs.x);
break;
case 4:
} break;
case 4: {
rd = op_ror(rd);
op_write(OPMODE_DP, dp + regs.x, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_inc_addr() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
dp |= op_read() << 8;
break;
case 3:
} break;
case 3: {
rd = op_read(OPMODE_ADDR, dp);
break;
case 4:
} break;
case 4: {
rd = op_inc(rd);
op_write(OPMODE_ADDR, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_dec_addr() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
dp |= op_read() << 8;
break;
case 3:
} break;
case 3: {
rd = op_read(OPMODE_ADDR, dp);
break;
case 4:
} break;
case 4: {
rd = op_dec(rd);
op_write(OPMODE_ADDR, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_asl_addr() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
dp |= op_read() << 8;
break;
case 3:
} break;
case 3: {
rd = op_read(OPMODE_ADDR, dp);
break;
case 4:
} break;
case 4: {
rd = op_asl(rd);
op_write(OPMODE_ADDR, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_lsr_addr() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
dp |= op_read() << 8;
break;
case 3:
} break;
case 3: {
rd = op_read(OPMODE_ADDR, dp);
break;
case 4:
} break;
case 4: {
rd = op_lsr(rd);
op_write(OPMODE_ADDR, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_rol_addr() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
dp |= op_read() << 8;
break;
case 3:
} break;
case 3: {
rd = op_read(OPMODE_ADDR, dp);
break;
case 4:
} break;
case 4: {
rd = op_rol(rd);
op_write(OPMODE_ADDR, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_ror_addr() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
dp |= op_read() << 8;
break;
case 3:
} break;
case 3: {
rd = op_read(OPMODE_ADDR, dp);
break;
case 4:
} break;
case 4: {
rd = op_ror(rd);
op_write(OPMODE_ADDR, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_incw_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd |= op_read(OPMODE_DP, dp + 1) << 8;
break;
case 4:
} break;
case 4: {
rd = op_incw(rd);
op_write(OPMODE_DP, dp + 1, rd >> 8);
break;
case 5:
} break;
case 5: {
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}
void bAPU::op_decw_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
rd = op_read(OPMODE_DP, dp);
break;
case 3:
} break;
case 3: {
rd |= op_read(OPMODE_DP, dp + 1) << 8;
break;
case 4:
} break;
case 4: {
rd = op_decw(rd);
op_write(OPMODE_DP, dp + 1, rd >> 8);
break;
case 5:
} break;
case 5: {
op_write(OPMODE_DP, dp, rd);
status.cycle_pos = 0;
break;
} break;
}
}

View File

@@ -0,0 +1,199 @@
uint8 bAPU::spcram_read(uint16 addr) {
uint8 r;
if(addr >= 0x00f0 && addr <= 0x00ff) {
switch(addr) {
case 0xf0: //TEST -- operation unknown, supposedly returns 0x00
r = 0x00;
break;
case 0xf1: //CONTROL -- write-only register, always returns 0x00
r = 0x00;
break;
case 0xf2: //DSPADDR
r = status.dsp_addr;
break;
case 0xf3: //DSPDATA
//0x80-0xff is a read-only mirror of 0x00-0x7f
r = r_dsp->read(status.dsp_addr & 0x7f);
break;
case 0xf4: //CPUIO0
case 0xf5: //CPUIO1
case 0xf6: //CPUIO2
case 0xf7: //CPUIO3
r = r_cpu->port_read(addr & 3);
break;
case 0xf8: //???
case 0xf9: //??? -- Mapped to SPCRAM
r = spcram[addr];
break;
case 0xfa: //T0TARGET
case 0xfb: //T1TARGET
case 0xfc: //T2TARGET -- write-only registers, always return 0x00
r = 0x00;
break;
case 0xfd: //T0OUT -- 4-bit counter value
r = t0.stage3_ticks & 15;
t0.stage3_ticks = 0;
break;
case 0xfe: //T1OUT -- 4-bit counter value
r = t1.stage3_ticks & 15;
t1.stage3_ticks = 0;
break;
case 0xff: //T2OUT -- 4-bit counter value
r = t2.stage3_ticks & 15;
t2.stage3_ticks = 0;
break;
}
} else if(addr < 0xffc0) {
r = spcram[addr];
} else {
if(status.iplrom_enabled == true) {
r = iplrom[addr & 0x3f];
} else {
r = spcram[addr];
}
}
#ifdef DEBUGGER
snes->notify(SNES::SPCRAM_READ, addr, r);
#endif
return r;
}
void bAPU::spcram_write(uint16 addr, uint8 value) {
if(addr >= 0x00f0 && addr <= 0x00ff) {
switch(addr) {
case 0xf0: //TEST -- operation unknown
break;
case 0xf1: //CONTROL
status.iplrom_enabled = !!(value & 0x80);
//one-time clearing of APU port read registers,
//emulated by simulating CPU writes of 0x00
if(value & 0x20) {
r_cpu->port_write(2, 0x00);
r_cpu->port_write(3, 0x00);
}
if(value & 0x10) {
r_cpu->port_write(0, 0x00);
r_cpu->port_write(1, 0x00);
}
//0->1 transistion resets timers
if(t2.enabled == false && (value & 0x04)) {
t2.stage2_ticks = 0;
t2.stage3_ticks = 0;
}
t2.enabled = !!(value & 0x04);
if(t1.enabled == false && (value & 0x02)) {
t1.stage2_ticks = 0;
t1.stage3_ticks = 0;
}
t1.enabled = !!(value & 0x02);
if(t0.enabled == false && (value & 0x01)) {
t0.stage2_ticks = 0;
t0.stage3_ticks = 0;
}
t0.enabled = !!(value & 0x01);
break;
case 0xf2: //DSPADDR
status.dsp_addr = value;
break;
case 0xf3: //DSPDATA
//0x80-0xff is a read-only mirror of 0x00-0x7f
if(status.dsp_addr < 0x80) {
r_dsp->write(status.dsp_addr & 0x7f, value);
}
break;
case 0xf4: //CPUIO0
case 0xf5: //CPUIO1
case 0xf6: //CPUIO2
case 0xf7: //CPUIO3
port_write(addr & 3, value);
break;
case 0xf8: //???
case 0xf9: //??? - Mapped to SPCRAM
spcram[addr] = value;
break;
case 0xfa: //T0TARGET
t0.target = value;
break;
case 0xfb: //T1TARGET
t1.target = value;
break;
case 0xfc: //T2TARGET
t2.target = value;
break;
case 0xfd: //T0OUT
case 0xfe: //T1OUT
case 0xff: //T2OUT -- read-only registers
break;
}
} else {
//writes to $ffc0-$ffff always go to spcram,
//even if the iplrom is enabled.
spcram[addr] = value;
}
#ifdef DEBUGGER
snes->notify(SNES::SPCRAM_WRITE, addr, value);
#endif
}
uint8 bAPU::port_read(uint8 port) {
return spcram[0xf4 + (port & 3)];
}
void bAPU::port_write(uint8 port, uint8 value) {
spcram[0xf4 + (port & 0x03)] = value;
}
uint8 bAPU::op_read() {
uint8 r;
r = spcram_read(regs.pc);
regs.pc++;
return r;
}
uint8 bAPU::op_read(uint8 mode, uint16 addr) {
uint8 r;
switch(mode) {
case OPMODE_ADDR:
r = spcram_read(addr);
break;
case OPMODE_DP:
r = spcram_read(((regs.p.p)?0x100:0x000) + (addr & 0xff));
break;
}
return r;
}
void bAPU::op_write(uint8 mode, uint16 addr, uint8 value) {
switch(mode) {
case OPMODE_ADDR:
spcram_write(addr, value);
break;
case OPMODE_DP:
spcram_write(((regs.p.p)?0x100:0x000) + (addr & 0xff), value);
break;
}
}
uint8 bAPU::stack_read() {
regs.sp++;
return spcram_read(0x0100 | regs.sp);
}
void bAPU::stack_write(uint8 value) {
spcram_write(0x0100 | regs.sp, value);
regs.sp--;
}
uint8 *bAPU::get_spcram_handle() {
if(!spcram) {
alert("bAPU::get_spcram_handle() -- spcram uninitialized");
}
return spcram;
}

View File

@@ -0,0 +1,14 @@
enum { OPMODE_ADDR, OPMODE_DP };
uint8 *spcram;
inline uint8 spcram_read (uint16 addr);
inline void spcram_write(uint16 addr, uint8 value);
inline uint8 port_read (uint8 port);
inline void port_write(uint8 port, uint8 value);
inline uint8 *get_spcram_handle();
inline uint8 op_read();
inline uint8 op_read (uint8 mode, uint16 addr);
inline void op_write(uint8 mode, uint16 addr, uint8 value);
inline uint8 stack_read();
inline void stack_write(uint8 value);

View File

@@ -0,0 +1,35 @@
void bAPU::add_cycles(int cycles) {
status.cycles_executed += cycles;
t0.add_cycles(cycles);
t1.add_cycles(cycles);
t2.add_cycles(cycles);
}
uint32 bAPU::cycles_executed() {
uint32 r = status.cycles_executed;
status.cycles_executed = 0;
return (r << 4) + (r << 3);
}
//cycles should never be greater than 12. since the minimum
//cycle_frequency value is 16, we don't have to worry about
//two ticks occuring in one call to this function.
void bAPU::bAPUTimer::add_cycles(int cycles) {
//stage 1 increment
stage1_ticks += cycles;
if(stage1_ticks < cycle_frequency)return;
stage1_ticks -= cycle_frequency;
if(enabled == false)return;
//stage 2 increment
stage2_ticks++;
if(stage2_ticks != target)return;
//stage 3 increment
stage2_ticks = 0;
stage3_ticks++;
stage3_ticks &= 15;
}

View File

@@ -0,0 +1,9 @@
class bAPUTimer {
public:
uint8 cycle_frequency, target;
uint8 stage1_ticks, stage2_ticks, stage3_ticks;
bool enabled;
inline void add_cycles(int cycles);
} t0, t1, t2;
inline void add_cycles(int cycles);
inline uint32 cycles_executed();

View File

@@ -1,15 +1,27 @@
//debugging extensions (~10% speed hit)
//#define DEBUGGER
#define BSNES_VERSION "0.016"
#define BSNES_TITLE "bsnes v" BSNES_VERSION
//snes core polymorphism (allow mem/cpu/apu/ppu overriding,
//~10% speed hit)
//#define POLYMORPHISM
#define MEMCORE bMemBus
#define CPUCORE bCPU
#define APUCORE bAPU
#define DSPCORE bDSP
#define PPUCORE bPPU
//game genie + pro action replay code support (~1-3% speed hit)
#define CHEAT_SYSTEM
//enable GZ, ZIP format support
#define GZIP_SUPPORT
//#define GZIP_SUPPORT
//enable JMA support
#define JMA_SUPPORT
//#define JMA_SUPPORT
//debugging extensions (~10% speed hit)
#define DEBUGGER
//snes core polymorphism
//(allow mem/cpu/apu/ppu overriding, ~10% speed hit)
//#define POLYMORPHISM
//this should be declared in the port-specific makefiles
//#define ARCH_LSB
@@ -21,20 +33,6 @@
#endif
#endif
#include <time.h>
#include "lib/libbase.h"
#include "lib/libvector.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
}
#if defined(_WIN32)
#define _WIN32_
#undef _UNIX_
@@ -45,9 +43,21 @@ inline uint16 read16(uint8 *addr, uint pos) {
#error "unknown architecture"
#endif
#include "lib/libbase.h"
#include "lib/libvector.h"
#include "lib/libstring.h"
#include "lib/libconfig.h"
#include "lib/libbpf.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 *memalloc(uint32 size, char *name = 0, ...);
void memfree(void *mem, char *name = 0, ...);
void alert(char *s, ...);
void dprintf(char *s, ...);

View File

@@ -4,6 +4,8 @@ void Cartridge::read_header() {
cart.srtc = false;
cart.sdd1 = false;
cart.c4 = false;
cart.dsp2 = false;
cart.obc1 = false;
if(cart.header_index == 0x7fc0 && cart.rom_size >= 0x401000) {
cart.mapper = EXLOROM;
@@ -31,18 +33,28 @@ uint8 rom_type = rom[cart.header_index + ROM_TYPE];
cart.c4 = true;
}
if(mapper == 0x20 && rom_type == 0x05) {
cart.dsp2 = true;
}
if(mapper == 0x30 && rom_type == 0x25) {
cart.obc1 = true;
}
cart.cart_mmio = cart.c4 | cart.dsp2 | cart.obc1;
if(rom[cart.header_index + SRAM_SIZE] & 7) {
cart.sram_size = 1024 << (rom[cart.header_index + SRAM_SIZE] & 7);
} else {
cart.sram_size = 0;
}
cart.region = (rom[cart.header_index + REGION] < 2) ? NTSC : PAL;
cart.region = ((rom[cart.header_index + REGION] & 0x7f) < 2) ? NTSC : PAL;
memcpy(&cart.name, &rom[cart.header_index + CART_NAME], 21);
cart.name[21] = 0;
for(int i=0;i<22;i++) {
for(int i = 0; i < 22; i++) {
if(cart.name[i] & 0x80) {
cart.name[i] = '?';
}
@@ -81,10 +93,15 @@ int32 score_lo = 0,
uint16 cksum, icksum;
cksum = rom[0x7fc0 + CKSUM] | (rom[0x7fc0 + CKSUM + 1] << 8);
icksum = rom[0x7fc0 + ICKSUM] | (rom[0x7fc0 + ICKSUM + 1] << 8);
if((cksum + icksum) == 0xffff)score_lo += 8;
if((cksum + icksum) == 0xffff && (cksum != 0) && (icksum != 0)) {
score_lo += 8;
}
cksum = rom[0xffc0 + CKSUM] | (rom[0xffc0 + CKSUM + 1] << 8);
icksum = rom[0xffc0 + ICKSUM] | (rom[0xffc0 + ICKSUM + 1] << 8);
if((cksum + icksum) == 0xffff)score_hi += 8;
if((cksum + icksum) == 0xffff && (cksum != 0) && (icksum != 0)) {
score_hi += 8;
}
if(rom_size < 0x401000) {
score_ex = 0;
@@ -108,25 +125,23 @@ void Cartridge::load_sram() {
return;
}
FileReader ff;
if(!ff.open(sram_fn)) {
FileReader ff(sram_fn);
if(!ff.ready()) {
sram = (uint8*)malloc(cart.sram_size);
memset(sram, 0, cart.sram_size);
return;
}
sram = ff.read(cart.sram_size);
ff.close();
}
void Cartridge::save_sram() {
if(cart.sram_size == 0)return;
FileWriter ff;
if(!ff.open(sram_fn))return;
FileWriter ff(sram_fn);
if(!ff.ready())return;
ff.write(sram, cart.sram_size);
ff.close();
}
void Cartridge::load_rom(Reader *rf) {
@@ -141,6 +156,55 @@ void Cartridge::load_rom(Reader *rf) {
}
cart.rom_size = rom_size;
cart.crc32 = 0xffffffff;
for(int32 i = 0; i < cart.rom_size; i++) {
cart.crc32 = crc32_adjust(cart.crc32, rom[i]);
}
cart.crc32 = ~cart.crc32;
}
void Cartridge::patch_rom(Reader *rf) {
uint8 *patch_data = rf->read();
uint32 patch_size = rf->size();
BPF bpf;
if(patch_size < 34)return;
uint32 target;
target = patch_data[BPF::INDEX_FORMAT + 0] << 0;
target |= patch_data[BPF::INDEX_FORMAT + 1] << 8;
target |= patch_data[BPF::INDEX_FORMAT + 2] << 16;
target |= patch_data[BPF::INDEX_FORMAT + 3] << 24;
if(target != BPF::FORMAT_SNES) {
alert("Warning: BPF patch file is not in SNES format!\n\n"
"The patch will still be applied, but it will not be "
"possible to determine whether the patch was created "
"against an image with a header or without a header.\n\n"
"bsnes is now forced to assume the patch was created "
"against a headerless source image. If this is not the "
"case, then patching will fail!\n\n"
"If you are the author of this patch, please recreate "
"the patch in SNES format.\n\n"
"If you are not the patch author, please contact the "
"author and ask them to create an SNES format BPF patch.");
}
if(bpf.apply_patch(patch_size, patch_data, rom_size, rom) == true) {
SafeFree(base_rom);
uint8 *temp = bpf.get_output_handle(rom_size);
base_rom = (uint8*)malloc(rom_size);
memcpy(base_rom, temp, rom_size);
rom = base_rom;
cart.rom_size = rom_size;
} else {
alert("Failed to apply patch.\n\nThis could be because the patch itself "
"does not match its internal checksum, because the ROM loaded does not "
"match the patch information for either the original or modified file, "
"or because the patched file does not match the checksum of either the "
"original or modified file that is stored inside the patch.\n\n"
"The original ROM image will be used instead.");
}
SafeFree(patch_data);
}
bool Cartridge::load(const char *fn) {
@@ -153,24 +217,22 @@ bool Cartridge::load(const char *fn) {
switch(Reader::detect(rom_fn)) {
case Reader::RF_NORMAL: {
FileReader ff;
if(!ff.open(rom_fn)) {
FileReader ff(rom_fn);
if(!ff.ready()) {
alert("Error loading image file (%s)!", rom_fn);
return false;
}
load_rom(static_cast<Reader*>(&ff));
ff.close();
break;
}
#ifdef GZIP_SUPPORT
case Reader::RF_GZ: {
GZReader gf;
if(!gf.open(rom_fn)) {
GZReader gf(rom_fn);
if(!gf.ready()) {
alert("Error loading image file (%s)!", rom_fn);
return false;
}
load_rom(static_cast<Reader*>(&gf));
gf.close();
break;
}
case Reader::RF_ZIP: {
@@ -193,13 +255,71 @@ bool Cartridge::load(const char *fn) {
#endif
}
int i;
//remove ROM extension
strcpy(sram_fn, fn);
for(i=strlen(fn)-1;i>=0;i--) {
if(fn[i] == '.')break;
for(int i = strlen(fn) - 1; i >= 0; i--) {
if(sram_fn[i] == '.') {
sram_fn[i] = 0;
break;
}
}
//check for bpf patch
#ifdef GZIP_SUPPORT
strcpy(patch_fn, sram_fn);
strcat(patch_fn, ".bpz");
if(fexists(patch_fn)) {
ZipReader zf(patch_fn);
patch_rom(static_cast<Reader*>(&zf));
} else {
#endif
strcpy(patch_fn, sram_fn);
strcat(patch_fn, ".bpf");
if(fexists(patch_fn)) {
FileReader ff(patch_fn);
patch_rom(static_cast<Reader*>(&ff));
}
#ifdef GZIP_SUPPORT
}
#endif
//add SRAM extension
strcat(sram_fn, ".");
strcat(sram_fn, config::fs.save_ext.sget());
//override default path (current directory)?
if(strmatch(config::fs.save_path.sget(), "") == false) {
//remove path if fs.sram_path was specified
string new_fn, parts;
strcpy(new_fn, sram_fn);
replace(new_fn, "\\", "/");
split(parts, "/", new_fn);
//add new SRAM path
strcpy(new_fn, config::fs.save_path.sget());
//append fs.base_path if fs.sram_path is not fully-qualified path
if(strbegin(new_fn, "./") == true) {
strltrim(new_fn, "./");
strcpy(new_fn[1], new_fn[0]);
strcpy(new_fn[0], config::fs.base_path.sget());
strcat(new_fn[0], new_fn[1]);
}
//finally, append SRAM file name
strcat(new_fn, parts[count(parts) - 1]);
strcpy(sram_fn, strptr(new_fn));
}
//load cheat file if it exists
strcpy(cheat_fn, sram_fn);
strrtrim(cheat_fn, config::fs.save_ext.sget());
strrtrim(cheat_fn, ".");
strcat(cheat_fn, ".cht");
if(fexists(cheat_fn) == true) {
FileReader ff(cheat_fn);
cheat.load(static_cast<Reader*>(&ff));
}
if(i != 0)sram_fn[i] = 0;
strcat(sram_fn, ".srm");
find_header();
read_header();
@@ -215,12 +335,18 @@ bool Cartridge::unload() {
r_mem->unload_cart();
if(base_rom) {
zerofree(base_rom);
SafeFree(base_rom);
}
if(sram) {
save_sram();
zerofree(sram);
SafeFree(sram);
}
if(cheat.count() > 0 || fexists(cheat_fn)) {
FileWriter ff(cheat_fn);
cheat.save(static_cast<Writer*>(&ff));
cheat.clear();
}
cart_loaded = false;

View File

@@ -1,7 +1,7 @@
class Cartridge {
public:
bool cart_loaded;
char rom_fn[4096], sram_fn[4096];
char rom_fn[4096], sram_fn[4096], cheat_fn[4096], patch_fn[4096];
uint8 *base_rom, *rom, *sram;
uint32 rom_size;
@@ -31,6 +31,7 @@ enum {
};
struct {
uint32 crc32;
uint32 header_index;
char name[32];
@@ -39,16 +40,24 @@ struct {
bool region;
uint32 mapper;
//set to true for games that need cart MMIO mapping (c4, dsp-n, ...),
//for games that map outside the standard MMIO range of $2000-$5fff
bool cart_mmio;
bool srtc;
bool sdd1;
bool c4;
bool dsp2;
bool obc1;
} cart;
void load_rom(Reader *rf);
void patch_rom(Reader *rf);
void load_sram();
void save_sram();
void find_header();
void read_header();
bool loaded() { return cart_loaded; }
bool load(const char *fn);
bool unload();

334
src/cheat/cheat.cpp Normal file
View File

@@ -0,0 +1,334 @@
#include "../base.h"
/*****
* string <> binary code translation routines
* decode() "7e1234:56" -> 0x7e123456
* encode() 0x7e123456 -> "7e1234:56"
*****/
bool Cheat::decode(char *str, uint32 &addr, uint8 &data, uint8 &type) {
string t, part;
strcpy(t, str);
strlower(t);
if(strlen(t) == 8 || (strlen(t) == 9 && strptr(t)[6] == ':')) {
type = CT_PRO_ACTION_REPLAY;
replace(t, ":", "");
uint32 r = strhex(t);
addr = r >> 8;
data = r & 0xff;
return true;
} else if(strlen(t) == 9 && strptr(t)[4] == '-') {
type = CT_GAME_GENIE;
replace(t, "-", "");
strtr(t, "df4709156bc8a23e", "0123456789abcdef");
uint32 r = strhex(t);
//8421 8421 8421 8421 8421 8421
//abcd efgh ijkl mnop qrst uvwx
//ijkl qrst opab cduv wxef ghmn
addr = (!!(r & 0x002000) << 23) | (!!(r & 0x001000) << 22) |
(!!(r & 0x000800) << 21) | (!!(r & 0x000400) << 20) |
(!!(r & 0x000020) << 19) | (!!(r & 0x000010) << 18) |
(!!(r & 0x000008) << 17) | (!!(r & 0x000004) << 16) |
(!!(r & 0x800000) << 15) | (!!(r & 0x400000) << 14) |
(!!(r & 0x200000) << 13) | (!!(r & 0x100000) << 12) |
(!!(r & 0x000002) << 11) | (!!(r & 0x000001) << 10) |
(!!(r & 0x008000) << 9) | (!!(r & 0x004000) << 8) |
(!!(r & 0x080000) << 7) | (!!(r & 0x040000) << 6) |
(!!(r & 0x020000) << 5) | (!!(r & 0x010000) << 4) |
(!!(r & 0x000200) << 3) | (!!(r & 0x000100) << 2) |
(!!(r & 0x000080) << 1) | (!!(r & 0x000040) << 0);
data = r >> 24;
return true;
}
return false;
}
bool Cheat::encode(char *str, uint32 addr, uint8 data, uint8 type) {
if(type == CT_PRO_ACTION_REPLAY) {
sprintf(str, "%0.6x:%0.2x", addr, data);
return true;
} else if(type == CT_GAME_GENIE) {
uint32 r = addr;
addr = (!!(r & 0x008000) << 23) | (!!(r & 0x004000) << 22) |
(!!(r & 0x002000) << 21) | (!!(r & 0x001000) << 20) |
(!!(r & 0x000080) << 19) | (!!(r & 0x000040) << 18) |
(!!(r & 0x000020) << 17) | (!!(r & 0x000010) << 16) |
(!!(r & 0x000200) << 15) | (!!(r & 0x000100) << 14) |
(!!(r & 0x800000) << 13) | (!!(r & 0x400000) << 12) |
(!!(r & 0x200000) << 11) | (!!(r & 0x100000) << 10) |
(!!(r & 0x000008) << 9) | (!!(r & 0x000004) << 8) |
(!!(r & 0x000002) << 7) | (!!(r & 0x000001) << 6) |
(!!(r & 0x080000) << 5) | (!!(r & 0x040000) << 4) |
(!!(r & 0x020000) << 3) | (!!(r & 0x010000) << 2) |
(!!(r & 0x000800) << 1) | (!!(r & 0x000400) << 0);
sprintf(str, "%0.2x%0.2x-%0.4x", data, addr >> 16, addr & 0xffff);
strtr(str, "0123456789abcdef", "df4709156bc8a23e");
return true;
}
return false;
}
/*****
* address lookup table manipulation and mirroring
* mirror_address() 0x000000 -> 0x7e0000
* set() enable specified address, mirror accordingly
* clear() disable specified address, mirror accordingly
*****/
uint Cheat::mirror_address(uint addr) {
if((addr & 0x40e000) != 0x0000)return addr;
//8k WRAM mirror
//$[00-3f|80-bf]:[0000-1fff] -> $7e:[0000-1fff]
return (0x7e0000 + (addr & 0x1fff));
}
void Cheat::set(uint32 addr) {
addr = mirror_address(addr);
mask[addr >> 3] |= 1 << (addr & 7);
if((addr & 0xffe000) == 0x7e0000) {
//mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff]
uint mirror;
for(int x = 0; x <= 0x3f; x++) {
mirror = ((0x00 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] |= 1 << (mirror & 7);
mirror = ((0x80 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] |= 1 << (mirror & 7);
}
}
}
void Cheat::clear(uint32 addr) {
addr = mirror_address(addr);
//is there more than one cheat code using the same address
//(and likely a different override value) that is enabled?
//if so, do not clear code lookup table entry for this address.
uint8 r;
if(read(addr, r) == true)return;
mask[addr >> 3] &= ~(1 << (addr & 7));
if((addr & 0xffe000) == 0x7e0000) {
//mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff]
uint mirror;
for(int x = 0; x <= 0x3f; x++) {
mirror = ((0x00 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] &= ~(1 << (mirror & 7));
mirror = ((0x80 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] &= ~(1 << (mirror & 7));
}
}
}
/*****
* read() is used by MemBus::read() if Cheat::enabled(addr)
* returns true to look up cheat code.
* returns true if cheat code was found, false if it was not.
* when true, cheat code substitution value is stored in data.
*****/
bool Cheat::read(uint32 addr, uint8 &data) {
addr = mirror_address(addr);
for(int i = 0; i < cheat_count; i++) {
if(enabled(i) == false)continue;
if(addr == mirror_address(index[i].addr)) {
data = index[i].data;
return true;
}
}
//code not found, or code is disabled
return false;
}
/*****
* update_cheat_status() will scan to see if any codes are
* enabled. if any are, make sure the cheat system is on.
* otherwise, turn cheat system off to speed up emulation.
*****/
void Cheat::update_cheat_status() {
for(int i = 0; i < cheat_count; i++) {
if(index[i].enabled) {
cheat_enabled = true;
return;
}
}
cheat_enabled = false;
}
/*****
* cheat list manipulation routines
*****/
bool Cheat::add(bool enable, char *code, char *desc) {
if(cheat_count >= CHEAT_LIMIT)return false;
uint32 addr, len;
uint8 data, type;
if(decode(code, addr, data, type) == false)return false;
index[cheat_count].enabled = enable;
index[cheat_count].addr = addr;
index[cheat_count].data = data;
len = strlen(code);
len = len > 16 ? 16 : len;
memcpy(index[cheat_count].code, code, len);
index[cheat_count].code[len] = 0;
len = strlen(desc);
len = len > 128 ? 128 : len;
memcpy(index[cheat_count].desc, desc, len);
index[cheat_count].desc[len] = 0;
cheat_count++;
(enable) ? set(addr) : clear(addr);
update_cheat_status();
return true;
}
bool Cheat::edit(uint32 n, bool enable, char *code, char *desc) {
if(n >= cheat_count)return false;
uint32 addr, len;
uint8 data, type;
if(decode(code, addr, data, type) == false)return false;
//disable current code and clear from code lookup table
index[n].enabled = false;
clear(index[n].addr);
//update code and enable in code lookup table
index[n].enabled = enable;
index[n].addr = addr;
index[n].data = data;
len = strlen(code);
len = len > 16 ? 16 : len;
memcpy(index[n].code, code, len);
index[n].code[len] = 0;
len = strlen(desc);
len = len > 128 ? 128 : len;
memcpy(index[n].desc, desc, len);
index[n].desc[len] = 0;
set(addr);
update_cheat_status();
return true;
}
bool Cheat::remove(uint32 n) {
if(n >= cheat_count)return false;
for(int i = n; i < cheat_count; i++) {
index[i].enabled = index[i + 1].enabled;
index[i].addr = index[i + 1].addr;
index[i].data = index[i + 1].data;
strcpy(index[i].desc, index[i + 1].desc);
}
cheat_count--;
update_cheat_status();
return true;
}
bool Cheat::get(uint32 n, bool &enable, uint32 &addr, uint8 &data, char *code, char *desc) {
if(n >= cheat_count)return false;
enable = index[n].enabled;
addr = index[n].addr;
data = index[n].data;
strcpy(code, index[n].code);
strcpy(desc, index[n].desc);
return true;
}
/*****
* code status modifier routines
*****/
bool Cheat::enabled(uint32 n) {
if(n >= cheat_count)return false;
return index[n].enabled;
}
void Cheat::enable(uint32 n) {
if(n >= cheat_count)return;
index[n].enabled = true;
set(index[n].addr);
update_cheat_status();
}
void Cheat::disable(uint32 n) {
if(n >= cheat_count)return;
index[n].enabled = false;
clear(index[n].addr);
update_cheat_status();
}
/*****
* cheat file manipulation routines
*****/
bool Cheat::load(Reader *rf) {
if(!rf->ready())return false;
uint8 *raw_data = rf->read();
string data;
raw_data[rf->size()] = 0;
strcpy(data, (char*)raw_data);
SafeFree(raw_data);
replace(data, "\r\n", "\n");
string line;
split(line, "\n", data);
for(int i = 0; i < ::count(line); i++) {
string part;
uint8 en = *(strptr(line[i]));
if(en == '+') {
strltrim(line[i], "+");
} else if(en == '-') {
strltrim(line[i], "-");
} else {
continue;
}
qreplace(line[i], " ", "");
qsplit(part, ",", line[i]);
if(::count(part) != 2)continue;
strunquote(part[1]);
add(en == '+', strptr(part[0]), strptr(part[1]));
}
return true;
}
bool Cheat::save(Writer *wf) {
if(!wf->ready())return false;
string data;
char t[4096];
strcpy(data, "");
for(int i = 0; i < cheat_count; i++) {
sprintf(t, "%c%s, \"%s\"\r\n", index[i].enabled ? '+' : '-', index[i].code, index[i].desc);
strcat(data, t);
}
wf->write((uint8*)strptr(data), strlen(data));
return true;
}
/*****
* initialization routines
*****/
void Cheat::clear() {
cheat_enabled = false;
cheat_count = 0;
memset(mask, 0, 0x200000);
for(int i = 0; i < CHEAT_LIMIT + 1; i++) {
index[i].enabled = false;
index[i].addr = 0x000000;
index[i].data = 0x00;
strcpy(index[i].code, "");
strcpy(index[i].desc, "");
}
}
Cheat::Cheat() {
clear();
}

48
src/cheat/cheat.h Normal file
View File

@@ -0,0 +1,48 @@
#define CHEAT_LIMIT 1024
class Cheat {
public:
enum { CT_PRO_ACTION_REPLAY, CT_GAME_GENIE };
struct CheatIndex {
bool enabled;
uint32 addr;
uint8 data;
char code[ 16 + 1];
char desc[128 + 1];
} index[CHEAT_LIMIT + 1];
bool cheat_enabled;
uint32 cheat_count;
uint8 mask[0x200000];
inline bool enabled() { return cheat_enabled; }
inline uint count() { return cheat_count; }
inline bool exists(uint32 addr) { return bool(mask[addr >> 3] & 1 << (addr & 7)); }
bool decode(char *str, uint32 &addr, uint8 &data, uint8 &type);
bool encode(char *str, uint32 addr, uint8 data, uint8 type);
private:
uint mirror_address(uint addr);
void set(uint32 addr);
void clear(uint32 addr);
public:
bool read(uint32 addr, uint8 &data);
void update_cheat_status();
bool add(bool enable, char *code, char *desc);
bool edit(uint32 n, bool enable, char *code, char *desc);
bool get(uint32 n, bool &enable, uint32 &addr, uint8 &data, char *code, char *desc);
bool remove (uint32 n);
bool enabled(uint32 n);
void enable (uint32 n);
void disable(uint32 n);
bool load(Reader *rf);
bool save(Writer *wf);
void clear();
Cheat();
};
extern Cheat cheat;

133
src/chip/dsp2/dsp2.cpp Normal file
View File

@@ -0,0 +1,133 @@
#include "../../base.h"
#include "dsp2_op.cpp"
void DSP2::init() {}
void DSP2::enable() {}
void DSP2::power() {
reset();
}
void DSP2::reset() {
status.waiting_for_command = true;
status.in_count = 0;
status.in_index = 0;
status.out_count = 0;
status.out_index = 0;
status.op05transparent = 0;
status.op05haslen = false;
status.op05len = 0;
status.op06haslen = false;
status.op06len = 0;
status.op09word1 = 0;
status.op09word2 = 0;
status.op0dhaslen = false;
status.op0doutlen = 0;
status.op0dinlen = 0;
}
uint8 DSP2::read(uint16 addr) {
uint8 r = 0xff;
if(status.out_count) {
r = status.output[status.out_index++];
status.out_index &= 511;
if(status.out_count == status.out_index) {
status.out_count = 0;
}
}
return r;
}
void DSP2::write(uint16 addr, uint8 data) {
if(status.waiting_for_command) {
status.command = data;
status.in_index = 0;
status.waiting_for_command = false;
switch(data) {
case 0x01: status.in_count = 32; break;
case 0x03: status.in_count = 1; break;
case 0x05: status.in_count = 1; break;
case 0x06: status.in_count = 1; break;
case 0x07: break;
case 0x08: break;
case 0x09: status.in_count = 4; break;
case 0x0d: status.in_count = 2; break;
case 0x0f: status.in_count = 0; break;
}
} else {
status.parameters[status.in_index++] = data;
status.in_index &= 511;
}
if(status.in_count == status.in_index) {
status.waiting_for_command = true;
status.out_index = 0;
switch(status.command) {
case 0x01: {
status.out_count = 32;
op01();
} break;
case 0x03: {
op03();
} break;
case 0x05: {
if(status.op05haslen) {
status.op05haslen = false;
status.out_count = status.op05len;
op05();
} else {
status.op05len = status.parameters[0];
status.in_index = 0;
status.in_count = status.op05len * 2;
status.op05haslen = true;
if(data)status.waiting_for_command = false;
}
} break;
case 0x06: {
if(status.op06haslen) {
status.op06haslen = false;
status.out_count = status.op06len;
op06();
} else {
status.op06len = status.parameters[0];
status.in_index = 0;
status.in_count = status.op06len;
status.op06haslen = true;
if(data)status.waiting_for_command = false;
}
} break;
case 0x07: break;
case 0x08: break;
case 0x09: {
op09();
} break;
case 0x0d: {
if(status.op0dhaslen) {
status.op0dhaslen = false;
status.out_count = status.op0doutlen;
op0d();
} else {
status.op0dinlen = status.parameters[0];
status.op0doutlen = status.parameters[1];
status.in_index = 0;
status.in_count = (status.op0dinlen + 1) >> 1;
status.op0dhaslen = true;
if(data)status.waiting_for_command = false;
}
} break;
case 0x0f: break;
}
}
}
DSP2::DSP2() {}
DSP2::~DSP2() {}

40
src/chip/dsp2/dsp2.h Normal file
View File

@@ -0,0 +1,40 @@
class DSP2 {
public:
struct {
bool waiting_for_command;
uint command;
uint in_count, in_index;
uint out_count, out_index;
uint8 parameters[512];
uint8 output[512];
uint8 op05transparent;
bool op05haslen;
int op05len;
bool op06haslen;
int op06len;
uint16 op09word1;
uint16 op09word2;
bool op0dhaslen;
int op0doutlen;
int op0dinlen;
} status;
void init();
void enable();
void power();
void reset();
void op01();
void op03();
void op05();
void op06();
void op09();
void op0d();
uint8 read (uint16 addr);
void write(uint16 addr, uint8 data);
DSP2();
~DSP2();
};

173
src/chip/dsp2/dsp2_op.cpp Normal file
View File

@@ -0,0 +1,173 @@
//convert bitmap to bitplane tile
void DSP2::op01() {
//op01 size is always 32 bytes input and output
//the hardware does strange things if you vary the size
unsigned char c0, c1, c2, c3;
unsigned char *p1 = status.parameters;
unsigned char *p2a = status.output;
unsigned char *p2b = status.output + 16; //halfway
//process 8 blocks of 4 bytes each
for(int j = 0; j < 8; j++) {
c0 = *p1++;
c1 = *p1++;
c2 = *p1++;
c3 = *p1++;
*p2a++ = (c0 & 0x10) << 3 |
(c0 & 0x01) << 6 |
(c1 & 0x10) << 1 |
(c1 & 0x01) << 4 |
(c2 & 0x10) >> 1 |
(c2 & 0x01) << 2 |
(c3 & 0x10) >> 3 |
(c3 & 0x01);
*p2a++ = (c0 & 0x20) << 2 |
(c0 & 0x02) << 5 |
(c1 & 0x20) |
(c1 & 0x02) << 3 |
(c2 & 0x20) >> 2 |
(c2 & 0x02) << 1 |
(c3 & 0x20) >> 4 |
(c3 & 0x02) >> 1;
*p2b++ = (c0 & 0x40) << 1 |
(c0 & 0x04) << 4 |
(c1 & 0x40) >> 1 |
(c1 & 0x04) << 2 |
(c2 & 0x40) >> 3 |
(c2 & 0x04) |
(c3 & 0x40) >> 5 |
(c3 & 0x04) >> 2;
*p2b++ = (c0 & 0x80) |
(c0 & 0x08) << 3 |
(c1 & 0x80) >> 2 |
(c1 & 0x08) << 1 |
(c2 & 0x80) >> 4 |
(c2 & 0x08) >> 1 |
(c3 & 0x80) >> 6 |
(c3 & 0x08) >> 3;
}
}
//set transparent color
void DSP2::op03() {
status.op05transparent = status.parameters[0];
}
//replace bitmap using transparent color
void DSP2::op05() {
uint8 color;
// Overlay bitmap with transparency.
// Input:
//
// Bitmap 1: i[0] <=> i[size-1]
// Bitmap 2: i[size] <=> i[2*size-1]
//
// Output:
//
// Bitmap 3: o[0] <=> o[size-1]
//
// Processing:
//
// Process all 4-bit pixels (nibbles) in the bitmap
//
// if ( BM2_pixel == transparent_color )
// pixelout = BM1_pixel
// else
// pixelout = BM2_pixel
// The max size bitmap is limited to 255 because the size parameter is a byte
// I think size=0 is an error. The behavior of the chip on size=0 is to
// return the last value written to DR if you read DR on Op05 with
// size = 0. I don't think it's worth implementing this quirk unless it's
// proven necessary.
unsigned char c1, c2;
unsigned char *p1 = status.parameters;
unsigned char *p2 = status.parameters + status.op05len;
unsigned char *p3 = status.output;
color = status.op05transparent & 0x0f;
for(int n = 0; n < status.op05len; n++) {
c1 = *p1++;
c2 = *p2++;
*p3++ = ( ((c2 >> 4) == color ) ? c1 & 0xf0 : c2 & 0xf0 ) |
( ((c2 & 0x0f) == color ) ? c1 & 0x0f : c2 & 0x0f );
}
}
//reverse bitmap
void DSP2::op06() {
// Input:
// size
// bitmap
int i, j;
for(i = 0, j = status.op06len - 1; i < status.op06len; i++, j--) {
status.output[j] = (status.parameters[i] << 4) | (status.parameters[i] >> 4);
}
}
//multiply
void DSP2::op09() {
status.out_count = 4;
status.op09word1 = status.parameters[0] | (status.parameters[1] << 8);
status.op09word2 = status.parameters[2] | (status.parameters[3] << 8);
uint32 r;
r = status.op09word1 * status.op09word2;
status.output[0] = r;
status.output[1] = r >> 8;
status.output[2] = r >> 16;
status.output[3] = r >> 24;
}
//scale bitmap
void DSP2::op0d() {
// Bit accurate hardware algorithm - uses fixed point math
// This should match the DSP2 Op0D output exactly
// I wouldn't recommend using this unless you're doing hardware debug.
// In some situations it has small visual artifacts that
// are not readily apparent on a TV screen but show up clearly
// on a monitor. Use Overload's scaling instead.
// This is for hardware verification testing.
//
// One note: the HW can do odd byte scaling but since we divide
// by two to get the count of bytes this won't work well for
// odd byte scaling (in any of the current algorithm implementations).
// So far I haven't seen Dungeon Master use it.
// If it does we can adjust the parameters and code to work with it
uint32 multiplier; // Any size int >= 32-bits
uint32 pixloc; // match size of multiplier
int i, j;
uint8 pixelarray[512];
if(status.op0dinlen <= status.op0doutlen) {
multiplier = 0x10000; // In our self defined fixed point 0x10000 == 1
} else {
multiplier = (status.op0dinlen << 17) / ((status.op0doutlen << 1) + 1);
}
pixloc = 0;
for(i = 0; i < status.op0doutlen * 2; i++) {
j = pixloc >> 16;
if(j & 1) {
pixelarray[i] = (status.parameters[j >> 1] & 0x0f);
} else {
pixelarray[i] = (status.parameters[j >> 1] & 0xf0) >> 4;
}
pixloc += multiplier;
}
for(i = 0; i < status.op0doutlen; i++) {
status.output[i] = (pixelarray[i << 1] << 4) | pixelarray[(i << 1) + 1];
}
}

88
src/chip/obc1/obc1.cpp Normal file
View File

@@ -0,0 +1,88 @@
#include "../../base.h"
void OBC1::init() {}
void OBC1::enable() {}
void OBC1::power() {
reset();
}
void OBC1::reset() {
memset(cartridge.sram, 0xff, 0x2000);
status.baseptr = (cartridge.sram[0x1ff5] & 1) ? 0x1800 : 0x1c00;
status.address = (cartridge.sram[0x1ff6] & 0x7f);
status.shift = (cartridge.sram[0x1ff6] & 3) << 1;
}
uint8 OBC1::read(uint16 addr) {
addr &= 0x1fff;
if((addr & 0x1ff8) != 0x1ff0) {
return cartridge.sram[addr];
}
switch(addr) {
case 0x1ff0:
return cartridge.sram[status.baseptr + (status.address << 2) + 0];
case 0x1ff1:
return cartridge.sram[status.baseptr + (status.address << 2) + 1];
case 0x1ff2:
return cartridge.sram[status.baseptr + (status.address << 2) + 2];
case 0x1ff3:
return cartridge.sram[status.baseptr + (status.address << 2) + 3];
case 0x1ff4:
return cartridge.sram[status.baseptr + (status.address >> 2) + 0x200];
case 0x1ff5:
case 0x1ff6:
case 0x1ff7:
return cartridge.sram[addr];
}
//never used, blocks compiler warning
return 0x00;
}
void OBC1::write(uint16 addr, uint8 data) {
addr &= 0x1fff;
if((addr & 0x1ff8) != 0x1ff0) {
cartridge.sram[addr] = data;
return;
}
switch(addr) {
case 0x1ff0:
cartridge.sram[status.baseptr + (status.address << 2) + 0] = data;
break;
case 0x1ff1:
cartridge.sram[status.baseptr + (status.address << 2) + 1] = data;
break;
case 0x1ff2:
cartridge.sram[status.baseptr + (status.address << 2) + 2] = data;
break;
case 0x1ff3:
cartridge.sram[status.baseptr + (status.address << 2) + 3] = data;
break;
case 0x1ff4: {
uint8 temp;
temp = cartridge.sram[status.baseptr + (status.address >> 2) + 0x200];
temp = (temp & ~(3 << status.shift)) | ((data & 3) << status.shift);
cartridge.sram[status.baseptr + (status.address >> 2) + 0x200] = temp;
} break;
case 0x1ff5:
status.baseptr = (data & 1) ? 0x1800 : 0x1c00;
cartridge.sram[addr] = data;
break;
case 0x1ff6:
status.address = (data & 0x7f);
status.shift = (data & 3) << 1;
cartridge.sram[addr] = data;
break;
case 0x1ff7:
cartridge.sram[addr] = data;
break;
}
}
OBC1::OBC1() {}
OBC1::~OBC1() {}

18
src/chip/obc1/obc1.h Normal file
View File

@@ -0,0 +1,18 @@
class OBC1 {
public:
struct {
uint16 address;
uint16 baseptr;
uint16 shift;
} status;
void init();
void enable();
void power();
void reset();
uint8 read (uint16 addr);
void write(uint16 addr, uint8 data);
OBC1();
~OBC1();
};

View File

@@ -4,8 +4,8 @@
void SDD1::init() {}
void SDD1::enable() {
for(int i=0x4800;i<=0x4807;i++) {
r_mem->set_mmio_mapper(i, mmio);
for(int i = 0x4800; i <= 0x4807; i++) {
r_mem->set_mmio_mapper(i, this);
}
}
@@ -50,10 +50,9 @@ uint8 SDD1::mmio_read(uint16 addr) {
}
void SDD1::mmio_write(uint16 addr, uint8 data) {
int i;
switch(addr) {
case 0x4801:
for(i=0;i<8;i++) {
for(int i = 0; i < 8; i++) {
sdd1.active[i] = !!(data & (1 << i));
}
break;
@@ -89,14 +88,4 @@ uint8 SDD1::dma_read() {
return sdd1.buffer[sdd1.buffer_index++];
}
SDD1::SDD1() {
mmio = new SDD1MMIO();
}
uint8 SDD1MMIO::read(uint32 addr) {
return sdd1->mmio_read(addr);
}
void SDD1MMIO::write(uint32 addr, uint8 value) {
sdd1->mmio_write(addr, value);
}
SDD1::SDD1() {}

View File

@@ -1,15 +1,8 @@
#include "sdd1emu.h"
class SDD1MMIO : public MMIO {
public:
inline uint8 read (uint32 addr);
inline void write(uint32 addr, uint8 value);
};
class SDD1 {
class SDD1 : public MMIO {
public:
SDD1emu sdd1emu;
SDD1MMIO *mmio;
struct {
uint32 index[4]; //memory mapping registers
@@ -19,7 +12,7 @@ struct {
uint16 buffer_size;
bool active[8]; //true when DMA channel should pass through S-DD1
bool dma_active;
}sdd1;
} sdd1;
void init();
void enable();
void power();
@@ -30,7 +23,7 @@ struct {
bool dma_active();
uint8 dma_read();
uint8 mmio_read(uint16 addr);
uint8 mmio_read (uint16 addr);
void mmio_write(uint16 addr, uint8 data);
SDD1();

View File

@@ -77,8 +77,8 @@ tm *t;
void SRTC::init() {}
void SRTC::enable() {
r_mem->set_mmio_mapper(0x2800, mmio);
r_mem->set_mmio_mapper(0x2801, mmio);
r_mem->set_mmio_mapper(0x2800, this);
r_mem->set_mmio_mapper(0x2801, this);
}
void SRTC::power() {
@@ -88,7 +88,35 @@ void SRTC::power() {
void SRTC::reset() {
srtc.index = -1;
srtc.mode = SRTC_READ;
srtc.mode = SRTC_READ;
}
uint8 SRTC::mmio_read(uint16 addr) {
switch(addr) {
case 0x2800: {
if(srtc.mode == SRTC_READ) {
if(srtc.index < 0) {
set_time();
srtc.index++;
return 0x0f; //send start message
} else if(srtc.index > MAX_SRTC_INDEX) {
srtc.index = -1;
return 0x0f; //send finished message
} else {
return srtc.data[srtc.index++];
}
} else {
return 0x00;
}
} break;
case 0x2801: {
} break;
}
return r_cpu->regs.mdr;
}
//Please see notes above about the implementation of the S-RTC
@@ -96,90 +124,66 @@ void SRTC::reset() {
//as reads will refresh the data array with the current system
//time. The write method is only here for the sake of faux
//emulation of the real hardware.
void SRTC::write(uint8 data) {
data &= 0x0f; //only the low four bits are used
void SRTC::mmio_write(uint16 addr, uint8 data) {
switch(addr) {
if(data >= 0x0d) {
switch(data) {
case 0x0d:
srtc.mode = SRTC_READ;
srtc.index = -1;
break;
case 0x0e:
srtc.mode = SRTC_COMMAND;
break;
case 0x0f:
//unknown behaviour
break;
case 0x2800: {
} break;
case 0x2801: {
data &= 0x0f; //only the low four bits are used
if(data >= 0x0d) {
switch(data) {
case 0x0d:
srtc.mode = SRTC_READ;
srtc.index = -1;
break;
case 0x0e:
srtc.mode = SRTC_COMMAND;
break;
case 0x0f:
//unknown behaviour
break;
}
return;
}
return;
}
if(srtc.mode == SRTC_WRITE) {
if(srtc.index >= 0 && srtc.index < MAX_SRTC_INDEX) {
srtc.data[srtc.index++] = data;
if(srtc.mode == SRTC_WRITE) {
if(srtc.index >= 0 && srtc.index < MAX_SRTC_INDEX) {
srtc.data[srtc.index++] = data;
if(srtc.index == MAX_SRTC_INDEX) {
//all S-RTC data has been loaded by program
srtc.data[srtc.index++] = 0x00; //day_of_week
if(srtc.index == MAX_SRTC_INDEX) {
//all S-RTC data has been loaded by program
srtc.data[srtc.index++] = 0x00; //day_of_week
}
}
} else if(srtc.mode == SRTC_COMMAND) {
switch(data) {
case SRTC_COMMAND_CLEAR:
memset(srtc.data, 0, MAX_SRTC_INDEX + 1);
srtc.index = -1;
srtc.mode = SRTC_READY;
break;
case SRTC_COMMAND_WRITE:
srtc.index = 0;
srtc.mode = SRTC_WRITE;
break;
default:
//unknown behaviour
srtc.mode = SRTC_READY;
break;
}
} else {
if(srtc.mode == SRTC_READ) {
//ignore writes while in read mode
} else if(srtc.mode == SRTC_READY) {
//unknown behaviour
}
}
} else if(srtc.mode == SRTC_COMMAND) {
switch(data) {
case SRTC_COMMAND_CLEAR:
memset(srtc.data, 0, MAX_SRTC_INDEX + 1);
srtc.index = -1;
srtc.mode = SRTC_READY;
break;
case SRTC_COMMAND_WRITE:
srtc.index = 0;
srtc.mode = SRTC_WRITE;
break;
default:
//unknown behaviour
srtc.mode = SRTC_READY;
break;
}
} else {
if(srtc.mode == SRTC_READ) {
//ignore writes while in read mode
} else if(srtc.mode == SRTC_READY) {
//unknown behaviour
}
} break;
}
}
uint8 SRTC::read() {
if(srtc.mode == SRTC_READ) {
if(srtc.index < 0) {
set_time();
srtc.index++;
return 0x0f; //send start message
} else if(srtc.index > MAX_SRTC_INDEX) {
srtc.index = -1;
return 0x0f; //send finished message
} else {
return srtc.data[srtc.index++];
}
} else {
return 0x00;
}
}
SRTC::SRTC() {
mmio = new SRTCMMIO();
}
uint8 SRTCMMIO::read(uint32 addr) {
switch(addr) {
case 0x2800:return srtc->read();
}
return r_cpu->regs.mdr;
}
void SRTCMMIO::write(uint32 addr, uint8 value) {
switch(addr) {
case 0x2801:srtc->write(value);break;
}
}
SRTC::SRTC() {}

View File

@@ -1,10 +1,4 @@
class SRTCMMIO : public MMIO {
public:
inline uint8 read (uint32 addr);
inline void write(uint32 addr, uint8 value);
};
class SRTC {
class SRTC : public MMIO {
public:
enum { MAX_SRTC_INDEX = 0x0c };
@@ -20,8 +14,6 @@ enum {
SRTC_COMMAND_CLEAR = 4
};
SRTCMMIO *mmio;
/******************************
[srtc.data structure]
Index Description Range
@@ -50,8 +42,9 @@ struct {
void enable();
void power();
void reset();
void write(uint8 data);
uint8 read();
uint8 mmio_read (uint16 addr);
void mmio_write(uint16 addr, uint8 data);
SRTC();
};

View File

@@ -2,25 +2,61 @@ Config config_file;
namespace config {
SNES::VideoColorAdjust SNES::video_color_curve(&config_file, "snes.video_color_curve",
"Applies contrast adjust filter to video output when enabled\n"
"Works by lowering the brightness of darker colors,\n"
"while leaving brighter colors alone; thus reducing saturation",
true, Setting::TRUE_FALSE);
FS::Path FS::base_path(0, "fs.base_path", "Directory that bsnes resides in", "");
SNES::VideoColorAdjust SNES::video_color_adjust_mode(&config_file, "snes.video_color_adjust_mode",
"Selects color adjustment filter for video output\n"
" 0 = Normal (no filter, rgb555)\n"
" 1 = Grayscale mode (l5)\n"
" 2 = VGA mode (rgb332)\n"
" 3 = Genesis mode (rgb333)",
0, Setting::DEC);
FS::Path FS::rom_path(&config_file, "fs.rom_path",
"Default path to look for ROM files in (\"\" = use default directory)", "");
FS::Path FS::save_path(&config_file, "fs.save_path",
"Default path for all save RAM and cheat files (\"\" = use current directory)", "");
void FS::Path::sset(const char *_data) {
string path;
strcpy(path, _data);
strunquote(path);
replace(path, "\\", "/");
//blank path?
if(strlen(path) == 0) {
Setting::sset(strptr(path));
return;
}
//missing final directory marker?
if(strptr(path)[strlen(path) - 1] != '/') {
strcat(path, "/");
}
Setting::sset(strptr(path));
}
Setting FS::save_ext(&config_file, "fs.save_ext",
"Extension to be used for all save RAM files", "srm");
SNES::VideoColorAdjust SNES::gamma_ramp(&config_file, "snes.colorfilter.gamma_ramp",
"Use precalculated TV-style gamma ramp", true, Setting::TRUE_FALSE);
SNES::VideoColorAdjust SNES::sepia(&config_file, "snes.colorfilter.sepia",
"Convert color to sepia tone", false, Setting::TRUE_FALSE);
SNES::VideoColorAdjust SNES::grayscale(&config_file, "snes.colorfilter.grayscale",
"Convert color to grayscale tone", false, Setting::TRUE_FALSE);
SNES::VideoColorAdjust SNES::invert(&config_file, "snes.colorfilter.invert",
"Invert output image colors", false, Setting::TRUE_FALSE);
SNES::VideoColorAdjust SNES::contrast(&config_file, "snes.colorfilter.contrast",
"", 0, Setting::DEC);
SNES::VideoColorAdjust SNES::brightness(&config_file, "snes.colorfilter.brightness",
"", 0, Setting::DEC);
SNES::VideoColorAdjust SNES::gamma(&config_file, "snes.colorfilter.gamma",
"", 100, Setting::DEC);
void SNES::VideoColorAdjust::set(uint32 _data) {
data = _data;
Setting::set(_data);
::snes->update_color_lookup_table();
}
Setting 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"
"", false, Setting::TRUE_FALSE);
Setting SNES::mute(&config_file, "snes.mute", "Mutes SNES audio output when enabled",
false, Setting::TRUE_FALSE);

View File

@@ -2,13 +2,23 @@ extern Config config_file;
namespace config {
extern struct FS {
static class Path : public Setting {
public:
void sset(const char *_data);
SettingOperators(Path);
} base_path, rom_path, save_path;
static Setting save_ext;
} fs;
extern struct SNES {
static class VideoColorAdjust : public Setting {
public:
void set(uint32 _data);
SettingOperators(VideoColorAdjust);
} video_color_curve, video_color_adjust_mode;
} gamma_ramp, sepia, grayscale, invert, contrast, brightness, gamma;
static Setting ntsc_merge_fields;
static Setting mute;
} snes;

View File

@@ -1,18 +1,12 @@
#include "../../base.h"
#include "bcpu_opfn.cpp"
#include "bcpu_op_read.cpp"
#include "bcpu_op_rmw.cpp"
#include "bcpu_op_write.cpp"
#include "bcpu_op_pc.cpp"
#include "bcpu_op_misc.cpp"
#include "core/core.cpp"
#include "memory/memory.cpp"
#include "dma/dma.cpp"
#include "timing/timing.cpp"
#include "bcpu_exec.cpp"
#include "bcpu_mmio.cpp"
#include "bcpu_dma.cpp"
#include "bcpu_timing.cpp"
#include "bcpu_int.cpp"
uint8 bCPU::pio_status() { return status.pio; }
@@ -49,7 +43,7 @@ void bCPU::run() {
void bCPU::scanline() {
time.hdma_triggered = false;
if(vcounter() == 225 && status.auto_joypad_poll == true) {
if(vcounter() == (overscan() == false ? 227 : 242) && status.auto_joypad_poll == true) {
snes->poll_input(SNES::DEV_JOYPAD1);
snes->poll_input(SNES::DEV_JOYPAD2);
//When the SNES auto-polls the joypads, it writes 1, then 0 to
@@ -85,7 +79,9 @@ void bCPU::power() {
void bCPU::reset() {
//reset vector location
regs.pc = r_mem->read(0xfffc) | (r_mem->read(0xfffd) << 8);
regs.pc.d = 0;
regs.pc.l = r_mem->read(0xfffc);
regs.pc.h = r_mem->read(0xfffd);
//registers are not fully reset by SNES
regs.x.h = 0x00;
@@ -97,6 +93,9 @@ void bCPU::reset() {
regs.e = 1;
regs.mdr = 0x00;
//simulate pbr:pc push during reset irq vector
regs.s.l -= 3;
time_reset();
mmio_reset();
dma_reset();
@@ -124,131 +123,8 @@ void bCPU::reset() {
add_cycles(186);
}
uint8 bCPU::port_read(uint8 port) {
return apu_port[port & 3];
}
void bCPU::port_write(uint8 port, uint8 value) {
apu_port[port & 3] = value;
}
void bCPU::cpu_c2() {
if(regs.d.l != 0x00) {
cpu_io();
}
}
void bCPU::cpu_c4(uint16 x, uint16 y) {
if(!regs.p.x && (x & 0xff00) != (y & 0xff00)) {
cpu_io();
}
}
void bCPU::cpu_c6(uint16 addr) {
if(regs.e && (regs.pc.w & 0xff00) != (addr & 0xff00)) {
cpu_io();
}
}
/* The next 3 functions control bus timing for the CPU.
* cpu_io is an I/O cycle, and always 6 clock cycles long.
* mem_read / mem_write indicate memory access bus cycle,
* they are either 6, 8, or 12 bus cycles long, depending
* both on location and the $420d.d0 FastROM enable bit.
*/
void bCPU::cpu_io() {
status.cycle_count = 6;
pre_exec_cycle();
add_cycles(6);
cycle_edge();
}
uint8 bCPU::mem_read(uint32 addr) {
status.cycle_count = r_mem->speed(addr);
pre_exec_cycle();
add_cycles(status.cycle_count - 4);
regs.mdr = r_mem->read(addr);
add_cycles(4);
cycle_edge();
return regs.mdr;
}
void bCPU::mem_write(uint32 addr, uint8 value) {
status.cycle_count = r_mem->speed(addr);
pre_exec_cycle();
add_cycles(status.cycle_count);
r_mem->write(addr, value);
cycle_edge();
}
uint32 bCPU::op_addr(uint8 mode, uint32 addr) {
switch(mode) {
case OPMODE_ADDR:
addr &= 0xffff;
break;
case OPMODE_LONG:
addr &= 0xffffff;
break;
case OPMODE_DBR:
addr = ((regs.db << 16) + addr) & 0xffffff;
break;
case OPMODE_PBR:
addr &= 0xffff;
addr = (regs.pc.b << 16) + addr;
break;
case OPMODE_DP:
addr &= 0xffff;
addr = (regs.d + addr) & 0xffff;
break;
case OPMODE_SP:
addr &= 0xffff;
addr = (regs.s + addr) & 0xffff;
break;
}
return addr;
}
uint8 bCPU::op_read() {
uint8 r;
r = mem_read(regs.pc.d);
regs.pc.w++;
return r;
}
uint8 bCPU::op_read(uint8 mode, uint32 addr) {
addr = op_addr(mode, addr);
return mem_read(addr);
}
void bCPU::op_write(uint8 mode, uint32 addr, uint8 value) {
addr = op_addr(mode, addr);
mem_write(addr, value);
}
uint8 bCPU::stack_read() {
if(regs.e) {
regs.s.l++;
} else {
regs.s.w++;
}
return mem_read(regs.s);
}
void bCPU::stack_write(uint8 value) {
mem_write(regs.s, value);
if(regs.e) {
regs.s.l--;
} else {
regs.s.w--;
}
}
bCPU::bCPU() {
mmio = new bCPUMMIO(this);
init_op_tables();
}
bCPU::~bCPU() {
delete(mmio);
}
bCPU::~bCPU() {}

View File

@@ -1,36 +1,13 @@
class bCPU;
class bCPUMMIO : public MMIO {
public:
bCPU *cpu;
inline uint8 read (uint32 addr);
inline void write(uint32 addr, uint8 value);
bCPUMMIO(bCPU *_cpu);
};
class bCPU : public CPU {
private:
void (bCPU::*optbl[256])();
public:
#include "core/core.h"
#include "memory/memory.h"
#include "dma/dma.h"
#include "timing/timing.h"
enum { NTSC = 0, PAL = 1 };
uint8 region;
public:
#include "bcpu_timing.h"
uint8 apu_port[4];
inline uint8 port_read (uint8 port);
inline void port_write(uint8 port, uint8 value);
enum {
OPMODE_ADDR = 1, OPMODE_LONG = 2,
OPMODE_DBR = 3, OPMODE_PBR = 4,
OPMODE_DP = 5, OPMODE_SP = 6
};
CPUReg24 aa, rd;
uint8 dp, sp;
enum {
DMASTATE_DMASYNC,
DMASTATE_DMASYNC2,
@@ -73,8 +50,8 @@ struct {
uint32 wram_addr;
//$4016-$4017
uint8 joypad1_strobe_value, joypad2_strobe_value;
uint8 joypad1_read_pos, joypad2_read_pos;
bool joypad_strobe_latch;
uint8 joypad1_read_pos, joypad2_read_pos;
//$4200
bool nmi_enabled;
@@ -99,51 +76,6 @@ struct {
uint16 r4216;
} status;
//$43x0.d7
enum {
DMA_CPUTOMMIO = 0,
DMA_MMIOTOCPU = 1
};
struct {
uint32 read_index; //set to 0 at beginning of DMA/HDMA
//$420b
bool active;
//$420c
bool hdma_enabled;
//$43x0
uint8 dmap;
bool direction;
bool hdma_indirect;
int8 incmode;
bool fixedxfer;
uint8 xfermode;
//$43x1
uint8 destaddr;
//$43x2-$43x3
uint16 srcaddr;
//$43x4
uint8 srcbank;
//$43x5-$43x6
union {
uint16 xfersize;
uint16 hdma_iaddr;
};
//$43x7
uint8 hdma_ibank;
//$43x8-$43x9
uint16 hdma_addr;
//$43xa
uint8 hdma_line_counter;
//$43xb/$43xf
uint8 hdma_unknown;
//hdma-specific
bool hdma_active;
bool hdma_do_transfer;
} channel[8];
inline bool hdma_test();
inline bool nmi_test();
inline bool irq_test();
@@ -158,27 +90,6 @@ struct {
inline void irq_run();
//dma commands
inline void dma_add_cycles(uint32 cycles);
inline void hdma_add_cycles(uint32 cycles);
inline void dma_run();
inline void hdma_run();
inline void hdma_update(uint8 i);
inline uint8 hdma_enabled_channels();
inline uint8 hdma_active_channels();
inline void hdmainit_activate();
inline void hdma_activate();
inline void dma_cputommio(uint8 i, uint8 index);
inline void dma_mmiotocpu(uint8 i, uint8 index);
inline void dma_write(uint8 i, uint8 index);
inline uint32 dma_addr(uint8 i);
inline uint32 hdma_addr(uint8 i);
inline uint32 hdma_iaddr(uint8 i);
inline uint16 hdma_mmio(uint8 i);
inline uint8 hdma_read(uint8 i);
inline void hdma_write(uint8 i, uint8 x);
inline void dma_reset();
//mmio commands
void mmio_reset();
uint8 mmio_r2180();
@@ -213,7 +124,6 @@ struct {
void mmio_w2182(uint8 value);
void mmio_w2183(uint8 value);
void mmio_w4016(uint8 value);
void mmio_w4017(uint8 value);
void mmio_w4200(uint8 value);
void mmio_w4201(uint8 value);
void mmio_w4202(uint8 value);
@@ -241,7 +151,10 @@ struct {
void mmio_w43xa(uint8 value, uint8 i);
void mmio_w43xb(uint8 value, uint8 i);
enum { CYCLE_OPREAD = 0, CYCLE_READ, CYCLE_WRITE, CYCLE_IO };
uint8 mmio_read (uint16 addr);
void mmio_write(uint16 addr, uint8 data);
enum { CYCLE_OPREAD, CYCLE_READ, CYCLE_WRITE, CYCLE_IO };
inline void pre_exec_cycle();
inline void exec_hdma();
inline void exec_dma();
@@ -249,68 +162,6 @@ enum { CYCLE_OPREAD = 0, CYCLE_READ, CYCLE_WRITE, CYCLE_IO };
inline void last_cycle();
inline bool in_opcode();
//cpu extra-cycle conditions
inline void cpu_c2();
inline void cpu_c4(uint16 x, uint16 y);
inline void cpu_c6(uint16 addr);
inline void cpu_io();
inline uint8 mem_read (uint32 addr);
inline void mem_write(uint32 addr, uint8 value);
inline uint32 op_addr(uint8 mode, uint32 addr);
inline uint8 op_read();
inline uint8 op_read(uint8 mode, uint32 addr);
inline void op_write(uint8 mode, uint32 addr, uint8 value);
inline uint8 stack_read();
inline void stack_write(uint8 value);
//opcode functions
inline void init_op_tables();
//op_read
inline void op_adc_b();
inline void op_adc_w();
inline void op_and_b();
inline void op_and_w();
inline void op_bit_b();
inline void op_bit_w();
inline void op_cmp_b();
inline void op_cmp_w();
inline void op_cpx_b();
inline void op_cpx_w();
inline void op_cpy_b();
inline void op_cpy_w();
inline void op_eor_b();
inline void op_eor_w();
inline void op_lda_b();
inline void op_lda_w();
inline void op_ldx_b();
inline void op_ldx_w();
inline void op_ldy_b();
inline void op_ldy_w();
inline void op_ora_b();
inline void op_ora_w();
inline void op_sbc_b();
inline void op_sbc_w();
//op_rmw
inline void op_inc_b();
inline void op_inc_w();
inline void op_dec_b();
inline void op_dec_w();
inline void op_asl_b();
inline void op_asl_w();
inline void op_lsr_b();
inline void op_lsr_w();
inline void op_rol_b();
inline void op_rol_w();
inline void op_ror_b();
inline void op_ror_w();
inline void op_trb_b();
inline void op_trb_w();
inline void op_tsb_b();
inline void op_tsb_w();
#include "bcpu_op.h"
bCPU();
~bCPU();
};

View File

@@ -1,255 +0,0 @@
void bCPU::dma_add_cycles(uint32 cycles) {
status.dma_cycle_count += cycles;
}
void bCPU::hdma_add_cycles(uint32 cycles) {
if(run_state.dma) {
status.dma_cycle_count += cycles;
}
status.hdma_cycle_count += cycles;
}
uint32 bCPU::dma_addr(uint8 i) {
uint32 r;
r = (channel[i].srcbank << 16) | (channel[i].srcaddr);
if(channel[i].fixedxfer == false) {
channel[i].srcaddr += channel[i].incmode;
}
return r;
}
void bCPU::dma_cputommio(uint8 i, uint8 index) {
uint8 x;
if(sdd1->dma_active() == true) {
x = sdd1->dma_read();
} else {
x = r_mem->read(dma_addr(i));
}
r_mem->write(0x2100 | ((channel[i].destaddr + index) & 0xff), x);
add_cycles(8);
channel[i].xfersize--;
}
void bCPU::dma_mmiotocpu(uint8 i, uint8 index) {
uint8 x;
x = r_mem->read(0x2100 | ((channel[i].destaddr + index) & 0xff));
r_mem->write(dma_addr(i), x);
add_cycles(8);
channel[i].xfersize--;
}
void bCPU::dma_write(uint8 i, uint8 index) {
if(channel[i].direction == 0) {
dma_cputommio(i, index);
} else {
dma_mmiotocpu(i, index);
}
}
void bCPU::dma_run() {
int i;
for(i=0;i<8;i++) {
if(channel[i].active == false)continue;
//first byte transferred?
if(channel[i].read_index == 0) {
sdd1->dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr),
channel[i].xfersize);
}
switch(channel[i].xfermode) {
case 0:dma_write(i, 0); break; //0
case 1:dma_write(i, channel[i].read_index & 1); break; //0,1
case 2:dma_write(i, 0); break; //0,0
case 3:dma_write(i, (channel[i].read_index >> 1) & 1);break; //0,0,1,1
case 4:dma_write(i, channel[i].read_index & 3); break; //0,1,2,3
case 5:dma_write(i, channel[i].read_index & 1); break; //0,1,0,1
case 6:dma_write(i, 0); break; //0,0 [2]
case 7:dma_write(i, (channel[i].read_index >> 1) & 1);break; //0,0,1,1 [3]
}
channel[i].read_index++;
dma_add_cycles(8);
if(channel[i].xfersize == 0) {
channel[i].active = false;
}
return;
}
status.dma_state = DMASTATE_CPUSYNC;
}
uint32 bCPU::hdma_addr(uint8 i) {
return (channel[i].srcbank << 16) | (channel[i].hdma_addr++);
}
uint32 bCPU::hdma_iaddr(uint8 i) {
return (channel[i].hdma_ibank << 16) | (channel[i].hdma_iaddr++);
}
uint16 bCPU::hdma_mmio(uint8 i) {
uint8 l = channel[i].read_index;
uint16 index;
switch(channel[i].xfermode) {
case 0:index = 0; break; //0
case 1:index = l & 1; break; //0,1
case 2:index = 0; break; //0,0
case 3:index = (l >> 1) & 1;break; //0,0,1,1
case 4:index = l & 3; break; //0,1,2,3
case 5:index = l & 1; break; //0,1,0,1
case 6:index = 0; break; //0,0 [2]
case 7:index = (l >> 1) & 1;break; //0,0,1,1 [3]
}
return (0x2100 | ((channel[i].destaddr + index) & 0xff));
}
uint8 bCPU::hdma_read(uint8 i) {
if(channel[i].direction == DMA_MMIOTOCPU) {
return r_mem->read(hdma_mmio(i));
} else if(!channel[i].hdma_indirect) {
return r_mem->read(hdma_addr(i));
} else {
return r_mem->read(hdma_iaddr(i));
}
}
void bCPU::hdma_write(uint8 i, uint8 x) {
uint32 addr;
if(channel[i].direction == DMA_CPUTOMMIO) {
addr = hdma_mmio(i);
} else if(!channel[i].hdma_indirect) {
addr = hdma_addr(i);
} else {
addr = hdma_iaddr(i);
}
if((bool)config::cpu.hdma_enable == true) {
r_mem->write(addr, x);
}
add_cycles(8);
hdma_add_cycles(8);
}
void bCPU::hdma_update(uint8 i) {
channel[i].hdma_line_counter = r_mem->read(hdma_addr(i));
add_cycles(8);
hdma_add_cycles(8);
if(channel[i].hdma_indirect) {
channel[i].hdma_iaddr = r_mem->read(hdma_addr(i)) << 8;
add_cycles(8);
hdma_add_cycles(8);
}
if(channel[i].hdma_line_counter == 0) {
channel[i].hdma_active = false;
channel[i].hdma_do_transfer = false;
return;
}
channel[i].hdma_do_transfer = true;
if(channel[i].hdma_indirect) {
channel[i].hdma_iaddr >>= 8;
channel[i].hdma_iaddr |= r_mem->read(hdma_addr(i)) << 8;
add_cycles(8);
hdma_add_cycles(8);
}
}
void bCPU::hdma_run() {
static uint8 hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
for(int i=0;i<8;i++) {
if(!channel[i].hdma_enabled || !channel[i].hdma_active)continue;
if(channel[i].hdma_do_transfer) {
int xferlen = hdma_xferlen[channel[i].xfermode];
for(channel[i].read_index=0;channel[i].read_index<xferlen;channel[i].read_index++) {
hdma_write(i, hdma_read(i));
}
}
channel[i].hdma_line_counter--;
channel[i].hdma_do_transfer = !!(channel[i].hdma_line_counter & 0x80);
if((channel[i].hdma_line_counter & 0x7f) == 0) {
hdma_update(i);
}
}
}
uint8 bCPU::hdma_enabled_channels() {
int r = 0;
for(int i=0;i<8;i++) {
if(channel[i].hdma_enabled)r++;
}
return r;
}
uint8 bCPU::hdma_active_channels() {
int r = 0;
for(int i=0;i<8;i++) {
if(channel[i].hdma_enabled && channel[i].hdma_active)r++;
}
return r;
}
/* hdmainit_activate()
* hdma_activate()
*
* Functions are called by CPU timing routine
* when an HDMA event (init or run) occurs.
*/
void bCPU::hdmainit_activate() {
for(int i=0;i<8;i++) {
channel[i].hdma_active = false;
channel[i].hdma_do_transfer = false;
}
if(hdma_enabled_channels() != 0) {
status.hdma_state = HDMASTATE_IDMASYNC;
run_state.hdma = true;
}
}
void bCPU::hdma_activate() {
if(hdma_active_channels() != 0) {
status.hdma_state = HDMASTATE_DMASYNC;
run_state.hdma = true;
}
}
void bCPU::dma_reset() {
for(int i=0;i<8;i++) {
channel[i].read_index = 0;
channel[i].active = false;
channel[i].hdma_enabled = false;
channel[i].dmap = 0x00;
channel[i].direction = 0;
channel[i].hdma_indirect = false;
channel[i].incmode = 1;
channel[i].fixedxfer = false;
channel[i].xfermode = 0;
channel[i].destaddr = 0;
channel[i].srcaddr = 0;
channel[i].xfersize = 0x0000;
//xfersize and hdma_iaddr are of union { uint16 };
//channel[i].hdma_iaddr = 0x0000;
channel[i].hdma_ibank = 0;
channel[i].hdma_addr = 0x0000;
channel[i].hdma_line_counter = 0x00;
channel[i].hdma_unknown = 0x00;
channel[i].hdma_active = false;
channel[i].hdma_do_transfer = false;
}
}

View File

@@ -1,5 +1,7 @@
void bCPU::last_cycle() {
time.nmi_pending = nmi_test();
//DMV27: keep previous nmi value,
//to allow wai and irq to work properly
time.nmi_pending = nmi_test() || time.nmi_pending;
time.irq_pending = irq_test();
}
@@ -170,7 +172,3 @@ void bCPU::exec_cycle() {
bool bCPU::in_opcode() {
return (status.cycle_pos != 0);
}
void bCPU::init_op_tables() {
#include "bcpu_optable.cpp"
}

View File

@@ -13,18 +13,37 @@ void bCPU::irq_run() {
//WDC documentation is incorrect, first cycle
//is a memory read fetch from PBR:PC
switch(status.cycle_pos++) {
case 0: add_cycles(r_mem->speed(regs.pc.d)); break;
case 1: add_cycles(6); break;
case 2: stack_write(regs.pc.b); break;
case 3: stack_write(regs.pc.h); break;
case 4: stack_write(regs.pc.l); break;
case 5: stack_write(regs.p); break;
case 6: rd.l = op_read(OPMODE_ADDR, aa.w); break;
case 7: rd.h = op_read(OPMODE_ADDR, aa.w + 1);
case 0:
//read from PBR:PC, but do not increment PC counter
mem_read(regs.pc.d);
break;
case 1:
cpu_io();
if(regs.e)status.cycle_pos++;
break;
case 2:
stack_write(regs.pc.b);
break;
case 3:
stack_write(regs.pc.h);
break;
case 4:
stack_write(regs.pc.l);
break;
case 5:
//emulation-mode irqs clear brk bit 0x10
stack_write((regs.e) ? (regs.p & ~0x10) : regs.p);
break;
case 6:
//todo: test if NMI can override IRQ here...
rd.l = op_read(OPMODE_ADDR, aa.w);
regs.pc.b = 0x00;
regs.pc.w = rd.w;
regs.p.i = 1;
regs.p.d = 0;
break;
case 7:
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
regs.pc.w = rd.w;
#ifdef DEBUGGER
//let debugger know the new IRQ opcode address
snes->notify(SNES::CPU_EXEC_OPCODE_END);

View File

@@ -3,10 +3,9 @@ void bCPU::mmio_reset() {
status.wram_addr = 0x000000;
//$4016-$4017
status.joypad1_strobe_value = 0x00;
status.joypad2_strobe_value = 0x00;
status.joypad1_read_pos = 0;
status.joypad2_read_pos = 0;
status.joypad_strobe_latch = 0;
status.joypad1_read_pos = 0;
status.joypad2_read_pos = 0;
//$4200
status.nmi_enabled = false;
@@ -18,16 +17,16 @@ void bCPU::mmio_reset() {
status.pio = 0xff;
//$4202-$4203
status.mul_a = 0x00;
status.mul_b = 0x00;
status.mul_a = 0xff;
status.mul_b = 0xff;
//$4204-$4206
status.div_a = 0x0000;
status.div_b = 0x00;
status.div_a = 0xffff;
status.div_b = 0xff;
//$4207-$420a
status.hirq_pos = 0;
status.virq_pos = 0;
status.hirq_pos = 0x01ff;
status.virq_pos = 0x01ff;
//$4214-$4217
status.r4214 = 0x0000;
@@ -59,26 +58,30 @@ uint8 bCPU::mmio_r4016() {
uint8 r;
r = regs.mdr & 0xfc;
if(status.joypad1_strobe_value == 1) {
if(status.joypad_strobe_latch == 1) {
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_B);
} else {
switch(status.joypad1_read_pos) {
case 0:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_B); break;
case 1:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_Y); break;
case 2:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_SELECT);break;
case 3:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_START); break;
case 4:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_UP); break;
case 5:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_DOWN); break;
case 6:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_LEFT); break;
case 7:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_RIGHT); break;
case 8:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_A); break;
case 9:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_X); break;
case 10:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_L); break;
case 11:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_R); break;
case 16:r |= 1;break; //joypad connected bit
default:r |= 1;break; //after 16th read, all subsequent reads return 1
case 0: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_B); break;
case 1: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_Y); break;
case 2: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_SELECT); break;
case 3: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_START); break;
case 4: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_UP); break;
case 5: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_DOWN); break;
case 6: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_LEFT); break;
case 7: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_RIGHT); break;
case 8: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_A); break;
case 9: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_X); break;
case 10: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_L); break;
case 11: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD1, SNES::JOYPAD_R); break;
case 12: break;
case 13: break;
case 14: break;
case 15: break; //bits 12-15 always return 0
//all subsequent reads return joypad connection status
case 16: r |= 1; break; //joypad connected bit
}
if(++status.joypad1_read_pos > 17)status.joypad1_read_pos = 17;
if(++status.joypad1_read_pos > 16)status.joypad1_read_pos = 16;
}
return r;
@@ -86,33 +89,37 @@ uint8 r;
//JOYSER1
//7-5 = MDR
//4-2 = Always 1
//4-2 = Always 1 (pins are connected to GND)
//1-0 = Joypad serial data
uint8 bCPU::mmio_r4017() {
uint8 r;
r = regs.mdr & 0xe0;
r |= 0x1c;
if(status.joypad2_strobe_value == 1) {
if(status.joypad_strobe_latch == 1) {
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_B);
} else {
switch(status.joypad2_read_pos) {
case 0:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_B); break;
case 1:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_Y); break;
case 2:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_SELECT);break;
case 3:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_START); break;
case 4:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_UP); break;
case 5:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_DOWN); break;
case 6:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_LEFT); break;
case 7:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_RIGHT); break;
case 8:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_A); break;
case 9:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_X); break;
case 10:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_L); break;
case 11:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_R); break;
case 16:r |= 1;break; //joypad connected bit
default:r |= 1;break; //after 16th read, all subsequent reads return 1
case 0: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_B); break;
case 1: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_Y); break;
case 2: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_SELECT); break;
case 3: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_START); break;
case 4: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_UP); break;
case 5: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_DOWN); break;
case 6: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_LEFT); break;
case 7: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_RIGHT); break;
case 8: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_A); break;
case 9: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_X); break;
case 10: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_L); break;
case 11: r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_R); break;
case 12: break;
case 13: break;
case 14: break;
case 15: break; //bits 12-15 always return 0
//all subsequent reads return joypad connection status
case 16: r |= 1; break; //joypad connected bit
}
if(++status.joypad2_read_pos > 17)status.joypad2_read_pos = 17;
if(++status.joypad2_read_pos > 16)status.joypad2_read_pos = 16;
}
return r;
@@ -320,8 +327,7 @@ uint8 bCPU::mmio_r43xb(uint8 i) {
return channel[i].hdma_unknown;
}
uint8 bCPUMMIO::read(uint32 addr) {
uint i;
uint8 bCPU::mmio_read(uint16 addr) {
//APU
if(addr >= 0x2140 && addr <= 0x217f) {
return r_apu->port_read(addr & 3);
@@ -329,47 +335,50 @@ uint i;
//HDMA
if(addr >= 0x4300 && addr <= 0x437f) {
i = (addr >> 4) & 7;
uint i = (addr >> 4) & 7;
switch(addr & 0xf) {
case 0x0:return cpu->mmio_r43x0(i);
case 0x1:return cpu->mmio_r43x1(i);
case 0x2:return cpu->mmio_r43x2(i);
case 0x3:return cpu->mmio_r43x3(i);
case 0x4:return cpu->mmio_r43x4(i);
case 0x5:return cpu->mmio_r43x5(i);
case 0x6:return cpu->mmio_r43x6(i);
case 0x7:return cpu->mmio_r43x7(i);
case 0x8:return cpu->mmio_r43x8(i);
case 0x9:return cpu->mmio_r43x9(i);
case 0xa:return cpu->mmio_r43xa(i);
case 0xb:return cpu->mmio_r43xb(i);
case 0xc:return cpu->regs.mdr; //unmapped
case 0xd:return cpu->regs.mdr; //unmapped
case 0xe:return cpu->regs.mdr; //unmapped
case 0xf:return cpu->mmio_r43xb(i); //mirror of 43xb
case 0x0: return mmio_r43x0(i);
case 0x1: return mmio_r43x1(i);
case 0x2: return mmio_r43x2(i);
case 0x3: return mmio_r43x3(i);
case 0x4: return mmio_r43x4(i);
case 0x5: return mmio_r43x5(i);
case 0x6: return mmio_r43x6(i);
case 0x7: return mmio_r43x7(i);
case 0x8: return mmio_r43x8(i);
case 0x9: return mmio_r43x9(i);
case 0xa: return mmio_r43xa(i);
case 0xb: return mmio_r43xb(i);
case 0xc: return regs.mdr; //unmapped
case 0xd: return regs.mdr; //unmapped
case 0xe: return regs.mdr; //unmapped
case 0xf: return mmio_r43xb(i); //mirror of 43xb
}
}
switch(addr) {
case 0x2180:return cpu->mmio_r2180(); //WMDATA
case 0x4016:return cpu->mmio_r4016(); //JOYSER0
case 0x4017:return cpu->mmio_r4017(); //JOYSER1
case 0x4210:return cpu->mmio_r4210(); //RDNMI
case 0x4211:return cpu->mmio_r4211(); //TIMEUP
case 0x4212:return cpu->mmio_r4212(); //HVBJOY
case 0x4213:return cpu->mmio_r4213(); //RDIO
case 0x4214:return cpu->mmio_r4214(); //RDDIVL
case 0x4215:return cpu->mmio_r4215(); //RDDIVH
case 0x4216:return cpu->mmio_r4216(); //RDMPYL
case 0x4217:return cpu->mmio_r4217(); //RDMPYH
case 0x4218:return cpu->mmio_r4218(); //JOY1L
case 0x4219:return cpu->mmio_r4219(); //JOY1H
case 0x421a:return cpu->mmio_r421a(); //JOY2L
case 0x421b:return cpu->mmio_r421b(); //JOY2H
case 0x421c:case 0x421d:case 0x421e:case 0x421f:return 0x00;
case 0x2180: return mmio_r2180(); //WMDATA
case 0x4016: return mmio_r4016(); //JOYSER0
case 0x4017: return mmio_r4017(); //JOYSER1
case 0x4210: return mmio_r4210(); //RDNMI
case 0x4211: return mmio_r4211(); //TIMEUP
case 0x4212: return mmio_r4212(); //HVBJOY
case 0x4213: return mmio_r4213(); //RDIO
case 0x4214: return mmio_r4214(); //RDDIVL
case 0x4215: return mmio_r4215(); //RDDIVH
case 0x4216: return mmio_r4216(); //RDMPYL
case 0x4217: return mmio_r4217(); //RDMPYH
case 0x4218: return mmio_r4218(); //JOY1L
case 0x4219: return mmio_r4219(); //JOY1H
case 0x421a: return mmio_r421a(); //JOY2L
case 0x421b: return mmio_r421b(); //JOY2H
case 0x421c: return 0x00;
case 0x421d: return 0x00;
case 0x421e: return 0x00;
case 0x421f: return 0x00;
}
return cpu->regs.mdr;
return regs.mdr;
}
//WMDATA
@@ -398,29 +407,26 @@ void bCPU::mmio_w2183(uint8 value) {
}
//JOYSER0
//bit 0 is shared between JOYSER0 and JOYSER1, therefore
//strobing $4016.d0 affects both controller port latches.
//$4017 bit 0 writes are ignored.
void bCPU::mmio_w4016(uint8 value) {
status.joypad1_strobe_value = !!(value & 1);
if(value == 1) {
snes->poll_input(SNES::DEV_JOYPAD1);
status.joypad1_read_pos = 0;
}
}
status.joypad_strobe_latch = bool(value & 1);
//JOYSER1
void bCPU::mmio_w4017(uint8 value) {
status.joypad2_strobe_value = !!(value & 1);
if(value == 1) {
if(status.joypad_strobe_latch == 1) {
snes->poll_input(SNES::DEV_JOYPAD1);
snes->poll_input(SNES::DEV_JOYPAD2);
status.joypad1_read_pos = 0;
status.joypad2_read_pos = 0;
}
}
//NMITIMEN
void bCPU::mmio_w4200(uint8 value) {
status.nmi_enabled = !!(value & 0x80);
status.virq_enabled = !!(value & 0x20);
status.hirq_enabled = !!(value & 0x10);
status.auto_joypad_poll = !!(value & 0x01);
status.nmi_enabled = bool(value & 0x80);
status.virq_enabled = bool(value & 0x20);
status.hirq_enabled = bool(value & 0x10);
status.auto_joypad_poll = bool(value & 0x01);
if(time.nmi_read == 0) {
if(time.nmi_line == 1 && !status.nmi_enabled == 0) {
@@ -499,27 +505,25 @@ void bCPU::mmio_w420a(uint8 value) {
//DMAEN
void bCPU::mmio_w420b(uint8 value) {
int len;
if(value != 0x00) {
run_state.dma = true;
status.dma_state = DMASTATE_DMASYNC;
}
for(int i=0;i<8;i++) {
for(int i = 0; i < 8; i++) {
if(value & (1 << i)) {
channel[i].active = true;
channel[i].hdma_enabled = false;
channel[i].hdma_active = false;
channel[i].read_index = 0;
//DMA enable does not disable active HDMA channels
channel[i].active = true;
channel[i].read_index = 0;
}
}
}
//HDMAEN
void bCPU::mmio_w420c(uint8 value) {
for(int i=0;i<8;i++) {
channel[i].hdma_enabled = !!(value & (1 << i));
channel[i].hdma_active = !!(value & (1 << i));
for(int i = 0; i < 8; i++) {
channel[i].hdma_enabled = bool(value & (1 << i));
channel[i].hdma_active = bool(value & (1 << i));
}
}
@@ -531,10 +535,10 @@ void bCPU::mmio_w420d(uint8 value) {
//DMAPx
void bCPU::mmio_w43x0(uint8 value, uint8 i) {
channel[i].dmap = value;
channel[i].direction = !!(value & 0x80);
channel[i].hdma_indirect = !!(value & 0x40);
channel[i].incmode = (value & 0x10)?-1:1;
channel[i].fixedxfer = !!(value & 0x08);
channel[i].direction = bool(value & 0x80);
channel[i].hdma_indirect = bool(value & 0x40);
channel[i].incmode = (value & 0x10) ? -1 : 1;
channel[i].fixedxfer = bool(value & 0x08);
channel[i].xfermode = value & 7;
}
@@ -593,61 +597,56 @@ void bCPU::mmio_w43xb(uint8 value, uint8 i) {
channel[i].hdma_unknown = value;
}
void bCPUMMIO::write(uint32 addr, uint8 value) {
uint8 i;
void bCPU::mmio_write(uint16 addr, uint8 data) {
//APU
if(addr >= 0x2140 && addr <= 0x217f) {
cpu->port_write(addr & 3, value);
port_write(addr & 3, data);
return;
}
//HDMA
if(addr >= 0x4300 && addr <= 0x437f) {
i = (addr >> 4) & 7;
uint i = (addr >> 4) & 7;
switch(addr & 0xf) {
case 0x0:cpu->mmio_w43x0(value, i);return;
case 0x1:cpu->mmio_w43x1(value, i);return;
case 0x2:cpu->mmio_w43x2(value, i);return;
case 0x3:cpu->mmio_w43x3(value, i);return;
case 0x4:cpu->mmio_w43x4(value, i);return;
case 0x5:cpu->mmio_w43x5(value, i);return;
case 0x6:cpu->mmio_w43x6(value, i);return;
case 0x7:cpu->mmio_w43x7(value, i);return;
case 0x8:cpu->mmio_w43x8(value, i);return;
case 0x9:cpu->mmio_w43x9(value, i);return;
case 0xa:cpu->mmio_w43xa(value, i);return;
case 0xb:cpu->mmio_w43xb(value, i);return;
case 0xc:return; //unmapped
case 0xd:return; //unmapped
case 0xe:return; //unmapped
case 0xf:cpu->mmio_w43xb(value, i);return; //mirror of 43xb
case 0x0: mmio_w43x0(data, i); return;
case 0x1: mmio_w43x1(data, i); return;
case 0x2: mmio_w43x2(data, i); return;
case 0x3: mmio_w43x3(data, i); return;
case 0x4: mmio_w43x4(data, i); return;
case 0x5: mmio_w43x5(data, i); return;
case 0x6: mmio_w43x6(data, i); return;
case 0x7: mmio_w43x7(data, i); return;
case 0x8: mmio_w43x8(data, i); return;
case 0x9: mmio_w43x9(data, i); return;
case 0xa: mmio_w43xa(data, i); return;
case 0xb: mmio_w43xb(data, i); return;
case 0xc: return; //unmapped
case 0xd: return; //unmapped
case 0xe: return; //unmapped
case 0xf: mmio_w43xb(data, i); return; //mirror of 43xb
}
}
switch(addr) {
case 0x2180:cpu->mmio_w2180(value);return; //WMDATA
case 0x2181:cpu->mmio_w2181(value);return; //WMADDL
case 0x2182:cpu->mmio_w2182(value);return; //WMADDM
case 0x2183:cpu->mmio_w2183(value);return; //WMADDH
case 0x4016:cpu->mmio_w4016(value);return; //JOYSER0
case 0x4017:cpu->mmio_w4017(value);return; //JOYSER1
case 0x4200:cpu->mmio_w4200(value);return; //NMITIMEN
case 0x4201:cpu->mmio_w4201(value);return; //WRIO
case 0x4202:cpu->mmio_w4202(value);return; //WRMPYA
case 0x4203:cpu->mmio_w4203(value);return; //WRMPYB
case 0x4204:cpu->mmio_w4204(value);return; //WRDIVL
case 0x4205:cpu->mmio_w4205(value);return; //WRDIVH
case 0x4206:cpu->mmio_w4206(value);return; //WRDIVB
case 0x4207:cpu->mmio_w4207(value);return; //HTIMEL
case 0x4208:cpu->mmio_w4208(value);return; //HTIMEH
case 0x4209:cpu->mmio_w4209(value);return; //VTIMEL
case 0x420a:cpu->mmio_w420a(value);return; //VTIMEH
case 0x420b:cpu->mmio_w420b(value);return; //DMAEN
case 0x420c:cpu->mmio_w420c(value);return; //HDMAEN
case 0x420d:cpu->mmio_w420d(value);return; //MEMSEL
case 0x2180: mmio_w2180(data); return; //WMDATA
case 0x2181: mmio_w2181(data); return; //WMADDL
case 0x2182: mmio_w2182(data); return; //WMADDM
case 0x2183: mmio_w2183(data); return; //WMADDH
case 0x4016: mmio_w4016(data); return; //JOYSER0
case 0x4017: return; //unmapped
case 0x4200: mmio_w4200(data); return; //NMITIMEN
case 0x4201: mmio_w4201(data); return; //WRIO
case 0x4202: mmio_w4202(data); return; //WRMPYA
case 0x4203: mmio_w4203(data); return; //WRMPYB
case 0x4204: mmio_w4204(data); return; //WRDIVL
case 0x4205: mmio_w4205(data); return; //WRDIVH
case 0x4206: mmio_w4206(data); return; //WRDIVB
case 0x4207: mmio_w4207(data); return; //HTIMEL
case 0x4208: mmio_w4208(data); return; //HTIMEH
case 0x4209: mmio_w4209(data); return; //VTIMEL
case 0x420a: mmio_w420a(data); return; //VTIMEH
case 0x420b: mmio_w420b(data); return; //DMAEN
case 0x420c: mmio_w420c(data); return; //HDMAEN
case 0x420d: mmio_w420d(data); return; //MEMSEL
}
}
bCPUMMIO::bCPUMMIO(bCPU *_cpu) {
cpu = _cpu;
}

View File

@@ -1,3 +0,0 @@
cl /ML /O2 bcpugen.cpp
@pause
@del *.obj

View File

@@ -1,8 +0,0 @@
@del *.exe
@del bcpu_op_misc.cpp
@del bcpu_op_pc.cpp
@del bcpu_op_read.cpp
@del bcpu_op_rmw.cpp
@del bcpu_op_write.cpp
@del bcpu_optable.cpp
@del bcpu_op.h

View File

@@ -0,0 +1,18 @@
#define CLASS_NAME "bCPU"
#include "../../../lib/opgen.cpp"
int main() {
fph = fopen("op.h", "wb");
fpt = fopen("optable.cpp", "wb");
generate("op_read.cpp", "op_read.b");
generate("op_rmw.cpp", "op_rmw.b");
generate("op_write.cpp", "op_write.b");
generate("op_pc.cpp", "op_pc.b");
generate("op_misc.cpp", "op_misc.b");
fclose(fph);
fclose(fpt);
return 0;
}

3
src/cpu/bcpu/core/cc.bat Normal file
View File

@@ -0,0 +1,3 @@
cl /O2 /wd4996 bcpugen.cpp
@pause
@del *.obj

View File

@@ -0,0 +1,8 @@
@del *.exe
@del op_misc.cpp
@del op_pc.cpp
@del op_read.cpp
@del op_rmw.cpp
@del op_write.cpp
@del optable.cpp
@del op.h

View File

@@ -0,0 +1,90 @@
#include "opfn.cpp"
#include "op_read.cpp"
#include "op_rmw.cpp"
#include "op_write.cpp"
#include "op_pc.cpp"
#include "op_misc.cpp"
void bCPU::cpu_c2() {
if(regs.d.l != 0x00) {
cpu_io();
}
}
void bCPU::cpu_c4(uint16 x, uint16 y) {
if(!regs.p.x && (x & 0xff00) != (y & 0xff00)) {
cpu_io();
}
}
void bCPU::cpu_c6(uint16 addr) {
if(regs.e && (regs.pc.w & 0xff00) != (addr & 0xff00)) {
cpu_io();
}
}
uint32 bCPU::op_addr(uint8 mode, uint32 addr) {
switch(mode) {
case OPMODE_ADDR:
addr &= 0xffff;
break;
case OPMODE_LONG:
addr &= 0xffffff;
break;
case OPMODE_DBR:
addr = ((regs.db << 16) + addr) & 0xffffff;
break;
case OPMODE_PBR:
addr &= 0xffff;
addr = (regs.pc.b << 16) + addr;
break;
case OPMODE_DP:
addr &= 0xffff;
addr = (regs.d + addr) & 0xffff;
break;
case OPMODE_SP:
addr &= 0xffff;
addr = (regs.s + addr) & 0xffff;
break;
}
return addr;
}
uint8 bCPU::op_read() {
uint8 r;
r = mem_read(regs.pc.d);
regs.pc.w++;
return r;
}
uint8 bCPU::op_read(uint8 mode, uint32 addr) {
addr = op_addr(mode, addr);
return mem_read(addr);
}
void bCPU::op_write(uint8 mode, uint32 addr, uint8 value) {
addr = op_addr(mode, addr);
mem_write(addr, value);
}
uint8 bCPU::stack_read() {
if(regs.e) {
regs.s.l++;
} else {
regs.s.w++;
}
return mem_read(regs.s);
}
void bCPU::stack_write(uint8 value) {
mem_write(regs.s, value);
if(regs.e) {
regs.s.l--;
} else {
regs.s.w--;
}
}
void bCPU::init_op_tables() {
#include "optable.cpp"
}

74
src/cpu/bcpu/core/core.h Normal file
View File

@@ -0,0 +1,74 @@
/* External functions:
* void last_cycle();
* void cpu_io();
* uint8 mem_read(uint32 addr);
* void mem_write(uint32 addr, uint8 value);
*/
void (bCPU::*optbl[256])();
CPUReg24 aa, rd;
uint8 dp, sp;
//op_read
inline void op_adc_b();
inline void op_adc_w();
inline void op_and_b();
inline void op_and_w();
inline void op_bit_b();
inline void op_bit_w();
inline void op_cmp_b();
inline void op_cmp_w();
inline void op_cpx_b();
inline void op_cpx_w();
inline void op_cpy_b();
inline void op_cpy_w();
inline void op_eor_b();
inline void op_eor_w();
inline void op_lda_b();
inline void op_lda_w();
inline void op_ldx_b();
inline void op_ldx_w();
inline void op_ldy_b();
inline void op_ldy_w();
inline void op_ora_b();
inline void op_ora_w();
inline void op_sbc_b();
inline void op_sbc_w();
//op_rmw
inline void op_inc_b();
inline void op_inc_w();
inline void op_dec_b();
inline void op_dec_w();
inline void op_asl_b();
inline void op_asl_w();
inline void op_lsr_b();
inline void op_lsr_w();
inline void op_rol_b();
inline void op_rol_w();
inline void op_ror_b();
inline void op_ror_w();
inline void op_trb_b();
inline void op_trb_w();
inline void op_tsb_b();
inline void op_tsb_w();
inline void cpu_c2();
inline void cpu_c4(uint16 x, uint16 y);
inline void cpu_c6(uint16 addr);
enum {
OPMODE_ADDR, OPMODE_LONG,
OPMODE_DBR, OPMODE_PBR,
OPMODE_DP, OPMODE_SP
};
inline uint32 op_addr(uint8 mode, uint32 addr);
inline uint8 op_read();
inline uint8 op_read(uint8 mode, uint32 addr);
inline void op_write(uint8 mode, uint32 addr, uint8 value);
inline uint8 stack_read();
inline void stack_write(uint8 value);
inline void init_op_tables();
#include "op.h"

View File

@@ -42,13 +42,13 @@ cop(0x02, 0xfff4, 0xfff5, 0xffe4, 0xffe5) {
3:stack_write(regs.pc.h);
4:stack_write(regs.pc.l);
5:stack_write(regs.p);
6:rd.l = op_read(OPMODE_LONG, (regs.e)?$1:$3);
7:last_cycle();
rd.h = op_read(OPMODE_LONG, (regs.e)?$2:$4);
6:rd.l = op_read(OPMODE_LONG, (regs.e) ? $1 : $3);
regs.pc.b = 0x00;
regs.pc.w = rd.w;
regs.p.i = 1;
regs.p.d = 0;
7:last_cycle();
rd.h = op_read(OPMODE_LONG, (regs.e) ? $2 : $4);
regs.pc.w = rd.w;
}
stp(0xdb) {
@@ -64,10 +64,16 @@ wai(0xcb) {
run_state.wai = true;
2:last_cycle();
cpu_io();
if(run_state.wai) {
//this can be cleared within last_cycle()
regs.pc.w--;
}
//no wakeup delay if last_cycle() cancelled wai
if(run_state.wai == false)end;
3:last_cycle();
cpu_io();
//sleep another i/o cycle
//note: this should alert the debugger that wai is continuing...
if(run_state.wai == true)status.cycle_pos--;
//wai wakeup delay (one i/o cycle)
4:last_cycle();
cpu_io();
}
xce(0xfb) {
@@ -183,12 +189,8 @@ txs(0x9a) {
cpu_io();
if(regs.e) {
regs.s.l = regs.x.l;
regs.p.n = !!(regs.s.l & 0x80);
regs.p.z = (regs.s.l == 0);
} else {
regs.s.w = regs.x.w;
regs.p.n = !!(regs.s.w & 0x8000);
regs.p.z = (regs.s.w == 0);
}
}

View File

@@ -126,7 +126,8 @@ rti(0x40) {
regs.y.h = 0x00;
}
4:rd.l = stack_read();
5:rd.h = stack_read();
5:if(regs.e)last_cycle();
rd.h = stack_read();
if(regs.e) {
regs.pc.w = rd.w;
end;

View File

@@ -1,6 +1,6 @@
void bCPU::op_bcc() {
switch(status.cycle_pos++) {
case 1:
case 1: {
if(!!regs.p.c)last_cycle();
rd.l = op_read();
if(!regs.p.c) {
@@ -9,21 +9,21 @@ void bCPU::op_bcc() {
} else {
status.cycle_pos = 0;
}
break;
case 2:
} break;
case 2: {
cpu_c6(aa.w);
break;
case 3:
} break;
case 3: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_bcs() {
switch(status.cycle_pos++) {
case 1:
case 1: {
if(!regs.p.c)last_cycle();
rd.l = op_read();
if(regs.p.c) {
@@ -32,21 +32,21 @@ void bCPU::op_bcs() {
} else {
status.cycle_pos = 0;
}
break;
case 2:
} break;
case 2: {
cpu_c6(aa.w);
break;
case 3:
} break;
case 3: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_bne() {
switch(status.cycle_pos++) {
case 1:
case 1: {
if(!!regs.p.z)last_cycle();
rd.l = op_read();
if(!regs.p.z) {
@@ -55,21 +55,21 @@ void bCPU::op_bne() {
} else {
status.cycle_pos = 0;
}
break;
case 2:
} break;
case 2: {
cpu_c6(aa.w);
break;
case 3:
} break;
case 3: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_beq() {
switch(status.cycle_pos++) {
case 1:
case 1: {
if(!regs.p.z)last_cycle();
rd.l = op_read();
if(regs.p.z) {
@@ -78,21 +78,21 @@ void bCPU::op_beq() {
} else {
status.cycle_pos = 0;
}
break;
case 2:
} break;
case 2: {
cpu_c6(aa.w);
break;
case 3:
} break;
case 3: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_bpl() {
switch(status.cycle_pos++) {
case 1:
case 1: {
if(!!regs.p.n)last_cycle();
rd.l = op_read();
if(!regs.p.n) {
@@ -101,21 +101,21 @@ void bCPU::op_bpl() {
} else {
status.cycle_pos = 0;
}
break;
case 2:
} break;
case 2: {
cpu_c6(aa.w);
break;
case 3:
} break;
case 3: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_bmi() {
switch(status.cycle_pos++) {
case 1:
case 1: {
if(!regs.p.n)last_cycle();
rd.l = op_read();
if(regs.p.n) {
@@ -124,21 +124,21 @@ void bCPU::op_bmi() {
} else {
status.cycle_pos = 0;
}
break;
case 2:
} break;
case 2: {
cpu_c6(aa.w);
break;
case 3:
} break;
case 3: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_bvc() {
switch(status.cycle_pos++) {
case 1:
case 1: {
if(!!regs.p.v)last_cycle();
rd.l = op_read();
if(!regs.p.v) {
@@ -147,21 +147,21 @@ void bCPU::op_bvc() {
} else {
status.cycle_pos = 0;
}
break;
case 2:
} break;
case 2: {
cpu_c6(aa.w);
break;
case 3:
} break;
case 3: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_bvs() {
switch(status.cycle_pos++) {
case 1:
case 1: {
if(!regs.p.v)last_cycle();
rd.l = op_read();
if(regs.p.v) {
@@ -170,313 +170,314 @@ void bCPU::op_bvs() {
} else {
status.cycle_pos = 0;
}
break;
case 2:
} break;
case 2: {
cpu_c6(aa.w);
break;
case 3:
} break;
case 3: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_bra() {
switch(status.cycle_pos++) {
case 1:
case 1: {
rd.l = op_read();
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
break;
case 2:
} break;
case 2: {
cpu_c6(aa.w);
break;
case 3:
} break;
case 3: {
last_cycle();
cpu_io();
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_brl() {
switch(status.cycle_pos++) {
case 1:
case 1: {
rd.l = op_read();
break;
case 2:
} break;
case 2: {
rd.h = op_read();
break;
case 3:
} break;
case 3: {
last_cycle();
cpu_io();
regs.pc.w = regs.pc.d + (int16)rd.w;
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_jmp_addr() {
switch(status.cycle_pos++) {
case 1:
case 1: {
rd.l = op_read();
break;
case 2:
} break;
case 2: {
last_cycle();
rd.h = op_read();
regs.pc.w = rd.w;
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_jmp_long() {
switch(status.cycle_pos++) {
case 1:
case 1: {
rd.l = op_read();
break;
case 2:
} break;
case 2: {
rd.h = op_read();
break;
case 3:
} break;
case 3: {
last_cycle();
rd.b = op_read();
regs.pc.d = rd.d & 0xffffff;
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_jmp_iaddr() {
switch(status.cycle_pos++) {
case 1:
case 1: {
aa.l = op_read();
break;
case 2:
} break;
case 2: {
aa.h = op_read();
break;
case 3:
} break;
case 3: {
rd.l = op_read(OPMODE_ADDR, aa.w);
break;
case 4:
} break;
case 4: {
last_cycle();
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
regs.pc.w = rd.w;
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_jmp_iaddrx() {
switch(status.cycle_pos++) {
case 1:
case 1: {
aa.l = op_read();
break;
case 2:
} break;
case 2: {
aa.h = op_read();
break;
case 3:
} break;
case 3: {
cpu_io();
break;
case 4:
} break;
case 4: {
rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
break;
case 5:
} break;
case 5: {
last_cycle();
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
regs.pc.w = rd.w;
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_jmp_iladdr() {
switch(status.cycle_pos++) {
case 1:
case 1: {
aa.l = op_read();
break;
case 2:
} break;
case 2: {
aa.h = op_read();
break;
case 3:
} break;
case 3: {
rd.l = op_read(OPMODE_ADDR, aa.w);
break;
case 4:
} break;
case 4: {
rd.h = op_read(OPMODE_ADDR, aa.w + 1);
break;
case 5:
} break;
case 5: {
last_cycle();
rd.b = op_read(OPMODE_ADDR, aa.w + 2);
regs.pc.d = rd.d & 0xffffff;
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_jsr_addr() {
switch(status.cycle_pos++) {
case 1:
case 1: {
aa.l = op_read();
break;
case 2:
} break;
case 2: {
aa.h = op_read();
break;
case 3:
} break;
case 3: {
cpu_io();
break;
case 4:
} break;
case 4: {
regs.pc.w--;
stack_write(regs.pc.h);
break;
case 5:
} break;
case 5: {
last_cycle();
stack_write(regs.pc.l);
regs.pc.w = aa.w;
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_jsr_long() {
switch(status.cycle_pos++) {
case 1:
case 1: {
aa.l = op_read();
break;
case 2:
} break;
case 2: {
aa.h = op_read();
break;
case 3:
} break;
case 3: {
stack_write(regs.pc.b);
break;
case 4:
} break;
case 4: {
cpu_io();
break;
case 5:
} break;
case 5: {
aa.b = op_read();
break;
case 6:
} break;
case 6: {
regs.pc.w--;
stack_write(regs.pc.h);
break;
case 7:
} break;
case 7: {
last_cycle();
stack_write(regs.pc.l);
regs.pc.d = aa.d & 0xffffff;
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_jsr_iaddrx() {
switch(status.cycle_pos++) {
case 1:
case 1: {
aa.l = op_read();
break;
case 2:
} break;
case 2: {
stack_write(regs.pc.h);
break;
case 3:
} break;
case 3: {
stack_write(regs.pc.l);
break;
case 4:
} break;
case 4: {
aa.h = op_read();
break;
case 5:
} break;
case 5: {
cpu_io();
break;
case 6:
} break;
case 6: {
rd.l = op_read(OPMODE_PBR, aa.w + regs.x.w);
break;
case 7:
} break;
case 7: {
last_cycle();
rd.h = op_read(OPMODE_PBR, aa.w + regs.x.w + 1);
regs.pc.w = rd.w;
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_rti() {
switch(status.cycle_pos++) {
case 1:
case 1: {
cpu_io();
break;
case 2:
} break;
case 2: {
cpu_io();
break;
case 3:
} break;
case 3: {
regs.p = stack_read();
if(regs.e)regs.p |= 0x30;
if(regs.p.x) {
regs.x.h = 0x00;
regs.y.h = 0x00;
}
break;
case 4:
} break;
case 4: {
rd.l = stack_read();
break;
case 5:
} break;
case 5: {
if(regs.e)last_cycle();
rd.h = stack_read();
if(regs.e) {
regs.pc.w = rd.w;
status.cycle_pos = 0;
}
break;
case 6:
} break;
case 6: {
last_cycle();
rd.b = stack_read();
regs.pc.d = rd.d & 0xffffff;
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_rts() {
switch(status.cycle_pos++) {
case 1:
case 1: {
cpu_io();
break;
case 2:
} break;
case 2: {
cpu_io();
break;
case 3:
} break;
case 3: {
rd.l = stack_read();
break;
case 4:
} break;
case 4: {
rd.h = stack_read();
break;
case 5:
} break;
case 5: {
last_cycle();
cpu_io();
regs.pc.w = rd.w;
regs.pc.w++;
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_rtl() {
switch(status.cycle_pos++) {
case 1:
case 1: {
cpu_io();
break;
case 2:
} break;
case 2: {
cpu_io();
break;
case 3:
} break;
case 3: {
rd.l = stack_read();
break;
case 4:
} break;
case 4: {
rd.h = stack_read();
break;
case 5:
} break;
case 5: {
last_cycle();
rd.b = stack_read();
regs.pc.d = rd.d & 0xffffff;
regs.pc.w++;
status.cycle_pos = 0;
break;
} break;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,582 +1,582 @@
void bCPU::op_sta_addr() {
switch(status.cycle_pos++) {
case 1:
case 1: {
aa.l = op_read();
break;
case 2:
} break;
case 2: {
aa.h = op_read();
break;
case 3:
} break;
case 3: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w, regs.a.w);
if(regs.p.m)status.cycle_pos = 0;
break;
case 4:
} break;
case 4: {
last_cycle();
op_write(OPMODE_DBR, aa.w + 1, regs.a.w >> 8);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_stx_addr() {
switch(status.cycle_pos++) {
case 1:
case 1: {
aa.l = op_read();
break;
case 2:
} break;
case 2: {
aa.h = op_read();
break;
case 3:
} break;
case 3: {
if(regs.p.x)last_cycle();
op_write(OPMODE_DBR, aa.w, regs.x.w);
if(regs.p.x)status.cycle_pos = 0;
break;
case 4:
} break;
case 4: {
last_cycle();
op_write(OPMODE_DBR, aa.w + 1, regs.x.w >> 8);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_sty_addr() {
switch(status.cycle_pos++) {
case 1:
case 1: {
aa.l = op_read();
break;
case 2:
} break;
case 2: {
aa.h = op_read();
break;
case 3:
} break;
case 3: {
if(regs.p.x)last_cycle();
op_write(OPMODE_DBR, aa.w, regs.y.w);
if(regs.p.x)status.cycle_pos = 0;
break;
case 4:
} break;
case 4: {
last_cycle();
op_write(OPMODE_DBR, aa.w + 1, regs.y.w >> 8);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_stz_addr() {
switch(status.cycle_pos++) {
case 1:
case 1: {
aa.l = op_read();
break;
case 2:
} break;
case 2: {
aa.h = op_read();
break;
case 3:
} break;
case 3: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w, 0x0000);
if(regs.p.m)status.cycle_pos = 0;
break;
case 4:
} break;
case 4: {
last_cycle();
op_write(OPMODE_DBR, aa.w + 1, 0x0000 >> 8);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_sta_addrx() {
switch(status.cycle_pos++) {
case 1:
case 1: {
aa.l = op_read();
break;
case 2:
} break;
case 2: {
aa.h = op_read();
break;
case 3:
} break;
case 3: {
cpu_c4(aa.w, aa.w + regs.x.w);
break;
case 4:
} break;
case 4: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w + regs.x.w, regs.a.w);
if(regs.p.m)status.cycle_pos = 0;
break;
case 5:
} break;
case 5: {
last_cycle();
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, regs.a.w >> 8);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_stz_addrx() {
switch(status.cycle_pos++) {
case 1:
case 1: {
aa.l = op_read();
break;
case 2:
} break;
case 2: {
aa.h = op_read();
break;
case 3:
} break;
case 3: {
cpu_c4(aa.w, aa.w + regs.x.w);
break;
case 4:
} break;
case 4: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w + regs.x.w, 0x0000);
if(regs.p.m)status.cycle_pos = 0;
break;
case 5:
} break;
case 5: {
last_cycle();
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, 0x0000 >> 8);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_sta_addry() {
switch(status.cycle_pos++) {
case 1:
case 1: {
aa.l = op_read();
break;
case 2:
} break;
case 2: {
aa.h = op_read();
break;
case 3:
} break;
case 3: {
cpu_c4(aa.w, aa.w + regs.y.w);
break;
case 4:
} break;
case 4: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
break;
case 5:
} break;
case 5: {
last_cycle();
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_sta_long() {
switch(status.cycle_pos++) {
case 1:
case 1: {
aa.l = op_read();
break;
case 2:
} break;
case 2: {
aa.h = op_read();
break;
case 3:
} break;
case 3: {
aa.b = op_read();
break;
case 4:
} break;
case 4: {
if(regs.p.m)last_cycle();
op_write(OPMODE_LONG, aa.d, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
break;
case 5:
} break;
case 5: {
last_cycle();
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_sta_longx() {
switch(status.cycle_pos++) {
case 1:
case 1: {
aa.l = op_read();
break;
case 2:
} break;
case 2: {
aa.h = op_read();
break;
case 3:
} break;
case 3: {
aa.b = op_read();
break;
case 4:
} break;
case 4: {
if(regs.p.m)last_cycle();
op_write(OPMODE_LONG, aa.d + regs.x.w, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
break;
case 5:
} break;
case 5: {
last_cycle();
op_write(OPMODE_LONG, aa.d + regs.x.w + 1, regs.a.h);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_sta_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
cpu_c2();
break;
case 3:
} break;
case 3: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DP, dp, regs.a.w);
if(regs.p.m)status.cycle_pos = 0;
break;
case 4:
} break;
case 4: {
last_cycle();
op_write(OPMODE_DP, dp + 1, regs.a.w >> 8);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_stx_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
cpu_c2();
break;
case 3:
} break;
case 3: {
if(regs.p.x)last_cycle();
op_write(OPMODE_DP, dp, regs.x.w);
if(regs.p.x)status.cycle_pos = 0;
break;
case 4:
} break;
case 4: {
last_cycle();
op_write(OPMODE_DP, dp + 1, regs.x.w >> 8);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_sty_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
cpu_c2();
break;
case 3:
} break;
case 3: {
if(regs.p.x)last_cycle();
op_write(OPMODE_DP, dp, regs.y.w);
if(regs.p.x)status.cycle_pos = 0;
break;
case 4:
} break;
case 4: {
last_cycle();
op_write(OPMODE_DP, dp + 1, regs.y.w >> 8);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_stz_dp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
cpu_c2();
break;
case 3:
} break;
case 3: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DP, dp, 0x0000);
if(regs.p.m)status.cycle_pos = 0;
break;
case 4:
} break;
case 4: {
last_cycle();
op_write(OPMODE_DP, dp + 1, 0x0000 >> 8);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_sta_dpx() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
cpu_c2();
break;
case 3:
} break;
case 3: {
cpu_io();
break;
case 4:
} break;
case 4: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DP, dp + regs.x.w, regs.a.w);
if(regs.p.m)status.cycle_pos = 0;
break;
case 5:
} break;
case 5: {
last_cycle();
op_write(OPMODE_DP, dp + regs.x.w + 1, regs.a.w >> 8);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_sty_dpx() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
cpu_c2();
break;
case 3:
} break;
case 3: {
cpu_io();
break;
case 4:
} break;
case 4: {
if(regs.p.x)last_cycle();
op_write(OPMODE_DP, dp + regs.x.w, regs.y.w);
if(regs.p.x)status.cycle_pos = 0;
break;
case 5:
} break;
case 5: {
last_cycle();
op_write(OPMODE_DP, dp + regs.x.w + 1, regs.y.w >> 8);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_stz_dpx() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
cpu_c2();
break;
case 3:
} break;
case 3: {
cpu_io();
break;
case 4:
} break;
case 4: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DP, dp + regs.x.w, 0x0000);
if(regs.p.m)status.cycle_pos = 0;
break;
case 5:
} break;
case 5: {
last_cycle();
op_write(OPMODE_DP, dp + regs.x.w + 1, 0x0000 >> 8);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_stx_dpy() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
cpu_c2();
break;
case 3:
} break;
case 3: {
cpu_io();
break;
case 4:
} break;
case 4: {
if(regs.p.x)last_cycle();
op_write(OPMODE_DP, dp + regs.y.w, regs.x.l);
if(regs.p.x)status.cycle_pos = 0;
break;
case 5:
} break;
case 5: {
last_cycle();
op_write(OPMODE_DP, dp + regs.y.w + 1, regs.x.h);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_sta_idp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
cpu_c2();
break;
case 3:
} break;
case 3: {
aa.l = op_read(OPMODE_DP, dp);
break;
case 4:
} break;
case 4: {
aa.h = op_read(OPMODE_DP, dp + 1);
break;
case 5:
} break;
case 5: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
break;
case 6:
} break;
case 6: {
last_cycle();
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_sta_ildp() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
cpu_c2();
break;
case 3:
} break;
case 3: {
aa.l = op_read(OPMODE_DP, dp);
break;
case 4:
} break;
case 4: {
aa.h = op_read(OPMODE_DP, dp + 1);
break;
case 5:
} break;
case 5: {
aa.b = op_read(OPMODE_DP, dp + 2);
break;
case 6:
} break;
case 6: {
if(regs.p.m)last_cycle();
op_write(OPMODE_LONG, aa.d, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
break;
case 7:
} break;
case 7: {
last_cycle();
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_sta_idpx() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
cpu_c2();
break;
case 3:
} break;
case 3: {
cpu_io();
break;
case 4:
} break;
case 4: {
aa.l = op_read(OPMODE_DP, dp + regs.x.w);
break;
case 5:
} break;
case 5: {
aa.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
break;
case 6:
} break;
case 6: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
break;
case 7:
} break;
case 7: {
last_cycle();
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_sta_idpy() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
cpu_c2();
break;
case 3:
} break;
case 3: {
aa.l = op_read(OPMODE_DP, dp);
break;
case 4:
} break;
case 4: {
aa.h = op_read(OPMODE_DP, dp + 1);
break;
case 5:
} break;
case 5: {
cpu_c4(aa.w, aa.w + regs.y.w);
break;
case 6:
} break;
case 6: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
break;
case 7:
} break;
case 7: {
last_cycle();
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_sta_ildpy() {
switch(status.cycle_pos++) {
case 1:
case 1: {
dp = op_read();
break;
case 2:
} break;
case 2: {
cpu_c2();
break;
case 3:
} break;
case 3: {
aa.l = op_read(OPMODE_DP, dp);
break;
case 4:
} break;
case 4: {
aa.h = op_read(OPMODE_DP, dp + 1);
break;
case 5:
} break;
case 5: {
aa.b = op_read(OPMODE_DP, dp + 2);
break;
case 6:
} break;
case 6: {
if(regs.p.m)last_cycle();
op_write(OPMODE_LONG, aa.d + regs.y.w, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
break;
case 7:
} break;
case 7: {
last_cycle();
op_write(OPMODE_LONG, aa.d + regs.y.w + 1, regs.a.h);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_sta_sr() {
switch(status.cycle_pos++) {
case 1:
case 1: {
sp = op_read();
break;
case 2:
} break;
case 2: {
cpu_io();
break;
case 3:
} break;
case 3: {
if(regs.p.m)last_cycle();
op_write(OPMODE_SP, sp, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
break;
case 4:
} break;
case 4: {
last_cycle();
op_write(OPMODE_SP, sp + 1, regs.a.h);
status.cycle_pos = 0;
break;
} break;
}
}
void bCPU::op_sta_isry() {
switch(status.cycle_pos++) {
case 1:
case 1: {
sp = op_read();
break;
case 2:
} break;
case 2: {
cpu_io();
break;
case 3:
} break;
case 3: {
aa.l = op_read(OPMODE_SP, sp);
break;
case 4:
} break;
case 4: {
aa.h = op_read(OPMODE_SP, sp + 1);
break;
case 5:
} break;
case 5: {
cpu_io();
break;
case 6:
} break;
case 6: {
if(regs.p.m)last_cycle();
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
if(regs.p.m)status.cycle_pos = 0;
break;
case 7:
} break;
case 7: {
last_cycle();
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
status.cycle_pos = 0;
break;
} break;
}
}

265
src/cpu/bcpu/dma/dma.cpp Normal file
View File

@@ -0,0 +1,265 @@
/* used by both DMA and HDMA
* prevents transfer across same bus (a->a or b->b)
*/
void bCPU::dma_transfer_byte(bool direction, uint8 bbus, uint32 abus) {
uint8 r;
if(direction == 0) {
//read from address bus a, write to address bus b
//DMA address bus a cannot read from or write to the following addresses:
//$[00-3f|80-bf]:21[00-ff] <address bus b>
//$[00-3f|80-bf]:43[00-7f] <DMA control registers>
//$[00-3f|80-bf]:420b <DMA enable register>
//$[00-3f|80-bf]:420c <HDMA enable register>
if((abus & 0x40ff00) == 0x2100 || (abus & 0x40ff80) == 0x4300 ||
(abus & 0x40ffff) == 0x420b || (abus & 0x40ffff) == 0x420c) {
//these invalid reads will return open bus
r = r_cpu->regs.mdr;
} else {
r = r_mem->read(abus);
}
r_mem->write(0x2100 | bbus, r);
} else {
//read from address bus b, write to address bus a
//block invalid writes, see comments above
r = (bbus == 0x80) ? r_cpu->regs.mdr : r_mem->read(0x2100 | bbus);
if((abus & 0x40ff00) == 0x2100 || (abus & 0x40ff80) == 0x4300 ||
(abus & 0x40ffff) == 0x420b || (abus & 0x40ffff) == 0x420c)return;
r_mem->write(abus, r);
}
}
void bCPU::dma_add_cycles(uint32 cycles) {
status.dma_cycle_count += cycles;
}
void bCPU::hdma_add_cycles(uint32 cycles) {
if(run_state.dma) {
status.dma_cycle_count += cycles;
}
status.hdma_cycle_count += cycles;
}
uint32 bCPU::dma_addr(uint8 i) {
uint32 r;
r = (channel[i].srcbank << 16) | (channel[i].srcaddr);
if(channel[i].fixedxfer == false) {
channel[i].srcaddr += channel[i].incmode;
}
return r;
}
void bCPU::dma_cputommio(uint8 i, uint8 index) {
if(sdd1->dma_active() == true) {
r_mem->write(0x2100 | ((channel[i].destaddr + index) & 0xff), sdd1->dma_read());
} else {
dma_transfer_byte(0, ((channel[i].destaddr + index) & 0xff), dma_addr(i));
}
add_cycles(8);
channel[i].xfersize--;
}
void bCPU::dma_mmiotocpu(uint8 i, uint8 index) {
dma_transfer_byte(1, ((channel[i].destaddr + index) & 0xff), dma_addr(i));
add_cycles(8);
channel[i].xfersize--;
}
void bCPU::dma_write(uint8 i, uint8 index) {
if(channel[i].direction == 0) {
dma_cputommio(i, index);
} else {
dma_mmiotocpu(i, index);
}
}
void bCPU::dma_run() {
for(int i = 0; i < 8; i++) {
if(channel[i].active == false)continue;
//first byte transferred?
if(channel[i].read_index == 0) {
sdd1->dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr),
channel[i].xfersize);
}
switch(channel[i].xfermode) {
case 0: dma_write(i, 0); break; //0
case 1: dma_write(i, channel[i].read_index & 1); break; //0,1
case 2: dma_write(i, 0); break; //0,0
case 3: dma_write(i, (channel[i].read_index >> 1) & 1); break; //0,0,1,1
case 4: dma_write(i, channel[i].read_index & 3); break; //0,1,2,3
case 5: dma_write(i, channel[i].read_index & 1); break; //0,1,0,1
case 6: dma_write(i, 0); break; //0,0 [2]
case 7: dma_write(i, (channel[i].read_index >> 1) & 1); break; //0,0,1,1 [3]
}
channel[i].read_index++;
dma_add_cycles(8);
if(channel[i].xfersize == 0) {
channel[i].active = false;
}
return;
}
status.dma_state = DMASTATE_CPUSYNC;
}
uint32 bCPU::hdma_addr(uint8 i) {
return (channel[i].srcbank << 16) | (channel[i].hdma_addr++);
}
uint32 bCPU::hdma_iaddr(uint8 i) {
return (channel[i].hdma_ibank << 16) | (channel[i].hdma_iaddr++);
}
uint16 bCPU::hdma_mmio(uint8 i) {
uint8 l = channel[i].read_index;
uint16 index;
switch(channel[i].xfermode) {
case 0: index = 0; break; //0
case 1: index = l & 1; break; //0,1
case 2: index = 0; break; //0,0
case 3: index = (l >> 1) & 1; break; //0,0,1,1
case 4: index = l & 3; break; //0,1,2,3
case 5: index = l & 1; break; //0,1,0,1
case 6: index = 0; break; //0,0 [2]
case 7: index = (l >> 1) & 1; break; //0,0,1,1 [3]
}
return (0x2100 | ((channel[i].destaddr + index) & 0xff));
}
void bCPU::hdma_update(uint8 i) {
channel[i].hdma_line_counter = r_mem->read(hdma_addr(i));
add_cycles(8);
hdma_add_cycles(8);
if(channel[i].hdma_indirect) {
channel[i].hdma_iaddr = r_mem->read(hdma_addr(i)) << 8;
add_cycles(8);
hdma_add_cycles(8);
}
if(channel[i].hdma_line_counter == 0) {
channel[i].hdma_active = false;
channel[i].hdma_do_transfer = false;
return;
}
channel[i].hdma_do_transfer = true;
if(channel[i].hdma_indirect) {
channel[i].hdma_iaddr >>= 8;
channel[i].hdma_iaddr |= r_mem->read(hdma_addr(i)) << 8;
add_cycles(8);
hdma_add_cycles(8);
}
}
void bCPU::hdma_run() {
static uint8 hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
for(int i = 0; i < 8; i++) {
if(!channel[i].hdma_enabled || !channel[i].hdma_active)continue;
if(channel[i].hdma_do_transfer) {
int xferlen = hdma_xferlen[channel[i].xfermode];
for(channel[i].read_index = 0; channel[i].read_index < xferlen; channel[i].read_index++) {
if(bool(config::cpu.hdma_enable) == true) {
dma_transfer_byte(channel[i].direction, hdma_mmio(i),
channel[i].hdma_indirect ? hdma_iaddr(i) : hdma_addr(i));
}
add_cycles(8);
hdma_add_cycles(8);
}
}
channel[i].hdma_line_counter--;
channel[i].hdma_do_transfer = bool(channel[i].hdma_line_counter & 0x80);
if((channel[i].hdma_line_counter & 0x7f) == 0) {
hdma_update(i);
}
}
}
uint8 bCPU::hdma_enabled_channels() {
int r = 0;
for(int i = 0; i < 8; i++) {
if(channel[i].hdma_enabled)r++;
}
return r;
}
uint8 bCPU::hdma_active_channels() {
int r = 0;
for(int i = 0; i < 8; i++) {
if(channel[i].hdma_enabled && channel[i].hdma_active)r++;
}
return r;
}
/* hdmainit_activate()
* hdma_activate()
*
* Functions are called by CPU timing routine
* when an HDMA event (init or run) occurs.
*/
void bCPU::hdmainit_activate() {
for(int i = 0; i < 8; i++) {
channel[i].hdma_active = false;
channel[i].hdma_do_transfer = false;
}
if(hdma_enabled_channels() != 0) {
status.hdma_state = HDMASTATE_IDMASYNC;
run_state.hdma = true;
}
}
void bCPU::hdma_activate() {
if(hdma_active_channels() != 0) {
status.hdma_state = HDMASTATE_DMASYNC;
run_state.hdma = true;
}
}
void bCPU::dma_reset() {
status.dma_state = DMASTATE_CPUSYNC;
status.hdma_state = HDMASTATE_CPUSYNC;
status.dma_cycle_count = 0;
status.hdma_cycle_count = 0;
for(int i = 0; i < 8; i++) {
channel[i].read_index = 0;
channel[i].active = false;
channel[i].hdma_enabled = false;
channel[i].dmap = 0xff;
channel[i].direction = 1;
channel[i].hdma_indirect = 1;
channel[i].incmode = -1;
channel[i].fixedxfer = 1;
channel[i].xfermode = 7;
channel[i].destaddr = 0xff;
channel[i].srcaddr = 0xffff;
channel[i].srcbank = 0xff;
channel[i].xfersize = 0xffff;
//xfersize and hdma_iaddr are of union { uint16 };
//channel[i].hdma_iaddr = 0xffff;
channel[i].hdma_ibank = 0xff;
channel[i].hdma_addr = 0xffff;
channel[i].hdma_line_counter = 0xff;
channel[i].hdma_unknown = 0xff;
channel[i].hdma_active = false;
channel[i].hdma_do_transfer = false;
}
}

60
src/cpu/bcpu/dma/dma.h Normal file
View File

@@ -0,0 +1,60 @@
struct {
uint32 read_index; //set to 0 at beginning of DMA/HDMA
//$420b
bool active;
//$420c
bool hdma_enabled;
//$43x0
uint8 dmap;
bool direction;
bool hdma_indirect;
int8 incmode;
bool fixedxfer;
uint8 xfermode;
//$43x1
uint8 destaddr;
//$43x2-$43x3
uint16 srcaddr;
//$43x4
uint8 srcbank;
//$43x5-$43x6
union {
uint16 xfersize;
uint16 hdma_iaddr;
};
//$43x7
uint8 hdma_ibank;
//$43x8-$43x9
uint16 hdma_addr;
//$43xa
uint8 hdma_line_counter;
//$43xb/$43xf
uint8 hdma_unknown;
//hdma-specific
bool hdma_active;
bool hdma_do_transfer;
uint8 hdma_current_channel;
uint8 hdma_current_pos;
} channel[8];
inline void dma_transfer_byte(bool direction, uint8 bbus, uint32 abus);
inline void dma_add_cycles(uint32 cycles);
inline void hdma_add_cycles(uint32 cycles);
inline void dma_run();
inline void hdma_run();
inline void hdma_update(uint8 i);
inline uint8 hdma_enabled_channels();
inline uint8 hdma_active_channels();
inline void hdmainit_activate();
inline void hdma_activate();
inline void dma_cputommio(uint8 i, uint8 index);
inline void dma_mmiotocpu(uint8 i, uint8 index);
inline void dma_write(uint8 i, uint8 index);
inline uint32 dma_addr(uint8 i);
inline uint32 hdma_addr(uint8 i);
inline uint32 hdma_iaddr(uint8 i);
inline uint16 hdma_mmio(uint8 i);
inline void dma_reset();

View File

@@ -0,0 +1,40 @@
uint8 bCPU::port_read(uint8 port) {
return apu_port[port & 3];
}
void bCPU::port_write(uint8 port, uint8 value) {
apu_port[port & 3] = value;
}
/* The next 3 functions control bus timing for the CPU.
* cpu_io is an I/O cycle, and always 6 clock cycles long.
* mem_read / mem_write indicate memory access bus cycle,
* they are either 6, 8, or 12 bus cycles long, depending
* both on location and the $420d.d0 FastROM enable bit.
*/
void bCPU::cpu_io() {
status.cycle_count = 6;
pre_exec_cycle();
add_cycles(6);
cycle_edge();
}
uint8 bCPU::mem_read(uint32 addr) {
status.cycle_count = r_mem->speed(addr);
pre_exec_cycle();
add_cycles(status.cycle_count - 4);
regs.mdr = r_mem->read(addr);
add_cycles(4);
cycle_edge();
return regs.mdr;
}
void bCPU::mem_write(uint32 addr, uint8 value) {
status.cycle_count = r_mem->speed(addr);
pre_exec_cycle();
add_cycles(status.cycle_count);
regs.mdr = value;
r_mem->write(addr, value);
cycle_edge();
}

View File

@@ -0,0 +1,7 @@
uint8 apu_port[4];
inline uint8 port_read (uint8 port);
inline void port_write(uint8 port, uint8 value);
inline void cpu_io();
inline uint8 mem_read(uint32 addr);
inline void mem_write(uint32 addr, uint8 value);

View File

@@ -200,7 +200,7 @@ void bCPU::inc_vcounter() {
time.v = 0;
time.interlace_field ^= 1;
if(time.interlace == true && time.interlace_field == 0) {
if(interlace() == true && interlace_field() == 0) {
time.frame_lines = time.region_scanlines + 1;
} else {
time.frame_lines = time.region_scanlines;
@@ -319,8 +319,8 @@ void bCPU::time_reset() {
time.hc = 0;
//upon SNES reset, start at scanline 0 non-interlace
time.interlace = false;
time.interlace_field = false;
time.interlace = 0;
time.interlace_field = 0;
time.overscan = false;
time.line_cycles = 1364;

View File

@@ -46,29 +46,29 @@ struct {
int32 irq_read_trigger_pos, irq_line_trigger_pos;
} time;
inline uint16 vcounter();
inline uint16 hcounter();
inline uint16 hcycles();
inline bool interlace();
inline bool interlace_field();
inline bool overscan();
inline uint16 region_scanlines();
inline uint16 vcounter();
inline uint16 hcounter();
inline uint16 hcycles();
inline bool interlace();
inline bool interlace_field();
inline bool overscan();
inline uint16 region_scanlines();
inline bool nmi_trigger_pos_match(uint32 offset);
inline bool irq_trigger_pos_match(uint32 offset);
inline bool nmi_trigger_pos_match(uint32 offset);
inline bool irq_trigger_pos_match(uint32 offset);
inline void update_nmi();
inline void update_irq();
inline void update_interrupts();
inline void poll_interrupts(int cycles);
inline void update_nmi();
inline void update_irq();
inline void update_interrupts();
inline void poll_interrupts(int cycles);
inline void set_interlace(bool r);
inline void set_overscan (bool r);
inline void set_interlace(bool r);
inline void set_overscan (bool r);
inline uint8 dma_counter();
inline uint8 dma_counter();
inline void inc_vcounter();
inline uint16 get_hcounter();
inline void cycle_edge();
inline void add_cycles(int cycles);
inline void time_reset();
inline void inc_vcounter();
inline uint16 get_hcounter();
inline void cycle_edge();
inline void add_cycles(int cycles);
inline void time_reset();

View File

@@ -3,5 +3,4 @@
CPU::CPU() {
cpu_version = 1;
mmio = &mmio_unmapped;
}

View File

@@ -1,6 +1,6 @@
#include "cpuregs.h"
class CPU {
class CPU : public MMIO {
public:
//CPU version number
//* 1 and 2 are known
@@ -12,14 +12,13 @@ uint8 cpu_version;
virtual uint16 vcounter() = 0;
virtual uint16 hcounter() = 0;
virtual uint16 hcycles() = 0;
virtual bool overscan() = 0;
virtual bool interlace() = 0;
virtual bool interlace_field() = 0;
virtual bool overscan() = 0;
virtual uint16 region_scanlines() = 0;
virtual void set_interlace(bool r) = 0;
virtual void set_overscan (bool r) = 0;
MMIO *mmio;
CPURegs regs;
virtual uint8 port_read (uint8 port) = 0;
virtual void port_write(uint8 port, uint8 value) = 0;

BIN
src/data/about.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@@ -380,11 +380,13 @@ int32 fir_samplel, fir_sampler;
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);
}
//moving status.ENDX bit set into == BRR_END condition per DMV27
//if(voice[v].brr_header_flags() & BRR_END) {
// status.ENDX |= (1 << v);
//}
if(voice[v].brr_header_flags() == BRR_END) {
status.ENDX |= (1 << v);
voice[v].env_state = SILENCE;
voice[v].AdjustEnvelope();
}
@@ -429,6 +431,10 @@ int32 fir_samplel, fir_sampler;
if(++voice[v].brr_index > 15) {
voice[v].brr_index = 0;
if(voice[v].brr_header_flags() & BRR_END) {
//below condition added by DMV27
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 {

View File

@@ -1,6 +1,3 @@
#define BSNES_VERSION "0.015"
#define BSNES_TITLE "bsnes v" BSNES_VERSION
#ifdef POLYMORPHISM
#define ref(x) x
#else
@@ -16,6 +13,7 @@
#include "reader/reader.h"
#include "cart/cart.h"
#include "cheat/cheat.h"
#include "memory/memory.h"
#include "memory/bmemory/bmemory.h"
@@ -37,6 +35,8 @@
#include "chip/srtc/srtc.h"
#include "chip/sdd1/sdd1.h"
#include "chip/c4/c4.h"
#include "chip/dsp2/dsp2.h"
#include "chip/obc1/obc1.h"
extern MMIO mmio_unmapped;
#ifdef POLYMORPHISM
@@ -46,22 +46,25 @@ extern MMIO mmio_unmapped;
extern DSP *deref(dsp);
extern PPU *deref(ppu);
#else
extern bMemBus deref(mem);
extern bCPU deref(cpu);
extern bAPU deref(apu);
extern bDSP deref(dsp);
extern bPPU deref(ppu);
extern MEMCORE deref(mem);
extern CPUCORE deref(cpu);
extern APUCORE deref(apu);
extern DSPCORE deref(dsp);
extern PPUCORE deref(ppu);
#endif
extern SNES *snes;
extern SRTC *srtc;
extern SDD1 *sdd1;
extern C4 *c4;
extern DSP2 *dsp2;
extern OBC1 *obc1;
#include "config/config.h"
#ifdef INTERFACE_MAIN
Cartridge cartridge;
Cheat cheat;
#include "config/config.cpp"
#ifdef POLYMORPHISM
@@ -71,16 +74,18 @@ Cartridge cartridge;
DSP *deref(dsp);
PPU *deref(ppu);
#else
bMemBus deref(mem);
bCPU deref(cpu);
bAPU deref(apu);
bDSP deref(dsp);
bPPU deref(ppu);
MEMCORE deref(mem);
CPUCORE deref(cpu);
APUCORE deref(apu);
DSPCORE deref(dsp);
PPUCORE deref(ppu);
#endif
SNES *snes;
SRTC *srtc;
SDD1 *sdd1;
C4 *c4;
DSP2 *dsp2;
OBC1 *obc1;
#endif

View File

@@ -1,5 +1,5 @@
/*
libbase : version 0.03 ~byuu (08/20/05)
libbase : version 0.07 ~byuu (04/21/06)
*/
#ifndef __LIBBASE
@@ -9,16 +9,20 @@
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#ifndef TRUE
#define TRUE 1
#endif
#include <time.h>
#include <math.h>
#ifndef FALSE
#define FALSE 0
#endif
#define zerofree(__n) if(__n) { free(__n); __n = 0; }
#ifndef TRUE
#define TRUE 1
#endif
#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; }
typedef unsigned int uint;
@@ -38,9 +42,91 @@ typedef signed short int16;
typedef signed long int32;
typedef signed long long int64;
#ifdef null
#undef null
#endif
#define null 0xffffffff
template<typename T> void swap(T &x, T &y) {
T z = x;
x = y;
y = z;
}
template<typename T, typename Targ> T bound_range(T &x, Targ min, Targ max) {
return (x < T(min)) ? T(min) : (x > T(max)) ? T(max) : x;
}
inline bool fexists(const char *fn) {
FILE *fp = fopen(fn, "rb");
if(!fp)return false;
fclose(fp);
fp = 0;
return true;
}
inline uint32 fsize(FILE *fp) {
if(!fp)return 0;
uint32 pos = ftell(fp);
fseek(fp, 0, SEEK_END);
uint32 size = ftell(fp);
fseek(fp, pos, SEEK_SET);
return size;
}
inline uint32 fsize(const char *fn) {
FILE *fp = fopen(fn, "rb");
if(!fp)return 0;
fseek(fp, 0, SEEK_END);
uint32 size = ftell(fp);
fclose(fp);
fp = 0;
return size;
}
const uint32 crc32_table[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
inline uint32 crc32_adjust(uint32 crc32, uint32 input) {
return ((crc32 >> 8) & 0x00ffffff) ^ crc32_table[(crc32 ^ input) & 0xff];
}
#endif

625
src/lib/libbpf.cpp Normal file
View File

@@ -0,0 +1,625 @@
#include "libbase.h"
#include "libvector.h"
#include "libbpf.h"
void BPF::Handle::seek(uint32 new_pos) {
if(pos == new_pos)return;
pos = new_pos;
if(mode == MODE_FILE) {
fseek(handle, new_pos, SEEK_SET);
}
}
void BPF::Handle::write(uint8 x) {
if(mode == MODE_MEMORY) {
data[pos] = x;
} else {
fputc(x, handle);
}
if(++pos > size)size = pos;
crc32 = crc32_adjust(crc32, x);
}
uint8 BPF::Handle::read() {
uint8 r;
if(pos >= size) {
return 0x00;
} else if(mode == MODE_MEMORY) {
r = data[pos];
} else {
r = fgetc(handle);
}
pos++;
crc32 = crc32_adjust(crc32, r);
return r;
}
uint32 BPF::Handle::calc_crc32() {
crc32 = 0xffffffff;
seek(0);
for(uint32 i = 0; i < size; i++) {
read();
}
seek(0);
crc32 = ~crc32;
return crc32;
}
bool BPF::Handle::open(uint8 _access, uint32 _size, uint8 *_data) {
close();
mode = MODE_MEMORY;
access = _access;
pos = 0;
size = _size;
crc32 = 0xffffffff;
if(access == ACCESS_READ) {
data.resize(_size);
data.copy(_data, _size);
} else {
data.resize(_size);
data.clear();
}
return true;
}
bool BPF::Handle::open(uint8 _access, const char *fn) {
close();
mode = MODE_FILE;
access = _access;
pos = 0;
crc32 = 0xffffffff;
if(access == ACCESS_READ) {
handle = fopen(fn, "rb");
if(!handle)return false;
size = fsize(handle);
} else if(access == ACCESS_WRITE) {
handle = fopen(fn, "wb");
if(!handle)return false;
size = 0;
}
return true;
}
bool BPF::Handle::load(const char *fn) {
close();
FILE *fp = fopen(fn, "rb");
if(!fp)return false;
size = fsize(fp);
uint8 *buffer = (uint8*)malloc(size);
memset(buffer, 0, size);
fread(buffer, 1, size, fp);
fclose(fp);
return open(ACCESS_READ, size, buffer);
}
bool BPF::Handle::save(const char *fn) {
if(mode != MODE_MEMORY)return false;
FILE *fp = fopen(fn, "wb");
if(!fp)return false;
fwrite(data.handle(), 1, size, fp);
fclose(fp);
return true;
}
void BPF::Handle::close() {
if(mode == MODE_MEMORY) {
data.release();
} else if(mode == MODE_FILE) {
if(handle) {
fclose(handle);
handle = 0;
}
}
}
uint8 *BPF::load(const char *fn, uint32 &size) {
FILE *fp = fopen(fn, "rb");
if(!fp)return 0;
size = fsize(fp);
uint8 *buffer = (uint8*)malloc(size);
fread(buffer, 1, size, fp);
fclose(fp);
fp = 0;
return buffer;
}
void BPF::save(const char *fn, uint8 *data, uint32 size) {
FILE *fp = fopen(fn, "wb");
if(!fp)return;
fwrite(data, 1, size, fp);
fclose(fp);
fp = 0;
}
void BPF::write_ptr(uint32 ptr) {
if(ptr <= 0xef) {
patch.write(ptr);
return;
}
ptr -= 0xf0;
if(ptr <= 0xffff) {
patch.write(0xf0);
patch.write(ptr);
patch.write(ptr >> 8);
return;
}
ptr -= 0x10000;
if(ptr <= 0xffffff) {
patch.write(0xf1);
patch.write(ptr);
patch.write(ptr >> 8);
patch.write(ptr >> 16);
return;
}
ptr -= 0x1000000;
patch.write(0xf2);
patch.write(ptr);
patch.write(ptr >> 8);
patch.write(ptr >> 16);
patch.write(ptr >> 24);
}
uint32 BPF::read_ptr() {
uint32 len = patch.read();
if(len <= 0xef) {
return len;
}
len &= 0x0f;
uint32 ptr = 0;
for(int i = 0; i < (len + 2); i++) {
ptr |= patch.read() << (i << 3);
}
ptr += 0xf0;
if(len >= 1)ptr += 0x10000;
if(len >= 2)ptr += 0x1000000;
return ptr;
}
void BPF::create_patch_binary() {
original.seek(0);
modified.seek(0);
uint32 last_ptr = 0, rle_count, last_out, rep_count;
for(uint32 i = 0; i < info.size_max;) {
uint8 r = original.read() ^ modified.read();
i++;
if(r == 0x00)continue;
//ptr
write_ptr((i - 1) - last_ptr);
//data
patch.write(r);
last_out = r;
rep_count = 0;
do {
r = original.read() ^ modified.read();
i++;
patch.write(r);
if(last_out == r) {
if(++rep_count == 2) {
rle_count = 0;
do {
r = original.read() ^ modified.read();
i++;
if(r != last_out || r == 0x00)break;
rle_count++;
} while(i < info.size_max);
write_ptr(rle_count);
if(i < info.size_max)patch.write(r);
rep_count = 0;
}
} else {
rep_count = 0;
}
last_out = r;
if(r == 0x00)break;
} while(i < info.size_max);
last_ptr = i;
}
}
bool BPF::create_patch(uint32 format, const char *fn) {
patch.open(ACCESS_WRITE, fn);
//header
patch.write('b');
patch.write('p');
patch.write('f');
patch.write(0x00);
//version (high-byte = major, low-byte = minor)
patch.write(0x00);
patch.write(0x01);
//bytes per pointer
info.size_max = (original.size >= modified.size) ? original.size : modified.size;
info.size_min = (original.size >= modified.size) ? modified.size : original.size;
if(info.size_max <= 0xff) {
info.ptr_size = 1;
} else if(info.size_max <= 0xffff) {
info.ptr_size = 2;
} else if(info.size_max <= 0xffffff) {
info.ptr_size = 3;
} else {
info.ptr_size = 4;
}
patch.write(info.ptr_size);
patch.write(info.ptr_size >> 8);
//format
patch.write(format);
patch.write(format >> 8);
patch.write(format >> 16);
patch.write(format >> 24);
//flags
uint32 flags = 0;
patch.write(flags);
patch.write(flags >> 8);
patch.write(flags >> 16);
patch.write(flags >> 24);
//original size
for(int i = 0; i < info.ptr_size; i++) {
patch.write(original.size >> (i << 3));
}
//modified size
for(int i = 0; i < info.ptr_size; i++) {
patch.write(modified.size >> (i << 3));
}
//patch data offset (currently unused)
uint32 pos = patch.pos + 4;
for(int i = 0; i < 4; i++) {
patch.write(pos >> (i << 3));
}
create_patch_binary();
//write crc32 of original file
for(int i = 0; i < 4; i++) {
patch.write(~original.crc32 >> (i << 3));
}
//write crc32 of modified file
for(int i = 0; i < 4; i++) {
patch.write(~modified.crc32 >> (i << 3));
}
uint32 patch_crc32 = patch.crc32;
//write crc32 of patch file
for(int i = 0; i < 4; i++) {
patch.write(~patch_crc32 >> (i << 3));
}
patch.close();
return true;
}
void BPF::apply_patch_binary() {
//copy old data info output buffer
output.seek(0);
input.seek(0);
for(uint32 z = 0; z < output.size; z++) {
output.write(input.read());
}
output.seek(0);
input.seek(0);
patch.seek(info.patch_start);
//the below routine may modify output.size if the input
//size is larger, so save the correct output size...
uint32 start_size = output.size;
//subtract 12 to ignore crc32 for original, modified, and patch files
uint32 rle_count, last_in, rep_count;
for(; patch.pos < (patch.size - 12);) {
//ptr
uint32 ptr = read_ptr();
//data
output.seek(output.pos + ptr);
input.seek(input.pos + ptr);
last_in = 0;
rep_count = 0;
do {
uint8 r = patch.read();
output.write(r ^ input.read());
if(r == last_in) {
if(++rep_count == 2) {
rle_count = read_ptr();
while(rle_count--) {
output.write(r ^ input.read());
}
rep_count = 0;
}
} else {
rep_count = 0;
}
last_in = r;
if(r == 0x00)break;
} while(patch.pos < (patch.size - 12));
}
//...and restore it when finished patching
output.size = start_size;
}
bool BPF::apply_patch() {
//verify patch is large enough to be a valid patchfile
if(patch.size < 34)return false;
patch.seek(INDEX_SIG);
//verify signature
if(patch.read() != 'b')return false;
if(patch.read() != 'p')return false;
if(patch.read() != 'f')return false;
if(patch.read() != 0x00)return false;
//read pointer size
patch.seek(INDEX_PTRSIZE);
info.ptr_size = patch.read();
info.ptr_size |= patch.read() << 8;
//read flags
uint32 flags;
patch.seek(INDEX_FLAGS);
flags = patch.read();
flags |= patch.read() << 8;
flags |= patch.read() << 16;
flags |= patch.read() << 24;
uint32 sx = 0, sy = 0;
patch.seek(INDEX_VARIABLE);
for(int i = 0; i < info.ptr_size; i++) {
sx |= patch.read() << (i << 3);
}
for(int i = 0; i < info.ptr_size; i++) {
sy |= patch.read() << (i << 3);
}
uint32 cx = 0, cy = 0, cp = 0;
patch.seek(patch.size - 12);
for(int i = 0; i < 4; i++) {
cx |= patch.read() << (i << 3);
}
for(int i = 0; i < 4; i++) {
cy |= patch.read() << (i << 3);
}
for(int i = 0; i < 4; i++) {
cp |= patch.read() << (i << 3);
}
input.calc_crc32();
//skip the stored patch crc32 when calculating
patch.size -= 4;
patch.calc_crc32();
patch.size += 4;
//validate patch crc32
if(patch.crc32 != cp) {
return false;
}
//validate input crc32 + size
bool input_num = 0;
if(input.crc32 == cx && input.size == sx) {
output.open(ACCESS_WRITE, sy);
input_num = 0;
} else if(input.crc32 == cy && input.size == sy) {
output.open(ACCESS_WRITE, sx);
input_num = 1;
} else {
return false;
}
patch.seek(INDEX_FORMAT);
info.format = 0;
for(int i = 0; i < 4; i++) {
info.format |= patch.read() << (i << 3);
}
info.patch_start = 0;
patch.seek(INDEX_VARIABLE + info.ptr_size * 2);
for(int i = 0; i < 4; i++) {
info.patch_start |= patch.read() << (i << 3);
}
apply_patch_binary();
output.calc_crc32();
return (output.crc32 == ((input_num == 0) ? cy : cx));
}
//main library interface functions
bool BPF::create_patch(uint32 format, const char *fn_patch, const char *fn_x, const char *fn_y) {
uint32 size_x = fsize(fn_x);
uint32 size_y = fsize(fn_y);
bool lim_x = (size_x >= settings.memory_limit);
bool lim_y = (size_y >= settings.memory_limit);
switch(format) {
case FORMAT_BINARY: {
if(lim_x == false) {
original.load(fn_x);
} else {
original.open(ACCESS_READ, fn_x);
}
if(lim_y == false) {
modified.load(fn_y);
} else {
modified.open(ACCESS_READ, fn_y);
}
} break;
case FORMAT_SNES: {
if(lim_x == true || lim_y == true) {
//files must be loaded into memory to manipulate, but
//one or more files exceed the memory limit setting
return false;
}
uint32 size;
uint8 *data;
//remove header, if it exists
data = load(fn_x, size);
if((size & 0x1fff) == 0x0200) {
original.open(ACCESS_READ, size - 512, data + 512);
} else {
original.open(ACCESS_READ, size, data);
}
SafeFree(data);
//remove header, if it exists
data = load(fn_y, size);
if((size & 0x1fff) == 0x0200) {
modified.open(ACCESS_READ, size - 512, data + 512);
} else {
modified.open(ACCESS_READ, size, data);
}
SafeFree(data);
} break;
}
bool result = create_patch(format, fn_patch);
original.close();
modified.close();
return result;
}
bool BPF::apply_patch(const char *fn_patch, const char *fn_input) {
uint32 size_p = fsize(fn_patch);
uint32 size_i = fsize(fn_input);
bool lim_p = (size_p >= settings.memory_limit);
bool lim_i = (size_i >= settings.memory_limit);
if(lim_p == false) {
patch.load(fn_patch);
} else {
patch.open(ACCESS_READ, fn_patch);
}
patch.seek(INDEX_FORMAT);
uint32 format;
format = patch.read();
format |= patch.read() << 8;
format |= patch.read() << 16;
format |= patch.read() << 24;
patch.seek(0);
switch(format) {
case FORMAT_BINARY: {
if(lim_i == false) {
input.load(fn_input);
} else {
input.open(ACCESS_READ, fn_input);
}
} break;
case FORMAT_SNES: {
if(lim_i == true) {
//file too large to load into memory?
patch.close();
return false;
}
uint32 size;
uint8 *data = load(fn_input, size);
//remove header, if it exists
if((size & 0x1fff) == 0x0200) {
input.open(ACCESS_READ, size - 512, data + 512);
} else {
input.open(ACCESS_READ, size, data);
}
SafeFree(data);
} break;
}
bool result = apply_patch();
patch.close();
input.close();
return result;
}
bool BPF::apply_patch(uint32 s_patch, uint8 *p_patch, uint32 s_input, uint8 *p_input) {
patch.open(ACCESS_READ, s_patch, p_patch);
patch.seek(INDEX_FORMAT);
uint32 format;
format = patch.read();
format |= patch.read() << 8;
format |= patch.read() << 16;
format |= patch.read() << 24;
patch.seek(0);
switch(format) {
case FORMAT_BINARY: {
input.open(ACCESS_READ, s_input, p_input);
} break;
case FORMAT_SNES: {
//remove header, if it exists
if((s_input & 0x1fff) == 0x0200) {
input.open(ACCESS_READ, s_input - 512, p_input + 512);
} else {
input.open(ACCESS_READ, s_input, p_input);
}
} break;
}
bool result = apply_patch();
patch.close();
input.close();
return result;
}
uint8 *BPF::get_output_handle(uint32 &size) {
size = output.size;
return (uint8*)output.data.handle();
}
void BPF::save_output(const char *fn) {
output.save(fn);
}
void BPF::clear_settings() {
settings.memory_limit = (16 * 1024 * 1024) + 4096;
settings.insert_data.enabled = false;
settings.insert_data.mode = 0;
settings.insert_data.handle = 0;
settings.insert_data.data = 0;
settings.insert_data.size = 0;
strcpy(settings.insert_data.fn, "");
}
BPF::BPF() {
clear_settings();
original.set_parent(this);
modified.set_parent(this);
output.set_parent(this);
input.set_parent(this);
patch.set_parent(this);
}
BPF::~BPF() {
original.close();
modified.close();
output.close();
input.close();
patch.close();
}

104
src/lib/libbpf.h Normal file
View File

@@ -0,0 +1,104 @@
/*
libbpf : version 0.01 ~byuu (12/18/05)
*/
#ifndef __LIBBPF
#define __LIBBPF
#include "libbase.h"
#include "libvector.h"
class BPF;
class BPF {
public:
enum {
//patch formats
FORMAT_BINARY = 0x0000,
FORMAT_SNES = 0x0001,
};
enum {
INDEX_SIG = 0x00, //4 bytes
INDEX_VERSION = 0x04, //2 bytes
INDEX_PTRSIZE = 0x06, //2 bytes
INDEX_FORMAT = 0x08, //4 bytes
INDEX_FLAGS = 0x0c, //4 bytes
INDEX_VARIABLE = 0x10, //variable data follows
};
enum { MODE_MEMORY, MODE_FILE };
enum { ACCESS_READ, ACCESS_WRITE };
struct Handle {
BPF *parent;
uint8 mode, access;
vector<uint8> data;
FILE *handle;
uint32 size, pos, crc32;
void seek(uint32 new_pos);
void write(uint8 x);
uint8 read();
uint32 calc_crc32();
bool open(uint8 _mode, uint32 size, uint8 *_data = 0);
bool open(uint8 _mode, const char *fn);
bool load(const char *fn);
bool save(const char *fn);
void close();
void set_parent(BPF *_bpf) { parent = _bpf; }
Handle() {
mode = 0; access = 0;
crc32 = 0; handle = 0;
size = 0; pos = 0;
}
} original, modified, output, input, patch;
struct {
uint32 memory_limit;
struct {
bool enabled;
uint8 mode;
char fn[4096];
FILE *handle;
uint8 *data;
uint32 size;
} insert_data;
} settings;
struct {
uint16 ptr_size;
uint32 size_min, size_max;
uint32 patch_start;
uint32 format;
} info;
uint8 *load(const char *fn, uint32 &size);
void save(const char *fn, uint8 *data, uint32 size);
void write_ptr(uint32 ptr);
uint32 read_ptr();
void create_patch_binary();
bool create_patch(uint32 format, const char *fn);
bool create_patch(uint32 format, const char *fn_patch, const char *fn_x, const char *fn_y);
void apply_patch_binary();
bool apply_patch();
bool apply_patch(const char *fn_patch, const char *fn_input);
bool apply_patch(uint32 s_patch, uint8 *p_patch, uint32 s_input, uint8 *p_input);
uint8 *get_output_handle(uint32 &size);
void save_output(const char *fn);
void clear_settings();
BPF();
~BPF();
};
#endif

View File

@@ -13,9 +13,22 @@ uint Setting::get() {
void Setting::set(uint _data) {
data = _data;
if(type != DEC && type != HEX) {
//data is a boolean type
switch(type) {
case TRUE_FALSE:
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;
}
}
@@ -98,11 +111,11 @@ uint Config::string_to_uint(uint type, char *input) {
return (uint)false;
}
if(strbegin(input, "0x")) {
return strhex(input + 2);
if(strbegin(input, "0x") || strbegin(input, "-0x")) {
return sstrhex(input + 2);
}
return strdec(input);
return sstrdec(input);
}
char *Config::uint_to_string(uint type, uint input) {
@@ -120,12 +133,12 @@ static char output[512];
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::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;

View File

@@ -1,5 +1,5 @@
/*
libconfig : version 0.05 ~byuu (10/30/05)
libconfig : version 0.07 ~byuu (02/10/06)
*/
#ifndef __LIBCONFIG
@@ -31,8 +31,10 @@ class Config;
inline __name &operator=(const float _data) { set((uint)_data); return *this; } \
inline __name &operator=(const double _data) { set((uint)_data); return *this; } \
void toggle() { data ^= 1; set(data); } \
__name(Config *_parent, char *_name, char *_desc = 0, uint _data = 0, uint _type = Setting::DEC) : \
Setting(_parent, _name, _desc, _data, _type) {}
__name(Config *_parent, char *_name, char *_desc, uint _data, uint _type) : \
Setting(_parent, _name, _desc, _data, _type) {} \
__name(Config *_parent, char *_name, char *_desc, char *_data) : \
Setting(_parent, _name, _desc, _data) {}
class Setting {
friend class Config;
@@ -46,9 +48,12 @@ enum {
ENABLED_DISABLED,
ON_OFF,
YES_NO,
BOOL,
DEC,
HEX,
HEX8,
HEX16,
HEX24,
HEX32,
STR
};
char *name, *desc;

View File

@@ -93,6 +93,18 @@ int srclen = strlen(src);
}
void strcpy(substring &dest, substring &src) { strcpy(dest, strptr(src)); }
//this differs from libc's strncpy in that it always
//appends a null terminator to the end of a copied string
void strncpy(substring &dest, const char *src, uint32 length) {
int srclen = strlen(src);
//never copy more text than is in the string
if(srclen > length)srclen = length;
if(srclen > dest.size) { strresize(dest, srclen); }
strncpy(dest.s, src, srclen);
dest.s[srclen] = 0;
}
void strncpy(substring &dest, substring &src, uint32 length) { strncpy(dest, strptr(src), length); }
void strset(substring &dest, uint pos, uint8 c) {
char *s;
if(pos > dest.size) { strresize(dest, pos); }
@@ -187,11 +199,14 @@ bool qstrpos(const char *str, substring &key, uint &pos) { return qstrpos(str, s
bool qstrpos(substring &str, substring &key, uint &pos) { return qstrpos(strptr(str), strptr(key), pos); }
void strtr(char *dest, const char *before, const char *after) {
int i, l, sl = strlen(dest), bsl = strlen(before), asl = strlen(after);
if((bsl != asl) || bsl == 0)return;
for(i=0;i<sl;i++) {
for(l=0;l<bsl;l++) {
if(dest[i] == before[l])dest[i] = after[l];
int sl = strlen(dest), bsl = strlen(before), asl = strlen(after);
if(bsl != asl || bsl == 0)return;
for(int i = 0; i < sl; i++) {
for(int l = 0; l < bsl; l++) {
if(dest[i] == before[l]) {
dest[i] = after[l];
break;
}
}
}
}
@@ -246,8 +261,8 @@ bool striend(substring &str, const char *key) { return striend(strptr(str), key)
void strltrim(char *str, const char *key) {
int i, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return;
if(!strbegin(str, key)) {
for(i=0;i<ssl-ksl;i++)str[i] = str[i + ksl];
if(strbegin(str, key)) {
for(i = 0; i < (ssl - ksl); i++)str[i] = str[i + ksl];
str[i] = 0;
}
}
@@ -256,8 +271,8 @@ void strltrim(substring &str, const char *key) { strltrim(strptr(str), key); }
void striltrim(char *str, const char *key) {
int i, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return;
if(!stribegin(str, key)) {
for(i=0;i<ssl-ksl;i++)str[i] = str[i + ksl];
if(stribegin(str, key)) {
for(i = 0; i < (ssl-ksl); i++)str[i] = str[i + ksl];
str[i] = 0;
}
}
@@ -266,7 +281,7 @@ void striltrim(substring &str, const char *key) { striltrim(strptr(str), key); }
void strrtrim(char *str, const char *key) {
int ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return;
if(!strend(str, key)) {
if(strend(str, key)) {
str[ssl - ksl] = 0;
}
}
@@ -275,7 +290,7 @@ void strrtrim(substring &str, const char *key) { strrtrim(strptr(str), key); }
void strirtrim(char *str, const char *key) {
int ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return;
if(!striend(str, key)) {
if(striend(str, key)) {
str[ssl - ksl] = 0;
}
}
@@ -314,13 +329,13 @@ uint strhex(const char *str) {
uint r = 0, m = 0;
int i, ssl = strlen(str);
uint8 x;
for(i=0;i<ssl;i++) {
for(i = 0; i < ssl; i++) {
if(str[i] >= '0' && str[i] <= '9');
else if(str[i] >= 'A' && str[i] <= 'F');
else if(str[i] >= 'a' && str[i] <= 'f');
else break;
}
for(--i;i>=0;i--, m+=4) {
for(--i; i >= 0; i--, m += 4) {
x = str[i];
if(x >= '0' && x <= '9')x -= '0';
else if(x >= 'A' && x <= 'F')x -= 'A' - 0x0a;
@@ -344,11 +359,11 @@ uint strdec(const char *str) {
uint m = 1;
int i, r = 0, ssl = strlen(str);
uint8 x;
for(i=0;i<ssl;i++) {
for(i = 0; i < ssl; i++) {
if(str[i] >= '0' && str[i] <= '9');
else break;
}
for(--i;i>=0;i--, m*=10) {
for(--i; i >= 0; i--, m *= 10) {
x = str[i];
if(x >= '0' && x <= '9')x -= '0';
else return r;
@@ -370,11 +385,11 @@ uint strbin(const char *str) {
uint r = 0, m = 0;
int i, ssl = strlen(str);
uint8 x;
for(i=0;i<ssl;i++) {
for(i = 0; i < ssl; i++) {
if(str[i] == '0' || str[i] == '1');
else break;
}
for(--i;i>=0;i--, m++) {
for(--i; i >= 0; i--, m++) {
x = str[i];
if(str[i] == '0' || str[i] == '1')x -= '0';
else return r;

View File

@@ -1,5 +1,5 @@
/*
libstring : version 0.07 ~byuu (11/30/05)
libstring : version 0.10 ~byuu (03/05/06)
*/
#ifndef __LIBSTRING
@@ -46,6 +46,8 @@ bool strimatch(substring &dest, substring &src);
void strcpy(substring &dest, const char *src);
void strcpy(substring &dest, substring &src);
void strncpy(substring &dest, const char *src, uint32 length);
void strncpy(substring &dest, substring &src, uint32 length);
void strset(substring &dest, uint pos, uint8 c);
@@ -135,10 +137,10 @@ void replace(substring &str, const char *key, substring &token);
void qreplace(substring &str, const char *key, const char *token);
void qreplace(substring &str, const char *key, substring &token);
void split(string &dest, const char *key, char *src);
void split(string &dest, const char *key, const char *src);
void split(string &dest, const char *key, substring &src);
void qsplit(string &dest, const char *key, char *src);
void qsplit(string &dest, const char *key, const char *src);
void qsplit(string &dest, const char *key, substring &src);
void sprintf(substring &str, const char *s, ...);

View File

@@ -112,7 +112,7 @@ char num[64];
} else if(str[i]==')') {
if(pdepth == 0) {
free(str);
return null; //error! too many )'s
return 0; //error! too many )'s
}
pdepth --;
}
@@ -120,7 +120,7 @@ char num[64];
if(pdepth != 0) {
free(str);
return null; //error! unequal ('s to )'s
return 0; //error! unequal ('s to )'s
}
pdepth = maxpdepth;

View File

@@ -1,13 +1,9 @@
void split(string &dest, const char *key, char *src) {
int i, ssl = strlen(src), ksl = strlen(key);
uint lp = 0, split_count = 0;
uint8 x;
for(i=0;i<=ssl-ksl;) {
void split(string &dest, const char *key, const char *src) {
int ssl = strlen(src), ksl = strlen(key);
uint lp = 0, split_count = 0;
for(int32 i = 0; i <= ssl - ksl;) {
if(!memcmp(src + i, key, ksl)) {
x = src[i];
src[i] = 0;
strcpy(dest[split_count++], src + lp);
src[i] = x;
strncpy(dest[split_count++], src + lp, i - lp);
i += ksl;
lp = i;
} else i++;
@@ -17,22 +13,18 @@ uint8 x;
}
void split(string &dest, const char *key, substring &src) { split(dest, key, strptr(src)); }
void qsplit(string &dest, const char *key, char *src) {
int i, z, ssl = strlen(src), ksl = strlen(key);
uint lp = 0, split_count = 0;
uint8 x;
for(i=0;i<=ssl-ksl;) {
x = src[i];
if(x=='\"' || x=='\'') {
void qsplit(string &dest, const char *key, const char *src) {
int z, ssl = strlen(src), ksl = strlen(key);
uint lp = 0, split_count = 0;
for(int32 i = 0; i <= ssl - ksl;) {
uint8 x = src[i];
if(x == '\"' || x == '\'') {
z = i++;
while(src[i] != x && i < ssl)i++;
if(i >= ssl)i = z;
}
if(!memcmp(src + i, key, ksl)) {
x = src[i];
src[i] = 0;
strcpy(dest[split_count++], src + lp);
src[i] = x;
strncpy(dest[split_count++], src + lp, i - lp);
i += ksl;
lp = i;
} else i++;

View File

@@ -1,5 +1,5 @@
/*
libvector : version 0.03 ~byuu (08/16/05)
libvector : version 0.04 ~byuu (12/24/05)
*/
#ifndef __LIBVECTOR
@@ -9,13 +9,14 @@ template<typename T> class vector {
private:
T *array;
int size, sizelimit;
//find next array size that is a power of two
int findsize(int newsize) {
int r = 1;
while(r >= 1) {
r <<= 1;
if(r > sizelimit)return sizelimit;
if(r >= newsize) return r;
if(r > sizelimit)return sizelimit;
if(r >= newsize)return r;
}
return size;
}
@@ -30,12 +31,32 @@ public:
array = (T*)realloc(array, sizeof(T) * newsize);
if(newsize > size) {
for(int i=size;i<newsize;i+=sizeof(T)) {
for(int i = size; i < newsize; i += sizeof(T)) {
array[i] = (T)0;
}
}
size = newsize;
size = newsize;
}
//used to free up memory used by vector, but without
//actually destroying the vector itself
void release() {
resize(16);
}
T *handle() { return (T*)array; }
void copy(T *source, uint32 copy_size) {
if(copy_size > size) {
resize(copy_size);
copy_size = size;
}
memcpy(array, source, copy_size * sizeof(T));
}
void clear() {
memset(array, 0, size * sizeof(T));
}
vector(int newsize, int newsizelimit) {

104
src/lib/libwin32.cpp Normal file
View File

@@ -0,0 +1,104 @@
#include "libbase.h"
#include "libwin32.h"
#include "libwin32_misc.cpp"
#include "libwin32_file.cpp"
#include "libwin32_window.cpp"
#include "libwin32_control.cpp"
#include "libwin32_label.cpp"
#include "libwin32_groupbox.cpp"
#include "libwin32_editbox.cpp"
#include "libwin32_button.cpp"
#include "libwin32_checkbox.cpp"
#include "libwin32_radiobox.cpp"
#include "libwin32_slider.cpp"
#include "libwin32_combobox.cpp"
#include "libwin32_listbox.cpp"
#include "libwin32_listview.cpp"
void alert(char *s, ...) {
char str[4096];
va_list args;
va_start(args, s);
vsprintf(str, s, args);
va_end(args);
MessageBox(0, str, "bsnes", MB_OK);
}
void ShowCursor() {
if(global::cursor_visible == false) {
global::cursor_visible = true;
ShowCursor(TRUE);
}
}
void HideCursor() {
if(global::cursor_visible == true) {
global::cursor_visible = false;
ShowCursor(FALSE);
}
}
void ParseStyleParam(const char *style, string &output) {
string temp;
strcpy(temp, style);
strlower(temp);
replace(temp, " ", "");
strltrim(temp, "|");
strrtrim(temp, "|");
replace(temp, "||", "|");
split(output, "|", temp);
}
long __stdcall CoreWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
return WindowList.WndProc(hwnd, msg, wparam, lparam);
}
bool WindowManager::Add(Window *window) {
if(window_count >= WINDOW_LIMIT)return false;
list[window_count++] = window;
return true;
}
long WindowManager::WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
for(int i = 0; i < window_count; i++) {
if(list[i]->hwnd == hwnd) {
return list[i]->WndProc(msg, wparam, lparam);
}
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
WindowManager::WindowManager() {
window_count = 0;
}
Font CreateFont(const char *name, uint height, const char *style) {
HDC hdc = GetDC(0);
Font font = CreateFont(-MulDiv(height, GetDeviceCaps(hdc, LOGPIXELSY), 72),
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, name);
ReleaseDC(0, hdc);
return font;
}
libwin32_init::libwin32_init() {
WindowList.list = (Window**)malloc((WINDOW_LIMIT + 1) * sizeof(Window*));
memset(WindowList.list, 0, (WINDOW_LIMIT + 1) * sizeof(Window*));
InitCommonControls();
global::font_default = CreateFont("Tahoma", 8);
WNDCLASS wc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = CoreWindowProc;
wc.lpszClassName = "resize_class";
wc.lpszMenuName = 0;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);
}

60
src/lib/libwin32.h Normal file
View File

@@ -0,0 +1,60 @@
/*
libwin32 : version 0.03 ~byuu (04/14/06)
*/
#ifndef __LIBWIN32
#define __LIBWIN32
#include "libstring.h"
#define WINVER 0x0400
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <commctrl.h>
#include <direct.h>
#define WINDOW_LIMIT 4095
#define CONTROL_LIMIT 4095
#define WINDOWID_INDEX 10000
#define CONTROLID_INDEX 20000
typedef HFONT Font;
namespace global {
bool cursor_visible = true;
Font font_default;
};
void alert(char *s, ...);
void ShowCursor();
void HideCursor();
void ParseStyleParam(const char *style, string &output);
class Window;
class Control;
#include "libwin32_window.h"
#include "libwin32_control.h"
long __stdcall CoreWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
class WindowManager {
public:
uint window_count;
Window **list;
long WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
bool Add(Window *window);
WindowManager();
} WindowList;
Font CreateFont(const char *name, uint height, const char *style = "");
class libwin32_init {
public:
libwin32_init();
} __libwin32_init;
#endif

View File

@@ -0,0 +1,32 @@
bool Button::Create(Window *parent_window, const char *style, int x, int y, int width, int height, const char *text) {
if(!parent_window)return false;
parent = parent_window;
id = CONTROLID_INDEX + parent->control_count;
type = BUTTON;
state.ws = WS_CHILD;
state.es = 0;
state.x = x;
state.y = y;
state.width = width;
state.height = height;
string part;
ParseStyleParam(style, part);
for(int i = 0; i < count(part); i++) {
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
if(strmatch(part[i], "disabled"))state.ws |= WS_DISABLED;
if(strmatch(part[i], "left"))state.ws |= BS_LEFT;
if(strmatch(part[i], "center"))state.ws |= BS_CENTER;
if(strmatch(part[i], "right"))state.ws |= BS_RIGHT;
}
hwnd = CreateWindowEx(state.es, "BUTTON", text, state.ws,
state.x, state.y, state.width, state.height,
parent->hwnd, (HMENU)id, GetModuleHandle(0), 0);
if(!hwnd)return false;
PostCreate();
return true;
}

View File

@@ -0,0 +1,40 @@
bool Checkbox::Checked() { return SendMessage(hwnd, BM_GETCHECK, 0, 0); }
void Checkbox::Check(bool state) { SendMessage(hwnd, BM_SETCHECK, (WPARAM)state, 0); }
void Checkbox::Check() { Check(true); }
void Checkbox::Uncheck() { Check(false); }
void Checkbox::ToggleCheck() { Check(!Checked()); }
bool Checkbox::Create(Window *parent_window, const char *style, int x, int y, int width, int height, const char *text) {
if(!parent_window)return false;
parent = parent_window;
id = CONTROLID_INDEX + parent->control_count;
type = CHECKBOX;
state.ws = WS_CHILD;
state.es = 0;
state.x = x;
state.y = y;
state.width = width;
state.height = height;
string part;
ParseStyleParam(style, part);
for(int i = 0; i < count(part); i++) {
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
if(strmatch(part[i], "disabled"))state.ws |= WS_DISABLED;
if(strmatch(part[i], "left"))state.ws |= BS_LEFT;
if(strmatch(part[i], "center"))state.ws |= BS_CENTER;
if(strmatch(part[i], "right"))state.ws |= BS_RIGHT;
if(strmatch(part[i], "auto"))state.ws |= BS_AUTOCHECKBOX;
}
if(!(state.ws & BS_AUTOCHECKBOX))state.ws |= BS_CHECKBOX;
hwnd = CreateWindowEx(state.es, "BUTTON", text, state.ws,
state.x, state.y, state.width, state.height,
parent->hwnd, (HMENU)id, GetModuleHandle(0), 0);
if(!hwnd)return false;
PostCreate();
return true;
}

View File

@@ -0,0 +1,66 @@
void Combobox::AddItem(const char *text) {
SendMessage(hwnd, CB_ADDSTRING, 0, (LPARAM)text);
}
void Combobox::DeleteItem(uint id) {
SendMessage(hwnd, CB_DELETESTRING, id, 0);
}
void Combobox::DeleteAllItems() {
SendMessage(hwnd, CB_RESETCONTENT, 0, 0);
}
uint Combobox::GetItemCount() {
return SendMessage(hwnd, CB_GETCOUNT, 0, 0);
}
void Combobox::SetSelection(uint id) {
SendMessage(hwnd, CB_SETCURSEL, id, 0);
}
int Combobox::GetSelection() {
return SendMessage(hwnd, CB_GETCURSEL, 0, 0);
}
bool Combobox::Create(Window *parent_window, const char *style, int x, int y, int width, int height, const char *text) {
if(!parent_window)return false;
parent = parent_window;
id = CONTROLID_INDEX + parent->control_count;
type = COMBOBOX;
state.ws = WS_CHILD | CBS_DROPDOWNLIST | CBS_HASSTRINGS;
state.es = 0;
state.x = x;
state.y = y;
state.width = width;
state.height = height;
string part;
ParseStyleParam(style, part);
for(int i = 0; i < count(part); i++) {
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
if(strmatch(part[i], "disabled"))state.ws |= WS_DISABLED;
if(strmatch(part[i], "border"))state.ws |= WS_BORDER;
if(strmatch(part[i], "raised"))state.ws |= WS_DLGFRAME;
if(strmatch(part[i], "sunken"))state.es |= WS_EX_STATICEDGE;
if(strmatch(part[i], "edge"))state.es |= WS_EX_CLIENTEDGE;
}
hwnd = CreateWindowEx(state.es, "COMBOBOX", text, state.ws,
state.x, state.y, state.width, state.height,
parent->hwnd, (HMENU)id, GetModuleHandle(0), 0);
if(!hwnd)return false;
if(strmatch(text, "") == false) {
string t;
split(t, "|", text);
for(int i = 0; i < ::count(t); i++) {
AddItem(strptr(t[i]));
}
}
SetSelection(0);
PostCreate();
return true;
}

View File

@@ -0,0 +1,99 @@
/*
* called after custom control type successfully creates
* control, used to initialize common control defaults
*/
void Control::PostCreate() {
SetFont(global::font_default);
parent->Add(*this);
}
uint Control::GetID() { return id; }
uint Control::GetType() { return type; }
void Control::SetFont(Font font) {
SendMessage(hwnd, WM_SETFONT, (WPARAM)font, 0);
}
void Control::Show(bool do_show) {
if(do_show == true) {
ShowWindow(hwnd, SW_NORMAL);
state.ws |= WS_VISIBLE;
} else {
ShowWindow(hwnd, SW_HIDE);
state.ws &= ~WS_VISIBLE;
}
}
bool Control::Visible() {
return !!(GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE);
}
void Control::Show() { Show(true); }
void Control::Hide() { Show(false); }
void Control::Focus() { SetFocus(hwnd); }
void Control::Enable(bool do_enable) {
if(do_enable == true) {
SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_DISABLED);
state.ws &= ~WS_DISABLED;
} else {
SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_DISABLED);
state.ws |= WS_DISABLED;
}
}
bool Control::Enabled() {
return !(GetWindowLong(hwnd, GWL_STYLE) & WS_DISABLED);
}
void Control::Enable() { Enable(true); }
void Control::Disable() { Enable(false); }
void Control::SetBackgroundColor(uint r, uint g, uint b) {
state.use_backcolor = true;
state.backcolor = (r << 16) | (g << 8) | b;
if(backbrush)DeleteObject((HGDIOBJ)backbrush);
backbrush = CreateSolidBrush(RGB(r, g, b));
if(hwnd)InvalidateRect(hwnd, 0, TRUE);
}
void Control::SetTextColor(uint r, uint g, uint b) {
state.use_textcolor = true;
state.textcolor = (r << 16) | (g << 8) | b;
if(hwnd)InvalidateRect(hwnd, 0, TRUE);
}
const char *Control::GetText() {
static char t[256 + 1];
GetWindowText(hwnd, t, 256);
return t;
}
void Control::GetText(char *text, uint length) {
GetWindowText(hwnd, text, length ? length : 255);
}
void Control::SetText(const char *text, ...) {
char str[4096];
va_list args;
va_start(args, text);
vsprintf(str, text, args);
va_end(args);
SetWindowText(hwnd, str);
}
Control::Control() {
hwnd = 0;
backbrush = 0;
state.use_backcolor = false;
state.use_textcolor = false;
state.backcolor = 0;
state.textcolor = 0;
}
Control::~Control() {
if(backbrush) {
DeleteObject((HGDIOBJ)backbrush);
backbrush = 0;
}
}

Some files were not shown because too many files have changed in this diff Show More