origen_sim 0.12.0 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +5 -5
  2. data/config/application.rb +17 -2
  3. data/config/shared_commands.rb +7 -0
  4. data/config/version.rb +1 -1
  5. data/ext/bridge.c +13 -3
  6. data/lib/origen_sim.rb +10 -0
  7. data/lib/origen_sim/artifacts.rb +101 -0
  8. data/lib/origen_sim/commands/build.rb +41 -9
  9. data/lib/origen_sim/heartbeat.rb +13 -1
  10. data/lib/origen_sim/origen_testers/api.rb +90 -7
  11. data/lib/origen_sim/simulation.rb +49 -4
  12. data/lib/origen_sim/simulator.rb +171 -19
  13. data/lib/origen_sim/stderr_reader.rb +19 -13
  14. data/lib/origen_sim/stdout_reader.rb +22 -16
  15. data/lib/origen_sim/tester.rb +110 -1
  16. data/lib/origen_sim_dev/dut.rb +5 -0
  17. data/pattern/test.rb +143 -0
  18. data/templates/empty.gtkw +19 -1
  19. data/templates/empty.rc +86 -0
  20. data/templates/empty.svcf +79 -9
  21. data/templates/empty.tcl +37 -9
  22. data/templates/origen_guides/simulation/app.md.erb +131 -0
  23. data/templates/origen_guides/simulation/artifacts.md.erb +115 -0
  24. data/templates/origen_guides/simulation/compiling.md.erb +190 -0
  25. data/templates/origen_guides/simulation/debugging.md.erb +135 -0
  26. data/templates/origen_guides/simulation/environment.md.erb +217 -0
  27. data/templates/origen_guides/simulation/flows.md.erb +69 -0
  28. data/templates/origen_guides/simulation/howitworks.md.erb +64 -0
  29. data/templates/origen_guides/simulation/introduction.md.erb +35 -0
  30. data/templates/origen_guides/simulation/log.md.erb +118 -0
  31. data/templates/origen_guides/simulation/patterns.md.erb +193 -0
  32. data/templates/probe.tcl.erb +3 -0
  33. data/templates/rtl_v/origen.v.erb +19 -3
  34. data/templates/web/layouts/_guides.html.erb +15 -0
  35. metadata +18 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: c34ffd12e0b7df9632e5bad4dcb933cb46f88460
4
- data.tar.gz: 6690aac5bb4335ac2de29b1757249eba1be026c0
2
+ SHA256:
3
+ metadata.gz: 6b34633d6530aedd5b581ff1bda44c6e727d72b76a3288dbde6f17c272c9b4a9
4
+ data.tar.gz: 82a82bdc494d1f39e6a3e8a46361d2a21352543e0839fb96dcb4488615de5a1d
5
5
  SHA512:
6
- metadata.gz: 71a090ebaa9f1440d3052773b0823187ada5fc10aab7786081b0c8274e079c78b6aab0866d85c90e7f6193c5a243d3c98012cf99e9d13b7078a4924510e3dda2
7
- data.tar.gz: a617b1e824ef7b9c36583df618440115f35aac94462b1d9a9601f917444360729d81a26235d72bc5dd2aa91f90e398d1d240233feec2ec0d07e568ae38219d47
6
+ metadata.gz: 6af3ed9ca21d9ed459ba26e0d4f7e1c3cbb491a26563376b8151bb51dce20f8d4ec21ff0cf058f5aa349e52d058aab09ee5b81e5203b08cdda1cb1a350eaefd3
7
+ data.tar.gz: 2282439c82a90b725d3191d5ed7c61d1b1c1ade3db935f16beae43a60c202b62e78fa099d3614da5a68cfc1c5c8454e62dc05ee5aeb3fef0c9cf75e2c15f6626
@@ -28,8 +28,23 @@ class OrigenSimApplication < Origen::Application
28
28
  #:patterns => "pattern",
29
29
  #:templates => "templates",
30
30
  #:programs => "program",
31
- :command_launcher => "config/shared_commands.rb",
32
- :global_launcher => "config/global_commands.rb"
31
+ command_launcher: "config/shared_commands.rb",
32
+ global_launcher: "config/global_commands.rb",
33
+ origen_guides: "templates/origen_guides",
34
+ origen_guides_index: -> (index) do
35
+ index.section :simulation, heading: "Simulation", after: :program do |section|
36
+ section.page :introduction, heading: "Introduction"
37
+ section.page :howitworks, heading: "How It Works"
38
+ section.page :compiling, heading: "Compiling the DUT"
39
+ section.page :environment, heading: "Environment Setup"
40
+ section.page :app, heading: "Application Setup"
41
+ section.page :patterns, heading: "Simulating Patterns"
42
+ section.page :flows, heading: "Simulating Flows"
43
+ section.page :log, heading: "Simulator Log Output"
44
+ section.page :artifacts, heading: "Artifacts"
45
+ section.page :debugging, heading: "Interactive Debugging"
46
+ end
47
+ end
33
48
  }
34
49
 
35
50
  config.remotes = [
@@ -11,6 +11,13 @@ when 'generate'
11
11
 
12
12
  @application_options << ["--flow NAME", "Simulate multiple patterns back-back within a single simulation with the given name", ->(options, name) { OrigenSim.flow = name }]
13
13
 
14
+ @application_options << ["--socket_dir PATH", "Specify the directory to be used for creating the Origen -> simulator communication socket (/tmp by default) ", ->(options, path) {
15
+ FileUtils.mkdir_p(path) unless File.exist?(path)
16
+ path = Pathname.new(path)
17
+ path = path.realpath.to_s
18
+ OrigenSim.socket_dir = path
19
+ }]
20
+
14
21
  when "sim:ci", "origen_sim:ci"
15
22
  require "#{Origen.root!}/lib/origen_sim/commands/ci"
16
23
  exit 0
@@ -1,6 +1,6 @@
1
1
  module OrigenSim
2
2
  MAJOR = 0
3
- MINOR = 12
3
+ MINOR = 13
4
4
  BUGFIX = 0
5
5
  DEV = nil
6
6
 
@@ -538,6 +538,7 @@ PLI_INT32 bridge_wait_for_msg(p_cb_data data) {
538
538
  UNUSED(data);
539
539
  int max_msg_len = 1024;
540
540
  char msg[max_msg_len];
541
+ char comment[128];
541
542
  int err;
542
543
  char *opcode, *arg1, *arg2, *arg3, *arg4;
543
544
  vpiHandle handle;
@@ -706,13 +707,18 @@ PLI_INT32 bridge_wait_for_msg(p_cb_data data) {
706
707
  }
707
708
  break;
708
709
  // Set Comment
709
- // c^Some comment about the pattern
710
+ // c^0^Some comment about the pattern
710
711
  case 'c' :
711
- handle = vpi_handle_by_name(ORIGEN_SIM_TESTBENCH_CAT("debug.comments"), NULL);
712
712
  arg1 = strtok(NULL, "^");
713
+ arg2 = strtok(NULL, "^");
714
+
715
+ strcpy(comment, ORIGEN_SIM_TESTBENCH_CAT("debug.comments"));
716
+ strcat(comment, arg1);
717
+
718
+ handle = vpi_handle_by_name(comment, NULL);
713
719
 
714
720
  v.format = vpiStringVal;
715
- v.value.str = arg1;
721
+ v.value.str = arg2;
716
722
  vpi_put_value(handle, &v, NULL, vpiNoDelay);
717
723
  break;
718
724
  // Log all messages
@@ -757,6 +763,10 @@ PLI_INT32 bridge_wait_for_msg(p_cb_data data) {
757
763
  case 'i' :
758
764
  client_put(ORIGEN_SIM_VERSION"\n");
759
765
  break;
766
+ // Flush
767
+ case 'j' :
768
+ vpi_flush();
769
+ break;
760
770
  default :
761
771
  vpi_printf("ERROR: Illegal message received from Origen: %s\n", orig_msg);
762
772
  runtime_errors += 1;
@@ -6,6 +6,8 @@ require 'origen_sim/origen/pins/pin'
6
6
  require 'origen_sim/origen/top_level'
7
7
  require 'origen_sim/origen/application/runner'
8
8
  module OrigenSim
9
+ NUMBER_OF_COMMENT_LINES = 10
10
+
9
11
  # THIS FILE SHOULD ONLY BE USED TO LOAD RUNTIME DEPENDENCIES
10
12
  # If this plugin has any development dependencies (e.g. dummy DUT or other models that are only used
11
13
  # for testing), then these should be loaded from config/boot.rb
@@ -58,6 +60,14 @@ module OrigenSim
58
60
  @flow
59
61
  end
60
62
 
63
+ def self.socket_dir=(val)
64
+ @socket_dir = val
65
+ end
66
+
67
+ def self.socket_dir
68
+ @socket_dir
69
+ end
70
+
61
71
  def self.error_strings
62
72
  @error_strings ||= ['ERROR']
63
73
  end
@@ -0,0 +1,101 @@
1
+ module OrigenSim
2
+ module Artifacts
3
+ class Artifacts
4
+ include Origen::Componentable
5
+
6
+ # Disable accessors on the simulator. Artifact retrieval must use simulator.artifact[name]
7
+ COMPONENTABLE_ADDS_ACCESSORS = false
8
+
9
+ # Clean up the names a bit. Componentable assumes the class name is the singleton name, but we're doing the opposite here.
10
+ COMPONENTABLE_SINGLETON_NAME = 'artifact'
11
+ COMPONENTABLE_PLURAL_NAME = 'artifacts'
12
+
13
+ def initialize
14
+ # Don't need the full extent of Origen::Mdoel, so we'll just init the includer class directly.
15
+ Origen::Componentable.init_includer_class(self)
16
+ end
17
+
18
+ # Force the class to be an OrigenSim::Artifacts::Artifact
19
+ def add(name, options = {}, &block)
20
+ instances = _split_by_instances(name, options, &block)
21
+ return_instances = []
22
+ instances.each do |n, opts|
23
+ opts[:class_name] = OrigenSim::Artifacts::Artifact
24
+ return_instances << _add(n, opts)
25
+ end
26
+
27
+ return_instances.size == 1 ? return_instances.first : return_instances
28
+ end
29
+
30
+ def populate
31
+ artifacts.each do |name, artifact|
32
+ Origen.log.info "Populating artifact: #{artifact.target}"
33
+ Origen.log.info " to: #{artifact.run_target}"
34
+ artifact.populate
35
+ end
36
+ true
37
+ end
38
+
39
+ def clean
40
+ artifacts.each do |name, artifact|
41
+ Origen.log.info "Cleaning artifact: #{artifact.run_target}"
42
+ artifact.clean
43
+ end
44
+ true
45
+ end
46
+ end
47
+
48
+ class Artifact
49
+ attr_reader :name
50
+ attr_reader :parent
51
+
52
+ def initialize(options)
53
+ @name = options.delete(:name)
54
+ @parent = options.delete(:parent)
55
+ @options = options
56
+ end
57
+
58
+ def target
59
+ Pathname(@options[:target] || parent.artifact_dir)
60
+ end
61
+
62
+ def run_target
63
+ run_target = Pathname(@options[:run_target] || parent.artifact_run_dir)
64
+ if run_target.absolute?
65
+ run_target.join(target.basename)
66
+ else
67
+ parent.artifact_run_dir.join(run_target).join(target.basename)
68
+ end
69
+ end
70
+
71
+ def populate_method
72
+ @options[:populate_method] || parent.artifact_populate_method
73
+ end
74
+ alias_method :pop_method, :populate_method
75
+
76
+ def populate
77
+ if populate_method == :symlink
78
+ File.symlink(target, run_target)
79
+ elsif populate_method == :copy
80
+ FileUtils.cp(target, run_target)
81
+ else
82
+ Origen.app.fail! "Cannot populate artifact :#{name} with populate method #{populate_method}!"
83
+ end
84
+ end
85
+
86
+ def clean
87
+ if File.exist?(run_target)
88
+ if File.symlink?(run_target)
89
+ File.unlink(run_target)
90
+ else
91
+ FileUtils.rm_r(run_target)
92
+ end
93
+ end
94
+ end
95
+
96
+ def reconfigure(options)
97
+ @options = options
98
+ end
99
+ end
100
+ end
101
+ end
@@ -107,14 +107,6 @@ else
107
107
 
108
108
  puts
109
109
  puts
110
- puts 'Testbench and VPI extension created!'
111
- puts
112
- puts 'This file can be imported into an Origen top-level DUT model to define the pins:'
113
- puts
114
- puts " #{output_directory}/#{rtl_top_module}.rb"
115
- puts
116
- puts 'See below for what to do now to create an Origen-enabled simulation object for your particular simulator:'
117
- puts
118
110
  puts '-----------------------------------------------------------'
119
111
  puts 'Cadence Incisive (irun)'
120
112
  puts '-----------------------------------------------------------'
@@ -145,7 +137,7 @@ else
145
137
  puts 'Add the following to your build script (AND REMOVE ANY OTHER TESTBENCH!):'
146
138
  puts
147
139
  puts " #{output_directory}/origen.v \\"
148
- puts " #{output_directory}/brdige.c \\"
140
+ puts " #{output_directory}/bridge.c \\"
149
141
  puts " #{output_directory}/client.c \\"
150
142
  puts ' -CFLAGS "-std=c99" \\'
151
143
  puts ' +vpi \\'
@@ -187,5 +179,45 @@ else
187
179
  puts " #{output_directory}/origen.vpi"
188
180
  puts ' origen.vvp'
189
181
  puts
182
+ puts '-----------------------------------------------------------'
183
+ puts 'Verdi w/ Synopsys VCS'
184
+ puts '-----------------------------------------------------------'
190
185
  puts
186
+ puts 'Add the following to your build script (AND REMOVE ANY OTHER TESTBENCH!):'
187
+ puts
188
+ puts " #{output_directory}/origen.v \\"
189
+ puts " #{output_directory}/brdige.c \\"
190
+ puts " #{output_directory}/client.c \\"
191
+ puts ' -CFLAGS "-std=c99" \\'
192
+ puts ' +vpi \\'
193
+ puts " #{output_directory}/origen.c \\"
194
+ puts ' +define+ORIGEN_FSDB=1 \\'
195
+ puts ' -debug_access+all \\'
196
+ puts ' +lint=all,noVCDE,noIWU,noVNGS,noCAWM-L,noPORTFRC,noZERO,noNS \\'
197
+ puts ' -PP \\'
198
+ puts ' -timescale=1ns/100ps \\'
199
+ puts ' -full64 \\'
200
+ puts ' -lca \\'
201
+ puts ' -kdb \\'
202
+ puts
203
+ puts 'Here is an example which may work for the file you just parsed (add additional -incdir options at the end if required):'
204
+ puts
205
+ puts " #{ENV['ORIGEN_SIM_VCS'] || 'vcs'} #{rtl_top} #{output_directory}/origen.v #{output_directory}/bridge.c #{output_directory}/client.c -CFLAGS \"-std=c99\" +vpi #{output_directory}/origen.c +define+ORIGEN_FSDB=1 +incdir+#{Pathname.new(rtl_top).dirname} -debug_access+all +lint=all,noVCDE,noIWU,noVNGS,noCAWM-L,noPORTFRC,noZERO,noNS -PP -timescale=1ns/100ps -full64 -lca -kdb"
206
+ puts
207
+ puts 'Copy the following files (produced by vcs) to simulation/<target>/verdi/. within your Origen application:'
208
+ puts
209
+ puts ' simv'
210
+ puts ' simv.daidir'
211
+ puts
212
+ puts '-----------------------------------------------------------'
213
+ puts
214
+ puts 'Testbench and VPI extension created!'
215
+ puts
216
+ puts 'This file can be imported into an Origen top-level DUT model to define the pins:'
217
+ puts
218
+ puts " #{output_directory}/#{rtl_top_module}.rb"
219
+ puts
220
+ puts 'See above for what to do now to create an Origen-enabled simulation object for your particular simulator.'
221
+ puts
222
+
191
223
  end
@@ -3,12 +3,24 @@ module OrigenSim
3
3
  class Heartbeat < Thread
4
4
  attr_reader :socket
5
5
 
6
+ # Can't use this with threads currently because Byebug pauses the sleep,
7
+ # during a breakpoint, which means that the simulator is killed.
8
+ # Currently working around via a forked process implementation instead
9
+ # whenever this is set to false.
10
+ THREADSAFE = false
11
+
6
12
  def initialize(socket)
7
13
  @socket = socket
8
14
  @continue = true
9
15
  super do
10
16
  while @continue
11
- socket.write("OK\n")
17
+ begin
18
+ socket.write("OK\n")
19
+ rescue Errno::EPIPE => e
20
+ Origen.log.error 'Communication with the simulation monitor has been lost!'
21
+ sleep 2
22
+ exit 1
23
+ end
12
24
  sleep 5
13
25
  end
14
26
  end
@@ -8,17 +8,83 @@ module OrigenTesters
8
8
  end
9
9
  alias_method :simulator?, :sim?
10
10
 
11
+ def sim_delay(id, options = {}, &block)
12
+ if sim? && dut_version <= '0.12.0'
13
+ OrigenSim.error "Use of sim_delay requires a DUT model compiled with OrigenSim version > 0.12.0, the current dut was compiled with #{dut_version}"
14
+ end
15
+ orig_id = id
16
+ id = "delay_#{id}".to_sym # Just to make sure it is unique from the sim_capture IDs
17
+ if @sim_capture || @sim_delay
18
+ fail 'Nesting of sim_capture and/or sim_delay blocks is not yet supported!'
19
+ end
20
+ Origen::OrgFile.open(id) do |org_file|
21
+ @org_file = org_file
22
+ if update_capture?
23
+ @sim_delay = true
24
+ # This enables errors to be captured in a separate variable so that they don't affect
25
+ # the overall simulation result
26
+ start_cycle = cycle_count
27
+ delay = 0
28
+ simulator.match_loop do
29
+ if options[:resolution]
30
+ if options[:resolution].is_a?(Hash)
31
+ resolution_in_cycles = time_to_cycles(options[:resolution])
32
+ else
33
+ resolution_in_cycles = options[:resolution]
34
+ end
35
+ end
36
+ timeout_in_cycles = time_to_cycles(options)
37
+ e = -1
38
+ until (e == simulator.match_errors) || (timeout_in_cycles > 0 ? delay > timeout_in_cycles : false)
39
+ delay = cycle_count - start_cycle
40
+ e = simulator.match_errors
41
+ pre_block_cycle = cycle_count
42
+ block.call
43
+ if resolution_in_cycles
44
+ remaining = resolution_in_cycles - (cycle_count - pre_block_cycle)
45
+ remaining.cycles if remaining > 0
46
+ else
47
+ # Make sure time is advancing, the block does not necessarily have to advance time
48
+ 1.cycle if pre_block_cycle == cycle_count
49
+ end
50
+ end
51
+ end
52
+ Origen.log.debug "sim_delay #{orig_id} resolved after #{delay} cycles"
53
+ # We now know how long it took before the block could pass, now record that information
54
+ # to the org file for next time
55
+ org_file.record('tester', 'cycle')
56
+ org_file.file # Need to call this since we are bypassing the regular capture API here
57
+ Origen::OrgFile.cycle(delay)
58
+ else
59
+ unless org_file.exist?
60
+ fail "The simulation delay \"#{orig_id}\" has not been simulated yet, re-run this pattern with a simulation target first!"
61
+ end
62
+ org_file.read_line do |operations, cycles|
63
+ cycles.cycles
64
+ end
65
+ end
66
+ end
67
+ # Finally execute the block after waiting
68
+ if options[:padding]
69
+ time_to_cycles(options[:padding]).cycles
70
+ end
71
+ block.call
72
+ @sim_delay = nil
73
+ end
74
+
11
75
  def sim_capture(id, *pins)
12
- if @sim_capture
13
- fail 'Nesting of sim_capture blocks is not yet supported!'
76
+ if @sim_capture || @sim_delay
77
+ fail 'Nesting of sim_capture and/or sim_delay blocks is not yet supported!'
14
78
  end
79
+ @sim_capture_id = id
15
80
  options = pins.last.is_a?(Hash) ? pins.pop : {}
16
81
  pins = pins.map { |p| p.is_a?(String) || p.is_a?(Symbol) ? dut.pin(p) : p }
17
82
  pins.each(&:save)
18
83
  @sim_capture = pins.map { |p| [p, "origen.dut.#{p.rtl_name}"] }
19
84
  Origen::OrgFile.open(id) do |org_file|
20
85
  @org_file = org_file
21
- if update_capture?
86
+ @update_capture = update_capture?
87
+ if @update_capture
22
88
  @sim_capture.each { |pin, net| pin.record_to_org_file(only: :assert) }
23
89
  end
24
90
  yield
@@ -34,7 +100,7 @@ module OrigenTesters
34
100
  # really assume that it will be constant for all cycles covered by the repeat
35
101
  cycles = options.delete(:repeat) || 1
36
102
  cycles.times do
37
- if update_capture?
103
+ if @update_capture
38
104
  _origen_testers_cycle(options)
39
105
  @sim_capture.each do |pin, net|
40
106
  pin.assert(simulator.peek(net))
@@ -45,7 +111,7 @@ module OrigenTesters
45
111
  Origen::OrgFile.cycle
46
112
  else
47
113
  unless @org_file.exist?
48
- fail "The simulation capture \"#{id}\" has not been made yet, re-run this pattern with a simulation target first!"
114
+ fail "The simulation capture \"#{@sim_capture_id}\" has not been simulated yet, re-run this pattern with a simulation target first!"
49
115
  end
50
116
  apply_captured_data
51
117
  _origen_testers_cycle(options)
@@ -70,8 +136,25 @@ module OrigenTesters
70
136
  end
71
137
 
72
138
  def update_capture?
73
- return @update_capture if defined? @update_capture
74
- @update_capture = sim? && (!@org_file.exist? || Origen.app!.update_sim_captures)
139
+ sim? && (!@org_file.exist? || Origen.app!.update_sim_captures)
140
+ end
141
+
142
+ def time_to_cycles(options)
143
+ options = {
144
+ cycles: 0,
145
+ time_in_cycles: 0,
146
+ time_in_us: 0,
147
+ time_in_ns: 0,
148
+ time_in_ms: 0,
149
+ time_in_s: 0
150
+ }.merge(options)
151
+ cycles = 0
152
+ cycles += options[:cycles] + options[:time_in_cycles]
153
+ cycles += s_to_cycles(options[:time_in_s])
154
+ cycles += ms_to_cycles(options[:time_in_ms])
155
+ cycles += us_to_cycles(options[:time_in_us])
156
+ cycles += ns_to_cycles(options[:time_in_ns])
157
+ cycles
75
158
  end
76
159
  end
77
160
  end