mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-25 12:39:09 +02:00
Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a3945e5772 | ||
|
6b6233b3af | ||
|
9f63cb1b99 |
202
bsnes.cfg
202
bsnes.cfg
@@ -1,202 +0,0 @@
|
||||
# Applies contrast adjust filter to video output when enabled
|
||||
# Works by lowering the brightness of darker colors,
|
||||
# while leaving brighter colors alone; thus reducing saturation
|
||||
# (default = true)
|
||||
snes.video_color_curve = true
|
||||
|
||||
# Selects color adjustment filter for video output
|
||||
# 0 = Normal (no filter, rgb555)
|
||||
# 1 = Grayscale mode (l5)
|
||||
# 2 = VGA mode (rgb332)
|
||||
# 3 = Genesis mode (rgb333)
|
||||
# (default = 0)
|
||||
snes.video_color_adjust_mode = 0
|
||||
|
||||
# Mutes SNES audio output when enabled
|
||||
# (default = false)
|
||||
snes.mute = false
|
||||
|
||||
# Regulate speed to 60hz (NTSC) / 50hz (PAL)
|
||||
# (default = true)
|
||||
system.regulate_speed = true
|
||||
|
||||
# Slowest speed setting (in hz)
|
||||
# (default = 16000)
|
||||
system.speed_slowest = 16000
|
||||
|
||||
# Slow speed setting
|
||||
# (default = 24000)
|
||||
system.speed_slow = 24000
|
||||
|
||||
# Normal speed setting
|
||||
# (default = 32000)
|
||||
system.speed_normal = 32000
|
||||
|
||||
# Fast speed setting
|
||||
# (default = 48000)
|
||||
system.speed_fast = 48000
|
||||
|
||||
# Fastest speed setting
|
||||
# (default = 64000)
|
||||
system.speed_fastest = 64000
|
||||
|
||||
# Video mode at startup
|
||||
# (default = 2)
|
||||
video.mode = 2
|
||||
|
||||
# Video mode 0 (windowed)
|
||||
# (default = "256x223")
|
||||
video.mode_0 = "256x223"
|
||||
|
||||
# Video mode 1 (windowed)
|
||||
# (default = "512x446")
|
||||
video.mode_1 = "512x446"
|
||||
|
||||
# Video mode 2 (windowed)
|
||||
# (default = "640x480")
|
||||
video.mode_2 = "640x480"
|
||||
|
||||
# Video mode 3 (windowed)
|
||||
# (default = "960x720")
|
||||
video.mode_3 = "960x720"
|
||||
|
||||
# Video mode 4 (windowed)
|
||||
# (default = "1152x864")
|
||||
video.mode_4 = "1152x864"
|
||||
|
||||
# Video mode 5 (fullscreen)
|
||||
# (default = "640x480@60:640x480")
|
||||
video.mode_5 = "640x480@60:640x480"
|
||||
|
||||
# Video mode 6 (fullscreen)
|
||||
# (default = "800x600@60:800x600")
|
||||
video.mode_6 = "800x600@60:800x600"
|
||||
|
||||
# Video mode 7 (fullscreen)
|
||||
# (default = "1024x768@60:1024x768")
|
||||
video.mode_7 = "1024x768@60:1024x768"
|
||||
|
||||
# Video mode 8 (fullscreen)
|
||||
# (default = "1280x960@60:1280x960")
|
||||
video.mode_8 = "1280x960@60:1280x960"
|
||||
|
||||
# Video mode 9 (fullscreen)
|
||||
# (default = "1600x1200@60:1600x1200")
|
||||
video.mode_9 = "1600x1200@60:1600x1200"
|
||||
|
||||
# Use Video RAM instead of System RAM
|
||||
# (default = true)
|
||||
video.use_vram = true
|
||||
|
||||
# Use triple buffering
|
||||
# (default = false)
|
||||
video.triple_buffering = false
|
||||
|
||||
# Show framerate in window title
|
||||
# (default = true)
|
||||
gui.show_fps = true
|
||||
|
||||
# Allow "impossible" key combinations for joypad 1 (not recommended)
|
||||
# (default = false)
|
||||
input.joypad1.allow_invalid_input = false
|
||||
|
||||
# Joypad1 up
|
||||
# (default = 0x80c8)
|
||||
input.joypad1.up = 0x80c8
|
||||
|
||||
# Joypad1 down
|
||||
# (default = 0x81d0)
|
||||
input.joypad1.down = 0x81d0
|
||||
|
||||
# Joypad1 left
|
||||
# (default = 0x82cb)
|
||||
input.joypad1.left = 0x82cb
|
||||
|
||||
# Joypad1 right
|
||||
# (default = 0x83cd)
|
||||
input.joypad1.right = 0x83cd
|
||||
|
||||
# Joypad1 A
|
||||
# (default = 0x42d)
|
||||
input.joypad1.a = 0x42d
|
||||
|
||||
# Joypad1 B
|
||||
# (default = 0x32c)
|
||||
input.joypad1.b = 0x32c
|
||||
|
||||
# Joypad1 X
|
||||
# (default = 0x11f)
|
||||
input.joypad1.x = 0x11f
|
||||
|
||||
# Joypad1 Y
|
||||
# (default = 0x1e)
|
||||
input.joypad1.y = 0x1e
|
||||
|
||||
# Joypad1 L
|
||||
# (default = 0x620)
|
||||
input.joypad1.l = 0x620
|
||||
|
||||
# Joypad1 R
|
||||
# (default = 0x72e)
|
||||
input.joypad1.r = 0x72e
|
||||
|
||||
# Joypad1 select
|
||||
# (default = 0x836)
|
||||
input.joypad1.select = 0x836
|
||||
|
||||
# Joypad1 start
|
||||
# (default = 0x91c)
|
||||
input.joypad1.start = 0x91c
|
||||
|
||||
# Allow "impossible" key combinations for joypad 2 (not recommended)
|
||||
# (default = false)
|
||||
input.joypad2.allow_invalid_input = false
|
||||
|
||||
# Joypad2 up
|
||||
# (default = 0xff14)
|
||||
input.joypad2.up = 0xff14
|
||||
|
||||
# Joypad2 down
|
||||
# (default = 0xff22)
|
||||
input.joypad2.down = 0xff22
|
||||
|
||||
# Joypad2 left
|
||||
# (default = 0xff21)
|
||||
input.joypad2.left = 0xff21
|
||||
|
||||
# Joypad2 right
|
||||
# (default = 0xff23)
|
||||
input.joypad2.right = 0xff23
|
||||
|
||||
# Joypad2 A
|
||||
# (default = 0xff25)
|
||||
input.joypad2.a = 0xff25
|
||||
|
||||
# Joypad2 B
|
||||
# (default = 0xff24)
|
||||
input.joypad2.b = 0xff24
|
||||
|
||||
# Joypad2 X
|
||||
# (default = 0xff17)
|
||||
input.joypad2.x = 0xff17
|
||||
|
||||
# Joypad2 Y
|
||||
# (default = 0xff16)
|
||||
input.joypad2.y = 0xff16
|
||||
|
||||
# Joypad2 L
|
||||
# (default = 0xff18)
|
||||
input.joypad2.l = 0xff18
|
||||
|
||||
# Joypad2 R
|
||||
# (default = 0xff26)
|
||||
input.joypad2.r = 0xff26
|
||||
|
||||
# Joypad2 select
|
||||
# (default = 0xff1a)
|
||||
input.joypad2.select = 0xff1a
|
||||
|
||||
# Joypad2 start
|
||||
# (default = 0xff1b)
|
||||
input.joypad2.start = 0xff1b
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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();
|
||||
|
@@ -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;
|
||||
}
|
@@ -1,3 +0,0 @@
|
||||
cl /ML /O2 bapugen.cpp
|
||||
@pause
|
||||
@del *.obj
|
@@ -1 +0,0 @@
|
||||
@del *.exe
|
18
src/apu/bapu/core/bapugen.cpp
Normal file
18
src/apu/bapu/core/bapugen.cpp
Normal 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
3
src/apu/bapu/core/cc.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
cl /O2 /wd4996 bapugen.cpp
|
||||
@pause
|
||||
@del *.obj
|
8
src/apu/bapu/core/clean.bat
Normal file
8
src/apu/bapu/core/clean.bat
Normal 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
|
@@ -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
25
src/apu/bapu/core/core.h
Normal 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"
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
199
src/apu/bapu/memory/memory.cpp
Normal file
199
src/apu/bapu/memory/memory.cpp
Normal 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;
|
||||
}
|
14
src/apu/bapu/memory/memory.h
Normal file
14
src/apu/bapu/memory/memory.h
Normal 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);
|
35
src/apu/bapu/timing/timing.cpp
Normal file
35
src/apu/bapu/timing/timing.cpp
Normal 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;
|
||||
}
|
9
src/apu/bapu/timing/timing.h
Normal file
9
src/apu/bapu/timing/timing.h
Normal 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();
|
56
src/base.h
56
src/base.h
@@ -1,15 +1,27 @@
|
||||
//debugging extensions (~10% speed hit)
|
||||
//#define DEBUGGER
|
||||
#define BSNES_VERSION "0.016"
|
||||
#define BSNES_TITLE "bsnes v" BSNES_VERSION
|
||||
|
||||
//snes core polymorphism (allow mem/cpu/apu/ppu overriding,
|
||||
//~10% speed hit)
|
||||
//#define POLYMORPHISM
|
||||
#define MEMCORE bMemBus
|
||||
#define CPUCORE bCPU
|
||||
#define APUCORE bAPU
|
||||
#define DSPCORE bDSP
|
||||
#define PPUCORE bPPU
|
||||
|
||||
//game genie + pro action replay code support (~1-3% speed hit)
|
||||
#define CHEAT_SYSTEM
|
||||
|
||||
//enable GZ, ZIP format support
|
||||
#define GZIP_SUPPORT
|
||||
//#define GZIP_SUPPORT
|
||||
|
||||
//enable JMA support
|
||||
#define JMA_SUPPORT
|
||||
//#define JMA_SUPPORT
|
||||
|
||||
//debugging extensions (~10% speed hit)
|
||||
#define DEBUGGER
|
||||
|
||||
//snes core polymorphism
|
||||
//(allow mem/cpu/apu/ppu overriding, ~10% speed hit)
|
||||
//#define POLYMORPHISM
|
||||
|
||||
//this should be declared in the port-specific makefiles
|
||||
//#define ARCH_LSB
|
||||
@@ -21,20 +33,6 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include "lib/libbase.h"
|
||||
#include "lib/libvector.h"
|
||||
#include "lib/libstring.h"
|
||||
#include "lib/libconfig.h"
|
||||
|
||||
inline uint16 read16(uint8 *addr, uint pos) {
|
||||
#ifdef ARCH_LSB
|
||||
return *((uint16*)(addr + pos));
|
||||
#else
|
||||
return (addr[pos]) | (addr[pos + 1] << 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define _WIN32_
|
||||
#undef _UNIX_
|
||||
@@ -45,9 +43,21 @@ inline uint16 read16(uint8 *addr, uint pos) {
|
||||
#error "unknown architecture"
|
||||
#endif
|
||||
|
||||
#include "lib/libbase.h"
|
||||
#include "lib/libvector.h"
|
||||
#include "lib/libstring.h"
|
||||
#include "lib/libconfig.h"
|
||||
#include "lib/libbpf.h"
|
||||
|
||||
inline uint16 read16(uint8 *addr, uint pos) {
|
||||
#ifdef ARCH_LSB
|
||||
return *((uint16*)(addr + pos));
|
||||
#else
|
||||
return (addr[pos]) | (addr[pos + 1] << 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
//platform-specific global functions
|
||||
void *memalloc(uint32 size, char *name = 0, ...);
|
||||
void memfree(void *mem, char *name = 0, ...);
|
||||
void alert(char *s, ...);
|
||||
void dprintf(char *s, ...);
|
||||
|
||||
|
@@ -4,6 +4,8 @@ void Cartridge::read_header() {
|
||||
cart.srtc = false;
|
||||
cart.sdd1 = false;
|
||||
cart.c4 = false;
|
||||
cart.dsp2 = false;
|
||||
cart.obc1 = false;
|
||||
|
||||
if(cart.header_index == 0x7fc0 && cart.rom_size >= 0x401000) {
|
||||
cart.mapper = EXLOROM;
|
||||
@@ -31,18 +33,28 @@ uint8 rom_type = rom[cart.header_index + ROM_TYPE];
|
||||
cart.c4 = true;
|
||||
}
|
||||
|
||||
if(mapper == 0x20 && rom_type == 0x05) {
|
||||
cart.dsp2 = true;
|
||||
}
|
||||
|
||||
if(mapper == 0x30 && rom_type == 0x25) {
|
||||
cart.obc1 = true;
|
||||
}
|
||||
|
||||
cart.cart_mmio = cart.c4 | cart.dsp2 | cart.obc1;
|
||||
|
||||
if(rom[cart.header_index + SRAM_SIZE] & 7) {
|
||||
cart.sram_size = 1024 << (rom[cart.header_index + SRAM_SIZE] & 7);
|
||||
} else {
|
||||
cart.sram_size = 0;
|
||||
}
|
||||
|
||||
cart.region = (rom[cart.header_index + REGION] < 2) ? NTSC : PAL;
|
||||
cart.region = ((rom[cart.header_index + REGION] & 0x7f) < 2) ? NTSC : PAL;
|
||||
|
||||
memcpy(&cart.name, &rom[cart.header_index + CART_NAME], 21);
|
||||
cart.name[21] = 0;
|
||||
|
||||
for(int i=0;i<22;i++) {
|
||||
for(int i = 0; i < 22; i++) {
|
||||
if(cart.name[i] & 0x80) {
|
||||
cart.name[i] = '?';
|
||||
}
|
||||
@@ -81,10 +93,15 @@ int32 score_lo = 0,
|
||||
uint16 cksum, icksum;
|
||||
cksum = rom[0x7fc0 + CKSUM] | (rom[0x7fc0 + CKSUM + 1] << 8);
|
||||
icksum = rom[0x7fc0 + ICKSUM] | (rom[0x7fc0 + ICKSUM + 1] << 8);
|
||||
if((cksum + icksum) == 0xffff)score_lo += 8;
|
||||
if((cksum + icksum) == 0xffff && (cksum != 0) && (icksum != 0)) {
|
||||
score_lo += 8;
|
||||
}
|
||||
|
||||
cksum = rom[0xffc0 + CKSUM] | (rom[0xffc0 + CKSUM + 1] << 8);
|
||||
icksum = rom[0xffc0 + ICKSUM] | (rom[0xffc0 + ICKSUM + 1] << 8);
|
||||
if((cksum + icksum) == 0xffff)score_hi += 8;
|
||||
if((cksum + icksum) == 0xffff && (cksum != 0) && (icksum != 0)) {
|
||||
score_hi += 8;
|
||||
}
|
||||
|
||||
if(rom_size < 0x401000) {
|
||||
score_ex = 0;
|
||||
@@ -108,25 +125,23 @@ void Cartridge::load_sram() {
|
||||
return;
|
||||
}
|
||||
|
||||
FileReader ff;
|
||||
if(!ff.open(sram_fn)) {
|
||||
FileReader ff(sram_fn);
|
||||
if(!ff.ready()) {
|
||||
sram = (uint8*)malloc(cart.sram_size);
|
||||
memset(sram, 0, cart.sram_size);
|
||||
return;
|
||||
}
|
||||
|
||||
sram = ff.read(cart.sram_size);
|
||||
ff.close();
|
||||
}
|
||||
|
||||
void Cartridge::save_sram() {
|
||||
if(cart.sram_size == 0)return;
|
||||
|
||||
FileWriter ff;
|
||||
if(!ff.open(sram_fn))return;
|
||||
FileWriter ff(sram_fn);
|
||||
if(!ff.ready())return;
|
||||
|
||||
ff.write(sram, cart.sram_size);
|
||||
ff.close();
|
||||
}
|
||||
|
||||
void Cartridge::load_rom(Reader *rf) {
|
||||
@@ -141,6 +156,55 @@ void Cartridge::load_rom(Reader *rf) {
|
||||
}
|
||||
|
||||
cart.rom_size = rom_size;
|
||||
|
||||
cart.crc32 = 0xffffffff;
|
||||
for(int32 i = 0; i < cart.rom_size; i++) {
|
||||
cart.crc32 = crc32_adjust(cart.crc32, rom[i]);
|
||||
}
|
||||
cart.crc32 = ~cart.crc32;
|
||||
}
|
||||
|
||||
void Cartridge::patch_rom(Reader *rf) {
|
||||
uint8 *patch_data = rf->read();
|
||||
uint32 patch_size = rf->size();
|
||||
BPF bpf;
|
||||
if(patch_size < 34)return;
|
||||
|
||||
uint32 target;
|
||||
target = patch_data[BPF::INDEX_FORMAT + 0] << 0;
|
||||
target |= patch_data[BPF::INDEX_FORMAT + 1] << 8;
|
||||
target |= patch_data[BPF::INDEX_FORMAT + 2] << 16;
|
||||
target |= patch_data[BPF::INDEX_FORMAT + 3] << 24;
|
||||
if(target != BPF::FORMAT_SNES) {
|
||||
alert("Warning: BPF patch file is not in SNES format!\n\n"
|
||||
"The patch will still be applied, but it will not be "
|
||||
"possible to determine whether the patch was created "
|
||||
"against an image with a header or without a header.\n\n"
|
||||
"bsnes is now forced to assume the patch was created "
|
||||
"against a headerless source image. If this is not the "
|
||||
"case, then patching will fail!\n\n"
|
||||
"If you are the author of this patch, please recreate "
|
||||
"the patch in SNES format.\n\n"
|
||||
"If you are not the patch author, please contact the "
|
||||
"author and ask them to create an SNES format BPF patch.");
|
||||
}
|
||||
|
||||
if(bpf.apply_patch(patch_size, patch_data, rom_size, rom) == true) {
|
||||
SafeFree(base_rom);
|
||||
uint8 *temp = bpf.get_output_handle(rom_size);
|
||||
base_rom = (uint8*)malloc(rom_size);
|
||||
memcpy(base_rom, temp, rom_size);
|
||||
rom = base_rom;
|
||||
cart.rom_size = rom_size;
|
||||
} else {
|
||||
alert("Failed to apply patch.\n\nThis could be because the patch itself "
|
||||
"does not match its internal checksum, because the ROM loaded does not "
|
||||
"match the patch information for either the original or modified file, "
|
||||
"or because the patched file does not match the checksum of either the "
|
||||
"original or modified file that is stored inside the patch.\n\n"
|
||||
"The original ROM image will be used instead.");
|
||||
}
|
||||
SafeFree(patch_data);
|
||||
}
|
||||
|
||||
bool Cartridge::load(const char *fn) {
|
||||
@@ -153,24 +217,22 @@ bool Cartridge::load(const char *fn) {
|
||||
|
||||
switch(Reader::detect(rom_fn)) {
|
||||
case Reader::RF_NORMAL: {
|
||||
FileReader ff;
|
||||
if(!ff.open(rom_fn)) {
|
||||
FileReader ff(rom_fn);
|
||||
if(!ff.ready()) {
|
||||
alert("Error loading image file (%s)!", rom_fn);
|
||||
return false;
|
||||
}
|
||||
load_rom(static_cast<Reader*>(&ff));
|
||||
ff.close();
|
||||
break;
|
||||
}
|
||||
#ifdef GZIP_SUPPORT
|
||||
case Reader::RF_GZ: {
|
||||
GZReader gf;
|
||||
if(!gf.open(rom_fn)) {
|
||||
GZReader gf(rom_fn);
|
||||
if(!gf.ready()) {
|
||||
alert("Error loading image file (%s)!", rom_fn);
|
||||
return false;
|
||||
}
|
||||
load_rom(static_cast<Reader*>(&gf));
|
||||
gf.close();
|
||||
break;
|
||||
}
|
||||
case Reader::RF_ZIP: {
|
||||
@@ -193,13 +255,71 @@ bool Cartridge::load(const char *fn) {
|
||||
#endif
|
||||
}
|
||||
|
||||
int i;
|
||||
//remove ROM extension
|
||||
strcpy(sram_fn, fn);
|
||||
for(i=strlen(fn)-1;i>=0;i--) {
|
||||
if(fn[i] == '.')break;
|
||||
for(int i = strlen(fn) - 1; i >= 0; i--) {
|
||||
if(sram_fn[i] == '.') {
|
||||
sram_fn[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//check for bpf patch
|
||||
#ifdef GZIP_SUPPORT
|
||||
strcpy(patch_fn, sram_fn);
|
||||
strcat(patch_fn, ".bpz");
|
||||
if(fexists(patch_fn)) {
|
||||
ZipReader zf(patch_fn);
|
||||
patch_rom(static_cast<Reader*>(&zf));
|
||||
} else {
|
||||
#endif
|
||||
strcpy(patch_fn, sram_fn);
|
||||
strcat(patch_fn, ".bpf");
|
||||
if(fexists(patch_fn)) {
|
||||
FileReader ff(patch_fn);
|
||||
patch_rom(static_cast<Reader*>(&ff));
|
||||
}
|
||||
#ifdef GZIP_SUPPORT
|
||||
}
|
||||
#endif
|
||||
|
||||
//add SRAM extension
|
||||
strcat(sram_fn, ".");
|
||||
strcat(sram_fn, config::fs.save_ext.sget());
|
||||
|
||||
//override default path (current directory)?
|
||||
if(strmatch(config::fs.save_path.sget(), "") == false) {
|
||||
//remove path if fs.sram_path was specified
|
||||
string new_fn, parts;
|
||||
strcpy(new_fn, sram_fn);
|
||||
replace(new_fn, "\\", "/");
|
||||
split(parts, "/", new_fn);
|
||||
|
||||
//add new SRAM path
|
||||
strcpy(new_fn, config::fs.save_path.sget());
|
||||
|
||||
//append fs.base_path if fs.sram_path is not fully-qualified path
|
||||
if(strbegin(new_fn, "./") == true) {
|
||||
strltrim(new_fn, "./");
|
||||
strcpy(new_fn[1], new_fn[0]);
|
||||
strcpy(new_fn[0], config::fs.base_path.sget());
|
||||
strcat(new_fn[0], new_fn[1]);
|
||||
}
|
||||
|
||||
//finally, append SRAM file name
|
||||
strcat(new_fn, parts[count(parts) - 1]);
|
||||
strcpy(sram_fn, strptr(new_fn));
|
||||
}
|
||||
|
||||
//load cheat file if it exists
|
||||
strcpy(cheat_fn, sram_fn);
|
||||
strrtrim(cheat_fn, config::fs.save_ext.sget());
|
||||
strrtrim(cheat_fn, ".");
|
||||
strcat(cheat_fn, ".cht");
|
||||
if(fexists(cheat_fn) == true) {
|
||||
FileReader ff(cheat_fn);
|
||||
cheat.load(static_cast<Reader*>(&ff));
|
||||
}
|
||||
if(i != 0)sram_fn[i] = 0;
|
||||
strcat(sram_fn, ".srm");
|
||||
|
||||
find_header();
|
||||
read_header();
|
||||
@@ -215,12 +335,18 @@ bool Cartridge::unload() {
|
||||
r_mem->unload_cart();
|
||||
|
||||
if(base_rom) {
|
||||
zerofree(base_rom);
|
||||
SafeFree(base_rom);
|
||||
}
|
||||
|
||||
if(sram) {
|
||||
save_sram();
|
||||
zerofree(sram);
|
||||
SafeFree(sram);
|
||||
}
|
||||
|
||||
if(cheat.count() > 0 || fexists(cheat_fn)) {
|
||||
FileWriter ff(cheat_fn);
|
||||
cheat.save(static_cast<Writer*>(&ff));
|
||||
cheat.clear();
|
||||
}
|
||||
|
||||
cart_loaded = false;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
class Cartridge {
|
||||
public:
|
||||
bool cart_loaded;
|
||||
char rom_fn[4096], sram_fn[4096];
|
||||
char rom_fn[4096], sram_fn[4096], cheat_fn[4096], patch_fn[4096];
|
||||
|
||||
uint8 *base_rom, *rom, *sram;
|
||||
uint32 rom_size;
|
||||
@@ -31,6 +31,7 @@ enum {
|
||||
};
|
||||
|
||||
struct {
|
||||
uint32 crc32;
|
||||
uint32 header_index;
|
||||
|
||||
char name[32];
|
||||
@@ -39,16 +40,24 @@ struct {
|
||||
bool region;
|
||||
|
||||
uint32 mapper;
|
||||
|
||||
//set to true for games that need cart MMIO mapping (c4, dsp-n, ...),
|
||||
//for games that map outside the standard MMIO range of $2000-$5fff
|
||||
bool cart_mmio;
|
||||
bool srtc;
|
||||
bool sdd1;
|
||||
bool c4;
|
||||
bool dsp2;
|
||||
bool obc1;
|
||||
} cart;
|
||||
|
||||
void load_rom(Reader *rf);
|
||||
void patch_rom(Reader *rf);
|
||||
void load_sram();
|
||||
void save_sram();
|
||||
void find_header();
|
||||
void read_header();
|
||||
bool loaded() { return cart_loaded; }
|
||||
bool load(const char *fn);
|
||||
bool unload();
|
||||
|
||||
|
334
src/cheat/cheat.cpp
Normal file
334
src/cheat/cheat.cpp
Normal 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
48
src/cheat/cheat.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#define CHEAT_LIMIT 1024
|
||||
|
||||
class Cheat {
|
||||
public:
|
||||
enum { CT_PRO_ACTION_REPLAY, CT_GAME_GENIE };
|
||||
|
||||
struct CheatIndex {
|
||||
bool enabled;
|
||||
uint32 addr;
|
||||
uint8 data;
|
||||
char code[ 16 + 1];
|
||||
char desc[128 + 1];
|
||||
} index[CHEAT_LIMIT + 1];
|
||||
bool cheat_enabled;
|
||||
uint32 cheat_count;
|
||||
uint8 mask[0x200000];
|
||||
|
||||
inline bool enabled() { return cheat_enabled; }
|
||||
inline uint count() { return cheat_count; }
|
||||
inline bool exists(uint32 addr) { return bool(mask[addr >> 3] & 1 << (addr & 7)); }
|
||||
|
||||
bool decode(char *str, uint32 &addr, uint8 &data, uint8 &type);
|
||||
bool encode(char *str, uint32 addr, uint8 data, uint8 type);
|
||||
|
||||
private:
|
||||
uint mirror_address(uint addr);
|
||||
void set(uint32 addr);
|
||||
void clear(uint32 addr);
|
||||
public:
|
||||
|
||||
bool read(uint32 addr, uint8 &data);
|
||||
|
||||
void update_cheat_status();
|
||||
bool add(bool enable, char *code, char *desc);
|
||||
bool edit(uint32 n, bool enable, char *code, char *desc);
|
||||
bool get(uint32 n, bool &enable, uint32 &addr, uint8 &data, char *code, char *desc);
|
||||
bool remove (uint32 n);
|
||||
bool enabled(uint32 n);
|
||||
void enable (uint32 n);
|
||||
void disable(uint32 n);
|
||||
bool load(Reader *rf);
|
||||
bool save(Writer *wf);
|
||||
void clear();
|
||||
|
||||
Cheat();
|
||||
};
|
||||
|
||||
extern Cheat cheat;
|
133
src/chip/dsp2/dsp2.cpp
Normal file
133
src/chip/dsp2/dsp2.cpp
Normal 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
40
src/chip/dsp2/dsp2.h
Normal 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
173
src/chip/dsp2/dsp2_op.cpp
Normal 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
88
src/chip/obc1/obc1.cpp
Normal 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
18
src/chip/obc1/obc1.h
Normal 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();
|
||||
};
|
@@ -4,8 +4,8 @@
|
||||
void SDD1::init() {}
|
||||
|
||||
void SDD1::enable() {
|
||||
for(int i=0x4800;i<=0x4807;i++) {
|
||||
r_mem->set_mmio_mapper(i, mmio);
|
||||
for(int i = 0x4800; i <= 0x4807; i++) {
|
||||
r_mem->set_mmio_mapper(i, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,10 +50,9 @@ uint8 SDD1::mmio_read(uint16 addr) {
|
||||
}
|
||||
|
||||
void SDD1::mmio_write(uint16 addr, uint8 data) {
|
||||
int i;
|
||||
switch(addr) {
|
||||
case 0x4801:
|
||||
for(i=0;i<8;i++) {
|
||||
for(int i = 0; i < 8; i++) {
|
||||
sdd1.active[i] = !!(data & (1 << i));
|
||||
}
|
||||
break;
|
||||
@@ -89,14 +88,4 @@ uint8 SDD1::dma_read() {
|
||||
return sdd1.buffer[sdd1.buffer_index++];
|
||||
}
|
||||
|
||||
SDD1::SDD1() {
|
||||
mmio = new SDD1MMIO();
|
||||
}
|
||||
|
||||
uint8 SDD1MMIO::read(uint32 addr) {
|
||||
return sdd1->mmio_read(addr);
|
||||
}
|
||||
|
||||
void SDD1MMIO::write(uint32 addr, uint8 value) {
|
||||
sdd1->mmio_write(addr, value);
|
||||
}
|
||||
SDD1::SDD1() {}
|
||||
|
@@ -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();
|
||||
|
@@ -77,8 +77,8 @@ tm *t;
|
||||
void SRTC::init() {}
|
||||
|
||||
void SRTC::enable() {
|
||||
r_mem->set_mmio_mapper(0x2800, mmio);
|
||||
r_mem->set_mmio_mapper(0x2801, mmio);
|
||||
r_mem->set_mmio_mapper(0x2800, this);
|
||||
r_mem->set_mmio_mapper(0x2801, this);
|
||||
}
|
||||
|
||||
void SRTC::power() {
|
||||
@@ -88,7 +88,35 @@ void SRTC::power() {
|
||||
|
||||
void SRTC::reset() {
|
||||
srtc.index = -1;
|
||||
srtc.mode = SRTC_READ;
|
||||
srtc.mode = SRTC_READ;
|
||||
}
|
||||
|
||||
uint8 SRTC::mmio_read(uint16 addr) {
|
||||
switch(addr) {
|
||||
|
||||
case 0x2800: {
|
||||
if(srtc.mode == SRTC_READ) {
|
||||
if(srtc.index < 0) {
|
||||
set_time();
|
||||
srtc.index++;
|
||||
return 0x0f; //send start message
|
||||
} else if(srtc.index > MAX_SRTC_INDEX) {
|
||||
srtc.index = -1;
|
||||
return 0x0f; //send finished message
|
||||
} else {
|
||||
return srtc.data[srtc.index++];
|
||||
}
|
||||
} else {
|
||||
return 0x00;
|
||||
}
|
||||
} break;
|
||||
|
||||
case 0x2801: {
|
||||
} break;
|
||||
|
||||
}
|
||||
|
||||
return r_cpu->regs.mdr;
|
||||
}
|
||||
|
||||
//Please see notes above about the implementation of the S-RTC
|
||||
@@ -96,90 +124,66 @@ void SRTC::reset() {
|
||||
//as reads will refresh the data array with the current system
|
||||
//time. The write method is only here for the sake of faux
|
||||
//emulation of the real hardware.
|
||||
void SRTC::write(uint8 data) {
|
||||
data &= 0x0f; //only the low four bits are used
|
||||
void SRTC::mmio_write(uint16 addr, uint8 data) {
|
||||
switch(addr) {
|
||||
|
||||
if(data >= 0x0d) {
|
||||
switch(data) {
|
||||
case 0x0d:
|
||||
srtc.mode = SRTC_READ;
|
||||
srtc.index = -1;
|
||||
break;
|
||||
case 0x0e:
|
||||
srtc.mode = SRTC_COMMAND;
|
||||
break;
|
||||
case 0x0f:
|
||||
//unknown behaviour
|
||||
break;
|
||||
case 0x2800: {
|
||||
} break;
|
||||
|
||||
case 0x2801: {
|
||||
data &= 0x0f; //only the low four bits are used
|
||||
|
||||
if(data >= 0x0d) {
|
||||
switch(data) {
|
||||
case 0x0d:
|
||||
srtc.mode = SRTC_READ;
|
||||
srtc.index = -1;
|
||||
break;
|
||||
case 0x0e:
|
||||
srtc.mode = SRTC_COMMAND;
|
||||
break;
|
||||
case 0x0f:
|
||||
//unknown behaviour
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(srtc.mode == SRTC_WRITE) {
|
||||
if(srtc.index >= 0 && srtc.index < MAX_SRTC_INDEX) {
|
||||
srtc.data[srtc.index++] = data;
|
||||
if(srtc.mode == SRTC_WRITE) {
|
||||
if(srtc.index >= 0 && srtc.index < MAX_SRTC_INDEX) {
|
||||
srtc.data[srtc.index++] = data;
|
||||
|
||||
if(srtc.index == MAX_SRTC_INDEX) {
|
||||
//all S-RTC data has been loaded by program
|
||||
srtc.data[srtc.index++] = 0x00; //day_of_week
|
||||
if(srtc.index == MAX_SRTC_INDEX) {
|
||||
//all S-RTC data has been loaded by program
|
||||
srtc.data[srtc.index++] = 0x00; //day_of_week
|
||||
}
|
||||
}
|
||||
} else if(srtc.mode == SRTC_COMMAND) {
|
||||
switch(data) {
|
||||
case SRTC_COMMAND_CLEAR:
|
||||
memset(srtc.data, 0, MAX_SRTC_INDEX + 1);
|
||||
srtc.index = -1;
|
||||
srtc.mode = SRTC_READY;
|
||||
break;
|
||||
case SRTC_COMMAND_WRITE:
|
||||
srtc.index = 0;
|
||||
srtc.mode = SRTC_WRITE;
|
||||
break;
|
||||
default:
|
||||
//unknown behaviour
|
||||
srtc.mode = SRTC_READY;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(srtc.mode == SRTC_READ) {
|
||||
//ignore writes while in read mode
|
||||
} else if(srtc.mode == SRTC_READY) {
|
||||
//unknown behaviour
|
||||
}
|
||||
}
|
||||
} else if(srtc.mode == SRTC_COMMAND) {
|
||||
switch(data) {
|
||||
case SRTC_COMMAND_CLEAR:
|
||||
memset(srtc.data, 0, MAX_SRTC_INDEX + 1);
|
||||
srtc.index = -1;
|
||||
srtc.mode = SRTC_READY;
|
||||
break;
|
||||
case SRTC_COMMAND_WRITE:
|
||||
srtc.index = 0;
|
||||
srtc.mode = SRTC_WRITE;
|
||||
break;
|
||||
default:
|
||||
//unknown behaviour
|
||||
srtc.mode = SRTC_READY;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(srtc.mode == SRTC_READ) {
|
||||
//ignore writes while in read mode
|
||||
} else if(srtc.mode == SRTC_READY) {
|
||||
//unknown behaviour
|
||||
}
|
||||
} break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
uint8 SRTC::read() {
|
||||
if(srtc.mode == SRTC_READ) {
|
||||
if(srtc.index < 0) {
|
||||
set_time();
|
||||
srtc.index++;
|
||||
return 0x0f; //send start message
|
||||
} else if(srtc.index > MAX_SRTC_INDEX) {
|
||||
srtc.index = -1;
|
||||
return 0x0f; //send finished message
|
||||
} else {
|
||||
return srtc.data[srtc.index++];
|
||||
}
|
||||
} else {
|
||||
return 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
SRTC::SRTC() {
|
||||
mmio = new SRTCMMIO();
|
||||
}
|
||||
|
||||
uint8 SRTCMMIO::read(uint32 addr) {
|
||||
switch(addr) {
|
||||
case 0x2800:return srtc->read();
|
||||
}
|
||||
|
||||
return r_cpu->regs.mdr;
|
||||
}
|
||||
|
||||
void SRTCMMIO::write(uint32 addr, uint8 value) {
|
||||
switch(addr) {
|
||||
case 0x2801:srtc->write(value);break;
|
||||
}
|
||||
}
|
||||
SRTC::SRTC() {}
|
||||
|
@@ -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();
|
||||
};
|
||||
|
@@ -2,25 +2,61 @@ Config config_file;
|
||||
|
||||
namespace config {
|
||||
|
||||
SNES::VideoColorAdjust SNES::video_color_curve(&config_file, "snes.video_color_curve",
|
||||
"Applies contrast adjust filter to video output when enabled\n"
|
||||
"Works by lowering the brightness of darker colors,\n"
|
||||
"while leaving brighter colors alone; thus reducing saturation",
|
||||
true, Setting::TRUE_FALSE);
|
||||
FS::Path FS::base_path(0, "fs.base_path", "Directory that bsnes resides in", "");
|
||||
|
||||
SNES::VideoColorAdjust SNES::video_color_adjust_mode(&config_file, "snes.video_color_adjust_mode",
|
||||
"Selects color adjustment filter for video output\n"
|
||||
" 0 = Normal (no filter, rgb555)\n"
|
||||
" 1 = Grayscale mode (l5)\n"
|
||||
" 2 = VGA mode (rgb332)\n"
|
||||
" 3 = Genesis mode (rgb333)",
|
||||
0, Setting::DEC);
|
||||
FS::Path FS::rom_path(&config_file, "fs.rom_path",
|
||||
"Default path to look for ROM files in (\"\" = use default directory)", "");
|
||||
FS::Path FS::save_path(&config_file, "fs.save_path",
|
||||
"Default path for all save RAM and cheat files (\"\" = use current directory)", "");
|
||||
|
||||
void FS::Path::sset(const char *_data) {
|
||||
string path;
|
||||
strcpy(path, _data);
|
||||
strunquote(path);
|
||||
replace(path, "\\", "/");
|
||||
|
||||
//blank path?
|
||||
if(strlen(path) == 0) {
|
||||
Setting::sset(strptr(path));
|
||||
return;
|
||||
}
|
||||
|
||||
//missing final directory marker?
|
||||
if(strptr(path)[strlen(path) - 1] != '/') {
|
||||
strcat(path, "/");
|
||||
}
|
||||
|
||||
Setting::sset(strptr(path));
|
||||
}
|
||||
|
||||
Setting FS::save_ext(&config_file, "fs.save_ext",
|
||||
"Extension to be used for all save RAM files", "srm");
|
||||
|
||||
SNES::VideoColorAdjust SNES::gamma_ramp(&config_file, "snes.colorfilter.gamma_ramp",
|
||||
"Use precalculated TV-style gamma ramp", true, Setting::TRUE_FALSE);
|
||||
SNES::VideoColorAdjust SNES::sepia(&config_file, "snes.colorfilter.sepia",
|
||||
"Convert color to sepia tone", false, Setting::TRUE_FALSE);
|
||||
SNES::VideoColorAdjust SNES::grayscale(&config_file, "snes.colorfilter.grayscale",
|
||||
"Convert color to grayscale tone", false, Setting::TRUE_FALSE);
|
||||
SNES::VideoColorAdjust SNES::invert(&config_file, "snes.colorfilter.invert",
|
||||
"Invert output image colors", false, Setting::TRUE_FALSE);
|
||||
SNES::VideoColorAdjust SNES::contrast(&config_file, "snes.colorfilter.contrast",
|
||||
"", 0, Setting::DEC);
|
||||
SNES::VideoColorAdjust SNES::brightness(&config_file, "snes.colorfilter.brightness",
|
||||
"", 0, Setting::DEC);
|
||||
SNES::VideoColorAdjust SNES::gamma(&config_file, "snes.colorfilter.gamma",
|
||||
"", 100, Setting::DEC);
|
||||
|
||||
void SNES::VideoColorAdjust::set(uint32 _data) {
|
||||
data = _data;
|
||||
Setting::set(_data);
|
||||
::snes->update_color_lookup_table();
|
||||
}
|
||||
|
||||
Setting SNES::ntsc_merge_fields(&config_file, "snes.ntsc_merge_fields",
|
||||
"Merge fields in NTSC video filter\n"
|
||||
"Set to true if using filter at any refresh rate other than 60hz\n"
|
||||
"", false, Setting::TRUE_FALSE);
|
||||
|
||||
Setting SNES::mute(&config_file, "snes.mute", "Mutes SNES audio output when enabled",
|
||||
false, Setting::TRUE_FALSE);
|
||||
|
||||
|
@@ -2,13 +2,23 @@ extern Config config_file;
|
||||
|
||||
namespace config {
|
||||
|
||||
extern struct FS {
|
||||
static class Path : public Setting {
|
||||
public:
|
||||
void sset(const char *_data);
|
||||
SettingOperators(Path);
|
||||
} base_path, rom_path, save_path;
|
||||
static Setting save_ext;
|
||||
} fs;
|
||||
|
||||
extern struct SNES {
|
||||
static class VideoColorAdjust : public Setting {
|
||||
public:
|
||||
void set(uint32 _data);
|
||||
SettingOperators(VideoColorAdjust);
|
||||
} video_color_curve, video_color_adjust_mode;
|
||||
} gamma_ramp, sepia, grayscale, invert, contrast, brightness, gamma;
|
||||
|
||||
static Setting ntsc_merge_fields;
|
||||
static Setting mute;
|
||||
} snes;
|
||||
|
||||
|
@@ -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() {}
|
||||
|
@@ -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();
|
||||
};
|
||||
|
@@ -1,255 +0,0 @@
|
||||
void bCPU::dma_add_cycles(uint32 cycles) {
|
||||
status.dma_cycle_count += cycles;
|
||||
}
|
||||
|
||||
void bCPU::hdma_add_cycles(uint32 cycles) {
|
||||
if(run_state.dma) {
|
||||
status.dma_cycle_count += cycles;
|
||||
}
|
||||
status.hdma_cycle_count += cycles;
|
||||
}
|
||||
|
||||
uint32 bCPU::dma_addr(uint8 i) {
|
||||
uint32 r;
|
||||
r = (channel[i].srcbank << 16) | (channel[i].srcaddr);
|
||||
|
||||
if(channel[i].fixedxfer == false) {
|
||||
channel[i].srcaddr += channel[i].incmode;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void bCPU::dma_cputommio(uint8 i, uint8 index) {
|
||||
uint8 x;
|
||||
if(sdd1->dma_active() == true) {
|
||||
x = sdd1->dma_read();
|
||||
} else {
|
||||
x = r_mem->read(dma_addr(i));
|
||||
}
|
||||
|
||||
r_mem->write(0x2100 | ((channel[i].destaddr + index) & 0xff), x);
|
||||
|
||||
add_cycles(8);
|
||||
channel[i].xfersize--;
|
||||
}
|
||||
|
||||
void bCPU::dma_mmiotocpu(uint8 i, uint8 index) {
|
||||
uint8 x;
|
||||
x = r_mem->read(0x2100 | ((channel[i].destaddr + index) & 0xff));
|
||||
r_mem->write(dma_addr(i), x);
|
||||
|
||||
add_cycles(8);
|
||||
channel[i].xfersize--;
|
||||
}
|
||||
|
||||
void bCPU::dma_write(uint8 i, uint8 index) {
|
||||
if(channel[i].direction == 0) {
|
||||
dma_cputommio(i, index);
|
||||
} else {
|
||||
dma_mmiotocpu(i, index);
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::dma_run() {
|
||||
int i;
|
||||
for(i=0;i<8;i++) {
|
||||
if(channel[i].active == false)continue;
|
||||
|
||||
//first byte transferred?
|
||||
if(channel[i].read_index == 0) {
|
||||
sdd1->dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr),
|
||||
channel[i].xfersize);
|
||||
}
|
||||
|
||||
switch(channel[i].xfermode) {
|
||||
case 0:dma_write(i, 0); break; //0
|
||||
case 1:dma_write(i, channel[i].read_index & 1); break; //0,1
|
||||
case 2:dma_write(i, 0); break; //0,0
|
||||
case 3:dma_write(i, (channel[i].read_index >> 1) & 1);break; //0,0,1,1
|
||||
case 4:dma_write(i, channel[i].read_index & 3); break; //0,1,2,3
|
||||
case 5:dma_write(i, channel[i].read_index & 1); break; //0,1,0,1
|
||||
case 6:dma_write(i, 0); break; //0,0 [2]
|
||||
case 7:dma_write(i, (channel[i].read_index >> 1) & 1);break; //0,0,1,1 [3]
|
||||
}
|
||||
|
||||
channel[i].read_index++;
|
||||
dma_add_cycles(8);
|
||||
|
||||
if(channel[i].xfersize == 0) {
|
||||
channel[i].active = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
status.dma_state = DMASTATE_CPUSYNC;
|
||||
}
|
||||
|
||||
uint32 bCPU::hdma_addr(uint8 i) {
|
||||
return (channel[i].srcbank << 16) | (channel[i].hdma_addr++);
|
||||
}
|
||||
|
||||
uint32 bCPU::hdma_iaddr(uint8 i) {
|
||||
return (channel[i].hdma_ibank << 16) | (channel[i].hdma_iaddr++);
|
||||
}
|
||||
|
||||
uint16 bCPU::hdma_mmio(uint8 i) {
|
||||
uint8 l = channel[i].read_index;
|
||||
uint16 index;
|
||||
switch(channel[i].xfermode) {
|
||||
case 0:index = 0; break; //0
|
||||
case 1:index = l & 1; break; //0,1
|
||||
case 2:index = 0; break; //0,0
|
||||
case 3:index = (l >> 1) & 1;break; //0,0,1,1
|
||||
case 4:index = l & 3; break; //0,1,2,3
|
||||
case 5:index = l & 1; break; //0,1,0,1
|
||||
case 6:index = 0; break; //0,0 [2]
|
||||
case 7:index = (l >> 1) & 1;break; //0,0,1,1 [3]
|
||||
}
|
||||
|
||||
return (0x2100 | ((channel[i].destaddr + index) & 0xff));
|
||||
}
|
||||
|
||||
uint8 bCPU::hdma_read(uint8 i) {
|
||||
if(channel[i].direction == DMA_MMIOTOCPU) {
|
||||
return r_mem->read(hdma_mmio(i));
|
||||
} else if(!channel[i].hdma_indirect) {
|
||||
return r_mem->read(hdma_addr(i));
|
||||
} else {
|
||||
return r_mem->read(hdma_iaddr(i));
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::hdma_write(uint8 i, uint8 x) {
|
||||
uint32 addr;
|
||||
if(channel[i].direction == DMA_CPUTOMMIO) {
|
||||
addr = hdma_mmio(i);
|
||||
} else if(!channel[i].hdma_indirect) {
|
||||
addr = hdma_addr(i);
|
||||
} else {
|
||||
addr = hdma_iaddr(i);
|
||||
}
|
||||
|
||||
if((bool)config::cpu.hdma_enable == true) {
|
||||
r_mem->write(addr, x);
|
||||
}
|
||||
|
||||
add_cycles(8);
|
||||
hdma_add_cycles(8);
|
||||
}
|
||||
|
||||
void bCPU::hdma_update(uint8 i) {
|
||||
channel[i].hdma_line_counter = r_mem->read(hdma_addr(i));
|
||||
add_cycles(8);
|
||||
hdma_add_cycles(8);
|
||||
|
||||
if(channel[i].hdma_indirect) {
|
||||
channel[i].hdma_iaddr = r_mem->read(hdma_addr(i)) << 8;
|
||||
add_cycles(8);
|
||||
hdma_add_cycles(8);
|
||||
}
|
||||
|
||||
if(channel[i].hdma_line_counter == 0) {
|
||||
channel[i].hdma_active = false;
|
||||
channel[i].hdma_do_transfer = false;
|
||||
return;
|
||||
}
|
||||
|
||||
channel[i].hdma_do_transfer = true;
|
||||
|
||||
if(channel[i].hdma_indirect) {
|
||||
channel[i].hdma_iaddr >>= 8;
|
||||
channel[i].hdma_iaddr |= r_mem->read(hdma_addr(i)) << 8;
|
||||
add_cycles(8);
|
||||
hdma_add_cycles(8);
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::hdma_run() {
|
||||
static uint8 hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
|
||||
for(int i=0;i<8;i++) {
|
||||
if(!channel[i].hdma_enabled || !channel[i].hdma_active)continue;
|
||||
|
||||
if(channel[i].hdma_do_transfer) {
|
||||
int xferlen = hdma_xferlen[channel[i].xfermode];
|
||||
for(channel[i].read_index=0;channel[i].read_index<xferlen;channel[i].read_index++) {
|
||||
hdma_write(i, hdma_read(i));
|
||||
}
|
||||
}
|
||||
|
||||
channel[i].hdma_line_counter--;
|
||||
channel[i].hdma_do_transfer = !!(channel[i].hdma_line_counter & 0x80);
|
||||
if((channel[i].hdma_line_counter & 0x7f) == 0) {
|
||||
hdma_update(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8 bCPU::hdma_enabled_channels() {
|
||||
int r = 0;
|
||||
for(int i=0;i<8;i++) {
|
||||
if(channel[i].hdma_enabled)r++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
uint8 bCPU::hdma_active_channels() {
|
||||
int r = 0;
|
||||
for(int i=0;i<8;i++) {
|
||||
if(channel[i].hdma_enabled && channel[i].hdma_active)r++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* hdmainit_activate()
|
||||
* hdma_activate()
|
||||
*
|
||||
* Functions are called by CPU timing routine
|
||||
* when an HDMA event (init or run) occurs.
|
||||
*/
|
||||
|
||||
void bCPU::hdmainit_activate() {
|
||||
for(int i=0;i<8;i++) {
|
||||
channel[i].hdma_active = false;
|
||||
channel[i].hdma_do_transfer = false;
|
||||
}
|
||||
|
||||
if(hdma_enabled_channels() != 0) {
|
||||
status.hdma_state = HDMASTATE_IDMASYNC;
|
||||
run_state.hdma = true;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::hdma_activate() {
|
||||
if(hdma_active_channels() != 0) {
|
||||
status.hdma_state = HDMASTATE_DMASYNC;
|
||||
run_state.hdma = true;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::dma_reset() {
|
||||
for(int i=0;i<8;i++) {
|
||||
channel[i].read_index = 0;
|
||||
channel[i].active = false;
|
||||
channel[i].hdma_enabled = false;
|
||||
channel[i].dmap = 0x00;
|
||||
channel[i].direction = 0;
|
||||
channel[i].hdma_indirect = false;
|
||||
channel[i].incmode = 1;
|
||||
channel[i].fixedxfer = false;
|
||||
channel[i].xfermode = 0;
|
||||
channel[i].destaddr = 0;
|
||||
channel[i].srcaddr = 0;
|
||||
channel[i].xfersize = 0x0000;
|
||||
//xfersize and hdma_iaddr are of union { uint16 };
|
||||
//channel[i].hdma_iaddr = 0x0000;
|
||||
channel[i].hdma_ibank = 0;
|
||||
channel[i].hdma_addr = 0x0000;
|
||||
channel[i].hdma_line_counter = 0x00;
|
||||
channel[i].hdma_unknown = 0x00;
|
||||
|
||||
channel[i].hdma_active = false;
|
||||
channel[i].hdma_do_transfer = false;
|
||||
}
|
||||
}
|
@@ -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"
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -1,3 +0,0 @@
|
||||
cl /ML /O2 bcpugen.cpp
|
||||
@pause
|
||||
@del *.obj
|
@@ -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
|
18
src/cpu/bcpu/core/bcpugen.cpp
Normal file
18
src/cpu/bcpu/core/bcpugen.cpp
Normal 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
3
src/cpu/bcpu/core/cc.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
cl /O2 /wd4996 bcpugen.cpp
|
||||
@pause
|
||||
@del *.obj
|
8
src/cpu/bcpu/core/clean.bat
Normal file
8
src/cpu/bcpu/core/clean.bat
Normal 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
|
90
src/cpu/bcpu/core/core.cpp
Normal file
90
src/cpu/bcpu/core/core.cpp
Normal 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
74
src/cpu/bcpu/core/core.h
Normal 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"
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -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;
|
@@ -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
@@ -1,582 +1,582 @@
|
||||
void bCPU::op_sta_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, regs.a.w);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.a.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_stx_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, regs.x.w);
|
||||
if(regs.p.x)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.x.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sty_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, regs.y.w);
|
||||
if(regs.p.x)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.y.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_stz_addr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, 0x0000);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, 0x0000 >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_addrx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
cpu_c4(aa.w, aa.w + regs.x.w);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, regs.a.w);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 5: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, regs.a.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_stz_addrx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
cpu_c4(aa.w, aa.w + regs.x.w);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w, 0x0000);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 5: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.x.w + 1, 0x0000 >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_addry() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
cpu_c4(aa.w, aa.w + regs.y.w);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 5: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_long() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
aa.b = op_read();
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 5: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_longx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
aa.l = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
aa.h = op_read();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
aa.b = op_read();
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.x.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 5: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.x.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DP, dp, regs.a.w);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + 1, regs.a.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_stx_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DP, dp, regs.x.w);
|
||||
if(regs.p.x)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + 1, regs.x.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sty_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DP, dp, regs.y.w);
|
||||
if(regs.p.x)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + 1, regs.y.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_stz_dp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DP, dp, 0x0000);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + 1, 0x0000 >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_dpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
cpu_io();
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, regs.a.w);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 5: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, regs.a.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sty_dpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
cpu_io();
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, regs.y.w);
|
||||
if(regs.p.x)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 5: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, regs.y.w >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_stz_dpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
cpu_io();
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w, 0x0000);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 5: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.x.w + 1, 0x0000 >> 8);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_stx_dpy() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
cpu_io();
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
if(regs.p.x)last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.y.w, regs.x.l);
|
||||
if(regs.p.x)status.cycle_pos = 0;
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 5: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_DP, dp + regs.y.w + 1, regs.x.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_idp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
aa.l = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 5: {
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 6:
|
||||
} break;
|
||||
case 6: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_ildp() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
aa.l = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 5: {
|
||||
aa.b = op_read(OPMODE_DP, dp + 2);
|
||||
break;
|
||||
case 6:
|
||||
} break;
|
||||
case 6: {
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 7:
|
||||
} break;
|
||||
case 7: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_idpx() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
cpu_io();
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
aa.l = op_read(OPMODE_DP, dp + regs.x.w);
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 5: {
|
||||
aa.h = op_read(OPMODE_DP, dp + regs.x.w + 1);
|
||||
break;
|
||||
case 6:
|
||||
} break;
|
||||
case 6: {
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 7:
|
||||
} break;
|
||||
case 7: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_idpy() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
aa.l = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 5: {
|
||||
cpu_c4(aa.w, aa.w + regs.y.w);
|
||||
break;
|
||||
case 6:
|
||||
} break;
|
||||
case 6: {
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 7:
|
||||
} break;
|
||||
case 7: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_ildpy() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
dp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
cpu_c2();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
aa.l = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
aa.h = op_read(OPMODE_DP, dp + 1);
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 5: {
|
||||
aa.b = op_read(OPMODE_DP, dp + 2);
|
||||
break;
|
||||
case 6:
|
||||
} break;
|
||||
case 6: {
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 7:
|
||||
} break;
|
||||
case 7: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_LONG, aa.d + regs.y.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_sr() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
cpu_io();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_SP, sp, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_SP, sp + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::op_sta_isry() {
|
||||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
case 1: {
|
||||
sp = op_read();
|
||||
break;
|
||||
case 2:
|
||||
} break;
|
||||
case 2: {
|
||||
cpu_io();
|
||||
break;
|
||||
case 3:
|
||||
} break;
|
||||
case 3: {
|
||||
aa.l = op_read(OPMODE_SP, sp);
|
||||
break;
|
||||
case 4:
|
||||
} break;
|
||||
case 4: {
|
||||
aa.h = op_read(OPMODE_SP, sp + 1);
|
||||
break;
|
||||
case 5:
|
||||
} break;
|
||||
case 5: {
|
||||
cpu_io();
|
||||
break;
|
||||
case 6:
|
||||
} break;
|
||||
case 6: {
|
||||
if(regs.p.m)last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w, regs.a.l);
|
||||
if(regs.p.m)status.cycle_pos = 0;
|
||||
break;
|
||||
case 7:
|
||||
} break;
|
||||
case 7: {
|
||||
last_cycle();
|
||||
op_write(OPMODE_DBR, aa.w + regs.y.w + 1, regs.a.h);
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
265
src/cpu/bcpu/dma/dma.cpp
Normal file
265
src/cpu/bcpu/dma/dma.cpp
Normal 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
60
src/cpu/bcpu/dma/dma.h
Normal 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();
|
40
src/cpu/bcpu/memory/memory.cpp
Normal file
40
src/cpu/bcpu/memory/memory.cpp
Normal 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();
|
||||
}
|
7
src/cpu/bcpu/memory/memory.h
Normal file
7
src/cpu/bcpu/memory/memory.h
Normal 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);
|
@@ -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;
|
||||
|
@@ -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();
|
@@ -3,5 +3,4 @@
|
||||
|
||||
CPU::CPU() {
|
||||
cpu_version = 1;
|
||||
mmio = &mmio_unmapped;
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#include "cpuregs.h"
|
||||
|
||||
class CPU {
|
||||
class CPU : public MMIO {
|
||||
public:
|
||||
//CPU version number
|
||||
//* 1 and 2 are known
|
||||
@@ -12,14 +12,13 @@ uint8 cpu_version;
|
||||
virtual uint16 vcounter() = 0;
|
||||
virtual uint16 hcounter() = 0;
|
||||
virtual uint16 hcycles() = 0;
|
||||
virtual bool overscan() = 0;
|
||||
virtual bool interlace() = 0;
|
||||
virtual bool interlace_field() = 0;
|
||||
virtual bool overscan() = 0;
|
||||
virtual uint16 region_scanlines() = 0;
|
||||
virtual void set_interlace(bool r) = 0;
|
||||
virtual void set_overscan (bool r) = 0;
|
||||
|
||||
MMIO *mmio;
|
||||
CPURegs regs;
|
||||
virtual uint8 port_read (uint8 port) = 0;
|
||||
virtual void port_write(uint8 port, uint8 value) = 0;
|
||||
|
BIN
src/data/about.bmp
Normal file
BIN
src/data/about.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 281 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
BIN
src/data/snes_controller.bmp
Normal file
BIN
src/data/snes_controller.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
@@ -380,11 +380,13 @@ int32 fir_samplel, fir_sampler;
|
||||
if(voice[v].brr_index == 0) {
|
||||
voice[v].brr_header = readb(voice[v].brr_ptr);
|
||||
|
||||
if(voice[v].brr_header_flags() & BRR_END) {
|
||||
status.ENDX |= (1 << v);
|
||||
}
|
||||
//moving status.ENDX bit set into == BRR_END condition per DMV27
|
||||
//if(voice[v].brr_header_flags() & BRR_END) {
|
||||
// status.ENDX |= (1 << v);
|
||||
//}
|
||||
|
||||
if(voice[v].brr_header_flags() == BRR_END) {
|
||||
status.ENDX |= (1 << v);
|
||||
voice[v].env_state = SILENCE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
@@ -429,6 +431,10 @@ int32 fir_samplel, fir_sampler;
|
||||
if(++voice[v].brr_index > 15) {
|
||||
voice[v].brr_index = 0;
|
||||
if(voice[v].brr_header_flags() & BRR_END) {
|
||||
//below condition added by DMV27
|
||||
if(voice[v].brr_header_flags() & BRR_LOOP) {
|
||||
status.ENDX |= (1 << v);
|
||||
}
|
||||
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2) + 2);
|
||||
voice[v].brr_looped = true;
|
||||
} else {
|
||||
|
@@ -1,6 +1,3 @@
|
||||
#define BSNES_VERSION "0.015"
|
||||
#define BSNES_TITLE "bsnes v" BSNES_VERSION
|
||||
|
||||
#ifdef POLYMORPHISM
|
||||
#define ref(x) x
|
||||
#else
|
||||
@@ -16,6 +13,7 @@
|
||||
|
||||
#include "reader/reader.h"
|
||||
#include "cart/cart.h"
|
||||
#include "cheat/cheat.h"
|
||||
|
||||
#include "memory/memory.h"
|
||||
#include "memory/bmemory/bmemory.h"
|
||||
@@ -37,6 +35,8 @@
|
||||
#include "chip/srtc/srtc.h"
|
||||
#include "chip/sdd1/sdd1.h"
|
||||
#include "chip/c4/c4.h"
|
||||
#include "chip/dsp2/dsp2.h"
|
||||
#include "chip/obc1/obc1.h"
|
||||
|
||||
extern MMIO mmio_unmapped;
|
||||
#ifdef POLYMORPHISM
|
||||
@@ -46,22 +46,25 @@ extern MMIO mmio_unmapped;
|
||||
extern DSP *deref(dsp);
|
||||
extern PPU *deref(ppu);
|
||||
#else
|
||||
extern bMemBus deref(mem);
|
||||
extern bCPU deref(cpu);
|
||||
extern bAPU deref(apu);
|
||||
extern bDSP deref(dsp);
|
||||
extern bPPU deref(ppu);
|
||||
extern MEMCORE deref(mem);
|
||||
extern CPUCORE deref(cpu);
|
||||
extern APUCORE deref(apu);
|
||||
extern DSPCORE deref(dsp);
|
||||
extern PPUCORE deref(ppu);
|
||||
#endif
|
||||
extern SNES *snes;
|
||||
|
||||
extern SRTC *srtc;
|
||||
extern SDD1 *sdd1;
|
||||
extern C4 *c4;
|
||||
extern DSP2 *dsp2;
|
||||
extern OBC1 *obc1;
|
||||
|
||||
#include "config/config.h"
|
||||
|
||||
#ifdef INTERFACE_MAIN
|
||||
Cartridge cartridge;
|
||||
Cheat cheat;
|
||||
|
||||
#include "config/config.cpp"
|
||||
#ifdef POLYMORPHISM
|
||||
@@ -71,16 +74,18 @@ Cartridge cartridge;
|
||||
DSP *deref(dsp);
|
||||
PPU *deref(ppu);
|
||||
#else
|
||||
bMemBus deref(mem);
|
||||
bCPU deref(cpu);
|
||||
bAPU deref(apu);
|
||||
bDSP deref(dsp);
|
||||
bPPU deref(ppu);
|
||||
MEMCORE deref(mem);
|
||||
CPUCORE deref(cpu);
|
||||
APUCORE deref(apu);
|
||||
DSPCORE deref(dsp);
|
||||
PPUCORE deref(ppu);
|
||||
#endif
|
||||
SNES *snes;
|
||||
|
||||
SRTC *srtc;
|
||||
SDD1 *sdd1;
|
||||
C4 *c4;
|
||||
DSP2 *dsp2;
|
||||
OBC1 *obc1;
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
libbase : version 0.03 ~byuu (08/20/05)
|
||||
libbase : version 0.07 ~byuu (04/21/06)
|
||||
*/
|
||||
|
||||
#ifndef __LIBBASE
|
||||
@@ -9,16 +9,20 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define zerofree(__n) if(__n) { free(__n); __n = 0; }
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#define SafeFree(__n) if(__n) { free(__n); __n = 0; }
|
||||
#define SafeDelete(__n) if(__n) { delete(__n); __n = 0; }
|
||||
#define SafeRelease(__n) if(__n) { __n->Release(); __n = 0; }
|
||||
|
||||
typedef unsigned int uint;
|
||||
|
||||
@@ -38,9 +42,91 @@ typedef signed short int16;
|
||||
typedef signed long int32;
|
||||
typedef signed long long int64;
|
||||
|
||||
#ifdef null
|
||||
#undef null
|
||||
#endif
|
||||
#define null 0xffffffff
|
||||
template<typename T> void swap(T &x, T &y) {
|
||||
T z = x;
|
||||
x = y;
|
||||
y = z;
|
||||
}
|
||||
|
||||
template<typename T, typename Targ> T bound_range(T &x, Targ min, Targ max) {
|
||||
return (x < T(min)) ? T(min) : (x > T(max)) ? T(max) : x;
|
||||
}
|
||||
|
||||
inline bool fexists(const char *fn) {
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
if(!fp)return false;
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline uint32 fsize(FILE *fp) {
|
||||
if(!fp)return 0;
|
||||
uint32 pos = ftell(fp);
|
||||
fseek(fp, 0, SEEK_END);
|
||||
uint32 size = ftell(fp);
|
||||
fseek(fp, pos, SEEK_SET);
|
||||
return size;
|
||||
}
|
||||
|
||||
inline uint32 fsize(const char *fn) {
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
if(!fp)return 0;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
uint32 size = ftell(fp);
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
return size;
|
||||
}
|
||||
|
||||
const uint32 crc32_table[256] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
inline uint32 crc32_adjust(uint32 crc32, uint32 input) {
|
||||
return ((crc32 >> 8) & 0x00ffffff) ^ crc32_table[(crc32 ^ input) & 0xff];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
625
src/lib/libbpf.cpp
Normal file
625
src/lib/libbpf.cpp
Normal 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
104
src/lib/libbpf.h
Normal 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
|
@@ -13,9 +13,22 @@ uint Setting::get() {
|
||||
void Setting::set(uint _data) {
|
||||
data = _data;
|
||||
|
||||
if(type != DEC && type != HEX) {
|
||||
//data is a boolean type
|
||||
switch(type) {
|
||||
case TRUE_FALSE:
|
||||
case ENABLED_DISABLED:
|
||||
case ON_OFF:
|
||||
case YES_NO:
|
||||
data &= 1;
|
||||
break;
|
||||
case HEX8:
|
||||
data &= 0xff;
|
||||
break;
|
||||
case HEX16:
|
||||
data &= 0xffff;
|
||||
break;
|
||||
case HEX24:
|
||||
data &= 0xffffff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,11 +111,11 @@ uint Config::string_to_uint(uint type, char *input) {
|
||||
return (uint)false;
|
||||
}
|
||||
|
||||
if(strbegin(input, "0x")) {
|
||||
return strhex(input + 2);
|
||||
if(strbegin(input, "0x") || strbegin(input, "-0x")) {
|
||||
return sstrhex(input + 2);
|
||||
}
|
||||
|
||||
return strdec(input);
|
||||
return sstrdec(input);
|
||||
}
|
||||
|
||||
char *Config::uint_to_string(uint type, uint input) {
|
||||
@@ -120,12 +133,12 @@ static char output[512];
|
||||
case Setting::YES_NO:
|
||||
sprintf(output, "%s", (input & 1) ? "yes" : "no");
|
||||
break;
|
||||
case Setting::DEC:
|
||||
sprintf(output, "%d", input);
|
||||
break;
|
||||
case Setting::HEX:
|
||||
sprintf(output, "0x%x", input);
|
||||
break;
|
||||
case Setting::DEC: sprintf(output, "%d", input); break;
|
||||
case Setting::HEX: sprintf(output, "0x%x", input); break;
|
||||
case Setting::HEX8: sprintf(output, "0x%0.2x", input & 0xff); break;
|
||||
case Setting::HEX16: sprintf(output, "0x%0.4x", input & 0xffff); break;
|
||||
case Setting::HEX24: sprintf(output, "0x%0.6x", input & 0xffffff); break;
|
||||
case Setting::HEX32: sprintf(output, "0x%0.8x", input); break;
|
||||
}
|
||||
|
||||
return output;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
libconfig : version 0.05 ~byuu (10/30/05)
|
||||
libconfig : version 0.07 ~byuu (02/10/06)
|
||||
*/
|
||||
|
||||
#ifndef __LIBCONFIG
|
||||
@@ -31,8 +31,10 @@ class Config;
|
||||
inline __name &operator=(const float _data) { set((uint)_data); return *this; } \
|
||||
inline __name &operator=(const double _data) { set((uint)_data); return *this; } \
|
||||
void toggle() { data ^= 1; set(data); } \
|
||||
__name(Config *_parent, char *_name, char *_desc = 0, uint _data = 0, uint _type = Setting::DEC) : \
|
||||
Setting(_parent, _name, _desc, _data, _type) {}
|
||||
__name(Config *_parent, char *_name, char *_desc, uint _data, uint _type) : \
|
||||
Setting(_parent, _name, _desc, _data, _type) {} \
|
||||
__name(Config *_parent, char *_name, char *_desc, char *_data) : \
|
||||
Setting(_parent, _name, _desc, _data) {}
|
||||
|
||||
class Setting {
|
||||
friend class Config;
|
||||
@@ -46,9 +48,12 @@ enum {
|
||||
ENABLED_DISABLED,
|
||||
ON_OFF,
|
||||
YES_NO,
|
||||
BOOL,
|
||||
DEC,
|
||||
HEX,
|
||||
HEX8,
|
||||
HEX16,
|
||||
HEX24,
|
||||
HEX32,
|
||||
STR
|
||||
};
|
||||
char *name, *desc;
|
||||
|
@@ -93,6 +93,18 @@ int srclen = strlen(src);
|
||||
}
|
||||
void strcpy(substring &dest, substring &src) { strcpy(dest, strptr(src)); }
|
||||
|
||||
//this differs from libc's strncpy in that it always
|
||||
//appends a null terminator to the end of a copied string
|
||||
void strncpy(substring &dest, const char *src, uint32 length) {
|
||||
int srclen = strlen(src);
|
||||
//never copy more text than is in the string
|
||||
if(srclen > length)srclen = length;
|
||||
if(srclen > dest.size) { strresize(dest, srclen); }
|
||||
strncpy(dest.s, src, srclen);
|
||||
dest.s[srclen] = 0;
|
||||
}
|
||||
void strncpy(substring &dest, substring &src, uint32 length) { strncpy(dest, strptr(src), length); }
|
||||
|
||||
void strset(substring &dest, uint pos, uint8 c) {
|
||||
char *s;
|
||||
if(pos > dest.size) { strresize(dest, pos); }
|
||||
@@ -187,11 +199,14 @@ bool qstrpos(const char *str, substring &key, uint &pos) { return qstrpos(str, s
|
||||
bool qstrpos(substring &str, substring &key, uint &pos) { return qstrpos(strptr(str), strptr(key), pos); }
|
||||
|
||||
void strtr(char *dest, const char *before, const char *after) {
|
||||
int i, l, sl = strlen(dest), bsl = strlen(before), asl = strlen(after);
|
||||
if((bsl != asl) || bsl == 0)return;
|
||||
for(i=0;i<sl;i++) {
|
||||
for(l=0;l<bsl;l++) {
|
||||
if(dest[i] == before[l])dest[i] = after[l];
|
||||
int sl = strlen(dest), bsl = strlen(before), asl = strlen(after);
|
||||
if(bsl != asl || bsl == 0)return;
|
||||
for(int i = 0; i < sl; i++) {
|
||||
for(int l = 0; l < bsl; l++) {
|
||||
if(dest[i] == before[l]) {
|
||||
dest[i] = after[l];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -246,8 +261,8 @@ bool striend(substring &str, const char *key) { return striend(strptr(str), key)
|
||||
void strltrim(char *str, const char *key) {
|
||||
int i, ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return;
|
||||
if(!strbegin(str, key)) {
|
||||
for(i=0;i<ssl-ksl;i++)str[i] = str[i + ksl];
|
||||
if(strbegin(str, key)) {
|
||||
for(i = 0; i < (ssl - ksl); i++)str[i] = str[i + ksl];
|
||||
str[i] = 0;
|
||||
}
|
||||
}
|
||||
@@ -256,8 +271,8 @@ void strltrim(substring &str, const char *key) { strltrim(strptr(str), key); }
|
||||
void striltrim(char *str, const char *key) {
|
||||
int i, ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return;
|
||||
if(!stribegin(str, key)) {
|
||||
for(i=0;i<ssl-ksl;i++)str[i] = str[i + ksl];
|
||||
if(stribegin(str, key)) {
|
||||
for(i = 0; i < (ssl-ksl); i++)str[i] = str[i + ksl];
|
||||
str[i] = 0;
|
||||
}
|
||||
}
|
||||
@@ -266,7 +281,7 @@ void striltrim(substring &str, const char *key) { striltrim(strptr(str), key); }
|
||||
void strrtrim(char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return;
|
||||
if(!strend(str, key)) {
|
||||
if(strend(str, key)) {
|
||||
str[ssl - ksl] = 0;
|
||||
}
|
||||
}
|
||||
@@ -275,7 +290,7 @@ void strrtrim(substring &str, const char *key) { strrtrim(strptr(str), key); }
|
||||
void strirtrim(char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl)return;
|
||||
if(!striend(str, key)) {
|
||||
if(striend(str, key)) {
|
||||
str[ssl - ksl] = 0;
|
||||
}
|
||||
}
|
||||
@@ -314,13 +329,13 @@ uint strhex(const char *str) {
|
||||
uint r = 0, m = 0;
|
||||
int i, ssl = strlen(str);
|
||||
uint8 x;
|
||||
for(i=0;i<ssl;i++) {
|
||||
for(i = 0; i < ssl; i++) {
|
||||
if(str[i] >= '0' && str[i] <= '9');
|
||||
else if(str[i] >= 'A' && str[i] <= 'F');
|
||||
else if(str[i] >= 'a' && str[i] <= 'f');
|
||||
else break;
|
||||
}
|
||||
for(--i;i>=0;i--, m+=4) {
|
||||
for(--i; i >= 0; i--, m += 4) {
|
||||
x = str[i];
|
||||
if(x >= '0' && x <= '9')x -= '0';
|
||||
else if(x >= 'A' && x <= 'F')x -= 'A' - 0x0a;
|
||||
@@ -344,11 +359,11 @@ uint strdec(const char *str) {
|
||||
uint m = 1;
|
||||
int i, r = 0, ssl = strlen(str);
|
||||
uint8 x;
|
||||
for(i=0;i<ssl;i++) {
|
||||
for(i = 0; i < ssl; i++) {
|
||||
if(str[i] >= '0' && str[i] <= '9');
|
||||
else break;
|
||||
}
|
||||
for(--i;i>=0;i--, m*=10) {
|
||||
for(--i; i >= 0; i--, m *= 10) {
|
||||
x = str[i];
|
||||
if(x >= '0' && x <= '9')x -= '0';
|
||||
else return r;
|
||||
@@ -370,11 +385,11 @@ uint strbin(const char *str) {
|
||||
uint r = 0, m = 0;
|
||||
int i, ssl = strlen(str);
|
||||
uint8 x;
|
||||
for(i=0;i<ssl;i++) {
|
||||
for(i = 0; i < ssl; i++) {
|
||||
if(str[i] == '0' || str[i] == '1');
|
||||
else break;
|
||||
}
|
||||
for(--i;i>=0;i--, m++) {
|
||||
for(--i; i >= 0; i--, m++) {
|
||||
x = str[i];
|
||||
if(str[i] == '0' || str[i] == '1')x -= '0';
|
||||
else return r;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
libstring : version 0.07 ~byuu (11/30/05)
|
||||
libstring : version 0.10 ~byuu (03/05/06)
|
||||
*/
|
||||
|
||||
#ifndef __LIBSTRING
|
||||
@@ -46,6 +46,8 @@ bool strimatch(substring &dest, substring &src);
|
||||
|
||||
void strcpy(substring &dest, const char *src);
|
||||
void strcpy(substring &dest, substring &src);
|
||||
void strncpy(substring &dest, const char *src, uint32 length);
|
||||
void strncpy(substring &dest, substring &src, uint32 length);
|
||||
|
||||
void strset(substring &dest, uint pos, uint8 c);
|
||||
|
||||
@@ -135,10 +137,10 @@ void replace(substring &str, const char *key, substring &token);
|
||||
void qreplace(substring &str, const char *key, const char *token);
|
||||
void qreplace(substring &str, const char *key, substring &token);
|
||||
|
||||
void split(string &dest, const char *key, char *src);
|
||||
void split(string &dest, const char *key, const char *src);
|
||||
void split(string &dest, const char *key, substring &src);
|
||||
|
||||
void qsplit(string &dest, const char *key, char *src);
|
||||
void qsplit(string &dest, const char *key, const char *src);
|
||||
void qsplit(string &dest, const char *key, substring &src);
|
||||
|
||||
void sprintf(substring &str, const char *s, ...);
|
||||
|
@@ -112,7 +112,7 @@ char num[64];
|
||||
} else if(str[i]==')') {
|
||||
if(pdepth == 0) {
|
||||
free(str);
|
||||
return null; //error! too many )'s
|
||||
return 0; //error! too many )'s
|
||||
}
|
||||
pdepth --;
|
||||
}
|
||||
@@ -120,7 +120,7 @@ char num[64];
|
||||
|
||||
if(pdepth != 0) {
|
||||
free(str);
|
||||
return null; //error! unequal ('s to )'s
|
||||
return 0; //error! unequal ('s to )'s
|
||||
}
|
||||
|
||||
pdepth = maxpdepth;
|
||||
|
@@ -1,13 +1,9 @@
|
||||
void split(string &dest, const char *key, char *src) {
|
||||
int i, ssl = strlen(src), ksl = strlen(key);
|
||||
uint lp = 0, split_count = 0;
|
||||
uint8 x;
|
||||
for(i=0;i<=ssl-ksl;) {
|
||||
void split(string &dest, const char *key, const char *src) {
|
||||
int ssl = strlen(src), ksl = strlen(key);
|
||||
uint lp = 0, split_count = 0;
|
||||
for(int32 i = 0; i <= ssl - ksl;) {
|
||||
if(!memcmp(src + i, key, ksl)) {
|
||||
x = src[i];
|
||||
src[i] = 0;
|
||||
strcpy(dest[split_count++], src + lp);
|
||||
src[i] = x;
|
||||
strncpy(dest[split_count++], src + lp, i - lp);
|
||||
i += ksl;
|
||||
lp = i;
|
||||
} else i++;
|
||||
@@ -17,22 +13,18 @@ uint8 x;
|
||||
}
|
||||
void split(string &dest, const char *key, substring &src) { split(dest, key, strptr(src)); }
|
||||
|
||||
void qsplit(string &dest, const char *key, char *src) {
|
||||
int i, z, ssl = strlen(src), ksl = strlen(key);
|
||||
uint lp = 0, split_count = 0;
|
||||
uint8 x;
|
||||
for(i=0;i<=ssl-ksl;) {
|
||||
x = src[i];
|
||||
if(x=='\"' || x=='\'') {
|
||||
void qsplit(string &dest, const char *key, const char *src) {
|
||||
int z, ssl = strlen(src), ksl = strlen(key);
|
||||
uint lp = 0, split_count = 0;
|
||||
for(int32 i = 0; i <= ssl - ksl;) {
|
||||
uint8 x = src[i];
|
||||
if(x == '\"' || x == '\'') {
|
||||
z = i++;
|
||||
while(src[i] != x && i < ssl)i++;
|
||||
if(i >= ssl)i = z;
|
||||
}
|
||||
if(!memcmp(src + i, key, ksl)) {
|
||||
x = src[i];
|
||||
src[i] = 0;
|
||||
strcpy(dest[split_count++], src + lp);
|
||||
src[i] = x;
|
||||
strncpy(dest[split_count++], src + lp, i - lp);
|
||||
i += ksl;
|
||||
lp = i;
|
||||
} else i++;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
libvector : version 0.03 ~byuu (08/16/05)
|
||||
libvector : version 0.04 ~byuu (12/24/05)
|
||||
*/
|
||||
|
||||
#ifndef __LIBVECTOR
|
||||
@@ -9,13 +9,14 @@ template<typename T> class vector {
|
||||
private:
|
||||
T *array;
|
||||
int size, sizelimit;
|
||||
|
||||
//find next array size that is a power of two
|
||||
int findsize(int newsize) {
|
||||
int r = 1;
|
||||
while(r >= 1) {
|
||||
r <<= 1;
|
||||
if(r > sizelimit)return sizelimit;
|
||||
if(r >= newsize) return r;
|
||||
if(r > sizelimit)return sizelimit;
|
||||
if(r >= newsize)return r;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
@@ -30,12 +31,32 @@ public:
|
||||
array = (T*)realloc(array, sizeof(T) * newsize);
|
||||
|
||||
if(newsize > size) {
|
||||
for(int i=size;i<newsize;i+=sizeof(T)) {
|
||||
for(int i = size; i < newsize; i += sizeof(T)) {
|
||||
array[i] = (T)0;
|
||||
}
|
||||
}
|
||||
|
||||
size = newsize;
|
||||
size = newsize;
|
||||
}
|
||||
|
||||
//used to free up memory used by vector, but without
|
||||
//actually destroying the vector itself
|
||||
void release() {
|
||||
resize(16);
|
||||
}
|
||||
|
||||
T *handle() { return (T*)array; }
|
||||
|
||||
void copy(T *source, uint32 copy_size) {
|
||||
if(copy_size > size) {
|
||||
resize(copy_size);
|
||||
copy_size = size;
|
||||
}
|
||||
memcpy(array, source, copy_size * sizeof(T));
|
||||
}
|
||||
|
||||
void clear() {
|
||||
memset(array, 0, size * sizeof(T));
|
||||
}
|
||||
|
||||
vector(int newsize, int newsizelimit) {
|
||||
|
104
src/lib/libwin32.cpp
Normal file
104
src/lib/libwin32.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
#include "libbase.h"
|
||||
#include "libwin32.h"
|
||||
|
||||
#include "libwin32_misc.cpp"
|
||||
#include "libwin32_file.cpp"
|
||||
#include "libwin32_window.cpp"
|
||||
#include "libwin32_control.cpp"
|
||||
#include "libwin32_label.cpp"
|
||||
#include "libwin32_groupbox.cpp"
|
||||
#include "libwin32_editbox.cpp"
|
||||
#include "libwin32_button.cpp"
|
||||
#include "libwin32_checkbox.cpp"
|
||||
#include "libwin32_radiobox.cpp"
|
||||
#include "libwin32_slider.cpp"
|
||||
#include "libwin32_combobox.cpp"
|
||||
#include "libwin32_listbox.cpp"
|
||||
#include "libwin32_listview.cpp"
|
||||
|
||||
void alert(char *s, ...) {
|
||||
char str[4096];
|
||||
va_list args;
|
||||
va_start(args, s);
|
||||
vsprintf(str, s, args);
|
||||
va_end(args);
|
||||
MessageBox(0, str, "bsnes", MB_OK);
|
||||
}
|
||||
|
||||
void ShowCursor() {
|
||||
if(global::cursor_visible == false) {
|
||||
global::cursor_visible = true;
|
||||
ShowCursor(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void HideCursor() {
|
||||
if(global::cursor_visible == true) {
|
||||
global::cursor_visible = false;
|
||||
ShowCursor(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void ParseStyleParam(const char *style, string &output) {
|
||||
string temp;
|
||||
strcpy(temp, style);
|
||||
strlower(temp);
|
||||
replace(temp, " ", "");
|
||||
strltrim(temp, "|");
|
||||
strrtrim(temp, "|");
|
||||
replace(temp, "||", "|");
|
||||
split(output, "|", temp);
|
||||
}
|
||||
|
||||
long __stdcall CoreWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
return WindowList.WndProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
bool WindowManager::Add(Window *window) {
|
||||
if(window_count >= WINDOW_LIMIT)return false;
|
||||
list[window_count++] = window;
|
||||
return true;
|
||||
}
|
||||
|
||||
long WindowManager::WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
for(int i = 0; i < window_count; i++) {
|
||||
if(list[i]->hwnd == hwnd) {
|
||||
return list[i]->WndProc(msg, wparam, lparam);
|
||||
}
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
WindowManager::WindowManager() {
|
||||
window_count = 0;
|
||||
}
|
||||
|
||||
Font CreateFont(const char *name, uint height, const char *style) {
|
||||
HDC hdc = GetDC(0);
|
||||
Font font = CreateFont(-MulDiv(height, GetDeviceCaps(hdc, LOGPIXELSY), 72),
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, name);
|
||||
ReleaseDC(0, hdc);
|
||||
return font;
|
||||
}
|
||||
|
||||
libwin32_init::libwin32_init() {
|
||||
WindowList.list = (Window**)malloc((WINDOW_LIMIT + 1) * sizeof(Window*));
|
||||
memset(WindowList.list, 0, (WINDOW_LIMIT + 1) * sizeof(Window*));
|
||||
|
||||
InitCommonControls();
|
||||
global::font_default = CreateFont("Tahoma", 8);
|
||||
|
||||
WNDCLASS wc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
|
||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = CoreWindowProc;
|
||||
wc.lpszClassName = "resize_class";
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&wc);
|
||||
}
|
60
src/lib/libwin32.h
Normal file
60
src/lib/libwin32.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
libwin32 : version 0.03 ~byuu (04/14/06)
|
||||
*/
|
||||
|
||||
#ifndef __LIBWIN32
|
||||
#define __LIBWIN32
|
||||
|
||||
#include "libstring.h"
|
||||
|
||||
#define WINVER 0x0400
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
#include <direct.h>
|
||||
|
||||
#define WINDOW_LIMIT 4095
|
||||
#define CONTROL_LIMIT 4095
|
||||
|
||||
#define WINDOWID_INDEX 10000
|
||||
#define CONTROLID_INDEX 20000
|
||||
|
||||
typedef HFONT Font;
|
||||
|
||||
namespace global {
|
||||
bool cursor_visible = true;
|
||||
Font font_default;
|
||||
};
|
||||
|
||||
void alert(char *s, ...);
|
||||
void ShowCursor();
|
||||
void HideCursor();
|
||||
void ParseStyleParam(const char *style, string &output);
|
||||
|
||||
class Window;
|
||||
class Control;
|
||||
|
||||
#include "libwin32_window.h"
|
||||
#include "libwin32_control.h"
|
||||
|
||||
long __stdcall CoreWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
|
||||
|
||||
class WindowManager {
|
||||
public:
|
||||
uint window_count;
|
||||
Window **list;
|
||||
|
||||
long WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
|
||||
bool Add(Window *window);
|
||||
|
||||
WindowManager();
|
||||
} WindowList;
|
||||
|
||||
Font CreateFont(const char *name, uint height, const char *style = "");
|
||||
|
||||
class libwin32_init {
|
||||
public:
|
||||
libwin32_init();
|
||||
} __libwin32_init;
|
||||
|
||||
#endif
|
32
src/lib/libwin32_button.cpp
Normal file
32
src/lib/libwin32_button.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
bool Button::Create(Window *parent_window, const char *style, int x, int y, int width, int height, const char *text) {
|
||||
if(!parent_window)return false;
|
||||
|
||||
parent = parent_window;
|
||||
id = CONTROLID_INDEX + parent->control_count;
|
||||
type = BUTTON;
|
||||
state.ws = WS_CHILD;
|
||||
state.es = 0;
|
||||
state.x = x;
|
||||
state.y = y;
|
||||
state.width = width;
|
||||
state.height = height;
|
||||
|
||||
string part;
|
||||
ParseStyleParam(style, part);
|
||||
for(int i = 0; i < count(part); i++) {
|
||||
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
|
||||
if(strmatch(part[i], "disabled"))state.ws |= WS_DISABLED;
|
||||
|
||||
if(strmatch(part[i], "left"))state.ws |= BS_LEFT;
|
||||
if(strmatch(part[i], "center"))state.ws |= BS_CENTER;
|
||||
if(strmatch(part[i], "right"))state.ws |= BS_RIGHT;
|
||||
}
|
||||
|
||||
hwnd = CreateWindowEx(state.es, "BUTTON", text, state.ws,
|
||||
state.x, state.y, state.width, state.height,
|
||||
parent->hwnd, (HMENU)id, GetModuleHandle(0), 0);
|
||||
if(!hwnd)return false;
|
||||
|
||||
PostCreate();
|
||||
return true;
|
||||
}
|
40
src/lib/libwin32_checkbox.cpp
Normal file
40
src/lib/libwin32_checkbox.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
bool Checkbox::Checked() { return SendMessage(hwnd, BM_GETCHECK, 0, 0); }
|
||||
void Checkbox::Check(bool state) { SendMessage(hwnd, BM_SETCHECK, (WPARAM)state, 0); }
|
||||
void Checkbox::Check() { Check(true); }
|
||||
void Checkbox::Uncheck() { Check(false); }
|
||||
void Checkbox::ToggleCheck() { Check(!Checked()); }
|
||||
|
||||
bool Checkbox::Create(Window *parent_window, const char *style, int x, int y, int width, int height, const char *text) {
|
||||
if(!parent_window)return false;
|
||||
|
||||
parent = parent_window;
|
||||
id = CONTROLID_INDEX + parent->control_count;
|
||||
type = CHECKBOX;
|
||||
state.ws = WS_CHILD;
|
||||
state.es = 0;
|
||||
state.x = x;
|
||||
state.y = y;
|
||||
state.width = width;
|
||||
state.height = height;
|
||||
|
||||
string part;
|
||||
ParseStyleParam(style, part);
|
||||
for(int i = 0; i < count(part); i++) {
|
||||
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
|
||||
if(strmatch(part[i], "disabled"))state.ws |= WS_DISABLED;
|
||||
|
||||
if(strmatch(part[i], "left"))state.ws |= BS_LEFT;
|
||||
if(strmatch(part[i], "center"))state.ws |= BS_CENTER;
|
||||
if(strmatch(part[i], "right"))state.ws |= BS_RIGHT;
|
||||
if(strmatch(part[i], "auto"))state.ws |= BS_AUTOCHECKBOX;
|
||||
}
|
||||
if(!(state.ws & BS_AUTOCHECKBOX))state.ws |= BS_CHECKBOX;
|
||||
|
||||
hwnd = CreateWindowEx(state.es, "BUTTON", text, state.ws,
|
||||
state.x, state.y, state.width, state.height,
|
||||
parent->hwnd, (HMENU)id, GetModuleHandle(0), 0);
|
||||
if(!hwnd)return false;
|
||||
|
||||
PostCreate();
|
||||
return true;
|
||||
}
|
66
src/lib/libwin32_combobox.cpp
Normal file
66
src/lib/libwin32_combobox.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
void Combobox::AddItem(const char *text) {
|
||||
SendMessage(hwnd, CB_ADDSTRING, 0, (LPARAM)text);
|
||||
}
|
||||
|
||||
void Combobox::DeleteItem(uint id) {
|
||||
SendMessage(hwnd, CB_DELETESTRING, id, 0);
|
||||
}
|
||||
|
||||
void Combobox::DeleteAllItems() {
|
||||
SendMessage(hwnd, CB_RESETCONTENT, 0, 0);
|
||||
}
|
||||
|
||||
uint Combobox::GetItemCount() {
|
||||
return SendMessage(hwnd, CB_GETCOUNT, 0, 0);
|
||||
}
|
||||
|
||||
void Combobox::SetSelection(uint id) {
|
||||
SendMessage(hwnd, CB_SETCURSEL, id, 0);
|
||||
}
|
||||
|
||||
int Combobox::GetSelection() {
|
||||
return SendMessage(hwnd, CB_GETCURSEL, 0, 0);
|
||||
}
|
||||
|
||||
bool Combobox::Create(Window *parent_window, const char *style, int x, int y, int width, int height, const char *text) {
|
||||
if(!parent_window)return false;
|
||||
|
||||
parent = parent_window;
|
||||
id = CONTROLID_INDEX + parent->control_count;
|
||||
type = COMBOBOX;
|
||||
state.ws = WS_CHILD | CBS_DROPDOWNLIST | CBS_HASSTRINGS;
|
||||
state.es = 0;
|
||||
state.x = x;
|
||||
state.y = y;
|
||||
state.width = width;
|
||||
state.height = height;
|
||||
|
||||
string part;
|
||||
ParseStyleParam(style, part);
|
||||
for(int i = 0; i < count(part); i++) {
|
||||
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
|
||||
if(strmatch(part[i], "disabled"))state.ws |= WS_DISABLED;
|
||||
if(strmatch(part[i], "border"))state.ws |= WS_BORDER;
|
||||
if(strmatch(part[i], "raised"))state.ws |= WS_DLGFRAME;
|
||||
|
||||
if(strmatch(part[i], "sunken"))state.es |= WS_EX_STATICEDGE;
|
||||
if(strmatch(part[i], "edge"))state.es |= WS_EX_CLIENTEDGE;
|
||||
}
|
||||
|
||||
hwnd = CreateWindowEx(state.es, "COMBOBOX", text, state.ws,
|
||||
state.x, state.y, state.width, state.height,
|
||||
parent->hwnd, (HMENU)id, GetModuleHandle(0), 0);
|
||||
if(!hwnd)return false;
|
||||
|
||||
if(strmatch(text, "") == false) {
|
||||
string t;
|
||||
split(t, "|", text);
|
||||
for(int i = 0; i < ::count(t); i++) {
|
||||
AddItem(strptr(t[i]));
|
||||
}
|
||||
}
|
||||
SetSelection(0);
|
||||
|
||||
PostCreate();
|
||||
return true;
|
||||
}
|
99
src/lib/libwin32_control.cpp
Normal file
99
src/lib/libwin32_control.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* called after custom control type successfully creates
|
||||
* control, used to initialize common control defaults
|
||||
*/
|
||||
void Control::PostCreate() {
|
||||
SetFont(global::font_default);
|
||||
parent->Add(*this);
|
||||
}
|
||||
|
||||
uint Control::GetID() { return id; }
|
||||
uint Control::GetType() { return type; }
|
||||
|
||||
void Control::SetFont(Font font) {
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)font, 0);
|
||||
}
|
||||
|
||||
void Control::Show(bool do_show) {
|
||||
if(do_show == true) {
|
||||
ShowWindow(hwnd, SW_NORMAL);
|
||||
state.ws |= WS_VISIBLE;
|
||||
} else {
|
||||
ShowWindow(hwnd, SW_HIDE);
|
||||
state.ws &= ~WS_VISIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
bool Control::Visible() {
|
||||
return !!(GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE);
|
||||
}
|
||||
|
||||
void Control::Show() { Show(true); }
|
||||
void Control::Hide() { Show(false); }
|
||||
void Control::Focus() { SetFocus(hwnd); }
|
||||
|
||||
void Control::Enable(bool do_enable) {
|
||||
if(do_enable == true) {
|
||||
SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_DISABLED);
|
||||
state.ws &= ~WS_DISABLED;
|
||||
} else {
|
||||
SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_DISABLED);
|
||||
state.ws |= WS_DISABLED;
|
||||
}
|
||||
}
|
||||
|
||||
bool Control::Enabled() {
|
||||
return !(GetWindowLong(hwnd, GWL_STYLE) & WS_DISABLED);
|
||||
}
|
||||
|
||||
void Control::Enable() { Enable(true); }
|
||||
void Control::Disable() { Enable(false); }
|
||||
|
||||
void Control::SetBackgroundColor(uint r, uint g, uint b) {
|
||||
state.use_backcolor = true;
|
||||
state.backcolor = (r << 16) | (g << 8) | b;
|
||||
if(backbrush)DeleteObject((HGDIOBJ)backbrush);
|
||||
backbrush = CreateSolidBrush(RGB(r, g, b));
|
||||
if(hwnd)InvalidateRect(hwnd, 0, TRUE);
|
||||
}
|
||||
|
||||
void Control::SetTextColor(uint r, uint g, uint b) {
|
||||
state.use_textcolor = true;
|
||||
state.textcolor = (r << 16) | (g << 8) | b;
|
||||
if(hwnd)InvalidateRect(hwnd, 0, TRUE);
|
||||
}
|
||||
|
||||
const char *Control::GetText() {
|
||||
static char t[256 + 1];
|
||||
GetWindowText(hwnd, t, 256);
|
||||
return t;
|
||||
}
|
||||
|
||||
void Control::GetText(char *text, uint length) {
|
||||
GetWindowText(hwnd, text, length ? length : 255);
|
||||
}
|
||||
|
||||
void Control::SetText(const char *text, ...) {
|
||||
char str[4096];
|
||||
va_list args;
|
||||
va_start(args, text);
|
||||
vsprintf(str, text, args);
|
||||
va_end(args);
|
||||
SetWindowText(hwnd, str);
|
||||
}
|
||||
|
||||
Control::Control() {
|
||||
hwnd = 0;
|
||||
backbrush = 0;
|
||||
state.use_backcolor = false;
|
||||
state.use_textcolor = false;
|
||||
state.backcolor = 0;
|
||||
state.textcolor = 0;
|
||||
}
|
||||
|
||||
Control::~Control() {
|
||||
if(backbrush) {
|
||||
DeleteObject((HGDIOBJ)backbrush);
|
||||
backbrush = 0;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user