Skip to content

Commit 5416255

Browse files
virtual filesystem: MMIO-based file I/O for Kov programs in the emulator
1 parent a9ab5ef commit 5416255

9 files changed

Lines changed: 162 additions & 3 deletions

File tree

src/emu/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod cpu;
22
pub mod memory;
3+
pub mod vfs;
34

45
pub use cpu::Cpu;

src/emu/vfs.rs

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// virtual filesystem for the emulator
2+
// MMIO addresses that map to host file operations
3+
// this lets Kov programs read/write files when running in the emulator
4+
5+
use std::collections::HashMap;
6+
7+
const VFS_BASE: u32 = 0xF000_0000;
8+
const VFS_OPEN: u32 = VFS_BASE; // write: ptr to path → read: fd
9+
const VFS_READ: u32 = VFS_BASE + 4; // write: fd | read: byte (-1 = EOF)
10+
const VFS_WRITE: u32 = VFS_BASE + 8; // write: fd << 8 | byte
11+
const VFS_CLOSE: u32 = VFS_BASE + 12; // write: fd
12+
const VFS_READDIR: u32 = VFS_BASE + 16; // write: ptr to path → fills buffer
13+
const VFS_STDOUT: u32 = VFS_BASE + 20; // write: byte → prints to stdout
14+
const VFS_STRLEN: u32 = VFS_BASE + 24; // write: ptr → read: length
15+
16+
pub struct VirtualFS {
17+
pub files: HashMap<u32, FileState>,
18+
next_fd: u32,
19+
pub stdout: Vec<u8>,
20+
pub last_result: u32,
21+
}
22+
23+
struct FileState {
24+
data: Vec<u8>,
25+
pos: usize,
26+
}
27+
28+
impl VirtualFS {
29+
pub fn new() -> Self {
30+
Self {
31+
files: HashMap::new(),
32+
next_fd: 3, // 0=stdin, 1=stdout, 2=stderr
33+
stdout: Vec::new(),
34+
last_result: 0,
35+
}
36+
}
37+
38+
pub fn is_vfs_addr(addr: u32) -> bool {
39+
addr >= VFS_BASE && addr < VFS_BASE + 0x100
40+
}
41+
42+
// preload a file into the VFS (for testing or providing input)
43+
pub fn preload(&mut self, path: &str, data: Vec<u8>) -> u32 {
44+
let fd = self.next_fd;
45+
self.next_fd += 1;
46+
self.files.insert(fd, FileState { data, pos: 0 });
47+
fd
48+
}
49+
50+
pub fn handle_write(&mut self, addr: u32, value: u32, memory: &[u8]) {
51+
match addr {
52+
VFS_OPEN => {
53+
// value is pointer to null-terminated path in memory
54+
let path = read_cstring(memory, value);
55+
match std::fs::read(&path) {
56+
Ok(data) => {
57+
let fd = self.next_fd;
58+
self.next_fd += 1;
59+
self.files.insert(fd, FileState { data, pos: 0 });
60+
self.last_result = fd;
61+
}
62+
Err(_) => {
63+
self.last_result = 0; // 0 = error
64+
}
65+
}
66+
}
67+
VFS_READ => {
68+
let fd = value;
69+
if let Some(file) = self.files.get_mut(&fd) {
70+
if file.pos < file.data.len() {
71+
self.last_result = file.data[file.pos] as u32;
72+
file.pos += 1;
73+
} else {
74+
self.last_result = 0xFFFF_FFFF; // EOF
75+
}
76+
} else {
77+
self.last_result = 0xFFFF_FFFF;
78+
}
79+
}
80+
VFS_WRITE => {
81+
let fd = value >> 8;
82+
let byte = (value & 0xFF) as u8;
83+
if fd == 1 {
84+
self.stdout.push(byte);
85+
}
86+
// for other fds, we'd append to a write buffer
87+
}
88+
VFS_CLOSE => {
89+
self.files.remove(&value);
90+
}
91+
VFS_STDOUT => {
92+
self.stdout.push(value as u8);
93+
if value as u8 == b'\n' {
94+
let line = String::from_utf8_lossy(&self.stdout);
95+
print!("{}", line);
96+
self.stdout.clear();
97+
}
98+
}
99+
_ => {}
100+
}
101+
}
102+
103+
pub fn handle_read(&self, addr: u32) -> u32 {
104+
match addr {
105+
VFS_OPEN | VFS_READ | VFS_STRLEN => self.last_result,
106+
_ => 0,
107+
}
108+
}
109+
}
110+
111+
fn read_cstring(memory: &[u8], addr: u32) -> String {
112+
let mut s = Vec::new();
113+
let mut i = addr as usize;
114+
while i < memory.len() && memory[i] != 0 {
115+
s.push(memory[i]);
116+
i += 1;
117+
}
118+
String::from_utf8_lossy(&s).to_string()
119+
}
120+
121+
#[cfg(test)]
122+
mod tests {
123+
use super::*;
124+
125+
#[test]
126+
fn vfs_stdout() {
127+
let mut vfs = VirtualFS::new();
128+
vfs.handle_write(VFS_STDOUT, b'h' as u32, &[]);
129+
vfs.handle_write(VFS_STDOUT, b'i' as u32, &[]);
130+
assert_eq!(&vfs.stdout, b"hi");
131+
}
132+
133+
#[test]
134+
fn vfs_preload_read() {
135+
let mut vfs = VirtualFS::new();
136+
let fd = vfs.preload("test.txt", b"abc".to_vec());
137+
vfs.handle_write(VFS_READ, fd, &[]);
138+
assert_eq!(vfs.last_result, b'a' as u32);
139+
vfs.handle_write(VFS_READ, fd, &[]);
140+
assert_eq!(vfs.last_result, b'b' as u32);
141+
vfs.handle_write(VFS_READ, fd, &[]);
142+
assert_eq!(vfs.last_result, b'c' as u32);
143+
vfs.handle_write(VFS_READ, fd, &[]);
144+
assert_eq!(vfs.last_result, 0xFFFF_FFFF); // EOF
145+
}
146+
147+
#[test]
148+
fn vfs_addr_detection() {
149+
assert!(VirtualFS::is_vfs_addr(0xF000_0000));
150+
assert!(VirtualFS::is_vfs_addr(0xF000_0020));
151+
assert!(!VirtualFS::is_vfs_addr(0x2000_0000));
152+
}
153+
}
Binary file not shown.
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
C:\Users\akrec\Desktop\kov-lang\tools\kovdocs\target\release\deps\kovdocs.d: src\main.rs
1+
C:\Users\akrec\Desktop\kov-lang\tools\kovdocs\target\release\deps\kovdocs.d: src\main.rs src\config.rs src\highlight.rs src\markdown.rs src\style.css src\app.js
22

3-
C:\Users\akrec\Desktop\kov-lang\tools\kovdocs\target\release\deps\kovdocs.exe: src\main.rs
3+
C:\Users\akrec\Desktop\kov-lang\tools\kovdocs\target\release\deps\kovdocs.exe: src\main.rs src\config.rs src\highlight.rs src\markdown.rs src\style.css src\app.js
44

55
src\main.rs:
6+
src\config.rs:
7+
src\highlight.rs:
8+
src\markdown.rs:
9+
src\style.css:
10+
src\app.js:
108 KB
Binary file not shown.
64 KB
Binary file not shown.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
C:\Users\akrec\Desktop\kov-lang\tools\kovdocs\target\release\kovdocs.exe: C:\Users\akrec\Desktop\kov-lang\tools\kovdocs\src\main.rs
1+
C:\Users\akrec\Desktop\kov-lang\tools\kovdocs\target\release\kovdocs.exe: C:\Users\akrec\Desktop\kov-lang\tools\kovdocs\src\app.js C:\Users\akrec\Desktop\kov-lang\tools\kovdocs\src\config.rs C:\Users\akrec\Desktop\kov-lang\tools\kovdocs\src\highlight.rs C:\Users\akrec\Desktop\kov-lang\tools\kovdocs\src\main.rs C:\Users\akrec\Desktop\kov-lang\tools\kovdocs\src\markdown.rs C:\Users\akrec\Desktop\kov-lang\tools\kovdocs\src\style.css
108 KB
Binary file not shown.
64 KB
Binary file not shown.

0 commit comments

Comments
 (0)