Implement atomic assembler
This commit is contained in:
parent
595ae8ce20
commit
d43f79500d
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
Loading…
Reference in New Issue