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

Reply via email to