mirror of
https://github.com/transistorfet/moa.git
synced 2025-02-19 15:31:35 +00:00
Added debugging and shift instructions to Z80
This commit is contained in:
parent
3da58c8d17
commit
2c6a1a1b3a
61
src/cpus/z80/debugger.rs
Normal file
61
src/cpus/z80/debugger.rs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
|
||||||
|
use crate::error::Error;
|
||||||
|
use crate::system::System;
|
||||||
|
use crate::devices::{Address, Addressable, Debuggable};
|
||||||
|
|
||||||
|
use super::state::Z80;
|
||||||
|
use super::decode::Z80Decoder;
|
||||||
|
|
||||||
|
|
||||||
|
pub struct Z80Debugger {
|
||||||
|
pub breakpoints: Vec<u16>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Z80Debugger {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
breakpoints: vec!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debuggable for Z80 {
|
||||||
|
fn add_breakpoint(&mut self, addr: Address) {
|
||||||
|
self.debugger.breakpoints.push(addr as u16);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_breakpoint(&mut self, addr: Address) {
|
||||||
|
if let Some(index) = self.debugger.breakpoints.iter().position(|a| *a == addr as u16) {
|
||||||
|
self.debugger.breakpoints.remove(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_current_step(&mut self, system: &System) -> Result<(), Error> {
|
||||||
|
self.decoder.decode_at(&mut self.port, self.state.pc)?;
|
||||||
|
self.decoder.dump_decoded(&mut self.port);
|
||||||
|
self.dump_state(system);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_disassembly(&mut self, addr: Address, count: usize) {
|
||||||
|
let mut decoder = Z80Decoder::new();
|
||||||
|
//decoder.dump_disassembly(&mut self.port, self.state.pc, 0x1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_command(&mut self, system: &System, args: &[&str]) -> Result<bool, Error> {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Z80 {
|
||||||
|
pub fn check_breakpoints(&mut self, system: &System) {
|
||||||
|
for breakpoint in &self.debugger.breakpoints {
|
||||||
|
if *breakpoint == self.state.pc {
|
||||||
|
println!("Breakpoint reached: {:08x}", *breakpoint);
|
||||||
|
system.enable_debugging();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,9 @@ use super::decode::{Condition, Instruction, LoadTarget, Target, OptionalSource,
|
|||||||
use super::state::{Z80, Status, Flags, Register};
|
use super::state::{Z80, Status, Flags, Register};
|
||||||
|
|
||||||
|
|
||||||
|
const DEV_NAME: &'static str = "z80-cpu";
|
||||||
|
|
||||||
|
|
||||||
enum RotateType {
|
enum RotateType {
|
||||||
Bit8,
|
Bit8,
|
||||||
Bit9,
|
Bit9,
|
||||||
@ -20,40 +23,12 @@ impl Steppable for Z80 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn on_error(&mut self, system: &System) {
|
fn on_error(&mut self, system: &System) {
|
||||||
//self.dump_state(system);
|
self.dump_state(system);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interruptable for Z80 { }
|
impl Interruptable for Z80 { }
|
||||||
|
|
||||||
impl Debuggable for Z80 {
|
|
||||||
fn add_breakpoint(&mut self, addr: Address) {
|
|
||||||
//self.debugger.breakpoints.push(addr as u32);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_breakpoint(&mut self, addr: Address) {
|
|
||||||
//if let Some(index) = self.debugger.breakpoints.iter().position(|a| *a == addr as u32) {
|
|
||||||
// self.debugger.breakpoints.remove(index);
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_current_step(&mut self, system: &System) -> Result<(), Error> {
|
|
||||||
//self.decoder.decode_at(&mut self.port, self.state.pc)?;
|
|
||||||
//self.decoder.dump_decoded(&mut self.port);
|
|
||||||
self.dump_state(system);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_disassembly(&mut self, addr: Address, count: usize) {
|
|
||||||
//let mut decoder = M68kDecoder::new(self.cputype, 0);
|
|
||||||
//decoder.dump_disassembly(&mut self.port, self.state.pc, 0x1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_command(&mut self, system: &System, args: &[&str]) -> Result<bool, Error> {
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl Transmutable for Z80 {
|
impl Transmutable for Z80 {
|
||||||
fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
|
fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
|
||||||
@ -112,13 +87,14 @@ impl Z80 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode_next(&mut self, system: &System) -> Result<(), Error> {
|
pub fn decode_next(&mut self, system: &System) -> Result<(), Error> {
|
||||||
//self.check_breakpoints(system);
|
self.check_breakpoints(system);
|
||||||
|
|
||||||
//self.timer.decode.start();
|
//self.timer.decode.start();
|
||||||
self.decoder.decode_at(&mut self.port, self.state.pc)?;
|
self.decoder.decode_at(&mut self.port, self.state.pc)?;
|
||||||
//self.timer.decode.end();
|
//self.timer.decode.end();
|
||||||
|
|
||||||
//if self.debugger.use_tracing {
|
//if self.debugger.use_tracing {
|
||||||
|
//self.decoder.dump_decoded(&mut self.port);
|
||||||
//self.dump_state(system);
|
//self.dump_state(system);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
@ -350,7 +326,7 @@ impl Z80 {
|
|||||||
//},
|
//},
|
||||||
Instruction::OUTx(port) => {
|
Instruction::OUTx(port) => {
|
||||||
// TODO this needs to be fixed
|
// TODO this needs to be fixed
|
||||||
println!("OUT: {:x}", self.state.reg[Register::A as usize]);
|
println!("OUT ({:x}), {:x}", port, self.state.reg[Register::A as usize]);
|
||||||
},
|
},
|
||||||
Instruction::POP(regpair) => {
|
Instruction::POP(regpair) => {
|
||||||
let value = self.pop_word()?;
|
let value = self.pop_word()?;
|
||||||
@ -379,52 +355,52 @@ impl Z80 {
|
|||||||
},
|
},
|
||||||
Instruction::RL(target, opt_src) => {
|
Instruction::RL(target, opt_src) => {
|
||||||
let value = self.get_opt_src_target_value(opt_src, target)?;
|
let value = self.get_opt_src_target_value(opt_src, target)?;
|
||||||
let result = self.rotate_left(value, RotateType::Bit9);
|
let (result, out_bit) = self.rotate_left(value, RotateType::Bit9);
|
||||||
self.set_logic_op_flags(result as u16, Size::Byte, false);
|
self.set_logic_op_flags(result as u16, Size::Byte, out_bit);
|
||||||
self.set_target_value(target, result)?;
|
self.set_target_value(target, result)?;
|
||||||
},
|
},
|
||||||
Instruction::RLA => {
|
Instruction::RLA => {
|
||||||
let value = self.get_register_value(Register::A);
|
let value = self.get_register_value(Register::A);
|
||||||
let result = self.rotate_left(value, RotateType::Bit9);
|
let (result, out_bit) = self.rotate_left(value, RotateType::Bit9);
|
||||||
self.set_logic_op_flags(result as u16, Size::Byte, false);
|
self.set_logic_op_flags(result as u16, Size::Byte, out_bit);
|
||||||
self.set_register_value(Register::A, result);
|
self.set_register_value(Register::A, result);
|
||||||
},
|
},
|
||||||
Instruction::RLC(target, opt_src) => {
|
Instruction::RLC(target, opt_src) => {
|
||||||
let value = self.get_opt_src_target_value(opt_src, target)?;
|
let value = self.get_opt_src_target_value(opt_src, target)?;
|
||||||
let result = self.rotate_left(value, RotateType::Bit8);
|
let (result, out_bit) = self.rotate_left(value, RotateType::Bit8);
|
||||||
self.set_logic_op_flags(result as u16, Size::Byte, false);
|
self.set_logic_op_flags(result as u16, Size::Byte, out_bit);
|
||||||
self.set_target_value(target, result)?;
|
self.set_target_value(target, result)?;
|
||||||
},
|
},
|
||||||
Instruction::RLCA => {
|
Instruction::RLCA => {
|
||||||
let value = self.get_register_value(Register::A);
|
let value = self.get_register_value(Register::A);
|
||||||
let result = self.rotate_left(value, RotateType::Bit8);
|
let (result, out_bit) = self.rotate_left(value, RotateType::Bit8);
|
||||||
self.set_logic_op_flags(result as u16, Size::Byte, false);
|
self.set_logic_op_flags(result as u16, Size::Byte, out_bit);
|
||||||
self.set_register_value(Register::A, result);
|
self.set_register_value(Register::A, result);
|
||||||
},
|
},
|
||||||
//Instruction::RLD => {
|
//Instruction::RLD => {
|
||||||
//},
|
//},
|
||||||
Instruction::RR(target, opt_src) => {
|
Instruction::RR(target, opt_src) => {
|
||||||
let value = self.get_opt_src_target_value(opt_src, target)?;
|
let value = self.get_opt_src_target_value(opt_src, target)?;
|
||||||
let result = self.rotate_right(value, RotateType::Bit9);
|
let (result, out_bit) = self.rotate_right(value, RotateType::Bit9);
|
||||||
self.set_logic_op_flags(result as u16, Size::Byte, false);
|
self.set_logic_op_flags(result as u16, Size::Byte, out_bit);
|
||||||
self.set_target_value(target, result)?;
|
self.set_target_value(target, result)?;
|
||||||
},
|
},
|
||||||
Instruction::RRA => {
|
Instruction::RRA => {
|
||||||
let value = self.get_register_value(Register::A);
|
let value = self.get_register_value(Register::A);
|
||||||
let result = self.rotate_right(value, RotateType::Bit9);
|
let (result, out_bit) = self.rotate_right(value, RotateType::Bit9);
|
||||||
self.set_logic_op_flags(result as u16, Size::Byte, false);
|
self.set_logic_op_flags(result as u16, Size::Byte, out_bit);
|
||||||
self.set_register_value(Register::A, result);
|
self.set_register_value(Register::A, result);
|
||||||
},
|
},
|
||||||
Instruction::RRC(target, opt_src) => {
|
Instruction::RRC(target, opt_src) => {
|
||||||
let value = self.get_opt_src_target_value(opt_src, target)?;
|
let value = self.get_opt_src_target_value(opt_src, target)?;
|
||||||
let result = self.rotate_right(value, RotateType::Bit8);
|
let (result, out_bit) = self.rotate_right(value, RotateType::Bit8);
|
||||||
self.set_logic_op_flags(result as u16, Size::Byte, false);
|
self.set_logic_op_flags(result as u16, Size::Byte, out_bit);
|
||||||
self.set_target_value(target, result)?;
|
self.set_target_value(target, result)?;
|
||||||
},
|
},
|
||||||
Instruction::RRCA => {
|
Instruction::RRCA => {
|
||||||
let value = self.get_register_value(Register::A);
|
let value = self.get_register_value(Register::A);
|
||||||
let result = self.rotate_right(value, RotateType::Bit8);
|
let (result, out_bit) = self.rotate_right(value, RotateType::Bit8);
|
||||||
self.set_logic_op_flags(result as u16, Size::Byte, false);
|
self.set_logic_op_flags(result as u16, Size::Byte, out_bit);
|
||||||
self.set_register_value(Register::A, result);
|
self.set_register_value(Register::A, result);
|
||||||
},
|
},
|
||||||
//Instruction::RRD => {
|
//Instruction::RRD => {
|
||||||
@ -457,14 +433,35 @@ impl Z80 {
|
|||||||
value = value | (1 << bit);
|
value = value | (1 << bit);
|
||||||
self.set_target_value(target, value);
|
self.set_target_value(target, value);
|
||||||
},
|
},
|
||||||
//Instruction::SLA(target, opt_src) => {
|
Instruction::SLA(target, opt_src) => {
|
||||||
//},
|
let value = self.get_opt_src_target_value(opt_src, target)?;
|
||||||
//Instruction::SLL(target, opt_src) => {
|
let out_bit = get_msb(value as u16, Size::Byte);
|
||||||
//},
|
let result = (value << 1) | 0x01;
|
||||||
//Instruction::SRA(target, opt_src) => {
|
self.set_logic_op_flags(result as u16, Size::Byte, out_bit);
|
||||||
//},
|
self.set_target_value(target, result)?;
|
||||||
//Instruction::SRL(target, opt_src) => {
|
},
|
||||||
//},
|
Instruction::SLL(target, opt_src) => {
|
||||||
|
let value = self.get_opt_src_target_value(opt_src, target)?;
|
||||||
|
let out_bit = get_msb(value as u16, Size::Byte);
|
||||||
|
let result = value << 1;
|
||||||
|
self.set_logic_op_flags(result as u16, Size::Byte, out_bit);
|
||||||
|
self.set_target_value(target, result)?;
|
||||||
|
},
|
||||||
|
Instruction::SRA(target, opt_src) => {
|
||||||
|
let value = self.get_opt_src_target_value(opt_src, target)?;
|
||||||
|
let out_bit = (value & 0x01) != 0;
|
||||||
|
let msb_mask = if get_msb(value as u16, Size::Byte) { 0x80 } else { 0 };
|
||||||
|
let result = (value >> 1) | msb_mask;
|
||||||
|
self.set_logic_op_flags(result as u16, Size::Byte, out_bit);
|
||||||
|
self.set_target_value(target, result)?;
|
||||||
|
},
|
||||||
|
Instruction::SRL(target, opt_src) => {
|
||||||
|
let value = self.get_opt_src_target_value(opt_src, target)?;
|
||||||
|
let out_bit = (value & 0x01) != 0;
|
||||||
|
let result = value >> 1;
|
||||||
|
self.set_logic_op_flags(result as u16, Size::Byte, out_bit);
|
||||||
|
self.set_target_value(target, result)?;
|
||||||
|
},
|
||||||
Instruction::SUB(target) => {
|
Instruction::SUB(target) => {
|
||||||
let src = self.get_target_value(target)?;
|
let src = self.get_target_value(target)?;
|
||||||
let acc = self.get_register_value(Register::A);
|
let acc = self.get_register_value(Register::A);
|
||||||
@ -480,14 +477,14 @@ impl Z80 {
|
|||||||
self.set_logic_op_flags(result as u16, Size::Byte, false);
|
self.set_logic_op_flags(result as u16, Size::Byte, false);
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
panic!("unimplemented");
|
return Err(Error::new(&format!("{}: unimplemented instruction: {:?}", DEV_NAME, self.decoder.instruction)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rotate_left(&mut self, mut value: u8, rtype: RotateType) -> u8 {
|
fn rotate_left(&mut self, mut value: u8, rtype: RotateType) -> (u8, bool) {
|
||||||
let out_bit = get_msb(value as u16, Size::Byte);
|
let out_bit = get_msb(value as u16, Size::Byte);
|
||||||
|
|
||||||
let in_bit = match rtype {
|
let in_bit = match rtype {
|
||||||
@ -497,11 +494,10 @@ impl Z80 {
|
|||||||
|
|
||||||
value <<= 1;
|
value <<= 1;
|
||||||
value |= in_bit as u8;
|
value |= in_bit as u8;
|
||||||
self.set_flag(Flags::Carry, out_bit);
|
(value, out_bit)
|
||||||
value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rotate_right(&mut self, mut value: u8, rtype: RotateType) -> u8 {
|
fn rotate_right(&mut self, mut value: u8, rtype: RotateType) -> (u8, bool) {
|
||||||
let out_bit = (value & 0x01) != 0;
|
let out_bit = (value & 0x01) != 0;
|
||||||
|
|
||||||
let in_bit = match rtype {
|
let in_bit = match rtype {
|
||||||
@ -511,8 +507,7 @@ impl Z80 {
|
|||||||
|
|
||||||
value >>= 1;
|
value >>= 1;
|
||||||
value |= if in_bit { 0x80 } else { 0 };
|
value |= if in_bit { 0x80 } else { 0 };
|
||||||
self.set_flag(Flags::Carry, out_bit);
|
(value, out_bit)
|
||||||
value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_word(&mut self, value: u16) -> Result<(), Error> {
|
fn push_word(&mut self, value: u16) -> Result<(), Error> {
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
pub mod state;
|
pub mod state;
|
||||||
pub mod decode;
|
pub mod decode;
|
||||||
pub mod execute;
|
pub mod execute;
|
||||||
|
pub mod debugger;
|
||||||
|
|
||||||
pub use self::state::{Z80, Z80Type};
|
pub use self::state::{Z80, Z80Type};
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ use crate::devices::Address;
|
|||||||
use crate::memory::BusPort;
|
use crate::memory::BusPort;
|
||||||
|
|
||||||
use super::decode::Z80Decoder;
|
use super::decode::Z80Decoder;
|
||||||
//use super::debugger::M68kDebugger;
|
use super::debugger::Z80Debugger;
|
||||||
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -89,7 +89,7 @@ pub struct Z80 {
|
|||||||
pub frequency: u32,
|
pub frequency: u32,
|
||||||
pub state: Z80State,
|
pub state: Z80State,
|
||||||
pub decoder: Z80Decoder,
|
pub decoder: Z80Decoder,
|
||||||
//pub debugger: M68kDebugger,
|
pub debugger: Z80Debugger,
|
||||||
pub port: BusPort,
|
pub port: BusPort,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ impl Z80 {
|
|||||||
frequency,
|
frequency,
|
||||||
state: Z80State::new(),
|
state: Z80State::new(),
|
||||||
decoder: Z80Decoder::new(),
|
decoder: Z80Decoder::new(),
|
||||||
//debugger: M68kDebugger::new(),
|
debugger: Z80Debugger::new(),
|
||||||
port: port,
|
port: port,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,8 +108,8 @@ impl Z80 {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
self.state = Z80State::new();
|
self.state = Z80State::new();
|
||||||
//self.decoder = M68kDecoder::new(self.cputype, 0);
|
self.decoder = Z80Decoder::new();
|
||||||
//self.debugger = M68kDebugger::new();
|
self.debugger = Z80Debugger::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump_state(&mut self, system: &System) {
|
pub fn dump_state(&mut self, system: &System) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user