diff --git a/emulator/core/src/debugger.rs b/emulator/core/src/debugger.rs index 5b7c39a..4720fcf 100644 --- a/emulator/core/src/debugger.rs +++ b/emulator/core/src/debugger.rs @@ -1,7 +1,5 @@ -use crate::error::Error; -use crate::system::System; -use crate::devices::{Address, Addressable}; +use crate::{Error, System, Address, Addressable}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/emulator/core/src/devices.rs b/emulator/core/src/devices.rs index ae20b97..a76bd20 100644 --- a/emulator/core/src/devices.rs +++ b/emulator/core/src/devices.rs @@ -3,9 +3,7 @@ use std::rc::Rc; use std::cell::{RefCell, RefMut, BorrowMutError}; use std::sync::atomic::{AtomicUsize, Ordering}; -use crate::error::Error; -use crate::system::System; -use crate::clock::{ClockTime, ClockDuration}; +use crate::{Error, System, ClockTime, ClockDuration}; /// A universal memory address used by the Addressable trait diff --git a/emulator/core/src/error.rs b/emulator/core/src/error.rs index fb709ba..6b6c28b 100644 --- a/emulator/core/src/error.rs +++ b/emulator/core/src/error.rs @@ -1,24 +1,16 @@ -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum ErrorType { - Assertion, - Emulator(EmulatorErrorKind), - Processor, - Breakpoint, -} - #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum EmulatorErrorKind { Misc, MemoryAlignment, } - -#[derive(Debug)] -pub struct Error { - pub err: ErrorType, - pub native: u32, - pub msg: String, +#[derive(Clone, Debug)] +pub enum Error { + Assertion(String), + Breakpoint(String), + Emulator(EmulatorErrorKind, String), + Processor(u32), } impl Error { @@ -26,56 +18,41 @@ impl Error { where S: Into, { - Error { - err: ErrorType::Emulator(EmulatorErrorKind::Misc), - native: 0, - msg: msg.into(), - } + Error::Emulator(EmulatorErrorKind::Misc, msg.into()) } pub fn emulator(kind: EmulatorErrorKind, msg: S) -> Error where S: Into, { - Error { - err: ErrorType::Emulator(kind), - native: 0, - msg: msg.into(), - } + Error::Emulator(kind, msg.into()) } pub fn processor(native: u32) -> Error { - Error { - err: ErrorType::Processor, - native, - msg: "".to_string(), - } + Error::Processor(native) } pub fn breakpoint(msg: S) -> Error where S: Into, { - Error { - err: ErrorType::Breakpoint, - native: 0, - msg: msg.into(), - } + Error::Breakpoint(msg.into()) } pub fn assertion(msg: S) -> Error where S: Into, { - Error { - err: ErrorType::Assertion, - native: 0, - msg: msg.into(), - } + Error::Assertion(msg.into()) } - pub fn is_processor(&self, native: u32) -> bool { - self.err == ErrorType::Processor && self.native == native + pub fn msg(&self) -> &str { + match self { + Error::Assertion(msg) | + Error::Breakpoint(msg) | + Error::Emulator(_, msg) => msg.as_str(), + Error::Processor(_) => "native exception", + } } } diff --git a/emulator/core/src/lib.rs b/emulator/core/src/lib.rs index 5c0c2fe..ba8a434 100644 --- a/emulator/core/src/lib.rs +++ b/emulator/core/src/lib.rs @@ -18,7 +18,7 @@ pub use crate::clock::{ClockTime, ClockDuration, Frequency}; pub use crate::debugger::{DebugControl, Debugger}; 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, ErrorType}; +pub use crate::error::Error; pub use crate::interrupts::InterruptController; pub use crate::memory::{MemoryBlock, AddressRightShifter, AddressRepeater, Bus, BusPort, dump_slice}; pub use crate::signals::{Observable, Signal, EdgeSignal, ObservableSignal, ObservableEdgeSignal}; diff --git a/emulator/core/src/signals.rs b/emulator/core/src/signals.rs index a465f1d..f083a9d 100644 --- a/emulator/core/src/signals.rs +++ b/emulator/core/src/signals.rs @@ -1,6 +1,8 @@ use std::cell::{Cell, RefCell, RefMut}; use std::rc::Rc; +use crate::ClockTime; + pub trait Observable { fn set_observer(&self, f: F) where @@ -120,3 +122,17 @@ impl Observable for ObservableEdgeSignal { self.0.notify() } } + + +pub trait SignalReceiver { + fn get_next(&self) -> (ClockTime, T); + fn get_at(clock: ClockTime) -> T; +} + +pub trait SignalDriver { + fn set_at(clock: ClockTime, value: T); +} + + +//pub struct LevelTriggeredOutput + diff --git a/emulator/core/src/system.rs b/emulator/core/src/system.rs index 261be13..3b3659d 100644 --- a/emulator/core/src/system.rs +++ b/emulator/core/src/system.rs @@ -3,12 +3,7 @@ use std::rc::Rc; use std::cell::{RefCell, RefMut}; use std::collections::HashMap; -use crate::memory::Bus; -use crate::signals::EdgeSignal; -use crate::error::{Error, ErrorType}; -use crate::interrupts::InterruptController; -use crate::clock::{ClockTime, ClockDuration}; -use crate::devices::{Address, Device}; +use crate::{Bus, EdgeSignal, Error, InterruptController, ClockTime, ClockDuration, Address, Device}; pub struct System { @@ -96,10 +91,11 @@ impl System { result } + /// Step the simulation one event exactly pub fn step(&mut self) -> Result<(), Error> { match self.process_one_event() { Ok(()) => {}, - Err(err) if err.err == ErrorType::Breakpoint => { + Err(err @ Error::Breakpoint(_)) => { return Err(err); }, Err(err) => { @@ -111,6 +107,7 @@ impl System { Ok(()) } + /// Step through the simulation until the next event is for the given device pub fn step_until_device(&mut self, device: Device) -> Result<(), Error> { loop { self.step()?; @@ -122,6 +119,7 @@ impl System { Ok(()) } + /// Step through the simulation until the next event scheduled is for a debuggable device pub fn step_until_debuggable(&mut self) -> Result<(), Error> { loop { self.step()?; @@ -133,6 +131,7 @@ impl System { Ok(()) } + /// Run the simulation until the given simulation clock time has been reached pub fn run_until_clock(&mut self, clock: ClockTime) -> Result<(), Error> { while self.clock < clock { self.step()?; @@ -140,6 +139,7 @@ impl System { Ok(()) } + /// Run the simulation for `elapsed` amount of simulation time pub fn run_for_duration(&mut self, elapsed: ClockDuration) -> Result<(), Error> { let target = self.clock + elapsed; @@ -149,23 +149,11 @@ impl System { Ok(()) } + /// Run the simulation forever, or until there is an error pub fn run_forever(&mut self) -> Result<(), Error> { self.run_until_clock(ClockTime::FOREVER) } - // TODO rename this run_until_signal, and make it take a signal as argument - pub fn run_until_break(&mut self) -> Result<(), Error> { - let mut signal = match &self.break_signal { - Some(signal) => signal.clone(), - None => return Ok(()), - }; - - while !signal.get() { - self.step()?; - } - Ok(()) - } - pub fn exit_error(&mut self) { for (_, dev) in self.devices.iter() { if let Some(dev) = dev.borrow_mut().as_steppable() { diff --git a/emulator/cpus/m68k/src/bin/m68kas.rs b/emulator/cpus/m68k/src/bin/m68kas.rs index c77b3de..9cb662c 100644 --- a/emulator/cpus/m68k/src/bin/m68kas.rs +++ b/emulator/cpus/m68k/src/bin/m68kas.rs @@ -20,7 +20,7 @@ fn main() { println!(""); }, Err(err) => { - println!("{}", err.msg); + println!("{:?}", err); }, }; } diff --git a/emulator/cpus/m68k/src/decode.rs b/emulator/cpus/m68k/src/decode.rs index 6a603df..0d087fd 100644 --- a/emulator/cpus/m68k/src/decode.rs +++ b/emulator/cpus/m68k/src/decode.rs @@ -813,7 +813,7 @@ impl M68kDecoder { Err(err) => { println!("{:?}", err); match err { - Error { native, .. } if native == Exceptions::IllegalInstruction as u32 => { + Error::Processor(native) if native == Exceptions::IllegalInstruction as u32 => { println!(" at {:08x}: {:04x}", self.start, memory.port.read_beu16(memory.current_clock, self.start as Address).unwrap()); }, _ => { }, diff --git a/emulator/cpus/m68k/src/execute.rs b/emulator/cpus/m68k/src/execute.rs index a7ebdaf..4770e48 100644 --- a/emulator/cpus/m68k/src/execute.rs +++ b/emulator/cpus/m68k/src/execute.rs @@ -1,6 +1,6 @@ use moa_core::debug; -use moa_core::{System, Error, ErrorType, ClockTime, ClockDuration, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable}; +use moa_core::{System, Error, ClockTime, ClockDuration, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable}; use crate::state::{M68k, M68kType, ClockCycles, Status, Flags, Exceptions, InterruptPriority}; use crate::memory::{MemType, MemAccess}; @@ -68,7 +68,7 @@ impl M68k { Status::Running => { match self.cycle_one(system) { Ok(diff) => Ok(diff), - Err(Error { err: ErrorType::Processor, native, .. }) => { + Err(Error::Processor(native)) => { self.exception(native as u8, false)?; Ok(4) }, diff --git a/emulator/cpus/z80/src/execute.rs b/emulator/cpus/z80/src/execute.rs index 8eed9cd..b552d2c 100644 --- a/emulator/cpus/z80/src/execute.rs +++ b/emulator/cpus/z80/src/execute.rs @@ -1,5 +1,5 @@ -use moa_core::{System, Error, ErrorType, ClockTime, ClockDuration, Address, Steppable, Addressable, Interruptable, Debuggable, Transmutable, read_beu16, write_beu16}; +use moa_core::{System, Error, ClockTime, ClockDuration, 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::state::{Z80, Status, Flags}; @@ -78,7 +78,7 @@ impl Z80 { Status::Running => { match self.cycle_one() { Ok(clocks) => Ok(clocks), - Err(Error { err: ErrorType::Processor, .. }) => { + Err(Error::Processor(_)) => { Ok(4) }, Err(err) => Err(err), diff --git a/emulator/frontends/console/src/lib.rs b/emulator/frontends/console/src/lib.rs index 98bd974..1f2cb21 100644 --- a/emulator/frontends/console/src/lib.rs +++ b/emulator/frontends/console/src/lib.rs @@ -2,7 +2,7 @@ use clap::{Command, Arg, ArgAction, ArgMatches}; use std::io::{self, Write}; -use moa_core::{Error, ErrorType, System, ClockDuration, DebugControl, Debugger}; +use moa_core::{Error, System, ClockDuration, DebugControl, Debugger}; use moa_core::host::{Host, Tty, ControllerEvent, Audio, DummyAudio, FrameReceiver, EventSender}; pub struct ConsoleFrontend; @@ -84,7 +84,7 @@ impl ConsoleFrontend { Ok(DebugControl::Exit) => break, Ok(_) => {}, Err(err) => { - println!("Error: {}", err.msg); + println!("Error: {:?}", err); }, } } @@ -92,7 +92,7 @@ impl ConsoleFrontend { match system.run_for_duration(ClockDuration::MAX - system.clock.as_duration()) { Ok(()) => {}, - Err(err) if err.err == ErrorType::Breakpoint => { + Err(Error::Breakpoint(_)) => { run_debugger = true; }, Err(err) => { diff --git a/emulator/frontends/minifb/src/lib.rs b/emulator/frontends/minifb/src/lib.rs index ea72e4d..3bc97d9 100644 --- a/emulator/frontends/minifb/src/lib.rs +++ b/emulator/frontends/minifb/src/lib.rs @@ -7,7 +7,7 @@ use std::time::{Duration, Instant}; use minifb::{self, Key, MouseMode, MouseButton}; use clap::{Command, Arg, ArgAction, ArgMatches}; -use moa_core::{System, Error, ErrorType, ClockDuration, Device, Debugger, DebugControl}; +use moa_core::{System, Error, ClockDuration, Device, Debugger, DebugControl}; use moa_core::host::{Host, Audio, KeyEvent, MouseEvent, MouseState, ControllerDevice, ControllerEvent, EventSender, PixelEncoding, Frame, FrameReceiver}; use moa_common::{AudioMixer, AudioSource}; @@ -281,7 +281,7 @@ impl MiniFrontend { }, Ok(_) => {}, Err(err) => { - println!("Error: {}", err.msg); + println!("Error: {:?}", err); }, } } @@ -296,7 +296,7 @@ impl MiniFrontend { //system.run_for(nanoseconds_per_frame).unwrap(); match system.run_for_duration(ClockDuration::from_nanos((frame_time.as_nanos() as f32 * speed) as u64)) { Ok(()) => {}, - Err(err) if err.err == ErrorType::Breakpoint => { + Err(Error::Breakpoint(_)) => { run_debugger = true; }, Err(err) => panic!("{:?}", err), diff --git a/emulator/systems/genesis/src/peripherals/ym7101.rs b/emulator/systems/genesis/src/peripherals/ym7101.rs index 389cc3d..b7405bb 100644 --- a/emulator/systems/genesis/src/peripherals/ym7101.rs +++ b/emulator/systems/genesis/src/peripherals/ym7101.rs @@ -690,7 +690,7 @@ impl Steppable for Ym7101 { self.sender.add(system.clock, frame); } - self.frame_complete.signal(); + self.vsync_interrupt.signal(); } if self.state.v_clock > 16_630_000 { self.state.v_clock -= 16_630_000; @@ -712,7 +712,7 @@ pub struct Ym7101 { sn_sound: Device, pub external_interrupt: Signal, - pub frame_complete: EdgeSignal, + pub vsync_interrupt: EdgeSignal, } impl Ym7101 { @@ -725,7 +725,7 @@ impl Ym7101 { state: Ym7101State::default(), sn_sound, external_interrupt, - frame_complete: EdgeSignal::default(), + vsync_interrupt: EdgeSignal::default(), } } diff --git a/emulator/systems/genesis/src/system.rs b/emulator/systems/genesis/src/system.rs index a838492..cece9fa 100644 --- a/emulator/systems/genesis/src/system.rs +++ b/emulator/systems/genesis/src/system.rs @@ -105,7 +105,6 @@ pub fn build_genesis(host: &mut H, mut options: SegaGenesisOptions) -> system.add_addressable_device(0x00a11000, Device::new(coproc)).unwrap(); let vdp = Ym7101::new(host, interrupt, coproc_sn_sound); - system.break_signal = Some(vdp.frame_complete.clone()); 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())); diff --git a/tests/harte_tests/src/main.rs b/tests/harte_tests/src/main.rs index 564aa59..a2a1785 100644 --- a/tests/harte_tests/src/main.rs +++ b/tests/harte_tests/src/main.rs @@ -271,7 +271,7 @@ fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> { initial_cpu.dump_state(); cpu.dump_state(); } - println!("FAILED: {}", err.msg); + println!("FAILED: {:?}", err); } Err(err) }, diff --git a/tests/rad_tests/src/main.rs b/tests/rad_tests/src/main.rs index 0c8ef6e..68d1e6b 100644 --- a/tests/rad_tests/src/main.rs +++ b/tests/rad_tests/src/main.rs @@ -308,7 +308,7 @@ fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> { initial_cpu.dump_state(system.clock); cpu.dump_state(system.clock); } - println!("FAILED: {}", err.msg); + println!("FAILED: {:?}", err); } Err(err) }, diff --git a/todo.txt b/todo.txt index 8a15374..4d58b0f 100644 --- a/todo.txt +++ b/todo.txt @@ -1,20 +1,11 @@ -* rename System::run_until_break into run_until_signal, and make it take a signal as argument +* the genesis coprocessor stuff will be a good reference point for things that make multiple devices, and how to add them correctly to the system -* make errors be enums to make for easier matching * test m68k cycle timing again -* fix tests * you really need a full web-based debugger - * breakpoints should be in the CPU implementation, and get checked before an instruction starts executing - * there should be a list of "debuggable" objects in the system to make it easier to list them and iterate over them - * a breakpoint should escape the system and return to the frontend, which should handle everything (not inline because the frontend won't update) -* can you make the debugger workable in the web ui in some way? So you can have a debug window open while playing the game or something -* the way you're doing debugging is so bad, and something's broken with the Z80 * 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 -* there needs to be a better way of finding devices, and getting names/refs out of them -* debugger should return a breakpoint error to the frontend, so that the frontend still runs, instead of suspending the current execution * 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