origen 0.27.0 → 0.28.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.
@@ -0,0 +1,238 @@
1
+ module Origen
2
+ module Model
3
+ module Exporter
4
+ def export(name, options = {})
5
+ options = {
6
+ include_pins: true,
7
+ include_registers: true,
8
+ include_sub_blocks: true,
9
+ include_timestamp: true,
10
+ file_path: nil
11
+ }.merge(options)
12
+ if options[:file_path]
13
+ file = File.join(options[:file_path], "#{name}.rb")
14
+ else
15
+ file = export_path(name)
16
+ end
17
+ file += '.rb' unless file =~ /.rb$/
18
+ file = Pathname.new(file)
19
+ FileUtils.rm_rf(file.sub_ext('').to_s) if File.exist?(file.sub_ext('').to_s)
20
+ FileUtils.rm_rf(file.to_s) if File.exist?(file.to_s)
21
+ FileUtils.mkdir_p(file.dirname)
22
+ File.open(file, 'w') do |f|
23
+ export_wrap_with_namespaces(f, options) do |indent|
24
+ f.puts((' ' * indent) + 'def self.extended(model)')
25
+ indent += 2
26
+ if top_level?
27
+ # Write out packages if any
28
+ unless Origen.top_level.packages.empty?
29
+ spaces = ' ' * indent
30
+ Origen.top_level.packages.each { |p| f.puts "#{spaces}model.add_package :#{p}\n" }
31
+ end
32
+ end
33
+ if options[:include_pins]
34
+ if top_level?
35
+ pins.each do |id, pin|
36
+ f.puts export_pin(id, pin, indent: indent)
37
+ end
38
+ pin_groups.each do |id, pins|
39
+ f.puts export_pin_group(id, pins, indent: indent)
40
+ end
41
+ power_pins.each do |id, pin|
42
+ f.puts export_pin(id, pin, indent: indent, method: :add_power_pin, attributes: [:voltage, :current_limit])
43
+ end
44
+ power_pin_groups.each do |id, pins|
45
+ f.puts export_pin_group(id, pins, indent: indent, method: :add_power_pin_group)
46
+ end
47
+ ground_pins.each do |id, pin|
48
+ f.puts export_pin(id, pin, indent: indent, method: :add_ground_pin)
49
+ end
50
+ ground_pin_groups.each do |id, pins|
51
+ f.puts export_pin_group(id, pins, indent: indent, method: :add_ground_pin_group)
52
+ end
53
+ f.puts
54
+ end
55
+ end
56
+ if options[:include_sub_blocks]
57
+ sub_blocks.each do |name, block|
58
+ f.puts export_sub_block(name, block, options.merge(indent: indent, file_path: file))
59
+ end
60
+ f.puts unless sub_blocks.empty?
61
+ end
62
+
63
+ if options[:include_registers]
64
+ regs.each do |name, reg|
65
+ f.puts export_reg(name, reg, indent: indent)
66
+ end
67
+ end
68
+
69
+ indent -= 2
70
+ f.puts((' ' * indent) + 'end')
71
+ end
72
+ end
73
+ end
74
+
75
+ def import(name, options = {})
76
+ path = export_path(name)
77
+ require path
78
+ extend "#{Origen.app.namespace.underscore.camelcase}::#{name.to_s.camelcase}".constantize
79
+ end
80
+
81
+ private
82
+
83
+ def write_pin_packages(pin)
84
+ ''.tap do |str|
85
+ unless pin.packages.empty?
86
+ str << 'packages: { '
87
+ pin.packages.each do |pin_pkg, pin_pkg_meta|
88
+ pkg_end_str = (pin_pkg == pin.packages.keys.last) ? ' }' : ', '
89
+ if pin_pkg_meta.empty?
90
+ str << "#{pin_pkg}: {}#{pkg_end_str}"
91
+ next
92
+ else
93
+ str << "#{pin_pkg}: { "
94
+ pin_pkg_meta.each do |attr, attr_val|
95
+ str << "#{attr}: "
96
+ attr_end_str = (attr == pin_pkg_meta.keys.last) ? ' }' : ', '
97
+ case attr_val
98
+ when String
99
+ str << "'#{attr_val}'#{attr_end_str}"
100
+ else
101
+ str << "#{attr_val}#{attr_end_str}"
102
+ end
103
+ end
104
+ str << pkg_end_str
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ def export_wrap_with_namespaces(file, options = {})
112
+ file.puts '# This file was generated by Origen, any hand edits will likely get overwritten'
113
+ if options[:include_timestamp]
114
+ file.puts "# Created at #{Time.now.strftime('%e %b %Y %H:%M%p')} by #{User.current.name}"
115
+ end
116
+ file.puts '# rubocop:disable all'
117
+ indent = 0
118
+ export_module_names_from_path(file.path).each do |name|
119
+ file.puts((' ' * indent) + "module #{name}")
120
+ indent += 2
121
+ end
122
+ yield indent
123
+ export_module_names_from_path(file.path).each do |name|
124
+ indent -= 2
125
+ file.puts((' ' * indent) + 'end')
126
+ end
127
+ file.puts '# rubocop:enable all'
128
+ end
129
+
130
+ def export_module_names_from_path(name)
131
+ name = name.sub("#{export_dir}/", '').sub('.rb', '')
132
+ name.split(/[\/\\]/).map do |n|
133
+ if n == ''
134
+ nil
135
+ else
136
+ n.camelcase
137
+ end
138
+ end.compact
139
+ end
140
+
141
+ def export_path(name)
142
+ File.join(export_dir, Origen.app.namespace.to_s.underscore, name.to_s.underscore)
143
+ end
144
+
145
+ def export_dir
146
+ File.join(Origen.root, 'vendor', 'lib', 'models')
147
+ end
148
+
149
+ def export_pin(id, pin, options = {})
150
+ indent = ' ' * (options[:indent] || 0)
151
+ line = indent + "model.#{options[:method] || 'add_pin'} :#{id}"
152
+ if (r = pin.instance_variable_get('@reset')) != :dont_care
153
+ line << ", reset: :#{r}"
154
+ end
155
+ if (d = pin.direction) != :io
156
+ line << ", direction: :#{d}"
157
+ end
158
+ pkg_meta = write_pin_packages(pin)
159
+ line << ", #{pkg_meta}" unless pkg_meta == ''
160
+ Array(options[:attributes]).each do |attr|
161
+ unless (v = pin.send(attr)).nil?
162
+ if v.is_a?(Numeric)
163
+ line << ", #{attr}: #{v}"
164
+ else
165
+ line << ", #{attr}: '#{v}'"
166
+ end
167
+ end
168
+ end
169
+ unless pin.meta.empty?
170
+ line << ', meta: { '
171
+ line << pin.meta.map do |k, v|
172
+ if v.is_a?(Numeric)
173
+ "#{k}: #{v}"
174
+ else
175
+ "#{k}: '#{v}'"
176
+ end
177
+ end.join(', ')
178
+ line << ' }'
179
+ end
180
+ line
181
+ end
182
+
183
+ def export_pin_group(id, pins, options = {})
184
+ indent = ' ' * (options[:indent] || 0)
185
+ line = indent + "model.#{options[:method] || 'add_pin_group'} :#{id}, "
186
+ if pins.endian == :little
187
+ line << pins.reverse_each.map { |p| ":#{p.id}" }.join(', ')
188
+ line << "\n#{indent}model.pins(:#{id}).endian = :little"
189
+ else
190
+ line << pins.map { |p| ":#{p.id}" }.join(', ')
191
+ end
192
+ line
193
+ end
194
+
195
+ def export_sub_block(id, block, options = {})
196
+ indent = ' ' * (options[:indent] || 0)
197
+ file = File.join(options[:file_path].sub_ext(''), "#{id}.rb")
198
+ local_file = file.to_s.sub("#{export_dir}/", '')
199
+ line = indent + "model.sub_block :#{id}, file: '#{local_file}'"
200
+ unless block.base_address == 0
201
+ line << ", base_address: #{block.base_address.to_hex}"
202
+ end
203
+ block.export(id, options.merge(file_path: options[:file_path].sub_ext('').to_s))
204
+ line
205
+ end
206
+
207
+ def export_reg(id, reg, options = {})
208
+ indent = ' ' * (options[:indent] || 0)
209
+ lines = []
210
+ unless reg.description.empty?
211
+ reg.description.each { |l| lines << indent + "# #{l}" }
212
+ end
213
+ lines << indent + "model.add_reg :#{id}, #{reg.offset.to_hex}, size: #{reg.size} do |reg|"
214
+ indent = ' ' * ((options[:indent] || 0) + 2)
215
+ reg.named_bits.each do |name, bits|
216
+ unless bits.description.empty?
217
+ bits.description.each { |l| lines << indent + "# #{l}" }
218
+ end
219
+ if bits.size == 1
220
+ line = indent + "reg.bit #{bits.position}, :#{name}"
221
+ else
222
+ line = indent + "reg.bit #{bits.position + bits.size - 1}..#{bits.position}, :#{name}"
223
+ end
224
+ unless bits.access == :rw
225
+ line << ", access: :#{bits.access}"
226
+ end
227
+ unless bits.reset_val == 0
228
+ line << ", reset: #{bits.reset_val.to_hex}"
229
+ end
230
+ lines << line
231
+ end
232
+ indent = ' ' * (options[:indent] || 0)
233
+ lines << indent + 'end'
234
+ lines.join("\n")
235
+ end
236
+ end
237
+ end
238
+ end
@@ -31,8 +31,8 @@ module Origen
31
31
  else
32
32
  _parameter_sets[name] = Set.new(top_level: true, owner: self)
33
33
  if options[:inherit]
34
- _validate_parameter_set_name(options[:inherit])
35
- parent = _parameter_sets[options[:inherit]]
34
+ kontext = _validate_parameter_set_name(options[:inherit])
35
+ parent = kontext[:obj]._parameter_sets[kontext[:context]]
36
36
  _parameter_sets[name].copy_defaults_from(parent)
37
37
  _parameter_sets[name].define(parent, &block)
38
38
  else
@@ -100,10 +100,31 @@ module Origen
100
100
 
101
101
  private
102
102
 
103
- def _validate_parameter_set_name(name)
104
- unless _parameter_sets.key?(name)
105
- puts "Unknown parameter set :#{name} requested for #{self.class}, these are the valid sets:"
106
- _parameter_sets.keys.each { |k| puts " :#{k}" }
103
+ def _validate_parameter_set_name(expr)
104
+ # Check if the user specified to inherit from another object
105
+ # or just passed in a param context
106
+ param_context = {}.tap do |context_hash|
107
+ case expr
108
+ when Symbol
109
+ # user specified a local context
110
+ context_hash[:obj] = self
111
+ context_hash[:context] = expr
112
+ when String
113
+ # user specified a DUT path
114
+ path = expr.split('.')[0..-2].join('.')
115
+ kontext = expr.split('.')[-1].to_sym
116
+ context_hash[:obj] = eval(path)
117
+ context_hash[:context] = kontext
118
+ else
119
+ Origen.log.error('Parameter context must be a Symbol (local to self) or a String (reference to another object)!')
120
+ fail
121
+ end
122
+ end
123
+ if param_context[:obj]._parameter_sets.key?(param_context[:context])
124
+ return param_context
125
+ else
126
+ puts "Unknown parameter set :#{param_context[:context]} requested for #{param_context[:obj].class}, these are the valid sets:"
127
+ param_context[:obj]._parameter_sets.keys.each { |k| puts " :#{k}" }
107
128
  puts ''
108
129
  fail 'Unknown parameter set!'
109
130
  end
data/lib/origen/pins.rb CHANGED
@@ -732,6 +732,7 @@ If you meant to define the pin then use the add_pin method instead.
732
732
  }.merge(options)
733
733
  pins(id, options, &block)
734
734
  end
735
+ alias_method :power_pin, :power_pins
735
736
 
736
737
  # Equivalent to the pins method but considers ground pins rather than regular pins
737
738
  def ground_pins(id = nil, options = {}, &block)
@@ -741,6 +742,7 @@ If you meant to define the pin then use the add_pin method instead.
741
742
  }.merge(options)
742
743
  pins(id, options, &block)
743
744
  end
745
+ alias_method :ground_pin, :ground_pins
744
746
 
745
747
  # Equivalent to the pins method but considers other pins rather than regular pins
746
748
  def other_pins(id = nil, options = {}, &block)
@@ -750,6 +752,7 @@ If you meant to define the pin then use the add_pin method instead.
750
752
  }.merge(options)
751
753
  pins(id, options, &block)
752
754
  end
755
+ alias_method :other_pin, :other_pins
753
756
 
754
757
  # Equivalent to the pins method but considers virtual pins rather than regular pins
755
758
  def virtual_pins(id = nil, options = {}, &block)
@@ -759,6 +762,7 @@ If you meant to define the pin then use the add_pin method instead.
759
762
  }.merge(options)
760
763
  pins(id, options, &block)
761
764
  end
765
+ alias_method :virtual_pin, :virtual_pins
762
766
 
763
767
  def delete_all_pins
764
768
  Origen.pin_bank.send :empty!
@@ -9,7 +9,7 @@ module Origen
9
9
 
10
10
  # Any attributes listed here will be looked up for the current package context
11
11
  # before falling back to a default
12
- PACKAGE_SCOPED_ATTRIBUTES = [:location, :dib_assignment]
12
+ PACKAGE_SCOPED_ATTRIBUTES = [:location, :dib_assignment, :dib_meta]
13
13
 
14
14
  # Pin Types
15
15
  TYPES = [:analog, :digital]
@@ -74,6 +74,7 @@ module Origen
74
74
  @value = 0
75
75
  @clock = nil
76
76
  @meta = options[:meta] || {}
77
+ @dib_meta = options[:dib_meta] || {}
77
78
  on_init(owner, options)
78
79
  # Assign the initial state from the method so that any inversion is picked up...
79
80
  send(@reset)
@@ -421,6 +422,18 @@ module Origen
421
422
  alias_method :add_dib_info, :add_dib_assignment
422
423
  alias_method :add_channel, :add_dib_assignment
423
424
 
425
+ def add_dib_meta(pkg, options)
426
+ unless Origen.top_level.packages.include? pkg
427
+ Origen.log.error("Cannot add DIB metadata for package '#{pkg}', that package has not been added yet!")
428
+ fail
429
+ end
430
+ options.each do |attr, attr_value|
431
+ packages[pkg][:dib_meta] ||= {}
432
+ packages[pkg][:dib_meta][attr] = attr_value
433
+ add_alias attr_value.to_s.symbolize, package: pkg, mode: :all, configuration: :all
434
+ end
435
+ end
436
+
424
437
  # Returns the number of test sites enabled for the pin
425
438
  def sites
426
439
  dib_assignment.size
@@ -978,6 +991,18 @@ module Origen
978
991
  end
979
992
  end
980
993
 
994
+ def method_missing(m, *args, &block)
995
+ if meta.include? m
996
+ meta[m]
997
+ else
998
+ super
999
+ end
1000
+ end
1001
+
1002
+ def respond_to_missing?(m, include_private = false)
1003
+ meta[m] || super
1004
+ end
1005
+
981
1006
  private
982
1007
 
983
1008
  def primary_group=(group)
@@ -1,7 +1,9 @@
1
+ require 'origen/specs'
1
2
  module Origen
2
3
  module PowerDomains
3
4
  class PowerDomain
4
- attr_accessor :id, :description, :unit_voltage_range, :nominal_voltage, :setpoint
5
+ include Origen::Specs
6
+ attr_accessor :id, :description, :unit_voltage_range, :nominal_voltage, :setpoint, :maximum_voltage_rating, :min, :max
5
7
 
6
8
  # Generic Power Domain Name
7
9
  # This is the power supply that can be blocked off to multiple power supplies
@@ -36,12 +38,31 @@ module Origen
36
38
  (block.arity < 1 ? (instance_eval(&block)) : block.call(self)) if block_given?
37
39
  @unit_voltage_range = :fixed if @unit_voltage_range.nil?
38
40
  fail unless attrs_ok?
41
+ create_dut_spec unless @min.nil? || @max.nil?
39
42
  end
40
43
 
41
44
  def name
42
45
  @id
43
46
  end
44
47
 
48
+ # Create DUT specs for the power supply
49
+ def create_dut_spec
50
+ if Origen.top_level.specs.nil?
51
+ set_specs
52
+ elsif Origen.top_level.specs.include? name
53
+ Origen.log.error("Cannot create power domain spec '#{name}', it already exists!")
54
+ fail
55
+ else
56
+ set_specs
57
+ end
58
+ end
59
+
60
+ # Maximum Voltage Rating
61
+ def maximum_voltage_rating
62
+ @maximum_voltage_rating
63
+ end
64
+ alias_method :mvr, :maximum_voltage_rating
65
+
45
66
  # Sets setpoint equal to nominal_voltage
46
67
  def setpoint_to_nominal
47
68
  @setpoint = @nominal_voltage
@@ -112,7 +133,8 @@ module Origen
112
133
  alias_method :curr_value, :setpoint
113
134
  alias_method :value, :setpoint
114
135
 
115
- # Acceptable voltage range
136
+ # Power domain can allow either a variable
137
+ # or fixed unit voltage range (Range or :fixed)
116
138
  def unit_voltage_range
117
139
  @unit_voltage_range
118
140
  end
@@ -129,11 +151,14 @@ module Origen
129
151
  # Checks if the setpoint is valid
130
152
  # This will need rework once the class has spec limits added
131
153
  def setpoint_ok?(val = nil)
132
- return true if unit_voltage_range == :fixed
133
- if val.nil?
134
- unit_voltage_range.include?(setpoint) ? true : false
154
+ return true if maximum_voltage_rating.nil?
155
+ compare_val = val.nil? ? setpoint : val
156
+ if compare_val.nil?
157
+ false
158
+ elsif compare_val <= maximum_voltage_rating
159
+ true
135
160
  else
136
- unit_voltage_range.include?(val) ? true : false
161
+ false
137
162
  end
138
163
  end
139
164
  alias_method :value_ok?, :setpoint_ok?
@@ -164,6 +189,16 @@ module Origen
164
189
 
165
190
  private
166
191
 
192
+ def set_specs
193
+ Origen.top_level.spec name, :dc do |s|
194
+ s.description = "#{name.to_s.upcase} Power Domain"
195
+ s.min = min
196
+ s.typ = nominal_voltage
197
+ s.max = max
198
+ s.unit = 'V'
199
+ end
200
+ end
201
+
167
202
  def attrs_ok?
168
203
  return_value = true
169
204
  unless description.is_a? String
@@ -188,15 +223,20 @@ module Origen
188
223
  elsif unit_voltage_range == :fixed
189
224
  true
190
225
  elsif unit_voltage_range.nil?
191
- Origen.log.error("PPEKit: Missing voltage range for power domain '#{name}'!")
226
+ Origen.log.error("PPEKit: Missing unit voltage range for power domain '#{name}'!")
192
227
  false
193
228
  elsif unit_voltage_range.is_a? Range
194
- if unit_voltage_range.include?(nominal_voltage)
195
- true
196
- else
197
- Origen.log.error("PPEKit: Nominal voltage #{nominal_voltage} is not inbetween the voltage range #{unit_voltage_range} for power domain '#{name}'!")
229
+ unless unit_voltage_range.include?(nominal_voltage)
230
+ Origen.log.error("PPEKit: Nominal voltage #{nominal_voltage} is not inbetween the unit voltage range #{unit_voltage_range} for power domain '#{name}'!")
198
231
  false
199
232
  end
233
+ unless maximum_voltage_rating.nil?
234
+ unless unit_voltage_range.last <= maximum_voltage_rating
235
+ Origen.log.error('PPEKit: Unit voltage range exceeds the maximum voltage range!')
236
+ fail
237
+ end
238
+ end
239
+ true
200
240
  else
201
241
  Origen.log.error("Power domain attribute 'unit_voltage_range' must be a Range or set to the value of :fixed!")
202
242
  return_value = false