Refactored to separate out the BusPort, to eventually replace it

This commit is contained in:
transistor 2024-03-03 22:57:27 -08:00
parent 54ebcce94c
commit b4a35641e4
8 changed files with 426 additions and 278 deletions

View File

@ -3,7 +3,7 @@ use moa_core::{System, Error, Address, Addressable, Debuggable};
use super::state::M68k;
use super::decode::M68kDecoder;
use super::execute::M68kCycleGuard;
use super::execute::M68kCycleExecutor;
#[derive(Clone, Default)]
pub struct StackTracer {
@ -49,8 +49,9 @@ impl Debuggable for M68k {
}
fn print_disassembly(&mut self, addr: Address, count: usize) {
let mut decoder = M68kDecoder::new(self.cputype, true, 0);
decoder.dump_disassembly(&mut self.port, addr as u32, count as u32);
let mut decoder = M68kDecoder::new(self.info.chip, true, 0);
// TODO temporarily disabled
//decoder.dump_disassembly(&mut self.port, addr as u32, count as u32);
}
fn run_command(&mut self, system: &System, args: &[&str]) -> Result<bool, Error> {
@ -58,7 +59,7 @@ impl Debuggable for M68k {
"ds" | "stack" | "dumpstack" => {
println!("Stack:");
for addr in &self.debugger.stack_tracer.calls {
println!(" {:08x}", self.port.port.read_beu32(system.clock, *addr as Address)?);
println!(" {:08x}", self.port.read_beu32(system.clock, *addr as Address)?);
}
},
"so" | "stepout" => {
@ -70,7 +71,7 @@ impl Debuggable for M68k {
}
}
impl<'a> M68kCycleGuard<'a> {
impl<'a> M68kCycleExecutor<'a> {
pub fn check_breakpoints(&mut self) -> Result<(), Error> {
for breakpoint in &self.debugger.breakpoints {
if *breakpoint == self.state.pc {

View File

@ -1,5 +1,7 @@
use moa_core::{Address, Addressable};
use femtos::Instant;
use moa_core::{Address, Addressable, BusPort};
use crate::state::{M68kType, M68kError, Exceptions};
use crate::memory::M68kBusPort;
@ -47,7 +49,14 @@ pub struct M68kDecoder {
pub instruction: Instruction,
}
pub struct InstructionDecoding<'a> {
port: &'a mut BusPort,
memory: &'a mut M68kBusPort,
decoder: &'a mut M68kDecoder,
}
impl M68kDecoder {
#[inline]
pub fn new(cputype: M68kType, is_supervisor: bool, start: u32) -> M68kDecoder {
M68kDecoder {
cputype,
@ -59,52 +68,91 @@ impl M68kDecoder {
}
}
#[inline(always)]
#[inline]
pub fn init(&mut self, is_supervisor: bool, start: u32) {
self.is_supervisor = is_supervisor;
self.start = start;
self.end = start;
}
pub fn decode_at(&mut self, bus: &mut M68kBusPort, is_supervisor: bool, start: u32) -> Result<(), M68kError> {
#[inline]
pub fn decode_at(&mut self, port: &mut BusPort, memory: &mut M68kBusPort, is_supervisor: bool, start: u32) -> Result<(), M68kError> {
self.init(is_supervisor, start);
self.instruction = self.decode_next(bus)?;
let mut decoding = InstructionDecoding {
port,
memory,
decoder: self,
};
self.instruction = decoding.decode_next()?;
Ok(())
}
pub fn decode_next(&mut self, bus: &mut M68kBusPort) -> Result<Instruction, M68kError> {
let ins = self.read_instruction_word(bus)?;
self.instruction_word = ins;
pub fn dump_disassembly(&mut self, port: &mut BusPort, memory: &mut M68kBusPort, start: u32, length: u32) {
let mut next = start;
while next < (start + length) {
match self.decode_at(port, memory, self.is_supervisor, next) {
Ok(()) => {
self.dump_decoded(memory.current_clock, port);
next = self.end;
},
Err(err) => {
println!("{:?}", err);
match err {
M68kError::Exception(ex) if ex == Exceptions::IllegalInstruction => {
println!(" at {:08x}: {:04x}", self.start, port.read_beu16(memory.current_clock, self.start as Address).unwrap());
},
_ => { },
}
return;
},
}
}
}
pub fn dump_decoded(&mut self, clock: Instant, port: &mut BusPort) {
let ins_data: Result<String, M68kError> =
(0..((self.end - self.start) / 2)).map(|offset|
Ok(format!("{:04x} ", port.read_beu16(clock, (self.start + (offset * 2)) as Address).unwrap()))
).collect();
println!("{:#010x}: {}\n\t{}\n", self.start, ins_data.unwrap(), self.instruction);
}
}
impl<'a> InstructionDecoding<'a> {
#[inline]
pub fn decode_next(&mut self) -> Result<Instruction, M68kError> {
let ins = self.read_instruction_word()?;
self.decoder.instruction_word = ins;
match ((ins & 0xF000) >> 12) as u8 {
OPCG_BIT_OPS => self.decode_group_bit_ops(bus, ins),
OPCG_MOVE_BYTE => self.decode_group_move_byte(bus, ins),
OPCG_MOVE_LONG => self.decode_group_move_long(bus, ins),
OPCG_MOVE_WORD => self.decode_group_move_word(bus, ins),
OPCG_MISC => self.decode_group_misc(bus, ins),
OPCG_ADDQ_SUBQ => self.decode_group_addq_subq(bus, ins),
OPCG_BRANCH => self.decode_group_branch(bus, ins),
OPCG_MOVEQ => self.decode_group_moveq(bus, ins),
OPCG_DIV_OR => self.decode_group_div_or(bus, ins),
OPCG_SUB => self.decode_group_sub(bus, ins),
OPCG_BIT_OPS => self.decode_group_bit_ops(ins),
OPCG_MOVE_BYTE => self.decode_group_move_byte(ins),
OPCG_MOVE_LONG => self.decode_group_move_long(ins),
OPCG_MOVE_WORD => self.decode_group_move_word(ins),
OPCG_MISC => self.decode_group_misc(ins),
OPCG_ADDQ_SUBQ => self.decode_group_addq_subq(ins),
OPCG_BRANCH => self.decode_group_branch(ins),
OPCG_MOVEQ => self.decode_group_moveq(ins),
OPCG_DIV_OR => self.decode_group_div_or(ins),
OPCG_SUB => self.decode_group_sub(ins),
OPCG_ALINE => Ok(Instruction::UnimplementedA(ins)),
OPCG_CMP_EOR => self.decode_group_cmp_eor(bus, ins),
OPCG_MUL_AND => self.decode_group_mul_and(bus, ins),
OPCG_ADD => self.decode_group_add(bus, ins),
OPCG_SHIFT => self.decode_group_shift(bus, ins),
OPCG_CMP_EOR => self.decode_group_cmp_eor(ins),
OPCG_MUL_AND => self.decode_group_mul_and(ins),
OPCG_ADD => self.decode_group_add(ins),
OPCG_SHIFT => self.decode_group_shift(ins),
OPCG_FLINE => Ok(Instruction::UnimplementedF(ins)),
_ => Err(M68kError::Exception(Exceptions::IllegalInstruction)),
}
}
#[inline]
fn decode_group_bit_ops(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
fn decode_group_bit_ops(&mut self, ins: u16) -> Result<Instruction, M68kError> {
let optype = (ins & 0x0F00) >> 8;
if (ins & 0x13F) == 0x03C {
match (ins & 0x00C0) >> 6 {
0b00 => {
let data = self.read_instruction_word(bus)?;
let data = self.read_instruction_word()?;
match optype {
0b0000 => Ok(Instruction::ORtoCCR(data as u8)),
0b0010 => Ok(Instruction::ANDtoCCR(data as u8)),
@ -113,7 +161,7 @@ impl M68kDecoder {
}
},
0b01 => {
let data = self.read_instruction_word(bus)?;
let data = self.read_instruction_word()?;
match optype {
0b0000 => Ok(Instruction::ORtoSR(data)),
0b0010 => Ok(Instruction::ANDtoSR(data)),
@ -128,16 +176,16 @@ impl M68kDecoder {
let areg = get_low_reg(ins);
let dir = if (ins & 0x0080) == 0 { Direction::FromTarget } else { Direction::ToTarget };
let size = if (ins & 0x0040) == 0 { Size::Word } else { Size::Long };
let offset = self.read_instruction_word(bus)? as i16;
let offset = self.read_instruction_word()? as i16;
Ok(Instruction::MOVEP(dreg, areg, offset, size, dir))
} else if (ins & 0x0100) == 0x0100 || (ins & 0x0F00) == 0x0800 {
let bitnum = if (ins & 0x0100) == 0x0100 {
Target::DirectDReg(get_high_reg(ins))
} else {
Target::Immediate(self.read_instruction_word(bus)? as u32)
Target::Immediate(self.read_instruction_word()? as u32)
};
let target = self.decode_lower_effective_address(bus, ins, Some(Size::Byte))?;
let target = self.decode_lower_effective_address(ins, Some(Size::Byte))?;
let size = match target {
Target::DirectAReg(_) | Target::DirectDReg(_) => Size::Long,
_ => Size::Byte,
@ -153,12 +201,12 @@ impl M68kDecoder {
} else {
let size = get_size(ins);
let data = match size {
Some(Size::Byte) => self.read_instruction_word(bus)? as u32 & 0xFF,
Some(Size::Word) => self.read_instruction_word(bus)? as u32,
Some(Size::Long) => self.read_instruction_long(bus)?,
Some(Size::Byte) => self.read_instruction_word()? as u32 & 0xFF,
Some(Size::Word) => self.read_instruction_word()? as u32,
Some(Size::Long) => self.read_instruction_long()?,
None => return Err(M68kError::Exception(Exceptions::IllegalInstruction)),
};
let target = self.decode_lower_effective_address(bus, ins, size)?;
let target = self.decode_lower_effective_address(ins, size)?;
match optype {
0b0000 => Ok(Instruction::OR(Target::Immediate(data), target, size.unwrap())),
@ -173,16 +221,16 @@ impl M68kDecoder {
}
#[inline]
fn decode_group_move_byte(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
let src = self.decode_lower_effective_address(bus, ins, Some(Size::Byte))?;
let dest = self.decode_upper_effective_address(bus, ins, Some(Size::Byte))?;
fn decode_group_move_byte(&mut self, ins: u16) -> Result<Instruction, M68kError> {
let src = self.decode_lower_effective_address(ins, Some(Size::Byte))?;
let dest = self.decode_upper_effective_address(ins, Some(Size::Byte))?;
Ok(Instruction::MOVE(src, dest, Size::Byte))
}
#[inline]
fn decode_group_move_long(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
let src = self.decode_lower_effective_address(bus, ins, Some(Size::Long))?;
let dest = self.decode_upper_effective_address(bus, ins, Some(Size::Long))?;
fn decode_group_move_long(&mut self, ins: u16) -> Result<Instruction, M68kError> {
let src = self.decode_lower_effective_address(ins, Some(Size::Long))?;
let dest = self.decode_upper_effective_address(ins, Some(Size::Long))?;
if let Target::DirectAReg(reg) = dest {
Ok(Instruction::MOVEA(src, reg, Size::Long))
} else {
@ -191,9 +239,9 @@ impl M68kDecoder {
}
#[inline]
fn decode_group_move_word(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
let src = self.decode_lower_effective_address(bus, ins, Some(Size::Word))?;
let dest = self.decode_upper_effective_address(bus, ins, Some(Size::Word))?;
fn decode_group_move_word(&mut self, ins: u16) -> Result<Instruction, M68kError> {
let src = self.decode_lower_effective_address(ins, Some(Size::Word))?;
let dest = self.decode_upper_effective_address(ins, Some(Size::Word))?;
if let Target::DirectAReg(reg) = dest {
Ok(Instruction::MOVEA(src, reg, Size::Word))
} else {
@ -202,7 +250,7 @@ impl M68kDecoder {
}
#[inline]
fn decode_group_misc(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
fn decode_group_misc(&mut self, ins: u16) -> Result<Instruction, M68kError> {
let ins_0f00 = ins & 0xF00;
let ins_00f0 = ins & 0x0F0;
@ -210,38 +258,38 @@ impl M68kDecoder {
if (ins & 0x040) == 0 {
let size = match get_size(ins) {
Some(Size::Word) => Size::Word,
Some(Size::Long) if self.cputype >= M68kType::MC68020 => Size::Long,
Some(Size::Long) if self.decoder.cputype >= M68kType::MC68020 => Size::Long,
// On the 68000, long words in CHK are not supported, but the opcode maps to the word size instruction
Some(Size::Long) => Size::Word,
_ => return Err(M68kError::Exception(Exceptions::IllegalInstruction)),
};
let reg = get_high_reg(ins);
let target = self.decode_lower_effective_address(bus, ins, Some(size))?;
let target = self.decode_lower_effective_address(ins, Some(size))?;
Ok(Instruction::CHK(target, reg, size))
} else {
let src = self.decode_lower_effective_address(bus, ins, None)?;
let src = self.decode_lower_effective_address(ins, None)?;
let dest = get_high_reg(ins);
Ok(Instruction::LEA(src, dest))
}
} else if (ins & 0xB80) == 0x880 && (ins & 0x038) != 0 {
let size = if (ins & 0x0040) == 0 { Size::Word } else { Size::Long };
let data = self.read_instruction_word(bus)?;
let target = self.decode_lower_effective_address(bus, ins, None)?;
let data = self.read_instruction_word()?;
let target = self.decode_lower_effective_address(ins, None)?;
let dir = if (ins & 0x0400) == 0 { Direction::ToTarget } else { Direction::FromTarget };
Ok(Instruction::MOVEM(target, size, dir, data))
} else if (ins & 0xF80) == 0xC00 && self.cputype >= M68kType::MC68020 {
let extension = self.read_instruction_word(bus)?;
} else if (ins & 0xF80) == 0xC00 && self.decoder.cputype >= M68kType::MC68020 {
let extension = self.read_instruction_word()?;
let reg_h = if (extension & 0x0400) != 0 { Some(get_low_reg(ins)) } else { None };
let reg_l = ((extension & 0x7000) >> 12) as u8;
let target = self.decode_lower_effective_address(bus, ins, Some(Size::Long))?;
let target = self.decode_lower_effective_address(ins, Some(Size::Long))?;
let sign = if (ins & 0x0800) == 0 { Sign::Unsigned } else { Sign::Signed };
match (ins & 0x040) == 0 {
true => Ok(Instruction::MULL(target, reg_h, reg_l, sign)),
false => Ok(Instruction::DIVL(target, reg_h, reg_l, sign)),
}
} else if (ins & 0x800) == 0 {
let target = self.decode_lower_effective_address(bus, ins, Some(Size::Word))?;
let target = self.decode_lower_effective_address(ins, Some(Size::Word))?;
match (ins & 0x0700) >> 8 {
0b000 => {
match get_size(ins) {
@ -252,7 +300,7 @@ impl M68kDecoder {
0b010 => {
match get_size(ins) {
Some(size) => Ok(Instruction::CLR(target, size)),
None if self.cputype >= M68kType::MC68010 => Ok(Instruction::MOVEfromCCR(target)),
None if self.decoder.cputype >= M68kType::MC68010 => Ok(Instruction::MOVEfromCCR(target)),
None => Err(M68kError::Exception(Exceptions::IllegalInstruction)),
}
},
@ -274,12 +322,12 @@ impl M68kDecoder {
let opmode = (ins & 0x01C0) >> 6;
let mode = get_low_mode(ins);
match (opmode, mode) {
(0b000, 0b001) if self.cputype >= M68kType::MC68020 => {
let data = self.read_instruction_long(bus)? as i32;
(0b000, 0b001) if self.decoder.cputype >= M68kType::MC68020 => {
let data = self.read_instruction_long()? as i32;
Ok(Instruction::LINK(get_low_reg(ins), data))
},
(0b000, _) => {
let target = self.decode_lower_effective_address(bus, ins, Some(Size::Byte))?;
let target = self.decode_lower_effective_address(ins, Some(Size::Byte))?;
Ok(Instruction::NBCD(target))
},
(0b001, 0b000) => {
@ -289,7 +337,7 @@ impl M68kDecoder {
Ok(Instruction::BKPT(get_low_reg(ins)))
},
(0b001, _) => {
let target = self.decode_lower_effective_address(bus, ins, None)?;
let target = self.decode_lower_effective_address(ins, None)?;
Ok(Instruction::PEA(target))
},
(0b010, 0b000) => {
@ -307,7 +355,7 @@ impl M68kDecoder {
if (ins & 0x0FF) == 0xFC {
Ok(Instruction::ILLEGAL)
} else {
let target = self.decode_lower_effective_address(bus, ins, Some(Size::Word))?;
let target = self.decode_lower_effective_address(ins, Some(Size::Word))?;
match get_size(ins) {
Some(size) => Ok(Instruction::TST(target, size)),
None => Ok(Instruction::TAS(target)),
@ -315,7 +363,7 @@ impl M68kDecoder {
}
} else if ins_0f00 == 0xE00 {
if (ins & 0x80) == 0x80 {
let target = self.decode_lower_effective_address(bus, ins, None)?;
let target = self.decode_lower_effective_address(ins, None)?;
if (ins & 0b01000000) == 0 {
Ok(Instruction::JSR(target))
} else {
@ -326,7 +374,7 @@ impl M68kDecoder {
} else if ins_00f0 == 0x50 {
let reg = get_low_reg(ins);
if (ins & 0b1000) == 0 {
let data = (self.read_instruction_word(bus)? as i16) as i32;
let data = (self.read_instruction_word()? as i16) as i32;
Ok(Instruction::LINK(reg, data))
} else {
Ok(Instruction::UNLK(reg))
@ -340,20 +388,20 @@ impl M68kDecoder {
0x70 => Ok(Instruction::RESET),
0x71 => Ok(Instruction::NOP),
0x72 => {
let data = self.read_instruction_word(bus)?;
let data = self.read_instruction_word()?;
Ok(Instruction::STOP(data))
},
0x73 => Ok(Instruction::RTE),
0x74 if self.cputype >= M68kType::MC68010 => {
let offset = self.read_instruction_word(bus)? as i16;
0x74 if self.decoder.cputype >= M68kType::MC68010 => {
let offset = self.read_instruction_word()? as i16;
Ok(Instruction::RTD(offset))
},
0x75 => Ok(Instruction::RTS),
0x76 => Ok(Instruction::TRAPV),
0x77 => Ok(Instruction::RTR),
0x7A | 0x7B if self.cputype >= M68kType::MC68010 => {
0x7A | 0x7B if self.decoder.cputype >= M68kType::MC68010 => {
let dir = if ins & 0x01 == 0 { Direction::ToTarget } else { Direction::FromTarget };
let ins2 = self.read_instruction_word(bus)?;
let ins2 = self.read_instruction_word()?;
let target = match ins2 & 0x8000 {
0 => Target::DirectDReg(((ins2 & 0x7000) >> 12) as u8),
_ => Target::DirectAReg(((ins2 & 0x7000) >> 12) as u8),
@ -373,10 +421,10 @@ impl M68kDecoder {
}
#[inline]
fn decode_group_addq_subq(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
fn decode_group_addq_subq(&mut self, ins: u16) -> Result<Instruction, M68kError> {
match get_size(ins) {
Some(size) => {
let target = self.decode_lower_effective_address(bus, ins, Some(size))?;
let target = self.decode_lower_effective_address(ins, Some(size))?;
let mut data = ((ins & 0x0E00) >> 9) as u32;
if data == 0 {
data = 8;
@ -400,10 +448,10 @@ impl M68kDecoder {
if mode == 0b001 {
let reg = get_low_reg(ins);
let disp = self.read_instruction_word(bus)? as i16;
let disp = self.read_instruction_word()? as i16;
Ok(Instruction::DBcc(condition, reg, disp))
} else {
let target = self.decode_lower_effective_address(bus, ins, Some(Size::Byte))?;
let target = self.decode_lower_effective_address(ins, Some(Size::Byte))?;
Ok(Instruction::Scc(condition, target))
}
},
@ -411,12 +459,12 @@ impl M68kDecoder {
}
#[inline]
fn decode_group_branch(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
fn decode_group_branch(&mut self, ins: u16) -> Result<Instruction, M68kError> {
let mut disp = ((ins & 0xFF) as i8) as i32;
if disp == 0 {
disp = (self.read_instruction_word(bus)? as i16) as i32;
} else if disp == -1 && self.cputype >= M68kType::MC68020 {
disp = self.read_instruction_long(bus)? as i32;
disp = (self.read_instruction_word()? as i16) as i32;
} else if disp == -1 && self.decoder.cputype >= M68kType::MC68020 {
disp = self.read_instruction_long()? as i32;
}
let condition = get_condition(ins);
match condition {
@ -427,7 +475,7 @@ impl M68kDecoder {
}
#[inline]
fn decode_group_moveq(&mut self, _bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
fn decode_group_moveq(&mut self, ins: u16) -> Result<Instruction, M68kError> {
if (ins & 0x0100) != 0 {
return Err(M68kError::Exception(Exceptions::IllegalInstruction));
}
@ -437,7 +485,7 @@ impl M68kDecoder {
}
#[inline]
fn decode_group_div_or(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
fn decode_group_div_or(&mut self, ins: u16) -> Result<Instruction, M68kError> {
let size = get_size(ins);
if (ins & 0x1F0) == 0x100 {
@ -450,18 +498,18 @@ impl M68kDecoder {
}
} else if let Some(size) = size {
let data_reg = Target::DirectDReg(get_high_reg(ins));
let effective_addr = self.decode_lower_effective_address(bus, ins, Some(size))?;
let effective_addr = self.decode_lower_effective_address(ins, Some(size))?;
let (from, to) = if (ins & 0x0100) == 0 { (effective_addr, data_reg) } else { (data_reg, effective_addr) };
Ok(Instruction::OR(from, to, size))
} else {
let sign = if (ins & 0x0100) == 0 { Sign::Unsigned } else { Sign::Signed };
let effective_addr = self.decode_lower_effective_address(bus, ins, Some(Size::Word))?;
let effective_addr = self.decode_lower_effective_address(ins, Some(Size::Word))?;
Ok(Instruction::DIVW(effective_addr, get_high_reg(ins), sign))
}
}
#[inline]
fn decode_group_sub(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
fn decode_group_sub(&mut self, ins: u16) -> Result<Instruction, M68kError> {
let reg = get_high_reg(ins);
let dir = (ins & 0x0100) >> 8;
let size = get_size(ins);
@ -475,7 +523,7 @@ impl M68kDecoder {
false => Ok(Instruction::SUBX(Target::IndirectARegDec(src), Target::IndirectARegDec(dest), size)),
}
} else {
let target = self.decode_lower_effective_address(bus, ins, Some(size))?;
let target = self.decode_lower_effective_address(ins, Some(size))?;
if dir == 0 {
Ok(Instruction::SUB(target, Target::DirectDReg(reg), size))
} else {
@ -485,14 +533,14 @@ impl M68kDecoder {
},
None => {
let size = if dir == 0 { Size::Word } else { Size::Long };
let target = self.decode_lower_effective_address(bus, ins, Some(size))?;
let target = self.decode_lower_effective_address(ins, Some(size))?;
Ok(Instruction::SUBA(target, reg, size))
},
}
}
#[inline]
fn decode_group_cmp_eor(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
fn decode_group_cmp_eor(&mut self, ins: u16) -> Result<Instruction, M68kError> {
let reg = get_high_reg(ins);
let optype = (ins & 0x0100) >> 8;
let size = get_size(ins);
@ -501,17 +549,17 @@ impl M68kDecoder {
if get_low_mode(ins) == 0b001 {
Ok(Instruction::CMP(Target::IndirectARegInc(get_low_reg(ins)), Target::IndirectARegInc(reg), size))
} else {
let target = self.decode_lower_effective_address(bus, ins, Some(size))?;
let target = self.decode_lower_effective_address(ins, Some(size))?;
Ok(Instruction::EOR(Target::DirectDReg(reg), target, size))
}
},
(0b0, Some(size)) => {
let target = self.decode_lower_effective_address(bus, ins, Some(size))?;
let target = self.decode_lower_effective_address(ins, Some(size))?;
Ok(Instruction::CMP(target, Target::DirectDReg(reg), size))
},
(_, None) => {
let size = if optype == 0 { Size::Word } else { Size::Long };
let target = self.decode_lower_effective_address(bus, ins, Some(size))?;
let target = self.decode_lower_effective_address(ins, Some(size))?;
Ok(Instruction::CMPA(target, reg, size))
},
_ => Err(M68kError::Exception(Exceptions::IllegalInstruction)),
@ -519,7 +567,7 @@ impl M68kDecoder {
}
#[inline]
fn decode_group_mul_and(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
fn decode_group_mul_and(&mut self, ins: u16) -> Result<Instruction, M68kError> {
let size = get_size(ins);
if (ins & 0b0001_1111_0000) == 0b0001_0000_0000 {
@ -541,18 +589,18 @@ impl M68kDecoder {
}
} else if let Some(size) = size {
let data_reg = Target::DirectDReg(get_high_reg(ins));
let effective_addr = self.decode_lower_effective_address(bus, ins, Some(size))?;
let effective_addr = self.decode_lower_effective_address(ins, Some(size))?;
let (from, to) = if (ins & 0x0100) == 0 { (effective_addr, data_reg) } else { (data_reg, effective_addr) };
Ok(Instruction::AND(from, to, size))
} else {
let sign = if (ins & 0x0100) == 0 { Sign::Unsigned } else { Sign::Signed };
let effective_addr = self.decode_lower_effective_address(bus, ins, Some(Size::Word))?;
let effective_addr = self.decode_lower_effective_address(ins, Some(Size::Word))?;
Ok(Instruction::MULW(effective_addr, get_high_reg(ins), sign))
}
}
#[inline]
fn decode_group_add(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
fn decode_group_add(&mut self, ins: u16) -> Result<Instruction, M68kError> {
let reg = get_high_reg(ins);
let dir = (ins & 0x0100) >> 8;
let size = get_size(ins);
@ -566,7 +614,7 @@ impl M68kDecoder {
false => Ok(Instruction::ADDX(Target::IndirectARegDec(src), Target::IndirectARegDec(dest), size)),
}
} else {
let target = self.decode_lower_effective_address(bus, ins, Some(size))?;
let target = self.decode_lower_effective_address(ins, Some(size))?;
if dir == 0 {
Ok(Instruction::ADD(target, Target::DirectDReg(reg), size))
} else {
@ -576,13 +624,13 @@ impl M68kDecoder {
},
None => {
let size = if dir == 0 { Size::Word } else { Size::Long };
let target = self.decode_lower_effective_address(bus, ins, Some(size))?;
let target = self.decode_lower_effective_address(ins, Some(size))?;
Ok(Instruction::ADDA(target, reg, size))
},
}
}
fn decode_group_shift(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
fn decode_group_shift(&mut self, ins: u16) -> Result<Instruction, M68kError> {
match get_size(ins) {
Some(size) => {
let target = Target::DirectDReg(get_low_reg(ins));
@ -613,7 +661,7 @@ impl M68kDecoder {
},
None => {
if (ins & 0x800) == 0 {
let target = self.decode_lower_effective_address(bus, ins, Some(Size::Word))?;
let target = self.decode_lower_effective_address(ins, Some(Size::Word))?;
let count = Target::Immediate(1);
let size = Size::Word;
@ -634,9 +682,9 @@ impl M68kDecoder {
_ => Err(M68kError::Exception(Exceptions::IllegalInstruction)),
}
}
} else if self.cputype > M68kType::MC68020 {
} else if self.decoder.cputype > M68kType::MC68020 {
// Bitfield instructions (MC68020+)
let ext = self.read_instruction_word(bus)?;
let ext = self.read_instruction_word()?;
let reg = ((ext & 0x7000) >> 12) as u8;
let offset = match (ext & 0x0800) == 0 {
@ -649,7 +697,7 @@ impl M68kDecoder {
false => RegOrImmediate::DReg((ext & 0x0007) as u8),
};
let target = self.decode_lower_effective_address(bus, ins, Some(Size::Word))?;
let target = self.decode_lower_effective_address(ins, Some(Size::Word))?;
match (ins & 0x0700) >> 8 {
0b010 => Ok(Instruction::BFCHG(target, offset, width)),
0b100 => Ok(Instruction::BFCLR(target, offset, width)),
@ -668,42 +716,42 @@ impl M68kDecoder {
}
}
fn read_instruction_word(&mut self, bus: &mut M68kBusPort) -> Result<u16, M68kError> {
let word = bus.read_instruction_word(self.is_supervisor, self.end)?;
self.end += 2;
fn read_instruction_word(&mut self) -> Result<u16, M68kError> {
let word = self.memory.read_instruction_word(self.port, self.decoder.is_supervisor, self.decoder.end)?;
self.decoder.end += 2;
Ok(word)
}
fn read_instruction_long(&mut self, bus: &mut M68kBusPort) -> Result<u32, M68kError> {
let word = bus.read_instruction_long(self.is_supervisor, self.end)?;
self.end += 4;
fn read_instruction_long(&mut self) -> Result<u32, M68kError> {
let word = self.memory.read_instruction_long(self.port, self.decoder.is_supervisor, self.decoder.end)?;
self.decoder.end += 4;
Ok(word)
}
fn decode_lower_effective_address(&mut self, bus: &mut M68kBusPort, ins: u16, size: Option<Size>) -> Result<Target, M68kError> {
fn decode_lower_effective_address(&mut self, ins: u16, size: Option<Size>) -> Result<Target, M68kError> {
let reg = get_low_reg(ins);
let mode = get_low_mode(ins);
self.get_mode_as_target(bus, mode, reg, size)
self.get_mode_as_target(mode, reg, size)
}
fn decode_upper_effective_address(&mut self, bus: &mut M68kBusPort, ins: u16, size: Option<Size>) -> Result<Target, M68kError> {
fn decode_upper_effective_address(&mut self, ins: u16, size: Option<Size>) -> Result<Target, M68kError> {
let reg = get_high_reg(ins);
let mode = get_high_mode(ins);
self.get_mode_as_target(bus, mode, reg, size)
self.get_mode_as_target(mode, reg, size)
}
fn get_extension_displacement(&mut self, bus: &mut M68kBusPort, select: u16) -> Result<i32, M68kError> {
fn get_extension_displacement(&mut self, select: u16) -> Result<i32, M68kError> {
let result = match select {
0b00 | 0b01 => 0,
0b10 => sign_extend_to_long(self.read_instruction_word(bus)? as u32, Size::Word),
0b11 => self.read_instruction_long(bus)? as i32,
0b10 => sign_extend_to_long(self.read_instruction_word()? as u32, Size::Word),
0b11 => self.read_instruction_long()? as i32,
_ => return Err(M68kError::Exception(Exceptions::IllegalInstruction)),
};
Ok(result)
}
fn decode_extension_word(&mut self, bus: &mut M68kBusPort, areg: Option<u8>) -> Result<Target, M68kError> {
let brief_extension = self.read_instruction_word(bus)?;
fn decode_extension_word(&mut self, areg: Option<u8>) -> Result<Target, M68kError> {
let brief_extension = self.read_instruction_word()?;
let use_brief = (brief_extension & 0x0100) == 0;
@ -712,7 +760,7 @@ impl M68kDecoder {
let xreg = if (brief_extension & 0x8000) == 0 { XRegister::DReg(xreg_num) } else { XRegister::AReg(xreg_num) };
let size = if (brief_extension & 0x0800) == 0 { Size::Word } else { Size::Long };
if self.cputype <= M68kType::MC68010 {
if self.decoder.cputype <= M68kType::MC68010 {
let index_reg = IndexRegister { xreg, scale: 0, size };
let displacement = sign_extend_to_long((brief_extension & 0x00FF) as u32, Size::Byte);
@ -744,8 +792,8 @@ impl M68kDecoder {
(true, Some(areg)) => BaseRegister::AReg(areg),
};
let opt_index_reg = if use_index { Some(index_reg) } else { None };
let base_disp = self.get_extension_displacement(bus, (brief_extension & 0x0030) >> 4)?;
let outer_disp = self.get_extension_displacement(bus, brief_extension & 0x0003)?;
let base_disp = self.get_extension_displacement((brief_extension & 0x0030) >> 4)?;
let outer_disp = self.get_extension_displacement(brief_extension & 0x0003)?;
match (use_sub_indirect, pre_not_post) {
(false, _) => Ok(Target::IndirectRegOffset(opt_base_reg, opt_index_reg, base_disp)),
@ -755,7 +803,7 @@ impl M68kDecoder {
}
}
pub(super) fn get_mode_as_target(&mut self, bus: &mut M68kBusPort, mode: u8, reg: u8, size: Option<Size>) -> Result<Target, M68kError> {
pub(super) fn get_mode_as_target(&mut self, mode: u8, reg: u8, size: Option<Size>) -> Result<Target, M68kError> {
let value = match mode {
0b000 => Target::DirectDReg(reg),
0b001 => Target::DirectAReg(reg),
@ -763,33 +811,33 @@ impl M68kDecoder {
0b011 => Target::IndirectARegInc(reg),
0b100 => Target::IndirectARegDec(reg),
0b101 => {
let displacement = sign_extend_to_long(self.read_instruction_word(bus)? as u32, Size::Word);
let displacement = sign_extend_to_long(self.read_instruction_word()? as u32, Size::Word);
Target::IndirectRegOffset(BaseRegister::AReg(reg), None, displacement)
},
0b110 => {
self.decode_extension_word(bus, Some(reg))?
self.decode_extension_word(Some(reg))?
},
0b111 => {
match reg {
0b000 => {
let value = sign_extend_to_long(self.read_instruction_word(bus)? as u32, Size::Word) as u32;
let value = sign_extend_to_long(self.read_instruction_word()? as u32, Size::Word) as u32;
Target::IndirectMemory(value, Size::Word)
},
0b001 => {
let value = self.read_instruction_long(bus)?;
let value = self.read_instruction_long()?;
Target::IndirectMemory(value, Size::Long)
},
0b010 => {
let displacement = sign_extend_to_long(self.read_instruction_word(bus)? as u32, Size::Word);
let displacement = sign_extend_to_long(self.read_instruction_word()? as u32, Size::Word);
Target::IndirectRegOffset(BaseRegister::PC, None, displacement)
},
0b011 => {
self.decode_extension_word(bus, None)?
self.decode_extension_word(None)?
},
0b100 => {
let data = match size {
Some(Size::Byte) | Some(Size::Word) => self.read_instruction_word(bus)? as u32,
Some(Size::Long) => self.read_instruction_long(bus)?,
Some(Size::Byte) | Some(Size::Word) => self.read_instruction_word()? as u32,
Some(Size::Long) => self.read_instruction_long()?,
None => return Err(M68kError::Exception(Exceptions::IllegalInstruction)),
};
Target::Immediate(data)
@ -802,35 +850,7 @@ impl M68kDecoder {
Ok(value)
}
pub fn dump_disassembly(&mut self, bus: &mut M68kBusPort, start: u32, length: u32) {
let mut next = start;
while next < (start + length) {
match self.decode_at(bus, self.is_supervisor, next) {
Ok(()) => {
self.dump_decoded(bus);
next = self.end;
},
Err(err) => {
println!("{:?}", err);
match err {
M68kError::Exception(ex) if ex == Exceptions::IllegalInstruction => {
println!(" at {:08x}: {:04x}", self.start, bus.port.read_beu16(bus.current_clock, self.start as Address).unwrap());
},
_ => { },
}
return;
},
}
}
}
pub fn dump_decoded(&mut self, bus: &mut M68kBusPort) {
let ins_data: Result<String, M68kError> =
(0..((self.end - self.start) / 2)).map(|offset|
Ok(format!("{:04x} ", bus.port.read_beu16(bus.current_clock, (self.start + (offset * 2)) as Address).unwrap()))
).collect();
println!("{:#010x}: {}\n\t{}\n", self.start, ins_data.unwrap(), self.instruction);
}
}
#[inline(always)]

View File

@ -1,7 +1,7 @@
use femtos::{Instant, Duration};
use moa_core::{System, Error, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable};
use moa_core::{System, Error, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable, BusPort};
use crate::state::{M68k, M68kType, M68kError, M68kState, ClockCycles, Status, Flags, Exceptions, InterruptPriority};
use crate::memory::{MemType, MemAccess, M68kBusPort};
@ -38,35 +38,35 @@ pub enum Used {
pub struct M68kCycle {
pub decoder: M68kDecoder,
pub timing: M68kInstructionTiming,
pub memory: M68kBusPort,
pub current_clock: Instant,
}
impl M68kCycle {
#[inline]
pub fn default(cputype: M68kType, data_width: u8) -> Self {
Self {
decoder: M68kDecoder::new(cputype, true, 0),
timing: M68kInstructionTiming::new(cputype, data_width),
memory: M68kBusPort::new(Instant::START),
current_clock: Instant::START,
}
}
#[inline]
pub fn new(cpu: &M68k, clock: Instant) -> Self {
let is_supervisor = cpu.state.sr & (Flags:: Supervisor as u16) != 0;
let pc = cpu.state.pc;
let data_width = cpu.port.data_width();
let cputype = cpu.cputype;
Self {
decoder: M68kDecoder::new(cputype, is_supervisor, pc),
timing: M68kInstructionTiming::new(cputype, data_width),
decoder: M68kDecoder::new(cpu.info.chip, is_supervisor, cpu.state.pc),
timing: M68kInstructionTiming::new(cpu.info.chip, cpu.info.data_width as u8),
memory: M68kBusPort::new(clock),
current_clock: clock,
}
}
pub fn begin<'a>(mut self, cpu: &'a mut M68k) -> M68kCycleGuard<'a> {
// TODO this port init_cycle must be integrated into the cycle struct instead
cpu.port.init_cycle(self.current_clock);
M68kCycleGuard {
#[inline]
pub fn begin<'a>(mut self, cpu: &'a mut M68k) -> M68kCycleExecutor<'a> {
M68kCycleExecutor {
state: &mut cpu.state,
port: &mut cpu.port,
debugger: &mut cpu.debugger,
@ -75,14 +75,15 @@ impl M68kCycle {
}
}
pub struct M68kCycleGuard<'a> {
pub struct M68kCycleExecutor<'a> {
pub state: &'a mut M68kState,
pub port: &'a mut M68kBusPort,
pub port: &'a mut BusPort,
pub debugger: &'a mut M68kDebugger,
pub cycle: M68kCycle,
}
impl<'a> M68kCycleGuard<'a> {
impl<'a> M68kCycleExecutor<'a> {
#[inline]
pub fn dump_state(&mut self) {
println!("Status: {:?}", self.state.status);
println!("PC: {:#010x}", self.state.pc);
@ -95,7 +96,7 @@ impl<'a> M68kCycleGuard<'a> {
println!("Current Instruction: {:#010x} {:?}", self.cycle.decoder.start, self.cycle.decoder.instruction);
println!();
self.port.dump_memory(self.state.ssp, 0x40);
self.cycle.memory.dump_memory(self.port, self.state.ssp, 0x40);
println!();
}
@ -107,10 +108,10 @@ impl<'a> M68kCycleGuard<'a> {
impl Steppable for M68k {
fn step(&mut self, system: &System) -> Result<Duration, Error> {
let cycle = M68kCycle::new(self, system.clock);
let mut execution = cycle.begin(self);
let clocks = execution.step(system)?;
self.cycle = execution.end();
Ok(self.frequency.period_duration() * clocks as u64)
let mut executor = cycle.begin(self);
let clocks = executor.step(system)?;
self.cycle = Some(executor.end());
Ok(self.info.frequency.period_duration() * clocks as u64)
}
fn on_error(&mut self, _system: &System) {
@ -158,26 +159,35 @@ impl From<Error> for M68kError {
}
}
impl<'a> M68kCycleGuard<'a> {
impl<'a> M68kCycleExecutor<'a> {
#[inline]
pub fn step(&mut self, system: &System) -> Result<ClockCycles, M68kError> {
let result = self.step_one(system);
self.process_error(result, 4)
}
#[inline]
pub fn process_error<T>(&mut self, result: Result<T, M68kError>, ok: T) -> Result<T, M68kError> {
match result {
Ok(value) => Ok(value),
Err(M68kError::Exception(ex)) => {
self.exception(ex as u8, false)?;
Ok(ok)
},
Err(M68kError::Interrupt(ex)) => {
self.exception(ex as u8, false)?;
Ok(ok)
},
Err(err) => Err(err),
}
}
#[inline]
pub fn step_one(&mut self, system: &System) -> Result<ClockCycles, M68kError> {
match self.state.status {
Status::Init => self.reset_cpu(),
Status::Stopped => Err(M68kError::Halted),
Status::Running => {
match self.cycle_one(system) {
Ok(diff) => Ok(diff),
Err(M68kError::Exception(ex)) => {
self.exception(ex as u8, false)?;
Ok(4)
},
Err(M68kError::Interrupt(ex)) => {
self.exception(ex as u8, false)?;
Ok(4)
},
Err(err) => Err(err),
}
},
Status::Running => self.cycle_one(system),
}
}
@ -201,6 +211,7 @@ impl<'a> M68kCycleGuard<'a> {
#[inline]
pub fn check_pending_interrupts(&mut self, system: &System) -> Result<(), M68kError> {
// TODO this could move somewhere else
self.state.pending_ipl = match system.get_interrupt_controller().check() {
(true, priority) => InterruptPriority::from_u8(priority),
(false, _) => InterruptPriority::NoInterrupt,
@ -228,6 +239,35 @@ impl<'a> M68kCycleGuard<'a> {
Ok(())
}
/*
#[inline]
pub fn check_pending_interrupts2(&mut self, interrupt: Option<(InterruptPriority, u8)>) -> Result<InterruptAcknowledge, M68kError> {
self.state.pending_ipl = interrupt.unwrap_or(InterruptPriority::NoInterrupt);
let current_ipl = self.state.current_ipl as u8;
let pending_ipl = self.state.pending_ipl as u8;
if self.state.pending_ipl != InterruptPriority::NoInterrupt {
let priority_mask = ((self.state.sr & Flags::IntMask as u16) >> 8) as u8;
if (pending_ipl > priority_mask || pending_ipl == 7) && pending_ipl >= current_ipl {
log::debug!("{} interrupt: {} @ {} ns", DEV_NAME, pending_ipl, system.clock.as_duration().as_nanos());
self.state.current_ipl = self.state.pending_ipl;
let acknowledge = self.state.current_ipl;
let ack_num = system.get_interrupt_controller().acknowledge(self.state.current_ipl as u8)?;
self.exception(ack_num, true)?;
return Ok(());
}
}
if pending_ipl < current_ipl {
self.state.current_ipl = self.state.pending_ipl;
}
Ok(())
}
*/
pub fn exception(&mut self, number: u8, is_interrupt: bool) -> Result<(), M68kError> {
log::debug!("{}: raising exception {}", DEV_NAME, number);
@ -247,9 +287,9 @@ impl<'a> M68kCycleGuard<'a> {
fn setup_group0_exception(&mut self, number: u8) -> Result<(), M68kError> {
let sr = self.state.sr;
let ins_word = self.cycle.decoder.instruction_word;
let extra_code = self.port.request.get_type_code();
let fault_size = self.port.request.size.in_bytes();
let fault_address = self.port.request.address;
let extra_code = self.cycle.memory.request.get_type_code();
let fault_size = self.cycle.memory.request.size.in_bytes();
let fault_address = self.cycle.memory.request.address;
// Changes to the flags must happen after the previous value has been pushed to the stack
self.set_flag(Flags::Supervisor, true);
@ -275,7 +315,7 @@ impl<'a> M68kCycleGuard<'a> {
fn setup_normal_exception(&mut self, number: u8, is_interrupt: bool) -> Result<(), M68kError> {
let sr = self.state.sr;
self.port.request.i_n_bit = true;
self.cycle.memory.request.i_n_bit = true;
// Changes to the flags must happen after the previous value has been pushed to the stack
self.set_flag(Flags::Supervisor, true);
@ -308,7 +348,7 @@ impl<'a> M68kCycleGuard<'a> {
#[inline]
pub fn decode_next(&mut self) -> Result<(), M68kError> {
let is_supervisor = self.is_supervisor();
self.cycle.decoder.decode_at(&mut self.port, is_supervisor, self.state.pc)?;
self.cycle.decoder.decode_at(&mut self.port, &mut self.cycle.memory, is_supervisor, self.state.pc)?;
self.cycle.timing.add_instruction(&self.cycle.decoder.instruction);
@ -1613,25 +1653,25 @@ impl<'a> M68kCycleGuard<'a> {
}
fn get_address_sized(&mut self, addr: Address, size: Size) -> Result<u32, M68kError> {
self.port.read_data_sized(self.is_supervisor(), addr, size)
self.cycle.memory.read_data_sized(self.port, self.is_supervisor(), addr, size)
}
fn set_address_sized(&mut self, addr: Address, value: u32, size: Size) -> Result<(), M68kError> {
self.port.write_data_sized(self.is_supervisor(), addr, value, size)
self.cycle.memory.write_data_sized(self.port, self.is_supervisor(), addr, value, size)
}
fn push_word(&mut self, value: u16) -> Result<(), M68kError> {
*self.get_stack_pointer_mut() -= 2;
let addr = *self.get_stack_pointer_mut();
self.port.start_request(self.is_supervisor(), addr, Size::Word, MemAccess::Write, MemType::Data, false)?;
self.port.port.write_beu16(self.cycle.current_clock, addr as Address, value)?;
self.cycle.memory.start_request(self.is_supervisor(), addr, Size::Word, MemAccess::Write, MemType::Data, false)?;
self.port.write_beu16(self.cycle.current_clock, addr as Address, value)?;
Ok(())
}
fn pop_word(&mut self) -> Result<u16, M68kError> {
let addr = *self.get_stack_pointer_mut();
self.port.start_request(self.is_supervisor(), addr, Size::Word, MemAccess::Read, MemType::Data, false)?;
let value = self.port.port.read_beu16(self.cycle.current_clock, addr as Address)?;
self.cycle.memory.start_request(self.is_supervisor(), addr, Size::Word, MemAccess::Read, MemType::Data, false)?;
let value = self.port.read_beu16(self.cycle.current_clock, addr as Address)?;
*self.get_stack_pointer_mut() += 2;
Ok(value)
}
@ -1639,22 +1679,22 @@ impl<'a> M68kCycleGuard<'a> {
fn push_long(&mut self, value: u32) -> Result<(), M68kError> {
*self.get_stack_pointer_mut() -= 4;
let addr = *self.get_stack_pointer_mut();
self.port.start_request(self.is_supervisor(), addr, Size::Long, MemAccess::Write, MemType::Data, false)?;
self.port.port.write_beu32(self.cycle.current_clock, addr as Address, value)?;
self.cycle.memory.start_request(self.is_supervisor(), addr, Size::Long, MemAccess::Write, MemType::Data, false)?;
self.port.write_beu32(self.cycle.current_clock, addr as Address, value)?;
Ok(())
}
fn pop_long(&mut self) -> Result<u32, M68kError> {
let addr = *self.get_stack_pointer_mut();
self.port.start_request(self.is_supervisor(), addr, Size::Long, MemAccess::Read, MemType::Data, false)?;
let value = self.port.port.read_beu32(self.cycle.current_clock, addr as Address)?;
self.cycle.memory.start_request(self.is_supervisor(), addr, Size::Long, MemAccess::Read, MemType::Data, false)?;
let value = self.port.read_beu32(self.cycle.current_clock, addr as Address)?;
*self.get_stack_pointer_mut() += 4;
Ok(value)
}
fn set_pc(&mut self, value: u32) -> Result<(), M68kError> {
self.state.pc = value;
self.port.start_request(self.is_supervisor(), self.state.pc, Size::Word, MemAccess::Read, MemType::Program, true)?;
self.cycle.memory.start_request(self.is_supervisor(), self.state.pc, Size::Word, MemAccess::Read, MemType::Program, true)?;
Ok(())
}

View File

@ -2,7 +2,7 @@
use femtos::Instant;
use emulator_hal::bus::{BusType, BusAccess};
use moa_core::{Error, Address, Addressable, BusPort};
use moa_core::{Address, Addressable, BusPort};
use crate::state::{M68k, M68kError, Exceptions};
use crate::instructions::Size;
@ -41,6 +41,7 @@ pub struct MemoryRequest {
pub code: FunctionCode,
pub size: Size,
pub address: u32,
pub clock: Instant,
}
impl FunctionCode {
@ -69,11 +70,22 @@ impl Default for MemoryRequest {
code: FunctionCode::Reserved0,
size: Size::Word,
address: 0,
clock: Instant::START,
}
}
}
impl MemoryRequest {
pub(crate) fn instruction(&mut self, is_supervisor: bool, addr: u32) -> Result<u32, M68kError> {
self.i_n_bit = false;
self.code = FunctionCode::program(is_supervisor);
self.access = MemAccess::Read;
self.address = addr;
validate_address(addr)
}
#[inline]
pub fn get_type_code(&self) -> u16 {
let ins = match self.i_n_bit {
false => 0x0000,
@ -89,9 +101,16 @@ impl MemoryRequest {
}
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct InstructionRequest {
pub request: MemoryRequest,
pub current_clock: Instant,
}
#[derive(Clone, Debug)]
pub struct M68kBusPort {
pub port: BusPort,
//pub port: BusPort,
pub request: MemoryRequest,
pub cycle_start_clock: Instant,
pub current_clock: Instant,
@ -102,60 +121,52 @@ impl M68k {
// TODO should some of the ones from execute.rs move here
}
impl M68kBusPort {
pub fn new(port: BusPort) -> Self {
impl Default for M68kBusPort {
fn default(/* port: BusPort */) -> Self {
Self {
port,
//port,
request: Default::default(),
cycle_start_clock: Instant::START,
current_clock: Instant::START,
}
}
}
pub fn data_width(&self) -> u8 {
self.port.data_width()
impl M68kBusPort {
pub fn new(clock: Instant) -> Self {
Self {
request: Default::default(),
cycle_start_clock: clock,
current_clock: clock,
}
}
pub fn init_cycle(&mut self, clock: Instant) {
self.cycle_start_clock = clock;
self.current_clock = clock;
}
pub(crate) fn read_instruction_word(&mut self, is_supervisor: bool, addr: u32) -> Result<u16, M68kError> {
self.start_instruction_request(is_supervisor, addr)?;
Ok(self.port.read_beu16(self.current_clock, addr as Address)?)
}
pub(crate) fn read_instruction_long(&mut self, is_supervisor: bool, addr: u32) -> Result<u32, M68kError> {
self.start_instruction_request(is_supervisor, addr)?;
Ok(self.port.read_beu32(self.current_clock, addr as Address)?)
}
pub(crate) fn read_data_sized(&mut self, is_supervisor: bool, addr: Address, size: Size) -> Result<u32, M68kError> {
pub(crate) fn read_data_sized(&mut self, port: &mut BusPort, is_supervisor: bool, addr: Address, size: Size) -> Result<u32, M68kError> {
self.start_request(is_supervisor, addr as u32, size, MemAccess::Read, MemType::Data, false)?;
Ok(match size {
Size::Byte => self.port.read_u8(self.current_clock, addr).map(|value| value as u32),
Size::Word => self.port.read_beu16(self.current_clock, addr).map(|value| value as u32),
Size::Long => self.port.read_beu32(self.current_clock, addr),
Size::Byte => port.read_u8(self.current_clock, addr).map(|value| value as u32),
Size::Word => port.read_beu16(self.current_clock, addr).map(|value| value as u32),
Size::Long => port.read_beu32(self.current_clock, addr),
}?)
}
pub(crate) fn write_data_sized(&mut self, is_supervisor: bool, addr: Address, value: u32, size: Size) -> Result<(), M68kError> {
pub(crate) fn write_data_sized(&mut self, port: &mut BusPort, is_supervisor: bool, addr: Address, value: u32, size: Size) -> Result<(), M68kError> {
self.start_request(is_supervisor, addr as u32, size, MemAccess::Write, MemType::Data, false)?;
Ok(match size {
Size::Byte => self.port.write_u8(self.current_clock, addr, value as u8),
Size::Word => self.port.write_beu16(self.current_clock, addr, value as u16),
Size::Long => self.port.write_beu32(self.current_clock, addr, value),
Size::Byte => port.write_u8(self.current_clock, addr, value as u8),
Size::Word => port.write_beu16(self.current_clock, addr, value as u16),
Size::Long => port.write_beu32(self.current_clock, addr, value),
}?)
}
pub(crate) fn start_instruction_request(&mut self, is_supervisor: bool, addr: u32) -> Result<u32, M68kError> {
self.request.i_n_bit = false;
self.request.code = FunctionCode::program(is_supervisor);
self.request.access = MemAccess::Read;
self.request.address = addr;
pub(crate) fn read_instruction_word(&mut self, port: &mut BusPort, is_supervisor: bool, addr: u32) -> Result<u16, M68kError> {
self.request.instruction(is_supervisor, addr)?;
Ok(port.read_beu16(self.current_clock, addr as Address)?)
}
validate_address(addr)
pub(crate) fn read_instruction_long(&mut self, port: &mut BusPort, is_supervisor: bool, addr: u32) -> Result<u32, M68kError> {
self.request.instruction(is_supervisor, addr)?;
Ok(port.read_beu32(self.current_clock, addr as Address)?)
}
pub(crate) fn start_request(&mut self, is_supervisor: bool, addr: u32, size: Size, access: MemAccess, mtype: MemType, i_n_bit: bool) -> Result<u32, M68kError> {
@ -175,8 +186,8 @@ impl M68kBusPort {
}
}
pub(crate) fn dump_memory(&mut self, addr: u32, length: usize) {
self.port.dump_memory(self.current_clock, addr as Address, length as u64);
pub(crate) fn dump_memory(&mut self, port: &mut BusPort, addr: u32, length: usize) {
port.dump_memory(self.current_clock, addr as Address, length as u64);
}
}

View File

@ -5,25 +5,109 @@ use femtos::{Instant, Frequency};
use moa_core::{Address, Bus, BusPort};
use crate::decode::M68kDecoder;
use crate::debugger::M68kDebugger;
use crate::memory::M68kBusPort;
use crate::timing::M68kInstructionTiming;
use crate::instructions::Target;
use crate::execute::M68kCycle;
pub type ClockCycles = u16;
#[allow(dead_code)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum M68kType {
#[repr(u8)]
pub enum AddressWidth {
A32 = 32, // MC68020+
A24 = 24, // MC68000 64-Pin, MC68010
A22 = 22, // MC68008 52-Pin
A20 = 20, // MC68008 48-Pin
}
#[allow(dead_code)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u8)]
pub enum DataWidth {
D32 = 32,
D16 = 16,
D8 = 8,
}
/// The instruction set of the chip
#[allow(dead_code)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum CoreType {
MC68000,
MC68010,
MC68020,
MC68030,
}
/// Complete collection of information about the CPU being simulated
#[allow(dead_code)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct CpuInfo {
pub chip: M68kType,
pub core_type: CoreType,
pub address_width: AddressWidth,
pub data_width: DataWidth,
pub frequency: Frequency,
}
/// The variant of the 68k family of CPUs that is being emulated
///
/// This can be used as a shorthand for creating a CpuInfo that
/// can be used by the simuation code to determine behaviour
#[allow(dead_code)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum M68kType {
MC68000,
MC68008,
MC68010,
MC68020,
MC68030,
}
impl From<M68kType> for CoreType {
fn from(cputype: M68kType) -> Self {
match cputype {
M68kType::MC68000 => CoreType::MC68000,
M68kType::MC68008 => CoreType::MC68000,
M68kType::MC68010 => CoreType::MC68010,
M68kType::MC68020 => CoreType::MC68020,
M68kType::MC68030 => CoreType::MC68030,
}
}
}
impl CpuInfo {
fn from(cputype: M68kType, frequency: Frequency) -> Self {
match cputype {
M68kType::MC68008 => Self {
chip: cputype,
core_type: cputype.into(),
address_width: AddressWidth::A22,
data_width: DataWidth::D8,
frequency,
},
M68kType::MC68000 | M68kType::MC68010 => Self {
chip: cputype,
core_type: cputype.into(),
address_width: AddressWidth::A24,
data_width: DataWidth::D16,
frequency,
},
M68kType::MC68020 | M68kType::MC68030 => Self {
chip: cputype,
core_type: cputype.into(),
address_width: AddressWidth::A32,
data_width: DataWidth::D32,
frequency,
}
}
}
}
const FLAGS_ON_RESET: u16 = 0x2700;
#[repr(u16)]
@ -111,15 +195,11 @@ pub enum M68kError {
#[derive(Clone)]
pub struct M68k {
pub cputype: M68kType,
pub frequency: Frequency,
pub info: CpuInfo,
pub state: M68kState,
//pub decoder: M68kDecoder,
//pub timing: M68kInstructionTiming,
pub debugger: M68kDebugger,
pub port: M68kBusPort,
//pub current_clock: Instant,
pub cycle: M68kCycle,
pub port: BusPort,
pub cycle: Option<M68kCycle>,
}
impl Default for M68kState {
@ -142,30 +222,20 @@ impl Default for M68kState {
}
impl M68k {
pub fn new(cputype: M68kType, frequency: Frequency, port: BusPort) -> M68k {
let data_width = port.data_width();
pub fn new(info: CpuInfo, port: BusPort) -> M68k {
M68k {
cputype,
frequency,
info,
state: M68kState::default(),
//decoder: M68kDecoder::new(cputype, true, 0),
//timing: M68kInstructionTiming::new(cputype, port.data_width()),
debugger: M68kDebugger::default(),
port: M68kBusPort::new(port),
//current_clock: Instant::START,
cycle: M68kCycle::default(cputype, data_width),
port,
cycle: None,
}
}
pub fn from_type(cputype: M68kType, frequency: Frequency, bus: Rc<RefCell<Bus>>, addr_offset: Address) -> Self {
match cputype {
M68kType::MC68000 |
M68kType::MC68010 => Self::new(cputype, frequency, BusPort::new(addr_offset, 24, 16, bus)),
M68kType::MC68020 |
M68kType::MC68030 => Self::new(cputype, frequency, BusPort::new(addr_offset, 32, 32, bus)),
}
let info = CpuInfo::from(cputype, frequency);
Self::new(info, BusPort::new(addr_offset, info.address_width as u8, info.data_width as u8, bus))
}
}
impl InterruptPriority {

View File

@ -255,7 +255,7 @@ mod execute_unit_tests {
use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Steppable, Device};
use crate::{M68k, M68kType};
use crate::execute::{Used, M68kCycle, M68kCycleGuard};
use crate::execute::{Used, M68kCycle, M68kCycleExecutor};
use crate::instructions::{Instruction, Target, Size};
const INIT_STACK: Address = 0x00002000;
@ -263,7 +263,7 @@ mod execute_unit_tests {
fn run_execute_test<F>(cputype: M68kType, mut test_func: F)
where
F: FnMut(M68kCycleGuard),
F: FnMut(M68kCycleExecutor),
{
let mut system = System::default();
@ -277,13 +277,13 @@ mod execute_unit_tests {
let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0);
cpu.step(&system).unwrap();
let mut cycle = M68kCycle::new(&mut cpu, system.clock);
let mut execution = cycle.begin(&mut cpu);
execution.cycle.decoder.init(true, execution.state.pc);
assert_eq!(execution.state.pc, INIT_ADDR as u32);
assert_eq!(execution.state.ssp, INIT_STACK as u32);
assert_eq!(execution.cycle.decoder.instruction, Instruction::NOP);
let mut executor = cycle.begin(&mut cpu);
executor.cycle.decoder.init(true, executor.state.pc);
assert_eq!(executor.state.pc, INIT_ADDR as u32);
assert_eq!(executor.state.ssp, INIT_STACK as u32);
assert_eq!(executor.cycle.decoder.instruction, Instruction::NOP);
test_func(execution);
test_func(executor);
}
//

View File

@ -5,7 +5,7 @@ use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Steppable, De
use moa_m68k::{M68k, M68kType};
use moa_m68k::state::M68kState;
use moa_m68k::execute::{M68kCycle, M68kCycleGuard};
use moa_m68k::execute::{M68kCycle, M68kCycleExecutor};
use moa_m68k::instructions::{Instruction, Target, Size, Sign, Direction, Condition};
const INIT_STACK: Address = 0x00002000;
@ -37,7 +37,7 @@ struct TestCase {
fn run_execute_test<F>(cputype: M68kType, mut test_func: F)
where
F: FnMut(M68kCycleGuard, System),
F: FnMut(M68kCycleExecutor, System),
{
let mut system = System::default();

View File

@ -1,4 +1,10 @@
* I want to push System, and BusPort into only the step function
* first I need to make Decoder take &mut Addressable, and still function like it does
* next I need to make Executor only access through a &mut Addressable
* move the interrupt controller logic to the step() function only, and have a customish interrupt interface into the sim
* move the impls for Step, Transmutable, etc into a moa.rs file or something
* the remaining code should really use Addressable, and then we can swap it for BusAccess
* the idea would be, instead of argument drilling, you create an object that is short lived, that lasts one instruction, or possibly even parts of one instruction, and
it has some references instead of "moving" data (or if you move, you move and move out without cloning), such that you can bundle everything up, call a method on the