lua-logic/sim/group.lua
2021-05-25 17:28:54 -05:00

210 lines
4.2 KiB
Lua

Group = {}
FFI.cdef[[
struct Port;
struct Net {
bool state;
bool fxstate;
bool in_queue;
int updatetick;
int internal_ref;
int state_num;
int num_in_ports_update;
struct Port* in_ports_update[1];
};
]]
function Group.new()
local o = {
state = false,
fxstate = false,
updatetick = 0,
wires = {},
out_ports = {},
in_ports = {},
in_ports_update = {},
state_num = 0,
in_queue = false,
nwires = 0,
nout_ports = 0,
nin_ports = 0,
}
return o
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(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.dequeuegroup(GSim, group)
end
function Group.addport(group, port)
if port.group~=nil then error("port already has group") end
port.group = 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
if Port.getstate(port) then
group.state_num = group.state_num + 1
end
Simulation.queuegroup(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
if port.causeupdate then
table.insert(group.in_ports_update, port)
end
Simulation.queuegate(GSim, Port.getgate(port))
end
end
function Group.removeport(group, port)
if port.group~=group then error("port does not have group") end
port.group = 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
if Port.getstate(port) then
group.state_num = group.state_num - 1
end
Simulation.queuegroup(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
if port.causeupdate then
array_remove(group.in_ports_update, port)
end
Simulation.queuegate(GSim, Port.getgate(port))
end
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.dequeuegroup(GSim, group)
end
function Group.setstate(group, state)
if state ~= group.state then
local sim = GSim
group.state = state
group.updatetick = sim.currenttick
for k, port in ipairs(group.in_ports_update) do
Simulation.queuegate(sim, Port.getgate(port))
end
Simulation.queuegroupfx(sim, group)
end
end
function Group.update(group)
Group.setstate(group, group.state_num>0)
end