Опубликован: 17.03.2025 | Доступ: свободный | Студентов: 0 / 0 | Длительность: 07:30:00
Лекция 9:

Проектирование счетчика инструкций, памяти инструкций и памяти данных

< Лекция 8 || Лекция 9: 12 || Лекция 10 >

Рис. 9.6.

Далее разместим на поле счетчик инструкций PC, АЛУ (ALU) и регистровый файл (RegFile). Проведем соединения адресных линий от счетчика к ПЗУ. Подключение осуществить с применением элемента "Разветвитель". Которому задать свойства:

  • "Внешний вид" - леворукий;
  • "Веерный выход" - 1;
  • "Разрядность входа" - 32;
  • Бит 0 - нет, Бит 1 - нет;
  • Бит с 16 и до 32 - нет.

Выход АЛУ также через разветвитель подключить к входу адреса ОЗУ. Единственное изменить настройки таким образом, чтобы с ОЗУ соединялись биты со 2 по 9, что соответствует 256 ячейкам памяти.

Выход данных rs2 регистрового файла подключим к входу D ОЗУ.

Добавим на поле мультиплексор с разрядностью 32 и свойством "Выбирающие биты" 1. Вход 0 мультиплексора подключим к выходу АЛУ. Второй вход подключить к выходу D ОЗУ. Выход мультиплексора подключить к входу данных регистрового файла DataIn. Организация такой схемы как раз обусловлена тем, что сначала данные загружаются в регистры, выполняется соответствующая операция, затем данные загружаются в память. Также данные из памяти загружаются в регистры, а потом в память.

За данный процесс отвечает дешифратор инструкций и блок управления.

На рисунке 9.7 показан результат объединения счетчика инструкций PC и памяти инструкций (IMEM). На рисунке 9.8 приведена схема включения операционного блока с памятью данных.


Рис. 9.7.

Рис. 9.8.

Для проектирования регистрового файла в среде Quartus, в существующем проекте RISC_V, создать новый Verilog HDL File. Сохранить файл как PCUnit.v.

Проектируемый в целом отражает функциональную схему, приведенную на рисунке 9.1, но в него уже интегрированы входы переходов с блока управления ветвлениями, который будет рассмотрен далее. В листинге 9.1 приведен код счетчика инструкций.

module PCUnit(
    input clk,                  // тактовый сигнал
    input reset,                // сигнал сброса
    input branchTaken,          // сигнал ветвления
    input [31:0] branchAddr,    // адрес для перехода при ветвлении
    output reg [31:0] pc        // выход счетчика
);
    

    // Инициализация PC стартовым адресом
    initial pc = 32'b0;

    // анализ сигнала clk по фронту
    always @(posedge clk) begin
        if (reset) begin
            // Установка PC в начальный адрес при сбросе
            pc  <= 32'b0;
        end else if (branchTaken) begin
            // Если присутсвует сигнал перехода то счетчик указывает на адрес branchAddr
            pc  <= branchAddr;
        end else begin
            // иначе PC увеличивается на 4
            pc  <= pc + 4;
        end
    end
endmodule
Листинг 9.1.

На рисунке 9.9 приведен вид RTL созданного модуля.


Рис. 9.9.

Оперативное запоминающее устройство, выполняющее функции памяти данных, создаваемая на Verilog HDL имеет аналогичные порты адреса и данных, а также входы управления записью и чтением. Для получения памяти данных в проекте создадим файл DataMemory.v и введем код из листинга 9.2.

module DataMemory (
    input clk, //синхросигнал
    input [31:0] addr, // шина адреса
    input [31:0] writeData, //входная шина данных 
    input memWrite, // сигнал управления записи
    input memRead, //сигнал управления чтением
    output [31:0] readData //выход данных
);
    reg [7:0] mem [0:255];// объем памяти равен 256 байт

    // Чтение данных
    assign readData = memRead ? {mem[addr+3], mem[addr+2], mem[addr+1], mem[addr]} : 32'b0;
	// здесь данные как раз объединаются с применением конкатенации
    // Запись данных по фронту clk
    always @(posedge clk) begin
        if (memWrite) begin 
            //здесь данные из 32-х битного слова делятся на 4 байта 
				mem[addr]    <= writeData[7:0];
            mem[addr+1]  <= writeData[15:8];
            mem[addr+2]  <= writeData[23:16];
            mem[addr+3]  <= writeData[31:24];
				//здесь данные из 32-х битного слова делятся на 4 байта 
        end
    end
endmodule
Листинг 9.2.

На рисунке 9.10 приведен вид RTL созданного модуля.


Рис. 9.10.

Для процессора требуется описать память инструкций. На данном моменте требуется отметить, что память инструкций - обычно модуль ROM. Данный модуль содержит код, записанный заранее. Данная память может содержать код программы в виде констант с заранее определенными адресами:

always @ (addr)
       case (addr)
32'h00000000: instr  <= 32'b001000_00000_10000_0000000011111111;
32'h00000004: instr  <= 32'b101011_00000_10000_1111000000000000;

Второй вариант применение файла инициализации, чтобы загрузить данные в модуль ROM из внешнего текстового файла. Это применяется как правило для загрузки больших таблиц кода.

Пример кода для данного метода имеет вид:

initial begin 
$readmemh("rom_data.hex", rom); 
End

Для первичной проверки работоспособности проектируемого процессора будет создана память инструкций, содержащая код программы непосредственно внутри модуля.

Для получения памяти инструкций в проекте создадим файл InstructionMemory.v и введем код из листинга 9.3.

module InstructionMemory(
    input [31:0] addr, // шина адреса
    output [31:0] instr // шина данных выхода 
);
    reg [31:0] mem [0:63]; // объем памяти 64 инструкции по 32 бит

    initial begin
        // Пример инструкций
        mem[0] = 32'h00000013; // ADDI r1, r0, 0 (NOP)
        mem[1] = 32'h002081B3; // ADD x3, x1, x2
        mem[2] = 32'h40400013; // ADDI x1, x0, 64
        
    end
    assign instr = mem[addr[31:2]]; // Выравнивание по 4 байтам
endmodule
Листинг 9.3.

На рисунке 9.11 приведен вид RTL созданного модуля.


Рис. 9.11.
< Лекция 8 || Лекция 9: 12 || Лекция 10 >