ruby-vpi 18.0.2 → 19.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +15 -19
- data/bin/generate/proto.rb +15 -10
- data/bin/ruby-vpi +2 -0
- data/doc/README +3 -5
- data/doc/Rakefile +3 -3
- data/doc/common.css +24 -136
- data/doc/common.tpl +48 -37
- data/doc/figures/figures.dia +19 -19
- data/doc/figures/ruby_relay.png +0 -0
- data/doc/history.html +252 -67
- data/doc/history.inc +98 -1
- data/doc/history.yaml +105 -0
- data/doc/intro.inc +43 -32
- data/doc/lib/doc_format.rb +19 -13
- data/doc/lib/doc_proxy.rb +7 -7
- data/doc/manual.doc +156 -117
- data/doc/manual.html +601 -560
- data/doc/memo.html +29 -25
- data/doc/print.css +63 -4
- data/doc/readme.doc +4 -6
- data/doc/readme.html +129 -111
- data/doc/rss.xml +168 -7
- data/doc/screen.css +146 -0
- data/doc/spacing.css +57 -0
- data/{samp → examples}/counter/RSpec/Rakefile +0 -0
- data/{samp → examples}/counter/RSpec/counter_design.rb +0 -0
- data/examples/counter/RSpec/counter_proto.rb +9 -0
- data/{samp → examples}/counter/RSpec/counter_runner.rake +0 -0
- data/{samp → examples}/counter/RSpec/counter_spec.rb +0 -0
- data/{samp → examples}/counter/Rakefile +0 -0
- data/{samp → examples}/counter/counter.v +0 -0
- data/{samp → examples}/counter/xUnit/Rakefile +0 -0
- data/{samp → examples}/counter/xUnit/counter_bench.rb +0 -0
- data/{samp → examples}/counter/xUnit/counter_bench.v +0 -0
- data/{samp → examples}/counter/xUnit/counter_design.rb +0 -0
- data/examples/counter/xUnit/counter_proto.rb +9 -0
- data/{samp → examples}/counter/xUnit/counter_runner.rake +0 -0
- data/{samp → examples}/counter/xUnit/counter_spec.rb +0 -0
- data/{samp → examples}/pipelined_alu/Hw5UnitModel.rb +0 -0
- data/{samp → examples}/pipelined_alu/README +0 -0
- data/{samp → examples}/pipelined_alu/Rakefile +0 -0
- data/{samp → examples}/pipelined_alu/TestHw5UnitModel.rb +0 -0
- data/{samp → examples}/pipelined_alu/hw5_unit.v +0 -0
- data/{samp → examples}/pipelined_alu/hw5_unit_design.rb +0 -7
- data/examples/pipelined_alu/hw5_unit_proto.rb +2 -0
- data/{samp → examples}/pipelined_alu/hw5_unit_runner.rake +0 -0
- data/{samp → examples}/pipelined_alu/hw5_unit_spec.rb +0 -0
- data/{samp → examples}/pipelined_alu/int_gen.rb +0 -0
- data/{samp → examples}/register_file/LICENSE +0 -0
- data/{samp → examples}/register_file/README +0 -0
- data/{samp → examples}/register_file/Rakefile +0 -0
- data/{samp → examples}/register_file/register_file.v +0 -0
- data/{samp → examples}/register_file/register_file_design.rb +0 -0
- data/examples/register_file/register_file_proto.rb +11 -0
- data/{samp → examples}/register_file/register_file_runner.rake +0 -0
- data/{samp → examples}/register_file/register_file_spec.rb +0 -0
- data/ext/main.c +5 -5
- data/ext/swig_vpi.i +6 -2
- data/lib/ruby-vpi/core/callback.rb +142 -0
- data/lib/ruby-vpi/core/edge.rb +128 -0
- data/lib/ruby-vpi/core/handle.rb +421 -0
- data/lib/ruby-vpi/core/scheduler.rb +244 -0
- data/lib/ruby-vpi/core/struct.rb +123 -0
- data/lib/ruby-vpi/core.rb +41 -0
- data/lib/ruby-vpi/rcov.rb +25 -12
- data/lib/ruby-vpi/runner.rb +30 -26
- data/lib/ruby-vpi/runner_boot_loader.rb +67 -37
- data/lib/ruby-vpi.rb +2 -2
- data/ref/c/annotated.html +1 -1
- data/ref/c/common_8h.html +1 -1
- data/ref/c/files.html +1 -1
- data/ref/c/functions.html +1 -1
- data/ref/c/functions_vars.html +1 -1
- data/ref/c/globals.html +1 -1
- data/ref/c/globals_0x63.html +1 -1
- data/ref/c/globals_0x65.html +1 -1
- data/ref/c/globals_0x66.html +1 -1
- data/ref/c/globals_0x6d.html +1 -1
- data/ref/c/globals_0x70.html +1 -1
- data/ref/c/globals_0x72.html +1 -1
- data/ref/c/globals_0x73.html +1 -1
- data/ref/c/globals_0x74.html +1 -1
- data/ref/c/globals_0x76.html +1 -1
- data/ref/c/globals_0x78.html +1 -1
- data/ref/c/globals_defs.html +1 -1
- data/ref/c/globals_defs_0x65.html +1 -1
- data/ref/c/globals_defs_0x70.html +1 -1
- data/ref/c/globals_defs_0x76.html +1 -1
- data/ref/c/globals_defs_0x78.html +1 -1
- data/ref/c/globals_enum.html +1 -1
- data/ref/c/globals_eval.html +1 -1
- data/ref/c/globals_func.html +1 -1
- data/ref/c/globals_type.html +1 -1
- data/ref/c/globals_vars.html +1 -1
- data/ref/c/index.html +1 -1
- data/ref/c/main_8c.html +1 -1
- data/ref/c/main_8h.html +1 -1
- data/ref/c/relay_8c.html +1 -1
- data/ref/c/relay_8h.html +1 -1
- data/ref/c/structt__cb__data.html +1 -1
- data/ref/c/structt__vpi__delay.html +1 -1
- data/ref/c/structt__vpi__error__info.html +1 -1
- data/ref/c/structt__vpi__strengthval.html +1 -1
- data/ref/c/structt__vpi__systf__data.html +1 -1
- data/ref/c/structt__vpi__time.html +1 -1
- data/ref/c/structt__vpi__value.html +1 -1
- data/ref/c/structt__vpi__vecval.html +1 -1
- data/ref/c/structt__vpi__vlog__info.html +1 -1
- data/ref/c/verilog_8h.html +1 -1
- data/ref/c/vlog_8c.html +1 -1
- data/ref/c/vlog_8h.html +1 -1
- data/ref/c/vpi__user_8h.html +1 -1
- data/ref/ruby/classes/ERB.html +7 -5
- data/ref/ruby/classes/ERB.src/{M000026.html → M000024.html} +0 -0
- data/ref/ruby/classes/FileUtils.html +11 -11
- data/ref/ruby/classes/FileUtils.src/{M000027.html → M000025.html} +0 -0
- data/ref/ruby/classes/FileUtils.src/{M000028.html → M000026.html} +0 -0
- data/ref/ruby/classes/Float.html +8 -6
- data/ref/ruby/classes/Float.src/{M000021.html → M000019.html} +0 -0
- data/ref/ruby/classes/Integer.html +67 -65
- data/ref/ruby/classes/Integer.src/M000007.html +25 -0
- data/ref/ruby/classes/Integer.src/{M000014.html → M000008.html} +5 -5
- data/ref/ruby/classes/Integer.src/M000009.html +5 -12
- data/ref/ruby/classes/Integer.src/M000010.html +5 -5
- data/ref/ruby/classes/Integer.src/M000011.html +5 -5
- data/ref/ruby/classes/Integer.src/M000012.html +5 -5
- data/ref/ruby/classes/Integer.src/M000015.html +25 -0
- data/ref/ruby/classes/Integer.src/M000016.html +31 -0
- data/ref/ruby/classes/Integer.src/M000017.html +12 -12
- data/ref/ruby/classes/Integer.src/M000018.html +17 -18
- data/ref/ruby/classes/Object.html +126 -0
- data/ref/ruby/classes/RDoc.html +5 -5
- data/ref/ruby/classes/RDoc.src/{M000061.html → M000081.html} +0 -0
- data/ref/ruby/classes/RubyVPI.html +50 -9
- data/ref/ruby/classes/String.html +22 -20
- data/ref/ruby/classes/String.src/M000020.html +36 -0
- data/ref/ruby/classes/String.src/M000021.html +41 -0
- data/ref/ruby/classes/String.src/M000022.html +5 -23
- data/ref/ruby/classes/String.src/M000023.html +5 -28
- data/ref/ruby/classes/{Vpi → VPI}/Handle.html +442 -140
- data/ref/ruby/classes/{Vpi/Handle.src/M000042.html → VPI/Handle.src/M000037.html} +4 -4
- data/ref/ruby/classes/VPI/Handle.src/M000038.html +21 -0
- data/ref/ruby/classes/VPI/Handle.src/M000039.html +18 -0
- data/ref/ruby/classes/{Vpi/Handle.src/M000036.html → VPI/Handle.src/M000040.html} +5 -5
- data/ref/ruby/classes/VPI/Handle.src/M000045.html +18 -0
- data/ref/ruby/classes/{Vpi/Handle.src/M000038.html → VPI/Handle.src/M000046.html} +5 -5
- data/ref/ruby/classes/VPI/Handle.src/M000057.html +18 -0
- data/ref/ruby/classes/{Vpi/Handle.src/M000040.html → VPI/Handle.src/M000058.html} +5 -5
- data/ref/ruby/classes/VPI/Handle.src/M000061.html +18 -0
- data/ref/ruby/classes/VPI/Handle.src/M000062.html +18 -0
- data/ref/ruby/classes/{Vpi/Handle.src/M000054.html → VPI/Handle.src/M000065.html} +11 -11
- data/ref/ruby/classes/VPI/Handle.src/M000067.html +21 -0
- data/ref/ruby/classes/VPI/Handle.src/M000068.html +28 -0
- data/ref/ruby/classes/VPI/Handle.src/M000069.html +50 -0
- data/ref/ruby/classes/{Vpi/Handle.src/M000048.html → VPI/Handle.src/M000070.html} +6 -6
- data/ref/ruby/classes/{Vpi/Handle.src/M000049.html → VPI/Handle.src/M000071.html} +6 -6
- data/ref/ruby/classes/{Vpi/Handle.src/M000050.html → VPI/Handle.src/M000072.html} +5 -5
- data/ref/ruby/classes/{Vpi/Handle.src/M000051.html → VPI/Handle.src/M000073.html} +17 -17
- data/ref/ruby/classes/VPI/Handle.src/M000075.html +18 -0
- data/ref/ruby/classes/VPI/Handle.src/M000076.html +40 -0
- data/ref/ruby/classes/{Vpi/Handle.src/M000056.html → VPI/Handle.src/M000077.html} +18 -18
- data/ref/ruby/classes/{Vpi → VPI}/S_vpi_time.html +22 -20
- data/ref/ruby/classes/VPI/S_vpi_time.src/M000078.html +18 -0
- data/ref/ruby/classes/VPI/S_vpi_time.src/M000079.html +19 -0
- data/ref/ruby/classes/{Vpi → VPI}/S_vpi_value.html +37 -23
- data/ref/ruby/classes/VPI/S_vpi_value.src/M000034.html +35 -0
- data/ref/ruby/classes/VPI/S_vpi_value.src/M000035.html +42 -0
- data/ref/ruby/classes/VPI/S_vpi_value.src/M000036.html +42 -0
- data/ref/ruby/classes/{Vpi.html → VPI.html} +129 -34
- data/ref/ruby/classes/VPI.src/M000027.html +19 -0
- data/ref/ruby/classes/VPI.src/M000028.html +18 -0
- data/ref/ruby/classes/VPI.src/M000029.html +19 -0
- data/ref/ruby/classes/VPI.src/M000031.html +25 -0
- data/ref/ruby/classes/VPI.src/M000032.html +26 -0
- data/ref/ruby/classes/VerilogParser/Module/Port.html +17 -15
- data/ref/ruby/classes/VerilogParser/Module/Port.src/M000004.html +23 -0
- data/ref/ruby/classes/VerilogParser/Module/Port.src/{M000007.html → M000005.html} +0 -0
- data/ref/ruby/classes/VerilogParser/Module/Port.src/M000006.html +5 -10
- data/ref/ruby/classes/VerilogParser/Module.html +7 -5
- data/ref/ruby/classes/VerilogParser/Module.src/{M000005.html → M000003.html} +0 -0
- data/ref/ruby/classes/VerilogParser.html +7 -5
- data/ref/ruby/classes/VerilogParser.src/{M000004.html → M000002.html} +0 -0
- data/ref/ruby/created.rid +1 -1
- data/ref/ruby/files/bin/generate_rb.html +2 -2
- data/ref/ruby/files/lib/ruby-vpi/{vpi_rb.html → core/callback_rb.html} +7 -8
- data/ref/ruby/files/lib/ruby-vpi/core/edge_rb.html +114 -0
- data/ref/ruby/files/lib/ruby-vpi/core/handle_rb.html +107 -0
- data/ref/ruby/files/lib/ruby-vpi/core/scheduler_rb.html +114 -0
- data/ref/ruby/files/lib/ruby-vpi/core/struct_rb.html +108 -0
- data/ref/ruby/files/lib/ruby-vpi/core_rb.html +121 -0
- data/ref/ruby/files/lib/ruby-vpi/rcov_rb.html +1 -1
- data/ref/ruby/files/lib/ruby-vpi/runner_boot_loader_rb.html +5 -41
- data/ref/ruby/files/lib/ruby-vpi/runner_boot_loader_rb.src/M000001.html +3 -3
- data/ref/ruby/files/lib/ruby-vpi/runner_rb.html +1 -1
- data/ref/ruby/files/lib/ruby-vpi_rb.html +1 -1
- data/ref/ruby/fr_class_index.html +5 -4
- data/ref/ruby/fr_file_index.html +6 -1
- data/ref/ruby/fr_method_index.html +80 -60
- metadata +126 -103
- data/ext/swig_vpi.h +0 -924
- data/ext/swig_wrap.cin +0 -7083
- data/lib/ruby-vpi/vpi.rb +0 -651
- data/ref/ruby/classes/Integer.src/M000013.html +0 -18
- data/ref/ruby/classes/Integer.src/M000019.html +0 -25
- data/ref/ruby/classes/Integer.src/M000020.html +0 -30
- data/ref/ruby/classes/String.src/M000024.html +0 -18
- data/ref/ruby/classes/String.src/M000025.html +0 -18
- data/ref/ruby/classes/VerilogParser/Module/Port.src/M000008.html +0 -18
- data/ref/ruby/classes/Vpi/Handle.src/M000035.html +0 -18
- data/ref/ruby/classes/Vpi/Handle.src/M000037.html +0 -18
- data/ref/ruby/classes/Vpi/Handle.src/M000039.html +0 -18
- data/ref/ruby/classes/Vpi/Handle.src/M000041.html +0 -18
- data/ref/ruby/classes/Vpi/Handle.src/M000043.html +0 -21
- data/ref/ruby/classes/Vpi/Handle.src/M000044.html +0 -21
- data/ref/ruby/classes/Vpi/Handle.src/M000045.html +0 -22
- data/ref/ruby/classes/Vpi/Handle.src/M000046.html +0 -50
- data/ref/ruby/classes/Vpi/Handle.src/M000047.html +0 -91
- data/ref/ruby/classes/Vpi/Handle.src/M000053.html +0 -18
- data/ref/ruby/classes/Vpi/Handle.src/M000057.html +0 -40
- data/ref/ruby/classes/Vpi/S_vpi_time.src/M000058.html +0 -18
- data/ref/ruby/classes/Vpi/S_vpi_time.src/M000059.html +0 -19
- data/ref/ruby/classes/Vpi/S_vpi_value.src/M000032.html +0 -18
- data/ref/ruby/classes/Vpi/S_vpi_value.src/M000033.html +0 -18
- data/ref/ruby/classes/Vpi/S_vpi_value.src/M000034.html +0 -18
- data/ref/ruby/classes/Vpi.src/M000029.html +0 -28
- data/ref/ruby/classes/Vpi.src/M000030.html +0 -39
- data/ref/ruby/classes/Vpi.src/M000031.html +0 -20
- data/ref/ruby/files/lib/ruby-vpi/runner_boot_loader_rb.src/M000002.html +0 -18
- data/samp/counter/RSpec/counter_proto.rb +0 -10
- data/samp/counter/xUnit/counter_proto.rb +0 -10
- data/samp/pipelined_alu/hw5_unit_proto.rb +0 -4
- data/samp/register_file/register_file_proto.rb +0 -11
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# Concurrent processes.
|
|
2
|
+
#--
|
|
3
|
+
# Copyright 2007 Suraj N. Kurapati
|
|
4
|
+
# See the file named LICENSE for details.
|
|
5
|
+
|
|
6
|
+
Thread.abort_on_exception = true
|
|
7
|
+
|
|
8
|
+
require 'singleton'
|
|
9
|
+
|
|
10
|
+
module RubyVPI
|
|
11
|
+
class SchedulerClass #:nodoc:
|
|
12
|
+
include Singleton
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
Task = Struct.new(:thread, :state)
|
|
16
|
+
|
|
17
|
+
class Task #:nodoc:
|
|
18
|
+
def run
|
|
19
|
+
self.state = :run
|
|
20
|
+
self.thread.wakeup
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def stop
|
|
24
|
+
self.state = :wait
|
|
25
|
+
Thread.stop
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def stop?
|
|
29
|
+
self.thread.stop? and self.state == :wait
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def initialize
|
|
35
|
+
@thread2task = { Thread.main => Task.new(Thread.main, :run) }
|
|
36
|
+
@thread2task_sw = @thread2task.dup # software threads
|
|
37
|
+
@thread2task_hw = {} # hardware threads (Ruby prototype of DUT)
|
|
38
|
+
@thread2task_lock = Mutex.new
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# base case: hardware runs first before any software does at startup
|
|
42
|
+
@time = 0
|
|
43
|
+
|
|
44
|
+
unless RubyVPI::USE_PROTOTYPE
|
|
45
|
+
Callback.relay_verilog(VPI::CbReadOnlySynch, 0)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
@scheduler = Thread.new do
|
|
49
|
+
# pause because boot loader is not fully init yet
|
|
50
|
+
Thread.stop
|
|
51
|
+
|
|
52
|
+
loop do
|
|
53
|
+
# run software in current time step
|
|
54
|
+
run_tasks @thread2task_sw, true
|
|
55
|
+
Edge.refresh_cache
|
|
56
|
+
|
|
57
|
+
# go to time slot where writing is permitted before flushing writes
|
|
58
|
+
unless RubyVPI::USE_PROTOTYPE
|
|
59
|
+
Callback.relay_verilog(VPI::CbAfterDelay, 1)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
flush_writes
|
|
63
|
+
|
|
64
|
+
# run hardware in next time step
|
|
65
|
+
@time += 1
|
|
66
|
+
|
|
67
|
+
if RubyVPI::USE_PROTOTYPE
|
|
68
|
+
run_tasks @thread2task_hw, false
|
|
69
|
+
flush_writes
|
|
70
|
+
else
|
|
71
|
+
Callback.relay_verilog(VPI::CbReadOnlySynch, 0)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@handle2write = Hash.new {|h,k| h[k] = []}
|
|
78
|
+
@handle2write_lock = Mutex.new
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def current_time
|
|
82
|
+
@time
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def start
|
|
86
|
+
@scheduler.wakeup
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Registers the calling thread with the scheduler.
|
|
90
|
+
def attach
|
|
91
|
+
key = Thread.current
|
|
92
|
+
|
|
93
|
+
hash =
|
|
94
|
+
if caller.grep(/_proto\.rb/).empty?
|
|
95
|
+
@thread2task_sw
|
|
96
|
+
else
|
|
97
|
+
@thread2task_hw
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
@thread2task_lock.synchronize do
|
|
101
|
+
task = Task.new(key, :run)
|
|
102
|
+
hash[key] = task
|
|
103
|
+
@thread2task[key] = task
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Unregisters the calling thread from the scheduler.
|
|
108
|
+
def detach
|
|
109
|
+
key = Thread.current
|
|
110
|
+
|
|
111
|
+
@thread2task_lock.synchronize do
|
|
112
|
+
@thread2task.delete key
|
|
113
|
+
@thread2task_hw.delete key
|
|
114
|
+
@thread2task_sw.delete key
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Waits for the scheduler to arrive in the next time step.
|
|
119
|
+
def await
|
|
120
|
+
key = Thread.current
|
|
121
|
+
|
|
122
|
+
task = @thread2task_lock.synchronize do
|
|
123
|
+
@thread2task[key]
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
task.stop
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def ensure_caller_is_registered
|
|
130
|
+
unless @thread2task_lock.synchronize {@thread2task.key? Thread.current}
|
|
131
|
+
raise SecurityError, 'This method may only be invoked from within a process (see the VPI::process() method).'
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
Write = Struct.new :thread, :trace, :args
|
|
136
|
+
|
|
137
|
+
# Captures the given write operation so it
|
|
138
|
+
# can be flushed later, at the correct time.
|
|
139
|
+
def capture_write aHandle, *aArgs
|
|
140
|
+
@handle2write_lock.synchronize do
|
|
141
|
+
@handle2write[aHandle] << Write.new(Thread.current, caller, aArgs)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
private
|
|
146
|
+
|
|
147
|
+
# Flushes all captured writes.
|
|
148
|
+
def flush_writes
|
|
149
|
+
@handle2write_lock.synchronize do
|
|
150
|
+
@handle2write.each_pair do |handle, writes|
|
|
151
|
+
if writes.map {|w| w.thread}.uniq.length > 1
|
|
152
|
+
culprits = writes.map {|w| "\n\n#{w.thread}" << w.trace.map {|x| "\n\t#{x}"}.join}.join
|
|
153
|
+
STDERR.puts "Race condition detected at time step #{current_time}: the logic value of handle #{handle} is being modified by more than one concurrent process: #{culprits}"
|
|
154
|
+
exit 1
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
writes.each do |w|
|
|
158
|
+
VPI::__scheduler__vpi_put_value(handle, *w.args)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
writes.clear
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def run_tasks aHash, aExitWhenEmpty
|
|
167
|
+
@thread2task_lock.synchronize do
|
|
168
|
+
tasks = aHash.values
|
|
169
|
+
tasks.each {|t| t.run}
|
|
170
|
+
|
|
171
|
+
if aExitWhenEmpty and tasks.empty?
|
|
172
|
+
Thread.exit
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
loop do
|
|
177
|
+
ready = @thread2task_lock.synchronize do
|
|
178
|
+
aHash.values.all? {|t| t.stop?}
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
if ready
|
|
182
|
+
break
|
|
183
|
+
else
|
|
184
|
+
Thread.pass
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
Scheduler = SchedulerClass.instance
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
module VPI
|
|
194
|
+
alias_method :__scheduler__vpi_put_value, :vpi_put_value
|
|
195
|
+
module_function :__scheduler__vpi_put_value
|
|
196
|
+
|
|
197
|
+
def vpi_put_value *args #:nodoc:
|
|
198
|
+
RubyVPI::Scheduler.capture_write(*args)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
# Returns the current simulation time.
|
|
203
|
+
def current_time
|
|
204
|
+
RubyVPI::Scheduler.current_time
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Wait until the simulation advances by the given number of time steps.
|
|
208
|
+
def advance_time aNumTimeSteps = 1
|
|
209
|
+
RubyVPI::Scheduler.ensure_caller_is_registered
|
|
210
|
+
aNumTimeSteps.times { RubyVPI::Scheduler.await }
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
alias wait advance_time
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
# Creates a new concurrent process, which will execute the
|
|
217
|
+
# given block with the given arguments, and returns it.
|
|
218
|
+
def process *aBlockArgs
|
|
219
|
+
RubyVPI::Scheduler.ensure_caller_is_registered
|
|
220
|
+
raise ArgumentError, "block must be given" unless block_given?
|
|
221
|
+
|
|
222
|
+
Thread.new do
|
|
223
|
+
RubyVPI::Scheduler.attach
|
|
224
|
+
yield(*aBlockArgs)
|
|
225
|
+
RubyVPI::Scheduler.detach
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Wraps the given block inside an infinite loop and executes it
|
|
230
|
+
# inside a new concurrent process (see the VPI::process method).
|
|
231
|
+
def always *aBlockArgs, &aBlock
|
|
232
|
+
process do
|
|
233
|
+
loop do
|
|
234
|
+
startTime = VPI.current_time
|
|
235
|
+
aBlock.call(*aBlockArgs)
|
|
236
|
+
finishTime = VPI.current_time
|
|
237
|
+
|
|
238
|
+
VPI.advance_time unless finishTime > startTime
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
alias forever always
|
|
244
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# VPI structures (S_vpi_* and S_cb_*) stuff
|
|
2
|
+
#--
|
|
3
|
+
# Copyright 2006 Suraj N. Kurapati
|
|
4
|
+
# See the file named LICENSE for details.
|
|
5
|
+
|
|
6
|
+
module VPI
|
|
7
|
+
class S_vpi_time
|
|
8
|
+
# Returns the high and low portions of
|
|
9
|
+
# this time as a single 64-bit integer.
|
|
10
|
+
def integer
|
|
11
|
+
(self.high << INTEGER_BITS) | self.low
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Sets the high and low portions of this
|
|
15
|
+
# time from the given 64-bit integer.
|
|
16
|
+
def integer= aValue
|
|
17
|
+
self.low = aValue & INTEGER_MASK
|
|
18
|
+
self.high = (aValue >> INTEGER_BITS) & INTEGER_MASK
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
alias to_i integer
|
|
22
|
+
alias to_f real
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class S_vpi_value
|
|
26
|
+
# Attempts to detect the format of the given value.
|
|
27
|
+
# Returns +nil+ if detection is not possible.
|
|
28
|
+
def S_vpi_value.detect_format aValue
|
|
29
|
+
if aValue.respond_to? :to_int
|
|
30
|
+
VpiIntVal
|
|
31
|
+
|
|
32
|
+
elsif aValue.respond_to? :to_float
|
|
33
|
+
VpiRealVal
|
|
34
|
+
|
|
35
|
+
elsif aValue.respond_to? :to_str
|
|
36
|
+
VpiStringVal
|
|
37
|
+
|
|
38
|
+
elsif aValue.is_a? S_vpi_time
|
|
39
|
+
VpiTimeVal
|
|
40
|
+
|
|
41
|
+
elsif aValue.is_a? S_vpi_vecval
|
|
42
|
+
VpiVectorVal
|
|
43
|
+
|
|
44
|
+
elsif aValue.is_a? S_vpi_strengthval
|
|
45
|
+
VpiStrengthVal
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Writes the given value, which has the given format.
|
|
50
|
+
def write aValue, aFormat
|
|
51
|
+
case aFormat
|
|
52
|
+
when VpiBinStrVal, VpiOctStrVal, VpiDecStrVal, VpiHexStrVal, VpiStringVal
|
|
53
|
+
value.str = aValue.to_s
|
|
54
|
+
|
|
55
|
+
when VpiScalarVal
|
|
56
|
+
value.scalar = aValue.to_i
|
|
57
|
+
|
|
58
|
+
when VpiIntVal
|
|
59
|
+
value.integer = aValue.to_i
|
|
60
|
+
|
|
61
|
+
when VpiRealVal
|
|
62
|
+
value.real = aValue.to_f
|
|
63
|
+
|
|
64
|
+
when VpiTimeVal
|
|
65
|
+
value.time = aValue
|
|
66
|
+
|
|
67
|
+
when VpiVectorVal
|
|
68
|
+
value.vector = aValue
|
|
69
|
+
|
|
70
|
+
when VpiStrengthVal
|
|
71
|
+
value.strength = aValue
|
|
72
|
+
|
|
73
|
+
else
|
|
74
|
+
raise "unknown format: #{aFormat.inspect}"
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Returns the value in the given format.
|
|
79
|
+
def read aFormat = self.format
|
|
80
|
+
case aFormat
|
|
81
|
+
when VpiBinStrVal, VpiOctStrVal, VpiDecStrVal, VpiHexStrVal, VpiStringVal
|
|
82
|
+
value.str.to_s
|
|
83
|
+
|
|
84
|
+
when VpiScalarVal
|
|
85
|
+
value.scalar.to_i
|
|
86
|
+
|
|
87
|
+
when VpiIntVal
|
|
88
|
+
value.integer.to_i
|
|
89
|
+
|
|
90
|
+
when VpiRealVal
|
|
91
|
+
value.real.to_f
|
|
92
|
+
|
|
93
|
+
when VpiTimeVal
|
|
94
|
+
value.time
|
|
95
|
+
|
|
96
|
+
when VpiVectorVal
|
|
97
|
+
value.vector
|
|
98
|
+
|
|
99
|
+
when VpiStrengthVal
|
|
100
|
+
value.strength
|
|
101
|
+
|
|
102
|
+
else
|
|
103
|
+
raise "unknown format: #{aFormat.inspect}"
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# make VPI structs more accessible by allowing their
|
|
109
|
+
# members to be initialized through the constructor
|
|
110
|
+
constants.grep(/^S_/).each do |s|
|
|
111
|
+
const_get(s).class_eval do
|
|
112
|
+
alias __struct__initialize initialize
|
|
113
|
+
|
|
114
|
+
def initialize aMembers = {} #:nodoc:
|
|
115
|
+
__struct__initialize
|
|
116
|
+
|
|
117
|
+
aMembers.each_pair do |k, v|
|
|
118
|
+
__send__("#{k}=", v)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# A utility layer which transforms the VPI interface
|
|
2
|
+
# into one that is more suitable for Ruby.
|
|
3
|
+
#--
|
|
4
|
+
# Copyright 2006 Suraj N. Kurapati
|
|
5
|
+
# See the file named LICENSE for details.
|
|
6
|
+
|
|
7
|
+
module VPI
|
|
8
|
+
# restore compatibility with the C language version of VPI: in Ruby,
|
|
9
|
+
# constants are capitalized, whereas in C, they do not have to be.
|
|
10
|
+
constants.grep(/^(S_|Cb|Vpi)/).each do |name|
|
|
11
|
+
meth = name[0,1].downcase << name[1..-1]
|
|
12
|
+
value = const_get(name)
|
|
13
|
+
|
|
14
|
+
define_method meth do value end
|
|
15
|
+
module_function meth
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Number of bits in PLI_INT32.
|
|
19
|
+
INTEGER_BITS = 32
|
|
20
|
+
|
|
21
|
+
# Lowest upper bound of PLI_INT32.
|
|
22
|
+
INTEGER_LIMIT = 2 ** INTEGER_BITS
|
|
23
|
+
|
|
24
|
+
# Bit-mask capable of capturing PLI_INT32.
|
|
25
|
+
INTEGER_MASK = INTEGER_LIMIT - 1
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
module RubyVPI
|
|
29
|
+
SIMULATOR = ENV['RUBYVPI_SIMULATOR'].to_sym
|
|
30
|
+
USE_DEBUGGER = ENV['DEBUGGER'].to_i == 1
|
|
31
|
+
USE_COVERAGE = ENV['COVERAGE'].to_i == 1
|
|
32
|
+
USE_PROTOTYPE = ENV['PROTOTYPE'].to_i == 1
|
|
33
|
+
USE_PROFILER = ENV['PROFILER'].to_i == 1
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
require 'thread'
|
|
37
|
+
require 'ruby-vpi/core/struct'
|
|
38
|
+
require 'ruby-vpi/core/handle'
|
|
39
|
+
require 'ruby-vpi/core/edge'
|
|
40
|
+
require 'ruby-vpi/core/callback'
|
|
41
|
+
require 'ruby-vpi/core/scheduler'
|
data/lib/ruby-vpi/rcov.rb
CHANGED
|
@@ -23,23 +23,36 @@ require 'rcov'
|
|
|
23
23
|
require 'rcov/report'
|
|
24
24
|
|
|
25
25
|
|
|
26
|
+
module RubyVPI::Coverage #:nodoc:
|
|
27
|
+
end
|
|
28
|
+
|
|
26
29
|
module RubyVPI
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
module Coverage
|
|
31
|
+
@@analyzer = Rcov::CodeCoverageAnalyzer.new
|
|
32
|
+
|
|
33
|
+
def Coverage.start
|
|
34
|
+
@@analyzer.install_hook
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def Coverage.stop
|
|
38
|
+
@@analyzer.remove_hook
|
|
39
|
+
end
|
|
29
40
|
|
|
30
|
-
COVERAGE_ANALYSIS_HANDLERS = []
|
|
31
41
|
|
|
32
|
-
|
|
33
|
-
COVERAGE_ANALYSIS.remove_hook
|
|
42
|
+
@@handlers = []
|
|
34
43
|
|
|
35
|
-
|
|
36
|
-
|
|
44
|
+
# Invokes the given block after code coverage analysis has completed.
|
|
45
|
+
def Coverage.attach &aBlock # :yield: Rcov::CodeCoverageAnalyzer
|
|
46
|
+
raise ArgumentError unless block_given?
|
|
47
|
+
@@handlers << aBlock if aBlock
|
|
37
48
|
end
|
|
38
|
-
end
|
|
39
49
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
50
|
+
at_exit do
|
|
51
|
+
Coverage.stop
|
|
52
|
+
|
|
53
|
+
@@handlers.each do |h|
|
|
54
|
+
h.call @@analyzer
|
|
55
|
+
end
|
|
56
|
+
end
|
|
44
57
|
end
|
|
45
58
|
end
|
data/lib/ruby-vpi/runner.rb
CHANGED
|
@@ -26,7 +26,7 @@ require 'ruby-vpi/util'
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
# auto-detect and set default parameters
|
|
29
|
-
runnerPath = caller.grep(/runner
|
|
29
|
+
runnerPath = caller.grep(/runner\.rake/).first.rstrip_from(':')
|
|
30
30
|
@target = File.basename(runnerPath).rstrip_from('_')
|
|
31
31
|
|
|
32
32
|
task :setup
|
|
@@ -84,6 +84,15 @@ def expand_incdir_options aSimId # :nodoc:
|
|
|
84
84
|
@incdirs.map {|i| prefix + i}
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
+
# Creates a new task for running the given simulator.
|
|
88
|
+
def sim_task aSimId #:nodoc:
|
|
89
|
+
desc "Simulate with #{RubyVPI::SIMULATORS[aSimId].name}."
|
|
90
|
+
task aSimId => :setup do
|
|
91
|
+
ENV['RUBYVPI_SIMULATOR'] = aSimId.to_s
|
|
92
|
+
yield aSimId
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
87
96
|
|
|
88
97
|
desc "Show a list of available tasks."
|
|
89
98
|
task :default do
|
|
@@ -92,24 +101,22 @@ task :default do
|
|
|
92
101
|
end
|
|
93
102
|
|
|
94
103
|
|
|
95
|
-
|
|
96
|
-
task :cver => :setup do
|
|
104
|
+
sim_task :cver do |id|
|
|
97
105
|
sh 'cver',
|
|
98
|
-
"+loadvpi=#{object_file_path(
|
|
99
|
-
SIMULATOR_ARGUMENTS[
|
|
100
|
-
expand_incdir_options(
|
|
106
|
+
"+loadvpi=#{object_file_path(id)}:#{LOADER_FUNC}",
|
|
107
|
+
SIMULATOR_ARGUMENTS[id],
|
|
108
|
+
expand_incdir_options(id),
|
|
101
109
|
@sources
|
|
102
110
|
end
|
|
103
111
|
|
|
104
112
|
CLOBBER.include 'verilog.log'
|
|
105
113
|
|
|
106
114
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
cp object_file_path(:ivl), 'ruby-vpi.vpi'
|
|
115
|
+
sim_task :ivl do |id|
|
|
116
|
+
cp object_file_path(id), 'ruby-vpi.vpi'
|
|
110
117
|
sh %w[iverilog -mruby-vpi],
|
|
111
|
-
SIMULATOR_ARGUMENTS[
|
|
112
|
-
expand_incdir_options(
|
|
118
|
+
SIMULATOR_ARGUMENTS[id],
|
|
119
|
+
expand_incdir_options(id),
|
|
113
120
|
@sources
|
|
114
121
|
sh 'vvp -M. a.out'
|
|
115
122
|
end
|
|
@@ -117,28 +124,26 @@ end
|
|
|
117
124
|
CLEAN.include 'ruby-vpi.vpi', 'a.out'
|
|
118
125
|
|
|
119
126
|
|
|
120
|
-
|
|
121
|
-
task :vcs => :setup do
|
|
127
|
+
sim_task :vcs do |id|
|
|
122
128
|
sh %w[vcs -R +v2k +vpi +cli],
|
|
123
129
|
'-P', File.join(File.dirname(__FILE__), 'pli.tab'),
|
|
124
|
-
'-load', "#{object_file_path(
|
|
130
|
+
'-load', "#{object_file_path(id)}:#{LOADER_FUNC}",
|
|
125
131
|
('-full64' if @archIs64),
|
|
126
|
-
SIMULATOR_ARGUMENTS[
|
|
127
|
-
expand_incdir_options(
|
|
132
|
+
SIMULATOR_ARGUMENTS[id],
|
|
133
|
+
expand_incdir_options(id),
|
|
128
134
|
@sources
|
|
129
135
|
end
|
|
130
136
|
|
|
131
137
|
CLEAN.include 'csrc', 'simv*'
|
|
132
138
|
|
|
133
139
|
|
|
134
|
-
|
|
135
|
-
task :vsim => :setup do
|
|
140
|
+
sim_task :vsim do |id|
|
|
136
141
|
sh 'vlib work'
|
|
137
|
-
sh 'vlog', expand_incdir_options(
|
|
142
|
+
sh 'vlog', expand_incdir_options(id), @sources
|
|
138
143
|
sh %w[vsim -c],
|
|
139
144
|
'-do', 'run -all; exit',
|
|
140
|
-
'-pli', object_file_path(
|
|
141
|
-
SIMULATOR_ARGUMENTS[
|
|
145
|
+
'-pli', object_file_path(id),
|
|
146
|
+
SIMULATOR_ARGUMENTS[id],
|
|
142
147
|
@target
|
|
143
148
|
end
|
|
144
149
|
|
|
@@ -146,13 +151,12 @@ CLEAN.include 'work', 'vsim.wlf'
|
|
|
146
151
|
CLOBBER.include 'transcript'
|
|
147
152
|
|
|
148
153
|
|
|
149
|
-
|
|
150
|
-
task :ncsim => :setup do
|
|
154
|
+
sim_task :ncsim do |id|
|
|
151
155
|
sh %w[ncverilog +access+rwc +plinowarn],
|
|
152
|
-
"+loadvpi=#{object_file_path(
|
|
156
|
+
"+loadvpi=#{object_file_path(id)}:#{LOADER_FUNC}",
|
|
153
157
|
('+nc64bit' if @archIs64),
|
|
154
|
-
SIMULATOR_ARGUMENTS[
|
|
155
|
-
expand_incdir_options(
|
|
158
|
+
SIMULATOR_ARGUMENTS[id],
|
|
159
|
+
expand_incdir_options(id),
|
|
156
160
|
@sources
|
|
157
161
|
end
|
|
158
162
|
|