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::system::System;
use crate::devices::{Address, Addressable};
use crate::{Error, System, Address, Addressable};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]

View File

@ -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

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)]
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<String>,
{
Error {
err: ErrorType::Emulator(EmulatorErrorKind::Misc),
native: 0,
msg: msg.into(),
}
Error::Emulator(EmulatorErrorKind::Misc, msg.into())
}
pub fn emulator<S>(kind: EmulatorErrorKind, msg: S) -> Error
where
S: Into<String>,
{
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<S>(msg: S) -> Error
where
S: Into<String>,
{
Error {
err: ErrorType::Breakpoint,
native: 0,
msg: msg.into(),
}
Error::Breakpoint(msg.into())
}
pub fn assertion<S>(msg: S) -> Error
where
S: Into<String>,
{
Error {
err: ErrorType::Assertion,
native: 0,
msg: msg.into(),
}
}
pub fn is_processor(&self, native: u32) -> bool {
self.err == ErrorType::Processor && self.native == native
Error::Assertion(msg.into())
}
pub fn msg(&self) -> &str {
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::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};

View File

@ -1,6 +1,8 @@
use std::cell::{Cell, RefCell, RefMut};
use std::rc::Rc;
use crate::ClockTime;
pub trait Observable<T> {
fn set_observer<F>(&self, f: F)
where
@ -120,3 +122,17 @@ impl Observable<bool> for ObservableEdgeSignal {
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::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() {

View File

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

View File

@ -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());
},
_ => { },

View File

@ -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)
},

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::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),

View File

@ -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) => {

View File

@ -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),

View File

@ -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<bool>,
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(),
}
}

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();
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()));

View File

@ -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)
},

View File

@ -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)
},

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
* 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