// designed by Sergey Suslov // // parameterizable queue with a trivial pointer encodings // can be implementer eather with on-chip Block RAM or distributed memory, subject to synthesis attribute setting of the stack memory // when implemeted with a RAM block adopt the first-word-falls-through policy for zero latency immediate pop // provides forward read and write grant signals for smooth operation of FSMs controlling the data-flows on both ports of the channel(queue) /* `include "definitions.v" `include "configuration.v" `ifdef VERIFICATION timeunit `verification_time_unit; timeprecision `verification_time_resolution; `endif */ module ring_buffer_gnt_forward_ram_based/*_fwft*/ #(parameter word_width=144,parameter stack_depth=16) (input bit clk, input bit reset_n, input bit [word_width-1:0] data_in, output bit [word_width-1:0] data_out, input bit read_op_req, input bit write_op_req, output bit read_op_gnt, output bit write_op_gnt, output bit forward_read_op_gnt, output bit forward_write_op_gnt ); localparam ptr_width=$clog2(stack_depth); localparam cnt_width=$clog2(stack_depth+1); //`include "log2.sv" //localparam ptr_width=number_of_bits_for_value_representation(stack_depth-1); //localparam cnt_width=number_of_bits_for_value_representation(stack_depth); //pragma attribute stack ram_block 1 bit [word_width-1:0] stack [stack_depth-1:0]; bit [ptr_width-1:0] write_op_ptr; bit [ptr_width-1:0] read_op_ptr; bit [cnt_width-1:0] queue_counter; bit write_op_strobe; bit read_op_strobe; always_comb begin write_op_strobe=write_op_req&write_op_gnt; read_op_strobe=read_op_req&read_op_gnt; end always_ff @(posedge clk) begin if(~reset_n) begin write_op_ptr<=0; read_op_ptr<=0; queue_counter<=0; write_op_gnt<=1; read_op_gnt<=0; forward_write_op_gnt<=1; forward_read_op_gnt<=0; end else begin unique case ({write_op_strobe,read_op_strobe}) 2'b01://when read and no write begin //write_op_gnt<=1; //forward_write_op_gnt<=write_op_gnt; //if (queue_counter==1) forward_read_op_gnt<=0; //read_op_gnt<=forward_read_op_gnt; write_op_gnt<=1; if (write_op_gnt==1)forward_write_op_gnt<=1; if (queue_counter==1) read_op_gnt<=0; if (queue_counter==2) forward_read_op_gnt<=0; queue_counter<=queue_counter-1; if (forward_read_op_gnt==1'b1)//if there are data in the stack begin if (read_op_ptr==stack_depth-1) read_op_ptr<=0; else read_op_ptr<=read_op_ptr+1; end data_out<=stack[read_op_ptr]; end 2'b10://when write and no read begin //read_op_gnt<=1; //forward_read_op_gnt<=read_op_gnt; //if (queue_counter==stack_depth-2)forward_write_op_gnt<=0; //write_op_gnt<=forward_write_op_gnt; read_op_gnt<=1; if (read_op_gnt==1)forward_read_op_gnt<=1; if (queue_counter==stack_depth)write_op_gnt<=0; if (queue_counter==stack_depth-1)forward_write_op_gnt<=0; queue_counter<=queue_counter+1; if (read_op_gnt==1'b1)//if data_out register is already filled begin//put data to the stack if (write_op_ptr==stack_depth-1) write_op_ptr<=0; else write_op_ptr<=write_op_ptr+1; stack[write_op_ptr]<=data_in; end else//if data_out register is empty begin//put data to the output resister (fall through) and do not perform any operation on the stack data_out<=data_in; end end 2'b11: begin write_op_gnt<=write_op_gnt; read_op_gnt<=read_op_gnt; queue_counter<=queue_counter; forward_write_op_gnt<=forward_write_op_gnt; forward_read_op_gnt<=forward_read_op_gnt; if (forward_read_op_gnt==1'b1)//if there are data in the stack begin if (write_op_ptr==stack_depth-1) write_op_ptr<=0; else write_op_ptr<=write_op_ptr+1; stack[write_op_ptr]<=data_in; if (read_op_ptr==stack_depth-1) read_op_ptr<=0; else read_op_ptr<=read_op_ptr+1; data_out<=stack[read_op_ptr]; end else begin data_out<=data_in; end end 2'b00: begin write_op_gnt<=write_op_gnt; read_op_gnt<=read_op_gnt; queue_counter<=queue_counter; forward_write_op_gnt<=forward_write_op_gnt; forward_read_op_gnt<=forward_read_op_gnt; end endcase end end endmodule