Modified to use a common trait to derive other traits

This commit is contained in:
transistor 2021-10-17 10:39:43 -07:00
parent 4bdbe7c7f0
commit 1262cbd8c0
11 changed files with 162 additions and 138 deletions

3
.gitignore vendored
View File

@ -2,3 +2,6 @@ Cargo.lock
.*.sw? .*.sw?
/target /target
*.vim *.vim
perf.data
perf.data.old

View File

@ -3,7 +3,7 @@ use std::fmt;
use crate::error::Error; use crate::error::Error;
use crate::system::System; use crate::system::System;
use crate::devices::{Address, Addressable, AddressableDeviceRefMut}; use crate::devices::{Address, Addressable};
use super::state::{M68kType, Exceptions}; use super::state::{M68kType, Exceptions};
@ -219,12 +219,12 @@ impl M68kDecoder {
pub fn decode_at(&mut self, system: &System, start: u32) -> Result<(), Error> { pub fn decode_at(&mut self, system: &System, start: u32) -> Result<(), Error> {
let (memory, relative_addr) = system.get_bus().get_device_at(start as Address, 12)?; let (memory, relative_addr) = system.get_bus().get_device_at(start as Address, 12)?;
self.init(start - relative_addr as u32, start); self.init(start - relative_addr as u32, start);
self.instruction = self.decode_one(&mut memory.borrow_mut())?; self.instruction = self.decode_one(memory.borrow_mut().as_addressable().unwrap())?;
Ok(()) Ok(())
} }
pub fn decode_one(&mut self, system: &mut AddressableDeviceRefMut<'_>) -> Result<Instruction, Error> { pub fn decode_one(&mut self, memory: &mut dyn Addressable) -> Result<Instruction, Error> {
let ins = self.read_instruction_word(system)?; let ins = self.read_instruction_word(memory)?;
match ((ins & 0xF000) >> 12) as u8 { match ((ins & 0xF000) >> 12) as u8 {
OPCG_BIT_OPS => { OPCG_BIT_OPS => {
@ -233,7 +233,7 @@ impl M68kDecoder {
if (ins & 0x3F) == 0b111100 { if (ins & 0x3F) == 0b111100 {
match (ins & 0x00C0) >> 6 { match (ins & 0x00C0) >> 6 {
0b00 => { 0b00 => {
let data = self.read_instruction_word(system)?; let data = self.read_instruction_word(memory)?;
match optype { match optype {
0b0000 => Ok(Instruction::ORtoCCR(data as u8)), 0b0000 => Ok(Instruction::ORtoCCR(data as u8)),
0b0001 => Ok(Instruction::ANDtoCCR(data as u8)), 0b0001 => Ok(Instruction::ANDtoCCR(data as u8)),
@ -242,7 +242,7 @@ impl M68kDecoder {
} }
}, },
0b01 => { 0b01 => {
let data = self.read_instruction_word(system)?; let data = self.read_instruction_word(memory)?;
match optype { match optype {
0b0000 => Ok(Instruction::ORtoSR(data)), 0b0000 => Ok(Instruction::ORtoSR(data)),
0b0010 => Ok(Instruction::ANDtoSR(data)), 0b0010 => Ok(Instruction::ANDtoSR(data)),
@ -257,16 +257,16 @@ impl M68kDecoder {
let areg = get_low_reg(ins); let areg = get_low_reg(ins);
let dir = if (ins & 0x0800) == 0 { Direction::FromTarget } else { Direction::ToTarget }; let dir = if (ins & 0x0800) == 0 { Direction::FromTarget } else { Direction::ToTarget };
let size = if (ins & 0x0040) == 0 { Size::Word } else { Size::Long }; let size = if (ins & 0x0040) == 0 { Size::Word } else { Size::Long };
let offset = sign_extend_to_long(self.read_instruction_word(system)? as u32, Size::Word); let offset = sign_extend_to_long(self.read_instruction_word(memory)? as u32, Size::Word);
Ok(Instruction::MOVEP(dreg, Target::IndirectARegOffset(areg, offset), size, dir)) Ok(Instruction::MOVEP(dreg, Target::IndirectARegOffset(areg, offset), size, dir))
} else if (ins & 0x0100) == 0x0100 || (ins & 0x0F00) == 0x0800 { } else if (ins & 0x0100) == 0x0100 || (ins & 0x0F00) == 0x0800 {
let bitnum = if (ins & 0x0100) == 0x0100 { let bitnum = if (ins & 0x0100) == 0x0100 {
Target::DirectDReg(get_high_reg(ins)) Target::DirectDReg(get_high_reg(ins))
} else { } else {
Target::Immediate(self.read_instruction_word(system)? as u32) Target::Immediate(self.read_instruction_word(memory)? as u32)
}; };
let target = self.decode_lower_effective_address(system, ins, Some(Size::Byte))?; let target = self.decode_lower_effective_address(memory, ins, Some(Size::Byte))?;
let size = match target { let size = match target {
Target::DirectAReg(_) | Target::DirectDReg(_) => Size::Long, Target::DirectAReg(_) | Target::DirectDReg(_) => Size::Long,
_ => Size::Byte, _ => Size::Byte,
@ -282,12 +282,12 @@ impl M68kDecoder {
} else { } else {
let size = get_size(ins); let size = get_size(ins);
let data = match size { let data = match size {
Some(Size::Byte) => (self.read_instruction_word(system)? as u32 & 0xFF), Some(Size::Byte) => (self.read_instruction_word(memory)? as u32 & 0xFF),
Some(Size::Word) => self.read_instruction_word(system)? as u32, Some(Size::Word) => self.read_instruction_word(memory)? as u32,
Some(Size::Long) => self.read_instruction_long(system)?, Some(Size::Long) => self.read_instruction_long(memory)?,
None => return Err(Error::processor(Exceptions::IllegalInstruction as u32)), None => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
}; };
let target = self.decode_lower_effective_address(system, ins, size)?; let target = self.decode_lower_effective_address(memory, ins, size)?;
match optype { match optype {
0b0000 => Ok(Instruction::OR(Target::Immediate(data), target, size.unwrap())), 0b0000 => Ok(Instruction::OR(Target::Immediate(data), target, size.unwrap())),
@ -301,13 +301,13 @@ impl M68kDecoder {
} }
}, },
OPCG_MOVE_BYTE => { OPCG_MOVE_BYTE => {
let src = self.decode_lower_effective_address(system, ins, Some(Size::Byte))?; let src = self.decode_lower_effective_address(memory, ins, Some(Size::Byte))?;
let dest = self.decode_upper_effective_address(system, ins, Some(Size::Byte))?; let dest = self.decode_upper_effective_address(memory, ins, Some(Size::Byte))?;
Ok(Instruction::MOVE(src, dest, Size::Byte)) Ok(Instruction::MOVE(src, dest, Size::Byte))
}, },
OPCG_MOVE_LONG => { OPCG_MOVE_LONG => {
let src = self.decode_lower_effective_address(system, ins, Some(Size::Long))?; let src = self.decode_lower_effective_address(memory, ins, Some(Size::Long))?;
let dest = self.decode_upper_effective_address(system, ins, Some(Size::Long))?; let dest = self.decode_upper_effective_address(memory, ins, Some(Size::Long))?;
if let Target::DirectAReg(reg) = dest { if let Target::DirectAReg(reg) = dest {
Ok(Instruction::MOVEA(src, reg, Size::Long)) Ok(Instruction::MOVEA(src, reg, Size::Long))
} else { } else {
@ -315,8 +315,8 @@ impl M68kDecoder {
} }
}, },
OPCG_MOVE_WORD => { OPCG_MOVE_WORD => {
let src = self.decode_lower_effective_address(system, ins, Some(Size::Word))?; let src = self.decode_lower_effective_address(memory, ins, Some(Size::Word))?;
let dest = self.decode_upper_effective_address(system, ins, Some(Size::Word))?; let dest = self.decode_upper_effective_address(memory, ins, Some(Size::Word))?;
if let Target::DirectAReg(reg) = dest { if let Target::DirectAReg(reg) = dest {
Ok(Instruction::MOVEA(src, reg, Size::Word)) Ok(Instruction::MOVEA(src, reg, Size::Word))
} else { } else {
@ -336,10 +336,10 @@ impl M68kDecoder {
}; };
let reg = get_high_reg(ins); let reg = get_high_reg(ins);
let target = self.decode_lower_effective_address(system, ins, Some(size))?; let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
Ok(Instruction::CHK(target, reg, size)) Ok(Instruction::CHK(target, reg, size))
} else { } else {
let src = self.decode_lower_effective_address(system, ins, None)?; let src = self.decode_lower_effective_address(memory, ins, None)?;
let dest = get_high_reg(ins); let dest = get_high_reg(ins);
Ok(Instruction::LEA(src, dest)) Ok(Instruction::LEA(src, dest))
} }
@ -347,12 +347,12 @@ impl M68kDecoder {
let mode = get_low_mode(ins); let mode = get_low_mode(ins);
let size = if (ins & 0x0040) == 0 { Size::Word } else { Size::Long }; let size = if (ins & 0x0040) == 0 { Size::Word } else { Size::Long };
let data = self.read_instruction_word(system)?; let data = self.read_instruction_word(memory)?;
let target = self.decode_lower_effective_address(system, ins, None)?; let target = self.decode_lower_effective_address(memory, ins, None)?;
let dir = if (ins & 0x0400) == 0 { Direction::ToTarget } else { Direction::FromTarget }; let dir = if (ins & 0x0400) == 0 { Direction::ToTarget } else { Direction::FromTarget };
Ok(Instruction::MOVEM(target, size, dir, data)) Ok(Instruction::MOVEM(target, size, dir, data))
} else if (ins & 0x800) == 0 { } else if (ins & 0x800) == 0 {
let target = self.decode_lower_effective_address(system, ins, Some(Size::Word))?; let target = self.decode_lower_effective_address(memory, ins, Some(Size::Word))?;
match (ins & 0x0700) >> 8 { match (ins & 0x0700) >> 8 {
0b000 => { 0b000 => {
match get_size(ins) { match get_size(ins) {
@ -386,7 +386,7 @@ impl M68kDecoder {
let mode = get_low_mode(ins); let mode = get_low_mode(ins);
match (subselect, mode) { match (subselect, mode) {
(0b000, _) => { (0b000, _) => {
let target = self.decode_lower_effective_address(system, ins, Some(Size::Byte))?; let target = self.decode_lower_effective_address(memory, ins, Some(Size::Byte))?;
Ok(Instruction::NBCD(target)) Ok(Instruction::NBCD(target))
}, },
(0b001, 0b000) => { (0b001, 0b000) => {
@ -396,7 +396,7 @@ impl M68kDecoder {
Ok(Instruction::BKPT(get_low_reg(ins))) Ok(Instruction::BKPT(get_low_reg(ins)))
}, },
(0b001, _) => { (0b001, _) => {
let target = self.decode_lower_effective_address(system, ins, None)?; let target = self.decode_lower_effective_address(memory, ins, None)?;
Ok(Instruction::PEA(target)) Ok(Instruction::PEA(target))
}, },
(0b010, 0b000) => { (0b010, 0b000) => {
@ -414,7 +414,7 @@ impl M68kDecoder {
if (ins & 0x0FF) == 0xFC { if (ins & 0x0FF) == 0xFC {
Ok(Instruction::ILLEGAL) Ok(Instruction::ILLEGAL)
} else { } else {
let target = self.decode_lower_effective_address(system, ins, Some(Size::Word))?; let target = self.decode_lower_effective_address(memory, ins, Some(Size::Word))?;
match get_size(ins) { match get_size(ins) {
Some(size) => Ok(Instruction::TST(target, size)), Some(size) => Ok(Instruction::TST(target, size)),
None => Ok(Instruction::TAS(target)), None => Ok(Instruction::TAS(target)),
@ -422,7 +422,7 @@ impl M68kDecoder {
} }
} else if ins_0f00 == 0xE00 { } else if ins_0f00 == 0xE00 {
if (ins & 0x80) == 0x80 { if (ins & 0x80) == 0x80 {
let target = self.decode_lower_effective_address(system, ins, None)?; let target = self.decode_lower_effective_address(memory, ins, None)?;
if (ins & 0b01000000) == 0 { if (ins & 0b01000000) == 0 {
Ok(Instruction::JSR(target)) Ok(Instruction::JSR(target))
} else { } else {
@ -433,7 +433,7 @@ impl M68kDecoder {
} else if ins_00f0 == 0x50 { } else if ins_00f0 == 0x50 {
let reg = get_low_reg(ins); let reg = get_low_reg(ins);
if (ins & 0b1000) == 0 { if (ins & 0b1000) == 0 {
let data = self.read_instruction_word(system)?; let data = self.read_instruction_word(memory)?;
Ok(Instruction::LINK(reg, data as i16)) Ok(Instruction::LINK(reg, data as i16))
} else { } else {
Ok(Instruction::UNLK(reg)) Ok(Instruction::UNLK(reg))
@ -447,12 +447,12 @@ impl M68kDecoder {
0x70 => Ok(Instruction::RESET), 0x70 => Ok(Instruction::RESET),
0x71 => Ok(Instruction::NOP), 0x71 => Ok(Instruction::NOP),
0x72 => { 0x72 => {
let data = self.read_instruction_word(system)?; let data = self.read_instruction_word(memory)?;
Ok(Instruction::STOP(data)) Ok(Instruction::STOP(data))
}, },
0x73 => Ok(Instruction::RTE), 0x73 => Ok(Instruction::RTE),
0x74 if self.cputype >= M68kType::MC68010 => { 0x74 if self.cputype >= M68kType::MC68010 => {
let offset = self.read_instruction_word(system)? as i16; let offset = self.read_instruction_word(memory)? as i16;
Ok(Instruction::RTD(offset)) Ok(Instruction::RTD(offset))
}, },
0x75 => Ok(Instruction::RTS), 0x75 => Ok(Instruction::RTS),
@ -460,7 +460,7 @@ impl M68kDecoder {
0x77 => Ok(Instruction::RTR), 0x77 => Ok(Instruction::RTR),
0x7A | 0x7B if self.cputype >= M68kType::MC68010 => { 0x7A | 0x7B if self.cputype >= M68kType::MC68010 => {
let dir = if ins & 0x01 == 0 { Direction::ToTarget } else { Direction::FromTarget }; let dir = if ins & 0x01 == 0 { Direction::ToTarget } else { Direction::FromTarget };
let ins2 = self.read_instruction_word(system)?; let ins2 = self.read_instruction_word(memory)?;
let target = match ins2 & 0x8000 { let target = match ins2 & 0x8000 {
0 => Target::DirectDReg(((ins2 & 0x7000) >> 12) as u8), 0 => Target::DirectDReg(((ins2 & 0x7000) >> 12) as u8),
_ => Target::DirectAReg(((ins2 & 0x7000) >> 12) as u8), _ => Target::DirectAReg(((ins2 & 0x7000) >> 12) as u8),
@ -481,7 +481,7 @@ impl M68kDecoder {
OPCG_ADDQ_SUBQ => { OPCG_ADDQ_SUBQ => {
match get_size(ins) { match get_size(ins) {
Some(size) => { Some(size) => {
let target = self.decode_lower_effective_address(system, ins, Some(size))?; let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
let mut data = ((ins & 0x0E00) >> 9) as u32; let mut data = ((ins & 0x0E00) >> 9) as u32;
if data == 0 { if data == 0 {
data = 8; data = 8;
@ -499,10 +499,10 @@ impl M68kDecoder {
if mode == 0b001 { if mode == 0b001 {
let reg = get_low_reg(ins); let reg = get_low_reg(ins);
let disp = self.read_instruction_word(system)? as i16; let disp = self.read_instruction_word(memory)? as i16;
Ok(Instruction::DBcc(condition, reg, disp)) Ok(Instruction::DBcc(condition, reg, disp))
} else { } else {
let target = self.decode_lower_effective_address(system, ins, Some(Size::Byte))?; let target = self.decode_lower_effective_address(memory, ins, Some(Size::Byte))?;
Ok(Instruction::Scc(condition, target)) Ok(Instruction::Scc(condition, target))
} }
}, },
@ -511,9 +511,9 @@ impl M68kDecoder {
OPCG_BRANCH => { OPCG_BRANCH => {
let mut disp = ((ins & 0xFF) as i8) as i32; let mut disp = ((ins & 0xFF) as i8) as i32;
if disp == 0 { if disp == 0 {
disp = (self.read_instruction_word(system)? as i16) as i32; disp = (self.read_instruction_word(memory)? as i16) as i32;
} else if disp == -1 && self.cputype >= M68kType::MC68020 { } else if disp == -1 && self.cputype >= M68kType::MC68020 {
disp = self.read_instruction_long(system)? as i32; disp = self.read_instruction_long(memory)? as i32;
} }
let condition = get_condition(ins); let condition = get_condition(ins);
match condition { match condition {
@ -536,7 +536,7 @@ impl M68kDecoder {
if size.is_none() { if size.is_none() {
let sign = if (ins & 0x0100) == 0 { Sign::Unsigned } else { Sign::Signed }; let sign = if (ins & 0x0100) == 0 { Sign::Unsigned } else { Sign::Signed };
let data_reg = Target::DirectDReg(get_high_reg(ins)); let data_reg = Target::DirectDReg(get_high_reg(ins));
let effective_addr = self.decode_lower_effective_address(system, ins, size)?; let effective_addr = self.decode_lower_effective_address(memory, ins, size)?;
Ok(Instruction::DIV(effective_addr, data_reg, Size::Word, sign)) Ok(Instruction::DIV(effective_addr, data_reg, Size::Word, sign))
} else if (ins & 0x1F0) == 0x100 { } else if (ins & 0x1F0) == 0x100 {
let regx = get_high_reg(ins); let regx = get_high_reg(ins);
@ -548,7 +548,7 @@ impl M68kDecoder {
} }
} else { } else {
let data_reg = Target::DirectDReg(get_high_reg(ins)); let data_reg = Target::DirectDReg(get_high_reg(ins));
let effective_addr = self.decode_lower_effective_address(system, ins, size)?; let effective_addr = self.decode_lower_effective_address(memory, ins, size)?;
let (from, to) = if (ins & 0x0100) == 0 { (effective_addr, data_reg) } else { (data_reg, effective_addr) }; let (from, to) = if (ins & 0x0100) == 0 { (effective_addr, data_reg) } else { (data_reg, effective_addr) };
Ok(Instruction::OR(from, to, size.unwrap())) Ok(Instruction::OR(from, to, size.unwrap()))
} }
@ -565,7 +565,7 @@ impl M68kDecoder {
// TODO implement SUBX // TODO implement SUBX
panic!("Not Implemented"); panic!("Not Implemented");
} else { } else {
let target = self.decode_lower_effective_address(system, ins, Some(size))?; let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
if dir == 0 { if dir == 0 {
Ok(Instruction::SUB(target, Target::DirectDReg(reg), size)) Ok(Instruction::SUB(target, Target::DirectDReg(reg), size))
} else { } else {
@ -575,7 +575,7 @@ impl M68kDecoder {
}, },
None => { None => {
let size = if dir == 0 { Size::Word } else { Size::Long }; let size = if dir == 0 { Size::Word } else { Size::Long };
let target = self.decode_lower_effective_address(system, ins, Some(size))?; let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
Ok(Instruction::SUB(target, Target::DirectAReg(reg), size)) Ok(Instruction::SUB(target, Target::DirectAReg(reg), size))
}, },
} }
@ -589,17 +589,17 @@ impl M68kDecoder {
if get_low_mode(ins) == 0b001 { if get_low_mode(ins) == 0b001 {
Ok(Instruction::CMP(Target::IndirectARegInc(get_low_reg(ins)), Target::IndirectARegInc(reg), size)) Ok(Instruction::CMP(Target::IndirectARegInc(get_low_reg(ins)), Target::IndirectARegInc(reg), size))
} else { } else {
let target = self.decode_lower_effective_address(system, ins, Some(size))?; let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
Ok(Instruction::EOR(Target::DirectDReg(reg), target, size)) Ok(Instruction::EOR(Target::DirectDReg(reg), target, size))
} }
}, },
(0b0, Some(size)) => { (0b0, Some(size)) => {
let target = self.decode_lower_effective_address(system, ins, Some(size))?; let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
Ok(Instruction::CMP(target, Target::DirectDReg(reg), size)) Ok(Instruction::CMP(target, Target::DirectDReg(reg), size))
}, },
(_, None) => { (_, None) => {
let size = if optype == 0 { Size::Word } else { Size::Long }; let size = if optype == 0 { Size::Word } else { Size::Long };
let target = self.decode_lower_effective_address(system, ins, Some(size))?; let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
Ok(Instruction::CMPA(target, reg, size)) Ok(Instruction::CMPA(target, reg, size))
}, },
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)), _ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
@ -628,11 +628,11 @@ impl M68kDecoder {
} else if size.is_none() { } else if size.is_none() {
let sign = if (ins & 0x0100) == 0 { Sign::Unsigned } else { Sign::Signed }; let sign = if (ins & 0x0100) == 0 { Sign::Unsigned } else { Sign::Signed };
let data_reg = Target::DirectDReg(get_high_reg(ins)); let data_reg = Target::DirectDReg(get_high_reg(ins));
let effective_addr = self.decode_lower_effective_address(system, ins, Some(Size::Word))?; let effective_addr = self.decode_lower_effective_address(memory, ins, Some(Size::Word))?;
Ok(Instruction::MUL(effective_addr, data_reg, Size::Word, sign)) Ok(Instruction::MUL(effective_addr, data_reg, Size::Word, sign))
} else { } else {
let data_reg = Target::DirectDReg(get_high_reg(ins)); let data_reg = Target::DirectDReg(get_high_reg(ins));
let effective_addr = self.decode_lower_effective_address(system, ins, size)?; let effective_addr = self.decode_lower_effective_address(memory, ins, size)?;
let (from, to) = if (ins & 0x0100) == 0 { (effective_addr, data_reg) } else { (data_reg, effective_addr) }; let (from, to) = if (ins & 0x0100) == 0 { (effective_addr, data_reg) } else { (data_reg, effective_addr) };
Ok(Instruction::AND(from, to, size.unwrap())) Ok(Instruction::AND(from, to, size.unwrap()))
} }
@ -649,7 +649,7 @@ impl M68kDecoder {
// TODO implement ADDX // TODO implement ADDX
panic!("Not Implemented"); panic!("Not Implemented");
} else { } else {
let target = self.decode_lower_effective_address(system, ins, Some(size))?; let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
if dir == 0 { if dir == 0 {
Ok(Instruction::ADD(target, Target::DirectDReg(reg), size)) Ok(Instruction::ADD(target, Target::DirectDReg(reg), size))
} else { } else {
@ -659,7 +659,7 @@ impl M68kDecoder {
}, },
None => { None => {
let size = if dir == 0 { Size::Word } else { Size::Long }; let size = if dir == 0 { Size::Word } else { Size::Long };
let target = self.decode_lower_effective_address(system, ins, Some(size))?; let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
Ok(Instruction::ADD(target, Target::DirectAReg(reg), size)) Ok(Instruction::ADD(target, Target::DirectAReg(reg), size))
}, },
} }
@ -685,7 +685,7 @@ impl M68kDecoder {
} }
}, },
None => { None => {
let target = self.decode_lower_effective_address(system, ins, Some(Size::Word))?; let target = self.decode_lower_effective_address(memory, ins, Some(Size::Word))?;
let count = Target::Immediate(1); let count = Target::Immediate(1);
match (ins & 0x0600) >> 9 { match (ins & 0x0600) >> 9 {
@ -702,32 +702,32 @@ impl M68kDecoder {
} }
} }
fn read_instruction_word(&mut self, device: &mut AddressableDeviceRefMut<'_>) -> Result<u16, Error> { fn read_instruction_word(&mut self, device: &mut dyn Addressable) -> Result<u16, Error> {
let word = device.read_beu16((self.end - self.base) as Address)?; let word = device.read_beu16((self.end - self.base) as Address)?;
self.end += 2; self.end += 2;
Ok(word) Ok(word)
} }
fn read_instruction_long(&mut self, device: &mut AddressableDeviceRefMut<'_>) -> Result<u32, Error> { fn read_instruction_long(&mut self, device: &mut dyn Addressable) -> Result<u32, Error> {
let word = device.read_beu32((self.end - self.base) as Address)?; let word = device.read_beu32((self.end - self.base) as Address)?;
self.end += 4; self.end += 4;
Ok(word) Ok(word)
} }
fn decode_lower_effective_address(&mut self, system: &mut AddressableDeviceRefMut<'_>, ins: u16, size: Option<Size>) -> Result<Target, Error> { fn decode_lower_effective_address(&mut self, memory: &mut dyn Addressable, ins: u16, size: Option<Size>) -> Result<Target, Error> {
let reg = get_low_reg(ins); let reg = get_low_reg(ins);
let mode = get_low_mode(ins); let mode = get_low_mode(ins);
self.get_mode_as_target(system, mode, reg, size) self.get_mode_as_target(memory, mode, reg, size)
} }
fn decode_upper_effective_address(&mut self, system: &mut AddressableDeviceRefMut<'_>, ins: u16, size: Option<Size>) -> Result<Target, Error> { fn decode_upper_effective_address(&mut self, memory: &mut dyn Addressable, ins: u16, size: Option<Size>) -> Result<Target, Error> {
let reg = get_high_reg(ins); let reg = get_high_reg(ins);
let mode = get_high_mode(ins); let mode = get_high_mode(ins);
self.get_mode_as_target(system, mode, reg, size) self.get_mode_as_target(memory, mode, reg, size)
} }
fn decode_extension_word(&mut self, system: &mut AddressableDeviceRefMut<'_>, areg: Option<u8>) -> Result<Target, Error> { fn decode_extension_word(&mut self, memory: &mut dyn Addressable, areg: Option<u8>) -> Result<Target, Error> {
let brief_extension = self.read_instruction_word(system)?; let brief_extension = self.read_instruction_word(memory)?;
let xreg_num = ((brief_extension & 0x7000) >> 12) as u8; let xreg_num = ((brief_extension & 0x7000) >> 12) as u8;
let xreg = if (brief_extension & 0x8000) == 0 { XRegister::Data(xreg_num) } else { XRegister::Address(xreg_num) }; let xreg = if (brief_extension & 0x8000) == 0 { XRegister::Data(xreg_num) } else { XRegister::Address(xreg_num) };
let size = if (brief_extension & 0x0800) == 0 { Size::Word } else { Size::Long }; let size = if (brief_extension & 0x0800) == 0 { Size::Word } else { Size::Long };
@ -750,7 +750,7 @@ impl M68kDecoder {
} }
} }
pub fn get_mode_as_target(&mut self, system: &mut AddressableDeviceRefMut<'_>, mode: u8, reg: u8, size: Option<Size>) -> Result<Target, Error> { pub fn get_mode_as_target(&mut self, memory: &mut dyn Addressable, mode: u8, reg: u8, size: Option<Size>) -> Result<Target, Error> {
let value = match mode { let value = match mode {
0b000 => Target::DirectDReg(reg), 0b000 => Target::DirectDReg(reg),
0b001 => Target::DirectAReg(reg), 0b001 => Target::DirectAReg(reg),
@ -758,33 +758,33 @@ impl M68kDecoder {
0b011 => Target::IndirectARegInc(reg), 0b011 => Target::IndirectARegInc(reg),
0b100 => Target::IndirectARegDec(reg), 0b100 => Target::IndirectARegDec(reg),
0b101 => { 0b101 => {
let data = sign_extend_to_long(self.read_instruction_word(system)? as u32, Size::Word); let data = sign_extend_to_long(self.read_instruction_word(memory)? as u32, Size::Word);
Target::IndirectARegOffset(reg, data) Target::IndirectARegOffset(reg, data)
}, },
0b110 => { 0b110 => {
self.decode_extension_word(system, Some(reg))? self.decode_extension_word(memory, Some(reg))?
}, },
0b111 => { 0b111 => {
match reg { match reg {
0b000 => { 0b000 => {
let value = sign_extend_to_long(self.read_instruction_word(system)? as u32, Size::Word) as u32; let value = sign_extend_to_long(self.read_instruction_word(memory)? as u32, Size::Word) as u32;
Target::IndirectMemory(value) Target::IndirectMemory(value)
}, },
0b001 => { 0b001 => {
let value = self.read_instruction_long(system)?; let value = self.read_instruction_long(memory)?;
Target::IndirectMemory(value) Target::IndirectMemory(value)
}, },
0b010 => { 0b010 => {
let data = sign_extend_to_long(self.read_instruction_word(system)? as u32, Size::Word); let data = sign_extend_to_long(self.read_instruction_word(memory)? as u32, Size::Word);
Target::IndirectPCOffset(data) Target::IndirectPCOffset(data)
}, },
0b011 => { 0b011 => {
self.decode_extension_word(system, None)? self.decode_extension_word(memory, None)?
}, },
0b100 => { 0b100 => {
let data = match size { let data = match size {
Some(Size::Byte) | Some(Size::Word) => self.read_instruction_word(system)? as u32, Some(Size::Byte) | Some(Size::Word) => self.read_instruction_word(memory)? as u32,
Some(Size::Long) => self.read_instruction_long(system)?, Some(Size::Long) => self.read_instruction_long(memory)?,
None => return Err(Error::processor(Exceptions::IllegalInstruction as u32)), None => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
}; };
Target::Immediate(data) Target::Immediate(data)

View File

@ -1,7 +1,7 @@
use crate::system::System; use crate::system::System;
use crate::error::{ErrorType, Error}; use crate::error::{ErrorType, Error};
use crate::devices::{Clock, Address, Steppable, Interruptable, Addressable}; use crate::devices::{Clock, Address, Steppable, Interruptable, Addressable, Transmutable};
use super::decode::{ use super::decode::{
Instruction, Instruction,
@ -20,6 +20,7 @@ const DEV_NAME: &'static str = "m68k-cpu";
use super::state::{M68k, Status, Flags, Exceptions, InterruptPriority}; use super::state::{M68k, Status, Flags, Exceptions, InterruptPriority};
impl Steppable for M68k { impl Steppable for M68k {
fn step(&mut self, system: &System) -> Result<Clock, Error> { fn step(&mut self, system: &System) -> Result<Clock, Error> {
self.step_internal(system)?; self.step_internal(system)?;
@ -53,6 +54,17 @@ impl Interruptable for M68k {
} }
} }
impl Transmutable for M68k {
fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
Some(self)
}
fn as_interruptable(&mut self) -> Option<&mut dyn Interruptable> {
Some(self)
}
}
impl M68k { impl M68k {
#[allow(dead_code)] #[allow(dead_code)]
pub fn is_running(&self) -> bool { pub fn is_running(&self) -> bool {

View File

@ -11,6 +11,7 @@ pub const MAX_READ: usize = 4;
pub type Clock = u64; pub type Clock = u64;
pub type Address = u64; pub type Address = u64;
/// A device that can change state over time. The `step()` method will be called /// A device that can change state over time. The `step()` method will be called
/// by the containing `System` when the system clock advances. If an error occurs /// by the containing `System` when the system clock advances. If an error occurs
/// with any device, the `on_error()` method will be called to display any state /// with any device, the `on_error()` method will be called to display any state
@ -21,12 +22,14 @@ pub trait Steppable {
fn on_debug(&mut self) { } fn on_debug(&mut self) { }
} }
/// A device that can receive an interrupt. The `interrupt_state_change()` method /// A device that can receive an interrupt. The `interrupt_state_change()` method
/// will be called whenever an interrupt signal changes goes high or low. /// will be called whenever an interrupt signal changes goes high or low.
pub trait Interruptable { pub trait Interruptable {
fn interrupt_state_change(&mut self, state: bool, priority: u8, number: u8) -> Result<(), Error>; fn interrupt_state_change(&mut self, state: bool, priority: u8, number: u8) -> Result<(), Error>;
} }
/// A device that can be addressed to read data from or write data to the device. /// A device that can be addressed to read data from or write data to the device.
pub trait Addressable { pub trait Addressable {
fn len(&self) -> usize; fn len(&self) -> usize;
@ -61,34 +64,6 @@ pub trait Addressable {
} }
} }
pub trait AddressableDevice: Addressable + Steppable { }
pub trait InterruptableDevice: Interruptable + Steppable { }
pub type AddressableDeviceBox = Rc<RefCell<Box<dyn AddressableDevice>>>;
pub type InterruptableDeviceBox = Rc<RefCell<Box<dyn InterruptableDevice>>>;
pub type AddressableDeviceRefMut<'a> = RefMut<'a, Box<dyn AddressableDevice>>;
impl<T: Addressable + Steppable> AddressableDevice for T { }
impl<T: Interruptable + Steppable> InterruptableDevice for T { }
pub fn wrap_addressable<T: AddressableDevice + 'static>(value: T) -> AddressableDeviceBox {
Rc::new(RefCell::new(Box::new(value)))
}
pub fn wrap_interruptable<T: InterruptableDevice + 'static>(value: T) -> InterruptableDeviceBox {
Rc::new(RefCell::new(Box::new(value)))
}
pub enum Device {
Addressable(AddressableDeviceBox),
Interruptable(InterruptableDeviceBox),
}
#[inline(always)] #[inline(always)]
pub fn read_beu16(data: &[u8]) -> u16 { pub fn read_beu16(data: &[u8]) -> u16 {
(data[0] as u16) << 8 | (data[0] as u16) << 8 |
@ -121,3 +96,23 @@ pub fn write_beu32(value: u32) -> [u8; 4] {
] ]
} }
pub trait Transmutable {
fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
None
}
fn as_addressable(&mut self) -> Option<&mut dyn Addressable> {
None
}
fn as_interruptable(&mut self) -> Option<&mut dyn Interruptable> {
None
}
}
pub type TransmutableBox = Rc<RefCell<Box<dyn Transmutable>>>;
pub fn wrap_transmutable<T: Transmutable + 'static>(value: T) -> TransmutableBox {
Rc::new(RefCell::new(Box::new(value)))
}

View File

@ -2,7 +2,7 @@
use std::iter; use std::iter;
use crate::error::Error; use crate::error::Error;
use crate::devices::{InterruptableDeviceBox}; use crate::devices::TransmutableBox;
pub struct Signal { pub struct Signal {
@ -35,7 +35,7 @@ impl Signal {
pub struct InterruptController { pub struct InterruptController {
pub target: Option<InterruptableDeviceBox>, pub target: Option<TransmutableBox>,
pub priority: Vec<Signal>, pub priority: Vec<Signal>,
} }
@ -47,7 +47,7 @@ impl InterruptController {
} }
} }
pub fn set_target(&mut self, dev: InterruptableDeviceBox) -> Result<(), Error> { pub fn set_target(&mut self, dev: TransmutableBox) -> Result<(), Error> {
if self.target.is_some() { if self.target.is_some() {
return Err(Error::new("Interruptable device already set, and interrupt controller only supports one receiver")); return Err(Error::new("Interruptable device already set, and interrupt controller only supports one receiver"));
} }
@ -73,7 +73,7 @@ impl InterruptController {
debug!("interrupts: priority {} state changed to {}", priority, state); debug!("interrupts: priority {} state changed to {}", priority, state);
match &self.target { match &self.target {
Some(dev) => { Some(dev) => {
Ok(dev.borrow_mut().interrupt_state_change(state, priority, number)?) Ok(dev.borrow_mut().as_interruptable().unwrap().interrupt_state_change(state, priority, number)?)
}, },
None => { None => {
Err(Error::new(&format!("unhandled interrupt: {:x}", number))) Err(Error::new(&format!("unhandled interrupt: {:x}", number)))

View File

@ -16,7 +16,7 @@ use crate::memory::MemoryBlock;
use crate::peripherals::ata::AtaDevice; use crate::peripherals::ata::AtaDevice;
use crate::cpus::m68k::{M68k, M68kType}; use crate::cpus::m68k::{M68k, M68kType};
use crate::peripherals::mc68681::MC68681; use crate::peripherals::mc68681::MC68681;
use crate::devices::{wrap_addressable, wrap_interruptable}; use crate::devices::wrap_transmutable;
fn main() { fn main() {
let mut system = System::new(); let mut system = System::new();
@ -25,20 +25,20 @@ fn main() {
for byte in monitor.contents.iter() { for byte in monitor.contents.iter() {
print!("{:02x} ", byte); print!("{:02x} ", byte);
} }
system.add_addressable_device(0x00000000, wrap_addressable(monitor)).unwrap(); system.add_addressable_device(0x00000000, wrap_transmutable(monitor)).unwrap();
let mut ram = MemoryBlock::new(vec![0; 0x00100000]); let mut ram = MemoryBlock::new(vec![0; 0x00100000]);
ram.load_at(0, "binaries/kernel.bin").unwrap(); ram.load_at(0, "binaries/kernel.bin").unwrap();
system.add_addressable_device(0x00100000, wrap_addressable(ram)).unwrap(); system.add_addressable_device(0x00100000, wrap_transmutable(ram)).unwrap();
let mut ata = AtaDevice::new(); let mut ata = AtaDevice::new();
ata.load("binaries/disk-with-partition-table.img").unwrap(); ata.load("binaries/disk-with-partition-table.img").unwrap();
system.add_addressable_device(0x00600000, wrap_addressable(ata)).unwrap(); system.add_addressable_device(0x00600000, wrap_transmutable(ata)).unwrap();
let mut serial = MC68681::new(); let mut serial = MC68681::new();
launch_terminal_emulator(serial.port_a.open().unwrap()); launch_terminal_emulator(serial.port_a.open().unwrap());
launch_slip_connection(serial.port_b.open().unwrap()); //launch_slip_connection(serial.port_b.open().unwrap());
system.add_addressable_device(0x00700000, wrap_addressable(serial)).unwrap(); system.add_addressable_device(0x00700000, wrap_transmutable(serial)).unwrap();
let mut cpu = M68k::new(M68kType::MC68010); let mut cpu = M68k::new(M68kType::MC68010);
@ -52,7 +52,7 @@ fn main() {
//cpu.decoder.dump_disassembly(&mut system, 0x100000, 0x2000); //cpu.decoder.dump_disassembly(&mut system, 0x100000, 0x2000);
//cpu.decoder.dump_disassembly(&mut system, 0x2ac, 0x200); //cpu.decoder.dump_disassembly(&mut system, 0x2ac, 0x200);
system.add_interruptable_device(wrap_interruptable(cpu)).unwrap(); system.add_interruptable_device(wrap_transmutable(cpu)).unwrap();
loop { loop {
match system.step() { match system.step() {
Ok(()) => { }, Ok(()) => { },

View File

@ -3,7 +3,7 @@ use std::fs;
use crate::error::Error; use crate::error::Error;
use crate::system::System; use crate::system::System;
use crate::devices::{Clock, Address, Steppable, Addressable, AddressableDeviceBox, MAX_READ}; use crate::devices::{Clock, Address, Steppable, Addressable, Transmutable, TransmutableBox, MAX_READ};
pub struct MemoryBlock { pub struct MemoryBlock {
@ -61,17 +61,18 @@ impl Addressable for MemoryBlock {
} }
} }
impl Steppable for MemoryBlock { impl Transmutable for MemoryBlock {
fn step(&mut self, _system: &System) -> Result<Clock, Error> { fn as_addressable(&mut self) -> Option<&mut dyn Addressable> {
Ok(1) Some(self)
} }
} }
pub struct Block { pub struct Block {
pub base: Address, pub base: Address,
pub length: usize, pub length: usize,
pub dev: AddressableDeviceBox, pub dev: TransmutableBox,
} }
pub struct Bus { pub struct Bus {
@ -85,7 +86,7 @@ impl Bus {
} }
} }
pub fn insert(&mut self, base: Address, length: usize, dev: AddressableDeviceBox) { pub fn insert(&mut self, base: Address, length: usize, dev: TransmutableBox) {
let block = Block { base, length, dev }; let block = Block { base, length, dev };
for i in 0..self.blocks.len() { for i in 0..self.blocks.len() {
if self.blocks[i].base > block.base { if self.blocks[i].base > block.base {
@ -96,7 +97,7 @@ impl Bus {
self.blocks.insert(0, block); self.blocks.insert(0, block);
} }
pub fn get_device_at(&self, addr: Address, count: usize) -> Result<(AddressableDeviceBox, Address), Error> { pub fn get_device_at(&self, addr: Address, count: usize) -> Result<(TransmutableBox, Address), Error> {
for block in &self.blocks { for block in &self.blocks {
if addr >= block.base && addr <= (block.base + block.length as Address) { if addr >= block.base && addr <= (block.base + block.length as Address) {
let relative_addr = addr - block.base; let relative_addr = addr - block.base;
@ -138,13 +139,13 @@ impl Addressable for Bus {
fn read(&mut self, addr: Address, count: usize) -> Result<[u8; MAX_READ], Error> { fn read(&mut self, addr: Address, count: usize) -> Result<[u8; MAX_READ], Error> {
let (dev, relative_addr) = self.get_device_at(addr, count)?; let (dev, relative_addr) = self.get_device_at(addr, count)?;
let result = dev.borrow_mut().read(relative_addr, count); let result = dev.borrow_mut().as_addressable().unwrap().read(relative_addr, count);
result result
} }
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> {
let (dev, relative_addr) = self.get_device_at(addr, data.len())?; let (dev, relative_addr) = self.get_device_at(addr, data.len())?;
let result = dev.borrow_mut().write(relative_addr, data); let result = dev.borrow_mut().as_addressable().unwrap().write(relative_addr, data);
result result
} }
} }

View File

@ -3,7 +3,7 @@ use std::fs;
use crate::error::Error; use crate::error::Error;
use crate::system::System; use crate::system::System;
use crate::devices::{Clock, Address, Steppable, Addressable, MAX_READ}; use crate::devices::{Clock, Address, Addressable, Transmutable, MAX_READ};
const ATA_REG_DATA_WORD: Address = 0x20; const ATA_REG_DATA_WORD: Address = 0x20;
@ -132,9 +132,9 @@ impl Addressable for AtaDevice {
} }
} }
impl Steppable for AtaDevice { impl Transmutable for AtaDevice {
fn step(&mut self, _system: &System) -> Result<Clock, Error> { fn as_addressable(&mut self) -> Option<&mut dyn Addressable> {
Ok(1) Some(self)
} }
} }

View File

@ -1,7 +1,7 @@
use crate::error::Error; use crate::error::Error;
use crate::system::System; use crate::system::System;
use crate::devices::{Clock, Address, Steppable, Addressable, MAX_READ}; use crate::devices::{Clock, Address, Steppable, Addressable, Transmutable, MAX_READ};
use crate::host::ttys::{SimplePty, SharedSimplePty}; use crate::host::ttys::{SimplePty, SharedSimplePty};
@ -379,3 +379,12 @@ impl Steppable for MC68681 {
} }
} }
impl Transmutable for MC68681 {
fn as_addressable(&mut self) -> Option<&mut dyn Addressable> {
Some(self)
}
fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
Some(self)
}
}

View File

@ -4,12 +4,12 @@ use std::cell::{RefCell, RefMut};
use crate::error::Error; use crate::error::Error;
use crate::memory::Bus; use crate::memory::Bus;
use crate::interrupts::InterruptController; use crate::interrupts::InterruptController;
use crate::devices::{Address, Device, AddressableDeviceBox, InterruptableDeviceBox, Clock}; use crate::devices::{Clock, Address, Transmutable, TransmutableBox};
pub struct System { pub struct System {
pub clock: Clock, pub clock: Clock,
pub devices: Vec<Device>, pub devices: Vec<TransmutableBox>,
pub bus: RefCell<Bus>, pub bus: RefCell<Bus>,
pub interrupt_controller: RefCell<InterruptController>, pub interrupt_controller: RefCell<InterruptController>,
} }
@ -33,44 +33,44 @@ impl System {
} }
pub fn add_addressable_device(&mut self, addr: Address, device: AddressableDeviceBox) -> Result<(), Error> { pub fn add_addressable_device(&mut self, addr: Address, device: TransmutableBox) -> Result<(), Error> {
let length = device.borrow().len(); let length = device.borrow_mut().as_addressable().unwrap().len();
self.bus.borrow_mut().insert(addr, length, device.clone()); self.bus.borrow_mut().insert(addr, length, device.clone());
self.devices.push(Device::Addressable(device)); self.devices.push(device);
Ok(()) Ok(())
} }
pub fn add_interruptable_device(&mut self, device: InterruptableDeviceBox) -> Result<(), Error> { pub fn add_interruptable_device(&mut self, device: TransmutableBox) -> Result<(), Error> {
self.interrupt_controller.borrow_mut().set_target(device.clone())?; self.interrupt_controller.borrow_mut().set_target(device.clone())?;
self.devices.push(Device::Interruptable(device)); self.devices.push(device);
Ok(()) Ok(())
} }
pub fn step(&mut self) -> Result<(), Error> { pub fn step(&mut self) -> Result<(), Error> {
self.clock += 1; self.clock += 1;
for dev in &self.devices { for dev in &self.devices {
match dev { match dev.borrow_mut().as_steppable() {
Device::Addressable(dev) => dev.borrow_mut().step(&self), Some(dev) => { dev.step(&self)?; },
Device::Interruptable(dev) => dev.borrow_mut().step(&self), None => { },
}?; }
} }
Ok(()) Ok(())
} }
pub fn exit_error(&mut self) { pub fn exit_error(&mut self) {
for dev in &self.devices { for dev in &self.devices {
match dev { match dev.borrow_mut().as_steppable() {
Device::Addressable(dev) => dev.borrow_mut().on_error(&self), Some(dev) => dev.on_error(&self),
Device::Interruptable(dev) => dev.borrow_mut().on_error(&self), None => { },
} }
} }
} }
pub fn debug(&mut self) -> Result<(), Error> { pub fn debug(&mut self) -> Result<(), Error> {
for dev in &self.devices { for dev in &self.devices {
match dev { match dev.borrow_mut().as_steppable() {
Device::Addressable(dev) => dev.borrow_mut().on_debug(), Some(dev) => dev.on_debug(),
Device::Interruptable(dev) => dev.borrow_mut().on_debug(), None => { },
} }
} }
Ok(()) Ok(())

View File

@ -1,5 +1,9 @@
* make IO in mc68681 use a separate thread... will that improve performance of mc68681.step()? * can you make Bus be an AddressableDeviceBox so that the CPU can have a ref to it instead of calling system.get_bus()
the alternative is having system.get_bus() take an argument or something to figure out what bus to return of multiple, for multibus systems
* can you eventually make this all configurable via a config file?
* test using mpsc to pass messages with the tty IO thread, and test if it's slower than what you have now
* make it possible to break out of the current execution, into the debugger, by using a certain keystroke * make it possible to break out of the current execution, into the debugger, by using a certain keystroke
* add support for MC68020+ indexing modes * add support for MC68020+ indexing modes