mirror of
https://github.com/transistorfet/moa.git
synced 2024-06-24 05:29:28 +00:00
Added start of Z80 decoder
This commit is contained in:
parent
58fc9ac827
commit
e0ef1d8fd9
|
@ -1,3 +1,4 @@
|
|||
|
||||
pub mod m68k;
|
||||
pub mod z80;
|
||||
|
||||
|
|
522
src/cpus/z80/decode.rs
Normal file
522
src/cpus/z80/decode.rs
Normal file
|
@ -0,0 +1,522 @@
|
|||
|
||||
use crate::error::Error;
|
||||
use crate::devices::{Address, Addressable};
|
||||
|
||||
use super::state::{Z80, Z80Type};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Condition {
|
||||
NotZero,
|
||||
Zero,
|
||||
NotCarry,
|
||||
Carry,
|
||||
ParityOdd,
|
||||
ParityEven,
|
||||
Positive,
|
||||
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,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Target {
|
||||
DirectRegByte(Register),
|
||||
IndirectRegByte(RegisterPair),
|
||||
ImmediateByte(u8),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum LoadTarget {
|
||||
DirectRegByte(Register),
|
||||
DirectRegWord(RegisterPair),
|
||||
IndirectRegByte(RegisterPair),
|
||||
IndirectRegWord(RegisterPair),
|
||||
DirectAltRegByte(Register),
|
||||
IndirectByte(u16),
|
||||
IndirectWord(u16),
|
||||
ImmediateByte(u8),
|
||||
ImmediateWord(u16),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Instruction {
|
||||
ADDa(Target),
|
||||
ADCa(Target),
|
||||
ADDhl(RegisterPair),
|
||||
AND(Target),
|
||||
CP(Target),
|
||||
CALL(u16),
|
||||
CALLcc(Condition, u16),
|
||||
DEC8(Target),
|
||||
DEC16(RegisterPair),
|
||||
DJNZ(i8),
|
||||
DI,
|
||||
EI,
|
||||
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),
|
||||
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),
|
||||
|
||||
RLCA,
|
||||
RRCA,
|
||||
RLA,
|
||||
RRA,
|
||||
DAA,
|
||||
CPL,
|
||||
SCF,
|
||||
CCF,
|
||||
}
|
||||
|
||||
pub struct Z80Decoder {
|
||||
pub start: u16,
|
||||
pub end: u16,
|
||||
pub instruction: Instruction,
|
||||
}
|
||||
|
||||
impl Z80Decoder {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
start: 0,
|
||||
end: 0,
|
||||
instruction: Instruction::NOP,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Z80Decoder {
|
||||
pub fn decode_at(&mut self, memory: &mut dyn Addressable, start: u16) -> Result<(), Error> {
|
||||
self.start = start;
|
||||
self.end = start;
|
||||
self.instruction = self.decode_one(memory)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn decode_one(&mut self, memory: &mut dyn Addressable) -> Result<Instruction, Error> {
|
||||
let ins = self.read_instruction_byte(memory)?;
|
||||
|
||||
match get_ins_x(ins) {
|
||||
0 => {
|
||||
match get_ins_z(ins) {
|
||||
0 => {
|
||||
match get_ins_y(ins) {
|
||||
0 => Ok(Instruction::NOP),
|
||||
1 => Ok(Instruction::EXafaf),
|
||||
2 => {
|
||||
let offset = self.read_instruction_byte(memory)? as i8;
|
||||
Ok(Instruction::DJNZ(offset))
|
||||
},
|
||||
3 => {
|
||||
let offset = self.read_instruction_byte(memory)? as i8;
|
||||
Ok(Instruction::JR(offset))
|
||||
},
|
||||
y => {
|
||||
let offset = self.read_instruction_byte(memory)? as i8;
|
||||
Ok(Instruction::JRcc(get_condition(y - 4), offset))
|
||||
},
|
||||
}
|
||||
},
|
||||
1 => {
|
||||
if get_ins_q(ins) == 0 {
|
||||
let data = self.read_instruction_word(memory)?;
|
||||
Ok(Instruction::LD(LoadTarget::DirectRegWord(get_register_pair(get_ins_p(ins))), LoadTarget::ImmediateWord(data)))
|
||||
} else {
|
||||
Ok(Instruction::ADDhl(get_register_pair(get_ins_p(ins))))
|
||||
}
|
||||
},
|
||||
2 => {
|
||||
if (ins & 0x20) == 0 {
|
||||
let target = match (ins & 0x10) != 0 {
|
||||
false => LoadTarget::IndirectRegByte(RegisterPair::BC),
|
||||
true => LoadTarget::IndirectRegByte(RegisterPair::DE),
|
||||
};
|
||||
|
||||
match (ins & 0x08) != 0 {
|
||||
false => Ok(Instruction::LD(target, LoadTarget::DirectRegByte(Register::A))),
|
||||
true => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::A), target)),
|
||||
}
|
||||
} else {
|
||||
let addr = self.read_instruction_word(memory)?;
|
||||
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))),
|
||||
3 => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::A), LoadTarget::IndirectByte(addr))),
|
||||
_ => panic!("InternalError: impossible value"),
|
||||
}
|
||||
}
|
||||
},
|
||||
3 => {
|
||||
if get_ins_q(ins) == 0 {
|
||||
Ok(Instruction::INC16(get_register_pair(get_ins_p(ins))))
|
||||
} else {
|
||||
Ok(Instruction::DEC16(get_register_pair(get_ins_p(ins))))
|
||||
}
|
||||
},
|
||||
4 => {
|
||||
Ok(Instruction::INC8(get_register(get_ins_y(ins))))
|
||||
},
|
||||
5 => {
|
||||
Ok(Instruction::DEC8(get_register(get_ins_y(ins))))
|
||||
},
|
||||
6 => {
|
||||
let data = self.read_instruction_byte(memory)?;
|
||||
Ok(Instruction::LD(to_load_target(get_register(get_ins_y(ins))), LoadTarget::ImmediateByte(data)))
|
||||
},
|
||||
7 => {
|
||||
match get_ins_y(ins) {
|
||||
0 => Ok(Instruction::RLCA),
|
||||
1 => Ok(Instruction::RRCA),
|
||||
2 => Ok(Instruction::RLA),
|
||||
3 => Ok(Instruction::RRA),
|
||||
4 => Ok(Instruction::DAA),
|
||||
5 => Ok(Instruction::CPL),
|
||||
6 => Ok(Instruction::SCF),
|
||||
7 => Ok(Instruction::CCF),
|
||||
_ => panic!("InternalError: impossible value"),
|
||||
}
|
||||
},
|
||||
_ => panic!("InternalError: impossible value"),
|
||||
}
|
||||
},
|
||||
1 => {
|
||||
if ins == 0x76 {
|
||||
Ok(Instruction::HALT)
|
||||
} else {
|
||||
Ok(Instruction::LD(to_load_target(get_register(get_ins_y(ins))), to_load_target(get_register(get_ins_z(ins)))))
|
||||
}
|
||||
},
|
||||
2 => {
|
||||
Ok(get_alu_instruction(get_ins_y(ins), get_register(get_ins_z(ins))))
|
||||
},
|
||||
3 => {
|
||||
match get_ins_z(ins) {
|
||||
0 => {
|
||||
Ok(Instruction::RETcc(get_condition(get_ins_y(ins))))
|
||||
},
|
||||
1 => {
|
||||
if get_ins_q(ins) == 0 {
|
||||
Ok(Instruction::POP(get_register_pair_alt(get_ins_p(ins))))
|
||||
} else {
|
||||
match get_ins_p(ins) {
|
||||
0 => Ok(Instruction::RET),
|
||||
1 => Ok(Instruction::EXX),
|
||||
2 => Ok(Instruction::JPIndirectHL),
|
||||
3 => Ok(Instruction::LD(LoadTarget::DirectRegWord(RegisterPair::SP), LoadTarget::DirectRegWord(RegisterPair::HL))),
|
||||
_ => panic!("InternalError: impossible value"),
|
||||
}
|
||||
}
|
||||
},
|
||||
2 => {
|
||||
let addr = self.read_instruction_word(memory)?;
|
||||
Ok(Instruction::JPcc(get_condition(get_ins_y(ins)), addr))
|
||||
},
|
||||
3 => {
|
||||
match get_ins_y(ins) {
|
||||
0 => {
|
||||
let addr = self.read_instruction_word(memory)?;
|
||||
Ok(Instruction::JP(addr))
|
||||
},
|
||||
1 => {
|
||||
self.decode_prefix_cb(memory)
|
||||
},
|
||||
2 => {
|
||||
let port = self.read_instruction_byte(memory)?;
|
||||
Ok(Instruction::OUTx(port))
|
||||
},
|
||||
3 => {
|
||||
let port = self.read_instruction_byte(memory)?;
|
||||
Ok(Instruction::INx(port))
|
||||
},
|
||||
4 => Ok(Instruction::EXhlsp),
|
||||
5 => Ok(Instruction::EXhlde),
|
||||
6 => Ok(Instruction::DI),
|
||||
7 => Ok(Instruction::EI),
|
||||
_ => panic!("InternalError: impossible value"),
|
||||
}
|
||||
},
|
||||
4 => {
|
||||
let addr = self.read_instruction_word(memory)?;
|
||||
Ok(Instruction::CALLcc(get_condition(get_ins_y(ins)), addr))
|
||||
}
|
||||
5 => {
|
||||
if get_ins_q(ins) == 0 {
|
||||
Ok(Instruction::PUSH(get_register_pair_alt(get_ins_p(ins))))
|
||||
} else {
|
||||
match get_ins_p(ins) {
|
||||
0 => {
|
||||
let addr = self.read_instruction_word(memory)?;
|
||||
Ok(Instruction::CALL(addr))
|
||||
},
|
||||
1 => self.decode_prefix_dd(memory),
|
||||
2 => self.decode_prefix_ed(memory),
|
||||
3 => self.decode_prefix_fd(memory),
|
||||
_ => panic!("Undecoded Instruction"),
|
||||
}
|
||||
}
|
||||
}
|
||||
6 => {
|
||||
let data = self.read_instruction_byte(memory)?;
|
||||
Ok(get_alu_instruction(get_ins_y(ins), Target::ImmediateByte(data)))
|
||||
},
|
||||
7 => {
|
||||
Ok(Instruction::RST(get_ins_y(ins) * 8))
|
||||
},
|
||||
_ => panic!("InternalError: impossible value"),
|
||||
}
|
||||
},
|
||||
_ => panic!("Undecoded Instruction"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_prefix_cb(&mut self, memory: &mut dyn Addressable) -> Result<Instruction, Error> {
|
||||
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)))),
|
||||
1 => Ok(Instruction::BIT(get_ins_y(ins), get_register(get_ins_z(ins)))),
|
||||
2 => Ok(Instruction::RES(get_ins_y(ins), get_register(get_ins_z(ins)))),
|
||||
3 => Ok(Instruction::SET(get_ins_y(ins), get_register(get_ins_z(ins)))),
|
||||
_ => panic!("InternalError: impossible value"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_prefix_dd(&mut self, memory: &mut dyn Addressable) -> Result<Instruction, Error> {
|
||||
panic!("DD instructions unimplemented")
|
||||
}
|
||||
|
||||
pub fn decode_prefix_ed(&mut self, memory: &mut dyn Addressable) -> Result<Instruction, Error> {
|
||||
let ins = self.read_instruction_byte(memory)?;
|
||||
|
||||
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!("");
|
||||
} else {
|
||||
//Ok(Instruction::INic(get_register(y))),
|
||||
}
|
||||
},
|
||||
1 => {
|
||||
},
|
||||
2 => {
|
||||
},
|
||||
3 => {
|
||||
},
|
||||
4 => {
|
||||
},
|
||||
5 => {
|
||||
},
|
||||
6 => {
|
||||
},
|
||||
7 => {
|
||||
},
|
||||
_ => panic!("InternalError: impossible value"),
|
||||
}
|
||||
*/
|
||||
panic!("random instructions are unimplemented");
|
||||
},
|
||||
2 => {
|
||||
match ins & 0xF0 {
|
||||
// TODO implement block
|
||||
//0xA0 => {
|
||||
|
||||
//},
|
||||
//0xB0 => {
|
||||
|
||||
//},
|
||||
_ => Ok(Instruction::NOP),
|
||||
}
|
||||
},
|
||||
3 => Ok(Instruction::NOP),
|
||||
_ => panic!("InternalError: impossible value"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_prefix_fd(&mut self, memory: &mut dyn Addressable) -> Result<Instruction, Error> {
|
||||
panic!("FD instructions unimplemented")
|
||||
}
|
||||
|
||||
|
||||
fn read_instruction_byte(&mut self, device: &mut dyn Addressable) -> Result<u8, Error> {
|
||||
let byte = device.read_u8(self.end as Address)?;
|
||||
self.end += 1;
|
||||
Ok(byte)
|
||||
}
|
||||
|
||||
fn read_instruction_word(&mut self, device: &mut dyn Addressable) -> Result<u16, Error> {
|
||||
let word = device.read_beu16(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|
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_alu_instruction(alu: u8, target: Target) -> Instruction {
|
||||
match alu {
|
||||
0 => Instruction::ADDa(target),
|
||||
1 => Instruction::ADCa(target),
|
||||
2 => Instruction::SUB(target),
|
||||
3 => Instruction::SBCa(target),
|
||||
4 => Instruction::AND(target),
|
||||
5 => Instruction::XOR(target),
|
||||
6 => Instruction::OR(target),
|
||||
7 => Instruction::CP(target),
|
||||
_ => panic!("InternalError: impossible value"),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_rot_instruction(rot: u8, target: Target) -> Instruction {
|
||||
match rot {
|
||||
0 => Instruction::RLC(target),
|
||||
1 => Instruction::RRC(target),
|
||||
2 => Instruction::RL(target),
|
||||
3 => Instruction::RR(target),
|
||||
4 => Instruction::SLA(target),
|
||||
5 => Instruction::SRA(target),
|
||||
6 => Instruction::SLL(target),
|
||||
7 => Instruction::SRL(target),
|
||||
_ => panic!("InternalError: impossible value"),
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
_ => 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),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_register_pair(reg: u8) -> RegisterPair {
|
||||
match reg {
|
||||
0 => RegisterPair::BC,
|
||||
1 => RegisterPair::DE,
|
||||
2 => RegisterPair::HL,
|
||||
3 => RegisterPair::SP,
|
||||
_ => panic!("InternalError: impossible value"),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_register_pair_alt(reg: u8) -> RegisterPair {
|
||||
match reg {
|
||||
0 => RegisterPair::BC,
|
||||
1 => RegisterPair::DE,
|
||||
2 => RegisterPair::HL,
|
||||
3 => RegisterPair::AF,
|
||||
_ => panic!("InternalError: impossible value"),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_condition(cond: u8) -> Condition {
|
||||
match cond {
|
||||
0 => Condition::NotZero,
|
||||
1 => Condition::Zero,
|
||||
2 => Condition::NotCarry,
|
||||
3 => Condition::Carry,
|
||||
4 => Condition::ParityOdd,
|
||||
5 => Condition::ParityEven,
|
||||
6 => Condition::Positive,
|
||||
7 => Condition::Negative,
|
||||
_ => panic!("InternalError: impossible value"),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_ins_x(ins: u8) -> u8 {
|
||||
(ins >> 6) & 0x03
|
||||
}
|
||||
|
||||
fn get_ins_y(ins: u8) -> u8 {
|
||||
(ins >> 3) & 0x07
|
||||
}
|
||||
|
||||
fn get_ins_z(ins: u8) -> u8 {
|
||||
ins & 0x07
|
||||
}
|
||||
|
||||
fn get_ins_p(ins: u8) -> u8 {
|
||||
(ins >> 4) & 0x03
|
||||
}
|
||||
|
||||
fn get_ins_q(ins: u8) -> u8 {
|
||||
(ins >> 3) & 0x01
|
||||
}
|
||||
|
97
src/cpus/z80/execute.rs
Normal file
97
src/cpus/z80/execute.rs
Normal file
|
@ -0,0 +1,97 @@
|
|||
|
||||
use crate::system::System;
|
||||
use crate::error::{ErrorType, Error};
|
||||
use crate::devices::{ClockElapsed, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable};
|
||||
|
||||
use super::decode::Z80Decoder;
|
||||
use super::state::{Z80, Z80State, Status};
|
||||
|
||||
impl Steppable for Z80 {
|
||||
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
|
||||
self.step_internal(system)?;
|
||||
Ok((1_000_000_000 / self.frequency as u64) * 4)
|
||||
}
|
||||
|
||||
fn on_error(&mut self, system: &System) {
|
||||
//self.dump_state(system);
|
||||
}
|
||||
}
|
||||
|
||||
impl Interruptable for Z80 { }
|
||||
|
||||
impl Transmutable for Z80 {
|
||||
fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
|
||||
Some(self)
|
||||
}
|
||||
|
||||
fn as_interruptable(&mut self) -> Option<&mut dyn Interruptable> {
|
||||
Some(self)
|
||||
}
|
||||
|
||||
//fn as_debuggable(&mut self) -> Option<&mut dyn Debuggable> {
|
||||
// Some(self)
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl Z80 {
|
||||
pub fn step_internal(&mut self, system: &System) -> Result<(), Error> {
|
||||
match self.state.status {
|
||||
Status::Init => self.init(system),
|
||||
Status::Halted => Err(Error::new("CPU stopped")),
|
||||
Status::Running => {
|
||||
match self.cycle_one(system) {
|
||||
Ok(()) => Ok(()),
|
||||
//Err(Error { err: ErrorType::Processor, native, .. }) => {
|
||||
Err(Error { err: ErrorType::Processor, native, .. }) => {
|
||||
//self.exception(system, native as u8, false)?;
|
||||
Ok(())
|
||||
},
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(&mut self, system: &System) -> Result<(), Error> {
|
||||
//self.state.msp = self.port.read_beu32(0)?;
|
||||
//self.state.pc = self.port.read_beu32(4)?;
|
||||
self.state.status = Status::Running;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cycle_one(&mut self, system: &System) -> Result<(), Error> {
|
||||
//self.timer.cycle.start();
|
||||
self.decode_next(system)?;
|
||||
//self.execute_current(system)?;
|
||||
//self.timer.cycle.end();
|
||||
|
||||
//if (self.timer.cycle.events % 500) == 0 {
|
||||
// println!("{}", self.timer);
|
||||
//}
|
||||
|
||||
//self.check_pending_interrupts(system)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn decode_next(&mut self, system: &System) -> Result<(), Error> {
|
||||
//self.check_breakpoints(system);
|
||||
|
||||
//self.timer.decode.start();
|
||||
self.decoder.decode_at(&mut self.port, self.state.pc)?;
|
||||
//self.timer.decode.end();
|
||||
|
||||
//if self.debugger.use_tracing {
|
||||
self.decoder.dump_decoded(&mut self.port);
|
||||
//}
|
||||
|
||||
self.state.pc = self.decoder.end;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn execute_current(&mut self, system: &System) -> Result<(), Error> {
|
||||
panic!("unimplemented");
|
||||
}
|
||||
}
|
||||
|
7
src/cpus/z80/mod.rs
Normal file
7
src/cpus/z80/mod.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
pub mod state;
|
||||
pub mod decode;
|
||||
pub mod execute;
|
||||
|
||||
pub use self::state::{Z80, Z80Type};
|
||||
|
161
src/cpus/z80/state.rs
Normal file
161
src/cpus/z80/state.rs
Normal file
|
@ -0,0 +1,161 @@
|
|||
|
||||
use crate::system::System;
|
||||
use crate::devices::Address;
|
||||
use crate::memory::BusPort;
|
||||
|
||||
use super::decode::Z80Decoder;
|
||||
//use super::debugger::M68kDebugger;
|
||||
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum Z80Type {
|
||||
Z80,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum Status {
|
||||
Init,
|
||||
Running,
|
||||
Halted,
|
||||
}
|
||||
|
||||
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum Flags {
|
||||
Carry = 0x0001,
|
||||
Overflow = 0x0002,
|
||||
Zero = 0x0004,
|
||||
Negative = 0x0008,
|
||||
Extend = 0x0010,
|
||||
}
|
||||
|
||||
/*
|
||||
#[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,
|
||||
}
|
||||
|
||||
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 {
|
||||
pub status: Status,
|
||||
|
||||
pub pc: u16,
|
||||
pub sp: u16,
|
||||
pub ix: u16,
|
||||
pub iy: u16,
|
||||
|
||||
pub reg: [u8; 8],
|
||||
pub alt_reg: [u8; 8],
|
||||
|
||||
pub i: u8,
|
||||
pub r: u8,
|
||||
}
|
||||
|
||||
impl Z80State {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
status: Status::Init,
|
||||
|
||||
pc: 0,
|
||||
sp: 0,
|
||||
ix: 0,
|
||||
iy: 0,
|
||||
|
||||
reg: [0; 8],
|
||||
alt_reg: [0; 8],
|
||||
|
||||
i: 0,
|
||||
r: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Z80 {
|
||||
pub cputype: Z80Type,
|
||||
pub frequency: u32,
|
||||
pub state: Z80State,
|
||||
pub decoder: Z80Decoder,
|
||||
//pub debugger: M68kDebugger,
|
||||
pub port: BusPort,
|
||||
}
|
||||
|
||||
impl Z80 {
|
||||
pub fn new(cputype: Z80Type, frequency: u32, port: BusPort) -> Self {
|
||||
Self {
|
||||
cputype,
|
||||
frequency,
|
||||
state: Z80State::new(),
|
||||
decoder: Z80Decoder::new(),
|
||||
//debugger: M68kDebugger::new(),
|
||||
port: port,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn reset(&mut self) {
|
||||
self.state = Z80State::new();
|
||||
//self.decoder = M68kDecoder::new(self.cputype, 0);
|
||||
//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!("Current Instruction: {:#010x} {:?}", self.decoder.start, self.decoder.instruction);
|
||||
println!("");
|
||||
self.port.dump_memory(self.state.msp as Address, 0x40);
|
||||
println!("");
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
11
todo.txt
11
todo.txt
|
@ -2,11 +2,6 @@
|
|||
* fix ym7101 to better handle V/H interrupts (right now it sets and then the next step will clear, but it'd be nice if it could 'edge trigger')
|
||||
|
||||
* could have a remapper device, which takes a big swath of addresses in and maps them to another set of addresses (for Mac VIA generic to bus-hookup-in-mac adapter)
|
||||
|
||||
* sort out how inputing keys will work
|
||||
* separate the debugger out of m68k, use on_debug or something to print out debug info
|
||||
* make devices nameable, using a hashmap to store them
|
||||
|
||||
* how can you do devices that change their address map during operation, like mac which puts rom at 0 and ram at 600000 temporarily
|
||||
* i need a better way of handling disperate reads/writes to I/O spaces, rather than having multiple devices or having a massive chunk of address space allocated, continuously
|
||||
* should you modify Addressable to also take the absolute address as input? I'm thinking of how the same device could be mapped to multiple addresses in memory instead
|
||||
|
@ -15,12 +10,6 @@
|
|||
So both could share the same Signal, one setting it and the other reading it, but how would you actually configure/build that?
|
||||
|
||||
|
||||
We Need:
|
||||
* devices that change address mapping during operation
|
||||
* device that can be mapped to multiple separated locations while sharing data
|
||||
* subdevices that can share data (eg. signal from one to another (mac128 via outputs), or being a subdevice with a special trait (joystick))
|
||||
|
||||
|
||||
|
||||
* implement a Z80
|
||||
* maybe see about a Mac 128k or something
|
||||
|
|
Loading…
Reference in New Issue
Block a user