origen_sim 0.16.1 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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