mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
0a3d6e4c53
commit
9a3650c6ab
|
@ -5,7 +5,7 @@ profile := accuracy
|
|||
ui := ui
|
||||
|
||||
# debugger
|
||||
options :=
|
||||
options := debugger
|
||||
|
||||
# compiler
|
||||
c := $(compiler) -std=gnu99
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
};
|
|
@ -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);
|
|
@ -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
|
|
@ -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();
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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", "");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue