mirror of
https://github.com/transistorfet/moa.git
synced 2024-12-23 18:30:20 +00:00
Added more Z80 instructions
This commit is contained in:
parent
7d2a4e4b44
commit
1a28208784
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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!("");
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user