diff --git a/.clippy.toml b/.clippy.toml index 16caf02..1645c19 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1 +1 @@ -msrv = "1.60.0" +msrv = "1.70.0" diff --git a/.github/workflows/clippy.yaml b/.github/workflows/clippy.yaml new file mode 100644 index 0000000..ad3b553 --- /dev/null +++ b/.github/workflows/clippy.yaml @@ -0,0 +1,32 @@ +name: clippy +on: + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened] + +permissions: + contents: read + +jobs: + clippy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Install dependencies + run: | + sudo apt-get install -y alsa-base libasound2-dev libxkbcommon-dev + + - name: Select rust version + run: | + rustup toolchain install 1.70 --profile minimal --no-self-update + rustup default 1.70 + rustup component add clippy + + - name: Check clippy + run: | + cargo clippy diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yaml similarity index 100% rename from .github/workflows/deploy-docs.yml rename to .github/workflows/deploy-docs.yaml diff --git a/.github/workflows/rustdoc.yaml b/.github/workflows/rustdoc.yaml new file mode 100644 index 0000000..486e4a1 --- /dev/null +++ b/.github/workflows/rustdoc.yaml @@ -0,0 +1,32 @@ +name: rustdoc +on: + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened] + +permissions: + contents: read + +jobs: + rustdocs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Install dependencies + run: | + sudo apt-get install -y alsa-base libasound2-dev libxkbcommon-dev + + - name: Select rust version + run: | + rm Cargo.lock + rustup toolchain install nightly --profile minimal --no-self-update + rustup default nightly + + - name: Build rustdoc + run: | + RUSTDOCFLAGS="--deny=warnings --cfg=docsrs" cargo doc --all-features diff --git a/.github/workflows/rustfmt.yaml b/.github/workflows/rustfmt.yaml new file mode 100644 index 0000000..fc6144d --- /dev/null +++ b/.github/workflows/rustfmt.yaml @@ -0,0 +1,32 @@ +name: rustfmt +on: + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened] + +permissions: + contents: read + +jobs: + rustfmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Install dependencies + run: | + sudo apt-get install -y alsa-base libasound2-dev libxkbcommon-dev + + - name: Select rust version + run: | + rustup toolchain install nightly --profile minimal --no-self-update + rustup default nightly + rustup component add rustfmt + + - name: Check rustfmt + run: | + cargo +nightly fmt --check diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..9b6206a --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,44 @@ +name: test +on: + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened] + +permissions: + contents: read + +env: + RUSTFLAGS: '--deny warnings' + +jobs: + test-ubuntu: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Install dependencies + run: | + sudo apt-get install -y alsa-base libasound2-dev libxkbcommon-dev + + - name: Select rust version + run: | + rustup toolchain install 1.70 --profile minimal --no-self-update + rustup default 1.70 + + - name: Run tests with default features + run: | + cargo test + + - name: Run tests with all features + run: | + cargo test #--features=std,fugit,femtos + + - name: Run test with no_std + run: | + cargo test --no-default-features + + diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..bb1fb9a --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,24 @@ +edition = "2021" +version = "Two" + +max_width = 132 + +struct_lit_width = 0 # default 18 (24) +fn_call_width=100 # default 60 (80) +array_width=132 # default 60 (80) +#chain_width=100 # default 60 (80) +#attr_fn_like_width=100 # default 70 (92) +#single_line_if_else_max_width=100 # default 50 (66) +#struct_variant_width = 0 # default 35 (46) + +newline_style = "Unix" +reorder_imports = false +match_block_trailing_comma = true + +## Experimental Features +unstable_features = true +blank_lines_upper_bound = 3 +overflow_delimited_expr = true + +# it would be nice to allow a newline at the top and bottom of file +# it would be nice to not erase the whitespace between the end of the code line and start of a comment on the same line diff --git a/Cargo.lock b/Cargo.lock index 70d773e..abd7b2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -420,10 +420,6 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "emulator-hal" version = "0.1.0" -dependencies = [ - "femtos", - "fugit", -] [[package]] name = "emulator-hal-memory" @@ -491,21 +487,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "fugit" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7" -dependencies = [ - "gcd", -] - -[[package]] -name = "gcd" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" - [[package]] name = "glob" version = "0.3.1" diff --git a/emulator/core/src/devices.rs b/emulator/core/src/devices.rs index 1da73bd..6ffae86 100644 --- a/emulator/core/src/devices.rs +++ b/emulator/core/src/devices.rs @@ -1,4 +1,3 @@ - use std::rc::Rc; use std::cell::{RefCell, RefMut, BorrowMutError}; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -17,7 +16,7 @@ pub type Address = u64; /// information that might be helpful for debugging. pub trait Steppable { fn step(&mut self, system: &System) -> Result; - fn on_error(&mut self, _system: &System) { } + fn on_error(&mut self, _system: &System) {} } /// A device that can receive an interrupt. The `interrupt_state_change()` method @@ -104,30 +103,22 @@ pub trait Addressable { #[inline] pub fn read_beu16(data: &[u8]) -> u16 { - (data[0] as u16) << 8 | - (data[1] as u16) + (data[0] as u16) << 8 | (data[1] as u16) } #[inline] pub fn read_leu16(data: &[u8]) -> u16 { - (data[1] as u16) << 8 | - (data[0] as u16) + (data[1] as u16) << 8 | (data[0] as u16) } #[inline] pub fn read_beu32(data: &[u8]) -> u32 { - (data[0] as u32) << 24 | - (data[1] as u32) << 16 | - (data[2] as u32) << 8 | - (data[3] as u32) + (data[0] as u32) << 24 | (data[1] as u32) << 16 | (data[2] as u32) << 8 | (data[3] as u32) } #[inline] pub fn read_leu32(data: &[u8]) -> u32 { - (data[3] as u32) << 24 | - (data[2] as u32) << 16 | - (data[1] as u32) << 8 | - (data[0] as u32) + (data[3] as u32) << 24 | (data[2] as u32) << 16 | (data[1] as u32) << 8 | (data[0] as u32) } @@ -239,7 +230,7 @@ pub struct Device(DeviceId, TransmutableBox); impl Device { pub fn new(value: T) -> Self where - T: Transmutable + 'static + T: Transmutable + 'static, { Self(DeviceId::new(), wrap_transmutable(value)) } diff --git a/emulator/core/src/error.rs b/emulator/core/src/error.rs index cd10af0..ff1ea22 100644 --- a/emulator/core/src/error.rs +++ b/emulator/core/src/error.rs @@ -1,4 +1,3 @@ - use std::fmt; use moa_host::HostError; @@ -52,10 +51,7 @@ impl Error { pub fn msg(&self) -> &str { match self { - Error::Assertion(msg) | - Error::Breakpoint(msg) | - Error::Other(msg) | - Error::Emulator(_, msg) => msg.as_str(), + Error::Assertion(msg) | Error::Breakpoint(msg) | Error::Other(msg) | Error::Emulator(_, msg) => msg.as_str(), Error::Processor(_) => "native exception", } } @@ -64,10 +60,7 @@ impl Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Error::Assertion(msg) | - Error::Breakpoint(msg) | - Error::Other(msg) | - Error::Emulator(_, msg) => write!(f, "{}", msg), + Error::Assertion(msg) | Error::Breakpoint(msg) | Error::Other(msg) | Error::Emulator(_, msg) => write!(f, "{}", msg), Error::Processor(_) => write!(f, "native exception"), } } @@ -78,4 +71,3 @@ impl From> for Error { Self::Other("other".to_string()) } } - diff --git a/emulator/core/src/interrupts.rs b/emulator/core/src/interrupts.rs index bcec953..73b90b0 100644 --- a/emulator/core/src/interrupts.rs +++ b/emulator/core/src/interrupts.rs @@ -1,4 +1,3 @@ - use crate::error::Error; @@ -43,4 +42,3 @@ impl InterruptController { Ok(acknowledge) } } - diff --git a/emulator/core/src/lib.rs b/emulator/core/src/lib.rs index d3f38f9..c0c332f 100644 --- a/emulator/core/src/lib.rs +++ b/emulator/core/src/lib.rs @@ -1,4 +1,3 @@ - #[macro_use] mod error; @@ -7,12 +6,15 @@ mod interrupts; mod memory; mod system; -pub use crate::devices::{Address, Addressable, Steppable, Interruptable, Debuggable, Inspectable, Transmutable, TransmutableBox, Device}; -pub use crate::devices::{read_beu16, read_beu32, read_leu16, read_leu32, write_beu16, write_beu32, write_leu16, write_leu32, wrap_transmutable}; +pub use crate::devices::{ + Address, Addressable, Steppable, Interruptable, Debuggable, Inspectable, Transmutable, TransmutableBox, Device, +}; +pub use crate::devices::{ + read_beu16, read_beu32, read_leu16, read_leu32, write_beu16, write_beu32, write_leu16, write_leu32, wrap_transmutable, +}; pub use crate::error::Error; pub use crate::interrupts::InterruptController; pub use crate::memory::{MemoryBlock, AddressTranslator, AddressRepeater, Bus, BusPort, dump_slice, dump_memory}; pub use crate::system::System; pub use emulator_hal::bus::{BusAccess}; - diff --git a/emulator/core/src/memory.rs b/emulator/core/src/memory.rs index 09c44da..1d841e2 100644 --- a/emulator/core/src/memory.rs +++ b/emulator/core/src/memory.rs @@ -1,4 +1,3 @@ - use std::fs; use std::cmp; use std::rc::Rc; @@ -20,7 +19,7 @@ impl MemoryBlock { pub fn new(contents: Vec) -> MemoryBlock { MemoryBlock { read_only: false, - contents + contents, } } @@ -62,10 +61,13 @@ impl Addressable for MemoryBlock { fn write(&mut self, _clock: Instant, addr: Address, data: &[u8]) -> Result<(), Error> { if self.read_only { - return Err(Error::breakpoint(format!("Attempt to write to read-only memory at {:x} with data {:?}", addr, data))); + return Err(Error::breakpoint(format!( + "Attempt to write to read-only memory at {:x} with data {:?}", + addr, data + ))); } - self.contents[(addr as usize) .. (addr as usize) + data.len()].copy_from_slice(data); + self.contents[(addr as usize)..(addr as usize) + data.len()].copy_from_slice(data); Ok(()) } } @@ -99,12 +101,20 @@ impl Addressable for AddressRepeater { fn read(&mut self, clock: Instant, addr: Address, data: &mut [u8]) -> Result<(), Error> { let size = self.subdevice.borrow_mut().as_addressable().unwrap().size() as Address; - self.subdevice.borrow_mut().as_addressable().unwrap().read(clock, addr % size, data) + self.subdevice + .borrow_mut() + .as_addressable() + .unwrap() + .read(clock, addr % size, data) } fn write(&mut self, clock: Instant, addr: Address, data: &[u8]) -> Result<(), Error> { let size = self.subdevice.borrow_mut().as_addressable().unwrap().size() as Address; - self.subdevice.borrow_mut().as_addressable().unwrap().write(clock, addr % size, data) + self.subdevice + .borrow_mut() + .as_addressable() + .unwrap() + .write(clock, addr % size, data) } } @@ -125,7 +135,7 @@ pub struct AddressTranslator { impl AddressTranslator { pub fn new(subdevice: Device, size: usize, func: F) -> Self where - F: Fn(Address) -> Address + 'static + F: Fn(Address) -> Address + 'static, { Self { subdevice, @@ -141,11 +151,19 @@ impl Addressable for AddressTranslator { } fn read(&mut self, clock: Instant, addr: Address, data: &mut [u8]) -> Result<(), Error> { - self.subdevice.borrow_mut().as_addressable().unwrap().read(clock, (self.func)(addr), data) + self.subdevice + .borrow_mut() + .as_addressable() + .unwrap() + .read(clock, (self.func)(addr), data) } fn write(&mut self, clock: Instant, addr: Address, data: &[u8]) -> Result<(), Error> { - self.subdevice.borrow_mut().as_addressable().unwrap().write(clock, (self.func)(addr), data) + self.subdevice + .borrow_mut() + .as_addressable() + .unwrap() + .write(clock, (self.func)(addr), data) } } @@ -185,8 +203,16 @@ impl Bus { pub fn insert(&mut self, base: Address, dev: Device) { let size = dev.borrow_mut().as_addressable().unwrap().size(); - let block = Block { base, size, dev }; - let i = self.blocks.iter().position(|cur| cur.base > block.base).unwrap_or(self.blocks.len()); + let block = Block { + base, + size, + dev, + }; + let i = self + .blocks + .iter() + .position(|cur| cur.base > block.base) + .unwrap_or(self.blocks.len()); self.blocks.insert(i, block); } @@ -252,7 +278,7 @@ impl Addressable for Bus { Ok(result) => result, Err(err) if self.ignore_unmapped => { log::info!("{:?}", err); - return Ok(()) + return Ok(()); }, Err(err) => return Err(err), }; @@ -270,7 +296,7 @@ impl Addressable for Bus { Ok(result) => result, Err(err) if self.ignore_unmapped => { log::info!("{:?}", err); - return Ok(()) + return Ok(()); }, Err(err) => return Err(err), }; @@ -300,7 +326,9 @@ impl BusPort { } pub fn dump_memory(&mut self, clock: Instant, addr: Address, count: Address) { - self.subdevice.borrow_mut().dump_memory(clock, self.offset + (addr & self.address_mask), count) + self.subdevice + .borrow_mut() + .dump_memory(clock, self.offset + (addr & self.address_mask), count) } #[inline] @@ -401,4 +429,3 @@ impl BusAccess for &mut dyn Addressable { Ok(data.len()) } } - diff --git a/emulator/core/src/system.rs b/emulator/core/src/system.rs index 87a00e5..60eff8b 100644 --- a/emulator/core/src/system.rs +++ b/emulator/core/src/system.rs @@ -1,4 +1,3 @@ - use std::rc::Rc; use std::cell::{RefCell, RefMut}; use std::collections::HashMap; @@ -45,7 +44,10 @@ impl System { } pub fn get_device(&self, name: &str) -> Result { - self.devices.get(name).cloned().ok_or_else(|| Error::new(format!("system: no device named {}", name))) + self.devices + .get(name) + .cloned() + .ok_or_else(|| Error::new(format!("system: no device named {}", name))) } pub fn add_device(&mut self, name: &str, device: Device) -> Result<(), Error> { diff --git a/emulator/cpus/m68k/src/assembler.rs b/emulator/cpus/m68k/src/assembler.rs index 8d48a65..6e66e87 100644 --- a/emulator/cpus/m68k/src/assembler.rs +++ b/emulator/cpus/m68k/src/assembler.rs @@ -1,4 +1,3 @@ - use std::collections::HashMap; use moa_parsing::{self as parser, AssemblyLine, AssemblyOperand, AssemblyParser, ParserError}; @@ -24,6 +23,7 @@ impl From for Error { #[repr(usize)] #[derive(Copy, Clone)] +#[rustfmt::skip] pub enum Disallow { None = 0x0000, NoDReg = 0x0001, @@ -136,7 +136,10 @@ impl M68kAssembler { match reloc.rtype { RelocationType::Displacement => { // TODO this doesn't yet take into accound the origin - let location = *self.labels.get(&reloc.label).ok_or_else(|| Error::new(format!("error during relocation, label undefined {:?}", reloc.label)))?; + let location = *self + .labels + .get(&reloc.label) + .ok_or_else(|| Error::new(format!("error during relocation, label undefined {:?}", reloc.label)))?; self.output[reloc.index] |= ((self.output[reloc.index] as i8 * 2 + 2) - (location as i8 * 2)) as u16 & 0x00ff; }, _ => panic!("relocation type unimplemented"), @@ -166,12 +169,22 @@ impl M68kAssembler { "bra" => { let label = parser::expect_label(lineno, args)?; self.output.push(0x6000); - self.relocations.push(Relocation::new(RelocationType::Displacement, label, self.output.len() - 1, self.current_origin)); + self.relocations.push(Relocation::new( + RelocationType::Displacement, + label, + self.output.len() - 1, + self.current_origin, + )); }, "bsr" => { let label = parser::expect_label(lineno, args)?; self.output.push(0x6100); - self.relocations.push(Relocation::new(RelocationType::Displacement, label, self.output.len() - 1, self.current_origin)); + self.relocations.push(Relocation::new( + RelocationType::Displacement, + label, + self.output.len() - 1, + self.current_origin, + )); }, "illegal" => { self.output.push(0x4AFC); @@ -180,7 +193,8 @@ impl M68kAssembler { "lea" => { parser::expect_args(lineno, args, 2)?; let reg = expect_address_register(lineno, &args[0])?; - let (effective_address, additional_words) = convert_target(lineno, &args[1], Size::Long, Disallow::NoRegsPrePostOrImmediate)?; + let (effective_address, additional_words) = + convert_target(lineno, &args[1], Size::Long, Disallow::NoRegsPrePostOrImmediate)?; self.output.push(0x41C0 | (reg << 9) | effective_address); self.output.extend(additional_words); }, @@ -213,7 +227,8 @@ impl M68kAssembler { } fn convert_sized_instruction(&mut self, lineno: usize, mneumonic: &str, args: &[AssemblyOperand]) -> Result<(), Error> { - let operation_size = get_size_from_mneumonic(mneumonic).ok_or_else(|| Error::new(format!("error at line {}: expected a size specifier (b/w/l)", lineno))); + let operation_size = get_size_from_mneumonic(mneumonic) + .ok_or_else(|| Error::new(format!("error at line {}: expected a size specifier (b/w/l)", lineno))); match &mneumonic[..mneumonic.len() - 1] { "addi" => { self.convert_common_immediate_instruction(lineno, 0x0600, args, operation_size?, Disallow::NoARegImmediateOrPC)?; @@ -229,7 +244,13 @@ impl M68kAssembler { }, "andi" => { if !self.check_convert_flags_instruction(lineno, 0x23C, 0x27C, args)? { - self.convert_common_immediate_instruction(lineno, 0x0200, args, operation_size?, Disallow::NoARegImmediateOrPC)?; + self.convert_common_immediate_instruction( + lineno, + 0x0200, + args, + operation_size?, + Disallow::NoARegImmediateOrPC, + )?; } }, "and" => { @@ -240,7 +261,13 @@ impl M68kAssembler { }, "clr" => { - self.convert_common_single_operand_instruction(lineno, 0x4200, args, operation_size?, Disallow::NoARegImmediateOrPC)?; + self.convert_common_single_operand_instruction( + lineno, + 0x4200, + args, + operation_size?, + Disallow::NoARegImmediateOrPC, + )?; }, "cmpi" => { self.convert_common_immediate_instruction(lineno, 0x0C00, args, operation_size?, Disallow::NoARegImmediateOrPC)?; @@ -251,7 +278,13 @@ impl M68kAssembler { "eori" => { if !self.check_convert_flags_instruction(lineno, 0x0A3C, 0x0A7C, args)? { - self.convert_common_immediate_instruction(lineno, 0x0A00, args, operation_size?, Disallow::NoARegImmediateOrPC)?; + self.convert_common_immediate_instruction( + lineno, + 0x0A00, + args, + operation_size?, + Disallow::NoARegImmediateOrPC, + )?; } }, "eor" => { @@ -265,27 +298,54 @@ impl M68kAssembler { "move" | "movea" => { let operation_size = operation_size?; parser::expect_args(lineno, args, 2)?; - let (effective_address_left, additional_words_left) = convert_target(lineno, &args[0], operation_size, Disallow::None)?; - let (effective_address_right, additional_words_right) = convert_target(lineno, &args[1], operation_size, Disallow::None)?; + let (effective_address_left, additional_words_left) = + convert_target(lineno, &args[0], operation_size, Disallow::None)?; + let (effective_address_right, additional_words_right) = + convert_target(lineno, &args[1], operation_size, Disallow::None)?; let effective_address_left = (effective_address_left >> 3) | (effective_address_left << 3); - self.output.push(encode_size_for_move(operation_size) | effective_address_left | effective_address_right); + self.output + .push(encode_size_for_move(operation_size) | effective_address_left | effective_address_right); self.output.extend(additional_words_left); self.output.extend(additional_words_right); }, "neg" => { - self.convert_common_single_operand_instruction(lineno, 0x4400, args, operation_size?, Disallow::NoARegImmediateOrPC)?; + self.convert_common_single_operand_instruction( + lineno, + 0x4400, + args, + operation_size?, + Disallow::NoARegImmediateOrPC, + )?; }, "negx" => { - self.convert_common_single_operand_instruction(lineno, 0x4000, args, operation_size?, Disallow::NoARegImmediateOrPC)?; + self.convert_common_single_operand_instruction( + lineno, + 0x4000, + args, + operation_size?, + Disallow::NoARegImmediateOrPC, + )?; }, "not" => { - self.convert_common_single_operand_instruction(lineno, 0x4600, args, operation_size?, Disallow::NoARegImmediateOrPC)?; + self.convert_common_single_operand_instruction( + lineno, + 0x4600, + args, + operation_size?, + Disallow::NoARegImmediateOrPC, + )?; }, "ori" => { if !self.check_convert_flags_instruction(lineno, 0x003C, 0x007C, args)? { - self.convert_common_immediate_instruction(lineno, 0x0000, args, operation_size?, Disallow::NoARegImmediateOrPC)?; + self.convert_common_immediate_instruction( + lineno, + 0x0000, + args, + operation_size?, + Disallow::NoARegImmediateOrPC, + )?; } }, "or" => { @@ -319,7 +379,14 @@ impl M68kAssembler { Ok(()) } - fn convert_common_immediate_instruction(&mut self, lineno: usize, opcode: u16, args: &[AssemblyOperand], operation_size: Size, disallow: Disallow) -> Result<(), Error> { + fn convert_common_immediate_instruction( + &mut self, + lineno: usize, + opcode: u16, + args: &[AssemblyOperand], + operation_size: Size, + disallow: Disallow, + ) -> Result<(), Error> { parser::expect_args(lineno, args, 2)?; let immediate = parser::expect_immediate(lineno, &args[0])?; let (effective_address, additional_words) = convert_target(lineno, &args[1], operation_size, disallow)?; @@ -329,27 +396,50 @@ impl M68kAssembler { Ok(()) } - fn convert_common_dreg_instruction(&mut self, lineno: usize, opcode: u16, args: &[AssemblyOperand], operation_size: Size, disallow: Disallow) -> Result<(), Error> { + fn convert_common_dreg_instruction( + &mut self, + lineno: usize, + opcode: u16, + args: &[AssemblyOperand], + operation_size: Size, + disallow: Disallow, + ) -> Result<(), Error> { parser::expect_args(lineno, args, 2)?; let (direction, reg, operand) = convert_reg_and_other(lineno, args, Disallow::NoAReg)?; let (effective_address, additional_words) = convert_target(lineno, operand, operation_size, disallow)?; - self.output.push(opcode | encode_size(operation_size) | direction | (reg << 9) | effective_address); + self.output + .push(opcode | encode_size(operation_size) | direction | (reg << 9) | effective_address); self.output.extend(additional_words); Ok(()) } - fn convert_common_areg_instruction(&mut self, lineno: usize, opcode: u16, args: &[AssemblyOperand], operation_size: Size, disallow: Disallow) -> Result<(), Error> { + fn convert_common_areg_instruction( + &mut self, + lineno: usize, + opcode: u16, + args: &[AssemblyOperand], + operation_size: Size, + disallow: Disallow, + ) -> Result<(), Error> { let size_bit = expect_a_instruction_size(lineno, operation_size)?; parser::expect_args(lineno, args, 2)?; //let (_direction, reg, operand) = convert_reg_and_other(lineno, args, Disallow::NoDReg)?; let reg = expect_address_register(lineno, &args[1])?; let (effective_address, additional_words) = convert_target(lineno, &args[0], operation_size, disallow)?; - self.output.push(opcode | size_bit | (0b11 << 6) | (reg << 9) | effective_address); + self.output + .push(opcode | size_bit | (0b11 << 6) | (reg << 9) | effective_address); self.output.extend(additional_words); Ok(()) } - fn convert_common_single_operand_instruction(&mut self, lineno: usize, opcode: u16, args: &[AssemblyOperand], operation_size: Size, disallow: Disallow) -> Result<(), Error> { + fn convert_common_single_operand_instruction( + &mut self, + lineno: usize, + opcode: u16, + args: &[AssemblyOperand], + operation_size: Size, + disallow: Disallow, + ) -> Result<(), Error> { parser::expect_args(lineno, args, 1)?; let (effective_address, additional_words) = convert_target(lineno, &args[0], operation_size, disallow)?; self.output.push(opcode | encode_size(operation_size) | effective_address); @@ -357,7 +447,13 @@ impl M68kAssembler { Ok(()) } - fn check_convert_flags_instruction(&mut self, lineno: usize, opcode_ccr: u16, opcode_sr: u16, args: &[AssemblyOperand]) -> Result { + fn check_convert_flags_instruction( + &mut self, + lineno: usize, + opcode_ccr: u16, + opcode_sr: u16, + args: &[AssemblyOperand], + ) -> Result { if let AssemblyOperand::Register(name) = &args[1] { let opcode = match name.as_str() { "ccr" => Some(opcode_ccr), @@ -376,32 +472,47 @@ impl M68kAssembler { Ok(false) } - fn convert_common_shift_instruction(&mut self, lineno: usize, mneumonic: &str, opcode: u16, args: &[AssemblyOperand], operation_size: Size) -> Result<(), Error> { + fn convert_common_shift_instruction( + &mut self, + lineno: usize, + mneumonic: &str, + opcode: u16, + args: &[AssemblyOperand], + operation_size: Size, + ) -> Result<(), Error> { let dirstr = &mneumonic[mneumonic.len() - 2..mneumonic.len() - 1]; let direction = if dirstr == "r" { 0 } else if dirstr == "l" { 1 << 8 } else { - return Err(Error::new(format!("error at line {}: expected direction of (l)eft or (r)ight, but found {:?}", lineno, dirstr))); + return Err(Error::new(format!( + "error at line {}: expected direction of (l)eft or (r)ight, but found {:?}", + lineno, dirstr + ))); }; match &args { [AssemblyOperand::Immediate(_), AssemblyOperand::Register(_)] => { let mut immediate = parser::expect_immediate(lineno, &args[0])?; if !(1..=8).contains(&immediate) { - return Err(Error::new(format!("error at line {}: immediate value must be between 1 and 8, found {:?}", lineno, args))); + return Err(Error::new(format!( + "error at line {}: immediate value must be between 1 and 8, found {:?}", + lineno, args + ))); } else if immediate == 8 { immediate = 0; } let reg = expect_data_register(lineno, &args[1])?; - self.output.push(opcode | ((immediate as u16) << 9) | direction | encode_size(operation_size) /*(0b0 << 5)*/ | reg); + self.output + .push(opcode | ((immediate as u16) << 9) | direction | encode_size(operation_size) /*(0b0 << 5)*/ | reg); }, [AssemblyOperand::Register(_), AssemblyOperand::Register(_)] => { let bit_reg = expect_data_register(lineno, &args[0])?; let reg = expect_data_register(lineno, &args[1])?; - self.output.push(opcode | (bit_reg << 9) | direction | encode_size(operation_size) | (0b1 << 5) | reg); + self.output + .push(opcode | (bit_reg << 9) | direction | encode_size(operation_size) | (0b1 << 5) | reg); }, //[_] => { // let (effective_address, additional_words) = convert_target(lineno, &args[0], Size::Word, Disallow::NoRegsImmediateOrPC)?; @@ -416,16 +527,12 @@ impl M68kAssembler { fn convert_target(lineno: usize, operand: &AssemblyOperand, size: Size, disallow: Disallow) -> Result<(u16, Vec), Error> { match operand { - AssemblyOperand::Register(name) => { - convert_register(lineno, name, disallow) - }, + AssemblyOperand::Register(name) => convert_register(lineno, name, disallow), AssemblyOperand::Immediate(value) => { disallow.check(lineno, Disallow::NoImmediate)?; Ok((0b111100, convert_immediate(lineno, *value, size)?)) }, - AssemblyOperand::Indirect(args) => { - convert_indirect(lineno, args, disallow) - }, + AssemblyOperand::Indirect(args) => convert_indirect(lineno, args, disallow), AssemblyOperand::IndirectPost(args, operator) => { disallow.check(lineno, Disallow::NoIndirectPost)?; if args.len() == 1 && operator == "+" { @@ -436,7 +543,10 @@ fn convert_target(lineno: usize, operand: &AssemblyOperand, size: Size, disallow } } } - Err(Error::new(format!("error at line {}: post-increment operator can only be used with a single address register", lineno))) + Err(Error::new(format!( + "error at line {}: post-increment operator can only be used with a single address register", + lineno + ))) }, AssemblyOperand::IndirectPre(operator, args) => { disallow.check(lineno, Disallow::NoIndirectPre)?; @@ -450,7 +560,10 @@ fn convert_target(lineno: usize, operand: &AssemblyOperand, size: Size, disallow } } } - Err(Error::new(format!("error at line {}: pre-decrement operator can only be used with a single address register", lineno))) + Err(Error::new(format!( + "error at line {}: pre-decrement operator can only be used with a single address register", + lineno + ))) }, _ => Err(Error::new(format!("not implemented: {:?}", operand))), } @@ -514,23 +627,25 @@ fn convert_indirect(lineno: usize, args: &[AssemblyOperand], disallow: Disallow) } }, // TODO add the MC68020 address options - _ => { - Err(Error::new(format!("error at line {}: expected valid indirect addressing mode, but found {:?}", lineno, args))) - } + _ => Err(Error::new(format!( + "error at line {}: expected valid indirect addressing mode, but found {:?}", + lineno, args + ))), } } -fn convert_reg_and_other(lineno: usize, args: &[AssemblyOperand], _disallow: Disallow) -> Result<(u16, u16, &AssemblyOperand), Error> { +fn convert_reg_and_other( + lineno: usize, + args: &[AssemblyOperand], + _disallow: Disallow, +) -> Result<(u16, u16, &AssemblyOperand), Error> { match &args { - [AssemblyOperand::Register(reg), effective_address] => { - Ok(((0b1 << 8), expect_reg_num(lineno, reg)?, effective_address)) - }, - [effective_address, AssemblyOperand::Register(reg)] => { - Ok(((0b0 << 8), expect_reg_num(lineno, reg)?, effective_address)) - }, - _ => { - Err(Error::new(format!("error at line {}: expected register and effective address, but found {:?}", lineno, args))) - } + [AssemblyOperand::Register(reg), effective_address] => Ok(((0b1 << 8), expect_reg_num(lineno, reg)?, effective_address)), + [effective_address, AssemblyOperand::Register(reg)] => Ok(((0b0 << 8), expect_reg_num(lineno, reg)?, effective_address)), + _ => Err(Error::new(format!( + "error at line {}: expected register and effective address, but found {:?}", + lineno, args + ))), } } @@ -540,14 +655,24 @@ fn convert_immediate(lineno: usize, value: usize, size: Size) -> Result if value <= u8::MAX as usize { Ok(vec![value as u16]) } else { - Err(Error::new(format!("error at line {}: immediate number is out of range; must be less than {}, but number is {:?}", lineno, u8::MAX, value))) + Err(Error::new(format!( + "error at line {}: immediate number is out of range; must be less than {}, but number is {:?}", + lineno, + u8::MAX, + value + ))) } }, Size::Word => { if value <= u16::MAX as usize { Ok(vec![value as u16]) } else { - Err(Error::new(format!("error at line {}: immediate number is out of range; must be less than {}, but number is {:?}", lineno, u16::MAX, value))) + Err(Error::new(format!( + "error at line {}: immediate number is out of range; must be less than {}, but number is {:?}", + lineno, + u16::MAX, + value + ))) } }, Size::Long => Ok(vec![(value >> 16) as u16, value as u16]), @@ -569,7 +694,10 @@ fn expect_address_register(lineno: usize, operand: &AssemblyOperand) -> Result Result { @@ -603,7 +731,7 @@ fn get_size_from_mneumonic(s: &str) -> Option { 'b' => Some(Size::Byte), 'w' => Some(Size::Word), 'l' => Some(Size::Long), - _ => None + _ => None, } } @@ -628,7 +756,6 @@ fn encode_size_bit(size: Size) -> Result { match size { Size::Word => Ok(0b01 << 6), Size::Long => Ok(0b10 << 6), - _ => Err(Error::new(format!("invalid size for this operation: {:?}", size))) + _ => Err(Error::new(format!("invalid size for this operation: {:?}", size))), } } - diff --git a/emulator/cpus/m68k/src/bin/m68kas.rs b/emulator/cpus/m68k/src/bin/m68kas.rs index 5681b9b..557ccf3 100644 --- a/emulator/cpus/m68k/src/bin/m68kas.rs +++ b/emulator/cpus/m68k/src/bin/m68kas.rs @@ -1,4 +1,3 @@ - use std::fs; use std::env; @@ -24,4 +23,3 @@ fn main() { }, }; } - diff --git a/emulator/cpus/m68k/src/debugger.rs b/emulator/cpus/m68k/src/debugger.rs index 7f5c709..95b7d93 100644 --- a/emulator/cpus/m68k/src/debugger.rs +++ b/emulator/cpus/m68k/src/debugger.rs @@ -1,4 +1,3 @@ - use femtos::Instant; use emulator_hal::bus::BusAccess; @@ -50,4 +49,3 @@ where Ok(()) } } - diff --git a/emulator/cpus/m68k/src/decode.rs b/emulator/cpus/m68k/src/decode.rs index 8c31f66..7b793d8 100644 --- a/emulator/cpus/m68k/src/decode.rs +++ b/emulator/cpus/m68k/src/decode.rs @@ -1,21 +1,10 @@ - use femtos::Instant; use emulator_hal::bus::BusAccess; use crate::state::{M68kType, M68kError, Exceptions}; use crate::memory::{M68kBusPort, M68kAddress}; use crate::instructions::{ - Size, - Sign, - Direction, - XRegister, - BaseRegister, - IndexRegister, - RegOrImmediate, - ControlRegister, - Condition, - Target, - Instruction, + Size, Sign, Direction, XRegister, BaseRegister, IndexRegister, RegOrImmediate, ControlRegister, Condition, Target, Instruction, sign_extend_to_long, }; @@ -78,7 +67,13 @@ impl M68kDecoder { } #[inline] - pub fn decode_at(&mut self, bus: &mut Bus, memory: &mut M68kBusPort, is_supervisor: bool, start: u32) -> Result<(), M68kError> + pub fn decode_at( + &mut self, + bus: &mut Bus, + memory: &mut M68kBusPort, + is_supervisor: bool, + start: u32, + ) -> Result<(), M68kError> where Bus: BusAccess, { @@ -119,10 +114,9 @@ impl M68kDecoder { where Bus: BusAccess, { - let ins_data: Result> = - (0..((self.end - self.start) / 2)).map(|offset| - Ok(format!("{:04x} ", bus.read_beu16(clock, self.start + (offset * 2)).unwrap())) - ).collect(); + let ins_data: Result> = (0..((self.end - self.start) / 2)) + .map(|offset| Ok(format!("{:04x} ", bus.read_beu16(clock, self.start + (offset * 2)).unwrap()))) + .collect(); println!("{:#010x}: {}\n\t{}\n", self.start, ins_data.unwrap(), self.instruction); } } @@ -186,7 +180,11 @@ where } else if (ins & 0x138) == 0x108 { let dreg = get_high_reg(ins); let areg = get_low_reg(ins); - let dir = if (ins & 0x0080) == 0 { Direction::FromTarget } else { Direction::ToTarget }; + let dir = if (ins & 0x0080) == 0 { + Direction::FromTarget + } else { + Direction::ToTarget + }; let size = if (ins & 0x0040) == 0 { Size::Word } else { Size::Long }; let offset = self.read_instruction_word()? as i16; Ok(Instruction::MOVEP(dreg, areg, offset, size, dir)) @@ -288,11 +286,19 @@ where let size = if (ins & 0x0040) == 0 { Size::Word } else { Size::Long }; let data = self.read_instruction_word()?; let target = self.decode_lower_effective_address(ins, None)?; - let dir = if (ins & 0x0400) == 0 { Direction::ToTarget } else { Direction::FromTarget }; + let dir = if (ins & 0x0400) == 0 { + Direction::ToTarget + } else { + Direction::FromTarget + }; Ok(Instruction::MOVEM(target, size, dir, data)) } else if (ins & 0xF80) == 0xC00 && self.decoder.cputype >= M68kType::MC68020 { let extension = self.read_instruction_word()?; - let reg_h = if (extension & 0x0400) != 0 { Some(get_low_reg(ins)) } else { None }; + let reg_h = if (extension & 0x0400) != 0 { + Some(get_low_reg(ins)) + } else { + None + }; let reg_l = ((extension & 0x7000) >> 12) as u8; let target = self.decode_lower_effective_address(ins, Some(Size::Long))?; let sign = if (ins & 0x0800) == 0 { Sign::Unsigned } else { Sign::Signed }; @@ -303,30 +309,22 @@ where } else if (ins & 0x800) == 0 { let target = self.decode_lower_effective_address(ins, Some(Size::Word))?; match (ins & 0x0700) >> 8 { - 0b000 => { - match get_size(ins) { - Some(size) => Ok(Instruction::NEGX(target, size)), - None => Ok(Instruction::MOVEfromSR(target)), - } + 0b000 => match get_size(ins) { + Some(size) => Ok(Instruction::NEGX(target, size)), + None => Ok(Instruction::MOVEfromSR(target)), }, - 0b010 => { - match get_size(ins) { - Some(size) => Ok(Instruction::CLR(target, size)), - None if self.decoder.cputype >= M68kType::MC68010 => Ok(Instruction::MOVEfromCCR(target)), - None => Err(M68kError::Exception(Exceptions::IllegalInstruction)), - } + 0b010 => match get_size(ins) { + Some(size) => Ok(Instruction::CLR(target, size)), + None if self.decoder.cputype >= M68kType::MC68010 => Ok(Instruction::MOVEfromCCR(target)), + None => Err(M68kError::Exception(Exceptions::IllegalInstruction)), }, - 0b100 => { - match get_size(ins) { - Some(size) => Ok(Instruction::NEG(target, size)), - None => Ok(Instruction::MOVEtoCCR(target)), - } + 0b100 => match get_size(ins) { + Some(size) => Ok(Instruction::NEG(target, size)), + None => Ok(Instruction::MOVEtoCCR(target)), }, - 0b110 => { - match get_size(ins) { - Some(size) => Ok(Instruction::NOT(target, size)), - None => Ok(Instruction::MOVEtoSR(target)), - } + 0b110 => match get_size(ins) { + Some(size) => Ok(Instruction::NOT(target, size)), + None => Ok(Instruction::MOVEtoSR(target)), }, _ => Err(M68kError::Exception(Exceptions::IllegalInstruction)), } @@ -342,25 +340,15 @@ where let target = self.decode_lower_effective_address(ins, Some(Size::Byte))?; Ok(Instruction::NBCD(target)) }, - (0b001, 0b000) => { - Ok(Instruction::SWAP(get_low_reg(ins))) - }, - (0b001, 0b001) => { - Ok(Instruction::BKPT(get_low_reg(ins))) - }, + (0b001, 0b000) => Ok(Instruction::SWAP(get_low_reg(ins))), + (0b001, 0b001) => Ok(Instruction::BKPT(get_low_reg(ins))), (0b001, _) => { let target = self.decode_lower_effective_address(ins, None)?; Ok(Instruction::PEA(target)) }, - (0b010, 0b000) => { - Ok(Instruction::EXT(get_low_reg(ins), Size::Byte, Size::Word)) - }, - (0b011, 0b000) => { - Ok(Instruction::EXT(get_low_reg(ins), Size::Word, Size::Long)) - }, - (0b111, 0b000) => { - Ok(Instruction::EXT(get_low_reg(ins), Size::Byte, Size::Long)) - }, + (0b010, 0b000) => Ok(Instruction::EXT(get_low_reg(ins), Size::Byte, Size::Word)), + (0b011, 0b000) => Ok(Instruction::EXT(get_low_reg(ins), Size::Word, Size::Long)), + (0b111, 0b000) => Ok(Instruction::EXT(get_low_reg(ins), Size::Byte, Size::Long)), _ => Err(M68kError::Exception(Exceptions::IllegalInstruction)), } } else if ins_0f00 == 0xA00 { @@ -393,7 +381,11 @@ where } } else if ins_00f0 == 0x60 { let reg = get_low_reg(ins); - let dir = if (ins & 0b1000) == 0 { Direction::FromTarget } else { Direction::ToTarget }; + let dir = if (ins & 0b1000) == 0 { + Direction::FromTarget + } else { + Direction::ToTarget + }; Ok(Instruction::MOVEUSP(Target::DirectAReg(reg), dir)) } else { match ins & 0x00FF { @@ -412,7 +404,11 @@ where 0x76 => Ok(Instruction::TRAPV), 0x77 => Ok(Instruction::RTR), 0x7A | 0x7B if self.decoder.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()?; let target = match ins2 & 0x8000 { 0 => Target::DirectDReg(((ins2 & 0x7000) >> 12) as u8), @@ -511,7 +507,11 @@ where } else if let Some(size) = size { let data_reg = Target::DirectDReg(get_high_reg(ins)); let effective_addr = self.decode_lower_effective_address(ins, Some(size))?; - let (from, to) = if (ins & 0x0100) == 0 { (effective_addr, data_reg) } else { (data_reg, effective_addr) }; + let (from, to) = if (ins & 0x0100) == 0 { + (effective_addr, data_reg) + } else { + (data_reg, effective_addr) + }; Ok(Instruction::OR(from, to, size)) } else { let sign = if (ins & 0x0100) == 0 { Sign::Unsigned } else { Sign::Signed }; @@ -602,7 +602,11 @@ where } else if let Some(size) = size { let data_reg = Target::DirectDReg(get_high_reg(ins)); let effective_addr = self.decode_lower_effective_address(ins, Some(size))?; - let (from, to) = if (ins & 0x0100) == 0 { (effective_addr, data_reg) } else { (data_reg, effective_addr) }; + let (from, to) = if (ins & 0x0100) == 0 { + (effective_addr, data_reg) + } else { + (data_reg, effective_addr) + }; Ok(Instruction::AND(from, to, size)) } else { let sign = if (ins & 0x0100) == 0 { Sign::Unsigned } else { Sign::Signed }; @@ -729,13 +733,17 @@ where } fn read_instruction_word(&mut self) -> Result> { - let word = self.memory.read_instruction_word(self.bus, self.decoder.is_supervisor, self.decoder.end)?; + let word = self + .memory + .read_instruction_word(self.bus, self.decoder.is_supervisor, self.decoder.end)?; self.decoder.end += 2; Ok(word) } fn read_instruction_long(&mut self) -> Result> { - let word = self.memory.read_instruction_long(self.bus, self.decoder.is_supervisor, self.decoder.end)?; + let word = self + .memory + .read_instruction_long(self.bus, self.decoder.is_supervisor, self.decoder.end)?; self.decoder.end += 4; Ok(word) } @@ -769,11 +777,23 @@ where // Decode Index Register let xreg_num = ((brief_extension & 0x7000) >> 12) as u8; - let xreg = if (brief_extension & 0x8000) == 0 { XRegister::DReg(xreg_num) } else { XRegister::AReg(xreg_num) }; - let size = if (brief_extension & 0x0800) == 0 { Size::Word } else { Size::Long }; + let xreg = if (brief_extension & 0x8000) == 0 { + XRegister::DReg(xreg_num) + } else { + XRegister::AReg(xreg_num) + }; + let size = if (brief_extension & 0x0800) == 0 { + Size::Word + } else { + Size::Long + }; if self.decoder.cputype <= M68kType::MC68010 { - let index_reg = IndexRegister { xreg, scale: 0, size }; + let index_reg = IndexRegister { + xreg, + scale: 0, + size, + }; let displacement = sign_extend_to_long((brief_extension & 0x00FF) as u32, Size::Byte); match areg { @@ -782,7 +802,11 @@ where } } else if use_brief { let scale = ((brief_extension & 0x0600) >> 9) as u8; - let index_reg = IndexRegister { xreg, scale, size }; + let index_reg = IndexRegister { + xreg, + scale, + size, + }; let displacement = sign_extend_to_long((brief_extension & 0x00FF) as u32, Size::Byte); match areg { @@ -791,7 +815,11 @@ where } } else { let scale = ((brief_extension & 0x0600) >> 9) as u8; - let index_reg = IndexRegister { xreg, scale, size }; + let index_reg = IndexRegister { + xreg, + scale, + size, + }; let use_base_reg = (brief_extension & 0x0080) == 0; let use_index = (brief_extension & 0x0040) == 0; @@ -826,43 +854,35 @@ where let displacement = sign_extend_to_long(self.read_instruction_word()? as u32, Size::Word); Target::IndirectRegOffset(BaseRegister::AReg(reg), None, displacement) }, - 0b110 => { - self.decode_extension_word(Some(reg))? - }, - 0b111 => { - match reg { - 0b000 => { - let value = sign_extend_to_long(self.read_instruction_word()? as u32, Size::Word) as u32; - Target::IndirectMemory(value, Size::Word) - }, - 0b001 => { - let value = self.read_instruction_long()?; - Target::IndirectMemory(value, Size::Long) - }, - 0b010 => { - let displacement = sign_extend_to_long(self.read_instruction_word()? as u32, Size::Word); - Target::IndirectRegOffset(BaseRegister::PC, None, displacement) - }, - 0b011 => { - self.decode_extension_word(None)? - }, - 0b100 => { - let data = match size { - Some(Size::Byte) | Some(Size::Word) => self.read_instruction_word()? as u32, - Some(Size::Long) => self.read_instruction_long()?, - None => return Err(M68kError::Exception(Exceptions::IllegalInstruction)), - }; - Target::Immediate(data) - }, - _ => return Err(M68kError::Exception(Exceptions::IllegalInstruction)), - } + 0b110 => self.decode_extension_word(Some(reg))?, + 0b111 => match reg { + 0b000 => { + let value = sign_extend_to_long(self.read_instruction_word()? as u32, Size::Word) as u32; + Target::IndirectMemory(value, Size::Word) + }, + 0b001 => { + let value = self.read_instruction_long()?; + Target::IndirectMemory(value, Size::Long) + }, + 0b010 => { + let displacement = sign_extend_to_long(self.read_instruction_word()? as u32, Size::Word); + Target::IndirectRegOffset(BaseRegister::PC, None, displacement) + }, + 0b011 => self.decode_extension_word(None)?, + 0b100 => { + let data = match size { + Some(Size::Byte) | Some(Size::Word) => self.read_instruction_word()? as u32, + Some(Size::Long) => self.read_instruction_long()?, + None => return Err(M68kError::Exception(Exceptions::IllegalInstruction)), + }; + Target::Immediate(data) + }, + _ => return Err(M68kError::Exception(Exceptions::IllegalInstruction)), }, _ => return Err(M68kError::Exception(Exceptions::IllegalInstruction)), }; Ok(value) } - - } #[inline(always)] @@ -917,4 +937,3 @@ fn get_condition(ins: u16) -> Condition { _ => Condition::True, } } - diff --git a/emulator/cpus/m68k/src/execute.rs b/emulator/cpus/m68k/src/execute.rs index 8aeca3c..9715387 100644 --- a/emulator/cpus/m68k/src/execute.rs +++ b/emulator/cpus/m68k/src/execute.rs @@ -1,4 +1,3 @@ - use femtos::Instant; use emulator_hal::bus::{self, BusAccess}; use emulator_hal::step::Step; @@ -9,19 +8,8 @@ use crate::decode::M68kDecoder; use crate::debugger::M68kDebugger; use crate::timing::M68kInstructionTiming; use crate::instructions::{ - Register, - Size, - Sign, - Direction, - XRegister, - BaseRegister, - IndexRegister, - RegOrImmediate, - ControlRegister, - Condition, - Target, - Instruction, - sign_extend_to_long, + Register, Size, Sign, Direction, XRegister, BaseRegister, IndexRegister, RegOrImmediate, ControlRegister, Condition, Target, + Instruction, sign_extend_to_long, }; @@ -55,7 +43,7 @@ impl M68kCycle { #[inline] pub fn new(cpu: &M68k, clock: Instant) -> Self { - let is_supervisor = cpu.state.sr & (Flags:: Supervisor as u16) != 0; + let is_supervisor = cpu.state.sr & (Flags::Supervisor as u16) != 0; Self { decoder: M68kDecoder::new(cpu.info.chip, is_supervisor, cpu.state.pc), timing: M68kInstructionTiming::new(cpu.info.chip, cpu.info.data_width as u8), @@ -174,7 +162,10 @@ where } #[inline] - pub fn check_pending_interrupts(&mut self, interrupt: (bool, u8, u8)) -> Result<(InterruptPriority, Option), M68kError> { + pub fn check_pending_interrupts( + &mut self, + interrupt: (bool, u8, u8), + ) -> Result<(InterruptPriority, Option), M68kError> { let ack_num; (self.state.pending_ipl, ack_num) = match interrupt { (true, priority, ack) => (InterruptPriority::from_u8(priority), ack), @@ -300,7 +291,9 @@ where #[inline] pub fn decode_next(&mut self) -> Result<(), M68kError> { let is_supervisor = self.is_supervisor(); - self.cycle.decoder.decode_at(&mut self.bus, &mut self.cycle.memory, is_supervisor, self.state.pc)?; + self.cycle + .decoder + .decode_at(&mut self.bus, &mut self.cycle.memory, is_supervisor, self.state.pc)?; self.cycle.timing.add_instruction(&self.cycle.decoder.instruction); @@ -400,7 +393,9 @@ where Instruction::UNLK(reg) => self.execute_unlk(reg), Instruction::UnimplementedA(value) => self.execute_unimplemented_a(value), Instruction::UnimplementedF(value) => self.execute_unimplemented_f(value), - _ => { return Err(M68kError::Other("Unsupported instruction".to_string())); }, + _ => { + return Err(M68kError::Other("Unsupported instruction".to_string())); + }, }?; Ok(()) @@ -416,9 +411,13 @@ where let binary_result = src_val.wrapping_add(dest_val).wrapping_add(extend_flag); let mut result = src_parts.1.wrapping_add(dest_parts.1).wrapping_add(extend_flag); - if result > 0x09 { result = result.wrapping_add(0x06) }; + if result > 0x09 { + result = result.wrapping_add(0x06) + }; result += src_parts.0 + dest_parts.0; - if result > 0x99 { result = result.wrapping_add(0x60) }; + if result > 0x99 { + result = result.wrapping_add(0x60) + }; let carry = (result & 0xFFFFFF00) != 0; self.set_target_value(dest, result, Size::Byte, Used::Twice)?; @@ -607,7 +606,12 @@ where Ok(()) } - fn execute_bfchg(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate) -> Result<(), M68kError> { + fn execute_bfchg( + &mut self, + target: Target, + offset: RegOrImmediate, + width: RegOrImmediate, + ) -> Result<(), M68kError> { let (offset, width) = self.get_bit_field_args(offset, width); let mask = get_bit_field_mask(offset, width); let value = self.get_target_value(target, Size::Long, Used::Twice)?; @@ -617,7 +621,12 @@ where Ok(()) } - fn execute_bfclr(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate) -> Result<(), M68kError> { + fn execute_bfclr( + &mut self, + target: Target, + offset: RegOrImmediate, + width: RegOrImmediate, + ) -> Result<(), M68kError> { let (offset, width) = self.get_bit_field_args(offset, width); let mask = get_bit_field_mask(offset, width); let value = self.get_target_value(target, Size::Long, Used::Twice)?; @@ -627,7 +636,13 @@ where Ok(()) } - fn execute_bfexts(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate, reg: Register) -> Result<(), M68kError> { + fn execute_bfexts( + &mut self, + target: Target, + offset: RegOrImmediate, + width: RegOrImmediate, + reg: Register, + ) -> Result<(), M68kError> { let (offset, width) = self.get_bit_field_args(offset, width); let mask = get_bit_field_mask(offset, width); let value = self.get_target_value(target, Size::Long, Used::Once)?; @@ -643,7 +658,13 @@ where Ok(()) } - fn execute_bfextu(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate, reg: Register) -> Result<(), M68kError> { + fn execute_bfextu( + &mut self, + target: Target, + offset: RegOrImmediate, + width: RegOrImmediate, + reg: Register, + ) -> Result<(), M68kError> { let (offset, width) = self.get_bit_field_args(offset, width); let mask = get_bit_field_mask(offset, width); let value = self.get_target_value(target, Size::Long, Used::Once)?; @@ -653,7 +674,12 @@ where Ok(()) } - fn execute_bfset(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate) -> Result<(), M68kError> { + fn execute_bfset( + &mut self, + target: Target, + offset: RegOrImmediate, + width: RegOrImmediate, + ) -> Result<(), M68kError> { let (offset, width) = self.get_bit_field_args(offset, width); let mask = get_bit_field_mask(offset, width); let value = self.get_target_value(target, Size::Long, Used::Twice)?; @@ -663,7 +689,12 @@ where Ok(()) } - fn execute_bftst(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate) -> Result<(), M68kError> { + fn execute_bftst( + &mut self, + target: Target, + offset: RegOrImmediate, + width: RegOrImmediate, + ) -> Result<(), M68kError> { let (offset, width) = self.get_bit_field_args(offset, width); let mask = get_bit_field_mask(offset, width); let value = self.get_target_value(target, Size::Long, Used::Once)?; @@ -749,16 +780,12 @@ where ( (dest_val % src_val) as u32, quotient as u32, - quotient > i16::MAX as i32 || quotient < i16::MIN as i32 + quotient > i16::MAX as i32 || quotient < i16::MIN as i32, ) }, Sign::Unsigned => { let quotient = dest_val / src_val; - ( - dest_val % src_val, - quotient, - (quotient & 0xFFFF0000) != 0 - ) + (dest_val % src_val, quotient, (quotient & 0xFFFF0000) != 0) }, }; @@ -773,7 +800,13 @@ where Ok(()) } - fn execute_divl(&mut self, src: Target, dest_h: Option, dest_l: Register, sign: Sign) -> Result<(), M68kError> { + fn execute_divl( + &mut self, + src: Target, + dest_h: Option, + dest_l: Register, + sign: Sign, + ) -> Result<(), M68kError> { let src_val = self.get_target_value(src, Size::Long, Used::Once)?; if src_val == 0 { self.exception(Exceptions::ZeroDivide as u8, false)?; @@ -988,8 +1021,8 @@ where Target::IndirectARegInc(reg) | Target::IndirectARegDec(reg) => { let a_reg_mut = self.get_a_reg_mut(reg); *a_reg_mut = addr + (mask.count_ones() * size.in_bytes()); - } - _ => { }, + }, + _ => {}, } } @@ -1006,11 +1039,9 @@ where } self.move_registers_to_memory_reverse(addr, size, mask)? }, - _ => { - match dir { - Direction::ToTarget => self.move_registers_to_memory(addr, size, mask)?, - Direction::FromTarget => self.move_memory_to_registers(addr, size, mask)?, - } + _ => match dir { + Direction::ToTarget => self.move_registers_to_memory(addr, size, mask)?, + Direction::FromTarget => self.move_memory_to_registers(addr, size, mask)?, }, }; @@ -1019,8 +1050,8 @@ where Target::IndirectARegInc(reg) | Target::IndirectARegDec(reg) => { let a_reg_mut = self.get_a_reg_mut(reg); *a_reg_mut = post_addr; - } - _ => { }, + }, + _ => {}, } Ok(()) @@ -1082,7 +1113,14 @@ where Ok(addr) } - fn execute_movep(&mut self, dreg: Register, areg: Register, offset: i16, size: Size, dir: Direction) -> Result<(), M68kError> { + fn execute_movep( + &mut self, + dreg: Register, + areg: Register, + offset: i16, + size: Size, + dir: Direction, + ) -> Result<(), M68kError> { match dir { Direction::ToTarget => { let mut shift = (size.in_bits() as i32) - 8; @@ -1119,7 +1157,9 @@ where self.require_supervisor()?; match dir { Direction::ToTarget => self.set_target_value(target, self.state.usp, Size::Long, Used::Once)?, - Direction::FromTarget => { self.state.usp = self.get_target_value(target, Size::Long, Used::Once)?; }, + Direction::FromTarget => { + self.state.usp = self.get_target_value(target, Size::Long, Used::Once)?; + }, } Ok(()) } @@ -1137,7 +1177,13 @@ where Ok(()) } - fn execute_mull(&mut self, src: Target, dest_h: Option, dest_l: Register, sign: Sign) -> Result<(), M68kError> { + fn execute_mull( + &mut self, + src: Target, + dest_h: Option, + dest_l: Register, + sign: Sign, + ) -> Result<(), M68kError> { let src_val = self.get_target_value(src, Size::Long, Used::Once)?; let dest_val = get_value_sized(self.state.d_reg[dest_l as usize], Size::Long); let result = match sign { @@ -1353,10 +1399,14 @@ where let binary_result = dest_val.wrapping_sub(src_val).wrapping_sub(extend_flag); let mut result = dest_parts.1.wrapping_sub(src_parts.1).wrapping_sub(extend_flag); - if (result & 0x1F) > 0x09 { result -= 0x06 }; + if (result & 0x1F) > 0x09 { + result -= 0x06 + }; result = result.wrapping_add(dest_parts.0.wrapping_sub(src_parts.0)); let carry = (result & 0x1FF) > 0x99; - if carry { result -= 0x60 }; + if carry { + result -= 0x60 + }; self.set_flag(Flags::Negative, get_msb(result, Size::Byte)); self.set_flag(Flags::Zero, (result & 0xFF) == 0); @@ -1489,7 +1539,8 @@ where Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => { let base_value = self.get_base_reg_value(base_reg); let index_value = self.get_index_reg_value(&index_reg); - let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32), Size::Long)?; + let intermediate = + self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32), Size::Long)?; self.get_address_sized(intermediate.wrapping_add(outer_disp as u32), size) }, Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => { @@ -1498,13 +1549,17 @@ where let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32), Size::Long)?; self.get_address_sized(intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32), size) }, - Target::IndirectMemory(addr, _) => { - self.get_address_sized(addr, size) - }, + Target::IndirectMemory(addr, _) => self.get_address_sized(addr, size), } } - pub(super) fn set_target_value(&mut self, target: Target, value: u32, size: Size, used: Used) -> Result<(), M68kError> { + pub(super) fn set_target_value( + &mut self, + target: Target, + value: u32, + size: Size, + used: Used, + ) -> Result<(), M68kError> { match target { Target::DirectDReg(reg) => { set_value_sized(&mut self.state.d_reg[reg as usize], value, size); @@ -1532,7 +1587,8 @@ where Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => { let base_value = self.get_base_reg_value(base_reg); let index_value = self.get_index_reg_value(&index_reg); - let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32), Size::Long)?; + let intermediate = + self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32), Size::Long)?; self.set_address_sized(intermediate.wrapping_add(outer_disp as u32), value, size)?; }, Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => { @@ -1560,7 +1616,8 @@ where Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => { let base_value = self.get_base_reg_value(base_reg); let index_value = self.get_index_reg_value(&index_reg); - let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32), Size::Long)?; + let intermediate = + self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32), Size::Long)?; intermediate.wrapping_add(outer_disp as u32) }, Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => { @@ -1569,9 +1626,7 @@ where let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32), Size::Long)?; intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32) }, - Target::IndirectMemory(addr, _) => { - addr - }, + Target::IndirectMemory(addr, _) => addr, _ => return Err(M68kError::InvalidTarget(target)), }; Ok(addr) @@ -1611,21 +1666,28 @@ where fn set_address_sized(&mut self, addr: M68kAddress, value: u32, size: Size) -> Result<(), M68kError> { let is_supervisor = self.is_supervisor(); - self.cycle.memory.write_data_sized(&mut self.bus, is_supervisor, addr, size, value) + self.cycle + .memory + .write_data_sized(&mut self.bus, is_supervisor, addr, size, value) } fn push_word(&mut self, value: u16) -> Result<(), M68kError> { let is_supervisor = self.is_supervisor(); *self.get_stack_pointer_mut() -= 2; let addr = *self.get_stack_pointer_mut(); - self.cycle.memory.write_data_sized(&mut self.bus, is_supervisor, addr, Size::Word, value as u32)?; + self.cycle + .memory + .write_data_sized(&mut self.bus, is_supervisor, addr, Size::Word, value as u32)?; Ok(()) } fn pop_word(&mut self) -> Result> { let is_supervisor = self.is_supervisor(); let addr = *self.get_stack_pointer_mut(); - let value = self.cycle.memory.read_data_sized(&mut self.bus, is_supervisor, addr, Size::Word)?; + let value = self + .cycle + .memory + .read_data_sized(&mut self.bus, is_supervisor, addr, Size::Word)?; *self.get_stack_pointer_mut() += 2; Ok(value as u16) } @@ -1634,21 +1696,33 @@ where let is_supervisor = self.is_supervisor(); *self.get_stack_pointer_mut() -= 4; let addr = *self.get_stack_pointer_mut(); - self.cycle.memory.write_data_sized(&mut self.bus, is_supervisor, addr, Size::Long, value)?; + self.cycle + .memory + .write_data_sized(&mut self.bus, is_supervisor, addr, Size::Long, value)?; Ok(()) } fn pop_long(&mut self) -> Result> { let is_supervisor = self.is_supervisor(); let addr = *self.get_stack_pointer_mut(); - let value = self.cycle.memory.read_data_sized(&mut self.bus, is_supervisor, addr, Size::Long)?; + let value = self + .cycle + .memory + .read_data_sized(&mut self.bus, is_supervisor, addr, Size::Long)?; *self.get_stack_pointer_mut() += 4; Ok(value) } fn set_pc(&mut self, value: u32) -> Result<(), M68kError> { self.state.pc = value; - self.cycle.memory.start_request(self.is_supervisor(), self.state.pc, Size::Word, MemAccess::Read, MemType::Program, true)?; + self.cycle.memory.start_request( + self.is_supervisor(), + self.state.pc, + Size::Word, + MemAccess::Read, + MemType::Program, + true, + )?; Ok(()) } @@ -1679,7 +1753,13 @@ where match base_reg { BaseRegister::None => 0, BaseRegister::PC => self.cycle.decoder.start + 2, - BaseRegister::AReg(7) => if self.is_supervisor() { self.state.ssp } else { self.state.usp }, + BaseRegister::AReg(7) => { + if self.is_supervisor() { + self.state.ssp + } else { + self.state.usp + } + }, BaseRegister::AReg(reg) => self.state.a_reg[reg as usize], } } @@ -1687,9 +1767,11 @@ where fn get_index_reg_value(&self, index_reg: &Option) -> i32 { match index_reg { None => 0, - Some(IndexRegister { xreg, scale, size }) => { - sign_extend_to_long(self.get_x_reg_value(*xreg), *size) << scale - } + Some(IndexRegister { + xreg, + scale, + size, + }) => sign_extend_to_long(self.get_x_reg_value(*xreg), *size) << scale, } } @@ -1700,12 +1782,20 @@ where } fn get_stack_pointer_mut(&mut self) -> &mut u32 { - if self.is_supervisor() { &mut self.state.ssp } else { &mut self.state.usp } + if self.is_supervisor() { + &mut self.state.ssp + } else { + &mut self.state.usp + } } fn get_a_reg(&self, reg: Register) -> u32 { if reg == 7 { - if self.is_supervisor() { self.state.ssp } else { self.state.usp } + if self.is_supervisor() { + self.state.ssp + } else { + self.state.usp + } } else { self.state.a_reg[reg as usize] } @@ -1713,14 +1803,18 @@ where fn get_a_reg_mut(&mut self, reg: Register) -> &mut u32 { if reg == 7 { - if self.is_supervisor() { &mut self.state.ssp } else { &mut self.state.usp } + if self.is_supervisor() { + &mut self.state.ssp + } else { + &mut self.state.usp + } } else { &mut self.state.a_reg[reg as usize] } } fn is_supervisor(&self) -> bool { - self.state.sr & (Flags:: Supervisor as u16) != 0 + self.state.sr & (Flags::Supervisor as u16) != 0 } fn require_supervisor(&self) -> Result<(), M68kError> { @@ -1732,7 +1826,11 @@ where } fn set_sr(&mut self, value: u16) { - let mask = if self.cycle.decoder.cputype <= M68kType::MC68010 { 0xA71F } else { 0xF71F }; + let mask = if self.cycle.decoder.cputype <= M68kType::MC68010 { + 0xA71F + } else { + 0xF71F + }; self.state.sr = value & mask; } @@ -1805,15 +1903,23 @@ where Condition::OverflowSet => self.get_flag(Flags::Overflow), Condition::Plus => !self.get_flag(Flags::Negative), Condition::Minus => self.get_flag(Flags::Negative), - Condition::GreaterThanOrEqual => (self.get_flag(Flags::Negative) && self.get_flag(Flags::Overflow)) || (!self.get_flag(Flags::Negative) && !self.get_flag(Flags::Overflow)), - Condition::LessThan => (self.get_flag(Flags::Negative) && !self.get_flag(Flags::Overflow)) || (!self.get_flag(Flags::Negative) && self.get_flag(Flags::Overflow)), - Condition::GreaterThan => + Condition::GreaterThanOrEqual => { + (self.get_flag(Flags::Negative) && self.get_flag(Flags::Overflow)) + || (!self.get_flag(Flags::Negative) && !self.get_flag(Flags::Overflow)) + }, + Condition::LessThan => { + (self.get_flag(Flags::Negative) && !self.get_flag(Flags::Overflow)) + || (!self.get_flag(Flags::Negative) && self.get_flag(Flags::Overflow)) + }, + Condition::GreaterThan => { (self.get_flag(Flags::Negative) && self.get_flag(Flags::Overflow) && !self.get_flag(Flags::Zero)) - || (!self.get_flag(Flags::Negative) && !self.get_flag(Flags::Overflow) && !self.get_flag(Flags::Zero)), - Condition::LessThanOrEqual => + || (!self.get_flag(Flags::Negative) && !self.get_flag(Flags::Overflow) && !self.get_flag(Flags::Zero)) + }, + Condition::LessThanOrEqual => { self.get_flag(Flags::Zero) - || (self.get_flag(Flags::Negative) && !self.get_flag(Flags::Overflow)) - || (!self.get_flag(Flags::Negative) && self.get_flag(Flags::Overflow)), + || (self.get_flag(Flags::Negative) && !self.get_flag(Flags::Overflow)) + || (!self.get_flag(Flags::Negative) && self.get_flag(Flags::Overflow)) + }, } } } @@ -1889,7 +1995,11 @@ fn rotate_left(value: u32, size: Size, use_extend: Option) -> (u32, bool) fn rotate_right(value: u32, size: Size, use_extend: Option) -> (u32, bool) { let bit = (value & 0x01) != 0; - let mask = if use_extend.unwrap_or(bit) { get_msb_mask(0xffffffff, size) } else { 0x0 }; + let mask = if use_extend.unwrap_or(bit) { + get_msb_mask(0xffffffff, size) + } else { + 0x0 + }; ((value >> 1) | mask, bit) } @@ -1899,17 +2009,23 @@ fn get_nibbles_from_byte(value: u32) -> (u32, u32) { fn get_value_sized(value: u32, size: Size) -> u32 { match size { - Size::Byte => { 0x000000FF & value }, - Size::Word => { 0x0000FFFF & value }, - Size::Long => { value }, + Size::Byte => 0x000000FF & value, + Size::Word => 0x0000FFFF & value, + Size::Long => value, } } fn set_value_sized(addr: &mut u32, value: u32, size: Size) { match size { - Size::Byte => { *addr = (*addr & 0xFFFFFF00) | (0x000000FF & value); } - Size::Word => { *addr = (*addr & 0xFFFF0000) | (0x0000FFFF & value); } - Size::Long => { *addr = value; } + Size::Byte => { + *addr = (*addr & 0xFFFFFF00) | (0x000000FF & value); + }, + Size::Word => { + *addr = (*addr & 0xFFFF0000) | (0x0000FFFF & value); + }, + Size::Long => { + *addr = value; + }, } } @@ -1956,5 +2072,3 @@ fn get_bit_field_mask(offset: u32, width: u32) -> u32 { fn get_bit_field_msb(offset: u32) -> u32 { 0x80000000 >> offset } - - diff --git a/emulator/cpus/m68k/src/instructions.rs b/emulator/cpus/m68k/src/instructions.rs index 68b2b7f..a555e05 100644 --- a/emulator/cpus/m68k/src/instructions.rs +++ b/emulator/cpus/m68k/src/instructions.rs @@ -1,4 +1,3 @@ - use std::fmt::{self, Write}; @@ -336,10 +335,12 @@ impl fmt::Display for Target { let index_str = fmt_index_disp(index_reg); write!(f, "([{}#{:08x}]{} + #{:08x})", base_reg, base_disp, index_str, outer_disp) }, - Target::IndirectMemory(value, size) => if *size == Size::Word { - write!(f, "(#{:04x})", value) - } else { - write!(f, "(#{:08x})", value) + Target::IndirectMemory(value, size) => { + if *size == Size::Word { + write!(f, "(#{:04x})", value) + } else { + write!(f, "(#{:08x})", value) + } }, } } @@ -432,7 +433,17 @@ impl fmt::Display for Instruction { Instruction::EORtoCCR(value) => write!(f, "eorib\t#{:#02x}, %ccr", value), Instruction::EORtoSR(value) => write!(f, "eoriw\t#{:#04x}, %sr", value), Instruction::EXG(src, dest) => write!(f, "exg\t{}, {}", src, dest), - Instruction::EXT(reg, from_size, to_size) => write!(f, "ext{}{}\t%d{}", if *from_size == Size::Byte && *to_size == Size::Long { "b" } else { "" }, to_size, reg), + Instruction::EXT(reg, from_size, to_size) => write!( + f, + "ext{}{}\t%d{}", + if *from_size == Size::Byte && *to_size == Size::Long { + "b" + } else { + "" + }, + to_size, + reg + ), Instruction::ILLEGAL => write!(f, "illegal"), @@ -517,4 +528,3 @@ impl fmt::Display for Instruction { } } } - diff --git a/emulator/cpus/m68k/src/lib.rs b/emulator/cpus/m68k/src/lib.rs index a8253e4..c334d34 100644 --- a/emulator/cpus/m68k/src/lib.rs +++ b/emulator/cpus/m68k/src/lib.rs @@ -1,17 +1,15 @@ - pub mod assembler; -pub mod state; +pub mod debugger; pub mod decode; pub mod execute; -pub mod debugger; pub mod instructions; pub mod memory; -pub mod timing; +pub mod state; pub mod tests; +pub mod timing; #[cfg(feature = "moa")] pub mod moa; pub use crate::state::{M68k, M68kType, M68kError}; pub use crate::memory::{M68kAddress, M68kAddressSpace}; - diff --git a/emulator/cpus/m68k/src/memory.rs b/emulator/cpus/m68k/src/memory.rs index 5826802..8db0d26 100644 --- a/emulator/cpus/m68k/src/memory.rs +++ b/emulator/cpus/m68k/src/memory.rs @@ -1,4 +1,3 @@ - use core::cmp; use core::fmt::Write; use femtos::Instant; @@ -10,6 +9,7 @@ use crate::instructions::Size; #[repr(u8)] #[allow(dead_code)] #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[rustfmt::skip] pub enum FunctionCode { Reserved0 = 0, UserData = 1, @@ -148,7 +148,13 @@ impl M68kBusPort { } } - fn read(&mut self, bus: &mut Bus, clock: Instant, addr: M68kAddress, data: &mut [u8]) -> Result<(), M68kError> + fn read( + &mut self, + bus: &mut Bus, + clock: Instant, + addr: M68kAddress, + data: &mut [u8], + ) -> Result<(), M68kError> where Bus: BusAccess, { @@ -162,7 +168,13 @@ impl M68kBusPort { Ok(()) } - fn write(&mut self, bus: &mut Bus, clock: Instant, addr: M68kAddress, data: &[u8]) -> Result<(), M68kError> + fn write( + &mut self, + bus: &mut Bus, + clock: Instant, + addr: M68kAddress, + data: &[u8], + ) -> Result<(), M68kError> where Bus: BusAccess, { @@ -185,10 +197,17 @@ impl M68kBusPort { Size::Byte => self.read(bus, self.current_clock, addr, &mut data[3..4]), Size::Word => self.read(bus, self.current_clock, addr, &mut data[2..4]), Size::Long => self.read(bus, self.current_clock, addr, &mut data[0..4]), - }.map(|_| u32::from_be_bytes(data)) + } + .map(|_| u32::from_be_bytes(data)) } - fn write_sized(&mut self, bus: &mut Bus, addr: M68kAddress, size: Size, value: u32) -> Result<(), M68kError> + fn write_sized( + &mut self, + bus: &mut Bus, + addr: M68kAddress, + size: Size, + value: u32, + ) -> Result<(), M68kError> where Bus: BusAccess, { @@ -200,7 +219,13 @@ impl M68kBusPort { } } - pub(crate) fn read_data_sized(&mut self, bus: &mut Bus, is_supervisor: bool, addr: M68kAddress, size: Size) -> Result> + pub(crate) fn read_data_sized( + &mut self, + bus: &mut Bus, + is_supervisor: bool, + addr: M68kAddress, + size: Size, + ) -> Result> where Bus: BusAccess, { @@ -208,7 +233,14 @@ impl M68kBusPort { self.read_sized(bus, addr, size) } - pub(crate) fn write_data_sized(&mut self, bus: &mut Bus, is_supervisor: bool, addr: M68kAddress, size: Size, value: u32) -> Result<(), M68kError> + pub(crate) fn write_data_sized( + &mut self, + bus: &mut Bus, + is_supervisor: bool, + addr: M68kAddress, + size: Size, + value: u32, + ) -> Result<(), M68kError> where Bus: BusAccess, { @@ -216,7 +248,12 @@ impl M68kBusPort { self.write_sized(bus, addr, size, value) } - pub(crate) fn read_instruction_word(&mut self, bus: &mut Bus, is_supervisor: bool, addr: u32) -> Result> + pub(crate) fn read_instruction_word( + &mut self, + bus: &mut Bus, + is_supervisor: bool, + addr: u32, + ) -> Result> where Bus: BusAccess, { @@ -224,7 +261,12 @@ impl M68kBusPort { Ok(self.read_sized(bus, addr, Size::Word)? as u16) } - pub(crate) fn read_instruction_long(&mut self, bus: &mut Bus, is_supervisor: bool, addr: u32) -> Result> + pub(crate) fn read_instruction_long( + &mut self, + bus: &mut Bus, + is_supervisor: bool, + addr: u32, + ) -> Result> where Bus: BusAccess, { @@ -232,7 +274,15 @@ impl M68kBusPort { self.read_sized(bus, addr, Size::Long) } - pub(crate) fn start_request(&mut self, is_supervisor: bool, addr: u32, size: Size, access: MemAccess, mtype: MemType, i_n_bit: bool) -> Result> { + pub(crate) fn start_request( + &mut self, + is_supervisor: bool, + addr: u32, + size: Size, + access: MemAccess, + mtype: MemType, + i_n_bit: bool, + ) -> Result> { self.request.i_n_bit = i_n_bit; self.request.code = match mtype { MemType::Program => FunctionCode::program(is_supervisor), @@ -314,7 +364,7 @@ impl TargetAccess { } pub(crate) fn complete(&self) -> Result { - + } } @@ -357,7 +407,7 @@ impl ReadOnceAccess { } pub(crate) fn complete(&self) -> Result { - + } } @@ -376,7 +426,7 @@ impl ReadUpdateAccess { } pub(crate) fn complete(&self) -> Result { - + } } @@ -391,7 +441,7 @@ impl WriteOnceAccess { } pub(crate) fn complete(&self) -> Result { - + } } */ diff --git a/emulator/cpus/m68k/src/moa.rs b/emulator/cpus/m68k/src/moa.rs index 46a05cd..10f3d6d 100644 --- a/emulator/cpus/m68k/src/moa.rs +++ b/emulator/cpus/m68k/src/moa.rs @@ -1,4 +1,3 @@ - use femtos::{Instant, Duration}; use emulator_hal::bus; @@ -13,11 +12,8 @@ impl Steppable for M68k { let cycle = M68kCycle::new(self, system.clock); let mut bus = system.bus.borrow_mut(); - let mut adapter: bus::BusAdapter = bus::BusAdapter::new( - &mut *bus, - |addr| addr as u64, - |err| err, - ); + let mut adapter: bus::BusAdapter = + bus::BusAdapter::new(&mut *bus, |addr| addr as u64, |err| err); let mut executor = cycle.begin(self, &mut adapter); executor.check_breakpoints()?; @@ -40,7 +36,7 @@ impl Steppable for M68k { } } -impl Interruptable for M68k { } +impl Interruptable for M68k {} impl Transmutable for M68k { fn as_steppable(&mut self) -> Option<&mut dyn Steppable> { @@ -104,11 +100,8 @@ impl Debuggable for M68k { let mut decoder = M68kDecoder::new(self.info.chip, true, 0); let mut bus = system.bus.borrow_mut(); - let mut adapter: bus::BusAdapter = bus::BusAdapter::new( - &mut *bus, - |addr| addr as u64, - |err| err, - ); + let mut adapter: bus::BusAdapter = + bus::BusAdapter::new(&mut *bus, |addr| addr as u64, |err| err); decoder.dump_disassembly(&mut adapter, addr as u32, count as u32); } @@ -124,9 +117,10 @@ impl Debuggable for M68k { "so" | "stepout" => { self.debugger.step_until_return = Some(self.debugger.stack_tracer.calls.len() - 1); }, - _ => { return Ok(true); }, + _ => { + return Ok(true); + }, } Ok(false) } } - diff --git a/emulator/cpus/m68k/src/state.rs b/emulator/cpus/m68k/src/state.rs index c2a46aa..c4fb47e 100644 --- a/emulator/cpus/m68k/src/state.rs +++ b/emulator/cpus/m68k/src/state.rs @@ -1,4 +1,3 @@ - use core::fmt::{self, Write}; use femtos::{Duration, Frequency}; @@ -14,10 +13,10 @@ pub type ClockCycles = u16; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[repr(u8)] pub enum AddressWidth { - A32 = 32, // MC68020+ - A24 = 24, // MC68000 64-Pin, MC68010 - A22 = 22, // MC68008 52-Pin - A20 = 20, // MC68008 48-Pin + A32 = 32, // MC68020+ + A24 = 24, // MC68000 64-Pin, MC68010 + A22 = 22, // MC68008 52-Pin + A20 = 20, // MC68008 48-Pin } #[allow(dead_code)] @@ -99,7 +98,7 @@ impl CpuInfo { address_width: AddressWidth::A32, data_width: DataWidth::D32, frequency, - } + }, } } } @@ -109,6 +108,7 @@ const FLAGS_ON_RESET: u16 = 0x2700; #[repr(u16)] #[allow(dead_code)] #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[rustfmt::skip] pub enum Flags { Carry = 0x0001, Overflow = 0x0002, @@ -124,6 +124,7 @@ pub enum Flags { #[repr(u8)] #[allow(dead_code)] #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[rustfmt::skip] pub enum Exceptions { BusError = 2, AddressError = 3, @@ -298,4 +299,3 @@ impl InterruptPriority { } } } - diff --git a/emulator/cpus/m68k/src/tests.rs b/emulator/cpus/m68k/src/tests.rs index a5bd84f..b6ddf24 100644 --- a/emulator/cpus/m68k/src/tests.rs +++ b/emulator/cpus/m68k/src/tests.rs @@ -1,4 +1,3 @@ - #[cfg(test)] mod decode_unit_tests { use femtos::Instant; @@ -96,7 +95,10 @@ mod decode_unit_tests { let size = Size::Long; let offset = -8; - decoder.bus.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap(); + decoder + .bus + .write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16) + .unwrap(); let target = decoder.get_mode_as_target(0b101, 0b100, Some(size)).unwrap(); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(4), None, offset)); @@ -111,10 +113,24 @@ mod decode_unit_tests { let brief_extension = 0x3800 | (((offset as i8) as u8) as u16); decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - decoder.bus.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).unwrap(); + decoder + .bus + .write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16) + .unwrap(); let target = decoder.get_mode_as_target(0b110, 0b010, Some(size)).unwrap(); - assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), Some(IndexRegister { xreg: XRegister::DReg(3), scale: 0, size: size }), offset)); + assert_eq!( + target, + Target::IndirectRegOffset( + BaseRegister::AReg(2), + Some(IndexRegister { + xreg: XRegister::DReg(3), + scale: 0, + size: size + }), + offset + ) + ); }); } @@ -129,7 +145,18 @@ mod decode_unit_tests { decoder.bus.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); let target = decoder.get_mode_as_target(0b110, 0b010, Some(size)).unwrap(); - assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), Some(IndexRegister { xreg: XRegister::AReg(7), scale: 1, size: size }), offset)); + assert_eq!( + target, + Target::IndirectRegOffset( + BaseRegister::AReg(2), + Some(IndexRegister { + xreg: XRegister::AReg(7), + scale: 1, + size: size + }), + offset + ) + ); }); } @@ -144,7 +171,18 @@ mod decode_unit_tests { decoder.bus.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); let target = decoder.get_mode_as_target(0b110, 0b010, Some(size)).unwrap(); - assert_eq!(target, Target::IndirectRegOffset(BaseRegister::None, Some(IndexRegister { xreg: XRegister::AReg(7), scale: 1, size: size }), offset)); + assert_eq!( + target, + Target::IndirectRegOffset( + BaseRegister::None, + Some(IndexRegister { + xreg: XRegister::AReg(7), + scale: 1, + size: size + }), + offset + ) + ); }); } @@ -169,7 +207,10 @@ mod decode_unit_tests { let size = Size::Long; let offset = -8; - decoder.bus.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap(); + decoder + .bus + .write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16) + .unwrap(); let target = decoder.get_mode_as_target(0b111, 0b010, Some(size)).unwrap(); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, None, offset)); @@ -184,10 +225,24 @@ mod decode_unit_tests { let brief_extension = 0x3000 | (((offset as i8) as u8) as u16); decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - decoder.bus.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).unwrap(); + decoder + .bus + .write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16) + .unwrap(); let target = decoder.get_mode_as_target(0b111, 0b011, Some(size)).unwrap(); - assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, Some(IndexRegister { xreg: XRegister::DReg(3), scale: 0, size: size }), offset)); + assert_eq!( + target, + Target::IndirectRegOffset( + BaseRegister::PC, + Some(IndexRegister { + xreg: XRegister::DReg(3), + scale: 0, + size: size + }), + offset + ) + ); }); } @@ -202,7 +257,18 @@ mod decode_unit_tests { decoder.bus.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); let target = decoder.get_mode_as_target(0b111, 0b011, Some(size)).unwrap(); - assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, Some(IndexRegister { xreg: XRegister::AReg(7), scale: 1, size: size }), offset)); + assert_eq!( + target, + Target::IndirectRegOffset( + BaseRegister::PC, + Some(IndexRegister { + xreg: XRegister::AReg(7), + scale: 1, + size: size + }), + offset + ) + ); }); } @@ -269,7 +335,9 @@ mod execute_unit_tests { // Insert basic initialization let len = 0x10_0000; let mut data = Vec::with_capacity(len); - unsafe { data.set_len(len); } + unsafe { + data.set_len(len); + } let mut memory = MemoryBlock::from(data); memory.write_beu32(Instant::START, 0, INIT_STACK as u32).unwrap(); memory.write_beu32(Instant::START, 4, INIT_ADDR as u32).unwrap(); diff --git a/emulator/cpus/m68k/src/timing.rs b/emulator/cpus/m68k/src/timing.rs index cd38386..2e5725a 100644 --- a/emulator/cpus/m68k/src/timing.rs +++ b/emulator/cpus/m68k/src/timing.rs @@ -1,4 +1,3 @@ - use crate::M68kType; use crate::state::ClockCycles; use crate::instructions::{Size, Sign, Direction, Target, Instruction}; @@ -69,8 +68,7 @@ impl M68kInstructionTiming { #[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, + Target::DirectDReg(_) | Target::DirectAReg(_) => reg, _ => mem, }; self @@ -95,7 +93,7 @@ impl M68kInstructionTiming { 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) + _ => self.add_word_v_long(size, mem.0, mem.1), } } @@ -115,7 +113,7 @@ impl M68kInstructionTiming { 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) + _ => self.add_word_v_long(size, mem.0, mem.1), } } @@ -139,14 +137,11 @@ impl M68kInstructionTiming { Target::IndirectAReg(_) => self.add_access(size), Target::IndirectARegInc(_) => self.add_access(size), Target::IndirectARegDec(_) => self.add_access(size).add_internal(2), - Target::IndirectRegOffset(_, index_reg, _) => { - match index_reg { - None => self.add_access(size).add_internal(4), - Some(_) => self.add_access(size).add_internal(6), - } + Target::IndirectRegOffset(_, index_reg, _) => match index_reg { + None => self.add_access(size).add_internal(4), + Some(_) => self.add_access(size).add_internal(6), }, - Target::IndirectMemoryPreindexed(_, index_reg, _, _) | - Target::IndirectMemoryPostindexed(_, index_reg, _, _) => { + Target::IndirectMemoryPreindexed(_, index_reg, _, _) | Target::IndirectMemoryPostindexed(_, index_reg, _, _) => { // TODO this is very wrong, but the 68020 timings are complicated match index_reg { None => self.add_access(size).add_internal(4), @@ -159,7 +154,9 @@ impl M68kInstructionTiming { 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), + (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), } } @@ -199,20 +196,31 @@ impl M68kInstructionTiming { match instruction { Instruction::ABCD(_, dest) => self.add_reg_v_mem(dest, 6, 18), - Instruction::ADD(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(Target::Immediate(_), dest, size) => self.add_immediate_set(*size, dest, (8, 16), (12, 20)).add_target(*size, dest), // ADDI + Instruction::ADD(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(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::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, _, size) => self.add_word_v_long(*size, 8, 6).add_target(*size, target), Instruction::ADDX(_, dest, size) => self.add_reg_mem_set(*size, dest, (4, 8), (18, 30)), - Instruction::AND(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::AND(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::ASL(_, target, size) | - Instruction::ASR(_, target, size) => self.add_word_v_long(*size, 6, 8).add_per_rep(2).add_target(*size, target), + Instruction::ASL(_, target, size) | Instruction::ASR(_, target, size) => { + 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), @@ -221,25 +229,36 @@ impl M68kInstructionTiming { 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), + } + .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), + } + .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), + } + .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), + } + .add_target(*size, target), Instruction::CHK(_, _, _) => 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::CLR(target, size) => self + .add_reg_v_mem(target, 4, 8) + .add_word_v_long(*size, 0, 2) + .add_target(*size, target), - Instruction::CMP(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::CMP(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), @@ -248,8 +267,12 @@ impl M68kInstructionTiming { Sign::Signed => self.add_internal(158).add_target(Size::Long, src), }, - Instruction::EOR(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::EOR(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), @@ -263,8 +286,9 @@ impl M68kInstructionTiming { Instruction::LEA(target, _) => self.add_indirect_set(target, 4, 8, 12, 8, 12), Instruction::LINK(_, _) => self.add_internal(16), - Instruction::LSL(_, target, size) | - Instruction::LSR(_, target, size) => self.add_word_v_long(*size, 6, 8).add_per_rep(2).add_target(*size, target), + Instruction::LSL(_, target, size) | Instruction::LSR(_, target, size) => { + 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), @@ -287,8 +311,12 @@ impl M68kInstructionTiming { 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(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::OR(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), @@ -296,26 +324,40 @@ impl M68kInstructionTiming { Instruction::RESET => self.add_internal(132), - Instruction::ROL(_, target, size) | - Instruction::ROR(_, target, size) => self.add_word_v_long(*size, 6, 8).add_per_rep(2).add_target(*size, target), - Instruction::ROXL(_, target, size) | - Instruction::ROXR(_, target, size) => self.add_word_v_long(*size, 6, 8).add_per_rep(2).add_target(*size, target), + Instruction::ROL(_, target, size) | Instruction::ROR(_, target, size) => { + self.add_word_v_long(*size, 6, 8).add_per_rep(2).add_target(*size, target) + }, + Instruction::ROXL(_, target, size) | Instruction::ROXR(_, target, size) => { + 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(_, 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::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(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(Target::Immediate(_), dest, size) => self.add_immediate_set(*size, dest, (8, 16), (12, 20)).add_target(*size, dest), // SUBI + | 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(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(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::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, _, size) => self.add_word_v_long(*size, 8, 6).add_target(*size, target), Instruction::SUBX(_, dest, size) => self.add_reg_mem_set(*size, dest, (4, 8), (18, 30)), @@ -362,9 +404,9 @@ impl M68kInstructionTiming { pub fn calculate_clocks(&self) -> ClockCycles { //println!("{:?}", self); (self.accesses as ClockCycles * 4) - + self.internal as ClockCycles - + (if self.branched { self.on_branch as ClockCycles } else { 0 }) - + self.per_rep as ClockCycles * self.reps + + self.internal as ClockCycles + + (if self.branched { self.on_branch as ClockCycles } else { 0 }) + + self.per_rep as ClockCycles * self.reps } #[inline(always)] @@ -376,6 +418,3 @@ impl M68kInstructionTiming { } } } - - - diff --git a/emulator/cpus/m68k/tests/decode_tests.rs b/emulator/cpus/m68k/tests/decode_tests.rs index 10b145a..052e1a3 100644 --- a/emulator/cpus/m68k/tests/decode_tests.rs +++ b/emulator/cpus/m68k/tests/decode_tests.rs @@ -1,4 +1,3 @@ - use femtos::{Instant, Frequency}; use emulator_hal::bus::BusAccess; use emulator_hal_memory::MemoryBlock; @@ -69,7 +68,9 @@ fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, MemoryBlock M68kState { fn load_memory>(bus: &mut Bus, data: &[u16]) { for i in 0..data.len() { bus.write_beu16(Instant::START, (i << 1) as u32, data[i]).unwrap(); - } + } } fn run_test(case: &TestCase) { @@ -708,4 +709,3 @@ const TEST_CASES: &'static [TestCase] = &[ fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000080, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x2719, mem: 0x00000000 }, }, ]; - diff --git a/emulator/cpus/m68k/tests/musashi_timing_tests.rs b/emulator/cpus/m68k/tests/musashi_timing_tests.rs index 65c3cb5..9857b68 100644 --- a/emulator/cpus/m68k/tests/musashi_timing_tests.rs +++ b/emulator/cpus/m68k/tests/musashi_timing_tests.rs @@ -1,4 +1,3 @@ - use femtos::{Instant, Frequency}; use emulator_hal::bus::BusAccess; use emulator_hal_memory::MemoryBlock; @@ -17,7 +16,9 @@ fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, MemoryBlock println!("ok"), - Err(err) => { println!("{:?}", err); errors += 1 }, + Err(err) => { + println!("{:?}", err); + errors += 1 + }, } if let Err(_) = run_timing_test(case) { @@ -1624,4 +1628,3 @@ pub const TIMING_TESTS: &'static [TimingCase] = &[ TimingCase { cpu: M68kType::MC68000, data: &[0x4A98], timing: ( 12, 12, 6), ins: Instruction::TST(Target::IndirectARegInc(0), Size::Long) }, TimingCase { cpu: M68kType::MC68000, data: &[0x4E58], timing: ( 12, 12, 6), ins: Instruction::UNLK(0) }, ]; - diff --git a/emulator/cpus/m68k/tests/timing_tests.rs b/emulator/cpus/m68k/tests/timing_tests.rs index 8700fe0..08f4b4b 100644 --- a/emulator/cpus/m68k/tests/timing_tests.rs +++ b/emulator/cpus/m68k/tests/timing_tests.rs @@ -1,4 +1,3 @@ - use femtos::{Instant, Frequency}; use emulator_hal::bus::BusAccess; use emulator_hal_memory::MemoryBlock; @@ -19,16 +18,21 @@ struct TimingCase { 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) }, -]; +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 init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, MemoryBlock) { // Insert basic initialization let len = 0x10_0000; let mut data = Vec::with_capacity(len); - unsafe { data.set_len(len); } + unsafe { + data.set_len(len); + } let mut memory = MemoryBlock::from(data); memory.write_beu32(Instant::START, 0, INIT_STACK).unwrap(); memory.write_beu32(Instant::START, 4, INIT_ADDR).unwrap(); @@ -85,7 +89,10 @@ pub fn run_timing_tests() { print!("Testing for {:?}...", case.ins); match run_timing_test(case) { Ok(()) => println!("ok"), - Err(err) => { println!("{:?}", err); errors += 1 }, + Err(err) => { + println!("{:?}", err); + errors += 1 + }, } if let Err(_) = run_timing_test(case) { @@ -97,4 +104,3 @@ pub fn run_timing_tests() { panic!("{} errors", errors); } } - diff --git a/emulator/cpus/z80/src/debugger.rs b/emulator/cpus/z80/src/debugger.rs index 5c0e5ce..c05e70a 100644 --- a/emulator/cpus/z80/src/debugger.rs +++ b/emulator/cpus/z80/src/debugger.rs @@ -1,4 +1,3 @@ - use moa_core::{System, Error, Address, Debuggable}; use crate::state::{Z80, Z80Error}; @@ -37,10 +36,10 @@ impl Debuggable for Z80 { fn run_command(&mut self, _system: &System, args: &[&str]) -> Result { match args[0] { - "l" => { - self.state.reg[Register::L as usize] = 0x05 + "l" => self.state.reg[Register::L as usize] = 0x05, + _ => { + return Ok(true); }, - _ => { return Ok(true); }, } Ok(false) } @@ -62,4 +61,3 @@ impl Z80 { Ok(()) } } - diff --git a/emulator/cpus/z80/src/decode.rs b/emulator/cpus/z80/src/decode.rs index 7875c80..2e47774 100644 --- a/emulator/cpus/z80/src/decode.rs +++ b/emulator/cpus/z80/src/decode.rs @@ -1,11 +1,13 @@ - use core::fmt::Write; use femtos::Instant; use moa_core::{Address, Addressable}; use crate::state::Z80Error; -use crate::instructions::{Direction, Condition, Register, RegisterPair, IndexRegister, IndexRegisterHalf, SpecialRegister, InterruptMode, Target, LoadTarget, UndocumentedCopy, Instruction}; +use crate::instructions::{ + Direction, Condition, Register, RegisterPair, IndexRegister, IndexRegisterHalf, SpecialRegister, InterruptMode, Target, + LoadTarget, UndocumentedCopy, Instruction, +}; //use emulator_hal::bus::BusAccess; // @@ -57,177 +59,169 @@ impl Z80Decoder { self.decode_bare(memory, ins, 0) } - pub fn decode_bare(&mut self, memory: &mut dyn Addressable, ins: u8, extra_instruction_bytes: u16) -> Result { + pub fn decode_bare( + &mut self, + memory: &mut dyn Addressable, + ins: u8, + extra_instruction_bytes: u16, + ) -> Result { self.extra_instruction_bytes = extra_instruction_bytes; match get_ins_x(ins) { - 0 => { - match get_ins_z(ins) { - 0 => { - match get_ins_y(ins) { - 0 => Ok(Instruction::NOP), - 1 => Ok(Instruction::EXafaf), - 2 => { - let offset = self.read_instruction_byte(memory)? as i8; - Ok(Instruction::DJNZ(offset)) - }, - 3 => { - let offset = self.read_instruction_byte(memory)? as i8; - Ok(Instruction::JR(offset)) - }, - y => { - let offset = self.read_instruction_byte(memory)? as i8; - Ok(Instruction::JRcc(get_condition(y - 4), offset)) - }, - } - }, - 1 => { - if get_ins_q(ins) == 0 { - let data = self.read_instruction_word(memory)?; - Ok(Instruction::LD(LoadTarget::DirectRegWord(get_register_pair(get_ins_p(ins))), LoadTarget::ImmediateWord(data))) - } else { - Ok(Instruction::ADD16(RegisterPair::HL, get_register_pair(get_ins_p(ins)))) - } - }, + 0 => match get_ins_z(ins) { + 0 => match get_ins_y(ins) { + 0 => Ok(Instruction::NOP), + 1 => Ok(Instruction::EXafaf), 2 => { - if (ins & 0x20) == 0 { - let target = match (ins & 0x10) != 0 { - false => LoadTarget::IndirectRegByte(RegisterPair::BC), - true => LoadTarget::IndirectRegByte(RegisterPair::DE), - }; - - match get_ins_q(ins) != 0 { - false => Ok(Instruction::LD(target, LoadTarget::DirectRegByte(Register::A))), - true => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::A), target)), - } - } else { - let addr = self.read_instruction_word(memory)?; - match (ins >> 3) & 0x03 { - 0 => Ok(Instruction::LD(LoadTarget::IndirectWord(addr), LoadTarget::DirectRegWord(RegisterPair::HL))), - 1 => Ok(Instruction::LD(LoadTarget::DirectRegWord(RegisterPair::HL), LoadTarget::IndirectWord(addr))), - 2 => Ok(Instruction::LD(LoadTarget::IndirectByte(addr), LoadTarget::DirectRegByte(Register::A))), - 3 => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::A), LoadTarget::IndirectByte(addr))), - _ => panic!("InternalError: impossible value"), - } - } + let offset = self.read_instruction_byte(memory)? as i8; + Ok(Instruction::DJNZ(offset)) }, 3 => { - if get_ins_q(ins) == 0 { - Ok(Instruction::INC16(get_register_pair(get_ins_p(ins)))) - } else { - Ok(Instruction::DEC16(get_register_pair(get_ins_p(ins)))) + let offset = self.read_instruction_byte(memory)? as i8; + Ok(Instruction::JR(offset)) + }, + y => { + let offset = self.read_instruction_byte(memory)? as i8; + Ok(Instruction::JRcc(get_condition(y - 4), offset)) + }, + }, + 1 => { + if get_ins_q(ins) == 0 { + let data = self.read_instruction_word(memory)?; + Ok(Instruction::LD( + LoadTarget::DirectRegWord(get_register_pair(get_ins_p(ins))), + LoadTarget::ImmediateWord(data), + )) + } else { + Ok(Instruction::ADD16(RegisterPair::HL, get_register_pair(get_ins_p(ins)))) + } + }, + 2 => { + if (ins & 0x20) == 0 { + let target = match (ins & 0x10) != 0 { + false => LoadTarget::IndirectRegByte(RegisterPair::BC), + true => LoadTarget::IndirectRegByte(RegisterPair::DE), + }; + + match get_ins_q(ins) != 0 { + false => Ok(Instruction::LD(target, LoadTarget::DirectRegByte(Register::A))), + true => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::A), target)), } - }, - 4 => { - Ok(Instruction::INC8(get_register(get_ins_y(ins)))) - }, - 5 => { - Ok(Instruction::DEC8(get_register(get_ins_y(ins)))) - }, - 6 => { - let data = self.read_instruction_byte(memory)?; - Ok(Instruction::LD(to_load_target(get_register(get_ins_y(ins))), LoadTarget::ImmediateByte(data))) - }, - 7 => { - match get_ins_y(ins) { - 0 => Ok(Instruction::RLCA), - 1 => Ok(Instruction::RRCA), - 2 => Ok(Instruction::RLA), - 3 => Ok(Instruction::RRA), - 4 => Ok(Instruction::DAA), - 5 => Ok(Instruction::CPL), - 6 => Ok(Instruction::SCF), - 7 => Ok(Instruction::CCF), + } else { + let addr = self.read_instruction_word(memory)?; + match (ins >> 3) & 0x03 { + 0 => Ok(Instruction::LD(LoadTarget::IndirectWord(addr), LoadTarget::DirectRegWord(RegisterPair::HL))), + 1 => Ok(Instruction::LD(LoadTarget::DirectRegWord(RegisterPair::HL), LoadTarget::IndirectWord(addr))), + 2 => Ok(Instruction::LD(LoadTarget::IndirectByte(addr), LoadTarget::DirectRegByte(Register::A))), + 3 => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::A), LoadTarget::IndirectByte(addr))), _ => panic!("InternalError: impossible value"), } - }, + } + }, + 3 => { + if get_ins_q(ins) == 0 { + Ok(Instruction::INC16(get_register_pair(get_ins_p(ins)))) + } else { + Ok(Instruction::DEC16(get_register_pair(get_ins_p(ins)))) + } + }, + 4 => Ok(Instruction::INC8(get_register(get_ins_y(ins)))), + 5 => Ok(Instruction::DEC8(get_register(get_ins_y(ins)))), + 6 => { + let data = self.read_instruction_byte(memory)?; + Ok(Instruction::LD(to_load_target(get_register(get_ins_y(ins))), LoadTarget::ImmediateByte(data))) + }, + 7 => match get_ins_y(ins) { + 0 => Ok(Instruction::RLCA), + 1 => Ok(Instruction::RRCA), + 2 => Ok(Instruction::RLA), + 3 => Ok(Instruction::RRA), + 4 => Ok(Instruction::DAA), + 5 => Ok(Instruction::CPL), + 6 => Ok(Instruction::SCF), + 7 => Ok(Instruction::CCF), _ => panic!("InternalError: impossible value"), - } + }, + _ => panic!("InternalError: impossible value"), }, 1 => { if ins == 0x76 { Ok(Instruction::HALT) } else { - Ok(Instruction::LD(to_load_target(get_register(get_ins_y(ins))), to_load_target(get_register(get_ins_z(ins))))) + Ok(Instruction::LD( + to_load_target(get_register(get_ins_y(ins))), + to_load_target(get_register(get_ins_z(ins))), + )) } }, - 2 => { - Ok(get_alu_instruction(get_ins_y(ins), get_register(get_ins_z(ins)))) - }, - 3 => { - match get_ins_z(ins) { - 0 => { - Ok(Instruction::RETcc(get_condition(get_ins_y(ins)))) - }, - 1 => { - if get_ins_q(ins) == 0 { - Ok(Instruction::POP(get_register_pair_alt(get_ins_p(ins)))) - } else { - match get_ins_p(ins) { - 0 => Ok(Instruction::RET), - 1 => Ok(Instruction::EXX), - 2 => Ok(Instruction::JPIndirect(RegisterPair::HL)), - 3 => Ok(Instruction::LD(LoadTarget::DirectRegWord(RegisterPair::SP), LoadTarget::DirectRegWord(RegisterPair::HL))), - _ => panic!("InternalError: impossible value"), - } - } - }, - 2 => { - let addr = self.read_instruction_word(memory)?; - Ok(Instruction::JPcc(get_condition(get_ins_y(ins)), addr)) - }, - 3 => { - match get_ins_y(ins) { - 0 => { - let addr = self.read_instruction_word(memory)?; - Ok(Instruction::JP(addr)) - }, - 1 => { - self.decode_prefix_cb(memory) - }, - 2 => { - let port = self.read_instruction_byte(memory)?; - Ok(Instruction::OUTx(port)) - }, - 3 => { - let port = self.read_instruction_byte(memory)?; - Ok(Instruction::INx(port)) - }, - 4 => Ok(Instruction::EXsp(RegisterPair::HL)), - 5 => Ok(Instruction::EXhlde), - 6 => Ok(Instruction::DI), - 7 => Ok(Instruction::EI), + 2 => Ok(get_alu_instruction(get_ins_y(ins), get_register(get_ins_z(ins)))), + 3 => match get_ins_z(ins) { + 0 => Ok(Instruction::RETcc(get_condition(get_ins_y(ins)))), + 1 => { + if get_ins_q(ins) == 0 { + Ok(Instruction::POP(get_register_pair_alt(get_ins_p(ins)))) + } else { + match get_ins_p(ins) { + 0 => Ok(Instruction::RET), + 1 => Ok(Instruction::EXX), + 2 => Ok(Instruction::JPIndirect(RegisterPair::HL)), + 3 => Ok(Instruction::LD( + LoadTarget::DirectRegWord(RegisterPair::SP), + LoadTarget::DirectRegWord(RegisterPair::HL), + )), _ => panic!("InternalError: impossible value"), } - }, - 4 => { - let addr = self.read_instruction_word(memory)?; - Ok(Instruction::CALLcc(get_condition(get_ins_y(ins)), addr)) } - 5 => { - if get_ins_q(ins) == 0 { - Ok(Instruction::PUSH(get_register_pair_alt(get_ins_p(ins)))) - } else { - match get_ins_p(ins) { - 0 => { - let addr = self.read_instruction_word(memory)?; - Ok(Instruction::CALL(addr)) - }, - 1 => self.decode_prefix_dd_fd(memory, IndexRegister::IX), - 2 => self.decode_prefix_ed(memory), - 3 => self.decode_prefix_dd_fd(memory, IndexRegister::IY), - _ => panic!("InternalError: impossible value"), - } + }, + 2 => { + let addr = self.read_instruction_word(memory)?; + Ok(Instruction::JPcc(get_condition(get_ins_y(ins)), addr)) + }, + 3 => match get_ins_y(ins) { + 0 => { + let addr = self.read_instruction_word(memory)?; + Ok(Instruction::JP(addr)) + }, + 1 => self.decode_prefix_cb(memory), + 2 => { + let port = self.read_instruction_byte(memory)?; + Ok(Instruction::OUTx(port)) + }, + 3 => { + let port = self.read_instruction_byte(memory)?; + Ok(Instruction::INx(port)) + }, + 4 => Ok(Instruction::EXsp(RegisterPair::HL)), + 5 => Ok(Instruction::EXhlde), + 6 => Ok(Instruction::DI), + 7 => Ok(Instruction::EI), + _ => panic!("InternalError: impossible value"), + }, + 4 => { + let addr = self.read_instruction_word(memory)?; + Ok(Instruction::CALLcc(get_condition(get_ins_y(ins)), addr)) + }, + 5 => { + if get_ins_q(ins) == 0 { + Ok(Instruction::PUSH(get_register_pair_alt(get_ins_p(ins)))) + } else { + match get_ins_p(ins) { + 0 => { + let addr = self.read_instruction_word(memory)?; + Ok(Instruction::CALL(addr)) + }, + 1 => self.decode_prefix_dd_fd(memory, IndexRegister::IX), + 2 => self.decode_prefix_ed(memory), + 3 => self.decode_prefix_dd_fd(memory, IndexRegister::IY), + _ => panic!("InternalError: impossible value"), } } - 6 => { - let data = self.read_instruction_byte(memory)?; - Ok(get_alu_instruction(get_ins_y(ins), Target::Immediate(data))) - }, - 7 => { - Ok(Instruction::RST(get_ins_y(ins) * 8)) - }, - _ => panic!("InternalError: impossible value"), - } + }, + 6 => { + let data = self.read_instruction_byte(memory)?; + Ok(get_alu_instruction(get_ins_y(ins), Target::Immediate(data))) + }, + 7 => Ok(Instruction::RST(get_ins_y(ins) * 8)), + _ => panic!("InternalError: impossible value"), }, _ => panic!("InternalError: impossible value"), } @@ -266,92 +260,88 @@ impl Z80Decoder { match get_ins_x(ins) { 0 => Ok(Instruction::NOP), - 1 => { - match get_ins_z(ins) { - 0 => { - let target = get_register(get_ins_y(ins)); - if let Target::DirectReg(reg) = target { - Ok(Instruction::INic(reg)) - } else { - Ok(Instruction::INicz) - } - }, - 1 => { - let target = get_register(get_ins_y(ins)); - if let Target::DirectReg(reg) = target { - Ok(Instruction::OUTic(reg)) - } else { - Ok(Instruction::OUTicz) - } - }, - 2 => { - if get_ins_q(ins) == 0 { - Ok(Instruction::SBC16(RegisterPair::HL, get_register_pair(get_ins_p(ins)))) - } else { - Ok(Instruction::ADC16(RegisterPair::HL, get_register_pair(get_ins_p(ins)))) - } - }, - 3 => { - let addr = self.read_instruction_word(memory)?; - if get_ins_q(ins) == 0 { - Ok(Instruction::LD(LoadTarget::IndirectWord(addr), LoadTarget::DirectRegWord(get_register_pair(get_ins_p(ins))))) - } else { - Ok(Instruction::LD(LoadTarget::DirectRegWord(get_register_pair(get_ins_p(ins))), LoadTarget::IndirectWord(addr))) - } - }, - 4 => { - Ok(Instruction::NEG) - }, - 5 => { - if get_ins_y(ins) == 1 { - Ok(Instruction::RETI) - } else { - Ok(Instruction::RETN) - } - }, - 6 => { - match get_ins_y(ins) & 0x03 { - 0 => Ok(Instruction::IM(InterruptMode::Mode0)), - 1 => Ok(Instruction::IM(InterruptMode::Mode0)), - 2 => Ok(Instruction::IM(InterruptMode::Mode1)), - 3 => Ok(Instruction::IM(InterruptMode::Mode2)), - _ => panic!("InternalError: impossible value"), - } - }, - 7 => { - match get_ins_y(ins) { - 0 => Ok(Instruction::LDsr(SpecialRegister::I, Direction::FromAcc)), - 1 => Ok(Instruction::LDsr(SpecialRegister::R, Direction::FromAcc)), - 2 => Ok(Instruction::LDsr(SpecialRegister::I, Direction::ToAcc)), - 3 => Ok(Instruction::LDsr(SpecialRegister::R, Direction::ToAcc)), - 4 => Ok(Instruction::RRD), - 5 => Ok(Instruction::RLD), - _ => Ok(Instruction::NOP), - } - }, + 1 => match get_ins_z(ins) { + 0 => { + let target = get_register(get_ins_y(ins)); + if let Target::DirectReg(reg) = target { + Ok(Instruction::INic(reg)) + } else { + Ok(Instruction::INicz) + } + }, + 1 => { + let target = get_register(get_ins_y(ins)); + if let Target::DirectReg(reg) = target { + Ok(Instruction::OUTic(reg)) + } else { + Ok(Instruction::OUTicz) + } + }, + 2 => { + if get_ins_q(ins) == 0 { + Ok(Instruction::SBC16(RegisterPair::HL, get_register_pair(get_ins_p(ins)))) + } else { + Ok(Instruction::ADC16(RegisterPair::HL, get_register_pair(get_ins_p(ins)))) + } + }, + 3 => { + let addr = self.read_instruction_word(memory)?; + if get_ins_q(ins) == 0 { + Ok(Instruction::LD( + LoadTarget::IndirectWord(addr), + LoadTarget::DirectRegWord(get_register_pair(get_ins_p(ins))), + )) + } else { + Ok(Instruction::LD( + LoadTarget::DirectRegWord(get_register_pair(get_ins_p(ins))), + LoadTarget::IndirectWord(addr), + )) + } + }, + 4 => Ok(Instruction::NEG), + 5 => { + if get_ins_y(ins) == 1 { + Ok(Instruction::RETI) + } else { + Ok(Instruction::RETN) + } + }, + 6 => match get_ins_y(ins) & 0x03 { + 0 => Ok(Instruction::IM(InterruptMode::Mode0)), + 1 => Ok(Instruction::IM(InterruptMode::Mode0)), + 2 => Ok(Instruction::IM(InterruptMode::Mode1)), + 3 => Ok(Instruction::IM(InterruptMode::Mode2)), _ => panic!("InternalError: impossible value"), - } - }, - 2 => { - match ins { - 0xA0 => Ok(Instruction::LDI), - 0xA1 => Ok(Instruction::CPI), - 0xA2 => Ok(Instruction::INI), - 0xA3 => Ok(Instruction::OUTI), - 0xA8 => Ok(Instruction::LDD), - 0xA9 => Ok(Instruction::CPD), - 0xAA => Ok(Instruction::IND), - 0xAB => Ok(Instruction::OUTD), - 0xB0 => Ok(Instruction::LDIR), - 0xB1 => Ok(Instruction::CPIR), - 0xB2 => Ok(Instruction::INIR), - 0xB3 => Ok(Instruction::OTIR), - 0xB8 => Ok(Instruction::LDDR), - 0xB9 => Ok(Instruction::CPDR), - 0xBA => Ok(Instruction::INDR), - 0xBB => Ok(Instruction::OTDR), + }, + 7 => match get_ins_y(ins) { + 0 => Ok(Instruction::LDsr(SpecialRegister::I, Direction::FromAcc)), + 1 => Ok(Instruction::LDsr(SpecialRegister::R, Direction::FromAcc)), + 2 => Ok(Instruction::LDsr(SpecialRegister::I, Direction::ToAcc)), + 3 => Ok(Instruction::LDsr(SpecialRegister::R, Direction::ToAcc)), + 4 => Ok(Instruction::RRD), + 5 => Ok(Instruction::RLD), _ => Ok(Instruction::NOP), - } + }, + _ => panic!("InternalError: impossible value"), + }, + 2 => match ins { + 0xA0 => Ok(Instruction::LDI), + 0xA1 => Ok(Instruction::CPI), + 0xA2 => Ok(Instruction::INI), + 0xA3 => Ok(Instruction::OUTI), + 0xA8 => Ok(Instruction::LDD), + 0xA9 => Ok(Instruction::CPD), + 0xAA => Ok(Instruction::IND), + 0xAB => Ok(Instruction::OUTD), + 0xB0 => Ok(Instruction::LDIR), + 0xB1 => Ok(Instruction::CPIR), + 0xB2 => Ok(Instruction::INIR), + 0xB3 => Ok(Instruction::OTIR), + 0xB8 => Ok(Instruction::LDDR), + 0xB9 => Ok(Instruction::CPDR), + 0xBA => Ok(Instruction::INDR), + 0xBB => Ok(Instruction::OTDR), + _ => Ok(Instruction::NOP), }, 3 => Ok(Instruction::NOP), _ => panic!("InternalError: impossible value"), @@ -372,125 +362,120 @@ impl Z80Decoder { } match get_ins_p(ins) { - 2 => { - match get_ins_z(ins) { - 1 => { - let data = self.read_instruction_word(memory)?; - Ok(Instruction::LD(LoadTarget::DirectRegWord(index_reg.into()), LoadTarget::ImmediateWord(data))) - }, - 2 => { - let addr = self.read_instruction_word(memory)?; - let regpair = index_reg.into(); - match get_ins_q(ins) != 0 { - false => Ok(Instruction::LD(LoadTarget::IndirectWord(addr), LoadTarget::DirectRegWord(regpair))), - true => Ok(Instruction::LD(LoadTarget::DirectRegWord(regpair), LoadTarget::IndirectWord(addr))), - } - }, - 3 => { - match get_ins_q(ins) != 0 { - false => Ok(Instruction::INC16(index_reg.into())), - true => Ok(Instruction::DEC16(index_reg.into())), - } - }, - 4 => { - self.extra_instruction_bytes = 4; - let half_target = Target::DirectRegHalf(get_index_register_half(index_reg, get_ins_q(ins))); - Ok(Instruction::INC8(half_target)) - }, - 5 => { - self.extra_instruction_bytes = 4; - let half_target = Target::DirectRegHalf(get_index_register_half(index_reg, get_ins_q(ins))); - Ok(Instruction::DEC8(half_target)) - }, - 6 => { - self.extra_instruction_bytes = 4; - let half_target = Target::DirectRegHalf(get_index_register_half(index_reg, get_ins_q(ins))); - let data = self.read_instruction_byte(memory)?; - Ok(Instruction::LD(to_load_target(half_target), LoadTarget::ImmediateByte(data))) - }, - _ => self.decode_bare(memory, ins, 4), - } + 2 => match get_ins_z(ins) { + 1 => { + let data = self.read_instruction_word(memory)?; + Ok(Instruction::LD(LoadTarget::DirectRegWord(index_reg.into()), LoadTarget::ImmediateWord(data))) + }, + 2 => { + let addr = self.read_instruction_word(memory)?; + let regpair = index_reg.into(); + match get_ins_q(ins) != 0 { + false => Ok(Instruction::LD(LoadTarget::IndirectWord(addr), LoadTarget::DirectRegWord(regpair))), + true => Ok(Instruction::LD(LoadTarget::DirectRegWord(regpair), LoadTarget::IndirectWord(addr))), + } + }, + 3 => match get_ins_q(ins) != 0 { + false => Ok(Instruction::INC16(index_reg.into())), + true => Ok(Instruction::DEC16(index_reg.into())), + }, + 4 => { + self.extra_instruction_bytes = 4; + let half_target = Target::DirectRegHalf(get_index_register_half(index_reg, get_ins_q(ins))); + Ok(Instruction::INC8(half_target)) + }, + 5 => { + self.extra_instruction_bytes = 4; + let half_target = Target::DirectRegHalf(get_index_register_half(index_reg, get_ins_q(ins))); + Ok(Instruction::DEC8(half_target)) + }, + 6 => { + self.extra_instruction_bytes = 4; + let half_target = Target::DirectRegHalf(get_index_register_half(index_reg, get_ins_q(ins))); + let data = self.read_instruction_byte(memory)?; + Ok(Instruction::LD(to_load_target(half_target), LoadTarget::ImmediateByte(data))) + }, + _ => self.decode_bare(memory, ins, 4), }, - 3 => { - match ins { - 0x34 => { - let offset = self.read_instruction_byte(memory)? as i8; - Ok(Instruction::INC8(Target::IndirectOffset(index_reg, offset))) - }, - 0x35 => { - let offset = self.read_instruction_byte(memory)? as i8; - Ok(Instruction::DEC8(Target::IndirectOffset(index_reg, offset))) - }, - 0x36 => { - let offset = self.read_instruction_byte(memory)? as i8; - let immediate = self.read_instruction_byte(memory)?; - Ok(Instruction::LD(LoadTarget::IndirectOffsetByte(index_reg, offset), LoadTarget::ImmediateByte(immediate))) - }, - _ => self.decode_bare(memory, ins, 4), - } + 3 => match ins { + 0x34 => { + let offset = self.read_instruction_byte(memory)? as i8; + Ok(Instruction::INC8(Target::IndirectOffset(index_reg, offset))) + }, + 0x35 => { + let offset = self.read_instruction_byte(memory)? as i8; + Ok(Instruction::DEC8(Target::IndirectOffset(index_reg, offset))) + }, + 0x36 => { + let offset = self.read_instruction_byte(memory)? as i8; + let immediate = self.read_instruction_byte(memory)?; + Ok(Instruction::LD( + LoadTarget::IndirectOffsetByte(index_reg, offset), + LoadTarget::ImmediateByte(immediate), + )) + }, + _ => self.decode_bare(memory, ins, 4), }, _ => self.decode_bare(memory, ins, 4), } }, - 1 => { - match get_ins_p(ins) { - 0 | 1 => { + 1 => match get_ins_p(ins) { + 0 | 1 => { + let target = match self.decode_index_target(memory, index_reg, get_ins_z(ins))? { + Some(target) => target, + None => return self.decode_bare(memory, ins, 4), + }; + + match (ins & 0x18) >> 3 { + 0 => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::B), to_load_target(target))), + 1 => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::C), to_load_target(target))), + 2 => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::D), to_load_target(target))), + 3 => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::E), to_load_target(target))), + _ => panic!("InternalError: impossible value"), + } + }, + 2 => { + let src = match get_ins_z(ins) { + 0 => Target::DirectReg(Register::B), + 1 => Target::DirectReg(Register::C), + 2 => Target::DirectReg(Register::D), + 3 => Target::DirectReg(Register::E), + 4 => Target::DirectRegHalf(get_index_register_half(index_reg, 0)), + 5 => Target::DirectRegHalf(get_index_register_half(index_reg, 1)), + 6 => { + let offset = self.read_instruction_byte(memory)? as i8; + let src = to_load_target(Target::IndirectOffset(index_reg, offset)); + if get_ins_q(ins) == 0 { + return Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::H), src)); + } else { + return Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::L), src)); + } + }, + 7 => Target::DirectReg(Register::A), + _ => panic!("InternalError: impossible value"), + }; + + let dest = get_index_register_half(index_reg, get_ins_q(ins)); + Ok(Instruction::LD(LoadTarget::DirectRegHalfByte(dest), to_load_target(src))) + }, + 3 => { + if get_ins_q(ins) == 0 { + if get_ins_z(ins) == 6 { + return self.decode_bare(memory, ins, 4); + } + let src = get_register(get_ins_z(ins)); + let offset = self.read_instruction_byte(memory)? as i8; + Ok(Instruction::LD(LoadTarget::IndirectOffsetByte(index_reg, offset), to_load_target(src))) + } else { let target = match self.decode_index_target(memory, index_reg, get_ins_z(ins))? { Some(target) => target, None => return self.decode_bare(memory, ins, 4), }; - match (ins & 0x18) >> 3 { - 0 => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::B), to_load_target(target))), - 1 => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::C), to_load_target(target))), - 2 => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::D), to_load_target(target))), - 3 => Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::E), to_load_target(target))), - _ => panic!("InternalError: impossible value"), - } - }, - 2 => { - let src = match get_ins_z(ins) { - 0 => Target::DirectReg(Register::B), - 1 => Target::DirectReg(Register::C), - 2 => Target::DirectReg(Register::D), - 3 => Target::DirectReg(Register::E), - 4 => Target::DirectRegHalf(get_index_register_half(index_reg, 0)), - 5 => Target::DirectRegHalf(get_index_register_half(index_reg, 1)), - 6 => { - let offset = self.read_instruction_byte(memory)? as i8; - let src = to_load_target(Target::IndirectOffset(index_reg, offset)); - if get_ins_q(ins) == 0 { - return Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::H), src)); - } else { - return Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::L), src)); - } - }, - 7 => Target::DirectReg(Register::A), - _ => panic!("InternalError: impossible value"), - }; - - let dest = get_index_register_half(index_reg, get_ins_q(ins)); - Ok(Instruction::LD(LoadTarget::DirectRegHalfByte(dest), to_load_target(src))) - }, - 3 => { - if get_ins_q(ins) == 0 { - if get_ins_z(ins) == 6 { - return self.decode_bare(memory, ins, 4); - } - let src = get_register(get_ins_z(ins)); - let offset = self.read_instruction_byte(memory)? as i8; - Ok(Instruction::LD(LoadTarget::IndirectOffsetByte(index_reg, offset), to_load_target(src))) - } else { - let target = match self.decode_index_target(memory, index_reg, get_ins_z(ins))? { - Some(target) => target, - None => return self.decode_bare(memory, ins, 4), - }; - - Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::A), to_load_target(target))) - } - }, - _ => panic!("InternalError: impossible value"), - } + Ok(Instruction::LD(LoadTarget::DirectRegByte(Register::A), to_load_target(target))) + } + }, + _ => panic!("InternalError: impossible value"), }, 2 => { self.extra_instruction_bytes = 4; @@ -512,21 +497,27 @@ impl Z80Decoder { _ => panic!("InternalError: impossible value"), } }, - 3 => { - match ins { - 0xE1 => Ok(Instruction::POP(index_reg.into())), - 0xE3 => Ok(Instruction::EXsp(index_reg.into())), - 0xE5 => Ok(Instruction::PUSH(index_reg.into())), - 0xE9 => Ok(Instruction::JPIndirect(index_reg.into())), - 0xF9 => Ok(Instruction::LD(LoadTarget::DirectRegWord(RegisterPair::SP), LoadTarget::DirectRegWord(index_reg.into()))), - _ => self.decode_bare(memory, ins, 4), - } + 3 => match ins { + 0xE1 => Ok(Instruction::POP(index_reg.into())), + 0xE3 => Ok(Instruction::EXsp(index_reg.into())), + 0xE5 => Ok(Instruction::PUSH(index_reg.into())), + 0xE9 => Ok(Instruction::JPIndirect(index_reg.into())), + 0xF9 => Ok(Instruction::LD( + LoadTarget::DirectRegWord(RegisterPair::SP), + LoadTarget::DirectRegWord(index_reg.into()), + )), + _ => self.decode_bare(memory, ins, 4), }, _ => panic!("InternalError: impossible value"), } } - fn decode_index_target(&mut self, memory: &mut dyn Addressable, index_reg: IndexRegister, z: u8) -> Result, Z80Error> { + fn decode_index_target( + &mut self, + memory: &mut dyn Addressable, + index_reg: IndexRegister, + z: u8, + ) -> Result, Z80Error> { let result = match z { 4 => Some(Target::DirectRegHalf(get_index_register_half(index_reg, 0))), 5 => Some(Target::DirectRegHalf(get_index_register_half(index_reg, 1))), @@ -675,8 +666,20 @@ fn get_register_pair_alt(reg: u8) -> RegisterPair { fn get_index_register_half(reg: IndexRegister, q: u8) -> IndexRegisterHalf { match reg { - IndexRegister::IX => if q == 0 { IndexRegisterHalf::IXH } else { IndexRegisterHalf::IXL }, - IndexRegister::IY => if q == 0 { IndexRegisterHalf::IYH } else { IndexRegisterHalf::IYL }, + IndexRegister::IX => { + if q == 0 { + IndexRegisterHalf::IXH + } else { + IndexRegisterHalf::IXL + } + }, + IndexRegister::IY => { + if q == 0 { + IndexRegisterHalf::IYH + } else { + IndexRegisterHalf::IYL + } + }, } } @@ -726,4 +729,3 @@ fn get_ins_p(ins: u8) -> u8 { fn get_ins_q(ins: u8) -> u8 { (ins >> 3) & 0x01 } - diff --git a/emulator/cpus/z80/src/execute.rs b/emulator/cpus/z80/src/execute.rs index a0d5fa4..db598df 100644 --- a/emulator/cpus/z80/src/execute.rs +++ b/emulator/cpus/z80/src/execute.rs @@ -1,16 +1,18 @@ - use femtos::{Instant, Duration}; use moa_core::{System, Error, Address, Steppable, Addressable, Interruptable, Debuggable, Transmutable, read_beu16, write_beu16}; -use crate::instructions::{Condition, Instruction, LoadTarget, Target, Register, InterruptMode, RegisterPair, IndexRegister, SpecialRegister, IndexRegisterHalf, Size, Direction, UndocumentedCopy}; +use crate::instructions::{ + Condition, Instruction, LoadTarget, Target, Register, InterruptMode, RegisterPair, IndexRegister, SpecialRegister, + IndexRegisterHalf, Size, Direction, UndocumentedCopy, +}; use crate::state::{Z80, Z80Error, Status, Flags}; use crate::timing::Z80InstructionCycles; -const FLAGS_NUMERIC: u8 = 0xC0; -const FLAGS_ARITHMETIC: u8 = 0x17; -const FLAGS_CARRY_HALF_CARRY: u8 = 0x11; +const FLAGS_NUMERIC: u8 = 0xC0; +const FLAGS_ARITHMETIC: u8 = 0x17; +const FLAGS_CARRY_HALF_CARRY: u8 = 0x11; enum RotateType { @@ -36,7 +38,7 @@ impl Steppable for Z80 { } } -impl Interruptable for Z80 { } +impl Interruptable for Z80 {} impl Transmutable for Z80 { @@ -72,7 +74,6 @@ impl From for Z80Error { Error::Other(msg) | Error::Assertion(msg) | Error::Emulator(_, msg) => Z80Error::BusError(msg.to_string()), } } - } #[derive(Clone)] pub struct Z80Executor { @@ -95,11 +96,9 @@ impl Z80 { match self.state.status { Status::Init => self.init(), Status::Halted => Err(Z80Error::Halted), - Status::Running => { - match self.cycle_one() { - Ok(clocks) => Ok(clocks), - Err(err) => Err(err), - } + Status::Running => match self.cycle_one() { + Ok(clocks) => Ok(clocks), + Err(err) => Err(err), }, } } @@ -120,12 +119,15 @@ impl Z80 { self.decode_next()?; self.execute_current()?; - Ok(Z80InstructionCycles::from_instruction(&self.decoder.instruction, self.decoder.extra_instruction_bytes)? - .calculate_cycles(self.executor.took_branch)) + Ok( + Z80InstructionCycles::from_instruction(&self.decoder.instruction, self.decoder.extra_instruction_bytes)? + .calculate_cycles(self.executor.took_branch), + ) } pub fn decode_next(&mut self) -> Result<(), Z80Error> { - self.decoder.decode_at(&mut self.port, self.executor.current_clock, self.state.pc)?; + self.decoder + .decode_at(&mut self.port, self.executor.current_clock, self.state.pc)?; self.increment_refresh(self.decoder.end.saturating_sub(self.decoder.start) as u8); self.state.pc = self.decoder.end; Ok(()) @@ -186,9 +188,7 @@ impl Z80 { Instruction::LDsr(special_reg, dir) => self.execute_ldsr(special_reg, dir), Instruction::LDD | Instruction::LDDR | Instruction::LDI | Instruction::LDIR => self.execute_ldx(), Instruction::NEG => self.execute_neg(), - Instruction::NOP => { - Ok(()) - }, + Instruction::NOP => Ok(()), Instruction::OR(target) => self.execute_or(target), //Instruction::OTDR => { //}, @@ -230,9 +230,7 @@ impl Z80 { Instruction::SRL(target, opt_copy) => self.execute_srl(target, opt_copy), Instruction::SUB(target) => self.execute_sub(target), Instruction::XOR(target) => self.execute_xor(target), - _ => { - Err(Z80Error::Unimplemented(self.decoder.instruction.clone())) - } + _ => Err(Z80Error::Unimplemented(self.decoder.instruction.clone())), } } @@ -242,7 +240,14 @@ impl Z80 { let (result1, carry1, overflow1, half_carry1) = add_bytes(acc, self.get_flag(Flags::Carry) as u8); let (result2, carry2, overflow2, half_carry2) = add_bytes(result1, src); - self.set_arithmetic_op_flags(result2 as u16, Size::Byte, false, carry1 | carry2, overflow1 ^ overflow2, half_carry1 | half_carry2); + self.set_arithmetic_op_flags( + result2 as u16, + Size::Byte, + false, + carry1 | carry2, + overflow1 ^ overflow2, + half_carry1 | half_carry2, + ); self.set_register_value(Register::A, result2); Ok(()) @@ -410,7 +415,7 @@ impl Z80 { let value = self.get_target_value(target)?; let (result, _, overflow, half_carry) = sub_bytes(value, 1); - let carry = self.get_flag(Flags::Carry); // Preserve the carry bit, according to Z80 reference + let carry = self.get_flag(Flags::Carry); // Preserve the carry bit, according to Z80 reference self.set_arithmetic_op_flags(result as u16, Size::Byte, true, carry, overflow, half_carry); self.set_target_value(target, result)?; @@ -498,7 +503,7 @@ impl Z80 { fn execute_inc8(&mut self, target: Target) -> Result<(), Z80Error> { let value = self.get_target_value(target)?; let (result, _, overflow, half_carry) = add_bytes(value, 1); - let carry = self.get_flag(Flags::Carry); // Preserve the carry bit, according to Z80 reference + let carry = self.get_flag(Flags::Carry); // Preserve the carry bit, according to Z80 reference self.set_arithmetic_op_flags(result as u16, Size::Byte, false, carry, overflow, half_carry); self.set_target_value(target, result)?; @@ -626,9 +631,7 @@ impl Z80 { let parity = if count != 0 { Flags::Parity as u8 } else { 0 }; self.set_flags(mask, parity); - if (self.decoder.instruction == Instruction::LDIR || self.decoder.instruction == Instruction::LDDR) - && count != 0 - { + if (self.decoder.instruction == Instruction::LDIR || self.decoder.instruction == Instruction::LDDR) && count != 0 { self.executor.took_branch = true; self.state.pc -= 2; } @@ -860,7 +863,14 @@ impl Z80 { let (result1, carry1, overflow1, half_carry1) = sub_bytes(acc, src); let (result2, carry2, overflow2, half_carry2) = sub_bytes(result1, self.get_flag(Flags::Carry) as u8); - self.set_arithmetic_op_flags(result2 as u16, Size::Byte, true, carry1 | carry2, overflow1 ^ overflow2, half_carry1 | half_carry2); + self.set_arithmetic_op_flags( + result2 as u16, + Size::Byte, + true, + carry1 | carry2, + overflow1 ^ overflow2, + half_carry1 | half_carry2, + ); self.set_register_value(Register::A, result2); Ok(()) @@ -1041,12 +1051,8 @@ impl Z80 { let addr = self.get_register_pair_value(regpair); self.read_port_u16(addr)? }, - LoadTarget::IndirectByte(addr) => { - self.read_port_u8(addr)? as u16 - }, - LoadTarget::IndirectWord(addr) => { - self.read_port_u16(addr)? - }, + LoadTarget::IndirectByte(addr) => self.read_port_u8(addr)? as u16, + LoadTarget::IndirectWord(addr) => self.read_port_u16(addr)?, LoadTarget::ImmediateByte(data) => data as u16, LoadTarget::ImmediateWord(data) => data, _ => panic!("Unsupported LoadTarget for set"), @@ -1176,10 +1182,18 @@ impl Z80 { fn set_index_register_half_value(&mut self, reg: IndexRegisterHalf, value: u8) { match reg { - IndexRegisterHalf::IXH => { self.state.ix = (self.state.ix & 0x00FF) | (value as u16) << 8; }, - IndexRegisterHalf::IXL => { self.state.ix = (self.state.ix & 0xFF00) | value as u16; }, - IndexRegisterHalf::IYH => { self.state.iy = (self.state.iy & 0x00FF) | (value as u16) << 8; }, - IndexRegisterHalf::IYL => { self.state.iy = (self.state.iy & 0xFF00) | value as u16; }, + IndexRegisterHalf::IXH => { + self.state.ix = (self.state.ix & 0x00FF) | (value as u16) << 8; + }, + IndexRegisterHalf::IXL => { + self.state.ix = (self.state.ix & 0xFF00) | value as u16; + }, + IndexRegisterHalf::IYH => { + self.state.iy = (self.state.iy & 0x00FF) | (value as u16) << 8; + }, + IndexRegisterHalf::IYL => { + self.state.iy = (self.state.iy & 0xFF00) | value as u16; + }, } } @@ -1197,13 +1211,27 @@ impl Z80 { fn set_register_pair_value(&mut self, regpair: RegisterPair, value: u16) { match regpair { - RegisterPair::BC => { write_beu16(&mut self.state.reg[0..2], value); }, - RegisterPair::DE => { write_beu16(&mut self.state.reg[2..4], value); }, - RegisterPair::HL => { write_beu16(&mut self.state.reg[4..6], value); }, - RegisterPair::AF => { write_beu16(&mut self.state.reg[6..8], value); }, - RegisterPair::SP => { self.state.sp = value; }, - RegisterPair::IX => { self.state.ix = value; }, - RegisterPair::IY => { self.state.iy = value; }, + RegisterPair::BC => { + write_beu16(&mut self.state.reg[0..2], value); + }, + RegisterPair::DE => { + write_beu16(&mut self.state.reg[2..4], value); + }, + RegisterPair::HL => { + write_beu16(&mut self.state.reg[4..6], value); + }, + RegisterPair::AF => { + write_beu16(&mut self.state.reg[6..8], value); + }, + RegisterPair::SP => { + self.state.sp = value; + }, + RegisterPair::IX => { + self.state.ix = value; + }, + RegisterPair::IY => { + self.state.iy = value; + }, } } @@ -1234,7 +1262,11 @@ impl Z80 { } fn set_parity_flags(&mut self, value: u8) { - let parity = if (value.count_ones() & 0x01) == 0 { Flags::Parity as u8 } else { 0 }; + let parity = if (value.count_ones() & 0x01) == 0 { + Flags::Parity as u8 + } else { + 0 + }; self.set_flags(Flags::Parity as u8, parity); } @@ -1313,4 +1345,3 @@ fn get_msb(value: u16, size: Size) -> bool { Size::Word => (value & 0x8000) != 0, } } - diff --git a/emulator/cpus/z80/src/instructions.rs b/emulator/cpus/z80/src/instructions.rs index a083635..e56cbe3 100644 --- a/emulator/cpus/z80/src/instructions.rs +++ b/emulator/cpus/z80/src/instructions.rs @@ -1,4 +1,3 @@ - #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Direction { ToAcc, @@ -206,5 +205,3 @@ impl RegisterPair { matches!(self, RegisterPair::IX | RegisterPair::IY) } } - - diff --git a/emulator/cpus/z80/src/lib.rs b/emulator/cpus/z80/src/lib.rs index d40824d..e95fcbe 100644 --- a/emulator/cpus/z80/src/lib.rs +++ b/emulator/cpus/z80/src/lib.rs @@ -1,4 +1,3 @@ - pub mod debugger; pub mod decode; pub mod execute; @@ -7,4 +6,3 @@ pub mod state; pub mod timing; pub use self::state::{Z80, Z80Type, Z80Error}; - diff --git a/emulator/cpus/z80/src/state.rs b/emulator/cpus/z80/src/state.rs index e738981..2b40704 100644 --- a/emulator/cpus/z80/src/state.rs +++ b/emulator/cpus/z80/src/state.rs @@ -1,4 +1,3 @@ - use std::rc::Rc; use std::cell::RefCell; use femtos::{Instant, Frequency}; @@ -28,6 +27,7 @@ pub enum Status { #[repr(u8)] #[allow(dead_code)] #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[rustfmt::skip] pub enum Flags { Carry = 0x01, AddSubtract = 0x02, @@ -134,9 +134,20 @@ impl Z80 { } } - pub fn from_type(cputype: Z80Type, frequency: Frequency, bus: Rc>, addr_offset: Address, io_bus: Option<(Rc>, Address)>) -> Self { + pub fn from_type( + cputype: Z80Type, + frequency: Frequency, + bus: Rc>, + addr_offset: Address, + io_bus: Option<(Rc>, Address)>, + ) -> Self { match cputype { - Z80Type::Z80 => Self::new(cputype, frequency, BusPort::new(addr_offset, 16, 8, bus), io_bus.map(|(io_bus, io_offset)| BusPort::new(io_offset, 16, 8, io_bus))), + Z80Type::Z80 => Self::new( + cputype, + frequency, + BusPort::new(addr_offset, 16, 8, bus), + io_bus.map(|(io_bus, io_offset)| BusPort::new(io_offset, 16, 8, io_bus)), + ), } } @@ -155,18 +166,45 @@ impl Z80 { println!("IX: {:#06x}", self.state.ix); println!("IY: {:#06x}", self.state.iy); - println!("A: {:#04x} F: {:#04x} A': {:#04x} F': {:#04x}", self.state.reg[Register::A as usize], self.state.reg[Register::F as usize], self.state.shadow_reg[Register::A as usize], self.state.shadow_reg[Register::F as usize]); - println!("B: {:#04x} C: {:#04x} B': {:#04x} C': {:#04x}", self.state.reg[Register::B as usize], self.state.reg[Register::C as usize], self.state.shadow_reg[Register::B as usize], self.state.shadow_reg[Register::C as usize]); - println!("D: {:#04x} E: {:#04x} D': {:#04x} E': {:#04x}", self.state.reg[Register::D as usize], self.state.reg[Register::E as usize], self.state.shadow_reg[Register::D as usize], self.state.shadow_reg[Register::E as usize]); - println!("H: {:#04x} L: {:#04x} H': {:#04x} L': {:#04x}", self.state.reg[Register::H as usize], self.state.reg[Register::L as usize], self.state.shadow_reg[Register::H as usize], self.state.shadow_reg[Register::L as usize]); + println!( + "A: {:#04x} F: {:#04x} A': {:#04x} F': {:#04x}", + self.state.reg[Register::A as usize], + self.state.reg[Register::F as usize], + self.state.shadow_reg[Register::A as usize], + self.state.shadow_reg[Register::F as usize] + ); + println!( + "B: {:#04x} C: {:#04x} B': {:#04x} C': {:#04x}", + self.state.reg[Register::B as usize], + self.state.reg[Register::C as usize], + self.state.shadow_reg[Register::B as usize], + self.state.shadow_reg[Register::C as usize] + ); + println!( + "D: {:#04x} E: {:#04x} D': {:#04x} E': {:#04x}", + self.state.reg[Register::D as usize], + self.state.reg[Register::E as usize], + self.state.shadow_reg[Register::D as usize], + self.state.shadow_reg[Register::E as usize] + ); + println!( + "H: {:#04x} L: {:#04x} H': {:#04x} L': {:#04x}", + self.state.reg[Register::H as usize], + self.state.reg[Register::L as usize], + self.state.shadow_reg[Register::H as usize], + self.state.shadow_reg[Register::L as usize] + ); println!("I: {:#04x} R: {:#04x}", self.state.i, self.state.r); println!("IM: {:?} IFF1: {:?} IFF2: {:?}", self.state.im, self.state.iff1, self.state.iff2); - println!("Current Instruction: {} {:?}", self.decoder.format_instruction_bytes(&mut self.port), self.decoder.instruction); + println!( + "Current Instruction: {} {:?}", + self.decoder.format_instruction_bytes(&mut self.port), + self.decoder.instruction + ); println!(); self.port.dump_memory(clock, self.state.sp as Address, 0x40); println!(); } } - diff --git a/emulator/cpus/z80/src/timing.rs b/emulator/cpus/z80/src/timing.rs index 77b06ed..b9d3dc0 100644 --- a/emulator/cpus/z80/src/timing.rs +++ b/emulator/cpus/z80/src/timing.rs @@ -1,18 +1,11 @@ - use moa_core::Error; use crate::instructions::{Instruction, Target, LoadTarget, RegisterPair}; pub enum Z80InstructionCycles { Single(u16), - Branch { - taken: u16, - not_taken: u16 - }, - Repeating { - repeating: u16, - terminating: u16, - }, + Branch { taken: u16, not_taken: u16 }, + Repeating { repeating: u16, terminating: u16 }, } impl Z80InstructionCycles { @@ -20,33 +13,47 @@ impl Z80InstructionCycles { match self { Z80InstructionCycles::Single(cycles) => *cycles, - Z80InstructionCycles::Branch { taken, not_taken } => if took_branch { *taken } else { *not_taken }, + Z80InstructionCycles::Branch { + taken, + not_taken, + } => { + if took_branch { + *taken + } else { + *not_taken + } + }, - Z80InstructionCycles::Repeating { repeating, terminating } => if took_branch { *repeating } else { *terminating }, + Z80InstructionCycles::Repeating { + repeating, + terminating, + } => { + if took_branch { + *repeating + } else { + *terminating + } + }, } } pub fn from_instruction(instruction: &Instruction, extra: u16) -> Result { let cycles = match instruction { - Instruction::ADCa(target) | - Instruction::ADDa(target) | - Instruction::AND(target) | - Instruction::CP(target) | - Instruction::SBCa(target) | - Instruction::SUB(target) | - Instruction::OR(target) | - Instruction::XOR(target) => { - match target { - Target::DirectReg(_) | - Target::DirectRegHalf(_) => 4, - Target::IndirectReg(_) => 7, - Target::Immediate(_) => 7, - Target::IndirectOffset(_, _) => 19, - } + Instruction::ADCa(target) + | Instruction::ADDa(target) + | Instruction::AND(target) + | Instruction::CP(target) + | Instruction::SBCa(target) + | Instruction::SUB(target) + | Instruction::OR(target) + | Instruction::XOR(target) => match target { + Target::DirectReg(_) | Target::DirectRegHalf(_) => 4, + Target::IndirectReg(_) => 7, + Target::Immediate(_) => 7, + Target::IndirectOffset(_, _) => 19, }, - Instruction::ADC16(_, _) | - Instruction::SBC16(_, _) => 15, + Instruction::ADC16(_, _) | Instruction::SBC16(_, _) => 15, Instruction::ADD16(dest_pair, _) => { if !dest_pair.is_index_reg() { @@ -56,13 +63,11 @@ impl Z80InstructionCycles { } }, - Instruction::BIT(_, target) => { - match target { - Target::DirectReg(_) => 8, - Target::IndirectReg(_) => 12, - Target::IndirectOffset(_, _) => 20, - _ => return Err(Error::new(format!("unexpected instruction: {:?}", instruction))), - } + Instruction::BIT(_, target) => match target { + Target::DirectReg(_) => 8, + Target::IndirectReg(_) => 12, + Target::IndirectOffset(_, _) => 20, + _ => return Err(Error::new(format!("unexpected instruction: {:?}", instruction))), }, Instruction::CALL(_) => 17, @@ -76,45 +81,40 @@ impl Z80InstructionCycles { Instruction::CCF => 4, - Instruction::CPD | - Instruction::CPI | - Instruction::IND | - Instruction::INI | - Instruction::LDD | - Instruction::LDI | - Instruction::OUTD | - Instruction::OUTI => 16, + Instruction::CPD + | Instruction::CPI + | Instruction::IND + | Instruction::INI + | Instruction::LDD + | Instruction::LDI + | Instruction::OUTD + | Instruction::OUTI => 16, - Instruction::CPDR | - Instruction::CPIR | - Instruction::INDR | - Instruction::INIR | - Instruction::LDDR | - Instruction::LDIR | - Instruction::OTDR | - Instruction::OTIR => { + Instruction::CPDR + | Instruction::CPIR + | Instruction::INDR + | Instruction::INIR + | Instruction::LDDR + | Instruction::LDIR + | Instruction::OTDR + | Instruction::OTIR => { return Ok(Z80InstructionCycles::Repeating { repeating: 21 + extra, terminating: 16 + extra, - }) + }); }, Instruction::CPL => 4, Instruction::DAA => 4, - Instruction::DEC8(target) | - Instruction::INC8(target) => { - match target { - Target::DirectReg(_) | - Target::DirectRegHalf(_) => 4, - Target::IndirectReg(_) => 11, - Target::IndirectOffset(_, _) => 23, - _ => return Err(Error::new(format!("unexpected instruction: {:?}", instruction))), - } + Instruction::DEC8(target) | Instruction::INC8(target) => match target { + Target::DirectReg(_) | Target::DirectRegHalf(_) => 4, + Target::IndirectReg(_) => 11, + Target::IndirectOffset(_, _) => 23, + _ => return Err(Error::new(format!("unexpected instruction: {:?}", instruction))), }, - Instruction::DEC16(regpair) | - Instruction::INC16(regpair) => { + Instruction::DEC16(regpair) | Instruction::INC16(regpair) => { if !regpair.is_index_reg() { 6 } else { @@ -122,8 +122,7 @@ impl Z80InstructionCycles { } }, - Instruction::DI | - Instruction::EI => 4, + Instruction::DI | Instruction::EI => 4, Instruction::DJNZ(_) => { return Ok(Z80InstructionCycles::Branch { @@ -146,13 +145,9 @@ impl Z80InstructionCycles { Instruction::HALT => 4, Instruction::IM(_) => 8, - Instruction::INic(_) | - Instruction::INicz | - Instruction::OUTic(_) | - Instruction::OUTicz => 12, + Instruction::INic(_) | Instruction::INicz | Instruction::OUTic(_) | Instruction::OUTicz => 12, - Instruction::INx(_) | - Instruction::OUTx(_) => 11, + Instruction::INx(_) | Instruction::OUTx(_) => 11, Instruction::JP(_) => 10, Instruction::JR(_) => 12, @@ -177,29 +172,24 @@ impl Z80InstructionCycles { Instruction::LD(dest, src) => { match (dest, src) { // 8-Bit Operations - (LoadTarget::DirectRegByte(_), LoadTarget::DirectRegByte(_)) => 4, - (LoadTarget::DirectRegHalfByte(_), LoadTarget::DirectRegByte(_)) | - (LoadTarget::DirectRegByte(_), LoadTarget::DirectRegHalfByte(_)) | - (LoadTarget::DirectRegHalfByte(_), LoadTarget::DirectRegHalfByte(_)) => 8, + (LoadTarget::DirectRegHalfByte(_), LoadTarget::DirectRegByte(_)) + | (LoadTarget::DirectRegByte(_), LoadTarget::DirectRegHalfByte(_)) + | (LoadTarget::DirectRegHalfByte(_), LoadTarget::DirectRegHalfByte(_)) => 8, (LoadTarget::DirectRegByte(_) | LoadTarget::DirectRegHalfByte(_), LoadTarget::ImmediateByte(_)) => 7, (LoadTarget::IndirectRegByte(_), LoadTarget::ImmediateByte(_)) => 10, - (LoadTarget::IndirectOffsetByte(_, _), _) | - (_, LoadTarget::IndirectOffsetByte(_, _)) => 19, + (LoadTarget::IndirectOffsetByte(_, _), _) | (_, LoadTarget::IndirectOffsetByte(_, _)) => 19, - (_, LoadTarget::IndirectRegByte(_)) | - (LoadTarget::IndirectRegByte(_), _) => 7, + (_, LoadTarget::IndirectRegByte(_)) | (LoadTarget::IndirectRegByte(_), _) => 7, - (_, LoadTarget::IndirectByte(_)) | - (LoadTarget::IndirectByte(_), _) => 13, + (_, LoadTarget::IndirectByte(_)) | (LoadTarget::IndirectByte(_), _) => 13, // 16-Bit Operations - - (LoadTarget::DirectRegWord(regpair), LoadTarget::ImmediateWord(_)) | - (LoadTarget::ImmediateWord(_), LoadTarget::DirectRegWord(regpair)) => { + (LoadTarget::DirectRegWord(regpair), LoadTarget::ImmediateWord(_)) + | (LoadTarget::ImmediateWord(_), LoadTarget::DirectRegWord(regpair)) => { if !regpair.is_index_reg() { 10 } else { @@ -215,11 +205,10 @@ impl Z80InstructionCycles { } }, - (LoadTarget::IndirectWord(_), LoadTarget::DirectRegWord(RegisterPair::HL)) | - (LoadTarget::DirectRegWord(RegisterPair::HL), LoadTarget::IndirectWord(_)) => 16, + (LoadTarget::IndirectWord(_), LoadTarget::DirectRegWord(RegisterPair::HL)) + | (LoadTarget::DirectRegWord(RegisterPair::HL), LoadTarget::IndirectWord(_)) => 16, - (LoadTarget::IndirectWord(_), _) | - (_, LoadTarget::IndirectWord(_)) => 20, + (LoadTarget::IndirectWord(_), _) | (_, LoadTarget::IndirectWord(_)) => 20, _ => return Err(Error::new(format!("unexpected instruction: {:?}", instruction))), } @@ -230,7 +219,6 @@ impl Z80InstructionCycles { Instruction::NEG => 8, Instruction::NOP => 4, - Instruction::POP(regpair) => { if !regpair.is_index_reg() { 10 @@ -246,14 +234,11 @@ impl Z80InstructionCycles { } }, - Instruction::RES(_, target, _) | - Instruction::SET(_, target, _) => { - match target { - Target::DirectReg(_) => 8, - Target::IndirectReg(_) => 15, - Target::IndirectOffset(_, _) => 23, - _ => return Err(Error::new(format!("unexpected instruction: {:?}", instruction))), - } + Instruction::RES(_, target, _) | Instruction::SET(_, target, _) => match target { + Target::DirectReg(_) => 8, + Target::IndirectReg(_) => 15, + Target::IndirectOffset(_, _) => 23, + _ => return Err(Error::new(format!("unexpected instruction: {:?}", instruction))), }, Instruction::RET => 10, @@ -267,26 +252,21 @@ impl Z80InstructionCycles { }); }, - Instruction::RL(target, _) | - Instruction::RLC(target, _) | - Instruction::RR(target, _) | - Instruction::RRC(target, _) | - Instruction::SLA(target, _) | - Instruction::SLL(target, _) | - Instruction::SRA(target, _) | - Instruction::SRL(target, _) => { - match target { - Target::DirectReg(_) => 8, - Target::IndirectReg(_) => 15, - Target::IndirectOffset(_, _) => 23, - _ => return Err(Error::new(format!("unexpected instruction: {:?}", instruction))), - } + Instruction::RL(target, _) + | Instruction::RLC(target, _) + | Instruction::RR(target, _) + | Instruction::RRC(target, _) + | Instruction::SLA(target, _) + | Instruction::SLL(target, _) + | Instruction::SRA(target, _) + | Instruction::SRL(target, _) => match target { + Target::DirectReg(_) => 8, + Target::IndirectReg(_) => 15, + Target::IndirectOffset(_, _) => 23, + _ => return Err(Error::new(format!("unexpected instruction: {:?}", instruction))), }, - Instruction::RLA | - Instruction::RLCA | - Instruction::RRA | - Instruction::RRCA => 4, + Instruction::RLA | Instruction::RLCA | Instruction::RRA | Instruction::RRCA => 4, Instruction::RLD => 18, Instruction::RRD => 18, @@ -298,4 +278,3 @@ impl Z80InstructionCycles { Ok(Z80InstructionCycles::Single(cycles + extra)) } } - diff --git a/emulator/cpus/z80/tests/decode_tests.rs b/emulator/cpus/z80/tests/decode_tests.rs index 87b83e9..d55e10e 100644 --- a/emulator/cpus/z80/tests/decode_tests.rs +++ b/emulator/cpus/z80/tests/decode_tests.rs @@ -1,4 +1,3 @@ - use femtos::Frequency; use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Device}; @@ -55,6 +54,7 @@ fn run_all_decode_tests() { } } +#[rustfmt::skip] const DECODE_TESTS: &'static [(&[u8], Instruction)] = &[ (&[0x00], Instruction::NOP), (&[0x01, 0x01, 0x02], Instruction::LD(LoadTarget::DirectRegWord(RegisterPair::BC), LoadTarget::ImmediateWord(0x0201))), @@ -70,4 +70,3 @@ const DECODE_TESTS: &'static [(&[u8], Instruction)] = &[ (&[0xDD, 0x84], Instruction::ADDa(Target::DirectRegHalf(IndexRegisterHalf::IXH))), (&[0xDD, 0x85], Instruction::ADDa(Target::DirectRegHalf(IndexRegisterHalf::IXL))), ]; - diff --git a/emulator/cpus/z80/tests/execute_tests.rs b/emulator/cpus/z80/tests/execute_tests.rs index 23ca97a..3c2d716 100644 --- a/emulator/cpus/z80/tests/execute_tests.rs +++ b/emulator/cpus/z80/tests/execute_tests.rs @@ -1,4 +1,3 @@ - use femtos::Frequency; use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Device}; @@ -26,6 +25,7 @@ struct TestCase { fini: TestState, } +#[rustfmt::skip] const TEST_CASES: &'static [TestCase] = &[ /* TestCase { @@ -551,4 +551,3 @@ pub fn run_execute_tests() { run_test(case); } } - diff --git a/emulator/frontends/common/src/audio.rs b/emulator/frontends/common/src/audio.rs index a15956a..3381074 100644 --- a/emulator/frontends/common/src/audio.rs +++ b/emulator/frontends/common/src/audio.rs @@ -1,4 +1,3 @@ - use std::sync::{Arc, Mutex, MutexGuard}; use femtos::{Instant, Duration}; @@ -21,10 +20,7 @@ impl AudioSource { let (id, sample_rate) = { let mut mixer = mixer.borrow_mut(); let id = mixer.add_source(queue.clone()); - ( - id, - mixer.sample_rate(), - ) + (id, mixer.sample_rate()) }; Self { @@ -122,7 +118,9 @@ impl AudioMixerInner { if let Some((clock, mut frame)) = source.pop_next() { index = (clock.duration_since(frame_start) / sample_duration) as usize; let size = frame.data.len().min(data.len() - index); - frame.data.iter() + frame + .data + .iter() .zip(&mut data[index..index + size]) .for_each(|(source, dest)| { dest.0 += source.0; @@ -198,4 +196,3 @@ impl AudioOutput { self.queue.is_empty() } } - diff --git a/emulator/frontends/common/src/cpal.rs b/emulator/frontends/common/src/cpal.rs index 24e9910..19d3c09 100644 --- a/emulator/frontends/common/src/cpal.rs +++ b/emulator/frontends/common/src/cpal.rs @@ -1,5 +1,7 @@ - -use cpal::{Stream, SampleRate, SampleFormat, StreamConfig, OutputCallbackInfo, traits::{DeviceTrait, HostTrait, StreamTrait}}; +use cpal::{ + Stream, SampleRate, SampleFormat, StreamConfig, OutputCallbackInfo, + traits::{DeviceTrait, HostTrait, StreamTrait}, +}; use crate::audio::{AudioOutput, SAMPLE_RATE}; @@ -27,7 +29,9 @@ impl CpalAudioOutput { while index < data.len() { if let Some((clock, mut frame)) = output.receive() { let size = (frame.data.len() * 2).min(data.len() - index); - frame.data.iter() + frame + .data + .iter() .zip(data[index..index + size].chunks_mut(2)) .for_each(|(sample, location)| { location[0] = sample.0; @@ -45,13 +49,11 @@ impl CpalAudioOutput { } }; - let stream = device.build_output_stream( - &config, - data_callback, - move |err| { + let stream = device + .build_output_stream(&config, data_callback, move |err| { log::error!("ERROR: {:?}", err); - }, - ).unwrap(); + }) + .unwrap(); stream.play().unwrap(); @@ -68,4 +70,3 @@ impl CpalAudioOutput { } } } - diff --git a/emulator/frontends/common/src/lib.rs b/emulator/frontends/common/src/lib.rs index 46aac76..cfb4b87 100644 --- a/emulator/frontends/common/src/lib.rs +++ b/emulator/frontends/common/src/lib.rs @@ -1,4 +1,3 @@ - #[cfg(feature = "tty")] pub mod tty; @@ -9,4 +8,3 @@ pub use crate::audio::{AudioMixer, AudioSource}; pub mod cpal; #[cfg(feature = "audio")] pub use crate::cpal::CpalAudioOutput; - diff --git a/emulator/frontends/common/src/tty.rs b/emulator/frontends/common/src/tty.rs index 8422103..21214b2 100644 --- a/emulator/frontends/common/src/tty.rs +++ b/emulator/frontends/common/src/tty.rs @@ -1,4 +1,3 @@ - use std::thread; use std::sync::mpsc; use std::time::Duration; @@ -34,11 +33,13 @@ impl SimplePty { } pub fn open() -> Result { - let pty = pty::posix_openpt(OFlag::O_RDWR).and_then(|pty| { - pty::grantpt(&pty)?; - pty::unlockpt(&pty)?; - Ok(pty) - }).map_err(|_| SimplePtyError::Open)?; + let pty = pty::posix_openpt(OFlag::O_RDWR) + .and_then(|pty| { + pty::grantpt(&pty)?; + pty::unlockpt(&pty)?; + Ok(pty) + }) + .map_err(|_| SimplePtyError::Open)?; let name = unsafe { pty::ptsname(&pty).map_err(|_| SimplePtyError::PtsName)? }; let (input_tx, input_rx) = mpsc::channel(); @@ -61,8 +62,10 @@ impl SimplePty { Ok(_) => { input_tx.send(buf[0]).unwrap(); }, - Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => { }, - Err(err) => { println!("ERROR: {:?}", err); } + Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => {}, + Err(err) => { + println!("ERROR: {:?}", err); + }, } while let Ok(data) = output_rx.try_recv() { @@ -92,4 +95,3 @@ impl Tty for SimplePty { true } } - diff --git a/emulator/frontends/console/src/bin/moa-bench.rs b/emulator/frontends/console/src/bin/moa-bench.rs index 898ce40..81a1e7b 100644 --- a/emulator/frontends/console/src/bin/moa-bench.rs +++ b/emulator/frontends/console/src/bin/moa-bench.rs @@ -1,4 +1,3 @@ - use std::thread; use std::time::Duration; use femtos::Frequency; @@ -45,4 +44,3 @@ fn main() { }); thread::sleep(Duration::from_secs(10)); } - diff --git a/emulator/frontends/console/src/bin/moa-computie.rs b/emulator/frontends/console/src/bin/moa-computie.rs index b073823..c9f08e5 100644 --- a/emulator/frontends/console/src/bin/moa-computie.rs +++ b/emulator/frontends/console/src/bin/moa-computie.rs @@ -1,4 +1,3 @@ - use clap::Arg; use moa_console::ConsoleFrontend; @@ -6,11 +5,13 @@ use moa_systems_computie::{build_computie, ComputieOptions}; fn main() { let matches = ConsoleFrontend::args("Computie68k Emulator") - .arg(Arg::new("ROM") - .short('r') - .long("rom") - .value_name("FILE") - .help("ROM file to load at the start of memory")) + .arg( + Arg::new("ROM") + .short('r') + .long("rom") + .value_name("FILE") + .help("ROM file to load at the start of memory"), + ) .get_matches(); let mut options = ComputieOptions::default(); @@ -23,4 +24,3 @@ fn main() { let system = build_computie(&frontend, options).unwrap(); frontend.start(matches, system); } - diff --git a/emulator/frontends/console/src/bin/moa-console-genesis.rs b/emulator/frontends/console/src/bin/moa-console-genesis.rs index dbbf581..91717c0 100644 --- a/emulator/frontends/console/src/bin/moa-console-genesis.rs +++ b/emulator/frontends/console/src/bin/moa-console-genesis.rs @@ -1,4 +1,3 @@ - use clap::{Arg}; use moa_console::ConsoleFrontend; @@ -6,8 +5,7 @@ use moa_systems_genesis::{build_genesis, SegaGenesisOptions}; fn main() { let matches = ConsoleFrontend::args("Sega Genesis/Mega Drive Emulator") - .arg(Arg::new("ROM") - .help("ROM file to load (must be flat binary)")) + .arg(Arg::new("ROM").help("ROM file to load (must be flat binary)")) .get_matches(); let mut frontend = ConsoleFrontend; @@ -20,4 +18,3 @@ fn main() { let system = build_genesis(&mut frontend, options).unwrap(); frontend.start(matches, system); } - diff --git a/emulator/frontends/console/src/lib.rs b/emulator/frontends/console/src/lib.rs index 1d5727c..c0b1971 100644 --- a/emulator/frontends/console/src/lib.rs +++ b/emulator/frontends/console/src/lib.rs @@ -1,4 +1,3 @@ - use clap::{Command, Arg, ArgAction, ArgMatches}; use std::io::{self, Write}; use femtos::Duration; @@ -14,7 +13,8 @@ impl Host for ConsoleFrontend { fn add_pty(&self) -> Result, HostError> { use moa_common::tty::SimplePty; - Ok(Box::new(SimplePty::open().map_err(|_| HostError::TTYNotSupported)?)) //.map_err(|err| Error::new(format!("console: error opening pty: {:?}", err)))?)) + Ok(Box::new(SimplePty::open().map_err(|_| HostError::TTYNotSupported)?)) + //.map_err(|err| Error::new(format!("console: error opening pty: {:?}", err)))?)) } fn add_video_source(&mut self, _receiver: FrameReceiver) -> Result<(), HostError> { @@ -42,15 +42,19 @@ impl Default for ConsoleFrontend { impl ConsoleFrontend { pub fn args(application_name: &'static str) -> Command { Command::new(application_name) - .arg(Arg::new("log-level") - .short('l') - .long("log-level") - .help("Set the type of log messages to print")) - .arg(Arg::new("debugger") - .short('d') - .long("debugger") - .action(ArgAction::SetTrue) - .help("Start the debugger before running machine")) + .arg( + Arg::new("log-level") + .short('l') + .long("log-level") + .help("Set the type of log messages to print"), + ) + .arg( + Arg::new("debugger") + .short('d') + .long("debugger") + .action(ArgAction::SetTrue) + .help("Start the debugger before running machine"), + ) } pub fn start(self, matches: ArgMatches, mut system: System) { @@ -108,4 +112,3 @@ impl ConsoleFrontend { } } } - diff --git a/emulator/frontends/minifb/src/bin/moa-genesis.rs b/emulator/frontends/minifb/src/bin/moa-genesis.rs index 86d1231..c23eaac 100644 --- a/emulator/frontends/minifb/src/bin/moa-genesis.rs +++ b/emulator/frontends/minifb/src/bin/moa-genesis.rs @@ -1,12 +1,10 @@ - use clap::Arg; use moa_systems_genesis::{build_genesis, SegaGenesisOptions}; fn main() { let matches = moa_minifb::new("Sega Genesis/Mega Drive Emulator") - .arg(Arg::new("ROM") - .help("ROM file to load (must be flat binary)")) + .arg(Arg::new("ROM").help("ROM file to load (must be flat binary)")) .get_matches(); let mut options = SegaGenesisOptions::default(); @@ -14,8 +12,5 @@ fn main() { options.rom = filename.to_string(); } - moa_minifb::run(matches, |frontend| { - build_genesis(frontend, options) - }); + moa_minifb::run(matches, |frontend| build_genesis(frontend, options)); } - diff --git a/emulator/frontends/minifb/src/bin/moa-macintosh.rs b/emulator/frontends/minifb/src/bin/moa-macintosh.rs index 8db7f19..220e82f 100644 --- a/emulator/frontends/minifb/src/bin/moa-macintosh.rs +++ b/emulator/frontends/minifb/src/bin/moa-macintosh.rs @@ -1,12 +1,7 @@ - use moa_systems_macintosh::build_macintosh_512k; fn main() { - let matches = moa_minifb::new("Macintosh 512k Emulator") - .get_matches(); + let matches = moa_minifb::new("Macintosh 512k Emulator").get_matches(); - moa_minifb::run(matches, |frontend| { - build_macintosh_512k(frontend) - }); + moa_minifb::run(matches, |frontend| build_macintosh_512k(frontend)); } - diff --git a/emulator/frontends/minifb/src/bin/moa-synth.rs b/emulator/frontends/minifb/src/bin/moa-synth.rs index f3057f7..4f7a053 100644 --- a/emulator/frontends/minifb/src/bin/moa-synth.rs +++ b/emulator/frontends/minifb/src/bin/moa-synth.rs @@ -1,4 +1,3 @@ - use femtos::{Instant, Duration, Frequency}; use moa_peripherals_yamaha::{Ym2612, Sn76489}; @@ -26,20 +25,23 @@ impl SynthControl { impl Steppable for SynthControl { fn step(&mut self, system: &System) -> Result { if let Some(event) = self.key_receiver.receive() { - match event.key { Key::Enter => { system.get_bus().write_u8(system.clock, 0x00, 0x28)?; - system.get_bus().write_u8(system.clock, 0x01, if event.state { 0xF0 } else { 0x00 })?; + system + .get_bus() + .write_u8(system.clock, 0x01, if event.state { 0xF0 } else { 0x00 })?; }, Key::A => { system.get_bus().write_u8(system.clock, 0x10, 0x84)?; system.get_bus().write_u8(system.clock, 0x10, 0x0F)?; - system.get_bus().write_u8(system.clock, 0x10, if event.state { 0x90 } else { 0x9F })?; + system + .get_bus() + .write_u8(system.clock, 0x10, if event.state { 0x90 } else { 0x9F })?; }, - _ => { }, + _ => {}, } } @@ -79,8 +81,7 @@ fn initialize_ym(ym_sound: Device) -> Result<(), Error> { } fn main() { - let matches = moa_minifb::new("YM2612 Tester/Synth") - .get_matches(); + let matches = moa_minifb::new("YM2612 Tester/Synth").get_matches(); moa_minifb::run(matches, |host| { let mut system = System::default(); @@ -103,5 +104,3 @@ fn main() { Ok(system) }); } - - diff --git a/emulator/frontends/minifb/src/bin/moa-trs80.rs b/emulator/frontends/minifb/src/bin/moa-trs80.rs index 9273148..f5cc7a1 100644 --- a/emulator/frontends/minifb/src/bin/moa-trs80.rs +++ b/emulator/frontends/minifb/src/bin/moa-trs80.rs @@ -1,16 +1,17 @@ - use clap::{Arg, ArgAction}; use moa_systems_trs80::{build_trs80, Trs80Options}; fn main() { let matches = moa_minifb::new("TRS-80 Emulator") - .arg(Arg::new("ROM") - .short('r') - .long("rom") - .action(ArgAction::SetTrue) - .value_name("FILE") - .help("ROM file to load at the start of memory")) + .arg( + Arg::new("ROM") + .short('r') + .long("rom") + .action(ArgAction::SetTrue) + .value_name("FILE") + .help("ROM file to load at the start of memory"), + ) .get_matches(); let mut options = Trs80Options::default(); @@ -18,8 +19,5 @@ fn main() { options.rom = filename.to_string(); } - moa_minifb::run(matches, |frontend| { - build_trs80(frontend, options) - }); + moa_minifb::run(matches, |frontend| build_trs80(frontend, options)); } - diff --git a/emulator/frontends/minifb/src/controllers.rs b/emulator/frontends/minifb/src/controllers.rs index d7f58d3..1bd5782 100644 --- a/emulator/frontends/minifb/src/controllers.rs +++ b/emulator/frontends/minifb/src/controllers.rs @@ -1,19 +1,17 @@ - use minifb::Key as MiniKey; use moa_host::ControllerInput; pub fn map_controller_a(key: MiniKey, state: bool) -> Option { match key { - MiniKey::A => { Some(ControllerInput::ButtonA(state)) }, - MiniKey::O => { Some(ControllerInput::ButtonB(state)) }, - MiniKey::E => { Some(ControllerInput::ButtonC(state)) }, - MiniKey::Up => { Some(ControllerInput::DpadUp(state)) }, - MiniKey::Down => { Some(ControllerInput::DpadDown(state)) }, - MiniKey::Left => { Some(ControllerInput::DpadLeft(state)) }, - MiniKey::Right => { Some(ControllerInput::DpadRight(state)) }, - MiniKey::Enter => { Some(ControllerInput::Start(state)) }, - MiniKey::M => { Some(ControllerInput::Mode(state)) }, + MiniKey::A => Some(ControllerInput::ButtonA(state)), + MiniKey::O => Some(ControllerInput::ButtonB(state)), + MiniKey::E => Some(ControllerInput::ButtonC(state)), + MiniKey::Up => Some(ControllerInput::DpadUp(state)), + MiniKey::Down => Some(ControllerInput::DpadDown(state)), + MiniKey::Left => Some(ControllerInput::DpadLeft(state)), + MiniKey::Right => Some(ControllerInput::DpadRight(state)), + MiniKey::Enter => Some(ControllerInput::Start(state)), + MiniKey::M => Some(ControllerInput::Mode(state)), _ => None, } } - diff --git a/emulator/frontends/minifb/src/keys.rs b/emulator/frontends/minifb/src/keys.rs index bd3b4a7..fe8ad31 100644 --- a/emulator/frontends/minifb/src/keys.rs +++ b/emulator/frontends/minifb/src/keys.rs @@ -1,4 +1,3 @@ - use minifb::Key as MiniKey; use moa_host::Key; @@ -109,4 +108,3 @@ pub fn map_key(key: MiniKey) -> Key { _ => Key::Unknown, } } - diff --git a/emulator/frontends/minifb/src/lib.rs b/emulator/frontends/minifb/src/lib.rs index 6c05bb3..fccf64f 100644 --- a/emulator/frontends/minifb/src/lib.rs +++ b/emulator/frontends/minifb/src/lib.rs @@ -1,4 +1,3 @@ - use std::thread; use std::io::{self, Write}; use std::sync::{Arc, Mutex}; @@ -10,13 +9,16 @@ use femtos::{Duration as FemtosDuration}; use moa_core::{System, Error, Device}; use moa_debugger::{Debugger, DebugControl}; -use moa_host::{Host, HostError, Audio, KeyEvent, MouseEvent, MouseState, ControllerDevice, ControllerEvent, EventSender, PixelEncoding, Frame, FrameReceiver}; +use moa_host::{ + Host, HostError, Audio, KeyEvent, MouseEvent, MouseState, ControllerDevice, ControllerEvent, EventSender, PixelEncoding, Frame, + FrameReceiver, +}; use moa_common::{AudioMixer, AudioSource}; use moa_common::CpalAudioOutput; -mod keys; mod controllers; +mod keys; use crate::keys::map_key; use crate::controllers::map_controller_a; @@ -28,36 +30,46 @@ const HEIGHT: u32 = 224; pub fn new(name: &'static str) -> Command { Command::new(name) - .arg(Arg::new("scale") - .short('s') - .long("scale") - .help("Scale the screen")) - .arg(Arg::new("speed") - .short('x') - .long("speed") - .help("Adjust the speed of the simulation")) - .arg(Arg::new("threaded") - .short('t') - .long("threaded") - .action(ArgAction::SetTrue) - .help("Run the simulation in a separate thread")) - .arg(Arg::new("log-level") - .short('l') - .long("log-level") - .help("Set the type of log messages to print")) - .arg(Arg::new("debugger") - .short('d') - .long("debugger") - .action(ArgAction::SetTrue) - .help("Start the debugger before running machine")) - .arg(Arg::new("disable-audio") - .short('a') - .long("disable-audio") - .action(ArgAction::SetTrue) - .help("Disable audio output")) + .arg(Arg::new("scale").short('s').long("scale").help("Scale the screen")) + .arg( + Arg::new("speed") + .short('x') + .long("speed") + .help("Adjust the speed of the simulation"), + ) + .arg( + Arg::new("threaded") + .short('t') + .long("threaded") + .action(ArgAction::SetTrue) + .help("Run the simulation in a separate thread"), + ) + .arg( + Arg::new("log-level") + .short('l') + .long("log-level") + .help("Set the type of log messages to print"), + ) + .arg( + Arg::new("debugger") + .short('d') + .long("debugger") + .action(ArgAction::SetTrue) + .help("Start the debugger before running machine"), + ) + .arg( + Arg::new("disable-audio") + .short('a') + .long("disable-audio") + .action(ArgAction::SetTrue) + .help("Disable audio output"), + ) } -pub fn run(matches: ArgMatches, init: I) where I: FnOnce(&mut MiniFrontendBuilder) -> Result + Send + 'static { +pub fn run(matches: ArgMatches, init: I) +where + I: FnOnce(&mut MiniFrontendBuilder) -> Result + Send + 'static, +{ if matches.get_flag("threaded") { run_threaded(matches, init); } else { @@ -65,16 +77,20 @@ pub fn run(matches: ArgMatches, init: I) where I: FnOnce(&mut MiniFrontendBui } } -pub fn run_inline(matches: ArgMatches, init: I) where I: FnOnce(&mut MiniFrontendBuilder) -> Result { +pub fn run_inline(matches: ArgMatches, init: I) +where + I: FnOnce(&mut MiniFrontendBuilder) -> Result, +{ let mut frontend = MiniFrontendBuilder::default(); let system = init(&mut frontend).unwrap(); - frontend - .build() - .start(matches, Some(system)); + frontend.build().start(matches, Some(system)); } -pub fn run_threaded(matches: ArgMatches, init: I) where I: FnOnce(&mut MiniFrontendBuilder) -> Result + Send + 'static { +pub fn run_threaded(matches: ArgMatches, init: I) +where + I: FnOnce(&mut MiniFrontendBuilder) -> Result + Send + 'static, +{ let frontend = Arc::new(Mutex::new(MiniFrontendBuilder::default())); { @@ -88,10 +104,7 @@ pub fn run_threaded(matches: ArgMatches, init: I) where I: FnOnce(&mut MiniFr wait_until_initialized(frontend.clone()); - frontend - .lock().unwrap() - .build() - .start(matches, None); + frontend.lock().unwrap().build().start(matches, None); } fn wait_until_initialized(frontend: Arc>) { @@ -156,7 +169,9 @@ impl Host for MiniFrontendBuilder { fn register_controllers(&mut self, sender: EventSender) -> Result<(), HostError> { if self.controllers.is_some() { - return Err(HostError::Specific(Error::new("A controller updater has already been registered with the frontend"))); + return Err(HostError::Specific(Error::new( + "A controller updater has already been registered with the frontend", + ))); } self.controllers = Some(sender); Ok(()) @@ -253,13 +268,7 @@ impl MiniFrontend { queue.request_encoding(PixelEncoding::ARGB); } - let mut window = minifb::Window::new( - "Test - ESC to exit", - size.0 as usize, - size.1 as usize, - options, - ) - .unwrap_or_else(|e| { + let mut window = minifb::Window::new("Test - ESC to exit", size.0 as usize, size.1 as usize, options).unwrap_or_else(|e| { panic!("{}", e); }); @@ -345,7 +354,9 @@ impl MiniFrontend { if let Some((_clock, frame)) = queue.latest() { last_frame = frame } - window.update_with_buffer(&last_frame.bitmap, last_frame.width as usize, last_frame.height as usize).unwrap(); + window + .update_with_buffer(&last_frame.bitmap, last_frame.width as usize, last_frame.height as usize) + .unwrap(); } } } @@ -363,4 +374,3 @@ impl MiniFrontend { } } } - diff --git a/emulator/libraries/audio/src/lib.rs b/emulator/libraries/audio/src/lib.rs index bc77fb6..bfba644 100644 --- a/emulator/libraries/audio/src/lib.rs +++ b/emulator/libraries/audio/src/lib.rs @@ -1,4 +1,3 @@ - use std::f32::consts::PI; @@ -72,7 +71,11 @@ impl Iterator for SquareWave { fn next(&mut self) -> Option { self.position += 1; let samples_per_hz = self.sample_rate as f32 / self.frequency; - let result = if (self.position as f32 % samples_per_hz) < (samples_per_hz / 2.0) { 1.0 } else { -1.0 }; + let result = if (self.position as f32 % samples_per_hz) < (samples_per_hz / 2.0) { + 1.0 + } else { + -1.0 + }; Some(result) } } @@ -162,4 +165,3 @@ impl Iterator for SkewedSquareWave { pub fn db_to_gain(db: f32) -> f32 { (10.0_f32).powf(db / 20.0) } - diff --git a/emulator/libraries/debugger/src/lib.rs b/emulator/libraries/debugger/src/lib.rs index 9149f3b..9b7fd31 100644 --- a/emulator/libraries/debugger/src/lib.rs +++ b/emulator/libraries/debugger/src/lib.rs @@ -1,4 +1,3 @@ - use moa_core::{Error, System, Address, Addressable}; @@ -56,11 +55,7 @@ impl Debugger { let args: Vec<&str> = command.split_whitespace().collect(); // If no command given, then run the `step` command - let args = if args.is_empty() { - vec!["step"] - } else { - args - }; + let args = if args.is_empty() { vec!["step"] } else { args }; match args[0] { "b" | "break" | "breakpoint" => { @@ -123,7 +118,11 @@ impl Debugger { "d" | "dump" => { if args.len() > 1 { let addr = u32::from_str_radix(args[1], 16).map_err(|_| Error::new("Unable to parse address"))?; - let len = if args.len() > 2 { u32::from_str_radix(args[2], 16).map_err(|_| Error::new("Unable to parse length"))? } else { 0x20 }; + let len = if args.len() > 2 { + u32::from_str_radix(args[2], 16).map_err(|_| Error::new("Unable to parse length"))? + } else { + 0x20 + }; system.get_bus().dump_memory(system.clock, addr as Address, len as Address); } else { //self.port.dump_memory(self.state.ssp as Address, 0x40 as Address); @@ -135,7 +134,9 @@ impl Debugger { } else { let device = system.get_device(args[1])?; let subargs = if args.len() > 2 { &args[2..] } else { &[""] }; - device.borrow_mut().as_inspectable() + device + .borrow_mut() + .as_inspectable() .ok_or_else(|| Error::new("That device is not inspectable"))? .inspect(system, subargs)?; } @@ -154,7 +155,11 @@ impl Debugger { }; if let Some(device) = system.get_next_debuggable_device() { - device.borrow_mut().as_debuggable().unwrap().print_disassembly(system, addr, count); + device + .borrow_mut() + .as_debuggable() + .unwrap() + .print_disassembly(system, addr, count); } }, "c" | "continue" => { @@ -170,7 +175,7 @@ impl Debugger { self.trace_only = true; system.step_until_debuggable()?; return Ok(DebugControl::Continue); - } + }, "setb" | "setw" | "setl" => { if args.len() != 3 { println!("Usage: set[b|w|l] "); @@ -208,7 +213,9 @@ impl Debugger { fn check_repeat_arg(&mut self, args: &[&str]) -> Result<(), Error> { if args.len() > 1 { - let count = args[1].parse::().map_err(|_| Error::new("Unable to parse repeat number"))?; + let count = args[1] + .parse::() + .map_err(|_| Error::new("Unable to parse repeat number"))?; self.repeat_command = Some((count, args[0].to_string())); } Ok(()) @@ -227,4 +234,3 @@ fn parse_address(arg: &str) -> Result<(Option<&str>, Address), Error> { let addr = Address::from_str_radix(addrstr, 16).map_err(|_| Error::new("Unable to parse address"))?; Ok((name, addr)) } - diff --git a/emulator/libraries/host/src/audio.rs b/emulator/libraries/host/src/audio.rs index d672c78..54cbbfc 100644 --- a/emulator/libraries/host/src/audio.rs +++ b/emulator/libraries/host/src/audio.rs @@ -1,4 +1,3 @@ - #[derive(Copy, Clone, Default)] pub struct Sample(pub f32, pub f32); @@ -22,4 +21,3 @@ impl AudioFrame { } } } - diff --git a/emulator/libraries/host/src/controllers.rs b/emulator/libraries/host/src/controllers.rs index cb96fc2..e457241 100644 --- a/emulator/libraries/host/src/controllers.rs +++ b/emulator/libraries/host/src/controllers.rs @@ -1,4 +1,3 @@ - #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum ControllerDevice { A, @@ -37,4 +36,3 @@ impl ControllerEvent { } } } - diff --git a/emulator/libraries/host/src/gfx.rs b/emulator/libraries/host/src/gfx.rs index b2b5b0f..b61b410 100644 --- a/emulator/libraries/host/src/gfx.rs +++ b/emulator/libraries/host/src/gfx.rs @@ -30,12 +30,9 @@ impl Pixel { }; match encoding { - PixelEncoding::RGBA => - (r << 24) | (g << 16) | (b << 8) | a, - PixelEncoding::ARGB => - (a << 24) | (r << 16) | (g << 8) | b, - PixelEncoding::ABGR => - (a << 24) | (b << 16) | (g << 8) | r, + PixelEncoding::RGBA => (r << 24) | (g << 16) | (b << 8) | a, + PixelEncoding::ARGB => (a << 24) | (r << 16) | (g << 8) | b, + PixelEncoding::ABGR => (a << 24) | (b << 16) | (g << 8) | r, } } } @@ -71,22 +68,22 @@ impl Frame { #[inline] pub fn set_pixel(&mut self, pos_x: u32, pos_y: u32, pixel: Pixel) { match pixel { - Pixel::Mask => {} + Pixel::Mask => {}, value if pos_x < self.width && pos_y < self.height => { self.bitmap[(pos_x + (pos_y * self.width)) as usize] = value.encode(self.encoding); - } - _ => {} + }, + _ => {}, } } #[inline] pub fn set_encoded_pixel(&mut self, pos_x: u32, pos_y: u32, pixel: u32) { match pixel { - MASK_COLOUR => { }, + MASK_COLOUR => {}, value if pos_x < self.width && pos_y < self.height => { self.bitmap[(pos_x + (pos_y * self.width)) as usize] = value; }, - _ => { }, + _ => {}, } } @@ -94,11 +91,11 @@ impl Frame { for y in pos_y..(pos_y + height) { for x in pos_x..(pos_x + width) { match bitmap.next().unwrap() { - Pixel::Mask => {} + Pixel::Mask => {}, value if x < self.width && y < self.height => { self.bitmap[(x + (y * self.width)) as usize] = value.encode(self.encoding); - } - _ => {} + }, + _ => {}, } } } @@ -159,4 +156,3 @@ impl FrameReceiver { self.queue.pop_latest() } } - diff --git a/emulator/libraries/host/src/input.rs b/emulator/libraries/host/src/input.rs index 3000dfa..a83ee65 100644 --- a/emulator/libraries/host/src/input.rs +++ b/emulator/libraries/host/src/input.rs @@ -1,4 +1,3 @@ - use std::sync::{Arc, Mutex}; use std::collections::VecDeque; @@ -35,4 +34,3 @@ impl EventReceiver { self.queue.lock().unwrap().pop_front() } } - diff --git a/emulator/libraries/host/src/keys.rs b/emulator/libraries/host/src/keys.rs index 9751bb9..14e42a0 100644 --- a/emulator/libraries/host/src/keys.rs +++ b/emulator/libraries/host/src/keys.rs @@ -1,4 +1,3 @@ - #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Key { A, @@ -124,4 +123,3 @@ impl KeyEvent { } } } - diff --git a/emulator/libraries/host/src/lib.rs b/emulator/libraries/host/src/lib.rs index cb0d3f9..53b15d3 100644 --- a/emulator/libraries/host/src/lib.rs +++ b/emulator/libraries/host/src/lib.rs @@ -1,4 +1,3 @@ - mod audio; mod controllers; mod gfx; @@ -14,4 +13,3 @@ pub use crate::mouse::{MouseButton, MouseEventType, MouseEvent, MouseState}; pub use crate::controllers::{ControllerDevice, ControllerInput, ControllerEvent}; pub use crate::input::{EventSender, EventReceiver, event_queue}; pub use crate::traits::{Host, HostError, Tty, Audio, ClockedQueue, DummyAudio}; - diff --git a/emulator/libraries/host/src/mouse.rs b/emulator/libraries/host/src/mouse.rs index 3acfa89..3c88e1b 100644 --- a/emulator/libraries/host/src/mouse.rs +++ b/emulator/libraries/host/src/mouse.rs @@ -1,4 +1,3 @@ - #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum MouseButton { Left, @@ -68,7 +67,8 @@ impl MouseState { self.pos = next_state.pos; let events: Vec = self - .buttons.into_iter() + .buttons + .into_iter() .zip(next_state.buttons) .enumerate() .filter_map(|(i, (prev, next))| { @@ -102,8 +102,7 @@ impl MouseState { match event.etype { MouseEventType::Up(button) => self.buttons[usize::from(button)] = false, MouseEventType::Down(button) => self.buttons[usize::from(button)] = true, - MouseEventType::Move => { }, + MouseEventType::Move => {}, } } } - diff --git a/emulator/libraries/host/src/traits.rs b/emulator/libraries/host/src/traits.rs index 8239b4f..bd3cad5 100644 --- a/emulator/libraries/host/src/traits.rs +++ b/emulator/libraries/host/src/traits.rs @@ -1,4 +1,3 @@ - use std::fmt; use std::error::Error; use std::collections::VecDeque; @@ -131,4 +130,3 @@ impl Audio for DummyAudio { fn write_samples(&mut self, _clock: Instant, _buffer: &[Sample]) {} } - diff --git a/emulator/libraries/parsing/src/lib.rs b/emulator/libraries/parsing/src/lib.rs index 4e5164b..94905fe 100644 --- a/emulator/libraries/parsing/src/lib.rs +++ b/emulator/libraries/parsing/src/lib.rs @@ -1,4 +1,3 @@ - use std::str::Chars; use std::iter::Peekable; @@ -56,9 +55,13 @@ impl<'input> AssemblyParser<'input> { fn parse_line(&mut self) -> Result, ParserError> { let token = loop { match self.lexer.get_next() { - Some(token) if token == "\n" => { }, - Some(token) => { break token; } - None => { return Ok(None); }, + Some(token) if token == "\n" => {}, + Some(token) => { + break token; + }, + None => { + return Ok(None); + }, } }; @@ -79,7 +82,11 @@ impl<'input> AssemblyParser<'input> { } }, _ => { - return Err(ParserError::new(format!("parse error at line {}: expected word, found {:?}", self.lexer.lineno(), token))); + return Err(ParserError::new(format!( + "parse error at line {}: expected word, found {:?}", + self.lexer.lineno(), + token + ))); }, }; @@ -164,7 +171,7 @@ impl<'input> AssemblyParser<'input> { } else { Ok(AssemblyOperand::Label(token)) } - } + }, } } } @@ -237,7 +244,8 @@ impl<'input> AssemblyLexer<'input> { } pub fn expect_next(&mut self) -> Result { - self.get_next().ok_or_else(|| ParserError::new(format!("unexpected end of input at line {}", self.lineno))) + self.get_next() + .ok_or_else(|| ParserError::new(format!("unexpected end of input at line {}", self.lineno))) } pub fn expect_token(&mut self, expected: &str) -> Result<(), ParserError> { @@ -245,7 +253,10 @@ impl<'input> AssemblyLexer<'input> { if token == expected { Ok(()) } else { - Err(ParserError::new(format!("parse error at line {}: expected {:?}, found {:?}", self.lineno, expected, token))) + Err(ParserError::new(format!( + "parse error at line {}: expected {:?}, found {:?}", + self.lineno, expected, token + ))) } } @@ -309,7 +320,12 @@ pub fn expect_args(lineno: usize, args: &[AssemblyOperand], expected: usize) -> if args.len() == expected { Ok(()) } else { - Err(ParserError::new(format!("error at line {}: expected {} args, but found {}", lineno, expected, args.len()))) + Err(ParserError::new(format!( + "error at line {}: expected {} args, but found {}", + lineno, + expected, + args.len() + ))) } } @@ -326,7 +342,9 @@ pub fn expect_immediate(lineno: usize, operand: &AssemblyOperand) -> Result { //pub struct LevelTriggeredOutput - diff --git a/emulator/peripherals/generic/src/ata.rs b/emulator/peripherals/generic/src/ata.rs index aaa046a..a7e2953 100644 --- a/emulator/peripherals/generic/src/ata.rs +++ b/emulator/peripherals/generic/src/ata.rs @@ -1,35 +1,40 @@ - use std::fs; use femtos::Instant; use moa_core::{Error, Address, Addressable, Transmutable}; +#[rustfmt::skip] +mod reg { + use super::Address; + pub(super) const DATA_WORD: Address = 0x20; + pub(super) const DATA_BYTE: Address = 0x21; + pub(super) const FEATURE: Address = 0x23; + pub(super) const ERROR: Address = 0x23; + pub(super) const SECTOR_COUNT: Address = 0x25; + pub(super) const SECTOR_NUM: Address = 0x27; + pub(super) const CYL_LOW: Address = 0x29; + pub(super) const CYL_HIGH: Address = 0x2B; + pub(super) const DRIVE_HEAD: Address = 0x2D; + pub(super) const STATUS: Address = 0x2F; + pub(super) const COMMAND: Address = 0x2F; +} -const ATA_REG_DATA_WORD: Address = 0x20; -const ATA_REG_DATA_BYTE: Address = 0x21; -const ATA_REG_FEATURE: Address = 0x23; -const ATA_REG_ERROR: Address = 0x23; -const ATA_REG_SECTOR_COUNT: Address = 0x25; -const ATA_REG_SECTOR_NUM: Address = 0x27; -const ATA_REG_CYL_LOW: Address = 0x29; -const ATA_REG_CYL_HIGH: Address = 0x2B; -const ATA_REG_DRIVE_HEAD: Address = 0x2D; -const ATA_REG_STATUS: Address = 0x2F; -const ATA_REG_COMMAND: Address = 0x2F; - -const ATA_CMD_READ_SECTORS: u8 = 0x20; -const ATA_CMD_WRITE_SECTORS: u8 = 0x30; -const ATA_CMD_IDENTIFY: u8 = 0xEC; -const ATA_CMD_SET_FEATURE: u8 = 0xEF; +#[rustfmt::skip] +mod cmd { + pub(super) const READ_SECTORS: u8 = 0x20; + pub(super) const WRITE_SECTORS: u8 = 0x30; + pub(super) const IDENTIFY: u8 = 0xEC; + pub(super) const SET_FEATURE: u8 = 0xEF; +} #[allow(dead_code)] -const ATA_ST_BUSY: u8 = 0x80; +const ATA_ST_BUSY: u8 = 0x80; #[allow(dead_code)] -const ATA_ST_DATA_READY: u8 = 0x08; +const ATA_ST_DATA_READY: u8 = 0x08; #[allow(dead_code)] -const ATA_ST_ERROR: u8 = 0x01; +const ATA_ST_ERROR: u8 = 0x01; -const ATA_SECTOR_SIZE: u32 = 512; +const ATA_SECTOR_SIZE: u32 = 512; const DEV_NAME: &str = "ata"; @@ -60,7 +65,7 @@ impl Addressable for AtaDevice { fn read(&mut self, _clock: Instant, addr: Address, data: &mut [u8]) -> Result<(), Error> { match addr { - ATA_REG_DATA_WORD => { + reg::DATA_WORD => { self.selected_count -= 2; let offset = ((self.selected_sector * ATA_SECTOR_SIZE) + (ATA_SECTOR_SIZE - 1 - self.selected_count)) as usize; data[0] = self.contents[offset]; @@ -70,7 +75,7 @@ impl Addressable for AtaDevice { self.selected_count = 0; } }, - ATA_REG_DATA_BYTE => { + reg::DATA_BYTE => { self.selected_count -= 1; let offset = ((self.selected_sector * ATA_SECTOR_SIZE) + (ATA_SECTOR_SIZE - 1 - self.selected_count)) as usize; data[0] = self.contents[offset]; @@ -79,13 +84,15 @@ impl Addressable for AtaDevice { self.selected_count = 0; } }, - ATA_REG_STATUS => { + reg::STATUS => { data[0] = ATA_ST_DATA_READY; }, - ATA_REG_ERROR => { + reg::ERROR => { data[0] = self.last_error; }, - _ => { log::debug!("{}: reading from {:0x}", DEV_NAME, addr); }, + _ => { + log::debug!("{}: reading from {:0x}", DEV_NAME, addr); + }, } Ok(()) @@ -94,27 +101,43 @@ impl Addressable for AtaDevice { fn write(&mut self, _clock: Instant, addr: Address, data: &[u8]) -> Result<(), Error> { log::debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]); match addr { - ATA_REG_DRIVE_HEAD => { self.selected_sector |= ((data[0] & 0x1F) as u32) << 24; }, - ATA_REG_CYL_HIGH => { self.selected_sector |= (data[0] as u32) << 16; }, - ATA_REG_CYL_LOW => { self.selected_sector |= (data[0] as u32) << 8; }, - ATA_REG_SECTOR_NUM => { self.selected_sector |= data[0] as u32; }, - ATA_REG_SECTOR_COUNT => { self.selected_count = (data[0] as u32) * ATA_SECTOR_SIZE; }, - ATA_REG_COMMAND => { - match data[0] { - ATA_CMD_READ_SECTORS => { log::debug!("{}: reading sector {:x}", DEV_NAME, self.selected_sector); }, - ATA_CMD_WRITE_SECTORS => { log::debug!("{}: writing sector {:x}", DEV_NAME, self.selected_sector); }, - ATA_CMD_IDENTIFY => { }, - ATA_CMD_SET_FEATURE => { }, - _ => { log::debug!("{}: unrecognized command {:x}", DEV_NAME, data[0]); }, - } + reg::DRIVE_HEAD => { + self.selected_sector |= ((data[0] & 0x1F) as u32) << 24; }, - ATA_REG_FEATURE => { + reg::CYL_HIGH => { + self.selected_sector |= (data[0] as u32) << 16; + }, + reg::CYL_LOW => { + self.selected_sector |= (data[0] as u32) << 8; + }, + reg::SECTOR_NUM => { + self.selected_sector |= data[0] as u32; + }, + reg::SECTOR_COUNT => { + self.selected_count = (data[0] as u32) * ATA_SECTOR_SIZE; + }, + reg::COMMAND => match data[0] { + cmd::READ_SECTORS => { + log::debug!("{}: reading sector {:x}", DEV_NAME, self.selected_sector); + }, + cmd::WRITE_SECTORS => { + log::debug!("{}: writing sector {:x}", DEV_NAME, self.selected_sector); + }, + cmd::IDENTIFY => {}, + cmd::SET_FEATURE => {}, + _ => { + log::debug!("{}: unrecognized command {:x}", DEV_NAME, data[0]); + }, + }, + reg::FEATURE => { // TODO implement features }, - ATA_REG_DATA_BYTE => { + reg::DATA_BYTE => { // TODO implement writing }, - _ => { log::debug!("{}: writing {:0x} to {:0x}", DEV_NAME, data[0], addr); }, + _ => { + log::debug!("{}: writing {:0x} to {:0x}", DEV_NAME, data[0], addr); + }, } Ok(()) } @@ -125,4 +148,3 @@ impl Transmutable for AtaDevice { Some(self) } } - diff --git a/emulator/peripherals/generic/src/lib.rs b/emulator/peripherals/generic/src/lib.rs index faaac5a..ad0df96 100644 --- a/emulator/peripherals/generic/src/lib.rs +++ b/emulator/peripherals/generic/src/lib.rs @@ -1,4 +1,2 @@ - mod ata; pub use crate::ata::AtaDevice; - diff --git a/emulator/peripherals/mos/src/lib.rs b/emulator/peripherals/mos/src/lib.rs index 96fa480..badb79c 100644 --- a/emulator/peripherals/mos/src/lib.rs +++ b/emulator/peripherals/mos/src/lib.rs @@ -1,4 +1,2 @@ - mod mos6522; pub use crate::mos6522::Mos6522; - diff --git a/emulator/peripherals/mos/src/mos6522.rs b/emulator/peripherals/mos/src/mos6522.rs index 1fb6245..3b00c3a 100644 --- a/emulator/peripherals/mos/src/mos6522.rs +++ b/emulator/peripherals/mos/src/mos6522.rs @@ -1,17 +1,20 @@ - use femtos::{Instant, Duration}; use moa_core::{Error, System, Address, Addressable, Steppable, Transmutable}; use moa_signals::{Signal, ObservableSignal, Observable}; -const REG_OUTPUT_B: Address = 0x00; -const REG_OUTPUT_A: Address = 0x01; -const REG_DDR_B: Address = 0x02; -const REG_DDR_A: Address = 0x03; -const REG_PERIPH_CTRL: Address = 0x0C; -const REG_INT_FLAGS: Address = 0x0D; -const REG_INT_ENABLE: Address = 0x0E; -const REG_OUTPUT_A_NHS: Address = 0x0F; +#[rustfmt::skip] +mod reg { + use super::Address; + pub(super) const OUTPUT_B: Address = 0x00; + pub(super) const OUTPUT_A: Address = 0x01; + pub(super) const DDR_B: Address = 0x02; + pub(super) const DDR_A: Address = 0x03; + pub(super) const PERIPH_CTRL: Address = 0x0C; + pub(super) const INT_FLAGS: Address = 0x0D; + pub(super) const INT_ENABLE: Address = 0x0E; + pub(super) const OUTPUT_A_NHS: Address = 0x0F; +} const DEV_NAME: &str = "mos6522"; @@ -61,12 +64,24 @@ impl Addressable for Mos6522 { fn read(&mut self, _clock: Instant, addr: Address, data: &mut [u8]) -> Result<(), Error> { match addr { - REG_OUTPUT_B => { data[0] = self.port_b.borrow_mut().data; }, - REG_OUTPUT_A => { data[0] = self.port_a.borrow_mut().data; }, - REG_DDR_B => { data[0] = self.port_b.borrow_mut().ddr; }, - REG_DDR_A => { data[0] = self.port_a.borrow_mut().ddr; }, - REG_INT_FLAGS => { data[0] = self.interrupt_flags; }, - REG_INT_ENABLE => { data[0] = self.interrupt_enable | 0x80; }, + reg::OUTPUT_B => { + data[0] = self.port_b.borrow_mut().data; + }, + reg::OUTPUT_A => { + data[0] = self.port_a.borrow_mut().data; + }, + reg::DDR_B => { + data[0] = self.port_b.borrow_mut().ddr; + }, + reg::DDR_A => { + data[0] = self.port_a.borrow_mut().ddr; + }, + reg::INT_FLAGS => { + data[0] = self.interrupt_flags; + }, + reg::INT_ENABLE => { + data[0] = self.interrupt_enable | 0x80; + }, _ => { log::warn!("{}: !!! unhandled read from {:0x}", DEV_NAME, addr); }, @@ -78,20 +93,40 @@ impl Addressable for Mos6522 { fn write(&mut self, _clock: Instant, addr: Address, data: &[u8]) -> Result<(), Error> { log::debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]); match addr { - REG_OUTPUT_B => { self.port_b.borrow_mut().data = data[0]; self.port_b.notify(); }, - REG_OUTPUT_A => { self.port_a.borrow_mut().data = data[0]; self.port_a.notify(); }, - REG_DDR_B => { self.port_b.borrow_mut().ddr = data[0]; self.port_b.notify(); }, - REG_DDR_A => { self.port_a.borrow_mut().ddr = data[0]; self.port_a.notify(); }, - REG_PERIPH_CTRL => { println!("SET TO {:?}", data[0]); self.peripheral_ctrl = data[0]; }, - REG_INT_FLAGS => { self.interrupt_flags &= !data[0] & 0x7F; }, - REG_INT_ENABLE => { + reg::OUTPUT_B => { + self.port_b.borrow_mut().data = data[0]; + self.port_b.notify(); + }, + reg::OUTPUT_A => { + self.port_a.borrow_mut().data = data[0]; + self.port_a.notify(); + }, + reg::DDR_B => { + self.port_b.borrow_mut().ddr = data[0]; + self.port_b.notify(); + }, + reg::DDR_A => { + self.port_a.borrow_mut().ddr = data[0]; + self.port_a.notify(); + }, + reg::PERIPH_CTRL => { + println!("SET TO {:?}", data[0]); + self.peripheral_ctrl = data[0]; + }, + reg::INT_FLAGS => { + self.interrupt_flags &= !data[0] & 0x7F; + }, + reg::INT_ENABLE => { if (data[0] & 0x80) == 0 { - self.interrupt_flags &= !data[0]; + self.interrupt_flags &= !data[0]; } else { - self.interrupt_flags |= data[0]; + self.interrupt_flags |= data[0]; } }, - REG_OUTPUT_A_NHS => { self.port_a.borrow_mut().data = data[0]; self.port_a.notify(); }, + reg::OUTPUT_A_NHS => { + self.port_a.borrow_mut().data = data[0]; + self.port_a.notify(); + }, _ => { log::warn!("{}: !!! unhandled write {:0x} to {:0x}", DEV_NAME, data[0], addr); }, @@ -102,7 +137,6 @@ impl Addressable for Mos6522 { impl Steppable for Mos6522 { fn step(&mut self, _system: &System) -> Result { - Ok(Duration::from_micros(16_600)) } } @@ -117,4 +151,3 @@ impl Transmutable for Mos6522 { Some(self) } } - diff --git a/emulator/peripherals/motorola/src/lib.rs b/emulator/peripherals/motorola/src/lib.rs index 6a03816..ea6da46 100644 --- a/emulator/peripherals/motorola/src/lib.rs +++ b/emulator/peripherals/motorola/src/lib.rs @@ -1,4 +1,2 @@ - mod mc68681; pub use crate::mc68681::MC68681; - diff --git a/emulator/peripherals/motorola/src/mc68681.rs b/emulator/peripherals/motorola/src/mc68681.rs index 42677fc..ec2f300 100644 --- a/emulator/peripherals/motorola/src/mc68681.rs +++ b/emulator/peripherals/motorola/src/mc68681.rs @@ -1,4 +1,3 @@ - use femtos::{Instant, Duration, Frequency}; use moa_core::{System, Error, Address, Steppable, Addressable, Transmutable}; @@ -95,15 +94,23 @@ impl MC68681Port { pub fn set_tx_status(&mut self, value: bool) { match value { - true => { self.status |= SR_TX_READY | SR_TX_EMPTY; }, - false => { self.status &= !(SR_TX_READY | SR_TX_EMPTY); }, + true => { + self.status |= SR_TX_READY | SR_TX_EMPTY; + }, + false => { + self.status &= !(SR_TX_READY | SR_TX_EMPTY); + }, } } pub fn set_rx_status(&mut self, value: bool) { match value { - true => { self.status |= SR_RX_READY; }, - false => { self.status &= !SR_RX_READY; }, + true => { + self.status |= SR_RX_READY; + }, + false => { + self.status &= !SR_RX_READY; + }, } } @@ -126,7 +133,7 @@ impl MC68681Port { } pub fn handle_command(&mut self, data: u8) -> Option { - let rx_cmd = data& 0x03; + let rx_cmd = data & 0x03; if rx_cmd == 0b01 { self.rx_enabled = true; } else if rx_cmd == 0b10 { @@ -202,7 +209,9 @@ impl MC68681 { } fn check_interrupt_state(&mut self, system: &System) -> Result<(), Error> { - system.get_interrupt_controller().set((self.int_status & self.int_mask) != 0, 4, self.int_vector) + system + .get_interrupt_controller() + .set((self.int_status & self.int_mask) != 0, 4, self.int_vector) } } @@ -254,17 +263,13 @@ impl Addressable for MC68681 { fn read(&mut self, _clock: Instant, addr: Address, data: &mut [u8]) -> Result<(), Error> { match addr { - REG_SRA_RD => { - data[0] = self.port_a.status - }, + REG_SRA_RD => data[0] = self.port_a.status, REG_RBA_RD => { data[0] = self.port_a.input; self.port_a.set_rx_status(false); self.set_interrupt_flag(ISR_CH_A_RX_READY_FULL, false); }, - REG_SRB_RD => { - data[0] = self.port_b.status - }, + REG_SRB_RD => data[0] = self.port_b.status, REG_RBB_RD => { data[0] = self.port_b.input; self.port_b.set_rx_status(false); @@ -294,7 +299,7 @@ impl Addressable for MC68681 { } self.set_interrupt_flag(ISR_TIMER_CHANGE, false); }, - _ => { }, + _ => {}, } if addr != REG_SRA_RD && addr != REG_SRB_RD { @@ -312,7 +317,7 @@ impl Addressable for MC68681 { }, REG_ACR_WR => { self.acr = data[0]; - } + }, REG_TBA_WR => { log::debug!("{}a: write {}", DEV_NAME, data[0] as char); self.port_a.send_byte(data[0]); @@ -354,7 +359,7 @@ impl Addressable for MC68681 { REG_OUT_RESET => { self.output_state &= !data[0]; }, - _ => { }, + _ => {}, } Ok(()) } diff --git a/emulator/peripherals/yamaha/src/lib.rs b/emulator/peripherals/yamaha/src/lib.rs index 7ab3051..4aab80c 100644 --- a/emulator/peripherals/yamaha/src/lib.rs +++ b/emulator/peripherals/yamaha/src/lib.rs @@ -1,7 +1,5 @@ - mod sn76489; pub use crate::sn76489::Sn76489; - + mod ym2612; pub use crate::ym2612::Ym2612; - diff --git a/emulator/peripherals/yamaha/src/sn76489.rs b/emulator/peripherals/yamaha/src/sn76489.rs index f3b0d3e..6255ee8 100644 --- a/emulator/peripherals/yamaha/src/sn76489.rs +++ b/emulator/peripherals/yamaha/src/sn76489.rs @@ -1,4 +1,3 @@ - use femtos::{Instant, Duration, Frequency}; use moa_core::{System, Error, Address, Addressable, Steppable, Transmutable}; @@ -96,7 +95,7 @@ pub struct Sn76489 { impl Sn76489 { pub fn new(host: &mut H, _clock_frequency: Frequency) -> Result> where - H: Host + H: Host, { let source = host.add_audio_source()?; let sample_rate = source.samples_per_second(); @@ -134,7 +133,7 @@ impl Steppable for Sn76489 { } self.source.write_samples(system.clock, &buffer); - Ok(Duration::from_millis(1)) // Every 1ms of simulated time + Ok(Duration::from_millis(1)) // Every 1ms of simulated time } } @@ -163,7 +162,9 @@ impl Addressable for Sn76489 { 5 => self.tones[2].set_attenuation(value), 6 => self.noise.set_control(value), 7 => self.noise.set_attenuation(value), - _ => { self.first_byte = Some(data[0]); }, + _ => { + self.first_byte = Some(data[0]); + }, } } else { let first = self.first_byte.unwrap_or(0); @@ -173,7 +174,7 @@ impl Addressable for Sn76489 { 0 => self.tones[0].set_counter(value), 2 => self.tones[1].set_counter(value), 4 => self.tones[2].set_counter(value), - _ => { }, + _ => {}, } } log::debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]); @@ -190,4 +191,3 @@ impl Transmutable for Sn76489 { Some(self) } } - diff --git a/emulator/peripherals/yamaha/src/ym2612.rs b/emulator/peripherals/yamaha/src/ym2612.rs index eb4340f..e3f522e 100644 --- a/emulator/peripherals/yamaha/src/ym2612.rs +++ b/emulator/peripherals/yamaha/src/ym2612.rs @@ -28,6 +28,7 @@ use moa_host::{Host, HostError, Audio, Sample}; /// /// The value here is used to shift a bit to get the number of global cycles between each increment /// of the envelope attenuation, based on the rate that's currently active +#[rustfmt::skip] const COUNTER_SHIFT_VALUES: &[u16] = &[ 11, 11, 11, 11, 10, 10, 10, 10, @@ -53,6 +54,7 @@ const COUNTER_SHIFT_VALUES: &[u16] = &[ /// than attenuation, and the values will always be below 64. This table maps each of the 64 /// possible angle values to a sequence of 8 cycles, and the amount to increment the attenuation /// at each point in that cycle +#[rustfmt::skip] const RATE_TABLE: &[u16] = &[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -120,6 +122,7 @@ const RATE_TABLE: &[u16] = &[ 8, 8, 8, 8, 8, 8, 8, 8, ]; +#[rustfmt::skip] const DETUNE_TABLE: &[u8] = &[ 0, 0, 1, 2, 0, 0, 1, 2, @@ -271,9 +274,6 @@ impl EnvelopeGenerator { let rate = self.get_scaled_rate(self.envelope_state, rate_adjust); let counter_shift = COUNTER_SHIFT_VALUES[rate]; -//if self.debug_name == "ch 2, op 0" { -//println!("{:4x} {:4x} {:4x}", envelope_clock, counter_shift, envelope_clock % (1 << counter_shift)); -//} if envelope_clock % (1 << counter_shift) == 0 { let update_cycle = (envelope_clock >> counter_shift) & 0x07; let increment = RATE_TABLE[rate * 8 + update_cycle as usize]; @@ -286,9 +286,6 @@ impl EnvelopeGenerator { // to bitwise-and with 0xFFC instead, which will wrap the number to a 12-bit signed number, which when // clamped to MAX_ENVELOPE will produce the same results let new_envelope = self.envelope + (((!self.envelope * increment) as i16) >> 4) as u16; -//if self.debug_name == "ch 2, op 0" { -//println!("{:4x} {:4x} {:4x} {:4x} {:4x}", self.envelope, update_cycle, rate * 8 + update_cycle as usize, (((!self.envelope * increment) as i16) >> 4) as u16 & 0xFFFC, new_envelope); -//} if new_envelope > self.envelope { self.envelope_state = EnvelopeState::Decay; self.envelope = 0; @@ -296,19 +293,16 @@ impl EnvelopeGenerator { self.envelope = new_envelope.min(MAX_ENVELOPE); } }, - EnvelopeState::Decay | - EnvelopeState::Sustain | - EnvelopeState::Release => { + EnvelopeState::Decay | EnvelopeState::Sustain | EnvelopeState::Release => { // Convert it to a fixed point decimal number of 4 bit : 8 bits, which will be the output self.envelope += increment << 2; - if self.envelope > MAX_ENVELOPE || self.envelope_state == EnvelopeState::Release && self.envelope >= ENVELOPE_CENTER { + if self.envelope > MAX_ENVELOPE + || self.envelope_state == EnvelopeState::Release && self.envelope >= ENVELOPE_CENTER + { self.envelope = MAX_ENVELOPE; } }, } -//if self.debug_name == "ch 2, op 0" { -//println!("{:4x} {:4x} {:4x} {:4x} {:4x}", rate, counter_shift, self.envelope_state as usize, increment, self.envelope); -//} } } @@ -411,7 +405,8 @@ impl PhaseGenerator { increment.saturating_add(detune) } else { increment.saturating_sub(detune) - }.min(0x1FFFF); + } + .min(0x1FFFF); // Apply multiple let increment = if self.multiple == 0 { @@ -440,6 +435,7 @@ impl PhaseGenerator { /// /// K1 = F11 /// K0 = F11 & (F10 | F9 | F8) | !F11 & (F10 & F9 & F8) +#[rustfmt::skip] const FNUMBER_TO_KEYCODE: &[u8] = &[ 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, @@ -507,7 +503,8 @@ impl Operator { } fn notify_key_change(&mut self, state: bool, envelope_clock: EnvelopeClock) { - self.envelope.notify_key_change(state, envelope_clock, self.phase.get_rate_adjust()); + self.envelope + .notify_key_change(state, envelope_clock, self.phase.get_rate_adjust()); self.phase.reset(); } @@ -519,10 +516,6 @@ impl Operator { let mod_phase = phase + modulator; -//if self.debug_name == "ch 2, op 0" { -//println!("{:4x} = {:4x} + {:4x} + {:4x}, e: {:x}, {:4x} {:4x}", mod_phase, phase, self.phase.increment, modulator, self.envelope.envelope_state as usize, envelope, self.envelope.envelope); -//} - // The sine table contains the first half of the wave as an attenuation value // Use the phase with the sign truncated to get the attenuation, plus the // attenuation from the envelope, to get the total attenuation at this point @@ -567,7 +560,9 @@ impl Channel { Self { debug_name: debug_name.clone(), enabled: (true, true), - operators: (0..OPERATORS).map(|i| Operator::new(format!("{}, op {}", debug_name, i))).collect(), + operators: (0..OPERATORS) + .map(|i| Operator::new(format!("{}, op {}", debug_name, i))) + .collect(), algorithm: OperatorAlgorithm::A0, feedback: 0, @@ -617,10 +612,6 @@ impl Channel { //let output = sign_extend_u16(output, 14); - //let output = output * 2 / 3; -//if self.debug_name == "ch 2" { -//println!("{:6x}", output); -//} let sample = output as f32 / (1 << 13) as f32; let left = if self.enabled.0 { sample } else { 0.0 }; @@ -663,7 +654,9 @@ impl Channel { }, OperatorAlgorithm::A5 => { let output1 = self.operators[0].get_output(feedback, clocks); - self.operators[1].get_output(output1, clocks) + self.operators[2].get_output(output1, clocks) + self.operators[3].get_output(output1, clocks) + self.operators[1].get_output(output1, clocks) + + self.operators[2].get_output(output1, clocks) + + self.operators[3].get_output(output1, clocks) }, OperatorAlgorithm::A6 => { let output1 = self.operators[0].get_output(feedback, clocks); @@ -672,9 +665,9 @@ impl Channel { }, OperatorAlgorithm::A7 => { self.operators[0].get_output(feedback, clocks) - + self.operators[1].get_output(0, clocks) - + self.operators[2].get_output(0, clocks) - + self.operators[3].get_output(0, clocks) + + self.operators[1].get_output(0, clocks) + + self.operators[2].get_output(0, clocks) + + self.operators[3].get_output(0, clocks) }, } } @@ -808,7 +801,7 @@ impl Steppable for Ym2612 { } self.source.write_samples(system.clock, &buffer); - Ok(Duration::from_millis(1)) // Every 1ms of simulated time + Ok(Duration::from_millis(1)) // Every 1ms of simulated time } } @@ -919,7 +912,7 @@ impl Ym2612 { self.channels[ch].operators[op].set_rate(EnvelopeState::Decay, first_decay_rate); }, - reg if is_reg_range(reg, 0x70)=> { + reg if is_reg_range(reg, 0x70) => { let (ch, op) = get_ch_op(bank, reg); let index = get_index(bank, reg); @@ -938,7 +931,11 @@ impl Ym2612 { // Register is 4 bits, so adjust it to match total_level's scale let sustain_level = (self.registers[0x80 + index] as u16 & 0xF0) << 3; // Adjust the maximum storable value to be the max attenuation - let sustain_level = if sustain_level == (0x00F0 << 3) { MAX_ENVELOPE } else { sustain_level }; + let sustain_level = if sustain_level == (0x00F0 << 3) { + MAX_ENVELOPE + } else { + sustain_level + }; self.channels[ch].operators[op].set_sustain_level(sustain_level); }, @@ -1033,7 +1030,7 @@ impl Addressable for Ym2612 { 0..=3 => { // Read the status byte (busy/overflow) data[0] = ((self.timer_a_overflow as u8) << 1) | (self.timer_b_overflow as u8); - } + }, _ => { log::warn!("{}: !!! unhandled read from {:0x}", DEV_NAME, addr); }, @@ -1078,4 +1075,3 @@ impl Transmutable for Ym2612 { Some(self) } } - diff --git a/emulator/peripherals/zilog/src/lib.rs b/emulator/peripherals/zilog/src/lib.rs index 18ea3fa..22cd217 100644 --- a/emulator/peripherals/zilog/src/lib.rs +++ b/emulator/peripherals/zilog/src/lib.rs @@ -1,4 +1,2 @@ - mod z8530; pub use crate::z8530::Z8530; - diff --git a/emulator/peripherals/zilog/src/z8530.rs b/emulator/peripherals/zilog/src/z8530.rs index 9e3a55c..7a60163 100644 --- a/emulator/peripherals/zilog/src/z8530.rs +++ b/emulator/peripherals/zilog/src/z8530.rs @@ -1,4 +1,3 @@ - use femtos::{Instant, Duration}; use moa_core::{System, Error, Address, Addressable, Steppable, Transmutable}; @@ -6,9 +5,7 @@ use moa_core::{System, Error, Address, Addressable, Steppable, Transmutable}; const DEV_NAME: &str = "z8530"; #[derive(Default)] -pub struct Z8530 { - -} +pub struct Z8530 {} impl Addressable for Z8530 { fn size(&self) -> usize { @@ -30,7 +27,6 @@ impl Addressable for Z8530 { impl Steppable for Z8530 { fn step(&mut self, _system: &System) -> Result { - Ok(Duration::from_secs(1)) } } @@ -44,5 +40,3 @@ impl Transmutable for Z8530 { Some(self) } } - - diff --git a/emulator/systems/computie/src/lib.rs b/emulator/systems/computie/src/lib.rs index 20c10fc..44fdeed 100644 --- a/emulator/systems/computie/src/lib.rs +++ b/emulator/systems/computie/src/lib.rs @@ -1,4 +1,2 @@ - mod system; pub use crate::system::{build_computie, build_computie_k30, launch_terminal_emulator, launch_slip_connection, ComputieOptions}; - diff --git a/emulator/systems/computie/src/system.rs b/emulator/systems/computie/src/system.rs index afadc8c..680696b 100644 --- a/emulator/systems/computie/src/system.rs +++ b/emulator/systems/computie/src/system.rs @@ -1,4 +1,3 @@ - use femtos::Frequency; use moa_core::{System, Error, Debuggable, MemoryBlock, Device}; @@ -47,15 +46,6 @@ pub fn build_computie(host: &H, options: ComputieOptions) -> Result(host: &H) -> Result { let cpu = M68k::from_type(M68kType::MC68030, Frequency::from_hz(10_000_000)); - //cpu.enable_tracing(); - //cpu.add_breakpoint(0x10781a); - //cpu.add_breakpoint(0x10bc9c); - //cpu.add_breakpoint(0x106a94); - //cpu.add_breakpoint(0x1015b2); - //cpu.add_breakpoint(0x103332); - //cpu.decoder.dump_disassembly(&mut system, 0x100000, 0x2000); - //cpu.decoder.dump_disassembly(&mut system, 0x2ac, 0x200); - system.add_interruptable_device("cpu", Device::new(cpu))?; Ok(system) @@ -104,18 +85,39 @@ pub fn launch_terminal_emulator(name: String) { use std::time::Duration; use std::process::Command; - Command::new("x-terminal-emulator").arg("-e").arg(&format!("pyserial-miniterm {}", name)).spawn().unwrap(); + Command::new("x-terminal-emulator") + .arg("-e") + .arg(&format!("pyserial-miniterm {}", name)) + .spawn() + .unwrap(); thread::sleep(Duration::from_secs(1)); } pub fn launch_slip_connection(name: String) { use std::process::Command; - Command::new("sudo").args(["slattach", "-s", "38400", "-p", "slip", &name]).spawn().unwrap(); - Command::new("sudo").args(["ifconfig", "sl0", "192.168.1.2", "pointopoint", "192.168.1.200", "up"]).status().unwrap(); - Command::new("sudo").args(["arp", "-Ds", "192.168.1.200", "enp4s0", "pub"]).status().unwrap(); - Command::new("sudo").args(["iptables", "-A", "FORWARD", "-i", "sl0", "-j", "ACCEPT"]).status().unwrap(); - Command::new("sudo").args(["iptables", "-A", "FORWARD", "-o", "sl0", "-j", "ACCEPT"]).status().unwrap(); - Command::new("sudo").args(["sh", "-c", "echo 1 > /proc/sys/net/ipv4/ip_forward"]).status().unwrap(); + Command::new("sudo") + .args(["slattach", "-s", "38400", "-p", "slip", &name]) + .spawn() + .unwrap(); + Command::new("sudo") + .args(["ifconfig", "sl0", "192.168.1.2", "pointopoint", "192.168.1.200", "up"]) + .status() + .unwrap(); + Command::new("sudo") + .args(["arp", "-Ds", "192.168.1.200", "enp4s0", "pub"]) + .status() + .unwrap(); + Command::new("sudo") + .args(["iptables", "-A", "FORWARD", "-i", "sl0", "-j", "ACCEPT"]) + .status() + .unwrap(); + Command::new("sudo") + .args(["iptables", "-A", "FORWARD", "-o", "sl0", "-j", "ACCEPT"]) + .status() + .unwrap(); + Command::new("sudo") + .args(["sh", "-c", "echo 1 > /proc/sys/net/ipv4/ip_forward"]) + .status() + .unwrap(); } - diff --git a/emulator/systems/genesis/src/lib.rs b/emulator/systems/genesis/src/lib.rs index a72c6ae..831dca2 100644 --- a/emulator/systems/genesis/src/lib.rs +++ b/emulator/systems/genesis/src/lib.rs @@ -1,7 +1,5 @@ - pub mod peripherals; pub mod utils; mod system; pub use crate::system::{SegaGenesisOptions, build_genesis}; - diff --git a/emulator/systems/genesis/src/peripherals/controllers.rs b/emulator/systems/genesis/src/peripherals/controllers.rs index 3167917..f91ea95 100644 --- a/emulator/systems/genesis/src/peripherals/controllers.rs +++ b/emulator/systems/genesis/src/peripherals/controllers.rs @@ -1,20 +1,19 @@ - use femtos::{Instant, Duration}; use moa_core::{System, Error, Address, Addressable, Steppable, Transmutable}; use moa_host::{self, Host, HostError, ControllerDevice, ControllerInput, ControllerEvent, EventReceiver}; use moa_signals::{Signal}; -const REG_VERSION: Address = 0x01; -const REG_DATA1: Address = 0x03; -const REG_DATA2: Address = 0x05; -const REG_DATA3: Address = 0x07; -const REG_CTRL1: Address = 0x09; -const REG_CTRL2: Address = 0x0B; -const REG_CTRL3: Address = 0x0D; -const REG_S_CTRL1: Address = 0x13; -const REG_S_CTRL2: Address = 0x19; -const REG_S_CTRL3: Address = 0x1F; +const REG_VERSION: Address = 0x01; +const REG_DATA1: Address = 0x03; +const REG_DATA2: Address = 0x05; +const REG_DATA3: Address = 0x07; +const REG_CTRL1: Address = 0x09; +const REG_CTRL2: Address = 0x0B; +const REG_CTRL3: Address = 0x0D; +const REG_S_CTRL1: Address = 0x13; +const REG_S_CTRL2: Address = 0x19; +const REG_S_CTRL3: Address = 0x1F; const DEV_NAME: &str = "genesis_controller"; @@ -50,13 +49,13 @@ impl GenesisControllerPort { let th_state = (self.outputs & 0x40) != 0; match (th_state, self.th_count) { - (true, 0) => self.outputs | ((inputs & 0x003F) as u8), + (true, 0) => self.outputs | ((inputs & 0x003F) as u8), (false, 1) => self.outputs | (((inputs & 0x00C0) >> 2) as u8) | ((inputs & 0x0003) as u8), - (true, 1) => self.outputs | ((inputs & 0x003F) as u8), + (true, 1) => self.outputs | ((inputs & 0x003F) as u8), (false, 2) => self.outputs | (((inputs & 0x00C0) >> 2) as u8), - (true, 2) => self.outputs | ((inputs & 0x0030) as u8) | (((inputs & 0x0F00) >> 8) as u8), + (true, 2) => self.outputs | ((inputs & 0x0030) as u8) | (((inputs & 0x0F00) >> 8) as u8), (false, 3) => self.outputs | (((inputs & 0x00C0) >> 2) as u8) | 0x0F, - (true, 3) => self.outputs | ((inputs & 0x003F) as u8), + (true, 3) => self.outputs | ((inputs & 0x003F) as u8), (false, 0) => self.outputs | (((inputs & 0x00C0) >> 2) as u8) | ((inputs & 0x0003) as u8), _ => 0, } @@ -159,17 +158,39 @@ impl Addressable for GenesisControllers { } match addr { - REG_VERSION => { data[i] = 0xA0; } // Overseas Version, NTSC, No Expansion - REG_DATA1 => { data[i] = self.port_1.get_data(); }, - REG_DATA2 => { data[i] = self.port_2.get_data(); }, - REG_DATA3 => { data[i] = self.expansion.get_data(); }, - REG_CTRL1 => { data[i] = self.port_1.ctrl; }, - REG_CTRL2 => { data[i] = self.port_2.ctrl; }, - REG_CTRL3 => { data[i] = self.expansion.ctrl; }, - REG_S_CTRL1 => { data[i] = self.port_1.s_ctrl | 0x02; }, - REG_S_CTRL2 => { data[i] = self.port_2.s_ctrl | 0x02; }, - REG_S_CTRL3 => { data[i] = self.expansion.s_ctrl | 0x02; }, - _ => { log::warn!("{}: !!! unhandled reading from {:0x}", DEV_NAME, addr); }, + REG_VERSION => { + data[i] = 0xA0; + }, // Overseas Version, NTSC, No Expansion + REG_DATA1 => { + data[i] = self.port_1.get_data(); + }, + REG_DATA2 => { + data[i] = self.port_2.get_data(); + }, + REG_DATA3 => { + data[i] = self.expansion.get_data(); + }, + REG_CTRL1 => { + data[i] = self.port_1.ctrl; + }, + REG_CTRL2 => { + data[i] = self.port_2.ctrl; + }, + REG_CTRL3 => { + data[i] = self.expansion.ctrl; + }, + REG_S_CTRL1 => { + data[i] = self.port_1.s_ctrl | 0x02; + }, + REG_S_CTRL2 => { + data[i] = self.port_2.s_ctrl | 0x02; + }, + REG_S_CTRL3 => { + data[i] = self.expansion.s_ctrl | 0x02; + }, + _ => { + log::warn!("{}: !!! unhandled reading from {:0x}", DEV_NAME, addr); + }, } log::info!("{}: read from register {:x} the value {:x}", DEV_NAME, addr, data[0]); Ok(()) @@ -180,16 +201,36 @@ impl Addressable for GenesisControllers { log::info!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]); match addr { - REG_DATA1 => { self.port_1.set_data(data[0]); } - REG_DATA2 => { self.port_2.set_data(data[0]); }, - REG_DATA3 => { self.expansion.set_data(data[0]); }, - REG_CTRL1 => { self.port_1.set_ctrl(data[0]); }, - REG_CTRL2 => { self.port_2.set_ctrl(data[0]); }, - REG_CTRL3 => { self.expansion.set_ctrl(data[0]); }, - REG_S_CTRL1 => { self.port_1.s_ctrl = data[0] & 0xF8; }, - REG_S_CTRL2 => { self.port_2.s_ctrl = data[0] & 0xF8; }, - REG_S_CTRL3 => { self.expansion.s_ctrl = data[0] & 0xF8; }, - _ => { log::warn!("{}: !!! unhandled write of {:0x} to {:0x}", DEV_NAME, data[0], addr); }, + REG_DATA1 => { + self.port_1.set_data(data[0]); + }, + REG_DATA2 => { + self.port_2.set_data(data[0]); + }, + REG_DATA3 => { + self.expansion.set_data(data[0]); + }, + REG_CTRL1 => { + self.port_1.set_ctrl(data[0]); + }, + REG_CTRL2 => { + self.port_2.set_ctrl(data[0]); + }, + REG_CTRL3 => { + self.expansion.set_ctrl(data[0]); + }, + REG_S_CTRL1 => { + self.port_1.s_ctrl = data[0] & 0xF8; + }, + REG_S_CTRL2 => { + self.port_2.s_ctrl = data[0] & 0xF8; + }, + REG_S_CTRL3 => { + self.expansion.s_ctrl = data[0] & 0xF8; + }, + _ => { + log::warn!("{}: !!! unhandled write of {:0x} to {:0x}", DEV_NAME, data[0], addr); + }, } Ok(()) } @@ -197,7 +238,7 @@ impl Addressable for GenesisControllers { impl Steppable for GenesisControllers { fn step(&mut self, _system: &System) -> Result { - let duration = Duration::from_micros(100); // Update every 100us + let duration = Duration::from_micros(100); // Update every 100us while let Some(event) = self.receiver.receive() { self.process_event(event); @@ -222,5 +263,3 @@ impl Transmutable for GenesisControllers { Some(self) } } - - diff --git a/emulator/systems/genesis/src/peripherals/coprocessor.rs b/emulator/systems/genesis/src/peripherals/coprocessor.rs index d96ec5d..ab3cf8a 100644 --- a/emulator/systems/genesis/src/peripherals/coprocessor.rs +++ b/emulator/systems/genesis/src/peripherals/coprocessor.rs @@ -1,4 +1,3 @@ - use std::rc::Rc; use std::cell::{Cell, RefCell}; use femtos::Instant; @@ -31,9 +30,15 @@ impl Addressable for CoprocessorCoordinator { fn read(&mut self, _clock: Instant, addr: Address, data: &mut [u8]) -> Result<(), Error> { match addr { 0x100 => { - data[0] = if self.bus_request.get() && self.reset.get() { 0x01 } else { 0x00 }; + data[0] = if self.bus_request.get() && self.reset.get() { + 0x01 + } else { + 0x00 + }; + }, + _ => { + log::warn!("{}: !!! unhandled read from {:0x}", DEV_NAME, addr); }, - _ => { log::warn!("{}: !!! unhandled read from {:0x}", DEV_NAME, addr); }, } log::info!("{}: read from register {:x} of {:?}", DEV_NAME, addr, data); Ok(()) @@ -49,7 +54,9 @@ impl Addressable for CoprocessorCoordinator { 0x200 => { self.reset.set(data[0] == 0); }, - _ => { log::warn!("{}: !!! unhandled write {:0x} to {:0x}", DEV_NAME, data[0], addr); }, + _ => { + log::warn!("{}: !!! unhandled write {:0x} to {:0x}", DEV_NAME, data[0], addr); + }, } Ok(()) } @@ -101,7 +108,9 @@ pub struct CoprocessorBankArea { impl CoprocessorBankArea { pub fn new(bus: Rc>) -> (Self, CoprocessorBankRegister) { let base = Rc::new(Cell::new(0)); - let register = CoprocessorBankRegister { base: base.clone() }; + let register = CoprocessorBankRegister { + base: base.clone(), + }; let bank = Self { base, bus, @@ -129,4 +138,3 @@ impl Transmutable for CoprocessorBankArea { Some(self) } } - diff --git a/emulator/systems/genesis/src/peripherals/mod.rs b/emulator/systems/genesis/src/peripherals/mod.rs index 5c4fc3a..0b3544e 100644 --- a/emulator/systems/genesis/src/peripherals/mod.rs +++ b/emulator/systems/genesis/src/peripherals/mod.rs @@ -1,5 +1,3 @@ - -pub mod ym7101; pub mod controllers; pub mod coprocessor; - +pub mod ym7101; diff --git a/emulator/systems/genesis/src/peripherals/ym7101.rs b/emulator/systems/genesis/src/peripherals/ym7101.rs index 4f203be..b8f6c3c 100644 --- a/emulator/systems/genesis/src/peripherals/ym7101.rs +++ b/emulator/systems/genesis/src/peripherals/ym7101.rs @@ -1,4 +1,3 @@ - use femtos::{Instant, Duration, Frequency}; use moa_core::{System, Error, Address, Addressable, Steppable, Inspectable, Transmutable, Device, read_beu16, dump_slice}; @@ -171,7 +170,13 @@ impl Ym7101Memory { 4 => Memory::Vsram, _ => Memory::Cram, }; - log::debug!("{}: transfer requested of type {:x} ({:?}) to address {:x}", DEV_NAME, self.transfer_type, self.transfer_target, self.transfer_dest_addr); + log::debug!( + "{}: transfer requested of type {:x} ({:?}) to address {:x}", + DEV_NAME, + self.transfer_type, + self.transfer_target, + self.transfer_dest_addr + ); if (self.transfer_type & 0x20) != 0 { if (self.transfer_type & 0x10) != 0 { self.set_dma_mode(DmaType::Copy); @@ -198,7 +203,15 @@ impl Ym7101Memory { } } self.transfer_dest_addr += self.transfer_auto_inc; - log::debug!("{}: data port read {} bytes from {:?}:{:x} returning {:x},{:x}", DEV_NAME, data.len(), self.transfer_target, addr, data[0], data[1]); + log::debug!( + "{}: data port read {} bytes from {:?}:{:x} returning {:x},{:x}", + DEV_NAME, + data.len(), + self.transfer_target, + addr, + data[0], + data[1] + ); Ok(()) } @@ -208,7 +221,14 @@ impl Ym7101Memory { self.transfer_fill_word = if data.len() >= 2 { read_beu16(data) } else { data[0] as u16 }; self.set_dma_mode(DmaType::Fill); } else { - log::debug!("{}: data port write {} bytes to {:?}:{:x} with {:?}", DEV_NAME, data.len(), self.transfer_target, self.transfer_dest_addr, data); + log::debug!( + "{}: data port write {} bytes to {:?}:{:x} with {:?}", + DEV_NAME, + data.len(), + self.transfer_target, + self.transfer_dest_addr, + data + ); { let addr = self.transfer_dest_addr as usize; @@ -225,10 +245,12 @@ impl Ym7101Memory { fn write_control_port(&mut self, data: &[u8]) -> Result<(), Error> { let value = read_beu16(data); match (data.len(), self.ctrl_port_buffer) { - (2, None) => { self.ctrl_port_buffer = Some(value) }, + (2, None) => self.ctrl_port_buffer = Some(value), (2, Some(upper)) => self.setup_transfer(upper, read_beu16(data)), (4, None) => self.setup_transfer(value, read_beu16(&data[2..])), - _ => { log::error!("{}: !!! error when writing to control port with {} bytes of {:?}", DEV_NAME, data.len(), data); }, + _ => { + log::error!("{}: !!! error when writing to control port with {} bytes of {:?}", DEV_NAME, data.len(), data); + }, } Ok(()) } @@ -239,7 +261,15 @@ impl Ym7101Memory { match self.transfer_run { DmaType::Memory => { - log::debug!("{}: starting dma transfer {:x} from Mem:{:x} to {:?}:{:x} ({} bytes)", DEV_NAME, self.transfer_type, self.transfer_src_addr, self.transfer_target, self.transfer_dest_addr, self.transfer_remain); + log::debug!( + "{}: starting dma transfer {:x} from Mem:{:x} to {:?}:{:x} ({} bytes)", + DEV_NAME, + self.transfer_type, + self.transfer_src_addr, + self.transfer_target, + self.transfer_dest_addr, + self.transfer_remain + ); let mut bus = system.get_bus(); while self.transfer_remain > 0 { @@ -257,7 +287,13 @@ impl Ym7101Memory { } }, DmaType::Copy => { - log::debug!("{}: starting dma copy from VRAM:{:x} to VRAM:{:x} ({} bytes)", DEV_NAME, self.transfer_src_addr, self.transfer_dest_addr, self.transfer_remain); + log::debug!( + "{}: starting dma copy from VRAM:{:x} to VRAM:{:x} ({} bytes)", + DEV_NAME, + self.transfer_src_addr, + self.transfer_dest_addr, + self.transfer_remain + ); while self.transfer_remain > 0 { self.vram[self.transfer_dest_addr as usize] = self.vram[self.transfer_src_addr as usize]; self.transfer_dest_addr += self.transfer_auto_inc; @@ -266,14 +302,22 @@ impl Ym7101Memory { } }, DmaType::Fill => { - log::debug!("{}: starting dma fill to VRAM:{:x} ({} bytes) with {:x}", DEV_NAME, self.transfer_dest_addr, self.transfer_remain, self.transfer_fill_word); + log::debug!( + "{}: starting dma fill to VRAM:{:x} ({} bytes) with {:x}", + DEV_NAME, + self.transfer_dest_addr, + self.transfer_remain, + self.transfer_fill_word + ); while self.transfer_remain > 0 { self.vram[self.transfer_dest_addr as usize] = self.transfer_fill_word as u8; self.transfer_dest_addr += self.transfer_auto_inc; self.transfer_remain -= 1; } }, - _ => { log::warn!("{}: !!! error unexpected transfer mode {:x}", DEV_NAME, self.transfer_type); }, + _ => { + log::warn!("{}: !!! error unexpected transfer mode {:x}", DEV_NAME, self.transfer_type); + }, } self.set_dma_mode(DmaType::None); @@ -426,7 +470,12 @@ impl Ym7101State { Pixel::Rgb(((rgb & 0x00F) << 4) as u8, (rgb & 0x0F0) as u8, ((rgb & 0xF00) >> 4) as u8).encode(encoding) } else { let offset = if mode == ColourMode::Highlight { 0x80 } else { 0x00 }; - Pixel::Rgb(((rgb & 0x00F) << 3) as u8 | offset, ((rgb & 0x0F0) >> 1) as u8 | offset, ((rgb & 0xF00) >> 5) as u8 | offset).encode(encoding) + Pixel::Rgb( + ((rgb & 0x00F) << 3) as u8 | offset, + ((rgb & 0x0F0) >> 1) as u8 | offset, + ((rgb & 0xF00) >> 5) as u8 | offset, + ) + .encode(encoding) } } @@ -631,7 +680,18 @@ impl Sprite { } fn calculate_pattern(&self, cell_x: usize, cell_y: usize) -> u16 { - let (h, v) = (if !self.rev.0 { cell_x } else { self.size.0 as usize - 1 - cell_x }, if !self.rev.1 { cell_y } else { self.size.1 as usize - 1 - cell_y }); + let (h, v) = ( + if !self.rev.0 { + cell_x + } else { + self.size.0 as usize - 1 - cell_x + }, + if !self.rev.1 { + cell_y + } else { + self.size.1 as usize - 1 - cell_y + }, + ); (self.pattern & 0xF800) | ((self.pattern & 0x07FF) + (h as u16 * self.size.1) + v as u16) } } @@ -664,7 +724,7 @@ impl Steppable for Ym7101 { self.state.current_y += 1; self.state.h_scanlines = self.state.h_scanlines.wrapping_sub(1); - if self.state.hsync_int_enabled() && self.state.h_scanlines == 0 { + if self.state.hsync_int_enabled() && self.state.h_scanlines == 0 { self.state.h_scanlines = self.state.h_int_lines; system.get_interrupt_controller().set(true, 4, 28)?; } @@ -686,7 +746,8 @@ impl Steppable for Ym7101 { } if (self.state.mode_1 & mode1::BF_DISABLE_DISPLAY) == 0 && self.state.screen_size != (0, 0) { - let mut frame = Frame::new(self.state.screen_size.0 as u32 * 8, self.state.screen_size.1 as u32 * 8, self.sender.encoding()); + let mut frame = + Frame::new(self.state.screen_size.0 as u32 * 8, self.state.screen_size.1 as u32 * 8, self.sender.encoding()); self.state.draw_frame(&mut frame); self.sender.add(system.clock, frame); } @@ -699,7 +760,12 @@ impl Steppable for Ym7101 { if (self.state.mode_2 & mode2::BF_DMA_ENABLED) != 0 { self.state.memory.step_dma(system)?; - self.state.status = (self.state.status & !status::DMA_BUSY) | (if self.state.memory.transfer_dma_busy { status::DMA_BUSY } else { 0 }); + self.state.status = (self.state.status & !status::DMA_BUSY) + | (if self.state.memory.transfer_dma_busy { + status::DMA_BUSY + } else { + 0 + }); } Ok(Frequency::from_hz(13_423_294).period_duration() * 4) @@ -742,24 +808,44 @@ impl Ym7101 { fn update_register_value(&mut self, reg: usize, data: u8) { match reg { - reg::MODE_SET_1 => { self.state.mode_1 = data; }, + reg::MODE_SET_1 => { + self.state.mode_1 = data; + }, reg::MODE_SET_2 => { self.state.mode_2 = data; self.state.update_screen_size(); }, - reg::SCROLL_A_ADDR => { self.state.scroll_a_addr = (data as usize) << 10; }, - reg::WINDOW_ADDR => { self.state.window_addr = (data as usize) << 10; }, - reg::SCROLL_B_ADDR => { self.state.scroll_b_addr = (data as usize) << 13; }, - reg::SPRITES_ADDR => { self.state.sprites_addr = (data as usize) << 9; }, - reg::BACKGROUND => { self.state.background = data; }, - reg::H_INTERRUPT => { self.state.h_int_lines = data; }, - reg::MODE_SET_3 => { self.state.mode_3 = data; }, + reg::SCROLL_A_ADDR => { + self.state.scroll_a_addr = (data as usize) << 10; + }, + reg::WINDOW_ADDR => { + self.state.window_addr = (data as usize) << 10; + }, + reg::SCROLL_B_ADDR => { + self.state.scroll_b_addr = (data as usize) << 13; + }, + reg::SPRITES_ADDR => { + self.state.sprites_addr = (data as usize) << 9; + }, + reg::BACKGROUND => { + self.state.background = data; + }, + reg::H_INTERRUPT => { + self.state.h_int_lines = data; + }, + reg::MODE_SET_3 => { + self.state.mode_3 = data; + }, reg::MODE_SET_4 => { self.state.mode_4 = data; self.state.update_screen_size(); }, - reg::HSCROLL_ADDR => { self.state.hscroll_addr = (data as usize) << 10; }, - reg::AUTO_INCREMENT => { self.state.memory.transfer_auto_inc = data as u32; }, + reg::HSCROLL_ADDR => { + self.state.hscroll_addr = (data as usize) << 10; + }, + reg::AUTO_INCREMENT => { + self.state.memory.transfer_auto_inc = data as u32; + }, reg::SCROLL_SIZE => { let h = decode_scroll_size(data & 0x03); let v = decode_scroll_size((data >> 4) & 0x03); @@ -790,10 +876,13 @@ impl Ym7101 { reg::DMA_ADDR_HIGH => { let mask = if (data & 0x80) == 0 { 0x7F } else { 0x3F }; self.state.memory.transfer_bits = data & 0xC0; - self.state.memory.transfer_src_addr = (self.state.memory.transfer_src_addr & 0x01FFFF) | (((data & mask) as u32) << 17); + self.state.memory.transfer_src_addr = + (self.state.memory.transfer_src_addr & 0x01FFFF) | (((data & mask) as u32) << 17); }, 0x6 | 0x8 | 0x9 | 0xE => { /* Reserved */ }, - _ => { panic!("{}: unknown register: {:?}", DEV_NAME, reg); }, + _ => { + panic!("{}: unknown register: {:?}", DEV_NAME, reg); + }, } } } @@ -838,7 +927,9 @@ impl Addressable for Ym7101 { } }, - _ => { println!("{}: !!! unhandled read from {:x}", DEV_NAME, addr); }, + _ => { + println!("{}: !!! unhandled read from {:x}", DEV_NAME, addr); + }, } Ok(()) } @@ -864,7 +955,12 @@ impl Addressable for Ym7101 { } } else { self.state.memory.write_control_port(data)?; - self.state.status = (self.state.status & !status::DMA_BUSY) | (if self.state.memory.transfer_dma_busy { status::DMA_BUSY } else { 0 }); + self.state.status = (self.state.status & !status::DMA_BUSY) + | (if self.state.memory.transfer_dma_busy { + status::DMA_BUSY + } else { + 0 + }); } }, @@ -872,7 +968,9 @@ impl Addressable for Ym7101 { self.sn_sound.borrow_mut().as_addressable().unwrap().write(clock, 0, data)?; }, - _ => { log::warn!("{}: !!! unhandled write to {:x} with {:?}", DEV_NAME, addr, data); }, + _ => { + log::warn!("{}: !!! unhandled write to {:x} with {:?}", DEV_NAME, addr, data); + }, } Ok(()) } @@ -905,7 +1003,7 @@ impl Inspectable for Ym7101 { "vsram" => { self.state.dump_vsram(); }, - _ => { }, + _ => {}, } Ok(()) } @@ -941,4 +1039,3 @@ impl Ym7101State { dump_slice(&self.memory.vsram, 80); } } - diff --git a/emulator/systems/genesis/src/system.rs b/emulator/systems/genesis/src/system.rs index 9719d97..d57e2e5 100644 --- a/emulator/systems/genesis/src/system.rs +++ b/emulator/systems/genesis/src/system.rs @@ -1,4 +1,3 @@ - use std::mem; use std::rc::Rc; use std::cell::RefCell; @@ -99,4 +98,3 @@ pub fn build_genesis(host: &mut H, mut options: SegaGenesisOptions) -> Ok(system) } - diff --git a/emulator/systems/genesis/src/utils.rs b/emulator/systems/genesis/src/utils.rs index 0abee11..7234031 100644 --- a/emulator/systems/genesis/src/utils.rs +++ b/emulator/systems/genesis/src/utils.rs @@ -1,4 +1,3 @@ - use std::fs; use moa_core::Error; @@ -39,5 +38,3 @@ pub fn load_rom_file(filename: &str) -> Result, Error> { Ok(contents) } - - diff --git a/emulator/systems/macintosh/src/lib.rs b/emulator/systems/macintosh/src/lib.rs index c195df6..9bcab02 100644 --- a/emulator/systems/macintosh/src/lib.rs +++ b/emulator/systems/macintosh/src/lib.rs @@ -1,6 +1,4 @@ - pub mod peripherals; mod system; pub use crate::system::{build_macintosh_512k}; - diff --git a/emulator/systems/macintosh/src/peripherals/iwm.rs b/emulator/systems/macintosh/src/peripherals/iwm.rs index f8d3567..fe5f0d2 100644 --- a/emulator/systems/macintosh/src/peripherals/iwm.rs +++ b/emulator/systems/macintosh/src/peripherals/iwm.rs @@ -1,4 +1,3 @@ - use femtos::{Instant, Duration}; use moa_core::{System, Error, Address, Addressable, Steppable, Transmutable}; @@ -8,10 +7,10 @@ use moa_core::{System, Error, Address, Addressable, Steppable, Transmutable}; //const CA1: u8 = 0x02; //const CA2: u8 = 0x04; //const LSTRB: u8 = 0x08; -const ENABLE: u8 = 0x10; +const ENABLE: u8 = 0x10; //const SELECT: u8 = 0x20; -const Q6: u8 = 0x40; -const Q7: u8 = 0x80; +const Q6: u8 = 0x40; +const Q7: u8 = 0x80; const DEV_NAME: &str = "iwm"; @@ -61,7 +60,7 @@ impl Addressable for IWM { Q7 => { // read "write-handshake" register data[i] = 0x3F | self.handshake; - } + }, b if b == (Q7 | Q6) => { panic!(""); }, @@ -111,4 +110,3 @@ impl Transmutable for IWM { Some(self) } } - diff --git a/emulator/systems/macintosh/src/peripherals/mainboard.rs b/emulator/systems/macintosh/src/peripherals/mainboard.rs index 0ccdcd6..67816f3 100644 --- a/emulator/systems/macintosh/src/peripherals/mainboard.rs +++ b/emulator/systems/macintosh/src/peripherals/mainboard.rs @@ -1,4 +1,3 @@ - use std::rc::Rc; use std::cell::RefCell; use femtos::{Instant, Duration}; @@ -47,16 +46,30 @@ impl Mainboard { if (port.data & 0x10) == 0 { println!("{}: overlay is 0 (normal)", DEV_NAME); lower_bus.borrow_mut().clear_all_bus_devices(); - lower_bus.borrow_mut().insert(0x000000, Device::new(AddressRepeater::new(ram.clone(), 0x400000))); - lower_bus.borrow_mut().insert(0x400000, Device::new(AddressRepeater::new(rom.clone(), 0x100000))); - lower_bus.borrow_mut().insert(0x600000, Device::new(AddressRepeater::new(rom.clone(), 0x100000))); + lower_bus + .borrow_mut() + .insert(0x000000, Device::new(AddressRepeater::new(ram.clone(), 0x400000))); + lower_bus + .borrow_mut() + .insert(0x400000, Device::new(AddressRepeater::new(rom.clone(), 0x100000))); + lower_bus + .borrow_mut() + .insert(0x600000, Device::new(AddressRepeater::new(rom.clone(), 0x100000))); } else { println!("{}: overlay is 1 (startup)", DEV_NAME); lower_bus.borrow_mut().clear_all_bus_devices(); - lower_bus.borrow_mut().insert(0x000000, Device::new(AddressRepeater::new(rom.clone(), 0x100000))); - lower_bus.borrow_mut().insert(0x200000, Device::new(AddressRepeater::new(rom.clone(), 0x100000))); - lower_bus.borrow_mut().insert(0x400000, Device::new(AddressRepeater::new(rom.clone(), 0x100000))); - lower_bus.borrow_mut().insert(0x600000, Device::new(AddressRepeater::new(ram.clone(), 0x200000))); + lower_bus + .borrow_mut() + .insert(0x000000, Device::new(AddressRepeater::new(rom.clone(), 0x100000))); + lower_bus + .borrow_mut() + .insert(0x200000, Device::new(AddressRepeater::new(rom.clone(), 0x100000))); + lower_bus + .borrow_mut() + .insert(0x400000, Device::new(AddressRepeater::new(rom.clone(), 0x100000))); + lower_bus + .borrow_mut() + .insert(0x600000, Device::new(AddressRepeater::new(ram.clone(), 0x200000))); } }); @@ -139,9 +152,7 @@ impl Transmutable for Mainboard { #[derive(Default)] -pub struct PhaseRead { - -} +pub struct PhaseRead {} impl Addressable for PhaseRead { fn size(&self) -> usize { @@ -159,4 +170,3 @@ impl Addressable for PhaseRead { Ok(()) } } - diff --git a/emulator/systems/macintosh/src/peripherals/mod.rs b/emulator/systems/macintosh/src/peripherals/mod.rs index 426b19b..0c0989d 100644 --- a/emulator/systems/macintosh/src/peripherals/mod.rs +++ b/emulator/systems/macintosh/src/peripherals/mod.rs @@ -1,5 +1,3 @@ - pub mod iwm; -pub mod video; pub mod mainboard; - +pub mod video; diff --git a/emulator/systems/macintosh/src/peripherals/video.rs b/emulator/systems/macintosh/src/peripherals/video.rs index 7854f8d..793160b 100644 --- a/emulator/systems/macintosh/src/peripherals/video.rs +++ b/emulator/systems/macintosh/src/peripherals/video.rs @@ -1,11 +1,10 @@ - use femtos::Duration; use moa_core::{System, Error, Address, Addressable, Steppable, Transmutable}; use moa_host::{self, Host, HostError, Frame, FrameSender, Pixel}; -const SCRN_BASE: u32 = 0x07A700; +const SCRN_BASE: u32 = 0x07A700; const SCRN_SIZE: (u32, u32) = (512, 342); pub struct MacVideo { @@ -81,4 +80,3 @@ impl Transmutable for MacVideo { Some(self) } } - diff --git a/emulator/systems/macintosh/src/system.rs b/emulator/systems/macintosh/src/system.rs index 2ce660d..b9e6af9 100644 --- a/emulator/systems/macintosh/src/system.rs +++ b/emulator/systems/macintosh/src/system.rs @@ -1,4 +1,3 @@ - use femtos::Frequency; use moa_core::{System, Error, MemoryBlock, Debuggable, Device}; @@ -80,7 +79,7 @@ pub fn build_macintosh_512k(host: &mut H) -> Result { //cpu.add_breakpoint(0x400694); // Ram Test //cpu.add_breakpoint(0x400170); // Failed, loops infinitely - cpu.add_breakpoint(0x4000f4); // Failed, should show the sad mac + cpu.add_breakpoint(0x4000f4); // Failed, should show the sad mac //cpu.add_breakpoint(0x4006ae); //cpu.add_breakpoint(0x400706); //cpu.add_breakpoint(0x400722); // end of ram test @@ -96,7 +95,7 @@ pub fn build_macintosh_512k(host: &mut H) -> Result { //cpu.add_breakpoint(0x40045c); //cpu.add_breakpoint(0x400614); // Start of InitIO - cpu.add_breakpoint(0x40062a); // Loop in InitIO + cpu.add_breakpoint(0x40062a); // Loop in InitIO //cpu.add_breakpoint(0x400648); //cpu.add_breakpoint(0x40064c); //cpu.add_breakpoint(0x4014a6); // DrvrInstall @@ -107,7 +106,7 @@ pub fn build_macintosh_512k(host: &mut H) -> Result { // Issue of writing to 0x100000 which doesn't exist cpu.add_breakpoint(0x400d62); - cpu.add_breakpoint(0x400464); // Boot Screen + cpu.add_breakpoint(0x400464); // Boot Screen /* use crate::devices::Addressable; @@ -127,4 +126,3 @@ pub fn build_macintosh_512k(host: &mut H) -> Result { Ok(system) } - diff --git a/emulator/systems/trs80/src/lib.rs b/emulator/systems/trs80/src/lib.rs index 09ba313..17e5e3c 100644 --- a/emulator/systems/trs80/src/lib.rs +++ b/emulator/systems/trs80/src/lib.rs @@ -1,6 +1,4 @@ - pub mod peripherals; mod system; pub use crate::system::{Trs80Options, build_trs80}; - diff --git a/emulator/systems/trs80/src/peripherals/mod.rs b/emulator/systems/trs80/src/peripherals/mod.rs index 6eba46e..aeca97f 100644 --- a/emulator/systems/trs80/src/peripherals/mod.rs +++ b/emulator/systems/trs80/src/peripherals/mod.rs @@ -1,5 +1,5 @@ - pub mod model1; +#[rustfmt::skip] pub mod keymap; +#[rustfmt::skip] pub mod charset; - diff --git a/emulator/systems/trs80/src/peripherals/model1.rs b/emulator/systems/trs80/src/peripherals/model1.rs index 577b465..1e6dc75 100644 --- a/emulator/systems/trs80/src/peripherals/model1.rs +++ b/emulator/systems/trs80/src/peripherals/model1.rs @@ -1,4 +1,3 @@ - use femtos::{Instant, Duration}; use moa_core::{System, Error, Address, Addressable, Steppable, Transmutable}; @@ -8,12 +7,12 @@ use super::keymap; use super::charset::CharacterGenerator; -const DEV_NAME: &str = "model1"; -const SCREEN_SIZE: (u32, u32) = (384, 128); +const DEV_NAME: &str = "model1"; +const SCREEN_SIZE: (u32, u32) = (384, 128); pub struct Model1Keyboard { - receiver: EventReceiver, + receiver: EventReceiver, keyboard_mem: [u8; 8], } @@ -41,14 +40,30 @@ impl Addressable for Model1Keyboard { if (0x20..=0xA0).contains(&addr) { let offset = addr - 0x20; data[0] = 0; - if (offset & 0x01) != 0 { data[0] |= self.keyboard_mem[0]; } - if (offset & 0x02) != 0 { data[0] |= self.keyboard_mem[1]; } - if (offset & 0x04) != 0 { data[0] |= self.keyboard_mem[2]; } - if (offset & 0x08) != 0 { data[0] |= self.keyboard_mem[3]; } - if (offset & 0x10) != 0 { data[0] |= self.keyboard_mem[4]; } - if (offset & 0x20) != 0 { data[0] |= self.keyboard_mem[5]; } - if (offset & 0x40) != 0 { data[0] |= self.keyboard_mem[6]; } - if (offset & 0x80) != 0 { data[0] |= self.keyboard_mem[7]; } + if (offset & 0x01) != 0 { + data[0] |= self.keyboard_mem[0]; + } + if (offset & 0x02) != 0 { + data[0] |= self.keyboard_mem[1]; + } + if (offset & 0x04) != 0 { + data[0] |= self.keyboard_mem[2]; + } + if (offset & 0x08) != 0 { + data[0] |= self.keyboard_mem[3]; + } + if (offset & 0x10) != 0 { + data[0] |= self.keyboard_mem[4]; + } + if (offset & 0x20) != 0 { + data[0] |= self.keyboard_mem[5]; + } + if (offset & 0x40) != 0 { + data[0] |= self.keyboard_mem[6]; + } + if (offset & 0x80) != 0 { + data[0] |= self.keyboard_mem[7]; + } //info!("{}: read from keyboard {:x} of {:?}", DEV_NAME, addr, data); } else { log::warn!("{}: !!! unhandled read from {:0x}", DEV_NAME, addr); @@ -147,4 +162,3 @@ impl Transmutable for Model1Video { Some(self) } } - diff --git a/emulator/systems/trs80/src/system.rs b/emulator/systems/trs80/src/system.rs index 9767c50..d692853 100644 --- a/emulator/systems/trs80/src/system.rs +++ b/emulator/systems/trs80/src/system.rs @@ -1,4 +1,3 @@ - use femtos::Frequency; use moa_core::{System, Error, MemoryBlock, Device}; @@ -46,32 +45,8 @@ pub fn build_trs80(host: &mut H, options: Trs80Options) -> Result Result<(M68k, Memo // Insert basic initialization let len = 0x100_0000; let mut data = Vec::with_capacity(len); - unsafe { data.set_len(len); } + unsafe { + data.set_len(len); + } let mut memory = MemoryBlock::::from(data); let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10)); @@ -164,7 +165,7 @@ fn init_execute_test(cputype: M68kType, state: &TestState) -> Result<(M68k, Memo fn assert_value(actual: T, expected: T, message: &str) -> Result<(), Error> where - T: PartialEq + Debug + UpperHex + T: PartialEq + Debug + UpperHex, { if actual == expected { Ok(()) @@ -197,13 +198,15 @@ fn load_state(cpu: &mut M68k, memory: &mut MemoryBlock, initial: & // Load instructions into memory for (i, ins) in initial.prefetch.iter().enumerate() { - memory.write_beu16(Instant::START, initial.pc + (i as u32 * 2), *ins) + memory + .write_beu16(Instant::START, initial.pc + (i as u32 * 2), *ins) .map_err(|err| Error::Bus(format!("{:?}", err)))?; } // Load data bytes into memory for (addr, byte) in initial.ram.iter() { - memory.write_u8(Instant::START, *addr, *byte) + memory + .write_u8(Instant::START, *addr, *byte) .map_err(|err| Error::Bus(format!("{:?}", err)))?; } @@ -237,14 +240,16 @@ fn assert_state(cpu: &M68k, memory: &mut MemoryBlock, expected: &T // Load instructions into memory for (i, ins) in expected.prefetch.iter().enumerate() { let addr = expected.pc + (i as u32 * 2); - let actual = memory.read_beu16(Instant::START, addr & addr_mask) + let actual = memory + .read_beu16(Instant::START, addr & addr_mask) .map_err(|err| Error::Bus(format!("{:?}", err)))?; assert_value(actual, *ins, &format!("prefetch at {:x}", addr))?; } // Load data bytes into memory for (addr, byte) in expected.ram.iter() { - let actual = memory.read_u8(Instant::START, *addr & addr_mask) + let actual = memory + .read_u8(Instant::START, *addr & addr_mask) .map_err(|err| Error::Bus(format!("{:?}", err)))?; assert_value(actual, *byte, &format!("ram at {:x}", addr))?; } @@ -252,8 +257,14 @@ fn assert_state(cpu: &M68k, memory: &mut MemoryBlock, expected: &T Ok(()) } -fn step_cpu_and_assert(cpu: &mut M68k, memory: &mut MemoryBlock, case: &TestCase, test_timing: bool) -> Result<(), Error> { - let clock_elapsed = cpu.step(Instant::START, memory) +fn step_cpu_and_assert( + cpu: &mut M68k, + memory: &mut MemoryBlock, + case: &TestCase, + test_timing: bool, +) -> Result<(), Error> { + let clock_elapsed = cpu + .step(Instant::START, memory) .map_err(|err| Error::Step(format!("{:?}", err)))?; let cycles = clock_elapsed.as_duration() / cpu.info.frequency.period_duration(); @@ -282,7 +293,7 @@ fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> { initial_cpu.dump_state(&mut writer).unwrap(); cpu.dump_state(&mut writer).unwrap(); } - writeln!(writer, "FAILED: {:?}", err).unwrap(); + writeln!(writer, "FAILED: {:?}", err).unwrap(); println!("{}", writer); } Err(err) @@ -315,8 +326,9 @@ fn test_json_file(path: PathBuf, args: &Args) -> (usize, usize, String) { // Only run the test if it's selected by the exceptions flag if case.is_extended_exception_case() && args.exceptions == Selection::ExcludeAddr - || case.is_exception_case() && args.exceptions == Selection::Exclude - || !case.is_exception_case() && args.exceptions == Selection::Only { + || case.is_exception_case() && args.exceptions == Selection::Exclude + || !case.is_exception_case() && args.exceptions == Selection::Only + { continue; } @@ -334,7 +346,7 @@ fn test_json_file(path: PathBuf, args: &Args) -> (usize, usize, String) { if let Err(err) = result { failed += 1; if !args.quiet { - println!("FAILED: {:?}", err); + println!("FAILED: {:?}", err); } } else { passed += 1 @@ -401,7 +413,11 @@ fn run_all_tests(args: &Args) { } println!(); - println!("passed: {}, failed: {}, total {:.0}%", passed, failed, ((passed as f32) / (passed as f32 + failed as f32)) * 100.0); + println!( + "passed: {}, failed: {}, total {:.0}%", + passed, + failed, + ((passed as f32) / (passed as f32 + failed as f32)) * 100.0 + ); println!("completed in {}m {}s", elapsed_secs / 60, elapsed_secs % 60); } - diff --git a/tests/rad_tests/src/main.rs b/tests/rad_tests/src/main.rs index 408f338..075bcf1 100644 --- a/tests/rad_tests/src/main.rs +++ b/tests/rad_tests/src/main.rs @@ -1,4 +1,3 @@ - const DEFAULT_RAD_TESTS: &str = "tests/jsmoo/misc/tests/GeneratedTests/z80/v1/"; use std::rc::Rc; @@ -171,7 +170,7 @@ fn init_execute_test(cputype: Z80Type, state: &TestState, ports: &[TestPort]) -> fn assert_value(actual: T, expected: T, message: &str) -> Result<(), Error> where - T: PartialEq + Debug + UpperHex + T: PartialEq + Debug + UpperHex, { if actual == expected { Ok(()) @@ -180,7 +179,13 @@ where } } -fn load_state(cpu: &mut Z80, system: &mut System, io_bus: Rc>, initial: &TestState, ports: &[TestPort]) -> Result<(), Error> { +fn load_state( + cpu: &mut Z80, + system: &mut System, + io_bus: Rc>, + initial: &TestState, + ports: &[TestPort], +) -> Result<(), Error> { cpu.state.reg[0] = initial.b; cpu.state.reg[1] = initial.c; cpu.state.reg[2] = initial.d; @@ -223,7 +228,14 @@ fn load_state(cpu: &mut Z80, system: &mut System, io_bus: Rc>, init const IGNORE_FLAG_MASK: u8 = Flags::F3 as u8 | Flags::F5 as u8; -fn assert_state(cpu: &Z80, system: &System, io_bus: Rc>, expected: &TestState, check_extra_flags: bool, ports: &[TestPort]) -> Result<(), Error> { +fn assert_state( + cpu: &Z80, + system: &System, + io_bus: Rc>, + expected: &TestState, + check_extra_flags: bool, + ports: &[TestPort], +) -> Result<(), Error> { assert_value(cpu.state.reg[0], expected.b, "b")?; assert_value(cpu.state.reg[1], expected.c, "c")?; assert_value(cpu.state.reg[2], expected.d, "d")?; @@ -279,14 +291,24 @@ fn assert_state(cpu: &Z80, system: &System, io_bus: Rc>, expected: Ok(()) } -fn step_cpu_and_assert(cpu: &mut Z80, system: &System, io_bus: Rc>, case: &TestCase, args: &Args) -> Result<(), Error> { +fn step_cpu_and_assert( + cpu: &mut Z80, + system: &System, + io_bus: Rc>, + case: &TestCase, + args: &Args, +) -> Result<(), Error> { let clock_elapsed = cpu.step(system)?; assert_state(cpu, system, io_bus, &case.final_state, args.check_extra_flags, &case.ports)?; if args.check_timings { let cycles = clock_elapsed / cpu.frequency.period_duration(); if cycles != case.cycles.len() as Address { - return Err(Error::assertion(format!("expected instruction to take {} cycles, but took {}", case.cycles.len(), cycles))); + return Err(Error::assertion(format!( + "expected instruction to take {} cycles, but took {}", + case.cycles.len(), + cycles + ))); } } @@ -309,7 +331,7 @@ fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> { initial_cpu.dump_state(system.clock); cpu.dump_state(system.clock); } - println!("FAILED: {:?}", err); + println!("FAILED: {:?}", err); } Err(err) }, @@ -353,7 +375,7 @@ fn test_json_file(path: PathBuf, args: &Args) -> (usize, usize, String) { if let Err(err) = result { failed += 1; if !args.quiet { - println!("FAILED: {:?}", err); + println!("FAILED: {:?}", err); } } else { passed += 1 @@ -426,7 +448,12 @@ fn run_all_tests(args: &Args) { } println!(); - println!("passed: {}, failed: {}, total {:.0}%", passed, failed, ((passed as f32) / (passed as f32 + failed as f32)) * 100.0); + println!( + "passed: {}, failed: {}, total {:.0}%", + passed, + failed, + ((passed as f32) / (passed as f32 + failed as f32)) * 100.0 + ); println!("completed in {}m {}s", elapsed_secs / 60, elapsed_secs % 60); } @@ -438,28 +465,24 @@ fn is_undocumented_instruction(name: &str) -> bool { opcodes.extend(vec![0; 3 - opcodes.len()]); match (opcodes[0], opcodes[1]) { - (0xCB, op) => { - (0x30..=0x37).contains(&op) - }, - (0xDD, 0xCB) | - (0xFD, 0xCB) => { - !(opcodes[2] & 0x07 == 0x06 && opcodes[2] != 0x36) - }, - (0xDD, op) | - (0xFD, op) => { + (0xCB, op) => (0x30..=0x37).contains(&op), + (0xDD, 0xCB) | (0xFD, 0xCB) => !(opcodes[2] & 0x07 == 0x06 && opcodes[2] != 0x36), + (0xDD, op) | (0xFD, op) => { let upper = op & 0xF0; let lower = op & 0x0F; - !(lower == 0x0E && (0x40..=0xB0).contains(&upper) || (0x70..=0x77).contains(&op) && op != 0x76 || op != 0x76 && (0x70..=0x77).contains(&op) || lower == 0x06 && (0x30..=0xB0).contains(&upper) && upper != 0x70) && - !((0x21..=0x23).contains(&op) || (0x34..=0x36).contains(&op) || (0x29..=0x2B).contains(&op)) && - !(lower == 0x09 && upper <= 0x30) && - !(op == 0xE1 || op == 0xE3 || op == 0xE5 || op == 0xE9 || op == 0xF9) + !(lower == 0x0E && (0x40..=0xB0).contains(&upper) + || (0x70..=0x77).contains(&op) && op != 0x76 + || op != 0x76 && (0x70..=0x77).contains(&op) + || lower == 0x06 && (0x30..=0xB0).contains(&upper) && upper != 0x70) + && !((0x21..=0x23).contains(&op) || (0x34..=0x36).contains(&op) || (0x29..=0x2B).contains(&op)) + && !(lower == 0x09 && upper <= 0x30) + && !(op == 0xE1 || op == 0xE3 || op == 0xE5 || op == 0xE9 || op == 0xF9) }, (0xED, op) => { // NOTE this assumes the tests don't have the missing instructions, or the Z180 instructions // so it only checks for the undocumented ones op == 0x63 || op == 0x6B || op == 0x70 || op == 0x71 }, - _ => false + _ => false, } } - diff --git a/todo.txt b/todo.txt index a5b6825..c22e1d1 100644 --- a/todo.txt +++ b/todo.txt @@ -1,17 +1,19 @@ +* convert the Z80 +* implement Inspect/Debug traits * fix dump_state everywhere, which now requires a writer. Is there an easier way? Is there a way that doesn't require std -* can you clean it up more? -* implement the inspect and debug traits -* move the interrupt controller logic to the step() function only, and have a customish interrupt interface into the sim +* fix it to use the full 68k address space, and maybe see if it's possible to make the address translation cleaner/nicer/simpler/faster +* figure out how to do interrupts, and add them to emulator-hal, implement them in m68k +* convert peripherals to use BusAccess and Step +* replace Addressable/Steppable and modify Transmutable to use the emulator-hal traits +* remove the custom moa impls from m68k if possible at this point +* publish the emulator-hal crate +* publish the m68k and z80 crates -* do the Z80? Should that be another PR? -* fix the tests -* fix all the clippy issues * it doesn't work when using debug due to math checks, so fix them -* change all the inspection and debugging things to return a struct which can then be printed by the frontend - +----- * there are many issues with the coprocessor address space, and the VDP * I mapped the sn sound chip into 0xC00010, in the middle of the VDP's address space, and didn't get a runtime error!!! needs fixing