mirror of
https://github.com/alexforencich/verilog-ethernet.git
synced 2025-02-04 07:13:13 +08:00
Optimize axis_arb_mux and improve latency
This commit is contained in:
parent
7a879aec1c
commit
8e5ec36ced
@ -120,49 +120,59 @@ wire [{{n-1}}:0] acknowledge;
|
|||||||
wire [{{n-1}}:0] grant;
|
wire [{{n-1}}:0] grant;
|
||||||
wire grant_valid;
|
wire grant_valid;
|
||||||
wire [{{w-1}}:0] grant_encoded;
|
wire [{{w-1}}:0] grant_encoded;
|
||||||
|
|
||||||
|
// internal datapath
|
||||||
|
reg [DATA_WIDTH-1:0] output_axis_tdata_int;
|
||||||
|
reg [KEEP_WIDTH-1:0] output_axis_tkeep_int;
|
||||||
|
reg output_axis_tvalid_int;
|
||||||
|
reg output_axis_tready_int_reg = 1'b0;
|
||||||
|
reg output_axis_tlast_int;
|
||||||
|
reg [ID_WIDTH-1:0] output_axis_tid_int;
|
||||||
|
reg [DEST_WIDTH-1:0] output_axis_tdest_int;
|
||||||
|
reg [USER_WIDTH-1:0] output_axis_tuser_int;
|
||||||
|
wire output_axis_tready_int_early;
|
||||||
{% for p in ports %}
|
{% for p in ports %}
|
||||||
assign acknowledge[{{p}}] = input_{{p}}_axis_tvalid & input_{{p}}_axis_tready & input_{{p}}_axis_tlast;
|
assign input_{{p}}_axis_tready = grant[{{p}}] & output_axis_tready_int_reg;
|
||||||
assign request[{{p}}] = input_{{p}}_axis_tvalid & ~acknowledge[{{p}}];
|
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
|
|
||||||
// mux instance
|
// mux for incoming packet
|
||||||
axis_mux_{{n}} #(
|
reg [DATA_WIDTH-1:0] current_input_tdata;
|
||||||
.DATA_WIDTH(DATA_WIDTH),
|
reg [KEEP_WIDTH-1:0] current_input_tkeep;
|
||||||
.KEEP_ENABLE(KEEP_ENABLE),
|
reg current_input_tvalid;
|
||||||
.KEEP_WIDTH(KEEP_WIDTH),
|
reg current_input_tready;
|
||||||
.ID_ENABLE(ID_ENABLE),
|
reg current_input_tlast;
|
||||||
.ID_WIDTH(ID_WIDTH),
|
reg [ID_WIDTH-1:0] current_input_tid;
|
||||||
.DEST_ENABLE(DEST_ENABLE),
|
reg [DEST_WIDTH-1:0] current_input_tdest;
|
||||||
.DEST_WIDTH(DEST_WIDTH),
|
reg [USER_WIDTH-1:0] current_input_tuser;
|
||||||
.USER_ENABLE(USER_ENABLE),
|
always @* begin
|
||||||
.USER_WIDTH(USER_WIDTH)
|
case (grant_encoded)
|
||||||
)
|
|
||||||
mux_inst (
|
|
||||||
.clk(clk),
|
|
||||||
.rst(rst),
|
|
||||||
{%- for p in ports %}
|
{%- for p in ports %}
|
||||||
.input_{{p}}_axis_tdata(input_{{p}}_axis_tdata),
|
{{w}}'d{{p}}: begin
|
||||||
.input_{{p}}_axis_tkeep(input_{{p}}_axis_tkeep),
|
current_input_tdata = input_{{p}}_axis_tdata;
|
||||||
.input_{{p}}_axis_tvalid(input_{{p}}_axis_tvalid & grant[{{p}}]),
|
current_input_tkeep = input_{{p}}_axis_tkeep;
|
||||||
.input_{{p}}_axis_tready(input_{{p}}_axis_tready),
|
current_input_tvalid = input_{{p}}_axis_tvalid;
|
||||||
.input_{{p}}_axis_tlast(input_{{p}}_axis_tlast),
|
current_input_tready = input_{{p}}_axis_tready;
|
||||||
.input_{{p}}_axis_tid(input_{{p}}_axis_tid),
|
current_input_tlast = input_{{p}}_axis_tlast;
|
||||||
.input_{{p}}_axis_tdest(input_{{p}}_axis_tdest),
|
current_input_tid = input_{{p}}_axis_tid;
|
||||||
.input_{{p}}_axis_tuser(input_{{p}}_axis_tuser),
|
current_input_tdest = input_{{p}}_axis_tdest;
|
||||||
|
current_input_tuser = input_{{p}}_axis_tuser;
|
||||||
|
end
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
.output_axis_tdata(output_axis_tdata),
|
default: begin
|
||||||
.output_axis_tkeep(output_axis_tkeep),
|
current_input_tdata = {DATA_WIDTH{1'b0}};
|
||||||
.output_axis_tvalid(output_axis_tvalid),
|
current_input_tkeep = {KEEP_WIDTH{1'b0}};
|
||||||
.output_axis_tready(output_axis_tready),
|
current_input_tvalid = 1'b0;
|
||||||
.output_axis_tlast(output_axis_tlast),
|
current_input_tready = 1'b0;
|
||||||
.output_axis_tid(output_axis_tid),
|
current_input_tlast = 1'b0;
|
||||||
.output_axis_tdest(output_axis_tdest),
|
current_input_tid = {ID_WIDTH{1'b0}};
|
||||||
.output_axis_tuser(output_axis_tuser),
|
current_input_tdest = {DEST_WIDTH{1'b0}};
|
||||||
.enable(grant_valid),
|
current_input_tuser = {USER_WIDTH{1'b0}};
|
||||||
.select(grant_encoded)
|
end
|
||||||
);
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
// arbiter instance
|
// arbiter instance
|
||||||
|
|
||||||
arbiter #(
|
arbiter #(
|
||||||
.PORTS({{n}}),
|
.PORTS({{n}}),
|
||||||
.TYPE(ARB_TYPE),
|
.TYPE(ARB_TYPE),
|
||||||
@ -179,6 +189,126 @@ arb_inst (
|
|||||||
.grant_encoded(grant_encoded)
|
.grant_encoded(grant_encoded)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// request generation
|
||||||
|
{%- for p in ports %}
|
||||||
|
assign request[{{p}}] = input_{{p}}_axis_tvalid & ~acknowledge[{{p}}];
|
||||||
|
{%- endfor %}
|
||||||
|
|
||||||
|
// acknowledge generation
|
||||||
|
{%- for p in ports %}
|
||||||
|
assign acknowledge[{{p}}] = grant[{{p}}] & input_{{p}}_axis_tvalid & input_{{p}}_axis_tready & input_{{p}}_axis_tlast;
|
||||||
|
{%- endfor %}
|
||||||
|
|
||||||
|
always @* begin
|
||||||
|
// pass through selected packet data
|
||||||
|
output_axis_tdata_int = current_input_tdata;
|
||||||
|
output_axis_tkeep_int = current_input_tkeep;
|
||||||
|
output_axis_tvalid_int = current_input_tvalid & current_input_tready;
|
||||||
|
output_axis_tlast_int = current_input_tlast;
|
||||||
|
output_axis_tid_int = current_input_tid;
|
||||||
|
output_axis_tdest_int = current_input_tdest;
|
||||||
|
output_axis_tuser_int = current_input_tuser;
|
||||||
|
end
|
||||||
|
|
||||||
|
// output datapath logic
|
||||||
|
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
|
||||||
|
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
|
||||||
|
reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
|
||||||
|
reg output_axis_tlast_reg = 1'b0;
|
||||||
|
reg [ID_WIDTH-1:0] output_axis_tid_reg = {ID_WIDTH{1'b0}};
|
||||||
|
reg [DEST_WIDTH-1:0] output_axis_tdest_reg = {DEST_WIDTH{1'b0}};
|
||||||
|
reg [USER_WIDTH-1:0] output_axis_tuser_reg = {USER_WIDTH{1'b0}};
|
||||||
|
|
||||||
|
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
|
||||||
|
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
|
||||||
|
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
|
||||||
|
reg temp_axis_tlast_reg = 1'b0;
|
||||||
|
reg [ID_WIDTH-1:0] temp_axis_tid_reg = {ID_WIDTH{1'b0}};
|
||||||
|
reg [DEST_WIDTH-1:0] temp_axis_tdest_reg = {DEST_WIDTH{1'b0}};
|
||||||
|
reg [USER_WIDTH-1:0] temp_axis_tuser_reg = {USER_WIDTH{1'b0}};
|
||||||
|
|
||||||
|
// datapath control
|
||||||
|
reg store_axis_int_to_output;
|
||||||
|
reg store_axis_int_to_temp;
|
||||||
|
reg store_axis_temp_to_output;
|
||||||
|
|
||||||
|
assign output_axis_tdata = output_axis_tdata_reg;
|
||||||
|
assign output_axis_tkeep = KEEP_ENABLE ? output_axis_tkeep_reg : {KEEP_WIDTH{1'b1}};
|
||||||
|
assign output_axis_tvalid = output_axis_tvalid_reg;
|
||||||
|
assign output_axis_tlast = output_axis_tlast_reg;
|
||||||
|
assign output_axis_tid = ID_ENABLE ? output_axis_tid_reg : {ID_WIDTH{1'b0}};
|
||||||
|
assign output_axis_tdest = DEST_ENABLE ? output_axis_tdest_reg : {DEST_WIDTH{1'b0}};
|
||||||
|
assign output_axis_tuser = USER_ENABLE ? output_axis_tuser_reg : {USER_WIDTH{1'b0}};
|
||||||
|
|
||||||
|
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
|
||||||
|
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
|
||||||
|
|
||||||
|
always @* begin
|
||||||
|
// transfer sink ready state to source
|
||||||
|
output_axis_tvalid_next = output_axis_tvalid_reg;
|
||||||
|
temp_axis_tvalid_next = temp_axis_tvalid_reg;
|
||||||
|
|
||||||
|
store_axis_int_to_output = 1'b0;
|
||||||
|
store_axis_int_to_temp = 1'b0;
|
||||||
|
store_axis_temp_to_output = 1'b0;
|
||||||
|
|
||||||
|
if (output_axis_tready_int_reg) begin
|
||||||
|
// input is ready
|
||||||
|
if (output_axis_tready | ~output_axis_tvalid_reg) begin
|
||||||
|
// output is ready or currently not valid, transfer data to output
|
||||||
|
output_axis_tvalid_next = output_axis_tvalid_int;
|
||||||
|
store_axis_int_to_output = 1'b1;
|
||||||
|
end else begin
|
||||||
|
// output is not ready, store input in temp
|
||||||
|
temp_axis_tvalid_next = output_axis_tvalid_int;
|
||||||
|
store_axis_int_to_temp = 1'b1;
|
||||||
|
end
|
||||||
|
end else if (output_axis_tready) begin
|
||||||
|
// input is not ready, but output is ready
|
||||||
|
output_axis_tvalid_next = temp_axis_tvalid_reg;
|
||||||
|
temp_axis_tvalid_next = 1'b0;
|
||||||
|
store_axis_temp_to_output = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (rst) begin
|
||||||
|
output_axis_tvalid_reg <= 1'b0;
|
||||||
|
output_axis_tready_int_reg <= 1'b0;
|
||||||
|
temp_axis_tvalid_reg <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
output_axis_tvalid_reg <= output_axis_tvalid_next;
|
||||||
|
output_axis_tready_int_reg <= output_axis_tready_int_early;
|
||||||
|
temp_axis_tvalid_reg <= temp_axis_tvalid_next;
|
||||||
|
end
|
||||||
|
|
||||||
|
// datapath
|
||||||
|
if (store_axis_int_to_output) begin
|
||||||
|
output_axis_tdata_reg <= output_axis_tdata_int;
|
||||||
|
output_axis_tkeep_reg <= output_axis_tkeep_int;
|
||||||
|
output_axis_tlast_reg <= output_axis_tlast_int;
|
||||||
|
output_axis_tid_reg <= output_axis_tid_int;
|
||||||
|
output_axis_tdest_reg <= output_axis_tdest_int;
|
||||||
|
output_axis_tuser_reg <= output_axis_tuser_int;
|
||||||
|
end else if (store_axis_temp_to_output) begin
|
||||||
|
output_axis_tdata_reg <= temp_axis_tdata_reg;
|
||||||
|
output_axis_tkeep_reg <= temp_axis_tkeep_reg;
|
||||||
|
output_axis_tlast_reg <= temp_axis_tlast_reg;
|
||||||
|
output_axis_tid_reg <= temp_axis_tid_reg;
|
||||||
|
output_axis_tdest_reg <= temp_axis_tdest_reg;
|
||||||
|
output_axis_tuser_reg <= temp_axis_tuser_reg;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (store_axis_int_to_temp) begin
|
||||||
|
temp_axis_tdata_reg <= output_axis_tdata_int;
|
||||||
|
temp_axis_tkeep_reg <= output_axis_tkeep_int;
|
||||||
|
temp_axis_tlast_reg <= output_axis_tlast_int;
|
||||||
|
temp_axis_tid_reg <= output_axis_tid_int;
|
||||||
|
temp_axis_tdest_reg <= output_axis_tdest_int;
|
||||||
|
temp_axis_tuser_reg <= output_axis_tuser_int;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
""")
|
""")
|
||||||
|
@ -107,75 +107,88 @@ wire [3:0] grant;
|
|||||||
wire grant_valid;
|
wire grant_valid;
|
||||||
wire [1:0] grant_encoded;
|
wire [1:0] grant_encoded;
|
||||||
|
|
||||||
assign acknowledge[0] = input_0_axis_tvalid & input_0_axis_tready & input_0_axis_tlast;
|
// internal datapath
|
||||||
assign request[0] = input_0_axis_tvalid & ~acknowledge[0];
|
reg [DATA_WIDTH-1:0] output_axis_tdata_int;
|
||||||
assign acknowledge[1] = input_1_axis_tvalid & input_1_axis_tready & input_1_axis_tlast;
|
reg [KEEP_WIDTH-1:0] output_axis_tkeep_int;
|
||||||
assign request[1] = input_1_axis_tvalid & ~acknowledge[1];
|
reg output_axis_tvalid_int;
|
||||||
assign acknowledge[2] = input_2_axis_tvalid & input_2_axis_tready & input_2_axis_tlast;
|
reg output_axis_tready_int_reg = 1'b0;
|
||||||
assign request[2] = input_2_axis_tvalid & ~acknowledge[2];
|
reg output_axis_tlast_int;
|
||||||
assign acknowledge[3] = input_3_axis_tvalid & input_3_axis_tready & input_3_axis_tlast;
|
reg [ID_WIDTH-1:0] output_axis_tid_int;
|
||||||
assign request[3] = input_3_axis_tvalid & ~acknowledge[3];
|
reg [DEST_WIDTH-1:0] output_axis_tdest_int;
|
||||||
|
reg [USER_WIDTH-1:0] output_axis_tuser_int;
|
||||||
|
wire output_axis_tready_int_early;
|
||||||
|
|
||||||
// mux instance
|
assign input_0_axis_tready = grant[0] & output_axis_tready_int_reg;
|
||||||
axis_mux_4 #(
|
assign input_1_axis_tready = grant[1] & output_axis_tready_int_reg;
|
||||||
.DATA_WIDTH(DATA_WIDTH),
|
assign input_2_axis_tready = grant[2] & output_axis_tready_int_reg;
|
||||||
.KEEP_ENABLE(KEEP_ENABLE),
|
assign input_3_axis_tready = grant[3] & output_axis_tready_int_reg;
|
||||||
.KEEP_WIDTH(KEEP_WIDTH),
|
|
||||||
.ID_ENABLE(ID_ENABLE),
|
// mux for incoming packet
|
||||||
.ID_WIDTH(ID_WIDTH),
|
reg [DATA_WIDTH-1:0] current_input_tdata;
|
||||||
.DEST_ENABLE(DEST_ENABLE),
|
reg [KEEP_WIDTH-1:0] current_input_tkeep;
|
||||||
.DEST_WIDTH(DEST_WIDTH),
|
reg current_input_tvalid;
|
||||||
.USER_ENABLE(USER_ENABLE),
|
reg current_input_tready;
|
||||||
.USER_WIDTH(USER_WIDTH)
|
reg current_input_tlast;
|
||||||
)
|
reg [ID_WIDTH-1:0] current_input_tid;
|
||||||
mux_inst (
|
reg [DEST_WIDTH-1:0] current_input_tdest;
|
||||||
.clk(clk),
|
reg [USER_WIDTH-1:0] current_input_tuser;
|
||||||
.rst(rst),
|
always @* begin
|
||||||
.input_0_axis_tdata(input_0_axis_tdata),
|
case (grant_encoded)
|
||||||
.input_0_axis_tkeep(input_0_axis_tkeep),
|
2'd0: begin
|
||||||
.input_0_axis_tvalid(input_0_axis_tvalid & grant[0]),
|
current_input_tdata = input_0_axis_tdata;
|
||||||
.input_0_axis_tready(input_0_axis_tready),
|
current_input_tkeep = input_0_axis_tkeep;
|
||||||
.input_0_axis_tlast(input_0_axis_tlast),
|
current_input_tvalid = input_0_axis_tvalid;
|
||||||
.input_0_axis_tid(input_0_axis_tid),
|
current_input_tready = input_0_axis_tready;
|
||||||
.input_0_axis_tdest(input_0_axis_tdest),
|
current_input_tlast = input_0_axis_tlast;
|
||||||
.input_0_axis_tuser(input_0_axis_tuser),
|
current_input_tid = input_0_axis_tid;
|
||||||
.input_1_axis_tdata(input_1_axis_tdata),
|
current_input_tdest = input_0_axis_tdest;
|
||||||
.input_1_axis_tkeep(input_1_axis_tkeep),
|
current_input_tuser = input_0_axis_tuser;
|
||||||
.input_1_axis_tvalid(input_1_axis_tvalid & grant[1]),
|
end
|
||||||
.input_1_axis_tready(input_1_axis_tready),
|
2'd1: begin
|
||||||
.input_1_axis_tlast(input_1_axis_tlast),
|
current_input_tdata = input_1_axis_tdata;
|
||||||
.input_1_axis_tid(input_1_axis_tid),
|
current_input_tkeep = input_1_axis_tkeep;
|
||||||
.input_1_axis_tdest(input_1_axis_tdest),
|
current_input_tvalid = input_1_axis_tvalid;
|
||||||
.input_1_axis_tuser(input_1_axis_tuser),
|
current_input_tready = input_1_axis_tready;
|
||||||
.input_2_axis_tdata(input_2_axis_tdata),
|
current_input_tlast = input_1_axis_tlast;
|
||||||
.input_2_axis_tkeep(input_2_axis_tkeep),
|
current_input_tid = input_1_axis_tid;
|
||||||
.input_2_axis_tvalid(input_2_axis_tvalid & grant[2]),
|
current_input_tdest = input_1_axis_tdest;
|
||||||
.input_2_axis_tready(input_2_axis_tready),
|
current_input_tuser = input_1_axis_tuser;
|
||||||
.input_2_axis_tlast(input_2_axis_tlast),
|
end
|
||||||
.input_2_axis_tid(input_2_axis_tid),
|
2'd2: begin
|
||||||
.input_2_axis_tdest(input_2_axis_tdest),
|
current_input_tdata = input_2_axis_tdata;
|
||||||
.input_2_axis_tuser(input_2_axis_tuser),
|
current_input_tkeep = input_2_axis_tkeep;
|
||||||
.input_3_axis_tdata(input_3_axis_tdata),
|
current_input_tvalid = input_2_axis_tvalid;
|
||||||
.input_3_axis_tkeep(input_3_axis_tkeep),
|
current_input_tready = input_2_axis_tready;
|
||||||
.input_3_axis_tvalid(input_3_axis_tvalid & grant[3]),
|
current_input_tlast = input_2_axis_tlast;
|
||||||
.input_3_axis_tready(input_3_axis_tready),
|
current_input_tid = input_2_axis_tid;
|
||||||
.input_3_axis_tlast(input_3_axis_tlast),
|
current_input_tdest = input_2_axis_tdest;
|
||||||
.input_3_axis_tid(input_3_axis_tid),
|
current_input_tuser = input_2_axis_tuser;
|
||||||
.input_3_axis_tdest(input_3_axis_tdest),
|
end
|
||||||
.input_3_axis_tuser(input_3_axis_tuser),
|
2'd3: begin
|
||||||
.output_axis_tdata(output_axis_tdata),
|
current_input_tdata = input_3_axis_tdata;
|
||||||
.output_axis_tkeep(output_axis_tkeep),
|
current_input_tkeep = input_3_axis_tkeep;
|
||||||
.output_axis_tvalid(output_axis_tvalid),
|
current_input_tvalid = input_3_axis_tvalid;
|
||||||
.output_axis_tready(output_axis_tready),
|
current_input_tready = input_3_axis_tready;
|
||||||
.output_axis_tlast(output_axis_tlast),
|
current_input_tlast = input_3_axis_tlast;
|
||||||
.output_axis_tid(output_axis_tid),
|
current_input_tid = input_3_axis_tid;
|
||||||
.output_axis_tdest(output_axis_tdest),
|
current_input_tdest = input_3_axis_tdest;
|
||||||
.output_axis_tuser(output_axis_tuser),
|
current_input_tuser = input_3_axis_tuser;
|
||||||
.enable(grant_valid),
|
end
|
||||||
.select(grant_encoded)
|
default: begin
|
||||||
);
|
current_input_tdata = {DATA_WIDTH{1'b0}};
|
||||||
|
current_input_tkeep = {KEEP_WIDTH{1'b0}};
|
||||||
|
current_input_tvalid = 1'b0;
|
||||||
|
current_input_tready = 1'b0;
|
||||||
|
current_input_tlast = 1'b0;
|
||||||
|
current_input_tid = {ID_WIDTH{1'b0}};
|
||||||
|
current_input_tdest = {DEST_WIDTH{1'b0}};
|
||||||
|
current_input_tuser = {USER_WIDTH{1'b0}};
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
// arbiter instance
|
// arbiter instance
|
||||||
|
|
||||||
arbiter #(
|
arbiter #(
|
||||||
.PORTS(4),
|
.PORTS(4),
|
||||||
.TYPE(ARB_TYPE),
|
.TYPE(ARB_TYPE),
|
||||||
@ -192,4 +205,126 @@ arb_inst (
|
|||||||
.grant_encoded(grant_encoded)
|
.grant_encoded(grant_encoded)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// request generation
|
||||||
|
assign request[0] = input_0_axis_tvalid & ~acknowledge[0];
|
||||||
|
assign request[1] = input_1_axis_tvalid & ~acknowledge[1];
|
||||||
|
assign request[2] = input_2_axis_tvalid & ~acknowledge[2];
|
||||||
|
assign request[3] = input_3_axis_tvalid & ~acknowledge[3];
|
||||||
|
|
||||||
|
// acknowledge generation
|
||||||
|
assign acknowledge[0] = grant[0] & input_0_axis_tvalid & input_0_axis_tready & input_0_axis_tlast;
|
||||||
|
assign acknowledge[1] = grant[1] & input_1_axis_tvalid & input_1_axis_tready & input_1_axis_tlast;
|
||||||
|
assign acknowledge[2] = grant[2] & input_2_axis_tvalid & input_2_axis_tready & input_2_axis_tlast;
|
||||||
|
assign acknowledge[3] = grant[3] & input_3_axis_tvalid & input_3_axis_tready & input_3_axis_tlast;
|
||||||
|
|
||||||
|
always @* begin
|
||||||
|
// pass through selected packet data
|
||||||
|
output_axis_tdata_int = current_input_tdata;
|
||||||
|
output_axis_tkeep_int = current_input_tkeep;
|
||||||
|
output_axis_tvalid_int = current_input_tvalid & current_input_tready;
|
||||||
|
output_axis_tlast_int = current_input_tlast;
|
||||||
|
output_axis_tid_int = current_input_tid;
|
||||||
|
output_axis_tdest_int = current_input_tdest;
|
||||||
|
output_axis_tuser_int = current_input_tuser;
|
||||||
|
end
|
||||||
|
|
||||||
|
// output datapath logic
|
||||||
|
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
|
||||||
|
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
|
||||||
|
reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
|
||||||
|
reg output_axis_tlast_reg = 1'b0;
|
||||||
|
reg [ID_WIDTH-1:0] output_axis_tid_reg = {ID_WIDTH{1'b0}};
|
||||||
|
reg [DEST_WIDTH-1:0] output_axis_tdest_reg = {DEST_WIDTH{1'b0}};
|
||||||
|
reg [USER_WIDTH-1:0] output_axis_tuser_reg = {USER_WIDTH{1'b0}};
|
||||||
|
|
||||||
|
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
|
||||||
|
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
|
||||||
|
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
|
||||||
|
reg temp_axis_tlast_reg = 1'b0;
|
||||||
|
reg [ID_WIDTH-1:0] temp_axis_tid_reg = {ID_WIDTH{1'b0}};
|
||||||
|
reg [DEST_WIDTH-1:0] temp_axis_tdest_reg = {DEST_WIDTH{1'b0}};
|
||||||
|
reg [USER_WIDTH-1:0] temp_axis_tuser_reg = {USER_WIDTH{1'b0}};
|
||||||
|
|
||||||
|
// datapath control
|
||||||
|
reg store_axis_int_to_output;
|
||||||
|
reg store_axis_int_to_temp;
|
||||||
|
reg store_axis_temp_to_output;
|
||||||
|
|
||||||
|
assign output_axis_tdata = output_axis_tdata_reg;
|
||||||
|
assign output_axis_tkeep = KEEP_ENABLE ? output_axis_tkeep_reg : {KEEP_WIDTH{1'b1}};
|
||||||
|
assign output_axis_tvalid = output_axis_tvalid_reg;
|
||||||
|
assign output_axis_tlast = output_axis_tlast_reg;
|
||||||
|
assign output_axis_tid = ID_ENABLE ? output_axis_tid_reg : {ID_WIDTH{1'b0}};
|
||||||
|
assign output_axis_tdest = DEST_ENABLE ? output_axis_tdest_reg : {DEST_WIDTH{1'b0}};
|
||||||
|
assign output_axis_tuser = USER_ENABLE ? output_axis_tuser_reg : {USER_WIDTH{1'b0}};
|
||||||
|
|
||||||
|
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
|
||||||
|
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
|
||||||
|
|
||||||
|
always @* begin
|
||||||
|
// transfer sink ready state to source
|
||||||
|
output_axis_tvalid_next = output_axis_tvalid_reg;
|
||||||
|
temp_axis_tvalid_next = temp_axis_tvalid_reg;
|
||||||
|
|
||||||
|
store_axis_int_to_output = 1'b0;
|
||||||
|
store_axis_int_to_temp = 1'b0;
|
||||||
|
store_axis_temp_to_output = 1'b0;
|
||||||
|
|
||||||
|
if (output_axis_tready_int_reg) begin
|
||||||
|
// input is ready
|
||||||
|
if (output_axis_tready | ~output_axis_tvalid_reg) begin
|
||||||
|
// output is ready or currently not valid, transfer data to output
|
||||||
|
output_axis_tvalid_next = output_axis_tvalid_int;
|
||||||
|
store_axis_int_to_output = 1'b1;
|
||||||
|
end else begin
|
||||||
|
// output is not ready, store input in temp
|
||||||
|
temp_axis_tvalid_next = output_axis_tvalid_int;
|
||||||
|
store_axis_int_to_temp = 1'b1;
|
||||||
|
end
|
||||||
|
end else if (output_axis_tready) begin
|
||||||
|
// input is not ready, but output is ready
|
||||||
|
output_axis_tvalid_next = temp_axis_tvalid_reg;
|
||||||
|
temp_axis_tvalid_next = 1'b0;
|
||||||
|
store_axis_temp_to_output = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (rst) begin
|
||||||
|
output_axis_tvalid_reg <= 1'b0;
|
||||||
|
output_axis_tready_int_reg <= 1'b0;
|
||||||
|
temp_axis_tvalid_reg <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
output_axis_tvalid_reg <= output_axis_tvalid_next;
|
||||||
|
output_axis_tready_int_reg <= output_axis_tready_int_early;
|
||||||
|
temp_axis_tvalid_reg <= temp_axis_tvalid_next;
|
||||||
|
end
|
||||||
|
|
||||||
|
// datapath
|
||||||
|
if (store_axis_int_to_output) begin
|
||||||
|
output_axis_tdata_reg <= output_axis_tdata_int;
|
||||||
|
output_axis_tkeep_reg <= output_axis_tkeep_int;
|
||||||
|
output_axis_tlast_reg <= output_axis_tlast_int;
|
||||||
|
output_axis_tid_reg <= output_axis_tid_int;
|
||||||
|
output_axis_tdest_reg <= output_axis_tdest_int;
|
||||||
|
output_axis_tuser_reg <= output_axis_tuser_int;
|
||||||
|
end else if (store_axis_temp_to_output) begin
|
||||||
|
output_axis_tdata_reg <= temp_axis_tdata_reg;
|
||||||
|
output_axis_tkeep_reg <= temp_axis_tkeep_reg;
|
||||||
|
output_axis_tlast_reg <= temp_axis_tlast_reg;
|
||||||
|
output_axis_tid_reg <= temp_axis_tid_reg;
|
||||||
|
output_axis_tdest_reg <= temp_axis_tdest_reg;
|
||||||
|
output_axis_tuser_reg <= temp_axis_tuser_reg;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (store_axis_int_to_temp) begin
|
||||||
|
temp_axis_tdata_reg <= output_axis_tdata_int;
|
||||||
|
temp_axis_tkeep_reg <= output_axis_tkeep_int;
|
||||||
|
temp_axis_tlast_reg <= output_axis_tlast_int;
|
||||||
|
temp_axis_tid_reg <= output_axis_tid_int;
|
||||||
|
temp_axis_tdest_reg <= output_axis_tdest_int;
|
||||||
|
temp_axis_tuser_reg <= output_axis_tuser_int;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
@ -509,7 +509,7 @@ def bench():
|
|||||||
source_2.send(test_frame2)
|
source_2.send(test_frame2)
|
||||||
yield clk.posedge
|
yield clk.posedge
|
||||||
|
|
||||||
yield delay(150)
|
yield delay(100)
|
||||||
yield clk.posedge
|
yield clk.posedge
|
||||||
source_1.send(test_frame1)
|
source_1.send(test_frame1)
|
||||||
|
|
||||||
@ -531,12 +531,12 @@ def bench():
|
|||||||
yield sink.wait()
|
yield sink.wait()
|
||||||
rx_frame = sink.recv()
|
rx_frame = sink.recv()
|
||||||
|
|
||||||
assert rx_frame == test_frame2
|
assert rx_frame == test_frame1
|
||||||
|
|
||||||
yield sink.wait()
|
yield sink.wait()
|
||||||
rx_frame = sink.recv()
|
rx_frame = sink.recv()
|
||||||
|
|
||||||
assert rx_frame == test_frame1
|
assert rx_frame == test_frame2
|
||||||
|
|
||||||
yield sink.wait()
|
yield sink.wait()
|
||||||
rx_frame = sink.recv()
|
rx_frame = sink.recv()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user