Started filling in Z80 execution

This commit is contained in:
transistor 2021-11-02 20:58:03 -07:00
parent 418bf2f141
commit dc25a9f171
3 changed files with 575 additions and 140 deletions

View File

@ -2,7 +2,14 @@
use crate::error::Error;
use crate::devices::{Address, Addressable};
use super::state::{Z80, Z80Type};
use super::state::{Z80, Z80Type, Register};
#[derive(Copy, Clone, Debug)]
pub enum Size {
Byte,
Word,
}
#[derive(Copy, Clone, Debug)]
pub enum Condition {
@ -16,32 +23,26 @@ pub enum Condition {
Negative,
}
#[derive(Copy, Clone, Debug)]
pub enum Register {
A,
B,
C,
D,
E,
H,
L,
F,
}
#[derive(Copy, Clone, Debug)]
pub enum RegisterPair {
BC,
DE,
HL,
SP,
AF,
SP,
}
#[derive(Copy, Clone, Debug)]
pub enum SpecialRegister {
I,
R,
}
#[derive(Copy, Clone, Debug)]
pub enum Target {
DirectRegByte(Register),
IndirectRegByte(RegisterPair),
ImmediateByte(u8),
DirectReg(Register),
IndirectReg(RegisterPair),
Immediate(u8),
}
#[derive(Copy, Clone, Debug)]
@ -51,6 +52,7 @@ pub enum LoadTarget {
IndirectRegByte(RegisterPair),
IndirectRegWord(RegisterPair),
DirectAltRegByte(Register),
DirectSpecialRegByte(SpecialRegister),
IndirectByte(u16),
IndirectWord(u16),
ImmediateByte(u8),
@ -59,66 +61,96 @@ pub enum LoadTarget {
#[derive(Clone, Debug)]
pub enum Instruction {
ADDa(Target),
ADCa(Target),
ADChl(RegisterPair),
ADDa(Target),
ADDhl(RegisterPair),
AND(Target),
CP(Target),
CALL(u16),
CALLcc(Condition, u16),
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),
DJNZ(i8),
DI,
EI,
INC8(Target),
INC16(RegisterPair),
EXX,
EXafaf,
EXhlsp,
EXhlde,
INx(u8),
INic(Register),
INC8(Target),
INC16(RegisterPair),
JP(u16),
JPcc(Condition, u16),
JPIndirectHL,
JR(i8),
JRcc(Condition, i8),
LD(LoadTarget, LoadTarget),
NOP,
HALT,
POP(RegisterPair),
PUSH(RegisterPair),
RET,
RETcc(Condition),
RST(u8),
OR(Target),
INx(u8),
INic(Register),
OUTx(u8),
OUTic(Register),
SUB(Target),
SBCa(Target),
XOR(Target),
RLC(Target),
RRC(Target),
RL(Target),
RR(Target),
SLA(Target),
SRA(Target),
SLL(Target),
SRL(Target),
BIT(u8, Target),
RES(u8, Target),
SET(u8, Target),
CALL(u16),
CALLcc(Condition, u16),
DJNZ(i8),
JP(u16),
JPIndirectHL,
JPcc(Condition, u16),
JR(i8),
JRcc(Condition, i8),
RET,
RETI,
RETN,
RETcc(Condition),
DI,
EI,
IM(u8),
NOP,
HALT,
RST(u8),
RLCA,
RRCA,
RLA,
RRA,
DAA,
CPL,
SCF,
CCF,
CPL,
DAA,
RLA,
RLCA,
RRA,
RRCA,
RRD,
RLD,
SCF,
CPD,
CPDR,
CPI,
CPIR,
IND,
INDR,
INI,
INIR,
LDD,
LDDR,
LDI,
LDIR,
OTDR,
OTIR,
OUTD,
OUTI,
}
pub struct Z80Decoder {
@ -190,7 +222,7 @@ impl Z80Decoder {
}
} else {
let addr = self.read_instruction_word(memory)?;
match ((ins >> 3) & 0x03) {
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))),
@ -310,7 +342,7 @@ impl Z80Decoder {
}
6 => {
let data = self.read_instruction_byte(memory)?;
Ok(get_alu_instruction(get_ins_y(ins), Target::ImmediateByte(data)))
Ok(get_alu_instruction(get_ins_y(ins), Target::Immediate(data)))
},
7 => {
Ok(Instruction::RST(get_ins_y(ins) * 8))
@ -343,45 +375,85 @@ impl Z80Decoder {
match get_ins_x(ins) {
0 => Ok(Instruction::NOP),
1 => {
/*
match get_ins_z(ins) {
0 => {
let y = get_ins_y(ins);
if y == 6 {
//Ok(Instruction::INic),
panic!("");
let target = get_register(get_ins_y(ins));
if let Target::DirectReg(reg) = target {
Ok(Instruction::INic(reg))
} else {
//Ok(Instruction::INic(get_register(y))),
//Ok(Instruction::INic())
panic!("Unimplemented");
}
},
1 => {
let target = get_register(get_ins_y(ins));
if let Target::DirectReg(reg) = target {
Ok(Instruction::OUTic(reg))
} else {
//Ok(Instruction::OUTic())
panic!("Unimplemented");
}
},
2 => {
if get_ins_q(ins) == 0 {
Ok(Instruction::SBChl(get_register_pair(get_ins_p(ins))))
} else {
Ok(Instruction::ADChl(get_register_pair(get_ins_p(ins))))
}
},
3 => {
let addr = self.read_instruction_word(memory)?;
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 => {
Ok(Instruction::IM(get_ins_y(ins)))
},
7 => {
match get_ins_y(ins) {
0 => Ok(Instruction::LD(LoadTarget::DirectSpecialRegByte(SpecialRegister::I), LoadTarget::DirectRegByte(Register::A))),
1 => Ok(Instruction::LD(LoadTarget::DirectSpecialRegByte(SpecialRegister::R), LoadTarget::DirectRegByte(Register::A))),
2 => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::A), LoadTarget::DirectSpecialRegByte(SpecialRegister::I))),
3 => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::A), LoadTarget::DirectSpecialRegByte(SpecialRegister::R))),
4 => Ok(Instruction::RRD),
5 => Ok(Instruction::RLD),
_ => Ok(Instruction::NOP),
}
},
_ => panic!("InternalError: impossible value"),
}
*/
panic!("random instructions are unimplemented");
},
2 => {
match ins & 0xF0 {
// TODO implement block
//0xA0 => {
//},
//0xB0 => {
//},
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),
}
},
@ -402,14 +474,14 @@ impl Z80Decoder {
}
fn read_instruction_word(&mut self, device: &mut dyn Addressable) -> Result<u16, Error> {
let word = device.read_beu16(self.end as Address)?;
let word = device.read_leu16(self.end as Address)?;
self.end += 2;
Ok(word)
}
pub fn dump_decoded(&mut self, memory: &mut dyn Addressable) {
let ins_data: Result<String, Error> =
(0..((self.end - self.start) / 2)).map(|offset|
(0..(self.end - self.start)).map(|offset|
Ok(format!("{:02x} ", memory.read_u8((self.start + offset) as Address).unwrap()))
).collect();
println!("{:#06x}: {}\n\t{:?}\n", self.start, ins_data.unwrap(), self.instruction);
@ -446,23 +518,23 @@ fn get_rot_instruction(rot: u8, target: Target) -> Instruction {
fn get_register(reg: u8) -> Target {
match reg {
0 => Target::DirectRegByte(Register::B),
1 => Target::DirectRegByte(Register::C),
2 => Target::DirectRegByte(Register::D),
3 => Target::DirectRegByte(Register::E),
4 => Target::DirectRegByte(Register::H),
5 => Target::DirectRegByte(Register::L),
6 => Target::IndirectRegByte(RegisterPair::HL),
7 => Target::DirectRegByte(Register::A),
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::DirectRegByte(reg) => LoadTarget::DirectRegByte(reg),
Target::IndirectRegByte(reg) => LoadTarget::IndirectRegByte(reg),
Target::ImmediateByte(data) => LoadTarget::ImmediateByte(data),
Target::DirectReg(reg) => LoadTarget::DirectRegByte(reg),
Target::IndirectReg(reg) => LoadTarget::IndirectRegByte(reg),
Target::Immediate(data) => LoadTarget::ImmediateByte(data),
}
}

View File

@ -1,10 +1,10 @@
use crate::system::System;
use crate::error::{ErrorType, Error};
use crate::devices::{ClockElapsed, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable};
use crate::devices::{ClockElapsed, Address, Steppable, Addressable, Interruptable, Debuggable, Transmutable, read_beu16, write_beu16};
use super::decode::Z80Decoder;
use super::state::{Z80, Z80State, Status};
use super::decode::{Condition, Instruction, LoadTarget, Target, RegisterPair};
use super::state::{Z80, Status, Flags, Register};
impl Steppable for Z80 {
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
@ -64,7 +64,7 @@ impl Z80 {
pub fn cycle_one(&mut self, system: &System) -> Result<(), Error> {
//self.timer.cycle.start();
self.decode_next(system)?;
//self.execute_current(system)?;
self.execute_current(system)?;
//self.timer.cycle.end();
//if (self.timer.cycle.events % 500) == 0 {
@ -91,7 +91,399 @@ impl Z80 {
}
pub fn execute_current(&mut self, system: &System) -> Result<(), Error> {
panic!("unimplemented");
match self.decoder.instruction {
//Instruction::ADCa(target) => {
//},
//Instruction::ADChl(regpair) => {
//},
//Instruction::ADDa(target) => {
//},
//Instruction::ADDhl(regpair) => {
//},
//Instruction::AND(target) => {
//},
//Instruction::CP(target) => {
//},
//Instruction::NEG => {
//},
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_op_flags(result, false);
},
//Instruction::SBCa(target) => {
//},
//Instruction::SBChl(regpair) => {
//},
//Instruction::SUB(target) => {
//},
//Instruction::XOR(target) => {
//},
//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 (result, overflow) = self.get_target_value(target)?.overflowing_sub(1);
self.set_op_flags(result, false);
self.set_target_value(target, result);
},
//Instruction::DEC16(regpair) => {
//},
//Instruction::INC8(target) => {
//},
//Instruction::INC16(regpair) => {
//},
//Instruction::EXX => {
//},
//Instruction::EXafaf => {
//},
//Instruction::EXhlsp => {
//},
//Instruction::EXhlde => {
//},
Instruction::LD(dest, src) => {
let src_value = self.get_load_target_value(src)?;
self.set_load_target_value(dest, src_value)?;
},
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::INx(u8) => {
//},
//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::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(i8) => {
//},
Instruction::JP(addr) => {
self.state.pc = addr;
},
//Instruction::JPIndirectHL => {
//},
Instruction::JPcc(cond, addr) => {
if self.get_current_condition(cond) {
self.state.pc = addr;
}
},
Instruction::JR(offset) => {
self.state.pc = ((self.state.pc as i16) + (offset as i16)) as u16;
},
Instruction::JRcc(cond, offset) => {
if self.get_current_condition(cond) {
self.state.pc = ((self.state.pc as i16) + (offset as i16)) as u16;
}
},
Instruction::RET => {
self.state.pc = self.pop_word()?;
},
//Instruction::RETI => {
//},
//Instruction::RETN => {
//},
//Instruction::RETcc(cond) => {
//},
//Instruction::DI => {
//},
//Instruction::EI => {
//},
//Instruction::IM(u8) => {
//},
Instruction::NOP => { },
//Instruction::HALT => {
//},
//Instruction::RST(u8) => {
//},
//Instruction::CCF => {
//},
//Instruction::CPL => {
//},
//Instruction::DAA => {
//},
//Instruction::RLA => {
//},
//Instruction::RLCA => {
//},
//Instruction::RRA => {
//},
//Instruction::RRCA => {
//},
//Instruction::RRD => {
//},
//Instruction::RLD => {
//},
//Instruction::SCF => {
//},
//Instruction::CPD => {
//},
//Instruction::CPDR => {
//},
//Instruction::CPI => {
//},
//Instruction::CPIR => {
//},
//Instruction::IND => {
//},
//Instruction::INDR => {
//},
//Instruction::INI => {
//},
//Instruction::INIR => {
//},
//Instruction::LDD => {
//},
//Instruction::LDDR => {
//},
//Instruction::LDI => {
//},
Instruction::LDIR => {
let src_value = self.get_load_target_value(LoadTarget::IndirectRegByte(RegisterPair::HL))?;
self.set_load_target_value(LoadTarget::IndirectRegByte(RegisterPair::DE), src_value)?;
self.register_pair_add_value(RegisterPair::DE, 1);
self.register_pair_add_value(RegisterPair::HL, 1);
let count = self.register_pair_add_value(RegisterPair::BC, -1);
if count != 0 {
self.state.pc -= 2;
}
},
//Instruction::OTDR => {
//},
//Instruction::OTIR => {
//},
//Instruction::OUTD => {
//},
//Instruction::OUTI => {
//},
_ => {
panic!("unimplemented");
}
}
Ok(())
}
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)?;
self.state.sp -= 1;
self.port.write_u8(self.state.sp as Address, (value & 0x00FF) as u8)?;
Ok(())
}
fn pop_word(&mut self) -> Result<u16, Error> {
let mut value = 0;
value = self.port.read_u8(self.state.sp as Address)? as u16;
self.state.sp += 1;
value |= (self.port.read_u8(self.state.sp as Address)? as u16) << 8;
self.state.sp += 1;
Ok(value)
}
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::DirectRegWord(regpair) => self.get_register_pair_value(regpair),
LoadTarget::IndirectRegByte(regpair) => {
let addr = self.get_register_pair_value(regpair);
self.port.read_u8(addr as Address)? as u16
},
LoadTarget::IndirectRegWord(regpair) => {
let addr = self.get_register_pair_value(regpair);
self.port.read_leu16(addr as Address)?
},
//LoadTarget::DirectAltRegByte(reg),
//LoadTarget::DirectSpecialRegByte(reg),
LoadTarget::IndirectByte(addr) => {
self.port.read_u8(addr as Address)? as u16
},
LoadTarget::IndirectWord(addr) => {
self.port.read_leu16(addr as Address)?
},
LoadTarget::ImmediateByte(data) => data as u16,
LoadTarget::ImmediateWord(data) => data,
_ => panic!("Unsupported LoadTarget for set"),
};
Ok(value)
}
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::DirectRegWord(regpair) => self.set_register_pair_value(regpair, value),
LoadTarget::IndirectRegByte(regpair) => {
let addr = self.get_register_pair_value(regpair);
self.port.write_u8(addr as Address, value as u8)?;
},
LoadTarget::IndirectRegWord(regpair) => {
let addr = self.get_register_pair_value(regpair);
self.port.write_leu16(addr as Address, value)?;
},
//LoadTarget::DirectAltRegByte(reg),
//LoadTarget::DirectSpecialRegByte(reg),
LoadTarget::IndirectByte(addr) => {
self.port.write_u8(addr as Address, value as u8)?;
},
LoadTarget::IndirectWord(addr) => {
self.port.write_leu16(addr as Address, value)?;
},
_ => panic!("Unsupported LoadTarget for set"),
}
Ok(())
}
fn get_target_value(&mut self, target: Target) -> Result<u8, Error> {
match target {
Target::DirectReg(reg) => Ok(self.get_register_value(reg)),
Target::IndirectReg(regpair) => {
let addr = self.get_register_pair_value(regpair);
Ok(self.port.read_u8(addr as Address)?)
},
Target::Immediate(data) => Ok(data),
}
}
fn set_target_value(&mut self, target: Target, value: u8) -> Result<(), Error> {
match target {
Target::DirectReg(reg) => self.set_register_value(reg, value),
Target::IndirectReg(regpair) => {
let addr = self.get_register_pair_value(regpair);
self.port.write_u8(addr as Address, value)?;
},
_ => panic!("Unsupported LoadTarget for set"),
}
Ok(())
}
fn get_register_value(&mut self, reg: Register) -> u8 {
let i = (reg as u8) as usize;
self.state.reg[i]
}
fn set_register_value(&mut self, reg: Register, value: u8) {
let i = (reg as u8) as usize;
self.state.reg[i] = value;
}
fn get_register_pair_value(&mut self, regpair: RegisterPair) -> u16 {
match regpair {
RegisterPair::BC => read_beu16(&self.state.reg[0..2]),
RegisterPair::DE => read_beu16(&self.state.reg[2..4]),
RegisterPair::HL => read_beu16(&self.state.reg[4..6]),
RegisterPair::AF => read_beu16(&self.state.reg[6..8]),
RegisterPair::SP => self.state.sp,
}
}
fn set_register_pair_value(&mut self, regpair: RegisterPair, value: u16) {
match regpair {
RegisterPair::BC => { write_beu16(&mut self.state.reg[0..2], value); },
RegisterPair::DE => { write_beu16(&mut self.state.reg[2..4], value); },
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; },
}
}
fn register_pair_add_value(&mut self, regpair: RegisterPair, value: i16) -> u16 {
let addr = match regpair {
RegisterPair::BC => &mut self.state.reg[0..2],
RegisterPair::DE => &mut self.state.reg[2..4],
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"),
};
let result = (read_beu16(addr) as i16).wrapping_add(value) as u16;
write_beu16(addr, result);
result
}
fn get_current_condition(&mut self, cond: Condition) -> bool {
match cond {
Condition::NotZero => !self.get_flag(Flags::Zero),
Condition::Zero => self.get_flag(Flags::Zero),
Condition::NotCarry => !self.get_flag(Flags::Carry),
Condition::Carry => self.get_flag(Flags::Carry),
Condition::ParityOdd => !self.get_flag(Flags::Parity),
Condition::ParityEven => self.get_flag(Flags::Parity),
Condition::Positive => !self.get_flag(Flags::Sign),
Condition::Negative => self.get_flag(Flags::Sign),
}
}
fn set_op_flags(&mut self, value: u8, carry: bool) {
let mut flags = 0;
if value == 0 {
flags |= Flags::Zero as u8;
}
if (value as i8) < 0 {
flags |= Flags::Sign as u8;
}
if carry {
flags |= Flags::Carry as u8;
}
self.state.reg[Register::F as usize] = flags;
}
#[inline(always)]
fn get_flags(&self) -> u8 {
self.state.reg[Register::F as usize]
}
#[inline(always)]
fn get_flag(&self, flag: Flags) -> bool {
self.get_flags() & (flag as u8) != 0
}
}

View File

@ -25,56 +25,27 @@ pub enum Status {
#[allow(dead_code)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Flags {
Carry = 0x0001,
Overflow = 0x0002,
Zero = 0x0004,
Negative = 0x0008,
Extend = 0x0010,
Carry = 0x01,
AddSubtract = 0x02,
Parity = 0x04,
HalfCarry = 0x10,
Zero = 0x40,
Sign = 0x80,
}
/*
#[repr(u8)]
#[allow(dead_code)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Exceptions {
BusError = 2,
AddressError = 3,
IllegalInstruction = 4,
ZeroDivide = 5,
ChkInstruction = 6,
TrapvInstruction = 7,
PrivilegeViolation = 8,
}
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum InterruptPriority {
NoInterrupt = 0,
Level1 = 1,
Level2 = 2,
Level3 = 3,
Level4 = 4,
Level5 = 5,
Level6 = 6,
Level7 = 7,
#[derive(Copy, Clone, Debug)]
pub enum Register {
B = 0,
C = 1,
D = 2,
E = 3,
H = 4,
L = 5,
A = 6,
F = 7,
}
impl InterruptPriority {
pub fn from_u8(priority: u8) -> InterruptPriority {
match priority {
0 => InterruptPriority::NoInterrupt,
1 => InterruptPriority::Level1,
2 => InterruptPriority::Level2,
3 => InterruptPriority::Level3,
4 => InterruptPriority::Level4,
5 => InterruptPriority::Level5,
6 => InterruptPriority::Level6,
_ => InterruptPriority::Level7,
}
}
}
*/
#[derive(Clone, Debug, PartialEq)]
pub struct Z80State {