Vendorize fpga-support submodule. (#1030)

This commit is contained in:
Zbigniew Chamski 2023-01-16 11:40:04 +01:00 committed by GitHub
parent 7c92b68b92
commit b44a696bbe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 3393 additions and 0 deletions

View file

@ -0,0 +1,113 @@
# Change Log
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/), and this project adheres to
[Semantic Versioning](http://semver.org).
## [Unreleased]
- Switch default implementation from ALTERA to XILINX
- Add simulation init options to inferable rams (none, 0, random, deadbeef)
### Added
### Fixed
## [v0.3.2] - 2018-07-24
### Updated
- This package has been moved from the internal GitLab to GitHub. The Changelog and the affected
Read-Mes and scripts have been updated accordingly.
## [v0.3.1] - 2018-07-03
### Fixed
- `AxiToAxiLitePc`:
- Fixed bug with multiple parallel transactions. The AXI interface now only accepts a new request
after the response from the previous transaction has been acknowledged.
- Return `SLVERR` on burst requests. This module does not support bursts and now consistently
responds with a Slave Error on a burst request.
## [v0.3.0] - 2017-07-11
### Added
- Set of five inferable, synchronous BRAM-based memories:
- `SyncDpRam` (dual-port)
- `SyncSpRam` (single-port)
- `SyncSpRamBeNx32` (single-port N x 32bit with byte-wise enable)
- `SyncSpRamBeNx64` (single-port N x 64bit with byte-wise enable)
- `SyncTpRam` (two-port)
## [v0.2.3] - 2017-07-11
### Fixed
- `src_files.yml`: added missing comma at the end of the `AxiToAxiLitePc` entry.
## [v0.2.2] - 2017-07-11
### Fixed
- URLs to the GitLab repository of this project now correctly point to
`pulp-restricted/fpga-support` instead of the outdated `pulp-project/fpga-support`.
## [v0.2.1] - 2017-07-11
### Fixed
- `src_files.yml`: added the missing entry for `AxiToAxiLitePc`.
## [v0.2.0] - 2017-02-10
### Added
- `AxiToAxiLitePc`: a simple AXI to AXI Lite Protocol Converter.
### Fixed
- `BramDwc`: address registering. The address can now be changed between clock edges and the output
will still correspond to the address applied at the former clock edge.
- `BramDwc`: compatibility of interface port declarations with synthesis tools. Interface ports are
now explicitly declared either as `Master` or as `Slave`, so that synthesis tools will not infer
`inout` connections.
## [v0.1.1] - 2017-02-10
### Fixed
- `BramDwc`: address registering. The address can now be changed between clock edges and the output
will still correspond to the address applied at the former clock edge.
- `BramDwc`: compatibility of interface port declarations with synthesis tools. Interface ports are
now explicitly declared either as `Master` or as `Slave`, so that synthesis tools will not infer
`inout` connections.
## v0.1.0 - 2016-11-14
### Added
- Three Block RAM (BRAM)-related modules:
- `BramPort`: the standard interface for Xilinx BRAMs,
- `TdpBramArray`: an array of Xilinx True Dual-Port BRAM cells with a standard BRAM interface, and
- `BramDwc`: a Data Width Converter from a narrow master BRAM controller to a wide slave BRAM
(array).
- `BramLogger`: a logger that writes events to a `TdpBramArray`.
- `AxiBramLogger`: a logger to keep track of events on an AXI bus. This module is build on
`BramLogger`.
[Unreleased]: https://github.com/pulp-platform/fpga-support/compare/v0.3.2...HEAD
[v0.3.2]: https://github.com/pulp-platform/fpga-support/compare/v0.3.1...v0.3.2
[v0.3.1]: https://github.com/pulp-platform/fpga-support/compare/v0.3.0...v0.3.1
[v0.3.0]: https://github.com/pulp-platform/fpga-support/compare/v0.2.3...v0.3.0
[v0.2.3]: https://github.com/pulp-platform/fpga-support/compare/v0.2.2...v0.2.3
[v0.2.2]: https://github.com/pulp-platform/fpga-support/compare/v0.2.1...v0.2.2
[v0.2.1]: https://github.com/pulp-platform/fpga-support/compare/v0.2.0...v0.2.1
[v0.2.0]: https://github.com/pulp-platform/fpga-support/compare/v0.1.0...v0.2.0
[v0.1.1]: https://github.com/pulp-platform/fpga-support/compare/v0.1.0...v0.1.1

View file

@ -0,0 +1,28 @@
# Contribution Guidelines
If you find bugs or have questions or feature requests, please discuss the issue the maintainer of
the respective IP block (see header of the source file). All developers are encouraged to
contribute small, simple patches that can be reviewed easily. If your patch is too large, break it
into logically connected, atomic units. A best-practice contribution follows this sequence:
1. Add a test to the testbench that clearly specifies the bug or feature you want to tackle. As
you have not contributed your code yet, this test must fail. Have it do so with a descriptive
reason.
2. Write the code that meets your specifications, thus causes the test to pass. The code does not
yet have to be perfect, as it will be improved later.
3. Run all tests in this repository and make sure they *all* pass. Do *not* modify any tests other
than the one you added for this contribution.
4. Reach back to the maintainer to discuss specifications and code. If your code initially caused
any other tests to fail and you had to modify existing code to get them to pass again, mention
this.
5. Refactor your code to make it clean, simple, and maintainable. Repeat steps 3 to 5 until no
refactoring is necessary anymore. Ask the maintainer to merge your contribution.
We only accept contributions that follow the formatting conventions specified by the
[`.editorconfig`](./.editorconfig) file. If you use an editor that is suitable for editing code,
chances are good that it can automatically take care of this (either out of the box or with a
plugin, see http://editorconfig.org for more information).

View 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

View file

@ -0,0 +1,25 @@
# IP Blocks to Support Design, Prototyping, and Verification of PULP on FPGAs
This repository contains IP blocks that can be useful in many aspects of working with PULP on FPGA
platforms. The repository is structured as follows:
- `behav/` Behavioral Simulation and Tests; contains one subdirectory for each module.
- `rtl/` End-User RTL Code
- `synth/` Post-Synthesis Simulation and Tests; contains one subdirectory for each module.
## Usage
Many IP blocks in this repository depend on the [CfMath](https://github.com/pulp-platform/cfmath)
package. Make sure to have that package on the list of source files for elaboration. For
behavioral and post-synthesis simulations, set the `CF_MATH_PKG_PATH` environment variable to the
path where you have that package installed.
Add all files in the `rtl/` folder to the list of compilation files of your development tool (e.g.,
Xilinx Vivado). Read the documentation (header of the source file) of the block that you want to
use and use the block as described there.
## Contributing
Thank you for your intent to contribute to improving the quality and usefulness of this repository!
In the interest of making this an optimal experience for you, the maintainers, and the users, please
follow the [Contribution Guidelines](CONTRIBUTING.md)

View file

@ -0,0 +1,8 @@
/work/*
/*.log
/*.out
/*.wlf
/modelsim.ini
/transcript

View file

@ -0,0 +1,66 @@
LIB = work
VER = 10.5c
VLOG_OPTS = -work $(LIB) +incdir+../common/include
ASSERT_LOG = assert.log
COMPILE_LOG = compile.log
SIMULATE_LOG = simulate.log
RUNSCRIPT_NOGUI = ./scripts/run.tcl
RUNSCRIPT_GUI = ./scripts/run_gui.tcl
# Path to the 'CfMath' package. This default path is correct when this package is used in the
# 'big.pulp' repository. Otherwise, adapt it so that 'CfMath.sv' can be found at this path.
CF_MATH_PKG_PATH ?= ../../../../../fe/ips/pkg/cfmath
PKGS = $(CF_MATH_PKG_PATH)/CfMath.sv
SRCS = $(wildcard ../common/modules/*.sv) $(wildcard ../../rtl/*.sv)
nogui: ${LIB} compile sim_nogui evaluate
gui: ${LIB} compile sim_gui
${LIB}:
@vlib-${VER} ${LIB}
compile: $(PKGS) $(SRCS) Testbench.sv
@rm -f $(COMPILE_LOG)
@vlog-${VER} $(VLOG_OPTS) $^ >> $(COMPILE_LOG); \
rc=$$?; \
if [ $$rc != 0 ]; then \
cat $(COMPILE_LOG); \
exit $$rc; \
fi
sim_nogui:
@if [ -e '$(RUNSCRIPT_NOGUI)' ]; then \
RUN_CMD="source $(RUNSCRIPT_NOGUI)"; \
else \
RUN_CMD="run"; \
fi; \
vsim-${VER} -c -do "$$RUN_CMD; quit" -assertfile $(ASSERT_LOG) $(LIB).Testbench > $(SIMULATE_LOG); \
rc=$$?; \
if [ $$rc != 0 ]; then \
cat $(SIMULATE_LOG); \
exit $$rc; \
fi
sim_gui:
@if [ -e '$(RUNSCRIPT_GUI)' ]; then \
RUN_CMD="source $(RUNSCRIPT_GUI)"; \
else \
RUN_CMD="run"; \
fi; \
vsim-${VER} -voptargs=+acc -do "$$RUN_CMD" $(LIB).Testbench
evaluate:
@if [ \"$$(wc -l $(ASSERT_LOG) | cut -d' ' -f1)\" != \"0\" ]; then \
cat $(ASSERT_LOG); \
exit 1; \
else \
echo "All assertions passed."; \
fi
clean:
@rm -rf work
@rm -f *.log *.out *.wlf
@rm -f modelsim.ini transcript

View file

@ -0,0 +1,9 @@
# BRAM Data Width Converter Behavioral Testbench
## Running Tests
This module depends on the `CfMath` package. You have to specify the path to this package when
running tests. If this module is not used as part of the `big.pulp` project, specify the correct
path to the package in `CF_MATH_PKG_PATH`, e.g.,
CF_MATH_PKG_PATH=../../../../../fe/ips/pkg/cfmath make

View file

@ -0,0 +1,215 @@
// Copyright 2016 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/**
* BRAM Data Width Converter Testbench
*
* Current Maintainers:
* - Andreas Kurth <akurth@iis.ee.ethz.ch>
* - Pirmin Vogel <vogelpi@iis.ee.ethz.ch>
*/
`include "assertions.sv"
module Testbench
// Parameters {{{
#(
parameter CLK_PERIOD = 10ns,
parameter STIM_APPL_DELAY = 5ns,
parameter RESP_ACQ_DELAY = 2ns,
parameter STIM_PATH = "./vectors/stim.txt",
parameter EXP_RESP_PATH = "./vectors/expresp.txt"
);
// }}}
// Module-Wide Constants {{{
localparam integer ADDR_BITW = 32;
localparam integer MST_DATA_BITW = 32;
localparam integer SLV_DATA_BITW = 96;
// }}}
// Clock and Reset Generator {{{
logic Clk_C, Rst_RB, EndOfSim_S;
ClkRstGen
#(
.CLK_LOW_TIME (CLK_PERIOD/2),
.CLK_HIGH_TIME (CLK_PERIOD/2)
)
clkRstGen
(
.EndOfSim_SI (EndOfSim_S),
.Clk_CO (Clk_C),
.Rst_RBO (Rst_RB)
);
// }}}
// Instantiation of Master and Slave Interfaces to be connected {{{
BramPort
#(
.DATA_BITW(MST_DATA_BITW),
.ADDR_BITW(ADDR_BITW)
) Bram_PM ();
BramPort
#(
.DATA_BITW(SLV_DATA_BITW),
.ADDR_BITW(ADDR_BITW)
) Bram_PS ();
// }}}
// DUT Instantiation {{{
BramDwc
#(
.ADDR_BITW (ADDR_BITW),
.MST_DATA_BITW(MST_DATA_BITW),
.SLV_DATA_BITW(SLV_DATA_BITW)
) dut (
.FromMaster_PS(Bram_PM),
.ToSlave_PM (Bram_PS)
);
// }}}
// Master Driver {{{
assign Bram_PM.Clk_C = Clk_C;
assign Bram_PM.Rst_R = ~Rst_RB;
assign Bram_PM.En_S = '1;
// }}}
// Assert properties that always hold. {{{
always @ (Bram_PM.Clk_C) begin
assert (Bram_PS.Clk_C == Bram_PM.Clk_C)
else $error("Slave clock is not equal to master clock!");
assert (Bram_PS.En_S == Bram_PM.En_S)
else $error("Slave enable signal is not equal to master enable signal!");
end
always @ (Bram_PM.Rst_R) begin
assert (Bram_PS.Rst_R == Bram_PM.Rst_R)
else $error("Slave reset signal is not equal to master reset signal!");
end
// }}}
// Set simulation up. {{{
integer stim_fd, expresp_fd;
logic EndOfStim_S = 0;
logic EndOfExpResp_S = 0;
assign EndOfSim_S = EndOfStim_S && EndOfExpResp_S;
initial begin
// Open files with test vectors. {{{
stim_fd = $fopen(STIM_PATH, "r");
if (stim_fd == 0)
$fatal(1, "Failed to open stimuli file '%s'!", STIM_PATH);
expresp_fd = $fopen(EXP_RESP_PATH, "r");
if (expresp_fd == 0)
$fatal(1, "Failed to open expected responses file '%s'!", EXP_RESP_PATH);
// }}}
end
// }}}
// Apply stimuli. {{{
string stim_vec;
integer stim_read;
struct {
logic [32-1:0] Addr_S;
logic [ 4-1:0] WrEn_S;
logic [96-1:0] Rd_D;
logic [32-1:0] Wr_D;
} Stim;
integer stim_ln = 0;
always @ (posedge Clk_C) begin
if (~EndOfStim_S) begin
stim_read = 0;
while (stim_read != 4) begin
stim_ln = stim_ln + 1;
stim_read = $fgets(stim_vec, stim_fd);
stim_read = $sscanf(stim_vec, "%h %h %h %h",
Stim.Addr_S, Stim.WrEn_S, Stim.Wr_D, Stim.Rd_D);
if ($feof(stim_fd)) begin
EndOfStim_S = 1;
break;
end
end
#STIM_APPL_DELAY;
Bram_PM.Addr_S = Stim.Addr_S;
Bram_PM.WrEn_S = Stim.WrEn_S;
Bram_PM.Wr_D = Stim.Wr_D;
Bram_PS.Rd_D = Stim.Rd_D;
end
end
// }}}
// Acquire and compare expected responses. {{{
logic ExpRespAcqEn_S = 0;
string expresp_vec;
integer expresp_read;
struct {
logic [32-1:0] Addr_S;
logic [12-1:0] WrEn_S;
logic [32-1:0] Rd_D;
logic [96-1:0] Wr_D;
} ExpResp;
integer expresp_ln = 0;
always @ (posedge Clk_C) begin
if (ExpRespAcqEn_S) begin
if (~EndOfExpResp_S) begin
expresp_read = 0;
while (expresp_read != 4) begin
expresp_ln = expresp_ln + 1;
expresp_read = $fgets(expresp_vec, expresp_fd);
expresp_read = $sscanf(expresp_vec, "%h %h %h %h",
ExpResp.Addr_S, ExpResp.WrEn_S, ExpResp.Wr_D, ExpResp.Rd_D);
if ($feof(expresp_fd)) begin
EndOfExpResp_S = 1;
break;
end
end
if (~EndOfExpResp_S) begin
#RESP_ACQ_DELAY;
`assert_equal_msg(Bram_PS.Addr_S, ExpResp.Addr_S, "Addr_S", expresp_ln);
`assert_equal_msg(Bram_PS.WrEn_S, ExpResp.WrEn_S, "WrEn_S", expresp_ln);
`assert_equal_msg(Bram_PS.Wr_D, ExpResp.Wr_D, "Wr_D", expresp_ln);
`assert_equal_msg(Bram_PM.Rd_D, ExpResp.Rd_D, "Rd_D", expresp_ln);
end
end
end else begin
ExpRespAcqEn_S = 1;
end
end
// }}}
// Deactivated Tests {{{
// The following code would correctly fail fatally. The code is currently inactive to avoid
// confusion with real assertion failures.
/*
BramPort
#(
.DATA_BITW(96),
.ADDR_BITW(32)
) wideMaster ();
BramPort
#(
.DATA_BITW(32),
.ADDR_BITW(32)
) narrowSlave ();
BramDwc incorrectFromToBitwidths
(
.FromMaster_PS(wideMaster),
.ToSlave_PM (narrowSlave)
);
*/
// }}}
endmodule
// vim: nosmartindent autoindent foldmethod=marker

View file

@ -0,0 +1,3 @@
run -all
# vim: syntax=tcl

View file

@ -0,0 +1,5 @@
source ./scripts/waves.tcl
source ./scripts/run.tcl
# vim: syntax=tcl

View file

@ -0,0 +1,17 @@
quietly WaveActivateNextPane {} 0
configure wave -signalnamewidth 1
delete wave *
add wave -noupdate /Testbench/Clk_C
add wave -noupdate /Testbench/Rst_RB
add wave -noupdate /Testbench/EndOfSim_S
add wave -noupdate -expand -group Bram_PM /Testbench/Bram_PM/*
add wave -noupdate -expand -group Bram_PS /Testbench/Bram_PS/*
add wave -noupdate -expand /Testbench/ExpResp
update
# vim: syntax=tcl

View file

@ -0,0 +1,35 @@
# Bram_PS.
# Addr_S WrEn_S Wr_D
# Bram_PM. Rd_D
# sequential writes
0000 00F 111111111111111111111111 00000000
0000 0F0 222222222222222222222222 00000000
0000 F00 333333333333333333333333 00000000
0010 00F 444444444444444444444444 00000000
0010 0F0 555555555555555555555555 00000000
0010 F00 666666666666666666666666 00000000
0020 00F 777777777777777777777777 00000000
0020 0F0 888888888888888888888888 00000000
0020 F00 999999999999999999999999 00000000
# sequential reads
0000 000 000000000000000000000000 11111111
0000 000 000000000000000000000000 22222222
0000 000 000000000000000000000000 33333333
0010 000 000000000000000000000000 44444444
0010 000 000000000000000000000000 55555555
0010 000 000000000000000000000000 66666666
0020 000 000000000000000000000000 77777777
0020 000 000000000000000000000000 88888888
0020 000 000000000000000000000000 99999999
# random writes
14D0 0F0 133713371337133713371337 42424242
D7430 00F 133713371337133713371337 42424242
314FD0 F00 133713371337133713371337 42424242
# random reads
6A80 000 000000000000000000000000 12345678
2B0230 000 000000000000000000000000 12345678
213FF0 000 000000000000000000000000 12345678

View file

@ -0,0 +1,35 @@
# Bram_PM.
# Addr_S WrEn_S Wr_D
# Bram_PS. Rd_D
# sequential writes
0000 F 11111111 000000000000000000000000
0004 F 22222222 000000000000000011111111
0008 F 33333333 000000002222222211111111
000C F 44444444 000000000000000000000000
0010 F 55555555 000000000000000044444444
0014 F 66666666 000000005555555544444444
0018 F 77777777 000000000000000000000000
001C F 88888888 000000000000000077777777
0020 F 99999999 000000008888888877777777
# sequential reads
0000 0 00000000 50000BAD50000BAD11111111
0004 0 00000000 50000BAD2222222250000BAD
0008 0 00000000 3333333350000BAD50000BAD
000C 0 00000000 50000BAD50000BAD44444444
0010 0 00000000 50000BAD5555555550000BAD
0014 0 00000000 6666666650000BAD50000BAD
0018 0 00000000 50000BAD50000BAD77777777
001C 0 00000000 50000BAD8888888850000BAD
0020 0 00000000 9999999950000BAD50000BAD
# random write
0FA0 F 13371337 50000BAD4242424250000BAD
A1724 F 13371337 50000BAD50000BAD42424242
24FBE4 F 13371337 4242424250000BAD50000BAD
# random read
4FE0 0 00000000 BAAAAAAABAAAAAAA12345678
2041AC 0 00000000 12345678BAAAAAAABAAAAAAA
18EFF8 0 00000000 BAAAAAAA12345678BAAAAAAA

View file

@ -0,0 +1,7 @@
TARGETS = $(filter-out common/.,$(wildcard */.))
.PHONY: all ${TARGETS}
all: ${TARGETS}
${TARGETS}:
$(MAKE) -C $@

View file

@ -0,0 +1,66 @@
LIB = work
VER = 10.5c
VLOG_OPTS = -work $(LIB) +incdir+../common/include
ASSERT_LOG = assert.log
COMPILE_LOG = compile.log
SIMULATE_LOG = simulate.log
RUNSCRIPT_NOGUI = ./scripts/run.tcl
RUNSCRIPT_GUI = ./scripts/run_gui.tcl
# Path to the 'CfMath' package. This default path is correct when this package is used in the
# 'big.pulp' repository. Otherwise, adapt it so that 'CfMath.sv' can be found at this path.
CF_MATH_PKG_PATH ?= ../../../../../fe/ips/pkg/cfmath
PKGS = $(CF_MATH_PKG_PATH)/CfMath.sv
SRCS = $(wildcard ../common/modules/*.sv) $(wildcard ../../rtl/*.sv)
nogui: ${LIB} compile sim_nogui evaluate
gui: ${LIB} compile sim_gui
${LIB}:
@vlib-${VER} ${LIB}
compile: $(PKGS) $(SRCS) Testbench.sv
@rm -f $(COMPILE_LOG)
@vlog-${VER} $(VLOG_OPTS) $^ >> $(COMPILE_LOG); \
rc=$$?; \
if [ $$rc != 0 ]; then \
cat $(COMPILE_LOG); \
exit $$rc; \
fi
sim_nogui:
@if [ -e '$(RUNSCRIPT_NOGUI)' ]; then \
RUN_CMD="source $(RUNSCRIPT_NOGUI)"; \
else \
RUN_CMD="run"; \
fi; \
vsim-${VER} -c -do "$$RUN_CMD; quit" -assertfile $(ASSERT_LOG) $(LIB).Testbench > $(SIMULATE_LOG); \
rc=$$?; \
if [ $$rc != 0 ]; then \
cat $(SIMULATE_LOG); \
exit $$rc; \
fi
sim_gui:
@if [ -e '$(RUNSCRIPT_GUI)' ]; then \
RUN_CMD="source $(RUNSCRIPT_GUI)"; \
else \
RUN_CMD="run"; \
fi; \
vsim-${VER} -voptargs=+acc -do "$$RUN_CMD" $(LIB).Testbench
evaluate:
@if [ \"$$(wc -l $(ASSERT_LOG) | cut -d' ' -f1)\" != \"0\" ]; then \
cat $(ASSERT_LOG); \
exit 1; \
else \
echo "All assertions passed."; \
fi
clean:
@rm -rf work
@rm -f *.log *.out *.wlf
@rm -f modelsim.ini transcript

View file

@ -0,0 +1,8 @@
/work/*
/*.log
/*.out
/*.wlf
/modelsim.ini
/transcript

View file

@ -0,0 +1,33 @@
// Copyright 2016 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/**
* Assertions for Actual/Expected Comparisons in Testbenches
*
* Current Maintainers:
* - Andreas Kurth <akurth@iis.ee.ethz.ch>
* - Pirmin Vogel <vogelpi@iis.ee.ethz.ch>
*/
`ifndef ASSERTIONS_SV
`define ASSERTIONS_SV
`define assert_equal(actual, expected) \
assert (actual == expected) \
else $error("Failed assertion: %0d == %0d", actual, expected);
`define assert_equal_msg(actual, expected, msg, ln) \
assert (actual == expected) \
else $error("Failed assertion (ExpResp LN %04d, %s): %x == %x", \
ln, msg, actual, expected);
`endif // ASSERTIONS_SV
// vim: nosmartindent autoindent

View file

@ -0,0 +1,82 @@
// Copyright 2016 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/**
* Clock and Reset Generator
*
* This module generates a single-phase clock and an active-low reset signal for a simulation
* testbench.
*
* Parameter Description:
* CLK_LOW_TIME Duration of the phase in which the clock is low.
* CLK_HIGH_TIME Duration of the phase in which the clock is high.
* RST_TIME Interval at the beginning of the simulation during which the reset is active.
*
* Port Description:
* EndOfSim_SI Stops the simulation clock in the next period.
* Clk_CO Single-phase clock.
* Rst_RBO Active-low reset.
*/
//timeunit 1ns;
module ClkRstGen
// Parameters {{{
#(
parameter CLK_LOW_TIME = 5ns,
parameter CLK_HIGH_TIME = 5ns,
parameter RST_TIME = 100ns
)
// }}}
// Ports {{{
(
input logic EndOfSim_SI,
output logic Clk_CO,
output logic Rst_RBO
);
// }}}
// Module-Wide Constants {{{
localparam time CLK_PERIOD = CLK_LOW_TIME + CLK_HIGH_TIME;
// }}}
// Clock Generation {{{
always begin
Clk_CO = 0;
if (Rst_RBO) begin
// Reset is inactive.
if (~EndOfSim_SI) begin
Clk_CO = 1;
#CLK_HIGH_TIME;
Clk_CO = 0;
#CLK_LOW_TIME;
end else begin
$stop(0);
end
end else begin
// Reset is still active, wait until the next clock period.
#CLK_PERIOD;
end
end
// }}}
// Reset Generation {{{
initial begin
Rst_RBO = 0;
#RST_TIME;
Rst_RBO = 1;
end
// }}}
endmodule
// vim: nosmartindent autoindent foldmethod=marker

View file

@ -0,0 +1,125 @@
// Copyright 2016 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/**
* AXI BRAM Logger
*
* Module that logs AXI accesses with timestamps. This module is built on top of `BramLogger`, and
* all ports that are not the logged AXI inputs are documented there, along with other properties.
*
* Log Format:
* - first word: 32-bit timestamp
* - second word: lowest `AXI_LEN_BITW` bits: AxiLen_DI
* all following bits: AxiId_DI
* - third word (and fourth word for 64-bit addresses): AxiAddr_DI
*
* Current Maintainers:
* - Andreas Kurth <akurth@iis.ee.ethz.ch>
* - Pirmin Vogel <vogelpi@iis.ee.ethz.ch>
*/
import CfMath::ceil_div;
module AxiBramLogger
// Parameters {{{
#(
// Width (in bits) of the logged AXI ID. Value must be in [1, 24].
parameter AXI_ID_BITW = 8,
// Width (in bits) of the logged AXI address. Value must be either 32 or 64.
parameter AXI_ADDR_BITW = 32,
// Number of entries in the log. Value must be >= 1024, should be a multiple of 1024, and is
// upper-bound by the available memory.
parameter NUM_LOG_ENTRIES = 16384,
// The following "parameters" must not be changed from their given value. They are solely
// declared here because they define the width of some of the ports.
parameter AXI_LEN_BITW = 8
)
// }}}
// Ports {{{
(
input logic Clk_CI,
input logic TimestampClk_CI,
input logic Rst_RBI,
// AXI Input
input logic AxiValid_SI,
input logic AxiReady_SI,
input logic [AXI_ID_BITW -1:0] AxiId_DI,
input logic [AXI_ADDR_BITW-1:0] AxiAddr_DI,
input logic [AXI_LEN_BITW -1:0] AxiLen_DI,
// Control Input
input logic Clear_SI,
input logic LogEn_SI,
// Status Output
output logic Full_SO,
output logic Ready_SO,
// Interface to Internal BRAM
BramPort.Slave Bram_PS
);
// }}}
// Module-Wide Constants {{{
// Properties of the data entries in the log
localparam integer META_BITW = ceil_div(AXI_LEN_BITW+AXI_ID_BITW, 32) * 32;
localparam integer LOGGING_DATA_BITW = ceil_div(META_BITW+AXI_ADDR_BITW, 32) * 32;
localparam integer AXI_LEN_LOW = 0;
localparam integer AXI_LEN_HIGH = AXI_LEN_LOW + AXI_LEN_BITW - 1;
localparam integer AXI_ID_LOW = AXI_LEN_HIGH + 1;
localparam integer AXI_ID_HIGH = AXI_ID_LOW + AXI_ID_BITW - 1;
localparam integer AXI_ADDR_LOW = META_BITW;
localparam integer AXI_ADDR_HIGH = AXI_ADDR_LOW + AXI_ADDR_BITW - 1;
// }}}
// BRAM Logger Instantiation {{{
logic LogTrigger_S;
assign LogTrigger_S = AxiValid_SI && AxiReady_SI;
logic [LOGGING_DATA_BITW-1:0] LogData_D;
always_comb begin
LogData_D = '0;
LogData_D[ AXI_LEN_HIGH: AXI_LEN_LOW] = AxiLen_DI;
LogData_D[ AXI_ID_HIGH: AXI_ID_LOW] = AxiId_DI;
LogData_D[AXI_ADDR_HIGH:AXI_ADDR_LOW] = AxiAddr_DI;
end
BramLogger #(
.LOG_DATA_BITW (LOGGING_DATA_BITW),
.NUM_LOG_ENTRIES (NUM_LOG_ENTRIES)
) bramLogger (
.Clk_CI (Clk_CI),
.TimestampClk_CI (TimestampClk_CI),
.Rst_RBI (Rst_RBI),
.LogData_DI (LogData_D),
.LogTrigger_SI (LogTrigger_S),
.Clear_SI (Clear_SI),
.LogEn_SI (LogEn_SI),
.Full_SO (Full_SO),
.Ready_SO (Ready_SO),
.Bram_PS (Bram_PS)
);
// }}}
endmodule
// vim: nosmartindent autoindent foldmethod=marker

View file

@ -0,0 +1,275 @@
// Copyright 2016 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/**
* AXI to AXI Lite Protocol Converter
*
* This module converts from AXI4 to AXI4 Lite by performing a simple ID reflection. It does not
* buffer multiple outstanding transactions; instead, a transaction is only accepted from the AXI
* master after the previous transaction has been completed by the AXI Lite slave.
*
* This module does NOT support bursts, because AXI Lite itself does not support bursts and
* converting AXI4 bursts into separate AXI Lite transactions is fairly involved (different burst
* types, alignment, etc.). If a burst is requested at the AXI4 slave interface, a slave error is
* returned and an assertion fails.
*
* For compatibility with Xilinx AXI Lite slaves, the AW and W channels are applied simultaneously
* at the output.
*
* Current Maintainers:
* - Andreas Kurth <akurth@iis.ee.ethz.ch>
* - Pirmin Vogel <vogelpi@iis.ee.ethz.ch>
*/
module AxiToAxiLitePc
// Parameters {{{
#(
parameter AXI_ADDR_WIDTH = 32,
parameter AXI_ID_WIDTH = 10
)
// }}}
// Ports {{{
(
input logic Clk_CI,
input logic Rst_RBI,
AXI_BUS.Slave Axi_PS,
AXI_LITE.Master AxiLite_PM
);
// }}}
// Signal Declarations {{{
logic [AXI_ID_WIDTH-1:0] ArId_DN, ArId_DP;
logic [AXI_ADDR_WIDTH-1:0] AwAddr_DN, AwAddr_DP;
logic [AXI_ID_WIDTH-1:0] AwId_DN, AwId_DP;
logic AwValid_DN, AwValid_DP;
enum logic [1:0] {RREADY, READ, RERR}
StateRead_SP, StateRead_SN;
enum logic [2:0] {WREADY, WRITE, WAITAWREADY, WAITWREADY, WRESP, WERRBEATS, WERRRESP}
StateWrite_SP, StateWrite_SN;
// }}}
// FSM to Control Handshaking Outputs for Write Channel and AW Latching. {{{
always_comb begin
// Default Assignments
AwAddr_DN = AwAddr_DP;
AwId_DN = AwId_DP;
Axi_PS.aw_ready = 1'b0;
Axi_PS.w_ready = 1'b0;
Axi_PS.b_resp = 2'b00;
Axi_PS.b_valid = 1'b0;
AxiLite_PM.aw_valid = 1'b0;
AxiLite_PM.w_valid = 1'b0;
AxiLite_PM.b_ready = 1'b0;
StateWrite_SN = StateWrite_SP;
case (StateWrite_SP)
WREADY: begin // Wait for aw_valid, latch address on encountering.
if (Axi_PS.aw_valid) begin
Axi_PS.aw_ready = 1'b1;
AwId_DN = Axi_PS.aw_id;
if (Axi_PS.aw_len != '0) begin // Burst length longer than 1 transfer,
StateWrite_SN = WERRBEATS; // which is not supported.
end else begin
AwAddr_DN = Axi_PS.aw_addr;
StateWrite_SN = WRITE;
end
end
end
WRITE: begin // Wait for w_valid, forward address and data on encountering.
if (Axi_PS.w_valid) begin
AxiLite_PM.aw_valid = 1'b1;
AxiLite_PM.w_valid = 1'b1;
if (AxiLite_PM.w_ready && AxiLite_PM.aw_ready) begin // Both AW and W channels fire.
Axi_PS.w_ready = 1'b1;
StateWrite_SN = WRESP;
end else if (AxiLite_PM.w_ready) begin // Only the W channel fires, the AW channel waits.
Axi_PS.w_ready = 1'b1;
StateWrite_SN = WAITAWREADY;
end else if (AxiLite_PM.aw_ready) begin // Only the AW channel fires, the W channel waits.
StateWrite_SN = WAITWREADY;
end
end
end
WAITAWREADY: begin // Wait for AW channel (the W channel already fired).
AxiLite_PM.aw_valid = 1'b1;
if (AxiLite_PM.aw_ready) begin
StateWrite_SN = WRESP;
end
end
WAITWREADY: begin // Wait for W channel (the AW channel already fired).
AxiLite_PM.w_valid = 1'b1;
if (AxiLite_PM.w_ready) begin
StateWrite_SN = WRESP;
end
end
// Connect B channel handshake signals and wait for it to fire before accepting the next
// transaction.
WRESP: begin
AxiLite_PM.b_ready = Axi_PS.b_ready;
Axi_PS.b_valid = AxiLite_PM.b_valid;
Axi_PS.b_resp = AxiLite_PM.b_resp;
if (Axi_PS.b_ready && AxiLite_PM.b_valid) begin
StateWrite_SN = WREADY;
end
end
// Absorb write beats of the unsupported burst.
WERRBEATS: begin
Axi_PS.w_ready = 1'b1;
if (Axi_PS.w_valid && Axi_PS.w_last) begin
StateWrite_SN = WERRRESP;
end
end
// Signal Slave Error on the B channel.
WERRRESP: begin
Axi_PS.b_resp = 2'b10; // SLVERR
Axi_PS.b_valid = 1'b1;
if (Axi_PS.b_ready) begin
StateWrite_SN = WREADY;
end
end
default: begin
StateWrite_SN = WREADY;
end
endcase
end
// }}}
// FSM to Control Handshaking Outputs for Read Channel and AR ID Latching. {{{
always_comb begin
// Default Assignments
ArId_DN = ArId_DP;
Axi_PS.ar_ready = 1'b0;
Axi_PS.r_resp = 2'b00;
Axi_PS.r_last = 1'b0;
Axi_PS.r_valid = 1'b0;
AxiLite_PM.ar_valid = 1'b0;
StateRead_SN = StateRead_SP;
case (StateRead_SP)
RREADY: begin // Wait for ar_valid, latch ID on encountering.
if (Axi_PS.ar_valid) begin
if (Axi_PS.ar_len != '0) begin // Burst length longer than 1 transfer,
StateRead_SN = RERR; // which is not supported.
ArId_DN = Axi_PS.ar_id;
Axi_PS.ar_ready = 1'b1;
end else begin
AxiLite_PM.ar_valid = Axi_PS.ar_valid;
if (AxiLite_PM.ar_ready) begin
Axi_PS.ar_ready = 1'b1;
ArId_DN = Axi_PS.ar_id;
StateRead_SN = READ;
end
end
end
end
READ: begin // Wait for r_valid, forward on encountering.
if (AxiLite_PM.r_valid) begin
Axi_PS.r_resp = AxiLite_PM.r_resp;
Axi_PS.r_last = 1'b1;
Axi_PS.r_valid = 1'b1;
if (Axi_PS.r_ready) begin
StateRead_SN = RREADY;
end
end
end
RERR: begin
Axi_PS.r_resp = 2'b10; // SLVERR
Axi_PS.r_last = 1'b1;
Axi_PS.r_valid = 1'b1;
if (Axi_PS.r_ready) begin
StateRead_SN = RREADY;
end
end
default: begin
StateRead_SN = RREADY;
end
endcase
end
// }}}
// Drive outputs of AXI Lite interface. {{{
assign AxiLite_PM.aw_addr = AwAddr_DP;
assign AxiLite_PM.w_data = Axi_PS.w_data;
assign AxiLite_PM.w_strb = Axi_PS.w_strb;
assign AxiLite_PM.ar_addr = Axi_PS.ar_addr;
assign AxiLite_PM.r_ready = Axi_PS.r_ready;
// }}}
// Drive outputs of AXI interface. {{{
assign Axi_PS.r_data = AxiLite_PM.r_data;
assign Axi_PS.r_id = ArId_DP;
assign Axi_PS.r_user = 'b0;
assign Axi_PS.b_id = AwId_DP;
assign Axi_PS.b_user = 'b0;
// }}}
// Flip-Flops {{{
always_ff @ (posedge Clk_CI)
begin
ArId_DP <= 'b0;
AwAddr_DP <= 'b0;
AwId_DP <= 'b0;
AwValid_DP <= 'b0;
StateRead_SP <= RREADY;
StateWrite_SP <= WREADY;
if (Rst_RBI) begin
ArId_DP <= ArId_DN;
AwAddr_DP <= AwAddr_DN;
AwId_DP <= AwId_DN;
AwValid_DP <= AwValid_DN;
StateRead_SP <= StateRead_SN;
StateWrite_SP <= StateWrite_SN;
end
end
// }}}
// Interface Assertions {{{
always @(posedge Clk_CI) begin
if (Rst_RBI) begin
assert (!(Axi_PS.aw_valid && Axi_PS.aw_len != '0))
else $error("Unsupported burst on AW channel!");
assert (!(Axi_PS.ar_valid && Axi_PS.ar_len != '0))
else $error("Unsupported burst on AR channel!");
end
end
// }}}
endmodule
// vim: nosmartindent autoindent foldmethod=marker

View file

@ -0,0 +1,151 @@
// Copyright 2016 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/**
* BRAM Data Width Converter
*
* This module performs data width conversion between a narrow master and a wide slave interface.
*
* Port Description:
* FromMaster_PS Slave BRAM Port interface through which master control signals go to the BRAM.
* ToSlave_PM Master BRAM Port interface at which the slave BRAM is connected.
*
* The data signal of the master interface must be narrower than that of the slave interface. The
* reverse situation would require handshaking and buffering and is not supported by the simple BRAM
* Port interface.
*
* Parameter Description:
* ADDR_BITW The width (in bits) of the address signals. Both ports must have the same
* address width.
* MST_DATA_BITW The width (in bits) of the data signal coming from the master controller.
* SLV_DATA_BITW The width (in bits) of the data signal of the slave BRAM.
*
* The value of all parameters must match the connected interfaces. DO NOT rely on the default
* values for these parameters, but explicitly set the parameters so that they are correct for your
* setup! If one or more values do not match, the behavior of this module is undefined.
*
* Compatibility Information:
* ModelSim >= 10.0b
* Vivado >= 2016.1
*
* Earlier versions of the tools are either untested or known to fail for this module.
*
* Current Maintainers:
* - Andreas Kurth <akurth@iis.ee.ethz.ch>
* - Pirmin Vogel <vogelpi@iis.ee.ethz.ch>
*/
import CfMath::ceil_div, CfMath::log2;
module BramDwc
// Parameters {{{
#(
parameter integer ADDR_BITW = 32,
parameter integer MST_DATA_BITW = 32,
parameter integer SLV_DATA_BITW = 96
)
// }}}
// Ports {{{
(
BramPort.Slave FromMaster_PS,
BramPort.Master ToSlave_PM
);
// }}}
// Module-Wide Constants {{{
localparam integer MST_DATA_BYTEW = MST_DATA_BITW/8;
localparam integer MST_ADDR_WORD_BITO = log2(MST_DATA_BYTEW);
localparam integer MST_ADDR_WORD_BITW = ADDR_BITW - MST_ADDR_WORD_BITO;
localparam integer SLV_DATA_BYTEW = SLV_DATA_BITW/8;
localparam integer SLV_ADDR_WORD_BITO = log2(SLV_DATA_BYTEW);
localparam integer SLV_ADDR_WORD_BITW = ADDR_BITW - SLV_ADDR_WORD_BITO;
localparam integer PAR_IDX_MAX_VAL = ceil_div(SLV_DATA_BITW, MST_DATA_BITW) - 1;
localparam integer PAR_IDX_BITW = log2(PAR_IDX_MAX_VAL+1);
// }}}
// Initial Assertions {{{
initial begin
assert (SLV_DATA_BITW >= MST_DATA_BITW)
else $fatal(1, "Downconversion of the data bitwidth from master to slave is not possible!");
assert (MST_DATA_BITW == FromMaster_PS.DATA_BITW)
else $fatal(1, "Parameter for data width of master does not match connected interface!");
assert (SLV_DATA_BITW == ToSlave_PM.DATA_BITW)
else $fatal(1, "Parameter for data width of slave does not match connected interface!");
assert ((ADDR_BITW == FromMaster_PS.ADDR_BITW) && (ADDR_BITW == ToSlave_PM.ADDR_BITW))
else $fatal(1, "Parameter for address width does not match connected interfaces!");
end
// }}}
// Register the Addr_S of master interface to make sure the address stays
// stable for word selection on reads
logic [ADDR_BITW-1:0] Addr_SN, Addr_SP;
assign Addr_SN = FromMaster_PS.Addr_S;
always_ff @ (posedge FromMaster_PS.Clk_C)
begin
if (FromMaster_PS.Rst_R == 1'b1) begin
Addr_SP <= 'b0;
end else if (FromMaster_PS.En_S == 1'b1) begin
Addr_SP <= Addr_SN;
end
end
// Pass clock, reset, and enable through. {{{
assign ToSlave_PM.Clk_C = FromMaster_PS.Clk_C;
assign ToSlave_PM.Rst_R = FromMaster_PS.Rst_R;
assign ToSlave_PM.En_S = FromMaster_PS.En_S;
// }}}
// Data Width Conversion {{{
logic [MST_ADDR_WORD_BITW-1:0] MstWordAddr_S, MstWordAddrReg_S;
assign MstWordAddr_S = Addr_SN[(MST_ADDR_WORD_BITW-1)+MST_ADDR_WORD_BITO:MST_ADDR_WORD_BITO];
assign MstWordAddrReg_S = Addr_SP[(MST_ADDR_WORD_BITW-1)+MST_ADDR_WORD_BITO:MST_ADDR_WORD_BITO];
logic [SLV_ADDR_WORD_BITW-1:0] ToWordAddr_S;
assign ToWordAddr_S = MstWordAddr_S / (PAR_IDX_MAX_VAL+1);
always_comb begin
ToSlave_PM.Addr_S = '0;
ToSlave_PM.Addr_S[(SLV_ADDR_WORD_BITW-1)+SLV_ADDR_WORD_BITO:SLV_ADDR_WORD_BITO] = ToWordAddr_S;
end
logic [PAR_IDX_BITW-1:0] ParIdxRd_S, ParIdxWr_S;
assign ParIdxWr_S = MstWordAddr_S % (PAR_IDX_MAX_VAL+1);
assign ParIdxRd_S = MstWordAddrReg_S % (PAR_IDX_MAX_VAL+1); // based on address applied with En_S
logic [PAR_IDX_MAX_VAL:0] [MST_DATA_BITW-1:0] Rd_D;
genvar p;
for (p = 0; p <= PAR_IDX_MAX_VAL; p++) begin
localparam integer SLV_BYTE_LOW = MST_DATA_BYTEW*p;
localparam integer SLV_BYTE_HIGH = SLV_BYTE_LOW + (MST_DATA_BYTEW-1);
localparam integer SLV_BIT_LOW = MST_DATA_BITW*p;
localparam integer SLV_BIT_HIGH = SLV_BIT_LOW + (MST_DATA_BITW-1);
always_comb begin
if (ParIdxWr_S == p) begin
ToSlave_PM.WrEn_S[SLV_BYTE_HIGH:SLV_BYTE_LOW] = FromMaster_PS.WrEn_S;
end else begin
ToSlave_PM.WrEn_S[SLV_BYTE_HIGH:SLV_BYTE_LOW] = '0;
end
end
assign Rd_D[p] = ToSlave_PM.Rd_D[SLV_BIT_HIGH:SLV_BIT_LOW];
assign ToSlave_PM.Wr_D[SLV_BIT_HIGH:SLV_BIT_LOW] = FromMaster_PS.Wr_D;
end
assign FromMaster_PS.Rd_D = Rd_D[ParIdxRd_S];
// }}}
endmodule
// vim: nosmartindent autoindent foldmethod=marker

View file

@ -0,0 +1,269 @@
// Copyright 2016 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/**
* BRAM Logger
*
* Module that logs timestamped events on a user-defined synchronous trigger and with user-defined
* meta data to a BRAM array.
*
* Port Description:
*
* Clk_CI All logging and control operations are synchronous to this clock.
* TimestampClk_CI The timestamp counter is synchronous to this clock.
* Rst_RBI Synchronous active-low reset for control logic and registers. Does NOT reset
* the cells of the internal BRAM.
*
* LogData_DI Meta data to be stored for each event.
* LogTrigger_SI If this signal is high during a rising edge of `Clk_CI` (and the logger is
* enabled), a log entry is added.
*
* Clear_SI Start signal to clear the internal BRAM.
* LogEn_SI Enables logging.
*
* Full_SO Active if the BRAM is nearly or completely full.
* Ready_SO Active if the logger is ready to log events. Inactive during clearing.
*
* Bram_PS Slave interface to access the internal BRAM (e.g., over AXI via an AXI BRAM
* Controller).
*
* In the BRAM, events are stored consecutively in multiple words each. The first word of a log
* entry is the 32-bit wide timestamp. All other words are defined by the user via `LogData_DI`.
*
* For the memory consumption by the internal BRAM, refer to the documentation of the employed BRAM
* module.
*
* During clearing, the logging memory is traversed sequentially. Thus, clearing takes
* `NUM_LOG_ENTRIES` clock cycles.
*
* Current Maintainers:
* - Andreas Kurth <akurth@iis.ee.ethz.ch>
* - Pirmin Vogel <vogelpi@iis.ee.ethz.ch>
*/
import CfMath::ceil_div, CfMath::log2;
module BramLogger
// Parameters {{{
#(
// Width (in bits) of one log data payload. Value should be a multiple of 32.
parameter LOG_DATA_BITW = 32,
// Number of entries in the log. Value must be >= 1024, should be a multiple of 1024, and is
// upper-bound by the available memory.
parameter NUM_LOG_ENTRIES = 16384
)
// }}}
// Ports {{{
(
input logic Clk_CI,
input logic TimestampClk_CI,
input logic Rst_RBI,
// Logging Input
input logic [LOG_DATA_BITW-1:0] LogData_DI,
input logic LogTrigger_SI,
// Control Input
input logic Clear_SI,
input logic LogEn_SI,
// Status Output
output logic Full_SO,
output logic Ready_SO,
// Interface to Internal BRAM
BramPort.Slave Bram_PS
);
// }}}
// Module-Wide Constants {{{
// Properties of the data entries in the log
localparam integer TIMESTAMP_BITW = 32;
localparam integer LOG_ENTRY_BITW = ceil_div(TIMESTAMP_BITW+LOG_DATA_BITW, 32) * 32;
localparam integer LOG_ENTRY_BYTEW = LOG_ENTRY_BITW / 8;
localparam integer TIMESTAMP_LOW = 0;
localparam integer TIMESTAMP_HIGH = TIMESTAMP_LOW + TIMESTAMP_BITW - 1;
localparam integer LOG_DATA_LOW = TIMESTAMP_HIGH + 1;
localparam integer LOG_DATA_HIGH = LOG_DATA_LOW + LOG_DATA_BITW - 1;
// Properties used when addressing the BRAM array
localparam integer LOGGING_CNT_BITW = log2(NUM_LOG_ENTRIES);
localparam integer LOGGING_CNT_MAX = NUM_LOG_ENTRIES-1;
localparam integer LOGGING_ADDR_WORD_BITO = log2(LOG_ENTRY_BYTEW);
localparam integer LOGGING_ADDR_BITW = LOGGING_CNT_BITW + LOGGING_ADDR_WORD_BITO;
// }}}
// Signal Declarations {{{
logic Rst_R;
enum reg [1:0] {READY, CLEARING, FULL}
State_SP, State_SN;
reg [LOGGING_CNT_BITW -1:0] WrCntA_SP, WrCntA_SN;
logic [LOG_ENTRY_BITW -1:0] WrA_D;
logic [LOG_ENTRY_BYTEW -1:0] WrEnA_S;
reg [TIMESTAMP_BITW-1:0] Timestamp_SP, Timestamp_SN;
// }}}
// Permanent Signal Assignments {{{
assign Rst_R = ~Rst_RBI;
// }}}
// Internal BRAM Interfaces {{{
BramPort #(
.DATA_BITW(LOG_ENTRY_BITW),
.ADDR_BITW(LOGGING_ADDR_BITW)
) BramLog_P ();
assign BramLog_P.Clk_C = Clk_CI;
assign BramLog_P.Rst_R = Rst_R;
assign BramLog_P.En_S = WrEnA_S;
always_comb begin
BramLog_P.Addr_S = '0;
BramLog_P.Addr_S[LOGGING_ADDR_BITW-1:0] = (WrCntA_SP << LOGGING_ADDR_WORD_BITO);
end
assign BramLog_P.Wr_D = WrA_D;
assign BramLog_P.WrEn_S = WrEnA_S;
BramPort #(
.DATA_BITW(LOG_ENTRY_BITW),
.ADDR_BITW(LOGGING_ADDR_BITW)
) BramDwc_P ();
// }}}
// Instantiation of True Dual-Port BRAM Array {{{
TdpBramArray #(
.DATA_BITW(LOG_ENTRY_BITW),
.NUM_ENTRIES(NUM_LOG_ENTRIES)
) bramArr (
.A_PS(BramLog_P),
.B_PS(BramDwc_P)
);
// }}}
// Instantiation of Data Width Converter {{{
BramDwc
#(
.ADDR_BITW (Bram_PS.ADDR_BITW),
.MST_DATA_BITW (32),
.SLV_DATA_BITW (LOG_ENTRY_BITW)
) bramDwc (
.FromMaster_PS(Bram_PS),
.ToSlave_PM (BramDwc_P)
);
// }}}
// Control FSM {{{
always_comb begin
// Default Assignments
Full_SO = 0;
Ready_SO = 0;
WrCntA_SN = WrCntA_SP;
WrEnA_S = '0;
State_SN = State_SP;
case (State_SP)
READY: begin
Ready_SO = 1;
if (LogEn_SI && LogTrigger_SI && ~Clear_SI) begin
WrCntA_SN = WrCntA_SP + 1;
WrEnA_S = '1;
end
// Raise "Full" output if BRAMs are nearly full (i.e., 1024 entries earlier).
if (WrCntA_SP >= (LOGGING_CNT_MAX-1024)) begin
Full_SO = 1;
end
if (WrCntA_SP == LOGGING_CNT_MAX) begin
State_SN = FULL;
end
if (Clear_SI && WrCntA_SP != 0) begin
WrCntA_SN = 0;
State_SN = CLEARING;
end
end
CLEARING: begin
WrCntA_SN = WrCntA_SP + 1;
WrEnA_S = '1;
if (WrCntA_SP == LOGGING_CNT_MAX) begin
WrCntA_SN = 0;
State_SN = READY;
end
end
FULL: begin
Full_SO = 1;
if (Clear_SI) begin
WrCntA_SN = 0;
State_SN = CLEARING;
end
end
endcase
end
// }}}
// Log Data Formatting {{{
always_comb begin
WrA_D = '0;
if (State_SP != CLEARING) begin
WrA_D[TIMESTAMP_HIGH:TIMESTAMP_LOW] = Timestamp_SP;
WrA_D[ LOG_DATA_HIGH: LOG_DATA_LOW] = LogData_DI;
end
end
// }}}
// Timestamp Counter {{{
always_comb
begin
Timestamp_SN = Timestamp_SP + 1;
if (Timestamp_SP == {TIMESTAMP_BITW{1'b1}}) begin
Timestamp_SN = 0;
end
end
// }}}
// Flip-Flops {{{
always_ff @ (posedge Clk_CI)
begin
State_SP <= READY;
WrCntA_SP <= 0;
if (Rst_RBI) begin
State_SP <= State_SN;
WrCntA_SP <= WrCntA_SN;
end
end
always_ff @ (posedge TimestampClk_CI)
begin
Timestamp_SP <= 0;
if (Rst_RBI) begin
Timestamp_SP <= Timestamp_SN;
end
end
// }}}
endmodule
// vim: nosmartindent autoindent foldmethod=marker

View file

@ -0,0 +1,62 @@
// Copyright 2016 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/**
* BRAM Port Interface
*
* This interface contains all signals required to connect a Block RAM.
*
* Parameter Description:
* DATA_BITW Width of the data ports in bits. Must be a multiple of 8.
* ADDR_BITW Width of the address port in bits. Must be a multiple of 8.
*
* Port Description:
* Clk_C All operations on this interface are synchronous to this single-phase clock port.
* Rst_R Synchronous reset for the output register/latch of the interface; does NOT reset the
* BRAM. Note that this reset is active high.
* En_S Enables read, write, and reset operations to through this interface.
* Addr_S Byte-wise address for all operations on this interface. Note that the word address
* offset varies with `DATA_BITW`!
* Rd_D Data output for read operations on the BRAM.
* Wr_D Data input for write operations on the BRAM.
* WrEn_S Byte-wise write enable.
*
* Current Maintainers:
* - Andreas Kurth <akurth@iis.ee.ethz.ch>
* - Pirmin Vogel <vogelpi@iis.ee.ethz.ch>
*/
interface BramPort
#(
parameter DATA_BITW = 32,
parameter ADDR_BITW = 32
);
logic Clk_C;
logic Rst_R;
logic En_S;
logic [ADDR_BITW-1:0] Addr_S;
logic [DATA_BITW-1:0] Rd_D;
logic [DATA_BITW-1:0] Wr_D;
logic [(DATA_BITW/8)-1:0] WrEn_S;
modport Slave (
input Clk_C, Rst_R, En_S, Addr_S, Wr_D, WrEn_S,
output Rd_D
);
modport Master (
input Rd_D,
output Clk_C, Rst_R, En_S, Addr_S, Wr_D, WrEn_S
);
endinterface
// vim: nosmartindent autoindent

View file

@ -0,0 +1,182 @@
// Copyright 2014 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/**
* Inferable, Synchronous Dual-Port RAM
*
* This module is designed to work with both Xilinx and Altera tools by following the respective
* guidelines:
* - Xilinx UG901 Vivado Design Suite User Guide: Synthesis (p. 106)
* - Altera Quartus II Handbook Volume 1: Design and Synthesis (p. 768)
*
* Current Maintainers:
* - Michael Schaffner <schaffer@iis.ee.ethz.ch>
*/
// this automatically switches the behavioral description
// pragma translate_off
`define SIMULATION
// pragma translate_on
module SyncDpRam
#(
parameter ADDR_WIDTH = 10,
parameter DATA_DEPTH = 1024, // usually 2**ADDR_WIDTH, but can be lower
parameter DATA_WIDTH = 32,
parameter OUT_REGS = 0,
parameter SIM_INIT = 0 // for simulation only, will not be synthesized
// 0: no init, 1: zero init, 2: random init
// note: on verilator, 2 is not supported. define the VERILATOR macro to work around.
)(
input logic Clk_CI,
input logic Rst_RBI,
// port A
input logic CSelA_SI,
input logic WrEnA_SI,
input logic [DATA_WIDTH-1:0] WrDataA_DI,
input logic [ADDR_WIDTH-1:0] AddrA_DI,
output logic [DATA_WIDTH-1:0] RdDataA_DO,
// port B
input logic CSelB_SI,
input logic WrEnB_SI,
input logic [DATA_WIDTH-1:0] WrDataB_DI,
input logic [ADDR_WIDTH-1:0] AddrB_DI,
output logic [DATA_WIDTH-1:0] RdDataB_DO
);
////////////////////////////
// signals, localparams
////////////////////////////
logic [DATA_WIDTH-1:0] RdDataA_DN;
logic [DATA_WIDTH-1:0] RdDataA_DP;
logic [DATA_WIDTH-1:0] RdDataB_DN;
logic [DATA_WIDTH-1:0] RdDataB_DP;
logic [DATA_WIDTH-1:0] Mem_DP [DATA_DEPTH-1:0];
////////////////////////////
// XILINX/ALTERA implementation
////////////////////////////
`ifdef SIMULATION
always_ff @(posedge Clk_CI)
begin
automatic logic [DATA_WIDTH-1:0] val;
if(Rst_RBI == 1'b0 && SIM_INIT>0) begin
for(int k=0; k<DATA_DEPTH;k++) begin
if(SIM_INIT==1) val = '0;
`ifndef VERILATOR
else if(SIM_INIT==2) void'(randomize(val));
`endif
Mem_DP[k] = val;
end
end else begin
if (CSelA_SI) begin
if (WrEnA_SI) begin
Mem_DP[AddrA_DI] <= WrDataA_DI;
end
else
begin
RdDataA_DN <= Mem_DP[AddrA_DI];
end
end
if (CSelB_SI) begin
if (WrEnB_SI) begin
Mem_DP[AddrB_DI] <= WrDataB_DI;
end
else
begin
RdDataB_DN <= Mem_DP[AddrB_DI];
end
end
end
end
`endif
////////////////////////////
// XILINX/ALTERA implementation
////////////////////////////
`ifndef SIMULATION
always_ff @(posedge Clk_CI)
begin
if (CSelA_SI) begin
if (WrEnA_SI) begin
Mem_DP[AddrA_DI] <= WrDataA_DI;
end
else
begin
RdDataA_DN <= Mem_DP[AddrA_DI];
end
end
end
always_ff @(posedge Clk_CI)
begin
if (CSelB_SI) begin
if (WrEnB_SI) begin
Mem_DP[AddrB_DI] <= WrDataB_DI;
end
else
begin
RdDataB_DN <= Mem_DP[AddrB_DI];
end
end
end
`endif
////////////////////////////
// optional output regs
////////////////////////////
// output regs
generate
if (OUT_REGS>0) begin : g_outreg
always_ff @(posedge Clk_CI or negedge Rst_RBI) begin
if(Rst_RBI == 1'b0)
begin
RdDataA_DP <= 0;
RdDataB_DP <= 0;
end
else
begin
RdDataA_DP <= RdDataA_DN;
RdDataB_DP <= RdDataB_DN;
end
end
end
endgenerate // g_outreg
// output reg bypass
generate
if (OUT_REGS==0) begin : g_oureg_byp
assign RdDataA_DP = RdDataA_DN;
assign RdDataB_DP = RdDataB_DN;
end
endgenerate// g_oureg_byp
assign RdDataA_DO = RdDataA_DP;
assign RdDataB_DO = RdDataB_DP;
////////////////////////////
// assertions
////////////////////////////
// pragma translate_off
assert property
(@(posedge Clk_CI) (longint'(2)**longint'(ADDR_WIDTH) >= longint'(DATA_DEPTH)))
else $error("depth out of bounds");
assert property
(@(posedge Clk_CI) (CSelA_SI & CSelB_SI & WrEnA_SI & WrEnB_SI) |-> (AddrA_DI != AddrB_DI))
else $error("A and B write to the same address");
// pragma translate_on
endmodule // SyncDpRam

View file

@ -0,0 +1,118 @@
// Copyright 2014 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/**
* Inferable, Synchronous Single-Port RAM
*
* This module is designed to work with both Xilinx and Altera tools by following the respective
* guidelines:
* - Xilinx UG901 Vivado Design Suite User Guide: Synthesis (p. 106)
* - Altera Quartus II Handbook Volume 1: Design and Synthesis (p. 768)
*
* Current Maintainers:
* - Michael Schaffner <schaffer@iis.ee.ethz.ch>
*/
module SyncSpRam
#(
parameter ADDR_WIDTH = 10,
parameter DATA_DEPTH = 1024, // usually 2**ADDR_WIDTH, but can be lower
parameter DATA_WIDTH = 32,
parameter OUT_REGS = 0,
parameter SIM_INIT = 0 // for simulation only, will not be synthesized
// 0: no init, 1: zero init, 2: random init
// note: on verilator, 2 is not supported. define the VERILATOR macro to work around.
)(
input logic Clk_CI,
input logic Rst_RBI,
input logic CSel_SI,
input logic WrEn_SI,
input logic [ADDR_WIDTH-1:0] Addr_DI,
input logic [DATA_WIDTH-1:0] WrData_DI,
output logic [DATA_WIDTH-1:0] RdData_DO
);
////////////////////////////
// signals, localparams
////////////////////////////
logic [DATA_WIDTH-1:0] RdData_DN;
logic [DATA_WIDTH-1:0] RdData_DP;
logic [DATA_WIDTH-1:0] Mem_DP [DATA_DEPTH-1:0];
////////////////////////////
// XILINX/ALTERA implementation
////////////////////////////
always_ff @(posedge Clk_CI)
begin
//pragma translate_off
automatic logic [DATA_WIDTH-1:0] val;
if(Rst_RBI == 1'b0 && SIM_INIT>0) begin
for(int k=0; k<DATA_DEPTH;k++) begin
if(SIM_INIT==1) val = '0;
`ifndef VERILATOR
else if(SIM_INIT==2) void'(randomize(val));
`endif
Mem_DP[k] = val;
end
end else
//pragma translate_on
if (CSel_SI) begin
if (WrEn_SI) begin
Mem_DP[Addr_DI] <= WrData_DI;
end
else
begin
RdData_DN <= Mem_DP[Addr_DI];
end
end
end
////////////////////////////
// optional output regs
////////////////////////////
// output regs
generate
if (OUT_REGS>0) begin : g_outreg
always_ff @(posedge Clk_CI or negedge Rst_RBI) begin
if(Rst_RBI == 1'b0)
begin
RdData_DP <= 0;
end
else
begin
RdData_DP <= RdData_DN;
end
end
end
endgenerate // g_outreg
// output reg bypass
generate
if (OUT_REGS==0) begin : g_oureg_byp
assign RdData_DP = RdData_DN;
end
endgenerate// g_oureg_byp
assign RdData_DO = RdData_DP;
////////////////////////////
// assertions
////////////////////////////
// pragma translate_off
assert property
(@(posedge Clk_CI) (longint'(2)**longint'(ADDR_WIDTH) >= longint'(DATA_DEPTH)))
else $error("depth out of bounds");
// pragma translate_on
endmodule // SyncSpRam

View file

@ -0,0 +1,168 @@
// Copyright 2014 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/**
* Inferable, Synchronous Single-Port N x 32bit RAM with Byte-Wise Enable
*
* This module contains an implementation for either Xilinx or Altera FPGAs. To synthesize for
* Xilinx, define `FPGA_TARGET_XILINX`. To synthesize for Altera, define `FPGA_TARGET_ALTERA`. The
* implementations follow the respective guidelines:
* - Xilinx UG901 Vivado Design Suite User Guide: Synthesis (p. 106)
* - Altera Quartus II Handbook Volume 1: Design and Synthesis (p. 768)
*
* Current Maintainers:
* - Michael Schaffner <schaffer@iis.ee.ethz.ch>
*/
`ifndef FPGA_TARGET_ALTERA
`define FPGA_TARGET_XILINX
`endif
module SyncSpRamBeNx32
#(
parameter ADDR_WIDTH = 10,
parameter DATA_DEPTH = 1024, // usually 2**ADDR_WIDTH, but can be lower
parameter OUT_REGS = 0, // set to 1 to enable outregs
parameter SIM_INIT = 0 // for simulation only, will not be synthesized
// 0: no init, 1: zero init, 2: random init, 3: deadbeef init
// note: on verilator, 2 is not supported. define the VERILATOR macro to work around.
)(
input logic Clk_CI,
input logic Rst_RBI,
input logic CSel_SI,
input logic WrEn_SI,
input logic [3:0] BEn_SI,
input logic [31:0] WrData_DI,
input logic [ADDR_WIDTH-1:0] Addr_DI,
output logic [31:0] RdData_DO
);
////////////////////////////
// signals, localparams
////////////////////////////
// needs to be consistent with the Altera implemenation below
localparam DATA_BYTES = 4;
logic [DATA_BYTES*8-1:0] RdData_DN;
logic [DATA_BYTES*8-1:0] RdData_DP;
////////////////////////////
// XILINX implementation
////////////////////////////
`ifdef FPGA_TARGET_XILINX
logic [DATA_BYTES*8-1:0] Mem_DP[DATA_DEPTH-1:0];
always_ff @(posedge Clk_CI) begin
//pragma translate_off
automatic logic [31:0] val;
if(Rst_RBI == 1'b0 && SIM_INIT>0) begin
for(int k=0; k<DATA_DEPTH;k++) begin
if(SIM_INIT==1) val = '0;
`ifndef VERILATOR
else if(SIM_INIT==2) void'(randomize(val));
`endif
else val = 32'hdeadbeef;
Mem_DP[k] = val;
end
end else
//pragma translate_on
if(CSel_SI) begin
if(WrEn_SI) begin
if(BEn_SI[0]) Mem_DP[Addr_DI][7:0] <= WrData_DI[7:0];
if(BEn_SI[1]) Mem_DP[Addr_DI][15:8] <= WrData_DI[15:8];
if(BEn_SI[2]) Mem_DP[Addr_DI][23:16] <= WrData_DI[23:16];
if(BEn_SI[3]) Mem_DP[Addr_DI][31:24] <= WrData_DI[31:24];
end
RdData_DN <= Mem_DP[Addr_DI];
end
end
`endif
////////////////////////////
// ALTERA implementation
////////////////////////////
`ifdef FPGA_TARGET_ALTERA
logic [DATA_BYTES-1:0][7:0] Mem_DP[0:DATA_DEPTH-1];
always_ff @(posedge Clk_CI) begin
//pragma translate_off
automatic logic [31:0] val;
if(Rst_RBI == 1'b0 && SIM_INIT>0) begin
for(int k=0; k<DATA_DEPTH;k++) begin
if(SIM_INIT==1) val = '0;
`ifndef VERILATOR
else if(SIM_INIT==2) void'(randomize(val));
`endif
else val = 32'hdeadbeef;
Mem_DP[k] = val;
end
end else
//pragma translate_on
if(CSel_SI) begin
if(WrEn_SI) begin // needs to be static, otherwise Altera wont infer it
if(BEn_SI[0]) Mem_DP[Addr_DI][0] <= WrData_DI[7:0];
if(BEn_SI[1]) Mem_DP[Addr_DI][1] <= WrData_DI[15:8];
if(BEn_SI[2]) Mem_DP[Addr_DI][2] <= WrData_DI[23:16];
if(BEn_SI[3]) Mem_DP[Addr_DI][3] <= WrData_DI[31:24];
end
RdData_DN <= Mem_DP[Addr_DI];
end
end
`endif
////////////////////////////
// optional output regs
////////////////////////////
// output regs
generate
if (OUT_REGS>0) begin : g_outreg
always_ff @(posedge Clk_CI or negedge Rst_RBI) begin
if(Rst_RBI == 1'b0)
begin
RdData_DP <= 0;
end
else
begin
RdData_DP <= RdData_DN;
end
end
end
endgenerate // g_outreg
// output reg bypass
generate
if (OUT_REGS==0) begin : g_oureg_byp
assign RdData_DP = RdData_DN;
end
endgenerate// g_oureg_byp
assign RdData_DO = RdData_DP;
////////////////////////////
// assertions
////////////////////////////
// pragma translate_off
assert property
(@(posedge Clk_CI) (longint'(2)**longint'(ADDR_WIDTH) >= longint'(DATA_DEPTH)))
else $error("depth out of bounds");
// pragma translate_on
`ifndef FPGA_TARGET_XILINX
`ifndef FPGA_TARGET_ALTERA
"FPGA target not defined, define FPGA_TARGET_XILINX or FPGA_TARGET_ALTERA."
`endif
`endif
endmodule // SyncSpRamBeNx32

View file

@ -0,0 +1,176 @@
// Copyright 2014 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/**
* Inferable, Synchronous Single-Port N x 64bit RAM with Byte-Wise Enable
*
* This module contains an implementation for either Xilinx or Altera FPGAs. To synthesize for
* Xilinx, define `FPGA_TARGET_XILINX`. To synthesize for Altera, define `FPGA_TARGET_ALTERA`. The
* implementations follow the respective guidelines:
* - Xilinx UG901 Vivado Design Suite User Guide: Synthesis (p. 106)
* - Altera Quartus II Handbook Volume 1: Design and Synthesis (p. 768)
*
* Current Maintainers:
* - Michael Schaffner <schaffer@iis.ee.ethz.ch>
*/
`ifndef FPGA_TARGET_ALTERA
`define FPGA_TARGET_XILINX
`endif
module SyncSpRamBeNx64
#(
parameter ADDR_WIDTH = 10,
parameter DATA_DEPTH = 1024, // usually 2**ADDR_WIDTH, but can be lower
parameter OUT_REGS = 0, // set to 1 to enable outregs
parameter SIM_INIT = 0 // for simulation only, will not be synthesized
// 0: no init, 1: zero init, 2: random init, 3: deadbeef init
// note: on verilator, 2 is not supported. define the VERILATOR macro to work around.
)(
input logic Clk_CI,
input logic Rst_RBI,
input logic CSel_SI,
input logic WrEn_SI,
input logic [7:0] BEn_SI,
input logic [63:0] WrData_DI,
input logic [ADDR_WIDTH-1:0] Addr_DI,
output logic [63:0] RdData_DO
);
////////////////////////////
// signals, localparams
////////////////////////////
// needs to be consistent with the Altera implemenation below
localparam DATA_BYTES = 8;
logic [DATA_BYTES*8-1:0] RdData_DN;
logic [DATA_BYTES*8-1:0] RdData_DP;
////////////////////////////
// XILINX implementation
////////////////////////////
`ifdef FPGA_TARGET_XILINX
logic [DATA_BYTES*8-1:0] Mem_DP[DATA_DEPTH-1:0];
always_ff @(posedge Clk_CI) begin
//pragma translate_off
automatic logic [63:0] val;
if(Rst_RBI == 1'b0 && SIM_INIT>0) begin
for(int k=0; k<DATA_DEPTH;k++) begin
if(SIM_INIT==1) val = '0;
`ifndef VERILATOR
else if(SIM_INIT==2) void'(randomize(val));
`endif
else val = 64'hdeadbeefdeadbeef;
Mem_DP[k] = val;
end
end else
//pragma translate_on
if(CSel_SI) begin
if(WrEn_SI) begin
if(BEn_SI[0]) Mem_DP[Addr_DI][7:0] <= WrData_DI[7:0];
if(BEn_SI[1]) Mem_DP[Addr_DI][15:8] <= WrData_DI[15:8];
if(BEn_SI[2]) Mem_DP[Addr_DI][23:16] <= WrData_DI[23:16];
if(BEn_SI[3]) Mem_DP[Addr_DI][31:24] <= WrData_DI[31:24];
if(BEn_SI[4]) Mem_DP[Addr_DI][39:32] <= WrData_DI[39:32];
if(BEn_SI[5]) Mem_DP[Addr_DI][47:40] <= WrData_DI[47:40];
if(BEn_SI[6]) Mem_DP[Addr_DI][55:48] <= WrData_DI[55:48];
if(BEn_SI[7]) Mem_DP[Addr_DI][63:56] <= WrData_DI[63:56];
end
RdData_DN <= Mem_DP[Addr_DI];
end
end
`endif
////////////////////////////
// ALTERA implementation
////////////////////////////
`ifdef FPGA_TARGET_ALTERA
logic [DATA_BYTES-1:0][7:0] Mem_DP[0:DATA_DEPTH-1];
always_ff @(posedge Clk_CI) begin
//pragma translate_off
automatic logic [63:0] val;
if(Rst_RBI == 1'b0 && SIM_INIT>0) begin
for(int k=0; k<DATA_DEPTH;k++) begin
if(SIM_INIT==1) val = '0;
`ifndef VERILATOR
else if(SIM_INIT==2) void'(randomize(val));
`endif
else val = 64'hdeadbeefdeadbeef;
Mem_DP[k] = val;
end
end else
//pragma translate_on
if(CSel_SI) begin
if(WrEn_SI) begin // needs to be static, otherwise Altera wont infer it
if(BEn_SI[0]) Mem_DP[Addr_DI][0] <= WrData_DI[7:0];
if(BEn_SI[1]) Mem_DP[Addr_DI][1] <= WrData_DI[15:8];
if(BEn_SI[2]) Mem_DP[Addr_DI][2] <= WrData_DI[23:16];
if(BEn_SI[3]) Mem_DP[Addr_DI][3] <= WrData_DI[31:24];
if(BEn_SI[4]) Mem_DP[Addr_DI][4] <= WrData_DI[39:32];
if(BEn_SI[5]) Mem_DP[Addr_DI][5] <= WrData_DI[47:40];
if(BEn_SI[6]) Mem_DP[Addr_DI][6] <= WrData_DI[55:48];
if(BEn_SI[7]) Mem_DP[Addr_DI][7] <= WrData_DI[63:56];
end
RdData_DN <= Mem_DP[Addr_DI];
end
end
`endif
////////////////////////////
// optional output regs
////////////////////////////
// output regs
generate
if (OUT_REGS>0) begin : g_outreg
always_ff @(posedge Clk_CI or negedge Rst_RBI) begin
if(Rst_RBI == 1'b0)
begin
RdData_DP <= 0;
end
else
begin
RdData_DP <= RdData_DN;
end
end
end
endgenerate // g_outreg
// output reg bypass
generate
if (OUT_REGS==0) begin : g_oureg_byp
assign RdData_DP = RdData_DN;
end
endgenerate// g_oureg_byp
assign RdData_DO = RdData_DP;
////////////////////////////
// assertions
////////////////////////////
// pragma translate_off
assert property
(@(posedge Clk_CI) (longint'(2)**longint'(ADDR_WIDTH) >= longint'(DATA_DEPTH)))
else $error("depth out of bounds");
// pragma translate_on
`ifndef FPGA_TARGET_XILINX
`ifndef FPGA_TARGET_ALTERA
$error("FPGA target not defined, define FPGA_TARGET_XILINX or FPGA_TARGET_ALTERA.");
`endif
`endif
endmodule // SyncSpRamBeNx64

View file

@ -0,0 +1,124 @@
// Copyright 2014 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/**
* Inferable, Synchronous Two-Port RAM
*
* This RAM has a dedicated read and a dedicated write port. When reading and writing from and to
* the same address in a single clock cycle, the read port returns the data before the write.
*
* This module is designed to work with both Xilinx and Altera tools by following the respective
* guidelines:
* - Xilinx UG901 Vivado Design Suite User Guide: Synthesis (p. 106)
* - Altera Quartus II Handbook Volume 1: Design and Synthesis (p. 768)
*
* Current Maintainers:
* - Michael Schaffner <schaffer@iis.ee.ethz.ch>
*/
module SyncTpRam
#(
parameter ADDR_WIDTH = 10,
parameter DATA_DEPTH = 1024, // usually 2**ADDR_WIDTH, but can be lower
parameter DATA_WIDTH = 32,
parameter OUT_REGS = 0,
parameter SIM_INIT = 0 // for simulation only, will not be synthesized
// 0: no init, 1: zero init, 2: random init
// note: on verilator, 2 is not supported. define the VERILATOR macro to work around.
)(
input logic Clk_CI,
input logic Rst_RBI,
input logic WrEn_SI,
input logic [ADDR_WIDTH-1:0] WrAddr_DI,
input logic [DATA_WIDTH-1:0] WrData_DI,
input logic RdEn_SI,
input logic [ADDR_WIDTH-1:0] RdAddr_DI,
output logic [DATA_WIDTH-1:0] RdData_DO
);
////////////////////////////
// signals, localparams
////////////////////////////
logic [DATA_WIDTH-1:0] RdData_DN;
logic [DATA_WIDTH-1:0] RdData_DP;
logic [DATA_WIDTH-1:0] Mem_DP [DATA_DEPTH-1:0];
////////////////////////////
// XILINX/ALTERA implementation
////////////////////////////
always_ff @(posedge Clk_CI)
begin
//pragma translate_off
automatic logic [DATA_WIDTH-1:0] val;
if(Rst_RBI == 1'b0 && SIM_INIT>0) begin
for(int k=0; k<DATA_DEPTH;k++) begin
if(SIM_INIT==1) val = '0;
`ifndef VERILATOR
else if(SIM_INIT==2) void'(randomize(val));
`endif
Mem_DP[k] = val;
end
end else begin
//pragma translate_on
if (RdEn_SI) begin
RdData_DN <= Mem_DP[RdAddr_DI];
end
if (WrEn_SI) begin
Mem_DP[WrAddr_DI] <= WrData_DI;
end
//pragma translate_off
`ifndef VERILATOR
end
`endif
//pragma translate_on
end
////////////////////////////
// optional output regs
////////////////////////////
// output regs
generate
if (OUT_REGS>0) begin : g_outreg
always_ff @(posedge Clk_CI or negedge Rst_RBI) begin
if(Rst_RBI == 1'b0)
begin
RdData_DP <= 0;
end
else
begin
RdData_DP <= RdData_DN;
end
end
end
endgenerate // g_outreg
// output reg bypass
generate
if (OUT_REGS==0) begin : g_oureg_byp
assign RdData_DP = RdData_DN;
end
endgenerate// g_oureg_byp
assign RdData_DO = RdData_DP;
////////////////////////////
// assertions
////////////////////////////
// pragma translate_off
assert property
(@(posedge Clk_CI) (longint'(2)**longint'(ADDR_WIDTH) >= longint'(DATA_DEPTH)))
else $error("depth out of bounds");
// pragma translate_on
endmodule // SyncTpRam

View file

@ -0,0 +1,403 @@
// Copyright 2016 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/**
* True Dual-Port BRAM Array for Xilinx 7 Series Devices
*
* This module contains a two-dimensional array of Xilinx' 7 Series True Dual-Port BRAM cells. The
* array is
* NUM_PAR_BRAMS = ceil(DATA_BITW/32)
* BRAMs wide and
* NUM_SER_BRAMS = ceil(NUM_ENTRIES/1024)
* BRAMs deep, as each BRAM is 32 bit wide and 1024 entries deep.
*
* This module is addressed byte-wise! Be careful when addressing a BRAM array that has more than
* one BRAM in parallel (i.e., when `DATA_BITW > 32`): the
* WORD_OFFSET = ceil(log2(DATA_BITW/8))
* least-significant bits of the address are used to address the bytes within a word. The reason
* for byte-wise addressing is to enable instances with a width that is a power of two (and >= 32)
* to directly connect to a Xilinx AXI 4 BRAM Controller. If you want to connect a BRAM that does
* not fulfill the direct connection criterion, use the Data Width Converter `BramDwc`.
*
* Even though addressing is byte-wise, accesses that are not aligned to words are not supported.
*
* Both ports can be operated independently and asynchronously; the behavior on access collisions is
* specified in the Xilinx Block Memory Generator Product Guide (PG058).
*
* Current Maintainers:
* - Andreas Kurth <akurth@iis.ee.ethz.ch>
* - Pirmin Vogel <vogelpi@iis.ee.ethz.ch>
*/
import CfMath::ceil_div, CfMath::log2;
module TdpBramArray
// Parameters {{{
#(
// Width (in bits) of the read/write data ports. Should be a multiple of 32 (for optimal
// resource usage) and is upper-bound by the available memory resources.
parameter DATA_BITW = 96,
// Number of entries (each entry is `DATA_BITW` bits wide) in the BRAM array. Should be
// a multiple of 1024 (for optimal resource usage) and is upper-bound by the available memory
// resources.
parameter NUM_ENTRIES = 8192
)
// }}}
// Ports {{{
(
BramPort.Slave A_PS,
BramPort.Slave B_PS
);
// }}}
// Module-Wide Constants {{{
// Properties of the employed BRAM cells
localparam integer BRAM_BITW = 32;
localparam integer BRAM_BYTEW = BRAM_BITW / 8;
localparam integer NUM_BRAM_WORDS = 1024;
// Properties of the resulting memory array
localparam integer NUM_PAR_BRAMS = ceil_div(DATA_BITW, BRAM_BITW);
localparam integer NUM_SER_BRAMS = ceil_div(NUM_ENTRIES, NUM_BRAM_WORDS);
localparam integer ARR_BITW = BRAM_BITW * NUM_PAR_BRAMS;
localparam integer ARR_BYTEW = BRAM_BYTEW * NUM_PAR_BRAMS;
localparam integer NUM_ARR_WORDS = NUM_BRAM_WORDS * NUM_SER_BRAMS;
// Offset (in bits) of words in the external addresses
localparam integer ADDR_WORD_BITO = log2(ARR_BYTEW);
localparam integer WORD_ADDR_BITW = log2(NUM_ARR_WORDS);
localparam integer SER_IDX_BITW = log2(NUM_SER_BRAMS);
localparam integer WORD_IDX_BITW = log2(NUM_BRAM_WORDS);
// }}}
// Signal Declarations {{{
// Output signals after multiplexing of parallel BRAM cells
logic [NUM_SER_BRAMS-1:0] [ARR_BITW -1:0] ARd_D, BRd_D;
// Word part of external address
logic [WORD_ADDR_BITW -1:0] WordAddrA_S, WordAddrB_S;
// Serial index of BRAM cell in array
logic [SER_IDX_BITW -1:0] SerIdxA_S, SerIdxB_S;
logic SerIdxAOverflow_S, SerIdxBOverflow_S;
// Word index in BRAM cell
logic [WORD_IDX_BITW -1:0] WordIdxA_S, WordIdxB_S;
// }}}
// Resolve (Linear) Address to Serial (BRAM), Word Index and Address of RAMs {{{
assign WordAddrA_S = A_PS.Addr_S[ADDR_WORD_BITO+(WORD_ADDR_BITW-1):ADDR_WORD_BITO];
assign WordAddrB_S = B_PS.Addr_S[ADDR_WORD_BITO+(WORD_ADDR_BITW-1):ADDR_WORD_BITO];
always_comb begin
SerIdxAOverflow_S = 0;
SerIdxA_S = WordAddrA_S / NUM_BRAM_WORDS;
if (SerIdxA_S >= NUM_SER_BRAMS) begin
SerIdxAOverflow_S = 1;
SerIdxA_S = 0;
end
end
always_comb begin
SerIdxBOverflow_S = 0;
SerIdxB_S = WordAddrB_S / NUM_BRAM_WORDS;
if (SerIdxB_S >= NUM_SER_BRAMS) begin
SerIdxBOverflow_S = 1;
SerIdxB_S = 0;
end
end
assign WordIdxA_S = WordAddrA_S % NUM_BRAM_WORDS;
assign WordIdxB_S = WordAddrB_S % NUM_BRAM_WORDS;
always @ (posedge A_PS.Clk_C) begin
if (A_PS.Rst_R == 0) begin
assert (~SerIdxAOverflow_S) else $warning("Serial index on port A out of bounds!");
assert (WordIdxA_S < NUM_BRAM_WORDS) else $error("Word index on port A out of bounds!");
end
end
always @ (posedge B_PS.Clk_C) begin
if (B_PS.Rst_R == 0) begin
assert (~SerIdxBOverflow_S) else $warning("Serial index on port B out of bounds!");
assert (WordIdxB_S < NUM_BRAM_WORDS) else $error("Word index on port B out of bounds!");
end
end
// }}}
// BRAM Instantiation, Signal Resolution, and Port Assignment {{{
genvar s, p;
for (s = 0; s < NUM_SER_BRAMS; s++) begin
for (p = 0; p < NUM_PAR_BRAMS; p++) begin
// Instance-Specific Constants {{{
localparam integer WORD_BIT_LOW = BRAM_BITW *p;
localparam integer WORD_BIT_HIGH = WORD_BIT_LOW + (BRAM_BITW -1);
localparam integer WORD_BYTE_LOW = BRAM_BYTEW*p;
localparam integer WORD_BYTE_HIGH = WORD_BYTE_LOW + (BRAM_BYTEW-1);
// }}}
// Write-Enable Resolution {{{
logic [BRAM_BYTEW-1:0] WrEnA_S, WrEnB_S;
always_comb begin
WrEnA_S = '0;
WrEnB_S = '0;
if (SerIdxA_S == s && ~SerIdxAOverflow_S) begin
WrEnA_S = A_PS.WrEn_S[WORD_BYTE_HIGH:WORD_BYTE_LOW];
end
if (SerIdxB_S == s && ~SerIdxBOverflow_S) begin
WrEnB_S = B_PS.WrEn_S[WORD_BYTE_HIGH:WORD_BYTE_LOW];
end
end
// }}}
// BRAM_TDP_MACRO Parameters and Initial Values {{{
// BRAM_TDP_MACRO: True Dual Port RAM
// Virtex-7
// Xilinx HDL Language Template, version 2016.1
BRAM_TDP_MACRO #(
// Target BRAM: {"18Kb", "36Kb"}
.BRAM_SIZE("36Kb"),
// Target Device: {"7SERIES"}
.DEVICE("7SERIES"),
// Optional Port A/B Output Registers: {0, 1}
.DOA_REG(0),
.DOB_REG(0),
// Initial Value of Port A/B Output
.INIT_A(36'h000000000),
.INIT_B(36'h000000000),
// RAM Initialization File
.INIT_FILE("NONE"),
// Width of Port A/B Output: 1..36 (19..36 only if BRAM_SIZE="36Kb")
.READ_WIDTH_A(BRAM_BITW),
.READ_WIDTH_B(BRAM_BITW),
// Enable Collision Check in Simulation: {"ALL", "WARNING_ONLY", "GENERATE_X_ONLY", "NONE"}
.SIM_COLLISION_CHECK ("ALL"),
// Set/Reset Value of Port A/B Output
.SRVAL_A(36'h00000000),
.SRVAL_B(36'h00000000),
// Write Mode of Port A/B {"WRITE_FIRST", "READ_FIRST", "NO_CHANGE"}
.WRITE_MODE_A("WRITE_FIRST"),
.WRITE_MODE_B("WRITE_FIRST"),
// Width of Port A/B Input: 1..36 (19..36 only if BRAM_SIZE="36Kb")
.WRITE_WIDTH_A(BRAM_BITW),
.WRITE_WIDTH_B(BRAM_BITW),
// Initialization of Data Bits in Lower 16 Kibit {{{
.INIT_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_07(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_08(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_09(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_0A(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_0B(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_0C(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_0D(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_0E(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_0F(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_10(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_11(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_12(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_13(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_14(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_15(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_16(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_17(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_18(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_19(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_1A(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_1B(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_1C(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_1D(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_1E(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_1F(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_20(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_21(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_22(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_23(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_24(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_25(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_26(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_27(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_28(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_29(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_2A(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_2B(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_2C(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_2D(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_2E(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_2F(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_30(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_31(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_32(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_33(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_34(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_35(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_36(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_37(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_38(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_39(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_3A(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_3B(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_3C(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_3D(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_3E(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_3F(256'h0000000000000000000000000000000000000000000000000000000000000000),
// }}}
// Initialization of Data Bits in Higher 16 Kibit {{{
// The next set of INIT_xx are valid when configured as 36Kb
.INIT_40(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_41(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_42(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_43(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_44(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_45(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_46(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_47(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_48(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_49(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_4A(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_4B(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_4C(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_4D(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_4E(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_4F(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_50(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_51(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_52(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_53(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_54(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_55(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_56(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_57(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_58(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_59(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_5A(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_5B(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_5C(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_5D(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_5E(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_5F(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_60(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_61(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_62(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_63(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_64(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_65(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_66(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_67(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_68(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_69(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_6A(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_6B(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_6C(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_6D(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_6E(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_6F(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_70(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_71(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_72(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_73(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_74(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_75(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_76(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_77(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_78(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_79(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_7A(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_7B(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_7C(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_7D(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_7E(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INIT_7F(256'h0000000000000000000000000000000000000000000000000000000000000000),
// }}}
// Initialization of Parity Bits in Lower 16 Kibit {{{
// The next set of INITP_xx are for the parity bits
.INITP_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INITP_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INITP_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INITP_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INITP_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INITP_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INITP_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INITP_07(256'h0000000000000000000000000000000000000000000000000000000000000000),
// }}}
// Initialization of Parity Bits in Higher 16 Kibit {{{
// The next set of INITP_xx are valid when configured as 36Kb
.INITP_08(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INITP_09(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INITP_0A(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INITP_0B(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INITP_0C(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INITP_0D(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INITP_0E(256'h0000000000000000000000000000000000000000000000000000000000000000),
.INITP_0F(256'h0000000000000000000000000000000000000000000000000000000000000000)
// }}}
)
// }}}
// BRAM_TDP_MACRO Instantation {{{
BRAM_TDP_MACRO_inst (
// Port A {{{
.CLKA (A_PS.Clk_C ), // 1-bit inp: clock
.RSTA (A_PS.Rst_R ), // 1-bit inp: reset (active high)
.ENA (A_PS.En_S ), // 1-bit inp: enable
.REGCEA (1'b0 ), // 1-bit inp: output register enable
.ADDRA (WordIdxA_S ), // 10-bit inp: word-wise address
.DOA (ARd_D[s] [WORD_BIT_HIGH:WORD_BIT_LOW] ), // 32-bit oup: data output
.DIA (A_PS.Wr_D[WORD_BIT_HIGH:WORD_BIT_LOW] ), // 32-bit inp: data input
.WEA (WrEnA_S ), // 4-bit inp: byte-wise write enable
// }}}
// Port B {{{
.CLKB (B_PS.Clk_C ), // 1-bit inp: clock
.RSTB (B_PS.Rst_R ), // 1-bit inp: reset (active high)
.ENB (B_PS.En_S ), // 1-bit inp: enable
.REGCEB (1'b0 ), // 1-bit inp: output register enable
.ADDRB (WordIdxB_S ), // 10-bit inp: word-wise address
.DOB (BRd_D[s] [WORD_BIT_HIGH:WORD_BIT_LOW] ), // 32-bit oup: data output
.DIB (B_PS.Wr_D[WORD_BIT_HIGH:WORD_BIT_LOW] ), // 32-bit inp: data input
.WEB (WrEnB_S ) // 4-bit inp: byte-wise write enable
// }}}
);
// }}}
end
end
// }}}
// Output Multiplexer {{{
assign A_PS.Rd_D = ARd_D[SerIdxA_S];
assign B_PS.Rd_D = BRd_D[SerIdxB_S];
// }}}
endmodule
// vim: nosmartindent autoindent foldmethod=marker

View file

@ -0,0 +1,5 @@
/*.jou
/*.log
/vivado.*
/vivado_pid*.str
/.Xil/*

View file

@ -0,0 +1,26 @@
VER = 2016.1
VIVADO_SOURCE_CMDS = -source scripts/setup.tcl -source scripts/synthesize.tcl
CF_MATH_PKG_PATH = ../../../../ips/pkg/cfmath
nogui: pkgdeps synth_nogui
gui: pkgdeps synth_gui
pkgdeps:
@if [ ! -e $(CF_MATH_PKG_PATH)/CfMath.sv ]; then \
echo "Error: Dependency 'CfMath.sv' not found, please specify 'CF_MATH_PKG_PATH'!"; \
exit 1; \
fi; \
ln -t deps/ -sf ../$(CF_MATH_PKG_PATH)/CfMath.sv
synth_nogui:
@vivado-${VER} vivado -mode batch $(VIVADO_SOURCE_CMDS)
synth_gui:
@vivado-${VER} vivado -mode gui $(VIVADO_SOURCE_CMDS)
clean:
@rm -f *.jou *.log vivado_*.str
@rm -rf vivado.*

View file

@ -0,0 +1,13 @@
# BRAM Data Width Converter Synthesis Testbench
## Running Tests
This module depends on the `CfMath` package. You have to specify the path to this package when
running tests. If this module is not used as part of the `big.pulp` project, specify the correct
path to the package in `CF_MATH_PKG_PATH`, e.g.,
CF_MATH_PKG_PATH=../../../../../fe/ips/pkg/cfmath make
## TODO
- Post-synthesis simulation

View file

@ -0,0 +1 @@
/CfMath.sv

View file

@ -0,0 +1,151 @@
// Copyright 2016 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/**
* BRAM Data Width Converter
*
* This module performs data width conversion between a narrow master and a wide slave interface.
*
* Port Description:
* FromMaster_PS Slave BRAM Port interface through which master control signals go to the BRAM.
* ToSlave_PM Master BRAM Port interface at which the slave BRAM is connected.
*
* The data signal of the master interface must be narrower than that of the slave interface. The
* reverse situation would require handshaking and buffering and is not supported by the simple BRAM
* Port interface.
*
* Parameter Description:
* ADDR_BITW The width (in bits) of the address signals. Both ports must have the same
* address width.
* MST_DATA_BITW The width (in bits) of the data signal coming from the master controller.
* SLV_DATA_BITW The width (in bits) of the data signal of the slave BRAM.
*
* The value of all parameters must match the connected interfaces. DO NOT rely on the default
* values for these parameters, but explicitly set the parameters so that they are correct for your
* setup! If one or more values do not match, the behavior of this module is undefined.
*
* Compatibility Information:
* ModelSim >= 10.0b
* Vivado >= 2016.1
*
* Earlier versions of the tools are either untested or known to fail for this module.
*
* Current Maintainers:
* - Andreas Kurth <akurth@iis.ee.ethz.ch>
* - Pirmin Vogel <vogelpi@iis.ee.ethz.ch>
*/
import CfMath::ceil_div, CfMath::log2;
module BramDwc
// Parameters {{{
#(
parameter integer ADDR_BITW = 32,
parameter integer MST_DATA_BITW = 32,
parameter integer SLV_DATA_BITW = 96
)
// }}}
// Ports {{{
(
BramPort.Slave FromMaster_PS,
BramPort.Master ToSlave_PM
);
// }}}
// Module-Wide Constants {{{
localparam integer MST_DATA_BYTEW = MST_DATA_BITW/8;
localparam integer MST_ADDR_WORD_BITO = log2(MST_DATA_BYTEW);
localparam integer MST_ADDR_WORD_BITW = ADDR_BITW - MST_ADDR_WORD_BITO;
localparam integer SLV_DATA_BYTEW = SLV_DATA_BITW/8;
localparam integer SLV_ADDR_WORD_BITO = log2(SLV_DATA_BYTEW);
localparam integer SLV_ADDR_WORD_BITW = ADDR_BITW - SLV_ADDR_WORD_BITO;
localparam integer PAR_IDX_MAX_VAL = ceil_div(SLV_DATA_BITW, MST_DATA_BITW) - 1;
localparam integer PAR_IDX_BITW = log2(PAR_IDX_MAX_VAL+1);
// }}}
// Initial Assertions {{{
initial begin
assert (SLV_DATA_BITW >= MST_DATA_BITW)
else $fatal(1, "Downconversion of the data bitwidth from master to slave is not possible!");
assert (MST_DATA_BITW == FromMaster_PS.DATA_BITW)
else $fatal(1, "Parameter for data width of master does not match connected interface!");
assert (SLV_DATA_BITW == ToSlave_PM.DATA_BITW)
else $fatal(1, "Parameter for data width of slave does not match connected interface!");
assert ((ADDR_BITW == FromMaster_PS.ADDR_BITW) && (ADDR_BITW == ToSlave_PM.ADDR_BITW))
else $fatal(1, "Parameter for address width does not match connected interfaces!");
end
// }}}
// Register the Addr_S of master interface to make sure the address stays
// stable for word selection on reads
logic [ADDR_BITW-1:0] Addr_SN, Addr_SP;
assign Addr_SN = FromMaster_PS.Addr_S;
always_ff @ (posedge FromMaster_PS.Clk_C)
begin
if (FromMaster_PS.Rst_R == 1'b1) begin
Addr_SP <= 'b0;
end else if (FromMaster_PS.En_S == 1'b1) begin
Addr_SP <= Addr_SN;
end
end
// Pass clock, reset, and enable through. {{{
assign ToSlave_PM.Clk_C = FromMaster_PS.Clk_C;
assign ToSlave_PM.Rst_R = FromMaster_PS.Rst_R;
assign ToSlave_PM.En_S = FromMaster_PS.En_S;
// }}}
// Data Width Conversion {{{
logic [MST_ADDR_WORD_BITW-1:0] MstWordAddr_S, MstWordAddrReg_S;
assign MstWordAddr_S = Addr_SN[(MST_ADDR_WORD_BITW-1)+MST_ADDR_WORD_BITO:MST_ADDR_WORD_BITO];
assign MstWordAddrReg_S = Addr_SP[(MST_ADDR_WORD_BITW-1)+MST_ADDR_WORD_BITO:MST_ADDR_WORD_BITO];
logic [SLV_ADDR_WORD_BITW-1:0] ToWordAddr_S;
assign ToWordAddr_S = MstWordAddr_S / (PAR_IDX_MAX_VAL+1);
always_comb begin
ToSlave_PM.Addr_S = '0;
ToSlave_PM.Addr_S[(SLV_ADDR_WORD_BITW-1)+SLV_ADDR_WORD_BITO:SLV_ADDR_WORD_BITO] = ToWordAddr_S;
end
logic [PAR_IDX_BITW-1:0] ParIdxRd_S, ParIdxWr_S;
assign ParIdxWr_S = MstWordAddr_S % (PAR_IDX_MAX_VAL+1);
assign ParIdxRd_S = MstWordAddrReg_S % (PAR_IDX_MAX_VAL+1); // based on address applied with En_S
logic [PAR_IDX_MAX_VAL:0] [MST_DATA_BITW-1:0] Rd_D;
genvar p;
for (p = 0; p <= PAR_IDX_MAX_VAL; p++) begin
localparam integer SLV_BYTE_LOW = MST_DATA_BYTEW*p;
localparam integer SLV_BYTE_HIGH = SLV_BYTE_LOW + (MST_DATA_BYTEW-1);
localparam integer SLV_BIT_LOW = MST_DATA_BITW*p;
localparam integer SLV_BIT_HIGH = SLV_BIT_LOW + (MST_DATA_BITW-1);
always_comb begin
if (ParIdxWr_S == p) begin
ToSlave_PM.WrEn_S[SLV_BYTE_HIGH:SLV_BYTE_LOW] = FromMaster_PS.WrEn_S;
end else begin
ToSlave_PM.WrEn_S[SLV_BYTE_HIGH:SLV_BYTE_LOW] = '0;
end
end
assign Rd_D[p] = ToSlave_PM.Rd_D[SLV_BIT_HIGH:SLV_BIT_LOW];
assign ToSlave_PM.Wr_D[SLV_BIT_HIGH:SLV_BIT_LOW] = FromMaster_PS.Wr_D;
end
assign FromMaster_PS.Rd_D = Rd_D[ParIdxRd_S];
// }}}
endmodule
// vim: nosmartindent autoindent foldmethod=marker

View file

@ -0,0 +1,62 @@
// Copyright 2016 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/**
* BRAM Port Interface
*
* This interface contains all signals required to connect a Block RAM.
*
* Parameter Description:
* DATA_BITW Width of the data ports in bits. Must be a multiple of 8.
* ADDR_BITW Width of the address port in bits. Must be a multiple of 8.
*
* Port Description:
* Clk_C All operations on this interface are synchronous to this single-phase clock port.
* Rst_R Synchronous reset for the output register/latch of the interface; does NOT reset the
* BRAM. Note that this reset is active high.
* En_S Enables read, write, and reset operations to through this interface.
* Addr_S Byte-wise address for all operations on this interface. Note that the word address
* offset varies with `DATA_BITW`!
* Rd_D Data output for read operations on the BRAM.
* Wr_D Data input for write operations on the BRAM.
* WrEn_S Byte-wise write enable.
*
* Current Maintainers:
* - Andreas Kurth <akurth@iis.ee.ethz.ch>
* - Pirmin Vogel <vogelpi@iis.ee.ethz.ch>
*/
interface BramPort
#(
parameter DATA_BITW = 32,
parameter ADDR_BITW = 32
);
logic Clk_C;
logic Rst_R;
logic En_S;
logic [ADDR_BITW-1:0] Addr_S;
logic [DATA_BITW-1:0] Rd_D;
logic [DATA_BITW-1:0] Wr_D;
logic [(DATA_BITW/8)-1:0] WrEn_S;
modport Slave (
input Clk_C, Rst_R, En_S, Addr_S, Wr_D, WrEn_S,
output Rd_D
);
modport Master (
input Rd_D,
output Clk_C, Rst_R, En_S, Addr_S, Wr_D, WrEn_S
);
endinterface
// vim: nosmartindent autoindent

View file

@ -0,0 +1,15 @@
# Create project.
create_project vivado . -force -part xc7vx485tffg1157-1
# Downgrade warning about "ignoring assertions" to information.
set_msg_config -id {[Synth 8-2898]} -new_severity "info"
# Add source files to project.
add_files -norecurse -scan_for_includes [glob ./deps/*]
add_files -norecurse -scan_for_includes [glob ./src/*]
# Define top-level module.
set_property top Top [current_fileset]
# Update compile order (must do if in batch mode).
update_compile_order -fileset [current_fileset]

View file

@ -0,0 +1 @@
synth_design -name synth_1

View file

@ -0,0 +1,44 @@
`timescale 1ns / 1ps
module Top;
localparam integer ADDR_BITW = 32;
localparam integer MST_DATA_BITW = 32;
localparam integer SLV_DATA_BITW = 96;
BramPort
#(
.DATA_BITW(MST_DATA_BITW),
.ADDR_BITW(ADDR_BITW)
)
fromMaster ();
BramPort
#(
.DATA_BITW(SLV_DATA_BITW),
.ADDR_BITW(ADDR_BITW)
)
toSlave ();
BramDwc
#(
.ADDR_BITW (ADDR_BITW),
.MST_DATA_BITW (MST_DATA_BITW),
.SLV_DATA_BITW (SLV_DATA_BITW)
) dwc (
.FromMaster_PS (fromMaster),
.ToSlave_PM (toSlave)
);
assign fromMaster.Clk_C = '0;
assign fromMaster.Rst_R = '0;
assign fromMaster.En_S = '0;
assign fromMaster.Addr_S = '0;
assign fromMaster.Wr_D = '0;
assign fromMaster.WrEn_S = '0;
assign toSlave.Rd_D = '0;
endmodule
// vim: nosmartindent autoindent

View file

@ -0,0 +1,26 @@
VER = 2016.1
VIVADO_SOURCE_CMDS = -source scripts/setup.tcl -source scripts/synthesize.tcl
CF_MATH_PKG_PATH = ../../../../ips/pkg/cfmath
nogui: pkgdeps synth_nogui
gui: pkgdeps synth_gui
pkgdeps:
@if [ ! -e $(CF_MATH_PKG_PATH)/CfMath.sv ]; then \
echo "Error: Dependency 'CfMath.sv' not found, please specify 'CF_MATH_PKG_PATH'!"; \
exit 1; \
fi; \
ln -t deps/ -sf ../$(CF_MATH_PKG_PATH)/CfMath.sv
synth_nogui:
@vivado-${VER} vivado -mode batch $(VIVADO_SOURCE_CMDS)
synth_gui:
@vivado-${VER} vivado -mode gui $(VIVADO_SOURCE_CMDS)
clean:
@rm -f *.jou *.log vivado_*.str
@rm -rf vivado.*

View file

@ -0,0 +1,5 @@
/*.jou
/*.log
/vivado.*
/vivado_pid*.str
/.Xil/*

View file

@ -0,0 +1,15 @@
# Create project.
create_project vivado . -force -part xc7vx485tffg1157-1
# Downgrade warning about "ignoring assertions" to information.
set_msg_config -id {[Synth 8-2898]} -new_severity "info"
# Add source files to project.
add_files -norecurse -scan_for_includes [glob ./deps/*]
add_files -norecurse -scan_for_includes [glob ./src/*]
# Define top-level module.
set_property top Top [current_fileset]
# Update compile order (must do if in batch mode).
update_compile_order -fileset [current_fileset]

View file

@ -0,0 +1 @@
synth_design -name synth_1

View file

@ -0,0 +1,14 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// This file is generated by the util/vendor script. Please do not modify it
// manually.
{
upstream:
{
url: https://github.com/pulp-platform/fpga-support.git
rev: a3ba269c0fc6cfcee6f81e5d9af018a08e479d2b
}
}

View file

@ -0,0 +1,30 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2023 Thales Silicon Security SAS
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0.
// Original Author: Zbigniew Chamski (zbigniew.chamski@thalesgroup.com)
{
// Name of the project
name: "pulp_fpga-support",
// Target directory: relative to the location of this script.
target_dir: "pulp-platform/fpga-support",
// Upstream repository
upstream: {
// URL
url: "https://github.com/pulp-platform/fpga-support.git",
// revision
rev: "a3ba269c0fc6cfcee6f81e5d9af018a08e479d2b",
}
// Patch dir for local changes
patch_dir: "patches/pulp-platform/fpga-support",
// Exclusions from upstream content
exclude_from_upstream: [
"ci",
".editorconfig",
"src_files.yml",
]
}