first steps sim
This commit is contained in:
parent
a9323bb7d9
commit
25c1c1eb6c
4 changed files with 221 additions and 29 deletions
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 }),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue