Added decoding of more of the DD/FD instructions

This commit is contained in:
transistor 2021-11-06 15:08:03 -07:00
parent 1a28208784
commit 3da58c8d17
3 changed files with 566 additions and 276 deletions

View File

@ -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<Instruction, Error> {
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<Instruction, Error> {
panic!("DD instructions unimplemented")
pub fn decode_sub_prefix_cb(&mut self, memory: &mut dyn Addressable, reg: IndexRegister) -> Result<Instruction, Error> {
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<Instruction, Error> {
@ -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<Instruction, Error> {
panic!("FD instructions unimplemented")
pub fn decode_prefix_dd_fd(&mut self, memory: &mut dyn Addressable, index_reg: IndexRegister) -> Result<Instruction, Error> {
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,

View File

@ -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<ClockElapsed, Error> {
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<u16, Error> {
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<u8, Error> {
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<u8, Error> {
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),

View File

@ -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);