origen_spi 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 83377bd6ba21533463dfa2f7b8a55ad734f53d4b
4
+ data.tar.gz: 375eee9fca4d3ff5482cae9ce6742515587e498e
5
+ SHA512:
6
+ metadata.gz: 548a96549d1c0fb2f21a3c42377fba70735092efc6c2be46bd2f6661c5e4558f1cd22890f6a47098163829289d1e616fc0933ef81289f40c12e4160216fcaff6
7
+ data.tar.gz: 976eff869da5fe052bfa92c756089b6328990f2e6fbeef0cc46c319b03ac25acfe1218b491edf8646ac3a9dc9f865235d6ec7461990f5deb636146cb2f6b5b9f
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env ruby
2
+ $VERBOSE = nil # Don't care about world writable dir warnings and the like
3
+
4
+ if $_fix_my_workspace_version_check
5
+ $_fix_my_workspace_version = '0.7.0'
6
+ else
7
+ if File.exist?(File.expand_path('../../lib/origen.rb', __FILE__))
8
+ # If this script is being run from within an origen-core workspace, use that Origen-core,
9
+ # not the system-installed origen-core version.
10
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
11
+ require 'origen'
12
+ else
13
+ # Use system-installed Origen (the gem in system Ruby)
14
+ require 'origen'
15
+ end
16
+
17
+ if !Origen.site_config.gem_manage_bundler
18
+ puts 'Sorry but you have opted to manage Bundler yourself via your Origen site config, and this means'
19
+ puts 'that I cannot make certain assumptions about how your workspace is configured.'
20
+ puts 'You will need to either resolve this problem yourself, or else change the value of'
21
+ puts 'gem_mange_bundler to true.'
22
+ puts 'See here for more details on how to do that: http://origen-sdk.org/origen/guides/starting/company/'
23
+
24
+ else
25
+ ENV['BUNDLE_GEMFILE'] = File.join(Origen.root, 'Gemfile')
26
+ ENV['BUNDLE_PATH'] = File.expand_path(Origen.site_config.gem_install_dir)
27
+ ENV['BUNDLE_BIN'] = File.join(Origen.root, 'lbin')
28
+
29
+ # Force copy system gems to local gems
30
+ if Origen.site_config.gem_use_from_system
31
+ local_gem_dir = "#{ENV['BUNDLE_PATH']}/ruby/#{Pathname.new(Gem.dir).basename}"
32
+ gem_dir = Pathname.new(Gem.dir)
33
+
34
+ Origen.site_config.gem_use_from_system.each do |gem, version|
35
+ begin
36
+ # This will raise an error if the system doesn't have this gem installed, that
37
+ # will be rescued below
38
+ spec = Gem::Specification.find_by_name(gem, version)
39
+
40
+ local_dir = File.join(local_gem_dir, Pathname.new(spec.gem_dir).relative_path_from(gem_dir))
41
+ FileUtils.mkdir_p local_dir
42
+ FileUtils.cp_r("#{spec.gem_dir}/.", local_dir)
43
+
44
+ local_file = Pathname.new(File.join(local_gem_dir, Pathname.new(spec.cache_file).relative_path_from(gem_dir)))
45
+ FileUtils.mkdir_p local_file.dirname
46
+ FileUtils.cp(spec.cache_file, local_file)
47
+
48
+ if spec.extension_dir && File.exist?(spec.extension_dir)
49
+ local_dir = File.join(local_gem_dir, Pathname.new(spec.extension_dir).relative_path_from(gem_dir))
50
+ FileUtils.mkdir_p local_dir
51
+ FileUtils.cp_r("#{spec.extension_dir}/.", local_dir)
52
+ end
53
+
54
+ local_file = Pathname.new(File.join(local_gem_dir, Pathname.new(spec.spec_file).relative_path_from(gem_dir)))
55
+ FileUtils.mkdir_p local_file.dirname
56
+ FileUtils.cp(spec.spec_file, local_file)
57
+
58
+ rescue Gem::LoadError
59
+ # This just means that one of the gems that should be copied from the system
60
+ # was not actually installed in the system, so nothing we can do about that here
61
+ end
62
+ end
63
+ end
64
+
65
+ # Delete lbin
66
+ FileUtils.rm_rf(ENV['BUNDLE_BIN']) if File.exist?(ENV['BUNDLE_BIN'])
67
+
68
+ # Run bundler with correct switches
69
+ cmd = "bundle install --gemfile #{ENV['BUNDLE_GEMFILE']} --binstubs #{ENV['BUNDLE_BIN']} --path #{ENV['BUNDLE_PATH']}"
70
+ `chmod o-w #{Origen.root}` # Stops some annoying world writable warnings during install
71
+ `chmod o-w #{Origen.root}/bin` if File.exist?("#{Origen.root}/bin")
72
+ `chmod o-w #{Origen.root}/.bin` if File.exist?("#{Origen.root}/.bin")
73
+
74
+ # Try again, this time updating the bundle
75
+ if system(cmd)
76
+ fixed = true
77
+ elsif system 'bundle update'
78
+ fixed = true
79
+ end
80
+
81
+ if File.exist?(ENV['BUNDLE_BIN'])
82
+ `chmod o-w #{ENV['BUNDLE_BIN']}`
83
+
84
+ # Make .bat versions of all executables, Bundler should really be doing this when running
85
+ # on windows
86
+ if Origen.os.windows?
87
+ Dir.glob("#{ENV['BUNDLE_BIN']}/*").each do |bin|
88
+ unless bin =~ /.bat$/
89
+ bat = "#{bin}.bat"
90
+ unless File.exist?(bat)
91
+ File.open(bat, 'w') { |f| f.write('@"ruby.exe" "%~dpn0" %*') }
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ system 'origen -v' if fixed
99
+ end
100
+ end
@@ -0,0 +1,103 @@
1
+ require 'origen'
2
+ class OrigenSpiApplication < Origen::Application
3
+
4
+ # See http://origen-sdk.org/origen/api/Origen/Application/Configuration.html
5
+ # for a full list of the configuration options available
6
+
7
+ # These attributes should never be changed, the duplication here will be resolved in future
8
+ # by condensing these attributes that do similar things
9
+ self.name = "origen_spi"
10
+ self.namespace = "OrigenSpi"
11
+ config.name = "origen_spi"
12
+ config.initials = "OrigenSpi"
13
+ # Change this to point to the revision control repository for this plugin
14
+ config.rc_url = "https://github.com/Origen-SDK/origen_spi.git"
15
+ config.release_externally = true
16
+
17
+ # To enable deployment of your documentation to a web server (via the 'origen web'
18
+ # command) fill in these attributes.
19
+ config.web_directory = "git@github.com:Origen-SDK/Origen-SDK.github.io.git/origen_spi"
20
+ config.web_domain = "http://origen-sdk.org/origen_spi"
21
+
22
+ # When false Origen will be less strict about checking for some common coding errors,
23
+ # it is recommended that you leave this to true for better feedback and easier debug.
24
+ # This will be the default setting in Origen v3.
25
+ config.strict_errors = true
26
+
27
+ # See: http://origen-sdk.org/origen/latest/guides/utilities/lint/
28
+ config.lint_test = {
29
+ # Require the lint tests to pass before allowing a release to proceed
30
+ run_on_tag: true,
31
+ # Auto correct violations where possible whenever 'origen lint' is run
32
+ auto_correct: true,
33
+ # Limit the testing for large legacy applications
34
+ #level: :easy,
35
+ # Run on these directories/files by default
36
+ #files: ["lib", "config/application.rb"],
37
+ }
38
+
39
+ config.semantically_version = true
40
+
41
+ # An example of how to set application specific LSF parameters
42
+ #config.lsf.project = "msg.te"
43
+
44
+ # An example of how to specify a prefix to add to all generated patterns
45
+ #config.pattern_prefix = "nvm"
46
+
47
+ # An example of how to add header comments to all generated patterns
48
+ #config.pattern_header do
49
+ # cc "This is a pattern created by the example origen application"
50
+ #end
51
+
52
+ # By default all generated output will end up in ./output.
53
+ # Here you can specify an alternative directory entirely, or make it dynamic such that
54
+ # the output ends up in a setup specific directory.
55
+ #config.output_directory do
56
+ # "#{Origen.root}/output/#{$dut.class}"
57
+ #end
58
+
59
+ # Similarly for the reference files, generally you want to setup the reference directory
60
+ # structure to mirror that of your output directory structure.
61
+ #config.reference_directory do
62
+ # "#{Origen.root}/.ref/#{$dut.class}"
63
+ #end
64
+
65
+ # This will automatically deploy your documentation after every tag
66
+ #def after_release_email(tag, note, type, selector, options)
67
+ # command = "origen web compile --remote --api"
68
+ # Dir.chdir Origen.root do
69
+ # system command
70
+ # end
71
+ #end
72
+
73
+ # Ensure that all tests pass before allowing a release to continue
74
+ #def validate_release
75
+ # if !system("origen specs") || !system("origen examples")
76
+ # puts "Sorry but you can't release with failing tests, please fix them and try again."
77
+ # exit 1
78
+ # else
79
+ # puts "All tests passing, proceeding with release process!"
80
+ # end
81
+ #end
82
+
83
+ # To enabled source-less pattern generation create a class (for example PatternDispatcher)
84
+ # to generate the pattern. This should return false if the requested pattern has been
85
+ # dispatched, otherwise Origen will proceed with looking up a pattern source as normal.
86
+ #def before_pattern_lookup(requested_pattern)
87
+ # PatternDispatcher.new.dispatch_or_return(requested_pattern)
88
+ #end
89
+
90
+ # If you use pattern iterators you may come across the case where you request a pattern
91
+ # like this:
92
+ # origen g example_pat_b0.atp
93
+ #
94
+ # However it cannot be found by Origen since the pattern name is actually example_pat_bx.atp
95
+ # In the case where the pattern cannot be found Origen will pass the name to this translator
96
+ # if it exists, and here you can make any substitutions to help Origen find the file you
97
+ # want. In this example any instances of _b\d, where \d means a number, are replaced by
98
+ # _bx.
99
+ #config.pattern_name_translator do |name|
100
+ # name.gsub(/_b\d/, "_bx")
101
+ #end
102
+
103
+ end
data/config/boot.rb ADDED
@@ -0,0 +1,24 @@
1
+ # This file is used to boot your plugin when it is running in standalone mode
2
+ # from its own workspace - i.e. when the plugin is being developed.
3
+ #
4
+ # It will not be loaded when the plugin is imported by a 3rd party app - in that
5
+ # case only lib/origen_spi.rb is loaded.
6
+ #
7
+ # Therefore this file can be used to load anything extra that you need to boot
8
+ # the development environment for this app. For example, this is typically used
9
+ # to load some additional test classes to use your plugin APIs so that they can
10
+ # be tested and/or interacted with in the console.
11
+ require "origen_spi"
12
+
13
+ module OrigenSpiDev
14
+ # Example of how to explicitly require a file
15
+ # require "origen_spi_dev/my_file"
16
+
17
+ # Load all files in the lib/origen_spi_dev directory.
18
+ # Note that there is no problem from requiring a file twice (Ruby will ignore
19
+ # the second require), so if you have a file that must be required first, then
20
+ # explicitly require it up above and then let this take care of the rest.
21
+ Dir.glob("#{File.dirname(__FILE__)}/../lib/origen_spi_dev/**/*.rb").sort.each do |file|
22
+ require file
23
+ end
24
+ end
@@ -0,0 +1,81 @@
1
+ # This file should be used to extend the origen with application specific commands
2
+
3
+ # Map any command aliases here, for example to allow 'origen ex' to refer to a
4
+ # command called execute you would add a reference as shown below:
5
+ aliases ={
6
+ # "ex" => "execute",
7
+ }
8
+
9
+ # The requested command is passed in here as @command, this checks it against
10
+ # the above alias table and should not be removed.
11
+ @command = aliases[@command] || @command
12
+
13
+ # Now branch to the specific task code
14
+ case @command
15
+
16
+ # (Working) example of how to create an application specific comment, here to generate
17
+ # a tags file for you application to enable method definition lookup and similar within
18
+ # editors/IDEs
19
+ when "tags"
20
+ # Here the logic is just written in-line, alternatively it could be written in a
21
+ # dedicated file and required here, e.g.
22
+ #require "origen_spi/commands/my_command" # Would load file lib/origen_spi/commands/my_command.rb
23
+ Dir.chdir Origen.root do
24
+ system("ripper-tags -R")
25
+ end
26
+ # You must always exit upon successfully capturing and executing a command to prevent
27
+ # control flowing back to Origen
28
+ exit 0
29
+
30
+ ## Example of how to make a command to run unit tests, this simply invokes RSpec on
31
+ ## the spec directory
32
+ when "specs"
33
+ require "rspec"
34
+ exit RSpec::Core::Runner.run(['spec'])
35
+
36
+ ## Example of how to make a command to run diff-based tests
37
+ when "examples", "test"
38
+ Origen.load_application
39
+ status = 0
40
+
41
+ ARGV = %w(pattern/clock_test.rb -t default.rb -e default.rb -r approved)
42
+ load "#{Origen.top}/lib/origen/commands/generate.rb"# #ARGV = %w(some_pattern -t debug -r approved)
43
+
44
+ ARGV = %w(pattern/shift_test.rb -t default.rb -e default.rb -r approved)
45
+ load "#{Origen.top}/lib/origen/commands/generate.rb"# #ARGV = %w(some_pattern -t debug -r approved)
46
+
47
+ ARGV = %w(pattern/overlay_test.rb -t default.rb -e default.rb -r approved)
48
+ load "#{Origen.top}/lib/origen/commands/generate.rb"# #ARGV = %w(some_pattern -t debug -r approved)
49
+
50
+ if Origen.app.stats.changed_files == 0 &&
51
+ Origen.app.stats.new_files == 0 &&
52
+ Origen.app.stats.changed_patterns == 0 &&
53
+ Origen.app.stats.new_patterns == 0
54
+
55
+ Origen.app.stats.report_pass
56
+ else
57
+ Origen.app.stats.report_fail
58
+ status = 1
59
+ end
60
+ puts
61
+ if @command == "test"
62
+ Origen.app.unload_target!
63
+ require "rspec"
64
+ result = RSpec::Core::Runner.run(['spec'])
65
+ status = status == 1 ? 1 : result
66
+ end
67
+ exit status # Exit with a 1 on the event of a failure per std unix result codes
68
+
69
+ # Always leave an else clause to allow control to fall back through to the
70
+ # Origen command handler.
71
+ else
72
+ # You probably want to also add the your commands to the help shown via
73
+ # origen -h, you can do this by assigning the required text to @application_commands
74
+ # before handing control back to Origen.
75
+ @application_commands = <<-EOT
76
+ tags Build a tags file for this app
77
+ EOT
78
+ # specs Run the specs (tests), -c will enable coverage
79
+ # examples Run the examples (tests), -c will enable coverage
80
+ # test Run both specs and examples, -c will enable coverage
81
+ end
data/config/version.rb ADDED
@@ -0,0 +1,8 @@
1
+ module OrigenSpi
2
+ MAJOR = 0
3
+ MINOR = 1
4
+ BUGFIX = 0
5
+ DEV = nil
6
+
7
+ VERSION = [MAJOR, MINOR, BUGFIX].join(".") + (DEV ? ".pre#{DEV}" : '')
8
+ end
@@ -0,0 +1,362 @@
1
+ module OrigenSpi
2
+ class Driver
3
+ include Origen::Model
4
+
5
+ # Dut pin that serves as the spi clock
6
+ # @example
7
+ # spi_instance.sclk_pin = dut.pin(:p1)
8
+ attr_reader :sclk_pin
9
+
10
+ # Dut pin that serves as the master out slave in pin
11
+ # @example
12
+ # spi_instance.mosi_pin = dut.pin(:p2)
13
+ attr_reader :mosi_pin
14
+
15
+ # Dut pin that serves as the master in slave out
16
+ # @example
17
+ # spi_instance.miso_pin = dut.pin(:p3)
18
+ attr_reader :miso_pin
19
+
20
+ # Dut pin that serves as the slave select
21
+ # @example
22
+ # spi_instance.ss_pin = dut.pin(:p4)
23
+ # @example
24
+ # spi_instance.ss_pin = nil # no ss pin
25
+ attr_reader :ss_pin
26
+
27
+ # clock format
28
+ #
29
+ # available options are:
30
+ # :rl # return low - data changes while sclk is low, latches on rising edge
31
+ # :rh # return high
32
+ #
33
+ # @example
34
+ # spi_instance.clk_format = :rl
35
+ attr_reader :clk_format
36
+
37
+ # pin state corresponding to slave select active
38
+ # @example
39
+ # spi_instance.ss_active = 0
40
+ attr_reader :ss_active
41
+
42
+ # time between ss_active and the first spi clock
43
+ #
44
+ # hash containing the wait time
45
+ #
46
+ # @example
47
+ # spi_instance.clk_wait_time = {time_in_us: 0} # no delay
48
+ # spi_instance.clk_wait_time = {time_in_ms: 1} # 1ms delay
49
+ # spi_instance.clk_wait_time = {time_in_cycles: 2} # 2 cycle delay
50
+ attr_reader :clk_wait_time
51
+
52
+ # number of tester cycles per spi clock
53
+ attr_reader :clk_multiple
54
+
55
+ # cycle on which miso compares are placed (0 is the first cycle)
56
+ attr_reader :miso_compare_cycle
57
+
58
+ # data order
59
+ #
60
+ # available options are:
61
+ # :msb0 - MSB is shifted first
62
+ # :lsb0
63
+ #
64
+ # @example
65
+ # spi_instance.data_order = :lsb0
66
+ attr_reader :data_order
67
+
68
+ # internal attribute
69
+ attr_reader :settings_validated
70
+
71
+ # options hash can configure
72
+ #
73
+ # @example
74
+ # options = {
75
+ # sclk_pin: dut.pin(:p1),
76
+ # mosi_pin: dut.pin(:p2),
77
+ # miso_pin: dut.pin(:p3),
78
+ # ss_pin: dut.pin(:p4),
79
+ # clk_format: :rl,
80
+ # ss_active: 0,
81
+ # clk_wait_time: {time_in_cycles: 2},
82
+ # clk_multiple: 2,
83
+ # miso_compare_cycle: 1,
84
+ # data_order: :msb0
85
+ # }
86
+ # spi = OrigenSpi::Driver.new(options)
87
+ def initialize(options = {})
88
+ options = {
89
+ sclk_pin: nil,
90
+ mosi_pin: nil,
91
+ miso_pin: nil,
92
+ ss_pin: nil,
93
+ clk_format: :nr,
94
+ ss_active: 0,
95
+ clk_wait_time: { time_in_us: 0 },
96
+ clk_multiple: 2,
97
+ data_order: :msb0
98
+ }.merge(options)
99
+
100
+ @sclk_pin = options[:sclk_pin]
101
+ @mosi_pin = options[:mosi_pin]
102
+ @miso_pin = options[:miso_pin]
103
+ @ss_pin = options[:ss_pin]
104
+ @clk_format = options[:clk_format]
105
+ @ss_active = options[:ss_active]
106
+ @clk_wait_time = options[:clk_wait_time]
107
+ @clk_multiple = options[:clk_multiple]
108
+ @miso_compare_cycle = options[:miso_compare_cycle] ? options[:miso_compare_cycle] : @clk_multiple - 1
109
+ @data_order = options[:data_order]
110
+ @settings_validated = false
111
+ end
112
+
113
+ def sclk_pin=(pin)
114
+ @sclk_pin = pin
115
+ @settings_validated = false
116
+ end
117
+
118
+ def mosi_pin=(pin)
119
+ @mosi_pin = pin
120
+ @settings_validated = false
121
+ end
122
+
123
+ def miso_pin=(pin)
124
+ @miso_pin = pin
125
+ @settings_validated = false
126
+ end
127
+
128
+ def ss_pin=(pin)
129
+ @ss_pin = pin
130
+ @settings_validated = false
131
+ end
132
+
133
+ def clk_format=(format)
134
+ if format == :nr || format == :rl || format == :rh
135
+ @clk_format = format
136
+ else
137
+ Origen.log.error "Invalid clock format for OrigenSpi::Driver -> #{format}"
138
+ Origen.log.error 'Valid formats are :rl, :rh'
139
+ end
140
+ @settings_validated = false
141
+ end
142
+
143
+ def ss_active=(state)
144
+ if state == 0 || state == 1
145
+ @ss_active = state
146
+ else
147
+ Origen.log.error 'Invalid OrigenSpi::Driver.ss_active state (valid states are 0 and 1)'
148
+ end
149
+ @settings_validated = false
150
+ end
151
+
152
+ def clk_wait_time=(clk_wait)
153
+ @clk_wait_time = clk_wait
154
+ @settings_validated = false
155
+ end
156
+
157
+ def clk_multiple=(mult)
158
+ @clk_multiple = mult
159
+ @settings_validated = false
160
+ end
161
+
162
+ def miso_compare_cycle=(cycle)
163
+ @miso_compare_cycle = cycle
164
+ @settings_validated = false
165
+ end
166
+
167
+ def data_order=(order)
168
+ if order == :msb0 || order == :lsb0
169
+ @data_order = order
170
+ else
171
+ Origen.log.error "Invalid OrigenSpi::Driver.data_order -> #{order}, (use :msb0 or :lsb0)"
172
+ end
173
+ end
174
+
175
+ # Check settings
176
+ def validate_settings
177
+ unless @settings_validated
178
+ settings_valid = true
179
+
180
+ # check that clock and miso are provided
181
+ unless @sclk_pin.is_a?(Origen::Pins::Pin)
182
+ settings_valid = false
183
+ Origen.log.error 'OrigenSpi::Driver.sclk_pin must be an Origen pin object'
184
+ end
185
+
186
+ unless @clk_format == :rl || @clk_format == :rh
187
+ settings_valid = false
188
+ Origen.log.error 'OrigenSpi::Driver.clk_format must be one of :rl, :rh'
189
+ end
190
+
191
+ unless @ss_active == 0 || @ss_active == 1
192
+ settings_valid = false
193
+ Origen.log.error 'OrigenSpi::Driver.ss_active must be either 0 or 1'
194
+ end
195
+
196
+ @clk_multiple = 1 if @clk_multiple < 1
197
+ @half_cycle = @clk_multiple / 2
198
+
199
+ @miso_compare_cycle = @clk_multiple - 1 if @miso_compare_cycle > @clk_multiple - 1
200
+
201
+ unless @data_order == :msb0 || @data_order == :lsb0
202
+ settings_valid = false
203
+ Origen.log.error 'OrigenSpi::Driver.data_order must be either :msb0 or :lsb0'
204
+ end
205
+
206
+ @settings_validated = settings_valid
207
+ end
208
+ end
209
+
210
+ # Run a spi clock cycle
211
+ #
212
+ # This method can be used to clock the spi port without specifying shift data
213
+ def sclk_cycle
214
+ validate_settings
215
+ cc 'OrigenSpi::Driver - Issue a clock cycle'
216
+ @sclk_pin.restore_state do
217
+ @sclk_pin.drive @clk_format == :rl ? 0 : 1
218
+ @half_cycle.times { tester.cycle }
219
+ @sclk_pin.drive @clk_format == :rl ? 1 : 0
220
+ @half_cycle.upto(@clk_multiple - 1) { tester.cycle }
221
+ end
222
+ end
223
+
224
+ # Shift a spi packet
225
+ #
226
+ # Overlay and capture is specified through reg.overlay and reg.store
227
+ #
228
+ # @example
229
+ # spi_instance.shift master_out: out_reg, master_in: in_cmp_reg
230
+ # @example
231
+ # spi_instance.shift master_out: 0x7a, size: 32
232
+ # @example
233
+ # spi_instance.shift master_in: in_cmp_reg
234
+ def shift(options = {})
235
+ options = {
236
+ master_out: 0
237
+ }.merge(options)
238
+
239
+ validate_settings
240
+ options = validate_options(options)
241
+ out_reg = build_output_packet(options).bits
242
+ in_reg = build_input_packet(options).bits
243
+
244
+ # reverse bit order if :msb0
245
+ if @data_order == :msb0
246
+ out_reg = out_reg.reverse
247
+ in_reg = in_reg.reverse
248
+ end
249
+
250
+ # set ss active
251
+ @ss_pin.drive @ss_active unless @ss_pin.nil?
252
+
253
+ # apply wait time if requested
254
+ tester.wait @clk_wait_time unless @clk_wait_time == { time_in_us: 0 }
255
+
256
+ # now do the shifting
257
+ 0.upto(out_reg.size - 1) do |bit|
258
+ # park the clock
259
+ @sclk_pin.drive @clk_format == :rl ? 0 : 1
260
+ @miso_pin.dont_care unless @miso_pin.nil?
261
+
262
+ # setup the bit to be driven, prep for overlay if requested
263
+ overlay_options = {}
264
+ unless @mosi_pin.nil?
265
+ @mosi_pin.drive out_reg[bit].data
266
+ if out_reg[bit].has_overlay?
267
+ overlay_options[:pins] = @mosi_pin
268
+ overlay_options[:overlay_str] = out_reg[bit].overlay_str
269
+ end
270
+ end
271
+
272
+ # advance to clock active edge
273
+ @half_cycle.times do |c|
274
+ handle_miso c, in_reg[bit]
275
+ cycle overlay_options
276
+ overlay_options[:change_data] = false unless overlay_options == {}
277
+ end
278
+
279
+ # drive the clock to active
280
+ @sclk_pin.drive @clk_format == :rl ? 1 : 0
281
+
282
+ # advance to the end of the sclk cycle checking for appropriate miso compare placement
283
+ @half_cycle.upto(@clk_multiple - 1) do |c|
284
+ handle_miso c, in_reg[bit]
285
+ cycle overlay_options
286
+ end
287
+ end
288
+
289
+ # park the clock, mask miso, clear ss
290
+ @sclk_pin.drive @clk_format == :rl ? 0 : 1
291
+ @miso_pin.dont_care unless @miso_pin.nil?
292
+ @mosi_pin.drive 0 unless @mosi_pin.nil?
293
+ @ss_pin.drive @ss_active == 1 ? 0 : 1 unless @ss_pin.nil?
294
+ end
295
+
296
+ # Internal method
297
+ #
298
+ # Set the state of miso
299
+ def handle_miso(c, bit)
300
+ unless @miso_pin.nil?
301
+ if c == @miso_compare_cycle
302
+ @miso_pin.assert bit.data if bit.is_to_be_read?
303
+ tester.store_next_cycle @miso_pin if bit.is_to_be_stored?
304
+ else
305
+ @miso_pin.dont_care
306
+ end
307
+ end
308
+ end
309
+
310
+ # Internal method
311
+ #
312
+ # Issue a tester cycle, conditionally with overlay options supplied
313
+ def cycle(overlay_options = {})
314
+ overlay_options == {} ? tester.cycle : (tester.cycle overlay: overlay_options)
315
+ end
316
+
317
+ # Build the shift out packet
318
+ #
319
+ # This is an internal method used by the shift method
320
+ def build_output_packet(options)
321
+ out_reg = Origen::Registers::Reg.dummy(options[:size])
322
+ if options[:master_out].respond_to?(:data)
323
+ out_reg.copy_all(options[:master_out])
324
+ else
325
+ out_reg.write options[:master_out]
326
+ end
327
+ out_reg
328
+ end
329
+
330
+ # Build the input packet
331
+ #
332
+ # This is an internal method used by the shift method
333
+ def build_input_packet(options)
334
+ in_reg = Origen::Registers::Reg.dummy(options[:size])
335
+ if options[:master_in].respond_to?(:data)
336
+ in_reg.copy_all(options[:master_in])
337
+ else
338
+ unless options[:master_in].nil?
339
+ in_reg.write options[:master_in]
340
+ in_reg.read
341
+ end
342
+ end
343
+ in_reg
344
+ end
345
+
346
+ # Internal method that logs errors in options passed to the shift method
347
+ def validate_options(options)
348
+ # check that size of the packet can be determined
349
+ unless options[:size]
350
+ options[:size] = options[:master_in].size if options[:master_in].respond_to?(:data)
351
+ end
352
+ unless options[:size]
353
+ options[:size] = options[:master_out].size if options[:master_out].respond_to?(:data)
354
+ end
355
+ unless options[:size]
356
+ Origen.log.error "OrigenSpi::Driver can't determine the packet size"
357
+ exit
358
+ end
359
+ options
360
+ end
361
+ end
362
+ end
data/lib/origen_spi.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'origen'
2
+ require 'origen_testers'
3
+ require_relative '../config/application.rb'
4
+ module OrigenSpi
5
+ # THIS FILE SHOULD ONLY BE USED TO LOAD RUNTIME DEPENDENCIES
6
+ # If this plugin has any development dependencies (e.g. dummy DUT or other models that are only used
7
+ # for testing), then these should be loaded from config/boot.rb
8
+
9
+ # Example of how to explicitly require a file
10
+ # require "origen_spi/my_file"
11
+
12
+ # Load all files in the lib/origen_spi directory.
13
+ # Note that there is no problem from requiring a file twice (Ruby will ignore
14
+ # the second require), so if you have a file that must be required first, then
15
+ # explicitly require it up above and then let this take care of the rest.
16
+ Dir.glob("#{File.dirname(__FILE__)}/origen_spi/**/*.rb").sort.each do |file|
17
+ require file
18
+ end
19
+ end
@@ -0,0 +1,6 @@
1
+ # You can define any Rake tasks to support your application here (or in any file
2
+ # ending in .rake in this directory).
3
+ #
4
+ # Rake (Ruby Make) is very useful for creating build scripts, see this short video
5
+ # for a quick introduction:
6
+ # http://railscasts.com/episodes/66-custom-rake-tasks
@@ -0,0 +1,39 @@
1
+ Pattern.create do
2
+ tester.set_timeset 'tp0', 20
3
+ dut.pin(:ss).drive 1
4
+ dut.pin(:sclk).drive 0
5
+ dut.pin(:mosi).drive 0
6
+ dut.pin(:miso).dont_care
7
+
8
+ tester.cycle
9
+ dut.spi.sclk_cycle
10
+ tester.cycle
11
+
12
+ cc 'change multiple to 2'
13
+ dut.spi.clk_multiple = 2
14
+ dut.spi.sclk_cycle
15
+ tester.cycle
16
+
17
+ cc 'change multiple to 80'
18
+ dut.spi.clk_multiple = 80
19
+ dut.spi.sclk_cycle
20
+ tester.cycle
21
+
22
+ cc 'change clock format and repeat'
23
+ dut.pin(:sclk).drive 1
24
+ dut.spi.clk_format = :rh
25
+ dut.spi.clk_multiple = 1
26
+ dut.spi.sclk_cycle
27
+ tester.cycle
28
+
29
+ cc 'change multiple to 2'
30
+ dut.spi.clk_multiple = 2
31
+ dut.spi.sclk_cycle
32
+ tester.cycle
33
+
34
+ cc 'change multiple to 80'
35
+ dut.spi.clk_multiple = 80
36
+ dut.spi.sclk_cycle
37
+ tester.cycle
38
+
39
+ end
@@ -0,0 +1,18 @@
1
+ Pattern.create do
2
+ tester.set_timeset 'tp0', 20
3
+ dut.pin(:ss).drive 1
4
+ dut.pin(:sclk).drive 0
5
+ dut.pin(:mosi).drive 0
6
+ dut.pin(:miso).dont_care
7
+
8
+ tester.cycle
9
+ tester.overlay_style = :label
10
+ out_data = Origen::Registers::Reg.dummy(12).write 7
11
+ out_data.bits[3..0].overlay 'heres_the_label'
12
+ dut.spi.shift master_out: out_data
13
+
14
+ cc 'repeat test reversing bit order'
15
+ dut.spi.data_order = :msb0
16
+ out_data.bits[3..0].overlay 'heres_the_other_label'
17
+ dut.spi.shift master_out: out_data
18
+ end
@@ -0,0 +1,61 @@
1
+ Pattern.create do
2
+ tester.set_timeset 'tp0', 20
3
+ dut.pin(:ss).drive 1
4
+ dut.pin(:sclk).drive 0
5
+ dut.pin(:mosi).drive 0
6
+ dut.pin(:miso).dont_care
7
+
8
+ tester.cycle
9
+
10
+ out_data = Origen::Registers::Reg.dummy(12).write 7
11
+ in_data = Origen::Registers::Reg.dummy(12).read 0x5a5
12
+ cc 'shifting 12-bits lsb first, 0x7 out, 0x5a5 in'
13
+ dut.spi.shift master_out: out_data, master_in: in_data
14
+
15
+ tester.cycle
16
+
17
+ cc 'repeat 12-bits lsb first, 0x7 out, 0x5a5 in; clock multiple = 4'
18
+ dut.spi.clk_multiple = 4
19
+ dut.spi.shift master_out: out_data, master_in: in_data
20
+
21
+ tester.cycle
22
+
23
+ cc 'repeat 12-bits, 0x7 out, 0x5a5 in; clock multiple = 4, with msb first, move miso compare to cycle 3'
24
+ dut.spi.data_order = :msb0
25
+ dut.spi.miso_compare_cycle = 3
26
+ dut.spi.shift master_out: out_data, master_in: in_data
27
+
28
+ tester.cycle
29
+
30
+ cc 'Now check bit masking'
31
+ cc 'shift 0xa5a, 12-bits, msb first, multiple = 1, clk format :rh, all bits masked'
32
+ dut.spi.clk_format = :rh
33
+ dut.spi.clk_multiple = 1
34
+ dut.spi.shift master_out: 0xa5a, size: 12
35
+
36
+ tester.cycle
37
+
38
+ cc 'repeat same, comparing for LLLL_XXXX_HHHH, clock back to :rl'
39
+ dut.spi.clk_format = :rl
40
+ in_data.write 0xf
41
+ in_data.bits[11..8].read
42
+ in_data.bits[7..4].clear_flags
43
+ in_data.bits[3..0].read
44
+ dut.spi.shift master_out: 0xa5a, master_in: in_data
45
+
46
+ tester.cycle
47
+
48
+ cc 'test capture'
49
+ in_data.bits[7..4].store
50
+ dut.spi.shift master_out: 0xa5a, master_in: in_data
51
+
52
+ tester.cycle
53
+
54
+ # cc 'test overlay, label should appear at bit 3'
55
+ # out_data.write 0xa5a
56
+ # out_data.bits[3..0].overlay 'heres_the_label'
57
+ # tester.overlay_style = :label
58
+ # dut.spi.shift master_out: out_data
59
+
60
+ # tester.cycle
61
+ end
@@ -0,0 +1,68 @@
1
+ % render "layouts/basic.html" do
2
+
3
+ %# HTML tags can be embedded in mark down files if you want to do specific custom
4
+ %# formatting like this, but in most cases that is not required.
5
+ <h1><%= Origen.app.namespace %> <span style="font-size: 14px">(<%= Origen.app.version %>)</span></h1>
6
+
7
+ ### Purpose
8
+
9
+ This plugin implements SPI protocol with the tester acting as the master. There are 4 pins standard to SPI,
10
+ however only sclk is required by this plugin. Any pins that aren't provided are ignored. This plugin seeks
11
+ to be very flexible given that the SPI standard is itself very flexible.
12
+
13
+ ### How To Install
14
+
15
+ In your Gemfile add:
16
+
17
+ ~~~ruby
18
+ gem "<%= Origen.app.name %>"
19
+ ~~~
20
+
21
+ or if your application is a plugin, then add this to your <code>.gemspec</code>
22
+
23
+ ~~~ruby
24
+ spec.add_runtime_dependency "<%= Origen.app.name %>", ">= <%= Origen.app.version %>"
25
+ ~~~
26
+
27
+ __NOTE:__ In the case of a plugin, you will also need to <code>require '<%= Origen.app.name %>'</code> somewhere in your environment.
28
+
29
+
30
+ ### How To Use
31
+
32
+ The spi driver is intended to be instantiated as a sub_block. The configuration can be passed in as a hash and / or
33
+ can be changed after instantiation. See API for more details.
34
+
35
+ ~~~ruby
36
+ sub_block :spi, class_name: 'OrigenSpi::Driver',
37
+ sclk_pin: dut.pin(:sclk),
38
+ mosi_pin: dut.pin(:mosi),
39
+ miso_pin: dut.pin(:miso),
40
+ ss_pin: dut.pin(:ss),
41
+ # :rl - return low - input data changes while sclk is low and is latched on rising edge
42
+ clk_format: :rl,
43
+ # drive state of 0 activates the slave port
44
+ ss_active: 0,
45
+ # wait time after ss_active and before any sclk activity
46
+ clk_wait_time: {time_in_cycles: 2},
47
+ # number of sclks per tester.cycle
48
+ clk_multiple: 1,
49
+ data_order: :lsb0
50
+ ~~~
51
+
52
+ ~~~ruby
53
+ # configuration can be changed after instantiation like this
54
+ dut.spi.clk_multiple = 80
55
+ dut.spi.miso_compare_cycle = 79
56
+ dut.spi.ss_pin = nil
57
+ ~~~
58
+
59
+
60
+ ### How To Setup a Development Environment
61
+
62
+ To setup a development environment:
63
+
64
+ ~~~
65
+ git clone https://github.com/Origen-SDK/origen_spi.git
66
+ ~~~
67
+
68
+ % end
@@ -0,0 +1,13 @@
1
+ ---
2
+ title: <%= options[:title] || Origen.config.name %>
3
+ ---
4
+ <%= render "partials/navbar.html", tab: options[:tab] %>
5
+
6
+ <div class="row">
7
+ %# The markdown attribute is important if you are going to include content written
8
+ %# in markdown, without this is will be included verbatim
9
+ <div class="span12" markdown="1">
10
+ <%= yield %>
11
+
12
+ </div>
13
+ </div>
@@ -0,0 +1,20 @@
1
+ <nav class="navbar navbar-inverse navbar-fixed-top">
2
+ <div class="container">
3
+ <div class="navbar-header">
4
+ <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
5
+ <span class="sr-only">Toggle navigation</span>
6
+ <span class="icon-bar"></span>
7
+ <span class="icon-bar"></span>
8
+ <span class="icon-bar"></span>
9
+ </button>
10
+ <a class="navbar-brand" href="<%= path "/" %>">Home</a>
11
+ </div>
12
+ <div id="navbar" class="collapse navbar-collapse">
13
+ <ul class="nav navbar-nav">
14
+ <li class="<%= options[:tab] == :api ? 'active' : '' %>"><a href="<%= path "/api/" %>">API</a></li>
15
+ <li class="<%= options[:tab] == :release ? 'active' : '' %>"><a href="<%= path "/release_notes" %>">Release Notes</a></li>
16
+ </ul>
17
+ <%= import "origen/web/logo.html" %>
18
+ </div><!--/.nav-collapse -->
19
+ </div>
20
+ </nav>
@@ -0,0 +1,5 @@
1
+ % render "layouts/basic.html", tab: :release do
2
+
3
+ <%= render "#{Origen.root}/doc/history" %>
4
+
5
+ % end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: origen_spi
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Paul DeRouen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-12-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: origen
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.28.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.28.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: origen_testers
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.15.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.15.0
41
+ description:
42
+ email:
43
+ - paul.derouen@nxp.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - bin/fix_my_workspace
49
+ - config/application.rb
50
+ - config/boot.rb
51
+ - config/commands.rb
52
+ - config/version.rb
53
+ - lib/origen_spi.rb
54
+ - lib/origen_spi/driver.rb
55
+ - lib/tasks/origen_spi.rake
56
+ - pattern/clock_test.rb
57
+ - pattern/overlay_test.rb
58
+ - pattern/shift_test.rb
59
+ - templates/web/index.md.erb
60
+ - templates/web/layouts/_basic.html.erb
61
+ - templates/web/partials/_navbar.html.erb
62
+ - templates/web/release_notes.md.erb
63
+ homepage:
64
+ licenses: []
65
+ metadata: {}
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '2'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: 1.8.11
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 2.6.7
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: Driver for SPI protocol
86
+ test_files: []