对单周期 RISC-V 处理器进行扩展

目录

(一)问题重述

(二)指令介绍

         (三)处理思路

(四)设计过程

1. 评估本次设计的任务量

2. 修改单周期处理器

3. 修改控制单元及ALU

4. 修改Main Decoder,ALU Decoder和ImmSrc真值表

5. 修改tb_top.v测试lui和xor

6. 运行所给测试程序

         (五)代码

(一)问题重述

对授课内容的单周期 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单周期处理器的内容,然后分析了一下增加luixor两条指令需要修改的控制单元以及verilog程序,第二天进行程序的调试发现总是报错,就先暂停了。在12月底又耗时两天完成了本次设计,第一天发现是modelsim问题导致出错,改用vivado软件后程序正常运行,然后进行程序设计的验证,第二天书写了本次报告。

2. 修改单周期处理器

图1-3 单周期处理器修改图

增加一条从ExtendResult选择器(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

  1. 修改代码top.v
  2. Immsrc改为3位,针对lui立即数扩展,增加case (immsrc)==100的情况;
  3. 修改maindec中的case(op),实现lui
  4. mux改为4输入,增加alucontrol==100的情况;
  5. 修改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
			

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值