lua-logic/sim/group.lua
2021-05-25 17:18:57 -05:00

212 lines
4.1 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(self)
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,
}
setmetatable(o, self)
self.__index = self
return o
end
function Group.getsize(self)
return self.nwires + self.nout_ports + self.nin_ports
end
function Group.addwire(self, wire)
if Wire.getgroup(wire) ~= self then
if Wire.getgroup(wire) ~= nil then
Group.mergewith(self, Wire.getgroup(wire))
else
self.wires[wire] = wire
self.nwires = self.nwires + 1
Wire.setgroup(wire, self)
Wire.update(wire)
Simulation.queuegroup(GSim, self)
end
end
end
function Group.removewire(self, wire)
Wire.setgroup(wire, nil)
self.wires[wire] = nil
local sim = GSim
for k, wire in pairs(self.wires) do
Wire.setgroup(wire, nil)
end
for k, port in pairs(self.out_ports) do
Port.setgroup(port, nil)
end
for k, port in pairs(self.in_ports) do
Port.setgroup(port, nil)
end
for k, wire in pairs(self.wires) do
Simulation.connectwire(sim, wire)
end
for k, port in pairs(self.out_ports) do
Simulation.connectport(sim, port)
end
for k, port in pairs(self.in_ports) do
Simulation.connectport(sim, port)
end
self.wires = {}
self.out_ports = {}
self.in_ports = {}
self.nwires = 0
self.nout_ports = 0
self.nin_ports = 0
Simulation.dequeuegroup(GSim, self)
end
function Group.addport(self, port)
if port.group~=nil then error("port already has group") end
port.group = self
if port.type == PortTypes.output then
if self.out_ports[port] then error("port already in group") end
self.out_ports[port] = port
self.nout_ports = self.nout_ports + 1
if Port.getstate(port) then
self.state_num = self.state_num + 1
end
Simulation.queuegroup(GSim, self)
elseif port.type == PortTypes.input then
if self.in_ports[port] then error("port already in group") end
self.in_ports[port] = port
self.nin_ports = self.nin_ports + 1
if port.causeupdate then
table.insert(self.in_ports_update, port)
end
Simulation.queuegate(GSim, Port.getgate(port))
end
end
function Group.removeport(self, port)
if port.group~=self then error("port does not have group") end
port.group = nil
if port.type == PortTypes.output then
if not self.out_ports[port] then error("port not in group") end
self.out_ports[port] = nil
self.nout_ports = self.nout_ports - 1
if Port.getstate(port) then
self.state_num = self.state_num - 1
end
Simulation.queuegroup(GSim, self)
elseif port.type == PortTypes.input then
if not self.in_ports[port] then error("port not in group") end
self.in_ports[port] = nil
self.nin_ports = self.nin_ports - 1
if port.causeupdate then
array_remove(self.in_ports_update, port)
end
Simulation.queuegate(GSim, Port.getgate(port))
end
end
function Group.mergewith(self, group)
if Group.getsize(self) >= Group.getsize(group) then
Group.mergeinto(group, self)
return self
else
Group.mergeinto(self, group)
return group
end
end
function Group.mergeinto(self, group)
for k, wire in pairs(self.wires) do
Wire.setgroup(wire, nil)
Group.addwire(group, wire)
end
for k, port in pairs(self.out_ports) do
Port.setgroup(port, nil)
Group.addport(group, port)
end
for k, port in pairs(self.in_ports) do
Port.setgroup(port, nil)
Group.addport(group, port)
end
self.wires = {}
self.out_ports = {}
self.in_ports = {}
self.nwires = 0
self.nout_ports = 0
self.nin_ports = 0
Simulation.dequeuegroup(GSim, self)
end
function Group.setstate(self, state)
if state ~= self.state then
local sim = GSim
self.state = state
self.updatetick = sim.currenttick
for k, port in ipairs(self.in_ports_update) do
Simulation.queuegate(sim, Port.getgate(port))
end
Simulation.queuegroupfx(sim, self)
end
end
function Group.update(group)
Group.setstate(group, group.state_num>0)
end