origen_sim 0.16.1 → 0.20.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.
@@ -428,8 +428,8 @@ module OrigenSim
428
428
  edir = Pathname.new(wave_config_dir).relative_path_from(Pathname.pwd)
429
429
  cmd = "cd #{edir} && "
430
430
  if configuration[:verdi]
431
- unless ENV['VCS_HOME'] && ENV['LD_LIBRARY_PATH']
432
- puts 'Please make sure the VCS_HOME and LD_LIBRARY PATH are setup correctly before using Verdi'
431
+ unless ENV['VCS_HOME']
432
+ Origen.log.warning "Your environment doesn't define VCS_HOME, you will probably need that to run Verdi"
433
433
  end
434
434
  edir = Pathname.new(wave_config_dir).relative_path_from(Pathname.pwd)
435
435
  cmd = "cd #{edir} && "
@@ -778,7 +778,7 @@ module OrigenSim
778
778
  # set up internal handles to efficiently access them
779
779
  def define_pins
780
780
  @pins_by_rtl_name = {}
781
- dut.rtl_pins.each_with_index do |(name, pin), i|
781
+ dut.rtl_pins(type: :digital).each_with_index do |(name, pin), i|
782
782
  @pins_by_rtl_name[pin.rtl_name] = pin
783
783
  pin.simulation_index = i
784
784
  put("0^#{pin.rtl_name}^#{i}^#{pin.drive_wave.index}^#{pin.compare_wave.index}")
@@ -865,6 +865,7 @@ module OrigenSim
865
865
 
866
866
  def error(message)
867
867
  simulation.logged_errors = true
868
+ poke "#{testbench_top}.debug.errors", error_count + 1
868
869
  log message, :error
869
870
  end
870
871
 
@@ -877,87 +878,82 @@ module OrigenSim
877
878
  # resolve to a valid node
878
879
  #
879
880
  # The value is returned as an instance of Origen::Value
880
- def peek(net)
881
- # The Verilog spec does not specify that underlying VPI put method should
882
- # handle a part select, so some simulators do not handle it. Therefore we
883
- # deal with it here to ensure cross simulator compatibility.
884
-
885
- # http://rubular.com/r/eTVGzrYmXQ
886
- if net =~ /(.*)\[(\d+):?(\.\.)?(\d*)\]$/
887
- net = Regexp.last_match(1)
888
- msb = Regexp.last_match(2).to_i
889
- lsb = Regexp.last_match(4)
890
- lsb = lsb.empty? ? nil : lsb.to_i
891
- end
892
-
881
+ def peek(net, real = false)
893
882
  sync_up
894
- put("9^#{clean(net)}")
895
- m = get.strip
883
+ if dut_version > '0.19.0'
884
+ if real
885
+ put("9^#{clean(net)}^f")
886
+ m = get.strip
887
+ if m == 'FAIL'
888
+ return nil
889
+ else
890
+ m.to_f
891
+ end
892
+ else
893
+ put("9^#{clean(net)}^i")
894
+ m = get.strip
896
895
 
897
- if m == 'FAIL'
898
- return nil
899
- else
900
- if msb
901
- # Setting a range of bits
902
- if lsb
903
- Origen::Value.new('b' + m[(m.size - 1 - msb)..(m.size - 1 - lsb)])
896
+ if m == 'FAIL'
897
+ Origen.log.warning "Peek of net #{net} failed to return any data!"
898
+ return nil
904
899
  else
905
- Origen::Value.new('b' + m[m.size - 1 - msb])
900
+ Origen::Value.new('b' + m)
906
901
  end
902
+ end
903
+ else
904
+ put("9^#{clean(net)}")
905
+ m = get.strip
906
+
907
+ if m == 'FAIL'
908
+ Origen.log.warning "Peek of net #{net} failed to return any data!"
909
+ return nil
907
910
  else
908
911
  Origen::Value.new('b' + m)
909
912
  end
910
913
  end
911
914
  end
912
915
 
916
+ def peek_real(net)
917
+ peek(net, true)
918
+ end
919
+
913
920
  # Forces the given value to the given net.
914
921
  # Note that no error checking is done and no error will be communicated if an illegal
915
922
  # net is supplied. The user should follow up with a peek if they want to verify that
916
923
  # the poke was applied.
917
924
  def poke(net, value)
918
- # The Verilog spec does not specify that underlying VPI put method should
919
- # handle a part select, so some simulators do not handle it. Therefore we
920
- # deal with it here to ensure cross simulator compatibility.
921
-
922
- # http://rubular.com/r/eTVGzrYmXQ
923
- if !config[:vendor] == :synopsys && net =~ /(.*)\[(\d+):?(\.\.)?(\d*)\]$/
924
- path = Regexp.last_match(1)
925
- msb = Regexp.last_match(2).to_i
926
- lsb = Regexp.last_match(4)
927
- lsb = lsb.empty? ? nil : lsb.to_i
928
-
929
- v = peek(path)
930
- return nil unless v
931
- # Setting a range of bits
932
- if lsb
933
- upper = v >> (msb + 1)
934
- # Make sure value does not overflow
935
- value = value[(msb - lsb)..0]
936
- if lsb == 0
937
- value = (upper << (msb + 1)) | value
938
- else
939
- lower = v[(lsb - 1)..0]
940
- value = (upper << (msb + 1)) |
941
- (value << lsb) | lower
942
- end
925
+ sync_up
926
+ if dut_version > '0.19.0'
927
+ if value.is_a?(Integer)
928
+ put("b^#{clean(net)}^i^#{value}")
929
+ else
930
+ put("b^#{clean(net)}^f^#{value}")
931
+ end
932
+ else
933
+ put("b^#{clean(net)}^#{value}")
934
+ end
935
+ end
943
936
 
944
- # Setting a single bit
937
+ def force(net, value)
938
+ sync_up
939
+ if dut_version > '0.19.0'
940
+ if value.is_a?(Integer)
941
+ put("r^#{clean(net)}^i^#{value}")
945
942
  else
946
- if msb == 0
947
- upper = v >> 1
948
- value = (upper << 1) | value[0]
949
- else
950
- lower = v[(msb - 1)..0]
951
- upper = v >> (msb + 1)
952
- value = (upper << (msb + 1)) |
953
- (value[0] << msb) | lower
954
- end
943
+ put("r^#{clean(net)}^f^#{value}")
955
944
  end
956
- net = path
945
+ else
946
+ OrigenSim.error 'Your DUT needs to be recompiled with OrigenSim >= 0.20.0 to support forcing, force not applied!'
957
947
  end
948
+ end
958
949
 
950
+ def release(net)
959
951
  sync_up
960
- put("b^#{clean(net)}^#{value}")
952
+ if dut_version > '0.19.0'
953
+ put("s^#{clean(net)}")
954
+ else
955
+ OrigenSim.error 'Your DUT needs to be recompiled with OrigenSim >= 0.20.0 to support releasing, force not released!'
956
+ end
961
957
  end
962
958
 
963
959
  def interactive_shutdown
@@ -1124,17 +1120,13 @@ module OrigenSim
1124
1120
  end
1125
1121
 
1126
1122
  def peek_str(signal)
1127
- val = tester.simulator.peek(signal)
1123
+ val = peek(signal)
1128
1124
  unless val.nil?
1129
- puts val
1130
- puts val.class
1131
1125
  # All zeros seems to be what an empty string is returned from the VPI,
1132
1126
  # Otherwise, break the string up into 8-bit chunks and decode the ASCII>
1133
1127
  val = (val.to_s == 'b00000000' ? '' : val.to_s[1..-1].scan(/.{1,8}/).collect { |char| char.to_i(2).chr }.join)
1134
1128
  end
1135
1129
  val
1136
- # puts "Peaking #{signal}: #{a}: #{a.class}"
1137
- # tester.simulator.peek(signal).to_s[1..-1].scan(/.{1,8}/).collect { |char| char.to_i(2).chr }.join
1138
1130
  end
1139
1131
  alias_method :str_peek, :peek_str
1140
1132
  alias_method :peek_string, :peek_str
@@ -1161,8 +1153,8 @@ module OrigenSim
1161
1153
  errors = []
1162
1154
  error_count.times do |i|
1163
1155
  data = get # => "tdo,648,1,0\n"
1164
- pin_name, cycle, expected, recieved = *(data.strip.split(','))
1165
- errors << { pin_name: pin_name, cycle: cycle.to_i, expected: expected.to_i, recieved: recieved.to_i }
1156
+ pin_name, cycle, expected, received = *(data.strip.split(','))
1157
+ errors << { pin_name: pin_name, cycle: cycle.to_i, expected: expected.to_i, received: received.to_i }
1166
1158
  end
1167
1159
  [true, error_count > max_errors, errors]
1168
1160
  end
@@ -1175,6 +1167,14 @@ module OrigenSim
1175
1167
  get.strip.to_i
1176
1168
  end
1177
1169
 
1170
+ # Returns true if the snapshot has been compiled with WREAL support
1171
+ def wreal?
1172
+ return @wreal if defined?(@wreal)
1173
+ @wreal = (dut_version > '0.19.0' &&
1174
+ peek("#{testbench_top}.debug.wreal_enabled").to_i == 1)
1175
+ end
1176
+ alias_method :wreal_enabled?, :wreal?
1177
+
1178
1178
  private
1179
1179
 
1180
1180
  # Will be called when the simulator has aborted due to the max error count being exceeded
@@ -16,6 +16,7 @@ module OrigenSim
16
16
  simulator.configure(opts, &block)
17
17
  @comment_buffer = []
18
18
  @last_comment_size = 0
19
+ @execution_time_in_ns = 0
19
20
  super()
20
21
  end
21
22
 
@@ -38,9 +39,9 @@ module OrigenSim
38
39
  end
39
40
  @sync_pins.map do |pin|
40
41
  if @sync_cycles.size == 1
41
- simulator.peek("#{simulator.testbench_top}.pins.#{pin.id}.sync_memory[0]")
42
+ simulator.peek("#{simulator.testbench_top}.pins.#{pin.id}.sync_memory")[0]
42
43
  else
43
- simulator.peek("#{simulator.testbench_top}.pins.#{pin.id}.sync_memory[#{@sync_cycles - 1}:0]")
44
+ simulator.peek("#{simulator.testbench_top}.pins.#{pin.id}.sync_memory").to_i[(@sync_cycles - 1)..0]
44
45
  end
45
46
  end
46
47
  end
@@ -80,11 +81,13 @@ module OrigenSim
80
81
  unless options[:timeset]
81
82
  puts 'No timeset defined!'
82
83
  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
+ puts 'tester.set_timeset("nvmbist", 40) # Where 40 is the period in ns'
84
85
  exit 1
85
86
  end
86
87
  flush_comments unless @comment_buffer.empty?
87
- simulator.cycle(options[:repeat] || 1)
88
+ repeat = options[:repeat] || 1
89
+ simulator.cycle(repeat)
90
+ @execution_time_in_ns += repeat * tester.timeset.period_in_ns
88
91
  if @after_next_vector
89
92
  @after_next_vector.call(@after_next_vector_args)
90
93
  @after_next_vector = nil
@@ -94,6 +97,7 @@ module OrigenSim
94
97
 
95
98
  def c1(msg, options = {})
96
99
  if @step_comment_on
100
+ PatSeq.add_thread(msg) unless options[:no_thread_id]
97
101
  simulator.log msg
98
102
  @comment_buffer << msg
99
103
  end
@@ -293,7 +297,7 @@ module OrigenSim
293
297
  if c = read_reg_cycles[error[:cycle]]
294
298
  if p = c[simulator.pins_by_rtl_name[error[:pin_name]]]
295
299
  if p[:position]
296
- diffs << [p[:position], error[:recieved], error[:expected]]
300
+ diffs << [p[:position], error[:received], error[:expected]]
297
301
  end
298
302
  end
299
303
  end
@@ -301,6 +305,7 @@ module OrigenSim
301
305
  if diffs.empty?
302
306
  if @read_reg_meta_supplied
303
307
  Origen.log.warning 'It looks like the miscompare(s) occurred on pins/cycles that are not associated with register data'
308
+ non_data_miscompare = true
304
309
  else
305
310
  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
311
  end
@@ -323,7 +328,11 @@ module OrigenSim
323
328
  end
324
329
 
325
330
  diffs.each do |position, received, expected|
326
- reg_or_val[position].data = received
331
+ if received == -1
332
+ reg_or_val[position].unknown = true
333
+ else
334
+ reg_or_val[position].data = received
335
+ end
327
336
  end
328
337
 
329
338
  actual = bit_names.map do |name|
@@ -357,7 +366,8 @@ module OrigenSim
357
366
  Origen.log.error msg
358
367
  end
359
368
  else
360
- msg += " received #{expected}" if @read_reg_meta_supplied
369
+ # This means that the correct data was read, but errors occurred on other pins/cycles during the transaction
370
+ msg += " received #{expected}" if non_data_miscompare
361
371
  Origen.log.error msg
362
372
  end
363
373
  end
@@ -367,7 +377,10 @@ module OrigenSim
367
377
  if actual_data_available
368
378
  actual = reg_or_val
369
379
  diffs.each do |position, received, expected|
370
- if received == 1
380
+ if received == -1
381
+ actual = '?' * reg_or_val.to_s(16).size
382
+ break
383
+ elsif received == 1
371
384
  actual |= (1 << position)
372
385
  else
373
386
  lower = actual[(position - 1)..0]
@@ -376,9 +389,14 @@ module OrigenSim
376
389
  actual |= lower
377
390
  end
378
391
  end
379
- msg += " received #{actual.to_s(16).upcase}"
392
+ if actual.is_a?(String)
393
+ msg += " received #{actual}"
394
+ else
395
+ msg += " received #{actual.to_s(16).upcase}"
396
+ end
380
397
  else
381
- msg += " received #{reg_or_val.to_s(16).upcase}" if @read_reg_meta_supplied
398
+ # This means that the correct data was read, but errors occurred on other pins/cycles during the transaction
399
+ msg += " received #{reg_or_val.to_s(16).upcase}" if non_data_miscompare
382
400
  end
383
401
  Origen.log.error msg
384
402
  end
@@ -409,6 +427,31 @@ module OrigenSim
409
427
  @read_reg_meta_supplied = val
410
428
  end
411
429
 
430
+ # Shorthand for simulator.poke
431
+ def poke(*args)
432
+ simulator.poke(*args)
433
+ end
434
+
435
+ # Shorthand for simulator.peek
436
+ def peek(*args)
437
+ simulator.peek(*args)
438
+ end
439
+
440
+ # Shorthand for simulator.peek_real
441
+ def peek_real(*args)
442
+ simulator.peek_real(*args)
443
+ end
444
+
445
+ # Shorthand for simulator.force
446
+ def force(*args)
447
+ simulator.force(*args)
448
+ end
449
+
450
+ # Shorthand for simulator.release
451
+ def release(*args)
452
+ simulator.release(*args)
453
+ end
454
+
412
455
  private
413
456
 
414
457
  def flush_comments
@@ -26,6 +26,8 @@ module OrigenSimDev
26
26
  add_pin :v2, rtl_name: :nc
27
27
  add_pin :done
28
28
  add_pin :not_present
29
+ add_power_pin :vdd
30
+ add_pin :ana, type: :analog
29
31
 
30
32
  timeset :func do |t|
31
33
  # Generate a clock pulse on TCK
@@ -73,6 +75,15 @@ module OrigenSimDev
73
75
  reg.bits 2..0, :b6
74
76
  end
75
77
 
78
+ add_reg :ana_test, 0x1C do |reg|
79
+ reg.bit 0, :vdd_valid, access: :ro
80
+ reg.bit 1, :bgap_out
81
+ reg.bit 2, :osc_out
82
+ reg.bit 3, :vdd_div4
83
+ end
84
+
85
+ add_reg :x_reg, 0x20
86
+
76
87
  sub_block :ip1, class_name: 'IP'
77
88
  sub_block :ip2, class_name: 'IP'
78
89
  end
@@ -84,6 +95,10 @@ module OrigenSimDev
84
95
  end
85
96
  end
86
97
 
98
+ def simulation_startup
99
+ power_pin(:vdd).drive(0)
100
+ end
101
+
87
102
  def startup(options = {})
88
103
  # tester.simulator.log_messages = true
89
104
  tester.set_timeset('func', 100)
@@ -101,60 +116,65 @@ module OrigenSimDev
101
116
  end
102
117
 
103
118
  def write_register(reg, options = {})
104
- if reg.path =~ /ip(\d)/
105
- ir_val = 0b0100 | Regexp.last_match(1).to_i
106
- jtag.write_ir(ir_val, size: 4)
107
- ip = reg.parent
108
- ip.dr.bits(:write).write(1)
109
- ip.dr.bits(:address).write(reg.address)
110
- ip.dr.bits(:data).write(reg.data)
111
- jtag.write_dr(ip.dr)
112
- # Write to top-level reg
113
- else
114
- jtag.write_ir(0x8, size: 4)
115
- dr.rg_enable.write(1)
116
- dr.rg_read.write(0)
117
- dr.rg_addr.write(reg.address)
118
- dr.rg_data.write(reg.data)
119
- jtag.write_dr(dr)
119
+ PatSeq.serialize :jtag do
120
+ if reg.path =~ /ip(\d)/
121
+ ir_val = 0b0100 | Regexp.last_match(1).to_i
122
+ jtag.write_ir(ir_val, size: 4)
123
+ ip = reg.parent
124
+ ip.dr.bits(:write).write(1)
125
+ ip.dr.bits(:address).write(reg.address)
126
+ ip.dr.bits(:data).write(reg.data)
127
+ jtag.write_dr(ip.dr)
128
+ # Write to top-level reg
129
+ else
130
+ jtag.write_ir(0x8, size: 4)
131
+ dr.rg_enable.write(1)
132
+ dr.rg_read.write(0)
133
+ dr.rg_addr.write(reg.address)
134
+ dr.rg_data.write(reg.data)
135
+ jtag.write_dr(dr)
136
+ end
120
137
  end
121
138
  end
122
139
 
123
140
  def read_register(reg, options = {})
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]
141
+ PatSeq.serialize :jtag do
142
+ tester.read_register(reg, options) do
143
+ # Special read for this register to test sync'ing over a parallel port
144
+ if reg.id == :parallel_read
145
+ pins = []
146
+ reg.shift_out_with_index do |bit, i|
147
+ if bit.is_to_be_stored?
148
+ pins << dut.pins(:dout)[i]
149
+ end
131
150
  end
132
- end
133
- tester.store_next_cycle(*pins.reverse)
134
- 1.cycle
135
- dut.pins(:dout).dont_care
136
- else
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)
151
+ tester.store_next_cycle(*pins.reverse)
152
+ 1.cycle
153
+ dut.pins(:dout).dont_care
147
154
  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)
155
+ if reg.path =~ /ip(\d)/
156
+ ir_val = 0b0100 | Regexp.last_match(1).to_i
157
+ jtag.write_ir(ir_val, size: 4)
158
+ ip = reg.parent
159
+ ip.dr.bits(:write).write(0)
160
+ ip.dr.bits(:address).write(reg.address)
161
+ ip.dr.bits(:data).write(0)
162
+ jtag.write_dr(ip.dr)
163
+ ip.dr.bits(:data).copy_all(reg)
164
+ jtag.read_dr(ip.dr)
165
+ else
166
+ jtag.write_ir(0x8, size: 4)
167
+ dr.rg_enable.write(1)
168
+ dr.rg_read.write(1)
169
+ dr.rg_addr.write(reg.address)
170
+ jtag.write_dr(dr)
171
+ dr.rg_enable.write(0)
172
+ dr.rg_data.copy_all(reg)
173
+ jtag.read_dr(dr)
174
+ end
156
175
  end
157
176
  end
177
+ reg.clear_flags
158
178
  end
159
179
  end
160
180
  end
@@ -33,14 +33,21 @@ module OrigenSimDev
33
33
 
34
34
  def execute_cmd(code)
35
35
  ss "Execute command #{code}"
36
- # Verify that no command is currently running
37
- status.read!(0)
38
-
39
- cmd.write!(code)
40
- 10.cycles
41
- # Verify that the command has started
42
-
43
- status.busy.read!(1)
36
+ PatSeq.reserve :jtag do
37
+ # This is redundant, but added as a test that if an embedded reservation is made to the same
38
+ # resource then the end of the inner block does not release the reservation before completion
39
+ # of the outer block
40
+ PatSeq.reserve :jtag do
41
+ # Verify that no command is currently running
42
+ status.read!(0)
43
+ end
44
+
45
+ cmd.write!(code)
46
+ 10.cycles
47
+ # Verify that the command has started
48
+
49
+ status.busy.read!(1)
50
+ end
44
51
 
45
52
  # Wait for the command to complete, a 'command' lasts for
46
53
  # 1000 cycles times the command code
@@ -0,0 +1,17 @@
1
+ Pattern.sequence do |seq|
2
+ 1.cycle
3
+
4
+ dut.ip1.communication_test
5
+
6
+ seq.run :ip1_test
7
+
8
+ seq.run :ip2_test
9
+
10
+ seq.in_parallel :ip1 do
11
+ seq.run :ip1_test
12
+ end
13
+
14
+ seq.in_parallel :ip2 do
15
+ seq.run :ip2_test
16
+ end
17
+ end