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

Разработка простейшего декодера команд RISC-V

< Лекция 3 || Лекция 4: 1234 || Лекция 5 >
Базовые форматы команд RISC-V, показывающие варианты размещения immediate с слове инструкции

Рис. 4.4. Базовые форматы команд RISC-V, показывающие варианты размещения immediate с слове инструкции

Ну и самое "весёлое" - собирать immediate по слову инструкции. Вишенкой на торте великой и свободной архитектуры RV, победно шествующей по миру - является именно кодировка в командах констант и непосредственных значений. Она вызывает прям бурю эмоций и восторга своей красотой и элегантностью технических решений. Небольшая шпаргалка на эту тему есть в спецификации - рис.4.5.

Непосредственные значения, создаваемые инструкциями RISC-V. Поля помечены битами команд, используемыми для построения их значения. Расширение знака всегда использует бит inst[31]

Рис. 4.5. Непосредственные значения, создаваемые инструкциями RISC-V. Поля помечены битами команд, используемыми для построения их значения. Расширение знака всегда использует бит inst[31]

Расширение знака всегда использует inst[31]. Расширение знака является одной из наиболее важных операций с immediates (особенно в RV64I), и в RISC-V бит знака для всех immediate всегда хранится в бите 31 инструкции, чтобы позволить расширению знака выполняться параллельно с декодированием команды.

Один из удобных инструментариев полезных при освоении ассемблера RISC-V, а также для целей тестирования разрабатываемых узлов процессора - симулятор RV32 - RARS- http://github.com/TheThirdOne/rars/releases - чтоб спокойно генерировать бинарные опкоды команд, а не писать их вручную с риском ошибиться в паре-тройке бит.

Декомпозиция…

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

Таким образом, декодер составится из блоков:

  • формирователь непосредственных значений;
  • декодер адресов регистров-операндов и функциональных полей.

Формирователь непосредственных значений

Формирователь непосредственных значений - принимает на вход 32 бита инструкции, на выходе формирует 32-битное непосредственное значение и сигнал "валидности" значения - 1, если из инструкции декодирован immediate, и 0, если его в команде нет - например, для команд R-типа.

Код:

module rv_imm
( input [31:0] inst,
  output reg [31:0] imm,
  output reg imm_en
);
wire [6:0] opcode;
wire [19:0] sign;
//wire zero;

assign opcode[6:0] = inst[6:0];
assign sign = {
    inst[31],inst[31],inst[31],inst[31],inst[31],//inst[31],
    inst[31],inst[31],inst[31],inst[31],inst[31],//inst[31],
    inst[31],inst[31],inst[31],inst[31],inst[31],//inst[31],
    inst[31],inst[31],inst[31],inst[31],inst[31]//,inst[31]
            };
//assign zero = 1'b0;

always @ *
begin
  case (opcode)
    //I-type
    7'b00000_11 : begin
        imm <= {sign,inst[31:20]}; $display ("LOAD"); 
        imm_en <= 1'b1;
        end
    7'b00011_11 : begin
        imm <= {sign,inst[31:20]}; $display ("Misc-MEM");
        imm_en <= 1'b1;
        end
    7'b00100_11 : begin
        imm <= {sign,inst[31:20]}; $display ("OP-Imm");
        imm_en <= 1'b1;
        end
    7'b11100_11 : begin
        imm <= {sign,inst[31:20]}; $display ("SYSTEM");
        imm_en <= 1'b1;
        end
    7'b11001_11 : begin
        imm <= {sign,inst[31:20]}; $display ("JALR");
        imm_en <= 1'b1;
        end
    //J-type
    7'b11011_11 : begin
        imm <= {sign[19:8],inst[19:12],inst[20],inst[30:25],inst[24:21],1'b0}; //J-type
        $display("JAL");
        imm_en <= 1'b1;
        end
    //S-type
    7'b01000_11 : begin
        imm <= {sign,inst[31:25],inst[11:7]}; 
        $display("Store");
        imm_en <= 1'b1;
        end
    //U-type
    7'b01101_11 : begin
        imm <= {inst[31:12],12'b0};
        $display("LUI");
        imm_en <= 1'b1;
        end
    7'b00101_11 : begin 
        imm <= {inst[31],inst[30:20],inst[19:12],12'b0};
        $display("AUIPC");
        imm_en <= 1'b1;
        end
    //B-type
    7'b11000_11 : begin
        imm <= {sign,inst[7],inst[30:25],inst[11:8],1'b0};
        $display("BRANCH");
        imm_en <= 1'b1;
        end
    default: begin
        imm <= 32'h00; $display ("default");
        imm_en <= 1'b0;
        end
  endcase
end
endmodule

Тестбэнч:

`include "rv_imm.v"
`timescale 10ns/1ns
/*
  input [31:0] inst,
  output reg [31:0] imm,
  output reg imm_en
*/ 
module testbench; // input and output test signals
reg  [31:0] inst;
wire [31:0] imm;    
wire [31:0] imm_en;
// creating the instance of the module we want to test    
//  bcd_to_sseg - module name    
//  dut  - instance name ('dut' means 'device under test')    
rv_imm dut( inst, imm, imm_en );    
// do at the beginning of the simulation    
initial         
  begin            
    inst = 32'h50b7;    // set test signals value            
    #10;            // pause            
    inst = 32'h0137;    // set test signals value            
    #10;            // pause            
    inst = 32'h508193;    // set test signals value            
    #10;            // pause            
    inst = 32'h502083;    // set test signals value            
    #10;            // pause        
    inst = 32'hfe000ce3;    // set test signals value            
    #10;            // pause        
    inst = 32'h77237;    // set test signals value            
    #10;            // pause        
    inst = 32'hc0d093;    // set test signals value            
    #10;            // pause        
    inst = 32'hff9ff2ef;    // set test signals value            
    #10;            // pause        

  end    // do at the beginning of the simulation    
//  print signal values on every change    
initial         
  $monitor("inst=%h imm=%h", inst, imm, imm_en);    
// do at the beginning of the simulation    
initial         
  $dumpvars;  //iverilog dump init
endmodule

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

< Лекция 3 || Лекция 4: 1234 || Лекция 5 >