origen 0.28.2 → 0.29.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/bin/origen +14 -2
  3. data/config/version.rb +2 -2
  4. data/lib/origen.rb +72 -45
  5. data/lib/origen/application.rb +29 -19
  6. data/lib/origen/application/deployer.rb +3 -1
  7. data/lib/origen/application/runner.rb +10 -8
  8. data/lib/origen/chip_mode.rb +1 -1
  9. data/lib/origen/commands.rb +24 -12
  10. data/lib/origen/commands/version.rb +1 -1
  11. data/lib/origen/commands_global.rb +32 -8
  12. data/lib/origen/core_ext.rb +1 -2
  13. data/lib/origen/core_ext/enumerable.rb +2 -2
  14. data/lib/origen/core_ext/integer.rb +85 -0
  15. data/lib/origen/core_ext/numeric.rb +28 -4
  16. data/lib/origen/global_app.rb +9 -0
  17. data/lib/origen/log.rb +1 -1
  18. data/lib/origen/model_initializer.rb +6 -1
  19. data/lib/origen/netlist/list.rb +2 -2
  20. data/lib/origen/org_file.rb +125 -0
  21. data/lib/origen/org_file/interceptable.rb +44 -0
  22. data/lib/origen/org_file/interceptor.rb +100 -0
  23. data/lib/origen/parameters/set.rb +1 -1
  24. data/lib/origen/pins.rb +4 -0
  25. data/lib/origen/pins/function_proxy.rb +8 -0
  26. data/lib/origen/pins/pin.rb +90 -38
  27. data/lib/origen/pins/pin_collection.rb +61 -21
  28. data/lib/origen/ports/port.rb +1 -1
  29. data/lib/origen/registers.rb +1 -1
  30. data/lib/origen/registers/reg.rb +1 -1
  31. data/lib/origen/remote_manager.rb +25 -15
  32. data/lib/origen/site_config.rb +140 -13
  33. data/lib/origen/specs/checkers.rb +2 -2
  34. data/lib/origen/sub_blocks.rb +6 -1
  35. data/lib/origen/value.rb +119 -0
  36. data/lib/origen/value/bin_str_val.rb +72 -0
  37. data/lib/origen/value/hex_str_val.rb +100 -0
  38. data/origen_site_config.yml +15 -8
  39. metadata +12 -6
  40. data/lib/origen/core_ext/bignum.rb +0 -38
  41. data/lib/origen/core_ext/fixnum.rb +0 -56
@@ -1,7 +1,6 @@
1
1
  require 'origen/core_ext/object'
2
2
  require 'origen/core_ext/string'
3
- require 'origen/core_ext/fixnum'
4
- require 'origen/core_ext/bignum'
3
+ require 'origen/core_ext/integer'
5
4
  require 'origen/core_ext/numeric'
6
5
  require 'origen/core_ext/module'
7
6
  require 'origen/core_ext/hash'
@@ -1,5 +1,5 @@
1
1
  module Enumerable
2
- PRIMATIVES = [TrueClass, FalseClass, NilClass, Integer, Float, String, Symbol, Regexp, Complex, Rational, Fixnum, Bignum]
2
+ PRIMATIVES = [TrueClass, FalseClass, NilClass, String, Symbol, Regexp, Numeric]
3
3
 
4
4
  def debug(msg)
5
5
  Origen.log.debug(msg)
@@ -48,7 +48,7 @@ module Enumerable
48
48
  end
49
49
  next
50
50
  else
51
- next unless options[:select].empty? || options[:select].include?(item.class) || PRIMATIVES.include?(item.class)
51
+ next unless options[:select].empty? || options[:select].include?(item.class) || PRIMATIVES.any? { |klass| item.is_a?(klass) }
52
52
  next if options[:ignore].include?(item.class)
53
53
  case item
54
54
  when NilClass
@@ -0,0 +1,85 @@
1
+ # The base class of ALL integers, i.e. including Fixum and Bignum
2
+
3
+ # Shim to handle Ruby < 2.4.0, where [] is implemented in Fixnum/Bignum instead
4
+ # of Integer
5
+ module Origen
6
+ module IntegerExtension
7
+ def [](*args)
8
+ if args.length == 1 && !args.first.is_a?(Range)
9
+ super
10
+ else
11
+ if args.first.is_a?(Range)
12
+ msb = args.first.first
13
+ lsb = args.first.last
14
+ else
15
+ msb = args.first
16
+ lsb = args.last
17
+ end
18
+ (self >> lsb) & 0.ones_comp(msb - lsb + 1)
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ class Integer
25
+ if RUBY_VERSION >= '2.4.0'
26
+ prepend Origen::IntegerExtension
27
+ end
28
+
29
+ # Implements 10.cycles
30
+ def cycles
31
+ if block_given?
32
+ times do
33
+ yield
34
+ Origen.app.tester.cycle
35
+ end
36
+ else
37
+ Origen.app.tester.cycle(repeat: self)
38
+ end
39
+ end
40
+ alias_method :cycle, :cycles
41
+
42
+ def ones_comp(num_bits)
43
+ self ^ ((1 << num_bits) - 1)
44
+ end
45
+ alias_method :ones_complement, :ones_comp
46
+ alias_method :ones_compliment, :ones_comp
47
+
48
+ # Returns a bit mask for the given number of bits:
49
+ #
50
+ # 4.to_bit_mask # => 0x1111
51
+ def to_bit_mask
52
+ (1 << self) - 1
53
+ end
54
+ alias_method :bit_mask, :to_bit_mask
55
+
56
+ def to_bool
57
+ if self == 1
58
+ return true
59
+ elsif self == 0
60
+ return false
61
+ else
62
+ return nil
63
+ end
64
+ end
65
+
66
+ def to_spreadsheet_column
67
+ index_hash = Hash.new { |hash, key| hash[key] = hash[key - 1].next }.merge(0 => 'A')
68
+ index_hash[self]
69
+ end
70
+ alias_method :to_xls_column, :to_spreadsheet_column
71
+ alias_method :to_xlsx_column, :to_spreadsheet_column
72
+ alias_method :to_xls_col, :to_spreadsheet_column
73
+ alias_method :to_xlsx_col, :to_spreadsheet_column
74
+ alias_method :to_spreadsheet_col, :to_spreadsheet_column
75
+ end
76
+
77
+ if RUBY_VERSION <= '2.4.0'
78
+ class Fixnum
79
+ prepend Origen::IntegerExtension
80
+ end
81
+
82
+ class Bignum
83
+ prepend Origen::IntegerExtension
84
+ end
85
+ end
@@ -1,6 +1,30 @@
1
+ # The base class of all numbers, i.e. integers and floats
1
2
  class Numeric
2
- def undefined?
3
- false
3
+ # Helpers for cases where a method may return a 0, 1 or an instance
4
+ # of Origen::Value::X or Origen::Value::Z
5
+
6
+ def z?;
7
+ false;
8
+ end
9
+
10
+ def hi_z?;
11
+ false;
12
+ end
13
+
14
+ def x?;
15
+ false;
16
+ end
17
+
18
+ def undefined?;
19
+ false;
20
+ end
21
+
22
+ def x_or_z?;
23
+ false;
24
+ end
25
+
26
+ def z_or_x?;
27
+ false;
4
28
  end
5
29
 
6
30
  def to_hex
@@ -65,13 +89,13 @@ class Numeric
65
89
 
66
90
  # Msps ==> Mega samples per second
67
91
 
68
- %w(GHz Ghz GTs Gts Gsps).each do |m|
92
+ %w(GHz Ghz GTs Gts Gsps Gbps).each do |m|
69
93
  define_method m do
70
94
  self * 1_000_000_000
71
95
  end
72
96
  end
73
97
 
74
- %w(MHz Mhz MTs Mts Msps).each do |m|
98
+ %w(MHz Mhz MTs Mts Msps Mbps).each do |m|
75
99
  define_method m do
76
100
  self * 1_000_000
77
101
  end
@@ -0,0 +1,9 @@
1
+ class OrigenGlobalApplication < Origen::Application
2
+ config.output_directory do
3
+ "#{Origen.root}/origen"
4
+ end
5
+
6
+ config.reference_directory do
7
+ "#{Origen.root}/origen/.ref"
8
+ end
9
+ end
@@ -35,7 +35,7 @@ module Origen
35
35
  end
36
36
 
37
37
  def console_only?
38
- self.class.console_only? || !Origen.app
38
+ self.class.console_only? || !Origen.app || Origen.running_globally?
39
39
  end
40
40
 
41
41
  # Anything executed within the given block will log to the console only
@@ -14,7 +14,7 @@ module Origen
14
14
  x.send(:init_sub_blocks, *args) if x.respond_to?(:init_sub_blocks)
15
15
  if x.respond_to?(:version=)
16
16
  version = options[:version]
17
- version ||= args.first if args.first.is_a?(Fixnum)
17
+ version ||= args.first if args.first.is_a?(Integer)
18
18
  x.version = version
19
19
  end
20
20
  if x.respond_to?(:parent=)
@@ -47,6 +47,11 @@ module Origen
47
47
  is_top_level = x.respond_to?(:includes_origen_top_level?)
48
48
  if x.respond_to?(:wrap_in_controller)
49
49
  x = x.wrap_in_controller
50
+ # If this object has been instantiated after on_create has already been called,
51
+ # then invoke it now
52
+ if Origen.application_loaded? && Origen.app.on_create_called?
53
+ x.controller.on_create if x.controller.respond_to?(:on_create)
54
+ end
50
55
  end
51
56
  if is_top_level
52
57
  Origen.app.listeners_for(:on_top_level_instantiated, top_level: false).each do |listener|
@@ -49,7 +49,7 @@ module Origen
49
49
  else
50
50
  from_proc = false
51
51
  end
52
- if val.is_a?(Fixnum)
52
+ if val.is_a?(Integer)
53
53
  bits << Registers::Bit.new(nil, index, access: :ro, data: (i == '*' && !from_proc) ? val[index] : val)
54
54
  elsif val
55
55
  vp, vi = *to_v(val)
@@ -122,7 +122,7 @@ module Origen
122
122
  end
123
123
 
124
124
  def clean(path)
125
- if path.is_a?(Fixnum)
125
+ if path.is_a?(Integer)
126
126
  { path: path, numeric: true }
127
127
  elsif path.is_a?(Proc)
128
128
  { path: path, proc: true }
@@ -0,0 +1,125 @@
1
+ module Origen
2
+ class OrgFile
3
+ autoload :Interceptor, 'origen/org_file/interceptor'
4
+ autoload :Interceptable, 'origen/org_file/interceptable'
5
+
6
+ class << self
7
+ def new(*args, &block)
8
+ if @internal_new
9
+ super
10
+ else
11
+ open(*args, &block)
12
+ end
13
+ end
14
+
15
+ def open(id, options = {})
16
+ fail "An org_file is already open with id: #{id}" if open_files[id]
17
+ @internal_new = true
18
+ f = OrgFile.new(id, options)
19
+ @internal_new = nil
20
+ open_files[id] = f
21
+ if block_given?
22
+ yield f
23
+ close(id, options)
24
+ else
25
+ f
26
+ end
27
+ end
28
+
29
+ def close(id, options = {})
30
+ fail "An org_file with this ID has not been opened id: #{id}" unless open_files[id]
31
+ open_files[id].close unless options[:_internal_org_file_call_]
32
+ open_files[id] = nil
33
+ end
34
+
35
+ def org_file(id = nil)
36
+ id ? open_files[id] : open_files.to_a.last[1]
37
+ end
38
+
39
+ def cycle(number = 1)
40
+ open_files.each { |id, f| f.cycle(number) }
41
+ end
42
+
43
+ private
44
+
45
+ def open_files
46
+ @open_files ||= {}.with_indifferent_access
47
+ end
48
+ end
49
+
50
+ attr_accessor :path, :filename
51
+ attr_reader :id, :operation
52
+
53
+ def initialize(id, options = {})
54
+ @id = id
55
+ @path = options[:path] || default_filepath
56
+ @filename = options[:filename] || "#{id}.org"
57
+ FileUtils.mkdir_p(path)
58
+ @path_to_file = File.join(path, filename)
59
+ end
60
+
61
+ def default_filepath
62
+ "#{Origen.root}/pattern/org/#{Origen.target.name}"
63
+ end
64
+
65
+ def file
66
+ @file ||= begin
67
+ if operation == 'r'
68
+ fail "No org file found at: #{@path_to_file}" unless exist?
69
+ end
70
+ File.open(@path_to_file, operation)
71
+ end
72
+ end
73
+
74
+ def exist?
75
+ File.exist?(@path_to_file)
76
+ end
77
+
78
+ def close
79
+ # Corner case, if no call to read_line or record was made then no file was created and there
80
+ # is no file to close
81
+ if @file
82
+ file.puts "#{@buffer}#{@buffer_cycles}" if @buffer
83
+ file.close
84
+ end
85
+ self.class.close(id, _internal_org_file_call_: true)
86
+ nil
87
+ end
88
+
89
+ def read_line
90
+ @operation ||= 'r'
91
+ operations = file.readline.strip.split(';')
92
+ cycles = operations.pop.to_i
93
+ operations = operations.map { |op| op.split(',') }.map { |op| op[0] = eval(op[0]); op }
94
+ if block_given?
95
+ yield operations, cycles
96
+ else
97
+ [operations, cycles]
98
+ end
99
+ end
100
+
101
+ def record(path_to_object, method, *args)
102
+ @operation ||= 'w'
103
+ @line ||= ''
104
+ @line += "#{path_to_object},#{method}"
105
+ @line += ",#{args.join(',')}" unless args.empty?
106
+ @line += ';'
107
+ end
108
+
109
+ def cycle(number)
110
+ if @buffer
111
+ if @line == @buffer
112
+ @buffer_cycles += 1
113
+ else
114
+ file.puts "#{@buffer}#{@buffer_cycles}"
115
+ @buffer = @line
116
+ @buffer_cycles = 1
117
+ end
118
+ else
119
+ @buffer = @line
120
+ @buffer_cycles = 1
121
+ end
122
+ @line = nil
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,44 @@
1
+ module Origen
2
+ class OrgFile
3
+ module Interceptable
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+
7
+ # Defers this executing until the whole class has loaded
8
+ Origen.after_app_loaded do
9
+ unless (base.instance_methods - Object.methods).include?(:global_path_to)
10
+ puts 'When adding the OrgFile::Interceptable module to a class, the class must define an instance method called "global_path_to", like this:'
11
+ puts
12
+ puts ' # Must return a string that contains a global path to access the given object,'
13
+ puts ' # here for example if the object was a pin'
14
+ puts ' def global_path_to'
15
+ puts ' "dut.pins(:#{id})"'
16
+ puts ' end'
17
+ fail "Incomplete integration of OrgFile::Interceptable in #{base}"
18
+ end
19
+ end
20
+ end
21
+
22
+ module ClassMethods
23
+ def new(*args, &block)
24
+ o = allocate
25
+ i = OrgFile::Interceptor.new(o)
26
+ o.__interceptor__ = i
27
+ i.send(:initialize, *args, &block)
28
+ i
29
+ end
30
+ end
31
+
32
+ # Class which include OrgFile::Interceptor should use 'myself' anytime then want to reference 'self',
33
+ # this ensures that there are never any references to the unwrapped object
34
+ def myself
35
+ @__interceptor__
36
+ end
37
+
38
+ # @api private
39
+ def __interceptor__=(obj)
40
+ @__interceptor__ = obj
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,100 @@
1
+ require 'set'
2
+ module Origen
3
+ class OrgFile
4
+ # @api private
5
+ #
6
+ # Helper for the Interceptor where block_given? doesn't work internally
7
+ def self._block_given_?(&block)
8
+ block_given?
9
+ end
10
+
11
+ class Interceptor < ::BasicObject
12
+ def initialize(object, options = {})
13
+ @object = object
14
+ @@locked = false unless defined? @@locked
15
+ end
16
+
17
+ def inspect(*args)
18
+ @object.inspect(*args)
19
+ end
20
+
21
+ def ==(obj)
22
+ if obj.respond_to?(:__org_file_interceptor__)
23
+ @object == obj.__object__
24
+ else
25
+ @object == obj
26
+ end
27
+ end
28
+ alias_method :equal?, :==
29
+
30
+ def record_to_org_file(id = nil, options = {})
31
+ id, options = nil, id if id.is_a?(::Hash)
32
+ if options[:only]
33
+ @org_file_methods_to_intercept = Array(options[:only]).to_set
34
+ else
35
+ @org_file_methods_to_intercept = default_org_file_captures
36
+ if options[:also]
37
+ @org_file_methods_to_intercept += Array(options[:also]).to_set
38
+ end
39
+ end
40
+ @org_file ||= @old_org_file || OrgFile.org_file(id)
41
+ end
42
+
43
+ # Temporarily stop recording operations within the given block, or stop recording
44
+ # completely if no block given
45
+ def stop_recording_to_org_file(&block)
46
+ @old_org_file = @org_file
47
+ if OrgFile._block_given_?(&block)
48
+ @org_file = nil
49
+ yield
50
+ @org_file = @old_org_file
51
+ else
52
+ @org_file = nil
53
+ end
54
+ end
55
+
56
+ def method_missing(method, *args, &block)
57
+ if !@@locked && @org_file && @org_file_methods_to_intercept.include?(method)
58
+ @org_file.record(@object.global_path_to, method, *args)
59
+ # Locking prevents an operation on an intercepted container object trigger from generating multiple
60
+ # org file entries if its contained objects are also intercepted. e.g. Imagine this is a pin group, we
61
+ # want the org file to reflect the operation called on the pin group, but not the many subsequent internal
62
+ # operations as the group proxies the operation to its contained pins
63
+ @@locked = true
64
+ @object.send(method, *args, &block)
65
+ @@locked = false
66
+ else
67
+ @object.send(method, *args, &block)
68
+ end
69
+ end
70
+
71
+ def respond_to?(method, include_private = false)
72
+ method == :__org_file_interceptor__ ||
73
+ @object.respond_to?(method, include_private)
74
+ end
75
+
76
+ def __org_file_interceptor__
77
+ true
78
+ end
79
+
80
+ # @api private
81
+ #
82
+ # Don't ever use this! An un-wrapped reference to an object must never make it into
83
+ # application code or else any operations called on the un-wrapped reference will not
84
+ # be captured.
85
+ def __object__
86
+ @object
87
+ end
88
+
89
+ private
90
+
91
+ def debugger
92
+ ::Kernel.debugger
93
+ end
94
+
95
+ def default_org_file_captures
96
+ @default_captures ||= Array(@object.try(:org_file_intercepted_methods)).to_set
97
+ end
98
+ end
99
+ end
100
+ end