add ls180 cxxsim test
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Thu, 8 Apr 2021 20:55:59 +0000 (21:55 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Thu, 8 Apr 2021 20:55:59 +0000 (21:55 +0100)
ls180_test/.gitignore [new file with mode: 0644]
ls180_test/Makefile [new file with mode: 0644]
ls180_test/README.txt [new file with mode: 0644]
ls180_test/SPBlock_512W64B8W.v [new file with mode: 0644]
ls180_test/cxxscript.y [new file with mode: 0644]
ls180_test/idcode.svf [new file with mode: 0644]
ls180_test/idcode_test2.svf [new file with mode: 0644]
ls180_test/main.cpp [new file with mode: 0644]
ls180_test/openocd.cfg [new file with mode: 0644]
ls180_test/openocd_test.sh [new file with mode: 0755]

diff --git a/ls180_test/.gitignore b/ls180_test/.gitignore
new file mode 100644 (file)
index 0000000..6e4bc45
--- /dev/null
@@ -0,0 +1,5 @@
+add.cpp
+add.v
+tb
+*.o
+.*.sw?
diff --git a/ls180_test/Makefile b/ls180_test/Makefile
new file mode 100644 (file)
index 0000000..b8eed8e
--- /dev/null
@@ -0,0 +1,30 @@
+
+YOSYS                  = yosys
+YOSYS_INCLUDE  = $(shell yosys-config --datdir)/include
+
+all: tb
+       ./tb
+
+tb: main.cpp ls180.cpp
+       clang++ -g -O3 -std=c++14 -I $(YOSYS_INCLUDE) $< -o $@
+
+#../../soc/src/soc/litex/florent/libresoc.v \
+#../../soc/src/soc/litex/florent/ls180.v
+VERILOG_SOURCES := \
+  ./SPBlock_512W64B8W.v \
+  #./libresoc.v \
+  #./ls180.v
+
+ls180.cpp: $(VERILOG_SOURCES)
+       # create dummy memory files
+       yes 0 | head -128 > mem.init
+       yes 0 | head -32 > mem_1.init
+       echo $<
+       $(YOSYS) -p "read_verilog $?; write_cxxrtl $@"
+
+# build verilog from nmigen
+ls180.v: ls180.py
+       python3 ls180.py
+
+clean:
+       \rm -f ls180.cpp tb ls180.v
diff --git a/ls180_test/README.txt b/ls180_test/README.txt
new file mode 100644 (file)
index 0000000..4af047c
--- /dev/null
@@ -0,0 +1,3 @@
+This experiment uses the litex verilog code for LibreSOC and allows
+doing a JTAG cxxrtl openocd "jtagremote" interface
+
diff --git a/ls180_test/SPBlock_512W64B8W.v b/ls180_test/SPBlock_512W64B8W.v
new file mode 100644 (file)
index 0000000..2188fd4
--- /dev/null
@@ -0,0 +1,35 @@
+// SPBlock_512W64B8W simulation mode
+module SPBlock_512W64B8W(
+    input clk,
+    input [8:0] a,
+    input [63:0] d,
+    output [63:0] q,
+    // Width of WE determines the write granularity
+    input [7:0] we
+);
+
+genvar i;
+
+reg [63:0] ram [511:0];
+wire[7:0] d_split [7:0];
+reg [8:0] a_hold;
+
+always @(posedge clk) begin
+    a_hold <= a;
+end
+
+assign q = ram[a_hold];
+
+generate
+    for (i = 0; i < 8; i = i + 1) begin
+        assign d_split[i] = d[((i + 1)*8 - 1):i*8];
+
+        always @(posedge clk) begin
+            if (we[i]) begin
+                ram[a][((i + 1)*8 - 1):i*8] = d_split[i];
+            end
+        end
+    end
+endgenerate
+
+endmodule
diff --git a/ls180_test/cxxscript.y b/ls180_test/cxxscript.y
new file mode 100644 (file)
index 0000000..d185c69
--- /dev/null
@@ -0,0 +1,5 @@
+read_verilog ls180.v libresoc.v SPBlock_512W64B8W.v
+hierarchy -check -top ls180
+proc
+memory
+write_cxxrtl ls180.cpp
diff --git a/ls180_test/idcode.svf b/ls180_test/idcode.svf
new file mode 100644 (file)
index 0000000..994e9c8
--- /dev/null
@@ -0,0 +1,4 @@
+!Loading device with 'idcode' instruction.
+SIR 4 TDI (1);
+SDR 32 TDI (00000000) TDO (000018FF) ;
+
diff --git a/ls180_test/idcode_test2.svf b/ls180_test/idcode_test2.svf
new file mode 100644 (file)
index 0000000..a7545e0
--- /dev/null
@@ -0,0 +1,46 @@
+STATE RESET IDLE;
+TIR 0 ;
+HIR 5 TDI (1f) SMASK (1f) ;
+//HDR 1 TDI (00) SMASK (01) ;
+TDR 0 ;
+//Loading device with 'idcode' instruction.
+SIR 4 TDI (1) SMASK (f) ;
+//SDR 32 TDI (00000000) SMASK (ffffffff) TDO (00000c7f) SMASK (ffffffff) ;
+SDR 32 TDI (00000000) SMASK (ffffffff) TDO (000018ff) MASK (ffffffff) ;
+//
+
+// set to DMI "address"
+SIR 4 TDI (8) SMASK (f) ;
+// set DMI "ctrl" address (0)
+SDR 8 TDI (0) SMASK (ff) ;
+// set to DMI "data read"
+SIR 4 TDI (9) SMASK (f) ;
+// read 64 bit
+SDR 64 TDI (0000000000000000) SMASK (0000000000000000) TDO (0000000000000004) MASK (ffffffffffffffff) ;
+
+// set to DMI "address"
+SIR 4 TDI (8) SMASK (f) ;
+// set DMI "ctrl" address (0)
+SDR 8 TDI (0) SMASK (ff) ;
+// set to DMI "data write-read"
+SIR 4 TDI (a) SMASK (f) ;
+// write-read 64 bit
+SDR 64 TDI (0000000000000002) SMASK (ffffffffffffffff) TDO (0000000000000004) MASK (ffffffffffffffff) ;
+
+// set to DMI "address"
+SIR 4 TDI (8) SMASK (f) ;
+// set DMI "ctrl" address (0)
+SDR 8 TDI (0) SMASK (ff) ;
+// set to DMI "data read"
+SIR 4 TDI (9) SMASK (f) ;
+// read 64 bit
+SDR 64 TDI (0000000000000000) SMASK (0000000000000000) TDO (0000000000000002) MASK (ffffffffffffffff) ;
+
+// set to DMI "address"
+SIR 4 TDI (8) SMASK (f) ;
+// set DMI "MSR" address (3)
+SDR 8 TDI (3) SMASK (ff) ;
+// set to DMI "data read"
+SIR 4 TDI (9) SMASK (f) ;
+// read 64 bit
+SDR 64 TDI (0000000000000000) SMASK (0000000000000000) TDO (00000000deadbeef) MASK (ffffffffffffffff) ;
diff --git a/ls180_test/main.cpp b/ls180_test/main.cpp
new file mode 100644 (file)
index 0000000..c46e4d1
--- /dev/null
@@ -0,0 +1,211 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/fcntl.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <iostream>
+#include <fstream>
+
+#include "ls180.cpp"
+
+#define VCD
+
+#ifdef VCD
+#include <backends/cxxrtl/cxxrtl_vcd.h>
+#endif
+
+using namespace std;
+
+extern "C" {
+
+/* nothing sophisticated: set up a listening socket
+ */
+int setup_socket()
+{
+       int listenfd = 0;
+       struct sockaddr_in serv_addr;
+
+       listenfd = socket(AF_INET, SOCK_STREAM, 0);
+       memset(&serv_addr, '0', sizeof(serv_addr));
+
+       serv_addr.sin_family = AF_INET;
+       serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+       serv_addr.sin_port = htons(44853);
+
+       bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
+       listen(listenfd, 1);
+
+    return listenfd;
+}
+
+/* sees if there is an incoming connection (non-blocking).  if so,
+   accept it and return it
+ */
+int get_connection(int listenfd)
+{
+       int connfd = 0;
+    int flag = 1;
+    int status;
+    fd_set active_fd_set;
+
+    struct   timeval tv;
+
+    tv.tv_sec = 0;
+    tv.tv_usec = 1;
+
+    /* Initialize the set of active sockets. */
+    FD_ZERO (&active_fd_set);
+    FD_SET (listenfd, &active_fd_set);
+
+    /* Block until input arrives on one or more active sockets. */
+    status = select (FD_SETSIZE, &active_fd_set, NULL, NULL, &tv);
+    switch (status)
+    {
+        case -1:
+            printf("Error listening on socket\n");
+            exit(status); // error
+            return -1;
+        case 0:
+            return -1; // timeout (nothing read)
+        default:
+            // return accepted socket
+            connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
+            setsockopt(connfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag,
+                       sizeof(int));
+            return connfd;
+    }
+}
+
+/* reads from a socket if it is ready (a single byte) and returns 1 if success
+ */
+int read_handler(int fdread, char *buffer)
+{
+    ssize_t read_len;
+    fd_set read_fds;
+    FD_ZERO(&read_fds);
+    FD_SET(fdread, &read_fds);
+    int status;
+    struct   timeval tv;
+
+    tv.tv_sec = 0;
+    tv.tv_usec = 1;
+
+    status = select(fdread+1, &read_fds, NULL, NULL, &tv);
+    switch (status)
+    {
+        case -1:
+            printf("Error reading on socket\n");
+            exit(status); // error
+            return 0;
+        case 0:
+            return 0; // timeout (nothing read)
+        default:
+            status = read(fdread, buffer, 1);
+            if (status == -1) {
+                printf("Error reading on socket\n");
+                close(fdread);
+            }
+            return status;
+    }
+}
+
+} // extern "C"
+
+/* main function which polls the socket and talks openocd jtagremote protocol.
+   dead simple: incoming number 0-7 sets TCK, TMS and TDK.  request "R"
+   indicates that receiver wants to know the status of TDO.
+   "Q" means "quit socket".
+*/
+int read_openocd_jtagremote(cxxrtl_design::p_ls180 &top, int sock)
+{
+    char c;
+    if (read_handler(sock, &c) != 1) {
+        return sock;
+    }
+    printf ("read %c\n", c);
+    if ((c >= '0') && (c <= '7'))
+    {
+        top.p_jtag__tck.set<bool>(((c - '0') >> 2) & 1);
+        top.p_jtag__tms.set<bool>(((c - '0') >> 1) & 1);
+        top.p_jtag__tdi.set<bool>((c - '0')  & 1);
+    }
+    if (c == 'R')
+    {
+        uint8_t val = top.p_jtag__tdo.get<uint8_t>() + '0';
+        if(-1 == write(sock, &val, 1))
+        {
+            printf("Error writing on socket\n");
+            close(sock);
+            sock = -1;
+        }
+    }
+    if (c == 'Q') {
+        printf("disconnect request\n");
+            close(sock);
+        sock = -1;
+    }
+    return sock;
+}
+
+int main()
+{
+    cxxrtl_design::p_ls180 top;
+    int steps = 0;
+
+#ifdef VCD
+    // Load the debug items of the top down the whole design hierarchy
+    cxxrtl::debug_items all_debug_items;
+    top.debug_info(all_debug_items);
+
+    // set up vcdwriter with 1ns resu
+    cxxrtl::vcd_writer vcd;
+    vcd.timescale(1, "us");
+#endif
+
+    int listenfd = setup_socket();
+    int sock = -1;
+
+#ifdef VCD
+    //vcd.add_without_memories(all_debug_items);
+    vcd.add(all_debug_items);
+    std::ofstream waves("waves.vcd");
+#endif
+
+    top.step();
+#ifdef VCD
+    vcd.sample(0);
+#endif
+    while (true) {
+
+        top.p_sys__clk.set<bool>(false);
+        top.step();
+#ifdef VCD
+        vcd.sample(steps*2 + 0);
+#endif
+        top.p_sys__clk.set<bool>(true);
+        top.step();
+#ifdef VCD
+        vcd.sample(steps*2 + 1);
+#endif
+        steps++;
+
+        // if no current connection see if there is one
+        if (sock == -1) {
+            sock = get_connection(listenfd);
+        }
+        /* read and process incoming jtag. sock set to -1 if disconnected */
+        sock = read_openocd_jtagremote(top, sock);
+
+        waves << vcd.buffer;
+        vcd.buffer.clear();
+    }
+}
+
diff --git a/ls180_test/openocd.cfg b/ls180_test/openocd.cfg
new file mode 100644 (file)
index 0000000..a3c7084
--- /dev/null
@@ -0,0 +1,15 @@
+
+interface remote_bitbang
+remote_bitbang_port 44853
+remote_bitbang_host localhost
+
+# this should be irlen=4
+jtag newtap libresoc tap -irlen 4 -irmask 0xf -ircapture 0xf -expected-id 0x000018ff
+
+#set _TARGETNAME libresoc.tap
+#target create $_TARGETNAME.0 ppc64 -chain-position $_TARGETNAME -rtos hwthread
+
+# Configure work area in on-chip SRAM
+#$_TARGETNAME.0 configure -work-area-phys 0x80000000 \
+#               -work-area-size 1000 -work-area-backup 0
+
diff --git a/ls180_test/openocd_test.sh b/ls180_test/openocd_test.sh
new file mode 100755 (executable)
index 0000000..dcad497
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+# run make followed by ./tb then run this script.
+
+openocd -f openocd.cfg -c init \
+                                   -c 'svf idcode.svf' \
+                                  -c shutdown