RosettaCodeData/Task/Execute-Computer-Zero/Julia/execute-computer-zero-1.jl

176 lines
3.6 KiB
Julia

mutable struct ComputerZero
ip::Int
ram::Vector{UInt8}
accum::UInt8
isready::Bool
end
function ComputerZero(program)
memory = zeros(UInt8, 32)
for i in 1:min(32, length(program))
memory[i] = program[i]
end
return ComputerZero(1, memory, 0, true)
end
NOP(c) = (c.ip = mod1(c.ip + 1, 32))
LDA(c) = (c.accum = c.ram[c.ram[c.ip] & 0b00011111 + 1]; c.ip = mod1(c.ip + 1, 32))
STA(c) = (c.ram[c.ram[c.ip] & 0b00011111 + 1] = c.accum; c.ip = mod1(c.ip + 1, 32))
ADD(c) = (c.accum += c.ram[c.ram[c.ip] & 0b00011111 + 1]; c.ip = mod1(c.ip + 1, 32))
SUB(c) = (c.accum -= c.ram[c.ram[c.ip] & 0b00011111 + 1]; c.ip = mod1(c.ip + 1, 32))
BRZ(c) = (c.ip = (c.accum == 0) ? c.ram[c.ip] & 0b00011111 + 1 : mod1(c.ip + 1, 32))
JMP(c) = (c.ip = c.ram[c.ip] & 0b00011111 + 1)
STP(c) = (println("Program completed with accumulator value $(c.accum).\n"); c.isready = false)
const step = [NOP, LDA, STA, ADD, SUB, BRZ, JMP, STP]
const instructions = ["NOP", "LDA", "STA", "ADD", "SUB", "BRZ", "JMP", "STP"]
const assemblywords = Dict(s => i - 1 for (i, s) in pairs(instructions))
function run(compzero::ComputerZero, debug = false)
while compzero.isready
instruction = compzero.ram[compzero.ip]
opcode, operand = instruction >> 5 + 1, instruction & 0b00011111
debug && println("op $(instructions[opcode]), operand $operand")
step[opcode](compzero)
end
return compzero.accum
end
run(program::Vector, debug = false) = run(ComputerZero(program), debug)
function compile(text::String)
bin, lines = UInt8[], 0
for line in strip.(split(text, "\n"))
lines += 1
if isempty(line)
push!(bin, 0)
elseif (m = match(r"(\w\w\w)\s+(\d\d?)", line)) != nothing
push!(bin, UInt8((assemblywords[m.captures[1]] << 5) | parse(UInt8, m.captures[2])))
elseif (m = match(r"(\w\w\w)", line)) != nothing
push!(bin, UInt8(assemblywords[m.match] << 5))
elseif (m = match(r"\d\d?", line)) != nothing
push!(bin, parse(UInt8, m.match))
else
error("Compilation error at line $lines: error parsing <$line>")
end
end
println("Compiled $lines lines.")
return bin
end
const testprograms = [
"""
LDA 3
ADD 4
STP
2
2
""",
"""
LDA 12
ADD 10
STA 12
LDA 11
SUB 13
STA 11
BRZ 8
JMP 0
LDA 12
STP
8
7
0
1
""",
"""
LDA 14
STA 15
ADD 13
STA 14
LDA 15
STA 13
LDA 16
SUB 17
BRZ 11
STA 16
JMP 0
LDA 14
STP
1
1
0
8
1
""",
"""
LDA 13
ADD 15
STA 5
ADD 16
STA 7
NOP
STA 14
NOP
BRZ 11
STA 15
JMP 0
LDA 14
STP
LDA 0
0
28
1
6
0
2
26
5
20
3
30
1
22
4
24
""",
"""
0
0
STP
NOP
LDA 3
SUB 29
BRZ 18
LDA 3
STA 29
BRZ 14
LDA 1
ADD 31
STA 1
JMP 2
LDA 0
ADD 31
STA 0
JMP 2
LDA 3
STA 29
LDA 0
ADD 30
ADD 3
STA 0
LDA 1
ADD 30
ADD 3
STA 1
JMP 2
0
1
3
"""
]
for t in testprograms
run(compile(t))
end