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

Проектирование блока управления


Рис. 10.33.

Последним функциональным модулем процессора выступит модуль ControlUnit. Данный модуль формирует сигналы управления в зависимости от поля opcode инструкции.

Для описания данного модуля создадим файл ControlUnit.v и введем код из листинга 10.7.

module ControlUnit(
    input [6:0] opcode,
    output reg [1:0] aluOp,
    output reg memWrite,
    output reg memRead,
    output reg branch,
    output reg regWrite,
    output reg jump // переход операций JAL и JALR
);
    always @(*) begin
        case (opcode)
            7'b0000011: begin // Load (I-type)
                aluOp = 2'b00;
                memWrite = 0;
                memRead = 1;
                branch = 0;
                regWrite = 1;
                jump = 0;
            end
            7'b0100011: begin // Store (S-type)
                aluOp = 2'b00;
                memWrite = 1;
                memRead = 0;
                branch = 0;
                regWrite = 0;
                jump = 0;
            end
            7'b1100011: begin // Branch (B-type)
                aluOp = 2'b01;
                memWrite = 0;
                memRead = 0;
                branch = 1;
                regWrite = 0;
                jump = 0;
            end
            7'b0110011: begin // R-type
                aluOp = 2'b10;
                memWrite = 0;
                memRead = 0;
                branch = 0;
                regWrite = 1;
                jump = 0;
            end
            7'b1100111: begin // JALR (I-type)
                aluOp = 2'b00; // Используется для вычисления адреса (PC + imm)
                memWrite = 0;
                memRead = 0;
                branch = 0;
                regWrite = 1; // Результат записывается в регистр
                jump = 1; // Указывает на команду перехода
            end
            7'b1101111: begin // JAL (UJ-type)
                aluOp = 2'b00; 
                memWrite = 0;
                memRead = 0;
                branch = 0;
                regWrite = 1; // Результат записывается в регистр
                jump = 1; // Указывает на команду перехода
            end
            7'b0110111: begin // LUI (U-type)
                aluOp = 2'b11; 
                memWrite = 0;
                memRead = 0;
                branch = 0;
                regWrite = 1; // Загружаем значение в регистр
                jump = 0;
            end
            default: begin
                aluOp = 2'b00;
                memWrite = 0;
                memRead = 0;
                branch = 0;
                regWrite = 0;
                jump = 0;
            end
        endcase
    end
endmodule
Листинг 10.7.

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


Рис. 10.34.

Все модули объединяются файлом верхнего уровня RISC_V.v код которого приведен в листинге 10.8.

module RISC_V(
    input clk,        // Основной тактовый сигнал
    input reset       // Сигнал сброса для процессора
);

 
    wire [31:0] pc;           // Счетчик команд (текущий адрес инструкции)
    wire [31:0] instr;        // Инструкция, извлеченная из памяти команд
    wire [31:0] readData1;    // Данные из первого регистра
    wire [31:0] readData2;    // Данные из второго регистра
    wire [31:0] aluResult;    // Результат вычислений АЛУ
    wire [31:0] imm;          // непосредственные значения из памяти
    wire memWrite;            // Сигнал записи данных в память данных
    wire memRead;             // Сигнал чтения данных из памяти данных
    wire regWrite;            // Сигнал записи в регистровый файл
    wire branchTaken;         // Флаг, указывающий на необходимость условного перехода
    wire jump;                // Флаг, указывающий на выполнение безусловноного
    wire [3:0] aluControl;    // Сигналы микроопераций для АЛУ
    wire [6:0] opcode;        // opcode извлеченной инструкции
    wire [4:0] rd, rs1, rs2;  // Регистр назначения и регистры-источники
    wire [2:0] funct3;        // Поле funct3
    wire [6:0] funct7;        // Поле funct3

 
    
    // Модуль счетчика команд (Program Counter)
    
    PCUnit pc_unit (
        .clk(clk),               // Синхровход
        .reset(reset),           // Сигнал сброса
        .branchTaken(branchTaken), //Указание на ветвление
        .branchAddr(aluResult),  // Адрес перехода при ветвлении
        .pc(pc)                  // Текущий адрес инструкции
    );

    // Модуль памяти инструкций (Instruction Memory)
    
    InstructionMemory instr_mem (
        .addr(pc),               // Вход адреса текущей инструкции
        .instr(instr)            // код инструкции
    );

    // Дешифратор инструкции (Instruction Decoder)
   
    InstructionDecoder instr_decoder (
        .instr(instr),           // На вход извлеченная инструкция
        .opcode(opcode),         // выход содержащий Opcode
        .rd(rd),                 // Выход, указывающий адрес регистра назначения (Rd)
        .funct3(funct3),         // Выход funct3 
        .rs1(rs1),               // Выход, указывающий адрес исходного регистра 1 (Rs1)
        .rs2(rs2),               // Выход, указывающий адрес исходного регистра 1 (Rs1)
        .funct7(funct7),         // Выход funct7 
        .imm(imm)                // непосредственное (немедленное значение (Immediate))
    );

    // Регистровый файл (Register File)
   
    RegisterFile reg_file (
        .clk(clk),               // Синхровход
        .reset(reset),           // Сигнал сброса
        .regWrite(regWrite),     // Сигнал управления записью в регистры
        .rs1(rs1),               // Вход адреса регистра Rs1 для чтения
        .rs2(rs2),               // Вход адреса регистра Rs2 для чтения
        .rd(rd),                 // Вход адреса регистра Rd для записи
        .writeData(aluResult),   // Шина данных для записи в регистр
        .readData1(readData1),   // Шина данных выхода из Rs1
        .readData2(readData2)    // Шина данных выхода из Rs2
    );

    // Модуль управления (Control Unit)
    
    ControlUnit control_unit (
        .opcode(opcode),         // Вход для поля opcode из инструкции
        .aluOp(aluOp),           // Выход - код для дешифратора АЛУ
        .memWrite(memWrite),     // Выходной сигнал управления записью в память
        .memRead(memRead),       // Выходной сигнал управления чтением из памяти
        .branch(branch),         // Выходной сигнал указывающий на ветвление
        .regWrite(regWrite),     // Выходной сигнал управления записью в регистры
        .jump(jump)              // Выходной сигнал безусловного перехода
    );

    // Дешифратор операций АЛУ (ALU Decoder)
   
    ALUDecoder alu_decoder (
        .funct7(funct7),         // Входное поле Funct7
        .funct3(funct3),         // Входное поле Funct3
        .aluOp(aluOp),           // Вход кода от ControlUnit
        .aluControl(aluControl)  // выход кода микрооперации
    );

    // Арифметико-логическое устройство (АЛУ)
   
    ALU alu (
        .srcA(readData1),        // Вход первый операнд (Rs1)
        .srcB(                  // Вход второй операнд
            (opcode == 7'b0000011 || opcode == 7'b0100011) 
            ? readData2 : imm    // Используется Immediate для операций загрузки/сохранения
        ),
        .aluControl(aluControl), // код микроопрации
        .aluResult(aluResult)    // Результат работы АЛУ
    );

    // Оперативная память данных (Data Memory)
    
    DataMemory data_memory (
        .clk(clk),               // Синхровход
        .addr(aluResult),        // Адрес памяти (выход результата АЛУ)
        .writeData(readData2),   // Данные для записи в память
        .memWrite(memWrite),     // Сигнал управления записи в память
        .memRead(memRead),       // Сигнал управления чтения из памяти
        .readData(readData)      // Данные, считанные из памяти
    );

    // Модуль ветвления (Branch Unit)
        BranchUnit branch_unit (
        .srcA(readData1),        // Первый операнд для сравнения
        .srcB(readData2),        // Второй операнд для сравнения
        .funct3(funct3),         // Тип сравнения (BEQ, BNE и т.д.)
        .branchTaken(branchTaken)// Флаг наличия перехода
    );

endmodule
Листинг 10.8.

На рисунке 10.35 представлен RTL вид процессора.


Рис. 10.35.

Литература

  1. С. Харрис, Д. Харрис. Цифровая схемотехника и архитектура компьютера RISC-V/ пер. с англ. В.С. Яценкова, А.Ю. Романова; под. ред. А.Ю. Романова.-М.: ДМК Пресс, 2021. - 810 с.: ил.
  2. СКВОЗНОЙ ЛАБОРАТОРНЫЙ ПРАКТИКУМ ПО ТЕХНОЛОГИЯМ RISC-V
  3. Курс "Основы программирования на языке Assembler под архитектуру RISC-V"