diff --git a/assembly/atomic_assembler.lua b/assembly/atomic_assembler.lua new file mode 100644 index 0000000..e6f3e9b --- /dev/null +++ b/assembly/atomic_assembler.lua @@ -0,0 +1,52 @@ +local function split_string(input_str, delimiter) + local result = {} + for match in (input_str .. delimiter):gmatch("(.-)" .. delimiter) do + table.insert(result, match) + end + return result +end + +function AssembleAtomicCode(buffer) + local brainfuck_code = "" + + buffer = buffer:gsub(" ", ";") + buffer = buffer:gsub("\n", ";") + buffer = buffer:gsub("\t", ";") + + local tokens = split_string(buffer, ";") + local is_comment = false + + for index, token in ipairs(tokens) do + if token == "##" and is_comment then + brainfuck_code = brainfuck_code .. "\n" + is_comment = false + elseif token == "##" and not is_comment then + brainfuck_code = brainfuck_code .. "\n" + is_comment = true + elseif is_comment then + brainfuck_code = brainfuck_code .. token .. " " + elseif token == "up" then + brainfuck_code = brainfuck_code .. ">" + elseif token == "down" then + brainfuck_code = brainfuck_code .. "<" + elseif token == "inc" then + brainfuck_code = brainfuck_code .. "+" + elseif token == "dec" then + brainfuck_code = brainfuck_code .. "-" + elseif token == "get" then + brainfuck_code = brainfuck_code .. "," + elseif token == "set" then + brainfuck_code = brainfuck_code .. "." + elseif token == "begin" then + brainfuck_code = brainfuck_code .. "[" + elseif token == "end" then + brainfuck_code = brainfuck_code .. "]" + else + if token ~= "\0" then + print("ERROR: The token " .. token .. " is not an atomic token!" .. token) + end + end + end + + return brainfuck_code +end diff --git a/assembly/basic_logic.bf b/assembly/basic_logic.bf new file mode 100644 index 0000000..e2bb7a1 --- /dev/null +++ b/assembly/basic_logic.bf @@ -0,0 +1,16 @@ +## Loading cell 0 with 5 and cell 1 with 3 ## +inc inc inc inc inc +up +inc inc inc +down + +## Adding cell 0 to cell 1 ## +begin + dec + up + inc + down +end + +up up inc +begin end diff --git a/assembly/brainfuck_compiler.lua b/assembly/brainfuck_compiler.lua new file mode 100644 index 0000000..9270cb9 --- /dev/null +++ b/assembly/brainfuck_compiler.lua @@ -0,0 +1,98 @@ +function wait(seconds) + local start = os.time() + repeat + until os.time() > start + seconds +end + +function CompileBrainfuck(brainfuck, target) + local machine_code = "(" + + if target == "vhdl" then + machine_code = "(" + elseif target == "logisim" then + machine_code = "v3.0 hex words plain\n" + else + print("ERROR: Target " .. target .. " is not supported!") + end + + for i = 0, #brainfuck do + local token = brainfuck:sub(i, i) + + if target == "vhdl" then + if token == ">" then + machine_code = machine_code .. 'b"000",' + elseif token == "<" then + machine_code = machine_code .. 'b"001",' + elseif token == "+" then + machine_code = machine_code .. 'b"010",' + elseif token == "-" then + machine_code = machine_code .. 'b"011",' + elseif token == "," then + machine_code = machine_code .. 'b"100",' + elseif token == "." then + machine_code = machine_code .. 'b"101",' + elseif token == "[" then + machine_code = machine_code .. 'b"110",' + elseif token == "]" then + machine_code = machine_code .. 'b"111",' + end + elseif target == "logisim" then + local found_token = false + if token == ">" then + machine_code = machine_code .. "0" + found_token = true + elseif token == "<" then + machine_code = machine_code .. "1" + found_token = true + elseif token == "+" then + machine_code = machine_code .. "2" + found_token = true + elseif token == "-" then + machine_code = machine_code .. "3" + found_token = true + elseif token == "," then + machine_code = machine_code .. "4" + found_token = true + elseif token == "." then + machine_code = machine_code .. "5" + found_token = true + elseif token == "[" then + machine_code = machine_code .. "6" + found_token = true + elseif token == "]" then + machine_code = machine_code .. "7" + found_token = true + end + + if found_token then + if (#machine_code - 20) % 64 == 0 then + machine_code = machine_code .. "\n" + else + machine_code = machine_code .. " " + end + end + else + print("ERROR: Target " .. target .. " is not supported!") + end + end + + if target == "vhdl" then + + machine_code = machine_code .. 'others => "000");\n' + + elseif target == "logisim" then + while #machine_code < 533 do + machine_code = machine_code .. '0' + + if (#machine_code - 20) % 64 == 0 then + machine_code = machine_code .. "\n" + else + machine_code = machine_code .. " " + end + end + else + print("ERROR: Target " .. target .. " not found!") + end + + return machine_code +end diff --git a/assembly/complex_assembler.lua b/assembly/complex_assembler.lua new file mode 100644 index 0000000..57657c5 --- /dev/null +++ b/assembly/complex_assembler.lua @@ -0,0 +1,153 @@ +function AssembleComplexCode(content) + local atomic = "" + memory_pointer = 0 + local state = "idle" + local instruction = {} + + content = content:gsub(" ", ";") + content = content:gsub("\n", ";") + content = content:gsub("\t", ";") + + local tokens = split_string(content, ";") + local is_comment = false + + for index, token in ipairs(tokens) do + if token == "##" and is_comment then + atomic = atomic .. " ##\n" + is_comment = false + elseif token == "##" and not is_comment then + atomic = "## " .. atomic .. "\n" + is_comment = true + elseif is_comment then + atomic = atomic .. token .. " " + elseif state == "idle" then + state, instruction = decode_instruction(token) + elseif state == "twooperands" then + table.insert(instruction, token) + state = "oneoperand" + elseif state == "oneoperand" then + table.insert(instruction, token) + state = "handling" + elseif state == "handling" then + atomic = handle_instrcution(content, instruction) + else + if token ~= "\0" then + print("ERROR: The token " .. token .. " is not a valid instruction!") + end + end + end + + return atomic +end + +local function decode_instruction(operand_token) + local singop = {} + local oneop = { "loop" } + local twoop = { "add", "sub" } + + if singop[operand_token] ~= nil then + return "handle", { operand_token } + elseif oneop[operand_token] ~= nil then + return "oneoperand", { operand_token } + elseif twoop[operand_token] ~= nil then + return "twooperands", { operand_token } + end + + return "idle", {} +end + +local function abs(number) + if number < 0 then + return number * -1 + else + return number + end +end + +local function get_fix_move(origin, destination) + local direction + local route = "" + + if origin < destination then + direction = "up" + else + direction = "down" + end + + for i = 0, abs(destination - origin) do + route = route .. direction .. " " + end + + return route +end + +local function handle_instrcution(content, instruction) + local atomic_code + + if instruction[1] == "add" then + local reg1 = tonumber(instruction[2]:sub(2)) + 8 + local reg2 = tonumber(instruction[3]:sub(2)) + 8 + local old_pos = memory_pointer + + atomic_code = "## ADD " .. instruction[2] .. " to " .. instruction[3] .. " ##\n" + + local move_to_operation = get_fix_move(old_pos, reg1) + local reg1_to_t1 = get_fix_move(reg1, 0) + local t2_to_reg1 = get_fix_move(2, reg1) + local reg1_to_t2 = get_fix_move(reg1, 2) + local t1_to_reg2 = get_fix_move(1, reg2) + local reg2_to_t1 = get_fix_move(reg2, 1) + local t1_to_origin = get_fix_move(1, old_pos) + + atomic_code = atomic_code .. move_to_operation + -- Move reg1 into t1,t2 + atomic_code = atomic_code .. "begin dec " .. reg1_to_t1 .. "inc up inc " .. t2_to_reg1 .. "end " + -- Move t2 into reg1 + atomic_code = atomic_code .. reg1_to_t2 .. "begin dec " .. t2_to_reg1 .. "inc " .. reg1_to_t2 .. "end " + -- Move to t1 + atomic_code = atomic_code .. "down " + -- Move t1 into reg2 + atomic_code = atomic_code .. "begin dec " .. t1_to_reg2 .. "inc " .. reg2_to_t1 .. "end " + -- Restore old position + atomic_code = atomic_code .. t1_to_origin + elseif instruction[1] == "sub" then + local reg1 = tonumber(instruction[2]:sub(2)) + 8 + local reg2 = tonumber(instruction[3]:sub(2)) + 8 + local old_pos = memory_pointer + + local move_to_operation = get_fix_move(old_pos, reg1) + local reg1_to_t1 = get_fix_move(reg1, 1) + local t1_to_reg1 = get_fix_move(1, reg1) + local reg1_to_reg2 = get_fix_move(reg1, reg2) + local reg2_to_t1 = get_fix_move(reg2, 1) + local t1_to_origin = get_fix_move(1, old_pos) + + atomic_code = "## SUB " .. instruction[2] .. " to " .. instruction[3] .. " ##\n" + + --move to reg1 + atomic_code = atomic_code .. move_to_operation + -- move reg1 into t1 + atomic_code = atomic_code .. "begin dec " .. reg1_to_t1 .. "inc " .. t1_to_reg1 .. "end " + -- move to t1 + atomic_code = atomic_code .. reg1_to_t1 + -- move t1 to reg1 and remove from reg2 + atomic_code = atomic_code + .. "begin dec " + .. t1_to_reg1 + .. "inc " + .. reg1_to_reg2 + .. "dec " + .. reg2_to_t1 + .. "end " + -- return to origin + atomic_code = atomic_code .. t1_to_origin + elseif instruction[1] == "loop" then + local reg = tonumber(instruction[2]:sub(2)) + 8 + print("ERROR: Loops are not yet implemented!") + else + print("ERROR: The instruction " .. instruction[1] .. " is not a valid instruction!") + return content + end + + return content .. atomic_code +end diff --git a/assembly/complex_assembly.md b/assembly/complex_assembly.md new file mode 100644 index 0000000..47ba466 --- /dev/null +++ b/assembly/complex_assembly.md @@ -0,0 +1,70 @@ +# Complex Assembly Functions + +## Memory sections + +1. Register Area +2. Stack +3. Open Memory + +## Navigation between sections + +- Compiler logs current position +- Registers can be navigated relative to zero index + +## Registers + +$r0 := 0 (constant to be replaced in code) +$r1 .. $r31 := all purpose registers +$io := Input/Output register (translates to read / write instruction) +$t1 .. $t8:= Registers to be used by the assembler only + +## Register cell map + +| cell | register | description | +| ---- | -------- | ---------------------------------- | +| 0 | $t1 | Start of hidden registers | +| 8 | $r1 | All purpose programmable registers | +| 40 | $mem | Random access memory | + +## Add function + +1. Store current position +2. Move to reg 1 +3. move reg 1 into t1, t2 +4. move t2 into reg 1 +5. move to t1 +6. move t1 to reg 2 +7. return to starting position + +### add $10 $11: + +Setup: >>>>>>>>>>>>>>>>>>++++++++++>+++++<<<<<<<<<<<<<<<<<<< + +Move to reg1: >>>>>>>>>>>>>>>>>> (move to operation) +Move reg 1 into t1, t2: [-<<<<<<<<<<<<<<<<<<+>+>>>>>>>>>>>>>>>>>] (reg1 to t1) +Move t2 into reg 1: <<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<] (reg1 to t2) +Move to t1: < +Move t1 to reg 2: [->>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<] (t2 to reg2) + +Optimization possible: + +1. Moving reg1 to t1 +2. Moving t1 to reg1 and reg2 +3. Return to starting position + +(Further optimization by checking the distances of reg1, reg2, t1 to avoid unnecessary steps) + +### sub $5, $12 + +1. Move reg1 into t1 +2. Move t1 into reg1, remove from reg2 + +while reg1: +reg1 -- +t1 ++ + +### loop + +Must store loop register and origin +Origin should be always the loop register inside loop +Old origin should be set on loopend diff --git a/assembly/test.lua b/assembly/test.lua new file mode 100644 index 0000000..9ad4bec --- /dev/null +++ b/assembly/test.lua @@ -0,0 +1,24 @@ +require("complex_assembler") +require("atomic_assembler") +require("brainfuck_compiler") + +local file = io.open("basic_logic.bf", "r") +local content = "" +if file ~= nil then + content = file:read("*all") +else + print("ERROR: Input file not found!") +end + +local atomic = AssembleComplexCode(content) + +local brainfuck = AssembleAtomicCode(atomic) + +local machine_code = CompileBrainfuck(brainfuck, "logisim") + +print(brainfuck) +print(machine_code) + +local logisim_file = io.open("logisim.mem", "w") + +logisim_file:write(machine_code)