Files
common/rtl/cdc/async_reqack.sv
T
maksyuki a542f1ee57 feat: enhance validation and error handling in RTL modules
- Added geometry validation for BIT_WIDTH, WORD_DEPTH, and ADDR_WIDTH in tech_ram, tech_ram_bm, tech_regfile, and tech_regfile_bm modules to ensure proper configurations.
- Implemented address range checks in tech_ram, tech_ram_bm, tech_regfile, and tech_regfile_bm modules to prevent out-of-bounds access.
- Improved error messages for unsupported access types in regfield module, including validation for DATA_WIDTH.
- Added DATA_WIDTH validation in spill_register module to ensure positive values.
- Refactored APB4AXI4Master and APB4Master classes to streamline constructor definitions and improve readability.
- Enhanced AXI4Master class with additional burst address calculations and legality checks for read/write operations.
- Updated read/write tasks in AXI4Master to include error handling for response mismatches and illegal burst conditions.
- Simplified the filtering of reference data in rd_check task of AXI4Master to improve clarity and maintainability.
- Cleaned up the TestBase class constructor for consistency and clarity.
2026-08-03 20:10:19 +08:00

148 lines
4.9 KiB
Systemverilog

// Copyright 2018-2024 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51. You may obtain a copy at
// http://solderpad.org/licenses/SHL-0.51.
//
// Derived design work: Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// SPDX-License-Identifier: SHL-0.51
// Design independently implemented for common; see NOTICE for attribution.
// A four-phase, one-entry asynchronous mailbox. Data is held stable by the
// source until the destination has acknowledged it; only the request and
// acknowledgement controls cross synchronizers. Reset on either side aborts
// an in-flight item and restarts the link from the empty state.
module async_reqack #(
parameter int DATA_WIDTH = 32,
parameter int SYNC_STAGES = 2
) (
input logic src_clk_i,
input logic src_rst_n_i,
input logic src_valid_i,
output logic src_ready_o,
input logic [DATA_WIDTH-1:0] src_data_i,
input logic dst_clk_i,
input logic dst_rst_n_i,
output logic dst_valid_o,
input logic dst_ready_i,
output logic [DATA_WIDTH-1:0] dst_data_o
);
logic [DATA_WIDTH-1:0] r_payload;
logic r_request;
logic r_busy;
logic r_acknowledge;
logic s_ack_src;
logic s_req_dst;
logic s_link_rst_n;
logic s_src_rst_n;
logic s_dst_rst_n;
initial begin
if (DATA_WIDTH < 1 || SYNC_STAGES < 2) begin
$fatal(1, "async_reqack: DATA_WIDTH must be positive and SYNC_STAGES at least two");
end
end
// A four-phase protocol cannot recover a unilateral reset safely: one side
// could otherwise interpret a stale request or acknowledgement as a new
// transaction. A reset in either domain therefore flushes the mailbox.
assign s_link_rst_n = src_rst_n_i && dst_rst_n_i;
cdc_reset_barrier #(
.STAGES(SYNC_STAGES)
) u_reset_barrier (
.clk_a_i (src_clk_i),
.clk_b_i (dst_clk_i),
.rst_n_i (s_link_rst_n),
.release_i(1'b1),
.rst_a_n_o(s_src_rst_n),
.rst_b_n_o(s_dst_rst_n)
);
cdc_sync #(
.STAGE(SYNC_STAGES)
) u_ack_sync (
.clk_i (src_clk_i),
.rst_n_i(s_src_rst_n),
.dat_i (r_acknowledge),
.dat_o (s_ack_src)
);
cdc_sync #(
.STAGE(SYNC_STAGES)
) u_req_sync (
.clk_i (dst_clk_i),
.rst_n_i(s_dst_rst_n),
.dat_i (r_request),
.dat_o (s_req_dst)
);
assign src_ready_o = s_src_rst_n && !r_busy;
// A request stays asserted until the four-phase return-to-zero completes.
// Suppress valid after its first destination handshake so a continuously
// ready consumer cannot accept the same item again.
assign dst_valid_o = s_dst_rst_n && s_req_dst && !r_acknowledge;
assign dst_data_o = r_payload;
always_ff @(posedge src_clk_i or negedge s_src_rst_n) begin
if (!s_src_rst_n) begin
r_payload <= '0;
r_request <= 1'b0;
r_busy <= 1'b0;
end else if (!r_busy && src_valid_i) begin
r_payload <= src_data_i;
r_request <= 1'b1;
r_busy <= 1'b1;
end else if (r_busy && r_request && s_ack_src) begin
r_request <= 1'b0;
end else if (r_busy && !r_request && !s_ack_src) begin
r_busy <= 1'b0;
end
end
always_ff @(posedge dst_clk_i or negedge s_dst_rst_n) begin
if (!s_dst_rst_n) begin
r_acknowledge <= 1'b0;
end else begin
if (!s_req_dst) begin
r_acknowledge <= 1'b0;
end else if (!r_acknowledge && dst_ready_i) begin
r_acknowledge <= 1'b1;
end
end
end
endmodule
// Named wrapper for the gray-pointer asynchronous queue. Keeping this wrapper
// avoids parallel implementations and makes the preferred public API explicit.
module async_gray_queue #(
parameter int DATA_WIDTH = 32,
parameter int BUFFER_DEPTH = 8,
parameter int SYNC_STAGES = 2
) (
input logic src_clk_i,
input logic src_rst_n_i,
input logic [DATA_WIDTH-1:0] src_data_i,
input logic src_valid_i,
output logic src_ready_o,
input logic dst_clk_i,
input logic dst_rst_n_i,
output logic [DATA_WIDTH-1:0] dst_data_o,
output logic dst_valid_o,
input logic dst_ready_i
);
cdc_fifo #(
.DATA_WIDTH (DATA_WIDTH),
.BUFFER_DEPTH(BUFFER_DEPTH),
.SYNC_STAGES (SYNC_STAGES)
) u_cdc_fifo (
.src_clk_i (src_clk_i),
.src_rst_n_i(src_rst_n_i),
.src_data_i (src_data_i),
.src_valid_i(src_valid_i),
.src_ready_o(src_ready_o),
.dst_clk_i (dst_clk_i),
.dst_rst_n_i(dst_rst_n_i),
.dst_data_o (dst_data_o),
.dst_valid_o(dst_valid_o),
.dst_ready_i(dst_ready_i)
);
endmodule