mirror of
https://github.com/transistorfet/moa.git
synced 2025-02-22 06:29:02 +00:00
Refactored to separate out the BusPort, to eventually replace it
This commit is contained in:
parent
54ebcce94c
commit
b4a35641e4
@ -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 {
|
||||
|
@ -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)]
|
||||
|
@ -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(())
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -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();
|
||||
|
||||
|
6
todo.txt
6
todo.txt
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user