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
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 [7:0] cycle_count_reg = 0, cycle_count_next;
reg [7:0] cycle_count_reg = 8'd0, cycle_count_next;
reg last_cycle;
reg [DATA_WIDTH-1:0] temp_tdata_reg = 0, temp_tdata_next;
reg [KEEP_WIDTH-1:0] temp_tkeep_reg = 0, temp_tkeep_next;
reg temp_tlast_reg = 0, temp_tlast_next;
reg temp_tuser_reg = 0, temp_tuser_next;
reg [DATA_WIDTH-1:0] temp_tdata_reg = {DATA_WIDTH{1'b0}}, temp_tdata_next;
reg [KEEP_WIDTH-1:0] temp_tkeep_reg = {KEEP_WIDTH{1'b0}}, temp_tkeep_next;
reg temp_tlast_reg = 1'b0, temp_tlast_next;
reg temp_tuser_reg = 1'b0, temp_tuser_next;
// internal datapath
reg [OUTPUT_DATA_WIDTH-1:0] output_axis_tdata_int;
reg [OUTPUT_KEEP_WIDTH-1:0] output_axis_tkeep_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_tuser_int;
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;
always @* begin
@ -132,13 +133,13 @@ always @* begin
temp_tlast_next = temp_tlast_reg;
temp_tuser_next = temp_tuser_reg;
output_axis_tdata_int = 0;
output_axis_tkeep_int = 0;
output_axis_tvalid_int = 0;
output_axis_tlast_int = 0;
output_axis_tuser_int = 0;
output_axis_tdata_int = {OUTPUT_DATA_WIDTH{1'b0}};
output_axis_tkeep_int = {OUTPUT_KEEP_WIDTH{1'b0}};
output_axis_tvalid_int = 1'b0;
output_axis_tlast_int = 1'b0;
output_axis_tuser_int = 1'b0;
input_axis_tready_next = 0;
input_axis_tready_next = 1'b0;
case (state_reg)
STATE_IDLE: begin
@ -161,7 +162,7 @@ always @* begin
// output bus is wider
// accept new data
input_axis_tready_next = 1;
input_axis_tready_next = 1'b1;
if (input_axis_tready & input_axis_tvalid) begin
// word transfer in - store it in data register
@ -173,15 +174,15 @@ always @* begin
temp_tuser_next = input_axis_tuser;
// first input cycle complete
cycle_count_next = 1;
cycle_count_next = 8'd1;
if (input_axis_tlast) begin
// 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;
end else begin
// otherwise, transfer in the rest of the words
input_axis_tready_next = 1;
input_axis_tready_next = 1'b1;
state_next = STATE_TRANSFER_IN;
end
end else begin
@ -191,24 +192,24 @@ always @* begin
// output bus is narrower
// accept new data
input_axis_tready_next = 1;
input_axis_tready_next = 1'b1;
if (input_axis_tready & input_axis_tvalid) begin
// word transfer in - store it in data register
cycle_count_next = 0;
cycle_count_next = 8'd0;
// is this the last cycle?
if (CYCLE_COUNT == 1) begin
// 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
// 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
// last cycle by tkeep fall at end of current cycle
last_cycle = 1;
last_cycle = 1'b1;
end else begin
last_cycle = 0;
last_cycle = 1'b0;
end
// pass complete input word, zero-extended to temp register
@ -220,18 +221,18 @@ always @* begin
// short-circuit and get first word out the door
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_tvalid_int = 1;
output_axis_tvalid_int = 1'b1;
output_axis_tlast_int = input_axis_tlast & 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
cycle_count_next = 1;
cycle_count_next = 8'd1;
end
if (!last_cycle || !output_axis_tready_int) begin
if (!last_cycle || !output_axis_tready_int_reg) begin
// continue outputting words
input_axis_tready_next = 0;
input_axis_tready_next = 1'b0;
state_next = STATE_TRANSFER_OUT;
end else begin
state_next = STATE_IDLE;
@ -246,7 +247,7 @@ always @* begin
// only used when output is wider
// accept new data
input_axis_tready_next = 1;
input_axis_tready_next = 1'b1;
if (input_axis_tready & input_axis_tvalid) begin
// word transfer in - store in data register
@ -265,7 +266,7 @@ always @* begin
state_next = STATE_TRANSFER_OUT;
end else begin
// more words to read
input_axis_tready_next = 1;
input_axis_tready_next = 1'b1;
state_next = STATE_TRANSFER_IN;
end
end else begin
@ -279,16 +280,16 @@ always @* begin
// output bus is wider
// 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)
output_axis_tdata_int = temp_tdata_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_tuser_int = temp_tuser_reg;
if (output_axis_tready_int) begin
if (output_axis_tready_int_reg) begin
// word transfer out
if (input_axis_tready & input_axis_tvalid) begin
@ -301,19 +302,19 @@ always @* begin
temp_tuser_next = input_axis_tuser;
// first input cycle complete
cycle_count_next = 1;
cycle_count_next = 8'd1;
if (input_axis_tlast) begin
// 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;
end else begin
// otherwise, transfer in the rest of the words
input_axis_tready_next = 1;
input_axis_tready_next = 1'b1;
state_next = STATE_TRANSFER_IN;
end
end else begin
input_axis_tready_next = 1;
input_axis_tready_next = 1'b1;
state_next = STATE_IDLE;
end
end else begin
@ -323,30 +324,30 @@ always @* begin
// output bus is narrower
// do not accept new data
input_axis_tready_next = 0;
input_axis_tready_next = 1'b0;
// is this the last cycle?
if (cycle_count_reg == CYCLE_COUNT-1) begin
// 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
// 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
// last cycle by tkeep fall at end of current cycle
last_cycle = 1;
last_cycle = 1'b1;
end else begin
last_cycle = 0;
last_cycle = 1'b0;
end
// 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_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_tuser_int = temp_tuser_reg & last_cycle;
if (output_axis_tready_int) begin
if (output_axis_tready_int_reg) begin
// word transfer out
cycle_count_next = cycle_count_reg + 1;
@ -354,7 +355,7 @@ always @* begin
if (last_cycle) begin
// terminated by counter or tlast signal
input_axis_tready_next = 1;
input_axis_tready_next = 1'b1;
state_next = STATE_IDLE;
end else begin
// more words to write
@ -371,38 +372,39 @@ end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
cycle_count_reg <= 0;
temp_tdata_reg <= 0;
temp_tkeep_reg <= 0;
temp_tlast_reg <= 0;
temp_tuser_reg <= 0;
input_axis_tready_reg <= 0;
cycle_count_reg <= 8'd0;
input_axis_tready_reg <= 1'b0;
end else begin
state_reg <= state_next;
input_axis_tready_reg <= input_axis_tready_next;
temp_tdata_reg <= temp_tdata_next;
temp_tkeep_reg <= temp_tkeep_next;
temp_tlast_reg <= temp_tlast_next;
temp_tuser_reg <= temp_tuser_next;
cycle_count_reg <= cycle_count_next;
end
temp_tdata_reg <= temp_tdata_next;
temp_tkeep_reg <= temp_tkeep_next;
temp_tlast_reg <= temp_tlast_next;
temp_tuser_reg <= temp_tuser_next;
end
// output datapath logic
reg [OUTPUT_DATA_WIDTH-1:0] output_axis_tdata_reg = 0;
reg [OUTPUT_KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0;
reg output_axis_tvalid_reg = 0;
reg output_axis_tlast_reg = 0;
reg output_axis_tuser_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 = {OUTPUT_KEEP_WIDTH{1'b0}};
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;
reg [OUTPUT_DATA_WIDTH-1:0] temp_axis_tdata_reg = 0;
reg [OUTPUT_KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0;
reg temp_axis_tvalid_reg = 0;
reg temp_axis_tlast_reg = 0;
reg temp_axis_tuser_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 = {OUTPUT_KEEP_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 1'b0;
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_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_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
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);
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (output_axis_tready_int_reg) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (output_axis_tready) begin
// input is not ready, but output is ready
output_axis_tvalid_next = temp_axis_tvalid_reg;
temp_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
output_axis_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;
output_axis_tvalid_reg <= 1'b0;
output_axis_tready_int_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
// transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early;
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
if (output_axis_tready_int) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int;
output_axis_tkeep_reg <= output_axis_tkeep_int;
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
// output is not ready and currently valid, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int;
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 else if (output_axis_tready) begin
// input is not ready, but output is ready
output_axis_tdata_reg <= temp_axis_tdata_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_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
// 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_tkeep_reg <= temp_axis_tkeep_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg;
end
if (store_axis_int_to_temp) begin
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
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
of this software and associated documentation files (the "Software"), to deal
@ -61,129 +61,163 @@ module axis_async_fifo #
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_gray = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
reg [ADDR_WIDTH:0] rd_ptr_gray = {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_gray_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_gray_next;
reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
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_sync2 = {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_sync2 = {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_reg = {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_reg = {ADDR_WIDTH+1{1'b0}};
reg input_rst_sync1 = 1;
reg input_rst_sync2 = 1;
reg input_rst_sync3 = 1;
reg output_rst_sync1 = 1;
reg output_rst_sync2 = 1;
reg output_rst_sync3 = 1;
reg input_rst_sync1_reg = 1'b1;
reg input_rst_sync2_reg = 1'b1;
reg input_rst_sync3_reg = 1'b1;
reg output_rst_sync1_reg = 1'b1;
reg output_rst_sync2_reg = 1'b1;
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 output_axis_tvalid_reg = 1'b0;
wire [DATA_WIDTH+2-1:0] data_in = {input_axis_tlast, input_axis_tuser, input_axis_tdata};
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
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
// (gray code equivalent of first MSB different but rest same)
wire full = ((wr_ptr_gray[ADDR_WIDTH] != rd_ptr_gray_sync2[ADDR_WIDTH]) &&
(wr_ptr_gray[ADDR_WIDTH-1] != rd_ptr_gray_sync2[ADDR_WIDTH-1]) &&
(wr_ptr_gray[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2[ADDR_WIDTH-2:0]));
wire full = ((wr_ptr_gray_reg[ADDR_WIDTH] != rd_ptr_gray_sync2_reg[ADDR_WIDTH]) &&
(wr_ptr_gray_reg[ADDR_WIDTH-1] != rd_ptr_gray_sync2_reg[ADDR_WIDTH-1]) &&
(wr_ptr_gray_reg[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2_reg[ADDR_WIDTH-2:0]));
// 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;
wire read = (output_axis_tready | ~output_axis_tvalid_reg) & ~empty;
// control signals
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_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg;
// reset synchronization
always @(posedge input_clk or posedge async_rst) begin
if (async_rst) begin
input_rst_sync1 <= 1;
input_rst_sync2 <= 1;
input_rst_sync3 <= 1;
input_rst_sync1_reg <= 1'b1;
input_rst_sync2_reg <= 1'b1;
input_rst_sync3_reg <= 1'b1;
end else begin
input_rst_sync1 <= 0;
input_rst_sync2 <= input_rst_sync1 | output_rst_sync1;
input_rst_sync3 <= input_rst_sync2;
input_rst_sync1_reg <= 1'b0;
input_rst_sync2_reg <= input_rst_sync1_reg | output_rst_sync1_reg;
input_rst_sync3_reg <= input_rst_sync2_reg;
end
end
always @(posedge output_clk or posedge async_rst) begin
if (async_rst) begin
output_rst_sync1 <= 1;
output_rst_sync2 <= 1;
output_rst_sync3 <= 1;
output_rst_sync1_reg <= 1'b1;
output_rst_sync2_reg <= 1'b1;
output_rst_sync3_reg <= 1'b1;
end else begin
output_rst_sync1 <= 0;
output_rst_sync2 <= output_rst_sync1;
output_rst_sync3 <= output_rst_sync2;
output_rst_sync1_reg <= 1'b0;
output_rst_sync2_reg <= output_rst_sync1_reg;
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
// write
always @(posedge input_clk) begin
if (input_rst_sync3) begin
wr_ptr <= 0;
wr_ptr_gray <= 0;
end else if (write) begin
mem[wr_ptr[ADDR_WIDTH-1:0]] <= data_in;
wr_ptr_next = wr_ptr + 1;
wr_ptr <= wr_ptr_next;
wr_ptr_gray <= wr_ptr_next ^ (wr_ptr_next >> 1);
if (input_rst_sync3_reg) begin
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
end else begin
wr_ptr_reg <= wr_ptr_next;
wr_ptr_gray_reg <= wr_ptr_gray_next;
end
if (write) begin
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= {input_axis_tlast, input_axis_tuser, input_axis_tdata};
end
end
// pointer synchronization
always @(posedge input_clk) begin
if (input_rst_sync3) begin
rd_ptr_gray_sync1 <= 0;
rd_ptr_gray_sync2 <= 0;
if (input_rst_sync3_reg) begin
rd_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
rd_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
end else begin
rd_ptr_gray_sync1 <= rd_ptr_gray;
rd_ptr_gray_sync2 <= rd_ptr_gray_sync1;
rd_ptr_gray_sync1_reg <= rd_ptr_gray_reg;
rd_ptr_gray_sync2_reg <= rd_ptr_gray_sync1_reg;
end
end
// read
always @(posedge output_clk) begin
if (output_rst_sync3) begin
rd_ptr <= 0;
rd_ptr_gray <= 0;
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;
if (output_rst_sync3_reg) begin
wr_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
end else begin
wr_ptr_gray_sync1 <= wr_ptr_gray;
wr_ptr_gray_sync2 <= wr_ptr_gray_sync1;
wr_ptr_gray_sync1_reg <= wr_ptr_gray_reg;
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
// source ready output
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;
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;
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

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
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
);
reg [ADDR_WIDTH:0] wr_ptr = {ADDR_WIDTH+1{1'b0}}, wr_ptr_next;
reg [ADDR_WIDTH:0] wr_ptr_gray = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
reg [ADDR_WIDTH:0] rd_ptr_gray = {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_gray_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_gray_next;
reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
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_sync2 = {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_sync2 = {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_reg = {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_reg = {ADDR_WIDTH+1{1'b0}};
reg input_rst_sync1 = 1;
reg input_rst_sync2 = 1;
reg input_rst_sync3 = 1;
reg output_rst_sync1 = 1;
reg output_rst_sync2 = 1;
reg output_rst_sync3 = 1;
reg input_rst_sync1_reg = 1'b1;
reg input_rst_sync2_reg = 1'b1;
reg input_rst_sync3_reg = 1'b1;
reg output_rst_sync1_reg = 1'b1;
reg output_rst_sync2_reg = 1'b1;
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 output_axis_tvalid_reg = 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 [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 1'b0;
// full when first TWO MSBs do NOT match, but rest matches
// (gray code equivalent of first MSB different but rest same)
wire full = ((wr_ptr_gray[ADDR_WIDTH] != rd_ptr_gray_sync2[ADDR_WIDTH]) &&
(wr_ptr_gray[ADDR_WIDTH-1] != rd_ptr_gray_sync2[ADDR_WIDTH-1]) &&
(wr_ptr_gray[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2[ADDR_WIDTH-2:0]));
wire full = ((wr_ptr_gray_reg[ADDR_WIDTH] != rd_ptr_gray_sync2_reg[ADDR_WIDTH]) &&
(wr_ptr_gray_reg[ADDR_WIDTH-1] != rd_ptr_gray_sync2_reg[ADDR_WIDTH-1]) &&
(wr_ptr_gray_reg[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2_reg[ADDR_WIDTH-2:0]));
// 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;
wire read = (output_axis_tready | ~output_axis_tvalid_reg) & ~empty;
// control signals
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_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg;
// reset synchronization
always @(posedge input_clk or posedge async_rst) begin
if (async_rst) begin
input_rst_sync1 <= 1;
input_rst_sync2 <= 1;
input_rst_sync3 <= 1;
input_rst_sync1_reg <= 1'b1;
input_rst_sync2_reg <= 1'b1;
input_rst_sync3_reg <= 1'b1;
end else begin
input_rst_sync1 <= 0;
input_rst_sync2 <= input_rst_sync1 | output_rst_sync1;
input_rst_sync3 <= input_rst_sync2;
input_rst_sync1_reg <= 1'b0;
input_rst_sync2_reg <= input_rst_sync1_reg | output_rst_sync1_reg;
input_rst_sync3_reg <= input_rst_sync2_reg;
end
end
always @(posedge output_clk or posedge async_rst) begin
if (async_rst) begin
output_rst_sync1 <= 1;
output_rst_sync2 <= 1;
output_rst_sync3 <= 1;
output_rst_sync1_reg <= 1'b1;
output_rst_sync2_reg <= 1'b1;
output_rst_sync3_reg <= 1'b1;
end else begin
output_rst_sync1 <= 0;
output_rst_sync2 <= output_rst_sync1;
output_rst_sync3 <= output_rst_sync2;
output_rst_sync1_reg <= 1'b0;
output_rst_sync2_reg <= output_rst_sync1_reg;
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
// write
always @(posedge input_clk) begin
if (input_rst_sync3) begin
wr_ptr <= 0;
wr_ptr_gray <= 0;
end else if (write) begin
mem[wr_ptr[ADDR_WIDTH-1:0]] <= data_in;
wr_ptr_next = wr_ptr + 1;
wr_ptr <= wr_ptr_next;
wr_ptr_gray <= wr_ptr_next ^ (wr_ptr_next >> 1);
if (input_rst_sync3_reg) begin
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
end else begin
wr_ptr_reg <= wr_ptr_next;
wr_ptr_gray_reg <= wr_ptr_gray_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
// pointer synchronization
always @(posedge input_clk) begin
if (input_rst_sync3) begin
rd_ptr_gray_sync1 <= 0;
rd_ptr_gray_sync2 <= 0;
if (input_rst_sync3_reg) begin
rd_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
rd_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
end else begin
rd_ptr_gray_sync1 <= rd_ptr_gray;
rd_ptr_gray_sync2 <= rd_ptr_gray_sync1;
rd_ptr_gray_sync1_reg <= rd_ptr_gray_reg;
rd_ptr_gray_sync2_reg <= rd_ptr_gray_sync1_reg;
end
end
// read
always @(posedge output_clk) begin
if (output_rst_sync3) begin
rd_ptr <= 0;
rd_ptr_gray <= 0;
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;
if (output_rst_sync3_reg) begin
wr_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
end else begin
wr_ptr_gray_sync1 <= wr_ptr_gray;
wr_ptr_gray_sync2 <= wr_ptr_gray_sync1;
wr_ptr_gray_sync1_reg <= wr_ptr_gray_reg;
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
// source ready output
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;
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;
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

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
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
);
reg [ADDR_WIDTH:0] wr_ptr = {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_gray = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
reg [ADDR_WIDTH:0] rd_ptr_gray = {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_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_cur_next;
reg [ADDR_WIDTH:0] wr_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_gray_next;
reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
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_sync2 = {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_sync2 = {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_reg = {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_reg = {ADDR_WIDTH+1{1'b0}};
reg input_rst_sync1 = 1;
reg input_rst_sync2 = 1;
reg input_rst_sync3 = 1;
reg output_rst_sync1 = 1;
reg output_rst_sync2 = 1;
reg output_rst_sync3 = 1;
reg input_rst_sync1_reg = 1'b1;
reg input_rst_sync2_reg = 1'b1;
reg input_rst_sync3_reg = 1'b1;
reg output_rst_sync1_reg = 1'b1;
reg output_rst_sync2_reg = 1'b1;
reg output_rst_sync3_reg = 1'b1;
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] mem[(2**ADDR_WIDTH)-1:0];
reg overflow_sync1 = 1'b0;
reg overflow_sync2 = 1'b0;
reg overflow_sync3 = 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};
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 1'b0;
// full when first TWO MSBs do NOT match, but rest matches
// (gray code equivalent of first MSB different but rest same)
wire full = ((wr_ptr_gray[ADDR_WIDTH] != rd_ptr_gray_sync2[ADDR_WIDTH]) &&
(wr_ptr_gray[ADDR_WIDTH-1] != rd_ptr_gray_sync2[ADDR_WIDTH-1]) &&
(wr_ptr_gray[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2[ADDR_WIDTH-2:0]));
wire full = ((wr_ptr_gray_reg[ADDR_WIDTH] != rd_ptr_gray_sync2_reg[ADDR_WIDTH]) &&
(wr_ptr_gray_reg[ADDR_WIDTH-1] != rd_ptr_gray_sync2_reg[ADDR_WIDTH-1]) &&
(wr_ptr_gray_reg[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2_reg[ADDR_WIDTH-2:0]));
// empty when pointers match exactly
wire empty = rd_ptr_gray == wr_ptr_gray_sync2;
// overflow in single packet
wire full_cur = ((wr_ptr[ADDR_WIDTH] != wr_ptr_cur[ADDR_WIDTH]) &&
(wr_ptr[ADDR_WIDTH-1:0] == wr_ptr_cur[ADDR_WIDTH-1:0]));
wire empty = rd_ptr_gray_reg == wr_ptr_gray_sync2_reg;
// overflow within packet
wire full_cur = ((wr_ptr_reg[ADDR_WIDTH] != wr_ptr_cur_reg[ADDR_WIDTH]) &&
(wr_ptr_reg[ADDR_WIDTH-1:0] == wr_ptr_cur_reg[ADDR_WIDTH-1:0]));
wire write = input_axis_tvalid & (~full | DROP_WHEN_FULL);
wire read = (output_axis_tready | ~output_axis_tvalid_reg) & ~empty;
// control signals
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_tlast = output_axis_tlast_reg;
assign input_status_overflow = overflow_reg;
assign input_status_bad_frame = bad_frame_reg;
assign input_status_good_frame = good_frame_reg;
assign output_status_overflow = overflow_sync3 ^ overflow_sync4;
assign output_status_bad_frame = bad_frame_sync3 ^ bad_frame_sync4;
assign output_status_good_frame = good_frame_sync3 ^ good_frame_sync4;
assign output_status_overflow = overflow_sync3_reg ^ overflow_sync4_reg;
assign output_status_bad_frame = bad_frame_sync3_reg ^ bad_frame_sync4_reg;
assign output_status_good_frame = good_frame_sync3_reg ^ good_frame_sync4_reg;
// reset synchronization
always @(posedge input_clk or posedge async_rst) begin
if (async_rst) begin
input_rst_sync1 <= 1;
input_rst_sync2 <= 1;
input_rst_sync3 <= 1;
input_rst_sync1_reg <= 1'b1;
input_rst_sync2_reg <= 1'b1;
input_rst_sync3_reg <= 1'b1;
end else begin
input_rst_sync1 <= 0;
input_rst_sync2 <= input_rst_sync1 | output_rst_sync1;
input_rst_sync3 <= input_rst_sync2;
input_rst_sync1_reg <= 1'b0;
input_rst_sync2_reg <= input_rst_sync1_reg | output_rst_sync1_reg;
input_rst_sync3_reg <= input_rst_sync2_reg;
end
end
always @(posedge output_clk or posedge async_rst) begin
if (async_rst) begin
output_rst_sync1 <= 1;
output_rst_sync2 <= 1;
output_rst_sync3 <= 1;
output_rst_sync1_reg <= 1'b1;
output_rst_sync2_reg <= 1'b1;
output_rst_sync3_reg <= 1'b1;
end else begin
output_rst_sync1 <= 0;
output_rst_sync2 <= output_rst_sync1;
output_rst_sync3 <= output_rst_sync2;
output_rst_sync1_reg <= 1'b0;
output_rst_sync2_reg <= output_rst_sync1_reg;
output_rst_sync3_reg <= output_rst_sync2_reg;
end
end
// write
always @(posedge input_clk) begin
if (input_rst_sync3) begin
wr_ptr <= 0;
wr_ptr_cur <= 0;
wr_ptr_gray <= 0;
drop_frame <= 0;
overflow_reg <= 0;
bad_frame_reg <= 0;
good_frame_reg <= 0;
end else if (write) begin
overflow_reg <= 0;
bad_frame_reg <= 0;
good_frame_reg <= 0;
if (full | full_cur | drop_frame) begin
// buffer full, hold current pointer, drop packet at end
drop_frame <= 1;
if (input_axis_tlast) begin
wr_ptr_cur <= wr_ptr;
drop_frame <= 0;
overflow_reg <= 1;
end
end else begin
mem[wr_ptr_cur[ADDR_WIDTH-1:0]] <= data_in;
wr_ptr_cur <= wr_ptr_cur + 1;
if (input_axis_tlast) begin
if (input_axis_tuser) begin
// bad packet, reset write pointer
wr_ptr_cur <= wr_ptr;
bad_frame_reg <= 1;
end else begin
// good packet, push new write pointer
wr_ptr_next = wr_ptr_cur + 1;
wr_ptr <= wr_ptr_next;
wr_ptr_gray <= wr_ptr_next ^ (wr_ptr_next >> 1);
good_frame_reg <= 1;
// Write logic
always @* begin
write = 1'b0;
drop_frame_next = 1'b0;
overflow_next = 1'b0;
bad_frame_next = 1'b0;
good_frame_next = 1'b0;
wr_ptr_next = wr_ptr_reg;
wr_ptr_cur_next = wr_ptr_cur_reg;
wr_ptr_gray_next = wr_ptr_gray_reg;
if (input_axis_tvalid) begin
// input data valid
if (~full | DROP_WHEN_FULL) begin
// 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
// end of frame, reset write pointer
wr_ptr_cur_next = wr_ptr_reg;
drop_frame_next = 1'b0;
overflow_next = 1'b1;
end
end else begin
write = 1'b1;
wr_ptr_cur_next = wr_ptr_cur_reg + 1;
if (input_axis_tlast) begin
// end of frame
if (input_axis_tuser) begin
// bad packet, reset write pointer
wr_ptr_cur_next = wr_ptr_reg;
bad_frame_next = 1'b1;
end else begin
// good packet, update write pointer
wr_ptr_next = wr_ptr_cur_reg + 1;
wr_ptr_gray_next = wr_ptr_next ^ (wr_ptr_next >> 1);
good_frame_next = 1'b1;
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
overflow_reg <= 0;
bad_frame_reg <= 0;
good_frame_reg <= 0;
wr_ptr_reg <= wr_ptr_next;
wr_ptr_cur_reg <= wr_ptr_cur_next;
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
// pointer synchronization
always @(posedge input_clk) begin
if (input_rst_sync3) begin
rd_ptr_gray_sync1 <= 0;
rd_ptr_gray_sync2 <= 0;
if (input_rst_sync3_reg) begin
rd_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
rd_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
end else begin
rd_ptr_gray_sync1 <= rd_ptr_gray;
rd_ptr_gray_sync2 <= rd_ptr_gray_sync1;
rd_ptr_gray_sync1_reg <= rd_ptr_gray_reg;
rd_ptr_gray_sync2_reg <= rd_ptr_gray_sync1_reg;
end
end
// read
always @(posedge output_clk) begin
if (output_rst_sync3) begin
rd_ptr <= 0;
rd_ptr_gray <= 0;
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;
if (output_rst_sync3_reg) begin
wr_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
end else begin
wr_ptr_gray_sync1 <= wr_ptr_gray;
wr_ptr_gray_sync2 <= wr_ptr_gray_sync1;
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;
wr_ptr_gray_sync1_reg <= wr_ptr_gray_reg;
wr_ptr_gray_sync2_reg <= wr_ptr_gray_sync1_reg;
end
end
// status synchronization
always @(posedge input_clk) begin
if (input_rst_sync3) begin
overflow_sync1 <= 1'b0;
bad_frame_sync1 <= 1'b0;
good_frame_sync1 <= 1'b0;
if (input_rst_sync3_reg) begin
overflow_sync1_reg <= 1'b0;
bad_frame_sync1_reg <= 1'b0;
good_frame_sync1_reg <= 1'b0;
end else begin
overflow_sync1 <= overflow_sync1 ^ overflow_reg;
bad_frame_sync1 <= bad_frame_sync1 ^ bad_frame_reg;
good_frame_sync1 <= good_frame_sync1 ^ good_frame_reg;
overflow_sync1_reg <= overflow_sync1_reg ^ overflow_reg;
bad_frame_sync1_reg <= bad_frame_sync1_reg ^ bad_frame_reg;
good_frame_sync1_reg <= good_frame_sync1_reg ^ good_frame_reg;
end
end
always @(posedge output_clk) begin
if (output_rst_sync3) begin
overflow_sync2 <= 1'b0;
overflow_sync3 <= 1'b0;
bad_frame_sync2 <= 1'b0;
bad_frame_sync3 <= 1'b0;
good_frame_sync2 <= 1'b0;
good_frame_sync3 <= 1'b0;
if (output_rst_sync3_reg) begin
overflow_sync2_reg <= 1'b0;
overflow_sync3_reg <= 1'b0;
bad_frame_sync2_reg <= 1'b0;
bad_frame_sync3_reg <= 1'b0;
good_frame_sync2_reg <= 1'b0;
good_frame_sync3_reg <= 1'b0;
end else begin
overflow_sync2 <= overflow_sync1;
overflow_sync3 <= overflow_sync2;
overflow_sync4 <= overflow_sync3;
bad_frame_sync2 <= bad_frame_sync1;
bad_frame_sync3 <= bad_frame_sync2;
bad_frame_sync4 <= bad_frame_sync3;
good_frame_sync2 <= good_frame_sync1;
good_frame_sync3 <= good_frame_sync2;
good_frame_sync4 <= good_frame_sync3;
overflow_sync2_reg <= overflow_sync1_reg;
overflow_sync3_reg <= overflow_sync2_reg;
overflow_sync4_reg <= overflow_sync3_reg;
bad_frame_sync2_reg <= bad_frame_sync1_reg;
bad_frame_sync3_reg <= bad_frame_sync2_reg;
bad_frame_sync4_reg <= bad_frame_sync3_reg;
good_frame_sync2_reg <= good_frame_sync1_reg;
good_frame_sync3_reg <= good_frame_sync2_reg;
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

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
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
);
reg [ADDR_WIDTH:0] wr_ptr = {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_gray = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
reg [ADDR_WIDTH:0] rd_ptr_gray = {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_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_cur_next;
reg [ADDR_WIDTH:0] wr_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_gray_next;
reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
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_sync2 = {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_sync2 = {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_reg = {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_reg = {ADDR_WIDTH+1{1'b0}};
reg input_rst_sync1 = 1;
reg input_rst_sync2 = 1;
reg input_rst_sync3 = 1;
reg output_rst_sync1 = 1;
reg output_rst_sync2 = 1;
reg output_rst_sync3 = 1;
reg input_rst_sync1_reg = 1'b1;
reg input_rst_sync2_reg = 1'b1;
reg input_rst_sync3_reg = 1'b1;
reg output_rst_sync1_reg = 1'b1;
reg output_rst_sync2_reg = 1'b1;
reg output_rst_sync3_reg = 1'b1;
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] mem[(2**ADDR_WIDTH)-1:0];
reg overflow_sync1 = 1'b0;
reg overflow_sync2 = 1'b0;
reg overflow_sync3 = 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+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};
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 1'b0;
// full when first TWO MSBs do NOT match, but rest matches
// (gray code equivalent of first MSB different but rest same)
wire full = ((wr_ptr_gray[ADDR_WIDTH] != rd_ptr_gray_sync2[ADDR_WIDTH]) &&
(wr_ptr_gray[ADDR_WIDTH-1] != rd_ptr_gray_sync2[ADDR_WIDTH-1]) &&
(wr_ptr_gray[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2[ADDR_WIDTH-2:0]));
wire full = ((wr_ptr_gray_reg[ADDR_WIDTH] != rd_ptr_gray_sync2_reg[ADDR_WIDTH]) &&
(wr_ptr_gray_reg[ADDR_WIDTH-1] != rd_ptr_gray_sync2_reg[ADDR_WIDTH-1]) &&
(wr_ptr_gray_reg[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2_reg[ADDR_WIDTH-2:0]));
// empty when pointers match exactly
wire empty = rd_ptr_gray == wr_ptr_gray_sync2;
// overflow in single packet
wire full_cur = ((wr_ptr[ADDR_WIDTH] != wr_ptr_cur[ADDR_WIDTH]) &&
(wr_ptr[ADDR_WIDTH-1:0] == wr_ptr_cur[ADDR_WIDTH-1:0]));
wire empty = rd_ptr_gray_reg == wr_ptr_gray_sync2_reg;
// overflow within packet
wire full_cur = ((wr_ptr_reg[ADDR_WIDTH] != wr_ptr_cur_reg[ADDR_WIDTH]) &&
(wr_ptr_reg[ADDR_WIDTH-1:0] == wr_ptr_cur_reg[ADDR_WIDTH-1:0]));
wire write = input_axis_tvalid & (~full | DROP_WHEN_FULL);
wire read = (output_axis_tready | ~output_axis_tvalid_reg) & ~empty;
// control signals
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_tlast = output_axis_tlast_reg;
assign input_status_overflow = overflow_reg;
assign input_status_bad_frame = bad_frame_reg;
assign input_status_good_frame = good_frame_reg;
assign output_status_overflow = overflow_sync3 ^ overflow_sync4;
assign output_status_bad_frame = bad_frame_sync3 ^ bad_frame_sync4;
assign output_status_good_frame = good_frame_sync3 ^ good_frame_sync4;
assign output_status_overflow = overflow_sync3_reg ^ overflow_sync4_reg;
assign output_status_bad_frame = bad_frame_sync3_reg ^ bad_frame_sync4_reg;
assign output_status_good_frame = good_frame_sync3_reg ^ good_frame_sync4_reg;
// reset synchronization
always @(posedge input_clk or posedge async_rst) begin
if (async_rst) begin
input_rst_sync1 <= 1;
input_rst_sync2 <= 1;
input_rst_sync3 <= 1;
input_rst_sync1_reg <= 1'b1;
input_rst_sync2_reg <= 1'b1;
input_rst_sync3_reg <= 1'b1;
end else begin
input_rst_sync1 <= 0;
input_rst_sync2 <= input_rst_sync1 | output_rst_sync1;
input_rst_sync3 <= input_rst_sync2;
input_rst_sync1_reg <= 1'b0;
input_rst_sync2_reg <= input_rst_sync1_reg | output_rst_sync1_reg;
input_rst_sync3_reg <= input_rst_sync2_reg;
end
end
always @(posedge output_clk or posedge async_rst) begin
if (async_rst) begin
output_rst_sync1 <= 1;
output_rst_sync2 <= 1;
output_rst_sync3 <= 1;
output_rst_sync1_reg <= 1'b1;
output_rst_sync2_reg <= 1'b1;
output_rst_sync3_reg <= 1'b1;
end else begin
output_rst_sync1 <= 0;
output_rst_sync2 <= output_rst_sync1;
output_rst_sync3 <= output_rst_sync2;
output_rst_sync1_reg <= 1'b0;
output_rst_sync2_reg <= output_rst_sync1_reg;
output_rst_sync3_reg <= output_rst_sync2_reg;
end
end
// write
always @(posedge input_clk) begin
if (input_rst_sync3) begin
wr_ptr <= 0;
wr_ptr_cur <= 0;
wr_ptr_gray <= 0;
drop_frame <= 0;
overflow_reg <= 0;
bad_frame_reg <= 0;
good_frame_reg <= 0;
end else if (write) begin
overflow_reg <= 0;
bad_frame_reg <= 0;
good_frame_reg <= 0;
if (full | full_cur | drop_frame) begin
// buffer full, hold current pointer, drop packet at end
drop_frame <= 1;
if (input_axis_tlast) begin
wr_ptr_cur <= wr_ptr;
drop_frame <= 0;
overflow_reg <= 1;
end
end else begin
mem[wr_ptr_cur[ADDR_WIDTH-1:0]] <= data_in;
wr_ptr_cur <= wr_ptr_cur + 1;
if (input_axis_tlast) begin
if (input_axis_tuser) begin
// bad packet, reset write pointer
wr_ptr_cur <= wr_ptr;
bad_frame_reg <= 1;
end else begin
// good packet, push new write pointer
wr_ptr_next = wr_ptr_cur + 1;
wr_ptr <= wr_ptr_next;
wr_ptr_gray <= wr_ptr_next ^ (wr_ptr_next >> 1);
good_frame_reg <= 1;
// Write logic
always @* begin
write = 1'b0;
drop_frame_next = 1'b0;
overflow_next = 1'b0;
bad_frame_next = 1'b0;
good_frame_next = 1'b0;
wr_ptr_next = wr_ptr_reg;
wr_ptr_cur_next = wr_ptr_cur_reg;
wr_ptr_gray_next = wr_ptr_gray_reg;
if (input_axis_tvalid) begin
// input data valid
if (~full | DROP_WHEN_FULL) begin
// 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
// end of frame, reset write pointer
wr_ptr_cur_next = wr_ptr_reg;
drop_frame_next = 1'b0;
overflow_next = 1'b1;
end
end else begin
write = 1'b1;
wr_ptr_cur_next = wr_ptr_cur_reg + 1;
if (input_axis_tlast) begin
// end of frame
if (input_axis_tuser) begin
// bad packet, reset write pointer
wr_ptr_cur_next = wr_ptr_reg;
bad_frame_next = 1'b1;
end else begin
// good packet, update write pointer
wr_ptr_next = wr_ptr_cur_reg + 1;
wr_ptr_gray_next = wr_ptr_next ^ (wr_ptr_next >> 1);
good_frame_next = 1'b1;
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
overflow_reg <= 0;
bad_frame_reg <= 0;
good_frame_reg <= 0;
wr_ptr_reg <= wr_ptr_next;
wr_ptr_cur_reg <= wr_ptr_cur_next;
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
// pointer synchronization
always @(posedge input_clk) begin
if (input_rst_sync3) begin
rd_ptr_gray_sync1 <= 0;
rd_ptr_gray_sync2 <= 0;
if (input_rst_sync3_reg) begin
rd_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
rd_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
end else begin
rd_ptr_gray_sync1 <= rd_ptr_gray;
rd_ptr_gray_sync2 <= rd_ptr_gray_sync1;
rd_ptr_gray_sync1_reg <= rd_ptr_gray_reg;
rd_ptr_gray_sync2_reg <= rd_ptr_gray_sync1_reg;
end
end
// read
always @(posedge output_clk) begin
if (output_rst_sync3) begin
rd_ptr <= 0;
rd_ptr_gray <= 0;
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;
if (output_rst_sync3_reg) begin
wr_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
end else begin
wr_ptr_gray_sync1 <= wr_ptr_gray;
wr_ptr_gray_sync2 <= wr_ptr_gray_sync1;
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;
wr_ptr_gray_sync1_reg <= wr_ptr_gray_reg;
wr_ptr_gray_sync2_reg <= wr_ptr_gray_sync1_reg;
end
end
// status synchronization
always @(posedge input_clk) begin
if (input_rst_sync3) begin
overflow_sync1 <= 1'b0;
bad_frame_sync1 <= 1'b0;
good_frame_sync1 <= 1'b0;
if (input_rst_sync3_reg) begin
overflow_sync1_reg <= 1'b0;
bad_frame_sync1_reg <= 1'b0;
good_frame_sync1_reg <= 1'b0;
end else begin
overflow_sync1 <= overflow_sync1 ^ overflow_reg;
bad_frame_sync1 <= bad_frame_sync1 ^ bad_frame_reg;
good_frame_sync1 <= good_frame_sync1 ^ good_frame_reg;
overflow_sync1_reg <= overflow_sync1_reg ^ overflow_reg;
bad_frame_sync1_reg <= bad_frame_sync1_reg ^ bad_frame_reg;
good_frame_sync1_reg <= good_frame_sync1_reg ^ good_frame_reg;
end
end
always @(posedge output_clk) begin
if (output_rst_sync3) begin
overflow_sync2 <= 1'b0;
overflow_sync3 <= 1'b0;
bad_frame_sync2 <= 1'b0;
bad_frame_sync3 <= 1'b0;
good_frame_sync2 <= 1'b0;
good_frame_sync3 <= 1'b0;
if (output_rst_sync3_reg) begin
overflow_sync2_reg <= 1'b0;
overflow_sync3_reg <= 1'b0;
bad_frame_sync2_reg <= 1'b0;
bad_frame_sync3_reg <= 1'b0;
good_frame_sync2_reg <= 1'b0;
good_frame_sync3_reg <= 1'b0;
end else begin
overflow_sync2 <= overflow_sync1;
overflow_sync3 <= overflow_sync2;
overflow_sync4 <= overflow_sync3;
bad_frame_sync2 <= bad_frame_sync1;
bad_frame_sync3 <= bad_frame_sync2;
bad_frame_sync4 <= bad_frame_sync3;
good_frame_sync2 <= good_frame_sync1;
good_frame_sync3 <= good_frame_sync2;
good_frame_sync4 <= good_frame_sync3;
overflow_sync2_reg <= overflow_sync1_reg;
overflow_sync3_reg <= overflow_sync2_reg;
overflow_sync4_reg <= overflow_sync3_reg;
bad_frame_sync2_reg <= bad_frame_sync1_reg;
bad_frame_sync3_reg <= bad_frame_sync2_reg;
bad_frame_sync4_reg <= bad_frame_sync3_reg;
good_frame_sync2_reg <= good_frame_sync1_reg;
good_frame_sync3_reg <= good_frame_sync2_reg;
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

View File

@ -40,7 +40,7 @@ def generate(ports=4, name=None, output=None):
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
of this software and associated documentation files (the "Software"), to deal
@ -103,21 +103,21 @@ module {{name}} #
{%- endfor %}
);
{% for p in ports %}
reg [DATA_WIDTH-1:0] input_{{p}}_axis_tdata_reg = 0;
reg input_{{p}}_axis_tvalid_reg = 0;
reg input_{{p}}_axis_tlast_reg = 0;
reg input_{{p}}_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] input_{{p}}_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg input_{{p}}_axis_tvalid_reg = 1'b0;
reg input_{{p}}_axis_tlast_reg = 1'b0;
reg input_{{p}}_axis_tuser_reg = 1'b0;
{% endfor %}
{%- for p in ports %}
reg [DATA_WIDTH-1:0] output_{{p}}_axis_tdata_reg = 0;
reg output_{{p}}_axis_tvalid_reg = 0;
reg output_{{p}}_axis_tlast_reg = 0;
reg output_{{p}}_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] output_{{p}}_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_{{p}}_axis_tvalid_reg = 1'b0;
reg output_{{p}}_axis_tlast_reg = 1'b0;
reg output_{{p}}_axis_tuser_reg = 1'b0;
{% endfor %}
{%- for p in ports %}
reg [{{w-1}}:0] output_{{p}}_select_reg = 0;
reg [{{w-1}}:0] output_{{p}}_select_reg = {{w}}'d0;
{%- endfor %}
{% for p in ports %}
assign output_{{p}}_axis_tdata = output_{{p}}_axis_tdata_reg;
@ -129,44 +129,48 @@ assign output_{{p}}_axis_tuser = output_{{p}}_axis_tuser_reg;
always @(posedge clk) begin
if (rst) begin
{%- for p in ports %}
output_{{p}}_select_reg <= 0;
output_{{p}}_select_reg <= {{w}}'d0;
{%- endfor %}
{% for p in ports %}
input_{{p}}_axis_tdata_reg <= 0;
input_{{p}}_axis_tvalid_reg <= 0;
input_{{p}}_axis_tlast_reg <= 0;
input_{{p}}_axis_tuser_reg <= 0;
input_{{p}}_axis_tvalid_reg <= 1'b0;
{%- endfor %}
{% for p in ports %}
output_{{p}}_axis_tdata_reg <= 0;
output_{{p}}_axis_tvalid_reg <= 0;
output_{{p}}_axis_tlast_reg <= 0;
output_{{p}}_axis_tuser_reg <= 0;
output_{{p}}_axis_tvalid_reg <= 1'b0;
{%- endfor %}
end else begin
{%- 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_tlast_reg <= input_{{p}}_axis_tlast;
input_{{p}}_axis_tuser_reg <= input_{{p}}_axis_tuser;
{% endfor %}
{%- for p in ports %}
{%- 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}}: begin
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_tuser_reg <= input_{{q}}_axis_tuser_reg;
end
{{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_tuser_reg <= input_{{p}}_axis_tuser;
{%- endfor %}
{%- for p in ports %}
case (output_{{p}}_select_reg)
{%- for q in ports %}
{{w}}'d{{q}}: begin
output_{{p}}_axis_tdata_reg <= input_{{q}}_axis_tdata_reg;
output_{{p}}_axis_tlast_reg <= input_{{q}}_axis_tlast_reg;
output_{{p}}_axis_tuser_reg <= input_{{q}}_axis_tuser_reg;
end
{%- endfor %}
endcase
{%- endfor %}
end
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
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
);
reg [DATA_WIDTH-1:0] input_0_axis_tdata_reg = 0;
reg input_0_axis_tvalid_reg = 0;
reg input_0_axis_tlast_reg = 0;
reg input_0_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] input_0_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg input_0_axis_tvalid_reg = 1'b0;
reg input_0_axis_tlast_reg = 1'b0;
reg input_0_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] input_1_axis_tdata_reg = 0;
reg input_1_axis_tvalid_reg = 0;
reg input_1_axis_tlast_reg = 0;
reg input_1_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] input_1_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg input_1_axis_tvalid_reg = 1'b0;
reg input_1_axis_tlast_reg = 1'b0;
reg input_1_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] input_2_axis_tdata_reg = 0;
reg input_2_axis_tvalid_reg = 0;
reg input_2_axis_tlast_reg = 0;
reg input_2_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] input_2_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg input_2_axis_tvalid_reg = 1'b0;
reg input_2_axis_tlast_reg = 1'b0;
reg input_2_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] input_3_axis_tdata_reg = 0;
reg input_3_axis_tvalid_reg = 0;
reg input_3_axis_tlast_reg = 0;
reg input_3_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] input_3_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg input_3_axis_tvalid_reg = 1'b0;
reg input_3_axis_tlast_reg = 1'b0;
reg input_3_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] output_0_axis_tdata_reg = 0;
reg output_0_axis_tvalid_reg = 0;
reg output_0_axis_tlast_reg = 0;
reg output_0_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] output_0_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_0_axis_tvalid_reg = 1'b0;
reg output_0_axis_tlast_reg = 1'b0;
reg output_0_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] output_1_axis_tdata_reg = 0;
reg output_1_axis_tvalid_reg = 0;
reg output_1_axis_tlast_reg = 0;
reg output_1_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] output_1_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_1_axis_tvalid_reg = 1'b0;
reg output_1_axis_tlast_reg = 1'b0;
reg output_1_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] output_2_axis_tdata_reg = 0;
reg output_2_axis_tvalid_reg = 0;
reg output_2_axis_tlast_reg = 0;
reg output_2_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] output_2_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_2_axis_tvalid_reg = 1'b0;
reg output_2_axis_tlast_reg = 1'b0;
reg output_2_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] output_3_axis_tdata_reg = 0;
reg output_3_axis_tvalid_reg = 0;
reg output_3_axis_tlast_reg = 0;
reg output_3_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] output_3_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_3_axis_tvalid_reg = 1'b0;
reg output_3_axis_tlast_reg = 1'b0;
reg output_3_axis_tuser_reg = 1'b0;
reg [1:0] output_0_select_reg = 0;
reg [1:0] output_1_select_reg = 0;
reg [1:0] output_2_select_reg = 0;
reg [1:0] output_3_select_reg = 0;
reg [1:0] output_0_select_reg = 2'd0;
reg [1:0] output_1_select_reg = 2'd0;
reg [1:0] output_2_select_reg = 2'd0;
reg [1:0] output_3_select_reg = 2'd0;
assign output_0_axis_tdata = output_0_axis_tdata_reg;
assign output_0_axis_tvalid = output_0_axis_tvalid_reg;
@ -160,64 +160,25 @@ assign output_3_axis_tuser = output_3_axis_tuser_reg;
always @(posedge clk) begin
if (rst) begin
output_0_select_reg <= 0;
output_1_select_reg <= 0;
output_2_select_reg <= 0;
output_3_select_reg <= 0;
output_0_select_reg <= 2'd0;
output_1_select_reg <= 2'd0;
output_2_select_reg <= 2'd0;
output_3_select_reg <= 2'd0;
input_0_axis_tdata_reg <= 0;
input_0_axis_tvalid_reg <= 0;
input_0_axis_tlast_reg <= 0;
input_0_axis_tuser_reg <= 0;
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;
input_0_axis_tvalid_reg <= 1'b0;
input_1_axis_tvalid_reg <= 1'b0;
input_2_axis_tvalid_reg <= 1'b0;
input_3_axis_tvalid_reg <= 1'b0;
output_0_axis_tdata_reg <= 0;
output_0_axis_tvalid_reg <= 0;
output_0_axis_tlast_reg <= 0;
output_0_axis_tuser_reg <= 0;
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;
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;
end else begin
input_0_axis_tdata_reg <= input_0_axis_tdata;
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_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_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_tlast_reg <= input_3_axis_tlast;
input_3_axis_tuser_reg <= input_3_axis_tuser;
output_0_select_reg <= output_0_select;
output_1_select_reg <= output_1_select;
@ -225,113 +186,141 @@ always @(posedge clk) begin
output_3_select_reg <= output_3_select;
case (output_0_select_reg)
2'd0: begin
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_tuser_reg <= input_0_axis_tuser_reg;
end
2'd1: begin
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_tuser_reg <= input_1_axis_tuser_reg;
end
2'd2: begin
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_tuser_reg <= input_2_axis_tuser_reg;
end
2'd3: begin
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_tuser_reg <= input_3_axis_tuser_reg;
end
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: begin
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_tuser_reg <= input_0_axis_tuser_reg;
end
2'd1: begin
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_tuser_reg <= input_1_axis_tuser_reg;
end
2'd2: begin
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_tuser_reg <= input_2_axis_tuser_reg;
end
2'd3: begin
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_tuser_reg <= input_3_axis_tuser_reg;
end
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: begin
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_tuser_reg <= input_0_axis_tuser_reg;
end
2'd1: begin
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_tuser_reg <= input_1_axis_tuser_reg;
end
2'd2: begin
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_tuser_reg <= input_2_axis_tuser_reg;
end
2'd3: begin
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_tuser_reg <= input_3_axis_tuser_reg;
end
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: begin
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_tuser_reg <= input_0_axis_tuser_reg;
end
2'd1: begin
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_tuser_reg <= input_1_axis_tuser_reg;
end
2'd2: begin
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_tuser_reg <= input_2_axis_tuser_reg;
end
2'd3: begin
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_tuser_reg <= input_3_axis_tuser_reg;
end
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)
2'd0: begin
output_0_axis_tdata_reg <= input_0_axis_tdata_reg;
output_0_axis_tlast_reg <= input_0_axis_tlast_reg;
output_0_axis_tuser_reg <= input_0_axis_tuser_reg;
end
2'd1: begin
output_0_axis_tdata_reg <= input_1_axis_tdata_reg;
output_0_axis_tlast_reg <= input_1_axis_tlast_reg;
output_0_axis_tuser_reg <= input_1_axis_tuser_reg;
end
2'd2: begin
output_0_axis_tdata_reg <= input_2_axis_tdata_reg;
output_0_axis_tlast_reg <= input_2_axis_tlast_reg;
output_0_axis_tuser_reg <= input_2_axis_tuser_reg;
end
2'd3: begin
output_0_axis_tdata_reg <= input_3_axis_tdata_reg;
output_0_axis_tlast_reg <= input_3_axis_tlast_reg;
output_0_axis_tuser_reg <= input_3_axis_tuser_reg;
end
endcase
case (output_1_select_reg)
2'd0: begin
output_1_axis_tdata_reg <= input_0_axis_tdata_reg;
output_1_axis_tlast_reg <= input_0_axis_tlast_reg;
output_1_axis_tuser_reg <= input_0_axis_tuser_reg;
end
2'd1: begin
output_1_axis_tdata_reg <= input_1_axis_tdata_reg;
output_1_axis_tlast_reg <= input_1_axis_tlast_reg;
output_1_axis_tuser_reg <= input_1_axis_tuser_reg;
end
2'd2: begin
output_1_axis_tdata_reg <= input_2_axis_tdata_reg;
output_1_axis_tlast_reg <= input_2_axis_tlast_reg;
output_1_axis_tuser_reg <= input_2_axis_tuser_reg;
end
2'd3: begin
output_1_axis_tdata_reg <= input_3_axis_tdata_reg;
output_1_axis_tlast_reg <= input_3_axis_tlast_reg;
output_1_axis_tuser_reg <= input_3_axis_tuser_reg;
end
endcase
case (output_2_select_reg)
2'd0: begin
output_2_axis_tdata_reg <= input_0_axis_tdata_reg;
output_2_axis_tlast_reg <= input_0_axis_tlast_reg;
output_2_axis_tuser_reg <= input_0_axis_tuser_reg;
end
2'd1: begin
output_2_axis_tdata_reg <= input_1_axis_tdata_reg;
output_2_axis_tlast_reg <= input_1_axis_tlast_reg;
output_2_axis_tuser_reg <= input_1_axis_tuser_reg;
end
2'd2: begin
output_2_axis_tdata_reg <= input_2_axis_tdata_reg;
output_2_axis_tlast_reg <= input_2_axis_tlast_reg;
output_2_axis_tuser_reg <= input_2_axis_tuser_reg;
end
2'd3: begin
output_2_axis_tdata_reg <= input_3_axis_tdata_reg;
output_2_axis_tlast_reg <= input_3_axis_tlast_reg;
output_2_axis_tuser_reg <= input_3_axis_tuser_reg;
end
endcase
case (output_3_select_reg)
2'd0: begin
output_3_axis_tdata_reg <= input_0_axis_tdata_reg;
output_3_axis_tlast_reg <= input_0_axis_tlast_reg;
output_3_axis_tuser_reg <= input_0_axis_tuser_reg;
end
2'd1: begin
output_3_axis_tdata_reg <= input_1_axis_tdata_reg;
output_3_axis_tlast_reg <= input_1_axis_tlast_reg;
output_3_axis_tuser_reg <= input_1_axis_tuser_reg;
end
2'd2: begin
output_3_axis_tdata_reg <= input_2_axis_tdata_reg;
output_3_axis_tlast_reg <= input_2_axis_tlast_reg;
output_3_axis_tuser_reg <= input_2_axis_tuser_reg;
end
2'd3: begin
output_3_axis_tdata_reg <= input_3_axis_tdata_reg;
output_3_axis_tlast_reg <= input_3_axis_tlast_reg;
output_3_axis_tuser_reg <= input_3_axis_tuser_reg;
end
endcase
end
endmodule

View File

@ -40,7 +40,7 @@ def generate(ports=4, name=None, output=None):
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
of this software and associated documentation files (the "Software"), to deal
@ -106,23 +106,23 @@ module {{name}} #
{%- endfor %}
);
{% for p in ports %}
reg [DATA_WIDTH-1:0] input_{{p}}_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] input_{{p}}_axis_tkeep_reg = 0;
reg input_{{p}}_axis_tvalid_reg = 0;
reg input_{{p}}_axis_tlast_reg = 0;
reg input_{{p}}_axis_tuser_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 = {KEEP_WIDTH{1'b0}};
reg input_{{p}}_axis_tvalid_reg = 1'b0;
reg input_{{p}}_axis_tlast_reg = 1'b0;
reg input_{{p}}_axis_tuser_reg = 1'b0;
{% endfor %}
{%- for p in ports %}
reg [DATA_WIDTH-1:0] output_{{p}}_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] output_{{p}}_axis_tkeep_reg = 0;
reg output_{{p}}_axis_tvalid_reg = 0;
reg output_{{p}}_axis_tlast_reg = 0;
reg output_{{p}}_axis_tuser_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 = {KEEP_WIDTH{1'b0}};
reg output_{{p}}_axis_tvalid_reg = 1'b0;
reg output_{{p}}_axis_tlast_reg = 1'b0;
reg output_{{p}}_axis_tuser_reg = 1'b0;
{% endfor %}
{%- for p in ports %}
reg [{{w-1}}:0] output_{{p}}_select_reg = 0;
reg [{{w-1}}:0] output_{{p}}_select_reg = {{w}}'d0;
{%- endfor %}
{% for p in ports %}
assign output_{{p}}_axis_tdata = output_{{p}}_axis_tdata_reg;
@ -135,48 +135,50 @@ assign output_{{p}}_axis_tuser = output_{{p}}_axis_tuser_reg;
always @(posedge clk) begin
if (rst) begin
{%- for p in ports %}
output_{{p}}_select_reg <= 0;
output_{{p}}_select_reg <= {{w}}'d0;
{%- endfor %}
{% for p in ports %}
input_{{p}}_axis_tdata_reg <= 0;
input_{{p}}_axis_tkeep_reg <= 0;
input_{{p}}_axis_tvalid_reg <= 0;
input_{{p}}_axis_tlast_reg <= 0;
input_{{p}}_axis_tuser_reg <= 0;
input_{{p}}_axis_tvalid_reg <= 1'b0;
{%- endfor %}
{% for p in ports %}
output_{{p}}_axis_tdata_reg <= 0;
output_{{p}}_axis_tkeep_reg <= 0;
output_{{p}}_axis_tvalid_reg <= 0;
output_{{p}}_axis_tlast_reg <= 0;
output_{{p}}_axis_tuser_reg <= 0;
output_{{p}}_axis_tvalid_reg <= 1'b0;
{%- endfor %}
end else begin
{%- for p in ports %}
input_{{p}}_axis_tdata_reg <= input_{{p}}_axis_tdata;
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_tuser_reg <= input_{{p}}_axis_tuser;
{% endfor %}
{%- for p in ports %}
{%- 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}}: begin
output_{{p}}_axis_tdata_reg <= input_{{q}}_axis_tdata_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_tuser_reg <= input_{{q}}_axis_tuser_reg;
end
{{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_tkeep_reg <= input_{{p}}_axis_tkeep;
input_{{p}}_axis_tlast_reg <= input_{{p}}_axis_tlast;
input_{{p}}_axis_tuser_reg <= input_{{p}}_axis_tuser;
{%- endfor %}
{%- for p in ports %}
case (output_{{p}}_select_reg)
{%- for q in ports %}
{{w}}'d{{q}}: begin
output_{{p}}_axis_tdata_reg <= input_{{q}}_axis_tdata_reg;
output_{{p}}_axis_tkeep_reg <= input_{{q}}_axis_tkeep_reg;
output_{{p}}_axis_tlast_reg <= input_{{q}}_axis_tlast_reg;
output_{{p}}_axis_tuser_reg <= input_{{q}}_axis_tuser_reg;
end
{%- endfor %}
endcase
{%- endfor %}
end
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
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
);
reg [DATA_WIDTH-1:0] input_0_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] input_0_axis_tkeep_reg = 0;
reg input_0_axis_tvalid_reg = 0;
reg input_0_axis_tlast_reg = 0;
reg input_0_axis_tuser_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 = {KEEP_WIDTH{1'b0}};
reg input_0_axis_tvalid_reg = 1'b0;
reg input_0_axis_tlast_reg = 1'b0;
reg input_0_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] input_1_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] input_1_axis_tkeep_reg = 0;
reg input_1_axis_tvalid_reg = 0;
reg input_1_axis_tlast_reg = 0;
reg input_1_axis_tuser_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 = {KEEP_WIDTH{1'b0}};
reg input_1_axis_tvalid_reg = 1'b0;
reg input_1_axis_tlast_reg = 1'b0;
reg input_1_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] input_2_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] input_2_axis_tkeep_reg = 0;
reg input_2_axis_tvalid_reg = 0;
reg input_2_axis_tlast_reg = 0;
reg input_2_axis_tuser_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 = {KEEP_WIDTH{1'b0}};
reg input_2_axis_tvalid_reg = 1'b0;
reg input_2_axis_tlast_reg = 1'b0;
reg input_2_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] input_3_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] input_3_axis_tkeep_reg = 0;
reg input_3_axis_tvalid_reg = 0;
reg input_3_axis_tlast_reg = 0;
reg input_3_axis_tuser_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 = {KEEP_WIDTH{1'b0}};
reg input_3_axis_tvalid_reg = 1'b0;
reg input_3_axis_tlast_reg = 1'b0;
reg input_3_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] output_0_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] output_0_axis_tkeep_reg = 0;
reg output_0_axis_tvalid_reg = 0;
reg output_0_axis_tlast_reg = 0;
reg output_0_axis_tuser_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 = {KEEP_WIDTH{1'b0}};
reg output_0_axis_tvalid_reg = 1'b0;
reg output_0_axis_tlast_reg = 1'b0;
reg output_0_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] output_1_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] output_1_axis_tkeep_reg = 0;
reg output_1_axis_tvalid_reg = 0;
reg output_1_axis_tlast_reg = 0;
reg output_1_axis_tuser_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 = {KEEP_WIDTH{1'b0}};
reg output_1_axis_tvalid_reg = 1'b0;
reg output_1_axis_tlast_reg = 1'b0;
reg output_1_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] output_2_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] output_2_axis_tkeep_reg = 0;
reg output_2_axis_tvalid_reg = 0;
reg output_2_axis_tlast_reg = 0;
reg output_2_axis_tuser_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 = {KEEP_WIDTH{1'b0}};
reg output_2_axis_tvalid_reg = 1'b0;
reg output_2_axis_tlast_reg = 1'b0;
reg output_2_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] output_3_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] output_3_axis_tkeep_reg = 0;
reg output_3_axis_tvalid_reg = 0;
reg output_3_axis_tlast_reg = 0;
reg output_3_axis_tuser_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 = {KEEP_WIDTH{1'b0}};
reg output_3_axis_tvalid_reg = 1'b0;
reg output_3_axis_tlast_reg = 1'b0;
reg output_3_axis_tuser_reg = 1'b0;
reg [1:0] output_0_select_reg = 0;
reg [1:0] output_1_select_reg = 0;
reg [1:0] output_2_select_reg = 0;
reg [1:0] output_3_select_reg = 0;
reg [1:0] output_0_select_reg = 2'd0;
reg [1:0] output_1_select_reg = 2'd0;
reg [1:0] output_2_select_reg = 2'd0;
reg [1:0] output_3_select_reg = 2'd0;
assign output_0_axis_tdata = output_0_axis_tdata_reg;
assign output_0_axis_tkeep = output_0_axis_tkeep_reg;
@ -181,76 +181,25 @@ assign output_3_axis_tuser = output_3_axis_tuser_reg;
always @(posedge clk) begin
if (rst) begin
output_0_select_reg <= 0;
output_1_select_reg <= 0;
output_2_select_reg <= 0;
output_3_select_reg <= 0;
output_0_select_reg <= 2'd0;
output_1_select_reg <= 2'd0;
output_2_select_reg <= 2'd0;
output_3_select_reg <= 2'd0;
input_0_axis_tdata_reg <= 0;
input_0_axis_tkeep_reg <= 0;
input_0_axis_tvalid_reg <= 0;
input_0_axis_tlast_reg <= 0;
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;
input_0_axis_tvalid_reg <= 1'b0;
input_1_axis_tvalid_reg <= 1'b0;
input_2_axis_tvalid_reg <= 1'b0;
input_3_axis_tvalid_reg <= 1'b0;
output_0_axis_tdata_reg <= 0;
output_0_axis_tkeep_reg <= 0;
output_0_axis_tvalid_reg <= 0;
output_0_axis_tlast_reg <= 0;
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;
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;
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_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_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_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_tlast_reg <= input_3_axis_tlast;
input_3_axis_tuser_reg <= input_3_axis_tuser;
output_0_select_reg <= output_0_select;
output_1_select_reg <= output_1_select;
@ -258,129 +207,161 @@ always @(posedge clk) begin
output_3_select_reg <= output_3_select;
case (output_0_select_reg)
2'd0: begin
output_0_axis_tdata_reg <= input_0_axis_tdata_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_tuser_reg <= input_0_axis_tuser_reg;
end
2'd1: begin
output_0_axis_tdata_reg <= input_1_axis_tdata_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_tuser_reg <= input_1_axis_tuser_reg;
end
2'd2: begin
output_0_axis_tdata_reg <= input_2_axis_tdata_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_tuser_reg <= input_2_axis_tuser_reg;
end
2'd3: begin
output_0_axis_tdata_reg <= input_3_axis_tdata_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_tuser_reg <= input_3_axis_tuser_reg;
end
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: begin
output_1_axis_tdata_reg <= input_0_axis_tdata_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_tuser_reg <= input_0_axis_tuser_reg;
end
2'd1: begin
output_1_axis_tdata_reg <= input_1_axis_tdata_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_tuser_reg <= input_1_axis_tuser_reg;
end
2'd2: begin
output_1_axis_tdata_reg <= input_2_axis_tdata_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_tuser_reg <= input_2_axis_tuser_reg;
end
2'd3: begin
output_1_axis_tdata_reg <= input_3_axis_tdata_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_tuser_reg <= input_3_axis_tuser_reg;
end
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: begin
output_2_axis_tdata_reg <= input_0_axis_tdata_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_tuser_reg <= input_0_axis_tuser_reg;
end
2'd1: begin
output_2_axis_tdata_reg <= input_1_axis_tdata_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_tuser_reg <= input_1_axis_tuser_reg;
end
2'd2: begin
output_2_axis_tdata_reg <= input_2_axis_tdata_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_tuser_reg <= input_2_axis_tuser_reg;
end
2'd3: begin
output_2_axis_tdata_reg <= input_3_axis_tdata_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_tuser_reg <= input_3_axis_tuser_reg;
end
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: begin
output_3_axis_tdata_reg <= input_0_axis_tdata_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_tuser_reg <= input_0_axis_tuser_reg;
end
2'd1: begin
output_3_axis_tdata_reg <= input_1_axis_tdata_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_tuser_reg <= input_1_axis_tuser_reg;
end
2'd2: begin
output_3_axis_tdata_reg <= input_2_axis_tdata_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_tuser_reg <= input_2_axis_tuser_reg;
end
2'd3: begin
output_3_axis_tdata_reg <= input_3_axis_tdata_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_tuser_reg <= input_3_axis_tuser_reg;
end
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)
2'd0: begin
output_0_axis_tdata_reg <= input_0_axis_tdata_reg;
output_0_axis_tkeep_reg <= input_0_axis_tkeep_reg;
output_0_axis_tlast_reg <= input_0_axis_tlast_reg;
output_0_axis_tuser_reg <= input_0_axis_tuser_reg;
end
2'd1: begin
output_0_axis_tdata_reg <= input_1_axis_tdata_reg;
output_0_axis_tkeep_reg <= input_1_axis_tkeep_reg;
output_0_axis_tlast_reg <= input_1_axis_tlast_reg;
output_0_axis_tuser_reg <= input_1_axis_tuser_reg;
end
2'd2: begin
output_0_axis_tdata_reg <= input_2_axis_tdata_reg;
output_0_axis_tkeep_reg <= input_2_axis_tkeep_reg;
output_0_axis_tlast_reg <= input_2_axis_tlast_reg;
output_0_axis_tuser_reg <= input_2_axis_tuser_reg;
end
2'd3: begin
output_0_axis_tdata_reg <= input_3_axis_tdata_reg;
output_0_axis_tkeep_reg <= input_3_axis_tkeep_reg;
output_0_axis_tlast_reg <= input_3_axis_tlast_reg;
output_0_axis_tuser_reg <= input_3_axis_tuser_reg;
end
endcase
case (output_1_select_reg)
2'd0: begin
output_1_axis_tdata_reg <= input_0_axis_tdata_reg;
output_1_axis_tkeep_reg <= input_0_axis_tkeep_reg;
output_1_axis_tlast_reg <= input_0_axis_tlast_reg;
output_1_axis_tuser_reg <= input_0_axis_tuser_reg;
end
2'd1: begin
output_1_axis_tdata_reg <= input_1_axis_tdata_reg;
output_1_axis_tkeep_reg <= input_1_axis_tkeep_reg;
output_1_axis_tlast_reg <= input_1_axis_tlast_reg;
output_1_axis_tuser_reg <= input_1_axis_tuser_reg;
end
2'd2: begin
output_1_axis_tdata_reg <= input_2_axis_tdata_reg;
output_1_axis_tkeep_reg <= input_2_axis_tkeep_reg;
output_1_axis_tlast_reg <= input_2_axis_tlast_reg;
output_1_axis_tuser_reg <= input_2_axis_tuser_reg;
end
2'd3: begin
output_1_axis_tdata_reg <= input_3_axis_tdata_reg;
output_1_axis_tkeep_reg <= input_3_axis_tkeep_reg;
output_1_axis_tlast_reg <= input_3_axis_tlast_reg;
output_1_axis_tuser_reg <= input_3_axis_tuser_reg;
end
endcase
case (output_2_select_reg)
2'd0: begin
output_2_axis_tdata_reg <= input_0_axis_tdata_reg;
output_2_axis_tkeep_reg <= input_0_axis_tkeep_reg;
output_2_axis_tlast_reg <= input_0_axis_tlast_reg;
output_2_axis_tuser_reg <= input_0_axis_tuser_reg;
end
2'd1: begin
output_2_axis_tdata_reg <= input_1_axis_tdata_reg;
output_2_axis_tkeep_reg <= input_1_axis_tkeep_reg;
output_2_axis_tlast_reg <= input_1_axis_tlast_reg;
output_2_axis_tuser_reg <= input_1_axis_tuser_reg;
end
2'd2: begin
output_2_axis_tdata_reg <= input_2_axis_tdata_reg;
output_2_axis_tkeep_reg <= input_2_axis_tkeep_reg;
output_2_axis_tlast_reg <= input_2_axis_tlast_reg;
output_2_axis_tuser_reg <= input_2_axis_tuser_reg;
end
2'd3: begin
output_2_axis_tdata_reg <= input_3_axis_tdata_reg;
output_2_axis_tkeep_reg <= input_3_axis_tkeep_reg;
output_2_axis_tlast_reg <= input_3_axis_tlast_reg;
output_2_axis_tuser_reg <= input_3_axis_tuser_reg;
end
endcase
case (output_3_select_reg)
2'd0: begin
output_3_axis_tdata_reg <= input_0_axis_tdata_reg;
output_3_axis_tkeep_reg <= input_0_axis_tkeep_reg;
output_3_axis_tlast_reg <= input_0_axis_tlast_reg;
output_3_axis_tuser_reg <= input_0_axis_tuser_reg;
end
2'd1: begin
output_3_axis_tdata_reg <= input_1_axis_tdata_reg;
output_3_axis_tkeep_reg <= input_1_axis_tkeep_reg;
output_3_axis_tlast_reg <= input_1_axis_tlast_reg;
output_3_axis_tuser_reg <= input_1_axis_tuser_reg;
end
2'd2: begin
output_3_axis_tdata_reg <= input_2_axis_tdata_reg;
output_3_axis_tkeep_reg <= input_2_axis_tkeep_reg;
output_3_axis_tlast_reg <= input_2_axis_tlast_reg;
output_3_axis_tuser_reg <= input_2_axis_tuser_reg;
end
2'd3: begin
output_3_axis_tdata_reg <= input_3_axis_tdata_reg;
output_3_axis_tkeep_reg <= input_3_axis_tkeep_reg;
output_3_axis_tlast_reg <= input_3_axis_tlast_reg;
output_3_axis_tuser_reg <= input_3_axis_tuser_reg;
end
endcase
end
endmodule

View File

@ -40,7 +40,7 @@ def generate(ports=4, name=None, output=None):
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
of this software and associated documentation files (the "Software"), to deal
@ -103,15 +103,15 @@ module {{name}} #
input wire [{{w-1}}:0] select
);
reg [{{w-1}}:0] select_reg = 0, select_next;
reg frame_reg = 0, frame_next;
reg [{{w-1}}:0] select_reg = {{w}}'d0, select_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
reg [DATA_WIDTH-1:0] output_axis_tdata_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_tuser_int;
wire output_axis_tready_int_early;
@ -129,6 +129,10 @@ always @* begin
current_output_tready = output_{{p}}_axis_tready;
end
{%- endfor %}
default: begin
current_output_tvalid = 1'b0;
current_output_tready = 1'b0;
end
endcase
end
@ -136,7 +140,7 @@ always @* begin
select_next = select_reg;
frame_next = frame_reg;
input_axis_tready_next = 0;
input_axis_tready_next = 1'b0;
if (frame_reg) begin
if (input_axis_tvalid & input_axis_tready) begin
@ -145,7 +149,7 @@ always @* begin
end
end else if (enable & input_axis_tvalid & ~current_output_tvalid) begin
// start of frame, grab select value
frame_next = 1;
frame_next = 1'b1;
select_next = select;
end
@ -159,9 +163,9 @@ end
always @(posedge clk) begin
if (rst) begin
select_reg <= 0;
frame_reg <= 0;
input_axis_tready_reg <= 0;
select_reg <= {{w}}'d0;
frame_reg <= 1'b0;
input_axis_tready_reg <= 1'b0;
end else begin
select_reg <= select_next;
frame_reg <= frame_next;
@ -170,77 +174,95 @@ always @(posedge clk) begin
end
// 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 %}
reg output_{{p}}_axis_tvalid_reg = 0;
reg output_{{p}}_axis_tvalid_reg = 1'b0, output_{{p}}_axis_tvalid_next;
{%- endfor %}
reg output_axis_tlast_reg = 0;
reg output_axis_tuser_reg = 0;
reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0;
reg temp_axis_tvalid_reg = 0;
reg temp_axis_tlast_reg = 0;
reg temp_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 1'b0;
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 %}
assign output_{{p}}_axis_tdata = output_axis_tdata_reg;
assign output_{{p}}_axis_tvalid = output_{{p}}_axis_tvalid_reg;
assign output_{{p}}_axis_tlast = output_axis_tlast_reg;
assign output_{{p}}_axis_tuser = output_axis_tuser_reg;
{% 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
assign output_axis_tready_int_early = current_output_tready | (~temp_axis_tvalid_reg & ~current_output_tvalid) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int);
// 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 | ~output_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
{%- for p in ports %}
output_{{p}}_axis_tvalid_next = output_{{p}}_axis_tvalid_reg;
{%- endfor %}
temp_axis_tvalid_next = temp_axis_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (output_axis_tready_int_reg) begin
// input is ready
if (current_output_tready | ~current_output_tvalid) begin
// output is ready or currently not valid, transfer data to output
{%- for p in ports %}
output_{{p}}_axis_tvalid_next = output_axis_tvalid_int & (select_reg == {{w}}'d{{p}});
{%- endfor %}
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (current_output_tready) begin
// 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
output_axis_tdata_reg <= 0;
{%- for p in ports %}
output_{{p}}_axis_tvalid_reg <= 0;
output_{{p}}_axis_tvalid_reg <= 1'b0;
{%- 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;
output_axis_tready_int_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
// transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early;
{%- 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
if (output_axis_tready_int) begin
// input is ready
if (current_output_tready | ~current_output_tvalid) begin
// 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 %}
{{w}}'d{{p}}: output_{{p}}_axis_tvalid_reg <= output_axis_tvalid_int;
{%- endfor %}
endcase
output_axis_tlast_reg <= output_axis_tlast_int;
output_axis_tuser_reg <= output_axis_tuser_int;
end else begin
// output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int;
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 else if (current_output_tready) begin
// input is not ready, but output is ready
output_axis_tdata_reg <= temp_axis_tdata_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_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
// 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_tuser_reg <= temp_axis_tuser_reg;
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

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
of this software and associated documentation files (the "Software"), to deal
@ -80,15 +80,15 @@ module axis_demux_4 #
input wire [1:0] select
);
reg [1:0] select_reg = 0, select_next;
reg frame_reg = 0, frame_next;
reg [1:0] select_reg = 2'd0, select_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
reg [DATA_WIDTH-1:0] output_axis_tdata_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_tuser_int;
wire output_axis_tready_int_early;
@ -116,6 +116,10 @@ always @* begin
current_output_tvalid = output_3_axis_tvalid;
current_output_tready = output_3_axis_tready;
end
default: begin
current_output_tvalid = 1'b0;
current_output_tready = 1'b0;
end
endcase
end
@ -123,7 +127,7 @@ always @* begin
select_next = select_reg;
frame_next = frame_reg;
input_axis_tready_next = 0;
input_axis_tready_next = 1'b0;
if (frame_reg) begin
if (input_axis_tvalid & input_axis_tready) begin
@ -132,7 +136,7 @@ always @* begin
end
end else if (enable & input_axis_tvalid & ~current_output_tvalid) begin
// start of frame, grab select value
frame_next = 1;
frame_next = 1'b1;
select_next = select;
end
@ -146,9 +150,9 @@ end
always @(posedge clk) begin
if (rst) begin
select_reg <= 0;
frame_reg <= 0;
input_axis_tready_reg <= 0;
select_reg <= 2'd0;
frame_reg <= 1'b0;
input_axis_tready_reg <= 1'b0;
end else begin
select_reg <= select_next;
frame_reg <= frame_next;
@ -157,18 +161,23 @@ always @(posedge clk) begin
end
// output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0;
reg output_0_axis_tvalid_reg = 0;
reg output_1_axis_tvalid_reg = 0;
reg output_2_axis_tvalid_reg = 0;
reg output_3_axis_tvalid_reg = 0;
reg output_axis_tlast_reg = 0;
reg output_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg output_0_axis_tvalid_reg = 1'b0, output_0_axis_tvalid_next;
reg output_1_axis_tvalid_reg = 1'b0, output_1_axis_tvalid_next;
reg output_2_axis_tvalid_reg = 1'b0, output_2_axis_tvalid_next;
reg output_3_axis_tvalid_reg = 1'b0, output_3_axis_tvalid_next;
reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0;
reg temp_axis_tvalid_reg = 0;
reg temp_axis_tlast_reg = 0;
reg temp_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 1'b0;
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_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_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
assign output_axis_tready_int_early = current_output_tready | (~temp_axis_tvalid_reg & ~current_output_tvalid) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int);
// 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 | ~output_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
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;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (output_axis_tready_int_reg) begin
// input is ready
if (current_output_tready | ~current_output_tvalid) begin
// output is ready or currently not valid, transfer data to output
output_0_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd0);
output_1_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd1);
output_2_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd2);
output_3_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd3);
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (current_output_tready) begin
// 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_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;
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
// transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early;
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
if (output_axis_tready_int) begin
// input is ready
if (current_output_tready | ~current_output_tvalid) begin
// output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int;
case (select_reg)
2'd0: output_0_axis_tvalid_reg <= output_axis_tvalid_int;
2'd1: output_1_axis_tvalid_reg <= output_axis_tvalid_int;
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
// output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int;
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 else if (current_output_tready) begin
// input is not ready, but output is ready
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_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
// 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_tuser_reg <= temp_axis_tuser_reg;
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

View File

@ -40,7 +40,7 @@ def generate(ports=4, name=None, output=None):
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
of this software and associated documentation files (the "Software"), to deal
@ -106,16 +106,16 @@ module {{name}} #
input wire [{{w-1}}:0] select
);
reg [{{w-1}}:0] select_reg = 0, select_next;
reg frame_reg = 0, frame_next;
reg [{{w-1}}:0] select_reg = {{w}}'d0, select_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
reg [DATA_WIDTH-1:0] output_axis_tdata_int;
reg [KEEP_WIDTH-1:0] output_axis_tkeep_int;
reg output_axis_tvalid_int;
reg output_axis_tready_int = 0;
reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int;
reg output_axis_tuser_int;
wire output_axis_tready_int_early;
@ -133,6 +133,10 @@ always @* begin
current_output_tready = output_{{p}}_axis_tready;
end
{%- endfor %}
default: begin
current_output_tvalid = 1'b0;
current_output_tready = 1'b0;
end
endcase
end
@ -140,7 +144,7 @@ always @* begin
select_next = select_reg;
frame_next = frame_reg;
input_axis_tready_next = 0;
input_axis_tready_next = 1'b0;
if (frame_reg) begin
if (input_axis_tvalid & input_axis_tready) begin
@ -149,7 +153,7 @@ always @* begin
end
end else if (enable & input_axis_tvalid & ~current_output_tvalid) begin
// start of frame, grab select value
frame_next = 1;
frame_next = 1'b1;
select_next = select;
end
@ -164,9 +168,9 @@ end
always @(posedge clk) begin
if (rst) begin
select_reg <= 0;
frame_reg <= 0;
input_axis_tready_reg <= 0;
select_reg <= {{w}}'d0;
frame_reg <= 1'b0;
input_axis_tready_reg <= 1'b0;
end else begin
select_reg <= select_next;
frame_reg <= frame_next;
@ -175,19 +179,24 @@ always @(posedge clk) begin
end
// output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0;
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}};
{%- 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 %}
reg output_axis_tlast_reg = 0;
reg output_axis_tuser_reg = 0;
reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0;
reg temp_axis_tvalid_reg = 0;
reg temp_axis_tlast_reg = 0;
reg temp_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 1'b0;
reg 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 %}
assign output_{{p}}_axis_tdata = output_axis_tdata_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_tuser = output_axis_tuser_reg;
{% 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
assign output_axis_tready_int_early = current_output_tready | (~temp_axis_tvalid_reg & ~current_output_tvalid) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int);
// 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 | ~output_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
{%- for p in ports %}
output_{{p}}_axis_tvalid_next = output_{{p}}_axis_tvalid_reg;
{%- endfor %}
temp_axis_tvalid_next = temp_axis_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (output_axis_tready_int_reg) begin
// input is ready
if (current_output_tready | ~current_output_tvalid) begin
// output is ready or currently not valid, transfer data to output
{%- for p in ports %}
output_{{p}}_axis_tvalid_next = output_axis_tvalid_int & (select_reg == {{w}}'d{{p}});
{%- endfor %}
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (current_output_tready) begin
// 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
output_axis_tdata_reg <= 0;
output_axis_tkeep_reg <= 0;
{%- for p in ports %}
output_{{p}}_axis_tvalid_reg <= 0;
output_{{p}}_axis_tvalid_reg <= 1'b0;
{%- 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;
output_axis_tready_int_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
// transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early;
{%- 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
if (output_axis_tready_int) begin
// input is ready
if (current_output_tready | ~current_output_tvalid) begin
// 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 %}
{{w}}'d{{p}}: output_{{p}}_axis_tvalid_reg <= output_axis_tvalid_int;
{%- endfor %}
endcase
output_axis_tlast_reg <= output_axis_tlast_int;
output_axis_tuser_reg <= output_axis_tuser_int;
end else begin
// output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int;
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 else if (current_output_tready) begin
// input is not ready, but output is ready
output_axis_tdata_reg <= temp_axis_tdata_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_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
// 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_tkeep_reg <= temp_axis_tkeep_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg;
end
if (store_axis_int_to_temp) begin
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
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
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
);
reg [1:0] select_reg = 0, select_next;
reg frame_reg = 0, frame_next;
reg [1:0] select_reg = 2'd0, select_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
reg [DATA_WIDTH-1:0] output_axis_tdata_int;
reg [KEEP_WIDTH-1:0] output_axis_tkeep_int;
reg output_axis_tvalid_int;
reg output_axis_tready_int = 0;
reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int;
reg output_axis_tuser_int;
wire output_axis_tready_int_early;
@ -123,6 +123,10 @@ always @* begin
current_output_tvalid = output_3_axis_tvalid;
current_output_tready = output_3_axis_tready;
end
default: begin
current_output_tvalid = 1'b0;
current_output_tready = 1'b0;
end
endcase
end
@ -130,7 +134,7 @@ always @* begin
select_next = select_reg;
frame_next = frame_reg;
input_axis_tready_next = 0;
input_axis_tready_next = 1'b0;
if (frame_reg) begin
if (input_axis_tvalid & input_axis_tready) begin
@ -139,7 +143,7 @@ always @* begin
end
end else if (enable & input_axis_tvalid & ~current_output_tvalid) begin
// start of frame, grab select value
frame_next = 1;
frame_next = 1'b1;
select_next = select;
end
@ -154,9 +158,9 @@ end
always @(posedge clk) begin
if (rst) begin
select_reg <= 0;
frame_reg <= 0;
input_axis_tready_reg <= 0;
select_reg <= 2'd0;
frame_reg <= 1'b0;
input_axis_tready_reg <= 1'b0;
end else begin
select_reg <= select_next;
frame_reg <= frame_next;
@ -165,20 +169,25 @@ always @(posedge clk) begin
end
// output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0;
reg output_0_axis_tvalid_reg = 0;
reg output_1_axis_tvalid_reg = 0;
reg output_2_axis_tvalid_reg = 0;
reg output_3_axis_tvalid_reg = 0;
reg output_axis_tlast_reg = 0;
reg output_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_0_axis_tvalid_reg = 1'b0, output_0_axis_tvalid_next;
reg output_1_axis_tvalid_reg = 1'b0, output_1_axis_tvalid_next;
reg output_2_axis_tvalid_reg = 1'b0, output_2_axis_tvalid_next;
reg output_3_axis_tvalid_reg = 1'b0, output_3_axis_tvalid_next;
reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0;
reg temp_axis_tvalid_reg = 0;
reg temp_axis_tlast_reg = 0;
reg temp_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 1'b0;
reg 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_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_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
assign output_axis_tready_int_early = current_output_tready | (~temp_axis_tvalid_reg & ~current_output_tvalid) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int);
// 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 | ~output_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
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;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (output_axis_tready_int_reg) begin
// input is ready
if (current_output_tready | ~current_output_tvalid) begin
// output is ready or currently not valid, transfer data to output
output_0_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd0);
output_1_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd1);
output_2_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd2);
output_3_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd3);
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (current_output_tready) begin
// 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_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;
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
// transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early;
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
if (output_axis_tready_int) begin
// input is ready
if (current_output_tready | ~current_output_tvalid) begin
// 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)
2'd0: output_0_axis_tvalid_reg <= output_axis_tvalid_int;
2'd1: output_1_axis_tvalid_reg <= output_axis_tvalid_int;
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
// output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int;
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 else if (current_output_tready) begin
// input is not ready, but output is ready
output_axis_tdata_reg <= temp_axis_tdata_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_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
// 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_tkeep_reg <= temp_axis_tkeep_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg;
end
if (store_axis_int_to_temp) begin
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
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
of this software and associated documentation files (the "Software"), to deal
@ -57,60 +57,93 @@ module axis_fifo #
output wire output_axis_tuser
);
reg [ADDR_WIDTH:0] wr_ptr = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_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_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 output_axis_tvalid_reg = 1'b0;
wire [DATA_WIDTH+2-1:0] data_in = {input_axis_tlast, input_axis_tuser, input_axis_tdata};
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
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
wire full = ((wr_ptr[ADDR_WIDTH] != rd_ptr[ADDR_WIDTH]) &&
(wr_ptr[ADDR_WIDTH-1:0] == rd_ptr[ADDR_WIDTH-1:0]));
wire full = ((wr_ptr_reg[ADDR_WIDTH] != rd_ptr_reg[ADDR_WIDTH]) &&
(wr_ptr_reg[ADDR_WIDTH-1:0] == rd_ptr_reg[ADDR_WIDTH-1:0]));
// 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;
wire read = (output_axis_tready | ~output_axis_tvalid_reg) & ~empty;
assign {output_axis_tlast, output_axis_tuser, output_axis_tdata} = data_out_reg;
// control signals
reg write;
reg read;
assign input_axis_tready = ~full;
assign output_axis_tdata = output_axis_tdata_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
always @(posedge clk) begin
if (rst) begin
wr_ptr <= 0;
end else if (write) begin
mem[wr_ptr[ADDR_WIDTH-1:0]] <= data_in;
wr_ptr <= wr_ptr + 1;
// Write logic
always @* begin
write = 1'b0;
wr_ptr_next = wr_ptr_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;
end
end
end
// read
always @(posedge clk) begin
if (rst) begin
rd_ptr <= 0;
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;
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
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

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
of this software and associated documentation files (the "Software"), to deal
@ -60,60 +60,96 @@ module axis_fifo_64 #
output wire output_axis_tuser
);
reg [ADDR_WIDTH:0] wr_ptr = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_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_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 output_axis_tvalid_reg = 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 [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 1'b0;
// full when first MSB different but rest same
wire full = ((wr_ptr[ADDR_WIDTH] != rd_ptr[ADDR_WIDTH]) &&
(wr_ptr[ADDR_WIDTH-1:0] == rd_ptr[ADDR_WIDTH-1:0]));
wire full = ((wr_ptr_reg[ADDR_WIDTH] != rd_ptr_reg[ADDR_WIDTH]) &&
(wr_ptr_reg[ADDR_WIDTH-1:0] == rd_ptr_reg[ADDR_WIDTH-1:0]));
// 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;
wire read = (output_axis_tready | ~output_axis_tvalid_reg) & ~empty;
assign {output_axis_tlast, output_axis_tuser, output_axis_tkeep, output_axis_tdata} = data_out_reg;
// control signals
reg write;
reg read;
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_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg;
// write
always @(posedge clk) begin
if (rst) begin
wr_ptr <= 0;
end else if (write) begin
mem[wr_ptr[ADDR_WIDTH-1:0]] <= data_in;
wr_ptr <= wr_ptr + 1;
// FIFO write logic
always @* begin
write = 1'b0;
wr_ptr_next = wr_ptr_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;
end
end
end
// read
always @(posedge clk) begin
if (rst) begin
rd_ptr <= 0;
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;
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
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

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
of this software and associated documentation files (the "Software"), to deal
@ -64,106 +64,147 @@ module axis_frame_fifo #
output wire good_frame
);
reg [ADDR_WIDTH:0] wr_ptr = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] wr_ptr_cur = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_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_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_cur_next;
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 output_axis_tvalid_reg = 1'b0;
wire [DATA_WIDTH+1-1:0] data_in = {input_axis_tlast, input_axis_tdata};
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
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
wire full = ((wr_ptr[ADDR_WIDTH] != rd_ptr[ADDR_WIDTH]) &&
(wr_ptr[ADDR_WIDTH-1:0] == rd_ptr[ADDR_WIDTH-1:0]));
wire full = ((wr_ptr_reg[ADDR_WIDTH] != rd_ptr_reg[ADDR_WIDTH]) &&
(wr_ptr_reg[ADDR_WIDTH-1:0] == rd_ptr_reg[ADDR_WIDTH-1:0]));
// empty when pointers match exactly
wire empty = wr_ptr == rd_ptr;
// overflow in single packet
wire full_cur = ((wr_ptr[ADDR_WIDTH] != wr_ptr_cur[ADDR_WIDTH]) &&
(wr_ptr[ADDR_WIDTH-1:0] == wr_ptr_cur[ADDR_WIDTH-1:0]));
wire empty = wr_ptr_reg == rd_ptr_reg;
// overflow within packet
wire full_cur = ((wr_ptr_reg[ADDR_WIDTH] != wr_ptr_cur_reg[ADDR_WIDTH]) &&
(wr_ptr_reg[ADDR_WIDTH-1:0] == wr_ptr_cur_reg[ADDR_WIDTH-1:0]));
wire write = input_axis_tvalid & (~full | DROP_WHEN_FULL);
wire read = (output_axis_tready | ~output_axis_tvalid_reg) & ~empty;
// control signals
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 output_axis_tdata = output_axis_tdata_reg;
assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg;
assign overflow = overflow_reg;
assign bad_frame = bad_frame_reg;
assign good_frame = good_frame_reg;
// write
always @(posedge clk) begin
if (rst) begin
wr_ptr <= 0;
wr_ptr_cur <= 0;
drop_frame <= 0;
overflow_reg <= 0;
bad_frame_reg <= 0;
good_frame_reg <= 0;
end else if (write) begin
overflow_reg <= 0;
bad_frame_reg <= 0;
good_frame_reg <= 0;
if (full | full_cur | drop_frame) begin
// buffer full, hold current pointer, drop packet at end
drop_frame <= 1;
if (input_axis_tlast) begin
wr_ptr_cur <= wr_ptr;
drop_frame <= 0;
overflow_reg <= 1;
end
end else begin
mem[wr_ptr_cur[ADDR_WIDTH-1:0]] <= data_in;
wr_ptr_cur <= wr_ptr_cur + 1;
if (input_axis_tlast) begin
if (input_axis_tuser) begin
// bad packet, reset write pointer
wr_ptr_cur <= wr_ptr;
bad_frame_reg <= 1;
end else begin
// good packet, push new write pointer
wr_ptr <= wr_ptr_cur + 1;
good_frame_reg <= 1;
// Write logic
always @* begin
write = 1'b0;
drop_frame_next = 1'b0;
overflow_next = 1'b0;
bad_frame_next = 1'b0;
good_frame_next = 1'b0;
wr_ptr_next = wr_ptr_reg;
wr_ptr_cur_next = wr_ptr_cur_reg;
if (input_axis_tvalid) begin
// input data valid
if (~full | DROP_WHEN_FULL) begin
// 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
// end of frame, reset write pointer
wr_ptr_cur_next = wr_ptr_reg;
drop_frame_next = 1'b0;
overflow_next = 1'b1;
end
end else begin
write = 1'b1;
wr_ptr_cur_next = wr_ptr_cur_reg + 1;
if (input_axis_tlast) begin
// end of frame
if (input_axis_tuser) begin
// bad packet, reset write pointer
wr_ptr_cur_next = wr_ptr_reg;
bad_frame_next = 1'b1;
end else begin
// good packet, update write pointer
wr_ptr_next = wr_ptr_cur_reg + 1;
good_frame_next = 1'b1;
end
end
end
end
end
end
always @(posedge clk) begin
if (rst) begin
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_cur_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
overflow_reg <= 0;
bad_frame_reg <= 0;
good_frame_reg <= 0;
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
always @(posedge clk) begin
if (rst) begin
rd_ptr <= 0;
end else if (read) begin
data_out_reg <= mem[rd_ptr[ADDR_WIDTH-1:0]];
rd_ptr <= rd_ptr + 1;
// 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
// source ready output
always @(posedge clk) begin
if (rst) begin
rd_ptr_reg <= {ADDR_WIDTH+1{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
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

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
of this software and associated documentation files (the "Software"), to deal
@ -67,106 +67,148 @@ module axis_frame_fifo_64 #
output wire good_frame
);
reg [ADDR_WIDTH:0] wr_ptr = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] wr_ptr_cur = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_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_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_cur_next;
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 output_axis_tvalid_reg = 1'b0;
wire [DATA_WIDTH+KEEP_WIDTH+1-1:0] data_in = {input_axis_tlast, input_axis_tkeep, input_axis_tdata};
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 1'b0;
// full when first MSB different but rest same
wire full = ((wr_ptr[ADDR_WIDTH] != rd_ptr[ADDR_WIDTH]) &&
(wr_ptr[ADDR_WIDTH-1:0] == rd_ptr[ADDR_WIDTH-1:0]));
wire full = ((wr_ptr_reg[ADDR_WIDTH] != rd_ptr_reg[ADDR_WIDTH]) &&
(wr_ptr_reg[ADDR_WIDTH-1:0] == rd_ptr_reg[ADDR_WIDTH-1:0]));
// empty when pointers match exactly
wire empty = wr_ptr == rd_ptr;
// overflow in single packet
wire full_cur = ((wr_ptr[ADDR_WIDTH] != wr_ptr_cur[ADDR_WIDTH]) &&
(wr_ptr[ADDR_WIDTH-1:0] == wr_ptr_cur[ADDR_WIDTH-1:0]));
wire empty = wr_ptr_reg == rd_ptr_reg;
// overflow within packet
wire full_cur = ((wr_ptr_reg[ADDR_WIDTH] != wr_ptr_cur_reg[ADDR_WIDTH]) &&
(wr_ptr_reg[ADDR_WIDTH-1:0] == wr_ptr_cur_reg[ADDR_WIDTH-1:0]));
wire write = input_axis_tvalid & (~full | DROP_WHEN_FULL);
wire read = (output_axis_tready | ~output_axis_tvalid_reg) & ~empty;
// control signals
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 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_tlast = output_axis_tlast_reg;
assign overflow = overflow_reg;
assign bad_frame = bad_frame_reg;
assign good_frame = good_frame_reg;
// write
always @(posedge clk) begin
if (rst) begin
wr_ptr <= 0;
wr_ptr_cur <= 0;
drop_frame <= 0;
overflow_reg <= 0;
bad_frame_reg <= 0;
good_frame_reg <= 0;
end else if (write) begin
overflow_reg <= 0;
bad_frame_reg <= 0;
good_frame_reg <= 0;
if (full | full_cur | drop_frame) begin
// buffer full, hold current pointer, drop packet at end
drop_frame <= 1;
if (input_axis_tlast) begin
wr_ptr_cur <= wr_ptr;
drop_frame <= 0;
overflow_reg <= 1;
end
end else begin
mem[wr_ptr_cur[ADDR_WIDTH-1:0]] <= data_in;
wr_ptr_cur <= wr_ptr_cur + 1;
if (input_axis_tlast) begin
if (input_axis_tuser) begin
// bad packet, reset write pointer
wr_ptr_cur <= wr_ptr;
bad_frame_reg <= 1;
end else begin
// good packet, push new write pointer
wr_ptr <= wr_ptr_cur + 1;
good_frame_reg <= 1;
// Write logic
always @* begin
write = 1'b0;
drop_frame_next = 1'b0;
overflow_next = 1'b0;
bad_frame_next = 1'b0;
good_frame_next = 1'b0;
wr_ptr_next = wr_ptr_reg;
wr_ptr_cur_next = wr_ptr_cur_reg;
if (input_axis_tvalid) begin
// input data valid
if (~full | DROP_WHEN_FULL) begin
// 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
// end of frame, reset write pointer
wr_ptr_cur_next = wr_ptr_reg;
drop_frame_next = 1'b0;
overflow_next = 1'b1;
end
end else begin
write = 1'b1;
wr_ptr_cur_next = wr_ptr_cur_reg + 1;
if (input_axis_tlast) begin
// end of frame
if (input_axis_tuser) begin
// bad packet, reset write pointer
wr_ptr_cur_next = wr_ptr_reg;
bad_frame_next = 1'b1;
end else begin
// good packet, update write pointer
wr_ptr_next = wr_ptr_cur_reg + 1;
good_frame_next = 1'b1;
end
end
end
end
end
end
always @(posedge clk) begin
if (rst) begin
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_cur_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
overflow_reg <= 0;
bad_frame_reg <= 0;
good_frame_reg <= 0;
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
always @(posedge clk) begin
if (rst) begin
rd_ptr <= 0;
end else if (read) begin
data_out_reg <= mem[rd_ptr[ADDR_WIDTH-1:0]];
rd_ptr <= rd_ptr + 1;
// 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
// source ready output
always @(posedge clk) begin
if (rst) begin
rd_ptr_reg <= {ADDR_WIDTH+1{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
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

View File

@ -40,7 +40,7 @@ def generate(ports=4, name=None, output=None):
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
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 [2:0] frame_ptr_reg = 0, frame_ptr_next;
reg [{{w-1}}:0] port_sel_reg = 0, port_sel_next;
reg [2:0] frame_ptr_reg = 3'd0, frame_ptr_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 input_tvalid;
reg input_tlast;
reg input_tuser;
reg output_tuser_reg = 0, output_tuser_next;
reg output_tuser_reg = 1'b0, output_tuser_next;
{% 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 %}
// internal datapath
reg [7:0] output_axis_tdata_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_tuser_int;
wire output_axis_tready_int_early;
@ -163,31 +163,31 @@ end
integer offset, i;
always @* begin
state_next = 2'bz;
state_next = STATE_IDLE;
frame_ptr_next = frame_ptr_reg;
port_sel_next = port_sel_reg;
{% for p in ports %}
input_{{p}}_axis_tready_next = 0;
input_{{p}}_axis_tready_next = 1'b0;
{%- endfor %}
output_axis_tdata_int = 0;
output_axis_tvalid_int = 0;
output_axis_tlast_int = 0;
output_axis_tuser_int = 0;
output_axis_tdata_int = 8'd0;
output_axis_tvalid_int = 1'b0;
output_axis_tlast_int = 1'b0;
output_axis_tuser_int = 1'b0;
output_tuser_next = output_tuser_reg;
case (state_reg)
STATE_IDLE: begin
// idle state - wait for data
frame_ptr_next = 0;
port_sel_next = 0;
output_tuser_next = 0;
frame_ptr_next = 3'd0;
port_sel_next = {{w}}'d0;
output_tuser_next = 1'b0;
if (TAG_ENABLE) begin
// 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
// next cycle if started will send data, so enable input
input_0_axis_tready_next = output_axis_tready_int_early;
@ -197,19 +197,19 @@ always @* begin
// input 0 valid; start transferring data
if (TAG_ENABLE) begin
// 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
frame_ptr_next = 1;
frame_ptr_next = 3'd1;
output_axis_tdata_int = tag[(TAG_BYTE_WIDTH-1)*8 +: 8];
output_axis_tvalid_int = 1;
output_axis_tvalid_int = 1'b1;
end
state_next = STATE_WRITE_TAG;
end else begin
// 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_axis_tdata_int = input_0_axis_tdata;
output_axis_tvalid_int = 1;
output_axis_tvalid_int = 1'b1;
end
state_next = STATE_TRANSFER;
end
@ -219,11 +219,11 @@ always @* begin
end
STATE_WRITE_TAG: begin
// write tag data
if (output_axis_tready_int) begin
if (output_axis_tready_int_reg) begin
// output ready, so send tag byte
state_next = STATE_WRITE_TAG;
frame_ptr_next = frame_ptr_reg + 1;
output_axis_tvalid_int = 1;
output_axis_tvalid_int = 1'b1;
offset = 0;
if (TAG_ENABLE) begin
@ -252,7 +252,7 @@ always @* begin
{%- endfor %}
endcase
if (input_tvalid & output_axis_tready_int) begin
if (input_tvalid & output_axis_tready_int_reg) begin
// output ready, transfer byte
state_next = STATE_TRANSFER;
output_axis_tdata_int = input_tdata;
@ -265,12 +265,12 @@ always @* begin
output_tuser_next = output_tuser_next | input_tuser;
// disable input
{%- for p in ports %}
input_{{p}}_axis_tready_next = 0;
input_{{p}}_axis_tready_next = 1'b0;
{%- 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
output_axis_tlast_int = 1;
output_axis_tlast_int = 1'b1;
output_axis_tuser_int = output_tuser_next;
state_next = STATE_IDLE;
end else begin
@ -292,13 +292,13 @@ end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
frame_ptr_reg <= 0;
port_sel_reg <= 0;
frame_ptr_reg <= 3'd0;
port_sel_reg <= {{w}}'d0;
{%- for p in ports %}
input_{{p}}_axis_tready_reg <= 0;
input_{{p}}_axis_tready_reg <= 1'b0;
{%- endfor %}
output_tuser_reg <= 0;
busy_reg <= 0;
output_tuser_reg <= 1'b0;
busy_reg <= 1'b0;
end else begin
state_reg <= state_next;
@ -316,65 +316,83 @@ always @(posedge clk) begin
end
// output datapath logic
reg [7:0] output_axis_tdata_reg = 0;
reg output_axis_tvalid_reg = 0;
reg output_axis_tlast_reg = 0;
reg output_axis_tuser_reg = 0;
reg [7:0] output_axis_tdata_reg = 8'd0;
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;
reg [7:0] temp_axis_tdata_reg = 0;
reg temp_axis_tvalid_reg = 0;
reg temp_axis_tlast_reg = 0;
reg temp_axis_tuser_reg = 0;
reg [7:0] temp_axis_tdata_reg = 8'd0;
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 1'b0;
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_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_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
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);
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (output_axis_tready_int_reg) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (output_axis_tready) begin
// input is not ready, but output is ready
output_axis_tvalid_next = temp_axis_tvalid_reg;
temp_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
output_axis_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;
output_axis_tvalid_reg <= 1'b0;
output_axis_tready_int_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
// transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early;
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
if (output_axis_tready_int) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int;
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
// output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int;
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 else if (output_axis_tready) begin
// input is not ready, but output is ready
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_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
// 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_tuser_reg <= temp_axis_tuser_reg;
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

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
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 [2:0] frame_ptr_reg = 0, frame_ptr_next;
reg [1:0] port_sel_reg = 0, port_sel_next;
reg [2:0] frame_ptr_reg = 3'd0, frame_ptr_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 input_tvalid;
reg input_tlast;
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_1_axis_tready_reg = 0, input_1_axis_tready_next;
reg input_2_axis_tready_reg = 0, input_2_axis_tready_next;
reg input_3_axis_tready_reg = 0, input_3_axis_tready_next;
reg input_0_axis_tready_reg = 1'b0, input_0_axis_tready_next;
reg input_1_axis_tready_reg = 1'b0, input_1_axis_tready_next;
reg input_2_axis_tready_reg = 1'b0, input_2_axis_tready_next;
reg input_3_axis_tready_reg = 1'b0, input_3_axis_tready_next;
// internal datapath
reg [7:0] output_axis_tdata_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_tuser_int;
wire output_axis_tready_int_early;
@ -160,33 +160,33 @@ end
integer offset, i;
always @* begin
state_next = 2'bz;
state_next = STATE_IDLE;
frame_ptr_next = frame_ptr_reg;
port_sel_next = port_sel_reg;
input_0_axis_tready_next = 0;
input_1_axis_tready_next = 0;
input_2_axis_tready_next = 0;
input_3_axis_tready_next = 0;
input_0_axis_tready_next = 1'b0;
input_1_axis_tready_next = 1'b0;
input_2_axis_tready_next = 1'b0;
input_3_axis_tready_next = 1'b0;
output_axis_tdata_int = 0;
output_axis_tvalid_int = 0;
output_axis_tlast_int = 0;
output_axis_tuser_int = 0;
output_axis_tdata_int = 8'd0;
output_axis_tvalid_int = 1'b0;
output_axis_tlast_int = 1'b0;
output_axis_tuser_int = 1'b0;
output_tuser_next = output_tuser_reg;
case (state_reg)
STATE_IDLE: begin
// idle state - wait for data
frame_ptr_next = 0;
port_sel_next = 0;
output_tuser_next = 0;
frame_ptr_next = 3'd0;
port_sel_next = 2'd0;
output_tuser_next = 1'b0;
if (TAG_ENABLE) begin
// 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
// next cycle if started will send data, so enable input
input_0_axis_tready_next = output_axis_tready_int_early;
@ -196,19 +196,19 @@ always @* begin
// input 0 valid; start transferring data
if (TAG_ENABLE) begin
// 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
frame_ptr_next = 1;
frame_ptr_next = 3'd1;
output_axis_tdata_int = tag[(TAG_BYTE_WIDTH-1)*8 +: 8];
output_axis_tvalid_int = 1;
output_axis_tvalid_int = 1'b1;
end
state_next = STATE_WRITE_TAG;
end else begin
// 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_axis_tdata_int = input_0_axis_tdata;
output_axis_tvalid_int = 1;
output_axis_tvalid_int = 1'b1;
end
state_next = STATE_TRANSFER;
end
@ -218,11 +218,11 @@ always @* begin
end
STATE_WRITE_TAG: begin
// write tag data
if (output_axis_tready_int) begin
if (output_axis_tready_int_reg) begin
// output ready, so send tag byte
state_next = STATE_WRITE_TAG;
frame_ptr_next = frame_ptr_reg + 1;
output_axis_tvalid_int = 1;
output_axis_tvalid_int = 1'b1;
offset = 0;
if (TAG_ENABLE) begin
@ -252,7 +252,7 @@ always @* begin
2'd3: input_3_axis_tready_next = output_axis_tready_int_early;
endcase
if (input_tvalid & output_axis_tready_int) begin
if (input_tvalid & output_axis_tready_int_reg) begin
// output ready, transfer byte
state_next = STATE_TRANSFER;
output_axis_tdata_int = input_tdata;
@ -264,14 +264,14 @@ always @* begin
// save tuser - assert tuser out if ANY tuser asserts received
output_tuser_next = output_tuser_next | input_tuser;
// disable input
input_0_axis_tready_next = 0;
input_1_axis_tready_next = 0;
input_2_axis_tready_next = 0;
input_3_axis_tready_next = 0;
input_0_axis_tready_next = 1'b0;
input_1_axis_tready_next = 1'b0;
input_2_axis_tready_next = 1'b0;
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
output_axis_tlast_int = 1;
output_axis_tlast_int = 1'b1;
output_axis_tuser_int = output_tuser_next;
state_next = STATE_IDLE;
end else begin
@ -294,14 +294,14 @@ end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
frame_ptr_reg <= 0;
port_sel_reg <= 0;
input_0_axis_tready_reg <= 0;
input_1_axis_tready_reg <= 0;
input_2_axis_tready_reg <= 0;
input_3_axis_tready_reg <= 0;
output_tuser_reg <= 0;
busy_reg <= 0;
frame_ptr_reg <= 3'd0;
port_sel_reg <= 2'd0;
input_0_axis_tready_reg <= 1'b0;
input_1_axis_tready_reg <= 1'b0;
input_2_axis_tready_reg <= 1'b0;
input_3_axis_tready_reg <= 1'b0;
output_tuser_reg <= 1'b0;
busy_reg <= 1'b0;
end else begin
state_reg <= state_next;
@ -321,65 +321,83 @@ always @(posedge clk) begin
end
// output datapath logic
reg [7:0] output_axis_tdata_reg = 0;
reg output_axis_tvalid_reg = 0;
reg output_axis_tlast_reg = 0;
reg output_axis_tuser_reg = 0;
reg [7:0] output_axis_tdata_reg = 8'd0;
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;
reg [7:0] temp_axis_tdata_reg = 0;
reg temp_axis_tvalid_reg = 0;
reg temp_axis_tlast_reg = 0;
reg temp_axis_tuser_reg = 0;
reg [7:0] temp_axis_tdata_reg = 8'd0;
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 1'b0;
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_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_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
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);
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (output_axis_tready_int_reg) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (output_axis_tready) begin
// input is not ready, but output is ready
output_axis_tvalid_next = temp_axis_tvalid_reg;
temp_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
output_axis_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;
output_axis_tvalid_reg <= 1'b0;
output_axis_tready_int_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
// transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early;
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
if (output_axis_tready_int) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int;
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
// output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int;
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 else if (output_axis_tready) begin
// input is not ready, but output is ready
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_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
// 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_tuser_reg <= temp_axis_tuser_reg;
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

View File

@ -98,33 +98,33 @@ reg [2:0] state_reg = STATE_IDLE, state_next;
// datapath control signals
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
reg [15:0] short_counter_reg = 0, short_counter_next = 0;
reg [15:0] long_counter_reg = 0, long_counter_next = 0;
reg [15:0] short_counter_reg = 16'd0, short_counter_next = 16'd0;
reg [15:0] long_counter_reg = 16'd0, long_counter_next = 16'd0;
reg [DATA_WIDTH-1:0] last_word_data_reg = 0;
reg [KEEP_WIDTH-1:0] last_word_keep_reg = 0;
reg [DATA_WIDTH-1:0] last_word_data_reg = {DATA_WIDTH{1'b0}};
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_frame_pad_reg = 0, status_frame_pad_next;
reg status_frame_truncate_reg = 0, status_frame_truncate_next;
reg [15:0] status_frame_length_reg = 0, status_frame_length_next;
reg [15:0] status_frame_original_length_reg = 0, status_frame_original_length_next;
reg status_valid_reg = 1'b0, status_valid_next;
reg status_frame_pad_reg = 1'b0, status_frame_pad_next;
reg status_frame_truncate_reg = 1'b0, status_frame_truncate_next;
reg [15:0] status_frame_length_reg = 16'd0, status_frame_length_next;
reg [15:0] status_frame_original_length_reg = 16'd0, status_frame_original_length_next;
// internal datapath
reg [DATA_WIDTH-1:0] output_axis_tdata_int;
reg [KEEP_WIDTH-1:0] output_axis_tkeep_int;
reg output_axis_tvalid_int;
reg output_axis_tready_int = 0;
reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int;
reg output_axis_tuser_int;
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 status_valid = status_valid_reg;
@ -138,20 +138,20 @@ integer i, word_cnt;
always @* begin
state_next = STATE_IDLE;
store_last_word = 0;
store_last_word = 1'b0;
frame_ptr_next = frame_ptr_reg;
short_counter_next = short_counter_reg;
long_counter_next = long_counter_reg;
output_axis_tdata_int = 0;
output_axis_tkeep_int = 0;
output_axis_tvalid_int = 0;
output_axis_tlast_int = 0;
output_axis_tuser_int = 0;
output_axis_tdata_int = {DATA_WIDTH{1'b0}};
output_axis_tkeep_int = {KEEP_WIDTH{1'b0}};
output_axis_tvalid_int = 1'b0;
output_axis_tlast_int = 1'b0;
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;
@ -188,31 +188,31 @@ always @* begin
if (short_counter_reg > KEEP_WIDTH) begin
short_counter_next = short_counter_reg - KEEP_WIDTH;
end else begin
short_counter_next = 0;
short_counter_next = 16'd0;
end
if (long_counter_reg > KEEP_WIDTH) begin
long_counter_next = long_counter_reg - KEEP_WIDTH;
end else begin
long_counter_next = 0;
long_counter_next = 16'd0;
end
if (long_counter_reg <= word_cnt) begin
output_axis_tkeep_int = ({KEEP_WIDTH{1'b1}}) >> (KEEP_WIDTH-long_counter_reg);
if (input_axis_tlast) begin
status_valid_next = 1;
status_frame_pad_next = 0;
status_valid_next = 1'b1;
status_frame_pad_next = 1'b0;
status_frame_truncate_next = word_cnt > long_counter_reg;
status_frame_length_next = length_max;
status_frame_original_length_next = frame_ptr_reg+word_cnt;
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;
long_counter_next = length_max;
state_next = STATE_IDLE;
end else begin
output_axis_tvalid_int = 0;
store_last_word = 1;
output_axis_tvalid_int = 1'b0;
store_last_word = 1'b1;
state_next = STATE_TRUNCATE;
end
end else begin
@ -221,32 +221,32 @@ always @* begin
if (short_counter_reg > word_cnt) begin
if (short_counter_reg > KEEP_WIDTH) begin
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_tlast_int = 0;
output_axis_tuser_int = 0;
output_axis_tlast_int = 1'b0;
output_axis_tuser_int = 1'b0;
last_cycle_tuser_next = input_axis_tuser;
state_next = STATE_PAD;
end else begin
status_valid_next = 1;
status_frame_pad_next = 1;
status_frame_truncate_next = 0;
status_valid_next = 1'b1;
status_frame_pad_next = 1'b1;
status_frame_truncate_next = 1'b0;
status_frame_length_next = length_min;
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));
frame_ptr_next = 0;
frame_ptr_next = 16'd0;
short_counter_next = length_min;
long_counter_next = length_max;
state_next = STATE_IDLE;
end
end else begin
status_valid_next = 1;
status_frame_pad_next = 0;
status_frame_truncate_next = 0;
status_valid_next = 1'b1;
status_frame_pad_next = 1'b0;
status_frame_truncate_next = 1'b0;
status_frame_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;
frame_ptr_next = 0;
frame_ptr_next = 16'd0;
short_counter_next = length_min;
long_counter_next = length_max;
state_next = STATE_IDLE;
@ -282,31 +282,31 @@ always @* begin
if (short_counter_reg > KEEP_WIDTH) begin
short_counter_next = short_counter_reg - KEEP_WIDTH;
end else begin
short_counter_next = 0;
short_counter_next = 16'd0;
end
if (long_counter_reg > KEEP_WIDTH) begin
long_counter_next = long_counter_reg - KEEP_WIDTH;
end else begin
long_counter_next = 0;
long_counter_next = 16'd0;
end
if (long_counter_reg <= word_cnt) begin
output_axis_tkeep_int = ({KEEP_WIDTH{1'b1}}) >> (KEEP_WIDTH-long_counter_reg);
if (input_axis_tlast) begin
status_valid_next = 1;
status_frame_pad_next = 0;
status_valid_next = 1'b1;
status_frame_pad_next = 1'b0;
status_frame_truncate_next = word_cnt > long_counter_reg;
status_frame_length_next = length_max;
status_frame_original_length_next = frame_ptr_reg+word_cnt;
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;
long_counter_next = length_max;
state_next = STATE_IDLE;
end else begin
output_axis_tvalid_int = 0;
store_last_word = 1;
output_axis_tvalid_int = 1'b0;
store_last_word = 1'b1;
state_next = STATE_TRUNCATE;
end
end else begin
@ -315,32 +315,32 @@ always @* begin
if (short_counter_reg > word_cnt) begin
if (short_counter_reg > KEEP_WIDTH) begin
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_tlast_int = 0;
output_axis_tuser_int = 0;
output_axis_tlast_int = 1'b0;
output_axis_tuser_int = 1'b0;
last_cycle_tuser_next = input_axis_tuser;
state_next = STATE_PAD;
end else begin
status_valid_next = 1;
status_frame_pad_next = 1;
status_frame_truncate_next = 0;
status_valid_next = 1'b1;
status_frame_pad_next = 1'b1;
status_frame_truncate_next = 1'b0;
status_frame_length_next = length_min;
input_axis_tready_next = output_axis_tready_int_early & status_ready;
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;
long_counter_next = length_max;
state_next = STATE_IDLE;
end
end else begin
status_valid_next = 1;
status_frame_pad_next = 0;
status_frame_truncate_next = 0;
status_valid_next = 1'b1;
status_frame_pad_next = 1'b0;
status_frame_truncate_next = 1'b0;
status_frame_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;
frame_ptr_next = 0;
frame_ptr_next = 16'd0;
short_counter_next = length_min;
long_counter_next = length_max;
state_next = STATE_IDLE;
@ -355,39 +355,39 @@ always @* begin
end
STATE_PAD: begin
// 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_tvalid_int = 1;
output_axis_tlast_int = 0;
output_axis_tuser_int = 0;
output_axis_tvalid_int = 1'b1;
output_axis_tlast_int = 1'b0;
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;
if (short_counter_reg > KEEP_WIDTH) begin
short_counter_next = short_counter_reg - KEEP_WIDTH;
end else begin
short_counter_next = 0;
short_counter_next = 16'd0;
end
if (long_counter_reg > KEEP_WIDTH) begin
long_counter_next = long_counter_reg - KEEP_WIDTH;
end else begin
long_counter_next = 0;
long_counter_next = 16'd0;
end
if (short_counter_reg <= KEEP_WIDTH) begin
status_valid_next = 1;
status_frame_pad_next = 1;
status_frame_truncate_next = 0;
status_valid_next = 1'b1;
status_frame_pad_next = 1'b1;
status_frame_truncate_next = 1'b0;
status_frame_length_next = length_min;
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_tlast_int = 1;
output_axis_tlast_int = 1'b1;
output_axis_tuser_int = last_cycle_tuser_reg;
frame_ptr_next = 0;
frame_ptr_next = 16'd0;
short_counter_next = length_min;
long_counter_next = length_max;
state_next = STATE_IDLE;
@ -417,13 +417,13 @@ always @* begin
frame_ptr_next = frame_ptr_reg+KEEP_WIDTH;
if (input_axis_tlast) begin
status_valid_next = 1;
status_frame_pad_next = 0;
status_frame_truncate_next = 1;
status_valid_next = 1'b1;
status_frame_pad_next = 1'b0;
status_frame_truncate_next = 1'b1;
status_frame_length_next = length_max;
status_frame_original_length_next = frame_ptr_reg+word_cnt;
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;
long_counter_next = length_max;
state_next = STATE_IDLE;
@ -440,18 +440,11 @@ end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
frame_ptr_reg <= 0;
short_counter_reg <= 0;
long_counter_reg <= 0;
input_axis_tready_reg <= 0;
last_word_data_reg <= 0;
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;
frame_ptr_reg <= 16'd0;
short_counter_reg <= 16'd0;
long_counter_reg <= 16'd0;
input_axis_tready_reg <= 1'b0;
status_valid_reg <= 1'b0;
end else begin
state_reg <= state_next;
@ -462,33 +455,39 @@ always @(posedge clk) begin
input_axis_tready_reg <= input_axis_tready_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_truncate_reg <= status_frame_truncate_next;
status_frame_length_reg <= status_frame_length_next;
status_frame_original_length_reg <= status_frame_original_length_next;
end
if (store_last_word) begin
last_word_data_reg <= output_axis_tdata_int;
last_word_keep_reg <= output_axis_tkeep_int;
end
last_cycle_tuser_reg <= last_cycle_tuser_next;
status_frame_pad_reg <= status_frame_pad_next;
status_frame_truncate_reg <= status_frame_truncate_next;
status_frame_length_reg <= status_frame_length_next;
status_frame_original_length_reg <= status_frame_original_length_next;
if (store_last_word) begin
last_word_data_reg <= output_axis_tdata_int;
last_word_keep_reg <= output_axis_tkeep_int;
end
end
// output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0;
reg output_axis_tvalid_reg = 0;
reg output_axis_tlast_reg = 0;
reg output_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0;
reg temp_axis_tvalid_reg = 0;
reg temp_axis_tlast_reg = 0;
reg temp_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 1'b0;
reg 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_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_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
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);
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (output_axis_tready_int_reg) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (output_axis_tready) begin
// input is not ready, but output is ready
output_axis_tvalid_next = temp_axis_tvalid_reg;
temp_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
output_axis_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;
output_axis_tvalid_reg <= 1'b0;
output_axis_tready_int_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
// transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early;
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
if (output_axis_tready_int) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int;
output_axis_tkeep_reg <= output_axis_tkeep_int;
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
// output is not ready and currently valid, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int;
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 else if (output_axis_tready) begin
// input is not ready, but output is ready
output_axis_tdata_reg <= temp_axis_tdata_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_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
// 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_tkeep_reg <= temp_axis_tkeep_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg;
end
if (store_axis_int_to_temp) begin
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
end
end

View File

@ -40,7 +40,7 @@ def generate(ports=4, name=None, output=None):
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
of this software and associated documentation files (the "Software"), to deal
@ -103,16 +103,16 @@ module {{name}} #
input wire [{{w-1}}:0] select
);
reg [{{w-1}}:0] select_reg = 0, select_next;
reg frame_reg = 0, frame_next;
reg [{{w-1}}:0] select_reg = {{w}}'d0, select_next;
reg frame_reg = 1'b0, frame_next;
{% 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 %}
// internal datapath
reg [DATA_WIDTH-1:0] output_axis_tdata_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_tuser_int;
wire output_axis_tready_int_early;
@ -127,6 +127,7 @@ always @* begin
{%- for p in ports %}
{{w}}'d{{p}}: selected_input_tvalid = input_{{p}}_axis_tvalid;
{%- endfor %}
default: selected_input_tvalid = 1'b0;
endcase
end
@ -147,6 +148,13 @@ always @* begin
current_input_tuser = input_{{p}}_axis_tuser;
end
{%- 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
end
@ -154,7 +162,7 @@ always @* begin
select_next = select_reg;
frame_next = frame_reg;
{% for p in ports %}
input_{{p}}_axis_tready_next = 0;
input_{{p}}_axis_tready_next = 1'b0;
{%- endfor %}
if (frame_reg) begin
@ -164,7 +172,7 @@ always @* begin
end
end else if (enable & selected_input_tvalid) begin
// start of frame, grab select value
frame_next = 1;
frame_next = 1'b1;
select_next = select;
end
@ -184,10 +192,10 @@ end
always @(posedge clk) begin
if (rst) begin
select_reg <= 0;
frame_reg <= 0;
select_reg <= {{w}}'d0;
frame_reg <= 1'b0;
{%- for p in ports %}
input_{{p}}_axis_tready_reg <= 0;
input_{{p}}_axis_tready_reg <= 1'b0;
{%- endfor %}
end else begin
select_reg <= select_next;
@ -199,65 +207,83 @@ always @(posedge clk) begin
end
// output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0;
reg output_axis_tvalid_reg = 0;
reg output_axis_tlast_reg = 0;
reg output_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
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;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0;
reg temp_axis_tvalid_reg = 0;
reg temp_axis_tlast_reg = 0;
reg temp_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 1'b0;
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_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_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
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);
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (output_axis_tready_int_reg) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (output_axis_tready) begin
// input is not ready, but output is ready
output_axis_tvalid_next = temp_axis_tvalid_reg;
temp_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
output_axis_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;
output_axis_tvalid_reg <= 1'b0;
output_axis_tready_int_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
// transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early;
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
if (output_axis_tready_int) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int;
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
// output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int;
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 else if (output_axis_tready) begin
// input is not ready, but output is ready
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_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
// 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_tuser_reg <= temp_axis_tuser_reg;
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

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
of this software and associated documentation files (the "Software"), to deal
@ -80,18 +80,18 @@ module axis_mux_4 #
input wire [1:0] select
);
reg [1:0] select_reg = 0, select_next;
reg frame_reg = 0, frame_next;
reg [1:0] select_reg = 2'd0, select_next;
reg frame_reg = 1'b0, frame_next;
reg input_0_axis_tready_reg = 0, input_0_axis_tready_next;
reg input_1_axis_tready_reg = 0, input_1_axis_tready_next;
reg input_2_axis_tready_reg = 0, input_2_axis_tready_next;
reg input_3_axis_tready_reg = 0, input_3_axis_tready_next;
reg input_0_axis_tready_reg = 1'b0, input_0_axis_tready_next;
reg input_1_axis_tready_reg = 1'b0, input_1_axis_tready_next;
reg input_2_axis_tready_reg = 1'b0, input_2_axis_tready_next;
reg input_3_axis_tready_reg = 1'b0, input_3_axis_tready_next;
// internal datapath
reg [DATA_WIDTH-1:0] output_axis_tdata_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_tuser_int;
wire output_axis_tready_int_early;
@ -109,6 +109,7 @@ always @* begin
2'd1: selected_input_tvalid = input_1_axis_tvalid;
2'd2: selected_input_tvalid = input_2_axis_tvalid;
2'd3: selected_input_tvalid = input_3_axis_tvalid;
default: selected_input_tvalid = 1'b0;
endcase
end
@ -148,6 +149,13 @@ always @* begin
current_input_tlast = input_3_axis_tlast;
current_input_tuser = input_3_axis_tuser;
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
end
@ -155,10 +163,10 @@ always @* begin
select_next = select_reg;
frame_next = frame_reg;
input_0_axis_tready_next = 0;
input_1_axis_tready_next = 0;
input_2_axis_tready_next = 0;
input_3_axis_tready_next = 0;
input_0_axis_tready_next = 1'b0;
input_1_axis_tready_next = 1'b0;
input_2_axis_tready_next = 1'b0;
input_3_axis_tready_next = 1'b0;
if (frame_reg) begin
if (current_input_tvalid & current_input_tready) begin
@ -167,7 +175,7 @@ always @* begin
end
end else if (enable & selected_input_tvalid) begin
// start of frame, grab select value
frame_next = 1;
frame_next = 1'b1;
select_next = select;
end
@ -188,12 +196,12 @@ end
always @(posedge clk) begin
if (rst) begin
select_reg <= 0;
frame_reg <= 0;
input_0_axis_tready_reg <= 0;
input_1_axis_tready_reg <= 0;
input_2_axis_tready_reg <= 0;
input_3_axis_tready_reg <= 0;
select_reg <= 2'd0;
frame_reg <= 1'b0;
input_0_axis_tready_reg <= 1'b0;
input_1_axis_tready_reg <= 1'b0;
input_2_axis_tready_reg <= 1'b0;
input_3_axis_tready_reg <= 1'b0;
end else begin
select_reg <= select_next;
frame_reg <= frame_next;
@ -205,65 +213,83 @@ always @(posedge clk) begin
end
// output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0;
reg output_axis_tvalid_reg = 0;
reg output_axis_tlast_reg = 0;
reg output_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
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;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0;
reg temp_axis_tvalid_reg = 0;
reg temp_axis_tlast_reg = 0;
reg temp_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 1'b0;
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_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_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
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);
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (output_axis_tready_int_reg) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (output_axis_tready) begin
// input is not ready, but output is ready
output_axis_tvalid_next = temp_axis_tvalid_reg;
temp_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
output_axis_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;
output_axis_tvalid_reg <= 1'b0;
output_axis_tready_int_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
// transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early;
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
if (output_axis_tready_int) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int;
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
// output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int;
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 else if (output_axis_tready) begin
// input is not ready, but output is ready
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_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
// 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_tuser_reg <= temp_axis_tuser_reg;
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

View File

@ -40,7 +40,7 @@ def generate(ports=4, name=None, output=None):
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
of this software and associated documentation files (the "Software"), to deal
@ -106,17 +106,17 @@ module {{name}} #
input wire [{{w-1}}:0] select
);
reg [{{w-1}}:0] select_reg = 0, select_next;
reg frame_reg = 0, frame_next;
reg [{{w-1}}:0] select_reg = {{w}}'d0, select_next;
reg frame_reg = 1'b0, frame_next;
{% 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 %}
// internal datapath
reg [DATA_WIDTH-1:0] output_axis_tdata_int;
reg [KEEP_WIDTH-1:0] output_axis_tkeep_int;
reg output_axis_tvalid_int;
reg output_axis_tready_int = 0;
reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int;
reg output_axis_tuser_int;
wire output_axis_tready_int_early;
@ -131,6 +131,7 @@ always @* begin
{%- for p in ports %}
{{w}}'d{{p}}: selected_input_tvalid = input_{{p}}_axis_tvalid;
{%- endfor %}
default: selected_input_tvalid = 1'b0;
endcase
end
@ -153,6 +154,14 @@ always @* begin
current_input_tuser = input_{{p}}_axis_tuser;
end
{%- 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
end
@ -160,7 +169,7 @@ always @* begin
select_next = select_reg;
frame_next = frame_reg;
{% for p in ports %}
input_{{p}}_axis_tready_next = 0;
input_{{p}}_axis_tready_next = 1'b0;
{%- endfor %}
if (frame_reg) begin
@ -170,7 +179,7 @@ always @* begin
end
end else if (enable & selected_input_tvalid) begin
// start of frame, grab select value
frame_next = 1;
frame_next = 1'b1;
select_next = select;
end
@ -191,10 +200,10 @@ end
always @(posedge clk) begin
if (rst) begin
select_reg <= 0;
frame_reg <= 0;
select_reg <= {{w}}'d0;
frame_reg <= 1'b0;
{%- for p in ports %}
input_{{p}}_axis_tready_reg <= 0;
input_{{p}}_axis_tready_reg <= 1'b0;
{%- endfor %}
end else begin
select_reg <= select_next;
@ -206,17 +215,22 @@ always @(posedge clk) begin
end
// output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0;
reg output_axis_tvalid_reg = 0;
reg output_axis_tlast_reg = 0;
reg output_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0;
reg temp_axis_tvalid_reg = 0;
reg temp_axis_tlast_reg = 0;
reg temp_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 1'b0;
reg 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_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_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
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);
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (output_axis_tready_int_reg) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (output_axis_tready) begin
// input is not ready, but output is ready
output_axis_tvalid_next = temp_axis_tvalid_reg;
temp_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
output_axis_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;
output_axis_tvalid_reg <= 1'b0;
output_axis_tready_int_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
// transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early;
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
if (output_axis_tready_int) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int;
output_axis_tkeep_reg <= output_axis_tkeep_int;
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
// output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int;
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 else if (output_axis_tready) begin
// input is not ready, but output is ready
output_axis_tdata_reg <= temp_axis_tdata_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_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
// 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_tkeep_reg <= temp_axis_tkeep_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg;
end
if (store_axis_int_to_temp) begin
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
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
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
);
reg [1:0] select_reg = 0, select_next;
reg frame_reg = 0, frame_next;
reg [1:0] select_reg = 2'd0, select_next;
reg frame_reg = 1'b0, frame_next;
reg input_0_axis_tready_reg = 0, input_0_axis_tready_next;
reg input_1_axis_tready_reg = 0, input_1_axis_tready_next;
reg input_2_axis_tready_reg = 0, input_2_axis_tready_next;
reg input_3_axis_tready_reg = 0, input_3_axis_tready_next;
reg input_0_axis_tready_reg = 1'b0, input_0_axis_tready_next;
reg input_1_axis_tready_reg = 1'b0, input_1_axis_tready_next;
reg input_2_axis_tready_reg = 1'b0, input_2_axis_tready_next;
reg input_3_axis_tready_reg = 1'b0, input_3_axis_tready_next;
// internal datapath
reg [DATA_WIDTH-1:0] output_axis_tdata_int;
reg [KEEP_WIDTH-1:0] output_axis_tkeep_int;
reg output_axis_tvalid_int;
reg output_axis_tready_int = 0;
reg output_axis_tready_int_reg = 1'b0;
reg output_axis_tlast_int;
reg output_axis_tuser_int;
wire output_axis_tready_int_early;
@ -116,6 +116,7 @@ always @* begin
2'd1: selected_input_tvalid = input_1_axis_tvalid;
2'd2: selected_input_tvalid = input_2_axis_tvalid;
2'd3: selected_input_tvalid = input_3_axis_tvalid;
default: selected_input_tvalid = 1'b0;
endcase
end
@ -160,6 +161,14 @@ always @* begin
current_input_tlast = input_3_axis_tlast;
current_input_tuser = input_3_axis_tuser;
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
end
@ -167,10 +176,10 @@ always @* begin
select_next = select_reg;
frame_next = frame_reg;
input_0_axis_tready_next = 0;
input_1_axis_tready_next = 0;
input_2_axis_tready_next = 0;
input_3_axis_tready_next = 0;
input_0_axis_tready_next = 1'b0;
input_1_axis_tready_next = 1'b0;
input_2_axis_tready_next = 1'b0;
input_3_axis_tready_next = 1'b0;
if (frame_reg) begin
if (current_input_tvalid & current_input_tready) begin
@ -179,7 +188,7 @@ always @* begin
end
end else if (enable & selected_input_tvalid) begin
// start of frame, grab select value
frame_next = 1;
frame_next = 1'b1;
select_next = select;
end
@ -201,12 +210,12 @@ end
always @(posedge clk) begin
if (rst) begin
select_reg <= 0;
frame_reg <= 0;
input_0_axis_tready_reg <= 0;
input_1_axis_tready_reg <= 0;
input_2_axis_tready_reg <= 0;
input_3_axis_tready_reg <= 0;
select_reg <= 2'd0;
frame_reg <= 1'b0;
input_0_axis_tready_reg <= 1'b0;
input_1_axis_tready_reg <= 1'b0;
input_2_axis_tready_reg <= 1'b0;
input_3_axis_tready_reg <= 1'b0;
end else begin
select_reg <= select_next;
frame_reg <= frame_next;
@ -218,17 +227,22 @@ always @(posedge clk) begin
end
// output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0;
reg output_axis_tvalid_reg = 0;
reg output_axis_tlast_reg = 0;
reg output_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0;
reg temp_axis_tvalid_reg = 0;
reg temp_axis_tlast_reg = 0;
reg temp_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 1'b0;
reg 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_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_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
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);
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (output_axis_tready_int_reg) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (output_axis_tready) begin
// input is not ready, but output is ready
output_axis_tvalid_next = temp_axis_tvalid_reg;
temp_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
output_axis_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;
output_axis_tvalid_reg <= 1'b0;
output_axis_tready_int_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
// transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early;
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
if (output_axis_tready_int) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int;
output_axis_tkeep_reg <= output_axis_tkeep_int;
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
// output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int;
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 else if (output_axis_tready) begin
// input is not ready, but output is ready
output_axis_tdata_reg <= temp_axis_tdata_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_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
// 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_tkeep_reg <= temp_axis_tkeep_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg;
end
if (store_axis_int_to_temp) begin
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
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
of this software and associated documentation files (the "Software"), to deal
@ -66,21 +66,22 @@ module axis_rate_limit #
// internal datapath
reg [DATA_WIDTH-1:0] output_axis_tdata_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_tuser_int;
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 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;
always @* begin
acc_next = acc_reg;
pause = 0;
pause = 1'b0;
frame_next = frame_reg;
if (acc_reg >= rate_num) begin
@ -97,7 +98,7 @@ always @* begin
if (rate_by_frame) begin
pause = ~frame_next;
end else begin
pause = 1;
pause = 1'b1;
end
end
@ -111,9 +112,9 @@ end
always @(posedge clk) begin
if (rst) begin
acc_reg <= 0;
frame_reg <= 0;
input_axis_tready_reg <= 0;
acc_reg <= 24'd0;
frame_reg <= 1'b0;
input_axis_tready_reg <= 1'b0;
end else begin
acc_reg <= acc_next;
frame_reg <= frame_next;
@ -122,65 +123,83 @@ always @(posedge clk) begin
end
// output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0;
reg output_axis_tvalid_reg = 0;
reg output_axis_tlast_reg = 0;
reg output_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
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;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0;
reg temp_axis_tvalid_reg = 0;
reg temp_axis_tlast_reg = 0;
reg temp_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 1'b0;
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_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_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
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);
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (output_axis_tready_int_reg) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (output_axis_tready) begin
// input is not ready, but output is ready
output_axis_tvalid_next = temp_axis_tvalid_reg;
temp_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
output_axis_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;
output_axis_tvalid_reg <= 1'b0;
output_axis_tready_int_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
// transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early;
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
if (output_axis_tready_int) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int;
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
// output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int;
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 else if (output_axis_tready) begin
// input is not ready, but output is ready
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_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
// 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_tuser_reg <= temp_axis_tuser_reg;
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

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
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 [KEEP_WIDTH-1:0] output_axis_tkeep_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_tuser_int;
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 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;
always @* begin
acc_next = acc_reg;
pause = 0;
pause = 1'b0;
frame_next = frame_reg;
if (acc_reg >= rate_num) begin
@ -101,7 +102,7 @@ always @* begin
if (rate_by_frame) begin
pause = ~frame_next;
end else begin
pause = 1;
pause = 1'b1;
end
end
@ -116,9 +117,9 @@ end
always @(posedge clk) begin
if (rst) begin
acc_reg <= 0;
frame_reg <= 0;
input_axis_tready_reg <= 0;
acc_reg <= 24'd0;
frame_reg <= 1'b0;
input_axis_tready_reg <= 1'b0;
end else begin
acc_reg <= acc_next;
frame_reg <= frame_next;
@ -127,17 +128,22 @@ always @(posedge clk) begin
end
// output datapath logic
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0;
reg output_axis_tvalid_reg = 0;
reg output_axis_tlast_reg = 0;
reg output_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0;
reg temp_axis_tvalid_reg = 0;
reg temp_axis_tlast_reg = 0;
reg temp_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 1'b0;
reg 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_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_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
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);
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (output_axis_tready_int_reg) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (output_axis_tready) begin
// input is not ready, but output is ready
output_axis_tvalid_next = temp_axis_tvalid_reg;
temp_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
output_axis_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;
output_axis_tvalid_reg <= 1'b0;
output_axis_tready_int_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
// transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early;
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
if (output_axis_tready_int) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int;
output_axis_tkeep_reg <= output_axis_tkeep_int;
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
// output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int;
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 else if (output_axis_tready) begin
// input is not ready, but output is ready
output_axis_tdata_reg <= temp_axis_tdata_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_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
// 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_tkeep_reg <= temp_axis_tkeep_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg;
end
if (store_axis_int_to_temp) begin
temp_axis_tdata_reg <= output_axis_tdata_int;
temp_axis_tkeep_reg <= output_axis_tkeep_int;
temp_axis_tlast_reg <= output_axis_tlast_int;
temp_axis_tuser_reg <= output_axis_tuser_int;
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
of this software and associated documentation files (the "Software"), to deal
@ -57,17 +57,22 @@ module axis_register #
);
// 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 output_axis_tvalid_reg = 0;
reg output_axis_tlast_reg = 0;
reg output_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
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;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0;
reg temp_axis_tvalid_reg = 0;
reg temp_axis_tlast_reg = 0;
reg temp_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 1'b0;
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;
@ -76,48 +81,63 @@ assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg;
// 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)
wire input_axis_tready_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~input_axis_tvalid));
always @* begin
// transfer sink ready state to source
output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
store_axis_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
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tvalid_next = input_axis_tvalid;
store_axis_input_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_axis_tvalid_next = input_axis_tvalid;
store_axis_input_to_temp = 1'b1;
end
end else if (output_axis_tready) begin
// input is not ready, but output is ready
output_axis_tvalid_next = temp_axis_tvalid_reg;
temp_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
input_axis_tready_reg <= 0;
output_axis_tdata_reg <= 0;
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;
input_axis_tready_reg <= 1'b0;
output_axis_tvalid_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
// 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
input_axis_tready_reg <= output_axis_tready | (~temp_axis_tvalid_reg & ~output_axis_tvalid_reg) | (~temp_axis_tvalid_reg & ~input_axis_tvalid);
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
if (input_axis_tready_reg) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= input_axis_tdata;
output_axis_tvalid_reg <= input_axis_tvalid;
output_axis_tlast_reg <= input_axis_tlast;
output_axis_tuser_reg <= input_axis_tuser;
end else begin
// output is not ready, store input in temp
temp_axis_tdata_reg <= input_axis_tdata;
temp_axis_tvalid_reg <= input_axis_tvalid;
temp_axis_tlast_reg <= input_axis_tlast;
temp_axis_tuser_reg <= input_axis_tuser;
end
end else if (output_axis_tready) begin
// input is not ready, but output is ready
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_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
// 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_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg;
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

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
of this software and associated documentation files (the "Software"), to deal
@ -60,19 +60,24 @@ module axis_register_64 #
);
// 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 [KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0;
reg output_axis_tvalid_reg = 0;
reg output_axis_tlast_reg = 0;
reg output_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
reg output_axis_tlast_reg = 1'b0;
reg output_axis_tuser_reg = 1'b0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0;
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0;
reg temp_axis_tvalid_reg = 0;
reg temp_axis_tlast_reg = 0;
reg temp_axis_tuser_reg = 0;
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 1'b0;
reg 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;
@ -82,54 +87,66 @@ assign output_axis_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_reg;
assign output_axis_tuser = output_axis_tuser_reg;
// 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)
wire input_axis_tready_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~input_axis_tvalid));
always @* begin
// transfer sink ready state to source
output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
store_axis_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
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tvalid_next = input_axis_tvalid;
store_axis_input_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_axis_tvalid_next = input_axis_tvalid;
store_axis_input_to_temp = 1'b1;
end
end else if (output_axis_tready) begin
// input is not ready, but output is ready
output_axis_tvalid_next = temp_axis_tvalid_reg;
temp_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
input_axis_tready_reg <= 0;
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;
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;
input_axis_tready_reg <= 1'b0;
output_axis_tvalid_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
// 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
input_axis_tready_reg <= output_axis_tready | (~temp_axis_tvalid_reg & ~output_axis_tvalid_reg) | (~temp_axis_tvalid_reg & ~input_axis_tvalid);
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
if (input_axis_tready_reg) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= input_axis_tdata;
output_axis_tkeep_reg <= input_axis_tkeep;
output_axis_tvalid_reg <= input_axis_tvalid;
output_axis_tlast_reg <= input_axis_tlast;
output_axis_tuser_reg <= input_axis_tuser;
end else begin
// output is not ready, store input in temp
temp_axis_tdata_reg <= input_axis_tdata;
temp_axis_tkeep_reg <= input_axis_tkeep;
temp_axis_tvalid_reg <= input_axis_tvalid;
temp_axis_tlast_reg <= input_axis_tlast;
temp_axis_tuser_reg <= input_axis_tuser;
end
end else if (output_axis_tready) begin
// input is not ready, but output is ready
output_axis_tdata_reg <= temp_axis_tdata_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_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
// 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_tkeep_reg <= temp_axis_tkeep_reg;
output_axis_tlast_reg <= temp_axis_tlast_reg;
output_axis_tuser_reg <= temp_axis_tuser_reg;
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

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
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 [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_reg = 0, frame_next;
reg frame_reg = 1'b0, frame_next;
reg store_output;
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 [FRAME_COUNT_WIDTH-1:0] frame_count_output_reg = 0;
reg busy_reg = 0;
reg busy_reg = 1'b0;
// internal datapath
reg [7:0] output_axis_tdata_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_tuser_int;
wire output_axis_tready_int_early;
@ -115,19 +115,19 @@ assign busy = busy_reg;
integer offset, i, bit_cnt;
always @* begin
state_next = 2'bz;
state_next = STATE_IDLE;
tick_count_next = tick_count_reg;
byte_count_next = byte_count_reg;
frame_count_next = frame_count_reg;
frame_next = frame_reg;
output_axis_tdata_int = 0;
output_axis_tvalid_int = 0;
output_axis_tlast_int = 0;
output_axis_tuser_int = 0;
output_axis_tdata_int = 8'd0;
output_axis_tvalid_int = 1'b0;
output_axis_tlast_int = 1'b0;
output_axis_tuser_int = 1'b0;
store_output = 0;
store_output = 1'b0;
frame_ptr_next = frame_ptr_reg;
@ -136,13 +136,13 @@ always @* begin
case (state_reg)
STATE_IDLE: begin
if (trigger) begin
store_output = 1;
store_output = 1'b1;
tick_count_next = 0;
byte_count_next = 0;
frame_count_next = 0;
frame_ptr_next = 0;
if (output_axis_tready_int) begin
if (output_axis_tready_int_reg) begin
frame_ptr_next = 1;
if (TAG_ENABLE) begin
output_axis_tdata_int = tag[(TAG_BYTE_WIDTH-1)*8 +: 8];
@ -153,7 +153,7 @@ always @* begin
end else if (FRAME_COUNT_ENABLE) begin
output_axis_tdata_int = frame_count_reg[(FRAME_COUNT_BYTE_WIDTH-1)*8 +: 8];
end
output_axis_tvalid_int = 1;
output_axis_tvalid_int = 1'b1;
end
state_next = STATE_OUTPUT_DATA;
@ -162,10 +162,10 @@ always @* begin
end
end
STATE_OUTPUT_DATA: begin
if (output_axis_tready_int) begin
if (output_axis_tready_int_reg) begin
state_next = STATE_OUTPUT_DATA;
frame_ptr_next = frame_ptr_reg + 1;
output_axis_tvalid_int = 1;
output_axis_tvalid_int = 1'b1;
offset = 0;
if (TAG_ENABLE) begin
@ -201,7 +201,7 @@ always @* begin
end
end
if (frame_ptr_reg == offset-1) begin
output_axis_tlast_int = 1;
output_axis_tlast_int = 1'b1;
state_next = STATE_IDLE;
end
end else begin
@ -229,11 +229,11 @@ always @* begin
// count frames
if (monitor_axis_tlast) begin
// end of frame
frame_next = 0;
frame_next = 1'b0;
end else if (~frame_reg) begin
// first word after end of frame
frame_count_next = frame_count_next + 1;
frame_next = 1;
frame_next = 1'b1;
end
end
end
@ -244,12 +244,9 @@ always @(posedge clk) begin
tick_count_reg <= 0;
byte_count_reg <= 0;
frame_count_reg <= 0;
frame_reg <= 0;
frame_reg <= 1'b0;
frame_ptr_reg <= 0;
busy_reg <= 0;
tick_count_output_reg <= 0;
byte_count_output_reg <= 0;
frame_count_output_reg <= 0;
busy_reg <= 1'b0;
end else begin
state_reg <= state_next;
tick_count_reg <= tick_count_next;
@ -260,74 +257,93 @@ always @(posedge clk) begin
busy_reg <= state_next != STATE_IDLE;
if (store_output) begin
tick_count_output_reg <= tick_count_reg;
byte_count_output_reg <= byte_count_reg;
frame_count_output_reg <= frame_count_reg;
end
end
if (store_output) begin
tick_count_output_reg <= tick_count_reg;
byte_count_output_reg <= byte_count_reg;
frame_count_output_reg <= frame_count_reg;
end
end
// output datapath logic
reg [7:0] output_axis_tdata_reg = 0;
reg output_axis_tvalid_reg = 0;
reg output_axis_tlast_reg = 0;
reg output_axis_tuser_reg = 0;
reg [7:0] output_axis_tdata_reg = 8'd0;
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;
reg [7:0] temp_axis_tdata_reg = 0;
reg temp_axis_tvalid_reg = 0;
reg temp_axis_tlast_reg = 0;
reg temp_axis_tuser_reg = 0;
reg [7:0] temp_axis_tdata_reg = 8'd0;
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
reg temp_axis_tlast_reg = 1'b0;
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_tvalid = output_axis_tvalid_reg;
assign output_axis_tlast = output_axis_tlast_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
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);
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
output_axis_tvalid_next = output_axis_tvalid_reg;
temp_axis_tvalid_next = temp_axis_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (output_axis_tready_int_reg) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_axis_tvalid_next = output_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (output_axis_tready) begin
// input is not ready, but output is ready
output_axis_tvalid_next = temp_axis_tvalid_reg;
temp_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
output_axis_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;
output_axis_tvalid_reg <= 1'b0;
output_axis_tready_int_reg <= 1'b0;
temp_axis_tvalid_reg <= 1'b0;
end else begin
// transfer sink ready state to source
output_axis_tready_int <= output_axis_tready_int_early;
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
if (output_axis_tready_int) begin
// input is ready
if (output_axis_tready | ~output_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_axis_tdata_reg <= output_axis_tdata_int;
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
// output is not ready, store input in temp
temp_axis_tdata_reg <= output_axis_tdata_int;
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 else if (output_axis_tready) begin
// input is not ready, but output is ready
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_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
// 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_tuser_reg <= temp_axis_tuser_reg;
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

View File

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

View File

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