RISC-V:实现ADDI指令
0 实验要求
实验整体框架已给出,任务主要包括:
- 数据窗口的添加(可选,我添加了)
- 立即数生成错误修改(老师主动设置错误,修改见代码)
- 三端口寄存器模块的添加(这与此前的三端口略有不同,注意重点查看RegisterFile模块的实现)
1 源代码
`default_nettype none
// --------------------------------------------------------------------
// 单周期 RISC-V CPU 模块
// --------------------------------------------------------------------
module CPU#(parameter DATAWIDTH = 32,parameter ADDRWIDTH = 32)
(input wire iCPU_Reset,input wire iCPU_Clk,// 指令存储器接口output wire [ADDRWIDTH-1:0] oIM_Addr, //指令存储器地址input wire [DATAWIDTH-1:0] iIM_Data, //指令存储器数据// 数据存储器接口input wire [DATAWIDTH-1:0] iReadData, //数据存储器读数据output wire [DATAWIDTH-1:0] oWriteData, //数据存储器写数据output wire [ADDRWIDTH-1:0] oAB, //数据存储器地址output wire oWR, //数据存储器写使能// 连接调试器的信号output wire [ADDRWIDTH-1:0] oCurrent_PC,output wire oFetch,input wire iScanClk,input wire iScanIn,output wire oScanOut,input wire [1:0] iScanCtrl
);/** The input port is replaced with an internal signal **/wire clk = iCPU_Clk;wire reset = iCPU_Reset;// Instruction partslogic [31:0] pc, nextPC;logic [31:0] instruction; // instruction codeassign nextPC = pc + 4; /*-TODO 目前仅支持PC+4,增加分支指令时需修改 -*/// PCDataReg #(32) pcreg(.iD(nextPC), .oQ(pc), .Clk(clk), .Reset(reset), .Load(1'b1));assign oIM_Addr = pc; // 连接指令存储器的地址端口assign instruction = iIM_Data;// 连接指令存储器的数据端口// Instruction decodelogic [6:0] opcode;logic [2:0] funct3;logic [6:0] funct7;logic [4:0] ra1,ra2,wa;assign funct7 = instruction[31:25];assign ra2 = instruction[24:20];assign ra1 = instruction[19:15]; assign funct3 = instruction[14:12];assign wa = instruction[11:7];assign opcode = instruction[6:0];// Control unitlogic cRegWrite;logic [4:0] cImm_type; //{J,U,B,S,I}Controller controller(.iOpcode(opcode),.iFunct3(funct3),/*-TODO 随着指令的增加,相应添加端口信号 -*/.oRegWrite(cRegWrite),.oImm_type(cImm_type));// Immediate data generation logic [31:0] immData;ImmGen immGen(.iInstruction(instruction[31:7]), .iImm_type(cImm_type), .oImmediate(immData));// Register filelogic [31:0] regWriteData, regReadData1, regReadData2;RegisterFile #(32) regFile(.Clk(clk), .iWE(cRegWrite), .iWA(wa), .iWD(regWriteData), .iRA1(ra1), .oRD1(regReadData1),.iRA2(ra2), .oRD2(regReadData2));assign regWriteData = aluOut; /*-目前仅支持将ALU运算结果写入寄存器堆,TODO:增加Load类指令时需修改 -*/// ALUlogic [31:0] aluOut;assign aluOut = regReadData1 + immData; /*-目前仅支持加立即数运算,TODO:需用自己设计的ALU模块代替 -*//*-TODO 连接数据存储器 -*///---------------------- 送给调试器的变量 ------------------------////送给调试器的观察信号,需要与虚拟面板的信号框相对应struct packed{/*-TODO 在这里添加观察信号的类型 -*/logic RegWrite; //对应虚拟元件WS1logic [4:0] ImmType; //对应虚拟元件WS0}ws; always_comb begin/*-【注意】添加观察信号类型后须关联相应变量!-*/ws.RegWrite = cRegWrite; //对应虚拟元件WS1ws.ImmType = cImm_type; //对应虚拟元件WS0end //送给调试器的观察变量,需要与虚拟面板的数据框相对应struct packed{/*-TODO 在这里添加观察数据的类型 -*/ logic [11:0] imm12; logic [31:0] aluOut; //对应虚拟元件WD8logic [31:0] immData; //对应虚拟元件WD7logic [31:0] regReadData1; //对应虚拟元件WD6logic [4:0] ra2; //对应虚拟元件WD5,5位logic [4:0] ra1; //对应虚拟元件WD4,5位logic [4:0] wa; //对应虚拟元件WD3,5位logic [31:0] instruction; //对应虚拟元件WD2 logic [31:0] pc; //对应虚拟元件WD1logic [31:0] nextPC; //对应虚拟元件WD0}wd;always_comb begin/*-【注意】添加观察数据类型后须关联相应变量!-*/ wd.imm12 = instruction[31:20]; wd.aluOut = aluOut; //对应虚拟元件WD8wd.immData = immData; //对应虚拟元件WD7wd.regReadData1 = regReadData1; //对应虚拟元件WD6wd.ra2 = ra2; //对应虚拟元件WD5,5位wd.ra1 = ra1; //对应虚拟元件WD4,5位wd.wa = wa; //对应虚拟元件WD3,5位wd.instruction = instruction; //对应虚拟元件WD2wd.pc = pc; //对应虚拟元件WD1wd.nextPC = nextPC; //对应虚拟元件WD0 end// 调试器部分,请勿修改!WatchChain #(.DATAWIDTH($bits(ws)+$bits(wd))) WatchChain_inst(.DataIn({ws,wd}), .ScanIn(iScanIn), .ScanOut(oScanOut), .ShiftDR(iScanCtrl[1]), .CaptureDR(iScanCtrl[0]), .TCK(iScanClk));assign oCurrent_PC = pc;assign oFetch = 1'b1;endmodule// --------------------------------------------------------------------
// Controller模块
// --------------------------------------------------------------------
module Controller(input logic [6:0] iOpcode,input logic [2:0] iFunct3,/*- TODO:扩充指令时在这里增加端口 -*/output logic oRegWrite, output logic [4:0] oImm_type //对应五种类型:{J,U,B,S,I}
);always_comb begin/*- TODO:扩充指令时需修改 ...... -*/if (iOpcode==7'b0010011 && iFunct3==3'b000) beginoImm_type = 5'b00001;oRegWrite = 1'b1;endelse beginoImm_type = 5'b00000;oRegWrite = 1'b0; end
end
endmodule// --------------------------------------------------------------------
// 立即数生成模块
// --------------------------------------------------------------------
module ImmGen( //立即数生成input logic [4:0] iImm_type, //{J,U,B,S,I}input logic [31:7] iInstruction,output logic [31:0] oImmediate
);
/*- TODO:增加其他类型的立即数需修改。目前只有I型,所以并未区分Imm_type -*/
assign oImmediate = {{20{iInstruction[31]}}, iInstruction[31:20]};
/*- 符号扩展为32位立即数。【注意】上面的代码注入了一个错误,这里已修改
原始错误:assign oImmediate = {{20{iInstruction[31]}}, iInstruction[30:20]}; -*/endmodule// --------------------------------------------------------------------
// 三端口寄存器堆模块
// --------------------------------------------------------------------
module RegisterFile#(parameter DATAWIDTH = 32,parameter ADDRWIDTH = 5)
(input logic Clk,input logic iWE,input logic [4:0] iWA, iRA1, iRA2,input logic [31:0] iWD,output logic [31:0] oRD1, oRD2
);
/*- TODO:... -*/
localparam MEMDEPTH = 1<<ADDRWIDTH;
logic [DATAWIDTH-1:0] mem[0:MEMDEPTH-1];always_ff @(posedge Clk)
begin if(iWE)if(iWA!={ADDRWIDTH{1'b0}})mem[iWA] <= iWD;
endassign oRD1 = mem[iRA1];
assign oRD2 = mem[iRA2];
endmodule// --------------------------------------------------------------------
// DataReg模块
// --------------------------------------------------------------------
module DataReg
#(parameter N = 4)
( output reg [N-1:0] oQ,input wire [N-1:0] iD,input wire Clk,input wire Load,input wire Reset
);
always @(posedge Clk or posedge Reset)
beginif (Reset)oQ <= 0; else if (Load)oQ <= iD;
end
endmodule
2 添加数据窗口
代码中我加了数据观察窗口
所以验证前把这个数据窗口加了,不添加会影响后续指令类型判断
3 运行测试
将编译后的rbf文件上传至远程FPGA,接着输入测试指令
点击复位按钮,可看到当前第一条指令06400293(addi x5,x0,100)执行状态
此时,从RD1从RA1端口00即x0寄存器(默认为0)读出值00000000,立即数为instruction[31:20] 0000_0110_0100即064h,扩展为32位对应00000064,相加结果为00000000+00000064=00000064
然后,将运算结果00000064传到WD,并写入寄存器地址wa 00101即WA端口显示的x5寄存器
控制器模块(见下图)根据opcode和funct3判断指令类型(JUBSI)是I型指令,显示00001
接着,点击微单步,执行下一条指令FFF28313(addi x6,x5,-1),可以发现RD1是从RA1显示的x5寄存器读值00000064(上一条指令已写入),立即数为-1,补码显示FFFFFFFF,运算结果为00000063,并把结果写入WA显示的x6寄存器
具体各端口值得分析可以参照第一条指令分析过程,将指令写成32位进行分析
再次微单步执行下一条指令00030393(addi x7,x6,0),执行状态如下
具体各端口值得分析可以参照第一条指令分析过程,将指令写成32位进行分析
整个运行记录如下:
最后,后面的实验你该尝试尽量自己分析解决了
RISC-V:实现ADDI指令相关推荐
- 计组学习笔记2(RISC v版)
指令集解释 (规定:R[r]表示通用寄存器r的内容,M[addr]表示存储单元addr的内容,SEXT[imm]表示对imm进行符号扩展,ZEXT[imm]表示对imm进行零扩展) 整数运算类 -U型 ...
- RISC V (RV32+RV64) 架构 整体介绍
文章目录 riscv 市场 芯片介绍 软件介绍 开发板介绍 PC介绍 riscv 架构 编程模型(指令集/寄存器/ABI/SBI) 运行状态 指令集 寄存器 riscv32和riscv64两者的区别 ...
- 安装Ubuntu RISC V toolchain失败(网速、git配置原因)
git获取大容量工程出错:RPC failed: curl GnuTLS recv error : Decryption has failed. error: RPC failed; curl 56 ...
- MIPS指令集处理器设计(支持64条汇编指令)
一.题目背景和意义 二.国内外研究现状 (略) 三.MIPS指令集处理器设计与实现 (一).MIPS指令集功能性梳理 1.MIPS指令集架构 (1).mips基础指令集格式总结 MIPS是(Micro ...
- RISC-V 指令学习笔记(基于CH32V103)
文章目录 RISC-V 指令学习笔记(基于CH32V103) 一.指令结构分类 二.寄存器功能 三.加载存储指令 四.算数运算指令 五.移位指令 六.逻辑操作指令 七.跳转指令 7.1 条件跳转 7. ...
- verilog实现多周期处理器之——(六)简单算数操作指令的实现
实现的指令说明 这里解释有符号扩展与无符号扩展,有符号数扩展符号位.也就是1,无符号数扩展0.也就是在前面补满零或1 R-型指令 加减比较指令 add.addu.sub.sub.slt.sltu 这6 ...
- 从零开始的RISCV架构CPU设计(2)-CISC与RISC
系列文章目录 上一节:从零开始的RISCV架构CPU设计(1)-CPU开源资料说明 文章目录 系列文章目录 前言 一.什么是CISC 二.什么是RISC 三.CISC与RISC 3.1 指令集实现架构 ...
- 【计组复习(二)指令】
考点概述:1.指令设计原则:2.RISC.CISC:3.寻址方式(重点):4.子函数调用:5.链接. 存储程序概念:多种类型的指令和数据均以数字形式存储于存储器中. 硬件设计四条基本原则 1.简单源于 ...
- 体系结构实验(3)—— 指令流水的分析
文章目录 Chp3 Lab: Analysis of Instruction Execution Pipelining a. b. c. Chp3 Lab: Analysis of Instructi ...
最新文章
- Tensorflow快餐教程(8) - 深度学习简史
- 创建带有关联的 XML 架构的 XML 文件 从 XML 文件创建 XML 架构
- wiki维基百科上logo中字母的意思是什么?
- Solaris RAID 换盘/替换坏盘
- 深入sql server中的事务
- 运用贪心思想解决跳跃游戏
- python argparse模块详解_python中argparse模块用法实例详解
- dst发育筛查有意义吗_岱岳区妇幼保健院眼耳鼻喉科成功引进双目视力筛查仪
- oracle里的or 短路么,Oracle CASE短路不能分组工作
- 数据结构(C语言版)
- PHP字符串函数ucfirst( 将字符串的首字母转换为大写)
- 手机浏览器查看控制台
- linux远程连接命令
- 打工人息息相关的个税计算
- UE4 Sequence学习
- 分布式数据库同步系统之Otter
- DSRC通信协议标准
- java素数对算法_Java版本 质数(也叫素数)算法
- HCIE证书真的有用吗?
- 如何把计算机颜色调正常,怎样调电脑屏幕亮度和颜色,电脑屏幕颜色调回正常...