+//! Detects how many TAPs are in the JTAG chain
+uint16_t jtag_detect_chain_length()
+{
+ int i;
+ int bit;
+ uint16_t length = 0;
+
+ if (!in_run_test_idle())
+ {
+ debugstr("detect chain length must start from run-test-idle");
+ return 0;
+ }
+
+ // The standard JTAG instruction for "bypass" mode is to set all 1's in the
+ // instruction register. When in "bypass" mode, the DR acts like a 1-bit
+ // shift regiser. So we can use that to detect how many TAPs are in the
+ // chain.
+
+ // first get into shift IR mode
+ jtag_capture_ir();
+ jtag_shift_register();
+
+ // then we flood the IR chain with all 1's to put all device's DRs
+ // into bypass mode
+ CLRTMS;
+ SETMOSI;
+ for (i = 0; i < 1024; i++)
+ {
+ if (i == 1023)
+ SETTMS; // exit on last bit
+ jtag_tcktock();
+ }
+ jtag_state = EXIT1_IR;
+
+ // go to Update-IR
+ CLRMOSI;
+ jtag_tcktock();
+ jtag_state = UPDATE_IR;
+
+ // go to Shift-DR state
+ jtag_capture_dr();
+ jtag_shift_register();
+
+ // flush the DR's with zeros
+ CLRTMS;
+ CLRMOSI;
+ for (i = 0; i < 1024; i++)
+ {
+ jtag_tcktock();
+ }
+
+ // send 1's into the DRs until we see one come out the other side
+ SETMOSI;
+ for (i = 0; i < 1024; i++)
+ {
+ jtag_tcktock();
+ bit = READMISO;
+ if (bit)
+ break;
+ length++;
+ }
+
+ // now get back to run-test-idle
+ jtag_run_test_idle();
+
+ return length;
+}
+
+//! Gets device ID for specified chip in the chain
+uint32_t jtag_get_device_id(int chip)
+{
+ int i;
+ uint16_t chain_length;
+ uint32_t id = 0;
+
+ // reset everything
+ jtag_reset_tap();
+
+ // figure out how many devices are in the chain
+ chain_length = jtag_detect_chain_length();
+
+ if (chip >= chain_length)
+ {
+ debugstr("invalid part index");
+ return 0;
+ }
+
+ // reset everything again because going through test-logic-reset forces
+ // all IR's to have their manufacturer specific instruction for IDCODE
+ // and loads the DR's with the chip's ID code.
+ jtag_reset_tap();
+
+ // get into shift DR state
+ jtag_capture_dr();
+ jtag_shift_register();
+
+ // read out the 32-bit ID codes for each device
+ CLRTMS;
+ CLRMOSI;
+ for (i = 0; i < (chip + 1); i++)
+ {
+ id = jtag_trans_n(0xFFFFFFFF, 32, LSB | NOEND | NORETIDLE);
+ }
+
+ jtag_run_test_idle();
+
+ return id;
+}
+
+//! Shift 8 bits in/out of selected register
+uint8_t jtag_trans_8(uint8_t in)
+{
+ uint32_t out = jtag_trans_n((uint32_t)in, 8, MSB);
+ return (uint8_t)(0x000000FF & out);
+}
+
+//! Shift 16 bits in/out of selected register
+uint16_t jtag_trans_16(uint16_t in)
+{
+ uint32_t out = jtag_trans_n((uint32_t)in, 16, MSB);
+ return (uint16_t)(0x0000FFFF & out);
+}