mirror of
https://github.com/transistorfet/moa.git
synced 2024-12-03 07:49:17 +00:00
Changed Error type into an enum
This commit is contained in:
parent
e3861f33b5
commit
83307d5b33
@ -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)]
|
||||
|
@ -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
|
||||
|
@ -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(),
|
||||
}
|
||||
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",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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};
|
||||
|
@ -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
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -20,7 +20,7 @@ fn main() {
|
||||
println!("");
|
||||
},
|
||||
Err(err) => {
|
||||
println!("{}", err.msg);
|
||||
println!("{:?}", err);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -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());
|
||||
},
|
||||
_ => { },
|
||||
|
@ -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)
|
||||
},
|
||||
|
@ -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),
|
||||
|
@ -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) => {
|
||||
|
@ -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),
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()));
|
||||
|
@ -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)
|
||||
},
|
||||
|
@ -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)
|
||||
},
|
||||
|
11
todo.txt
11
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
|
||||
|
Loading…
Reference in New Issue
Block a user