mirror of
https://github.com/transistorfet/moa.git
synced 2024-06-09 01:29:32 +00:00
Started filling in Z80 execution
This commit is contained in:
parent
418bf2f141
commit
dc25a9f171
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue
Block a user