目录
本实验包含:
指令存储器和数据存储器的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&equal;
// 数据存储器
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.
发表评论