serial working
This commit is contained in:
@@ -144,6 +144,11 @@ fn assemble(src: &Path) -> Result<Vec<Instruction>, AssembleError> {
|
||||
|
||||
let mut nodes = program.nodes.clone();
|
||||
|
||||
println!("PRE LINK");
|
||||
for node in &nodes {
|
||||
println!("{:?}", node);
|
||||
}
|
||||
|
||||
create_sections(&mut nodes)?;
|
||||
resolve_symbols(&mut nodes)?;
|
||||
|
||||
|
||||
@@ -272,14 +272,14 @@ impl Emulator {
|
||||
|
||||
#[inline]
|
||||
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.mut_reg(Register::Pcx) =
|
||||
self.mem_read_word(self.reg(Register::Idr) + int.code() as u32 * 4);
|
||||
|
||||
println!(
|
||||
"Jumping to interrupt at address {}",
|
||||
"Jumping to interrupt at address {:04X}",
|
||||
self.reg(Register::Pcx)
|
||||
);
|
||||
}
|
||||
@@ -498,7 +498,7 @@ impl Emulator {
|
||||
*self.mut_reg(Register::Pcx) = self.reg(Register::Ret);
|
||||
|
||||
println!(
|
||||
"Returning from interrupt to address {}",
|
||||
"Returning from interrupt to address {:04X}",
|
||||
self.reg(Register::Pcx)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ pub struct SharedState {
|
||||
pub reseting: AtomicBool,
|
||||
pub paused: AtomicBool,
|
||||
pub update_req: AtomicBool,
|
||||
|
||||
pub interrupt_queue: mpsc::Sender<Interrupt>,
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,12 @@ impl Component for Controller {
|
||||
let pcx = state.registers[Register::Pcx as usize];
|
||||
let clock = state.clock;
|
||||
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!("Pcx: 0x{pcx:08X}"));
|
||||
|
||||
@@ -101,11 +101,11 @@ impl Component for MemoryInspector {
|
||||
ui.end_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, 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})"));
|
||||
for byte in word.to_le_bytes() {
|
||||
ui.monospace(format!("{byte:02X}"));
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use std::sync::{
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
sync::{
|
||||
Arc,
|
||||
atomic::Ordering,
|
||||
mpsc::{Receiver, Sender},
|
||||
},
|
||||
};
|
||||
|
||||
use super::Component;
|
||||
@@ -32,7 +35,13 @@ impl Serial {
|
||||
tx: Sender<u8>,
|
||||
rx: Receiver<u8>,
|
||||
) {
|
||||
let mut write_buffer: VecDeque<u8> = VecDeque::new();
|
||||
|
||||
loop {
|
||||
while let Ok(byte) = rx.try_recv() {
|
||||
write_buffer.push_back(byte);
|
||||
}
|
||||
|
||||
let ser_out_valid = mem.read_byte(uart_base + 0);
|
||||
// Kernel => emulator: valid flag in byte 0, data in byte 1
|
||||
if ser_out_valid == 0x01 {
|
||||
@@ -41,16 +50,21 @@ impl Serial {
|
||||
mem.write_byte(uart_base, 0x00); // clear the whole word
|
||||
}
|
||||
|
||||
if !write_buffer.is_empty() {
|
||||
// Emulator => kernel: valid flag in byte 2, data in byte 3
|
||||
let ser_in_valid = mem.read_byte(uart_base + 2);
|
||||
if ser_in_valid == 0x00 {
|
||||
if let Ok(byte) = rx.try_recv() {
|
||||
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 + 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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ _loop_start:
|
||||
setup_io: func
|
||||
push rg0
|
||||
|
||||
lwi serial::serial_isr, rg0
|
||||
lwi serial::isr, rg0
|
||||
stw rg0, idr, 128 // 32*4, interrupt idx 32
|
||||
|
||||
pop rg0
|
||||
|
||||
Binary file not shown.
+61
-95
@@ -2,17 +2,21 @@
|
||||
dw UART: 0x40000
|
||||
|
||||
// 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_WRITE_PTR: 0
|
||||
|
||||
serial_init: func
|
||||
reset: func
|
||||
push rg0
|
||||
|
||||
lwi SERIAL_BUFFER, rg0
|
||||
stw rg0, SER_READ_PTR, 0
|
||||
stw rg0, SER_WRITE_PTR, 0
|
||||
|
||||
pop rg0
|
||||
return
|
||||
|
||||
serial_isr:
|
||||
isr:
|
||||
push rg0
|
||||
push rg1
|
||||
push rg2
|
||||
@@ -21,10 +25,11 @@ serial_isr:
|
||||
ldb rg0, rg1, 2 // load ser_in_valid flag
|
||||
|
||||
// no serial input
|
||||
jez rg1, _serial_isr_end
|
||||
jez rg1, _isr_end
|
||||
|
||||
// we should have a valid byte to read at offset 3
|
||||
ldb rg0, rg1, 3 // data byte
|
||||
stb zero, rg0, 2 // unset ser_in_valid
|
||||
|
||||
// write data to ptr and increment
|
||||
ldw SER_WRITE_PTR, rg2
|
||||
@@ -37,133 +42,94 @@ serial_isr:
|
||||
|
||||
// if ptr != buff+1024, nowrap.
|
||||
ine rg1, rg2, rg1
|
||||
jnz rg1, _serial_isr_nowrap
|
||||
jnz rg1, _isr_nowrap
|
||||
|
||||
lwi SERIAL_BUFFER, rg2 // set the pointer
|
||||
|
||||
_serial_isr_nowrap:
|
||||
_isr_nowrap:
|
||||
stw rg2, SER_WRITE_PTR
|
||||
|
||||
_serial_isr_end:
|
||||
pop rg0
|
||||
pop rg1
|
||||
_isr_end:
|
||||
pop rg2
|
||||
pop rg1
|
||||
pop rg0
|
||||
iret
|
||||
|
||||
|
||||
|
||||
// read_byte: emulator → kernel
|
||||
// reads data from base+0x00, valid flag at base+0x01
|
||||
read_byte: func
|
||||
// serial_readline: waits until a null byte is received
|
||||
// returns nothing, data is in SERIAL_BUFFER starting at SER_READ_PTR
|
||||
readline: func
|
||||
push rg0
|
||||
push rg1
|
||||
push rg2
|
||||
ldw UART, rg1
|
||||
_serial_read_wait:
|
||||
ldb rg1, rg0, 2 // base+0x02 = read valid flag
|
||||
lli 0x01, rg2
|
||||
ieq rg0, rg2, rg2
|
||||
jnz rg2, _serial_read_ready
|
||||
_readline_wait:
|
||||
// check if write ptr == read ptr (buffer empty)
|
||||
ldw SER_WRITE_PTR, rg0
|
||||
ldw SER_READ_PTR, rg1
|
||||
ieq rg0, rg1, rg0
|
||||
jnz rg0, _readline_halt // nothing written yet, halt
|
||||
|
||||
// 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
|
||||
jmp _serial_read_wait
|
||||
_serial_read_ready:
|
||||
ldb rg1, rg0, 3 // base+0x03 = data byte
|
||||
stb zero, rg1, 2 // clear read valid flag
|
||||
stb rg0, bpr, 8 // return byte
|
||||
pop rg2
|
||||
jmp _readline_wait
|
||||
|
||||
_readline_done:
|
||||
pop rg1
|
||||
pop rg0
|
||||
return
|
||||
|
||||
// _serial_send: kernel → emulator
|
||||
// writes data to base+0x01, valid flag to base+0x00
|
||||
// _serial_send: trashes rg2, rg3, rg4, rg5
|
||||
// byte to send in rg0
|
||||
_serial_send:
|
||||
push rg0
|
||||
push rg2
|
||||
push rg3
|
||||
push rg4
|
||||
push rg5
|
||||
ldw UART, rg5
|
||||
_serial_wait:
|
||||
ldb rg5, rg2, 0 // base+0x00 = ser_out_valid
|
||||
ldb rg5, rg2, 0
|
||||
lli 0x01, rg3
|
||||
ieq rg2, rg3, rg4
|
||||
jnz rg4, _serial_wait // wait while emulator hasn't consumed yet
|
||||
stb rg0, rg5, 1 // base+0x01 = ser_out_data
|
||||
lli 0x01, rg2
|
||||
stb rg2, rg5, 0 // base+0x00 = ser_out_valid = 1
|
||||
pop rg5
|
||||
pop rg4
|
||||
pop rg3
|
||||
pop rg2
|
||||
pop rg0
|
||||
jnz rg4, _serial_wait
|
||||
stb rg0, rg5, 1
|
||||
stb rg3, rg5, 0 // rg3 is still 0x01 from above
|
||||
ret
|
||||
// ------------------------------------------
|
||||
// prints the null-terminated string at addr(arg[0])
|
||||
|
||||
print: func
|
||||
push rg0
|
||||
push rg1
|
||||
push rg2
|
||||
ldw bpr, rg0, 8 // load string address from arg
|
||||
ldw bpr, rg0, 8
|
||||
_serial_print_loop:
|
||||
ldb rg0, rg1 // load byte
|
||||
ieq rg1, zero, rg2 // null terminator?
|
||||
jnz rg2, _serial_print_end
|
||||
push rg0 // save string pointer
|
||||
ldb rg0, rg1
|
||||
jez rg1, _serial_print_end
|
||||
push rg0
|
||||
mov rg1, rg0
|
||||
call _serial_send
|
||||
pop rg0
|
||||
addi rg0, 1, rg0
|
||||
jmp _serial_print_loop
|
||||
_serial_print_end:
|
||||
pop rg2
|
||||
pop rg1
|
||||
pop rg0
|
||||
jmp _serial_end
|
||||
// ------------------------------------------
|
||||
// prints the last byte of arg[0]
|
||||
return
|
||||
|
||||
print_byte: func
|
||||
push rg0
|
||||
ldw bpr, rg0, 8
|
||||
call _serial_send
|
||||
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
|
||||
|
||||
@@ -2,40 +2,39 @@ include serial: "./serial.dsa"
|
||||
include idt: "./idt.dsa"
|
||||
include print: "./print.dsa"
|
||||
|
||||
dw stack: 0x1000
|
||||
dw stack: 0x10000
|
||||
_init:
|
||||
ldw stack, bpr
|
||||
mov bpr, spr
|
||||
call idt::setup_base
|
||||
call idt::setup_io
|
||||
|
||||
db hello2: "hello2"
|
||||
call serial::reset
|
||||
|
||||
db hello: "Test message, hello world etc etc."
|
||||
main:
|
||||
lwi hello, rg0
|
||||
push rg0
|
||||
call serial::print
|
||||
pop zero
|
||||
//lwi hello, rg0
|
||||
//push rg0
|
||||
//call serial::print
|
||||
//pop zero
|
||||
|
||||
lwi hello, rg0
|
||||
push rg0
|
||||
call print::print
|
||||
pop zero
|
||||
// lwi hello, rg0
|
||||
// push rg0
|
||||
// call print::print
|
||||
// pop zero
|
||||
|
||||
//lwi buff, rg0
|
||||
//lwi 32, rg1
|
||||
//push rg0
|
||||
//push rg1
|
||||
|
||||
call serial::readline
|
||||
|
||||
lwi serial::SERIAL_BUFFER, rg0
|
||||
push rg0
|
||||
call print::print
|
||||
pop zero
|
||||
|
||||
lwi hello2, rg0
|
||||
push rg0
|
||||
call print::print
|
||||
call serial::print
|
||||
pop zero
|
||||
|
||||
call serial::reset
|
||||
hlt
|
||||
jmp main
|
||||
|
||||
Reference in New Issue
Block a user