Changed the way frontend works and added keyboard support
This commit is contained in:
parent
2c6a1a1b3a
commit
7e999d4c3a
|
@ -1,28 +1,43 @@
|
|||
|
||||
use std::thread;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use moa::machines::genesis::build_genesis;
|
||||
use moa_minifb::MiniFrontend;
|
||||
use moa_minifb::MiniFrontendBuilder;
|
||||
|
||||
fn main() {
|
||||
/*
|
||||
let mut frontend = Arc::new(MiniFrontend::init_frontend());
|
||||
let mut frontend = Arc::new(Mutex::new(MiniFrontendBuilder::new()));
|
||||
|
||||
{
|
||||
let frontend = frontend.clone();
|
||||
thread::spawn(move || {
|
||||
let mut system = build_genesis(&*frontend).unwrap();
|
||||
let mut system = build_genesis(&mut *(frontend.lock().unwrap())).unwrap();
|
||||
frontend.lock().unwrap().finalize();
|
||||
system.run_loop();
|
||||
});
|
||||
}
|
||||
|
||||
frontend.start();
|
||||
wait_until_initialized(frontend.clone());
|
||||
|
||||
frontend
|
||||
.lock().unwrap()
|
||||
.build()
|
||||
.start(None);
|
||||
|
||||
/*
|
||||
let mut frontend = MiniFrontendBuilder::new();
|
||||
let mut system = build_genesis(&mut frontend).unwrap();
|
||||
|
||||
frontend
|
||||
.build()
|
||||
.start(Some(system));
|
||||
*/
|
||||
|
||||
let mut frontend = MiniFrontend::init_frontend();
|
||||
let mut system = build_genesis(&frontend).unwrap();
|
||||
|
||||
frontend.start(system);
|
||||
}
|
||||
|
||||
fn wait_until_initialized(frontend: Arc<Mutex<MiniFrontendBuilder>>) {
|
||||
while frontend.lock().unwrap().finalized == false {
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
|
||||
use minifb::Key as MiniKey;
|
||||
use moa::host::keys::Key;
|
||||
|
||||
pub fn map_key(key: MiniKey) -> Key {
|
||||
match key {
|
||||
MiniKey::Key0 => Key::Num0,
|
||||
MiniKey::Key1 => Key::Num1,
|
||||
MiniKey::Key2 => Key::Num2,
|
||||
MiniKey::Key3 => Key::Num3,
|
||||
MiniKey::Key4 => Key::Num4,
|
||||
MiniKey::Key5 => Key::Num5,
|
||||
MiniKey::Key6 => Key::Num6,
|
||||
MiniKey::Key7 => Key::Num7,
|
||||
MiniKey::Key8 => Key::Num8,
|
||||
MiniKey::Key9 => Key::Num9,
|
||||
MiniKey::A => Key::A,
|
||||
MiniKey::B => Key::B,
|
||||
MiniKey::C => Key::C,
|
||||
MiniKey::D => Key::D,
|
||||
MiniKey::E => Key::E,
|
||||
MiniKey::F => Key::F,
|
||||
MiniKey::G => Key::G,
|
||||
MiniKey::H => Key::H,
|
||||
MiniKey::I => Key::I,
|
||||
MiniKey::J => Key::J,
|
||||
MiniKey::K => Key::K,
|
||||
MiniKey::L => Key::L,
|
||||
MiniKey::M => Key::M,
|
||||
MiniKey::N => Key::N,
|
||||
MiniKey::O => Key::O,
|
||||
MiniKey::P => Key::P,
|
||||
MiniKey::Q => Key::Q,
|
||||
MiniKey::R => Key::R,
|
||||
MiniKey::S => Key::S,
|
||||
MiniKey::T => Key::T,
|
||||
MiniKey::U => Key::U,
|
||||
MiniKey::V => Key::V,
|
||||
MiniKey::W => Key::W,
|
||||
MiniKey::X => Key::X,
|
||||
MiniKey::Y => Key::Y,
|
||||
MiniKey::Z => Key::Z,
|
||||
MiniKey::F1 => Key::F1,
|
||||
MiniKey::F2 => Key::F2,
|
||||
MiniKey::F3 => Key::F3,
|
||||
MiniKey::F4 => Key::F4,
|
||||
MiniKey::F5 => Key::F5,
|
||||
MiniKey::F6 => Key::F6,
|
||||
MiniKey::F7 => Key::F7,
|
||||
MiniKey::F8 => Key::F8,
|
||||
MiniKey::F9 => Key::F9,
|
||||
MiniKey::F10 => Key::F10,
|
||||
MiniKey::F11 => Key::F11,
|
||||
MiniKey::F12 => Key::F12,
|
||||
MiniKey::Down => Key::Down,
|
||||
MiniKey::Left => Key::Left,
|
||||
MiniKey::Right => Key::Right,
|
||||
MiniKey::Up => Key::Up,
|
||||
MiniKey::Apostrophe => Key::Apostrophe,
|
||||
MiniKey::Backquote => Key::Backquote,
|
||||
MiniKey::Backslash => Key::Backslash,
|
||||
MiniKey::Comma => Key::Comma,
|
||||
MiniKey::Equal => Key::Equals,
|
||||
MiniKey::LeftBracket => Key::LeftBracket,
|
||||
MiniKey::Minus => Key::Minus,
|
||||
MiniKey::Period => Key::Period,
|
||||
MiniKey::RightBracket => Key::RightBracket,
|
||||
MiniKey::Semicolon => Key::Semicolon,
|
||||
MiniKey::Slash => Key::Slash,
|
||||
MiniKey::Backspace => Key::Backspace,
|
||||
MiniKey::Delete => Key::Delete,
|
||||
MiniKey::End => Key::End,
|
||||
MiniKey::Enter => Key::Enter,
|
||||
MiniKey::Escape => Key::Escape,
|
||||
MiniKey::Home => Key::Home,
|
||||
MiniKey::Insert => Key::Insert,
|
||||
MiniKey::PageDown => Key::PageDown,
|
||||
MiniKey::PageUp => Key::PageUp,
|
||||
MiniKey::Pause => Key::Pause,
|
||||
MiniKey::Space => Key::Space,
|
||||
MiniKey::Tab => Key::Tab,
|
||||
MiniKey::NumLock => Key::NumLock,
|
||||
MiniKey::CapsLock => Key::CapsLock,
|
||||
MiniKey::ScrollLock => Key::ScrollLock,
|
||||
MiniKey::LeftShift => Key::LeftShift,
|
||||
MiniKey::RightShift => Key::RightShift,
|
||||
MiniKey::LeftCtrl => Key::LeftCtrl,
|
||||
MiniKey::RightCtrl => Key::RightCtrl,
|
||||
MiniKey::NumPad0 => Key::NumPad0,
|
||||
MiniKey::NumPad1 => Key::NumPad1,
|
||||
MiniKey::NumPad2 => Key::NumPad2,
|
||||
MiniKey::NumPad3 => Key::NumPad3,
|
||||
MiniKey::NumPad4 => Key::NumPad4,
|
||||
MiniKey::NumPad5 => Key::NumPad5,
|
||||
MiniKey::NumPad6 => Key::NumPad6,
|
||||
MiniKey::NumPad7 => Key::NumPad7,
|
||||
MiniKey::NumPad8 => Key::NumPad8,
|
||||
MiniKey::NumPad9 => Key::NumPad9,
|
||||
MiniKey::NumPadDot => Key::NumPadDot,
|
||||
MiniKey::NumPadSlash => Key::NumPadSlash,
|
||||
MiniKey::NumPadAsterisk => Key::NumPadAsterisk,
|
||||
MiniKey::NumPadMinus => Key::NumPadMinus,
|
||||
MiniKey::NumPadPlus => Key::NumPadPlus,
|
||||
MiniKey::NumPadEnter => Key::NumPadEnter,
|
||||
MiniKey::LeftAlt => Key::LeftAlt,
|
||||
MiniKey::RightAlt => Key::RightAlt,
|
||||
MiniKey::LeftSuper => Key::LeftSuper,
|
||||
MiniKey::RightSuper => Key::RightSuper,
|
||||
_ => Key::Unknown,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
|
||||
mod keys;
|
||||
|
||||
use std::time::Duration;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
|
@ -6,55 +8,94 @@ use minifb::{self, Key};
|
|||
|
||||
use moa::error::Error;
|
||||
use moa::system::System;
|
||||
use moa::host::traits::{Host, JoystickDevice, JoystickUpdater, WindowUpdater};
|
||||
use moa::host::traits::{Host, JoystickDevice, JoystickUpdater, KeyboardUpdater, WindowUpdater};
|
||||
|
||||
use crate::keys::map_key;
|
||||
|
||||
|
||||
const WIDTH: usize = 320;
|
||||
const HEIGHT: usize = 224;
|
||||
|
||||
pub struct MiniFrontend {
|
||||
pub buffer: Mutex<Vec<u32>>,
|
||||
pub updater: Mutex<Option<Box<dyn WindowUpdater>>>,
|
||||
pub input: Mutex<Option<Box<dyn JoystickUpdater>>>,
|
||||
pub struct MiniFrontendBuilder {
|
||||
pub window: Option<Box<dyn WindowUpdater>>,
|
||||
pub joystick: Option<Box<dyn JoystickUpdater>>,
|
||||
pub keyboard: Option<Box<dyn KeyboardUpdater>>,
|
||||
pub finalized: bool,
|
||||
}
|
||||
|
||||
impl Host for MiniFrontend {
|
||||
fn add_window(&self, updater: Box<dyn WindowUpdater>) -> Result<(), Error> {
|
||||
let mut unlocked = self.updater.lock().unwrap();
|
||||
if unlocked.is_some() {
|
||||
impl MiniFrontendBuilder {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
window: None,
|
||||
joystick: None,
|
||||
keyboard: None,
|
||||
finalized: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finalize(&mut self) {
|
||||
self.finalized = true;
|
||||
}
|
||||
|
||||
pub fn build(&mut self) -> MiniFrontend {
|
||||
let window = std::mem::take(&mut self.window);
|
||||
let joystick = std::mem::take(&mut self.joystick);
|
||||
let keyboard = std::mem::take(&mut self.keyboard);
|
||||
MiniFrontend::new(window, joystick, keyboard)
|
||||
}
|
||||
}
|
||||
|
||||
impl Host for MiniFrontendBuilder {
|
||||
fn add_window(&mut self, updater: Box<dyn WindowUpdater>) -> Result<(), Error> {
|
||||
if self.window.is_some() {
|
||||
return Err(Error::new("A window updater has already been registered with the frontend"));
|
||||
}
|
||||
*unlocked = Some(updater);
|
||||
self.window = Some(updater);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn register_joystick(&self, device: JoystickDevice, input: Box<dyn JoystickUpdater>) -> Result<(), Error> {
|
||||
fn register_joystick(&mut self, device: JoystickDevice, input: Box<dyn JoystickUpdater>) -> Result<(), Error> {
|
||||
if device != JoystickDevice::A {
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
let mut unlocked = self.input.lock().unwrap();
|
||||
if unlocked.is_some() {
|
||||
return Err(Error::new("A window updater has already been registered with the frontend"));
|
||||
if self.joystick.is_some() {
|
||||
return Err(Error::new("A joystick updater has already been registered with the frontend"));
|
||||
}
|
||||
*unlocked = Some(input);
|
||||
self.joystick = Some(input);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn register_keyboard(&mut self, input: Box<dyn KeyboardUpdater>) -> Result<(), Error> {
|
||||
if self.keyboard.is_some() {
|
||||
return Err(Error::new("A keyboard updater has already been registered with the frontend"));
|
||||
}
|
||||
self.keyboard = Some(input);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct MiniFrontend {
|
||||
pub buffer: Vec<u32>,
|
||||
pub window: Option<Box<dyn WindowUpdater>>,
|
||||
pub joystick: Option<Box<dyn JoystickUpdater>>,
|
||||
pub keyboard: Option<Box<dyn KeyboardUpdater>>,
|
||||
}
|
||||
|
||||
impl MiniFrontend {
|
||||
pub fn init_frontend() -> MiniFrontend {
|
||||
MiniFrontend {
|
||||
buffer: Mutex::new(vec![0; WIDTH * HEIGHT]),
|
||||
updater: Mutex::new(None),
|
||||
input: Mutex::new(None),
|
||||
pub fn new(window: Option<Box<dyn WindowUpdater>>, joystick: Option<Box<dyn JoystickUpdater>>, keyboard: Option<Box<dyn KeyboardUpdater>>) -> Self {
|
||||
Self {
|
||||
buffer: vec![0; WIDTH * HEIGHT],
|
||||
window,
|
||||
joystick,
|
||||
keyboard,
|
||||
}
|
||||
}
|
||||
|
||||
//pub fn start(&self) {
|
||||
pub fn start(&self, mut system: System) {
|
||||
pub fn start(&mut self, mut system: Option<System>) {
|
||||
let mut options = minifb::WindowOptions::default();
|
||||
options.scale = minifb::Scale::X4;
|
||||
options.scale = minifb::Scale::X2;
|
||||
|
||||
let mut window = minifb::Window::new(
|
||||
"Test - ESC to exit",
|
||||
|
@ -70,26 +111,37 @@ impl MiniFrontend {
|
|||
window.limit_update_rate(Some(Duration::from_micros(16600)));
|
||||
|
||||
while window.is_open() && !window.is_key_down(Key::Escape) {
|
||||
system.run_for(16_600_000).unwrap();
|
||||
if let Some(system) = system.as_mut() {
|
||||
system.run_for(16_600_000).unwrap();
|
||||
}
|
||||
|
||||
if let Some(keys) = window.get_keys_pressed(minifb::KeyRepeat::Yes) {
|
||||
let mut modifiers: u16 = 0;
|
||||
for key in keys {
|
||||
if let Some(mut updater) = self.keyboard.as_mut() {
|
||||
updater.update_keyboard(map_key(key), true);
|
||||
}
|
||||
match key {
|
||||
Key::Enter => { modifiers |= 0xffff; },
|
||||
Key::D => { system.enable_debugging(); },
|
||||
Key::D => { system.as_ref().map(|s| s.enable_debugging()); },
|
||||
_ => { },
|
||||
}
|
||||
}
|
||||
if let Some(updater) = &mut *self.input.lock().unwrap() {
|
||||
if let Some(mut updater) = self.joystick.as_mut() {
|
||||
updater.update_joystick(modifiers);
|
||||
}
|
||||
}
|
||||
if let Some(keys) = window.get_keys_released() {
|
||||
for key in keys {
|
||||
if let Some(mut updater) = self.keyboard.as_mut() {
|
||||
updater.update_keyboard(map_key(key), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(updater) = &mut *self.updater.lock().unwrap() {
|
||||
let mut buffer = self.buffer.lock().unwrap();
|
||||
updater.update_frame(WIDTH as u32, HEIGHT as u32, &mut buffer);
|
||||
window.update_with_buffer(&buffer, WIDTH, HEIGHT).unwrap();
|
||||
if let Some(mut updater) = self.window.as_mut() {
|
||||
updater.update_frame(WIDTH as u32, HEIGHT as u32, &mut self.buffer);
|
||||
window.update_with_buffer(&self.buffer, WIDTH, HEIGHT).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,12 @@ impl BlitableSurface for Frame {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clear(&mut self, value: u32) {
|
||||
for i in 0..((self.width as usize) * (self.height as usize)) {
|
||||
self.bitmap[i] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -38,15 +44,15 @@ pub struct FrameSwapper {
|
|||
}
|
||||
|
||||
impl FrameSwapper {
|
||||
pub fn new() -> FrameSwapper {
|
||||
pub fn new(width: u32, height: u32) -> FrameSwapper {
|
||||
FrameSwapper {
|
||||
current: Frame { width: 0, height: 0, bitmap: vec![] },
|
||||
previous: Frame { width: 0, height: 0, bitmap: vec![] },
|
||||
current: Frame { width, height, bitmap: vec![0; (width * height) as usize] },
|
||||
previous: Frame { width, height, bitmap: vec![0; (width * height) as usize] },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_shared() -> Arc<Mutex<FrameSwapper>> {
|
||||
Arc::new(Mutex::new(FrameSwapper::new()))
|
||||
pub fn new_shared(width: u32, height: u32) -> Arc<Mutex<FrameSwapper>> {
|
||||
Arc::new(Mutex::new(FrameSwapper::new(width, height)))
|
||||
}
|
||||
|
||||
pub fn to_boxed(swapper: Arc<Mutex<FrameSwapper>>) -> Box<dyn WindowUpdater> {
|
||||
|
|
|
@ -5,4 +5,5 @@ pub mod traits;
|
|||
pub mod tty;
|
||||
|
||||
pub mod gfx;
|
||||
pub mod keys;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::host::keys::Key;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum JoystickDevice {
|
||||
|
@ -13,8 +14,9 @@ pub enum JoystickDevice {
|
|||
|
||||
pub trait Host {
|
||||
//fn create_pty(&self) -> Result<Box<dyn Tty>, Error>;
|
||||
fn add_window(&self, updater: Box<dyn WindowUpdater>) -> Result<(), Error>;
|
||||
fn register_joystick(&self, device: JoystickDevice, input: Box<dyn JoystickUpdater>) -> Result<(), Error> { Err(Error::new("Not supported")) }
|
||||
fn add_window(&mut self, updater: Box<dyn WindowUpdater>) -> Result<(), Error>;
|
||||
fn register_joystick(&mut self, device: JoystickDevice, input: Box<dyn JoystickUpdater>) -> Result<(), Error> { Err(Error::new("Not supported")) }
|
||||
fn register_keyboard(&mut self, input: Box<dyn KeyboardUpdater>) -> Result<(), Error> { Err(Error::new("Not supported")) }
|
||||
}
|
||||
|
||||
pub trait Tty {
|
||||
|
@ -31,9 +33,14 @@ pub trait JoystickUpdater: Send {
|
|||
fn update_joystick(&mut self, modifiers: u16);
|
||||
}
|
||||
|
||||
pub trait KeyboardUpdater: Send {
|
||||
fn update_keyboard(&mut self, key: Key, state: bool);
|
||||
}
|
||||
|
||||
pub trait BlitableSurface {
|
||||
fn set_size(&mut self, width: u32, height: 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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ pub fn build_computie<H: Host>(host: &H) -> Result<System, Error> {
|
|||
let mut cpu = M68k::new(M68kType::MC68010, 10_000_000, BusPort::new(0, 24, 16, system.bus.clone()));
|
||||
|
||||
//cpu.enable_tracing();
|
||||
cpu.add_breakpoint(0x10781a);
|
||||
//cpu.add_breakpoint(0x10781a);
|
||||
//cpu.add_breakpoint(0x10bc9c);
|
||||
//cpu.add_breakpoint(0x106a94);
|
||||
//cpu.add_breakpoint(0x1015b2);
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::peripherals::genesis;
|
|||
use crate::host::traits::{Host, WindowUpdater};
|
||||
|
||||
|
||||
pub fn build_genesis<H: Host>(host: &H) -> Result<System, Error> {
|
||||
pub fn build_genesis<H: Host>(host: &mut H) -> Result<System, Error> {
|
||||
let mut system = System::new();
|
||||
|
||||
//let mut rom = MemoryBlock::load("binaries/genesis/Sonic The Hedgehog (W) (REV 00) [!].bin").unwrap();
|
||||
|
@ -19,7 +19,7 @@ pub fn build_genesis<H: Host>(host: &H) -> Result<System, Error> {
|
|||
//let mut rom = MemoryBlock::load("binaries/genesis/Sonic the Hedgehog 3 (U) [!].bin").unwrap();
|
||||
//let mut rom = MemoryBlock::load("binaries/genesis/Earthworm Jim (U) [h1].bin").unwrap();
|
||||
//let mut rom = MemoryBlock::load("binaries/genesis/Home Alone (beta).bin").unwrap();
|
||||
//let mut mut rom = MemoryBlock::load("binaries/genesis/F1 World Championship (JUE) [!].bin").unwrap();
|
||||
//let mut rom = MemoryBlock::load("binaries/genesis/F1 World Championship (JUE) [!].bin").unwrap();
|
||||
//let mut rom = MemoryBlock::load("binaries/genesis/Ren and Stimpy's Invention (U) [!].bin").unwrap();
|
||||
//let mut rom = MemoryBlock::load("binaries/genesis/Out of this World (U) [!].bin").unwrap();
|
||||
//let mut rom = MemoryBlock::load("binaries/genesis/Ghostbusters (REV 00) (JUE).bin").unwrap();
|
||||
|
@ -58,8 +58,11 @@ pub fn build_genesis<H: Host>(host: &H) -> Result<System, Error> {
|
|||
//cpu.add_breakpoint(0x16a0e);
|
||||
//cpu.add_breakpoint(0x16812);
|
||||
//cpu.add_breakpoint(0x166ec);
|
||||
cpu.add_breakpoint(0x13e18);
|
||||
cpu.add_breakpoint(0x16570);
|
||||
//cpu.add_breakpoint(0x13e18);
|
||||
//cpu.add_breakpoint(0x16570);
|
||||
//cpu.add_breakpoint(0x1714);
|
||||
|
||||
//cpu.add_breakpoint(0x43c2);
|
||||
|
||||
system.add_interruptable_device("cpu", wrap_transmutable(cpu)).unwrap();
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@ impl GenesisController {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create<H: Host>(host: &H) -> Result<Self, Error> {
|
||||
pub fn create<H: Host>(host: &mut H) -> Result<Self, Error> {
|
||||
let controller = GenesisController::new();
|
||||
|
||||
let joystick1 = Box::new(GenesisControllerUpdater(controller.port_1.data.clone(), controller.interrupt.clone()));
|
||||
|
|
20
todo.txt
20
todo.txt
|
@ -1,11 +1,25 @@
|
|||
|
||||
* there is a problem where something writes to the rom area which causes a crash
|
||||
At 0x16cde, a move writes an invalid value to 0 via an indirect %a2 reg. The value of the reg might have changed during an interrupt, but it definitely breaks when the next interrupt occurs
|
||||
Before the loop is 0x16a0e which then calculates the count and such
|
||||
0x16584 is where the memory address 0xffd11a is updated, which is then used for the bad 0x0000 address which causes the improper write. 0x16570 is a better start
|
||||
On broken cycle: %a1 = 1df40, moves that location + 1 to %d0
|
||||
|
||||
|
||||
* there is a problem where something writes to the rom area which causes a crash
|
||||
* 0x1650e is where 0xffac08 is changed to 0xd100
|
||||
* 0x16572 is where 0xffd100 is changed to 0
|
||||
* what if it's a problem when turning the 0 into a full address (which should be ff0000 or ffff00 but instead ends up being 000000)
|
||||
|
||||
|
||||
|
||||
|
||||
* the overflow bit is only correct for addition but not subtraction... in subtraction, two positives can result in a negative and vice versa
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
* fix ym7101 to better handle V/H interrupts (right now it sets and then the next step will clear, but it'd be nice if it could 'edge trigger')
|
||||
|
||||
|
@ -18,6 +32,10 @@ On broken cycle: %a1 = 1df40, moves that location + 1 to %d0
|
|||
So both could share the same Signal, one setting it and the other reading it, but how would you actually configure/build that?
|
||||
|
||||
|
||||
* make it possible to set the frame sizes when creating the frame swapper
|
||||
* should you rename devices.rs traits.rs?
|
||||
|
||||
|
||||
|
||||
* implement a Z80
|
||||
* maybe see about a Mac 128k or something
|
||||
|
|
Loading…
Reference in New Issue