fox32: Move Bus to a separate file
This commit is contained in:
parent
3c6fda4b5c
commit
994f6d7152
166
src/bus.rs
Normal file
166
src/bus.rs
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
// bus.rs
|
||||||
|
|
||||||
|
use crate::{Memory, Mouse};
|
||||||
|
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use std::io::{stdout, Write};
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
use rodio::{OutputStream, buffer::SamplesBuffer, Sink};
|
||||||
|
|
||||||
|
pub struct Bus {
|
||||||
|
pub memory: Memory,
|
||||||
|
pub mouse: Arc<Mutex<Mouse>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bus {
|
||||||
|
pub fn read_io(&mut self, port: u32) -> u32 {
|
||||||
|
match port {
|
||||||
|
0x02000000..=0x0200031F => { // overlay port
|
||||||
|
let overlay_lock = self.memory.overlays.lock().unwrap();
|
||||||
|
let overlay_number = (port & 0x000000FF) as usize;
|
||||||
|
let setting = (port & 0x0000FF00) >> 8;
|
||||||
|
|
||||||
|
match setting {
|
||||||
|
0x00 => {
|
||||||
|
// we're reading the position of this overlay
|
||||||
|
let x = overlay_lock[overlay_number].x as u32;
|
||||||
|
let y = overlay_lock[overlay_number].y as u32;
|
||||||
|
(y << 16) | x
|
||||||
|
}
|
||||||
|
0x01 => {
|
||||||
|
// we're reading the size of this overlay
|
||||||
|
let width = overlay_lock[overlay_number].width as u32;
|
||||||
|
let height = overlay_lock[overlay_number].height as u32;
|
||||||
|
(height << 16) | width
|
||||||
|
}
|
||||||
|
0x02 => {
|
||||||
|
// we're reading the framebuffer pointer of this overlay
|
||||||
|
overlay_lock[overlay_number].framebuffer_pointer + 0x02000000
|
||||||
|
}
|
||||||
|
0x03 => {
|
||||||
|
// we're reading the enable status of this overlay
|
||||||
|
overlay_lock[overlay_number].enabled as u32
|
||||||
|
}
|
||||||
|
_ => panic!("invalid overlay control port"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0x02000400..=0x02000401 => { // mouse port
|
||||||
|
let setting = (port & 0x000000FF) as u8;
|
||||||
|
match setting {
|
||||||
|
0x00 => {
|
||||||
|
// we're reading the button states
|
||||||
|
let mut byte: u8 = 0x00;
|
||||||
|
let mut mouse_lock = self.mouse.lock().expect("failed to lock the mouse mutex");
|
||||||
|
if mouse_lock.click {
|
||||||
|
byte |= 0b01;
|
||||||
|
mouse_lock.click = false;
|
||||||
|
}
|
||||||
|
if mouse_lock.held {
|
||||||
|
byte |= 0b10;
|
||||||
|
} else {
|
||||||
|
byte &= !0b10;
|
||||||
|
}
|
||||||
|
byte as u32
|
||||||
|
}
|
||||||
|
0x01 => {
|
||||||
|
// we're reading the position
|
||||||
|
let mouse_lock = self.mouse.lock().expect("failed to lock the mouse mutex");
|
||||||
|
let x = mouse_lock.x as u32;
|
||||||
|
let y = mouse_lock.y as u32;
|
||||||
|
(y << 16) | x
|
||||||
|
}
|
||||||
|
_ => panic!("invalid mouse control port"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn write_io(&mut self, port: u32, word: u32) {
|
||||||
|
match port {
|
||||||
|
0x00000000 => { // terminal output port
|
||||||
|
print!("{}", word as u8 as char);
|
||||||
|
stdout().flush().expect("could not flush stdout");
|
||||||
|
}
|
||||||
|
0x02000000..=0x0200031F => { // overlay port
|
||||||
|
let mut overlay_lock = self.memory.overlays.lock().unwrap();
|
||||||
|
let overlay_number = (port & 0x000000FF) as usize;
|
||||||
|
let setting = (port & 0x0000FF00) >> 8;
|
||||||
|
|
||||||
|
match setting {
|
||||||
|
0x00 => {
|
||||||
|
// we're setting the position of this overlay
|
||||||
|
let x = (word & 0x0000FFFF) as usize;
|
||||||
|
let y = ((word & 0xFFFF0000) >> 16) as usize;
|
||||||
|
overlay_lock[overlay_number].x = x;
|
||||||
|
overlay_lock[overlay_number].y = y;
|
||||||
|
}
|
||||||
|
0x01 => {
|
||||||
|
// we're setting the size of this overlay
|
||||||
|
let width = (word & 0x0000FFFF) as usize;
|
||||||
|
let height = ((word & 0xFFFF0000) >> 16) as usize;
|
||||||
|
overlay_lock[overlay_number].width = width;
|
||||||
|
overlay_lock[overlay_number].height = height;
|
||||||
|
}
|
||||||
|
0x02 => {
|
||||||
|
// we're setting the framebuffer pointer of this overlay
|
||||||
|
if word < 0x02000000 {
|
||||||
|
panic!("overlay framebuffer must be within shared memory");
|
||||||
|
}
|
||||||
|
overlay_lock[overlay_number].framebuffer_pointer = word - 0x02000000;
|
||||||
|
}
|
||||||
|
0x03 => {
|
||||||
|
// we're setting the enable status of this overlay
|
||||||
|
overlay_lock[overlay_number].enabled = word != 0;
|
||||||
|
}
|
||||||
|
_ => panic!("invalid overlay control port"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0x02000320 => { // audio port
|
||||||
|
if word < 0x02000000 {
|
||||||
|
panic!("audio buffer must be within shared memory");
|
||||||
|
}
|
||||||
|
let address = word as usize - 0x02000000;
|
||||||
|
let shared_memory_lock = self.memory.shared_memory.lock().unwrap();
|
||||||
|
|
||||||
|
let length = u32::from_le_bytes(shared_memory_lock[address..address+4].try_into().unwrap()) as usize;
|
||||||
|
let start_address = address + 4;
|
||||||
|
let end_address = start_address + length;
|
||||||
|
|
||||||
|
let audio_data: Vec<i16> = shared_memory_lock[start_address..end_address].to_vec().chunks_exact(2).map(|x| ((x[1] as i16) << 8) | x[0] as i16).collect();
|
||||||
|
let builder = thread::Builder::new().name("audio".to_string());
|
||||||
|
builder.spawn({
|
||||||
|
move || {
|
||||||
|
let buffer = SamplesBuffer::new(1, 44100, audio_data);
|
||||||
|
let (_stream, stream_handle) = OutputStream::try_default().unwrap();
|
||||||
|
let sink = Sink::try_new(&stream_handle).unwrap();
|
||||||
|
sink.append(buffer);
|
||||||
|
sink.sleep_until_end();
|
||||||
|
}
|
||||||
|
}).unwrap();
|
||||||
|
}
|
||||||
|
0x02000400..=0x02000401 => { // mouse port
|
||||||
|
let setting = (port & 0x000000FF) as u8;
|
||||||
|
match setting {
|
||||||
|
0x00 => {
|
||||||
|
// we're setting the button states
|
||||||
|
let mut mouse_lock = self.mouse.lock().expect("failed to lock the mouse mutex");
|
||||||
|
mouse_lock.click = word & (1 << 0) != 0;
|
||||||
|
mouse_lock.held = word & (1 << 1) != 0;
|
||||||
|
}
|
||||||
|
0x01 => {
|
||||||
|
// we're setting the position
|
||||||
|
let mut mouse_lock = self.mouse.lock().expect("failed to lock the mouse mutex");
|
||||||
|
let x = (word & 0x0000FFFF) as u16;
|
||||||
|
let y = ((word & 0xFFFF0000) >> 16) as u16;
|
||||||
|
mouse_lock.x = x;
|
||||||
|
mouse_lock.y = y;
|
||||||
|
}
|
||||||
|
_ => panic!("invalid mouse control port"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => return,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
src/cpu.rs
20
src/cpu.rs
|
@ -3,7 +3,7 @@
|
||||||
// TODO: in the instruction match statement, all of the register ones have `let result` inside the if statement
|
// TODO: in the instruction match statement, all of the register ones have `let result` inside the if statement
|
||||||
// move this up to match all of the other ones (or move all of the other ones down, which would probably be better anyways)
|
// move this up to match all of the other ones (or move all of the other ones down, which would probably be better anyways)
|
||||||
|
|
||||||
use crate::{Mouse, Overlay};
|
use crate::{Bus, Overlay};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
const DEBUG: bool = false;
|
const DEBUG: bool = false;
|
||||||
|
@ -95,24 +95,6 @@ impl Memory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait IO {
|
|
||||||
// called during the `in` instruction
|
|
||||||
// default implementation returns 0
|
|
||||||
fn read_io(&mut self, port: u32) -> u32 {
|
|
||||||
if DEBUG { println!("read_io(): port: {:#010X}", port); }
|
|
||||||
0
|
|
||||||
}
|
|
||||||
// called during the `out` instruction
|
|
||||||
fn write_io(&mut self, port: u32, word: u32) {
|
|
||||||
if DEBUG { println!("write_io(): port: {:#010X}, word: {:#010X}", port, word); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Bus {
|
|
||||||
pub memory: Memory,
|
|
||||||
pub mouse: Arc<Mutex<Mouse>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct Flag {
|
pub struct Flag {
|
||||||
pub carry: bool,
|
pub carry: bool,
|
||||||
|
|
159
src/main.rs
159
src/main.rs
|
@ -1,16 +1,16 @@
|
||||||
// main.rs
|
// main.rs
|
||||||
|
|
||||||
|
pub mod bus;
|
||||||
pub mod cpu;
|
pub mod cpu;
|
||||||
pub mod mouse;
|
pub mod mouse;
|
||||||
use cpu::{Bus, Cpu, Memory, Interrupt, IO};
|
use bus::Bus;
|
||||||
|
use cpu::{Cpu, Memory, Interrupt};
|
||||||
use mouse::Mouse;
|
use mouse::Mouse;
|
||||||
|
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::read;
|
use std::fs::read;
|
||||||
//use std::process::exit;
|
//use std::process::exit;
|
||||||
use std::sync::{Arc, mpsc, Mutex};
|
use std::sync::{Arc, mpsc, Mutex};
|
||||||
use std::io::{stdout, Write};
|
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
use log::error;
|
use log::error;
|
||||||
|
@ -21,8 +21,6 @@ use winit::event_loop::{ControlFlow, EventLoop};
|
||||||
use winit::window::WindowBuilder;
|
use winit::window::WindowBuilder;
|
||||||
use winit_input_helper::WinitInputHelper;
|
use winit_input_helper::WinitInputHelper;
|
||||||
|
|
||||||
use rodio::{OutputStream, buffer::SamplesBuffer, Sink};
|
|
||||||
|
|
||||||
const WIDTH: usize = 640;
|
const WIDTH: usize = 640;
|
||||||
const HEIGHT: usize = 480;
|
const HEIGHT: usize = 480;
|
||||||
|
|
||||||
|
@ -41,157 +39,6 @@ pub struct Overlay {
|
||||||
framebuffer_pointer: u32,
|
framebuffer_pointer: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IO for Bus {
|
|
||||||
fn read_io(&mut self, port: u32) -> u32 {
|
|
||||||
match port {
|
|
||||||
0x02000000..=0x0200031F => { // overlay port
|
|
||||||
let overlay_lock = self.memory.overlays.lock().unwrap();
|
|
||||||
let overlay_number = (port & 0x000000FF) as usize;
|
|
||||||
let setting = (port & 0x0000FF00) >> 8;
|
|
||||||
|
|
||||||
match setting {
|
|
||||||
0x00 => {
|
|
||||||
// we're reading the position of this overlay
|
|
||||||
let x = overlay_lock[overlay_number].x as u32;
|
|
||||||
let y = overlay_lock[overlay_number].y as u32;
|
|
||||||
(y << 16) | x
|
|
||||||
}
|
|
||||||
0x01 => {
|
|
||||||
// we're reading the size of this overlay
|
|
||||||
let width = overlay_lock[overlay_number].width as u32;
|
|
||||||
let height = overlay_lock[overlay_number].height as u32;
|
|
||||||
(height << 16) | width
|
|
||||||
}
|
|
||||||
0x02 => {
|
|
||||||
// we're reading the framebuffer pointer of this overlay
|
|
||||||
overlay_lock[overlay_number].framebuffer_pointer + 0x02000000
|
|
||||||
}
|
|
||||||
0x03 => {
|
|
||||||
// we're reading the enable status of this overlay
|
|
||||||
overlay_lock[overlay_number].enabled as u32
|
|
||||||
}
|
|
||||||
_ => panic!("invalid overlay control port"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
0x02000400..=0x02000401 => { // mouse port
|
|
||||||
let setting = (port & 0x000000FF) as u8;
|
|
||||||
match setting {
|
|
||||||
0x00 => {
|
|
||||||
// we're reading the button states
|
|
||||||
let mut byte: u8 = 0x00;
|
|
||||||
let mut mouse_lock = self.mouse.lock().expect("failed to lock the mouse mutex");
|
|
||||||
if mouse_lock.click {
|
|
||||||
byte |= 0b01;
|
|
||||||
mouse_lock.click = false;
|
|
||||||
}
|
|
||||||
if mouse_lock.held {
|
|
||||||
byte |= 0b10;
|
|
||||||
} else {
|
|
||||||
byte &= !0b10;
|
|
||||||
}
|
|
||||||
byte as u32
|
|
||||||
}
|
|
||||||
0x01 => {
|
|
||||||
// we're reading the position
|
|
||||||
let mouse_lock = self.mouse.lock().expect("failed to lock the mouse mutex");
|
|
||||||
let x = mouse_lock.x as u32;
|
|
||||||
let y = mouse_lock.y as u32;
|
|
||||||
(y << 16) | x
|
|
||||||
}
|
|
||||||
_ => panic!("invalid mouse control port"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn write_io(&mut self, port: u32, word: u32) {
|
|
||||||
match port {
|
|
||||||
0x00000000 => { // terminal output port
|
|
||||||
print!("{}", word as u8 as char);
|
|
||||||
stdout().flush().expect("could not flush stdout");
|
|
||||||
}
|
|
||||||
0x02000000..=0x0200031F => { // overlay port
|
|
||||||
let mut overlay_lock = self.memory.overlays.lock().unwrap();
|
|
||||||
let overlay_number = (port & 0x000000FF) as usize;
|
|
||||||
let setting = (port & 0x0000FF00) >> 8;
|
|
||||||
|
|
||||||
match setting {
|
|
||||||
0x00 => {
|
|
||||||
// we're setting the position of this overlay
|
|
||||||
let x = (word & 0x0000FFFF) as usize;
|
|
||||||
let y = ((word & 0xFFFF0000) >> 16) as usize;
|
|
||||||
overlay_lock[overlay_number].x = x;
|
|
||||||
overlay_lock[overlay_number].y = y;
|
|
||||||
}
|
|
||||||
0x01 => {
|
|
||||||
// we're setting the size of this overlay
|
|
||||||
let width = (word & 0x0000FFFF) as usize;
|
|
||||||
let height = ((word & 0xFFFF0000) >> 16) as usize;
|
|
||||||
overlay_lock[overlay_number].width = width;
|
|
||||||
overlay_lock[overlay_number].height = height;
|
|
||||||
}
|
|
||||||
0x02 => {
|
|
||||||
// we're setting the framebuffer pointer of this overlay
|
|
||||||
if word < 0x02000000 {
|
|
||||||
panic!("overlay framebuffer must be within shared memory");
|
|
||||||
}
|
|
||||||
overlay_lock[overlay_number].framebuffer_pointer = word - 0x02000000;
|
|
||||||
}
|
|
||||||
0x03 => {
|
|
||||||
// we're setting the enable status of this overlay
|
|
||||||
overlay_lock[overlay_number].enabled = word != 0;
|
|
||||||
}
|
|
||||||
_ => panic!("invalid overlay control port"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
0x02000320 => { // audio port
|
|
||||||
if word < 0x02000000 {
|
|
||||||
panic!("audio buffer must be within shared memory");
|
|
||||||
}
|
|
||||||
let address = word as usize - 0x02000000;
|
|
||||||
let shared_memory_lock = self.memory.shared_memory.lock().unwrap();
|
|
||||||
|
|
||||||
let length = u32::from_le_bytes(shared_memory_lock[address..address+4].try_into().unwrap()) as usize;
|
|
||||||
let start_address = address + 4;
|
|
||||||
let end_address = start_address + length;
|
|
||||||
|
|
||||||
let audio_data: Vec<i16> = shared_memory_lock[start_address..end_address].to_vec().chunks_exact(2).map(|x| ((x[1] as i16) << 8) | x[0] as i16).collect();
|
|
||||||
let builder = thread::Builder::new().name("audio".to_string());
|
|
||||||
builder.spawn({
|
|
||||||
move || {
|
|
||||||
let buffer = SamplesBuffer::new(1, 44100, audio_data);
|
|
||||||
let (_stream, stream_handle) = OutputStream::try_default().unwrap();
|
|
||||||
let sink = Sink::try_new(&stream_handle).unwrap();
|
|
||||||
sink.append(buffer);
|
|
||||||
sink.sleep_until_end();
|
|
||||||
}
|
|
||||||
}).unwrap();
|
|
||||||
}
|
|
||||||
0x02000400..=0x02000401 => { // mouse port
|
|
||||||
let setting = (port & 0x000000FF) as u8;
|
|
||||||
match setting {
|
|
||||||
0x00 => {
|
|
||||||
// we're setting the button states
|
|
||||||
let mut mouse_lock = self.mouse.lock().expect("failed to lock the mouse mutex");
|
|
||||||
mouse_lock.click = word & (1 << 0) != 0;
|
|
||||||
mouse_lock.held = word & (1 << 1) != 0;
|
|
||||||
}
|
|
||||||
0x01 => {
|
|
||||||
// we're setting the position
|
|
||||||
let mut mouse_lock = self.mouse.lock().expect("failed to lock the mouse mutex");
|
|
||||||
let x = (word & 0x0000FFFF) as u16;
|
|
||||||
let y = ((word & 0xFFFF0000) >> 16) as u16;
|
|
||||||
mouse_lock.x = x;
|
|
||||||
mouse_lock.y = y;
|
|
||||||
}
|
|
||||||
_ => panic!("invalid mouse control port"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => return,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
/*if args.len() != 2 {
|
/*if args.len() != 2 {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user