1
0
mirror of https://github.com/corundum/corundum.git synced 2025-01-30 08:32:52 +08:00

merged changes in axis

This commit is contained in:
Alex Forencich 2015-11-09 15:00:49 -08:00
commit 4e8ef42031
31 changed files with 3241 additions and 2595 deletions

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -101,25 +101,26 @@ localparam [2:0]
reg [2:0] state_reg = STATE_IDLE, state_next; reg [2:0] state_reg = STATE_IDLE, state_next;
reg [7:0] cycle_count_reg = 0, cycle_count_next; reg [7:0] cycle_count_reg = 8'd0, cycle_count_next;
reg last_cycle; reg last_cycle;
reg [DATA_WIDTH-1:0] temp_tdata_reg = 0, temp_tdata_next; reg [DATA_WIDTH-1:0] temp_tdata_reg = {DATA_WIDTH{1'b0}}, temp_tdata_next;
reg [KEEP_WIDTH-1:0] temp_tkeep_reg = 0, temp_tkeep_next; reg [KEEP_WIDTH-1:0] temp_tkeep_reg = {KEEP_WIDTH{1'b0}}, temp_tkeep_next;
reg temp_tlast_reg = 0, temp_tlast_next; reg temp_tlast_reg = 1'b0, temp_tlast_next;
reg temp_tuser_reg = 0, temp_tuser_next; reg temp_tuser_reg = 1'b0, temp_tuser_next;
// internal datapath // internal datapath
reg [OUTPUT_DATA_WIDTH-1:0] output_axis_tdata_int; reg [OUTPUT_DATA_WIDTH-1:0] output_axis_tdata_int;
reg [OUTPUT_KEEP_WIDTH-1:0] output_axis_tkeep_int; reg [OUTPUT_KEEP_WIDTH-1:0] output_axis_tkeep_int;
reg output_axis_tvalid_int; reg output_axis_tvalid_int;
reg output_axis_tready_int = 0; reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int; reg output_axis_tlast_int;
reg output_axis_tuser_int; reg output_axis_tuser_int;
wire output_axis_tready_int_early; wire output_axis_tready_int_early;
reg input_axis_tready_reg = 0, input_axis_tready_next; reg input_axis_tready_reg = 1'b0, input_axis_tready_next;
assign input_axis_tready = input_axis_tready_reg; assign input_axis_tready = input_axis_tready_reg;
always @* begin always @* begin
@ -132,13 +133,13 @@ always @* begin
temp_tlast_next = temp_tlast_reg; temp_tlast_next = temp_tlast_reg;
temp_tuser_next = temp_tuser_reg; temp_tuser_next = temp_tuser_reg;
output_axis_tdata_int = 0; output_axis_tdata_int = {OUTPUT_DATA_WIDTH{1'b0}};
output_axis_tkeep_int = 0; output_axis_tkeep_int = {OUTPUT_KEEP_WIDTH{1'b0}};
output_axis_tvalid_int = 0; output_axis_tvalid_int = 1'b0;
output_axis_tlast_int = 0; output_axis_tlast_int = 1'b0;
output_axis_tuser_int = 0; output_axis_tuser_int = 1'b0;
input_axis_tready_next = 0; input_axis_tready_next = 1'b0;
case (state_reg) case (state_reg)
STATE_IDLE: begin STATE_IDLE: begin
@ -161,7 +162,7 @@ always @* begin
// output bus is wider // output bus is wider
// accept new data // accept new data
input_axis_tready_next = 1; input_axis_tready_next = 1'b1;
if (input_axis_tready & input_axis_tvalid) begin if (input_axis_tready & input_axis_tvalid) begin
// word transfer in - store it in data register // word transfer in - store it in data register
@ -173,15 +174,15 @@ always @* begin
temp_tuser_next = input_axis_tuser; temp_tuser_next = input_axis_tuser;
// first input cycle complete // first input cycle complete
cycle_count_next = 1; cycle_count_next = 8'd1;
if (input_axis_tlast) begin if (input_axis_tlast) begin
// got last signal on first cycle, so output it // got last signal on first cycle, so output it
input_axis_tready_next = 0; input_axis_tready_next = 1'b0;
state_next = STATE_TRANSFER_OUT; state_next = STATE_TRANSFER_OUT;
end else begin end else begin
// otherwise, transfer in the rest of the words // otherwise, transfer in the rest of the words
input_axis_tready_next = 1; input_axis_tready_next = 1'b1;
state_next = STATE_TRANSFER_IN; state_next = STATE_TRANSFER_IN;
end end
end else begin end else begin
@ -191,24 +192,24 @@ always @* begin
// output bus is narrower // output bus is narrower
// accept new data // accept new data
input_axis_tready_next = 1; input_axis_tready_next = 1'b1;
if (input_axis_tready & input_axis_tvalid) begin if (input_axis_tready & input_axis_tvalid) begin
// word transfer in - store it in data register // word transfer in - store it in data register
cycle_count_next = 0; cycle_count_next = 8'd0;
// is this the last cycle? // is this the last cycle?
if (CYCLE_COUNT == 1) begin if (CYCLE_COUNT == 1) begin
// last cycle by counter value // last cycle by counter value
last_cycle = 1; last_cycle = 1'b1;
end else if (input_axis_tkeep[CYCLE_KEEP_WIDTH-1:0] != {CYCLE_KEEP_WIDTH{1'b1}}) begin end else if (input_axis_tkeep[CYCLE_KEEP_WIDTH-1:0] != {CYCLE_KEEP_WIDTH{1'b1}}) begin
// last cycle by tkeep fall in current cycle // last cycle by tkeep fall in current cycle
last_cycle = 1; last_cycle = 1'b1;
end else if (input_axis_tkeep[(CYCLE_KEEP_WIDTH*2)-1:CYCLE_KEEP_WIDTH] == {CYCLE_KEEP_WIDTH{1'b0}}) begin end else if (input_axis_tkeep[(CYCLE_KEEP_WIDTH*2)-1:CYCLE_KEEP_WIDTH] == {CYCLE_KEEP_WIDTH{1'b0}}) begin
// last cycle by tkeep fall at end of current cycle // last cycle by tkeep fall at end of current cycle
last_cycle = 1; last_cycle = 1'b1;
end else begin end else begin
last_cycle = 0; last_cycle = 1'b0;
end end
// pass complete input word, zero-extended to temp register // pass complete input word, zero-extended to temp register
@ -220,18 +221,18 @@ always @* begin
// short-circuit and get first word out the door // short-circuit and get first word out the door
output_axis_tdata_int = input_axis_tdata[CYCLE_DATA_WIDTH-1:0]; output_axis_tdata_int = input_axis_tdata[CYCLE_DATA_WIDTH-1:0];
output_axis_tkeep_int = input_axis_tkeep[CYCLE_KEEP_WIDTH-1:0]; output_axis_tkeep_int = input_axis_tkeep[CYCLE_KEEP_WIDTH-1:0];
output_axis_tvalid_int = 1; output_axis_tvalid_int = 1'b1;
output_axis_tlast_int = input_axis_tlast & last_cycle; output_axis_tlast_int = input_axis_tlast & last_cycle;
output_axis_tuser_int = input_axis_tuser & last_cycle; output_axis_tuser_int = input_axis_tuser & last_cycle;
if (output_axis_tready_int) begin if (output_axis_tready_int_reg) begin
// if output register is ready for first word, then move on to the next one // if output register is ready for first word, then move on to the next one
cycle_count_next = 1; cycle_count_next = 8'd1;
end end
if (!last_cycle || !output_axis_tready_int) begin if (!last_cycle || !output_axis_tready_int_reg) begin
// continue outputting words // continue outputting words
input_axis_tready_next = 0; input_axis_tready_next = 1'b0;
state_next = STATE_TRANSFER_OUT; state_next = STATE_TRANSFER_OUT;
end else begin end else begin
state_next = STATE_IDLE; state_next = STATE_IDLE;
@ -246,7 +247,7 @@ always @* begin
// only used when output is wider // only used when output is wider
// accept new data // accept new data
input_axis_tready_next = 1; input_axis_tready_next = 1'b1;
if (input_axis_tready & input_axis_tvalid) begin if (input_axis_tready & input_axis_tvalid) begin
// word transfer in - store in data register // word transfer in - store in data register
@ -265,7 +266,7 @@ always @* begin
state_next = STATE_TRANSFER_OUT; state_next = STATE_TRANSFER_OUT;
end else begin end else begin
// more words to read // more words to read
input_axis_tready_next = 1; input_axis_tready_next = 1'b1;
state_next = STATE_TRANSFER_IN; state_next = STATE_TRANSFER_IN;
end end
end else begin end else begin
@ -279,16 +280,16 @@ always @* begin
// output bus is wider // output bus is wider
// do not accept new data // do not accept new data
input_axis_tready_next = 0; input_axis_tready_next = 1'b0;
// single-cycle output of entire stored word (output wider) // single-cycle output of entire stored word (output wider)
output_axis_tdata_int = temp_tdata_reg; output_axis_tdata_int = temp_tdata_reg;
output_axis_tkeep_int = temp_tkeep_reg; output_axis_tkeep_int = temp_tkeep_reg;
output_axis_tvalid_int = 1; output_axis_tvalid_int = 1'b1;
output_axis_tlast_int = temp_tlast_reg; output_axis_tlast_int = temp_tlast_reg;
output_axis_tuser_int = temp_tuser_reg; output_axis_tuser_int = temp_tuser_reg;
if (output_axis_tready_int) begin if (output_axis_tready_int_reg) begin
// word transfer out // word transfer out
if (input_axis_tready & input_axis_tvalid) begin if (input_axis_tready & input_axis_tvalid) begin
@ -301,19 +302,19 @@ always @* begin
temp_tuser_next = input_axis_tuser; temp_tuser_next = input_axis_tuser;
// first input cycle complete // first input cycle complete
cycle_count_next = 1; cycle_count_next = 8'd1;
if (input_axis_tlast) begin if (input_axis_tlast) begin
// got last signal on first cycle, so output it // got last signal on first cycle, so output it
input_axis_tready_next = 0; input_axis_tready_next = 1'b0;
state_next = STATE_TRANSFER_OUT; state_next = STATE_TRANSFER_OUT;
end else begin end else begin
// otherwise, transfer in the rest of the words // otherwise, transfer in the rest of the words
input_axis_tready_next = 1; input_axis_tready_next = 1'b1;
state_next = STATE_TRANSFER_IN; state_next = STATE_TRANSFER_IN;
end end
end else begin end else begin
input_axis_tready_next = 1; input_axis_tready_next = 1'b1;
state_next = STATE_IDLE; state_next = STATE_IDLE;
end end
end else begin end else begin
@ -323,30 +324,30 @@ always @* begin
// output bus is narrower // output bus is narrower
// do not accept new data // do not accept new data
input_axis_tready_next = 0; input_axis_tready_next = 1'b0;
// is this the last cycle? // is this the last cycle?
if (cycle_count_reg == CYCLE_COUNT-1) begin if (cycle_count_reg == CYCLE_COUNT-1) begin
// last cycle by counter value // last cycle by counter value
last_cycle = 1; last_cycle = 1'b1;
end else if (temp_tkeep_reg[cycle_count_reg*CYCLE_KEEP_WIDTH +: CYCLE_KEEP_WIDTH] != {CYCLE_KEEP_WIDTH{1'b1}}) begin end else if (temp_tkeep_reg[cycle_count_reg*CYCLE_KEEP_WIDTH +: CYCLE_KEEP_WIDTH] != {CYCLE_KEEP_WIDTH{1'b1}}) begin
// last cycle by tkeep fall in current cycle // last cycle by tkeep fall in current cycle
last_cycle = 1; last_cycle = 1'b1;
end else if (temp_tkeep_reg[(cycle_count_reg+1)*CYCLE_KEEP_WIDTH +: CYCLE_KEEP_WIDTH] == {CYCLE_KEEP_WIDTH{1'b0}}) begin end else if (temp_tkeep_reg[(cycle_count_reg+1)*CYCLE_KEEP_WIDTH +: CYCLE_KEEP_WIDTH] == {CYCLE_KEEP_WIDTH{1'b0}}) begin
// last cycle by tkeep fall at end of current cycle // last cycle by tkeep fall at end of current cycle
last_cycle = 1; last_cycle = 1'b1;
end else begin end else begin
last_cycle = 0; last_cycle = 1'b0;
end end
// output current part of stored word (output narrower) // output current part of stored word (output narrower)
output_axis_tdata_int = temp_tdata_reg[cycle_count_reg*CYCLE_DATA_WIDTH +: CYCLE_DATA_WIDTH]; output_axis_tdata_int = temp_tdata_reg[cycle_count_reg*CYCLE_DATA_WIDTH +: CYCLE_DATA_WIDTH];
output_axis_tkeep_int = temp_tkeep_reg[cycle_count_reg*CYCLE_KEEP_WIDTH +: CYCLE_KEEP_WIDTH]; output_axis_tkeep_int = temp_tkeep_reg[cycle_count_reg*CYCLE_KEEP_WIDTH +: CYCLE_KEEP_WIDTH];
output_axis_tvalid_int = 1; output_axis_tvalid_int = 1'b1;
output_axis_tlast_int = temp_tlast_reg & last_cycle; output_axis_tlast_int = temp_tlast_reg & last_cycle;
output_axis_tuser_int = temp_tuser_reg & last_cycle; output_axis_tuser_int = temp_tuser_reg & last_cycle;
if (output_axis_tready_int) begin if (output_axis_tready_int_reg) begin
// word transfer out // word transfer out
cycle_count_next = cycle_count_reg + 1; cycle_count_next = cycle_count_reg + 1;
@ -354,7 +355,7 @@ always @* begin
if (last_cycle) begin if (last_cycle) begin
// terminated by counter or tlast signal // terminated by counter or tlast signal
input_axis_tready_next = 1; input_axis_tready_next = 1'b1;
state_next = STATE_IDLE; state_next = STATE_IDLE;
end else begin end else begin
// more words to write // more words to write
@ -371,38 +372,39 @@ end
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
state_reg <= STATE_IDLE; state_reg <= STATE_IDLE;
cycle_count_reg <= 0; cycle_count_reg <= 8'd0;
temp_tdata_reg <= 0; input_axis_tready_reg <= 1'b0;
temp_tkeep_reg <= 0;
temp_tlast_reg <= 0;
temp_tuser_reg <= 0;
input_axis_tready_reg <= 0;
end else begin end else begin
state_reg <= state_next; state_reg <= state_next;
input_axis_tready_reg <= input_axis_tready_next; input_axis_tready_reg <= input_axis_tready_next;
cycle_count_reg <= cycle_count_next;
end
temp_tdata_reg <= temp_tdata_next; temp_tdata_reg <= temp_tdata_next;
temp_tkeep_reg <= temp_tkeep_next; temp_tkeep_reg <= temp_tkeep_next;
temp_tlast_reg <= temp_tlast_next; temp_tlast_reg <= temp_tlast_next;
temp_tuser_reg <= temp_tuser_next; temp_tuser_reg <= temp_tuser_next;
cycle_count_reg <= cycle_count_next;
end
end end
// output datapath logic // output datapath logic
reg [OUTPUT_DATA_WIDTH-1:0] output_axis_tdata_reg = 0; reg [OUTPUT_DATA_WIDTH-1:0] output_axis_tdata_reg = {OUTPUT_DATA_WIDTH{1'b0}};
reg [OUTPUT_KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0; reg [OUTPUT_KEEP_WIDTH-1:0] output_axis_tkeep_reg = {OUTPUT_KEEP_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 0; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 0; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 0; reg output_axis_tuser_reg = 1'b0;
reg [OUTPUT_DATA_WIDTH-1:0] temp_axis_tdata_reg = 0; reg [OUTPUT_DATA_WIDTH-1:0] temp_axis_tdata_reg = {OUTPUT_DATA_WIDTH{1'b0}};
reg [OUTPUT_KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0; reg [OUTPUT_KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {OUTPUT_KEEP_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 0; reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 0; reg temp_axis_tlast_reg = 1'b0;
reg temp_axis_tuser_reg = 0; reg temp_axis_tuser_reg = 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_tdata = output_axis_tdata_reg;
assign output_axis_tkeep = output_axis_tkeep_reg; assign output_axis_tkeep = output_axis_tkeep_reg;
@ -410,56 +412,66 @@ assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg; assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg; assign output_axis_tuser = output_axis_tuser_reg;
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle // 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) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int); assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @(posedge clk) begin always @* begin
if (rst) begin
output_axis_tdata_reg <= 0;
output_axis_tkeep_reg <= 0;
output_axis_tvalid_reg <= 0;
output_axis_tlast_reg <= 0;
output_axis_tuser_reg <= 0;
output_axis_tready_int <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tkeep_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source // transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early; output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
if (output_axis_tready_int) begin 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 // input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output // output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int; output_axis_tvalid_next = output_axis_tvalid_int;
output_axis_tkeep_reg <= output_axis_tkeep_int; store_axis_int_to_output = 1'b1;
output_axis_tvalid_reg <= output_axis_tvalid_int;
output_axis_tlast_reg <= output_axis_tlast_int;
output_axis_tuser_reg <= output_axis_tuser_int;
end else begin end else begin
// output is not ready and currently valid, store input in temp // output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int; temp_axis_tvalid_next = output_axis_tvalid_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int; store_axis_int_to_temp = 1'b1;
temp_axis_tvalid_reg <= output_axis_tvalid_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end else if (output_axis_tready) begin end else if (output_axis_tready) begin
// input is not ready, but output is ready // 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_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_tdata_reg <= temp_axis_tdata_reg;
output_axis_tkeep_reg <= temp_axis_tkeep_reg; output_axis_tkeep_reg <= temp_axis_tkeep_reg;
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg; output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg; output_axis_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tkeep_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end 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_tuser_reg <= output_axis_tuser_int;
end end
end end

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -61,129 +61,163 @@ module axis_async_fifo #
output wire output_axis_tuser output wire output_axis_tuser
); );
reg [ADDR_WIDTH:0] wr_ptr = {ADDR_WIDTH+1{1'b0}}, wr_ptr_next; reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_next;
reg [ADDR_WIDTH:0] wr_ptr_gray = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_gray_next;
reg [ADDR_WIDTH:0] rd_ptr = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next; reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
reg [ADDR_WIDTH:0] rd_ptr_gray = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_gray_next;
reg [ADDR_WIDTH:0] wr_ptr_gray_sync1 = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_gray_sync1_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] wr_ptr_gray_sync2 = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_gray_sync2_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr_gray_sync1 = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_gray_sync1_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr_gray_sync2 = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_gray_sync2_reg = {ADDR_WIDTH+1{1'b0}};
reg input_rst_sync1 = 1; reg input_rst_sync1_reg = 1'b1;
reg input_rst_sync2 = 1; reg input_rst_sync2_reg = 1'b1;
reg input_rst_sync3 = 1; reg input_rst_sync3_reg = 1'b1;
reg output_rst_sync1 = 1; reg output_rst_sync1_reg = 1'b1;
reg output_rst_sync2 = 1; reg output_rst_sync2_reg = 1'b1;
reg output_rst_sync3 = 1; reg output_rst_sync3_reg = 1'b1;
reg [DATA_WIDTH+2-1:0] data_out_reg = {1'b0, 1'b0, {DATA_WIDTH{1'b0}}};
//(* RAM_STYLE="BLOCK" *)
reg [DATA_WIDTH+2-1:0] mem[(2**ADDR_WIDTH)-1:0]; reg [DATA_WIDTH+2-1:0] mem[(2**ADDR_WIDTH)-1:0];
reg output_axis_tvalid_reg = 1'b0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
wire [DATA_WIDTH+2-1:0] data_in = {input_axis_tlast, input_axis_tuser, input_axis_tdata}; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 1'b0;
// full when first TWO MSBs do NOT match, but rest matches // full when first TWO MSBs do NOT match, but rest matches
// (gray code equivalent of first MSB different but rest same) // (gray code equivalent of first MSB different but rest same)
wire full = ((wr_ptr_gray[ADDR_WIDTH] != rd_ptr_gray_sync2[ADDR_WIDTH]) && wire full = ((wr_ptr_gray_reg[ADDR_WIDTH] != rd_ptr_gray_sync2_reg[ADDR_WIDTH]) &&
(wr_ptr_gray[ADDR_WIDTH-1] != rd_ptr_gray_sync2[ADDR_WIDTH-1]) && (wr_ptr_gray_reg[ADDR_WIDTH-1] != rd_ptr_gray_sync2_reg[ADDR_WIDTH-1]) &&
(wr_ptr_gray[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2[ADDR_WIDTH-2:0])); (wr_ptr_gray_reg[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2_reg[ADDR_WIDTH-2:0]));
// empty when pointers match exactly // empty when pointers match exactly
wire empty = rd_ptr_gray == wr_ptr_gray_sync2; wire empty = rd_ptr_gray_reg == wr_ptr_gray_sync2_reg;
wire write = input_axis_tvalid & ~full; // control signals
wire read = (output_axis_tready | ~output_axis_tvalid_reg) & ~empty; reg write;
reg read;
assign {output_axis_tlast, output_axis_tuser, output_axis_tdata} = data_out_reg; assign input_axis_tready = ~full & ~input_rst_sync3_reg;
assign input_axis_tready = ~full & ~input_rst_sync3; assign output_axis_tdata = output_axis_tdata_reg;
assign output_axis_tvalid = output_axis_tvalid_reg; assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg;
// reset synchronization // reset synchronization
always @(posedge input_clk or posedge async_rst) begin always @(posedge input_clk or posedge async_rst) begin
if (async_rst) begin if (async_rst) begin
input_rst_sync1 <= 1; input_rst_sync1_reg <= 1'b1;
input_rst_sync2 <= 1; input_rst_sync2_reg <= 1'b1;
input_rst_sync3 <= 1; input_rst_sync3_reg <= 1'b1;
end else begin end else begin
input_rst_sync1 <= 0; input_rst_sync1_reg <= 1'b0;
input_rst_sync2 <= input_rst_sync1 | output_rst_sync1; input_rst_sync2_reg <= input_rst_sync1_reg | output_rst_sync1_reg;
input_rst_sync3 <= input_rst_sync2; input_rst_sync3_reg <= input_rst_sync2_reg;
end end
end end
always @(posedge output_clk or posedge async_rst) begin always @(posedge output_clk or posedge async_rst) begin
if (async_rst) begin if (async_rst) begin
output_rst_sync1 <= 1; output_rst_sync1_reg <= 1'b1;
output_rst_sync2 <= 1; output_rst_sync2_reg <= 1'b1;
output_rst_sync3 <= 1; output_rst_sync3_reg <= 1'b1;
end else begin end else begin
output_rst_sync1 <= 0; output_rst_sync1_reg <= 1'b0;
output_rst_sync2 <= output_rst_sync1; output_rst_sync2_reg <= output_rst_sync1_reg;
output_rst_sync3 <= output_rst_sync2; output_rst_sync3_reg <= output_rst_sync2_reg;
end
end
// Write logic
always @* begin
write = 1'b0;
wr_ptr_next = wr_ptr_reg;
wr_ptr_gray_next = wr_ptr_gray_reg;
if (input_axis_tvalid) begin
// input data valid
if (~full) begin
// not full, perform write
write = 1'b1;
wr_ptr_next = wr_ptr_reg + 1;
wr_ptr_gray_next = wr_ptr_next ^ (wr_ptr_next >> 1);
end
end end
end end
// write
always @(posedge input_clk) begin always @(posedge input_clk) begin
if (input_rst_sync3) begin if (input_rst_sync3_reg) begin
wr_ptr <= 0; wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_gray <= 0; wr_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
end else if (write) begin end else begin
mem[wr_ptr[ADDR_WIDTH-1:0]] <= data_in; wr_ptr_reg <= wr_ptr_next;
wr_ptr_next = wr_ptr + 1; wr_ptr_gray_reg <= wr_ptr_gray_next;
wr_ptr <= wr_ptr_next; end
wr_ptr_gray <= wr_ptr_next ^ (wr_ptr_next >> 1);
if (write) begin
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= {input_axis_tlast, input_axis_tuser, input_axis_tdata};
end end
end end
// pointer synchronization // pointer synchronization
always @(posedge input_clk) begin always @(posedge input_clk) begin
if (input_rst_sync3) begin if (input_rst_sync3_reg) begin
rd_ptr_gray_sync1 <= 0; rd_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
rd_ptr_gray_sync2 <= 0; rd_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
end else begin end else begin
rd_ptr_gray_sync1 <= rd_ptr_gray; rd_ptr_gray_sync1_reg <= rd_ptr_gray_reg;
rd_ptr_gray_sync2 <= rd_ptr_gray_sync1; rd_ptr_gray_sync2_reg <= rd_ptr_gray_sync1_reg;
end end
end end
// read
always @(posedge output_clk) begin always @(posedge output_clk) begin
if (output_rst_sync3) begin if (output_rst_sync3_reg) begin
rd_ptr <= 0; wr_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
rd_ptr_gray <= 0; wr_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
end else if (read) begin
data_out_reg <= mem[rd_ptr[ADDR_WIDTH-1:0]];
rd_ptr_next = rd_ptr + 1;
rd_ptr <= rd_ptr_next;
rd_ptr_gray <= rd_ptr_next ^ (rd_ptr_next >> 1);
end
end
// pointer synchronization
always @(posedge output_clk) begin
if (output_rst_sync3) begin
wr_ptr_gray_sync1 <= 0;
wr_ptr_gray_sync2 <= 0;
end else begin end else begin
wr_ptr_gray_sync1 <= wr_ptr_gray; wr_ptr_gray_sync1_reg <= wr_ptr_gray_reg;
wr_ptr_gray_sync2 <= wr_ptr_gray_sync1; wr_ptr_gray_sync2_reg <= wr_ptr_gray_sync1_reg;
end
end
// Read logic
always @* begin
read = 1'b0;
rd_ptr_next = rd_ptr_reg;
rd_ptr_gray_next = rd_ptr_gray_reg;
output_axis_tvalid_next = output_axis_tvalid_reg;
if (output_axis_tready | ~output_axis_tvalid) begin
// output data not valid OR currently being transferred
if (~empty) begin
// not empty, perform read
read = 1'b1;
output_axis_tvalid_next = 1'b1;
rd_ptr_next = rd_ptr_reg + 1;
rd_ptr_gray_next = rd_ptr_next ^ (rd_ptr_next >> 1);
end else begin
output_axis_tvalid_next = 1'b0;
end
end end
end end
// source ready output
always @(posedge output_clk) begin always @(posedge output_clk) begin
if (output_rst_sync3) begin if (output_rst_sync3_reg) begin
rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
rd_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
output_axis_tvalid_reg <= 1'b0; output_axis_tvalid_reg <= 1'b0;
end else if (output_axis_tready | ~output_axis_tvalid_reg) begin
output_axis_tvalid_reg <= ~empty;
end else begin end else begin
output_axis_tvalid_reg <= output_axis_tvalid_reg; rd_ptr_reg <= rd_ptr_next;
rd_ptr_gray_reg <= rd_ptr_gray_next;
output_axis_tvalid_reg <= output_axis_tvalid_next;
end
if (read) begin
{output_axis_tlast_reg, output_axis_tuser_reg, output_axis_tdata_reg} <= mem[rd_ptr_reg[ADDR_WIDTH-1:0]];
end end
end end

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -64,129 +64,165 @@ module axis_async_fifo_64 #
output wire output_axis_tuser output wire output_axis_tuser
); );
reg [ADDR_WIDTH:0] wr_ptr = {ADDR_WIDTH+1{1'b0}}, wr_ptr_next; reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_next;
reg [ADDR_WIDTH:0] wr_ptr_gray = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_gray_next;
reg [ADDR_WIDTH:0] rd_ptr = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next; reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
reg [ADDR_WIDTH:0] rd_ptr_gray = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_gray_next;
reg [ADDR_WIDTH:0] wr_ptr_gray_sync1 = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_gray_sync1_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] wr_ptr_gray_sync2 = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_gray_sync2_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr_gray_sync1 = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_gray_sync1_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr_gray_sync2 = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_gray_sync2_reg = {ADDR_WIDTH+1{1'b0}};
reg input_rst_sync1 = 1; reg input_rst_sync1_reg = 1'b1;
reg input_rst_sync2 = 1; reg input_rst_sync2_reg = 1'b1;
reg input_rst_sync3 = 1; reg input_rst_sync3_reg = 1'b1;
reg output_rst_sync1 = 1; reg output_rst_sync1_reg = 1'b1;
reg output_rst_sync2 = 1; reg output_rst_sync2_reg = 1'b1;
reg output_rst_sync3 = 1; reg output_rst_sync3_reg = 1'b1;
reg [DATA_WIDTH+KEEP_WIDTH+2-1:0] data_out_reg = {1'b0, 1'b0, {KEEP_WIDTH{1'b0}}, {DATA_WIDTH{1'b0}}};
//(* RAM_STYLE="BLOCK" *)
reg [DATA_WIDTH+KEEP_WIDTH+2-1:0] mem[(2**ADDR_WIDTH)-1:0]; reg [DATA_WIDTH+KEEP_WIDTH+2-1:0] mem[(2**ADDR_WIDTH)-1:0];
reg output_axis_tvalid_reg = 1'b0; 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}};
wire [DATA_WIDTH+KEEP_WIDTH+2-1:0] data_in = {input_axis_tlast, input_axis_tuser, input_axis_tkeep, input_axis_tdata}; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 1'b0;
// full when first TWO MSBs do NOT match, but rest matches // full when first TWO MSBs do NOT match, but rest matches
// (gray code equivalent of first MSB different but rest same) // (gray code equivalent of first MSB different but rest same)
wire full = ((wr_ptr_gray[ADDR_WIDTH] != rd_ptr_gray_sync2[ADDR_WIDTH]) && wire full = ((wr_ptr_gray_reg[ADDR_WIDTH] != rd_ptr_gray_sync2_reg[ADDR_WIDTH]) &&
(wr_ptr_gray[ADDR_WIDTH-1] != rd_ptr_gray_sync2[ADDR_WIDTH-1]) && (wr_ptr_gray_reg[ADDR_WIDTH-1] != rd_ptr_gray_sync2_reg[ADDR_WIDTH-1]) &&
(wr_ptr_gray[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2[ADDR_WIDTH-2:0])); (wr_ptr_gray_reg[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2_reg[ADDR_WIDTH-2:0]));
// empty when pointers match exactly // empty when pointers match exactly
wire empty = rd_ptr_gray == wr_ptr_gray_sync2; wire empty = rd_ptr_gray_reg == wr_ptr_gray_sync2_reg;
wire write = input_axis_tvalid & ~full; // control signals
wire read = (output_axis_tready | ~output_axis_tvalid_reg) & ~empty; reg write;
reg read;
assign {output_axis_tlast, output_axis_tuser, output_axis_tkeep, output_axis_tdata} = data_out_reg; assign input_axis_tready = ~full & ~input_rst_sync3_reg;
assign input_axis_tready = ~full & ~input_rst_sync3; assign output_axis_tdata = output_axis_tdata_reg;
assign output_axis_tkeep = output_axis_tkeep_reg;
assign output_axis_tvalid = output_axis_tvalid_reg; assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg;
// reset synchronization // reset synchronization
always @(posedge input_clk or posedge async_rst) begin always @(posedge input_clk or posedge async_rst) begin
if (async_rst) begin if (async_rst) begin
input_rst_sync1 <= 1; input_rst_sync1_reg <= 1'b1;
input_rst_sync2 <= 1; input_rst_sync2_reg <= 1'b1;
input_rst_sync3 <= 1; input_rst_sync3_reg <= 1'b1;
end else begin end else begin
input_rst_sync1 <= 0; input_rst_sync1_reg <= 1'b0;
input_rst_sync2 <= input_rst_sync1 | output_rst_sync1; input_rst_sync2_reg <= input_rst_sync1_reg | output_rst_sync1_reg;
input_rst_sync3 <= input_rst_sync2; input_rst_sync3_reg <= input_rst_sync2_reg;
end end
end end
always @(posedge output_clk or posedge async_rst) begin always @(posedge output_clk or posedge async_rst) begin
if (async_rst) begin if (async_rst) begin
output_rst_sync1 <= 1; output_rst_sync1_reg <= 1'b1;
output_rst_sync2 <= 1; output_rst_sync2_reg <= 1'b1;
output_rst_sync3 <= 1; output_rst_sync3_reg <= 1'b1;
end else begin end else begin
output_rst_sync1 <= 0; output_rst_sync1_reg <= 1'b0;
output_rst_sync2 <= output_rst_sync1; output_rst_sync2_reg <= output_rst_sync1_reg;
output_rst_sync3 <= output_rst_sync2; output_rst_sync3_reg <= output_rst_sync2_reg;
end
end
// Write logic
always @* begin
write = 1'b0;
wr_ptr_next = wr_ptr_reg;
wr_ptr_gray_next = wr_ptr_gray_reg;
if (input_axis_tvalid) begin
// input data valid
if (~full) begin
// not full, perform write
write = 1'b1;
wr_ptr_next = wr_ptr_reg + 1;
wr_ptr_gray_next = wr_ptr_next ^ (wr_ptr_next >> 1);
end
end end
end end
// write
always @(posedge input_clk) begin always @(posedge input_clk) begin
if (input_rst_sync3) begin if (input_rst_sync3_reg) begin
wr_ptr <= 0; wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_gray <= 0; wr_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
end else if (write) begin end else begin
mem[wr_ptr[ADDR_WIDTH-1:0]] <= data_in; wr_ptr_reg <= wr_ptr_next;
wr_ptr_next = wr_ptr + 1; wr_ptr_gray_reg <= wr_ptr_gray_next;
wr_ptr <= wr_ptr_next; end
wr_ptr_gray <= wr_ptr_next ^ (wr_ptr_next >> 1);
if (write) begin
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= {input_axis_tlast, input_axis_tuser, input_axis_tkeep, input_axis_tdata};
end end
end end
// pointer synchronization // pointer synchronization
always @(posedge input_clk) begin always @(posedge input_clk) begin
if (input_rst_sync3) begin if (input_rst_sync3_reg) begin
rd_ptr_gray_sync1 <= 0; rd_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
rd_ptr_gray_sync2 <= 0; rd_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
end else begin end else begin
rd_ptr_gray_sync1 <= rd_ptr_gray; rd_ptr_gray_sync1_reg <= rd_ptr_gray_reg;
rd_ptr_gray_sync2 <= rd_ptr_gray_sync1; rd_ptr_gray_sync2_reg <= rd_ptr_gray_sync1_reg;
end end
end end
// read
always @(posedge output_clk) begin always @(posedge output_clk) begin
if (output_rst_sync3) begin if (output_rst_sync3_reg) begin
rd_ptr <= 0; wr_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
rd_ptr_gray <= 0; wr_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
end else if (read) begin
data_out_reg <= mem[rd_ptr[ADDR_WIDTH-1:0]];
rd_ptr_next = rd_ptr + 1;
rd_ptr <= rd_ptr_next;
rd_ptr_gray <= rd_ptr_next ^ (rd_ptr_next >> 1);
end
end
// pointer synchronization
always @(posedge output_clk) begin
if (output_rst_sync3) begin
wr_ptr_gray_sync1 <= 0;
wr_ptr_gray_sync2 <= 0;
end else begin end else begin
wr_ptr_gray_sync1 <= wr_ptr_gray; wr_ptr_gray_sync1_reg <= wr_ptr_gray_reg;
wr_ptr_gray_sync2 <= wr_ptr_gray_sync1; wr_ptr_gray_sync2_reg <= wr_ptr_gray_sync1_reg;
end
end
// Read logic
always @* begin
read = 1'b0;
rd_ptr_next = rd_ptr_reg;
rd_ptr_gray_next = rd_ptr_gray_reg;
output_axis_tvalid_next = output_axis_tvalid_reg;
if (output_axis_tready | ~output_axis_tvalid) begin
// output data not valid OR currently being transferred
if (~empty) begin
// not empty, perform read
read = 1'b1;
output_axis_tvalid_next = 1'b1;
rd_ptr_next = rd_ptr_reg + 1;
rd_ptr_gray_next = rd_ptr_next ^ (rd_ptr_next >> 1);
end else begin
output_axis_tvalid_next = 1'b0;
end
end end
end end
// source ready output
always @(posedge output_clk) begin always @(posedge output_clk) begin
if (output_rst_sync3) begin if (output_rst_sync3_reg) begin
rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
rd_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
output_axis_tvalid_reg <= 1'b0; output_axis_tvalid_reg <= 1'b0;
end else if (output_axis_tready | ~output_axis_tvalid_reg) begin
output_axis_tvalid_reg <= ~empty;
end else begin end else begin
output_axis_tvalid_reg <= output_axis_tvalid_reg; rd_ptr_reg <= rd_ptr_next;
rd_ptr_gray_reg <= rd_ptr_gray_next;
output_axis_tvalid_reg <= output_axis_tvalid_next;
end
if (read) begin
{output_axis_tlast_reg, output_axis_tuser_reg, output_axis_tkeep_reg, output_axis_tdata_reg} <= mem[rd_ptr_reg[ADDR_WIDTH-1:0]];
end end
end end

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -71,226 +71,267 @@ module axis_async_frame_fifo #
output wire output_status_good_frame output wire output_status_good_frame
); );
reg [ADDR_WIDTH:0] wr_ptr = {ADDR_WIDTH+1{1'b0}}, wr_ptr_next; reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_next;
reg [ADDR_WIDTH:0] wr_ptr_cur = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_cur_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_cur_next;
reg [ADDR_WIDTH:0] wr_ptr_gray = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_gray_next;
reg [ADDR_WIDTH:0] rd_ptr = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next; reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
reg [ADDR_WIDTH:0] rd_ptr_gray = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_gray_next;
reg [ADDR_WIDTH:0] wr_ptr_gray_sync1 = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_gray_sync1_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] wr_ptr_gray_sync2 = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_gray_sync2_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr_gray_sync1 = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_gray_sync1_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr_gray_sync2 = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_gray_sync2_reg = {ADDR_WIDTH+1{1'b0}};
reg input_rst_sync1 = 1; reg input_rst_sync1_reg = 1'b1;
reg input_rst_sync2 = 1; reg input_rst_sync2_reg = 1'b1;
reg input_rst_sync3 = 1; reg input_rst_sync3_reg = 1'b1;
reg output_rst_sync1 = 1; reg output_rst_sync1_reg = 1'b1;
reg output_rst_sync2 = 1; reg output_rst_sync2_reg = 1'b1;
reg output_rst_sync3 = 1; reg output_rst_sync3_reg = 1'b1;
reg drop_frame = 1'b0; reg [DATA_WIDTH+1-1:0] mem[(2**ADDR_WIDTH)-1:0];
reg overflow_reg = 1'b0;
reg bad_frame_reg = 1'b0;
reg good_frame_reg = 1'b0;
reg overflow_sync1 = 1'b0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg overflow_sync2 = 1'b0; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg overflow_sync3 = 1'b0; reg output_axis_tlast_reg = 1'b0;
reg overflow_sync4 = 1'b0;
reg bad_frame_sync1 = 1'b0;
reg bad_frame_sync2 = 1'b0;
reg bad_frame_sync3 = 1'b0;
reg bad_frame_sync4 = 1'b0;
reg good_frame_sync1 = 1'b0;
reg good_frame_sync2 = 1'b0;
reg good_frame_sync3 = 1'b0;
reg good_frame_sync4 = 1'b0;
reg [DATA_WIDTH+2-1:0] data_out_reg = {1'b0, {DATA_WIDTH{1'b0}}};
//(* RAM_STYLE="BLOCK" *)
reg [DATA_WIDTH+2-1:0] mem[(2**ADDR_WIDTH)-1:0];
reg output_axis_tvalid_reg = 1'b0;
wire [DATA_WIDTH+2-1:0] data_in = {input_axis_tlast, input_axis_tdata};
// full when first TWO MSBs do NOT match, but rest matches // full when first TWO MSBs do NOT match, but rest matches
// (gray code equivalent of first MSB different but rest same) // (gray code equivalent of first MSB different but rest same)
wire full = ((wr_ptr_gray[ADDR_WIDTH] != rd_ptr_gray_sync2[ADDR_WIDTH]) && wire full = ((wr_ptr_gray_reg[ADDR_WIDTH] != rd_ptr_gray_sync2_reg[ADDR_WIDTH]) &&
(wr_ptr_gray[ADDR_WIDTH-1] != rd_ptr_gray_sync2[ADDR_WIDTH-1]) && (wr_ptr_gray_reg[ADDR_WIDTH-1] != rd_ptr_gray_sync2_reg[ADDR_WIDTH-1]) &&
(wr_ptr_gray[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2[ADDR_WIDTH-2:0])); (wr_ptr_gray_reg[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2_reg[ADDR_WIDTH-2:0]));
// empty when pointers match exactly // empty when pointers match exactly
wire empty = rd_ptr_gray == wr_ptr_gray_sync2; wire empty = rd_ptr_gray_reg == wr_ptr_gray_sync2_reg;
// overflow in single packet // overflow within packet
wire full_cur = ((wr_ptr[ADDR_WIDTH] != wr_ptr_cur[ADDR_WIDTH]) && wire full_cur = ((wr_ptr_reg[ADDR_WIDTH] != wr_ptr_cur_reg[ADDR_WIDTH]) &&
(wr_ptr[ADDR_WIDTH-1:0] == wr_ptr_cur[ADDR_WIDTH-1:0])); (wr_ptr_reg[ADDR_WIDTH-1:0] == wr_ptr_cur_reg[ADDR_WIDTH-1:0]));
wire write = input_axis_tvalid & (~full | DROP_WHEN_FULL); // control signals
wire read = (output_axis_tready | ~output_axis_tvalid_reg) & ~empty; reg write;
reg read;
assign {output_axis_tlast, output_axis_tdata} = data_out_reg; reg drop_frame_reg = 1'b0, drop_frame_next;
reg overflow_reg = 1'b0, overflow_next;
reg bad_frame_reg = 1'b0, bad_frame_next;
reg good_frame_reg = 1'b0, good_frame_next;
assign input_axis_tready = (~full | DROP_WHEN_FULL) & ~input_rst_sync3; reg overflow_sync1_reg = 1'b0;
reg overflow_sync2_reg = 1'b0;
reg overflow_sync3_reg = 1'b0;
reg overflow_sync4_reg = 1'b0;
reg bad_frame_sync1_reg = 1'b0;
reg bad_frame_sync2_reg = 1'b0;
reg bad_frame_sync3_reg = 1'b0;
reg bad_frame_sync4_reg = 1'b0;
reg good_frame_sync1_reg = 1'b0;
reg good_frame_sync2_reg = 1'b0;
reg good_frame_sync3_reg = 1'b0;
reg good_frame_sync4_reg = 1'b0;
assign input_axis_tready = (~full | DROP_WHEN_FULL) & ~input_rst_sync3_reg;
assign output_axis_tdata = output_axis_tdata_reg;
assign output_axis_tvalid = output_axis_tvalid_reg; assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg;
assign input_status_overflow = overflow_reg; assign input_status_overflow = overflow_reg;
assign input_status_bad_frame = bad_frame_reg; assign input_status_bad_frame = bad_frame_reg;
assign input_status_good_frame = good_frame_reg; assign input_status_good_frame = good_frame_reg;
assign output_status_overflow = overflow_sync3 ^ overflow_sync4; assign output_status_overflow = overflow_sync3_reg ^ overflow_sync4_reg;
assign output_status_bad_frame = bad_frame_sync3 ^ bad_frame_sync4; assign output_status_bad_frame = bad_frame_sync3_reg ^ bad_frame_sync4_reg;
assign output_status_good_frame = good_frame_sync3 ^ good_frame_sync4; assign output_status_good_frame = good_frame_sync3_reg ^ good_frame_sync4_reg;
// reset synchronization // reset synchronization
always @(posedge input_clk or posedge async_rst) begin always @(posedge input_clk or posedge async_rst) begin
if (async_rst) begin if (async_rst) begin
input_rst_sync1 <= 1; input_rst_sync1_reg <= 1'b1;
input_rst_sync2 <= 1; input_rst_sync2_reg <= 1'b1;
input_rst_sync3 <= 1; input_rst_sync3_reg <= 1'b1;
end else begin end else begin
input_rst_sync1 <= 0; input_rst_sync1_reg <= 1'b0;
input_rst_sync2 <= input_rst_sync1 | output_rst_sync1; input_rst_sync2_reg <= input_rst_sync1_reg | output_rst_sync1_reg;
input_rst_sync3 <= input_rst_sync2; input_rst_sync3_reg <= input_rst_sync2_reg;
end end
end end
always @(posedge output_clk or posedge async_rst) begin always @(posedge output_clk or posedge async_rst) begin
if (async_rst) begin if (async_rst) begin
output_rst_sync1 <= 1; output_rst_sync1_reg <= 1'b1;
output_rst_sync2 <= 1; output_rst_sync2_reg <= 1'b1;
output_rst_sync3 <= 1; output_rst_sync3_reg <= 1'b1;
end else begin end else begin
output_rst_sync1 <= 0; output_rst_sync1_reg <= 1'b0;
output_rst_sync2 <= output_rst_sync1; output_rst_sync2_reg <= output_rst_sync1_reg;
output_rst_sync3 <= output_rst_sync2; output_rst_sync3_reg <= output_rst_sync2_reg;
end end
end end
// write // Write logic
always @(posedge input_clk) begin always @* begin
if (input_rst_sync3) begin write = 1'b0;
wr_ptr <= 0;
wr_ptr_cur <= 0; drop_frame_next = 1'b0;
wr_ptr_gray <= 0; overflow_next = 1'b0;
drop_frame <= 0; bad_frame_next = 1'b0;
overflow_reg <= 0; good_frame_next = 1'b0;
bad_frame_reg <= 0;
good_frame_reg <= 0; wr_ptr_next = wr_ptr_reg;
end else if (write) begin wr_ptr_cur_next = wr_ptr_cur_reg;
overflow_reg <= 0; wr_ptr_gray_next = wr_ptr_gray_reg;
bad_frame_reg <= 0;
good_frame_reg <= 0; if (input_axis_tvalid) begin
if (full | full_cur | drop_frame) begin // input data valid
// buffer full, hold current pointer, drop packet at end if (~full | DROP_WHEN_FULL) begin
drop_frame <= 1; // not full, perform write
if (full | full_cur | drop_frame_reg) begin
// full, packet overflow, or currently dropping frame
// drop frame
drop_frame_next = 1'b1;
if (input_axis_tlast) begin if (input_axis_tlast) begin
wr_ptr_cur <= wr_ptr; // end of frame, reset write pointer
drop_frame <= 0; wr_ptr_cur_next = wr_ptr_reg;
overflow_reg <= 1; drop_frame_next = 1'b0;
overflow_next = 1'b1;
end end
end else begin end else begin
mem[wr_ptr_cur[ADDR_WIDTH-1:0]] <= data_in; write = 1'b1;
wr_ptr_cur <= wr_ptr_cur + 1; wr_ptr_cur_next = wr_ptr_cur_reg + 1;
if (input_axis_tlast) begin if (input_axis_tlast) begin
// end of frame
if (input_axis_tuser) begin if (input_axis_tuser) begin
// bad packet, reset write pointer // bad packet, reset write pointer
wr_ptr_cur <= wr_ptr; wr_ptr_cur_next = wr_ptr_reg;
bad_frame_reg <= 1; bad_frame_next = 1'b1;
end else begin end else begin
// good packet, push new write pointer // good packet, update write pointer
wr_ptr_next = wr_ptr_cur + 1; wr_ptr_next = wr_ptr_cur_reg + 1;
wr_ptr <= wr_ptr_next; wr_ptr_gray_next = wr_ptr_next ^ (wr_ptr_next >> 1);
wr_ptr_gray <= wr_ptr_next ^ (wr_ptr_next >> 1); good_frame_next = 1'b1;
good_frame_reg <= 1;
end end
end end
end end
end
end
end
always @(posedge input_clk) begin
if (input_rst_sync3_reg) begin
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_cur_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
drop_frame_reg <= 1'b0;
overflow_reg <= 1'b0;
bad_frame_reg <= 1'b0;
good_frame_reg <= 1'b0;
end else begin end else begin
overflow_reg <= 0; wr_ptr_reg <= wr_ptr_next;
bad_frame_reg <= 0; wr_ptr_cur_reg <= wr_ptr_cur_next;
good_frame_reg <= 0; wr_ptr_gray_reg <= wr_ptr_gray_next;
drop_frame_reg <= drop_frame_next;
overflow_reg <= overflow_next;
bad_frame_reg <= bad_frame_next;
good_frame_reg <= good_frame_next;
end
if (write) begin
mem[wr_ptr_cur_reg[ADDR_WIDTH-1:0]] <= {input_axis_tlast, input_axis_tdata};
end end
end end
// pointer synchronization // pointer synchronization
always @(posedge input_clk) begin always @(posedge input_clk) begin
if (input_rst_sync3) begin if (input_rst_sync3_reg) begin
rd_ptr_gray_sync1 <= 0; rd_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
rd_ptr_gray_sync2 <= 0; rd_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
end else begin end else begin
rd_ptr_gray_sync1 <= rd_ptr_gray; rd_ptr_gray_sync1_reg <= rd_ptr_gray_reg;
rd_ptr_gray_sync2 <= rd_ptr_gray_sync1; rd_ptr_gray_sync2_reg <= rd_ptr_gray_sync1_reg;
end end
end end
// read
always @(posedge output_clk) begin always @(posedge output_clk) begin
if (output_rst_sync3) begin if (output_rst_sync3_reg) begin
rd_ptr <= 0; wr_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
rd_ptr_gray <= 0; wr_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
end else if (read) begin
data_out_reg <= mem[rd_ptr[ADDR_WIDTH-1:0]];
rd_ptr_next = rd_ptr + 1;
rd_ptr <= rd_ptr_next;
rd_ptr_gray <= rd_ptr_next ^ (rd_ptr_next >> 1);
end
end
// pointer synchronization
always @(posedge output_clk) begin
if (output_rst_sync3) begin
wr_ptr_gray_sync1 <= 0;
wr_ptr_gray_sync2 <= 0;
end else begin end else begin
wr_ptr_gray_sync1 <= wr_ptr_gray; wr_ptr_gray_sync1_reg <= wr_ptr_gray_reg;
wr_ptr_gray_sync2 <= wr_ptr_gray_sync1; wr_ptr_gray_sync2_reg <= wr_ptr_gray_sync1_reg;
end
end
// source ready output
always @(posedge output_clk) begin
if (output_rst_sync3) begin
output_axis_tvalid_reg <= 1'b0;
end else if (output_axis_tready | ~output_axis_tvalid_reg) begin
output_axis_tvalid_reg <= ~empty;
end else begin
output_axis_tvalid_reg <= output_axis_tvalid_reg;
end end
end end
// status synchronization // status synchronization
always @(posedge input_clk) begin always @(posedge input_clk) begin
if (input_rst_sync3) begin if (input_rst_sync3_reg) begin
overflow_sync1 <= 1'b0; overflow_sync1_reg <= 1'b0;
bad_frame_sync1 <= 1'b0; bad_frame_sync1_reg <= 1'b0;
good_frame_sync1 <= 1'b0; good_frame_sync1_reg <= 1'b0;
end else begin end else begin
overflow_sync1 <= overflow_sync1 ^ overflow_reg; overflow_sync1_reg <= overflow_sync1_reg ^ overflow_reg;
bad_frame_sync1 <= bad_frame_sync1 ^ bad_frame_reg; bad_frame_sync1_reg <= bad_frame_sync1_reg ^ bad_frame_reg;
good_frame_sync1 <= good_frame_sync1 ^ good_frame_reg; good_frame_sync1_reg <= good_frame_sync1_reg ^ good_frame_reg;
end end
end end
always @(posedge output_clk) begin always @(posedge output_clk) begin
if (output_rst_sync3) begin if (output_rst_sync3_reg) begin
overflow_sync2 <= 1'b0; overflow_sync2_reg <= 1'b0;
overflow_sync3 <= 1'b0; overflow_sync3_reg <= 1'b0;
bad_frame_sync2 <= 1'b0; bad_frame_sync2_reg <= 1'b0;
bad_frame_sync3 <= 1'b0; bad_frame_sync3_reg <= 1'b0;
good_frame_sync2 <= 1'b0; good_frame_sync2_reg <= 1'b0;
good_frame_sync3 <= 1'b0; good_frame_sync3_reg <= 1'b0;
end else begin end else begin
overflow_sync2 <= overflow_sync1; overflow_sync2_reg <= overflow_sync1_reg;
overflow_sync3 <= overflow_sync2; overflow_sync3_reg <= overflow_sync2_reg;
overflow_sync4 <= overflow_sync3; overflow_sync4_reg <= overflow_sync3_reg;
bad_frame_sync2 <= bad_frame_sync1; bad_frame_sync2_reg <= bad_frame_sync1_reg;
bad_frame_sync3 <= bad_frame_sync2; bad_frame_sync3_reg <= bad_frame_sync2_reg;
bad_frame_sync4 <= bad_frame_sync3; bad_frame_sync4_reg <= bad_frame_sync3_reg;
good_frame_sync2 <= good_frame_sync1; good_frame_sync2_reg <= good_frame_sync1_reg;
good_frame_sync3 <= good_frame_sync2; good_frame_sync3_reg <= good_frame_sync2_reg;
good_frame_sync4 <= good_frame_sync3; good_frame_sync4_reg <= good_frame_sync3_reg;
end
end
// Read logic
always @* begin
read = 1'b0;
rd_ptr_next = rd_ptr_reg;
rd_ptr_gray_next = rd_ptr_gray_reg;
output_axis_tvalid_next = output_axis_tvalid_reg;
if (output_axis_tready | ~output_axis_tvalid) begin
// output data not valid OR currently being transferred
if (~empty) begin
// not empty, perform read
read = 1'b1;
output_axis_tvalid_next = 1'b1;
rd_ptr_next = rd_ptr_reg + 1;
rd_ptr_gray_next = rd_ptr_next ^ (rd_ptr_next >> 1);
end else begin
output_axis_tvalid_next = 1'b0;
end
end
end
always @(posedge output_clk) begin
if (output_rst_sync3_reg) begin
rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
rd_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
output_axis_tvalid_reg <= 1'b0;
end else begin
rd_ptr_reg <= rd_ptr_next;
rd_ptr_gray_reg <= rd_ptr_gray_next;
output_axis_tvalid_reg <= output_axis_tvalid_next;
end
if (read) begin
{output_axis_tlast_reg, output_axis_tdata_reg} <= mem[rd_ptr_reg[ADDR_WIDTH-1:0]];
end end
end end

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -74,226 +74,269 @@ module axis_async_frame_fifo_64 #
output wire output_status_good_frame output wire output_status_good_frame
); );
reg [ADDR_WIDTH:0] wr_ptr = {ADDR_WIDTH+1{1'b0}}, wr_ptr_next; reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_next;
reg [ADDR_WIDTH:0] wr_ptr_cur = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_cur_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_cur_next;
reg [ADDR_WIDTH:0] wr_ptr_gray = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_gray_next;
reg [ADDR_WIDTH:0] rd_ptr = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next; reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
reg [ADDR_WIDTH:0] rd_ptr_gray = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_gray_next;
reg [ADDR_WIDTH:0] wr_ptr_gray_sync1 = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_gray_sync1_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] wr_ptr_gray_sync2 = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_gray_sync2_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr_gray_sync1 = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_gray_sync1_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr_gray_sync2 = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_gray_sync2_reg = {ADDR_WIDTH+1{1'b0}};
reg input_rst_sync1 = 1; reg input_rst_sync1_reg = 1'b1;
reg input_rst_sync2 = 1; reg input_rst_sync2_reg = 1'b1;
reg input_rst_sync3 = 1; reg input_rst_sync3_reg = 1'b1;
reg output_rst_sync1 = 1; reg output_rst_sync1_reg = 1'b1;
reg output_rst_sync2 = 1; reg output_rst_sync2_reg = 1'b1;
reg output_rst_sync3 = 1; reg output_rst_sync3_reg = 1'b1;
reg drop_frame = 1'b0; reg [DATA_WIDTH+KEEP_WIDTH+1-1:0] mem[(2**ADDR_WIDTH)-1:0];
reg overflow_reg = 1'b0;
reg bad_frame_reg = 1'b0;
reg good_frame_reg = 1'b0;
reg overflow_sync1 = 1'b0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg overflow_sync2 = 1'b0; reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg overflow_sync3 = 1'b0; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg overflow_sync4 = 1'b0; reg output_axis_tlast_reg = 1'b0;
reg bad_frame_sync1 = 1'b0;
reg bad_frame_sync2 = 1'b0;
reg bad_frame_sync3 = 1'b0;
reg bad_frame_sync4 = 1'b0;
reg good_frame_sync1 = 1'b0;
reg good_frame_sync2 = 1'b0;
reg good_frame_sync3 = 1'b0;
reg good_frame_sync4 = 1'b0;
reg [DATA_WIDTH+KEEP_WIDTH+2-1:0] data_out_reg = {1'b0, {KEEP_WIDTH{1'b0}}, {DATA_WIDTH{1'b0}}};
//(* RAM_STYLE="BLOCK" *)
reg [DATA_WIDTH+KEEP_WIDTH+2-1:0] mem[(2**ADDR_WIDTH)-1:0];
reg output_axis_tvalid_reg = 1'b0;
wire [DATA_WIDTH+KEEP_WIDTH+2-1:0] data_in = {input_axis_tlast, input_axis_tkeep, input_axis_tdata};
// full when first TWO MSBs do NOT match, but rest matches // full when first TWO MSBs do NOT match, but rest matches
// (gray code equivalent of first MSB different but rest same) // (gray code equivalent of first MSB different but rest same)
wire full = ((wr_ptr_gray[ADDR_WIDTH] != rd_ptr_gray_sync2[ADDR_WIDTH]) && wire full = ((wr_ptr_gray_reg[ADDR_WIDTH] != rd_ptr_gray_sync2_reg[ADDR_WIDTH]) &&
(wr_ptr_gray[ADDR_WIDTH-1] != rd_ptr_gray_sync2[ADDR_WIDTH-1]) && (wr_ptr_gray_reg[ADDR_WIDTH-1] != rd_ptr_gray_sync2_reg[ADDR_WIDTH-1]) &&
(wr_ptr_gray[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2[ADDR_WIDTH-2:0])); (wr_ptr_gray_reg[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2_reg[ADDR_WIDTH-2:0]));
// empty when pointers match exactly // empty when pointers match exactly
wire empty = rd_ptr_gray == wr_ptr_gray_sync2; wire empty = rd_ptr_gray_reg == wr_ptr_gray_sync2_reg;
// overflow in single packet // overflow within packet
wire full_cur = ((wr_ptr[ADDR_WIDTH] != wr_ptr_cur[ADDR_WIDTH]) && wire full_cur = ((wr_ptr_reg[ADDR_WIDTH] != wr_ptr_cur_reg[ADDR_WIDTH]) &&
(wr_ptr[ADDR_WIDTH-1:0] == wr_ptr_cur[ADDR_WIDTH-1:0])); (wr_ptr_reg[ADDR_WIDTH-1:0] == wr_ptr_cur_reg[ADDR_WIDTH-1:0]));
wire write = input_axis_tvalid & (~full | DROP_WHEN_FULL); // control signals
wire read = (output_axis_tready | ~output_axis_tvalid_reg) & ~empty; reg write;
reg read;
assign {output_axis_tlast, output_axis_tkeep, output_axis_tdata} = data_out_reg; reg drop_frame_reg = 1'b0, drop_frame_next;
reg overflow_reg = 1'b0, overflow_next;
reg bad_frame_reg = 1'b0, bad_frame_next;
reg good_frame_reg = 1'b0, good_frame_next;
assign input_axis_tready = (~full | DROP_WHEN_FULL) & ~input_rst_sync3; reg overflow_sync1_reg = 1'b0;
reg overflow_sync2_reg = 1'b0;
reg overflow_sync3_reg = 1'b0;
reg overflow_sync4_reg = 1'b0;
reg bad_frame_sync1_reg = 1'b0;
reg bad_frame_sync2_reg = 1'b0;
reg bad_frame_sync3_reg = 1'b0;
reg bad_frame_sync4_reg = 1'b0;
reg good_frame_sync1_reg = 1'b0;
reg good_frame_sync2_reg = 1'b0;
reg good_frame_sync3_reg = 1'b0;
reg good_frame_sync4_reg = 1'b0;
assign input_axis_tready = (~full | DROP_WHEN_FULL) & ~input_rst_sync3_reg;
assign output_axis_tdata = output_axis_tdata_reg;
assign output_axis_tkeep = output_axis_tkeep_reg;
assign output_axis_tvalid = output_axis_tvalid_reg; assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg;
assign input_status_overflow = overflow_reg; assign input_status_overflow = overflow_reg;
assign input_status_bad_frame = bad_frame_reg; assign input_status_bad_frame = bad_frame_reg;
assign input_status_good_frame = good_frame_reg; assign input_status_good_frame = good_frame_reg;
assign output_status_overflow = overflow_sync3 ^ overflow_sync4; assign output_status_overflow = overflow_sync3_reg ^ overflow_sync4_reg;
assign output_status_bad_frame = bad_frame_sync3 ^ bad_frame_sync4; assign output_status_bad_frame = bad_frame_sync3_reg ^ bad_frame_sync4_reg;
assign output_status_good_frame = good_frame_sync3 ^ good_frame_sync4; assign output_status_good_frame = good_frame_sync3_reg ^ good_frame_sync4_reg;
// reset synchronization // reset synchronization
always @(posedge input_clk or posedge async_rst) begin always @(posedge input_clk or posedge async_rst) begin
if (async_rst) begin if (async_rst) begin
input_rst_sync1 <= 1; input_rst_sync1_reg <= 1'b1;
input_rst_sync2 <= 1; input_rst_sync2_reg <= 1'b1;
input_rst_sync3 <= 1; input_rst_sync3_reg <= 1'b1;
end else begin end else begin
input_rst_sync1 <= 0; input_rst_sync1_reg <= 1'b0;
input_rst_sync2 <= input_rst_sync1 | output_rst_sync1; input_rst_sync2_reg <= input_rst_sync1_reg | output_rst_sync1_reg;
input_rst_sync3 <= input_rst_sync2; input_rst_sync3_reg <= input_rst_sync2_reg;
end end
end end
always @(posedge output_clk or posedge async_rst) begin always @(posedge output_clk or posedge async_rst) begin
if (async_rst) begin if (async_rst) begin
output_rst_sync1 <= 1; output_rst_sync1_reg <= 1'b1;
output_rst_sync2 <= 1; output_rst_sync2_reg <= 1'b1;
output_rst_sync3 <= 1; output_rst_sync3_reg <= 1'b1;
end else begin end else begin
output_rst_sync1 <= 0; output_rst_sync1_reg <= 1'b0;
output_rst_sync2 <= output_rst_sync1; output_rst_sync2_reg <= output_rst_sync1_reg;
output_rst_sync3 <= output_rst_sync2; output_rst_sync3_reg <= output_rst_sync2_reg;
end end
end end
// write // Write logic
always @(posedge input_clk) begin always @* begin
if (input_rst_sync3) begin write = 1'b0;
wr_ptr <= 0;
wr_ptr_cur <= 0; drop_frame_next = 1'b0;
wr_ptr_gray <= 0; overflow_next = 1'b0;
drop_frame <= 0; bad_frame_next = 1'b0;
overflow_reg <= 0; good_frame_next = 1'b0;
bad_frame_reg <= 0;
good_frame_reg <= 0; wr_ptr_next = wr_ptr_reg;
end else if (write) begin wr_ptr_cur_next = wr_ptr_cur_reg;
overflow_reg <= 0; wr_ptr_gray_next = wr_ptr_gray_reg;
bad_frame_reg <= 0;
good_frame_reg <= 0; if (input_axis_tvalid) begin
if (full | full_cur | drop_frame) begin // input data valid
// buffer full, hold current pointer, drop packet at end if (~full | DROP_WHEN_FULL) begin
drop_frame <= 1; // not full, perform write
if (full | full_cur | drop_frame_reg) begin
// full, packet overflow, or currently dropping frame
// drop frame
drop_frame_next = 1'b1;
if (input_axis_tlast) begin if (input_axis_tlast) begin
wr_ptr_cur <= wr_ptr; // end of frame, reset write pointer
drop_frame <= 0; wr_ptr_cur_next = wr_ptr_reg;
overflow_reg <= 1; drop_frame_next = 1'b0;
overflow_next = 1'b1;
end end
end else begin end else begin
mem[wr_ptr_cur[ADDR_WIDTH-1:0]] <= data_in; write = 1'b1;
wr_ptr_cur <= wr_ptr_cur + 1; wr_ptr_cur_next = wr_ptr_cur_reg + 1;
if (input_axis_tlast) begin if (input_axis_tlast) begin
// end of frame
if (input_axis_tuser) begin if (input_axis_tuser) begin
// bad packet, reset write pointer // bad packet, reset write pointer
wr_ptr_cur <= wr_ptr; wr_ptr_cur_next = wr_ptr_reg;
bad_frame_reg <= 1; bad_frame_next = 1'b1;
end else begin end else begin
// good packet, push new write pointer // good packet, update write pointer
wr_ptr_next = wr_ptr_cur + 1; wr_ptr_next = wr_ptr_cur_reg + 1;
wr_ptr <= wr_ptr_next; wr_ptr_gray_next = wr_ptr_next ^ (wr_ptr_next >> 1);
wr_ptr_gray <= wr_ptr_next ^ (wr_ptr_next >> 1); good_frame_next = 1'b1;
good_frame_reg <= 1;
end end
end end
end end
end
end
end
always @(posedge input_clk) begin
if (input_rst_sync3_reg) begin
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_cur_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
drop_frame_reg <= 1'b0;
overflow_reg <= 1'b0;
bad_frame_reg <= 1'b0;
good_frame_reg <= 1'b0;
end else begin end else begin
overflow_reg <= 0; wr_ptr_reg <= wr_ptr_next;
bad_frame_reg <= 0; wr_ptr_cur_reg <= wr_ptr_cur_next;
good_frame_reg <= 0; wr_ptr_gray_reg <= wr_ptr_gray_next;
drop_frame_reg <= drop_frame_next;
overflow_reg <= overflow_next;
bad_frame_reg <= bad_frame_next;
good_frame_reg <= good_frame_next;
end
if (write) begin
mem[wr_ptr_cur_reg[ADDR_WIDTH-1:0]] <= {input_axis_tlast, input_axis_tkeep, input_axis_tdata};
end end
end end
// pointer synchronization // pointer synchronization
always @(posedge input_clk) begin always @(posedge input_clk) begin
if (input_rst_sync3) begin if (input_rst_sync3_reg) begin
rd_ptr_gray_sync1 <= 0; rd_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
rd_ptr_gray_sync2 <= 0; rd_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
end else begin end else begin
rd_ptr_gray_sync1 <= rd_ptr_gray; rd_ptr_gray_sync1_reg <= rd_ptr_gray_reg;
rd_ptr_gray_sync2 <= rd_ptr_gray_sync1; rd_ptr_gray_sync2_reg <= rd_ptr_gray_sync1_reg;
end end
end end
// read
always @(posedge output_clk) begin always @(posedge output_clk) begin
if (output_rst_sync3) begin if (output_rst_sync3_reg) begin
rd_ptr <= 0; wr_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
rd_ptr_gray <= 0; wr_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
end else if (read) begin
data_out_reg <= mem[rd_ptr[ADDR_WIDTH-1:0]];
rd_ptr_next = rd_ptr + 1;
rd_ptr <= rd_ptr_next;
rd_ptr_gray <= rd_ptr_next ^ (rd_ptr_next >> 1);
end
end
// pointer synchronization
always @(posedge output_clk) begin
if (output_rst_sync3) begin
wr_ptr_gray_sync1 <= 0;
wr_ptr_gray_sync2 <= 0;
end else begin end else begin
wr_ptr_gray_sync1 <= wr_ptr_gray; wr_ptr_gray_sync1_reg <= wr_ptr_gray_reg;
wr_ptr_gray_sync2 <= wr_ptr_gray_sync1; wr_ptr_gray_sync2_reg <= wr_ptr_gray_sync1_reg;
end
end
// source ready output
always @(posedge output_clk) begin
if (output_rst_sync3) begin
output_axis_tvalid_reg <= 1'b0;
end else if (output_axis_tready | ~output_axis_tvalid_reg) begin
output_axis_tvalid_reg <= ~empty;
end else begin
output_axis_tvalid_reg <= output_axis_tvalid_reg;
end end
end end
// status synchronization // status synchronization
always @(posedge input_clk) begin always @(posedge input_clk) begin
if (input_rst_sync3) begin if (input_rst_sync3_reg) begin
overflow_sync1 <= 1'b0; overflow_sync1_reg <= 1'b0;
bad_frame_sync1 <= 1'b0; bad_frame_sync1_reg <= 1'b0;
good_frame_sync1 <= 1'b0; good_frame_sync1_reg <= 1'b0;
end else begin end else begin
overflow_sync1 <= overflow_sync1 ^ overflow_reg; overflow_sync1_reg <= overflow_sync1_reg ^ overflow_reg;
bad_frame_sync1 <= bad_frame_sync1 ^ bad_frame_reg; bad_frame_sync1_reg <= bad_frame_sync1_reg ^ bad_frame_reg;
good_frame_sync1 <= good_frame_sync1 ^ good_frame_reg; good_frame_sync1_reg <= good_frame_sync1_reg ^ good_frame_reg;
end end
end end
always @(posedge output_clk) begin always @(posedge output_clk) begin
if (output_rst_sync3) begin if (output_rst_sync3_reg) begin
overflow_sync2 <= 1'b0; overflow_sync2_reg <= 1'b0;
overflow_sync3 <= 1'b0; overflow_sync3_reg <= 1'b0;
bad_frame_sync2 <= 1'b0; bad_frame_sync2_reg <= 1'b0;
bad_frame_sync3 <= 1'b0; bad_frame_sync3_reg <= 1'b0;
good_frame_sync2 <= 1'b0; good_frame_sync2_reg <= 1'b0;
good_frame_sync3 <= 1'b0; good_frame_sync3_reg <= 1'b0;
end else begin end else begin
overflow_sync2 <= overflow_sync1; overflow_sync2_reg <= overflow_sync1_reg;
overflow_sync3 <= overflow_sync2; overflow_sync3_reg <= overflow_sync2_reg;
overflow_sync4 <= overflow_sync3; overflow_sync4_reg <= overflow_sync3_reg;
bad_frame_sync2 <= bad_frame_sync1; bad_frame_sync2_reg <= bad_frame_sync1_reg;
bad_frame_sync3 <= bad_frame_sync2; bad_frame_sync3_reg <= bad_frame_sync2_reg;
bad_frame_sync4 <= bad_frame_sync3; bad_frame_sync4_reg <= bad_frame_sync3_reg;
good_frame_sync2 <= good_frame_sync1; good_frame_sync2_reg <= good_frame_sync1_reg;
good_frame_sync3 <= good_frame_sync2; good_frame_sync3_reg <= good_frame_sync2_reg;
good_frame_sync4 <= good_frame_sync3; good_frame_sync4_reg <= good_frame_sync3_reg;
end
end
// Read logic
always @* begin
read = 1'b0;
rd_ptr_next = rd_ptr_reg;
rd_ptr_gray_next = rd_ptr_gray_reg;
output_axis_tvalid_next = output_axis_tvalid_reg;
if (output_axis_tready | ~output_axis_tvalid) begin
// output data not valid OR currently being transferred
if (~empty) begin
// not empty, perform read
read = 1'b1;
output_axis_tvalid_next = 1'b1;
rd_ptr_next = rd_ptr_reg + 1;
rd_ptr_gray_next = rd_ptr_next ^ (rd_ptr_next >> 1);
end else begin
output_axis_tvalid_next = 1'b0;
end
end
end
always @(posedge output_clk) begin
if (output_rst_sync3_reg) begin
rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
rd_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
output_axis_tvalid_reg <= 1'b0;
end else begin
rd_ptr_reg <= rd_ptr_next;
rd_ptr_gray_reg <= rd_ptr_gray_next;
output_axis_tvalid_reg <= output_axis_tvalid_next;
end
if (read) begin
{output_axis_tlast_reg, output_axis_tkeep_reg, output_axis_tdata_reg} <= mem[rd_ptr_reg[ADDR_WIDTH-1:0]];
end end
end end

View File

@ -40,7 +40,7 @@ def generate(ports=4, name=None, output=None):
t = Template(u"""/* t = Template(u"""/*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -103,21 +103,21 @@ module {{name}} #
{%- endfor %} {%- endfor %}
); );
{% for p in ports %} {% for p in ports %}
reg [DATA_WIDTH-1:0] input_{{p}}_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] input_{{p}}_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg input_{{p}}_axis_tvalid_reg = 0; reg input_{{p}}_axis_tvalid_reg = 1'b0;
reg input_{{p}}_axis_tlast_reg = 0; reg input_{{p}}_axis_tlast_reg = 1'b0;
reg input_{{p}}_axis_tuser_reg = 0; reg input_{{p}}_axis_tuser_reg = 1'b0;
{% endfor %} {% endfor %}
{%- for p in ports %} {%- for p in ports %}
reg [DATA_WIDTH-1:0] output_{{p}}_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_{{p}}_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_{{p}}_axis_tvalid_reg = 0; reg output_{{p}}_axis_tvalid_reg = 1'b0;
reg output_{{p}}_axis_tlast_reg = 0; reg output_{{p}}_axis_tlast_reg = 1'b0;
reg output_{{p}}_axis_tuser_reg = 0; reg output_{{p}}_axis_tuser_reg = 1'b0;
{% endfor %} {% endfor %}
{%- for p in ports %} {%- for p in ports %}
reg [{{w-1}}:0] output_{{p}}_select_reg = 0; reg [{{w-1}}:0] output_{{p}}_select_reg = {{w}}'d0;
{%- endfor %} {%- endfor %}
{% for p in ports %} {% for p in ports %}
assign output_{{p}}_axis_tdata = output_{{p}}_axis_tdata_reg; assign output_{{p}}_axis_tdata = output_{{p}}_axis_tdata_reg;
@ -129,29 +129,35 @@ assign output_{{p}}_axis_tuser = output_{{p}}_axis_tuser_reg;
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
{%- for p in ports %} {%- for p in ports %}
output_{{p}}_select_reg <= 0; output_{{p}}_select_reg <= {{w}}'d0;
{%- endfor %} {%- endfor %}
{% for p in ports %} {% for p in ports %}
input_{{p}}_axis_tdata_reg <= 0; input_{{p}}_axis_tvalid_reg <= 1'b0;
input_{{p}}_axis_tvalid_reg <= 0;
input_{{p}}_axis_tlast_reg <= 0;
input_{{p}}_axis_tuser_reg <= 0;
{%- endfor %} {%- endfor %}
{% for p in ports %} {% for p in ports %}
output_{{p}}_axis_tdata_reg <= 0; output_{{p}}_axis_tvalid_reg <= 1'b0;
output_{{p}}_axis_tvalid_reg <= 0;
output_{{p}}_axis_tlast_reg <= 0;
output_{{p}}_axis_tuser_reg <= 0;
{%- endfor %} {%- endfor %}
end else begin end else begin
{%- for p in ports %} {%- for p in ports %}
input_{{p}}_axis_tdata_reg <= input_{{p}}_axis_tdata;
input_{{p}}_axis_tvalid_reg <= input_{{p}}_axis_tvalid; input_{{p}}_axis_tvalid_reg <= input_{{p}}_axis_tvalid;
{%- endfor %}
{% for p in ports %}
output_{{p}}_select_reg <= output_{{p}}_select;
{%- endfor %}
{%- for p in ports %}
case (output_{{p}}_select_reg)
{%- for q in ports %}
{{w}}'d{{q}}: output_{{p}}_axis_tvalid_reg <= input_{{q}}_axis_tvalid_reg;
{%- endfor %}
endcase
{%- endfor %}
end
{%- for p in ports %}
input_{{p}}_axis_tdata_reg <= input_{{p}}_axis_tdata;
input_{{p}}_axis_tlast_reg <= input_{{p}}_axis_tlast; input_{{p}}_axis_tlast_reg <= input_{{p}}_axis_tlast;
input_{{p}}_axis_tuser_reg <= input_{{p}}_axis_tuser; input_{{p}}_axis_tuser_reg <= input_{{p}}_axis_tuser;
{% endfor %}
{%- for p in ports %}
output_{{p}}_select_reg <= output_{{p}}_select;
{%- endfor %} {%- endfor %}
{%- for p in ports %} {%- for p in ports %}
@ -159,7 +165,6 @@ always @(posedge clk) begin
{%- for q in ports %} {%- for q in ports %}
{{w}}'d{{q}}: begin {{w}}'d{{q}}: begin
output_{{p}}_axis_tdata_reg <= input_{{q}}_axis_tdata_reg; output_{{p}}_axis_tdata_reg <= input_{{q}}_axis_tdata_reg;
output_{{p}}_axis_tvalid_reg <= input_{{q}}_axis_tvalid_reg;
output_{{p}}_axis_tlast_reg <= input_{{q}}_axis_tlast_reg; output_{{p}}_axis_tlast_reg <= input_{{q}}_axis_tlast_reg;
output_{{p}}_axis_tuser_reg <= input_{{q}}_axis_tuser_reg; output_{{p}}_axis_tuser_reg <= input_{{q}}_axis_tuser_reg;
end end
@ -167,7 +172,6 @@ always @(posedge clk) begin
endcase endcase
{%- endfor %} {%- endfor %}
end end
end
endmodule endmodule

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -92,50 +92,50 @@ module axis_crosspoint_4x4 #
input wire [1:0] output_3_select input wire [1:0] output_3_select
); );
reg [DATA_WIDTH-1:0] input_0_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] input_0_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg input_0_axis_tvalid_reg = 0; reg input_0_axis_tvalid_reg = 1'b0;
reg input_0_axis_tlast_reg = 0; reg input_0_axis_tlast_reg = 1'b0;
reg input_0_axis_tuser_reg = 0; reg input_0_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] input_1_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] input_1_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg input_1_axis_tvalid_reg = 0; reg input_1_axis_tvalid_reg = 1'b0;
reg input_1_axis_tlast_reg = 0; reg input_1_axis_tlast_reg = 1'b0;
reg input_1_axis_tuser_reg = 0; reg input_1_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] input_2_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] input_2_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg input_2_axis_tvalid_reg = 0; reg input_2_axis_tvalid_reg = 1'b0;
reg input_2_axis_tlast_reg = 0; reg input_2_axis_tlast_reg = 1'b0;
reg input_2_axis_tuser_reg = 0; reg input_2_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] input_3_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] input_3_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg input_3_axis_tvalid_reg = 0; reg input_3_axis_tvalid_reg = 1'b0;
reg input_3_axis_tlast_reg = 0; reg input_3_axis_tlast_reg = 1'b0;
reg input_3_axis_tuser_reg = 0; reg input_3_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] output_0_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_0_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_0_axis_tvalid_reg = 0; reg output_0_axis_tvalid_reg = 1'b0;
reg output_0_axis_tlast_reg = 0; reg output_0_axis_tlast_reg = 1'b0;
reg output_0_axis_tuser_reg = 0; reg output_0_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] output_1_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_1_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_1_axis_tvalid_reg = 0; reg output_1_axis_tvalid_reg = 1'b0;
reg output_1_axis_tlast_reg = 0; reg output_1_axis_tlast_reg = 1'b0;
reg output_1_axis_tuser_reg = 0; reg output_1_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] output_2_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_2_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_2_axis_tvalid_reg = 0; reg output_2_axis_tvalid_reg = 1'b0;
reg output_2_axis_tlast_reg = 0; reg output_2_axis_tlast_reg = 1'b0;
reg output_2_axis_tuser_reg = 0; reg output_2_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] output_3_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_3_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_3_axis_tvalid_reg = 0; reg output_3_axis_tvalid_reg = 1'b0;
reg output_3_axis_tlast_reg = 0; reg output_3_axis_tlast_reg = 1'b0;
reg output_3_axis_tuser_reg = 0; reg output_3_axis_tuser_reg = 1'b0;
reg [1:0] output_0_select_reg = 0; reg [1:0] output_0_select_reg = 2'd0;
reg [1:0] output_1_select_reg = 0; reg [1:0] output_1_select_reg = 2'd0;
reg [1:0] output_2_select_reg = 0; reg [1:0] output_2_select_reg = 2'd0;
reg [1:0] output_3_select_reg = 0; reg [1:0] output_3_select_reg = 2'd0;
assign output_0_axis_tdata = output_0_axis_tdata_reg; assign output_0_axis_tdata = output_0_axis_tdata_reg;
assign output_0_axis_tvalid = output_0_axis_tvalid_reg; assign output_0_axis_tvalid = output_0_axis_tvalid_reg;
@ -160,92 +160,94 @@ assign output_3_axis_tuser = output_3_axis_tuser_reg;
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
output_0_select_reg <= 0; output_0_select_reg <= 2'd0;
output_1_select_reg <= 0; output_1_select_reg <= 2'd0;
output_2_select_reg <= 0; output_2_select_reg <= 2'd0;
output_3_select_reg <= 0; output_3_select_reg <= 2'd0;
input_0_axis_tdata_reg <= 0; input_0_axis_tvalid_reg <= 1'b0;
input_0_axis_tvalid_reg <= 0; input_1_axis_tvalid_reg <= 1'b0;
input_0_axis_tlast_reg <= 0; input_2_axis_tvalid_reg <= 1'b0;
input_0_axis_tuser_reg <= 0; input_3_axis_tvalid_reg <= 1'b0;
input_1_axis_tdata_reg <= 0;
input_1_axis_tvalid_reg <= 0;
input_1_axis_tlast_reg <= 0;
input_1_axis_tuser_reg <= 0;
input_2_axis_tdata_reg <= 0;
input_2_axis_tvalid_reg <= 0;
input_2_axis_tlast_reg <= 0;
input_2_axis_tuser_reg <= 0;
input_3_axis_tdata_reg <= 0;
input_3_axis_tvalid_reg <= 0;
input_3_axis_tlast_reg <= 0;
input_3_axis_tuser_reg <= 0;
output_0_axis_tdata_reg <= 0; output_0_axis_tvalid_reg <= 1'b0;
output_0_axis_tvalid_reg <= 0; output_1_axis_tvalid_reg <= 1'b0;
output_0_axis_tlast_reg <= 0; output_2_axis_tvalid_reg <= 1'b0;
output_0_axis_tuser_reg <= 0; output_3_axis_tvalid_reg <= 1'b0;
output_1_axis_tdata_reg <= 0;
output_1_axis_tvalid_reg <= 0;
output_1_axis_tlast_reg <= 0;
output_1_axis_tuser_reg <= 0;
output_2_axis_tdata_reg <= 0;
output_2_axis_tvalid_reg <= 0;
output_2_axis_tlast_reg <= 0;
output_2_axis_tuser_reg <= 0;
output_3_axis_tdata_reg <= 0;
output_3_axis_tvalid_reg <= 0;
output_3_axis_tlast_reg <= 0;
output_3_axis_tuser_reg <= 0;
end else begin end else begin
input_0_axis_tdata_reg <= input_0_axis_tdata;
input_0_axis_tvalid_reg <= input_0_axis_tvalid; input_0_axis_tvalid_reg <= input_0_axis_tvalid;
input_0_axis_tlast_reg <= input_0_axis_tlast;
input_0_axis_tuser_reg <= input_0_axis_tuser;
input_1_axis_tdata_reg <= input_1_axis_tdata;
input_1_axis_tvalid_reg <= input_1_axis_tvalid; input_1_axis_tvalid_reg <= input_1_axis_tvalid;
input_1_axis_tlast_reg <= input_1_axis_tlast;
input_1_axis_tuser_reg <= input_1_axis_tuser;
input_2_axis_tdata_reg <= input_2_axis_tdata;
input_2_axis_tvalid_reg <= input_2_axis_tvalid; input_2_axis_tvalid_reg <= input_2_axis_tvalid;
input_2_axis_tlast_reg <= input_2_axis_tlast;
input_2_axis_tuser_reg <= input_2_axis_tuser;
input_3_axis_tdata_reg <= input_3_axis_tdata;
input_3_axis_tvalid_reg <= input_3_axis_tvalid; input_3_axis_tvalid_reg <= input_3_axis_tvalid;
input_3_axis_tlast_reg <= input_3_axis_tlast;
input_3_axis_tuser_reg <= input_3_axis_tuser;
output_0_select_reg <= output_0_select; output_0_select_reg <= output_0_select;
output_1_select_reg <= output_1_select; output_1_select_reg <= output_1_select;
output_2_select_reg <= output_2_select; output_2_select_reg <= output_2_select;
output_3_select_reg <= output_3_select; output_3_select_reg <= output_3_select;
case (output_0_select_reg)
2'd0: output_0_axis_tvalid_reg <= input_0_axis_tvalid_reg;
2'd1: output_0_axis_tvalid_reg <= input_1_axis_tvalid_reg;
2'd2: output_0_axis_tvalid_reg <= input_2_axis_tvalid_reg;
2'd3: output_0_axis_tvalid_reg <= input_3_axis_tvalid_reg;
endcase
case (output_1_select_reg)
2'd0: output_1_axis_tvalid_reg <= input_0_axis_tvalid_reg;
2'd1: output_1_axis_tvalid_reg <= input_1_axis_tvalid_reg;
2'd2: output_1_axis_tvalid_reg <= input_2_axis_tvalid_reg;
2'd3: output_1_axis_tvalid_reg <= input_3_axis_tvalid_reg;
endcase
case (output_2_select_reg)
2'd0: output_2_axis_tvalid_reg <= input_0_axis_tvalid_reg;
2'd1: output_2_axis_tvalid_reg <= input_1_axis_tvalid_reg;
2'd2: output_2_axis_tvalid_reg <= input_2_axis_tvalid_reg;
2'd3: output_2_axis_tvalid_reg <= input_3_axis_tvalid_reg;
endcase
case (output_3_select_reg)
2'd0: output_3_axis_tvalid_reg <= input_0_axis_tvalid_reg;
2'd1: output_3_axis_tvalid_reg <= input_1_axis_tvalid_reg;
2'd2: output_3_axis_tvalid_reg <= input_2_axis_tvalid_reg;
2'd3: output_3_axis_tvalid_reg <= input_3_axis_tvalid_reg;
endcase
end
input_0_axis_tdata_reg <= input_0_axis_tdata;
input_0_axis_tlast_reg <= input_0_axis_tlast;
input_0_axis_tuser_reg <= input_0_axis_tuser;
input_1_axis_tdata_reg <= input_1_axis_tdata;
input_1_axis_tlast_reg <= input_1_axis_tlast;
input_1_axis_tuser_reg <= input_1_axis_tuser;
input_2_axis_tdata_reg <= input_2_axis_tdata;
input_2_axis_tlast_reg <= input_2_axis_tlast;
input_2_axis_tuser_reg <= input_2_axis_tuser;
input_3_axis_tdata_reg <= input_3_axis_tdata;
input_3_axis_tlast_reg <= input_3_axis_tlast;
input_3_axis_tuser_reg <= input_3_axis_tuser;
case (output_0_select_reg) case (output_0_select_reg)
2'd0: begin 2'd0: begin
output_0_axis_tdata_reg <= input_0_axis_tdata_reg; output_0_axis_tdata_reg <= input_0_axis_tdata_reg;
output_0_axis_tvalid_reg <= input_0_axis_tvalid_reg;
output_0_axis_tlast_reg <= input_0_axis_tlast_reg; output_0_axis_tlast_reg <= input_0_axis_tlast_reg;
output_0_axis_tuser_reg <= input_0_axis_tuser_reg; output_0_axis_tuser_reg <= input_0_axis_tuser_reg;
end end
2'd1: begin 2'd1: begin
output_0_axis_tdata_reg <= input_1_axis_tdata_reg; output_0_axis_tdata_reg <= input_1_axis_tdata_reg;
output_0_axis_tvalid_reg <= input_1_axis_tvalid_reg;
output_0_axis_tlast_reg <= input_1_axis_tlast_reg; output_0_axis_tlast_reg <= input_1_axis_tlast_reg;
output_0_axis_tuser_reg <= input_1_axis_tuser_reg; output_0_axis_tuser_reg <= input_1_axis_tuser_reg;
end end
2'd2: begin 2'd2: begin
output_0_axis_tdata_reg <= input_2_axis_tdata_reg; output_0_axis_tdata_reg <= input_2_axis_tdata_reg;
output_0_axis_tvalid_reg <= input_2_axis_tvalid_reg;
output_0_axis_tlast_reg <= input_2_axis_tlast_reg; output_0_axis_tlast_reg <= input_2_axis_tlast_reg;
output_0_axis_tuser_reg <= input_2_axis_tuser_reg; output_0_axis_tuser_reg <= input_2_axis_tuser_reg;
end end
2'd3: begin 2'd3: begin
output_0_axis_tdata_reg <= input_3_axis_tdata_reg; output_0_axis_tdata_reg <= input_3_axis_tdata_reg;
output_0_axis_tvalid_reg <= input_3_axis_tvalid_reg;
output_0_axis_tlast_reg <= input_3_axis_tlast_reg; output_0_axis_tlast_reg <= input_3_axis_tlast_reg;
output_0_axis_tuser_reg <= input_3_axis_tuser_reg; output_0_axis_tuser_reg <= input_3_axis_tuser_reg;
end end
@ -254,25 +256,21 @@ always @(posedge clk) begin
case (output_1_select_reg) case (output_1_select_reg)
2'd0: begin 2'd0: begin
output_1_axis_tdata_reg <= input_0_axis_tdata_reg; output_1_axis_tdata_reg <= input_0_axis_tdata_reg;
output_1_axis_tvalid_reg <= input_0_axis_tvalid_reg;
output_1_axis_tlast_reg <= input_0_axis_tlast_reg; output_1_axis_tlast_reg <= input_0_axis_tlast_reg;
output_1_axis_tuser_reg <= input_0_axis_tuser_reg; output_1_axis_tuser_reg <= input_0_axis_tuser_reg;
end end
2'd1: begin 2'd1: begin
output_1_axis_tdata_reg <= input_1_axis_tdata_reg; output_1_axis_tdata_reg <= input_1_axis_tdata_reg;
output_1_axis_tvalid_reg <= input_1_axis_tvalid_reg;
output_1_axis_tlast_reg <= input_1_axis_tlast_reg; output_1_axis_tlast_reg <= input_1_axis_tlast_reg;
output_1_axis_tuser_reg <= input_1_axis_tuser_reg; output_1_axis_tuser_reg <= input_1_axis_tuser_reg;
end end
2'd2: begin 2'd2: begin
output_1_axis_tdata_reg <= input_2_axis_tdata_reg; output_1_axis_tdata_reg <= input_2_axis_tdata_reg;
output_1_axis_tvalid_reg <= input_2_axis_tvalid_reg;
output_1_axis_tlast_reg <= input_2_axis_tlast_reg; output_1_axis_tlast_reg <= input_2_axis_tlast_reg;
output_1_axis_tuser_reg <= input_2_axis_tuser_reg; output_1_axis_tuser_reg <= input_2_axis_tuser_reg;
end end
2'd3: begin 2'd3: begin
output_1_axis_tdata_reg <= input_3_axis_tdata_reg; output_1_axis_tdata_reg <= input_3_axis_tdata_reg;
output_1_axis_tvalid_reg <= input_3_axis_tvalid_reg;
output_1_axis_tlast_reg <= input_3_axis_tlast_reg; output_1_axis_tlast_reg <= input_3_axis_tlast_reg;
output_1_axis_tuser_reg <= input_3_axis_tuser_reg; output_1_axis_tuser_reg <= input_3_axis_tuser_reg;
end end
@ -281,25 +279,21 @@ always @(posedge clk) begin
case (output_2_select_reg) case (output_2_select_reg)
2'd0: begin 2'd0: begin
output_2_axis_tdata_reg <= input_0_axis_tdata_reg; output_2_axis_tdata_reg <= input_0_axis_tdata_reg;
output_2_axis_tvalid_reg <= input_0_axis_tvalid_reg;
output_2_axis_tlast_reg <= input_0_axis_tlast_reg; output_2_axis_tlast_reg <= input_0_axis_tlast_reg;
output_2_axis_tuser_reg <= input_0_axis_tuser_reg; output_2_axis_tuser_reg <= input_0_axis_tuser_reg;
end end
2'd1: begin 2'd1: begin
output_2_axis_tdata_reg <= input_1_axis_tdata_reg; output_2_axis_tdata_reg <= input_1_axis_tdata_reg;
output_2_axis_tvalid_reg <= input_1_axis_tvalid_reg;
output_2_axis_tlast_reg <= input_1_axis_tlast_reg; output_2_axis_tlast_reg <= input_1_axis_tlast_reg;
output_2_axis_tuser_reg <= input_1_axis_tuser_reg; output_2_axis_tuser_reg <= input_1_axis_tuser_reg;
end end
2'd2: begin 2'd2: begin
output_2_axis_tdata_reg <= input_2_axis_tdata_reg; output_2_axis_tdata_reg <= input_2_axis_tdata_reg;
output_2_axis_tvalid_reg <= input_2_axis_tvalid_reg;
output_2_axis_tlast_reg <= input_2_axis_tlast_reg; output_2_axis_tlast_reg <= input_2_axis_tlast_reg;
output_2_axis_tuser_reg <= input_2_axis_tuser_reg; output_2_axis_tuser_reg <= input_2_axis_tuser_reg;
end end
2'd3: begin 2'd3: begin
output_2_axis_tdata_reg <= input_3_axis_tdata_reg; output_2_axis_tdata_reg <= input_3_axis_tdata_reg;
output_2_axis_tvalid_reg <= input_3_axis_tvalid_reg;
output_2_axis_tlast_reg <= input_3_axis_tlast_reg; output_2_axis_tlast_reg <= input_3_axis_tlast_reg;
output_2_axis_tuser_reg <= input_3_axis_tuser_reg; output_2_axis_tuser_reg <= input_3_axis_tuser_reg;
end end
@ -308,30 +302,25 @@ always @(posedge clk) begin
case (output_3_select_reg) case (output_3_select_reg)
2'd0: begin 2'd0: begin
output_3_axis_tdata_reg <= input_0_axis_tdata_reg; output_3_axis_tdata_reg <= input_0_axis_tdata_reg;
output_3_axis_tvalid_reg <= input_0_axis_tvalid_reg;
output_3_axis_tlast_reg <= input_0_axis_tlast_reg; output_3_axis_tlast_reg <= input_0_axis_tlast_reg;
output_3_axis_tuser_reg <= input_0_axis_tuser_reg; output_3_axis_tuser_reg <= input_0_axis_tuser_reg;
end end
2'd1: begin 2'd1: begin
output_3_axis_tdata_reg <= input_1_axis_tdata_reg; output_3_axis_tdata_reg <= input_1_axis_tdata_reg;
output_3_axis_tvalid_reg <= input_1_axis_tvalid_reg;
output_3_axis_tlast_reg <= input_1_axis_tlast_reg; output_3_axis_tlast_reg <= input_1_axis_tlast_reg;
output_3_axis_tuser_reg <= input_1_axis_tuser_reg; output_3_axis_tuser_reg <= input_1_axis_tuser_reg;
end end
2'd2: begin 2'd2: begin
output_3_axis_tdata_reg <= input_2_axis_tdata_reg; output_3_axis_tdata_reg <= input_2_axis_tdata_reg;
output_3_axis_tvalid_reg <= input_2_axis_tvalid_reg;
output_3_axis_tlast_reg <= input_2_axis_tlast_reg; output_3_axis_tlast_reg <= input_2_axis_tlast_reg;
output_3_axis_tuser_reg <= input_2_axis_tuser_reg; output_3_axis_tuser_reg <= input_2_axis_tuser_reg;
end end
2'd3: begin 2'd3: begin
output_3_axis_tdata_reg <= input_3_axis_tdata_reg; output_3_axis_tdata_reg <= input_3_axis_tdata_reg;
output_3_axis_tvalid_reg <= input_3_axis_tvalid_reg;
output_3_axis_tlast_reg <= input_3_axis_tlast_reg; output_3_axis_tlast_reg <= input_3_axis_tlast_reg;
output_3_axis_tuser_reg <= input_3_axis_tuser_reg; output_3_axis_tuser_reg <= input_3_axis_tuser_reg;
end end
endcase endcase
end end
end
endmodule endmodule

View File

@ -40,7 +40,7 @@ def generate(ports=4, name=None, output=None):
t = Template(u"""/* t = Template(u"""/*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -106,23 +106,23 @@ module {{name}} #
{%- endfor %} {%- endfor %}
); );
{% for p in ports %} {% for p in ports %}
reg [DATA_WIDTH-1:0] input_{{p}}_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] input_{{p}}_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] input_{{p}}_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] input_{{p}}_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg input_{{p}}_axis_tvalid_reg = 0; reg input_{{p}}_axis_tvalid_reg = 1'b0;
reg input_{{p}}_axis_tlast_reg = 0; reg input_{{p}}_axis_tlast_reg = 1'b0;
reg input_{{p}}_axis_tuser_reg = 0; reg input_{{p}}_axis_tuser_reg = 1'b0;
{% endfor %} {% endfor %}
{%- for p in ports %} {%- for p in ports %}
reg [DATA_WIDTH-1:0] output_{{p}}_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_{{p}}_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_{{p}}_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] output_{{p}}_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_{{p}}_axis_tvalid_reg = 0; reg output_{{p}}_axis_tvalid_reg = 1'b0;
reg output_{{p}}_axis_tlast_reg = 0; reg output_{{p}}_axis_tlast_reg = 1'b0;
reg output_{{p}}_axis_tuser_reg = 0; reg output_{{p}}_axis_tuser_reg = 1'b0;
{% endfor %} {% endfor %}
{%- for p in ports %} {%- for p in ports %}
reg [{{w-1}}:0] output_{{p}}_select_reg = 0; reg [{{w-1}}:0] output_{{p}}_select_reg = {{w}}'d0;
{%- endfor %} {%- endfor %}
{% for p in ports %} {% for p in ports %}
assign output_{{p}}_axis_tdata = output_{{p}}_axis_tdata_reg; assign output_{{p}}_axis_tdata = output_{{p}}_axis_tdata_reg;
@ -135,32 +135,36 @@ assign output_{{p}}_axis_tuser = output_{{p}}_axis_tuser_reg;
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
{%- for p in ports %} {%- for p in ports %}
output_{{p}}_select_reg <= 0; output_{{p}}_select_reg <= {{w}}'d0;
{%- endfor %} {%- endfor %}
{% for p in ports %} {% for p in ports %}
input_{{p}}_axis_tdata_reg <= 0; input_{{p}}_axis_tvalid_reg <= 1'b0;
input_{{p}}_axis_tkeep_reg <= 0;
input_{{p}}_axis_tvalid_reg <= 0;
input_{{p}}_axis_tlast_reg <= 0;
input_{{p}}_axis_tuser_reg <= 0;
{%- endfor %} {%- endfor %}
{% for p in ports %} {% for p in ports %}
output_{{p}}_axis_tdata_reg <= 0; output_{{p}}_axis_tvalid_reg <= 1'b0;
output_{{p}}_axis_tkeep_reg <= 0;
output_{{p}}_axis_tvalid_reg <= 0;
output_{{p}}_axis_tlast_reg <= 0;
output_{{p}}_axis_tuser_reg <= 0;
{%- endfor %} {%- endfor %}
end else begin end else begin
{%- for p in ports %} {%- for p in ports %}
input_{{p}}_axis_tvalid_reg <= input_{{p}}_axis_tvalid;
{%- endfor %}
{% for p in ports %}
output_{{p}}_select_reg <= output_{{p}}_select;
{%- endfor %}
{%- for p in ports %}
case (output_{{p}}_select_reg)
{%- for q in ports %}
{{w}}'d{{q}}: output_{{p}}_axis_tvalid_reg <= input_{{q}}_axis_tvalid_reg;
{%- endfor %}
endcase
{%- endfor %}
end
{%- for p in ports %}
input_{{p}}_axis_tdata_reg <= input_{{p}}_axis_tdata; input_{{p}}_axis_tdata_reg <= input_{{p}}_axis_tdata;
input_{{p}}_axis_tkeep_reg <= input_{{p}}_axis_tkeep; input_{{p}}_axis_tkeep_reg <= input_{{p}}_axis_tkeep;
input_{{p}}_axis_tvalid_reg <= input_{{p}}_axis_tvalid;
input_{{p}}_axis_tlast_reg <= input_{{p}}_axis_tlast; input_{{p}}_axis_tlast_reg <= input_{{p}}_axis_tlast;
input_{{p}}_axis_tuser_reg <= input_{{p}}_axis_tuser; input_{{p}}_axis_tuser_reg <= input_{{p}}_axis_tuser;
{% endfor %}
{%- for p in ports %}
output_{{p}}_select_reg <= output_{{p}}_select;
{%- endfor %} {%- endfor %}
{%- for p in ports %} {%- for p in ports %}
@ -169,7 +173,6 @@ always @(posedge clk) begin
{{w}}'d{{q}}: begin {{w}}'d{{q}}: begin
output_{{p}}_axis_tdata_reg <= input_{{q}}_axis_tdata_reg; output_{{p}}_axis_tdata_reg <= input_{{q}}_axis_tdata_reg;
output_{{p}}_axis_tkeep_reg <= input_{{q}}_axis_tkeep_reg; output_{{p}}_axis_tkeep_reg <= input_{{q}}_axis_tkeep_reg;
output_{{p}}_axis_tvalid_reg <= input_{{q}}_axis_tvalid_reg;
output_{{p}}_axis_tlast_reg <= input_{{q}}_axis_tlast_reg; output_{{p}}_axis_tlast_reg <= input_{{q}}_axis_tlast_reg;
output_{{p}}_axis_tuser_reg <= input_{{q}}_axis_tuser_reg; output_{{p}}_axis_tuser_reg <= input_{{q}}_axis_tuser_reg;
end end
@ -177,7 +180,6 @@ always @(posedge clk) begin
endcase endcase
{%- endfor %} {%- endfor %}
end end
end
endmodule endmodule

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -101,58 +101,58 @@ module axis_crosspoint_64_4x4 #
input wire [1:0] output_3_select input wire [1:0] output_3_select
); );
reg [DATA_WIDTH-1:0] input_0_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] input_0_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] input_0_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] input_0_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg input_0_axis_tvalid_reg = 0; reg input_0_axis_tvalid_reg = 1'b0;
reg input_0_axis_tlast_reg = 0; reg input_0_axis_tlast_reg = 1'b0;
reg input_0_axis_tuser_reg = 0; reg input_0_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] input_1_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] input_1_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] input_1_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] input_1_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg input_1_axis_tvalid_reg = 0; reg input_1_axis_tvalid_reg = 1'b0;
reg input_1_axis_tlast_reg = 0; reg input_1_axis_tlast_reg = 1'b0;
reg input_1_axis_tuser_reg = 0; reg input_1_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] input_2_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] input_2_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] input_2_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] input_2_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg input_2_axis_tvalid_reg = 0; reg input_2_axis_tvalid_reg = 1'b0;
reg input_2_axis_tlast_reg = 0; reg input_2_axis_tlast_reg = 1'b0;
reg input_2_axis_tuser_reg = 0; reg input_2_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] input_3_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] input_3_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] input_3_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] input_3_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg input_3_axis_tvalid_reg = 0; reg input_3_axis_tvalid_reg = 1'b0;
reg input_3_axis_tlast_reg = 0; reg input_3_axis_tlast_reg = 1'b0;
reg input_3_axis_tuser_reg = 0; reg input_3_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] output_0_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_0_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_0_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] output_0_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_0_axis_tvalid_reg = 0; reg output_0_axis_tvalid_reg = 1'b0;
reg output_0_axis_tlast_reg = 0; reg output_0_axis_tlast_reg = 1'b0;
reg output_0_axis_tuser_reg = 0; reg output_0_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] output_1_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_1_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_1_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] output_1_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_1_axis_tvalid_reg = 0; reg output_1_axis_tvalid_reg = 1'b0;
reg output_1_axis_tlast_reg = 0; reg output_1_axis_tlast_reg = 1'b0;
reg output_1_axis_tuser_reg = 0; reg output_1_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] output_2_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_2_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_2_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] output_2_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_2_axis_tvalid_reg = 0; reg output_2_axis_tvalid_reg = 1'b0;
reg output_2_axis_tlast_reg = 0; reg output_2_axis_tlast_reg = 1'b0;
reg output_2_axis_tuser_reg = 0; reg output_2_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] output_3_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_3_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_3_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] output_3_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_3_axis_tvalid_reg = 0; reg output_3_axis_tvalid_reg = 1'b0;
reg output_3_axis_tlast_reg = 0; reg output_3_axis_tlast_reg = 1'b0;
reg output_3_axis_tuser_reg = 0; reg output_3_axis_tuser_reg = 1'b0;
reg [1:0] output_0_select_reg = 0; reg [1:0] output_0_select_reg = 2'd0;
reg [1:0] output_1_select_reg = 0; reg [1:0] output_1_select_reg = 2'd0;
reg [1:0] output_2_select_reg = 0; reg [1:0] output_2_select_reg = 2'd0;
reg [1:0] output_3_select_reg = 0; reg [1:0] output_3_select_reg = 2'd0;
assign output_0_axis_tdata = output_0_axis_tdata_reg; assign output_0_axis_tdata = output_0_axis_tdata_reg;
assign output_0_axis_tkeep = output_0_axis_tkeep_reg; assign output_0_axis_tkeep = output_0_axis_tkeep_reg;
@ -181,108 +181,102 @@ assign output_3_axis_tuser = output_3_axis_tuser_reg;
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
output_0_select_reg <= 0; output_0_select_reg <= 2'd0;
output_1_select_reg <= 0; output_1_select_reg <= 2'd0;
output_2_select_reg <= 0; output_2_select_reg <= 2'd0;
output_3_select_reg <= 0; output_3_select_reg <= 2'd0;
input_0_axis_tdata_reg <= 0; input_0_axis_tvalid_reg <= 1'b0;
input_0_axis_tkeep_reg <= 0; input_1_axis_tvalid_reg <= 1'b0;
input_0_axis_tvalid_reg <= 0; input_2_axis_tvalid_reg <= 1'b0;
input_0_axis_tlast_reg <= 0; input_3_axis_tvalid_reg <= 1'b0;
input_0_axis_tuser_reg <= 0;
input_1_axis_tdata_reg <= 0;
input_1_axis_tkeep_reg <= 0;
input_1_axis_tvalid_reg <= 0;
input_1_axis_tlast_reg <= 0;
input_1_axis_tuser_reg <= 0;
input_2_axis_tdata_reg <= 0;
input_2_axis_tkeep_reg <= 0;
input_2_axis_tvalid_reg <= 0;
input_2_axis_tlast_reg <= 0;
input_2_axis_tuser_reg <= 0;
input_3_axis_tdata_reg <= 0;
input_3_axis_tkeep_reg <= 0;
input_3_axis_tvalid_reg <= 0;
input_3_axis_tlast_reg <= 0;
input_3_axis_tuser_reg <= 0;
output_0_axis_tdata_reg <= 0; output_0_axis_tvalid_reg <= 1'b0;
output_0_axis_tkeep_reg <= 0; output_1_axis_tvalid_reg <= 1'b0;
output_0_axis_tvalid_reg <= 0; output_2_axis_tvalid_reg <= 1'b0;
output_0_axis_tlast_reg <= 0; output_3_axis_tvalid_reg <= 1'b0;
output_0_axis_tuser_reg <= 0;
output_1_axis_tdata_reg <= 0;
output_1_axis_tkeep_reg <= 0;
output_1_axis_tvalid_reg <= 0;
output_1_axis_tlast_reg <= 0;
output_1_axis_tuser_reg <= 0;
output_2_axis_tdata_reg <= 0;
output_2_axis_tkeep_reg <= 0;
output_2_axis_tvalid_reg <= 0;
output_2_axis_tlast_reg <= 0;
output_2_axis_tuser_reg <= 0;
output_3_axis_tdata_reg <= 0;
output_3_axis_tkeep_reg <= 0;
output_3_axis_tvalid_reg <= 0;
output_3_axis_tlast_reg <= 0;
output_3_axis_tuser_reg <= 0;
end else begin end else begin
input_0_axis_tdata_reg <= input_0_axis_tdata;
input_0_axis_tkeep_reg <= input_0_axis_tkeep;
input_0_axis_tvalid_reg <= input_0_axis_tvalid; input_0_axis_tvalid_reg <= input_0_axis_tvalid;
input_0_axis_tlast_reg <= input_0_axis_tlast;
input_0_axis_tuser_reg <= input_0_axis_tuser;
input_1_axis_tdata_reg <= input_1_axis_tdata;
input_1_axis_tkeep_reg <= input_1_axis_tkeep;
input_1_axis_tvalid_reg <= input_1_axis_tvalid; input_1_axis_tvalid_reg <= input_1_axis_tvalid;
input_1_axis_tlast_reg <= input_1_axis_tlast;
input_1_axis_tuser_reg <= input_1_axis_tuser;
input_2_axis_tdata_reg <= input_2_axis_tdata;
input_2_axis_tkeep_reg <= input_2_axis_tkeep;
input_2_axis_tvalid_reg <= input_2_axis_tvalid; input_2_axis_tvalid_reg <= input_2_axis_tvalid;
input_2_axis_tlast_reg <= input_2_axis_tlast;
input_2_axis_tuser_reg <= input_2_axis_tuser;
input_3_axis_tdata_reg <= input_3_axis_tdata;
input_3_axis_tkeep_reg <= input_3_axis_tkeep;
input_3_axis_tvalid_reg <= input_3_axis_tvalid; input_3_axis_tvalid_reg <= input_3_axis_tvalid;
input_3_axis_tlast_reg <= input_3_axis_tlast;
input_3_axis_tuser_reg <= input_3_axis_tuser;
output_0_select_reg <= output_0_select; output_0_select_reg <= output_0_select;
output_1_select_reg <= output_1_select; output_1_select_reg <= output_1_select;
output_2_select_reg <= output_2_select; output_2_select_reg <= output_2_select;
output_3_select_reg <= output_3_select; output_3_select_reg <= output_3_select;
case (output_0_select_reg)
2'd0: output_0_axis_tvalid_reg <= input_0_axis_tvalid_reg;
2'd1: output_0_axis_tvalid_reg <= input_1_axis_tvalid_reg;
2'd2: output_0_axis_tvalid_reg <= input_2_axis_tvalid_reg;
2'd3: output_0_axis_tvalid_reg <= input_3_axis_tvalid_reg;
endcase
case (output_1_select_reg)
2'd0: output_1_axis_tvalid_reg <= input_0_axis_tvalid_reg;
2'd1: output_1_axis_tvalid_reg <= input_1_axis_tvalid_reg;
2'd2: output_1_axis_tvalid_reg <= input_2_axis_tvalid_reg;
2'd3: output_1_axis_tvalid_reg <= input_3_axis_tvalid_reg;
endcase
case (output_2_select_reg)
2'd0: output_2_axis_tvalid_reg <= input_0_axis_tvalid_reg;
2'd1: output_2_axis_tvalid_reg <= input_1_axis_tvalid_reg;
2'd2: output_2_axis_tvalid_reg <= input_2_axis_tvalid_reg;
2'd3: output_2_axis_tvalid_reg <= input_3_axis_tvalid_reg;
endcase
case (output_3_select_reg)
2'd0: output_3_axis_tvalid_reg <= input_0_axis_tvalid_reg;
2'd1: output_3_axis_tvalid_reg <= input_1_axis_tvalid_reg;
2'd2: output_3_axis_tvalid_reg <= input_2_axis_tvalid_reg;
2'd3: output_3_axis_tvalid_reg <= input_3_axis_tvalid_reg;
endcase
end
input_0_axis_tdata_reg <= input_0_axis_tdata;
input_0_axis_tkeep_reg <= input_0_axis_tkeep;
input_0_axis_tlast_reg <= input_0_axis_tlast;
input_0_axis_tuser_reg <= input_0_axis_tuser;
input_1_axis_tdata_reg <= input_1_axis_tdata;
input_1_axis_tkeep_reg <= input_1_axis_tkeep;
input_1_axis_tlast_reg <= input_1_axis_tlast;
input_1_axis_tuser_reg <= input_1_axis_tuser;
input_2_axis_tdata_reg <= input_2_axis_tdata;
input_2_axis_tkeep_reg <= input_2_axis_tkeep;
input_2_axis_tlast_reg <= input_2_axis_tlast;
input_2_axis_tuser_reg <= input_2_axis_tuser;
input_3_axis_tdata_reg <= input_3_axis_tdata;
input_3_axis_tkeep_reg <= input_3_axis_tkeep;
input_3_axis_tlast_reg <= input_3_axis_tlast;
input_3_axis_tuser_reg <= input_3_axis_tuser;
case (output_0_select_reg) case (output_0_select_reg)
2'd0: begin 2'd0: begin
output_0_axis_tdata_reg <= input_0_axis_tdata_reg; output_0_axis_tdata_reg <= input_0_axis_tdata_reg;
output_0_axis_tkeep_reg <= input_0_axis_tkeep_reg; output_0_axis_tkeep_reg <= input_0_axis_tkeep_reg;
output_0_axis_tvalid_reg <= input_0_axis_tvalid_reg;
output_0_axis_tlast_reg <= input_0_axis_tlast_reg; output_0_axis_tlast_reg <= input_0_axis_tlast_reg;
output_0_axis_tuser_reg <= input_0_axis_tuser_reg; output_0_axis_tuser_reg <= input_0_axis_tuser_reg;
end end
2'd1: begin 2'd1: begin
output_0_axis_tdata_reg <= input_1_axis_tdata_reg; output_0_axis_tdata_reg <= input_1_axis_tdata_reg;
output_0_axis_tkeep_reg <= input_1_axis_tkeep_reg; output_0_axis_tkeep_reg <= input_1_axis_tkeep_reg;
output_0_axis_tvalid_reg <= input_1_axis_tvalid_reg;
output_0_axis_tlast_reg <= input_1_axis_tlast_reg; output_0_axis_tlast_reg <= input_1_axis_tlast_reg;
output_0_axis_tuser_reg <= input_1_axis_tuser_reg; output_0_axis_tuser_reg <= input_1_axis_tuser_reg;
end end
2'd2: begin 2'd2: begin
output_0_axis_tdata_reg <= input_2_axis_tdata_reg; output_0_axis_tdata_reg <= input_2_axis_tdata_reg;
output_0_axis_tkeep_reg <= input_2_axis_tkeep_reg; output_0_axis_tkeep_reg <= input_2_axis_tkeep_reg;
output_0_axis_tvalid_reg <= input_2_axis_tvalid_reg;
output_0_axis_tlast_reg <= input_2_axis_tlast_reg; output_0_axis_tlast_reg <= input_2_axis_tlast_reg;
output_0_axis_tuser_reg <= input_2_axis_tuser_reg; output_0_axis_tuser_reg <= input_2_axis_tuser_reg;
end end
2'd3: begin 2'd3: begin
output_0_axis_tdata_reg <= input_3_axis_tdata_reg; output_0_axis_tdata_reg <= input_3_axis_tdata_reg;
output_0_axis_tkeep_reg <= input_3_axis_tkeep_reg; output_0_axis_tkeep_reg <= input_3_axis_tkeep_reg;
output_0_axis_tvalid_reg <= input_3_axis_tvalid_reg;
output_0_axis_tlast_reg <= input_3_axis_tlast_reg; output_0_axis_tlast_reg <= input_3_axis_tlast_reg;
output_0_axis_tuser_reg <= input_3_axis_tuser_reg; output_0_axis_tuser_reg <= input_3_axis_tuser_reg;
end end
@ -292,28 +286,24 @@ always @(posedge clk) begin
2'd0: begin 2'd0: begin
output_1_axis_tdata_reg <= input_0_axis_tdata_reg; output_1_axis_tdata_reg <= input_0_axis_tdata_reg;
output_1_axis_tkeep_reg <= input_0_axis_tkeep_reg; output_1_axis_tkeep_reg <= input_0_axis_tkeep_reg;
output_1_axis_tvalid_reg <= input_0_axis_tvalid_reg;
output_1_axis_tlast_reg <= input_0_axis_tlast_reg; output_1_axis_tlast_reg <= input_0_axis_tlast_reg;
output_1_axis_tuser_reg <= input_0_axis_tuser_reg; output_1_axis_tuser_reg <= input_0_axis_tuser_reg;
end end
2'd1: begin 2'd1: begin
output_1_axis_tdata_reg <= input_1_axis_tdata_reg; output_1_axis_tdata_reg <= input_1_axis_tdata_reg;
output_1_axis_tkeep_reg <= input_1_axis_tkeep_reg; output_1_axis_tkeep_reg <= input_1_axis_tkeep_reg;
output_1_axis_tvalid_reg <= input_1_axis_tvalid_reg;
output_1_axis_tlast_reg <= input_1_axis_tlast_reg; output_1_axis_tlast_reg <= input_1_axis_tlast_reg;
output_1_axis_tuser_reg <= input_1_axis_tuser_reg; output_1_axis_tuser_reg <= input_1_axis_tuser_reg;
end end
2'd2: begin 2'd2: begin
output_1_axis_tdata_reg <= input_2_axis_tdata_reg; output_1_axis_tdata_reg <= input_2_axis_tdata_reg;
output_1_axis_tkeep_reg <= input_2_axis_tkeep_reg; output_1_axis_tkeep_reg <= input_2_axis_tkeep_reg;
output_1_axis_tvalid_reg <= input_2_axis_tvalid_reg;
output_1_axis_tlast_reg <= input_2_axis_tlast_reg; output_1_axis_tlast_reg <= input_2_axis_tlast_reg;
output_1_axis_tuser_reg <= input_2_axis_tuser_reg; output_1_axis_tuser_reg <= input_2_axis_tuser_reg;
end end
2'd3: begin 2'd3: begin
output_1_axis_tdata_reg <= input_3_axis_tdata_reg; output_1_axis_tdata_reg <= input_3_axis_tdata_reg;
output_1_axis_tkeep_reg <= input_3_axis_tkeep_reg; output_1_axis_tkeep_reg <= input_3_axis_tkeep_reg;
output_1_axis_tvalid_reg <= input_3_axis_tvalid_reg;
output_1_axis_tlast_reg <= input_3_axis_tlast_reg; output_1_axis_tlast_reg <= input_3_axis_tlast_reg;
output_1_axis_tuser_reg <= input_3_axis_tuser_reg; output_1_axis_tuser_reg <= input_3_axis_tuser_reg;
end end
@ -323,28 +313,24 @@ always @(posedge clk) begin
2'd0: begin 2'd0: begin
output_2_axis_tdata_reg <= input_0_axis_tdata_reg; output_2_axis_tdata_reg <= input_0_axis_tdata_reg;
output_2_axis_tkeep_reg <= input_0_axis_tkeep_reg; output_2_axis_tkeep_reg <= input_0_axis_tkeep_reg;
output_2_axis_tvalid_reg <= input_0_axis_tvalid_reg;
output_2_axis_tlast_reg <= input_0_axis_tlast_reg; output_2_axis_tlast_reg <= input_0_axis_tlast_reg;
output_2_axis_tuser_reg <= input_0_axis_tuser_reg; output_2_axis_tuser_reg <= input_0_axis_tuser_reg;
end end
2'd1: begin 2'd1: begin
output_2_axis_tdata_reg <= input_1_axis_tdata_reg; output_2_axis_tdata_reg <= input_1_axis_tdata_reg;
output_2_axis_tkeep_reg <= input_1_axis_tkeep_reg; output_2_axis_tkeep_reg <= input_1_axis_tkeep_reg;
output_2_axis_tvalid_reg <= input_1_axis_tvalid_reg;
output_2_axis_tlast_reg <= input_1_axis_tlast_reg; output_2_axis_tlast_reg <= input_1_axis_tlast_reg;
output_2_axis_tuser_reg <= input_1_axis_tuser_reg; output_2_axis_tuser_reg <= input_1_axis_tuser_reg;
end end
2'd2: begin 2'd2: begin
output_2_axis_tdata_reg <= input_2_axis_tdata_reg; output_2_axis_tdata_reg <= input_2_axis_tdata_reg;
output_2_axis_tkeep_reg <= input_2_axis_tkeep_reg; output_2_axis_tkeep_reg <= input_2_axis_tkeep_reg;
output_2_axis_tvalid_reg <= input_2_axis_tvalid_reg;
output_2_axis_tlast_reg <= input_2_axis_tlast_reg; output_2_axis_tlast_reg <= input_2_axis_tlast_reg;
output_2_axis_tuser_reg <= input_2_axis_tuser_reg; output_2_axis_tuser_reg <= input_2_axis_tuser_reg;
end end
2'd3: begin 2'd3: begin
output_2_axis_tdata_reg <= input_3_axis_tdata_reg; output_2_axis_tdata_reg <= input_3_axis_tdata_reg;
output_2_axis_tkeep_reg <= input_3_axis_tkeep_reg; output_2_axis_tkeep_reg <= input_3_axis_tkeep_reg;
output_2_axis_tvalid_reg <= input_3_axis_tvalid_reg;
output_2_axis_tlast_reg <= input_3_axis_tlast_reg; output_2_axis_tlast_reg <= input_3_axis_tlast_reg;
output_2_axis_tuser_reg <= input_3_axis_tuser_reg; output_2_axis_tuser_reg <= input_3_axis_tuser_reg;
end end
@ -354,33 +340,28 @@ always @(posedge clk) begin
2'd0: begin 2'd0: begin
output_3_axis_tdata_reg <= input_0_axis_tdata_reg; output_3_axis_tdata_reg <= input_0_axis_tdata_reg;
output_3_axis_tkeep_reg <= input_0_axis_tkeep_reg; output_3_axis_tkeep_reg <= input_0_axis_tkeep_reg;
output_3_axis_tvalid_reg <= input_0_axis_tvalid_reg;
output_3_axis_tlast_reg <= input_0_axis_tlast_reg; output_3_axis_tlast_reg <= input_0_axis_tlast_reg;
output_3_axis_tuser_reg <= input_0_axis_tuser_reg; output_3_axis_tuser_reg <= input_0_axis_tuser_reg;
end end
2'd1: begin 2'd1: begin
output_3_axis_tdata_reg <= input_1_axis_tdata_reg; output_3_axis_tdata_reg <= input_1_axis_tdata_reg;
output_3_axis_tkeep_reg <= input_1_axis_tkeep_reg; output_3_axis_tkeep_reg <= input_1_axis_tkeep_reg;
output_3_axis_tvalid_reg <= input_1_axis_tvalid_reg;
output_3_axis_tlast_reg <= input_1_axis_tlast_reg; output_3_axis_tlast_reg <= input_1_axis_tlast_reg;
output_3_axis_tuser_reg <= input_1_axis_tuser_reg; output_3_axis_tuser_reg <= input_1_axis_tuser_reg;
end end
2'd2: begin 2'd2: begin
output_3_axis_tdata_reg <= input_2_axis_tdata_reg; output_3_axis_tdata_reg <= input_2_axis_tdata_reg;
output_3_axis_tkeep_reg <= input_2_axis_tkeep_reg; output_3_axis_tkeep_reg <= input_2_axis_tkeep_reg;
output_3_axis_tvalid_reg <= input_2_axis_tvalid_reg;
output_3_axis_tlast_reg <= input_2_axis_tlast_reg; output_3_axis_tlast_reg <= input_2_axis_tlast_reg;
output_3_axis_tuser_reg <= input_2_axis_tuser_reg; output_3_axis_tuser_reg <= input_2_axis_tuser_reg;
end end
2'd3: begin 2'd3: begin
output_3_axis_tdata_reg <= input_3_axis_tdata_reg; output_3_axis_tdata_reg <= input_3_axis_tdata_reg;
output_3_axis_tkeep_reg <= input_3_axis_tkeep_reg; output_3_axis_tkeep_reg <= input_3_axis_tkeep_reg;
output_3_axis_tvalid_reg <= input_3_axis_tvalid_reg;
output_3_axis_tlast_reg <= input_3_axis_tlast_reg; output_3_axis_tlast_reg <= input_3_axis_tlast_reg;
output_3_axis_tuser_reg <= input_3_axis_tuser_reg; output_3_axis_tuser_reg <= input_3_axis_tuser_reg;
end end
endcase endcase
end end
end
endmodule endmodule

View File

@ -40,7 +40,7 @@ def generate(ports=4, name=None, output=None):
t = Template(u"""/* t = Template(u"""/*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -103,15 +103,15 @@ module {{name}} #
input wire [{{w-1}}:0] select input wire [{{w-1}}:0] select
); );
reg [{{w-1}}:0] select_reg = 0, select_next; reg [{{w-1}}:0] select_reg = {{w}}'d0, select_next;
reg frame_reg = 0, frame_next; reg frame_reg = 1'b0, frame_next;
reg input_axis_tready_reg = 0, input_axis_tready_next; reg input_axis_tready_reg = 1'b0, input_axis_tready_next;
// internal datapath // internal datapath
reg [DATA_WIDTH-1:0] output_axis_tdata_int; reg [DATA_WIDTH-1:0] output_axis_tdata_int;
reg output_axis_tvalid_int; reg output_axis_tvalid_int;
reg output_axis_tready_int = 0; reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int; reg output_axis_tlast_int;
reg output_axis_tuser_int; reg output_axis_tuser_int;
wire output_axis_tready_int_early; wire output_axis_tready_int_early;
@ -129,6 +129,10 @@ always @* begin
current_output_tready = output_{{p}}_axis_tready; current_output_tready = output_{{p}}_axis_tready;
end end
{%- endfor %} {%- endfor %}
default: begin
current_output_tvalid = 1'b0;
current_output_tready = 1'b0;
end
endcase endcase
end end
@ -136,7 +140,7 @@ always @* begin
select_next = select_reg; select_next = select_reg;
frame_next = frame_reg; frame_next = frame_reg;
input_axis_tready_next = 0; input_axis_tready_next = 1'b0;
if (frame_reg) begin if (frame_reg) begin
if (input_axis_tvalid & input_axis_tready) begin if (input_axis_tvalid & input_axis_tready) begin
@ -145,7 +149,7 @@ always @* begin
end end
end else if (enable & input_axis_tvalid & ~current_output_tvalid) begin end else if (enable & input_axis_tvalid & ~current_output_tvalid) begin
// start of frame, grab select value // start of frame, grab select value
frame_next = 1; frame_next = 1'b1;
select_next = select; select_next = select;
end end
@ -159,9 +163,9 @@ end
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
select_reg <= 0; select_reg <= {{w}}'d0;
frame_reg <= 0; frame_reg <= 1'b0;
input_axis_tready_reg <= 0; input_axis_tready_reg <= 1'b0;
end else begin end else begin
select_reg <= select_next; select_reg <= select_next;
frame_reg <= frame_next; frame_reg <= frame_next;
@ -170,77 +174,95 @@ always @(posedge clk) begin
end end
// output datapath logic // output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
{%- for p in ports %} {%- for p in ports %}
reg output_{{p}}_axis_tvalid_reg = 0; reg output_{{p}}_axis_tvalid_reg = 1'b0, output_{{p}}_axis_tvalid_next;
{%- endfor %} {%- endfor %}
reg output_axis_tlast_reg = 0; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 0; reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 0; reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 0; reg temp_axis_tlast_reg = 1'b0;
reg temp_axis_tuser_reg = 0; reg temp_axis_tuser_reg = 1'b0;
// datapath control
reg store_axis_int_to_output;
reg store_axis_int_to_temp;
reg store_axis_temp_to_output;
{% for p in ports %} {% for p in ports %}
assign output_{{p}}_axis_tdata = output_axis_tdata_reg; assign output_{{p}}_axis_tdata = output_axis_tdata_reg;
assign output_{{p}}_axis_tvalid = output_{{p}}_axis_tvalid_reg; assign output_{{p}}_axis_tvalid = output_{{p}}_axis_tvalid_reg;
assign output_{{p}}_axis_tlast = output_axis_tlast_reg; assign output_{{p}}_axis_tlast = output_axis_tlast_reg;
assign output_{{p}}_axis_tuser = output_axis_tuser_reg; assign output_{{p}}_axis_tuser = output_axis_tuser_reg;
{% endfor %} {% endfor %}
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle // 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 = current_output_tready | (~temp_axis_tvalid_reg & ~current_output_tvalid) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int); assign output_axis_tready_int_early = current_output_tready | (~temp_axis_tvalid_reg & (~current_output_tvalid | ~output_axis_tvalid_int));
always @(posedge clk) begin always @* begin
if (rst) begin
output_axis_tdata_reg <= 0;
{%- for p in ports %}
output_{{p}}_axis_tvalid_reg <= 0;
{%- endfor %}
output_axis_tlast_reg <= 0;
output_axis_tuser_reg <= 0;
output_axis_tready_int <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source // transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early; {%- for p in ports %}
output_{{p}}_axis_tvalid_next = output_{{p}}_axis_tvalid_reg;
{%- endfor %}
temp_axis_tvalid_next = temp_axis_tvalid_reg;
if (output_axis_tready_int) begin 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 // input is ready
if (current_output_tready | ~current_output_tvalid) begin if (current_output_tready | ~current_output_tvalid) begin
// output is ready or currently not valid, transfer data to output // output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int;
case (select_reg)
{%- for p in ports %} {%- for p in ports %}
{{w}}'d{{p}}: output_{{p}}_axis_tvalid_reg <= output_axis_tvalid_int; output_{{p}}_axis_tvalid_next = output_axis_tvalid_int & (select_reg == {{w}}'d{{p}});
{%- endfor %} {%- endfor %}
endcase store_axis_int_to_output = 1'b1;
output_axis_tlast_reg <= output_axis_tlast_int;
output_axis_tuser_reg <= output_axis_tuser_int;
end else begin end else begin
// output is not ready, store input in temp // output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int; temp_axis_tvalid_next = output_axis_tvalid_int;
temp_axis_tvalid_reg <= output_axis_tvalid_int; store_axis_int_to_temp = 1'b1;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end else if (current_output_tready) begin end else if (current_output_tready) begin
// input is not ready, but output is ready // input is not ready, but output is ready
output_axis_tdata_reg <= temp_axis_tdata_reg;
case (select_reg)
{%- for p in ports %} {%- for p in ports %}
{{w}}'d{{p}}: output_{{p}}_axis_tvalid_reg <= temp_axis_tvalid_reg; output_{{p}}_axis_tvalid_next = temp_axis_tvalid_reg & (select_reg == {{w}}'d{{p}});
{%- endfor %} {%- endfor %}
endcase temp_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
{%- for p in ports %}
output_{{p}}_axis_tvalid_reg <= 1'b0;
{%- endfor %}
output_axis_tready_int_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
{%- for p in ports %}
output_{{p}}_axis_tvalid_reg <= output_{{p}}_axis_tvalid_next;
{%- endfor %}
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_tlast_reg <= output_axis_tlast_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_tlast_reg <= temp_axis_tlast_reg; output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg; output_axis_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end end
if (store_axis_int_to_temp) begin
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end end

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -80,15 +80,15 @@ module axis_demux_4 #
input wire [1:0] select input wire [1:0] select
); );
reg [1:0] select_reg = 0, select_next; reg [1:0] select_reg = 2'd0, select_next;
reg frame_reg = 0, frame_next; reg frame_reg = 1'b0, frame_next;
reg input_axis_tready_reg = 0, input_axis_tready_next; reg input_axis_tready_reg = 1'b0, input_axis_tready_next;
// internal datapath // internal datapath
reg [DATA_WIDTH-1:0] output_axis_tdata_int; reg [DATA_WIDTH-1:0] output_axis_tdata_int;
reg output_axis_tvalid_int; reg output_axis_tvalid_int;
reg output_axis_tready_int = 0; reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int; reg output_axis_tlast_int;
reg output_axis_tuser_int; reg output_axis_tuser_int;
wire output_axis_tready_int_early; wire output_axis_tready_int_early;
@ -116,6 +116,10 @@ always @* begin
current_output_tvalid = output_3_axis_tvalid; current_output_tvalid = output_3_axis_tvalid;
current_output_tready = output_3_axis_tready; current_output_tready = output_3_axis_tready;
end end
default: begin
current_output_tvalid = 1'b0;
current_output_tready = 1'b0;
end
endcase endcase
end end
@ -123,7 +127,7 @@ always @* begin
select_next = select_reg; select_next = select_reg;
frame_next = frame_reg; frame_next = frame_reg;
input_axis_tready_next = 0; input_axis_tready_next = 1'b0;
if (frame_reg) begin if (frame_reg) begin
if (input_axis_tvalid & input_axis_tready) begin if (input_axis_tvalid & input_axis_tready) begin
@ -132,7 +136,7 @@ always @* begin
end end
end else if (enable & input_axis_tvalid & ~current_output_tvalid) begin end else if (enable & input_axis_tvalid & ~current_output_tvalid) begin
// start of frame, grab select value // start of frame, grab select value
frame_next = 1; frame_next = 1'b1;
select_next = select; select_next = select;
end end
@ -146,9 +150,9 @@ end
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
select_reg <= 0; select_reg <= 2'd0;
frame_reg <= 0; frame_reg <= 1'b0;
input_axis_tready_reg <= 0; input_axis_tready_reg <= 1'b0;
end else begin end else begin
select_reg <= select_next; select_reg <= select_next;
frame_reg <= frame_next; frame_reg <= frame_next;
@ -157,18 +161,23 @@ always @(posedge clk) begin
end end
// output datapath logic // output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_0_axis_tvalid_reg = 0; reg output_0_axis_tvalid_reg = 1'b0, output_0_axis_tvalid_next;
reg output_1_axis_tvalid_reg = 0; reg output_1_axis_tvalid_reg = 1'b0, output_1_axis_tvalid_next;
reg output_2_axis_tvalid_reg = 0; reg output_2_axis_tvalid_reg = 1'b0, output_2_axis_tvalid_next;
reg output_3_axis_tvalid_reg = 0; reg output_3_axis_tvalid_reg = 1'b0, output_3_axis_tvalid_next;
reg output_axis_tlast_reg = 0; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 0; reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 0; reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 0; reg temp_axis_tlast_reg = 1'b0;
reg temp_axis_tuser_reg = 0; reg temp_axis_tuser_reg = 1'b0;
// datapath control
reg store_axis_int_to_output;
reg store_axis_int_to_temp;
reg store_axis_temp_to_output;
assign output_0_axis_tdata = output_axis_tdata_reg; assign output_0_axis_tdata = output_axis_tdata_reg;
assign output_0_axis_tvalid = output_0_axis_tvalid_reg; assign output_0_axis_tvalid = output_0_axis_tvalid_reg;
@ -190,63 +199,78 @@ assign output_3_axis_tvalid = output_3_axis_tvalid_reg;
assign output_3_axis_tlast = output_axis_tlast_reg; assign output_3_axis_tlast = output_axis_tlast_reg;
assign output_3_axis_tuser = output_axis_tuser_reg; assign output_3_axis_tuser = output_axis_tuser_reg;
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle // 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 = current_output_tready | (~temp_axis_tvalid_reg & ~current_output_tvalid) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int); assign output_axis_tready_int_early = current_output_tready | (~temp_axis_tvalid_reg & (~current_output_tvalid | ~output_axis_tvalid_int));
always @(posedge clk) begin always @* begin
if (rst) begin
output_axis_tdata_reg <= 0;
output_0_axis_tvalid_reg <= 0;
output_1_axis_tvalid_reg <= 0;
output_2_axis_tvalid_reg <= 0;
output_3_axis_tvalid_reg <= 0;
output_axis_tlast_reg <= 0;
output_axis_tuser_reg <= 0;
output_axis_tready_int <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source // transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early; output_0_axis_tvalid_next = output_0_axis_tvalid_reg;
output_1_axis_tvalid_next = output_1_axis_tvalid_reg;
output_2_axis_tvalid_next = output_2_axis_tvalid_reg;
output_3_axis_tvalid_next = output_3_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
if (output_axis_tready_int) begin 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 // input is ready
if (current_output_tready | ~current_output_tvalid) begin if (current_output_tready | ~current_output_tvalid) begin
// output is ready or currently not valid, transfer data to output // output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int; output_0_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd0);
case (select_reg) output_1_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd1);
2'd0: output_0_axis_tvalid_reg <= output_axis_tvalid_int; output_2_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd2);
2'd1: output_1_axis_tvalid_reg <= output_axis_tvalid_int; output_3_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd3);
2'd2: output_2_axis_tvalid_reg <= output_axis_tvalid_int; store_axis_int_to_output = 1'b1;
2'd3: output_3_axis_tvalid_reg <= output_axis_tvalid_int;
endcase
output_axis_tlast_reg <= output_axis_tlast_int;
output_axis_tuser_reg <= output_axis_tuser_int;
end else begin end else begin
// output is not ready, store input in temp // output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int; temp_axis_tvalid_next = output_axis_tvalid_int;
temp_axis_tvalid_reg <= output_axis_tvalid_int; store_axis_int_to_temp = 1'b1;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end else if (current_output_tready) begin end else if (current_output_tready) begin
// input is not ready, but output is ready // input is not ready, but output is ready
output_0_axis_tvalid_next = temp_axis_tvalid_reg & (select_reg == 2'd0);
output_1_axis_tvalid_next = temp_axis_tvalid_reg & (select_reg == 2'd1);
output_2_axis_tvalid_next = temp_axis_tvalid_reg & (select_reg == 2'd2);
output_3_axis_tvalid_next = temp_axis_tvalid_reg & (select_reg == 2'd3);
temp_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
output_0_axis_tvalid_reg <= 1'b0;
output_1_axis_tvalid_reg <= 1'b0;
output_2_axis_tvalid_reg <= 1'b0;
output_3_axis_tvalid_reg <= 1'b0;
output_axis_tready_int_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
output_0_axis_tvalid_reg <= output_0_axis_tvalid_next;
output_1_axis_tvalid_reg <= output_1_axis_tvalid_next;
output_2_axis_tvalid_reg <= output_2_axis_tvalid_next;
output_3_axis_tvalid_reg <= output_3_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_tlast_reg <= output_axis_tlast_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_tdata_reg <= temp_axis_tdata_reg;
case (select_reg)
2'd0: output_0_axis_tvalid_reg <= temp_axis_tvalid_reg;
2'd1: output_1_axis_tvalid_reg <= temp_axis_tvalid_reg;
2'd2: output_2_axis_tvalid_reg <= temp_axis_tvalid_reg;
2'd3: output_3_axis_tvalid_reg <= temp_axis_tvalid_reg;
endcase
output_axis_tlast_reg <= temp_axis_tlast_reg; output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg; output_axis_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end end
if (store_axis_int_to_temp) begin
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end end

View File

@ -40,7 +40,7 @@ def generate(ports=4, name=None, output=None):
t = Template(u"""/* t = Template(u"""/*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -106,16 +106,16 @@ module {{name}} #
input wire [{{w-1}}:0] select input wire [{{w-1}}:0] select
); );
reg [{{w-1}}:0] select_reg = 0, select_next; reg [{{w-1}}:0] select_reg = {{w}}'d0, select_next;
reg frame_reg = 0, frame_next; reg frame_reg = 1'b0, frame_next;
reg input_axis_tready_reg = 0, input_axis_tready_next; reg input_axis_tready_reg = 1'b0, input_axis_tready_next;
// internal datapath // internal datapath
reg [DATA_WIDTH-1:0] output_axis_tdata_int; reg [DATA_WIDTH-1:0] output_axis_tdata_int;
reg [KEEP_WIDTH-1:0] output_axis_tkeep_int; reg [KEEP_WIDTH-1:0] output_axis_tkeep_int;
reg output_axis_tvalid_int; reg output_axis_tvalid_int;
reg output_axis_tready_int = 0; reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int; reg output_axis_tlast_int;
reg output_axis_tuser_int; reg output_axis_tuser_int;
wire output_axis_tready_int_early; wire output_axis_tready_int_early;
@ -133,6 +133,10 @@ always @* begin
current_output_tready = output_{{p}}_axis_tready; current_output_tready = output_{{p}}_axis_tready;
end end
{%- endfor %} {%- endfor %}
default: begin
current_output_tvalid = 1'b0;
current_output_tready = 1'b0;
end
endcase endcase
end end
@ -140,7 +144,7 @@ always @* begin
select_next = select_reg; select_next = select_reg;
frame_next = frame_reg; frame_next = frame_reg;
input_axis_tready_next = 0; input_axis_tready_next = 1'b0;
if (frame_reg) begin if (frame_reg) begin
if (input_axis_tvalid & input_axis_tready) begin if (input_axis_tvalid & input_axis_tready) begin
@ -149,7 +153,7 @@ always @* begin
end end
end else if (enable & input_axis_tvalid & ~current_output_tvalid) begin end else if (enable & input_axis_tvalid & ~current_output_tvalid) begin
// start of frame, grab select value // start of frame, grab select value
frame_next = 1; frame_next = 1'b1;
select_next = select; select_next = select;
end end
@ -164,9 +168,9 @@ end
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
select_reg <= 0; select_reg <= {{w}}'d0;
frame_reg <= 0; frame_reg <= 1'b0;
input_axis_tready_reg <= 0; input_axis_tready_reg <= 1'b0;
end else begin end else begin
select_reg <= select_next; select_reg <= select_next;
frame_reg <= frame_next; frame_reg <= frame_next;
@ -175,19 +179,24 @@ always @(posedge clk) begin
end end
// output datapath logic // output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
{%- for p in ports %} {%- for p in ports %}
reg output_{{p}}_axis_tvalid_reg = 0; reg output_{{p}}_axis_tvalid_reg = 1'b0, output_{{p}}_axis_tvalid_next;
{%- endfor %} {%- endfor %}
reg output_axis_tlast_reg = 0; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 0; reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 0; reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 0; reg temp_axis_tlast_reg = 1'b0;
reg temp_axis_tuser_reg = 0; reg temp_axis_tuser_reg = 1'b0;
// datapath control
reg store_axis_int_to_output;
reg store_axis_int_to_temp;
reg store_axis_temp_to_output;
{% for p in ports %} {% for p in ports %}
assign output_{{p}}_axis_tdata = output_axis_tdata_reg; assign output_{{p}}_axis_tdata = output_axis_tdata_reg;
assign output_{{p}}_axis_tkeep = output_axis_tkeep_reg; assign output_{{p}}_axis_tkeep = output_axis_tkeep_reg;
@ -195,66 +204,76 @@ assign output_{{p}}_axis_tvalid = output_{{p}}_axis_tvalid_reg;
assign output_{{p}}_axis_tlast = output_axis_tlast_reg; assign output_{{p}}_axis_tlast = output_axis_tlast_reg;
assign output_{{p}}_axis_tuser = output_axis_tuser_reg; assign output_{{p}}_axis_tuser = output_axis_tuser_reg;
{% endfor %} {% endfor %}
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle // 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 = current_output_tready | (~temp_axis_tvalid_reg & ~current_output_tvalid) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int); assign output_axis_tready_int_early = current_output_tready | (~temp_axis_tvalid_reg & (~current_output_tvalid | ~output_axis_tvalid_int));
always @(posedge clk) begin always @* begin
if (rst) begin
output_axis_tdata_reg <= 0;
output_axis_tkeep_reg <= 0;
{%- for p in ports %}
output_{{p}}_axis_tvalid_reg <= 0;
{%- endfor %}
output_axis_tlast_reg <= 0;
output_axis_tuser_reg <= 0;
output_axis_tready_int <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tkeep_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source // transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early; {%- for p in ports %}
output_{{p}}_axis_tvalid_next = output_{{p}}_axis_tvalid_reg;
{%- endfor %}
temp_axis_tvalid_next = temp_axis_tvalid_reg;
if (output_axis_tready_int) begin 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 // input is ready
if (current_output_tready | ~current_output_tvalid) begin if (current_output_tready | ~current_output_tvalid) begin
// output is ready or currently not valid, transfer data to output // output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int;
output_axis_tkeep_reg <= output_axis_tkeep_int;
case (select_reg)
{%- for p in ports %} {%- for p in ports %}
{{w}}'d{{p}}: output_{{p}}_axis_tvalid_reg <= output_axis_tvalid_int; output_{{p}}_axis_tvalid_next = output_axis_tvalid_int & (select_reg == {{w}}'d{{p}});
{%- endfor %} {%- endfor %}
endcase store_axis_int_to_output = 1'b1;
output_axis_tlast_reg <= output_axis_tlast_int;
output_axis_tuser_reg <= output_axis_tuser_int;
end else begin end else begin
// output is not ready, store input in temp // output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int; temp_axis_tvalid_next = output_axis_tvalid_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int; store_axis_int_to_temp = 1'b1;
temp_axis_tvalid_reg <= output_axis_tvalid_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end else if (current_output_tready) begin end else if (current_output_tready) begin
// input is not ready, but output is ready // input is not ready, but output is ready
{%- for p in ports %}
output_{{p}}_axis_tvalid_next = temp_axis_tvalid_reg & (select_reg == {{w}}'d{{p}});
{%- endfor %}
temp_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
{%- for p in ports %}
output_{{p}}_axis_tvalid_reg <= 1'b0;
{%- endfor %}
output_axis_tready_int_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
{%- for p in ports %}
output_{{p}}_axis_tvalid_reg <= output_{{p}}_axis_tvalid_next;
{%- endfor %}
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_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_tdata_reg <= temp_axis_tdata_reg;
output_axis_tkeep_reg <= temp_axis_tkeep_reg; output_axis_tkeep_reg <= temp_axis_tkeep_reg;
case (select_reg)
{%- for p in ports %}
{{w}}'d{{p}}: output_{{p}}_axis_tvalid_reg <= temp_axis_tvalid_reg;
{%- endfor %}
endcase
output_axis_tlast_reg <= temp_axis_tlast_reg; output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg; output_axis_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tkeep_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end 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_tuser_reg <= output_axis_tuser_int;
end end
end end

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -86,16 +86,16 @@ module axis_demux_64_4 #
input wire [1:0] select input wire [1:0] select
); );
reg [1:0] select_reg = 0, select_next; reg [1:0] select_reg = 2'd0, select_next;
reg frame_reg = 0, frame_next; reg frame_reg = 1'b0, frame_next;
reg input_axis_tready_reg = 0, input_axis_tready_next; reg input_axis_tready_reg = 1'b0, input_axis_tready_next;
// internal datapath // internal datapath
reg [DATA_WIDTH-1:0] output_axis_tdata_int; reg [DATA_WIDTH-1:0] output_axis_tdata_int;
reg [KEEP_WIDTH-1:0] output_axis_tkeep_int; reg [KEEP_WIDTH-1:0] output_axis_tkeep_int;
reg output_axis_tvalid_int; reg output_axis_tvalid_int;
reg output_axis_tready_int = 0; reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int; reg output_axis_tlast_int;
reg output_axis_tuser_int; reg output_axis_tuser_int;
wire output_axis_tready_int_early; wire output_axis_tready_int_early;
@ -123,6 +123,10 @@ always @* begin
current_output_tvalid = output_3_axis_tvalid; current_output_tvalid = output_3_axis_tvalid;
current_output_tready = output_3_axis_tready; current_output_tready = output_3_axis_tready;
end end
default: begin
current_output_tvalid = 1'b0;
current_output_tready = 1'b0;
end
endcase endcase
end end
@ -130,7 +134,7 @@ always @* begin
select_next = select_reg; select_next = select_reg;
frame_next = frame_reg; frame_next = frame_reg;
input_axis_tready_next = 0; input_axis_tready_next = 1'b0;
if (frame_reg) begin if (frame_reg) begin
if (input_axis_tvalid & input_axis_tready) begin if (input_axis_tvalid & input_axis_tready) begin
@ -139,7 +143,7 @@ always @* begin
end end
end else if (enable & input_axis_tvalid & ~current_output_tvalid) begin end else if (enable & input_axis_tvalid & ~current_output_tvalid) begin
// start of frame, grab select value // start of frame, grab select value
frame_next = 1; frame_next = 1'b1;
select_next = select; select_next = select;
end end
@ -154,9 +158,9 @@ end
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
select_reg <= 0; select_reg <= 2'd0;
frame_reg <= 0; frame_reg <= 1'b0;
input_axis_tready_reg <= 0; input_axis_tready_reg <= 1'b0;
end else begin end else begin
select_reg <= select_next; select_reg <= select_next;
frame_reg <= frame_next; frame_reg <= frame_next;
@ -165,20 +169,25 @@ always @(posedge clk) begin
end end
// output datapath logic // output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_0_axis_tvalid_reg = 0; reg output_0_axis_tvalid_reg = 1'b0, output_0_axis_tvalid_next;
reg output_1_axis_tvalid_reg = 0; reg output_1_axis_tvalid_reg = 1'b0, output_1_axis_tvalid_next;
reg output_2_axis_tvalid_reg = 0; reg output_2_axis_tvalid_reg = 1'b0, output_2_axis_tvalid_next;
reg output_3_axis_tvalid_reg = 0; reg output_3_axis_tvalid_reg = 1'b0, output_3_axis_tvalid_next;
reg output_axis_tlast_reg = 0; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 0; reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 0; reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 0; reg temp_axis_tlast_reg = 1'b0;
reg temp_axis_tuser_reg = 0; reg temp_axis_tuser_reg = 1'b0;
// datapath control
reg store_axis_int_to_output;
reg store_axis_int_to_temp;
reg store_axis_temp_to_output;
assign output_0_axis_tdata = output_axis_tdata_reg; assign output_0_axis_tdata = output_axis_tdata_reg;
assign output_0_axis_tkeep = output_axis_tkeep_reg; assign output_0_axis_tkeep = output_axis_tkeep_reg;
@ -204,69 +213,81 @@ assign output_3_axis_tvalid = output_3_axis_tvalid_reg;
assign output_3_axis_tlast = output_axis_tlast_reg; assign output_3_axis_tlast = output_axis_tlast_reg;
assign output_3_axis_tuser = output_axis_tuser_reg; assign output_3_axis_tuser = output_axis_tuser_reg;
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle // 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 = current_output_tready | (~temp_axis_tvalid_reg & ~current_output_tvalid) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int); assign output_axis_tready_int_early = current_output_tready | (~temp_axis_tvalid_reg & (~current_output_tvalid | ~output_axis_tvalid_int));
always @(posedge clk) begin always @* begin
if (rst) begin
output_axis_tdata_reg <= 0;
output_axis_tkeep_reg <= 0;
output_0_axis_tvalid_reg <= 0;
output_1_axis_tvalid_reg <= 0;
output_2_axis_tvalid_reg <= 0;
output_3_axis_tvalid_reg <= 0;
output_axis_tlast_reg <= 0;
output_axis_tuser_reg <= 0;
output_axis_tready_int <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tkeep_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source // transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early; output_0_axis_tvalid_next = output_0_axis_tvalid_reg;
output_1_axis_tvalid_next = output_1_axis_tvalid_reg;
output_2_axis_tvalid_next = output_2_axis_tvalid_reg;
output_3_axis_tvalid_next = output_3_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
if (output_axis_tready_int) begin 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 // input is ready
if (current_output_tready | ~current_output_tvalid) begin if (current_output_tready | ~current_output_tvalid) begin
// output is ready or currently not valid, transfer data to output // output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int; output_0_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd0);
output_axis_tkeep_reg <= output_axis_tkeep_int; output_1_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd1);
case (select_reg) output_2_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd2);
2'd0: output_0_axis_tvalid_reg <= output_axis_tvalid_int; output_3_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd3);
2'd1: output_1_axis_tvalid_reg <= output_axis_tvalid_int; store_axis_int_to_output = 1'b1;
2'd2: output_2_axis_tvalid_reg <= output_axis_tvalid_int;
2'd3: output_3_axis_tvalid_reg <= output_axis_tvalid_int;
endcase
output_axis_tlast_reg <= output_axis_tlast_int;
output_axis_tuser_reg <= output_axis_tuser_int;
end else begin end else begin
// output is not ready, store input in temp // output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int; temp_axis_tvalid_next = output_axis_tvalid_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int; store_axis_int_to_temp = 1'b1;
temp_axis_tvalid_reg <= output_axis_tvalid_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end else if (current_output_tready) begin end else if (current_output_tready) begin
// input is not ready, but output is ready // input is not ready, but output is ready
output_0_axis_tvalid_next = temp_axis_tvalid_reg & (select_reg == 2'd0);
output_1_axis_tvalid_next = temp_axis_tvalid_reg & (select_reg == 2'd1);
output_2_axis_tvalid_next = temp_axis_tvalid_reg & (select_reg == 2'd2);
output_3_axis_tvalid_next = temp_axis_tvalid_reg & (select_reg == 2'd3);
temp_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
output_0_axis_tvalid_reg <= 1'b0;
output_1_axis_tvalid_reg <= 1'b0;
output_2_axis_tvalid_reg <= 1'b0;
output_3_axis_tvalid_reg <= 1'b0;
output_axis_tready_int_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
output_0_axis_tvalid_reg <= output_0_axis_tvalid_next;
output_1_axis_tvalid_reg <= output_1_axis_tvalid_next;
output_2_axis_tvalid_reg <= output_2_axis_tvalid_next;
output_3_axis_tvalid_reg <= output_3_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_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_tdata_reg <= temp_axis_tdata_reg;
output_axis_tkeep_reg <= temp_axis_tkeep_reg; output_axis_tkeep_reg <= temp_axis_tkeep_reg;
case (select_reg)
2'd0: output_0_axis_tvalid_reg <= temp_axis_tvalid_reg;
2'd1: output_1_axis_tvalid_reg <= temp_axis_tvalid_reg;
2'd2: output_2_axis_tvalid_reg <= temp_axis_tvalid_reg;
2'd3: output_3_axis_tvalid_reg <= temp_axis_tvalid_reg;
endcase
output_axis_tlast_reg <= temp_axis_tlast_reg; output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg; output_axis_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tkeep_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end 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_tuser_reg <= output_axis_tuser_int;
end end
end end

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2013 Alex Forencich Copyright (c) 2013-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -57,60 +57,93 @@ module axis_fifo #
output wire output_axis_tuser output wire output_axis_tuser
); );
reg [ADDR_WIDTH:0] wr_ptr = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_next;
reg [ADDR_WIDTH:0] rd_ptr = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
reg [DATA_WIDTH+2-1:0] data_out_reg = {1'b0, 1'b0, {DATA_WIDTH{1'b0}}};
//(* RAM_STYLE="BLOCK" *)
reg [DATA_WIDTH+2-1:0] mem[(2**ADDR_WIDTH)-1:0]; reg [DATA_WIDTH+2-1:0] mem[(2**ADDR_WIDTH)-1:0];
reg output_axis_tvalid_reg = 1'b0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
wire [DATA_WIDTH+2-1:0] data_in = {input_axis_tlast, input_axis_tuser, input_axis_tdata}; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 1'b0;
// full when first MSB different but rest same // full when first MSB different but rest same
wire full = ((wr_ptr[ADDR_WIDTH] != rd_ptr[ADDR_WIDTH]) && wire full = ((wr_ptr_reg[ADDR_WIDTH] != rd_ptr_reg[ADDR_WIDTH]) &&
(wr_ptr[ADDR_WIDTH-1:0] == rd_ptr[ADDR_WIDTH-1:0])); (wr_ptr_reg[ADDR_WIDTH-1:0] == rd_ptr_reg[ADDR_WIDTH-1:0]));
// empty when pointers match exactly // empty when pointers match exactly
wire empty = wr_ptr == rd_ptr; wire empty = wr_ptr_reg == rd_ptr_reg;
wire write = input_axis_tvalid & ~full; // control signals
wire read = (output_axis_tready | ~output_axis_tvalid_reg) & ~empty; reg write;
reg read;
assign {output_axis_tlast, output_axis_tuser, output_axis_tdata} = data_out_reg;
assign input_axis_tready = ~full; assign input_axis_tready = ~full;
assign output_axis_tdata = output_axis_tdata_reg;
assign output_axis_tvalid = output_axis_tvalid_reg; assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg;
// write // Write logic
always @(posedge clk) begin always @* begin
if (rst) begin write = 1'b0;
wr_ptr <= 0;
end else if (write) begin wr_ptr_next = wr_ptr_reg;
mem[wr_ptr[ADDR_WIDTH-1:0]] <= data_in;
wr_ptr <= wr_ptr + 1; if (input_axis_tvalid) begin
// input data valid
if (~full) begin
// not full, perform write
write = 1'b1;
wr_ptr_next = wr_ptr_reg + 1;
end
end end
end end
// read
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
rd_ptr <= 0; wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
end else if (read) begin
data_out_reg <= mem[rd_ptr[ADDR_WIDTH-1:0]];
rd_ptr <= rd_ptr + 1;
end
end
// source ready output
always @(posedge clk) begin
if (rst) begin
output_axis_tvalid_reg <= 1'b0;
end else if (output_axis_tready | ~output_axis_tvalid_reg) begin
output_axis_tvalid_reg <= ~empty;
end else begin end else begin
output_axis_tvalid_reg <= output_axis_tvalid_reg; wr_ptr_reg <= wr_ptr_next;
end
if (write) begin
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= {input_axis_tlast, input_axis_tuser, input_axis_tdata};
end
end
// Read logic
always @* begin
read = 1'b0;
rd_ptr_next = rd_ptr_reg;
output_axis_tvalid_next = output_axis_tvalid_reg;
if (output_axis_tready | ~output_axis_tvalid) begin
// output data not valid OR currently being transferred
if (~empty) begin
// not empty, perform read
read = 1'b1;
output_axis_tvalid_next = 1'b1;
rd_ptr_next = rd_ptr_reg + 1;
end else begin
output_axis_tvalid_next = 1'b0;
end
end
end
always @(posedge clk) begin
if (rst) begin
rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
output_axis_tvalid_reg <= 1'b0;
end else begin
rd_ptr_reg <= rd_ptr_next;
output_axis_tvalid_reg <= output_axis_tvalid_next;
end
if (read) begin
{output_axis_tlast_reg, output_axis_tuser_reg, output_axis_tdata_reg} <= mem[rd_ptr_reg[ADDR_WIDTH-1:0]];
end end
end end

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2013 Alex Forencich Copyright (c) 2013-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -60,60 +60,96 @@ module axis_fifo_64 #
output wire output_axis_tuser output wire output_axis_tuser
); );
reg [ADDR_WIDTH:0] wr_ptr = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_next;
reg [ADDR_WIDTH:0] rd_ptr = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
reg [DATA_WIDTH+KEEP_WIDTH+2-1:0] data_out_reg = {1'b0, 1'b0, {KEEP_WIDTH{1'b0}}, {DATA_WIDTH{1'b0}}};
//(* RAM_STYLE="BLOCK" *)
reg [DATA_WIDTH+KEEP_WIDTH+2-1:0] mem[(2**ADDR_WIDTH)-1:0]; reg [DATA_WIDTH+KEEP_WIDTH+2-1:0] mem[(2**ADDR_WIDTH)-1:0];
reg output_axis_tvalid_reg = 1'b0; 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}};
wire [DATA_WIDTH+KEEP_WIDTH+2-1:0] data_in = {input_axis_tlast, input_axis_tuser, input_axis_tkeep, input_axis_tdata}; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 1'b0;
// full when first MSB different but rest same // full when first MSB different but rest same
wire full = ((wr_ptr[ADDR_WIDTH] != rd_ptr[ADDR_WIDTH]) && wire full = ((wr_ptr_reg[ADDR_WIDTH] != rd_ptr_reg[ADDR_WIDTH]) &&
(wr_ptr[ADDR_WIDTH-1:0] == rd_ptr[ADDR_WIDTH-1:0])); (wr_ptr_reg[ADDR_WIDTH-1:0] == rd_ptr_reg[ADDR_WIDTH-1:0]));
// empty when pointers match exactly // empty when pointers match exactly
wire empty = wr_ptr == rd_ptr; wire empty = wr_ptr_reg == rd_ptr_reg;
wire write = input_axis_tvalid & ~full; // control signals
wire read = (output_axis_tready | ~output_axis_tvalid_reg) & ~empty; reg write;
reg read;
assign {output_axis_tlast, output_axis_tuser, output_axis_tkeep, output_axis_tdata} = data_out_reg;
assign input_axis_tready = ~full; assign input_axis_tready = ~full;
assign output_axis_tdata = output_axis_tdata_reg;
assign output_axis_tkeep = output_axis_tkeep_reg;
assign output_axis_tvalid = output_axis_tvalid_reg; assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg;
// write // FIFO write logic
always @(posedge clk) begin always @* begin
if (rst) begin write = 1'b0;
wr_ptr <= 0;
end else if (write) begin wr_ptr_next = wr_ptr_reg;
mem[wr_ptr[ADDR_WIDTH-1:0]] <= data_in;
wr_ptr <= wr_ptr + 1; if (input_axis_tvalid) begin
// input data valid
if (~full) begin
// not full, perform write
write = 1'b1;
wr_ptr_next = wr_ptr_reg + 1;
end
end end
end end
// read
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
rd_ptr <= 0; wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
end else if (read) begin
data_out_reg <= mem[rd_ptr[ADDR_WIDTH-1:0]];
rd_ptr <= rd_ptr + 1;
end
end
// source ready output
always @(posedge clk) begin
if (rst) begin
output_axis_tvalid_reg <= 1'b0;
end else if (output_axis_tready | ~output_axis_tvalid_reg) begin
output_axis_tvalid_reg <= ~empty;
end else begin end else begin
output_axis_tvalid_reg <= output_axis_tvalid_reg; wr_ptr_reg <= wr_ptr_next;
end
if (write) begin
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= {input_axis_tlast, input_axis_tuser, input_axis_tkeep, input_axis_tdata};
end
end
// FIFO read logic
always @* begin
read = 1'b0;
rd_ptr_next = rd_ptr_reg;
output_axis_tvalid_next = output_axis_tvalid_reg;
if (output_axis_tready | ~output_axis_tvalid) begin
// output data not valid OR currently being transferred
if (~empty) begin
// not empty, perform read
read = 1'b1;
output_axis_tvalid_next = 1'b1;
rd_ptr_next = rd_ptr_reg + 1;
end else begin
// empty, invalidate
output_axis_tvalid_next = 1'b0;
end
end
end
always @(posedge clk) begin
if (rst) begin
rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
output_axis_tvalid_reg <= 1'b0;
end else begin
rd_ptr_reg <= rd_ptr_next;
output_axis_tvalid_reg <= output_axis_tvalid_next;
end
if (read) begin
{output_axis_tlast_reg, output_axis_tuser_reg, output_axis_tkeep_reg, output_axis_tdata_reg} <= mem[rd_ptr_reg[ADDR_WIDTH-1:0]];
end end
end end

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -64,106 +64,147 @@ module axis_frame_fifo #
output wire good_frame output wire good_frame
); );
reg [ADDR_WIDTH:0] wr_ptr = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_next;
reg [ADDR_WIDTH:0] wr_ptr_cur = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_cur_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_cur_next;
reg [ADDR_WIDTH:0] rd_ptr = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
reg drop_frame = 1'b0;
reg overflow_reg = 1'b0;
reg bad_frame_reg = 1'b0;
reg good_frame_reg = 1'b0;
reg [DATA_WIDTH+1-1:0] data_out_reg = {1'b0, {DATA_WIDTH{1'b0}}};
//(* RAM_STYLE="BLOCK" *)
reg [DATA_WIDTH+1-1:0] mem[(2**ADDR_WIDTH)-1:0]; reg [DATA_WIDTH+1-1:0] mem[(2**ADDR_WIDTH)-1:0];
reg output_axis_tvalid_reg = 1'b0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
wire [DATA_WIDTH+1-1:0] data_in = {input_axis_tlast, input_axis_tdata}; reg output_axis_tlast_reg = 1'b0;
// full when first MSB different but rest same // full when first MSB different but rest same
wire full = ((wr_ptr[ADDR_WIDTH] != rd_ptr[ADDR_WIDTH]) && wire full = ((wr_ptr_reg[ADDR_WIDTH] != rd_ptr_reg[ADDR_WIDTH]) &&
(wr_ptr[ADDR_WIDTH-1:0] == rd_ptr[ADDR_WIDTH-1:0])); (wr_ptr_reg[ADDR_WIDTH-1:0] == rd_ptr_reg[ADDR_WIDTH-1:0]));
// empty when pointers match exactly // empty when pointers match exactly
wire empty = wr_ptr == rd_ptr; wire empty = wr_ptr_reg == rd_ptr_reg;
// overflow in single packet // overflow within packet
wire full_cur = ((wr_ptr[ADDR_WIDTH] != wr_ptr_cur[ADDR_WIDTH]) && wire full_cur = ((wr_ptr_reg[ADDR_WIDTH] != wr_ptr_cur_reg[ADDR_WIDTH]) &&
(wr_ptr[ADDR_WIDTH-1:0] == wr_ptr_cur[ADDR_WIDTH-1:0])); (wr_ptr_reg[ADDR_WIDTH-1:0] == wr_ptr_cur_reg[ADDR_WIDTH-1:0]));
wire write = input_axis_tvalid & (~full | DROP_WHEN_FULL); // control signals
wire read = (output_axis_tready | ~output_axis_tvalid_reg) & ~empty; reg write;
reg read;
assign {output_axis_tlast, output_axis_tdata} = data_out_reg; reg drop_frame_reg = 1'b0, drop_frame_next;
reg overflow_reg = 1'b0, overflow_next;
reg bad_frame_reg = 1'b0, bad_frame_next;
reg good_frame_reg = 1'b0, good_frame_next;
assign input_axis_tready = (~full | DROP_WHEN_FULL); assign input_axis_tready = (~full | DROP_WHEN_FULL);
assign output_axis_tdata = output_axis_tdata_reg;
assign output_axis_tvalid = output_axis_tvalid_reg; assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg;
assign overflow = overflow_reg; assign overflow = overflow_reg;
assign bad_frame = bad_frame_reg; assign bad_frame = bad_frame_reg;
assign good_frame = good_frame_reg; assign good_frame = good_frame_reg;
// write // Write logic
always @(posedge clk) begin always @* begin
if (rst) begin write = 1'b0;
wr_ptr <= 0;
wr_ptr_cur <= 0; drop_frame_next = 1'b0;
drop_frame <= 0; overflow_next = 1'b0;
overflow_reg <= 0; bad_frame_next = 1'b0;
bad_frame_reg <= 0; good_frame_next = 1'b0;
good_frame_reg <= 0;
end else if (write) begin wr_ptr_next = wr_ptr_reg;
overflow_reg <= 0; wr_ptr_cur_next = wr_ptr_cur_reg;
bad_frame_reg <= 0;
good_frame_reg <= 0; if (input_axis_tvalid) begin
if (full | full_cur | drop_frame) begin // input data valid
// buffer full, hold current pointer, drop packet at end if (~full | DROP_WHEN_FULL) begin
drop_frame <= 1; // not full, perform write
if (full | full_cur | drop_frame_reg) begin
// full, packet overflow, or currently dropping frame
// drop frame
drop_frame_next = 1'b1;
if (input_axis_tlast) begin if (input_axis_tlast) begin
wr_ptr_cur <= wr_ptr; // end of frame, reset write pointer
drop_frame <= 0; wr_ptr_cur_next = wr_ptr_reg;
overflow_reg <= 1; drop_frame_next = 1'b0;
overflow_next = 1'b1;
end end
end else begin end else begin
mem[wr_ptr_cur[ADDR_WIDTH-1:0]] <= data_in; write = 1'b1;
wr_ptr_cur <= wr_ptr_cur + 1; wr_ptr_cur_next = wr_ptr_cur_reg + 1;
if (input_axis_tlast) begin if (input_axis_tlast) begin
// end of frame
if (input_axis_tuser) begin if (input_axis_tuser) begin
// bad packet, reset write pointer // bad packet, reset write pointer
wr_ptr_cur <= wr_ptr; wr_ptr_cur_next = wr_ptr_reg;
bad_frame_reg <= 1; bad_frame_next = 1'b1;
end else begin end else begin
// good packet, push new write pointer // good packet, update write pointer
wr_ptr <= wr_ptr_cur + 1; wr_ptr_next = wr_ptr_cur_reg + 1;
good_frame_reg <= 1; good_frame_next = 1'b1;
end
end end
end end
end end
end else begin
overflow_reg <= 0;
bad_frame_reg <= 0;
good_frame_reg <= 0;
end end
end end
// read
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
rd_ptr <= 0; wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
end else if (read) begin wr_ptr_cur_reg <= {ADDR_WIDTH+1{1'b0}};
data_out_reg <= mem[rd_ptr[ADDR_WIDTH-1:0]];
rd_ptr <= rd_ptr + 1; drop_frame_reg <= 1'b0;
overflow_reg <= 1'b0;
bad_frame_reg <= 1'b0;
good_frame_reg <= 1'b0;
end else begin
wr_ptr_reg <= wr_ptr_next;
wr_ptr_cur_reg <= wr_ptr_cur_next;
drop_frame_reg <= drop_frame_next;
overflow_reg <= overflow_next;
bad_frame_reg <= bad_frame_next;
good_frame_reg <= good_frame_next;
end
if (write) begin
mem[wr_ptr_cur_reg[ADDR_WIDTH-1:0]] <= {input_axis_tlast, input_axis_tdata};
end
end
// Read logic
always @* begin
read = 1'b0;
rd_ptr_next = rd_ptr_reg;
output_axis_tvalid_next = output_axis_tvalid_reg;
if (output_axis_tready | ~output_axis_tvalid) begin
// output data not valid OR currently being transferred
if (~empty) begin
// not empty, perform read
read = 1'b1;
output_axis_tvalid_next = 1'b1;
rd_ptr_next = rd_ptr_reg + 1;
end else begin
// empty, invalidate
output_axis_tvalid_next = 1'b0;
end
end end
end end
// source ready output
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
output_axis_tvalid_reg <= 1'b0; output_axis_tvalid_reg <= 1'b0;
end else if (output_axis_tready | ~output_axis_tvalid_reg) begin
output_axis_tvalid_reg <= ~empty;
end else begin end else begin
output_axis_tvalid_reg <= output_axis_tvalid_reg; rd_ptr_reg <= rd_ptr_next;
output_axis_tvalid_reg <= output_axis_tvalid_next;
end
if (read) begin
{output_axis_tlast_reg, output_axis_tdata_reg} <= mem[rd_ptr_reg[ADDR_WIDTH-1:0]];
end end
end end

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -67,106 +67,148 @@ module axis_frame_fifo_64 #
output wire good_frame output wire good_frame
); );
reg [ADDR_WIDTH:0] wr_ptr = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_next;
reg [ADDR_WIDTH:0] wr_ptr_cur = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_cur_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_cur_next;
reg [ADDR_WIDTH:0] rd_ptr = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
reg drop_frame = 1'b0;
reg overflow_reg = 1'b0;
reg bad_frame_reg = 1'b0;
reg good_frame_reg = 1'b0;
reg [DATA_WIDTH+KEEP_WIDTH+1-1:0] data_out_reg = {1'b0, {KEEP_WIDTH{1'b0}}, {DATA_WIDTH{1'b0}}};
//(* RAM_STYLE="BLOCK" *)
reg [DATA_WIDTH+KEEP_WIDTH+1-1:0] mem[(2**ADDR_WIDTH)-1:0]; reg [DATA_WIDTH+KEEP_WIDTH+1-1:0] mem[(2**ADDR_WIDTH)-1:0];
reg output_axis_tvalid_reg = 1'b0; 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}};
wire [DATA_WIDTH+KEEP_WIDTH+1-1:0] data_in = {input_axis_tlast, input_axis_tkeep, input_axis_tdata}; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 1'b0;
// full when first MSB different but rest same // full when first MSB different but rest same
wire full = ((wr_ptr[ADDR_WIDTH] != rd_ptr[ADDR_WIDTH]) && wire full = ((wr_ptr_reg[ADDR_WIDTH] != rd_ptr_reg[ADDR_WIDTH]) &&
(wr_ptr[ADDR_WIDTH-1:0] == rd_ptr[ADDR_WIDTH-1:0])); (wr_ptr_reg[ADDR_WIDTH-1:0] == rd_ptr_reg[ADDR_WIDTH-1:0]));
// empty when pointers match exactly // empty when pointers match exactly
wire empty = wr_ptr == rd_ptr; wire empty = wr_ptr_reg == rd_ptr_reg;
// overflow in single packet // overflow within packet
wire full_cur = ((wr_ptr[ADDR_WIDTH] != wr_ptr_cur[ADDR_WIDTH]) && wire full_cur = ((wr_ptr_reg[ADDR_WIDTH] != wr_ptr_cur_reg[ADDR_WIDTH]) &&
(wr_ptr[ADDR_WIDTH-1:0] == wr_ptr_cur[ADDR_WIDTH-1:0])); (wr_ptr_reg[ADDR_WIDTH-1:0] == wr_ptr_cur_reg[ADDR_WIDTH-1:0]));
wire write = input_axis_tvalid & (~full | DROP_WHEN_FULL); // control signals
wire read = (output_axis_tready | ~output_axis_tvalid_reg) & ~empty; reg write;
reg read;
assign {output_axis_tlast, output_axis_tkeep, output_axis_tdata} = data_out_reg; reg drop_frame_reg = 1'b0, drop_frame_next;
reg overflow_reg = 1'b0, overflow_next;
reg bad_frame_reg = 1'b0, bad_frame_next;
reg good_frame_reg = 1'b0, good_frame_next;
assign input_axis_tready = (~full | DROP_WHEN_FULL); assign input_axis_tready = (~full | DROP_WHEN_FULL);
assign output_axis_tdata = output_axis_tdata_reg;
assign output_axis_tkeep = output_axis_tkeep_reg;
assign output_axis_tvalid = output_axis_tvalid_reg; assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg;
assign overflow = overflow_reg; assign overflow = overflow_reg;
assign bad_frame = bad_frame_reg; assign bad_frame = bad_frame_reg;
assign good_frame = good_frame_reg; assign good_frame = good_frame_reg;
// write // Write logic
always @(posedge clk) begin always @* begin
if (rst) begin write = 1'b0;
wr_ptr <= 0;
wr_ptr_cur <= 0; drop_frame_next = 1'b0;
drop_frame <= 0; overflow_next = 1'b0;
overflow_reg <= 0; bad_frame_next = 1'b0;
bad_frame_reg <= 0; good_frame_next = 1'b0;
good_frame_reg <= 0;
end else if (write) begin wr_ptr_next = wr_ptr_reg;
overflow_reg <= 0; wr_ptr_cur_next = wr_ptr_cur_reg;
bad_frame_reg <= 0;
good_frame_reg <= 0; if (input_axis_tvalid) begin
if (full | full_cur | drop_frame) begin // input data valid
// buffer full, hold current pointer, drop packet at end if (~full | DROP_WHEN_FULL) begin
drop_frame <= 1; // not full, perform write
if (full | full_cur | drop_frame_reg) begin
// full, packet overflow, or currently dropping frame
// drop frame
drop_frame_next = 1'b1;
if (input_axis_tlast) begin if (input_axis_tlast) begin
wr_ptr_cur <= wr_ptr; // end of frame, reset write pointer
drop_frame <= 0; wr_ptr_cur_next = wr_ptr_reg;
overflow_reg <= 1; drop_frame_next = 1'b0;
overflow_next = 1'b1;
end end
end else begin end else begin
mem[wr_ptr_cur[ADDR_WIDTH-1:0]] <= data_in; write = 1'b1;
wr_ptr_cur <= wr_ptr_cur + 1; wr_ptr_cur_next = wr_ptr_cur_reg + 1;
if (input_axis_tlast) begin if (input_axis_tlast) begin
// end of frame
if (input_axis_tuser) begin if (input_axis_tuser) begin
// bad packet, reset write pointer // bad packet, reset write pointer
wr_ptr_cur <= wr_ptr; wr_ptr_cur_next = wr_ptr_reg;
bad_frame_reg <= 1; bad_frame_next = 1'b1;
end else begin end else begin
// good packet, push new write pointer // good packet, update write pointer
wr_ptr <= wr_ptr_cur + 1; wr_ptr_next = wr_ptr_cur_reg + 1;
good_frame_reg <= 1; good_frame_next = 1'b1;
end
end end
end end
end end
end else begin
overflow_reg <= 0;
bad_frame_reg <= 0;
good_frame_reg <= 0;
end end
end end
// read
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
rd_ptr <= 0; wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
end else if (read) begin wr_ptr_cur_reg <= {ADDR_WIDTH+1{1'b0}};
data_out_reg <= mem[rd_ptr[ADDR_WIDTH-1:0]];
rd_ptr <= rd_ptr + 1; drop_frame_reg <= 1'b0;
overflow_reg <= 1'b0;
bad_frame_reg <= 1'b0;
good_frame_reg <= 1'b0;
end else begin
wr_ptr_reg <= wr_ptr_next;
wr_ptr_cur_reg <= wr_ptr_cur_next;
drop_frame_reg <= drop_frame_next;
overflow_reg <= overflow_next;
bad_frame_reg <= bad_frame_next;
good_frame_reg <= good_frame_next;
end
if (write) begin
mem[wr_ptr_cur_reg[ADDR_WIDTH-1:0]] <= {input_axis_tlast, input_axis_tkeep, input_axis_tdata};
end
end
// Read logic
always @* begin
read = 1'b0;
rd_ptr_next = rd_ptr_reg;
output_axis_tvalid_next = output_axis_tvalid_reg;
if (output_axis_tready | ~output_axis_tvalid) begin
// output data not valid OR currently being transferred
if (~empty) begin
// not empty, perform read
read = 1'b1;
output_axis_tvalid_next = 1'b1;
rd_ptr_next = rd_ptr_reg + 1;
end else begin
output_axis_tvalid_next = 1'b0;
end
end end
end end
// source ready output
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
output_axis_tvalid_reg <= 1'b0; output_axis_tvalid_reg <= 1'b0;
end else if (output_axis_tready | ~output_axis_tvalid_reg) begin
output_axis_tvalid_reg <= ~empty;
end else begin end else begin
output_axis_tvalid_reg <= output_axis_tvalid_reg; rd_ptr_reg <= rd_ptr_next;
output_axis_tvalid_reg <= output_axis_tvalid_next;
end
if (read) begin
{output_axis_tlast_reg, output_axis_tkeep_reg, output_axis_tdata_reg} <= mem[rd_ptr_reg[ADDR_WIDTH-1:0]];
end end
end end

View File

@ -40,7 +40,7 @@ def generate(ports=4, name=None, output=None):
t = Template(u"""/* t = Template(u"""/*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -118,25 +118,25 @@ localparam [1:0]
reg [1:0] state_reg = STATE_IDLE, state_next; reg [1:0] state_reg = STATE_IDLE, state_next;
reg [2:0] frame_ptr_reg = 0, frame_ptr_next; reg [2:0] frame_ptr_reg = 3'd0, frame_ptr_next;
reg [{{w-1}}:0] port_sel_reg = 0, port_sel_next; reg [{{w-1}}:0] port_sel_reg = {{w}}'d0, port_sel_next;
reg busy_reg = 0, busy_next; reg busy_reg = 1'b0, busy_next;
reg [7:0] input_tdata; reg [7:0] input_tdata;
reg input_tvalid; reg input_tvalid;
reg input_tlast; reg input_tlast;
reg input_tuser; reg input_tuser;
reg output_tuser_reg = 0, output_tuser_next; reg output_tuser_reg = 1'b0, output_tuser_next;
{% for p in ports %} {% for p in ports %}
reg input_{{p}}_axis_tready_reg = 0, input_{{p}}_axis_tready_next; reg input_{{p}}_axis_tready_reg = 1'b0, input_{{p}}_axis_tready_next;
{%- endfor %} {%- endfor %}
// internal datapath // internal datapath
reg [7:0] output_axis_tdata_int; reg [7:0] output_axis_tdata_int;
reg output_axis_tvalid_int; reg output_axis_tvalid_int;
reg output_axis_tready_int = 0; reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int; reg output_axis_tlast_int;
reg output_axis_tuser_int; reg output_axis_tuser_int;
wire output_axis_tready_int_early; wire output_axis_tready_int_early;
@ -163,31 +163,31 @@ end
integer offset, i; integer offset, i;
always @* begin always @* begin
state_next = 2'bz; state_next = STATE_IDLE;
frame_ptr_next = frame_ptr_reg; frame_ptr_next = frame_ptr_reg;
port_sel_next = port_sel_reg; port_sel_next = port_sel_reg;
{% for p in ports %} {% for p in ports %}
input_{{p}}_axis_tready_next = 0; input_{{p}}_axis_tready_next = 1'b0;
{%- endfor %} {%- endfor %}
output_axis_tdata_int = 0; output_axis_tdata_int = 8'd0;
output_axis_tvalid_int = 0; output_axis_tvalid_int = 1'b0;
output_axis_tlast_int = 0; output_axis_tlast_int = 1'b0;
output_axis_tuser_int = 0; output_axis_tuser_int = 1'b0;
output_tuser_next = output_tuser_reg; output_tuser_next = output_tuser_reg;
case (state_reg) case (state_reg)
STATE_IDLE: begin STATE_IDLE: begin
// idle state - wait for data // idle state - wait for data
frame_ptr_next = 0; frame_ptr_next = 3'd0;
port_sel_next = 0; port_sel_next = {{w}}'d0;
output_tuser_next = 0; output_tuser_next = 1'b0;
if (TAG_ENABLE) begin if (TAG_ENABLE) begin
// next cycle if started will send tag, so do not enable input // next cycle if started will send tag, so do not enable input
input_0_axis_tready_next = 0; input_0_axis_tready_next = 1'b0;
end else begin end else begin
// next cycle if started will send data, so enable input // next cycle if started will send data, so enable input
input_0_axis_tready_next = output_axis_tready_int_early; input_0_axis_tready_next = output_axis_tready_int_early;
@ -197,19 +197,19 @@ always @* begin
// input 0 valid; start transferring data // input 0 valid; start transferring data
if (TAG_ENABLE) begin if (TAG_ENABLE) begin
// tag enabled, so transmit it // tag enabled, so transmit it
if (output_axis_tready_int) begin if (output_axis_tready_int_reg) begin
// output is ready, so short-circuit first tag byte // output is ready, so short-circuit first tag byte
frame_ptr_next = 1; frame_ptr_next = 3'd1;
output_axis_tdata_int = tag[(TAG_BYTE_WIDTH-1)*8 +: 8]; output_axis_tdata_int = tag[(TAG_BYTE_WIDTH-1)*8 +: 8];
output_axis_tvalid_int = 1; output_axis_tvalid_int = 1'b1;
end end
state_next = STATE_WRITE_TAG; state_next = STATE_WRITE_TAG;
end else begin end else begin
// tag disabled, so transmit data // tag disabled, so transmit data
if (output_axis_tready_int) begin if (output_axis_tready_int_reg) begin
// output is ready, so short-circuit first data byte // output is ready, so short-circuit first data byte
output_axis_tdata_int = input_0_axis_tdata; output_axis_tdata_int = input_0_axis_tdata;
output_axis_tvalid_int = 1; output_axis_tvalid_int = 1'b1;
end end
state_next = STATE_TRANSFER; state_next = STATE_TRANSFER;
end end
@ -219,11 +219,11 @@ always @* begin
end end
STATE_WRITE_TAG: begin STATE_WRITE_TAG: begin
// write tag data // write tag data
if (output_axis_tready_int) begin if (output_axis_tready_int_reg) begin
// output ready, so send tag byte // output ready, so send tag byte
state_next = STATE_WRITE_TAG; state_next = STATE_WRITE_TAG;
frame_ptr_next = frame_ptr_reg + 1; frame_ptr_next = frame_ptr_reg + 1;
output_axis_tvalid_int = 1; output_axis_tvalid_int = 1'b1;
offset = 0; offset = 0;
if (TAG_ENABLE) begin if (TAG_ENABLE) begin
@ -252,7 +252,7 @@ always @* begin
{%- endfor %} {%- endfor %}
endcase endcase
if (input_tvalid & output_axis_tready_int) begin if (input_tvalid & output_axis_tready_int_reg) begin
// output ready, transfer byte // output ready, transfer byte
state_next = STATE_TRANSFER; state_next = STATE_TRANSFER;
output_axis_tdata_int = input_tdata; output_axis_tdata_int = input_tdata;
@ -265,12 +265,12 @@ always @* begin
output_tuser_next = output_tuser_next | input_tuser; output_tuser_next = output_tuser_next | input_tuser;
// disable input // disable input
{%- for p in ports %} {%- for p in ports %}
input_{{p}}_axis_tready_next = 0; input_{{p}}_axis_tready_next = 1'b0;
{%- endfor %} {%- endfor %}
if (port_sel_reg == {{n-1}}) begin if (port_sel_reg == {{w}}'d{{n-1}}) begin
// last port - send tlast and tuser and revert to idle // last port - send tlast and tuser and revert to idle
output_axis_tlast_int = 1; output_axis_tlast_int = 1'b1;
output_axis_tuser_int = output_tuser_next; output_axis_tuser_int = output_tuser_next;
state_next = STATE_IDLE; state_next = STATE_IDLE;
end else begin end else begin
@ -292,13 +292,13 @@ end
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
state_reg <= STATE_IDLE; state_reg <= STATE_IDLE;
frame_ptr_reg <= 0; frame_ptr_reg <= 3'd0;
port_sel_reg <= 0; port_sel_reg <= {{w}}'d0;
{%- for p in ports %} {%- for p in ports %}
input_{{p}}_axis_tready_reg <= 0; input_{{p}}_axis_tready_reg <= 1'b0;
{%- endfor %} {%- endfor %}
output_tuser_reg <= 0; output_tuser_reg <= 1'b0;
busy_reg <= 0; busy_reg <= 1'b0;
end else begin end else begin
state_reg <= state_next; state_reg <= state_next;
@ -316,65 +316,83 @@ always @(posedge clk) begin
end end
// output datapath logic // output datapath logic
reg [7:0] output_axis_tdata_reg = 0; reg [7:0] output_axis_tdata_reg = 8'd0;
reg output_axis_tvalid_reg = 0; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 0; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 0; reg output_axis_tuser_reg = 1'b0;
reg [7:0] temp_axis_tdata_reg = 0; reg [7:0] temp_axis_tdata_reg = 8'd0;
reg temp_axis_tvalid_reg = 0; reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 0; reg temp_axis_tlast_reg = 1'b0;
reg temp_axis_tuser_reg = 0; reg temp_axis_tuser_reg = 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_tdata = output_axis_tdata_reg;
assign output_axis_tvalid = output_axis_tvalid_reg; assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg; assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg; assign output_axis_tuser = output_axis_tuser_reg;
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle // 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) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int); assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @(posedge clk) begin always @* begin
if (rst) begin
output_axis_tdata_reg <= 0;
output_axis_tvalid_reg <= 0;
output_axis_tlast_reg <= 0;
output_axis_tuser_reg <= 0;
output_axis_tready_int <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source // transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early; output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
if (output_axis_tready_int) begin 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 // input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output // output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int; output_axis_tvalid_next = output_axis_tvalid_int;
output_axis_tvalid_reg <= output_axis_tvalid_int; store_axis_int_to_output = 1'b1;
output_axis_tlast_reg <= output_axis_tlast_int;
output_axis_tuser_reg <= output_axis_tuser_int;
end else begin end else begin
// output is not ready, store input in temp // output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int; temp_axis_tvalid_next = output_axis_tvalid_int;
temp_axis_tvalid_reg <= output_axis_tvalid_int; store_axis_int_to_temp = 1'b1;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end else if (output_axis_tready) begin end else if (output_axis_tready) begin
// input is not ready, but output is ready // 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_tlast_reg <= output_axis_tlast_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_tdata_reg <= temp_axis_tdata_reg;
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg; output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg; output_axis_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end end
if (store_axis_int_to_temp) begin
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end end

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -95,27 +95,27 @@ localparam [1:0]
reg [1:0] state_reg = STATE_IDLE, state_next; reg [1:0] state_reg = STATE_IDLE, state_next;
reg [2:0] frame_ptr_reg = 0, frame_ptr_next; reg [2:0] frame_ptr_reg = 3'd0, frame_ptr_next;
reg [1:0] port_sel_reg = 0, port_sel_next; reg [1:0] port_sel_reg = 2'd0, port_sel_next;
reg busy_reg = 0, busy_next; reg busy_reg = 1'b0, busy_next;
reg [7:0] input_tdata; reg [7:0] input_tdata;
reg input_tvalid; reg input_tvalid;
reg input_tlast; reg input_tlast;
reg input_tuser; reg input_tuser;
reg output_tuser_reg = 0, output_tuser_next; reg output_tuser_reg = 1'b0, output_tuser_next;
reg input_0_axis_tready_reg = 0, input_0_axis_tready_next; reg input_0_axis_tready_reg = 1'b0, input_0_axis_tready_next;
reg input_1_axis_tready_reg = 0, input_1_axis_tready_next; reg input_1_axis_tready_reg = 1'b0, input_1_axis_tready_next;
reg input_2_axis_tready_reg = 0, input_2_axis_tready_next; reg input_2_axis_tready_reg = 1'b0, input_2_axis_tready_next;
reg input_3_axis_tready_reg = 0, input_3_axis_tready_next; reg input_3_axis_tready_reg = 1'b0, input_3_axis_tready_next;
// internal datapath // internal datapath
reg [7:0] output_axis_tdata_int; reg [7:0] output_axis_tdata_int;
reg output_axis_tvalid_int; reg output_axis_tvalid_int;
reg output_axis_tready_int = 0; reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int; reg output_axis_tlast_int;
reg output_axis_tuser_int; reg output_axis_tuser_int;
wire output_axis_tready_int_early; wire output_axis_tready_int_early;
@ -160,33 +160,33 @@ end
integer offset, i; integer offset, i;
always @* begin always @* begin
state_next = 2'bz; state_next = STATE_IDLE;
frame_ptr_next = frame_ptr_reg; frame_ptr_next = frame_ptr_reg;
port_sel_next = port_sel_reg; port_sel_next = port_sel_reg;
input_0_axis_tready_next = 0; input_0_axis_tready_next = 1'b0;
input_1_axis_tready_next = 0; input_1_axis_tready_next = 1'b0;
input_2_axis_tready_next = 0; input_2_axis_tready_next = 1'b0;
input_3_axis_tready_next = 0; input_3_axis_tready_next = 1'b0;
output_axis_tdata_int = 0; output_axis_tdata_int = 8'd0;
output_axis_tvalid_int = 0; output_axis_tvalid_int = 1'b0;
output_axis_tlast_int = 0; output_axis_tlast_int = 1'b0;
output_axis_tuser_int = 0; output_axis_tuser_int = 1'b0;
output_tuser_next = output_tuser_reg; output_tuser_next = output_tuser_reg;
case (state_reg) case (state_reg)
STATE_IDLE: begin STATE_IDLE: begin
// idle state - wait for data // idle state - wait for data
frame_ptr_next = 0; frame_ptr_next = 3'd0;
port_sel_next = 0; port_sel_next = 2'd0;
output_tuser_next = 0; output_tuser_next = 1'b0;
if (TAG_ENABLE) begin if (TAG_ENABLE) begin
// next cycle if started will send tag, so do not enable input // next cycle if started will send tag, so do not enable input
input_0_axis_tready_next = 0; input_0_axis_tready_next = 1'b0;
end else begin end else begin
// next cycle if started will send data, so enable input // next cycle if started will send data, so enable input
input_0_axis_tready_next = output_axis_tready_int_early; input_0_axis_tready_next = output_axis_tready_int_early;
@ -196,19 +196,19 @@ always @* begin
// input 0 valid; start transferring data // input 0 valid; start transferring data
if (TAG_ENABLE) begin if (TAG_ENABLE) begin
// tag enabled, so transmit it // tag enabled, so transmit it
if (output_axis_tready_int) begin if (output_axis_tready_int_reg) begin
// output is ready, so short-circuit first tag byte // output is ready, so short-circuit first tag byte
frame_ptr_next = 1; frame_ptr_next = 3'd1;
output_axis_tdata_int = tag[(TAG_BYTE_WIDTH-1)*8 +: 8]; output_axis_tdata_int = tag[(TAG_BYTE_WIDTH-1)*8 +: 8];
output_axis_tvalid_int = 1; output_axis_tvalid_int = 1'b1;
end end
state_next = STATE_WRITE_TAG; state_next = STATE_WRITE_TAG;
end else begin end else begin
// tag disabled, so transmit data // tag disabled, so transmit data
if (output_axis_tready_int) begin if (output_axis_tready_int_reg) begin
// output is ready, so short-circuit first data byte // output is ready, so short-circuit first data byte
output_axis_tdata_int = input_0_axis_tdata; output_axis_tdata_int = input_0_axis_tdata;
output_axis_tvalid_int = 1; output_axis_tvalid_int = 1'b1;
end end
state_next = STATE_TRANSFER; state_next = STATE_TRANSFER;
end end
@ -218,11 +218,11 @@ always @* begin
end end
STATE_WRITE_TAG: begin STATE_WRITE_TAG: begin
// write tag data // write tag data
if (output_axis_tready_int) begin if (output_axis_tready_int_reg) begin
// output ready, so send tag byte // output ready, so send tag byte
state_next = STATE_WRITE_TAG; state_next = STATE_WRITE_TAG;
frame_ptr_next = frame_ptr_reg + 1; frame_ptr_next = frame_ptr_reg + 1;
output_axis_tvalid_int = 1; output_axis_tvalid_int = 1'b1;
offset = 0; offset = 0;
if (TAG_ENABLE) begin if (TAG_ENABLE) begin
@ -252,7 +252,7 @@ always @* begin
2'd3: input_3_axis_tready_next = output_axis_tready_int_early; 2'd3: input_3_axis_tready_next = output_axis_tready_int_early;
endcase endcase
if (input_tvalid & output_axis_tready_int) begin if (input_tvalid & output_axis_tready_int_reg) begin
// output ready, transfer byte // output ready, transfer byte
state_next = STATE_TRANSFER; state_next = STATE_TRANSFER;
output_axis_tdata_int = input_tdata; output_axis_tdata_int = input_tdata;
@ -264,14 +264,14 @@ always @* begin
// save tuser - assert tuser out if ANY tuser asserts received // save tuser - assert tuser out if ANY tuser asserts received
output_tuser_next = output_tuser_next | input_tuser; output_tuser_next = output_tuser_next | input_tuser;
// disable input // disable input
input_0_axis_tready_next = 0; input_0_axis_tready_next = 1'b0;
input_1_axis_tready_next = 0; input_1_axis_tready_next = 1'b0;
input_2_axis_tready_next = 0; input_2_axis_tready_next = 1'b0;
input_3_axis_tready_next = 0; input_3_axis_tready_next = 1'b0;
if (port_sel_reg == 3) begin if (port_sel_reg == 2'd3) begin
// last port - send tlast and tuser and revert to idle // last port - send tlast and tuser and revert to idle
output_axis_tlast_int = 1; output_axis_tlast_int = 1'b1;
output_axis_tuser_int = output_tuser_next; output_axis_tuser_int = output_tuser_next;
state_next = STATE_IDLE; state_next = STATE_IDLE;
end else begin end else begin
@ -294,14 +294,14 @@ end
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
state_reg <= STATE_IDLE; state_reg <= STATE_IDLE;
frame_ptr_reg <= 0; frame_ptr_reg <= 3'd0;
port_sel_reg <= 0; port_sel_reg <= 2'd0;
input_0_axis_tready_reg <= 0; input_0_axis_tready_reg <= 1'b0;
input_1_axis_tready_reg <= 0; input_1_axis_tready_reg <= 1'b0;
input_2_axis_tready_reg <= 0; input_2_axis_tready_reg <= 1'b0;
input_3_axis_tready_reg <= 0; input_3_axis_tready_reg <= 1'b0;
output_tuser_reg <= 0; output_tuser_reg <= 1'b0;
busy_reg <= 0; busy_reg <= 1'b0;
end else begin end else begin
state_reg <= state_next; state_reg <= state_next;
@ -321,65 +321,83 @@ always @(posedge clk) begin
end end
// output datapath logic // output datapath logic
reg [7:0] output_axis_tdata_reg = 0; reg [7:0] output_axis_tdata_reg = 8'd0;
reg output_axis_tvalid_reg = 0; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 0; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 0; reg output_axis_tuser_reg = 1'b0;
reg [7:0] temp_axis_tdata_reg = 0; reg [7:0] temp_axis_tdata_reg = 8'd0;
reg temp_axis_tvalid_reg = 0; reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 0; reg temp_axis_tlast_reg = 1'b0;
reg temp_axis_tuser_reg = 0; reg temp_axis_tuser_reg = 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_tdata = output_axis_tdata_reg;
assign output_axis_tvalid = output_axis_tvalid_reg; assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg; assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg; assign output_axis_tuser = output_axis_tuser_reg;
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle // 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) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int); assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @(posedge clk) begin always @* begin
if (rst) begin
output_axis_tdata_reg <= 0;
output_axis_tvalid_reg <= 0;
output_axis_tlast_reg <= 0;
output_axis_tuser_reg <= 0;
output_axis_tready_int <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source // transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early; output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
if (output_axis_tready_int) begin 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 // input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output // output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int; output_axis_tvalid_next = output_axis_tvalid_int;
output_axis_tvalid_reg <= output_axis_tvalid_int; store_axis_int_to_output = 1'b1;
output_axis_tlast_reg <= output_axis_tlast_int;
output_axis_tuser_reg <= output_axis_tuser_int;
end else begin end else begin
// output is not ready, store input in temp // output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int; temp_axis_tvalid_next = output_axis_tvalid_int;
temp_axis_tvalid_reg <= output_axis_tvalid_int; store_axis_int_to_temp = 1'b1;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end else if (output_axis_tready) begin end else if (output_axis_tready) begin
// input is not ready, but output is ready // 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_tlast_reg <= output_axis_tlast_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_tdata_reg <= temp_axis_tdata_reg;
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg; output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg; output_axis_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end end
if (store_axis_int_to_temp) begin
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end end

View File

@ -98,33 +98,33 @@ reg [2:0] state_reg = STATE_IDLE, state_next;
// datapath control signals // datapath control signals
reg store_last_word; reg store_last_word;
reg [15:0] frame_ptr_reg = 0, frame_ptr_next; reg [15:0] frame_ptr_reg = 16'd0, frame_ptr_next;
// frame length counters // frame length counters
reg [15:0] short_counter_reg = 0, short_counter_next = 0; reg [15:0] short_counter_reg = 16'd0, short_counter_next = 16'd0;
reg [15:0] long_counter_reg = 0, long_counter_next = 0; reg [15:0] long_counter_reg = 16'd0, long_counter_next = 16'd0;
reg [DATA_WIDTH-1:0] last_word_data_reg = 0; reg [DATA_WIDTH-1:0] last_word_data_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] last_word_keep_reg = 0; reg [KEEP_WIDTH-1:0] last_word_keep_reg = {KEEP_WIDTH{1'b0}};
reg last_cycle_tuser_reg = 0, last_cycle_tuser_next; reg last_cycle_tuser_reg = 1'b0, last_cycle_tuser_next;
reg status_valid_reg = 0, status_valid_next; reg status_valid_reg = 1'b0, status_valid_next;
reg status_frame_pad_reg = 0, status_frame_pad_next; reg status_frame_pad_reg = 1'b0, status_frame_pad_next;
reg status_frame_truncate_reg = 0, status_frame_truncate_next; reg status_frame_truncate_reg = 1'b0, status_frame_truncate_next;
reg [15:0] status_frame_length_reg = 0, status_frame_length_next; reg [15:0] status_frame_length_reg = 16'd0, status_frame_length_next;
reg [15:0] status_frame_original_length_reg = 0, status_frame_original_length_next; reg [15:0] status_frame_original_length_reg = 16'd0, status_frame_original_length_next;
// internal datapath // internal datapath
reg [DATA_WIDTH-1:0] output_axis_tdata_int; reg [DATA_WIDTH-1:0] output_axis_tdata_int;
reg [KEEP_WIDTH-1:0] output_axis_tkeep_int; reg [KEEP_WIDTH-1:0] output_axis_tkeep_int;
reg output_axis_tvalid_int; reg output_axis_tvalid_int;
reg output_axis_tready_int = 0; reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int; reg output_axis_tlast_int;
reg output_axis_tuser_int; reg output_axis_tuser_int;
wire output_axis_tready_int_early; wire output_axis_tready_int_early;
reg input_axis_tready_reg = 0, input_axis_tready_next; reg input_axis_tready_reg = 1'b0, input_axis_tready_next;
assign input_axis_tready = input_axis_tready_reg; assign input_axis_tready = input_axis_tready_reg;
assign status_valid = status_valid_reg; assign status_valid = status_valid_reg;
@ -138,20 +138,20 @@ integer i, word_cnt;
always @* begin always @* begin
state_next = STATE_IDLE; state_next = STATE_IDLE;
store_last_word = 0; store_last_word = 1'b0;
frame_ptr_next = frame_ptr_reg; frame_ptr_next = frame_ptr_reg;
short_counter_next = short_counter_reg; short_counter_next = short_counter_reg;
long_counter_next = long_counter_reg; long_counter_next = long_counter_reg;
output_axis_tdata_int = 0; output_axis_tdata_int = {DATA_WIDTH{1'b0}};
output_axis_tkeep_int = 0; output_axis_tkeep_int = {KEEP_WIDTH{1'b0}};
output_axis_tvalid_int = 0; output_axis_tvalid_int = 1'b0;
output_axis_tlast_int = 0; output_axis_tlast_int = 1'b0;
output_axis_tuser_int = 0; output_axis_tuser_int = 1'b0;
input_axis_tready_next = 0; input_axis_tready_next = 1'b0;
last_cycle_tuser_next = last_cycle_tuser_reg; last_cycle_tuser_next = last_cycle_tuser_reg;
@ -188,31 +188,31 @@ always @* begin
if (short_counter_reg > KEEP_WIDTH) begin if (short_counter_reg > KEEP_WIDTH) begin
short_counter_next = short_counter_reg - KEEP_WIDTH; short_counter_next = short_counter_reg - KEEP_WIDTH;
end else begin end else begin
short_counter_next = 0; short_counter_next = 16'd0;
end end
if (long_counter_reg > KEEP_WIDTH) begin if (long_counter_reg > KEEP_WIDTH) begin
long_counter_next = long_counter_reg - KEEP_WIDTH; long_counter_next = long_counter_reg - KEEP_WIDTH;
end else begin end else begin
long_counter_next = 0; long_counter_next = 16'd0;
end end
if (long_counter_reg <= word_cnt) begin if (long_counter_reg <= word_cnt) begin
output_axis_tkeep_int = ({KEEP_WIDTH{1'b1}}) >> (KEEP_WIDTH-long_counter_reg); output_axis_tkeep_int = ({KEEP_WIDTH{1'b1}}) >> (KEEP_WIDTH-long_counter_reg);
if (input_axis_tlast) begin if (input_axis_tlast) begin
status_valid_next = 1; status_valid_next = 1'b1;
status_frame_pad_next = 0; status_frame_pad_next = 1'b0;
status_frame_truncate_next = word_cnt > long_counter_reg; status_frame_truncate_next = word_cnt > long_counter_reg;
status_frame_length_next = length_max; status_frame_length_next = length_max;
status_frame_original_length_next = frame_ptr_reg+word_cnt; status_frame_original_length_next = frame_ptr_reg+word_cnt;
input_axis_tready_next = output_axis_tready_int_early & status_ready; input_axis_tready_next = output_axis_tready_int_early & status_ready;
frame_ptr_next = 0; frame_ptr_next = 16'd0;
short_counter_next = length_min; short_counter_next = length_min;
long_counter_next = length_max; long_counter_next = length_max;
state_next = STATE_IDLE; state_next = STATE_IDLE;
end else begin end else begin
output_axis_tvalid_int = 0; output_axis_tvalid_int = 1'b0;
store_last_word = 1; store_last_word = 1'b1;
state_next = STATE_TRUNCATE; state_next = STATE_TRUNCATE;
end end
end else begin end else begin
@ -221,32 +221,32 @@ always @* begin
if (short_counter_reg > word_cnt) begin if (short_counter_reg > word_cnt) begin
if (short_counter_reg > KEEP_WIDTH) begin if (short_counter_reg > KEEP_WIDTH) begin
frame_ptr_next = frame_ptr_reg + KEEP_WIDTH; frame_ptr_next = frame_ptr_reg + KEEP_WIDTH;
input_axis_tready_next = 0; input_axis_tready_next = 1'b0;
output_axis_tkeep_int = {KEEP_WIDTH{1'b1}}; output_axis_tkeep_int = {KEEP_WIDTH{1'b1}};
output_axis_tlast_int = 0; output_axis_tlast_int = 1'b0;
output_axis_tuser_int = 0; output_axis_tuser_int = 1'b0;
last_cycle_tuser_next = input_axis_tuser; last_cycle_tuser_next = input_axis_tuser;
state_next = STATE_PAD; state_next = STATE_PAD;
end else begin end else begin
status_valid_next = 1; status_valid_next = 1'b1;
status_frame_pad_next = 1; status_frame_pad_next = 1'b1;
status_frame_truncate_next = 0; status_frame_truncate_next = 1'b0;
status_frame_length_next = length_min; status_frame_length_next = length_min;
input_axis_tready_next = output_axis_tready_int_early & status_ready; input_axis_tready_next = output_axis_tready_int_early & status_ready;
output_axis_tkeep_int = ({KEEP_WIDTH{1'b1}}) >> (KEEP_WIDTH-(length_min - frame_ptr_reg)); output_axis_tkeep_int = ({KEEP_WIDTH{1'b1}}) >> (KEEP_WIDTH-(length_min - frame_ptr_reg));
frame_ptr_next = 0; frame_ptr_next = 16'd0;
short_counter_next = length_min; short_counter_next = length_min;
long_counter_next = length_max; long_counter_next = length_max;
state_next = STATE_IDLE; state_next = STATE_IDLE;
end end
end else begin end else begin
status_valid_next = 1; status_valid_next = 1'b1;
status_frame_pad_next = 0; status_frame_pad_next = 1'b0;
status_frame_truncate_next = 0; status_frame_truncate_next = 1'b0;
status_frame_length_next = frame_ptr_reg+word_cnt; status_frame_length_next = frame_ptr_reg+word_cnt;
status_frame_original_length_next = frame_ptr_reg+word_cnt; status_frame_original_length_next = frame_ptr_reg+word_cnt;
input_axis_tready_next = output_axis_tready_int_early & status_ready; input_axis_tready_next = output_axis_tready_int_early & status_ready;
frame_ptr_next = 0; frame_ptr_next = 16'd0;
short_counter_next = length_min; short_counter_next = length_min;
long_counter_next = length_max; long_counter_next = length_max;
state_next = STATE_IDLE; state_next = STATE_IDLE;
@ -282,31 +282,31 @@ always @* begin
if (short_counter_reg > KEEP_WIDTH) begin if (short_counter_reg > KEEP_WIDTH) begin
short_counter_next = short_counter_reg - KEEP_WIDTH; short_counter_next = short_counter_reg - KEEP_WIDTH;
end else begin end else begin
short_counter_next = 0; short_counter_next = 16'd0;
end end
if (long_counter_reg > KEEP_WIDTH) begin if (long_counter_reg > KEEP_WIDTH) begin
long_counter_next = long_counter_reg - KEEP_WIDTH; long_counter_next = long_counter_reg - KEEP_WIDTH;
end else begin end else begin
long_counter_next = 0; long_counter_next = 16'd0;
end end
if (long_counter_reg <= word_cnt) begin if (long_counter_reg <= word_cnt) begin
output_axis_tkeep_int = ({KEEP_WIDTH{1'b1}}) >> (KEEP_WIDTH-long_counter_reg); output_axis_tkeep_int = ({KEEP_WIDTH{1'b1}}) >> (KEEP_WIDTH-long_counter_reg);
if (input_axis_tlast) begin if (input_axis_tlast) begin
status_valid_next = 1; status_valid_next = 1'b1;
status_frame_pad_next = 0; status_frame_pad_next = 1'b0;
status_frame_truncate_next = word_cnt > long_counter_reg; status_frame_truncate_next = word_cnt > long_counter_reg;
status_frame_length_next = length_max; status_frame_length_next = length_max;
status_frame_original_length_next = frame_ptr_reg+word_cnt; status_frame_original_length_next = frame_ptr_reg+word_cnt;
input_axis_tready_next = output_axis_tready_int_early & status_ready; input_axis_tready_next = output_axis_tready_int_early & status_ready;
frame_ptr_next = 0; frame_ptr_next = 16'd0;
short_counter_next = length_min; short_counter_next = length_min;
long_counter_next = length_max; long_counter_next = length_max;
state_next = STATE_IDLE; state_next = STATE_IDLE;
end else begin end else begin
output_axis_tvalid_int = 0; output_axis_tvalid_int = 1'b0;
store_last_word = 1; store_last_word = 1'b1;
state_next = STATE_TRUNCATE; state_next = STATE_TRUNCATE;
end end
end else begin end else begin
@ -315,32 +315,32 @@ always @* begin
if (short_counter_reg > word_cnt) begin if (short_counter_reg > word_cnt) begin
if (short_counter_reg > KEEP_WIDTH) begin if (short_counter_reg > KEEP_WIDTH) begin
frame_ptr_next = frame_ptr_reg + KEEP_WIDTH; frame_ptr_next = frame_ptr_reg + KEEP_WIDTH;
input_axis_tready_next = 0; input_axis_tready_next = 1'b0;
output_axis_tkeep_int = {KEEP_WIDTH{1'b1}}; output_axis_tkeep_int = {KEEP_WIDTH{1'b1}};
output_axis_tlast_int = 0; output_axis_tlast_int = 1'b0;
output_axis_tuser_int = 0; output_axis_tuser_int = 1'b0;
last_cycle_tuser_next = input_axis_tuser; last_cycle_tuser_next = input_axis_tuser;
state_next = STATE_PAD; state_next = STATE_PAD;
end else begin end else begin
status_valid_next = 1; status_valid_next = 1'b1;
status_frame_pad_next = 1; status_frame_pad_next = 1'b1;
status_frame_truncate_next = 0; status_frame_truncate_next = 1'b0;
status_frame_length_next = length_min; status_frame_length_next = length_min;
input_axis_tready_next = output_axis_tready_int_early & status_ready; input_axis_tready_next = output_axis_tready_int_early & status_ready;
output_axis_tkeep_int = ({KEEP_WIDTH{1'b1}}) >> (KEEP_WIDTH-short_counter_reg); output_axis_tkeep_int = ({KEEP_WIDTH{1'b1}}) >> (KEEP_WIDTH-short_counter_reg);
frame_ptr_next = 0; frame_ptr_next = 16'd0;
short_counter_next = length_min; short_counter_next = length_min;
long_counter_next = length_max; long_counter_next = length_max;
state_next = STATE_IDLE; state_next = STATE_IDLE;
end end
end else begin end else begin
status_valid_next = 1; status_valid_next = 1'b1;
status_frame_pad_next = 0; status_frame_pad_next = 1'b0;
status_frame_truncate_next = 0; status_frame_truncate_next = 1'b0;
status_frame_length_next = frame_ptr_reg+word_cnt; status_frame_length_next = frame_ptr_reg+word_cnt;
status_frame_original_length_next = frame_ptr_reg+word_cnt; status_frame_original_length_next = frame_ptr_reg+word_cnt;
input_axis_tready_next = output_axis_tready_int_early & status_ready; input_axis_tready_next = output_axis_tready_int_early & status_ready;
frame_ptr_next = 0; frame_ptr_next = 16'd0;
short_counter_next = length_min; short_counter_next = length_min;
long_counter_next = length_max; long_counter_next = length_max;
state_next = STATE_IDLE; state_next = STATE_IDLE;
@ -355,39 +355,39 @@ always @* begin
end end
STATE_PAD: begin STATE_PAD: begin
// pad to minimum length // pad to minimum length
input_axis_tready_next = 0; input_axis_tready_next = 1'b0;
output_axis_tdata_int = 0; output_axis_tdata_int = {DATA_WIDTH{1'b0}};
output_axis_tkeep_int = {KEEP_WIDTH{1'b1}}; output_axis_tkeep_int = {KEEP_WIDTH{1'b1}};
output_axis_tvalid_int = 1; output_axis_tvalid_int = 1'b1;
output_axis_tlast_int = 0; output_axis_tlast_int = 1'b0;
output_axis_tuser_int = 0; output_axis_tuser_int = 1'b0;
if (output_axis_tready_int) begin if (output_axis_tready_int_reg) begin
frame_ptr_next = frame_ptr_reg + KEEP_WIDTH; frame_ptr_next = frame_ptr_reg + KEEP_WIDTH;
if (short_counter_reg > KEEP_WIDTH) begin if (short_counter_reg > KEEP_WIDTH) begin
short_counter_next = short_counter_reg - KEEP_WIDTH; short_counter_next = short_counter_reg - KEEP_WIDTH;
end else begin end else begin
short_counter_next = 0; short_counter_next = 16'd0;
end end
if (long_counter_reg > KEEP_WIDTH) begin if (long_counter_reg > KEEP_WIDTH) begin
long_counter_next = long_counter_reg - KEEP_WIDTH; long_counter_next = long_counter_reg - KEEP_WIDTH;
end else begin end else begin
long_counter_next = 0; long_counter_next = 16'd0;
end end
if (short_counter_reg <= KEEP_WIDTH) begin if (short_counter_reg <= KEEP_WIDTH) begin
status_valid_next = 1; status_valid_next = 1'b1;
status_frame_pad_next = 1; status_frame_pad_next = 1'b1;
status_frame_truncate_next = 0; status_frame_truncate_next = 1'b0;
status_frame_length_next = length_min; status_frame_length_next = length_min;
input_axis_tready_next = output_axis_tready_int_early & status_ready; input_axis_tready_next = output_axis_tready_int_early & status_ready;
output_axis_tkeep_int = ({KEEP_WIDTH{1'b1}}) >> (KEEP_WIDTH-short_counter_reg); output_axis_tkeep_int = ({KEEP_WIDTH{1'b1}}) >> (KEEP_WIDTH-short_counter_reg);
output_axis_tlast_int = 1; output_axis_tlast_int = 1'b1;
output_axis_tuser_int = last_cycle_tuser_reg; output_axis_tuser_int = last_cycle_tuser_reg;
frame_ptr_next = 0; frame_ptr_next = 16'd0;
short_counter_next = length_min; short_counter_next = length_min;
long_counter_next = length_max; long_counter_next = length_max;
state_next = STATE_IDLE; state_next = STATE_IDLE;
@ -417,13 +417,13 @@ always @* begin
frame_ptr_next = frame_ptr_reg+KEEP_WIDTH; frame_ptr_next = frame_ptr_reg+KEEP_WIDTH;
if (input_axis_tlast) begin if (input_axis_tlast) begin
status_valid_next = 1; status_valid_next = 1'b1;
status_frame_pad_next = 0; status_frame_pad_next = 1'b0;
status_frame_truncate_next = 1; status_frame_truncate_next = 1'b1;
status_frame_length_next = length_max; status_frame_length_next = length_max;
status_frame_original_length_next = frame_ptr_reg+word_cnt; status_frame_original_length_next = frame_ptr_reg+word_cnt;
input_axis_tready_next = output_axis_tready_int_early & status_ready; input_axis_tready_next = output_axis_tready_int_early & status_ready;
frame_ptr_next = 0; frame_ptr_next = 16'd0;
short_counter_next = length_min; short_counter_next = length_min;
long_counter_next = length_max; long_counter_next = length_max;
state_next = STATE_IDLE; state_next = STATE_IDLE;
@ -440,18 +440,11 @@ end
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
state_reg <= STATE_IDLE; state_reg <= STATE_IDLE;
frame_ptr_reg <= 0; frame_ptr_reg <= 16'd0;
short_counter_reg <= 0; short_counter_reg <= 16'd0;
long_counter_reg <= 0; long_counter_reg <= 16'd0;
input_axis_tready_reg <= 0; input_axis_tready_reg <= 1'b0;
last_word_data_reg <= 0; status_valid_reg <= 1'b0;
last_word_keep_reg <= 0;
last_cycle_tuser_reg <= 0;
status_valid_reg <= 0;
status_frame_pad_reg <= 0;
status_frame_truncate_reg <= 0;
status_frame_length_reg <= 0;
status_frame_original_length_reg <= 0;
end else begin end else begin
state_reg <= state_next; state_reg <= state_next;
@ -462,9 +455,11 @@ always @(posedge clk) begin
input_axis_tready_reg <= input_axis_tready_next; input_axis_tready_reg <= input_axis_tready_next;
status_valid_reg <= status_valid_next;
end
last_cycle_tuser_reg <= last_cycle_tuser_next; last_cycle_tuser_reg <= last_cycle_tuser_next;
status_valid_reg <= status_valid_next;
status_frame_pad_reg <= status_frame_pad_next; status_frame_pad_reg <= status_frame_pad_next;
status_frame_truncate_reg <= status_frame_truncate_next; status_frame_truncate_reg <= status_frame_truncate_next;
status_frame_length_reg <= status_frame_length_next; status_frame_length_reg <= status_frame_length_next;
@ -475,20 +470,24 @@ always @(posedge clk) begin
last_word_keep_reg <= output_axis_tkeep_int; last_word_keep_reg <= output_axis_tkeep_int;
end end
end end
end
// output datapath logic // output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 0; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 0; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 0; reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 0; reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 0; reg temp_axis_tlast_reg = 1'b0;
reg temp_axis_tuser_reg = 0; reg temp_axis_tuser_reg = 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_tdata = output_axis_tdata_reg;
assign output_axis_tkeep = output_axis_tkeep_reg; assign output_axis_tkeep = output_axis_tkeep_reg;
@ -496,56 +495,66 @@ assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg; assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg; assign output_axis_tuser = output_axis_tuser_reg;
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle // 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) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int); assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @(posedge clk) begin always @* begin
if (rst) begin
output_axis_tdata_reg <= 0;
output_axis_tkeep_reg <= 0;
output_axis_tvalid_reg <= 0;
output_axis_tlast_reg <= 0;
output_axis_tuser_reg <= 0;
output_axis_tready_int <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tkeep_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source // transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early; output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
if (output_axis_tready_int) begin 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 // input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output // output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int; output_axis_tvalid_next = output_axis_tvalid_int;
output_axis_tkeep_reg <= output_axis_tkeep_int; store_axis_int_to_output = 1'b1;
output_axis_tvalid_reg <= output_axis_tvalid_int;
output_axis_tlast_reg <= output_axis_tlast_int;
output_axis_tuser_reg <= output_axis_tuser_int;
end else begin end else begin
// output is not ready and currently valid, store input in temp // output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int; temp_axis_tvalid_next = output_axis_tvalid_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int; store_axis_int_to_temp = 1'b1;
temp_axis_tvalid_reg <= output_axis_tvalid_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end else if (output_axis_tready) begin end else if (output_axis_tready) begin
// input is not ready, but output is ready // 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_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_tdata_reg <= temp_axis_tdata_reg;
output_axis_tkeep_reg <= temp_axis_tkeep_reg; output_axis_tkeep_reg <= temp_axis_tkeep_reg;
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg; output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg; output_axis_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tkeep_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end 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_tuser_reg <= output_axis_tuser_int;
end end
end end

View File

@ -40,7 +40,7 @@ def generate(ports=4, name=None, output=None):
t = Template(u"""/* t = Template(u"""/*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -103,16 +103,16 @@ module {{name}} #
input wire [{{w-1}}:0] select input wire [{{w-1}}:0] select
); );
reg [{{w-1}}:0] select_reg = 0, select_next; reg [{{w-1}}:0] select_reg = {{w}}'d0, select_next;
reg frame_reg = 0, frame_next; reg frame_reg = 1'b0, frame_next;
{% for p in ports %} {% for p in ports %}
reg input_{{p}}_axis_tready_reg = 0, input_{{p}}_axis_tready_next; reg input_{{p}}_axis_tready_reg = 1'b0, input_{{p}}_axis_tready_next;
{%- endfor %} {%- endfor %}
// internal datapath // internal datapath
reg [DATA_WIDTH-1:0] output_axis_tdata_int; reg [DATA_WIDTH-1:0] output_axis_tdata_int;
reg output_axis_tvalid_int; reg output_axis_tvalid_int;
reg output_axis_tready_int = 0; reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int; reg output_axis_tlast_int;
reg output_axis_tuser_int; reg output_axis_tuser_int;
wire output_axis_tready_int_early; wire output_axis_tready_int_early;
@ -127,6 +127,7 @@ always @* begin
{%- for p in ports %} {%- for p in ports %}
{{w}}'d{{p}}: selected_input_tvalid = input_{{p}}_axis_tvalid; {{w}}'d{{p}}: selected_input_tvalid = input_{{p}}_axis_tvalid;
{%- endfor %} {%- endfor %}
default: selected_input_tvalid = 1'b0;
endcase endcase
end end
@ -147,6 +148,13 @@ always @* begin
current_input_tuser = input_{{p}}_axis_tuser; current_input_tuser = input_{{p}}_axis_tuser;
end end
{%- endfor %} {%- endfor %}
default: begin
current_input_tdata = {DATA_WIDTH{1'b0}};
current_input_tvalid = 1'b0;
current_input_tready = 1'b0;
current_input_tlast = 1'b0;
current_input_tuser = 1'b0;
end
endcase endcase
end end
@ -154,7 +162,7 @@ always @* begin
select_next = select_reg; select_next = select_reg;
frame_next = frame_reg; frame_next = frame_reg;
{% for p in ports %} {% for p in ports %}
input_{{p}}_axis_tready_next = 0; input_{{p}}_axis_tready_next = 1'b0;
{%- endfor %} {%- endfor %}
if (frame_reg) begin if (frame_reg) begin
@ -164,7 +172,7 @@ always @* begin
end end
end else if (enable & selected_input_tvalid) begin end else if (enable & selected_input_tvalid) begin
// start of frame, grab select value // start of frame, grab select value
frame_next = 1; frame_next = 1'b1;
select_next = select; select_next = select;
end end
@ -184,10 +192,10 @@ end
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
select_reg <= 0; select_reg <= {{w}}'d0;
frame_reg <= 0; frame_reg <= 1'b0;
{%- for p in ports %} {%- for p in ports %}
input_{{p}}_axis_tready_reg <= 0; input_{{p}}_axis_tready_reg <= 1'b0;
{%- endfor %} {%- endfor %}
end else begin end else begin
select_reg <= select_next; select_reg <= select_next;
@ -199,65 +207,83 @@ always @(posedge clk) begin
end end
// output datapath logic // output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 0; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 0; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 0; reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 0; reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 0; reg temp_axis_tlast_reg = 1'b0;
reg temp_axis_tuser_reg = 0; reg temp_axis_tuser_reg = 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_tdata = output_axis_tdata_reg;
assign output_axis_tvalid = output_axis_tvalid_reg; assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg; assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg; assign output_axis_tuser = output_axis_tuser_reg;
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle // 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) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int); assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @(posedge clk) begin always @* begin
if (rst) begin
output_axis_tdata_reg <= 0;
output_axis_tvalid_reg <= 0;
output_axis_tlast_reg <= 0;
output_axis_tuser_reg <= 0;
output_axis_tready_int <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source // transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early; output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
if (output_axis_tready_int) begin 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 // input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output // output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int; output_axis_tvalid_next = output_axis_tvalid_int;
output_axis_tvalid_reg <= output_axis_tvalid_int; store_axis_int_to_output = 1'b1;
output_axis_tlast_reg <= output_axis_tlast_int;
output_axis_tuser_reg <= output_axis_tuser_int;
end else begin end else begin
// output is not ready, store input in temp // output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int; temp_axis_tvalid_next = output_axis_tvalid_int;
temp_axis_tvalid_reg <= output_axis_tvalid_int; store_axis_int_to_temp = 1'b1;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end else if (output_axis_tready) begin end else if (output_axis_tready) begin
// input is not ready, but output is ready // 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_tlast_reg <= output_axis_tlast_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_tdata_reg <= temp_axis_tdata_reg;
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg; output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg; output_axis_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end end
if (store_axis_int_to_temp) begin
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end end

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -80,18 +80,18 @@ module axis_mux_4 #
input wire [1:0] select input wire [1:0] select
); );
reg [1:0] select_reg = 0, select_next; reg [1:0] select_reg = 2'd0, select_next;
reg frame_reg = 0, frame_next; reg frame_reg = 1'b0, frame_next;
reg input_0_axis_tready_reg = 0, input_0_axis_tready_next; reg input_0_axis_tready_reg = 1'b0, input_0_axis_tready_next;
reg input_1_axis_tready_reg = 0, input_1_axis_tready_next; reg input_1_axis_tready_reg = 1'b0, input_1_axis_tready_next;
reg input_2_axis_tready_reg = 0, input_2_axis_tready_next; reg input_2_axis_tready_reg = 1'b0, input_2_axis_tready_next;
reg input_3_axis_tready_reg = 0, input_3_axis_tready_next; reg input_3_axis_tready_reg = 1'b0, input_3_axis_tready_next;
// internal datapath // internal datapath
reg [DATA_WIDTH-1:0] output_axis_tdata_int; reg [DATA_WIDTH-1:0] output_axis_tdata_int;
reg output_axis_tvalid_int; reg output_axis_tvalid_int;
reg output_axis_tready_int = 0; reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int; reg output_axis_tlast_int;
reg output_axis_tuser_int; reg output_axis_tuser_int;
wire output_axis_tready_int_early; wire output_axis_tready_int_early;
@ -109,6 +109,7 @@ always @* begin
2'd1: selected_input_tvalid = input_1_axis_tvalid; 2'd1: selected_input_tvalid = input_1_axis_tvalid;
2'd2: selected_input_tvalid = input_2_axis_tvalid; 2'd2: selected_input_tvalid = input_2_axis_tvalid;
2'd3: selected_input_tvalid = input_3_axis_tvalid; 2'd3: selected_input_tvalid = input_3_axis_tvalid;
default: selected_input_tvalid = 1'b0;
endcase endcase
end end
@ -148,6 +149,13 @@ always @* begin
current_input_tlast = input_3_axis_tlast; current_input_tlast = input_3_axis_tlast;
current_input_tuser = input_3_axis_tuser; current_input_tuser = input_3_axis_tuser;
end end
default: begin
current_input_tdata = {DATA_WIDTH{1'b0}};
current_input_tvalid = 1'b0;
current_input_tready = 1'b0;
current_input_tlast = 1'b0;
current_input_tuser = 1'b0;
end
endcase endcase
end end
@ -155,10 +163,10 @@ always @* begin
select_next = select_reg; select_next = select_reg;
frame_next = frame_reg; frame_next = frame_reg;
input_0_axis_tready_next = 0; input_0_axis_tready_next = 1'b0;
input_1_axis_tready_next = 0; input_1_axis_tready_next = 1'b0;
input_2_axis_tready_next = 0; input_2_axis_tready_next = 1'b0;
input_3_axis_tready_next = 0; input_3_axis_tready_next = 1'b0;
if (frame_reg) begin if (frame_reg) begin
if (current_input_tvalid & current_input_tready) begin if (current_input_tvalid & current_input_tready) begin
@ -167,7 +175,7 @@ always @* begin
end end
end else if (enable & selected_input_tvalid) begin end else if (enable & selected_input_tvalid) begin
// start of frame, grab select value // start of frame, grab select value
frame_next = 1; frame_next = 1'b1;
select_next = select; select_next = select;
end end
@ -188,12 +196,12 @@ end
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
select_reg <= 0; select_reg <= 2'd0;
frame_reg <= 0; frame_reg <= 1'b0;
input_0_axis_tready_reg <= 0; input_0_axis_tready_reg <= 1'b0;
input_1_axis_tready_reg <= 0; input_1_axis_tready_reg <= 1'b0;
input_2_axis_tready_reg <= 0; input_2_axis_tready_reg <= 1'b0;
input_3_axis_tready_reg <= 0; input_3_axis_tready_reg <= 1'b0;
end else begin end else begin
select_reg <= select_next; select_reg <= select_next;
frame_reg <= frame_next; frame_reg <= frame_next;
@ -205,65 +213,83 @@ always @(posedge clk) begin
end end
// output datapath logic // output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 0; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 0; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 0; reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 0; reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 0; reg temp_axis_tlast_reg = 1'b0;
reg temp_axis_tuser_reg = 0; reg temp_axis_tuser_reg = 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_tdata = output_axis_tdata_reg;
assign output_axis_tvalid = output_axis_tvalid_reg; assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg; assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg; assign output_axis_tuser = output_axis_tuser_reg;
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle // 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) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int); assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @(posedge clk) begin always @* begin
if (rst) begin
output_axis_tdata_reg <= 0;
output_axis_tvalid_reg <= 0;
output_axis_tlast_reg <= 0;
output_axis_tuser_reg <= 0;
output_axis_tready_int <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source // transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early; output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
if (output_axis_tready_int) begin 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 // input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output // output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int; output_axis_tvalid_next = output_axis_tvalid_int;
output_axis_tvalid_reg <= output_axis_tvalid_int; store_axis_int_to_output = 1'b1;
output_axis_tlast_reg <= output_axis_tlast_int;
output_axis_tuser_reg <= output_axis_tuser_int;
end else begin end else begin
// output is not ready, store input in temp // output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int; temp_axis_tvalid_next = output_axis_tvalid_int;
temp_axis_tvalid_reg <= output_axis_tvalid_int; store_axis_int_to_temp = 1'b1;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end else if (output_axis_tready) begin end else if (output_axis_tready) begin
// input is not ready, but output is ready // 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_tlast_reg <= output_axis_tlast_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_tdata_reg <= temp_axis_tdata_reg;
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg; output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg; output_axis_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end end
if (store_axis_int_to_temp) begin
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end end

View File

@ -40,7 +40,7 @@ def generate(ports=4, name=None, output=None):
t = Template(u"""/* t = Template(u"""/*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -106,17 +106,17 @@ module {{name}} #
input wire [{{w-1}}:0] select input wire [{{w-1}}:0] select
); );
reg [{{w-1}}:0] select_reg = 0, select_next; reg [{{w-1}}:0] select_reg = {{w}}'d0, select_next;
reg frame_reg = 0, frame_next; reg frame_reg = 1'b0, frame_next;
{% for p in ports %} {% for p in ports %}
reg input_{{p}}_axis_tready_reg = 0, input_{{p}}_axis_tready_next; reg input_{{p}}_axis_tready_reg = 1'b0, input_{{p}}_axis_tready_next;
{%- endfor %} {%- endfor %}
// internal datapath // internal datapath
reg [DATA_WIDTH-1:0] output_axis_tdata_int; reg [DATA_WIDTH-1:0] output_axis_tdata_int;
reg [KEEP_WIDTH-1:0] output_axis_tkeep_int; reg [KEEP_WIDTH-1:0] output_axis_tkeep_int;
reg output_axis_tvalid_int; reg output_axis_tvalid_int;
reg output_axis_tready_int = 0; reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int; reg output_axis_tlast_int;
reg output_axis_tuser_int; reg output_axis_tuser_int;
wire output_axis_tready_int_early; wire output_axis_tready_int_early;
@ -131,6 +131,7 @@ always @* begin
{%- for p in ports %} {%- for p in ports %}
{{w}}'d{{p}}: selected_input_tvalid = input_{{p}}_axis_tvalid; {{w}}'d{{p}}: selected_input_tvalid = input_{{p}}_axis_tvalid;
{%- endfor %} {%- endfor %}
default: selected_input_tvalid = 1'b0;
endcase endcase
end end
@ -153,6 +154,14 @@ always @* begin
current_input_tuser = input_{{p}}_axis_tuser; current_input_tuser = input_{{p}}_axis_tuser;
end end
{%- endfor %} {%- endfor %}
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_tuser = 1'b0;
end
endcase endcase
end end
@ -160,7 +169,7 @@ always @* begin
select_next = select_reg; select_next = select_reg;
frame_next = frame_reg; frame_next = frame_reg;
{% for p in ports %} {% for p in ports %}
input_{{p}}_axis_tready_next = 0; input_{{p}}_axis_tready_next = 1'b0;
{%- endfor %} {%- endfor %}
if (frame_reg) begin if (frame_reg) begin
@ -170,7 +179,7 @@ always @* begin
end end
end else if (enable & selected_input_tvalid) begin end else if (enable & selected_input_tvalid) begin
// start of frame, grab select value // start of frame, grab select value
frame_next = 1; frame_next = 1'b1;
select_next = select; select_next = select;
end end
@ -191,10 +200,10 @@ end
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
select_reg <= 0; select_reg <= {{w}}'d0;
frame_reg <= 0; frame_reg <= 1'b0;
{%- for p in ports %} {%- for p in ports %}
input_{{p}}_axis_tready_reg <= 0; input_{{p}}_axis_tready_reg <= 1'b0;
{%- endfor %} {%- endfor %}
end else begin end else begin
select_reg <= select_next; select_reg <= select_next;
@ -206,17 +215,22 @@ always @(posedge clk) begin
end end
// output datapath logic // output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 0; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 0; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 0; reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 0; reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 0; reg temp_axis_tlast_reg = 1'b0;
reg temp_axis_tuser_reg = 0; reg temp_axis_tuser_reg = 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_tdata = output_axis_tdata_reg;
assign output_axis_tkeep = output_axis_tkeep_reg; assign output_axis_tkeep = output_axis_tkeep_reg;
@ -224,56 +238,66 @@ assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg; assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg; assign output_axis_tuser = output_axis_tuser_reg;
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle // 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) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int); assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @(posedge clk) begin always @* begin
if (rst) begin
output_axis_tdata_reg <= 0;
output_axis_tkeep_reg <= 0;
output_axis_tvalid_reg <= 0;
output_axis_tlast_reg <= 0;
output_axis_tuser_reg <= 0;
output_axis_tready_int <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tkeep_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source // transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early; output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
if (output_axis_tready_int) begin 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 // input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output // output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int; output_axis_tvalid_next = output_axis_tvalid_int;
output_axis_tkeep_reg <= output_axis_tkeep_int; store_axis_int_to_output = 1'b1;
output_axis_tvalid_reg <= output_axis_tvalid_int;
output_axis_tlast_reg <= output_axis_tlast_int;
output_axis_tuser_reg <= output_axis_tuser_int;
end else begin end else begin
// output is not ready, store input in temp // output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int; temp_axis_tvalid_next = output_axis_tvalid_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int; store_axis_int_to_temp = 1'b1;
temp_axis_tvalid_reg <= output_axis_tvalid_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end else if (output_axis_tready) begin end else if (output_axis_tready) begin
// input is not ready, but output is ready // 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_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_tdata_reg <= temp_axis_tdata_reg;
output_axis_tkeep_reg <= temp_axis_tkeep_reg; output_axis_tkeep_reg <= temp_axis_tkeep_reg;
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg; output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg; output_axis_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tkeep_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end 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_tuser_reg <= output_axis_tuser_int;
end end
end end

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -86,19 +86,19 @@ module axis_mux_64_4 #
input wire [1:0] select input wire [1:0] select
); );
reg [1:0] select_reg = 0, select_next; reg [1:0] select_reg = 2'd0, select_next;
reg frame_reg = 0, frame_next; reg frame_reg = 1'b0, frame_next;
reg input_0_axis_tready_reg = 0, input_0_axis_tready_next; reg input_0_axis_tready_reg = 1'b0, input_0_axis_tready_next;
reg input_1_axis_tready_reg = 0, input_1_axis_tready_next; reg input_1_axis_tready_reg = 1'b0, input_1_axis_tready_next;
reg input_2_axis_tready_reg = 0, input_2_axis_tready_next; reg input_2_axis_tready_reg = 1'b0, input_2_axis_tready_next;
reg input_3_axis_tready_reg = 0, input_3_axis_tready_next; reg input_3_axis_tready_reg = 1'b0, input_3_axis_tready_next;
// internal datapath // internal datapath
reg [DATA_WIDTH-1:0] output_axis_tdata_int; reg [DATA_WIDTH-1:0] output_axis_tdata_int;
reg [KEEP_WIDTH-1:0] output_axis_tkeep_int; reg [KEEP_WIDTH-1:0] output_axis_tkeep_int;
reg output_axis_tvalid_int; reg output_axis_tvalid_int;
reg output_axis_tready_int = 0; reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int; reg output_axis_tlast_int;
reg output_axis_tuser_int; reg output_axis_tuser_int;
wire output_axis_tready_int_early; wire output_axis_tready_int_early;
@ -116,6 +116,7 @@ always @* begin
2'd1: selected_input_tvalid = input_1_axis_tvalid; 2'd1: selected_input_tvalid = input_1_axis_tvalid;
2'd2: selected_input_tvalid = input_2_axis_tvalid; 2'd2: selected_input_tvalid = input_2_axis_tvalid;
2'd3: selected_input_tvalid = input_3_axis_tvalid; 2'd3: selected_input_tvalid = input_3_axis_tvalid;
default: selected_input_tvalid = 1'b0;
endcase endcase
end end
@ -160,6 +161,14 @@ always @* begin
current_input_tlast = input_3_axis_tlast; current_input_tlast = input_3_axis_tlast;
current_input_tuser = input_3_axis_tuser; current_input_tuser = input_3_axis_tuser;
end end
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_tuser = 1'b0;
end
endcase endcase
end end
@ -167,10 +176,10 @@ always @* begin
select_next = select_reg; select_next = select_reg;
frame_next = frame_reg; frame_next = frame_reg;
input_0_axis_tready_next = 0; input_0_axis_tready_next = 1'b0;
input_1_axis_tready_next = 0; input_1_axis_tready_next = 1'b0;
input_2_axis_tready_next = 0; input_2_axis_tready_next = 1'b0;
input_3_axis_tready_next = 0; input_3_axis_tready_next = 1'b0;
if (frame_reg) begin if (frame_reg) begin
if (current_input_tvalid & current_input_tready) begin if (current_input_tvalid & current_input_tready) begin
@ -179,7 +188,7 @@ always @* begin
end end
end else if (enable & selected_input_tvalid) begin end else if (enable & selected_input_tvalid) begin
// start of frame, grab select value // start of frame, grab select value
frame_next = 1; frame_next = 1'b1;
select_next = select; select_next = select;
end end
@ -201,12 +210,12 @@ end
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
select_reg <= 0; select_reg <= 2'd0;
frame_reg <= 0; frame_reg <= 1'b0;
input_0_axis_tready_reg <= 0; input_0_axis_tready_reg <= 1'b0;
input_1_axis_tready_reg <= 0; input_1_axis_tready_reg <= 1'b0;
input_2_axis_tready_reg <= 0; input_2_axis_tready_reg <= 1'b0;
input_3_axis_tready_reg <= 0; input_3_axis_tready_reg <= 1'b0;
end else begin end else begin
select_reg <= select_next; select_reg <= select_next;
frame_reg <= frame_next; frame_reg <= frame_next;
@ -218,17 +227,22 @@ always @(posedge clk) begin
end end
// output datapath logic // output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 0; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 0; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 0; reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 0; reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 0; reg temp_axis_tlast_reg = 1'b0;
reg temp_axis_tuser_reg = 0; reg temp_axis_tuser_reg = 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_tdata = output_axis_tdata_reg;
assign output_axis_tkeep = output_axis_tkeep_reg; assign output_axis_tkeep = output_axis_tkeep_reg;
@ -236,56 +250,66 @@ assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg; assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg; assign output_axis_tuser = output_axis_tuser_reg;
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle // 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) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int); assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @(posedge clk) begin always @* begin
if (rst) begin
output_axis_tdata_reg <= 0;
output_axis_tkeep_reg <= 0;
output_axis_tvalid_reg <= 0;
output_axis_tlast_reg <= 0;
output_axis_tuser_reg <= 0;
output_axis_tready_int <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tkeep_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source // transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early; output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
if (output_axis_tready_int) begin 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 // input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output // output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int; output_axis_tvalid_next = output_axis_tvalid_int;
output_axis_tkeep_reg <= output_axis_tkeep_int; store_axis_int_to_output = 1'b1;
output_axis_tvalid_reg <= output_axis_tvalid_int;
output_axis_tlast_reg <= output_axis_tlast_int;
output_axis_tuser_reg <= output_axis_tuser_int;
end else begin end else begin
// output is not ready, store input in temp // output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int; temp_axis_tvalid_next = output_axis_tvalid_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int; store_axis_int_to_temp = 1'b1;
temp_axis_tvalid_reg <= output_axis_tvalid_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end else if (output_axis_tready) begin end else if (output_axis_tready) begin
// input is not ready, but output is ready // 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_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_tdata_reg <= temp_axis_tdata_reg;
output_axis_tkeep_reg <= temp_axis_tkeep_reg; output_axis_tkeep_reg <= temp_axis_tkeep_reg;
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg; output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg; output_axis_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tkeep_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end 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_tuser_reg <= output_axis_tuser_int;
end end
end end

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -66,21 +66,22 @@ module axis_rate_limit #
// internal datapath // internal datapath
reg [DATA_WIDTH-1:0] output_axis_tdata_int; reg [DATA_WIDTH-1:0] output_axis_tdata_int;
reg output_axis_tvalid_int; reg output_axis_tvalid_int;
reg output_axis_tready_int = 0; reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int; reg output_axis_tlast_int;
reg output_axis_tuser_int; reg output_axis_tuser_int;
wire output_axis_tready_int_early; wire output_axis_tready_int_early;
reg [23:0] acc_reg = 0, acc_next; reg [23:0] acc_reg = 24'd0, acc_next;
reg pause; reg pause;
reg frame_reg = 0, frame_next; reg frame_reg = 1'b0, frame_next;
reg input_axis_tready_reg = 1'b0, input_axis_tready_next;
reg input_axis_tready_reg = 0, input_axis_tready_next;
assign input_axis_tready = input_axis_tready_reg; assign input_axis_tready = input_axis_tready_reg;
always @* begin always @* begin
acc_next = acc_reg; acc_next = acc_reg;
pause = 0; pause = 1'b0;
frame_next = frame_reg; frame_next = frame_reg;
if (acc_reg >= rate_num) begin if (acc_reg >= rate_num) begin
@ -97,7 +98,7 @@ always @* begin
if (rate_by_frame) begin if (rate_by_frame) begin
pause = ~frame_next; pause = ~frame_next;
end else begin end else begin
pause = 1; pause = 1'b1;
end end
end end
@ -111,9 +112,9 @@ end
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
acc_reg <= 0; acc_reg <= 24'd0;
frame_reg <= 0; frame_reg <= 1'b0;
input_axis_tready_reg <= 0; input_axis_tready_reg <= 1'b0;
end else begin end else begin
acc_reg <= acc_next; acc_reg <= acc_next;
frame_reg <= frame_next; frame_reg <= frame_next;
@ -122,65 +123,83 @@ always @(posedge clk) begin
end end
// output datapath logic // output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 0; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 0; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 0; reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 0; reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 0; reg temp_axis_tlast_reg = 1'b0;
reg temp_axis_tuser_reg = 0; reg temp_axis_tuser_reg = 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_tdata = output_axis_tdata_reg;
assign output_axis_tvalid = output_axis_tvalid_reg; assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg; assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg; assign output_axis_tuser = output_axis_tuser_reg;
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle // 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) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int); assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @(posedge clk) begin always @* begin
if (rst) begin
output_axis_tdata_reg <= 0;
output_axis_tvalid_reg <= 0;
output_axis_tlast_reg <= 0;
output_axis_tuser_reg <= 0;
output_axis_tready_int <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source // transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early; output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
if (output_axis_tready_int) begin 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 // input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output // output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int; output_axis_tvalid_next = output_axis_tvalid_int;
output_axis_tvalid_reg <= output_axis_tvalid_int; store_axis_int_to_output = 1'b1;
output_axis_tlast_reg <= output_axis_tlast_int;
output_axis_tuser_reg <= output_axis_tuser_int;
end else begin end else begin
// output is not ready, store input in temp // output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int; temp_axis_tvalid_next = output_axis_tvalid_int;
temp_axis_tvalid_reg <= output_axis_tvalid_int; store_axis_int_to_temp = 1'b1;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end else if (output_axis_tready) begin end else if (output_axis_tready) begin
// input is not ready, but output is ready // 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_tlast_reg <= output_axis_tlast_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_tdata_reg <= temp_axis_tdata_reg;
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg; output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg; output_axis_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end end
if (store_axis_int_to_temp) begin
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end end

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -70,21 +70,22 @@ module axis_rate_limit_64 #
reg [DATA_WIDTH-1:0] output_axis_tdata_int; reg [DATA_WIDTH-1:0] output_axis_tdata_int;
reg [KEEP_WIDTH-1:0] output_axis_tkeep_int; reg [KEEP_WIDTH-1:0] output_axis_tkeep_int;
reg output_axis_tvalid_int; reg output_axis_tvalid_int;
reg output_axis_tready_int = 0; reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int; reg output_axis_tlast_int;
reg output_axis_tuser_int; reg output_axis_tuser_int;
wire output_axis_tready_int_early; wire output_axis_tready_int_early;
reg [23:0] acc_reg = 0, acc_next; reg [23:0] acc_reg = 24'd0, acc_next;
reg pause; reg pause;
reg frame_reg = 0, frame_next; reg frame_reg = 1'b0, frame_next;
reg input_axis_tready_reg = 1'b0, input_axis_tready_next;
reg input_axis_tready_reg = 0, input_axis_tready_next;
assign input_axis_tready = input_axis_tready_reg; assign input_axis_tready = input_axis_tready_reg;
always @* begin always @* begin
acc_next = acc_reg; acc_next = acc_reg;
pause = 0; pause = 1'b0;
frame_next = frame_reg; frame_next = frame_reg;
if (acc_reg >= rate_num) begin if (acc_reg >= rate_num) begin
@ -101,7 +102,7 @@ always @* begin
if (rate_by_frame) begin if (rate_by_frame) begin
pause = ~frame_next; pause = ~frame_next;
end else begin end else begin
pause = 1; pause = 1'b1;
end end
end end
@ -116,9 +117,9 @@ end
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
acc_reg <= 0; acc_reg <= 24'd0;
frame_reg <= 0; frame_reg <= 1'b0;
input_axis_tready_reg <= 0; input_axis_tready_reg <= 1'b0;
end else begin end else begin
acc_reg <= acc_next; acc_reg <= acc_next;
frame_reg <= frame_next; frame_reg <= frame_next;
@ -127,17 +128,22 @@ always @(posedge clk) begin
end end
// output datapath logic // output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 0; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 0; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 0; reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 0; reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 0; reg temp_axis_tlast_reg = 1'b0;
reg temp_axis_tuser_reg = 0; reg temp_axis_tuser_reg = 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_tdata = output_axis_tdata_reg;
assign output_axis_tkeep = output_axis_tkeep_reg; assign output_axis_tkeep = output_axis_tkeep_reg;
@ -145,56 +151,66 @@ assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg; assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg; assign output_axis_tuser = output_axis_tuser_reg;
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle // 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) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int); assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @(posedge clk) begin always @* begin
if (rst) begin
output_axis_tdata_reg <= 0;
output_axis_tkeep_reg <= 0;
output_axis_tvalid_reg <= 0;
output_axis_tlast_reg <= 0;
output_axis_tuser_reg <= 0;
output_axis_tready_int <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tkeep_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source // transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early; output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
if (output_axis_tready_int) begin 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 // input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output // output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int; output_axis_tvalid_next = output_axis_tvalid_int;
output_axis_tkeep_reg <= output_axis_tkeep_int; store_axis_int_to_output = 1'b1;
output_axis_tvalid_reg <= output_axis_tvalid_int;
output_axis_tlast_reg <= output_axis_tlast_int;
output_axis_tuser_reg <= output_axis_tuser_int;
end else begin end else begin
// output is not ready, store input in temp // output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int; temp_axis_tvalid_next = output_axis_tvalid_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int; store_axis_int_to_temp = 1'b1;
temp_axis_tvalid_reg <= output_axis_tvalid_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end else if (output_axis_tready) begin end else if (output_axis_tready) begin
// input is not ready, but output is ready // 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_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_tdata_reg <= temp_axis_tdata_reg;
output_axis_tkeep_reg <= temp_axis_tkeep_reg; output_axis_tkeep_reg <= temp_axis_tkeep_reg;
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg; output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg; output_axis_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tkeep_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end 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_tuser_reg <= output_axis_tuser_int;
end end
end end

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -57,17 +57,22 @@ module axis_register #
); );
// datapath registers // datapath registers
reg input_axis_tready_reg = 0; reg input_axis_tready_reg = 1'b0;
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 0; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 0; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 0; reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 0; reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 0; reg temp_axis_tlast_reg = 1'b0;
reg temp_axis_tuser_reg = 0; reg temp_axis_tuser_reg = 1'b0;
// datapath control
reg store_axis_input_to_output;
reg store_axis_input_to_temp;
reg store_axis_temp_to_output;
assign input_axis_tready = input_axis_tready_reg; assign input_axis_tready = input_axis_tready_reg;
@ -76,48 +81,63 @@ assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg; assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg; assign output_axis_tuser = output_axis_tuser_reg;
always @(posedge clk) begin // 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)
if (rst) begin wire input_axis_tready_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~input_axis_tvalid));
input_axis_tready_reg <= 0;
output_axis_tdata_reg <= 0; always @* begin
output_axis_tvalid_reg <= 0;
output_axis_tlast_reg <= 0;
output_axis_tuser_reg <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source // transfer sink ready state to source
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle output_axis_tvalid_next = output_axis_tvalid_reg;
input_axis_tready_reg <= output_axis_tready | (~temp_axis_tvalid_reg & ~output_axis_tvalid_reg) | (~temp_axis_tvalid_reg & ~input_axis_tvalid); temp_axis_tvalid_next = temp_axis_tvalid_reg;
store_axis_input_to_output = 1'b0;
store_axis_input_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (input_axis_tready_reg) begin if (input_axis_tready_reg) begin
// input is ready // input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output // output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= input_axis_tdata; output_axis_tvalid_next = input_axis_tvalid;
output_axis_tvalid_reg <= input_axis_tvalid; store_axis_input_to_output = 1'b1;
output_axis_tlast_reg <= input_axis_tlast;
output_axis_tuser_reg <= input_axis_tuser;
end else begin end else begin
// output is not ready, store input in temp // output is not ready, store input in temp
temp_axis_tdata_reg <= input_axis_tdata; temp_axis_tvalid_next = input_axis_tvalid;
temp_axis_tvalid_reg <= input_axis_tvalid; store_axis_input_to_temp = 1'b1;
temp_axis_tlast_reg <= input_axis_tlast;
temp_axis_tuser_reg <= input_axis_tuser;
end end
end else if (output_axis_tready) begin end else if (output_axis_tready) begin
// input is not ready, but output is ready // 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
input_axis_tready_reg <= 1'b0;
output_axis_tvalid_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
input_axis_tready_reg <= input_axis_tready_early;
output_axis_tvalid_reg <= output_axis_tvalid_next;
temp_axis_tvalid_reg <= temp_axis_tvalid_next;
end
// datapath
if (store_axis_input_to_output) begin
output_axis_tdata_reg <= input_axis_tdata;
output_axis_tlast_reg <= input_axis_tlast;
output_axis_tuser_reg <= input_axis_tuser;
end else if (store_axis_temp_to_output) begin
output_axis_tdata_reg <= temp_axis_tdata_reg; output_axis_tdata_reg <= temp_axis_tdata_reg;
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg; output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg; output_axis_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end end
if (store_axis_input_to_temp) begin
temp_axis_tdata_reg <= input_axis_tdata;
temp_axis_tlast_reg <= input_axis_tlast;
temp_axis_tuser_reg <= input_axis_tuser;
end end
end end

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -60,19 +60,24 @@ module axis_register_64 #
); );
// datapath registers // datapath registers
reg input_axis_tready_reg = 0; reg input_axis_tready_reg = 1'b0;
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 0; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 0; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 0; reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 0; reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 0; reg temp_axis_tlast_reg = 1'b0;
reg temp_axis_tuser_reg = 0; reg temp_axis_tuser_reg = 1'b0;
// datapath control
reg store_axis_input_to_output;
reg store_axis_input_to_temp;
reg store_axis_temp_to_output;
assign input_axis_tready = input_axis_tready_reg; assign input_axis_tready = input_axis_tready_reg;
@ -82,54 +87,66 @@ assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg; assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg; assign output_axis_tuser = output_axis_tuser_reg;
always @(posedge clk) begin // 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)
if (rst) begin wire input_axis_tready_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~input_axis_tvalid));
input_axis_tready_reg <= 0;
output_axis_tdata_reg <= 0; always @* begin
output_axis_tkeep_reg <= 0;
output_axis_tvalid_reg <= 0;
output_axis_tlast_reg <= 0;
output_axis_tuser_reg <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tkeep_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source // transfer sink ready state to source
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle output_axis_tvalid_next = output_axis_tvalid_reg;
input_axis_tready_reg <= output_axis_tready | (~temp_axis_tvalid_reg & ~output_axis_tvalid_reg) | (~temp_axis_tvalid_reg & ~input_axis_tvalid); temp_axis_tvalid_next = temp_axis_tvalid_reg;
store_axis_input_to_output = 1'b0;
store_axis_input_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (input_axis_tready_reg) begin if (input_axis_tready_reg) begin
// input is ready // input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output // output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= input_axis_tdata; output_axis_tvalid_next = input_axis_tvalid;
output_axis_tkeep_reg <= input_axis_tkeep; store_axis_input_to_output = 1'b1;
output_axis_tvalid_reg <= input_axis_tvalid;
output_axis_tlast_reg <= input_axis_tlast;
output_axis_tuser_reg <= input_axis_tuser;
end else begin end else begin
// output is not ready, store input in temp // output is not ready, store input in temp
temp_axis_tdata_reg <= input_axis_tdata; temp_axis_tvalid_next = input_axis_tvalid;
temp_axis_tkeep_reg <= input_axis_tkeep; store_axis_input_to_temp = 1'b1;
temp_axis_tvalid_reg <= input_axis_tvalid;
temp_axis_tlast_reg <= input_axis_tlast;
temp_axis_tuser_reg <= input_axis_tuser;
end end
end else if (output_axis_tready) begin end else if (output_axis_tready) begin
// input is not ready, but output is ready // 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
input_axis_tready_reg <= 1'b0;
output_axis_tvalid_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
input_axis_tready_reg <= input_axis_tready_early;
output_axis_tvalid_reg <= output_axis_tvalid_next;
temp_axis_tvalid_reg <= temp_axis_tvalid_next;
end
// datapath
if (store_axis_input_to_output) begin
output_axis_tdata_reg <= input_axis_tdata;
output_axis_tkeep_reg <= input_axis_tkeep;
output_axis_tlast_reg <= input_axis_tlast;
output_axis_tuser_reg <= input_axis_tuser;
end else if (store_axis_temp_to_output) begin
output_axis_tdata_reg <= temp_axis_tdata_reg; output_axis_tdata_reg <= temp_axis_tdata_reg;
output_axis_tkeep_reg <= temp_axis_tkeep_reg; output_axis_tkeep_reg <= temp_axis_tkeep_reg;
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg; output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg; output_axis_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tkeep_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end end
if (store_axis_input_to_temp) begin
temp_axis_tdata_reg <= input_axis_tdata;
temp_axis_tkeep_reg <= input_axis_tkeep;
temp_axis_tlast_reg <= input_axis_tlast;
temp_axis_tuser_reg <= input_axis_tuser;
end end
end end

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2014 Alex Forencich Copyright (c) 2014-2015 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -91,7 +91,7 @@ reg [1:0] state_reg = STATE_IDLE, state_next;
reg [TICK_COUNT_WIDTH-1:0] tick_count_reg = 0, tick_count_next; reg [TICK_COUNT_WIDTH-1:0] tick_count_reg = 0, tick_count_next;
reg [BYTE_COUNT_WIDTH-1:0] byte_count_reg = 0, byte_count_next; reg [BYTE_COUNT_WIDTH-1:0] byte_count_reg = 0, byte_count_next;
reg [FRAME_COUNT_WIDTH-1:0] frame_count_reg = 0, frame_count_next; reg [FRAME_COUNT_WIDTH-1:0] frame_count_reg = 0, frame_count_next;
reg frame_reg = 0, frame_next; reg frame_reg = 1'b0, frame_next;
reg store_output; reg store_output;
reg [$clog2(TOTAL_LENGTH)-1:0] frame_ptr_reg = 0, frame_ptr_next; reg [$clog2(TOTAL_LENGTH)-1:0] frame_ptr_reg = 0, frame_ptr_next;
@ -100,12 +100,12 @@ reg [TICK_COUNT_WIDTH-1:0] tick_count_output_reg = 0;
reg [BYTE_COUNT_WIDTH-1:0] byte_count_output_reg = 0; reg [BYTE_COUNT_WIDTH-1:0] byte_count_output_reg = 0;
reg [FRAME_COUNT_WIDTH-1:0] frame_count_output_reg = 0; reg [FRAME_COUNT_WIDTH-1:0] frame_count_output_reg = 0;
reg busy_reg = 0; reg busy_reg = 1'b0;
// internal datapath // internal datapath
reg [7:0] output_axis_tdata_int; reg [7:0] output_axis_tdata_int;
reg output_axis_tvalid_int; reg output_axis_tvalid_int;
reg output_axis_tready_int = 0; reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int; reg output_axis_tlast_int;
reg output_axis_tuser_int; reg output_axis_tuser_int;
wire output_axis_tready_int_early; wire output_axis_tready_int_early;
@ -115,19 +115,19 @@ assign busy = busy_reg;
integer offset, i, bit_cnt; integer offset, i, bit_cnt;
always @* begin always @* begin
state_next = 2'bz; state_next = STATE_IDLE;
tick_count_next = tick_count_reg; tick_count_next = tick_count_reg;
byte_count_next = byte_count_reg; byte_count_next = byte_count_reg;
frame_count_next = frame_count_reg; frame_count_next = frame_count_reg;
frame_next = frame_reg; frame_next = frame_reg;
output_axis_tdata_int = 0; output_axis_tdata_int = 8'd0;
output_axis_tvalid_int = 0; output_axis_tvalid_int = 1'b0;
output_axis_tlast_int = 0; output_axis_tlast_int = 1'b0;
output_axis_tuser_int = 0; output_axis_tuser_int = 1'b0;
store_output = 0; store_output = 1'b0;
frame_ptr_next = frame_ptr_reg; frame_ptr_next = frame_ptr_reg;
@ -136,13 +136,13 @@ always @* begin
case (state_reg) case (state_reg)
STATE_IDLE: begin STATE_IDLE: begin
if (trigger) begin if (trigger) begin
store_output = 1; store_output = 1'b1;
tick_count_next = 0; tick_count_next = 0;
byte_count_next = 0; byte_count_next = 0;
frame_count_next = 0; frame_count_next = 0;
frame_ptr_next = 0; frame_ptr_next = 0;
if (output_axis_tready_int) begin if (output_axis_tready_int_reg) begin
frame_ptr_next = 1; frame_ptr_next = 1;
if (TAG_ENABLE) begin if (TAG_ENABLE) begin
output_axis_tdata_int = tag[(TAG_BYTE_WIDTH-1)*8 +: 8]; output_axis_tdata_int = tag[(TAG_BYTE_WIDTH-1)*8 +: 8];
@ -153,7 +153,7 @@ always @* begin
end else if (FRAME_COUNT_ENABLE) begin end else if (FRAME_COUNT_ENABLE) begin
output_axis_tdata_int = frame_count_reg[(FRAME_COUNT_BYTE_WIDTH-1)*8 +: 8]; output_axis_tdata_int = frame_count_reg[(FRAME_COUNT_BYTE_WIDTH-1)*8 +: 8];
end end
output_axis_tvalid_int = 1; output_axis_tvalid_int = 1'b1;
end end
state_next = STATE_OUTPUT_DATA; state_next = STATE_OUTPUT_DATA;
@ -162,10 +162,10 @@ always @* begin
end end
end end
STATE_OUTPUT_DATA: begin STATE_OUTPUT_DATA: begin
if (output_axis_tready_int) begin if (output_axis_tready_int_reg) begin
state_next = STATE_OUTPUT_DATA; state_next = STATE_OUTPUT_DATA;
frame_ptr_next = frame_ptr_reg + 1; frame_ptr_next = frame_ptr_reg + 1;
output_axis_tvalid_int = 1; output_axis_tvalid_int = 1'b1;
offset = 0; offset = 0;
if (TAG_ENABLE) begin if (TAG_ENABLE) begin
@ -201,7 +201,7 @@ always @* begin
end end
end end
if (frame_ptr_reg == offset-1) begin if (frame_ptr_reg == offset-1) begin
output_axis_tlast_int = 1; output_axis_tlast_int = 1'b1;
state_next = STATE_IDLE; state_next = STATE_IDLE;
end end
end else begin end else begin
@ -229,11 +229,11 @@ always @* begin
// count frames // count frames
if (monitor_axis_tlast) begin if (monitor_axis_tlast) begin
// end of frame // end of frame
frame_next = 0; frame_next = 1'b0;
end else if (~frame_reg) begin end else if (~frame_reg) begin
// first word after end of frame // first word after end of frame
frame_count_next = frame_count_next + 1; frame_count_next = frame_count_next + 1;
frame_next = 1; frame_next = 1'b1;
end end
end end
end end
@ -244,12 +244,9 @@ always @(posedge clk) begin
tick_count_reg <= 0; tick_count_reg <= 0;
byte_count_reg <= 0; byte_count_reg <= 0;
frame_count_reg <= 0; frame_count_reg <= 0;
frame_reg <= 0; frame_reg <= 1'b0;
frame_ptr_reg <= 0; frame_ptr_reg <= 0;
busy_reg <= 0; busy_reg <= 1'b0;
tick_count_output_reg <= 0;
byte_count_output_reg <= 0;
frame_count_output_reg <= 0;
end else begin end else begin
state_reg <= state_next; state_reg <= state_next;
tick_count_reg <= tick_count_next; tick_count_reg <= tick_count_next;
@ -260,74 +257,93 @@ always @(posedge clk) begin
busy_reg <= state_next != STATE_IDLE; busy_reg <= state_next != STATE_IDLE;
end
if (store_output) begin if (store_output) begin
tick_count_output_reg <= tick_count_reg; tick_count_output_reg <= tick_count_reg;
byte_count_output_reg <= byte_count_reg; byte_count_output_reg <= byte_count_reg;
frame_count_output_reg <= frame_count_reg; frame_count_output_reg <= frame_count_reg;
end end
end end
end
// output datapath logic // output datapath logic
reg [7:0] output_axis_tdata_reg = 0; reg [7:0] output_axis_tdata_reg = 8'd0;
reg output_axis_tvalid_reg = 0; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 0; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 0; reg output_axis_tuser_reg = 1'b0;
reg [7:0] temp_axis_tdata_reg = 0; reg [7:0] temp_axis_tdata_reg = 8'd0;
reg temp_axis_tvalid_reg = 0; reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 0; reg temp_axis_tlast_reg = 1'b0;
reg temp_axis_tuser_reg = 0; reg temp_axis_tuser_reg = 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_tdata = output_axis_tdata_reg;
assign output_axis_tvalid = output_axis_tvalid_reg; assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg; assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg; assign output_axis_tuser = output_axis_tuser_reg;
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle // 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) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int); assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @(posedge clk) begin always @* begin
if (rst) begin
output_axis_tdata_reg <= 0;
output_axis_tvalid_reg <= 0;
output_axis_tlast_reg <= 0;
output_axis_tuser_reg <= 0;
output_axis_tready_int <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source // transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early; output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
if (output_axis_tready_int) begin 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 // input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output // output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int; output_axis_tvalid_next = output_axis_tvalid_int;
output_axis_tvalid_reg <= output_axis_tvalid_int; store_axis_int_to_output = 1'b1;
output_axis_tlast_reg <= output_axis_tlast_int;
output_axis_tuser_reg <= output_axis_tuser_int;
end else begin end else begin
// output is not ready, store input in temp // output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int; temp_axis_tvalid_next = output_axis_tvalid_int;
temp_axis_tvalid_reg <= output_axis_tvalid_int; store_axis_int_to_temp = 1'b1;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end else if (output_axis_tready) begin end else if (output_axis_tready) begin
// input is not ready, but output is ready // 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_tlast_reg <= output_axis_tlast_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_tdata_reg <= temp_axis_tdata_reg;
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg; output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg; output_axis_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end end
if (store_axis_int_to_temp) begin
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end end

View File

@ -59,7 +59,7 @@ module axis_tap #
// internal datapath // internal datapath
reg [DATA_WIDTH-1:0] output_axis_tdata_int; reg [DATA_WIDTH-1:0] output_axis_tdata_int;
reg output_axis_tvalid_int; reg output_axis_tvalid_int;
reg output_axis_tready_int = 0; reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int; reg output_axis_tlast_int;
reg output_axis_tuser_int; reg output_axis_tuser_int;
wire output_axis_tready_int_early; wire output_axis_tready_int_early;
@ -72,17 +72,17 @@ localparam [1:0]
reg [1:0] state_reg = STATE_IDLE, state_next; reg [1:0] state_reg = STATE_IDLE, state_next;
reg frame_reg = 0, frame_next; reg frame_reg = 1'b0, frame_next;
always @* begin always @* begin
state_next = STATE_IDLE; state_next = STATE_IDLE;
frame_next = frame_reg; frame_next = frame_reg;
output_axis_tdata_int = 0; output_axis_tdata_int = {DATA_WIDTH{1'b0}};
output_axis_tvalid_int = 0; output_axis_tvalid_int = 1'b0;
output_axis_tlast_int = 0; output_axis_tlast_int = 1'b0;
output_axis_tuser_int = 0; output_axis_tuser_int = 1'b0;
if (tap_axis_tready & tap_axis_tvalid) begin if (tap_axis_tready & tap_axis_tvalid) begin
frame_next = ~tap_axis_tlast; frame_next = ~tap_axis_tlast;
@ -92,7 +92,7 @@ always @* begin
STATE_IDLE: begin STATE_IDLE: begin
if (tap_axis_tready & tap_axis_tvalid) begin if (tap_axis_tready & tap_axis_tvalid) begin
// start of frame // start of frame
if (output_axis_tready_int) begin if (output_axis_tready_int_reg) begin
output_axis_tdata_int = tap_axis_tdata; output_axis_tdata_int = tap_axis_tdata;
output_axis_tvalid_int = tap_axis_tvalid & tap_axis_tready; output_axis_tvalid_int = tap_axis_tvalid & tap_axis_tready;
output_axis_tlast_int = tap_axis_tlast; output_axis_tlast_int = tap_axis_tlast;
@ -112,7 +112,7 @@ always @* begin
STATE_TRANSFER: begin STATE_TRANSFER: begin
if (tap_axis_tready & tap_axis_tvalid) begin if (tap_axis_tready & tap_axis_tvalid) begin
// transfer data // transfer data
if (output_axis_tready_int) begin if (output_axis_tready_int_reg) begin
output_axis_tdata_int = tap_axis_tdata; output_axis_tdata_int = tap_axis_tdata;
output_axis_tvalid_int = tap_axis_tvalid & tap_axis_tready; output_axis_tvalid_int = tap_axis_tvalid & tap_axis_tready;
output_axis_tlast_int = tap_axis_tlast; output_axis_tlast_int = tap_axis_tlast;
@ -130,11 +130,11 @@ always @* begin
end end
end end
STATE_TRUNCATE: begin STATE_TRUNCATE: begin
if (output_axis_tready_int) begin if (output_axis_tready_int_reg) begin
output_axis_tdata_int = 0; output_axis_tdata_int = {DATA_WIDTH{1'b0}};
output_axis_tvalid_int = 1; output_axis_tvalid_int = 1'b1;
output_axis_tlast_int = 1; output_axis_tlast_int = 1'b1;
output_axis_tuser_int = 1; output_axis_tuser_int = 1'b1;
if (frame_next) begin if (frame_next) begin
state_next = STATE_WAIT; state_next = STATE_WAIT;
end else begin end else begin
@ -161,7 +161,7 @@ end
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
state_reg <= STATE_IDLE; state_reg <= STATE_IDLE;
frame_reg <= 0; frame_reg <= 1'b0;
end else begin end else begin
state_reg <= state_next; state_reg <= state_next;
frame_reg <= frame_next; frame_reg <= frame_next;
@ -169,65 +169,83 @@ always @(posedge clk) begin
end end
// output datapath logic // output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 0; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 0; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 0; reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 0; reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 0; reg temp_axis_tlast_reg = 1'b0;
reg temp_axis_tuser_reg = 0; reg temp_axis_tuser_reg = 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_tdata = output_axis_tdata_reg;
assign output_axis_tvalid = output_axis_tvalid_reg; assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg; assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg; assign output_axis_tuser = output_axis_tuser_reg;
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle // 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) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int); assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @(posedge clk) begin always @* begin
if (rst) begin
output_axis_tdata_reg <= 0;
output_axis_tvalid_reg <= 0;
output_axis_tlast_reg <= 0;
output_axis_tuser_reg <= 0;
output_axis_tready_int <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source // transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early; output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
if (output_axis_tready_int) begin 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 // input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output // output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int; output_axis_tvalid_next = output_axis_tvalid_int;
output_axis_tvalid_reg <= output_axis_tvalid_int; store_axis_int_to_output = 1'b1;
output_axis_tlast_reg <= output_axis_tlast_int;
output_axis_tuser_reg <= output_axis_tuser_int;
end else begin end else begin
// output is not ready, store input in temp // output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int; temp_axis_tvalid_next = output_axis_tvalid_int;
temp_axis_tvalid_reg <= output_axis_tvalid_int; store_axis_int_to_temp = 1'b1;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end else if (output_axis_tready) begin end else if (output_axis_tready) begin
// input is not ready, but output is ready // 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_tlast_reg <= output_axis_tlast_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_tdata_reg <= temp_axis_tdata_reg;
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg; output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg; output_axis_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end end
if (store_axis_int_to_temp) begin
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end end

View File

@ -63,7 +63,7 @@ module axis_tap_64 #
reg [DATA_WIDTH-1:0] output_axis_tdata_int; reg [DATA_WIDTH-1:0] output_axis_tdata_int;
reg [KEEP_WIDTH-1:0] output_axis_tkeep_int; reg [KEEP_WIDTH-1:0] output_axis_tkeep_int;
reg output_axis_tvalid_int; reg output_axis_tvalid_int;
reg output_axis_tready_int = 0; reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int; reg output_axis_tlast_int;
reg output_axis_tuser_int; reg output_axis_tuser_int;
wire output_axis_tready_int_early; wire output_axis_tready_int_early;
@ -76,18 +76,18 @@ localparam [1:0]
reg [1:0] state_reg = STATE_IDLE, state_next; reg [1:0] state_reg = STATE_IDLE, state_next;
reg frame_reg = 0, frame_next; reg frame_reg = 1'b0, frame_next;
always @* begin always @* begin
state_next = STATE_IDLE; state_next = STATE_IDLE;
frame_next = frame_reg; frame_next = frame_reg;
output_axis_tdata_int = 0; output_axis_tdata_int = {DATA_WIDTH{1'b0}};
output_axis_tkeep_int = 0; output_axis_tkeep_int = {KEEP_WIDTH{1'b0}};
output_axis_tvalid_int = 0; output_axis_tvalid_int = 1'b0;
output_axis_tlast_int = 0; output_axis_tlast_int = 1'b0;
output_axis_tuser_int = 0; output_axis_tuser_int = 1'b0;
if (tap_axis_tready & tap_axis_tvalid) begin if (tap_axis_tready & tap_axis_tvalid) begin
frame_next = ~tap_axis_tlast; frame_next = ~tap_axis_tlast;
@ -97,7 +97,7 @@ always @* begin
STATE_IDLE: begin STATE_IDLE: begin
if (tap_axis_tready & tap_axis_tvalid) begin if (tap_axis_tready & tap_axis_tvalid) begin
// start of frame // start of frame
if (output_axis_tready_int) begin if (output_axis_tready_int_reg) begin
output_axis_tdata_int = tap_axis_tdata; output_axis_tdata_int = tap_axis_tdata;
output_axis_tkeep_int = tap_axis_tkeep; output_axis_tkeep_int = tap_axis_tkeep;
output_axis_tvalid_int = tap_axis_tvalid & tap_axis_tready; output_axis_tvalid_int = tap_axis_tvalid & tap_axis_tready;
@ -118,7 +118,7 @@ always @* begin
STATE_TRANSFER: begin STATE_TRANSFER: begin
if (tap_axis_tready & tap_axis_tvalid) begin if (tap_axis_tready & tap_axis_tvalid) begin
// transfer data // transfer data
if (output_axis_tready_int) begin if (output_axis_tready_int_reg) begin
output_axis_tdata_int = tap_axis_tdata; output_axis_tdata_int = tap_axis_tdata;
output_axis_tkeep_int = tap_axis_tkeep; output_axis_tkeep_int = tap_axis_tkeep;
output_axis_tvalid_int = tap_axis_tvalid & tap_axis_tready; output_axis_tvalid_int = tap_axis_tvalid & tap_axis_tready;
@ -137,12 +137,12 @@ always @* begin
end end
end end
STATE_TRUNCATE: begin STATE_TRUNCATE: begin
if (output_axis_tready_int) begin if (output_axis_tready_int_reg) begin
output_axis_tdata_int = 0; output_axis_tdata_int = {DATA_WIDTH{1'b0}};
output_axis_tkeep_int = 1; output_axis_tkeep_int = {{KEEP_WIDTH-1{1'b0}}, 1'b1};
output_axis_tvalid_int = 1; output_axis_tvalid_int = 1'b1;
output_axis_tlast_int = 1; output_axis_tlast_int = 1'b1;
output_axis_tuser_int = 1; output_axis_tuser_int = 1'b1;
if (frame_next) begin if (frame_next) begin
state_next = STATE_WAIT; state_next = STATE_WAIT;
end else begin end else begin
@ -169,7 +169,7 @@ end
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
state_reg <= STATE_IDLE; state_reg <= STATE_IDLE;
frame_reg <= 0; frame_reg <= 1'b0;
end else begin end else begin
state_reg <= state_next; state_reg <= state_next;
frame_reg <= frame_next; frame_reg <= frame_next;
@ -177,17 +177,22 @@ always @(posedge clk) begin
end end
// output datapath logic // output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 0; reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 0; reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 0; reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0; reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0; reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 0; reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 0; reg temp_axis_tlast_reg = 1'b0;
reg temp_axis_tuser_reg = 0; reg temp_axis_tuser_reg = 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_tdata = output_axis_tdata_reg;
assign output_axis_tkeep = output_axis_tkeep_reg; assign output_axis_tkeep = output_axis_tkeep_reg;
@ -195,56 +200,66 @@ assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg; assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg; assign output_axis_tuser = output_axis_tuser_reg;
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle // 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) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int); assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @(posedge clk) begin always @* begin
if (rst) begin
output_axis_tdata_reg <= 0;
output_axis_tkeep_reg <= 0;
output_axis_tvalid_reg <= 0;
output_axis_tlast_reg <= 0;
output_axis_tuser_reg <= 0;
output_axis_tready_int <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tkeep_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source // transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early; output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
if (output_axis_tready_int) begin 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 // input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output // output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int; output_axis_tvalid_next = output_axis_tvalid_int;
output_axis_tkeep_reg <= output_axis_tkeep_int; store_axis_int_to_output = 1'b1;
output_axis_tvalid_reg <= output_axis_tvalid_int;
output_axis_tlast_reg <= output_axis_tlast_int;
output_axis_tuser_reg <= output_axis_tuser_int;
end else begin end else begin
// output is not ready, store input in temp // output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int; temp_axis_tvalid_next = output_axis_tvalid_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int; store_axis_int_to_temp = 1'b1;
temp_axis_tvalid_reg <= output_axis_tvalid_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end end
end else if (output_axis_tready) begin end else if (output_axis_tready) begin
// input is not ready, but output is ready // 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_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_tdata_reg <= temp_axis_tdata_reg;
output_axis_tkeep_reg <= temp_axis_tkeep_reg; output_axis_tkeep_reg <= temp_axis_tkeep_reg;
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg; output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg; output_axis_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tkeep_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end 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_tuser_reg <= output_axis_tuser_int;
end end
end end