Added more Z80 instructions

This commit is contained in:
transistor 2021-11-04 21:30:33 -07:00
parent 7d2a4e4b44
commit 1a28208784
3 changed files with 248 additions and 77 deletions

View File

@ -67,6 +67,7 @@ pub enum Instruction {
ADDhl(RegisterPair),
AND(Target),
CP(Target),
CPL,
NEG,
OR(Target),
SBCa(Target),
@ -125,7 +126,6 @@ pub enum Instruction {
RST(u8),
CCF,
CPL,
DAA,
RLA,
RLCA,
@ -479,12 +479,17 @@ impl Z80Decoder {
Ok(word)
}
pub fn dump_decoded(&mut self, memory: &mut dyn Addressable) {
let ins_data: Result<String, Error> =
pub fn format_instruction_bytes(&mut self, memory: &mut dyn Addressable) -> String {
let ins_data: String =
(0..(self.end - self.start)).map(|offset|
Ok(format!("{:02x} ", memory.read_u8((self.start + offset) as Address).unwrap()))
format!("{:02x} ", memory.read_u8((self.start + offset) as Address).unwrap())
).collect();
println!("{:#06x}: {}\n\t{:?}\n", self.start, ins_data.unwrap(), self.instruction);
ins_data
}
pub fn dump_decoded(&mut self, memory: &mut dyn Addressable) {
let ins_data = self.format_instruction_bytes(memory);
println!("{:#06x}: {}\n\t{:?}\n", self.start, ins_data, self.instruction);
}
}

View File

@ -3,9 +3,10 @@ use crate::system::System;
use crate::error::{ErrorType, Error};
use crate::devices::{ClockElapsed, Address, Steppable, Addressable, Interruptable, Debuggable, Transmutable, read_beu16, write_beu16};
use super::decode::{Condition, Instruction, LoadTarget, Target, RegisterPair};
use super::decode::{Condition, Instruction, LoadTarget, Target, RegisterPair, Size};
use super::state::{Z80, Status, Flags, Register};
impl Steppable for Z80 {
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
self.step_internal(system)?;
@ -19,6 +20,35 @@ impl Steppable 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 {
fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
Some(self)
@ -28,9 +58,9 @@ impl Transmutable for Z80 {
Some(self)
}
//fn as_debuggable(&mut self) -> Option<&mut dyn Debuggable> {
// Some(self)
//}
fn as_debuggable(&mut self) -> Option<&mut dyn Debuggable> {
Some(self)
}
}
@ -83,7 +113,7 @@ impl Z80 {
//self.timer.decode.end();
//if self.debugger.use_tracing {
self.decoder.dump_decoded(&mut self.port);
self.dump_state(system);
//}
self.state.pc = self.decoder.end;
@ -96,14 +126,39 @@ impl Z80 {
//},
//Instruction::ADChl(regpair) => {
//},
//Instruction::ADDa(target) => {
//},
//Instruction::ADDhl(regpair) => {
//},
//Instruction::AND(target) => {
//},
//Instruction::CP(target) => {
//},
Instruction::ADDa(target) => {
let src = self.get_target_value(target)?;
let acc = self.get_register_value(Register::A);
let (result, carry) = acc.overflowing_add(src);
self.set_add_flags(result as u16, Size::Byte, carry);
self.set_register_value(Register::A, result);
},
Instruction::ADDhl(regpair) => {
let src = self.get_register_pair_value(regpair);
let hl = self.get_register_pair_value(RegisterPair::HL);
let (result, carry) = hl.overflowing_add(src);
self.set_add_flags(result as u16, Size::Word, carry);
self.set_register_pair_value(RegisterPair::HL, result);
},
Instruction::AND(target) => {
let acc = self.get_register_value(Register::A);
let value = self.get_target_value(target)?;
let result = acc & value;
self.set_register_value(Register::A, result);
self.set_logic_op_flags(result as u16, Size::Byte, true);
},
Instruction::CP(target) => {
let src = self.get_target_value(target)?;
let acc = self.get_register_value(Register::A);
let (result, carry) = acc.overflowing_sub(src);
self.set_sub_flags(result as u16, Size::Byte, carry);
},
Instruction::CPL => {
let value = self.get_register_value(Register::A);
self.set_register_value(Register::A, !value);
self.set_flag(Flags::HalfCarry, true);
self.set_flag(Flags::AddSubtract, true);
},
//Instruction::NEG => {
//},
Instruction::OR(target) => {
@ -111,16 +166,26 @@ impl Z80 {
let value = self.get_target_value(target)?;
let result = acc | value;
self.set_register_value(Register::A, result);
self.set_op_flags(result, false);
self.set_logic_op_flags(result as u16, Size::Byte, false);
},
//Instruction::SBCa(target) => {
//},
//Instruction::SBChl(regpair) => {
//},
//Instruction::SUB(target) => {
//},
//Instruction::XOR(target) => {
//},
Instruction::SUB(target) => {
let src = self.get_target_value(target)?;
let acc = self.get_register_value(Register::A);
let (result, carry) = acc.overflowing_sub(src);
self.set_sub_flags(result as u16, Size::Byte, carry);
self.set_register_value(Register::A, result);
},
Instruction::XOR(target) => {
let acc = self.get_register_value(Register::A);
let value = self.get_target_value(target)?;
let result = acc ^ value;
self.set_register_value(Register::A, result);
self.set_logic_op_flags(result as u16, Size::Byte, false);
},
//Instruction::BIT(u8, target) => {
//},
@ -146,25 +211,55 @@ impl Z80 {
//},
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);
let value = self.get_target_value(target)?;
let (result, carry) = value.overflowing_sub(1);
self.set_sub_flags(result as u16, Size::Byte, carry);
self.set_target_value(target, result)?;
},
Instruction::DEC16(regpair) => {
let value = self.get_register_pair_value(regpair);
let (result, carry) = value.overflowing_sub(1);
self.set_sub_flags(result, Size::Word, carry);
self.set_register_pair_value(regpair, result);
},
Instruction::INC8(target) => {
let value = self.get_target_value(target)?;
let (result, carry) = value.overflowing_add(1);
self.set_add_flags(result as u16, Size::Byte, carry);
self.set_target_value(target, result)?;
},
Instruction::INC16(regpair) => {
let value = self.get_register_pair_value(regpair);
let (result, carry) = value.overflowing_add(1);
self.set_add_flags(result, Size::Word, carry);
self.set_register_pair_value(regpair, result);
},
//Instruction::DEC16(regpair) => {
//},
//Instruction::INC8(target) => {
//},
//Instruction::INC16(regpair) => {
//},
//Instruction::EXX => {
//},
//Instruction::EXafaf => {
//},
//Instruction::EXhlsp => {
//},
//Instruction::EXhlde => {
//},
Instruction::EXX => {
for i in 0..6 {
let (normal, shadow) = (self.state.reg[i], self.state.shadow_reg[i]);
self.state.reg[i] = shadow;
self.state.shadow_reg[i] = normal;
}
},
Instruction::EXafaf => {
for i in 6..8 {
let (normal, shadow) = (self.state.reg[i], self.state.shadow_reg[i]);
self.state.reg[i] = shadow;
self.state.shadow_reg[i] = normal;
}
},
Instruction::EXhlsp => {
let (sp_addr, hl) = (self.get_register_pair_value(RegisterPair::SP), self.get_register_pair_value(RegisterPair::HL));
let sp = self.port.read_leu16(sp_addr as Address)?;
self.set_register_pair_value(RegisterPair::HL, sp);
self.port.write_leu16(sp_addr as Address, hl)?;
},
Instruction::EXhlde => {
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);
},
Instruction::LD(dest, src) => {
let src_value = self.get_load_target_value(src)?;
self.set_load_target_value(dest, src_value)?;
@ -199,13 +294,23 @@ impl Z80 {
self.state.pc = addr;
}
},
//Instruction::DJNZ(i8) => {
//},
Instruction::DJNZ(offset) => {
let value = self.get_register_value(Register::B);
let result = value.wrapping_sub(1);
self.set_register_value(Register::B, result);
if result != 0 {
self.state.pc = ((self.state.pc as i16) + (offset as i16)) as u16;
}
},
Instruction::JP(addr) => {
self.state.pc = addr;
},
//Instruction::JPIndirectHL => {
//},
Instruction::JPIndirectHL => {
let hl = self.get_register_pair_value(RegisterPair::HL);
let addr = self.port.read_leu16(hl as Address)?;
self.state.pc = addr;
},
Instruction::JPcc(cond, addr) => {
if self.get_current_condition(cond) {
self.state.pc = addr;
@ -226,25 +331,32 @@ impl Z80 {
//},
//Instruction::RETN => {
//},
//Instruction::RETcc(cond) => {
//},
Instruction::RETcc(cond) => {
if self.get_current_condition(cond) {
self.state.pc = self.pop_word()?;
}
},
//Instruction::DI => {
//},
//Instruction::EI => {
//},
Instruction::DI => {
self.state.interrupts_enabled = false;
},
Instruction::EI => {
self.state.interrupts_enabled = true;
},
//Instruction::IM(u8) => {
//},
Instruction::NOP => { },
//Instruction::HALT => {
//},
//Instruction::RST(u8) => {
//},
Instruction::HALT => {
self.state.status = Status::Halted;
},
Instruction::RST(addr) => {
self.push_word(self.decoder.end)?;
self.state.pc = addr as u16;
},
//Instruction::CCF => {
//},
//Instruction::CPL => {
//},
Instruction::CCF => {
self.set_flag(Flags::Carry, false);
},
//Instruction::DAA => {
//},
//Instruction::RLA => {
@ -259,8 +371,9 @@ impl Z80 {
//},
//Instruction::RLD => {
//},
//Instruction::SCF => {
//},
Instruction::SCF => {
self.set_flag(Flags::Carry, true);
},
//Instruction::CPD => {
//},
@ -460,21 +573,59 @@ impl Z80 {
}
}
fn set_op_flags(&mut self, value: u8, carry: bool) {
fn set_add_flags(&mut self, value: u16, size: Size, carry: bool) {
let mut flags = 0;
if get_msb(value, size) {
flags |= Flags::Sign as u8;
}
if value == 0 {
flags |= Flags::Zero as u8;
}
if (value as i8) < 0 {
flags |= Flags::Sign as u8;
if (value & 0x10) != 0 {
flags |= Flags::HalfCarry as u8;
}
// TODO need overflow
if carry {
flags |= Flags::Carry as u8;
}
self.state.reg[Register::F as usize] = flags;
}
fn set_sub_flags(&mut self, value: u16, size: Size, carry: bool) {
let mut flags = Flags::AddSubtract as u8;
if get_msb(value, size) {
flags |= Flags::Sign as u8;
}
if value == 0 {
flags |= Flags::Zero as u8;
}
// TODO need overflow and half carry
if carry {
flags |= Flags::Carry as u8;
}
self.state.reg[Register::F as usize] = flags;
}
fn set_logic_op_flags(&mut self, value: u16, size: Size, half_carry: bool) {
let mut flags = 0;
if get_msb(value, size) {
flags |= Flags::Sign as u8;
}
if value == 0 {
flags |= Flags::Zero as u8;
}
if half_carry {
flags |= Flags::HalfCarry as u8;
}
if (value.count_ones() & 0x01) == 0 {
flags |= Flags::Parity as u8;
}
self.state.reg[Register::F as usize] = flags;
}
#[inline(always)]
fn get_flags(&self) -> u8 {
self.state.reg[Register::F as usize]
@ -485,5 +636,19 @@ impl Z80 {
self.get_flags() & (flag as u8) != 0
}
#[inline(always)]
fn set_flag(&mut self, flag: Flags, value: bool) {
self.state.reg[Register::F as usize] = self.state.reg[Register::F as usize] & !(flag as u8);
if value {
self.state.reg[Register::F as usize] |= flag as u8;
}
}
}
fn get_msb(value: u16, size: Size) -> bool {
match size {
Size::Byte => (value & 0x0080) != 0,
Size::Word => (value & 0x8000) != 0,
}
}

View File

@ -50,6 +50,7 @@ pub enum Register {
#[derive(Clone, Debug, PartialEq)]
pub struct Z80State {
pub status: Status,
pub interrupts_enabled: bool,
pub pc: u16,
pub sp: u16,
@ -57,7 +58,7 @@ pub struct Z80State {
pub iy: u16,
pub reg: [u8; 8],
pub alt_reg: [u8; 8],
pub shadow_reg: [u8; 8],
pub i: u8,
pub r: u8,
@ -67,6 +68,7 @@ impl Z80State {
pub fn new() -> Self {
Self {
status: Status::Init,
interrupts_enabled: false,
pc: 0,
sp: 0,
@ -74,7 +76,7 @@ impl Z80State {
iy: 0,
reg: [0; 8],
alt_reg: [0; 8],
shadow_reg: [0; 8],
i: 0,
r: 0,
@ -110,23 +112,22 @@ impl Z80 {
//self.debugger = M68kDebugger::new();
}
/*
pub fn dump_state(&mut self, system: &System) {
println!("Status: {:?}", self.state.status);
println!("PC: {:#010x}", self.state.pc);
println!("SR: {:#06x}", self.state.sr);
for i in 0..7 {
println!("D{}: {:#010x} A{}: {:#010x}", i, self.state.d_reg[i as usize], i, self.state.a_reg[i as usize]);
}
println!("D7: {:#010x}", self.state.d_reg[7]);
println!("MSP: {:#010x}", self.state.msp);
println!("USP: {:#010x}", self.state.usp);
println!("PC: {:#06x}", self.state.pc);
println!("SP: {:#06x}", self.state.sp);
println!("IX: {:#06x}", self.state.ix);
println!("IY: {:#06x}", self.state.iy);
println!("Current Instruction: {:#010x} {:?}", self.decoder.start, self.decoder.instruction);
println!("A: {:#04x} F: {:#04x}", self.state.reg[Register::A as usize], self.state.reg[Register::F as usize]);
println!("B: {:#04x} C: {:#04x}", self.state.reg[Register::B as usize], self.state.reg[Register::C as usize]);
println!("D: {:#04x} E: {:#04x}", self.state.reg[Register::D as usize], self.state.reg[Register::B as usize]);
println!("H: {:#04x} L: {:#04x}", self.state.reg[Register::H as usize], self.state.reg[Register::L as usize]);
println!("Current Instruction: {} {:?}", self.decoder.format_instruction_bytes(&mut self.port), self.decoder.instruction);
println!("");
self.port.dump_memory(self.state.msp as Address, 0x40);
self.port.dump_memory(self.state.sp as Address, 0x40);
println!("");
}
*/
}