require "set" module Lace class Netlist attr_reader :components attr_reader :nets def initialize(&p) @components = {} @nets = {} edit(&p) if p end def definitive_net(n) nn = @nets[n.object_id] return n if nn.object_id == n.object_id return definitive_net(nn) end def merge_nets(a, b) da = definitive_net(a) db = definitive_net(b) return da if da.object_id == db.object_id into = @nets[[da.object_id, db.object_id].min] if da.name raise "Nets #{into.name} and #{da.name} merged!" if into.name and into.name != da.name into.name = da.name end if db.name raise "Nets #{into.name} and #{db.name} merged!" if into.name and into.name != db.name into.name = db.name end @nets.each do | id, n | dn = definitive_net(n) if dn.object_id != into.object_id and (dn.object_id == da.object_id or dn.object_id == db.object_id) @nets[id] = into end end return into end def edit(&p) instance_eval &p end def comp(*args) c = Component.new(self, *args) @components[c.object_id] = c return c end def net(*args) n = Net.new(self, *args) @nets[n.object_id] = n return n end def pair(left, right) x = Wireable.new(self, left, right) return x end def real_refs refs = {} counters = {} seen = Set.new @components.each do | id, comp | next if seen.member?(comp.object_id) seen.add(comp.object_id) counter = counters[comp.refbase] || 1 counters[comp.refbase] = counter + 1 ref = "#{comp.refbase}#{counter}" refs[ref] = comp end return refs end def real_nets(refs) n = 1 nets = {} seen = Set.new @nets.each do | id, net | next if seen.member?(net.object_id) seen.add(net.object_id) name = net.name unless name name = "$unnamed#{n}" n += 1 end raise "Multiple disconnected nets named #{name}" if nets.member?(name) nodes = [] refs.each do | ref, comp | comp.pins.each do | pin, pinnet | nodes << {:ref => ref, :pin => pin} if definitive_net(pinnet).object_id == net.object_id end end nets[name] = nodes if nodes.size > 1 end return nets end def real refs = real_refs nets = real_nets(refs) return [refs, nets] end def kicad(stream=$stdout) refs, nets = real stream.write(<