Added timing to m68k implementation

This commit is contained in:
transistor 2021-12-14 21:13:01 -08:00
parent 1b6cbfa831
commit e3819fe549
5 changed files with 449 additions and 4 deletions

View File

@ -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);
}

View File

@ -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};

View File

@ -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();
}

View File

@ -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
View 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
}
}
}