axis_wb_bridge: Use a counter for data phases

This commit is contained in:
Sean Anderson 2023-03-19 11:29:14 -04:00
parent a75b77d8e5
commit 9750e841f5
3 changed files with 41 additions and 43 deletions

View File

@ -13,26 +13,26 @@ The UART protocol uses a request/response format. Each wishbone transaction
corresponds to one request and one response. Each request begins with a command corresponds to one request and one response. Each request begins with a command
byte; an optional, variable-length address; and some data if the request is a byte; an optional, variable-length address; and some data if the request is a
write. Each response begins with a status byte, followed by some data if the write. Each response begins with a status byte, followed by some data if the
request was a read. The following diagram shows a successful read: request was a read. The following diagram shows a successful 16-bit read:
++++ ++++
<script type="WaveDrom"> <script type="WaveDrom">
{ signal : [ { signal : [
{ name: "rx", wave: "z34444z....", data: "CMD ADDR0 ADDR1 ADDR2 ADDR3" }, { name: "rx", wave: "z34444z....", data: "CMD ADDR ADDR ADDR ADDR" },
{ name: "tx", wave: "z......655z", data: "STATUS DATA0 DATA1" }, { name: "tx", wave: "z......655z", data: "STATUS DATA DATA" },
], ],
config: { hscale: 2 }, config: { hscale: 2 },
} }
</script> </script>
++++ ++++
Similarly, this diagram shows a successful write: Similarly, this diagram shows a successful 32-bit write:
++++ ++++
<script type="WaveDrom"> <script type="WaveDrom">
{ signal : [ { signal : [
{ name: "rx", wave: "z3444455z..", data: "CMD ADDR0 ADDR1 ADDR2 ADDR3 DATA0 DATA1" }, { name: "rx", wave: "z3444455z..", data: "CMD ADDR ADDR DATA DATA DATA DATA" },
{ name: "tx", wave: "z........6z", data: "RESP" }, { name: "tx", wave: "z........6z", data: "STATUS" },
], ],
config: { hscale: 2 }, config: { hscale: 2 },
} }
@ -40,8 +40,8 @@ Similarly, this diagram shows a successful write:
++++ ++++
The bridge contains an internal address register that retains its state between The bridge contains an internal address register that retains its state between
different transactions. It possible to reduce the length of requests by different transactions. Requests may send fewer address bytes if the upper bytes
partially modifying the address register. do not need to be modified.
=== Requests === Requests
@ -124,8 +124,8 @@ follows:
| 7:4 | Reserved | Reserved, do not use. | 7:4 | Reserved | Reserved, do not use.
|=== |===
Finally, there is a data phase if the request was a read. Data is transmitted Finally, there is a data phase if the request was a successful read. Data is
in big-endian byte order (most-significant byte first). transmitted in little-endian byte order (least-significant byte first).
=== Resetting === Resetting

View File

@ -28,23 +28,20 @@ module axis_wb_bridge (
); );
parameter ADDR_WIDTH = 32; parameter ADDR_WIDTH = 32;
parameter DATA_WIDTH = 16;
generate if (ADDR_WIDTH % 8) generate if (ADDR_WIDTH % 8)
$error("Unsupported ADDR_WIDTH"); $error("Unsupported ADDR_WIDTH");
endgenerate endgenerate
/* The data width is not parametric for now */
localparam DATA_WIDTH = 16;
localparam IDLE = 0; localparam IDLE = 0;
localparam ADDR3 = 1; localparam ADDR3 = 1;
localparam ADDR2 = 2; localparam ADDR2 = 2;
localparam ADDR1 = 3; localparam ADDR1 = 3;
localparam ADDR0 = 4; localparam ADDR0 = 4;
localparam DATA1 = 5; localparam DATA = 5;
localparam DATA0 = 6; localparam BUS = 6;
localparam BUS = 7; localparam RESP = 7;
localparam RESP2 = 8; localparam END = 8;
localparam RESP1 = 9;
localparam RESP0 = 10;
reg s_axis_ready_next, m_axis_valid_next; reg s_axis_ready_next, m_axis_valid_next;
reg [7:0] m_axis_data_next; reg [7:0] m_axis_data_next;
@ -53,6 +50,7 @@ module axis_wb_bridge (
reg [ADDR_WIDTH - 1:0] wb_addr_next; reg [ADDR_WIDTH - 1:0] wb_addr_next;
reg [DATA_WIDTH - 1:0] wb_data_write_next, wb_data_latch, wb_data_latch_next; reg [DATA_WIDTH - 1:0] wb_data_write_next, wb_data_latch, wb_data_latch_next;
reg [3:0] state, state_next; reg [3:0] state, state_next;
reg [2:0] counter, counter_next;
reg overflow_latch, overflow_latch_next, postinc, postinc_next; reg overflow_latch, overflow_latch_next, postinc, postinc_next;
always @(*) begin always @(*) begin
@ -71,6 +69,7 @@ module axis_wb_bridge (
wb_data_latch_next = wb_data_latch; wb_data_latch_next = wb_data_latch;
state_next = state; state_next = state;
counter_next = counter;
postinc_next = postinc; postinc_next = postinc;
overflow_latch_next = overflow_latch || overflow; overflow_latch_next = overflow_latch || overflow;
@ -85,13 +84,15 @@ module axis_wb_bridge (
2'd2: state_next = ADDR1; 2'd2: state_next = ADDR1;
2'd1: state_next = ADDR0; 2'd1: state_next = ADDR0;
2'd0: if (wb_we_next) begin 2'd0: if (wb_we_next) begin
state_next = DATA1; state_next = DATA;
end else begin end else begin
state_next = BUS; state_next = BUS;
wb_stb_next = 1; wb_stb_next = 1;
s_axis_ready_next = 0; s_axis_ready_next = 0;
end end
endcase endcase
counter_next = 1;
end end
ADDR3: if (s_axis_valid && s_axis_ready) begin ADDR3: if (s_axis_valid && s_axis_ready) begin
if (ADDR_WIDTH >= 32) if (ADDR_WIDTH >= 32)
@ -112,22 +113,21 @@ module axis_wb_bridge (
if (ADDR_WIDTH >= 8) if (ADDR_WIDTH >= 8)
wb_addr_next[7:0] = s_axis_data; wb_addr_next[7:0] = s_axis_data;
if (wb_we) begin if (wb_we) begin
state_next = DATA1; state_next = DATA;
end else begin end else begin
state_next = BUS; state_next = BUS;
wb_stb_next = 1; wb_stb_next = 1;
s_axis_ready_next = 0; s_axis_ready_next = 0;
end end
end end
DATA1: if (s_axis_valid && s_axis_ready) begin DATA: if(s_axis_valid && s_axis_ready) begin
wb_data_write_next = { wb_data_write[7:0], s_axis_data }; wb_data_write_next = { wb_data_write[7:0], s_axis_data };
state_next = DATA0; counter_next = counter - 1;
end if (!counter) begin
DATA0: if(s_axis_valid && s_axis_ready) begin state_next = BUS;
wb_data_write_next = { wb_data_write[7:0], s_axis_data }; wb_stb_next = 1;
state_next = BUS; s_axis_ready_next = 0;
wb_stb_next = 1; end
s_axis_ready_next = 0;
end end
BUS: if (wb_ack || wb_err) begin BUS: if (wb_ack || wb_err) begin
wb_stb_next = 0; wb_stb_next = 0;
@ -135,17 +135,16 @@ module axis_wb_bridge (
m_axis_valid_next = 1; m_axis_valid_next = 1;
m_axis_data_next = { 4'b0, overflow_latch_next, 1'b0, wb_err, wb_we }; m_axis_data_next = { 4'b0, overflow_latch_next, 1'b0, wb_err, wb_we };
overflow_latch_next = 0; overflow_latch_next = 0;
state_next = wb_we || wb_err ? RESP0 : RESP2; state_next = wb_we || wb_err ? END : RESP;
end end
RESP2: if (m_axis_ready && m_axis_valid) begin RESP: if (m_axis_ready && m_axis_valid) begin
m_axis_data_next = wb_data_latch[15:8];
state_next = RESP1;
end
RESP1: if (m_axis_ready && m_axis_valid) begin
m_axis_data_next = wb_data_latch[7:0]; m_axis_data_next = wb_data_latch[7:0];
state_next = RESP0; wb_data_latch_next = { 8'bX, wb_data_latch[15:8] };
counter_next = counter - 1;
if (!counter)
state_next = END;
end end
RESP0: if (m_axis_ready && m_axis_valid) begin END: if (m_axis_ready && m_axis_valid) begin
m_axis_valid_next = 0; m_axis_valid_next = 0;
s_axis_ready_next = 1; s_axis_ready_next = 1;
state_next = IDLE; state_next = IDLE;
@ -160,6 +159,7 @@ module axis_wb_bridge (
wb_data_write <= wb_data_write_next; wb_data_write <= wb_data_write_next;
wb_data_latch <= wb_data_latch_next; wb_data_latch <= wb_data_latch_next;
postinc <= postinc_next; postinc <= postinc_next;
counter <= counter_next;
end end
always @(posedge clk, posedge rst) begin always @(posedge clk, posedge rst) begin
@ -192,12 +192,10 @@ module axis_wb_bridge (
ADDR2: state_text = "ADDR2"; ADDR2: state_text = "ADDR2";
ADDR1: state_text = "ADDR1"; ADDR1: state_text = "ADDR1";
ADDR0: state_text = "ADDR0"; ADDR0: state_text = "ADDR0";
DATA1: state_text = "DATA1"; DATA: state_text = "DATA";
DATA0: state_text = "DATA0";
BUS: state_text = "BUS"; BUS: state_text = "BUS";
RESP2: state_text = "RESP2"; END: state_text = "RESP";
RESP1: state_text = "RESP1"; RESP: state_text = "END";
RESP0: state_text = "RESP0";
endcase endcase
end end
`endif `endif

View File

@ -124,7 +124,7 @@ async def test_bridge(bridge, in_ratio, out_ratio):
else: else:
await wb_read(wb, addr, data) await wb_read(wb, addr, data)
bridge.overflow.value = 0 bridge.overflow.value = 0
await recv_packet(m_axis, (resp, *data.to_bytes(2, 'big'))) await recv_packet(m_axis, (resp, *data.to_bytes(2, 'little')))
async def write(addr, data, postinc=False, resp=STATUS_WE): async def write(addr, data, postinc=False, resp=STATUS_WE):
await send_packet(s_axis, e.encode(addr, data, postinc), in_ratio) await send_packet(s_axis, e.encode(addr, data, postinc), in_ratio)
@ -154,7 +154,7 @@ async def test_bridge(bridge, in_ratio, out_ratio):
await f(0x00000000, 11) await f(0x00000000, 11)
# fast back-to-back # fast back-to-back
recv = await cocotb.start(recv_packet(m_axis, (STATUS_WE, 0, 0, 4))) recv = await cocotb.start(recv_packet(m_axis, (STATUS_WE, 0, 4, 0)))
await send_packet(s_axis, e.encode(1, 2)) await send_packet(s_axis, e.encode(1, 2))
await wb_write(wb, 1, 2) await wb_write(wb, 1, 2)
await send_packet(s_axis, e.encode(3)) await send_packet(s_axis, e.encode(3))