Update to v078r01 release.

byuu says:

Started on a new SMP core for bsnes/Performance. I wanted to start
clean, and only copied over the debugger+disassembler portions from the
existing version.  I figured that if I took the existing one and tried
trimming it down, that it'd end up with too much old baggage.  But so
far, the opcodes are looking mostly the same anyway, only I'm
using #defines and a switch table in place of the template function
trickery.

I have enough written now that I can run Zelda 3 at least (although it
gets stuck in a loop immediately after.) No real point in comparing
speed yet, because it'll definitely go down as it becomes more complete.
This commit is contained in:
Tim Allen 2011-05-02 23:53:16 +10:00
parent 0a3d6e4c53
commit 9a3650c6ab
22 changed files with 1255 additions and 43 deletions

View File

@ -5,7 +5,7 @@ profile := accuracy
ui := ui
# debugger
options :=
options := debugger
# compiler
c := $(compiler) -std=gnu99

View File

@ -23,7 +23,7 @@ else ifeq ($(profile),compatibility)
else ifeq ($(profile),performance)
flags += -DPROFILE_PERFORMANCE
snescpu := $(snes)/alt/cpu
snessmp := $(snes)/smp
snessmp := $(snes)/alt/smp
snesdsp := $(snes)/alt/dsp
snesppu := $(snes)/alt/ppu-performance
endif

122
bsnes/snes/alt/smp/algorithms.cpp Executable file
View File

@ -0,0 +1,122 @@
uint8 SMP::fn_adc(uint8 x, uint8 y) {
int r = x + y + regs.p.c;
regs.p.n = r & 0x80;
regs.p.v = ~(x ^ y) & (x ^ r) & 0x80;
regs.p.h = (x ^ y ^ r) & 0x10;
regs.p.z = (uint8)r == 0;
regs.p.c = r > 0xff;
return r;
}
uint16 SMP::fn_addw(uint16 x, uint16 y) {
uint16 r;
regs.p.c = 0;
r = fn_adc(x, y);
r |= fn_adc(x >> 8, y >> 8) << 8;
regs.p.z = r == 0;
return r;
}
uint8 SMP::fn_and(uint8 x, uint8 y) {
x &= y;
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 SMP::fn_cmp(uint8 x, uint8 y) {
int r = x - y;
regs.p.n = r & 0x80;
regs.p.z = (uint8)r == 0;
regs.p.c = r >= 0;
return x;
}
uint16 SMP::fn_cmpw(uint16 x, uint16 y) {
int r = x - y;
regs.p.n = r & 0x8000;
regs.p.z = (uint16)r == 0;
regs.p.c = r >= 0;
return x;
}
uint8 SMP::fn_eor(uint8 x, uint8 y) {
x ^= y;
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 SMP::fn_or(uint8 x, uint8 y) {
x |= y;
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 SMP::fn_sbc(uint8 x, uint8 y) {
int r = x - y - !regs.p.c;
regs.p.n = r & 0x80;
regs.p.v = (x ^ y) & (x ^ r) & 0x80;
regs.p.h = !((x ^ y ^ r) & 0x10);
regs.p.z = (uint8)r == 0;
regs.p.c = r >= 0;
return r;
}
uint16 SMP::fn_subw(uint16 x, uint16 y) {
uint16 r;
regs.p.c = 1;
r = fn_sbc(x, y);
r |= fn_sbc(x >> 8, y >> 8) << 8;
regs.p.z = r == 0;
return r;
}
uint8 SMP::fn_inc(uint8 x) {
x++;
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 SMP::fn_dec(uint8 x) {
x--;
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 SMP::fn_asl(uint8 x) {
regs.p.c = x & 0x80;
x <<= 1;
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 SMP::fn_lsr(uint8 x) {
regs.p.c = x & 0x01;
x >>= 1;
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 SMP::fn_rol(uint8 x) {
unsigned carry = (unsigned)regs.p.c;
regs.p.c = x & 0x80;
x = (x << 1) | carry;
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 SMP::fn_ror(uint8 x) {
unsigned carry = (unsigned)regs.p.c << 7;
regs.p.c = x & 0x01;
x = carry | (x >> 1);
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}

255
bsnes/snes/alt/smp/core.cpp Executable file
View File

@ -0,0 +1,255 @@
void SMP::op_io() {
timer0.tick();
timer1.tick();
timer2.tick();
}
uint8 SMP::op_read(uint16 addr) {
timer0.tick();
timer1.tick();
timer2.tick();
if((addr & 0xfff0) == 0x00f0) return mmio_read(addr);
if((addr & 0xffc0) == 0xffc0 && status.iplrom_enable) return iplrom[addr & 0x3f];
return apuram[addr];
}
void SMP::op_write(uint16 addr, uint8 data) {
timer0.tick();
timer1.tick();
timer2.tick();
if((addr & 0xfff0) == 0x00f0) mmio_write(addr, data);
apuram[addr] = data; //all writes go to RAM, even MMIO writes
}
#define op_readpc() op_read(regs.pc++)
#define op_readdp(addr) op_read((regs.p.p << 8) + addr)
#define op_writedp(addr, data) op_write((regs.p.p << 8) + addr, data)
#define OP_ADJUST_DP(func) \
dp = op_readpc(); \
rd = op_readdp(dp); \
rd = func(rd); \
op_writedp(dp, rd);
#define OP_ADJUST_REG(func, target) \
op_io(); \
target = func(target);
#define OP_BRANCH(condition) \
rd = op_readpc(); \
if(condition) { \
op_io(); \
op_io(); \
regs.pc += (int8)rd; \
}
#define OP_MOV_DP_REG(source) \
dp = op_readpc(); \
op_readdp(dp); \
op_writedp(dp, source);
#define OP_MOV_REG_CONST(target) \
target = op_readpc(); \
regs.p.n = (target & 0x80); \
regs.p.z = (target == 0);
#define OP_MOV_REG_DP(target) \
sp = op_readpc(); \
target = op_readdp(sp); \
regs.p.n = (target & 0x80); \
regs.p.z = (target == 0);
#define OP_MOV_REG_REG(target, source) \
op_io(); \
target = source; \
regs.p.n = (target & 0x80); \
regs.p.z = (target == 0);
#define OP_READ_REG_DP(func, target) \
dp = op_readpc(); \
rd = op_readdp(dp); \
target = func(target, rd);
void SMP::op_step() {
unsigned opcode = op_readpc();
op_io();
static unsigned rd, wr, dp, sp;
switch(opcode) {
case 0x00: //nop
break;
case 0x10: //bpl $rr
OP_BRANCH(regs.p.n == 0)
break;
case 0x1d: //dec x
OP_ADJUST_REG(fn_dec, regs.x)
break;
case 0x1f: //jmp ($aaaa,x)
dp = op_readpc() << 0;
dp |= op_readpc() << 8;
op_io();
dp += regs.x;
rd = op_read(dp + 0) << 0;
rd |= op_read(dp + 1) << 8;
regs.pc = rd;
break;
case 0x2f: //bra $rr
rd = op_readpc();
op_io();
op_io();
regs.pc += (int8)rd;
break;
case 0x5d: //mov x,a
OP_MOV_REG_REG(regs.x, regs.a)
break;
case 0x78: //cmp $dp,#$ss
rd = op_readpc();
dp = op_readpc();
wr = op_readdp(dp);
fn_cmp(wr, rd);
op_io();
break;
case 0x7d: //mov a,x
OP_MOV_REG_REG(regs.a, regs.x)
break;
case 0x7e: //cmp y,$dp
OP_READ_REG_DP(fn_cmp, regs.y)
break;
case 0x8f: //mov $dp,#$ss
rd = op_readpc();
dp = op_readpc();
op_readdp(dp);
op_writedp(dp, rd);
break;
case 0xab: //inc $dp
OP_ADJUST_DP(fn_inc)
break;
case 0xba: //movw ya,$dp
sp = op_readpc();
regs.a = op_readdp(sp + 0);
op_io();
regs.y = op_readdp(sp + 1);
regs.p.n = (regs.ya & 0x8000);
regs.p.z = (regs.ya == 0);
break;
case 0xbd: //mov sp,x
op_io();
regs.sp = regs.x;
break;
case 0xc4: //mov $dd,a
OP_MOV_DP_REG(regs.a)
break;
case 0xc6: //mov (x),a
op_io();
op_readdp(regs.x);
op_writedp(regs.x, regs.a);
break;
case 0xcb: //mov $dp,y
OP_MOV_DP_REG(regs.y)
break;
case 0xcd: //mov x,#$ss
OP_MOV_REG_CONST(regs.x)
break;
case 0xd0: //bne $rr
OP_BRANCH(regs.p.z == 0)
break;
case 0xd7: //mov ($dp)+y,a
sp = op_readpc();
dp = op_readdp(sp + 0) << 0;
dp |= op_readdp(sp + 1) << 8;
op_io();
dp += regs.y;
op_read(dp);
op_write(dp, regs.a);
break;
case 0xda: //movw $dp,ya
dp = op_readpc();
op_readdp(dp);
op_writedp(dp + 0, regs.a);
op_writedp(dp + 1, regs.y);
break;
case 0xdd: //mov a,y
OP_MOV_REG_REG(regs.a, regs.y)
break;
case 0xe4: //mov y,$dp
OP_MOV_REG_DP(regs.a)
break;
case 0xe8: //mov a,#$ss
OP_MOV_REG_CONST(regs.a)
break;
case 0xeb: //mov y,$dp
OP_MOV_REG_DP(regs.y)
break;
case 0xfc: //inc y
OP_ADJUST_REG(fn_inc, regs.y)
break;
default:
static bool stop = false;
regs.pc--;
if(stop == false) {
stop = true;
print("Unknown opcode @ ", hex<4>(regs.pc), ":", hex<2>(opcode), "\n");
char buffer[4096];
disassemble_opcode(buffer, regs.pc);
print(buffer, "\n");
}
break;
}
step(cycle_table[opcode]);
}
const unsigned SMP::cycle_table[256] = {
#define c 12
//0 1 2 3 4 5 6 7 8 9 A B C D E F
2,8,4,7, 3,4,3,6, 2,6,5,4, 5,4,6,8, //0
4,8,4,7, 4,5,5,6, 5,5,6,5, 2,2,4,6, //1
2,8,4,7, 3,4,3,6, 2,6,5,4, 5,4,7,4, //2
4,8,4,7, 4,5,5,6, 5,5,6,5, 2,2,3,8, //3
2,8,4,7, 3,4,3,6, 2,6,4,4, 5,4,6,6, //4
4,8,4,7, 4,5,5,6, 5,5,4,5, 2,2,4,3, //5
2,8,4,7, 3,4,3,6, 2,6,4,4, 5,4,7,5, //6
4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,3,6, //7
2,8,4,7, 3,4,3,6, 2,6,5,4, 5,2,4,5, //8
4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,c,5, //9
3,8,4,7, 3,4,3,6, 2,6,4,4, 5,2,4,4, //A
4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,3,4, //B
3,8,4,7, 4,5,4,7, 2,5,6,4, 5,2,4,9, //C
4,8,4,7, 5,6,6,7, 4,5,5,5, 2,2,8,3, //D
2,8,4,7, 3,4,3,6, 2,4,5,3, 4,3,4,1, //E
4,8,4,7, 4,5,5,6, 3,4,5,4, 2,2,6,1, //F
#undef c
};

21
bsnes/snes/alt/smp/core.hpp Executable file
View File

@ -0,0 +1,21 @@
alwaysinline void op_io();
debugvirtual alwaysinline uint8 op_read(uint16 addr);
debugvirtual alwaysinline void op_write(uint16 addr, uint8 data);
debugvirtual alwaysinline void op_step();
static const unsigned cycle_table[256];
uint8 fn_adc (uint8 x, uint8 y);
uint16 fn_addw(uint16 x, uint16 y);
uint8 fn_and (uint8 x, uint8 y);
uint8 fn_cmp (uint8 x, uint8 y);
uint16 fn_cmpw(uint16 x, uint16 y);
uint8 fn_eor (uint8 x, uint8 y);
uint8 fn_inc (uint8 x);
uint8 fn_dec (uint8 x);
uint8 fn_or (uint8 x, uint8 y);
uint8 fn_sbc (uint8 x, uint8 y);
uint16 fn_subw(uint16 x, uint16 y);
uint8 fn_asl (uint8 x);
uint8 fn_lsr (uint8 x);
uint8 fn_rol (uint8 x);
uint8 fn_ror (uint8 x);

View File

@ -0,0 +1,75 @@
#ifdef SMP_CPP
void SMPDebugger::op_step() {
bool break_event = false;
usage[regs.pc] |= UsageExec;
opcode_pc = regs.pc;
opcode_edge = true;
debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00);
if(step_event && step_event() == true) {
debugger.break_event = Debugger::BreakEvent::SMPStep;
scheduler.exit(Scheduler::ExitReason::DebuggerEvent);
}
opcode_edge = false;
SMP::op_step();
synchronize_cpu();
}
uint8 SMPDebugger::op_read(uint16 addr) {
uint8 data = SMP::op_read(addr);
usage[addr] |= UsageRead;
debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Read, addr, data);
return data;
}
void SMPDebugger::op_write(uint16 addr, uint8 data) {
SMP::op_write(addr, data);
usage[addr] |= UsageWrite;
usage[addr] &= ~UsageExec;
debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Write, addr, data);
}
SMPDebugger::SMPDebugger() {
usage = new uint8[1 << 16]();
opcode_pc = 0xffc0;
opcode_edge = false;
}
SMPDebugger::~SMPDebugger() {
delete[] usage;
}
bool SMPDebugger::property(unsigned id, string &name, string &value) {
unsigned n = 0;
#define item(name_, value_) \
if(id == n++) { \
name = name_; \
value = value_; \
return true; \
}
//$00f0
item("$00f0", "");
item("Clock Speed", (unsigned)status.clock_speed);
item("Timers Enable", status.timers_enable);
item("RAM Disable", status.ram_disable);
item("RAM Writable", status.ram_writable);
item("Timers Disable", status.timers_disable);
//$00f1
item("$00f1", "");
item("IPLROM Enable", status.iplrom_enable);
//$00f2
item("$00f2", "");
item("DSP Address", string("0x", hex<2>(status.dsp_addr)));
#undef item
return false;
}
#endif

View File

@ -0,0 +1,22 @@
class SMPDebugger : public SMP, public ChipDebugger {
public:
bool property(unsigned id, string &name, string &value);
function<bool ()> step_event;
enum Usage {
UsageRead = 0x80,
UsageWrite = 0x40,
UsageExec = 0x20,
};
uint8 *usage;
uint16 opcode_pc;
bool opcode_edge;
void op_step();
uint8 op_read(uint16 addr);
void op_write(uint16 addr, uint8 data);
SMPDebugger();
~SMPDebugger();
};

View File

@ -0,0 +1,304 @@
uint8 SMP::disassemble_read(uint16 addr) {
if(addr >= 0xffc0) return smp.iplrom[addr & 0x3f];
return smp.apuram[addr];
}
uint16 SMP::relb(int8 offset, int op_len) {
uint16 pc = regs.pc + op_len;
return pc + offset;
}
void SMP::disassemble_opcode(char *output, uint16 addr) {
char *s, t[512];
uint8 op, op0, op1;
uint16 opw, opdp0, opdp1;
s = output;
sprintf(s, "..%.4x ", addr);
op = disassemble_read(addr + 0);
op0 = disassemble_read(addr + 1);
op1 = disassemble_read(addr + 2);
opw = (op0) | (op1 << 8);
opdp0 = ((unsigned)regs.p.p << 8) + op0;
opdp1 = ((unsigned)regs.p.p << 8) + op1;
strcpy(t, " ");
switch(op) {
case 0x00: sprintf(t, "nop"); break;
case 0x01: sprintf(t, "tcall 0"); break;
case 0x02: sprintf(t, "set0 $%.3x", opdp0); break;
case 0x03: sprintf(t, "bbs0 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x04: sprintf(t, "or a,$%.3x", opdp0); break;
case 0x05: sprintf(t, "or a,$%.4x", opw); break;
case 0x06: sprintf(t, "or a,(x)"); break;
case 0x07: sprintf(t, "or a,($%.3x+x)", opdp0); break;
case 0x08: sprintf(t, "or a,#$%.2x", op0); break;
case 0x09: sprintf(t, "or $%.3x,$%.3x", opdp1, opdp0); break;
case 0x0a: sprintf(t, "or1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break;
case 0x0b: sprintf(t, "asl $%.3x", opdp0); break;
case 0x0c: sprintf(t, "asl $%.4x", opw); break;
case 0x0d: sprintf(t, "push p"); break;
case 0x0e: sprintf(t, "tset $%.4x,a", opw); break;
case 0x0f: sprintf(t, "brk"); break;
case 0x10: sprintf(t, "bpl $%.4x", relb(op0, 2)); break;
case 0x11: sprintf(t, "tcall 1"); break;
case 0x12: sprintf(t, "clr0 $%.3x", opdp0); break;
case 0x13: sprintf(t, "bbc0 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x14: sprintf(t, "or a,$%.3x+x", opdp0); break;
case 0x15: sprintf(t, "or a,$%.4x+x", opw); break;
case 0x16: sprintf(t, "or a,$%.4x+y", opw); break;
case 0x17: sprintf(t, "or a,($%.3x)+y", opdp0); break;
case 0x18: sprintf(t, "or $%.3x,#$%.2x", opdp1, op0); break;
case 0x19: sprintf(t, "or (x),(y)"); break;
case 0x1a: sprintf(t, "decw $%.3x", opdp0); break;
case 0x1b: sprintf(t, "asl $%.3x+x", opdp0); break;
case 0x1c: sprintf(t, "asl a"); break;
case 0x1d: sprintf(t, "dec x"); break;
case 0x1e: sprintf(t, "cmp x,$%.4x", opw); break;
case 0x1f: sprintf(t, "jmp ($%.4x+x)", opw); break;
case 0x20: sprintf(t, "clrp"); break;
case 0x21: sprintf(t, "tcall 2"); break;
case 0x22: sprintf(t, "set1 $%.3x", opdp0); break;
case 0x23: sprintf(t, "bbs1 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x24: sprintf(t, "and a,$%.3x", opdp0); break;
case 0x25: sprintf(t, "and a,$%.4x", opw); break;
case 0x26: sprintf(t, "and a,(x)"); break;
case 0x27: sprintf(t, "and a,($%.3x+x)", opdp0); break;
case 0x28: sprintf(t, "and a,#$%.2x", op0); break;
case 0x29: sprintf(t, "and $%.3x,$%.3x", opdp1, opdp0); break;
case 0x2a: sprintf(t, "or1 c,!$%.4x:%d", opw & 0x1fff, opw >> 13); break;
case 0x2b: sprintf(t, "rol $%.3x", opdp0); break;
case 0x2c: sprintf(t, "rol $%.4x", opw); break;
case 0x2d: sprintf(t, "push a"); break;
case 0x2e: sprintf(t, "cbne $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x2f: sprintf(t, "bra $%.4x", relb(op0, 2)); break;
case 0x30: sprintf(t, "bmi $%.4x", relb(op0, 2)); break;
case 0x31: sprintf(t, "tcall 3"); break;
case 0x32: sprintf(t, "clr1 $%.3x", opdp0); break;
case 0x33: sprintf(t, "bbc1 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x34: sprintf(t, "and a,$%.3x+x", opdp0); break;
case 0x35: sprintf(t, "and a,$%.4x+x", opw); break;
case 0x36: sprintf(t, "and a,$%.4x+y", opw); break;
case 0x37: sprintf(t, "and a,($%.3x)+y", opdp0); break;
case 0x38: sprintf(t, "and $%.3x,#$%.2x", opdp1, op0); break;
case 0x39: sprintf(t, "and (x),(y)"); break;
case 0x3a: sprintf(t, "incw $%.3x", opdp0); break;
case 0x3b: sprintf(t, "rol $%.3x+x", opdp0); break;
case 0x3c: sprintf(t, "rol a"); break;
case 0x3d: sprintf(t, "inc x"); break;
case 0x3e: sprintf(t, "cmp x,$%.3x", opdp0); break;
case 0x3f: sprintf(t, "call $%.4x", opw); break;
case 0x40: sprintf(t, "setp"); break;
case 0x41: sprintf(t, "tcall 4"); break;
case 0x42: sprintf(t, "set2 $%.3x", opdp0); break;
case 0x43: sprintf(t, "bbs2 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x44: sprintf(t, "eor a,$%.3x", opdp0); break;
case 0x45: sprintf(t, "eor a,$%.4x", opw); break;
case 0x46: sprintf(t, "eor a,(x)"); break;
case 0x47: sprintf(t, "eor a,($%.3x+x)", opdp0); break;
case 0x48: sprintf(t, "eor a,#$%.2x", op0); break;
case 0x49: sprintf(t, "eor $%.3x,$%.3x", opdp1, opdp0); break;
case 0x4a: sprintf(t, "and1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break;
case 0x4b: sprintf(t, "lsr $%.3x", opdp0); break;
case 0x4c: sprintf(t, "lsr $%.4x", opw); break;
case 0x4d: sprintf(t, "push x"); break;
case 0x4e: sprintf(t, "tclr $%.4x,a", opw); break;
case 0x4f: sprintf(t, "pcall $ff%.2x", op0); break;
case 0x50: sprintf(t, "bvc $%.4x", relb(op0, 2)); break;
case 0x51: sprintf(t, "tcall 5"); break;
case 0x52: sprintf(t, "clr2 $%.3x", opdp0); break;
case 0x53: sprintf(t, "bbc2 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x54: sprintf(t, "eor a,$%.3x+x", opdp0); break;
case 0x55: sprintf(t, "eor a,$%.4x+x", opw); break;
case 0x56: sprintf(t, "eor a,$%.4x+y", opw); break;
case 0x57: sprintf(t, "eor a,($%.3x)+y", opdp0); break;
case 0x58: sprintf(t, "eor $%.3x,#$%.2x", opdp1, op0); break;
case 0x59: sprintf(t, "eor (x),(y)"); break;
case 0x5a: sprintf(t, "cmpw ya,$%.3x", opdp0); break;
case 0x5b: sprintf(t, "lsr $%.3x+x", opdp0); break;
case 0x5c: sprintf(t, "lsr a"); break;
case 0x5d: sprintf(t, "mov x,a"); break;
case 0x5e: sprintf(t, "cmp y,$%.4x", opw); break;
case 0x5f: sprintf(t, "jmp $%.4x", opw); break;
case 0x60: sprintf(t, "clrc"); break;
case 0x61: sprintf(t, "tcall 6"); break;
case 0x62: sprintf(t, "set3 $%.3x", opdp0); break;
case 0x63: sprintf(t, "bbs3 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x64: sprintf(t, "cmp a,$%.3x", opdp0); break;
case 0x65: sprintf(t, "cmp a,$%.4x", opw); break;
case 0x66: sprintf(t, "cmp a,(x)"); break;
case 0x67: sprintf(t, "cmp a,($%.3x+x)", opdp0); break;
case 0x68: sprintf(t, "cmp a,#$%.2x", op0); break;
case 0x69: sprintf(t, "cmp $%.3x,$%.3x", opdp1, opdp0); break;
case 0x6a: sprintf(t, "and1 c,!$%.4x:%d", opw & 0x1fff, opw >> 13); break;
case 0x6b: sprintf(t, "ror $%.3x", opdp0); break;
case 0x6c: sprintf(t, "ror $%.4x", opw); break;
case 0x6d: sprintf(t, "push y"); break;
case 0x6e: sprintf(t, "dbnz $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x6f: sprintf(t, "ret"); break;
case 0x70: sprintf(t, "bvs $%.4x", relb(op0, 2)); break;
case 0x71: sprintf(t, "tcall 7"); break;
case 0x72: sprintf(t, "clr3 $%.3x", opdp0); break;
case 0x73: sprintf(t, "bbc3 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x74: sprintf(t, "cmp a,$%.3x+x", opdp0); break;
case 0x75: sprintf(t, "cmp a,$%.4x+x", opw); break;
case 0x76: sprintf(t, "cmp a,$%.4x+y", opw); break;
case 0x77: sprintf(t, "cmp a,($%.3x)+y", opdp0); break;
case 0x78: sprintf(t, "cmp $%.3x,#$%.2x", opdp1, op0); break;
case 0x79: sprintf(t, "cmp (x),(y)"); break;
case 0x7a: sprintf(t, "addw ya,$%.3x", opdp0); break;
case 0x7b: sprintf(t, "ror $%.3x+x", opdp0); break;
case 0x7c: sprintf(t, "ror a"); break;
case 0x7d: sprintf(t, "mov a,x"); break;
case 0x7e: sprintf(t, "cmp y,$%.3x", opdp0); break;
case 0x7f: sprintf(t, "reti"); break;
case 0x80: sprintf(t, "setc"); break;
case 0x81: sprintf(t, "tcall 8"); break;
case 0x82: sprintf(t, "set4 $%.3x", opdp0); break;
case 0x83: sprintf(t, "bbs4 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x84: sprintf(t, "adc a,$%.3x", opdp0); break;
case 0x85: sprintf(t, "adc a,$%.4x", opw); break;
case 0x86: sprintf(t, "adc a,(x)"); break;
case 0x87: sprintf(t, "adc a,($%.3x+x)", opdp0); break;
case 0x88: sprintf(t, "adc a,#$%.2x", op0); break;
case 0x89: sprintf(t, "adc $%.3x,$%.3x", opdp1, opdp0); break;
case 0x8a: sprintf(t, "eor1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break;
case 0x8b: sprintf(t, "dec $%.3x", opdp0); break;
case 0x8c: sprintf(t, "dec $%.4x", opw); break;
case 0x8d: sprintf(t, "mov y,#$%.2x", op0); break;
case 0x8e: sprintf(t, "pop p"); break;
case 0x8f: sprintf(t, "mov $%.3x,#$%.2x", opdp1, op0); break;
case 0x90: sprintf(t, "bcc $%.4x", relb(op0, 2)); break;
case 0x91: sprintf(t, "tcall 9"); break;
case 0x92: sprintf(t, "clr4 $%.3x", opdp0); break;
case 0x93: sprintf(t, "bbc4 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x94: sprintf(t, "adc a,$%.3x+x", opdp0); break;
case 0x95: sprintf(t, "adc a,$%.4x+x", opw); break;
case 0x96: sprintf(t, "adc a,$%.4x+y", opw); break;
case 0x97: sprintf(t, "adc a,($%.3x)+y", opdp0); break;
case 0x98: sprintf(t, "adc $%.3x,#$%.2x", opdp1, op0); break;
case 0x99: sprintf(t, "adc (x),(y)"); break;
case 0x9a: sprintf(t, "subw ya,$%.3x", opdp0); break;
case 0x9b: sprintf(t, "dec $%.3x+x", opdp0); break;
case 0x9c: sprintf(t, "dec a"); break;
case 0x9d: sprintf(t, "mov x,sp"); break;
case 0x9e: sprintf(t, "div ya,x"); break;
case 0x9f: sprintf(t, "xcn a"); break;
case 0xa0: sprintf(t, "ei"); break;
case 0xa1: sprintf(t, "tcall 10"); break;
case 0xa2: sprintf(t, "set5 $%.3x", opdp0); break;
case 0xa3: sprintf(t, "bbs5 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0xa4: sprintf(t, "sbc a,$%.3x", opdp0); break;
case 0xa5: sprintf(t, "sbc a,$%.4x", opw); break;
case 0xa6: sprintf(t, "sbc a,(x)"); break;
case 0xa7: sprintf(t, "sbc a,($%.3x+x)", opdp0); break;
case 0xa8: sprintf(t, "sbc a,#$%.2x", op0); break;
case 0xa9: sprintf(t, "sbc $%.3x,$%.3x", opdp1, opdp0); break;
case 0xaa: sprintf(t, "mov1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break;
case 0xab: sprintf(t, "inc $%.3x", opdp0); break;
case 0xac: sprintf(t, "inc $%.4x", opw); break;
case 0xad: sprintf(t, "cmp y,#$%.2x", op0); break;
case 0xae: sprintf(t, "pop a"); break;
case 0xaf: sprintf(t, "mov (x)+,a"); break;
case 0xb0: sprintf(t, "bcs $%.4x", relb(op0, 2)); break;
case 0xb1: sprintf(t, "tcall 11"); break;
case 0xb2: sprintf(t, "clr5 $%.3x", opdp0); break;
case 0xb3: sprintf(t, "bbc5 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0xb4: sprintf(t, "sbc a,$%.3x+x", opdp0); break;
case 0xb5: sprintf(t, "sbc a,$%.4x+x", opw); break;
case 0xb6: sprintf(t, "sbc a,$%.4x+y", opw); break;
case 0xb7: sprintf(t, "sbc a,($%.3x)+y", opdp0); break;
case 0xb8: sprintf(t, "sbc $%.3x,#$%.2x", opdp1, op0); break;
case 0xb9: sprintf(t, "sbc (x),(y)"); break;
case 0xba: sprintf(t, "movw ya,$%.3x", opdp0); break;
case 0xbb: sprintf(t, "inc $%.3x+x", opdp0); break;
case 0xbc: sprintf(t, "inc a"); break;
case 0xbd: sprintf(t, "mov sp,x"); break;
case 0xbe: sprintf(t, "das a"); break;
case 0xbf: sprintf(t, "mov a,(x)+"); break;
case 0xc0: sprintf(t, "di"); break;
case 0xc1: sprintf(t, "tcall 12"); break;
case 0xc2: sprintf(t, "set6 $%.3x", opdp0); break;
case 0xc3: sprintf(t, "bbs6 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0xc4: sprintf(t, "mov $%.3x,a", opdp0); break;
case 0xc5: sprintf(t, "mov $%.4x,a", opw); break;
case 0xc6: sprintf(t, "mov (x),a"); break;
case 0xc7: sprintf(t, "mov ($%.3x+x),a", opdp0); break;
case 0xc8: sprintf(t, "cmp x,#$%.2x", op0); break;
case 0xc9: sprintf(t, "mov $%.4x,x", opw); break;
case 0xca: sprintf(t, "mov1 $%.4x:%d,c", opw & 0x1fff, opw >> 13); break;
case 0xcb: sprintf(t, "mov $%.3x,y", opdp0); break;
case 0xcc: sprintf(t, "mov $%.4x,y", opw); break;
case 0xcd: sprintf(t, "mov x,#$%.2x", op0); break;
case 0xce: sprintf(t, "pop x"); break;
case 0xcf: sprintf(t, "mul ya"); break;
case 0xd0: sprintf(t, "bne $%.4x", relb(op0, 2)); break;
case 0xd1: sprintf(t, "tcall 13"); break;
case 0xd2: sprintf(t, "clr6 $%.3x", opdp0); break;
case 0xd3: sprintf(t, "bbc6 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0xd4: sprintf(t, "mov $%.3x+x,a", opdp0); break;
case 0xd5: sprintf(t, "mov $%.4x+x,a", opw); break;
case 0xd6: sprintf(t, "mov $%.4x+y,a", opw); break;
case 0xd7: sprintf(t, "mov ($%.3x)+y,a", opdp0); break;
case 0xd8: sprintf(t, "mov $%.3x,x", opdp0); break;
case 0xd9: sprintf(t, "mov $%.3x+y,x", opdp0); break;
case 0xda: sprintf(t, "movw $%.3x,ya", opdp0); break;
case 0xdb: sprintf(t, "mov $%.3x+x,y", opdp0); break;
case 0xdc: sprintf(t, "dec y"); break;
case 0xdd: sprintf(t, "mov a,y"); break;
case 0xde: sprintf(t, "cbne $%.3x+x,$%.4x", opdp0, relb(op1, 3)); break;
case 0xdf: sprintf(t, "daa a"); break;
case 0xe0: sprintf(t, "clrv"); break;
case 0xe1: sprintf(t, "tcall 14"); break;
case 0xe2: sprintf(t, "set7 $%.3x", opdp0); break;
case 0xe3: sprintf(t, "bbs7 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0xe4: sprintf(t, "mov a,$%.3x", opdp0); break;
case 0xe5: sprintf(t, "mov a,$%.4x", opw); break;
case 0xe6: sprintf(t, "mov a,(x)"); break;
case 0xe7: sprintf(t, "mov a,($%.3x+x)", opdp0); break;
case 0xe8: sprintf(t, "mov a,#$%.2x", op0); break;
case 0xe9: sprintf(t, "mov x,$%.4x", opw); break;
case 0xea: sprintf(t, "not1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break;
case 0xeb: sprintf(t, "mov y,$%.3x", opdp0); break;
case 0xec: sprintf(t, "mov y,$%.4x", opw); break;
case 0xed: sprintf(t, "notc"); break;
case 0xee: sprintf(t, "pop y"); break;
case 0xef: sprintf(t, "sleep"); break;
case 0xf0: sprintf(t, "beq $%.4x", relb(op0, 2)); break;
case 0xf1: sprintf(t, "tcall 15"); break;
case 0xf2: sprintf(t, "clr7 $%.3x", opdp0); break;
case 0xf3: sprintf(t, "bbc7 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0xf4: sprintf(t, "mov a,$%.3x+x", opdp0); break;
case 0xf5: sprintf(t, "mov a,$%.4x+x", opw); break;
case 0xf6: sprintf(t, "mov a,$%.4x+y", opw); break;
case 0xf7: sprintf(t, "mov a,($%.3x)+y", opdp0); break;
case 0xf8: sprintf(t, "mov x,$%.3x", opdp0); break;
case 0xf9: sprintf(t, "mov x,$%.3x+y", opdp0); break;
case 0xfa: sprintf(t, "mov $%.3x,$%.3x", opdp1, opdp0); break;
case 0xfb: sprintf(t, "mov y,$%.3x+x", opdp0); break;
case 0xfc: sprintf(t, "inc y"); break;
case 0xfd: sprintf(t, "mov y,a"); break;
case 0xfe: sprintf(t, "dbnz y,$%.4x", relb(op0, 2)); break;
case 0xff: sprintf(t, "stop"); break;
}
t[strlen(t)] = ' ';
strcat(s, t);
sprintf(t, "A:%.2x X:%.2x Y:%.2x SP:01%.2x YA:%.4x ",
regs.a, regs.x, regs.y, regs.sp, (uint16)regs.ya);
strcat(s, t);
sprintf(t, "%c%c%c%c%c%c%c%c",
regs.p.n ? 'N' : 'n',
regs.p.v ? 'V' : 'v',
regs.p.p ? 'P' : 'p',
regs.p.b ? 'B' : 'b',
regs.p.h ? 'H' : 'h',
regs.p.i ? 'I' : 'i',
regs.p.z ? 'Z' : 'z',
regs.p.c ? 'C' : 'c');
strcat(s, t);
}

44
bsnes/snes/alt/smp/iplrom.cpp Executable file
View File

@ -0,0 +1,44 @@
#ifdef SMP_CPP
//this is the IPLROM for the S-SMP coprocessor.
//the S-SMP does not allow writing to the IPLROM.
//all writes are instead mapped to the extended
//RAM region, accessible when $f1.d7 is clear.
const uint8 SMP::iplrom[64] = {
/*ffc0*/ 0xcd, 0xef, //mov x,#$ef
/*ffc2*/ 0xbd, //mov sp,x
/*ffc3*/ 0xe8, 0x00, //mov a,#$00
/*ffc5*/ 0xc6, //mov (x),a
/*ffc6*/ 0x1d, //dec x
/*ffc7*/ 0xd0, 0xfc, //bne $ffc5
/*ffc9*/ 0x8f, 0xaa, 0xf4, //mov $f4,#$aa
/*ffcc*/ 0x8f, 0xbb, 0xf5, //mov $f5,#$bb
/*ffcf*/ 0x78, 0xcc, 0xf4, //cmp $f4,#$cc
/*ffd2*/ 0xd0, 0xfb, //bne $ffcf
/*ffd4*/ 0x2f, 0x19, //bra $ffef
/*ffd6*/ 0xeb, 0xf4, //mov y,$f4
/*ffd8*/ 0xd0, 0xfc, //bne $ffd6
/*ffda*/ 0x7e, 0xf4, //cmp y,$f4
/*ffdc*/ 0xd0, 0x0b, //bne $ffe9
/*ffde*/ 0xe4, 0xf5, //mov a,$f5
/*ffe0*/ 0xcb, 0xf4, //mov $f4,y
/*ffe2*/ 0xd7, 0x00, //mov ($00)+y,a
/*ffe4*/ 0xfc, //inc y
/*ffe5*/ 0xd0, 0xf3, //bne $ffda
/*ffe7*/ 0xab, 0x01, //inc $01
/*ffe9*/ 0x10, 0xef, //bpl $ffda
/*ffeb*/ 0x7e, 0xf4, //cmp y,$f4
/*ffed*/ 0x10, 0xeb, //bpl $ffda
/*ffef*/ 0xba, 0xf6, //movw ya,$f6
/*fff1*/ 0xda, 0x00, //movw $00,ya
/*fff3*/ 0xba, 0xf4, //movw ya,$f4
/*fff5*/ 0xc4, 0xf4, //mov $f4,a
/*fff7*/ 0xdd, //mov a,y
/*fff8*/ 0x5d, //mov x,a
/*fff9*/ 0xd0, 0xdb, //bne $ffd6
/*fffb*/ 0x1f, 0x00, 0x00, //jmp ($0000+x)
/*fffe*/ 0xc0, 0xff //reset vector location ($ffc0)
};
#endif

130
bsnes/snes/alt/smp/memory.cpp Executable file
View File

@ -0,0 +1,130 @@
unsigned SMP::port_read(unsigned addr) {
return apuram[0xf4 + (addr & 3)];
}
void SMP::port_write(unsigned addr, unsigned data) {
apuram[0xf4 + (addr & 3)] = data;
}
unsigned SMP::mmio_read(unsigned addr) {
switch(addr) {
case 0xf2:
return status.dsp_addr;
case 0xf3:
return dsp.read(status.dsp_addr & 0x7f);
case 0xf4:
case 0xf5:
case 0xf6:
case 0xf7:
synchronize_cpu();
return cpu.port_read(addr);
case 0xf8:
return status.ram00f8;
case 0xf9:
return status.ram00f9;
case 0xfd: {
unsigned result = timer0.stage3_ticks & 15;
timer0.stage3_ticks = 0;
return result;
}
case 0xfe: {
unsigned result = timer1.stage3_ticks & 15;
timer1.stage3_ticks = 0;
return result;
}
case 0xff: {
unsigned result = timer2.stage3_ticks & 15;
timer2.stage3_ticks = 0;
return result;
}
}
return 0x00;
}
void SMP::mmio_write(unsigned addr, unsigned data) {
switch(addr) {
case 0xf1:
status.iplrom_enable = data & 0x80;
if(data & 0x30) {
synchronize_cpu();
if(data & 0x20) {
cpu.port_write(3, 0x00);
cpu.port_write(2, 0x00);
}
if(data & 0x10) {
cpu.port_write(1, 0x00);
cpu.port_write(0, 0x00);
}
}
if(timer2.enable == false && (data & 0x04)) {
timer2.stage2_ticks = 0;
timer2.stage3_ticks = 0;
}
timer2.enable = data & 0x04;
if(timer1.enable == false && (data & 0x02)) {
timer1.stage2_ticks = 0;
timer1.stage3_ticks = 0;
}
timer1.enable = data & 0x02;
if(timer0.enable == false && (data & 0x01)) {
timer0.stage2_ticks = 0;
timer0.stage3_ticks = 0;
}
timer0.enable = data & 0x01;
break;
case 0xf2:
status.dsp_addr = data;
break;
case 0xf3:
if(status.dsp_addr & 0x80) break;
dsp.write(status.dsp_addr, data);
break;
case 0xf4:
case 0xf5:
case 0xf6:
case 0xf7:
synchronize_cpu();
port_write(addr, data);
break;
case 0xf8:
status.ram00f8 = data;
break;
case 0xf9:
status.ram00f9 = data;
break;
case 0xfa:
timer0.target = data;
break;
case 0xfb:
timer1.target = data;
break;
case 0xfc:
timer2.target = data;
break;
}
}

100
bsnes/snes/alt/smp/smp.cpp Executable file
View File

@ -0,0 +1,100 @@
#include <snes/snes.hpp>
#define SMP_CPP
namespace SNES {
#if defined(DEBUGGER)
#include "debugger/debugger.cpp"
SMPDebugger smp;
#else
SMP smp;
#endif
#include "algorithms.cpp"
#include "core.cpp"
#include "disassembler.cpp"
#include "iplrom.cpp"
#include "memory.cpp"
#include "timing.cpp"
void SMP::step(unsigned clocks) {
clock += clocks * (uint64)cpu.frequency;
dsp.clock -= clocks;
synchronize_dsp();
}
void SMP::synchronize_cpu() {
if(CPU::Threaded == true) {
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
} else {
//while(clock >= 0) cpu.enter();
}
}
void SMP::synchronize_dsp() {
if(DSP::Threaded == true) {
if(dsp.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(dsp.thread);
} else {
while(dsp.clock < 0) dsp.enter();
}
}
void SMP::enter() {
op_step();
}
void SMP::power() {
Processor::frequency = system.apu_frequency() / 24;
Processor::clock = 0;
timer0.target = 0;
timer1.target = 0;
timer2.target = 0;
reset();
}
void SMP::reset() {
for(unsigned n = 0x0000; n <= 0xffff; n++) apuram[n] = 0x00;
regs.pc = 0xffc0;
regs.sp = 0x00ef;
regs.a = 0x00;
regs.x = 0x00;
regs.y = 0x00;
regs.p = 0x02;
//timing
status.clock_counter = 0;
status.dsp_counter = 0;
status.timer_step = 3;
//$00f0
status.clock_speed = 0;
status.timer_speed = 0;
status.timers_enable = true;
status.ram_disable = false;
status.ram_writable = true;
status.timers_disable = false;
//$00f1
status.iplrom_enable = true;
//$00f2
status.dsp_addr = 0x00;
//$00f8,$00f9
status.ram00f8 = 0x00;
status.ram00f9 = 0x00;
}
void SMP::serialize(serializer &s) {
}
SMP::SMP() {
}
SMP::~SMP() {
}
}

110
bsnes/snes/alt/smp/smp.hpp Executable file
View File

@ -0,0 +1,110 @@
class SMP : public Processor {
public:
static const uint8 iplrom[64];
uint8 apuram[64 * 1024];
enum : bool { Threaded = false };
alwaysinline void step(unsigned clocks);
alwaysinline void synchronize_cpu();
alwaysinline void synchronize_dsp();
unsigned port_read(unsigned port);
void port_write(unsigned port, unsigned data);
void enter();
void power();
void reset();
void serialize(serializer&);
SMP();
~SMP();
#include "core.hpp"
struct Flags {
bool n, v, p, b, h, i, z, c;
alwaysinline operator unsigned() const {
return (n << 7) | (v << 6) | (p << 5) | (b << 4)
| (h << 3) | (i << 2) | (z << 1) | (c << 0);
};
alwaysinline unsigned operator=(unsigned data) {
n = data & 0x80; v = data & 0x40; p = data & 0x20; b = data & 0x10;
h = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01;
}
alwaysinline unsigned operator|=(unsigned data) { return operator=(operator unsigned() | data); }
alwaysinline unsigned operator^=(unsigned data) { return operator=(operator unsigned() ^ data); }
alwaysinline unsigned operator&=(unsigned data) { return operator=(operator unsigned() & data); }
};
struct Regs {
uint16 pc;
uint16 sp;
union {
uint16 ya;
struct { uint8 order_lsb2(a, y); };
};
uint8 x;
Flags p;
} regs;
struct Status {
//timing
unsigned clock_counter;
unsigned dsp_counter;
unsigned timer_step;
//$00f0
unsigned clock_speed;
unsigned timer_speed;
bool timers_enable;
bool ram_disable;
bool ram_writable;
bool timers_disable;
//$00f1
bool iplrom_enable;
//$00f2
unsigned dsp_addr;
//$00f8,$00f9
unsigned ram00f8;
unsigned ram00f9;
} status;
template<unsigned frequency>
struct Timer {
unsigned stage0_ticks;
unsigned stage1_ticks;
unsigned stage2_ticks;
unsigned stage3_ticks;
bool current_line;
bool enable;
unsigned target;
void tick();
void synchronize();
};
Timer<192> timer0;
Timer<192> timer1;
Timer< 24> timer2;
unsigned mmio_read(unsigned addr);
void mmio_write(unsigned addr, unsigned data);
//disassembler
void disassemble_opcode(char *output, uint16 addr);
inline uint8 disassemble_read(uint16 addr);
inline uint16 relb(int8 offset, int op_len);
};
#if defined(DEBUGGER)
#include "debugger/debugger.hpp"
extern SMPDebugger smp;
#else
extern SMP smp;
#endif

29
bsnes/snes/alt/smp/timing.cpp Executable file
View File

@ -0,0 +1,29 @@
template<unsigned timer_frequency>
void SMP::Timer<timer_frequency>::tick() {
//stage 0 increment
stage0_ticks += smp.status.timer_step;
if(stage0_ticks < timer_frequency) return;
stage0_ticks -= timer_frequency;
//stage 1 increment
stage1_ticks ^= 1;
synchronize();
}
template<unsigned timer_frequency>
void SMP::Timer<timer_frequency>::synchronize() {
bool new_line = stage1_ticks;
bool old_line = current_line;
current_line = new_line;
if(old_line != 1 || new_line != 0) return; //only pulse on 1->0 transition
//stage 2 increment
if(enable == false) return;
stage2_ticks++;
if(stage2_ticks != target) return;
//stage 3 increment
stage2_ticks = 0;
stage3_ticks++;
stage3_ticks &= 15;
}

View File

@ -3,6 +3,6 @@ namespace Info {
}
#include <snes/alt/cpu/cpu.hpp>
#include <snes/smp/smp.hpp>
#include <snes/alt/smp/smp.hpp>
#include <snes/alt/dsp/dsp.hpp>
#include <snes/alt/ppu-performance/ppu.hpp>

View File

@ -55,14 +55,14 @@ bool SMPDebugger::property(unsigned id, string &name, string &value) {
//$00f0
item("$00f0", "");
item("Clock Speed", (unsigned)status.clock_speed);
item("Timers Enable", status.timers_enabled);
item("RAM Disable", status.ram_disabled);
item("Timers Enable", status.timers_enable);
item("RAM Disable", status.ram_disable);
item("RAM Writable", status.ram_writable);
item("Timers Disable", status.timers_disabled);
item("Timers Disable", status.timers_disable);
//$00f1
item("$00f1", "");
item("IPLROM Enable", status.iplrom_enabled);
item("IPLROM Enable", status.iplrom_enable);
//$00f2
item("$00f2", "");

View File

@ -1,14 +1,14 @@
#ifdef SMP_CPP
alwaysinline uint8 SMP::ram_read(uint16 addr) {
if(addr >= 0xffc0 && status.iplrom_enabled) return iplrom[addr & 0x3f];
if(status.ram_disabled) return 0x5a; //0xff on mini-SNES
if(addr >= 0xffc0 && status.iplrom_enable) return iplrom[addr & 0x3f];
if(status.ram_disable) return 0x5a; //0xff on mini-SNES
return apuram[addr];
}
alwaysinline void SMP::ram_write(uint16 addr, uint8 data) {
//writes to $ffc0-$ffff always go to apuram, even if the iplrom is enabled
if(status.ram_writable && !status.ram_disabled) apuram[addr] = data;
if(status.ram_writable && !status.ram_disable) apuram[addr] = data;
}
uint8 SMP::port_read(uint2 port) const {
@ -49,11 +49,11 @@ alwaysinline uint8 SMP::op_busread(uint16 addr) {
} break;
case 0xf8: { //RAM0
r = status.ram0;
r = status.ram00f8;
} break;
case 0xf9: { //RAM1
r = status.ram1;
r = status.ram00f9;
} break;
case 0xfa: //T0TARGET
@ -90,12 +90,12 @@ alwaysinline void SMP::op_buswrite(uint16 addr, uint8 data) {
case 0xf0: { //TEST
if(regs.p.p) break; //writes only valid when P flag is clear
status.clock_speed = (data >> 6) & 3;
status.timer_speed = (data >> 4) & 3;
status.timers_enabled = data & 0x08;
status.ram_disabled = data & 0x04;
status.ram_writable = data & 0x02;
status.timers_disabled = data & 0x01;
status.clock_speed = (data >> 6) & 3;
status.timer_speed = (data >> 4) & 3;
status.timers_enable = data & 0x08;
status.ram_disable = data & 0x04;
status.ram_writable = data & 0x02;
status.timers_disable = data & 0x01;
status.timer_step = (1 << status.clock_speed) + (2 << status.timer_speed);
@ -105,7 +105,7 @@ alwaysinline void SMP::op_buswrite(uint16 addr, uint8 data) {
} break;
case 0xf1: { //CONTROL
status.iplrom_enabled = data & 0x80;
status.iplrom_enable = data & 0x80;
if(data & 0x30) {
//one-time clearing of APU port read registers,
@ -161,11 +161,11 @@ alwaysinline void SMP::op_buswrite(uint16 addr, uint8 data) {
} break;
case 0xf8: { //RAM0
status.ram0 = data;
status.ram00f8 = data;
} break;
case 0xf9: { //RAM1
status.ram1 = data;
status.ram00f9 = data;
} break;
case 0xfa: { //T0TARGET

View File

@ -12,17 +12,17 @@ void SMP::serialize(serializer &s) {
s.integer(status.clock_speed);
s.integer(status.timer_speed);
s.integer(status.timers_enabled);
s.integer(status.ram_disabled);
s.integer(status.timers_enable);
s.integer(status.ram_disable);
s.integer(status.ram_writable);
s.integer(status.timers_disabled);
s.integer(status.timers_disable);
s.integer(status.iplrom_enabled);
s.integer(status.iplrom_enable);
s.integer(status.dsp_addr);
s.integer(status.ram0);
s.integer(status.ram1);
s.integer(status.ram00f8);
s.integer(status.ram00f9);
s.integer(t0.stage0_ticks);
s.integer(t0.stage1_ticks);

View File

@ -80,20 +80,20 @@ void SMP::reset() {
//$00f0
status.clock_speed = 0;
status.timer_speed = 0;
status.timers_enabled = true;
status.ram_disabled = false;
status.timers_enable = true;
status.ram_disable = false;
status.ram_writable = true;
status.timers_disabled = false;
status.timers_disable = false;
//$00f1
status.iplrom_enabled = true;
status.iplrom_enable = true;
//$00f2
status.dsp_addr = 0x00;
//$00f8,$00f9
status.ram0 = 0x00;
status.ram1 = 0x00;
status.ram00f8 = 0x00;
status.ram00f9 = 0x00;
t0.stage0_ticks = 0;
t1.stage0_ticks = 0;

View File

@ -32,20 +32,20 @@ private:
//$00f0
uint8 clock_speed;
uint8 timer_speed;
bool timers_enabled;
bool ram_disabled;
bool timers_enable;
bool ram_disable;
bool ram_writable;
bool timers_disabled;
bool timers_disable;
//$00f1
bool iplrom_enabled;
bool iplrom_enable;
//$00f2
uint8 dsp_addr;
//$00f8,$00f9
uint8 ram0;
uint8 ram1;
uint8 ram00f8;
uint8 ram00f9;
} status;
static void Enter();

View File

@ -39,8 +39,8 @@ void SMP::sSMPTimer<timer_frequency>::tick() {
template<unsigned frequency>
void SMP::sSMPTimer<frequency>::sync_stage1() {
bool new_line = stage1_ticks;
if(smp.status.timers_enabled == false) new_line = false;
if(smp.status.timers_disabled == true) new_line = false;
if(smp.status.timers_enable == false) new_line = false;
if(smp.status.timers_disable == true) new_line = false;
bool old_line = current_line;
current_line = new_line;

View File

@ -1,7 +1,7 @@
namespace SNES {
namespace Info {
static const char Name[] = "bsnes";
static const char Version[] = "078";
static const char Version[] = "078.01";
static const unsigned SerializerVersion = 19;
}
}

View File

@ -14,7 +14,7 @@ struct Interface : public SNES::Interface {
void video_refresh(const uint16_t *data, bool hires, bool interlace, bool overscan) {
unsigned width = hires ? 512 : 256;
unsigned height = overscan ? 224 : 239;
unsigned height = overscan ? 239 : 224;
if(interlace) height <<= 1;
data += 9 * 1024; //skip front porch
if(pvideo_refresh) return pvideo_refresh(data, width, height);