Cleanups suggested by Clippy

This commit is contained in:
Seth Morabito 2018-12-26 12:24:17 -08:00
parent 20b07f0079
commit 848d9c18c5
6 changed files with 208 additions and 176 deletions

View File

@ -63,40 +63,53 @@ pub struct Bus {
ram: Mem,
}
const ROM_START: usize = 0;
const ROM_SIZE: usize = 0x2_0000;
const DUART_START: usize = 0x20_0000;
const DUART_SIZE: usize = 0x40;
const MOUSE_START: usize = 0x40_0000;
const MOUSE_SIZE: usize = 4;
const VID_START: usize = 0x50_0000;
const VID_SIZE: usize = 2;
const BBRAM_START: usize = 0x60_0000;
const BBRAM_SIZE: usize = 0x2000;
const RAM_START: usize = 0x70_0000;
const RAM_SIZE: usize = 0x10_0000;
impl Bus {
pub fn new(mem_size: usize) -> Bus {
Bus {
rom: Mem::new(0, 0x20000, true),
rom: Mem::new(ROM_START, ROM_SIZE, true),
duart: Duart::new(),
mouse: Mouse::new(),
vid: Mem::new(0x500000, 0x2, false),
bbram: Mem::new(0x600000, 0x2000, false),
ram: Mem::new(0x700000, mem_size, false),
vid: Mem::new(0x50_0000, 0x2, false),
bbram: Mem::new(0x60_0000, 0x2000, false),
ram: Mem::new(0x70_0000, mem_size, false),
}
}
fn get_device(&mut self, address: usize) -> Result<&mut Device, BusError> {
if address < 0x20000 {
if address < ROM_SIZE {
return Ok(&mut self.rom);
}
if address >= 0x200000 && address < 0x200040 {
if address >= DUART_START && address < DUART_START + DUART_SIZE {
return Ok(&mut self.duart);
}
if address >= 0x400000 && address < 0x400004 {
if address >= MOUSE_START && address < MOUSE_START + MOUSE_SIZE {
return Ok(&mut self.mouse);
}
if address >= 0x500000 && address < 0x500002 {
if address >= VID_START && address < VID_START + VID_SIZE {
return Ok(&mut self.vid);
}
if address >= 0x600000 && address < 0x602000 {
if address >= BBRAM_START && address < BBRAM_START + BBRAM_SIZE {
return Ok(&mut self.bbram);
}
if address >= 0x700000 && address < 0x800000 {
if address >= RAM_START && address < RAM_START + RAM_SIZE {
return Ok(&mut self.ram);
}
@ -124,17 +137,17 @@ impl Bus {
pub fn read_op_half(&mut self, address: usize) -> Result<u16, BusError> {
let m = self.get_device(address)?;
Ok((m.read_byte(address, AccessCode::OperandFetch)? as u16)
| (m.read_byte(address + 1, AccessCode::OperandFetch)? as u16).wrapping_shl(8))
Ok(u16::from(m.read_byte(address, AccessCode::OperandFetch)?)
| u16::from(m.read_byte(address + 1, AccessCode::OperandFetch)?).wrapping_shl(8))
}
pub fn read_op_word(&mut self, address: usize) -> Result<u32, BusError> {
let m = self.get_device(address)?;
Ok((m.read_byte(address, AccessCode::OperandFetch)? as u32)
| (m.read_byte(address + 1, AccessCode::OperandFetch)? as u32).wrapping_shl(8)
| (m.read_byte(address + 2, AccessCode::OperandFetch)? as u32).wrapping_shl(16)
| (m.read_byte(address + 3, AccessCode::OperandFetch)? as u32).wrapping_shl(24))
Ok(u32::from(m.read_byte(address, AccessCode::OperandFetch)?)
| u32::from(m.read_byte(address + 1, AccessCode::OperandFetch)?).wrapping_shl(8)
| u32::from(m.read_byte(address + 2, AccessCode::OperandFetch)?).wrapping_shl(16)
| u32::from(m.read_byte(address + 3, AccessCode::OperandFetch)?).wrapping_shl(24))
}
pub fn write_byte(&mut self, address: usize, val: u8) -> Result<(), BusError> {
@ -204,14 +217,8 @@ impl Bus {
self.duart.output_port()
}
pub fn get_nvram(&self) -> [u8; NVRAM_SIZE] {
let mut contents: [u8; NVRAM_SIZE] = [0u8; NVRAM_SIZE];
for i in 0..NVRAM_SIZE {
contents[i] = self.bbram[i];
}
contents
pub fn get_nvram(&self) -> Result<&[u8], BusError> {
self.bbram.as_slice(0..NVRAM_SIZE)
}
pub fn set_nvram(&mut self, nvram: &[u8; NVRAM_SIZE]) {
@ -229,14 +236,14 @@ mod tests {
fn should_fail_on_alignment_errors() {
let mut bus: Bus = Bus::new(0x10000);
assert!(bus.write_byte(0x700000, 0x1f).is_ok());
assert!(bus.write_half(0x700000, 0x1f1f).is_ok());
assert!(bus.write_word(0x700000, 0x1f1f1f1f).is_ok());
assert!(bus.write_half(0x700001, 0x1f1f).is_err());
assert!(bus.write_half(0x700002, 0x1f1f).is_ok());
assert!(bus.write_word(0x700001, 0x1f1f1f1f).is_err());
assert!(bus.write_word(0x700002, 0x1f1f1f1f).is_err());
assert!(bus.write_word(0x700003, 0x1f1f1f1f).is_err());
assert!(bus.write_word(0x700004, 0x1f1f1f1f).is_ok());
assert!(bus.write_byte(0x70_0000, 0x1f).is_ok());
assert!(bus.write_half(0x70_0000, 0x1f1f).is_ok());
assert!(bus.write_word(0x70_0000, 0x1f1f_1f1f).is_ok());
assert!(bus.write_half(0x70_0001, 0x1f1f).is_err());
assert!(bus.write_half(0x70_0002, 0x1f1f).is_ok());
assert!(bus.write_word(0x70_0001, 0x1f1f_1f1f).is_err());
assert!(bus.write_word(0x70_0002, 0x1f1f_1f1f).is_err());
assert!(bus.write_word(0x70_0003, 0x1f1f_1f1f).is_err());
assert!(bus.write_word(0x70_0004, 0x1f1f_1f1f).is_ok());
}
}

View File

@ -6,21 +6,21 @@ use std::collections::HashMap;
///
/// PSW Flags and Offsets
///
const F_ET: u32 = 0x00000003;
const F_TM: u32 = 0x00000004;
const F_ISC: u32 = 0x00000078;
const F_I: u32 = 0x00000080;
const F_R: u32 = 0x00000100;
const F_PM: u32 = 0x00000600;
const F_CM: u32 = 0x00001800;
const F_IPL: u32 = 0x0001e000;
const F_C: u32 = 0x00040000;
const F_V: u32 = 0x00080000;
const F_Z: u32 = 0x00100000;
const F_N: u32 = 0x00200000;
const F_CD: u32 = 0x00800000;
const F_QIE: u32 = 0x01000000;
const F_CFD: u32 = 0x02000000;
const F_ET: u32 = 0x0000_0003;
const F_TM: u32 = 0x0000_0004;
const F_ISC: u32 = 0x0000_0078;
const F_I: u32 = 0x0000_0080;
const F_R: u32 = 0x0000_0100;
const F_PM: u32 = 0x0000_0600;
const F_CM: u32 = 0x0000_1800;
const F_IPL: u32 = 0x0001_e000;
const F_C: u32 = 0x0004_0000;
const F_V: u32 = 0x0008_0000;
const F_Z: u32 = 0x0010_0000;
const F_N: u32 = 0x0020_0000;
const F_CD: u32 = 0x0080_0000;
const F_QIE: u32 = 0x0100_0000;
const F_CFD: u32 = 0x0200_0000;
const O_ET: u32 = 0;
const O_TM: u32 = 2;
@ -191,11 +191,11 @@ macro_rules! mn {
}
fn sign_extend_halfword(data: u16) -> u32 {
((data as i16) as i32) as u32
(i32::from(data as i16)) as u32
}
fn sign_extend_byte(data: u8) -> u32 {
((data as i8) as i32) as u32
(i32::from(data as i8)) as u32
}
fn add_offset(val: u32, offset: u32) -> u32 {
@ -403,6 +403,12 @@ pub struct Cpu {
ir: Instruction,
}
impl Default for Cpu {
fn default() -> Self {
Cpu::new()
}
}
impl Cpu {
pub fn new() -> Cpu {
Cpu {
@ -542,8 +548,8 @@ impl Cpu {
match op.data_type() {
Data::Word | Data::UWord => self.r[r],
Data::Half => sign_extend_halfword(self.r[r] as u16),
Data::UHalf => (self.r[r] as u16) as u32,
Data::Byte => (self.r[r] as u8) as u32,
Data::UHalf => u32::from(self.r[r] as u16),
Data::Byte => u32::from(self.r[r] as u8),
Data::SByte => sign_extend_byte(self.r[r] as u8),
_ => return Err(CpuError::Exception(CpuException::IllegalOpcode)),
}
@ -557,8 +563,8 @@ impl Cpu {
match op.data_type() {
Data::UWord | Data::Word => bus.read_word(eff as usize, AccessCode::InstrFetch)?,
Data::Half => sign_extend_halfword(bus.read_half(eff as usize, AccessCode::InstrFetch)?),
Data::UHalf => bus.read_half(eff as usize, AccessCode::InstrFetch)? as u32,
Data::Byte => bus.read_byte(eff as usize, AccessCode::InstrFetch)? as u32,
Data::UHalf => u32::from(bus.read_half(eff as usize, AccessCode::InstrFetch)?),
Data::Byte => u32::from(bus.read_byte(eff as usize, AccessCode::InstrFetch)?),
Data::SByte => sign_extend_byte(bus.read_byte(eff as usize, AccessCode::InstrFetch)?),
_ => return Err(CpuError::Exception(CpuException::IllegalOpcode)),
}
@ -684,7 +690,7 @@ impl Cpu {
}
fn add(&mut self, bus: &mut Bus, a: u32, b: u32, dst: usize) -> Result<(), CpuError> {
let result: u64 = (a as u64).wrapping_add(b as u64);
let result: u64 = u64::from(a).wrapping_add(u64::from(b));
self.write_op(bus, dst, result as u32)?;
@ -694,8 +700,8 @@ impl Cpu {
match data_type {
Data::Word | Data::UWord => {
self.set_c_flag(result > 0xffffffff);
self.set_v_flag((((a ^ !b) & (a ^ result as u32)) & 0x80000000) != 0);
self.set_c_flag(result > 0xffff_ffff);
self.set_v_flag((((a ^ !b) & (a ^ result as u32)) & 0x8000_0000) != 0);
}
Data::Half | Data::UHalf => {
self.set_c_flag(result > 0xffff);
@ -714,7 +720,7 @@ impl Cpu {
}
fn sub(&mut self, bus: &mut Bus, a: u32, b: u32, dst: usize) -> Result<(), CpuError> {
let result: u64 = (a as u64).wrapping_sub(b as u64);
let result: u64 = u64::from(a).wrapping_sub(u64::from(b));
self.write_op(bus, dst, result as u32)?;
@ -731,8 +737,8 @@ impl Cpu {
Data::Half => (b as i16 / a as i16) as u32,
Data::SByte => (b as i8 / a as i8) as u32,
Data::UWord => b / a,
Data::UHalf => (b as u16 / a as u16) as u32,
Data::Byte => (b as u8 / a as u8) as u32,
Data::UHalf => u32::from(b as u16 / a as u16),
Data::Byte => u32::from(b as u8 / a as u8),
_ => b / a,
}
}
@ -743,15 +749,15 @@ impl Cpu {
Data::Half => (b as i16 % a as i16) as u32,
Data::SByte => (b as i8 % a as i8) as u32,
Data::UWord => b % a,
Data::UHalf => (b as u16 % a as u16) as u32,
Data::Byte => (b as u8 % a as u8) as u32,
Data::UHalf => u32::from(b as u16 % a as u16),
Data::Byte => u32::from(b as u8 % a as u8),
_ => b % a,
}
}
// TODO: Remove unwraps
fn on_interrupt(&mut self, bus: &mut Bus, vector: u8) {
let new_pcbp = bus.read_word((0x8c + (4 * (vector as u32))) as usize, AccessCode::AddressFetch).unwrap();
let new_pcbp = bus.read_word((0x8c + (4 * u32::from(vector))) as usize, AccessCode::AddressFetch).unwrap();
self.irq_push(bus, self.r[R_PCBP]).unwrap();
self.r[R_PSW] &= !(F_ISC | F_TM | F_ET);
@ -767,26 +773,30 @@ impl Cpu {
self.context_switch_3(bus).unwrap();
}
// Note: This function has ridiculous cyclomatic complexity. Clippy (rightfully)
// warns about this fact, but I can't think of a better way to do instruction
// dispatch at the moment that wouldn't end up being more expensive. So, until
// that glorious day, I'll turn off clippy's
#[allow(clippy::cyclomatic_complexity)]
fn dispatch(&mut self, bus: &mut Bus) -> Result<i32, CpuError> {
self.steps += 1;
// Update anything that needs updating.
bus.service();
let interrupt: Option<u8> = bus.get_interrupts();
match interrupt {
Some(val) => {
let cpu_ipl = (self.r[R_PSW]) >> 13 & 0xf;
if cpu_ipl < IPL_TABLE[(val & 0x3f) as usize] {
self.on_interrupt(bus, (!val) & 0x3f);
}
if let Some(interrupt) = bus.get_interrupts() {
let cpu_ipl = (self.r[R_PSW]) >> 13 & 0xf;
if cpu_ipl < IPL_TABLE[(interrupt & 0x3f) as usize] {
self.on_interrupt(bus, (!interrupt) & 0x3f);
}
None => {}
}
self.decode_instruction(bus)?;
let mut pc_increment: i32 = self.ir.bytes as i32;
// pc_increment is an i32 because it may be negative (jumps
// and branches, etc.) Strictly speaking, the case from u8
// to i8 here isn't strictly necessary, since ir.bytes will
// never be negative. But, being idiomatic and all that...
let mut pc_increment: i32 = i32::from(self.ir.bytes as i8);
match self.ir.opcode {
NOP => {
@ -811,7 +821,7 @@ impl Cpu {
ALSW3 => {
let a = self.read_op(bus, 0)?;
let b = self.read_op(bus, 1)?;
let result = (b as u64) << (a & 0x1f);
let result = u64::from(b) << (a & 0x1f);
self.write_op(bus, 2, result as u32)?;
self.set_nz_flags(result as u32, 2);
@ -1087,7 +1097,7 @@ impl Cpu {
return Err(CpuError::Exception(CpuException::IntegerZeroDivide));
}
if a == 0xffffffff && b == 0x80000000 {
if a == 0xffff_ffff && b == 0x8000_0000 {
self.set_v_flag(true);
}
@ -1138,7 +1148,7 @@ impl Cpu {
return Err(CpuError::Exception(CpuException::IntegerZeroDivide));
}
if a == 0xffffffff && b == 0x80000000 {
if a == 0xffff_ffff && b == 0x8000_0000 {
self.set_v_flag(true);
}
@ -1213,20 +1223,20 @@ impl Cpu {
let offset = self.read_op(bus, 1)? & 0x1f;
let mut mask = if width >= 32 {
0xffffffff
0xffff_ffff
} else {
(1 << width) - 1
};
mask = mask << offset;
mask <<= offset;
if width + offset > 32 {
mask |= 1 << ((width + offset) - 32) - 1;
mask |= 1 << (((width + offset) - 32) - 1);
}
let mut a = self.read_op(bus, 2)?;
a &= mask;
a = a >> offset;
a >>= offset;
self.write_op(bus, 3, a)?;
self.set_nz_flags(a, 3);
@ -1242,7 +1252,7 @@ impl Cpu {
let offset = self.read_op(bus, 1)? & 0x1f;
let mask = if width >= 32 {
0xffffffff
0xffff_ffff
} else {
(1 << width) - 1
};
@ -1269,7 +1279,7 @@ impl Cpu {
pc_increment = 0;
}
LLSW3 | LLSH3 | LLSB3 => {
let a: u64 = self.read_op(bus, 1)? as u64;
let a: u64 = u64::from(self.read_op(bus, 1)?);
let b = self.read_op(bus, 0)? & 0x1f;
let result = (a << b) as u32;
@ -1286,8 +1296,8 @@ impl Cpu {
Data::Word => (a as i32 >> b as i32) as u32,
Data::UWord => a >> b,
Data::Half => (a as i16 >> b as i16) as u32,
Data::UHalf => (a as u16 >> b as u16) as u32,
Data::Byte => (a as u8 >> b as u8) as u32,
Data::UHalf => u32::from(a as u16 >> b as u16),
Data::Byte => u32::from(a as u8 >> b as u8),
Data::SByte => (a as i8 >> b as i8) as u32,
_ => 0,
};
@ -1598,7 +1608,7 @@ impl Cpu {
stack_offset += 4;
}
self.r[R_SP] = self.r[R_SP] + 28;
self.r[R_SP] += 28;
self.r[R_FP] = self.r[R_SP];
}
SUBW2 | SUBH2 | SUBB2 => {
@ -1687,7 +1697,7 @@ impl Cpu {
Ok(())
}
fn on_exception(&mut self, bus: &mut Bus, exc: ExceptionType) -> Result<(), CpuError> {
fn on_exception(&mut self, bus: &mut Bus, exc: &ExceptionType) -> Result<(), CpuError> {
let (et, isc) = match exc {
ExceptionType::ExternalMemory => (3, 5)
};
@ -1733,7 +1743,7 @@ impl Cpu {
Err(CpuError::Bus(BusError::NoDevice(_)))
| Err(CpuError::Bus(BusError::Read(_)))
| Err(CpuError::Bus(BusError::Write(_))) => {
self.on_exception(bus, ExceptionType::ExternalMemory).unwrap();
self.on_exception(bus, &ExceptionType::ExternalMemory).unwrap();
}
Err(CpuError::Exception(CpuException::IllegalOpcode)) => {}
Err(CpuError::Exception(CpuException::InvalidDescriptor)) => {}
@ -1756,6 +1766,8 @@ impl Cpu {
self.r[R_PC] = val;
}
#[allow(clippy::too_many_arguments)]
fn set_operand(
&mut self,
index: usize,
@ -1782,11 +1794,11 @@ impl Cpu {
match mn.dtype {
Data::Byte => {
let b: u8 = bus.read_byte(addr, AccessCode::OperandFetch)?;
self.set_operand(index, 1, AddrMode::None, Data::Byte, None, None, b as u32);
self.set_operand(index, 1, AddrMode::None, Data::Byte, None, None, u32::from(b));
}
Data::Half => {
let h: u16 = bus.read_op_half(addr)?;
self.set_operand(index, 2, AddrMode::None, Data::Half, None, None, h as u32);
self.set_operand(index, 2, AddrMode::None, Data::Half, None, None, u32::from(h));
}
Data::Word => {
let w: u32 = bus.read_op_word(addr)?;
@ -1824,7 +1836,7 @@ impl Cpu {
match m {
0 | 1 | 2 | 3 => {
// Positive Literal
self.set_operand(index, dsize, AddrMode::PositiveLiteral, dtype, etype, None, descriptor_byte as u32);
self.set_operand(index, dsize, AddrMode::PositiveLiteral, dtype, etype, None, u32::from(descriptor_byte));
}
4 => {
match r {
@ -1844,7 +1856,7 @@ impl Cpu {
15 => {
// Halfword Immediate
let h = bus.read_op_half(addr + 1)?;
self.set_operand(index, dsize + 2, AddrMode::HalfwordImmediate, dtype, etype, None, h as u32);
self.set_operand(index, dsize + 2, AddrMode::HalfwordImmediate, dtype, etype, None, u32::from(h));
}
11 => {
// Illegal
@ -1861,11 +1873,11 @@ impl Cpu {
15 => {
// Byte Immediate
let b = bus.read_byte(addr + 1, AccessCode::OperandFetch)?;
self.set_operand(index, dsize + 1, AddrMode::ByteImmediate, dtype, etype, None, b as u32);
self.set_operand(index, dsize + 1, AddrMode::ByteImmediate, dtype, etype, None, u32::from(b));
}
_ => {
// FP Short Offset
self.set_operand(index, dsize, AddrMode::FPShortOffset, dtype, etype, Some(R_FP), r as u32);
self.set_operand(index, dsize, AddrMode::FPShortOffset, dtype, etype, Some(R_FP), u32::from(r));
}
}
}
@ -1878,7 +1890,7 @@ impl Cpu {
}
_ => {
// AP Short Offset
self.set_operand(index, dsize, AddrMode::APShortOffset, dtype, etype, Some(R_AP), r as u32);
self.set_operand(index, dsize, AddrMode::APShortOffset, dtype, etype, Some(R_AP), u32::from(r));
}
}
}
@ -1908,7 +1920,7 @@ impl Cpu {
_ => {
// Halfword Displacement
let disp = bus.read_op_half(addr + 1)?;
self.set_operand(index, dsize + 2, AddrMode::HalfwordDisplacement, dtype, etype, Some(r as usize), disp as u32);
self.set_operand(index, dsize + 2, AddrMode::HalfwordDisplacement, dtype, etype, Some(r as usize), u32::from(disp));
}
}
}
@ -1925,7 +1937,7 @@ impl Cpu {
dtype,
etype,
Some(r as usize),
disp as u32,
u32::from(disp),
);
}
}
@ -1936,7 +1948,7 @@ impl Cpu {
_ => {
// Byte Displacement
let disp = bus.read_byte(addr + 1, AccessCode::OperandFetch)?;
self.set_operand(index, dsize + 1, AddrMode::ByteDisplacement, dtype, etype, Some(r as usize), disp as u32);
self.set_operand(index, dsize + 1, AddrMode::ByteDisplacement, dtype, etype, Some(r as usize), u32::from(disp));
}
}
}
@ -1946,7 +1958,7 @@ impl Cpu {
_ => {
// Byte Displacement Deferred
let disp = bus.read_byte(addr + 1, AccessCode::OperandFetch)?;
self.set_operand(index, dsize + 1, AddrMode::ByteDisplacementDeferred, dtype, etype, Some(r as usize), disp as u32);
self.set_operand(index, dsize + 1, AddrMode::ByteDisplacementDeferred, dtype, etype, Some(r as usize), u32::from(disp));
}
}
}
@ -1965,7 +1977,7 @@ impl Cpu {
},
15 => {
// Negative Literal
self.set_operand(index, 1, AddrMode::NegativeLiteral, dtype, etype, None, descriptor_byte as u32);
self.set_operand(index, 1, AddrMode::NegativeLiteral, dtype, etype, None, u32::from(descriptor_byte));
},
_ => { return Err(CpuError::Exception(CpuException::IllegalOpcode)); }
};
@ -1979,11 +1991,11 @@ impl Cpu {
bus: &mut Bus,
index: usize,
mn: &Mnemonic,
ot: &OpType,
ot: OpType,
etype: Option<Data>,
addr: usize,
) -> Result<(), CpuError> {
match *ot {
match ot {
OpType::Lit => self.decode_literal_operand(bus, index, mn, addr),
OpType::Src | OpType::Dest => self.decode_descriptor_operand(bus, index, mn.dtype, etype, addr, false),
}
@ -2008,9 +2020,9 @@ impl Cpu {
// Special case for half-word opcodes
let b2 = bus.read_byte(addr, AccessCode::InstrFetch)?;
addr += 1;
((b1 as u16) << 8) | b2 as u16
(u16::from(b1) << 8) | u16::from(b2)
} else {
b1 as u16
u16::from(b1)
};
let mn = MNEMONICS.get(&index);
@ -2023,7 +2035,7 @@ impl Cpu {
for (index, ot) in mn.ops.iter().enumerate() {
// Push a decoded operand
self.decode_operand(bus, index, mn, ot, etype, addr)?;
self.decode_operand(bus, index, mn, *ot, etype, addr)?;
etype = self.ir.operands[index].expanded_type;
addr += self.ir.operands[index].size as usize;
}
@ -2039,7 +2051,7 @@ impl Cpu {
None => return Err(CpuError::Exception(CpuException::IllegalOpcode)),
}
return Ok(())
Ok(())
}
/// Convenience operations on flags.
@ -2057,16 +2069,16 @@ impl Cpu {
fn set_nz_flags(&mut self, val: u32, index: usize) {
match self.ir.operands[index].data_type {
Data::Word | Data::UWord => {
self.set_n_flag((val & 0x80000000) != 0);
self.set_n_flag((val & 0x8000_0000) != 0);
self.set_z_flag(val == 0);
}
Data::Half | Data::UHalf => {
self.set_n_flag((val & 0x8000) != 0);
self.set_z_flag((val & 0xffff) == 0);
self.set_z_flag(val.trailing_zeros() > 4);
}
Data::Byte | Data::SByte => {
self.set_n_flag((val & 0x80) != 0);
self.set_z_flag((val & 0xff) == 0);
self.set_z_flag(val.trailing_zeros() > 2);
}
Data::None => {
// Intentionally ignored
@ -2193,11 +2205,12 @@ impl Cpu {
}
#[cfg(test)]
#[allow(clippy::unreadable_literal)]
mod tests {
use super::*;
use crate::bus::Bus;
const BASE: usize = 0x700000;
const BASE: usize = 0x70_0000;
/// Helper function to set up and prepare a cpu and bus
/// with a supplied program.
@ -2216,8 +2229,8 @@ mod tests {
#[test]
fn sign_extension() {
assert_eq!(0xffff8000, sign_extend_halfword(0x8000));
assert_eq!(0xffffff80, sign_extend_byte(0x80));
assert_eq!(0xffff_8000, sign_extend_halfword(0x8000));
assert_eq!(0xffff_ff80, sign_extend_byte(0x80));
}
#[test]
@ -2300,7 +2313,7 @@ mod tests {
do_with_program(&program, |cpu, mut bus| {
cpu.decode_descriptor_operand(&mut bus, 0, Data::Word, None, BASE + 1, false).unwrap();
assert_eq!(cpu.ir.operands[0], Operand::new(5, AddrMode::WordImmediate, Data::Word, None, None, 0x12345678));
assert_eq!(cpu.ir.operands[0], Operand::new(5, AddrMode::WordImmediate, Data::Word, None, None, 0x1234_5678));
});
}
@ -2360,7 +2373,7 @@ mod tests {
do_with_program(&program, |cpu, mut bus| {
cpu.decode_descriptor_operand(&mut bus, 0, Data::Byte, None, BASE + 1, false).unwrap();
assert_eq!(cpu.ir.operands[0], Operand::new(5, AddrMode::Absolute, Data::Byte, None, None, 0x00000100));
assert_eq!(cpu.ir.operands[0], Operand::new(5, AddrMode::Absolute, Data::Byte, None, None, 0x100));
});
}
@ -2370,7 +2383,7 @@ mod tests {
do_with_program(&program, |cpu, mut bus| {
cpu.decode_descriptor_operand(&mut bus, 0, Data::Byte, None, BASE + 1, false).unwrap();
assert_eq!(cpu.ir.operands[0], Operand::new(5, AddrMode::AbsoluteDeferred, Data::Byte, None, None, 0x00000100));
assert_eq!(cpu.ir.operands[0], Operand::new(5, AddrMode::AbsoluteDeferred, Data::Byte, None, None, 0x100));
});
}
@ -2724,7 +2737,7 @@ mod tests {
let program = [0x40];
do_with_program(&program, |cpu, mut bus| {
cpu.r[0] = 0;
cpu.decode_descriptor_operand(&mut bus, 0, Data::Byte, None, BASE + 0, false).unwrap();
cpu.decode_descriptor_operand(&mut bus, 0, Data::Byte, None, BASE, false).unwrap();
cpu.write_op(bus, 0, 0x5a).unwrap();
assert_eq!(0x5a, cpu.r[0]);
});

View File

@ -22,10 +22,16 @@ pub struct Dmd {
bus: Bus,
}
impl Default for Dmd {
fn default() -> Self {
Dmd::new()
}
}
impl Dmd {
pub fn new() -> Dmd {
let cpu = Cpu::new();
let bus = Bus::new(0x100000);
let bus = Bus::new(0x10_0000);
Dmd {
cpu,
bus,
@ -113,7 +119,7 @@ impl Dmd {
self.bus.set_nvram(nvram);
}
pub fn get_nvram(&self) -> [u8; 8192] {
pub fn get_nvram(&self) -> Result<&[u8], BusError> {
self.bus.get_nvram()
}
}
@ -305,11 +311,12 @@ fn dmd_set_nvram(nvram: &[u8; 8192]) -> c_int {
fn dmd_get_nvram(nvram: &mut [u8; 8192]) -> c_int {
match DMD.lock() {
Ok(dmd) => {
let buf = dmd.get_nvram();
for i in 0..8192 {
nvram[i] = buf[i];
if let Ok(slice) = dmd.get_nvram() {
nvram.copy_from_slice(slice);
SUCCESS
} else {
ERROR
}
SUCCESS
}
Err(_) => ERROR
}
@ -334,7 +341,7 @@ mod tests {
to_load[0xfff] = 0xa5;
to_load[0x1fff] = 0xff;
let old_nvram = dmd.get_nvram();
let old_nvram = dmd.get_nvram().unwrap();
assert_eq!(0, old_nvram[0]);
assert_eq!(0, old_nvram[0xfff]);
@ -342,7 +349,7 @@ mod tests {
dmd.set_nvram(&to_load);
let new_nvram = dmd.get_nvram();
let new_nvram = dmd.get_nvram().unwrap();
assert_eq!(0x5a, new_nvram[0]);
assert_eq!(0xa5, new_nvram[0xfff]);

View File

@ -10,8 +10,8 @@ use std::time::Duration;
use std::time::Instant;
use std::collections::VecDeque;
const START_ADDR: usize = 0x200000;
const END_ADDR: usize = 0x2000040;
const START_ADDR: usize = 0x20_0000;
const END_ADDR: usize = 0x20_0040;
const ADDRESS_RANGE: Range<usize> = START_ADDR..END_ADDR;
// Vertical blanks should occur at 60Hz. This value is in nanoseconds
@ -19,16 +19,16 @@ const VERTICAL_BLANK_DELAY: u32 = 16_666_666; // 60 Hz
// Delay rates selected when ACR[7] = 0
const DELAY_RATES_A: [u32;13] = [
200000000, 90909096, 74074072, 50000000,
33333336, 16666668, 8333334, 9523810,
4166667, 2083333, 1388888, 1041666, 260416,
200_000_000, 90_909_096, 74_074_072, 50_000_000,
33_333_336, 16_666_668, 8_333_334, 9_523_810,
4_166_667, 2_083_333, 1_388_888, 1_041_666, 260_416,
];
// Delay rates selected when ACR[7] = 1
const DELAY_RATES_B: [u32;13] = [
133333344, 90909096, 74074072, 66666672,
33333336, 16666668, 8333334, 5000000,
4166667, 205338, 5555555, 1041666, 520833,
133_333_344, 90_909_096, 74_074_072, 66_666_672,
33_333_336, 16_666_668, 8_333_334, 5_000_000,
4_166_667, 205_338, 5_555_555, 1_041_666, 520_833,
];
const PORT_0: usize = 0;
@ -119,36 +119,42 @@ pub struct Duart {
last_vblank: Instant,
}
impl Port {
fn new() -> Self {
Port {
mode: [0; 2],
stat: 0,
conf: 0,
rx_data: 0,
tx_data: 0,
mode_ptr: 0,
rx_queue: VecDeque::new(),
tx_queue: VecDeque::new(),
char_delay: Duration::new(0, 1_000_000),
next_rx: Instant::now(),
next_tx: Instant::now(),
}
}
}
impl Default for Port {
fn default() -> Self {
Port::new()
}
}
impl Default for Duart {
fn default() -> Self {
Duart::new()
}
}
impl Duart {
pub fn new() -> Duart {
Duart {
ports: [
Port {
mode: [0; 2],
stat: 0,
conf: 0,
rx_data: 0,
tx_data: 0,
mode_ptr: 0,
rx_queue: VecDeque::new(),
tx_queue: VecDeque::new(),
char_delay: Duration::new(0, 1_000_000),
next_rx: Instant::now(),
next_tx: Instant::now(),
},
Port {
mode: [0; 2],
stat: 0,
conf: 0,
rx_data: 0,
tx_data: 0,
mode_ptr: 0,
rx_queue: VecDeque::new(),
tx_queue: VecDeque::new(),
char_delay: Duration::new(0, 1_000_000),
next_rx: Instant::now(),
next_tx: Instant::now(),
},
Port::new(),
Port::new(),
],
acr: 0,
ipcr: 0x40,
@ -187,21 +193,14 @@ impl Duart {
};
if !ctx.rx_queue.is_empty() && Instant::now() >= ctx.next_rx {
match ctx.rx_queue.pop_back() {
Some(c) => {
if ctx.conf & CNF_ERX != 0 {
ctx.rx_data = c;
ctx.stat |= STS_RXR;
self.istat |= istat;
self.ivec |= ivec;
} else {
ctx.stat |= STS_OER;
}
},
None => {
// This is really unexpected! We just asserted
// that the queue was not empty, so this should
// really never happen.
if let Some(c) = ctx.rx_queue.pop_back() {
if ctx.conf & CNF_ERX != 0 {
ctx.rx_data = c;
ctx.stat |= STS_RXR;
self.istat |= istat;
self.ivec |= ivec;
} else {
ctx.stat |= STS_OER;
}
}

View File

@ -169,7 +169,7 @@ impl Index<usize> for Mem {
}
impl IndexMut<usize> for Mem {
fn index_mut<'a>(&'a mut self, idx: usize) -> &'a mut u8 {
fn index_mut(&'_ mut self, idx: usize) -> &'_ mut u8 {
&mut self.ram[idx]
}
}
@ -183,7 +183,7 @@ mod tests {
let mut mem = Mem::new(0, 0x1000, true);
assert!(mem.write_byte(0, 0x1f, AccessCode::Write).is_err());
assert!(mem.write_half(0, 0x1f1f, AccessCode::Write).is_err());
assert!(mem.write_word(0, 0x1f1f1f1f, AccessCode::Write).is_err());
assert!(mem.write_word(0, 0x1f1f_1f1f, AccessCode::Write).is_err());
}
#[test]

View File

@ -3,8 +3,8 @@ use crate::bus::AccessCode;
use crate::err::BusError;
use std::ops::Range;
const START_ADDRESS: usize = 0x400000;
const END_ADDRESS: usize = 0x4000004;
const START_ADDRESS: usize = 0x40_0000;
const END_ADDRESS: usize = 0x40_0004;
const ADDRESS_RANGE: Range<usize> = START_ADDRESS..END_ADDRESS;
#[derive(Debug)]
@ -22,6 +22,12 @@ impl Mouse {
}
}
impl Default for Mouse {
fn default() -> Self {
Mouse::new()
}
}
impl Device for Mouse {
fn address_range(&self) -> &Range<usize> {
&ADDRESS_RANGE