1. Реализация модулей FIFO, LIFO

Очередь, FIFO (первым вошёл, первым вышел), Очередь

FIFO (очередь) представляет собой одномерную таблицу памяти, которая, как правило, используется в цифровых схемах для передачи данных между двумя схемами с различными тактовыми сигналами. Кроме того, существуют и другие области применения. FIFO реализуется на основе памяти с двумя портами входа/выхода и двумя указателями, которые указывают адреса, по которым должны читаться/записываться данные.

Изначально указатели указывают на один и тот же адрес. При каждой записи/чтении данных указатель записи/чтения инкрементируется. Когда указатель достигает последнего адреса, происходит переполнение, и он начинает снова инкрементироваться с адреса 0.

Для мониторинга состояния памяти (какие адреса свободны) добавляется регистр (fifo_counter), который инкрементируется/декрементируется при записи/чтении. Соответственно, когда значение этого регистра становится равным объёму памяти, устанавливается флаг, указывающий, что память полностью занята. И наоборот, если значение fifo_counter равно 0, устанавливается флаг, указывающий, что вся память свободна.


S1. Реализуйте указанный ниже модуль, используя компилятор языка Verilog.

module Queue (
    clk,
    rst,
    wr_cs,
    rd_cs,
    data_in,
    rd_en,
    wr_en,
    data_out,
    empty
);

parameter DATA_WIDTH = 8;
parameter ADDR_WIDTH = 8;
parameter RAM_DEPTH = (1 << ADDR_WIDTH);

input clk;
input rst;
input wr_cs;
input rd_cs;
input rd_en;
input wr_en;
input [DATA_WIDTH-1:0] data_in;
output full;
output empty;
output [DATA_WIDTH-1:0] data_out;

reg [ADDR_WIDTH-1:0] wr_pointer;
reg [ADDR_WIDTH-1:0] rd_pointer;
reg [ADDR_WIDTH:0] status_cnt;
reg [DATA_WIDTH-1:0] data_out;
wire [DATA_WIDTH-1:0] data_ram;

assign full = (status_cnt == (RAM_DEPTH-1));
assign empty = (status_cnt == 0);

always @ (posedge clk or posedge rst)
begin
    if (rst) begin
        wr_pointer <= 0;
    end else if (wr_cs && wr_en) begin
        wr_pointer <= wr_pointer + 1;
    end
end

always @ (posedge clk or posedge rst)
begin
    if (rst) begin
        rd_pointer <= 0;
    end else if (rd_cs && rd_en) begin
        rd_pointer <= rd_pointer + 1;
    end
end

always @ (posedge clk or posedge rst)
begin
    if (rst) begin
        data_out <= 0;
    end else if (rd_cs && rd_en) begin
        data_out <= data_ram;
    end
end

always @ (posedge clk or posedge rst)
begin
    if (rst) begin
        status_cnt <= 0;
    end else if ((rd_cs && rd_en) && !(wr_cs && wr_en) 
                 && (status_cnt != 0)) begin
        status_cnt <= status_cnt - 1;
    end else if ((wr_cs && wr_en) && !(rd_cs && rd_en)
                 && (status_cnt != RAM_DEPTH)) begin
        status_cnt <= status_cnt + 1;
    end
end

S2. Реализуйте TestBench для проверки и моделирования работы модуля. В рамках этого тестового стенда в качестве значений для проверки используйте вашу дату рождения.


Стек, LIFO (последним вошёл, первым вышел), Стек

Стек в Verilog моделируется аналогично очереди, однако, как правило, запись/чтение из стека происходит через один и тот же интерфейс, поэтому логика входа/выхода будет отличаться.


S3. Реализуйте указанный ниже модуль, используя компилятор языка Verilog. В рамках этого тестового стенда в качестве значений для проверки используйте вашу дату рождения.

module Stack (DataIO, Reset, Push, Pop, SP, Full, Empty, Err);
    inout [3:0] DataIO;
    input Push, Pop, Reset;
    output Full, Empty, Err;
    output [2:0] SP; // Указатель стека
    reg Empty, Err;
    reg Full;
    reg [2:0] SP;
    reg [3:0] Stack[7:0];
    reg [3:0] DataR;

    wire [3:0] #(0) DataIO = DataR;

    always @ (negedge Pop)
    begin
        DataR = 4'bzzzz;
    end

    always @ (posedge Push or posedge Pop or posedge Reset)
    begin
        if (Reset == 1)
        begin
            DataR = 4'bzzzz;
            SP = 3'b0;
            Full = 0;
            Empty = 0;
            Err = 0;
        end

        if (Push == 1) begin
            if (Empty == 1)
            begin
                Stack[SP] = DataIO;
                Empty = 0;
                if (Err == 1)
                    Err = 0;
            end
            else
                if (Full == 1)
                begin
                    Stack[SP] = DataIO;
                    Err = 1;
                end
                else
                begin
                    SP = SP + 1;
                    Stack[SP] = DataIO;
                    if (SP == 3'b111)
                        Full = 1;
                end
        end

        if (Pop == 1) begin
            if ((SP == 3'b000) && (Empty != 1))
            begin
                DataR = Stack[SP];
                Empty = 1;
            end
            else
                if (Empty == 1)
                begin
                    DataR = Stack[SP];
                    Err = 1;
                end
                else
                begin
                    DataR = Stack[SP];
                    if (SP != 3'b000)
                        SP = SP - 1;
                    if (Err == 1) Err = 0;
                    if (Full == 1) Full = 0;
                end
        end
    end
endmodule

S4. Реализуйте TestBench для проверки и моделирования работы модуля. В рамках этого тестового стенда в качестве значений для проверки используйте вашу дату рождения.


Ход работы

  1. Реализуйте модуль FIFO, используя компилятор языка Verilog.
  2. Реализуйте TestBench для проверки и моделирования работы модуля FIFO. В рамках этого тестового стенда в качестве значений для проверки используйте вашу дату рождения.
  3. Реализуйте модуль LIFO, используя компилятор языка Verilog.
  4. Реализуйте TestBench для проверки и моделирования работы модуля LIFO. В рамках этого тестового стенда в качестве значений для проверки используйте вашу дату рождения.