JTAG Driver tutorial
The jtag_driver entity provides facilities for generating JTAG test logic input excitations
for rtl simulations.
Since JTAG test logic can be used for various control and test functions, this entity aims to be as general as possible
by providing only the primitive operations required by all JTAG use cases. Concretely, jtag_driver defines
operations for controlling a JTAG state machine and leaves the implementation of more complex control sequences to the
user of this entity. The circuit designer can define further functions that utilize this minimal driver for generating
application specific control sequences for their use case. The benefit of this approach is that multiple different helper
objects can share a reference to a single instance of the jtag_driver, which enbles the control of multiple different
devices over a single JTAG Test Access Port.
Since JTAG implementations can vary, this entity supports:
configurable Instruction Register (IR) width
arbitrary Test Data Register (TDR) widths
The jtag_driver class provides helpers for:
resetting all JTAG test logic through the dedicated
tapRSTinputprimitive functions for moving around the JTAG state machine
shifting values to
the Instruction Register, and
the corresponding Test Data Registers
capturing and shifting out parallel inputs
Example
This example shows how to use the jtag_driver to do primitive operations on the
JTAG state machine as well as how to define a custom helpers for automating JTAG test
operations to control test logic.
When jtag_driver is instantiated, it creates a TheSyDeKick iofile with the name 'jtag_tap'
and adds it to self.iofile_bundle. This iofile contains the simulation input excitation
that will be fed to the JTAG TAP inputs. The helper functions can then use this shared reference
to control the JTAG state machine to accomplish the desired sequence of actions.
To demonstrate how to use the jtag_driver to build a custom simulation controller consider the following design:
JTAG configuration
IR width = 4
Test Data Registers
"0000"– EXTEST"0001"–enable"1111"– BYPASS
EXTEST and BYPASS are standard instructions required by the JTAG specification.
The instruction "0001" is user-defined for controlling user-defined logic.
The parallel output of the TDR selected by IR=0001 is drives an enable signal
that is used to control some logic inside the design.
In order to abstract away the JTAG configuration from the simulation controls. We can define a
jtag_controller helper class for controlling these signals. This lets us reason about the
control in terms of the signal names instead of having to think about them in terms of the associated
JTAG instruction numbers.
from JTAG.driver import jtag_driver
class jtag_controller:
def __init__(self, driver):
assert isinstance(driver, jtag_driver)
self.driver = driver
def enable(self, value):
self.driver.shift_to_chain(icode_str="0001", tdi_str=value)
The jtag_controller stores a local reference to the jtag_driver. The helper functions use this
stored reference to call the driver’s primitive methods for controlling the JTAG state machine to achieve
the desired functionality. Here the helper enable simply shifts in the bit given by its value argument
to a TDR selected by IR=0001. With this definition, we can use the more descriptively named helpers to
control the simulation in the main simulation test bench.
from JTAG.driver import jtag_driver
# instantiate design under test
dut = ...
driver = jtag_driver()
ctrl = jtag_controller(driver=driver)
# control sequence
driver.reset_tap()
driver.reset_to_idle()
ctrl.enable("1")
...
# driver contains the whole JTAG input waveform
dut.IOS.Members['jtag_tap'] = driver.IOS.Members['jtag_tap']
While in this example it is trivial to see that ctrl.enable("1") corresponds to the single action
driver.shift_to_chain(icode_str="0001", tdi_str="1"), in larger desigs it becomes tedious to manually
track which signals correspond to which instructions. By defining helpers based on jtag_driver, we can
reason about the signals in terms of their usage rather than the associated JTAG implementation. Furthermore,
it’s possible to define longer control sequences. For example, one could define a helper for uploading data
into device memory over JTAG. Once these helpers have been written, they can also be reused in different projects
that use similar test logic.