fox32: Implement a very basic disk controller
Any file type can be mounted as a disk, as long as the code running inside fox32 can understand its data.
This commit is contained in:
parent
4f278bc58b
commit
b957b58fb2
810
Cargo.lock
generated
810
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
|
@ -10,6 +10,7 @@ build = "build.rs"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pixels = "0.9.0"
|
pixels = "0.9.0"
|
||||||
|
rfd = "0.7.0"
|
||||||
rodio = "0.14.0"
|
rodio = "0.14.0"
|
||||||
winit = "0.26"
|
winit = "0.26"
|
||||||
winit_input_helper = "0.11"
|
winit_input_helper = "0.11"
|
||||||
|
|
70
src/bus.rs
70
src/bus.rs
|
@ -1,6 +1,6 @@
|
||||||
// bus.rs
|
// bus.rs
|
||||||
|
|
||||||
use crate::{Memory, Mouse};
|
use crate::{DiskController, Memory, Mouse};
|
||||||
|
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::io::{stdout, Write};
|
use std::io::{stdout, Write};
|
||||||
|
@ -10,6 +10,7 @@ use std::thread;
|
||||||
use rodio::{OutputStream, buffer::SamplesBuffer, Sink};
|
use rodio::{OutputStream, buffer::SamplesBuffer, Sink};
|
||||||
|
|
||||||
pub struct Bus {
|
pub struct Bus {
|
||||||
|
pub disk_controller: DiskController,
|
||||||
pub memory: Memory,
|
pub memory: Memory,
|
||||||
pub mouse: Arc<Mutex<Mouse>>,
|
pub mouse: Arc<Mutex<Mouse>>,
|
||||||
}
|
}
|
||||||
|
@ -74,6 +75,31 @@ impl Bus {
|
||||||
_ => panic!("invalid mouse control port"),
|
_ => panic!("invalid mouse control port"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
0x80001000..=0x80002200 => { // disk controller port
|
||||||
|
let address_or_id = (port & 0x00000FFF) as usize;
|
||||||
|
let operation = (port & 0x0000F000) >> 8;
|
||||||
|
|
||||||
|
match operation {
|
||||||
|
0x10 => {
|
||||||
|
// we're reading the current mount state of the specified disk id
|
||||||
|
if address_or_id > 3 {
|
||||||
|
panic!("invalid disk ID");
|
||||||
|
}
|
||||||
|
match &self.disk_controller.disk[address_or_id] {
|
||||||
|
Some(disk) => disk.size as u32, // return size if this disk is mounted
|
||||||
|
None => 0, // return 0 if this disk is not mounted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0x20 => {
|
||||||
|
// we're reading from the sector buffer
|
||||||
|
if address_or_id > 512 {
|
||||||
|
panic!("attempted to read past the end of the disk controller sector buffer");
|
||||||
|
}
|
||||||
|
self.disk_controller.sector_buffer[address_or_id] as u32
|
||||||
|
}
|
||||||
|
_ => panic!("invalid disk controller port"),
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => 0,
|
_ => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,6 +186,48 @@ impl Bus {
|
||||||
_ => panic!("invalid mouse control port"),
|
_ => panic!("invalid mouse control port"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
0x80001000..=0x80004200 => { // disk controller port
|
||||||
|
let address_or_id = (port & 0x00000FFF) as usize;
|
||||||
|
let operation = (port & 0x0000F000) >> 8;
|
||||||
|
|
||||||
|
match operation {
|
||||||
|
0x10 => {
|
||||||
|
// we're requesting a disk to be mounted to the specified disk id
|
||||||
|
if address_or_id > 3 {
|
||||||
|
panic!("invalid disk ID");
|
||||||
|
}
|
||||||
|
let file = self.disk_controller.select_file();
|
||||||
|
match file {
|
||||||
|
Some(file) => self.disk_controller.mount(file, address_or_id as u8),
|
||||||
|
None => {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
0x20 => {
|
||||||
|
// we're writing to the sector buffer
|
||||||
|
if address_or_id > 512 {
|
||||||
|
panic!("attempted to read past the end of the disk controller sector buffer");
|
||||||
|
}
|
||||||
|
self.disk_controller.sector_buffer[address_or_id] = word as u8;
|
||||||
|
}
|
||||||
|
0x30 => {
|
||||||
|
// we're reading the specified sector of the specified disk id into the sector buffer
|
||||||
|
if address_or_id > 3 {
|
||||||
|
panic!("invalid disk ID");
|
||||||
|
}
|
||||||
|
self.disk_controller.set_current_sector(address_or_id as u8, word);
|
||||||
|
self.disk_controller.read_into_buffer(address_or_id as u8);
|
||||||
|
}
|
||||||
|
0x40 => {
|
||||||
|
// we're writing the specified sector to the specified disk id from the sector buffer
|
||||||
|
if address_or_id > 3 {
|
||||||
|
panic!("invalid disk ID");
|
||||||
|
}
|
||||||
|
self.disk_controller.set_current_sector(address_or_id as u8, word);
|
||||||
|
self.disk_controller.write_from_buffer(address_or_id as u8);
|
||||||
|
}
|
||||||
|
_ => panic!("invalid disk controller port"),
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => return,
|
_ => return,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
79
src/disk.rs
Normal file
79
src/disk.rs
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
// disk.rs
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{Seek, SeekFrom, Read, Write};
|
||||||
|
use rfd::FileDialog;
|
||||||
|
|
||||||
|
pub struct Disk {
|
||||||
|
file: File,
|
||||||
|
pub size: u64,
|
||||||
|
current_sector: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Disk {
|
||||||
|
pub fn new(file: File) -> Self {
|
||||||
|
Disk {
|
||||||
|
size: file.metadata().unwrap().len(),
|
||||||
|
file,
|
||||||
|
current_sector: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DiskController {
|
||||||
|
pub disk: [Option<Disk>; 4],
|
||||||
|
pub sector_buffer: [u8; 512],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiskController {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
DiskController {
|
||||||
|
disk: [None, None, None, None],
|
||||||
|
sector_buffer: [0; 512]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn select_file(&self) -> Option<File> {
|
||||||
|
let path = FileDialog::new()
|
||||||
|
.add_filter("disk image", &["img", "dsk"])
|
||||||
|
.add_filter("f32 binary", &["f32"])
|
||||||
|
.add_filter("raw binary", &["bin"])
|
||||||
|
.pick_file();
|
||||||
|
match path {
|
||||||
|
Some(path) => Some(File::open(path).unwrap()),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn mount(&mut self, file: File, disk_id: u8) {
|
||||||
|
self.disk[disk_id as usize] = Some(Disk::new(file));
|
||||||
|
}
|
||||||
|
pub fn unmount(&mut self, disk_id: u8) {
|
||||||
|
self.disk[disk_id as usize] = None;
|
||||||
|
}
|
||||||
|
pub fn get_size(&mut self, disk_id: u8) -> u64 {
|
||||||
|
let disk = self.disk[disk_id as usize].as_mut().expect("attempted to access unmounted disk");
|
||||||
|
disk.size
|
||||||
|
}
|
||||||
|
pub fn set_current_sector(&mut self, disk_id: u8, sector: u32) {
|
||||||
|
let disk = self.disk[disk_id as usize].as_mut().expect("attempted to access unmounted disk");
|
||||||
|
disk.current_sector = sector;
|
||||||
|
disk.file.seek(SeekFrom::Start(sector as u64 * 512)).unwrap();
|
||||||
|
}
|
||||||
|
pub fn get_current_sector(&mut self, disk_id: u8) -> u32 {
|
||||||
|
let disk = self.disk[disk_id as usize].as_mut().expect("attempted to access unmounted disk");
|
||||||
|
disk.current_sector
|
||||||
|
}
|
||||||
|
pub fn read_into_buffer(&mut self, disk_id: u8) -> usize {
|
||||||
|
let disk = self.disk[disk_id as usize].as_mut().expect("attempted to access unmounted disk");
|
||||||
|
let mut temp_buffer = [0u8; 512];
|
||||||
|
|
||||||
|
let number_of_bytes_read = disk.file.read(&mut temp_buffer).unwrap();
|
||||||
|
self.sector_buffer = temp_buffer;
|
||||||
|
number_of_bytes_read
|
||||||
|
}
|
||||||
|
pub fn write_from_buffer(&mut self, disk_id: u8) -> usize {
|
||||||
|
let disk = self.disk[disk_id as usize].as_mut().expect("attempted to access unmounted disk");
|
||||||
|
|
||||||
|
let number_of_bytes_written = disk.file.write(&mut self.sector_buffer).unwrap();
|
||||||
|
number_of_bytes_written
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,10 +2,12 @@
|
||||||
|
|
||||||
pub mod bus;
|
pub mod bus;
|
||||||
pub mod cpu;
|
pub mod cpu;
|
||||||
|
pub mod disk;
|
||||||
pub mod memory;
|
pub mod memory;
|
||||||
pub mod mouse;
|
pub mod mouse;
|
||||||
use bus::Bus;
|
use bus::Bus;
|
||||||
use cpu::{Cpu, Interrupt};
|
use cpu::{Cpu, Interrupt};
|
||||||
|
use disk::DiskController;
|
||||||
use memory::Memory;
|
use memory::Memory;
|
||||||
use mouse::Mouse;
|
use mouse::Mouse;
|
||||||
|
|
||||||
|
@ -92,7 +94,8 @@ fn main() {
|
||||||
|
|
||||||
let cpu_mouse = Arc::clone(&mouse);
|
let cpu_mouse = Arc::clone(&mouse);
|
||||||
|
|
||||||
let bus = Bus { memory, mouse: cpu_mouse };
|
let disk_controller = DiskController::new();
|
||||||
|
let bus = Bus { disk_controller, memory, mouse: cpu_mouse };
|
||||||
Cpu::new(bus)
|
Cpu::new(bus)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user