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
|
||||
// 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};
|
||||
|
||||
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)]
|
||||
pub struct Flag {
|
||||
pub carry: bool,
|
||||
|
|
159
src/main.rs
159
src/main.rs
|
@ -1,16 +1,16 @@
|
|||
// main.rs
|
||||
|
||||
pub mod bus;
|
||||
pub mod cpu;
|
||||
pub mod mouse;
|
||||
use cpu::{Bus, Cpu, Memory, Interrupt, IO};
|
||||
use bus::Bus;
|
||||
use cpu::{Cpu, Memory, Interrupt};
|
||||
use mouse::Mouse;
|
||||
|
||||
use std::convert::TryInto;
|
||||
use std::env;
|
||||
use std::fs::read;
|
||||
//use std::process::exit;
|
||||
use std::sync::{Arc, mpsc, Mutex};
|
||||
use std::io::{stdout, Write};
|
||||
use std::thread;
|
||||
|
||||
use log::error;
|
||||
|
@ -21,8 +21,6 @@ use winit::event_loop::{ControlFlow, EventLoop};
|
|||
use winit::window::WindowBuilder;
|
||||
use winit_input_helper::WinitInputHelper;
|
||||
|
||||
use rodio::{OutputStream, buffer::SamplesBuffer, Sink};
|
||||
|
||||
const WIDTH: usize = 640;
|
||||
const HEIGHT: usize = 480;
|
||||
|
||||
|
@ -41,157 +39,6 @@ pub struct Overlay {
|
|||
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() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
/*if args.len() != 2 {
|
||||
|
|
Loading…
Reference in New Issue
Block a user