From 3da58c8d177028023711c1724b9c159eb7cae373 Mon Sep 17 00:00:00 2001 From: transistor Date: Sat, 6 Nov 2021 15:08:03 -0700 Subject: [PATCH] Added decoding of more of the DD/FD instructions --- src/cpus/z80/decode.rs | 333 ++++++++++++++++++-------- src/cpus/z80/execute.rs | 507 ++++++++++++++++++++++++++-------------- src/cpus/z80/state.rs | 2 +- 3 files changed, 566 insertions(+), 276 deletions(-) diff --git a/src/cpus/z80/decode.rs b/src/cpus/z80/decode.rs index 6af59a5..d387a0d 100644 --- a/src/cpus/z80/decode.rs +++ b/src/cpus/z80/decode.rs @@ -30,6 +30,22 @@ pub enum RegisterPair { HL, AF, SP, + IX, + IY, +} + +#[derive(Copy, Clone, Debug)] +pub enum IndexRegister { + IX, + IY, +} + +#[derive(Copy, Clone, Debug)] +pub enum IndexRegisterHalf { + IXH, + IXL, + IYH, + IYL, } #[derive(Copy, Clone, Debug)] @@ -41,16 +57,20 @@ pub enum SpecialRegister { #[derive(Copy, Clone, Debug)] pub enum Target { DirectReg(Register), + DirectRegHalf(IndexRegisterHalf), IndirectReg(RegisterPair), + IndirectOffset(IndexRegister, i8), Immediate(u8), } #[derive(Copy, Clone, Debug)] pub enum LoadTarget { DirectRegByte(Register), + DirectRegHalfByte(IndexRegisterHalf), DirectRegWord(RegisterPair), IndirectRegByte(RegisterPair), IndirectRegWord(RegisterPair), + IndirectOffsetByte(IndexRegister, i8), DirectAltRegByte(Register), DirectSpecialRegByte(SpecialRegister), IndirectByte(u16), @@ -59,98 +79,92 @@ pub enum LoadTarget { ImmediateWord(u16), } +pub type OptionalSource = Option<(IndexRegister, i8)>; + #[derive(Clone, Debug)] pub enum Instruction { ADCa(Target), - ADChl(RegisterPair), + ADC16(RegisterPair, RegisterPair), ADDa(Target), - ADDhl(RegisterPair), + ADD16(RegisterPair, RegisterPair), AND(Target), - CP(Target), - CPL, - NEG, - OR(Target), - SBCa(Target), - SBChl(RegisterPair), - SUB(Target), - XOR(Target), - BIT(u8, Target), - RES(u8, Target), - RL(Target), - RLC(Target), - RR(Target), - RRC(Target), - SET(u8, Target), - SLA(Target), - SLL(Target), - SRA(Target), - SRL(Target), - - DEC8(Target), - DEC16(RegisterPair), - INC8(Target), - INC16(RegisterPair), - - EXX, - EXafaf, - EXhlsp, - EXhlde, - LD(LoadTarget, LoadTarget), - POP(RegisterPair), - PUSH(RegisterPair), - - INx(u8), - INic(Register), - OUTx(u8), - OUTic(Register), - CALL(u16), CALLcc(Condition, u16), + CCF, + CP(Target), + CPD, + CPDR, + CPI, + CPIR, + CPL, + DAA, + DEC16(RegisterPair), + DEC8(Target), + DI, DJNZ(i8), + EI, + EXX, + EXafaf, + EXhlde, + EXhlsp, + HALT, + IM(u8), + INC16(RegisterPair), + INC8(Target), + IND, + INDR, + INI, + INIR, + INic(Register), + INx(u8), JP(u16), JPIndirectHL, JPcc(Condition, u16), JR(i8), JRcc(Condition, i8), - RET, - RETI, - RETN, - RETcc(Condition), - - DI, - EI, - IM(u8), - NOP, - HALT, - RST(u8), - - CCF, - DAA, - RLA, - RLCA, - RRA, - RRCA, - RRD, - RLD, - SCF, - - CPD, - CPDR, - CPI, - CPIR, - IND, - INDR, - INI, - INIR, + LD(LoadTarget, LoadTarget), LDD, LDDR, LDI, LDIR, + NEG, + NOP, + OR(Target), OTDR, OTIR, OUTD, OUTI, + OUTic(Register), + OUTx(u8), + POP(RegisterPair), + PUSH(RegisterPair), + RES(u8, Target, OptionalSource), + RET, + RETI, + RETN, + RETcc(Condition), + RL(Target, OptionalSource), + RLA, + RLC(Target, OptionalSource), + RLCA, + RLD, + RR(Target, OptionalSource), + RRA, + RRC(Target, OptionalSource), + RRCA, + RRD, + RST(u8), + SBCa(Target), + SBC16(RegisterPair, RegisterPair), + SCF, + SET(u8, Target, OptionalSource), + SLA(Target, OptionalSource), + SLL(Target, OptionalSource), + SRA(Target, OptionalSource), + SRL(Target, OptionalSource), + SUB(Target), + XOR(Target), } pub struct Z80Decoder { @@ -206,7 +220,7 @@ impl Z80Decoder { let data = self.read_instruction_word(memory)?; Ok(Instruction::LD(LoadTarget::DirectRegWord(get_register_pair(get_ins_p(ins))), LoadTarget::ImmediateWord(data))) } else { - Ok(Instruction::ADDhl(get_register_pair(get_ins_p(ins)))) + Ok(Instruction::ADD16(RegisterPair::HL, get_register_pair(get_ins_p(ins)))) } }, 2 => { @@ -216,7 +230,7 @@ impl Z80Decoder { true => LoadTarget::IndirectRegByte(RegisterPair::DE), }; - match (ins & 0x08) != 0 { + match get_ins_q(ins) != 0 { false => Ok(Instruction::LD(target, LoadTarget::DirectRegByte(Register::A))), true => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::A), target)), } @@ -224,8 +238,8 @@ impl Z80Decoder { let addr = self.read_instruction_word(memory)?; match (ins >> 3) & 0x03 { 0 => Ok(Instruction::LD(LoadTarget::IndirectWord(addr), LoadTarget::DirectRegWord(RegisterPair::HL))), - 1 => Ok(Instruction::LD(LoadTarget::IndirectByte(addr), LoadTarget::DirectRegByte(Register::A))), - 2 => Ok(Instruction::LD(LoadTarget::DirectRegWord(RegisterPair::HL), LoadTarget::IndirectWord(addr))), + 1 => Ok(Instruction::LD(LoadTarget::DirectRegWord(RegisterPair::HL), LoadTarget::IndirectWord(addr))), + 2 => Ok(Instruction::LD(LoadTarget::IndirectByte(addr), LoadTarget::DirectRegByte(Register::A))), 3 => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::A), LoadTarget::IndirectByte(addr))), _ => panic!("InternalError: impossible value"), } @@ -333,9 +347,9 @@ impl Z80Decoder { let addr = self.read_instruction_word(memory)?; Ok(Instruction::CALL(addr)) }, - 1 => self.decode_prefix_dd(memory), + 1 => self.decode_prefix_dd_fd(memory, IndexRegister::IX), 2 => self.decode_prefix_ed(memory), - 3 => self.decode_prefix_fd(memory), + 3 => self.decode_prefix_dd_fd(memory, IndexRegister::IY), _ => panic!("Undecoded Instruction"), } } @@ -357,16 +371,35 @@ impl Z80Decoder { pub fn decode_prefix_cb(&mut self, memory: &mut dyn Addressable) -> Result { let ins = self.read_instruction_byte(memory)?; match get_ins_x(ins) { - 0 => Ok(get_rot_instruction(get_ins_y(ins), get_register(get_ins_z(ins)))), + 0 => Ok(get_rot_instruction(get_ins_y(ins), get_register(get_ins_z(ins)), None)), 1 => Ok(Instruction::BIT(get_ins_y(ins), get_register(get_ins_z(ins)))), - 2 => Ok(Instruction::RES(get_ins_y(ins), get_register(get_ins_z(ins)))), - 3 => Ok(Instruction::SET(get_ins_y(ins), get_register(get_ins_z(ins)))), + 2 => Ok(Instruction::RES(get_ins_y(ins), get_register(get_ins_z(ins)), None)), + 3 => Ok(Instruction::SET(get_ins_y(ins), get_register(get_ins_z(ins)), None)), _ => panic!("InternalError: impossible value"), } } - pub fn decode_prefix_dd(&mut self, memory: &mut dyn Addressable) -> Result { - panic!("DD instructions unimplemented") + pub fn decode_sub_prefix_cb(&mut self, memory: &mut dyn Addressable, reg: IndexRegister) -> Result { + let ins = self.read_instruction_byte(memory)?; + match get_ins_x(ins) { + 0 => { + let opt_src = Some((reg, self.read_instruction_byte(memory)? as i8)); + Ok(get_rot_instruction(get_ins_y(ins), get_register(get_ins_z(ins)), opt_src)) + }, + 1 => { + let offset = self.read_instruction_byte(memory)? as i8; + Ok(Instruction::BIT(get_ins_y(ins), Target::IndirectOffset(reg, offset))) + }, + 2 => { + let opt_src = Some((reg, self.read_instruction_byte(memory)? as i8)); + Ok(Instruction::RES(get_ins_y(ins), get_register(get_ins_z(ins)), opt_src)) + }, + 3 => { + let opt_src = Some((reg, self.read_instruction_byte(memory)? as i8)); + Ok(Instruction::SET(get_ins_y(ins), get_register(get_ins_z(ins)), opt_src)) + }, + _ => panic!("InternalError: impossible value"), + } } pub fn decode_prefix_ed(&mut self, memory: &mut dyn Addressable) -> Result { @@ -396,9 +429,9 @@ impl Z80Decoder { }, 2 => { if get_ins_q(ins) == 0 { - Ok(Instruction::SBChl(get_register_pair(get_ins_p(ins)))) + Ok(Instruction::SBC16(RegisterPair::HL, get_register_pair(get_ins_p(ins)))) } else { - Ok(Instruction::ADChl(get_register_pair(get_ins_p(ins)))) + Ok(Instruction::ADC16(RegisterPair::HL, get_register_pair(get_ins_p(ins)))) } }, 3 => { @@ -462,8 +495,94 @@ impl Z80Decoder { } } - pub fn decode_prefix_fd(&mut self, memory: &mut dyn Addressable) -> Result { - panic!("FD instructions unimplemented") + pub fn decode_prefix_dd_fd(&mut self, memory: &mut dyn Addressable, index_reg: IndexRegister) -> Result { + let ins = self.read_instruction_byte(memory)?; + + if ins == 0xCB { + return self.decode_sub_prefix_cb(memory, index_reg); + } + + match get_ins_x(ins) { + 0 => { + if (ins & 0x0F) == 9 { + return Ok(Instruction::ADD16(RegisterPair::IX, get_register_pair_index(get_ins_p(ins), index_reg))); + } + + match get_ins_p(ins) { + 2 => { + match get_ins_z(ins) { + 1 => { + let data = self.read_instruction_word(memory)?; + Ok(Instruction::LD(LoadTarget::DirectRegWord(get_register_pair_from_index(index_reg)), LoadTarget::ImmediateWord(data))) + }, + 2 => { + let addr = self.read_instruction_word(memory)?; + let regpair = get_register_pair_from_index(index_reg); + match get_ins_q(ins) != 0 { + false => Ok(Instruction::LD(LoadTarget::IndirectWord(addr), LoadTarget::DirectRegWord(regpair))), + true => Ok(Instruction::LD(LoadTarget::DirectRegWord(regpair), LoadTarget::IndirectWord(addr))), + } + }, + 3 => { + match get_ins_q(ins) != 0 { + false => Ok(Instruction::INC16(get_register_pair_from_index(index_reg))), + true => Ok(Instruction::DEC16(get_register_pair_from_index(index_reg))), + } + }, + 4 => { + let half_target = Target::DirectRegHalf(get_index_register_half(index_reg, get_ins_q(ins))); + Ok(Instruction::INC8(half_target)) + }, + 5 => { + let half_target = Target::DirectRegHalf(get_index_register_half(index_reg, get_ins_q(ins))); + Ok(Instruction::DEC8(half_target)) + }, + 6 => { + let half_target = Target::DirectRegHalf(get_index_register_half(index_reg, get_ins_q(ins))); + let data = self.read_instruction_byte(memory)?; + Ok(Instruction::LD(to_load_target(half_target), LoadTarget::ImmediateByte(data))) + }, + _ => Ok(Instruction::NOP), + } + }, + 3 => { + let offset = self.read_instruction_byte(memory)? as i8; + match ins { + 0x34 => Ok(Instruction::INC8(Target::IndirectOffset(index_reg, offset))), + 0x35 => Ok(Instruction::DEC8(Target::IndirectOffset(index_reg, offset))), + 0x36 => Ok(Instruction::LD(LoadTarget::IndirectOffsetByte(index_reg, offset), LoadTarget::ImmediateByte(self.read_instruction_byte(memory)?))), + _ => Ok(Instruction::NOP), + } + }, + _ => Ok(Instruction::NOP), + } + }, + 1 => { + match get_ins_y(ins) { + 4 => { + /* + match get_ins_z(ins) { + 6 => { + let offset = self.read_instruction_byte(memory)?; + Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::H), LoadTarget::IndirectIndexByte(offset))) + }, + _ => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::IXH), to_load_target(get_register(get_ins_z(ins))))) + } + */ + panic!(""); + }, + _ => panic!("InternalError: impossible value"), + } + }, + 2 => { +panic!(""); + }, + 3 => { + +panic!(""); + }, + _ => panic!("InternalError: impossible value"), + } } @@ -507,16 +626,16 @@ fn get_alu_instruction(alu: u8, target: Target) -> Instruction { } } -fn get_rot_instruction(rot: u8, target: Target) -> Instruction { +fn get_rot_instruction(rot: u8, target: Target, opt_src: OptionalSource) -> Instruction { match rot { - 0 => Instruction::RLC(target), - 1 => Instruction::RRC(target), - 2 => Instruction::RL(target), - 3 => Instruction::RR(target), - 4 => Instruction::SLA(target), - 5 => Instruction::SRA(target), - 6 => Instruction::SLL(target), - 7 => Instruction::SRL(target), + 0 => Instruction::RLC(target, opt_src), + 1 => Instruction::RRC(target, opt_src), + 2 => Instruction::RL(target, opt_src), + 3 => Instruction::RR(target, opt_src), + 4 => Instruction::SLA(target, opt_src), + 5 => Instruction::SRA(target, opt_src), + 6 => Instruction::SLL(target, opt_src), + 7 => Instruction::SRL(target, opt_src), _ => panic!("InternalError: impossible value"), } } @@ -538,7 +657,9 @@ fn get_register(reg: u8) -> Target { fn to_load_target(target: Target) -> LoadTarget { match target { Target::DirectReg(reg) => LoadTarget::DirectRegByte(reg), + Target::DirectRegHalf(reg) => LoadTarget::DirectRegHalfByte(reg), Target::IndirectReg(reg) => LoadTarget::IndirectRegByte(reg), + Target::IndirectOffset(reg, offset) => LoadTarget::IndirectOffsetByte(reg, offset), Target::Immediate(data) => LoadTarget::ImmediateByte(data), } } @@ -553,6 +674,16 @@ fn get_register_pair(reg: u8) -> RegisterPair { } } +fn get_register_pair_index(reg: u8, index_reg: IndexRegister) -> RegisterPair { + match reg { + 0 => RegisterPair::BC, + 1 => RegisterPair::DE, + 2 => get_register_pair_from_index(index_reg), + 3 => RegisterPair::SP, + _ => panic!("InternalError: impossible value"), + } +} + fn get_register_pair_alt(reg: u8) -> RegisterPair { match reg { 0 => RegisterPair::BC, @@ -563,6 +694,20 @@ fn get_register_pair_alt(reg: u8) -> RegisterPair { } } +fn get_register_pair_from_index(reg: IndexRegister) -> RegisterPair { + match reg { + IndexRegister::IX => RegisterPair::IX, + IndexRegister::IY => RegisterPair::IY, + } +} + +fn get_index_register_half(reg: IndexRegister, q: u8) -> IndexRegisterHalf { + match reg { + IndexRegister::IX => if q == 0 { IndexRegisterHalf::IXH } else { IndexRegisterHalf::IXL }, + IndexRegister::IY => if q == 0 { IndexRegisterHalf::IYH } else { IndexRegisterHalf::IYL }, + } +} + fn get_condition(cond: u8) -> Condition { match cond { 0 => Condition::NotZero, diff --git a/src/cpus/z80/execute.rs b/src/cpus/z80/execute.rs index 85bf1dd..cb4a4db 100644 --- a/src/cpus/z80/execute.rs +++ b/src/cpus/z80/execute.rs @@ -3,10 +3,16 @@ use crate::system::System; use crate::error::{ErrorType, Error}; use crate::devices::{ClockElapsed, Address, Steppable, Addressable, Interruptable, Debuggable, Transmutable, read_beu16, write_beu16}; -use super::decode::{Condition, Instruction, LoadTarget, Target, RegisterPair, Size}; +use super::decode::{Condition, Instruction, LoadTarget, Target, OptionalSource, RegisterPair, IndexRegister, IndexRegisterHalf, Size}; use super::state::{Z80, Status, Flags, Register}; +enum RotateType { + Bit8, + Bit9, +} + + impl Steppable for Z80 { fn step(&mut self, system: &System) -> Result { self.step_internal(system)?; @@ -113,7 +119,7 @@ impl Z80 { //self.timer.decode.end(); //if self.debugger.use_tracing { - self.dump_state(system); + //self.dump_state(system); //} self.state.pc = self.decoder.end; @@ -122,10 +128,22 @@ impl Z80 { pub fn execute_current(&mut self, system: &System) -> Result<(), Error> { match self.decoder.instruction { - //Instruction::ADCa(target) => { - //}, - //Instruction::ADChl(regpair) => { - //}, + Instruction::ADCa(target) => { + let src = self.get_target_value(target)?; + let acc = self.get_register_value(Register::A); + let (result, carry) = acc.overflowing_add(src); + let (result, carry) = result.overflowing_add((carry as u8) + (self.get_flag(Flags::Carry) as u8)); + self.set_add_flags(result as u16, Size::Byte, carry); + self.set_register_value(Register::A, result); + }, + Instruction::ADC16(dest_pair, src_pair) => { + let src = self.get_register_pair_value(src_pair); + let hl = self.get_register_pair_value(dest_pair); + let (result, carry) = hl.overflowing_add(src); + let (result, carry) = result.overflowing_add((carry as u16) + (self.get_flag(Flags::Carry) as u16)); + self.set_add_flags(result, Size::Word, carry); + self.set_register_pair_value(dest_pair, result); + }, Instruction::ADDa(target) => { let src = self.get_target_value(target)?; let acc = self.get_register_value(Register::A); @@ -133,12 +151,12 @@ impl Z80 { self.set_add_flags(result as u16, Size::Byte, carry); self.set_register_value(Register::A, result); }, - Instruction::ADDhl(regpair) => { - let src = self.get_register_pair_value(regpair); - let hl = self.get_register_pair_value(RegisterPair::HL); + Instruction::ADD16(dest_pair, src_pair) => { + let src = self.get_register_pair_value(src_pair); + let hl = self.get_register_pair_value(dest_pair); let (result, carry) = hl.overflowing_add(src); self.set_add_flags(result as u16, Size::Word, carry); - self.set_register_pair_value(RegisterPair::HL, result); + self.set_register_pair_value(dest_pair, result); }, Instruction::AND(target) => { let acc = self.get_register_value(Register::A); @@ -147,94 +165,74 @@ impl Z80 { self.set_register_value(Register::A, result); self.set_logic_op_flags(result as u16, Size::Byte, true); }, + Instruction::BIT(bit, target) => { + let value = self.get_target_value(target)?; + self.set_flag(Flags::Zero, (value & (1 << bit)) == 0); + self.set_flag(Flags::AddSubtract, false); + self.set_flag(Flags::HalfCarry, true); + }, + Instruction::CALL(addr) => { + self.push_word(self.decoder.end)?; + self.state.pc = addr; + }, + Instruction::CALLcc(cond, addr) => { + if self.get_current_condition(cond) { + self.push_word(self.decoder.end)?; + self.state.pc = addr; + } + }, + Instruction::CCF => { + self.set_flag(Flags::Carry, false); + }, Instruction::CP(target) => { let src = self.get_target_value(target)?; let acc = self.get_register_value(Register::A); let (result, carry) = acc.overflowing_sub(src); self.set_sub_flags(result as u16, Size::Byte, carry); }, + //Instruction::CPD => { + //}, + //Instruction::CPDR => { + //}, + //Instruction::CPI => { + //}, + //Instruction::CPIR => { + //}, Instruction::CPL => { let value = self.get_register_value(Register::A); self.set_register_value(Register::A, !value); self.set_flag(Flags::HalfCarry, true); self.set_flag(Flags::AddSubtract, true); }, - //Instruction::NEG => { + //Instruction::DAA => { //}, - Instruction::OR(target) => { - let acc = self.get_register_value(Register::A); - let value = self.get_target_value(target)?; - let result = acc | value; - self.set_register_value(Register::A, result); - self.set_logic_op_flags(result as u16, Size::Byte, false); - }, - //Instruction::SBCa(target) => { - //}, - //Instruction::SBChl(regpair) => { - //}, - Instruction::SUB(target) => { - let src = self.get_target_value(target)?; - let acc = self.get_register_value(Register::A); - let (result, carry) = acc.overflowing_sub(src); - self.set_sub_flags(result as u16, Size::Byte, carry); - self.set_register_value(Register::A, result); - }, - Instruction::XOR(target) => { - let acc = self.get_register_value(Register::A); - let value = self.get_target_value(target)?; - let result = acc ^ value; - self.set_register_value(Register::A, result); - self.set_logic_op_flags(result as u16, Size::Byte, false); - }, - - //Instruction::BIT(u8, target) => { - //}, - //Instruction::RES(u8, target) => { - //}, - //Instruction::RL(target) => { - //}, - //Instruction::RLC(target) => { - //}, - //Instruction::RR(target) => { - //}, - //Instruction::RRC(target) => { - //}, - //Instruction::SET(u8, target) => { - //}, - //Instruction::SLA(target) => { - //}, - //Instruction::SLL(target) => { - //}, - //Instruction::SRA(target) => { - //}, - //Instruction::SRL(target) => { - //}, - - Instruction::DEC8(target) => { - let value = self.get_target_value(target)?; - let (result, carry) = value.overflowing_sub(1); - self.set_sub_flags(result as u16, Size::Byte, carry); - self.set_target_value(target, result)?; - }, Instruction::DEC16(regpair) => { let value = self.get_register_pair_value(regpair); let (result, carry) = value.overflowing_sub(1); self.set_sub_flags(result, Size::Word, carry); self.set_register_pair_value(regpair, result); }, - Instruction::INC8(target) => { + Instruction::DEC8(target) => { let value = self.get_target_value(target)?; - let (result, carry) = value.overflowing_add(1); - self.set_add_flags(result as u16, Size::Byte, carry); + let (result, carry) = value.overflowing_sub(1); + self.set_sub_flags(result as u16, Size::Byte, carry); self.set_target_value(target, result)?; }, - Instruction::INC16(regpair) => { - let value = self.get_register_pair_value(regpair); - let (result, carry) = value.overflowing_add(1); - self.set_add_flags(result, Size::Word, carry); - self.set_register_pair_value(regpair, result); + Instruction::DI => { + self.state.interrupts_enabled = false; }, + Instruction::DJNZ(offset) => { + let value = self.get_register_value(Register::B); + let result = value.wrapping_sub(1); + self.set_register_value(Register::B, result); + if result != 0 { + self.state.pc = ((self.state.pc as i16) + (offset as i16)) as u16; + } + }, + Instruction::EI => { + self.state.interrupts_enabled = true; + }, Instruction::EXX => { for i in 0..6 { let (normal, shadow) = (self.state.reg[i], self.state.shadow_reg[i]); @@ -260,49 +258,35 @@ impl Z80 { self.set_register_pair_value(RegisterPair::DE, hl); self.set_register_pair_value(RegisterPair::HL, de); }, - Instruction::LD(dest, src) => { - let src_value = self.get_load_target_value(src)?; - self.set_load_target_value(dest, src_value)?; + Instruction::HALT => { + self.state.status = Status::Halted; }, - Instruction::POP(regpair) => { - let value = self.pop_word()?; - self.set_register_pair_value(regpair, value); - }, - Instruction::PUSH(regpair) => { + //Instruction::IM(u8) => { + //}, + Instruction::INC16(regpair) => { let value = self.get_register_pair_value(regpair); - self.push_word(value)?; + let (result, carry) = value.overflowing_add(1); + self.set_add_flags(result, Size::Word, carry); + self.set_register_pair_value(regpair, result); }, - - //Instruction::INx(u8) => { + Instruction::INC8(target) => { + let value = self.get_target_value(target)?; + let (result, carry) = value.overflowing_add(1); + self.set_add_flags(result as u16, Size::Byte, carry); + self.set_target_value(target, result)?; + }, + //Instruction::IND => { + //}, + //Instruction::INDR => { + //}, + //Instruction::INI => { + //}, + //Instruction::INIR => { //}, //Instruction::INic(reg) => { //}, - Instruction::OUTx(port) => { - // TODO this needs to be fixed - println!("OUT: {:x}", self.state.reg[Register::A as usize]); - }, - //Instruction::OUTic(reg) => { + //Instruction::INx(u8) => { //}, - - Instruction::CALL(addr) => { - self.push_word(self.decoder.end)?; - self.state.pc = addr; - }, - Instruction::CALLcc(cond, addr) => { - if self.get_current_condition(cond) { - self.push_word(self.decoder.end)?; - self.state.pc = addr; - } - }, - Instruction::DJNZ(offset) => { - let value = self.get_register_value(Register::B); - let result = value.wrapping_sub(1); - self.set_register_value(Register::B, result); - - if result != 0 { - self.state.pc = ((self.state.pc as i16) + (offset as i16)) as u16; - } - }, Instruction::JP(addr) => { self.state.pc = addr; }, @@ -324,73 +308,10 @@ impl Z80 { self.state.pc = ((self.state.pc as i16) + (offset as i16)) as u16; } }, - Instruction::RET => { - self.state.pc = self.pop_word()?; + Instruction::LD(dest, src) => { + let src_value = self.get_load_target_value(src)?; + self.set_load_target_value(dest, src_value)?; }, - //Instruction::RETI => { - //}, - //Instruction::RETN => { - //}, - Instruction::RETcc(cond) => { - if self.get_current_condition(cond) { - self.state.pc = self.pop_word()?; - } - }, - - Instruction::DI => { - self.state.interrupts_enabled = false; - }, - Instruction::EI => { - self.state.interrupts_enabled = true; - }, - //Instruction::IM(u8) => { - //}, - Instruction::NOP => { }, - Instruction::HALT => { - self.state.status = Status::Halted; - }, - Instruction::RST(addr) => { - self.push_word(self.decoder.end)?; - self.state.pc = addr as u16; - }, - - Instruction::CCF => { - self.set_flag(Flags::Carry, false); - }, - //Instruction::DAA => { - //}, - //Instruction::RLA => { - //}, - //Instruction::RLCA => { - //}, - //Instruction::RRA => { - //}, - //Instruction::RRCA => { - //}, - //Instruction::RRD => { - //}, - //Instruction::RLD => { - //}, - Instruction::SCF => { - self.set_flag(Flags::Carry, true); - }, - - //Instruction::CPD => { - //}, - //Instruction::CPDR => { - //}, - //Instruction::CPI => { - //}, - //Instruction::CPIR => { - //}, - //Instruction::IND => { - //}, - //Instruction::INDR => { - //}, - //Instruction::INI => { - //}, - //Instruction::INIR => { - //}, //Instruction::LDD => { //}, //Instruction::LDDR => { @@ -407,6 +328,16 @@ impl Z80 { self.state.pc -= 2; } }, + //Instruction::NEG => { + //}, + Instruction::NOP => { }, + Instruction::OR(target) => { + let acc = self.get_register_value(Register::A); + let value = self.get_target_value(target)?; + let result = acc | value; + self.set_register_value(Register::A, result); + self.set_logic_op_flags(result as u16, Size::Byte, false); + }, //Instruction::OTDR => { //}, //Instruction::OTIR => { @@ -415,7 +346,139 @@ impl Z80 { //}, //Instruction::OUTI => { //}, - + //Instruction::OUTic(reg) => { + //}, + Instruction::OUTx(port) => { + // TODO this needs to be fixed + println!("OUT: {:x}", self.state.reg[Register::A as usize]); + }, + Instruction::POP(regpair) => { + let value = self.pop_word()?; + self.set_register_pair_value(regpair, value); + }, + Instruction::PUSH(regpair) => { + let value = self.get_register_pair_value(regpair); + self.push_word(value)?; + }, + Instruction::RES(bit, target, opt_src) => { + let mut value = self.get_opt_src_target_value(opt_src, target)?; + value = value & !(1 << bit); + self.set_target_value(target, value); + }, + Instruction::RET => { + self.state.pc = self.pop_word()?; + }, + //Instruction::RETI => { + //}, + //Instruction::RETN => { + //}, + Instruction::RETcc(cond) => { + if self.get_current_condition(cond) { + self.state.pc = self.pop_word()?; + } + }, + Instruction::RL(target, opt_src) => { + let value = self.get_opt_src_target_value(opt_src, target)?; + let result = self.rotate_left(value, RotateType::Bit9); + self.set_logic_op_flags(result as u16, Size::Byte, false); + self.set_target_value(target, result)?; + }, + Instruction::RLA => { + let value = self.get_register_value(Register::A); + let result = self.rotate_left(value, RotateType::Bit9); + self.set_logic_op_flags(result as u16, Size::Byte, false); + self.set_register_value(Register::A, result); + }, + Instruction::RLC(target, opt_src) => { + let value = self.get_opt_src_target_value(opt_src, target)?; + let result = self.rotate_left(value, RotateType::Bit8); + self.set_logic_op_flags(result as u16, Size::Byte, false); + self.set_target_value(target, result)?; + }, + Instruction::RLCA => { + let value = self.get_register_value(Register::A); + let result = self.rotate_left(value, RotateType::Bit8); + self.set_logic_op_flags(result as u16, Size::Byte, false); + self.set_register_value(Register::A, result); + }, + //Instruction::RLD => { + //}, + Instruction::RR(target, opt_src) => { + let value = self.get_opt_src_target_value(opt_src, target)?; + let result = self.rotate_right(value, RotateType::Bit9); + self.set_logic_op_flags(result as u16, Size::Byte, false); + self.set_target_value(target, result)?; + }, + Instruction::RRA => { + let value = self.get_register_value(Register::A); + let result = self.rotate_right(value, RotateType::Bit9); + self.set_logic_op_flags(result as u16, Size::Byte, false); + self.set_register_value(Register::A, result); + }, + Instruction::RRC(target, opt_src) => { + let value = self.get_opt_src_target_value(opt_src, target)?; + let result = self.rotate_right(value, RotateType::Bit8); + self.set_logic_op_flags(result as u16, Size::Byte, false); + self.set_target_value(target, result)?; + }, + Instruction::RRCA => { + let value = self.get_register_value(Register::A); + let result = self.rotate_right(value, RotateType::Bit8); + self.set_logic_op_flags(result as u16, Size::Byte, false); + self.set_register_value(Register::A, result); + }, + //Instruction::RRD => { + //}, + Instruction::RST(addr) => { + self.push_word(self.decoder.end)?; + self.state.pc = addr as u16; + }, + Instruction::SBCa(target) => { + let src = self.get_target_value(target)?; + let acc = self.get_register_value(Register::A); + let (result, carry) = acc.overflowing_sub(src); + let (result, carry) = result.overflowing_sub((carry as u8) + (self.get_flag(Flags::Carry) as u8)); + self.set_sub_flags(result as u16, Size::Byte, carry); + self.set_register_value(Register::A, result); + }, + Instruction::SBC16(dest_pair, src_pair) => { + let src = self.get_register_pair_value(src_pair); + let hl = self.get_register_pair_value(dest_pair); + let (result, carry) = hl.overflowing_sub(src); + let (result, carry) = result.overflowing_sub((carry as u16) + (self.get_flag(Flags::Carry) as u16)); + self.set_sub_flags(result, Size::Word, carry); + self.set_register_pair_value(dest_pair, result); + }, + Instruction::SCF => { + self.set_flag(Flags::Carry, true); + }, + Instruction::SET(bit, target, opt_src) => { + let mut value = self.get_opt_src_target_value(opt_src, target)?; + value = value | (1 << bit); + self.set_target_value(target, value); + }, + //Instruction::SLA(target, opt_src) => { + //}, + //Instruction::SLL(target, opt_src) => { + //}, + //Instruction::SRA(target, opt_src) => { + //}, + //Instruction::SRL(target, opt_src) => { + //}, + Instruction::SUB(target) => { + let src = self.get_target_value(target)?; + let acc = self.get_register_value(Register::A); + let (result, carry) = acc.overflowing_sub(src); + self.set_sub_flags(result as u16, Size::Byte, carry); + self.set_register_value(Register::A, result); + }, + Instruction::XOR(target) => { + let acc = self.get_register_value(Register::A); + let value = self.get_target_value(target)?; + let result = acc ^ value; + self.set_register_value(Register::A, result); + self.set_logic_op_flags(result as u16, Size::Byte, false); + }, _ => { panic!("unimplemented"); } @@ -424,6 +487,34 @@ impl Z80 { Ok(()) } + fn rotate_left(&mut self, mut value: u8, rtype: RotateType) -> u8 { + let out_bit = get_msb(value as u16, Size::Byte); + + let in_bit = match rtype { + RotateType::Bit9 => self.get_flag(Flags::Carry), + RotateType::Bit8 => out_bit, + }; + + value <<= 1; + value |= in_bit as u8; + self.set_flag(Flags::Carry, out_bit); + value + } + + fn rotate_right(&mut self, mut value: u8, rtype: RotateType) -> u8 { + let out_bit = (value & 0x01) != 0; + + let in_bit = match rtype { + RotateType::Bit9 => self.get_flag(Flags::Carry), + RotateType::Bit8 => out_bit, + }; + + value >>= 1; + value |= if in_bit { 0x80 } else { 0 }; + self.set_flag(Flags::Carry, out_bit); + value + } + fn push_word(&mut self, value: u16) -> Result<(), Error> { self.state.sp -= 1; self.port.write_u8(self.state.sp as Address, (value >> 8) as u8)?; @@ -444,6 +535,7 @@ impl Z80 { fn get_load_target_value(&mut self, target: LoadTarget) -> Result { let value = match target { LoadTarget::DirectRegByte(reg) => self.get_register_value(reg) as u16, + LoadTarget::DirectRegHalfByte(reg) => self.get_index_register_half_value(reg) as u16, LoadTarget::DirectRegWord(regpair) => self.get_register_pair_value(regpair), LoadTarget::IndirectRegByte(regpair) => { let addr = self.get_register_pair_value(regpair); @@ -471,6 +563,7 @@ impl Z80 { fn set_load_target_value(&mut self, target: LoadTarget, value: u16) -> Result<(), Error> { match target { LoadTarget::DirectRegByte(reg) => self.set_register_value(reg, value as u8), + LoadTarget::DirectRegHalfByte(reg) => self.set_index_register_half_value(reg, value as u8), LoadTarget::DirectRegWord(regpair) => self.set_register_pair_value(regpair, value), LoadTarget::IndirectRegByte(regpair) => { let addr = self.get_register_pair_value(regpair); @@ -496,10 +589,15 @@ impl Z80 { fn get_target_value(&mut self, target: Target) -> Result { match target { Target::DirectReg(reg) => Ok(self.get_register_value(reg)), + Target::DirectRegHalf(reg) => Ok(self.get_index_register_half_value(reg)), Target::IndirectReg(regpair) => { let addr = self.get_register_pair_value(regpair); Ok(self.port.read_u8(addr as Address)?) }, + Target::IndirectOffset(reg, offset) => { + let addr = (self.get_index_register_value(reg) as i16) + (offset as i16); + Ok(self.port.read_u8(addr as Address)?) + }, Target::Immediate(data) => Ok(data), } } @@ -507,6 +605,7 @@ impl Z80 { fn set_target_value(&mut self, target: Target, value: u8) -> Result<(), Error> { match target { Target::DirectReg(reg) => self.set_register_value(reg, value), + Target::DirectRegHalf(reg) => self.set_index_register_half_value(reg, value), Target::IndirectReg(regpair) => { let addr = self.get_register_pair_value(regpair); self.port.write_u8(addr as Address, value)?; @@ -516,14 +615,41 @@ impl Z80 { Ok(()) } + fn get_opt_src_target_value(&mut self, opt_src: OptionalSource, target: Target) -> Result { + match opt_src { + None => self.get_target_value(target), + Some((reg, offset)) => { + let addr = (self.get_index_register_value(reg) as i16) + (offset as i16); + self.port.read_u8(addr as Address) + }, + } + } + + fn get_register_value(&mut self, reg: Register) -> u8 { - let i = (reg as u8) as usize; - self.state.reg[i] + self.state.reg[reg as usize] } fn set_register_value(&mut self, reg: Register, value: u8) { - let i = (reg as u8) as usize; - self.state.reg[i] = value; + self.state.reg[reg as usize] = value; + } + + fn get_index_register_half_value(&mut self, reg: IndexRegisterHalf) -> u8 { + match reg { + IndexRegisterHalf::IXH => (self.state.ix >> 8) as u8, + IndexRegisterHalf::IXL => (self.state.ix & 0x00FF) as u8, + IndexRegisterHalf::IYH => (self.state.iy >> 8) as u8, + IndexRegisterHalf::IYL => (self.state.iy & 0x00FF) as u8, + } + } + + fn set_index_register_half_value(&mut self, reg: IndexRegisterHalf, value: u8) { + match reg { + IndexRegisterHalf::IXH => { self.state.ix |= (value as u16) << 8; }, + IndexRegisterHalf::IXL => { self.state.ix |= value as u16; }, + IndexRegisterHalf::IYH => { self.state.iy |= (value as u16) << 8; }, + IndexRegisterHalf::IYL => { self.state.iy |= value as u16; }, + } } fn get_register_pair_value(&mut self, regpair: RegisterPair) -> u16 { @@ -533,6 +659,8 @@ impl Z80 { RegisterPair::HL => read_beu16(&self.state.reg[4..6]), RegisterPair::AF => read_beu16(&self.state.reg[6..8]), RegisterPair::SP => self.state.sp, + RegisterPair::IX => self.state.ix, + RegisterPair::IY => self.state.iy, } } @@ -543,6 +671,8 @@ impl Z80 { RegisterPair::HL => { write_beu16(&mut self.state.reg[4..6], value); }, RegisterPair::AF => { write_beu16(&mut self.state.reg[6..8], value); }, RegisterPair::SP => { self.state.sp = value; }, + RegisterPair::IX => { self.state.ix = value; }, + RegisterPair::IY => { self.state.iy = value; }, } } @@ -553,6 +683,14 @@ impl Z80 { RegisterPair::HL => &mut self.state.reg[4..6], RegisterPair::AF => &mut self.state.reg[6..8], RegisterPair::SP => panic!("SP is not supported by inc/dec"), + RegisterPair::IX => { + self.state.ix = (self.state.ix as i16).wrapping_add(value) as u16; + return self.state.ix; + }, + RegisterPair::IY => { + self.state.iy = (self.state.iy as i16).wrapping_add(value) as u16; + return self.state.iy; + }, }; let result = (read_beu16(addr) as i16).wrapping_add(value) as u16; @@ -560,6 +698,13 @@ impl Z80 { result } + fn get_index_register_value(&mut self, reg: IndexRegister) -> u16 { + match reg { + IndexRegister::IX => self.state.ix, + IndexRegister::IY => self.state.iy, + } + } + fn get_current_condition(&mut self, cond: Condition) -> bool { match cond { Condition::NotZero => !self.get_flag(Flags::Zero), diff --git a/src/cpus/z80/state.rs b/src/cpus/z80/state.rs index 9f3e5ae..0a529a9 100644 --- a/src/cpus/z80/state.rs +++ b/src/cpus/z80/state.rs @@ -121,7 +121,7 @@ impl Z80 { println!("A: {:#04x} F: {:#04x}", self.state.reg[Register::A as usize], self.state.reg[Register::F as usize]); println!("B: {:#04x} C: {:#04x}", self.state.reg[Register::B as usize], self.state.reg[Register::C as usize]); - println!("D: {:#04x} E: {:#04x}", self.state.reg[Register::D as usize], self.state.reg[Register::B as usize]); + println!("D: {:#04x} E: {:#04x}", self.state.reg[Register::D as usize], self.state.reg[Register::E as usize]); println!("H: {:#04x} L: {:#04x}", self.state.reg[Register::H as usize], self.state.reg[Register::L as usize]); println!("Current Instruction: {} {:?}", self.decoder.format_instruction_bytes(&mut self.port), self.decoder.instruction);