目录
本实验包含:
指令存储器和数据存储器的ip核调用,控制器,寄存器堆,ALU,单周期CPU的实现。
简易结构图:
各部件代码或实现:
控制器:
控制器有13条指令,需要可以再加,照着之前格式注释加就行了,对于同RAM相关的指令未测试
R: | |||||||
指令 | [31:26] | [25:21] | [20:16] | [15:11] | [10:6] | [5:0] | 功能 |
add | 000000 | rs | rt | rd | 000000 | 100000 | 寄存器加 |
sub | 000000 | rs | rt | rd | 000000 | 100010 | 寄存器减 |
and | 000000 | rs | rt | rd | 000000 | 100100 | 寄存器与 |
or | 000000 | rs | rt | rd | 000000 | 100101 | 寄存器或 |
nor | 000000 | rs | rt | rd | 000000 | 100111 | 寄存器或非 |
sll | 000000 | rs | 000000 | rd | sa | 000000 | 逻辑左移 |
srl | 000000 | rs | 000000 | rd | sa | 000010 | 逻辑右移 |
sra | 000000 | rs | 000000 | rd | sa | 100111 | 算术右移 |
I: | |||||||
指令 | [31:26] | [25:21] | [20:16] | [15:0] | 功能 | ||
addi | 001000 | rs | rt | immediate | 立即数加 | ||
lw | 100011 | rs | rt | immediate | 取字数据 | ||
sw | 101011 | rs | rt | immediate | 存字数据 | ||
beq | 000100 | rs | rt | immediate | 相等转移 | ||
J: | |||||||
指令 | [31:26] | [25:21] | [20:16] | [15;0] | 功能 | ||
j | 000010 | 00000 | 00000 | immediate | 转移 |
输入:op,func
输出:MemtoReg,MemWrite,Branch,ALUOP,ALUSrc,RegWrite,RegDst
-
//
-
//创建日期:2022/12/19 10:46:36
-
//设计名称:控制器
-
//课程名称:Controler
-
//说明:
-
//输入:op,func
-
//输出:MemtoReg,MemWrite,Branch,ALUOP,ALUSrc,RegWrite,RegDst
-
//依赖项:
-
//
-
//版次:
-
//版本0.01-文件已创建
-
//其他注释:
-
//
-
//
-
module
Controler(op,func,MemtoReg,MemWrite,Branch,ALUOP,ALUSrc,RegWrite,RegDst);
-
input [
5:
0] op;
-
input [
5:
0] func;
-
output MemtoReg;
-
output MemWrite;
-
output Branch;
-
output [
11:
0] ALUOP;
-
output ALUSrc;
-
output RegWrite;
-
output RegDst;
-
reg MemtoReg,MemWrite,Branch,ALUSrc,RegWrite,RegDst;
-
reg [
11:
0] ALUOP;
-
// R:
-
// 指令 [31:26] [25:21] [20:16] [15:11] [10:6] [5:0] 功能
-
// add 000000 rs rt rd 000000 100000 寄存器加
-
// sub 000000 rs rt rd 000000 100010 寄存器减
-
// and 000000 rs rt rd 000000 100100 寄存器与
-
// or 000000 rs rt rd 000000 100101 寄存器或
-
// nor 000000 rs rt rd 000000 100111 寄存器或非
-
// sll 000000 rs 000000 rd sa 000000 逻辑左移
-
// srl 000000 rs 000000 rd sa 000010 逻辑右移
-
// sra 000000 rs 000000 rd sa 000011 算术右移
-
//I:
-
// 指令 [31:26] [25:21] [20:16] [15:0] 功能
-
// addi 001000 rs rt immediate 立即数加
-
// lw 100011 rs rt immediate 取字数据
-
// sw 101011 rs rt immediate 存字数据
-
// beq 000100 rs rt immediate 相等转移
-
//J:
-
// 指令 [31:26] [25:21] [20:16] [15:0] 功能
-
// j 000010 00000 00000 immediate 转移
-
-
always @(*)
-
begin
-
case(op)
-
6
'b000000:
//寄存器操作
-
begin
-
MemtoReg=
0;
//输出ALU的输出
-
MemWrite=
0;
//数据存储器不写入
-
Branch=
0;
//正常PC
-
ALUSrc=
0;
//ALU输入2选择寄存器输出
-
RegWrite=
1;
//寄存器写入
-
RegDst=
1;
//有rd
-
case(func)
//控制ALU操作
-
6
'b100000:
// 寄存器加
-
ALUOP=
12
'b010000000000;
-
6
'b100010:
// 寄存器减
-
ALUOP=
12
'b100000000000;
-
6
'b100100:
// 寄存器与
-
ALUOP=
12
'b000010000000;
-
6
'b100101:
// 寄存器或
-
ALUOP=
12
'b000000100000;
-
6
'b100111:
// 寄存器或非
-
ALUOP=
12
'b000001000000;
-
6
'b100100:
// 逻辑左移
-
ALUOP=
12
'b000000001000;
-
6
'b100101:
// 逻辑右移
-
ALUOP=
12
'b000000000100;
-
6
'b100111:
// 算术右移
-
ALUOP=
12
'b000000000010;
-
default:ALUOP=
12
'b010000000000;
-
endcase
-
end
-
6
'b001000:
// 立即数加
-
begin
-
MemtoReg=
0;
//输出ALU结果
-
MemWrite=
0;
//数据存储器不写入
-
Branch=
0;
//正常PC
-
ALUOP=
12
'b010000000000;
//ALU加操作
-
ALUSrc=
1;
//数据2选择立即数输出
-
RegWrite=
1;
//寄存器写入
-
RegDst=
0;
//无rd选择rt
-
end
-
6
'b100011:
// 取字数据
-
begin
-
MemtoReg=
1;
//输出数据存储器结果
-
MemWrite=
0;
//数据存储器不写入
-
Branch=
0;
//正常PC
-
ALUOP=
12
'b000000000000;
//ALU无操作,输出第一个输入
-
ALUSrc=
1;
//数据2随意
-
RegWrite=
1;
//寄存器写入
-
RegDst=
0;
//无rd选择rt
-
end
-
6
'b101011:
// 存字数据
-
begin
-
MemtoReg=
1;
//输出随意
-
MemWrite=
1;
//数据存储器写入
-
Branch=
0;
//正常PC
-
ALUOP=
12
'b000000000000;
//ALU无操作,输出第一个输入
-
ALUSrc=
1;
//数据2随意
-
RegWrite=
0;
//寄存器不写入
-
RegDst=
0;
//不写入随意
-
end
-
6
'b000100:
// 相等转移
-
begin
-
MemtoReg=
1;
//输出随意
-
MemWrite=
0;
//数据存储器不写入
-
Branch=
1;
//PC可能改变
-
ALUOP=
12
'b000000000000;
//ALU无操作,输出第一个输入
-
ALUSrc=
0;
//ALU输入2选择寄存器输出
-
RegWrite=
0;
//寄存器不写入
-
RegDst=
0;
//不写入随意
-
end
-
6
'b000010:
//跳转
-
begin
-
MemtoReg=
1;
//输出随意
-
MemWrite=
0;
//数据存储器不写入
-
Branch=
1;
//PC可能改变
-
ALUOP=
12
'b000000000000;
//ALU无操作,输出第一个输入
-
ALUSrc=
0;
//数据2选择寄存器输出
-
RegWrite=
0;
//寄存器不写入
-
RegDst=
0;
//不写入随意
-
end
-
default:
-
begin
-
MemtoReg=
0;
-
MemWrite=
0;
-
Branch=
0;
-
ALUOP =
12
'b000000000000;
//ALU无操作,输出第一个输入
-
ALUSrc=
0;
-
RegWrite=
1;
-
RegDst=
1;
-
end
-
endcase
-
end
-
endmodule
寄存器堆:
采用之前的寄存器堆(短版)代码,没有初始化,不影响使用,需要的话加上就行
-
//
-
//
-
//创建日期:2022/10/16 21:37:00
-
//设计名称:寄存器堆
-
//课程名称:regfile
-
//说明:
-
// 实现 32 个寄存器, 其中 0 号寄存器读出的值恒为 0,
-
// 寄存器堆为异步读同步写,
-
// 共有 1 个写端口和 2 个读端口
-
//依赖项:
-
//
-
//版次:
-
//版本0.01-文件已创建
-
//其他注释:
-
//
-
-
module regfile(
-
input clk,
// 时钟
-
input wen,
// 写使能
-
input [
4 :
0] raddr1,
// 读地址1
-
input [
4 :
0] raddr2,
// 读地址2
-
input [
4 :
0] waddr,
// 写地址
-
input [
31:
0] wdata,
// 写数据
-
output reg [
31:
0] rdata1,
// 读到的数据1
-
output reg [
31:
0] rdata2,
// 读到的数据2
-
input [
4 :
0] test_addr,
// 测试读端口
-
output reg [
31:
0] test_data
// 测试输出
-
);
-
reg [
31:
0] rf[
31:
0];
// 定义32个32位的寄存器
-
always @(posedge clk)
// 时钟上升沿
-
begin
-
if (wen)
// 如果写使能wen为1则写入寄存器
-
begin
-
rf[waddr] <= wdata;
-
end
-
end
-
-
//读端口 1
-
always @
(*)
-
begin
-
if (raddr1==5'd0)
-
rdata1 <= 32'd0;
-
else
-
rdata1 <= rf[raddr1];
-
end
-
//读端口 2
-
always @(*)
-
begin
-
if (raddr2==
5
'd0)
-
rdata2 <= 32'd0;
-
else
-
rdata2 <= rf[raddr2];
-
end
-
//测试读端口
-
always @
(*)
-
begin
-
if (test_addr==5'd0)
-
test_data <= 32'd0;
-
else
-
test_data <= rf[test_addr];
-
end
-
endmodule
ALU:
对照之前的ALU增加了比较相等的输出,用于PC的跳转,采用独热编码,相当于13种简易运算。
-
//
-
//创建日期:2022/11/6 20:06:00
-
//设计名称:ALU算术逻辑单元
-
//课程名称:alu
-
//说明:
-
//输入: [11:0] alu_control; // ALU控制信号
-
// [31:0] alu_src1; // ALU操作数1
-
// [31:0] alu_src2; // ALU操作数2
-
//输出: [31:0] alu_result; // ALU结果
-
// Equal 两个输入是否相等
-
//依赖项:
-
//
-
//版次:
-
//版本0.01-文件已创建
-
//其他注释:
-
//
-
//
-
module
alu(alu_control,alu_src1,alu_src2,alu_result,Equal);
-
input [
11:
0] alu_control;
// ALU控制信号
-
input [
31:
0] alu_src1;
// ALU操作数1
-
input [
31:
0] alu_src2;
// ALU操作数2
-
output [
31:
0] alu_result;
// ALU结果
-
output Equal;
//相等
-
wire Equal;
-
reg [
31:
0] alu_result;
-
// 控制信号为独热编码
-
assign Equal = alu_src1==alu_src2;
-
always @(*)
-
begin
-
case(alu_control)
// 下面的1,2指操作数1,操作数2
-
12
'b000000000001:alu_result<=alu_src1<<
16;
// 高位加载 1
-
12
'b000000000010:alu_result<=alu_src1>>>alu_src2;
// 算术右移 2
-
12
'b000000000100:alu_result<=alu_src1>>alu_src2;
// 逻辑右移 4
-
12
'b000000001000:alu_result<=alu_src1<<alu_src2;
// 逻辑左移 8
-
12
'b000000010000:alu_result<=alu_src1^alu_src2;
// 按位异或 16
-
12
'b000000100000:alu_result<=alu_src1|alu_src2;
// 按位或 32
-
12
'b000001000000:alu_result<=~(alu_src1|alu_src2);
// 按位或非 64
-
12
'b000010000000:alu_result<=alu_src1&alu_src2;
// 按位与 128
-
12
'b000100000000:alu_result<=alu_src1<alu_src2?
32
'd1:
32
'd0;
// 无符号比较,小于置位 256
-
12
'b001000000000:alu_result<=$
signed(alu_src1)<$
signed(alu_src2)?
32
'd1:
32
'd0;
// 有符号比较,小于置位 512
-
12
'b010000000000:alu_result<=alu_src1+alu_src2;
// 1加 1024
-
12
'b100000000000:alu_result<=alu_src1-alu_src2;
// 1减 2048
-
default: alu_result<=alu_src1;
-
endcase
-
end
-
endmodule
数据存储器:
采用IP核实现:
没有测试,功能或许有问题
指令存储器:
采用IP核实现:
第四张图的ROM.coe数据如下:
-
memory_initialization_radix=2;
-
memory_initialization_vector=
-
00100000000000010000000000001000
-
00100000000000100000000000000010
-
00100000000000110000000000000000
-
00000000010000110001100000100000
-
00010000001000110000000000000111
-
00001000000000000000000000000011
这是一段测试用的指令段,具体功能在tp文件种有注释
这个文件什么名字和位置都可以,后缀是.coe就行。
CPU:
-
//
-
//创建日期:2022/12/19 16:32:56
-
//设计名称:CPU
-
//课程名称:CPU
-
//说明:
-
//调用各个部件,进行运算
-
//依赖项:
-
// 控制器,寄存器,ALU
-
//版次:
-
//版本0.01-文件已创建
-
//其他注释:
-
-
module CPU(clk);
-
input clk;
-
// PC
-
reg [
7:
0] PC=
8'd0;
//PC从第0条指令开始
-
wire[
31:
0] SignImm;
//指令后16位扩展结果
-
wire PCSrc;
//是否跳转
-
always@(posedge clk)
//上升沿
-
begin
-
if
(PCSrc == 0)
-
PC = PC+
1;
-
else
-
PC = SignImm[
7:
0];
-
end
-
// 指令存储器
-
wire [
31:
0] instructions;
//指令存储器输出
-
ROM_D IROM(
-
.a(PC),//地址
-
.spo(instructions));
//指令输出
-
wire[
5:
0] op,func;
//控制器输入
-
wire[
4:
0] rs,rt,rd;
//三个寄存器地址
-
assign op = instructions[
31:
26];
-
assign func = instructions[
5:
0];
-
assign rs = instructions[
25:
21];
-
assign rt = instructions[
20:
16];
-
assign rd = instructions[
15:
11];
-
assign SignImm = {{(
16){instructions[
15]}},instructions[
15:
0]};
-
// 控制器
-
wire MemtoReg,MemWrite,Branch,ALUSrc,RegWrite,RegDst;
//控制器输出控制信号
-
wire[
11:
0] ALUOP;
//ALU所做的操作
-
Controler Contr(op,func,MemtoReg,MemWrite,Branch,ALUOP,ALUSrc,RegWrite,RegDst);
-
// 寄存器堆
-
wire[
31:
0] R1,R2,WriteBackData;
//寄存器输出和数据输入
-
wire[
4:
0] reg_w;
//寄存器写地址
-
assign reg_w = RegDst?rd:rt;
-
regfile regfile_(clk,RegWrite,rs,rt,reg_w,WriteBackData,R1,R2);
-
// ALU
-
wire[
31:
0] srcB,ALUResult;
//ALU第二个数据输入和数据输出
-
wire Equal;
//输入是否相等
-
assign srcB = ALUSrc?SignImm:R2;
-
alu ALU(ALUOP,R1,srcB,ALUResult,Equal);
-
assign PCSrc = Branch⩵
-
// 数据存储器
-
wire [
31:
0] ReadData;
//数据存储器输出
-
data_RAM DRM(
-
.clka (clk ),
-
.wea (MemWrite ),
-
.addra (ALUResult[7:0]),
-
.dina (R2 ),
-
.douta (ReadData ));
-
assign WriteBackData = MemWrite?ReadData:ALUResult;
-
endmodule
tp(仿真文件):
就一个clk和CPU的调用,所用指令段的注释。
-
`timescale
1ns /
1ps
-
-
//001000 00000 00001 0000000000001000 第0个寄存器和8相加存入第1个寄存器
-
//001000 00000 00010 0000000000000010 第0个寄存器和2相加存入第2个寄存器
-
//001000 00000 00011 0000000000000000 第0个寄存器和0相加存入第3个寄存器
-
//000000 00010 00011 00011 00000 100000 第3个寄存器和第2个寄存器相加,结果存入第3个寄存器
-
//000100 00001 00011 0000000000000111 第1个寄存器和第3个相等转移到7
-
//000010 00000 00000 0000000000000011 转移到3
-
//相当于以下程序:
-
// reg[1] = 8
-
// reg[2] = 2
-
// reg[3] = 0
-
//M: reg[3] = reg[3]+reg[2]
-
// if reg[1] == reg[3]: goto N
-
// goto M
-
//N:
-
module tp;
-
reg clk=
0;
-
CPU cpu_(clk);
-
always
#10 clk = ~clk;
-
endmodule
仿真结果:
单周期CPU压缩包下载
开了动态调分,初始积分是0.
转载:https://blog.csdn.net/weixin_58196051/article/details/128380444
查看评论