Compare commits

..

No commits in common. "c4226e6e767fb711ded4e0f70a5d73731db01019" and "865c11d53c76114b3587f11ff073a2c57543a2b6" have entirely different histories.

3 changed files with 117 additions and 128 deletions

View File

@ -4,6 +4,5 @@
"tamasfe.even-better-toml", "tamasfe.even-better-toml",
"serayuzgur.crates", "serayuzgur.crates",
"vadimcn.vscode-lldb", "vadimcn.vscode-lldb",
"donaldhays.rgbds-z80"
] ]
} }

View File

@ -73,15 +73,12 @@ impl Cpu {
/// ///
/// If opcode == 0xCB, then decoding costs 4 cycles. /// If opcode == 0xCB, then decoding costs 4 cycles.
/// Otherwise, decoding is free /// Otherwise, decoding is free
pub(crate) fn decode(&mut self, mut opcode: u8) -> Instruction { pub(crate) fn decode(&mut self, opcode: u8) -> Instruction {
let instr = if opcode == 0xCB { if opcode == 0xCB {
opcode = self.fetch(); Instruction::decode(self.fetch(), true)
Instruction::decode(opcode, true)
} else { } else {
Instruction::decode(opcode, false) Instruction::decode(opcode, false)
}; }
instr.unwrap_or_else(|| panic!("{:#04X} is an invalid instruction", opcode))
} }
/// Execute an [Instruction]. /// Execute an [Instruction].
@ -366,15 +363,12 @@ impl Cpu {
} }
fn _dbg_instr(&self) -> Instruction { fn _dbg_instr(&self) -> Instruction {
let mut byte = self.read_byte(self.reg.pc); let byte = self.read_byte(self.reg.pc);
let instr = if byte == 0xCB { if byte == 0xCB {
byte = self.read_byte(self.reg.pc + 1); Instruction::decode(self.read_byte(self.reg.pc + 1), true)
Instruction::decode(byte, true)
} else { } else {
Instruction::decode(byte, false) Instruction::decode(byte, false)
}; }
instr.unwrap_or_else(|| panic!("{:#04X} is an invalid instruction", byte))
} }
} }
@ -524,6 +518,9 @@ pub(crate) mod dbg {
} }
pub(crate) fn ime(cpu: &Cpu) -> bool { pub(crate) fn ime(cpu: &Cpu) -> bool {
matches!(cpu.ime, ImeState::Enabled) match cpu.ime {
ImeState::Enabled => true,
_ => false,
}
} }
} }

View File

@ -1,6 +1,6 @@
use self::add::{Source as AddSource, Target as AddTarget}; use self::add::{Source as AddSource, Target as AddTarget};
use self::alu::Source as AluSource; use self::alu::Source as AluSource;
use self::jump::{JpCond, JpLoc}; use self::jump::{JumpCondition, JumpLocation};
use self::load::{Source as LDSource, Target as LDTarget}; use self::load::{Source as LDSource, Target as LDTarget};
use self::table::{ use self::table::{
alu_imm_instr, alu_reg_instr, flag_instr, group1, group2, group3, jump_cond, prefix_alu, alu_imm_instr, alu_reg_instr, flag_instr, group1, group2, group3, jump_cond, prefix_alu,
@ -16,7 +16,7 @@ use crate::Cycle;
pub(crate) enum Instruction { pub(crate) enum Instruction {
NOP, NOP,
STOP, STOP,
JR(JpCond), JR(JumpCondition),
LD(LDTarget, LDSource), LD(LDTarget, LDSource),
ADD(AddTarget, AddSource), ADD(AddTarget, AddSource),
LDHL, LDHL,
@ -38,13 +38,13 @@ pub(crate) enum Instruction {
XOR(AluSource), XOR(AluSource),
OR(AluSource), OR(AluSource),
CP(AluSource), CP(AluSource),
RET(JpCond), RET(JumpCondition),
POP(Group3RegisterPair), POP(Group3RegisterPair),
RETI, RETI,
JP(JpCond, JpLoc), JP(JumpCondition, JumpLocation),
DI, DI,
EI, EI,
CALL(JpCond), CALL(JumpCondition),
PUSH(Group3RegisterPair), PUSH(Group3RegisterPair),
RST(u8), RST(u8),
RLC(Register), RLC(Register),
@ -293,7 +293,7 @@ impl Instruction {
let addr = pc.wrapping_add(byte as u16); let addr = pc.wrapping_add(byte as u16);
match cond { match cond {
JpCond::NotZero => { JumpCondition::NotZero => {
if !flags.z() { if !flags.z() {
Self::jump(cpu, addr); Self::jump(cpu, addr);
12 12
@ -301,7 +301,7 @@ impl Instruction {
8 8
} }
} }
JpCond::Zero => { JumpCondition::Zero => {
if flags.z() { if flags.z() {
Self::jump(cpu, addr); Self::jump(cpu, addr);
12 12
@ -309,7 +309,7 @@ impl Instruction {
8 8
} }
} }
JpCond::NotCarry => { JumpCondition::NotCarry => {
if !flags.c() { if !flags.c() {
Self::jump(cpu, addr); Self::jump(cpu, addr);
12 12
@ -317,7 +317,7 @@ impl Instruction {
8 8
} }
} }
JpCond::Carry => { JumpCondition::Carry => {
if flags.c() { if flags.c() {
Self::jump(cpu, addr); Self::jump(cpu, addr);
12 12
@ -325,7 +325,7 @@ impl Instruction {
8 8
} }
} }
JpCond::Always => { JumpCondition::Always => {
Self::jump(cpu, addr); Self::jump(cpu, addr);
12 12
} }
@ -837,7 +837,7 @@ impl Instruction {
let flags: Flags = *cpu.flags(); let flags: Flags = *cpu.flags();
match cond { match cond {
JpCond::NotZero => { JumpCondition::NotZero => {
cpu.bus.clock(); // internal branch decision cpu.bus.clock(); // internal branch decision
if !flags.z() { if !flags.z() {
@ -848,7 +848,7 @@ impl Instruction {
8 8
} }
} }
JpCond::Zero => { JumpCondition::Zero => {
cpu.bus.clock(); // internal branch decision cpu.bus.clock(); // internal branch decision
if flags.z() { if flags.z() {
@ -859,7 +859,7 @@ impl Instruction {
8 8
} }
} }
JpCond::NotCarry => { JumpCondition::NotCarry => {
cpu.bus.clock(); // internal branch decision cpu.bus.clock(); // internal branch decision
if !flags.c() { if !flags.c() {
@ -870,7 +870,7 @@ impl Instruction {
8 8
} }
} }
JpCond::Carry => { JumpCondition::Carry => {
cpu.bus.clock(); // internal branch decision cpu.bus.clock(); // internal branch decision
if flags.c() { if flags.c() {
@ -881,7 +881,7 @@ impl Instruction {
8 8
} }
} }
JpCond::Always => { JumpCondition::Always => {
let addr = Self::pop(cpu); let addr = Self::pop(cpu);
Self::jump(cpu, addr); Self::jump(cpu, addr);
16 16
@ -908,13 +908,13 @@ impl Instruction {
16 16
} }
Instruction::JP(cond, location) => match location { Instruction::JP(cond, location) => match location {
JpLoc::HL => { JumpLocation::HL => {
// JP HL | Store HL in program counter // JP HL | Store HL in program counter
let right = cpu.register_pair(RegisterPair::HL); let right = cpu.register_pair(RegisterPair::HL);
cpu.set_register_pair(RegisterPair::PC, right); cpu.set_register_pair(RegisterPair::PC, right);
4 4
} }
JpLoc::ImmediateWord => { JumpLocation::ImmediateWord => {
// JP cond u16 | Store u16 in program counter if condition is true // JP cond u16 | Store u16 in program counter if condition is true
// JP u16 | Store u16 in program counter // JP u16 | Store u16 in program counter
let flags: Flags = *cpu.flags(); let flags: Flags = *cpu.flags();
@ -922,7 +922,7 @@ impl Instruction {
let addr = Self::imm_word(cpu); let addr = Self::imm_word(cpu);
match cond { match cond {
JpCond::NotZero => { JumpCondition::NotZero => {
if !flags.z() { if !flags.z() {
Self::jump(cpu, addr); Self::jump(cpu, addr);
16 16
@ -930,7 +930,7 @@ impl Instruction {
12 12
} }
} }
JpCond::Zero => { JumpCondition::Zero => {
if flags.z() { if flags.z() {
Self::jump(cpu, addr); Self::jump(cpu, addr);
16 16
@ -938,7 +938,7 @@ impl Instruction {
12 12
} }
} }
JpCond::NotCarry => { JumpCondition::NotCarry => {
if !flags.c() { if !flags.c() {
Self::jump(cpu, addr); Self::jump(cpu, addr);
16 16
@ -946,7 +946,7 @@ impl Instruction {
12 12
} }
} }
JpCond::Carry => { JumpCondition::Carry => {
if flags.c() { if flags.c() {
Self::jump(cpu, addr); Self::jump(cpu, addr);
16 16
@ -954,7 +954,7 @@ impl Instruction {
12 12
} }
} }
JpCond::Always => { JumpCondition::Always => {
Self::jump(cpu, addr); Self::jump(cpu, addr);
16 16
} }
@ -980,7 +980,7 @@ impl Instruction {
let return_addr = cpu.register_pair(RegisterPair::PC); let return_addr = cpu.register_pair(RegisterPair::PC);
match cond { match cond {
JpCond::NotZero => { JumpCondition::NotZero => {
if !flags.z() { if !flags.z() {
cpu.bus.clock(); // internal branch decision cpu.bus.clock(); // internal branch decision
Self::push(cpu, return_addr); Self::push(cpu, return_addr);
@ -990,7 +990,7 @@ impl Instruction {
12 12
} }
} }
JpCond::Zero => { JumpCondition::Zero => {
if flags.z() { if flags.z() {
cpu.bus.clock(); // internal branch decision cpu.bus.clock(); // internal branch decision
Self::push(cpu, return_addr); Self::push(cpu, return_addr);
@ -1000,7 +1000,7 @@ impl Instruction {
12 12
} }
} }
JpCond::NotCarry => { JumpCondition::NotCarry => {
if !flags.c() { if !flags.c() {
cpu.bus.clock(); // internal branch decision cpu.bus.clock(); // internal branch decision
Self::push(cpu, return_addr); Self::push(cpu, return_addr);
@ -1010,7 +1010,7 @@ impl Instruction {
12 12
} }
} }
JpCond::Carry => { JumpCondition::Carry => {
if flags.c() { if flags.c() {
cpu.bus.clock(); // internal branch decision cpu.bus.clock(); // internal branch decision
Self::push(cpu, return_addr); Self::push(cpu, return_addr);
@ -1020,7 +1020,7 @@ impl Instruction {
12 12
} }
} }
JpCond::Always => { JumpCondition::Always => {
cpu.bus.clock(); // internal branch decision cpu.bus.clock(); // internal branch decision
Self::push(cpu, return_addr); Self::push(cpu, return_addr);
cpu.set_register_pair(RegisterPair::PC, addr); cpu.set_register_pair(RegisterPair::PC, addr);
@ -1538,7 +1538,7 @@ impl Instruction {
} }
impl Instruction { impl Instruction {
pub(crate) fn decode(byte: u8, prefixed: bool) -> Option<Self> { pub(crate) fn decode(byte: u8, prefixed: bool) -> Self {
if prefixed { if prefixed {
Self::prefixed(byte) Self::prefixed(byte)
} else { } else {
@ -1546,139 +1546,134 @@ impl Instruction {
} }
} }
fn unprefixed(byte: u8) -> Option<Self> { fn unprefixed(byte: u8) -> Self {
use Instruction::*; use Instruction::*;
match byte { match byte {
// NOP // NOP
0o000 => Some(NOP), 0o000 => NOP,
// LD (u16), SP // LD (u16), SP
0o010 => Some(LD(LDTarget::IndirectImmediateWord, LDSource::SP)), 0o010 => LD(LDTarget::IndirectImmediateWord, LDSource::SP),
// STOP // STOP
0o020 => Some(STOP), 0o020 => STOP,
// JR i8 // JR i8
0o030 => Some(JR(JpCond::Always)), 0o030 => JR(JumpCondition::Always),
// JR cond i8 // JR cond i8
0o040 | 0o050 | 0o060 | 0o070 => Some(JR(jump_cond((byte >> 3) & 0x03))), 0o040 | 0o050 | 0o060 | 0o070 => JR(jump_cond((byte >> 3) & 0x03)),
// LD r16, u16 // LD r16, u16
0o001 | 0o021 | 0o041 | 0o061 => Some(LD( 0o001 | 0o021 | 0o041 | 0o061 => LD(
LDTarget::Group1(group1((byte >> 4) & 0x03)), LDTarget::Group1(group1((byte >> 4) & 0x03)),
LDSource::ImmediateWord, LDSource::ImmediateWord,
)), ),
// ADD HL, r16 // ADD HL, r16
0o011 | 0o031 | 0o051 | 0o071 => Some(ADD( 0o011 | 0o031 | 0o051 | 0o071 => {
AddTarget::HL, ADD(AddTarget::HL, AddSource::Group1(group1((byte >> 4) & 0x03)))
AddSource::Group1(group1((byte >> 4) & 0x03)), }
)),
// LD (r16), A // LD (r16), A
0o002 | 0o022 | 0o042 | 0o062 => Some(LD( 0o002 | 0o022 | 0o042 | 0o062 => LD(
LDTarget::IndirectGroup2(group2((byte >> 4) & 0x03)), LDTarget::IndirectGroup2(group2((byte >> 4) & 0x03)),
LDSource::A, LDSource::A,
)), ),
// LD A, (r16) // LD A, (r16)
0o012 | 0o032 | 0o052 | 0o072 => Some(LD( 0o012 | 0o032 | 0o052 | 0o072 => LD(
LDTarget::A, LDTarget::A,
LDSource::IndirectGroup2(group2((byte >> 4) & 0x03)), LDSource::IndirectGroup2(group2((byte >> 4) & 0x03)),
)), ),
// INC r16 // INC r16
0o003 | 0o023 | 0o043 | 0o063 => { 0o003 | 0o023 | 0o043 | 0o063 => INC(AllRegisters::Group1(group1((byte >> 4) & 0x03))),
Some(INC(AllRegisters::Group1(group1((byte >> 4) & 0x03))))
}
// DEC r16 // DEC r16
0o013 | 0o033 | 0o053 | 0o073 => { 0o013 | 0o033 | 0o053 | 0o073 => DEC(AllRegisters::Group1(group1((byte >> 4) & 0x03))),
Some(DEC(AllRegisters::Group1(group1((byte >> 4) & 0x03))))
}
// INC r8 // INC r8
0o004 | 0o014 | 0o024 | 0o034 | 0o044 | 0o054 | 0o064 | 0o074 => { 0o004 | 0o014 | 0o024 | 0o034 | 0o044 | 0o054 | 0o064 | 0o074 => {
Some(INC(AllRegisters::Register(register((byte >> 3) & 0x07)))) INC(AllRegisters::Register(register((byte >> 3) & 0x07)))
} }
// DEC r8 // DEC r8
0o005 | 0o015 | 0o025 | 0o035 | 0o045 | 0o055 | 0o065 | 0o075 => { 0o005 | 0o015 | 0o025 | 0o035 | 0o045 | 0o055 | 0o065 | 0o075 => {
Some(DEC(AllRegisters::Register(register((byte >> 3) & 0x07)))) DEC(AllRegisters::Register(register((byte >> 3) & 0x07)))
} }
// LD r8, u8 // LD r8, u8
0o006 | 0o016 | 0o026 | 0o036 | 0o046 | 0o056 | 0o066 | 0o076 => Some(LD( 0o006 | 0o016 | 0o026 | 0o036 | 0o046 | 0o056 | 0o066 | 0o076 => LD(
LDTarget::Register(register((byte >> 3) & 0x07)), LDTarget::Register(register((byte >> 3) & 0x07)),
LDSource::ImmediateByte, LDSource::ImmediateByte,
)), ),
// RLCA, RRCA, RLA, RRA, DAA, CPL, SCF, and CCF // RLCA, RRCA, RLA, RRA, DAA, CPL, SCF, and CCF
0o007 | 0o017 | 0o027 | 0o037 | 0o047 | 0o057 | 0o067 | 0o077 => { 0o007 | 0o017 | 0o027 | 0o037 | 0o047 | 0o057 | 0o067 | 0o077 => {
Some(flag_instr((byte >> 3) & 0x07)) flag_instr((byte >> 3) & 0x07)
} }
// HALT // HALT
0o166 => Some(HALT), 0o166 => HALT,
// LD r8, r8 // LD r8, r8
0o100..=0o177 => Some(LD( 0o100..=0o177 => LD(
LDTarget::Register(register((byte >> 3) & 0x07)), LDTarget::Register(register((byte >> 3) & 0x07)),
LDSource::Register(register(byte & 0x07)), LDSource::Register(register(byte & 0x07)),
)), ),
// ADD, ADC, SUB, SBC, AND, XOR, OR, and CP // ADD, ADC, SUB, SBC, AND, XOR, OR, and CP
0o200..=0o277 => Some(alu_reg_instr((byte >> 3) & 0x07, byte & 0x07)), 0o200..=0o277 => alu_reg_instr((byte >> 3) & 0x07, byte & 0x07),
// RET cond // RET cond
0o300 | 0o310 | 0o320 | 0o330 => Some(RET(jump_cond((byte >> 3) & 0x03))), 0o300 | 0o310 | 0o320 | 0o330 => RET(jump_cond((byte >> 3) & 0x03)),
// LD (0xFF00 + u8), A // LD (0xFF00 + u8), A
0o340 => Some(LD(LDTarget::IoWithImmediateOffset, LDSource::A)), 0o340 => LD(LDTarget::IoWithImmediateOffset, LDSource::A),
// ADD SP, i8 // ADD SP, i8
0o350 => Some(ADD(AddTarget::SP, AddSource::ImmediateSignedByte)), 0o350 => ADD(AddTarget::SP, AddSource::ImmediateSignedByte),
// LD A, (0xFF00 + u8) // LD A, (0xFF00 + u8)
0o360 => Some(LD(LDTarget::A, LDSource::IoWithImmediateOffset)), 0o360 => LD(LDTarget::A, LDSource::IoWithImmediateOffset),
// LD HL, SP + i8 // LD HL, SP + i8
0o370 => Some(LDHL), 0o370 => LDHL,
// POP r16 // POP r16
0o301 | 0o321 | 0o341 | 0o361 => Some(POP(group3((byte >> 4) & 0x03))), 0o301 | 0o321 | 0o341 | 0o361 => POP(group3((byte >> 4) & 0x03)),
// RET // RET
0o311 => Some(RET(JpCond::Always)), 0o311 => RET(JumpCondition::Always),
// RETI // RETI
0o331 => Some(RETI), 0o331 => RETI,
// JP HL // JP HL
0o351 => Some(JP(JpCond::Always, JpLoc::HL)), 0o351 => JP(JumpCondition::Always, JumpLocation::HL),
// LD SP, HL // LD SP, HL
0o371 => Some(LD(LDTarget::SP, LDSource::HL)), 0o371 => LD(LDTarget::SP, LDSource::HL),
// JP cond u16 // JP cond u16
0o302 | 0o312 | 0o322 | 0o332 => { 0o302 | 0o312 | 0o322 | 0o332 => {
Some(JP(jump_cond((byte >> 3) & 0x03), JpLoc::ImmediateWord)) JP(jump_cond((byte >> 3) & 0x03), JumpLocation::ImmediateWord)
} }
// LD (0xFF00 + C), A // LD (0xFF00 + C), A
0o342 => Some(LD(LDTarget::IoWithC, LDSource::A)), 0o342 => LD(LDTarget::IoWithC, LDSource::A),
// LD (u16), A // LD (u16), A
0o352 => Some(LD(LDTarget::IndirectImmediateWord, LDSource::A)), 0o352 => LD(LDTarget::IndirectImmediateWord, LDSource::A),
// LD A, (0xFF00 + C) // LD A, (0xFF00 + C)
0o362 => Some(LD(LDTarget::A, LDSource::IoWithC)), 0o362 => LD(LDTarget::A, LDSource::IoWithC),
// LD A, (u16) // LD A, (u16)
0o372 => Some(LD(LDTarget::A, LDSource::IndirectImmediateWord)), 0o372 => LD(LDTarget::A, LDSource::IndirectImmediateWord),
// JP u16 // JP u16
0o303 => Some(JP(JpCond::Always, JpLoc::ImmediateWord)), 0o303 => JP(JumpCondition::Always, JumpLocation::ImmediateWord),
// 0xCB Prefix
0o313 => unreachable!("{:#04X} should be handled by the prefixed decoder", byte),
// DI // DI
0o363 => Some(DI), 0o363 => DI,
// EI // EI
0o373 => Some(EI), 0o373 => EI,
// CALL cond u16 // CALL cond u16
0o304 | 0o314 | 0o324 | 0o334 => Some(CALL(jump_cond((byte >> 3) & 0x03))), 0o304 | 0o314 | 0o324 | 0o334 => CALL(jump_cond((byte >> 3) & 0x03)),
// PUSH r16 // PUSH r16
0o305 | 0o325 | 0o345 | 0o365 => Some(PUSH(group3((byte >> 4) & 0x03))), 0o305 | 0o325 | 0o345 | 0o365 => PUSH(group3((byte >> 4) & 0x03)),
0o315 => Some(CALL(JpCond::Always)), 0o315 => CALL(JumpCondition::Always),
0o306 | 0o316 | 0o326 | 0o336 | 0o346 | 0o356 | 0o366 | 0o376 => { 0o306 | 0o316 | 0o326 | 0o336 | 0o346 | 0o356 | 0o366 | 0o376 => {
Some(alu_imm_instr((byte >> 3) & 0x07)) alu_imm_instr((byte >> 3) & 0x07)
} }
0o307 | 0o317 | 0o327 | 0o337 | 0o347 | 0o357 | 0o367 | 0o377 => { 0o307 | 0o317 | 0o327 | 0o337 | 0o347 | 0o357 | 0o367 | 0o377 => RST(byte & 0b00111000),
Some(RST(byte & 0b00111000)) _ => panic!("{:#04X} is an illegal opcode", byte),
}
_ => None, // 0xCB is 0o313
} }
} }
fn prefixed(byte: u8) -> Option<Self> { fn prefixed(byte: u8) -> Self {
use Instruction::*; use Instruction::*;
match byte { match byte {
// RLC, RRC, RL, RR, SLA, SRA, SWAP and SRL // RLC, RRC, RL, RR, SLA, SRA, SWAP and SRL
0o000..=0o077 => Some(prefix_alu((byte >> 3) & 0x07, byte & 0x07)), 0o000..=0o077 => prefix_alu((byte >> 3) & 0x07, byte & 0x07),
// BIT bit, r8 // BIT bit, r8
0o100..=0o177 => Some(BIT((byte >> 3) & 0x07, register(byte & 0x07))), 0o100..=0o177 => BIT((byte >> 3) & 0x07, register(byte & 0x07)),
// RES bit, r8 // RES bit, r8
0o200..=0o277 => Some(RES((byte >> 3) & 0x07, register(byte & 0x07))), 0o200..=0o277 => RES((byte >> 3) & 0x07, register(byte & 0x07)),
// SET bit, r8 // SET bit, r8
0o300..=0o377 => Some(SET((byte >> 3) & 0x07, register(byte & 0x07))), 0o300..=0o377 => SET((byte >> 3) & 0x07, register(byte & 0x07)),
} }
} }
} }
@ -1686,7 +1681,7 @@ impl Instruction {
mod jump { mod jump {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub(crate) enum JpCond { pub(crate) enum JumpCondition {
Always, Always,
NotZero, NotZero,
Zero, Zero,
@ -1694,9 +1689,9 @@ mod jump {
Carry, Carry,
} }
impl std::fmt::Debug for JpCond { impl std::fmt::Debug for JumpCondition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use JpCond::*; use JumpCondition::*;
match self { match self {
Always => f.write_str(""), Always => f.write_str(""),
@ -1709,14 +1704,14 @@ mod jump {
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub(crate) enum JpLoc { pub(crate) enum JumpLocation {
HL, HL,
ImmediateWord, ImmediateWord,
} }
impl std::fmt::Debug for JpLoc { impl std::fmt::Debug for JumpLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use JpLoc::*; use JumpLocation::*;
match *self { match *self {
HL => f.write_str("HL"), HL => f.write_str("HL"),
@ -1876,7 +1871,7 @@ mod load {
mod table { mod table {
use super::add::{Source as AddSource, Target as AddTarget}; use super::add::{Source as AddSource, Target as AddTarget};
use super::alu::Source as AluSource; use super::alu::Source as AluSource;
use super::{Instruction, JpCond}; use super::{Instruction, JumpCondition};
use crate::cpu::{Register as CpuRegister, RegisterPair}; use crate::cpu::{Register as CpuRegister, RegisterPair};
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -2079,8 +2074,8 @@ mod table {
} }
} }
pub(crate) fn jump_cond(code: u8) -> JpCond { pub(crate) fn jump_cond(code: u8) -> JumpCondition {
use JpCond::*; use JumpCondition::*;
match code { match code {
0b00 => NotZero, 0b00 => NotZero,
@ -2158,7 +2153,7 @@ mod table {
pub(crate) mod dbg { pub(crate) mod dbg {
use super::add::{Source as AddSource, Target as AddTarget}; use super::add::{Source as AddSource, Target as AddTarget};
use super::jump::JpCond; use super::jump::JumpCondition;
use super::load::{Source as LDSource, Target as LDTarget}; use super::load::{Source as LDSource, Target as LDTarget};
use super::{AllRegisters, BusIo, Cpu, Instruction, RegisterPair}; use super::{AllRegisters, BusIo, Cpu, Instruction, RegisterPair};
@ -2170,7 +2165,7 @@ pub(crate) mod dbg {
let opcode = cpu.read_byte(pc); let opcode = cpu.read_byte(pc);
pc += 1; pc += 1;
let maybe_instr = if opcode == 0xCB { let instr = if opcode == 0xCB {
let opcode = cpu.read_byte(pc); let opcode = cpu.read_byte(pc);
pc += 1; pc += 1;
@ -2179,12 +2174,10 @@ pub(crate) mod dbg {
Instruction::unprefixed(opcode) Instruction::unprefixed(opcode)
}; };
if let Some(instr) = maybe_instr { let instr_asm = format!("{:04X} {:?}\n", pc - 1, instr);
let instr_asm = format!("{:04X} {:?}\n", pc - 1, instr); asm.push_str(&instr_asm);
asm.push_str(&instr_asm);
pc += delta::pc_inc_count(instr) pc += delta::pc_inc_count(instr)
}
} }
asm asm
@ -2197,12 +2190,12 @@ pub(crate) mod dbg {
let imm_word = (cpu.read_byte(pc + 2) as u16) << 8 | imm_byte as u16; let imm_word = (cpu.read_byte(pc + 2) as u16) << 8 | imm_byte as u16;
match instr { match instr {
NOP => "NOP".to_string(), NOP => format!("NOP"),
LD(LDTarget::IndirectImmediateWord, LDSource::SP) => { LD(LDTarget::IndirectImmediateWord, LDSource::SP) => {
format!("LD ({:#06X}), SP", imm_word) format!("LD ({:#06X}), SP", imm_word)
} }
STOP => "STOP".to_string(), STOP => format!("STOP"),
JR(JpCond::Always) => format!("JR {}", imm_byte as i8), JR(JumpCondition::Always) => format!("JR {}", imm_byte as i8),
JR(cond) => format!("JR {:?} {}", cond, imm_byte as i8), JR(cond) => format!("JR {:?} {}", cond, imm_byte as i8),
LD(LDTarget::Group1(rp), LDSource::ImmediateWord) => { LD(LDTarget::Group1(rp), LDSource::ImmediateWord) => {
format!("LD {:?} {:#06X}", rp, imm_word) format!("LD {:?} {:#06X}", rp, imm_word)
@ -2218,7 +2211,7 @@ pub(crate) mod dbg {
mod delta { mod delta {
use super::super::add::{Source as AddSource, Target as AddTarget}; use super::super::add::{Source as AddSource, Target as AddTarget};
use super::super::alu::Source as AluSource; use super::super::alu::Source as AluSource;
use super::super::jump::{JpCond, JpLoc}; use super::super::jump::{JumpCondition, JumpLocation};
use super::super::load::{Source as LDSource, Target as LDTarget}; use super::super::load::{Source as LDSource, Target as LDTarget};
use super::super::{AllRegisters, Instruction}; use super::super::{AllRegisters, Instruction};
@ -2265,9 +2258,9 @@ pub(crate) mod dbg {
LDHL => 1, LDHL => 1,
POP(_) => 0, POP(_) => 0,
RETI => 0, RETI => 0,
JP(JpCond::Always, JpLoc::HL) => 0, JP(JumpCondition::Always, JumpLocation::HL) => 0,
LD(LDTarget::SP, LDSource::HL) => 0, LD(LDTarget::SP, LDSource::HL) => 0,
JP(_, JpLoc::ImmediateWord) => 2, JP(_, JumpLocation::ImmediateWord) => 2,
LD(LDTarget::IoWithC, LDSource::A) => 0, LD(LDTarget::IoWithC, LDSource::A) => 0,
LD(LDTarget::IndirectImmediateWord, LDSource::A) => 2, LD(LDTarget::IndirectImmediateWord, LDSource::A) => 2,
LD(LDTarget::A, LDSource::IoWithC) => 0, LD(LDTarget::A, LDSource::IoWithC) => 0,