Compare commits

..

4 Commits
v014 ... 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
byuu
49c39e0e4d Update to bsnes v015 release.
- Added GZ / ZIP / JMA archive support [Nach, NSRT team]
    - Fixed bug in APU ADDW/SUBW opcode flags, thanks to DMV27, anomymous for info
    - Mosaic support is now (mostly) hardware accurate, thanks to TRAC for info
    - Fixed a bug in SC tilemap clipping, fixes Seiken Densetsu 3
    - Emulated pseudo-hires mode, uses a fairly poor color filter to simulate TV effect, the same one that SNES9x and Super Sleuth use
    - Rewrote the ROM loading code to be more port-friendly, and improved header detection
    - Added C4 emulation -- mostly correct. Only minor bugs remain, possibly not C4 related [Nach, byuu], also uses code from zsKnight, Overload, and anomie
    - Fixed noise channel generation for DSP, fixes Dual Orb 2 opening. Thanks to DMV27 for info
    - Fixed bug with DSP VxSRCN registers, fixes horrible sound corruption in Mortal Kombat 2/3
    - Modified DSP KON register reading to act according to anomie's research, while still allowing Der Langrisser, etc. to play sounds correctly
    - Fixed a bug in CPU BCD math, fixes numbers in SimEarth, thanks to DMV27 for info
    - Rewrote the windows port from scratch
    - -- Added triple buffering support (buggy)
    - -- Added DirectInput (joypad) support, allows both keyboard and joypad to be mapped to the same SNES controller button. Only one controller supported for this release, will be improved shortly
    - -- Added pause key (mapped to Pause/Break)
    - -- bsnes no longer consumes CPU time when paused or when no ROM is loaded
    - -- Updated DirectDraw to 7, and added video mode configuration options to configuration file
    - -- Video modes can specify screen width+height, refresh rate, and render width+height
    - -- Added CTRL+[1-0] hotkeys for swapping video modes
    - -- Added +/- hotkeys for adjusting frameskipping rate
    - -- Added adjustable speed regulation. There are five modes, all can be adjusted inside the configuration file. CTRL+[+/-] will adjust the speed mode.
    - -- Added PPU options to toggle any BG / OAM layers with any priority, HDMA effects, and offset per tile effects
    - -- Added option to accept invalid button combinations (up+down, left+right) to joypad config menu
    - -- bsnes now properly clears the main window when unloading games
    - [code] Made destructors for base classes virtual, so the correct destructors will be called now
2005-12-03 21:05:52 +00:00
327 changed files with 40165 additions and 10085 deletions

139
bsnes.cfg
View File

@@ -1,139 +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 = true)
snes.mute = false
# Regulate speed to 60hz (NTSC) / 50hz (PAL)
# (default = true)
system.regulate_speed = true
# Video mode
# 0 = 256x224w
# 1 = 512x448w
# 2 = 960x720w
# 3 = 640x480f
# 4 = 1024x768f
# (default = 1)
video.mode = 1
# Use Video RAM instead of System RAM
# (default = true)
video.use_vram = true
# Wait for vertical retrace when updating screen
# (default = false)
video.vblank = false
# Show framerate in window title
# (default = true)
gui.show_fps = true
# Joypad1 up
# (default = 0x26)
input.joypad1.up = 0x26
# Joypad1 down
# (default = 0x28)
input.joypad1.down = 0x28
# Joypad1 left
# (default = 0x25)
input.joypad1.left = 0x25
# Joypad1 right
# (default = 0x27)
input.joypad1.right = 0x27
# Joypad1 A
# (default = 0x58)
input.joypad1.a = 0x58
# Joypad1 B
# (default = 0x5a)
input.joypad1.b = 0x5a
# Joypad1 X
# (default = 0x53)
input.joypad1.x = 0x53
# Joypad1 Y
# (default = 0x41)
input.joypad1.y = 0x41
# Joypad1 L
# (default = 0x44)
input.joypad1.l = 0x44
# Joypad1 R
# (default = 0x43)
input.joypad1.r = 0x43
# Joypad1 select
# (default = 0x10)
input.joypad1.select = 0x10
# Joypad1 start
# (default = 0xd)
input.joypad1.start = 0xd
# Joypad2 up
# (default = 0x54)
input.joypad2.up = 0x54
# Joypad2 down
# (default = 0x47)
input.joypad2.down = 0x47
# Joypad2 left
# (default = 0x46)
input.joypad2.left = 0x46
# Joypad2 right
# (default = 0x48)
input.joypad2.right = 0x48
# Joypad2 A
# (default = 0x4b)
input.joypad2.a = 0x4b
# Joypad2 B
# (default = 0x4a)
input.joypad2.b = 0x4a
# Joypad2 X
# (default = 0x49)
input.joypad2.x = 0x49
# Joypad2 Y
# (default = 0x55)
input.joypad2.y = 0x55
# Joypad2 L
# (default = 0x4f)
input.joypad2.l = 0x4f
# Joypad2 R
# (default = 0x4c)
input.joypad2.r = 0x4c
# Joypad2 select
# (default = 0x5b)
input.joypad2.select = 0x5b
# Joypad2 start
# (default = 0x5d)
input.joypad2.start = 0x5d

BIN
bsnes.exe

Binary file not shown.

View File

@@ -27,4 +27,7 @@ static const uint8 iplrom[64];
virtual bool in_opcode();
void disassemble_opcode(char *output);
inline uint16 __relb(int8 offset, int op_len);
APU() {}
virtual ~APU() {}
};

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

@@ -9,12 +9,11 @@ int16 r = x + y + regs.p.c;
}
uint16 bAPU::op_addw(uint16 x, uint16 y) {
int32 r = x + y;
regs.p.n = !!(r & 0x8000);
regs.p.v = !!(~(x ^ y) & (y ^ (uint16)r) & 0x8000);
regs.p.h = !!((x ^ y ^ (uint16)r) & 0x10);
int16 r;
regs.p.c = 0;
r = op_adc(x, y);
r |= op_adc(x >> 8, y >> 8) << 8;
regs.p.z = ((uint16)r == 0);
regs.p.c = (r > 0xffff);
return r;
}
@@ -66,12 +65,11 @@ int16 r = x - y - !regs.p.c;
}
uint16 bAPU::op_subw(uint16 x, uint16 y) {
int32 r = x - y;
regs.p.n = !!(r & 0x8000);
regs.p.v = !!((x ^ y) & (x ^ (uint16)r) & 0x8000);
regs.p.h = !((x ^ y ^ (uint16)r) & 0x10);
int16 r;
regs.p.c = 1;
r = op_sbc(x, y);
r |= op_sbc(x >> 8, y >> 8) << 8;
regs.p.z = ((uint16)r == 0);
regs.p.c = (r >= 0);
return r;
}

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,4 +1,26 @@
//#define DEBUGGER
#define BSNES_VERSION "0.016"
#define BSNES_TITLE "bsnes v" BSNES_VERSION
#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
//enable 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
@@ -11,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_
@@ -35,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, ...);

369
src/cart/cart.cpp Normal file
View File

@@ -0,0 +1,369 @@
#include "../base.h"
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;
} else if(cart.header_index == 0x7fc0 && rom[cart.header_index + MAPPER] == 0x32) {
cart.mapper = EXLOROM;
} else if(cart.header_index == 0x7fc0) {
cart.mapper = LOROM;
} else if(cart.header_index == 0xffc0) {
cart.mapper = HIROM;
} else { //cart.header_index == 0x40ffc0
cart.mapper = EXHIROM;
}
uint8 mapper = rom[cart.header_index + MAPPER];
uint8 rom_type = rom[cart.header_index + ROM_TYPE];
if(mapper == 0x35 && rom_type == 0x55) {
cart.srtc = true;
}
if(mapper == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
cart.sdd1 = true;
}
if(mapper == 0x20 && rom_type == 0xf3) {
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] & 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++) {
if(cart.name[i] & 0x80) {
cart.name[i] = '?';
}
}
}
void Cartridge::find_header() {
int32 score_lo = 0,
score_hi = 0,
score_ex = 0;
if(rom_size < 0x010000) {
//cart too small to be anything else
cart.header_index = 0x007fc0;
return;
}
if((rom[0x7fc0 + MAPPER] & ~0x10) == 0x20)score_lo++;
if((rom[0xffc0 + MAPPER] & ~0x10) == 0x21)score_hi++;
if(rom[0x7fc0 + ROM_TYPE] < 0x08)score_lo++;
if(rom[0xffc0 + ROM_TYPE] < 0x08)score_hi++;
if(rom[0x7fc0 + ROM_SIZE] < 0x10)score_lo++;
if(rom[0xffc0 + ROM_SIZE] < 0x10)score_hi++;
if(rom[0x7fc0 + SRAM_SIZE] < 0x08)score_lo++;
if(rom[0xffc0 + SRAM_SIZE] < 0x08)score_hi++;
if(rom[0x7fc0 + REGION] < 14)score_lo++;
if(rom[0xffc0 + REGION] < 14)score_hi++;
if(rom[0x7fc0 + LICENSE] < 3)score_lo++;
if(rom[0xffc0 + LICENSE] < 3)score_hi++;
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 && (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 && (cksum != 0) && (icksum != 0)) {
score_hi += 8;
}
if(rom_size < 0x401000) {
score_ex = 0;
} else {
if(rom[0x7fc0 + MAPPER] == 0x32)score_lo++;
else score_ex += 16;
}
if(score_lo >= score_hi && score_lo >= score_ex) {
cart.header_index = 0x007fc0;
} else if(score_hi >= score_ex) {
cart.header_index = 0x00ffc0;
} else {
cart.header_index = 0x40ffc0;
}
}
void Cartridge::load_sram() {
if(cart.sram_size == 0) {
sram = 0;
return;
}
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);
}
void Cartridge::save_sram() {
if(cart.sram_size == 0)return;
FileWriter ff(sram_fn);
if(!ff.ready())return;
ff.write(sram, cart.sram_size);
}
void Cartridge::load_rom(Reader *rf) {
base_rom = rf->read();
rom_size = rf->size();
if((rom_size & 0x7fff) == 0x0200) {
rom = base_rom + 512;
rom_size -= 512;
} else {
rom = base_rom;
}
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) {
if(cart_loaded == true)return false;
if(strlen(fn) < 3)return false;
dprintf("* Loading \"%s\"...", fn);
strcpy(rom_fn, fn);
switch(Reader::detect(rom_fn)) {
case Reader::RF_NORMAL: {
FileReader ff(rom_fn);
if(!ff.ready()) {
alert("Error loading image file (%s)!", rom_fn);
return false;
}
load_rom(static_cast<Reader*>(&ff));
break;
}
#ifdef GZIP_SUPPORT
case Reader::RF_GZ: {
GZReader gf(rom_fn);
if(!gf.ready()) {
alert("Error loading image file (%s)!", rom_fn);
return false;
}
load_rom(static_cast<Reader*>(&gf));
break;
}
case Reader::RF_ZIP: {
ZipReader zf(rom_fn);
load_rom(static_cast<Reader*>(&zf));
break;
}
#endif
#ifdef JMA_SUPPORT
case Reader::RF_JMA: {
try {
JMAReader jf(rom_fn);
load_rom(static_cast<Reader*>(&jf));
} catch(JMA::jma_errors jma_error) {
alert("Error loading image file (%s)!", rom_fn);
return false;
}
break;
}
#endif
}
//remove ROM extension
strcpy(sram_fn, fn);
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));
}
find_header();
read_header();
load_sram();
cart_loaded = true;
r_mem->load_cart();
return true;
}
bool Cartridge::unload() {
if(cart_loaded == false)return false;
r_mem->unload_cart();
if(base_rom) {
SafeFree(base_rom);
}
if(sram) {
save_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;
return true;
}
Cartridge::Cartridge() {
cart_loaded = false;
base_rom = 0;
rom = 0;
sram = 0;
rom_size = 0;
}
Cartridge::~Cartridge() {
if(cart_loaded == true) {
unload();
}
}

68
src/cart/cart.h Normal file
View File

@@ -0,0 +1,68 @@
class Cartridge {
public:
bool cart_loaded;
char rom_fn[4096], sram_fn[4096], cheat_fn[4096], patch_fn[4096];
uint8 *base_rom, *rom, *sram;
uint32 rom_size;
enum {
//header fields
CART_NAME = 0x00,
MAPPER = 0x15,
ROM_TYPE = 0x16,
ROM_SIZE = 0x17,
SRAM_SIZE = 0x18,
REGION = 0x19,
LICENSE = 0x1a,
VERSION = 0x1b,
ICKSUM = 0x1c,
CKSUM = 0x1e,
//regions
NTSC = 0,
PAL = 1,
//memory mappers
LOROM = 0x20,
HIROM = 0x21,
EXLOROM = 0x22,
EXHIROM = 0x25,
};
struct {
uint32 crc32;
uint32 header_index;
char name[32];
uint32 rom_size;
uint32 sram_size;
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();
Cartridge();
~Cartridge();
};
extern Cartridge cartridge;

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;

197
src/chip/c4/c4.cpp Normal file
View File

@@ -0,0 +1,197 @@
/*
C4 emulation
Used in Rockman X2/X3 (Megaman X2/X3)
Portions (c) anomie, Overload, zsKnight, Nach, byuu
*/
#include "../../base.h"
#include "c4data.cpp"
#include "c4fn.cpp"
#include "c4oam.cpp"
#include "c4ops.cpp"
void C4::init() {}
void C4::enable() {}
uint32 C4::ldr(uint8 r) {
uint16 addr = 0x0080 + (r * 3);
return (reg[addr]) | (reg[addr + 1] << 8) | (reg[addr + 2] << 16);
}
void C4::str(uint8 r, uint32 data) {
uint16 addr = 0x0080 + (r * 3);
reg[addr ] = (data);
reg[addr + 1] = (data >> 8);
reg[addr + 2] = (data >> 16);
}
void C4::mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh) {
int64 rx = x & 0xffffff;
int64 ry = y & 0xffffff;
if(rx & 0x800000)rx |= ~0x7fffff;
if(ry & 0x800000)ry |= ~0x7fffff;
rx *= ry;
rl = (rx) & 0xffffff;
rh = (rx >> 24) & 0xffffff;
}
uint32 C4::sin(uint32 rx) {
r0 = rx & 0x1ff;
if(r0 & 0x100)r0 ^= 0x1ff;
if(r0 & 0x080)r0 ^= 0x0ff;
if(rx & 0x100) {
return sin_table[r0 + 0x80];
} else {
return sin_table[r0];
}
}
uint32 C4::cos(uint32 rx) {
return sin(rx + 0x080);
}
void C4::immediate_reg(uint32 start) {
r0 = ldr(0);
for(uint32 i=start;i<48;i++) {
if((r0 & 0x0fff) < 0x0c00) {
ram[r0 & 0x0fff] = immediate_data[i];
}
r0++;
}
str(0, r0);
}
void C4::transfer_data() {
uint32 src;
uint16 dest, count;
src = (reg[0x40]) | (reg[0x41] << 8) | (reg[0x42] << 16);
count = (reg[0x43]) | (reg[0x44] << 8);
dest = (reg[0x45]) | (reg[0x46] << 8);
for(uint32 i=0;i<count;i++) {
write(dest++, r_mem->read(src++));
}
}
void C4::write(uint16 addr, uint8 data) {
addr &= 0x1fff;
if(addr < 0x0c00) {
//ram
ram[addr] = data;
return;
}
if(addr < 0x1f00) {
//unmapped
return;
}
//command register
reg[addr & 0xff] = data;
if(addr == 0x1f47) {
//memory transfer
transfer_data();
return;
}
if(addr == 0x1f4f) {
//c4 command
if(reg[0x4d] == 0x0e && !(data & 0xc3)) {
//c4 test command
reg[0x80] = data >> 2;
return;
}
switch(data) {
case 0x00:op00();break;
case 0x01:op01();break;
case 0x05:op05();break;
case 0x0d:op0d();break;
case 0x10:op10();break;
case 0x13:op13();break;
case 0x15:op15();break;
case 0x1f:op1f();break;
case 0x22:op22();break;
case 0x25:op25();break;
case 0x2d:op2d();break;
case 0x40:op40();break;
case 0x54:op54();break;
case 0x5c:op5c();break;
case 0x5e:op5e();break;
case 0x60:op60();break;
case 0x62:op62();break;
case 0x64:op64();break;
case 0x66:op66();break;
case 0x68:op68();break;
case 0x6a:op6a();break;
case 0x6c:op6c();break;
case 0x6e:op6e();break;
case 0x70:op70();break;
case 0x72:op72();break;
case 0x74:op74();break;
case 0x76:op76();break;
case 0x78:op78();break;
case 0x7a:op7a();break;
case 0x7c:op7c();break;
case 0x89:op89();break;
}
}
}
void C4::writeb(uint16 addr, uint8 data) {
write(addr, data);
}
void C4::writew(uint16 addr, uint16 data) {
write(addr, data);
write(addr + 1, data >> 8);
}
void C4::writel(uint16 addr, uint32 data) {
write(addr, data);
write(addr + 1, data >> 8);
write(addr + 2, data >> 16);
}
uint8 C4::read(uint16 addr) {
addr &= 0x1fff;
if(addr < 0x0c00) {
return ram[addr];
}
if(addr >= 0x1f00) {
return reg[addr & 0xff];
}
return r_cpu->regs.mdr;
}
uint8 C4::readb(uint16 addr) {
return read(addr);
}
uint16 C4::readw(uint16 addr) {
return read(addr) | (read(addr + 1) << 8);
}
uint32 C4::readl(uint16 addr) {
return read(addr) | (read(addr + 1) << 8) + (read(addr + 2) << 16);
}
void C4::power() {
reset();
}
void C4::reset() {
memset(ram, 0, 0x0c00);
memset(reg, 0, 0x0100);
}
C4::C4() {}

94
src/chip/c4/c4.h Normal file
View File

@@ -0,0 +1,94 @@
class C4 {
private:
uint8 ram[0x0c00];
uint8 reg[0x0100];
uint32 r0, r1, r2, r3, r4, r5, r6, r7,
r8, r9, r10, r11, r12, r13, r14, r15;
static const uint8 immediate_data[48];
static const uint16 wave_data[40];
static const uint32 sin_table[256];
static const int16 SinTable[512];
static const int16 CosTable[512];
int16 C4WFXVal, C4WFYVal, C4WFZVal, C4WFX2Val, C4WFY2Val, C4WFDist, C4WFScale;
int16 C41FXVal, C41FYVal, C41FAngleRes, C41FDist, C41FDistVal;
double tanval;
double c4x,c4y,c4z, c4x2,c4y2,c4z2;
void C4TransfWireFrame();
void C4TransfWireFrame2();
void C4CalcWireFrame();
void C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color);
void C4DrawWireFrame();
void C4DoScaleRotate(int row_padding);
public:
uint32 ldr(uint8 r);
void str(uint8 r, uint32 data);
void mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh);
uint32 sin(uint32 rx);
uint32 cos(uint32 rx);
void transfer_data();
void immediate_reg(uint32 num);
void op00_00();
void op00_03();
void op00_05();
void op00_07();
void op00_08();
void op00_0b();
void op00_0c();
void op00();
void op01();
void op05();
void op0d();
void op10();
void op13();
void op15();
void op1f();
void op22();
void op25();
void op2d();
void op40();
void op54();
void op5c();
void op5e();
void op60();
void op62();
void op64();
void op66();
void op68();
void op6a();
void op6c();
void op6e();
void op70();
void op72();
void op74();
void op76();
void op78();
void op7a();
void op7c();
void op89();
void init();
void enable();
void power();
void reset();
void write (uint16 addr, uint8 data);
void writeb(uint16 addr, uint8 data);
void writew(uint16 addr, uint16 data);
void writel(uint16 addr, uint32 data);
uint8 read (uint16 addr);
uint8 readb(uint16 addr);
uint16 readw(uint16 addr);
uint32 readl(uint16 addr);
C4();
};

183
src/chip/c4/c4data.cpp Normal file
View File

@@ -0,0 +1,183 @@
const uint8 C4::immediate_data[48] = {
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f,
0x00, 0x80, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff,
0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00
};
const uint16 C4::wave_data[40] = {
0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020a, 0x020c, 0x020e,
0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e,
0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060a, 0x060c, 0x060e,
0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080a, 0x080c, 0x080e
};
const uint32 C4::sin_table[256] = {
0x000000, 0x000324, 0x000648, 0x00096c, 0x000c8f, 0x000fb2, 0x0012d5, 0x0015f6,
0x001917, 0x001c37, 0x001f56, 0x002273, 0x002590, 0x0028aa, 0x002bc4, 0x002edb,
0x0031f1, 0x003505, 0x003817, 0x003b26, 0x003e33, 0x00413e, 0x004447, 0x00474d,
0x004a50, 0x004d50, 0x00504d, 0x005347, 0x00563e, 0x005931, 0x005c22, 0x005f0e,
0x0061f7, 0x0064dc, 0x0067bd, 0x006a9b, 0x006d74, 0x007049, 0x007319, 0x0075e5,
0x0078ad, 0x007b70, 0x007e2e, 0x0080e7, 0x00839c, 0x00864b, 0x0088f5, 0x008b9a,
0x008e39, 0x0090d3, 0x009368, 0x0095f6, 0x00987f, 0x009b02, 0x009d7f, 0x009ff6,
0x00a267, 0x00a4d2, 0x00a736, 0x00a994, 0x00abeb, 0x00ae3b, 0x00b085, 0x00b2c8,
0x00b504, 0x00b73a, 0x00b968, 0x00bb8f, 0x00bdae, 0x00bfc7, 0x00c1d8, 0x00c3e2,
0x00c5e4, 0x00c7de, 0x00c9d1, 0x00cbbb, 0x00cd9f, 0x00cf7a, 0x00d14d, 0x00d318,
0x00d4db, 0x00d695, 0x00d848, 0x00d9f2, 0x00db94, 0x00dd2d, 0x00debe, 0x00e046,
0x00e1c5, 0x00e33c, 0x00e4aa, 0x00e60f, 0x00e76b, 0x00e8bf, 0x00ea09, 0x00eb4b,
0x00ec83, 0x00edb2, 0x00eed8, 0x00eff5, 0x00f109, 0x00f213, 0x00f314, 0x00f40b,
0x00f4fa, 0x00f5de, 0x00f6ba, 0x00f78b, 0x00f853, 0x00f912, 0x00f9c7, 0x00fa73,
0x00fb14, 0x00fbac, 0x00fc3b, 0x00fcbf, 0x00fd3a, 0x00fdab, 0x00fe13, 0x00fe70,
0x00fec4, 0x00ff0e, 0x00ff4e, 0x00ff84, 0x00ffb1, 0x00ffd3, 0x00ffec, 0x00fffb,
0x000000, 0xfffcdb, 0xfff9b7, 0xfff693, 0xfff370, 0xfff04d, 0xffed2a, 0xffea09,
0xffe6e8, 0xffe3c8, 0xffe0a9, 0xffdd8c, 0xffda6f, 0xffd755, 0xffd43b, 0xffd124,
0xffce0e, 0xffcafa, 0xffc7e8, 0xffc4d9, 0xffc1cc, 0xffbec1, 0xffbbb8, 0xffb8b2,
0xffb5af, 0xffb2af, 0xffafb2, 0xffacb8, 0xffa9c1, 0xffa6ce, 0xffa3dd, 0xffa0f1,
0xff9e08, 0xff9b23, 0xff9842, 0xff9564, 0xff928b, 0xff8fb6, 0xff8ce6, 0xff8a1a,
0xff8752, 0xff848f, 0xff81d1, 0xff7f18, 0xff7c63, 0xff79b4, 0xff770a, 0xff7465,
0xff71c6, 0xff6f2c, 0xff6c97, 0xff6a09, 0xff6780, 0xff64fd, 0xff6280, 0xff6009,
0xff5d98, 0xff5b2d, 0xff58c9, 0xff566b, 0xff5414, 0xff51c4, 0xff4f7a, 0xff4d37,
0xff4afb, 0xff48c5, 0xff4697, 0xff4470, 0xff4251, 0xff4038, 0xff3e27, 0xff3c1e,
0xff3a1b, 0xff3821, 0xff362e, 0xff3444, 0xff3260, 0xff3085, 0xff2eb2, 0xff2ce7,
0xff2b24, 0xff296a, 0xff27b7, 0xff260d, 0xff246b, 0xff22d2, 0xff2141, 0xff1fb9,
0xff1e3a, 0xff1cc3, 0xff1b55, 0xff19f0, 0xff1894, 0xff1740, 0xff15f6, 0xff14b4,
0xff137c, 0xff124d, 0xff1127, 0xff100a, 0xff0ef6, 0xff0dec, 0xff0ceb, 0xff0bf4,
0xff0b05, 0xff0a21, 0xff0945, 0xff0874, 0xff07ac, 0xff06ed, 0xff0638, 0xff058d,
0xff04eb, 0xff0453, 0xff03c4, 0xff0340, 0xff02c5, 0xff0254, 0xff01ec, 0xff018f,
0xff013b, 0xff00f1, 0xff00b1, 0xff007b, 0xff004e, 0xff002c, 0xff0013, 0xff0004
};
const int16 C4::SinTable[512] = {
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765,
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402
};
const int16 C4::CosTable[512] = {
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402,
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765
};

242
src/chip/c4/c4fn.cpp Normal file
View File

@@ -0,0 +1,242 @@
#include <math.h>
#define Tan(a) (CosTable[a] ? ((((int32)SinTable[a]) << 16) / CosTable[a]) : 0x80000000)
#define sar(b, n) ((b) >> (n))
#ifdef PI
#undef PI
#endif
#define PI 3.1415926535897932384626433832795
//Wireframe Helpers
void C4::C4TransfWireFrame() {
c4x = (double)C4WFXVal;
c4y = (double)C4WFYVal;
c4z = (double)C4WFZVal - 0x95;
//Rotate X
tanval = -(double)C4WFX2Val * PI * 2 / 128;
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
//Rotate Y
tanval = -(double)C4WFY2Val * PI * 2 / 128;
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
//Rotate Z
tanval = -(double)C4WFDist * PI * 2 / 128;
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
//Scale
C4WFXVal = (int16)(c4x * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
C4WFYVal = (int16)(c4y * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
}
void C4::C4CalcWireFrame() {
C4WFXVal = C4WFX2Val - C4WFXVal;
C4WFYVal = C4WFY2Val - C4WFYVal;
if(abs(C4WFXVal) > abs(C4WFYVal)) {
C4WFDist = abs(C4WFXVal) + 1;
C4WFYVal = (256 * (long)C4WFYVal) / abs(C4WFXVal);
C4WFXVal = (C4WFXVal < 0) ? -256 : 256;
} else if(C4WFYVal != 0) {
C4WFDist = abs(C4WFYVal) + 1;
C4WFXVal = (256 * (long)C4WFXVal) / abs(C4WFYVal);
C4WFYVal = (C4WFYVal < 0) ? -256 : 256;
} else {
C4WFDist = 0;
}
}
void C4::C4TransfWireFrame2() {
c4x = (double)C4WFXVal;
c4y = (double)C4WFYVal;
c4z = (double)C4WFZVal;
//Rotate X
tanval = -(double)C4WFX2Val * PI * 2 / 128;
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
//Rotate Y
tanval = -(double)C4WFY2Val * PI * 2 / 128;
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
//Rotate Z
tanval = -(double)C4WFDist * PI * 2 / 128;
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
//Scale
C4WFXVal = (int16)(c4x * C4WFScale / 0x100);
C4WFYVal = (int16)(c4y * C4WFScale / 0x100);
}
void C4::C4DrawWireFrame() {
uint32 line = readl(0x1f80);
uint32 point1, point2;
int16 X1, Y1, Z1;
int16 X2, Y2, Z2;
uint8 Color;
for(int32 i = ram[0x0295]; i > 0; i--, line += 5) {
if(r_mem->read(line) == 0xff && r_mem->read(line + 1) == 0xff) {
int32 tmp = line - 5;
while(r_mem->read(tmp + 2) == 0xff && r_mem->read(tmp + 3) == 0xff && (tmp + 2) >= 0) { tmp -= 5; }
point1 = (read(0x1f82) << 16) | (r_mem->read(tmp + 2) << 8) | r_mem->read(tmp + 3);
} else {
point1 = (read(0x1f82) << 16) | (r_mem->read(line) << 8) | r_mem->read(line + 1);
}
point2 = (read(0x1f82) << 16) | (r_mem->read(line + 2) << 8) | r_mem->read(line + 3);
X1=(r_mem->read(point1 + 0) << 8) | r_mem->read(point1 + 1);
Y1=(r_mem->read(point1 + 2) << 8) | r_mem->read(point1 + 3);
Z1=(r_mem->read(point1 + 4) << 8) | r_mem->read(point1 + 5);
X2=(r_mem->read(point2 + 0) << 8) | r_mem->read(point2 + 1);
Y2=(r_mem->read(point2 + 2) << 8) | r_mem->read(point2 + 3);
Z2=(r_mem->read(point2 + 4) << 8) | r_mem->read(point2 + 5);
Color = r_mem->read(line + 4);
C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color);
}
}
void C4::C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color) {
//Transform coordinates
C4WFXVal = (int16)X1;
C4WFYVal = (int16)Y1;
C4WFZVal = Z1;
C4WFScale = read(0x1f90);
C4WFX2Val = read(0x1f86);
C4WFY2Val = read(0x1f87);
C4WFDist = read(0x1f88);
C4TransfWireFrame2();
X1 = (C4WFXVal + 48) << 8;
Y1 = (C4WFYVal + 48) << 8;
C4WFXVal = (int16)X2;
C4WFYVal = (int16)Y2;
C4WFZVal = Z2;
C4TransfWireFrame2();
X2 = (C4WFXVal + 48) << 8;
Y2 = (C4WFYVal + 48) << 8;
//Get line info
C4WFXVal = (int16)(X1 >> 8);
C4WFYVal = (int16)(Y1 >> 8);
C4WFX2Val = (int16)(X2 >> 8);
C4WFY2Val = (int16)(Y2 >> 8);
C4CalcWireFrame();
X2 = (int16)C4WFXVal;
Y2 = (int16)C4WFYVal;
//Render line
for(int32 i = C4WFDist ? C4WFDist : 1; i > 0; i--) {
if(X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000) {
uint16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2;
uint8 bit = 0x80 >> ((X1 >> 8) & 7);
ram[addr + 0x300] &= ~bit;
ram[addr + 0x301] &= ~bit;
if(Color & 1) { ram[addr + 0x300] |= bit; }
if(Color & 2) { ram[addr + 0x301] |= bit; }
}
X1 += X2;
Y1 += Y2;
}
}
void C4::C4DoScaleRotate(int row_padding) {
int16 A, B, C, D;
//Calculate matrix
int32 XScale = readw(0x1f8f);
int32 YScale = readw(0x1f92);
if(XScale & 0x8000)XScale = 0x7fff;
if(YScale & 0x8000)YScale = 0x7fff;
if(readw(0x1f80) == 0) { //no rotation
A = (int16)XScale;
B = 0;
C = 0;
D = (int16)YScale;
} else if(readw(0x1f80) == 128) { //90 degree rotation
A = 0;
B = (int16)(-YScale);
C = (int16)XScale;
D = 0;
} else if(readw(0x1f80) == 256) { //180 degree rotation
A = (int16)(-XScale);
B = 0;
C = 0;
D = (int16)(-YScale);
} else if(readw(0x1f80) == 384) { //270 degree rotation
A = 0;
B = (int16)YScale;
C = (int16)(-XScale);
D = 0;
} else {
A = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * XScale, 15);
B = (int16)(-sar(SinTable[readw(0x1f80) & 0x1ff] * YScale, 15));
C = (int16) sar(SinTable[readw(0x1f80) & 0x1ff] * XScale, 15);
D = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * YScale, 15);
}
//Calculate Pixel Resolution
uint8 w = read(0x1f89) & ~7;
uint8 h = read(0x1f8c) & ~7;
//Clear the output RAM
memset(ram, 0, (w + row_padding / 4) * h / 2);
int32 Cx = (int16)readw(0x1f83);
int32 Cy = (int16)readw(0x1f86);
//Calculate start position (i.e. (Ox, Oy) = (0, 0))
//The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in
//the function. We do Cx*A etc normally because the matrix parameters
//already have the fractional parts.
int32 LineX = (Cx << 12) - Cx * A - Cx * B;
int32 LineY = (Cy << 12) - Cy * C - Cy * D;
//Start loop
uint32 X, Y;
uint8 byte;
int32 outidx = 0;
uint8 bit = 0x80;
for(int32 y = 0; y < h; y++) {
X = LineX;
Y = LineY;
for(int32 x = 0; x < w; x++) {
if((X >> 12) >= w || (Y >> 12) >= h) {
byte = 0;
} else {
uint32 addr = (Y >> 12) * w + (X >> 12);
byte = read(0x600 + (addr >> 1));
if(addr & 1) { byte >>= 4; }
}
//De-bitplanify
if(byte & 1) { ram[outidx ] |= bit; }
if(byte & 2) { ram[outidx + 1] |= bit; }
if(byte & 4) { ram[outidx + 16] |= bit; }
if(byte & 8) { ram[outidx + 17] |= bit; }
bit >>= 1;
if(!bit) {
bit = 0x80;
outidx += 32;
}
X += A; //Add 1 to output x => add an A and a C
Y += C;
}
outidx += 2 + row_padding;
if(outidx & 0x10) {
outidx &= ~0x10;
} else {
outidx -= w * 4 + row_padding;
}
LineX += B; //Add 1 to output y => add a B and a D
LineY += D;
}
}

224
src/chip/c4/c4oam.cpp Normal file
View File

@@ -0,0 +1,224 @@
//Build OAM
void C4::op00_00() {
uint32 oamptr = ram[0x626] << 2;
for(int32 i=0x1fd;i>oamptr && i>=0;i-=4) {
//clear oam-to-be
if(i >= 0)ram[i] = 0xe0;
}
uint16 globalx, globaly;
uint32 oamptr2;
int16 sprx, spry;
uint8 sprname, sprattr;
uint8 sprcount;
globalx = readw(0x621);
globaly = readw(0x623);
oamptr2 = 0x200 + (ram[0x626] >> 2);
if(!ram[0x620])return;
sprcount = 128 - ram[0x626];
uint8 offset = (ram[0x626] & 3) * 2;
for(int pri=0x30;pri>=0;pri-=0x10) {
uint32 srcptr = 0x220;
for(int i=ram[0x620];i>0 && sprcount>0;i--, srcptr+=16) {
if((ram[srcptr + 4] & 0x30) != pri)continue;
sprx = readw(srcptr) - globalx;
spry = readw(srcptr + 2) - globaly;
sprname = ram[srcptr + 5];
sprattr = ram[srcptr + 4] | ram[srcptr + 6];
uint32 spraddr = readl(srcptr + 7);
if(r_mem->read(spraddr)) {
int16 x, y;
for(int sprcnt=r_mem->read(spraddr++);sprcnt>0 && sprcount>0;sprcnt--, spraddr+=4) {
x = (int8)r_mem->read(spraddr + 1);
if(sprattr & 0x40) {
x = -x - ((r_mem->read(spraddr) & 0x20) ? 16 : 8);
}
x += sprx;
if(x >= -16 && x <= 272) {
y = (int8)r_mem->read(spraddr + 2);
if(sprattr & 0x80) {
y = -y - ((r_mem->read(spraddr) & 0x20) ? 16 : 8);
}
y += spry;
if(y >= -16 && y <= 224) {
ram[oamptr ] = (uint8)x;
ram[oamptr + 1] = (uint8)y;
ram[oamptr + 2] = sprname + r_mem->read(spraddr + 3);
ram[oamptr + 3] = sprattr ^ (r_mem->read(spraddr) & 0xc0);
ram[oamptr2] &= ~(3 << offset);
if(x & 0x100)ram[oamptr2] |= 1 << offset;
if(r_mem->read(spraddr) & 0x20)ram[oamptr2] |= 2 << offset;
oamptr += 4;
sprcount--;
offset = (offset + 2) & 6;
if(!offset)oamptr2++;
}
}
}
} else if(sprcount > 0) {
ram[oamptr ] = (uint8)sprx;
ram[oamptr + 1] = (uint8)spry;
ram[oamptr + 2] = sprname;
ram[oamptr + 3] = sprattr;
ram[oamptr2] &= ~(3 << offset);
if(sprx & 0x100)ram[oamptr2] |= 3 << offset;
else ram[oamptr2] |= 2 << offset;
oamptr += 4;
sprcount--;
offset = (offset + 2) & 6;
if(!offset)oamptr2++;
}
}
}
}
//Scale and Rotate
void C4::op00_03() {
C4DoScaleRotate(0);
}
//Transform Lines
void C4::op00_05() {
C4WFX2Val = read(0x1f83);
C4WFY2Val = read(0x1f86);
C4WFDist = read(0x1f89);
C4WFScale = read(0x1f8c);
//Transform Vertices
uint32 ptr = 0;
for(int32 i = readw(0x1f80); i > 0; i--, ptr += 0x10) {
C4WFXVal = readw(ptr + 1);
C4WFYVal = readw(ptr + 5);
C4WFZVal = readw(ptr + 9);
C4TransfWireFrame();
//Displace
writew(ptr + 1, C4WFXVal + 0x80);
writew(ptr + 5, C4WFYVal + 0x50);
}
writew(0x600, 23);
writew(0x602, 0x60);
writew(0x605, 0x40);
writew(0x600 + 8, 23);
writew(0x602 + 8, 0x60);
writew(0x605 + 8, 0x40);
ptr = 0xb02;
uint32 ptr2 = 0;
for(int32 i = readw(0xb00); i > 0; i--, ptr += 2, ptr2 += 8) {
C4WFXVal = readw((read(ptr + 0) << 4) + 1);
C4WFYVal = readw((read(ptr + 0) << 4) + 5);
C4WFX2Val = readw((read(ptr + 1) << 4) + 1);
C4WFY2Val = readw((read(ptr + 1) << 4) + 5);
C4CalcWireFrame();
writew(ptr2 + 0x600, C4WFDist ? C4WFDist : 1);
writew(ptr2 + 0x602, C4WFXVal);
writew(ptr2 + 0x605, C4WFYVal);
}
}
//Scale and Rotate
void C4::op00_07() {
C4DoScaleRotate(64);
}
//Draw Wireframe
void C4::op00_08() {
C4DrawWireFrame();
}
//Disintegrate
void C4::op00_0b() {
uint8 width, height;
uint32 startx, starty;
uint32 srcptr;
uint32 x, y;
int32 scalex, scaley;
int32 cx, cy;
int32 i, j;
width = read(0x1f89);
height = read(0x1f8c);
cx = readw(0x1f80);
cy = readw(0x1f83);
scalex = (int16)readw(0x1f86);
scaley = (int16)readw(0x1f8f);
startx = -cx * scalex + (cx << 8);
starty = -cy * scaley + (cy << 8);
srcptr = 0x600;
for(i = 0; i < (width * height) >> 1; i++) {
write(i, 0);
}
for(y = starty, i = 0;i < height; i++, y += scaley) {
for(x = startx, j = 0;j < width; j++, x += scalex) {
if((x >> 8) < width && (y >> 8) < height && (y >> 8) * width + (x >> 8) < 0x2000) {
uint8 pixel = (j & 1) ? (ram[srcptr] >> 4) : (ram[srcptr]);
int32 index = (y >> 11) * width * 4 + (x >> 11) * 32 + ((y >> 8) & 7) * 2;
uint8 mask = 0x80 >> ((x >> 8) & 7);
if(pixel & 1)ram[index ] |= mask;
if(pixel & 2)ram[index + 1] |= mask;
if(pixel & 4)ram[index + 16] |= mask;
if(pixel & 8)ram[index + 17] |= mask;
}
if(j & 1)srcptr++;
}
}
}
//Bitplane Wave
void C4::op00_0c() {
uint32 destptr = 0;
uint32 waveptr = read(0x1f83);
uint16 mask1 = 0xc0c0;
uint16 mask2 = 0x3f3f;
int32 i, j;
int16 height, temp;
for(j = 0; j < 0x10; j++) {
do {
height = -((int8)ram[waveptr + 0xb00]) - 16;
for(i = 0; i < 40; i++) {
temp = readw(destptr + wave_data[i]) & mask2;
if(height >= 0) {
if(height < 8) {
temp |= mask1 & readw(0xa00 + height * 2);
} else {
temp |= mask1 & 0xff00;
}
}
writew(destptr + wave_data[i], temp);
height++;
}
waveptr = (waveptr + 1) & 0x7f;
mask1 = (mask1 >> 2) | (mask1 << 6);
mask2 = (mask2 >> 2) | (mask2 << 6);
} while(mask1 != 0xc0c0);
destptr += 16;
do {
height = -((int8)ram[waveptr + 0xb00]) - 16;
for(i = 0; i < 40; i++) {
temp = readw(destptr + wave_data[i]) & mask2;
if(height >= 0) {
if(height < 8) {
temp |= mask1 & readw(0xa10 + height * 2);
} else {
temp |= mask1 & 0xff00;
}
writew(destptr + wave_data[i], temp);
height++;
}
waveptr = (waveptr + 1) & 0x7f;
mask1 = (mask1 >> 2) | (mask1 << 6);
mask2 = (mask2 >> 2) | (mask2 << 6);
}
} while(mask1 != 0xc0c0);
destptr += 16;
}
}

222
src/chip/c4/c4ops.cpp Normal file
View File

@@ -0,0 +1,222 @@
//Sprite Functions
void C4::op00() {
switch(reg[0x4d]) {
case 0x00:op00_00();break;
case 0x03:op00_03();break;
case 0x05:op00_05();break;
case 0x07:op00_07();break;
case 0x08:op00_08();break;
case 0x0b:op00_0b();break;
case 0x0c:op00_0c();break;
}
}
//Draw Wireframe
void C4::op01() {
memset(ram + 0x300, 0, 2304);
C4DrawWireFrame();
}
//Propulsion
void C4::op05() {
int32 temp = 0x10000;
if(readw(0x1f83)) {
temp = sar((temp / readw(0x1f83)) * readw(0x1f81), 8);
}
writew(0x1f80, temp);
}
//Set Vector length
void C4::op0d() {
C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83);
C41FDistVal = readw(0x1f86);
tanval = sqrt(((double)C41FYVal) * ((double)C41FYVal) + ((double)C41FXVal) * ((double)C41FXVal));
tanval = (double)C41FDistVal / tanval;
C41FYVal = (int16)(((double)C41FYVal * tanval) * 0.99);
C41FXVal = (int16)(((double)C41FXVal * tanval) * 0.98);
writew(0x1f89, C41FXVal);
writew(0x1f8c, C41FYVal);
}
//Triangle
void C4::op10() {
r0 = ldr(0);
r1 = ldr(1);
r4 = r0 & 0x1ff;
if(r1 & 0x8000)r1 |= ~0x7fff;
mul(cos(r4), r1, r5, r2);
r5 = (r5 >> 16) & 0xff;
r2 = (r2 << 8) + r5;
mul(sin(r4), r1, r5, r3);
r5 = (r5 >> 16) & 0xff;
r3 = (r3 << 8) + r5;
str(0, r0);
str(1, r1);
str(2, r2);
str(3, r3);
str(4, r4);
str(5, r5);
}
//Triangle
void C4::op13() {
r0 = ldr(0);
r1 = ldr(1);
r4 = r0 & 0x1ff;
mul(cos(r4), r1, r5, r2);
r5 = (r5 >> 8) & 0xffff;
r2 = (r2 << 16) + r5;
mul(sin(r4), r1, r5, r3);
r5 = (r5 >> 8) & 0xffff;
r3 = (r3 << 16) + r5;
str(0, r0);
str(1, r1);
str(2, r2);
str(3, r3);
str(4, r4);
str(5, r5);
}
//Pythagorean
void C4::op15() {
C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83);
C41FDist = (int16)sqrt((double)C41FXVal * (double)C41FXVal + (double)C41FYVal * (double)C41FYVal);
writew(0x1f80, C41FDist);
}
//Calculate distance
void C4::op1f() {
C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83);
if(!C41FXVal) {
C41FAngleRes = (C41FYVal > 0) ? 0x080 : 0x180;
} else {
tanval = ((double)C41FYVal) / ((double)C41FXVal);
C41FAngleRes = (short)(atan(tanval) / (PI * 2) * 512);
C41FAngleRes = C41FAngleRes;
if(C41FXVal < 0) {
C41FAngleRes += 0x100;
}
C41FAngleRes &= 0x1ff;
}
writew(0x1f86, C41FAngleRes);
}
//Trapezoid
void C4::op22() {
int16 angle1 = readw(0x1f8c) & 0x1ff;
int16 angle2 = readw(0x1f8f) & 0x1ff;
int32 tan1 = Tan(angle1);
int32 tan2 = Tan(angle2);
int16 y = readw(0x1f83) - readw(0x1f89);
int16 left, right;
for(int32 j = 0; j < 225; j++, y++) {
if(y >= 0) {
left = sar((int32)tan1 * y, 16) - readw(0x1f80) + readw(0x1f86);
right = sar((int32)tan2 * y, 16) - readw(0x1f80) + readw(0x1f86) + readw(0x1f93);
if(left < 0 && right < 0) {
left = 1;
right = 0;
} else if(left < 0) {
left = 0;
} else if(right < 0) {
right = 0;
}
if(left > 255 && right > 255) {
left = 255;
right = 254;
} else if(left > 255) {
left = 255;
} else if(right > 255) {
right = 255;
}
} else {
left = 1;
right = 0;
}
ram[j + 0x800] = (uint8)left;
ram[j + 0x900] = (uint8)right;
}
}
//Multiply
void C4::op25() {
r0 = ldr(0);
r1 = ldr(1);
mul(r0, r1, r0, r1);
str(0, r0);
str(1, r1);
}
//Transform Coords
void C4::op2d() {
C4WFXVal = readw(0x1f81);
C4WFYVal = readw(0x1f84);
C4WFZVal = readw(0x1f87);
C4WFX2Val = read (0x1f89);
C4WFY2Val = read (0x1f8a);
C4WFDist = read (0x1f8b);
C4WFScale = readw(0x1f90);
C4TransfWireFrame2();
writew(0x1f80, C4WFXVal);
writew(0x1f83, C4WFYVal);
}
//Sum
void C4::op40() {
r0 = 0;
for(uint32 i=0;i<0x800;i++) {
r0 += ram[i];
}
str(0, r0);
}
//Square
void C4::op54() {
r0 = ldr(0);
mul(r0, r0, r1, r2);
str(1, r1);
str(2, r2);
}
//Immediate Register
void C4::op5c() {
str(0, 0x000000);
immediate_reg(0);
}
//Immediate Register (Multiple)
void C4::op5e() { immediate_reg( 0); }
void C4::op60() { immediate_reg( 3); }
void C4::op62() { immediate_reg( 6); }
void C4::op64() { immediate_reg( 9); }
void C4::op66() { immediate_reg(12); }
void C4::op68() { immediate_reg(15); }
void C4::op6a() { immediate_reg(18); }
void C4::op6c() { immediate_reg(21); }
void C4::op6e() { immediate_reg(24); }
void C4::op70() { immediate_reg(27); }
void C4::op72() { immediate_reg(30); }
void C4::op74() { immediate_reg(33); }
void C4::op76() { immediate_reg(36); }
void C4::op78() { immediate_reg(39); }
void C4::op7a() { immediate_reg(42); }
void C4::op7c() { immediate_reg(45); }
//Immediate ROM
void C4::op89() {
str(0, 0x054336);
str(1, 0xffffff);
}

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

@@ -1,12 +1,11 @@
#include "../../base.h"
#include "sdd1emu.cpp"
void SDD1::init() {
}
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);
}
}
@@ -51,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;
@@ -90,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

@@ -74,12 +74,11 @@ tm *t;
srtc.data[12] = t->tm_wday;
}
void SRTC::init() {
}
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() {
@@ -89,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
@@ -97,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,27 +2,79 @@ 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::mute(&config_file, "snes.mute",
"Mutes SNES audio output when enabled",
true, Setting::TRUE_FALSE);
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);
//do not save these settings to config_file
Setting CPU::hdma_enable(0, "cpu.hdma_enable", "Enable HDMA effects", true, Setting::TRUE_FALSE);
Setting PPU::opt_enable(0, "ppu.opt_enable", "Enable offset-per-tile effects", true, Setting::TRUE_FALSE);
Setting PPU::bg1_pri0_enable(0, "ppu.bg1_pri0_enable", "Enable BG1 Priority 0", true, Setting::TRUE_FALSE);
Setting PPU::bg1_pri1_enable(0, "ppu.bg1_pri1_enable", "Enable BG1 Priority 1", true, Setting::TRUE_FALSE);
Setting PPU::bg2_pri0_enable(0, "ppu.bg2_pri0_enable", "Enable BG2 Priority 0", true, Setting::TRUE_FALSE);
Setting PPU::bg2_pri1_enable(0, "ppu.bg2_pri1_enable", "Enable BG2 Priority 1", true, Setting::TRUE_FALSE);
Setting PPU::bg3_pri0_enable(0, "ppu.bg3_pri0_enable", "Enable BG3 Priority 0", true, Setting::TRUE_FALSE);
Setting PPU::bg3_pri1_enable(0, "ppu.bg3_pri1_enable", "Enable BG3 Priority 1", true, Setting::TRUE_FALSE);
Setting PPU::bg4_pri0_enable(0, "ppu.bg4_pri0_enable", "Enable BG4 Priority 0", true, Setting::TRUE_FALSE);
Setting PPU::bg4_pri1_enable(0, "ppu.bg4_pri1_enable", "Enable BG4 Priority 1", true, Setting::TRUE_FALSE);
Setting PPU::oam_pri0_enable(0, "ppu.oam_pri0_enable", "Enable OAM Priority 0", true, Setting::TRUE_FALSE);
Setting PPU::oam_pri1_enable(0, "ppu.oam_pri1_enable", "Enable OAM Priority 1", true, Setting::TRUE_FALSE);
Setting PPU::oam_pri2_enable(0, "ppu.oam_pri2_enable", "Enable OAM Priority 2", true, Setting::TRUE_FALSE);
Setting PPU::oam_pri3_enable(0, "ppu.oam_pri3_enable", "Enable OAM Priority 3", true, Setting::TRUE_FALSE);
};

View File

@@ -2,14 +2,39 @@ 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;
extern struct CPU {
static Setting hdma_enable;
} cpu;
extern struct PPU {
static Setting opt_enable;
static Setting bg1_pri0_enable, bg1_pri1_enable;
static Setting bg2_pri0_enable, bg2_pri1_enable;
static Setting bg3_pri0_enable, bg3_pri1_enable;
static Setting bg4_pri0_enable, bg4_pri1_enable;
static Setting oam_pri0_enable, oam_pri1_enable;
static Setting oam_pri2_enable, oam_pri3_enable;
} ppu;
};

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,250 +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) {
if(channel[i].direction == DMA_CPUTOMMIO) {
r_mem->write(hdma_mmio(i), x);
} else if(!channel[i].hdma_indirect) {
r_mem->write(hdma_addr(i), x);
} else {
r_mem->write(hdma_iaddr(i), 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;
}
}

View File

@@ -1,31 +1,75 @@
//op_read
inline void bCPU::op_adc_b() {
int32 r = regs.a.l + rd.l + regs.p.c;
//bcd
if(regs.p.d) {
if(((r ) & 15) > 9)r += 6;
if(((r >> 4) & 15) > 9)r += 6 << 4;
uint8 n0 = (regs.a.l ) & 15;
uint8 n1 = (regs.a.l >> 4) & 15;
n0 += ((rd.l) & 15) + regs.p.c;
if(n0 > 9) {
n0 -= 10;
n0 &= 15;
n1++;
}
n1 += ((rd.l >> 4) & 15);
if(n1 > 9) {
n1 -= 10;
n1 &= 15;
regs.p.c = 1;
} else {
regs.p.c = 0;
}
r = (n1 << 4) | (n0);
} else {
r = regs.a.l + rd.l + regs.p.c;
regs.p.c = (r > 0xff);
}
regs.p.n = !!(r & 0x80);
regs.p.v = !!(~(regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80);
regs.p.z = ((uint8)r == 0);
regs.p.c = (r > 0xff);
regs.a.l = r;
}
inline void bCPU::op_adc_w() {
int32 r = regs.a.w + rd.w + regs.p.c;
//bcd
int32 r;
if(regs.p.d) {
if(((r ) & 15) > 9)r += 6;
if(((r >> 4) & 15) > 9)r += 6 << 4;
if(((r >> 8) & 15) > 9)r += 6 << 8;
if(((r >> 12) & 15) > 9)r += 6 << 12;
uint8 n0 = (regs.a.w ) & 15;
uint8 n1 = (regs.a.w >> 4) & 15;
uint8 n2 = (regs.a.w >> 8) & 15;
uint8 n3 = (regs.a.w >> 12) & 15;
n0 += ((rd.w) & 15) + regs.p.c;
if(n0 > 9) {
n0 -= 10;
n0 &= 15;
n1++;
}
n1 += ((rd.w >> 4) & 15);
if(n1 > 9) {
n1 -= 10;
n1 &= 15;
n2++;
}
n2 += ((rd.w >> 8) & 15);
if(n2 > 9) {
n2 -= 10;
n2 &= 15;
n3++;
}
n3 += ((rd.w >> 12) & 15);
if(n3 > 9) {
n3 -= 10;
n3 &= 15;
regs.p.c = 1;
} else {
regs.p.c = 0;
}
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | (n0);
} else {
r = regs.a.w + rd.w + regs.p.c;
regs.p.c = (r > 0xffff);
}
regs.p.n = !!(r & 0x8000);
regs.p.v = !!(~(regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000);
regs.p.z = ((uint16)r == 0);
regs.p.c = (r > 0xffff);
regs.a.w = r;
}
@@ -156,32 +200,70 @@ inline void bCPU::op_ora_w() {
}
inline void bCPU::op_sbc_b() {
int32 r = regs.a.l - rd.l - !regs.p.c;
//bcd
int32 r;
if(regs.p.d) {
if(((r ) & 15) > 9)r -= 6;
if(((r >> 4) & 15) > 9)r -= 6 << 4;
uint8 n0 = (regs.a.l ) & 15;
uint8 n1 = (regs.a.l >> 4) & 15;
n0 -= ((rd.l ) & 15) + !regs.p.c;
n1 -= ((rd.l >> 4) & 15);
if(n0 > 9) {
n0 += 10;
n1--;
}
if(n1 > 9) {
n1 += 10;
regs.p.c = 0;
} else {
regs.p.c = 1;
}
r = (n1 << 4) | (n0);
} else {
r = regs.a.l - rd.l - !regs.p.c;
regs.p.c = (r >= 0);
}
regs.p.n = !!(r & 0x80);
regs.p.v = !!((regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80);
regs.p.z = ((byte)r == 0);
regs.p.c = (r >= 0);
regs.p.z = ((uint8)r == 0);
regs.a.l = r;
}
inline void bCPU::op_sbc_w() {
int32 r = regs.a.w - rd.w - !regs.p.c;
//bcd
int32 r;
if(regs.p.d) {
if(((r ) & 15) > 9)r -= 6;
if(((r >> 4) & 15) > 9)r -= 6 << 4;
if(((r >> 8) & 15) > 9)r -= 6 << 8;
if(((r >> 12) & 15) > 9)r -= 6 << 12;
uint8 n0 = (regs.a.w ) & 15;
uint8 n1 = (regs.a.w >> 4) & 15;
uint8 n2 = (regs.a.w >> 8) & 15;
uint8 n3 = (regs.a.w >> 12) & 15;
n0 -= ((rd.w ) & 15) + !regs.p.c;
n1 -= ((rd.w >> 4) & 15);
n2 -= ((rd.w >> 8) & 15);
n3 -= ((rd.w >> 12) & 15);
if(n0 > 9) {
n0 += 10;
n1--;
}
if(n1 > 9) {
n1 += 10;
n2--;
}
if(n2 > 9) {
n2 += 10;
n3--;
}
if(n3 > 9) {
n3 += 10;
regs.p.c = 0;
} else {
regs.p.c = 1;
}
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | (n0);
} else {
r = regs.a.w - rd.w - !regs.p.c;
regs.p.c = (r >= 0);
}
regs.p.n = !!(r & 0x8000);
regs.p.v = !!((regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000);
regs.p.z = ((word)r == 0);
regs.p.c = (r >= 0);
regs.p.z = ((uint16)r == 0);
regs.a.w = r;
}

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;
@@ -70,4 +69,5 @@ enum {
uint16 __relw(int16 offset);
CPU();
virtual ~CPU() {}
};

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

@@ -1,10 +1,22 @@
#include "../../base.h"
#include "bdsp_tables.cpp"
uint8 bDSP::read_8 (uint16 addr) { return (spcram[addr]); }
uint16 bDSP::read_16 (uint16 addr) { return (spcram[(addr + 1) & 0xffff] << 8) + (spcram[addr]); }
void bDSP::write_8 (uint16 addr, uint8 data) { spcram[addr] = data; }
void bDSP::write_16(uint16 addr, uint16 data) { spcram[addr++] = data; spcram[addr] = data >> 8; }
uint8 bDSP::readb(uint16 addr) {
return spcram[addr];
}
void bDSP::writeb(uint16 addr, uint8 data) {
spcram[addr] = data;
}
uint16 bDSP::readw(uint16 addr) {
return (readb(addr)) | (readb(addr + 1) << 8);
}
void bDSP::writew(uint16 addr, uint16 data) {
writeb(addr, data);
writeb(addr + 1, data >> 8);
}
uint8 bDSP::read(uint8 addr) {
int i, v, n;
@@ -98,12 +110,14 @@ int i, v, n;
break;
case 0x04:case 0x14:case 0x24:case 0x34:
case 0x44:case 0x54:case 0x64:case 0x74:
//voice[v].SRCN = data;
voice[v].SRCN = data;
break;
//below is anomie's code, but TRAC says writing SRCN doesn't affect anything until a
//BRR-with-end block is encountered, where it loads the loop address from the new SRCN
//anomie's code breaks MK2 sound completely...
if(voice[v].SRCN != data) {
voice[v].SRCN = data;
voice[v].brr_ptr = read_16((status.DIR << 8) + (voice[v].SRCN << 2) + ((voice[v].brr_looped)?2:0));
voice[v].SRCN = data;
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2) + ((voice[v].brr_looped) ? 2 : 0));
voice[v].brr_index = 0;
}
break;
@@ -144,18 +158,18 @@ int i, v, n;
case 0x3c:status.EVOLR = data;break;
case 0x4c:
status.KON = data;
// status.kon = data;
status.KON = data;
status.kon = data;
status.key_flag = true;
break;
case 0x5c:
status.KOFF = data;
status.KOFF = data;
status.key_flag = true;
break;
case 0x6c:
status.FLG = data;
status.FLG = data;
status.key_flag = true;
status.noise_rate = RateTable[data & 0x1f];
break;
@@ -165,15 +179,15 @@ int i, v, n;
status.ENDX = 0;
break;
case 0x0d:status.EFB = data;break;
case 0x2d:status.PMON = data;break;
case 0x3d:status.NON = data;break;
case 0x4d:status.EON = data;break;
case 0x5d:status.DIR = data;break;
case 0x6d:status.ESA = data;break;
case 0x0d:status.EFB = data;break;
case 0x2d:status.PMON = data;break;
case 0x3d:status.NON = data;break;
case 0x4d:status.EON = data;break;
case 0x5d:status.DIR = data;break;
case 0x6d:status.ESA = data;break;
case 0x7d:
status.EDL = data;
status.EDL = data;
status.echo_size = (data & 0x0f) << 11;
break;
}
@@ -221,7 +235,7 @@ int v;
status.KOFF = 0x00;
status.FLG |= 0xe0;
//status.kon = 0x00;
status.kon = 0x00;
status.key_flag = false;
status.noise_ctr = 0;
@@ -238,7 +252,7 @@ int v;
voice[v].pitch_ctr = 0;
voice[v].brr_index = 0;
voice[v].brr_ptr = read_16((status.DIR << 8) + (voice[v].SRCN << 2));
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2));
voice[v].brr_looped = false;
voice[v].brr_data[0] = 0;
voice[v].brr_data[1] = 0;
@@ -288,7 +302,9 @@ int32 esamplel, esampler;
int32 fir_samplel, fir_sampler;
pmon = status.PMON & ~status.NON & ~1;
if(!(dsp_counter++ & 1) && status.key_flag) {
//if(!(dsp_counter++ & 1) && status.key_flag) {
//TRAC believes KON/KOFF is polled every sample. further testing is needed
if(status.key_flag) {
for(v=0;v<8;v++) {
uint8 mask = 1 << v;
if(status.soft_reset()) {
@@ -301,10 +317,12 @@ int32 fir_samplel, fir_sampler;
voice[v].env_state = RELEASE;
voice[v].AdjustEnvelope();
}
} else if(status.KON & mask) { //status.kon
status.KON &= ~mask; //new code
status.ENDX &= ~mask; //new code
voice[v].brr_ptr = read_16((status.DIR << 8) + (voice[v].SRCN << 2));
} else if(status.kon & mask) {
//new KON code
status.ENDX &= ~mask;
status.kon &= ~mask;
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2));
voice[v].brr_index = -9;
voice[v].brr_looped = false;
voice[v].brr_data[0] = 0;
@@ -316,7 +334,8 @@ int32 fir_samplel, fir_sampler;
voice[v].AdjustEnvelope();
}
}
// status.ENDX &= ~status.kon;
//old KON code, breaks sound effects in DL / SFA2
// status.ENDX &= ~status.kon;
// status.kon = 0;
status.key_flag = false;
}
@@ -359,13 +378,15 @@ int32 fir_samplel, fir_sampler;
voice[v].brr_data_index &= 3;
if(voice[v].brr_index == 0) {
voice[v].brr_header = read_8(voice[v].brr_ptr);
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();
}
@@ -373,7 +394,7 @@ int32 fir_samplel, fir_sampler;
#define S(x) voice[v].brr_data[(voice[v].brr_data_index + (x)) & 3]
if(voice[v].env_state != SILENCE) {
sample = read_8(voice[v].brr_ptr + 1 + (voice[v].brr_index >> 1));
sample = readb(voice[v].brr_ptr + 1 + (voice[v].brr_index >> 1));
if(voice[v].brr_index & 1) {
sample = clip(4, sample);
} else {
@@ -410,7 +431,11 @@ int32 fir_samplel, fir_sampler;
if(++voice[v].brr_index > 15) {
voice[v].brr_index = 0;
if(voice[v].brr_header_flags() & BRR_END) {
voice[v].brr_ptr = read_16((status.DIR << 8) + (voice[v].SRCN << 2) + 2);
//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 {
voice[v].brr_ptr += 9;
@@ -496,7 +521,7 @@ int32 fir_samplel, fir_sampler;
//gaussian interpolation / noise
if(status.NON & (1 << v)) {
sample = status.noise_sample;
sample = clip(15, status.noise_sample);
} else {
d = voice[v].pitch_ctr >> 4; //-256 <= sample <= -1
sample = ((GaussTable[ -1-d] * S(-3)) >> 11);
@@ -527,8 +552,8 @@ int32 fir_samplel, fir_sampler;
//echo (FIR) adjust
#define F(c,x) status.fir_buffer[c][(status.fir_buffer_index+(x)) & 7]
status.fir_buffer_index++;
F(0,0) = read_16((status.ESA << 8) + status.echo_index);
F(1,0) = read_16((status.ESA << 8) + status.echo_index + 2);
F(0,0) = readw((status.ESA << 8) + status.echo_index);
F(1,0) = readw((status.ESA << 8) + status.echo_index + 2);
fir_samplel = (F(0,-0) * status.FIR[7] +
F(0,-1) * status.FIR[6] +
@@ -557,8 +582,8 @@ int32 fir_samplel, fir_sampler;
esamplel = clamp(16, esamplel);
esampler = clamp(16, esampler);
write_16((status.ESA << 8) + status.echo_index, esamplel);
write_16((status.ESA << 8) + status.echo_index + 2, esampler);
writew((status.ESA << 8) + status.echo_index, esamplel);
writew((status.ESA << 8) + status.echo_index + 2, esampler);
}
status.echo_index += 4;

View File

@@ -10,10 +10,10 @@ enum {
BRR_LOOP = 2
};
uint8 read_8 (uint16 addr);
uint16 read_16 (uint16 addr);
void write_8 (uint16 addr, uint8 data);
void write_16(uint16 addr, uint16 data);
uint8 readb (uint16 addr);
uint16 readw (uint16 addr);
void writeb(uint16 addr, uint8 data);
void writew(uint16 addr, uint16 data);
public:
static const uint16 RateTable[32];
@@ -63,7 +63,7 @@ struct Status {
int8 FIR[8];
//internal variables
//uint8 kon;
uint8 kon;
bool key_flag;
int16 noise_ctr, noise_rate;

View File

@@ -6,4 +6,7 @@ public:
virtual void power() = 0;
virtual void reset() = 0;
virtual uint32 run() = 0;
DSP() {}
virtual ~DSP() {}
};

View File

@@ -1,6 +1,3 @@
#define BSNES_VERSION "0.014"
#define BSNES_TITLE "bsnes v" BSNES_VERSION
#ifdef POLYMORPHISM
#define ref(x) x
#else
@@ -15,6 +12,8 @@
#define r_ppu ref(deref(ppu))
#include "reader/reader.h"
#include "cart/cart.h"
#include "cheat/cheat.h"
#include "memory/memory.h"
#include "memory/bmemory/bmemory.h"
@@ -35,6 +34,9 @@
#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
@@ -44,20 +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
@@ -67,15 +74,18 @@ extern SDD1 *sdd1;
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,35 +9,124 @@
#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; }
typedef unsigned int uint;
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long ulong;
typedef unsigned char bool8;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned long uint32;
typedef signed char int8;
typedef signed short int16;
typedef signed long int32;
#ifdef null
#undef null
#ifndef TRUE
#define TRUE 1
#endif
#define null 0xffffffff
#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;
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long ulong;
typedef unsigned long long uquad;
typedef unsigned char bool8;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned long uint32;
typedef unsigned long long uint64;
typedef signed char int8;
typedef signed short int16;
typedef signed long int32;
typedef signed long long int64;
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,12 +13,34 @@ 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;
}
}
char *Setting::sget() {
return strptr(char_data);
}
void Setting::sset(const char *_data) {
strcpy(char_data, _data);
strunquote(char_data);
}
Setting::Setting(Config *_parent, char *_name, char *_desc, uint _data, uint _type) {
int s;
if(_parent) {
@@ -43,55 +65,80 @@ int s;
type = _type;
}
Setting::Setting(Config *_parent, char *_name, char *_desc, char *_data) {
int s;
if(_parent) {
_parent->add(this);
}
s = strlen(_name);
name = (char*)malloc(s + 1);
strcpy(name, _name);
if(_desc) {
s = strlen(_desc);
desc = (char*)malloc(s + 1);
strcpy(desc, _desc);
} else {
desc = (char*)malloc(1);
*desc = 0;
}
strcpy(char_data, _data);
strcpy(char_def, _data);
type = STR;
}
void Config::add(Setting *setting) {
list[list_count++] = setting;
}
uint Config::string_to_uint(uint type, char *input) {
if(!strcmp(input, "true") ||
!strcmp(input, "enabled") ||
!strcmp(input, "on") ||
!strcmp(input, "yes")
if(strmatch(input, "true") ||
strmatch(input, "enabled") ||
strmatch(input, "on") ||
strmatch(input, "yes")
) {
return (uint)true;
}
if(!strcmp(input, "false") ||
!strcmp(input, "disabled") ||
!strcmp(input, "off") ||
!strcmp(input, "no")
if(strmatch(input, "false") ||
strmatch(input, "disabled") ||
strmatch(input, "off") ||
strmatch(input, "no")
) {
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) {
static char output[512];
switch(type) {
case Setting::TRUE_FALSE:
sprintf(output, "%s", (input & 1)?"true":"false");
sprintf(output, "%s", (input & 1) ? "true" : "false");
break;
case Setting::ENABLED_DISABLED:
sprintf(output, "%s", (input & 1)?"enabled":"disabled");
sprintf(output, "%s", (input & 1) ? "enabled" : "disabled");
break;
case Setting::ON_OFF:
sprintf(output, "%s", (input & 1)?"on":"off");
sprintf(output, "%s", (input & 1) ? "on" : "off");
break;
case Setting::YES_NO:
sprintf(output, "%s", (input & 1)?"yes":"no");
break;
case Setting::DEC:
sprintf(output, "%d", input);
break;
case Setting::HEX:
sprintf(output, "0x%x", input);
sprintf(output, "%s", (input & 1) ? "yes" : "no");
break;
case Setting::DEC: sprintf(output, "%d", input); break;
case Setting::HEX: sprintf(output, "0x%x", input); break;
case Setting::HEX8: sprintf(output, "0x%0.2x", input & 0xff); break;
case Setting::HEX16: sprintf(output, "0x%0.4x", input & 0xffff); break;
case Setting::HEX24: sprintf(output, "0x%0.6x", input & 0xffffff); break;
case Setting::HEX32: sprintf(output, "0x%0.8x", input); break;
}
return output;
@@ -119,14 +166,18 @@ char *buffer = (char*)malloc(fsize + 1);
qreplace(data, " ", "");
split(line, "\n", data);
for(int i=0;i<count(line);i++) {
for(int i = 0; i < count(line); i++) {
if(strlen(line[i]) == 0)continue;
if(*strptr(line[i]) == '#')continue;
split(part, "=", line[i]);
for(int l=0;l<list_count;l++) {
if(!strcmp(list[l]->name, part[0])) {
list[l]->set(string_to_uint(list[l]->type, strptr(part[1])));
qsplit(part, "=", line[i]);
for(int l = 0; l < list_count; l++) {
if(strmatch(list[l]->name, part[0])) {
if(list[l]->type != Setting::STR) {
list[l]->set(string_to_uint(list[l]->type, strptr(part[1])));
} else {
list[l]->sset(strptr(part[1]));
}
}
}
}
@@ -140,15 +191,20 @@ FILE *fp;
fp = fopen(fn, "wb");
if(!fp)return false;
for(int i=0;i<list_count;i++) {
for(int i = 0; i < list_count; i++) {
strcpy(data, list[i]->desc);
replace(data, "\r\n", "\n");
split(line, "\n", data);
for(int l=0;l<count(line);l++) {
for(int l = 0; l < count(line); l++) {
fprintf(fp, "# %s\r\n", strptr(line[l]));
}
fprintf(fp, "# (default = %s)\r\n", uint_to_string(list[i]->type, list[i]->def));
fprintf(fp, "%s = %s\r\n\r\n", list[i]->name, uint_to_string(list[i]->type, list[i]->data));
if(list[i]->type != Setting::STR) {
fprintf(fp, "# (default = %s)\r\n", uint_to_string(list[i]->type, list[i]->def));
fprintf(fp, "%s = %s\r\n\r\n", list[i]->name, uint_to_string(list[i]->type, list[i]->data));
} else {
fprintf(fp, "# (default = \"%s\")\r\n", strptr(list[i]->char_def));
fprintf(fp, "%s = \"%s\"\r\n\r\n", list[i]->name, strptr(list[i]->char_data));
}
}
return true;

View File

@@ -1,5 +1,5 @@
/*
libconfig : version 0.05 ~byuu (09/13/05)
libconfig : version 0.07 ~byuu (02/10/06)
*/
#ifndef __LIBCONFIG
@@ -28,9 +28,13 @@ class Config;
inline __name &operator=(const int8 _data) { set(_data); return *this; } \
inline __name &operator=(const int16 _data) { set(_data); return *this; } \
inline __name &operator=(const int32 _data) { set(_data); return *this; } \
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;
@@ -44,16 +48,25 @@ enum {
ENABLED_DISABLED,
ON_OFF,
YES_NO,
BOOL,
DEC,
HEX
HEX,
HEX8,
HEX16,
HEX24,
HEX32,
STR
};
char *name, *desc;
virtual void toggle();
virtual uint get();
virtual void set(uint _data);
substring char_data, char_def;
virtual void toggle();
virtual uint get();
virtual void set(uint _data);
Setting(Config *_parent, char *_name, char *_desc = 0, uint _data = 0, uint _type = DEC);
virtual char *sget();
virtual void sset(const char *_data);
Setting(Config *_parent, char *_name, char *_desc, uint _data, uint _type);
Setting(Config *_parent, char *_name, char *_desc, char *_data);
inline operator bool() { return (bool)get(); }
inline operator uint() { return get(); }
@@ -64,6 +77,8 @@ char *name, *desc;
inline operator int8() { return get(); }
inline operator int16() { return get(); }
inline operator int32() { return get(); }
inline operator float() { return (float) get(); }
inline operator double() { return (double)get(); }
inline Setting &operator=(const bool _data) { set((uint)_data); return *this; }
inline Setting &operator=(const uint _data) { set(_data); return *this; }
@@ -74,6 +89,8 @@ char *name, *desc;
inline Setting &operator=(const int8 _data) { set(_data); return *this; }
inline Setting &operator=(const int16 _data) { set(_data); return *this; }
inline Setting &operator=(const int32 _data) { set(_data); return *this; }
inline Setting &operator=(const float _data) { set((uint)_data); return *this; }
inline Setting &operator=(const double _data) { set((uint)_data); return *this; }
};
class Config {

View File

@@ -64,6 +64,28 @@ int strcmp(substring &dest, const char *src) { return strcmp(strptr(dest), src);
int strcmp(const char *dest, substring &src) { return strcmp(dest, strptr(src)); }
int strcmp(substring &dest, substring &src) { return strcmp(strptr(dest), strptr(src)); }
int __stricmp(const char *dest, const char *src) {
while(*dest && *src) {
if(chrlower(*dest) != chrlower(*src))break;
dest++;
src++;
}
return (int)chrlower(*dest) - (int)chrlower(*src);
}
int stricmp(substring &dest, const char *src) { return __stricmp(strptr(dest), src); }
int stricmp(const char *dest, substring &src) { return __stricmp(dest, strptr(src)); }
int stricmp(substring &dest, substring &src) { return __stricmp(strptr(dest), strptr(src)); }
bool strmatch(const char *dest, const char *src) { return !strcmp(dest, src); }
bool strmatch(substring &dest, const char *src) { return strmatch(strptr(dest), src); }
bool strmatch(const char *dest, substring &src) { return strmatch(dest, strptr(src)); }
bool strmatch(substring &dest, substring &src) { return strmatch(strptr(dest), strptr(src)); }
bool strimatch(const char *dest, const char *src) { return !stricmp(dest, src); }
bool strimatch(substring &dest, const char *src) { return strimatch(strptr(dest), src); }
bool strimatch(const char *dest, substring &src) { return strimatch(dest, strptr(src)); }
bool strimatch(substring &dest, substring &src) { return strimatch(strptr(dest), strptr(src)); }
void strcpy(substring &dest, const char *src) {
int srclen = strlen(src);
if(srclen > dest.size) { strresize(dest, srclen); }
@@ -71,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); }
@@ -109,18 +143,6 @@ int i, sl = strlen(dest.s);
s[i] = 0;
}
int __stricmp(const char *dest, const char *src) {
while(*dest && *src) {
if(chrlower(*dest) != chrlower(*src))break;
dest++;
src++;
}
return (int)chrlower(*dest) - (int)chrlower(*src);
}
int stricmp(substring &dest, const char *src) { return __stricmp(strptr(dest), src); }
int stricmp(const char *dest, substring &src) { return __stricmp(dest, strptr(src)); }
int stricmp(substring &dest, substring &src) { return __stricmp(strptr(dest), strptr(src)); }
void strlower(char *str) {
while(*str) {
*str = chrlower(*str);
@@ -137,105 +159,110 @@ void strupper(char *str) {
}
void strupper(substring &str) { strupper(strptr(str)); }
uint strpos(const char *str, const char *key) {
bool strpos(const char *str, const char *key, uint &pos) {
int i, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return null;
for(i=0;i<=ssl-ksl;i++) {
if(!memcmp(str+i, key, ksl))return i;
if(ksl > ssl)return false;
for(i = 0; i <= ssl - ksl; i++) {
if(!memcmp(str + i, key, ksl)) {
pos = i;
return true;
}
}
return null;
return false;
}
uint strpos(substring &str, const char *key) { return strpos(strptr(str), key); }
uint strpos(const char *str, substring &key) { return strpos(str, strptr(key)); }
uint strpos(substring &str, substring &key) { return strpos(strptr(str), strptr(key)); }
bool strpos(substring &str, const char *key, uint &pos) { return strpos(strptr(str), key, pos); }
bool strpos(const char *str, substring &key, uint &pos) { return strpos(str, strptr(key), pos); }
bool strpos(substring &str, substring &key, uint &pos) { return strpos(strptr(str), strptr(key), pos); }
uint qstrpos(const char *str, const char *key) {
bool qstrpos(const char *str, const char *key, uint &pos) {
int i, z, ssl = strlen(str), ksl = strlen(key);
uint8 x;
if(ksl > ssl)return null;
for(i=0;i<=ssl-ksl;) {
if(ksl > ssl)return false;
for(i = 0; i <= ssl - ksl;) {
x = str[i];
if(x == '\"' || x == '\'') {
z = i++;
while(str[i] != x && i < ssl)i++;
if(i >= ssl)i = z;
}
if(!memcmp(str+i, key, ksl)) {
return i;
if(!memcmp(str + i, key, ksl)) {
pos = i;
return true;
} else {
i++;
}
}
return null;
return false;
}
uint qstrpos(substring &str, const char *key) { return qstrpos(strptr(str), key); }
uint qstrpos(const char *str, substring &key) { return qstrpos(str, strptr(key)); }
uint qstrpos(substring &str, substring &key) { return qstrpos(strptr(str), strptr(key)); }
bool qstrpos(substring &str, const char *key, uint &pos) { return qstrpos(strptr(str), key, pos); }
bool qstrpos(const char *str, substring &key, uint &pos) { return qstrpos(str, strptr(key), pos); }
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;
}
}
}
}
void strtr(substring &dest, const char *before, const char *after) { strtr(strptr(dest), before, after); }
uint strbegin(const char *str, const char *key) {
bool strbegin(const char *str, const char *key) {
int i, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return 1;
if(!memcmp(str, key, ksl))return 0;
return 1;
if(ksl > ssl)return false;
return (!memcmp(str, key, ksl));
}
uint strbegin(substring &str, const char *key) { return strbegin(strptr(str), key); }
bool strbegin(substring &str, const char *key) { return strbegin(strptr(str), key); }
uint stribegin(const char *str, const char *key) {
bool stribegin(const char *str, const char *key) {
int i, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return 1;
if(ksl > ssl)return false;
for(i=0;i<ksl;i++) {
if(str[i] >= 'A' && str[i] <= 'Z') {
if(str[i] != key[i] && str[i]+0x20 != key[i])return 1;
if(str[i] != key[i] && str[i]+0x20 != key[i])return false;
} else if(str[i] >= 'a' && str[i] <= 'z') {
if(str[i] != key[i] && str[i]-0x20 != key[i])return 1;
if(str[i] != key[i] && str[i]-0x20 != key[i])return false;
} else {
if(str[i] != key[i])return 1;
if(str[i] != key[i])return false;
}
}
return 0;
return true;
}
uint stribegin(substring &str, const char *key) { return stribegin(strptr(str), key); }
bool stribegin(substring &str, const char *key) { return stribegin(strptr(str), key); }
uint strend(const char *str, const char *key) {
bool strend(const char *str, const char *key) {
int i, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return 1;
if(!memcmp(str + ssl - ksl, key, ksl))return 0;
return 1;
if(ksl > ssl)return false;
return (!memcmp(str + ssl - ksl, key, ksl));
}
uint strend(substring &str, const char *key) { return strend(strptr(str), key); }
bool strend(substring &str, const char *key) { return strend(strptr(str), key); }
uint striend(const char *str, const char *key) {
bool striend(const char *str, const char *key) {
int i, z, ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl)return 1;
if(ksl > ssl)return false;
for(i=ssl-ksl, z=0;i<ssl;i++, z++) {
if(str[i] >= 'A' && str[i] <= 'Z') {
if(str[i] != key[z] && str[i]+0x20 != key[z])return 1;
if(str[i] != key[z] && str[i]+0x20 != key[z])return false;
} else if(str[i] >= 'a' && str[i] <= 'z') {
if(str[i] != key[z] && str[i]-0x20 != key[z])return 1;
if(str[i] != key[z] && str[i]-0x20 != key[z])return false;
} else {
if(str[i] != key[z])return 1;
if(str[i] != key[z])return false;
}
}
return 0;
return true;
}
uint striend(substring &str, const char *key) { return striend(strptr(str), key); }
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;
}
}
@@ -244,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;
}
}
@@ -254,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;
}
}
@@ -263,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;
}
}
@@ -302,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;
@@ -332,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;
@@ -358,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.06a ~byuu (08/22/05)
libstring : version 0.10 ~byuu (03/05/06)
*/
#ifndef __LIBSTRING
@@ -25,8 +25,29 @@ int strcmp(substring &dest, const char *src);
int strcmp(const char *dest, substring &src);
int strcmp(substring &dest, substring &src);
//vc6/win32 and gcc/dos only support stricmp, whereas
//gcc/unix only supports strcasecmp. this is an attempt
//to avoid platform-specific defines...
#define stricmp __stricmp
int __stricmp(const char *dest, const char *src);
int stricmp(substring &dest, const char *src);
int stricmp(const char *dest, substring &src);
int stricmp(substring &dest, substring &src);
bool strmatch(const char *dest, const char *src);
bool strmatch(substring &dest, const char *src);
bool strmatch(const char *dest, substring &src);
bool strmatch(substring &dest, substring &src);
bool strimatch(const char *dest, const char *src);
bool strimatch(substring &dest, const char *src);
bool strimatch(const char *dest, substring &src);
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);
@@ -38,45 +59,36 @@ void strinsert(substring &dest, substring &src, uint pos);
void strremove(substring &dest, uint start, uint length = 0);
//vc6/win32 and gcc/dos only support stricmp, whereas
//gcc/unix only supports strcasecmp. this is an attempt
//to avoid platform-specific defines...
#define stricmp __stricmp
int __stricmp(const char *dest, const char *src);
int stricmp(substring &dest, const char *src);
int stricmp(const char *dest, substring &src);
int stricmp(substring &dest, substring &src);
void strlower(char *str);
void strlower(substring &str);
void strupper(char *str);
void strupper(substring &str);
uint strpos(const char *str, const char *key);
uint strpos(substring &str, const char *key);
uint strpos(const char *str, substring &key);
uint strpos(substring &str, substring &key);
bool strpos(const char *str, const char *key, uint &pos);
bool strpos(substring &str, const char *key, uint &pos);
bool strpos(const char *str, substring &key, uint &pos);
bool strpos(substring &str, substring &key, uint &pos);
uint qstrpos(const char *str, const char *key);
uint qstrpos(substring &str, const char *key);
uint qstrpos(const char *str, substring &key);
uint qstrpos(substring &str, substring &key);
bool qstrpos(const char *str, const char *key, uint &pos);
bool qstrpos(substring &str, const char *key, uint &pos);
bool qstrpos(const char *str, substring &key, uint &pos);
bool qstrpos(substring &str, substring &key, uint &pos);
void strtr(char *dest, const char *before, const char *after);
void strtr(substring &dest, const char *before, const char *after);
uint strbegin(const char *str, const char *key);
uint strbegin(substring &str, const char *key);
bool strbegin(const char *str, const char *key);
bool strbegin(substring &str, const char *key);
uint stribegin(const char *str, const char *key);
uint stribegin(substring &str, const char *key);
bool stribegin(const char *str, const char *key);
bool stribegin(substring &str, const char *key);
uint strend(const char *str, const char *key);
uint strend(substring &str, const char *key);
bool strend(const char *str, const char *key);
bool strend(substring &str, const char *key);
uint striend(const char *str, const char *key);
uint striend(substring &str, const char *key);
bool striend(const char *str, const char *key);
bool striend(substring &str, const char *key);
void strltrim(char *str, const char *key);
void strltrim(substring &str, const char *key);
@@ -125,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, ...);

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