fpga4fun.comwhere FPGAs are fun

Query the JTAG chain

Count the number of devices in the JTAG chain

One important IR value is the "all-ones" value. For the CPU that would be 11111 and for the FPGA, that's 1111111111. This value corresponds to the mandatory IR instruction called BYPASS. In bypass mode, the TAP controller DR register is always a single flip-flop which does nothing besides delaying the TDI input by one clock cycle before outputting to TDO.

One interesting way to use this BYPASS mode is to count the number of ICs that are present in the JTAG chain.
If each JTAG IC delays the TDI-TDO chain by one clock, we can send some data and check by how long it is delayed. That gives us the number of ICs in the chain.

Here's an example:

  // go to reset state
  for(i=0; i<5; i++) JTAG_clock(TMS);

  // go to Shift-IR
  JTAG_clock(0);
  JTAG_clock(TMS);
  JTAG_clock(TMS);
  JTAG_clock(0);
  JTAG_clock(0);

  // Send plenty of ones into the IR registers
  // That makes sure all devices are in BYPASS!
  for(i=0; i<999; i++) JTAG_clock(1);
  JTAG_clock(1 | TMS);  // last bit needs to have TMS active, to exit shift-IR

  // we are in Exit1-IR, go to Shift-DR
  JTAG_clock(TMS);
  JTAG_clock(TMS);
  JTAG_clock(0);
  JTAG_clock(0);

  // Send plenty of zeros into the DR registers to flush them
  for(i=0; i<1000; i++) JTAG_clock(0);

  // now send ones until we receive one back
  for(i=0; i<1000; i++) if(JTAG_clock(1)) break;

  nbDevices = i;
  printf("There are %d device(s) in the JTAG chain\n", nbDevices);

Get the IDs of the devices in the JTAG chain

Most JTAG ICs support the IDCODE instruction. In IDCODE mode, the DR register is loaded with a 32-bits value that represents the device ID.

Unlike for the BYPASS instruction, the IR value for the IDCODE is not standard. Fortunately, each time the TAP controller goes into Test-Logic-Reset, it goes into IDCODE mode (and loads the IDCODE into DR).

Here's an example:

  // go to reset state (that loads IDCODE into IR of all the devices)
  for(i=0; i<5; i++) JTAG_clock(TMS);

  // go to Shift-DR
  JTAG_clock(0);
  JTAG_clock(TMS);
  JTAG_clock(0);
  JTAG_clock(0);

  // and read the IDCODES
  for(i=0; i < nbDevices; i++)
  {
    printf("IDCODE for device %d is %08X\n", i+1, JTAG_read(32));
  }