From e0235094bb953029c86c98d3bcfeba18b6f2c308 Mon Sep 17 00:00:00 2001 From: Rekai Musuka Date: Sat, 29 Aug 2020 18:38:27 -0500 Subject: [PATCH] Implement basic layout of Gameboy Emulator --- src/bus.rs | 21 ++++++ src/cpu.rs | 158 +++++++++++++++++++++++++++++++++++++++++++++ src/instruction.rs | 114 ++++++++++++++++++++++++++++++++ src/lib.rs | 3 + src/main.rs | 3 + 5 files changed, 299 insertions(+) create mode 100644 src/bus.rs create mode 100644 src/cpu.rs create mode 100644 src/instruction.rs create mode 100644 src/lib.rs create mode 100644 src/main.rs diff --git a/src/bus.rs b/src/bus.rs new file mode 100644 index 0000000..cefe63a --- /dev/null +++ b/src/bus.rs @@ -0,0 +1,21 @@ +#[derive(Debug, Copy, Clone)] +pub struct Bus { +} + +impl Bus { + pub fn read_byte(&self, address: u16) -> u8 { + unimplemented!() + } + + pub fn write_byte(&mut self, address: u16, byte: u8) { + unimplemented!() + } + + pub fn read_word(&self, address: u16) -> u16 { + unimplemented!() + } + + pub fn write_word(&mut self, address: u16, word: u16) { + unimplemented!() + } +} \ No newline at end of file diff --git a/src/cpu.rs b/src/cpu.rs new file mode 100644 index 0000000..68bf23a --- /dev/null +++ b/src/cpu.rs @@ -0,0 +1,158 @@ +use super::bus::Bus; +use super::instruction::Instruction; +pub struct Cpu { + bus: Bus, + reg: Registers, + flags: Flags, + ime: bool, + state: State, + +} + +impl Cpu { + pub fn fetch(&self) -> u8 { + self.bus.read_byte(self.reg.pc) + // TODO: Figure out where to increment the program counter. + } + + pub fn decode(&self, opcode: u8) -> Instruction { + Instruction::from_byte(self, opcode) + } + + pub fn execute(&mut self, instruction: Instruction) { + unimplemented!() + } +} + +enum State { + Execute, + Halt, + Stop, +} + + +impl Cpu { + pub fn set_register(&mut self, register: Register, value: u8) { + match register { + Register::A => self.reg.a = value, + Register::B => self.reg.b = value, + Register::C => self.reg.c = value, + Register::D => self.reg.d = value, + Register::E => self.reg.e = value, + Register::H => self.reg.h = value, + Register::L => self.reg.l = value, + Register::Flags => self.reg.a = value.into() + } + } + + pub fn register(&self, register: Register) -> u8 { + match register { + Register::A => self.reg.a, + Register::B => self.reg.b, + Register::C => self.reg.c, + Register::D => self.reg.d, + Register::E => self.reg.e, + Register::H => self.reg.h, + Register::L => self.reg.l, + Register::Flags => self.flags.into() + } + } + + pub fn register_pair(&self, pair: RegisterPair) -> u16 { + match pair { + RegisterPair::AF => (self.reg.a as u16) << 8 | u8::from(self.flags) as u16, + RegisterPair::BC => (self.reg.b as u16) << 8 | self.reg.c as u16, + RegisterPair::DE => (self.reg.d as u16) << 8 | self.reg.e as u16, + RegisterPair::HL => (self.reg.h as u16) << 8 | self.reg.l as u16, + RegisterPair::SP => self.reg.sp, + RegisterPair::PC => self.reg.pc, + } + } + + pub fn set_register_pair(&mut self, pair: RegisterPair, value: u16) { + let high = (value >> 8) as u8; + let low = value as u8; + + match pair { + RegisterPair::AF => { + self.reg.a = high; + self.flags = low.into(); + } + RegisterPair::BC => { + self.reg.b = high; + self.reg.c = low; + } + RegisterPair::DE => { + self.reg.d = high; + self.reg.e = low; + } + RegisterPair::HL => { + self.reg.h = high; + self.reg.l = low; + } + RegisterPair::SP => self.reg.sp = value, + RegisterPair::PC => self.reg.pc = value, + } + } +} + + + +pub enum Register { + A, + B, + C, + D, + E, + H, + L, + Flags, +} + +pub enum RegisterPair { + AF, + BC, + DE, + HL, + SP, + PC, +} + + +struct Registers { + a: u8, + b: u8, + c: u8, + d: u8, + e: u8, + h: u8, + l: u8, + sp: u16, + pc: u16, +} + + +#[derive(Debug, Copy, Clone)] +struct Flags { + z: bool, // Zero Flag + n: bool, // Negative Flag + h: bool, // Half-Carry Flag + c: bool, // Carry Flag +} + +impl From for Flags { + fn from(flag: u8) -> Self { + Self { + z: (flag >> 7) == 1, + n: ((flag >> 6) & 0x01) == 1, + h: ((flag >> 5) & 0x01) == 1, + c: ((flag >> 4) & 0x01) == 1, + } + } +} + +impl From for u8 { + fn from(flag: Flags) -> Self { + (flag.z as u8) << 7 | (flag.n as u8) << 6 | (flag.h as u8) << 5 | (flag.c as u8) << 4 + } +} diff --git a/src/instruction.rs b/src/instruction.rs new file mode 100644 index 0000000..469f39e --- /dev/null +++ b/src/instruction.rs @@ -0,0 +1,114 @@ +use super::cpu::{Cpu, RegisterPair}; +pub enum Instruction { + NOP +} + + +impl Instruction { + pub fn from_byte(cpu: &Cpu, byte: u8) -> Self { + if byte == 0xCB { + Self::from_prefixed_byte(cpu, byte) + } else { + Self::from_unprefixed_byte(cpu, byte) + } + } + + fn from_prefixed_byte(cpu: &Cpu, byte: u8) -> Self { + // https://gb-archive.github.io/salvage/decoding_gbz80_opcodes/Decoding%20Gamboy%20Z80%20Opcodes.html + let x = (byte >> 6) & 0b00000011; + let y = (byte >> 3) & 0b00000111; + let z = byte & 0b00000111; + let p = y >> 1; + let q = y & 0b00000001; + + + unimplemented!() + } + + fn from_unprefixed_byte(cpu: &Cpu, byte: u8) -> Self { + unimplemented!() + } +} + + +enum InstrRegisterPairs { + AF, + BC, + DE, + HL, + IncrementHL, + DecrementHL, +} + +enum InstrRegisters { + A, + B, + C, + D, + E, + H, + L, + IndirectHL, +} + + + +enum JumpCondition { + NotZero, + Zero, + NotCarry, + Carry, + Always, +} + +struct Table; + +impl Table { + pub fn r(index: u8) -> InstrRegisters { + match index { + 0 => InstrRegisters::B, + 1 => InstrRegisters::C, + 2 => InstrRegisters::D, + 3 => InstrRegisters::E, + 4 => InstrRegisters::H, + 5 => InstrRegisters::L, + 6 => InstrRegisters::IndirectHL, + 7 => InstrRegisters::A, + _ => unreachable!("Index {} is out of bounds in r[]", index) + } + } + + pub fn rp2(index: u8) -> RegisterPair { + match index { + 0 => RegisterPair::BC, + 1 => RegisterPair::DE, + 2 => RegisterPair::HL, + 3 => RegisterPair::AF, + _ => unreachable!("Index {} out of bounds in rp2[]", index) + } + } + + pub fn rp(index: u8) -> RegisterPair { + match index { + 0 => RegisterPair::BC, + 1 => RegisterPair::DE, + 2 => RegisterPair::HL, + 3 => RegisterPair::AF, + _ => unreachable!("Index {} out of bounds in rp[]", index) + } + } + + pub fn cc(index: u8) -> JumpCondition { + match index { + 0 => JumpCondition::NotZero, + 1 => JumpCondition::Zero, + 2 => JumpCondition::NotCarry, + 3 => JumpCondition::Carry, + _ => unreachable!("Index {} out of bounds in cc[]", index) + } + } + + pub fn alu(index: u8) -> Instruction { + unimplemented!() + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..2b822e6 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,3 @@ +mod cpu; +mod bus; +mod instruction; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..47ad8c6 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello World!"); +}