mirror of
https://gitlab.com/deetmit/mesecons_x.git
synced 2024-10-05 17:13:16 +02:00
add FSM generator (orange book)
This commit is contained in:
parent
909dc5715f
commit
7e77480fc7
@ -266,6 +266,62 @@ function flip(v)
|
||||
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)
|
||||
if sel.pos1 == nil then return end
|
||||
if sel.pos2 == nil then return end
|
||||
@ -311,7 +367,7 @@ function paste_circuit(sel,file,direction)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
]]--
|
||||
|
||||
|
||||
local function make_selection(user,file,direction,pos)
|
||||
|
@ -9,6 +9,15 @@ function generate_file_name(user)
|
||||
return file
|
||||
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)
|
||||
local days = minetest.get_day_count()
|
||||
local sec = minetest.get_gametime()
|
||||
|
@ -79,7 +79,6 @@ function traverse_list(list,action)
|
||||
if list == nil then return end
|
||||
|
||||
for _,v in ipairs(list) do
|
||||
print("traverser.id =" .. v.id)
|
||||
if v.type == "circuit" then
|
||||
action(v)
|
||||
elseif v.type == "library" then
|
||||
|
@ -281,6 +281,25 @@ function iterate_m3(m,action)
|
||||
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
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -51,7 +51,7 @@ end
|
||||
|
||||
|
||||
function rotate_node(node, saved_direction,direction)
|
||||
|
||||
if node == nil then return nil end
|
||||
local values =
|
||||
{
|
||||
{0,1,2,3},
|
||||
|
@ -1,4 +1,5 @@
|
||||
function is_gate(node)
|
||||
if node == nil then return false end
|
||||
local gates = {
|
||||
"mesecons_gates:and",
|
||||
"mesecons_gates:or",
|
||||
@ -39,6 +40,7 @@ function is_wire_node(node)
|
||||
"mesecons_morewires:xjunction_off", "mesecons_morewires:xjunction_on",
|
||||
}
|
||||
|
||||
if node == nil then return false end
|
||||
local pos_name = node.name
|
||||
for i,name in ipairs(list) do
|
||||
if name == pos_name then
|
||||
@ -54,6 +56,7 @@ end
|
||||
function get_stats(m)
|
||||
local blocks,gates,wires = 0,0,0
|
||||
iterate_m3(m, function(node)
|
||||
if node == nil then return end
|
||||
if is_wire_node(node) then
|
||||
wires = wires + 1
|
||||
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/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
|
||||
|
||||
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 |
@ -50,6 +50,7 @@ local tool_list = {
|
||||
{"yellow", "Move Horizontal Tool"},
|
||||
{"yellow_updown", "Move Vertical Tool"},
|
||||
{"refresh", "Refresh Tool"},
|
||||
|
||||
}
|
||||
for _,t in pairs(tool_list) do
|
||||
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)
|
||||
elseif create_bundle_bended_wire(user,sel,pos,user_direction) then
|
||||
-- nothing to do here so far
|
||||
-- update of new selection is inside the function
|
||||
-- update of new selection if inside the function
|
||||
end
|
||||
|
||||
|
||||
|
@ -4,7 +4,9 @@ mesecons_autotools.register_action("test","left","air", function(user,pos,rad)
|
||||
end)
|
||||
mesecons_autotools.register_action("test","left","block", function(user,pos,rad)
|
||||
local node = minetest.get_node(pos)
|
||||
print ("rules[" .. dump(mesecon.get_any_rules(node)) .. "]" )
|
||||
-- print ("rules[" .. dump(mesecon.get_any_rules(node)) .. "]" )
|
||||
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)
|
||||
@ -20,4 +22,3 @@ end)
|
||||
|
||||
|
||||
|
||||
|
@ -2,3 +2,4 @@ name = mesecons_x
|
||||
title = Mesecons Extended
|
||||
author = marek
|
||||
description = Adds Latch, Flipflop, tools for automatic wireing, 3-input gates etc.
|
||||
release = 10474
|
||||
|
Loading…
Reference in New Issue
Block a user