The attached patch against git head adds to the python bindings

    New chain method "flush" - calls urj_tap_chain_flush to
     make sure all queued activity has been sent to the hardware cable
    New chain method get_tdo - gets the current value of TDO pin.
Don't unnecessarily shift instruction registers after doing an addpart.
    Fix retrieval of data register shift-in buffer values with get_dr
    Created include file py_urjtag.h so we can have more than one file
    of python-C bindings
    New chain method get_register - returns a python object representing a
        data register (urj_data_register)
    Implementation of useful methods on register objects, which can make
    code dealing with multiple parts and user registers much cleaner.


From 7990d3d7a928c5997736915b0ed47f3f397e1a69 Mon Sep 17 00:00:00 2001
From: Steve Tell <t...@telltronics.org>
Date: Mon, 26 Jun 2017 18:59:55 -0400
Subject: [PATCH] python binding additions and fixes
 New chain method "flush" - calls urj_tap_chain_flush to
  make sure all queued activity has been sent to the hardware cable
 New chain method get_tdo - gets the current value of TDO pin.
 Don't unnecessarily shift instruction registers after doing an addpart.
 Fix retrieval of data register shift-in buffer values with get_dr
 Created include file py_urjtag.h so we can have more than one file
 of python-C bindings
 New chain method get_register - returns a python object representing a
        data register (urj_data_register)
 Implementation of useful methods on registers, which can make code dealing
 with multiple parts and user registers much cleaner.

---
 urjtag/bindings/python/chain.c       |  167 ++++++++++++++---
 urjtag/bindings/python/py_urjtag.h   |   43 ++++
 urjtag/bindings/python/register.c    |  348 ++++++++++++++++++++++++++++++++++
 urjtag/bindings/python/setup.py.in   |    2 +-
 urjtag/doc/urjtag-python.txt         |   31 +++-
 urjtag/include/urjtag/tap_register.h |    2 +
 urjtag/src/tap/register.c            |   94 +++++++++
 7 files changed, 654 insertions(+), 33 deletions(-)
 create mode 100644 urjtag/bindings/python/py_urjtag.h
 create mode 100644 urjtag/bindings/python/register.c

diff --git a/urjtag/bindings/python/chain.c b/urjtag/bindings/python/chain.c
index 088928c..5886513 100644
--- a/urjtag/bindings/python/chain.c
+++ b/urjtag/bindings/python/chain.c
@@ -32,16 +32,34 @@
 #include <urjtag/chain.h>
 #include <urjtag/cmd.h>
 
-static PyObject *UrjtagError;
+#include "py_urjtag.h"
+
+PyObject *UrjtagError;
 
 typedef struct
 {
     PyObject_HEAD urj_chain_t *urchain;
+    urj_pyregister_t *reglist;
 } urj_pychain_t;
 
+
+static void urj_pyc_invalidate_reglist(urj_pychain_t *self)
+{
+    urj_pyregister_t *r;
+    while(self->reglist) {
+        self->reglist->inst = NULL;
+        self->reglist->urreg = NULL;
+        r = self->reglist;
+        self->reglist = self->reglist->next;
+        Py_DECREF (r);
+    }
+}
+
 static void
 urj_pyc_dealloc (urj_pychain_t *self)
 {
+    urj_tap_chain_flush (self->urchain);
+    urj_pyc_invalidate_reglist (self);
     urj_tap_chain_free (self->urchain);
     Py_TYPE (self)->tp_free ((PyObject *) self);
 }
@@ -74,7 +92,7 @@ urj_pyc_new (PyTypeObject *type, PyObject *args, PyObject 
*kwds)
  * if OK, return python "none".
  * else, throw a python exception
  */
-static PyObject *
+PyObject *
 urj_py_chkret (int rc)
 {
     if (rc == URJ_STATUS_OK)
@@ -91,16 +109,12 @@ urj_py_chkret (int rc)
     return NULL;
 }
 
-#define UPRC_CBL 1
-#define UPRC_DET 2
-#define UPRC_BUS 4
-
 /* perform selected prerequesite checks on the state of a chain object
  * returns nonzero on success.
  * if 0 is returned, python exception has been posted and
  *     caller must return NULL to signal python exception.
  */
-static int
+int
 urj_pyc_precheck (urj_chain_t *urc, int checks_needed)
 {
     if (urc == NULL)
@@ -171,6 +185,18 @@ urj_pyc_cable (urj_pychain_t *self, PyObject *args)
 }
 
 static PyObject *
+urj_pyc_flush (urj_pychain_t *self)
+{
+    urj_chain_t *urc = self->urchain;
+
+    if (!urj_pyc_precheck (urc, UPRC_CBL))
+        return NULL;
+
+    urj_tap_chain_flush (urc);
+    return Py_BuildValue ("");
+}
+
+static PyObject *
 urj_pyc_disconnect (urj_pychain_t *self)
 {
     urj_chain_t *urc = self->urchain;
@@ -198,6 +224,8 @@ urj_pyc_tap_detect (urj_pychain_t *self, PyObject *args)
         return NULL;
     if (!urj_pyc_precheck (urc, UPRC_CBL))
         return NULL;
+
+    urj_pyc_invalidate_reglist(self);
     return urj_py_chkret (urj_tap_detect (urc, maxirlen));
 }
 
@@ -278,6 +306,18 @@ urj_pyc_get_trst (urj_pychain_t *self)
 }
 
 static PyObject *
+urj_pyc_get_tdo (urj_pychain_t *self)
+{
+    int tdoval;
+    urj_chain_t *urc = self->urchain;
+    if (!urj_pyc_precheck (urc, UPRC_CBL))
+        return NULL;
+
+    tdoval = urj_tap_cable_get_tdo (urc->cable);
+    return Py_BuildValue ("i", tdoval);
+}
+
+static PyObject *
 urj_pyc_set_pod_signal (urj_pychain_t *self, PyObject *args)
 {
     urj_chain_t *urc = self->urchain;
@@ -388,6 +428,7 @@ urj_pyc_get_dr (urj_pychain_t *self, int in, int string, 
PyObject *args)
     urj_part_instruction_t *active_ir;
     int lsb = -1;
     int msb = -1;
+    const char *value_string;
 
     if (!PyArg_ParseTuple (args, "|ii", &msb, &lsb))
         return NULL;
@@ -421,20 +462,26 @@ urj_pyc_get_dr (urj_pychain_t *self, int in, int string, 
PyObject *args)
     else
         r = dr->out;            /* recently captured+scanned-out values */
 
+    if (in)
+        r = dr->in;             /* input buffer for next shift_dr */
+    else
+        r = dr->out;            /* recently captured+scanned-out values */
+
     if (msb == -1)
-    {
-        if (string)
-            return Py_BuildValue ("s", urj_tap_register_get_string (r));
-        else
-            return Py_BuildValue ("L", urj_tap_register_get_value (r));
-    }
+        value_string = urj_tap_register_get_string (r);
     else
+        value_string = urj_tap_register_get_string_bit_range (r, msb, lsb);
+    if (value_string == NULL)
     {
-        if (string)
-            return Py_BuildValue (""); /* TODO 
urj_tap_register_get_string_bit_range (r, msb, lsb)); */
-        else
-            return Py_BuildValue ("L", urj_tap_register_get_value_bit_range 
(r, msb, lsb));
+        PyErr_SetString (UrjtagError,
+                         _("error obtaining tap register value"));
+        return NULL;
     }
+
+    if (string)
+        return Py_BuildValue ("s", value_string);
+    else
+        return PyLong_FromString((char *)value_string, NULL, 2);
 }
 
 static PyObject *
@@ -477,7 +524,7 @@ urj_pyc_set_dr (urj_pychain_t *self, int in, PyObject *args)
     if (!PyArg_ParseTuple (args, "s|ii", &newstr, &msb, &lsb))
     {
         PyErr_Clear ();
-        if (!PyArg_ParseTuple (args, "L|ii", &newval, &msb, &lsb))
+        if (!PyArg_ParseTuple (args, "K|ii", &newval, &msb, &lsb))
             return NULL;
     }
 
@@ -522,8 +569,7 @@ urj_pyc_set_dr (urj_pychain_t *self, int in, PyObject *args)
             lsb = msb;
 
         if (newstr)
-            /* TODO urj_tap_register_set_string_bit_range(r, newstr, msb, 
lsb); */
-            return Py_BuildValue ("");
+            return urj_py_chkret (urj_tap_register_set_string_bit_range(r, 
newstr, msb, lsb));
         else
             return urj_py_chkret (urj_tap_register_set_value_bit_range(r, 
newval, msb, lsb));
     }
@@ -604,7 +650,7 @@ urj_pyc_addpart (urj_pychain_t *self, PyObject *args)
     }
 
     urj_part_parts_set_instruction (urc->parts, "BYPASS");
-    urj_tap_chain_shift_instructions (urc);
+//    urj_tap_chain_shift_instructions (urc);
     return Py_BuildValue ("");
 }
 
@@ -809,6 +855,62 @@ urj_pyc_flashmem (urj_pychain_t *self, PyObject *args)
     return Py_BuildValue ("i", r);
 }
 
+static PyObject *
+urj_pyc_get_register (urj_pychain_t *self, PyObject *args)
+{
+    urj_chain_t *urc = self->urchain;
+    int partn;
+    char *regname = NULL;
+    char *instname = NULL;
+    urj_part_t *p;
+    urj_data_register_t *dr;
+    urj_pyregister_t *reg;
+    urj_part_instruction_t *inst;
+
+    PyTypeObject *regtype = &urj_pyregister_Type;
+
+    if (!urj_pyc_precheck (urc, UPRC_CBL|UPRC_DET))
+        return NULL;
+    if (!PyArg_ParseTuple (args, "is|s", &partn, &regname, &instname))
+        return NULL;
+    
+    if(partn < 0 || partn > urc->parts->len) {
+         PyErr_SetString (UrjtagError,
+                          _("part number out of range for chain length"));
+         return NULL;
+    }
+    p = urc->parts->parts[partn];
+
+    dr = urj_part_find_data_register (p, regname);
+    if(dr == NULL) {
+         PyErr_SetString (UrjtagError,
+                          _("get_register: register not found"));
+         return NULL;
+    }
+    if(instname) {
+        inst = urj_part_find_instruction (p, instname);
+        if(inst == NULL) {
+            PyErr_SetString (UrjtagError,
+                             _("get_register: instruction not found"));
+            return NULL;
+        }
+    } else {
+        inst = NULL;
+    }
+
+    reg = (urj_pyregister_t *) PyObject_New (urj_pyregister_t*, regtype);
+    reg->part = partn;
+    reg->urreg = dr;
+    reg->urc = urc;
+    reg->inst = inst;
+
+    Py_INCREF(reg);
+    reg->next = self->reglist;
+    self->reglist = reg;
+    return (PyObject *) reg;
+}
+
+
 static PyMethodDef urj_pyc_methods[] =
 {
     {"cable", (PyCFunction) urj_pyc_cable, METH_VARARGS,
@@ -823,12 +925,16 @@ static PyMethodDef urj_pyc_methods[] =
      "Return the length of the TAP chain"},
     {"reset", (PyCFunction) urj_pyc_reset, METH_NOARGS,
      "Perform jtag reset using TMS"},
+    {"flush", (PyCFunction) urj_pyc_flush, METH_NOARGS,
+     "Flush the chain output"},
     {"partid", (PyCFunction) urj_pyc_partid, METH_VARARGS,
      "Return the IDCODE for the indicated part number in the chain"},
     {"set_trst", (PyCFunction) urj_pyc_set_trst, METH_VARARGS,
      "set the TRST output of the cable"},
     {"get_trst", (PyCFunction) urj_pyc_get_trst, METH_NOARGS,
      "get the current value of the TRST output of the cable"},
+    {"get_tdo", (PyCFunction) urj_pyc_get_tdo, METH_NOARGS,
+     "get the current value of the TDO output of the cable"},
     {"set_pod_signal", (PyCFunction) urj_pyc_set_pod_signal, METH_VARARGS,
      "set an auxiliary pod signal"},
     {"get_pod_signal", (PyCFunction) urj_pyc_get_pod_signal, METH_VARARGS,
@@ -843,7 +949,6 @@ static PyMethodDef urj_pyc_methods[] =
      "scan values through the instruction register"},
     {"shift_dr", (PyCFunction) urj_pyc_shift_dr, METH_NOARGS,
      "scan values through the data register"},
-
     {"get_dr_in_string", (PyCFunction) urj_pyc_get_str_dr_in, METH_VARARGS,
      "get bits that will be scanned in on next shift_dr, as string"},
     {"get_dr_out_string", (PyCFunction) urj_pyc_get_str_dr_out, METH_VARARGS,
@@ -852,7 +957,6 @@ static PyMethodDef urj_pyc_methods[] =
      "get bits that will be scanned in on next shift_dr, as integer"},
     {"get_dr_out", (PyCFunction) urj_pyc_get_int_dr_out, METH_VARARGS,
      "retrieve values scanned out from the data registers on the last 
shift_dr, as integer"},
-
     {"set_dr_in", (PyCFunction) urj_pyc_set_dr_in, METH_VARARGS,
      "set bits that will be scanned in on next shiftdr"},
     {"set_dr_out", (PyCFunction) urj_pyc_set_dr_out, METH_VARARGS,
@@ -877,13 +981,16 @@ static PyMethodDef urj_pyc_methods[] =
      "write a single word"},
     {"flashmem", (PyCFunction) urj_pyc_flashmem, METH_VARARGS,
      "burn flash memory with data from a file"},
+    {"get_register", (PyCFunction)urj_pyc_get_register, METH_VARARGS,
+     "retrieve register object for convenient set_dr/shift_dr use"},
+
     {NULL}                      /* Sentinel */
 };
 
 static PyTypeObject urj_pychain_Type =
 {
     PyVarObject_HEAD_INIT (NULL, 0) "urjtag.chain", /* tp_name */
-    sizeof (urj_pychain_t),             /* tp_basicsize */
+    sizeof (urj_pychain_t),     /* tp_basicsize */
     0,                          /* tp_itemsize */
     (destructor) urj_pyc_dealloc, /* tp_dealloc */
     0,                          /* tp_print */
@@ -908,7 +1015,7 @@ static PyTypeObject urj_pychain_Type =
     0,                          /* tp_weaklistoffset */
     0,                          /* tp_iter */
     0,                          /* tp_iternext */
-    urj_pyc_methods,              /* tp_methods */
+    urj_pyc_methods,            /* tp_methods */
     0,                          /* tp_members */
     0,                          /* tp_getset */
     0,                          /* tp_base */
@@ -918,7 +1025,7 @@ static PyTypeObject urj_pychain_Type =
     0,                          /* tp_dictoffset */
     0,                          /* tp_init */
     0,                          /* tp_alloc */
-    urj_pyc_new,                  /* tp_new */
+    urj_pyc_new,                /* tp_new */
 };
 
 /************************************************************************
@@ -942,7 +1049,7 @@ static PyMethodDef module_methods[] =
     {NULL}                      /* Sentinel */
 };
 
-static struct PyModuleDef chain_moduledef =
+static struct PyModuleDef urjtag_moduledef =
 {
     PyModuleDef_HEAD_INIT,
     "urjtag",
@@ -957,8 +1064,10 @@ MODINIT_DECL (urjtag)
 
     if (PyType_Ready (&urj_pychain_Type) < 0)
         return MODINIT_ERROR_VAL;
+    if (PyType_Ready (&urj_pyregister_Type) < 0)
+        return MODINIT_ERROR_VAL;
 
-    m = PyModule_Create (&chain_moduledef);
+    m = PyModule_Create (&urjtag_moduledef);
 
     if (m == NULL)
         return MODINIT_ERROR_VAL;
@@ -987,6 +1096,8 @@ MODINIT_DECL (urjtag)
 
     Py_INCREF (&urj_pychain_Type);
     PyModule_AddObject (m, "chain", (PyObject *) &urj_pychain_Type);
+    Py_INCREF (&urj_pyregister_Type);
+    PyModule_AddObject (m, "register", (PyObject *) &urj_pyregister_Type);
 
     return MODINIT_SUCCESS_VAL (m);
 }
diff --git a/urjtag/bindings/python/py_urjtag.h 
b/urjtag/bindings/python/py_urjtag.h
new file mode 100644
index 0000000..38582eb
--- /dev/null
+++ b/urjtag/bindings/python/py_urjtag.h
@@ -0,0 +1,43 @@
+/*
+ * common definitions for python bindings
+ *
+ * Copyright (C) 2011 Steve Tell
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Python bindings for urjtag intially written by Steve Tell.
+ * Additional methods by Jonathan Stroud.
+ */
+
+typedef struct urj_pyregister urj_pyregister_t;
+struct urj_pyregister
+{
+    PyObject_HEAD urj_data_register_t *urreg;
+    int part;
+    urj_chain_t *urc;
+    urj_part_instruction_t *inst;
+    urj_pyregister_t *next;
+};
+
+extern PyTypeObject urj_pyregister_Type;
+
+extern PyObject *urj_py_chkret (int rc);
+PyObject *UrjtagError;
+
+extern int urj_pyc_precheck (urj_chain_t *urc, int checks_needed);
+#define UPRC_CBL 1
+#define UPRC_DET 2
+#define UPRC_BUS 4
diff --git a/urjtag/bindings/python/register.c 
b/urjtag/bindings/python/register.c
new file mode 100644
index 0000000..063ad18
--- /dev/null
+++ b/urjtag/bindings/python/register.c
@@ -0,0 +1,348 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2011 Steve Tell
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Python bindings for urjtag intially written by Steve Tell.
+ * Additional methods by Jonathan Stroud.
+ *
+ */
+#include <Python.h>
+#include "structmember.h"
+#include "pycompat23.h"
+
+#include <sysdep.h>
+
+#include <urjtag/urjtag.h>
+#include <urjtag/chain.h>
+#include <urjtag/cmd.h>
+
+#include "py_urjtag.h"
+
+extern PyObject *UrjtagError;
+
+static void
+urj_pyr_dealloc (urj_pyregister_t *self)
+{
+    Py_TYPE (self)->tp_free ((PyObject *) self);
+}
+
+static PyObject *
+urj_pyr_str (PyObject *s)
+{
+    urj_pyregister_t *self = (urj_pyregister_t *) s;
+    char buf[200];
+    urj_chain_t *urc = self->urc;
+
+    if (self->urreg == NULL || self->inst == NULL)
+        snprintf (buf, 200, "<urjtag.register chain=%p invalid>", urc);
+    else
+        snprintf (buf, 200, "<urjtag.register chain=%p reg=%s inst=%s>", urc, 
+             self->urreg->name, self->inst->name);
+    return PyString_FromString (buf);
+}
+
+
+static PyObject *
+urj_pyr_get_dr (urj_pyregister_t *self, int in, int string, PyObject *args)
+{
+    urj_data_register_t *dr = self->urreg;
+    urj_chain_t *urc = self->urc;
+    urj_tap_register_t *r;
+    int lsb = -1;
+    int msb = -1;
+    const char *value_string;
+
+    if (!PyArg_ParseTuple (args, "|ii", &msb, &lsb))
+        return NULL;
+    if (lsb == -1)
+        lsb = msb;
+    if (!urj_pyc_precheck (urc, UPRC_CBL))
+        return NULL;
+
+    if (dr == NULL)
+    {
+        PyErr_SetString (UrjtagError,
+                         _("invalid data register object"));
+        return NULL;
+    }
+
+    if (in)
+        r = dr->in;             /* input buffer for next shift_dr */
+    else
+        r = dr->out;            /* recently captured+scanned-out values */
+
+    if (msb == -1)
+        value_string = urj_tap_register_get_string (r);
+    else
+        value_string = urj_tap_register_get_string_bit_range (r, msb, lsb);
+    if (value_string == NULL)
+    {
+        PyErr_SetString (UrjtagError,
+                         _("error obtaining tap register value"));
+        return NULL;
+    }
+
+    if (string)
+        return Py_BuildValue ("s", value_string);
+    else
+        return PyLong_FromString ((char *)value_string, NULL, 2);
+}
+
+static PyObject *
+urj_pyr_get_str_dr_out (urj_pyregister_t *self, PyObject *args)
+{
+    return urj_pyr_get_dr (self, 0, 1, args);
+}
+
+static PyObject *
+urj_pyr_get_str_dr_in (urj_pyregister_t *self, PyObject *args)
+{
+    return urj_pyr_get_dr (self, 1, 1, args);
+}
+
+static PyObject *
+urj_pyr_get_int_dr_out (urj_pyregister_t *self, PyObject *args)
+{
+    return urj_pyr_get_dr (self, 0, 0, args);
+}
+
+static PyObject *
+urj_pyr_get_int_dr_in (urj_pyregister_t *self, PyObject *args)
+{
+    return urj_pyr_get_dr (self, 1, 0, args);
+}
+
+static PyObject *
+urj_pyr_set_dr (urj_pyregister_t *self, int in, PyObject *args)
+{
+    urj_data_register_t *dr = self->urreg;
+    urj_tap_register_t *r;
+    char *newstr = NULL;
+    uint64_t newval;
+    int lsb = -1;
+    int msb = -1;
+
+
+    if (!PyArg_ParseTuple (args, "s|ii", &newstr, &msb, &lsb))
+    {
+        PyErr_Clear ();
+        if (!PyArg_ParseTuple (args, "L|ii", &newval, &msb, &lsb))
+            return NULL;
+    }
+
+    if (dr == NULL)
+    {
+        PyErr_SetString (UrjtagError,
+                         _("invalid register object"));
+        return NULL;
+    }
+
+    if (in)
+        r = dr->in;
+    else
+        r = dr->out;
+
+    if (msb == -1)
+    {
+        if (newstr)
+            return urj_py_chkret (urj_tap_register_set_string (r, newstr));
+        else
+            return urj_py_chkret (urj_tap_register_set_value (r, newval));
+    }
+    else
+    {
+        if (lsb == -1)
+            lsb = msb;
+
+        if (newstr)
+            return urj_py_chkret (urj_tap_register_set_string_bit_range (r, 
newstr, msb, lsb));
+        else
+            return urj_py_chkret (urj_tap_register_set_value_bit_range (r, 
newval, msb, lsb));
+    }
+}
+
+static PyObject *
+urj_pyr_set_dr_out (urj_pyregister_t *self, PyObject *args)
+{
+    return urj_pyr_set_dr (self, 0, args);
+}
+
+static PyObject *
+urj_pyr_set_dr_in (urj_pyregister_t *self, PyObject *args)
+{
+    return urj_pyr_set_dr (self, 1, args);
+}
+
+static PyObject *
+urj_pyr_shift_dr (urj_pyregister_t *self, PyObject *args)
+{
+
+    urj_chain_t *urc = self->urc;
+    int partn = self->part;
+    char *instname = NULL;
+    urj_part_t *part;
+
+    if (!PyArg_ParseTuple (args, "|s", &instname))
+        return NULL;
+
+
+    if (!urj_pyc_precheck (urc, UPRC_CBL))
+        return NULL;
+
+    if (self->urreg == NULL)
+    {
+        PyErr_SetString (UrjtagError,
+                         _("invalid register object"));
+        return NULL;
+    }
+
+    
+    urc->active_part = partn;
+    part = urj_tap_chain_active_part (urc);
+    if (part == NULL)
+    {
+        PyErr_SetString (UrjtagError, _("No active part on chain"));
+        return NULL;
+    }
+    if (instname) 
+    {
+        urj_part_set_instruction (part, instname);
+    }
+    else 
+    {
+        if (!self->inst) { 
+            PyErr_SetString (UrjtagError, _("no instruction for data 
register"));
+            return NULL;
+        }
+        part->active_instruction = self->inst;
+    }
+
+    return urj_py_chkret (urj_tap_chain_shift_data_registers (urc, 1));
+}
+
+static PyObject *
+urj_pyr_shift_ir (urj_pyregister_t *self,  PyObject *args)
+{
+    urj_chain_t *urc = self->urc;
+    char *instname = NULL;
+    urj_part_t *part;
+
+    if (!PyArg_ParseTuple (args, "|s", &instname)) 
+        return NULL;
+
+    if (!urj_pyc_precheck (urc, UPRC_CBL))
+        return NULL;
+
+    urc->active_part = self->part;
+    part = urj_tap_chain_active_part (urc);
+    if (part == NULL)
+    {
+        PyErr_SetString (UrjtagError, _("No active part on chain"));
+        return NULL;
+    }
+    if (instname) {
+        urj_part_set_instruction (part, instname);
+    } 
+    else 
+    {
+        if (!self->inst) 
+        { 
+            PyErr_SetString (UrjtagError, _("no instruction for data 
register"));
+            return NULL;
+        }
+        part->active_instruction = self->inst;
+    }
+
+    return urj_py_chkret (urj_tap_chain_shift_instructions (urc));
+}
+
+
+
+static PyMethodDef urj_pyr_methods[] =
+{
+    {"get_dr_in", (PyCFunction) urj_pyr_get_int_dr_in, METH_VARARGS,
+     "get bits that will be scanned in on next shift_dr, as integer"},
+    {"get_dr_in_string", (PyCFunction) urj_pyr_get_str_dr_in, METH_VARARGS,
+     "get bits that will be scanned in on next shift_dr, as string"},
+    {"get_dr_out", (PyCFunction) urj_pyr_get_int_dr_out, METH_VARARGS,
+     "retrieve values scanned out from the data registers on the last 
shift_dr, as integer"},
+    {"get_dr_out_string", (PyCFunction) urj_pyr_get_str_dr_out, METH_VARARGS,
+     "retrieve values scanned out from the data registers on the last 
shift_dr, as string"},
+
+    {"set_dr_in", (PyCFunction) urj_pyr_set_dr_in, METH_VARARGS,
+     "set bits that will be scanned in on next shiftdr"},
+    {"set_dr_out", (PyCFunction) urj_pyr_set_dr_out, METH_VARARGS,
+     "set the holding register for values scanned out from the data register"},
+    {"shift_dr", (PyCFunction) urj_pyr_shift_dr, METH_VARARGS,
+     "scan values through the data register"},
+    {"shift_ir", (PyCFunction) urj_pyr_shift_ir, METH_VARARGS,
+     "scan values through the instruction register to select this data 
regsiter"},
+    {NULL},
+};
+
+
+PyTypeObject urj_pyregister_Type =
+{
+    PyVarObject_HEAD_INIT (NULL, 0) "urjtag.register", /* tp_name */
+    sizeof (urj_pyregister_t),             /* tp_basicsize */
+    0,                          /* tp_itemsize */
+    (destructor) urj_pyr_dealloc, /* tp_dealloc */
+    0,                          /* tp_print */
+    0,                          /* tp_getattr */
+    0,                          /* tp_setattr */
+    0,                          /* tp_compare */
+    urj_pyr_str,                /* tp_repr */
+    0,                          /* tp_as_number */
+    0,                          /* tp_as_sequence */
+    0,                          /* tp_as_mapping */
+    0,                          /* tp_hash */
+    0,                          /* tp_call */
+    urj_pyr_str,                /* tp_str */
+    0,                          /* tp_getattro */
+    0,                          /* tp_setattro */
+    0,                          /* tp_as_buffer */
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   /* tp_flags */
+    "JTAG register object",     /* tp_doc */
+    0,                          /* tp_traverse */
+    0,                          /* tp_clear */
+    0,                          /* tp_richcompare */
+    0,                          /* tp_weaklistoffset */
+    0,                          /* tp_iter */
+    0,                          /* tp_iternext */
+    urj_pyr_methods,            /* tp_methods */
+    0,                          /* tp_members */
+    0,                          /* tp_getset */
+    0,                          /* tp_base */
+    0,                          /* tp_dict */
+    0,                          /* tp_descr_get */
+    0,                          /* tp_descr_set */
+    0,                          /* tp_dictoffset */
+    0,                          /* tp_init */
+    0,                          /* tp_alloc */
+    0,                          /* tp_new */
+};
+
+
+/* Local Variables: */
+/* mode:c */
+/* comment-column:0 */
+/* c-basic-offset:4 */
+/* space-before-funcall:t */
+/* indent-tabs-mode:nil */
+/* End: */
diff --git a/urjtag/bindings/python/setup.py.in 
b/urjtag/bindings/python/setup.py.in
index 7eef262..2babf7c 100644
--- a/urjtag/bindings/python/setup.py.in
+++ b/urjtag/bindings/python/setup.py.in
@@ -5,7 +5,7 @@ setup(name="urjtag",
       version="1.0",
       description="urJtag Python Bindings",
       ext_modules=[
-        Extension("urjtag", ["chain.c"],
+        Extension("urjtag", ["chain.c", "register.c"],
                   define_macros=[('HAVE_CONFIG_H', None)],
                   include_dirs=['@top_srcdir@', '@top_srcdir@/include'],
                   library_dirs=['@top_builddir@/src/.libs'],
diff --git a/urjtag/doc/urjtag-python.txt b/urjtag/doc/urjtag-python.txt
index ddb9e11..8f8265a 100644
--- a/urjtag/doc/urjtag-python.txt
+++ b/urjtag/doc/urjtag-python.txt
@@ -109,8 +109,7 @@ we must call shift_ir:
 
  urc.shift_ir()
 
-
-For each data register, the chain object tracks two register values.
+For each data register, the chain object tracks two values.
 The "input" register value is sent to the device(s) on the TDI pin,
 and changes the device's status in the DR_UPDATE state.  The "output"
 register value is built up of the values observed on the TDO pin.
@@ -156,12 +155,36 @@ bits) is also possible:
  drval = urc.get_dr_out_string();
  printf("  set_dr_out result: %s %02x\n", drval, r)
 
-
 Remember to call shift_dr() before making use of values read with get_dr_in(),
 and after changing values written with set_dr_out().
 
 
 
+Urjtag register objects
+
+When using multiple data registers, not remembering to call set_instruction
+and shift_ir before doing set_dr and shift_dr can lead to annoying
+bugs.  Avoid this and write cleaner code by obtaining a python object
+corresponding to each data register:
+
+ # part 0, data register FOOREG, using instruction INSTFOO
+ regf = urc.get_register(0, 'FOOREG', 'INSTFOO');
+ # part 1, BARREG, INSTBAR1
+ regb = urc.get_register(1, 'BARREG', 'INSTBAR1');
+
+ regf.set_dr_out(0, 3, 7);
+ regb.set_dr_out(1, 8, 5);
+ regf.shift_dr();
+ regb.shift_dr();
+ regb.shift_dr('INSTBAR2');  // use alternate instruction with BARREG
+
+ v = regb.get_dr_in(15, 11);
+ s = regf.get_dr_in_string();
+
+Calling shift_dr on a register object has the same effect as calling
+chain.part() followed by chain.set_instruction().
+
+
 
 
 Sometimes your chip isn't known to urjtag's database.  You can
@@ -205,7 +228,7 @@ implicit global bus, and only one bus can be active at a 
time.
  urc.detectflash(i)
  val = urc.peek(addr)
  urc.poke(addr,val)
- urj.flashmem(options, filename, noverify=0)
+ urc.flashmem(options, filename, noverify=0)
 
 FUTURE: detectflash, peek, poke, and flashmem will be a methods in a new
 urjtag.bus class, not methods of urjtag.chain.
diff --git a/urjtag/include/urjtag/tap_register.h 
b/urjtag/include/urjtag/tap_register.h
index bb9fdbe..33fc5cb 100644
--- a/urjtag/include/urjtag/tap_register.h
+++ b/urjtag/include/urjtag/tap_register.h
@@ -41,9 +41,11 @@ urj_tap_register_t *urj_tap_register_duplicate (const 
urj_tap_register_t *tr);
 void urj_tap_register_free (urj_tap_register_t *tr);
 urj_tap_register_t *urj_tap_register_fill (urj_tap_register_t *tr, int val);
 int urj_tap_register_set_string (urj_tap_register_t *tr, const char *str);
+int urj_tap_register_set_string_bit_range (urj_tap_register_t *tr, const char 
*str, int msb, int lsb);
 int urj_tap_register_set_value (urj_tap_register_t *tr, uint64_t val);
 int urj_tap_register_set_value_bit_range (urj_tap_register_t *tr, uint64_t 
val, int msb, int lsb);
 const char *urj_tap_register_get_string (const urj_tap_register_t *tr);
+const char *urj_tap_register_get_string_bit_range (const urj_tap_register_t 
*tr, int msb, int lsb);
 uint64_t urj_tap_register_get_value (const urj_tap_register_t *tr);
 uint64_t urj_tap_register_get_value_bit_range (const urj_tap_register_t *tr, 
int msb, int lsb);
 /** @return 0 or 1 on success; -1 on error */
diff --git a/urjtag/src/tap/register.c b/urjtag/src/tap/register.c
index 2d0b108..d8ca1c6 100644
--- a/urjtag/src/tap/register.c
+++ b/urjtag/src/tap/register.c
@@ -191,6 +191,72 @@ urj_tap_register_set_string (urj_tap_register_t *tr, const 
char *str)
 }
 
 int
+urj_tap_register_set_string_bit_range (urj_tap_register_t *tr, const char 
*str, int msb, int lsb)
+{
+    int step = msb >= lsb ? 1 : -1;
+    int len =  msb >= lsb ? msb - lsb + 1 : lsb - msb + 1;
+    int sidx;
+
+    if (!tr)
+    {
+        urj_error_set (URJ_ERROR_INVALID, "tr == NULL");
+        return URJ_STATUS_FAIL;
+    }
+
+    if (msb > tr->len - 1 || lsb > tr->len - 1 || msb < 0 || lsb < 0)
+    {
+        urj_error_set (URJ_ERROR_OUT_OF_BOUNDS,
+                       _("register %d:%d will not fit in %d bits"),
+                       msb, lsb, tr->len);
+        return URJ_STATUS_FAIL;
+    }
+
+    if (strncmp (str, "0x", 2) == 0)
+    {
+        /* Hex values */
+        uint64_t val;
+
+       //printf("in urj_tap_register_set_string_bit_range(%s) hexmode\n", str);
+        if (sscanf (str, "%"PRIX64, &val) != 1)
+        {
+            urj_error_set (URJ_ERROR_SYNTAX,
+                           _("invalid hex string '%s'"),
+                           str);
+            return URJ_STATUS_FAIL;
+        }
+        return urj_tap_register_set_value_bit_range (tr, val, msb, lsb);
+    }
+    else
+    {
+        /* Bit string */
+        int bit;
+
+       //printf("in urj_tap_register_set_string_bit_range(%s, %d, %d) binmode 
len=%d step=%d\n", str, msb, lsb, len, step);
+        if (strspn (str, "01") != strlen (str))
+        {
+            urj_error_set (URJ_ERROR_SYNTAX,
+                           _("bit patterns should be 0s and 1s, not '%s'"),
+                           str);
+            return URJ_STATUS_FAIL;
+        }
+        else if (len != strlen (str))
+        {
+            urj_error_set (URJ_ERROR_OUT_OF_BOUNDS,
+                           _("register subfield length %d mismatch: %zd"),
+                           len, strlen (str));
+            return URJ_STATUS_FAIL;
+        }
+
+        for (sidx = 0, bit = msb; bit*step >= lsb*step; bit -= step, sidx++)
+        {
+            tr->data[bit] = (str[sidx] == '1');
+        }
+
+        return URJ_STATUS_OK;
+    }
+}
+
+int
 urj_tap_register_set_value_bit_range (urj_tap_register_t *tr, uint64_t val, 
int msb, int lsb)
 {
     int bit;
@@ -226,6 +292,34 @@ urj_tap_register_set_value (urj_tap_register_t *tr, 
uint64_t val)
 }
 
 const char *
+urj_tap_register_get_string_bit_range (const urj_tap_register_t *tr, int msb, 
int lsb)
+{
+    int bit;
+    int string_idx;
+    int step = msb >= lsb ? 1 : -1;
+
+    if (!tr)
+    {
+        urj_error_set (URJ_ERROR_INVALID, "tr == NULL");
+        return NULL;
+    }
+
+    if (msb > tr->len - 1 || lsb > tr->len - 1 || msb < 0 || lsb < 0) 
+    {
+        urj_error_set (URJ_ERROR_INVALID, "msb or lsb out of range");
+        return NULL;
+    }
+
+    for (bit = msb, string_idx = 0; bit * step >= lsb * step; bit -= step, 
string_idx++)
+    {
+        tr->string[string_idx] = (tr->data[bit] & 1) ? '1' : '0';
+    }
+    tr->string[string_idx] = '\0';
+
+    return tr->string;
+}
+
+const char *
 urj_tap_register_get_string (const urj_tap_register_t *tr)
 {
     int i;
-- 
1.7.1

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
UrJTAG-development mailing list
UrJTAG-development@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/urjtag-development

Reply via email to