Merge branch 'master' of github.com:pjht/rcircuit
This commit is contained in:
commit
370672e25e
106
lib/rcircuit/vcd.rb
Normal file
106
lib/rcircuit/vcd.rb
Normal file
@ -0,0 +1,106 @@
|
||||
# creates VCD file from port states
|
||||
|
||||
require "set"
|
||||
|
||||
def create_vcd_id(index)
|
||||
#VCD uses short id codes for signals.
|
||||
#Generate a unique id given a numeric index, 'a' to 'z'
|
||||
#then 'aa', ab',...
|
||||
new_id = ""
|
||||
loop do
|
||||
new_id = ('a'.ord + index%26).chr + new_id
|
||||
index = (index - index%26)
|
||||
break if index < 1
|
||||
index = index / 26 - 1
|
||||
end
|
||||
return new_id
|
||||
end
|
||||
|
||||
def test_vcd_id
|
||||
[0, 1, 25, 26, 30, 26*26-1, 26*26, 27*26, 27*26+1].each do |i|
|
||||
puts "#{i} -> #{create_vcd_id(i)}"
|
||||
end
|
||||
end
|
||||
|
||||
#test_vcd_id()
|
||||
|
||||
class VCD
|
||||
def initialize(filename, timescale="1ps")
|
||||
@fd = File.open(filename, 'w')
|
||||
@time=0
|
||||
@id_index = 0
|
||||
@changeset = Set.new()
|
||||
@timescale = timescale
|
||||
@portmap = {}
|
||||
@idmap = {}
|
||||
write_header
|
||||
end
|
||||
|
||||
def start
|
||||
@portmap.keys.each do |portname|
|
||||
port = @portmap[portname]
|
||||
id = @idmap[portname]
|
||||
@fd.write("$var wire #{port.width} #{id} #{portname} $end\n")
|
||||
end
|
||||
@fd.write("$dumpvars\n")
|
||||
@portmap.keys.each do |portname|
|
||||
write_port_state(portname)
|
||||
end
|
||||
@fd.write("$end\n")
|
||||
@fd.write("\#0\n")
|
||||
return self
|
||||
end
|
||||
|
||||
def finish
|
||||
@fd.close
|
||||
end
|
||||
|
||||
def attach(port, portname=nil)
|
||||
if portname == nil
|
||||
portname = port.to_s
|
||||
end
|
||||
raise RunTimeError.new("Duplicate port name '#{portname}'") if @portmap.has_key?(portname)
|
||||
@idmap[portname] = create_vcd_id(@id_index)
|
||||
@id_index += 1
|
||||
@portmap[portname] = port
|
||||
port.add_callback do |value|
|
||||
@changeset.add(portname)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
def advance(timesteps)
|
||||
@time += timesteps
|
||||
@fd.write("\##{@time.to_s}\n")
|
||||
return self
|
||||
end
|
||||
|
||||
def write
|
||||
#write out any changes and clear the changed set
|
||||
@changeset.each do |portname|
|
||||
write_port_state(portname)
|
||||
end
|
||||
@changeset.clear
|
||||
end
|
||||
|
||||
def write_header
|
||||
@fd.write("$date\n#{Time.now.asctime}\n$end\n")
|
||||
@fd.write("$version\nRCircuit VCD Generator Version 0.0\n$end\n")
|
||||
@fd.write("$timescale #{@timescale} $end\n")
|
||||
end
|
||||
|
||||
def write_port_state(portname)
|
||||
#writes VCD line for state of port, using id
|
||||
port = @portmap[portname]
|
||||
if port.width == 1
|
||||
state = port.val.to_s
|
||||
else
|
||||
state = "b#{port.val.to_s(2)} " #include a space
|
||||
end
|
||||
@fd.write(state + @idmap[portname] + "\n")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
27
vcd_test.rb
Normal file
27
vcd_test.rb
Normal file
@ -0,0 +1,27 @@
|
||||
#xor_test.rb
|
||||
|
||||
require_relative "lib/rcircuit/port.rb"
|
||||
require_relative "lib/rcircuit/gate.rb"
|
||||
require_relative "lib/rcircuit/xor.rb"
|
||||
require_relative "lib/rcircuit/vcd.rb"
|
||||
|
||||
in_a = Port.new(1, "A")
|
||||
in_b = Port.new(1, "B")
|
||||
gate = XorGate.new(in_a, in_b)
|
||||
|
||||
vcd = VCD.new("vcd_test.vcd").attach(in_a)
|
||||
.attach(in_b)
|
||||
.attach(gate.out, "OUT")
|
||||
|
||||
in_a.setval(0)
|
||||
in_b.setval(0)
|
||||
vcd.start
|
||||
in_a.setval(1)
|
||||
vcd.advance(1000).write
|
||||
in_b.setval(1)
|
||||
vcd.advance(1000).write
|
||||
in_a.setval(0)
|
||||
vcd.advance(1000).write
|
||||
vcd.advance(1000)
|
||||
vcd.finish
|
||||
|
Loading…
Reference in New Issue
Block a user