mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
Integrate RNG, CRC, WS2812, Crypto, I2S master and the SDIO private AXI owner on SAFE24. Preserve the 128 KiB main SRAM and six private Crypto macros, add product-specific DMA assignments and reject unsupported SDK operations.
Correct APB read strobes, I2S receive assembly and SDIO command timing, backpressure and descriptor retirement. Add pin-level workloads, source-bound evidence checks and publication/commercial consumer compatibility.
Validation of the final P6 worktree: 1726 pytest tests passed with one optional pypdf skip (exit 0, 4021.61 seconds; terminal session 36439). Both PDKs passed both RTL simulators, netlist boot and 38-macro binding checks. Shared formal, Mini compatibility and software/source quality gates passed.
Evidence remains attributed to the retained dirty-worktree snapshots based on b3b30a72cd under build/ics55-tiny-2026-10-12-11-50-2eb98c0e1fae/meta/tiny-r2-p6/. Timing is negative and warning observations are not promoted. This commit does not accept P6, qualify physical operation or enable P7.
214 lines
5.8 KiB
Systemverilog
214 lines
5.8 KiB
Systemverilog
// Copyright (c) 2026 Yuchi Miao
|
|
// SPDX-License-Identifier: MulanPSL-2.0
|
|
`include "mmap_define.svh"
|
|
|
|
// APB setup/access are separate cycles; rejected bursts never assert PSEL.
|
|
module tiny_axi42apb4 (
|
|
input logic clk_i,
|
|
input logic rst_n_i,
|
|
axi4_if.slave axi4,
|
|
apb4_if.master apb4
|
|
);
|
|
typedef enum logic [2:0] {
|
|
Idle,
|
|
WriteData,
|
|
Setup,
|
|
Access,
|
|
ReadResponse,
|
|
WriteResponse,
|
|
ReadError,
|
|
WriteError
|
|
} state_e;
|
|
state_e s_state_d, s_state_q;
|
|
logic [2:0] s_state_bits_q;
|
|
logic [31:0] s_addr_d, s_addr_q;
|
|
logic [31:0] s_wdata_d, s_wdata_q;
|
|
logic [31:0] s_data_d, s_data_q;
|
|
logic [3:0] s_wstrb_d, s_wstrb_q;
|
|
logic s_id_d, s_id_q;
|
|
logic s_write_d, s_write_q;
|
|
logic [1:0] s_resp_d, s_resp_q;
|
|
logic [7:0] s_len_d, s_len_q;
|
|
logic [7:0] s_beat_d, s_beat_q;
|
|
logic s_access, s_enable, s_done, s_err;
|
|
logic [31:0] s_read_data;
|
|
|
|
assign s_state_q = state_e'(s_state_bits_q);
|
|
assign axi4.arready = s_state_q == Idle;
|
|
assign axi4.awready = (s_state_q == Idle) && !axi4.arvalid;
|
|
assign axi4.wready = (s_state_q == WriteData) || (s_state_q == WriteError);
|
|
assign axi4.bid = s_id_q;
|
|
assign axi4.bresp = s_resp_q;
|
|
assign axi4.buser = '0;
|
|
assign axi4.bvalid = s_state_q == WriteResponse;
|
|
assign axi4.rid = s_id_q;
|
|
assign axi4.rdata = s_data_q;
|
|
assign axi4.rresp = s_resp_q;
|
|
assign axi4.ruser = '0;
|
|
assign axi4.rlast = s_beat_q == s_len_q;
|
|
assign axi4.rvalid = (s_state_q == ReadResponse) || (s_state_q == ReadError);
|
|
assign s_access = (s_state_q == Setup) || (s_state_q == Access);
|
|
assign s_enable = s_state_q == Access;
|
|
// The fabric owns peripheral decoding. Each bridge owns only this APB
|
|
// endpoint, including its setup/access and retained response state.
|
|
assign s_done = apb4.pready;
|
|
assign s_err = apb4.pslverr;
|
|
assign s_read_data = apb4.prdata;
|
|
assign apb4.paddr = s_addr_q;
|
|
assign apb4.pwrite = s_write_q;
|
|
assign apb4.pwdata = s_wdata_q;
|
|
assign apb4.pstrb = s_write_q ? s_wstrb_q : 4'd0;
|
|
assign apb4.pprot = 3'd0;
|
|
assign apb4.psel = s_access;
|
|
assign apb4.penable = s_enable;
|
|
|
|
always_comb begin
|
|
s_state_d = s_state_q;
|
|
s_addr_d = s_addr_q;
|
|
s_wdata_d = s_wdata_q;
|
|
s_wstrb_d = s_wstrb_q;
|
|
s_id_d = s_id_q;
|
|
s_write_d = s_write_q;
|
|
s_resp_d = s_resp_q;
|
|
s_data_d = s_data_q;
|
|
s_len_d = s_len_q;
|
|
s_beat_d = s_beat_q;
|
|
unique case (s_state_q)
|
|
Idle: begin
|
|
s_beat_d = '0;
|
|
s_data_d = '0;
|
|
s_resp_d = 2'b00;
|
|
if (axi4.arvalid) begin
|
|
s_addr_d = axi4.araddr;
|
|
s_id_d = axi4.arid;
|
|
s_write_d = 1'b0;
|
|
s_len_d = axi4.arlen;
|
|
if ((axi4.arlen != 8'd0) || (axi4.arburst[1]) || axi4.arlock ||
|
|
(axi4.arsize > 3'd2) || (axi4.araddr[1:0] != 2'd0)) begin
|
|
s_resp_d = 2'b10;
|
|
s_state_d = ReadError;
|
|
end else s_state_d = Setup;
|
|
end else if (axi4.awvalid) begin
|
|
s_addr_d = axi4.awaddr;
|
|
s_id_d = axi4.awid;
|
|
s_write_d = 1'b1;
|
|
s_len_d = axi4.awlen;
|
|
if ((axi4.awlen != 8'd0) || (axi4.awburst[1]) || axi4.awlock ||
|
|
(axi4.awsize > 3'd2) || (axi4.awaddr[1:0] != 2'd0)) begin
|
|
s_resp_d = 2'b10;
|
|
s_state_d = WriteError;
|
|
end else s_state_d = WriteData;
|
|
end
|
|
end
|
|
WriteData:
|
|
if (axi4.wvalid) begin
|
|
s_wdata_d = axi4.wdata;
|
|
s_wstrb_d = axi4.wstrb;
|
|
if (!axi4.wlast) begin
|
|
s_resp_d = 2'b10;
|
|
s_state_d = WriteResponse;
|
|
end else s_state_d = Setup;
|
|
end
|
|
Setup: s_state_d = Access;
|
|
Access:
|
|
if (s_done) begin
|
|
s_resp_d = s_err ? 2'b10 : 2'b00;
|
|
s_data_d = s_read_data;
|
|
s_state_d = s_write_q ? WriteResponse : ReadResponse;
|
|
end
|
|
ReadResponse, ReadError:
|
|
if (axi4.rready) begin
|
|
if (s_beat_q == s_len_q) s_state_d = Idle;
|
|
else s_beat_d = s_beat_q + 8'd1;
|
|
end
|
|
WriteResponse: if (axi4.bready) s_state_d = Idle;
|
|
WriteError:
|
|
if (axi4.wvalid) begin
|
|
if (s_beat_q == s_len_q) s_state_d = WriteResponse;
|
|
else s_beat_d = s_beat_q + 8'd1;
|
|
end
|
|
default: s_state_d = Idle;
|
|
endcase
|
|
end
|
|
dffr #(
|
|
.DATA_WIDTH(3)
|
|
) u_state_reg (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.dat_i (s_state_d),
|
|
.dat_o (s_state_bits_q)
|
|
);
|
|
dffr #(
|
|
.DATA_WIDTH(32)
|
|
) u_addr_reg (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.dat_i (s_addr_d),
|
|
.dat_o (s_addr_q)
|
|
);
|
|
dffr #(
|
|
.DATA_WIDTH(32)
|
|
) u_wdata_reg (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.dat_i (s_wdata_d),
|
|
.dat_o (s_wdata_q)
|
|
);
|
|
dffr #(
|
|
.DATA_WIDTH(32)
|
|
) u_data_reg (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.dat_i (s_data_d),
|
|
.dat_o (s_data_q)
|
|
);
|
|
dffr #(
|
|
.DATA_WIDTH(4)
|
|
) u_wstrb_reg (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.dat_i (s_wstrb_d),
|
|
.dat_o (s_wstrb_q)
|
|
);
|
|
dffr #(
|
|
.DATA_WIDTH(1)
|
|
) u_id_reg (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.dat_i (s_id_d),
|
|
.dat_o (s_id_q)
|
|
);
|
|
dffr #(
|
|
.DATA_WIDTH(1)
|
|
) u_write_reg (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.dat_i (s_write_d),
|
|
.dat_o (s_write_q)
|
|
);
|
|
dffr #(
|
|
.DATA_WIDTH(2)
|
|
) u_resp_reg (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.dat_i (s_resp_d),
|
|
.dat_o (s_resp_q)
|
|
);
|
|
dffr #(
|
|
.DATA_WIDTH(8)
|
|
) u_len_reg (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.dat_i (s_len_d),
|
|
.dat_o (s_len_q)
|
|
);
|
|
dffr #(
|
|
.DATA_WIDTH(8)
|
|
) u_beat_reg (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.dat_i (s_beat_d),
|
|
.dat_o (s_beat_q)
|
|
);
|
|
endmodule
|