目录
4. 修改Main Decoder,ALU Decoder和ImmSrc真值表
(一)问题重述
对授课内容的单周期 RISC-V 处理器进行扩展,使之能够支持两个额外的指令:lui 和 xor。设计报告中需涵盖以下内容:
1、请说明在这个设计过程中你共耗时多久,评估一下这次设计的工作量。
2、在图中标记显示所需的修改。
3、如果修改过,则在图中标记所加指令(lui 和 xor)所需的修改。
4、修改Main Decoder, ALU Decoder和ImmSrc真值表,以支持lui和xor。
5、修改提供的 Verilog 代码 top.v,增加 lui 和 xor 指令。
6、修改提供的验证代码 tb_top.v,能测试 lui 和 xor。
7、提供运行测试程序的仿真波形(按以下列出的顺序:clk、reset、PC、Instr、SrcA、SrcB、 ALUResult、DataAdr、WriteData 和 MemWrite,为了便于阅读,所有波形都以十六进制显示)。观察波形并圈出或高亮显示波形,表明正确的值写入了正确的地址,并确保它是可读的。
(二)指令介绍
本次课程设计1中需要添加lui和xor两个指令,它们均是RISC-V指令系统中的指令,其中lui属于U-type指令,xor属于R-type指令。
lui全称load upper immediate,即取立即数高位,用于将高20位常数加载到寄存器的第31位到第12位,将寄存器的低12位用0填充。RISC-V使用I-type格式的指令和U-type格式的指令加载立即数,I-type格式包含12位立即数,U-type格式包含20位立即数,而且这20位是加载到寄存器的高20位的,U类型指令将32位划分为3个区域,如图1-1所示。该指令会与ADDI指令一起使用,目的是将低12位写入目标寄存器,以实现对32位的寄存器数值设置。其操作过程如下所示:
LUI x10,0x87654 # x10 = 0x87654000
ADDI x10,x10,0x321 # x10 = 0x87654321
图1-1 U类型指令
xor指令是在两个操作数的对应位之间进行(按位)逻辑异或操作,并将结果存放在目标操作数中。与0异或值保持不变,与1异或则被触发(求补)。R类型指令将32位划分为6个区域,如图1-2所示。对相同操作数进行两次xor运算,则结果逆转为其本身。如下表所示,位x与位y进行了两次异或,结果逆转为 x 的初始值,异或运算这种“可逆的”属性使其成为简单对称加密的理想工具。
图1-2 R类型指令
(三)处理思路
经过我的考虑与分析,关于增加lui指令有两种方法(本实验采用方法2):
(1)增加ALUsrcAmux,当控制信号ALUsrcA为1时,表示进入ALU的数为0;ALUsrcA为0时,表示进入ALU的数为RD1,然后将0与lui扩展后的立即数进行相加,将ALUresult的结果经resultmux输出到Register file;
(2)将lui扩展后的立即数直接输入到resultmux,增加状态ResultSrc==11时输出到Register file。
增加xor指令时,只需要在ALU单元中直接分配资源,使得Funct3为100时执行xor(异或运算即可),不需要修改RISC-V处理器的其它部分。
(四)设计过程
1. 评估本次设计的任务量
在本次课程设计1的完成过程中,我大概耗费了四天时间。耗时之久,主要在于完成过程中时间跨度比较大。在11月份耗时两天初步完成了设计要求,第一天复习了一下课程中RISC-V单周期处理器的内容,然后分析了一下增加lui和xor两条指令需要修改的控制单元以及verilog程序,第二天进行程序的调试发现总是报错,就先暂停了。在12月底又耗时两天完成了本次设计,第一天发现是modelsim问题导致出错,改用vivado软件后程序正常运行,然后进行程序设计的验证,第二天书写了本次报告。
2. 修改单周期处理器
图1-3 单周期处理器修改图
增加一条从Extend到Result选择器(11)的通路,如图1-3所示。
3. 修改控制单元及ALU
将控制单元中的Immsrc1:0扩展到3位,变为Immsrc2:0,如图1-4所示。在ALU中增加ALUControl=100的情况,如图1-4所示。
图1-4 控制单元修改图
图1-5 ALU修改图
4. 修改Main Decoder,ALU Decoder和ImmSrc真值表
lui属于U-type指令,xor属于R-type指令,所以只需在Main Decoder中增加U-type指令,如表1-1所示.。
表1-1 Main Decode真值表
Instruction | Opcode | RegWrite | ImmSrc | ALUSrcA | ALUSrcB | MemWrite | ResultSrc | Branch | ALUOp | Jump |
lw | 0000011 | 1 | 000 | 0 | 1 | 0 | 01 | 0 | 00 | 0 |
sw | 0100011 | 0 | 001 | 0 | 1 | 1 | xx | 0 | 00 | 0 |
R-type | 0110011 | 1 | xxx | 0 | 0 | 0 | 00 | 0 | 10 | 0 |
beq | 1100011 | 0 | 010 | 0 | 0 | 0 | xx | 1 | 01 | 0 |
I-type | 0010011 | 1 | 000 | 0 | 1 | 0 | 00 | 0 | 10 | 0 |
jal | 1101111 | 1 | 011 | x | x | 0 | 10 | 0 | xx | 1 |
U-type(lui) | 0110111 | 1 | 100 | 0 | 1 | 0 | 11 | 0 | 00 | 0 |
在ALU Decoder中增加Funct3=100的情况,如表1-2所示。
表1-2 ALU Decode真值表
ALUOp1:0 | Funct3 | {op5, funct75} | ALUControl | |
00 | x | x | 000 | Add |
01 | x | x | 001 | Subtract |
10 | 000 | 00,01,10 | 000 | Add |
000 | 11 | 001 | Subtract | |
010 | x | 101 | SLT | |
100 | X | 100 | XOR | |
110 | x | 011 | OR | |
111 | x | 010 | AND |
RISC-V使用I-type格式的指令和U-type格式的指令加载立即数,I-type格式包含12位立即数,U-type格式包含20位立即数,而且这20位是加载到寄存器的高20位的,如表1-3所示。
表1-3 ImmSrc编码表
ImmSrc | ImmExt | Type | Description |
000 | {{20{Instr[31]}}, Instr[31:20]} | I | 12-bit signed immediate |
001 | {{20{Instr[31]}}, Instr[31:25], Instr[11:7]} | S | 12-bit signed immediate |
010 | {{20{Instr[31]}}, Instr[7], Instr[30:25], Instr[11:8], 1’b0} | B | 13-bit signed immediate |
011 | {{12{Instr[31]}}, Instr[19:12], Instr[20], Instr[30:21], 1’b0} | J | 21-bit signed immediate |
100 | { Instr[31:12,12’b000000000000]} | U | 20-bit signed immediate |
- 修改代码top.v
- 将Immsrc改为3位,针对lui立即数扩展,增加case (immsrc)==100的情况;
- 修改maindec中的case(op),实现lui;
- 将mux改为4输入,增加alucontrol==100的情况;
- 修改aludec中的case (funct3),实现xor。
代码修改的部分地方如图1-6所示。
图1-6 代码修改部分示意图
5. 修改tb_top.v测试lui和xor
编写机器码存放于riscvtest1文件中,其思路如图1-7所示。
图1-7 测试代码编写过程示意图
在tb_top.v中增加代码如图1-8所示。
图1-8 tb_top.v代码修改
测试成功如图1-9和1-10所示。
图 1-9 控制台输出成功显示
图1-10 测试lui和xor仿真结果
6. 运行所给测试程序
得到的仿真波形图如图1-11所示,可以看出所有信号均正常。
图1-11 测试样例仿真结果
(五)代码
`timescale 1ns / 1ps
module top (
input wire clk,
input wire reset,
output wire [31:0] WriteData,
output wire [31:0] DataAdr,
output wire MemWrite
);
wire [31:0] PC;
wire [31:0] Instr;
wire [31:0] ReadData;
riscvsingle rvsingle(
.clk(clk),
.reset(reset),
.PC(PC),
.Instr(Instr),
.MemWrite(MemWrite),
.ALUResult(DataAdr),
.WriteData(WriteData),
.ReadData(ReadData)
);
imem imem(
.a(PC),
.rd(Instr)
);
dmem dmem(
.clk(clk),
.we(MemWrite),
.a(DataAdr),
.wd(WriteData),
.rd(ReadData)
);
endmodule
module riscvsingle (
input wire clk,
input wire reset,
output wire [31:0] PC,
input wire [31:0] Instr,
output wire MemWrite,
output wire [31:0] ALUResult,
output wire [31:0] WriteData,
input wire [31:0] ReadData
);
wire ALUSrc;
wire RegWrite;
wire Jump;
wire Zero;
wire [1:0] ResultSrc;
wire [2:0] ImmSrc; //修改丿3bit
wire [2:0] ALUControl;
wire PCSrc;
controller c(
.op(Instr[6:0]),
.funct3(Instr[14:12]),
.funct7b5(Instr[30]),
.Zero(Zero),
.ResultSrc(ResultSrc),
.MemWrite(MemWrite),
.PCSrc(PCSrc),
.ALUSrc(ALUSrc),
.RegWrite(RegWrite),
.Jump(Jump),
.ImmSrc(ImmSrc),
.ALUControl(ALUControl)
);
datapath dp(
.clk(clk),
.reset(reset),
.ResultSrc(ResultSrc),
.PCSrc(PCSrc),
.ALUSrc(ALUSrc),
.RegWrite(RegWrite),
.ImmSrc(ImmSrc),
.ALUControl(ALUControl),
.Zero(Zero),
.PC(PC),
.Instr(Instr),
.ALUResult(ALUResult),
.WriteData(WriteData),
.ReadData(ReadData)
);
endmodule
module controller (
input wire [6:0] op,
input wire [2:0] funct3,
input wire funct7b5,
input wire Zero,
output wire [1:0] ResultSrc,
output wire MemWrite,
output wire PCSrc,
output wire ALUSrc,
output wire RegWrite,
output wire Jump,
output wire [2:0] ImmSrc, //修改丿3bit
output wire [2:0] ALUControl
);
wire [1:0] ALUOp;
wire Branch;
maindec md(
.op(op),
.ResultSrc(ResultSrc),
.MemWrite(MemWrite),
.Branch(Branch),
.ALUSrc(ALUSrc),
.RegWrite(RegWrite),
.Jump(Jump),
.ImmSrc(ImmSrc),
.ALUOp(ALUOp)
);
aludec ad(
.opb5(op[5]),
.funct3(funct3),
.funct7b5(funct7b5),
.ALUOp(ALUOp),
.ALUControl(ALUControl)
);
assign PCSrc = (Branch & Zero) | Jump;
endmodule
module maindec ( //放指仿
input wire [6:0] op,
output wire [1:0] ResultSrc,
output wire MemWrite,
output wire Branch,
output wire ALUSrc,
output wire RegWrite,
output wire Jump,
output wire [2:0] ImmSrc, //修改为3bit
output wire [1:0] ALUOp
);
reg [11:0] controls; //修改control位数
assign {RegWrite, ImmSrc, ALUSrc, MemWrite, ResultSrc, Branch, ALUOp, Jump} = controls;
always @(*)
case (op)
7'b0000011: controls = 12'b100010010000;
7'b0100011: controls = 12'b000111000000;
7'b0110011: controls = 12'b1xxx00000100;
7'b1100011: controls = 12'b001000001010;
7'b0010011: controls = 12'b100010000100;
7'b1101111: controls = 12'b101100100001;
7'b0110111: controls = 12'b110010110000; //增加的lui指令
default: controls = 12'b000000000000;
endcase
endmodule
module aludec ( //放alu真值表
input wire opb5,
input wire [2:0] funct3,
input wire funct7b5,
input wire [1:0] ALUOp,
output reg [2:0] ALUControl
);
wire RtypeSub;
assign RtypeSub = funct7b5 & opb5;
always @(*)
case (ALUOp)
2'b00: ALUControl = 3'b000;
2'b01: ALUControl = 3'b001;
default:
case (funct3)
3'b000:
if (RtypeSub)
ALUControl = 3'b001;
else
ALUControl = 3'b000;
3'b010: ALUControl = 3'b101;
3'b100: ALUControl = 3'b100; //增加的xor指令
3'b110: ALUControl = 3'b011;
3'b111: ALUControl = 3'b010;
default: ALUControl = 3'b000;
endcase
endcase
endmodule
module datapath (
input wire clk,
input wire reset,
input wire [1:0] ResultSrc,
input wire PCSrc,
input wire ALUSrc,
input wire RegWrite,
input wire [2:0] ImmSrc, //修改3bit
input wire [2:0] ALUControl,
output wire Zero,
output wire [31:0] PC,
input wire [31:0] Instr,
output wire [31:0] ALUResult,
output wire [31:0] WriteData,
input wire [31:0] ReadData
);
wire [31:0] PCNext;
wire [31:0] PCPlus4;
wire [31:0] PCTarget;
wire [31:0] ImmExt;
wire [31:0] SrcA;
wire [31:0] SrcB;
wire [31:0] Result;
flopr #(.WIDTH(32)) pcreg(
.clk(clk),
.reset(reset),
.d(PCNext),
.q(PC)
);
adder pcadd4(
.a(PC),
.b(32'd4),
.y(PCPlus4)
);
adder pcaddbranch(
.a(PC),
.b(ImmExt),
.y(PCTarget)
);
mux2 #(.WIDTH(32)) pcmux(
.d0(PCPlus4),
.d1(PCTarget),
.s(PCSrc),
.y(PCNext)
);
regfile rf(
.clk(clk),
.we3(RegWrite),
.a1(Instr[19:15]),
.a2(Instr[24:20]),
.a3(Instr[11:7]),
.wd3(Result),
.rd1(SrcA),
.rd2(WriteData)
);
extend ext(
.instr(Instr[31:7]),
.immsrc(ImmSrc),
.immext(ImmExt)
);
mux2 #(.WIDTH(32)) srcbmux(
.d0(WriteData),
.d1(ImmExt),
.s(ALUSrc),
.y(SrcB)
);
alu alu(
.a(SrcA),
.b(SrcB),
.alucontrol(ALUControl),
.result(ALUResult),
.zero(Zero)
);
mux4 #(.WIDTH(32)) resultmux( //修改为mux4
.d0(ALUResult),
.d1(ReadData),
.d2(PCPlus4),
.d3(ImmExt), //新增通路
.s(ResultSrc),
.y(Result)
);
endmodule
module regfile (
input wire clk,
input wire we3,
input wire [4:0] a1,
input wire [4:0] a2,
input wire [4:0] a3,
input wire [31:0] wd3,
output wire [31:0] rd1,
output wire [31:0] rd2
);
reg [31:0] rf [31:0];
always @(posedge clk)
if (we3)
rf[a3] <= wd3;
assign rd1 = (a1 != 0 ? rf[a1] : 0);
assign rd2 = (a2 != 0 ? rf[a2] : 0);
endmodule
module adder (
input [31:0] a,
input [31:0] b,
output wire [31:0] y
);
assign y = a + b;
endmodule
module extend (
input wire [31:7] instr,
input wire [2:0] immsrc, //修改丿3bit
output reg [31:0] immext
);
always @(*)
case (immsrc)
3'b000: immext = {{20 {instr[31]}}, instr[31:20]};
3'b001: immext = {{20 {instr[31]}}, instr[31:25], instr[11:7]};
3'b010: immext = {{20 {instr[31]}}, instr[7], instr[30:25], instr[11:8], 1'b0};
3'b011: immext = {{12 {instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0};
3'b100: immext = {instr[31:12], 12'b000000000000}; //对lui指令的立即数进行扩展
default: immext = 32'bx;
endcase
endmodule
module flopr (
input wire clk,
input wire reset,
input wire [WIDTH - 1:0] d,
output reg [WIDTH - 1:0] q
);
parameter WIDTH = 8;
always @(posedge clk or posedge reset)
if (reset)
q <= 0;
else
q <= d;
endmodule
module mux2 (
input wire [WIDTH - 1:0] d0,
input wire [WIDTH - 1:0] d1,
input wire s,
output wire [WIDTH - 1:0] y
);
parameter WIDTH = 8;
assign y = (s ? d1 : d0);
endmodule
module mux4 (
input wire [WIDTH - 1:0] d0,
input wire [WIDTH - 1:0] d1,
input wire [WIDTH - 1:0] d2,
input wire [WIDTH - 1:0] d3, //新增通路,连接至extend
input wire [1:0] s,
output wire [WIDTH - 1:0] y
);
parameter WIDTH = 8;
assign y = (s[1] ? (s[0] ? d3 : d2): (s[0] ? d1 : d0)); //选择输出lui扩展后结枿
endmodule
module imem (
input wire [31:0] a,
output wire [31:0] rd
);
reg [31:0] RAM [63:0];
initial $readmemh("D:/Project/Vivado/VLSI/project_1/project_1.srcs/riscvtest1.txt", RAM);
assign rd = RAM[a[31:2]];
endmodule
module dmem (
input wire clk,
input wire we,
input wire [31:0] a,
input wire [31:0] wd,
output wire [31:0] rd
);
reg [31:0] RAM [63:0];
assign rd = RAM[a[31:2]];
always @(posedge clk)
if (we)
RAM[a[31:2]] <= wd;
endmodule
module alu (
input wire [31:0] a,
input wire [31:0] b,
input wire [2:0] alucontrol,
output reg [31:0] result,
output wire zero
);
wire [31:0] condinvb;
wire [31:0] sum;
wire v;
wire isAddSub;
assign condinvb = (alucontrol[0] ? ~b : b);
assign sum = (a + condinvb) + alucontrol[0];
assign isAddSub = (~alucontrol[2] & ~alucontrol[1]) | (~alucontrol[1] & alucontrol[0]);
always @(*)
case (alucontrol)
3'b000: result = sum;
3'b001: result = sum;
3'b010: result = a & b;
3'b011: result = a | b;
3'b100: result = a ^ b; //xor
3'b101: result = sum[31] ^ v;
3'b110: result = a << b[4:0];
3'b111: result = a >> b[4:0];
default: result = 32'bx;
endcase
assign zero = result == 32'b0;
assign v = (~((alucontrol[0] ^ a[31]) ^ b[31]) & (a[31] ^ sum[31])) & isAddSub;
endmodule
`timescale 1ns / 1ps
module testbench;
reg clk;
reg reset;
wire [31:0] WriteData;
wire [31:0] DataAdr;
wire MemWrite;
top dut(
.clk(clk),
.reset(reset),
.WriteData(WriteData),
.DataAdr(DataAdr),
.MemWrite(MemWrite)
);
initial begin
clk <= 1;
reset <= 1;
#22
reset <= 0;
end
always #5 clk = ~clk;
always @(negedge clk)
if (MemWrite)
if ((DataAdr === 100) & (WriteData === 25)) begin
$display("Simulation succeeded");
$stop;
end
/*测试lui和xor是否修改成功*/
else if ((DataAdr === 32'hff0000fb) & (WriteData === 32'hff0000f9)) begin
$display("Simulation succeeded");
$stop;
end
else if (DataAdr !== 96) begin
$display("Simulation failed");
$stop;
end
endmodule