448 lines
11 KiB
Lua
448 lines
11 KiB
Lua
|
|
local ffi = FFI or require("ffi")
|
|
|
|
ffi.cdef [[
|
|
struct Gate;
|
|
struct Net;
|
|
void sim_set_data(struct Net** net_queue, int* num_net_queue, struct Gate** gate_queue, int* num_gate_queue, int* current_tick, int queue_max);
|
|
void sim_update_nets();
|
|
void sim_update_gates();
|
|
]]
|
|
local csim = ffi.load("./compiled_sim.dll")
|
|
|
|
Simulation = {}
|
|
|
|
local queue_max = 65536
|
|
|
|
function Simulation.new(sim)
|
|
local o = {
|
|
-- Logic Critical
|
|
groupqueue = ffi.new("struct Net*["..queue_max.."]"),
|
|
num_groupqueue = ffi.new("int[1]"),
|
|
gatequeue = ffi.new("struct Gate*["..queue_max.."]"),
|
|
num_gatequeue = ffi.new("int[1]"),
|
|
current_tick = ffi.new("int[1]"),
|
|
--groupfxqueue = {},
|
|
|
|
definitions = {},
|
|
wires = {},
|
|
gates = {},
|
|
nets = {},
|
|
nwires = 0,
|
|
ngates = 0,
|
|
ninports = 0,
|
|
noutports = 0,
|
|
|
|
initqueue = nil,
|
|
inputqueue = nil,
|
|
tickqueue = {},
|
|
callbacks = nil,
|
|
}
|
|
setmetatable(o, sim)
|
|
sim.__index = sim
|
|
o.num_groupqueue[0] = 0
|
|
o.num_gatequeue[0] = 0
|
|
o.current_tick[0] = 0
|
|
csim.sim_set_data(o.groupqueue, o.num_groupqueue, o.gatequeue, o.num_gatequeue, o.current_tick, queue_max)
|
|
return o
|
|
end
|
|
|
|
function Simulation.addtoworld(sim, obj, x, y, z)
|
|
if sim[x] == nil then
|
|
sim[x] = {}
|
|
end
|
|
|
|
if sim[x][y] == nil then
|
|
sim[x][y] = {}
|
|
end
|
|
|
|
if sim[x][y][z] == nil then
|
|
sim[x][y][z] = {}
|
|
end
|
|
|
|
sim[x][y][z][obj] = obj
|
|
end
|
|
|
|
function Simulation.getfromworld(sim, x, y, z)
|
|
if sim[x] == nil or sim[x][y] == nil or sim[x][y][z] == nil then
|
|
return {}
|
|
else
|
|
return sim[x][y][z]
|
|
end
|
|
end
|
|
|
|
function Simulation.getdefinitionbyref(sim, objref)
|
|
return sim.definitions[objref]
|
|
end
|
|
|
|
function Simulation.getgatebyref(sim, objref)
|
|
return sim.gates[objref]
|
|
end
|
|
|
|
function Simulation.getwirebyref(sim, objref)
|
|
return sim.wires[objref]
|
|
end
|
|
|
|
function Simulation.addgatedefinition(sim, definition)
|
|
sim.definitions[definition.objref] = definition
|
|
end
|
|
|
|
function Simulation.addwire(sim, wire)
|
|
sim.wires[Wire.getobjref(wire)] = wire
|
|
|
|
local bounds = Wire.getbounds(wire)
|
|
|
|
for x = bounds[1]+1, bounds[4]-1, 2 do
|
|
for z = bounds[3]+1, bounds[6]-1, 2 do
|
|
Simulation.addtoworld(sim, wire, x, bounds[2], z)
|
|
Simulation.addtoworld(sim, wire, x, bounds[5], z)
|
|
end
|
|
end
|
|
|
|
for y = bounds[2]+1, bounds[5]-1, 2 do
|
|
for z = bounds[3]+1, bounds[6]-1, 2 do
|
|
Simulation.addtoworld(sim, wire, bounds[1], y, z)
|
|
Simulation.addtoworld(sim, wire, bounds[4], y, z)
|
|
end
|
|
end
|
|
|
|
for x = bounds[1]+1, bounds[4]-1, 2 do
|
|
for y = bounds[2]+1, bounds[5]-1, 2 do
|
|
Simulation.addtoworld(sim, wire, x, y, bounds[3])
|
|
Simulation.addtoworld(sim, wire, x, y, bounds[6])
|
|
end
|
|
end
|
|
|
|
sim.nwires = sim.nwires + 1
|
|
Simulation.connectwire(sim, wire)
|
|
end
|
|
|
|
function Simulation.addgate(sim, gate)
|
|
sim.gates[gate.objref] = gate
|
|
|
|
for k, port in pairs(gate.ports) do
|
|
local offset = Port.getconnectionposition(port)
|
|
Simulation.addtoworld(sim, port, offset[1], offset[2], offset[3])
|
|
Simulation.connectport(sim, port)
|
|
|
|
if Port.gettype(port) == PortTypes.input then
|
|
sim.ninports = sim.ninports + 1
|
|
elseif Port.gettype(port) == PortTypes.output then
|
|
sim.noutports = sim.noutports + 1
|
|
end
|
|
end
|
|
|
|
sim.ngates = sim.ngates + 1
|
|
|
|
Gate.preinit(gate)
|
|
Simulation.queuegateinit(sim, gate)
|
|
Simulation.queuegate_safe(sim, gate)
|
|
end
|
|
|
|
function Simulation.removewire(sim, objref)
|
|
local wire = sim.wires[objref]
|
|
if wire ~= nil then
|
|
sim.wires[objref] = nil
|
|
|
|
local bounds = Wire.getbounds(wire)
|
|
|
|
for x = bounds[1]+1, bounds[4]-1, 2 do
|
|
for z = bounds[3]+1, bounds[6]-1, 2 do
|
|
sim[x][bounds[2]][z][wire] = nil
|
|
sim[x][bounds[5]][z][wire] = nil
|
|
end
|
|
end
|
|
|
|
for y = bounds[2]+1, bounds[5]-1, 2 do
|
|
for z = bounds[3]+1, bounds[6]-1, 2 do
|
|
sim[bounds[1]][y][z][wire] = nil
|
|
sim[bounds[4]][y][z][wire] = nil
|
|
end
|
|
end
|
|
|
|
for x = bounds[1]+1, bounds[4]-1, 2 do
|
|
for y = bounds[2]+1, bounds[5]-1, 2 do
|
|
sim[x][y][bounds[3]][wire] = nil
|
|
sim[x][y][bounds[6]][wire] = nil
|
|
end
|
|
end
|
|
|
|
sim.nwires = sim.nwires - 1
|
|
Group.removewire(Wire.getgroup(wire), wire)
|
|
end
|
|
end
|
|
|
|
function Simulation.removegate(sim, objref)
|
|
local gate = sim.gates[objref]
|
|
if gate ~= nil then
|
|
for k, port in pairs(gate.ports) do
|
|
local pos = Port.getconnectionposition(port)
|
|
sim[pos[1]][pos[2]][pos[3]][port] = nil
|
|
Group.removeport(Port.getgroup(port), port)
|
|
|
|
if Port.gettype(port) == PortTypes.input then
|
|
sim.ninports = sim.ninports - 1
|
|
elseif Port.gettype(port) == PortTypes.output then
|
|
sim.noutports = sim.noutports - 1
|
|
end
|
|
end
|
|
end
|
|
|
|
Simulation.dequeuegate(sim, gate)
|
|
sim.gates[objref] = nil
|
|
sim.ngates = sim.ngates - 1
|
|
end
|
|
|
|
local function is_wire(obj)
|
|
return obj.layer~=nil
|
|
end
|
|
|
|
function Simulation.connectwireat(sim, wire, x, y, z)
|
|
local objs = Simulation.getfromworld(sim, x, y, z)
|
|
for k, obj in pairs(objs) do
|
|
if obj ~= wire and obj.group ~= nil then
|
|
if is_wire(obj) then -- wire
|
|
local layer1 = Wire.getlayer(wire)
|
|
local layer2 = Wire.getlayer(obj)
|
|
--if they are on the same real layer, or exactly one is rainbow but not both, then connect
|
|
if ((layer1==layer2) or (layer1==-1 and layer2~=-1) or (layer1~=-1 and layer2==-1)) and (not (layer1==-1 and layer2==-1)) then
|
|
Group.addwire(obj.group, wire)
|
|
end
|
|
else -- port
|
|
Group.addwire(obj.group, wire)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function Simulation.connectwire(sim, wire)
|
|
local bounds = Wire.getbounds(wire)
|
|
|
|
for x = bounds[1]+1, bounds[4]-1, 2 do
|
|
for z = bounds[3]+1, bounds[6]-1, 2 do
|
|
Simulation.connectwireat(sim, wire, x, bounds[2], z)
|
|
Simulation.connectwireat(sim, wire, x, bounds[5], z)
|
|
end
|
|
end
|
|
|
|
for y = bounds[2]+1, bounds[5]-1, 2 do
|
|
for z = bounds[3]+1, bounds[6]-1, 2 do
|
|
Simulation.connectwireat(sim, wire, bounds[1], y, z)
|
|
Simulation.connectwireat(sim, wire, bounds[4], y, z)
|
|
end
|
|
end
|
|
|
|
for x = bounds[1]+1, bounds[4]-1, 2 do
|
|
for y = bounds[2]+1, bounds[5]-1, 2 do
|
|
Simulation.connectwireat(sim, wire, x, y, bounds[3])
|
|
Simulation.connectwireat(sim, wire, x, y, bounds[6])
|
|
end
|
|
end
|
|
|
|
if Wire.getgroup(wire)==nil then
|
|
local newnet = Group.new()
|
|
Simulation.add_net(sim, newnet)
|
|
Group.addwire(newnet, wire)
|
|
end
|
|
end
|
|
|
|
function Simulation.connectport(sim, port)
|
|
local connpos = Port.getconnectionposition(port)
|
|
local objs = Simulation.getfromworld(sim, connpos[1], connpos[2], connpos[3])
|
|
for k, obj in pairs(objs) do
|
|
if obj ~= port and obj.group ~= nil then
|
|
Group.addport(obj.group, port)
|
|
end
|
|
end
|
|
|
|
if Port.getgroup(port) == nil then
|
|
local newnet = Group.new()
|
|
Simulation.add_net(sim, newnet)
|
|
Group.addport(newnet, port)
|
|
end
|
|
end
|
|
|
|
-- Logic Critical
|
|
function Simulation.queuegate_c(sim, cgate)
|
|
assert(sim.num_gatequeue[0] < queue_max-1)
|
|
sim.gatequeue[sim.num_gatequeue[0]] = cgate
|
|
sim.num_gatequeue[0] = sim.num_gatequeue[0] + 1
|
|
cgate.in_queue[0] = 1
|
|
end
|
|
|
|
function Simulation.queuegate(sim, gate)
|
|
local cgate = gate.c
|
|
Simulation.queuegate_c(sim, cgate)
|
|
end
|
|
|
|
function Simulation.queuegate_safe(sim, gate)
|
|
if gate.in_queue[0]==0 then
|
|
Simulation.queuegate(sim, gate)
|
|
end
|
|
end
|
|
|
|
-- Logic Critical
|
|
function Simulation.queuegatelater(sim, gate, delay)
|
|
local tick = sim.current_tick[0] + delay
|
|
if sim.tickqueue[tick] == nil then
|
|
sim.tickqueue[tick] = {}
|
|
end
|
|
sim.tickqueue[tick][gate] = gate
|
|
end
|
|
|
|
function Simulation.queuegateinput(sim, gate, argv)
|
|
sim.inputqueue = sim.inputqueue or {}
|
|
sim.inputqueue[gate] = sim.inputqueue[gate] or {}
|
|
table.insert(sim.inputqueue[gate], argv)
|
|
end
|
|
|
|
function Simulation.queuegateinit(sim, gate)
|
|
sim.initqueue = sim.initqueue or {}
|
|
sim.initqueue[gate] = gate
|
|
end
|
|
|
|
-- Logic Critical
|
|
function Simulation.queuegroup_c(sim, cnet)
|
|
assert(sim.num_groupqueue[0] < queue_max-1)
|
|
sim.groupqueue[sim.num_groupqueue[0]] = cnet
|
|
sim.num_groupqueue[0] = sim.num_groupqueue[0] + 1
|
|
cnet.in_queue[0] = 1
|
|
end
|
|
|
|
function Simulation.queuegroup(sim, net)
|
|
local cnet = net.c
|
|
Simulation.queuegroup_c(sim, cnet)
|
|
end
|
|
|
|
function Simulation.queuegroup_safe(sim, group)
|
|
if group.in_queue[0]==0 then
|
|
Simulation.queuegroup(sim, group)
|
|
end
|
|
end
|
|
|
|
function Simulation.dequeuegroup(sim, group)
|
|
if group.in_queue[0]~=0 then
|
|
sim.num_groupqueue[0] = array_remove(sim.groupqueue, sim.num_groupqueue[0], group.c, true)
|
|
group.in_queue[0] = 0
|
|
end
|
|
--sim.groupfxqueue[group] = nil
|
|
end
|
|
|
|
function Simulation.dequeuegate(sim, gate)
|
|
if gate.in_queue[0]~=0 then
|
|
sim.num_gatequeue[0] = array_remove(sim.gatequeue, sim.num_gatequeue[0], gate.c, true)
|
|
gate.in_queue[0] = 0
|
|
end
|
|
if sim.inputqueue~=nil then sim.inputqueue[gate] = nil end
|
|
if sim.initqueue ~=nil then sim.initqueue [gate] = nil end
|
|
for tick, tickq in pairs(sim.tickqueue) do
|
|
tickq[gate] = nil
|
|
end
|
|
end
|
|
|
|
--function Simulation.queuegroupfx(sim, group)
|
|
-- sim.groupfxqueue[group] = group
|
|
--end
|
|
|
|
function Simulation.queuecallback(sim, gate, ...)
|
|
sim.callbacks = sim.callbacks or {}
|
|
sim.callbacks[gate.objref] = {...}
|
|
end
|
|
|
|
-- Logic Critical
|
|
function Simulation.ticklogic(sim)
|
|
csim.sim_update_nets()
|
|
|
|
if sim.tickqueue[sim.current_tick[0]] ~= nil then
|
|
for i, gate in pairs(sim.tickqueue[sim.current_tick[0]]) do
|
|
if gate.in_queue[0]==0 then
|
|
Simulation.queuegate(sim, gate)
|
|
end
|
|
end
|
|
sim.tickqueue[sim.current_tick[0]] = nil
|
|
end
|
|
|
|
csim.sim_update_gates() -- handle any leftover gates, those without c logic functions
|
|
for i = 0, sim.num_gatequeue[0]-1 do
|
|
local cgate = sim.gatequeue[i]
|
|
local gate = Simulation.gate_from_cgate(sim, cgate)
|
|
gate.logic(gate)
|
|
cgate.in_queue[0] = 0
|
|
sim.gatequeue[i] = nil
|
|
end
|
|
sim.num_gatequeue[0] = 0
|
|
|
|
sim.current_tick[0] = sim.current_tick[0] + 1
|
|
end
|
|
|
|
function Simulation.tickinit(sim)
|
|
if sim.initqueue ~= nil then
|
|
for k, gate in pairs(sim.initqueue) do
|
|
Gate.init(gate)
|
|
end
|
|
sim.initqueue = nil
|
|
end
|
|
end
|
|
|
|
function Simulation.tickinput(sim)
|
|
if sim.inputqueue ~= nil then
|
|
for gate, inputs in pairs(sim.inputqueue) do
|
|
for k, argv in ipairs(inputs) do
|
|
Gate.input(gate, argv)
|
|
end
|
|
end
|
|
sim.inputqueue = nil
|
|
end
|
|
end
|
|
|
|
function Simulation.sendfxupdate(sim)
|
|
--for k, group in pairs(sim.groupfxqueue) do
|
|
for k, group in pairs(sim.nets) do
|
|
if group.state[0] ~= group.fxstate then
|
|
group.fxstate = group.state[0]
|
|
|
|
local data = group.state[0]
|
|
|
|
for i, wire in pairs(group.wires) do
|
|
data = data .. "\t" .. Wire.getobjref(wire)
|
|
end
|
|
|
|
network_send("WU\t" .. data .. "\n")
|
|
end
|
|
end
|
|
|
|
--sim.groupfxqueue = {}
|
|
end
|
|
|
|
function Simulation.sendcallbacks(sim)
|
|
if sim.callbacks ~= nil then
|
|
local data = "CB"
|
|
|
|
for objref, args in pairs(sim.callbacks) do
|
|
local escargs = {}
|
|
for argidx, argv in ipairs(args) do
|
|
table.insert(escargs, expandescape(tostring(argv)))
|
|
end
|
|
data = data .. "\t" .. objref .. "\t"..(#escargs)..(#escargs>0 and ("\t"..table.concat(escargs, "\t")) or "")
|
|
end
|
|
|
|
network_send(data .. "\n")
|
|
sim.callbacks = nil
|
|
end
|
|
end
|
|
|
|
function Simulation.add_net(sim, net)
|
|
sim.nets[net.id] = net
|
|
end
|
|
function Simulation.remove_net(sim, net)
|
|
sim.nets[net.id] = nil
|
|
end
|
|
|
|
function Simulation.net_from_cnet(sim, cnet)
|
|
return sim.nets[cnet.id] or error("no net for id "..cnet.id)
|
|
end
|
|
|
|
function Simulation.gate_from_cgate(sim, cgate)
|
|
return sim.gates[cgate.objref] or error("no gate for objref "..cgate.objref)
|
|
end
|