Utilize pattern matching more

This commit is contained in:
Rekai Nyangadzayi Musuka 2020-09-02 19:35:48 -05:00
parent cb365fd932
commit 49dac85470
2 changed files with 153 additions and 166 deletions

View File

@ -1,5 +1,7 @@
use super::bus::Bus; use super::bus::Bus;
use super::instruction::Instruction; use super::instruction::Instruction;
#[derive(Debug, Copy, Clone)]
pub struct Cpu { pub struct Cpu {
bus: Bus, bus: Bus,
reg: Registers, reg: Registers,
@ -41,6 +43,7 @@ impl Cpu {
} }
} }
#[derive(Debug, Copy, Clone)]
enum State { enum State {
Execute, Execute,
Halt, Halt,
@ -112,6 +115,7 @@ impl Cpu {
} }
} }
#[derive(Debug, Copy, Clone)]
pub enum Register { pub enum Register {
A, A,
B, B,
@ -123,6 +127,7 @@ pub enum Register {
Flag, Flag,
} }
#[derive(Debug, Copy, Clone)]
pub enum RegisterPair { pub enum RegisterPair {
AF, AF,
BC, BC,
@ -132,6 +137,7 @@ pub enum RegisterPair {
PC, PC,
} }
#[derive(Debug, Copy, Clone)]
struct Registers { struct Registers {
a: u8, a: u8,
b: u8, b: u8,

View File

@ -1,4 +1,6 @@
use super::cpu::{Cpu, Flags, Register, RegisterPair}; use super::cpu::{Cpu, Flags, Register, RegisterPair};
use std::convert::TryFrom;
#[derive(Debug, Copy, Clone)]
pub enum Instruction { pub enum Instruction {
NOP, NOP,
LD(LDTarget, LDTarget), LD(LDTarget, LDTarget),
@ -35,6 +37,7 @@ pub enum Instruction {
RST(u8), RST(u8),
} }
#[derive(Debug, Copy, Clone)]
pub struct Cycles(u8); pub struct Cycles(u8);
impl Instruction { impl Instruction {
@ -47,29 +50,26 @@ impl Instruction {
cpu.write_word(nn, cpu.register_pair(RegisterPair::SP)); cpu.write_word(nn, cpu.register_pair(RegisterPair::SP));
Cycles(20) Cycles(20)
} }
(LDTarget::RegisterPair(pairs), LDTarget::ImmediateWord(nn)) => { (LDTarget::RegisterPair(pair), LDTarget::ImmediateWord(nn)) => {
// LD rp[p], nn | Put value nn into register pair // LD rp[p], nn | Put value nn into register pair
match pairs { match pair {
RegisterPair::BC => cpu.set_register_pair(RegisterPair::BC, nn), RegisterPair::BC
RegisterPair::DE => cpu.set_register_pair(RegisterPair::DE, nn), | RegisterPair::DE
RegisterPair::HL => cpu.set_register_pair(RegisterPair::HL, nn), | RegisterPair::HL
RegisterPair::SP => cpu.set_register_pair(RegisterPair::SP, nn), | RegisterPair::SP => {
cpu.set_register_pair(RegisterPair::try_from(pair).unwrap(), nn)
}
_ => unreachable!(), _ => unreachable!(),
} }
Cycles(12) Cycles(12)
} }
(LDTarget::IndirectRegister(pair), LDTarget::Register(InstrRegister::A)) => { (LDTarget::IndirectRegister(pair), LDTarget::Register(InstrRegister::A)) => {
let a = cpu.register(Register::A); let a = cpu.register(Register::A);
match pair { match pair {
InstrRegisterPair::BC => { InstrRegisterPair::BC | InstrRegisterPair::DE => {
// LD (BC), A | Put A into memory address BC // LD (BC), A | Put A into memory address BC
let addr = cpu.register_pair(RegisterPair::BC);
cpu.write_byte(addr, a);
}
InstrRegisterPair::DE => {
// LD (DE), A | Put A into memory address DE // LD (DE), A | Put A into memory address DE
let addr = cpu.register_pair(RegisterPair::DE); let addr = cpu.register_pair(RegisterPair::try_from(pair).unwrap());
cpu.write_byte(addr, a); cpu.write_byte(addr, a);
} }
InstrRegisterPair::IncrementHL => { InstrRegisterPair::IncrementHL => {
@ -92,14 +92,10 @@ impl Instruction {
} }
(LDTarget::Register(InstrRegister::A), LDTarget::IndirectRegister(pair)) => { (LDTarget::Register(InstrRegister::A), LDTarget::IndirectRegister(pair)) => {
match pair { match pair {
InstrRegisterPair::BC => { InstrRegisterPair::BC | InstrRegisterPair::DE => {
// LD A, (BC) | Put value at address BC into A // LD A, (BC) | Put value at address BC into A
let addr = cpu.register_pair(RegisterPair::BC);
cpu.set_register(Register::A, cpu.read_byte(addr));
}
InstrRegisterPair::DE => {
// LD A, (DE) | Put value at address DE into A // LD A, (DE) | Put value at address DE into A
let addr = cpu.register_pair(RegisterPair::DE); let addr = cpu.register_pair(RegisterPair::try_from(pair).unwrap());
cpu.set_register(Register::A, cpu.read_byte(addr)); cpu.set_register(Register::A, cpu.read_byte(addr));
} }
InstrRegisterPair::IncrementHL => { InstrRegisterPair::IncrementHL => {
@ -122,46 +118,26 @@ impl Instruction {
} }
(LDTarget::Register(reg), LDTarget::ImmediateByte(n)) => { (LDTarget::Register(reg), LDTarget::ImmediateByte(n)) => {
// LD r[y], n | Store n in Register // LD r[y], n | Store n in Register
let cycles: Cycles;
match reg { match reg {
InstrRegister::B => {
cpu.set_register(Register::B, n);
cycles = Cycles(8);
}
InstrRegister::C => {
cpu.set_register(Register::C, n);
cycles = Cycles(8);
}
InstrRegister::D => {
cpu.set_register(Register::D, n);
cycles = Cycles(8);
}
InstrRegister::E => {
cpu.set_register(Register::E, n);
cycles = Cycles(8);
}
InstrRegister::H => {
cpu.set_register(Register::H, n);
cycles = Cycles(8);
}
InstrRegister::L => {
cpu.set_register(Register::L, n);
cycles = Cycles(8);
}
InstrRegister::IndirectHL => { InstrRegister::IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
cpu.write_byte(addr, n); cpu.write_byte(addr, n);
cycles = Cycles(12); Cycles(12)
} }
InstrRegister::A => { InstrRegister::A
cpu.set_register(Register::A, n); | InstrRegister::B
cycles = Cycles(8); | InstrRegister::C
| InstrRegister::D
| InstrRegister::E
| InstrRegister::H
| InstrRegister::L => {
cpu.set_register(Register::try_from(reg).unwrap(), n);
Cycles(8)
} }
InstrRegister::IndirectC => unreachable!(), InstrRegister::IndirectC => unreachable!(),
} }
cycles
} }
(LDTarget::Register(lhs), LDTarget::Register(rhs)) => unimplemented!(),
_ => unimplemented!(), _ => unimplemented!(),
}, },
Instruction::STOP => Cycles(4), Instruction::STOP => Cycles(4),
@ -211,30 +187,22 @@ impl Instruction {
Instruction::ADD(lhs, rhs) => match (lhs, rhs) { Instruction::ADD(lhs, rhs) => match (lhs, rhs) {
(MATHTarget::RegisterPair(RegisterPair::HL), MATHTarget::RegisterPair(pair)) => { (MATHTarget::RegisterPair(RegisterPair::HL), MATHTarget::RegisterPair(pair)) => {
// ADD HL, rp[p] | add register pair to HL. // ADD HL, rp[p] | add register pair to HL.
let hl = cpu.register_pair(RegisterPair::HL);
let mut flags: Flags = cpu.register(Register::Flag).into(); let mut flags: Flags = cpu.register(Register::Flag).into();
let sum;
match pair { match pair {
RegisterPair::BC => { RegisterPair::BC
let bc = cpu.register_pair(RegisterPair::BC); | RegisterPair::DE
sum = Self::add_u16s(hl, bc, &mut flags); | RegisterPair::HL
} | RegisterPair::SP => {
RegisterPair::DE => { let hl_value = cpu.register_pair(RegisterPair::HL);
let de = cpu.register_pair(RegisterPair::DE); let value = cpu.register_pair(RegisterPair::try_from(pair).unwrap());
sum = Self::add_u16s(hl, de, &mut flags); let sum = Self::add_u16s(hl_value, value, &mut flags);
}
RegisterPair::HL => { cpu.set_register_pair(RegisterPair::HL, sum);
sum = Self::add_u16s(hl, hl, &mut flags);
}
RegisterPair::SP => {
let sp = cpu.register_pair(RegisterPair::SP);
sum = Self::add_u16s(hl, sp, &mut flags);
} }
_ => unreachable!(), _ => unreachable!(),
} }
cpu.set_register(Register::Flag, flags.into()); cpu.set_register(Register::Flag, flags.into());
cpu.set_register_pair(RegisterPair::HL, sum);
Cycles(8) Cycles(8)
} }
_ => unimplemented!(), _ => unimplemented!(),
@ -242,21 +210,9 @@ impl Instruction {
Instruction::INC(Registers::Word(pair)) => { Instruction::INC(Registers::Word(pair)) => {
// INC rp[p] | Increment Register Pair // INC rp[p] | Increment Register Pair
match pair { match pair {
RegisterPair::BC => { RegisterPair::BC | RegisterPair::DE | RegisterPair::HL | RegisterPair::SP => {
let bc = cpu.register_pair(RegisterPair::BC); let value = cpu.register_pair(pair);
cpu.set_register_pair(RegisterPair::BC, bc + 1); cpu.set_register_pair(pair, value + 1);
}
RegisterPair::DE => {
let de = cpu.register_pair(RegisterPair::DE);
cpu.set_register_pair(RegisterPair::DE, de + 1);
}
RegisterPair::HL => {
let hl = cpu.register_pair(RegisterPair::HL);
cpu.set_register_pair(RegisterPair::HL, hl + 1);
}
RegisterPair::SP => {
let sp = cpu.register_pair(RegisterPair::SP);
cpu.set_register_pair(RegisterPair::SP, sp + 1);
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -268,45 +224,23 @@ impl Instruction {
let cycles: Cycles; let cycles: Cycles;
match reg { match reg {
InstrRegister::B => { InstrRegister::B
let b = cpu.register(Register::B); | InstrRegister::C
cpu.set_register(Register::B, Self::inc_register(b, &mut flags)); | InstrRegister::D
cycles = Cycles(4); | InstrRegister::E
} | InstrRegister::H
InstrRegister::C => { | InstrRegister::L
let c = cpu.register(Register::C); | InstrRegister::A => {
cpu.set_register(Register::C, Self::inc_register(c, &mut flags)); let reg = Register::try_from(reg).unwrap();
cycles = Cycles(4);
} let value = cpu.register(reg);
InstrRegister::D => { cpu.set_register(reg, Self::inc_register(value, &mut flags));
let d = cpu.register(Register::D); cycles = Cycles(4)
cpu.set_register(Register::D, Self::inc_register(d, &mut flags));
cycles = Cycles(4);
}
InstrRegister::E => {
let e = cpu.register(Register::E);
cpu.set_register(Register::E, Self::inc_register(e, &mut flags));
cycles = Cycles(4);
}
InstrRegister::H => {
let h = cpu.register(Register::H);
cpu.set_register(Register::H, Self::inc_register(h, &mut flags));
cycles = Cycles(4);
}
InstrRegister::L => {
let l = cpu.register(Register::L);
cpu.set_register(Register::L, Self::inc_register(l, &mut flags));
cycles = Cycles(4);
} }
InstrRegister::IndirectHL => { InstrRegister::IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
cpu.write_byte(addr, Self::inc_register(cpu.read_byte(addr), &mut flags)); cpu.write_byte(addr, Self::inc_register(cpu.read_byte(addr), &mut flags));
cycles = Cycles(12); cycles = Cycles(12)
}
InstrRegister::A => {
let a = cpu.register(Register::A);
cpu.set_register(Register::A, Self::inc_register(a, &mut flags));
cycles = Cycles(4);
} }
InstrRegister::IndirectC => unreachable!(), InstrRegister::IndirectC => unreachable!(),
} }
@ -314,23 +248,10 @@ impl Instruction {
cycles cycles
} }
Instruction::DEC(Registers::Word(pair)) => { Instruction::DEC(Registers::Word(pair)) => {
// DEC rp[p] | Decrement Register Pair
match pair { match pair {
RegisterPair::BC => { RegisterPair::BC | RegisterPair::DE | RegisterPair::HL | RegisterPair::SP => {
let bc = cpu.register_pair(RegisterPair::BC); let value = cpu.register_pair(pair);
cpu.set_register_pair(RegisterPair::BC, bc - 1); cpu.set_register_pair(pair, value - 1);
}
RegisterPair::DE => {
let de = cpu.register_pair(RegisterPair::DE);
cpu.set_register_pair(RegisterPair::DE, de - 1);
}
RegisterPair::HL => {
let hl = cpu.register_pair(RegisterPair::HL);
cpu.set_register_pair(RegisterPair::HL, hl - 1);
}
RegisterPair::SP => {
let sp = cpu.register_pair(RegisterPair::SP);
cpu.set_register_pair(RegisterPair::SP, sp - 1);
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -342,34 +263,17 @@ impl Instruction {
let cycles: Cycles; let cycles: Cycles;
match reg { match reg {
InstrRegister::B => { InstrRegister::B
let b = cpu.register(Register::B); | InstrRegister::C
cpu.set_register(Register::B, Self::dec_register(b, &mut flags)); | InstrRegister::D
cycles = Cycles(4); | InstrRegister::E
} | InstrRegister::H
InstrRegister::C => { | InstrRegister::L
let c = cpu.register(Register::C); | InstrRegister::A => {
cpu.set_register(Register::C, Self::dec_register(c, &mut flags)); let reg = Register::try_from(reg).unwrap();
cycles = Cycles(4);
} let value = cpu.register(reg);
InstrRegister::D => { cpu.set_register(reg, Self::dec_register(value, &mut flags));
let d = cpu.register(Register::D);
cpu.set_register(Register::D, Self::dec_register(d, &mut flags));
cycles = Cycles(4);
}
InstrRegister::E => {
let e = cpu.register(Register::E);
cpu.set_register(Register::E, Self::dec_register(e, &mut flags));
cycles = Cycles(4);
}
InstrRegister::H => {
let h = cpu.register(Register::H);
cpu.set_register(Register::H, Self::dec_register(h, &mut flags));
cycles = Cycles(4);
}
InstrRegister::L => {
let l = cpu.register(Register::L);
cpu.set_register(Register::L, Self::dec_register(l, &mut flags));
cycles = Cycles(4); cycles = Cycles(4);
} }
InstrRegister::IndirectHL => { InstrRegister::IndirectHL => {
@ -377,11 +281,6 @@ impl Instruction {
cpu.write_byte(addr, Self::dec_register(cpu.read_byte(addr), &mut flags)); cpu.write_byte(addr, Self::dec_register(cpu.read_byte(addr), &mut flags));
cycles = Cycles(12); cycles = Cycles(12);
} }
InstrRegister::A => {
let a = cpu.register(Register::A);
cpu.set_register(Register::A, Self::dec_register(a, &mut flags));
cycles = Cycles(4);
}
InstrRegister::IndirectC => unreachable!(), InstrRegister::IndirectC => unreachable!(),
} }
cpu.set_register(Register::Flag, flags.into()); cpu.set_register(Register::Flag, flags.into());
@ -732,16 +631,20 @@ impl Instruction {
unimplemented!() unimplemented!()
} }
} }
#[derive(Debug, Copy, Clone)]
pub enum JPTarget { pub enum JPTarget {
RegisterPair(RegisterPair), RegisterPair(RegisterPair),
ImmediateWord(u16), ImmediateWord(u16),
} }
#[derive(Debug, Copy, Clone)]
pub enum Registers { pub enum Registers {
Byte(InstrRegister), Byte(InstrRegister),
Word(RegisterPair), Word(RegisterPair),
} }
#[derive(Debug, Copy, Clone)]
pub enum MATHTarget { pub enum MATHTarget {
HL, HL,
SP, SP,
@ -750,6 +653,7 @@ pub enum MATHTarget {
ImmediateByte(u8), ImmediateByte(u8),
} }
#[derive(Debug, Copy, Clone)]
pub enum LDTarget { pub enum LDTarget {
Register(InstrRegister), Register(InstrRegister),
IndirectRegister(InstrRegisterPair), IndirectRegister(InstrRegisterPair),
@ -759,6 +663,7 @@ pub enum LDTarget {
RegisterPair(RegisterPair), RegisterPair(RegisterPair),
} }
#[derive(Debug, Copy, Clone)]
enum InstrRegisterPair { enum InstrRegisterPair {
AF, AF,
BC, BC,
@ -770,6 +675,41 @@ enum InstrRegisterPair {
DecrementHL, DecrementHL,
} }
impl From<RegisterPair> for InstrRegisterPair {
fn from(pair: RegisterPair) -> Self {
match pair {
RegisterPair::AF => Self::AF,
RegisterPair::BC => Self::BC,
RegisterPair::DE => Self::DE,
RegisterPair::HL => Self::HL,
RegisterPair::SP => Self::SP,
RegisterPair::PC => Self::PC,
}
}
}
impl TryFrom<InstrRegisterPair> for RegisterPair {
type Error = String; // FIXME: Proper error type goes here.
fn try_from(pair: InstrRegisterPair) -> Result<Self, Self::Error> {
match pair {
InstrRegisterPair::AF => Ok(Self::AF),
InstrRegisterPair::BC => Ok(Self::BC),
InstrRegisterPair::DE => Ok(Self::DE),
InstrRegisterPair::HL => Ok(Self::HL),
InstrRegisterPair::SP => Ok(Self::SP),
InstrRegisterPair::PC => Ok(Self::PC),
InstrRegisterPair::IncrementHL => {
Err("Can not convert InstrRegisterPair::IncrementHL to RegisterPair".to_string())
}
InstrRegisterPair::DecrementHL => {
Err("Can not convert InstrRegisterPair::DecrementHL to RegisterPair".to_string())
}
}
}
}
#[derive(Debug, Copy, Clone)]
enum InstrRegister { enum InstrRegister {
A, A,
B, B,
@ -782,6 +722,46 @@ enum InstrRegister {
IndirectC, // (0xFF00 + C) IndirectC, // (0xFF00 + C)
} }
impl TryFrom<Register> for InstrRegister {
type Error = String; // FIXME: Proper error type goes here
fn try_from(register: Register) -> Result<Self, Self::Error> {
match register {
Register::A => Ok(Self::A),
Register::B => Ok(Self::B),
Register::C => Ok(Self::C),
Register::D => Ok(Self::D),
Register::E => Ok(Self::E),
Register::H => Ok(Self::H),
Register::L => Ok(Self::L),
Register::Flag => Err("Can not convert Register::Flag to InstrRegister".to_string()),
}
}
}
impl TryFrom<InstrRegister> for Register {
type Error = String; // FIXME: Proper error type goes here.
fn try_from(register: InstrRegister) -> Result<Self, Self::Error> {
match register {
InstrRegister::A => Ok(Self::A),
InstrRegister::B => Ok(Self::B),
InstrRegister::C => Ok(Self::C),
InstrRegister::D => Ok(Self::D),
InstrRegister::E => Ok(Self::E),
InstrRegister::H => Ok(Self::H),
InstrRegister::L => Ok(Self::L),
InstrRegister::IndirectHL => {
Err("Can not convert InstrRegister::IndirectHL to Register".to_string())
}
InstrRegister::IndirectC => {
Err("Can not convert InstrRegister::IndirectC to Register".to_string())
}
}
}
}
#[derive(Debug, Copy, Clone)]
pub enum JumpCondition { pub enum JumpCondition {
NotZero, NotZero,
Zero, Zero,
@ -790,6 +770,7 @@ pub enum JumpCondition {
Always, Always,
} }
#[derive(Debug, Copy, Clone)]
struct Table; struct Table;
impl Table { impl Table {