mirror of
https://gitlab.com/deetmit/mesecons_x.git
synced 2024-08-19 12:54:10 +02:00
add FSM generator (orange book)
This commit is contained in:
parent
909dc5715f
commit
7e77480fc7
@ -266,6 +266,62 @@ function flip(v)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function paste_circuit_from_table(sel,circ,direction)
|
||||||
|
if sel.pos1 == nil then return end
|
||||||
|
if sel.pos2 == nil then return end
|
||||||
|
|
||||||
|
|
||||||
|
local nodes = circ.nodes
|
||||||
|
local metas = circ.metas
|
||||||
|
|
||||||
|
local sx = nodes.sx
|
||||||
|
local sy = nodes.sy
|
||||||
|
local sz = nodes.sz
|
||||||
|
|
||||||
|
local right = rotate_direction_right(direction)
|
||||||
|
|
||||||
|
local start_pos = get_corner00(sel,direction)
|
||||||
|
|
||||||
|
for xi=1,sx do
|
||||||
|
for zi=1,sz do
|
||||||
|
for yi=1,sy do
|
||||||
|
local shift= add_vectors(
|
||||||
|
vector.multiply(right,xi-1),
|
||||||
|
vector.multiply(direction,zi-1),
|
||||||
|
vector.multiply({x=0,y=1,z=0},yi-1))
|
||||||
|
|
||||||
|
local pos = vector.add(start_pos, shift)
|
||||||
|
|
||||||
|
if is_in_selection(sel,pos) then
|
||||||
|
|
||||||
|
local node = m3_get(nodes,xi,yi,zi) if node ~= nil then
|
||||||
|
local meta = m3_get(metas,xi,yi,zi)
|
||||||
|
node = rotate_node(node,{x=0,y=0,z=1},direction)
|
||||||
|
--minetest.set_node(pos, node)
|
||||||
|
--mesecons_autotools.set_node(pos,node,"paste_circuit")
|
||||||
|
minetest.set_node(pos,node)
|
||||||
|
minetest.get_meta(pos):from_table(meta)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function paste_circuit(sel,file,direction)
|
||||||
|
if sel.pos1 == nil then return end
|
||||||
|
if sel.pos2 == nil then return end
|
||||||
|
|
||||||
|
local circ = read_table_from_file(file)
|
||||||
|
paste_circuit_from_table(sel,circ,direction)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
function paste_circuit(sel,file,direction)
|
function paste_circuit(sel,file,direction)
|
||||||
if sel.pos1 == nil then return end
|
if sel.pos1 == nil then return end
|
||||||
if sel.pos2 == nil then return end
|
if sel.pos2 == nil then return end
|
||||||
@ -275,7 +331,7 @@ function paste_circuit(sel,file,direction)
|
|||||||
--local rotate_direction = diff_directions(direction)
|
--local rotate_direction = diff_directions(direction)
|
||||||
--local nodes = rotate_m3(info.nodes,direction)
|
--local nodes = rotate_m3(info.nodes,direction)
|
||||||
local nodes = info.nodes
|
local nodes = info.nodes
|
||||||
local metas = info.metas
|
local metas = info.metas
|
||||||
|
|
||||||
local sx = nodes.sx
|
local sx = nodes.sx
|
||||||
local sy = nodes.sy
|
local sy = nodes.sy
|
||||||
@ -311,7 +367,7 @@ function paste_circuit(sel,file,direction)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
]]--
|
||||||
|
|
||||||
|
|
||||||
local function make_selection(user,file,direction,pos)
|
local function make_selection(user,file,direction,pos)
|
||||||
|
@ -9,6 +9,15 @@ function generate_file_name(user)
|
|||||||
return file
|
return file
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function generate_file_name_fsm(user)
|
||||||
|
local days = minetest.get_day_count()
|
||||||
|
local sec = minetest.get_gametime()
|
||||||
|
local rand = math.abs(mesecons_autotools.rand:next())
|
||||||
|
local file = "fsm-"..user.."-"..sec.."-" .. rand
|
||||||
|
return file
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function generate_file_name_library(user)
|
function generate_file_name_library(user)
|
||||||
local days = minetest.get_day_count()
|
local days = minetest.get_day_count()
|
||||||
local sec = minetest.get_gametime()
|
local sec = minetest.get_gametime()
|
||||||
|
@ -79,7 +79,6 @@ function traverse_list(list,action)
|
|||||||
if list == nil then return end
|
if list == nil then return end
|
||||||
|
|
||||||
for _,v in ipairs(list) do
|
for _,v in ipairs(list) do
|
||||||
print("traverser.id =" .. v.id)
|
|
||||||
if v.type == "circuit" then
|
if v.type == "circuit" then
|
||||||
action(v)
|
action(v)
|
||||||
elseif v.type == "library" then
|
elseif v.type == "library" then
|
||||||
|
@ -281,6 +281,25 @@ function iterate_m3(m,action)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function m3_insert(mbase, melement, x,y,z)
|
||||||
|
local sx = melement.sx
|
||||||
|
local sy = melement.sy
|
||||||
|
local sz = melement.sz
|
||||||
|
|
||||||
|
for xi=1,sx do
|
||||||
|
for yi=1,sy do
|
||||||
|
for zi=1,sz do
|
||||||
|
if m3_get(melement,xi,yi,zi) ~= nil then
|
||||||
|
m3_set(mbase,x+xi-1,y+yi-1,z+zi-1, m3_get(melement,xi,yi,zi))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
mbase.sx = math.max(mbase.sx, x+sx-1)
|
||||||
|
mbase.sy = math.max(mbase.sy, y+sy-1)
|
||||||
|
mbase.sz = math.max(mbase.sz, z+sz-1)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,78 +4,78 @@ local n10 = "mesecons_extrawires:crossover_10"
|
|||||||
|
|
||||||
-- axuliary function
|
-- axuliary function
|
||||||
function switch (name)
|
function switch (name)
|
||||||
if( name == n01 ) then
|
if( name == n01 ) then
|
||||||
return n10
|
return n10
|
||||||
else
|
else
|
||||||
return n01
|
return n01
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function rotate_node_to_direction(node,direction)
|
function rotate_node_to_direction(node,direction)
|
||||||
local add = 0
|
local add = 0
|
||||||
if direction.x == 1 then add = 3 end
|
if direction.x == 1 then add = 3 end
|
||||||
if direction.x == -1 then add = 1 end
|
if direction.x == -1 then add = 1 end
|
||||||
if direction.z == 1 then add = 0 end
|
if direction.z == 1 then add = 0 end
|
||||||
if direction.z == -1 then add = 2 end
|
if direction.z == -1 then add = 2 end
|
||||||
|
|
||||||
local param2 = node.param2
|
local param2 = node.param2
|
||||||
|
|
||||||
param2 = (param2+add)% 4
|
param2 = (param2+add)% 4
|
||||||
|
|
||||||
-- special treatement for crossover wire
|
-- special treatement for crossover wire
|
||||||
if( node.name == n01 or node.name == n10 ) then
|
if( node.name == n01 or node.name == n10 ) then
|
||||||
if( add % 2 == 0 ) then
|
if( add % 2 == 0 ) then
|
||||||
return { name = node.name, param2=param2}
|
return { name = node.name, param2=param2}
|
||||||
else
|
else
|
||||||
return { name = switch(node.name), param2=param2}
|
return { name = switch(node.name), param2=param2}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
return { name = node.name , param2 = param2 }
|
return { name = node.name , param2 = param2 }
|
||||||
end
|
end
|
||||||
|
|
||||||
local function direction_to_number(direction)
|
local function direction_to_number(direction)
|
||||||
if( direction.z == 1 ) then
|
if( direction.z == 1 ) then
|
||||||
return 1
|
return 1
|
||||||
elseif( direction.x == 1 ) then
|
elseif( direction.x == 1 ) then
|
||||||
return 2
|
return 2
|
||||||
elseif(direction.z == -1 )then
|
elseif(direction.z == -1 )then
|
||||||
return 3
|
return 3
|
||||||
else
|
else
|
||||||
return 4
|
return 4
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function rotate_node(node, saved_direction,direction)
|
function rotate_node(node, saved_direction,direction)
|
||||||
|
if node == nil then return nil end
|
||||||
|
local values =
|
||||||
|
{
|
||||||
|
{0,1,2,3},
|
||||||
|
{3,0,1,2},
|
||||||
|
{2,3,0,1},
|
||||||
|
{1,2,3,0}
|
||||||
|
}
|
||||||
|
|
||||||
local values =
|
local rotate =
|
||||||
{
|
values[direction_to_number(saved_direction)][direction_to_number(direction)]
|
||||||
{0,1,2,3},
|
|
||||||
{3,0,1,2},
|
|
||||||
{2,3,0,1},
|
|
||||||
{1,2,3,0}
|
|
||||||
}
|
|
||||||
|
|
||||||
local rotate =
|
local new_node = {}
|
||||||
values[direction_to_number(saved_direction)][direction_to_number(direction)]
|
new_node.name = node.name
|
||||||
|
new_node.param2 = (node.param2+rotate)%4
|
||||||
|
|
||||||
local new_node = {}
|
-- an exception, special treatement of crossover wire
|
||||||
new_node.name = node.name
|
if( node.name == n01 or node.name == n10 ) then
|
||||||
new_node.param2 = (node.param2+rotate)%4
|
|
||||||
|
|
||||||
-- an exception, special treatement of crossover wire
|
if( rotate % 2 == 0 ) then
|
||||||
if( node.name == n01 or node.name == n10 ) then
|
new_node = node
|
||||||
|
else
|
||||||
|
new_node = {name = switch(node.name), param2=node.param2}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if( rotate % 2 == 0 ) then
|
return new_node
|
||||||
new_node = node
|
|
||||||
else
|
|
||||||
new_node = {name = switch(node.name), param2=node.param2}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return new_node
|
|
||||||
end
|
end
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
function is_gate(node)
|
function is_gate(node)
|
||||||
|
if node == nil then return false end
|
||||||
local gates = {
|
local gates = {
|
||||||
"mesecons_gates:and",
|
"mesecons_gates:and",
|
||||||
"mesecons_gates:or",
|
"mesecons_gates:or",
|
||||||
@ -39,6 +40,7 @@ function is_wire_node(node)
|
|||||||
"mesecons_morewires:xjunction_off", "mesecons_morewires:xjunction_on",
|
"mesecons_morewires:xjunction_off", "mesecons_morewires:xjunction_on",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if node == nil then return false end
|
||||||
local pos_name = node.name
|
local pos_name = node.name
|
||||||
for i,name in ipairs(list) do
|
for i,name in ipairs(list) do
|
||||||
if name == pos_name then
|
if name == pos_name then
|
||||||
@ -54,6 +56,7 @@ end
|
|||||||
function get_stats(m)
|
function get_stats(m)
|
||||||
local blocks,gates,wires = 0,0,0
|
local blocks,gates,wires = 0,0,0
|
||||||
iterate_m3(m, function(node)
|
iterate_m3(m, function(node)
|
||||||
|
if node == nil then return end
|
||||||
if is_wire_node(node) then
|
if is_wire_node(node) then
|
||||||
wires = wires + 1
|
wires = wires + 1
|
||||||
end
|
end
|
||||||
|
1
mesecons_autotools/formula/README
Normal file
1
mesecons_autotools/formula/README
Normal file
@ -0,0 +1 @@
|
|||||||
|
Formula tool (still in progress, not published in mod)
|
33
mesecons_autotools/formula/formula.lua
Normal file
33
mesecons_autotools/formula/formula.lua
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
local function on_use_formula_book(itemstack, player, pointed_thing)
|
||||||
|
local user = player:get_player_name()
|
||||||
|
local formspec =
|
||||||
|
"formspec_version[3]"..
|
||||||
|
"size[32,25]"..
|
||||||
|
"label[15,0.7;FSM generator]"..
|
||||||
|
|
||||||
|
|
||||||
|
"field[0.5,2;15,1;title;Name;]"..
|
||||||
|
"textarea[0.5,4;15,15;text;" .. "Code:" .. ";" .. "" .. "]" ..
|
||||||
|
"textarea[16.5,2;15,17;d;" .. "Compilation Logs:" .. ";" .. "" .. "]" ..
|
||||||
|
|
||||||
|
|
||||||
|
"button_exit[0.5,19;3,1;save;" .. "Save" .. "]" ..
|
||||||
|
"button_exit[14.5,20;3,1;compile;" .. "Compile" .. "]" ..
|
||||||
|
"button_exit[28.5,20;3,1;generate;" .. "Generate" .. "]" ..
|
||||||
|
""
|
||||||
|
minetest.show_formspec(user, "mesecons_autotools:formula_show", formspec)
|
||||||
|
end
|
||||||
|
|
||||||
|
--minetest.register_craftitem("mesecons_autotools:circuit_empty", {
|
||||||
|
minetest.register_tool("mesecons_autotools:formula", {
|
||||||
|
description = "Logic formula generator",
|
||||||
|
inventory_image = "formula_book.png",
|
||||||
|
stack_max = 1,
|
||||||
|
|
||||||
|
on_use = on_use_formula_book,
|
||||||
|
|
||||||
|
--[[
|
||||||
|
on_place = none,
|
||||||
|
on_secondary_use = none,
|
||||||
|
--]]
|
||||||
|
})
|
163
mesecons_autotools/fsm/alg.lua
Normal file
163
mesecons_autotools/fsm/alg.lua
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
------------------------------------------------------------------------
|
||||||
|
-- logic functions
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
function show(area)
|
||||||
|
local vars = area.vars
|
||||||
|
local s = ""
|
||||||
|
dump(area)
|
||||||
|
if #area.parts == 0 then
|
||||||
|
s = "(none)"
|
||||||
|
else
|
||||||
|
|
||||||
|
for _,part in pairs(area.parts) do
|
||||||
|
for _,v in ipairs(vars) do
|
||||||
|
if ( part[v] == true ) then s = s .. " " .. v end
|
||||||
|
if part[v] == false then s = s .. " ~" .. v end
|
||||||
|
if part[v] == nil then s = s .. " x" end
|
||||||
|
end
|
||||||
|
s = s .. "\n"
|
||||||
|
end
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function area_add(a1,a2)
|
||||||
|
local a3 = area_copy(a1)
|
||||||
|
|
||||||
|
for _,v in pairs(a2.parts) do
|
||||||
|
table.insert(a3.parts,v)
|
||||||
|
end
|
||||||
|
return a3
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function drop_negation_list(list)
|
||||||
|
local l = {}
|
||||||
|
for _,v in pairs(list) do
|
||||||
|
table.insert(l, drop_negation(v))
|
||||||
|
end
|
||||||
|
return l
|
||||||
|
end
|
||||||
|
|
||||||
|
function swap_truefalse(v)
|
||||||
|
if v == true then return false end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function part_sub_part(a,b)
|
||||||
|
|
||||||
|
local vars = {}
|
||||||
|
|
||||||
|
for keya,_ in pairs(b) do
|
||||||
|
if (a[keya] == true and b[keya] == false ) or
|
||||||
|
( a[keya] == false and b[keya] == true ) then
|
||||||
|
local ll = {}
|
||||||
|
table.insert(ll,a)
|
||||||
|
return ll
|
||||||
|
end
|
||||||
|
|
||||||
|
if a[keya] == nil and b[keya] ~= nil then
|
||||||
|
vars[keya] = swap_truefalse(b[keya])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local parts = {}
|
||||||
|
for k,v in pairs(vars) do
|
||||||
|
local new = copy_list(a)
|
||||||
|
new[k] = v
|
||||||
|
table.insert(parts,new)
|
||||||
|
end
|
||||||
|
return parts
|
||||||
|
end
|
||||||
|
|
||||||
|
function insert_parts_in_area(a,list)
|
||||||
|
local c = {}
|
||||||
|
c = area_copy(a)
|
||||||
|
for _,v in pairs(list) do
|
||||||
|
table.insert(c.parts, v)
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function area_sub_part(a,p)
|
||||||
|
local c = {}
|
||||||
|
c.vars = copy_list(a.vars)
|
||||||
|
c.parts = {}
|
||||||
|
|
||||||
|
for _,part in pairs(a.parts) do
|
||||||
|
local l = part_sub_part(part,p)
|
||||||
|
c = insert_parts_in_area(c,l)
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
function copy_list(l)
|
||||||
|
local nl = {}
|
||||||
|
for k,v in pairs(l) do
|
||||||
|
nl[k] = v
|
||||||
|
end
|
||||||
|
return nl
|
||||||
|
end
|
||||||
|
]]--
|
||||||
|
function copy_list(l)
|
||||||
|
return DeepCopy(l)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function area_copy(a)
|
||||||
|
return DeepCopy(a)
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
function area_copy(a)
|
||||||
|
local c = {}
|
||||||
|
c.vars = copy_list(a.vars)
|
||||||
|
c.parts = {}
|
||||||
|
for _,v in pairs(a.parts) do
|
||||||
|
table.insert(c.parts, copy_list(v))
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
]]--
|
||||||
|
|
||||||
|
function area_sub(a,b)
|
||||||
|
local c = {}
|
||||||
|
c = area_copy(a)
|
||||||
|
|
||||||
|
for _,v in pairs(b.parts) do
|
||||||
|
c = area_sub_part(c,v)
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--[[
|
||||||
|
local a1 = {
|
||||||
|
vars={"a","b","c","d"},
|
||||||
|
parts = {
|
||||||
|
{ d = true} ,
|
||||||
|
--{c = true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
local a2 = {
|
||||||
|
vars={"a","b","c","d"},
|
||||||
|
parts = { { a=false, b =true,c = true} }
|
||||||
|
}
|
||||||
|
|
||||||
|
]]--
|
||||||
|
--local a = area_sub(a1,a2)
|
||||||
|
|
||||||
|
|
||||||
|
--[[
|
||||||
|
print(show(a1))
|
||||||
|
print(show(a2))
|
||||||
|
print(show(a))
|
||||||
|
--]]
|
470
mesecons_autotools/fsm/compiler.lua
Normal file
470
mesecons_autotools/fsm/compiler.lua
Normal file
@ -0,0 +1,470 @@
|
|||||||
|
|
||||||
|
dofile(minetest.get_modpath("mesecons_autotools").."/fsm/compiler_general.lua");
|
||||||
|
dofile(minetest.get_modpath("mesecons_autotools").."/fsm/compiler_parsing.lua");
|
||||||
|
dofile(minetest.get_modpath("mesecons_autotools").."/fsm/compiler_generating.lua");
|
||||||
|
dofile(minetest.get_modpath("mesecons_autotools").."/fsm/compiler_checking.lua");
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
-- compilation functions
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function compile_init(inits)
|
||||||
|
if empty(inits) then return nil,"no init state" end
|
||||||
|
if #inits ~= 1 then return nil,"more than one init states" end
|
||||||
|
return inits[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
function compile_pin_assigns(pins_assigns)
|
||||||
|
local db = {}
|
||||||
|
for _,v in ipairs(pins_assigns) do
|
||||||
|
|
||||||
|
-- check if already defined
|
||||||
|
if e(db,v.pin) then
|
||||||
|
return nil, "pin " .. v.pin .. " defined two times"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- check if self loop
|
||||||
|
if is_in_list(v.pins,drop_negation(v.pin)) then
|
||||||
|
return nil, "self reference in definition " .. v.pin
|
||||||
|
end
|
||||||
|
if is_in_list(v.pins,add_negation(v.pin)) then
|
||||||
|
return nil, "self reference in definition " .. v.pin
|
||||||
|
end
|
||||||
|
|
||||||
|
-- expand pins
|
||||||
|
local pins_expanded = {}
|
||||||
|
for _,p in ipairs(v.pins) do
|
||||||
|
if is_pin_name_n(p) then
|
||||||
|
table.insert(pins_expanded,p)
|
||||||
|
elseif is_pin_group_name_n(p) then
|
||||||
|
local gr = drop_negation(p)
|
||||||
|
if e(db,gr) then
|
||||||
|
for _,pp in ipairs(db[gr]) do
|
||||||
|
if( is_negated(p) ) then
|
||||||
|
table.insert(pins_expanded,swap_negation(pp))
|
||||||
|
else
|
||||||
|
table.insert(pins_expanded,pp)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return nil, "pin " .. p .. " no defined in " .. v.pin .. " definition"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
db[v.pin] = remove_duplicates( pins_expanded )
|
||||||
|
end
|
||||||
|
return db
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function compile_state_assigns(state_assigns)
|
||||||
|
local db = {}
|
||||||
|
for _,v in ipairs(state_assigns) do
|
||||||
|
|
||||||
|
-- check if already defined
|
||||||
|
if e(db,v.state) then
|
||||||
|
return nil, "state group " .. v.state .. " defined two times"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- check if self loop
|
||||||
|
if is_in_list(v.states,v.state) then
|
||||||
|
return nil, "self reference in definition " .. v.state
|
||||||
|
end
|
||||||
|
|
||||||
|
-- expand pins
|
||||||
|
local states_expanded = {}
|
||||||
|
for _,p in ipairs(v.states) do
|
||||||
|
if is_state_name(p) then
|
||||||
|
table.insert(states_expanded,p)
|
||||||
|
elseif is_state_group_name(p) then
|
||||||
|
if e(db,p) then
|
||||||
|
for _,pp in ipairs(db[p]) do
|
||||||
|
table.insert(states_expanded,pp)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return nil, "state " .. p .. " no defined in definition " .. v.state
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
db[v.state] =remove_duplicates( states_expanded )
|
||||||
|
end
|
||||||
|
|
||||||
|
return db
|
||||||
|
end
|
||||||
|
|
||||||
|
function expand_pin(pin,db)
|
||||||
|
if is_negated(pin) then
|
||||||
|
local pure = drop_negation(pin)
|
||||||
|
if db[pin] == nil then
|
||||||
|
local l = {}
|
||||||
|
table.insert(l,pin)
|
||||||
|
return l
|
||||||
|
else
|
||||||
|
local l = {}
|
||||||
|
for _,v in pairs(db[pure]) do
|
||||||
|
table.insert(l,swap_negation(v))
|
||||||
|
end
|
||||||
|
return l
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if db[pin] == nil then
|
||||||
|
local l = {}
|
||||||
|
table.insert(l,pin)
|
||||||
|
return l
|
||||||
|
else
|
||||||
|
return db[pin]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function expand_pins(list, db)
|
||||||
|
local l = {}
|
||||||
|
for _,pin in ipairs(list) do
|
||||||
|
for _,p in ipairs( expand_pin(pin,db) ) do
|
||||||
|
table.insert(l,p)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return l
|
||||||
|
end
|
||||||
|
|
||||||
|
function expand_state(s,db)
|
||||||
|
local l = {}
|
||||||
|
if db[s] == nil then
|
||||||
|
table.insert(l,s)
|
||||||
|
return l
|
||||||
|
else
|
||||||
|
return db[s]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function expand_states(list, db)
|
||||||
|
local l = {}
|
||||||
|
for _,state in ipairs(list) do
|
||||||
|
for _,p in ipairs( expand_state( state, db) ) do
|
||||||
|
table.insert(l,p)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return l
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function all_defined_states(db,list)
|
||||||
|
for _,v in pairs(list) do
|
||||||
|
if is_state_group_name(v) then
|
||||||
|
if not e(db, v) then
|
||||||
|
return false,v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function all_defined_pins(db,list)
|
||||||
|
for _,v in pairs(list) do
|
||||||
|
if is_pin_group_name(v) then
|
||||||
|
if not e(db, v) then
|
||||||
|
return false,v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function compile_state_outputs(state_outputs, db_pins, db_states)
|
||||||
|
local db = {}
|
||||||
|
for _,v in ipairs(state_outputs) do
|
||||||
|
local states = v.states
|
||||||
|
local pins = v.pins
|
||||||
|
|
||||||
|
|
||||||
|
local df,err
|
||||||
|
-- expanding pins
|
||||||
|
local pins_exp = expand_pins(pins,db_pins)
|
||||||
|
df,err = all_defined_pins(db_pins,pins_exp)
|
||||||
|
if df == false then
|
||||||
|
return nil, "pin '" .. err .. "' not defined in line: " .. v.line
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--expand states
|
||||||
|
local states_exp = expand_states(states, db_states)
|
||||||
|
df,err = all_defined_states(db_states,states_exp)
|
||||||
|
if df == false then
|
||||||
|
return nil, "state '" .. err .. "' not defined, error in line: " .. v.line
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- check if state already defined
|
||||||
|
for _,w in pairs(states_exp) do
|
||||||
|
if e(db,w) then
|
||||||
|
return nil, "state output '" .. w .. "' already defined, duplicate in line: " .. v.line
|
||||||
|
else
|
||||||
|
db[w] = pins_exp
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return db
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function compile_state_transitions(state_transitions, db_pins, db_states)
|
||||||
|
local db = {}
|
||||||
|
if state_transitions == nil then
|
||||||
|
return nil,"no transitions"
|
||||||
|
end
|
||||||
|
if #state_transitions == 0 then
|
||||||
|
return nil, "no transitions"
|
||||||
|
end
|
||||||
|
for _,v in pairs(state_transitions) do
|
||||||
|
local states = v.states
|
||||||
|
local pins = v.pins
|
||||||
|
local state = v.state
|
||||||
|
|
||||||
|
--expand
|
||||||
|
local df,err
|
||||||
|
-- expanding pins
|
||||||
|
local pins_exp = expand_pins(pins,db_pins)
|
||||||
|
df,err = all_defined_pins(db_pins,pins_exp)
|
||||||
|
if df == false then
|
||||||
|
return nil, "pin " .. err .. " not defined, error in line: " .. v.line
|
||||||
|
end
|
||||||
|
|
||||||
|
--expand states
|
||||||
|
local states_exp = expand_states(states, db_states)
|
||||||
|
df,err = all_defined_states(db_states,states_exp)
|
||||||
|
if df == false then
|
||||||
|
return nil, "state " .. err .. " not defined, error in line: " .. v.line
|
||||||
|
end
|
||||||
|
|
||||||
|
-- building db
|
||||||
|
for _,w in ipairs(states_exp) do
|
||||||
|
if db[w] == nil then db[w] = {} end
|
||||||
|
table.insert(db[w], { pins = pins_exp, state = state } )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if count_hash(db) == 0 then
|
||||||
|
return nil,"coudn't find any transitions"
|
||||||
|
end
|
||||||
|
|
||||||
|
return db
|
||||||
|
end
|
||||||
|
|
||||||
|
function compile_state_values(state_values)
|
||||||
|
local db = {}
|
||||||
|
if state_values == nil then return db end
|
||||||
|
|
||||||
|
for _,v in pairs(state_values) do
|
||||||
|
local state = v.state
|
||||||
|
local value = v.value
|
||||||
|
if db[state] ~= nil then
|
||||||
|
return nil, "duplicate state value definition, ".. state ..
|
||||||
|
" := " .. db[state] .. " and " .. state .. " := " .. v.value
|
||||||
|
else
|
||||||
|
db[state] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- checking if all values the same length
|
||||||
|
|
||||||
|
local min = 0
|
||||||
|
-- seting initial value of min (bigger than any of the elment)
|
||||||
|
for k,v in pairs(db) do
|
||||||
|
min = min + string.len(v)
|
||||||
|
end
|
||||||
|
|
||||||
|
local max = 0
|
||||||
|
local maxs,mins
|
||||||
|
for k,v in pairs(db) do
|
||||||
|
if string.len(v) < min then
|
||||||
|
min = string.len(v)
|
||||||
|
mins = k
|
||||||
|
end
|
||||||
|
if string.len(v) > max then
|
||||||
|
max = string.len(v)
|
||||||
|
maxs = k
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (min ~= 0 and min ~= max) then
|
||||||
|
return nil, "values of states have different length, " .. mins .. " := " .. db[mins] ..
|
||||||
|
" and " .. maxs .. " := " .. db[maxs]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- checking if values are uniq
|
||||||
|
local vdb = {}
|
||||||
|
for k,v in pairs(db) do
|
||||||
|
if vdb[v] ~= nil then
|
||||||
|
return nil, "duplicate state value, " .. k .. " := " .. v .. " and " .. vdb[v] .. " := " .. v
|
||||||
|
else
|
||||||
|
vdb[v] = k
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return db
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function compile_in_pins(in_pins)
|
||||||
|
if #in_pins > 1 then return nil, "multiple input pins definitions" end
|
||||||
|
|
||||||
|
local duplicate = get_duplicate(in_pins[1])
|
||||||
|
if duplicate == nil then
|
||||||
|
return (in_pins[1] or {})
|
||||||
|
else
|
||||||
|
return nil, "input pins duplicated: " .. duplicate
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function compile_out_pins(out_pins)
|
||||||
|
if #out_pins > 1 then return nil, "multiple output pins definitions" end
|
||||||
|
|
||||||
|
local duplicate = get_duplicate(out_pins[1])
|
||||||
|
if duplicate == nil then
|
||||||
|
return (out_pins[1] or {} )
|
||||||
|
else
|
||||||
|
return nil, "output pins duplicated: " .. duplicate
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function compile_code(code)
|
||||||
|
|
||||||
|
local data = parse_code(code)
|
||||||
|
local db = {}
|
||||||
|
|
||||||
|
|
||||||
|
local init,erroi = compile_init(data.inits)
|
||||||
|
local bin_pins,errop = compile_pin_assigns(data.pin_assigns)
|
||||||
|
local bin_states,erros = compile_state_assigns(data.state_assigns)
|
||||||
|
local bin_outputs,erroo = compile_state_outputs(data.state_outputs, bin_pins,bin_states)
|
||||||
|
local bin_trans,errot = compile_state_transitions(data.state_transitions, bin_pins,bin_states)
|
||||||
|
local bin_state_values, errosv = compile_state_values(data.state_values)
|
||||||
|
local bin_in_pins,erroip = compile_in_pins(data.in_pins)
|
||||||
|
local bin_out_pins,erroop = compile_out_pins(data.out_pins)
|
||||||
|
|
||||||
|
db.init = init
|
||||||
|
db.init_err = erroi
|
||||||
|
|
||||||
|
db.pins = bin_pins
|
||||||
|
db.pins_err = errop
|
||||||
|
|
||||||
|
db.states = bin_states
|
||||||
|
db.states_err = erros
|
||||||
|
|
||||||
|
db.outputs = bin_outputs
|
||||||
|
db.outputs_err = erroo
|
||||||
|
|
||||||
|
db.trans = bin_trans
|
||||||
|
db.trans_err = errot
|
||||||
|
|
||||||
|
db.state_values = bin_state_values
|
||||||
|
db.state_values_err = errosv
|
||||||
|
|
||||||
|
db.in_pins = bin_in_pins
|
||||||
|
db.in_pins_err = erroip
|
||||||
|
|
||||||
|
db.out_pins = bin_out_pins
|
||||||
|
db.out_pins_err = erroop
|
||||||
|
|
||||||
|
db.unknowns = data.unknowns
|
||||||
|
|
||||||
|
|
||||||
|
if not is_compilation_success(db) then
|
||||||
|
return nil,generate_compilation_error_message(db)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- further processing
|
||||||
|
|
||||||
|
-- warning: orders of executing functions is important, they depend on the db data
|
||||||
|
-- I know, it's a huge weld :)
|
||||||
|
local errs = {}
|
||||||
|
local err
|
||||||
|
local msg = ""
|
||||||
|
function insert_error(err)
|
||||||
|
if err ~= nil then
|
||||||
|
if type(err) == "table" then
|
||||||
|
for _,i in pairs(err) do
|
||||||
|
table.insert(errs,i)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
table.insert(errs,err)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function err_string()
|
||||||
|
-- show errors
|
||||||
|
if #errs > 0 then
|
||||||
|
msg = ""
|
||||||
|
for _,v in pairs(errs) do
|
||||||
|
msg = msg .. "error: " .. v .. "\n"
|
||||||
|
end
|
||||||
|
msg = "Errors(".. #errs .. "):\n" .. msg
|
||||||
|
return msg
|
||||||
|
end
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
db.reachables = get_all_reachable_states(db)
|
||||||
|
|
||||||
|
_,err = get_not_used_states(db)
|
||||||
|
insert_error(err); if #errs ~= 0 then return nil, err_string() end
|
||||||
|
|
||||||
|
db.state_bitsize,err = compute_bitsize_of_state(db)
|
||||||
|
insert_error(err); if #errs ~= 0 then return nil, err_string() end
|
||||||
|
|
||||||
|
db.state_values = only_reachable_state_values(db)
|
||||||
|
|
||||||
|
_,err = check_dead_states(db)
|
||||||
|
insert_error(err); if #errs ~= 0 then return nil, err_string() end
|
||||||
|
|
||||||
|
db.state_values,err = fill_states_values(db)
|
||||||
|
insert_error(err); if #errs ~= 0 then return nil, err_string() end
|
||||||
|
|
||||||
|
db.inputs_used,err = get_inputs(db)
|
||||||
|
insert_error(err); if #errs ~= 0 then return nil, err_string() end
|
||||||
|
|
||||||
|
db.outputs_used,err = get_outputs(db)
|
||||||
|
insert_error(err); if #errs ~= 0 then return nil, err_string() end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- further checking: applying priority and others
|
||||||
|
add_default_loops(db)
|
||||||
|
apply_priority(db)
|
||||||
|
clear_empty_transitions(db)
|
||||||
|
|
||||||
|
-- the part above must be rewritten, too many welds here
|
||||||
|
-- additionally, algorithm does not remove all unused states,
|
||||||
|
-- therefore sometimes it generates dead transistions
|
||||||
|
-- the FSM is correct, but when generated has unused subcircuits
|
||||||
|
-- TODO: fix this
|
||||||
|
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return db,"\nCompilation successful\n\n" ..
|
||||||
|
msg_state_values(db) .. "\n" ..
|
||||||
|
"\n" .. msg_inout_values(db)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
383
mesecons_autotools/fsm/compiler_checking.lua
Normal file
383
mesecons_autotools/fsm/compiler_checking.lua
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
|
||||||
|
function msg_state_values(db)
|
||||||
|
|
||||||
|
local l = db.state_values
|
||||||
|
if l == nil then return "" end
|
||||||
|
|
||||||
|
local msg = ""
|
||||||
|
for k,v in pairs(l) do
|
||||||
|
msg = msg .. k .. ":=" .. v .. "\n"
|
||||||
|
end
|
||||||
|
return msg
|
||||||
|
end
|
||||||
|
|
||||||
|
function msg_inout_values(db)
|
||||||
|
local mi = "Inputs: " .. table.concat(db.inputs_used,", ")
|
||||||
|
local mo = "Outputs: " .. table.concat(db.outputs_used,", ")
|
||||||
|
return mi .. "\n" .. mo
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function is_compilation_success(db)
|
||||||
|
local list = { "init_err" , "pins_err", "states_err" ,"trans_err",
|
||||||
|
"state_values_err", "in_pins_err" , "out_pins_err", "outputs_err" }
|
||||||
|
|
||||||
|
for _,v in pairs(list) do
|
||||||
|
if db[v] ~= nil then return false end
|
||||||
|
end
|
||||||
|
|
||||||
|
if db.unknowns ~= nil then
|
||||||
|
if #db.unknowns ~= 0 then return false end
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function generate_compilation_error_message(db)
|
||||||
|
local list = { "init_err" , "pins_err", "states_err" ,"trans_err",
|
||||||
|
"state_values_err", "in_pins_err" , "out_pins_err" , "outputs_err" }
|
||||||
|
|
||||||
|
local counter = 0
|
||||||
|
local msg = ""
|
||||||
|
for _,v in pairs(list) do
|
||||||
|
if db[v] ~= nil then
|
||||||
|
counter = counter + 1
|
||||||
|
msg = msg .. "error: " .. db[v] .. "\n"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- adding unknows lines
|
||||||
|
if db.unknowns ~= nil then
|
||||||
|
if #db.unknowns ~= 0 then
|
||||||
|
for _,v in pairs(db.unknowns) do
|
||||||
|
msg = msg .. "error: unknown line '" .. v.line .. "'\n"
|
||||||
|
counter = counter + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return "Errors (" .. counter .. ")\n" .. msg
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
-- checking fsm functions
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- TODO: redesign queue functions
|
||||||
|
function is_empty_queue(q)
|
||||||
|
local count = 0
|
||||||
|
for _,v in pairs(q) do
|
||||||
|
count = count +1
|
||||||
|
end
|
||||||
|
if count == 0 then return true end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO: redesign queue functions
|
||||||
|
function push_on_queue(q,e)
|
||||||
|
local qq = DeepCopy(q)
|
||||||
|
table.insert(qq,e)
|
||||||
|
return qq
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO: redesign queue functions
|
||||||
|
function pop_from_queue(q)
|
||||||
|
local e = DeepCopy(q[1])
|
||||||
|
q[1] = nil
|
||||||
|
local newq = {}
|
||||||
|
for _,v in pairs(q) do
|
||||||
|
table.insert(newq,v)
|
||||||
|
end
|
||||||
|
return e,newq
|
||||||
|
end
|
||||||
|
|
||||||
|
function get_all_reachable_states(db)
|
||||||
|
local init = db.init
|
||||||
|
local queue = {}
|
||||||
|
local color = {}
|
||||||
|
local next_state = {}
|
||||||
|
local curr
|
||||||
|
|
||||||
|
queue = push_on_queue(queue,init)
|
||||||
|
while not is_empty_queue(queue) do
|
||||||
|
curr,queue = pop_from_queue(queue)
|
||||||
|
if color[curr] ~= true then
|
||||||
|
color[curr] = true
|
||||||
|
if( db.trans[curr] ~= nil ) then
|
||||||
|
for _,ifthen in pairs(db.trans[curr]) do
|
||||||
|
next_state = ifthen.state
|
||||||
|
queue = push_on_queue(queue,next_state)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return color
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function count_hash(h)
|
||||||
|
local c = 0
|
||||||
|
for _,_ in pairs(h) do
|
||||||
|
c=c+1
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
-- math.log is computins some trash!!!!!!
|
||||||
|
-- is that a bug or something
|
||||||
|
-- making my own binary log function
|
||||||
|
function lg2(n)
|
||||||
|
local c = 0
|
||||||
|
local mul = 1
|
||||||
|
while (mul < n ) do
|
||||||
|
mul = 2* mul
|
||||||
|
c=c+1
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
function get_first_hash_element(h)
|
||||||
|
if h == nil then return nil end
|
||||||
|
local e = nil
|
||||||
|
for k,v in pairs(h) do
|
||||||
|
return k,v
|
||||||
|
end
|
||||||
|
return nil,nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function compute_bitsize_of_state(db)
|
||||||
|
local reachable = get_all_reachable_states(db)
|
||||||
|
local count = count_hash(reachable)
|
||||||
|
local bits_reachable = lg2(count)
|
||||||
|
|
||||||
|
local state_values = db.state_values
|
||||||
|
local count_values = count_hash(state_values)
|
||||||
|
|
||||||
|
if( count_values == 0 ) then
|
||||||
|
if bits_reachable == 0 then
|
||||||
|
return nil,"no reachable states or only one state"
|
||||||
|
end
|
||||||
|
return bits_reachable
|
||||||
|
end
|
||||||
|
|
||||||
|
-- check if all values have the same size
|
||||||
|
local fk,fv = get_first_hash_element(state_values)
|
||||||
|
local flen = string.len(fv)
|
||||||
|
for k,v in pairs(state_values) do
|
||||||
|
if string.len(v) ~= flen then
|
||||||
|
return nil, "states valuse do not have the same length, eg " ..
|
||||||
|
fk .. " := " .. fv .. " and " .. k .. " := " .. v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- checking if enoguth bits for reachable states
|
||||||
|
if ( bits_reachable > flen ) then
|
||||||
|
return nil, "lenght of state value is too small, need " ..
|
||||||
|
bits_reachable .. " bits to code " ..
|
||||||
|
count .. " states, but got only " .. flen ..
|
||||||
|
"eg. " .. fk .. " := " .. fv
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if flen == 0 then
|
||||||
|
return nil,"no reachable states or only one state"
|
||||||
|
end
|
||||||
|
|
||||||
|
return flen
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function list_to_hash(list)
|
||||||
|
local hash = {}
|
||||||
|
for _,v in pairs(list) do
|
||||||
|
hash[v] = true
|
||||||
|
end
|
||||||
|
return hash
|
||||||
|
end
|
||||||
|
|
||||||
|
function hash_in_hash(h1,h2)
|
||||||
|
for k,_ in pairs(h1) do
|
||||||
|
if h2[k] == nil then return false end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function same_hash(h1,h2)
|
||||||
|
if hash_in_hash(h1,h2) and hash_in_hash(h2,h1) then return true else return false end
|
||||||
|
end
|
||||||
|
--[[ not used
|
||||||
|
function hash_cut_hash(h1,h2)
|
||||||
|
local h3 = {}
|
||||||
|
for k,_ in pairs(h1) do
|
||||||
|
if h2[k] ~= nil then
|
||||||
|
h3[k] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return h3
|
||||||
|
end
|
||||||
|
]]--
|
||||||
|
function hash_minus_hash(h1,h2)
|
||||||
|
local out = {}
|
||||||
|
for k,_ in pairs(h1) do
|
||||||
|
if h2[k] == nil then
|
||||||
|
out[k] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function hash_to_list(h)
|
||||||
|
local list = {}
|
||||||
|
for k,v in pairs(h) do
|
||||||
|
table.insert(list,k)
|
||||||
|
end
|
||||||
|
return list
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function check_dead_states(db)
|
||||||
|
-- states reachable from init
|
||||||
|
local hreachable = db.reachables
|
||||||
|
local trans = {}
|
||||||
|
|
||||||
|
-- all states in trans
|
||||||
|
for state,v in pairs(db.trans) do
|
||||||
|
table.insert(trans,state)
|
||||||
|
end
|
||||||
|
|
||||||
|
local htrans = list_to_hash(trans)
|
||||||
|
|
||||||
|
if same_hash(hreachable,htrans) then
|
||||||
|
return nil,nil
|
||||||
|
else
|
||||||
|
local hdiff = hash_minus_hash(htrans,hreachable)
|
||||||
|
if count_hash(hdiff) ~= 0 then
|
||||||
|
local ldiff = hash_to_list(hdiff)
|
||||||
|
return nil, "following states '" .. table.concat(ldiff,", ") ..
|
||||||
|
"' are used in transitions but are not reachable from init state"
|
||||||
|
end
|
||||||
|
return nil,nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function cmp_list_eq(a,b)
|
||||||
|
local ha = list_to_hash(a)
|
||||||
|
local hb = list_to_hash(b)
|
||||||
|
|
||||||
|
return same_hash(ha,hb)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function list_minus_list(l1,l2)
|
||||||
|
local h1 = list_to_hash(l1)
|
||||||
|
local h2 = list_to_hash(l2)
|
||||||
|
local minus = hash_minus_hash(h1,h2)
|
||||||
|
return hash_to_list(minus)
|
||||||
|
end
|
||||||
|
|
||||||
|
function get_all_inputs_from_reachable_transitions(db)
|
||||||
|
local list = {}
|
||||||
|
for state,v in pairs(db.trans) do
|
||||||
|
if db.reachables[state] then
|
||||||
|
for _,w in pairs(v) do
|
||||||
|
append(list,drop_negation_list(w.pins))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local sorted_by_name = DeepCopy(remove_duplicates(list))
|
||||||
|
table.sort(sorted_by_name)
|
||||||
|
return sorted_by_name
|
||||||
|
end
|
||||||
|
|
||||||
|
function get_inpus_from_transistions_and_check_with_declared(db)
|
||||||
|
local ins_from_trans = get_all_inputs_from_reachable_transitions(db)
|
||||||
|
local ins_from_def = db.in_pins
|
||||||
|
|
||||||
|
if cmp_list_eq(ins_from_def,ins_from_trans) then
|
||||||
|
return ins_from_def
|
||||||
|
else
|
||||||
|
local more_in_def = list_minus_list(ins_from_def,ins_from_trans)
|
||||||
|
local more_in_trans = list_minus_list(ins_from_trans, ins_from_def)
|
||||||
|
|
||||||
|
|
||||||
|
if #more_in_def ~= 0 then
|
||||||
|
return nil, "pins '" .. table.concat(more_in_def, ", ") ..
|
||||||
|
"' declared in 'in:' but never used in transitions";
|
||||||
|
end
|
||||||
|
if #more_in_trans ~= 0 then
|
||||||
|
return nil, "pins '" .. table.concat(more_in_trans, ", " ) ..
|
||||||
|
"' used in transitions, but not declared in 'in:'"
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil, {"pins declared and pins used in transitions are not the same"}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function get_inputs(db)
|
||||||
|
-- checking if input pins are not declared
|
||||||
|
if db.in_pins == nil or #db.in_pins == 0 then
|
||||||
|
return get_all_inputs_from_reachable_transitions(db)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- checing if the same as from transistion
|
||||||
|
return get_inpus_from_transistions_and_check_with_declared(db)
|
||||||
|
end
|
||||||
|
|
||||||
|
function get_all_output_from_reachable_transitions(db)
|
||||||
|
local list = {}
|
||||||
|
for state,v in pairs(db.trans) do
|
||||||
|
if db.reachables[state] then
|
||||||
|
for _,w in pairs(v) do
|
||||||
|
if db.outputs[w.state] ~= nil then
|
||||||
|
append(list,db.outputs[w.state])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local sorted_by_name = DeepCopy(remove_duplicates(list))
|
||||||
|
table.sort(sorted_by_name)
|
||||||
|
return sorted_by_name
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function get_outputs_from_transistions_and_check_with_declared(db)
|
||||||
|
local outs_from_trans = get_all_output_from_reachable_transitions(db)
|
||||||
|
local outs_from_def = db.out_pins
|
||||||
|
|
||||||
|
if cmp_list_eq(outs_from_trans,outs_from_def) then
|
||||||
|
return outs_from_def
|
||||||
|
else
|
||||||
|
local more_in_def = list_minus_list(outs_from_def,outs_from_trans)
|
||||||
|
local more_in_trans = list_minus_list(outs_from_trans, outs_from_def)
|
||||||
|
|
||||||
|
|
||||||
|
if #more_in_def ~= 0 then
|
||||||
|
return nil, "pins '" .. table.concat(more_in_def, ", ") ..
|
||||||
|
"' declared in 'out:' but never used in output states";
|
||||||
|
end
|
||||||
|
if #more_in_trans ~= 0 then
|
||||||
|
return nil, "pins '" .. table.concat(more_in_trans, ", " ) ..
|
||||||
|
"' used in output state definitons, but not declared in 'out:'"
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil, {"pins declared and pins used in transitions are not the same"}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function get_outputs(db)
|
||||||
|
-- check if output pins are declared
|
||||||
|
if db.out_pins == nil or #db.out_pins == 0 then
|
||||||
|
return get_all_output_from_reachable_transitions(db)
|
||||||
|
end
|
||||||
|
return get_outputs_from_transistions_and_check_with_declared(db)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
191
mesecons_autotools/fsm/compiler_general.lua
Normal file
191
mesecons_autotools/fsm/compiler_general.lua
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
------------------------------------------------------------------------
|
||||||
|
-- general functions
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function trim(s)
|
||||||
|
return s:match( "^%s*(.-)%s*$" )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function get_list_from_string(str)
|
||||||
|
local l = {}
|
||||||
|
for i in string.gmatch(str,"%S+") do
|
||||||
|
table.insert(l,trim(i))
|
||||||
|
end
|
||||||
|
return l
|
||||||
|
end
|
||||||
|
|
||||||
|
function get_lines_from_string(str)
|
||||||
|
local l = {}
|
||||||
|
for i in string.gmatch(str,"[^\n]+") do
|
||||||
|
table.insert(l,trim(i))
|
||||||
|
end
|
||||||
|
return l
|
||||||
|
end
|
||||||
|
|
||||||
|
function empty(list)
|
||||||
|
if #list == 0 then return true end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- exists
|
||||||
|
function e(db,key)
|
||||||
|
if db == nil then return false end
|
||||||
|
if db[key] ~= nil then return true end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function is_in_list(list,elem)
|
||||||
|
for _,v in ipairs(list) do
|
||||||
|
if v == elem then return true end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function remove_duplicates(list)
|
||||||
|
local l = {}
|
||||||
|
local db = {}
|
||||||
|
for key,value in pairs(list) do
|
||||||
|
db[value] = true
|
||||||
|
end
|
||||||
|
for key,_ in pairs(db) do
|
||||||
|
table.insert(l,key)
|
||||||
|
end
|
||||||
|
return l
|
||||||
|
end
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
-- help functions
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
local name_reg = "[a-zA-Z][a-zA-Z0-9_]*"
|
||||||
|
|
||||||
|
function is_name(str)
|
||||||
|
return string.match(str,"^" .. name_reg .. "$")
|
||||||
|
end
|
||||||
|
|
||||||
|
function is_negated(n)
|
||||||
|
if string.match(n,"^~.*$") == nil then
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function drop_negation(n)
|
||||||
|
local name = string.match(n,"^~?(.*)$")
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
|
||||||
|
function add_negation(n)
|
||||||
|
return "~" .. drop_negation(n)
|
||||||
|
end
|
||||||
|
|
||||||
|
function swap_negation(n)
|
||||||
|
if is_negated(n) then
|
||||||
|
return drop_negation(n)
|
||||||
|
else
|
||||||
|
return add_negation(n)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function is_pin_name(n)
|
||||||
|
if is_name(n) == nil then return false end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function is_pin_group_name(n)
|
||||||
|
local name = string.match(n,"^#(.*)")
|
||||||
|
if name == nil then return false end
|
||||||
|
return is_pin_name(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
function is_pin_name_n(n)
|
||||||
|
if is_pin_name(n) then return true end
|
||||||
|
|
||||||
|
local name = string.match(n,"^~(.*)$")
|
||||||
|
if name == nil then return false end
|
||||||
|
return is_pin_name(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
function is_pin_group_name_n(n)
|
||||||
|
if is_pin_group_name(n) then return true end
|
||||||
|
|
||||||
|
local name = string.match(n,"^~(.*)$")
|
||||||
|
if name == nil then return false end
|
||||||
|
return is_pin_group_name(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function is_pin_and_group_list(list)
|
||||||
|
for _,v in pairs(list) do
|
||||||
|
if not is_pin_name(v) and not is_pin_group_name(v) then return false end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function is_pin_name_list(list)
|
||||||
|
for _,v in pairs(list) do
|
||||||
|
if not is_pin_name(v) then return false end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function is_pin_and_group_list_n(list)
|
||||||
|
for _,v in pairs(list) do
|
||||||
|
if not is_pin_name_n(v) and
|
||||||
|
not is_pin_group_name_n(v) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function is_state_name(n)
|
||||||
|
if is_name(n) == nil then return false end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function is_state_group_name(n)
|
||||||
|
local name = string.match(n,"^@(.*)")
|
||||||
|
if name == nil then return false end
|
||||||
|
return is_state_name(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
function is_state_and_group_list(list)
|
||||||
|
for _,v in pairs(list) do
|
||||||
|
if (not is_state_name(v)) and
|
||||||
|
(not is_state_group_name(v)) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--[[ not used, for delete
|
||||||
|
function is_uniq_list(list)
|
||||||
|
local db = {}
|
||||||
|
for _,v in pairs(list) do
|
||||||
|
if db[v] == nil then
|
||||||
|
db[v] = true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
]]--
|
||||||
|
-- find first duplicate
|
||||||
|
function get_duplicate(list)
|
||||||
|
if list == nil then return nil end
|
||||||
|
local db = {}
|
||||||
|
for _,v in pairs(list) do
|
||||||
|
if db[v] == nil then
|
||||||
|
db[v] = true
|
||||||
|
else
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
225
mesecons_autotools/fsm/compiler_generating.lua
Normal file
225
mesecons_autotools/fsm/compiler_generating.lua
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
-- generating fsm functions
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
function get_list(list)
|
||||||
|
if list == nil then
|
||||||
|
return {}
|
||||||
|
else
|
||||||
|
return list
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
function fsm_generate_trans(db)
|
||||||
|
-- from ins -> to outs
|
||||||
|
local results = {}
|
||||||
|
local states = get_all_reachable_states(db)
|
||||||
|
for state,_ in pairs(states) do
|
||||||
|
if( db.trans[state] == nilv) then
|
||||||
|
table.insert(results, { from = state, to = state, ins = {} , outs = {} })
|
||||||
|
else
|
||||||
|
for _,ifthens in pairs(db.trans[state]) do
|
||||||
|
local pins_in = ifthens.pins
|
||||||
|
local next_state = ifthens.state
|
||||||
|
local pins_out = db.outputs[next_state]
|
||||||
|
if pins_out == nil then pins_out = {} end
|
||||||
|
table.insert(results, { from = state, to = next_state, ins = pins_in, outs = pins_out } )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return results
|
||||||
|
end
|
||||||
|
|
||||||
|
]]--
|
||||||
|
|
||||||
|
function value_inc(v)
|
||||||
|
local len = #v
|
||||||
|
local carry = true
|
||||||
|
local new = ""
|
||||||
|
|
||||||
|
for i=len,1,-1 do
|
||||||
|
local ch = string.sub(v,i,i)
|
||||||
|
if carry == false then
|
||||||
|
new = ch .. new
|
||||||
|
else
|
||||||
|
if ch == "0" then
|
||||||
|
new = "1" .. new
|
||||||
|
carry = false
|
||||||
|
else
|
||||||
|
new = "0" .. new
|
||||||
|
carry = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return new
|
||||||
|
end
|
||||||
|
|
||||||
|
function next_free_value(len,db)
|
||||||
|
local nv = string.rep("0",len)
|
||||||
|
|
||||||
|
vals = {}
|
||||||
|
-- get only vlaues
|
||||||
|
for k,v in pairs(db) do
|
||||||
|
vals[v] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
for i=1,math.pow(2,len) do
|
||||||
|
if vals[nv] == nil then
|
||||||
|
return nv
|
||||||
|
end
|
||||||
|
nv = value_inc(nv)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- should never get here
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function get_not_used_states(db)
|
||||||
|
local reachables = db.reachables
|
||||||
|
local state_values = db.state_values
|
||||||
|
local not_used_states = {}
|
||||||
|
|
||||||
|
-- checking if some states are not used
|
||||||
|
for k,v in pairs(state_values) do
|
||||||
|
if reachables[k] == nil then
|
||||||
|
table.insert(not_used_states,k)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if #not_used_states == 0 then
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local list = {}
|
||||||
|
for _,v in pairs(not_used_states) do
|
||||||
|
table.insert(list, "state '" .. v .. "' is not used, but declared " .. v ..
|
||||||
|
" := " .. state_values[v])
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil,list
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function fill_states_values(db)
|
||||||
|
local states_values = db.state_values
|
||||||
|
local states = db.reachables
|
||||||
|
local filled = {}
|
||||||
|
|
||||||
|
-- filling existing values
|
||||||
|
for k,_ in pairs(states) do
|
||||||
|
filled[k] = states_values[k]
|
||||||
|
end
|
||||||
|
|
||||||
|
local len = db.state_bitsize
|
||||||
|
local zerostate = string.rep("0",len)
|
||||||
|
|
||||||
|
-- checkint if init already has value, and if it is 0000
|
||||||
|
if filled[init] ~= nil and filled[init] ~= zerostate then
|
||||||
|
return nil, "init state " .. filled[init] .. " has value " ..
|
||||||
|
filled[init] .. ", only value 0 is allovwd for init state"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- checking if state 0000 is used by other state
|
||||||
|
for k,v in pairs(filled) do
|
||||||
|
if v == zerostate then
|
||||||
|
if k ~= db.init then
|
||||||
|
return nil, "value " .. zerostate ..
|
||||||
|
" is reserved for init state, but already used by " ..
|
||||||
|
k .. " := " .. v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- adding default init state as 0000
|
||||||
|
local init = db.init
|
||||||
|
if filled[init] ~= nil then
|
||||||
|
if filled[init] ~= zerostate then
|
||||||
|
return nil,"init state must be " .. zerostate .. ", but is " ..
|
||||||
|
init .. " := " .. filled[init]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if filled[init] == nil then
|
||||||
|
filled[init] = zerostate
|
||||||
|
end
|
||||||
|
|
||||||
|
-- adding rest
|
||||||
|
|
||||||
|
for k,v in pairs(states) do
|
||||||
|
if filled[k] == nil then
|
||||||
|
filled[k] = next_free_value(len,filled)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return filled
|
||||||
|
end
|
||||||
|
|
||||||
|
function only_reachable_state_values(db)
|
||||||
|
local reach = db.reachables
|
||||||
|
local values = db.state_values
|
||||||
|
|
||||||
|
local new = {}
|
||||||
|
|
||||||
|
for k,_ in pairs(values) do
|
||||||
|
if reach[k] ~= nil then
|
||||||
|
new[k] = values[k]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return new
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function fsm_get_all_used_inputs(db)
|
||||||
|
local pins = {}
|
||||||
|
|
||||||
|
for _,v in pairs(db.trans) do
|
||||||
|
local ins = v.ins
|
||||||
|
for _,pin in pairs(ins) do
|
||||||
|
pins[drop_negation(pin)] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return pins
|
||||||
|
end
|
||||||
|
|
||||||
|
-- appends list 2 to lits 1
|
||||||
|
-- probably there is a function for that
|
||||||
|
-- couldn't bother to find it
|
||||||
|
function append(list1,list2)
|
||||||
|
for _,v in pairs(list2) do
|
||||||
|
table.insert(list1,v)
|
||||||
|
end
|
||||||
|
return list1
|
||||||
|
end
|
||||||
|
|
||||||
|
function fsm_get_all_used_outputs(reachable_trans,db)
|
||||||
|
local list = {}
|
||||||
|
|
||||||
|
-- get all pins
|
||||||
|
for _,v in pairs(reachable_trans) do
|
||||||
|
local ps = db.outputs[v.to]
|
||||||
|
apend(list,ps)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- remove negations
|
||||||
|
local list2 = {}
|
||||||
|
for _,v in pairs(list) do
|
||||||
|
table.insert(list2, drop_negation(v))
|
||||||
|
end
|
||||||
|
return remove_duplicates(list2)
|
||||||
|
end
|
||||||
|
|
||||||
|
function check_inputs(db)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
-- generating error messages
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
function error_unknows(unknows)
|
||||||
|
local msg = ""
|
||||||
|
for _,v in pairs(unknows) do
|
||||||
|
msg = msg .. "line: .. " .. v.nr .. " " .. v.line .. "\n"
|
||||||
|
end
|
||||||
|
return msg
|
||||||
|
end
|
216
mesecons_autotools/fsm/compiler_parsing.lua
Normal file
216
mesecons_autotools/fsm/compiler_parsing.lua
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
-- parsing functions
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function is_pin_assign(line)
|
||||||
|
if line == nil then return nil end
|
||||||
|
local pin,pins = string.match(line,"^%s*([#].*)%s*=(.*)$")
|
||||||
|
if pin == nil or pins == nil then return nil end
|
||||||
|
pin = trim(pin)
|
||||||
|
|
||||||
|
if( is_pin_group_name(trim(pin)) ~= true ) then return nil end
|
||||||
|
|
||||||
|
local list = get_list_from_string(pins)
|
||||||
|
if( not is_pin_and_group_list_n(list) ) then return nil end
|
||||||
|
|
||||||
|
local data = {}
|
||||||
|
data.pin = pin
|
||||||
|
data.pins = list
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function is_state_assign(line)
|
||||||
|
if line == nil then return nil end
|
||||||
|
local state,states = string.match(line, "^%s*(@.*)%s*=(.*)$")
|
||||||
|
if state == nil or states == nil then return nil end
|
||||||
|
state = trim(state)
|
||||||
|
|
||||||
|
if( not is_state_group_name(state) ) then return nil end
|
||||||
|
|
||||||
|
local list = get_list_from_string(states)
|
||||||
|
if( not is_state_and_group_list(list) ) then return nil end
|
||||||
|
|
||||||
|
local data = {}
|
||||||
|
data.state = state
|
||||||
|
data.states = list
|
||||||
|
data.line = line
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
|
||||||
|
function is_bin_value(value)
|
||||||
|
if value == nil then return false end
|
||||||
|
for i=1,#value do
|
||||||
|
local ch = string.sub(value,i,i)
|
||||||
|
if (ch ~= "0" ) and (ch ~= "1" ) then return false end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function is_state_value_assign(line)
|
||||||
|
if line == nil then return nil end
|
||||||
|
local state,value = string.match(line, "^%s*(.*)%s*:=(.*)$")
|
||||||
|
|
||||||
|
if state == nil then return nil end
|
||||||
|
if value == nil then return nil end
|
||||||
|
state = trim(state)
|
||||||
|
value = trim(value)
|
||||||
|
|
||||||
|
if not is_state_name(state) then return nil end
|
||||||
|
if not is_bin_value(value) then return nil end
|
||||||
|
|
||||||
|
local data = {}
|
||||||
|
data.state = state
|
||||||
|
data.value = value
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function is_in_assign(line)
|
||||||
|
if line == nil then return nil end
|
||||||
|
local ins = string.match(line, "^%s*in:(.*)$")
|
||||||
|
|
||||||
|
if ins == nil then return nil end
|
||||||
|
local list = get_list_from_string(ins)
|
||||||
|
if( not is_pin_name_list(list) ) then return nil end
|
||||||
|
|
||||||
|
local data = {}
|
||||||
|
data = list
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
|
||||||
|
function is_out_assign(line)
|
||||||
|
if line == nil then return nil end
|
||||||
|
local ins = string.match(line, "^%s*out:(.*)$")
|
||||||
|
|
||||||
|
if ins == nil then return nil end
|
||||||
|
local list = get_list_from_string(ins)
|
||||||
|
if( not is_pin_name_list(list) ) then return nil end
|
||||||
|
|
||||||
|
local data = {}
|
||||||
|
data = list
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function is_init_assign(line)
|
||||||
|
if line == nil then return nil end
|
||||||
|
local init = string.match(line,"^%s*[[][[]%s*(.*)%s*[]][]]%s*$")
|
||||||
|
if init == nil then return nil end
|
||||||
|
if( not is_state_name(init)) then return nil end
|
||||||
|
return trim(init)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function is_state_output_assign(line)
|
||||||
|
if line == nil then return nil end
|
||||||
|
local states,pins = string.match(line, "^%s*[[]%s*(.*)%s*[]](.*)$")
|
||||||
|
if( states == nil or pins == nil ) then return nil end
|
||||||
|
|
||||||
|
local state_list = get_list_from_string(states)
|
||||||
|
if empty(state_list) then return nil end
|
||||||
|
if not is_state_and_group_list(state_list) then return nil end
|
||||||
|
|
||||||
|
local pin_list = get_list_from_string(pins)
|
||||||
|
if empty(pin_list) then return nil end
|
||||||
|
--if not is_pin_and_group_list_n(pin_list) then return nil end
|
||||||
|
if not is_pin_and_group_list(pin_list) then return nil end
|
||||||
|
--if not is_pin_name_list(pin_list) then return nil end
|
||||||
|
|
||||||
|
local data = {}
|
||||||
|
data.states = state_list
|
||||||
|
data.pins = pin_list
|
||||||
|
data.line = line
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
|
||||||
|
function is_state_transition_assign(line)
|
||||||
|
if line == nil then return nil end
|
||||||
|
local states,pins,state = string.match(line,"^%s*[[](.*)[]](.*)->%s*[[](.*)[]]%s*$")
|
||||||
|
if states == nil or state == nil or pins == nil then return nil end
|
||||||
|
|
||||||
|
local state_list = get_list_from_string(states)
|
||||||
|
if empty(state_list) then return nil end
|
||||||
|
if not is_state_and_group_list(state_list) then return nil end
|
||||||
|
|
||||||
|
local pin_list = get_list_from_string(pins)
|
||||||
|
if not is_pin_and_group_list_n(pin_list) then return nil end
|
||||||
|
|
||||||
|
if not is_state_name(trim(state)) then return nil end
|
||||||
|
|
||||||
|
local data = {}
|
||||||
|
data.states = state_list
|
||||||
|
data.pins = pin_list
|
||||||
|
data.state = trim(state)
|
||||||
|
data.line = line
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
|
||||||
|
function is_comment(line)
|
||||||
|
if line == nil then return nil end
|
||||||
|
local comment = string.match(line,"^%s*;.*$")
|
||||||
|
return comment
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function parse_code(text)
|
||||||
|
local inits = {}
|
||||||
|
local pin_assigns = {}
|
||||||
|
local state_assigns = {}
|
||||||
|
local state_outputs = {}
|
||||||
|
local state_transitions = {}
|
||||||
|
local state_values = {}
|
||||||
|
local in_pins = {}
|
||||||
|
local out_pins = {}
|
||||||
|
local unknowns = {}
|
||||||
|
|
||||||
|
local lines = get_lines_from_string(text)
|
||||||
|
for i,line in ipairs(lines) do
|
||||||
|
local init = is_init_assign(line)
|
||||||
|
local pin_assgn = is_pin_assign(line)
|
||||||
|
local state_assign = is_state_assign(line)
|
||||||
|
local state_output = is_state_output_assign(line)
|
||||||
|
local state_transition = is_state_transition_assign(line)
|
||||||
|
local state_value = is_state_value_assign(line)
|
||||||
|
local in_pin = is_in_assign(line)
|
||||||
|
local out_pin = is_out_assign(line)
|
||||||
|
local comment = is_comment(line)
|
||||||
|
|
||||||
|
if( init ~= nil ) then
|
||||||
|
table.insert(inits,init)
|
||||||
|
elseif pin_assgn ~= nil then
|
||||||
|
table.insert(pin_assigns,pin_assgn)
|
||||||
|
elseif state_assign ~= nil then
|
||||||
|
table.insert(state_assigns,state_assign)
|
||||||
|
elseif state_output ~=nil then
|
||||||
|
table.insert(state_outputs,state_output)
|
||||||
|
elseif state_transition ~= nil then
|
||||||
|
table.insert(state_transitions, state_transition)
|
||||||
|
elseif state_value ~= nil then
|
||||||
|
table.insert(state_values,state_value)
|
||||||
|
elseif in_pin ~= nil then
|
||||||
|
table.insert(in_pins,in_pin)
|
||||||
|
elseif out_pin ~= nil then
|
||||||
|
table.insert(out_pins,out_pin)
|
||||||
|
elseif comment ~= nil then
|
||||||
|
-- drop comment
|
||||||
|
else
|
||||||
|
table.insert(unknowns,{nr=i, line = line})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local data = {}
|
||||||
|
data.inits = inits
|
||||||
|
data.pin_assigns = pin_assigns
|
||||||
|
data.state_assigns = state_assigns
|
||||||
|
data.state_outputs = state_outputs
|
||||||
|
data.state_transitions = state_transitions
|
||||||
|
data.state_values = state_values
|
||||||
|
data.in_pins = in_pins
|
||||||
|
data.out_pins = out_pins
|
||||||
|
data.unknowns = unknowns
|
||||||
|
return data
|
||||||
|
end
|
275
mesecons_autotools/fsm/fsm.lua
Normal file
275
mesecons_autotools/fsm/fsm.lua
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
dofile(minetest.get_modpath("mesecons_autotools").."/fsm/lib.lua");
|
||||||
|
dofile(minetest.get_modpath("mesecons_autotools").."/fsm/alg.lua");
|
||||||
|
dofile(minetest.get_modpath("mesecons_autotools").."/fsm/compiler.lua");
|
||||||
|
dofile(minetest.get_modpath("mesecons_autotools").."/fsm/generate.lua");
|
||||||
|
dofile(minetest.get_modpath("mesecons_autotools").."/fsm/priority.lua");
|
||||||
|
|
||||||
|
local esc = minetest.formspec_escape
|
||||||
|
|
||||||
|
function get_stats_string(data)
|
||||||
|
if data == nil then return "<no circuit>" end
|
||||||
|
if data.circ == nil then return "<no circuit>" end
|
||||||
|
if data.circ.nodes == nil then return "<no circuit>" end
|
||||||
|
|
||||||
|
local nodes = data.circ.nodes
|
||||||
|
local stats = "<no circuit>"
|
||||||
|
local block, gate, wire
|
||||||
|
local sx,xy,sz
|
||||||
|
|
||||||
|
block, gate, wire = get_stats(nodes)
|
||||||
|
sx = nodes.sx
|
||||||
|
sy = nodes.sy
|
||||||
|
sz = nodes.sz
|
||||||
|
|
||||||
|
stats = "size : " .. sx .. "x"..sy .. "x"..sz .. "(=".. sx*sy*sz .. ")\n" ..
|
||||||
|
"wires : " .. wire .. "\n" ..
|
||||||
|
"gates : " .. gate .. "\n" ..
|
||||||
|
"others : ".. block - wire - gate .. "\n" ..
|
||||||
|
"blocks: " .. block
|
||||||
|
return stats
|
||||||
|
end
|
||||||
|
|
||||||
|
local function get_formspec(data)
|
||||||
|
local code = minetest.formspec_escape(data.code or "")
|
||||||
|
local name = minetest.formspec_escape(data.name or "")
|
||||||
|
local log = minetest.formspec_escape(data.log or "")
|
||||||
|
|
||||||
|
local stats_string = get_stats_string(data)
|
||||||
|
|
||||||
|
local create_button = ""
|
||||||
|
if data.circ ~= nil then
|
||||||
|
if data.circ.nodes ~= nil then
|
||||||
|
create_button = "image[27.5,23;1,1;circuit_full.png]" ..
|
||||||
|
"button[28.5,23;3,1;create;" .. "Create" .. "]"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
local formspec =
|
||||||
|
"formspec_version[3]"..
|
||||||
|
|
||||||
|
"size[32,25]"..
|
||||||
|
"style_type[textarea;font=mono]" ..
|
||||||
|
|
||||||
|
"label[15,0.7;FSM generator]"..
|
||||||
|
--"label[20,0.7;" .. file .. "]" ..
|
||||||
|
"field[0.5,2;15,1;name;Name;" .. name .. "]"..
|
||||||
|
"textarea[0.5,4;15,15;code;" .. "Code:;" .. code .. "]" ..
|
||||||
|
"textarea[16.5,2;15,17;;" .. "Compilation Logs:" .. ";" .. log .. "]" ..
|
||||||
|
"button[0.5,19;3,1;save;" .. "Save" .. "]" ..
|
||||||
|
"button[14.5,20;3,1;compile;" .. "Compile" .. "]" ..
|
||||||
|
|
||||||
|
|
||||||
|
"textarea[23.5,21;8,5;;Circuit Parameters;" .. esc(stats_string) .. "]" ..
|
||||||
|
|
||||||
|
|
||||||
|
"label[0.5,21;Generation Options:]" ..
|
||||||
|
"label[1,22;Circuit Type:]" ..
|
||||||
|
"dropdown[4,21.5;5,1;type;flat_raw;1]" ..
|
||||||
|
|
||||||
|
create_button ..
|
||||||
|
|
||||||
|
""
|
||||||
|
return formspec
|
||||||
|
end
|
||||||
|
|
||||||
|
function on_place_fsm_book(itemstack, player, pointed_thing)
|
||||||
|
local user = player:get_player_name()
|
||||||
|
local rad = player:get_look_horizontal()
|
||||||
|
local direction = radians_to_direction_looking_forward(rad)
|
||||||
|
local fields = itemstack:get_meta():to_table().fields
|
||||||
|
local file = fields.file
|
||||||
|
|
||||||
|
if not mesecons_autotools.is_full_selection(user) then return nil end
|
||||||
|
local pos1 = mesecons_autotools.get_pos(user,1)
|
||||||
|
local pos2 = mesecons_autotools.get_pos(user,2)
|
||||||
|
local sel = {pos1=pos1,pos2=pos2}
|
||||||
|
|
||||||
|
local data = read_table_from_file(file)
|
||||||
|
if data.circ == nil then return end
|
||||||
|
local circ = data.circ
|
||||||
|
|
||||||
|
|
||||||
|
paste_circuit_from_table(sel,circ,direction)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function show_dialog_fsm(player,itemstack)
|
||||||
|
local user = player:get_player_name()
|
||||||
|
local fields = itemstack:get_meta():to_table().fields
|
||||||
|
local file = fields.file
|
||||||
|
local stack = player:get_wielded_item()
|
||||||
|
local db = {}
|
||||||
|
local data = {}
|
||||||
|
|
||||||
|
if file == nil then
|
||||||
|
file = generate_file_name_fsm(user)
|
||||||
|
fields.file = file
|
||||||
|
stack:get_meta():from_table({ fields = fields})
|
||||||
|
player:set_wielded_item(stack)
|
||||||
|
|
||||||
|
data.code = ""
|
||||||
|
data.name = ""
|
||||||
|
data.log = ""
|
||||||
|
save_table_to_file(file,data)
|
||||||
|
else
|
||||||
|
data = read_table_from_file(file)
|
||||||
|
if data == nil then data = {} end
|
||||||
|
end
|
||||||
|
|
||||||
|
local formspec = get_formspec(data)
|
||||||
|
|
||||||
|
minetest.show_formspec(user, "mesecons_autotools:fsm_show", formspec)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function fsm_make_selection(user,file,direction,pos)
|
||||||
|
if file == nil then return end
|
||||||
|
|
||||||
|
local data = read_table_from_file(file)
|
||||||
|
if data.circ == nil then return end
|
||||||
|
local nodes = data.circ.nodes
|
||||||
|
|
||||||
|
if nodes == nil then return end
|
||||||
|
|
||||||
|
|
||||||
|
local sx = nodes.sx
|
||||||
|
local sy = nodes.sy
|
||||||
|
local sz = nodes.sz
|
||||||
|
|
||||||
|
|
||||||
|
local pos2 = make_pos2(pos,direction,sx,sy,sz)
|
||||||
|
|
||||||
|
-- Updatecd
|
||||||
|
mesecons_autotools.set_pos(user,1,pos)
|
||||||
|
mesecons_autotools.set_pos(user,2,pos2)
|
||||||
|
mesecons_autotools.render(user)
|
||||||
|
mesecons_autotools.zero_stack_counter(user)
|
||||||
|
mesecons_autotools.zero_stack_direction(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function on_use_fsm_book(itemstack, player, pointed_thing)
|
||||||
|
|
||||||
|
local user = player:get_player_name()
|
||||||
|
local data = itemstack:get_meta():to_table().fields
|
||||||
|
local rad = player:get_look_horizontal()
|
||||||
|
local direction = radians_to_direction_looking_forward(rad)
|
||||||
|
local file = data.file
|
||||||
|
-- local stack = player:get_wielded_item()
|
||||||
|
|
||||||
|
if( pointed_thing.type == "node" ) then
|
||||||
|
fsm_make_selection(user,file,direction,pointed_thing.above)
|
||||||
|
else
|
||||||
|
show_dialog_fsm(player,itemstack)
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
|
if formname ~= "mesecons_autotools:fsm_show" then return end
|
||||||
|
local user = player:get_player_name()
|
||||||
|
local stack = player:get_wielded_item()
|
||||||
|
local ffields = stack:get_meta():to_table().fields
|
||||||
|
|
||||||
|
local data = {}
|
||||||
|
local file = ffields.file
|
||||||
|
|
||||||
|
if file == nil then
|
||||||
|
file = generate_file_name_fsm(user)
|
||||||
|
ffields.file = file
|
||||||
|
data.name =""
|
||||||
|
data.code =""
|
||||||
|
data.log =""
|
||||||
|
|
||||||
|
save_table_to_file(file,data) -- just to generate file
|
||||||
|
else
|
||||||
|
data = read_table_from_file(file)
|
||||||
|
if data == nil then data = {} end
|
||||||
|
end
|
||||||
|
|
||||||
|
data.name = fields.name or ""
|
||||||
|
data.code = fields.code or ""
|
||||||
|
|
||||||
|
|
||||||
|
if (fields.save) or fields.key_enter_field == "name" then
|
||||||
|
ffields.description = data.name
|
||||||
|
stack:get_meta():from_table({ fields = ffields})
|
||||||
|
player:set_wielded_item(stack)
|
||||||
|
save_table_to_file(file,data)
|
||||||
|
|
||||||
|
elseif fields.compile then
|
||||||
|
ffields.description = data.name
|
||||||
|
stack:get_meta():from_table({ fields = ffields})
|
||||||
|
player:set_wielded_item(stack)
|
||||||
|
|
||||||
|
|
||||||
|
--compilation area
|
||||||
|
|
||||||
|
local bin,err = compile_code(data.code)
|
||||||
|
if bin == nil then
|
||||||
|
data.log = err
|
||||||
|
data.circ = nil
|
||||||
|
else
|
||||||
|
local circ = generate_circuit(bin,{})
|
||||||
|
data.circ = circ
|
||||||
|
data.log = err
|
||||||
|
end
|
||||||
|
|
||||||
|
--end of copmilation area
|
||||||
|
|
||||||
|
save_table_to_file(file,data)
|
||||||
|
|
||||||
|
local formspec = get_formspec(data)
|
||||||
|
minetest.show_formspec(user, "mesecons_autotools:fsm_show", formspec)
|
||||||
|
|
||||||
|
elseif fields.create then
|
||||||
|
if data.circ == nil then return end
|
||||||
|
if data.circ.nodes == nil then return end
|
||||||
|
|
||||||
|
-- create file
|
||||||
|
local blue = {}
|
||||||
|
blue.nodes = data.circ.nodes
|
||||||
|
blue.metas = data.circ.metas
|
||||||
|
blue.title = data.name
|
||||||
|
blue.text = ""
|
||||||
|
blue.direction = {x=0,y=0,z=1}
|
||||||
|
|
||||||
|
-- save file
|
||||||
|
|
||||||
|
local blue_file = generate_file_name(user)
|
||||||
|
save_table_to_file(blue_file,blue)
|
||||||
|
|
||||||
|
-- create item in inventory
|
||||||
|
|
||||||
|
local new_stack = ItemStack("mesecons_autotools:circuit_full")
|
||||||
|
local b = {}
|
||||||
|
b.file = blue_file
|
||||||
|
b.description = blue.title
|
||||||
|
new_stack:get_meta():from_table({ fields = b})
|
||||||
|
|
||||||
|
local inv = player:get_inventory()
|
||||||
|
if inv:room_for_item("main", new_stack) then
|
||||||
|
inv:add_item("main", new_stack)
|
||||||
|
else
|
||||||
|
minetest.add_item(player:get_pos(), new_stack)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_tool("mesecons_autotools:fsm", {
|
||||||
|
description = "FSM generator",
|
||||||
|
inventory_image = "fsm_book.png",
|
||||||
|
stack_max = 1,
|
||||||
|
|
||||||
|
on_use = on_use_fsm_book,
|
||||||
|
on_place = on_place_fsm_book,
|
||||||
|
on_secondary_use = none,
|
||||||
|
|
||||||
|
})
|
742
mesecons_autotools/fsm/generate.lua
Normal file
742
mesecons_autotools/fsm/generate.lua
Normal file
@ -0,0 +1,742 @@
|
|||||||
|
------------------------------------------------------------------------
|
||||||
|
-- generating wires
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
function g_wire_line(rotation,state)
|
||||||
|
local r = 0
|
||||||
|
if rotation == "h" then
|
||||||
|
r = 0
|
||||||
|
else -- == "v"
|
||||||
|
r = 1
|
||||||
|
end
|
||||||
|
return {
|
||||||
|
node = {name="mesecons_insulated:insulated_".. state , param2 = r},
|
||||||
|
meta = {}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function g_wire_bend(rotation,state)
|
||||||
|
local rot = 0
|
||||||
|
if rotation == "lu" then
|
||||||
|
rot = 1
|
||||||
|
elseif rotation == "ru" then
|
||||||
|
rot = 2
|
||||||
|
elseif rotation == "rd" then
|
||||||
|
rot = 3
|
||||||
|
elseif rotation == "ld" then
|
||||||
|
rot = 0
|
||||||
|
else
|
||||||
|
rot = 0
|
||||||
|
end
|
||||||
|
return {
|
||||||
|
node = {name="mesecons_extrawires:corner_" .. state, param2=rot},
|
||||||
|
meta = {}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function g_wire_cross(state)
|
||||||
|
local s = "off"
|
||||||
|
if state == "off" then
|
||||||
|
s = "off"
|
||||||
|
elseif state == "on" then
|
||||||
|
s = "on"
|
||||||
|
elseif state == "h" then
|
||||||
|
s = "01"
|
||||||
|
elseif state == "v" then
|
||||||
|
s = "10"
|
||||||
|
else
|
||||||
|
s = "off"
|
||||||
|
end
|
||||||
|
return {
|
||||||
|
node = {name="mesecons_extrawires:crossover_" .. s, param2=0},
|
||||||
|
meta = {}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function g_wire_t(rotation,state)
|
||||||
|
local p = 0
|
||||||
|
if rotation == "u" then
|
||||||
|
p = 2
|
||||||
|
elseif rotation == "d" then
|
||||||
|
p = 0
|
||||||
|
elseif rotation == "l" then
|
||||||
|
p = 1
|
||||||
|
else -- "r"
|
||||||
|
p = 3
|
||||||
|
end
|
||||||
|
return {
|
||||||
|
node = {name="mesecons_extrawires:tjunction_" .. state, param2=p},
|
||||||
|
meta = {}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function g_wire_xjunction(state)
|
||||||
|
return {
|
||||||
|
node = {name="mesecons_morewires:xjunction_" .. state, param2=0},
|
||||||
|
meta = {}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
-- generating gates
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
function g_gate_not(state,rot)
|
||||||
|
local p
|
||||||
|
if rot == "up" then
|
||||||
|
p = 3
|
||||||
|
elseif rot == "left" then
|
||||||
|
p = 2
|
||||||
|
elseif rot == "right" then
|
||||||
|
p = 0
|
||||||
|
else --down
|
||||||
|
p = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
node = {name="mesecons_gates:not_" .. state,param2=p},
|
||||||
|
meta = { ["inventory"] = { } ,["fields"] = { } ,}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function g_gate_diode(state,rot)
|
||||||
|
local p
|
||||||
|
if rot == "up" then
|
||||||
|
p = 3
|
||||||
|
elseif rot == "left" then
|
||||||
|
p = 2
|
||||||
|
elseif rot == "right" then
|
||||||
|
p = 0
|
||||||
|
else --down
|
||||||
|
p = 1
|
||||||
|
end
|
||||||
|
return {
|
||||||
|
node = {name="mesecons_gates:diode_" .. state, param2=p},
|
||||||
|
meta = { ["inventory"] = { } ,["fields"] = { } ,}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function g_ff(state,rot,data) -- din = data in
|
||||||
|
local p
|
||||||
|
if rot == "up" then
|
||||||
|
p = 3
|
||||||
|
elseif rot == "left" then
|
||||||
|
p = 2
|
||||||
|
elseif rot == "right" then
|
||||||
|
p = 0
|
||||||
|
else --down
|
||||||
|
p = 1
|
||||||
|
end
|
||||||
|
local din
|
||||||
|
if data == "off" then din = 0 else din =1 end
|
||||||
|
return {
|
||||||
|
node={ name = "mesecons_regs:flipflop_off" ,param2 = p} ,
|
||||||
|
meta={ ["inventory"] = { } ,["fields"] = { ["enable"] = 0,["data"] = din,} }
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
-- help functions
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function set(circ,x,z,elem)
|
||||||
|
local node = elem.node
|
||||||
|
local meta = elem.meta
|
||||||
|
m3_set(circ.nodes,x,1,z,node)
|
||||||
|
m3_set(circ.metas,x,1,z,meta)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function is_bl_empty(c)
|
||||||
|
if c == nil then return true end
|
||||||
|
if c.nodes == nil then return true end
|
||||||
|
if c.nodes.sx == 0 or c.nodes.sy == 0 or c.nodes.sz==0 then return true end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- block insert
|
||||||
|
function blinsert(chost,celem,x,y,z)
|
||||||
|
if is_bl_empty(celem) then return end
|
||||||
|
m3_insert(chost.nodes,celem.nodes,x,y,z)
|
||||||
|
m3_insert(chost.metas,celem.metas,x,y,z)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function is_all_zeros(v)
|
||||||
|
for i=1,string.len(v) do
|
||||||
|
if string.sub(v,i,i) ~= "0" then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function new_circ()
|
||||||
|
return { nodes = { sx=0,sy=0,sz=0} , metas = {sx=0,sy=0,sz=0} }
|
||||||
|
end
|
||||||
|
|
||||||
|
function gnode_to_circ(n)
|
||||||
|
local c = new_circ()
|
||||||
|
set(c,1,1,n)
|
||||||
|
c.nodes.sx = 1
|
||||||
|
c.nodes.sy = 1
|
||||||
|
c.nodes.sz = 1
|
||||||
|
c.metas.sx = 1
|
||||||
|
c.metas.sy = 1
|
||||||
|
c.metas.sz = 1
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function inverse_state(v)
|
||||||
|
if v == "on" then return "off" else return "on" end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function switch_01_to_onoff(c)
|
||||||
|
if c == "0" then
|
||||||
|
return "off"
|
||||||
|
else
|
||||||
|
return "on"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[ not used
|
||||||
|
function has_negation(list)
|
||||||
|
for _,v in pairs(list) do
|
||||||
|
if is_negated(v) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
]]--
|
||||||
|
function has_positive_pin(list)
|
||||||
|
for _,v in pairs(list) do
|
||||||
|
if not is_negated(v) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function or_state(s1,s2)
|
||||||
|
if s1 == "off" and s2 == "off" then return "off" else return "on" end
|
||||||
|
end
|
||||||
|
|
||||||
|
function or_value(v1,v2)
|
||||||
|
local s = ""
|
||||||
|
for i=1,string.len(v1) do
|
||||||
|
if string.sub(v1,i,i) == "0" and string.sub(v2,i,i) == "0" then
|
||||||
|
s = s .. "0"
|
||||||
|
else
|
||||||
|
s = s .. "1"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
-- generating bundles of wires
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function bl_bend_1wire_from_down_to_right(x0,y0, x1,y1)
|
||||||
|
-- (x0,y0) to (x1,y1) first going up, then going right
|
||||||
|
local c = new_circ()
|
||||||
|
|
||||||
|
-- vertical
|
||||||
|
for i=y0,y1-1 do
|
||||||
|
blinsert(c,gnode_to_circ( g_wire_line("v","off") ), x0,1,i)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- curve
|
||||||
|
blinsert(c,gnode_to_circ(g_wire_bend("rd","off")), x0,1,y1)
|
||||||
|
|
||||||
|
-- horizontal
|
||||||
|
for i=x0+1,x1 do
|
||||||
|
blinsert(c,gnode_to_circ(g_wire_line("h","off")),i,1,y1)
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function bl_bend_bundle_from_down_to_right_step2(size)
|
||||||
|
local c = new_circ()
|
||||||
|
|
||||||
|
for i=1,size do
|
||||||
|
local shifth = (i-1)*2+1
|
||||||
|
local shiftv = size - i +1
|
||||||
|
local maxshift = size*2-1
|
||||||
|
blinsert(c, bl_bend_1wire_from_down_to_right(shifth,1,maxshift,shiftv),1,1,1)
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function bl_t_bundle_to_down_step2(size)
|
||||||
|
-- crossing
|
||||||
|
local c = new_circ()
|
||||||
|
for i=1,size do
|
||||||
|
local hshift = (i-1)*2+1
|
||||||
|
|
||||||
|
for k=1,size-i do
|
||||||
|
blinsert(c,gnode_to_circ(g_wire_cross("off")),hshift,1,k)
|
||||||
|
end
|
||||||
|
|
||||||
|
local vstart = size-i+1
|
||||||
|
blinsert(c,gnode_to_circ(g_wire_t("d","off")),hshift,1,vstart)
|
||||||
|
|
||||||
|
for k=size-i+2,size do
|
||||||
|
blinsert(c, gnode_to_circ(g_wire_line("h","off")),hshift,1,k)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for i=1,size do
|
||||||
|
local hsift = (i-1)*2+1+1
|
||||||
|
for k=1,size do
|
||||||
|
blinsert(c,gnode_to_circ(g_wire_line("h","off")),hsift,1,k)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function add_left_connection(size)
|
||||||
|
-- adding connections
|
||||||
|
local left = new_circ()
|
||||||
|
for i=1,size do
|
||||||
|
blinsert(left,gnode_to_circ(g_wire_line("h","off")),1,1,i)
|
||||||
|
blinsert(left,gnode_to_circ(g_wire_line("h","off")),2,1,i)
|
||||||
|
end
|
||||||
|
return left
|
||||||
|
end
|
||||||
|
|
||||||
|
function bl_bundle_horisontal(count,length)
|
||||||
|
local c = new_circ()
|
||||||
|
for x=1,length do
|
||||||
|
for y=1,count do
|
||||||
|
blinsert(c,gnode_to_circ(g_wire_line("h","off")),x,1,y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function add_down_connection(size)
|
||||||
|
local down = new_circ()
|
||||||
|
for i=1,size do
|
||||||
|
local hshift = (i-1)*2+1
|
||||||
|
blinsert(down,gnode_to_circ(g_wire_line("v","off")),hshift,1,1)
|
||||||
|
blinsert(down,gnode_to_circ(g_wire_line("v","off")),hshift,1,2)
|
||||||
|
end
|
||||||
|
return down
|
||||||
|
end
|
||||||
|
|
||||||
|
function bl_t_bundle_to_down_step2_and_down_conn(size)
|
||||||
|
-- crossing
|
||||||
|
local c = bl_t_bundle_to_down_step2(size)
|
||||||
|
|
||||||
|
-- adding connections
|
||||||
|
local down = add_down_connection(size)
|
||||||
|
|
||||||
|
local all = new_circ()
|
||||||
|
blinsert(all,down,1,1,1)
|
||||||
|
blinsert(all,c,1,1,3)
|
||||||
|
return all
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function bl_t_bundle_to_down_step2_and_connections(size)
|
||||||
|
|
||||||
|
-- crossing
|
||||||
|
local c = bl_t_bundle_to_down_step2(size)
|
||||||
|
|
||||||
|
-- connections
|
||||||
|
local left = add_left_connection(size)
|
||||||
|
local down = add_down_connection(size)
|
||||||
|
|
||||||
|
local all = new_circ()
|
||||||
|
blinsert(all,left,1,1,3)
|
||||||
|
blinsert(all,down,3,1,1)
|
||||||
|
blinsert(all,c,3,1,3)
|
||||||
|
return all
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
-- generating circuits
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
function bl_frame(gate, gstate, vstate, hstate,rot)
|
||||||
|
-- rot = "up" | "down"
|
||||||
|
|
||||||
|
local c = {}
|
||||||
|
c.nodes = {}
|
||||||
|
c.metas = {}
|
||||||
|
|
||||||
|
if gate == "diode" or gate == "not" then
|
||||||
|
-- vertical wires
|
||||||
|
set(c,1,1, g_wire_t("r",vstate))
|
||||||
|
set(c,2,1, g_wire_bend("lu",vstate))
|
||||||
|
set(c,1,2, g_wire_line("v",vstate))
|
||||||
|
|
||||||
|
if gate == "diode" then
|
||||||
|
set(c,2,2, g_gate_diode(gstate,rot))
|
||||||
|
else
|
||||||
|
set(c,2,2, g_gate_not(gstate,rot))
|
||||||
|
end
|
||||||
|
|
||||||
|
--horizontal wires
|
||||||
|
set(c,2,3, g_wire_t("d",hstate))
|
||||||
|
|
||||||
|
else -- wire
|
||||||
|
set(c,1,1, g_wire_line("v",vstate))
|
||||||
|
set(c,1,2, g_wire_line("v",vstate))
|
||||||
|
set(c,2,3, g_wire_line("h",hstate))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- crossing
|
||||||
|
if hstate == "off" and vstate == "off" then
|
||||||
|
set(c,1,3, g_wire_cross("off"))
|
||||||
|
elseif hstate == "on" and vstate == "off" then
|
||||||
|
set(c,1,3, g_wire_cross("h"))
|
||||||
|
elseif hstate == "off" and vstate == "on" then
|
||||||
|
set(c,1,3, g_wire_cross("v"))
|
||||||
|
else
|
||||||
|
set(c,1,3, g_wire_cross("on"))
|
||||||
|
end
|
||||||
|
|
||||||
|
c.nodes.sx = 2
|
||||||
|
c.nodes.sy = 1
|
||||||
|
c.nodes.sz = 3
|
||||||
|
c.metas.sx = 2
|
||||||
|
c.metas.sy = 1
|
||||||
|
c.metas.sz = 3
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function bl_ff(data)
|
||||||
|
local c = new_circ()
|
||||||
|
set(c,1,1,g_ff("off","up",data))
|
||||||
|
set(c,1,2,g_wire_cross("off"))
|
||||||
|
set(c,2,2,g_wire_t("d","off"))
|
||||||
|
set(c,2,1,g_wire_bend("lu","off"))
|
||||||
|
c.nodes.sx = 2
|
||||||
|
c.nodes.sy = 1
|
||||||
|
c.nodes.sz = 2
|
||||||
|
c.metas.sx = 2
|
||||||
|
c.metas.sy = 1
|
||||||
|
c.metas.sz = 2
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function bl_register(vvalue)
|
||||||
|
local c = new_circ()
|
||||||
|
for i=1,#vvalue do
|
||||||
|
local char = string.sub(vvalue,i,i)
|
||||||
|
if char == "0" then
|
||||||
|
blinsert(c,bl_ff("off"),(i-1)*2+1,1,1)
|
||||||
|
else
|
||||||
|
blinsert(c,bl_ff("on"),(i-1)*2+1,1,1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function bl_state_value_in(v,hstate)
|
||||||
|
-- eg. v = "01011"
|
||||||
|
local len = string.len(v)
|
||||||
|
local vstate = "off"
|
||||||
|
local c = new_circ()
|
||||||
|
local rot = "up"
|
||||||
|
|
||||||
|
local curri = 1
|
||||||
|
for i=1,len do
|
||||||
|
local char = string.sub(v,i,i)
|
||||||
|
if char == "0" then
|
||||||
|
blinsert(c,bl_frame("diode",vstate, vstate,hstate,rot), (i-1)*2+1,1,1 )
|
||||||
|
else
|
||||||
|
blinsert(c,bl_frame("not",inverse_state(vstate), vstate,hstate,rot), (i-1)*2+1,1,1 )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
function bl_state_value_out(v,hv,vvalue)
|
||||||
|
-- eg. v = "01011"
|
||||||
|
-- eg. hv = "on" | "off"
|
||||||
|
-- eg. vvalue "010110"
|
||||||
|
local len = string.len(v)
|
||||||
|
local c = new_circ()
|
||||||
|
local rot = "down"
|
||||||
|
|
||||||
|
local curri = 1
|
||||||
|
for i=1,len do
|
||||||
|
local char = string.sub(v,i,i)
|
||||||
|
local out_wire_state = switch_01_to_onoff(string.sub(vvalue,i,i))
|
||||||
|
if char == "1" then
|
||||||
|
blinsert(c,bl_frame("diode",hv, out_wire_state, hv, rot), (i-1)*2+1,1,1 )
|
||||||
|
else
|
||||||
|
blinsert(c,bl_frame("wire",hv, out_wire_state, hv, rot), (i-1)*2+1,1,1 )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function bl_pin_value(pins, defined_pins,hstate)
|
||||||
|
local hpins = list_to_hash(pins)
|
||||||
|
local c = new_circ()
|
||||||
|
local rot = "up"
|
||||||
|
local vstate = "off"
|
||||||
|
for i=1,#defined_pins do
|
||||||
|
local v = defined_pins[i]
|
||||||
|
local p = (i-1)*2+1
|
||||||
|
if hpins[v] ~= nil then
|
||||||
|
blinsert(c,bl_frame("not",inverse_state(vstate), vstate, hstate,rot),p,1,1)
|
||||||
|
elseif hpins[add_negation(v)] ~= nil then
|
||||||
|
blinsert(c,bl_frame("diode",vstate, vstate, hstate,rot), p,1,1)
|
||||||
|
else
|
||||||
|
blinsert(c,bl_frame("wire",vstate, vstate, hstate,rot), p,1,1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function generate_ifthens(db)
|
||||||
|
local c = new_circ()
|
||||||
|
|
||||||
|
-- computing output state
|
||||||
|
local cumulative_state = string.rep("0", db.state_bitsize)
|
||||||
|
for state,ifs in pairs(db.trans) do
|
||||||
|
for _,v in pairs(ifs) do
|
||||||
|
local pins = v.pins
|
||||||
|
local valuein = db.state_values[state]
|
||||||
|
local valueout = db.state_values[v.state]
|
||||||
|
local if_pin_state
|
||||||
|
if has_positive_pin(pins) then
|
||||||
|
if_pin_state = "on"
|
||||||
|
else
|
||||||
|
if_pin_state = "off"
|
||||||
|
end
|
||||||
|
|
||||||
|
local if_state_state
|
||||||
|
if is_all_zeros(valuein) then
|
||||||
|
if_state_state = "off"
|
||||||
|
else
|
||||||
|
if_state_state = "on"
|
||||||
|
end
|
||||||
|
local if_state = or_state(if_pin_state, if_state_state)
|
||||||
|
|
||||||
|
if if_state == "off" then -- because of negation in front of it
|
||||||
|
-- so this one is active
|
||||||
|
cumulative_state = or_value(cumulative_state,valueout)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- generating
|
||||||
|
local thens = new_circ()
|
||||||
|
local ifs = new_circ()
|
||||||
|
local i = 1
|
||||||
|
for state,ife in pairs(db.trans) do
|
||||||
|
for _,v in pairs(ife) do
|
||||||
|
local pins = v.pins
|
||||||
|
local valuein = db.state_values[state]
|
||||||
|
local valueout = db.state_values[v.state]
|
||||||
|
local defined_pins = db.inputs_used
|
||||||
|
|
||||||
|
-- if state == 0000 then skip generating
|
||||||
|
if not is_all_zeros(valueout) then
|
||||||
|
|
||||||
|
local if_pin_state
|
||||||
|
if has_positive_pin(pins) then
|
||||||
|
if_pin_state = "on"
|
||||||
|
else
|
||||||
|
if_pin_state = "off"
|
||||||
|
end
|
||||||
|
|
||||||
|
local if_state_state
|
||||||
|
if is_all_zeros(valuein) then
|
||||||
|
if_state_state = "off"
|
||||||
|
else
|
||||||
|
if_state_state = "on"
|
||||||
|
end
|
||||||
|
|
||||||
|
local if_state = or_state(if_pin_state, if_state_state)
|
||||||
|
|
||||||
|
|
||||||
|
local bl_statein = bl_state_value_in(valuein,if_state)
|
||||||
|
local bl_pinsin = bl_pin_value(pins, defined_pins, if_state)
|
||||||
|
local bl_stateout = bl_state_value_out(valueout,inverse_state(if_state), cumulative_state)
|
||||||
|
|
||||||
|
-- putting all together
|
||||||
|
local curr_pos = (i-1)*3+1
|
||||||
|
blinsert(thens,bl_stateout,1,1,curr_pos)
|
||||||
|
|
||||||
|
blinsert(ifs, gnode_to_circ(g_gate_not(inverse_state(if_state) ,"left")),1,1,curr_pos+2)
|
||||||
|
blinsert(ifs, bl_statein, 2,1,curr_pos)
|
||||||
|
blinsert(ifs, bl_pinsin, 1+1+ db.state_bitsize*2,1,curr_pos)
|
||||||
|
|
||||||
|
i=i+1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
blinsert(c,thens,1,1,1)
|
||||||
|
blinsert(c,ifs, 1+db.state_bitsize*2,1,1)
|
||||||
|
blinsert(c,bl_register(cumulative_state), 1, 1, (i-1)*3+1 )
|
||||||
|
|
||||||
|
blinsert(c,bl_bend_bundle_from_down_to_right_step2(db.state_bitsize),1,1,(i-1)*3+1 +2)
|
||||||
|
blinsert(c,bl_t_bundle_to_down_step2_and_connections(db.state_bitsize),
|
||||||
|
db.state_bitsize*2,1,(i-1)*3+1 )
|
||||||
|
|
||||||
|
|
||||||
|
local posy = (i-1)*3+1 +2
|
||||||
|
local posx = 2*2*db.state_bitsize + 2
|
||||||
|
blinsert(c,bl_bundle_horisontal(db.state_bitsize,2*#db.inputs_used),posx,1,posy)
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function pins_to_value(lpins,defined_output_pins)
|
||||||
|
local hpins = list_to_hash(lpins)
|
||||||
|
local v = ""
|
||||||
|
for _,p in ipairs(defined_output_pins) do
|
||||||
|
if hpins[p] ~= nil then
|
||||||
|
if not is_negated(p) then
|
||||||
|
v = v .. "1"
|
||||||
|
else
|
||||||
|
v = v .. "0"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
v=v.."0"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function generate_output_ifstate_thenpins(db)
|
||||||
|
local c = new_circ()
|
||||||
|
local defined_pins = db.outputs_used
|
||||||
|
|
||||||
|
-- computing output state
|
||||||
|
local cumulative_state = string.rep("0", #defined_pins)
|
||||||
|
for state,out_pins in pairs(db.outputs) do
|
||||||
|
local value = db.state_values[state]
|
||||||
|
if value ~= nil then
|
||||||
|
if is_all_zeros(value) then
|
||||||
|
cumulative_state = pins_to_value(out_pins,defined_pins )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- generating
|
||||||
|
local ifs = new_circ()
|
||||||
|
local thens = new_circ()
|
||||||
|
local nots = new_circ()
|
||||||
|
local i = 1
|
||||||
|
for state,out_pins in pairs(db.outputs) do
|
||||||
|
local value = db.state_values[state]
|
||||||
|
if value == nil then return new_circ() end --aborting all, no states
|
||||||
|
|
||||||
|
local pinso = pins_to_value(out_pins,defined_pins)
|
||||||
|
|
||||||
|
local if_state_state
|
||||||
|
if is_all_zeros(value) then
|
||||||
|
if_state = "off"
|
||||||
|
else
|
||||||
|
if_state = "on"
|
||||||
|
end
|
||||||
|
|
||||||
|
local bl_state = bl_state_value_in(value,if_state)
|
||||||
|
local bl_stateout = bl_state_value_out(pinso,inverse_state(if_state), cumulative_state)
|
||||||
|
|
||||||
|
-- putting all together
|
||||||
|
local curr_pos = (i-1)*3+1
|
||||||
|
blinsert(ifs,bl_state,1,1,curr_pos)
|
||||||
|
blinsert(nots, gnode_to_circ(g_gate_not(inverse_state(if_state) ,"right")),
|
||||||
|
1,1,curr_pos+2)
|
||||||
|
|
||||||
|
blinsert(thens, bl_stateout, 1,1,curr_pos)
|
||||||
|
i=i+1
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
blinsert(c,ifs,1,1,1)
|
||||||
|
blinsert(c,nots, db.state_bitsize*2+1,1,1)
|
||||||
|
blinsert(c,thens,db.state_bitsize*2+2,1,1)
|
||||||
|
if count_hash(db.outputs) ~= 0 then
|
||||||
|
blinsert(c,bl_t_bundle_to_down_step2_and_down_conn(db.state_bitsize),
|
||||||
|
1,1,(i-1)*3+1 )
|
||||||
|
end
|
||||||
|
|
||||||
|
return c
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-----------------------------------------------------------------
|
||||||
|
|
||||||
|
function fill_with_air(c)
|
||||||
|
if c == nil then return nil end
|
||||||
|
local sx = c.nodes.sx
|
||||||
|
local sy = c.nodes.sy
|
||||||
|
local sz = c.nodes.sz
|
||||||
|
|
||||||
|
for ix=1,sx do
|
||||||
|
for iy=1,sy do
|
||||||
|
for iz=1,sz do
|
||||||
|
if m3_get(c.nodes,ix,iy,iz) == nil then
|
||||||
|
m3_set(c.nodes,ix,iy,iz, {name="air",param2=0})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- do I have to fill meta too?
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function fsmgenerate_raw(db)
|
||||||
|
local ifth = generate_ifthens(db)
|
||||||
|
local ifout = generate_output_ifstate_thenpins(db)
|
||||||
|
local c = new_circ()
|
||||||
|
|
||||||
|
local hsize = ifth.nodes.sx
|
||||||
|
local vsize = ifth.nodes.sz
|
||||||
|
|
||||||
|
local hsize2 = ifout.nodes.sx
|
||||||
|
local vsize2 = ifout.nodes.sz
|
||||||
|
|
||||||
|
local max = math.max(vsize,vsize2)
|
||||||
|
|
||||||
|
|
||||||
|
blinsert(c,ifth,1,1,max+1-vsize)
|
||||||
|
blinsert(c,ifout,hsize+2,1,max-vsize2+1 )
|
||||||
|
|
||||||
|
blinsert(c,bl_bundle_horisontal(db.state_bitsize,1),
|
||||||
|
1+ifth.nodes.sx,1, max+1-db.state_bitsize)
|
||||||
|
|
||||||
|
fill_with_air(c)
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
function generate_circuit(bin,options)
|
||||||
|
return fsmgenerate_raw(bin)
|
||||||
|
end
|
11
mesecons_autotools/fsm/lib.lua
Normal file
11
mesecons_autotools/fsm/lib.lua
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
function DeepCopy(Src)
|
||||||
|
local Dest = {}
|
||||||
|
if type(Src) ~= "table" then return Src end
|
||||||
|
for Key, Val in pairs(Src) do
|
||||||
|
|
||||||
|
Key = type(Key) == "table" and DeepCopy(Key) or Key
|
||||||
|
Val = type(Val) == "table" and DeepCopy(Val) or Val
|
||||||
|
Dest[Key] = Val
|
||||||
|
end
|
||||||
|
return Dest
|
||||||
|
end
|
113
mesecons_autotools/fsm/priority.lua
Normal file
113
mesecons_autotools/fsm/priority.lua
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
function pins_to_area(pins,defined_pins)
|
||||||
|
-- pins : list
|
||||||
|
|
||||||
|
local part = {}
|
||||||
|
for _,pin in pairs(pins) do
|
||||||
|
if is_negated(pin) then
|
||||||
|
part[drop_negation(pin)] = false
|
||||||
|
else
|
||||||
|
part[pin] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local parts = {}
|
||||||
|
table.insert(parts,part)
|
||||||
|
|
||||||
|
local area = {}
|
||||||
|
|
||||||
|
area.vars = defined_pins
|
||||||
|
area.parts = parts
|
||||||
|
|
||||||
|
return area
|
||||||
|
end
|
||||||
|
|
||||||
|
function part_to_pins(part)
|
||||||
|
local list = {}
|
||||||
|
for k,v in pairs(part) do
|
||||||
|
if v == true then
|
||||||
|
table.insert(list, k)
|
||||||
|
else
|
||||||
|
table.insert(list, add_negation(k))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return list
|
||||||
|
end
|
||||||
|
|
||||||
|
function apply_priority_state(list_ifs,defined_pins)
|
||||||
|
if list_ifs == nil then return nil end
|
||||||
|
if #list_ifs == 0 then return {} end
|
||||||
|
local new_ifs = {}
|
||||||
|
local aggreg_area = pins_to_area(list_ifs[1].pins,defined_pins)
|
||||||
|
|
||||||
|
table.insert(new_ifs,list_ifs[1])
|
||||||
|
|
||||||
|
for i=2,#list_ifs do
|
||||||
|
local curr_area = pins_to_area(list_ifs[i].pins,defined_pins)
|
||||||
|
local new_area = area_sub(curr_area,aggreg_area)
|
||||||
|
aggreg_area = area_add(aggreg_area,curr_area)
|
||||||
|
|
||||||
|
for _,part in pairs(new_area.parts) do
|
||||||
|
table.insert(new_ifs, { pins = part_to_pins(part), state = list_ifs[i].state })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return new_ifs
|
||||||
|
end
|
||||||
|
|
||||||
|
function apply_priority_special_case_no_input_pins(db)
|
||||||
|
-- no inputs, adding one phantom input
|
||||||
|
table.insert(db.inputs_used, "x")
|
||||||
|
apply_priority(db)
|
||||||
|
db.inputs_used = {}
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- changes db.trans
|
||||||
|
function apply_priority(db)
|
||||||
|
if db.inputs_used == nil then return end
|
||||||
|
if #db.inputs_used == 0 then
|
||||||
|
if count_hash(db.trans) == 0 then
|
||||||
|
return
|
||||||
|
else
|
||||||
|
apply_priority_special_case_no_input_pins(db)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local new_trans = {}
|
||||||
|
for state, v in pairs(db.trans) do
|
||||||
|
new_trans[state] = apply_priority_state(v, db.inputs_used)
|
||||||
|
end
|
||||||
|
db.trans = new_trans
|
||||||
|
end
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
-- other algorithms
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function clear_empty_transitions(db)
|
||||||
|
for state,ifs in pairs(db.trans) do
|
||||||
|
if #ifs == 0 then
|
||||||
|
db.trans[state] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
-- default behavior
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
function add_default_loops(db)
|
||||||
|
-- if no transition, stay in current state
|
||||||
|
local hreachables = db.reachables
|
||||||
|
for s,_ in pairs(hreachables) do
|
||||||
|
if db.trans[s] == nil then
|
||||||
|
db.trans[s] = {}
|
||||||
|
end
|
||||||
|
table.insert(db.trans[s], { pins = {} , state = s } )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
@ -310,6 +310,13 @@ dofile(minetest.get_modpath("mesecons_autotools").."/book/circuit.lua");
|
|||||||
--dofile(minetest.get_modpath("mesecons_autotools").."/book/library.lua");
|
--dofile(minetest.get_modpath("mesecons_autotools").."/book/library.lua");
|
||||||
dofile(minetest.get_modpath("mesecons_autotools").."/book/file.lua");
|
dofile(minetest.get_modpath("mesecons_autotools").."/book/file.lua");
|
||||||
|
|
||||||
|
-- Register FSM generator
|
||||||
|
dofile(minetest.get_modpath("mesecons_autotools").."/fsm/fsm.lua");
|
||||||
|
|
||||||
|
-- Register Formula generator
|
||||||
|
dofile(minetest.get_modpath("mesecons_autotools").."/formula/formula.lua");
|
||||||
|
|
||||||
|
|
||||||
-- Register chatcommands
|
-- Register chatcommands
|
||||||
|
|
||||||
dofile(minetest.get_modpath("mesecons_autotools").."/commands/all_commands.lua");
|
dofile(minetest.get_modpath("mesecons_autotools").."/commands/all_commands.lua");
|
||||||
|
BIN
mesecons_autotools/textures/formula_book.png
Normal file
BIN
mesecons_autotools/textures/formula_book.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
BIN
mesecons_autotools/textures/fsm_book.png
Normal file
BIN
mesecons_autotools/textures/fsm_book.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
BIN
mesecons_autotools/textures/fsm_book_empty.png
Normal file
BIN
mesecons_autotools/textures/fsm_book_empty.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
@ -39,7 +39,7 @@ dofile(minetest.get_modpath("mesecons_autotools").."/tools/bundle.lua");
|
|||||||
|
|
||||||
local tool_list = {
|
local tool_list = {
|
||||||
{"black", "Auto Wire Tool"},
|
{"black", "Auto Wire Tool"},
|
||||||
{"grey", "Auto crossing Tool"},
|
{"grey", "Auto crossing Tool"},
|
||||||
{"blue", "Selection Tool"},
|
{"blue", "Selection Tool"},
|
||||||
{"white_up", "Selection Top Edge Tool"},
|
{"white_up", "Selection Top Edge Tool"},
|
||||||
{"white_down", "Selection Bottom Edge Tool"},
|
{"white_down", "Selection Bottom Edge Tool"},
|
||||||
@ -50,6 +50,7 @@ local tool_list = {
|
|||||||
{"yellow", "Move Horizontal Tool"},
|
{"yellow", "Move Horizontal Tool"},
|
||||||
{"yellow_updown", "Move Vertical Tool"},
|
{"yellow_updown", "Move Vertical Tool"},
|
||||||
{"refresh", "Refresh Tool"},
|
{"refresh", "Refresh Tool"},
|
||||||
|
|
||||||
}
|
}
|
||||||
for _,t in pairs(tool_list) do
|
for _,t in pairs(tool_list) do
|
||||||
local tool = t[1]
|
local tool = t[1]
|
||||||
|
@ -51,7 +51,7 @@ mesecons_autotools.register_action("black","right","block", function(user,pos,ra
|
|||||||
mesecons_autotools.zero_stack_direction(user)
|
mesecons_autotools.zero_stack_direction(user)
|
||||||
elseif create_bundle_bended_wire(user,sel,pos,user_direction) then
|
elseif create_bundle_bended_wire(user,sel,pos,user_direction) then
|
||||||
-- nothing to do here so far
|
-- nothing to do here so far
|
||||||
-- update of new selection is inside the function
|
-- update of new selection if inside the function
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,23 +1,24 @@
|
|||||||
|
|
||||||
mesecons_autotools.register_action("test","left","air", function(user,pos,rad)
|
mesecons_autotools.register_action("test","left","air", function(user,pos,rad)
|
||||||
|
|
||||||
end)
|
end)
|
||||||
mesecons_autotools.register_action("test","left","block", function(user,pos,rad)
|
mesecons_autotools.register_action("test","left","block", function(user,pos,rad)
|
||||||
local node = minetest.get_node(pos)
|
local node = minetest.get_node(pos)
|
||||||
print ("rules[" .. dump(mesecon.get_any_rules(node)) .. "]" )
|
-- print ("rules[" .. dump(mesecon.get_any_rules(node)) .. "]" )
|
||||||
end)
|
print("node=" .. dump(minetest.get_node(pos) ))
|
||||||
|
print("meta=" ..dump(minetest.get_meta(pos):to_table() ) )
|
||||||
|
end)
|
||||||
|
|
||||||
mesecons_autotools.register_action("test","right","block", function(user,pos,rad)
|
mesecons_autotools.register_action("test","right","block", function(user,pos,rad)
|
||||||
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
mesecons_autotools.register_action("test","right","air", function(user,pos,rad)
|
mesecons_autotools.register_action("test","right","air", function(user,pos,rad)
|
||||||
local pos1 = mesecons_autotools.get_pos(user,1)
|
local pos1 = mesecons_autotools.get_pos(user,1)
|
||||||
local pos2 = mesecons_autotools.get_pos(user,2)
|
local pos2 = mesecons_autotools.get_pos(user,2)
|
||||||
|
|
||||||
print ("D=pos1="..dump(pos1) .. ", pos2="..dump(pos2))
|
|
||||||
end)
|
|
||||||
|
|
||||||
|
print ("D=pos1="..dump(pos1) .. ", pos2="..dump(pos2))
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2,3 +2,4 @@ name = mesecons_x
|
|||||||
title = Mesecons Extended
|
title = Mesecons Extended
|
||||||
author = marek
|
author = marek
|
||||||
description = Adds Latch, Flipflop, tools for automatic wireing, 3-input gates etc.
|
description = Adds Latch, Flipflop, tools for automatic wireing, 3-input gates etc.
|
||||||
|
release = 10474
|
||||||
|
Loading…
Reference in New Issue
Block a user