Added jtagutils and openpower state dependency for borrowed jtag test cases, see...
authorAndrey Miroshnikov <andrey@technepisteme.xyz>
Thu, 18 Nov 2021 22:53:25 +0000 (22:53 +0000)
committerAndrey Miroshnikov <andrey@technepisteme.xyz>
Thu, 18 Nov 2021 22:53:25 +0000 (22:53 +0000)
src/spec/dmi.py
src/spec/jtagutils.py [new file with mode: 0644]
src/spec/state.py [new file with mode: 0644]
src/spec/svstate.py [new file with mode: 0644]

index 4d897699737672ee9b58ebd8e2f585eed4f52803..52a00c4a419eea71b478bed245661df2e75a25cc 100644 (file)
@@ -10,7 +10,7 @@ from nmigen import Elaboratable, Module, Signal, Cat, Const, Record, Array, Mux
 from nmutil.iocontrol import RecordObject
 from nmigen.utils import log2_int
 from nmigen.cli import rtlil
-from soc.config.state import CoreState
+from state import CoreState
 
 
 # DMI register addresses
diff --git a/src/spec/jtagutils.py b/src/spec/jtagutils.py
new file mode 100644 (file)
index 0000000..a642bd1
--- /dev/null
@@ -0,0 +1,223 @@
+#The server code
+import socket
+from socket import close, AF_INET, SOCK_STREAM
+import sys
+import select
+import time
+
+
+def client_sync(dut):
+    tck = yield dut.cbus.tck
+    tms = yield dut.cbus.tms
+    tdi = yield dut.cbus.tdi
+    dut.c.jtagremote_client_send((tck, tms, tdi))
+    #print ("about to client recv")
+    while True:
+        tdo = dut.c.jtagremote_client_recv(timeout=0)
+        if tdo is not None:
+            break
+        yield
+    yield dut.cbus.tdo.eq(tdo)
+
+
+def tms_state_set(dut, bits):
+    for bit in bits:
+        yield dut.cbus.tms.eq(bit)
+        yield from client_sync(dut)
+        yield dut.cbus.tck.eq(1)
+        yield from client_sync(dut)
+        yield
+        yield dut.cbus.tck.eq(0)
+        yield from client_sync(dut)
+        yield
+        yield from client_sync(dut)
+    yield dut.cbus.tms.eq(0)
+    yield from client_sync(dut)
+
+
+def tms_data_getset(dut, tms, d_len, d_in=0):
+    res = 0
+    yield dut.cbus.tms.eq(tms)
+    for i in range(d_len):
+        tdi = 1 if (d_in & (1<<i)) else 0
+        yield dut.cbus.tck.eq(1)
+        yield from client_sync(dut)
+        res |= (1<<i) if (yield dut.cbus.tdo) else 0
+        yield
+        yield from client_sync(dut)
+        yield dut.cbus.tdi.eq(tdi)
+        yield dut.cbus.tck.eq(0)
+        yield from client_sync(dut)
+        yield
+        yield from client_sync(dut)
+    yield dut.cbus.tms.eq(0)
+    yield from client_sync(dut)
+
+    return res
+
+
+def jtag_set_reset(dut):
+    yield from tms_state_set(dut, [1, 1, 1, 1, 1])
+
+def jtag_set_shift_dr(dut):
+    yield from tms_state_set(dut, [1, 0, 0])
+
+def jtag_set_shift_ir(dut):
+    yield from tms_state_set(dut, [1, 1, 0])
+
+def jtag_set_run(dut):
+    yield from tms_state_set(dut, [0])
+
+def jtag_set_idle(dut):
+    yield from tms_state_set(dut, [1, 1, 0])
+
+
+def jtag_set_ir(dut, addr):
+    yield from jtag_set_run(dut)
+    yield from jtag_set_shift_ir(dut)
+    result = yield from tms_data_getset(dut, 0, dut._ir_width, addr)
+    yield from jtag_set_idle(dut)
+    return result
+
+
+def jtag_set_get_dr(dut, d_len, d_in=0):
+    yield from jtag_set_shift_dr(dut)
+    result = yield from tms_data_getset(dut, 0, d_len, d_in)
+    yield from jtag_set_idle(dut)
+    return result
+
+def jtag_read_write_reg(dut, addr, d_len, d_in=0):
+    yield from jtag_set_ir(dut, addr)
+    return (yield from jtag_set_get_dr(dut, d_len, d_in))
+
+
+def jtag_srv(dut):
+    while not dut.stop:
+        # loop and receive data from client
+        tdo = yield dut.bus.tdo
+        #print ("server tdo data", tdo)
+        data = dut.s.jtagremote_server_recv(tdo)
+        #print ("server recv data", data)
+        if not data:
+            yield
+            continue
+        tck, tms, tdi = data
+        yield dut.bus.tck.eq(tck)
+        yield dut.bus.tms.eq(tms)
+        yield dut.bus.tdi.eq(tdi)
+        yield
+    print ("jtag srv stopping")
+
+
+def get_data(s, length=1024, timeout=None):
+    r, w, e = select.select( [s], [], [], timeout)
+
+    for sock in r:
+        #incoming message from remote server
+        if sock == s:
+            return sock.recv(length)
+    return None
+
+class JTAGServer:
+    def __init__(self, debug=False):
+        self.debug = debug
+        HOST = ''
+        PORT = 44853
+        s = socket.socket(AF_INET, SOCK_STREAM)
+        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        s.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
+        s.bind((HOST, PORT))
+        s.listen(1) #only needs to receive one connection (the client)
+        self.s = s
+        self.conn = None
+
+    def close(self):
+        self.s.close()
+        if self.conn:
+            self.conn.close()
+
+    def get_connection(self, timeout=0):
+        r, w, e = select.select( [self.s], [], [], timeout)
+        for sock in r:
+            #incoming message from remote server
+            if sock == self.s:
+                conn, addr = self.s.accept() #accepts the connection
+                if self.debug:
+                    print("Connected by: ", addr) #prints the connection
+                conn.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
+                self.conn = conn
+                return conn
+        return None
+
+    def get_data(self, length=1024, timeout=None):
+        return get_data(self.conn, length, timeout)
+
+    def send(self, data):
+        return self.conn.sendall(data)
+
+    def jtagremote_server_recv(self, tdo):
+        data = self.get_data(1, 0) # read 1 byte, non-blocking
+        if data is None:
+            return None # no data read
+        data = bytes.decode(data)
+        if self.debug:
+            print ("jtagremote_server_recv", data)
+        # request to read TDO
+        if data == 'R':
+            self.send(str.encode(chr(ord('0') + tdo)))
+            return [] # no data
+        # decode tck, tms, tdi
+        data = ord(data) - ord('0')
+        # encode tck, tms and tdi as number from 0-7
+        tdi = 1 if (data & 1) else 0
+        tms = 1 if (data & 2) else 0
+        tck = 1 if (data & 4) else 0
+
+        return (tck, tms, tdi)
+
+
+
+class JTAGClient:
+    def __init__(self, debug=False):
+        self.debug = debug
+        HOST = 'localhost'
+        PORT = 44853
+        s = socket.socket(AF_INET, SOCK_STREAM)
+        s.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
+        s.connect((HOST, PORT))
+        self.s = s
+
+    def close(self):
+        self.s.close()
+
+    def get_data(self, length=1024, timeout=None):
+        return get_data(self.s, length, timeout)
+
+    def send(self, data):
+        return self.s.sendall(data)
+
+    def jtagremote_client_send(self, to_send):
+        # encode tck, tms and tdi as number from 0-7
+        tck, tms, tdi = to_send
+        data = 0
+        if tdi: data |= 1
+        if tms: data |= 2
+        if tck: data |= 4
+        data = chr(ord('0') + data)
+        self.send(str.encode(data))
+        if self.debug:
+            print ("jtagremote_client_send", data)
+        # now read tdo
+        self.send(str.encode('R'))
+
+
+    def jtagremote_client_recv(self, timeout=None):
+        data = self.get_data(1, timeout) # read 1 byte, blocking
+        if data is None:
+            return None
+        if self.debug:
+            print ("client recv", data)
+        data = bytes.decode(data)
+        return ord(data) - ord('0') # subtract ASCII for "0" to give 0 or 1
+
+
diff --git a/src/spec/state.py b/src/spec/state.py
new file mode 100644 (file)
index 0000000..8433fd0
--- /dev/null
@@ -0,0 +1,20 @@
+from nmutil.iocontrol import RecordObject
+from nmigen import Signal
+from svstate import SVSTATERec
+
+
+class CoreState(RecordObject):
+    """contains "Core State Information" which says exactly where things are
+
+    example: eint says to PowerDecoder that it should fire an exception
+    rather than let the current decoded instruction proceed.  likewise
+    if dec goes negative.  MSR contains LE/BE and Priv state.  PC contains
+    the Program Counter, and SVSTATE is the Sub-Program-Counter.
+    """
+    def __init__(self, name):
+        super().__init__(name=name)
+        self.pc = Signal(64)      # Program Counter (CIA, NIA)
+        self.msr = Signal(64)     # Machine Status Register (MSR)
+        self.eint = Signal()      # External Interrupt
+        self.dec = Signal(64)     # DEC SPR (again, for interrupt generation)
+        self.svstate = SVSTATERec(name) # Simple-V SVSTATE
diff --git a/src/spec/svstate.py b/src/spec/svstate.py
new file mode 100644 (file)
index 0000000..281c8aa
--- /dev/null
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: LGPLv3+
+# Copyright (C) 2021 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+# Funded by NLnet http://nlnet.nl
+"""SVSATE SPR Record.  actually a peer of PC (CIA/NIA) and MSR
+
+https://libre-soc.org/openpower/sv/sprs/
+
+| Field | Name     | Description           |
+| ----- | -------- | --------------------- |
+| 0:6   | maxvl    | Max Vector Length     |
+| 7:13  |    vl    | Vector Length         |
+| 14:20 | srcstep  | for srcstep = 0..VL-1 |
+| 21:27 | dststep  | for dststep = 0..VL-1 |
+| 28:29 | subvl    | Sub-vector length     |
+| 30:31 | svstep   | for svstep = 0..SUBVL-1  |
+| 32:33 | mi0      | REMAP RA SVSHAPE0-3    |
+| 34:35 | mi1      | REMAP RB SVSHAPE0-3    |
+| 36:37 | mi2      | REMAP RC SVSHAPE0-3    |
+| 38:39 | mo0      | REMAP RT SVSHAPE0-3    |
+| 40:41 | mo1      | REMAP EA SVSHAPE0-3    |
+| 42:46 | SVme     | REMAP enable (RA-RT)  |
+| 47:61 | rsvd     | reserved              |
+| 62    | RMpst    | REMAP persistence     |
+| 63    | vfirst   | Vertical First mode   |
+"""
+
+from nmigen import Signal, Record
+
+
+# In nMigen, Record order is from LSB to MSB
+# but Power ISA specs are all MSB to LSB (MSB0).
+class SVSTATERec(Record):
+    layout = [("vfirst", 1),
+            ("RMpst", 1),
+            ("rsvd", 15),
+            ("SVme", 5),
+            ("mo1", 2),
+            ("mo0", 2),
+            ("mi2", 2),
+            ("mi1", 2),
+            ("mi0", 2),
+            ("svstep", 2),
+            ("subvl", 2),
+            ("dststep", 7),
+            ("srcstep", 7),
+            ("vl", 7),
+            ("maxvl", 7),
+        ]
+
+    def __init__(self, name=None):
+        super().__init__(name=name, layout=SVSTATERec.layout)