origen_link 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +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
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
@@ -1,4 +1,4 @@
1
- Pattern.create do
2
- # Call controller methods from here...
3
- # $dut.atd.convert
4
- end
1
+ Pattern.create do
2
+ # Call controller methods from here...
3
+ # $dut.atd.convert
4
+ end
@@ -1,23 +1,23 @@
1
- Pattern.create(options={:name => "JTAG_CaptureID"})do
2
- $dut.jtag.reset
3
- $dut.jtag.idle
4
- ss "reading default ID"
5
- $dut.reg(:testreg).bits(31..0).store
6
- default_id = tester.capture {$dut.jtag.read_dr $dut.reg(:testreg), size: 32 }
7
- default_id_str = default_id[0].to_s(2)
8
- default_id_str.reverse!
9
- default_id = default_id_str.to_i(2)
10
- puts '**************************************************'
11
- puts 'Captured default ID through JTAG: 0x' + default_id.to_s(16)
12
- puts '**************************************************'
13
- $dut.jtag.write_ir 0, size: 4
14
- ss "reading JTAG ID"
15
- $dut.reg(:testreg).bits(31..0).store
16
- jtag_id = tester.capture {$dut.jtag.read_dr $dut.reg(:testreg), size: 32 }
17
- jtag_id_str = jtag_id[0].to_s(2)
18
- jtag_id_str.reverse!
19
- jtag_id = jtag_id_str.to_i(2)
20
- puts '**************************************************'
21
- puts 'Captured JTAG ID: 0x' + jtag_id.to_s(16)
22
- puts '**************************************************'
1
+ Pattern.create(options={:name => "JTAG_CaptureID"})do
2
+ $dut.jtag.reset
3
+ $dut.jtag.idle
4
+ ss "reading default ID"
5
+ $dut.reg(:testreg).bits(31..0).store
6
+ default_id = tester.capture {$dut.jtag.read_dr $dut.reg(:testreg), size: 32 }
7
+ default_id_str = default_id[0].to_s(2)
8
+ default_id_str.reverse!
9
+ default_id = default_id_str.to_i(2)
10
+ puts '**************************************************'
11
+ puts 'Captured default ID through JTAG: 0x' + default_id.to_s(16)
12
+ puts '**************************************************'
13
+ $dut.jtag.write_ir 0, size: 4
14
+ ss "reading JTAG ID"
15
+ $dut.reg(:testreg).bits(31..0).store
16
+ jtag_id = tester.capture {$dut.jtag.read_dr $dut.reg(:testreg), size: 32 }
17
+ jtag_id_str = jtag_id[0].to_s(2)
18
+ jtag_id_str.reverse!
19
+ jtag_id = jtag_id_str.to_i(2)
20
+ puts '**************************************************'
21
+ puts 'Captured JTAG ID: 0x' + jtag_id.to_s(16)
22
+ puts '**************************************************'
23
23
  end
@@ -1,19 +1,19 @@
1
- Pattern.create(options={:name => "transaction_test"})do
2
- $dut.jtag.reset
3
- $dut.jtag.idle
4
- ss "reading Halo debugger ID - setting correct compare value"
5
- result = tester.transaction do
6
- $dut.reg(:testreg).read(0x5ba00477)
7
- $dut.jtag.read_dr $dut.reg(:testreg), size: 32
8
- end
9
- result_comment = "transaction result: #{result}"
10
- ss result_comment
11
-
12
- ss "reading Halo debugger ID - setting wrong compare value"
13
- result = tester.transaction do
14
- $dut.reg(:testreg).read(0x5bd00477)
15
- $dut.jtag.read_dr $dut.reg(:testreg), size: 32
16
- end
17
- result_comment = "transaction result: #{result}"
18
- ss result_comment
1
+ Pattern.create(options={:name => "transaction_test"})do
2
+ $dut.jtag.reset
3
+ $dut.jtag.idle
4
+ ss "reading Halo debugger ID - setting correct compare value"
5
+ result = tester.transaction do
6
+ $dut.reg(:testreg).read(0x5ba00477)
7
+ $dut.jtag.read_dr $dut.reg(:testreg), size: 32
8
+ end
9
+ result_comment = "transaction result: #{result}"
10
+ ss result_comment
11
+
12
+ ss "reading Halo debugger ID - setting wrong compare value"
13
+ result = tester.transaction do
14
+ $dut.reg(:testreg).read(0x5bd00477)
15
+ $dut.jtag.read_dr $dut.reg(:testreg), size: 32
16
+ end
17
+ result_comment = "transaction result: #{result}"
18
+ ss result_comment
19
19
  end
@@ -1,451 +1,470 @@
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 is a plug-in for Origen that enables live silicon debug directly from origen source. There are 2 parts to OrigenLink, the plug-in and the server. Setup for each is documented separately. The OrigenLink server is capable of being shared by multiple people working on the same project. It will lock out other users during your debug or pattern execution session.
10
-
11
- # Plug-in
12
-
13
- Instructions for integrating and using the plug-in with your app.
14
-
15
- ## How To Import
16
-
17
- ##### Add the following line to your application's GEMFILE:
18
-
19
- ~~~ruby
20
- gem 'origen_link'
21
- ~~~
22
-
23
-
24
- ##### Add a link environment (./environment/link.rb). See server setup section for more information:
25
-
26
- ~~~ruby
27
- # Note that the field for providing the computer name or IP address is a string
28
- OrigenLink::VectorBased.new('<ServerComputerName -- or IP_Address>', 12777)
29
- ~~~
30
-
31
-
32
- ##### Select link as your environment to run a pattern over the link connection when the origen generate command is run:
33
-
34
- ~~~
35
- origen e environment/link.rb
36
- origen g pattern/my_pattern.rb
37
- ~~~
38
-
39
-
40
- ## How To Configure
41
-
42
- Before OrigenLink can be used the physical pin map and timing must be setup. There are 2 supported ways of doing this. The high-level setup method allows OrigenLink to determine how to configure the server side pin sequencer. The high-level setup method is highly recommended. For cases where the high-level setup is not functioning correctly, legacy apps, or if you just enjoy doing things the hard way, a legacy low-level api is available. Both will be described here.
43
-
44
- ### How To Configure - High-Level Method (Preferred)
45
-
46
- This is the recomended way to setup OrigenLink in your application.
47
-
48
- #### Physical Pin Map
49
-
50
- OrigenLink needs to tell the server application which physical IO pin on the UDOO device (see UDOO-Neo GPIO documentation) corresponds to which DUT pin in your app. The number after 'gpio_' is what OrigenLink needs. This IO number is passed to OrigenLink through pin meta data.
51
-
52
- ~~~ruby
53
- add_pin :tclk, meta: {link_io: 8}
54
- add_pin :tdi, meta: {link_io: 146}
55
- ~~~
56
-
57
- #### Timing
58
-
59
- OrigenLink emulates a tester sequencer through software. The timing it implemtents will not be precise. Setting the drive edge of tdi to 5ns and tclk to 20ns will not result in tclk being driven 15ns after tdi. What will happen, though, is the sequencer will drive tdi first, followed by tclk. It is recommended that you use the built in Origen API for setting timing.
60
-
61
- ~~~ruby
62
- # Configure timing for jtag communication with RL tclk
63
- tester.set_timeset('api_tst', 40)
64
- dut.timeset :api_tst do |t|
65
- t.drive_wave :tclk do |w|
66
- w.drive :data, at: 10
67
- w.drive 0, at: 30
68
- end
69
- t.drive_wave :tdi, :tms, :tdo do |w|
70
- w.drive :data, at: 5
71
- end
72
- t.compare_wave do |w|
73
- w.compare :data, at: 25
74
- end
75
- end
76
- ~~~
77
-
78
- #### Finished
79
-
80
- Start your OrigenLink server (see server setup section), connect your DUT to the server device and off you go.
81
-
82
- ### How To Configure - Low-Level Legacy API (Skip Reading This Section)
83
-
84
- The prefered configuration method is above. These methods for configuring the server application are supported for legacy applications. This method is more prone to producing hard to debug errors during setup of a new app.
85
-
86
- #### Low-Level Physical Pin Map Setup
87
-
88
- Create a comma separated list of pin_name and IO# and pass it to the tester. The .pinmap method will clear all server settings. So, this should be done first. The pin name string provided to the pinmap must exactly match the pin name string provided to the pin timing and pin order methods. Any typo may result strange behavior (pin operation not occuring, timing error messages, and/or server crash). No cause for alarm, just be sure to check for consistent names if you get those problems.
89
-
90
- ~~~ruby
91
- tester.pinmap = 'tclk,119,tms,6,tdi,116,tdo,124'
92
- ~~~
93
-
94
- #### Low-Level Pattern Pin Order Setup
95
-
96
- Pins that don't have an assiciated physical IO will not have their pin data transmitted to the link server. Create a comma separated list of the pins that are linked (only include pins that are in the pinmap) in the order that they appear in the pattern. Using this command is not needed unless you used the low-level pin map setup command AND your dut.pins(:pin_name) doesn't match the pin name that you setup using 'tester.pinmap ='.
97
-
98
- ~~~ruby
99
- pin_pattern_order :tclk, :tms, :tdi, :tdo # This sets the order of the pins in the pattern
100
-
101
- # order given below must match order in pin_pattern_order
102
- # names used below must match names used in tester.pinmap=
103
- # the below example will cause issues because of a typo: 'tck' versus 'tclk' (tester.pinmap = 'tclk,119,)
104
- tester.pinorder = 'tck,tms,tdi,tdo' # This tells the server what order the pins are in the pattern
105
- ~~~
106
-
107
- #### Low-Level Timing Setup
108
-
109
- ~~~ruby
110
- # pinformat=
111
- # This method is used to setup the pin clock format on the debugger device.
112
- # The supported formats are rl and rh
113
- #
114
- # example:
115
- # tester.pinformat = 'func_25mhz,tclk,rl'
116
-
117
- # pintiming=
118
- # This method is used to setup the pin timing on the debugger device.
119
- # Timing is relative to the rise and fall of a clock
120
- #
121
- # timing value: 0 1 2
122
- # clock waveform: ___/***\___
123
- #
124
- # example:
125
- # tester.pintiming = 'func_25mhz,tms,0,tdi,0,tdo,1'
126
-
127
- ~~~
128
-
129
- ### Debugging Your App
130
-
131
- What follows are some pointers for using OrigenLink to debug your app (or pattern). Run the origen pattern generation command with debug enabled and set a break point in your code to interactively debug.
132
-
133
- ~~~
134
- origen g pattern/my_pattern.rb -d
135
- ~~~
136
-
137
- ~~~ruby
138
- # inside pattern/my_pattern.rb
139
-
140
- dut.reg(:MyReg).write!(my_value)
141
-
142
- # stop after updating this register to observe device state
143
- debugger # generation of the pattern will pause here
144
- ~~~
145
-
146
- #### Debugging Pin Map
147
-
148
- There are pin methods available to aid debug of an OrigenLink setup.
149
-
150
- ~~~
151
- # Cause a pin to continuously toggle every 2 seconds
152
- (debugger prompt): dut.pin(:tdi).hello
153
-
154
- # Stop the pin from toggling
155
- (debugger prompt): dut.pin(:tdi).goodbye
156
- ~~~
157
-
158
- #### Staying Synchronized
159
-
160
- For efficiency vectors that are generated by your app are compressed and stored until the pattern generation is completed. This means that when execution reaches a 'debugger' statement the previously generated vectors may not have been sent to the server yet. There are a handful of ways to make this happen.
161
-
162
- ##### Use the tester.synchronize command from the debugger interface:
163
-
164
- ~~~
165
- # one time synchronize
166
- (debugger prompt): tester.synchronize
167
-
168
- # tell debugger to evaluate the synchronize command every time it gets control
169
- # will cause continuous synchronization
170
- (debugger prompt): disp tester.synchronize
171
- ~~~
172
-
173
- ##### Use tester.transaction
174
-
175
- It makes the most sense to have this in your app's reg read/write methods). Before the transaction method executes the code block provided it will perform a synchronization. Then, the code in the block is executed (which generates new vectors) and a second synchronization is performed. The transaction method returns a boolean indicating whether the vectors generated by the code block passed or failed.
176
-
177
- ~~~ruby
178
- result = tester.transaction { dut.jtag.shift_xx (yy) }
179
- if tester.link?
180
- # result = true if the code in the provided block passed
181
- end
182
- ~~~
183
-
184
- #### Capturing DUT Information
185
-
186
- There are a few methods for observing the actual state of the DUT.
187
-
188
- ##### Capture using tester.capture
189
-
190
- ~~~ruby
191
- # example of capturing and programatically using information read from the DUT
192
- ss "reading default ID"
193
- dut.reg(:testreg).bits(31..0).store
194
- default_id = tester.capture {dut.jtag.read_dr dut.reg(:testreg), size: 32 }
195
- default_id_str = default_id[0].to_s(2)
196
- default_id_str.reverse!
197
- default_id = default_id_str.to_i(2)
198
- puts '**************************************************'
199
- puts 'Captured default ID through JTAG: 0x' + default_id.to_s(16)
200
- puts '**************************************************'
201
- ~~~
202
-
203
- ##### Capture using mem api
204
-
205
- This command will read the contents of memory from the DUT and display it.
206
-
207
- ~~~
208
- # example of mem api use
209
- (debugger prompt): dut.mem(0x2000_0000).sync(3)
210
- 20000000: DEADBEEF
211
- 20000004: 200000D4
212
- 20000008: 1C000898
213
-
214
- (debugger prompt): dut.mem(0x2000_0000).write!(0x1234567)
215
- (debugger prompt): dut.mem(0x2000_0000).sync(3)
216
- 20000000: 01234567
217
- 20000004: 200000D4
218
- 20000008: 1C000898
219
- ~~~
220
-
221
- ##### reg.sync!
222
-
223
- This command will read the contents of the register from the DUT and display it by bit field.
224
-
225
- ~~~
226
- (debugger prompt): dut.reg(:My_Reg).sync!
227
-
228
- 0x3B4 - :My_Reg
229
- ===============================================================================================================
230
- | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 |
231
- | unused[16:9] |
232
- | 0x0 |
233
- ---------------------------------------------------------------------------------------------------------------
234
- | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
235
- | unused[8:1] |
236
- | 0x0 |
237
- ---------------------------------------------------------------------------------------------------------------
238
- | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 |
239
- | unused[0:0] | result[14:8] |
240
- | 0x0 | 0x1C |
241
- ---------------------------------------------------------------------------------------------------------------
242
- | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
243
- | result[7:0] |
244
- | 0x98 |
245
- ---------------------------------------------------------------------------------------------------------------
246
- ~~~
247
-
248
- ##### When A Shared Server Session Isn't Properly Ended
249
-
250
- The server is able to handle multiple users. Once a user connects to the server, it will only allow access from that same IP address and user name until the session has ended. The session end command is transmitted when pattern generation is completed. If a user fails to properly end their session (happens when you exit debug mode by typing 'q' instead of 'c'), the server application will continue to lock out access until the time out has expired (20 minutes). Before terminating a running session, check with the user who started the session to make sure they aren't in the middle of debug (the user id and IP address will be displayed when you try to connect).
251
-
252
- ~~~
253
- ...origen/work 224$ origen g pattern/sar_debug.rb
254
- [ERROR] 0.011[0.011] || Busy: server is in use by joshua from IP address 10.84.152.212
255
- retry in 1 second
256
- [ERROR] 1.039[1.028] || Busy: server is in use by joshua from IP address 10.84.152.212
257
- retry in 1 second
258
- [ERROR] 2.203[1.164] || Busy: server is in use by joshua from IP address 10.84.152.212
259
- retry in 1 second
260
- ~~~
261
-
262
- If the previous session needs to be manually terminated, this is how you do it (this should be a rare exception to the rule - it's bad manners to forcefully kill another user's session):
263
-
264
- ~~~ruby
265
- require 'socket'
266
- require 'etc'
267
-
268
- user_name = Etc.getlogin
269
-
270
- TCPSocket.open('udooneo-computer-name', 12777) do |link|
271
- link.puts("#{user_name}\nsession_kill\n\n")
272
- while received = link.gets
273
- puts received
274
- end
275
- end
276
- puts "unlocked the server"
277
- ~~~
278
-
279
- ------------------------------------------------------------------------------------------------------
280
-
281
- # Server
282
-
283
- This section describes how to setup a new IOT device to serve the OrigenLink pin sequencer.
284
-
285
- ## Setting Up a New UDOO device
286
-
287
- Here are the steps to take to setup a new UDOO-Neo to run the OrigenLink server application. These instructions are not intended to be exhaustive, but should be good enough to get you up and running.
288
-
289
- ##### Change the name of the computer to something unique (like udooneo-myname).
290
-
291
- This name is the string that you will enter in your environment ruby file for your app. Your computer running origen g pattern/my_pattern.rb and the UDOO should be attached to the same network (either through USB or ethernet)
292
-
293
- ~~~
294
- prompt$> sudo nano /etc/hostname
295
- ~~~
296
-
297
- ~~~ruby
298
- # Note that the field for providing the computer name or IP address is a string
299
- OrigenLink::VectorBased.new('<ServerComputerName -- or IP_Address>', 12777)
300
- ~~~
301
-
302
- ##### Disable the M4 core (allows access to all IO's from unix)
303
-
304
- ~~~
305
- menu -> preferences -> Udoo web configuration -> Advanced settings
306
- ~~~
307
-
308
- ##### Install ruby. This is a decision point. If you want to install the OrigenLink gem, the steps are a bit more complicated.
309
-
310
- ** Option 1 (I want the gem): You need to install ruby 2.2.
311
-
312
- ~~~
313
- prompt$> sudo apt-get install ruby22
314
- ~~~
315
-
316
- ** Option 2 (I'm fine using git to pull down the server code)
317
-
318
- ~~~
319
- # of course you're still welcomed to install a newer ruby version
320
- # the server will run just fine
321
- prompt$> sudo apt-get install ruby
322
- ~~~
323
-
324
- ##### Install the OrigenLink server.
325
-
326
- ** Option 1 (if you installed ruby22 you can do this). Install origen and origen_link gems.
327
-
328
- ~~~
329
- # follow the instructions for installing origen at origen-sdk.org
330
- prompt$> sudo gem install origen
331
- prompt$> sudo gem install origen_link
332
- ~~~
333
-
334
- ** Option 2 (This is what I do)
335
-
336
- ~~~
337
- prompt$> git clone https://github.com/Origen-SDK/OrigenLink.git
338
-
339
- # if you get SSL certificate errors do this and retry the clone command
340
- prompt$> git config --global http.sslverify false
341
- ~~~
342
-
343
- ## Starting the Server
344
-
345
- If you installed Ruby 2.x and Origen, run this command to start the server:
346
-
347
- ~~~
348
- <command_prompt>$ start_link_server
349
- ~~~
350
-
351
- If you chose to clone the OrigenLink project from github, navigate to the OrigenLink directory and type this command:
352
-
353
- ~~~
354
- <command_prompt>$ bin/start_link_server
355
- ~~~
356
-
357
- The server is now running
358
-
359
- To have the server started automatically when the UDOO boots add the following line to the end of ~/.profile (note replace the path with your path):
360
-
361
- ~~~
362
- lxterminal -e "/home/udooer/RubyCode/OrigenLink/bin/start_link_server"
363
- ~~~
364
-
365
- ## Physical Interconnect
366
-
367
- Keep the following things in mind when connecting the IO's of your UDOO Neo to a DUT
368
-
369
- * Ground is important. As a rule of thumb, connect at least 2 ground wires between the UDOO and your DUT
370
-
371
- * Pay attention to pin levels. The UDOO IO's are 3.3v. If your device is not also 3.3v, the most reliable and convenient way to connect the IO's is by using a bi-directional (auto-direction sensing) level shifter. This one works well and is easy to find (available on Amazon Prime at the writing of this document): TXB0108
372
-
373
- * An alternative method for shifting a voltage down is to use a diode and pullup resistor. The anode gets connected to the higher voltage device. The cathode is connected to the lower voltage device. A 10K pullup resistor is connected from the cathode to the supply voltage for the lower voltage device. --- A word of advice: This method is quick and easy. But, you get a slow rise time which makes it a terrible way of shifting the level of a clock signal (like TCLK for JTAG or SPICLK for SPI).
374
-
375
- ---
376
-
377
- # How It Works
378
-
379
- This section will explain the in's and out's of how the plug-in and server applications work and how they communicate. This section is intended to aid developers who want to add or modify features. More in depth information can be found in the api documentation.
380
-
381
- ## Server Side App
382
-
383
- What follows is the structure of the server side app.
384
-
385
- ### Pin IO
386
-
387
- Pin IO is accomplished by using the file objects exported by linux at \sys\class\gpio
388
-
389
- ~~~
390
- <command_prompt>$ cd /sys/class/gpio
391
-
392
- # export the file objects for a pin
393
- <command_prompt>$ echo 20 > export
394
-
395
- # read the state of gpio20
396
- <command_prompt>$ cd gpio20
397
- <command_prompt>$ cat value
398
-
399
- # drive gpio20 to logic 1
400
- <command_prompt>$ echo out > direction
401
- <command_prompt>$ echo 1 > value
402
-
403
- # change gpio20 from output to input
404
- <command_prompt>$ echo in > direction
405
- ~~~
406
-
407
- ### Pin Class
408
-
409
- The server pin class implements IO interactions for a pin. When the pin assign command creates a pin object, it exports the associated IO number and opens IO objects for the direction and value of that pin. The IO objects are kept open until the pin is destroyed. For more information see the api documentation.
410
-
411
- ### Pin Sequencer
412
-
413
- The pin sequencer is the class that does all of the heavy lifting for the server side app. It implements all of the command messages that begin with "pin_". See the api documentation (Server::Sequencer) for more information. Timing is perhaps the most complicated construct to understand:
414
-
415
- ~~~ruby
416
- # tset is a number that corresponds to a timeset name from origen ex: 1 corresponds to 'tp0'
417
- # @cycletiming[tset] is a hash
418
- # each timeset contains these keys:
419
- # 'events' - [array of timestamps for timing events]
420
- # 'drive_event_data' - hash, the keys of the hash correspond to elements of 'events'
421
- # - each value in the hash is an array
422
- # - each element in the array is one of 3 values: 'data', '0', or '1'
423
- # 'drive_event_pins' - hash, the keys of the hash correspond to elements of 'events'
424
- # - each value in the hash is an array
425
- # - each element in the array is an array of pin objects
426
- # - the drive event data will be performed for each pin object
427
- # 'compare_event_data' - similar to drive_event_data, the only valid event data is 'data'
428
- # 'compare_event_pins' - similar to drive_event_pins
429
-
430
- @cycletiming[tset] = {
431
- ['events'] = [0, 5, 10, 35]
432
- ['drive_event_data'] = {
433
- 0: ['data']
434
- 10: ['data','0']
435
- 35: ['0']
436
- }
437
- ['drive_event_pins'] = {
438
- 0: [[pin_obj1, pin_obj2]]
439
- 10: [[pin1,pin2], [pin3]]
440
- 35: [[pin4]]
441
- }
442
- }
443
- ~~~
444
-
445
- The main message supported by the sequencer is 'pin_cycle'. As the name implies, this message implements 1 or more cycles of vector data. It will return the response of the dut to the plug-in side app along with pass/fail information.
446
-
447
- ### Server
448
-
449
- The server serves a TCP socket at 12777. No fancy gems are used for several reasons, the main one being simplicity. Ruby has a built in socket library that is extremely simple to use. Multiple messages from the plug-in side app can be received with a single connection. "\n" indicates the end of a message. "\n\n" indicates that the packet of messages has ended. Why TCP and not UDP? I know the web says that UDP socket communication is faster. But, my testing indicated otherwise. Plus, TCP is more reliable.
450
-
451
- % end
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 is a plug-in for Origen that enables live silicon debug directly from origen source. There are 2 parts to OrigenLink, the plug-in and the server. Setup for each is documented separately. The OrigenLink server is capable of being shared by multiple people working on the same project. It will lock out other users during your debug or pattern execution session.
10
+
11
+ # Plug-in
12
+
13
+ Instructions for integrating and using the plug-in with your app.
14
+
15
+ ## How To Import
16
+
17
+ ##### Add the following line to your application's GEMFILE:
18
+
19
+ ~~~ruby
20
+ gem 'origen_link'
21
+ ~~~
22
+
23
+
24
+ ##### Add a link environment (./environment/link.rb). See server setup section for more information:
25
+
26
+ ~~~ruby
27
+ # Note that the field for providing the computer name or IP address is a string
28
+ OrigenLink::VectorBased.new('<ServerComputerName -- or IP_Address>', 12777)
29
+ ~~~
30
+
31
+
32
+ ##### Select link as your environment to run a pattern over the link connection when the origen generate command is run:
33
+
34
+ ~~~
35
+ origen e environment/link.rb
36
+ origen g pattern/my_pattern.rb
37
+ ~~~
38
+
39
+
40
+ ## How To Configure
41
+
42
+ Before OrigenLink can be used the physical pin map and timing must be setup. There are 2 supported ways of doing this. The high-level setup method allows OrigenLink to determine how to configure the server side pin sequencer. The high-level setup method is highly recommended. For cases where the high-level setup is not functioning correctly, legacy apps, or if you just enjoy doing things the hard way, a legacy low-level api is available. Both will be described here.
43
+
44
+ ### How To Configure - High-Level Method (Preferred)
45
+
46
+ This is the recomended way to setup OrigenLink in your application.
47
+
48
+ #### Physical Pin Map
49
+
50
+ OrigenLink needs to tell the server application which physical IO pin on the UDOO device (see UDOO-Neo GPIO documentation) corresponds to which DUT pin in your app. The number after 'gpio_' is what OrigenLink needs. This IO number is passed to OrigenLink through pin meta data.
51
+
52
+ ~~~ruby
53
+ add_pin :tclk, meta: {link_io: 8}
54
+ add_pin :tdi, meta: {link_io: 146}
55
+ ~~~
56
+
57
+ #### Timing
58
+
59
+ OrigenLink emulates a tester sequencer through software. The timing it implemtents will not be precise. Setting the drive edge of tdi to 5ns and tclk to 20ns will not result in tclk being driven 15ns after tdi. What will happen, though, is the sequencer will drive tdi first, followed by tclk. It is recommended that you use the built in Origen API for setting timing.
60
+
61
+ ~~~ruby
62
+ # Configure timing for jtag communication with RL tclk
63
+ tester.set_timeset('api_tst', 40)
64
+ dut.timeset :api_tst do |t|
65
+ t.drive_wave :tclk do |w|
66
+ w.drive :data, at: 10
67
+ w.drive 0, at: 30
68
+ end
69
+ t.drive_wave :tdi, :tms, :tdo do |w|
70
+ w.drive :data, at: 5
71
+ end
72
+ t.compare_wave do |w|
73
+ w.compare :data, at: 25
74
+ end
75
+ end
76
+ ~~~
77
+
78
+ #### Finished
79
+
80
+ Start your OrigenLink server (see server setup section), connect your DUT to the server device and off you go.
81
+
82
+ ### How To Configure - Low-Level Legacy API (Skip Reading This Section)
83
+
84
+ The prefered configuration method is above. These methods for configuring the server application are supported for legacy applications. This method is more prone to producing hard to debug errors during setup of a new app.
85
+
86
+ #### Low-Level Physical Pin Map Setup
87
+
88
+ Create a comma separated list of pin_name and IO# and pass it to the tester. The .pinmap method will clear all server settings. So, this should be done first. The pin name string provided to the pinmap must exactly match the pin name string provided to the pin timing and pin order methods. Any typo may result strange behavior (pin operation not occuring, timing error messages, and/or server crash). No cause for alarm, just be sure to check for consistent names if you get those problems.
89
+
90
+ ~~~ruby
91
+ tester.pinmap = 'tclk,119,tms,6,tdi,116,tdo,124'
92
+ ~~~
93
+
94
+ #### Low-Level Pattern Pin Order Setup
95
+
96
+ Pins that don't have an assiciated physical IO will not have their pin data transmitted to the link server. Create a comma separated list of the pins that are linked (only include pins that are in the pinmap) in the order that they appear in the pattern. Using this command is not needed unless you used the low-level pin map setup command AND your dut.pins(:pin_name) doesn't match the pin name that you setup using 'tester.pinmap ='.
97
+
98
+ ~~~ruby
99
+ pin_pattern_order :tclk, :tms, :tdi, :tdo # This sets the order of the pins in the pattern
100
+
101
+ # order given below must match order in pin_pattern_order
102
+ # names used below must match names used in tester.pinmap=
103
+ # the below example will cause issues because of a typo: 'tck' versus 'tclk' (tester.pinmap = 'tclk,119,)
104
+ tester.pinorder = 'tck,tms,tdi,tdo' # This tells the server what order the pins are in the pattern
105
+ ~~~
106
+
107
+ #### Low-Level Timing Setup
108
+
109
+ ~~~ruby
110
+ # pinformat=
111
+ # This method is used to setup the pin clock format on the debugger device.
112
+ # The supported formats are rl and rh
113
+ #
114
+ # example:
115
+ # tester.pinformat = 'func_25mhz,tclk,rl'
116
+
117
+ # pintiming=
118
+ # This method is used to setup the pin timing on the debugger device.
119
+ # Timing is relative to the rise and fall of a clock
120
+ #
121
+ # timing value: 0 1 2
122
+ # clock waveform: ___/***\___
123
+ #
124
+ # example:
125
+ # tester.pintiming = 'func_25mhz,tms,0,tdi,0,tdo,1'
126
+
127
+ ~~~
128
+
129
+ ### Debugging Your App
130
+
131
+ What follows are some pointers for using OrigenLink to debug your app (or pattern). Run the origen pattern generation command with debug enabled and set a break point in your code to interactively debug.
132
+
133
+ ~~~
134
+ origen g pattern/my_pattern.rb -d
135
+ ~~~
136
+
137
+ ~~~ruby
138
+ # inside pattern/my_pattern.rb
139
+
140
+ dut.reg(:MyReg).write!(my_value)
141
+
142
+ # stop after updating this register to observe device state
143
+ debugger # generation of the pattern will pause here
144
+ ~~~
145
+
146
+ #### Debugging Pin Map
147
+
148
+ There are pin methods available to aid debug of an OrigenLink setup.
149
+
150
+ ~~~
151
+ # Cause a pin to continuously toggle every 2 seconds
152
+ (debugger prompt): dut.pin(:tdi).hello
153
+
154
+ # Stop the pin from toggling
155
+ (debugger prompt): dut.pin(:tdi).goodbye
156
+ ~~~
157
+
158
+ #### Staying Synchronized
159
+
160
+ For efficiency vectors that are generated by your app are compressed and stored until the pattern generation is completed. This means that when execution reaches a 'debugger' statement the previously generated vectors may not have been sent to the server yet. There are a handful of ways to make this happen.
161
+
162
+ ##### Use the tester.synchronize command from the debugger interface:
163
+
164
+ ~~~
165
+ # one time synchronize
166
+ (debugger prompt): tester.synchronize
167
+
168
+ # tell debugger to evaluate the synchronize command every time it gets control
169
+ # will cause continuous synchronization
170
+ (debugger prompt): disp tester.synchronize
171
+ ~~~
172
+
173
+ ##### Use tester.transaction
174
+
175
+ It makes the most sense to have this in your app's reg read/write methods). Before the transaction method executes the code block provided it will perform a synchronization. Then, the code in the block is executed (which generates new vectors) and a second synchronization is performed. The transaction method returns a boolean indicating whether the vectors generated by the code block passed or failed.
176
+
177
+ ~~~ruby
178
+ result = tester.transaction { dut.jtag.shift_xx (yy) }
179
+ if tester.link?
180
+ # result = true if the code in the provided block passed
181
+ end
182
+ ~~~
183
+
184
+ #### Capturing DUT Information
185
+
186
+ There are a few methods for observing the actual state of the DUT.
187
+
188
+ ##### Capture using tester.capture
189
+
190
+ ~~~ruby
191
+ # example of capturing and programatically using information read from the DUT
192
+ ss "reading default ID"
193
+ dut.reg(:testreg).bits(31..0).store
194
+ default_id = tester.capture {dut.jtag.read_dr dut.reg(:testreg), size: 32 }
195
+ default_id_str = default_id[0].to_s(2)
196
+ default_id_str.reverse!
197
+ default_id = default_id_str.to_i(2)
198
+ puts '**************************************************'
199
+ puts 'Captured default ID through JTAG: 0x' + default_id.to_s(16)
200
+ puts '**************************************************'
201
+ ~~~
202
+
203
+ ##### Capture using mem api
204
+
205
+ This command will read the contents of memory from the DUT and display it.
206
+
207
+ ~~~
208
+ # example of mem api use
209
+ (debugger prompt): dut.mem(0x2000_0000).sync(3)
210
+ 20000000: DEADBEEF
211
+ 20000004: 200000D4
212
+ 20000008: 1C000898
213
+
214
+ (debugger prompt): dut.mem(0x2000_0000).write!(0x1234567)
215
+ (debugger prompt): dut.mem(0x2000_0000).sync(3)
216
+ 20000000: 01234567
217
+ 20000004: 200000D4
218
+ 20000008: 1C000898
219
+ ~~~
220
+
221
+ ##### reg.sync!
222
+
223
+ This command will read the contents of the register from the DUT and display it by bit field.
224
+
225
+ ~~~
226
+ (debugger prompt): dut.reg(:My_Reg).sync!
227
+
228
+ 0x3B4 - :My_Reg
229
+ ===============================================================================================================
230
+ | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 |
231
+ | unused[16:9] |
232
+ | 0x0 |
233
+ ---------------------------------------------------------------------------------------------------------------
234
+ | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
235
+ | unused[8:1] |
236
+ | 0x0 |
237
+ ---------------------------------------------------------------------------------------------------------------
238
+ | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 |
239
+ | unused[0:0] | result[14:8] |
240
+ | 0x0 | 0x1C |
241
+ ---------------------------------------------------------------------------------------------------------------
242
+ | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
243
+ | result[7:0] |
244
+ | 0x98 |
245
+ ---------------------------------------------------------------------------------------------------------------
246
+ ~~~
247
+
248
+ ##### When A Shared Server Session Isn't Properly Ended
249
+
250
+ The server is able to handle multiple users. Once a user connects to the server, it will only allow access from that same IP address and user name until the session has ended. The session end command is transmitted when pattern generation is completed. If a user fails to properly end their session (happens when you exit debug mode by typing 'q' instead of 'c'), the server application will continue to lock out access until the time out has expired (20 minutes). Before terminating a running session, check with the user who started the session to make sure they aren't in the middle of debug (the user id and IP address will be displayed when you try to connect).
251
+
252
+ ~~~
253
+ ...origen/work 224$ origen g pattern/sar_debug.rb
254
+ [ERROR] 0.011[0.011] || Busy: server is in use by joshua from IP address 10.84.152.212
255
+ retry in 1 second
256
+ [ERROR] 1.039[1.028] || Busy: server is in use by joshua from IP address 10.84.152.212
257
+ retry in 1 second
258
+ [ERROR] 2.203[1.164] || Busy: server is in use by joshua from IP address 10.84.152.212
259
+ retry in 1 second
260
+ ~~~
261
+
262
+ If the previous session needs to be manually terminated, this is how you do it (this should be a rare exception to the rule - it's bad manners to forcefully kill another user's session):
263
+
264
+ ~~~ruby
265
+ require 'socket'
266
+ require 'etc'
267
+
268
+ user_name = Etc.getlogin
269
+
270
+ TCPSocket.open('udooneo-computer-name', 12777) do |link|
271
+ link.puts("#{user_name}\nsession_kill\n\n")
272
+ while received = link.gets
273
+ puts received
274
+ end
275
+ end
276
+ puts "unlocked the server"
277
+ ~~~
278
+
279
+ ---
280
+
281
+ # Server
282
+
283
+ This section describes how to setup a new IOT device to serve the OrigenLink pin sequencer.
284
+
285
+ ## UDOO NEO Shopping list
286
+
287
+ These items will be needed:
288
+
289
+ * [UDOO NEO](www.udoo.org) - The UDOO NEO Full is recommended (WiFi & Ethernet built in)
290
+ * 8GB micro SD card
291
+ * Micro USB to USB cable
292
+
293
+ These items are optional, but likely helpful:
294
+
295
+ * Bread board (solderless prototyping board)
296
+ * Prototyping wires (male to male, male to female, female to female)
297
+ * 300 ohm resistors (for current limiting)
298
+ * 10K ohm resistors (for pull up)
299
+ * Diodes (for constructing cheap 1 way level shifter)
300
+ * Level shifters (required if shifting down a clock signal - TXS0108E is easy to use)
301
+ * Power adapter (if you plan to connect through a network instead of USB) - old cell phone micro USB charger or 12v 3amp DC supply
302
+ * 3D printed case. The bottom half of [this](https://www.thingiverse.com/thing:1191832) design has worked well.
303
+
304
+ ## Setting Up a New UDOO device
305
+
306
+ Here are the steps to take to setup a new UDOO-Neo to run the OrigenLink server application. These instructions are not intended to be exhaustive, but should be good enough to get you up and running.
307
+
308
+ ##### Change the name of the computer to something unique (like udooneo-myname).
309
+
310
+ This name is the string that you will enter in your environment ruby file for your app. Your computer running origen g pattern/my_pattern.rb and the UDOO should be attached to the same network (either through USB or ethernet)
311
+
312
+ ~~~
313
+ prompt$> sudo nano /etc/hostname
314
+ ~~~
315
+
316
+ ~~~ruby
317
+ # Note that the field for providing the computer name or IP address is a string
318
+ OrigenLink::VectorBased.new('<ServerComputerName -- or IP_Address>', 12777)
319
+ ~~~
320
+
321
+ ##### Disable the M4 core (allows access to all IO's from unix)
322
+
323
+ ~~~
324
+ menu -> preferences -> Udoo web configuration -> Advanced settings
325
+ ~~~
326
+
327
+ ##### Install ruby. This is a decision point. If you want to install the OrigenLink gem, the steps are a bit more complicated.
328
+
329
+ ** Option 1 (I want the gem): You need to install ruby 2.2.
330
+
331
+ ~~~
332
+ prompt$> sudo apt-get install ruby22
333
+ ~~~
334
+
335
+ ** Option 2 (I'm fine using git to pull down the server code)
336
+
337
+ ~~~
338
+ # of course you're still welcomed to install a newer ruby version
339
+ # the server will run just fine
340
+ prompt$> sudo apt-get install ruby
341
+ ~~~
342
+
343
+ ##### Install the OrigenLink server.
344
+
345
+ ** Option 1 (if you installed ruby22 you can do this). Install origen and origen_link gems.
346
+
347
+ ~~~
348
+ # follow the instructions for installing origen at origen-sdk.org
349
+ prompt$> sudo gem install origen
350
+ prompt$> sudo gem install origen_link
351
+ ~~~
352
+
353
+ ** Option 2 (This is what I do)
354
+
355
+ ~~~
356
+ prompt$> git clone https://github.com/Origen-SDK/OrigenLink.git
357
+
358
+ # if you get SSL certificate errors do this and retry the clone command
359
+ prompt$> git config --global http.sslverify false
360
+ ~~~
361
+
362
+ ## Starting the Server
363
+
364
+ If you installed Ruby 2.x and Origen, run this command to start the server:
365
+
366
+ ~~~
367
+ <command_prompt>$ start_link_server
368
+ ~~~
369
+
370
+ If you chose to clone the OrigenLink project from github, navigate to the OrigenLink directory and type this command:
371
+
372
+ ~~~
373
+ <command_prompt>$ bin/start_link_server
374
+ ~~~
375
+
376
+ The server is now running
377
+
378
+ To have the server started automatically when the UDOO boots add the following line to the end of ~/.profile (note replace the path with your path):
379
+
380
+ ~~~
381
+ lxterminal -e "/home/udooer/RubyCode/OrigenLink/bin/start_link_server"
382
+ ~~~
383
+
384
+ ## Physical Interconnect
385
+
386
+ Keep the following things in mind when connecting the IO's of your UDOO Neo to a DUT
387
+
388
+ * Ground is important. As a rule of thumb, connect at least 2 ground wires between the UDOO and your DUT
389
+
390
+ * Pay attention to pin levels. The UDOO IO's are 3.3v. If your device is not also 3.3v, the most reliable and convenient way to connect the IO's is by using a bi-directional (auto-direction sensing) level shifter. This one works well and is easy to find (available on Amazon Prime at the writing of this document): TXB0108
391
+
392
+ * An alternative method for shifting a voltage down is to use a diode and pullup resistor. The anode gets connected to the higher voltage device. The cathode is connected to the lower voltage device. A 10K pullup resistor is connected from the cathode to the supply voltage for the lower voltage device. --- A word of advice: This method is quick and easy. But, you get a slow rise time which makes it a terrible way of shifting the level of a clock signal (like TCLK for JTAG or SPICLK for SPI).
393
+
394
+ ---
395
+
396
+ # How It Works
397
+
398
+ This section will explain the in's and out's of how the plug-in and server applications work and how they communicate. This section is intended to aid developers who want to add or modify features. More in depth information can be found in the api documentation.
399
+
400
+ ## Server Side App
401
+
402
+ What follows is the structure of the server side app.
403
+
404
+ ### Pin IO
405
+
406
+ Pin IO is accomplished by using the file objects exported by linux at \sys\class\gpio
407
+
408
+ ~~~
409
+ <command_prompt>$ cd /sys/class/gpio
410
+
411
+ # export the file objects for a pin
412
+ <command_prompt>$ echo 20 > export
413
+
414
+ # read the state of gpio20
415
+ <command_prompt>$ cd gpio20
416
+ <command_prompt>$ cat value
417
+
418
+ # drive gpio20 to logic 1
419
+ <command_prompt>$ echo out > direction
420
+ <command_prompt>$ echo 1 > value
421
+
422
+ # change gpio20 from output to input
423
+ <command_prompt>$ echo in > direction
424
+ ~~~
425
+
426
+ ### Pin Class
427
+
428
+ The server pin class implements IO interactions for a pin. When the pin assign command creates a pin object, it exports the associated IO number and opens IO objects for the direction and value of that pin. The IO objects are kept open until the pin is destroyed. For more information see the api documentation.
429
+
430
+ ### Pin Sequencer
431
+
432
+ The pin sequencer is the class that does all of the heavy lifting for the server side app. It implements all of the command messages that begin with "pin_". See the api documentation (Server::Sequencer) for more information. Timing is perhaps the most complicated construct to understand:
433
+
434
+ ~~~ruby
435
+ # tset is a number that corresponds to a timeset name from origen ex: 1 corresponds to 'tp0'
436
+ # @cycletiming[tset] is a hash
437
+ # each timeset contains these keys:
438
+ # 'events' - [array of timestamps for timing events]
439
+ # 'drive_event_data' - hash, the keys of the hash correspond to elements of 'events'
440
+ # - each value in the hash is an array
441
+ # - each element in the array is one of 3 values: 'data', '0', or '1'
442
+ # 'drive_event_pins' - hash, the keys of the hash correspond to elements of 'events'
443
+ # - each value in the hash is an array
444
+ # - each element in the array is an array of pin objects
445
+ # - the drive event data will be performed for each pin object
446
+ # 'compare_event_data' - similar to drive_event_data, the only valid event data is 'data'
447
+ # 'compare_event_pins' - similar to drive_event_pins
448
+
449
+ @cycletiming[tset] = {
450
+ ['events'] = [0, 5, 10, 35]
451
+ ['drive_event_data'] = {
452
+ 0: ['data']
453
+ 10: ['data','0']
454
+ 35: ['0']
455
+ }
456
+ ['drive_event_pins'] = {
457
+ 0: [[pin_obj1, pin_obj2]]
458
+ 10: [[pin1,pin2], [pin3]]
459
+ 35: [[pin4]]
460
+ }
461
+ }
462
+ ~~~
463
+
464
+ The main message supported by the sequencer is 'pin_cycle'. As the name implies, this message implements 1 or more cycles of vector data. It will return the response of the dut to the plug-in side app along with pass/fail information.
465
+
466
+ ### Server
467
+
468
+ The server serves a TCP socket at 12777. No fancy gems are used for several reasons, the main one being simplicity. Ruby has a built in socket library that is extremely simple to use. Multiple messages from the plug-in side app can be received with a single connection. "\n" indicates the end of a message. "\n\n" indicates that the packet of messages has ended. Why TCP and not UDP? I know the web says that UDP socket communication is faster. But, my testing indicated otherwise. Plus, TCP is more reliable.
469
+
470
+ % end