serial working

This commit is contained in:
2026-03-17 02:17:03 +00:00
parent ffdd392003
commit b9d0f4fdd4
11 changed files with 1193 additions and 133 deletions
+5
View File
@@ -144,6 +144,11 @@ fn assemble(src: &Path) -> Result<Vec<Instruction>, AssembleError> {
let mut nodes = program.nodes.clone(); let mut nodes = program.nodes.clone();
println!("PRE LINK");
for node in &nodes {
println!("{:?}", node);
}
create_sections(&mut nodes)?; create_sections(&mut nodes)?;
resolve_symbols(&mut nodes)?; resolve_symbols(&mut nodes)?;
@@ -272,14 +272,14 @@ impl Emulator {
#[inline] #[inline]
fn interrupt(&mut self, int: Interrupt) { fn interrupt(&mut self, int: Interrupt) {
println!("Interrupt while at address {}", self.reg(Register::Pcx)); println!("Interrupt while at address {:04X}", self.reg(Register::Pcx));
self.push(Register::Pcx); self.push(Register::Pcx);
*self.mut_reg(Register::Pcx) = *self.mut_reg(Register::Pcx) =
self.mem_read_word(self.reg(Register::Idr) + int.code() as u32 * 4); self.mem_read_word(self.reg(Register::Idr) + int.code() as u32 * 4);
println!( println!(
"Jumping to interrupt at address {}", "Jumping to interrupt at address {:04X}",
self.reg(Register::Pcx) self.reg(Register::Pcx)
); );
} }
@@ -498,7 +498,7 @@ impl Emulator {
*self.mut_reg(Register::Pcx) = self.reg(Register::Ret); *self.mut_reg(Register::Pcx) = self.reg(Register::Ret);
println!( println!(
"Returning from interrupt to address {}", "Returning from interrupt to address {:04X}",
self.reg(Register::Pcx) self.reg(Register::Pcx)
); );
} }
@@ -12,7 +12,6 @@ pub struct SharedState {
pub reseting: AtomicBool, pub reseting: AtomicBool,
pub paused: AtomicBool, pub paused: AtomicBool,
pub update_req: AtomicBool, pub update_req: AtomicBool,
pub interrupt_queue: mpsc::Sender<Interrupt>, pub interrupt_queue: mpsc::Sender<Interrupt>,
} }
@@ -95,7 +95,12 @@ impl Component for Controller {
let pcx = state.registers[Register::Pcx as usize]; let pcx = state.registers[Register::Pcx as usize];
let clock = state.clock; let clock = state.clock;
let time = state.time.as_micros(); let time = state.time.as_micros();
let mips = state.clock as u128 / time;
let mips = if time != 0 {
state.clock as u128 / time
} else {
0
};
ui.label(format!("Clock: {clock}")); ui.label(format!("Clock: {clock}"));
ui.label(format!("Pcx: 0x{pcx:08X}")); ui.label(format!("Pcx: 0x{pcx:08X}"));
@@ -101,11 +101,11 @@ impl Component for MemoryInspector {
ui.end_row(); ui.end_row();
// Memory data (8 bytes per row) // Memory data (8 bytes per row)
for (row, word) in (0..self.view_size / 4) for (offset, word) in (0..self.view_size / 4)
.map(|i| i * 4) .map(|i| i * 4)
.map(|i| (i, self.memory.read_word(self.view_addr + i))) .map(|i| (i, self.memory.read_word(self.view_addr + i)))
{ {
let row_address = self.view_addr + (row * 4); let row_address = self.view_addr + offset;
ui.monospace(format!("0x{row_address:08X} ({row_address})")); ui.monospace(format!("0x{row_address:08X} ({row_address})"));
for byte in word.to_le_bytes() { for byte in word.to_le_bytes() {
ui.monospace(format!("{byte:02X}")); ui.monospace(format!("{byte:02X}"));
+25 -11
View File
@@ -1,7 +1,10 @@
use std::sync::{ use std::{
Arc, collections::VecDeque,
atomic::Ordering, sync::{
mpsc::{Receiver, Sender}, Arc,
atomic::Ordering,
mpsc::{Receiver, Sender},
},
}; };
use super::Component; use super::Component;
@@ -32,7 +35,13 @@ impl Serial {
tx: Sender<u8>, tx: Sender<u8>,
rx: Receiver<u8>, rx: Receiver<u8>,
) { ) {
let mut write_buffer: VecDeque<u8> = VecDeque::new();
loop { loop {
while let Ok(byte) = rx.try_recv() {
write_buffer.push_back(byte);
}
let ser_out_valid = mem.read_byte(uart_base + 0); let ser_out_valid = mem.read_byte(uart_base + 0);
// Kernel => emulator: valid flag in byte 0, data in byte 1 // Kernel => emulator: valid flag in byte 0, data in byte 1
if ser_out_valid == 0x01 { if ser_out_valid == 0x01 {
@@ -41,14 +50,19 @@ impl Serial {
mem.write_byte(uart_base, 0x00); // clear the whole word mem.write_byte(uart_base, 0x00); // clear the whole word
} }
// Emulator => kernel: valid flag in byte 2, data in byte 3 if !write_buffer.is_empty() {
let ser_in_valid = mem.read_byte(uart_base + 2); // Emulator => kernel: valid flag in byte 2, data in byte 3
if ser_in_valid == 0x00 { let ser_in_valid = mem.read_byte(uart_base + 2);
if let Ok(byte) = rx.try_recv() { if ser_in_valid == 0x00 {
state.interrupt_queue.send(Interrupt::SerialIn).unwrap(); if let Some(byte) = write_buffer.pop_front() {
mem.write_byte(uart_base + 3, byte); mem.write_byte(uart_base + 3, byte);
mem.write_byte(uart_base + 2, 0x01); mem.write_byte(uart_base + 2, 0x01);
}
} }
std::thread::sleep(std::time::Duration::from_millis(2));
state.interrupt_queue.send(Interrupt::SerialIn).unwrap();
} }
std::thread::sleep(std::time::Duration::from_millis(1)); std::thread::sleep(std::time::Duration::from_millis(1));
+1 -1
View File
@@ -32,7 +32,7 @@ _loop_start:
setup_io: func setup_io: func
push rg0 push rg0
lwi serial::serial_isr, rg0 lwi serial::isr, rg0
stw rg0, idr, 128 // 32*4, interrupt idx 32 stw rg0, idr, 128 // 32*4, interrupt idx 32
pop rg0 pop rg0
Binary file not shown.
+61 -95
View File
@@ -2,17 +2,21 @@
dw UART: 0x40000 dw UART: 0x40000
// Reserve space for our read buffer // Reserve space for our read buffer
resb SERIAL_BUFFER: 1024 resb SERIAL_BUFFER: 1025 // final byte is a null terminator
dw SER_READ_PTR: 0 dw SER_READ_PTR: 0
dw SER_WRITE_PTR: 0 dw SER_WRITE_PTR: 0
serial_init: func reset: func
push rg0
lwi SERIAL_BUFFER, rg0 lwi SERIAL_BUFFER, rg0
stw rg0, SER_READ_PTR, 0 stw rg0, SER_READ_PTR, 0
stw rg0, SER_WRITE_PTR, 0 stw rg0, SER_WRITE_PTR, 0
pop rg0
return return
serial_isr: isr:
push rg0 push rg0
push rg1 push rg1
push rg2 push rg2
@@ -21,10 +25,11 @@ serial_isr:
ldb rg0, rg1, 2 // load ser_in_valid flag ldb rg0, rg1, 2 // load ser_in_valid flag
// no serial input // no serial input
jez rg1, _serial_isr_end jez rg1, _isr_end
// we should have a valid byte to read at offset 3 // we should have a valid byte to read at offset 3
ldb rg0, rg1, 3 // data byte ldb rg0, rg1, 3 // data byte
stb zero, rg0, 2 // unset ser_in_valid
// write data to ptr and increment // write data to ptr and increment
ldw SER_WRITE_PTR, rg2 ldw SER_WRITE_PTR, rg2
@@ -37,133 +42,94 @@ serial_isr:
// if ptr != buff+1024, nowrap. // if ptr != buff+1024, nowrap.
ine rg1, rg2, rg1 ine rg1, rg2, rg1
jnz rg1, _serial_isr_nowrap jnz rg1, _isr_nowrap
lwi SERIAL_BUFFER, rg2 // set the pointer lwi SERIAL_BUFFER, rg2 // set the pointer
_serial_isr_nowrap: _isr_nowrap:
stw rg2, SER_WRITE_PTR stw rg2, SER_WRITE_PTR
_serial_isr_end: _isr_end:
pop rg0
pop rg1
pop rg2 pop rg2
pop rg1
pop rg0
iret iret
// serial_readline: waits until a null byte is received
// returns nothing, data is in SERIAL_BUFFER starting at SER_READ_PTR
// read_byte: emulator → kernel readline: func
// reads data from base+0x00, valid flag at base+0x01
read_byte: func
push rg0 push rg0
push rg1 push rg1
push rg2 _readline_wait:
ldw UART, rg1 // check if write ptr == read ptr (buffer empty)
_serial_read_wait: ldw SER_WRITE_PTR, rg0
ldb rg1, rg0, 2 // base+0x02 = read valid flag ldw SER_READ_PTR, rg1
lli 0x01, rg2 ieq rg0, rg1, rg0
ieq rg0, rg2, rg2 jnz rg0, _readline_halt // nothing written yet, halt
jnz rg2, _serial_read_ready
// check if the byte just before write ptr is null
ldw SER_WRITE_PTR, rg0
// handle wrap: if write ptr == SERIAL_BUFFER, check last byte of buffer
lwi SERIAL_BUFFER, rg1
ieq rg0, rg1, rg1
jnz rg1, _readline_check_wrap
// normal case: read byte at write_ptr - 1
subi rg0, 1, rg0
ldb rg0, rg1, 0
jez rg1, _readline_done
jmp _readline_halt
_readline_check_wrap:
// write ptr is at start of buffer, last byte is at SERIAL_BUFFER + 1023
lwi SERIAL_BUFFER, rg0
addi rg0, 1023, rg0
ldb rg0, rg1, 0
jez rg1, _readline_done
_readline_halt:
hlt hlt
jmp _serial_read_wait jmp _readline_wait
_serial_read_ready:
ldb rg1, rg0, 3 // base+0x03 = data byte _readline_done:
stb zero, rg1, 2 // clear read valid flag
stb rg0, bpr, 8 // return byte
pop rg2
pop rg1 pop rg1
pop rg0 pop rg0
return return
// _serial_send: kernel → emulator // _serial_send: trashes rg2, rg3, rg4, rg5
// writes data to base+0x01, valid flag to base+0x00 // byte to send in rg0
_serial_send: _serial_send:
push rg0
push rg2
push rg3
push rg4
push rg5
ldw UART, rg5 ldw UART, rg5
_serial_wait: _serial_wait:
ldb rg5, rg2, 0 // base+0x00 = ser_out_valid ldb rg5, rg2, 0
lli 0x01, rg3 lli 0x01, rg3
ieq rg2, rg3, rg4 ieq rg2, rg3, rg4
jnz rg4, _serial_wait // wait while emulator hasn't consumed yet jnz rg4, _serial_wait
stb rg0, rg5, 1 // base+0x01 = ser_out_data stb rg0, rg5, 1
lli 0x01, rg2 stb rg3, rg5, 0 // rg3 is still 0x01 from above
stb rg2, rg5, 0 // base+0x00 = ser_out_valid = 1
pop rg5
pop rg4
pop rg3
pop rg2
pop rg0
ret ret
// ------------------------------------------
// prints the null-terminated string at addr(arg[0])
print: func print: func
push rg0 push rg0
push rg1 push rg1
push rg2 ldw bpr, rg0, 8
ldw bpr, rg0, 8 // load string address from arg
_serial_print_loop: _serial_print_loop:
ldb rg0, rg1 // load byte ldb rg0, rg1
ieq rg1, zero, rg2 // null terminator? jez rg1, _serial_print_end
jnz rg2, _serial_print_end push rg0
push rg0 // save string pointer
mov rg1, rg0 mov rg1, rg0
call _serial_send call _serial_send
pop rg0 pop rg0
addi rg0, 1, rg0 addi rg0, 1, rg0
jmp _serial_print_loop jmp _serial_print_loop
_serial_print_end: _serial_print_end:
pop rg2
pop rg1 pop rg1
pop rg0 pop rg0
jmp _serial_end return
// ------------------------------------------
// prints the last byte of arg[0]
print_byte: func print_byte: func
push rg0 push rg0
ldw bpr, rg0, 8 ldw bpr, rg0, 8
call _serial_send call _serial_send
pop rg0 pop rg0
jmp _serial_end
// ------------------------------------------
_serial_end:
return
// ------------------------------------------
// reads up to rg1 bytes into buffer at rg2
// args: buf_size @ bpr+8, buf_addr @ bpr+12
// returns: 0 in bpr+8 on success, 1 on nullptr error
buf_read: func
push rg0
push rg1
push rg2
push rg3
ldw bpr, rg1, 8 // buf size
ldw bpr, rg2, 12 // buf addr
jez rg2, _buf_read_err // return err if nullptr
_buf_read_loop:
jez rg1, _buf_read_end
call read_byte
ldw bpr, rg3, 8 // read return value from frame
stb rg3, rg2 // store into buffer
addi rg2, 1, rg2
subi rg1, 1, rg1
jmp _buf_read_loop
_buf_read_end:
stw zero, bpr, 8 // return 0 (success)
pop rg3
pop rg2
pop rg1
pop rg0
return
_buf_read_err:
lli 1, rg0
stw rg0, bpr, 8 // return 1 (error)
pop rg3
pop rg2
pop rg1
pop rg0
return return
+15 -16
View File
@@ -2,40 +2,39 @@ include serial: "./serial.dsa"
include idt: "./idt.dsa" include idt: "./idt.dsa"
include print: "./print.dsa" include print: "./print.dsa"
dw stack: 0x1000 dw stack: 0x10000
_init: _init:
ldw stack, bpr ldw stack, bpr
mov bpr, spr mov bpr, spr
call idt::setup_base call idt::setup_base
call idt::setup_io call idt::setup_io
db hello2: "hello2" call serial::reset
db hello: "Test message, hello world etc etc." db hello: "Test message, hello world etc etc."
main: main:
lwi hello, rg0 //lwi hello, rg0
push rg0 //push rg0
call serial::print //call serial::print
pop zero //pop zero
lwi hello, rg0 // lwi hello, rg0
push rg0 // push rg0
call print::print // call print::print
pop zero // pop zero
//lwi buff, rg0 //lwi buff, rg0
//lwi 32, rg1 //lwi 32, rg1
//push rg0 //push rg0
//push rg1 //push rg1
call serial::readline
lwi serial::SERIAL_BUFFER, rg0 lwi serial::SERIAL_BUFFER, rg0
push rg0 push rg0
call print::print call serial::print
pop zero
lwi hello2, rg0
push rg0
call print::print
pop zero pop zero
call serial::reset
hlt hlt
jmp main jmp main
+1072
View File
File diff suppressed because it is too large Load Diff