251 lines
5.4 KiB
Lua
251 lines
5.4 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.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 = ffi.cast("struct Gate**", 0)
|
|
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_c(netc, tick)
|
|
local state = netc.state_num[0]>0 and 1 or 0
|
|
if state ~= netc.state[0] then
|
|
netc.state[0] = state
|
|
netc.update_tick[0] = tick
|
|
|
|
local len = netc.num_gates_update[0]
|
|
for i = 1, len do
|
|
local gatec = netc.gates_update_c[i]
|
|
if gatec and gatec.in_queue[0]==0 then
|
|
Simulation.queue_gate_c(GSim, gatec)
|
|
end
|
|
end
|
|
|
|
local net = Simulation.net_from_netc(GSim, netc)
|
|
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]).."]")
|
|
for i = 0, net.num_gates_update[0]-1 do
|
|
net.gates_update_c[i] = net.gates_update[i+1].c
|
|
end
|
|
end
|