mirror of
https://github.com/transistorfet/moa.git
synced 2025-01-23 08:32:36 +00:00
Added decoding of more of the DD/FD instructions
This commit is contained in:
parent
1a28208784
commit
3da58c8d17
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user