diff --git a/sim/log.log b/sim/log.log new file mode 100644 index 0000000..d45904e --- /dev/null +++ b/sim/log.log @@ -0,0 +1,120 @@ +0320361B20360F203603202D1F202D0F20300320242320240F202A03201B27201B0F20242320150F202103200C1F201B0F20180F20033F2FFD00002A00001B +a: 000000 +x: 000000 +l: 000000 +b: 000000 +s: 000000 +t: 000000 +f: 000000 +pc: 000000 +sw: 000000 +0320361B20360F203603202D1F202D0F20300320242320240F202A03201B27201B0F20242320150F202103200C1F201B0F20180F20033F2FFD00002A00001B +a: 00002A +x: 000000 +l: 000000 +b: 000000 +s: 000000 +t: 000000 +f: 000000 +pc: 000003 +sw: 000000 +0320361B20360F203603202D1F202D0F20300320242320240F202A03201B27201B0F20242320150F202103200C1F201B0F20180F20033F2FFD00002A00001B +a: 000045 +x: 000000 +l: 000000 +b: 000000 +s: 000000 +t: 000000 +f: 000000 +pc: 000006 +sw: 000000 +0320361B20360F203603202D1F202D0F20300320242320240F202A03201B27201B0F20242320150F202103200C1F201B0F20180F20033F2FFD00002A00001B000045 +a: 000045 +x: 000000 +l: 000000 +b: 000000 +s: 000000 +t: 000000 +f: 000000 +pc: 000009 +sw: 000000 +0320361B20360F203603202D1F202D0F20300320242320240F202A03201B27201B0F20242320150F202103200C1F201B0F20180F20033F2FFD00002A00001B000045 +a: 00002A +x: 000000 +l: 000000 +b: 000000 +s: 000000 +t: 000000 +f: 000000 +pc: 00000C +sw: 000000 +0320361B20360F203603202D1F202D0F20300320242320240F202A03201B27201B0F20242320150F202103200C1F201B0F20180F20033F2FFD00002A00001B000045 +a: 00000F +x: 000000 +l: 000000 +b: 000000 +s: 000000 +t: 000000 +f: 000000 +pc: 00000F +sw: 000000 +0320361B20360F203603202D1F202D0F20300320242320240F202A03201B27201B0F20242320150F202103200C1F201B0F20180F20033F2FFD00002A00001B00004500000F +a: 00000F +x: 000000 +l: 000000 +b: 000000 +s: 000000 +t: 000000 +f: 000000 +pc: 000012 +sw: 000000 +0320361B20360F203603202D1F202D0F20300320242320240F202A03201B27201B0F20242320150F202103200C1F201B0F20180F20033F2FFD00002A00001B00004500000F +a: 00002A +x: 000000 +l: 000000 +b: 000000 +s: 000000 +t: 000000 +f: 000000 +pc: 000015 +sw: 000000 +0320361B20360F203603202D1F202D0F20300320242320240F202A03201B27201B0F20242320150F202103200C1F201B0F20180F20033F2FFD00002A00001B00004500000F +a: 00046E +x: 000000 +l: 000000 +b: 000000 +s: 000000 +t: 000000 +f: 000000 +pc: 000018 +sw: 000000 +0320361B20360F203603202D1F202D0F20300320242320240F202A03201B27201B0F20242320150F202103200C1F201B0F20180F20033F2FFD00002A00001B00004500000F00046E +a: 00046E +x: 000000 +l: 000000 +b: 000000 +s: 000000 +t: 000000 +f: 000000 +pc: 00001B +sw: 000000 +0320361B20360F203603202D1F202D0F20300320242320240F202A03201B27201B0F20242320150F202103200C1F201B0F20180F20033F2FFD00002A00001B00004500000F00046E +a: 00002A +x: 000000 +l: 000000 +b: 000000 +s: 000000 +t: 000000 +f: 000000 +pc: 00001E +sw: 000000 +0320361B20360F203603202D1F202D0F20300320242320240F202A03201B27201B0F20242320150F202103200C1F201B0F20180F20033F2FFD00002A00001B00004500000F00046E +a: 000001 +x: 000000 +l: 000000 +b: 000000 +s: 000000 +t: 000000 +f: 000000 +pc: 000021 +sw: 000000 diff --git a/sim/src/sim.gleam b/sim/src/sim.gleam index 00ce928..382372c 100644 --- a/sim/src/sim.gleam +++ b/sim/src/sim.gleam @@ -20,13 +20,34 @@ fn step( machine } +fn status(machine: machine.Machine) { + io.println(machine.state_string(machine)) +} + pub fn main() -> Nil { let machine = machine.init("../arith.obj") let instructions = machine.get_instructions() - io.println(machine.state_string(machine)) + status(machine) + let machine = step(machine, instructions) + let machine = step(machine, instructions) + let machine = step(machine, instructions) + let machine = step(machine, instructions) + let machine = step(machine, instructions) + let machine = step(machine, instructions) + let machine = step(machine, instructions) + let machine = step(machine, instructions) + let machine = step(machine, instructions) + let machine = step(machine, instructions) + let machine = step(machine, instructions) + let machine = step(machine, instructions) + let machine = step(machine, instructions) + let machine = step(machine, instructions) + let machine = step(machine, instructions) + let machine = step(machine, instructions) + let machine = step(machine, instructions) + let machine = step(machine, instructions) + let machine = step(machine, instructions) + let machine = step(machine, instructions) 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/device.gleam b/sim/src/sim/device.gleam new file mode 100644 index 0000000..6984ce2 --- /dev/null +++ b/sim/src/sim/device.gleam @@ -0,0 +1,84 @@ +import file_streams/file_open_mode +import file_streams/file_stream +import gleam/bit_array +import gleam/io +import gleam/option + +pub opaque type DeviceType { + Stdin + Stdout + Stderr + Default +} + +pub type Device { + Device( + stream: option.Option(file_stream.FileStream), + dev_type: DeviceType, + buffer: BitArray, + has_data: Bool, + ) +} + +pub fn open(name: String) -> Device { + case name { + "0.dev" -> Device(option.None, Stdin, <<>>, False) + "1.dev" -> Device(option.None, Stdout, <<>>, False) + "2.dev" -> Device(option.None, Stderr, <<>>, False) + _ -> { + let assert Ok(str) = + file_stream.open(name, [file_open_mode.Read, file_open_mode.Write]) + Device(option.Some(str), Default, <<>>, False) + } + } +} + +pub fn read(device: Device) -> #(BitArray, Device) { + #(device.buffer, Device(..device, buffer: <<>>, has_data: False)) +} + +pub fn write(device: Device, char: BitArray) -> Device { + let _ = case device.dev_type { + Default -> { + let assert option.Some(stream) = device.stream + let assert Ok(_r) = file_stream.write_bytes(stream, char) + let assert Ok(_r) = file_stream.sync(stream) + Nil + } + Stdout -> { + let assert Ok(str) = bit_array.to_string(char) + io.print(str) + } + Stderr -> { + let assert Ok(str) = bit_array.to_string(char) + io.print_error(str) + } + _ -> Nil + } + device +} + +pub fn test_device(device: Device) -> Device { + case device.dev_type { + Default -> { + let assert option.Some(stream) = device.stream + let data = file_stream.read_bytes(stream, 1) + case data { + Ok(char) -> Device(..device, buffer: char, has_data: True) + Error(_) -> Device(..device, buffer: <<>>, has_data: False) + } + } + _ -> device + } +} + +pub fn close(device: Device) { + case device.dev_type { + Default -> { + let assert option.Some(stream) = device.stream + let assert Ok(_) = file_stream.close(stream) + Nil + } + _ -> Nil + } +} diff --git a/sim/src/sim/machine.gleam b/sim/src/sim/machine.gleam index 8ce6d54..b60fd00 100644 --- a/sim/src/sim/machine.gleam +++ b/sim/src/sim/machine.gleam @@ -1,17 +1,25 @@ import gleam/bit_array +import gleam/dict +import gleam/int import gleam/list +import gleam/order import gleam/result import gleam/string +import sim/device import sim/loader import sim/memory import sim/registers pub type Machine { - Machine(memory: memory.Memory, registers: registers.Registers) + Machine( + memory: memory.Memory, + registers: registers.Registers, + devices: dict.Dict(Int, device.Device), + ) } pub fn init(program: String) -> Machine { - Machine(loader.load_obj(program), registers.new()) + Machine(loader.load_obj(program), registers.new(), dict.new()) } pub fn state_string(machine: Machine) -> String { @@ -66,6 +74,92 @@ fn fetch_instruction( } } +fn get_operand34(machine: Machine, code: BitArray, size: Int) -> BitArray { + let assert <<_opcode:6, n:1, i:1, x:1, b:1, p:1, _e:1, offset:bits>> = code + let addr = + case b, p { + 1, 0 -> memory.to_int(machine.registers.b) + memory.to_int(offset) + 0, 1 -> memory.to_int(machine.registers.pc) + memory.to_int(offset) + 0, 0 -> memory.to_int(offset) + _, _ -> panic + } + + case x { + 0 -> 0 + _ -> memory.to_int(machine.registers.x) + } + let getter = case size { + 1 -> memory.get_char_at + 3 -> memory.get_int_at + 6 -> memory.get_float_at + _ -> panic + } + case n, i { + 0, 1 -> memory.left_pad_to_length(<>, size * 8) + 1, 1 -> getter(machine.memory, addr) + 1, 0 -> + getter( + machine.memory, + memory.to_int(memory.get_int_at(machine.memory, addr)), + ) + _, _ -> panic + } +} + +fn get_address34(machine: Machine, code: BitArray, size: Int) -> BitArray { + let assert <<_opcode:6, n:1, i:1, x:1, b:1, p:1, _e:1, offset:bits>> = code + let addr = + case b, p { + 1, 0 -> memory.to_int(machine.registers.b) + memory.to_int(offset) + 0, 1 -> memory.to_int(machine.registers.pc) + memory.to_int(offset) + 0, 0 -> memory.to_int(offset) + _, _ -> panic + } + + case x { + 0 -> 0 + _ -> memory.to_int(machine.registers.x) + } + let getter = case size { + 1 -> memory.get_char_at + 3 -> memory.get_int_at + 6 -> memory.get_float_at + _ -> panic + } + case n, i { + 0, 1 -> panic + 1, 1 -> <> + 1, 0 -> getter(machine.memory, addr) + _, _ -> panic + } +} + +fn get_register(machine: Machine, code: Int) -> BitArray { + case code { + 0 -> machine.registers.a + 1 -> machine.registers.x + 2 -> machine.registers.l + 3 -> machine.registers.b + 4 -> machine.registers.s + 5 -> machine.registers.t + _ -> panic + } +} + +fn set_register( + machine: Machine, + code: Int, + value: BitArray, +) -> registers.Registers { + case code { + 0 -> registers.Registers(..machine.registers, a: value) + 1 -> registers.Registers(..machine.registers, x: value) + 2 -> registers.Registers(..machine.registers, l: value) + 3 -> registers.Registers(..machine.registers, b: value) + 4 -> registers.Registers(..machine.registers, s: value) + 5 -> registers.Registers(..machine.registers, t: value) + _ -> panic + } +} + pub fn step(machine: Machine, instructions: List(Def)) -> Machine { let assert <> = machine.registers.pc @@ -124,252 +218,454 @@ pub fn get_def(instructions: List(Def), first_byte: BitArray) -> Def { pub fn get_instructions() -> List(Def) { [ 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 - } + let operand = get_operand34(machine, code, 3) Machine( - machine.memory, - registers.Registers(..machine.registers, a: << + ..machine, + registers: 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 }), Def(36, 2, "ADDR", fn(machine: Machine, code: BitArray) -> Machine { - machine + let assert <<_opcode:8, reg1:4, reg2:4>> = code + let assert <> = get_register(machine, reg1) + let assert <> = get_register(machine, reg2) + let value = operand2 + operand1 + Machine(..machine, registers: set_register(machine, reg2, <>)) }), - Def(16, 3, "AND", fn(machine: Machine, code: BitArray) -> Machine { + Def(16, 3, "AND", fn(machine: Machine, _code: BitArray) -> Machine { machine }), Def(45, 2, "CLEAR", fn(machine: Machine, code: BitArray) -> Machine { - machine + let assert <<_opcode:8, reg1:4, _reg2:4>> = code + Machine(..machine, registers: set_register(machine, reg1, <<0:24>>)) }), Def(10, 3, "COMP", fn(machine: Machine, code: BitArray) -> Machine { - machine + let operand = get_operand34(machine, code, 3) + let sw = case bit_array.compare(machine.registers.a, operand) { + order.Lt -> <<0x80:24>> + order.Eq -> <<0:24>> + order.Gt -> <<0x40:24>> + } + Machine( + ..machine, + registers: registers.Registers(..machine.registers, sw: sw), + ) }), - Def(34, 3, "COMPF", fn(machine: Machine, code: BitArray) -> Machine { + Def(34, 3, "COMPF", fn(machine: Machine, _code: BitArray) -> Machine { machine }), Def(40, 2, "COMPR", 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 + let assert <<_opcode:8, reg1:4, reg2:4>> = code + let sw = case + bit_array.compare( + get_register(machine, reg1), + get_register(machine, reg2), + ) + { + order.Lt -> <<0x80:24>> + order.Eq -> <<0:24>> + order.Gt -> <<0x40:24>> } Machine( - machine.memory, - registers.Registers(..machine.registers, a: << + ..machine, + registers: registers.Registers(..machine.registers, sw: sw), + ) + }), + Def(9, 3, "DIV", fn(machine: Machine, code: BitArray) -> Machine { + let operand = get_operand34(machine, code, 3) + Machine( + ..machine, + registers: 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 }), Def(39, 2, "DIVR", fn(machine: Machine, code: BitArray) -> Machine { + let assert <<_opcode:8, reg1:4, reg2:4>> = code + let assert <> = get_register(machine, reg1) + let assert <> = get_register(machine, reg2) + let value = operand2 / operand1 + Machine(..machine, registers: set_register(machine, reg2, <>)) + }), + Def(49, 1, "FIX", fn(machine: Machine, _code: BitArray) -> Machine { machine }), - Def(49, 1, "FIX", fn(machine: Machine, code: BitArray) -> Machine { + Def(48, 1, "FLOAT", fn(machine: Machine, _code: BitArray) -> Machine { machine }), - Def(48, 1, "FLOAT", fn(machine: Machine, code: BitArray) -> Machine { - machine - }), - Def(61, 1, "HIO", fn(machine: Machine, code: BitArray) -> Machine { + Def(61, 1, "HIO", 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 - } + let addr = get_address34(machine, code, 3) Machine( - machine.memory, - registers.Registers(..machine.registers, pc: <>), + ..machine, + registers: registers.Registers(..machine.registers, pc: addr), ) }), Def(12, 3, "JEQ", fn(machine: Machine, code: BitArray) -> Machine { - machine + let addr = get_address34(machine, code, 3) + case machine.registers.sw { + <<0:24>> -> + Machine( + ..machine, + registers: registers.Registers(..machine.registers, pc: addr), + ) + _ -> machine + } }), Def(13, 3, "JGT", fn(machine: Machine, code: BitArray) -> Machine { - machine + let addr = get_address34(machine, code, 3) + case machine.registers.sw { + <<0x40:24>> -> + Machine( + ..machine, + registers: registers.Registers(..machine.registers, pc: addr), + ) + _ -> machine + } }), Def(14, 3, "JLT", fn(machine: Machine, code: BitArray) -> Machine { - machine + let addr = get_address34(machine, code, 3) + case machine.registers.sw { + <<0x80:24>> -> + Machine( + ..machine, + registers: registers.Registers(..machine.registers, pc: addr), + ) + _ -> machine + } }), Def(18, 3, "JSUB", fn(machine: Machine, code: BitArray) -> Machine { - machine + let addr = get_address34(machine, code, 3) + Machine( + ..machine, + registers: registers.Registers( + ..machine.registers, + l: machine.registers.pc, + pc: addr, + ), + ) }), 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 - } + let operand = get_operand34(machine, code, 3) Machine( - machine.memory, - registers.Registers(..machine.registers, a: operand), + ..machine, + registers: registers.Registers(..machine.registers, a: operand), ) }), Def(26, 3, "LDB", fn(machine: Machine, code: BitArray) -> Machine { - machine + let operand = get_operand34(machine, code, 3) + Machine( + ..machine, + registers: registers.Registers(..machine.registers, b: operand), + ) }), Def(20, 3, "LDCH", fn(machine: Machine, code: BitArray) -> Machine { + let operand = get_operand34(machine, code, 3) + Machine( + ..machine, + registers: registers.Registers(..machine.registers, a: << + 0:16, + operand:bits, + >>), + ) + }), + Def(28, 3, "LDF", fn(machine: Machine, _code: BitArray) -> Machine { machine }), - Def(28, 3, "LDF", fn(machine: Machine, code: BitArray) -> Machine { - machine + Def(2, 3, "LDL", fn(machine: Machine, code: BitArray) -> Machine { + let operand = get_operand34(machine, code, 3) + Machine( + ..machine, + registers: registers.Registers(..machine.registers, l: operand), + ) }), - Def(2, 3, "LDL", fn(machine: Machine, code: BitArray) -> Machine { machine }), Def(27, 3, "LDS", fn(machine: Machine, code: BitArray) -> Machine { - machine + let operand = get_operand34(machine, code, 3) + Machine( + ..machine, + registers: registers.Registers(..machine.registers, s: operand), + ) }), Def(29, 3, "LDT", fn(machine: Machine, code: BitArray) -> Machine { - machine + let operand = get_operand34(machine, code, 3) + Machine( + ..machine, + registers: registers.Registers(..machine.registers, t: operand), + ) }), - Def(1, 3, "LDX", fn(machine: Machine, code: BitArray) -> Machine { machine }), - Def(52, 3, "LPS", fn(machine: Machine, code: BitArray) -> Machine { + Def(1, 3, "LDX", fn(machine: Machine, code: BitArray) -> Machine { + let operand = get_operand34(machine, code, 3) + Machine( + ..machine, + registers: registers.Registers(..machine.registers, x: operand), + ) + }), + Def(52, 3, "LPS", 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 - } + let operand = get_operand34(machine, code, 3) Machine( - machine.memory, - registers.Registers(..machine.registers, a: << + ..machine, + registers: 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 }), Def(38, 2, "MULR", fn(machine: Machine, code: BitArray) -> Machine { + let assert <<_opcode:8, reg1:4, reg2:4>> = code + let assert <> = get_register(machine, reg1) + let assert <> = get_register(machine, reg2) + let value = operand2 * operand1 + Machine(..machine, registers: set_register(machine, reg2, <>)) + }), + Def(50, 1, "NORM", fn(machine: Machine, _code: BitArray) -> Machine { machine }), - Def(50, 1, "NORM", fn(machine: Machine, code: BitArray) -> Machine { + Def(17, 3, "OR", fn(machine: Machine, _code: BitArray) -> Machine { machine }), - Def(17, 3, "OR", fn(machine: Machine, code: BitArray) -> Machine { machine }), - Def(54, 3, "RD", fn(machine: Machine, code: BitArray) -> Machine { machine }), - Def(43, 2, "RMO", fn(machine: Machine, code: BitArray) -> Machine { + Def(54, 3, "RD", fn(machine: Machine, code: BitArray) -> Machine { + let assert <> = get_operand34(machine, code, 1) + let #(char, dev) = case dict.get(machine.devices, devnr) { + Ok(d) -> device.read(d) + Error(Nil) -> { + let d = device.open(int.to_base16(devnr) <> ".dev") + device.read(d) + } + } + Machine( + ..machine, + registers: registers.Registers(..machine.registers, a: << + 0:16, + char:bits, + >>), + devices: dict.insert(machine.devices, devnr, dev), + ) + }), + Def(43, 2, "RMO", fn(machine: Machine, _code: BitArray) -> Machine { machine }), - Def(19, 3, "RSUB", fn(machine: Machine, code: BitArray) -> Machine { + Def(19, 3, "RSUB", fn(machine: Machine, _code: BitArray) -> Machine { + Machine( + ..machine, + registers: registers.Registers( + ..machine.registers, + pc: machine.registers.l, + ), + ) + }), + Def(41, 2, "SHIFTL", fn(machine: Machine, _code: BitArray) -> Machine { machine }), - Def(41, 2, "SHIFTL", fn(machine: Machine, code: BitArray) -> Machine { + Def(42, 2, "SHIFTR", fn(machine: Machine, _code: BitArray) -> Machine { machine }), - Def(42, 2, "SHIFTR", fn(machine: Machine, code: BitArray) -> Machine { + Def(60, 1, "SIO", fn(machine: Machine, _code: BitArray) -> Machine { machine }), - Def(60, 1, "SIO", fn(machine: Machine, code: BitArray) -> Machine { - machine - }), - Def(59, 3, "SSK", fn(machine: Machine, code: BitArray) -> Machine { + Def(59, 3, "SSK", 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) + let operand = get_address34(machine, code, 3) + echo bit_array.base16_encode(operand) + let memory = + memory.set_int_at( + machine.memory, + memory.to_int(operand), + machine.registers.a, + ) + + Machine(..machine, memory: memory) }), Def(30, 3, "STB", fn(machine: Machine, code: BitArray) -> Machine { - machine + let operand = get_address34(machine, code, 3) + echo bit_array.base16_encode(operand) + let memory = + memory.set_int_at( + machine.memory, + memory.to_int(operand), + machine.registers.b, + ) + + Machine(..machine, memory: memory) }), Def(21, 3, "STCH", fn(machine: Machine, code: BitArray) -> Machine { + let operand = get_address34(machine, code, 3) + echo bit_array.base16_encode(operand) + let memory = + memory.set_char_at( + machine.memory, + memory.to_int(operand), + machine.registers.a, + ) + + Machine(..machine, memory: memory) + }), + Def(32, 3, "STF", fn(machine: Machine, _code: BitArray) -> Machine { machine }), - Def(32, 3, "STF", fn(machine: Machine, code: BitArray) -> Machine { + Def(53, 3, "STI", fn(machine: Machine, _code: BitArray) -> Machine { machine }), - Def(53, 3, "STI", fn(machine: Machine, code: BitArray) -> Machine { - machine + Def(5, 3, "STL", fn(machine: Machine, code: BitArray) -> Machine { + let operand = get_address34(machine, code, 3) + echo bit_array.base16_encode(operand) + let memory = + memory.set_int_at( + machine.memory, + memory.to_int(operand), + machine.registers.l, + ) + + Machine(..machine, memory: memory) }), - Def(5, 3, "STL", fn(machine: Machine, code: BitArray) -> Machine { machine }), Def(31, 3, "STS", fn(machine: Machine, code: BitArray) -> Machine { - machine + let operand = get_address34(machine, code, 3) + echo bit_array.base16_encode(operand) + let memory = + memory.set_int_at( + machine.memory, + memory.to_int(operand), + machine.registers.s, + ) + + Machine(..machine, memory: memory) }), Def(58, 3, "STSW", fn(machine: Machine, code: BitArray) -> Machine { - machine + let operand = get_address34(machine, code, 3) + echo bit_array.base16_encode(operand) + let memory = + memory.set_int_at( + machine.memory, + memory.to_int(operand), + machine.registers.sw, + ) + + Machine(..machine, memory: memory) }), Def(33, 3, "STT", fn(machine: Machine, code: BitArray) -> Machine { - machine + let operand = get_address34(machine, code, 3) + echo bit_array.base16_encode(operand) + let memory = + memory.set_int_at( + machine.memory, + memory.to_int(operand), + machine.registers.t, + ) + + Machine(..machine, memory: memory) + }), + Def(4, 3, "STX", fn(machine: Machine, code: BitArray) -> Machine { + let operand = get_address34(machine, code, 3) + echo bit_array.base16_encode(operand) + let memory = + memory.set_int_at( + machine.memory, + memory.to_int(operand), + machine.registers.x, + ) + + Machine(..machine, memory: memory) }), - Def(4, 3, "STX", 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 - } + let operand = get_operand34(machine, code, 3) Machine( - machine.memory, - registers.Registers(..machine.registers, a: << + ..machine, + registers: 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 }), Def(23, 2, "SUBR", fn(machine: Machine, code: BitArray) -> Machine { + let assert <<_opcode:8, reg1:4, reg2:4>> = code + let assert <> = get_register(machine, reg1) + let assert <> = get_register(machine, reg2) + let value = operand2 - operand1 + Machine(..machine, registers: set_register(machine, reg2, <>)) + }), + Def(23, 2, "SVC", fn(machine: Machine, _code: BitArray) -> Machine { machine }), - Def(23, 2, "SVC", fn(machine: Machine, code: BitArray) -> Machine { - machine + Def(23, 3, "TD", fn(machine: Machine, code: BitArray) -> Machine { + let assert <> = get_operand34(machine, code, 1) + let #(dev, machine) = case dict.get(machine.devices, devnr) { + Ok(d) -> #(d, machine) + Error(Nil) -> { + let d = device.open(int.to_base16(devnr) <> ".dev") + #( + d, + Machine(..machine, devices: dict.insert(machine.devices, devnr, d)), + ) + } + } + let dev = device.test_device(dev) + Machine( + ..machine, + devices: dict.insert(machine.devices, devnr, dev), + registers: registers.Registers(..machine.registers, sw: <<0x40:24>>), + ) }), - Def(23, 3, "TD", fn(machine: Machine, code: BitArray) -> Machine { machine }), - Def(23, 1, "TIO", fn(machine: Machine, code: BitArray) -> Machine { + Def(23, 1, "TIO", fn(machine: Machine, _code: BitArray) -> Machine { machine }), Def(23, 3, "TIX", fn(machine: Machine, code: BitArray) -> Machine { - machine + let assert <> = machine.registers.x + let x = x + 1 + let operand = get_operand34(machine, code, 3) + let sw = case bit_array.compare(machine.registers.x, operand) { + order.Lt -> <<0x80:24>> + order.Eq -> <<0:24>> + order.Gt -> <<0x40:24>> + } + Machine( + ..machine, + registers: registers.Registers(..machine.registers, sw: sw, x: <>), + ) }), Def(23, 2, "TIXR", fn(machine: Machine, code: BitArray) -> Machine { - machine + let assert <> = machine.registers.x + let x = x + 1 + let assert <<_opcode:8, reg1:4, _reg2:4>> = code + let sw = case + bit_array.compare(machine.registers.x, get_register(machine, reg1)) + { + order.Lt -> <<0x80:24>> + order.Eq -> <<0:24>> + order.Gt -> <<0x40:24>> + } + Machine( + ..machine, + registers: registers.Registers(..machine.registers, sw: sw, x: <>), + ) + }), + Def(23, 3, "WD", fn(machine: Machine, code: BitArray) -> Machine { + let assert <> = get_operand34(machine, code, 1) + let assert <<_:16, char:bits>> = machine.registers.a + let dev = case dict.get(machine.devices, devnr) { + Ok(d) -> device.write(d, char) + Error(Nil) -> { + let d = device.open(int.to_base16(devnr) <> ".dev") + device.write(d, char) + } + } + Machine(..machine, devices: dict.insert(machine.devices, devnr, dev)) }), - Def(23, 3, "WD", fn(machine: Machine, code: BitArray) -> Machine { machine }), ] } diff --git a/sim/src/sim/memory.gleam b/sim/src/sim/memory.gleam index d3a2835..88ff75a 100644 --- a/sim/src/sim/memory.gleam +++ b/sim/src/sim/memory.gleam @@ -3,7 +3,7 @@ import gleam/bit_array pub type Memory = BitArray -fn pad_to_length(memory: Memory, lenght: Int) -> Memory { +pub fn pad_to_length(memory: Memory, lenght: Int) -> Memory { case bit_array.bit_size(memory) < lenght { True -> { pad_to_length(<>, lenght) @@ -12,20 +12,29 @@ fn pad_to_length(memory: Memory, lenght: Int) -> Memory { } } -pub fn insert_at(memory: Memory, pos: Int, value: BitArray) -> Memory { - let memory = case pos >= bit_array.bit_size(memory) { +pub fn left_pad_to_length(memory: Memory, lenght: Int) -> Memory { + case bit_array.bit_size(memory) < lenght { True -> { - pad_to_length(memory, pos) + pad_to_length(<<0:1, memory:bits>>, lenght) + } + _ -> memory + } +} + +pub fn insert_at(memory: Memory, pos: Int, value: BitArray) -> Memory { + let memory = case pos > bit_array.byte_size(memory) { + True -> { + pad_to_length(memory, pos * 8) } False -> memory } - let length = bit_array.bit_size(value) + let length = bit_array.byte_size(value) let assert Ok(head) = bit_array.slice(memory, 0, pos) case bit_array.slice( memory, pos + length, - bit_array.bit_size(memory) - pos - length, + bit_array.byte_size(memory) - pos - length, ) { Ok(tail) -> <> @@ -52,7 +61,7 @@ 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, 5) + let assert Ok(value) = bit_array.slice(memory, pos, 6) value } diff --git a/sim/test/sim_test.gleam b/sim/test/sim_test.gleam index fba3c88..0cc33bd 100644 --- a/sim/test/sim_test.gleam +++ b/sim/test/sim_test.gleam @@ -1,4 +1,6 @@ import gleeunit +import sim/device +import sim/memory pub fn main() -> Nil { gleeunit.main() @@ -11,3 +13,35 @@ pub fn hello_world_test() { assert greeting == "Hello, Joe!" } + +pub fn pad_test() { + assert <<1, 2, 3, 0>> == memory.pad_to_length(<<1, 2, 3>>, 32) +} + +pub fn insert_test() { + assert <<1, 2, 3, 4>> == memory.insert_at(<<1, 2, 3>>, 3, <<4>>) + assert <<1, 2, 3, 0, 5>> == memory.insert_at(<<1, 2, 3>>, 4, <<5>>) + assert <<1, 67, 3>> == memory.insert_at(<<1, 2, 3>>, 1, <<67>>) +} + +pub fn open_test() { + let d0 = device.open("0") + device.close(d0) +} + +pub fn test_device_test() { + let d1 = device.open("1") + assert <<>> == device.read(d1).0 + let d1 = device.test_device(d1) + assert d1.has_data == True + let #(char, d1) = device.read(d1) + assert <<"a">> == char + assert d1.has_data == False + assert <<>> == device.read(d1).0 + device.close(d1) + + let d0 = device.open("0") + let d0 = device.test_device(d0) + assert d0.has_data == False + device.close(d0) +}