Hello,
I have been having a difficult time debugging this segmentation
fault and am wondering if somebody can help me. The seg fault
appears within the relay.c:relay_verilog() routine when trying
to apply a mutex_lock on the ruby interpreter. Also, this seg faults
happens only for GPL Cver and NC-Verilog. On vcs it works fine.
The segmentation fault happens for both ruby 1.8.6 and ruby 1.6.8
Just want to know if you can try out my test program to see if anyone
of you can reproduce this problem. This test program introduces another
scheme to handle multiple atPosEdge/atNegEdge/wait routines in multiple
threads using cbValueChange callbacks for edge triggering and cbAfterDelay
for fixed wait times.
Calvin
//---------------------------
//
// Verilog Module
//
//---------------------------
module cadd_tb;
reg clk0; initial clk0 = 'h0;
reg clk1; initial clk1 = 'h0;
initial forever #5 clk0 = ~clk0;
initial forever #7 clk1 = ~clk1;
// initial $dumpvars;
initial
begin
repeat(2000) @(posedge clk0);
$finish;
end
endmodule
#-----------------------------
#
# Ruby Test
#
#-----------------------------
# -- Required since no cleanup routines existed
# --
at_exit { Vpi::__extension__relay_verilog }
# --
# -- Barbones method to getting at?Edge working
# -- using sheer verilog vpi calls
# --
# -------------------------------------
#
# Scheduler Variables Declared Here!
#
# -------------------------------------
require 'monitor'
@@__scheduler__lock = Monitor.new # synchronizer
@@__scheduler__main = nil # Main thread
@@__scheduler__thread = {} # Individual threads
@@__scheduler__probe = nil # Arbitration thread
@@__scheduler__handler = {} # Might want to combine handler/cbRetData
@@__scheduler__cbRetData = {}
# -------------------------------------
#
# CW DEFINED FUNCTIONS HERE!
#
# -------------------------------------
def advanceTime waitTime
aVpiTime = Vpi::S_vpi_time.new
aVpiTime.type = Vpi::VpiSimTime
aVpiTime.high = 0
aVpiTime.low = waitTime
aVpiValue = Vpi::S_vpi_value.new
aVpiValue.format = Vpi::VpiSuppressVal
aCbData = Vpi::S_cb_data.new
aCbData.reason = Vpi::CbAfterDelay
aCbData.cb_rtn = Vpi::Vlog_relay_ruby
aCbData.obj = nil
aCbData.time = aVpiTime
aCbData.value = aVpiValue
aCbData.index = 0
aCbData.user_data = nil
@@__scheduler__lock.synchronize do
Vpi::vpi_free_object(Vpi::vpi_register_cb(aCbData))
Vpi::__extension__relay_verilog
end
end
def displaySimTime index
aVpiTime = Vpi::S_vpi_time.new
aVpiTime.type = Vpi::VpiSimTime
aVpiTime.high = 0
aVpiTime.low = 0
Vpi::vpi_get_time(nil, aVpiTime)
puts "Line #{index} : Simulation time is #{aVpiTime.low}"
end
def getCurrentValue aHandle, format=Vpi::VpiIntVal
aVpiValue = Vpi::S_vpi_value.new
aVpiValue.format = format
Vpi::vpi_get_value(aHandle, aVpiValue)
case format
when Vpi::VpiIntVal
return aVpiValue.value.integer
end
end
def atXEdge aHandle
@@__scheduler__lock.synchronize do
# 1. Register the callback
aVpiTime = Vpi::S_vpi_time.new
aVpiTime.type = Vpi::VpiSimTime
aVpiTime.high = 0
aVpiTime.low = 0
aVpiValue = Vpi::S_vpi_value.new
aVpiValue.format = Vpi::VpiIntVal
aCbData = Vpi::S_cb_data.new
aCbData.reason = Vpi::CbValueChange
aCbData.cb_rtn = Vpi::Vlog_relay_ruby
aCbData.obj = aHandle
aCbData.time = aVpiTime
aCbData.value = aVpiValue
aCbData.index = 0
aCbData.user_data = aHandle.id.to_s
if (@@__scheduler__cbRetData[aHandle.id.to_s] == nil)
@@__scheduler__cbRetData[aHandle.id.to_s] =
Vpi::vpi_register_cb(aCbData)
end
# 2. Push thread onto the handler hash
if (@@__scheduler__handler[aHandle.id.to_s] == nil)
@@__scheduler__handler[aHandle.id.to_s] = Array.new(1,Thread.current)
else
@@__scheduler__handler[aHandle.id.to_s] << Thread.current
end
end
Thread.stop
end
def atPosEdge aHandle
if (getCurrentValue(aHandle) == 0)
atXEdge(aHandle)
else
atXEdge(aHandle)
atXEdge(aHandle)
end
end
def atNegEdge aHandle
if (getCurrentValue(aHandle) == 0)
atXEdge(aHandle)
atXEdge(aHandle)
else
atXEdge(aHandle)
end
end
def waitSimTime waitTime
@@__scheduler__lock.synchronize do
aVpiTimeCurrentTime = Vpi::S_vpi_time.new
aVpiTimeCurrentTime.type = Vpi::VpiSimTime
Vpi::vpi_get_time(nil, aVpiTimeCurrentTime)
cbTime = aVpiTimeCurrentTime.low + waitTime # Absolute callback time
#1. Register the callback
aVpiTime = Vpi::S_vpi_time.new
aVpiTime.type = Vpi::VpiSimTime
aVpiTime.high = 0 # CW.TODO : assume time < 2^32
aVpiTime.low = waitTime
aVpiValue = Vpi::S_vpi_value.new
aVpiValue.format = Vpi::VpiSuppressVal
aCbData = Vpi::S_cb_data.new
aCbData.reason = Vpi::CbAfterDelay
aCbData.cb_rtn = Vpi::Vlog_relay_ruby
aCbData.obj = nil
aCbData.time = aVpiTime
aCbData.value = aVpiValue
aCbData.index = 0
aCbData.user_data = cbTime.id.to_s
if (@@__scheduler__cbRetData[cbTime.id.to_s] == nil)
@@__scheduler__cbRetData[cbTime.id.to_s] = Vpi::vpi_register_cb(aCbData)
end
# 2. Push thread onto the handler hash
if (@@__scheduler__handler[cbTime.id.to_s] == nil)
@@__scheduler__handler[cbTime.id.to_s] = Array.new(1,Thread.current)
else
@@__scheduler__handler[cbTime.id.to_s] << Thread.current
end
end
Thread.stop
end
# -------------------------------------
#
# TEST BEGINS HERE
#
# -------------------------------------
@@__scheduler__main = Thread.new do
# Define the Probe Here
@@__scheduler__probe = Thread.new do
loop do
unless (@@__scheduler__thread.empty?)
all_threads_asleep = true
@@__scheduler__thread.each do |key,value|
all_threads_asleep &= value.stop?
end
Thread.pass # --[CW.TODO] : This hack seems to work
if ((all_threads_asleep) && (!@@__scheduler__handler.empty?))
@@__scheduler__lock.synchronize do
Vpi::__extension__relay_verilog
reason = Vpi::__extension__relay_ruby_reason
@@__scheduler__handler[reason.user_data].each { |aThread|
aThread.wakeup }
@@__scheduler__handler.delete(reason.user_data)
Vpi::vpi_remove_cb(@@__scheduler__cbRetData[reason.user_data])
@@__scheduler__cbRetData.delete(reason.user_data)
end
end
end
Thread.pass
end
end
# Advance 1 time unit for now
advanceTime 1
clk0 = Vpi::vpi_handle_by_name("cadd_tb.clk0", nil)
clk1 = Vpi::vpi_handle_by_name("cadd_tb.clk1", nil)
@@__scheduler__thread['t0'] = Thread.new do
5.times do
atXEdge(clk0)
displaySimTime "#{__LINE__} : T0.clk0 = #{getCurrentValue(clk0)}"
end
end
@@__scheduler__thread['t1'] = Thread.new do
5.times do
atXEdge(clk0)
displaySimTime "#{__LINE__} : T1.clk0 = #{getCurrentValue(clk0)}"
end
end
@@__scheduler__thread['t2'] = Thread.new do
5.times do
atPosEdge(clk1)
displaySimTime "#{__LINE__} : T2.clk1 = #{getCurrentValue(clk1)}"
end
end
@@__scheduler__thread['t3'] = Thread.new do
5.times do
atNegEdge(clk1)
displaySimTime "#{__LINE__} : T3.clk1 = #{getCurrentValue(clk1)}"
end
end
@@__scheduler__thread['t4'] = Thread.new do
5.times do
waitSimTime 11
displaySimTime "#{__LINE__}"
end
end
@@__scheduler__thread['t0'].join
@@__scheduler__thread['t1'].join
@@__scheduler__thread['t2'].join
@@__scheduler__thread['t3'].join
@@__scheduler__thread['t4'].join
@@__scheduler__thread.delete('t0')
@@__scheduler__thread.delete('t1')
@@__scheduler__thread.delete('t2')
@@__scheduler__thread.delete('t3')
@@__scheduler__thread.delete('t4')
end
@@__scheduler__main.join
advanceTime 10
displaySimTime __LINE__
puts "scheduler.thread.size = #{@@__scheduler__thread.size}"
puts "scheduler.handler.size = #{@@__scheduler__handler.size}"
puts "scheduler.cbRetData.size = #{@@__scheduler__cbRetData.size}"