more opcodes, better loop function

This commit is contained in:
'mr software' 2022-03-13 19:12:17 -07:00
parent e2ea5d84c8
commit 5160605711
5 changed files with 167 additions and 90 deletions

View File

@ -6,17 +6,15 @@ SNES emulator for awful people
you know how zsnes 0.150 is all kinds of awful? i want an emulator that is accurate enough to run most games, but is completely crippled in sound and video. i want to scream. i want to scream, and i want to be able to say it's my own damn fault you know how zsnes 0.150 is all kinds of awful? i want an emulator that is accurate enough to run most games, but is completely crippled in sound and video. i want to scream. i want to scream, and i want to be able to say it's my own damn fault
ultimately it will let you use proper emulation but it primarily serves to suck badly and will let you do stuff like mess with data and address lines or disable audio/video features or emulate old zsnes audio because it sounds lovely
## What's wrong with you? ## What's wrong with you?
wish i knew wish i knew
## How do I play games in it? ## How do I play games in it?
i ask myself this too! wish i knew
short answer: thats the neat thing. you dont
long answer: build layla and create an instruction decode loop, write a memory remapper, and implement 96% of the opcodes in the 65816 emulator. next, create an emulator for the ricoh 5a22 extensions, the spc700, and the s-ppu. finally, send me your code because you just made an entire emulator! congratulations! you can play any game without expansion chips!
## What's the name mean? ## What's the name mean?

7
dsp/dsp.c Normal file
View File

@ -0,0 +1,7 @@
int dsp_eval(sdsp* d) {
}
int dsp_loop(sdsp* d) {
}

4
spencer/inf Executable file
View File

@ -0,0 +1,4 @@
NUMREM=$(($(grep OPCL -A256 ~/projects/snezzy/spencer/opcodes | wc -l)-1))
PERCREM=$(echo "scale=4; $NUMREM/2.56" | bc)
[ ! -z "$1" ] && grep -A256 OPCL ~/projects/snezzy/spencer/opcodes | grep -E "$1" | nvim
echo $((256-$NUMREM)) done, $NUMREM remaining "($(echo scale=4\; 100-$PERCREM | bc)% done, $PERCREM% remaining)"

View File

@ -6,15 +6,6 @@
// needs printf // needs printf
#include <stdio.h> #include <stdio.h>
void spc_init(spc_cpu* s, void* mem, uint8_t(*mmr)(spc_cpu*, uint8_t, uint8_t, uint8_t), void(*stop)(spc_cpu*)) {
if(!mmr || !stop) return; // just dont initialize. bad data in, bad data out
memset(s, 0, sizeof(spc_cpu));
s->mmr = (uint8_t(*)(void*, uint8_t, uint8_t, uint8_t))mmr;
s->mem = mem;
s->stop = (void(*)(void*))stop;
s->initialized = 0x59C700;
}
const uint8_t spc_ipl[0x40] = { const uint8_t spc_ipl[0x40] = {
0xCD, 0xEF, 0xBD, 0xE8, 0x00, 0xC6, 0x1D, 0xD0, 0xFC, 0x8F, 0xAA, 0xF4, 0x8F, 0xBB, 0xF5, 0x78, 0xCD, 0xEF, 0xBD, 0xE8, 0x00, 0xC6, 0x1D, 0xD0, 0xFC, 0x8F, 0xAA, 0xF4, 0x8F, 0xBB, 0xF5, 0x78,
0xCC, 0xF4, 0xD0, 0xFB, 0x2F, 0x19, 0xEB, 0xF4, 0xD0, 0xFC, 0x7E, 0xF4, 0xD0, 0x0B, 0xE4, 0xF5, 0xCC, 0xF4, 0xD0, 0xFB, 0x2F, 0x19, 0xEB, 0xF4, 0xD0, 0xFC, 0x7E, 0xF4, 0xD0, 0x0B, 0xE4, 0xF5,
@ -22,16 +13,24 @@ const uint8_t spc_ipl[0x40] = {
0xF6, 0xDA, 0x00, 0xBA, 0xF4, 0xC4, 0xF4, 0xDD, 0x5D, 0xD0, 0xDB, 0x1F, 0x00, 0x00, 0xC0, 0xFF 0xF6, 0xDA, 0x00, 0xBA, 0xF4, 0xC4, 0xF4, 0xDD, 0x5D, 0xD0, 0xDB, 0x1F, 0x00, 0x00, 0xC0, 0xFF
}; };
uint8_t spc_r(spc_cpu* s, uint16_t p) { void spc_init(spc_cpu* s, void* mem, uint8_t(*mmr)(spc_cpu*, uint8_t, uint8_t, uint8_t), void(*stop)(spc_cpu*)) {
if((p >= 0xF0 && p <= 0xF7) || (p >= 0xFA && p <= 0xFF)) return s->mmr(s, p - 0xF0, 0, S_R); if(!mmr || !stop) return; // just dont initialize. bad data in, bad data out
//if((p >= 0xF0 && p <= 0xF7) || (p >= 0xFA && p <= 0xFF)) {uint8_t i = s->mmr(s, p - 0xF0, 0, S_R);printf("MMR %02X\n", i);return i;} memset(s, 0, sizeof(spc_cpu));
if(p >= 0xFFC0 && s->mmr(s, 0xF1, 0, S_R|S_I) >> 7) return spc_ipl[p - 0xFFC0]; s->mmr = (uint8_t(*)(void*, uint8_t, uint8_t, uint8_t))mmr;
return s->mem[p]; s->mem = mem;
s->stop = (void(*)(void*))stop;
s->PC = 0xFFC0;
s->wait = *spc_ipl;
s->initialized = 0x59C700;
} }
uint8_t spc_intr(spc_cpu* s, uint16_t p) { #define spc_r(s, p) spc_vr(s, p, 0)
if((p >= 0xF0 && p <= 0xF7) || (p >= 0xFA && p <= 0xFF)) return s->mmr(s, p - 0xF0, 0, S_R|S_I); #define spc_ir(s, p) spc_vr(s, p, S_I)
return spc_r(s, p);
uint8_t spc_vr(spc_cpu* s, uint16_t p, uint8_t f) {
if((p >= 0xF0 && p <= 0xF7) || (p >= 0xFA && p <= 0xFF)) return s->mmr(s, p - 0xF0, 0, S_R | f);
if(p >= 0xFFC0 && s->mmr(s, 0xF1, 0, S_R | S_I) >> 7) return spc_ipl[p - 0xFFC0];
return s->mem[p];
} }
void spc_w(spc_cpu* s, uint16_t p, uint8_t d) { void spc_w(spc_cpu* s, uint16_t p, uint8_t d) {
@ -69,27 +68,25 @@ void spc_w(spc_cpu* s, uint16_t p, uint8_t d) {
#define spc_sbn(c, d) c->P = (c->P & 0x7F) | (d & 0x80) #define spc_sbn(c, d) c->P = (c->P & 0x7F) | (d & 0x80)
#define spc_sbz(c, d) c->P = (c->P & 0xFD) | (!d << 1) #define spc_sbz(c, d) c->P = (c->P & 0xFD) | (!d << 1)
#define spc_inc(c, d) d++; spc_sbn(c, d); spc_sbz(c, d) #define spc_sbnz(c, d) spc_sbn(c, d); spc_sbz(c, d)
#define spc_dec(c, d) d--; spc_sbn(c, d); spc_sbz(c, d)
#define spc_trans(c, a, b) a = b; spc_sbn(c, a); spc_sbz(c, a) #define spc_inc(c, d) d++; spc_sbnz(c, d)
#define spc_dec(c, d) d--; spc_sbnz(c, d)
// this is bad
#define spc_im8(C, O) (spc_r(C, C->PC + 1 + O)) #define spc_im8(C, O) (spc_r(C, C->PC + 1 + O))
#define spc_im16(C) spc_r16(s, C->PC+1)
#define spc_dp(C, O) ((((uint16_t)spc_getp(C)) << 8) | (uint8_t)(O))
// this is not okay #define spc_sp(C, O) (0x100 | (uint8_t)(O))
#define spc_im16(C) ((((uint16_t)spc_im8(C, 1)) << 8) | spc_im8(C, 0))
// with code like this all these opcodes are illegal opcodes
#define spc_dp(C, O) ((((uint16_t)spc_getp(C)) << 8) | (uint8_t)O)
#define spc_sp(C, O) (0x100 | (uint8_t)O)
#define spc_push(C, O) spc_w(C, 0x100 + ((uint8_t)C->SP--), O) #define spc_push(C, O) spc_w(C, 0x100 + ((uint8_t)C->SP--), O)
#define spc_push16(C, O) spc_push(C, O >> 8); spc_push(C, O); #define spc_push16(C, O) spc_push(C, O >> 8); spc_push(C, O)
#define spc_pull(C) spc_r(C, C->SP++) #define spc_pull(C) spc_r(C, C->SP++)
#define spc_or(C, A, B) A |= B; spc_sbnz(C, A)
uint16_t spc_pull16(spc_cpu* s) { uint16_t spc_pull16(spc_cpu* s) {
uint16_t c = spc_pull(s); uint16_t c = spc_pull(s);
return c | ((uint16_t)spc_pull(s) << 8); return c | ((uint16_t)spc_pull(s) << 8);
@ -97,10 +94,22 @@ uint16_t spc_pull16(spc_cpu* s) {
#define spc_setbf(C, S) C |= (1 << S) #define spc_setbf(C, S) C |= (1 << S)
#define spc_unsetbf(C, S) C &= ~(1 << S) #define spc_unsetbf(C, S) C &= ~(1 << S)
#define spc_getbf(C, S) ((C >> S) & 1)
#define spc_branch(C, O) s->PC += (int8_t)spc_im8(C, O) #define spc_branch(C, O) s->PC += (int8_t)spc_im8(C, O)
typedef struct {
uint16_t adr;
uint8_t bit;
} spc_mb;
#define spc_splitmb(O) ((spc_mb){O & 0x1FFF, O >> 13})
#define spc_getya(C) = ((uint16_t)C->A | (((uint16_t)C->Y) << 8))
// cool guy macros
#define spc_getbf(C, S) ((C >> S) & 1)
#define spc_trans(c, a, b) a = b; spc_sbnz(c, a)
uint16_t spc_r16(spc_cpu* s, uint16_t p) { uint16_t spc_r16(spc_cpu* s, uint16_t p) {
uint16_t d = spc_r(s, p++); uint16_t d = spc_r(s, p++);
return (d << 8) | spc_r(s, p); return (d << 8) | spc_r(s, p);
@ -148,6 +157,9 @@ uint8_t spc_len[256] = {
}; };
void spc_eval(spc_cpu* s, int* d, uint8_t opcode) { void spc_eval(spc_cpu* s, int* d, uint8_t opcode) {
uint8_t ri;
uint16_t adr;
spc_mb mb;
if((opcode & 0xF) == 1) { // tcall (0x*1) if((opcode & 0xF) == 1) { // tcall (0x*1)
spc_push16(s, s->PC); spc_push16(s, s->PC);
// should be xFFDE, but spc_len adds 3 to // should be xFFDE, but spc_len adds 3 to
@ -159,10 +171,26 @@ void spc_eval(spc_cpu* s, int* d, uint8_t opcode) {
if(opcode & 0x10) spc_unsetbf(b, opcode >> 5); if(opcode & 0x10) spc_unsetbf(b, opcode >> 5);
else spc_setbf(b, opcode >> 5); else spc_setbf(b, opcode >> 5);
spc_w(s, spc_dp(s, spc_im8(s, 0)), b); spc_w(s, spc_dp(s, spc_im8(s, 0)), b);
} else if(!(opcode & 0x0F) && (opcode & 0x10) && opcode <= 0x70) { } else if((opcode << 3) == 0x80) {
// bpl (x10), bmi (x30), bvc (x50), bvs (x70) // - GUIDE - reg !if opcode id
uint8_t conflags[4] = {!spc_getn(s), spc_getn(s), !spc_getv(s), spc_getv(s)}; // bpl (x10), 00 0 10000
if(conflags[opcode >> 5]) spc_branch(s, 0); // bmi (x30), 00 1 10000
//
// bvc (x50), 01 0 10000
// bvs (x70), 01 1 10000
//
// bcc (x90), 10 0 10000
// bcs (xB0), 10 1 10000
//
// bne (xD0), 11 0 10000
// beq (xF0), 11 1 10000
uint8_t conflags[4] = {spc_getn(s), spc_getv(s), spc_getc(s), spc_getz(s)};
if(conflags[opcode >> 6] & spc_getbf(opcode, 5)) spc_branch(s, 0);
} else if((opcode & 0x1F) == 0xA && opcode <= 0x6A) {
mb = spc_splitmb(spc_im16(s));
ri = spc_getbf(spc_r(s, mb.adr), mb.bit) ^ spc_getbf(opcode, 6);
if(opcode & 0x40) s->P |= ri;
else s->P &= ri;
} else if((opcode & 0x0F) == 3) { } else if((opcode & 0x0F) == 3) {
uint8_t set = spc_getbf(spc_r(s, spc_im8(s, 0)), opcode >> 5); uint8_t set = spc_getbf(spc_r(s, spc_im8(s, 0)), opcode >> 5);
if((opcode & 0x10) && !set) goto br; if((opcode & 0x10) && !set) goto br;
@ -182,6 +210,19 @@ nobr:
} else switch(opcode) { } else switch(opcode) {
case 0x00: case 0x00:
break; break;
case 0x04:
spc_or(s, s->A, spc_r(s, spc_dp(s, spc_im8(s, 0))));
break;
case 0x05:
spc_or(s, s->A, spc_r(s, spc_im16(s)));
break;
case 0x0F:
spc_push16(s, s->PC);
spc_push(s, s->P);
s->PC = 0xFFDD;
s->P |= 0x10;
s->P &= 0xFB;
break;
case 0x1D: case 0x1D:
spc_dec(s, s->X); spc_dec(s, s->X);
break; break;
@ -214,39 +255,103 @@ nobr:
case 0x6F: case 0x6F:
s->PC = spc_pull16(s) - 1; s->PC = spc_pull16(s) - 1;
break; break;
case 0x7D:
spc_trans(s, s->A, s->X);
break;
case 0x7F:
s->P = spc_pull(s);
s->PC = spc_pull16(s) - 1;
break;
case 0x80: case 0x80:
spc_setc(s); spc_setc(s);
break; break;
case 0x8A:
adr = spc_im16(s);
spc_mb mb = spc_splitmb(adr);
s->P ^= spc_getbf(spc_r(s, mb.adr), mb.bit);
break;
case 0x8B:
adr = spc_dp(s, spc_im8(s, 0));
ri = spc_r(s, adr) - 1;
spc_w(s, adr, ri);
spc_sbnz(s, ri);
break;
case 0x8C:
adr = spc_im16(s);
ri = spc_r(s, adr) - 1;
spc_w(s, adr, ri);
spc_sbnz(s, ri);
break;
case 0x8D:
spc_trans(s, s->Y, spc_im8(s, 0));
break;
case 0x9B:
adr = spc_dp(s, spc_im8(s, 0) + s->X);
ri = spc_r(s, adr) - 1;
spc_w(s, adr, ri);
spc_sbnz(s, ri);
break;
case 0x9C:
spc_dec(s, s->A);
break;
case 0x9D:
spc_trans(s, s->X, s->SP);
break;
case 0x9F: case 0x9F:
s->A = (s->A >> 4) | (s-> A << 4); s->A = (s->A >> 4) | (s->A << 4);
spc_sbn(s, s->A); spc_sbn(s, s->A);
spc_sbz(s, s->A); spc_sbz(s, s->A);
break; break;
case 0xA0: case 0xA0:
spc_seti(s); spc_seti(s);
break; break;
case 0xAA:
adr = spc_im16(s);
mb = spc_splitmb(adr);
s->P = (s->P & 0xFE) | (spc_getbf(spc_r(s, mb.adr), mb.bit));
break;
case 0xBC: case 0xBC:
spc_inc(s, s->A); spc_inc(s, s->A);
break; break;
case 0xBD:
spc_trans(s, s->SP, s->X);
break;
case 0xC0: case 0xC0:
spc_unseti(s); spc_unseti(s);
break; break;
case 0xD0: case 0xCA:
if(!spc_getz(s)) spc_branch(s, 0); adr = spc_im16(s);
mb = spc_splitmb(adr);
spc_w(s, mb.adr, (spc_r(s, mb.adr) & ~(1 << mb.bit)) | (spc_getc(s) << mb.bit));
break;
case 0xCD:
spc_trans(s, s->X, spc_im8(s, 0));
break;
case 0xDC:
spc_dec(s, s->Y);
break;
case 0xDD:
spc_trans(s, s->A, s->Y);
break; break;
case 0xE0: case 0xE0:
spc_unsetv(s); spc_unsetv(s);
spc_unseth(s); spc_unseth(s);
break; break;
case 0xE8:
spc_trans(s, s->A, spc_im8(s, 0));
break;
case 0xEA:
adr = spc_im16(s);
mb = spc_splitmb(adr);
spc_w(s, mb.adr, spc_r(s, mb.adr) ^ (1 << mb.bit));
break;
case 0xED: case 0xED:
s->P ^= 1; s->P ^= 1;
break; break;
case 0xEF: case 0xEF:
s->stp = 0xEF;
s->stop(s); s->stop(s);
break; break;
case 0xF0:
if(spc_getz(s)) spc_branch(s, 0);
break;
case 0xFC: case 0xFC:
spc_inc(s, s->Y); spc_inc(s, s->Y);
break; break;
@ -255,6 +360,7 @@ nobr:
break; break;
case 0xFF: case 0xFF:
s->stop(s); s->stop(s);
s->stp = 0xFF;
break; break;
default: default:
printf("unimplemented opcode: 0x%02X\n", spc_r(s, s->PC)); printf("unimplemented opcode: 0x%02X\n", spc_r(s, s->PC));
@ -263,52 +369,15 @@ nobr:
} }
} }
uint8_t spc_cyc(spc_cpu* s, uint8_t o) { /* opcodes that need the Variable Timingness (they are branches)
switch(o) { 0x2E
case 0x10: 0x6E
break; 0xDE
case 0x2E: 0xFE
break; */
case 0x30:
break;
case 0x50:
break;
case 0x6E:
break;
case 0x70:
break;
case 0x90:
break;
case 0xB0:
break;
case 0xD0:
break;
case 0xDE:
break;
case 0xEF:
s->stp = 0xEF;
s->stop(s);
return 0;
break;
case 0xF0:
break;
case 0xFE:
break;
case 0xFF:
s->stp = 0xFF;
s->stop(s);
return 0;
break;
default:
return spc_cycles[spc_r(s, s->PC)];
break;
}
return 0;
}
int spc_loop(spc_cpu* s) { int spc_loop(spc_cpu* s) {
if(s->initialized != 0x59C700) return !printf("SPENCER UNINITIALIZED\n") - 1; if(s->initialized != 0x59C700) return !printf("SPENCER UNINITIALIZED\n") - 1;
if(!s->use) s->use = !!(s->wait = spc_cyc(s, spc_intr(s, s->PC)));
if(s->stp) return 0; if(s->stp) return 0;
int d = 0; int d = 0;
if(s->wait == 0) { if(s->wait == 0) {
@ -322,7 +391,7 @@ int spc_loop(spc_cpu* s) {
s->con = 1; s->con = 1;
} }
s->PC += spc_len[opcode]; s->PC += spc_len[opcode];
s->wait = spc_cyc(s, opcode); s->wait = spc_cycles[opcode];
} else s->con = 0; } else s->con = 0;
} else s->wait--; } else s->wait--;
return d; return d;

View File

@ -29,7 +29,6 @@ typedef struct {
unsigned int wait; unsigned int wait;
unsigned int initialized; unsigned int initialized;
uint8_t stp; uint8_t stp;
uint8_t use;
uint8_t con; uint8_t con;
} spc_cpu; } spc_cpu;