diff --git a/sim/src/sim.gleam b/sim/src/sim.gleam index 657833b..00ce928 100644 --- a/sim/src/sim.gleam +++ b/sim/src/sim.gleam @@ -1,8 +1,32 @@ +import gleam/io 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 { let machine = machine.init("../arith.obj") - echo machine - machine.step(machine, machine.get_instructions()) + let instructions = 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 } diff --git a/sim/src/sim/loader.gleam b/sim/src/sim/loader.gleam index 151ca1c..7207a93 100644 --- a/sim/src/sim/loader.gleam +++ b/sim/src/sim/loader.gleam @@ -45,17 +45,13 @@ fn read_section(stream: file_stream.FileStream) -> List(Record) { pub fn load_obj(file: String) -> memory.Memory { let assert Ok(stream) = file_stream.open_read(file) let section = read_section(stream) - echo section list.fold(section, <<0>>, fn(memory, record) -> memory.Memory { case record.record_type { T -> { let assert <> = record.content - echo position - echo bit_array.base16_encode(value) memory.insert_at(memory, position, value) } _ -> memory } - |> echo }) } diff --git a/sim/src/sim/machine.gleam b/sim/src/sim/machine.gleam index 9c74ca5..8ce6d54 100644 --- a/sim/src/sim/machine.gleam +++ b/sim/src/sim/machine.gleam @@ -1,5 +1,7 @@ +import gleam/bit_array import gleam/list import gleam/result +import gleam/string import sim/loader import sim/memory import sim/registers @@ -12,13 +14,31 @@ pub fn init(program: String) -> Machine { 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( instructions: List(Def), memory: memory.Memory, ptr: Int, ) -> Instruction { 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 { 1 -> Instruction(1, char, def.modifier) 2 -> @@ -32,17 +52,48 @@ fn fetch_instruction( ) 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 { let assert <> = machine.registers.pc - fetch_instruction(instructions, machine.memory, pc) + let inst = fetch_instruction(instructions, machine.memory, pc) + + let assert <> = machine.registers.pc + let pc = pc + inst.size + let machine = + inst.modifier( + Machine( + ..machine, + registers: registers.Registers(..machine.registers, pc: <>), + ), + inst.source, + ) 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 { Instruction( 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 <> = first_byte + opcode == inst.opcode + }), + Def(0, 0, "", fn(machine: Machine, _code: BitArray) -> Machine { machine }), + ) +} + 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 { machine }), @@ -84,7 +161,23 @@ pub fn get_instructions() -> List(Def) { Def(40, 2, "COMPR", fn(machine: Machine, code: BitArray) -> 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 { machine }), @@ -100,7 +193,18 @@ pub fn get_instructions() -> List(Def) { Def(61, 1, "HIO", fn(machine: Machine, code: BitArray) -> 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: <>), + ) + }), Def(12, 3, "JEQ", fn(machine: Machine, code: BitArray) -> Machine { machine }), @@ -113,7 +217,21 @@ pub fn get_instructions() -> List(Def) { Def(18, 3, "JSUB", fn(machine: Machine, code: BitArray) -> 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 { machine }), @@ -134,7 +252,23 @@ pub fn get_instructions() -> List(Def) { Def(52, 3, "LPS", fn(machine: Machine, code: BitArray) -> 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 { machine }), @@ -164,7 +298,19 @@ pub fn get_instructions() -> List(Def) { Def(59, 3, "SSK", fn(machine: Machine, code: BitArray) -> 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 { machine }), @@ -188,7 +334,23 @@ pub fn get_instructions() -> List(Def) { 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 { machine }), @@ -211,13 +373,3 @@ pub fn get_instructions() -> List(Def) { 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 <> = first_byte - opcode == inst.opcode - }), - Def(0, 0, "", fn(machine: Machine, code: BitArray) -> Machine { machine }), - ) -} diff --git a/sim/src/sim/memory.gleam b/sim/src/sim/memory.gleam index 0e92d40..d3a2835 100644 --- a/sim/src/sim/memory.gleam +++ b/sim/src/sim/memory.gleam @@ -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 { - let assert Ok(value) = bit_array.slice(memory, pos, 8) + let assert Ok(value) = bit_array.slice(memory, pos, 1) 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 { - let assert Ok(value) = bit_array.slice(memory, pos, 24) + let assert Ok(value) = bit_array.slice(memory, pos, 3) 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 { - let assert Ok(value) = bit_array.slice(memory, pos, 40) + let assert Ok(value) = bit_array.slice(memory, pos, 5) value } pub fn set_float_at(memory: Memory, pos: Int, value: BitArray) -> Memory { 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 + <> -> ival + <> -> ival + _ -> panic + } + case val { + <<1:1, _:bits>> -> ival - pow2(bit_array.bit_size(val)) + _ -> ival + } +}