赞
踩
目录
指令存储器和数据存储器的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增加了比较相等的输出,用于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就行。
- //
- //创建日期: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
就一个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
开了动态调分,初始积分是0.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。