Changed Error type into an enum

This commit is contained in:
transistor 2023-06-10 19:29:54 -07:00
parent e3861f33b5
commit 83307d5b33
17 changed files with 63 additions and 96 deletions

View File

@ -1,7 +1,5 @@
use crate::error::Error; use crate::{Error, System, Address, Addressable};
use crate::system::System;
use crate::devices::{Address, Addressable};
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]

View File

@ -3,9 +3,7 @@ use std::rc::Rc;
use std::cell::{RefCell, RefMut, BorrowMutError}; use std::cell::{RefCell, RefMut, BorrowMutError};
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use crate::error::Error; use crate::{Error, System, ClockTime, ClockDuration};
use crate::system::System;
use crate::clock::{ClockTime, ClockDuration};
/// A universal memory address used by the Addressable trait /// A universal memory address used by the Addressable trait

View File

@ -1,24 +1,16 @@
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ErrorType {
Assertion,
Emulator(EmulatorErrorKind),
Processor,
Breakpoint,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum EmulatorErrorKind { pub enum EmulatorErrorKind {
Misc, Misc,
MemoryAlignment, MemoryAlignment,
} }
#[derive(Clone, Debug)]
#[derive(Debug)] pub enum Error {
pub struct Error { Assertion(String),
pub err: ErrorType, Breakpoint(String),
pub native: u32, Emulator(EmulatorErrorKind, String),
pub msg: String, Processor(u32),
} }
impl Error { impl Error {
@ -26,56 +18,41 @@ impl Error {
where where
S: Into<String>, S: Into<String>,
{ {
Error { Error::Emulator(EmulatorErrorKind::Misc, msg.into())
err: ErrorType::Emulator(EmulatorErrorKind::Misc),
native: 0,
msg: msg.into(),
}
} }
pub fn emulator<S>(kind: EmulatorErrorKind, msg: S) -> Error pub fn emulator<S>(kind: EmulatorErrorKind, msg: S) -> Error
where where
S: Into<String>, S: Into<String>,
{ {
Error { Error::Emulator(kind, msg.into())
err: ErrorType::Emulator(kind),
native: 0,
msg: msg.into(),
}
} }
pub fn processor(native: u32) -> Error { pub fn processor(native: u32) -> Error {
Error { Error::Processor(native)
err: ErrorType::Processor,
native,
msg: "".to_string(),
}
} }
pub fn breakpoint<S>(msg: S) -> Error pub fn breakpoint<S>(msg: S) -> Error
where where
S: Into<String>, S: Into<String>,
{ {
Error { Error::Breakpoint(msg.into())
err: ErrorType::Breakpoint,
native: 0,
msg: msg.into(),
}
} }
pub fn assertion<S>(msg: S) -> Error pub fn assertion<S>(msg: S) -> Error
where where
S: Into<String>, S: Into<String>,
{ {
Error { Error::Assertion(msg.into())
err: ErrorType::Assertion,
native: 0,
msg: msg.into(),
}
} }
pub fn is_processor(&self, native: u32) -> bool { pub fn msg(&self) -> &str {
self.err == ErrorType::Processor && self.native == native match self {
Error::Assertion(msg) |
Error::Breakpoint(msg) |
Error::Emulator(_, msg) => msg.as_str(),
Error::Processor(_) => "native exception",
}
} }
} }

View File

@ -18,7 +18,7 @@ pub use crate::clock::{ClockTime, ClockDuration, Frequency};
pub use crate::debugger::{DebugControl, Debugger}; pub use crate::debugger::{DebugControl, Debugger};
pub use crate::devices::{Address, Addressable, Steppable, Interruptable, Debuggable, Inspectable, Transmutable, TransmutableBox, Device}; 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::{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::interrupts::InterruptController;
pub use crate::memory::{MemoryBlock, AddressRightShifter, AddressRepeater, Bus, BusPort, dump_slice}; pub use crate::memory::{MemoryBlock, AddressRightShifter, AddressRepeater, Bus, BusPort, dump_slice};
pub use crate::signals::{Observable, Signal, EdgeSignal, ObservableSignal, ObservableEdgeSignal}; pub use crate::signals::{Observable, Signal, EdgeSignal, ObservableSignal, ObservableEdgeSignal};

View File

@ -1,6 +1,8 @@
use std::cell::{Cell, RefCell, RefMut}; use std::cell::{Cell, RefCell, RefMut};
use std::rc::Rc; use std::rc::Rc;
use crate::ClockTime;
pub trait Observable<T> { pub trait Observable<T> {
fn set_observer<F>(&self, f: F) fn set_observer<F>(&self, f: F)
where where
@ -120,3 +122,17 @@ impl Observable<bool> for ObservableEdgeSignal {
self.0.notify() self.0.notify()
} }
} }
pub trait SignalReceiver<T> {
fn get_next(&self) -> (ClockTime, T);
fn get_at(clock: ClockTime) -> T;
}
pub trait SignalDriver<T> {
fn set_at(clock: ClockTime, value: T);
}
//pub struct LevelTriggeredOutput

View File

@ -3,12 +3,7 @@ use std::rc::Rc;
use std::cell::{RefCell, RefMut}; use std::cell::{RefCell, RefMut};
use std::collections::HashMap; use std::collections::HashMap;
use crate::memory::Bus; use crate::{Bus, EdgeSignal, Error, InterruptController, ClockTime, ClockDuration, Address, Device};
use crate::signals::EdgeSignal;
use crate::error::{Error, ErrorType};
use crate::interrupts::InterruptController;
use crate::clock::{ClockTime, ClockDuration};
use crate::devices::{Address, Device};
pub struct System { pub struct System {
@ -96,10 +91,11 @@ impl System {
result result
} }
/// Step the simulation one event exactly
pub fn step(&mut self) -> Result<(), Error> { pub fn step(&mut self) -> Result<(), Error> {
match self.process_one_event() { match self.process_one_event() {
Ok(()) => {}, Ok(()) => {},
Err(err) if err.err == ErrorType::Breakpoint => { Err(err @ Error::Breakpoint(_)) => {
return Err(err); return Err(err);
}, },
Err(err) => { Err(err) => {
@ -111,6 +107,7 @@ impl System {
Ok(()) 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> { pub fn step_until_device(&mut self, device: Device) -> Result<(), Error> {
loop { loop {
self.step()?; self.step()?;
@ -122,6 +119,7 @@ impl System {
Ok(()) Ok(())
} }
/// Step through the simulation until the next event scheduled is for a debuggable device
pub fn step_until_debuggable(&mut self) -> Result<(), Error> { pub fn step_until_debuggable(&mut self) -> Result<(), Error> {
loop { loop {
self.step()?; self.step()?;
@ -133,6 +131,7 @@ impl System {
Ok(()) Ok(())
} }
/// Run the simulation until the given simulation clock time has been reached
pub fn run_until_clock(&mut self, clock: ClockTime) -> Result<(), Error> { pub fn run_until_clock(&mut self, clock: ClockTime) -> Result<(), Error> {
while self.clock < clock { while self.clock < clock {
self.step()?; self.step()?;
@ -140,6 +139,7 @@ impl System {
Ok(()) Ok(())
} }
/// Run the simulation for `elapsed` amount of simulation time
pub fn run_for_duration(&mut self, elapsed: ClockDuration) -> Result<(), Error> { pub fn run_for_duration(&mut self, elapsed: ClockDuration) -> Result<(), Error> {
let target = self.clock + elapsed; let target = self.clock + elapsed;
@ -149,23 +149,11 @@ impl System {
Ok(()) Ok(())
} }
/// Run the simulation forever, or until there is an error
pub fn run_forever(&mut self) -> Result<(), Error> { pub fn run_forever(&mut self) -> Result<(), Error> {
self.run_until_clock(ClockTime::FOREVER) 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) { pub fn exit_error(&mut self) {
for (_, dev) in self.devices.iter() { for (_, dev) in self.devices.iter() {
if let Some(dev) = dev.borrow_mut().as_steppable() { if let Some(dev) = dev.borrow_mut().as_steppable() {

View File

@ -20,7 +20,7 @@ fn main() {
println!(""); println!("");
}, },
Err(err) => { Err(err) => {
println!("{}", err.msg); println!("{:?}", err);
}, },
}; };
} }

View File

@ -813,7 +813,7 @@ impl M68kDecoder {
Err(err) => { Err(err) => {
println!("{:?}", err); println!("{:?}", err);
match 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()); println!(" at {:08x}: {:04x}", self.start, memory.port.read_beu16(memory.current_clock, self.start as Address).unwrap());
}, },
_ => { }, _ => { },

View File

@ -1,6 +1,6 @@
use moa_core::debug; 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::state::{M68k, M68kType, ClockCycles, Status, Flags, Exceptions, InterruptPriority};
use crate::memory::{MemType, MemAccess}; use crate::memory::{MemType, MemAccess};
@ -68,7 +68,7 @@ impl M68k {
Status::Running => { Status::Running => {
match self.cycle_one(system) { match self.cycle_one(system) {
Ok(diff) => Ok(diff), Ok(diff) => Ok(diff),
Err(Error { err: ErrorType::Processor, native, .. }) => { Err(Error::Processor(native)) => {
self.exception(native as u8, false)?; self.exception(native as u8, false)?;
Ok(4) Ok(4)
}, },

View File

@ -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::instructions::{Condition, Instruction, LoadTarget, Target, Register, InterruptMode, RegisterPair, IndexRegister, SpecialRegister, IndexRegisterHalf, Size, Direction, UndocumentedCopy};
use crate::state::{Z80, Status, Flags}; use crate::state::{Z80, Status, Flags};
@ -78,7 +78,7 @@ impl Z80 {
Status::Running => { Status::Running => {
match self.cycle_one() { match self.cycle_one() {
Ok(clocks) => Ok(clocks), Ok(clocks) => Ok(clocks),
Err(Error { err: ErrorType::Processor, .. }) => { Err(Error::Processor(_)) => {
Ok(4) Ok(4)
}, },
Err(err) => Err(err), Err(err) => Err(err),

View File

@ -2,7 +2,7 @@
use clap::{Command, Arg, ArgAction, ArgMatches}; use clap::{Command, Arg, ArgAction, ArgMatches};
use std::io::{self, Write}; 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}; use moa_core::host::{Host, Tty, ControllerEvent, Audio, DummyAudio, FrameReceiver, EventSender};
pub struct ConsoleFrontend; pub struct ConsoleFrontend;
@ -84,7 +84,7 @@ impl ConsoleFrontend {
Ok(DebugControl::Exit) => break, Ok(DebugControl::Exit) => break,
Ok(_) => {}, Ok(_) => {},
Err(err) => { 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()) { match system.run_for_duration(ClockDuration::MAX - system.clock.as_duration()) {
Ok(()) => {}, Ok(()) => {},
Err(err) if err.err == ErrorType::Breakpoint => { Err(Error::Breakpoint(_)) => {
run_debugger = true; run_debugger = true;
}, },
Err(err) => { Err(err) => {

View File

@ -7,7 +7,7 @@ use std::time::{Duration, Instant};
use minifb::{self, Key, MouseMode, MouseButton}; use minifb::{self, Key, MouseMode, MouseButton};
use clap::{Command, Arg, ArgAction, ArgMatches}; 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_core::host::{Host, Audio, KeyEvent, MouseEvent, MouseState, ControllerDevice, ControllerEvent, EventSender, PixelEncoding, Frame, FrameReceiver};
use moa_common::{AudioMixer, AudioSource}; use moa_common::{AudioMixer, AudioSource};
@ -281,7 +281,7 @@ impl MiniFrontend {
}, },
Ok(_) => {}, Ok(_) => {},
Err(err) => { Err(err) => {
println!("Error: {}", err.msg); println!("Error: {:?}", err);
}, },
} }
} }
@ -296,7 +296,7 @@ impl MiniFrontend {
//system.run_for(nanoseconds_per_frame).unwrap(); //system.run_for(nanoseconds_per_frame).unwrap();
match system.run_for_duration(ClockDuration::from_nanos((frame_time.as_nanos() as f32 * speed) as u64)) { match system.run_for_duration(ClockDuration::from_nanos((frame_time.as_nanos() as f32 * speed) as u64)) {
Ok(()) => {}, Ok(()) => {},
Err(err) if err.err == ErrorType::Breakpoint => { Err(Error::Breakpoint(_)) => {
run_debugger = true; run_debugger = true;
}, },
Err(err) => panic!("{:?}", err), Err(err) => panic!("{:?}", err),

View File

@ -690,7 +690,7 @@ impl Steppable for Ym7101 {
self.sender.add(system.clock, frame); self.sender.add(system.clock, frame);
} }
self.frame_complete.signal(); self.vsync_interrupt.signal();
} }
if self.state.v_clock > 16_630_000 { if self.state.v_clock > 16_630_000 {
self.state.v_clock -= 16_630_000; self.state.v_clock -= 16_630_000;
@ -712,7 +712,7 @@ pub struct Ym7101 {
sn_sound: Device, sn_sound: Device,
pub external_interrupt: Signal<bool>, pub external_interrupt: Signal<bool>,
pub frame_complete: EdgeSignal, pub vsync_interrupt: EdgeSignal,
} }
impl Ym7101 { impl Ym7101 {
@ -725,7 +725,7 @@ impl Ym7101 {
state: Ym7101State::default(), state: Ym7101State::default(),
sn_sound, sn_sound,
external_interrupt, external_interrupt,
frame_complete: EdgeSignal::default(), vsync_interrupt: EdgeSignal::default(),
} }
} }

View File

@ -105,7 +105,6 @@ pub fn build_genesis<H: Host>(host: &mut H, mut options: SegaGenesisOptions) ->
system.add_addressable_device(0x00a11000, Device::new(coproc)).unwrap(); system.add_addressable_device(0x00a11000, Device::new(coproc)).unwrap();
let vdp = Ym7101::new(host, interrupt, coproc_sn_sound); 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(); 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::new(M68kType::MC68000, Frequency::from_hz(7_670_454), BusPort::new(0, 24, 16, system.bus.clone()));

View File

@ -271,7 +271,7 @@ fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> {
initial_cpu.dump_state(); initial_cpu.dump_state();
cpu.dump_state(); cpu.dump_state();
} }
println!("FAILED: {}", err.msg); println!("FAILED: {:?}", err);
} }
Err(err) Err(err)
}, },

View File

@ -308,7 +308,7 @@ fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> {
initial_cpu.dump_state(system.clock); initial_cpu.dump_state(system.clock);
cpu.dump_state(system.clock); cpu.dump_state(system.clock);
} }
println!("FAILED: {}", err.msg); println!("FAILED: {:?}", err);
} }
Err(err) Err(err)
}, },

View File

@ -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 * test m68k cycle timing again
* fix tests
* you really need a full web-based debugger * 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 * 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 * 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