目录
本实验包含:
简易结构图:
各部件代码或实现:
控制器:
寄存器堆:
ALU:
数据存储器:
指令存储器:
CPU:
tp(仿真文件):
仿真结果:
单周期CPU压缩包下载
本实验包含:
指令存储器和数据存储器的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]功能 // add000000 rs rt rd000000100000寄存器加 // sub000000 rs rt rd000000100010寄存器减 // and000000 rs rt rd000000100100寄存器与 // or000000 rs rt rd000000100101寄存器或 // nor000000 rs rt rd000000100111寄存器或非 // sll000000 rs 000000 rd sa000000逻辑左移 // srl000000 rs 000000 rd sa000010逻辑右移 // sra000000 rs 000000 rd sa000011算术右移 //I: // 指令[31:26][25:21][20:16][15:0]功能 // addi001000 rsrt immediate立即数加 // lw100011 rsrt immediate取字数据 // sw101011 rsrt immediate存字数据 // beq000100 rsrt immediate相等转移 //J: // 指令[31:26] [25:21] [20:16] [15:0] 功能 // j 0000100000000000 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 endendmodule
寄存器堆:
采用之前的寄存器堆(短版)代码,没有初始化,不影响使用,需要的话加上就行
//////创建日期:2022/10/16 21:37:00//设计名称:寄存器堆//课程名称:regfile//说明:// 实现 32 个寄存器, 其中 0 号寄存器读出的值恒为 0,// 寄存器堆为异步读同步写, // 共有 1 个写端口和 2 个读端口//依赖项:// //版次://版本0.01-文件已创建//其他注释:// module regfile(input clk, // 时钟input wen, // 写使能input [4 :0] raddr1, // 读地址1input [4 :0] raddr2, // 读地址2input [4 :0] waddr, // 写地址input [31:0] wdata, // 写数据output reg [31:0] rdata1, // 读到的数据1output reg [31:0] rdata2, // 读到的数据2input [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; endend //读端口 1always @(*)begin if (raddr1==5'd0) rdata1 <= 32'd0; else rdata1 <= rf[raddr1];end//读端口 2always @(*)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];endendmodule
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 endendmodule
数据存储器:
采用IP核实现:
没有测试,功能或许有问题
指令存储器:
采用IP核实现:
第四张图的ROM.coe数据如下:
memory_initialization_radix=2;memory_initialization_vector=001000000000000100000000000010000010000000000010000000000000001000100000000000110000000000000000000000000100001100011000001000000001000000100011000000000000011100001000000000000000000000000011
这是一段测试用的指令段,具体功能在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.