all: $(SOBJECTS)
 
-libusb-driver.so: usb-driver.c parport.c jtagkey.c config.c usb-driver.h parport.h jtagkey.h config.h Makefile
-       gcc $(CFLAGS) usb-driver.c parport.c config.c $(JTAGKEYSRC) -o $@ -ldl -lusb -lpthread $(FTDI) -shared
+libusb-driver.so: usb-driver.c parport.c jtagkey.c config.c jtagmon.c usb-driver.h parport.h jtagkey.h config.h jtagmon.h Makefile
+       gcc $(CFLAGS) usb-driver.c parport.c config.c jtagmon.c $(JTAGKEYSRC) -o $@ -ldl -lusb -lpthread $(FTDI) -shared
 
-libusb-driver-DEBUG.so: usb-driver.c parport.c jtagkey.c config.c usb-driver.h parport.h jtagkey.h config.h Makefile
-       gcc -DDEBUG $(CFLAGS) usb-driver.c parport.c config.c $(JTAGKEYSRC) -o $@ -ldl -lusb -lpthread $(FTDI) -shared
+libusb-driver-DEBUG.so: usb-driver.c parport.c jtagkey.c config.c jtagmon.c usb-driver.h parport.h jtagkey.h config.h jtagmon.h Makefile
+       gcc -DDEBUG $(CFLAGS) usb-driver.c parport.c config.c jtagmon.c $(JTAGKEYSRC) -o $@ -ldl -lusb -lpthread $(FTDI) -shared
 
 clean:
        rm -f $(SOBJECTS)
 
 #include "usb-driver.h"
 #include "config.h"
 #include "jtagkey.h"
+#include "jtagmon.h"
 
 #define USBBUFSIZE 1048576
 #define JTAG_SPEED 100000
 #ifdef DEBUG
                if (tr[i].cmdTrans == 13)
                        DPRINTF("write byte: %d\n", val);
+
+               if (tr[i].cmdTrans == 13)
+                       tapmon(val & PP_TCK, val & PP_TMS);
 #endif
 
                /* Pad writebuf for read-commands in stream */
 
--- /dev/null
+#include <string.h>
+#include <stdio.h>
+#include "jtagmon.h"
+
+enum tap_states {
+       TEST_LOGIC_RESET,
+       RUN_TEST_IDLE,
+       SELECT_DR,
+       CAPTURE_DR,
+       SHIFT_DR,
+       EXIT1_DR,
+       PAUSE_DR,
+       EXIT2_DR,
+       UPDATE_DR,
+       SELECT_IR,
+       CAPTURE_IR,
+       SHIFT_IR,
+       EXIT1_IR,
+       PAUSE_IR,
+       EXIT2_IR,
+       UPDATE_IR
+};
+
+void tapmon(unsigned char tck, unsigned char tms) {
+       static unsigned char last_tck = 1;
+       static int state = TEST_LOGIC_RESET;
+       static char state_text[32] = "Test Logic Reset";
+       char last_state_text[32];
+       int last_state = state;
+
+       strcpy(last_state_text, state_text);
+
+       if (!last_tck && tck) {
+               switch(state) {
+                       case TEST_LOGIC_RESET:
+                               if (tms) {
+                                       state = TEST_LOGIC_RESET;
+                               } else {
+                                       state = RUN_TEST_IDLE;
+                               }
+                               break;
+                       case RUN_TEST_IDLE:
+                               if (tms) {
+                                       state = SELECT_DR;
+                               } else {
+                                       state = RUN_TEST_IDLE;
+                               }
+                               break;
+                       case SELECT_DR:
+                               if (tms) {
+                                       state = SELECT_IR;
+                               } else {
+                                       state = CAPTURE_DR;
+                               }
+                               break;
+                       case CAPTURE_DR:
+                               if (tms) {
+                                       state = EXIT1_DR;
+                               } else {
+                                       state = SHIFT_DR;
+                               }
+                               break;
+                       case SHIFT_DR:
+                               if (tms) {
+                                       state = EXIT1_DR;
+                               } else {
+                                       state = SHIFT_DR;
+                               }
+                               break;
+                       case EXIT1_DR:
+                               if (tms) {
+                                       state = UPDATE_DR;
+                               } else {
+                                       state = PAUSE_DR;
+                               }
+                               break;
+                       case PAUSE_DR:
+                               if (tms) {
+                                       state = EXIT2_DR;
+                               } else {
+                                       state = PAUSE_DR;
+                               }
+                               break;
+                       case EXIT2_DR:
+                               if (tms) {
+                                       state = UPDATE_DR;
+                               } else {
+                                       state = SHIFT_DR;
+                               }
+                               break;
+                       case UPDATE_DR:
+                               if (tms) {
+                                       state = SELECT_DR;
+                               } else {
+                                       state = RUN_TEST_IDLE;
+                               }
+                               break;
+                       case SELECT_IR:
+                               if (tms) {
+                                       state = TEST_LOGIC_RESET;
+                               } else {
+                                       state = CAPTURE_IR;
+                               }
+                               break;
+                       case CAPTURE_IR:
+                               if (tms) {
+                                       state = EXIT1_IR;
+                               } else {
+                                       state = SHIFT_IR;
+                               }
+                               break;
+                       case SHIFT_IR:
+                               if (tms) {
+                                       state = EXIT1_IR;
+                               } else {
+                                       state = SHIFT_IR;
+                               }
+                               break;
+                       case EXIT1_IR:
+                               if (tms) {
+                                       state = UPDATE_IR;
+                               } else {
+                                       state = PAUSE_IR;
+                               }
+                               break;
+                       case PAUSE_IR:
+                               if (tms) {
+                                       state = EXIT2_IR;
+                               } else {
+                                       state = PAUSE_IR;
+                               }
+                               break;
+                       case EXIT2_IR:
+                               if (tms) {
+                                       state = UPDATE_IR;
+                               } else {
+                                       state = SHIFT_IR;
+                               }
+                               break;
+                       case UPDATE_IR:
+                               if (tms) {
+                                       state = SELECT_DR;
+                               } else {
+                                       state = RUN_TEST_IDLE;
+                               }
+                               break;
+               }
+
+               switch(state) {
+                       case TEST_LOGIC_RESET:
+                               strcpy(state_text, "Test Logic Reset");
+                               break;
+                       case RUN_TEST_IDLE:
+                               strcpy(state_text, "Run-Test / Idle");
+                               break;
+                       case SELECT_DR:
+                               strcpy(state_text, "Select-DR");
+                               break;
+                       case CAPTURE_DR:
+                               strcpy(state_text, "Capture-DR");
+                               break;
+                       case SHIFT_DR:
+                               strcpy(state_text, "Shift-DR");
+                               break;
+                       case EXIT1_DR:
+                               strcpy(state_text, "Exit1-DR");
+                               break;
+                       case PAUSE_DR:
+                               strcpy(state_text, "Pause-DR");
+                               break;
+                       case EXIT2_DR:
+                               strcpy(state_text, "Exit2-DR");
+                               break;
+                       case UPDATE_DR:
+                               strcpy(state_text, "Update-DR");
+                               break;
+                       case SELECT_IR:
+                               strcpy(state_text, "Select-IR");
+                               break;
+                       case CAPTURE_IR:
+                               strcpy(state_text, "Capture-IR");
+                               break;
+                       case SHIFT_IR:
+                               strcpy(state_text, "Shift-IR");
+                               break;
+                       case EXIT1_IR:
+                               strcpy(state_text, "Exit1-IR");
+                               break;
+                       case PAUSE_IR:
+                               strcpy(state_text, "Pause-IR");
+                               break;
+                       case EXIT2_IR:
+                               strcpy(state_text, "Exit2-IR");
+                               break;
+                       case UPDATE_IR:
+                               strcpy(state_text, "Update-IR");
+                               break;
+               }
+
+               if (last_state != state) {
+                       fprintf(stderr,"TAP state transition from %s to %s\n", last_state_text, state_text);
+               }
+       }
+
+       last_tck = tck;
+}