Added new clock types similar to Duration
This commit is contained in:
parent
f298d1b341
commit
07a675fab5
|
@ -6,6 +6,7 @@ junk/
|
|||
|
||||
perf.data
|
||||
perf.data.old
|
||||
flamegraph*.svg
|
||||
|
||||
binaries/*/*.asm
|
||||
binaries/*/*.bin
|
||||
|
|
|
@ -0,0 +1,265 @@
|
|||
/// Clock time and duration types for simulation with femtosecond accurancy
|
||||
///
|
||||
|
||||
use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign};
|
||||
|
||||
/// Type to use for storing femtoseconds
|
||||
///
|
||||
/// In webassembly, using u128 results in exceedingly slow runtimes, so we use u64 instead
|
||||
/// which is enough for 5 hours of simulation time.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
type Femtos = u128;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
type Femtos = u64;
|
||||
|
||||
/// Represents a duration of time in femtoseconds
|
||||
///
|
||||
/// The `ClockDuration` type is used to represent lengths of time and is
|
||||
/// intentionally similar to `std::time::Duration`, but which records
|
||||
/// time as femtoseconds to keep accurancy when dealing with partial
|
||||
/// nanosecond clock divisons.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct ClockDuration {
|
||||
femtos: Femtos,
|
||||
}
|
||||
|
||||
impl ClockDuration {
|
||||
pub const ZERO: Self = Self::from_femtos(0);
|
||||
|
||||
pub const FEMTOS_PER_SEC: Femtos = 1_000_000_000_000_000;
|
||||
pub const FEMTOS_PER_MILLISEC: Femtos = 1_000_000_000_000;
|
||||
pub const FEMTOS_PER_MICROSEC: Femtos = 1_000_000_000;
|
||||
pub const FEMTOS_PER_NANOSEC: Femtos = 1_000_000;
|
||||
pub const FEMTOS_PER_PICOSEC: Femtos = 1_000;
|
||||
|
||||
#[inline]
|
||||
pub const fn from_secs(secs: u64) -> Self {
|
||||
Self {
|
||||
femtos: secs as Femtos * Self::FEMTOS_PER_SEC,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn from_millis(millisecs: u64) -> Self {
|
||||
Self {
|
||||
femtos: millisecs as Femtos * Self::FEMTOS_PER_MILLISEC,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn from_micros(microsecs: u64) -> Self {
|
||||
Self {
|
||||
femtos: microsecs as Femtos * Self::FEMTOS_PER_MICROSEC,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn from_nanos(nanosecs: u64) -> Self {
|
||||
Self {
|
||||
femtos: nanosecs as Femtos * Self::FEMTOS_PER_NANOSEC,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn from_picos(picosecs: u128) -> Self {
|
||||
Self {
|
||||
femtos: picosecs as Femtos * Self::FEMTOS_PER_PICOSEC,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn from_femtos(femtos: Femtos) -> Self {
|
||||
Self {
|
||||
femtos,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn as_secs(self) -> u64 {
|
||||
(self.femtos / Self::FEMTOS_PER_SEC) as u64
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn as_millis(self) -> u64 {
|
||||
(self.femtos / Self::FEMTOS_PER_MILLISEC) as u64
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn as_micros(self) -> u64 {
|
||||
(self.femtos / Self::FEMTOS_PER_MICROSEC) as u64
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn as_nanos(self) -> u64 {
|
||||
(self.femtos / Self::FEMTOS_PER_NANOSEC) as u64
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn as_picos(self) -> u128 {
|
||||
(self.femtos / Self::FEMTOS_PER_PICOSEC) as u128
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn as_femtos(self) -> Femtos {
|
||||
self.femtos
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn checked_add(self, rhs: Self) -> Option<Self> {
|
||||
self.femtos.checked_add(rhs.femtos).map(Self::from_femtos)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.femtos.checked_sub(rhs.femtos).map(Self::from_femtos)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for ClockDuration {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
self.checked_add(rhs).expect("clock duration overflow")
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for ClockDuration {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
*self = self.checked_add(rhs).expect("clock duration overflow");
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for ClockDuration {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
self.checked_sub(rhs).expect("clock duration overflow")
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign for ClockDuration {
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
*self = self.checked_sub(rhs).expect("clock duration overflow");
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<u64> for ClockDuration {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, rhs: u64) -> Self::Output {
|
||||
Self::from_femtos(self.femtos * rhs as Femtos)
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign<u64> for ClockDuration {
|
||||
fn mul_assign(&mut self, rhs: u64) {
|
||||
*self = Self::from_femtos(self.femtos * rhs as Femtos);
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<u64> for ClockDuration {
|
||||
type Output = Self;
|
||||
|
||||
fn div(self, rhs: u64) -> Self::Output {
|
||||
Self::from_femtos(self.femtos / rhs as Femtos)
|
||||
}
|
||||
}
|
||||
|
||||
impl DivAssign<u64> for ClockDuration {
|
||||
fn div_assign(&mut self, rhs: u64) {
|
||||
*self = Self::from_femtos(self.femtos / rhs as Femtos);
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<ClockDuration> for ClockDuration {
|
||||
type Output = u64;
|
||||
|
||||
fn div(self, rhs: ClockDuration) -> Self::Output {
|
||||
(self.femtos / rhs.femtos) as u64
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Represents time from the start of the simulation
|
||||
///
|
||||
/// `ClockTime` is for representing the current running clock. It uses a
|
||||
/// duration to represent the time from simulation start, and is monotonic.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct ClockTime(ClockDuration);
|
||||
|
||||
impl ClockTime {
|
||||
pub const START: Self = Self(ClockDuration::ZERO);
|
||||
|
||||
pub const fn as_duration(self) -> ClockDuration {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn duration_since(self, other: Self) -> ClockDuration {
|
||||
self.0 - other.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<ClockDuration> for ClockTime {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: ClockDuration) -> Self::Output {
|
||||
Self(self.0.add(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<ClockDuration> for ClockTime {
|
||||
fn add_assign(&mut self, rhs: ClockDuration) {
|
||||
*self = Self(self.0.add(rhs));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Frequency {
|
||||
hertz: u32,
|
||||
}
|
||||
|
||||
impl Frequency {
|
||||
#[inline]
|
||||
pub const fn from_hz(hertz: u32) -> Self {
|
||||
Self {
|
||||
hertz,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn from_khz(khz: u32) -> Self {
|
||||
Self {
|
||||
hertz: khz * 1_000,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn from_mhz(mhz: u32) -> Self {
|
||||
Self {
|
||||
hertz: mhz * 1_000_000,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn as_hz(self) -> u32 {
|
||||
self.hertz
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn as_khz(self) -> u32 {
|
||||
self.hertz / 1_000
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn as_mhz(self) -> u32 {
|
||||
self.hertz / 1_000_000
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn period_duration(self) -> ClockDuration {
|
||||
ClockDuration::from_femtos(ClockDuration::FEMTOS_PER_SEC / self.hertz as Femtos)
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@ impl Debugger {
|
|||
pub fn run_debugger(&mut self, system: &System, target: TransmutableBox) -> Result<(), Error> {
|
||||
let mut target = target.borrow_mut();
|
||||
let debug_obj = target.as_debuggable().unwrap();
|
||||
println!("@ {} ns", system.clock);
|
||||
println!("@ {} ns", system.clock.as_duration().as_nanos());
|
||||
debug_obj.print_current_step(system)?;
|
||||
|
||||
if self.trace_only {
|
||||
|
|
|
@ -4,14 +4,9 @@ use std::cell::RefCell;
|
|||
|
||||
use crate::error::Error;
|
||||
use crate::system::System;
|
||||
use crate::clock::ClockDuration;
|
||||
|
||||
|
||||
/// The time in nanoseconds that have elapsed since the start of the simulation
|
||||
pub type Clock = u64;
|
||||
|
||||
/// The time in nanoseconds until the `step()` method should be called again
|
||||
pub type ClockElapsed = u64;
|
||||
|
||||
/// A universal memory address used by the Addressable trait
|
||||
pub type Address = u64;
|
||||
|
||||
|
@ -21,7 +16,7 @@ pub type Address = u64;
|
|||
/// with any device, the `on_error()` method will be called to display any state
|
||||
/// information that might be helpful for debugging.
|
||||
pub trait Steppable {
|
||||
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error>;
|
||||
fn step(&mut self, system: &System) -> Result<ClockDuration, Error>;
|
||||
fn on_error(&mut self, _system: &System) { }
|
||||
}
|
||||
|
||||
|
@ -207,3 +202,11 @@ pub fn wrap_transmutable<T: Transmutable + 'static>(value: T) -> TransmutableBox
|
|||
Rc::new(RefCell::new(Box::new(value)))
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Device(TransmutableBox);
|
||||
|
||||
impl Device {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::host::traits::{BlitableSurface, ClockedQueue, WindowUpdater};
|
||||
use crate::Clock;
|
||||
use crate::ClockTime;
|
||||
use crate::Error;
|
||||
|
||||
pub const MASK_COLOUR: u32 = 0xFFFFFFFF;
|
||||
|
@ -92,13 +92,13 @@ impl BlitableSurface for Frame {
|
|||
}
|
||||
}
|
||||
|
||||
fn blit<B: Iterator<Item = u32>>(&mut self, pos_x: u32, pos_y: u32, mut bitmap: B, width: u32, height: u32) {
|
||||
fn blit<B: Iterator<Item = Pixel>>(&mut self, pos_x: u32, pos_y: u32, mut bitmap: B, width: u32, height: u32) {
|
||||
for y in pos_y..(pos_y + height) {
|
||||
for x in pos_x..(pos_x + width) {
|
||||
match bitmap.next().unwrap() {
|
||||
MASK_COLOUR => {}
|
||||
Pixel::Mask => {}
|
||||
value if x < self.width && y < self.height => {
|
||||
self.bitmap[(x + (y * self.width)) as usize] = value;
|
||||
self.bitmap[(x + (y * self.width)) as usize] = value.encode(self.encoding);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -106,8 +106,8 @@ impl BlitableSurface for Frame {
|
|||
}
|
||||
}
|
||||
|
||||
fn clear(&mut self, value: u32) {
|
||||
let value = if value == MASK_COLOUR { 0 } else { value };
|
||||
fn clear(&mut self, value: Pixel) {
|
||||
let value = value.encode(self.encoding);
|
||||
self.bitmap.iter_mut().for_each(|pixel| *pixel = value);
|
||||
}
|
||||
}
|
||||
|
@ -132,11 +132,11 @@ impl FrameQueue {
|
|||
*self.encoding.lock().unwrap()
|
||||
}
|
||||
|
||||
pub fn add(&self, clock: Clock, frame: Frame) {
|
||||
pub fn add(&self, clock: ClockTime, frame: Frame) {
|
||||
self.queue.push(clock, frame);
|
||||
}
|
||||
|
||||
pub fn latest(&self) -> Option<(Clock, Frame)> {
|
||||
pub fn latest(&self) -> Option<(ClockTime, Frame)> {
|
||||
self.queue.pop_latest()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
use std::collections::VecDeque;
|
||||
use std::sync::{Arc, Mutex, MutexGuard};
|
||||
|
||||
use crate::{Clock, Error};
|
||||
use crate::{ClockTime, Error};
|
||||
use crate::host::gfx::{PixelEncoding, Pixel, Frame};
|
||||
use crate::host::keys::KeyEvent;
|
||||
use crate::host::controllers::{ControllerDevice, ControllerEvent};
|
||||
|
@ -62,7 +62,7 @@ pub trait MouseUpdater: Send {
|
|||
pub trait Audio {
|
||||
fn samples_per_second(&self) -> usize;
|
||||
fn space_available(&self) -> usize;
|
||||
fn write_samples(&mut self, clock: Clock, buffer: &[f32]);
|
||||
fn write_samples(&mut self, clock: ClockTime, buffer: &[f32]);
|
||||
fn flush(&mut self);
|
||||
}
|
||||
|
||||
|
@ -70,8 +70,8 @@ pub trait BlitableSurface {
|
|||
fn set_size(&mut self, width: u32, height: u32);
|
||||
fn set_pixel(&mut self, pos_x: u32, pos_y: u32, pixel: Pixel);
|
||||
fn set_encoded_pixel(&mut self, pos_x: u32, pos_y: u32, pixel: u32);
|
||||
fn blit<B: Iterator<Item=u32>>(&mut self, pos_x: u32, pos_y: u32, bitmap: B, width: u32, height: u32);
|
||||
fn clear(&mut self, value: u32);
|
||||
fn blit<B: Iterator<Item=Pixel>>(&mut self, pos_x: u32, pos_y: u32, bitmap: B, width: u32, height: u32);
|
||||
fn clear(&mut self, value: Pixel);
|
||||
}
|
||||
|
||||
|
||||
|
@ -99,26 +99,26 @@ impl<T: Copy> HostData<T> {
|
|||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct ClockedQueue<T>(Arc<Mutex<VecDeque<(Clock, T)>>>);
|
||||
pub struct ClockedQueue<T>(Arc<Mutex<VecDeque<(ClockTime, T)>>>);
|
||||
|
||||
impl<T: Clone> ClockedQueue<T> {
|
||||
pub fn push(&self, clock: Clock, data: T) {
|
||||
pub fn push(&self, clock: ClockTime, data: T) {
|
||||
self.0.lock().unwrap().push_back((clock, data));
|
||||
}
|
||||
|
||||
pub fn pop_next(&self) -> Option<(Clock, T)> {
|
||||
pub fn pop_next(&self) -> Option<(ClockTime, T)> {
|
||||
self.0.lock().unwrap().pop_front()
|
||||
}
|
||||
|
||||
pub fn pop_latest(&self) -> Option<(Clock, T)> {
|
||||
pub fn pop_latest(&self) -> Option<(ClockTime, T)> {
|
||||
self.0.lock().unwrap().drain(..).last()
|
||||
}
|
||||
|
||||
pub fn unpop(&mut self, clock: Clock, data: T) {
|
||||
pub fn unpop(&mut self, clock: ClockTime, data: T) {
|
||||
self.0.lock().unwrap().push_front((clock, data));
|
||||
}
|
||||
|
||||
pub fn peek_clock(&self) -> Option<Clock> {
|
||||
pub fn peek_clock(&self) -> Option<ClockTime> {
|
||||
self.0.lock().unwrap().front().map(|(clock, _)| *clock)
|
||||
}
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ impl Audio for DummyAudio {
|
|||
4800
|
||||
}
|
||||
|
||||
fn write_samples(&mut self, _clock: Clock, _buffer: &[f32]) {}
|
||||
fn write_samples(&mut self, _clock: ClockTime, _buffer: &[f32]) {}
|
||||
|
||||
fn flush(&mut self) {}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#[macro_use]
|
||||
mod error;
|
||||
|
||||
mod clock;
|
||||
mod debugger;
|
||||
mod devices;
|
||||
mod interrupts;
|
||||
|
@ -14,8 +15,9 @@ pub mod timers;
|
|||
|
||||
pub use log::{trace, debug, info, warn, error};
|
||||
|
||||
pub use crate::clock::{ClockTime, ClockDuration, Frequency};
|
||||
pub use crate::debugger::Debugger;
|
||||
pub use crate::devices::{Clock, ClockElapsed, Address, Addressable, Steppable, Interruptable, Debuggable, Inspectable, Transmutable, TransmutableBox};
|
||||
pub use crate::devices::{Address, Addressable, Steppable, Interruptable, Debuggable, Inspectable, Transmutable, TransmutableBox};
|
||||
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::interrupts::InterruptController;
|
||||
|
|
|
@ -8,11 +8,12 @@ use crate::debugger::Debugger;
|
|||
use crate::signals::EdgeSignal;
|
||||
use crate::error::{Error, ErrorType};
|
||||
use crate::interrupts::InterruptController;
|
||||
use crate::devices::{Clock, ClockElapsed, Address, TransmutableBox};
|
||||
use crate::clock::{ClockTime, ClockDuration};
|
||||
use crate::devices::{Address, TransmutableBox};
|
||||
|
||||
|
||||
pub struct System {
|
||||
pub clock: Clock,
|
||||
pub clock: ClockTime,
|
||||
pub devices: HashMap<String, TransmutableBox>,
|
||||
pub event_queue: Vec<NextStep>,
|
||||
|
||||
|
@ -28,7 +29,7 @@ pub struct System {
|
|||
impl Default for System {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
clock: 0,
|
||||
clock: ClockTime::START,
|
||||
devices: HashMap::new(),
|
||||
event_queue: vec![],
|
||||
|
||||
|
@ -125,7 +126,7 @@ impl System {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_for(&mut self, elapsed: ClockElapsed) -> Result<(), Error> {
|
||||
pub fn run_for(&mut self, elapsed: ClockDuration) -> Result<(), Error> {
|
||||
let target = self.clock + elapsed;
|
||||
|
||||
while self.clock < target {
|
||||
|
@ -147,7 +148,7 @@ impl System {
|
|||
}
|
||||
|
||||
pub fn run_loop(&mut self) {
|
||||
self.run_for(u64::MAX).unwrap();
|
||||
self.run_for(ClockDuration::from_nanos(u64::MAX)).unwrap();
|
||||
}
|
||||
|
||||
pub fn exit_error(&mut self) {
|
||||
|
@ -188,14 +189,14 @@ impl System {
|
|||
|
||||
|
||||
pub struct NextStep {
|
||||
pub next_clock: Clock,
|
||||
pub next_clock: ClockTime,
|
||||
pub device: TransmutableBox,
|
||||
}
|
||||
|
||||
impl NextStep {
|
||||
pub fn new(device: TransmutableBox) -> Self {
|
||||
Self {
|
||||
next_clock: 0,
|
||||
next_clock: ClockTime::START,
|
||||
device,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
use moa_core::debug;
|
||||
use moa_core::{System, Error, ErrorType, ClockElapsed, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable};
|
||||
use moa_core::{System, Error, ErrorType, ClockDuration, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable};
|
||||
|
||||
use crate::state::{M68k, M68kType, Status, Flags, Exceptions, InterruptPriority, FunctionCode, MemType, MemAccess};
|
||||
use crate::instructions::{
|
||||
|
@ -30,7 +30,7 @@ pub enum Used {
|
|||
}
|
||||
|
||||
impl Steppable for M68k {
|
||||
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
|
||||
fn step(&mut self, system: &System) -> Result<ClockDuration, Error> {
|
||||
self.step_internal(system)
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ impl M68k {
|
|||
self.state.status != Status::Stopped
|
||||
}
|
||||
|
||||
pub fn step_internal(&mut self, system: &System) -> Result<ClockElapsed, Error> {
|
||||
pub fn step_internal(&mut self, system: &System) -> Result<ClockDuration, Error> {
|
||||
match self.state.status {
|
||||
Status::Init => self.init(),
|
||||
Status::Stopped => Err(Error::new("CPU stopped")),
|
||||
|
@ -73,7 +73,7 @@ impl M68k {
|
|||
// TODO match arm conditional is temporary: illegal instructions generate a top level error in order to debug and fix issues with decode
|
||||
//Err(Error { err: ErrorType::Processor, native, .. }) if native != Exceptions::IllegalInstruction as u32 => {
|
||||
self.exception(native as u8, false)?;
|
||||
Ok(4)
|
||||
Ok(self.frequency.period_duration() * 4)
|
||||
},
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
|
@ -81,14 +81,14 @@ impl M68k {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn init(&mut self) -> Result<ClockElapsed, Error> {
|
||||
pub fn init(&mut self) -> Result<ClockDuration, Error> {
|
||||
self.state.ssp = self.port.read_beu32(0)?;
|
||||
self.state.pc = self.port.read_beu32(4)?;
|
||||
self.state.status = Status::Running;
|
||||
Ok(16)
|
||||
Ok(self.frequency.period_duration() * 16)
|
||||
}
|
||||
|
||||
pub fn cycle_one(&mut self, system: &System) -> Result<ClockElapsed, Error> {
|
||||
pub fn cycle_one(&mut self, system: &System) -> Result<ClockDuration, Error> {
|
||||
self.timer.cycle.start();
|
||||
self.decode_next()?;
|
||||
self.execute_current()?;
|
||||
|
@ -99,7 +99,7 @@ impl M68k {
|
|||
|
||||
self.check_pending_interrupts(system)?;
|
||||
self.check_breakpoints(system);
|
||||
Ok((1_000_000_000 / self.frequency as u64) * self.timing.calculate_clocks(false, 1) as ClockElapsed)
|
||||
Ok(self.frequency.period_duration() * self.timing.calculate_clocks(false, 1) as u64)
|
||||
}
|
||||
|
||||
pub fn check_pending_interrupts(&mut self, system: &System) -> Result<(), Error> {
|
||||
|
@ -115,7 +115,7 @@ impl M68k {
|
|||
let priority_mask = ((self.state.sr & Flags::IntMask as u16) >> 8) as u8;
|
||||
|
||||
if (pending_ipl > priority_mask || pending_ipl == 7) && pending_ipl >= current_ipl {
|
||||
debug!("{} interrupt: {} @ {} ns", DEV_NAME, pending_ipl, system.clock);
|
||||
debug!("{} interrupt: {} @ {} ns", DEV_NAME, pending_ipl, system.clock.as_duration().as_nanos());
|
||||
self.state.current_ipl = self.state.pending_ipl;
|
||||
let ack_num = system.get_interrupt_controller().acknowledge(self.state.current_ipl as u8)?;
|
||||
self.exception(ack_num, true)?;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
use moa_core::{Address, BusPort};
|
||||
use moa_core::{Address, BusPort, Frequency};
|
||||
use moa_core::timers::CpuTimer;
|
||||
|
||||
use crate::instructions::Size;
|
||||
|
@ -125,7 +125,7 @@ pub struct M68kState {
|
|||
#[derive(Clone)]
|
||||
pub struct M68k {
|
||||
pub cputype: M68kType,
|
||||
pub frequency: u32,
|
||||
pub frequency: Frequency,
|
||||
pub state: M68kState,
|
||||
pub decoder: M68kDecoder,
|
||||
pub timing: M68kInstructionTiming,
|
||||
|
@ -155,7 +155,7 @@ impl Default for M68kState {
|
|||
}
|
||||
|
||||
impl M68k {
|
||||
pub fn new(cputype: M68kType, frequency: u32, port: BusPort) -> M68k {
|
||||
pub fn new(cputype: M68kType, frequency: Frequency, port: BusPort) -> M68k {
|
||||
M68k {
|
||||
cputype,
|
||||
frequency,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
use moa_core::{System, Error, ErrorType, ClockElapsed, Address, Steppable, Addressable, Interruptable, Debuggable, Transmutable, read_beu16, write_beu16};
|
||||
use moa_core::{System, Error, ErrorType, ClockDuration, Address, Steppable, Addressable, Interruptable, Debuggable, Transmutable, read_beu16, write_beu16};
|
||||
|
||||
use crate::decode::{Condition, Instruction, LoadTarget, Target, RegisterPair, IndexRegister, SpecialRegister, IndexRegisterHalf, Size, Direction};
|
||||
use crate::state::{Z80, Status, Flags, Register};
|
||||
|
@ -19,19 +19,16 @@ enum RotateType {
|
|||
|
||||
|
||||
impl Steppable for Z80 {
|
||||
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
|
||||
fn step(&mut self, system: &System) -> Result<ClockDuration, Error> {
|
||||
let clocks = if self.reset.get() {
|
||||
//println!("RESET");
|
||||
self.reset()?
|
||||
} else if self.bus_request.get() {
|
||||
//println!("BUS REQ");
|
||||
4
|
||||
} else {
|
||||
//println!("RUNNING {:?}", self.decoder.instruction);
|
||||
self.step_internal(system)?
|
||||
};
|
||||
|
||||
Ok((1_000_000_000 / self.frequency as ClockElapsed) * clocks as ClockElapsed)
|
||||
Ok(self.frequency.period_duration() * clocks as u64)
|
||||
}
|
||||
|
||||
fn on_error(&mut self, _system: &System) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
use moa_core::{Address, BusPort, Signal};
|
||||
use moa_core::{Address, BusPort, Signal, Frequency};
|
||||
|
||||
use crate::decode::Z80Decoder;
|
||||
use crate::debugger::Z80Debugger;
|
||||
|
@ -106,7 +106,7 @@ impl Z80State {
|
|||
|
||||
pub struct Z80 {
|
||||
pub cputype: Z80Type,
|
||||
pub frequency: u32,
|
||||
pub frequency: Frequency,
|
||||
pub state: Z80State,
|
||||
pub decoder: Z80Decoder,
|
||||
pub debugger: Z80Debugger,
|
||||
|
@ -116,7 +116,7 @@ pub struct Z80 {
|
|||
}
|
||||
|
||||
impl Z80 {
|
||||
pub fn new(cputype: Z80Type, frequency: u32, port: BusPort) -> Self {
|
||||
pub fn new(cputype: Z80Type, frequency: Frequency, port: BusPort) -> Self {
|
||||
Self {
|
||||
cputype,
|
||||
frequency,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use moa_core::Clock;
|
||||
use moa_core::{ClockTime, ClockDuration};
|
||||
use moa_core::host::{Audio, ClockedQueue};
|
||||
|
||||
|
||||
|
@ -51,7 +51,7 @@ impl AudioSource {
|
|||
self.frame_size / 2
|
||||
}
|
||||
|
||||
pub fn add_frame(&mut self, clock: Clock, buffer: &[f32]) {
|
||||
pub fn add_frame(&mut self, clock: ClockTime, buffer: &[f32]) {
|
||||
let mut data = vec![];
|
||||
for sample in buffer.iter() {
|
||||
// TODO this is here to keep it quiet for testing, but should be removed later
|
||||
|
@ -81,7 +81,7 @@ impl Audio for AudioSource {
|
|||
self.space_available()
|
||||
}
|
||||
|
||||
fn write_samples(&mut self, clock: Clock, buffer: &[f32]) {
|
||||
fn write_samples(&mut self, clock: ClockTime, buffer: &[f32]) {
|
||||
self.add_frame(clock, buffer);
|
||||
self.flush();
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ pub struct AudioMixer {
|
|||
sample_rate: usize,
|
||||
frame_size: usize,
|
||||
sequence_num: usize,
|
||||
clock: Clock,
|
||||
clock: ClockTime,
|
||||
sources: Vec<ClockedQueue<AudioFrame>>,
|
||||
buffer_underrun: bool,
|
||||
output: Arc<Mutex<AudioOutput>>,
|
||||
|
@ -108,7 +108,7 @@ impl AudioMixer {
|
|||
sample_rate,
|
||||
frame_size: 1280,
|
||||
sequence_num: 0,
|
||||
clock: 0,
|
||||
clock: ClockTime::START,
|
||||
sources: vec![],
|
||||
buffer_underrun: false,
|
||||
output: AudioOutput::new(),
|
||||
|
@ -132,8 +132,8 @@ impl AudioMixer {
|
|||
self.sample_rate
|
||||
}
|
||||
|
||||
pub fn nanos_per_sample(&self) -> Clock {
|
||||
1_000_000_000 as Clock / self.sample_rate as Clock
|
||||
pub fn sample_duration(&self) -> ClockDuration {
|
||||
ClockDuration::from_secs(1) / self.sample_rate as u64
|
||||
}
|
||||
|
||||
pub fn frame_size(&self) -> usize {
|
||||
|
@ -157,12 +157,12 @@ impl AudioMixer {
|
|||
pub fn assemble_frame(&mut self) {
|
||||
self.frame_size = self.output.lock().unwrap().frame_size;
|
||||
|
||||
let nanos_per_sample = self.nanos_per_sample();
|
||||
let sample_duration = self.sample_duration();
|
||||
let mut data: Vec<(f32, f32)> = vec![(0.0, 0.0); self.frame_size];
|
||||
|
||||
if self.buffer_underrun {
|
||||
self.buffer_underrun = false;
|
||||
self.clock += nanos_per_sample * data.len() as Clock;
|
||||
self.clock += sample_duration * data.len() as u64;
|
||||
let empty_frame = AudioFrame { data };
|
||||
self.output.lock().unwrap().add_frame(empty_frame.clone());
|
||||
self.output.lock().unwrap().add_frame(empty_frame);
|
||||
|
@ -189,7 +189,7 @@ impl AudioMixer {
|
|||
},
|
||||
};
|
||||
|
||||
let start = (((clock - self.clock) / nanos_per_sample) as usize).min(data.len() - 1);
|
||||
let start = ((clock.duration_since(self.clock) / sample_duration) as usize).min(data.len() - 1);
|
||||
let length = frame.data.len().min(data.len() - start);
|
||||
|
||||
data[start..start + length].iter_mut()
|
||||
|
@ -201,14 +201,14 @@ impl AudioMixer {
|
|||
)
|
||||
);
|
||||
if length < frame.data.len() {
|
||||
let adjusted_clock = clock + nanos_per_sample * length as Clock;
|
||||
let adjusted_clock = clock + sample_duration * length as u64;
|
||||
//println!("unpopping at clock {}, length {}", adjusted_clock, frame.data.len() - length);
|
||||
source.unpop(adjusted_clock, AudioFrame { data: frame.data[length..].to_vec() });
|
||||
}
|
||||
i = start + length;
|
||||
}
|
||||
}
|
||||
self.clock += nanos_per_sample * data.len() as Clock;
|
||||
self.clock += sample_duration * data.len() as u64;
|
||||
|
||||
self.output.lock().unwrap().add_frame(AudioFrame { data });
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@ use std::sync::mpsc;
|
|||
|
||||
use moa_peripherals_yamaha::{Ym2612, Sn76489};
|
||||
|
||||
use moa_core::host::gfx::{Frame, FrameQueue};
|
||||
use moa_core::host::gfx::{Frame, FrameQueue, PixelEncoding};
|
||||
use moa_core::host::{Host, WindowUpdater, KeyboardUpdater, Key, KeyEvent /*, MouseUpdater, MouseState, MouseEvent*/};
|
||||
use moa_core::{System, Error, ClockElapsed, Address, Addressable, Steppable, Transmutable, TransmutableBox, wrap_transmutable};
|
||||
use moa_core::{System, Error, ClockDuration, Frequency, Address, Addressable, Steppable, Transmutable, TransmutableBox, wrap_transmutable};
|
||||
|
||||
|
||||
pub struct SynthControlsUpdater(mpsc::Sender<KeyEvent>);
|
||||
|
@ -37,7 +37,7 @@ impl SynthControl {
|
|||
}
|
||||
|
||||
impl Steppable for SynthControl {
|
||||
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
|
||||
fn step(&mut self, system: &System) -> Result<ClockDuration, Error> {
|
||||
if let Ok(event) = self.receiver.try_recv() {
|
||||
|
||||
match event.key {
|
||||
|
@ -57,10 +57,10 @@ impl Steppable for SynthControl {
|
|||
}
|
||||
|
||||
let size = self.queue.max_size();
|
||||
let frame = Frame::new(size.0, size.1);
|
||||
let frame = Frame::new(size.0, size.1, PixelEncoding::RGBA);
|
||||
self.queue.add(system.clock, frame);
|
||||
|
||||
Ok(33_000_000)
|
||||
Ok(ClockDuration::from_millis(1))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,11 +104,11 @@ fn main() {
|
|||
let control = wrap_transmutable(SynthControl::new(queue.clone(), receiver));
|
||||
system.add_device("control", control)?;
|
||||
|
||||
let ym_sound = wrap_transmutable(Ym2612::create(host)?);
|
||||
let ym_sound = wrap_transmutable(Ym2612::create(host, Frequency::from_hz(7_670_454))?);
|
||||
initialize_ym(ym_sound.clone())?;
|
||||
system.add_addressable_device(0x00, ym_sound)?;
|
||||
|
||||
let sn_sound = wrap_transmutable(Sn76489::create(host)?);
|
||||
let sn_sound = wrap_transmutable(Sn76489::create(host, Frequency::from_hz(3_579_545))?);
|
||||
system.add_addressable_device(0x10, sn_sound)?;
|
||||
|
||||
host.add_window(Box::new(queue))?;
|
||||
|
|
|
@ -14,7 +14,7 @@ fn main() {
|
|||
.get_matches();
|
||||
|
||||
let mut options = Trs80Options::default();
|
||||
if let Some(filename) = matches.value_of("rom") {
|
||||
if let Some(filename) = matches.value_of("ROM") {
|
||||
options.rom = filename.to_string();
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::time::{Duration, Instant};
|
|||
use minifb::{self, Key, MouseMode, MouseButton};
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
|
||||
use moa_core::{System, Error};
|
||||
use moa_core::{System, Error, ClockDuration};
|
||||
use moa_core::host::{Host, ControllerUpdater, KeyboardUpdater, KeyEvent, MouseUpdater, MouseState, WindowUpdater, Audio, ControllerDevice};
|
||||
use moa_core::host::gfx::{PixelEncoding, Frame};
|
||||
|
||||
|
@ -257,22 +257,23 @@ impl MiniFrontend {
|
|||
|
||||
// Limit to max ~60 fps update rate
|
||||
window.limit_update_rate(Some(Duration::from_micros(16600)));
|
||||
//let nanoseconds_per_frame = (16_600_000 as f32 * speed) as u64;
|
||||
|
||||
let mut update_timer = Instant::now();
|
||||
let mut last_frame = Frame::new(size.0, size.1, PixelEncoding::ARGB);
|
||||
while window.is_open() && !window.is_key_down(Key::Escape) {
|
||||
let frame_time = update_timer.elapsed();
|
||||
update_timer = Instant::now();
|
||||
//println!("new frame after {:?}us", frame_time.as_micros());
|
||||
println!("new frame after {:?}us", frame_time.as_micros());
|
||||
|
||||
//let run_timer = Instant::now();
|
||||
let run_timer = Instant::now();
|
||||
if let Some(system) = system.as_mut() {
|
||||
//system.run_for(nanoseconds_per_frame).unwrap();
|
||||
system.run_for((frame_time.as_nanos() as f32 * speed) as u64).unwrap();
|
||||
system.run_for(ClockDuration::from_nanos((frame_time.as_nanos() as f32 * speed) as u64)).unwrap();
|
||||
//system.run_until_break().unwrap();
|
||||
}
|
||||
//let sim_time = run_timer.elapsed().as_micros();
|
||||
//println!("ran simulation for {:?}us in {:?}us (avg: {:?}us)", frame_time.as_micros(), sim_time, frame_time.as_micros() as f64 / sim_time as f64);
|
||||
let sim_time = run_timer.elapsed().as_micros();
|
||||
println!("ran simulation for {:?}us in {:?}us (avg: {:?}us)", frame_time.as_micros(), sim_time, frame_time.as_micros() as f64 / sim_time as f64);
|
||||
|
||||
if let Some(keys) = window.get_keys_pressed(minifb::KeyRepeat::No) {
|
||||
for key in keys {
|
||||
|
|
|
@ -7,7 +7,7 @@ use winit::dpi::LogicalSize;
|
|||
use winit::event_loop::EventLoop;
|
||||
use winit::window::{Window, WindowBuilder};
|
||||
|
||||
use moa_core::{Clock, System};
|
||||
use moa_core::{ClockDuration, System};
|
||||
|
||||
use crate::settings;
|
||||
use crate::frontend::{self, PixelsFrontend, LoadSystemFn};
|
||||
|
@ -90,7 +90,7 @@ pub fn load_system(handle: &mut HostHandle, load: LoadSystemFnHandle) -> SystemH
|
|||
#[wasm_bindgen]
|
||||
pub fn run_system_for(handle: &mut SystemHandle, nanos: u32) -> usize {
|
||||
let run_timer = Instant::now();
|
||||
let nanoseconds_per_frame = nanos as Clock;
|
||||
let nanoseconds_per_frame = ClockDuration::from_nanos(nanos as u64);
|
||||
//let nanoseconds_per_frame = (16_600_000 as f32 * settings::get().speed) as Clock;
|
||||
if let Err(err) = handle.0.run_for(nanoseconds_per_frame) {
|
||||
log::error!("{:?}", err);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
use moa_core::{Error, System, ClockElapsed, Address, Addressable, Steppable, Transmutable, Signal, ObservableSignal, Observable, debug, warn};
|
||||
use moa_core::{Error, System, ClockDuration, Address, Addressable, Steppable, Transmutable, Signal, ObservableSignal, Observable, debug, warn};
|
||||
|
||||
|
||||
const REG_OUTPUT_B: Address = 0x00;
|
||||
|
@ -99,9 +99,9 @@ impl Addressable for Mos6522 {
|
|||
}
|
||||
|
||||
impl Steppable for Mos6522 {
|
||||
fn step(&mut self, _system: &System) -> Result<ClockElapsed, Error> {
|
||||
fn step(&mut self, _system: &System) -> Result<ClockDuration, Error> {
|
||||
|
||||
Ok(16_600_000)
|
||||
Ok(ClockDuration::from_micros(16_600))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
use moa_core::{System, Error, ClockElapsed, Address, Steppable, Addressable, Transmutable, debug};
|
||||
use moa_core::{System, Error, ClockDuration, Frequency, Address, Steppable, Addressable, Transmutable, debug};
|
||||
use moa_core::host::Tty;
|
||||
|
||||
|
||||
|
@ -147,6 +147,8 @@ impl MC68681Port {
|
|||
}
|
||||
|
||||
pub struct MC68681 {
|
||||
frequency: Frequency,
|
||||
|
||||
acr: u8,
|
||||
pub port_a: MC68681Port,
|
||||
pub port_b: MC68681Port,
|
||||
|
@ -169,6 +171,8 @@ pub struct MC68681 {
|
|||
impl Default for MC68681 {
|
||||
fn default() -> Self {
|
||||
MC68681 {
|
||||
frequency: Frequency::from_hz(3_686_400),
|
||||
|
||||
acr: 0,
|
||||
port_a: MC68681Port::default(),
|
||||
port_b: MC68681Port::default(),
|
||||
|
@ -201,7 +205,7 @@ impl MC68681 {
|
|||
}
|
||||
|
||||
impl Steppable for MC68681 {
|
||||
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
|
||||
fn step(&mut self, system: &System) -> Result<ClockDuration, Error> {
|
||||
if self.port_a.check_rx()? {
|
||||
self.set_interrupt_flag(ISR_CH_A_RX_READY_FULL, true);
|
||||
}
|
||||
|
@ -237,7 +241,7 @@ impl Steppable for MC68681 {
|
|||
self.set_interrupt_flag(ISR_CH_B_TX_READY, true);
|
||||
}
|
||||
|
||||
Ok(1_000_000_000 / 3_686_400)
|
||||
Ok(self.frequency.period_duration())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
use moa_core::{info, warn, debug};
|
||||
use moa_core::{System, Error, ClockElapsed, Address, Addressable, Steppable, Transmutable};
|
||||
use moa_core::{System, Error, ClockDuration, Frequency, Address, Addressable, Steppable, Transmutable};
|
||||
use moa_core::host::{Host, Audio};
|
||||
use moa_core::host::audio::{SquareWave};
|
||||
|
||||
|
@ -86,7 +86,7 @@ impl NoiseGenerator {
|
|||
|
||||
|
||||
pub struct Sn76489 {
|
||||
clock_frequency: u32,
|
||||
clock_frequency: Frequency,
|
||||
first_byte: Option<u8>,
|
||||
source: Box<dyn Audio>,
|
||||
tones: Vec<ToneGenerator>,
|
||||
|
@ -94,7 +94,7 @@ pub struct Sn76489 {
|
|||
}
|
||||
|
||||
impl Sn76489 {
|
||||
pub fn create<H: Host>(host: &mut H, clock_frequency: u32) -> Result<Self, Error> {
|
||||
pub fn create<H: Host>(host: &mut H, clock_frequency: Frequency) -> Result<Self, Error> {
|
||||
let source = host.create_audio_source()?;
|
||||
let sample_rate = source.samples_per_second();
|
||||
|
||||
|
@ -109,7 +109,7 @@ impl Sn76489 {
|
|||
}
|
||||
|
||||
impl Steppable for Sn76489 {
|
||||
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
|
||||
fn step(&mut self, system: &System) -> Result<ClockDuration, Error> {
|
||||
let rate = self.source.samples_per_second();
|
||||
let available = self.source.space_available();
|
||||
let samples = if available < rate / 1000 { available } else { rate / 1000 };
|
||||
|
@ -137,7 +137,7 @@ impl Steppable for Sn76489 {
|
|||
self.source.flush();
|
||||
}
|
||||
|
||||
Ok(1_000_000) // Every 1ms of simulated time
|
||||
Ok(ClockDuration::from_millis(1)) // Every 1ms of simulated time
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ use std::num::NonZeroU8;
|
|||
use std::collections::VecDeque;
|
||||
|
||||
use moa_core::{debug, warn};
|
||||
use moa_core::{System, Error, Clock, ClockElapsed, Address, Addressable, Steppable, Transmutable};
|
||||
use moa_core::{System, Error, ClockTime, ClockDuration, Frequency, Address, Addressable, Steppable, Transmutable};
|
||||
use moa_core::host::{Host, Audio};
|
||||
use moa_core::host::audio::{SineWave, db_to_gain};
|
||||
|
||||
|
@ -120,6 +120,8 @@ const OPERATORS: usize = 4;
|
|||
const MAX_ENVELOPE: u16 = 0xFFC;
|
||||
|
||||
|
||||
type EnvelopeClock = u64;
|
||||
|
||||
#[repr(usize)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
enum EnvelopeState {
|
||||
|
@ -137,8 +139,8 @@ struct EnvelopeGenerator {
|
|||
rates: [usize; 4],
|
||||
|
||||
envelope_state: EnvelopeState,
|
||||
last_state_change: Clock,
|
||||
last_envelope_clock: Clock,
|
||||
last_state_change: ClockTime,
|
||||
next_envelope_clock: EnvelopeClock,
|
||||
envelope: u16,
|
||||
}
|
||||
|
||||
|
@ -151,8 +153,8 @@ impl EnvelopeGenerator {
|
|||
rates: [0; 4],
|
||||
|
||||
envelope_state: EnvelopeState::Attack,
|
||||
last_state_change: 0,
|
||||
last_envelope_clock: 0,
|
||||
last_state_change: ClockTime::START,
|
||||
next_envelope_clock: 0,
|
||||
envelope: 0,
|
||||
}
|
||||
}
|
||||
|
@ -169,10 +171,10 @@ impl EnvelopeGenerator {
|
|||
self.rates[etype as usize] = rate;
|
||||
}
|
||||
|
||||
fn notify_state_change(&mut self, state: bool, envelope_clock: Clock) {
|
||||
self.last_state_change = envelope_clock;
|
||||
fn notify_state_change(&mut self, state: bool, envelope_clock: EnvelopeClock) {
|
||||
//self.last_state_change = envelope_clock;
|
||||
if state {
|
||||
self.last_envelope_clock = envelope_clock;
|
||||
self.next_envelope_clock = envelope_clock;
|
||||
self.envelope_state = EnvelopeState::Attack;
|
||||
self.envelope = 0;
|
||||
} else {
|
||||
|
@ -180,14 +182,14 @@ impl EnvelopeGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
fn update_envelope(&mut self, envelope_clock: Clock) {
|
||||
for clock in (self.last_envelope_clock + 1)..=envelope_clock {
|
||||
fn update_envelope(&mut self, envelope_clock: EnvelopeClock) {
|
||||
for clock in self.next_envelope_clock..=envelope_clock {
|
||||
self.do_cycle(clock);
|
||||
}
|
||||
self.last_envelope_clock = envelope_clock;
|
||||
self.next_envelope_clock = envelope_clock + 1;
|
||||
}
|
||||
|
||||
fn do_cycle(&mut self, envelope_clock: Clock) {
|
||||
fn do_cycle(&mut self, envelope_clock: EnvelopeClock) {
|
||||
if self.envelope_state == EnvelopeState::Decay && self.envelope >= self.sustain_level {
|
||||
self.envelope_state = EnvelopeState::Sustain;
|
||||
}
|
||||
|
@ -224,7 +226,7 @@ impl EnvelopeGenerator {
|
|||
self.envelope
|
||||
};
|
||||
let attenuation_10bit = (envelope + self.total_level).min(MAX_ENVELOPE);
|
||||
envelope as f32 * 0.09375
|
||||
attenuation_10bit as f32 * 0.09375
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -285,11 +287,11 @@ impl Operator {
|
|||
self.envelope.set_rate(etype, rate)
|
||||
}
|
||||
|
||||
fn notify_state_change(&mut self, state: bool, envelope_clock: Clock) {
|
||||
fn notify_state_change(&mut self, state: bool, envelope_clock: EnvelopeClock) {
|
||||
self.envelope.notify_state_change(state, envelope_clock);
|
||||
}
|
||||
|
||||
fn get_sample(&mut self, modulator: f32, envelope_clock: Clock) -> f32 {
|
||||
fn get_sample(&mut self, modulator: f32, envelope_clock: EnvelopeClock) -> f32 {
|
||||
self.wave.set_frequency((self.frequency * self.multiplier) + modulator);
|
||||
let sample = self.wave.next().unwrap();
|
||||
|
||||
|
@ -300,9 +302,6 @@ impl Operator {
|
|||
}
|
||||
}
|
||||
|
||||
fn rate_to_gain(rate: usize, envelope_clock: Clock) -> f32 {
|
||||
envelope_clock as f32 * rate as f32
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Channel {
|
||||
|
@ -339,12 +338,11 @@ impl Channel {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_sample(&mut self, envelope_clock: Clock) -> f32 {
|
||||
fn get_sample(&mut self, envelope_clock: EnvelopeClock) -> f32 {
|
||||
if self.on_state != self.next_on_state {
|
||||
self.on_state = self.next_on_state;
|
||||
for (i, operator) in self.operators.iter_mut().enumerate() {
|
||||
operator.notify_state_change(((self.on_state >> i) & 0x01) != 0, envelope_clock);
|
||||
println!("notified at {}", envelope_clock);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -355,7 +353,7 @@ println!("notified at {}", envelope_clock);
|
|||
}
|
||||
}
|
||||
|
||||
fn get_algorithm_sample(&mut self, envelope_clock: Clock) -> f32 {
|
||||
fn get_algorithm_sample(&mut self, envelope_clock: EnvelopeClock) -> f32 {
|
||||
match self.algorithm {
|
||||
OperatorAlgorithm::A0 => {
|
||||
let modulator0 = self.operators[0].get_sample(0.0, envelope_clock);
|
||||
|
@ -441,8 +439,8 @@ pub struct Ym2612 {
|
|||
selected_reg_0: Option<NonZeroU8>,
|
||||
selected_reg_1: Option<NonZeroU8>,
|
||||
|
||||
clock_frequency: u32,
|
||||
envelope_clock_period: ClockElapsed,
|
||||
clock_frequency: Frequency,
|
||||
envelope_clock_period: ClockDuration,
|
||||
channels: Vec<Channel>,
|
||||
channel_frequencies: [(u8, u16); CHANNELS],
|
||||
dac: Dac,
|
||||
|
@ -461,7 +459,7 @@ pub struct Ym2612 {
|
|||
}
|
||||
|
||||
impl Ym2612 {
|
||||
pub fn create<H: Host>(host: &mut H, clock_frequency: u32) -> Result<Self, Error> {
|
||||
pub fn create<H: Host>(host: &mut H, clock_frequency: Frequency) -> Result<Self, Error> {
|
||||
let source = host.create_audio_source()?;
|
||||
let sample_rate = source.samples_per_second();
|
||||
Ok(Self {
|
||||
|
@ -470,7 +468,7 @@ impl Ym2612 {
|
|||
selected_reg_1: None,
|
||||
|
||||
clock_frequency,
|
||||
envelope_clock_period: 351 * 1_000_000_000 / clock_frequency as ClockElapsed, //3 * 144 * 1_000_000_000 / clock_frequency as ClockElapsed,
|
||||
envelope_clock_period: clock_frequency.period_duration() * 351, //3 * 144 * 1_000_000_000 / clock_frequency as ClockDuration,
|
||||
channels: (0..CHANNELS).map(|i| Channel::new(format!("ch {}", i), sample_rate)).collect(),
|
||||
channel_frequencies: [(0, 0); CHANNELS],
|
||||
|
||||
|
@ -492,16 +490,16 @@ impl Ym2612 {
|
|||
}
|
||||
|
||||
impl Steppable for Ym2612 {
|
||||
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
|
||||
fn step(&mut self, system: &System) -> Result<ClockDuration, Error> {
|
||||
let rate = self.source.samples_per_second();
|
||||
let available = self.source.space_available();
|
||||
let samples = if available < rate / 1000 { available } else { rate / 1000 };
|
||||
let nanos_per_sample = 1_000_000_000 / rate;
|
||||
let sample_duration = ClockDuration::from_secs(1) / rate as u64;
|
||||
|
||||
//if self.source.space_available() >= samples {
|
||||
let mut buffer = vec![0.0; samples];
|
||||
for (i, buffered_sample) in buffer.iter_mut().enumerate().take(samples) {
|
||||
let envelope_clock = (system.clock + (i * nanos_per_sample) as Clock) / self.envelope_clock_period;
|
||||
let envelope_clock = (system.clock.as_duration() + (sample_duration * i as u64)) / self.envelope_clock_period;
|
||||
let mut sample = 0.0;
|
||||
|
||||
for ch in 0..(CHANNELS - 1) {
|
||||
|
@ -519,7 +517,7 @@ impl Steppable for Ym2612 {
|
|||
self.source.write_samples(system.clock, &buffer);
|
||||
//}
|
||||
|
||||
Ok(1_000_000) // Every 1ms of simulated time
|
||||
Ok(ClockDuration::from_millis(1)) // Every 1ms of simulated time
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -554,7 +552,6 @@ impl Ym2612 {
|
|||
return;
|
||||
},
|
||||
};
|
||||
println!("ch {} is {}", ch, if data >> 4 != 0 { "on" } else { "off" });
|
||||
self.channels[ch].next_on_state = data >> 4;
|
||||
},
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
use moa_core::{System, Error, ClockElapsed, Address, Addressable, Steppable, Transmutable, warn, debug};
|
||||
use moa_core::{System, Error, ClockDuration, Address, Addressable, Steppable, Transmutable, warn, debug};
|
||||
|
||||
const DEV_NAME: &str = "z8530";
|
||||
|
||||
|
@ -27,9 +27,9 @@ impl Addressable for Z8530 {
|
|||
}
|
||||
|
||||
impl Steppable for Z8530 {
|
||||
fn step(&mut self, _system: &System) -> Result<ClockElapsed, Error> {
|
||||
fn step(&mut self, _system: &System) -> Result<ClockDuration, Error> {
|
||||
|
||||
Ok(1_000_000_000)
|
||||
Ok(ClockDuration::from_secs(1))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
use moa_core::{System, Error, Debuggable, MemoryBlock, BusPort, wrap_transmutable};
|
||||
use moa_core::{System, Error, Frequency, Debuggable, MemoryBlock, BusPort, wrap_transmutable};
|
||||
use moa_core::host::Host;
|
||||
|
||||
use moa_m68k::{M68k, M68kType};
|
||||
|
@ -27,7 +27,7 @@ pub fn build_computie<H: Host>(host: &H) -> Result<System, Error> {
|
|||
system.add_addressable_device(0x00700000, wrap_transmutable(serial))?;
|
||||
|
||||
|
||||
let mut cpu = M68k::new(M68kType::MC68010, 10_000_000, BusPort::new(0, 24, 16, system.bus.clone()));
|
||||
let mut cpu = M68k::new(M68kType::MC68010, Frequency::from_hz(10_000_000), BusPort::new(0, 24, 16, system.bus.clone()));
|
||||
|
||||
//cpu.enable_tracing();
|
||||
//cpu.add_breakpoint(0x10781a);
|
||||
|
@ -65,7 +65,7 @@ pub fn build_computie_k30<H: Host>(host: &H) -> Result<System, Error> {
|
|||
system.add_addressable_device(0x00700000, wrap_transmutable(serial))?;
|
||||
|
||||
|
||||
let cpu = M68k::new(M68kType::MC68030, 10_000_000, BusPort::new(0, 32, 32, system.bus.clone()));
|
||||
let cpu = M68k::new(M68kType::MC68030, Frequency::from_hz(10_000_000), BusPort::new(0, 32, 32, system.bus.clone()));
|
||||
|
||||
//cpu.enable_tracing();
|
||||
//cpu.add_breakpoint(0x10781a);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
use moa_core::{warn, info};
|
||||
use moa_core::{System, Error, Clock, ClockElapsed, Address, Addressable, Steppable, Transmutable};
|
||||
use moa_core::{System, Error, ClockTime, ClockDuration, Address, Addressable, Steppable, Transmutable};
|
||||
use moa_core::host::{Host, ControllerUpdater, HostData, ControllerDevice, ControllerEvent};
|
||||
|
||||
|
||||
|
@ -117,7 +117,7 @@ pub struct GenesisControllers {
|
|||
port_2: GenesisControllerPort,
|
||||
expansion: GenesisControllerPort,
|
||||
interrupt: HostData<bool>,
|
||||
reset_timer: Clock,
|
||||
reset_timer: ClockDuration,
|
||||
}
|
||||
|
||||
impl Default for GenesisControllers {
|
||||
|
@ -127,7 +127,7 @@ impl Default for GenesisControllers {
|
|||
port_2: GenesisControllerPort::default(),
|
||||
expansion: GenesisControllerPort::default(),
|
||||
interrupt: HostData::new(false),
|
||||
reset_timer: 0,
|
||||
reset_timer: ClockDuration::ZERO,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ impl Addressable for GenesisControllers {
|
|||
}
|
||||
|
||||
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> {
|
||||
self.reset_timer = 0;
|
||||
self.reset_timer = ClockDuration::ZERO;
|
||||
|
||||
info!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]);
|
||||
match addr {
|
||||
|
@ -200,11 +200,11 @@ impl Addressable for GenesisControllers {
|
|||
}
|
||||
|
||||
impl Steppable for GenesisControllers {
|
||||
fn step(&mut self, _system: &System) -> Result<ClockElapsed, Error> {
|
||||
let duration = 100_000; // Update every 100us
|
||||
fn step(&mut self, _system: &System) -> Result<ClockDuration, Error> {
|
||||
let duration = ClockDuration::from_micros(100); // Update every 100us
|
||||
|
||||
self.reset_timer += duration;
|
||||
if self.reset_timer >= 1_500_000 {
|
||||
if self.reset_timer >= ClockDuration::from_micros(1_500) {
|
||||
self.port_1.reset_count();
|
||||
self.port_2.reset_count();
|
||||
self.expansion.reset_count();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
use moa_core::{debug, warn, error};
|
||||
use moa_core::{System, Error, EdgeSignal, Clock, ClockElapsed, Address, Addressable, Steppable, Inspectable, Transmutable, TransmutableBox, read_beu16, dump_slice};
|
||||
use moa_core::{System, Error, EdgeSignal, ClockTime, ClockDuration, Frequency, Address, Addressable, Steppable, Inspectable, Transmutable, TransmutableBox, read_beu16, dump_slice};
|
||||
use moa_core::host::{Host, BlitableSurface, HostData};
|
||||
use moa_core::host::gfx::{Pixel, PixelEncoding, Frame, FrameQueue};
|
||||
|
||||
|
@ -314,7 +314,7 @@ struct Ym7101State {
|
|||
sprites: Vec<Sprite>,
|
||||
sprites_by_line: Vec<Vec<usize>>,
|
||||
|
||||
last_clock: Clock,
|
||||
last_clock: ClockTime,
|
||||
p_clock: u32,
|
||||
h_clock: u32,
|
||||
v_clock: u32,
|
||||
|
@ -349,7 +349,7 @@ impl Default for Ym7101State {
|
|||
sprites: vec![],
|
||||
sprites_by_line: vec![],
|
||||
|
||||
last_clock: 0,
|
||||
last_clock: ClockTime::START,
|
||||
p_clock: 0,
|
||||
h_clock: 0,
|
||||
v_clock: 0,
|
||||
|
@ -609,8 +609,8 @@ impl Sprite {
|
|||
}
|
||||
|
||||
impl Steppable for Ym7101 {
|
||||
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
|
||||
let diff = (system.clock - self.state.last_clock) as u32;
|
||||
fn step(&mut self, system: &System) -> Result<ClockDuration, Error> {
|
||||
let diff = system.clock.duration_since(self.state.last_clock).as_nanos() as u32;
|
||||
self.state.last_clock = system.clock;
|
||||
|
||||
if self.state.external_int_enabled() && self.external_interrupt.get() {
|
||||
|
@ -674,7 +674,7 @@ impl Steppable for Ym7101 {
|
|||
self.state.status = (self.state.status & !STATUS_DMA_BUSY) | (if self.state.memory.transfer_dma_busy { STATUS_DMA_BUSY } else { 0 });
|
||||
}
|
||||
|
||||
Ok((1_000_000_000 / 13_423_294) * 4)
|
||||
Ok(Frequency::from_hz(13_423_294).period_duration() * 4)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::mem;
|
|||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
|
||||
use moa_core::{System, Error, Signal, MemoryBlock, Bus, BusPort, Address, Addressable, Debuggable, wrap_transmutable};
|
||||
use moa_core::{System, Error, Frequency, Signal, MemoryBlock, Bus, BusPort, Address, Addressable, Debuggable, wrap_transmutable};
|
||||
use moa_core::host::Host;
|
||||
|
||||
use moa_m68k::{M68k, M68kType};
|
||||
|
@ -70,8 +70,8 @@ pub fn build_genesis<H: Host>(host: &mut H, mut options: SegaGenesisOptions) ->
|
|||
// Build the Coprocessor's Bus
|
||||
let bank_register = Signal::new(0);
|
||||
let coproc_ram = wrap_transmutable(MemoryBlock::new(vec![0; 0x00002000]));
|
||||
let coproc_ym_sound = wrap_transmutable(Ym2612::create(host, 7_670_454)?);
|
||||
let coproc_sn_sound = wrap_transmutable(Sn76489::create(host, 3_579_545)?);
|
||||
let coproc_ym_sound = wrap_transmutable(Ym2612::create(host, Frequency::from_hz(7_670_454))?);
|
||||
let coproc_sn_sound = wrap_transmutable(Sn76489::create(host, Frequency::from_hz(3_579_545))?);
|
||||
let coproc_register = wrap_transmutable(CoprocessorBankRegister::new(bank_register.clone()));
|
||||
let coproc_area = wrap_transmutable(CoprocessorBankArea::new(bank_register, system.bus.clone()));
|
||||
|
||||
|
@ -82,7 +82,7 @@ pub fn build_genesis<H: Host>(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 mut coproc = Z80::new(Z80Type::Z80, 3_579_545, BusPort::new(0, 16, 8, coproc_bus));
|
||||
let mut coproc = Z80::new(Z80Type::Z80, Frequency::from_hz(3_579_545), BusPort::new(0, 16, 8, coproc_bus));
|
||||
coproc.set_debugging(true);
|
||||
let mut reset = coproc.reset.clone();
|
||||
let mut bus_request = coproc.bus_request.clone();
|
||||
|
@ -109,7 +109,7 @@ pub fn build_genesis<H: Host>(host: &mut H, mut options: SegaGenesisOptions) ->
|
|||
system.break_signal = Some(vdp.frame_complete.clone());
|
||||
system.add_peripheral("vdp", 0x00c00000, wrap_transmutable(vdp)).unwrap();
|
||||
|
||||
let cpu = M68k::new(M68kType::MC68000, 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()));
|
||||
system.add_interruptable_device("cpu", wrap_transmutable(cpu)).unwrap();
|
||||
|
||||
Ok(system)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
use moa_core::{System, Error, ClockElapsed, Address, Addressable, Steppable, Transmutable, info, warn};
|
||||
use moa_core::{System, Error, ClockDuration, Address, Addressable, Steppable, Transmutable, info, warn};
|
||||
|
||||
|
||||
//const CA0: u8 = 0x01;
|
||||
|
@ -94,9 +94,9 @@ impl Addressable for IWM {
|
|||
}
|
||||
|
||||
impl Steppable for IWM {
|
||||
fn step(&mut self, _system: &System) -> Result<ClockElapsed, Error> {
|
||||
fn step(&mut self, _system: &System) -> Result<ClockDuration, Error> {
|
||||
// TODO implement
|
||||
Ok(1_000_000_000)
|
||||
Ok(ClockDuration::from_secs(1))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
|
||||
use moa_core::{System, Bus, Error, Observable, Clock, ClockElapsed, Address, Addressable, AddressRepeater, Steppable, Transmutable, TransmutableBox, wrap_transmutable};
|
||||
use moa_core::{System, Bus, Error, Observable, ClockTime, ClockDuration, Address, Addressable, AddressRepeater, Steppable, Transmutable, TransmutableBox, wrap_transmutable};
|
||||
|
||||
use moa_peripherals_mos::Mos6522;
|
||||
use moa_peripherals_zilog::Z8530;
|
||||
|
@ -18,7 +18,7 @@ pub struct Mainboard {
|
|||
iwm: IWM,
|
||||
via: Mos6522,
|
||||
phase_read: PhaseRead,
|
||||
last_sec: Clock,
|
||||
last_sec: ClockTime,
|
||||
}
|
||||
|
||||
impl Mainboard {
|
||||
|
@ -38,7 +38,7 @@ impl Mainboard {
|
|||
iwm,
|
||||
via,
|
||||
phase_read,
|
||||
last_sec: 0,
|
||||
last_sec: ClockTime::START,
|
||||
};
|
||||
|
||||
mainboard.via.port_a.set_observer(move |port| {
|
||||
|
@ -110,12 +110,12 @@ impl Addressable for Mainboard {
|
|||
}
|
||||
|
||||
impl Steppable for Mainboard {
|
||||
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
|
||||
fn step(&mut self, system: &System) -> Result<ClockDuration, Error> {
|
||||
let elapsed = self.via.step(system)?;
|
||||
|
||||
// TODO should this be 1 second, or a multiple of 979_200, which is an 8th of the CPU clock
|
||||
if self.last_sec + 1_000_000_000 > system.clock {
|
||||
self.last_sec += 1_000_000_000;
|
||||
if self.last_sec + ClockDuration::from_secs(1) > system.clock {
|
||||
self.last_sec += ClockDuration::from_secs(1);
|
||||
//let port_a = self.via.port_a.borrow_mut();
|
||||
// TODO how will the ca1/ca2 cb1/cb2 pins work in the via
|
||||
system.get_interrupt_controller().set(true, 1, 25)?;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
use moa_core::{System, Error, ClockElapsed, Address, Addressable, Steppable, Transmutable};
|
||||
use moa_core::host::gfx::{Frame, FrameQueue};
|
||||
use moa_core::{System, Error, ClockDuration, Address, Addressable, Steppable, Transmutable};
|
||||
use moa_core::host::gfx::{Frame, FrameQueue, Pixel};
|
||||
use moa_core::host::{Host, BlitableSurface};
|
||||
|
||||
|
||||
|
@ -38,7 +38,7 @@ impl BitIter {
|
|||
}
|
||||
|
||||
impl Iterator for BitIter {
|
||||
type Item = u32;
|
||||
type Item = Pixel;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.bit < 0 {
|
||||
|
@ -48,16 +48,16 @@ impl Iterator for BitIter {
|
|||
self.bit -= 1;
|
||||
|
||||
if bit {
|
||||
Some(0xC0C0C0)
|
||||
Some(Pixel::Rgb(0xC0, 0xC0, 0xC0))
|
||||
} else {
|
||||
Some(0)
|
||||
Some(Pixel::Rgb(0, 0, 0))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Steppable for MacVideo {
|
||||
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
|
||||
fn step(&mut self, system: &System) -> Result<ClockDuration, Error> {
|
||||
let mut memory = system.get_bus();
|
||||
let mut frame = Frame::new(SCRN_SIZE.0, SCRN_SIZE.1, self.frame_queue.encoding());
|
||||
for y in 0..SCRN_SIZE.1 {
|
||||
|
@ -68,7 +68,7 @@ impl Steppable for MacVideo {
|
|||
}
|
||||
|
||||
self.frame_queue.add(system.clock, frame);
|
||||
Ok(16_600_000)
|
||||
Ok(ClockDuration::from_micros(16_600))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
use moa_core::{System, Error, MemoryBlock, BusPort, Debuggable, wrap_transmutable};
|
||||
use moa_core::{System, Error, Frequency, MemoryBlock, BusPort, Debuggable, wrap_transmutable};
|
||||
use moa_core::host::Host;
|
||||
|
||||
use moa_m68k::{M68k, M68kType};
|
||||
|
@ -69,7 +69,7 @@ pub fn build_macintosh_512k<H: Host>(host: &mut H) -> Result<System, Error> {
|
|||
system.add_addressable_device(0x00000000, wrap_transmutable(mainboard))?;
|
||||
|
||||
|
||||
let mut cpu = M68k::new(M68kType::MC68000, 7_833_600, BusPort::new(0, 24, 16, system.bus.clone()));
|
||||
let mut cpu = M68k::new(M68kType::MC68000, Frequency::from_hz(7_833_600), BusPort::new(0, 24, 16, system.bus.clone()));
|
||||
|
||||
//cpu.enable_tracing();
|
||||
//system.enable_debugging();
|
||||
|
|
|
@ -650,6 +650,7 @@ const CHARACTERS: [[u8; 8]; 64] = [
|
|||
];
|
||||
|
||||
|
||||
use moa_core::host::gfx::Pixel;
|
||||
|
||||
pub struct CharacterGenerator {
|
||||
pub row: i8,
|
||||
|
@ -668,7 +669,7 @@ impl CharacterGenerator {
|
|||
}
|
||||
|
||||
impl Iterator for CharacterGenerator {
|
||||
type Item = u32;
|
||||
type Item = Pixel;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.row >= 8 {
|
||||
|
@ -683,9 +684,9 @@ impl Iterator for CharacterGenerator {
|
|||
}
|
||||
|
||||
if bit {
|
||||
Some(0xC0C0C0)
|
||||
Some(Pixel::Rgb(0xC0, 0xC0, 0xC0))
|
||||
} else {
|
||||
Some(0)
|
||||
Some(Pixel::Rgb(0, 0, 0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use moa_core::{System, Error, ClockElapsed, Address, Addressable, Steppable, Transmutable, debug, warn};
|
||||
use moa_core::{System, Error, ClockDuration, Address, Addressable, Steppable, Transmutable, debug, warn};
|
||||
use moa_core::host::gfx::{Frame, FrameQueue};
|
||||
use moa_core::host::{Host, BlitableSurface, KeyboardUpdater, KeyEvent};
|
||||
|
||||
|
@ -29,7 +29,7 @@ impl Model1Peripherals {
|
|||
Ok(Self {
|
||||
frame_queue,
|
||||
keyboard_mem,
|
||||
video_mem: [0; 1024],
|
||||
video_mem: [0x20; 1024],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -44,18 +44,18 @@ impl KeyboardUpdater for Model1KeyboardUpdater {
|
|||
}
|
||||
|
||||
impl Steppable for Model1Peripherals {
|
||||
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
|
||||
fn step(&mut self, system: &System) -> Result<ClockDuration, Error> {
|
||||
let mut frame = Frame::new(SCREEN_SIZE.0, SCREEN_SIZE.1, self.frame_queue.encoding());
|
||||
for y in 0..16 {
|
||||
for x in 0..64 {
|
||||
let ch = self.video_mem[x + (y * 64)];
|
||||
let iter = CharacterGenerator::new((ch - 0x20) % 64);
|
||||
let iter = CharacterGenerator::new(ch.saturating_sub(0x20) % 64);
|
||||
frame.blit((x * 6) as u32, (y * 8) as u32, iter, 6, 8);
|
||||
}
|
||||
}
|
||||
self.frame_queue.add(system.clock, frame);
|
||||
|
||||
Ok(16_630_000)
|
||||
Ok(ClockDuration::from_micros(16_630))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
use moa_core::{System, Error, MemoryBlock, BusPort, wrap_transmutable};
|
||||
use moa_core::{System, Error, Frequency, MemoryBlock, BusPort, wrap_transmutable};
|
||||
use moa_core::host::Host;
|
||||
|
||||
use moa_z80::{Z80, Z80Type};
|
||||
|
@ -10,7 +10,7 @@ use crate::peripherals::model1::Model1Peripherals;
|
|||
pub struct Trs80Options {
|
||||
pub rom: String,
|
||||
pub memory: u16,
|
||||
pub frequency: u32,
|
||||
pub frequency: Frequency,
|
||||
}
|
||||
|
||||
impl Default for Trs80Options {
|
||||
|
@ -18,7 +18,7 @@ impl Default for Trs80Options {
|
|||
Self {
|
||||
rom: "binaries/trs80/level2.rom".to_string(),
|
||||
memory: 0xC000,
|
||||
frequency: 1_774_000,
|
||||
frequency: Frequency::from_hz(1_774_000),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue