Created
May 5, 2021 10:49
-
-
Save fujidig/804f85a1393f8a2c5f6b5d0986ccc15a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
namespace ConsoleApp1 | |
{ | |
class Interpreter | |
{ | |
ushort af; | |
ushort bc; | |
ushort de; | |
ushort hl; | |
ushort pc; | |
ushort sp; | |
bool ime; | |
byte[] mem; | |
static string[] REGNAME = { "B", "C", "D", "E", "H", "L", "(HL)", "A" }; | |
static string[] REGNAME2 = { "BC", "DE", "HL", "AF", "SP" }; | |
public Interpreter(byte[] mem_) | |
{ | |
mem = mem_; | |
af = bc = de = hl = 0; | |
sp = 0xfffe; | |
pc = 0x100; | |
ime = false; | |
} | |
public void RunLoop() | |
{ | |
for (int i = 0; i < 100; i ++) | |
{ | |
Run(); | |
} | |
} | |
void Run() | |
{ | |
Console.Write("pc={0:x}: ", pc); | |
byte insn = read(pc++); | |
switch (insn) | |
{ | |
case 0x00: | |
Console.WriteLine("nop"); | |
break; | |
case 0xc3: | |
{ | |
byte lsb = read(pc++); | |
byte msb = read(pc++); | |
ushort nn = (ushort)(lsb | (msb << 8)); | |
Console.WriteLine("jp {0:x}", nn); | |
pc = nn; | |
break; | |
} | |
case 0xf3: | |
Console.WriteLine("di"); | |
ime = false; | |
break; | |
case 0xea: | |
{ | |
byte lsb = read(pc++); | |
byte msb = read(pc++); | |
ushort nn = (ushort)(lsb | (msb << 8)); | |
Console.WriteLine("ld ({0:x}), A", nn); | |
write(nn, (byte)(af >> 8)); | |
break; | |
} | |
case 0x3e: | |
{ | |
byte n = read(pc++); | |
Console.WriteLine("ld A, {0:x}", n); | |
af = (ushort)((n << 8) | (af & 0xff)); | |
break; | |
} | |
case 0xe0: | |
{ | |
byte n = read(pc++); | |
Console.WriteLine("ldh ({0:x}), A", n); | |
write((ushort)(0xff00 | n), (byte)(af >> 8)); | |
break; | |
} | |
case 0xcd: | |
{ | |
byte lsb = read(pc++); | |
byte msb = read(pc++); | |
ushort nn = (ushort)(lsb | (msb << 8)); | |
Console.WriteLine("call ({0:x})", nn); | |
write(--sp, (byte)(pc >> 8)); | |
write(--sp, (byte)(pc & 0xff)); | |
pc = nn; | |
break; | |
} | |
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: | |
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: | |
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: | |
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: | |
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: | |
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: | |
case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: | |
case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: | |
{ | |
int lhs = (insn >> 3) - 8; | |
int rhs = insn & 7; | |
Console.WriteLine("ld {0} {1}", REGNAME[lhs], REGNAME[rhs]); | |
writereg(lhs, readreg(rhs)); | |
break; | |
} | |
case 0x18: | |
{ | |
sbyte e = (sbyte)read(pc++); | |
Console.WriteLine("jr {0}", e); | |
pc = (ushort)(pc + e); | |
break; | |
} | |
case 0xc9: | |
{ | |
Console.WriteLine("ret"); | |
byte lsb = read(sp++); | |
byte msb = read(sp++); | |
pc = (ushort)(msb << 8 | lsb); | |
break; | |
} | |
case 0xc5: case 0xd5: case 0xe5: case 0xf5: | |
{ | |
int i = (insn >> 4) - 0xc; | |
Console.WriteLine("push {0}", REGNAME2[i]); | |
ushort v = readreg2(i); | |
write(--sp, (byte)(v >> 8)); | |
write(--sp, (byte)(v & 0xff)); | |
break; | |
} | |
case 0xc1: case 0xd1: case 0xe1: case 0xf1: | |
{ | |
int i = (insn >> 4) - 0xc; | |
Console.WriteLine("pop {0}", REGNAME2[i]); | |
byte lsb = read(sp++); | |
byte msb = read(sp++); | |
writereg2(i, (ushort)(lsb | msb << 8)); | |
break; | |
} | |
case 0x03: case 0x13: case 0x23: case 0x33: | |
{ | |
int i = (insn >> 4); | |
if (i == 3) i = 4; | |
Console.WriteLine("inc {0}", REGNAME2[i]); | |
writereg2(i, (ushort)(readreg2(i) + 1)); | |
break; | |
} | |
case 0x2a: | |
{ | |
Console.WriteLine("ldi a, (hl)"); | |
writereg(7, read(hl)); | |
hl++; | |
break; | |
} | |
case 0x01: case 0x11: case 0x21: case 0x31: | |
{ | |
int i = (insn >> 4); | |
if (i == 3) i = 4; | |
byte lsb = read(pc++); | |
byte msb = read(pc++); | |
ushort nn = (ushort)(lsb | (msb << 8)); | |
Console.WriteLine("ld {0}, {1:x}", REGNAME2[i], nn); | |
writereg2(i, nn); | |
break; | |
} | |
case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: | |
{ | |
int i = insn & 0x7; | |
Console.WriteLine("or {0}", REGNAME[i]); | |
writereg(7, (byte)(readreg(7) | readreg(i))); | |
break; | |
} | |
default: | |
Console.WriteLine("unimplemented insn: {0:x}", insn); | |
throw new Exception(); | |
} | |
} | |
byte read(ushort addr) | |
{ | |
return mem[addr]; | |
} | |
void write(ushort addr, byte val) | |
{ | |
Console.WriteLine("({0:x}) <- {1:x}", addr, val); | |
mem[addr] = val; | |
} | |
byte readreg(int i) | |
{ | |
switch (i) | |
{ | |
case 0: return (byte)(bc >> 8); | |
case 1: return (byte)(bc & 0xff); | |
case 2: return (byte)(de >> 8); | |
case 3: return (byte)(de & 0xff); | |
case 4: return (byte)(hl >> 8); | |
case 5: return (byte)(hl & 0xff); | |
case 6: return read(hl); | |
case 7: return (byte)(af >> 8); | |
default: throw new Exception("readreg: unknown i"); | |
} | |
} | |
void writereg(int i, byte v) | |
{ | |
switch (i) | |
{ | |
case 0: bc = (ushort)(v << 8 | (bc & 0xff)); break; | |
case 1: bc = (ushort)((bc & 0xff00) | v); break; | |
case 2: de = (ushort)(v << 8 | (de & 0xff)); break; | |
case 3: de = (ushort)((de & 0xff00) | v); break; | |
case 4: hl = (ushort)(v << 8 | (hl & 0xff)); break; | |
case 5: hl = (ushort)((hl & 0xff00) | v); break; | |
case 6: write(hl, v); break; | |
case 7: af = (ushort)(v << 8 | (af & 0xff)); break; | |
default: throw new Exception("writereg: unknown i"); | |
} | |
} | |
ushort readreg2(int i) | |
{ | |
switch (i) | |
{ | |
case 0: return bc; | |
case 1: return de; | |
case 2: return hl; | |
case 3: return af; | |
case 4: return sp; | |
default: throw new Exception("readreg2: unknwon i"); | |
} | |
} | |
void writereg2(int i, ushort v) | |
{ | |
switch (i) | |
{ | |
case 0: bc = v; break; | |
case 1: de = v; break; | |
case 2: hl = v; break; | |
case 3: af = v; break; | |
case 4: sp = v; break; | |
default: throw new Exception("writereg2: unknown i"); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
namespace ConsoleApp1 | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
FileStream fs = new FileStream("C:/Users/Owner/Downloads/cpu_instrs/cpu_instrs/cpu_instrs.gb", FileMode.Open, FileAccess.Read); | |
int fileSize = (int)fs.Length; | |
byte[] buf = new byte[fileSize]; | |
fs.Read(buf, 0, fileSize); | |
Interpreter intp = new Interpreter(buf); | |
intp.RunLoop(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment