Entry is stored into the Queue in a certain order. The order could be as simple as find any first vacant entry or find a next vacant entry from previous allocation or find the last entry that became available recently.
Queues are used in Digital design when the Data from a Stream is needed to be stored into a Structure, manipulated and taken out of Order based on a protocol or events in the Design.
The Entry could be taken out of queue (de-allocated) based on a certain protocol. If the protocol involves series of events that are common for each entry then a FSM shown below is used. However, if each entry in the queue needs a separate event then just a Combinational Trigger logic to clear a valid bit maybe sufficient.
Here’s an example of 8 Entry Queue that uses FSM for each Entry manipulation :


parameter DEPTH = 8; parameter INVALID_STATE = 4'b0001; parameter VALID_STATE = 4'b0010; parameter EVENT1_STATE = 4'b0100; parameter DISABLE_STATE = 4'b1000; logic [DEPTH-1:0] state_ps[3:0]; logic [DEPTH-1:0] state_ns[3:0]; logic queue_empty; logic queue_full; logic [DATA_WIDTH-1:0] queue_data[DEPTH-1:0]; logic queue_valid[DEPTH-1:0]; logic [DATA_WIDTH-1:0] data_out[DEPTH-1:0]; logic [DEPTH-1:0] new_entry; logic [DEPTH-1:0] allocate_entry; logic allocate_new; logic [DEPTH-1:0] event1_started; logic [DEPTH-1:0] event1_completed; logic [DEPTH-1:0] event1_dis; genvar x, i, j; always_comb begin casez (state_ps[0]) 8'b????_???1 : new_entry = 8'h1; 8'b????_??10 : new_entry = 8'h2; 8'b????_?100 : new_entry = 8'h4; 8'b????_1000 : new_entry = 8'h8; 8'b???1_0000 : new_entry = 8'h10; 8'b??10_0000 : new_entry = 8'h20; 8'b?100_0000 : new_entry = 8'h40; 8'b1000_0000 : new_entry = 8'h80; default : new_entry = '0; endcase end assign allocate_entry = (~queue_full & allocate_new) ? new_entry : 8'b0; always_comb begin for (int entry = 0; entry < DEPTH; entry++) casez (state_ps[entry]) INVALID_STATE : if(entry_dis[entry]) state_ns[entry] = DISABLE_STATE; else if(allocate_entry[entry]) state_ns[entry] = VALID_STATE; else state_ns[entry] = INVALID_STATE; DISABLE_STATE : if(~entry_dis[entry]) state_ns[entry] = INVALID_STATE; else state_ns[entry] = DISABLE_STATE; VALID_STATE : if(event1_started[entry]) state_ns[entry] = EVENT1_STATE; else state_ns[entry] = VALID_STATE; EVENT1_STATE : if(event1_completed[entry]) state_ns[entry] = INVALID_STATE; else state_ns[entry] = EVENT1_STATE; default : state_ns[entry] = state_ps[entry]; endcase end end generate for (x = 0; x < DEPTH; x++) always_ff @(posedge clk or negedge reset) begin if(~reset) state_ps[x] <= INVALID_STATE; else state_ps[x] <= state_ns[x]; end end endgenerate assign event1_started = request_sent[DEPTH-1:0]; // From other Module assign event1_completed = response_ack[DEPTH-1:0]; // From other Module assign entry_dis = entry_disable[DEPTH-1:0];// From other Module //Queue Data maintenance generate for (i = 0; i < DEPTH; i++) always_ff @(posedge clk or negedge reset) if(~reset | event_completed[i]) begin queue_data[i] <= queue_data[i]; // Can be zero if required queue_valid[i] <= 1'b0; end else if (allocate_entry[i]) begin queue_data[i] <= data_in; queue_valid[i] <= 1'b1; end else begin queue_data[i] <= queue_data[i]; queue_valid[i] <= queue_valid[i]; end end end endgenerate //Queue Data readout of multiple entries. generate for (j = 0; j < DEPTH; j++) assign data_out[j] = (event_completed[j] & queue_valid[j]) ? queue_data[j] :'0; end endgenerate
Here request & response could be sent and received from another Design Module. These Events (Started and Completed) could happen one per entry per cycle or multiple entries per cycle. Hence, there are multiple entries getting State updates i.e multiple entries taken out of Queue.
If only single event is expected to complete every cycle then Decoder is needed to extract out single Data element out of queue as shown below:
logic [2:0] entry_dec; always_comb begin unique case (event_completed[7:0]) 8'h0000_0001 : entry_dec = 3'h0; 8'b0000_0010 : entry_dec = 3'h1; 8'b0000_0100 : entry_dec = 3'h2; 8'b0000_1000 : entry_dec = 3'h3; 8'b0001_0000 : entry_dec = 3'h4; 8'b0010_0000 : entry_dec = 3'h5; 8'b0100_0000 : entry_dec = 8'h6; 8'b1000_0000 : entry_dec = 8'h7; endcase end //Queue Data readout of Single entry assign data_out = ((|event_completed) & queue_valid[entry_dec]) ? queue_data[entry_dec] :'0;
Entry disable is done in order to limit or disable the number of Entries Queue or apply back-pressure on preceding Design module. This programming is usually done via Firmware and used as a effective tool to Test out Corner cases.