origen 0.27.0 → 0.28.0

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