mirror of
https://github.com/transistorfet/moa.git
synced 2024-09-29 15:56:19 +00:00
Added timing to m68k implementation
This commit is contained in:
parent
1b6cbfa831
commit
e3819fe549
@ -29,7 +29,7 @@ use super::state::{M68k, M68kType, Status, Flags, Exceptions, InterruptPriority}
|
||||
impl Steppable for M68k {
|
||||
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
|
||||
self.step_internal(system)?;
|
||||
Ok((1_000_000_000 / self.frequency as u64) * 4 as ClockElapsed)
|
||||
Ok((1_000_000_000 / self.frequency as u64) * self.timing.calculate_clocks(false, 1) as ClockElapsed)
|
||||
}
|
||||
|
||||
fn on_error(&mut self, system: &System) {
|
||||
@ -151,10 +151,14 @@ impl M68k {
|
||||
}
|
||||
|
||||
pub fn decode_next(&mut self) -> Result<(), Error> {
|
||||
self.timing.reset();
|
||||
|
||||
self.timer.decode.start();
|
||||
self.decoder.decode_at(&mut self.port, self.state.pc)?;
|
||||
self.timer.decode.end();
|
||||
|
||||
self.timing.add_instruction(&self.decoder.instruction);
|
||||
|
||||
if self.debugger.use_tracing {
|
||||
self.decoder.dump_decoded(&mut self.port);
|
||||
}
|
||||
|
@ -4,7 +4,9 @@ pub mod decode;
|
||||
pub mod execute;
|
||||
pub mod debugger;
|
||||
pub mod instructions;
|
||||
pub mod timing;
|
||||
pub mod tests;
|
||||
//pub mod testcases;
|
||||
|
||||
pub use self::state::{M68k, M68kType};
|
||||
|
||||
|
@ -6,7 +6,7 @@ use crate::memory::BusPort;
|
||||
|
||||
use super::decode::M68kDecoder;
|
||||
use super::debugger::M68kDebugger;
|
||||
|
||||
use super::timing::M68kInstructionTiming;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
@ -126,6 +126,7 @@ pub struct M68k {
|
||||
pub frequency: u32,
|
||||
pub state: M68kState,
|
||||
pub decoder: M68kDecoder,
|
||||
pub timing: M68kInstructionTiming,
|
||||
pub debugger: M68kDebugger,
|
||||
pub port: BusPort,
|
||||
pub timer: CpuTimer,
|
||||
@ -138,6 +139,7 @@ impl M68k {
|
||||
frequency,
|
||||
state: M68kState::new(),
|
||||
decoder: M68kDecoder::new(cputype, 0),
|
||||
timing: M68kInstructionTiming::new(cputype, port.data_width()),
|
||||
debugger: M68kDebugger::new(),
|
||||
port: port,
|
||||
timer: CpuTimer::new(),
|
||||
@ -148,6 +150,7 @@ impl M68k {
|
||||
pub fn reset(&mut self) {
|
||||
self.state = M68kState::new();
|
||||
self.decoder = M68kDecoder::new(self.cputype, 0);
|
||||
self.timing = M68kInstructionTiming::new(self.cputype, self.port.data_width());
|
||||
self.debugger = M68kDebugger::new();
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ mod decode_tests {
|
||||
use crate::cpus::m68k::{M68k, M68kType};
|
||||
use crate::cpus::m68k::state::Exceptions;
|
||||
use crate::cpus::m68k::instructions::{Instruction, Target, Size, Sign, XRegister, BaseRegister, IndexRegister, Direction, ShiftDirection};
|
||||
use crate::cpus::m68k::timing::M68kInstructionTiming;
|
||||
|
||||
const INIT_STACK: Address = 0x00002000;
|
||||
const INIT_ADDR: Address = 0x00000010;
|
||||
@ -26,8 +27,15 @@ mod decode_tests {
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0x003C, 0x00FF], ins: Some(Instruction::ORtoCCR(0xFF)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0x007C, 0x1234], ins: Some(Instruction::ORtoSR(0x1234)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0x0263, 0x1234], ins: Some(Instruction::AND(Target::Immediate(0x1234), Target::IndirectARegDec(3), Size::Word)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0x0240, 0x1234], ins: Some(Instruction::AND(Target::Immediate(0x1234), Target::DirectDReg(0), Size::Word)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0x02A3, 0x1234, 0x5678], ins: Some(Instruction::AND(Target::Immediate(0x12345678), Target::IndirectARegDec(3), Size::Long)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0x0280, 0x1234, 0x5678], ins: Some(Instruction::AND(Target::Immediate(0x12345678), Target::DirectDReg(0), Size::Long)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0x023C, 0x1234], ins: Some(Instruction::ANDtoCCR(0x34)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0x027C, 0xF8FF], ins: Some(Instruction::ANDtoSR(0xF8FF)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0x4240], ins: Some(Instruction::CLR(Target::DirectDReg(0), Size::Word)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0x4280], ins: Some(Instruction::CLR(Target::DirectDReg(0), Size::Long)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0x4250], ins: Some(Instruction::CLR(Target::IndirectAReg(0), Size::Word)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0x4290], ins: Some(Instruction::CLR(Target::IndirectAReg(0), Size::Long)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0x0487, 0x1234, 0x5678], ins: Some(Instruction::SUB(Target::Immediate(0x12345678), Target::DirectDReg(7), Size::Long)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0x063A, 0x1234, 0x0055], ins: Some(Instruction::ADD(Target::Immediate(0x34), Target::IndirectRegOffset(BaseRegister::PC, None, 0x55), Size::Byte)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0x0A23, 0x1234], ins: Some(Instruction::EOR(Target::Immediate(0x34), Target::IndirectARegDec(3), Size::Byte)) },
|
||||
@ -116,6 +124,65 @@ mod decode_tests {
|
||||
}
|
||||
}
|
||||
|
||||
//use super::super::testcases::{TimingCase, TIMING_TESTS};
|
||||
|
||||
struct TimingCase {
|
||||
cpu: M68kType,
|
||||
data: &'static [u16],
|
||||
timing: (u16, u16, u16),
|
||||
ins: Instruction,
|
||||
}
|
||||
|
||||
const TIMING_TESTS: &'static [TimingCase] = &[
|
||||
TimingCase { cpu: M68kType::MC68000, data: &[0xD090], timing: ( 14, 14, 6), ins: Instruction::ADD(Target::IndirectAReg(0), Target::DirectDReg(0), Size::Long) },
|
||||
];
|
||||
|
||||
fn run_timing_test(case: &TimingCase) -> Result<(), Error> {
|
||||
let (mut cpu, system) = init_decode_test(case.cpu);
|
||||
let mut timing = M68kInstructionTiming::new(case.cpu, 16);
|
||||
|
||||
load_memory(&system, case.data);
|
||||
cpu.decode_next().unwrap();
|
||||
assert_eq!(cpu.decoder.instruction, case.ins.clone());
|
||||
|
||||
timing.add_instruction(&cpu.decoder.instruction);
|
||||
let result = timing.calculate_clocks(false, 1);
|
||||
let expected = match case.cpu {
|
||||
M68kType::MC68000 => case.timing.0,
|
||||
M68kType::MC68010 => case.timing.1,
|
||||
_ => case.timing.2,
|
||||
};
|
||||
|
||||
//assert_eq!(expected, result);
|
||||
if expected == result {
|
||||
Ok(())
|
||||
} else {
|
||||
println!("{:?}", timing);
|
||||
Err(Error::new(&format!("expected {} but found {}", expected, result)))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn run_timing_tests() {
|
||||
let mut errors = 0;
|
||||
for case in TIMING_TESTS {
|
||||
// NOTE switched to only show the failures rather than all tests
|
||||
//print!("Testing for {:?}...", case.ins);
|
||||
//match run_timing_test(case) {
|
||||
// Ok(()) => println!("ok"),
|
||||
// Err(err) => { println!("{}", err.msg); errors += 1 },
|
||||
//}
|
||||
|
||||
if let Err(err) = run_timing_test(case) {
|
||||
errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if errors > 0 {
|
||||
panic!("{} errors", errors);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Addressing Mode Target Tests
|
||||
//
|
||||
@ -306,7 +373,7 @@ mod decode_tests {
|
||||
system.get_bus().write_beu16(INIT_ADDR, expected as u16).unwrap();
|
||||
|
||||
let target = cpu.decoder.get_mode_as_target(&mut cpu.port, 0b111, 0b000, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectMemory(expected));
|
||||
assert_eq!(target, Target::IndirectMemory(expected, Size::Word));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -319,7 +386,7 @@ mod decode_tests {
|
||||
system.get_bus().write_beu32(INIT_ADDR, expected).unwrap();
|
||||
|
||||
let target = cpu.decoder.get_mode_as_target(&mut cpu.port, 0b111, 0b001, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectMemory(expected));
|
||||
assert_eq!(target, Target::IndirectMemory(expected, Size::Long));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
369
src/cpus/m68k/timing.rs
Normal file
369
src/cpus/m68k/timing.rs
Normal file
@ -0,0 +1,369 @@
|
||||
|
||||
use super::state::M68kType;
|
||||
|
||||
use super::instructions::{
|
||||
Register,
|
||||
Size,
|
||||
Sign,
|
||||
Direction,
|
||||
ShiftDirection,
|
||||
XRegister,
|
||||
BaseRegister,
|
||||
IndexRegister,
|
||||
RegOrImmediate,
|
||||
ControlRegister,
|
||||
Condition,
|
||||
Target,
|
||||
Instruction,
|
||||
};
|
||||
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct M68kInstructionTiming {
|
||||
pub cputype: M68kType,
|
||||
pub bus_size: Size,
|
||||
|
||||
pub accesses: u8,
|
||||
pub internal: u8,
|
||||
pub on_branch: u8,
|
||||
pub per_rep: u8,
|
||||
}
|
||||
|
||||
impl M68kInstructionTiming {
|
||||
pub fn new(cputype: M68kType, bus_width: u8) -> Self {
|
||||
let bus_size = if bus_width <= 16 { Size::Word } else { Size::Long };
|
||||
Self {
|
||||
cputype,
|
||||
bus_size,
|
||||
|
||||
accesses: 0,
|
||||
internal: 0,
|
||||
on_branch: 0,
|
||||
per_rep: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.accesses = 0;
|
||||
self.internal = 0;
|
||||
self.on_branch = 0;
|
||||
self.per_rep = 0;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_access(&mut self, size: Size) -> &mut Self {
|
||||
self.accesses += self.access_size(size);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_internal(&mut self, clocks: u8) -> &mut Self {
|
||||
self.internal += clocks;
|
||||
self
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn sub_internal(&mut self, clocks: u8) -> &mut Self {
|
||||
self.internal = self.internal.saturating_sub(clocks);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_if_long(&mut self, size: Size, clocks: u8) -> &mut Self {
|
||||
self.internal += if size == Size::Long { clocks } else { 0 };
|
||||
self
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_reg_v_mem(&mut self, target: &Target, reg: u8, mem: u8) -> &mut Self {
|
||||
self.internal += match target {
|
||||
Target::DirectDReg(_) |
|
||||
Target::DirectAReg(_) => reg,
|
||||
_ => mem,
|
||||
};
|
||||
self
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_word_v_long(&mut self, size: Size, word: u8, long: u8) -> &mut Self {
|
||||
self.internal += if size != Size::Long { word } else { long };
|
||||
self
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_standard_set(&mut self, size: Size, target: &Target, areg: (u8, u8), dreg: (u8, u8), mem: (u8, u8)) -> &mut Self {
|
||||
match target {
|
||||
Target::DirectDReg(_) => self.add_word_v_long(size, dreg.0, dreg.1),
|
||||
Target::DirectAReg(_) => self.add_word_v_long(size, areg.0, dreg.1),
|
||||
_ => self.add_word_v_long(size, mem.0, mem.1),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_immediate_set(&mut self, size: Size, target: &Target, reg: (u8, u8), mem: (u8, u8)) -> &mut Self {
|
||||
match target {
|
||||
Target::DirectDReg(_) | Target::DirectAReg(_) => self.add_word_v_long(size, reg.0, reg.1),
|
||||
_ => self.add_word_v_long(size, mem.0, mem.1)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_indirect_set(&mut self, target: &Target, areg: u8, aoff: u8, indoff: u8, indw: u8, indl: u8) -> &mut Self {
|
||||
match target {
|
||||
Target::IndirectAReg(_) => self.add_internal(areg),
|
||||
Target::IndirectRegOffset(_, None, _) => self.add_internal(aoff),
|
||||
Target::IndirectRegOffset(_, Some(_), _) => self.add_internal(indoff),
|
||||
Target::IndirectMemory(_, Size::Long) => self.add_internal(indl),
|
||||
Target::IndirectMemory(_, _) => self.add_internal(indw),
|
||||
_ => panic!("This timing set can't be used with {:?} targetting", target),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_reg_mem_set(&mut self, size: Size, target: &Target, reg: (u8, u8), mem: (u8, u8)) -> &mut Self {
|
||||
match target {
|
||||
Target::DirectDReg(_) | Target::DirectAReg(_) => self.add_word_v_long(size, reg.0, reg.1),
|
||||
_ => self.add_word_v_long(size, mem.0, mem.1)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_on_branch(&mut self, clocks: u8) -> &mut Self {
|
||||
self.on_branch += clocks;
|
||||
self
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_per_rep(&mut self, clocks: u8) -> &mut Self {
|
||||
self.per_rep += clocks;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_target(&mut self, size: Size, target: &Target) -> &mut Self {
|
||||
match target {
|
||||
Target::Immediate(_) => self.add_access(size),
|
||||
Target::DirectDReg(_) => self,
|
||||
Target::DirectAReg(_) => self,
|
||||
Target::IndirectAReg(_) => self.add_access(size),
|
||||
Target::IndirectARegInc(_) => self.add_access(size),
|
||||
Target::IndirectARegDec(_) => self.add_access(size).add_internal(2),
|
||||
Target::IndirectRegOffset(base_reg, index_reg, offset) => {
|
||||
match index_reg {
|
||||
None => self.add_access(size).add_internal(4),
|
||||
Some(_) => self.add_access(size).add_internal(6),
|
||||
}
|
||||
},
|
||||
Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) |
|
||||
Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => {
|
||||
// TODO this is very wrong, but the 68020 timings are complicated
|
||||
match index_reg {
|
||||
None => self.add_access(size).add_internal(4),
|
||||
Some(_) => self.add_access(size).add_internal(6),
|
||||
}
|
||||
},
|
||||
Target::IndirectMemory(_, addr_size) => self.add_access(*addr_size).add_access(size),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_two_targets(&mut self, size: Size, src: &Target, dest: &Target) -> &mut Self {
|
||||
match (src, dest) {
|
||||
(Target::IndirectARegDec(_), Target::IndirectARegDec(_)) => self.add_target(size, src).add_target(size, dest).sub_internal(2),
|
||||
_ => self.add_target(size, src).add_target(size, dest),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_movem(&mut self, size: Size, target: &Target, dir: Direction, n: u8) -> &mut Self {
|
||||
if dir == Direction::FromTarget {
|
||||
match target {
|
||||
Target::IndirectAReg(_) => self.add_word_v_long(size, 12 + 4 * n, 12 + 8 * n),
|
||||
Target::IndirectARegInc(_) => self.add_word_v_long(size, 12 + 4 * n, 12 + 8 * n),
|
||||
Target::IndirectRegOffset(_, None, _) => self.add_word_v_long(size, 16 + 4 * n, 16 + 8 * n),
|
||||
Target::IndirectRegOffset(_, Some(_), _) => self.add_word_v_long(size, 18 + 4 * n, 18 + 8 * n),
|
||||
Target::IndirectMemory(_, Size::Long) => self.add_word_v_long(size, 20 + 4 * n, 20 + 8 * n),
|
||||
Target::IndirectMemory(_, _) => self.add_word_v_long(size, 16 + 4 * n, 16 + 8 * n),
|
||||
_ => panic!("This timing set can't be used with {:?} targetting", target),
|
||||
}
|
||||
} else {
|
||||
match target {
|
||||
Target::IndirectAReg(_) => self.add_word_v_long(size, 8 + 4 * n, 8 + 8 * n),
|
||||
Target::IndirectARegDec(_) => self.add_word_v_long(size, 8 + 4 * n, 8 + 8 * n),
|
||||
Target::IndirectRegOffset(_, None, _) => self.add_word_v_long(size, 12 + 4 * n, 12 + 8 * n),
|
||||
Target::IndirectRegOffset(_, Some(_), _) => self.add_word_v_long(size, 14 + 4 * n, 14 + 8 * n),
|
||||
Target::IndirectMemory(_, Size::Long) => self.add_word_v_long(size, 16 + 4 * n, 16 + 8 * n),
|
||||
Target::IndirectMemory(_, _) => self.add_word_v_long(size, 12 + 4 * n, 12 + 8 * n),
|
||||
_ => panic!("This timing set can't be used with {:?} targetting", target),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_instruction(&mut self, instruction: &Instruction) -> &mut Self {
|
||||
match self.cputype {
|
||||
M68kType::MC68000 | M68kType::MC68010 => self.add_instruction_68000(instruction),
|
||||
_ => self.add_instruction_68020(instruction),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_instruction_68000(&mut self, instruction: &Instruction) -> &mut Self {
|
||||
match instruction {
|
||||
Instruction::ABCD(src, dest) => self.add_reg_v_mem(dest, 6, 18),
|
||||
|
||||
Instruction::ADD(src @ Target::Immediate(x), dest, size) if *x <= 8 => self.add_immediate_set(*size, dest, (4, 8), (8, 12)).add_target(*size, dest),// ADDQ
|
||||
Instruction::ADD(src @ Target::Immediate(_), dest, size) => self.add_immediate_set(*size, dest, (8, 16), (12, 20)).add_target(*size, dest), // ADDI
|
||||
|
||||
Instruction::ADD(src, dest, size) => self.add_standard_set(*size, dest, (8, 6), (4, 6), (8, 12)).add_two_targets(*size, src, dest),
|
||||
Instruction::ADDA(target, reg, size) => self.add_word_v_long(*size, 8, 6).add_target(*size, target),
|
||||
Instruction::ADDX(src, dest, size) => self.add_reg_mem_set(*size, dest, (4, 8), (18, 30)),
|
||||
|
||||
Instruction::AND(src @ Target::Immediate(_), dest, size) => self.add_immediate_set(*size, dest, (8, 14), (12, 20)).add_target(*size, dest),
|
||||
Instruction::AND(src, dest, size) => self.add_standard_set(*size, dest, (0, 0), (4, 6), (8, 12)).add_two_targets(*size, src, dest),
|
||||
Instruction::ANDtoCCR(_) => self.add_internal(20),
|
||||
Instruction::ANDtoSR(_) => self.add_internal(20),
|
||||
|
||||
Instruction::ASd(count, target, size, dir) => self.add_word_v_long(*size, 6, 8).add_per_rep(2).add_target(*size, target),
|
||||
|
||||
Instruction::Bcc(_, _) => self.add_internal(8).add_on_branch(2),
|
||||
Instruction::BRA(_) => self.add_internal(10),
|
||||
Instruction::BSR(_) => self.add_internal(18),
|
||||
|
||||
Instruction::BCHG(bit, target, size) => match bit {
|
||||
Target::Immediate(_) => self.add_reg_v_mem(target, 12, 12),
|
||||
_ => self.add_reg_v_mem(target, 8, 8),
|
||||
}.add_target(*size, target),
|
||||
Instruction::BCLR(bit, target, size) => match bit {
|
||||
Target::Immediate(_) => self.add_reg_v_mem(target, 14, 12),
|
||||
_ => self.add_reg_v_mem(target, 10, 8),
|
||||
}.add_target(*size, target),
|
||||
Instruction::BSET(bit, target, size) => match bit {
|
||||
Target::Immediate(_) => self.add_reg_v_mem(target, 12, 12),
|
||||
_ => self.add_reg_v_mem(target, 8, 8),
|
||||
}.add_target(*size, target),
|
||||
Instruction::BTST(bit, target, size) => match bit {
|
||||
Target::Immediate(_) => self.add_reg_v_mem(target, 10, 8),
|
||||
_ => self.add_reg_v_mem(target, 6, 4),
|
||||
}.add_target(*size, target),
|
||||
|
||||
Instruction::CHK(target, reg, size) => self.add_internal(10),
|
||||
Instruction::CLR(target, size) => self.add_reg_v_mem(target, 4, 8).add_word_v_long(*size, 0, 2).add_target(*size, target),
|
||||
|
||||
Instruction::CMP(src @ Target::Immediate(_), dest, size) => self.add_immediate_set(*size, dest, (8, 14), (8, 12)).add_target(*size, dest),
|
||||
Instruction::CMP(src, dest, size) => self.add_standard_set(*size, dest, (6, 6), (4, 6), (0, 0)).add_two_targets(*size, src, dest),
|
||||
Instruction::CMPA(target, _, size) => self.add_word_v_long(*size, 6, 6).add_target(*size, target),
|
||||
|
||||
Instruction::DBcc(_, _, _) => self.add_internal(10).add_on_branch(4),
|
||||
Instruction::DIVW(src, _, sign) => match sign {
|
||||
Sign::Unsigned => self.add_internal(140).add_target(Size::Long, src),
|
||||
Sign::Signed => self.add_internal(158).add_target(Size::Long, src),
|
||||
},
|
||||
|
||||
Instruction::EOR(src @ Target::Immediate(_), dest, size) => self.add_immediate_set(*size, dest, (8, 16), (12, 20)).add_target(*size, dest),
|
||||
Instruction::EOR(src, dest, size) => self.add_standard_set(*size, dest, (0, 0), (4, 8), (8, 12)).add_two_targets(*size, src, dest),
|
||||
Instruction::EORtoCCR(_) => self.add_internal(20),
|
||||
Instruction::EORtoSR(_) => self.add_internal(20),
|
||||
|
||||
Instruction::EXG(_, _) => self.add_internal(6),
|
||||
Instruction::EXT(_, _, _) => self.add_internal(4),
|
||||
|
||||
Instruction::ILLEGAL => self.add_internal(4),
|
||||
|
||||
Instruction::JMP(target) => self.add_indirect_set(target, 8, 10, 14, 10, 12),
|
||||
Instruction::JSR(target) => self.add_indirect_set(target, 16, 18, 22, 18, 20),
|
||||
|
||||
Instruction::LEA(target, reg) => self.add_indirect_set(target, 4, 8, 12, 8, 12),
|
||||
Instruction::LINK(_, _) => self.add_internal(16),
|
||||
Instruction::LSd(count, target, size, dir) => self.add_word_v_long(*size, 6, 8).add_per_rep(2).add_target(*size, target),
|
||||
|
||||
Instruction::MOVE(src, dest, size) => self.add_internal(4).add_two_targets(*size, src, dest),
|
||||
Instruction::MOVEA(target, _, size) => self.add_internal(4).add_target(*size, target),
|
||||
Instruction::MOVEfromSR(target) => self.add_reg_v_mem(target, 6, 8).add_target(Size::Word, target),
|
||||
Instruction::MOVEtoSR(target) => self.add_internal(12).add_target(Size::Word, target),
|
||||
Instruction::MOVEfromCCR(target) => self.add_internal(12).add_target(Size::Word, target),
|
||||
Instruction::MOVEtoCCR(target) => self.add_internal(12).add_target(Size::Word, target),
|
||||
Instruction::MOVEC(target, reg, dir) => self.add_reg_v_mem(target, 10, 12),
|
||||
Instruction::MOVEM(target, size, dir, mask) => self.add_movem(*size, target, *dir, mask.count_ones() as u8),
|
||||
Instruction::MOVEP(_, _, _, size, _) => self.add_word_v_long(*size, 16, 24),
|
||||
Instruction::MOVEQ(value, reg) => self.add_internal(4),
|
||||
Instruction::MOVEUSP(_, _) => self.add_internal(4),
|
||||
|
||||
Instruction::MULW(src, _, _) => self.add_internal(70).add_target(Size::Word, src),
|
||||
|
||||
Instruction::NBCD(target) => self.add_reg_v_mem(target, 6, 8),
|
||||
Instruction::NEG(target, size) => self.add_reg_mem_set(*size, target, (4, 6), (8, 12)).add_target(*size, target),
|
||||
Instruction::NEGX(target, size) => self.add_reg_mem_set(*size, target, (4, 6), (8, 12)).add_target(*size, target),
|
||||
|
||||
Instruction::NOP => self.add_internal(4),
|
||||
Instruction::NOT(target, size) => self.add_reg_mem_set(*size, target, (4, 6), (8, 12)).add_target(*size, target),
|
||||
|
||||
Instruction::OR(src @ Target::Immediate(_), dest, size) => self.add_immediate_set(*size, dest, (8, 16), (12, 20)).add_target(*size, dest),
|
||||
Instruction::OR(src, dest, size) => self.add_standard_set(*size, dest, (0, 0), (4, 6), (8, 12)).add_two_targets(*size, src, dest),
|
||||
Instruction::ORtoCCR(_) => self.add_internal(20),
|
||||
Instruction::ORtoSR(_) => self.add_internal(20),
|
||||
|
||||
Instruction::PEA(target) => self.add_indirect_set(target, 12, 16, 20, 16, 20),
|
||||
|
||||
Instruction::RESET => self.add_internal(132),
|
||||
|
||||
Instruction::ROd(count, target, size, dir) => self.add_word_v_long(*size, 6, 8).add_per_rep(2).add_target(*size, target),
|
||||
Instruction::ROXd(count, target, size, dir) => self.add_word_v_long(*size, 6, 8).add_per_rep(2).add_target(*size, target),
|
||||
|
||||
Instruction::RTE => self.add_internal(20),
|
||||
Instruction::RTR => self.add_internal(20),
|
||||
Instruction::RTS => self.add_internal(16),
|
||||
//Instruction::RTD(offset) => ,
|
||||
|
||||
Instruction::SBCD(src, dest) => self.add_reg_v_mem(dest, 6, 18),
|
||||
Instruction::Scc(_, target) => self.add_reg_v_mem(target, 4, 8).add_on_branch(2).add_target(Size::Byte, target),
|
||||
Instruction::STOP(_) => self.add_internal(4),
|
||||
|
||||
Instruction::SUB(Target::Immediate(x), Target::DirectAReg(_), Size::Byte)
|
||||
| Instruction::SUB(Target::Immediate(x), Target::DirectAReg(_), Size::Word) if *x <= 8 => self.add_internal(8), // SUBQ with an address reg as dest
|
||||
Instruction::SUB(src @ Target::Immediate(x), dest, size) if *x <= 8 => self.add_immediate_set(*size, dest, (4, 8), (8, 12)).add_target(*size, dest), // SUBQ
|
||||
Instruction::SUB(src @ Target::Immediate(_), dest, size) => self.add_immediate_set(*size, dest, (8, 16), (12, 20)).add_target(*size, dest), // SUBI
|
||||
|
||||
Instruction::SUB(src, dest, size) => self.add_standard_set(*size, dest, (0, 0), (4, 6), (8, 12)).add_two_targets(*size, src, dest),
|
||||
Instruction::SUBA(target, reg, size) => self.add_word_v_long(*size, 8, 6).add_target(*size, target),
|
||||
Instruction::SUBX(src, dest, size) => self.add_reg_mem_set(*size, dest, (4, 8), (18, 30)),
|
||||
|
||||
Instruction::SWAP(_) => self.add_internal(4),
|
||||
|
||||
Instruction::TAS(target) => self.add_reg_v_mem(target, 4, 14).add_target(Size::Byte, target),
|
||||
Instruction::TST(target, size) => self.add_internal(4).add_target(*size, target),
|
||||
Instruction::TRAP(_) => self.add_internal(34),
|
||||
Instruction::TRAPV => self.add_internal(34),
|
||||
|
||||
Instruction::UNLK(_) => self.add_internal(12),
|
||||
Instruction::UnimplementedA(_) => self.add_internal(34),
|
||||
Instruction::UnimplementedF(_) => self.add_internal(34),
|
||||
_ => {
|
||||
//panic!("Unexpected instruction for cpu type {:?}: {:?}", self.cputype, instruction);
|
||||
self.add_internal(4)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_instruction_68020(&mut self, instruction: &Instruction) -> &mut Self {
|
||||
match instruction {
|
||||
// TODO implement
|
||||
_ => self.add_internal(4),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn calculate_clocks(&self, branched: bool, reps: u16) -> u16 {
|
||||
//println!("{:?}", self);
|
||||
(self.accesses as u16 * 4)
|
||||
+ self.internal as u16
|
||||
+ (if branched { self.on_branch as u16 } else { 0 })
|
||||
+ self.per_rep as u16 * reps
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn access_size(&self, size: Size) -> u8 {
|
||||
if self.bus_size == Size::Word && size == Size::Long {
|
||||
2
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user