Last-In-First-Out Buffer

  1. Introduction

    In low level programming, we mostly manipulate data that is present in registers. Registers are units of memory which are closely coupled with the processor core (ALU) and in most architectures the ALU operations are carried out on these registers and the results obtained are also stored in them. Registers are a limited resource and efficient management of registers is a key issue in low level programming. Processors must carry out a large number of functions utilizing the limited number of registers available. In order to do so, the registers are used to store the data values that are required by the current function being executed on the processor and not all the data values of all the functions which are currently in inactive states. Instead the data values of inactive functions are stored in a special area of memory known as the stack.

    A stack is a reserved area in the memory which is used by the processor to store data that is not being used currently by the processor but is still is required future processing steps. Stack memories are useful when there is a need to call a subroutine function. If the registers used by the subroutine were being used in the calling portion of the program, then they cannot be erased. Upon returning to the calling portion of the program these registers should have the same values that they had before the subroutine call and not the values of the variables used in the subroutine. When a processor switches between tasks in a multitasking environment then a context of the all the tasks that are not currently running must be stored to allow for the switching back to them. This is done by storing the context of the inactive tasks in the stack.

    Stacks are implemented as Last In First Out (LIFO) Buffers. The term PUSH to stack means putting data in the stack and the term POP from stack means removing the data from the top of stack (TOS)

    The push and pull operations for a stack are described below:
    Push Operation
    Steps:
    1. Decrement Stack Pointer
    2. Push/Write Data to the top of the stack

    Pop Operation
    Steps:
    1. Pop/Read Data from the top of the stack
    2. Increment the Stack Pointer

  2. Verilog Module

    Figure 1 presents the Verilog module of the LIFO Buffer. This LIFO Buffer can store sixteen 32-bit values. The LIFO Buffer module consists of a 32-bit data input line, dataIn and a 32-bit data output line, dataOut. The module is clocked using the 1-bit input clock line Clk. The module also has a 1-bit enable line, EN and a 1-bit active high reset line, Rst.

    The 1-bit RW line is used to select between LIFO read (POP) and LIFO write (PUSH) operations. If the RW line is high then POP operation is selected and if RW line is low then PUSH operation is selected. The module also has two output lines FULL and EMPTY which are each 1-bit wide. The FULL line becomes high when the LIFO Buffer is or becomes full (internal stack pointer counter becomes zero). The EMPTY line becomes high when the LIFO Buffer is or becomes empty (internal stack pointer counter becomes sixteen).

    Figure 1. Verilog module of LIFO Buffer

  3. Verilog Code for LIFO Buffer (LIFObuffer.v)


    1. module LIFObuffer( dataIn,
    2. dataOut,
    3. RW,
    4. EN,
    5. Rst,
    6. EMPTY,
    7. FULL,
    8. Clk
    9. );
    10. input [3:0] dataIn;
    11. input RW,
    12. EN,
    13. Rst,
    14. Clk;
    15. output reg EMPTY,
    16. FULL;
    17. output reg [3:0] dataOut;
    18. reg [3:0] stack_mem[0:3];
    19. reg [2:0] SP;
    20. integer i;
    21. always @ (posedge Clk)
    22. begin
    23. if (EN==0);
    24. else begin
    25. if (Rst==1) begin
    26. SP = 3'd4;
    27. EMPTY = SP[2];
    28. dataOut = 4'h0;
    29. for (i=0;i<4;i=i+1) begin
    30. stack_mem[i]= 0;
    31. end
    32. end
    33. else if (Rst==0) begin
    34. FULL = SP? 0:1;
    35. EMPTY = SP[2];
    36. dataOut = 4'hx;
    37. if (FULL == 1'b0 && RW == 1'b0) begin
    38. SP = SP-1'b1;
    39. FULL = SP? 0:1;
    40. EMPTY = SP[2];
    41. stack_mem[SP] = dataIn;
    42. end
    43. else if (EMPTY == 1'b0 && RW == 1'b1) begin
    44. dataOut = stack_mem[SP];
    45. stack_mem[SP] = 0;
    46. SP = SP+1;
    47. FULL = SP? 0:1;
    48. EMPTY = SP[2];
    49. end
    50. else;
    51. end
    52. else;
    53. end
    54. end
    55. endmodule
    Figure 2. Verilog code for LIFO Buffer

  4. Verilog Test Bench for LIFO Buffer (LIFObuffer_tb.v)


    1. `timescale 1ns / 1ps
    2. module LIFObuffer_tb;
    3. // Inputs
    4. reg [3:0] dataIn;
    5. reg RW;
    6. reg EN;
    7. reg Rst;
    8. reg Clk;
    9. // Outputs
    10. wire [3:0] dataOut;
    11. wire EMPTY;
    12. wire FULL;
    13. // Instantiate the Unit Under Test (UUT)
    14. LIFObuffer uut (
    15. .dataIn(dataIn),
    16. .dataOut(dataOut),
    17. .RW(RW),
    18. .EN(EN),
    19. .Rst(Rst),
    20. .EMPTY(EMPTY),
    21. .FULL(FULL),
    22. .Clk(Clk)
    23. );
    24. initial begin
    25. // Initialize Inputs
    26. dataIn = 4'h0;
    27. RW = 1'b0;
    28. EN = 1'b0;
    29. Rst = 1'b1;
    30. Clk = 1'b0;
    31. // Wait 100 ns for global reset to finish
    32. #100;
    33. // Add stimulus here
    34. EN = 1'b1;
    35. Rst = 1'b1;
    36. #40;
    37. Rst = 1'b0;
    38. RW = 1'b0;
    39. dataIn = 4'h0;
    40. #20;
    41. dataIn = 4'h2;
    42. #20;
    43. dataIn = 4'h4;
    44. #20;
    45. dataIn = 4'h6;
    46. #20;
    47. RW = 1'b1;
    48. end
    49. always #10 Clk = ~Clk;
    50. endmodule
    Figure 3. Verilog Test-bench for LIFO Buffer

  5. Timing Diagram


    Figure 4. Timing Diagram of LIFO Buffer