lua-logic/sim/group.lua
2022-11-04 18:07:17 -06:00

255 lines
5.5 KiB
Lua

local ffi = FFI or require("ffi")
Group = {}
ffi.cdef [[
struct Gate;
struct Net {
int* state;
int* state_num;
int* in_queue;
int* update_tick;
int* num_gates_update;
struct Gate** gates_update_c;
int id;
};
]]
local last_net_id = 1
function Group.new()
local net = {
-- Logic Critical
state = ffi.new("int[1]"),
state_num = ffi.new("int[1]"),
in_queue = ffi.new("int[1]"),
update_tick = ffi.new("int[1]"),
gates_update = {},
num_gates_update = ffi.new("int[1]"),
gates_update_c = nil,
fxstate = 0,
wires = {},
out_ports = {},
in_ports = {},
nwires = 0,
nout_ports = 0,
nin_ports = 0,
id = last_net_id,
}
last_net_id = last_net_id + 1
net.state[0] = 0
net.state_num[0] = 0
net.in_queue[0] = 0
net.update_tick[0] = 0
net.gates_update_c = ffi.cast("struct Gate**", 0)
net.c = ffi.new("struct Net")
net.c.state = net.state
net.c.state_num = net.state_num
net.c.in_queue = net.in_queue
net.c.update_tick = net.update_tick
net.c.num_gates_update = net.num_gates_update
net.c.gates_update_c = net.gates_update_c
net.c.id = net.id
return net
end
function Group.getsize(group)
return group.nwires + group.nout_ports + group.nin_ports
end
function Group.addwire(group, wire)
if Wire.getgroup(wire) ~= group then
if Wire.getgroup(wire) ~= nil then
Group.mergewith(group, Wire.getgroup(wire))
else
group.wires[wire] = wire
group.nwires = group.nwires + 1
Wire.setgroup(wire, group)
Wire.update(wire)
Simulation.queuegroup_safe(GSim, group)
end
end
end
function Group.removewire(group, wire)
Wire.setgroup(wire, nil)
group.wires[wire] = nil
local sim = GSim
for k, wire in pairs(group.wires) do
Wire.setgroup(wire, nil)
end
for k, port in pairs(group.out_ports) do
Port.setgroup(port, nil)
end
for k, port in pairs(group.in_ports) do
Port.setgroup(port, nil)
end
for k, wire in pairs(group.wires) do
Simulation.connectwire(sim, wire)
end
for k, port in pairs(group.out_ports) do
Simulation.connectport(sim, port)
end
for k, port in pairs(group.in_ports) do
Simulation.connectport(sim, port)
end
group.wires = {}
group.out_ports = {}
group.in_ports = {}
group.nwires = 0
group.nout_ports = 0
group.nin_ports = 0
Simulation.remove_net(GSim, group)
Simulation.dequeuegroup(GSim, group)
end
function Group.addport(group, port)
if port.group~=nil then error("port already has group") end
Port.setgroup(port, group)
if port.type == PortTypes.output then
if group.out_ports[port] then error("port already in group") end
group.out_ports[port] = port
group.nout_ports = group.nout_ports + 1
group.state_num[0] = group.state_num[0] + Port.getstate(port)
Simulation.queuegroup_safe(GSim, group)
elseif port.type == PortTypes.input then
if group.in_ports[port] then error("port already in group") end
group.in_ports[port] = port
group.nin_ports = group.nin_ports + 1
Simulation.queuegate_safe(GSim, Port.getgate(port))
end
Group.rebuild_ports(group)
end
function Group.removeport(group, port)
if port.group~=group then error("port does not have group") end
Port.setgroup(port, nil)
if port.type == PortTypes.output then
if not group.out_ports[port] then error("port not in group") end
group.out_ports[port] = nil
group.nout_ports = group.nout_ports - 1
group.state_num[0] = group.state_num[0] - Port.getstate(port)
Simulation.queuegroup_safe(GSim, group)
elseif port.type == PortTypes.input then
if not group.in_ports[port] then error("port not in group") end
group.in_ports[port] = nil
group.nin_ports = group.nin_ports - 1
Simulation.queuegate_safe(GSim, Port.getgate(port))
end
Group.rebuild_ports(group)
end
function Group.mergewith(group, group2)
if Group.getsize(group) >= Group.getsize(group2) then
Group.mergeinto(group2, group)
return group
else
Group.mergeinto(group, group2)
return group2
end
end
function Group.mergeinto(group, group2)
for k, wire in pairs(group.wires) do
Wire.setgroup(wire, nil)
Group.addwire(group2, wire)
end
for k, port in pairs(group.out_ports) do
Port.setgroup(port, nil)
Group.addport(group2, port)
end
for k, port in pairs(group.in_ports) do
Port.setgroup(port, nil)
Group.addport(group2, port)
end
group.wires = {}
group.out_ports = {}
group.in_ports = {}
group.nwires = 0
group.nout_ports = 0
group.nin_ports = 0
Simulation.remove_net(GSim, group)
Simulation.dequeuegroup(GSim, group)
end
-- Logic Critical
function Group.update(net, tick)
local cnet = net.c
local state = cnet.state_num[0]>0 and 1 or 0
if state ~= cnet.state[0] then
cnet.state[0] = state
cnet.update_tick[0] = tick
local len = cnet.num_gates_update[0]-1
for i = 0, len do
local cgate = cnet.gates_update_c[i]
if cgate.in_queue[0]==0 then
local gate = Simulation.gate_from_cgate(GSim, cgate)
Simulation.queuegate(GSim, gate)
end
end
--Simulation.queuegroupfx(GSim, net)
end
end
function Group.rebuild_ports(net)
net.gates_update = {}
net.num_gates_update[0] = 0
local gates_seen = {}
for k, port in pairs(net.in_ports) do
if port.causeupdate then
local gate = Port.getgate(port)
if not gates_seen[gate] then
gates_seen[gate] = true
net.gates_update[net.num_gates_update[0]+1] = gate
net.num_gates_update[0] = net.num_gates_update[0] + 1
end
end
end
net.gates_update_c = ffi.new("struct Gate*["..(net.num_gates_update[0]+1).."]")
for i = 0, net.num_gates_update[0]-1 do
net.gates_update_c[i] = net.gates_update[i+1].c
end
net.c.gates_update_c = net.gates_update_c
end