首页 > 其他分享 >单周期riscv处理器的实现

单周期riscv处理器的实现

时间:2022-11-19 00:33:06浏览次数:62  
标签:周期 instr riscv 31 imme 指令 处理器 input output

目录

单周期riscv处理器的实现

代码放到了:尚未完成
小组成员:

指令分析

最初想要实现完整的riscv32i指令集,但由于试验任务的时间要求以及我个人能力的限制,最终只是选择了并不完整的riscv指令集进行实现。但基本搭建了完整的框架,倘若之后有时间,会尝试实现完整的riscv32i指令集。

实现指令

指令 指令说明 指令类型 opcode func3
jal 无条件跳转 J型指令 1101111
beq 有条件跳转 B型指令 1100011
lw 加载字 I型指令 0000011
sw 存字 S型指令 0100011
add R型指令 0110011 000
sub R型指令 0110011 010
sll 逻辑左移 R型指令 0110011 001
srl 逻辑右移 R型指令 0110011 011
and R型指令 0110011 110
or R型指令 0110011 110
xor 异或 R型指令 0110011 100
addi I型指令 0010011 000
subi I型指令 0010011 010
slli 逻辑左移 I型指令 0010011 001
srli 逻辑右移 I型指令 0010011 011
andi I型指令 0010011 110
ori I型指令 0010011 110
xori 异或 I型指令 0010011 100

出于方便译码的考虑,我们对sub指令以及subi指令实现的func3数据段进行了细微的调整,与原版riscv32i有出入,利用汇编转机器码时可能需要手动修正。

处理器总体思路

我实现的指令集是残缺的,为了能够之后可能进行的完整实现以及方便与课堂内容结合,我决定尽量完全按照黑皮书《计算机组成与设计 riscv版》进行实现
下图为完整实现

分块拆解

直接实现未免过于困难,于是尝试先把每一个部分进行实现,最后整合成完整的数据通路。
下面列一下要实现的所有小模块。

模块 说明
InstrMem 指令存储器
DataMem 数据存储器
rigisters 寄存器堆
PC PC寄存器
PC_mux PC多选器
Add_imm 指令地址跳转计算器
Add_4 指令地址非跳转计算器
Control 主控制器
ALU_mux ALU来源多选器
ALU ALU运算器
ALUControl ALU运算控制
Branch_judge 判断指令是否跳转
ImmGen 立即数生成器
rigister_write_mux 寄存器写入数据多选器

处理器完整实现

各分模块实现

接下来我们一步步实现每一个模块

指令存储器

类型 信号 注释
input [7:0]addr 指令地址(总共可存\({2^8}\)个指令)
output [31:0]instr 地址对应的指令

指令存储器相对比较容易实现,只要根据输入的地址取出相对应的指令即可。

代码实现

module InstrMem(
	input [7:0]addr,
	output [31:0]instr
    );	
	reg[31:0] rom[255:0];	
    //rom进行初始化
    initial begin
        rom[0] = 32'b00000000000100000000000010010011;
        rom[1] = 32'b00000000000100001000000100110011;
        rom[2] = 32'b00000000001000010000000110110011;
        rom[3] = 32'b01000000000100011000000110110011;    
    end
	
    assign instr = rom[addr];

endmodule

input clk,
input rst_n,

input MemWrite,
input MemRead,

input [7:0]Address,

input [31:0] WriteData,
output [31:0] ReadData

数据存储器

类型 信号 注释
input clk 时钟信号
input rst_n 复位信号
input MemWrite 写使能信号
input MemRead 读使能信号
input [7:0]Address 数据存储器地址
input [31:0] WriteData 写入数据
output [31:0] ReadData 读出数据

根据控制器处理得到的的读写使能信号,决定写入还是读出数据。
写入数据来自寄存器堆读出的第二个寄存器数据。
数据存储器地址来自主ALU运算。

代码实现:

module DataMem(
	input clk,
	input rst_n,	
	input MemWrite,
	input MemRead,
	input [7:0]Address,
	input [31:0] WriteData,
	output [31:0] ReadData
    );
	
	
	reg [31:0]ram[255:0];
	assign ReadData = (Address==32'd0) ? 32'b0 : ram[Address];

	always@(posedge clk)
	begin
		if(!rst_n)// for循环不知道为什么会报错,仿真暂且这样初始化
			begin //对每一个存储器都置零
				ram[0]<=`zero_word;
				ram[1]<=`zero_word;
				ram[2]<=`zero_word;
				ram[3]<=`zero_word;
				ram[4]<=`zero_word;
				ram[5]<=`zero_word;
				ram[6]<=`zero_word;
			        ······//略去
			end
		else if(MemWrite & (Address!=32'b0))
			ram[Address]<=WriteData;	
	end

endmodule

控制模块

这里几乎是整个处理器的核心模块,既然是实验结束后复盘,可以先从这里写起,方便之后模块输入输出的描述的
input [6:0] opcode,
output reg ALUSrc,
output reg[1:0] Branch,
output reg MemRead,
output reg MemtoReg, // 1 时写入dataMem中的, 0 时写ALU里的
output reg MemWrite,
output reg RegWrite,
output reg ALUop // 1时结合func3进行判断,0时直接加

类型 信号 注释
input [6:0]opcode
output ALUSrc 决定ALU的第二个操作数来源
output [1:0] Branch 分辨beq, jal, 与其他指令。后面被输入到Branch_judge模块判断指令是否跳转
output MemWrite 写使能信号
output MemRead 读使能信号
output [7:0]Address 数据存储器地址
output [31:0] WriteData 写入数据
output [31:0] ReadData 读出数据

代码实现:

module Control(
    input [6:0] opcode,
    output reg ALUSrc, // 0时来自寄存器,1时来自立即数
    output reg[1:0] Branch,
    output reg MemRead,
    output reg MemtoReg, // 1 时写入dataMem中的, 0 时写ALU里的
    output reg MemWrite,
    output reg RegWrite,
    output reg ALUop // 1时结合func3进行判断,0时直接加
);

always@(*) begin
    case(opcode) 
        7'b0110011: begin // R型指令
            Branch = 2'b00;
            ALUSrc = 0;
            MemRead = 0;
            MemtoReg = 0;
            MemWrite = 0;
            RegWrite = 1;
            ALUop = 1;
       end
        7'b0010011: begin // I型指令_立即数
            Branch = 2'b00;
            ALUSrc = 1;
            MemRead = 0;
            MemtoReg = 0;
            MemWrite = 0;
            RegWrite = 1;
            ALUop = 1;
       end
        7'b0000011: begin// I型指令_load
            Branch = 2'b00;
            ALUSrc = 0;
            MemRead = 1;
            MemtoReg = 1;
            MemWrite = 0;
            RegWrite = 1;
            ALUop = 0;
        end
        7'b0100011: begin// S型指令
            Branch = 2'b00;
            ALUSrc = 0;
            MemRead = 0;
            MemtoReg = 0;
            MemWrite = 1;
            RegWrite = 0;
            ALUop = 0;
        end
        7'b1100011: begin// B型指令
            Branch = 2'b10;
            ALUSrc = 1;
            MemRead = 0;
            MemtoReg = 0;
            MemWrite = 0;
            RegWrite = 0;
            ALUop = 0;
        end
        7'b1101111: begin// J型指令
            Branch = 2'b01;
            ALUSrc = 1;
            MemRead = 0;
            MemtoReg = 0;
            MemWrite = 0;
            RegWrite = 1;
            ALUop = 0;
        end
    endcase
end                
endmodule

立即数生成模块

类型 信号 注释
input [31:0]instr 指令
output [31:0]imme 立即数

输入指令输出符号扩展之后的立即数,这个模块事实上是第一个我实现的模块,这时候我还怀着一颗勇敢的心,把所有指令的立即数都进行了生成,然而毫无疑问后来失败跑路了,但这个模块见证了我曾经的雄心壮志(笑

define lui 7'b0110111 define auipc 7'b0010111
define jal 7'b1101111 define jalr 7'b1100111
define B_type 7'b1100011 define load 7'b0000011
define store 7'b0100011 define I_type 7'b0010011
`define R_type 7'b0110011

module ImmGen(
input [31:0]instr,
output [31:0]imme
);

wire I;
wire U;
wire J;
wire B;
wire S;

wire [31:0]I_imme;
wire [31:0]U_imme;
wire [31:0]J_imme;
wire [31:0]B_imme;
wire [31:0]S_imme;

assign I=(instr[6:0]==`jalr) | (instr[6:0]==`load) | (instr[6:0]==`I_type);
assign U=(instr[6:0]==`lui) | (instr[6:0]==`auipc);
assign J=(instr[6:0]==`jal);
assign B=(instr[6:0]==`B_type);
assign S=(instr[6:0]==`store);

//立即数符号扩展
assign I_imme = {{20{instr[31]}},instr[31:20]}; 
assign U_imme = {instr[31:12],{12{1'b0}}};
assign J_imme = {{12{instr[31]}},instr[19:12],instr[20],instr[30:21],1'b0};   
assign B_imme = {{20{instr[31]}},instr[7],instr[30:25],instr[11:8],1'b0};
assign S_imme = {{20{instr[31]}},instr[31:25],instr[11:7]}; 

assign imme = I ? I_imme : U ? U_imme : J ? J_imme : B ? B_imme : S ? S_imme : 32'd0;

endmodule

标签:周期,instr,riscv,31,imme,指令,处理器,input,output
From: https://www.cnblogs.com/ccuu/p/16905175.html

相关文章

  • Spring Bean 的生命周期(详细解读)
    SpringBean的生命周期简单易懂。在一个bean实例被初始化时,需要执行一系列的初始化操作以达到可用的状态。同样的,当一个bean不再被调用时需要进行相关的析构操作,并从......
  • React生命周期深度完全解读
    在React中,对于每一次由状态改变导致页面视图的改变,都会经历两个阶段:render阶段、commit阶段。只有class组件才有生命周期,因为class组件会创建对应的实例,而函数组......
  • React组件生命周期
     组件的生命周期  挂载:--------------- ......
  • 超标量处理器设计 电子书 pdf
    关注公众号:红宸笑。回复:电子书即可  ......
  • 大规模并行处理器编程实战 第三版 电子书 pdf
    英文《ProgrammingMassivelyParallelProcessors:AHands-onApproach》第三版,中文版第三版好像没出过。 关注公众号:红宸笑。回复:电子书即可   ......
  • IOC容器的加载过程-Bean的生命周期
    核心模块部分截图:   IOC源码加载过程:1.newAnnotationConfigApplicationContext():         再看:AnnotationConfigApplicationContext()的无......
  • 4. servlet类的继承关系与生命周期
    #继承关系:##自定义类->HttpServlet->GenericServlet->Servlet(接口)。#Servlet接口核心方法:init()、service()、destroy()。##service()方法:由HttpServlet类实现,查看源......
  • 数据集成平台关于【源平台调度&任务生命周期】
    任务调度者调度事件生产任务调度任务池-异步
AsynDispatcher--source实例化适配器执行消费任务实例化集成应用DataHubInstance
handleSourceDispatch()依赖注入集成方......
  • 手把手教你设计CPU:RISC-V处理器 电子书 pdf
    作者:胡振波出版社:人民邮电出版社链接:手把手教你设计CPU:RISC-V处理器  本书是一本介绍通用CPU设计的入门书,以通俗的语言系统介绍了CPU和RISC-V架构,力求为读者揭......
  • 超标量处理器设计 电子书 pdf
    作者:姚永斌出版社:清华大学出版社副标题:SuperscalarRiscProcessorDesign 链接:超标量处理器设计  《超标量处理器设计》讲述超标量(SuperScalar)处理器的设......