found a cause of a memory bug in emulator - fix is TODO (#6) - continued working on brainf interpreter. we really need better debugging tools tbh.

This commit is contained in:
2025-06-23 00:31:09 +01:00
parent b8091222a4
commit ddd0c27893
6 changed files with 125 additions and 62 deletions
+1 -1
View File
@@ -183,7 +183,7 @@ fn expand_stx(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError>
let base = expect_type!(current.arg(0).unwrap(), Register)?;
let dest = expect_type!(current.arg(1).unwrap(), Symbol)?;
let offset = expect_type!(current.arg(2).unwrap(), Immediate)?;
let temp = Token::Register(Register::Rgf);
let temp = Token::Register(Register::Acc);
nodes.extend(vec![
node!(current.label(), Opcode::Lli, dest, temp),
+2 -2
View File
@@ -326,8 +326,8 @@ impl FromStr for Opcode {
"include" => Ok(Self::Include),
"call" => Ok(Self::Call),
"return" => Ok(Self::Return),
"pusha" => Ok(Self::Push),
"popa" => Ok(Self::Pop),
"pusha" => Ok(Self::Pusha),
"popa" => Ok(Self::Popa),
_ => Err(OpcodeFromStrError::InvalidRegister("unknown opcode")),
}
}
+3
View File
@@ -72,6 +72,9 @@ impl MemoryUnit for MainStore {
fn read_word(&mut self, addr: u32) -> u32 {
let (block_addr, offset) = Self::segment_addr(addr);
println!("reading word from {block_addr:x?} + {offset}");
let block = self.mut_block(block_addr);
let mut bytes = [0; 4];
bytes[0] = block.data[offset as usize];
@@ -21,6 +21,10 @@ pub struct Processor {
pub dustbin: u32,
}
fn log(message: &str) {
println!("\x1b[32mINFO:\x1b[0m {message}");
}
#[allow(clippy::needless_pass_by_ref_mut)]
impl Processor {
#[must_use]
@@ -62,12 +66,10 @@ impl Processor {
// Decode and execute the instruction.
let instruction = Instruction::decode(val)?;
println!("Executing instruction: {instruction}");
log(&instruction.to_string());
instruction.execute(self);
println!("ok!");
Ok((addr, instruction))
}
+114 -56
View File
@@ -1,10 +1,12 @@
// a simple brainf##k interpreter, because I already wrote a compiler lol.
// a simple brainf##k interpreter,
// because I already wrote a compiler lol.
include print "./lib/print.dsa"
// "print hello world"
db program: "++++++[>++++++++++++<-]>.>++++++++++[>++++++++++<-]>+.+++++++..+++.>++++[>+++++++++++<-]>.<+++[>----<-]>.<<<<<+++[>+++++<-]>.>>.+++.------.--------.>>+."
db error: "Invalid Instruction!"
dw stack: 0x10000
dw input: 0x30000
@@ -21,25 +23,32 @@ start:
// rg0 is our instruction pointer
// rg1 is our data pointer
// acc is the value at the data pointer
// rg2 is the value at the data pointer
// rg3 stores the current instruction
// rg4 is the expression nesting level.
lui rg8, 43 // + = 43 increment
lui rg9, 45 // - = 45 decrement
lui rga, 62 // > = 62 increment pointer
lui rgb, 60 // < = 60 decrement pointer
lui rgc, 46 // . = 46 output
lui rgd, 44 // , = 44 input
lui rge, 91 // [ = 91 loop start
lui rgf, 93 // ] = 93 loop end
lli 43, rg8 // + = 43 increment
lli 45, rg9 // - = 45 decrement
lli 62, rga // > = 62 increment pointer
lli 60, rgb // < = 60 decrement pointer
lli 46, rgc // . = 46 output
lli 44, rgd // , = 44 input
lli 91, rge // [ = 91 loop start
lli 93, rgf // ] = 93 loop end
loop:
loop_start:
// load the current instruction into rg3
ldb rg0, rg3
inc rg0
// pusha 2
// push rg3
// call print::print_byte
// pop zero
// popa 2
// switch on the instruction
// all cases will return to either loop_start or loop_end
cmp rg3, rg8
jeq increment
cmp rg3, rg9
@@ -56,93 +65,142 @@ loop:
jeq expr_start
cmp rg3, rgf
jeq expr_end
cmp rg3, zero
jeq end
// if we get here, we don't know what the instruction is
lwi error, rg0
push rg0
call print::print
pop zero
end:
lwi error, rg2
pusha 2
push rg2
call print::print
pop zero
popa 2
hlt
loop_end:
inc rg0
jmp loop_start
// ------------------------------------------
// increment the current cell
increment:
inc acc
jmp loop
inc rg2
jmp loop_end
// ------------------------------------------
// decrement the current cell
decrement:
dec acc
jmp loop
dec rg2
jmp loop_end
// ------------------------------------------
// increment the pointer
inc_ptr:
stw acc, rg1
stw rg2, rg1
addi rg1, 4
ldw rg1, acc
jmp loop
ldw rg1, rg2
jmp loop_end
// ------------------------------------------
// decrement the pointer
dec_ptr:
stw rg1, acc
stw rg1, rg2
subi rg1, 4
ldw rg1, acc
jmp loop
ldw rg1, rg2
jmp loop_end
// ------------------------------------------
// print the byte in the current cell
output:
push acc
pusha 2
push rg2
call print::print_byte
pop zero
jmp loop
popa 2
jmp loop_end
// ------------------------------------------
// read a byte into the current cell
input:
ldw input, acc
jmp loop
ldw input, rg2
jmp loop_end
// ------------------------------------------
// handle an open bracket instruction
expr_start:
cmp acc, zero
jeq _traverse_right
inc rg4
jmp loop
cmp rg2, zero
jne loop_end
expr_end:
cmp acc, zero
jne _traverse_left
dec rg4
jmp loop
_traverse_right_start:
// push a register that definitely has a nonzero value
// when we pop this value from the stack
// we know we've finished traversing.
push rg8
traverse_right_start:
// we need to traverse to the right until we find the closing bracket.
// for each open bracket, we push to the stack
// for each close bracket, we pop from the stack
_traverse_right_loop:
_traverse_right:
inc rg0
ldb rg0, rg3
cmp rg3, rge
jeq _open
jeq open_right
cmp rg3, rgf
jeq _close
jeq close_right
cmp rg3, zero
jeq end
jmp _traverse_right
_open:
push rg4
inc rg4
open_right:
// push zero to the stack
push zero
jmp _traverse_right
_close:
pop rg5
cmp rg4,
jmp _traverse_right
close_right:
// check if we've reached the bottom of the stack
pop rg4
cmp rg4, zero
jeq _traverse_right
// go to next instruction after closing bracket
inc rg0
jmp loop_start
// ------------------------------------------
// handle the close bracket instruction
expr_end:
cmp rg2, zero
jeq loop_end
_traverse_left_start:
push rg8
_traverse_left:
dec rg0
ldb rg0, rg3
cmp rg3, rge
jeq open_left
cmp rg3, rgf
jeq close_left
cmp rg3, zero
jeq end
jmp _traverse_left
open_left:
// check if we've reached the bottom of the stack
pop rg4
cmp rg4, zero
jeq _traverse_left
// go to next instruction after open bracket
inc rg0
jmp loop_start
close_left:
// push zero to the stack
push zero
jmp _traverse_left
Binary file not shown.