Опубликован: 17.03.2025 | Доступ: свободный | Студентов: 0 / 0 | Длительность: 07:30:00
Лекция 10:
Проектирование блока управления
Последним функциональным модулем процессора выступит модуль 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 созданного модуля.
Все модули объединяются файлом верхнего уровня 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 вид процессора.
Литература
- С. Харрис, Д. Харрис. Цифровая схемотехника и архитектура компьютера RISC-V/ пер. с англ. В.С. Яценкова, А.Ю. Романова; под. ред. А.Ю. Романова.-М.: ДМК Пресс, 2021. - 810 с.: ил.
- СКВОЗНОЙ ЛАБОРАТОРНЫЙ ПРАКТИКУМ ПО ТЕХНОЛОГИЯМ RISC-V
- Курс "Основы программирования на языке Assembler под архитектуру RISC-V"