From be91118bac178bf8dfcbe74cce663aad5280c24e Mon Sep 17 00:00:00 2001 From: transistor Date: Sat, 10 Jun 2023 20:28:40 -0700 Subject: [PATCH] Added function to create the CPU BusPorts based on the CPU type --- emulator/cpus/m68k/src/state.rs | 14 ++- emulator/cpus/m68k/src/tests.rs | 7 +- emulator/cpus/m68k/tests/decode_tests.rs | 7 +- emulator/cpus/m68k/tests/execute_tests.rs | 7 +- .../cpus/m68k/tests/musashi_timing_tests.rs | 7 +- emulator/cpus/m68k/tests/timing_tests.rs | 7 +- emulator/cpus/z80/src/state.rs | 11 ++- .../frontends/console/src/bin/moa-bench.rs | 2 +- emulator/systems/computie/src/system.rs | 6 +- emulator/systems/genesis/src/system.rs | 6 +- emulator/systems/macintosh/src/system.rs | 4 +- emulator/systems/trs80/src/system.rs | 4 +- todo.txt | 97 ++++++++----------- 13 files changed, 77 insertions(+), 102 deletions(-) diff --git a/emulator/cpus/m68k/src/state.rs b/emulator/cpus/m68k/src/state.rs index fa0535d..ef75ab8 100644 --- a/emulator/cpus/m68k/src/state.rs +++ b/emulator/cpus/m68k/src/state.rs @@ -1,5 +1,8 @@ -use moa_core::{ClockTime, BusPort, Frequency}; +use std::rc::Rc; +use std::cell::RefCell; + +use moa_core::{ClockTime, Address, Bus, BusPort, Frequency}; use crate::decode::M68kDecoder; use crate::debugger::M68kDebugger; @@ -132,6 +135,15 @@ impl M68k { } } + pub fn from_type(cputype: M68kType, frequency: Frequency, bus: Rc>, addr_offset: Address) -> Self { + match cputype { + M68kType::MC68000 | + M68kType::MC68010 => Self::new(cputype, frequency, BusPort::new(addr_offset, 24, 16, bus)), + M68kType::MC68020 | + M68kType::MC68030 => Self::new(cputype, frequency, BusPort::new(addr_offset, 32, 32, bus)), + } + } + pub fn dump_state(&mut self) { println!("Status: {:?}", self.state.status); println!("PC: {:#010x}", self.state.pc); diff --git a/emulator/cpus/m68k/src/tests.rs b/emulator/cpus/m68k/src/tests.rs index 1014a85..812bd55 100644 --- a/emulator/cpus/m68k/src/tests.rs +++ b/emulator/cpus/m68k/src/tests.rs @@ -269,12 +269,7 @@ mod execute_unit_tests { system.get_bus().write_beu32(system.clock, 0, INIT_STACK as u32).unwrap(); system.get_bus().write_beu32(system.clock, 4, INIT_ADDR as u32).unwrap(); - let port = if cputype <= M68kType::MC68010 { - BusPort::new(0, 24, 16, system.bus.clone()) - } else { - BusPort::new(0, 24, 16, system.bus.clone()) - }; - let mut cpu = M68k::new(cputype, Frequency::from_mhz(10), port); + let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0); cpu.step(&system).unwrap(); cpu.decoder.init(true, cpu.state.pc); assert_eq!(cpu.state.pc, INIT_ADDR as u32); diff --git a/emulator/cpus/m68k/tests/decode_tests.rs b/emulator/cpus/m68k/tests/decode_tests.rs index 4403237..c7ff40b 100644 --- a/emulator/cpus/m68k/tests/decode_tests.rs +++ b/emulator/cpus/m68k/tests/decode_tests.rs @@ -72,12 +72,7 @@ fn init_decode_test(cputype: M68kType) -> (M68k, System) { system.get_bus().write_beu32(ClockTime::START, 4, INIT_ADDR as u32).unwrap(); // Initialize the CPU and make sure it's in the expected state - let port = if cputype <= M68kType::MC68010 { - BusPort::new(0, 24, 16, system.bus.clone()) - } else { - BusPort::new(0, 24, 16, system.bus.clone()) - }; - let mut cpu = M68k::new(cputype, Frequency::from_mhz(10), port); + let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0); cpu.reset_cpu().unwrap(); assert_eq!(cpu.state.pc, INIT_ADDR as u32); assert_eq!(cpu.state.ssp, INIT_STACK as u32); diff --git a/emulator/cpus/m68k/tests/execute_tests.rs b/emulator/cpus/m68k/tests/execute_tests.rs index 8fba59c..892cb2b 100644 --- a/emulator/cpus/m68k/tests/execute_tests.rs +++ b/emulator/cpus/m68k/tests/execute_tests.rs @@ -42,12 +42,7 @@ fn init_execute_test(cputype: M68kType) -> (M68k, System) { system.get_bus().write_beu32(ClockTime::START, 0, INIT_STACK as u32).unwrap(); system.get_bus().write_beu32(ClockTime::START, 4, INIT_ADDR as u32).unwrap(); - let port = if cputype <= M68kType::MC68010 { - BusPort::new(0, 24, 16, system.bus.clone()) - } else { - BusPort::new(0, 24, 16, system.bus.clone()) - }; - let mut cpu = M68k::new(cputype, Frequency::from_mhz(10), port); + let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0); cpu.step(&system).unwrap(); cpu.decoder.init(true, cpu.state.pc); assert_eq!(cpu.state.pc, INIT_ADDR as u32); diff --git a/emulator/cpus/m68k/tests/musashi_timing_tests.rs b/emulator/cpus/m68k/tests/musashi_timing_tests.rs index d494d8b..7f29d2b 100644 --- a/emulator/cpus/m68k/tests/musashi_timing_tests.rs +++ b/emulator/cpus/m68k/tests/musashi_timing_tests.rs @@ -20,12 +20,7 @@ fn init_decode_test(cputype: M68kType) -> (M68k, System) { system.get_bus().write_beu32(ClockTime::START, 4, INIT_ADDR as u32).unwrap(); // Initialize the CPU and make sure it's in the expected state - let port = if cputype <= M68kType::MC68010 { - BusPort::new(0, 24, 16, system.bus.clone()) - } else { - BusPort::new(0, 24, 16, system.bus.clone()) - }; - let mut cpu = M68k::new(cputype, Frequency::from_mhz(10), port); + let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0); cpu.init_cycle(ClockTime::START); assert_eq!(cpu.state.pc, INIT_ADDR as u32); assert_eq!(cpu.state.ssp, INIT_STACK as u32); diff --git a/emulator/cpus/m68k/tests/timing_tests.rs b/emulator/cpus/m68k/tests/timing_tests.rs index b0597aa..f943a12 100644 --- a/emulator/cpus/m68k/tests/timing_tests.rs +++ b/emulator/cpus/m68k/tests/timing_tests.rs @@ -32,12 +32,7 @@ fn init_decode_test(cputype: M68kType) -> (M68k, System) { system.get_bus().write_beu32(ClockTime::START, 4, INIT_ADDR as u32).unwrap(); // Initialize the CPU and make sure it's in the expected state - let port = if cputype <= M68kType::MC68010 { - BusPort::new(0, 24, 16, system.bus.clone()) - } else { - BusPort::new(0, 24, 16, system.bus.clone()) - }; - let mut cpu = M68k::new(cputype, Frequency::from_mhz(10), port); + let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0); cpu.reset_cpu().unwrap(); assert_eq!(cpu.state.pc, INIT_ADDR as u32); assert_eq!(cpu.state.ssp, INIT_STACK as u32); diff --git a/emulator/cpus/z80/src/state.rs b/emulator/cpus/z80/src/state.rs index c463bca..897dd87 100644 --- a/emulator/cpus/z80/src/state.rs +++ b/emulator/cpus/z80/src/state.rs @@ -1,5 +1,8 @@ -use moa_core::{ClockTime, Address, BusPort, Signal, Frequency}; +use std::rc::Rc; +use std::cell::RefCell; + +use moa_core::{ClockTime, Address, Bus, BusPort, Signal, Frequency}; use crate::decode::Z80Decoder; use crate::debugger::Z80Debugger; @@ -117,6 +120,12 @@ impl Z80 { } } + 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))), + } + } + #[allow(dead_code)] pub fn clear_state(&mut self) { self.state = Z80State::default(); diff --git a/emulator/frontends/console/src/bin/moa-bench.rs b/emulator/frontends/console/src/bin/moa-bench.rs index 579f081..c6d869f 100644 --- a/emulator/frontends/console/src/bin/moa-bench.rs +++ b/emulator/frontends/console/src/bin/moa-bench.rs @@ -27,7 +27,7 @@ fn main() { system.add_addressable_device(0x00700000, Device::new(serial)).unwrap(); - let cpu = M68k::new(M68kType::MC68010, Frequency::from_mhz(8), BusPort::new(0, 24, 16, system.bus.clone())); + let cpu = M68k::from_type(M68kType::MC68010, Frequency::from_mhz(8), system.bus.clone(), 0); //cpu.enable_tracing(); //cpu.add_breakpoint(0x10781a); diff --git a/emulator/systems/computie/src/system.rs b/emulator/systems/computie/src/system.rs index 34180e1..bfc9aee 100644 --- a/emulator/systems/computie/src/system.rs +++ b/emulator/systems/computie/src/system.rs @@ -1,5 +1,5 @@ -use moa_core::{System, Error, Frequency, Debuggable, MemoryBlock, BusPort, Device}; +use moa_core::{System, Error, Frequency, Debuggable, MemoryBlock, Device}; use moa_core::host::Host; use moa_m68k::{M68k, M68kType}; @@ -27,7 +27,7 @@ pub fn build_computie(host: &H) -> Result { system.add_addressable_device(0x00700000, Device::new(serial))?; - let mut cpu = M68k::new(M68kType::MC68010, Frequency::from_hz(10_000_000), BusPort::new(0, 24, 16, system.bus.clone())); + let mut cpu = M68k::from_type(M68kType::MC68010, Frequency::from_hz(10_000_000), system.bus.clone(), 0); //cpu.enable_tracing(); //cpu.add_breakpoint(0x10781a); @@ -65,7 +65,7 @@ pub fn build_computie_k30(host: &H) -> Result { system.add_addressable_device(0x00700000, Device::new(serial))?; - let cpu = M68k::new(M68kType::MC68030, Frequency::from_hz(10_000_000), BusPort::new(0, 32, 32, system.bus.clone())); + let cpu = M68k::from_type(M68kType::MC68030, Frequency::from_hz(10_000_000), system.bus.clone(), 0); //cpu.enable_tracing(); //cpu.add_breakpoint(0x10781a); diff --git a/emulator/systems/genesis/src/system.rs b/emulator/systems/genesis/src/system.rs index cece9fa..a8fabbd 100644 --- a/emulator/systems/genesis/src/system.rs +++ b/emulator/systems/genesis/src/system.rs @@ -3,7 +3,7 @@ use std::mem; use std::rc::Rc; use std::cell::RefCell; -use moa_core::{System, Error, Frequency, Signal, MemoryBlock, Bus, BusPort, Address, Addressable, Device}; +use moa_core::{System, Error, Frequency, Signal, MemoryBlock, Bus, Address, Addressable, Device}; use moa_core::host::Host; use moa_m68k::{M68k, M68kType}; @@ -82,7 +82,7 @@ pub fn build_genesis(host: &mut H, mut options: SegaGenesisOptions) -> coproc_bus.borrow_mut().insert(0x6000, coproc_register.clone()); coproc_bus.borrow_mut().insert(0x7f11, coproc_sn_sound.clone()); coproc_bus.borrow_mut().insert(0x8000, coproc_area); - let coproc = Z80::new(Z80Type::Z80, Frequency::from_hz(3_579_545), BusPort::new(0, 16, 8, coproc_bus), None); + let coproc = Z80::from_type(Z80Type::Z80, Frequency::from_hz(3_579_545), coproc_bus, 0, None); let mut reset = coproc.reset.clone(); let mut bus_request = coproc.bus_request.clone(); reset.set(true); @@ -107,7 +107,7 @@ pub fn build_genesis(host: &mut H, mut options: SegaGenesisOptions) -> let vdp = Ym7101::new(host, interrupt, coproc_sn_sound); system.add_peripheral("vdp", 0x00c00000, Device::new(vdp)).unwrap(); - let cpu = M68k::new(M68kType::MC68000, Frequency::from_hz(7_670_454), BusPort::new(0, 24, 16, system.bus.clone())); + let cpu = M68k::from_type(M68kType::MC68000, Frequency::from_hz(7_670_454), system.bus.clone(), 0); system.add_interruptable_device("cpu", Device::new(cpu)).unwrap(); Ok(system) diff --git a/emulator/systems/macintosh/src/system.rs b/emulator/systems/macintosh/src/system.rs index 84f1091..a1e7175 100644 --- a/emulator/systems/macintosh/src/system.rs +++ b/emulator/systems/macintosh/src/system.rs @@ -1,5 +1,5 @@ -use moa_core::{System, Error, Frequency, MemoryBlock, BusPort, Debuggable, Device}; +use moa_core::{System, Error, Frequency, MemoryBlock, Debuggable, Device}; use moa_core::host::Host; use moa_m68k::{M68k, M68kType}; @@ -69,7 +69,7 @@ pub fn build_macintosh_512k(host: &mut H) -> Result { system.add_addressable_device(0x00000000, Device::new(mainboard))?; - let mut cpu = M68k::new(M68kType::MC68000, Frequency::from_hz(7_833_600), BusPort::new(0, 24, 16, system.bus.clone())); + let mut cpu = M68k::from_type(M68kType::MC68000, Frequency::from_hz(7_833_600), system.bus.clone(), 0); //cpu.enable_tracing(); //system.enable_debugging(); diff --git a/emulator/systems/trs80/src/system.rs b/emulator/systems/trs80/src/system.rs index 1359666..180c541 100644 --- a/emulator/systems/trs80/src/system.rs +++ b/emulator/systems/trs80/src/system.rs @@ -1,5 +1,5 @@ -use moa_core::{System, Error, Frequency, MemoryBlock, BusPort, Device}; +use moa_core::{System, Error, Frequency, MemoryBlock, Device}; use moa_core::host::Host; use moa_z80::{Z80, Z80Type}; @@ -43,7 +43,7 @@ pub fn build_trs80(host: &mut H, options: Trs80Options) -> Result/Into - -* go through flags on m68k and see if you can fix the remaining ones and/or clean up the implementation - -* you could possibly make a Z80MemoryPort type that wraps the BusPort type and which impls Addressable, which can be passed into the decoder - to auto-insert things like the refresh counter, as well as the record all bus timings whenever any mem access is performed -* should you make Address a newtype and add From impls for each type of numeric, and add utils to wrap address at certain boundaries and such -* should you make a means of storing different kinds of buses? -* should you make buses hide their RcRefCell? -* make functions for creating a processor instance from the cpu type (M68k::from_type()), ie. initialize the busport internally with the correct - bitwidths, but it would still be possible to initialize the CPU manually to create one that never existed as such - - -* address repeater on ym2612 doesn't seem to work the same, when it's on the 68000 device. The Z80 device doesn't have an affect, but maybe it's not being used -* sound doesn't work on a lot of games... is it a problem with the Z80 accessing the YM2612, or the lack of YM timers? or something else? -* make the ym generate audio in sync so the DAC timings can be more accurate -* add stereo output to ym2612 -* you need to scale the output sample to be +/- 1.0 instead of 0-1.0 -* fix ym2612 sound generation (no drums/bass, no LFO, etc) - * what if, to allow a device to have multiple steppable functions, you pass the system in, or otherwise provide some mechanism for each device to create sub devices which are scheduled independently * should it be possible to reschedule multiple events at different intervals to reduce the times a given step function is called? Some have @@ -42,13 +10,13 @@ the cost of having more events on the queue when re-scheduling. There needs to be a mechanism to avoid the event queue ballooning due to an error * can you somehow make devices have two step functions for running things at different times? (I'm thinking ym2612 audio gen vs timers) +* address repeater on ym2612 doesn't seem to work the same, when it's on the 68000 device. The Z80 device doesn't have an affect, but maybe it's not being used +* make it possible to compile without audio support (minifb frontend requires it atm) +* can you make it so you don't need borrow_mut() so much? -* for some unknown reason, the js-based updater works much better than the rust based one, but the rust based one just goes back to - a fixed time per loop instead of trying to speed up -* can you refactor the update timeout to put it in rust? Would that make it faster? (the tricky part is the closure) -* make Signal directional, by making SignalDriver and SignalInput or SignalReceiver -* clean up pixels frontend + +* make the keys easier to config... * modify cpal code to skip audio until caught up * AudioFrame (and possibly the mixer and source) should be moved to the core, it should probably have the sample rate @@ -56,42 +24,51 @@ * can you eliminate the source-to-mixer queues? * add audio support to the console, but it needs to be conditionally compilable so that audio can be disabled (computie doesn't need it, only genesis) - * the interrupt controller stuff is really not good. It should be more like busport, and connected to a device at startup (eg. create interrupt controller, then create objects that use that controller and pass in values, maybe an option so that the controller doesn't have to be hooked up, meaning hardware interrupts would not be used. -* I'm kind of thinking of packaging things a bit differently, like using a tuple struct for the rc refcell - transmutable abstraction, so that you can avoid the need for explicit borrows -* add rust runtime checks for math to look for overflow errors -* double check the functioning of the banked areas and register settings for Z80 coprocessor -* add opentelemetry if it can be wasm compatible, or some kind of timing for giving an average framerate -* improve performance +* I like making address adapters like this (below) +* you could have busport take a closure or something which translates the address, and returns an error that will be passed up if it occurs + in order to implement the correct behaviour for address exceptions in 68k, transparently -* can you make the frontend more adaptive to the input that the devices are using -* maybe I should make ClockDuration use picos as the base instead, and use u64 since that gives like 212 days or something instead of 5h - and should prevent split nanoseconds which is the main concern -* make the keys easier to config... +* you could possibly make a Z80MemoryPort type that wraps the BusPort type and which impls Addressable, which can be passed into the decoder + to auto-insert things like the refresh counter, as well as the record all bus timings whenever any mem access is performed +* should you make Address a newtype and add From impls for each type of numeric, and add utils to wrap address at certain boundaries and such +* should you make a means of storing different kinds of buses? +* should you make buses hide their RcRefCell? + +* sound doesn't work on a lot of games... is it a problem with the Z80 accessing the YM2612, or the lack of YM timers? or something else? +* make the ym generate audio in sync so the DAC timings can be more accurate +* add stereo output to ym2612 +* you need to scale the output sample to be +/- 1.0 instead of 0-1.0 +* fix ym2612 sound generation (no bass, no LFO, etc) + +* for some unknown reason, the js-based updater works much better than the rust based one, but the rust based one just goes back to + a fixed time per loop instead of trying to speed up +* clean up pixels frontend * add doc strings everywhere * get rustfmt, rustdoc, and clippy working in some kind of semi-automatic fashion +* you really need a full web-based debugger +* test m68k cycle timing again -* can you make the debugger more accessible, so a web interface could access the data and display it, in light of the fact that println isn't available in wasm - Web Assembly: - * can you make the web interface nicer with like... a picture of a genesis or something -* make it possible to compile without audio support (minifb frontend requires it atm) + * can you make the web interface nicer with like... a picture of a genesis or something System/Traits: + * maybe I should make ClockDuration use picos as the base instead, and use u64 since that gives like 212 days or something instead of 5h + and should prevent split nanoseconds which is the main concern + + * add opentelemetry if it can be wasm compatible, or some kind of timing for giving an average framerate * can you make the connections between things (like memory adapters), be expressed in a way that's more similar to the electrical design? like specifying that address pins 10-7 should be ignored/unconnected, pin 11 will connect to "chip select", etc - * should you add a unique ID to devices, such that they can be indexed, and their step functions can reset the next_run count and run them immediately * should you simulate bus arbitration? * interrupts could be done in a better way @@ -105,13 +82,12 @@ System/Traits: Debugger: + * the debug dump things should not used the clocked addressing, but use a debugging mode thing of some kind so as not to influence the sim state + * i need a way to debug only the cpu and not the coprocessor, but that's tricky without a way to id or compare Transmutables * add a way to delete a watcher - * can you improve how the watcher implementation in the Bus works, instead of setting a flag and then checking it every cycle, pass in the System to Addressable?? - * can you use the breakpoint address parser in other commands? * get stack tracing working again, but can you do it with just data? * how can you improve the debugger? - * the command line definitely needs to be fixed so it prints the prompt correctly * debugger could maybe even allows arrows left/right for editing, and up/down for history @@ -136,6 +112,9 @@ Macintosh: 68000: + * for 68k impl, I want to make some kind of memory transaction object that does everything in a contained but logical way, including handling exception + information needed about the last access, and adjusting the pre/post inc/dec + * unimplemented: BFFFO, BFINS, NBCD, RTD * >=MC68020 undecoded & unimplemented: BKPT, CALLM, CAS, CAS2, CHK2, CMP2, RTM, PACK, TRAPcc, UNPK