simulator
This commit is contained in:
parent
6d722acba9
commit
a9323bb7d9
10 changed files with 459 additions and 0 deletions
24
sim/README.md
Normal file
24
sim/README.md
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# sim
|
||||||
|
|
||||||
|
[](https://hex.pm/packages/sim)
|
||||||
|
[](https://hexdocs.pm/sim/)
|
||||||
|
|
||||||
|
```sh
|
||||||
|
gleam add sim@1
|
||||||
|
```
|
||||||
|
```gleam
|
||||||
|
import sim
|
||||||
|
|
||||||
|
pub fn main() -> Nil {
|
||||||
|
// TODO: An example of the project in use
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Further documentation can be found at <https://hexdocs.pm/sim>.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
```sh
|
||||||
|
gleam run # Run the project
|
||||||
|
gleam test # Run the tests
|
||||||
|
```
|
||||||
21
sim/gleam.toml
Normal file
21
sim/gleam.toml
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
name = "sim"
|
||||||
|
version = "1.0.0"
|
||||||
|
|
||||||
|
|
||||||
|
# Fill out these fields if you intend to generate HTML documentation or publish
|
||||||
|
# your project to the Hex package manager.
|
||||||
|
#
|
||||||
|
# description = ""
|
||||||
|
# licences = ["Apache-2.0"]
|
||||||
|
# repository = { type = "github", user = "", repo = "" }
|
||||||
|
# links = [{ title = "Website", href = "" }]
|
||||||
|
#
|
||||||
|
# For a full reference of all the available options, you can have a look at
|
||||||
|
# https://gleam.run/writing-gleam/gleam-toml/.
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
|
||||||
|
file_streams = ">= 1.7.0 and < 2.0.0"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
gleeunit = ">= 1.0.0 and < 2.0.0"
|
||||||
13
sim/manifest.toml
Normal file
13
sim/manifest.toml
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
# This file was generated by Gleam
|
||||||
|
# You typically do not need to edit this file
|
||||||
|
|
||||||
|
packages = [
|
||||||
|
{ name = "file_streams", version = "1.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "file_streams", source = "hex", outer_checksum = "62757932B5FAC14FC9D0EE69BC4694DC6EA9F0FE6E198F695711C4FCAC1F7A26" },
|
||||||
|
{ name = "gleam_stdlib", version = "0.67.1", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "6CE3E4189A8B8EC2F73AB61A2FBDE49F159D6C9C61C49E3B3082E439F260D3D0" },
|
||||||
|
{ name = "gleeunit", version = "1.9.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "DA9553CE58B67924B3C631F96FE3370C49EB6D6DC6B384EC4862CC4AAA718F3C" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[requirements]
|
||||||
|
file_streams = { version = ">= 1.7.0 and < 2.0.0" }
|
||||||
|
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
|
||||||
|
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
|
||||||
8
sim/src/sim.gleam
Normal file
8
sim/src/sim.gleam
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import sim/machine
|
||||||
|
|
||||||
|
pub fn main() -> Nil {
|
||||||
|
let machine = machine.init("../arith.obj")
|
||||||
|
echo machine
|
||||||
|
machine.step(machine, machine.get_instructions())
|
||||||
|
Nil
|
||||||
|
}
|
||||||
61
sim/src/sim/loader.gleam
Normal file
61
sim/src/sim/loader.gleam
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
import file_streams/file_stream
|
||||||
|
import gleam/bit_array
|
||||||
|
import gleam/list
|
||||||
|
import gleam/result
|
||||||
|
import gleam/string
|
||||||
|
import sim/memory
|
||||||
|
|
||||||
|
type RecordType {
|
||||||
|
H
|
||||||
|
T
|
||||||
|
E
|
||||||
|
}
|
||||||
|
|
||||||
|
fn record_from_string(str: String) -> RecordType {
|
||||||
|
case str {
|
||||||
|
"H" <> _ -> H
|
||||||
|
"T" <> _ -> T
|
||||||
|
"E" <> _ | _ -> E
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Record {
|
||||||
|
Record(record_type: RecordType, content: BitArray)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_record(stream: file_stream.FileStream) -> Record {
|
||||||
|
let assert Ok(line) = file_stream.read_line(stream)
|
||||||
|
Record(
|
||||||
|
record_from_string(line),
|
||||||
|
result.unwrap(
|
||||||
|
bit_array.base16_decode(string.drop_end(string.drop_start(line, 1), 1)),
|
||||||
|
<<0>>,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_section(stream: file_stream.FileStream) -> List(Record) {
|
||||||
|
let record = read_record(stream)
|
||||||
|
case record.record_type {
|
||||||
|
E -> [record]
|
||||||
|
_ -> [record, ..read_section(stream)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 <<position:24, _len:8, value:bits>> = record.content
|
||||||
|
echo position
|
||||||
|
echo bit_array.base16_encode(value)
|
||||||
|
memory.insert_at(memory, position, value)
|
||||||
|
}
|
||||||
|
_ -> memory
|
||||||
|
}
|
||||||
|
|> echo
|
||||||
|
})
|
||||||
|
}
|
||||||
223
sim/src/sim/machine.gleam
Normal file
223
sim/src/sim/machine.gleam
Normal file
|
|
@ -0,0 +1,223 @@
|
||||||
|
import gleam/list
|
||||||
|
import gleam/result
|
||||||
|
import sim/loader
|
||||||
|
import sim/memory
|
||||||
|
import sim/registers
|
||||||
|
|
||||||
|
pub type Machine {
|
||||||
|
Machine(memory: memory.Memory, registers: registers.Registers)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(program: String) -> Machine {
|
||||||
|
Machine(loader.load_obj(program), registers.new())
|
||||||
|
}
|
||||||
|
|
||||||
|
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 inst = case def.size {
|
||||||
|
1 -> Instruction(1, char, def.modifier)
|
||||||
|
2 ->
|
||||||
|
Instruction(
|
||||||
|
2,
|
||||||
|
<<
|
||||||
|
char:bits,
|
||||||
|
memory.get_char_at(memory, ptr + 1):bits,
|
||||||
|
>>,
|
||||||
|
def.modifier,
|
||||||
|
)
|
||||||
|
3 | _ -> Instruction(3, memory.get_int_at(memory, ptr), def.modifier)
|
||||||
|
}
|
||||||
|
inst
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn step(machine: Machine, instructions: List(Def)) -> Machine {
|
||||||
|
let assert <<pc:24>> = machine.registers.pc
|
||||||
|
|
||||||
|
fetch_instruction(instructions, machine.memory, pc)
|
||||||
|
|
||||||
|
machine
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Instruction {
|
||||||
|
Instruction(
|
||||||
|
size: Int,
|
||||||
|
source: BitArray,
|
||||||
|
modifier: fn(Machine, BitArray) -> Machine,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Def {
|
||||||
|
Def(
|
||||||
|
opcode: Int,
|
||||||
|
size: Int,
|
||||||
|
mnemonic: String,
|
||||||
|
modifier: fn(Machine, BitArray) -> Machine,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_instructions() -> List(Def) {
|
||||||
|
[
|
||||||
|
Def(6, 3, "ADD", fn(machine: Machine, code: BitArray) -> Machine { machine }),
|
||||||
|
Def(22, 3, "ADDF", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(36, 2, "ADDR", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(16, 3, "AND", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(45, 2, "CLEAR", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(10, 3, "COMP", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
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 { machine }),
|
||||||
|
Def(25, 3, "DIVF", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(39, 2, "DIVR", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(49, 1, "FIX", 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 {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(15, 3, "J", fn(machine: Machine, code: BitArray) -> Machine { machine }),
|
||||||
|
Def(12, 3, "JEQ", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(13, 3, "JGT", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(14, 3, "JLT", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(18, 3, "JSUB", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(0, 3, "LDA", fn(machine: Machine, code: BitArray) -> Machine { machine }),
|
||||||
|
Def(26, 3, "LDB", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(20, 3, "LDCH", 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 { machine }),
|
||||||
|
Def(27, 3, "LDS", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(29, 3, "LDT", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(1, 3, "LDX", fn(machine: Machine, code: BitArray) -> Machine { machine }),
|
||||||
|
Def(52, 3, "LPS", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(8, 3, "MUL", fn(machine: Machine, code: BitArray) -> Machine { machine }),
|
||||||
|
Def(24, 3, "MULF", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(38, 2, "MULR", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(50, 1, "NORM", 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 {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(19, 3, "RSUB", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(41, 2, "SHIFTL", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(42, 2, "SHIFTR", 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 {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(3, 3, "STA", fn(machine: Machine, code: BitArray) -> Machine { machine }),
|
||||||
|
Def(30, 3, "STB", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(21, 3, "STCH", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(32, 3, "STF", 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 { machine }),
|
||||||
|
Def(31, 3, "STS", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(58, 3, "STSW", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(33, 3, "STT", 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(23, 3, "SUBF", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(23, 2, "SUBR", 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 { machine }),
|
||||||
|
Def(23, 1, "TIO", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(23, 3, "TIX", fn(machine: Machine, code: BitArray) -> Machine {
|
||||||
|
machine
|
||||||
|
}),
|
||||||
|
Def(23, 2, "TIXR", 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 }),
|
||||||
|
)
|
||||||
|
}
|
||||||
61
sim/src/sim/memory.gleam
Normal file
61
sim/src/sim/memory.gleam
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
import gleam/bit_array
|
||||||
|
|
||||||
|
pub type Memory =
|
||||||
|
BitArray
|
||||||
|
|
||||||
|
fn pad_to_length(memory: Memory, lenght: Int) -> Memory {
|
||||||
|
case bit_array.bit_size(memory) < lenght {
|
||||||
|
True -> {
|
||||||
|
pad_to_length(<<memory:bits, 0:1>>, lenght)
|
||||||
|
}
|
||||||
|
_ -> memory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_at(memory: Memory, pos: Int, value: BitArray) -> Memory {
|
||||||
|
let memory = case pos >= bit_array.bit_size(memory) {
|
||||||
|
True -> {
|
||||||
|
pad_to_length(memory, pos)
|
||||||
|
}
|
||||||
|
False -> memory
|
||||||
|
}
|
||||||
|
let length = bit_array.bit_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,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Ok(tail) -> <<head:bits, value:bits, tail:bits>>
|
||||||
|
Error(Nil) -> <<head:bits, value:bits>>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_char_at(memory: Memory, pos: Int) -> BitArray {
|
||||||
|
let assert Ok(value) = bit_array.slice(memory, pos, 8)
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_char_at(memory: Memory, pos: Int, value: BitArray) -> Memory {
|
||||||
|
insert_at(memory, pos, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_int_at(memory: Memory, pos: Int) -> BitArray {
|
||||||
|
let assert Ok(value) = bit_array.slice(memory, pos, 24)
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_int_at(memory: Memory, pos: Int, value: BitArray) -> Memory {
|
||||||
|
insert_at(memory, pos, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_float_at(memory: Memory, pos: Int) -> BitArray {
|
||||||
|
let assert Ok(value) = bit_array.slice(memory, pos, 40)
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_float_at(memory: Memory, pos: Int, value: BitArray) -> Memory {
|
||||||
|
insert_at(memory, pos, value)
|
||||||
|
}
|
||||||
6
sim/src/sim/register.gleam
Normal file
6
sim/src/sim/register.gleam
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
pub type Register =
|
||||||
|
BitArray
|
||||||
|
|
||||||
|
pub fn new() -> Register {
|
||||||
|
<<0:size(24)>>
|
||||||
|
}
|
||||||
29
sim/src/sim/registers.gleam
Normal file
29
sim/src/sim/registers.gleam
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import sim/register
|
||||||
|
|
||||||
|
pub type Registers {
|
||||||
|
Registers(
|
||||||
|
a: register.Register,
|
||||||
|
x: register.Register,
|
||||||
|
l: register.Register,
|
||||||
|
b: register.Register,
|
||||||
|
s: register.Register,
|
||||||
|
t: register.Register,
|
||||||
|
f: register.Register,
|
||||||
|
pc: register.Register,
|
||||||
|
sw: register.Register,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new() -> Registers {
|
||||||
|
Registers(
|
||||||
|
register.new(),
|
||||||
|
register.new(),
|
||||||
|
register.new(),
|
||||||
|
register.new(),
|
||||||
|
register.new(),
|
||||||
|
register.new(),
|
||||||
|
register.new(),
|
||||||
|
register.new(),
|
||||||
|
register.new(),
|
||||||
|
)
|
||||||
|
}
|
||||||
13
sim/test/sim_test.gleam
Normal file
13
sim/test/sim_test.gleam
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import gleeunit
|
||||||
|
|
||||||
|
pub fn main() -> Nil {
|
||||||
|
gleeunit.main()
|
||||||
|
}
|
||||||
|
|
||||||
|
// gleeunit test functions end in `_test`
|
||||||
|
pub fn hello_world_test() {
|
||||||
|
let name = "Joe"
|
||||||
|
let greeting = "Hello, " <> name <> "!"
|
||||||
|
|
||||||
|
assert greeting == "Hello, Joe!"
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue