Compare commits

...

3 Commits

7 changed files with 547 additions and 133 deletions

View File

@@ -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

16
assembly/basic_logic.bf Normal file
View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

24
assembly/test.lua Normal file
View File

@@ -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)

View File

@@ -8,195 +8,196 @@ use ieee.numeric_std.all;
-- Entity bfpu: brainfuck processing unit
entity bfpu is
port(
clk : in std_logic; -- board clock
sw : in std_logic_vector(7 downto 0); -- Input for instruction ,
debug : out std_logic_vector(7 downto 0); -- Value of currently selected logic cell.
led : out std_logic_vector(7 downto 0) -- Output for instruction .
port (
clk : in std_logic; -- board clock
sw : in std_logic_vector(7 downto 0); -- Input for instruction ,
debug : out std_logic_vector(7 downto 0); -- Value of currently selected logic cell.
led : out std_logic_vector(7 downto 0) -- Output for instruction .
);
end bfpu;
end entity bfpu;
-- Architecture arch of bfpu: setup and connect components
architecture arch of bfpu is
component instructionMemory
port(
instructionAddr : in std_logic_vector(7 downto 0);
instruction : out std_logic_vector(2 downto 0)
component instructionMemory is
port (
instructionAddr : in std_logic_vector(7 downto 0);
instruction : out std_logic_vector(2 downto 0)
);
end component;
end component instructionMemory;
component alu
port(
instruction : in std_logic_vector(2 downto 0);
old_cell : in std_logic_vector(7 downto 0);
old_pointer : in std_logic_vector(15 downto 0);
extern_in : in std_logic_vector(7 downto 0);
component alu is
port (
instruction : in std_logic_vector(2 downto 0);
old_cell : in std_logic_vector(7 downto 0);
old_pointer : in std_logic_vector(15 downto 0);
extern_in : in std_logic_vector(7 downto 0);
new_cell : out std_logic_vector(7 downto 0);
new_pointer : out std_logic_vector(15 downto 0);
enable_cell : out std_logic;
enable_ptr : out std_logic;
extern_out : out std_logic_vector(7 downto 0)
new_cell : out std_logic_vector(7 downto 0);
new_pointer : out std_logic_vector(15 downto 0);
enable_cell : out std_logic;
enable_ptr : out std_logic;
extern_out : out std_logic_vector(7 downto 0)
);
end component;
end component alu;
component ptr
port(
clk : in std_logic;
enable_ptr : in std_logic;
new_ptr : in std_logic_vector(15 downto 0);
old_ptr : out std_logic_vector(15 downto 0)
component ptr is
port (
clk : in std_logic;
enable_ptr : in std_logic;
new_ptr : in std_logic_vector(15 downto 0);
old_ptr : out std_logic_vector(15 downto 0)
);
end component;
end component ptr;
component cellblock
port(
clk : in std_logic;
enable : in std_logic;
address : in std_logic_vector(15 downto 0);
new_cell : in std_logic_vector(7 downto 0);
old_cell : out std_logic_vector(7 downto 0)
component cellblock is
port (
clk : in std_logic;
enable : in std_logic;
address : in std_logic_vector(15 downto 0);
new_cell : in std_logic_vector(7 downto 0);
old_cell : out std_logic_vector(7 downto 0)
);
end component;
end component cellblock;
component program_counter
port(
clk : in std_logic;
enable : in std_logic;
jmp : in std_logic;
pc_in : in std_logic_vector(7 downto 0);
pc_out : out std_logic_vector(7 downto 0)
component program_counter is
port (
clk : in std_logic;
enable : in std_logic;
jmp : in std_logic;
pc_in : in std_logic_vector(7 downto 0);
pc_out : out std_logic_vector(7 downto 0)
);
end component;
end component program_counter;
component branch
port(
clk : in std_logic;
state : in std_logic;
instruction : in std_logic_vector(2 downto 0);
instr_addr : in std_logic_vector(7 downto 0);
cell_value : in std_logic_vector(7 downto 0);
component branch is
port (
clk : in std_logic;
state : in std_logic;
instruction : in std_logic_vector(2 downto 0);
instr_addr : in std_logic_vector(7 downto 0);
cell_value : in std_logic_vector(7 downto 0);
skip : out std_logic;
jump : out std_logic;
pc_enable : out std_logic;
pc_out : out std_logic_vector(7 downto 0)
skip : out std_logic;
jump : out std_logic;
pc_enable : out std_logic;
pc_out : out std_logic_vector(7 downto 0)
);
end component;
end component branch;
signal s_clk : std_logic;
signal s_in : std_logic_vector(7 downto 0) := (others => '0');
signal s_out : std_logic_vector(7 downto 0) := (others => '0');
signal s_clk : std_logic;
signal s_in : std_logic_vector(7 downto 0) := (others => '0');
signal s_out : std_logic_vector(7 downto 0) := (others => '0');
signal s_led : std_logic_vector(7 downto 0) := (others => '0');
signal s_instrAddr : std_logic_vector(7 downto 0) := "00000000";
signal s_instruction : std_logic_vector(2 downto 0) := "000";
signal s_instrAddr : std_logic_vector(7 downto 0) := "00000000";
signal s_instruction : std_logic_vector(2 downto 0) := "000";
signal s_cell_out : std_logic_vector(7 downto 0) := (others => '0');
signal s_cell_in : std_logic_vector(7 downto 0) := (others => '0');
signal s_ptr_out : std_logic_vector(15 downto 0) := (others => '0');
signal s_ptr_in : std_logic_vector(15 downto 0) := (others => '0');
signal s_cell_out : std_logic_vector(7 downto 0) := (others => '0');
signal s_cell_in : std_logic_vector(7 downto 0) := (others => '0');
signal s_ptr_out : std_logic_vector(15 downto 0) := (others => '0');
signal s_ptr_in : std_logic_vector(15 downto 0) := (others => '0');
signal s_enable_cells : std_logic := '0';
signal s_enable_ptr : std_logic := '0';
signal s_enable_cells : std_logic := '0';
signal s_enable_ptr : std_logic := '0';
signal s_enable_pc : std_logic := '1';
signal s_jmp_pc : std_logic := '0';
signal s_jmp_addr_pc : std_logic_vector(7 downto 0) := "00000000";
signal s_enable_pc : std_logic := '1';
signal s_jmp_pc : std_logic := '0';
signal s_jmp_addr_pc : std_logic_vector(7 downto 0) := "00000000";
signal s_skip : std_logic := '0';
signal s_enable_cells_o : std_logic := '0';
signal s_enable_ptr_o : std_logic := '0';
signal s_skip : std_logic := '0';
signal s_enable_cells_o : std_logic := '0';
signal s_enable_ptr_o : std_logic := '0';
signal processor_state : std_logic := '0'; -- 0: execute; 1: write back
signal processor_state : std_logic := '0'; -- 0: execute; 1: write back
begin
-- clock and state logic
s_clk <= clk;
s_clk <= clk;
-- Process state change state between execute and write back
state : process (s_clk) -- runs only, when s_clk changed
state: process (s_clk) is -- runs only, when s_clk changed
begin
if rising_edge(s_clk) then
processor_state <= not processor_state;
end if;
end process;
end process state;
-- Process in_out set in- and output on clk high and exec/write back
in_out : process (s_clk) -- runs only, when s_clk changed
in_out: process (s_clk) is -- runs only, when s_clk changed
begin
if rising_edge(s_clk) then
if processor_state = '1' then
led <= s_out;
s_led <= s_out;
else
s_in <= sw;
s_in <= sw;
end if;
end if;
end process;
end process in_out;
instrMemory : instructionMemory
port map(
instrMemory: component instructionMemory
port map (
instructionAddr => s_instrAddr,
instruction => s_instruction
instruction => s_instruction
);
alu_entity : alu
port map(
instruction => s_instruction,
old_cell => s_cell_out,
old_pointer => s_ptr_out,
extern_in => s_in,
alu_entity: component alu
port map (
instruction => s_instruction,
old_cell => s_cell_out,
old_pointer => s_ptr_out,
extern_in => s_in,
new_cell => s_cell_in,
new_pointer => s_ptr_in,
enable_cell => s_enable_cells_o,
enable_ptr => s_enable_ptr_o,
extern_out => s_out
new_cell => s_cell_in,
new_pointer => s_ptr_in,
enable_cell => s_enable_cells_o,
enable_ptr => s_enable_ptr_o,
extern_out => s_out
);
ptr_bf : ptr
port map(
clk => s_clk,
enable_ptr => s_enable_ptr,
new_ptr => s_ptr_in,
old_ptr => s_ptr_out
ptr_bf: component ptr
port map (
clk => s_clk,
enable_ptr => s_enable_ptr,
new_ptr => s_ptr_in,
old_ptr => s_ptr_out
);
cellblock_bf : cellblock
port map(
clk => s_clk,
enable => s_enable_cells,
address => s_ptr_out,
new_cell => s_cell_in,
old_cell => s_cell_out
cellblock_bf: component cellblock
port map (
clk => s_clk,
enable => s_enable_cells,
address => s_ptr_out,
new_cell => s_cell_in,
old_cell => s_cell_out
);
pc : program_counter
port map(
clk => s_clk,
enable => s_enable_pc and processor_state,
jmp => s_jmp_pc,
pc_in => s_jmp_addr_pc,
pc_out => s_instrAddr
pc: component program_counter
port map (
clk => s_clk,
enable => s_enable_pc and processor_state,
jmp => s_jmp_pc,
pc_in => s_jmp_addr_pc,
pc_out => s_instrAddr
);
branch_bf : branch
port map(
clk => s_clk,
state => processor_state,
instruction => s_instruction,
instr_addr => s_instrAddr,
cell_value => s_cell_out,
skip => s_skip,
jump => s_jmp_pc,
pc_enable => s_enable_pc,
pc_out => s_jmp_addr_pc
branch_bf: component branch
port map (
clk => s_clk,
state => processor_state,
instruction => s_instruction,
instr_addr => s_instrAddr,
cell_value => s_cell_out,
skip => s_skip,
jump => s_jmp_pc,
pc_enable => s_enable_pc,
pc_out => s_jmp_addr_pc
);
s_enable_ptr <= not s_skip and s_enable_ptr_o and processor_state;
s_enable_cells <= not s_skip and s_enable_cells_o and processor_state;
debug <= s_cell_out;
s_enable_ptr <= not s_skip and s_enable_ptr_o and processor_state;
s_enable_cells <= not s_skip and s_enable_cells_o and processor_state;
debug <= s_cell_out;
led <= s_led;
end arch;
end architecture arch;