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}"