How to resolve the algorithm Execute Computer/Zero step by step in the Julia programming language

Published on 22 June 2024 08:30 PM

How to resolve the algorithm Execute Computer/Zero step by step in the Julia programming language

Table of Contents

Problem Statement

Create a Computer/zero Assembly emulator. You may consider this webpage as a reference implementation. Output the results of the sample programs "2+2" and "7*8" found there.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Execute Computer/Zero step by step in the Julia programming language

The code is a program written in the Julia programming language that simulates a simple 8-bit computer called the "ComputerZero". It includes several functions and macros that define the behavior of the computer and its instructions. Here's a breakdown of the code:

  1. ComputerZero Struct:

    • Defines a custom struct called ComputerZero that represents the computer itself.
    • It contains fields such as ip for the instruction pointer, ram for the memory, accum for the accumulator, and isready to indicate if the computer is still running.
  2. ComputerZero Constructor:

    • This function initializes a ComputerZero struct with the specified program as a vector of unsigned 8-bit integers.
    • It populates the first 32 bytes of memory with the program instructions and sets the other fields to their initial values.
  3. Instruction Definitions:

    • A series of macros (NOP, LDA, STA, ADD, SUB, BRZ, JMP, and STP) define the behavior of each instruction.
    • These macros update the computer's state based on the instruction being executed. For example, LDA loads a value from memory into the accumulator, while ADD adds a value from memory to the accumulator.
  4. step and instructions Arrays:

    • step is an array that maps each instruction opcode to its corresponding macro.
    • instructions is an array that contains the string names of the instructions.
  5. run Function:

    • This function runs the specified ComputerZero instance by executing instructions one by one until it completes or encounters an error.
    • It uses the step array to execute the appropriate instruction for each opcode.
  6. compile Function:

    • This function takes an assembly language program as a string and compiles it into a vector of unsigned 8-bit integers that can be loaded into the computer's memory.
    • It parses the assembly instructions and translates them into the corresponding opcodes and operands.
  7. testprograms Array:

    • Defines several test programs in assembly language that are used for testing the computer.
  8. interpret Function:

    • This function is similar to the run function but interprets the assembly language instructions directly without compiling them.
    • It uses a custom interpreter that parses the assembly instructions and executes them one by one.
  9. Additional Test Programs:

    • Several more test programs are defined in assembly language to demonstrate the capabilities of the computer and the interpreter.

Overall, this code provides a framework for simulating a simple 8-bit computer and executing assembly language programs on it. The modular design and use of macros make it easy to add new instructions and modify the behavior of the computer.

Source code in the julia programming language

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


function interpret(text::String)
    ip, accum, isready, ram = 0x1, 0x0, true, zeros(UInt8, 32)
    NOP() = (ip = mod1(ip + 1, 32))
    LDA() = (accum = ram[ram[ip] & 0b00011111 + 1]; ip = mod1(ip + 1, 32))
    STA() = (ram[ram[ip] & 0b00011111 + 1] = accum; ip = mod1(ip + 1, 32))
    ADD() = (accum += ram[ram[ip] & 0b00011111 + 1]; ip = mod1(ip + 1, 32))
    SUB() = (accum -= ram[ram[ip] & 0b00011111 + 1]; ip = mod1(ip + 1, 32))
    BRZ() = (ip = (accum == 0) ? ram[ip] & 0b00011111 + 1 : mod1(ip + 1, 32))
    JMP() = (ip = ram[ip] & 0b00011111 + 1)
    STP() = (println("Program completed with accumulator value $(accum).\n"); isready = false)
    step = [NOP, LDA, STA, ADD, SUB, BRZ, JMP, STP]
    assemblywords = Dict(s => i - 1 for (i, s) in pairs(string.(step)))
    labels = Dict{String, Int}()
    arglabels = Dict{Int, Tuple{Int, String}}()
    for (i, line) in pairs(strip.(split(text, "\n")))
        i > 32 && break
        line = replace(line, r";.*$" => "")  # remove comment
        if occursin(":", line)
            label, line = split(line, ":", limit = 2)
            haskey(labels, label) && error("Duplicate label at line $i")
            labels[strip(label)] = i - 1
        end
        if isempty(line)
           ram[i] = 0
        elseif (m = match(r"(\w\w\w)\s+([a-zA-Z]\w*)", line)) != nothing
            arglabels[i] = (UInt8((assemblywords[m.captures[1]] << 5)), m.captures[2])
        elseif (m = match(r"(\w\w\w)\s+(\d\d*)", line)) != nothing
            ram[i] = UInt8((assemblywords[m.captures[1]] << 5) | parse(UInt8, m.captures[2]))
        elseif (m = match(r"([a-zA-Z]\w*)", line)) != nothing
            ram[i] = UInt8(assemblywords[m.match] << 5)
        elseif (m = match(r"\d\d*", line)) != nothing
                ram[i] = parse(UInt8, m.match)
        else
            error("Compilation error at line $i: error parsing <$line>")
        end
    end
    for (i, t) in arglabels
        ram[i] = t[1] | labels[t[2]]
    end
    while isready
        step[ram[ip] >> 5 + 1]()
    end
    return accum
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
    """,
    """\
            LDA   x
            ADD   y       ; accumulator = x + y
            STP
    x:            2
    y:            2
    """,
    """\
    loop:   LDA   prodt
            ADD   x
            STA   prodt
            LDA   y
            SUB   one
            STA   y
            BRZ   done
            JMP   loop
    done:   LDA   prodt   ; to display it
            STP
    x:            8
    y:            7
    prodt:        0
    one:          1
    """,
    """\
    loop:   LDA   n
            STA   temp
            ADD   m
            STA   n
            LDA   temp
            STA   m
            LDA   count
            SUB   one
            BRZ   done
            STA   count
            JMP   loop
    done:   LDA   n       ; to display it
            STP
    m:            1
    n:            1
    temp:         0
    count:        8       ; valid range: 1-11
    one:          1
    """,
    """\
    start:  LDA   load
            ADD   car     ; head of list
            STA   ldcar
            ADD   one
            STA   ldcdr   ; next CONS cell
    ldcar:  NOP
            STA   value
    ldcdr:  NOP
            BRZ   done    ; 0 stands for NIL
            STA   car
            JMP   start
    done:   LDA   value   ; CAR of last CONS
            STP
    load:   LDA   0
    value:        0
    car:          28
    one:          1
                        ; order of CONS cells
                        ; in memory
                        ; does not matter
                6
                0       ; 0 stands for NIL
                2       ; (CADR ls)
                26      ; (CDDR ls) -- etc.
                5
                20
                3
                30
                1       ; value of (CAR ls)
                22      ; points to (CDR ls)
                4
                24
    """,
    """\
    p:            0       ; NOP in first round
    c:            0
    start:  STP           ; wait for p's move
    pmove:  NOP
            LDA   pmove
            SUB   cmove
            BRZ   same
            LDA   pmove
            STA   cmove   ; tit for tat
            BRZ   cdeft
            LDA   c       ; p defected, c did not
            ADD   three
            STA   c
            JMP   start
    cdeft:  LDA   p
            ADD   three
            STA   p
            JMP   start
    same:   LDA   pmove
            STA   cmove   ; tit for tat
            LDA   p
            ADD   one
            ADD   pmove
            STA   p
            LDA   c
            ADD   one
            ADD   pmove
            STA   c
            JMP   start
    cmove:        0       ; co-operate initially
    one:          1
    three:        3
    """,
    """\
    LDA  3
    SUB  4
    STP  0
         0
         255
    """,
    """\
    LDA  3
    SUB  4
    STP  0
         0
         1
    """,
    """\
    LDA  3
    ADD  4
    STP  0
         1
         255
    """,
]

for t in testprograms
    interpret(t)
end


  

You may also check:How to resolve the algorithm Factors of a Mersenne number step by step in the Crystal programming language
You may also check:How to resolve the algorithm Greatest element of a list step by step in the PureBasic programming language
You may also check:How to resolve the algorithm Sieve of Eratosthenes step by step in the PowerShell programming language
You may also check:How to resolve the algorithm User input/Text step by step in the Oz programming language
You may also check:How to resolve the algorithm Mandelbrot set step by step in the Forth programming language