move axil bridge

This commit is contained in:
2022-12-01 01:13:23 -07:00
parent 5d3d9b222f
commit e301d2c4d2
3 changed files with 13 additions and 3 deletions

205
lib/axil_wb_bridge.sv Normal file
View File

@@ -0,0 +1,205 @@
// TODO: improve throughput. Currently limited to 1 write every 3 cycles and read every 2 cycles (plus wb slave latency)
module axil_wb_bridge #(
parameter ADDR_WIDTH = 8,
parameter DATA_WIDTH = 32
)(
input logic clk,
input logic reset,
///// AXI4-Lite /////
// Write address
input logic axil_awvalid,
output logic axil_awready,
input logic [ADDR_WIDTH-1:0] axil_awaddr,
input logic [2:0] axil_awprot,
// Write data
input logic axil_wvalid,
output logic axil_wready,
input logic [DATA_WIDTH-1:0] axil_wdata,
input logic [DATA_WIDTH/8 - 1:0] axil_wstrb,
// Write response
output logic axil_bvalid,
input logic axil_bready,
output logic [1:0] axil_bresp,
// Read address
input logic axil_arvalid,
output logic axil_arready,
input logic [ADDR_WIDTH-1:0] axil_araddr,
input logic [2:0] axil_arprot,
// Read data
output logic axil_rvalid,
input logic axil_rready,
output logic [DATA_WIDTH-1:0] axil_rdata,
output logic [1:0] axil_rresp,
///// Wishbone /////
output logic [ADDR_WIDTH-1:0] wb_adr_o,
input logic [DATA_WIDTH-1:0] wb_dat_i,
output logic [DATA_WIDTH-1:0] wb_dat_o,
output logic wb_we_o,
output logic wb_sel_o,
output logic wb_stb_o,
input logic wb_ack_i,
output logic wb_cyc_o
);
localparam AXIL_RESP_OKAY = 2'b00;
// localparam AXIL_RESP_EXOKAY = 2'b01; // Only valid for full AXI, not AXI-Lite
localparam AXIL_RESP_SLVERR = 2'b10;
localparam AXIL_RESP_DECERR = 2'b11; // Indicates there is no slave at the transaction address
localparam STATE_IDLE = 0;
localparam STATE_READ = 1;
localparam STATE_WRITE = 2;
logic [ADDR_WIDTH-1:0] waddr;
logic [ADDR_WIDTH-1:0] raddr;
logic [DATA_WIDTH-1:0] wdata;
logic [DATA_WIDTH-1:0] rdata;
logic waddr_legal;
logic raddr_legal;
logic wdata_legal;
logic waddr_valid = 0;
logic raddr_valid = 0;
logic wdata_valid = 0;
logic rdata_valid = 0;
logic w_complete = 0;
logic [1:0] state_wb = STATE_IDLE;
always_ff @(posedge clk) begin
if (reset) begin
waddr_valid <= 0;
wdata_valid <= 0;
w_complete <= 0;
raddr_valid <= 0;
rdata_valid <= 0;
state_wb <= STATE_IDLE;
end else begin
// axil write address
if (axil_awvalid && axil_awready) begin
waddr <= axil_awaddr;
waddr_valid <= 1;
waddr_legal <= 1;
// TODO: use write protection
end
// axil write data
if (axil_wvalid && axil_wready) begin
wdata <= axil_wdata;
wdata_valid <= 1;
if (&axil_wstrb) begin
// wishbone only supports full width writes
wdata_legal <= 1;
// end else if (!|axil_wstrb) begin
// // TODO: optionally discard and ignore access with axil_wstrb = 4'b0000
end else begin
// invalid write strobe combination
wdata_legal <= 0;
end
end
if (
((axil_wvalid && axil_wready) || wdata_valid) &&
((axil_awvalid && axil_awready) || waddr_valid) &&
!w_complete
// TODO: check for wdata_legal (and combinatorial wdata_legal)
) begin
if (state_wb == STATE_IDLE) begin
state_wb <= STATE_WRITE;
end
end
// axil write response
if (axil_bvalid && axil_bready) begin
// reset write logic for next transfer
waddr_valid <= 0;
wdata_valid <= 0;
w_complete <= 0;
end
// axil read address
if (axil_arvalid && axil_arready) begin
raddr <= axil_araddr;
raddr_valid <= 1;
raddr_legal <= 1;
// TODO: use read protection
if (state_wb == STATE_IDLE) begin
// if write and read arrive on the same cycle, read takes priority
state_wb <= STATE_READ;
end
end
// axil read data
if (axil_rvalid && axil_rready) begin
// read is complete. Get ready for next read
raddr_valid <= 0;
rdata_valid <= 0;
end
// wb
case (state_wb)
STATE_IDLE: begin
// do nothing
end
STATE_WRITE: begin
if (wb_cyc_o && wb_sel_o && wb_stb_o && wb_ack_i) begin
w_complete <= 1;
state_wb <= STATE_IDLE;
// TODO: switch directly to STATE_READ if we can
end
end
STATE_READ: begin
if (wb_cyc_o && wb_sel_o && wb_stb_o && wb_ack_i) begin
rdata <= wb_dat_i;
rdata_valid <= 1;
state_wb <= STATE_IDLE;
// TODO: switch directly to STATE_WRITE if we can
// This will also ensure continuous reads don't inhibit all writes
end
end
default: begin
// bh_assert_equal(state_wb, 0, "Wishbone master encountered unknown state");
state_wb <= STATE_IDLE;
end
endcase
end
end
always_comb begin
// axil write address
axil_awready = !waddr_valid;
// axil write data
axil_wready = !wdata_valid;
// axil write response
axil_bvalid = waddr_valid && wdata_valid && w_complete;
axil_bresp = (waddr_legal && wdata_legal) ? AXIL_RESP_OKAY : AXIL_RESP_SLVERR;
// axil read address
axil_arready = !raddr_valid;
// axil read data
axil_rvalid = rdata_valid;
axil_rresp = raddr_legal ? AXIL_RESP_OKAY : AXIL_RESP_SLVERR;
// wishbone
wb_we_o = state_wb == STATE_WRITE;
wb_dat_o = wdata;
wb_adr_o = (state_wb == STATE_WRITE) ? waddr : raddr;
wb_cyc_o = state_wb == STATE_WRITE || state_wb == STATE_READ;
wb_sel_o = 1; // TODO: figure out if this is right
wb_stb_o = 1; // TODO: figure out if this is right
end
endmodule

105
lib/tb/axil_wb_bridge_tb.sv Normal file
View File

@@ -0,0 +1,105 @@
`include "bh_assert.sv"
`timescale 1ns/1ps
import bh_assert::bh_assert_equal;
import bh_assert::bh_assert_stats;
module axil_wb_bridge_tb();
parameter ADDR_WIDTH = 8;
parameter DATA_WIDTH = 32;
logic clk = 0;
logic reset = 1;
logic axil_awvalid;
logic axil_awready;
logic [ADDR_WIDTH-1:0] axil_awaddr;
logic [2:0] axil_awprot;
logic axil_wvalid;
logic axil_wready;
logic [DATA_WIDTH-1:0] axil_wdata;
logic [DATA_WIDTH/8 - 1:0] axil_wstrb;
logic axil_bvalid;
logic axil_bready;
logic [1:0] axil_bresp;
logic axil_arvalid;
logic axil_arready;
logic [ADDR_WIDTH-1:0] axil_araddr;
logic [2:0] axil_arprot;
logic axil_rvalid;
logic axil_rready;
logic [DATA_WIDTH-1:0] axil_rdata;
logic [2:0] axil_rresp;
logic [ADDR_WIDTH-1:0] wb_adr_o;
logic [DATA_WIDTH-1:0] wb_dat_i;
logic [DATA_WIDTH-1:0] wb_dat_o;
logic wb_we_o;
logic wb_sel_o;
logic wb_stb_o;
logic wb_ack_i;
logic wb_cyc_o;
axil_wb_bridge #(
.ADDR_WIDTH(ADDR_WIDTH),
.DATA_WIDTH(DATA_WIDTH)
) dut(
.clk(clk),
.reset(reset),
///// AXI4-Lite /////
// Write address
.axil_awvalid(axil_awvalid),
.axil_awready(axil_awready),
.axil_awaddr(axil_awaddr),
.axil_awprot(axil_awprot),
// Write data
.axil_wvalid(axil_wvalid),
.axil_wready(axil_wready),
.axil_wdata(axil_wdata),
.axil_wstrb(axil_wstrb),
// Write response
.axil_bvalid(axil_bvalid),
.axil_bready(axil_bready),
.axil_bresp(axil_bresp),
// Read address
.axil_arvalid(axil_arvalid),
.axil_arready(axil_arready),
.axil_araddr(axil_araddr),
.axil_arprot(axil_arprot),
// Read data
.axil_rvalid(axil_rvalid),
.axil_rready(axil_rready),
.axil_rdata(axil_rdata),
.axil_rresp(axil_rresp),
///// Wishbone /////
.wb_adr_o(wb_adr_o),
.wb_dat_i(wb_dat_i),
.wb_dat_o(wb_dat_o),
.wb_we_o(wb_we_o),
.wb_sel_o(wb_sel_o),
.wb_stb_o(wb_stb_o),
.wb_ack_i(wb_ack_i),
.wb_cyc_o(wb_cyc_o)
);
always #5 clk <= !clk;
initial begin
#10
bh_assert_stats();
$finish;
end
endmodule

View File

@@ -60,6 +60,7 @@ module skidbuffer_tb();
end
end
#10
bh_assert_stats();
$finish;
end