JTAG Scans in a JTAG Block

Inside a JTAG block, data to scan through all the currently available JTAG chains is set up and read back with the DR or IR statements, which access the data register and instruction register respectively. The actual scan is performed by using the DRSCAN or IRSCAN statements. Scanning the JTAG chains is typically done in three steps: setting the data up to send, performing the scan and then extracting the data that is returned.

The data from the JTAG chains can either be accessed using device references or by indexing directly into a single combined chain ignoring device and JTAG chain boundaries.

Device access

This is the syntax to set data up in the JTAG chains to be scanned by device:

IR deviceName { WIDTH width } := [data|instruction] {, ...};
DR deviceName { WIDTH width } := data {, ...};

This is the syntax to read the scanned data back from the JTAG chains by device:

IR variable := deviceName {, ...};
DR variable := deviceName {, ...};

The deviceName is a string expression. If it is a constant string, it is validated at compile-time, otherwise if it is non-constant it is validated at run-time. For a multicore device the name of the core to be accessed must also be specified.

The data is any integer expression or, in the case of an instruction register (IR) access, must be the name of a JTAG instruction as defined in the device's BSDL file. If the optional width is given then the register width for that device is modified. In the case of named instructions the width is always set, since the instruction register width is well-defined in the BSDL file; any explicit width is ignored in this case.

Data is read from and written to each device least significant bit first, i.e. the least significant bit is the first bit into the device and the first bit out of the device.

For the first write it is recommended that width is specified for every device and that every bit in the data has been set. Widths should also be specified when changing back to Device access scans after using Direct chain access scans.

Direct chain access

Alternatively data can be written and read directly to the JTAG chain currently available in the test. When run from a test in a dynamic chains project this will be the full JTAG chain of the profile defined for the test group. When run within a subchain test reset sequence it will just be the JTAG chains that form that subchain. When run in a test or reset sequence of a non-dynamic project it will include all the JTAG devices in the project.

Here is the syntax for setting up chain data to be scanned out:

IR TDI { WIDTH width } { [b..a] } := data;
DR TDI { WIDTH width } { [b..a] } := data;

Note that the TDI keyword used here is not referring to any specific TDI pin in the pin mapping, it is just the keyword used to define direct chain access reads.

This is the syntax for reading the JTAG chains data that has been scanned back in:

IR variable := TDO { [b..a] };
DR variable := TDO { [b..a] };

Note that the TDO keyword used here is not referring to any specific TDO pin in the pin mapping, it is just the keyword used to define direct chain access writes.

The optional ranges can be used to access specific portions of the JTAG chains. If the optional width is specified, then the instruction or data register width is modified.

Note that the data in the JTAG chains before the first JTAG access (i.e. in a TEST_RESET sequence) is undefined.

For the first write it is recommended that width is specified and that every bit in the data has been set. The width should also be specified when changing back to Direct chain access scans after using Device access scans.

The data will be scanned through all JTAG chains currently available in the order TDI1 -> TDI2 -> TDI3 -> TDI4.

Data is read from and written least significant bit first, i.e. the least significant bit is the first bit into the first chain and the first bit out of the last chain.

Performing scans

To write data to the JTAG chains the IRSCAN and DRSCAN statements are used:

IRSCAN { "state" };
DRSCAN { "state" };

The optional state argument is a string that specifies the JTAG state to go to after the data has been clocked through the JTAG chains. It can be any JTAG state, but it is recommended that it be one of the following stable states:

  • RESET
  • IDLE
  • IRPAUSE
  • DRPAUSE

The string is not case sensitive. An error is reported if the string is not a valid JTAG state, either at compile-time if the string is a constant, otherwise at run-time.

If no state is given, the system defaults to IDLE.

The data to write and the data read back during JTAG scans are kept separate by the system - when performing IRSCAN or DRSCAN the data read back from the JTAG chains does not overwrite the variable that is used for the write operation. This means, for example, that if you are performing a sequence of scans that just change the value of one pin, then between scans you will only need to modify one or two bits in the variable used for the write operation – you do not need to set bits in the variable unless they need to change. Similarly, changing widths to scan out does not immediately change the width of the variable used for the data last read in – that will only change after the next scan is performed using IRSCAN or DRSCAN.

When reading data back after a scan the type of access for the read must match the type of access used for the write before the scan. For example if a scan is performed after writing using Device access, reading back using Direct chain access syntax will be a runtime error.

Examples

The following example assumes that there are two JTAG devices on the board, IC1 (CPLD) and IC2 (CPU); IC1 has a data register length of 108.

INT data WIDTH 108;
CONST STRING cpld := "XJDemo.IC1";
CONST STRING cpu := "XJDemo.IC2";

JTAG
  // Reset
  JTAGSTATE ("RESET");

  // Preload safe values into boundary-scan cells of IC1
  IR cpld := "SAMPLE", cpu := "BYPASS";
  IRSCAN "IDLE";
    
  data := SAFE(cpld);
    
  DR cpld WIDTH WIDTHOF(data) := data, cpu WIDTH 1 := 0b0;
  DRSCAN "IDLE";

  // Put IC1 into EXTEST and IC2 into BYPASS.
  IR cpld := "EXTEST", cpu := "BYPASS";
  IRSCAN "IDLE";

  // Now set a pin to output.
  data[51] := 1;

  DR cpld := data, cpu := 0b0;
  DRSCAN "IDLE";
  DR data := cpld;
END;

This example initialises the board, after which it puts IC2 into BYPASS and IC1 into EXTEST. It then sets a specific bit in IC1's chain. The data returned from the JTAG chains is then stored back into the variable data. Note that the data register for IC2 is intentionally set to be a single bit wide, since the expression assigned to it is one bit wide.

The following example also assumes 2 JTAG devices on a board. It resets the devices and then clocks the JTAG chains. This will read out the ID codes of the two devices, which are 32 bits long each. It demonstrates accessing the data register directly.

INT data WIDTH 64;

JTAG
  // Reset
  JTAGSTATE("RESET");

  // Set data register to 64 bits wide and all zeroes
  DR TDI WIDTH 64 := 0;
  // Scan
  DRSCAN "IDLE";
  DR data := TDO;

  PRINT("Idcodes are 0x", HEX(data[63..32]), " and 0x", HEX(data[31..0]), "\n");
END;

Inside HOLDOFF

Raw JTAG scans are allowed inside a HOLDOFF block. Writes will be grouped together and not sent until exiting the block. If a read is required by IRSCAN or DRSCAN then HOLDOFF is temporarily disabled and all held off statements up to and including the IRSCAN or DRSCAN are performed. HOLDOFF is then re-enabled.