2023-03-01 18:14:59 -06:00
|
|
|
// SPDX-License-Identifier: AGPL-3.0-Only
|
|
|
|
/*
|
2023-03-04 13:30:26 -06:00
|
|
|
* Copyright (C) 2023 Sean Anderson <seanga2@gmail.com>
|
2023-03-01 18:14:59 -06:00
|
|
|
*/
|
|
|
|
|
|
|
|
`include "common.vh"
|
|
|
|
|
|
|
|
module axis_wb_bridge (
|
|
|
|
input clk,
|
|
|
|
input rst,
|
|
|
|
|
|
|
|
output reg s_axis_ready,
|
|
|
|
input s_axis_valid,
|
|
|
|
input [7:0] s_axis_data,
|
|
|
|
|
|
|
|
input m_axis_ready,
|
|
|
|
output reg m_axis_valid,
|
|
|
|
output reg [7:0] m_axis_data,
|
|
|
|
|
|
|
|
/* Wishbone */
|
|
|
|
input wb_ack, wb_err,
|
|
|
|
output reg wb_cyc, wb_stb, wb_we,
|
|
|
|
output reg [ADDR_WIDTH - 1:0] wb_addr,
|
2023-03-04 13:30:26 -06:00
|
|
|
output reg [DATA_WIDTH - 1:0] wb_data_write,
|
|
|
|
input [DATA_WIDTH - 1:0] wb_data_read,
|
2023-03-01 18:14:59 -06:00
|
|
|
|
|
|
|
input overflow
|
|
|
|
);
|
|
|
|
|
|
|
|
parameter ADDR_WIDTH = 32;
|
|
|
|
generate if (ADDR_WIDTH % 8)
|
|
|
|
$error("Unsupported ADDR_WIDTH");
|
|
|
|
endgenerate
|
|
|
|
/* The data width is not parametric for now */
|
|
|
|
localparam DATA_WIDTH = 16;
|
|
|
|
|
|
|
|
localparam IDLE = 0;
|
|
|
|
localparam ADDR3 = 1;
|
|
|
|
localparam ADDR2 = 2;
|
|
|
|
localparam ADDR1 = 3;
|
|
|
|
localparam ADDR0 = 4;
|
|
|
|
localparam DATA1 = 5;
|
|
|
|
localparam DATA0 = 6;
|
|
|
|
localparam BUS = 7;
|
|
|
|
localparam RESP2 = 8;
|
|
|
|
localparam RESP1 = 9;
|
|
|
|
localparam RESP0 = 10;
|
|
|
|
|
|
|
|
reg s_axis_ready_next, s_axis_valid_last, m_axis_ready_last, m_axis_valid_next;
|
|
|
|
reg [7:0] s_axis_data_last, m_axis_data_next;
|
|
|
|
reg wb_ack_last, wb_err_last;
|
|
|
|
reg wb_stb_next, wb_we_next;
|
|
|
|
reg [ADDR_WIDTH - 1:0] wb_addr_next;
|
2023-03-04 13:30:26 -06:00
|
|
|
reg [DATA_WIDTH - 1:0] wb_data_write_next, wb_data_latch, wb_data_latch_next;
|
2023-03-01 18:14:59 -06:00
|
|
|
reg [3:0] state, state_next;
|
|
|
|
reg overflow_latch, overflow_latch_next, postinc, postinc_next;
|
|
|
|
|
|
|
|
always @(*) begin
|
|
|
|
s_axis_ready_next = s_axis_ready;
|
|
|
|
m_axis_valid_next = m_axis_valid;
|
|
|
|
m_axis_data_next = 8'bX;
|
|
|
|
|
|
|
|
wb_cyc = wb_stb;
|
|
|
|
wb_stb_next = wb_stb;
|
|
|
|
wb_we_next = wb_we;
|
|
|
|
wb_addr_next = wb_addr;
|
|
|
|
wb_data_write_next = wb_data_write;
|
|
|
|
if (wb_stb && (wb_err || wb_ack))
|
|
|
|
wb_data_latch_next = wb_data_read;
|
|
|
|
else
|
|
|
|
wb_data_latch_next = wb_data_latch;
|
|
|
|
|
|
|
|
state_next = state;
|
|
|
|
postinc_next = postinc;
|
|
|
|
overflow_latch_next = overflow_latch || overflow;
|
|
|
|
|
|
|
|
case (state)
|
|
|
|
IDLE: if (s_axis_valid_last) begin
|
|
|
|
if (s_axis_data_last[0])
|
|
|
|
wb_addr_next = {ADDR_WIDTH{1'b0}};
|
|
|
|
wb_we_next = s_axis_data_last[1];
|
|
|
|
postinc_next = s_axis_data_last[2];
|
|
|
|
case (s_axis_data_last[4:3])
|
|
|
|
2'd3: state_next = ADDR3;
|
|
|
|
2'd2: state_next = ADDR1;
|
|
|
|
2'd1: state_next = ADDR0;
|
|
|
|
2'd0: if (wb_we_next) begin
|
|
|
|
state_next = DATA1;
|
|
|
|
end else begin
|
|
|
|
state_next = BUS;
|
|
|
|
wb_stb_next = 1;
|
|
|
|
s_axis_ready_next = 0;
|
|
|
|
end
|
|
|
|
endcase
|
|
|
|
end
|
|
|
|
ADDR3: if (s_axis_valid_last) begin
|
|
|
|
if (ADDR_WIDTH >= 32)
|
|
|
|
wb_addr_next[31:24] = s_axis_data_last;
|
|
|
|
state_next = ADDR2;
|
|
|
|
end
|
|
|
|
ADDR2: if (s_axis_valid_last) begin
|
|
|
|
if (ADDR_WIDTH >= 24)
|
|
|
|
wb_addr_next[23:16] = s_axis_data_last;
|
|
|
|
state_next = ADDR1;
|
|
|
|
end
|
|
|
|
ADDR1: if (s_axis_valid_last) begin
|
|
|
|
if (ADDR_WIDTH >= 16)
|
|
|
|
wb_addr_next[15:8] = s_axis_data_last;
|
|
|
|
state_next = ADDR0;
|
|
|
|
end
|
|
|
|
ADDR0: if (s_axis_valid_last) begin
|
|
|
|
if (ADDR_WIDTH >= 8)
|
|
|
|
wb_addr_next[7:0] = s_axis_data_last;
|
|
|
|
if (wb_we) begin
|
|
|
|
state_next = DATA1;
|
|
|
|
end else begin
|
|
|
|
state_next = BUS;
|
|
|
|
wb_stb_next = 1;
|
|
|
|
s_axis_ready_next = 0;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
DATA1: if (s_axis_valid_last) begin
|
|
|
|
wb_data_write_next = { wb_data_write[7:0], s_axis_data_last };
|
|
|
|
state_next = DATA0;
|
|
|
|
end
|
|
|
|
DATA0: if(s_axis_valid_last) begin
|
|
|
|
wb_data_write_next = { wb_data_write[7:0], s_axis_data_last };
|
|
|
|
state_next = BUS;
|
|
|
|
wb_stb_next = 1;
|
|
|
|
s_axis_ready_next = 0;
|
|
|
|
end
|
|
|
|
BUS: if (wb_ack || wb_err) begin
|
|
|
|
wb_stb_next = 0;
|
|
|
|
wb_addr_next[7:0] = wb_addr[7:0] + postinc;
|
|
|
|
m_axis_valid_next = 1;
|
|
|
|
m_axis_data_next = { 4'b0, overflow_latch_next, 1'b0, wb_err, wb_we };
|
|
|
|
overflow_latch_next = 0;
|
|
|
|
state_next = wb_we || wb_err ? RESP0 : RESP2;
|
|
|
|
end
|
|
|
|
RESP2: if (m_axis_ready_last) begin
|
|
|
|
m_axis_data_next = wb_data_latch[15:8];
|
|
|
|
state_next = RESP1;
|
|
|
|
end
|
|
|
|
RESP1: if (m_axis_ready_last) begin
|
|
|
|
m_axis_data_next = wb_data_latch[7:0];
|
|
|
|
state_next = RESP0;
|
|
|
|
end
|
|
|
|
RESP0: if (m_axis_ready_last) begin
|
|
|
|
m_axis_valid_next = 0;
|
|
|
|
s_axis_ready_next = 1;
|
|
|
|
state_next = IDLE;
|
|
|
|
end
|
|
|
|
endcase
|
|
|
|
end
|
|
|
|
|
|
|
|
always @(posedge clk) begin
|
|
|
|
s_axis_data_last <= s_axis_data;
|
|
|
|
m_axis_data <= m_axis_data_next;
|
|
|
|
wb_we <= wb_we_next;
|
|
|
|
wb_addr <= wb_addr_next;
|
|
|
|
wb_data_write <= wb_data_write_next;
|
|
|
|
wb_data_latch <= wb_data_latch_next;
|
|
|
|
postinc <= postinc_next;
|
|
|
|
end
|
|
|
|
|
|
|
|
always @(posedge clk, posedge rst) begin
|
|
|
|
if (rst) begin
|
|
|
|
s_axis_ready <= 1;
|
|
|
|
s_axis_valid_last <= 0;
|
|
|
|
m_axis_ready_last <= 0;
|
|
|
|
m_axis_valid <= 0;
|
|
|
|
wb_ack_last <= 0;
|
|
|
|
wb_err_last <= 0;
|
|
|
|
wb_stb <= 0;
|
|
|
|
state <= IDLE;
|
|
|
|
overflow_latch <= 0;
|
|
|
|
end else begin
|
|
|
|
s_axis_ready <= s_axis_ready_next;
|
|
|
|
s_axis_valid_last <= s_axis_valid;
|
|
|
|
m_axis_ready_last <= m_axis_ready;
|
|
|
|
m_axis_valid <= m_axis_valid_next;
|
|
|
|
wb_ack_last <= wb_ack;
|
|
|
|
wb_err_last <= wb_err;
|
|
|
|
wb_stb <= wb_stb_next;
|
|
|
|
state <= state_next;
|
|
|
|
overflow_latch <= overflow_latch_next;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
`ifndef SYNTHESIS
|
|
|
|
reg [255:0] state_text;
|
|
|
|
|
|
|
|
always @(*) begin
|
|
|
|
case (state)
|
|
|
|
IDLE: state_text = "IDLE";
|
|
|
|
ADDR3: state_text = "ADDR3";
|
|
|
|
ADDR2: state_text = "ADDR2";
|
|
|
|
ADDR1: state_text = "ADDR1";
|
|
|
|
ADDR0: state_text = "ADDR0";
|
|
|
|
DATA1: state_text = "DATA1";
|
|
|
|
DATA0: state_text = "DATA0";
|
|
|
|
BUS: state_text = "BUS";
|
|
|
|
RESP2: state_text = "RESP2";
|
|
|
|
RESP1: state_text = "RESP1";
|
|
|
|
RESP0: state_text = "RESP0";
|
|
|
|
endcase
|
|
|
|
end
|
|
|
|
`endif
|
|
|
|
|
|
|
|
endmodule
|