This plugin provides an ATE driver for an IEEE 1149.1 compliant JTAG interface.
It makes no assumptions about the instruction or data register attributes or higher level protocol concerns. For use at DUT model level this plugin would be normally be wrapped in a higher level protocol such as Nexus.
In your Gemfile add:
gem "origen_jtag", ">= 0.22.3"
or if your application is a plugin add this to your .gemspec
spec.add_development_dependency "origen_jtag", ">= 0.22.3"
NOTE: You will also need to include require 'origen_jtag'
somewhere in your environment.
This can be done in config/environment.rb
for example.
This plugin provides a JTAG driver that should be instantiated by the top-level DUT model as shown in this basic integration example:
class MyApp::MyDUT include Origen::TopLevel def initialize(options = {}) # The JTAG driver will use these pins by default if they are defined (or aliases) add_pin :tck add_pin :tdi add_pin :tdo add_pin :tms sub_block :jtag, class_name: 'OrigenJTAG::Driver' end end
Multiple JTAG blocks can be instantiated if the DUT has multiple JTAG ports, and each one can be individually customized as shown in this more complex example:
class MyApp::MyDUT include Origen::TopLevel def initialize # The JTAG driver will use these pins by default if they are defined (or aliases) add_pin :tck add_pin :tdi add_pin :tdo add_pin :tms add_pin :tck2 add_pin :tdi2 add_pin :tdo2 add_pin :tms2 # In this first instance TCK covers 4 tester cycles, # 2 high then 2 low for each effective TCK pulse. # Strobe TDO only when TCK high. Only store TDO on last cycle (3) # Several plugins use dut.jtag, your default port driver should be named jtag for compatibility sub_block :jtag, class_name: 'OrigenJTAG::Driver', tck_format: :rl, tck_multiple: 4, tdo_strobe: :tck_high, tdo_store_cycle: 3 # Create a driver for a 2nd port like this, note different configuration settings can be used sub_block :jtag_port2, class_name: 'OrigenJTAG::Driver', tck_format: :rh, tck_multiple: 2, tdo_strobe: :tck_high, tdo_store_cycle: 1, tck_pin: :tck2, tdi_pin: :tdi2, tdo_pin: :tdo2, tms_pin: :tms2 end end dut.jtag # => jtag driver for the first port (tck, tdi, tdo, tms) dut.jtag_port2 # => jtag driver for the second port (tck2, tdi2, tdo2, tms2)
Here are some of the most common configuration options:
By default, the driver will apply the conventional ‘1’ and ‘0’ drive values on the TCK pin to turn
the clock on and off, however
this can be overridden by supplying the :tck_vals
option as shown in the example below:
# My V93K timing setup uses 'P' to enable a clock pulse instead of '1' tck_vals: { on: 'P', off: 0 }
A legacy integration is also supported, but not recommended for new projects as it may be deprecated in future.
Two APIs are provided, the primary one provides canned methods to read and write to the IR and DR registers.
These accept either an absolute data value or an Origen register/bit collection.
jtag.write_dr 0x1234, :size => 16 # The size option is not required when a register is supplied jtag.write_dr $dut.reg(:clkdiv) # Although it can still be added if the register is not the full data width jtag.write_dr $dut.reg(:clkdiv), :size => 32 # A rich read method is available which supports bit-level read, store and overlay operations $dut.reg(:clkdiv).bits(:div).read(0x55) jtag.read $dut.reg(:clkdiv) # In cases where both shift in (TDI) and shift out data (TDO) are critical, (e.g. compare shift # out data on a write, or shfit in specific data on a read) the shift_in_data and # shift_out_data options can be specified. By default, TDO will be dont care on writes # and TDI will be 0 on reads. jtag.write_dr $dut.reg(:clkdiv), :shift_out_data => 0x4321 jtag.read_dr $udt.reg(:clkdiv), :shift_in_data => 0x5678 # Similar methods exist for the instruction register jtag.write_ir 0x1F, :size => 5 jtag.read_ir 0x1F, :size => 5
A secondary API provides low level control of the TAP Controller state machine.
jtag.pause_dr do jtag.shift_dr do # The shift method accepts the same arguments as the canned read/write methods jtag.shift 0x55, :size => 32 end end
See the OrigenJTAG::Driver
and
OrigenJTAG::TAPController
APIs for more details about the available driver methods.
Any model/controller within a target runtime environment can listen out for JTAG state changes by implementing the following callback handler:
def on_jtag_state_change(new_state) if new_state == :update_dr # Do something every time we enter this state end end
This plugin also allows applications to define how a JTAG cycle should be implemented at the pin-level, providing the flexibility to handle hybrid JTAG protocols. An example would be an ultra-low pincount device where the JTAG signals are multiplexed down a single wire.
To implement a custom protocol, a :cycle_callback
option should be supplied when instantiating the
driver to specify the name of the DUT method that will implement the cycle.
Note that most other configuration options are meaningless in this context (and some non-default
values will raise an error) because the application
is now taking full responsibility for how a JTAG cycle is implemented.
Similarly, there is no requirement for the conventional JTAG pins to be present or specified when this
option is given since the driver is no longer responsible for the vector generation.
The given method should accept two arguments:
:tdi
, :tms
and :tdo
,
pins and a boolean flag called :store
which indicates if TDO should be stored/captured on this cycletester.cycle
The JTAG driver provides a method called apply_action
which accepts a pin object and the pin-specific
actions from the actions hash, e.g.
jtag.apply_action(pin(:my_pin), actions[:tms])
Here is a complete example which would serialize TDI, TMS and TDO on a single pin:
class MyApp::MyDUT def initialize(options = {}) add_pin :tck add_pin :tio sub_block :jtag, class_name: 'OrigenJTAG::Driver', cycle_callback: :jtag_cycle end def jtag_cycle(actions, options = {}) pin(:tck).drive(1) jtag.apply_action(pin(:tio), actions[:tdi]) tester.cycle(options) jtag.apply_action(pin(:tio), actions[:tms]) tester.cycle(options) jtag.apply_action(pin(:tio), actions[:tdo]) tester.store_next_cycle(pin(:tio)) if actions[:store] tester.cycle(options) end end
Clone the repository from Github.
An instance of the OrigenJTAG driver is hooked up to a dummy DUT object for use in the console:
origen i
> $dut.jtag
=> #<OrigenJTAG::Driver:0x0000001ee48e78>
Follow the instructions here if you want to make a 3rd party app workspace use your development copy of the OrigenJTAG plugin: Setting up a Plugin Development Environment
This plugin also contains a test suite, makes sure this passes before committing any changes!
origen examples