mirror of
https://gitlab.com/brendanhaines/cpu.git
synced 2024-11-09 21:14:57 -07:00
152 lines
4.9 KiB
Coq
152 lines
4.9 KiB
Coq
|
module axi_lite_memory(
|
||
|
// Global
|
||
|
input ACLK,
|
||
|
input ARESETn,
|
||
|
|
||
|
// Write address
|
||
|
input AWVALID,
|
||
|
input [ADDR_WIDTH-1:0] AWADDR,
|
||
|
input [2:0] AWPROT,
|
||
|
output reg AWREADY,
|
||
|
|
||
|
// Write data
|
||
|
input WVALID,
|
||
|
input [DATA_WIDTH-1:0] WDATA,
|
||
|
input [(DATA_WIDTH/8)-1:0] WSTRB,
|
||
|
output reg WREADY,
|
||
|
|
||
|
// Write response
|
||
|
output reg BVALID,
|
||
|
input BREADY,
|
||
|
output reg [1:0] BRESP,
|
||
|
|
||
|
// Read address
|
||
|
input ARVALID,
|
||
|
input [ADDR_WIDTH-1:0] ARADDR,
|
||
|
input [2:0] ARPROT, // IGNORED
|
||
|
output reg ARREADY,
|
||
|
|
||
|
// Read data
|
||
|
output reg RVALID,
|
||
|
output reg [DATA_WIDTH-1:0] RDATA,
|
||
|
output reg [1:0] RRESP,
|
||
|
input RREADY,
|
||
|
|
||
|
// Wishbone write
|
||
|
output reg [ADDR_WIDTH-1:0] WB_WADDR,
|
||
|
output reg [2:0] WB_WPROT,
|
||
|
output reg [DATA_WIDTH-1:0] WB_WDATA,
|
||
|
output reg [(DATA_WIDTH/8)-1:0] WB_WSTRB,
|
||
|
output reg WB_WVALID = 0,
|
||
|
input WB_WREADY,
|
||
|
|
||
|
// Wishbone read
|
||
|
output reg [ADDR_WIDTH-1:0] WB_RADDR,
|
||
|
input [DATA_WIDTH-1:0] WB_RDATA,
|
||
|
input WB_RVALID,
|
||
|
output reg WB_RREADY
|
||
|
);
|
||
|
|
||
|
parameter DATA_WIDTH = 32; // Only 32 allowed for now (AXI-Lite allows 32 or 64). 64 might work but I haven't investigated it yet.
|
||
|
parameter ADDR_WIDTH = 12; // No minimum requirement. Typically at least 12b (4KB)
|
||
|
parameter SYNC_DEPTH = 1; // Minimum recommended: 2. Larger synchronizer depth allows for larger delay between AXI address and data without stalling.
|
||
|
|
||
|
reg [ADDR_WIDTH-1:0] sync_awaddr [0:SYNC_DEPTH-1];
|
||
|
reg [2:0] sync_awprot [0:SYNC_DEPTH-1];
|
||
|
reg [$clog2(SYNC_DEPTH)+1:0] sync_aw_fill = 0;
|
||
|
|
||
|
reg [DATA_WIDTH-1:0] sync_wdata [0:SYNC_DEPTH-1];
|
||
|
reg [(DATA_WIDTH/8)-1:0] sync_wstrb [0:SYNC_DEPTH-1];
|
||
|
reg [$clog2(SYNC_DEPTH)+1:0] sync_w_fill = 0;
|
||
|
|
||
|
reg [1:0] sync_bresp [0:SYNC_DEPTH-1]; // TODO: make this not be the same sync_depth?
|
||
|
reg [$clog2(SYNC_DEPTH)+1:0] sync_b_fill = 0;
|
||
|
|
||
|
localparam RESP_OKAY = 2'b00,
|
||
|
RESP_EXOKAY = 2'b01,
|
||
|
RESP_SLVERR = 2'b10,
|
||
|
RESP_DECERR = 2'b11;
|
||
|
|
||
|
always @(*) begin
|
||
|
AWREADY = sync_aw_fill < SYNC_DEPTH;
|
||
|
WREADY = sync_w_fill < SYNC_DEPTH;
|
||
|
|
||
|
BRESP = RESP_OKAY; // TODO: add support for responses other than OKAY
|
||
|
BVALID = sync_b_fill > 0;
|
||
|
end
|
||
|
|
||
|
always @(posedge ACLK or negedge ARESETn) begin: clk_update
|
||
|
integer i;
|
||
|
|
||
|
// Write direction
|
||
|
integer event_wb_write;
|
||
|
integer event_aw;
|
||
|
integer event_w;
|
||
|
integer event_b;
|
||
|
|
||
|
// Read direction
|
||
|
integer event_wb_read;
|
||
|
integer event_ar;
|
||
|
integer event_r;
|
||
|
|
||
|
// Write direction
|
||
|
event_wb_write = 0;
|
||
|
event_aw = 0;
|
||
|
event_w = 0;
|
||
|
event_b = 0;
|
||
|
|
||
|
// Read direction
|
||
|
event_wb_read = 0;
|
||
|
event_ar = 0;
|
||
|
event_r = 0;
|
||
|
|
||
|
if (ARESETn == 0) begin
|
||
|
// TODO: deal with reset
|
||
|
sync_aw_fill <= 0;
|
||
|
sync_w_fill <= 0;
|
||
|
sync_b_fill <= 0;
|
||
|
end else begin
|
||
|
if (AWREADY && AWVALID) begin
|
||
|
event_aw = 1;
|
||
|
for (i=0; i<sync_aw_fill; i=i+1) begin
|
||
|
sync_awaddr[i+1] <= sync_awaddr[i];
|
||
|
sync_awprot[i+1] <= sync_awprot[i];
|
||
|
end
|
||
|
sync_awaddr[0] <= AWADDR;
|
||
|
sync_awprot[0] <= AWPROT;
|
||
|
end
|
||
|
|
||
|
if (WREADY && WVALID) begin
|
||
|
event_w = 1;
|
||
|
for (i=0; i<sync_w_fill; i=i+1) begin
|
||
|
sync_wdata[i+1] <= sync_wstrb[i];
|
||
|
sync_wstrb[i+1] <= sync_wstrb[i];
|
||
|
end
|
||
|
sync_wdata[sync_w_fill] <= WDATA;
|
||
|
sync_wstrb[sync_w_fill] <= WSTRB;
|
||
|
end
|
||
|
|
||
|
if (BREADY && BVALID) begin
|
||
|
event_b = 1;
|
||
|
end
|
||
|
|
||
|
if (WB_WREADY || !WB_WVALID) begin
|
||
|
event_wb_write = 1;
|
||
|
if (sync_aw_fill > 0 && sync_w_fill > 0) begin
|
||
|
WB_WVALID <= 1'b1;
|
||
|
WB_WADDR <= sync_awaddr[sync_aw_fill-1];
|
||
|
WB_WPROT <= sync_awprot[sync_aw_fill-1];
|
||
|
WB_WDATA <= sync_wdata[sync_w_fill-1];
|
||
|
WB_WSTRB <= sync_wstrb[sync_w_fill-1];
|
||
|
end else begin
|
||
|
WB_WVALID <= 1'b0;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
sync_aw_fill <= sync_aw_fill + event_aw - event_wb_write;
|
||
|
sync_w_fill <= sync_w_fill + event_w - event_wb_write;
|
||
|
sync_b_fill <= sync_b_fill - event_b + event_wb_write; // TODO: is this right?
|
||
|
end
|
||
|
end
|
||
|
|
||
|
endmodule
|