origen_spi 0.1.0

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