1
0
mirror of https://github.com/bmartini/zynq-axis.git synced 2024-09-05 19:19:27 +08:00
zynq-axis/hdl/axis/axis_write.v
Berin Martini 76537507eb Bug fix: AXI transaction ID usage and generation
Because the axis modules are minimalist, it assumes that all
transactions are performed without error and that transaction processing
is performed in-order. Thus the transaction IDs can safely be set to
zero. Doing so also fixes a bug in the write path that had prevented
multiple burst of data being sent. This was due to the fact that the
write data burst ID needs to have the same ID as the write address. But
the write address module was incrementing the ID while the write data ID
was not being set at all.
2015-01-08 11:39:07 -05:00

253 lines
6.3 KiB
Verilog

/**
* Module:
* axis_write
*
* Description:
* The axis_write takes a system stream an translate it to the axi data
* channel protocol.
*
* Test bench:
* axis_write_tb.v
*
* Created:
* Tue Nov 4 22:18:14 EST 2014
*
* Author:
* Berin Martini (berin.martini@gmail.com)
*/
`ifndef _axis_write_ `define _axis_write_
`include "axis_addr.v"
`include "axis_write_data.v"
module axis_write
#(parameter
BUF_AWIDTH = 9,
CONFIG_ID = 1,
CONFIG_ADDR = 23,
CONFIG_DATA = 24,
CONFIG_AWIDTH = 5,
CONFIG_DWIDTH = 32,
AXI_LEN_WIDTH = 8,
AXI_ADDR_WIDTH = 32,
AXI_DATA_WIDTH = 32,
DATA_WIDTH = 32)
(input clk,
input rst,
input [CONFIG_AWIDTH-1:0] cfg_addr,
input [CONFIG_DWIDTH-1:0] cfg_data,
input cfg_valid,
input axi_awready,
output [AXI_ADDR_WIDTH-1:0] axi_awaddr,
output [AXI_LEN_WIDTH-1:0] axi_awlen,
output axi_awvalid,
output axi_wlast,
output [AXI_DATA_WIDTH-1:0] axi_wdata,
output axi_wvalid,
input axi_wready,
input [DATA_WIDTH-1:0] data,
input valid,
output ready
);
/**
* Local parameters
*/
localparam WIDTH_RATIO = AXI_DATA_WIDTH/DATA_WIDTH;
localparam CONFIG_NB = 2;
localparam
C_IDLE = 0,
C_CONFIG = 1,
C_WAIT = 2,
C_ENABLE = 3;
`ifdef VERBOSE
initial $display("\using 'axis_write'\n");
`endif
/**
* Internal signals
*/
reg [3:0] c_state;
reg [3:0] c_state_nx;
wire cfg_addr_ready;
wire cfg_data_ready;
reg [CONFIG_AWIDTH-1:0] cfg_addr_r;
reg [CONFIG_DWIDTH-1:0] cfg_data_r;
reg cfg_valid_r;
reg [CONFIG_DWIDTH*CONFIG_NB-1:0] cfg_store;
reg [7:0] cfg_cnt;
wire [CONFIG_DWIDTH-1:0] start_addr;
reg [CONFIG_DWIDTH-1:0] cfg_address;
wire [CONFIG_DWIDTH-1:0] str_length;
reg [CONFIG_DWIDTH-1:0] cfg_length;
reg cfg_enable;
/**
* Implementation
*/
assign start_addr = cfg_store[CONFIG_DWIDTH +: CONFIG_DWIDTH];
assign str_length = cfg_store[0 +: CONFIG_DWIDTH];
assign id_valid = (CONFIG_ID == cfg_data_r);
assign addressed = (CONFIG_ADDR == cfg_addr_r) & cfg_valid_r;
assign axis_data = (CONFIG_DATA == cfg_addr_r) & cfg_valid_r;
// register for improved timing
always @(posedge clk)
if (rst) cfg_valid_r <= 1'b0;
else cfg_valid_r <= cfg_valid;
// register for improved timing
always @(posedge clk) begin
cfg_addr_r <= cfg_addr;
cfg_data_r <= cfg_data;
end
always @(posedge clk)
if (c_state[C_CONFIG] & axis_data) begin
cfg_store <= {cfg_store, cfg_data_r};
end
always @(posedge clk) begin
cfg_cnt <= 'b0;
if (c_state[C_CONFIG]) begin
cfg_cnt <= cfg_cnt + axis_data;
end
end
always @(posedge clk)
if (rst) cfg_enable <= 1'b0;
else cfg_enable <= c_state[C_ENABLE];
always @(posedge clk) begin
if (c_state[C_ENABLE]) begin
cfg_address <= start_addr;
cfg_length <= str_length;
end
end
always @(posedge clk)
if (rst) begin
c_state <= 'b0;
c_state[C_IDLE] <= 1'b1;
end
else c_state <= c_state_nx;
always @* begin : CONFIG_
c_state_nx = 'b0;
case (1'b1)
c_state[C_IDLE] : begin
if (addressed & id_valid) begin
c_state_nx[C_CONFIG] = 1'b1;
end
else c_state_nx[C_IDLE] = 1'b1;
end
c_state[C_CONFIG] : begin
if (axis_data & ((CONFIG_NB-1) <= cfg_cnt)) begin
c_state_nx[C_WAIT] = 1'b1;
end
else c_state_nx[C_CONFIG] = 1'b1;
end
c_state[C_WAIT] : begin
if (cfg_addr_ready & cfg_data_ready) begin
c_state_nx[C_ENABLE] = 1'b1;
end
else c_state_nx[C_WAIT] = 1'b1;
end
c_state[C_ENABLE] : begin
c_state_nx[C_IDLE] = 1'b1;
end
default : begin
c_state_nx[C_IDLE] = 1'b1;
end
endcase
end
axis_addr #(
.CONFIG_DWIDTH (CONFIG_DWIDTH),
.WIDTH_RATIO (WIDTH_RATIO),
.CONVERT_SHIFT ($clog2(WIDTH_RATIO)),
.AXI_LEN_WIDTH (AXI_LEN_WIDTH),
.AXI_ADDR_WIDTH (AXI_ADDR_WIDTH),
.AXI_DATA_WIDTH (AXI_DATA_WIDTH))
axis_addr_ (
.clk (clk),
.rst (rst),
.cfg_address (cfg_address),
.cfg_length (cfg_length),
.cfg_valid (cfg_enable),
.cfg_ready (cfg_addr_ready),
.axi_aready (axi_awready),
.axi_aaddr (axi_awaddr),
.axi_alen (axi_awlen),
.axi_avalid (axi_awvalid)
);
axis_write_data #(
.BUF_AWIDTH (BUF_AWIDTH),
.CONFIG_DWIDTH (CONFIG_DWIDTH),
.WIDTH_RATIO (WIDTH_RATIO),
.CONVERT_SHIFT ($clog2(WIDTH_RATIO)),
.AXI_LEN_WIDTH (AXI_LEN_WIDTH),
.AXI_DATA_WIDTH (AXI_DATA_WIDTH),
.DATA_WIDTH (DATA_WIDTH))
axis_write_data_ (
.clk (clk),
.rst (rst),
.cfg_length (cfg_length),
.cfg_valid (cfg_enable),
.cfg_ready (cfg_data_ready),
.axi_wlast (axi_wlast),
.axi_wdata (axi_wdata),
.axi_wvalid (axi_wvalid),
.axi_wready (axi_wready),
.data (data),
.valid (valid),
.ready (ready)
);
endmodule
`endif // `ifndef _axis_write_