Added SVF_Executor class that allows to execute a SVF file through a JTAG_Master...
authorStaf Verhaegen <staf@stafverhaegen.be>
Sat, 14 Apr 2018 09:28:44 +0000 (11:28 +0200)
committerStaf Verhaegen <staf@stafverhaegen.be>
Sat, 14 Apr 2018 09:28:44 +0000 (11:28 +0200)
Currently only limited implementation only enough to run demos in simulation
on the Retro_uC.

sim/cocotb/c4m_jtag.py
sim/cocotb/c4m_jtag_svfcocotb.py [new file with mode: 0755]

index 529e66bc589a99e8c70b6343cdafc22463a2dcbf..bdac25ca5c5f17f3e6bc750744e95ded23849ffc 100644 (file)
@@ -3,6 +3,9 @@ from cocotb.triggers import Timer
 from cocotb.utils import get_sim_steps
 from cocotb.binary import BinaryValue
 
+class JTAGException(Exception):
+    pass
+
 class JTAG_Clock(object):
     """
     Class for the JTAG clock, run cycle by cycle
diff --git a/sim/cocotb/c4m_jtag_svfcocotb.py b/sim/cocotb/c4m_jtag_svfcocotb.py
new file mode 100755 (executable)
index 0000000..177b7a1
--- /dev/null
@@ -0,0 +1,226 @@
+import c4m_jtag_svfgrammar
+import cocotb
+from cocotb.binary import BinaryValue
+from functools import singledispatch
+
+def decodescanspec(node):
+    length = int(str(node[2]))
+    fstr = "{:0"+str(node[2])+"b}"
+
+    g_tdi = node[4]
+    g_tdo = node[5]
+    g_mask = node[6]
+    g_smask = node[7]
+
+    if g_tdi is None:
+        tdi = None
+    else:
+        tdi = BinaryValue(fstr.format(int(str(g_tdi[2]),16)), length)
+
+    if g_tdo is None:
+        tdo = None
+    else:
+        tdo = BinaryValue(fstr.format(int(str(g_tdo[3]),16)), length)
+
+    if g_mask is None:
+        mask = None
+    else:
+        mask = BinaryValue(fstr.format(int(str(g_mask[3]),16)), length)
+
+    if g_smask is None:
+        smask = None
+    else:
+        smask = BinaryValue(fstr.format(int(str(g_smask[3]),16)), length)
+
+    return (length, tdi, tdo, mask, smask)
+
+
+class SVF_Executor(object):
+    @cocotb.coroutine
+    def execute(self, node):
+        """This is the generic method"""
+        self._p("generic")
+        if False: # Make coroutine work
+            yield PythonTrigger()
+
+    @cocotb.coroutine
+    def _execute_NOP(self, node):
+        if False: # Make coroutine work
+            yield PythonTrigger()
+
+    @cocotb.coroutine
+    def _execute_EndDR(self, node):
+        self._p("EndDR ignored")
+        if False: # Make coroutine work
+            yield PythonTrigger()
+
+    @cocotb.coroutine
+    def _execute_EndIR(self, node):
+        self._p("EndIR ignored")
+        if False: # Make coroutine work
+            yield PythonTrigger()
+
+    @cocotb.coroutine
+    def _execute_Frequency(self, node):
+        self._p("Frequency ignored")
+        if False: # Make coroutine work
+            yield PythonTrigger()
+
+    @cocotb.coroutine
+    def _execute_HDR(self, node):
+        self._p("HDR ignored")
+        if False: # Make coroutine work
+            yield PythonTrigger()
+
+    @cocotb.coroutine
+    def _execute_HIR(self, node):
+        self._p("HIR ignored")
+        if False: # Make coroutine work
+            yield PythonTrigger()
+
+    @cocotb.coroutine
+    def _execute_SDR(self, node):
+        self._p("Executing SDR")
+        (length, tdi, tdo, mask, smask) = decodescanspec(node)
+
+        samelength = length == self._d_length
+        self._d_length = length
+
+        if tdi is None:
+            if not samelength:
+                raise(JTAGException("TDI needs to be specified when length of data changes"))
+        else:
+            self._d_tdi = tdi
+
+        if mask is not None:
+            self._d_mask = mask
+        elif not samelength:
+            self._d_mask = None
+
+        if smask is not None:
+            self._d_smask = smask
+        elif not samelength:
+            self._d_smask = None
+
+        yield self.master.shift_data(self._d_tdi)
+        if tdo is not None:
+            if self._d_mask is not None:
+                raise(JTAGException("MASK not supported for SDR"))
+            assert(self.result == tdo)
+
+    @cocotb.coroutine
+    def _execute_SIR(self, node):
+        (length, tdi, tdo, mask, smask) = decodescanspec(node)
+
+        samelength = length == self._i_length
+        self._i_length = length
+
+        if tdi is None:
+            if not samelength:
+                raise(JTAGException("TDI needs to be specified when length of data changes"))
+        else:
+            self._i_tdi = tdi
+
+        if mask is not None:
+            self._i_mask = mask
+        elif not samelength:
+            self._i_mask = None
+
+        if smask is not None:
+            self._i_smask = smask
+        elif not samelength:
+            self._i_smask = None
+
+        self._p("Executing SIR ({})".format(self._i_tdi.integer))
+
+        yield self.master.load_ir(self._i_tdi)
+        if tdo is not None:
+            if self._i_mask is not None:
+                raise(JTAGException("MASK not supported for SIR"))
+            assert(self.result == tdo)
+        
+
+    @cocotb.coroutine
+    def _execute_State(self, node):
+        self._p("State")
+        if False: # Make coroutine work
+            yield PythonTrigger()
+
+    @cocotb.coroutine
+    def _execute_TDR(self, node):
+        self._p("TDR")
+        if False: # Make coroutine work
+            yield PythonTrigger()
+
+    @cocotb.coroutine
+    def _execute_TIR(self, node):
+        self._p("TIR")
+        if False: # Make coroutine work
+            yield PythonTrigger()
+
+    @cocotb.coroutine
+    def _execute_Trst(self, node):
+        self._p("TRST ignored")
+        if False: # Make coroutine work
+            yield PythonTrigger()
+
+    @cocotb.coroutine
+    def _execute_Runtest(self, node):
+        if node[1] is not None:
+            raise(JTAGException("State specification for RUNTEST not supported"))
+        # TODO: cycle the right number of clocks or wait the right time
+        yield(self.master.change_state([0]))
+
+    @cocotb.coroutine
+    def _execute_SVFFile(self, node):
+        self._p("Executing SVFFile")
+        for statement in node.elements[0]:
+            yield self.execute(statement)
+
+    def __init__(self, master):
+        # master is assumed to be a JTAG_Master class
+        # it needs to support methods load_ir() and shift_data()
+        self.master = master
+
+        # Due to bug in Grammar definition all possible classes have to have
+        # a dispatch entry otherwise an error will be raised.
+        self.execute = singledispatch(self.execute)
+        self.execute.register(c4m_jtag_svfgrammar.EmptyLine, self._execute_NOP)
+        self.execute.register(c4m_jtag_svfgrammar.Comment, self._execute_NOP)
+        self.execute.register(c4m_jtag_svfgrammar.EndDR, self._execute_EndDR)
+        self.execute.register(c4m_jtag_svfgrammar.EndIR, self._execute_EndIR)
+        self.execute.register(c4m_jtag_svfgrammar.Frequency, self._execute_Frequency)
+        self.execute.register(c4m_jtag_svfgrammar.HDR, self._execute_HDR)
+        self.execute.register(c4m_jtag_svfgrammar.HIR, self._execute_HIR)
+        self.execute.register(c4m_jtag_svfgrammar.Runtest, self._execute_Runtest)
+        self.execute.register(c4m_jtag_svfgrammar.SDR, self._execute_SDR)
+        self.execute.register(c4m_jtag_svfgrammar.SIR, self._execute_SIR)
+        self.execute.register(c4m_jtag_svfgrammar.State, self._execute_State)
+        self.execute.register(c4m_jtag_svfgrammar.TDR, self._execute_TDR)
+        self.execute.register(c4m_jtag_svfgrammar.TIR, self._execute_TIR)
+        self.execute.register(c4m_jtag_svfgrammar.Trst, self._execute_Trst)
+        self.execute.register(c4m_jtag_svfgrammar.SVFFile, self._execute_SVFFile)
+
+        # Store the head and tail for the scan
+        self._d_tdi = self._d_tdi_h = self._d_tdi_t = None
+        self._d_tdo_h = self._d_tdo_t = None
+        self._i_tdi = self._i_tdi_h = self._i_tdi_t = None
+        self._i_tdo_h = self._i_tdo_t = None
+
+        # Remember the masks; smasks are ignored and bits always considered as care, e.g right
+        # value applied
+        self._d_length = self._d_length_h = self._d_length_t = None
+        self._d_mask = self._d_mask_h = self._d_mask_t = None
+        self._d_smask = self._d_smask_h = self._d_smask_t = None
+        self._i_length = self._i_length_h = self._i_length_t = None
+        self._i_mask = self._i_mask_h = self._i_mask_t = None
+        self._i_smask = self._i_smask_h = self._i_smask_t = None
+
+    @cocotb.coroutine
+    def run(self, cmds, p=print):
+        self._p = p
+        if isinstance(cmds, c4m_jtag_svfgrammar.SVFFile):
+            yield self.execute(cmds)
+        else:
+            p = c4m_jtag_svfgrammar.SVFFile.parser()
+            yield self.execute(p.parse_string(cmds))