first steps sim

This commit is contained in:
Jesenko, Jakob 2025-12-08 10:38:04 +01:00
parent a9323bb7d9
commit 25c1c1eb6c
4 changed files with 221 additions and 29 deletions

View file

@ -1,8 +1,32 @@
import gleam/io
import sim/machine import sim/machine
fn run_for(
machine: machine.Machine,
instructions: List(machine.Def),
steps: Int,
) -> machine.Machine {
let machine = machine.run_for(machine, instructions, steps)
io.println(machine.state_string(machine))
machine
}
fn step(
machine: machine.Machine,
instructions: List(machine.Def),
) -> machine.Machine {
let machine = machine.step(machine, instructions)
io.println(machine.state_string(machine))
machine
}
pub fn main() -> Nil { pub fn main() -> Nil {
let machine = machine.init("../arith.obj") let machine = machine.init("../arith.obj")
echo machine let instructions = machine.get_instructions()
machine.step(machine, machine.get_instructions()) io.println(machine.state_string(machine))
let machine = run_for(machine, instructions, 16)
let machine = step(machine, instructions)
let machine = step(machine, instructions)
let machine = step(machine, instructions)
Nil Nil
} }

View file

@ -45,17 +45,13 @@ fn read_section(stream: file_stream.FileStream) -> List(Record) {
pub fn load_obj(file: String) -> memory.Memory { pub fn load_obj(file: String) -> memory.Memory {
let assert Ok(stream) = file_stream.open_read(file) let assert Ok(stream) = file_stream.open_read(file)
let section = read_section(stream) let section = read_section(stream)
echo section
list.fold(section, <<0>>, fn(memory, record) -> memory.Memory { list.fold(section, <<0>>, fn(memory, record) -> memory.Memory {
case record.record_type { case record.record_type {
T -> { T -> {
let assert <<position:24, _len:8, value:bits>> = record.content let assert <<position:24, _len:8, value:bits>> = record.content
echo position
echo bit_array.base16_encode(value)
memory.insert_at(memory, position, value) memory.insert_at(memory, position, value)
} }
_ -> memory _ -> memory
} }
|> echo
}) })
} }

View file

@ -1,5 +1,7 @@
import gleam/bit_array
import gleam/list import gleam/list
import gleam/result import gleam/result
import gleam/string
import sim/loader import sim/loader
import sim/memory import sim/memory
import sim/registers import sim/registers
@ -12,13 +14,31 @@ pub fn init(program: String) -> Machine {
Machine(loader.load_obj(program), registers.new()) Machine(loader.load_obj(program), registers.new())
} }
pub fn state_string(machine: Machine) -> String {
string.join(
[
bit_array.base16_encode(machine.memory),
"a: " <> bit_array.base16_encode(machine.registers.a),
"x: " <> bit_array.base16_encode(machine.registers.x),
"l: " <> bit_array.base16_encode(machine.registers.l),
"b: " <> bit_array.base16_encode(machine.registers.b),
"s: " <> bit_array.base16_encode(machine.registers.s),
"t: " <> bit_array.base16_encode(machine.registers.t),
"f: " <> bit_array.base16_encode(machine.registers.f),
"pc: " <> bit_array.base16_encode(machine.registers.pc),
"sw: " <> bit_array.base16_encode(machine.registers.sw),
],
"\n",
)
}
fn fetch_instruction( fn fetch_instruction(
instructions: List(Def), instructions: List(Def),
memory: memory.Memory, memory: memory.Memory,
ptr: Int, ptr: Int,
) -> Instruction { ) -> Instruction {
let char = memory.get_char_at(memory, ptr) let char = memory.get_char_at(memory, ptr)
let def = get_def(instructions, char) let def = get_def(instructions, char) |> echo
let inst = case def.size { let inst = case def.size {
1 -> Instruction(1, char, def.modifier) 1 -> Instruction(1, char, def.modifier)
2 -> 2 ->
@ -32,17 +52,48 @@ fn fetch_instruction(
) )
3 | _ -> Instruction(3, memory.get_int_at(memory, ptr), def.modifier) 3 | _ -> Instruction(3, memory.get_int_at(memory, ptr), def.modifier)
} }
inst case inst.source {
<<_:11, 1:1, _:bits>> ->
Instruction(
4,
<<
inst.source:bits,
memory.get_char_at(memory, ptr + 1):bits,
>>,
def.modifier,
)
_ -> inst
}
} }
pub fn step(machine: Machine, instructions: List(Def)) -> Machine { pub fn step(machine: Machine, instructions: List(Def)) -> Machine {
let assert <<pc:24>> = machine.registers.pc let assert <<pc:24>> = machine.registers.pc
fetch_instruction(instructions, machine.memory, pc) let inst = fetch_instruction(instructions, machine.memory, pc)
let assert <<pc:24>> = machine.registers.pc
let pc = pc + inst.size
let machine =
inst.modifier(
Machine(
..machine,
registers: registers.Registers(..machine.registers, pc: <<pc:24>>),
),
inst.source,
)
machine machine
} }
pub fn run_for(machine: Machine, instructions: List(Def), steps: Int) -> Machine {
case steps {
0 -> machine
_ -> {
run_for(step(machine, instructions), instructions, steps - 1)
}
}
}
pub type Instruction { pub type Instruction {
Instruction( Instruction(
size: Int, size: Int,
@ -60,9 +111,35 @@ pub type Def {
) )
} }
pub fn get_def(instructions: List(Def), first_byte: BitArray) -> Def {
result.unwrap(
list.find(instructions, fn(inst) -> Bool {
let assert <<opcode:6, _:2>> = first_byte
opcode == inst.opcode
}),
Def(0, 0, "", fn(machine: Machine, _code: BitArray) -> Machine { machine }),
)
}
pub fn get_instructions() -> List(Def) { pub fn get_instructions() -> List(Def) {
[ [
Def(6, 3, "ADD", fn(machine: Machine, code: BitArray) -> Machine { machine }), Def(6, 3, "ADD", fn(machine: Machine, code: BitArray) -> Machine {
let assert <<_:12, offset:bits>> = code
let operand = case code {
<<_:6, 1:1, 1:1, 0:1, 0:1, 1:1, 0:1, _:bits>> ->
memory.get_int_at(
machine.memory,
memory.to_int(machine.registers.pc) + memory.to_int(offset),
)
_ -> panic
}
Machine(
machine.memory,
registers.Registers(..machine.registers, a: <<
{ memory.to_int(machine.registers.a) + memory.to_int(operand) }:24,
>>),
)
}),
Def(22, 3, "ADDF", fn(machine: Machine, code: BitArray) -> Machine { Def(22, 3, "ADDF", fn(machine: Machine, code: BitArray) -> Machine {
machine machine
}), }),
@ -84,7 +161,23 @@ pub fn get_instructions() -> List(Def) {
Def(40, 2, "COMPR", fn(machine: Machine, code: BitArray) -> Machine { Def(40, 2, "COMPR", fn(machine: Machine, code: BitArray) -> Machine {
machine machine
}), }),
Def(9, 3, "DIV", fn(machine: Machine, code: BitArray) -> Machine { machine }), Def(9, 3, "DIV", fn(machine: Machine, code: BitArray) -> Machine {
let assert <<_:12, offset:bits>> = code
let operand = case code {
<<_:6, 1:1, 1:1, 0:1, 0:1, 1:1, 0:1, _:bits>> ->
memory.get_int_at(
machine.memory,
memory.to_int(machine.registers.pc) + memory.to_int(offset),
)
_ -> panic
}
Machine(
machine.memory,
registers.Registers(..machine.registers, a: <<
{ memory.to_int(machine.registers.a) / memory.to_int(operand) }:24,
>>),
)
}),
Def(25, 3, "DIVF", fn(machine: Machine, code: BitArray) -> Machine { Def(25, 3, "DIVF", fn(machine: Machine, code: BitArray) -> Machine {
machine machine
}), }),
@ -100,7 +193,18 @@ pub fn get_instructions() -> List(Def) {
Def(61, 1, "HIO", fn(machine: Machine, code: BitArray) -> Machine { Def(61, 1, "HIO", fn(machine: Machine, code: BitArray) -> Machine {
machine machine
}), }),
Def(15, 3, "J", fn(machine: Machine, code: BitArray) -> Machine { machine }), Def(15, 3, "J", fn(machine: Machine, code: BitArray) -> Machine {
let assert <<_:12, offset:bits>> = code
let addr = case code {
<<_:6, 1:1, 1:1, 0:1, 0:1, 1:1, 0:1, _:bits>> ->
memory.to_int(machine.registers.pc) + memory.to_int(offset)
_ -> todo
}
Machine(
machine.memory,
registers.Registers(..machine.registers, pc: <<addr:24>>),
)
}),
Def(12, 3, "JEQ", fn(machine: Machine, code: BitArray) -> Machine { Def(12, 3, "JEQ", fn(machine: Machine, code: BitArray) -> Machine {
machine machine
}), }),
@ -113,7 +217,21 @@ pub fn get_instructions() -> List(Def) {
Def(18, 3, "JSUB", fn(machine: Machine, code: BitArray) -> Machine { Def(18, 3, "JSUB", fn(machine: Machine, code: BitArray) -> Machine {
machine machine
}), }),
Def(0, 3, "LDA", fn(machine: Machine, code: BitArray) -> Machine { machine }), Def(0, 3, "LDA", fn(machine: Machine, code: BitArray) -> Machine {
let assert <<_:12, offset:bits>> = code
let operand = case code {
<<_:6, 1:1, 1:1, 0:1, 0:1, 1:1, 0:1, _:bits>> ->
memory.get_int_at(
machine.memory,
memory.to_int(machine.registers.pc) + memory.to_int(offset),
)
_ -> todo
}
Machine(
machine.memory,
registers.Registers(..machine.registers, a: operand),
)
}),
Def(26, 3, "LDB", fn(machine: Machine, code: BitArray) -> Machine { Def(26, 3, "LDB", fn(machine: Machine, code: BitArray) -> Machine {
machine machine
}), }),
@ -134,7 +252,23 @@ pub fn get_instructions() -> List(Def) {
Def(52, 3, "LPS", fn(machine: Machine, code: BitArray) -> Machine { Def(52, 3, "LPS", fn(machine: Machine, code: BitArray) -> Machine {
machine machine
}), }),
Def(8, 3, "MUL", fn(machine: Machine, code: BitArray) -> Machine { machine }), Def(8, 3, "MUL", fn(machine: Machine, code: BitArray) -> Machine {
let assert <<_:12, offset:bits>> = code
let operand = case code {
<<_:6, 1:1, 1:1, 0:1, 0:1, 1:1, 0:1, _:bits>> ->
memory.get_int_at(
machine.memory,
memory.to_int(machine.registers.pc) + memory.to_int(offset),
)
_ -> panic
}
Machine(
machine.memory,
registers.Registers(..machine.registers, a: <<
{ memory.to_int(machine.registers.a) * memory.to_int(operand) }:24,
>>),
)
}),
Def(24, 3, "MULF", fn(machine: Machine, code: BitArray) -> Machine { Def(24, 3, "MULF", fn(machine: Machine, code: BitArray) -> Machine {
machine machine
}), }),
@ -164,7 +298,19 @@ pub fn get_instructions() -> List(Def) {
Def(59, 3, "SSK", fn(machine: Machine, code: BitArray) -> Machine { Def(59, 3, "SSK", fn(machine: Machine, code: BitArray) -> Machine {
machine machine
}), }),
Def(3, 3, "STA", fn(machine: Machine, code: BitArray) -> Machine { machine }), Def(3, 3, "STA", fn(machine: Machine, code: BitArray) -> Machine {
let assert <<_:12, offset:bits>> = code
let memory = case code {
<<_:6, 1:1, 1:1, 0:1, 0:1, 1:1, 0:1, _:bits>> ->
memory.set_int_at(
machine.memory,
memory.to_int(machine.registers.pc) + memory.to_int(offset),
machine.registers.a,
)
_ -> todo
}
Machine(memory, machine.registers)
}),
Def(30, 3, "STB", fn(machine: Machine, code: BitArray) -> Machine { Def(30, 3, "STB", fn(machine: Machine, code: BitArray) -> Machine {
machine machine
}), }),
@ -188,7 +334,23 @@ pub fn get_instructions() -> List(Def) {
machine machine
}), }),
Def(4, 3, "STX", fn(machine: Machine, code: BitArray) -> Machine { machine }), Def(4, 3, "STX", fn(machine: Machine, code: BitArray) -> Machine { machine }),
Def(7, 3, "SUB", fn(machine: Machine, code: BitArray) -> Machine { machine }), Def(7, 3, "SUB", fn(machine: Machine, code: BitArray) -> Machine {
let assert <<_:12, offset:bits>> = code
let operand = case code {
<<_:6, 1:1, 1:1, 0:1, 0:1, 1:1, 0:1, _:bits>> ->
memory.get_int_at(
machine.memory,
memory.to_int(machine.registers.pc) + memory.to_int(offset),
)
_ -> panic
}
Machine(
machine.memory,
registers.Registers(..machine.registers, a: <<
{ memory.to_int(machine.registers.a) - memory.to_int(operand) }:24,
>>),
)
}),
Def(23, 3, "SUBF", fn(machine: Machine, code: BitArray) -> Machine { Def(23, 3, "SUBF", fn(machine: Machine, code: BitArray) -> Machine {
machine machine
}), }),
@ -211,13 +373,3 @@ pub fn get_instructions() -> List(Def) {
Def(23, 3, "WD", fn(machine: Machine, code: BitArray) -> Machine { machine }), Def(23, 3, "WD", fn(machine: Machine, code: BitArray) -> Machine { machine }),
] ]
} }
pub fn get_def(instructions: List(Def), first_byte: BitArray) -> Def {
result.unwrap(
list.find(instructions, fn(inst) -> Bool {
let assert <<opcode:6, _:2>> = first_byte
opcode == inst.opcode
}),
Def(0, 0, "", fn(machine: Machine, code: BitArray) -> Machine { machine }),
)
}

View file

@ -34,7 +34,7 @@ pub fn insert_at(memory: Memory, pos: Int, value: BitArray) -> Memory {
} }
pub fn get_char_at(memory: Memory, pos: Int) -> BitArray { pub fn get_char_at(memory: Memory, pos: Int) -> BitArray {
let assert Ok(value) = bit_array.slice(memory, pos, 8) let assert Ok(value) = bit_array.slice(memory, pos, 1)
value value
} }
@ -43,7 +43,7 @@ pub fn set_char_at(memory: Memory, pos: Int, value: BitArray) -> Memory {
} }
pub fn get_int_at(memory: Memory, pos: Int) -> BitArray { pub fn get_int_at(memory: Memory, pos: Int) -> BitArray {
let assert Ok(value) = bit_array.slice(memory, pos, 24) let assert Ok(value) = bit_array.slice(memory, pos, 3)
value value
} }
@ -52,10 +52,30 @@ pub fn set_int_at(memory: Memory, pos: Int, value: BitArray) -> Memory {
} }
pub fn get_float_at(memory: Memory, pos: Int) -> BitArray { pub fn get_float_at(memory: Memory, pos: Int) -> BitArray {
let assert Ok(value) = bit_array.slice(memory, pos, 40) let assert Ok(value) = bit_array.slice(memory, pos, 5)
value value
} }
pub fn set_float_at(memory: Memory, pos: Int, value: BitArray) -> Memory { pub fn set_float_at(memory: Memory, pos: Int, value: BitArray) -> Memory {
insert_at(memory, pos, value) insert_at(memory, pos, value)
} }
fn pow2(n: Int) {
case n {
0 -> 1
_ -> 2 * pow2(n - 1)
}
}
pub fn to_int(val: BitArray) -> Int {
let ival = case val {
<<ival:24>> -> ival
<<ival:12>> -> ival
<<ival:20>> -> ival
_ -> panic
}
case val {
<<1:1, _:bits>> -> ival - pow2(bit_array.bit_size(val))
_ -> ival
}
}