Repository: zeroasiccorp/umi (language: python)

Issue:
PR for coverage now
Will pick up integration with codecov later.


Discussion / hints:

Fix patch:
diff --git a/umi/rtl/umi_endpoint.v b/umi/rtl/umi_endpoint.v
index 23ee476..79e45a8 100644
--- a/umi/rtl/umi_endpoint.v
+++ b/umi/rtl/umi_endpoint.v
@@ -4,7 +4,9 @@
  * License:
  *
  * Documentation:
- *
+ * The endpoint is meant to allow communication with a register like interface
+ * over UMI. Hence, it can only receive UMI requests that require a single
+ * response beat i.e. (udev_req_cmd.len + 1)*(1 << udev_req_cmd.size) <= DW/8.
  *
  ******************************************************************************/
 module umi_endpoint
@@ -34,9 +36,11 @@ module umi_endpoint
     output [AW-1:0] loc_addr,   // memory address
     output          loc_write,  // write enable
     output          loc_read,   // read request
+    output          loc_atomic, // atomic request
     output [7:0]    loc_opcode, // opcode
     output [2:0]    loc_size,   // size
     output [7:0]    loc_len,    // len
+    output [7:0]    loc_atype, // atomic type
     output [DW-1:0] loc_wrdata, // data to write
     input [DW-1:0]  loc_rddata, // data response
     input           loc_ready   // device is ready
@@ -74,7 +78,6 @@ module umi_endpoint
    wire                 cmd_write;
    wire                 cmd_write_posted;
    wire                 cmd_write_resp;
-   wire [7:0]           loc_atype;
    wire                 loc_eof;
    wire                 loc_eom;
    wire [1:0]           loc_err;
@@ -178,9 +181,10 @@ module umi_endpoint
               .command          (udev_req_cmd[CW-1:0])); // Templated
 
    // TODO - implement atomic
-   assign loc_read  = ready_gated & cmd_read & udev_req_valid & ~request_stall;
-   assign loc_write = ready_gated & (cmd_write | cmd_write_posted) & udev_req_valid & ~request_stall;
-   assign loc_resp  = ready_gated & (cmd_read | cmd_write) & udev_req_valid & loc_ready;
+   assign loc_read   = ready_gated & cmd_read & udev_req_valid & ~request_stall;
+   assign loc_write  = ready_gated & (cmd_write | cmd_write_posted) & udev_req_valid & ~request_stall;
+   assign loc_atomic = ready_gated & cmd_atomic & udev_req_valid & ~request_stall;
+   assign loc_resp   = ready_gated & (cmd_read | cmd_write | cmd_atomic) & udev_req_valid & loc_ready & ~request_stall;
 
    //############################
    //# Outgoing Transaction
@@ -200,7 +204,7 @@ module umi_endpoint
    // Amir - outputs should be sampled when the read command is accepted
    // Read data only arrives one cycle after the read is accepted
 
-   assign cmd_opcode[4:0] = cmd_read ? UMI_RESP_READ : UMI_RESP_WRITE;
+   assign cmd_opcode[4:0] = (cmd_read | cmd_atomic) ? UMI_RESP_READ : UMI_RESP_WRITE;
 
    /* umi_pack AUTO_TEMPLATE(
     .cmd_\(.*\) (loc_\1[]),
@@ -236,7 +240,7 @@ module umi_endpoint
      if (!nreset)
        loc_resp_vld <= 1'b0;
      else
-       loc_resp_vld <= loc_resp & loc_ready & ~request_stall;
+       loc_resp_vld <= loc_resp;
 
    always @ (posedge clk or negedge nreset)
      if (!nreset)
@@ -245,7 +249,7 @@ module umi_endpoint
           loc_dstaddr_out[AW-1:0] <= {AW{1'b0}};
           loc_srcaddr_out[AW-1:0] <= {AW{1'b0}};
        end
-     else if (loc_resp & loc_ready & ~request_stall)
+     else if (loc_resp)
        begin
           loc_cmd_out[CW-1:0]     <= packet_cmd[CW-1:0];
           loc_dstaddr_out[AW-1:0] <= udev_req_srcaddr[AW-1:0];
diff --git a/umi/rtl/umi_mem_agent.v b/umi/rtl/umi_mem_agent.v
index d598c7e..8b2a643 100644
--- a/umi/rtl/umi_mem_agent.v
+++ b/umi/rtl/umi_mem_agent.v
@@ -40,6 +40,53 @@ module umi_mem_agent
     ///*AUTOOUTPUT*/
     );
 
+   //##################################################################
+   //# UMI FIFO FLEX (acting as a transaction splitter)
+   //##################################################################
+
+    wire            ff2ep_req_valid;
+    wire [CW-1:0]   ff2ep_req_cmd;
+    wire [AW-1:0]   ff2ep_req_dstaddr;
+    wire [AW-1:0]   ff2ep_req_srcaddr;
+    wire [DW-1:0]   ff2ep_req_data;
+    wire            ff2ep_req_ready;
+
+    umi_fifo_flex #(
+        .ASYNC  (0),
+        .SPLIT  (1),
+        .DEPTH  (0),
+        .CW     (CW),
+        .AW     (AW),
+        .IDW    (DW),
+        .ODW    (DW))
+    umi_fifo_flex_ (
+        .bypass             (1'b1),
+        .chaosmode          (1'b0),
+        .fifo_full          (),
+        .fifo_empty         (),
+
+        .umi_in_clk         (clk),
+        .umi_in_nreset      (nreset),
+        .umi_in_valid       (udev_req_valid),
+        .umi_in_cmd         (udev_req_cmd),
+        .umi_in_dstaddr     (udev_req_dstaddr),
+        .umi_in_srcaddr     (udev_req_srcaddr),
+        .umi_in_data        (udev_req_data),
+        .umi_in_ready       (udev_req_ready),
+
+        .umi_out_clk        (clk),
+        .umi_out_nreset     (nreset),
+        .umi_out_valid      (ff2ep_req_valid),
+        .umi_out_cmd        (ff2ep_req_cmd),
+        .umi_out_dstaddr    (ff2ep_req_dstaddr),
+        .umi_out_srcaddr    (ff2ep_req_srcaddr),
+        .umi_out_data       (ff2ep_req_data),
+        .umi_out_ready      (ff2ep_req_ready),
+
+        .vdd                (),
+        .vss                ()
+    );
+
    /*AUTOREG*/
 
    /*AUTOWIRE*/
@@ -52,18 +99,20 @@ module umi_mem_agent
    wire [DW-1:0]        loc_wrdata;
    wire                 loc_write;
    // End of automatics
-   reg [AW-1:0]         loc_rdaddr;
    wire [11:0]          loc_lenp1;
    wire [11:0]          loc_bytes;
 
+   wire                 loc_atomic;
+   wire [7:0]           loc_atype;
    wire [DW-1:0]        loc_rddata;
-   wire [DW-1:0]        mem_rddata;
+   wire                 loc_ready;
 
    //##################################################################
    //# UMI ENDPOINT (Pipelined Request/Response)
    //##################################################################
 
    /*umi_endpoint AUTO_TEMPLATE (
+    .udev_req_\(.*\)      (ff2ep_req_\1[]),
     );
     */
 
@@ -71,10 +120,10 @@ module umi_mem_agent
                   .AW(AW),
                   .DW(DW),
                   .REG(0))
-   umi_endpoint(.loc_ready      (1'b1),
+   umi_endpoint(.loc_ready      (loc_ready),
                 /*AUTOINST*/
                 // Outputs
-                .udev_req_ready (udev_req_ready),
+                .udev_req_ready (ff2ep_req_ready),
                 .udev_resp_valid(udev_resp_valid),
                 .udev_resp_cmd  (udev_resp_cmd[CW-1:0]),
                 .udev_resp_dstaddr(udev_resp_dstaddr[AW-1:0]),
@@ -83,22 +132,26 @@ module umi_mem_agent
                 .loc_addr       (loc_addr[AW-1:0]),
                 .loc_write      (loc_write),
                 .loc_read       (loc_read),
+                .loc_atomic     (loc_atomic),
                 .loc_opcode     (loc_opcode[7:0]),
                 .loc_size       (loc_size[2:0]),
                 .loc_len        (loc_len[7:0]),
+                .loc_atype      (loc_atype[7:0]),
                 .loc_wrdata     (loc_wrdata[DW-1:0]),
                 // Inputs
                 .nreset         (nreset),
                 .clk            (clk),
-                .udev_req_valid (udev_req_valid),
-                .udev_req_cmd   (udev_req_cmd[CW-1:0]),
-                .udev_req_dstaddr(udev_req_dstaddr[AW-1:0]),
-                .udev_req_srcaddr(udev_req_srcaddr[AW-1:0]),
-                .udev_req_data  (udev_req_data[DW-1:0]),
+                .udev_req_valid (ff2ep_req_valid),
+                .udev_req_cmd   (ff2ep_req_cmd[CW-1:0]),
+                .udev_req_dstaddr(ff2ep_req_dstaddr[AW-1:0]),
+                .udev_req_srcaddr(ff2ep_req_srcaddr[AW-1:0]),
+                .udev_req_data  (ff2ep_req_data[DW-1:0]),
                 .udev_resp_ready(udev_resp_ready),
                 .loc_rddata     (loc_rddata[DW-1:0]));
 
    // Add support for partial writes - for now only 8B aligned addr
+   // These are 12 bits wide - it works because the max data a SUMI
+   // packet can transfer is 1024 bits/128 bytes.
    assign loc_lenp1[11:0] = {4'h0,loc_len[7:0]} + 1'b1;
    assign loc_bytes[11:0] = loc_lenp1[11:0] << loc_size[2:0];
 
@@ -114,10 +167,94 @@ module umi_mem_agent
           wmask[i*8+:8] = 8'h00;
      end
 
+   reg  [AW-1:0]    loc_addr_r;
+   reg              loc_write_r;
+   reg              loc_read_r;
+   reg              loc_atomic_r;
+   reg  [7:0]       loc_atype_r;
+   reg  [DW-1:0]    loc_wrdata_r;
+   reg  [DW-1:0]    wmask_r;
+
+   reg  [DW-1:0]    loc_wrdata_atomic;
+
+
+   wire [DW-1:0]    mem_rddata;
+   wire             mem_we;
+   wire [DW-1:0]    mem_wmask;
+   wire [AW-1:0]    mem_addr;
+   wire [DW-1:0]    mem_wrdata;
+
+   wire [DW-1:0]    mem_rddata_atomic;
+   reg  [31:0]      postatomic_shift;
+
+   // Deassert ready to get additional cycle to write data
+   assign loc_ready = ~loc_atomic_r;
+
+   always @(posedge clk or negedge nreset) begin
+     if (~nreset) begin
+       loc_addr_r       <= 'b0;
+       loc_write_r      <= 'b0;
+       loc_read_r       <= 'b0;
+       loc_atomic_r     <= 'b0;
+       loc_atype_r      <= 'b0;
+       loc_wrdata_r     <= 'b0;
+       wmask_r          <= 'b0;
+       postatomic_shift <= 'b0;
+     end
+     else begin
+       loc_addr_r       <= loc_addr;
+       loc_write_r      <= loc_write;
+       loc_read_r       <= loc_read;
+       loc_atomic_r     <= loc_atomic;
+       loc_atype_r      <= loc_atype;
+       loc_wrdata_r     <= loc_wrdata<<(DW - ({20'h0,loc_bytes}<<3));
+       wmask_r          <= wmask;
+       postatomic_shift <= DW -
+                           (({{32-$clog2(DW/8){1'b0}},loc_addr[$clog2(DW/8)-1:0]} +
+                           {20'h0,loc_bytes})<<3);
+     end
+   end
+
+   assign mem_rddata_atomic = mem_rddata<<postatomic_shift;
+
+   always @(*) begin
+     if (loc_atype_r == 8'h00)
+       loc_wrdata_atomic = loc_wrdata_r + mem_rddata_atomic;
+     else if (loc_atype_r == 8'h01)
+       loc_wrdata_atomic = loc_wrdata_r & mem_rddata_atomic;
+     else if (loc_atype_r == 8'h02)
+       loc_wrdata_atomic = loc_wrdata_r | mem_rddata_atomic;
+     else if (loc_atype_r == 8'h03)
+       loc_wrdata_atomic = loc_wrdata_r ^ mem_rddata_atomic;
+     else if (loc_atype_r == 8'h04)
+       loc_wrdata_atomic = $signed(loc_wrdata_r) > $signed(mem_rddata_atomic) ?
+                           loc_wrdata_r : mem_rddata_atomic;
+     else if (loc_atype_r == 8'h05)
+       loc_wrdata_atomic = $signed(loc_wrdata_r) > $signed(mem_rddata_atomic) ?
+                           mem_rddata_atomic : loc_wrdata_r;
+     else if (loc_atype_r == 8'h06)
+       loc_wrdata_atomic = $unsigned(loc_wrdata_r) > $unsigned(mem_rddata_atomic) ?
+                           loc_wrdata_r : mem_rddata_atomic;
+     else if (loc_atype_r == 8'h07)
+       loc_wrdata_atomic = $unsigned(loc_wrdata_r) > $unsigned(mem_rddata_atomic) ?
+                           mem_rddata_atomic : loc_wrdata_r;
+     else if (loc_atype_r == 8'h08)
+       loc_wrdata_atomic = loc_wrdata_r;
+     else
+       loc_wrdata_atomic = loc_wrdata_r;
+   end
+
+   assign mem_we = loc_write | loc_atomic_r;
+   assign mem_addr = loc_atomic_r ? loc_addr_r : loc_addr;
+   assign mem_wmask = loc_atomic_r ? wmask_r : wmask;
+   assign mem_wrdata = loc_atomic_r ?
+                       (loc_wrdata_atomic[DW-1:0]>>postatomic_shift) :
+                       (loc_wrdata[DW-1:0]<<(8*loc_addr[$clog2(DW/8)-1:0]));
+
    la_spram #(.DW    (DW),               // Memory width
               .AW    ($clog2(RAMDEPTH)), // Address width (derived)
               .TYPE  ("DEFAULT"),        // Pass through variable for hard macro
-              .CTRLW (128),              // Width of asic ctrl interface
+              .CTRLW (8),                // Width of asic ctrl interface
               .TESTW (128)               // Width of asic test interface
               )
    la_spram_i(// Outputs
@@ -125,23 +262,17 @@ module umi_mem_agent
               // Inputs
               .clk              (clk),
               .ce               (1'b1),
-              .we               (loc_write),
-              .wmask            (wmask[DW-1:0]),
-              .addr             (loc_addr[$clog2(DW/8)+:$clog2(RAMDEPTH)]),
-              .din              (loc_wrdata[DW-1:0]<<(8*loc_addr[$clog2(DW/8)-1:0])),
+              .we               (mem_we),
+              .wmask            (mem_wmask[DW-1:0]),
+              .addr             (mem_addr[$clog2(DW/8)+:$clog2(RAMDEPTH)]),
+              .din              (mem_wrdata),
               .vss              (1'b0),
               .vdd              (1'b1),
               .vddio            (1'b1),
               .ctrl             ('h0),
               .test             ('h0));
 
-   always @(posedge clk or negedge nreset)
-     if (~nreset)
-       loc_rdaddr <= 'h0;
-     else
-       loc_rdaddr <= loc_addr;
-
-   assign loc_rddata = mem_rddata >> (8*loc_rdaddr[$clog2(DW/8)-1:0]);
+   assign loc_rddata = mem_rddata >> (8*loc_addr_r[$clog2(DW/8)-1:0]);
 
 endmodule // ebrick_core
 // Local Variables:
diff --git a/utils/rtl/umi_packet_merge_greedy.v b/utils/rtl/umi_packet_merge_greedy.v
index c727759..c5c47da 100644
--- a/utils/rtl/umi_packet_merge_greedy.v
+++ b/utils/rtl/umi_packet_merge_greedy.v
@@ -126,10 +126,16 @@ module umi_packet_merge_greedy #(
     wire                    umi_in_ready_r;
     wire                    umi_in_cmd_commit_r;
 
+    reg [$clog2(ODW/8):0]   byte_counter;
+    /* verilator lint_off WIDTHTRUNC */
+    localparam [$clog2(ODW/8):0]    ODW_BYTES = ODW/8;
+    localparam                      ADDR_PAD_BYTES = AW - 1 - $clog2(ODW/8);
+    /* verilator lint_on WIDTHTRUNC */
+
     assign umi_in_cmd_commit_r = umi_in_ready_r & umi_in_valid_r;
     assign umi_in_ready = reset_done[1] & (~umi_in_valid_r | umi_in_ready_r);
     assign umi_in_ready_r = umi_out_cmd_commit |
-                            (umi_in_mergeable_r & ((byte_counter + umi_in_bytes_r) <= (ODW/8))) |
+                            (umi_in_mergeable_r & ((byte_counter + umi_in_bytes_r) <= ODW_BYTES)) |
                             (byte_counter == 0);
 
     always @(posedge clk or negedge nreset) begin
@@ -253,7 +259,7 @@ module umi_packet_merge_greedy #(
 
     always @(posedge clk or negedge nreset) begin
         if (~nreset)
-            umi_in_bytes_r <= 1'b0;
+            umi_in_bytes_r <= 'b0;
         else if (umi_in_cmd_commit)
             umi_in_bytes_r <= umi_in_bytes;
     end
@@ -325,9 +331,7 @@ module umi_packet_merge_greedy #(
     assign umi_out_dstaddr  = umi_out_dstaddr_r;
     assign umi_out_srcaddr  = umi_out_srcaddr_r;
     assign umi_out_valid = ((~umi_in_mergeable_r | umi_out_cmd_eom_r) & |byte_counter) |
-                           ((byte_counter + umi_in_bytes_r) > (ODW/8));
-
-    reg [$clog2(ODW/8):0]   byte_counter;
+                           ((byte_counter + umi_in_bytes_r) > ODW_BYTES);
 
     always @(posedge clk or negedge nreset) begin
         if (~nreset) begin
@@ -346,7 +350,7 @@ module umi_packet_merge_greedy #(
     wire [ODW-1:0]  umi_in_data_masked;
     reg  [ODW-1:0]  umi_out_data_r;
 
-    assign umi_in_data_masked = umi_in_data_r & ((1 << (umi_in_bytes_r*8))-1);
+    assign umi_in_data_masked = {{(ODW-IDW){1'b0}},umi_in_data_r} & ((1 << (umi_in_bytes_r*8))-1);
 
     always @(posedge clk or negedge nreset) begin
         if (~nreset) begin


Test patch:
diff --git a/umi/testbench/test_mem_agent.py b/umi/testbench/test_mem_agent.py
index f0c580e..e68073e 100755
--- a/umi/testbench/test_mem_agent.py
+++ b/umi/testbench/test_mem_agent.py
@@ -46,7 +46,51 @@ def build_testbench():
     return dut.find_result('vexe', step='compile')
 
 
-def main(vldmode="2", rdymode="2", host2dut="host2dut_0.q", dut2host="dut2host_0.q"):
+def apply_atomic(origdata, atomicdata, operation, maxrange):
+    tempval = origdata
+    if (operation == 0):
+        tempval = origdata + atomicdata
+        if (tempval >= maxrange):
+            tempval = tempval - maxrange
+    elif (operation == 1):
+        tempval = origdata & atomicdata
+    elif (operation == 2):
+        tempval = origdata | atomicdata
+    elif (operation == 3):
+        tempval = origdata ^ atomicdata
+    elif (operation == 4):
+        if (origdata & (maxrange>>1)):
+            origdata = int(origdata) - int(maxrange)
+        else:
+            origdata = int(origdata)
+        if (atomicdata & (maxrange>>1)):
+            atomicdata = int(atomicdata) - int(maxrange)
+        else:
+            atomicdata = int(atomicdata)
+        tempval = origdata if (origdata > atomicdata) else atomicdata
+    elif (operation == 5):
+        if (origdata & (maxrange>>1)):
+            origdata = int(origdata) - int(maxrange)
+        else:
+            origdata = int(origdata)
+        if (atomicdata & (maxrange>>1)):
+            atomicdata = int(atomicdata) - int(maxrange)
+        else:
+            atomicdata = int(atomicdata)
+        tempval = atomicdata if (origdata > atomicdata) else origdata
+    elif (operation == 6):
+        tempval = origdata if (origdata > atomicdata) else atomicdata
+    elif (operation == 7):
+        tempval = atomicdata if (origdata > atomicdata) else origdata
+    elif (operation == 8):
+        tempval = atomicdata
+    else:
+        tempval = atomicdata
+
+    return tempval
+
+
+def main(vldmode="2", rdymode="2", n=100, host2dut="host2dut_0.q", dut2host="dut2host_0.q"):
     # clean up old queues if present
     for q in [host2dut, dut2host]:
         delete_queue(q)
@@ -65,35 +109,35 @@ def main(vldmode="2", rdymode="2", host2dut="host2dut_0.q", dut2host="dut2host_0
 
     print("### Statring test ###")
 
+    avail_datatype = [np.uint8, np.uint16, np.uint32]
+
     # un-aligned accesses
-    for count in range (1000):
-        addr = random.randrange(511)
+    for count in range (n):
+        addr = np.random.randint(0, 512)
         src_addr = random.randrange(2**64-1)
         # lenth should not cross the DW boundary - umi_mem_agent limitation
-        length = np.random.randint(0,16-addr%16)
-        data8 = np.random.randint(0,255,size=length,dtype=np.uint8)
-        print(f"umi writing {length+1} bytes to addr 0x{addr:08x}")
-        host.write(addr, data8, srcaddr=src_addr)
-        print(f"umi read from addr 0x{addr:08x}")
-        val8 = host.read(addr, length, np.uint8, srcaddr=src_addr)
-        if ~((val8 == data8).all()):
-            print(f"ERROR umi read from addr 0x{addr:08x} expected {data8} actual {val8}")
-            assert (val8 == data8).all()
-
-    # Aligned accesses, b2b
-    for count in range (1000):
-        addr = 16 * random.randrange(127)
-        src_addr = random.randrange(2**64-1)
-        # lenth should not cross the DW boundary - umi_mem_agent limitation
-        length = np.random.randint(0,63)
-        data8 = np.random.randint(0,255,size=length,dtype=np.uint8)
-        print(f"umi writing {length+1} bytes to addr 0x{addr:08x}")
-        host.write(addr, data8, srcaddr=src_addr, max_bytes=16)
+        length = np.random.randint(0, 256)
+        wordindexer = np.random.choice([0,1,2])
+        maxrange = 2**(8*(2**wordindexer))
+        data = np.random.randint(0, maxrange, size=(length+1), dtype=avail_datatype[wordindexer])
+        addr = addr*(2**wordindexer) & 0x1FF
+
+        print(f"umi writing {length+1} words of type {avail_datatype[wordindexer]} to addr 0x{addr:08x}")
+        host.write(addr, data)
+        atomicopcode = np.random.randint(0, 9)
+        atomicdata = np.random.randint(0,256,dtype=avail_datatype[wordindexer])
+        print(f"umi atomic opcode: {atomicopcode} of type {avail_datatype[wordindexer]} to addr 0x{addr:08x}")
+        atomicval = host.atomic(addr, atomicdata, atomicopcode)
+        if not (atomicval == data[0]):
+            print(f"ERROR umi atomic from addr 0x{addr:08x} expected {data[0]} actual {atomicval}")
+            assert (atomicval == data[0])
+        data[0] = apply_atomic(data[0], atomicdata, atomicopcode, maxrange)
+
         print(f"umi read from addr 0x{addr:08x}")
-        val8 = host.read(addr, length, np.uint8, srcaddr=src_addr, max_bytes=16)
-        if ~((val8 == data8).all()):
-            print(f"ERROR umi read from addr 0x{addr:08x} expected {data8} actual {val8}")
-            assert (val8 == data8).all()
+        val = host.read(addr, length+1, dtype=avail_datatype[wordindexer])
+        if not (np.array_equal(val, data)):
+            print(f"ERROR umi read from addr 0x{addr:08x} expected {data} actual {val}")
+            assert (np.array_equal(val, data))
 
     print("### TEST PASS ###")
 
@@ -101,6 +145,8 @@ def main(vldmode="2", rdymode="2", host2dut="host2dut_0.q", dut2host="dut2host_0
     parser = ArgumentParser()
     parser.add_argument('--vldmode', default='2')
     parser.add_argument('--rdymode', default='2')
+    parser.add_argument('-n', type=int, default=10, help='Number of'
+                    ' transactions to send during the test.')
     args = parser.parse_args()
 
-    main(vldmode=args.vldmode,rdymode=args.rdymode)
+    main(vldmode=args.vldmode,rdymode=args.rdymode, n=args.n)
diff --git a/umi/testbench/testbench_mem_agent.sv b/umi/testbench/testbench_mem_agent.sv
index f8b3e02..74483ca 100644
--- a/umi/testbench/testbench_mem_agent.sv
+++ b/umi/testbench/testbench_mem_agent.sv
@@ -5,7 +5,7 @@ module testbench (
                   );
 
    parameter integer RW=32;
-   parameter integer DW=128;
+   parameter integer DW=256;
    parameter integer AW=64;
    parameter integer CW=32;
    parameter integer RAMDEPTH=512;
diff --git a/utils/testbench/config.vlt b/utils/testbench/config.vlt
index 076a5c3..2fbead8 100644
--- a/utils/testbench/config.vlt
+++ b/utils/testbench/config.vlt
@@ -1,12 +1,10 @@
 `verilator_config
-lint_off -file "*umi/umi/rtl/*"
-lint_off -file "*lambdalib/ramlib/*"
-lint_off -file "*lambdalib/stdlib/*"
-lint_off -file "*verilog-axi/rtl/*"
-lint_off -rule LATCH
-lint_off -rule UNOPTFLAT
 lint_off -rule WIDTHTRUNC
-lint_off -rule SELRANGE
-lint_off -rule IMPLICIT
 lint_off -rule WIDTHEXPAND
 lint_off -rule TIMESCALEMOD
+coverage_off -file "/home/ali/workspace/ebrick-ml-092523/submodules/ebrick/ebrick/submodules/umi/utils/testbench/testbench_umi2tl_np.v"
+coverage_off -file "/home/ali/workspace/Tools/switchboard/switchboard/verilog/sim/auto_stop_sim.sv"
+coverage_off -file "/home/ali/workspace/Tools/switchboard/switchboard/verilog/sim/umi_rx_sim.sv"
+coverage_off -file "/home/ali/workspace/Tools/switchboard/switchboard/verilog/sim/sb_rx_sim.sv"
+coverage_off -file "/home/ali/workspace/Tools/switchboard/switchboard/verilog/sim/umi_tx_sim.sv"
+coverage_off -file "/home/ali/workspace/Tools/switchboard/switchboard/verilog/sim/sb_tx_sim.sv"
diff --git a/utils/testbench/test_umi2tl_np.py b/utils/testbench/test_umi2tl_np.py
index 2ceb5de..c29a8b2 100644
--- a/utils/testbench/test_umi2tl_np.py
+++ b/utils/testbench/test_umi2tl_np.py
@@ -38,6 +38,7 @@ def build_testbench(topo="2d"):
         dut.add('option', option, EX_DIR / 'submodules' / 'lambdalib' / 'vectorlib' / 'rtl')
 
     # Verilator configuration
+    dut.add('tool', 'verilator', 'task', 'compile', 'option', '--coverage')
     vlt_config = EX_DIR / 'utils' / 'testbench' / 'config.vlt'
     header_files_dir = EX_DIR / 'utils' / 'testbench'
     dut.set('tool', 'verilator', 'task', 'compile', 'var', 'cflags', f'-I{header_files_dir}')
diff --git a/utils/testbench/test_umi_packet_merge_greedy.py b/utils/testbench/test_umi_packet_merge_greedy.py
index 3b7c720..4d2c236 100644
--- a/utils/testbench/test_umi_packet_merge_greedy.py
+++ b/utils/testbench/test_umi_packet_merge_greedy.py
@@ -17,7 +17,7 @@ def build_testbench(topo="2d"):
 
     # Set up inputs
     if topo=='2d':
-        dut.input('tb_umi_packet_merge_greedy.v')
+        dut.input('testbench_umi_packet_merge_greedy.v')
         print("### Running 2D topology ###")
     # elif topo=='3d':
     #     dut.input('testbench_3d.sv')
@@ -26,7 +26,7 @@ def build_testbench(topo="2d"):
     else:
         raise ValueError('Invalid topology')
 
-    dut.input(EX_DIR / 'submodules' / 'switchboard' / 'examples' / 'common' / 'verilator' / 'testbench.cc')
+    dut.input('testbench_umi_packet_merge_greedy.cc')
     for option in ['ydir', 'idir']:
         dut.add('option', option, EX_DIR / 'umi' / 'rtl')
         dut.add('option', option, EX_DIR / 'utils' / 'rtl')
@@ -38,6 +38,7 @@ def build_testbench(topo="2d"):
     # Verilator configuration
     vlt_config = EX_DIR / 'utils' / 'testbench' / 'config.vlt'
     dut.set('tool', 'verilator', 'task', 'compile', 'file', 'config', vlt_config)
+    dut.add('tool', 'verilator', 'task', 'compile', 'option', '--coverage')
 
     # Settings
     dut.set('option', 'trace', True)  # enable VCD (TODO: FST option)
diff --git a/utils/testbench/testbench_umi2tl_np.cc b/utils/testbench/testbench_umi2tl_np.cc
index 96ad049..3622b41 100644
--- a/utils/testbench/testbench_umi2tl_np.cc
+++ b/utils/testbench/testbench_umi2tl_np.cc
@@ -141,6 +141,12 @@ int main(int argc, char** argv, char** env) {
         contextp->timeInc(9); // 1 timeprecision period passes...
     }
 
+    if (VM_COVERAGE) {
+        //printf("\n\nYes, Coverage is here\n\n");
+        contextp->coveragep()->forcePerInstance(true);
+        contextp->coveragep()->write("coverage.dat");
+    }
+
     // Final model cleanup
     top->final();
 
diff --git a/utils/testbench/testbench_umi_packet_merge_greedy.cc b/utils/testbench/testbench_umi_packet_merge_greedy.cc
new file mode 100644
index 0000000..ad0c426
--- /dev/null
+++ b/utils/testbench/testbench_umi_packet_merge_greedy.cc
@@ -0,0 +1,91 @@
+// For Ctrl-C handling
+#include <signal.h>
+
+// For std::unique_ptr
+#include <memory>
+
+// Include common routines
+#include <verilated.h>
+
+// Include model header, generated from Verilating "top.v"
+#include "Vtestbench.h"
+
+// Legacy function required only so linking works on Cygwin and MSVC++
+double sc_time_stamp() {
+    return 0;
+}
+
+// ref: https://stackoverflow.com/a/4217052
+static volatile int got_sigint = 0;
+
+void sigint_handler(int unused) {
+    got_sigint = 1;
+}
+
+int main(int argc, char** argv, char** env) {
+    // Prevent unused variable warnings
+    if (false && argc && argv && env) {}
+
+    // Using unique_ptr is similar to
+    // "VerilatedContext* contextp = new VerilatedContext" then deleting at end.
+    const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
+    // Do not instead make Vtop as a file-scope static variable, as the
+    // "C++ static initialization order fiasco" may cause a crash
+
+    // Verilator must compute traced signals
+    contextp->traceEverOn(true);
+
+    // Pass arguments so Verilated code can see them, e.g. $value$plusargs
+    // This needs to be called before you create any model
+    contextp->commandArgs(argc, argv);
+
+    // Construct the Verilated model, from Vtop.h generated from Verilating "top.v".
+    // Using unique_ptr is similar to "Vtop* top = new Vtop" then deleting at end.
+    // "TOP" will be the hierarchical name of the module.
+    const std::unique_ptr<Vtestbench> top{new Vtestbench{contextp.get(), "TOP"}};
+
+    // Set Vtestbench's input signals
+    top->clk = 0;
+    top->eval();
+
+    // Set up Ctrl-C handler
+    signal(SIGINT, sigint_handler);
+
+    // Main loop
+    while (!(contextp->gotFinish() || got_sigint)) {
+        // Historical note, before Verilator 4.200 Verilated::gotFinish()
+        // was used above in place of contextp->gotFinish().
+        // Most of the contextp-> calls can use Verilated:: calls instead;
+        // the Verilated:: versions just assume there's a single context
+        // being used (per thread).  It's faster and clearer to use the
+        // newer contextp-> versions.
+
+        contextp->timeInc(1); // 1 timeprecision period passes...
+        // Historical note, before Verilator 4.200 a sc_time_stamp()
+        // function was required instead of using timeInc.  Once timeInc()
+        // is called (with non-zero), the Verilated libraries assume the
+        // new API, and sc_time_stamp() will no longer work.
+
+        // Toggle a fast (time/2 period) clock
+        top->clk = !top->clk;
+
+        // Evaluate model
+        // (If you have multiple models being simulated in the same
+        // timestep then instead of eval(), call eval_step() on each, then
+        // eval_end_step() on each. See the manual.)
+        top->eval();
+    }
+
+    if (VM_COVERAGE) {
+        //printf("\n\nYes, Coverage is here\n\n");
+        contextp->coveragep()->forcePerInstance(true);
+        contextp->coveragep()->write("coverage.dat");
+    }
+
+    // Final model cleanup
+    top->final();
+
+    // Return good completion status
+    // Don't use exit() or destructor won't get called
+    return 0;
+}
diff --git a/utils/testbench/tb_umi_packet_merge_greedy.v b/utils/testbench/testbench_umi_packet_merge_greedy.v
similarity index 95%
rename from utils/testbench/tb_umi_packet_merge_greedy.v
rename to utils/testbench/testbench_umi_packet_merge_greedy.v
index e3117fe..bc63f5c 100644
--- a/utils/testbench/tb_umi_packet_merge_greedy.v
+++ b/utils/testbench/testbench_umi_packet_merge_greedy.v
@@ -23,11 +23,11 @@ module testbench #(
     // SIM Ctrl signals
     wire            nreset;
     wire            go;
-    reg  [15:0]     nreset_vec = 16'h00;
+    reg  [15:0]     nreset_vec = 16'h0000;
 
     // Reset initialization
     always @(posedge clk) begin
-        nreset_vec <= {nreset_vec[15:0], 1'b1};
+        nreset_vec <= {nreset_vec[14:0], 1'b1};
     end
 
     assign nreset = nreset_vec[14];
@@ -76,7 +76,7 @@ module testbench #(
         .umi_in_cmd         (umi_stim2dut_cmd),
         .umi_in_dstaddr     (umi_stim2dut_dstaddr),
         .umi_in_srcaddr     (umi_stim2dut_srcaddr),
-        .umi_in_data        ({128'd0, umi_stim2dut_data}),
+        .umi_in_data        (umi_stim2dut_data),
         .umi_in_ready       (umi_stim2dut_ready),
 
         .umi_out_valid      (umi_dut2check_valid),