use core::fmt::Write;
use emulator_hal::{BusAccess, Instant as EmuInstant};
use crate::state::{Z80Error, Z80Address, Z80AddressSpace};
use crate::instructions::{
Direction, Condition, Register, RegisterPair, IndexRegister, IndexRegisterHalf, SpecialRegister, InterruptMode, Target,
LoadTarget, UndocumentedCopy, Instruction,
};
#[derive(Clone)]
pub struct Z80Decoder {
pub start: Z80Address,
pub end: Z80Address,
pub extra_instruction_bytes: u16,
pub instruction: Instruction,
}
impl Default for Z80Decoder {
fn default() -> Self {
Self {
start: 0,
end: 0,
extra_instruction_bytes: 0,
instruction: Instruction::NOP,
}
}
}
impl Z80Decoder {
fn new(start: Z80Address) -> Self {
Self {
start,
end: start,
extra_instruction_bytes: 0,
instruction: Instruction::NOP,
}
}
}
impl Z80Decoder {
pub fn decode_at<Bus>(bus: &mut Bus, clock: Bus::Instant, start: Z80Address) -> Result<Self, Z80Error>
where
Bus: BusAccess<Z80AddressSpace>,
{
let mut decoder: DecodeNext<'_, Bus, Bus::Instant> = DecodeNext {
clock,
bus,
decoder: Z80Decoder::new(start),
};
decoder.decode_one()?;
Ok(decoder.decoder)
}
pub fn dump_disassembly<Bus>(bus: &mut Bus, start: Z80Address, length: Z80Address)
where
Bus: BusAccess<Z80AddressSpace>,
{
let mut next = start;
while next < (start + length) {
match Z80Decoder::decode_at(bus, Bus::Instant::START, next) {
Ok(mut decoder) => {
decoder.dump_decoded(bus);
next = decoder.end;
},
Err(err) => {
println!("{:?}", err);
return;
},
}
}
}
pub fn dump_decoded<Bus>(&mut self, bus: &mut Bus)
where
Bus: BusAccess<Z80AddressSpace>,
{
let ins_data = self.format_instruction_bytes(bus);
println!("{:#06x}: {}\n\t{:?}\n", self.start, ins_data, self.instruction);
}
pub fn format_instruction_bytes<Bus>(&mut self, bus: &mut Bus) -> String
where
Bus: BusAccess<Z80AddressSpace>,
{
let mut ins_data = String::new();
for offset in 0..self.end.saturating_sub(self.start) {
write!(
ins_data,
"{:02x} ",
bus.read_u8(Bus::Instant::START, Z80AddressSpace::Memory(self.start + offset))
.unwrap()
)
.unwrap()
}
ins_data
}
}
pub struct DecodeNext<'a, Bus, Instant>
where
Bus: BusAccess<Z80AddressSpace, Instant = Instant>,
{
clock: Instant,
bus: &'a mut Bus,
decoder: Z80Decoder,
}
impl<'a, Bus, Instant> DecodeNext<'a, Bus, Instant>
where
Bus: BusAccess<Z80AddressSpace, Instant = Instant>,
Instant: EmuInstant,
{
pub fn decode_one(&mut self) -> Result<(), Z80Error> {
let ins = self.read_instruction_byte()?;
self.decoder.instruction = self.decode_bare(ins, 0)?;
Ok(())
}
pub fn decode_bare(&mut self, ins: u8, extra_instruction_bytes: u16) -> Result<Instruction, Z80Error> {
self.decoder.extra_instruction_bytes = extra_instruction_bytes;
match get_ins_x(ins) {
0 => match get_ins_z(ins) {
0 => match get_ins_y(ins) {
0 => Ok(Instruction::NOP),
1 => Ok(Instruction::EXafaf),
2 => {
let offset = self.read_instruction_byte()? as i8;
Ok(Instruction::DJNZ(offset))
},
3 => {
let offset = self.read_instruction_byte()? as i8;
Ok(Instruction::JR(offset))
},
y => {
let offset = self.read_instruction_byte()? as i8;
Ok(Instruction::JRcc(get_condition(y - 4), offset))
},
},
1 => {
if get_ins_q(ins) == 0 {
let data = self.read_instruction_word()?;
Ok(Instruction::LD(
LoadTarget::DirectRegWord(get_register_pair(get_ins_p(ins))),
LoadTarget::ImmediateWord(data),
))
} else {
Ok(Instruction::ADD16(RegisterPair::HL, get_register_pair(get_ins_p(ins))))
}
},
2 => {
if (ins & 0x20) == 0 {
let target = match (ins & 0x10) != 0 {
false => LoadTarget::IndirectRegByte(RegisterPair::BC),
true => LoadTarget::IndirectRegByte(RegisterPair::DE),
};
match get_ins_q(ins) != 0 {
false => Ok(Instruction::LD(target, LoadTarget::DirectRegByte(Register::A))),
true => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::A), target)),
}
} else {
let addr = self.read_instruction_word()?;
match (ins >> 3) & 0x03 {
0 => Ok(Instruction::LD(LoadTarget::IndirectWord(addr), LoadTarget::DirectRegWord(RegisterPair::HL))),
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"),
}
}
},
3 => {
if get_ins_q(ins) == 0 {
Ok(Instruction::INC16(get_register_pair(get_ins_p(ins))))
} else {
Ok(Instruction::DEC16(get_register_pair(get_ins_p(ins))))
}
},
4 => Ok(Instruction::INC8(get_register(get_ins_y(ins)))),
5 => Ok(Instruction::DEC8(get_register(get_ins_y(ins)))),
6 => {
let data = self.read_instruction_byte()?;
Ok(Instruction::LD(to_load_target(get_register(get_ins_y(ins))), LoadTarget::ImmediateByte(data)))
},
7 => match get_ins_y(ins) {
0 => Ok(Instruction::RLCA),
1 => Ok(Instruction::RRCA),
2 => Ok(Instruction::RLA),
3 => Ok(Instruction::RRA),
4 => Ok(Instruction::DAA),
5 => Ok(Instruction::CPL),
6 => Ok(Instruction::SCF),
7 => Ok(Instruction::CCF),
_ => panic!("InternalError: impossible value"),
},
_ => panic!("InternalError: impossible value"),
},
1 => {
if ins == 0x76 {
Ok(Instruction::HALT)
} else {
Ok(Instruction::LD(
to_load_target(get_register(get_ins_y(ins))),
to_load_target(get_register(get_ins_z(ins))),
))
}
},
2 => Ok(get_alu_instruction(get_ins_y(ins), get_register(get_ins_z(ins)))),
3 => match get_ins_z(ins) {
0 => Ok(Instruction::RETcc(get_condition(get_ins_y(ins)))),
1 => {
if get_ins_q(ins) == 0 {
Ok(Instruction::POP(get_register_pair_alt(get_ins_p(ins))))
} else {
match get_ins_p(ins) {
0 => Ok(Instruction::RET),
1 => Ok(Instruction::EXX),
2 => Ok(Instruction::JPIndirect(RegisterPair::HL)),
3 => Ok(Instruction::LD(
LoadTarget::DirectRegWord(RegisterPair::SP),
LoadTarget::DirectRegWord(RegisterPair::HL),
)),
_ => panic!("InternalError: impossible value"),
}
}
},
2 => {
let addr = self.read_instruction_word()?;
Ok(Instruction::JPcc(get_condition(get_ins_y(ins)), addr))
},
3 => match get_ins_y(ins) {
0 => {
let addr = self.read_instruction_word()?;
Ok(Instruction::JP(addr))
},
1 => self.decode_prefix_cb(),
2 => {
let port = self.read_instruction_byte()?;
Ok(Instruction::OUTx(port))
},
3 => {
let port = self.read_instruction_byte()?;
Ok(Instruction::INx(port))
},
4 => Ok(Instruction::EXsp(RegisterPair::HL)),
5 => Ok(Instruction::EXhlde),
6 => Ok(Instruction::DI),
7 => Ok(Instruction::EI),
_ => panic!("InternalError: impossible value"),
},
4 => {
let addr = self.read_instruction_word()?;
Ok(Instruction::CALLcc(get_condition(get_ins_y(ins)), addr))
},
5 => {
if get_ins_q(ins) == 0 {
Ok(Instruction::PUSH(get_register_pair_alt(get_ins_p(ins))))
} else {
match get_ins_p(ins) {
0 => {
let addr = self.read_instruction_word()?;
Ok(Instruction::CALL(addr))
},
1 => self.decode_prefix_dd_fd(IndexRegister::IX),
2 => self.decode_prefix_ed(),
3 => self.decode_prefix_dd_fd(IndexRegister::IY),
_ => panic!("InternalError: impossible value"),
}
}
},
6 => {
let data = self.read_instruction_byte()?;
Ok(get_alu_instruction(get_ins_y(ins), Target::Immediate(data)))
},
7 => Ok(Instruction::RST(get_ins_y(ins) * 8)),
_ => panic!("InternalError: impossible value"),
},
_ => panic!("InternalError: impossible value"),
}
}
pub fn decode_prefix_cb(&mut self) -> Result<Instruction, Z80Error> {
let ins = self.read_instruction_byte()?;
match get_ins_x(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)), None)),
3 => Ok(Instruction::SET(get_ins_y(ins), get_register(get_ins_z(ins)), None)),
_ => panic!("InternalError: impossible value"),
}
}
pub fn decode_sub_prefix_cb(&mut self, reg: IndexRegister) -> Result<Instruction, Z80Error> {
let offset = self.read_instruction_byte()? as i8;
let ins = self.read_instruction_byte()?;
let opt_copy = match get_ins_z(ins) {
6 => None, z => Some(get_register(z)),
};
match get_ins_x(ins) {
0 => Ok(get_rot_instruction(get_ins_y(ins), Target::IndirectOffset(reg, offset), opt_copy)),
1 => Ok(Instruction::BIT(get_ins_y(ins), Target::IndirectOffset(reg, offset))),
2 => Ok(Instruction::RES(get_ins_y(ins), Target::IndirectOffset(reg, offset), opt_copy)),
3 => Ok(Instruction::SET(get_ins_y(ins), Target::IndirectOffset(reg, offset), opt_copy)),
_ => panic!("InternalError: impossible value"),
}
}
pub fn decode_prefix_ed(&mut self) -> Result<Instruction, Z80Error> {
let ins = self.read_instruction_byte()?;
match get_ins_x(ins) {
0 => Ok(Instruction::NOP),
1 => match get_ins_z(ins) {
0 => {
let target = get_register(get_ins_y(ins));
if let Target::DirectReg(reg) = target {
Ok(Instruction::INic(reg))
} else {
Ok(Instruction::INicz)
}
},
1 => {
let target = get_register(get_ins_y(ins));
if let Target::DirectReg(reg) = target {
Ok(Instruction::OUTic(reg))
} else {
Ok(Instruction::OUTicz)
}
},
2 => {
if get_ins_q(ins) == 0 {
Ok(Instruction::SBC16(RegisterPair::HL, get_register_pair(get_ins_p(ins))))
} else {
Ok(Instruction::ADC16(RegisterPair::HL, get_register_pair(get_ins_p(ins))))
}
},
3 => {
let addr = self.read_instruction_word()?;
if get_ins_q(ins) == 0 {
Ok(Instruction::LD(
LoadTarget::IndirectWord(addr),
LoadTarget::DirectRegWord(get_register_pair(get_ins_p(ins))),
))
} else {
Ok(Instruction::LD(
LoadTarget::DirectRegWord(get_register_pair(get_ins_p(ins))),
LoadTarget::IndirectWord(addr),
))
}
},
4 => Ok(Instruction::NEG),
5 => {
if get_ins_y(ins) == 1 {
Ok(Instruction::RETI)
} else {
Ok(Instruction::RETN)
}
},
6 => match get_ins_y(ins) & 0x03 {
0 => Ok(Instruction::IM(InterruptMode::Mode0)),
1 => Ok(Instruction::IM(InterruptMode::Mode0)),
2 => Ok(Instruction::IM(InterruptMode::Mode1)),
3 => Ok(Instruction::IM(InterruptMode::Mode2)),
_ => panic!("InternalError: impossible value"),
},
7 => match get_ins_y(ins) {
0 => Ok(Instruction::LDsr(SpecialRegister::I, Direction::FromAcc)),
1 => Ok(Instruction::LDsr(SpecialRegister::R, Direction::FromAcc)),
2 => Ok(Instruction::LDsr(SpecialRegister::I, Direction::ToAcc)),
3 => Ok(Instruction::LDsr(SpecialRegister::R, Direction::ToAcc)),
4 => Ok(Instruction::RRD),
5 => Ok(Instruction::RLD),
_ => Ok(Instruction::NOP),
},
_ => panic!("InternalError: impossible value"),
},
2 => match ins {
0xA0 => Ok(Instruction::LDI),
0xA1 => Ok(Instruction::CPI),
0xA2 => Ok(Instruction::INI),
0xA3 => Ok(Instruction::OUTI),
0xA8 => Ok(Instruction::LDD),
0xA9 => Ok(Instruction::CPD),
0xAA => Ok(Instruction::IND),
0xAB => Ok(Instruction::OUTD),
0xB0 => Ok(Instruction::LDIR),
0xB1 => Ok(Instruction::CPIR),
0xB2 => Ok(Instruction::INIR),
0xB3 => Ok(Instruction::OTIR),
0xB8 => Ok(Instruction::LDDR),
0xB9 => Ok(Instruction::CPDR),
0xBA => Ok(Instruction::INDR),
0xBB => Ok(Instruction::OTDR),
_ => Ok(Instruction::NOP),
},
3 => Ok(Instruction::NOP),
_ => panic!("InternalError: impossible value"),
}
}
pub fn decode_prefix_dd_fd(&mut self, index_reg: IndexRegister) -> Result<Instruction, Z80Error> {
let ins = self.read_instruction_byte()?;
if ins == 0xCB {
return self.decode_sub_prefix_cb(index_reg);
}
match get_ins_x(ins) {
0 => {
if (ins & 0x0F) == 9 {
return Ok(Instruction::ADD16(index_reg.into(), 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()?;
Ok(Instruction::LD(LoadTarget::DirectRegWord(index_reg.into()), LoadTarget::ImmediateWord(data)))
},
2 => {
let addr = self.read_instruction_word()?;
let regpair = index_reg.into();
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(index_reg.into())),
true => Ok(Instruction::DEC16(index_reg.into())),
},
4 => {
self.decoder.extra_instruction_bytes = 4;
let half_target = Target::DirectRegHalf(get_index_register_half(index_reg, get_ins_q(ins)));
Ok(Instruction::INC8(half_target))
},
5 => {
self.decoder.extra_instruction_bytes = 4;
let half_target = Target::DirectRegHalf(get_index_register_half(index_reg, get_ins_q(ins)));
Ok(Instruction::DEC8(half_target))
},
6 => {
self.decoder.extra_instruction_bytes = 4;
let half_target = Target::DirectRegHalf(get_index_register_half(index_reg, get_ins_q(ins)));
let data = self.read_instruction_byte()?;
Ok(Instruction::LD(to_load_target(half_target), LoadTarget::ImmediateByte(data)))
},
_ => self.decode_bare(ins, 4),
},
3 => match ins {
0x34 => {
let offset = self.read_instruction_byte()? as i8;
Ok(Instruction::INC8(Target::IndirectOffset(index_reg, offset)))
},
0x35 => {
let offset = self.read_instruction_byte()? as i8;
Ok(Instruction::DEC8(Target::IndirectOffset(index_reg, offset)))
},
0x36 => {
let offset = self.read_instruction_byte()? as i8;
let immediate = self.read_instruction_byte()?;
Ok(Instruction::LD(
LoadTarget::IndirectOffsetByte(index_reg, offset),
LoadTarget::ImmediateByte(immediate),
))
},
_ => self.decode_bare(ins, 4),
},
_ => self.decode_bare(ins, 4),
}
},
1 => match get_ins_p(ins) {
0 | 1 => {
let target = match self.decode_index_target(index_reg, get_ins_z(ins))? {
Some(target) => target,
None => return self.decode_bare(ins, 4),
};
match (ins & 0x18) >> 3 {
0 => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::B), to_load_target(target))),
1 => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::C), to_load_target(target))),
2 => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::D), to_load_target(target))),
3 => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::E), to_load_target(target))),
_ => panic!("InternalError: impossible value"),
}
},
2 => {
let src = match get_ins_z(ins) {
0 => Target::DirectReg(Register::B),
1 => Target::DirectReg(Register::C),
2 => Target::DirectReg(Register::D),
3 => Target::DirectReg(Register::E),
4 => Target::DirectRegHalf(get_index_register_half(index_reg, 0)),
5 => Target::DirectRegHalf(get_index_register_half(index_reg, 1)),
6 => {
let offset = self.read_instruction_byte()? as i8;
let src = to_load_target(Target::IndirectOffset(index_reg, offset));
if get_ins_q(ins) == 0 {
return Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::H), src));
} else {
return Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::L), src));
}
},
7 => Target::DirectReg(Register::A),
_ => panic!("InternalError: impossible value"),
};
let dest = get_index_register_half(index_reg, get_ins_q(ins));
Ok(Instruction::LD(LoadTarget::DirectRegHalfByte(dest), to_load_target(src)))
},
3 => {
if get_ins_q(ins) == 0 {
if get_ins_z(ins) == 6 {
return self.decode_bare(ins, 4);
}
let src = get_register(get_ins_z(ins));
let offset = self.read_instruction_byte()? as i8;
Ok(Instruction::LD(LoadTarget::IndirectOffsetByte(index_reg, offset), to_load_target(src)))
} else {
let target = match self.decode_index_target(index_reg, get_ins_z(ins))? {
Some(target) => target,
None => return self.decode_bare(ins, 4),
};
Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::A), to_load_target(target)))
}
},
_ => panic!("InternalError: impossible value"),
},
2 => {
self.decoder.extra_instruction_bytes = 4;
let target = match self.decode_index_target(index_reg, get_ins_z(ins))? {
Some(target) => target,
None => return self.decode_bare(ins, 4),
};
match get_ins_y(ins) {
0 => Ok(Instruction::ADDa(target)),
1 => Ok(Instruction::ADCa(target)),
2 => Ok(Instruction::SUB(target)),
3 => Ok(Instruction::SBCa(target)),
4 => Ok(Instruction::AND(target)),
5 => Ok(Instruction::XOR(target)),
6 => Ok(Instruction::OR(target)),
7 => Ok(Instruction::CP(target)),
_ => panic!("InternalError: impossible value"),
}
},
3 => match ins {
0xE1 => Ok(Instruction::POP(index_reg.into())),
0xE3 => Ok(Instruction::EXsp(index_reg.into())),
0xE5 => Ok(Instruction::PUSH(index_reg.into())),
0xE9 => Ok(Instruction::JPIndirect(index_reg.into())),
0xF9 => Ok(Instruction::LD(
LoadTarget::DirectRegWord(RegisterPair::SP),
LoadTarget::DirectRegWord(index_reg.into()),
)),
_ => self.decode_bare(ins, 4),
},
_ => panic!("InternalError: impossible value"),
}
}
fn decode_index_target(&mut self, index_reg: IndexRegister, z: u8) -> Result<Option<Target>, Z80Error> {
let result = match z {
4 => Some(Target::DirectRegHalf(get_index_register_half(index_reg, 0))),
5 => Some(Target::DirectRegHalf(get_index_register_half(index_reg, 1))),
6 => {
let offset = self.read_instruction_byte()? as i8;
Some(Target::IndirectOffset(index_reg, offset))
},
_ => None,
};
Ok(result)
}
fn read_instruction_byte(&mut self) -> Result<u8, Z80Error> {
let byte = self
.bus
.read_u8(self.clock, Z80AddressSpace::Memory(self.decoder.end))
.map_err(|err| Z80Error::BusError(format!("{:?}", err)))?;
self.decoder.end = self.decoder.end.wrapping_add(1);
Ok(byte)
}
fn read_instruction_word(&mut self) -> Result<u16, Z80Error> {
let mut bytes = [0; 2];
for byte in bytes.iter_mut() {
*byte = self
.bus
.read_u8(self.clock, Z80AddressSpace::Memory(self.decoder.end))
.map_err(|err| Z80Error::BusError(format!("{:?}", err)))?;
self.decoder.end = self.decoder.end.wrapping_add(1);
}
Ok(u16::from_le_bytes(bytes))
}
}
impl From<IndexRegister> for RegisterPair {
fn from(value: IndexRegister) -> Self {
match value {
IndexRegister::IX => RegisterPair::IX,
IndexRegister::IY => RegisterPair::IY,
}
}
}
fn get_alu_instruction(alu: u8, target: Target) -> Instruction {
match alu {
0 => Instruction::ADDa(target),
1 => Instruction::ADCa(target),
2 => Instruction::SUB(target),
3 => Instruction::SBCa(target),
4 => Instruction::AND(target),
5 => Instruction::XOR(target),
6 => Instruction::OR(target),
7 => Instruction::CP(target),
_ => panic!("InternalError: impossible value"),
}
}
fn get_rot_instruction(rot: u8, target: Target, opt_copy: UndocumentedCopy) -> Instruction {
match rot {
0 => Instruction::RLC(target, opt_copy),
1 => Instruction::RRC(target, opt_copy),
2 => Instruction::RL(target, opt_copy),
3 => Instruction::RR(target, opt_copy),
4 => Instruction::SLA(target, opt_copy),
5 => Instruction::SRA(target, opt_copy),
6 => Instruction::SLL(target, opt_copy),
7 => Instruction::SRL(target, opt_copy),
_ => panic!("InternalError: impossible value"),
}
}
fn get_register(reg: u8) -> Target {
match reg {
0 => Target::DirectReg(Register::B),
1 => Target::DirectReg(Register::C),
2 => Target::DirectReg(Register::D),
3 => Target::DirectReg(Register::E),
4 => Target::DirectReg(Register::H),
5 => Target::DirectReg(Register::L),
6 => Target::IndirectReg(RegisterPair::HL),
7 => Target::DirectReg(Register::A),
_ => panic!("InternalError: impossible value"),
}
}
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),
}
}
fn get_register_pair(reg: u8) -> RegisterPair {
match reg {
0 => RegisterPair::BC,
1 => RegisterPair::DE,
2 => RegisterPair::HL,
3 => RegisterPair::SP,
_ => panic!("InternalError: impossible value"),
}
}
fn get_register_pair_index(reg: u8, index_reg: IndexRegister) -> RegisterPair {
match reg {
0 => RegisterPair::BC,
1 => RegisterPair::DE,
2 => index_reg.into(),
3 => RegisterPair::SP,
_ => panic!("InternalError: impossible value"),
}
}
fn get_register_pair_alt(reg: u8) -> RegisterPair {
match reg {
0 => RegisterPair::BC,
1 => RegisterPair::DE,
2 => RegisterPair::HL,
3 => RegisterPair::AF,
_ => panic!("InternalError: impossible value"),
}
}
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,
1 => Condition::Zero,
2 => Condition::NotCarry,
3 => Condition::Carry,
4 => Condition::ParityOdd,
5 => Condition::ParityEven,
6 => Condition::Positive,
7 => Condition::Negative,
_ => panic!("InternalError: impossible value"),
}
}
fn get_ins_x(ins: u8) -> u8 {
(ins >> 6) & 0x03
}
fn get_ins_y(ins: u8) -> u8 {
(ins >> 3) & 0x07
}
fn get_ins_z(ins: u8) -> u8 {
ins & 0x07
}
fn get_ins_p(ins: u8) -> u8 {
(ins >> 4) & 0x03
}
fn get_ins_q(ins: u8) -> u8 {
(ins >> 3) & 0x01
}