mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-22 13:17:41 -04:00
Vendorize pulp OBI specs at tag v0.1.3
This commit is contained in:
parent
81426a4b85
commit
4a6b458011
25 changed files with 4319 additions and 0 deletions
1
vendor/pulp-platform/obi/.gitignore
vendored
Normal file
1
vendor/pulp-platform/obi/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.bender
|
38
vendor/pulp-platform/obi/Bender.yml
vendored
Normal file
38
vendor/pulp-platform/obi/Bender.yml
vendored
Normal file
|
@ -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 <michaero@iis.ee.ethz.ch>"
|
||||
|
||||
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
|
34
vendor/pulp-platform/obi/CHANGELOG.md
vendored
Normal file
34
vendor/pulp-platform/obi/CHANGELOG.md
vendored
Normal file
|
@ -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`.
|
176
vendor/pulp-platform/obi/LICENSE
vendored
Normal file
176
vendor/pulp-platform/obi/LICENSE
vendored
Normal file
|
@ -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
|
35
vendor/pulp-platform/obi/Makefile
vendored
Normal file
35
vendor/pulp-platform/obi/Makefile
vendored
Normal file
|
@ -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
|
25
vendor/pulp-platform/obi/Readme.md
vendored
Normal file
25
vendor/pulp-platform/obi/Readme.md
vendored
Normal file
|
@ -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
|
257
vendor/pulp-platform/obi/include/obi/assign.svh
vendored
Normal file
257
vendor/pulp-platform/obi/include/obi/assign.svh
vendored
Normal file
|
@ -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 <michaero@iis.ee.ethz.ch>
|
||||
|
||||
`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
|
122
vendor/pulp-platform/obi/include/obi/typedef.svh
vendored
Normal file
122
vendor/pulp-platform/obi/include/obi/typedef.svh
vendored
Normal file
|
@ -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 <michaero@iis.ee.ethz.ch>
|
||||
|
||||
`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
|
509
vendor/pulp-platform/obi/src/obi_atop_resolver.sv
vendored
Normal file
509
vendor/pulp-platform/obi/src/obi_atop_resolver.sv
vendored
Normal file
|
@ -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 <sriedel@iis.ee.ethz.ch>
|
||||
// Author: Michael Rogenmoser <michaero@iis.ee.ethz.ch>
|
||||
|
||||
`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
|
164
vendor/pulp-platform/obi/src/obi_demux.sv
vendored
Normal file
164
vendor/pulp-platform/obi/src/obi_demux.sv
vendored
Normal file
|
@ -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 <michaero@iis.ee.ethz.ch>
|
||||
|
||||
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
|
||||
|
107
vendor/pulp-platform/obi/src/obi_err_sbr.sv
vendored
Normal file
107
vendor/pulp-platform/obi/src/obi_err_sbr.sv
vendored
Normal file
|
@ -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 <michaero@iis.ee.ethz.ch>
|
||||
|
||||
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
|
241
vendor/pulp-platform/obi/src/obi_intf.sv
vendored
Normal file
241
vendor/pulp-platform/obi/src/obi_intf.sv
vendored
Normal file
|
@ -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 <michaero@iis.ee.ethz.ch>
|
||||
|
||||
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
|
228
vendor/pulp-platform/obi/src/obi_mux.sv
vendored
Normal file
228
vendor/pulp-platform/obi/src/obi_mux.sv
vendored
Normal file
|
@ -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 <michaero@iis.ee.ethz.ch>
|
||||
|
||||
`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
|
136
vendor/pulp-platform/obi/src/obi_pkg.sv
vendored
Normal file
136
vendor/pulp-platform/obi/src/obi_pkg.sv
vendored
Normal file
|
@ -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 <michaero@iis.ee.ethz.ch>
|
||||
|
||||
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
|
72
vendor/pulp-platform/obi/src/obi_rready_converter.sv
vendored
Normal file
72
vendor/pulp-platform/obi/src/obi_rready_converter.sv
vendored
Normal file
|
@ -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 <georgr@iis.ee.ethz.ch>
|
||||
|
||||
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
|
66
vendor/pulp-platform/obi/src/obi_sram_shim.sv
vendored
Normal file
66
vendor/pulp-platform/obi/src/obi_sram_shim.sv
vendored
Normal file
|
@ -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 <michaero@iis.ee.ethz.ch>
|
||||
|
||||
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
|
242
vendor/pulp-platform/obi/src/obi_xbar.sv
vendored
Normal file
242
vendor/pulp-platform/obi/src/obi_xbar.sv
vendored
Normal file
|
@ -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 <michaero@iis.ee.ethz.ch>
|
||||
|
||||
/// 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
|
245
vendor/pulp-platform/obi/src/test/atop_golden_mem_pkg.sv
vendored
Normal file
245
vendor/pulp-platform/obi/src/test/atop_golden_mem_pkg.sv
vendored
Normal file
|
@ -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 <michaero@iis.ee.ethz.ch>
|
||||
|
||||
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
|
42
vendor/pulp-platform/obi/src/test/obi_asserter.sv
vendored
Normal file
42
vendor/pulp-platform/obi/src/test/obi_asserter.sv
vendored
Normal file
|
@ -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 <tsenti@ethz.ch>
|
||||
|
||||
`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
|
201
vendor/pulp-platform/obi/src/test/obi_sim_mem.sv
vendored
Normal file
201
vendor/pulp-platform/obi/src/test/obi_sim_mem.sv
vendored
Normal file
|
@ -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 <michaero@iis.ee.ethz.ch>
|
||||
|
||||
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
|
398
vendor/pulp-platform/obi/src/test/obi_test.sv
vendored
Normal file
398
vendor/pulp-platform/obi/src/test/obi_test.sv
vendored
Normal file
|
@ -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 <michaero@iis.ee.ethz.ch>
|
||||
|
||||
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
|
706
vendor/pulp-platform/obi/src/test/tb_obi_atop_resolver.sv
vendored
Normal file
706
vendor/pulp-platform/obi/src/test/tb_obi_atop_resolver.sv
vendored
Normal file
|
@ -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 <sriedel@iis.ee.ethz.ch>
|
||||
// Author: Michael Rogenmoser <michaero@iis.ee.ethz.ch>
|
||||
|
||||
`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
|
229
vendor/pulp-platform/obi/src/test/tb_obi_xbar.sv
vendored
Normal file
229
vendor/pulp-platform/obi/src/test/tb_obi_xbar.sv
vendored
Normal file
|
@ -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 <michaero@iis.ee.ethz.ch>
|
||||
|
||||
`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
|
13
vendor/pulp-platform_obi.lock.hjson
vendored
Normal file
13
vendor/pulp-platform_obi.lock.hjson
vendored
Normal file
|
@ -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
|
||||
}
|
||||
}
|
32
vendor/pulp-platform_obi.vendor.hjson
vendored
Normal file
32
vendor/pulp-platform_obi.vendor.hjson
vendored
Normal file
|
@ -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",
|
||||
]
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue