diff --git a/vendor/pulp-platform/obi/.gitignore b/vendor/pulp-platform/obi/.gitignore new file mode 100644 index 000000000..092a4fa6a --- /dev/null +++ b/vendor/pulp-platform/obi/.gitignore @@ -0,0 +1 @@ +.bender diff --git a/vendor/pulp-platform/obi/Bender.yml b/vendor/pulp-platform/obi/Bender.yml new file mode 100644 index 000000000..eebd06852 --- /dev/null +++ b/vendor/pulp-platform/obi/Bender.yml @@ -0,0 +1,38 @@ +# Copyright 2023 ETH Zurich and University of Bologna. +# Solderpad Hardware License, Version 0.51, see LICENSE for details. +# SPDX-License-Identifier: SHL-0.51 + +package: + name: obi + authors: + - "Michael Rogenmoser " + +dependencies: + common_cells: { git: "https://github.com/pulp-platform/common_cells.git", version: 1.37.0 } + common_verification: { git: "https://github.com/pulp-platform/common_verification.git", version: 0.2.3 } + +export_include_dirs: + - include + +sources: + # Level 1 + - src/obi_pkg.sv + # Level 2 + - src/obi_intf.sv + - src/obi_rready_converter.sv + # Level 3 + - src/obi_atop_resolver.sv + - src/obi_demux.sv + - src/obi_err_sbr.sv + - src/obi_mux.sv + - src/obi_sram_shim.sv + # Level 4 + - src/obi_xbar.sv + - target: test + files: + - src/test/obi_asserter.sv + - src/test/obi_test.sv + - src/test/obi_sim_mem.sv + - src/test/tb_obi_xbar.sv + - src/test/atop_golden_mem_pkg.sv + - src/test/tb_obi_atop_resolver.sv diff --git a/vendor/pulp-platform/obi/CHANGELOG.md b/vendor/pulp-platform/obi/CHANGELOG.md new file mode 100644 index 000000000..04af30e29 --- /dev/null +++ b/vendor/pulp-platform/obi/CHANGELOG.md @@ -0,0 +1,34 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + + +## Unreleased + +## 0.1.3 - 2024-07-18 +### Added +- Add `obi_rready_converter` to convert between manager requiring rready to subordinate not supporting it. + +## 0.1.2 - 2024-03-11 +### Added +- Add assertion module to check protocol constraints. +- Add additional typedefs. + +## 0.1.1 - 2023-08-08 +### Fixed +- `obi_mux`: Move `if` outside `always_comb` to enforce `generate` and remove compile warning. + +## 0.1.0 - 2023-07-24 + +Initial release +### Added +- `obi_mux.sv`: A multiplexer IP for the OBI protocol. +- `obi_demux.sv`: A demultiplexer IP for the OBI protocol. +- `obi_xbar.sv`: A crossbar interconnect IP for the OBI protocol. +- `obi_err_sbr.sv`: A error subordinate, responding with the error bit set. +- `obi_sram_shim.sv`: An adapter for a standard sram. +- `obi_atop_resolver.sv`: An atomics filter, resolving atomic operations on an exclusive bus. +- Various support infrastructure for types and configurations in `obi_pkg.sv`, `obi_typedef.svh`, and `obi_assign.svh`. +- Initial testing infrastructure, testing `obi_xbar` and `obi_atop_resolver`. diff --git a/vendor/pulp-platform/obi/LICENSE b/vendor/pulp-platform/obi/LICENSE new file mode 100644 index 000000000..18e4f6769 --- /dev/null +++ b/vendor/pulp-platform/obi/LICENSE @@ -0,0 +1,176 @@ +SOLDERPAD HARDWARE LICENSE version 0.51 + +This license is based closely on the Apache License Version 2.0, but is not +approved or endorsed by the Apache Foundation. A copy of the non-modified +Apache License 2.0 can be found at http://www.apache.org/licenses/LICENSE-2.0. + +As this license is not currently OSI or FSF approved, the Licensor permits any +Work licensed under this License, at the option of the Licensee, to be treated +as licensed under the Apache License Version 2.0 (which is so approved). + +This License is licensed under the terms of this License and in particular +clause 7 below (Disclaimer of Warranties) applies in relation to its use. + +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 Rights owner or entity authorized by the Rights 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. + +"Rights" means copyright and any similar right including design right (whether +registered or unregistered), semiconductor topography (mask) rights and +database rights (but excluding Patents and Trademarks). + +"Source" form shall mean the preferred form for making modifications, including +but not limited to source code, net lists, board layouts, CAD files, +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, the instantiation of a hardware design and +conversions to other media types, including intermediate forms such as +bytecodes, FPGA bitstreams, artwork and semiconductor topographies (mask +works). + +"Work" shall mean the work of authorship, whether in Source form or other +Object form, made available under the License, as indicated by a Rights 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) or physically connect to or interoperate with the interfaces of, the Work +and Derivative Works thereof. + +"Contribution" shall mean any design or 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 Rights owner or by an individual or Legal Entity +authorized to submit on behalf of the Rights 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 Rights 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 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 license under the Rights to reproduce, +prepare Derivative Works of, publicly display, publicly perform, sublicense, +and distribute the Work and such Derivative Works in Source or Object form and +do anything in relation to the Work as if the Rights did not exist. + +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: + + You must give any other recipients of the Work or Derivative Works a copy + of this License; and + + You must cause any modified files to carry prominent notices stating that + You changed the files; and + + 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 + + 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 diff --git a/vendor/pulp-platform/obi/Makefile b/vendor/pulp-platform/obi/Makefile new file mode 100644 index 000000000..f0650712d --- /dev/null +++ b/vendor/pulp-platform/obi/Makefile @@ -0,0 +1,35 @@ +# Copyright 2023 ETH Zurich and University of Bologna. +# Solderpad Hardware License, Version 0.51, see LICENSE for details. +# SPDX-License-Identifier: SHL-0.51 + +BENDER ?= bender +VSIM ?= vsim + +AVAILABLE_TESTBENCHES = tb_obi_xbar tb_obi_atop_resolver + +scripts/compile.tcl: + mkdir -p scripts + $(BENDER) script vsim -t test --vlog-arg="-svinputport=compat" > $@ + +.PHONY: build +build: scripts/compile.tcl + $(VSIM) -c -do 'exit -code [source scripts/compile.tcl]' + +.PHONY: $(AVAILABLE_TESTBENCHES) +$(AVAILABLE_TESTBENCHES): build +ifdef gui + $(VSIM) $@ -voptargs="+acc" +else + $(VSIM) -c $@ -do "run -all; quit -f" +endif + +.PHONY: all +all: $(AVAILABLE_TESTBENCHES) + +.PHONY: clean +clean: + rm -f scripts/compile.tcl + rm -rf work + rm -f modelsim.ini + rm -f transcript + rm -f vsim.wlf diff --git a/vendor/pulp-platform/obi/Readme.md b/vendor/pulp-platform/obi/Readme.md new file mode 100644 index 000000000..41b7f1589 --- /dev/null +++ b/vendor/pulp-platform/obi/Readme.md @@ -0,0 +1,25 @@ +# OBI + +The repository contains a collection of SystemVerilog IPs for the [OBI v1.6 standard](https://github.com/openhwgroup/obi/blob/072d9173c1f2d79471d6f2a10eae59ee387d4c6f/OBI-v1.6.0.pdf). + +They are designed by PULP-platform and are available under the Solderpad v0.51 license (See [`LICENSE`](LICENSE)). + +## Using the IPs +As the OBI protocol is very configurable, the IPs are designed to incorporate specific parameters for the design: + +- `ObiCfg`: This specifies the configuration used for the OBI protocol being input or output from the link. A default config can be found in the `obi_pkg.sv`. This config should be aligned with the `req` and `rsp` structs. +- `obi_req_t`: The OBI request struct is designed to be generated with a macro available in the `include/obi/typedef.svh` include file and has fields for the handshake and a field for the *A* channel. +- `obi_rsp_t`: The OBI response struct is designed to be generated with a macro available in the `include/obi/typedef.svh` include file and has fields for the handshake and a filed for the *R* channel. + +Most IPs will also support a SystemVerilog `interface` variant, also based on `ObiCfg`. + +## Available IPs +- `obi_mux.sv`: A multiplexer IP for the OBI protocol. +- `obi_demux.sv`: A demultiplexer IP for the OBI protocol. +- `obi_xbar.sv`: A crossbar interconnect IP for the OBI protocol. +- `obi_err_sbr.sv`: A error subordinate, responding with the error bit set. +- `obi_sram_shim.sv`: An adapter for a standard sram. +- `obi_atop_resolver.sv`: An atomics filter, resolving atomic operations on an exclusive bus. + +## License +Solderpad Hardware License, Version 0.51 diff --git a/vendor/pulp-platform/obi/include/obi/assign.svh b/vendor/pulp-platform/obi/include/obi/assign.svh new file mode 100644 index 000000000..a5395e22e --- /dev/null +++ b/vendor/pulp-platform/obi/include/obi/assign.svh @@ -0,0 +1,257 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Michael Rogenmoser + +`ifndef OBI_ASSIGN_SVH +`define OBI_ASSIGN_SVH + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Internal implementation for assigning one ONE struct or interface to another struct or interface. +// The path to the signals on each side is defined by the `__sep*` arguments. The `__opt_as` +// argument allows to use this standalone (with `__opt_as = assign`) or in assignments inside +// processes (with `__opt_as` void). + +`define __OBI_TO_A(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + __opt_as __lhs``__lhs_sep``addr = __rhs``__rhs_sep``addr; \ + __opt_as __lhs``__lhs_sep``we = __rhs``__rhs_sep``we; \ + __opt_as __lhs``__lhs_sep``be = __rhs``__rhs_sep``be; \ + __opt_as __lhs``__lhs_sep``wdata = __rhs``__rhs_sep``wdata; \ + __opt_as __lhs``__lhs_sep``aid = __rhs``__rhs_sep``aid; \ + __opt_as __lhs``__lhs_sep``a_optional = __rhs``__rhs_sep``a_optional; +`define __OBI_TO_R(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + __opt_as __lhs``__lhs_sep``rdata = __rhs``__rhs_sep``rdata; \ + __opt_as __lhs``__lhs_sep``rid = __rhs``__rhs_sep``rid; \ + __opt_as __lhs``__lhs_sep``err = __rhs``__rhs_sep``err; \ + __opt_as __lhs``__lhs_sep``r_optional = __rhs``__rhs_sep``r_optional; +`define __OBI_TO_REQ(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep, __lhscfg, __rhscfg) \ + `__OBI_TO_A(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + __opt_as __lhs.req = __rhs.req; \ + if (__lhscfg.UseRReady) begin \ + if (__rhscfg.UseRReady) begin \ + __opt_as __lhs.rready = __rhs.rready; \ + if (__lhscfg.Integrity) begin \ + if (__rhscfg.Integrity) begin \ + __opt_as __lhs.rreadypar = __rhs.rreadypar; \ + end else begin \ + __opt_as __lhs.rreadypar = ~__rhs.rready; \ + end \ + end \ + end else begin \ + __opt_as __lhs.rready = 1'b1; \ + if (__lhscfg.Integrity) begin \ + __opt_as __lhs.rreadypar = 1'b0; \ + end \ + end \ + end else if (__rhscfg.UseRReady) begin \ + $error("Incompatible Configs! Please assign manually!"); \ + end \ + if (__lhscfg.Integrity) begin \ + if (__rhscfg.Integrity) begin \ + __opt_as __lhs.reqpar = __rhs.reqpar; \ + end else begin \ + __opt_as __lhs.reqpar = ~__rhs.req; \ + end \ + end +`define __OBI_TO_RSP(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep, __lhscfg, __rhscfg) \ + `__OBI_TO_R(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + __opt_as __lhs.gnt = __rhs.gnt; \ + __opt_as __lhs.rvalid = __rhs.rvalid; \ + if (__lhscfg.Integrity) begin \ + if (__rhscfg.Integrity) begin \ + __opt_as __lhs.gntpar = __rhs.gntpar; \ + __opt_as __lhs.rvalidpar = __rhs.rvalidpar; \ + end else begin \ + __opt_as __lhs.gntpar = ~__rhs.gnt; \ + __opt_as __lhs.rvalidpar = ~__rhs.rvalid; \ + end \ + end +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Assigning one OBI interface to another, as if you would do `assign sbr = mgr;` +// +// The channel assignments `OBI_ASSIGN_XX(dst, src)` assign all payload and the valid signal of the +// `XX` channel from the `src` to the `dst` interface and they assign the ready signal from the +// `src` to the `dst` interface. +// The interface assignment `OBI_ASSIGN(dst, src)` assigns all channels including handshakes as if +// `src` was the manager of `dst`. +// +// Usage Example: +// `OBI_ASSIGN(sbr, mgr) +// `OBI_ASSIGN_A(dst, src) +// `OBI_ASSIGN_R(dst, src) +`define OBI_ASSIGN_A(dst, src, dstcfg, srccfg) \ + `__OBI_TO_A(assign, dst, ., src, .) \ + assign dst.req = src.req; \ + assign src.gnt = dst.gnt; \ + if (dstcfg.Integrity && srccfg.Integrity) begin \ + assign dst.reqpar = src.reqpar; \ + assign src.gntpar = dst.gntpar; \ + end else if (dstcfg.Integrity ^ srccfg.Integrity) begin \ + $error("Incompatible Configs! Please assign manually!"); \ + end +`define OBI_ASSIGN_R(dst, src, dstcfg, srccfg) \ + `__OBI_TO_R(assign, dst, ., src, .) \ + assign dst.rvalid = src.rvalid; \ + if (dstcfg.Integrity && srccfg.Integrity) begin \ + assign dst.rvalidpar = src.rvalidpar; \ + end else if (dstcfg.Integrity ^ srccfg.Integrity) begin \ + $error("Incompatible Configs! Please assign manually!"); \ + end \ + if (srccfg.UseRReady) begin \ + if (dstcfg.UseRReady) begin \ + assign src.rready = dst.rready; \ + if (srccfg.Integrity && dstcfg.Integrity) begin \ + assign src.rreadypar = dst.rreadypar; \ + end \ + end else begin \ + assign src.rready = 1'b1; \ + if (srccfg.Integrity) begin \ + assign src.rreadypar = 1'b0; \ + end \ + end \ + end else if (dstcfg.UseRReady) begin \ + $error("Incompatible Configs! Please assign manually!"); \ + end +`define OBI_ASSIGN(sbr, mgr, sbrcfg, mgrcfg) \ + `OBI_ASSIGN_A(sbr, mgr, sbrcfg, mgrcfg) \ + `OBI_ASSIGN_R(mgr, sbr, mgrcfg, sbrcfg) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Setting an interface from channel or request/response structs inside a process. +// +// The channel macros `OBI_SET_FROM_XX(obi_if, xx_struct)` set the payload signals of the `obi_if` +// interface from the signals in `xx_struct`. They do not set the handshake signals. +// The request macro `OBI_SET_FROM_REQ(obi_if, req_struct)` sets the request channel and the +// request-side handshake signals of the `obi_if` interface from the signals in `req_struct`. +// The response macro `OBI_SET_FROM_RESP(obi_if, rsp_struct)` sets the response channel and the +// response-side handshake signals of the `obi_if` interface from the signals in `resp_struct`. +// +// Usage Example: +// always_comb begin +// `OBI_SET_FROM_REQ(my_if, my_req_struct) +// end +`define OBI_SET_FROM_A(obi_if, a_struct) `__OBI_TO_A(, obi_if, ., a_struct, .) +`define OBI_SET_FROM_R(obi_if, r_struct) `__OBI_TO_R(, obi_if, ., r_struct, .) +`define OBI_SET_FROM_REQ(obi_if, req_struct, cfg) `__OBI_TO_REQ(, obi_if, ., req_struct, .a., cfg, cfg) +`define OBI_SET_FROM_RSP(obi_if, rsp_struct, cfg) `__OBI_TO_RSP(, obi_if, ., rsp_struct, .r., cfg, cfg) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Assigning an interface from channel or request/response structs outside a process. +// +// The channel macros `OBI_ASSIGN_FROM_XX(obi_if, xx_struct)` assign the payload signals of the +// `obi_if` interface from the signals in `xx_struct`. They do not assign the handshake signals. +// The request macro `OBI_ASSIGN_FROM_REQ(obi_if, req_struct)` assigns the request channel and the +// request-side handshake signals of the `obi_if` interface from the signals in `req_struct`. +// The response macro `OBI_ASSIGN_FROM_RSP(obi_if, rsp_struct)` assigns the response channel and +// the response-side handshake signals of the `obi_if` interface from the signals in `rsp_struct`. +// +// Usage Example: +// `AXI_ASSIGN_FROM_REQ(my_if, my_req_struct) +`define OBI_ASSIGN_FROM_A(obi_if, a_struct) `__OBI_TO_A(assign, obi_if, ., a_struct, .) +`define OBI_ASSIGN_FROM_R(obi_if, r_struct) `__OBI_TO_R(assign, obi_if, ., r_struct, .) +`define OBI_ASSIGN_FROM_REQ(obi_if, req_struct, cfg) `__OBI_TO_REQ(assign, obi_if, ., req_struct, .a., cfg, cfg) +`define OBI_ASSIGN_FROM_RSP(obi_if, rsp_struct, cfg) `__OBI_TO_RSP(assign, obi_if, ., rsp_struct, .r., cfg, cfg) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Setting channel or request/response structs from an interface inside a process. +// +// The channel macros `OBI_SET_TO_XX(xx_struct, obi_if)` set the signals of `xx_struct` to the +// payload signals of that channel in the `obi_if` interface. They do not set the handshake +// signals. +// The request macro `OBI_SET_TO_REQ(obi_if, req_struct)` sets all signals of `req_struct` (i.e., +// request channel payload and request-side handshake signals) to the signals in the `obi_if` +// interface. +// The response macro `OBI_SET_TO_RSP(obi_if, rsp_struct)` sets all signals of `rsp_struct` +// (i.e., response channel payload and response-side handshake signals) to the signals in the +// `obi_if` interface. +// +// Usage Example: +// always_comb begin +// `OBI_SET_TO_REQ(my_req_struct, my_if) +// end +`define OBI_SET_TO_A(a_struct, obi_if) `__OBI_TO_A(, a_struct, ., obi_if, .) +`define OBI_SET_TO_R(r_struct, obi_if) `__OBI_TO_R(, r_struct, ., obi_if, .) +`define OBI_SET_TO_REQ(req_struct, obi_if, cfg) `__OBI_TO_REQ(, req_struct, .a., obi_if, ., cfg, cfg) +`define OBI_SET_TO_RSP(rsp_struct, obi_if, cfg) `__OBI_TO_RSP(, rsp_struct, .r., obi_if, ., cfg, cfg) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Assigning channel or request/response structs from an interface outside a process. +// +// The channel macros `OBI_ASSIGN_TO_XX(xx_struct, obi_if)` assign the signals of `xx_struct` to the +// payload signals of that channel in the `obi_if` interface. They do not assign the handshake +// signals. +// The request macro `OBI_ASSIGN_TO_REQ(obi_if, req_struct)` assigns all signals of `req_struct` +// (i.e., request channel payload and request-side handshake signals) to the signals in the `obi_if` +// interface. +// The response macro `OBI_ASSIGN_TO_RSP(obi_if, rsp_struct)` assigns all signals of `rsp_struct` +// (i.e., response channel payload and response-side handshake signals) to the signals in the +// `obi_if` interface. +// +// Usage Example: +// `OBI_ASSIGN_TO_REQ(my_req_struct, my_if) +`define OBI_ASSIGN_TO_A(a_struct, obi_if) `__OBI_TO_A(assign, a_struct, ., obi_if, .) +`define OBI_ASSIGN_TO_R(r_struct, obi_if) `__OBI_TO_R(assign, r_struct, ., obi_if, .) +`define OBI_ASSIGN_TO_REQ(req_struct, obi_if, cfg) `__OBI_TO_REQ(assign, req_struct, .a., obi_if, ., cfg, cfg) +`define OBI_ASSIGN_TO_RSP(rsp_struct, obi_if, cfg) `__OBI_TO_RSP(assign, rsp_struct, .r., obi_if, ., cfg, cfg) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Setting channel or request/response structs from another struct inside a process. +// +// The channel macros `OBI_SET_XX_STRUCT(lhs, rhs)` set the fields of the `lhs` channel struct to +// the fields of the `rhs` channel struct. They do not set the handshake signals, which are not +// part of channel structs. +// The request macro `OBI_SET_REQ_STRUCT(lhs, rhs)` sets all fields of the `lhs` request struct to +// the fields of the `rhs` request struct. This includes the request channel payload and +// request-side handshake signals. +// The response macro `OBI_SET_RSP_STRUCT(lhs, rhs)` sets all fields of the `lhs` response struct +// to the fields of the `rhs` response struct. This includes the response channel payload +// and response-side handshake signals. +// +// Usage Example: +// always_comb begin +// `OBI_SET_REQ_STRUCT(my_req_struct, another_req_struct) +// end +`define OBI_SET_A_STRUCT(lhs, rhs) `__OBI_TO_A(, lhs, ., rhs, .) +`define OBI_SET_R_STRUCT(lhs, rhs) `__OBI_TO_R(, lhs, ., rhs, .) +`define OBI_SET_REQ_STRUCT(lhs, rhs) `__OBI_TO_REQ(, lhs, .a., rhs, .a.) +`define OBI_SET_RSP_STRUCT(lhs, rhs) `__OBI_TO_RSP(, lhs, .r., rhs, .r.) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Assigning channel or request/response structs from another struct outside a process. +// +// The channel macros `OBI_ASSIGN_XX_STRUCT(lhs, rhs)` assign the fields of the `lhs` channel struct +// to the fields of the `rhs` channel struct. They do not assign the handshake signals, which are +// not part of the channel structs. +// The request macro `OBI_ASSIGN_REQ_STRUCT(lhs, rhs)` assigns all fields of the `lhs` request +// struct to the fields of the `rhs` request struct. This includes the request channel payload and +// request-side handshake signals. +// The response macro `OBI_ASSIGN_RSP_STRUCT(lhs, rhs)` assigns all fields of the `lhs` response +// struct to the fields of the `rhs` response struct. This includes the response channel payload +// and response-side handshake signals. +// +// Usage Example: +// `OBI_ASSIGN_REQ_STRUCT(my_req_struct, another_req_struct) +`define OBI_ASSIGN_A_STRUCT(lhs, rhs) `__OBI_TO_A(assign, lhs, ., rhs, .) +`define OBI_ASSIGN_R_STRUCT(lhs, rhs) `__OBI_TO_R(assign, lhs, ., rhs, .) +`define OBI_ASSIGN_REQ_STRUCT(lhs, rhs) `__OBI_TO_REQ(assign, lhs, .a., rhs, .a.) +`define OBI_ASSIGN_RSP_STRUCT(lhs, rhs) `__OBI_TO_RSP(assign, lhs, .r., rhs, .r.) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +`endif // OBI_ASSIGN_SVH diff --git a/vendor/pulp-platform/obi/include/obi/typedef.svh b/vendor/pulp-platform/obi/include/obi/typedef.svh new file mode 100644 index 000000000..dadc40f6b --- /dev/null +++ b/vendor/pulp-platform/obi/include/obi/typedef.svh @@ -0,0 +1,122 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Michael Rogenmoser + +`ifndef OBI_TYPEDEF_SVH +`define OBI_TYPEDEF_SVH + +`define OBI_TYPEDEF_A_CHAN_T(a_chan_t, ADDR_WIDTH, DATA_WIDTH, ID_WIDTH, a_optional_t) \ + typedef struct packed { \ + logic [ ADDR_WIDTH-1:0] addr; \ + logic we; \ + logic [DATA_WIDTH/8-1:0] be; \ + logic [ DATA_WIDTH-1:0] wdata; \ + logic [ ID_WIDTH-1:0] aid; \ + a_optional_t a_optional; \ + } a_chan_t; + +`define OBI_TYPEDEF_TYPE_A_CHAN_T(a_chan_t, addr_t, data_t, strb_t, id_t, a_optional_t) \ + typedef struct packed { \ + addr_t addr; \ + logic we; \ + strb_t be; \ + data_t wdata; \ + id_t aid; \ + a_optional_t a_optional; \ + } a_chan_t; + +`define OBI_TYPEDEF_MINIMAL_A_OPTIONAL(a_optional_t) \ + typedef logic a_optional_t; + +`define OBI_TYPEDEF_ATOP_A_OPTIONAL(a_optional_t) \ + typedef struct packed { \ + obi_pkg::atop_t atop; \ + } a_optional_t; + +`define OBI_TYPEDEF_ALL_A_OPTIONAL(a_optional_t, AUSER_WIDTH, WUSER_WIDTH, MID_WIDTH, ACHK_WIDTH) \ + typedef struct packed { \ + logic [ AUSER_WIDTH-1:0] auser; \ + logic [ WUSER_WIDTH-1:0] wuser; \ + obi_pkg::atop_t atop; \ + obi_pkg::memtype_t memtype; \ + logic [ MID_WIDTH-1:0] mid; \ + obi_pkg::prot_t prot; \ + logic dbg; \ + logic [ ACHK_WIDTH-1:0] achk; \ + } a_optional_t; + +`define OBI_TYPEDEF_R_CHAN_T(r_chan_t, RDATA_WIDTH, ID_WIDTH, r_optional_t) \ + typedef struct packed { \ + logic [RDATA_WIDTH-1:0] rdata; \ + logic [ ID_WIDTH-1:0] rid; \ + logic err; \ + r_optional_t r_optional; \ + } r_chan_t; + +`define OBI_TYPEDEF_TYPE_R_CHAN_T(r_chan_t, data_t, id_t, r_optional_t) \ + typedef struct packed { \ + data_t rdata; \ + id_t rid; \ + logic err; \ + r_optional_t r_optional; \ + } r_chan_t; + +`define OBI_TYPEDEF_MINIMAL_R_OPTIONAL(r_optional_t) \ + typedef logic r_optional_t; + +`define OBI_TYPEDEF_ALL_R_OPTIONAL(r_optional_t, RUSER_WIDTH, RCHK_WIDTH) \ + typedef struct packed { \ + logic [RUSER_WIDTH-1:0] ruser; \ + logic exokay; \ + logic [ RCHK_WIDTH-1:0] rchk; \ + } r_optional_t; + +`define OBI_TYPEDEF_DEFAULT_REQ_T(req_t, a_chan_t) \ + typedef struct packed { \ + a_chan_t a; \ + logic req; \ + } req_t; + +`define OBI_TYPEDEF_REQ_T(req_t, a_chan_t) \ + typedef struct packed { \ + a_chan_t a; \ + logic req; \ + logic rready; \ + } req_t; + +`define OBI_TYPEDEF_RSP_T(rsp_t, r_chan_t) \ + typedef struct packed { \ + r_chan_t r; \ + logic gnt; \ + logic rvalid; \ + } rsp_t; + +`define OBI_TYPEDEF_INTEGRITY_REQ_T(req_t, a_chan_t) \ + typedef struct packed { \ + a_chan_t a; \ + logic req; \ + logic rready; \ + logic reqpar; \ + logic rreadypar; \ + } req_t; + +`define OBI_TYPEDEF_INTEGRITY_RSP_T(rsp_t, r_chan_t) \ + typedef struct packed { \ + r_chan_t r; \ + logic gnt; \ + logic gntpar; \ + logic rvalid; \ + logic rvalidpar; \ + } rsp_t; + +`define OBI_TYPEDEF_ALL(obi_t, cfg) \ + `OBI_TYPEDEF_ALL_A_OPTIONAL(obi_t``_a_optional_t, cfg.OptionalCfg.AUserWidth, cfg.OptionalCfg.WUserWidth, cfg.OptionalCfg.MidWidth, cfg.OptionalCfg.AChkWidth) \ + `OBI_TYPEDEF_A_CHAN_T(obi_t``_a_chan_t, cfg.AddrWidth, cfg.DataWidth, cfg.IdWidth, obi_t``_a_optional_t) \ + `OBI_TYPEDEF_INTEGRITY_REQ_T(obi_t``_req_t, obi_t``_a_chan_t) \ + `OBI_TYPEDEF_ALL_R_OPTIONAL(obi_t``_r_optional_t, cfg.OptionalCfg.RUserWidth, cfg.OptionalCfg.RChkWidth) \ + `OBI_TYPEDEF_R_CHAN_T(obi_t``_r_chan_t, cfg.DataWidth, cfg.IdWidth, obi_t``_r_optional_t) \ + `OBI_TYPEDEF_INTEGRITY_RSP_T(obi_t``_rsp_t, obi_t``_r_chan_t) + +`endif // OBI_TYPEDEF_SVH diff --git a/vendor/pulp-platform/obi/src/obi_atop_resolver.sv b/vendor/pulp-platform/obi/src/obi_atop_resolver.sv new file mode 100644 index 000000000..439ee39d1 --- /dev/null +++ b/vendor/pulp-platform/obi/src/obi_atop_resolver.sv @@ -0,0 +1,509 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Author: Samuel Riedel +// Author: Michael Rogenmoser + +`include "common_cells/registers.svh" + +/// Handles atomics. Hence, it needs to be instantiated in front of a memory region over which the +/// bus has exclusive access. +module obi_atop_resolver import obi_pkg::*; #( + /// The configuration of the subordinate ports (input ports). + parameter obi_pkg::obi_cfg_t SbrPortObiCfg = obi_pkg::ObiDefaultConfig, + /// The configuration of the manager port (output port). + parameter obi_pkg::obi_cfg_t MgrPortObiCfg = SbrPortObiCfg, + /// The request struct for the subordinate port (input ports). + parameter type sbr_port_obi_req_t = logic, + /// The response struct for the subordinate port (input ports). + parameter type sbr_port_obi_rsp_t = logic, + /// The request struct for the manager port (output port). + parameter type mgr_port_obi_req_t = sbr_port_obi_req_t, + /// The response struct for the manager ports (output ports). + parameter type mgr_port_obi_rsp_t = sbr_port_obi_rsp_t, + /// + parameter type mgr_port_obi_a_optional_t = logic, + parameter type mgr_port_obi_r_optional_t = logic, + /// Enable LR & SC AMOS + parameter bit LrScEnable = 1, + /// Cut path between request and response at the cost of increased AMO latency + parameter bit RegisterAmo = 1'b0 +) ( + input logic clk_i, + input logic rst_ni, + input logic testmode_i, + + input sbr_port_obi_req_t sbr_port_req_i, + output sbr_port_obi_rsp_t sbr_port_rsp_o, + + output mgr_port_obi_req_t mgr_port_req_o, + input mgr_port_obi_rsp_t mgr_port_rsp_i +); + + if (!SbrPortObiCfg.OptionalCfg.UseAtop) $fatal(1, "Atomics require atop to be enabled"); + if (MgrPortObiCfg.OptionalCfg.UseAtop) + $fatal(1, "Filter requires atop to be disabled on manager port"); + if (SbrPortObiCfg.Integrity || MgrPortObiCfg.Integrity) $error("Integrity not supported"); + + logic meta_valid, meta_ready; + logic rdata_valid, rdata_ready; + + // read signal before register + logic [SbrPortObiCfg.DataWidth-1:0] out_rdata; + + logic pop_resp; + logic last_amo_wb; + + typedef enum logic [1:0] { + Idle, DoAMO, WriteBackAMO + } amo_state_e; + + amo_state_e state_q, state_d; + + logic load_amo; + obi_atop_e amo_op_q; + logic amo_wb; + logic [SbrPortObiCfg.DataWidth/8-1:0] be_expand; + logic [SbrPortObiCfg.AddrWidth-1:0] addr_q; + logic [SbrPortObiCfg.IdWidth-1:0] aid_q; + + logic [31:0] amo_operand_a; + logic [31:0] amo_operand_a_q; + logic [31:0] amo_operand_b_q; + logic [31:0] amo_result, amo_result_q; + + // Store the metadata at handshake + spill_register #( + .T (logic [SbrPortObiCfg.IdWidth-1:0]), + .Bypass(1'b0 ) + ) i_metadata_register ( + .clk_i, + .rst_ni, + .valid_i ( sbr_port_req_i.req && sbr_port_rsp_o.gnt ), + .ready_o ( meta_ready ), + .data_i ( sbr_port_req_i.a.aid ), + .valid_o ( meta_valid ), + .ready_i ( pop_resp ), + .data_o ( sbr_port_rsp_o.r.rid ) + ); + + // Store response if it's not accepted immediately + logic rdata_full, rdata_empty; + logic rdata_usage; + + assign rdata_ready = !rdata_usage && !rdata_full; + assign rdata_valid = !rdata_empty; + + logic sc_successful_or_lr_d, sc_successful_or_lr_q; + logic sc_q; + + typedef struct packed { + logic [SbrPortObiCfg.DataWidth-1:0] data; + logic err; + logic exokay; + mgr_port_obi_r_optional_t optional; + } out_buffer_t; + out_buffer_t out_buf_fifo_in, out_buf_fifo_out; + + assign out_buf_fifo_in = '{ + data: out_rdata, + err: mgr_port_rsp_i.r.err, + exokay: sc_successful_or_lr_q, + optional: mgr_port_rsp_i.r.r_optional + }; + + assign sbr_port_rsp_o.r.rdata = out_buf_fifo_out.data; + assign sbr_port_rsp_o.r.err = out_buf_fifo_out.err; + assign sbr_port_rsp_o.r.r_optional.exokay = out_buf_fifo_out.exokay; + if (SbrPortObiCfg.OptionalCfg.RUserWidth) begin : gen_ruser + if (MgrPortObiCfg.OptionalCfg.RUserWidth) begin : gen_ruser_assign + always_comb begin + sbr_port_rsp_o.r.r_optional.ruser = '0; + sbr_port_rsp_o.r.r_optional.ruser = out_buf_fifo_in.optional.ruser; + end + end else begin : gen_no_ruser + assign sbr_port_rsp_o.r.r_optional.ruser = '0; + end + end + + fifo_v3 #( + .FALL_THROUGH (1'b1 ), + .dtype (out_buffer_t), + .DEPTH (2 ) + ) i_rdata_fifo ( + .clk_i, + .rst_ni, + .testmode_i, + .flush_i (1'b0 ), + .full_o (rdata_full ), + .empty_o (rdata_empty ), + .usage_o (rdata_usage ), + .data_i (out_buf_fifo_in ), + .push_i (~last_amo_wb & mgr_port_rsp_i.rvalid), + .data_o (out_buf_fifo_out ), + .pop_i (pop_resp & ~rdata_empty) + ); + + // In case of a SC we must forward SC result from the cycle earlier. + assign out_rdata = (sc_q && LrScEnable) ? $unsigned(!sc_successful_or_lr_q) : + mgr_port_rsp_i.r.rdata; + + // Ready to output data if both meta and read data + // are available (the read data will always be last) + assign sbr_port_rsp_o.rvalid = meta_valid & rdata_valid; + // Only pop the data from the registers once both registers are ready + if (SbrPortObiCfg.UseRReady) begin : gen_pop_rready + assign pop_resp = sbr_port_rsp_o.rvalid & sbr_port_req_i.rready; + end else begin : gen_pop_norready + assign pop_resp = sbr_port_rsp_o.rvalid; + end + + // Buffer amo_wb signal to ensure wb rdata is not used + `FFL(last_amo_wb, amo_wb, mgr_port_req_o.req, 1'b0, clk_i, rst_ni); + + // ---------------- + // LR/SC + // ---------------- + + if (LrScEnable) begin : gen_lrsc + // unique requester identifier, does not necessarily match core_id + logic [SbrPortObiCfg.IdWidth-1:0] unique_requester_id; + + typedef struct packed { + /// Is the reservation valid. + logic valid; + /// On which address is the reservation placed. + /// This address is aligned to the memory size + /// implying that the reservation happen on a set size + /// equal to the word width of the memory (32 or 64 bit). + logic [SbrPortObiCfg.AddrWidth-1:0] addr; + /// Which requester made this reservation. Important to + /// track the reservations from different requesters and + /// to prevent any live-locking. + logic [SbrPortObiCfg.IdWidth-1:0] requester; + } reservation_t; + reservation_t reservation_d, reservation_q; + + `FF(sc_successful_or_lr_q, sc_successful_or_lr_d, 1'b0, clk_i, rst_ni); + `FF(reservation_q, reservation_d, 1'b0, clk_i, rst_ni); + `FF(sc_q, sbr_port_req_i.req & + sbr_port_rsp_o.gnt & + (obi_atop_e'(sbr_port_req_i.a.a_optional.atop) == ATOPSC), 1'b0, clk_i, rst_ni); + + always_comb begin + unique_requester_id = sbr_port_req_i.a.aid; + + reservation_d = reservation_q; + sc_successful_or_lr_d = 1'b0; + // new valid transaction + if (sbr_port_req_i.req && sbr_port_rsp_o.gnt) begin + + // An SC can only pair with the most recent LR in program order. + // Place a reservation on the address if there isn't already a valid reservation. + // We prevent a live-lock by don't throwing away the reservation of a hart unless + // it makes a new reservation in program order or issues any SC. + if (obi_atop_e'(sbr_port_req_i.a.a_optional.atop) == ATOPLR && + (!reservation_q.valid || reservation_q.requester == unique_requester_id)) begin + reservation_d.valid = 1'b1; + reservation_d.addr = sbr_port_req_i.a.addr; + reservation_d.requester = unique_requester_id; + sc_successful_or_lr_d = 1'b1; + end + + // An SC may succeed only if no store from another hart (or other device) to + // the reservation set can be observed to have occurred between + // the LR and the SC, and if there is no other SC between the + // LR and itself in program order. + + // check whether another requester has made a write attempt + if ((unique_requester_id != reservation_q.requester) && + (sbr_port_req_i.a.addr == reservation_q.addr) && + (!((obi_atop_e'(sbr_port_req_i.a.a_optional.atop) inside {ATOPLR, ATOPSC}) || + !sbr_port_req_i.a.a_optional.atop[5]) || sbr_port_req_i.a.we)) begin + reservation_d.valid = 1'b0; + end + + // An SC from the same hart clears any pending reservation. + if (reservation_q.valid && obi_atop_e'(sbr_port_req_i.a.a_optional.atop) == ATOPSC + && reservation_q.requester == unique_requester_id) begin + reservation_d.valid = 1'b0; + sc_successful_or_lr_d = (reservation_q.addr == sbr_port_req_i.a.addr); + end + end + end // always_comb + end else begin : gen_disable_lrcs + assign sc_q = 1'b0; + assign sc_successful_or_lr_d = 1'b0; + assign sc_successful_or_lr_q = 1'b0; + end + + // ---------------- + // Atomics + // ---------------- + + mgr_port_obi_a_optional_t a_optional; + if (MgrPortObiCfg.OptionalCfg.AUserWidth) begin : gen_auser + if (SbrPortObiCfg.OptionalCfg.AUserWidth) begin : gen_auser_assign + always_comb begin + a_optional.auser = '0; + a_optional.auser = sbr_port_req_i.a.a_optional.auser; + end + end else begin : gen_no_auser + assign a_optional.auser = '0; + end + end + if (MgrPortObiCfg.OptionalCfg.WUserWidth) begin : gen_wuser + if (SbrPortObiCfg.OptionalCfg.WUserWidth) begin : gen_wuser_assign + always_comb begin + a_optional.wuser = '0; + a_optional.wuser = sbr_port_req_i.a.a_optional.wuser; + end + end else begin : gen_no_wuser + assign a_optional.wuser = '0; + end + end + if (MgrPortObiCfg.OptionalCfg.UseProt) begin : gen_prot + if (SbrPortObiCfg.OptionalCfg.UseProt) begin : gen_prot_assign + assign a_optional.prot = sbr_port_req_i.a.a_optional.prot; + end else begin : gen_no_prot + assign a_optional.prot = obi_pkg::DefaultProt; + end + end + if (MgrPortObiCfg.OptionalCfg.UseMemtype) begin : gen_memtype + if (SbrPortObiCfg.OptionalCfg.UseMemtype) begin : gen_memtype_assign + assign a_optional.memtype = sbr_port_req_i.a.a_optional.memtype; + end else begin : gen_no_memtype + assign a_optional.memtype = obi_pkg::DefaultMemtype; + end + end + if (MgrPortObiCfg.OptionalCfg.MidWidth) begin : gen_mid + if (SbrPortObiCfg.OptionalCfg.MidWidth) begin : gen_mid_assign + always_comb begin + a_optional.mid = '0; + a_optional.mid = sbr_port_req_i.a.a_optional.mid; + end + end else begin : gen_no_mid + assign a_optional.mid = '0; + end + end + if (MgrPortObiCfg.OptionalCfg.UseDbg) begin : gen_dbg + if (SbrPortObiCfg.OptionalCfg.UseDbg) begin : gen_dbg_assign + assign a_optional.dbg = sbr_port_req_i.a.a_optional.dbg; + end else begin : gen_no_dbg + assign a_optional.dbg = '0; + end + end + + if (!MgrPortObiCfg.OptionalCfg.AUserWidth && + !MgrPortObiCfg.OptionalCfg.WUserWidth && + !MgrPortObiCfg.OptionalCfg.UseProt && + !MgrPortObiCfg.OptionalCfg.UseMemtype && + !MgrPortObiCfg.OptionalCfg.MidWidth && + !MgrPortObiCfg.OptionalCfg.UseDbg) begin : gen_no_optional + assign a_optional = '0; + end + + always_comb begin + // feed-through + sbr_port_rsp_o.gnt = rdata_ready & mgr_port_rsp_i.gnt; + mgr_port_req_o.req = sbr_port_req_i.req & rdata_ready; + mgr_port_req_o.a.addr = sbr_port_req_i.a.addr; + mgr_port_req_o.a.we = obi_atop_e'(sbr_port_req_i.a.a_optional.atop) != ATOPSC ? + sbr_port_req_i.a.we : sc_successful_or_lr_d; + mgr_port_req_o.a.wdata = sbr_port_req_i.a.wdata; + mgr_port_req_o.a.be = sbr_port_req_i.a.be; + mgr_port_req_o.a.aid = sbr_port_req_i.a.aid; + mgr_port_req_o.a.a_optional = a_optional; + + state_d = state_q; + load_amo = 1'b0; + amo_wb = 1'b0; + + unique case (state_q) + Idle: begin + if (sbr_port_req_i.req & + sbr_port_rsp_o.gnt & + !((obi_atop_e'(sbr_port_req_i.a.a_optional.atop) inside {ATOPLR, ATOPSC}) || + !sbr_port_req_i.a.a_optional.atop[5])) begin + load_amo = 1'b1; + state_d = DoAMO; + if (obi_atop_e'(sbr_port_req_i.a.a_optional.atop) inside {AMOSWAP, AMOADD, AMOXOR, + AMOAND, AMOOR, AMOMIN, AMOMAX, + AMOMINU, AMOMAXU}) begin + mgr_port_req_o.a.we = 1'b0; + end + end + end + // Claim the memory interface + DoAMO, WriteBackAMO: begin + sbr_port_rsp_o.gnt = 1'b0; + if (mgr_port_rsp_i.gnt) begin + state_d = (RegisterAmo && state_q != WriteBackAMO) ? WriteBackAMO : Idle; + end + // Commit AMO + amo_wb = 1'b1; + mgr_port_req_o.req = 1'b1; + mgr_port_req_o.a.we = 1'b1; + mgr_port_req_o.a.addr = addr_q; + mgr_port_req_o.a.aid = aid_q; + mgr_port_req_o.a.be = {SbrPortObiCfg.DataWidth/8{1'b1}}; + // serve from register if we cut the path + if (RegisterAmo) begin + mgr_port_req_o.a.wdata = amo_result_q; + end else begin + mgr_port_req_o.a.wdata = amo_result; + end + end + default:; + endcase + end + + if (RegisterAmo) begin : gen_amo_slice + `FFLNR(amo_result_q, amo_result, (state_q == DoAMO), clk_i) + end else begin : gen_amo_slice + assign amo_result_q = '0; + end + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + state_q <= Idle; + amo_op_q <= obi_atop_e'('0); + addr_q <= '0; + amo_operand_b_q <= '0; + aid_q <= '0; + end else begin + state_q <= state_d; + if (load_amo) begin + amo_op_q <= obi_atop_e'(sbr_port_req_i.a.a_optional.atop); + addr_q <= sbr_port_req_i.a.addr; + aid_q <= sbr_port_req_i.a.aid; + amo_operand_b_q <= sbr_port_req_i.a.wdata; + end else begin + amo_op_q <= ATOPNONE; + end + end + end + + // ---------------- + // AMO ALU + // ---------------- + logic [33:0] adder_sum; + logic [32:0] adder_operand_a, adder_operand_b; + + `FFL(amo_operand_a_q, mgr_port_rsp_i.r.rdata, mgr_port_rsp_i.rvalid, '0, clk_i, rst_ni) + + assign amo_operand_a = mgr_port_rsp_i.rvalid ? mgr_port_rsp_i.r.rdata : amo_operand_a_q; + assign adder_sum = adder_operand_a + adder_operand_b; + /* verilator lint_off WIDTH */ + always_comb begin : amo_alu + + adder_operand_a = $signed(amo_operand_a); + adder_operand_b = $signed(amo_operand_b_q); + + amo_result = amo_operand_b_q; + + unique case (amo_op_q) + // the default is to output operand_b + AMOSWAP:; + AMOADD: amo_result = adder_sum[31:0]; + AMOAND: amo_result = amo_operand_a & amo_operand_b_q; + AMOOR: amo_result = amo_operand_a | amo_operand_b_q; + AMOXOR: amo_result = amo_operand_a ^ amo_operand_b_q; + AMOMAX: begin + adder_operand_b = -$signed(amo_operand_b_q); + amo_result = adder_sum[32] ? amo_operand_b_q : amo_operand_a; + end + AMOMIN: begin + adder_operand_b = -$signed(amo_operand_b_q); + amo_result = adder_sum[32] ? amo_operand_a : amo_operand_b_q; + end + AMOMAXU: begin + adder_operand_a = $unsigned(amo_operand_a); + adder_operand_b = -$unsigned(amo_operand_b_q); + amo_result = adder_sum[32] ? amo_operand_b_q : amo_operand_a; + end + AMOMINU: begin + adder_operand_a = $unsigned(amo_operand_a); + adder_operand_b = -$unsigned(amo_operand_b_q); + amo_result = adder_sum[32] ? amo_operand_a : amo_operand_b_q; + end + default: amo_result = '0; + endcase + end + + // pragma translate_off + // Check for unsupported parameters + if (SbrPortObiCfg.DataWidth != 32 || MgrPortObiCfg.DataWidth != 32) begin : gen_datawidth_err + $error($sformatf({"Module currently only supports DataWidth = 32. ", + "DataWidth is currently set to: %0d"}, DataWidth)); + end + + `ifndef VERILATOR + assert_rdata_full : assert property( + @(posedge clk_i) disable iff (~rst_ni) (sbr_port_rsp_o.gnt |-> !rdata_full)) + else $fatal (1, "Trying to push new data although the i_rdata_register is not ready."); + `endif + // pragma translate_on + +endmodule + +`include "obi/typedef.svh" +`include "obi/assign.svh" + +module obi_atop_resolver_intf import obi_pkg::*; #( + /// The configuration of the subordinate ports (input ports). + parameter obi_pkg::obi_cfg_t SbrPortObiCfg = obi_pkg::ObiDefaultConfig, + /// The configuration of the manager port (output port). + parameter obi_pkg::obi_cfg_t MgrPortObiCfg = SbrPortObiCfg, + /// Enable LR & SC AMOS + parameter bit LrScEnable = 1, + /// Cut path between request and response at the cost of increased AMO latency + parameter bit RegisterAmo = 1'b0 +) ( + input logic clk_i, + input logic rst_ni, + input logic testmode_i, + + OBI_BUS.Subordinate sbr_port, + + OBI_BUS.Manager mgr_port +); + + `OBI_TYPEDEF_ALL(sbr_port_obi, SbrPortObiCfg) + `OBI_TYPEDEF_ALL(mgr_port_obi, MgrPortObiCfg) + + sbr_port_obi_req_t sbr_port_req; + sbr_port_obi_rsp_t sbr_port_rsp; + + mgr_port_obi_req_t mgr_port_req; + mgr_port_obi_rsp_t mgr_port_rsp; + + `OBI_ASSIGN_TO_REQ(sbr_port_req, sbr_port, SbrPortObiCfg) + `OBI_ASSIGN_FROM_RSP(sbr_port, sbr_port_rsp, SbrPortObiCfg) + + `OBI_ASSIGN_FROM_REQ(mgr_port, mgr_port_req, MgrPortObiCfg) + `OBI_ASSIGN_TO_RSP(mgr_port_rsp, mgr_port, MgrPortObiCfg) + + obi_atop_resolver #( + .SbrPortObiCfg ( SbrPortObiCfg ), + .MgrPortObiCfg ( MgrPortObiCfg ), + .sbr_port_obi_req_t ( sbr_port_obi_req_t ), + .sbr_port_obi_rsp_t ( sbr_port_obi_rsp_t ), + .mgr_port_obi_req_t ( mgr_port_obi_req_t ), + .mgr_port_obi_rsp_t ( mgr_port_obi_rsp_t ), + .mgr_port_obi_a_optional_t( mgr_port_obi_a_optional_t), + .mgr_port_obi_r_optional_t( mgr_port_obi_r_optional_t), + .LrScEnable ( LrScEnable ), + .RegisterAmo ( RegisterAmo ) + ) i_obi_atop_resolver ( + .clk_i, + .rst_ni, + .testmode_i, + .sbr_port_req_i(sbr_port_req), + .sbr_port_rsp_o(sbr_port_rsp), + .mgr_port_req_o(mgr_port_req), + .mgr_port_rsp_i(mgr_port_rsp) + ); + +endmodule diff --git a/vendor/pulp-platform/obi/src/obi_demux.sv b/vendor/pulp-platform/obi/src/obi_demux.sv new file mode 100644 index 000000000..8176a6aed --- /dev/null +++ b/vendor/pulp-platform/obi/src/obi_demux.sv @@ -0,0 +1,164 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Michael Rogenmoser + +module obi_demux #( + /// The OBI configuration for all ports. + parameter obi_pkg::obi_cfg_t ObiCfg = obi_pkg::ObiDefaultConfig, + /// The request struct for all ports. + parameter type obi_req_t = logic, + /// The response struct for all ports. + parameter type obi_rsp_t = logic, + /// The number of manager ports. + parameter int unsigned NumMgrPorts = 32'd0, + /// The maximum number of outstanding transactions. + parameter int unsigned NumMaxTrans = 32'd0, + /// The type of the port select signal. + parameter type select_t = logic [$clog2(NumMgrPorts)-1:0] +) ( + input logic clk_i, + input logic rst_ni, + + input select_t sbr_port_select_i, + input obi_req_t sbr_port_req_i, + output obi_rsp_t sbr_port_rsp_o, + + output obi_req_t [NumMgrPorts-1:0] mgr_ports_req_o, + input obi_rsp_t [NumMgrPorts-1:0] mgr_ports_rsp_i +); + + if (ObiCfg.Integrity) begin : gen_integrity_err + $fatal(1, "unimplemented"); + end + + // stall requests to ensure in-order behavior (could be handled differently with rready) + localparam int unsigned CounterWidth = cf_math_pkg::idx_width(NumMaxTrans); + + logic cnt_up, cnt_down, overflow; + logic [CounterWidth-1:0] in_flight; + logic sbr_port_rready; + + select_t select_d, select_q; + + always_comb begin : proc_req + select_d = select_q; + cnt_up = 1'b0; + for (int i = 0; i < NumMgrPorts; i++) begin + mgr_ports_req_o[i].req = 1'b0; + mgr_ports_req_o[i].a = '0; + end + + if (!overflow) begin + if (sbr_port_select_i == select_q || in_flight == '0 || (in_flight == 1 && cnt_down)) begin + mgr_ports_req_o[sbr_port_select_i].req = sbr_port_req_i.req; + mgr_ports_req_o[sbr_port_select_i].a = sbr_port_req_i.a; + end + end + + if (mgr_ports_req_o[sbr_port_select_i].req && mgr_ports_rsp_i[sbr_port_select_i].gnt) begin + select_d = sbr_port_select_i; + cnt_up = 1'b1; + end + end + + assign sbr_port_rsp_o.gnt = mgr_ports_rsp_i[sbr_port_select_i].gnt; + assign sbr_port_rsp_o.r = mgr_ports_rsp_i[select_q].r; + assign sbr_port_rsp_o.rvalid = mgr_ports_rsp_i[select_q].rvalid; + + if (ObiCfg.UseRReady) begin : gen_rready + assign sbr_port_rready = sbr_port_req_i.rready; + for (genvar i = 0; i < NumMgrPorts; i++) begin : gen_rready + assign mgr_ports_req_o[i].rready = sbr_port_req_i.rready; + end + end else begin : gen_no_rready + assign sbr_port_rready = 1'b1; + end + + assign cnt_down = mgr_ports_rsp_i[select_q].rvalid && sbr_port_rready; + + delta_counter #( + .WIDTH ( CounterWidth ), + .STICKY_OVERFLOW ( 1'b0 ) + ) i_counter ( + .clk_i, + .rst_ni, + + .clear_i ( 1'b0 ), + .en_i ( cnt_up ^ cnt_down ), + .load_i ( 1'b0 ), + .down_i ( cnt_down ), + .delta_i ( {{CounterWidth-1{1'b0}}, 1'b1} ), + .d_i ( '0 ), + .q_o ( in_flight ), + .overflow_o( overflow ) + ); + + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_select + if(!rst_ni) begin + select_q <= '0; + end else begin + select_q <= select_d; + end + end + +endmodule + +`include "obi/typedef.svh" +`include "obi/assign.svh" + +module obi_demux_intf #( + /// The OBI configuration for all ports. + parameter obi_pkg::obi_cfg_t ObiCfg = obi_pkg::ObiDefaultConfig, + /// The number of manager ports. + parameter int unsigned NumMgrPorts = 32'd0, + /// The maximum number of outstanding transactions. + parameter int unsigned NumMaxTrans = 32'd0, + /// The type of the port select signal. + parameter type select_t = logic [$clog2(NumMgrPorts)-1:0] +) ( + input logic clk_i, + input logic rst_ni, + + input select_t sbr_port_select_i, + OBI_BUS.Subordinate sbr_port, + + OBI_BUS.Manager mgr_ports [NumMgrPorts] +); + + `OBI_TYPEDEF_ALL(obi, ObiCfg) + + obi_req_t sbr_port_req; + obi_rsp_t sbr_port_rsp; + + obi_req_t [NumMgrPorts-1:0] mgr_ports_req; + obi_rsp_t [NumMgrPorts-1:0] mgr_ports_rsp; + + `OBI_ASSIGN_TO_REQ(sbr_port_req, sbr_port, ObiCfg) + `OBI_ASSIGN_FROM_RSP(sbr_port, sbr_port_rsp, ObiCfg) + + for (genvar i = 0; i < NumMgrPorts; i++) begin : gen_mgr_ports_assign + `OBI_ASSIGN_FROM_REQ(mgr_ports[i], mgr_ports_req[i], ObiCfg) + `OBI_ASSIGN_TO_RSP(mgr_ports_rsp[i], mgr_ports[i], ObiCfg) + end + + obi_demux #( + .ObiCfg ( ObiCfg ), + .obi_req_t ( obi_req_t ), + .obi_rsp_t ( obi_rsp_t ), + .NumMgrPorts ( NumMgrPorts ), + .NumMaxTrans ( NumMaxTrans ), + .select_t ( select_t ) + ) i_obi_demux ( + .clk_i, + .rst_ni, + .sbr_port_select_i, + .sbr_port_req_i ( sbr_port_req ), + .sbr_port_rsp_o ( sbr_port_rsp ), + .mgr_ports_req_o ( mgr_ports_req ), + .mgr_ports_rsp_i ( mgr_ports_rsp ) + ); + +endmodule + diff --git a/vendor/pulp-platform/obi/src/obi_err_sbr.sv b/vendor/pulp-platform/obi/src/obi_err_sbr.sv new file mode 100644 index 000000000..62f7781d9 --- /dev/null +++ b/vendor/pulp-platform/obi/src/obi_err_sbr.sv @@ -0,0 +1,107 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Michael Rogenmoser + +module obi_err_sbr #( + /// The OBI configuration for all ports. + parameter obi_pkg::obi_cfg_t ObiCfg = obi_pkg::ObiDefaultConfig, + /// The request struct. + parameter type obi_req_t = logic, + /// The response struct. + parameter type obi_rsp_t = logic, + /// Numper of transactions accepted before stalling if UseRReady + parameter int unsigned NumMaxTrans = 1, + /// Data to respond with from error subordinate + parameter logic [ObiCfg.DataWidth-1:0] RspData = 32'hBADCAB1E +) ( + input logic clk_i, + input logic rst_ni, + input logic testmode_i, + + input obi_req_t obi_req_i, + output obi_rsp_t obi_rsp_o +); + + logic [ObiCfg.IdWidth-1:0] rid; + logic fifo_full, fifo_empty, fifo_pop; + + always_comb begin + obi_rsp_o.r.rdata = '0; + obi_rsp_o.r.rdata = RspData; + obi_rsp_o.r.rid = rid; + obi_rsp_o.r.err = 1'b1; + obi_rsp_o.r.r_optional = '0; + obi_rsp_o.gnt = ~fifo_full; + obi_rsp_o.rvalid = ~fifo_empty; + end + + if (ObiCfg.UseRReady) begin : gen_pop_rready + assign fifo_pop = obi_rsp_o.rvalid && obi_req_i.rready; + end else begin : gen_pop_default + assign fifo_pop = obi_rsp_o.rvalid; + end + + fifo_v3 #( + .DEPTH ( ObiCfg.UseRReady ? NumMaxTrans : 1 ), + .FALL_THROUGH ( 1'b0 ), + .DATA_WIDTH ( ObiCfg.IdWidth ) + ) i_id_fifo ( + .clk_i, + .rst_ni, + .testmode_i, + .flush_i ( '0 ), + .full_o ( fifo_full ), + .empty_o ( fifo_empty ), + .usage_o (), + .data_i ( obi_req_i.a.aid ), + .push_i ( obi_req_i.req && obi_rsp_o.gnt ), + .data_o ( rid ), + .pop_i ( fifo_pop ) + ); + +endmodule + +`include "obi/typedef.svh" +`include "obi/assign.svh" + +module obi_err_sbr_intf #( + /// The OBI configuration for all ports. + parameter obi_pkg::obi_cfg_t ObiCfg = obi_pkg::ObiDefaultConfig, + /// Numper of transactions accepted before stalling if UseRReady + parameter int unsigned NumMaxTrans = 1, + /// Data to respond with from error subordinate + parameter logic [ObiCfg.DataWidth-1:0] RspData = 32'hBADCAB1E +) ( + input logic clk_i, + input logic rst_ni, + input logic testmode_i, + + OBI_BUS.Subordinate sbr_port +); + + `OBI_TYPEDEF_ALL(obi, ObiCfg) + + obi_req_t obi_req; + obi_rsp_t obi_rsp; + + `OBI_ASSIGN_TO_REQ(obi_req, sbr_port, ObiCfg) + `OBI_ASSIGN_FROM_RSP(sbr_port, obi_rsp, ObiCfg) + + obi_err_sbr #( + .ObiCfg ( ObiCfg ), + .obi_req_t ( obi_req_t ), + .obi_rsp_t ( obi_rsp_t ), + .NumMaxTrans ( NumMaxTrans ), + .RspData ( RspData ) + ) i_err_sbr ( + .clk_i, + .rst_ni, + .testmode_i, + + .obi_req_i ( obi_req ), + .obi_rsp_o ( obi_rsp ) + ); + +endmodule diff --git a/vendor/pulp-platform/obi/src/obi_intf.sv b/vendor/pulp-platform/obi/src/obi_intf.sv new file mode 100644 index 000000000..cc2bf6c8b --- /dev/null +++ b/vendor/pulp-platform/obi/src/obi_intf.sv @@ -0,0 +1,241 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Michael Rogenmoser + +interface OBI_BUS #( + parameter obi_pkg::obi_cfg_t OBI_CFG = obi_pkg::ObiDefaultConfig, + parameter type obi_a_optional_t = logic, + parameter type obi_r_optional_t = logic +) (); + logic req; + logic reqpar; + logic gnt; + logic gntpar; + logic [ OBI_CFG.AddrWidth-1:0] addr; + logic we; + logic [OBI_CFG.DataWidth/8-1:0] be; + logic [ OBI_CFG.DataWidth-1:0] wdata; + logic [ OBI_CFG.IdWidth-1:0] aid; + obi_a_optional_t a_optional; + + logic rvalid; + logic rvalidpar; + logic rready; + logic rreadypar; + logic [ OBI_CFG.DataWidth-1:0] rdata; + logic [ OBI_CFG.IdWidth-1:0] rid; + logic err; + obi_r_optional_t r_optional; + + modport Manager ( + output req, + output reqpar, + input gnt, + input gntpar, + output addr, + output we, + output be, + output wdata, + output aid, + output a_optional, + + input rvalid, + input rvalidpar, + output rready, + output rreadypar, + input rdata, + input rid, + input err, + input r_optional + ); + + modport Subordinate ( + input req, + input reqpar, + output gnt, + output gntpar, + input addr, + input we, + input be, + input wdata, + input aid, + input a_optional, + + output rvalid, + output rvalidpar, + input rready, + input rreadypar, + output rdata, + output rid, + output err, + output r_optional + ); + + modport Monitor ( + input req, + input reqpar, + input gnt, + input gntpar, + input addr, + input we, + input be, + input wdata, + input aid, + input a_optional, + + input rvalid, + input rvalidpar, + input rready, + input rreadypar, + input rdata, + input rid, + input err, + input r_optional + ); + + +endinterface + +interface OBI_BUS_DV #( + parameter obi_pkg::obi_cfg_t OBI_CFG = obi_pkg::ObiDefaultConfig, + parameter type obi_a_optional_t = logic, + parameter type obi_r_optional_t = logic +) ( + input logic clk_i, + input logic rst_ni +); + logic req; + logic reqpar; + logic gnt; + logic gntpar; + logic [ OBI_CFG.AddrWidth-1:0] addr; + logic we; + logic [OBI_CFG.DataWidth/8-1:0] be; + logic [ OBI_CFG.DataWidth-1:0] wdata; + logic [ OBI_CFG.IdWidth-1:0] aid; + obi_a_optional_t a_optional; + + logic rvalid; + logic rvalidpar; + logic rready; + logic rreadypar; + logic [ OBI_CFG.DataWidth-1:0] rdata; + logic [ OBI_CFG.IdWidth-1:0] rid; + logic err; + obi_r_optional_t r_optional; + + modport Manager ( + output req, + output reqpar, + input gnt, + input gntpar, + output addr, + output we, + output be, + output wdata, + output aid, + output a_optional, + + input rvalid, + input rvalidpar, + output rready, + output rreadypar, + input rdata, + input rid, + input err, + input r_optional + ); + + modport Subordinate ( + input req, + input reqpar, + output gnt, + output gntpar, + input addr, + input we, + input be, + input wdata, + input aid, + input a_optional, + + output rvalid, + output rvalidpar, + input rready, + input rreadypar, + output rdata, + output rid, + output err, + output r_optional + ); + + modport Monitor ( + input req, + input reqpar, + input gnt, + input gntpar, + input addr, + input we, + input be, + input wdata, + input aid, + input a_optional, + + input rvalid, + input rvalidpar, + input rready, + input rreadypar, + input rdata, + input rid, + input err, + input r_optional + ); + +// pragma translate_off +`ifndef VERILATOR + + // A channel + // OBI spec R3.1 + assert property (@(posedge clk_i) disable iff (!rst_ni) req |-> ##[1:$] gnt); + assert property (@(posedge clk_i) disable iff (!rst_ni) (req && !gnt |=> $stable(addr))); + assert property (@(posedge clk_i) disable iff (!rst_ni) (req && !gnt |=> $stable(we))); + assert property (@(posedge clk_i) disable iff (!rst_ni) (req && !gnt |=> $stable(be))); + assert property (@(posedge clk_i) disable iff (!rst_ni) (req && !gnt |=> $stable(wdata))); + assert property (@(posedge clk_i) disable iff (!rst_ni) (req && !gnt |=> $stable(aid))); + assert property (@(posedge clk_i) disable iff (!rst_ni) (req && !gnt |=> $stable(a_optional))); + assert property (@(posedge clk_i) disable iff (!rst_ni) (req && !gnt |=> req)); + if (OBI_CFG.Integrity) begin : gen_integrity_req_check + assert property (@(posedge clk_i) disable iff (!rst_ni) (req && ~reqpar)); + assert property (@(posedge clk_i) disable iff (!rst_ni) (gnt && ~gntpar)); + // TODO: achk? + end + + // R channel + if (OBI_CFG.UseRReady) begin : gen_rready_checks + // OBI spec R4.1 + assert property (@(posedge clk_i) disable iff (!rst_ni) rvalid |-> ##[1:$] rready); + assert property (@(posedge clk_i) disable iff (!rst_ni) (rvalid && !rready |=> $stable(rdata))); + assert property (@(posedge clk_i) disable iff (!rst_ni) (rvalid && !rready |=> $stable(rid))); + assert property (@(posedge clk_i) disable iff (!rst_ni) (rvalid && !rready |=> $stable(err))); + assert property (@(posedge clk_i) disable iff (!rst_ni) (rvalid && !rready |=> + $stable(r_optional))); + assert property (@(posedge clk_i) disable iff (!rst_ni) (rvalid && !rready |=> rvalid)); + end + if (OBI_CFG.Integrity) begin : gen_integrity_rsp_check + assert property (@(posedge clk_i) disable iff (!rst_ni) (rvalid && ~rvalidpar)); + if (OBI_CFG.UseRReady) begin : gen_rready_integrity_check + assert property (@(posedge clk_i) disable iff (!rst_ni) (rready && ~rreadypar)); + end + end + + if (!OBI_CFG.BeFull) begin : gen_be_checks + // OBI spec R7 + assert property (@(posedge clk_i) disable iff (!rst_ni) (req && gnt && we |-> be != '0)); + // TODO R7: assert be contiguous + end + +`endif +// pragma translate_on + +endinterface diff --git a/vendor/pulp-platform/obi/src/obi_mux.sv b/vendor/pulp-platform/obi/src/obi_mux.sv new file mode 100644 index 000000000..4a98e26f8 --- /dev/null +++ b/vendor/pulp-platform/obi/src/obi_mux.sv @@ -0,0 +1,228 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Michael Rogenmoser + +`include "obi/assign.svh" + +/// An OBI multiplexer. +module obi_mux #( + /// The configuration of the subordinate ports (input ports). + parameter obi_pkg::obi_cfg_t SbrPortObiCfg = obi_pkg::ObiDefaultConfig, + /// The configuration of the manager port (output port). + parameter obi_pkg::obi_cfg_t MgrPortObiCfg = SbrPortObiCfg, + /// The request struct for the subordinate ports (input ports). + parameter type sbr_port_obi_req_t = logic, + /// The A channel struct for the subordinate ports (input ports). + parameter type sbr_port_a_chan_t = logic, + /// The response struct for the subordinate ports (input ports). + parameter type sbr_port_obi_rsp_t = logic, + /// The R channel struct for the subordinate ports (input ports). + parameter type sbr_port_r_chan_t = logic, + /// The request struct for the manager port (output port). + parameter type mgr_port_obi_req_t = sbr_port_obi_req_t, + /// The response struct for the manager ports (output ports). + parameter type mgr_port_obi_rsp_t = sbr_port_obi_rsp_t, + /// The number of subordinate ports (input ports). + parameter int unsigned NumSbrPorts = 32'd0, + /// The maximum number of outstanding transactions. + parameter int unsigned NumMaxTrans = 32'd0, + /// Use the extended ID field (aid & rid) to route the response + parameter bit UseIdForRouting = 1'b0 +) ( + input logic clk_i, + input logic rst_ni, + input logic testmode_i, + + input sbr_port_obi_req_t [NumSbrPorts-1:0] sbr_ports_req_i, + output sbr_port_obi_rsp_t [NumSbrPorts-1:0] sbr_ports_rsp_o, + + output mgr_port_obi_req_t mgr_port_req_o, + input mgr_port_obi_rsp_t mgr_port_rsp_i +); + if (NumSbrPorts <= 1) begin : gen_NumSbrPorts_err + $fatal(1, "unimplemented"); + end + + localparam int unsigned RequiredExtraIdWidth = $clog2(NumSbrPorts); + + logic [NumSbrPorts-1:0] sbr_ports_req, sbr_ports_gnt; + sbr_port_a_chan_t [NumSbrPorts-1:0] sbr_ports_a; + for (genvar i = 0; i < NumSbrPorts; i++) begin : gen_sbr_assign + assign sbr_ports_req[i] = sbr_ports_req_i[i].req; + assign sbr_ports_a[i] = sbr_ports_req_i[i].a; + assign sbr_ports_rsp_o[i].gnt = sbr_ports_gnt[i]; + end + + sbr_port_a_chan_t mgr_port_a_in_sbr; + logic [RequiredExtraIdWidth-1:0] selected_id, response_id; + logic mgr_port_req, fifo_full, fifo_pop; + + rr_arb_tree #( + .NumIn ( NumSbrPorts ), + .DataType ( sbr_port_a_chan_t ), + .AxiVldRdy ( 1'b1 ), + .LockIn ( 1'b1 ) + ) i_rr_arb ( + .clk_i, + .rst_ni, + + .flush_i ( 1'b0 ), + .rr_i ( '0 ), + + .req_i ( sbr_ports_req ), + .gnt_o ( sbr_ports_gnt ), + .data_i ( sbr_ports_a ), + + .req_o ( mgr_port_req ), + .gnt_i ( mgr_port_rsp_i.gnt && ~fifo_full ), + .data_o ( mgr_port_a_in_sbr ), + + .idx_o ( selected_id ) + ); + + assign mgr_port_req_o.req = mgr_port_req && ~fifo_full; + + if (MgrPortObiCfg.IdWidth > 0 && + (MgrPortObiCfg.IdWidth >= SbrPortObiCfg.IdWidth + RequiredExtraIdWidth)) begin : gen_aid_extend + always_comb begin + mgr_port_req_o.a.aid = '0; + `OBI_SET_A_STRUCT(mgr_port_req_o.a, mgr_port_a_in_sbr) + mgr_port_req_o.a.aid[SbrPortObiCfg.IdWidth + RequiredExtraIdWidth-1:0] = + {selected_id, mgr_port_a_in_sbr.aid}; + end + end else begin : gen_aid_consistent + always_comb begin + mgr_port_req_o.a.aid = '0; + `OBI_SET_A_STRUCT(mgr_port_req_o.a, mgr_port_a_in_sbr) + end + end + + logic [SbrPortObiCfg.IdWidth-1:0] rsp_rid; + + if (UseIdForRouting) begin : gen_id_assign + if (!(MgrPortObiCfg.IdWidth > 0 && + (MgrPortObiCfg.IdWidth >= SbrPortObiCfg.IdWidth + RequiredExtraIdWidth))) + $fatal(1, "UseIdForRouting requires MgrPort IdWidth to increase with log2(NumSbrPorts)"); + + assign {response_id, rsp_rid} = + mgr_port_rsp_i.r.rid[SbrPortObiCfg.IdWidth + RequiredExtraIdWidth-1:0]; + assign fifo_full = 1'b0; + + end else begin : gen_no_id_assign + + fifo_v3 #( + .FALL_THROUGH( 1'b0 ), + .DATA_WIDTH ( RequiredExtraIdWidth ), + .DEPTH ( NumMaxTrans ) + ) i_fifo ( + .clk_i, + .rst_ni, + .flush_i ('0), + .testmode_i, + + .full_o ( fifo_full ), + .empty_o (), + .usage_o (), + .data_i ( selected_id ), + .push_i ( mgr_port_req_o.req && mgr_port_rsp_i.gnt ), + + .data_o ( response_id ), + .pop_i ( fifo_pop ) + ); + + end + + if (MgrPortObiCfg.UseRReady) begin : gen_rready_connect + assign mgr_port_req_o.rready = sbr_ports_req_i[response_id].rready; + end + logic [NumSbrPorts-1:0] sbr_rsp_rvalid; + sbr_port_r_chan_t [NumSbrPorts-1:0] sbr_rsp_r; + always_comb begin : proc_sbr_rsp + for (int i = 0; i < NumSbrPorts; i++) begin + sbr_rsp_r[i] = '0; + sbr_rsp_rvalid[i] = '0; + end + `OBI_SET_R_STRUCT(sbr_rsp_r[response_id], mgr_port_rsp_i.r); + sbr_rsp_rvalid[response_id] = mgr_port_rsp_i.rvalid; + end + + for (genvar i = 0; i < NumSbrPorts; i++) begin : gen_sbr_rsp_assign + assign sbr_ports_rsp_o[i].r = sbr_rsp_r[i]; + assign sbr_ports_rsp_o[i].rvalid = sbr_rsp_rvalid[i]; + end + + if (MgrPortObiCfg.UseRReady) begin : gen_fifo_pop + assign fifo_pop = mgr_port_rsp_i.rvalid && mgr_port_req_o.rready; + end else begin : gen_fifo_pop + assign fifo_pop = mgr_port_rsp_i.rvalid; + end + +endmodule + +`include "obi/typedef.svh" + +module obi_mux_intf #( + /// The configuration of the subordinate ports (input ports). + parameter obi_pkg::obi_cfg_t SbrPortObiCfg = obi_pkg::ObiDefaultConfig, + /// The configuration of the manager port (output port). + parameter obi_pkg::obi_cfg_t MgrPortObiCfg = SbrPortObiCfg, + /// The number of subordinate ports (input ports). + parameter int unsigned NumSbrPorts = 32'd0, + /// The maximum number of outstanding transactions. + parameter int unsigned NumMaxTrans = 32'd0, + /// Use the extended ID field (aid & rid) to route the response + parameter bit UseIdForRouting = 1'b0 +) ( + input logic clk_i, + input logic rst_ni, + input logic testmode_i, + + OBI_BUS.Subordinate sbr_ports [NumSbrPorts], + + OBI_BUS.Manager mgr_port +); + + `OBI_TYPEDEF_ALL(sbr_port_obi, SbrPortObiCfg) + `OBI_TYPEDEF_ALL(mgr_port_obi, MgrPortObiCfg) + + sbr_port_obi_req_t [NumSbrPorts-1:0] sbr_ports_req; + sbr_port_obi_rsp_t [NumSbrPorts-1:0] sbr_ports_rsp; + + mgr_port_obi_req_t mgr_port_req; + mgr_port_obi_rsp_t mgr_port_rsp; + + for (genvar i = 0; i < NumSbrPorts; i++) begin : gen_sbr_ports_assign + `OBI_ASSIGN_TO_REQ(sbr_ports_req[i], sbr_ports[i], SbrPortObiCfg) + `OBI_ASSIGN_FROM_RSP(sbr_ports[i], sbr_ports_rsp[i], SbrPortObiCfg) + end + + `OBI_ASSIGN_FROM_REQ(mgr_port, mgr_port_req, MgrPortObiCfg) + `OBI_ASSIGN_TO_RSP(mgr_port_rsp, mgr_port, MgrPortObiCfg) + + obi_mux #( + .SbrPortObiCfg ( SbrPortObiCfg ), + .MgrPortObiCfg ( MgrPortObiCfg ), + .sbr_port_obi_req_t ( sbr_port_obi_req_t ), + .sbr_port_a_chan_t ( sbr_port_obi_a_chan_t ), + .sbr_port_obi_rsp_t ( sbr_port_obi_rsp_t ), + .sbr_port_r_chan_t ( sbr_port_obi_r_chan_t ), + .mgr_port_obi_req_t ( mgr_port_obi_req_t ), + .mgr_port_obi_rsp_t ( mgr_port_obi_rsp_t ), + .NumSbrPorts ( NumSbrPorts ), + .NumMaxTrans ( NumMaxTrans ), + .UseIdForRouting ( UseIdForRouting ) + ) i_obi_mux ( + .clk_i, + .rst_ni, + .testmode_i, + + .sbr_ports_req_i ( sbr_ports_req ), + .sbr_ports_rsp_o ( sbr_ports_rsp ), + + .mgr_port_req_o ( mgr_port_req ), + .mgr_port_rsp_i ( mgr_port_rsp ) + ); + +endmodule diff --git a/vendor/pulp-platform/obi/src/obi_pkg.sv b/vendor/pulp-platform/obi/src/obi_pkg.sv new file mode 100644 index 000000000..32bb1d10b --- /dev/null +++ b/vendor/pulp-platform/obi/src/obi_pkg.sv @@ -0,0 +1,136 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Michael Rogenmoser + +package obi_pkg; + + /// The OBI atomics type, to be expanded. + typedef logic [5:0] atop_t; + + /// The OBI memtype type, to be expanded. + typedef logic [1:0] memtype_t; + + /// The OBI prot type, to be expanded. + typedef logic [2:0] prot_t; + + localparam atop_t DefaultAtop = 6'b000000; + localparam memtype_t DefaultMemtype = 2'b00; + localparam prot_t DefaultProt = 3'b111; + + /// The config type for OBI bus optional fields. + typedef struct packed { + bit UseAtop; + bit UseMemtype; + bit UseProt; + bit UseDbg; + int unsigned AUserWidth; + int unsigned WUserWidth; + int unsigned RUserWidth; + int unsigned MidWidth; + int unsigned AChkWidth; + int unsigned RChkWidth; + } obi_optional_cfg_t; + + localparam obi_optional_cfg_t ObiMinimalOptionalConfig = '{ + UseAtop: 1'b0, + UseMemtype: 1'b0, + UseProt: 1'b0, + UseDbg: 1'b0, + AUserWidth: 0, + WUserWidth: 0, + RUserWidth: 0, + MidWidth: 0, + AChkWidth: 0, + RChkWidth: 0 + }; + + localparam obi_optional_cfg_t ObiAtopOptionalConfig = '{ + UseAtop: 1'b1, + UseMemtype: 1'b0, + UseProt: 1'b0, + UseDbg: 1'b0, + AUserWidth: 0, + WUserWidth: 0, + RUserWidth: 0, + MidWidth: 0, + AChkWidth: 0, + RChkWidth: 0 + }; + + function automatic obi_optional_cfg_t obi_all_optional_config(int unsigned AUserWidth, + int unsigned WUserWidth, int unsigned RUserWidth, int unsigned MidWidth, + int unsigned AChkWidth, int unsigned RChkWidth); + obi_all_optional_config = '{ + UseAtop: 1'b1, + UseMemtype: 1'b1, + UseProt: 1'b1, + UseDbg: 1'b1, + AUserWidth: AUserWidth, + WUserWidth: WUserWidth, + RUserWidth: RUserWidth, + MidWidth: MidWidth, + AChkWidth: AChkWidth, + RChkWidth: RChkWidth + }; + endfunction + + /// The OBI bus config type. + typedef struct packed { + bit UseRReady; + bit CombGnt; + int unsigned AddrWidth; + int unsigned DataWidth; + int unsigned IdWidth; + bit Integrity; + bit BeFull; + obi_optional_cfg_t OptionalCfg; + } obi_cfg_t; + + function automatic obi_cfg_t obi_default_cfg(int unsigned AddrWidth, int unsigned DataWidth, + int unsigned IdWidth, obi_optional_cfg_t OptionalCfg); + obi_default_cfg = '{ + UseRReady: 1'b0, + CombGnt: 1'b0, + AddrWidth: AddrWidth, + DataWidth: DataWidth, + IdWidth: IdWidth, + Integrity: 1'b0, + BeFull: 1'b1, + OptionalCfg: OptionalCfg + }; + endfunction + + /// The default OBI bus config. + localparam obi_cfg_t ObiDefaultConfig = obi_default_cfg(32, 32, 1, ObiMinimalOptionalConfig); + + function automatic obi_cfg_t mux_grow_cfg(obi_cfg_t ObiCfgIn, int unsigned NumManagers); + mux_grow_cfg = '{ + UseRReady: ObiCfgIn.UseRReady, + CombGnt: ObiCfgIn.CombGnt, + AddrWidth: ObiCfgIn.AddrWidth, + DataWidth: ObiCfgIn.DataWidth, + IdWidth: ObiCfgIn.IdWidth + cf_math_pkg::idx_width(NumManagers), + Integrity: ObiCfgIn.Integrity, + BeFull: ObiCfgIn.BeFull, + OptionalCfg: ObiCfgIn.OptionalCfg + }; + endfunction + + typedef enum atop_t { + ATOPLR = 6'h22, + ATOPSC = 6'h23, + AMOSWAP = 6'h21, + AMOADD = 6'h20, + AMOXOR = 6'h24, + AMOAND = 6'h2C, + AMOOR = 6'h28, + AMOMIN = 6'h30, + AMOMAX = 6'h34, + AMOMINU = 6'h38, + AMOMAXU = 6'h3C, + ATOPNONE = 6'h0 + } obi_atop_e; + +endpackage diff --git a/vendor/pulp-platform/obi/src/obi_rready_converter.sv b/vendor/pulp-platform/obi/src/obi_rready_converter.sv new file mode 100644 index 000000000..518d9234c --- /dev/null +++ b/vendor/pulp-platform/obi/src/obi_rready_converter.sv @@ -0,0 +1,72 @@ +// Copyright 2024 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Author: Georg Rutishauser + +module obi_rready_converter #( + parameter type obi_a_chan_t = logic, + parameter type obi_r_chan_t = logic, + parameter int unsigned Depth = 1, + parameter bit CombRspReq = 1'b1 +) ( + input logic clk_i, + input logic rst_ni, + input logic test_mode_i, + + input obi_a_chan_t sbr_a_chan_i, + input logic req_i, + output logic gnt_o, + output obi_r_chan_t sbr_r_chan_o, + output logic rvalid_o, + input logic rready_i, + + output obi_a_chan_t mgr_a_chan_o, + output logic req_o, + input logic gnt_i, + input obi_r_chan_t mgr_r_chan_i, + input logic rvalid_i +); + + logic fifo_ready, credit_left; + stream_fifo #( + .FALL_THROUGH ( 1'b1 ), + .DEPTH ( Depth ), + .T ( obi_r_chan_t ) + ) response_fifo_i ( + .clk_i, + .rst_ni, + .flush_i ( 1'b0 ), + .testmode_i ( test_mode_i ), + .usage_o (), + .data_i ( mgr_r_chan_i ), + .valid_i ( rvalid_i ), + .ready_o ( fifo_ready ), + .data_o ( sbr_r_chan_o ), + .valid_o ( rvalid_o ), + .ready_i ( rready_i ) + ); + + credit_counter #( + .NumCredits ( Depth ), + .InitCreditEmpty ( 1'b0 ) + ) credit_cntr_i ( + .clk_i, + .rst_ni, + .credit_o (), + .credit_give_i ( rvalid_o & rready_i ), + .credit_take_i ( req_o & gnt_i ), + .credit_init_i ( 1'b0 ), + .credit_left_o ( credit_left ), + .credit_crit_o (), + .credit_full_o () + ); + + // only transmit requests if we have credits left or free a space in the FIFO + assign req_o = req_i & (credit_left | (CombRspReq & rready_i & rvalid_o)); + // only grant requests if we have credits left or free a space in the FIFO + assign gnt_o = gnt_i & (credit_left | (CombRspReq & rready_i & rvalid_o)); + + assign mgr_a_chan_o = sbr_a_chan_i; + +endmodule diff --git a/vendor/pulp-platform/obi/src/obi_sram_shim.sv b/vendor/pulp-platform/obi/src/obi_sram_shim.sv new file mode 100644 index 000000000..d2e744364 --- /dev/null +++ b/vendor/pulp-platform/obi/src/obi_sram_shim.sv @@ -0,0 +1,66 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Michael Rogenmoser + +module obi_sram_shim #( + /// The OBI configuration for all ports. + parameter obi_pkg::obi_cfg_t ObiCfg = obi_pkg::ObiDefaultConfig, + /// The request struct for all ports. + parameter type obi_req_t = logic, + /// The response struct for all ports. + parameter type obi_rsp_t = logic +) ( + input logic clk_i, + input logic rst_ni, + + input obi_req_t obi_req_i, + output obi_rsp_t obi_rsp_o, + + output logic req_o, + output logic we_o, + output logic [ ObiCfg.AddrWidth-1:0] addr_o, + output logic [ ObiCfg.DataWidth-1:0] wdata_o, + output logic [ObiCfg.DataWidth/8-1:0] be_o, + + input logic gnt_i, + input logic [ ObiCfg.DataWidth-1:0] rdata_i +); + + if (ObiCfg.OptionalCfg.UseAtop) $error("Please use an ATOP resolver before sram shim."); + if (ObiCfg.UseRReady) $error("Please use an RReady Fifo before sram shim."); + if (ObiCfg.Integrity) $error("Integrity not yet supported, WIP"); + if (ObiCfg.OptionalCfg.UseProt) $warning("Prot not checked!"); + if (ObiCfg.OptionalCfg.UseMemtype) $warning("Memtype not checked!"); + + logic rvalid_d, rvalid_q; + logic [ObiCfg.IdWidth-1:0] id_d, id_q; + + assign req_o = obi_req_i.req; + assign we_o = obi_req_i.a.we; + assign addr_o = obi_req_i.a.addr; + assign wdata_o = obi_req_i.a.wdata; + assign be_o = obi_req_i.a.be; + + assign obi_rsp_o.gnt = gnt_i; + assign obi_rsp_o.rvalid = rvalid_q; + assign obi_rsp_o.r.rdata = rdata_i; + assign obi_rsp_o.r.rid = id_q; + assign obi_rsp_o.r.err = 1'b0; + assign obi_rsp_o.r.r_optional = '0; + + assign rvalid_d = obi_req_i.req & obi_rsp_o.gnt; + assign id_d = obi_req_i.a.aid; + + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_sram_state + if(!rst_ni) begin + rvalid_q <= 1'b0; + id_q <= '0; + end else begin + rvalid_q <= rvalid_d; + id_q <= id_d; + end + end + +endmodule diff --git a/vendor/pulp-platform/obi/src/obi_xbar.sv b/vendor/pulp-platform/obi/src/obi_xbar.sv new file mode 100644 index 000000000..21e21c8ff --- /dev/null +++ b/vendor/pulp-platform/obi/src/obi_xbar.sv @@ -0,0 +1,242 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Michael Rogenmoser + +/// An OBI crossbar interconnect. +module obi_xbar #( + /// The OBI configuration for the subordinate ports (input ports). + parameter obi_pkg::obi_cfg_t SbrPortObiCfg = obi_pkg::ObiDefaultConfig, + /// The OBI configuration for the manager ports (ouput ports). + parameter obi_pkg::obi_cfg_t MgrPortObiCfg = SbrPortObiCfg, + /// The request struct for the subordinate ports (input ports). + parameter type sbr_port_obi_req_t = logic, + /// The A channel struct for the subordinate ports (input ports). + parameter type sbr_port_a_chan_t = logic, + /// The response struct for the subordinate ports (input ports). + parameter type sbr_port_obi_rsp_t = logic, + /// The R channel struct for the subordinate ports (input ports). + parameter type sbr_port_r_chan_t = logic, + /// The request struct for the manager ports (output ports). + parameter type mgr_port_obi_req_t = sbr_port_obi_req_t, + /// The response struct for the manager ports (output ports). + parameter type mgr_port_obi_rsp_t = sbr_port_obi_rsp_t, + /// The number of subordinate ports (input ports). + parameter int unsigned NumSbrPorts = 32'd0, + /// The number of manager ports (output ports). + parameter int unsigned NumMgrPorts = 32'd0, + /// The maximum number of outstanding transactions. + parameter int unsigned NumMaxTrans = 32'd0, + /// The number of address rules. + parameter int unsigned NumAddrRules = 32'd0, + /// The address map rule type. + parameter type addr_map_rule_t = logic, + /// Use the extended ID field (aid & rid) to route the response + parameter bit UseIdForRouting = 1'b0, + /// Connectivity matrix to disable certain paths. + parameter bit [NumSbrPorts-1:0][NumMgrPorts-1:0] Connectivity = '1 +) ( + input logic clk_i, + input logic rst_ni, + input logic testmode_i, + + input sbr_port_obi_req_t [NumSbrPorts-1:0] sbr_ports_req_i, + output sbr_port_obi_rsp_t [NumSbrPorts-1:0] sbr_ports_rsp_o, + + output mgr_port_obi_req_t [NumMgrPorts-1:0] mgr_ports_req_o, + input mgr_port_obi_rsp_t [NumMgrPorts-1:0] mgr_ports_rsp_i, + + input addr_map_rule_t [NumAddrRules-1:0] addr_map_i, + input logic [NumSbrPorts-1:0] en_default_idx_i, + input logic [NumSbrPorts-1:0][$clog2(NumMgrPorts)-1:0] default_idx_i +); + + logic [NumSbrPorts-1:0][$clog2(NumMgrPorts)-1:0] sbr_port_select; + + // Signals from the demuxes + sbr_port_obi_req_t [NumSbrPorts-1:0][NumMgrPorts-1:0] sbr_reqs; + sbr_port_obi_rsp_t [NumSbrPorts-1:0][NumMgrPorts-1:0] sbr_rsps; + + // Signals to the muxes + sbr_port_obi_req_t [NumMgrPorts-1:0][NumSbrPorts-1:0] mgr_reqs; + sbr_port_obi_rsp_t [NumMgrPorts-1:0][NumSbrPorts-1:0] mgr_rsps; + + for (genvar i = 0; i < NumSbrPorts; i++) begin : gen_demux + addr_decode #( + .NoIndices ( NumMgrPorts ), + .NoRules ( NumAddrRules ), + .addr_t ( logic [MgrPortObiCfg.AddrWidth-1:0] ), + .rule_t ( addr_map_rule_t ) + ) i_addr_decode ( + .addr_i ( sbr_ports_req_i[i].a.addr ), + .addr_map_i ( addr_map_i ), + .idx_o ( sbr_port_select[i] ), + .dec_valid_o (), + .dec_error_o (), + .en_default_idx_i( en_default_idx_i[i] ), + .default_idx_i ( default_idx_i[i] ) + ); + + obi_demux #( + .ObiCfg ( SbrPortObiCfg ), + .obi_req_t ( sbr_port_obi_req_t ), + .obi_rsp_t ( sbr_port_obi_rsp_t ), + .NumMgrPorts ( NumMgrPorts ), + .NumMaxTrans ( NumMaxTrans ) + ) i_demux ( + .clk_i, + .rst_ni, + .sbr_port_select_i ( sbr_port_select[i] ), + .sbr_port_req_i ( sbr_ports_req_i[i] ), + .sbr_port_rsp_o ( sbr_ports_rsp_o[i] ), + .mgr_ports_req_o ( sbr_reqs[i] ), + .mgr_ports_rsp_i ( sbr_rsps[i] ) + ); + end + + for (genvar i = 0; i < NumSbrPorts; i++) begin : gen_interco_sbr + for (genvar j = 0; j < NumMgrPorts; j++) begin : gen_interco_mgr + if (Connectivity[i][j]) begin : gen_connected + assign mgr_reqs[j][i] = sbr_reqs[i][j]; + assign sbr_rsps[i][j] = mgr_rsps[j][i]; + end else begin : gen_err_sbr + assign mgr_reqs[j][i].req = 1'b0; + if (MgrPortObiCfg.UseRReady) begin : gen_rready + assign mgr_reqs[j][i].rready = 1'b0; + end + assign mgr_reqs[j][i].a = '0; + if (MgrPortObiCfg.Integrity) begin : gen_integrity + assign mgr_reqs[j][i].reqpar = 1'b1; + if (MgrPortObiCfg.UseRReady) begin : gen_int_rready + assign mgr_reqs[j][i].rreadypar = 1'b1; + end + end + obi_err_sbr #( + .ObiCfg ( SbrPortObiCfg ), + .obi_req_t ( sbr_port_obi_req_t ), + .obi_rsp_t ( sbr_port_obi_rsp_t ), + .NumMaxTrans ( NumMaxTrans ), + .RspData ( 32'hBADCAB1E ) + ) i_err_sbr ( + .clk_i, + .rst_ni, + .testmode_i, + .obi_req_i (sbr_reqs[i][j]), + .obi_rsp_o (sbr_rsps[i][j]) + ); + end + end + end + + for (genvar i = 0; i < NumMgrPorts; i++) begin : gen_mux + obi_mux #( + .SbrPortObiCfg ( SbrPortObiCfg ), + .MgrPortObiCfg ( MgrPortObiCfg ), + .sbr_port_obi_req_t ( sbr_port_obi_req_t ), + .sbr_port_a_chan_t ( sbr_port_a_chan_t ), + .sbr_port_obi_rsp_t ( sbr_port_obi_rsp_t ), + .sbr_port_r_chan_t ( sbr_port_r_chan_t ), + .mgr_port_obi_req_t ( mgr_port_obi_req_t ), + .mgr_port_obi_rsp_t ( mgr_port_obi_rsp_t ), + .NumSbrPorts ( NumSbrPorts ), + .NumMaxTrans ( NumMaxTrans ), + .UseIdForRouting ( UseIdForRouting ) + ) i_mux ( + .clk_i, + .rst_ni, + .testmode_i, + .sbr_ports_req_i ( mgr_reqs[i] ), + .sbr_ports_rsp_o ( mgr_rsps[i] ), + .mgr_port_req_o ( mgr_ports_req_o[i] ), + .mgr_port_rsp_i ( mgr_ports_rsp_i[i] ) + ); + end + +endmodule + +`include "obi/typedef.svh" +`include "obi/assign.svh" + +module obi_xbar_intf #( + /// The OBI configuration for the subordinate ports (input ports). + parameter obi_pkg::obi_cfg_t SbrPortObiCfg = obi_pkg::ObiDefaultConfig, + /// The OBI configuration for the manager ports (ouput ports). + parameter obi_pkg::obi_cfg_t MgrPortObiCfg = SbrPortObiCfg, + /// The number of subordinate ports (input ports). + parameter int unsigned NumSbrPorts = 32'd0, + /// The number of manager ports (output ports). + parameter int unsigned NumMgrPorts = 32'd0, + /// The maximum number of outstanding transactions. + parameter int unsigned NumMaxTrans = 32'd0, + /// The number of address rules. + parameter int unsigned NumAddrRules = 32'd0, + /// The address map rule type. + parameter type addr_map_rule_t = logic, + /// Use the extended ID field (aid & rid) to route the response + parameter bit UseIdForRouting = 1'b0, + /// Connectivity matrix to disable certain paths. + parameter bit [NumSbrPorts-1:0][NumMgrPorts-1:0] Connectivity = '1 +) ( + input logic clk_i, + input logic rst_ni, + input logic testmode_i, + + OBI_BUS.Subordinate sbr_ports [NumSbrPorts], + + OBI_BUS.Manager mgr_ports [NumMgrPorts], + + input addr_map_rule_t [NumAddrRules-1:0] addr_map_i, + input logic [NumSbrPorts-1:0] en_default_idx_i, + input logic [NumSbrPorts-1:0][$clog2(NumMgrPorts)-1:0] default_idx_i +); + + `OBI_TYPEDEF_ALL(sbr_port_obi, SbrPortObiCfg) + `OBI_TYPEDEF_ALL(mgr_port_obi, MgrPortObiCfg) + + sbr_port_obi_req_t [NumSbrPorts-1:0] sbr_ports_req; + sbr_port_obi_rsp_t [NumSbrPorts-1:0] sbr_ports_rsp; + + mgr_port_obi_req_t [NumMgrPorts-1:0] mgr_ports_req; + mgr_port_obi_rsp_t [NumMgrPorts-1:0] mgr_ports_rsp; + + for (genvar i = 0; i < NumSbrPorts; i++) begin : gen_sbr_ports_assign + `OBI_ASSIGN_TO_REQ(sbr_ports_req[i], sbr_ports[i], SbrPortObiCfg) + `OBI_ASSIGN_FROM_RSP(sbr_ports[i], sbr_ports_rsp[i], SbrPortObiCfg) + end + + for (genvar i = 0; i < NumMgrPorts; i++) begin : gen_mgr_ports_assign + `OBI_ASSIGN_FROM_REQ(mgr_ports[i], mgr_ports_req[i], MgrPortObiCfg) + `OBI_ASSIGN_TO_RSP(mgr_ports_rsp[i], mgr_ports[i], MgrPortObiCfg) + end + + obi_xbar #( + .SbrPortObiCfg ( SbrPortObiCfg ), + .MgrPortObiCfg ( MgrPortObiCfg ), + .sbr_port_obi_req_t ( sbr_port_obi_req_t ), + .sbr_port_a_chan_t ( sbr_port_obi_a_chan_t ), + .sbr_port_obi_rsp_t ( sbr_port_obi_rsp_t ), + .sbr_port_r_chan_t ( sbr_port_obi_r_chan_t ), + .mgr_port_obi_req_t ( mgr_port_obi_req_t ), + .mgr_port_obi_rsp_t ( mgr_port_obi_rsp_t ), + .NumSbrPorts ( NumSbrPorts ), + .NumMgrPorts ( NumMgrPorts ), + .NumMaxTrans ( NumMaxTrans ), + .NumAddrRules ( NumAddrRules ), + .addr_map_rule_t ( addr_map_rule_t ), + .UseIdForRouting ( UseIdForRouting ), + .Connectivity ( Connectivity ) + ) i_obi_xbar ( + .clk_i, + .rst_ni, + .testmode_i, + .sbr_ports_req_i ( sbr_ports_req ), + .sbr_ports_rsp_o ( sbr_ports_rsp ), + .mgr_ports_req_o ( mgr_ports_req ), + .mgr_ports_rsp_i ( mgr_ports_rsp ), + .addr_map_i ( addr_map_i ), + .en_default_idx_i ( en_default_idx_i ), + .default_idx_i ( default_idx_i ) + ); + +endmodule diff --git a/vendor/pulp-platform/obi/src/test/atop_golden_mem_pkg.sv b/vendor/pulp-platform/obi/src/test/atop_golden_mem_pkg.sv new file mode 100644 index 000000000..8ef1d646c --- /dev/null +++ b/vendor/pulp-platform/obi/src/test/atop_golden_mem_pkg.sv @@ -0,0 +1,245 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Author: Michael Rogenmoser + +interface OBI_ATOP_MONITOR_BUS #( + parameter int unsigned AddrWidth = 0, + parameter int unsigned DataWidth = 0, + parameter int unsigned IdWidth = 0, + parameter int unsigned UserWidth = 0 +) ( + input logic clk_i +); + + typedef logic [IdWidth-1:0] id_t; + typedef logic [AddrWidth-1:0] addr_t; + typedef logic [DataWidth-1:0] data_t; + typedef logic [DataWidth/8-1:0] be_t; + typedef logic [UserWidth-1:0] user_t; + + logic valid; + logic we; + addr_t addr; + data_t data; + be_t be; + id_t id; + user_t user; + + modport Manager (output valid, we, addr, data, be, id, user); + modport Subordinate (input valid, we, addr, data, be, id, user); + +endinterface + +package atop_golden_mem_pkg; + + class atop_golden_mem #( + parameter int unsigned ObiAddrWidth = 32, + parameter int unsigned ObiDataWidth = 32, + parameter int unsigned ObiIdWidthM = 5, + parameter int unsigned ObiIdWidthS = 8, + parameter int unsigned ObiUserWidth = 5, + parameter int unsigned NumMgrWidth = 2, + parameter time ApplDelay = 0ns, + parameter time AcqDelay = 0ns + ); + + typedef logic [ObiAddrWidth-1:0] mem_addr_t; + + static logic [7:0] memory [mem_addr_t]; + + virtual OBI_ATOP_MONITOR_BUS #( + .AddrWidth(ObiAddrWidth), + .DataWidth(ObiDataWidth), + .IdWidth (ObiIdWidthS), + .UserWidth(ObiUserWidth) + ) monitor; + + function new(virtual OBI_ATOP_MONITOR_BUS #( + .AddrWidth(ObiAddrWidth), + .DataWidth(ObiDataWidth), + .IdWidth (ObiIdWidthS), + .UserWidth(ObiUserWidth) + ) monitor + ); + this.monitor = monitor; + assert (randomize(memory)); + endfunction + + function automatic logic [ObiIdWidthS-1:0] subordinate_id(logic [ObiIdWidthM-1:0] mgr_id, + logic [NumMgrWidth-1:0] mgr_channel); + subordinate_id = '0; + if (ObiIdWidthS > ObiIdWidthM) begin + subordinate_id |= (mgr_channel) << ObiIdWidthM; + end + subordinate_id[ObiIdWidthM-1:0] = mgr_id; + endfunction + + task set_memory(logic [ObiAddrWidth-1:0] addr, logic [ObiDataWidth-1:0] data, + logic [ObiDataWidth/8-1:0] be); + #(ApplDelay); + // $display("set 0x%x at 0x%x",data, addr); + for (int i = 0; i < ObiDataWidth/8; i++) begin + if (be[i]) begin + memory[addr+i] = data[i*8+:8]; + end + end + endtask + + function logic [ObiDataWidth-1:0] get_memory(logic [ObiAddrWidth-1:0] addr); + get_memory = '0; + for (int i = 0; i < ObiDataWidth/8; i++) begin + get_memory[i*8+:8] = memory[addr+i]; + end + // $display("got 0x%x at 0x%x",get_memory, addr); + endfunction + + + + + task write( + input logic [ ObiAddrWidth-1:0] addr, + input logic [ ObiDataWidth-1:0] wdata, + input logic [ObiDataWidth/8-1:0] be, + input logic [ ObiIdWidthM-1:0] m_id, + // input logic [ ObiUserWidth-1:0] user, + input logic [ NumMgrWidth-1:0] manager = 0, + input obi_pkg::atop_t atop = '0, + output logic [ ObiDataWidth-1:0] rdata, + output logic err, + output logic exokay + ); + + automatic logic [ObiIdWidthS-1:0] res_id = subordinate_id(m_id, manager); + automatic logic unsigned [ObiDataWidth-1:0] data_ui = $unsigned(wdata); + automatic logic unsigned [ObiDataWidth-1:0] data_uo = 0; + automatic logic signed [ObiDataWidth-1:0] data_si = $signed(wdata); + automatic logic signed [ObiDataWidth-1:0] data_so = 0; + + // $display("Writing 0x%x to 0x%x and atop 0x%x", wdata, addr, atop); + + + if (atop == obi_pkg::ATOPSC) begin + + // TODO + + end else if (atop == obi_pkg::ATOPNONE) begin + + wait_write_rsp(res_id); + set_memory(addr, wdata, be); + rdata = '0; + err = '0; + exokay = '0; + + end else if (atop == obi_pkg::AMOSWAP) begin + + wait_write_rsp(res_id); + rdata = get_memory(addr); + set_memory(addr, wdata, be); + err = '0; + exokay = '0; + + end else if (atop == obi_pkg::AMOADD || atop == obi_pkg::AMOXOR || + atop == obi_pkg::AMOAND || atop == obi_pkg::AMOOR || + atop == obi_pkg::AMOMIN || atop == obi_pkg::AMOMAX || + atop == obi_pkg::AMOMINU || atop == obi_pkg::AMOMAXU ) begin + + wait_write_rsp(res_id); + + data_uo = $unsigned(get_memory(addr)); + data_so = $unsigned(get_memory(addr)); + + rdata = data_uo; + + unique case (atop) + obi_pkg::AMOADD: begin + set_memory(addr, data_uo + data_ui, be); + end + obi_pkg::AMOXOR: begin + set_memory(addr, data_uo ^ data_ui, be); + end + obi_pkg::AMOAND: begin + set_memory(addr, data_uo & data_ui, be); + end + obi_pkg::AMOOR: begin + set_memory(addr, data_uo | data_ui, be); + end + obi_pkg::AMOMIN: begin + set_memory(addr, data_so > data_si ? data_si : data_so, be); + end + obi_pkg::AMOMAX: begin + set_memory(addr, data_so > data_si ? data_so : data_si, be); + end + obi_pkg::AMOMINU: begin + set_memory(addr, data_uo > data_ui ? data_ui : data_uo, be); + end + obi_pkg::AMOMAXU: begin + set_memory(addr, data_uo > data_ui ? data_uo : data_ui, be); + end + default: begin + set_memory(addr, data_uo, be); + end + endcase + err = '0; + exokay = '0; + + end else begin + err = 1'b1; + exokay = 1'b0; + rdata = '0; + end + + endtask + + task read( + input logic [ObiAddrWidth-1:0] addr, + input logic [ ObiIdWidthM-1:0] m_id, + // input logic [ObiUserWidth-1:0] user, + input logic [ NumMgrWidth-1:0] manager = 0, + input obi_pkg::atop_t atop = '0, + output logic [ObiDataWidth-1:0] rdata, + output logic err, + output logic exokay + ); + automatic logic [ObiIdWidthS-1:0] res_id = subordinate_id(m_id, manager); + + wait_read(res_id); + rdata = get_memory(addr); + err = '0; + + if (atop == obi_pkg::ATOPLR) begin + end + + exokay = '0; + + endtask + + task wait_write_rsp( + input logic [ObiIdWidthS-1:0] id + ); + forever begin + @(posedge monitor.clk_i) + #(AcqDelay); + if (monitor.valid && monitor.we && monitor.id == id) begin + break; + end + end + endtask + + task wait_read( + input logic [ObiIdWidthS-1:0] id + ); + forever begin + @(posedge monitor.clk_i) + #(AcqDelay); + if (monitor.valid && !monitor.we && monitor.id == id) begin + break; + end + end + endtask + + + endclass + +endpackage diff --git a/vendor/pulp-platform/obi/src/test/obi_asserter.sv b/vendor/pulp-platform/obi/src/test/obi_asserter.sv new file mode 100644 index 000000000..e7fe6e01b --- /dev/null +++ b/vendor/pulp-platform/obi/src/test/obi_asserter.sv @@ -0,0 +1,42 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Authors: +// - Tobias Senti + +`include "common_cells/assertions.svh" + +/// Checks for compliance with the OBI spec !!!Not complete!!! +module obi_asserter #( + parameter type obi_req_t = logic, + parameter type obi_rsp_t = logic +) ( + input logic clk_i, + input logic rst_ni, + + input obi_req_t obi_req_i, + input obi_rsp_t obi_rsp_i +); + //R-2.1 + `ASSERT(OBIAReqLowDuringReset, !rst_ni |-> !obi_req_i.a_req, clk_i, 1'b0) + //R-2.2 + `ASSERT(OBIRValidLowDuringReset, !rst_ni |-> !obi_rsp_i.r_valid, clk_i, 1'b0) + + //R-3.1 - Stable during address phase + `ASSERT(OBIReadStableDuringAddressPhase, + ((obi_req_i.a_req && !obi_req_i.a.we && !obi_rsp_i.a_gnt) |=> + $stable({obi_req_i.a_req, obi_req_i.a.we, obi_req_i.a.addr, obi_req_i.a.be})), + clk_i, !rst_ni) + + `ASSERT(OBIWriteStableDuringAddressPhase, + ((obi_req_i.a_req && obi_req_i.a.we && !obi_rsp_i.a_gnt) |=> + $stable({obi_req_i.a_req, obi_req_i.a})), clk_i, !rst_ni) + + //R-4.1 - Stable during response phase + `ASSERT(OBIStableDuringResponsePhase, ((obi_rsp_i.r_valid && !obi_req_i.r_ready) |=> + $stable({obi_rsp_i.r_valid, obi_rsp_i.r})), clk_i, !rst_ni) + + //R-5 - Response phase should only be sent after the corresponding address phase has ended + +endmodule diff --git a/vendor/pulp-platform/obi/src/test/obi_sim_mem.sv b/vendor/pulp-platform/obi/src/test/obi_sim_mem.sv new file mode 100644 index 000000000..aec152898 --- /dev/null +++ b/vendor/pulp-platform/obi/src/test/obi_sim_mem.sv @@ -0,0 +1,201 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Author: Michael Rogenmoser + +module obi_sim_mem import obi_pkg::*; #( + parameter obi_pkg::obi_cfg_t ObiCfg = obi_pkg::ObiDefaultConfig, + parameter type obi_req_t = logic, + parameter type obi_rsp_t = logic, + parameter type obi_r_chan_t = logic, + parameter bit WarnUninitialized = 1'b0, + parameter bit ClearErrOnAccess = 1'b0, + parameter time ApplDelay = 0ps, + parameter time AcqDelay = 0ps +) ( + input logic clk_i, + input logic rst_ni, + input obi_req_t obi_req_i, + output obi_rsp_t obi_rsp_o, + + output logic mon_valid_o, + output logic mon_we_o, + output logic [ ObiCfg.AddrWidth-1:0] mon_addr_o, + output logic [ ObiCfg.DataWidth-1:0] mon_wdata_o, + output logic [ObiCfg.DataWidth/8-1:0] mon_be_o, + output logic [ ObiCfg.IdWidth-1:0] mon_id_o +); + if (ObiCfg.OptionalCfg.UseAtop) $error("Please use an ATOP resolver before sim mem."); + if (ObiCfg.Integrity) $error("Integrity not supported"); + if (ObiCfg.OptionalCfg.UseProt) $warning("Prot not checked!"); + if (ObiCfg.OptionalCfg.UseMemtype) $warning("Memtype not checked!"); + + typedef logic [ObiCfg.AddrWidth-1:0] addr_t; + + obi_r_chan_t rsp_queue[$]; + + logic [7:0] mem[addr_t]; + logic rsp_ready; + + if (ObiCfg.UseRReady) begin : gen_rready + assign rsp_ready = obi_req_i.rready; + end else begin : gen_no_rready + assign rsp_ready = 1'b1; + end + + logic mon_valid; + logic mon_we; + logic [ObiCfg.AddrWidth-1:0] mon_addr; + logic [ObiCfg.DataWidth-1:0] mon_wdata; + logic [ObiCfg.DataWidth/8-1:0] mon_be; + logic [ObiCfg.IdWidth-1:0] mon_id; + + assign mon_we = obi_req_i.a.we; + assign mon_addr = obi_req_i.a.addr; + assign mon_wdata = obi_req_i.a.wdata; + assign mon_be = obi_req_i.a.be; + assign mon_id = obi_req_i.a.aid; + + initial begin + fork + // Request Handling + forever begin + // Start cycle + @(posedge clk_i); + #(ApplDelay); + // Indicate ready + obi_rsp_o.gnt = 1'b1; + mon_valid = 1'b0; + // End of cycle + #(AcqDelay-ApplDelay); + // If requesting + if (obi_req_i.req) begin + mon_valid = 1'b1; + if (obi_req_i.a.we) begin + automatic obi_r_chan_t write_rsp; + // write memory + for (int i = 0; i < ObiCfg.DataWidth/8; i++) begin + if (obi_req_i.a.be[i]) begin + mem[obi_req_i.a.addr+i] = obi_req_i.a.wdata[8*i+:8]; + end + end + // write response + write_rsp = 'x; + write_rsp.rid = obi_req_i.a.aid; + write_rsp.err = 1'b0; + write_rsp.r_optional = '0; + rsp_queue.push_back(write_rsp); + end else begin + // read response + automatic obi_r_chan_t read_rsp = 'x; + if (!mem.exists(obi_req_i.a.addr)) begin + if (WarnUninitialized) begin + $warning("%t - Access to non-initialized address at 0x%016x by ID 0x%x.", + $realtime, obi_req_i.a.addr, obi_req_i.a.aid); + end + end else begin + for (int i = 0; i < ObiCfg.DataWidth/8; i++) begin + read_rsp.rdata[8*i+:8] = mem[obi_req_i.a.addr+i]; + end + end + read_rsp.rid = obi_req_i.a.aid; + read_rsp.err = 1'b0; + read_rsp.r_optional = '0; + rsp_queue.push_back(read_rsp); + end + end + end + // Response Handling + forever begin + // Start cycle + @(posedge clk_i); + #(ApplDelay); + obi_rsp_o.rvalid = 1'b0; + if (rsp_queue.size() != 0) begin + obi_rsp_o.r = rsp_queue[0]; + obi_rsp_o.rvalid = 1'b1; + // End of cycle + #(AcqDelay-ApplDelay); + if (rsp_ready) begin + void'(rsp_queue.pop_front()); + end + end + end + join + end + + initial begin + mon_valid_o = '0; + mon_we_o = '0; + mon_addr_o = '0; + mon_wdata_o = '0; + mon_be_o = '0; + mon_id_o = '0; + wait (rst_ni); + forever begin + @(posedge clk_i); + mon_valid_o <= #(ApplDelay) mon_valid; + mon_we_o <= #(ApplDelay) mon_we; + mon_addr_o <= #(ApplDelay) mon_addr; + mon_wdata_o <= #(ApplDelay) mon_wdata; + mon_be_o <= #(ApplDelay) mon_be; + mon_id_o <= #(ApplDelay) mon_id; + end + end +endmodule + +`include "obi/typedef.svh" +`include "obi/assign.svh" + +module obi_sim_mem_intf import obi_pkg::*; #( + parameter obi_pkg::obi_cfg_t ObiCfg = obi_pkg::ObiDefaultConfig, + parameter bit WarnUninitialized = 1'b0, + parameter bit ClearErrOnAccess = 1'b0, + parameter time ApplDelay = 0ps, + parameter time AcqDelay = 0ps +) ( + input logic clk_i, + input logic rst_ni, + OBI_BUS.Subordinate obi_sbr, + + output logic mon_valid_o, + output logic mon_we_o, + output logic [ ObiCfg.AddrWidth-1:0] mon_addr_o, + output logic [ ObiCfg.DataWidth-1:0] mon_wdata_o, + output logic [ObiCfg.DataWidth/8-1:0] mon_be_o, + output logic [ ObiCfg.IdWidth-1:0] mon_id_o +); + + `OBI_TYPEDEF_ALL(obi, ObiCfg) + + obi_req_t obi_req; + obi_rsp_t obi_rsp; + + `OBI_ASSIGN_TO_REQ(obi_req, obi_sbr, ObiCfg) + `OBI_ASSIGN_FROM_RSP(obi_sbr, obi_rsp, ObiCfg) + + obi_sim_mem #( + .ObiCfg (ObiCfg), + .obi_req_t (obi_req_t), + .obi_rsp_t (obi_rsp_t), + .obi_r_chan_t (obi_r_chan_t), + .WarnUninitialized(WarnUninitialized), + .ClearErrOnAccess (ClearErrOnAccess), + .ApplDelay (ApplDelay), + .AcqDelay (AcqDelay) + ) i_obi_sim_mem ( + .clk_i, + .rst_ni, + .obi_req_i(obi_req), + .obi_rsp_o(obi_rsp), + + .mon_valid_o, + .mon_we_o, + .mon_addr_o, + .mon_wdata_o, + .mon_be_o, + .mon_id_o + ); + +endmodule diff --git a/vendor/pulp-platform/obi/src/test/obi_test.sv b/vendor/pulp-platform/obi/src/test/obi_test.sv new file mode 100644 index 000000000..90a49efce --- /dev/null +++ b/vendor/pulp-platform/obi/src/test/obi_test.sv @@ -0,0 +1,398 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Michael Rogenmoser + +package obi_test; + import obi_pkg::*; + + class obi_driver #( + parameter obi_cfg_t ObiCfg = ObiDefaultConfig, + parameter type obi_a_optional_t = logic, + parameter type obi_r_optional_t = logic, + parameter time TA = 0ns, + parameter time TT = 0ns + ); + virtual OBI_BUS_DV #( + .OBI_CFG ( ObiCfg ), + .obi_a_optional_t ( obi_a_optional_t ), + .obi_r_optional_t ( obi_r_optional_t ) + ) obi; + + function new( + virtual OBI_BUS_DV #( + .OBI_CFG ( ObiCfg ), + .obi_a_optional_t ( obi_a_optional_t ), + .obi_r_optional_t ( obi_r_optional_t ) + ) obi + ); + this.obi = obi; + endfunction + + function void reset_manager(); + obi.req <= '0; + obi.reqpar <= '1; + obi.addr <= '0; + obi.we <= '0; + obi.be <= '0; + obi.wdata <= '0; + obi.aid <= '0; + obi.a_optional <= '0; + obi.rready <= '0; + obi.rreadypar <= '1; + endfunction + + function void reset_subordinate(); + obi.gnt <= '0; + obi.gntpar <= '1; + obi.rvalid <= '0; + obi.rvalidpar <= '1; + obi.rdata <= '0; + obi.rid <= '0; + obi.r_optional <= '0; + endfunction + + task cycle_start; + #TT; + endtask + + task cycle_end; + @(posedge obi.clk_i); + endtask + + task send_a ( + input logic [ ObiCfg.AddrWidth-1:0] addr, + input logic we, + input logic [ObiCfg.DataWidth/8-1:0] be, + input logic [ ObiCfg.DataWidth-1:0] wdata, + input logic [ ObiCfg.IdWidth-1:0] aid, + input obi_a_optional_t a_optional + ); + obi.req <= #TA 1'b1; + obi.reqpar <= #TA 1'b0; + obi.addr <= #TA addr; + obi.we <= #TA we; + obi.be <= #TA be; + obi.wdata <= #TA wdata; + obi.aid <= #TA aid; + obi.a_optional <= #TA a_optional; + cycle_start(); + while (obi.gnt != 1'b1) begin cycle_end(); cycle_start(); end + cycle_end(); + obi.req <= #TA 1'b0; + obi.reqpar <= #TA 1'b1; + obi.addr <= #TA '0; + obi.we <= #TA '0; + obi.be <= #TA '0; + obi.wdata <= #TA '0; + obi.aid <= #TA '0; + obi.a_optional <= #TA '0; + endtask + + task send_r ( + input logic [ObiCfg.DataWidth-1:0] rdata, + input logic [ ObiCfg.IdWidth-1:0] rid, + input obi_r_optional_t r_optional + ); + obi.rvalid <= #TA 1'b1; + obi.rvalidpar <= #TA 1'b0; + obi.rdata <= #TA rdata; + obi.rid <= #TA rid; + obi.r_optional <= #TA r_optional; + cycle_start(); + if (ObiCfg.UseRReady) begin + while (obi.rready != 1'b1) begin cycle_end(); cycle_start(); end + end + cycle_end(); + obi.rvalid <= #TA 1'b0; + obi.rvalidpar <= #TA 1'b1; + obi.rdata <= #TA '0; + obi.rid <= #TA '0; + obi.r_optional <= #TA '0; + endtask + + task recv_a ( + output logic [ ObiCfg.AddrWidth-1:0] addr, + output logic we, + output logic [ObiCfg.DataWidth/8-1:0] be, + output logic [ ObiCfg.DataWidth-1:0] wdata, + output logic [ ObiCfg.IdWidth-1:0] aid, + output obi_a_optional_t a_optional + ); + obi.gnt <= #TA 1'b1; + obi.gntpar <= #TA 1'b0; + cycle_start(); + while (obi.req != 1'b1) begin cycle_end(); cycle_start(); end + addr = obi.addr; + we = obi.we; + be = obi.be; + wdata = obi.wdata; + aid = obi.aid; + a_optional = obi.a_optional; + cycle_end(); + obi.gnt <= #TA 1'b0; + obi.gntpar <= #TA 1'b1; + endtask + + task recv_r ( + output logic [ObiCfg.DataWidth-1:0] rdata, + output logic [ ObiCfg.IdWidth-1:0] rid, + output logic err, + output obi_r_optional_t r_optional + ); + obi.rready <= #TA 1'b1; + obi.rreadypar <= #TA 1'b0; + cycle_start(); + while (obi.rvalid != 1'b1) begin cycle_end(); cycle_start(); end + rdata = obi.rdata; + rid = obi.rid; + err = obi.err; + r_optional = obi.r_optional; + cycle_end(); + if (ObiCfg.UseRReady) begin + obi.rready <= #TA 1'b0; + obi.rreadypar <= #TA 1'b1; + end + endtask + + endclass + + class obi_rand_manager #( + // Obi Parameters + parameter obi_cfg_t ObiCfg = ObiDefaultConfig, + parameter type obi_a_optional_t = logic, + parameter type obi_r_optional_t = logic, + // Stimuli Parameters + parameter time TA = 2ns, + parameter time TT = 8ns, + // Manager Parameters + parameter int unsigned MinAddr = 32'h0000_0000, + parameter int unsigned MaxAddr = 32'hffff_ffff, + // Wait Parameters + parameter int unsigned AMinWaitCycles = 0, + parameter int unsigned AMaxWaitCycles = 100, + parameter int unsigned RMinWaitCycles = 0, + parameter int unsigned RMaxWaitCycles = 100 + ); + typedef obi_test::obi_driver #( + .ObiCfg ( ObiCfg ), + .obi_a_optional_t ( obi_a_optional_t ), + .obi_r_optional_t ( obi_r_optional_t ), + .TA ( TA ), + .TT ( TT ) + ) obi_driver_t; + + typedef logic [ObiCfg.AddrWidth-1:0] addr_t; + + string name; + obi_driver_t drv; + addr_t a_queue[$]; + logic r_queue[$]; + + function new( + virtual OBI_BUS_DV #( + .OBI_CFG ( ObiCfg ), + .obi_a_optional_t ( obi_a_optional_t ), + .obi_r_optional_t ( obi_r_optional_t ) + ) obi, + input string name + ); + this.drv = new(obi); + this.name = name; + assert(ObiCfg.AddrWidth != 0) else $fatal(1, "ObiCfg.AddrWidth must be non-zero!"); + assert(ObiCfg.DataWidth != 0) else $fatal(1, "ObiCfg.DataWidth must be non-zero!"); + endfunction + + function void reset(); + drv.reset_manager(); + endfunction + + task automatic rand_wait(input int unsigned min, input int unsigned max); + int unsigned rand_success, cycles; + rand_success = std::randomize(cycles) with { + cycles >= min; + cycles <= max; + }; + assert (rand_success) else $error("Failed to randomize wait cycles!"); + repeat (cycles) @(posedge this.drv.obi.clk_i); + endtask + + task automatic send_as(input int unsigned n_reqs); + automatic addr_t a_addr; + automatic logic a_we; + automatic logic [ObiCfg.DataWidth/8-1:0] a_be; + automatic logic [ ObiCfg.DataWidth-1:0] a_wdata; + automatic logic [ ObiCfg.IdWidth-1:0] a_aid; + automatic obi_a_optional_t a_optional; + + repeat (n_reqs) begin + rand_wait(AMinWaitCycles, AMaxWaitCycles); + + a_addr = addr_t'($urandom_range(MinAddr, MaxAddr)); + a_we = $urandom() % 2; + a_be = $urandom() % (1 << (ObiCfg.DataWidth/8)); + a_wdata = $urandom() % (1 << ObiCfg.DataWidth); + a_aid = $urandom() % (1 << ObiCfg.IdWidth); + a_optional = obi_a_optional_t'($urandom()); + + this.a_queue.push_back(a_addr); + this.drv.send_a(a_addr, a_we, a_be, a_wdata, a_aid, a_optional); + end + endtask + + task automatic recv_rs(input int unsigned n_rsps); + automatic addr_t a_addr; + automatic logic [ObiCfg.DataWidth-1:0] r_rdata; + automatic logic [ ObiCfg.IdWidth-1:0] r_rid; + automatic logic r_err; + automatic obi_r_optional_t r_optional; + repeat (n_rsps) begin + wait (a_queue.size() > 0); + a_addr = this.a_queue.pop_front(); + rand_wait(RMinWaitCycles, RMaxWaitCycles); + drv.recv_r(r_rdata, r_rid, r_err, r_optional); + end + endtask + + task automatic run(int unsigned n_reqs); + $display("Run for Reqs: %0d", n_reqs); + fork + this.send_as(n_reqs); + this.recv_rs(n_reqs); + join + endtask + + task automatic write( + input addr_t addr, + input logic [ObiCfg.DataWidth/8-1:0] be, + input logic [ ObiCfg.DataWidth-1:0] wdata, + input logic [ ObiCfg.IdWidth-1:0] aid, + input obi_a_optional_t a_optional, + output logic [ ObiCfg.DataWidth-1:0] r_rdata, + output logic [ ObiCfg.IdWidth-1:0] r_rid, + output logic r_err, + output obi_r_optional_t r_optional + ); + this.drv.send_a(addr, 1'b1, be, wdata, aid, a_optional); + this.drv.recv_r(r_rdata, r_rid, r_err, r_optional); + endtask + + task automatic read( + input addr_t addr, + input logic [ ObiCfg.IdWidth-1:0] aid, + input obi_a_optional_t a_optional, + output logic [ObiCfg.DataWidth-1:0] r_rdata, + output logic [ ObiCfg.IdWidth-1:0] r_rid, + output logic r_err, + output obi_r_optional_t r_optional + ); + this.drv.send_a(addr, 1'b0, '1, '0, aid, a_optional); + this.drv.recv_r(r_rdata, r_rid, r_err, r_optional); + endtask + + endclass + + class obi_rand_subordinate #( + // Obi Parameters + parameter obi_cfg_t ObiCfg = ObiDefaultConfig, + parameter type obi_a_optional_t = logic, + parameter type obi_r_optional_t = logic, + // Stimuli Parameters + parameter time TA = 2ns, + parameter time TT = 8ns, + // Wait Parameters + parameter int unsigned AMinWaitCycles = 0, + parameter int unsigned AMaxWaitCycles = 100, + parameter int unsigned RMinWaitCycles = 0, + parameter int unsigned RMaxWaitCycles = 100 + ); + typedef obi_test::obi_driver #( + .ObiCfg ( ObiCfg ), + .obi_a_optional_t ( obi_a_optional_t ), + .obi_r_optional_t ( obi_r_optional_t ), + .TA ( TA ), + .TT ( TT ) + ) obi_driver_t; + + typedef logic [ObiCfg.AddrWidth-1:0] addr_t; + typedef logic [ ObiCfg.IdWidth-1:0] id_t; + + string name; + obi_driver_t drv; + addr_t a_queue[$]; + id_t id_queue[$]; + logic r_queue[$]; + + function new( + virtual OBI_BUS_DV #( + .OBI_CFG ( ObiCfg ), + .obi_a_optional_t ( obi_a_optional_t ), + .obi_r_optional_t ( obi_r_optional_t ) + ) obi, + input string name + ); + this.drv = new(obi); + this.name = name; + assert(ObiCfg.AddrWidth != 0) else $fatal(1, "ObiCfg.AddrWidth must be non-zero!"); + assert(ObiCfg.DataWidth != 0) else $fatal(1, "ObiCfg.DataWidth must be non-zero!"); + endfunction + + function void reset(); + drv.reset_subordinate(); + endfunction + + task automatic rand_wait(input int unsigned min, input int unsigned max); + int unsigned rand_success, cycles; + rand_success = std::randomize(cycles) with { + cycles >= min; + cycles <= max; + }; + assert (rand_success) else $error("Failed to randomize wait cycles!"); + repeat (cycles) @(posedge this.drv.obi.clk_i); + endtask + + task automatic recv_as(); + forever begin + automatic addr_t a_addr; + automatic logic [ObiCfg.DataWidth/8-1:0] a_be; + automatic logic a_we; + automatic logic [ ObiCfg.DataWidth-1:0] a_wdata; + automatic logic [ ObiCfg.IdWidth-1:0] a_aid; + automatic obi_a_optional_t a_optional; + + this.drv.recv_a(a_addr, a_we, a_be, a_wdata, a_aid, a_optional); + this.a_queue.push_back(a_addr); + this.id_queue.push_back(a_aid); + end + endtask + + task automatic send_rs(); + forever begin + automatic logic rand_success; + automatic addr_t a_addr; + automatic logic [ObiCfg.DataWidth-1:0] r_rdata; + automatic logic [ ObiCfg.IdWidth-1:0] r_rid; + automatic obi_r_optional_t r_optional; + + wait (a_queue.size() > 0); + wait (id_queue.size() > 0); + + a_addr = this.a_queue.pop_front(); + r_rid = this.id_queue.pop_front(); + rand_success = std::randomize(r_rdata); assert(rand_success); + rand_success = std::randomize(r_optional); assert(rand_success); + this.drv.send_r(r_rdata, r_rid, r_optional); + end + endtask + + task automatic run(); + fork + recv_as(); + send_rs(); + join + endtask + + endclass + +endpackage diff --git a/vendor/pulp-platform/obi/src/test/tb_obi_atop_resolver.sv b/vendor/pulp-platform/obi/src/test/tb_obi_atop_resolver.sv new file mode 100644 index 000000000..3d56b3339 --- /dev/null +++ b/vendor/pulp-platform/obi/src/test/tb_obi_atop_resolver.sv @@ -0,0 +1,706 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Author: Samuel Riedel +// Author: Michael Rogenmoser + +`include "obi/typedef.svh" +`include "obi/assign.svh" + +module tb_obi_atop_resolver; + import obi_pkg::*; + + localparam int unsigned MaxTimeout = 10000; + + localparam int unsigned NumManagers = 32'd10; + localparam int unsigned NumMaxTrans = 32'd8; + localparam int unsigned AddrWidth = 32; + localparam int unsigned DataWidth = 32; + localparam int unsigned MgrIdWidth = 5; + localparam int unsigned SbrIdWidth = MgrIdWidth+$clog2(NumManagers); + localparam int unsigned AUserWidth = 4; + localparam int unsigned WUserWidth = 2; + localparam int unsigned RUserWidth = 3; + + localparam time CyclTime = 10ns; + localparam time ApplTime = 2ns; + localparam time TestTime = 8ns; + + localparam obi_pkg::obi_cfg_t MgrConfig = '{ + UseRReady: 1'b0, + CombGnt: 1'b0, + AddrWidth: AddrWidth, + DataWidth: DataWidth, + IdWidth: MgrIdWidth, + Integrity: 1'b0, + BeFull: 1'b1, + OptionalCfg: '{ + UseAtop: 1'b1, + UseMemtype: 1'b0, + UseProt: 1'b0, + UseDbg: 1'b0, + AUserWidth: AUserWidth, + WUserWidth: WUserWidth, + RUserWidth: RUserWidth, + MidWidth: 0, + AChkWidth: 0, + RChkWidth: 0 + } + }; + `OBI_TYPEDEF_ALL_A_OPTIONAL(mgr_a_optional_t, AUserWidth, WUserWidth, 0, 0) + `OBI_TYPEDEF_ALL_R_OPTIONAL(mgr_r_optional_t, RUserWidth, 0) + typedef obi_test::obi_rand_manager #( + .ObiCfg ( MgrConfig ), + .obi_a_optional_t ( mgr_a_optional_t ), + .obi_r_optional_t ( mgr_r_optional_t ), + .TA ( ApplTime ), + .TT ( TestTime ), + .MinAddr (32'h0000_0000), + .MaxAddr (32'h0001_3000) + ) rand_manager_t; + + localparam obi_pkg::obi_cfg_t MgrMuxedConfig = '{ + UseRReady: 1'b0, + CombGnt: 1'b0, + AddrWidth: AddrWidth, + DataWidth: DataWidth, + IdWidth: SbrIdWidth, + Integrity: 1'b0, + BeFull: 1'b1, + OptionalCfg: '{ + UseAtop: 1'b1, + UseMemtype: 1'b0, + UseProt: 1'b0, + UseDbg: 1'b0, + AUserWidth: AUserWidth, + WUserWidth: WUserWidth, + RUserWidth: RUserWidth, + MidWidth: 0, + AChkWidth: 0, + RChkWidth: 0 + } + }; + + + localparam obi_pkg::obi_cfg_t SbrConfig = '{ + UseRReady: 1'b0, + CombGnt: 1'b0, + AddrWidth: AddrWidth, + DataWidth: DataWidth, + IdWidth: SbrIdWidth, + Integrity: 1'b0, + BeFull: 1'b1, + OptionalCfg: '{ + UseAtop: 1'b0, + UseMemtype: 1'b0, + UseProt: 1'b0, + UseDbg: 1'b0, + AUserWidth: AUserWidth, + WUserWidth: WUserWidth, + RUserWidth: RUserWidth, + MidWidth: 0, + AChkWidth: 0, + RChkWidth: 0 + } + }; + `OBI_TYPEDEF_ALL_A_OPTIONAL(sbr_a_optional_t, AUserWidth, WUserWidth, 0, 0) + `OBI_TYPEDEF_ALL_R_OPTIONAL(sbr_r_optional_t, RUserWidth, 0) + + logic clk, rst_n; + logic [NumManagers-1:0] end_of_sim; + int unsigned num_errors = 0; + + OBI_BUS_DV #( + .OBI_CFG ( MgrConfig ), + .obi_a_optional_t ( mgr_a_optional_t ), + .obi_r_optional_t ( mgr_r_optional_t ) + ) mgr_bus_dv [NumManagers] ( + .clk_i ( clk ), + .rst_ni ( rst_n ) + ); + OBI_BUS #( + .OBI_CFG ( MgrConfig ), + .obi_a_optional_t ( mgr_a_optional_t ), + .obi_r_optional_t ( mgr_r_optional_t ) + ) mgr_bus [NumManagers] (); + + OBI_BUS #( + .OBI_CFG ( MgrMuxedConfig ), + .obi_a_optional_t ( mgr_a_optional_t ), + .obi_r_optional_t ( mgr_r_optional_t ) + ) mgr_bus_muxed (); + + rand_manager_t obi_rand_managers[NumManagers]; + + for (genvar i = 0; i < NumManagers; i++) begin : gen_mgr_drivers + initial begin + obi_rand_managers[i] = new ( mgr_bus_dv[i], $sformatf("MGR_%0d",i)); + end_of_sim[i] <= 1'b0; + obi_rand_managers[i].reset(); + + end + + `OBI_ASSIGN(mgr_bus[i], mgr_bus_dv[i], MgrConfig, MgrConfig) + end + + OBI_BUS #( + .OBI_CFG ( SbrConfig ), + .obi_a_optional_t ( sbr_a_optional_t ), + .obi_r_optional_t ( sbr_r_optional_t ) + ) sbr_bus (); + + OBI_ATOP_MONITOR_BUS #( + .DataWidth ( DataWidth ), + .AddrWidth ( AddrWidth ), + .IdWidth ( SbrIdWidth ), + .UserWidth ( AUserWidth ) + ) mem_monitor_dv ( + .clk_i ( clk ) + ); + + clk_rst_gen #( + .ClkPeriod ( CyclTime ), + .RstClkCycles ( 5 ) + ) i_clk_gen ( + .clk_o ( clk ), + .rst_no ( rst_n ) + ); + + obi_mux_intf #( + .SbrPortObiCfg ( MgrConfig ), + .MgrPortObiCfg ( MgrMuxedConfig ), + .NumSbrPorts ( NumManagers ), + .NumMaxTrans ( 2 ), + .UseIdForRouting ( 1'b0 ) + ) i_obi_mux ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .testmode_i ( 1'b0 ), + .sbr_ports ( mgr_bus ), + .mgr_port ( mgr_bus_muxed ) + ); + + obi_atop_resolver_intf #( + .SbrPortObiCfg ( MgrMuxedConfig ), + .MgrPortObiCfg ( SbrConfig ), + .LrScEnable ( 1 ), + .RegisterAmo ( 1'b0 ) + ) i_atop_resolver ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .testmode_i ( '0 ), + .sbr_port ( mgr_bus_muxed ), + .mgr_port ( sbr_bus ) + ); + + obi_sim_mem_intf #( + .ObiCfg ( SbrConfig ), + .ClearErrOnAccess ( 1'b0 ), + .WarnUninitialized ( 1'b0 ), + .ApplDelay ( ApplTime ), + .AcqDelay ( TestTime ) + ) i_sim_mem ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .obi_sbr ( sbr_bus ), + .mon_valid_o ( mem_monitor_dv.valid ), + .mon_we_o ( mem_monitor_dv.we ), + .mon_addr_o ( mem_monitor_dv.addr ), + .mon_wdata_o ( mem_monitor_dv.data ), + .mon_be_o ( mem_monitor_dv.be ), + .mon_id_o ( mem_monitor_dv.id ) + ); + + atop_golden_mem_pkg::atop_golden_mem #( + .ObiAddrWidth ( AddrWidth ), + .ObiDataWidth ( DataWidth ), + .ObiIdWidthM ( MgrIdWidth ), + .ObiIdWidthS ( SbrIdWidth ), + .ObiUserWidth ( AUserWidth ), + .NumMgrWidth ( $clog2(NumManagers) ), + .ApplDelay ( ApplTime ), + .AcqDelay ( TestTime ) + ) golden_memory = new(mem_monitor_dv); + assign mem_monitor_dv.user = '0; + + /*==================================================================== + = Main = + ====================================================================*/ + + initial begin + wait (rst_n); + @(posedge clk); + + // Run tests! + test_all_amos(); + test_same_address(); + test_amo_write_consistency(); + // // test_interleaving(); + test_atomic_counter(); + // random_amo(); + // overtake_r(); + test_lr_sc(); + + end_of_sim <= '1; + end + + /*==================================================================== + = Timeout = + ====================================================================*/ + + initial begin + automatic int unsigned timeout = 0; + automatic logic [1:0] handshake = 2'b00; + + @(posedge clk); + wait (rst_n); + + fork + while (timeout < MaxTimeout) begin + handshake = {sbr_bus.req, sbr_bus.gnt}; + @(posedge clk); + if (handshake != {sbr_bus.req, sbr_bus.gnt}) begin + timeout = 0; + end else begin + timeout += 1; + end + end + wait (&end_of_sim); + join_any + + if (&end_of_sim && num_errors == 0) begin + $display("\nSUCCESS\n"); + end else if (&end_of_sim) begin + $display("\nFINISHED\n"); + if (num_errors > 0) begin + $fatal(1, "Encountered %d errors.", num_errors); + end else begin + $display("All tests passed."); + end + end else begin + $fatal(1, "TIMEOUT"); + end + + $stop; + end + + /*==================================================================== + = Hand crafted tests = + ====================================================================*/ + + task automatic test_all_amos(); + + automatic logic [AddrWidth-1:0] address; + automatic logic [DataWidth-1:0] data_init; + automatic logic [DataWidth-1:0] data_amo; + automatic atop_t atop; + + $display("%t - Test all possible amos with a single thread...\n", $realtime); + + for (int j = 0; j < 9; j++) begin + // Go through standard AMOs + if (j == 0) atop = AMOSWAP; + if (j == 1) atop = AMOADD; + if (j == 2) atop = AMOXOR; + if (j == 3) atop = AMOAND; + if (j == 4) atop = AMOOR; + if (j == 5) atop = AMOMIN; + if (j == 6) atop = AMOMAX; + if (j == 7) atop = AMOMINU; + if (j == 8) atop = AMOMAXU; + + assert (randomize(address)); + assert (randomize(data_init)); + assert (randomize(data_amo)); + + write_amo_read_cycle(0, address, data_init, data_amo, 0, 0, atop); + + end + + endtask + + // Test if the adapter protects the atomic region correctly + task automatic test_same_address(); + parameter int unsigned NumIterations = 64; + parameter logic [AddrWidth-1:0] Address = 'h01004000; + + automatic logic [ AddrWidth-1:0] address = Address; + automatic logic [ DataWidth-1:0] rdata_init; + automatic logic [MgrIdWidth-1:0] rid_init; + automatic logic err_init; + automatic mgr_r_optional_t r_optional_init; + automatic logic [ DataWidth-1:0] exp_data_init; + automatic logic exp_err_init; + automatic logic exp_exokay_init; + + $display("%t - Test random accesses to the same memory location...\n", $realtime); + + // Initialize memory with 0 + fork + obi_rand_managers[0].write(address, '1, '0, '0, '0, rdata_init, rid_init, err_init, + r_optional_init); + golden_memory.write(address, '0, '1, '0, 0, '0, exp_data_init, exp_err_init, + exp_exokay_init); + join + + for (int i = 0; i < NumManagers; i++) begin + automatic int m = i; + automatic logic [MgrIdWidth-1:0] id; + automatic logic [SbrIdWidth-1:0] s_id; + automatic logic [ DataWidth-1:0] wdata; + automatic mgr_a_optional_t a_optional; + automatic logic [ DataWidth-1:0] rdata; + automatic logic [ DataWidth-1:0] exp_data; + automatic logic [MgrIdWidth-1:0] rid; + automatic logic [MgrIdWidth-1:0] exp_rid; + automatic logic err; + automatic logic exp_err; + automatic mgr_r_optional_t r_optional; + automatic logic exp_exokay; + automatic atop_t atop; + + fork + for (int j = 0; j < NumIterations; j++) begin + assert (randomize(id)); + assert (randomize(wdata)); + do begin + assert (randomize(atop)); + end while (!(obi_atop_e'(atop) inside {AMOSWAP, AMOADD, AMOXOR, AMOAND, AMOOR, AMOMIN, + AMOMAX, AMOMINU, AMOMAXU, ATOPNONE})); + a_optional.atop = atop; + fork + obi_rand_managers[m].write(address, '1, wdata, id, a_optional, rdata, rid, err, + r_optional); + golden_memory.write(address, wdata, '1, id, m, atop, exp_data, exp_err, exp_exokay); + join + assert (err == exp_err && r_optional.exokay == exp_exokay) else begin + $warning("%t - Response codes did not match! got: 0x%b, exp: 0x%b", $realtime, + {err, r_optional.exokay}, {exp_err, exp_exokay}); + num_errors += 1; + end + if (atop != ATOPNONE) begin + assert (rdata == exp_data) else begin + $warning("%t - ATOP data did not match! got: 0x%x, exp: 0x%x with op 0x%x", + $realtime, rdata, exp_data, atop); + num_errors += 1; + end + end + end + join_none + end + + wait fork; + + #1000ns; + + endtask + + // Test if the adapter protects the atomic region correctly + task automatic test_amo_write_consistency(); + parameter int unsigned NumIterations = 64; + parameter logic [AddrWidth-1:0] Address = 'h01004000; + + automatic logic [ AddrWidth-1:0] address = Address; + + $display("%t - Test write consistency...\n", $realtime); + + // Initialize to 0 + write_amo_read_cycle(0, address, '0, '0, '0, 0, '0); + + for (int i = 0; i < NumManagers; i++) begin + automatic int m = i; + automatic logic [MgrIdWidth-1:0] id; + automatic logic [ DataWidth-1:0] data; + automatic logic [ DataWidth-1:0] data_amo; + automatic atop_t atop; + + fork + for (int j = 0; j < NumIterations; j++) begin + do begin + assert (randomize(atop)); + end while (!(obi_atop_e'(atop) inside {AMOSWAP, AMOADD, AMOXOR, AMOAND, AMOOR, AMOMIN, + AMOMAX, AMOMINU, AMOMAXU, ATOPNONE})); + assert (randomize(data)); + assert (randomize(data_amo)); + assert (randomize(id)); + + write_amo_read_cycle(m, address, data, data_amo, id, 0, atop); + end + join_none + end + + wait fork; + + + endtask + + // Test multiple atomic accesses to the same address + task automatic test_atomic_counter(); + parameter int unsigned NumIterations = 64; + parameter logic [AddrWidth-1:0] Address = 'h01002000; + + automatic logic [ AddrWidth-1:0] address = Address; + automatic logic [ DataWidth-1:0] rdata; + automatic logic [MgrIdWidth-1:0] rid; + automatic logic err; + automatic mgr_r_optional_t r_optional; + + $display("%t - Test atomic counter...\n", $realtime); + + // Initialize to 0 + obi_rand_managers[0].write(address, '1, '0, '0, '0, rdata, rid, err, r_optional); + + for (int i = 0; i < NumManagers; i++) begin + automatic int m = i; + fork + for (int j = 0; j < NumIterations; j++) begin + obi_rand_managers[m].write(address, '1, 1, '0, '{atop: AMOADD, default: '0}, rdata, rid, + err, r_optional); + end + join_none + end + + wait fork; + + obi_rand_managers[0].read(address, '0, '0, rdata, rid, err, r_optional); + + if (rdata == NumIterations*NumManagers) begin + $display("%t - Adder result correct: %d", $realtime, rdata); + end else begin + $display("%t - Adder result wrong: %d (Expected: %d)", $realtime, rdata, + NumIterations*NumManagers); + num_errors += 1; + end + + endtask + + // Test LR/SC accesses + task automatic test_lr_sc(); + automatic logic [ AddrWidth-1:0] address; + automatic logic [ AddrWidth-1:0] address_2; + automatic logic [ DataWidth-1:0] data; + automatic logic [ DataWidth-1:0] data_2; + automatic logic [MgrIdWidth-1:0] trans_id; + automatic mgr_a_optional_t a_optional = '0; + automatic logic [ DataWidth-1:0] rdata; + automatic logic [MgrIdWidth-1:0] rid; + automatic logic err; + automatic mgr_r_optional_t r_optional; + + $display("%t - Test LR/SC...\n", $realtime); + + // SC without acquiring lock -> !exokay + /////////////////////////////////////// + assert (randomize(address)); + address[$clog2(DataWidth/8)-1:0] = '0; + assert (randomize(data)); + assert (randomize(trans_id)); + // Initialize address + obi_rand_managers[0].write(address, '1, '0, trans_id, a_optional, rdata, rid, err, r_optional); + + a_optional.atop = ATOPSC; + obi_rand_managers[0].write(address, '1, data, trans_id, a_optional, rdata, rid, err, + r_optional); + + assert (r_optional.exokay == 1'b0 && rdata != '0) else begin + $warning("%t - SC without LR returned exokay", $realtime); + num_errors += 1; + end + + // Ensure SC did not store + a_optional.atop = ATOPNONE; + obi_rand_managers[0].read(address, trans_id, a_optional, rdata, rid, err, r_optional); + assert (rdata == '0 && rdata != data) else begin + $warning("%t - SC without LR stored data 0x%x", $realtime, rdata); + num_errors += 1; + end + + // LR/SC sequence -> exokay + /////////////////////////// + assert (randomize(address)); + address[$clog2(DataWidth/8)-1:0] = '0; + assert (randomize(trans_id)); + // Initialize address + obi_rand_managers[0].write(address, '1, '0, trans_id, a_optional, rdata, rid, err, r_optional); + + a_optional.atop = ATOPLR; + obi_rand_managers[0].read(address, trans_id, a_optional, rdata, rid, err, r_optional); + + assert (r_optional.exokay == 1'b1) else begin + $warning("%t - LR did not return exokay", $realtime); + num_errors += 1; + end + + assert (randomize(data)); + a_optional.atop = ATOPSC; + obi_rand_managers[0].write(address, '1, data, trans_id, a_optional, rdata, rid, err, + r_optional); + + assert (r_optional.exokay == 1'b1) else begin + $warning("%t - SC with LR did not return exokay", $realtime); + num_errors += 1; + end + + // Ensure SC did store + a_optional.atop = ATOPNONE; + obi_rand_managers[0].read(address, trans_id, a_optional, rdata, rid, err, r_optional); + assert (rdata == data) else begin + $warning("%t - SC with LR did not store data", $realtime); + num_errors += 1; + end + + // LR then different SC -> !exokay + ////////////////////////////////// + assert (randomize(address)); + address[$clog2(DataWidth/8)-1:0] = '0; + assert (randomize(trans_id)); + // Initialize address + obi_rand_managers[0].write(address, '1, '0, trans_id, a_optional, rdata, rid, err, r_optional); + + a_optional.atop = ATOPLR; + obi_rand_managers[0].read(address, trans_id, a_optional, rdata, rid, err, r_optional); + + assert (r_optional.exokay == 1'b1) else begin + $warning("%t - LR did not return exokay", $realtime); + num_errors += 1; + end + + do begin + assert (randomize(address_2)); + address_2[$clog2(DataWidth/8)-1:0] = '0; + end while (address_2 == address); + assert (randomize(data)); + a_optional.atop = ATOPSC; + obi_rand_managers[0].write(address_2, '1, data, trans_id, a_optional, rdata, rid, err, + r_optional); + + assert (r_optional.exokay == 1'b0) else begin + $warning("%t - SC with LR to different address returned exokay", $realtime); + num_errors += 1; + end + + // LR, other core store, SC -> !exokay + ////////////////////////////////////// + assert (randomize(address)); + address[$clog2(DataWidth/8)-1:0] = '0; + assert (randomize(trans_id)); + // Initialize address + obi_rand_managers[0].write(address, '1, '0, trans_id, a_optional, rdata, rid, err, r_optional); + + a_optional.atop = ATOPLR; + obi_rand_managers[0].read(address, trans_id, a_optional, rdata, rid, err, r_optional); + + assert (r_optional.exokay == 1'b1) else begin + $warning("%t - LR did not return exokay", $realtime); + num_errors += 1; + end + + assert (randomize(data)); + a_optional.atop = ATOPNONE; + obi_rand_managers[1].write(address, '1, data, trans_id, a_optional, rdata, rid, err, + r_optional); + + assert (randomize(data_2)); + a_optional.atop = ATOPSC; + obi_rand_managers[0].write(address, '1, data_2, trans_id, a_optional, rdata, rid, err, + r_optional); + + assert (r_optional.exokay == 1'b0) else begin + $warning("%t - SC with LR and injected store returned exokay", $realtime); + num_errors += 1; + end + + // Ensure SC did not store + a_optional.atop = ATOPNONE; + obi_rand_managers[0].read(address, trans_id, a_optional, rdata, rid, err, r_optional); + assert (rdata == data && rdata != data_2) else begin + $warning("%t - SC without LR stored data (stored: 0x%x, SC: 0x%x, rdata: 0x%x)", $realtime, + data, data_2, rdata); + num_errors += 1; + end + + endtask + + + /*==================================================================== + = Helper Functions = + ====================================================================*/ + + task automatic write_amo_read_cycle( + input int unsigned driver, + input logic [ AddrWidth-1:0] address, + input logic [ DataWidth-1:0] data_init, + input logic [ DataWidth-1:0] data_amo, + input logic [MgrIdWidth-1:0] id, + input logic [AUserWidth-1:0] user, + input atop_t atop + ); + + automatic logic [MgrIdWidth-1:0] trans_id = id; + automatic logic [ DataWidth-1:0] rdata; + automatic logic [ DataWidth-1:0] exp_data; + automatic logic [ DataWidth-1:0] act_data; + automatic logic err; + automatic logic exokay; + automatic logic exp_err; + automatic logic exp_exokay; + automatic logic [MgrIdWidth-1:0] rid; + automatic mgr_a_optional_t a_optional = '0; + automatic mgr_r_optional_t r_optional; + + a_optional.atop = '0; + exokay = r_optional.exokay; + + if (!id) begin + assert (randomize(trans_id)); + end + // Preload data + fork + obi_rand_managers[driver].write(address, '1, data_init, trans_id, a_optional, rdata, rid, + err, r_optional); + golden_memory.write(address, data_init, '1, trans_id, driver, '0, exp_data, exp_err, + exp_exokay); + join + if (!id) begin + assert (randomize(trans_id)); + end + // Execute AMO + a_optional.atop = atop; + fork + obi_rand_managers[driver].write(address, '1, data_amo, trans_id, a_optional, rdata, rid, err, + r_optional); + golden_memory.write(address, data_amo, '1, trans_id, driver, atop, exp_data, exp_err, + exp_exokay); + join + exokay = r_optional.exokay; + assert (err == exp_err && exokay == exp_exokay) else begin + $warning("%t - Response codes did not match! got: 0x%b, exp: 0x%b", $realtime, {err, exokay}, + {exp_err, exp_exokay}); + num_errors += 1; + end + if (atop != '0) begin + assert (rdata == exp_data) else begin + $warning("%t - ATOP data did not match! got: 0x%x, exp: 0x%x at addr: 0x%x with op 0x%x", + $realtime, rdata, exp_data, address, atop); + num_errors += 1; + end + end + if (!id) begin + assert (randomize(trans_id)); + end + // Check stored data + a_optional.atop = '0; + fork + obi_rand_managers[driver].read(address, trans_id, a_optional, act_data, rid, err, r_optional); + golden_memory.read(address, trans_id, driver, '0, exp_data, exp_err, exp_exokay); + join + assert(act_data == exp_data) else begin + $warning("%t - Stored data did not match! got: 0x%x, exp: 0x%x at addr: 0x%x with op 0x%x", + $realtime, act_data, exp_data, address, atop); + num_errors += 1; + end + + endtask + +endmodule diff --git a/vendor/pulp-platform/obi/src/test/tb_obi_xbar.sv b/vendor/pulp-platform/obi/src/test/tb_obi_xbar.sv new file mode 100644 index 000000000..7f0b81f4c --- /dev/null +++ b/vendor/pulp-platform/obi/src/test/tb_obi_xbar.sv @@ -0,0 +1,229 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Michael Rogenmoser + +`include "obi/typedef.svh" +`include "obi/assign.svh" + +module tb_obi_xbar; + + localparam int unsigned NumManagers = 32'd6; + localparam int unsigned NumSubordinates = 32'd8; + localparam bit UseIdForRouting = 1'b0; + + localparam int unsigned NumMaxTrans = 32'd8; + localparam int unsigned AddrWidth = 32; + localparam int unsigned DataWidth = 32; + localparam int unsigned MgrIdWidth = 5; + localparam int unsigned SbrIdWidth = MgrIdWidth+$clog2(NumManagers); + localparam int unsigned AUserWidth = 4; + localparam int unsigned WUserWidth = 2; + localparam int unsigned RUserWidth = 3; + + // TODO CHK! + + localparam int unsigned NumRequests = 32'd10000; + + localparam time CyclTime = 10ns; + localparam time ApplTime = 2ns; + localparam time TestTime = 8ns; + + localparam obi_pkg::obi_cfg_t MgrConfig = '{ + UseRReady: 1'b1, + CombGnt: 1'b0, + AddrWidth: AddrWidth, + DataWidth: DataWidth, + IdWidth: MgrIdWidth, + Integrity: 1'b0, + BeFull: 1'b1, + OptionalCfg: '{ + UseAtop: 1'b1, + UseMemtype: 1'b1, + UseProt: 1'b1, + UseDbg: 1'b1, + AUserWidth: AUserWidth, + WUserWidth: WUserWidth, + RUserWidth: RUserWidth, + MidWidth: 0, + AChkWidth: 0, + RChkWidth: 0 + } + }; + `OBI_TYPEDEF_ALL_A_OPTIONAL(mgr_a_optional_t, AUserWidth, WUserWidth, 0, 0) + `OBI_TYPEDEF_ALL_R_OPTIONAL(mgr_r_optional_t, RUserWidth, 0) + typedef obi_test::obi_rand_manager #( + .ObiCfg ( MgrConfig ), + .obi_a_optional_t ( mgr_a_optional_t ), + .obi_r_optional_t ( mgr_r_optional_t ), + .TA ( ApplTime ), + .TT ( TestTime ), + .MinAddr (32'h0000_0000), + .MaxAddr (32'h0001_3000) + ) rand_manager_t; + + localparam obi_pkg::obi_cfg_t SbrConfig = '{ + UseRReady: 1'b1, + CombGnt: 1'b0, + AddrWidth: AddrWidth, + DataWidth: DataWidth, + IdWidth: SbrIdWidth, + Integrity: 1'b0, + BeFull: 1'b1, + OptionalCfg: '{ + UseAtop: 1'b1, + UseMemtype: 1'b1, + UseProt: 1'b1, + UseDbg: 1'b1, + AUserWidth: AUserWidth, + WUserWidth: WUserWidth, + RUserWidth: RUserWidth, + MidWidth: 0, + AChkWidth: 0, + RChkWidth: 0 + } + }; + `OBI_TYPEDEF_ALL_A_OPTIONAL(sbr_a_optional_t, AUserWidth, WUserWidth, 0, 0) + `OBI_TYPEDEF_ALL_R_OPTIONAL(sbr_r_optional_t, RUserWidth, 0) + + typedef obi_test::obi_rand_subordinate #( + .ObiCfg ( SbrConfig ), + .obi_a_optional_t ( sbr_a_optional_t ), + .obi_r_optional_t ( sbr_r_optional_t ), + .TA ( ApplTime ), + .TT ( TestTime ) + ) rand_subordinate_t; + + localparam int unsigned NumRules = 8; + typedef struct packed { + int unsigned idx; + logic [AddrWidth-1:0] start_addr; + logic [AddrWidth:0] end_addr; + } rule_t; + + localparam rule_t [NumRules-1:0] AddrMap = '{ + '{idx: 32'd7, start_addr: 32'h0001_0000, end_addr: 32'h0001_1000}, + '{idx: 32'd6, start_addr: 32'h0000_9000, end_addr: 32'h0001_0000}, + '{idx: 32'd5, start_addr: 32'h0000_8000, end_addr: 32'h0000_9000}, + '{idx: 32'd4, start_addr: 32'h0000_7000, end_addr: 32'h0000_8000}, + '{idx: 32'd3, start_addr: 32'h0000_6300, end_addr: 32'h0000_7000}, + '{idx: 32'd2, start_addr: 32'h0000_4000, end_addr: 32'h0000_6300}, + '{idx: 32'd1, start_addr: 32'h0000_3000, end_addr: 32'h0000_4000}, + '{idx: 32'd0, start_addr: 32'h0000_0000, end_addr: 32'h0000_3000} + }; + + logic clk, rst_n; + logic [NumManagers-1:0] end_of_sim; + + OBI_BUS_DV #( + .OBI_CFG ( MgrConfig ), + .obi_a_optional_t ( mgr_a_optional_t ), + .obi_r_optional_t ( mgr_r_optional_t ) + ) mgr_bus_dv [NumManagers] ( + .clk_i ( clk ), + .rst_ni ( rst_n ) + ); + OBI_BUS #( + .OBI_CFG ( MgrConfig ), + .obi_a_optional_t ( mgr_a_optional_t ), + .obi_r_optional_t ( mgr_r_optional_t ) + ) mgr_bus [NumManagers] (); + + for (genvar i = 0; i < NumManagers; i++) begin : gen_mgr_drivers + initial begin + automatic rand_manager_t obi_rand_manager = new ( mgr_bus_dv[i], $sformatf("MGR_%0d",i)); + automatic logic [ MgrConfig.DataWidth-1:0] r_rdata = '0; + automatic logic [ MgrConfig.IdWidth-1:0] r_rid = '0; + automatic logic r_err = '0; + automatic mgr_r_optional_t r_optional = '0; + end_of_sim[i] <= 1'b0; + obi_rand_manager.reset(); + @(posedge rst_n); + obi_rand_manager.write(32'h0000_1100, 4'hF, 32'hDEAD_BEEF, 2, + '{auser: '0, + wuser: '0, + atop: '0, + memtype: obi_pkg::memtype_t'('0), + mid: '0, + prot: obi_pkg::prot_t'('0), + dbg: '0, + achk: '0}, r_rdata, r_rid, r_err, r_optional); + obi_rand_manager.read(32'h0000_e100, 2, '{auser: '0, + wuser: '0, + atop: '0, + memtype: obi_pkg::memtype_t'('0), + mid: '0, + prot: obi_pkg::prot_t'('0), + dbg: '0, + achk: '0}, r_rdata, r_rid, r_err, r_optional); + obi_rand_manager.run(NumRequests); + end_of_sim[i] <= 1'b1; + end + + `OBI_ASSIGN(mgr_bus[i], mgr_bus_dv[i], MgrConfig, MgrConfig) + end + + OBI_BUS_DV #( + .OBI_CFG ( SbrConfig ), + .obi_a_optional_t ( sbr_a_optional_t ), + .obi_r_optional_t ( sbr_r_optional_t ) + ) sbr_bus_dv [NumSubordinates] ( + .clk_i ( clk ), + .rst_ni ( rst_n ) + ); + OBI_BUS #( + .OBI_CFG ( SbrConfig ), + .obi_a_optional_t ( sbr_a_optional_t ), + .obi_r_optional_t ( sbr_r_optional_t ) + ) sbr_bus [NumSubordinates] (); + + for (genvar i = 0; i < NumSubordinates; i++) begin : gen_sbr_drivers + initial begin + automatic rand_subordinate_t obi_rand_subordinate = + new ( sbr_bus_dv[i], $sformatf("SBR_%0d",i)); + obi_rand_subordinate.reset(); + @(posedge rst_n); + obi_rand_subordinate.run(); + end + + `OBI_ASSIGN(sbr_bus_dv[i], sbr_bus[i], SbrConfig, SbrConfig) + end + + clk_rst_gen #( + .ClkPeriod ( CyclTime ), + .RstClkCycles ( 5 ) + ) i_clk_gen ( + .clk_o ( clk ), + .rst_no ( rst_n ) + ); + + // DUT + obi_xbar_intf #( + .SbrPortObiCfg ( MgrConfig ), + .MgrPortObiCfg ( SbrConfig ), + .NumSbrPorts ( NumManagers ), + .NumMgrPorts ( NumSubordinates ), + .NumMaxTrans ( NumMaxTrans ), + .NumAddrRules ( NumRules ), + .addr_map_rule_t ( rule_t ), + .UseIdForRouting ( UseIdForRouting ) + ) i_dut ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .testmode_i ( 1'b0 ), + .sbr_ports ( mgr_bus ), + .mgr_ports ( sbr_bus ), + .addr_map_i ( AddrMap ), + .en_default_idx_i ( '0 ), + .default_idx_i ( '0 ) + ); + + initial begin + wait(&end_of_sim); + repeat (1000) @(posedge clk); + $display("Simulation stopped as all Masters transferred their data, Success.",); + $stop(); + end + +endmodule diff --git a/vendor/pulp-platform_obi.lock.hjson b/vendor/pulp-platform_obi.lock.hjson new file mode 100644 index 000000000..1978d3bf9 --- /dev/null +++ b/vendor/pulp-platform_obi.lock.hjson @@ -0,0 +1,13 @@ +// -*- coding: utf-8 -*- +// Copyright (C) 2024 Thales DIS France SAS +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0. +// Original Author: Yannick Casamatta + + +{ + upstream: + { + url: https://github.com/pulp-platform/obi.git + rev: c2141a653c755461ff44f61d12aeb5d99fc8e760 + } +} diff --git a/vendor/pulp-platform_obi.vendor.hjson b/vendor/pulp-platform_obi.vendor.hjson new file mode 100644 index 000000000..6a85ef445 --- /dev/null +++ b/vendor/pulp-platform_obi.vendor.hjson @@ -0,0 +1,32 @@ +// -*- coding: utf-8 -*- +// Copyright (C) 2024 Thales DIS France SAS +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0. +// Original Author: Yannick Casamatta + + +{ + // Name of the project + name: "pulp_obi", + + // Target directory: relative to the location of this script. + target_dir: "pulp-platform/obi", + + // Upstream repository + upstream: { + // URL + url: "https://github.com/pulp-platform/obi.git", + // revision + rev: "v0.1.3", + } + + // Patch dir for local changes + patch_dir: "patches/pulp-platform/obi", + + // Exclusions from upstream content + exclude_from_upstream: [ + ".ci", + ".github", + ".gitlab-ci.d", + ".gitlab-ci.yml", + ] +}