Repository: zeroasiccorp/umi (language: python)

Issue:
Auto lumi
This PR enhances lumi block to enable self-configuration based on the phy width. As a result configuration and/or link training only needs to happen in the phy and lumi will self-configure to match that. 

The changes include the following:
- Add phy_iow indication from the phy, sampled at the rise of phy_linkactive
- Rx/Tx enable, credit enable and credit depth will all be sampled based on the phy iow at phy_linkactive rise
- Change credit mechanism to send credit init until lumi framing is locked
- Add logic to receive side to lock on credit init messages after reset, supporting cases where the two sides of the link start in different times 
- Reset credit mechanism when Rx/Tx enable is cleared to support re-configuration

All of the changes include test updates (with random start time) and README for the block.



Discussion / hints:

Fix patch:
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..39a03ab
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,9 @@
+Andreas Olofsson
+Amir Volk
+Steven Herbst
+Edgar Iglesias
+Aliasger Zaidy
+Wenting Zhang
+Peter Grossmann
+Noah Moroze
+Ben Sheffer
diff --git a/LICENSE b/LICENSE
index d2126e2..2cca7c5 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,21 +1,203 @@
-MIT License
-
-Copyright (c) 2023 Zero ASIC Corporation
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+   ------------------
diff --git a/README.md b/README.md
index 0421c72..928b298 100644
--- a/README.md
+++ b/README.md
@@ -1,25 +1,13 @@
-![UMI](docs/_images/hokusai.jpg)
-
 # Universal Memory Interface (UMI)
 
-## License
-
-[Apache License 2.0](LICENSE)
-
-## Contributing
-
-UMI is an open-source project and welcomes contributions. To find out
-how to contribute to the project, see our
-[Contributing Guidelines.](./CONTRIBUTING.md)
-
-## Issues / Bugs
+## 1. Introduction
 
-We use [GitHub Issues](https://github.com/zeroasiccorp/umi/issues)
-for tracking requests and bugs.
+### 1.1 Design Philosophy
 
-## 1. Introduction
+* Make everything addressable
+* Keep it simple
 
-### 1.1 Architecture
+### 1.2 Architecture
 
 The Universal Memory Interface (UMI) is a transaction based standard for accessing memory through request-response message exchange patterns. UMI includes five distinct abstraction layers:
 
@@ -31,7 +19,7 @@ The Universal Memory Interface (UMI) is a transaction based standard for accessi
 
 ![UMI](docs/_images/umi_stack.svg)
 
-### 1.2 Key Features
+### 1.3 Key Features
 
   * independent request and response channels
   * word sizes up to 1024 bits
@@ -41,7 +29,7 @@ The Universal Memory Interface (UMI) is a transaction based standard for accessi
   * protection and security support
   * reserved opcodes for users and future expansion
 
-### 1.3 Key Terms
+### 1.4 Key Terms
 
 * **Transaction**: Complete request-response memory operation.
 * **Message**: Unidirectional request or response, consisting of a command header, address fields, and an optional data payload.
@@ -922,3 +910,18 @@ UCIe also requires implementing other phy control logic to maintain the link. Th
 [3] [AMBA4 AXI Stream Protocol Specification (09 April 2021, Version A)](https://developer.arm.com/documentation/ihi0051/a)
 
 [4] [AMBA4 APB Protocol Specification (13 April 2010, Version C)](https://developer.arm.com/documentation/ihi0024/c)
+
+## License
+
+[Apache License 2.0](LICENSE)
+
+## Contributing
+
+UMI is an open-source project and welcomes contributions. To find out
+how to contribute to the project, see our
+[Contributing Guidelines.](./CONTRIBUTING.md)
+
+## Issues / Bugs
+
+We use [GitHub Issues](https://github.com/zeroasiccorp/umi/issues)
+for tracking requests and bugs.
diff --git a/examples/umi_mem/.gitignore b/examples/umi_mem/.gitignore
deleted file mode 100644
index 6fdd538..0000000
--- a/examples/umi_mem/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-# SC build directory
-build/
diff --git a/examples/umi_mem/README.md b/examples/umi_mem/README.md
deleted file mode 100644
index 799a55a..0000000
--- a/examples/umi_mem/README.md
+++ /dev/null
@@ -1,43 +0,0 @@
-# UMI Memory Example
-
-This example is a small test of `umi_endpoint` that wires it up to a generic
-memory. It is meant to demonstrate how to use a common testbench to write unit
-tests for a block that uses UMI.
-
-We use pytest for managing tests, which provides useful functionality for
-automatic test discovery and running. To run the tests in this example, install
-pytest:
-
-```shell
-pip install pytest
-```
-
-Next, clone switchboard, compile its umidriver executable, and set an env
-variable pointing to it:
-
-```shell
-cd /path/to/switchboard/cpp
-make umidriver
-export SBDIR=/path/to/switchboard
-```
-
-Then, simply execute pytest to run the tests:
-
-```shell
-pytest
-```
-
-By default, pytest will look for and run any Python functions whose names begin
-with test_ in Python files whose names begin with test_. We've placed the
-example tests in `test_umi_mem.py.`
-
-## pytest tricks
-
-pytest has a variety of command line flags to control how and which tests are
-run. Here are some useful ones:
-
-- `pytest -s`: displays live output (pytest usually swallows it, and only prints
-on failure)
-- `pytest --collect-only`: display test names, but do not execute them (dry-run)
-- `pytest -k <test-name>`: run specific test(s), e.g. `pytest -k test_basic`
-(`-k` supports fuzzy matching as well)
diff --git a/examples/umi_mem/umi_mem.py b/examples/umi_mem/umi_mem.py
deleted file mode 100644
index fa21730..0000000
--- a/examples/umi_mem/umi_mem.py
+++ /dev/null
@@ -1,14 +0,0 @@
-import os
-
-import siliconcompiler
-
-umi_root = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..')
-
-def setup():
-    '''Generic setup for ASIC build and verification.'''
-    chip = siliconcompiler.Chip('umi_mem')
-    chip.set('input', 'verilog', 'umi_mem.v')
-    chip.add('option', 'ydir', f'{umi_root}/umi/rtl')
-    # May load entire target here instead, but only flow required for verif.
-    chip.load_flow('verification')
-    return chip
diff --git a/examples/umi_mem/umi_mem.v b/examples/umi_mem/umi_mem.v
deleted file mode 100644
index 384d8d7..0000000
--- a/examples/umi_mem/umi_mem.v
+++ /dev/null
@@ -1,58 +0,0 @@
-module umi_mem #(
-    parameter AW = 16,
-    parameter DW = 64
-) (
-    input clk,
-    input nreset,
-
-	input rx0_umi_valid,
-	input [255:0] rx0_umi_packet,
-	output rx0_umi_ready,
-
-	output tx0_umi_valid,
-	output [255:0] tx0_umi_packet,
-	input tx0_umi_ready
-);
-
-    wire [AW-1:0] addr;
-    wire write;
-    wire read;
-    wire [DW-1:0] write_data;
-    wire [DW-1:0] read_data;
-
-    reg [DW-1:0] mem[1 << (AW - $clog2(DW))];
-
-    umi_endpoint #(
-        .DW(DW)
-    ) endpoint(
-        .clk(clk),
-        .nreset(nreset),
-
-        .valid_in(rx0_umi_valid),
-        .packet_in(rx0_umi_packet),
-        .ready_out(rx0_umi_ready),
-
-        .valid_out(tx0_umi_valid),
-        .packet_out(tx0_umi_packet),
-        .ready_in(tx0_umi_ready),
-
-        .addr(addr),
-        .write(write),
-        .read(read),
-        .write_data(write_data),
-        .read_data(read_data)
-    );
-
-    // Truncate address - mem only supports DW-aligned accesses.
-    wire [AW-1-$clog2(DW):0] mem_addr;
-    assign mem_addr = addr[AW-1:$clog2(DW)];
-
-    always @(posedge clk) begin
-        if (write) begin
-            mem[mem_addr] <= write_data;
-        end
-    end
-
-    assign read_data = mem[mem_addr];
-
-endmodule
diff --git a/lumi/README.md b/lumi/README.md
new file mode 100644
index 0000000..db1873e
--- /dev/null
+++ b/lumi/README.md
@@ -0,0 +1,154 @@
+# Universal Memory Interface Link Layer (LUMI)
+
+## 1. Introduction
+
+This IP implements UMI link layer protocol based on UMI spec:
+* [Universal Memory Interface (UMI)](https://github.com/zeroasiccorp/umi)
+
+
+### 1.1 Design Philosophy
+
+* Keep it simple
+* Low latency, maximum throughput
+* Flexible, parametrized design to match application
+
+### 1.2 Architecture
+
+The Universal Memory Interface Link Layer (LUMI) is an implementation of the UMI link layer for multiple speeds and interface width. The design is parametrized for maximum implementation and also configurable at run time for application specific use cases. LUMI includes the following layers:
+
+* Lumi register file for configuration
+* Lumi crossbar for side band bus to the phy
+* Lumi receive logic (Rx), including clock domain crossing to the phy receive clock
+* Lumi transmit logic (Tx), including clock domain crossing to the phy transmit clock
+
+### 1.3 Key Features
+
+  * Parametrized UMI bus interface
+  * Parametrized phy interface width
+  * Parametrized number of credits and fifo depth
+  * Low latency, maximum bandwidth implementation
+  * Autonomous, no configuration self boot
+  * Run-time reconfigurable support
+
+----
+## 2. Design parameters
+
+LUMI block imeplentation exposes the following parameters to the user:
+
+| Parameter      | Default Value | Meaning                       |
+|----------------|---------------|-------------------------------|
+| TARGET         | DEFAULT       | Design target (for SC)        |
+| IDOFFSET       | 40            | Chip ID offset                |
+| GRPOFFSET      | 24            | Register group offset         |
+| GRPAW          | 8             | Group address width           |
+| GRPID          | 0             | Lumi regs group ID            |
+| IOW            | 64            | lumi-phy i/f width            |
+| ASYNCFIFODEPTH | 8             | Async fifo depth              |
+| RXFIFOW        | *             | Rx FIFO width in bits         |
+| NFIFO          | *             | Number of receive fifo's      |
+| CRDTDEPTH      | *             | Credit fifo depth             |
+| CW             | 32            | SUMI command width            |
+| AW             | 64            | SUMI address width            |
+| DW             | 128           | SUMI data width               |
+| RW             | 32            | SUMI register width           |
+| IDW            | 16            | chipid width                  |
+|----------------|---------------|-------------------------------|
+
+* The parameters for the Rx fifo are calculated based on the sumi parameters and the phy IO width. The default values are calculated for 8b fifo width and the minimum fifo depth required to absorb a full SUMI packet. Increasing the fifo depth will provide better utilization of the bus due to lower credit update interval but will add area.
+
+----
+## 3. Interface
+
+The following is the LUMI block interface. All signals are synchronous, active on rising edge and active high unless specified differently. \
+
+| Signal Name        | Width     |   Dir  | Description               |
+|--------------------|-----------|--------|---------------------------|
+| nreset             |           | input  | Primary reset, active low |
+| clk                |           | input  | SUMI clock, active high   |
+| deviceready        |           | input  | Device ready              |
+| host_linkactive    |           | output | Link active to host       |
+| devicemode         |           | input  | Mode: 1-device, 0-host    |
+| uhost_req_valid    |           | output | SUMI host port            |
+| uhost_req_cmd      | [CW-1:0]  | output | SUMI host port            |
+| uhost_req_dstaddr  | [AW-1:0]  | output | SUMI host port            |
+| uhost_req_srcaddr  | [AW-1:0]  | output | SUMI host port            |
+| uhost_req_data     | [DW-1:0]  | output | SUMI host port            |
+| uhost_req_ready    |           | input  | SUMI host port            |
+| uhost_resp_valid   |           | input  | SUMI host port            |
+| uhost_resp_cmd     | [CW-1:0]  | input  | SUMI host port            |
+| uhost_resp_dstaddr | [AW-1:0]  | input  | SUMI host port            |
+| uhost_resp_srcaddr | [AW-1:0]  | input  | SUMI host port            |
+| uhost_resp_data    | [DW-1:0]  | input  | SUMI host port            |
+| uhost_resp_ready   |           | output | SUMI host port            |
+| udev_req_valid     |           | input  | SUMI device port          |
+| udev_req_cmd       | [CW-1:0]  | input  | SUMI device port          |
+| udev_req_dstaddr   | [AW-1:0]  | input  | SUMI device port          |
+| udev_req_srcaddr   | [AW-1:0]  | input  | SUMI device port          |
+| udev_req_data      | [DW-1:0]  | input  | SUMI device port          |
+| udev_req_ready     |           | output | SUMI device port          |
+| udev_resp_valid    |           | output | SUMI device port          |
+| udev_resp_cmd      | [CW-1:0]  | output | SUMI device port          |
+| udev_resp_dstaddr  | [AW-1:0]  | output | SUMI device port          |
+| udev_resp_srcaddr  | [AW-1:0]  | output | SUMI device port          |
+| udev_resp_data     | [DW-1:0]  | output | SUMI device port          |
+| udev_resp_ready    |           | input  | SUMI device port          |
+| sb_in_valid        |           | input  | sideband SUMI port        |
+| sb_in_cmd          | [CW-1:0]  | input  | sideband SUMI port        |
+| sb_in_dstaddr      | [AW-1:0]  | input  | sideband SUMI port        |
+| sb_in_srcaddr      | [AW-1:0]  | input  | sideband SUMI port        |
+| sb_in_data         | [RW-1:0]  | input  | sideband SUMI port        |
+| sb_in_ready        |           | output | sideband SUMI port        |
+| sb_out_valid       |           | output | sideband SUMI port        |
+| sb_out_cmd         | [CW-1:0]  | output | sideband SUMI port        |
+| sb_out_dstaddr     | [AW-1:0]  | output | sideband SUMI port        |
+| sb_out_srcaddr     | [AW-1:0]  | output | sideband SUMI port        |
+| sb_out_data        | [RW-1:0]  | output | sideband SUMI port        |
+| sb_out_ready       |           | input  | sideband SUMI port        |
+| phy_clk            |           | input  | phy sb clock              |
+| phy_nreset         |           | input  | phy sb reset, active low  |
+| phy_in_valid       |           | input  | phy sideband port         |
+| phy_in_cmd         | [CW-1:0]  | input  | phy sideband port         |
+| phy_in_dstaddr     | [AW-1:0]  | input  | phy sideband port         |
+| phy_in_srcaddr     | [AW-1:0]  | input  | phy sideband port         |
+| phy_in_data        | [RW-1:0]  | input  | phy sideband port         |
+| phy_in_ready       |           | output | phy sideband port         |
+| phy_out_valid      |           | output | phy sideband port         |
+| phy_out_cmd        | [CW-1:0]  | output | phy sideband port         |
+| phy_out_dstaddr    | [AW-1:0]  | output | phy sideband port         |
+| phy_out_srcaddr    | [AW-1:0]  | output | phy sideband port         |
+| phy_out_data       | [RW-1:0]  | output | phy sideband port         |
+| phy_out_ready      |           | input  | phy sideband port         |
+| phy_rxdata         | [IOW-1:0] | input  | phy lumi rx data          |
+| phy_rxvld          |           | input  | phy lumi rx valid         |
+| rxclk              |           | input  | phy lumi rx clk           |
+| rxnreset           |           | input  | phy lumi rx reset (low)   |
+| phy_txdata         | [IOW-1:0] | output | phy lumi tx data          |
+| phy_txvld          |           | output | phy lumi tx valid         |
+| txclk              |           | input  | phy lumi tx clk           |
+| txnreset           |           | input  | phy lumi tx reset (low)   |
+| phy_linkactive     |           | input  | phy link active           |
+| phy_iow            | [7:0]     | input  | phy IO width              |
+
+----
+## 4. Operation and configuration
+
+The LUMI block is designed to work without any configuration based on the parameters used.
+In this mode it will enable the receiver, transmitter and credit mechanism at the rise of linkactive indication from the phy. This allows the phy to initialize and train (if applicable) before lumi is enabled.
+
+### 4.1 Autonomous Flow
+
+In this mode lumi is self-configuring based on the parameters and phy width.
+
+1. nreset deassertion
+2. phy layer sets phy_iow
+3. phy_linkactive is asserted
+
+### 4.2 Re-configuration Flow
+
+As lumi is self-configured based on the phy width there might be cases where parameters need to be changed. In order to override the configuration the following flow should be followed:
+1. Pull on remote and local side link active indication in LUMI_STATUS register and wait for the link to be active on both sides
+2. Disable Tx on both sides of the link
+3. Disable Rx on both sides of the link
+4. Configure required lumi configurations over side band
+5. Enable Rx on both sides
+6. Enable Tx (and credits if needed) on both sides
diff --git a/lumi/rtl/lumi.v b/lumi/rtl/lumi.v
index 772a291..27aa28c 100644
--- a/lumi/rtl/lumi.v
+++ b/lumi/rtl/lumi.v
@@ -1,31 +1,44 @@
-/******************************************************************************
- * Function:  Link UMI ("LUMI") Top Level Module
- * Author:    Amir Volk
- * Copyright: 2023 Zero ASIC Corporation. All rights reserved.
+/*******************************************************************************
+ * Copyright 2023 Zero ASIC Corporation
  *
- * License: This file contains confidential and proprietary information of
- * Zero ASIC. This file may only be used in accordance with the terms and
- * conditions of a signed license agreement with Zero ASIC. All other use,
- * reproduction, or distribution of this software is strictly prohibited.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- * Version history:
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * 1. convert from CLINK
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  *
- *****************************************************************************/
+ * ----
+ *
+ * Documentation:
+ * - Link UMI ("LUMI") Top Level Module
+ * - Wakes up in 1B, infinite credit mode. Chaging width must be done before
+ *   enabling credit mechanism or sending traffic
+ *
+ ******************************************************************************/
+
 module lumi
-  #(parameter TARGET = "DEFAULT", // compiler target
-    parameter IDOFFSET = 24,      // chip ID address offset
-    parameter GRPOFFSET = 24,     // group address offset
-    parameter GRPAW = 8,          // group address width
-    parameter GRPID = 0,          // group ID
+  #(parameter TARGET = "DEFAULT",                          // compiler target
+    parameter IDOFFSET = 40,                               // chip ID address offset
+    parameter GRPOFFSET = 24,                              // group address offset
+    parameter GRPAW = 8,                                   // group address width
+    parameter GRPID = 0,                                   // group ID
+    parameter ASYNCFIFODEPTH = 8,                          // depth of async fifo
+    parameter RXFIFOW = 8,                                 // width of Rx fifo (in bits) - cannot be smaller than IOW!!!
+    parameter NFIFO = IOW/RXFIFOW,                         // number of parallel fifo's
+    parameter CRDTDEPTH = 1+((DW+AW+AW+CW)/RXFIFOW)/NFIFO, // total fifo depth, eq is minimum
     // for development
-    parameter DW = 128,           // umi packet width
-    parameter CW = 32,            // umi packet width
-    parameter AW = 64,            // address width
-    parameter RW = 64,            // register width
-    parameter IDW = 16,           // chipid width
-    parameter IOW = 64            // phy IO width
+    parameter DW = 128,                                    // umi packet width
+    parameter CW = 32,                                     // umi packet width
+    parameter AW = 64,                                     // address width
+    parameter RW = 64,                                     // register width
+    parameter IDW = 16,                                    // chipid width
+    parameter IOW = 64                                     // phy IO width
     )
    (// host/device selector
     input            devicemode,      // 1=device, 0=host
@@ -94,6 +107,7 @@ module lumi
     input            txnreset,
     // phy control interface
     input            phy_linkactive,
+    input [7:0]      phy_iow,
     // Host control interface
     input            nreset,          // host driven reset
     input            clk,             // host driven clock
@@ -101,13 +115,11 @@ module lumi
     output           host_linkactive, // link is locked/ready
     // supplies
     input            vss,             // common ground
-    input            vdd              // core supply
+    input            vdd             // core supply
     /*AUTOINPUT*/
     /*AUTOOUTPUT*/
     );
 
-   localparam RXFIFOW = 8;
-
    /*AUTOWIRE*/
    // Beginning of automatic wires (for undeclared instantiated-module outputs)
    wire [CW-1:0]        cb2fifo_cmd;
@@ -137,6 +149,7 @@ module lumi
    wire                 fifo2cb_ready;
    wire [AW-1:0]        fifo2cb_srcaddr;
    wire                 fifo2cb_valid;
+   wire [1:0]           loc_crdt_init;
    wire [15:0]          loc_crdt_req;
    wire [15:0]          loc_crdt_resp;
    wire [CW-1:0]        regs2cb_cmd;
@@ -145,6 +158,7 @@ module lumi
    wire                 regs2cb_ready;
    wire [AW-1:0]        regs2cb_srcaddr;
    wire                 regs2cb_valid;
+   wire [1:0]           rmt_crdt_init;
    wire [15:0]          rmt_crdt_req;
    wire [15:0]          rmt_crdt_resp;
    // End of automatics
@@ -170,7 +184,12 @@ module lumi
                .DW(DW),
                .CW(CW),
                .AW(AW),
-               .RXFIFOW(RXFIFOW))
+               .IOW(IOW),
+               .ASYNCFIFODEPTH(ASYNCFIFODEPTH),
+               .RXFIFOW(RXFIFOW),
+               .NFIFO(NFIFO),
+               .CRDTDEPTH(CRDTDEPTH)
+               )
    lumi_regs(/*AUTOINST*/
              // Outputs
              .udev_req_ready    (cb2regs_ready),         // Templated
@@ -201,6 +220,7 @@ module lumi
              .udev_req_data     (cb2regs_data[RW-1:0]),  // Templated
              .udev_resp_ready   (regs2cb_ready),         // Templated
              .phy_linkactive    (phy_linkactive),
+             .phy_iow           (phy_iow[7:0]),
              .csr_txcrdt_status (csr_txcrdt_status[31:0]));
 
    //###########################
@@ -380,7 +400,11 @@ module lumi
              .CW(CW),
              .AW(AW),
              .DW(DW),
-             .RXFIFOW(RXFIFOW))
+             .ASYNCFIFODEPTH(ASYNCFIFODEPTH),
+             .RXFIFOW(RXFIFOW),
+             .NFIFO(NFIFO),
+             .CRDTDEPTH(CRDTDEPTH)
+             )
    lumi_rx(/*AUTOINST*/
            // Outputs
            .umi_resp_out_cmd    (udev_resp_cmd[CW-1:0]), // Templated
@@ -397,6 +421,8 @@ module lumi
            .loc_crdt_resp       (loc_crdt_resp[15:0]),
            .rmt_crdt_req        (rmt_crdt_req[15:0]),
            .rmt_crdt_resp       (rmt_crdt_resp[15:0]),
+           .loc_crdt_init       (loc_crdt_init[1:0]),
+           .rmt_crdt_init       (rmt_crdt_init[1:0]),
            // Inputs
            .clk                 (clk),
            .nreset              (nreset),
@@ -462,7 +488,9 @@ module lumi
            .rmt_crdt_req        (rmt_crdt_req[15:0]),
            .rmt_crdt_resp       (rmt_crdt_resp[15:0]),
            .loc_crdt_req        (loc_crdt_req[15:0]),
-           .loc_crdt_resp       (loc_crdt_resp[15:0]));
+           .loc_crdt_resp       (loc_crdt_resp[15:0]),
+           .loc_crdt_init       (loc_crdt_init[1:0]),
+           .rmt_crdt_init       (rmt_crdt_init[1:0]));
 
 endmodule // clink
 // Local Variables:
diff --git a/lumi/rtl/lumi_crossbar.v b/lumi/rtl/lumi_crossbar.v
index 1b09550..dc262a3 100644
--- a/lumi/rtl/lumi_crossbar.v
+++ b/lumi/rtl/lumi_crossbar.v
@@ -1,14 +1,22 @@
 /*******************************************************************************
- * Function:  LUMI REGISTER CROSSBAR
- * Author:    Amir Volk
- * Copyright: 2023 Zero ASIC Corporation. All rights reserved.
+ * Copyright 2023 Zero ASIC Corporation
  *
- * License: This file contains confidential and proprietary information of
- * Zero ASIC. This file may only be used in accordance with the terms and
- * conditions of a signed license agreement with Zero ASIC. All other use,
- * reproduction, or distribution of this software is strictly prohibited.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
  *
  * Documentation:
+ * - LUMI register access crossbar
  *
  * 1. Note asymmetry, only host can initiate register access
  * 2. Pipelined interface avoids lockup/complexity.
diff --git a/lumi/rtl/lumi_regmap.vh b/lumi/rtl/lumi_regmap.vh
index 01ebfd5..4f32b9d 100644
--- a/lumi/rtl/lumi_regmap.vh
+++ b/lumi/rtl/lumi_regmap.vh
@@ -1,17 +1,24 @@
-/*****************************************************************************
- * Function:  LUMI Register Map
- * Author:    Amir Volk
- * Copyright: 2023 Zero ASIC Corporation
+/*******************************************************************************
+ * Copyright 2023 Zero ASIC Corporation
  *
- * License: This file contains confidential and proprietary information of
- * Zero ASIC. This file may only be used in accordance with the terms and
- * conditions of a signed license agreement with Zero ASIC. All other use,
- * reproduction, or distribution of this software is strictly prohibited.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- * Version history:
- * Ver 1 - convert from CLINK register
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- *****************************************************************************/
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
+ *
+ * Documentation:
+ * - LUMI Register Map
+ *
+ ******************************************************************************/
 
 // registers (addr[7:0]), 32bit aligned
 localparam LUMI_CTRL        = 8'h00; // device configuration
diff --git a/lumi/rtl/lumi_regs.v b/lumi/rtl/lumi_regs.v
index a164a6d..bce3e0d 100644
--- a/lumi/rtl/lumi_regs.v
+++ b/lumi/rtl/lumi_regs.v
@@ -1,30 +1,41 @@
-/******************************************************************************
- * Function:  LUMI Control Registers
- * Author:    Amir Volk
- * Copyright: 2023 Zero ASIC Corporation
+/*******************************************************************************
+ * Copyright 2023 Zero ASIC Corporation
  *
- * License: This file contains confidential and proprietary information of
- * Zero ASIC. This file may only be used in accordance with the terms and
- * conditions of a signed license agreement with Zero ASIC. All other use,
- * reproduction, or distribution of this software is strictly prohibited.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- * Version history:
- * Ver 1 - convert from CLINK register
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- *****************************************************************************/
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
+ *
+ * Documentation:
+ * - LUMI Control Registers
+ *
+ ******************************************************************************/
 
 module lumi_regs
-  #(parameter TARGET = "DEFAULT", // LUMI type
-    parameter GRPOFFSET = 24,     // group address offset
-    parameter GRPAW = 8,          // group address width
-    parameter GRPID = 0,          // group ID
+  #(parameter TARGET = "DEFAULT",                         // LUMI type
+    parameter GRPOFFSET = 24,                             // group address offset
+    parameter GRPAW = 8,                                  // group address width
+    parameter GRPID = 0,                                  // group ID
     // for development only (fixed )
-    parameter CW = 32,            // umi data width
-    parameter AW = 64,            // address width
-    parameter DW = 128,           // register width
-    parameter RW = 32,            // register width
-    parameter IDW = 16,           // chipid width
-    parameter RXFIFOW =8
+    parameter CW = 32,                                    // umi data width
+    parameter AW = 64,                                    // address width
+    parameter DW = 128,                                   // register width
+    parameter RW = 32,                                    // register width
+    parameter IDW = 16,                                   // chipid width
+    parameter IOW = 64,                                   // phy-lumi IO width
+    parameter ASYNCFIFODEPTH = 8,                         // depth of async fifo
+    parameter RXFIFOW = 8,                                // width of Rx fifo (in bits) - cannot be smaller than IOW!!!
+    parameter NFIFO = IOW/RXFIFOW,                        // number of parallel fifo's
+    parameter CRDTDEPTH = 1+((DW+AW+AW+CW)/RXFIFOW)/NFIFO // total fifo depth, eq is minimum
     )
    (// common controls
     input           devicemode,    // 1=host, 0=device
@@ -46,6 +57,7 @@ module lumi_regs
     input           udev_resp_ready,
     // phy control signals
     input           phy_linkactive,
+    input [7:0]     phy_iow,
     // host side signals
     output          host_linkactive,
     // crossbar settings
@@ -65,7 +77,8 @@ module lumi_regs
     );
 
 `include "lumi_regmap.vh"
-   localparam CRDTDEPTH = 1+(DW+AW+AW+CW)/RXFIFOW;
+
+   localparam TOTCRDT = CRDTDEPTH * NFIFO;
 
    genvar     i;
 
@@ -86,6 +99,8 @@ module lumi_regs
    reg [RW-1:0]  rxcrdt_init_reg;
 
    reg           linkactive;
+   reg           linkactive_d;
+   reg           linkactive_rise;
 
    // sb interface
    wire [AW-1:0] reg_addr;
@@ -113,6 +128,18 @@ module lumi_regs
      else if (deviceready & devicemode | ~devicemode)
        linkactive <= phy_linkactive;
 
+   always @ (posedge clk or negedge nreset)
+     if (!nreset)
+       begin
+          linkactive_d <= 1'b0;
+          linkactive_rise <= 1'b0;
+       end
+     else
+       begin
+          linkactive_d <= linkactive;
+          linkactive_rise <= linkactive & ~linkactive_d;
+       end
+
    assign host_linkactive = linkactive;
 
    //###############################################
@@ -142,17 +169,24 @@ module lumi_regs
    //######################################
    // TXMODE Register
    //######################################
-   // Amir - tx enable should not be set out of reset since you need to configure (from the host)
-   // the link parameters first.
+   // In order to enable lumi to work without a SW sequenece it
+   // will enable and sample the parameters from the phy once linkactive
+   // goes high
+
    always @ (posedge clk or negedge nreset)
      if(!nreset)
-       txmode_reg[RW-1:0] <= 'b0;
+       txmode_reg[RW-1:0] <= 'h0;
+     else if (linkactive_rise)
+       txmode_reg[RW-1:0] <= {{(RW-24){1'b0}}, // Unused
+                              phy_iow[7:0],    // IOW
+                              8'h00,           // Unused
+                              4'b0001,         // 3 unused, credit enable
+                              4'b0001};        // 3 unused, tx enable
      else if(write_txmode)
        txmode_reg[RW-1:0] <= reg_wrdata[RW-1:0];
 
-   assign csr_txen        = linkactive & txmode_reg[0]; // tx enable
-   assign csr_txcrdt_en   = txmode_reg[4];   // Enable sending credit updates
-
+   assign csr_txen           = linkactive & txmode_reg[0]; // tx enable
+   assign csr_txcrdt_en      = txmode_reg[4];   // Enable sending credit updates
    assign csr_txiowidth[7:0] = txmode_reg[23:16];
    // 00000000 = 1 bytes
    // 00000001 = 2 bytes
@@ -167,13 +201,17 @@ module lumi_regs
 
    always @ (posedge clk or negedge nreset)
      if(!nreset)
-       rxmode_reg[RW-1:0] <= 'b0;
+       rxmode_reg[RW-1:0] <= 'h0;
+     else if (linkactive_rise)
+       rxmode_reg[RW-1:0] <= {{(RW-24){1'b0}}, // Unused
+                              phy_iow[7:0],    // IOW
+                              12'h000,         // Unused
+                              4'b0001};        // 3 unused, rx enable
      else if(write_rxmode)
        rxmode_reg[RW-1:0] <= reg_wrdata[RW-1:0];
 
-   assign csr_rxen      = linkactive & rxmode_reg[0]; // rx enable
-
-   assign csr_rxiowidth[7:0]  = rxmode_reg[23:16];
+   assign csr_rxen           = linkactive & rxmode_reg[0]; // rx enable
+   assign csr_rxiowidth[7:0] = rxmode_reg[23:16];
    // 00000000 = 1 bytes
    // 00000001 = 2 bytes
    // 00000010 = 4 bytes
@@ -186,7 +224,10 @@ module lumi_regs
    //######################################
    always @ (posedge clk or negedge nreset)
      if(!nreset)
-       rxcrdt_init_reg[31:0] <= {CRDTDEPTH[15:0],CRDTDEPTH[15:0]};
+       rxcrdt_init_reg[31:0] <= 'h0;
+     else if (linkactive_rise)
+       rxcrdt_init_reg[31:0] <= {TOTCRDT[15:0] >> phy_iow,
+                                 TOTCRDT[15:0] >> phy_iow};
      else if(write_crdt_init)
        rxcrdt_init_reg[31:0] <= reg_wrdata[31:0];
 
@@ -198,7 +239,7 @@ module lumi_regs
    //######################################
    always @ (posedge clk or negedge nreset)
      if(!nreset)
-       txcrdt_intrvl_reg[15:0] <= 16'h00FF;
+       txcrdt_intrvl_reg[15:0] <= 16'h0010;
      else if(write_crdt_intrvl)
        txcrdt_intrvl_reg[15:0] <= reg_wrdata[15:0];
 
diff --git a/lumi/rtl/lumi_rx.v b/lumi/rtl/lumi_rx.v
index 001a076..93086a0 100644
--- a/lumi/rtl/lumi_rx.v
+++ b/lumi/rtl/lumi_rx.v
@@ -1,28 +1,37 @@
-/******************************************************************************
- * Function:  Link UMI (LUMI) Rx block
- * Author:    Amir Volk
- * Copyright: 2023 Zero ASIC Corporation
+/*******************************************************************************
+ * Copyright 2023 Zero ASIC Corporation
  *
- * License: This file contains confidential and proprietary information of
- * Zero ASIC. This file may only be used in accordance with the terms and
- * conditions of a signed license agreement with Zero ASIC. All other use,
- * reproduction, or distribution of this software is strictly prohibited.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
  *
  * Documentation:
- * - converts UMI signaling layer (cmd, addr, data) to multiplexed LUMI i/f
+ * - LUMI Receiver
+ * - Converts PHY side interface to SUMI (cmd, addr, data)
  *
- * Version history:
- * Version 1 - convert from CLINK to LUMI
- * Version 2 - reduce fifo sizes by diving into multiple fifo's
- *****************************************************************************/
+ ******************************************************************************/
+
 module lumi_rx
-  #(parameter TARGET = "DEFAULT", // implementation target
+  #(parameter TARGET = "DEFAULT",                         // implementation target
     // for development only (fixed )
-    parameter IOW = 64,           // clink rx/tx width
-    parameter DW = 256,           // umi data width
-    parameter CW = 32,            // umi data width
-    parameter AW = 64,            // address width
-    parameter RXFIFOW = 8         // width of Rx fifo (in bits) - cannot be smaller than IOW!!!
+    parameter IOW = 64,                                   // clink rx/tx width
+    parameter DW = 256,                                   // umi data width
+    parameter CW = 32,                                    // umi data width
+    parameter AW = 64,                                    // address width
+    parameter ASYNCFIFODEPTH = 8,                         // depth of async fifo
+    parameter RXFIFOW = 8,                                // width of Rx fifo (in bits) - cannot be smaller than IOW!!!
+    parameter NFIFO = IOW/RXFIFOW,                        // number of parallel fifo's
+    parameter CRDTDEPTH = 1+((DW+AW+AW+CW)/RXFIFOW)/NFIFO // total fifo depth, eq is minimum
     )
    (// local control
     input             clk,                // clock for sampling input data
@@ -56,12 +65,11 @@ module lumi_rx
     output [15:0]     loc_crdt_req,       // Realtime rx credits to be sent to the remote side
     output [15:0]     loc_crdt_resp,      // Realtime rx credits to be sent to the remote side
     output reg [15:0] rmt_crdt_req,       // Credit value from remote side (for Tx)
-    output reg [15:0] rmt_crdt_resp       // Credit value from remote side (for Tx)
+    output reg [15:0] rmt_crdt_resp,      // Credit value from remote side (for Tx)
+    output reg [1:0]  loc_crdt_init,
+    output reg [1:0]  rmt_crdt_init
     );
 
-   localparam ASYNCFIFODEPTH = 8;
-   localparam NFIFO = IOW/RXFIFOW;
-   localparam CRDTDEPTH = 1+((DW+AW+AW+CW)/RXFIFOW)/NFIFO;
    localparam LOGFIFOWIDTH = $clog2(RXFIFOW/8);
    localparam LOGNFIFO = $clog2(NFIFO);
 
@@ -85,7 +93,7 @@ module lumi_rx
    wire [(DW+AW+AW+CW)-1:0]         req_shiftreg_in;
    wire [(DW+AW+AW+CW)-1:0]         resp_shiftreg_in;
    reg [CW-1:0]                     lnk_shiftreg;
-   reg [CW-1:0]                     lnk_fifo_dout_mask;
+   reg [CW-1:0]                     lnk_rxdata_mask;
    reg [1:0]                        lnk_sop;
    wire [4:0]                       lnk_sop_bit;
    wire [1:0]                       lnk_sop_next;
@@ -97,10 +105,9 @@ module lumi_rx
    wire [1:0]                       fifo_empty;
    wire                             lnk_fifo_empty;
    wire [1:0]                       fifo_wr;
-   wire                             lnk_fifo_wr;
+   reg                              lnk_fifo_wr;
    wire [1:0]                       fifo_rd;
    wire                             lnk_fifo_rd;
-   reg                              lnk_cmd_vld;
    wire [NFIFO:0]                   fifo_mux_sel;
    wire [NFIFO-1:0]                 fifo_dout_sel;
    wire [NFIFO-1:0]                 fifo_dout_mask;
@@ -159,7 +166,6 @@ module lumi_rx
    wire [11:0]                      resp_cmd_lenp1;
    wire [11:0]                      req_cmd_bytes;
    wire [11:0]                      resp_cmd_bytes;
-
    wire [1:0]                       credit_req_in;
 
    wire [15:0]                      rxhdr;
@@ -254,9 +260,9 @@ module lumi_rx
           rxvalid  <= 1'b0;
           rxvalid2 <= 1'b0;
        end
-     else if (csr_en)
+     else
        begin
-          rxvalid  <= phy_rxvld;
+          rxvalid  <= phy_rxvld & csr_en;
           rxvalid2 <= rxvalid;
        end
 
@@ -396,7 +402,11 @@ module lumi_rx
 
    // Count by the number of bytes per cycle transferred
    // When reaching the end of the header need to re-align to the remaining bytes
-   assign sopptr_next = ((sopptr + byterate) >= rxbytes_to_rcv) ?
+   // When we are still waiting for credit init the sop will not progress unless
+   // the command is a link command. This is done in order to align the lumi framing
+   // in case rxen is set in the middle of a packet
+   assign sopptr_next = (((sopptr + byterate) >= rxbytes_to_rcv) |
+                         (sopptr == 0) & (|loc_crdt_init) & ~rxcmd_link) ?
                         0 :
                         sopptr + byterate;
 
@@ -409,15 +419,20 @@ module lumi_rx
    // Since the data might come on a narror interface will only use the first byte
 
    // Sample packet type from the RX lines upon SOP
+   // All packets but link will be blocked until credit init is done
    always @(posedge ioclk or negedge ionreset)
      if (~ionreset)
        rxtype_next[2:0] <= 3'b000;
      else
        if (rxhdr_sample & rxvalid)
-         rxtype_next[2:0] <= {rxcmd_link, rxcmd_response & ~rxcmd_link, rxcmd_request & ~rxcmd_link};
+         rxtype_next[2:0] <= {rxcmd_link,
+                              rxcmd_response & ~rxcmd_link & ~(|loc_crdt_init),
+                              rxcmd_request  & ~rxcmd_link & ~(|loc_crdt_init)};
 
    assign rxtype = rxhdr_sample & rxvalid ?
-                   {rxcmd_link, rxcmd_response & ~rxcmd_link, rxcmd_request & ~rxcmd_link} :
+                   {rxcmd_link,
+                    rxcmd_response & ~rxcmd_link & ~(|loc_crdt_init),
+                    rxcmd_request  & ~rxcmd_link & ~(|loc_crdt_init)} :
                    rxtype_next;
 
    // credit counters - to be sent to the remote side
@@ -602,9 +617,37 @@ module lumi_rx
    //########################################
    // link cmd Fifo - no FC
    //########################################
-   assign lnk_fifo_wr = rxvalid & (rxtype[2:0] == 3'b100);
-   assign lnk_fifo_rd = ~lnk_fifo_empty;
-   assign lnk_fifo_din[CW-1:0] = rxdata[CW-1:0];
+   // Shift register to align full command is done in front of the async
+   // fifo. This is done to handle a case of overflow so losing a full
+   // command does not get you out of framing.
+   assign lnk_sop_next[1:0] = lnk_sop[1:0] + iowidth[1:0];
+
+   // For shift left
+   assign lnk_sop_bit[4:0] = {3'b000,lnk_sop[1:0]};
+
+   always @(posedge ioclk or negedge ionreset)
+     if (~ionreset)
+       begin
+          lnk_sop[1:0]            <= 'h0;
+          lnk_rxdata_mask[CW-1:0] <= 'h0;
+          lnk_shiftreg[CW-1:0]    <= 'h0;
+          lnk_fifo_wr             <= 'b0;
+       end
+     else if (rxvalid & (rxtype[2:0] == 3'b100))
+       begin
+          lnk_sop[1:0]            <= lnk_sop_next[1:0];
+          lnk_rxdata_mask[CW-1:0] <= (lnk_sop_next[1:0] == 2'b00) ?
+                                     ~({CW{1'b1}}<<(iowidth<<3))  :
+                                     lnk_rxdata_mask[CW-1:0] << (iowidth*8);
+          lnk_shiftreg[CW-1:0]    <= (lnk_sop[1:0] == 2'b00) ?
+                                     rxdata[CW-1:0] :
+                                     (rxdata[CW-1:0] << (lnk_sop_bit<<3)) & lnk_rxdata_mask[CW-1:0] |
+                                     lnk_shiftreg[CW-1:0] & ~lnk_rxdata_mask[CW-1:0];
+          lnk_fifo_wr             <= rxvalid & (rxtype[2:0] == 3'b100) & (lnk_sop_next[1:0] == 2'b00);
+       end
+
+   assign lnk_fifo_rd          = ~lnk_fifo_empty;
+   assign lnk_fifo_din[CW-1:0] = lnk_shiftreg[CW-1:0];
 
    la_asyncfifo #(.DW(CW)  ,  // Link commands are only 32b
                   .DEPTH(8),  // FIFO depth
@@ -631,32 +674,8 @@ module lumi_rx
               .wr_din           (lnk_fifo_din[CW-1:0]),
               .rd_en            (lnk_fifo_rd));
 
-   assign lnk_sop_next[1:0] = lnk_sop[1:0] + iowidth[1:0];
-
-   // For shift left
-   assign lnk_sop_bit[4:0] = {3'b000,lnk_sop[1:0]};
-
-   always @(posedge clk or negedge nreset)
-     if (~nreset)
-       begin
-          lnk_sop[1:0]               <= 'h0;
-          lnk_fifo_dout_mask[CW-1:0] <= 'h0;
-          lnk_shiftreg[CW-1:0]       <= 'h0;
-       end
-     else if (lnk_fifo_rd)
-       begin
-          lnk_sop[1:0]               <= lnk_sop_next[1:0];
-          lnk_fifo_dout_mask[CW-1:0] <= (lnk_sop_next[1:0] == 2'b00) ?
-                                        ~({CW{1'b1}}<<(iowidth<<3))  :
-                                        lnk_fifo_dout_mask[CW-1:0] << (iowidth*8);
-          lnk_shiftreg[CW-1:0]       <= (lnk_sop[1:0] == 2'b00) ?
-                                        lnk_fifo_dout[CW-1:0] :
-                                        (lnk_fifo_dout[CW-1:0] << (lnk_sop_bit<<3)) & lnk_fifo_dout_mask[CW-1:0] |
-                                        lnk_shiftreg[CW-1:0] & ~lnk_fifo_dout_mask[CW-1:0];
-       end
-
    /*umi_unpack AUTO_TEMPLATE(
-    .packet_cmd        (lnk_shiftreg[]),
+    .packet_cmd        (lnk_fifo_dout[]),
     .cmd_user_extended (lnk_cmd_user[]),
     .cmd_.*            (),
     );*/
@@ -677,22 +696,15 @@ module lumi_rx
                .cmd_err         (),                      // Templated
                .cmd_hostid      (),                      // Templated
                // Inputs
-               .packet_cmd      (lnk_shiftreg[CW-1:0])); // Templated
+               .packet_cmd      (lnk_fifo_dout[CW-1:0])); // Templated
 
    //########################################
-   //# "steal" incoming credit update
+   //# Incoming credit update
    //########################################
-   always @(posedge clk or negedge nreset)
-     if (~nreset)
-       lnk_cmd_vld <= 'h0;
-     else
-       lnk_cmd_vld <= lnk_fifo_rd &
-                      (lnk_sop_next[1:0] == 2'b00);
-
-   assign credit_req_in[0] = lnk_cmd_vld &
+   assign credit_req_in[0] = lnk_fifo_rd &
                              ((lnk_cmd_user[7:0] == 8'h01) | (lnk_cmd_user[7:0] == 8'h02));
 
-   assign credit_req_in[1] = lnk_cmd_vld &
+   assign credit_req_in[1] = lnk_fifo_rd &
                              ((lnk_cmd_user[7:0] == 8'h11) | (lnk_cmd_user[7:0] == 8'h12));
 
    always @(posedge clk or negedge nreset)
@@ -709,6 +721,37 @@ module lumi_rx
             rmt_crdt_resp <= lnk_cmd_user[23:8];
        end
 
+   //########################################
+   // Credit init receive
+   //########################################
+   // Starting at link up each Tx will send credit init messages
+   // This will indicate to the other side that lumi framing is in progress
+   // Once the first valid credit init message is received lumi is locked
+   // and credit updates will be sent
+
+   always @(posedge clk or negedge nreset)
+     if (~nreset)
+       begin
+          loc_crdt_init[1:0] <= 2'b11;
+          rmt_crdt_init[1:0] <= 2'b11;
+       end
+     else if (~csr_en)
+       begin
+          loc_crdt_init[1:0] <= 2'b11;
+          rmt_crdt_init[1:0] <= 2'b11;
+       end
+     else
+       begin
+          if (credit_req_in[0]) // init or update
+            loc_crdt_init[0] <= 1'b0;
+          if (credit_req_in[1]) // init or update
+            loc_crdt_init[1] <= 1'b0;
+          if (credit_req_in[0] & (lnk_cmd_user[7:0] == 8'h02)) // update only
+            rmt_crdt_init[0] <= 1'b0;
+          if (credit_req_in[1] & (lnk_cmd_user[7:0] == 8'h12)) // update only
+            rmt_crdt_init[1] <= 1'b0;
+       end
+
    //########################################
    // Everything from this point on is duplicated
    // for request and response in order to prever deadlocks
diff --git a/lumi/rtl/lumi_tx.v b/lumi/rtl/lumi_tx.v
index 136009f..5090f77 100644
--- a/lumi/rtl/lumi_tx.v
+++ b/lumi/rtl/lumi_tx.v
@@ -1,16 +1,25 @@
-/******************************************************************************
- * Function:  Link UMI (LUMI) transmit
- * Author:    Amir Volk
- * Copyright: 2023 Zero ASIC Corporation
+/*******************************************************************************
+ * Copyright 2023 Zero ASIC Corporation
  *
- * License: This file contains confidential and proprietary information of
- * Zero ASIC. This file may only be used in accordance with the terms and
- * conditions of a signed license agreement with Zero ASIC. All other use,
- * reproduction, or distribution of this software is strictly prohibited.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- * Version history:
- * Version 1 - convert from CLINK to LUMI
- *****************************************************************************/
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
+ *
+ * Documentation:
+ * - LUMI Transmit module
+ *
+ ******************************************************************************/
+
 module lumi_tx
   #(parameter TARGET = "DEFAULT", // implementation target
     // for development only (fixed )
@@ -52,7 +61,9 @@ module lumi_tx
     input [15:0]      rmt_crdt_req,
     input [15:0]      rmt_crdt_resp,
     input [15:0]      loc_crdt_req,
-    input [15:0]      loc_crdt_resp
+    input [15:0]      loc_crdt_resp,
+    input [1:0]       loc_crdt_init,
+    input [1:0]       rmt_crdt_init
     );
 
    // local state
@@ -112,14 +123,14 @@ module lumi_tx
    wire [11:0]                    cmd_req_bytes;
    reg [11:0]                     req_packet_bytes;
    reg [11:0]                     resp_packet_bytes;
-   reg [11:0]                     req_packet_lines;
-   reg [11:0]                     resp_packet_lines;
-   reg [11:0]                     req_packet_mod;
-   reg [11:0]                     resp_packet_mod;
-   reg [15:0]                     req_crdt_need;
-   reg [15:0]                     resp_crdt_need;
-   reg [15:0]                     req_crdt_avail;
-   reg [15:0]                     resp_crdt_avail;
+   wire [11:0]                    req_packet_lines;
+   wire [11:0]                    resp_packet_lines;
+   wire [11:0]                    req_packet_mod;
+   wire [11:0]                    resp_packet_mod;
+   wire [15:0]                    req_crdt_need;
+   wire [15:0]                    resp_crdt_need;
+   wire [15:0]                    req_crdt_avail;
+   wire [15:0]                    resp_crdt_avail;
    reg [15:0]                     crdt_updt_cntr;
    reg [1:0]                      crdt_updt_send;
 
@@ -180,12 +191,16 @@ module lumi_tx
           tx_crdt_req[15:0]  <= 'h0;
           tx_crdt_resp[15:0] <= 'h0;
        end
-     else
-       if (phy_fifo_wr & phy_txrdy)
-         begin
-            tx_crdt_resp[15:0] <= tx_crdt_resp[15:0] + {15'h0,shift_reg_type[1]};
-            tx_crdt_req[15:0]  <= tx_crdt_req[15:0]  + {15'h0,shift_reg_type[0]};
-         end
+     else if (~csr_en)
+       begin
+          tx_crdt_req[15:0]  <= 'h0;
+          tx_crdt_resp[15:0] <= 'h0;
+          end
+     else if (phy_fifo_wr & phy_txrdy)
+       begin
+          tx_crdt_resp[15:0] <= tx_crdt_resp[15:0] + {15'h0,shift_reg_type[1]};
+          tx_crdt_req[15:0]  <= tx_crdt_req[15:0]  + {15'h0,shift_reg_type[0]};
+       end
 
    // Credit status - count cycles of no-credit
 
@@ -219,7 +234,7 @@ module lumi_tx
      if (~nreset)
        crdt_updt_send <= 2'b00;
      else
-       if (crdt_updt_cntr == csr_crdt_intrvl)
+       if (csr_crdt_en & (crdt_updt_cntr == csr_crdt_intrvl))
          crdt_updt_send <= 2'b01;
        else
          crdt_updt_send <= (|crdt_updt_send) & sample_packet ?
@@ -265,10 +280,14 @@ module lumi_tx
    // Muxing the umi_mux output with sending credit updates
    // Change the order to send resp credits first so in case both are pending
    // response will get credits first
+   wire [3:0] req_crdt_msg, resp_crdt_msg;
+   assign req_crdt_msg  = loc_crdt_init[0] ? 4'h1 : 4'h2;
+   assign resp_crdt_msg = loc_crdt_init[1] ? 4'h1 : 4'h2;
+
    assign umi_muxed_cmd = crdt_updt_send[1] ?
-                          {loc_crdt_req[15:0],4'h0,4'h2,8'h2F}  :
+                          {loc_crdt_req[15:0],4'h0,req_crdt_msg[3:0],8'h2F}  :
                           crdt_updt_send[0] ?
-                          {loc_crdt_resp[15:0],4'h1,4'h2,8'h2F} :
+                          {loc_crdt_resp[15:0],4'h1,resp_crdt_msg[3:0],8'h2F} :
                           umi_out_cmd;
 
    // response takes precedence over request
@@ -278,7 +297,7 @@ module lumi_tx
    assign umi_req_in_gated  = umi_req_in_valid  & phy_txrdy & rxready[0] & ~(|crdt_updt_send);
    assign umi_resp_in_gated = umi_resp_in_valid & phy_txrdy & rxready[1] & ~(|crdt_updt_send);
 
-   assign lumi_txrdy        = ((~|valid[(DW+AW+AW+CW)/8-1:0]) | (~|valid_next[(DW+AW+AW+CW)/8-1:0]));
+   assign lumi_txrdy        = csr_en & ((~|valid[(DW+AW+AW+CW)/8-1:0]) | (~|valid_next[(DW+AW+AW+CW)/8-1:0]));
    assign umi_req_in_ready  = umi_req_ready  & umi_req_in_gated & ~umi_resp_in_gated;
    assign umi_resp_in_ready = umi_resp_ready & umi_resp_in_gated;
 
@@ -355,8 +374,10 @@ module lumi_tx
    assign req_crdt_avail[15:0]  = (rmt_crdt_req[15:0]  - tx_crdt_req[15:0] - {15'h0,phy_fifo_wr & phy_txrdy & shift_reg_type[0]});
    assign resp_crdt_avail[15:0] = (rmt_crdt_resp[15:0] - tx_crdt_resp[15:0]- {15'h0,phy_fifo_wr & phy_txrdy & shift_reg_type[1]});
 
-   assign rxready[0] = req_crdt_avail[15:0]  >= req_crdt_need[15:0];
-   assign rxready[1] = resp_crdt_avail[15:0] >= resp_crdt_need[15:0];
+   // If credit mechanism is not enabled Tx works in infinite credit mode
+   // Do not start sending packets until remote side finished credit init
+   assign rxready[0] = ~(csr_crdt_en) | ~(|rmt_crdt_init[1:0]) & (req_crdt_avail[15:0]  >= req_crdt_need[15:0]);
+   assign rxready[1] = ~(csr_crdt_en) | ~(|rmt_crdt_init[1:0]) & (resp_crdt_avail[15:0] >= resp_crdt_need[15:0]);
 
    assign phy_fifo_wr = |valid[(DW+AW+AW+CW)/8-1:0];
 
@@ -577,7 +598,7 @@ module lumi_tx
                   .CTRLW(1),         // width of asic ctrl interface
                   .TESTW(1),         // width of asic test interface
                   .TYPE("DEFAULT"))  // Pass through variable for hard macro
-   req_fifo_i(// Outputs
+   phy_fifo_i(// Outputs
               .wr_full          (phy_fifo_full),
               .rd_dout          (phy_txdata[IOW-1:0]),
               .rd_empty         (phy_fifo_empty),
diff --git a/submodules/lambdalib b/submodules/lambdalib
index e9ff56c..5245fd7 160000
--- a/submodules/lambdalib
+++ b/submodules/lambdalib
@@ -1,1 +1,1 @@
-Subproject commit e9ff56c7fda8802c3d752d6d06d5df35b9012a0d
+Subproject commit 5245fd7cde572a16532690dfda733b60cd8b0271
diff --git a/submodules/switchboard b/submodules/switchboard
index 00db121..dd5a7b1 160000
--- a/submodules/switchboard
+++ b/submodules/switchboard
@@ -1,1 +1,1 @@
-Subproject commit 00db121a19622bc638a584eea1f3e0651fa33851
+Subproject commit dd5a7b193c091a7c3c572151e9930a3486097f9d
diff --git a/umi/rtl/umi_arbiter.v b/umi/rtl/umi_arbiter.v
index 85b9cc8..9a8431c 100644
--- a/umi/rtl/umi_arbiter.v
+++ b/umi/rtl/umi_arbiter.v
@@ -1,22 +1,25 @@
 /*******************************************************************************
- * Function:  UMI Arbiter
- * Author:    Andreas Olofsson
- * License:   (c) 2023 Zero ASIC Corporation
+ * Copyright 2020 Zero ASIC Corporation
  *
- * Documentation:
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * - Dynamically configurable arbiter (fixed, roundrobin, ...)
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  *
- * - mode[1:0]:
- * -     00 = priority
- * -     01 = round robin
- * -     10 = reserved
- * -     11 = reserved
+ * ----
  *
- * TODO: Support a round robin arbiter. Current scheme has bugs that can cause
- * deadlock.
+ * Documentation:
+ * - Dynamically configurable arbiter (fixed, roundrobin, reserve,...)
  *
  ******************************************************************************/
+
 module umi_arbiter
   #(parameter N      = 4,         // number of inputs
     parameter TARGET = "DEFAULT"  // SIM, ASIC, FPGA, ...
diff --git a/umi/rtl/umi_combiner.v b/umi/rtl/umi_combiner.v
deleted file mode 100644
index 4c8313e..0000000
--- a/umi/rtl/umi_combiner.v
+++ /dev/null
@@ -1,72 +0,0 @@
-/*******************************************************************************
- * Function:  UMI Traffic Combiner (2:1 Mux)
- * Author:    Andreas Olofsson
- * License:
- *
- * Documentation:
- *
- * - Splits up traffic based on type.
- * - UMI 0 carries high priority traffic ("writes")
- * - UMI 1 carries low priority traffic ("read requests")
- * - No cycles allowed since this would deadlock
- * - Traffic source must be self throttling
- *
- ******************************************************************************/
-module umi_combiner
-  #(// standard parameters
-    parameter AW   = 64,
-    parameter CW   = 32,
-    parameter DW   = 256)
-   (// controls
-    input           clk,
-    input           nreset,
-    // Input (0), Higher Priority
-    input           umi_resp_in_valid,
-    input [CW-1:0]  umi_resp_in_cmd,
-    input [AW-1:0]  umi_resp_in_dstaddr,
-    input [AW-1:0]  umi_resp_in_srcaddr,
-    input [DW-1:0]  umi_resp_in_data,
-    output          umi_resp_in_ready,
-    // Input (1)
-    input           umi_req_in_valid,
-    input [CW-1:0]  umi_req_in_cmd,
-    input [AW-1:0]  umi_req_in_dstaddr,
-    input [AW-1:0]  umi_req_in_srcaddr,
-    input [DW-1:0]  umi_req_in_data,
-    output          umi_req_in_ready,
-    // Output
-    output          umi_out_valid,
-    output [CW-1:0] umi_out_cmd,
-    output [AW-1:0] umi_out_dstaddr,
-    output [AW-1:0] umi_out_srcaddr,
-    output [DW-1:0] umi_out_data,
-    input           umi_out_ready
-    );
-
-   // local wires
-   wire             umi_resp_ready;
-   wire             umi_req_ready;
-
-   umi_mux #(.N(2))
-   umi_mux (// Outputs
-            .umi_in_ready      ({umi_req_ready,umi_resp_ready}),
-            .umi_out_valid     (umi_out_valid),
-            .umi_out_cmd       (umi_out_cmd[CW-1:0]),
-            .umi_out_dstaddr   (umi_out_dstaddr[AW-1:0]),
-            .umi_out_srcaddr   (umi_out_srcaddr[AW-1:0]),
-            .umi_out_data      (umi_out_data[DW-1:0]),
-            // Inputs
-            .umi_in_valid      ({umi_req_in_valid, umi_resp_in_valid}),
-            .umi_in_cmd        ({umi_req_in_cmd, umi_resp_in_cmd}),
-            .umi_in_dstaddr    ({umi_req_in_dstaddr, umi_resp_in_dstaddr}),
-            .umi_in_srcaddr    ({umi_req_in_srcaddr, umi_resp_in_srcaddr}),
-            .umi_in_data       ({umi_req_in_data, umi_resp_in_data}),
-            /*AUTOINST*/
-            // Inputs
-            .umi_out_ready      (umi_out_ready));
-
-   // Flow through pushback
-   assign umi_resp_in_ready = umi_out_ready & umi_resp_ready;
-   assign umi_req_in_ready = umi_out_ready & umi_req_ready;
-
-endmodule // umi_splitter
diff --git a/umi/rtl/umi_crossbar.v b/umi/rtl/umi_crossbar.v
index 58e960c..6bfab00 100644
--- a/umi/rtl/umi_crossbar.v
+++ b/umi/rtl/umi_crossbar.v
@@ -1,15 +1,23 @@
 /*******************************************************************************
- * Function:  UMI NxN Crossbar
- * Author:    Andreas Olofsson
- * License:   (c) 2023 Zero ASIC Corporation
+ * Copyright 2020 Zero ASIC Corporation
  *
- * Documentation:
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * The crossbar is pipelined and non-blocking, allowing for any-to-any
- * simultaneous input to output connections.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  *
- * The input request vector is a concatenated vectors of inputs
- * requesting outputs ports per the order below.
+ * ----
+ *
+ * Documentation:
+ * - Pipelined non-blocking NxN crossbar
+ * - Input request vector is a concatenated vectors of inputs:
  *
  * [0]     = input 0   requesting output 0
  * [1]     = input 1   requesting output 0
@@ -25,6 +33,7 @@
  * which follows ordering of the input valid convention shown above.
  *
  ******************************************************************************/
+
 module umi_crossbar
   #(parameter TARGET = "DEFAULT", // implementation target
     parameter DW = 256,           // UMI width
diff --git a/umi/rtl/umi_decode.v b/umi/rtl/umi_decode.v
index 86bcaf0..9e3c2a1 100644
--- a/umi/rtl/umi_decode.v
+++ b/umi/rtl/umi_decode.v
@@ -1,12 +1,25 @@
 /*******************************************************************************
- * Function:  Universal Memory Interface (UMI) Command Decoder
- * Author:    Andreas Olofsson
- * License:
+ * Copyright 2020 Zero ASIC Corporation
  *
- * Documentation:
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  *
+ * ----
+ *
+ * Documentation:
+ * - UMI command decoder
  *
  ******************************************************************************/
+
 module umi_decode #(parameter CW = 32)
    (
     // Packet Command
diff --git a/umi/rtl/umi_endpoint.v b/umi/rtl/umi_endpoint.v
index 9e9dcec..ebba914 100644
--- a/umi/rtl/umi_endpoint.v
+++ b/umi/rtl/umi_endpoint.v
@@ -1,14 +1,27 @@
 /*******************************************************************************
- * Function:  UMI Simple Endpoint
- * Author:    Andreas Olofsson
- * License:
+ * Copyright 2020 Zero ASIC Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the 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.
+ * - A simple register file UMI device endpoint.
+ * - It can only receive UMI requests that require a single response beat.
+ * - (udev_req_cmd.len + 1)*(1 << udev_req_cmd.size) <= DW/8.
  *
  ******************************************************************************/
+
 module umi_endpoint
   #(parameter REG  = 0,       // 1=insert register on read_data
     parameter TYPE = "LIGHT", // FULL, LIGHT
diff --git a/umi/rtl/umi_fifo.v b/umi/rtl/umi_fifo.v
index 16a5213..db03c1f 100644
--- a/umi/rtl/umi_fifo.v
+++ b/umi/rtl/umi_fifo.v
@@ -1,12 +1,27 @@
 /*******************************************************************************
- * Function:  UMI FIFO
- * Author:    Andreas Olofsson
- * License:   (c) 2022 Zero ASIC Corporation
+ * Copyright 2020 Zero ASIC Corporation
  *
- * Documentation:
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
+ *
+ * ##Documentation##
+ *
+ * - Asynchronous UMI FIFO
+ * - Separate read and write clocks
  *
  ******************************************************************************/
+
 module umi_fifo
   #(parameter TARGET  = "DEFAULT", // implementation target
     parameter DEPTH   = 4,         // FIFO depth
@@ -15,43 +30,43 @@ module umi_fifo
     parameter DW      = 256        // UMI width
     )
    (// control/status signals
-    input 	    bypass, // bypass FIFO
-    input 	    chaosmode, // enable "random" fifo pushback
-    output 	    fifo_full,
-    output 	    fifo_empty,
+    input           bypass, // bypass FIFO
+    input           chaosmode, // enable "random" fifo pushback
+    output          fifo_full,
+    output          fifo_empty,
     // Input
-    input 	    umi_in_clk,
-    input 	    umi_in_nreset,
-    input 	    umi_in_valid,//per byte valid signal
+    input           umi_in_clk,
+    input           umi_in_nreset,
+    input           umi_in_valid,//per byte valid signal
     input [CW-1:0]  umi_in_cmd,
     input [AW-1:0]  umi_in_dstaddr,
     input [AW-1:0]  umi_in_srcaddr,
     input [DW-1:0]  umi_in_data,
-    output 	    umi_in_ready,
+    output          umi_in_ready,
     // Output
-    input 	    umi_out_clk,
-    input 	    umi_out_nreset,
-    output 	    umi_out_valid,
+    input           umi_out_clk,
+    input           umi_out_nreset,
+    output          umi_out_valid,
     output [CW-1:0] umi_out_cmd,
     output [AW-1:0] umi_out_dstaddr,
     output [AW-1:0] umi_out_srcaddr,
     output [DW-1:0] umi_out_data,
-    input 	    umi_out_ready,
+    input           umi_out_ready,
     // Supplies
-    input 	    vdd,
-    input 	    vss
+    input           vdd,
+    input           vss
     );
 
    // local state
-   reg 		    fifo_out_valid;
+   reg              fifo_out_valid;
    reg [DW-1:0]     fifo_out_data;
 
    // local wires
-   wire 	    umi_out_beat;
-   wire 	    fifo_read;
+   wire             umi_out_beat;
+   wire             fifo_read;
    wire             fifo_write;
    wire [DW+AW+AW+CW-1:0] fifo_dout;
-   wire 	    fifo_in_ready;
+   wire             fifo_in_ready;
    wire             sync_nreset;
 
    //#################################
@@ -77,24 +92,24 @@ module umi_fifo
    //#################################
 
    la_asyncfifo  #(.DW(CW+AW+AW+DW),
-		   .DEPTH(DEPTH))
+                   .DEPTH(DEPTH))
    fifo  (// Outputs
-	  .wr_full	(fifo_full),
-	  .rd_dout	(fifo_dout[DW+AW+AW+CW-1:0]),
-	  .rd_empty	(fifo_empty),
-	  // Inputs
-	  .wr_clk	(umi_in_clk),
-	  .wr_nreset	(umi_in_nreset),
-	  .wr_din	({umi_in_data[DW-1:0],umi_in_srcaddr[AW-1:0],umi_in_dstaddr[AW-1:0],umi_in_cmd[CW-1:0]}),
-	  .wr_en	(umi_in_valid & sync_nreset),
-	  .wr_chaosmode (chaosmode),
-	  .rd_clk	(umi_out_clk),
-	  .rd_nreset	(umi_out_nreset),
-	  .rd_en	(fifo_read),
-	  .vss		(vss),
-	  .vdd		(vdd),
-	  .ctrl		(1'b0),
-	  .test		(1'b0));
+          .wr_full      (fifo_full),
+          .rd_dout      (fifo_dout[DW+AW+AW+CW-1:0]),
+          .rd_empty     (fifo_empty),
+          // Inputs
+          .wr_clk       (umi_in_clk),
+          .wr_nreset    (umi_in_nreset),
+          .wr_din       ({umi_in_data[DW-1:0],umi_in_srcaddr[AW-1:0],umi_in_dstaddr[AW-1:0],umi_in_cmd[CW-1:0]}),
+          .wr_en        (umi_in_valid & sync_nreset),
+          .wr_chaosmode (chaosmode),
+          .rd_clk       (umi_out_clk),
+          .rd_nreset    (umi_out_nreset),
+          .rd_en        (fifo_read),
+          .vss          (vss),
+          .vdd          (vdd),
+          .ctrl         (1'b0),
+          .test         (1'b0));
 
    //#################################
    // FIFO Bypass
diff --git a/umi/rtl/umi_fifo_flex.v b/umi/rtl/umi_fifo_flex.v
index 0974325..a028592 100644
--- a/umi/rtl/umi_fifo_flex.v
+++ b/umi/rtl/umi_fifo_flex.v
@@ -1,20 +1,33 @@
 /*******************************************************************************
- * Function:  UMI FIFO with width change
- * Author:    Amir Volk
- * License:   (c) 2023 Zero ASIC Corporation
+ * Copyright 2020 Zero ASIC Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
  *
  * Documentation:
- * This block converts UMI transactions between different width options
- * Ver 1 - only split large width to small, no merge small->large
+ * - Converts UMI transactions between different width options.
+ * - Currently does not support merge small -> large
  *
- * TODO Future enhancements:
+ * Future enhancements:
  * 1. merge small->large transactions (adds latency)
  * 2. do not split large->small transactions in case they carry no data
  *
  * Known limitation/bugs:
- * 1. does not handle cases where SIZE>ODW (does not manipulate SIZE)
+ * - Does not handle cases where SIZE>ODW (does not manipulate SIZE)
  *
  ******************************************************************************/
+
 module umi_fifo_flex
   #(parameter TARGET = "DEFAULT", // implementation target
     parameter ASYNC = 0,
diff --git a/umi/rtl/umi_isolate.v b/umi/rtl/umi_isolate.v
index 0183186..c812bf5 100644
--- a/umi/rtl/umi_isolate.v
+++ b/umi/rtl/umi_isolate.v
@@ -1,12 +1,26 @@
 /*******************************************************************************
- * Function:  UMI Power Isolation
- * Author:    Andreas Olofsson
- * License:
+ * Copyright 2020 Zero ASIC Corporation
  *
- * Documentation:
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
+ *
+ * ##Documentation##
+ *
+ * - Power domain isolation buffers
  *
  ******************************************************************************/
+
 module umi_isolate
   #(parameter CW = 32, // umi command width
     parameter AW = 64, // umi address width
@@ -33,46 +47,46 @@ module umi_isolate
 
    generate
       if(ISO)
-	begin : g0
-	   la_visolo #(.N(1))
+        begin : g0
+           la_visolo #(.N(1))
            i_ready (.in(umi_ready),
-		    .out(umi_ready_iso),
-		    .iso(isolate));
+                    .out(umi_ready_iso),
+                    .iso(isolate));
 
-	   la_visolo #(.N(1))
+           la_visolo #(.N(1))
            i_valid (.in(umi_valid),
-		    .out(umi_valid_iso),
-		    .iso(isolate));
+                    .out(umi_valid_iso),
+                    .iso(isolate));
 
-	   la_visolo #(.N(CW))
+           la_visolo #(.N(CW))
            i_cmd (.in(umi_cmd[CW-1:0]),
-		  .out(umi_cmd_iso[CW-1:0]),
-		  .iso(isolate));
+                  .out(umi_cmd_iso[CW-1:0]),
+                  .iso(isolate));
 
-	   la_visolo #(.N(AW))
+           la_visolo #(.N(AW))
            i_dstaddr (.in(umi_dstaddr[AW-1:0]),
-		      .out(umi_dstaddr_iso[AW-1:0]),
-		      .iso(isolate));
+                      .out(umi_dstaddr_iso[AW-1:0]),
+                      .iso(isolate));
 
            la_visolo #(.N(AW))
            i_srcaddr (.in(umi_srcaddr[AW-1:0]),
-		      .out(umi_srcaddr_iso[AW-1:0]),
-		      .iso(isolate));
+                      .out(umi_srcaddr_iso[AW-1:0]),
+                      .iso(isolate));
 
            la_visolo #(.N(DW))
            i_data (.in(umi_srcaddr[DW-1:0]),
-		   .out(umi_srcaddr_iso[DW-1:0]),
-		   .iso(isolate));
-	end
+                   .out(umi_srcaddr_iso[DW-1:0]),
+                   .iso(isolate));
+        end
       else
-	begin : g0
-	   assign umi_ready_iso           = umi_ready;
-	   assign umi_valid_iso           = umi_valid;
-	   assign umi_cmd_iso[CW-1:0]     = umi_cmd[CW-1:0];
+        begin : g0
+           assign umi_ready_iso           = umi_ready;
+           assign umi_valid_iso           = umi_valid;
+           assign umi_cmd_iso[CW-1:0]     = umi_cmd[CW-1:0];
            assign umi_dstaddr_iso[AW-1:0] = umi_dstaddr[AW-1:0];
            assign umi_srcaddr_iso[AW-1:0] = umi_srcaddr[AW-1:0];
            assign umi_data_iso[DW-1:0]    = umi_data[DW-1:0];
-	end
+        end
 
    endgenerate
 
diff --git a/umi/rtl/umi_mem_agent.v b/umi/rtl/umi_mem_agent.v
index 45e67e0..0779197 100644
--- a/umi/rtl/umi_mem_agent.v
+++ b/umi/rtl/umi_mem_agent.v
@@ -1,18 +1,27 @@
-/******************************************************************************
- * Function:  UMI memory agent
- * Author:    Amir Volk
- * Copyright: (c) 2023 Zero ASIC. All rights reserved.
+/*******************************************************************************
+ * Copyright 2020 Zero ASIC Corporation
  *
- * License: This file contains confidential and proprietary information of
- * Zero ASIC. This file may only be used in accordance with the terms and
- * conditions of a signed license agreement with Zero ASIC. All other use,
- * reproduction, or distribution of this software is strictly prohibited.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- * This block is implementing a simple memory array for use in simulation
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Limitation - transaction cannot cross the DW boundary (need to be split at the request side)
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  *
- ****************************************************************************/
+ * ----
+ *
+ * Documentation:
+ * - Implements a simple memory array for use in simulation
+ *
+ * Known limitation/bugs:
+ * - Transaction cannot cross the DW boundary
+ *
+ ******************************************************************************/
 
 module umi_mem_agent
   #(parameter DW = 256,           // umi packet width
diff --git a/umi/rtl/umi_messages.vh b/umi/rtl/umi_messages.vh
index 5bca9f3..245cacf 100644
--- a/umi/rtl/umi_messages.vh
+++ b/umi/rtl/umi_messages.vh
@@ -1,17 +1,24 @@
 /*******************************************************************************
- * Function:  UMI Opcodes
- * Author:    Andreas Olofsson
- * License:
+ * Copyright 2020 Zero ASIC Corporation
  *
- * Documentation:
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- * This file defines all UMI commands.
- * command[7:4] is used for non-functional
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * This file describes the standard opcodes for umi transactions.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
+ *
+ * ##Documentation##
+ *
+ * - This file defines all UMI commands.
  *
- * opcode[3:0] dictates transaction types
- * opcode[7:4] is used for hints and transaction options.
  *
  ******************************************************************************/
 
@@ -20,21 +27,21 @@ localparam UMI_INVALID         = 8'h00;
 // Requests (host -> device)
 localparam UMI_REQ_READ        = 5'h01; // read/load
 localparam UMI_REQ_WRITE       = 5'h03; // write/store with ack
-localparam UMI_REQ_POSTED      = 5'h05;
-localparam UMI_REQ_RDMA        = 5'h07;
+localparam UMI_REQ_POSTED      = 5'h05; // posted write
+localparam UMI_REQ_RDMA        = 5'h07; // remote DMA command
 localparam UMI_REQ_ATOMIC      = 5'h09; // alias for all atomics
-localparam UMI_REQ_USER0       = 5'h0B;
-localparam UMI_REQ_FUTURE0     = 5'h0D;
-localparam UMI_REQ_ERROR       = 8'h0F;
-localparam UMI_REQ_LINK        = 8'h2F;
+localparam UMI_REQ_USER0       = 5'h0B; // reserved for user
+localparam UMI_REQ_FUTURE0     = 5'h0D; // reserved fur future use
+localparam UMI_REQ_ERROR       = 8'h0F; // reserved for error message
+localparam UMI_REQ_LINK        = 8'h2F; // reserved for link ctrl
 // Response (device -> host)
 localparam UMI_RESP_READ       = 5'h02; // response to read request
 localparam UMI_RESP_WRITE      = 5'h04; // response (ack) from write request
 localparam UMI_RESP_USER0      = 5'h06; // signal write without ack
-localparam UMI_RESP_USER1      = 5'h08;
-localparam UMI_RESP_FUTURE0    = 5'h0A;
-localparam UMI_RESP_FUTURE1    = 5'h0C;
-localparam UMI_RESP_LINK       = 8'h0E;
+localparam UMI_RESP_USER1      = 5'h08; // reserved for user
+localparam UMI_RESP_FUTURE0    = 5'h0A; // reserved for future use
+localparam UMI_RESP_FUTURE1    = 5'h0C; // reserved for future use
+localparam UMI_RESP_LINK       = 8'h0E; // reserved for link ctrl
 
 localparam UMI_REQ_ATOMICADD   = 8'h00;
 localparam UMI_REQ_ATOMICAND   = 8'h01;
diff --git a/umi/rtl/umi_mux.v b/umi/rtl/umi_mux.v
index 8762fc8..d5749fe 100644
--- a/umi/rtl/umi_mux.v
+++ b/umi/rtl/umi_mux.v
@@ -1,16 +1,30 @@
 /*******************************************************************************
- * Function:  UMI Mux (one-hot)
- * Author:    Andreas Olofsson
- * License:
+ * Copyright 2020 Zero ASIC Corporation
  *
- * Documentation:
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
+ *
+ * ##Documentation##
  *
  * - Selects between N inputs
  * - Assumes one-hot selects
- * - NOTE: The input ready is combinatorially connected to the output ready.
- *   Please make sure your surrounding logic does not create a timing loop.
+ * - WARNING: input ready is combinatorially connected to the output ready.
  *
  ******************************************************************************/
+
+
+
 module umi_mux
   #(parameter DW = 256, // UMI transaction width
     parameter CW = 32,
@@ -25,8 +39,8 @@ module umi_mux
     input [N*DW-1:0] umi_in_data,
     output [N-1:0]   umi_in_ready,
     // Outgoing UMI
-    output 	     umi_out_valid,
-    input 	     umi_out_ready,
+    output           umi_out_valid,
+    input            umi_out_ready,
     output [CW-1:0]  umi_out_cmd,
     output [AW-1:0]  umi_out_dstaddr,
     output [AW-1:0]  umi_out_srcaddr,
@@ -41,30 +55,30 @@ module umi_mux
 
    // packet mux
    la_vmux #(.N(N),
-	     .W(CW))
+             .W(CW))
    la_cmd_vmux(.out (umi_out_cmd[CW-1:0]),
-	       .sel (umi_in_valid[N-1:0]),
-	       .in  (umi_in_cmd[N*CW-1:0]));
+               .sel (umi_in_valid[N-1:0]),
+               .in  (umi_in_cmd[N*CW-1:0]));
 
    // packet mux
    la_vmux #(.N(N),
-	     .W(AW))
+             .W(AW))
    la_dstaddr_vmux(.out (umi_out_dstaddr[AW-1:0]),
-	           .sel (umi_in_valid[N-1:0]),
-	           .in  (umi_in_dstaddr[N*AW-1:0]));
+                   .sel (umi_in_valid[N-1:0]),
+                   .in  (umi_in_dstaddr[N*AW-1:0]));
 
    // packet mux
    la_vmux #(.N(N),
-	     .W(AW))
+             .W(AW))
    la_srcaddr_vmux(.out (umi_out_srcaddr[AW-1:0]),
-	           .sel (umi_in_valid[N-1:0]),
-	           .in  (umi_in_srcaddr[N*AW-1:0]));
+                   .sel (umi_in_valid[N-1:0]),
+                   .in  (umi_in_srcaddr[N*AW-1:0]));
 
    // packet mux
    la_vmux #(.N(N),
-	     .W(DW))
+             .W(DW))
    la_data_vmux(.out (umi_out_data[DW-1:0]),
-	        .sel (umi_in_valid[N-1:0]),
-	        .in  (umi_in_data[N*DW-1:0]));
+                .sel (umi_in_valid[N-1:0]),
+                .in  (umi_in_data[N*DW-1:0]));
 
 endmodule
diff --git a/umi/rtl/umi_pack.v b/umi/rtl/umi_pack.v
index e71df5f..c8f6c36 100644
--- a/umi/rtl/umi_pack.v
+++ b/umi/rtl/umi_pack.v
@@ -1,12 +1,26 @@
 /*******************************************************************************
- * Function:  Universal Memory Interface (UMI) Packer
- * Author:    Andreas Olofsson
- * License:
+ * Copyright 2020 Zero ASIC Corporation
  *
- * Documentation:
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
+ *
+ * ##Documentation##
+ *
+ * - Packs ctrl fields into a single 32-bit command
  *
  ******************************************************************************/
+
 module umi_pack #(parameter CW = 32)
    (
     // Command inputs
diff --git a/umi/rtl/umi_pipeline.v b/umi/rtl/umi_pipeline.v
index c8e9b2d..0d251aa 100644
--- a/umi/rtl/umi_pipeline.v
+++ b/umi/rtl/umi_pipeline.v
@@ -1,39 +1,49 @@
 /*******************************************************************************
- * Function:  UMI Pipeline Stage
- * Author:    Andreas Olofsson
- * License:
+ * Copyright 2020 Zero ASIC Corporation
  *
- * Documentation:
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * -This module create a single cycle umi pipeline.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  *
- * -The "umi_in_ready" output is omitted to make it clear that the ready signal
- * must be broadcasted externally.
+ * ----
  *
- * -We don't reset the packet
+ * Documentation:
+ * - Single cycle umi pipeline
+ * - The "umi_in_ready" output is omitted to make it clear that the ready signal
+ *   must be broadcasted externally.
+ * - We don't reset the packet
  *
  ******************************************************************************/
+
 module umi_pipeline
   #(parameter CW  = 32,
     parameter AW  = 64,
     parameter DW  = 256
     )
    (// clock, reset
-    input 		clk,
-    input 		nreset,
+    input               clk,
+    input               nreset,
     // Incoming UMI request
-    input 		umi_in_valid,
-    input [CW-1:0] 	umi_in_cmd,
-    input [AW-1:0] 	umi_in_dstaddr,
-    input [AW-1:0] 	umi_in_srcaddr,
-    input [DW-1:0] 	umi_in_data,
+    input               umi_in_valid,
+    input [CW-1:0]      umi_in_cmd,
+    input [AW-1:0]      umi_in_dstaddr,
+    input [AW-1:0]      umi_in_srcaddr,
+    input [DW-1:0]      umi_in_data,
     // Outgoing UMI response
-    output reg 		umi_out_valid,
+    output reg          umi_out_valid,
     output reg [CW-1:0] umi_out_cmd,
     output reg [AW-1:0] umi_out_dstaddr,
     output reg [AW-1:0] umi_out_srcaddr,
     output reg [DW-1:0] umi_out_data,
-    input 		umi_out_ready
+    input               umi_out_ready
     );
 
    // valid
diff --git a/umi/rtl/umi_priority.v b/umi/rtl/umi_priority.v
index f54a67f..1c206d1 100644
--- a/umi/rtl/umi_priority.v
+++ b/umi/rtl/umi_priority.v
@@ -1,13 +1,27 @@
 /*******************************************************************************
- * Function:  UMI Priority Selector
- * Author:    Andreas Olofsson
- * License:
+ * Copyright 2020 Zero ASIC Corporation
  *
- * Documentation:
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
+ *
+ * ##Documentation##
+ *
+ * - Priority selector
  * - Index zero has highest priority.
  *
  ******************************************************************************/
+
 module umi_priority
   #(parameter N   = 4    // number of inputs
     )
@@ -16,13 +30,13 @@ module umi_priority
     );
 
    wire [N-1:0]   mask;
-   genvar 	  j;
+   genvar         j;
 
    // priority maskx
    assign mask[0] = 1'b0;
    for (j=N-1; j>=1; j=j-1)
      begin : ipri
-	assign mask[j] = |requests[j-1:0];
+        assign mask[j] = |requests[j-1:0];
      end
 
    // priority grant circuit
diff --git a/umi/rtl/umi_regif.v b/umi/rtl/umi_regif.v
index ec3d5ba..709fadd 100644
--- a/umi/rtl/umi_regif.v
+++ b/umi/rtl/umi_regif.v
@@ -1,7 +1,19 @@
 /*******************************************************************************
- * Function:  UMI Register Interface
- * Author:    Andreas Olofsson
- * License:
+ * Copyright 2020 Zero ASIC Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
  *
  * Documentation:
  *
@@ -17,6 +29,7 @@
  * Only read/writes <= DW is supported.
  *
  ******************************************************************************/
+
 module umi_regif
   #(parameter TARGET = "DEFAULT", // compile target
     parameter AW = 64,            // address width
@@ -103,13 +116,41 @@ module umi_regif
    wire                 cmd_resp;
    wire                 group_match;
    wire                 reg_resp;
+   reg                  atomic_wr;
+   reg [AW-1:0]         atomic_addr;
+   reg [RW-1:0]         atomic_data;
+   wire [RW-1:0]        atomic_wrdata;
+   reg                  atomic_add;
+   reg                  atomic_and;
+   reg                  atomic_or;
+   reg                  atomic_xor;
+   reg                  atomic_max;
+   reg                  atomic_min;
+   reg                  atomic_maxu;
+   reg                  atomic_minu;
+   reg                  atomic_swap;
+   wire                 signed_max;
+   wire                 unsigned_max;
 
    //########################
    // UMI INPUT
    //########################
 
-   assign reg_addr[AW-1:0]   = udev_req_dstaddr[AW-1:0];
-   assign reg_wrdata[RW-1:0] = udev_req_data[RW-1:0];
+   assign reg_addr[AW-1:0]   = atomic_wr ? atomic_addr[AW-1:0] : udev_req_dstaddr[AW-1:0];
+   assign reg_wrdata[RW-1:0] = atomic_wr ? atomic_wrdata[RW-1:0] : udev_req_data[RW-1:0];
+
+   assign signed_max = $signed(atomic_data[RW-1:0]) > $signed(reg_rddata[RW-1:0]);
+   assign unsigned_max = $unsigned(atomic_data[RW-1:0]) > $unsigned(reg_rddata[RW-1:0]);
+
+   assign atomic_wrdata[RW-1:0] = atomic_add  ? atomic_data[RW-1:0] + reg_rddata[RW-1:0] :
+                                  atomic_and  ? atomic_data[RW-1:0] & reg_rddata[RW-1:0] :
+                                  atomic_or   ? atomic_data[RW-1:0] | reg_rddata[RW-1:0] :
+                                  atomic_xor  ? atomic_data[RW-1:0] ^ reg_rddata[RW-1:0] :
+                                  (atomic_max  & ~signed_max   |
+                                   atomic_maxu & ~unsigned_max |
+                                   atomic_min  & signed_max    |
+                                   atomic_minu & unsigned_max  ) ?    reg_rddata[RW-1:0] :
+                                  atomic_data[RW-1:0]; // inlcd. swap
 
    /* umi_unpack AUTO_TEMPLATE(
     .cmd_\(.*\)     (reg_\1[]),
@@ -179,22 +220,44 @@ module umi_regif
    endgenerate
 
    // TODO - implement atomic
-   assign reg_read  = cmd_read & udev_req_valid & udev_req_ready & group_match;
-   assign reg_write = (cmd_write | cmd_write_posted) & udev_req_valid & udev_req_ready & group_match;
-   assign reg_resp  = (cmd_read | cmd_write) & udev_req_valid & udev_req_ready & group_match;
-
-   // single cycle stall on every ready
-   // Amir - BUG - there is no guarantee that in the next cycle after the
-   // read req the ready will be high, need to hold the data in that case
+   assign reg_read  = (cmd_read | cmd_atomic) & udev_req_valid & udev_req_ready & group_match;
+   assign reg_write = (cmd_write | cmd_write_posted) & udev_req_valid & udev_req_ready & group_match |
+                      atomic_wr;
+   assign reg_resp  = (cmd_read | cmd_write | cmd_atomic) & udev_req_valid & udev_req_ready & group_match;
 
-//   always @ (posedge clk or negedge nreset)
-//     if(!nreset)
-//       udev_req_ready <= 1'b0;
-//     else if (udev_req_valid & udev_resp_ready)
-//       udev_req_ready <= ~udev_req_ready;
-//     else
-//       udev_req_ready <= 1'b0;
+   always @ (posedge clk or negedge nreset)
+     if(!nreset)
+       begin
+          atomic_wr   <= 'b0;
+          atomic_addr <= 'b0;
+          atomic_data <= 'b0;
+          atomic_add  <= 'b0;
+          atomic_and  <= 'b0;
+          atomic_or   <= 'b0;
+          atomic_xor  <= 'b0;
+          atomic_max  <= 'b0;
+          atomic_min  <= 'b0;
+          atomic_maxu <= 'b0;
+          atomic_minu <= 'b0;
+          atomic_swap <= 'b0;
+       end
+     else
+       begin
+          atomic_wr   <= cmd_atomic & udev_req_valid & udev_req_ready & group_match;
+          atomic_addr <= udev_req_dstaddr;
+          atomic_data <= udev_req_data[RW-1:0];
+          atomic_add  <= cmd_atomic_add;
+          atomic_and  <= cmd_atomic_and;
+          atomic_or   <= cmd_atomic_or;
+          atomic_xor  <= cmd_atomic_xor;
+          atomic_max  <= cmd_atomic_max;
+          atomic_min  <= cmd_atomic_min;
+          atomic_maxu <= cmd_atomic_maxu;
+          atomic_minu <= cmd_atomic_minu;
+          atomic_swap <= cmd_atomic_swap;
+       end
 
+   // single cycle stall on every ready
    always @ (posedge clk or negedge nreset)
      if(!nreset)
        udev_req_ready <= 1'b0;
@@ -246,7 +309,8 @@ module umi_regif
 
    // Amir - response fields cannot assume that the request will be help
    // Therefore they need to be sampled when the request is acknowledged
-//   assign udev_resp_dstaddr[AW-1:0] = udev_req_srcaddr[AW-1:0];
+   // assign udev_resp_dstaddr[AW-1:0] = udev_req_srcaddr[AW-1:0];
+
    always @ (posedge clk or negedge nreset)
      if(!nreset)
        begin
@@ -261,7 +325,6 @@ module umi_regif
           udev_resp_srcaddr[AW-1:0] <= udev_req_dstaddr[AW-1:0];
        end
 
-//   assign udev_resp_srcaddr[AW-1:0] = {(AW){1'b0}};
    assign udev_resp_data[DW-1:0]    = {(DW/RW){reg_rddata[RW-1:0]}};
 
 endmodule // umi_regif
diff --git a/umi/rtl/umi_splitter.v b/umi/rtl/umi_splitter.v
index f4f17ac..783a0eb 100644
--- a/umi/rtl/umi_splitter.v
+++ b/umi/rtl/umi_splitter.v
@@ -1,41 +1,52 @@
 /*******************************************************************************
- * Function:  UMI Traffic Splitter
- * Author:    Andreas Olofsson
- * License:
+ * Copyright 2020 Zero ASIC Corporation
  *
- * Documentation:
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
  *
+ * Documentation:
  * - Splits up traffic based on type.
- * - Responses (writes) has priority over requests (reads)
- * - Both outputs must be ready for input to go through.("blocking")
  *
  ******************************************************************************/
+
+
 module umi_splitter
   #(// standard parameters
     parameter AW   = 64,
     parameter CW   = 32,
     parameter DW   = 256)
    (// UMI Input
-    input 	    umi_in_valid,
+    input           umi_in_valid,
     input [CW-1:0]  umi_in_cmd,
     input [AW-1:0]  umi_in_dstaddr,
     input [AW-1:0]  umi_in_srcaddr,
     input [DW-1:0]  umi_in_data,
-    output 	    umi_in_ready,
+    output          umi_in_ready,
     // UMI Output
-    output 	    umi_resp_out_valid,
+    output          umi_resp_out_valid,
     output [CW-1:0] umi_resp_out_cmd,
     output [AW-1:0] umi_resp_out_dstaddr,
     output [AW-1:0] umi_resp_out_srcaddr,
     output [DW-1:0] umi_resp_out_data,
-    input 	    umi_resp_out_ready,
+    input           umi_resp_out_ready,
     // UMI Output
-    output 	    umi_req_out_valid,
+    output          umi_req_out_valid,
     output [CW-1:0] umi_req_out_cmd,
     output [AW-1:0] umi_req_out_dstaddr,
     output [AW-1:0] umi_req_out_srcaddr,
     output [DW-1:0] umi_req_out_data,
-    input 	    umi_req_out_ready
+    input           umi_req_out_ready
     );
 
    /*AUTOWIRE*/
@@ -106,6 +117,6 @@ module umi_splitter
 
    // Globally blocking ready implementation
    assign umi_in_ready = ~(umi_resp_out_valid & ~umi_resp_out_ready) &
-			 ~(umi_req_out_valid & ~umi_req_out_ready);
+                         ~(umi_req_out_valid & ~umi_req_out_ready);
 
 endmodule // umi_splitter
diff --git a/umi/rtl/umi_stimulus.v b/umi/rtl/umi_stimulus.v
index af66909..03d4060 100644
--- a/umi/rtl/umi_stimulus.v
+++ b/umi/rtl/umi_stimulus.v
@@ -1,10 +1,24 @@
 /*******************************************************************************
- * Function:  UMI Synthesizable Stimulus Driver
- * Author:    Andreas Olofsson
- * License:
+ * Copyright 2020 Zero ASIC Corporation
  *
- * Documentation:
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
+ *
+ * ##Documentation##
+ *
+ * - Synthesizable UMI stimulus
+ * - Useful for FPGAs and emulators
  *
  ******************************************************************************/
 
@@ -60,9 +74,9 @@ module umi_stimulus
    wire [MAW-1:0]            rd_addr_nxt;
    wire [TCW-2:0]             rd_delay_nxt;
 
-   wire 		      beat;
-   wire 		      pause;
-   
+   wire                       beat;
+   wire                       pause;
+
    //#################################
    // Memory write port state machine
    //#################################
@@ -100,20 +114,20 @@ module umi_stimulus
        rd_state[1:0]  <= STIM_IDLE;
      else
        case (rd_state[1:0])
-	 STIM_IDLE :
-	   rd_state[1:0] <= (dut_start & data_valid)  ? STIM_ACTIVE :
-			    (dut_start & ~data_valid) ? STIM_DONE :
+         STIM_IDLE :
+           rd_state[1:0] <= (dut_start & data_valid)  ? STIM_ACTIVE :
+                            (dut_start & ~data_valid) ? STIM_DONE :
                             STIM_IDLE;
-	 STIM_ACTIVE :
-	   rd_state[1:0] <= pause      ? STIM_PAUSE :
-			    data_valid ? STIM_ACTIVE :
-			    STIM_DONE;
-	 STIM_PAUSE :
-	   rd_state[1:0] <= (|rd_delay) ? STIM_PAUSE :
-			    data_valid  ? STIM_ACTIVE :
-			    STIM_DONE;
-	 STIM_DONE  :
-	   rd_state[1:0] <= STIM_DONE;
+         STIM_ACTIVE :
+           rd_state[1:0] <= pause      ? STIM_PAUSE :
+                            data_valid ? STIM_ACTIVE :
+                            STIM_DONE;
+         STIM_PAUSE :
+           rd_state[1:0] <= (|rd_delay) ? STIM_PAUSE :
+                            data_valid  ? STIM_ACTIVE :
+                            STIM_DONE;
+         STIM_DONE  :
+           rd_state[1:0] <= STIM_DONE;
 
        endcase // case (rd_state[1:0])
 
@@ -125,7 +139,7 @@ module umi_stimulus
    /* verilator lint_off WIDTH */
    assign rd_addr_nxt = rd_addr[MAW-1:0] + beat;
    /* verilator lint_on WIDTH */
-   
+
    always @ (posedge dut_clk or negedge nreset)
      if(!nreset)
        rd_addr[MAW-1:0] <= 'b0;
diff --git a/umi/rtl/umi_unpack.v b/umi/rtl/umi_unpack.v
index 4c2c1e1..9464ea0 100644
--- a/umi/rtl/umi_unpack.v
+++ b/umi/rtl/umi_unpack.v
@@ -1,25 +1,26 @@
 /*******************************************************************************
- * Function:  Universal Memory Interface (UMI) Unpack(er)
- * Author:    Andreas Olofsson
- * License:
+ * Copyright 2020 Zero ASIC Corporation
  *
- * Documentation:
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- * Higher priority write/response (packet[0]==1)
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * 1. stores
- * 2. read (load) responses
- * 3. atomic response
- * 4. acks
- * 5. other responses
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  *
- * Lower priority read/request (packet[0]==0)
+ * ----
  *
- * 1. loads
- * 2. atomic request
- * 3. stores/writes that need acks
+ * ##Documentation##
+ *
+ * - Unpacks 32b command into separate ctrl fields
  *
  ******************************************************************************/
+
 module umi_unpack
   #(parameter CW = 32)
    (
diff --git a/umi/umi.py b/umi/umi.py
deleted file mode 100644
index 396f017..0000000
--- a/umi/umi.py
+++ /dev/null
@@ -1,23 +0,0 @@
-import siliconcompiler
-import os
-
-########################
-# SiliconCompiler Setup
-########################
-
-def setup(target=None):
-    '''UMI library setup'''
-
-    # Create chip object
-    chip = siliconcompiler.Chip('umi')
-
-    # Project sources
-    root = os.path.dirname(__file__)
-    chip.add('option', 'ydir', f"{root}/rtl")
-    chip.add('option', 'idir', f"{root}/rtl")
-#    chip.add('option', 'ydir', f"sumi/rtl")
-#    chip.add('option', 'idir', f"sumi/rtl")
-    chip.add('option', 'ydir', f"umi/rtl")
-    chip.add('option', 'idir', f"umi/rtl")
-
-    return chip
diff --git a/utils/rtl/tl-uh.vh b/utils/rtl/tl-uh.vh
index 29c4033..014e65f 100644
--- a/utils/rtl/tl-uh.vh
+++ b/utils/rtl/tl-uh.vh
@@ -1,13 +1,24 @@
-/******************************************************************************
- * Function:  TileLink Uncached Heavyweight (TL-UH) definitions
- * Author:    Wenting Zhang
- * Copyright: 2022 Zero ASIC Corporation. All rights reserved.
- * License:
+/*******************************************************************************
+ * Copyright 2023 Zero ASIC Corporation
  *
- * Documentation:
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  *
+ * ----
+ *
+ * Documentation:
+ * - TileLink Uncached Heavyweight (TL-UH) definitions
  *
- *****************************************************************************/
+ ******************************************************************************/
 
 // Opcode for channel A
 `define TL_OP_Get               3'd4
diff --git a/utils/rtl/tl2umi_np.v b/utils/rtl/tl2umi_np.v
index 0f7d535..8cf13f5 100644
--- a/utils/rtl/tl2umi_np.v
+++ b/utils/rtl/tl2umi_np.v
@@ -1,15 +1,24 @@
-/******************************************************************************
- * Function:  TL-UH to UMI converter
- * Author:    Aliasger Zaidy
- * Copyright: 2023 Zero ASIC Corporation. All rights reserved.
- * License: This file contains confidential and proprietary information of
- * Zero ASIC. This file may only be used in accordance with the terms and
- * conditions of a signed license agreement with Zero ASIC. All other use,
- * reproduction, or distribution of this software is strictly prohibited.
+/*******************************************************************************
+ * Copyright 2023 Zero ASIC Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
  *
  * Documentation:
- * The umi_srcaddr for requests uses User Defined Bits. It format is as
- * follows:
+ * -TL-UH to UMI converter
+ *
+ * The umi_srcaddr for requests uses User Defined Bits as follows:
  * [63:56]  : Reserved
  * [55:40]  : Chip ID
  * [39:24]  : Local routing address
@@ -17,7 +26,9 @@
  * [19:16]  : tl_a_size (TileLink Size)
  * [15:8]   : tl_a_source (TileLink Source)
  * [7:0]    : 0000_0000b
- *****************************************************************************/
+ *
+ ******************************************************************************/
+
 
 `default_nettype wire
 `include "tl-uh.vh"
@@ -318,8 +329,20 @@ module tl2umi_np #(
                         put_bytes_resp <= dataag_out_resp_bytes;
                     end
                     else begin
-                        // Not supported request, ignore
+                        // Not supported response type. Ignore and stay in idle.
+                        resp_state <= RESP_IDLE;
+                        dataag_out_resp_ready_assert <= 1'b1;
+                        tl_d_valid <= 1'b0;
+                        tl_d_opcode <= 3'b0;
+                        tl_d_size <= 3'b0;
+                        tl_d_source <= 5'b0;
+                        tl_d_data <= 64'b0;
+                        put_ack_resp <= 1'b0;
+                        put_bytes_resp <= 8'b0;
+                        get_ack_resp <= 1'b0;
+                    `ifndef SYNTHESIS
                         $display("Unsupported response on UMI side %d", dataag_out_resp_cmd_opcode);
+                    `endif
                     end
                 end
             end
@@ -381,8 +404,20 @@ module tl2umi_np #(
                 end
             end
             default: begin
-                // Entered wrong state
+                // Entered wrong state. Return to idle.
+                resp_state <= RESP_IDLE;
+                dataag_out_resp_ready_assert <= 1'b1;
+                tl_d_valid <= 1'b0;
+                tl_d_opcode <= 3'b0;
+                tl_d_size <= 3'b0;
+                tl_d_source <= 5'b0;
+                tl_d_data <= 64'b0;
+                put_ack_resp <= 1'b0;
+                put_bytes_resp <= 8'b0;
+                get_ack_resp <= 1'b0;
+            `ifndef SYNTHESIS
                 $display("Entered Invalid State in Response State Machine");
+            `endif
             end
 
             endcase
@@ -526,7 +561,7 @@ module tl2umi_np #(
 
     always @(posedge clk or negedge nreset) begin
         if (~nreset) begin
-            req_state <= 'b0;
+            req_state <= REQ_IDLE;
             tl_a_ready_assert <= 1'b1;
             uhost_req_packet_cmd_opcode <= 'b0;
             uhost_req_packet_cmd_len <= 'b0;
@@ -538,6 +573,7 @@ module tl2umi_np #(
             uhost_req_packet_data <= 'b0;
             uhost_req_packet_valid_r <= 1'b0;
             ml_tx_non_zero_mask_r <= 1'b0;
+            put_ack_req <= 1'b0;
             put_bytes_req <= 8'b0;
         end
         else begin
@@ -628,8 +664,23 @@ module tl2umi_np #(
                         endcase
                     end
                     default: begin
-                        // Not supported request, ignore
+                        // Not supported request type. Ignore and stay in idle.
+                        req_state <= REQ_IDLE;
+                        tl_a_ready_assert <= 1'b1;
+                        uhost_req_packet_cmd_opcode <= 'b0;
+                        uhost_req_packet_cmd_len <= 'b0;
+                        uhost_req_packet_cmd_size <= 'b0;
+                        uhost_req_packet_cmd_atype <= 'b0;
+                        uhost_req_packet_cmd_eom <= 'b0;
+                        uhost_req_packet_dstaddr <= 'b0;
+                        uhost_req_packet_srcaddr <= 'b0;
+                        uhost_req_packet_data <= 'b0;
+                        uhost_req_packet_valid_r <= 1'b0;
+                        ml_tx_non_zero_mask_r <= 1'b0;
+                        put_bytes_req <= 8'b0;
+                    `ifndef SYNTHESIS
                         $display("Unsupported request on TL side %d", tl_a_opcode);
+                    `endif
                     end
                     endcase
                 end
@@ -693,8 +744,24 @@ module tl2umi_np #(
                 end
             end
             default: begin
-                // Entered wrong state
+                // Entered wrong state. Return to idle.
+                req_state <= REQ_IDLE;
+                tl_a_ready_assert <= 1'b1;
+                uhost_req_packet_cmd_opcode <= 'b0;
+                uhost_req_packet_cmd_len <= 'b0;
+                uhost_req_packet_cmd_size <= 'b0;
+                uhost_req_packet_cmd_atype <= 'b0;
+                uhost_req_packet_cmd_eom <= 'b0;
+                uhost_req_packet_dstaddr <= 'b0;
+                uhost_req_packet_srcaddr <= 'b0;
+                uhost_req_packet_data <= 'b0;
+                uhost_req_packet_valid_r <= 1'b0;
+                ml_tx_non_zero_mask_r <= 1'b0;
+                put_ack_req <= 1'b0;
+                put_bytes_req <= 8'b0;
+            `ifndef SYNTHESIS
                 $display("Entered Invalid State in Request State Machine");
+            `endif
             end
 
             endcase
diff --git a/utils/rtl/umi2tl_np.v b/utils/rtl/umi2tl_np.v
index 2fad170..029f8f3 100644
--- a/utils/rtl/umi2tl_np.v
+++ b/utils/rtl/umi2tl_np.v
@@ -1,14 +1,25 @@
-/******************************************************************************
- * Function:  UMI to TL-UH converter
- * Author:    Aliasger Zaidy
- * Copyright: 2023 Zero ASIC Corporation. All rights reserved.
- * License: This file contains confidential and proprietary information of
- * Zero ASIC. This file may only be used in accordance with the terms and
- * conditions of a signed license agreement with Zero ASIC. All other use,
- * reproduction, or distribution of this software is strictly prohibited.
+/*******************************************************************************
+ * Copyright 2023 Zero ASIC Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
  *
  * Documentation:
- *****************************************************************************/
+ * - TileLink TL-UH converter
+ *
+ ******************************************************************************/
+
 `default_nettype none
 `include "tl-uh.vh"
 
@@ -270,7 +281,11 @@ module umi2tl_np #(
                             tl_a_opcode_r <= `TL_OP_LogicalData;
                         end
                     end
-                    default: $display("[UMI2TL]: Unsupported UMI Request");
+                `ifndef SYNTHESIS
+                    default: begin
+                        $display("[UMI2TL]: Unsupported UMI Request");
+                    end
+                `endif
                 endcase
             end
         end
@@ -293,7 +308,11 @@ module umi2tl_np #(
                         UMI_REQ_ATOMICMAXU: tl_a_param_r <= `TL_PA_MAXU;
                         UMI_REQ_ATOMICMINU: tl_a_param_r <= `TL_PA_MINU;
                         UMI_REQ_ATOMICSWAP: tl_a_param_r <= `TL_PL_SWAP;
-                        default: $display("[UMI2TL]: Unsupported UMI Atomic");
+                    `ifndef SYNTHESIS
+                        default: begin
+                            $display("[UMI2TL]: Unsupported UMI Atomic");
+                        end
+                    `endif
                     endcase
                 end
                 else begin
@@ -458,7 +477,11 @@ module umi2tl_np #(
             case (tl_d_opcode)
                 `TL_OP_AccessAck:       udev_resp_cmd_opcode_r <= UMI_RESP_WRITE;
                 `TL_OP_AccessAckData:   udev_resp_cmd_opcode_r <= UMI_RESP_READ;
-                default: $display("[UMI2TL]: Unsupported TileLink Response");
+            `ifndef SYNTHESIS
+                default: begin
+                    $display("[UMI2TL]: Unsupported TileLink Response");
+                end
+            `endif
             endcase
         end
     end
diff --git a/utils/rtl/umi_address_remap.v b/utils/rtl/umi_address_remap.v
index d6004ac..dc87482 100644
--- a/utils/rtl/umi_address_remap.v
+++ b/utils/rtl/umi_address_remap.v
@@ -1,11 +1,19 @@
-/******************************************************************************
- * Function:  UMI address remap
- * Author:    Aliasger Zaidy
- * Copyright: 2023 Zero ASIC Corporation. All rights reserved.
- * License: This file contains confidential and proprietary information of
- * Zero ASIC. This file may only be used in accordance with the terms and
- * conditions of a signed license agreement with Zero ASIC. All other use,
- * reproduction, or distribution of this software is strictly prohibited.
+/*******************************************************************************
+ * Copyright 2023 Zero ASIC Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
  *
  * Documentation:
  * This module remaps UMI transactions across different memory regions.
@@ -21,7 +29,8 @@
  * NMAPS parameterization is incomplete
  * Currently NMAPS < 8 will fail and NMAPS > 8 will not have the desired effect
  * beyond 8 remappings.
- *****************************************************************************/
+ *
+ ******************************************************************************/
 
 `default_nettype wire
 
diff --git a/utils/rtl/umi_data_aggregator.v b/utils/rtl/umi_data_aggregator.v
index 0e86602..388245e 100644
--- a/utils/rtl/umi_data_aggregator.v
+++ b/utils/rtl/umi_data_aggregator.v
@@ -1,3 +1,25 @@
+/*******************************************************************************
+ * Copyright 2023 Zero ASIC Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
+ *
+ * Documentation:
+ * - UMI data aggregator
+ *
+ ******************************************************************************/
+
 `default_nettype wire
 
 module umi_data_aggregator #(
diff --git a/utils/rtl/umi_packet_merge_greedy.v b/utils/rtl/umi_packet_merge_greedy.v
index e98cc4d..cf42932 100644
--- a/utils/rtl/umi_packet_merge_greedy.v
+++ b/utils/rtl/umi_packet_merge_greedy.v
@@ -1,3 +1,25 @@
+/*******************************************************************************
+ * Copyright 2023 Zero ASIC Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
+ *
+ * Documentation:
+ * - Greedy packet merge logic
+ *
+ ******************************************************************************/
+
 `default_nettype wire
 
 module umi_packet_merge_greedy #(


Test patch:
diff --git a/examples/umi_mem/test_umi_mem.py b/examples/umi_mem/test_umi_mem.py
deleted file mode 100644
index 091f58f..0000000
--- a/examples/umi_mem/test_umi_mem.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import sys
-
-sys.path.append('../../umi/testbench')
-import umi_testbench
-
-import pytest
-
-import umi_mem
-
-@pytest.fixture(scope='module')
-def chip_tb():
-    '''Setup/compile the testbench.
-
-    The decorator above this method ensures that this code executes once per
-    test session, making it faster to run multiple tests at once.
-    '''
-    chip = umi_mem.setup()
-
-    # Uncomment to enable VCD dumps for each test.
-    #chip.set('option', 'trace', True)
-
-    # Set a timeout for test execution in seconds. Useful since tests will
-    # otherwise hang if the expected # of transactions are not received.
-    chip.set('flowgraph', 'verification', 'execute', '0', 'timeout', 2)
-
-    return umi_testbench.compile_tb(chip, 'umi_mem')
-
-def test_1(chip_tb):
-    chip_tb.set('input', 'txfile', 'tests/stimulus1.memh')
-    chip_tb.set('input', 'rxfile', 'tests/expect1.memh')
-    umi_testbench.run_tb(chip_tb, 'test_1')
-
-def test_2(chip_tb):
-    chip_tb.set('input', 'txfile', 'tests/stimulus2.memh')
-    chip_tb.set('input', 'rxfile', 'tests/expect2.memh')
-    umi_testbench.run_tb(chip_tb, 'test_2')
diff --git a/examples/umi_mem/tests/expect1.memh b/examples/umi_mem/tests/expect1.memh
deleted file mode 100644
index 0d45011..0000000
--- a/examples/umi_mem/tests/expect1.memh
+++ /dev/null
@@ -1,1 +0,0 @@
-00000000_00000000_00000000_00000000_DEADBEEF_00000000_00000000_00000208
diff --git a/examples/umi_mem/tests/expect2.memh b/examples/umi_mem/tests/expect2.memh
deleted file mode 100644
index 75a5a0b..0000000
--- a/examples/umi_mem/tests/expect2.memh
+++ /dev/null
@@ -1,2 +0,0 @@
-00000000_00000000_00000000_00000000_DEADBEEF_00000000_00000000_00000208
-00000000_00000000_00000000_00000000_BEEFDEAD_00000000_00000000_00000208
diff --git a/examples/umi_mem/tests/stimulus1.memh b/examples/umi_mem/tests/stimulus1.memh
deleted file mode 100644
index 5c6bb1d..0000000
--- a/examples/umi_mem/tests/stimulus1.memh
+++ /dev/null
@@ -1,2 +0,0 @@
-00000000_00000000_00000000_00000000_DEADBEEF_00000000_00000000_00000201
-00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000208
diff --git a/examples/umi_mem/tests/stimulus2.memh b/examples/umi_mem/tests/stimulus2.memh
deleted file mode 100644
index 7534b1a..0000000
--- a/examples/umi_mem/tests/stimulus2.memh
+++ /dev/null
@@ -1,4 +0,0 @@
-00000000_00000000_00000000_00000000_DEADBEEF_00000000_00000000_00000201
-00000000_00000000_00000000_00000000_BEEFDEAD_00000000_00000040_00000201
-00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000208
-00000000_00000000_00000000_00000000_00000000_00000000_00000040_00000208
diff --git a/lumi/testbench/test_lumi.py b/lumi/testbench/test_lumi.py
index 3f31198..77919db 100755
--- a/lumi/testbench/test_lumi.py
+++ b/lumi/testbench/test_lumi.py
@@ -2,17 +2,19 @@
 
 # Example illustrating how UMI packets handled in the Switchboard Python binding
 # Copyright (C) 2023 Zero ASIC
+# This code is licensed under Apache License 2.0 (see LICENSE for details)
 
+import random
 import numpy as np
 from pathlib import Path
 from argparse import ArgumentParser
-from switchboard import SbDut, UmiTxRx, delete_queue, verilator_run, binary_run
+from switchboard import SbDut, UmiTxRx, delete_queue
 
 THIS_DIR = Path(__file__).resolve().parent
 
 
-def build_testbench(topo="2d"):
-    dut = SbDut('testbench')
+def build_testbench(topo="2d", trace=False):
+    dut = SbDut('testbench', trace=True, trace_type='fst', default_main=True)
 
     EX_DIR = Path('..')
 
@@ -30,9 +32,9 @@ def build_testbench(topo="2d"):
         dut.add('option', option, EX_DIR / 'rtl')
         dut.add('option', option, EX_DIR / '..' / 'umi' / 'rtl')
         dut.add('option', option, EX_DIR / '..' / 'submodules' / 'switchboard' / 'examples' / 'common' / 'verilog')
-        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'lambdalib' / 'ramlib' / 'rtl')
-        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'lambdalib' / 'stdlib' / 'rtl')
-        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'lambdalib' / 'vectorlib' / 'rtl')
+        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'lambdalib' / 'lambdalib' / 'ramlib' / 'rtl')
+        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'lambdalib' / 'lambdalib' / 'stdlib' / 'rtl')
+        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'lambdalib' / 'lambdalib' / 'vectorlib' / 'rtl')
 
     # Verilator configuration
     vlt_config = EX_DIR / 'testbench' / 'config.vlt'
@@ -47,21 +49,32 @@ def build_testbench(topo="2d"):
     dut.set('tool', 'verilator', 'task', 'compile', 'var', 'trace_type', 'fst')
 
     # Build simulator
-    dut.run()
+    dut.build()
 
-    return dut.find_result('vexe', step='compile')
+    return dut
 
 
-def main(topo="2d", vldmode="2", rdymode="2", host2dut="host2dut_0.q", dut2host="dut2host_0.q", sb2dut="sb2dut_0.q", dut2sb="dut2sb_0.q"):
+def main(topo="2d", vldmode="2", rdymode="2", trace=False, host2dut="host2dut_0.q", dut2host="dut2host_0.q", sb2dut="sb2dut_0.q", dut2sb="dut2sb_0.q"):
     # clean up old queues if present
     for q in [host2dut, dut2host, sb2dut, dut2sb]:
         delete_queue(q)
 
-    verilator_bin = build_testbench(topo)
+    dut = build_testbench(topo,trace)
+
+    hostdly = random.randrange(500)
+    devdly = random.randrange(500)
 
     # launch the simulation
-    #verilator_run(verilator_bin, plusargs=['trace'])
-    verilator_run(verilator_bin, plusargs=['trace', ('valid_mode', vldmode), ('ready_mode', rdymode)])
+    dut.simulate(
+        plusargs=[
+            ('valid_mode', vldmode),
+            ('ready_mode', rdymode),
+            ('hostdly', hostdly),
+            ('devdly', devdly)
+        ],
+        trace=trace,
+        args=['+verilator+seed+100']
+    )
 
     # instantiate TX and RX queues.  note that these can be instantiated without
     # specifying a URI, in which case the URI can be specified later via the
@@ -70,71 +83,93 @@ def main(topo="2d", vldmode="2", rdymode="2", host2dut="host2dut_0.q", dut2host=
     sb = UmiTxRx(sb2dut, dut2sb)
     host = UmiTxRx(host2dut, dut2host)
 
+    # Lumi starts in auto configuration based on the link indication from the phy
+    # In 2d mode no need to configure anything!
+    # In 3d mode need to take down the link and re-enable it with the right configuration
     print("### Side Band loc reset ###")
     sb.write(0x7000000C, np.uint32(0x00000000), posted=True)
-
-    # Need to add some delay are reassertion before sending things
-    # over serial link
     print("### Read local reset ###")
     val32 = sb.read(0x70000000, np.uint32)
     print(f"Read: 0x{val32:08x}")
     assert val32 == 0x00000000
 
     if topo=='2d':
-        width = np.uint32(0x00010000)
+        width = np.uint32(0x00000000)
     if topo=='3d':
         width = np.uint32(0x00030000)
 
-    print("### configure loc Rx width ###")
-    sb.write(0x70000010, width, posted=True)
+        linkactive = 0
+        while (linkactive == 0):
+            print("### Wait for linkactive ###")
+            linkactive = sb.read(0x70000004, np.uint32)
+            print(f"Read: 0x{val32:08x}")
+
+        linkactive = 0
+        while (linkactive == 0):
+            print("### Wait for linkactive ###")
+            linkactive = sb.read(0x60000004, np.uint32)
+            print(f"Read: 0x{val32:08x}")
+
+        print("### disable Tx ###")
+        sb.write(0x60000010, np.uint32(0x0), posted=True)
+        sb.write(0x70000010, np.uint32(0x0), posted=True)
 
-    print("### configure rmt Rx 2B width ###")
-    sb.write(0x60000010, width, posted=True)
+        import time
+        time.sleep (0.1)
 
-    print("### configure loc Tx 2B width ###")
-    sb.write(0x70000014, width, posted=True)
+        print("### disable Rx ###")
+        sb.write(0x70000014, np.uint32(0x0), posted=True)
+        sb.write(0x60000014, np.uint32(0x0), posted=True)
 
-    print("### configure rmt Tx 2B width ###")
-    sb.write(0x60000014, width, posted=True)
+        print("### configure loc Rx width ###")
+        sb.write(0x70000010, width, posted=True)
 
-    print("### Rx enable local ###")
-    sb.write(0x70000014, np.uint32(0x1) + width, posted=True)
+        print("### configure rmt Rx width ###")
+        sb.write(0x60000010, width, posted=True)
 
-    print("### Rx enable remote ###")
-    sb.write(0x60000014, np.uint32(0x1) + width, posted=True)
+        print("### configure loc Tx width ###")
+        sb.write(0x70000014, width, posted=True)
 
-    print("### Tx enable remote ###")
-    sb.write(0x60000010, np.uint32(0x1) + width, posted=True)
+        print("### configure rmt Tx width ###")
+        sb.write(0x60000014, width, posted=True)
 
-    print("### Tx enable local ###")
-    sb.write(0x70000010, np.uint32(0x1) + width, posted=True)
+        print("### Rx enable local ###")
+        sb.write(0x70000014, np.uint32(0x1) + width, posted=True)
 
-    print("### Tx enable credit ###")
-    sb.write(0x60000010, np.uint32(0x11) + width, posted=True)
+        print("### Rx enable remote ###")
+        sb.write(0x60000014, np.uint32(0x1) + width, posted=True)
 
-    print("### Tx enable credit ###")
-    sb.write(0x70000010, np.uint32(0x11) + width, posted=True)
+        print("### Tx enable remote ###")
+        sb.write(0x60000010, np.uint32(0x1) + width, posted=True)
+
+        print("### Tx enable local ###")
+        sb.write(0x70000010, np.uint32(0x1) + width, posted=True)
+
+        print("### Tx enable credit ###")
+        sb.write(0x60000010, np.uint32(0x11) + width, posted=True)
+
+        print("### Tx enable credit ###")
+        sb.write(0x70000010, np.uint32(0x11) + width, posted=True)
 
     print("### Read loc Rx ctrl ###")
     val32 = sb.read(0x70000014, np.uint32)
     print(f"Read: 0x{val32:08x}")
-    assert val32 == np.uint32(0x1) + width
+    #assert val32 == np.uint32(0x1) + width
 
     print("### Read loc Tx ctrl ###")
     val32 = sb.read(0x70000010, np.uint32)
     print(f"Read: 0x{val32:08x}")
-    assert val32 == np.uint32(0x11) + width
+    #assert val32 == np.uint32(0x11) + width
 
     print("### Read rmt Rx ctrl ###")
     val32 = sb.read(0x60000014, np.uint32)
     print(f"Read: 0x{val32:08x}")
-    assert val32 == np.uint32(0x1) + width
+    #assert val32 == np.uint32(0x1) + width
 
     print("### Read rmt Tx ctrl ###")
     val32 = sb.read(0x60000010, np.uint32)
     print(f"Read: 0x{val32:08x}")
-    assert val32 == np.uint32(0x11) + width
-
+    #assert val32 == np.uint32(0x11) + width
 
     print("### UMI WRITES ###")
 
@@ -226,9 +261,11 @@ def main(topo="2d", vldmode="2", rdymode="2", host2dut="host2dut_0.q", dut2host=
 
 if __name__ == '__main__':
     parser = ArgumentParser()
+    parser.add_argument('--trace', action='store_true', default=False,
+                        help="Enable waveform tracing")
     parser.add_argument('--topo', default='2d')
     parser.add_argument('--vldmode', default='2')
     parser.add_argument('--rdymode', default='2')
     args = parser.parse_args()
 
-    main(topo=args.topo,vldmode=args.vldmode,rdymode=args.rdymode)
+    main(topo=args.topo,vldmode=args.vldmode,rdymode=args.rdymode,trace=args.trace)
diff --git a/lumi/testbench/test_lumi_rnd.py b/lumi/testbench/test_lumi_rnd.py
index b0d6e2c..b873725 100755
--- a/lumi/testbench/test_lumi_rnd.py
+++ b/lumi/testbench/test_lumi_rnd.py
@@ -2,18 +2,19 @@
 
 # Example illustrating how UMI packets handled in the Switchboard Python binding
 # Copyright (C) 2023 Zero ASIC
+# This code is licensed under Apache License 2.0 (see LICENSE for details)
 
 import random
 import numpy as np
 from pathlib import Path
 from argparse import ArgumentParser
-from switchboard import SbDut, UmiTxRx, delete_queue, verilator_run, binary_run
+from switchboard import SbDut, UmiTxRx, delete_queue
 
 THIS_DIR = Path(__file__).resolve().parent
 
 
-def build_testbench(topo="2d"):
-    dut = SbDut('testbench')
+def build_testbench(topo="2d", trace=False):
+    dut = SbDut('testbench', trace=True, trace_type='fst', default_main=True)
 
     EX_DIR = Path('..')
 
@@ -31,9 +32,9 @@ def build_testbench(topo="2d"):
         dut.add('option', option, EX_DIR / 'rtl')
         dut.add('option', option, EX_DIR / '..' / 'umi' / 'rtl')
         dut.add('option', option, EX_DIR / '..' / 'submodules' / 'switchboard' / 'examples' / 'common' / 'verilog')
-        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'lambdalib' / 'ramlib' / 'rtl')
-        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'lambdalib' / 'stdlib' / 'rtl')
-        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'lambdalib' / 'vectorlib' / 'rtl')
+        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'lambdalib' / 'lambdalib' / 'ramlib' / 'rtl')
+        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'lambdalib' / 'lambdalib' / 'stdlib' / 'rtl')
+        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'lambdalib' / 'lambdalib' / 'vectorlib' / 'rtl')
 
     # Verilator configuration
     vlt_config = EX_DIR / 'testbench' / 'config.vlt'
@@ -43,26 +44,32 @@ def build_testbench(topo="2d"):
     dut.add('tool', 'verilator', 'task', 'compile', 'option', '-CFLAGS')
     dut.add('tool', 'verilator', 'task', 'compile', 'option', '-DVL_DEBUG')
 
-    # Settings - enable tracing
-    dut.set('option', 'trace', True)
-    dut.set('tool', 'verilator', 'task', 'compile', 'var', 'trace_type', 'fst')
-
     # Build simulator
-    dut.run()
-
-    return dut.find_result('vexe', step='compile')
+    dut.build()
 
+    return dut
 
-def main(topo="2d", vldmode="2", rdymode="2", host2dut="host2dut_0.q", dut2host="dut2host_0.q", sb2dut="sb2dut_0.q", dut2sb="dut2sb_0.q"):
+def main(topo="2d", vldmode="2", rdymode="2", trace=False, host2dut="host2dut_0.q", dut2host="dut2host_0.q", sb2dut="sb2dut_0.q", dut2sb="dut2sb_0.q"):
     # clean up old queues if present
     for q in [host2dut, dut2host, sb2dut, dut2sb]:
         delete_queue(q)
 
-    verilator_bin = build_testbench(topo)
+    dut = build_testbench(topo,trace)
+
+    hostdly = random.randrange(500)
+    devdly = random.randrange(500)
 
     # launch the simulation
-    #verilator_run(verilator_bin, plusargs=['trace'])
-    verilator_run(verilator_bin, plusargs=['trace', ('valid_mode', vldmode), ('ready_mode', rdymode)])
+    dut.simulate(
+        plusargs=[
+            ('valid_mode', vldmode),
+            ('ready_mode', rdymode),
+            ('hostdly', hostdly),
+            ('devdly', devdly)
+        ],
+        trace=trace,
+        args=['+verilator+seed+0']
+    )
 
     # instantiate TX and RX queues.  note that these can be instantiated without
     # specifying a URI, in which case the URI can be specified later via the
@@ -82,68 +89,90 @@ def main(topo="2d", vldmode="2", rdymode="2", host2dut="host2dut_0.q", dut2host=
     assert val32 == 0x00000000
 
     if topo=='2d':
-        width = np.uint32(0x00010000)
+        width = np.uint32(0x00000000)
         crdt  = np.uint32(0x001A001A)
     if topo=='3d':
         width = np.uint32(0x00030000)
         crdt  = np.uint32(0x00070007)
 
-    print("### configure loc Rx width ###")
-    sb.write(0x70000010, width, posted=True)
+        linkactive = 0
+        while (linkactive == 0):
+            print("### Wait for linkactive ###")
+            linkactive = sb.read(0x70000004, np.uint32)
+            print(f"Read: 0x{val32:08x}")
+
+        linkactive = 0
+        while (linkactive == 0):
+            print("### Wait for linkactive ###")
+            linkactive = sb.read(0x60000004, np.uint32)
+            print(f"Read: 0x{val32:08x}")
+
+        print("### disable Tx ###")
+        sb.write(0x60000010, np.uint32(0x0), posted=True)
+        sb.write(0x70000010, np.uint32(0x0), posted=True)
 
-    print("### configure rmt Rx 2B width ###")
-    sb.write(0x60000010, width, posted=True)
+        import time
+        time.sleep (0.1)
 
-    print("### configure loc Tx 2B width ###")
-    sb.write(0x70000014, width, posted=True)
+        print("### disable Rx ###")
+        sb.write(0x70000014, np.uint32(0x0), posted=True)
+        sb.write(0x60000014, np.uint32(0x0), posted=True)
 
-    print("### configure rmt Tx 2B width ###")
-    sb.write(0x60000014, width, posted=True)
+        print("### configure loc Rx width ###")
+        sb.write(0x70000010, width, posted=True)
 
-    print("### Tx init credit ###")
-    sb.write(0x60000020, crdt, posted=True)
+        print("### configure rmt Rx width ###")
+        sb.write(0x60000010, width, posted=True)
 
-    print("### Tx init credit ###")
-    sb.write(0x70000020, crdt, posted=True)
+        print("### configure loc Tx width ###")
+        sb.write(0x70000014, width, posted=True)
 
-    print("### Rx enable local ###")
-    sb.write(0x70000014, np.uint32(0x1) + width, posted=True)
+        print("### configure rmt Tx width ###")
+        sb.write(0x60000014, width, posted=True)
 
-    print("### Rx enable remote ###")
-    sb.write(0x60000014, np.uint32(0x1) + width, posted=True)
+        print("### Tx init credit ###")
+        sb.write(0x60000020, crdt, posted=True)
 
-    print("### Tx enable remote ###")
-    sb.write(0x60000010, np.uint32(0x1) + width, posted=True)
+        print("### Tx init credit ###")
+        sb.write(0x70000020, crdt, posted=True)
 
-    print("### Tx enable local ###")
-    sb.write(0x70000010, np.uint32(0x1) + width, posted=True)
+        print("### Rx enable local ###")
+        sb.write(0x70000014, np.uint32(0x1) + width, posted=True)
 
-    print("### Tx enable credit ###")
-    sb.write(0x60000010, np.uint32(0x11) + width, posted=True)
+        print("### Rx enable remote ###")
+        sb.write(0x60000014, np.uint32(0x1) + width, posted=True)
 
-    print("### Tx enable credit ###")
-    sb.write(0x70000010, np.uint32(0x11) + width, posted=True)
+        print("### Tx enable remote ###")
+        sb.write(0x60000010, np.uint32(0x1) + width, posted=True)
+
+        print("### Tx enable local ###")
+        sb.write(0x70000010, np.uint32(0x1) + width, posted=True)
+
+        print("### Tx enable credit ###")
+        sb.write(0x60000010, np.uint32(0x11) + width, posted=True)
+
+        print("### Tx enable credit ###")
+        sb.write(0x70000010, np.uint32(0x11) + width, posted=True)
 
     print("### Read loc Rx ctrl ###")
     val32 = sb.read(0x70000014, np.uint32)
     print(f"Read: 0x{val32:08x}")
-    assert val32 == np.uint32(0x1) + width
+    #assert val32 == np.uint32(0x1) + width
 
     print("### Read loc Tx ctrl ###")
     val32 = sb.read(0x70000010, np.uint32)
     print(f"Read: 0x{val32:08x}")
-    assert val32 == np.uint32(0x11) + width
+    #assert val32 == np.uint32(0x11) + width
 
     print("### Read rmt Rx ctrl ###")
     val32 = sb.read(0x60000014, np.uint32)
     print(f"Read: 0x{val32:08x}")
-    assert val32 == np.uint32(0x1) + width
+    #assert val32 == np.uint32(0x1) + width
 
     print("### Read rmt Tx ctrl ###")
     val32 = sb.read(0x60000010, np.uint32)
     print(f"Read: 0x{val32:08x}")
-    assert val32 == np.uint32(0x11) + width
-
+    #assert val32 == np.uint32(0x11) + width
 
     print("### UMI WRITE/READ ###")
 
@@ -169,9 +198,11 @@ def main(topo="2d", vldmode="2", rdymode="2", host2dut="host2dut_0.q", dut2host=
 
 if __name__ == '__main__':
     parser = ArgumentParser()
+    parser.add_argument('--trace', action='store_true', default=False,
+                        help="Enable waveform tracing")
     parser.add_argument('--topo', default='2d')
     parser.add_argument('--vldmode', default='2')
     parser.add_argument('--rdymode', default='2')
     args = parser.parse_args()
 
-    main(topo=args.topo,vldmode=args.vldmode,rdymode=args.rdymode)
+    main(topo=args.topo,vldmode=args.vldmode,rdymode=args.rdymode,trace=args.trace)
diff --git a/lumi/testbench/testbench_lumi.sv b/lumi/testbench/testbench_lumi.sv
index 64a935e..b4eb359 100644
--- a/lumi/testbench/testbench_lumi.sv
+++ b/lumi/testbench/testbench_lumi.sv
@@ -1,3 +1,20 @@
+/*******************************************************************************
+ * Copyright 2023 Zero ASIC Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
 `default_nettype none
 
 module testbench (
@@ -139,8 +156,42 @@ module testbench (
    // No clink so driving all clock from the tb
    wire rxclk = clk;
    wire txclk = clk;
+   wire phy_clk = clk;
    wire rxnreset = nreset;
    wire txnreset = nreset;
+   wire phy_nreset = nreset;
+   reg  linkactive_host;
+   reg  linkactive_device;
+   integer host_delay;
+   integer device_delay;
+   reg [31:0] delay_cnt;
+
+   always @(posedge clk or negedge nreset)
+     if (~nreset)
+       delay_cnt <= 'd0;
+     else
+       delay_cnt <= delay_cnt + 1;
+   initial
+     begin
+        if (!$value$plusargs("hostdly=%d",host_delay))
+          host_delay = $urandom%500;
+        if (!$value$plusargs("devdly=%d",device_delay))
+          device_delay = $urandom%500;
+     end
+
+   always @(posedge clk or negedge nreset)
+     if (~nreset)
+       begin
+          linkactive_host <= 1'b0;
+          linkactive_device <= 1'b0;
+       end
+     else
+       begin
+          if (delay_cnt == host_delay)
+            linkactive_host <= 1'b1;
+          if (delay_cnt == device_delay)
+            linkactive_device <= 1'b1;
+       end
 
    // instantiate dut with UMI ports
    /* lumi AUTO_TEMPLATE(
@@ -157,7 +208,8 @@ module testbench (
     .phy_tx\(.*\)     (phy_rx\1[]),
     .devicemode       (1'b0),
     .deviceready      (1'b1),
-    .phy_linkactive   (1'b1),
+    .phy_linkactive   (linkactive_host),
+    .phy_iow          (8'h0),
     .host_linkactive  (),
     .vss              (),
     .vdd.*            (),
@@ -217,6 +269,8 @@ module testbench (
                .sb_in_srcaddr   (host_sb_req_srcaddr[AW-1:0]), // Templated
                .sb_in_data      (host_sb_req_data[RW-1:0]), // Templated
                .sb_out_ready    (host_sb_resp_ready),    // Templated
+               .phy_clk         (phy_clk),
+               .phy_nreset      (phy_nreset),
                .phy_in_valid    (phy_out_valid),         // Templated
                .phy_in_cmd      (phy_out_cmd[CW-1:0]),   // Templated
                .phy_in_dstaddr  (phy_out_dstaddr[AW-1:0]), // Templated
@@ -229,13 +283,13 @@ module testbench (
                .rxnreset        (rxnreset),
                .txclk           (txclk),
                .txnreset        (txnreset),
-               .phy_linkactive  (1'b1),                  // Templated
+               .phy_linkactive  (linkactive_host),       // Templated
+               .phy_iow         (8'h0),                  // Templated
                .nreset          (nreset),
                .clk             (clk),
                .deviceready     (1'b1),                  // Templated
                .vss             (),                      // Templated
-               .vdd             (),                      // Templated
-               .vddio           ());                     // Templated
+               .vdd             ());                     // Templated
 
    /* lumi AUTO_TEMPLATE(
     .uhost_req_\(.*\)  (udev_req_\1[]),
@@ -250,7 +304,8 @@ module testbench (
     .sb_out.*          (),
     .devicemode        (1'b1),
     .deviceready       (1'b1),
-    .phy_linkactive    (1'b1),
+    .phy_linkactive    (linkactive_device),
+    .phy_iow           (8'h0),
     .host_linkactive   (),
     .vss               (),
     .vdd.*             (),
@@ -310,6 +365,8 @@ module testbench (
               .sb_in_srcaddr    ('h0),                   // Templated
               .sb_in_data       ('h0),                   // Templated
               .sb_out_ready     (1'b0),                  // Templated
+              .phy_clk          (phy_clk),
+              .phy_nreset       (phy_nreset),
               .phy_in_valid     (phy_in_valid),
               .phy_in_cmd       (phy_in_cmd[CW-1:0]),
               .phy_in_dstaddr   (phy_in_dstaddr[AW-1:0]),
@@ -322,13 +379,13 @@ module testbench (
               .rxnreset         (rxnreset),
               .txclk            (txclk),
               .txnreset         (txnreset),
-              .phy_linkactive   (1'b1),                  // Templated
+              .phy_linkactive   (linkactive_device),     // Templated
+              .phy_iow          (8'h0),                  // Templated
               .nreset           (nreset),
               .clk              (clk),
               .deviceready      (1'b1),                  // Templated
               .vss              (),                      // Templated
-              .vdd              (),                      // Templated
-              .vddio            ());                     // Templated
+              .vdd              ());                     // Templated
 
    umiram #(.ADDR_WIDTH(10),
             .DATA_WIDTH(DW),
diff --git a/umi/testbench/buffer.memh b/umi/testbench/buffer.memh
deleted file mode 100644
index 2aa61bd..0000000
--- a/umi/testbench/buffer.memh
+++ /dev/null
@@ -1,20 +0,0 @@
-@0
-//DAHI_DAHI_SAHI_SAHI_DADA_DADA_DADA_DADA_DADA_DADA_SALO_SALO_DALO_DALO_OPCO_OPCO_VV
-//DATF_DATE_DATD_DATC_DATB_DATA_DAT9_DAT8_DAT7_DAT6_DAT5_DAT4_DAT3_DAT2_DAT1_DAT0_DATF_DATE_DATD_DATC_DATB_DATA_DAT9_DAT8_DAT7_DAT6_DAT5_DAT4_DAT3_DAT2_DAT1_DAT0_SRCA_SRCA_SRCA_SRCA_DSTA_DSTA_DSTA_DSTA_UCMD_UCMD_VV
-  DEAD_BEEF_0000_0000_2222_2222_1111_1111_0000_0000_0000_0000_2222_2222_1111_1111_0000_0000_0000_0000_2222_2222_1111_1111_0000_0000_0000_2222_2222_1111_1111_0000_0000_0100_0000_0000_0000_0000_0000_0000_0040_1F25_01 // write buffer
-  DEAD_BEEF_0000_0000_4444_4444_3333_3333_0000_0000_0000_0000_4444_4444_3333_3333_0000_0000_0000_0000_4444_4444_3333_3333_0000_0000_0000_4444_4444_3333_3333_0000_0000_0100_0000_0000_0000_0000_1000_0008_0000_2F05_01
-  DEAD_BEEF_0000_0000_6666_6666_5555_5555_0000_0000_0000_0000_6666_6666_5555_5555_0000_0000_0000_0000_6666_6666_5555_5555_0000_0000_0000_6666_6666_5555_5555_0000_0000_0100_0000_0000_0000_0000_2000_0010_0040_3F05_01
-  DEAD_BEEF_0000_0000_8888_8888_7777_7777_0000_0000_0000_0000_8888_8888_7777_7777_0000_0000_0000_0000_8888_8888_7777_7777_0000_0000_0000_8888_8888_7777_7777_0000_0000_0100_0000_0000_0000_0000_3000_0018_0040_0F45_01
-  DEAD_BEEF_0000_0000_AAAA_AAAA_9999_9999_0000_0000_0000_0000_AAAA_AAAA_9999_9999_0000_0000_0000_0000_AAAA_AAAA_9999_9999_0000_0000_0000_AAAA_AAAA_9999_9999_0000_0000_0100_0000_0000_0000_0000_4000_0020_0040_3F05_01
-  DEAD_BEEF_0000_0000_CCCC_CCCC_BBBB_BBBB_0000_0000_0000_0000_CCCC_CCCC_BBBB_BBBB_0000_0000_0000_0000_CCCC_CCCC_BBBB_BBBB_0000_0000_0000_CCCC_CCCC_BBBB_BBBB_0000_0000_0100_0000_0000_0000_0000_5000_0028_0000_3F05_01
-  DEAD_BEEF_0000_0000_EEEE_EEEE_DDDD_DDDD_0000_0000_0000_0000_EEEE_EEEE_DDDD_DDDD_0000_0000_0000_0000_EEEE_EEEE_DDDD_DDDD_0000_0000_0000_EEEE_EEEE_DDDD_DDDD_0000_0000_0100_0000_0000_0000_0000_6000_0030_0000_3F05_01
-  DEAD_BEEF_0000_0000_0000_0000_FFFF_FFFF_0000_0000_0000_0000_0000_0000_FFFF_FFFF_0000_0000_0000_0000_0000_0000_FFFF_FFFF_0000_0000_0000_0000_0000_FFFF_FFFF_0000_0000_0100_0000_0000_0000_0000_7000_0038_0000_3F05_01
-  DEAD_BEEF_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0100_0000_6660_0000_0000_0000_0000_0000_3F01_01 // read buffer
-  DEAD_BEEF_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0100_0000_6661_0000_0000_0000_0008_0000_3F01_01
-  DEAD_BEEF_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0100_0000_6662_0000_0000_0000_0010_0000_3F01_01
-  DEAD_BEEF_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0100_0000_6663_0000_0000_0000_0018_0000_3F01_01
-  DEAD_BEEF_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0100_0000_6664_0000_0000_0000_0020_0000_3F01_01
-  DEAD_BEEF_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0100_0000_6665_0000_0000_0000_0028_0000_3F01_01
-  DEAD_BEEF_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0100_0000_6666_0000_0000_0000_0030_0000_3F01_01
-  DEAD_BEEF_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0100_0000_6667_0000_0000_0000_0038_0000_3F01_01
-  DEAD_BEEF_ABBA_ABBA_ABBA_ABBA_ABBA_ABBA_0000_ABBA_ABBA_ABBA_ABBA_ABBA_ABBA_ABBA_0000_ABBA_ABBA_ABBA_ABBA_ABBA_ABBA_ABBA_0000_ABBA_ABBA_ABBA_ABBA_ABBA_ABBA_0000_ABBA_ABBA_ABBA_ABBA_ABBA_ABBA_ABBA_ABBA_ABBA_ABBA_00 // 00=EOT
diff --git a/umi/testbench/build_local.sh b/umi/testbench/build_local.sh
deleted file mode 100755
index 8398072..0000000
--- a/umi/testbench/build_local.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-\rm -f a.out
-
-iverilog tb_umi_fifo_flex.v \
-         -y . \
-         -y ../rtl \
-         -I . \
-         -I ../rtl \
-         -y ../../submodules/lambdalib/stdlib/rtl \
-         -y ../../submodules/lambdalib/vectorlib/rtl \
-         -y ../../submodules/lambdalib/ramlib/rtl
-
-#./a.out
-#./a.out +MEMHFILE=./hello.memh
-./a.out +MEMHFILE=./buffer.memh
diff --git a/umi/testbench/dut_umi_fifo.v b/umi/testbench/dut_umi_fifo.v
index 3fb994b..cd66c07 100644
--- a/umi/testbench/dut_umi_fifo.v
+++ b/umi/testbench/dut_umi_fifo.v
@@ -1,14 +1,3 @@
-
-/******************************************************************************
- * Function:  UMI FIFO Device Under Test "DUT"
- * Author:    Andreas Olofsson
- * Copyright: 2022 Zero ASIC Corporation. All rights reserved.
- * License:
- *
- * Documentation:
- *
- *****************************************************************************/
-
 module dut_umi_fifo
   #(parameter TARGET   = "DEFAULT", // synthesis target
     parameter MONITOR  = 1,         // turn on umi monitor
@@ -23,36 +12,36 @@ module dut_umi_fifo
     parameter DEPTH    = 4          // fifo depth
     )
    (// generic control interface
-    input 		 nreset, // common async active low reset
-    input [NCLK-1:0] 	 clk, //  generic set of clocks
-    input 		 go, // go dut, go!
-    output 		 error, //dut  error
-    output 		 done, // dut done
-    input [NCTRL-1:0] 	 ctrl, // generic control vector (optional)
+    input                nreset, // common async active low reset
+    input [NCLK-1:0]     clk, //  generic set of clocks
+    input                go, // go dut, go!
+    output               error, //dut  error
+    output               done, // dut done
+    input [NCTRL-1:0]    ctrl, // generic control vector (optional)
     output [NSTATUS-1:0] status, // generic status vector (optional)
     // umi interfaces
-    input [NUMI-1:0] 	 umi_in_clk,
-    input [NUMI-1:0] 	 umi_in_nreset,
-    input [NUMI-1:0] 	 umi_in_valid,
+    input [NUMI-1:0]     umi_in_clk,
+    input [NUMI-1:0]     umi_in_nreset,
+    input [NUMI-1:0]     umi_in_valid,
     input [NUMI*CW-1:0]  umi_in_cmd,
     input [NUMI*AW-1:0]  umi_in_dstaddr,
     input [NUMI*AW-1:0]  umi_in_srcaddr,
     input [NUMI*DW-1:0]  umi_in_data,
-    output [NUMI-1:0] 	 umi_in_ready,
-    input [NUMI-1:0] 	 umi_out_clk,
-    input [NUMI-1:0] 	 umi_out_nreset,
-    output [NUMI-1:0] 	 umi_out_valid,
+    output [NUMI-1:0]    umi_in_ready,
+    input [NUMI-1:0]     umi_out_clk,
+    input [NUMI-1:0]     umi_out_nreset,
+    output [NUMI-1:0]    umi_out_valid,
     output [NUMI*CW-1:0] umi_out_cmd,
     output [NUMI*AW-1:0] umi_out_dstaddr,
     output [NUMI*AW-1:0] umi_out_srcaddr,
     output [NUMI*DW-1:0] umi_out_data,
-    input [NUMI-1:0] 	 umi_out_ready
+    input [NUMI-1:0]     umi_out_ready
     );
 
    // Local wires
-   reg 		slowclk;
-   wire 	fifo_empty;
-   wire 	fifo_full;
+   reg          slowclk;
+   wire         fifo_empty;
+   wire         fifo_full;
 
    /*AUTOINPUT*/
    /*AUTOWIRE*/
@@ -65,14 +54,14 @@ module dut_umi_fifo
     .chaosmode (1'b0),
     );*/
    umi_fifo  #(.CW(CW),
-	       .AW(AW),
-	       .DW(DW),
-	       .DEPTH(DEPTH),
-	       .TARGET(TARGET))
-   umi_fifo (.bypass			(1'b0),
-	     .vdd			(1'b1),
-	     .vss			(1'b0),
-	     /*AUTOINST*/
+               .AW(AW),
+               .DW(DW),
+               .DEPTH(DEPTH),
+               .TARGET(TARGET))
+   umi_fifo (.bypass                    (1'b0),
+             .vdd                       (1'b1),
+             .vss                       (1'b0),
+             /*AUTOINST*/
              // Outputs
              .fifo_full         (fifo_full),
              .fifo_empty        (fifo_empty),
diff --git a/umi/testbench/dut_umi_fifo_flex.v b/umi/testbench/dut_umi_fifo_flex.v
index ff8e0b2..5d0b63e 100644
--- a/umi/testbench/dut_umi_fifo_flex.v
+++ b/umi/testbench/dut_umi_fifo_flex.v
@@ -1,14 +1,3 @@
-
-/******************************************************************************
- * Function:  UMI FIFO Device Under Test "DUT"
- * Author:    Andreas Olofsson
- * Copyright: 2022 Zero ASIC Corporation. All rights reserved.
- * License:
- *
- * Documentation:
- *
- *****************************************************************************/
-
 module dut_umi_fifo_flex
   #(parameter TARGET = "DEFAULT", // synthesis target
     parameter BYPASS = 0,
@@ -53,8 +42,8 @@ module dut_umi_fifo_flex
     );
 
    // Local wires
-   wire 	fifo_empty;
-   wire 	fifo_full;
+   wire         fifo_empty;
+   wire         fifo_full;
 
    /*AUTOINPUT*/
    /*AUTOWIRE*/
@@ -67,16 +56,16 @@ module dut_umi_fifo_flex
     .chaosmode (1'b0),
     );*/
    umi_fifo_flex  #(.CW(CW),
-	            .AW(AW),
-	            .IDW(IDW),
-	            .ODW(ODW),
-	            .DEPTH(DEPTH),
-	            .TARGET(TARGET),
+                    .AW(AW),
+                    .IDW(IDW),
+                    .ODW(ODW),
+                    .DEPTH(DEPTH),
+                    .TARGET(TARGET),
                     .BYPASS(BYPASS))
-   umi_fifo_flex (.bypass		(bypass),
-	          .vdd			(1'b1),
-	          .vss			(1'b0),
-	           /*AUTOINST*/
+   umi_fifo_flex (.bypass               (bypass),
+                  .vdd                  (1'b1),
+                  .vss                  (1'b0),
+                   /*AUTOINST*/
                   // Outputs
                   .fifo_full            (fifo_full),
                   .fifo_empty           (fifo_empty),
diff --git a/umi/testbench/hello.memh b/umi/testbench/hello.memh
deleted file mode 100644
index 52b8742..0000000
--- a/umi/testbench/hello.memh
+++ /dev/null
@@ -1,3 +0,0 @@
-@0
-AAAA_AAAA_01 // WRITE
-0000_0000_00 // EOT
diff --git a/umi/testbench/scripts/README b/umi/testbench/scripts/README
deleted file mode 100644
index ea1e2f6..0000000
--- a/umi/testbench/scripts/README
+++ /dev/null
@@ -1,3 +0,0 @@
-
-The egen.pl is a dumb transaction generator for the emesh packet transactions. 
-./egen.pl -da "0x8e0800000" -sa "0x80800000" -d "0xABCD0000" -c 06 -n 64 > reads
\ No newline at end of file
diff --git a/umi/testbench/scripts/egen.pl b/umi/testbench/scripts/egen.pl
deleted file mode 100755
index fb9be48..0000000
--- a/umi/testbench/scripts/egen.pl
+++ /dev/null
@@ -1,191 +0,0 @@
-#! /usr/bin/perl
-use Getopt::Long;
-use POSIX qw(ceil floor);
-#######################################################
-# Author:  Andreas Olofsson, Nov 11, 2015
-#######################################################
-$Usage =<<EOF;
-#######################################################
-Usage: egen.pl  -mode <random|memcpy>
-                -n    <number-of-bytes>
-                -bl   <max-burst-in-bytes>
-#######################################################
-Description: 
-* Generates random Epiphany 104 bit packet transaction
-* Data is completely random
-* Data sizes are completely random
-* Address fields are random (but legal)
-* Random burst sizes up to <max-burst-length>
-* Default return address base is 810D0000
-* Default destination address base is 83000000
-#################################################################
-Example1: Generate a random test
-    
-egen.pl -mode random -n 1024 -bl 128
-
-Example2:
-    
-egen.pl -mode memcpy -n 1024 -dstaddr 90000000 -srcaddr 80000000
-
-################################################################
-EOF
-$result = GetOptions('mode:s',
-		     'dstaddr:s', 
-		     'srcaddr:s',
-		     'd:s',
-		     'c:s',  #ctrlmode 
-		     'n:s',
-		     'bl:s',
-		     '32:s',
-    );
-
-
-if ((!defined $opt_n) | (!defined $opt_mode) ) {
-    printf $Usage;
-    exit;
-}
-$n=$opt_n;
-$mode=$opt_mode;
-#####################################################################
-# OPTIONAL OPTIONS
-#####################################################################
-
-#MAX BURST
-if(defined $opt_bl){
-    $burst_max = $opt_bl;
-}
-else{
-    $burst_max = 4;
-}
-
-#LIMIT TO 32 BITS
-if(defined $opt_32){
-    $ctrl_max = 5;
-}
-else{
-    $ctrl_max = 7;
-}
-if(defined $did){
-    $addrid = $opt_did;
-}
-else{
-    $addrid  =hex("0x83000000"); #NOTE: should not be equal to RX ID
-}
-if(defined $sid){
-    $returnid=$sid;
-}
-else{
-    $returnid=hex("0x810D0000");
-}
-if(defined $opt_c){
-    $cltrmode=$opt_c;
-}
-else{
-    $ctrlmode = 5;	
-}
-
-$count =0;
-$bytes=0;
-#Writes
-$dstaddr    = hex($opt_dstaddr);
-$returnaddr = $returnid+ (hex($opt_srcaddr) & 0x000FFFFF);
-while($bytes<$n){
-    if($mode eq "random"){
-	$ctrlmode = (int(rand(hex($ctrl_max))) + 1)  | 0x1;  #only writes
-	$burst    = (int(rand($opt_bl)) + 1);         #variable bursts
-    }
-    else{
-
-	$burst = $n;
-    }
-    #BYTES
-    if($ctrlmode<2){
-	$addrmask = hex("0x0000ffff");
-	$maskhi   = hex("0x00000000");
-	$masklo   = hex("0x000000FF");
-	$incr     = 1;
-    }
-    #HALF-WORD
-    elsif($ctrlmode<4){
-	$addrmask = hex("0x0000fffe");
-	$maskhi   = hex("0x00000000");
-	$masklo   = hex("0x0000FFFF");
-	$incr     = 2;
-    }
-    #WORD
-    elsif($ctrlmode<6){
-	$addrmask = hex("0x0000fffc");
-	$maskhi   = hex("0x00000000");
-	$masklo   = hex("0xFFFFFFFF");
-	$incr     = 4;
-    }
-    #DOUBLE
-    else{
-	$addrmask = hex("0x0000fff8");
-	$maskhi   = hex("0xFFFFFFFF");
-	$masklo   = hex("0xFFFFFFFF");
-	$incr     = 8;
-    }
-    $burst=floor($burst/$incr);
-
-    #randomize destination address
-    if($mode eq "random"){
-	$dstaddr    = $addrid + ((int(rand(hex("0xFFFFFFFF"))) + 0) & $addrmask); #filter "D/F group" and illegal aligns
-	$returnaddr = $returnid+((int(rand(hex("0xFFFFFFFF")))) & $addrmask);
-    }
-    #create a burst of transactions
-    for ($j=0;$j<$burst;$j++){ 
-	$datalo     = (int(rand(hex("0xFFFFFFFF"))) + 0) & 0xFFFFFFFF;	
-	$datahi     = (int(rand(hex("0xFFFFFFFF"))) + 0) & 0xFFFFFFFF;		    
-	
-	#make sure address wasn't used already
-	$inuse=0;
-	for($k=0;$k<$incr;$k++){	    
-	    $addr=$dstaddr+$k;
-	    #check if in use
-	    if(exists ($usedaddr{$addr})){
-		$inuse=1;
-	    }
-	    #set as used	       
-	    $usedaddr{$addr}=1;
-	}	   
-	if($inuse == 0){
-	    $transaction[$count]{dstaddr}   =$dstaddr;
-	    $transaction[$count]{srcaddr}   =$datahi;
-	    $transaction[$count]{data}      =$datalo;
-	    $transaction[$count]{reslo}     =$datalo & $masklo;
-	    $transaction[$count]{reshi}     =$datahi & $maskhi; 
-	    $transaction[$count]{ctrlmode}  =$ctrlmode;
-	    $transaction[$count]{returnaddr}=$returnaddr;
-	    $transaction[$count]{burst}     =$burst;		
-	    printf("%08x_%08x_%08x_%02x_0000//WRITE (i=%d, j=%d, bytes=%d)\n",
-		   $datahi,$datalo,$dstaddr,$ctrlmode, $count, $j, $bytes);
-	    $bytes      = $bytes+$incr;
-	    $count      = $count+1;
-	    $dstaddr    = $dstaddr+$incr;
-	    $returnaddr = $returnaddr+$incr;
-	}	    	   	   
-	else{
-	    #printf("ADDR %08x in USE (CTRLMODE=%04x)\n",$dstaddr,$ctrlmode);
-	}
-	#print "b=$bytes incr=$incr transaction-burst=$burst ctrl=$ctrlmode count=$count use=$inuse n=$n\n";
-    }
-}
-#Reads/Expected results
-for ($i=0;$i<($#transaction+1);$i++){
-    #Pushing read transactions
-    printf("%08x_%08x_%08x_%02x_0000//READ\n",
-	   $transaction[$i]{returnaddr},       #address to return to
-	   hex("0xDEADBEEF"), 
-	   $transaction[$i]{dstaddr},           
-	   $transaction[$i]{ctrlmode}&hex(0x6) #turn write into read
-	);	
-    #Expected results
-    printf("%08x_%08x_%08x_%02x\n",
-	   $transaction[$i]{reshi},
-	   $transaction[$i]{reslo},
-	   $transaction[$i]{returnaddr},
-	   $transaction[$i]{ctrlmode}
-	);	
-}
-
diff --git a/umi/testbench/tb_umi_arbiter.v b/umi/testbench/tb_umi_arbiter.v
deleted file mode 100644
index e4bddce..0000000
--- a/umi/testbench/tb_umi_arbiter.v
+++ /dev/null
@@ -1,60 +0,0 @@
-
-module testbench();
-
-   localparam N=4;
-   localparam PERIOD_CLK = 10;
-
-   reg [N-1:0] requests;
-   reg 	       nreset;
-   reg 	       clk;
-
-  // reset initialization
-   initial
-     begin
-	#(1)
-	nreset   = 1'b0;
-	clk      = 1'b0;
-	#(PERIOD_CLK * 10)
-	nreset   = 1'b1;
-     end // initial begin
-
-   // clocks
-   always
-     #(PERIOD_CLK/2) clk = ~clk;
-
-
-   always @ (posedge clk or negedge nreset)
-     if(~nreset)
-       requests <= 'b0;
-     else
-       requests <= requests+1'b1;
-
-     initial
-       begin
-          $dumpfile("waveform.vcd");
-          $dumpvars();
-	  #500
-          $finish;
-       end
-
-   /*AUTOWIRE*/
-   // Beginning of automatic wires (for undeclared instantiated-module outputs)
-   wire [N-1:0]         grants;
-   // End of automatics
-
-   umi_arbiter #(.N(N))
-   umi_arbiter  (.mode			(2'b00),
-		 .mask			({(N){1'b0}}),
-		 /*AUTOINST*/
-                 // Outputs
-                 .grants                (grants[N-1:0]),
-                 // Inputs
-                 .clk                   (clk),
-                 .nreset                (nreset),
-                 .requests              (requests[N-1:0]));
-
-
-endmodule
-// Local Variables:
-// verilog-library-directories:("." "../rtl")
-// End:
diff --git a/umi/testbench/tb_umi_crossbar.v b/umi/testbench/tb_umi_crossbar.v
deleted file mode 100644
index 66eee88..0000000
--- a/umi/testbench/tb_umi_crossbar.v
+++ /dev/null
@@ -1,100 +0,0 @@
-
-module testbench();
-
-   localparam N          = 2;
-   localparam DW         = 16;
-   localparam AW         = 64;
-   localparam CW         = 32;
-   localparam PERIOD_CLK = 10;
-
-   reg [N*CW-1:0] umi_in_cmd;
-   reg [N*AW-1:0] umi_in_dstaddr;
-   reg [N*AW-1:0] umi_in_srcaddr;
-   reg [N*DW-1:0] umi_in_data;
-   reg [N*N-1:0]  umi_in_request;
-   reg [N*N-1:0]  mask;
-   reg [N-1:0] 	  umi_out_ready;
-   reg 		  nreset;
-   reg 		  clk;
-
-  // reset initialization
-   initial
-     begin
-	#(1)
-	nreset   = 1'b0;
-	clk      = 1'b0;
-	#(PERIOD_CLK * 10)
-	nreset   = 1'b1;
-        mask = {N*N{1'b0}};
-        umi_in_data[0*DW+:DW] = {(DW/4){4'hA}};
-	umi_in_data[1*DW+:DW] = {(DW/4){4'hB}};
-        umi_in_cmd[CW-1:0] = 'b0;
-        umi_in_dstaddr[AW-1:0] = 'b0;
-        umi_in_srcaddr[AW-1:0] = 'b0;
-     end // initial begin
-
-   // clocks
-   always
-     #(PERIOD_CLK/2) clk = ~clk;
-
-   // test vectors
-
-
-   always @ (posedge clk or negedge nreset)
-     if(~nreset)
-       begin
-	  umi_out_ready  <='b0;
-	  umi_in_request <='b0;
-       end
-     else
-       begin
-	  umi_out_ready  <= umi_out_ready+1'b1;
-	  umi_in_request <= umi_in_request+1'b1;
-       end
-     initial
-       begin
-          $dumpfile("waveform.vcd");
-          $dumpvars();
-	  #500
-          $finish;
-       end
-
-   /*AUTOWIRE*/
-   // Beginning of automatic wires (for undeclared instantiated-module outputs)
-   wire [N-1:0]         umi_in_ready;
-   wire [N*CW-1:0]      umi_out_cmd;
-   wire [N*DW-1:0]      umi_out_data;
-   wire [N*AW-1:0]      umi_out_dstaddr;
-   wire [N*AW-1:0]      umi_out_srcaddr;
-   wire [N-1:0]         umi_out_valid;
-   // End of automatics
-
-   umi_crossbar #(.N(N),
-                  .CW(CW),
-                  .AW(AW),
-		  .DW(DW))
-   umi_crossbar  (.mode			(2'b00),
-		  /*AUTOINST*/
-                  // Outputs
-                  .umi_in_ready         (umi_in_ready[N-1:0]),
-                  .umi_out_valid        (umi_out_valid[N-1:0]),
-                  .umi_out_cmd          (umi_out_cmd[N*CW-1:0]),
-                  .umi_out_dstaddr      (umi_out_dstaddr[N*AW-1:0]),
-                  .umi_out_srcaddr      (umi_out_srcaddr[N*AW-1:0]),
-                  .umi_out_data         (umi_out_data[N*DW-1:0]),
-                  // Inputs
-                  .clk                  (clk),
-                  .nreset               (nreset),
-                  .mask                 (mask[N*N-1:0]),
-                  .umi_in_request       (umi_in_request[N*N-1:0]),
-                  .umi_in_cmd           (umi_in_cmd[N*CW-1:0]),
-                  .umi_in_dstaddr       (umi_in_dstaddr[N*AW-1:0]),
-                  .umi_in_srcaddr       (umi_in_srcaddr[N*AW-1:0]),
-                  .umi_in_data          (umi_in_data[N*DW-1:0]),
-                  .umi_out_ready        (umi_out_ready[N-1:0]));
-
-
-endmodule
-// Local Variables:
-// verilog-library-directories:("." "../rtl")
-// End:
diff --git a/umi/testbench/tb_umi_fifo.v b/umi/testbench/tb_umi_fifo.v
deleted file mode 100644
index 58dd31c..0000000
--- a/umi/testbench/tb_umi_fifo.v
+++ /dev/null
@@ -1,217 +0,0 @@
-/******************************************************************************
- * Function:  UMI FIFO Testbench
- * Author:    Andreas Olofsson
- * Copyright: 2022 Zero ASIC Corporation. All rights reserved.
- * License:
- *
- * Documentation:
- *
- *
- *****************************************************************************/
-
-module tb_umi_fifo
-  #(parameter TARGET     = "DEFAULT",   // pass through variable for hard macro
-    parameter TIMEOUT    = 5000,        // timeout value (cycles)
-    parameter PERIOD_CLK = 10,          // clock period
-    parameter FIFODEPTH  = 4,           // fifo depth
-    parameter CW         = 32,          // UMI width
-    parameter AW         = 64,          // UMI width
-    parameter DW         = 512          // UMI width
-    )
-   ();
-
-   //####################
-   // LOCAL PARAMS
-   //####################
-
-   localparam STIMDEPTH = 1024;
-   localparam NUMI      = 1;
-   localparam TCW       = 8;
-
-   //#####################
-   //# SIMCTRL
-   //#####################
-   reg umi_dut2check_ready;
-
-   reg [128*8-1:0] memhfile;
-   reg 		   slowclk;
-   reg 		   clk;
-   reg 		   load;
-   reg 		   nreset;
-   reg 		   dut_nreset;
-   reg 		   go;
-   integer 	   r;
-
-   // reset initialization
-   initial
-     begin
-	#(1)
-	nreset   = 1'b0;
-	dut_nreset = 1'b0;
-	clk      = 1'b0;
-	load     = 1'b0;
-	go       = 1'b0;
-	#(PERIOD_CLK)
-	go       = 1'b1;
-        nreset   = 1'b1;
-	#(PERIOD_CLK * 10)
-	dut_nreset   = 1'b1;
-//	#(PERIOD_CLK * 10)
-//	go       = 1'b1;
-     end // initial begin
-
-   // clocks
-   always
-     #(PERIOD_CLK/2) clk = ~clk;
-
-   // control block
-   initial
-     begin
-	r = $value$plusargs("MEMHFILE=%s", memhfile);
-	$readmemh(memhfile, umi_stimulus.ram);
-        $timeformat(-9, 0, " ns", 20);
-        $dumpfile("waveform.vcd");
-        $dumpvars();
-	#(TIMEOUT)
-        $finish;
-     end
-
-   always @ (posedge slowclk or negedge nreset)
-     if(~nreset)
-       umi_dut2check_ready <= 1'b0;
-     else
-       umi_dut2check_ready <= ~umi_dut2check_ready;
-
-   // clock divider
-   always @ (posedge clk or negedge nreset)
-     if (~nreset)
-       slowclk <= 1'b0;
-     else
-       slowclk <= ~slowclk;
-
-   la_rsync la_rsync (// Outputs
-		      .nrst_out		(slownreset),
-		      // Inputs
-		      .clk		(slowclk),
-		      .nrst_in		(nreset));
-
-
-   /*AUTOWIRE*/
-   // Beginning of automatic wires (for undeclared instantiated-module outputs)
-   wire                 done;
-   wire                 error;
-   wire [NUMI*CW-1:0]   umi_dut2check_cmd;
-   wire [NUMI*DW-1:0]   umi_dut2check_data;
-   wire [NUMI*AW-1:0]   umi_dut2check_dstaddr;
-   wire [NUMI*AW-1:0]   umi_dut2check_srcaddr;
-   wire [NUMI-1:0]      umi_dut2check_valid;
-   wire [CW-1:0]        umi_stim2dut_cmd;
-   wire [DW-1:0]        umi_stim2dut_data;
-   wire                 umi_stim2dut_done;
-   wire [AW-1:0]        umi_stim2dut_dstaddr;
-   wire [NUMI-1:0]      umi_stim2dut_ready;
-   wire [AW-1:0]        umi_stim2dut_srcaddr;
-   wire                 umi_stim2dut_valid;
-   // End of automatics
-
-   //################################################
-   //# DUT
-   //#################################################
-
-   /*dut_umi_fifo AUTO_TEMPLATE (
-    .clk                (clk),
-    .ctrl               (1'b0),
-    .status             (),
-    .umi_out_clk	(slowclk),
-    .umi_out_nreset     (slownreset),
-    .umi_out_ready	(1'b1),
-    .umi_out_\(.*\)	(umi_dut2check_\1[]),
-    .umi_in_clk	        (clk),
-    .umi_in_nreset      (nreset),
-    .umi_in_valid       (umi_stim2dut_valid),
-    .umi_in_\(.*\)	(umi_stim2dut_\1[]),
-    );
-    */
-
-   dut_umi_fifo #(.CW(CW),
-		  .AW(AW),
-		  .DW(DW),
-		  .DEPTH(FIFODEPTH))
-   dut_umi_fifo (.umi_out_ready		(umi_dut2check_ready),
-		 /*AUTOINST*/
-                 // Outputs
-                 .error                 (error),
-                 .done                  (done),
-                 .status                (),                      // Templated
-                 .umi_in_ready          (umi_stim2dut_ready[NUMI-1:0]), // Templated
-                 .umi_out_valid         (umi_dut2check_valid[NUMI-1:0]), // Templated
-                 .umi_out_cmd           (umi_dut2check_cmd[NUMI*CW-1:0]), // Templated
-                 .umi_out_dstaddr       (umi_dut2check_dstaddr[NUMI*AW-1:0]), // Templated
-                 .umi_out_srcaddr       (umi_dut2check_srcaddr[NUMI*AW-1:0]), // Templated
-                 .umi_out_data          (umi_dut2check_data[NUMI*DW-1:0]), // Templated
-                 // Inputs
-                 .nreset                (dut_nreset),
-                 .clk                   (clk),                   // Templated
-                 .go                    (go),
-                 .ctrl                  (1'b0),                  // Templated
-                 .umi_in_clk            (clk),                   // Templated
-                 .umi_in_nreset         (dut_nreset),                // Templated
-                 .umi_in_valid          (umi_stim2dut_valid),    // Templated
-                 .umi_in_cmd            (umi_stim2dut_cmd[NUMI*CW-1:0]), // Templated
-                 .umi_in_dstaddr        (umi_stim2dut_dstaddr[NUMI*AW-1:0]), // Templated
-                 .umi_in_srcaddr        (umi_stim2dut_srcaddr[NUMI*AW-1:0]), // Templated
-                 .umi_in_data           (umi_stim2dut_data[NUMI*DW-1:0]), // Templated
-                 .umi_out_clk           (slowclk),               // Templated
-                 .umi_out_nreset        (slownreset));           // Templated
-
-   //##################################################
-   //# UMI STIMULUS DRIVER (CLK)
-   //##################################################
-
-   /*umi_stimulus AUTO_TEMPLATE (
-    // Outputs
-    .stim_\(.*\)	(umi_stim2dut_\1[]),
-    .dut_ready          (umi_stim2dut_ready),
-    .ext_valid		(1'b0),
-    .ext_packet		({(DW+AW+AW+CW+TCW){1'b0}}),
-    .\(.*\)_clk         (clk),
-    );
-    */
-
-   umi_stimulus #(.DEPTH(STIMDEPTH),
-		  .TARGET(TARGET),
-		  .CW(CW),
-		  .AW(AW),
-		  .DW(DW),
-		  .TCW(TCW))
-   umi_stimulus (/*AUTOINST*/
-                 // Outputs
-                 .stim_valid            (umi_stim2dut_valid),    // Templated
-                 .stim_cmd              (umi_stim2dut_cmd[CW-1:0]), // Templated
-                 .stim_dstaddr          (umi_stim2dut_dstaddr[AW-1:0]), // Templated
-                 .stim_srcaddr          (umi_stim2dut_srcaddr[AW-1:0]), // Templated
-                 .stim_data             (umi_stim2dut_data[DW-1:0]), // Templated
-                 .stim_done             (umi_stim2dut_done),     // Templated
-                 // Inputs
-                 .nreset                (nreset),
-                 .load                  (load),
-                 .go                    (go),
-                 .ext_clk               (clk),                   // Templated
-                 .ext_valid             (1'b0),                  // Templated
-                 .ext_packet            ({(DW+AW+AW+CW+TCW){1'b0}}), // Templated
-                 .dut_clk               (clk),                   // Templated
-                 .dut_ready             (umi_stim2dut_ready));   // Templated
-
-   //###################################################
-   //# TRAFFIC MONITOR (SLOWCLK)
-   //###################################################
-
-   always @ (negedge slowclk)
-     if(umi_dut2check_valid & umi_dut2check_ready)
-       $display("dut result: data=%h, srcaddr=%h, dstaddr=%h, cmd=%h", umi_dut2check_data[DW-1:0], umi_dut2check_srcaddr[AW-1:0],umi_dut2check_dstaddr[AW-1:0],umi_dut2check_cmd[CW-1:0]);
-
-
-endmodule // testbench
-// Local Variables:
-// verilog-library-directories:("." "../rtl" "../../submodules/oh/stdlib/rtl/" "../../submodules/oh/stdlib/testbench/")
-// End:
diff --git a/umi/testbench/tb_umi_fifo_flex.v b/umi/testbench/tb_umi_fifo_flex.v
deleted file mode 100644
index 5a658d6..0000000
--- a/umi/testbench/tb_umi_fifo_flex.v
+++ /dev/null
@@ -1,228 +0,0 @@
-/******************************************************************************
- * Function:  UMI FIFO Testbench
- * Author:    Andreas Olofsson
- * Copyright: 2022 Zero ASIC Corporation. All rights reserved.
- * License:
- *
- * Documentation:
- *
- *
- *****************************************************************************/
-
-module tb_umi_fifo
-  #(parameter TARGET     = "DEFAULT",   // pass through variable for hard macro
-    parameter TIMEOUT    = 5000,        // timeout value (cycles)
-    parameter PERIOD_CLK = 10,          // clock period
-    parameter FIFODEPTH  = 4            // fifo depth
-    )
-   ();
-
-   //####################
-   // LOCAL PARAMS
-   //####################
-
-   localparam STIMDEPTH = 1024;
-   localparam NUMI      = 1;
-   localparam TCW       = 8;
-   localparam CW        = 32;          // UMI width
-   localparam AW        = 64;          // UMI width
-   localparam IDW       = 512;         // UMI width
-   localparam ODW       = 128;          // UMI width
-   localparam DW        = IDW;
-   localparam BYPASS    = 0;
-
-   //#####################
-   //# SIMCTRL
-   //#####################
-   reg umi_dut2check_ready;
-
-   reg [128*8-1:0] memhfile;
-   reg             slowclk;
-   reg             clk;
-   reg             load;
-   reg             nreset;
-   reg             early_nreset;
-   reg             go;
-   integer         r;
-
-   // reset initialization
-   initial
-     begin
-        #(1)
-        nreset       = 1'b0;
-        early_nreset = 1'b0;
-        clk      =  1'b0;
-        load     = 1'b0;
-        go       = 1'b0;
-        #(PERIOD_CLK * 5)
-        early_nreset   = 1'b1;
-        #(PERIOD_CLK * 10)
-        nreset   = 1'b1;
-        #(PERIOD_CLK * 10)
-        go       = 1'b1;
-     end // initial begin
-
-   // clocks
-   always
-     #(PERIOD_CLK/2) clk = ~clk;
-
-   // control block
-   initial
-     begin
-        r = $value$plusargs("MEMHFILE=%s", memhfile);
-        $readmemh(memhfile, umi_stimulus.ram);
-        $timeformat(-9, 0, " ns", 20);
-        $dumpfile("waveform.vcd");
-        $dumpvars();
-        #(TIMEOUT)
-        $finish;
-     end
-
-   always @ (posedge slowclk or negedge nreset)
-     if(~nreset)
-       umi_dut2check_ready <= 1'b0;
-     else
-       umi_dut2check_ready <= ~umi_dut2check_ready;
-
-   generate if (BYPASS)
-     always @*
-       slowclk = clk;
-   else
-     // clock divider
-     always @ (posedge clk or negedge early_nreset)
-       if (~early_nreset)
-         slowclk <= 1'b0;
-       else
-         slowclk <= ~slowclk;
-   endgenerate
-
-   la_rsync la_rsync (// Outputs
-                      .nrst_out         (slownreset),
-                      // Inputs
-                      .clk              (slowclk),
-                      .nrst_in          (nreset));
-
-
-   /*AUTOWIRE*/
-   // Beginning of automatic wires (for undeclared instantiated-module outputs)
-   wire                 done;
-   wire                 error;
-   wire [NUMI*CW-1:0]   umi_dut2check_cmd;
-   wire [NUMI*ODW-1:0]  umi_dut2check_data;
-   wire [NUMI*AW-1:0]   umi_dut2check_dstaddr;
-   wire [NUMI*AW-1:0]   umi_dut2check_srcaddr;
-   wire [NUMI-1:0]      umi_dut2check_valid;
-   wire [CW-1:0]        umi_stim2dut_cmd;
-   wire [DW-1:0]        umi_stim2dut_data;
-   wire                 umi_stim2dut_done;
-   wire [AW-1:0]        umi_stim2dut_dstaddr;
-   wire [NUMI-1:0]      umi_stim2dut_ready;
-   wire [AW-1:0]        umi_stim2dut_srcaddr;
-   wire                 umi_stim2dut_valid;
-   // End of automatics
-
-   //################################################
-   //# DUT
-   //#################################################
-
-   /*dut_umi_fifo_flex AUTO_TEMPLATE (
-    .clk                (clk),
-    .ctrl               (1'b0),
-    .status             (),
-    .bypass             (|BYPASS),
-    .umi_out_clk        (slowclk),
-    .umi_out_nreset     (slownreset),
-    .umi_out_ready      (1'b1),
-    .umi_out_\(.*\)     (umi_dut2check_\1[]),
-    .umi_in_clk         (clk),
-    .umi_in_nreset      (nreset),
-    .umi_in_valid       (umi_stim2dut_valid),
-    .umi_in_\(.*\)      (umi_stim2dut_\1[]),
-    );
-    */
-
-   dut_umi_fifo_flex #(.CW(CW),
-                       .IDW(IDW),
-                       .AW(AW),
-                       .ODW(ODW),
-                       .DEPTH(FIFODEPTH),
-                       .BYPASS(BYPASS))
-   dut_umi_fifo_flex (.umi_out_ready            (umi_dut2check_ready),
-                       /*AUTOINST*/
-                      // Outputs
-                      .error            (error),
-                      .done             (done),
-                      .status           (),                      // Templated
-                      .umi_in_ready     (umi_stim2dut_ready[NUMI-1:0]), // Templated
-                      .umi_out_valid    (umi_dut2check_valid[NUMI-1:0]), // Templated
-                      .umi_out_cmd      (umi_dut2check_cmd[NUMI*CW-1:0]), // Templated
-                      .umi_out_dstaddr  (umi_dut2check_dstaddr[NUMI*AW-1:0]), // Templated
-                      .umi_out_srcaddr  (umi_dut2check_srcaddr[NUMI*AW-1:0]), // Templated
-                      .umi_out_data     (umi_dut2check_data[NUMI*ODW-1:0]), // Templated
-                      // Inputs
-                      .nreset           (nreset),
-                      .clk              (clk),                   // Templated
-                      .go               (go),
-                      .ctrl             (1'b0),                  // Templated
-                      .bypass           (|BYPASS),               // Templated
-                      .umi_in_clk       (clk),                   // Templated
-                      .umi_in_nreset    (nreset),                // Templated
-                      .umi_in_valid     (umi_stim2dut_valid),    // Templated
-                      .umi_in_cmd       (umi_stim2dut_cmd[NUMI*CW-1:0]), // Templated
-                      .umi_in_dstaddr   (umi_stim2dut_dstaddr[NUMI*AW-1:0]), // Templated
-                      .umi_in_srcaddr   (umi_stim2dut_srcaddr[NUMI*AW-1:0]), // Templated
-                      .umi_in_data      (umi_stim2dut_data[NUMI*IDW-1:0]), // Templated
-                      .umi_out_clk      (slowclk),               // Templated
-                      .umi_out_nreset   (slownreset));           // Templated
-
-   //##################################################
-   //# UMI STIMULUS DRIVER (CLK)
-   //##################################################
-
-   /*umi_stimulus AUTO_TEMPLATE (
-    // Outputs
-    .stim_\(.*\)        (umi_stim2dut_\1[]),
-    .dut_ready          (umi_stim2dut_ready[]),
-    .ext_valid          (1'b0),
-    .ext_packet         ({(IDW+AW+AW+CW+TCW){1'b0}}),
-    .\(.*\)_clk         (clk),
-    );
-    */
-
-   umi_stimulus #(.DEPTH(STIMDEPTH),
-                  .TARGET(TARGET),
-                  .CW(CW),
-                  .AW(AW),
-                  .DW(IDW),
-                  .TCW(TCW))
-   umi_stimulus (/*AUTOINST*/
-                 // Outputs
-                 .stim_valid            (umi_stim2dut_valid),    // Templated
-                 .stim_cmd              (umi_stim2dut_cmd[CW-1:0]), // Templated
-                 .stim_dstaddr          (umi_stim2dut_dstaddr[AW-1:0]), // Templated
-                 .stim_srcaddr          (umi_stim2dut_srcaddr[AW-1:0]), // Templated
-                 .stim_data             (umi_stim2dut_data[DW-1:0]), // Templated
-                 .stim_done             (umi_stim2dut_done),     // Templated
-                 // Inputs
-                 .nreset                (nreset),
-                 .load                  (load),
-                 .go                    (go),
-                 .ext_clk               (clk),                   // Templated
-                 .ext_valid             (1'b0),                  // Templated
-                 .ext_packet            ({(IDW+AW+AW+CW+TCW){1'b0}}), // Templated
-                 .dut_clk               (clk),                   // Templated
-                 .dut_ready             (umi_stim2dut_ready));   // Templated
-
-   //###################################################
-   //# TRAFFIC MONITOR (SLOWCLK)
-   //###################################################
-
-   always @ (negedge slowclk)
-     if(umi_dut2check_valid & umi_dut2check_ready)
-       $display("dut result: data=%h, srcaddr=%h, dstaddr=%h, cmd=%h", umi_dut2check_data[DW-1:0], umi_dut2check_srcaddr[AW-1:0],umi_dut2check_dstaddr[AW-1:0],umi_dut2check_cmd[CW-1:0]);
-
-
-endmodule // testbench
-// Local Variables:
-// verilog-library-directories:("." "../rtl" "../../submodules/oh/stdlib/rtl/" "../../submodules/oh/stdlib/testbench/")
-// End:
diff --git a/umi/testbench/tb_umi_priority.v b/umi/testbench/tb_umi_priority.v
deleted file mode 100644
index 91081ef..0000000
--- a/umi/testbench/tb_umi_priority.v
+++ /dev/null
@@ -1,53 +0,0 @@
-
-module testbench();
-
-   localparam N=4;
-   localparam PERIOD_CLK = 10;
-
-   reg [N-1:0] umi_in_valid;
-   reg 	       nreset;
-   reg 	       clk;
-
-
-  // reset initialization
-   initial
-     begin
-	#(1)
-	nreset   = 1'b0;
-	clk      = 1'b0;
-	#(PERIOD_CLK * 10)
-	nreset   = 1'b1;
-     end // initial begin
-
-   // clocks
-   always
-     #(PERIOD_CLK/2) clk = ~clk;
-
-
-   always @ (posedge clk or negedge nreset)
-     if(~nreset)
-       umi_in_valid <='b0;
-     else
-       umi_in_valid <=umi_in_valid+1'b1;
-
-     initial
-       begin
-          $dumpfile("waveform.vcd");
-          $dumpvars();
-	  #500
-          $finish;
-       end
-
-   /*AUTOWIRE*/
-   // Beginning of automatic wires (for undeclared instantiated-module outputs)
-   wire [N-1:0]		umi_out_valid;		// From umi_priority of umi_priority.v
-   // End of automatics
-
-   umi_priority umi_priority  (/*AUTOINST*/
-			       // Outputs
-			       .umi_out_valid	(umi_out_valid[N-1:0]),
-			       // Inputs
-			       .umi_in_valid	(umi_in_valid[N-1:0]));
-
-
-endmodule
diff --git a/umi/testbench/tb_umi_regif.v b/umi/testbench/tb_umi_regif.v
deleted file mode 100644
index 0c5fe51..0000000
--- a/umi/testbench/tb_umi_regif.v
+++ /dev/null
@@ -1,175 +0,0 @@
-
-module testbench();
-
-`include "umi_messages.vh"
-
-   localparam N          = 1;
-   localparam CW         = 32;
-   localparam AW         = 64;
-   localparam DW         = 512;
-   localparam RW         = 64;
-   localparam PERIOD_CLK = 10;
-   localparam RAMDEPTH   = 1024;
-
-   reg [N-1:0] 	 udev_req_valid;
-   reg [CW-1:0]  udev_req_cmd;
-   reg [AW-1:0]  udev_req_dstaddr;
-   reg [N-1:0] 	 udev_resp_ready;
-   reg 		 nreset;
-   reg 		 clk;
-
-   reg [RW-1:0]  ram [1023:0];
-   reg [RW-1:0]  reg_rddata;
-   reg [$clog2(RAMDEPTH)-1:0] ram_addr;
-   reg [AW-1:0]               addr_latch;
-   reg                        reg_read_d1;
-   reg                        error;
-
-   /*AUTOWIRE*/
-   // Beginning of automatic wires (for undeclared instantiated-module outputs)
-   wire [AW-1:0]        reg_addr;
-   wire [7:0]           reg_len;
-   wire [4:0]           reg_opcode;
-   wire                 reg_read;
-   wire [2:0]           reg_size;
-   wire [RW-1:0]        reg_wrdata;
-   wire                 reg_write;
-   wire                 udev_req_ready;
-   wire [CW-1:0]        udev_resp_cmd;
-   wire [DW-1:0]        udev_resp_data;
-   wire [AW-1:0]        udev_resp_srcaddr;
-   wire                 udev_resp_valid;
-   // End of automatics
-
-   // Run Sim
-   initial
-     begin
-        $dumpfile("waveform.vcd");
-        $dumpvars();
-     end
-
-   always @(posedge clk)
-     if (nreset)
-       begin
-//          if (udev_req_valid)
-//            $display("addr: %h", udev_req_dstaddr);
-          if (!udev_req_valid & (&ram_addr))
-            begin
-               #100;
-               if (error)
-                 $display("Test failed :-(");
-               else
-                 $display("Test passed :-)");
-               $finish;
-            end
-       end
-
-  // Reset/init
-   initial
-     begin
-	#(1)
-        addr_latch = 'b0;
-        error    = 1'b0;
-        nreset   = 1'b0;
-	clk      = 1'b0;
-	#(PERIOD_CLK * 10)
-	nreset        = 1'b1;
-     end // initial begin
-
-   // clocks
-   always
-     #(PERIOD_CLK/2) clk = ~clk;
-
-   // write followed by read for all addresses
-   // ignore LSB of address
-   always @ (posedge clk or negedge nreset)
-     if(~nreset)
-       begin
-          ram_addr         <= 0;
-          udev_req_valid   <= 1'b0;
-	  udev_req_dstaddr <= 'b0;
-	  udev_req_cmd     <= 'b0;
-	  udev_resp_ready  <= 1'b1;
-       end
-     else if(udev_req_ready)
-       if ((&ram_addr) & (udev_req_cmd[4:0] == UMI_REQ_READ)) // end of stimuli
-         begin
-            udev_req_valid <= 1'b0;
-         end
-       else
-         begin
-            udev_req_valid   <= (&ram_addr) ? 1'b0 : 1'b1;
-            udev_req_cmd     <= (udev_req_cmd[4:0] == UMI_REQ_WRITE) ? UMI_REQ_READ : UMI_REQ_WRITE;
-	    ram_addr         <= (udev_req_cmd[4:0] == UMI_REQ_WRITE) ? ram_addr : ram_addr + 1'b1;
-            udev_req_dstaddr <= (udev_req_cmd[4:0] == UMI_REQ_WRITE) ? udev_req_dstaddr : $random%16777215;//reg addr has 24 bits
-         end
-
-   //###########################################
-   // DUT
-   //###########################################
-   /*umi_regif AUTO_TEMPLATE(
-    .udev_req_srcaddr  ({@"vl-width"{1'b0}}),
-    .udev_req_data     ({DW/AW{udev_req_dstaddr[AW-1:0]}}),
-    .udev_resp_dstaddr (),
-    );*/
-
-   umi_regif #(.CW(CW),
-               .AW(AW),
-               .DW(DW),
-               .RW(RW))
-   umi_regif (/*AUTOINST*/
-              // Outputs
-              .udev_req_ready   (udev_req_ready),
-              .udev_resp_valid  (udev_resp_valid),
-              .udev_resp_cmd    (udev_resp_cmd[CW-1:0]),
-              .udev_resp_dstaddr(),                      // Templated
-              .udev_resp_srcaddr(udev_resp_srcaddr[AW-1:0]),
-              .udev_resp_data   (udev_resp_data[DW-1:0]),
-              .reg_addr         (reg_addr[AW-1:0]),
-              .reg_write        (reg_write),
-              .reg_read         (reg_read),
-              .reg_opcode       (reg_opcode[4:0]),
-              .reg_size         (reg_size[2:0]),
-              .reg_len          (reg_len[7:0]),
-              .reg_wrdata       (reg_wrdata[RW-1:0]),
-              // Inputs
-              .clk              (clk),
-              .nreset           (nreset),
-              .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 ({AW{1'b0}}),            // Templated
-              .udev_req_data    ({DW/AW{udev_req_dstaddr[AW-1:0]}}), // Templated
-              .udev_resp_ready  (udev_resp_ready),
-              .reg_rddata       (reg_rddata[RW-1:0]));
-
-
-   // Dummy RAM
-   always @(posedge clk)
-     if (reg_write)
-       ram[ram_addr[$clog2(RAMDEPTH)-1:1]] <= reg_wrdata[RW-1:0];
-
-   always @(posedge clk or negedge nreset)
-     if (~nreset)
-       reg_rddata[RW-1:0] <= '0;
-     else
-       if(reg_read)
-         reg_rddata[RW-1:0] <= ram[ram_addr[$clog2(RAMDEPTH)-1:1]];
-
-   // Ram checking
-   always @(posedge clk)
-     begin
-        if (udev_req_valid & udev_req_ready & (udev_req_cmd[4:0] == UMI_REQ_WRITE))
-          addr_latch <= udev_req_dstaddr;
-
-        if (udev_resp_valid & udev_resp_ready & (udev_resp_cmd[4:0] == UMI_RESP_READ) & (udev_resp_data[AW-1:0] != addr_latch))
-          begin
-             $display("Error reading address %h", addr_latch);
-             error <= 1'b1;
-          end
-     end
-
-endmodule
-// Local Variables:
-// verilog-library-directories:("." "../rtl")
-// End:
diff --git a/umi/testbench/test_crossbar.py b/umi/testbench/test_crossbar.py
new file mode 100755
index 0000000..7a30d70
--- /dev/null
+++ b/umi/testbench/test_crossbar.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2023 Zero ASIC
+# This code is licensed under Apache License 2.0 (see LICENSE for details)
+
+import multiprocessing
+import random
+import numpy as np
+from pathlib import Path
+from argparse import ArgumentParser
+from switchboard import (UmiTxRx, random_umi_packet, delete_queue,
+    verilator_run, SbDut, UmiCmd, umi_opcode)
+
+THIS_DIR = Path(__file__).resolve().parent
+
+def build_testbench():
+    dut = SbDut('testbench')
+
+    EX_DIR = Path('..')
+    EX_DIR = EX_DIR.resolve()
+
+    # Set up inputs
+    dut.input('testbench_crossbar.sv')
+
+    dut.input(EX_DIR / '..' / 'submodules' / 'switchboard' / 'examples' / 'common' / 'verilator' / 'testbench.cc')
+    for option in ['ydir', 'idir']:
+        dut.add('option', option, EX_DIR / 'rtl')
+        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'switchboard' / 'examples' / 'common' / 'verilog')
+        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'lambdalib' / 'ramlib' / 'rtl')
+        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'lambdalib' / 'stdlib' / 'rtl')
+        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'lambdalib' / 'vectorlib' / 'rtl')
+
+    # Verilator configuration
+    vlt_config = EX_DIR / 'testbench' / 'config.vlt'
+    dut.set('tool', 'verilator', 'task', 'compile', 'file', 'config', vlt_config)
+#    dut.set('option', 'relax', True)
+    dut.add('tool', 'verilator', 'task', 'compile', 'option', '--prof-cfuncs')
+    dut.add('tool', 'verilator', 'task', 'compile', 'option', '-CFLAGS')
+    dut.add('tool', 'verilator', 'task', 'compile', 'option', '-DVL_DEBUG')
+
+    # Settings - enable tracing
+    dut.set('option', 'trace', True)
+    dut.set('tool', 'verilator', 'task', 'compile', 'var', 'trace_type', 'fst')
+
+    # Build simulator
+    dut.run()
+
+    return dut.find_result('vexe', step='compile')
+
+def umi_send(x,n,ports):
+    import os
+
+    random.seed(os.getpid())
+    np.random.seed(os.getpid())
+
+    umi = UmiTxRx(f'client2rtl_{x}.q', '')
+    tee = UmiTxRx(f'tee_{x}.q', '')
+
+    for count in range (n):
+        dstport = random.randint(0,ports-1)
+        dstaddr = (2**8)*random.randint(0,(2**32)-1) + dstport*(2**40)
+        srcaddr = (2**8)*random.randint(0,(2**32)-1) + x*(2**40)
+        txp = random_umi_packet(dstaddr=dstaddr,srcaddr=srcaddr)
+        print(f"port {x} sending #{count} cmd: 0x{txp.cmd:08x} srcaddr: 0x{srcaddr:08x} dstaddr: 0x{dstaddr:08x} to port {dstport}")
+        # send the packet to both simulation and local queues
+        umi.send(txp)
+        tee.send(txp)
+
+def main(vldmode="2", rdymode="2", n=100, ports=4):
+    for x in range (ports):
+        delete_queue(f'rtl2client_{x}.q')
+        delete_queue(f'client2rtl_{x}.q')
+        delete_queue(f'tee_{x}.q')
+
+    verilator_bin = build_testbench()
+
+    # launch the simulation
+    verilator_run(verilator_bin, plusargs=['trace', ('PORTS', ports), ('valid_mode', vldmode), ('ready_mode', rdymode)])
+
+    # instantiate TX and RX queues.  note that these can be instantiated without
+    # specifying a URI, in which case the URI can be specified later via the
+    # "init" method
+
+    umi = [UmiTxRx('', f'rtl2client_{x}.q') for x in range(ports)]
+    tee = [UmiTxRx('', f'tee_{x}.q') for x in range(ports)]
+
+    print("### Starting test ###")
+    recv_queue = [[[] for i in range(n)] for j in range(ports)]
+    send_queue = [[[] for i in range(n)] for j in range(ports)]
+
+    procs = []
+    for x in range(ports):
+        procs.append(multiprocessing.Process(target=umi_send, args=(x,n,ports,)))
+
+    for proc in procs:
+        proc.start()
+
+    nrecv = 0
+    nsend = 0
+    while (nrecv < ports*n) or (nsend < ports*n):
+        for i in range(ports):
+            rxp = umi[i].recv(blocking=False)
+            if rxp is not None:
+                if nrecv >= ports*n:
+                    print(f'Unexpected packet received {nrecv}')
+                    raise Exception(f'Unexpected packet received {nrecv}')
+                else:
+                    recv_src = (rxp.srcaddr >> 40)
+                    print(f"port {i} receiving srcaddr: 0x{rxp.srcaddr:08x} dstaddr: 0x{rxp.dstaddr:08x} src: {recv_src} #{nrecv}")
+                    recv_queue[recv_src][i].append(rxp)
+                    nrecv += 1
+
+        for i in range(ports):
+            txp = tee[i].recv(blocking=False)
+            if txp is not None:
+                if nsend >= ports*n:
+                    raise Exception('Unexpected packet sent')
+                else:
+                    send_dst = (txp.dstaddr >> 40)
+                    #print(f"Tee port {i} dst: {send_dst} #{nsend}")
+                    send_queue[i][send_dst].append(txp)
+                    nsend += 1
+
+    # join running processes
+
+    for proc in procs:
+        proc.join()
+
+    for i in range(ports):
+        for j in range(ports):
+            if len(send_queue[i][j]) != len(recv_queue[i][j]):
+                print(f"packets sent: {len(send_queue[i][j])} packets received: {len(recv_queue[i][j])}")
+            assert len(send_queue[i][j]) == len(recv_queue[i][j])
+            for txp, rxp in zip(send_queue[i][j],recv_queue[i][j]):
+                #print(f"{rxp} {txp}")
+                assert txp == rxp
+            print(f"compared {len(recv_queue[i][j])} packets from port {i} to port {j}")
+    print("TEST PASS")
+
+if __name__ == '__main__':
+    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.')
+    parser.add_argument('-ports', type=int, default=4, help='Number of ports')
+    args = parser.parse_args()
+
+    main(vldmode=args.vldmode,rdymode=args.rdymode, n=args.n, ports=args.ports)
diff --git a/umi/testbench/test_fifo.py b/umi/testbench/test_fifo.py
index f710f7c..4a8b7f0 100755
--- a/umi/testbench/test_fifo.py
+++ b/umi/testbench/test_fifo.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 
-# Example illustrating how UMI packets handled in the Switchboard Python binding
 # Copyright (C) 2023 Zero ASIC
+# This code is licensed under Apache License 2.0 (see LICENSE for details)
 
 import random
 import numpy as np
diff --git a/umi/testbench/test_fifo_flex.py b/umi/testbench/test_fifo_flex.py
index 519335c..cb2c57e 100755
--- a/umi/testbench/test_fifo_flex.py
+++ b/umi/testbench/test_fifo_flex.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 
-# Example illustrating how UMI packets handled in the Switchboard Python binding
 # Copyright (C) 2023 Zero ASIC
+# This code is licensed under Apache License 2.0 (see LICENSE for details)
 
 import random
 import numpy as np
diff --git a/umi/testbench/test_mem_agent.py b/umi/testbench/test_mem_agent.py
index 7f575c8..0022c4f 100755
--- a/umi/testbench/test_mem_agent.py
+++ b/umi/testbench/test_mem_agent.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 
-# Example illustrating how UMI packets handled in the Switchboard Python binding
 # Copyright (C) 2023 Zero ASIC
+# This code is licensed under Apache License 2.0 (see LICENSE for details)
 
 import random
 import numpy as np
diff --git a/umi/testbench/test_regif.py b/umi/testbench/test_regif.py
new file mode 100755
index 0000000..b2dee2b
--- /dev/null
+++ b/umi/testbench/test_regif.py
@@ -0,0 +1,147 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2023 Zero ASIC
+# This code is licensed under Apache License 2.0 (see LICENSE for details)
+
+import random
+import numpy as np
+from pathlib import Path
+from argparse import ArgumentParser
+from switchboard import SbDut, UmiTxRx, delete_queue, verilator_run, binary_run
+
+THIS_DIR = Path(__file__).resolve().parent
+
+
+def build_testbench():
+    dut = SbDut('testbench')
+
+    EX_DIR = Path('..')
+    EX_DIR = EX_DIR.resolve()
+
+    # Set up inputs
+    dut.input('testbench_regif.sv')
+
+    dut.input(EX_DIR / '..' / 'submodules' / 'switchboard' / 'examples' / 'common' / 'verilator' / 'testbench.cc')
+    for option in ['ydir', 'idir']:
+        dut.add('option', option, EX_DIR / 'rtl')
+        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'switchboard' / 'examples' / 'common' / 'verilog')
+        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'lambdalib' / 'ramlib' / 'rtl')
+        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'lambdalib' / 'stdlib' / 'rtl')
+        dut.add('option', option, EX_DIR / '..' / 'submodules' / 'lambdalib' / 'vectorlib' / 'rtl')
+
+    # Verilator configuration
+    vlt_config = EX_DIR / 'testbench' / 'config.vlt'
+    dut.set('tool', 'verilator', 'task', 'compile', 'file', 'config', vlt_config)
+#    dut.set('option', 'relax', True)
+    dut.add('tool', 'verilator', 'task', 'compile', 'option', '--prof-cfuncs')
+    dut.add('tool', 'verilator', 'task', 'compile', 'option', '-CFLAGS')
+    dut.add('tool', 'verilator', 'task', 'compile', 'option', '-DVL_DEBUG')
+
+    # Settings - enable tracing
+    dut.set('option', 'trace', True)
+    dut.set('tool', 'verilator', 'task', 'compile', 'var', 'trace_type', 'fst')
+
+    # Build simulator
+    dut.run()
+
+    return dut.find_result('vexe', step='compile')
+
+
+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)
+
+    verilator_bin = build_testbench()
+
+    # launch the simulation
+    #verilator_run(verilator_bin, plusargs=['trace'])
+    verilator_run(verilator_bin, plusargs=['trace', ('valid_mode', vldmode), ('ready_mode', rdymode)])
+
+    # instantiate TX and RX queues.  note that these can be instantiated without
+    # specifying a URI, in which case the URI can be specified later via the
+    # "init" method
+
+    host = UmiTxRx(host2dut, dut2host)
+
+    print("### Starting test ###")
+
+    # regif accesses are all 32b wide and aligned
+    for count in range (n):
+        addr = np.random.randint(0, 512) * 4
+        src_addr = random.randrange(2**64-1)
+        # length should not cross the DW boundary - umi_mem_agent limitation
+        data = np.uint32(random.randrange(2**32-1))
+
+        print(f"umi writing 0x{data:08x} to addr 0x{addr:08x}")
+        host.write(addr, data)
+        atomicopcode = np.random.randint(0, 9)
+        atomicdata = np.uint32(random.randrange(2**32-1))
+        print(f"umi atomic opcode: {atomicopcode} data: {atomicdata:08x} to addr 0x{addr:08x}")
+        atomicval = host.atomic(addr, atomicdata, atomicopcode)
+        if not (atomicval == data):
+            print(f"ERROR umi atomic from addr 0x{addr:08x} expected {data} actual {atomicval}")
+            assert (atomicval == data)
+        data = np.uint32(apply_atomic(data, atomicdata, atomicopcode, 2**32))
+
+        print(f"umi read from addr 0x{addr:08x}")
+        val = host.read(addr, np.uint32)
+        if not (val == data):
+            print(f"ERROR umi read from addr 0x{addr:08x} expected {data} actual {val}")
+            assert (val == data)
+
+    print("### TEST PASS ###")
+
+if __name__ == '__main__':
+    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, n=args.n)
diff --git a/umi/testbench/testbench_crossbar.sv b/umi/testbench/testbench_crossbar.sv
new file mode 100644
index 0000000..2f84885
--- /dev/null
+++ b/umi/testbench/testbench_crossbar.sv
@@ -0,0 +1,191 @@
+/*******************************************************************************
+ * Copyright 2020 Zero ASIC Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
+ *
+ * Documentation:
+ * - Simple umi crossbar testbench
+ *
+ ******************************************************************************/
+
+module testbench
+  #(parameter PORTS=4,
+    parameter RW=32,
+    parameter DW=512,
+    parameter AW=64,
+    parameter CW=32)
+   (
+    input clk
+    );
+
+   localparam N = PORTS;
+
+   /*AUTOWIRE*/
+   reg               nreset;
+   wire [N*N-1:0]    umi_in_request;
+
+   wire [N-1:0]      umi_in_valid;
+   wire [N-1:0]      umi_in_ready;
+   wire [N*CW-1:0]   umi_in_cmd;
+   wire [N*DW-1:0]   umi_in_data;
+   wire [N*AW-1:0]   umi_in_dstaddr;
+   wire [N*AW-1:0]   umi_in_srcaddr;
+
+   wire [N-1:0]      umi_out_valid;
+   wire [N-1:0]      umi_out_ready;
+   wire [N*CW-1:0]   umi_out_cmd;
+   wire [N*DW-1:0]   umi_out_data;
+   wire [N*AW-1:0]   umi_out_dstaddr;
+   wire [N*AW-1:0]   umi_out_srcaddr;
+
+   ///////////////////////////////////////////
+   // Host side umi agents
+   ///////////////////////////////////////////
+
+   genvar            i,j;
+   generate
+      for(i=0;i<N;i=i+1)
+        begin: portif
+           umi_rx_sim #(.VALID_MODE_DEFAULT(2),
+                        .DW(256))
+           umi_rx_i (.clk(clk),
+                     .data(umi_in_data[i*DW+:256]),
+                     .srcaddr(umi_in_srcaddr[i*AW+:AW]),
+                     .dstaddr(umi_in_dstaddr[i*AW+:AW]),
+                     .cmd(umi_in_cmd[i*CW+:CW]),
+                     .ready(umi_in_ready[i]),
+                     .valid(umi_in_valid[i]));
+
+           assign umi_in_data[i*DW+256+:256] = 'h0;
+
+           for (j=0;j<N;j=j+1)
+             begin: request
+                assign umi_in_request[j*N + i] = umi_in_valid[i] &
+                                                 (umi_in_dstaddr[i*AW+40+:16] == j);
+             end
+
+           umi_tx_sim #(.READY_MODE_DEFAULT(2),
+                        .DW(256))
+           umi_tx_i (.clk(clk),
+                     .data(umi_out_data[i*DW+:256]),
+                     .srcaddr(umi_out_srcaddr[i*AW+:AW]),
+                     .dstaddr(umi_out_dstaddr[i*AW+:AW]),
+                     .cmd(umi_out_cmd[i*CW+:CW]),
+                     .ready(umi_out_ready[i]),
+                     .valid(umi_out_valid[i])
+                     );
+        end
+   endgenerate
+
+   // instantiate dut with UMI ports
+   /* umi_crossbar AUTO_TEMPLATE(
+    .mode (2'b10),
+    .mask ({@"vl-width"{1'b0}}),
+    );*/
+   umi_crossbar #(.CW(CW),
+                  .AW(AW),
+                  .DW(DW),
+                  .N(N))
+   umi_crossbar_i(/*AUTOINST*/
+                  // Outputs
+                  .umi_in_ready         (umi_in_ready[N-1:0]),
+                  .umi_out_valid        (umi_out_valid[N-1:0]),
+                  .umi_out_cmd          (umi_out_cmd[N*CW-1:0]),
+                  .umi_out_dstaddr      (umi_out_dstaddr[N*AW-1:0]),
+                  .umi_out_srcaddr      (umi_out_srcaddr[N*AW-1:0]),
+                  .umi_out_data         (umi_out_data[N*DW-1:0]),
+                  // Inputs
+                  .clk                  (clk),
+                  .nreset               (nreset),
+                  .mode                 (2'b10),                 // Templated
+                  .mask                 ({(1+(N*N-1)){1'b0}}),   // Templated
+                  .umi_in_request       (umi_in_request[N*N-1:0]),
+                  .umi_in_cmd           (umi_in_cmd[N*CW-1:0]),
+                  .umi_in_dstaddr       (umi_in_dstaddr[N*AW-1:0]),
+                  .umi_in_srcaddr       (umi_in_srcaddr[N*AW-1:0]),
+                  .umi_in_data          (umi_in_data[N*DW-1:0]),
+                  .umi_out_ready        (umi_out_ready[N-1:0]));
+
+   // Initialize UMI
+   integer valid_mode, ready_mode;
+
+   initial begin
+      /* verilator lint_off IGNOREDRETURN */
+      if (!$value$plusargs("valid_mode=%d", valid_mode)) begin
+         valid_mode = 2;  // default if not provided as a plusarg
+      end
+
+      if (!$value$plusargs("ready_mode=%d", ready_mode)) begin
+         ready_mode = 2;  // default if not provided as a plusarg
+      end
+      /* verilator lint_on IGNOREDRETURN */
+   end
+
+   // This should be made into a loop in order to support any number of ports but
+   // that currently does not work in Verilator
+   initial
+     begin
+        portif[0].umi_rx_i.init("client2rtl_0.q");
+        portif[0].umi_rx_i.set_valid_mode(valid_mode);
+        portif[0].umi_tx_i.init("rtl2client_0.q");
+        portif[0].umi_tx_i.set_ready_mode(ready_mode);
+
+        portif[1].umi_rx_i.init("client2rtl_1.q");
+        portif[1].umi_rx_i.set_valid_mode(valid_mode);
+        portif[1].umi_tx_i.init("rtl2client_1.q");
+        portif[1].umi_tx_i.set_ready_mode(ready_mode);
+
+        portif[2].umi_rx_i.init("client2rtl_2.q");
+        portif[2].umi_rx_i.set_valid_mode(valid_mode);
+        portif[2].umi_tx_i.init("rtl2client_2.q");
+        portif[2].umi_tx_i.set_ready_mode(ready_mode);
+
+        portif[3].umi_rx_i.init("client2rtl_3.q");
+        portif[3].umi_rx_i.set_valid_mode(valid_mode);
+        portif[3].umi_tx_i.init("rtl2client_3.q");
+        portif[3].umi_tx_i.set_ready_mode(ready_mode);
+     end
+
+   // VCD
+
+   initial
+     begin
+        nreset   = 1'b0;
+     end // initial begin
+
+   // Bring up reset and the go signal on the first clock cycle
+   always @(negedge clk)
+     begin
+        nreset <= nreset | 1'b1;
+     end
+
+   // control block
+   initial
+     begin
+        if ($test$plusargs("trace"))
+          begin
+             $dumpfile("testbench.fst");
+             $dumpvars(0, testbench);
+          end
+     end
+
+   // auto-stop
+
+   auto_stop_sim auto_stop_sim_i (.clk(clk));
+
+endmodule
+// Local Variables:
+// verilog-library-directories:("../rtl" "../../submodules/switchboard/examples/common/verilog/" "../../submodules/lambdalib/ramlib/rtl/")
+// End:
diff --git a/umi/testbench/testbench_fifo.sv b/umi/testbench/testbench_fifo.sv
index 49d89de..8599a51 100644
--- a/umi/testbench/testbench_fifo.sv
+++ b/umi/testbench/testbench_fifo.sv
@@ -1,3 +1,25 @@
+/*******************************************************************************
+ * Copyright 2023 Zero ASIC Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
+ *
+ * Documentation:
+ * - Simple fifo testbench
+ *
+ ******************************************************************************/
+
 `default_nettype none
 
 module testbench (
diff --git a/umi/testbench/testbench_fifo_flex.sv b/umi/testbench/testbench_fifo_flex.sv
index 1962579..c19cddc 100644
--- a/umi/testbench/testbench_fifo_flex.sv
+++ b/umi/testbench/testbench_fifo_flex.sv
@@ -1,3 +1,26 @@
+/*******************************************************************************
+ * Copyright 2020 Zero ASIC Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
+ *
+ * Documentation:
+ * - Simple fifo flex testbench
+ *
+ ******************************************************************************/
+
+
 `default_nettype none
 
 module testbench (
diff --git a/umi/testbench/testbench_mem_agent.sv b/umi/testbench/testbench_mem_agent.sv
index 90c49d2..d0ac981 100644
--- a/umi/testbench/testbench_mem_agent.sv
+++ b/umi/testbench/testbench_mem_agent.sv
@@ -1,3 +1,25 @@
+/*******************************************************************************
+ * Copyright 2020 Zero ASIC Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
+ *
+ * Documentation:
+ * - Simple mem_agent testbench
+ *
+ ******************************************************************************/
+
 `default_nettype none
 
 module testbench (
diff --git a/umi/testbench/testbench_regif.sv b/umi/testbench/testbench_regif.sv
new file mode 100644
index 0000000..3a6d4fe
--- /dev/null
+++ b/umi/testbench/testbench_regif.sv
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ * Copyright 2020 Zero ASIC Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
+ *
+ * Documentation:
+ * - Simple register interface testbench
+ *
+ ******************************************************************************/
+
+`default_nettype none
+
+module testbench (
+                  input clk
+                  );
+
+   parameter integer RW=32;
+   parameter integer DW=256;
+   parameter integer AW=64;
+   parameter integer CW=32;
+   parameter integer CTRLW=8;
+   parameter integer RAMDEPTH=512;
+
+
+   /*AUTOWIRE*/
+   // Beginning of automatic wires (for undeclared instantiated-module outputs)
+   wire [AW-1:0]        reg_addr;
+   wire [RW-1:0]        reg_rddata;
+   wire                 reg_read;
+   wire [RW-1:0]        reg_wrdata;
+   wire                 reg_write;
+   // End of automatics
+   reg                  nreset;
+   reg                  go;
+
+   wire                 udev_resp_ready;
+   wire [CW-1:0]        udev_resp_cmd;
+   wire [DW-1:0]        udev_resp_data;
+   wire [AW-1:0]        udev_resp_dstaddr;
+   wire [AW-1:0]        udev_resp_srcaddr;
+   wire                 udev_resp_valid;
+
+   wire                 udev_req_ready;
+   wire [CW-1:0]        udev_req_cmd;
+   wire [DW-1:0]        udev_req_data;
+   wire [AW-1:0]        udev_req_dstaddr;
+   wire [AW-1:0]        udev_req_srcaddr;
+   wire                 udev_req_valid;
+
+   wire [CTRLW-1:0]  sram_ctrl = 8'b0;
+
+   ///////////////////////////////////////////
+   // Host side umi agents
+   ///////////////////////////////////////////
+
+   umi_rx_sim #(.VALID_MODE_DEFAULT(2),
+                .DW(DW)
+                )
+   host_umi_rx_i (.clk(clk),
+                  .data(udev_req_data[DW-1:0]),
+                  .srcaddr(udev_req_srcaddr[AW-1:0]),
+                  .dstaddr(udev_req_dstaddr[AW-1:0]),
+                  .cmd(udev_req_cmd[CW-1:0]),
+                  .ready(udev_req_ready),
+                  .valid(udev_req_valid)
+                  );
+
+   umi_tx_sim #(.READY_MODE_DEFAULT(2),
+                .DW(DW)
+                )
+   host_umi_tx_i (.clk(clk),
+                  .data(udev_resp_data[DW-1:0]),
+                  .srcaddr(udev_resp_srcaddr[AW-1:0]),
+                  .dstaddr(udev_resp_dstaddr[AW-1:0]),
+                  .cmd(udev_resp_cmd[CW-1:0]),
+                  .ready(udev_resp_ready),
+                  .valid(udev_resp_valid)
+                  );
+
+   // instantiate dut with UMI ports
+   /* umi_regif AUTO_TEMPLATE(
+    .reg_opcode (), // Future use
+    .reg_size   (), // Future use
+    .reg_len    (), // Future use
+    );*/
+   umi_regif #(.CW(CW),
+               .AW(AW),
+               .DW(DW),
+               .RW(RW))
+   umi_regif_i(/*AUTOINST*/
+               // Outputs
+               .udev_req_ready  (udev_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]),
+               .udev_resp_srcaddr(udev_resp_srcaddr[AW-1:0]),
+               .udev_resp_data  (udev_resp_data[DW-1:0]),
+               .reg_addr        (reg_addr[AW-1:0]),
+               .reg_write       (reg_write),
+               .reg_read        (reg_read),
+               .reg_opcode      (),                      // Templated
+               .reg_size        (),                      // Templated
+               .reg_len         (),                      // Templated
+               .reg_wrdata      (reg_wrdata[RW-1:0]),
+               // Inputs
+               .clk             (clk),
+               .nreset          (nreset),
+               .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_resp_ready (udev_resp_ready),
+               .reg_rddata      (reg_rddata[RW-1:0]));
+
+   la_spram #(.DW    (RW),               // Memory width
+              .AW    ($clog2(RAMDEPTH)), // Address width (derived)
+              .CTRLW (CTRLW),            // Width of asic ctrl interface
+              .TESTW (128)               // Width of asic test interface
+              )
+   la_spram_i(// Outputs
+              .dout             (reg_rddata[RW-1:0]),
+              // Inputs
+              .clk              (clk),
+              .ce               (reg_read | reg_write),
+              .we               (reg_write),
+              .wmask            ({RW{1'b1}}),
+              .addr             (reg_addr[2+:$clog2(RAMDEPTH)]),
+              .din              (reg_wrdata[RW-1:0]),
+              .vss              (1'b0),
+              .vdd              (1'b1),
+              .vddio            (1'b1),
+              .ctrl             (sram_ctrl),
+              .test             (128'h0)
+              /*AUTOINST*/);
+
+   // Initialize UMI
+   integer valid_mode, ready_mode;
+
+   initial begin
+      /* verilator lint_off IGNOREDRETURN */
+      if (!$value$plusargs("valid_mode=%d", valid_mode)) begin
+         valid_mode = 2;  // default if not provided as a plusarg
+      end
+
+      if (!$value$plusargs("ready_mode=%d", ready_mode)) begin
+         ready_mode = 2;  // default if not provided as a plusarg
+      end
+
+      host_umi_rx_i.init("host2dut_0.q");
+      host_umi_rx_i.set_valid_mode(valid_mode);
+
+      host_umi_tx_i.init("dut2host_0.q");
+      host_umi_tx_i.set_ready_mode(ready_mode);
+      /* verilator lint_on IGNOREDRETURN */
+   end
+
+   // VCD
+
+   initial
+     begin
+        nreset   = 1'b0;
+        go       = 1'b0;
+     end // initial begin
+
+   // Bring up reset and the go signal on the first clock cycle
+   always @(negedge clk)
+     begin
+        nreset <= nreset | 1'b1;
+        go <= 1'b1;
+     end
+
+   // control block
+   initial
+     begin
+        if ($test$plusargs("trace"))
+          begin
+             $dumpfile("testbench.fst");
+             $dumpvars(0, testbench);
+          end
+     end
+
+   // auto-stop
+
+   auto_stop_sim auto_stop_sim_i (.clk(clk));
+
+endmodule
+// Local Variables:
+// verilog-library-directories:("../rtl" "../../submodules/switchboard/examples/common/verilog/" "../../submodules/lambdalib/ramlib/rtl/")
+// End:
+
+`default_nettype wire
diff --git a/umi/testbench/umi_testbench.py b/umi/testbench/umi_testbench.py
index 3c50aad..d9dc99b 100644
--- a/umi/testbench/umi_testbench.py
+++ b/umi/testbench/umi_testbench.py
@@ -1,3 +1,5 @@
+# Copyright (C) 2023 Zero ASIC
+# This code is licensed under Apache License 2.0 (see LICENSE for details)
 import os
 import platform
 
diff --git a/umi/testbench/verilog/umi_testbench.sv b/umi/testbench/verilog/umi_testbench.sv
deleted file mode 100644
index fb25742..0000000
--- a/umi/testbench/verilog/umi_testbench.sv
+++ /dev/null
@@ -1,73 +0,0 @@
-module umi_testbench (
-	input clk,
-	input nreset
-);
-	// UMI RX port
-
-	wire [255:0] umi_packet_rx;
-	wire umi_valid_rx;
-	wire umi_ready_rx;
-
-	// UMI TX port
-
-	wire [255:0] umi_packet_tx;
-	wire umi_valid_tx;
-	wire umi_ready_tx;
-
-	umi_rx_sim rx_i (
-		.clk(clk),
-		.ready(umi_ready_rx), // input
-		.packet(umi_packet_rx), // output
-		.valid(umi_valid_rx) // output
-	);
-
-	umi_tx_sim tx_i (
-		.clk(clk),
-		.ready(umi_ready_tx), // output
-		.packet(umi_packet_tx), // input
-		.valid(umi_valid_tx) // input
-	);
-
-	`MOD_UNDER_TEST uut (
-		.clk(clk),
-		.nreset(nreset),
-
-		.rx0_umi_valid(umi_valid_rx),
-		.rx0_umi_packet(umi_packet_rx),
-		.rx0_umi_ready(umi_ready_rx),
-
-		.tx0_umi_valid(umi_valid_tx),
-		.tx0_umi_packet(umi_packet_tx),
-		.tx0_umi_ready(umi_ready_tx)
-	);
-
-	string rx_port;
-	string tx_port;
-
-`ifdef TRACE
-	initial begin
-		$dumpfile("umi_testbench.vcd");
-		$dumpvars;
-	end
-`endif
-
-	initial begin
-		// read command-line arguments, setting defaults as needed
-
-		if (!$value$plusargs("rx_port=%s", rx_port)) begin
-			rx_port = "queue-5555";
-		end
-
-		if (!$value$plusargs("tx_port=%s", tx_port)) begin
-			tx_port = "queue-5556";
-		end
-
-		// initialize UMI according to command-line arguments
-
-		/* verilator lint_off IGNOREDRETURN */
-		rx_i.init(rx_port);
-		tx_i.init(tx_port);
-		/* verilator lint_on IGNOREDRETURN */
-	end
-
-endmodule
diff --git a/utils/testbench/config.h b/utils/testbench/config.h
index 81a628f..23f30a2 100644
--- a/utils/testbench/config.h
+++ b/utils/testbench/config.h
@@ -1,13 +1,25 @@
-/******************************************************************************
- * Function:  Simulator global configurations
- * Author:    Wenting Zhang
- * Copyright: 2022 Zero ASIC Corporation. All rights reserved.
- * License:
+/*******************************************************************************
+ * Copyright 2022 Zero ASIC Corporation
  *
- * Documentation:
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  *
+ * ----
  *
- *****************************************************************************/
+ * Documentation:
+ * - Simulator global configurations
+ *
+ ******************************************************************************/
+
 #pragma once
 
 #define CLK_PREIOD_PS       (10000)
diff --git a/utils/testbench/tb_tl2umi_np.v b/utils/testbench/tb_tl2umi_np.v
index 0bcee5a..bbd19da 100644
--- a/utils/testbench/tb_tl2umi_np.v
+++ b/utils/testbench/tb_tl2umi_np.v
@@ -1,15 +1,24 @@
-/******************************************************************************
- * Function:  TL-UH to UMI converter testbench
- * Author:    Aliasger Zaidy
- * Copyright: 2023 Zero ASIC Corporation. All rights reserved.
- * License: This file contains confidential and proprietary information of
- * Zero ASIC. This file may only be used in accordance with the terms and
- * conditions of a signed license agreement with Zero ASIC. All other use,
- * reproduction, or distribution of this software is strictly prohibited.
+/*******************************************************************************
+ * Copyright 2023 Zero ASIC Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
  *
  * Documentation:
+ * - TL-UH to UMI converter testbench
  *
- ****************************************************************************/
+ ******************************************************************************/
 
 `timescale 1ns / 1ps
 `default_nettype wire
diff --git a/utils/testbench/tb_umi_data_aggregator.v b/utils/testbench/tb_umi_data_aggregator.v
index 508e5f0..ee8e05f 100644
--- a/utils/testbench/tb_umi_data_aggregator.v
+++ b/utils/testbench/tb_umi_data_aggregator.v
@@ -1,3 +1,26 @@
+/*******************************************************************************
+ * Copyright 2023 Zero ASIC Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
+ *
+ * Documentation:
+ * - UMI data aggeregator testbench
+ *
+ ******************************************************************************/
+
+
 `timescale 1ns / 1ps
 `default_nettype wire
 
diff --git a/utils/testbench/tilelink.h b/utils/testbench/tilelink.h
index 3af7ed2..2ec8cea 100644
--- a/utils/testbench/tilelink.h
+++ b/utils/testbench/tilelink.h
@@ -1,13 +1,20 @@
-/******************************************************************************
- * Function:  TileLink Uncached Heavyweight (TL-UH) definitions
- * Author:    Wenting Zhang
- * Copyright: 2022 Zero ASIC Corporation. All rights reserved.
- * License:
+/*******************************************************************************
+ * Copyright 2022 Zero ASIC Corporation
  *
- * Documentation:
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- *****************************************************************************/
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
 #pragma once
 
 typedef enum {
@@ -42,4 +49,4 @@ typedef enum {
     PL_OR = 1,
     PL_AND = 2,
     PL_SWAP = 3
-} TLParam_Logical;
\ No newline at end of file
+} TLParam_Logical;
diff --git a/utils/testbench/tlmemsim.cpp b/utils/testbench/tlmemsim.cpp
index 4a9afb9..539f6e9 100644
--- a/utils/testbench/tlmemsim.cpp
+++ b/utils/testbench/tlmemsim.cpp
@@ -1,13 +1,25 @@
-/******************************************************************************
- * Function:  TileLink memory simulator
- * Author:    Wenting Zhang
- * Copyright: 2022 Zero ASIC Corporation. All rights reserved.
- * License:
+/*******************************************************************************
+ * Copyright 2023 Zero ASIC Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----
  *
  * Documentation:
- *   Single-cycle access TL-UH memory model.
+ * - Single-cycle access TL-UH memory model
  *
- *****************************************************************************/
+ ******************************************************************************/
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdint.h>
@@ -225,7 +237,7 @@ void TLMemsim::apply(uint8_t &a_ready, uint8_t a_valid, uint8_t a_opcode,
             assert(req_param == 0);
             #endif
             if (req_bubble) {
-                if (d_ready) { 
+                if (d_ready) {
                     // Accepted
                     a_ready = 1;
                     req_beatcount = 0;
@@ -314,7 +326,7 @@ void TLMemsim::apply(uint8_t &a_ready, uint8_t a_valid, uint8_t a_opcode,
         case OP_Intent:
             // Ignore
             #ifdef VERBOSE
-            fprintf(stderr, "MEM: INTENT %s (%d) address %08lx size %d...\n", 
+            fprintf(stderr, "MEM: INTENT %s (%d) address %08lx size %d...\n",
                     (req_param == 0) ? "PrefetchRead" :
                     (req_param == 1) ? "PrefetchWrite" : "Unknown",
                     req_param, req_addr, req_size);
@@ -324,7 +336,7 @@ void TLMemsim::apply(uint8_t &a_ready, uint8_t a_valid, uint8_t a_opcode,
             }
             else {
                 // Check if data is accepted last cycle
-                if (d_ready) { 
+                if (d_ready) {
                     // Accepted
                     a_ready = 1;
                     req_beatcount = 0;
diff --git a/utils/testbench/tlmemsim.h b/utils/testbench/tlmemsim.h
index fa24427..58e1825 100644
--- a/utils/testbench/tlmemsim.h
+++ b/utils/testbench/tlmemsim.h
@@ -1,13 +1,20 @@
-/******************************************************************************
- * Function:  TileLink (TL-UH) memory simulator
- * Author:    Wenting Zhang
- * Copyright: 2022 Zero ASIC Corporation. All rights reserved.
- * License:
+/*******************************************************************************
+ * Copyright 2023 Zero ASIC Corporation
  *
- * Documentation:
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- *****************************************************************************/
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
 #pragma once
 
 class TLMemsim {