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

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

Содержимое файла ROM памяти приведено ниже

v3.0 hex words addressed
0000: 00000093 0010a0a3 00100093 0010a223 00100133 0020a423 002081b3 0030a623
0008: 00310233 0040a823 004182b3 0050aa23 00520333 0060ac23 006283b3 0070ae23
0010: 00730433 0280a023 008384b3 0290a223 00000513 00000073 00000000 00000000

На рисунке 10.28 приведен итог вычисления числа Фибоначчи. Он должен соответствовать результату вычисления в линейном алгоритме.


Рис. 10.28.

Для завершения проектирования процессора на языке Verilog HDL необходимо вернуться в среду в ранее созданный проект RISC_V. Реализуем блок переходов BranchUnit. Как видно из рисунка 10.23 в его основе лежат компараторы, выполняющие сравнение двух 32-х битных кодов. В зависимости от кода на шине funct3 коммутирующие результирующий сигнал сравнения на выход. На языке Verilog HDL данная схема может быть реализована так как показано в листинге 10.4 (файл BranchUnit.v)

module BranchUnit(
    input [31:0] srcA, srcB, //входы данных с регистров
    input [2:0] funct3, // вход funct3
    output reg branchTaken //выход сигнализирующий о наличии перехода
);
    always @(*) begin
        case (funct3)
            3'b000: branchTaken = (srcA == srcB); // BEQ
            3'b001: branchTaken = (srcA != srcB); // BNE
            3'b100: branchTaken = ($signed(srcA) < $signed(srcB)); // BLT
            3'b101: branchTaken = ($signed(srcA) >= $signed(srcB)); // BGE
            3'b110: branchTaken = (srcA < srcB); // BLTU
            3'b111: branchTaken = (srcA >= srcB); // BGEU
            default: branchTaken = 1'b0; // по умолчанию выход 0 
        endcase
    end
endmodule
Листинг 10.4.

На рисунке 10.29 приведен вид RTL созданного модуля. Развернув его (рисунок 10.30) , можно убедится в эквивалентности схемы, приведенной на рисунке 10.23.


Рис. 10.29.

Рис. 10.30.

Реализуем модуля дешифратора операций АЛУ. Для этого создадим файл ALUDecoder.v. В листинге 10.5 приведен код данного модуля. Анализируя поля funct7, funct3 инструкции RISC-V, а также поле aluOp формируемое блоком ControlUnit данный дешифратор осуществляет формирование кода микрооперации в АЛУ.

module ALUDecoder(
    input [6:0] funct7,
    input [2:0] funct3,
    input [1:0] aluOp,//код операции
    output reg [3:0] aluControl
);
    always @(*) begin
        case (aluOp)
            2'b00: aluControl = 4'b0000; // операции загрузка/сохранение (ADD)
            2'b01: aluControl = 4'b0001; // операция ветвления (SUB)
            2'b10: begin // R-type инструкции
                case ({funct7, funct3})
                    10'b0000000000: aluControl = 4'b0000; // ADD
                    10'b0100000000: aluControl = 4'b0001; // SUB
                    10'b0000000111: aluControl = 4'b0010; // AND
                    10'b0000000110: aluControl = 4'b0011; // OR
                    10'b0000000100: aluControl = 4'b0100; // XOR
                    10'b0000000001: aluControl = 4'b0101; // SLL
                    10'b0000000101: aluControl = 4'b0110; // SRL
                    10'b0100000101: aluControl = 4'b0111; // SRA
                    10'b0000000010: aluControl = 4'b1000; // SLT
                    10'b0000000011: aluControl = 4'b1001; // SLTU
                    default: aluControl = 4'b0000;
                endcase
            end
            default: aluControl = 4'b0000;
        endcase
    end
endmodule
Листинг 10.5.

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


Рис. 10.31.

Следующим этапом выполним построение "сплиттера" кода инструкции - дешифратора инструкции (схемотехническая реализация разборки кода инструкции рассмотрена нами в начале данного раздела). Создадим в проекте RISC_V новый файл с именем InstructionDecoder.v. Внесем в него код из листинга 10.6.

module InstructionDecoder(
    input [31:0] instr,
    output [6:0] opcode,
    output [4:0] rd,
    output [2:0] funct3,
    output [4:0] rs1, rs2,
    output [6:0] funct7,
    output [31:0] imm
);
    assign opcode = instr[6:0];// выделяем 0 по 6 бит под opcode
    assign rd = instr[11:7]; //с 7 по 11 бит адрес регистра назначения
    assign funct3 = instr[14:12]; //с 12 по 14 бит поле funct3
    assign rs1 = instr[19:15];//с 15 по 19 бит адрес регистра источника 1
    assign rs2 = instr[24:20];//с 20 по 24 бит адрес регистра источника 2
    assign funct7 = instr[31:25];
    assign imm = { {21{instr[31]}}, instr[30:20] }; //формируемое поле //непосредственных значений Immediate (I-Type)
endmodule
Листинг 10.6.

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


Рис. 10.32.

Если раскрыть модуль InstructionDecoder, то можно наблюдать разветвление эквивалентное разветвителю, приведенному на рисунке 10.12 (рисунок 10.33).