ASIC SoC2012. 2. 6. 19:20

Ruby-vpi를 테스트 하는 과정을 정리하였다.
여기서 사용하는 예제는 아래 링크에서 참조 하였다.

http://snk.tuxfamily.org/lib/ruby-vpi/#usage.tutorial.declare-design

디자인은 counter.v 이다.

일단 Top module부터 만든다.

module counter #(parameter Size = 5) (
  input                   clock,
  input                   reset,
  output reg [Size-1 : 0] count
);
endmodule


일단 폴더를 만들고

mkdir xUnit

디자인을 옮겨 둔다.
cp counter.v ./xUnit

그리고 해당 폴더로 가서 xUnit용 파일을 만든다.


GUNDAM-NT:xUnit kevinim$ ruby-vpi generate counter.v --xUnit

  module  counter
  create  counter_runner.rake
  create  counter_design.rb
  create  counter_proto.rb
  create  counter_spec.rb
  create  counter_loader.rb
  create  Rakefile 


위와 같이 커맨드를 넣으면 그에 맞게 파일이 만들어진다.
각각 앞에서 설명하였던 *.rake *_design.rb _proto.rb *_spec.rb *_loader.rb Rakefile 등이다.

(2) Spec 생성

카운터라는 것의 특성상 기본적인 내용은 아래와 같이 정의할 수 있겠다.
- 초기 값은 0이어야 한다.
- 상승 클럭에서 카운트 값이 1씩 증가한다.
- 최대 값에 도달하면 overflow가 발생하지만 하여튼 0부터 시작한다.

이것을 스펙으로 정의하면 아래와 같다.

require 'test/unit'

# lowest upper bound of counter's value
LIMIT = 2 ** DUT.Size.intVal

# maximum allowed value for a counter
MAX = LIMIT - 1


class A_counter_when_reset < Test::Unit::TestCase
  def setup
    DUT.reset! # reset the counter
  end

  def test_should_be_zero
    assert_equal( 0, DUT.count.intVal )
  end

  def test_should_increment_upon_each_subsequent_posedge
    LIMIT.times do |i|
      assert_equal( i, DUT.count.intVal )
      DUT.cycle! # increment the counter
    end
  end
end

class A_counter_with_the_maximum_value < Test::Unit::TestCase
  def setup
    DUT.reset! # reset the counter

    # increment the counter to maximum value
    MAX.times { DUT.cycle! }
    assert_equal( MAX, DUT.count.intVal )
  end

  def test_should_overflow_upon_increment
    DUT.cycle! # increment the counter
    assert_equal( 0, DUT.count.intVal )
  end
end

 크게 2개의 클래스를 만들었는데
하나가  A_counter_after_being_reset 이고
나머지 하나가 A_conter_with_the_maximum_value 이다.

각각 다음과 같은 동작을 수행한다.
 
 
A_counter_after_being_reset 
-  setup :: Reset을 건다. 
- test_should_be_zero :: 0인지 확인한다. 
- test_should_increment_upon_each_subsequent_posedge :: 계속 증가하면서 하나씩 커지는 것을 확인한다. 

A_counter_with_the_maximum_value
- setup :: 리셋을 건다.
- test_should_overflow_upon_increment :: overflow가 되면 0이 된다.

이다.

(3) Prototype을 만든다.

counter_proto.rb 파일에서 만든다.

if RubyVPI::USE_PROTOTYPE
  always do
    wait until DUT.clock.posedge?

    if DUT.reset.t ?
      DUT.count.intVal = 0 
    else
      DUT.count.intVal  += 1
   end
  end
end
      
 
카운터의 값의 프로토 타입을 의미한다.


(4) Prototype을 검증하기

검증은 다음과 같이 한다.

GUNDAM-NT:xUnit kevinim$ rake ivl PROTOTYPE=1 
(in /Users/kevinim/Documents/Verilog_toos/ruby-vpi-test/xUnit)
rake aborted!
no such file to load -- ruby-vpi/runner_proxy

옵션으로 ivl은 icarus verilog simulator를 의미한다.

위와 같은 오류가 발생한다.
 
ruby-vpi/runner_proxy 

를 찾을 수 없다는 오류이다.

이 파일은 라이브러리에 있으므로 환경 변수를 설정한다.

export RUBYLIB=/Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/lib/ 

이후에 다시 실행한다.

GUNDAM-NT:xUnit kevinim$ rake ivl PROTOTYPE=1 
(in /Users/kevinim/Documents/Verilog_toos/ruby-vpi-test/xUnit)
rake -f counter_runner.rake ivl PROTOTYPE=1
(in /Users/kevinim/Documents/Verilog_toos/ruby-vpi-test/xUnit)
cp /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/obj/ivl.so ruby-vpi.vpi
["iverilog", "-mruby-vpi", "counter.v", {:verbose=>:default, :noop=>false}]
iverilog -mruby-vpi counter.v
["vvp -M. a.out", {:verbose=>:default, :noop=>false}]
vvp -M. a.out
ruby-vpi: prototype is enabled
SyntaxError: compile error
counter_proto.rb:6: syntax error, unexpected '\n'
counter_proto.rb:12: syntax error, unexpected kEND, expecting $end
        from counter_proto.rb:12:in `load_test'
        from /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/lib/ruby-vpi.rb:68:in `each'
        from /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/lib/ruby-vpi.rb:68:in `load_test'
        from ./counter_loader.rb:1
        from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
        from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/custom_require.rb:31:in `require'
        from /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/lib/ruby-vpi/boot/loader.rb:146
        from /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/lib/ruby-vpi/core/scheduler.rb:121:in `call'
        from /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/lib/ruby-vpi/core/scheduler.rb:121:in `initialize'
        from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/generator.rb:83:in `call'
        from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/generator.rb:83:in `initialize'
        from /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/lib/ruby-vpi/core/scheduler.rb:119:in `new'
        from /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/lib/ruby-vpi/core/scheduler.rb:119:in `initialize'
        from /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/lib/ruby-vpi/core/scheduler.rb:53:in `new'
        from /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/lib/ruby-vpi/core/scheduler.rb:53:in `run'
        from /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/lib/ruby-vpi/boot/loader.rb:144


몇개의 오류가 보인다.
이것을 먼저 수정하고 진행한다.

GUNDAM-NT:xUnit kevinim$ vi counter_proto.rb 
GUNDAM-NT:xUnit kevinim$ rake ivl PROTOTYPE=1 
(in /Users/kevinim/Documents/Verilog_toos/ruby-vpi-test/xUnit)
rake -f counter_runner.rake ivl PROTOTYPE=1
(in /Users/kevinim/Documents/Verilog_toos/ruby-vpi-test/xUnit)
cp /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/obj/ivl.so ruby-vpi.vpi
["iverilog", "-mruby-vpi", "counter.v", {:verbose=>:default, :noop=>false}]
iverilog -mruby-vpi counter.v
["vvp -M. a.out", {:verbose=>:default, :noop=>false}]
vvp -M. a.out
ruby-vpi: prototype is enabled
Loaded suite ruby-vpi
Started
EEE
Finished in 0.00128 seconds.

  1) Error:
test_should_be_zero(#<Module:0x10252d340>::A_counter_when_reset):
ArgumentError: "VpiHigh" is not a valid VPI property
    /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/lib/ruby-vpi/core/handle.rb:364:in `initialize'
    /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/lib/ruby-vpi/core/handle.rb:288:in `new'
    /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/lib/ruby-vpi/core/handle.rb:288
....
  2) Error:
test_should_increment_upon_each_subsequent_posedge(#<Module:0x10252d340>::A_counter_when_reset):
ArgumentError: "VpiHigh" is not a valid VPI property
    /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/lib/ruby-vpi/core/handle.rb:364:in `initialize'
    /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/lib/ruby-vpi/core/handle.rb:288:in `new'
 ....

  3) Error:
test_should_overflow_upon_increment(#<Module:0x10252d340>::A_counter_with_the_maximum_value):
ArgumentError: "VpiHigh" is not a valid VPI property
    /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/lib/ruby-vpi/core/handle.rb:364:in `initialize'
    /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/lib/ruby-vpi/core/handle.rb:288:in `new'
    /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/lib/ruby-vpi/core/handle.rb:288
...

3 tests, 0 assertions, 0 failures, 3 errors
     
위의 에러는 뜻밖인데,
Ruby-VPI에서 버그가 있는것이다.
Test Code용으로 만들어낸 디자인에서 code가 틀리게 되어 있다.

counter_design.rb 를 아래와 같이 수정한다.


# Simulates the design under test for one clock cycle.
def DUT.cycle!
  clock.t!
  advance_time

  clock.f!
  advance_time
end

# Brings the design under test into a blank state.
def DUT.reset!
  reset.t!
  cycle!
  reset.f!
end
 
그리고 시뮬레이션을 수행하면 다음과 같은 오류가 발생한다.

GUNDAM-NT:xUnit kevinim$ rake ivl PROTOTYPE=1
(in /Users/kevinim/Documents/Verilog_toos/ruby-vpi-test/xUnit)
rake -f counter_runner.rake ivl PROTOTYPE=1
(in /Users/kevinim/Documents/Verilog_toos/ruby-vpi-test/xUnit)
cp /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/obj/ivl.so ruby-vpi.vpi
["iverilog", "-mruby-vpi", "counter.v", {:verbose=>:default, :noop=>false}]
iverilog -mruby-vpi counter.v
["vvp -M. a.out", {:verbose=>:default, :noop=>false}]
vvp -M. a.out
ruby-vpi: prototype is enabled
 MAX   is 31
 SIZE  is 5
 Limit is 32
Loaded suite ruby-vpi
Started
.FF
Finished in 0.059358 seconds.

  1) Failure:
test_should_increment_upon_each_subsequent_posedge(#<Module:0x10232d3d8>::A_counter_when_reset)
    [counter_spec.rb:27:in `test_should_increment_upon_each_subsequent_posedge'
     counter_spec.rb:26:in `times'
     counter_spec.rb:26:in `test_should_increment_upon_each_subsequent_posedge']:
<1> expected but was
<0>.

  2) Failure:
test_should_overflow_upon_increment(#<Module:0x10232d3d8>::A_counter_with_the_maximum_value) [counter_spec.rb:39]:
<31> expected but was
<0>.

3 tests, 4 assertions, 2 failures, 0 errors
 
이번의 오류는 RUBY와 icaurs가 연결이 되지 않는다는 의미이다.

그래서 이번에는 CVER로 바꾸어서 컴파일을 해본다.
GPLCver에 대한 설치는 이 페이지를 참조하고 여기서는 그냥 진행한다

GUNDAM-NT:xUnit kevinim$ rake cver PROTOTYPE=1
(in /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/examples/counter/xUnit)
rake -f counter_runner.rake cver PROTOTYPE=1
(in /Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/examples/counter/xUnit)
["cver", "+loadvpi=/Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/obj/cver.so:vlog_startup_routines_bootstrap", "+incdir+..", "../counter.v", {:verbose=>:default, :noop=>false}]
cver +loadvpi=/Users/kevinim/Documents/Verilog_toos/Ruby-VPI/ruby-vpi-21.1.0/obj/cver.so:vlog_startup_routines_bootstrap +incdir+.. ../counter.v
GPLCVER_2.12a of 05/16/07 (Mac OSX).
Copyright (c) 1991-2007 Pragmatic C Software Corp.
  All Rights reserved.  Licensed under the GNU General Public License (GPL).
  See the 'COPYING' file for details.  NO WARRANTY provided.
Today is Wed Nov  2 19:37:38 2011.
Compiling source file "../counter.v"
Highest level modules:
counter

ruby-vpi: prototype is enabled
Loaded suite ruby-vpi
Started
...
Finished in 0.103285 seconds.

3 tests, 35 assertions, 0 failures, 0 errors
0 simulation events and 0 declarative immediate assigns processed.
1 behavioral statements executed (1 procedural suspends).
  Times (in sec.):  Translate 0.0, load/optimize 0.1, simulation 0.3.
  There were 3 error(s), 136 warning(s), and 4 inform(s).
End of GPLCVER_2.12a at Wed Nov  2 19:37:38 2011 (elapsed 0.3 seconds).

결과는 이상없이 잘 진행된다.
아마도 icarus와 ruby-vpi가 잘 안맞는 문제인듯..
Osx에서만 안맞는것인지 linux에서도 그런지는 확인을 하지 못하였다.
 
 
이 방법은 불안정 해서  더이상 진행하지 않습니다.
나중에 Linux + ModelSim이나 VCS로 테스트 해보고 되면 진행 예정입니다.


 
Posted by GUNDAM_IM