commit db560436c5f04ae3120ddbecdcc38e66b421af4e Author: mothcompute Date: Wed Feb 2 12:49:45 2022 -0800 initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..bc43285 --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +# Snezzy + +SNES emulator for awful people + +## What? + +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 + +## What's wrong with you? + +wish i knew + +## How do I play games in it? + +i ask myself this too! + +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? + +snezzy: [see this twitter post](https://twitter.com/Lynntendo64/status/1479021585646473216) + +layla: i was listening to [this song](https://www.youtube.com/watch?v=TngViNw2pOo) on loop when i started writing it + +spencer: SPenCer. SPC diff --git a/layla/bin/howmany b/layla/bin/howmany new file mode 100755 index 0000000..1cdd32f Binary files /dev/null and b/layla/bin/howmany differ diff --git a/layla/bin/laylatest b/layla/bin/laylatest new file mode 100755 index 0000000..af63dab Binary files /dev/null and b/layla/bin/laylatest differ diff --git a/layla/buildcheck b/layla/buildcheck new file mode 100755 index 0000000..162d853 --- /dev/null +++ b/layla/buildcheck @@ -0,0 +1 @@ +cc main.c -o bin/laylatest && cc howmany.c -o bin/howmany && bin/howmany && bin/laylatest diff --git a/layla/howmany.c b/layla/howmany.c new file mode 100644 index 0000000..0e7f086 --- /dev/null +++ b/layla/howmany.c @@ -0,0 +1,8 @@ +#include +#include "layla.c" + +int main() { + int c = 0; + for(int i = 0; i < 256; i++) c+=(!!(long)ll_opcodes[i]); + printf("%i opcodes complete (%f%% to native mode success!)\n", c, 0.390625 * c); +} diff --git a/layla/layla.c b/layla/layla.c new file mode 100644 index 0000000..762a79d --- /dev/null +++ b/layla/layla.c @@ -0,0 +1,168 @@ +#include "layla.h" + +uint8_t (*ll_read)(ll_cpu* c, uint32_t addr) = NULL; +void (*ll_write)(ll_cpu* c, uint32_t addr, uint8_t b) = NULL; + +int ll_init_status = 0; + +void ll_reg_read(uint8_t(*rdp)(ll_cpu* c, uint32_t addr)) { + ll_read = rdp; + ll_init_status |= 2; + if(ll_init_status == 6) ll_init_status = 1; +} + +void ll_reg_write(void(*wrp)(ll_cpu* c, uint32_t addr, uint8_t b)) { + ll_write = wrp; + ll_init_status |= 4; + if(ll_init_status == 6) ll_init_status = 1; +} + +uint16_t ll_read16(ll_cpu* c, uint32_t addr) { + // TODO + return 0; +} + +void ll_write16(ll_cpu* c, uint32_t addr, uint16_t w) { + // TODO +} + +uint16_t llnop(ll_cpu* c) {} + +uint16_t ll18(ll_cpu* c) { + c->P.f.C = 0; +} + +uint16_t ll1b(ll_cpu* c) { + if(c->e) { + if(c->SP.D.H != 1) exit(printf("LINE %s ERR\n", __LINE__)); + c->SP.D.L = c->A.D.L; + } + else c->SP.F = c->A.F; +} + +uint16_t ll38(ll_cpu* c) { + c->P.f.C = 1; +} + +uint16_t ll3b(ll_cpu* c) { + c->A.F = c->SP.F; + ll_setnz16(SP); +} + +uint16_t ll58(ll_cpu* c) { + c->P.f.I = 0; +} + +uint16_t ll5b(ll_cpu* c) { + c->D.F = c->A.F; + ll_setnz16(D); +} + +uint16_t ll78(ll_cpu* c) { + c->P.f.I = 1; +} + +uint16_t ll7b(ll_cpu* c) { + c->A.F = c->D.F; + ll_setnz16(A); +} + +uint16_t ll98(ll_cpu* c) { + ll_trans(Y, A); +} + +uint16_t ll9a(ll_cpu* c) { + // ll_trans sans status + if(c->P.f.XB) c->SP.D.L = c->X.D.L; + // TODO needed? + if(!c->e && c->P.f.XB) c->SP.D.H = 0; + else c->SP.F = c->X.F; +} + +uint16_t ll9b(ll_cpu* c) { + ll_trans(X, Y); +} + +uint16_t lla8(ll_cpu* c) { + ll_trans(A, Y); +} + +// `llaa, you got me on my knees` +uint16_t llaa(ll_cpu* c) { + ll_trans(A, X); +} + +uint16_t llb8(ll_cpu* c) { + c->P.f.V = 0; +} + +uint16_t llba(ll_cpu* c) { + ll_trans(SP, X); +} + +uint16_t lld8(ll_cpu* c) { + c->P.f.D = 0; +} + +uint16_t lleb(ll_cpu* c) { + ll_swap(c->A.D.H, c->A.D.L); + ll_setnz8(A); +} + +uint16_t llf8(ll_cpu* c) { + c->P.f.D = 1; + printf("DECIMAL UNIMPLEMENTED\n"); +} + +uint16_t llfb(ll_cpu* c) { + c->e = c->P.f.C; + if(c->e) { + c->P.f.M = 1; + c->P.f.XB = 1; + c->X.D.H = 0; + c->Y.D.H = 0; + c->SP.D.H = 1; + } +} + +#define LL_E 0 +// if negative, called opcode will return the number of cycles. else, use this +int ll_cycles[256] = { +//(YX) 0 1 2 3 4 5 6 7 8 9 a b c d e f + LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, // 0 + LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, // 1 + LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, // 2 + LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, 2, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, // 3 + LL_E, LL_E, 2, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, // 4 + LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, // 5 + LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, // 6 + LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, 2, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, // 7 + LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, // 8 + LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, 2, 2, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, // 9 + LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, 2, LL_E, 2, LL_E, LL_E, LL_E, LL_E, LL_E, // a + LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, 2, LL_E, LL_E, LL_E, LL_E, LL_E, // b + LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, // c + LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, // d + LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, 2, 3, LL_E, LL_E, LL_E, LL_E, // e + LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, LL_E, 2, LL_E, LL_E, 2, LL_E, LL_E, LL_E, LL_E // f +}; + +ll_opcode ll_opcodes[256] = { +//(YX) 0 1 2 3 4 5 6 7 8 9 a b c d e f + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 0 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &ll18, NULL, NULL, &ll1b, NULL, NULL, NULL, NULL, // 1 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 2 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &ll38, NULL, NULL, &ll3b, NULL, NULL, NULL, NULL, // 3 + NULL, NULL, &llnop, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 4 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &ll58, NULL, NULL, &ll5b, NULL, NULL, NULL, NULL, // 5 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 6 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &ll78, NULL, NULL, &ll7b, NULL, NULL, NULL, NULL, // 7 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 8 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &ll98, &ll9b, NULL, NULL, NULL, NULL, NULL, NULL, // 9 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &lla8, NULL, &llaa, NULL, NULL, NULL, NULL, NULL, // a + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &llb8, NULL, &llba, NULL, NULL, NULL, NULL, NULL, // b + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // c + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &lld8, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // d + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &llnop, &lleb, NULL, NULL, NULL, NULL, // e + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &llf8, NULL, NULL, &llfb, NULL, NULL, NULL, NULL // f +}; diff --git a/layla/layla.h b/layla/layla.h new file mode 100644 index 0000000..53fd786 --- /dev/null +++ b/layla/layla.h @@ -0,0 +1,69 @@ +#ifndef LAYLA_H +#define LAYLA_H + +#include + +#define PACK_STRUCT __attribute__((packed)) +#define ll_swap(X, Y) X ^= Y ^= X ^= Y + +typedef struct { + uint8_t C : 1; + uint8_t Z : 1; + uint8_t I : 1; + uint8_t D : 1; + uint8_t XB : 1; + uint8_t M : 1; + uint8_t V : 1; + uint8_t N : 1; +} PACK_STRUCT ll_status_internal; + +typedef union { + uint8_t byte; + ll_status_internal f; +} ll_status; + +typedef struct { + uint8_t L; + uint8_t H; +} ll_reg_HL; + +typedef union { + uint16_t F; + ll_reg_HL D; +} ll_reg; + +typedef struct { + // bools? whats that, a bowl spoon? + uint8_t e : 1; + uint8_t DB; + uint8_t PB; + ll_status P; + ll_reg A; + ll_reg X; + ll_reg Y; + ll_reg D; + ll_reg SP; + ll_reg PC; + void* data; +} ll_cpu; + +typedef uint16_t(*ll_opcode)(ll_cpu*); + +#define ll_setnz16(DEST) \ + c->P.f.N = c->DEST.F >> 15; \ + c->P.f.Z = (c->DEST.F == 0) + +#define ll_setnz8(DEST) \ + c->P.f.N = c->DEST.D.L >> 7; \ + c->P.f.Z = (c->DEST.D.L == 0) + +#define ll_trans(SRC, DEST) \ + if(c->P.f.XB) { \ + c->DEST.D.L = c->SRC.D.L; \ + ll_setnz8(DEST); \ + } else { \ + c->DEST.F = c->SRC.F; \ + ll_setnz16(DEST); \ + } + +#endif diff --git a/layla/main.c b/layla/main.c new file mode 100644 index 0000000..beffa11 --- /dev/null +++ b/layla/main.c @@ -0,0 +1,9 @@ +#include +#include +#include "layla.c" +int main() { + printf("sizeof ll_status: %u\n", sizeof(ll_status)); + ll_reg b; + b.F = 0xFFEE; + printf("%02X\n", b.D.H); +} diff --git a/spencer/main.c b/spencer/main.c new file mode 100644 index 0000000..e08c9bb --- /dev/null +++ b/spencer/main.c @@ -0,0 +1,30 @@ +#include + +uint8_t mmr(uint8_t reg, uint8_t d, uint8_t rw) { + +} + +int main(int argc, char** argv) { + spc_cpu s; + spc_init(&s, malloc(0x10000), &mmr); + // TODO copy in new spc data + while(1) { + printf( "WAIT: %u\n" + "\tPC: 0x%04X\n" + "\tSP: 0x%02X\n" + "\tA: 0x%02X\n" + "\tX: 0x%02X\n" + "\tY: 0x%02X\n" + , + s.wait, + s.PC, + s.SP, + s.A, + s.X, + s.Y + ); + int r = spc_loop(&s); + if(r) exit(printf("error\n")); + } + return printf("stub\n"); +} diff --git a/spencer/mcbs b/spencer/mcbs new file mode 100644 index 0000000..1101da0 --- /dev/null +++ b/spencer/mcbs @@ -0,0 +1,3 @@ +SOURCES=main.c +OUTPUT=spctest +FLAGS=-I. diff --git a/spencer/opcodes b/spencer/opcodes new file mode 100644 index 0000000..1ce02cd --- /dev/null +++ b/spencer/opcodes @@ -0,0 +1,275 @@ +Mnemonic Code Bytes Cyc Operation NVPBHIZC + + NOP 00 1 2 do nothing ........ + + CLRP 20 1 2 P = 0 ..0..... + + INC X 3D 1 2 X++ N.....Z. + + SETP 40 1 2 P = 1 ..1..... + + MOV X, A 5D 1 2 X = A N.....Z. + + CLRC 60 1 2 C = 0 .......0 + + SETC 80 1 2 C = 1 .......1 + + EI A0 1 3 I = 1 .....1.. + + INC A BC 1 2 A++ N.....Z. + + DI C0 1 3 I = 0 .....0.. + + CLRV E0 1 2 V = 0, H = 0 .0..0... + + INC Y FC 1 2 Y++ N.....Z. + + + + + TCALL 0 01 1 8 CALL [$FFDE] ........ + SET1 d.0 02 2 4 d.0 = 1 ........ + BBS d.0, r 03 3 5/7 PC+=r if d.0 == 1 ........ + OR A, d 04 2 3 A = A | (d) N.....Z. + OR A, !a 05 3 4 A = A | (a) N.....Z. + OR A, (X) 06 1 3 A = A | (X) N.....Z. + OR A, [d+X] 07 2 6 A = A | ([d+X]) N.....Z. + OR A, #i 08 2 2 A = A | i N.....Z. + OR dd, ds 09 3 6 (dd) = (dd) | (ds) N.....Z. + OR1 C, m.b 0A 3 5 C = C | (m.b) .......C + ASL d 0B 2 4 Left shift (d) as above N.....ZC + ASL !a 0C 3 5 Left shift (a) as above N.....ZC + PUSH PSW 0D 1 4 (SP--) = Flags ........ + TSET1 !a 0E 3 6 (a) = (a)|A, ZN as for A-(a) N.....Z. + BRK 0F 1 8 Push PC and Flags, PC = [$FFDE] ...1.0.. + BPL r 10 2 2/4 PC+=r if N == 0 ........ + TCALL 1 11 1 8 CALL [$FFDC] ........ + CLR1 d.0 12 2 4 d.0 = 0 ........ + BBC d.0, r 13 3 5/7 PC+=r if d.0 == 0 ........ + OR A, d+X 14 2 4 A = A | (d+X) N.....Z. + OR A, !a+X 15 3 5 A = A | (a+X) N.....Z. + OR A, !a+Y 16 3 5 A = A | (a+Y) N.....Z. + OR A, [d]+Y 17 2 6 A = A | ([d]+Y) N.....Z. + OR d, #i 18 3 5 (d) = (d) | i N.....Z. + OR (X), (Y) 19 1 5 (X) = (X) | (Y) N.....Z. + DECW d 1A 2 6 Word (d)-- N.....Z. + ASL d+X 1B 2 5 Left shift (d+X) as above N.....ZC + ASL A 1C 1 2 Left shift A: high->C, 0->low N.....ZC + DEC X 1D 1 2 X-- N.....Z. + CMP X, !a 1E 3 4 X - (a) N.....ZC + JMP [!a+X] 1F 3 6 PC = [a+X] ........ + TCALL 2 21 1 8 CALL [$FFDA] ........ + SET1 d.1 22 2 4 d.1 = 1 ........ + BBS d.1, r 23 3 5/7 PC+=r if d.1 == 1 ........ + AND A, d 24 2 3 A = A & (d) N.....Z. + AND A, !a 25 3 4 A = A & (a) N.....Z. + AND A, (X) 26 1 3 A = A & (X) N.....Z. + AND A, [d+X] 27 2 6 A = A & ([d+X]) N.....Z. + AND A, #i 28 2 2 A = A & i N.....Z. + AND dd, ds 29 3 6 (dd) = (dd) & (ds) N.....Z. + OR1 C, /m.b 2A 3 5 C = C | ~(m.b) .......C + ROL d 2B 2 4 Left shift (d) as above N.....ZC + ROL !a 2C 3 5 Left shift (a) as above N.....ZC + PUSH A 2D 1 4 (SP--) = A ........ + CBNE d, r 2E 3 5/7 CMP A, (d) then BNE ........ + BRA r 2F 2 4 PC+=r ........ + BMI r 30 2 2/4 PC+=r if N == 1 ........ + TCALL 3 31 1 8 CALL [$FFD8] ........ + CLR1 d.1 32 2 4 d.1 = 0 ........ + BBC d.1, r 33 3 5/7 PC+=r if d.1 == 0 ........ + AND A, d+X 34 2 4 A = A & (d+X) N.....Z. + AND A, !a+X 35 3 5 A = A & (a+X) N.....Z. + AND A, !a+Y 36 3 5 A = A & (a+Y) N.....Z. + AND A, [d]+Y 37 2 6 A = A & ([d]+Y) N.....Z. + AND d, #i 38 3 5 (d) = (d) & i N.....Z. + AND (X), (Y) 39 1 5 (X) = (X) & (Y) N.....Z. + INCW d 3A 2 6 Word (d)++ N.....Z. + ROL d+X 3B 2 5 Left shift (d+X) as above N.....ZC + ROL A 3C 1 2 Left shift A: low=C, C=high N.....ZC + CMP X, d 3E 2 3 X - (d) N.....ZC + CALL !a 3F 3 8 (SP--)=PCh, (SP--)=PCl, PC=a ........ + TCALL 4 41 1 8 CALL [$FFD6] ........ + SET1 d.2 42 2 4 d.2 = 1 ........ + BBS d.2, r 43 3 5/7 PC+=r if d.2 == 1 ........ + EOR A, d 44 2 3 A = A EOR (d) N.....Z. + EOR A, !a 45 3 4 A = A EOR (a) N.....Z. + EOR A, (X) 46 1 3 A = A EOR (X) N.....Z. + EOR A, [d+X] 47 2 6 A = A EOR ([d+X]) N.....Z. + EOR A, #i 48 2 2 A = A EOR i N.....Z. + EOR dd, ds 49 3 6 (dd) = (dd) EOR (ds) N.....Z. + AND1 C, m.b 4A 3 4 C = C & (m.b) .......C + LSR d 4B 2 4 Right shift (d) as above N.....ZC + LSR !a 4C 3 5 Right shift (a) as above N.....ZC + PUSH X 4D 1 4 (SP--) = X ........ + TCLR1 !a 4E 3 6 (a) = (a)&~A, ZN as for A-(a) N.....Z. + PCALL u 4F 2 6 CALL $FF00+u ........ + BVC r 50 2 2/4 PC+=r if V == 0 ........ + TCALL 5 51 1 8 CALL [$FFD4] ........ + CLR1 d.2 52 2 4 d.2 = 0 ........ + BBC d.2, r 53 3 5/7 PC+=r if d.2 == 0 ........ + EOR A, d+X 54 2 4 A = A EOR (d+X) N.....Z. + EOR A, !a+X 55 3 5 A = A EOR (a+X) N.....Z. + EOR A, !a+Y 56 3 5 A = A EOR (a+Y) N.....Z. + EOR A, [d]+Y 57 2 6 A = A EOR ([d]+Y) N.....Z. + EOR d, #i 58 3 5 (d) = (d) EOR i N.....Z. + EOR (X), (Y) 59 1 5 (X) = (X) EOR (Y) N.....Z. + CMPW YA, d 5A 2 4 YA - (d) N.....ZC + LSR d+X 5B 2 5 Right shift (d+X) as above N.....ZC + LSR A 5C 1 2 Right shift A: 0->high, low->C N.....ZC + CMP Y, !a 5E 3 4 Y - (a) N.....ZC + JMP !a 5F 3 3 PC = a ........ + TCALL 6 61 1 8 CALL [$FFD2] ........ + SET1 d.3 62 2 4 d.3 = 1 ........ + BBS d.3, r 63 3 5/7 PC+=r if d.3 == 1 ........ + CMP A, d 64 2 3 A - (d) N.....ZC + CMP A, !a 65 3 4 A - (a) N.....ZC + CMP A, (X) 66 1 3 A - (X) N.....ZC + CMP A, [d+X] 67 2 6 A - ([d+X]) N.....ZC + CMP A, #i 68 2 2 A - i N.....ZC + CMP dd, ds 69 3 6 (dd) - (ds) N.....ZC + AND1 C, /m.b 6A 3 4 C = C & ~(m.b) .......C + ROR d 6B 2 4 Right shift (d) as above N.....ZC + ROR !a 6C 3 5 Right shift (a) as above N.....ZC + PUSH Y 6D 1 4 (SP--) = Y ........ + DBNZ d, r 6E 3 5/7 (d)-- then JNZ ........ + RET 6F 1 5 Pop PC ........ + BVS r 70 2 2/4 PC+=r if V == 1 ........ + TCALL 7 71 1 8 CALL [$FFD0] ........ + CLR1 d.3 72 2 4 d.3 = 0 ........ + BBC d.3, r 73 3 5/7 PC+=r if d.3 == 0 ........ + CMP A, d+X 74 2 4 A - (d+X) N.....ZC + CMP A, !a+X 75 3 5 A - (a+X) N.....ZC + CMP A, !a+Y 76 3 5 A - (a+Y) N.....ZC + CMP A, [d]+Y 77 2 6 A - ([d]+Y) N.....ZC + CMP d, #i 78 3 5 (d) - i N.....ZC + CMP (X), (Y) 79 1 5 (X) - (Y) N.....ZC + ADDW YA, d 7A 2 5 YA = YA + (d), H on high byte NV..H.ZC + ROR d+X 7B 2 5 Right shift (d+X) as above N.....ZC + ROR A 7C 1 2 Right shift A: high=C, C=low N.....ZC + MOV A, X 7D 1 2 A = X N.....Z. + CMP Y, d 7E 2 3 Y - (d) N.....ZC + RET1 7F 1 6 Pop Flags, PC NVPBHIZC + TCALL 8 81 1 8 CALL [$FFCE] ........ + SET1 d.4 82 2 4 d.4 = 1 ........ + BBS d.4, r 83 3 5/7 PC+=r if d.4 == 1 ........ + ADC A, d 84 2 3 A = A+(d)+C NV..H.ZC + ADC A, !a 85 3 4 A = A+(a)+C NV..H.ZC + ADC A, (X) 86 1 3 A = A+(X)+C NV..H.ZC + ADC A, [d+X] 87 2 6 A = A+([d+X])+C NV..H.ZC + ADC A, #i 88 2 2 A = A+i+C NV..H.ZC + ADC dd, ds 89 3 6 (dd) = (dd)+(d)+C NV..H.ZC + EOR1 C, m.b 8A 3 5 C = C EOR (m.b) .......C + DEC d 8B 2 4 (d)-- N.....Z. + DEC !a 8C 3 5 (a)-- N.....Z. + MOV Y, #i 8D 2 2 Y = i N.....Z. + POP PSW 8E 1 4 Flags = (++SP) NVPBHIZC + MOV d, #i 8F 3 5 (d) = i (read) ........ + BCC r 90 2 2/4 PC+=r if C == 0 ........ + TCALL 9 91 1 8 CALL [$FFCC] ........ + CLR1 d.4 92 2 4 d.4 = 0 ........ + BBC d.4, r 93 3 5/7 PC+=r if d.4 == 0 ........ + ADC A, d+X 94 2 4 A = A+(d+X)+C NV..H.ZC + ADC A, !a+X 95 3 5 A = A+(a+X)+C NV..H.ZC + ADC A, !a+Y 96 3 5 A = A+(a+Y)+C NV..H.ZC + ADC A, [d]+Y 97 2 6 A = A+([d]+Y)+C NV..H.ZC + ADC d, #i 98 3 5 (d) = (d)+i+C NV..H.ZC + ADC (X), (Y) 99 1 5 (X) = (X)+(Y)+C NV..H.ZC + SUBW YA, d 9A 2 5 YA = YA - (d), H on high byte NV..H.ZC + DEC d+X 9B 2 5 (d+X)-- N.....Z. + DEC A 9C 1 2 A-- N.....Z. + MOV X, SP 9D 1 2 X = SP N.....Z. + DIV YA, X 9E 1 12 A=YA/X, Y=mod(YA,X) NV..H.Z. + XCN A 9F 1 5 A = (A>>4) | (A<<4) N.....Z. + + + TCALL 10 A1 1 8 CALL [$FFCA] ........ + SET1 d.5 A2 2 4 d.5 = 1 ........ + BBS d.5, r A3 3 5/7 PC+=r if d.5 == 1 ........ + SBC A, d A4 2 3 A = A-(d)-!C NV..H.ZC + SBC A, !a A5 3 4 A = A-(a)-!C NV..H.ZC + SBC A, (X) A6 1 3 A = A-(X)-!C NV..H.ZC + SBC A, [d+X] A7 2 6 A = A-([d+X])-!C NV..H.ZC + SBC A, #i A8 2 2 A = A-i-!C NV..H.ZC + SBC dd, ds A9 3 6 (dd) = (dd)-(ds)-!C NV..H.ZC + MOV1 C, m.b AA 3 4 C = (m.b) .......C + INC d AB 2 4 (d)++ N.....Z. + INC !a AC 3 5 (a)++ N.....Z. + CMP Y, #i AD 2 2 Y - i N.....ZC + POP A AE 1 4 A = (++SP) ........ + MOV (X)+, A AF 1 4 (X++) = A (no read) ........ + BCS r B0 2 2/4 PC+=r if C == 1 ........ + TCALL 11 B1 1 8 CALL [$FFC8] ........ + CLR1 d.5 B2 2 4 d.5 = 0 ........ + BBC d.5, r B3 3 5/7 PC+=r if d.5 == 0 ........ + SBC A, d+X B4 2 4 A = A-(d+X)-!C NV..H.ZC + SBC A, !a+X B5 3 5 A = A-(a+X)-!C NV..H.ZC + SBC A, !a+Y B6 3 5 A = A-(a+Y)-!C NV..H.ZC + SBC A, [d]+Y B7 2 6 A = A-([d]+Y)-!C NV..H.ZC + SBC d, #i B8 3 5 (d) = (d)-i-!C NV..H.ZC + SBC (X), (Y) B9 1 5 (X) = (X)-(Y)-!C NV..H.ZC + MOVW YA, d BA 2 5 YA = word (d) N.....Z. + INC d+X BB 2 5 (d+X)++ N.....Z. + MOV SP, X BD 1 2 SP = X ........ + DAS A BE 1 3 decimal adjust for subtraction N.....ZC + MOV A, (X)+ BF 1 4 A = (X++) N.....Z. + TCALL 12 C1 1 8 CALL [$FFC6] ........ + SET1 d.6 C2 2 4 d.6 = 1 ........ + BBS d.6, r C3 3 5/7 PC+=r if d.6 == 1 ........ + MOV d, A C4 2 4 (d) = A (read) ........ + MOV !a, A C5 3 5 (a) = A (read) ........ + MOV (X), A C6 1 4 (X) = A (read) ........ + MOV [d+X], A C7 2 7 ([d+X]) = A (read) ........ + CMP X, #i C8 2 2 X - i N.....ZC + MOV !a, X C9 3 5 (a) = X (read) ........ + MOV1 m.b, C CA 3 6 (m.b) = C ........ + MOV d, Y CB 2 4 (d) = Y (read) ........ + MOV !a, Y CC 3 5 (a) = Y (read) ........ + MOV X, #i CD 2 2 X = i N.....Z. + POP X CE 1 4 X = (++SP) ........ + MUL YA CF 1 9 YA = Y * A, NZ on Y only N.....Z. + BNE r D0 2 2/4 PC+=r if Z == 0 ........ + TCALL 13 D1 1 8 CALL [$FFC4] ........ + CLR1 d.6 D2 2 4 d.6 = 0 ........ + BBC d.6, r D3 3 5/7 PC+=r if d.6 == 0 ........ + MOV d+X, A D4 2 5 (d+X) = A (read) ........ + MOV !a+X, A D5 3 6 (a+X) = A (read) ........ + MOV !a+Y, A D6 3 6 (a+Y) = A (read) ........ + MOV [d]+Y, A D7 2 7 ([d]+Y) = A (read) ........ + MOV d, X D8 2 4 (d) = X (read) ........ + MOV d+Y, X D9 2 5 (d+Y) = X (read) ........ + MOVW d, YA DA 2 5 word (d) = YA (read low only) ........ + MOV d+X, Y DB 2 5 (d+X) = Y (read) ........ + DEC Y DC 1 2 Y-- N.....Z. + MOV A, Y DD 1 2 A = Y N.....Z. + CBNE d+X, r DE 3 6/8 CMP A, (d+X) then BNE ........ + DAA A DF 1 3 decimal adjust for addition N.....ZC + TCALL 14 E1 1 8 CALL [$FFC2] ........ + SET1 d.7 E2 2 4 d.7 = 1 ........ + BBS d.7, r E3 3 5/7 PC+=r if d.7 == 1 ........ + MOV A, d E4 2 3 A = (d) N.....Z. + MOV A, !a E5 3 4 A = (a) N.....Z. + MOV A, (X) E6 1 3 A = (X) N.....Z. + MOV A, [d+X] E7 2 6 A = ([d+X]) N.....Z. + MOV A, #i E8 2 2 A = i N.....Z. + MOV X, !a E9 3 4 X = (a) N.....Z. + NOT1 m.b EA 3 5 m.b = ~m.b ........ + MOV Y, d EB 2 3 Y = (d) N.....Z. + MOV Y, !a EC 3 4 Y = (a) N.....Z. + NOTC ED 1 3 C = !C .......C + POP Y EE 1 4 Y = (++SP) ........ + SLEEP EF 1 ? Halts the processor ........ + BEQ r F0 2 2/4 PC+=r if Z == 1 ........ + TCALL 15 F1 1 8 CALL [$FFC0] ........ + CLR1 d.7 F2 2 4 d.7 = 0 ........ + BBC d.7, r F3 3 5/7 PC+=r if d.7 == 0 ........ + MOV A, d+X F4 2 4 A = (d+X) N.....Z. + MOV A, !a+X F5 3 5 A = (a+X) N.....Z. + MOV A, !a+Y F6 3 5 A = (a+Y) N.....Z. + MOV A, [d]+Y F7 2 6 A = ([d]+Y) N.....Z. + MOV X, d F8 2 3 X = (d) N.....Z. + MOV X, d+Y F9 2 4 X = (d+Y) N.....Z. + MOV dd, ds FA 3 5 (dd) = (ds) (no read) ........ + MOV Y, d+X FB 2 4 Y = (d+X) N.....Z. + MOV Y, A FD 1 2 Y = A N.....Z. + DBNZ Y, r FE 2 4/6 Y-- then JNZ ........ + STOP FF 1 ? Halts the processor ........ diff --git a/spencer/spctest b/spencer/spctest new file mode 100755 index 0000000..75a71ce Binary files /dev/null and b/spencer/spctest differ diff --git a/spencer/spencer.c b/spencer/spencer.c new file mode 100644 index 0000000..2f97462 --- /dev/null +++ b/spencer/spencer.c @@ -0,0 +1,152 @@ +#include + +// needs memset +#include + +// needs printf +#include + +void spc_init(spc_cpu* s, void* mem, uint8_t(*mmr)(uint8_t, uint8_t, uint8_t)) { + memset(s, 0, sizeof(spc_cpu)); + s->mmr = mmr; + s->mem = mem; + s->initialized = 0x59C700; +} + +const uint8_t spc_ipl[0x40] = { + 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, + 0xCB, 0xF4, 0xD7, 0x00, 0xFC, 0xD0, 0xF3, 0xAB, 0x01, 0x10, 0xEF, 0x7E, 0xF4, 0x10, 0xEB, 0xBA, + 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) { + if((p >= 0xF0 && p <= 0xF7) || (p >= 0xFA && p <= 0xFF)) return s->mmr(p - 0xF0, 0, S_R); + if(p >= 0xFFC0 && s->mmr(0xF1, 0, S_R) >> 7) return spc_ipl[p - 0xFFC0]; + return s->mem[p]; +} + +void spc_w(spc_cpu* s, uint16_t p, uint8_t d) { + if((p >= 0xF0 && p <= 0xF7) || (p >= 0xFA && p <= 0xFF)) { + s->mmr(p - 0xF0, d, S_W); + return; + } + s->mem[p] = d; +} + +// this is bad +#define spc_im8(C, O) (spc_r(C, C->PC + 1 + O)) + +// this is not okay +#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_pull(C) spc_r(C, C->SP++) + +#define NUL 0 +int spc_cycles[256] = { // -1: length returned by spc_eval +// 0 1 2 3 4 5 6 7 8 9 a b c d e f + 2, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 0 + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 1 + 2, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 2 + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, 2, NUL, NUL, // 3 + 2, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 4 + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, 2, NUL, NUL, // 5 + 2, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 6 + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 7 + 2, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 8 + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 9 + 3, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // a + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, 2, NUL, NUL, NUL, // b + 3, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // c + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // d + 2, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // e + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, 2, NUL, NUL, NUL // f +}; + +uint8_t spc_len[256] = { +// 0 1 2 3 4 5 6 7 8 9 a b c d e f + 1, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 0 + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 1 + 1, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 2 + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, 1, NUL, NUL, // 3 + 1, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 4 + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, 1, NUL, NUL, // 5 + 1, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 6 + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 7 + 1, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 8 + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 9 + 1, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // a + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, 1, NUL, NUL, NUL, // b + 1, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // c + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // d + 1, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // e + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, 1, NUL, NUL, NUL // f +}; + +int spc_eval(spc_cpu* s, int* err) { + int cycles = 0; + switch(spc_r(s, s->PC)) { + case 0x00: + break; + case 0x20: + spc_unsetp(s); + break; + case 0xBC: + spc_inc(s, s->A); + break; + case 0x3D: + spc_inc(s, s->X); + break; + case 0x40: + spc_setp(s); + break; + case 0x5D: + spc_trans(s, s->X, s->A); + break; + case 0x60: + spc_unsetc(s); + break; + case 0x80: + spc_setc(s); + break; + case 0xA0: + spc_seti(s); + break; + case 0xC0: + spc_unseti(s); + break; + case 0xE0: + spc_unsetv(s); + spc_unseth(s); + break; + case 0xFC: + spc_inc(s, s->Y); + break; + default: + printf("unimplemented opcode: 0x%02X\n", spc_r(s, s->PC)); + *err = 1; + break; + } + s->PC += spc_len[spc_r(s, s->PC)]; + return cycles; +} + +int spc_loop(spc_cpu* s) { + if(s->initialized != 0x59C700) return !printf("SPENCER UNINITIALIZED\n") - 1; + int err = 0; + if(s->wait == 0) { + printf("-- EVAL --\n"); + int w = spc_cycles[spc_r(s, s->PC)], c = spc_eval(s, &err); + if(w == -1) s->wait = c; + else s->wait = w; + s->wait--; + } else s->wait--; + return err; +} diff --git a/spencer/spencer.h b/spencer/spencer.h new file mode 100644 index 0000000..7af743a --- /dev/null +++ b/spencer/spencer.h @@ -0,0 +1,64 @@ +#ifndef SPENCER_H +#define SPENCER_H + +#include +#include + +// mmr flags +#define S_R 1 // read +#define S_W 0 // write +#define S_I 2 // internal (for internal emulator function) + +typedef struct { + uint8_t A, X, Y, SP, P; // 1 byte registers + uint16_t PC; // 2 byte registers + uint8_t* mem; // 0x10000 bytes + + /* MMR arguments: + * + * width description + * ------------------------- + * u8 | register number (0-15) + * u8 | data to write (if reading anything is fine) + * u8 | S_R to read, S_W to write + */ + uint8_t(*mmr)(uint8_t, uint8_t, uint8_t); + unsigned int wait; + unsigned int initialized; + uint8_t sleeping; +} spc_cpu; + +#define spc_getn(CPU) (CPU->P >> 7) +#define spc_getv(CPU) ((CPU->P >> 6) & 1) +#define spc_getp(CPU) ((CPU->P >> 5) & 1) +#define spc_getb(CPU) ((CPU->P >> 4) & 1) +#define spc_geth(CPU) ((CPU->P >> 3) & 1) +#define spc_geti(CPU) ((CPU->P >> 2) & 1) +#define spc_getz(CPU) ((CPU->P >> 1) & 1) +#define spc_getc(CPU) (CPU->P & 1) + +#define spc_setn(CPU) CPU->P |= 0x80 +#define spc_setv(CPU) CPU->P |= 0x40 +#define spc_setp(CPU) CPU->P |= 0x20 +#define spc_setb(CPU) CPU->P |= 0x10 +#define spc_seth(CPU) CPU->P |= 0x08 +#define spc_seti(CPU) CPU->P |= 0x04 +#define spc_setz(CPU) CPU->P |= 0x02 +#define spc_setc(CPU) CPU->P |= 0x01 + +#define spc_unsetn(CPU) CPU->P &= ~0x80 +#define spc_unsetv(CPU) CPU->P &= ~0x40 +#define spc_unsetp(CPU) CPU->P &= ~0x20 +#define spc_unsetb(CPU) CPU->P &= ~0x10 +#define spc_unseth(CPU) CPU->P &= ~0x08 +#define spc_unseti(CPU) CPU->P &= ~0x04 +#define spc_unsetz(CPU) CPU->P &= ~0x02 +#define spc_unsetc(CPU) CPU->P &= ~0x01 + +#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_inc(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) + +#endif