mirror of
https://github.com/transistorfet/moa.git
synced 2024-12-03 07:49:17 +00:00
Modified Z80 to use a custom error type
This commit is contained in:
parent
e13c172364
commit
83289d6b8e
@ -5,6 +5,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
thiserror = "1.0"
|
||||
femtos = "0.1"
|
||||
moa-core = { path = "../../core" }
|
||||
moa-signals = { path = "../../libraries/signals" }
|
||||
|
@ -1,8 +1,9 @@
|
||||
|
||||
use femtos::Instant;
|
||||
|
||||
use moa_core::{Error, Address, Addressable};
|
||||
use moa_core::{Address, Addressable};
|
||||
|
||||
use crate::state::Z80Error;
|
||||
use crate::instructions::{Direction, Condition, Register, RegisterPair, IndexRegister, IndexRegisterHalf, SpecialRegister, InterruptMode, Target, LoadTarget, UndocumentedCopy, Instruction};
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -27,7 +28,7 @@ impl Default for Z80Decoder {
|
||||
}
|
||||
|
||||
impl Z80Decoder {
|
||||
pub fn decode_at(&mut self, memory: &mut dyn Addressable, clock: Instant, start: u16) -> Result<(), Error> {
|
||||
pub fn decode_at(&mut self, memory: &mut dyn Addressable, clock: Instant, start: u16) -> Result<(), Z80Error> {
|
||||
self.clock = clock;
|
||||
self.start = start;
|
||||
self.end = start;
|
||||
@ -36,12 +37,12 @@ impl Z80Decoder {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn decode_one(&mut self, memory: &mut dyn Addressable) -> Result<Instruction, Error> {
|
||||
pub fn decode_one(&mut self, memory: &mut dyn Addressable) -> Result<Instruction, Z80Error> {
|
||||
let ins = self.read_instruction_byte(memory)?;
|
||||
self.decode_bare(memory, ins, 0)
|
||||
}
|
||||
|
||||
pub fn decode_bare(&mut self, memory: &mut dyn Addressable, ins: u8, extra_instruction_bytes: u16) -> Result<Instruction, Error> {
|
||||
pub fn decode_bare(&mut self, memory: &mut dyn Addressable, ins: u8, extra_instruction_bytes: u16) -> Result<Instruction, Z80Error> {
|
||||
self.extra_instruction_bytes = extra_instruction_bytes;
|
||||
match get_ins_x(ins) {
|
||||
0 => {
|
||||
@ -217,7 +218,7 @@ impl Z80Decoder {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_prefix_cb(&mut self, memory: &mut dyn Addressable) -> Result<Instruction, Error> {
|
||||
pub fn decode_prefix_cb(&mut self, memory: &mut dyn Addressable) -> Result<Instruction, Z80Error> {
|
||||
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)), None)),
|
||||
@ -228,7 +229,7 @@ impl Z80Decoder {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_sub_prefix_cb(&mut self, memory: &mut dyn Addressable, reg: IndexRegister) -> Result<Instruction, Error> {
|
||||
pub fn decode_sub_prefix_cb(&mut self, memory: &mut dyn Addressable, reg: IndexRegister) -> Result<Instruction, Z80Error> {
|
||||
let offset = self.read_instruction_byte(memory)? as i8;
|
||||
let ins = self.read_instruction_byte(memory)?;
|
||||
let opt_copy = match get_ins_z(ins) {
|
||||
@ -245,7 +246,7 @@ impl Z80Decoder {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_prefix_ed(&mut self, memory: &mut dyn Addressable) -> Result<Instruction, Error> {
|
||||
pub fn decode_prefix_ed(&mut self, memory: &mut dyn Addressable) -> Result<Instruction, Z80Error> {
|
||||
let ins = self.read_instruction_byte(memory)?;
|
||||
|
||||
match get_ins_x(ins) {
|
||||
@ -342,7 +343,7 @@ impl Z80Decoder {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_prefix_dd_fd(&mut self, memory: &mut dyn Addressable, index_reg: IndexRegister) -> Result<Instruction, Error> {
|
||||
pub fn decode_prefix_dd_fd(&mut self, memory: &mut dyn Addressable, index_reg: IndexRegister) -> Result<Instruction, Z80Error> {
|
||||
let ins = self.read_instruction_byte(memory)?;
|
||||
|
||||
if ins == 0xCB {
|
||||
@ -510,7 +511,7 @@ impl Z80Decoder {
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_index_target(&mut self, memory: &mut dyn Addressable, index_reg: IndexRegister, z: u8) -> Result<Option<Target>, Error> {
|
||||
fn decode_index_target(&mut self, memory: &mut dyn Addressable, 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))),
|
||||
@ -525,13 +526,13 @@ impl Z80Decoder {
|
||||
|
||||
|
||||
|
||||
fn read_instruction_byte(&mut self, device: &mut dyn Addressable) -> Result<u8, Error> {
|
||||
fn read_instruction_byte(&mut self, device: &mut dyn Addressable) -> Result<u8, Z80Error> {
|
||||
let byte = device.read_u8(self.clock, self.end as Address)?;
|
||||
self.end = self.end.wrapping_add(1);
|
||||
Ok(byte)
|
||||
}
|
||||
|
||||
fn read_instruction_word(&mut self, device: &mut dyn Addressable) -> Result<u16, Error> {
|
||||
fn read_instruction_word(&mut self, device: &mut dyn Addressable) -> Result<u16, Z80Error> {
|
||||
let word = device.read_leu16(self.clock, self.end as Address)?;
|
||||
self.end = self.end.wrapping_add(2);
|
||||
Ok(word)
|
||||
|
@ -4,7 +4,7 @@ use femtos::{Instant, Duration};
|
||||
use moa_core::{System, Error, Address, Steppable, Addressable, Interruptable, Debuggable, Transmutable, read_beu16, write_beu16};
|
||||
|
||||
use crate::instructions::{Condition, Instruction, LoadTarget, Target, Register, InterruptMode, RegisterPair, IndexRegister, SpecialRegister, IndexRegisterHalf, Size, Direction, UndocumentedCopy};
|
||||
use crate::state::{Z80, Status, Flags};
|
||||
use crate::state::{Z80, Z80Error, Status, Flags};
|
||||
use crate::timing::Z80InstructionCycles;
|
||||
|
||||
|
||||
@ -55,7 +55,27 @@ impl Transmutable for Z80 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Z80Error> for Error {
|
||||
fn from(err: Z80Error) -> Self {
|
||||
match err {
|
||||
Z80Error::Halted => Self::Other("cpu halted".to_string()),
|
||||
Z80Error::Breakpoint => Self::Breakpoint("breakpoint".to_string()),
|
||||
Z80Error::Unimplemented(instruction) => Self::new(format!("unimplemented instruction {:?}", instruction)),
|
||||
Z80Error::BusError(msg) => Self::Other(msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for Z80Error {
|
||||
fn from(err: Error) -> Self {
|
||||
match err {
|
||||
Error::Processor(ex) => Z80Error::BusError(format!("processor error {}", ex)),
|
||||
Error::Breakpoint(msg) => Z80Error::Breakpoint,
|
||||
Error::Other(msg) | Error::Assertion(msg) | Error::Emulator(_, msg) => Z80Error::BusError(format!("{}", msg)),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct Z80Executor {
|
||||
pub current_clock: Instant,
|
||||
@ -72,35 +92,32 @@ impl Z80Executor {
|
||||
}
|
||||
|
||||
impl Z80 {
|
||||
pub fn step_internal(&mut self, system: &System) -> Result<u16, Error> {
|
||||
pub fn step_internal(&mut self, system: &System) -> Result<u16, Z80Error> {
|
||||
self.executor = Z80Executor::at_time(system.clock);
|
||||
match self.state.status {
|
||||
Status::Init => self.init(),
|
||||
Status::Halted => Err(Error::new("CPU stopped")),
|
||||
Status::Halted => Err(Z80Error::Halted),
|
||||
Status::Running => {
|
||||
match self.cycle_one() {
|
||||
Ok(clocks) => Ok(clocks),
|
||||
Err(Error::Processor(_)) => {
|
||||
Ok(4)
|
||||
},
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(&mut self) -> Result<u16, Error> {
|
||||
pub fn init(&mut self) -> Result<u16, Z80Error> {
|
||||
self.state.pc = 0;
|
||||
self.state.status = Status::Running;
|
||||
Ok(16)
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) -> Result<u16, Error> {
|
||||
pub fn reset(&mut self) -> Result<u16, Z80Error> {
|
||||
self.clear_state();
|
||||
Ok(16)
|
||||
}
|
||||
|
||||
pub fn cycle_one(&mut self) -> Result<u16, Error> {
|
||||
pub fn cycle_one(&mut self) -> Result<u16, Z80Error> {
|
||||
self.check_breakpoints()?;
|
||||
|
||||
self.decode_next()?;
|
||||
@ -109,14 +126,14 @@ impl Z80 {
|
||||
.calculate_cycles(self.executor.took_branch))
|
||||
}
|
||||
|
||||
pub fn decode_next(&mut self) -> Result<(), Error> {
|
||||
pub fn decode_next(&mut self) -> Result<(), Z80Error> {
|
||||
self.decoder.decode_at(&mut self.port, self.executor.current_clock, self.state.pc)?;
|
||||
self.increment_refresh(self.decoder.end.saturating_sub(self.decoder.start) as u8);
|
||||
self.state.pc = self.decoder.end;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn execute_current(&mut self) -> Result<(), Error> {
|
||||
pub fn execute_current(&mut self) -> Result<(), Z80Error> {
|
||||
match self.decoder.instruction {
|
||||
Instruction::ADCa(target) => self.execute_adca(target),
|
||||
Instruction::ADC16(dest_pair, src_pair) => self.execute_adc16(dest_pair, src_pair),
|
||||
@ -216,12 +233,12 @@ impl Z80 {
|
||||
Instruction::SUB(target) => self.execute_sub(target),
|
||||
Instruction::XOR(target) => self.execute_xor(target),
|
||||
_ => {
|
||||
Err(Error::new(format!("{}: unimplemented instruction: {:?}", DEV_NAME, self.decoder.instruction)))
|
||||
Err(Z80Error::Unimplemented(self.decoder.instruction.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_adca(&mut self, target: Target) -> Result<(), Error> {
|
||||
fn execute_adca(&mut self, target: Target) -> Result<(), Z80Error> {
|
||||
let src = self.get_target_value(target)?;
|
||||
let acc = self.get_register_value(Register::A);
|
||||
|
||||
@ -233,7 +250,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_adc16(&mut self, dest_pair: RegisterPair, src_pair: RegisterPair) -> Result<(), Error> {
|
||||
fn execute_adc16(&mut self, dest_pair: RegisterPair, src_pair: RegisterPair) -> Result<(), Z80Error> {
|
||||
let src = self.get_register_pair_value(src_pair);
|
||||
let dest = self.get_register_pair_value(dest_pair);
|
||||
|
||||
@ -245,7 +262,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_adda(&mut self, target: Target) -> Result<(), Error> {
|
||||
fn execute_adda(&mut self, target: Target) -> Result<(), Z80Error> {
|
||||
let src = self.get_target_value(target)?;
|
||||
let acc = self.get_register_value(Register::A);
|
||||
|
||||
@ -256,7 +273,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_add16(&mut self, dest_pair: RegisterPair, src_pair: RegisterPair) -> Result<(), Error> {
|
||||
fn execute_add16(&mut self, dest_pair: RegisterPair, src_pair: RegisterPair) -> Result<(), Z80Error> {
|
||||
let src = self.get_register_pair_value(src_pair);
|
||||
let dest = self.get_register_pair_value(dest_pair);
|
||||
|
||||
@ -269,7 +286,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_and(&mut self, target: Target) -> Result<(), Error> {
|
||||
fn execute_and(&mut self, target: Target) -> Result<(), Z80Error> {
|
||||
let acc = self.get_register_value(Register::A);
|
||||
let value = self.get_target_value(target)?;
|
||||
let result = acc & value;
|
||||
@ -278,7 +295,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_bit(&mut self, bit: u8, target: Target) -> Result<(), Error> {
|
||||
fn execute_bit(&mut self, bit: u8, target: Target) -> Result<(), Z80Error> {
|
||||
let value = self.get_target_value(target)?;
|
||||
let result = value & (1 << bit);
|
||||
self.set_flag(Flags::Zero, result == 0);
|
||||
@ -289,13 +306,13 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_call(&mut self, addr: u16) -> Result<(), Error> {
|
||||
fn execute_call(&mut self, addr: u16) -> Result<(), Z80Error> {
|
||||
self.push_word(self.decoder.end)?;
|
||||
self.state.pc = addr;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_callcc(&mut self, cond: Condition, addr: u16) -> Result<(), Error> {
|
||||
fn execute_callcc(&mut self, cond: Condition, addr: u16) -> Result<(), Z80Error> {
|
||||
if self.get_current_condition(cond) {
|
||||
self.executor.took_branch = true;
|
||||
self.push_word(self.decoder.end)?;
|
||||
@ -304,14 +321,14 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_ccf(&mut self) -> Result<(), Error> {
|
||||
fn execute_ccf(&mut self) -> Result<(), Z80Error> {
|
||||
self.set_flag(Flags::AddSubtract, false);
|
||||
self.set_flag(Flags::HalfCarry, self.get_flag(Flags::Carry));
|
||||
self.set_flag(Flags::Carry, !self.get_flag(Flags::Carry));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_cp(&mut self, target: Target) -> Result<(), Error> {
|
||||
fn execute_cp(&mut self, target: Target) -> Result<(), Z80Error> {
|
||||
let src = self.get_target_value(target)?;
|
||||
let acc = self.get_register_value(Register::A);
|
||||
|
||||
@ -329,7 +346,7 @@ impl Z80 {
|
||||
//Instruction::CPIR => {
|
||||
//}
|
||||
|
||||
fn execute_cpl(&mut self) -> Result<(), Error> {
|
||||
fn execute_cpl(&mut self) -> Result<(), Z80Error> {
|
||||
let value = self.get_register_value(Register::A);
|
||||
self.set_register_value(Register::A, !value);
|
||||
self.set_flag(Flags::HalfCarry, true);
|
||||
@ -337,7 +354,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_daa(&mut self) -> Result<(), Error> {
|
||||
fn execute_daa(&mut self) -> Result<(), Z80Error> {
|
||||
// From <http://z80-heaven.wikidot.com/instructions-set:daa>
|
||||
// if the least significant four bits of A contain a non-BCD digit (i. e. it is
|
||||
// greater than 9) or the H flag is set, then $06 is added to the register. Then
|
||||
@ -382,7 +399,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_dec16(&mut self, regpair: RegisterPair) -> Result<(), Error> {
|
||||
fn execute_dec16(&mut self, regpair: RegisterPair) -> Result<(), Z80Error> {
|
||||
let value = self.get_register_pair_value(regpair);
|
||||
|
||||
let (result, _, _, _) = sub_words(value, 1);
|
||||
@ -391,7 +408,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_dec8(&mut self, target: Target) -> Result<(), Error> {
|
||||
fn execute_dec8(&mut self, target: Target) -> Result<(), Z80Error> {
|
||||
let value = self.get_target_value(target)?;
|
||||
|
||||
let (result, _, overflow, half_carry) = sub_bytes(value, 1);
|
||||
@ -402,13 +419,13 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_di(&mut self) -> Result<(), Error> {
|
||||
fn execute_di(&mut self) -> Result<(), Z80Error> {
|
||||
self.state.iff1 = false;
|
||||
self.state.iff2 = false;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_djnz(&mut self, offset: i8) -> Result<(), Error> {
|
||||
fn execute_djnz(&mut self, offset: i8) -> Result<(), Z80Error> {
|
||||
let value = self.get_register_value(Register::B);
|
||||
let result = value.wrapping_sub(1);
|
||||
self.set_register_value(Register::B, result);
|
||||
@ -420,13 +437,13 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_ei(&mut self) -> Result<(), Error> {
|
||||
fn execute_ei(&mut self) -> Result<(), Z80Error> {
|
||||
self.state.iff1 = true;
|
||||
self.state.iff2 = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_exx(&mut self) -> Result<(), Error> {
|
||||
fn execute_exx(&mut self) -> Result<(), Z80Error> {
|
||||
for i in 0..6 {
|
||||
let (normal, shadow) = (self.state.reg[i], self.state.shadow_reg[i]);
|
||||
self.state.reg[i] = shadow;
|
||||
@ -435,7 +452,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_ex_af_af(&mut self) -> Result<(), Error> {
|
||||
fn execute_ex_af_af(&mut self) -> Result<(), Z80Error> {
|
||||
for i in 6..8 {
|
||||
let (normal, shadow) = (self.state.reg[i], self.state.shadow_reg[i]);
|
||||
self.state.reg[i] = shadow;
|
||||
@ -444,14 +461,14 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_ex_hl_de(&mut self) -> Result<(), Error> {
|
||||
fn execute_ex_hl_de(&mut self) -> Result<(), Z80Error> {
|
||||
let (hl, de) = (self.get_register_pair_value(RegisterPair::HL), self.get_register_pair_value(RegisterPair::DE));
|
||||
self.set_register_pair_value(RegisterPair::DE, hl);
|
||||
self.set_register_pair_value(RegisterPair::HL, de);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_ex_sp(&mut self, regpair: RegisterPair) -> Result<(), Error> {
|
||||
fn execute_ex_sp(&mut self, regpair: RegisterPair) -> Result<(), Z80Error> {
|
||||
let reg_value = self.get_register_pair_value(regpair);
|
||||
let sp = self.get_register_pair_value(RegisterPair::SP);
|
||||
let sp_value = self.read_port_u16(sp)?;
|
||||
@ -460,18 +477,18 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_halt(&mut self) -> Result<(), Error> {
|
||||
fn execute_halt(&mut self) -> Result<(), Z80Error> {
|
||||
self.state.status = Status::Halted;
|
||||
self.state.pc -= 1;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_im(&mut self, mode: InterruptMode) -> Result<(), Error> {
|
||||
fn execute_im(&mut self, mode: InterruptMode) -> Result<(), Z80Error> {
|
||||
self.state.im = mode;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_inc16(&mut self, regpair: RegisterPair) -> Result<(), Error> {
|
||||
fn execute_inc16(&mut self, regpair: RegisterPair) -> Result<(), Z80Error> {
|
||||
let value = self.get_register_pair_value(regpair);
|
||||
|
||||
let (result, _, _, _) = add_words(value, 1);
|
||||
@ -480,7 +497,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_inc8(&mut self, target: Target) -> Result<(), Error> {
|
||||
fn execute_inc8(&mut self, target: Target) -> Result<(), Z80Error> {
|
||||
let value = self.get_target_value(target)?;
|
||||
let (result, _, overflow, half_carry) = add_bytes(value, 1);
|
||||
let carry = self.get_flag(Flags::Carry); // Preserve the carry bit, according to Z80 reference
|
||||
@ -495,7 +512,7 @@ impl Z80 {
|
||||
//Instruction::INDR => {
|
||||
//}
|
||||
|
||||
fn execute_ini(&mut self) -> Result<(), Error> {
|
||||
fn execute_ini(&mut self) -> Result<(), Z80Error> {
|
||||
let b = self.get_register_value(Register::B);
|
||||
let c = self.get_register_value(Register::C);
|
||||
let value = self.read_ioport_value(b, c)?;
|
||||
@ -511,7 +528,7 @@ impl Z80 {
|
||||
//Instruction::INIR => {
|
||||
//}
|
||||
|
||||
fn execute_inic(&mut self, reg: Register) -> Result<(), Error> {
|
||||
fn execute_inic(&mut self, reg: Register) -> Result<(), Z80Error> {
|
||||
let b = self.get_register_value(Register::B);
|
||||
let c = self.get_register_value(Register::C);
|
||||
let value = self.read_ioport_value(b, c)?;
|
||||
@ -527,25 +544,25 @@ impl Z80 {
|
||||
//Instruction::INicz => {
|
||||
//}
|
||||
|
||||
fn execute_inx(&mut self, n: u8) -> Result<(), Error> {
|
||||
fn execute_inx(&mut self, n: u8) -> Result<(), Z80Error> {
|
||||
let a = self.get_register_value(Register::A);
|
||||
let value = self.read_ioport_value(a, n)?;
|
||||
self.set_register_value(Register::A, value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_jp(&mut self, addr: u16) -> Result<(), Error> {
|
||||
fn execute_jp(&mut self, addr: u16) -> Result<(), Z80Error> {
|
||||
self.state.pc = addr;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_jp_indirect(&mut self, regpair: RegisterPair) -> Result<(), Error> {
|
||||
fn execute_jp_indirect(&mut self, regpair: RegisterPair) -> Result<(), Z80Error> {
|
||||
let value = self.get_register_pair_value(regpair);
|
||||
self.state.pc = value;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_jpcc(&mut self, cond: Condition, addr: u16) -> Result<(), Error> {
|
||||
fn execute_jpcc(&mut self, cond: Condition, addr: u16) -> Result<(), Z80Error> {
|
||||
if self.get_current_condition(cond) {
|
||||
self.executor.took_branch = true;
|
||||
self.state.pc = addr;
|
||||
@ -553,12 +570,12 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_jr(&mut self, offset: i8) -> Result<(), Error> {
|
||||
fn execute_jr(&mut self, offset: i8) -> Result<(), Z80Error> {
|
||||
self.state.pc = self.state.pc.wrapping_add_signed(offset as i16);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_jrcc(&mut self, cond: Condition, offset: i8) -> Result<(), Error> {
|
||||
fn execute_jrcc(&mut self, cond: Condition, offset: i8) -> Result<(), Z80Error> {
|
||||
if self.get_current_condition(cond) {
|
||||
self.executor.took_branch = true;
|
||||
self.state.pc = self.state.pc.wrapping_add_signed(offset as i16);
|
||||
@ -566,13 +583,13 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_ld(&mut self, dest: LoadTarget, src: LoadTarget) -> Result<(), Error> {
|
||||
fn execute_ld(&mut self, dest: LoadTarget, src: LoadTarget) -> Result<(), Z80Error> {
|
||||
let src_value = self.get_load_target_value(src)?;
|
||||
self.set_load_target_value(dest, src_value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_ldsr(&mut self, special_reg: SpecialRegister, dir: Direction) -> Result<(), Error> {
|
||||
fn execute_ldsr(&mut self, special_reg: SpecialRegister, dir: Direction) -> Result<(), Z80Error> {
|
||||
let addr = match special_reg {
|
||||
SpecialRegister::I => &mut self.state.i,
|
||||
SpecialRegister::R => &mut self.state.r,
|
||||
@ -595,7 +612,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_ldx(&mut self) -> Result<(), Error> {
|
||||
fn execute_ldx(&mut self) -> Result<(), Z80Error> {
|
||||
let diff = if self.decoder.instruction == Instruction::LDI || self.decoder.instruction == Instruction::LDIR {
|
||||
1
|
||||
} else {
|
||||
@ -620,7 +637,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_neg(&mut self) -> Result<(), Error> {
|
||||
fn execute_neg(&mut self) -> Result<(), Z80Error> {
|
||||
let acc = self.get_register_value(Register::A);
|
||||
|
||||
let (result, carry, overflow, half_carry) = sub_bytes(0, acc);
|
||||
@ -630,7 +647,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_or(&mut self, target: Target) -> Result<(), Error> {
|
||||
fn execute_or(&mut self, target: Target) -> Result<(), Z80Error> {
|
||||
let acc = self.get_register_value(Register::A);
|
||||
let value = self.get_target_value(target)?;
|
||||
let result = acc | value;
|
||||
@ -648,7 +665,7 @@ impl Z80 {
|
||||
//Instruction::OUTI => {
|
||||
//}
|
||||
|
||||
fn execute_outic(&mut self, reg: Register) -> Result<(), Error> {
|
||||
fn execute_outic(&mut self, reg: Register) -> Result<(), Z80Error> {
|
||||
let b = self.get_register_value(Register::B);
|
||||
let c = self.get_register_value(Register::C);
|
||||
let value = self.get_register_value(reg);
|
||||
@ -659,26 +676,26 @@ impl Z80 {
|
||||
//Instruction::OUTicz => {
|
||||
//}
|
||||
|
||||
fn execute_outx(&mut self, n: u8) -> Result<(), Error> {
|
||||
fn execute_outx(&mut self, n: u8) -> Result<(), Z80Error> {
|
||||
let a = self.get_register_value(Register::A);
|
||||
let value = self.get_register_value(Register::A);
|
||||
self.write_ioport_value(a, n, value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_pop(&mut self, regpair: RegisterPair) -> Result<(), Error> {
|
||||
fn execute_pop(&mut self, regpair: RegisterPair) -> Result<(), Z80Error> {
|
||||
let value = self.pop_word()?;
|
||||
self.set_register_pair_value(regpair, value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_push(&mut self, regpair: RegisterPair) -> Result<(), Error> {
|
||||
fn execute_push(&mut self, regpair: RegisterPair) -> Result<(), Z80Error> {
|
||||
let value = self.get_register_pair_value(regpair);
|
||||
self.push_word(value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_res(&mut self, bit: u8, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Error> {
|
||||
fn execute_res(&mut self, bit: u8, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Z80Error> {
|
||||
let mut value = self.get_target_value(target)?;
|
||||
value &= !(1 << bit);
|
||||
self.set_target_value(target, value)?;
|
||||
@ -688,24 +705,24 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_ret(&mut self) -> Result<(), Error> {
|
||||
fn execute_ret(&mut self) -> Result<(), Z80Error> {
|
||||
self.state.pc = self.pop_word()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_reti(&mut self) -> Result<(), Error> {
|
||||
fn execute_reti(&mut self) -> Result<(), Z80Error> {
|
||||
self.state.pc = self.pop_word()?;
|
||||
self.state.iff1 = self.state.iff2;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_retn(&mut self) -> Result<(), Error> {
|
||||
fn execute_retn(&mut self) -> Result<(), Z80Error> {
|
||||
self.state.pc = self.pop_word()?;
|
||||
self.state.iff1 = self.state.iff2;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_retcc(&mut self, cond: Condition) -> Result<(), Error> {
|
||||
fn execute_retcc(&mut self, cond: Condition) -> Result<(), Z80Error> {
|
||||
if self.get_current_condition(cond) {
|
||||
self.executor.took_branch = true;
|
||||
self.state.pc = self.pop_word()?;
|
||||
@ -713,7 +730,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_rl(&mut self, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Error> {
|
||||
fn execute_rl(&mut self, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Z80Error> {
|
||||
let value = self.get_target_value(target)?;
|
||||
let (result, out_bit) = self.rotate_left(value, RotateType::Bit9);
|
||||
self.set_logic_op_flags(result, out_bit, false);
|
||||
@ -724,7 +741,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_rla(&mut self) -> Result<(), Error> {
|
||||
fn execute_rla(&mut self) -> Result<(), Z80Error> {
|
||||
let value = self.get_register_value(Register::A);
|
||||
let (result, out_bit) = self.rotate_left(value, RotateType::Bit9);
|
||||
self.set_flag(Flags::AddSubtract, false);
|
||||
@ -734,7 +751,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_rlc(&mut self, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Error> {
|
||||
fn execute_rlc(&mut self, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Z80Error> {
|
||||
let value = self.get_target_value(target)?;
|
||||
let (result, out_bit) = self.rotate_left(value, RotateType::Bit8);
|
||||
self.set_logic_op_flags(result, out_bit, false);
|
||||
@ -745,7 +762,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_rlca(&mut self) -> Result<(), Error> {
|
||||
fn execute_rlca(&mut self) -> Result<(), Z80Error> {
|
||||
let value = self.get_register_value(Register::A);
|
||||
let (result, out_bit) = self.rotate_left(value, RotateType::Bit8);
|
||||
self.set_flag(Flags::AddSubtract, false);
|
||||
@ -755,7 +772,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_rld(&mut self) -> Result<(), Error> {
|
||||
fn execute_rld(&mut self) -> Result<(), Z80Error> {
|
||||
let a = self.get_register_value(Register::A);
|
||||
let mem = self.get_load_target_value(LoadTarget::IndirectRegByte(RegisterPair::HL))? as u8;
|
||||
|
||||
@ -773,7 +790,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_rr(&mut self, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Error> {
|
||||
fn execute_rr(&mut self, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Z80Error> {
|
||||
let value = self.get_target_value(target)?;
|
||||
let (result, out_bit) = self.rotate_right(value, RotateType::Bit9);
|
||||
self.set_logic_op_flags(result, out_bit, false);
|
||||
@ -784,7 +801,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_rra(&mut self) -> Result<(), Error> {
|
||||
fn execute_rra(&mut self) -> Result<(), Z80Error> {
|
||||
let value = self.get_register_value(Register::A);
|
||||
let (result, out_bit) = self.rotate_right(value, RotateType::Bit9);
|
||||
self.set_flag(Flags::AddSubtract, false);
|
||||
@ -794,7 +811,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_rrc(&mut self, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Error> {
|
||||
fn execute_rrc(&mut self, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Z80Error> {
|
||||
let value = self.get_target_value(target)?;
|
||||
let (result, out_bit) = self.rotate_right(value, RotateType::Bit8);
|
||||
self.set_logic_op_flags(result, out_bit, false);
|
||||
@ -805,7 +822,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_rrca(&mut self) -> Result<(), Error> {
|
||||
fn execute_rrca(&mut self) -> Result<(), Z80Error> {
|
||||
let value = self.get_register_value(Register::A);
|
||||
let (result, out_bit) = self.rotate_right(value, RotateType::Bit8);
|
||||
self.set_flag(Flags::AddSubtract, false);
|
||||
@ -815,7 +832,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_rrd(&mut self) -> Result<(), Error> {
|
||||
fn execute_rrd(&mut self) -> Result<(), Z80Error> {
|
||||
let a = self.get_register_value(Register::A);
|
||||
let mem = self.get_load_target_value(LoadTarget::IndirectRegByte(RegisterPair::HL))? as u8;
|
||||
|
||||
@ -833,13 +850,13 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_rst(&mut self, addr: u8) -> Result<(), Error> {
|
||||
fn execute_rst(&mut self, addr: u8) -> Result<(), Z80Error> {
|
||||
self.push_word(self.decoder.end)?;
|
||||
self.state.pc = addr as u16;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_sbca(&mut self, target: Target) -> Result<(), Error> {
|
||||
fn execute_sbca(&mut self, target: Target) -> Result<(), Z80Error> {
|
||||
let src = self.get_target_value(target)?;
|
||||
let acc = self.get_register_value(Register::A);
|
||||
|
||||
@ -851,7 +868,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_sbc16(&mut self, dest_pair: RegisterPair, src_pair: RegisterPair) -> Result<(), Error> {
|
||||
fn execute_sbc16(&mut self, dest_pair: RegisterPair, src_pair: RegisterPair) -> Result<(), Z80Error> {
|
||||
let src = self.get_register_pair_value(src_pair);
|
||||
let dest = self.get_register_pair_value(dest_pair);
|
||||
|
||||
@ -863,14 +880,14 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_scf(&mut self) -> Result<(), Error> {
|
||||
fn execute_scf(&mut self) -> Result<(), Z80Error> {
|
||||
self.set_flag(Flags::AddSubtract, false);
|
||||
self.set_flag(Flags::HalfCarry, false);
|
||||
self.set_flag(Flags::Carry, true);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_set(&mut self, bit: u8, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Error> {
|
||||
fn execute_set(&mut self, bit: u8, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Z80Error> {
|
||||
let mut value = self.get_target_value(target)?;
|
||||
value |= 1 << bit;
|
||||
self.set_target_value(target, value)?;
|
||||
@ -880,7 +897,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_sla(&mut self, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Error> {
|
||||
fn execute_sla(&mut self, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Z80Error> {
|
||||
let value = self.get_target_value(target)?;
|
||||
let out_bit = get_msb(value as u16, Size::Byte);
|
||||
let result = value << 1;
|
||||
@ -892,7 +909,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_sll(&mut self, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Error> {
|
||||
fn execute_sll(&mut self, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Z80Error> {
|
||||
let value = self.get_target_value(target)?;
|
||||
let out_bit = get_msb(value as u16, Size::Byte);
|
||||
let result = (value << 1) | 0x01;
|
||||
@ -904,7 +921,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_sra(&mut self, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Error> {
|
||||
fn execute_sra(&mut self, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Z80Error> {
|
||||
let value = self.get_target_value(target)?;
|
||||
let out_bit = (value & 0x01) != 0;
|
||||
let msb_mask = if get_msb(value as u16, Size::Byte) { 0x80 } else { 0 };
|
||||
@ -917,7 +934,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_srl(&mut self, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Error> {
|
||||
fn execute_srl(&mut self, target: Target, opt_copy: UndocumentedCopy) -> Result<(), Z80Error> {
|
||||
let value = self.get_target_value(target)?;
|
||||
let out_bit = (value & 0x01) != 0;
|
||||
let result = value >> 1;
|
||||
@ -929,7 +946,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_sub(&mut self, target: Target) -> Result<(), Error> {
|
||||
fn execute_sub(&mut self, target: Target) -> Result<(), Z80Error> {
|
||||
let src = self.get_target_value(target)?;
|
||||
let acc = self.get_register_value(Register::A);
|
||||
|
||||
@ -940,7 +957,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_xor(&mut self, target: Target) -> Result<(), Error> {
|
||||
fn execute_xor(&mut self, target: Target) -> Result<(), Z80Error> {
|
||||
let acc = self.get_register_value(Register::A);
|
||||
let value = self.get_target_value(target)?;
|
||||
let result = acc ^ value;
|
||||
@ -992,7 +1009,7 @@ impl Z80 {
|
||||
|
||||
|
||||
|
||||
fn push_word(&mut self, value: u16) -> Result<(), Error> {
|
||||
fn push_word(&mut self, value: u16) -> Result<(), Z80Error> {
|
||||
self.state.sp = self.state.sp.wrapping_sub(1);
|
||||
self.write_port_u8(self.state.sp, (value >> 8) as u8)?;
|
||||
self.state.sp = self.state.sp.wrapping_sub(1);
|
||||
@ -1000,7 +1017,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pop_word(&mut self) -> Result<u16, Error> {
|
||||
fn pop_word(&mut self) -> Result<u16, Z80Error> {
|
||||
let mut value;
|
||||
value = self.read_port_u8(self.state.sp)? as u16;
|
||||
self.state.sp = self.state.sp.wrapping_add(1);
|
||||
@ -1009,7 +1026,7 @@ impl Z80 {
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn get_load_target_value(&mut self, target: LoadTarget) -> Result<u16, Error> {
|
||||
fn get_load_target_value(&mut self, target: LoadTarget) -> Result<u16, Z80Error> {
|
||||
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,
|
||||
@ -1039,7 +1056,7 @@ impl Z80 {
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn set_load_target_value(&mut self, target: LoadTarget, value: u16) -> Result<(), Error> {
|
||||
fn set_load_target_value(&mut self, target: LoadTarget, value: u16) -> Result<(), Z80Error> {
|
||||
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),
|
||||
@ -1067,7 +1084,7 @@ impl Z80 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_target_value(&mut self, target: Target) -> Result<u8, Error> {
|
||||
fn get_target_value(&mut self, target: Target) -> Result<u8, Z80Error> {
|
||||
match target {
|
||||
Target::DirectReg(reg) => Ok(self.get_register_value(reg)),
|
||||
Target::DirectRegHalf(reg) => Ok(self.get_index_register_half_value(reg)),
|
||||
@ -1083,7 +1100,7 @@ impl Z80 {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_target_value(&mut self, target: Target, value: u8) -> Result<(), Error> {
|
||||
fn set_target_value(&mut self, target: Target, value: u8) -> Result<(), Z80Error> {
|
||||
match target {
|
||||
Target::DirectReg(reg) => self.set_register_value(reg, value),
|
||||
Target::DirectRegHalf(reg) => self.set_index_register_half_value(reg, value),
|
||||
@ -1104,27 +1121,27 @@ impl Z80 {
|
||||
self.state.r = (self.state.r & 0x80) | ((self.state.r + count) & 0x7F);
|
||||
}
|
||||
|
||||
fn read_port_u8(&mut self, addr: u16) -> Result<u8, Error> {
|
||||
fn read_port_u8(&mut self, addr: u16) -> Result<u8, Z80Error> {
|
||||
self.increment_refresh(1);
|
||||
self.port.read_u8(self.executor.current_clock, addr as Address)
|
||||
Ok(self.port.read_u8(self.executor.current_clock, addr as Address)?)
|
||||
}
|
||||
|
||||
fn write_port_u8(&mut self, addr: u16, value: u8) -> Result<(), Error> {
|
||||
fn write_port_u8(&mut self, addr: u16, value: u8) -> Result<(), Z80Error> {
|
||||
self.increment_refresh(1);
|
||||
self.port.write_u8(self.executor.current_clock, addr as Address, value)
|
||||
Ok(self.port.write_u8(self.executor.current_clock, addr as Address, value)?)
|
||||
}
|
||||
|
||||
fn read_port_u16(&mut self, addr: u16) -> Result<u16, Error> {
|
||||
fn read_port_u16(&mut self, addr: u16) -> Result<u16, Z80Error> {
|
||||
self.increment_refresh(2);
|
||||
self.port.read_leu16(self.executor.current_clock, addr as Address)
|
||||
Ok(self.port.read_leu16(self.executor.current_clock, addr as Address)?)
|
||||
}
|
||||
|
||||
fn write_port_u16(&mut self, addr: u16, value: u16) -> Result<(), Error> {
|
||||
fn write_port_u16(&mut self, addr: u16, value: u16) -> Result<(), Z80Error> {
|
||||
self.increment_refresh(2);
|
||||
self.port.write_leu16(self.executor.current_clock, addr as Address, value)
|
||||
Ok(self.port.write_leu16(self.executor.current_clock, addr as Address, value)?)
|
||||
}
|
||||
|
||||
fn read_ioport_value(&mut self, upper: u8, lower: u8) -> Result<u8, Error> {
|
||||
fn read_ioport_value(&mut self, upper: u8, lower: u8) -> Result<u8, Z80Error> {
|
||||
let addr = ((upper as Address) << 8) | (lower as Address);
|
||||
if let Some(io) = self.ioport.as_mut() {
|
||||
Ok(io.read_u8(self.executor.current_clock, addr)?)
|
||||
@ -1133,7 +1150,7 @@ impl Z80 {
|
||||
}
|
||||
}
|
||||
|
||||
fn write_ioport_value(&mut self, upper: u8, lower: u8, value: u8) -> Result<(), Error> {
|
||||
fn write_ioport_value(&mut self, upper: u8, lower: u8, value: u8) -> Result<(), Z80Error> {
|
||||
let addr = ((upper as Address) << 8) | (lower as Address);
|
||||
if let Some(io) = self.ioport.as_mut() {
|
||||
io.write_u8(self.executor.current_clock, addr, value)?
|
||||
|
@ -6,5 +6,5 @@ pub mod instructions;
|
||||
pub mod state;
|
||||
pub mod timing;
|
||||
|
||||
pub use self::state::{Z80, Z80Type};
|
||||
pub use self::state::{Z80, Z80Type, Z80Error};
|
||||
|
||||
|
@ -9,7 +9,7 @@ use moa_signals::Signal;
|
||||
use crate::decode::Z80Decoder;
|
||||
use crate::debugger::Z80Debugger;
|
||||
use crate::execute::Z80Executor;
|
||||
use crate::instructions::{Register, InterruptMode};
|
||||
use crate::instructions::{Instruction, Register, InterruptMode};
|
||||
|
||||
|
||||
#[allow(dead_code)]
|
||||
@ -92,6 +92,18 @@ impl Z80State {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, thiserror::Error)]
|
||||
pub enum Z80Error {
|
||||
#[error("cpu halted")]
|
||||
Halted,
|
||||
#[error("breakpoint reached")]
|
||||
Breakpoint,
|
||||
#[error("unimplemented instruction {0:?}")]
|
||||
Unimplemented(Instruction),
|
||||
#[error("bus error: {0}")]
|
||||
BusError(String),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Z80 {
|
||||
pub cputype: Z80Type,
|
||||
|
Loading…
Reference in New Issue
Block a user