origen_sim 0.15.0 → 0.16.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.
- checksums.yaml +4 -4
- data/config/application.rb +1 -1
- data/config/shared_commands.rb +13 -4
- data/config/version.rb +1 -1
- data/ext/bridge.c +521 -272
- data/ext/bridge.h +2 -0
- data/ext/defines.h.erb +8 -0
- data/ext/origen.c +2 -0
- data/lib/origen_sim.rb +21 -1
- data/lib/origen_sim/origen/pins/pin.rb +7 -2
- data/lib/origen_sim/origen_testers/api.rb +11 -2
- data/lib/origen_sim/simulation.rb +34 -4
- data/lib/origen_sim/simulator.rb +227 -19
- data/lib/origen_sim/stderr_reader.rb +9 -3
- data/lib/origen_sim/stdout_reader.rb +35 -12
- data/lib/origen_sim/tester.rb +209 -29
- data/lib/origen_sim_dev/dut.rb +31 -29
- data/pattern/test.rb +2 -0
- data/templates/origen_guides/simulation/debugging.md.erb +123 -6
- data/templates/origen_guides/simulation/environment.md.erb +3 -6
- data/templates/origen_guides/simulation/log.md.erb +1 -1
- data/templates/origen_guides/simulation/patterns.md.erb +35 -0
- data/templates/rtl_v/origen.v.erb +14 -49
- metadata +5 -5
@@ -7,6 +7,7 @@ module OrigenSim
|
|
7
7
|
@socket = socket
|
8
8
|
@continue = true
|
9
9
|
@logged_errors = false
|
10
|
+
@last_message_at = Time.now
|
10
11
|
super do
|
11
12
|
begin
|
12
13
|
while @continue
|
@@ -17,12 +18,13 @@ module OrigenSim
|
|
17
18
|
!OrigenSim.stderr_string_exceptions.any? { |s| s.is_a?(Regexp) ? s.match?(line) : line =~ /#{s}/i }
|
18
19
|
# We're failing on stderr, so print its results and log as errors if its not an exception.
|
19
20
|
@logged_errors = true
|
20
|
-
Origen.log.error "(STDERR): #{line}"
|
21
|
+
Origen.log.error "(STDERR): #{line}", from_origen_sim: true
|
21
22
|
elsif OrigenSim.verbose?
|
22
|
-
Origen.log.info line
|
23
|
+
Origen.log.info line, from_origen_sim: true
|
23
24
|
else
|
24
|
-
Origen.log.debug line
|
25
|
+
Origen.log.debug line, from_origen_sim: true
|
25
26
|
end
|
27
|
+
@last_message_at = Time.now
|
26
28
|
end
|
27
29
|
end
|
28
30
|
rescue IOError => e
|
@@ -36,5 +38,9 @@ module OrigenSim
|
|
36
38
|
def stop
|
37
39
|
@continue = false
|
38
40
|
end
|
41
|
+
|
42
|
+
def time_since_last_message
|
43
|
+
Time.now - @last_message_at
|
44
|
+
end
|
39
45
|
end
|
40
46
|
end
|
@@ -3,31 +3,50 @@ module OrigenSim
|
|
3
3
|
class StdoutReader < Thread
|
4
4
|
attr_reader :socket, :logged_errors
|
5
5
|
|
6
|
-
def initialize(socket)
|
6
|
+
def initialize(socket, simulator)
|
7
7
|
@socket = socket
|
8
8
|
@continue = true
|
9
9
|
@logged_errors = false
|
10
|
+
@last_message_at = Time.now
|
10
11
|
super do
|
11
12
|
begin
|
12
13
|
while @continue
|
13
14
|
line = @socket.gets
|
14
15
|
if line
|
15
16
|
line = line.chomp
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
17
|
+
# If line has been sent from Origen for logging
|
18
|
+
# https://rubular.com/r/1czQZnlhBq9YtK
|
19
|
+
if line =~ /^!(\d)!\[\s*((\d+),)?\s*(\d+)\]\s*(.*)/
|
20
|
+
if Regexp.last_match(3)
|
21
|
+
time_in_sim_units = (Regexp.last_match(3).to_i << 32) | Regexp.last_match(4).to_i
|
22
|
+
time_in_ns = simulator.send(:simtime_units_to_ns, time_in_sim_units)
|
23
|
+
else
|
24
|
+
# Messages sent from the Origen testbench already have a timestamp in ns
|
25
|
+
time_in_ns = Regexp.last_match(4).to_i
|
26
|
+
end
|
27
|
+
msg = "#{time_in_ns}".rjust(11) + ' ns: ' + Regexp.last_match(5)
|
28
|
+
|
29
|
+
Origen.log.send(Simulator::LOG_CODES_[Regexp.last_match(1).to_i], msg, from_origen_sim: true)
|
30
|
+
|
31
|
+
simulator.send(:max_error_abort) if line =~ /!MAX_ERROR_ABORT!/
|
23
32
|
else
|
24
|
-
if OrigenSim.
|
25
|
-
OrigenSim.
|
26
|
-
|
33
|
+
if OrigenSim.error_strings.any? { |s| s.is_a?(Regexp) ? s.match?(line) : line =~ /#{s}/i } &&
|
34
|
+
!OrigenSim.error_string_exceptions.any? { |s| s.is_a?(Regexp) ? s.match?(line) : line =~ /#{s}/i }
|
35
|
+
@logged_errors = true
|
36
|
+
Origen.log.error "(STDOUT): #{line}", from_origen_sim: true
|
37
|
+
elsif OrigenSim.warning_strings.any? { |s| s.is_a?(Regexp) ? s.match?(line) : line =~ /#{s}/i } &&
|
38
|
+
!OrigenSim.warning_string_exceptions.any? { |s| s.is_a?(Regexp) ? s.match?(line) : line =~ /#{s}/i }
|
39
|
+
Origen.log.warn line, from_origen_sim: true
|
27
40
|
else
|
28
|
-
|
41
|
+
if OrigenSim.verbose? ||
|
42
|
+
OrigenSim.log_strings.any? { |s| s.is_a?(Regexp) ? s.match?(line) : line =~ /#{s}/i }
|
43
|
+
Origen.log.info line, from_origen_sim: true
|
44
|
+
else
|
45
|
+
Origen.log.debug line, from_origen_sim: true
|
46
|
+
end
|
29
47
|
end
|
30
48
|
end
|
49
|
+
@last_message_at = Time.now
|
31
50
|
end
|
32
51
|
end
|
33
52
|
rescue IOError => e
|
@@ -41,5 +60,9 @@ module OrigenSim
|
|
41
60
|
def stop
|
42
61
|
@continue = false
|
43
62
|
end
|
63
|
+
|
64
|
+
def time_since_last_message
|
65
|
+
Time.now - @last_message_at
|
66
|
+
end
|
44
67
|
end
|
45
68
|
end
|
data/lib/origen_sim/tester.rb
CHANGED
@@ -19,11 +19,6 @@ module OrigenSim
|
|
19
19
|
super()
|
20
20
|
end
|
21
21
|
|
22
|
-
# Returns the current cycle count
|
23
|
-
def cycle_count
|
24
|
-
@cycle_count || 0
|
25
|
-
end
|
26
|
-
|
27
22
|
def simulator
|
28
23
|
OrigenSim.simulator
|
29
24
|
end
|
@@ -43,9 +38,9 @@ module OrigenSim
|
|
43
38
|
end
|
44
39
|
@sync_pins.map do |pin|
|
45
40
|
if @sync_cycles.size == 1
|
46
|
-
simulator.peek("
|
41
|
+
simulator.peek("#{simulator.testbench_top}.pins.#{pin.id}.sync_memory[0]")
|
47
42
|
else
|
48
|
-
simulator.peek("
|
43
|
+
simulator.peek("#{simulator.testbench_top}.pins.#{pin.id}.sync_memory[#{@sync_cycles - 1}:0]")
|
49
44
|
end
|
50
45
|
end
|
51
46
|
end
|
@@ -62,9 +57,9 @@ module OrigenSim
|
|
62
57
|
end
|
63
58
|
|
64
59
|
# Flush any buffered simulation output, this should cause live waveviewers to
|
65
|
-
# reflect the latest state
|
66
|
-
def flush
|
67
|
-
simulator.flush
|
60
|
+
# reflect the latest state and the console and log files to update
|
61
|
+
def flush(*args)
|
62
|
+
simulator.flush(*args)
|
68
63
|
end
|
69
64
|
|
70
65
|
def set_timeset(name, period_in_ns)
|
@@ -79,24 +74,35 @@ module OrigenSim
|
|
79
74
|
|
80
75
|
# This method intercepts vector data from Origen, removes white spaces and compresses repeats
|
81
76
|
def push_vector(options)
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
@after_next_vector
|
94
|
-
|
77
|
+
if simulator.simulation.max_errors_exceeded
|
78
|
+
fail Origen::Generator::AbortError, 'The max error count has been exceeded in the simulation'
|
79
|
+
else
|
80
|
+
unless options[:timeset]
|
81
|
+
puts 'No timeset defined!'
|
82
|
+
puts 'Add one to your top level startup method or target like this:'
|
83
|
+
puts '$tester.set_timeset("nvmbist", 40) # Where 40 is the period in ns'
|
84
|
+
exit 1
|
85
|
+
end
|
86
|
+
flush_comments unless @comment_buffer.empty?
|
87
|
+
simulator.cycle(options[:repeat] || 1)
|
88
|
+
if @after_next_vector
|
89
|
+
@after_next_vector.call(@after_next_vector_args)
|
90
|
+
@after_next_vector = nil
|
91
|
+
end
|
95
92
|
end
|
96
93
|
end
|
97
94
|
|
98
95
|
def c1(msg, options = {})
|
99
|
-
|
96
|
+
if @step_comment_on
|
97
|
+
simulator.log msg
|
98
|
+
@comment_buffer << msg
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def ss(msg = nil)
|
103
|
+
simulator.log '=' * 70
|
104
|
+
super
|
105
|
+
simulator.log '=' * 70
|
100
106
|
end
|
101
107
|
|
102
108
|
def loop_vectors(name, number_of_loops, options = {})
|
@@ -132,7 +138,7 @@ module OrigenSim
|
|
132
138
|
end
|
133
139
|
end
|
134
140
|
end
|
135
|
-
if simulator.sync_active?
|
141
|
+
if simulator.sync_active? && @sync_cycles
|
136
142
|
@sync_cycles += 1
|
137
143
|
pins.each do |pin|
|
138
144
|
@sync_pins << pin unless @sync_pins.include?(pin)
|
@@ -222,12 +228,186 @@ module OrigenSim
|
|
222
228
|
|
223
229
|
def wait(*args)
|
224
230
|
super
|
225
|
-
|
231
|
+
if Origen.running_interactively? ||
|
232
|
+
(defined?(Byebug) && Byebug.try(:mode) == :attached)
|
233
|
+
flush quiet: true
|
234
|
+
end
|
226
235
|
end
|
227
236
|
|
228
|
-
|
229
|
-
|
230
|
-
|
237
|
+
def log_file_written(path)
|
238
|
+
simulator.simulation.log_files << path if simulator.simulation
|
239
|
+
end
|
240
|
+
|
241
|
+
def read_register(reg_or_val, options = {})
|
242
|
+
# This could be called multiple times for the same transaction
|
243
|
+
if read_reg_open?
|
244
|
+
yield
|
245
|
+
else
|
246
|
+
@read_reg_meta_supplied = false
|
247
|
+
@read_reg_open = true
|
248
|
+
@read_reg_cycles = {}
|
249
|
+
unless @supports_transactions_set
|
250
|
+
@supports_transactions = dut_version > '0.15.0'
|
251
|
+
@supports_transactions_set = true
|
252
|
+
end
|
253
|
+
|
254
|
+
if reg_or_val.respond_to?(:named_bits)
|
255
|
+
bit_names = reg_or_val.named_bits.map { |name, bits| name }.uniq
|
256
|
+
expected = bit_names.map do |name|
|
257
|
+
bits = reg_or_val.bits(name)
|
258
|
+
if bits.is_to_be_read?
|
259
|
+
[name, bits.status_str(:read)]
|
260
|
+
end
|
261
|
+
end.compact
|
262
|
+
|
263
|
+
# Save which bits are being read for later, the driver performing the read will
|
264
|
+
# clear the register flags
|
265
|
+
read_flags = reg_or_val.map(&:is_to_be_read?)
|
266
|
+
end
|
267
|
+
|
268
|
+
error_count = simulator.error_count
|
269
|
+
|
270
|
+
simulator.start_read_reg_transaction if @supports_transactions
|
271
|
+
|
272
|
+
yield
|
273
|
+
|
274
|
+
if @supports_transactions
|
275
|
+
errors_captured, exceeded_max_errors, errors = *(simulator.stop_read_reg_transaction)
|
276
|
+
end
|
277
|
+
|
278
|
+
@read_reg_open = false
|
279
|
+
|
280
|
+
if simulator.error_count > error_count
|
281
|
+
if @supports_transactions
|
282
|
+
actual_data_available = true
|
283
|
+
if exceeded_max_errors
|
284
|
+
Origen.log.warning 'The number of errors in this transaction exceeded the capture buffer, the actual data reported here may not be accurate'
|
285
|
+
end
|
286
|
+
out_of_sync = simulator.simulation.cycle_count != simulator.cycle_count
|
287
|
+
if out_of_sync
|
288
|
+
Origen.log.warning 'Something has gone wrong and Origen and the simulator do not agree on the current cycle number, it is not possible to resolve the actual data'
|
289
|
+
actual_data_available = false
|
290
|
+
else
|
291
|
+
diffs = []
|
292
|
+
errors.each do |error|
|
293
|
+
if c = read_reg_cycles[error[:cycle]]
|
294
|
+
if p = c[simulator.pins_by_rtl_name[error[:pin_name]]]
|
295
|
+
if p[:position]
|
296
|
+
diffs << [p[:position], error[:recieved], error[:expected]]
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
if diffs.empty?
|
302
|
+
if @read_reg_meta_supplied
|
303
|
+
Origen.log.warning 'It looks like the miscompare(s) occurred on pins/cycles that are not associated with register data'
|
304
|
+
else
|
305
|
+
Origen.log.warning 'It looks like your current read register driver does not provide the necessary meta-data to map these errors to an actual register value'
|
306
|
+
end
|
307
|
+
actual_data_available = false
|
308
|
+
end
|
309
|
+
end
|
310
|
+
else
|
311
|
+
Origen.log.warning 'Your DUT needs to be compiled with a newer version of OrigenSim to support reporting of the actual read data from this failed transaction'
|
312
|
+
actual_data_available = false
|
313
|
+
end
|
314
|
+
|
315
|
+
# If a register object has been supplied...
|
316
|
+
if read_flags
|
317
|
+
Origen.log.error "Errors occurred reading register #{reg_or_val.path}:"
|
318
|
+
if actual_data_available
|
319
|
+
actual = nil
|
320
|
+
reg_or_val.preserve_flags do
|
321
|
+
reg_or_val.each_with_index do |bit, i|
|
322
|
+
bit.read if read_flags[i]
|
323
|
+
end
|
324
|
+
|
325
|
+
diffs.each do |position, received, expected|
|
326
|
+
reg_or_val[position].data = received
|
327
|
+
end
|
328
|
+
|
329
|
+
actual = bit_names.map do |name|
|
330
|
+
bits = reg_or_val.bits(name)
|
331
|
+
if bits.is_to_be_read?
|
332
|
+
[name, bits.status_str(:read)]
|
333
|
+
end
|
334
|
+
end.compact
|
335
|
+
|
336
|
+
# Put the data back so the application behaves as it would if generating
|
337
|
+
# for a non-simulation tester target
|
338
|
+
diffs.each do |position, received, expected|
|
339
|
+
reg_or_val[position].data = expected
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
expected.each do |name, expected|
|
345
|
+
msg = "#{reg_or_val.path}.#{name}: expected #{expected}"
|
346
|
+
if actual_data_available
|
347
|
+
received_ = nil
|
348
|
+
actual.each do |name2, received|
|
349
|
+
if name == name2
|
350
|
+
received_ = received
|
351
|
+
msg += " received #{received}"
|
352
|
+
end
|
353
|
+
end
|
354
|
+
if expected == received_
|
355
|
+
Origen.log.info msg
|
356
|
+
else
|
357
|
+
Origen.log.error msg
|
358
|
+
end
|
359
|
+
else
|
360
|
+
msg += " received #{expected}" if @read_reg_meta_supplied
|
361
|
+
Origen.log.error msg
|
362
|
+
end
|
363
|
+
end
|
364
|
+
else
|
365
|
+
Origen.log.error 'Errors occurred while reading a register:'
|
366
|
+
msg = "expected #{reg_or_val.to_s(16).upcase}"
|
367
|
+
if actual_data_available
|
368
|
+
actual = reg_or_val
|
369
|
+
diffs.each do |position, received, expected|
|
370
|
+
if received == 1
|
371
|
+
actual |= (1 << position)
|
372
|
+
else
|
373
|
+
lower = actual[(position - 1)..0]
|
374
|
+
actual = actual >> (position + 1)
|
375
|
+
actual = actual << (position + 1)
|
376
|
+
actual |= lower
|
377
|
+
end
|
378
|
+
end
|
379
|
+
msg += " received #{actual.to_s(16).upcase}"
|
380
|
+
else
|
381
|
+
msg += " received #{reg_or_val.to_s(16).upcase}" if @read_reg_meta_supplied
|
382
|
+
end
|
383
|
+
Origen.log.error msg
|
384
|
+
end
|
385
|
+
|
386
|
+
Origen.log.error
|
387
|
+
caller.each do |line|
|
388
|
+
if Pathname.new(line.split(':').first).expand_path.to_s =~ /^#{Origen.root}(?!(\/lbin|\/vendor\/gems)).*$/
|
389
|
+
Origen.log.error line
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
def read_reg_open?
|
397
|
+
@read_reg_open
|
398
|
+
end
|
399
|
+
|
400
|
+
def read_reg_cycles
|
401
|
+
@read_reg_cycles
|
402
|
+
end
|
403
|
+
|
404
|
+
def cycle_count
|
405
|
+
simulator.simulation.cycle_count
|
406
|
+
end
|
407
|
+
|
408
|
+
def read_reg_meta_supplied=(val)
|
409
|
+
@read_reg_meta_supplied = val
|
410
|
+
end
|
231
411
|
|
232
412
|
private
|
233
413
|
|
data/lib/origen_sim_dev/dut.rb
CHANGED
@@ -121,37 +121,39 @@ module OrigenSimDev
|
|
121
121
|
end
|
122
122
|
|
123
123
|
def read_register(reg, options = {})
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
124
|
+
tester.read_register(reg, options) do
|
125
|
+
# Special read for this register to test sync'ing over a parallel
|
126
|
+
if reg.id == :parallel_read
|
127
|
+
pins = []
|
128
|
+
reg.shift_out_with_index do |bit, i|
|
129
|
+
if bit.is_to_be_stored?
|
130
|
+
pins << dut.pins(:dout)[i]
|
131
|
+
end
|
130
132
|
end
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
dut.pins(:dout).dont_care
|
135
|
-
else
|
136
|
-
if reg.path =~ /ip(\d)/
|
137
|
-
ir_val = 0b0100 | Regexp.last_match(1).to_i
|
138
|
-
jtag.write_ir(ir_val, size: 4)
|
139
|
-
ip = reg.parent
|
140
|
-
ip.dr.bits(:write).write(0)
|
141
|
-
ip.dr.bits(:address).write(reg.address)
|
142
|
-
ip.dr.bits(:data).write(0)
|
143
|
-
jtag.write_dr(ip.dr)
|
144
|
-
ip.dr.bits(:data).copy_all(reg)
|
145
|
-
jtag.read_dr(ip.dr)
|
133
|
+
tester.store_next_cycle(*pins.reverse)
|
134
|
+
1.cycle
|
135
|
+
dut.pins(:dout).dont_care
|
146
136
|
else
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
137
|
+
if reg.path =~ /ip(\d)/
|
138
|
+
ir_val = 0b0100 | Regexp.last_match(1).to_i
|
139
|
+
jtag.write_ir(ir_val, size: 4)
|
140
|
+
ip = reg.parent
|
141
|
+
ip.dr.bits(:write).write(0)
|
142
|
+
ip.dr.bits(:address).write(reg.address)
|
143
|
+
ip.dr.bits(:data).write(0)
|
144
|
+
jtag.write_dr(ip.dr)
|
145
|
+
ip.dr.bits(:data).copy_all(reg)
|
146
|
+
jtag.read_dr(ip.dr)
|
147
|
+
else
|
148
|
+
jtag.write_ir(0x8, size: 4)
|
149
|
+
dr.rg_enable.write(1)
|
150
|
+
dr.rg_read.write(1)
|
151
|
+
dr.rg_addr.write(reg.address)
|
152
|
+
jtag.write_dr(dr)
|
153
|
+
dr.rg_enable.write(0)
|
154
|
+
dr.rg_data.copy_all(reg)
|
155
|
+
jtag.read_dr(dr)
|
156
|
+
end
|
155
157
|
end
|
156
158
|
end
|
157
159
|
end
|