实验二三(CPU部件实现之ALU、寄存器堆、PC、RAM)
系统硬件综合设计-多周期CPU的设计与实现
通过设计并实现支持 10 条指令的 CPU,进一步理解和掌握 CPU设计的基本原理和过程。
设计和实现一个支持如下十条指令的单周期CPU。
非访存指令
清除累加器指令CLA
累加器取反指令COM
算术右移一位指令SHR:将累加器ACC中的数右移一位,结果放回ACC
循环左移一位指令CSL:对累加器中的数据进行操作
停机指令STP
访存指令
加法指令ADD X:[X] + [ACC] –〉ACC,X为存储器地址,直接寻址
存数指令STA X,采用直接寻址方式
取数指令LDA X,采用直接寻址
转移类指令
无条件转移指令JMP imm:signExt(imm) -> PC
有条件转移(负则转)指令BAN X: ACC最高位为1则(PC)+ X -> PC,否则不变
单周期 CPU 是指所有指令均在一个时钟周期内完成的 CPU。CPU 由数据通路及其控制部件两部分构成,因而要完成一个支持若干条指令 CPU 的设计, 需要依次完成以下两件事:
PC 模块功能描述
输入 | 时钟信号 clk、重置信号 rst |
---|---|
输出 | 指令地址 pc(8 位) |
功能 | 每个时钟上升沿 PC 的值自动加 1,并输出 |
源码:
module PC(
input stop,
input clk,
input rst,
input pcJMP,
input banEBL,
input ban,
input wire [7:0] data_in,
output reg [7:0] PC
);
always @(posedge clk )begin
if(rst==1) begin PC = 0;end
if(stop!=1)begin
PC = PC +1;
if(banEBL == 1) begin
if(ban == 1) begin
PC = PC + data_in;
end
end
if(pcJMP == 1 ) begin PC = data_in;end
end
end
endmodule
指令存储器模块功能描述
输入 | 8位指令地址Addr |
---|---|
输出 | 16位指令Ins |
功能 | 存放待执行的指令(初始化),并根据地址输出指令 |
源码:
module ins(
output reg[15:0] outins,
input wire[7:0] adder,
output reg[5:0] r1,
output reg[7:0] r2,
input wire clk
);
reg [15:0] storage [0:255];
reg [15:0] temp;
initial begin
storage [8'h00] = 16'h0000; //start
storage [8'h01] = 16'h0100; //cla
storage [8'h02] = 16'h0200; //com
storage [8'h03] = 16'h0300; //shr
storage [8'h04] = 16'h0400; //csl
storage [8'h05] = 16'h0500; //add x
storage [8'h06] = 16'h0600; //sta x
storage [8'h07] = 16'h0701; //lda x
storage [8'h08] = 16'h0803; //jmp
storage [8'h09] = 16'h0902; //ban
storage [8'h0a] = 16'hffff; //stop
end
always @(adder)begin
temp = storage[adder];
r1 = {storage[adder][5:0]};
r2 = {storage[adder][7:0]};
outins = temp;
end
endmodule
寄存器堆模块功能描述
输入 | 时钟信号clk、读写控制线wr_en、读寄存器编号read_reg1和 read_reg2、写寄存器编号write_reg、写入数据write_data |
---|---|
输出 | 对应两个读寄存器编号的寄存器值reg1和reg2 |
功能 | 根据读寄存器编号给出对应寄存器的值;在写允许情况下,把写入端的数据在clk下降沿写到写寄存器编号对应的寄存器 |
源码:
module register(RA, RB, RW, busW, clk, WE, busA, busB, RD);
input wire [2:0] RA, RB, RW;
input wire [15:0] busW;
input clk, WE, RD;
output reg [15:0] busA, busB;
reg [15:0] Reg[7:0];
always @(negedge clk)
begin
if(WE == 1)
begin
Reg[RW] = busW;
busA = Reg[RA];
busB = Reg[RB];
end else if(RD == 1)begin
busA = Reg[RA];
busB = Reg[RB];
end
end
endmodule
ALU 模块功能描述
输入 | 操作数in1和in2、操作选择信号alu_op |
---|---|
输出 | ALU运算结果Z |
功能 | 根据操作选择信号计算in1和in2的运算结果Z |
源码:
module alu(outalu, a, b, select);
output [15:0] outalu;
input [15:0]a, b;
input [2:0]select;
reg [15:0] outalu;
always @(\*)
case(select)
3'b000: outalu = a + b;
3'b001: outalu = a - b;
3'b010: outalu = a&b;
3'b011: outalu = a\|b;
3'b100: outalu = a\<\<b;
3'b101: outalu = a\>\>b;
3'b110: outalu = a\*b;
3'b111: outalu = a%b;
default: outalu = 16'b1111111111111111;
endcase
endmodule
控制单元模块功能描述
输入 | 指令(操作码) |
---|---|
输出 | 寄存器堆的读写控制线wr_en、ALU的操作选择信号alu_op |
功能 | 根据当前指令功能对wr_en和alu_op赋值 |
源码:
module cu(
input wire[7:0] accout,
input wire [15:0] outins,
output reg stop,
output reg [1:0]accop,
output reg ena,
output reg [2:0] aluop,
output reg enable,
output reg pcJMP,banEBL,ban
);
always @\* begin
case(outins[15:8])
8'h00:
begin
stop = 0;
end
8'hff:
begin
stop = 1;
end
8'h01:
begin
ena = 1;
accop = 2'b00;
banEBL = 0;
pcJMP=0;
end
8'h02:
begin
ena = 1;
accop = 2'b01;
banEBL = 0;
pcJMP=0;
end
8'h03:
begin
ena = 1;
accop = 2'b10;
banEBL = 0;
pcJMP=0;
end
8'h04:
begin
ena = 1;
accop = 2'b11;
banEBL = 0;
pcJMP=0;
end
8'h05:
begin
ena = 1;
enable = 0;
aluop = 3'b000;
banEBL = 0;
pcJMP=0;
end
8'h06:
begin
ena = 1;
enable = 1;
banEBL = 0;
pcJMP=0;
end
8'h07:
begin
ena = 1;
enable = 0;
banEBL = 0;
pcJMP = 0;
end
8'h08:
begin
pcJMP = 1 ;
end
8'h09:
begin
banEBL = 1 ;
if(accout[7] == 1)
begin
ban = 1 ;
end
end
endcase
end
endmodule
通过将以上定义的模块进行连接、封装就得到了目标
CPU,该CPU的输入为系统时钟信号clk和重置信号 reset。
源码:
module cpu(
input clk,
input rst,
output wire [7:0] pc
);
wire [2:0] RA, RB, RW;
wire [15:0] busW;
wire WE, RD;
wire [15:0] busA, busB;
wire [15:0] accout;
wire [2:0] aluop;
wire stop, pcJMP, banEBL, ban, ena, enable;
wire [15:0] outins;
wire [1:0] accop;
wire [5:0] r1;
wire [7:0] r2;
wire [15:0] dataout, out1, out2;
alu malu(.outalu(out1),.a(accout),.b(out2),.select(aluop));
pc
mpc(.stop(stop),.clk(clk),.rst(rst),.pcJMP(pcJMP),.banEBL(banEBL),.ban(ban),.data_in(r2),.pc(pc));
ins mins(.outins(outins),.adder(pc),.r1(r1),.r2(r2),.clk(clk));
cu
mcu(.accout(accout),.outins(outins),.stop(stop),.accop(accop),.ena(ena),.aluop(aluop),.enable(enable),.pcJMP(pcJMP),.banEBL(banEBL),.ban(ban));
acc myacc(.ena(ena),.accop(accop),.accin(out1),.acc(accout));
register mregister(RA, RB, RW, busW, clk, WE, busA, busB, RD);
Datastorage
mDatastorage(.address(r1),.enable(enable),.clk(clk),.dataout(dataout),.datain(accout));
endmodule
为了仿真验证所实现的
CPU,需要定义测试文件并在测试文件中对指令存储器和寄存器堆中的相应寄存器的值进行初始化,并通过仿真波形图查看是否指令得到了正确执行。
源码:
module MyCPU_tb;
parameter CYCLE = 32;
reg clk;
wire [7:0] PC;
reg rst;
cpu MyCPU(clk, rst, PC);
initial clk = 0;
always \#(CYCLE/2) clk = \~ clk;
initial begin
clk = 1;
rst = 0;
(CYCLE\*1)
clk = 1;
rst = 1;
(CYCLE\*2)
rst = 0;
(CYCLE\*3)
rst = 0;
(CYCLE\*4)
rst = 0;
(CYCLE\*5)
rst = 1;
(CYCLE\*6)
rst = 0;
(CYCLE\*7)
rst = 0;
(CYCLE\*8)
rst = 0;
(CYCLE\*9)
rst = 1;
(CYCLE\*9)
rst = 0;
force MyCPU.r1 = 7'h5;
force MyCPU.r2 = 8'h9;
(CYCLE\*10)
force MyCPU.outins = 16'h0600;
force MyCPU.banEBL = 1;
(CYCLE\*12)
force MyCPU.accout[7] = 1;
force MyCPU.r2 = 16'h2;
(CYCLE\*13)
force MyCPU.outins = 16'h0902;
(CYCLE\*14)
force MyCPU.outins = 16'hffff;
(CYCLE\*20)
stop;
end
endmodule
执行指令前,如图5.1所示:
执行指令后,如图5.2所示:
执行指令前,如图5.3所示:
执行指令后,如图5.4所示:
执行指令前,如图5.5所示:
图5.5
执行指令后,如图5.6所示:
图5.6
执行指令前,如图5.7所示:
执行指令前后如图5.9所示
图5.9
执行指令前后,如图5.10所示:
执行指令前,如图5.11所示:
图5.11
执行指令后,如图5.12所示
图5.12
指令执行前后如图5.13所示:
图5.13
指令执行前后,如图5.14所示:
图5.14
指令执行前后如图5.15所示:
图5.15
清除累加器指令 CLA:执行清除累加器指令 CLA 前,程序计数寄存器ACC为不确定状态,ACC 处于待机状态;执行 CLA 后,0000 被送入ACC 中,CPU可以开始执行程序。如图 5.1 与图 5.2 所示。
累加器取反指令 COM:执行累加器取反指令 COM 前,ACC 的输出accout 为 0000H;执行后COM 后,accout 跳变为 FFFFH,ACC 的内容被成功取反输出。如图 5.3 与图 5.4 所示。
算术右移一位指令 SHR:执行算术右移一位指令 SHR 前,ACC 的输出accout 为FFFFH;执行 SHR 后,accout 跳变为 7FFFH,ACC 的内容被成功右移一位。如图 5.5 与图5.6所示。
循环左移一位指令 CSL:执行循环左移一位指令 CSL 前,ACC 的输出accout 为7FFFH;执行 CLS 后,accout 跳变为 FFFEH,ACC 的内容被成功循环左移一位。如图 5.7与图 5.8 所示。
停机指令STP:执行停机指令STP后,PC停止工作,outins赋值为FFFFH。如图 5.9所示。
加法指令 ADD X:执行加法指令 ADD X 前,程序计数器寄存器 ACC 的值为 9H,r1 为5H,r2 为 9H;执行 ADD X 后,ACC 的值为 13H,即(r2)+(ACC)->ACC,ACC+1->ACC。如图 5.10所示。
存数指令 STA X:执行存数指令 STA X 前,存储器 dataout 为不确定状态;执行 STA X后,因 ACC=06H,传送給 ALU 的指令为 0B,因此ACC 中的数据 FFFEH在下一个时钟下降沿传送給 dataout。如图 5.11与图 5.12 所示。
取数指令 LDA X:执行取数指令 LDA X 前,程序计数器寄存器 ACC的值为 06H;执行 LDAX 后,因 accop=3H,所以依然执行(ACC)+1->ACC,因此 ACC的值在下一个时钟下降沿变为 07H。如图5.13 所示。
无条件转移指令 JMP imm:执行无条件转移指令 JMP imm 前,程序计数器寄存器 ACC的值为 07H,pcJMP=1H,允许无条件跳转;执行JMP imm后outins=0803H,ins=03H,所以在下一个时钟上升沿,ACC 跳变到 03H。如图 5.14所示。
有条件转移(负则转)指令 BAN X:执行有条件转移(负则转)指令BAN X前,程序计数器寄存器 ACC 的值为04H,r2=02H,ban=1,允许有条件跳转,;执行有条件转移(负则转)指令 BAN X 后,(ACC)+(r2)->ACC,(ACC)+1->ACC,所以在下一个时钟上升沿,ACC 跳变为 07H。如图5.15所示。
实验二三(CPU部件实现之ALU、寄存器堆、PC、RAM)
既来之 则赞之
若有疑问,欢迎评论
本文仅供参考,务必独立思考
完整项目baidu网盘链接
链接:https://pan.baidu.com/s/1B9eXsySMq_MvHXM_PQtemw
提取码:ehu4