diff --git a/lib/axis/rtl/axis_adapter.v b/lib/axis/rtl/axis_adapter.v index 1eed1403..c5f4358c 100644 --- a/lib/axis/rtl/axis_adapter.v +++ b/lib/axis/rtl/axis_adapter.v @@ -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 diff --git a/lib/axis/rtl/axis_async_fifo.v b/lib/axis/rtl/axis_async_fifo.v index 4edb9155..97a57224 100644 --- a/lib/axis/rtl/axis_async_fifo.v +++ b/lib/axis/rtl/axis_async_fifo.v @@ -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 diff --git a/lib/axis/rtl/axis_async_fifo_64.v b/lib/axis/rtl/axis_async_fifo_64.v index c7eed0e3..cf5ae7ed 100644 --- a/lib/axis/rtl/axis_async_fifo_64.v +++ b/lib/axis/rtl/axis_async_fifo_64.v @@ -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 diff --git a/lib/axis/rtl/axis_async_frame_fifo.v b/lib/axis/rtl/axis_async_frame_fifo.v index 944b1f48..e2f9d43e 100644 --- a/lib/axis/rtl/axis_async_frame_fifo.v +++ b/lib/axis/rtl/axis_async_frame_fifo.v @@ -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 diff --git a/lib/axis/rtl/axis_async_frame_fifo_64.v b/lib/axis/rtl/axis_async_frame_fifo_64.v index 2183ea03..2a52d9b6 100644 --- a/lib/axis/rtl/axis_async_frame_fifo_64.v +++ b/lib/axis/rtl/axis_async_frame_fifo_64.v @@ -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 diff --git a/lib/axis/rtl/axis_crosspoint.py b/lib/axis/rtl/axis_crosspoint.py index ac193f2d..5d0367d3 100755 --- a/lib/axis/rtl/axis_crosspoint.py +++ b/lib/axis/rtl/axis_crosspoint.py @@ -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 diff --git a/lib/axis/rtl/axis_crosspoint_4x4.v b/lib/axis/rtl/axis_crosspoint_4x4.v index cb8a26a5..d2be80b0 100644 --- a/lib/axis/rtl/axis_crosspoint_4x4.v +++ b/lib/axis/rtl/axis_crosspoint_4x4.v @@ -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 diff --git a/lib/axis/rtl/axis_crosspoint_64.py b/lib/axis/rtl/axis_crosspoint_64.py index bb871037..bb27fc86 100755 --- a/lib/axis/rtl/axis_crosspoint_64.py +++ b/lib/axis/rtl/axis_crosspoint_64.py @@ -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 diff --git a/lib/axis/rtl/axis_crosspoint_64_4x4.v b/lib/axis/rtl/axis_crosspoint_64_4x4.v index 4e7688a3..a241c699 100644 --- a/lib/axis/rtl/axis_crosspoint_64_4x4.v +++ b/lib/axis/rtl/axis_crosspoint_64_4x4.v @@ -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 diff --git a/lib/axis/rtl/axis_demux.py b/lib/axis/rtl/axis_demux.py index 8cd57b75..71b37dba 100755 --- a/lib/axis/rtl/axis_demux.py +++ b/lib/axis/rtl/axis_demux.py @@ -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 diff --git a/lib/axis/rtl/axis_demux_4.v b/lib/axis/rtl/axis_demux_4.v index 493f5585..9d5b8310 100644 --- a/lib/axis/rtl/axis_demux_4.v +++ b/lib/axis/rtl/axis_demux_4.v @@ -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 diff --git a/lib/axis/rtl/axis_demux_64.py b/lib/axis/rtl/axis_demux_64.py index 8b327138..d3f6294f 100755 --- a/lib/axis/rtl/axis_demux_64.py +++ b/lib/axis/rtl/axis_demux_64.py @@ -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 diff --git a/lib/axis/rtl/axis_demux_64_4.v b/lib/axis/rtl/axis_demux_64_4.v index e4fb0a44..f4bb51fc 100644 --- a/lib/axis/rtl/axis_demux_64_4.v +++ b/lib/axis/rtl/axis_demux_64_4.v @@ -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 diff --git a/lib/axis/rtl/axis_fifo.v b/lib/axis/rtl/axis_fifo.v index c31f4ef1..c34298ac 100644 --- a/lib/axis/rtl/axis_fifo.v +++ b/lib/axis/rtl/axis_fifo.v @@ -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 diff --git a/lib/axis/rtl/axis_fifo_64.v b/lib/axis/rtl/axis_fifo_64.v index 7409df3e..4f1d60b1 100644 --- a/lib/axis/rtl/axis_fifo_64.v +++ b/lib/axis/rtl/axis_fifo_64.v @@ -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 diff --git a/lib/axis/rtl/axis_frame_fifo.v b/lib/axis/rtl/axis_frame_fifo.v index 10e6805a..8111eaa3 100644 --- a/lib/axis/rtl/axis_frame_fifo.v +++ b/lib/axis/rtl/axis_frame_fifo.v @@ -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 diff --git a/lib/axis/rtl/axis_frame_fifo_64.v b/lib/axis/rtl/axis_frame_fifo_64.v index 085d1972..873869ce 100644 --- a/lib/axis/rtl/axis_frame_fifo_64.v +++ b/lib/axis/rtl/axis_frame_fifo_64.v @@ -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 diff --git a/lib/axis/rtl/axis_frame_join.py b/lib/axis/rtl/axis_frame_join.py index 91c23bb9..63f7bd84 100755 --- a/lib/axis/rtl/axis_frame_join.py +++ b/lib/axis/rtl/axis_frame_join.py @@ -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 diff --git a/lib/axis/rtl/axis_frame_join_4.v b/lib/axis/rtl/axis_frame_join_4.v index d57acf7c..82298e3b 100644 --- a/lib/axis/rtl/axis_frame_join_4.v +++ b/lib/axis/rtl/axis_frame_join_4.v @@ -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 diff --git a/lib/axis/rtl/axis_frame_length_adjust.v b/lib/axis/rtl/axis_frame_length_adjust.v index 6c1c2ae6..5b1073a6 100644 --- a/lib/axis/rtl/axis_frame_length_adjust.v +++ b/lib/axis/rtl/axis_frame_length_adjust.v @@ -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 diff --git a/lib/axis/rtl/axis_mux.py b/lib/axis/rtl/axis_mux.py index 16fc4c9f..95c2ada0 100755 --- a/lib/axis/rtl/axis_mux.py +++ b/lib/axis/rtl/axis_mux.py @@ -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 diff --git a/lib/axis/rtl/axis_mux_4.v b/lib/axis/rtl/axis_mux_4.v index bafefba1..b52c17e9 100644 --- a/lib/axis/rtl/axis_mux_4.v +++ b/lib/axis/rtl/axis_mux_4.v @@ -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 diff --git a/lib/axis/rtl/axis_mux_64.py b/lib/axis/rtl/axis_mux_64.py index cc5b5ede..bd3b27f3 100755 --- a/lib/axis/rtl/axis_mux_64.py +++ b/lib/axis/rtl/axis_mux_64.py @@ -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 diff --git a/lib/axis/rtl/axis_mux_64_4.v b/lib/axis/rtl/axis_mux_64_4.v index 624fad75..11ee9aeb 100644 --- a/lib/axis/rtl/axis_mux_64_4.v +++ b/lib/axis/rtl/axis_mux_64_4.v @@ -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 diff --git a/lib/axis/rtl/axis_rate_limit.v b/lib/axis/rtl/axis_rate_limit.v index fb0da33e..835863bf 100644 --- a/lib/axis/rtl/axis_rate_limit.v +++ b/lib/axis/rtl/axis_rate_limit.v @@ -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 diff --git a/lib/axis/rtl/axis_rate_limit_64.v b/lib/axis/rtl/axis_rate_limit_64.v index be6cc1c2..b527a349 100644 --- a/lib/axis/rtl/axis_rate_limit_64.v +++ b/lib/axis/rtl/axis_rate_limit_64.v @@ -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 diff --git a/lib/axis/rtl/axis_register.v b/lib/axis/rtl/axis_register.v index 35ce7555..5c8b2309 100644 --- a/lib/axis/rtl/axis_register.v +++ b/lib/axis/rtl/axis_register.v @@ -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 diff --git a/lib/axis/rtl/axis_register_64.v b/lib/axis/rtl/axis_register_64.v index c635b3f5..45d63185 100644 --- a/lib/axis/rtl/axis_register_64.v +++ b/lib/axis/rtl/axis_register_64.v @@ -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 diff --git a/lib/axis/rtl/axis_stat_counter.v b/lib/axis/rtl/axis_stat_counter.v index 77b99e73..cabc9843 100644 --- a/lib/axis/rtl/axis_stat_counter.v +++ b/lib/axis/rtl/axis_stat_counter.v @@ -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 diff --git a/lib/axis/rtl/axis_tap.v b/lib/axis/rtl/axis_tap.v index b4fa25f9..77165a17 100644 --- a/lib/axis/rtl/axis_tap.v +++ b/lib/axis/rtl/axis_tap.v @@ -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 diff --git a/lib/axis/rtl/axis_tap_64.v b/lib/axis/rtl/axis_tap_64.v index bed8668b..0080d5be 100644 --- a/lib/axis/rtl/axis_tap_64.v +++ b/lib/axis/rtl/axis_tap_64.v @@ -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