开发环境:vivado2018.3版本和modelsim10.6C版本
题目要求
基本要求
根据图1的8位模型计算机框图的工作原理,实现10个以上功能模块设计、仿真和调试,以及系统设计、仿真和调试。
- 基本8位模型计算机需设计4条指令:数据传送、加法、减法、暂停。
- 总线结构是单总线,数据总线位数8位、地址总线最少是3位。
- 存储器容量最少是7x8位。
- 操作码、操作数自行设计。
扩展要求
根据掌握的数字系统设计知识和能力,在基本要求的基础上自行扩展系统功能。也可以选择如下一个或一个以上的扩展功能。
- 改变系统结构,例如,取消图1中的内部数据总线。
- 在8位模型计算机结构基础上增加指令,例如:逻辑运算、乘法等。
- 将单总线结构改为双总线。
- 将数据总线位数从8位增加到16位。
- 存储器用RAM或双端口存储器。
- 将累加器改为寄存器组。
CPU的设计
指令集的设计
任务中只实现了基本要求,但是除了指令之外在结构上有不同之处,后面会有解释
指令位数为8位,指令的高四位为操作数在主存中的地址;[3:2]位并没有用,可以用于扩展指令集或地址,看个人需求;最低两位为操作码。下面细讲:
指令在指令存储器中的存储方式如下:
reg [7:0]ROM[15:0];
initial begin
ROM[0]=8'B00010000;
ROM[1]=8'B00100001;
ROM[2]=8'B00110010;
ROM[3]=8'B01000011;
end
0001 00 00
00为lw(取数指令)的操作码,其所取的数在主存中的地址为0001
从主存的0001位置取一个数存入累加器中。
0010 00 01
01为add(加法指令)的操作码,其所取的数在主存中的地址为0010
从主存的0010位置取一个数与累加器中的数相加结果存入累加器中
0011 00 10
10为sub(减法指令)的操作码,其所取的数在主存中的地址为0011
从主存的0011位置取一个数与累加器中的数相减结果存入累加器中
0100 00 11
11为halt(停机指令)的操作码
使CPU停机
数据通路的设计
设计图
CPU的设计运用了经典的哈佛计算机结构,简单概括就是指令和数据分别由不同的存储器存储,这样的话以后可以向流水线处理器拓展
RTL视图
器件介绍
Metronome(节拍器):产生5个节拍来控制一条指令的实现过程,5个节拍分别为取指(Fetch),译码(Decoding),取数(Access),执行(Operation),写会(Write)
Controller(控制器):产生控制信号来控制CPU在每个阶段的运行过程
IR(指令寄存器):寄存指令并进行译码工作
Instruction(指令存储器):指令存储器,用于存储指令
PC(程序计数器):计算指令个数同时给出指令在指令存储器中的地址
Data(数据存储器(主存)):用于存储操作数
MUX(数据选择器):用于选择向寄存器A内所写入的数据
RegA(数据寄存器1 兼 累加器):用于寄存操作数1和计算结果用于下一次的计算
RegB(数据寄存器2):用于寄存操作数2
ALU(算术逻辑运算单元):用于算术和逻辑运算
SR(结果寄存器):用于存储运算结果
信号介绍
设计逻辑为正逻辑,所有的控制、使能信号都是高有效
Clk:时钟信号
Clr:清零信号
W_ XXX:为该器件的写入使能信号,XXX为器件简称
R_ XXX:为该器件的读取使能信号,XXX为器件简称
E_ XXX:为该器件的运行使能信号,XXX为器件简称
ALUctr:为运算器ALU的选择使能信号,用于判断运行加法或者减法
CPU的实现
模块实现
Metronome(节拍器)
//节拍发生器
module Metronome(
input wire Clk,
input wire Clr,
output wire Fetch,Decoding,Access,Operation,Write
);
reg [2:0]state;
always @(negedge Clk or posedge Clr)begin
if(Clr)begin
state<=3'b111;
end
else begin
state[0]<=~state[2]&~state[1];
state[1]<=state[0];
state[2]<=state[1];
end
end
assign Fetch=state[2] & state[1] & ~state[0];
assign Decoding=state[2] & ~state[1] & ~state[0];
assign Access=~state[2] & ~state[1] & ~state[0];
assign Operation=~state[2] & ~state[1] & state[0];
assign Write=~state[2] & state[1] & state[0];
endmodule
Controller(控制器)
//控制器
module Controller(
input wire Fetch,Decoding,Access,Operation,Write,
input wire LD,ADD,SUB,HALT,
output wire E_PC,
output wire R_I,
output wire W_IR,R_IR,
output wire R_Data,
output wire W_RA,W_RB,R_Reg,
output wire E_ALU,
output wire [1:0]ALUctr,
output wire R_SR
);
assign E_PC=Decoding;
assign R_I=Fetch; //取指阶段
assign W_IR=Decoding; //译码阶段
assign R_IR=Access & (~HALT);
assign R_Data=Access & (~HALT);
assign W_RA=(Access&LD | Write&(ADD|SUB)) & (~HALT);
assign W_RB=Access &(~LD) & (~HALT); //取数阶段
assign R_Reg=(Operation &(ADD|SUB)) & (~HALT);
assign E_ALU=(Operation&(ADD|SUB)) & (~HALT);
assign ALUctr[0]=Operation & ADD & (~SUB);
assign ALUctr[1]=Operation & (~ADD) & SUB; //执行阶段
assign R_SR=(Write&(ADD|SUB)) & (~HALT);
//assign W_Reg=Access|Write; //回写阶段
endmodule
IR(指令寄存器)
//指令寄存器(兼译码)
module IR(
input wire Clk,
input wire W_IR,
input wire R_IR,
input wire [7:0]Instr,
output wire LD,ADD,SUB,HALT,
output wire [3:0]Data_adder
);
reg [7:0]IR;
reg ld,add,sub,halt;
reg [3:0]temp1;
always @ (posedge Clk) begin
if(W_IR==1)begin
IR=Instr;
ld<=~IR[1]&~IR[0];
add<=~IR[1]&IR[0];
sub<=IR[1]&~IR[0];
halt<=IR[1]&IR[0];
temp1<=IR[7:4];
end
end
assign LD=ld;
assign ADD=add;
assign SUB=sub;
assign HALT=halt;
assign Data_adder=(R_IR==1)?temp1:4'b0;
endmodule
Instruction(指令存储器)
//指令存储器
module Instructin(
input wire Clk,
input wire [3:0]fromPC,
input wire R_I,
output reg [7:0]instr
);
reg [7:0]ROM[15:0];
initial begin
ROM[0]=8'B00010000;
ROM[1]=8'B00100001;
ROM[2]=8'B00110010;
ROM[3]=8'B01000011;
end
always @(posedge Clk)begin
if(R_I)begin
instr=ROM[fromPC];
end
end
endmodule
PC(程序计数器)
//程序计数器
module PC(
input wire Clk,
input wire Clr,
input wire E_PC,
output reg [3:0]PC
);
always @ (posedge Clk or posedge Clr)begin
if(Clr)begin PC=4'b0; end
else begin
if(E_PC)begin
PC=PC+1;
end
end
end
endmodule
Data(数据存储器:主存)
//数据存储器
module Data(
input wire Clk,
input wire R_Data,
input wire [3:0]Dadder,
output wire [7:0]Data
);
reg [3:0]temp1;
always @(*)begin temp1<=Dadder; end
reg [7:0]MEM[15:0];
initial begin
//$readmemb("D:\\Vivado project\\SDKS\\data.txt",MEM);
MEM[0]=8'B11111111;
MEM[1]=8'B00001111;
MEM[2]=8'B00000011;
MEM[3]=8'B00000111;
end
reg [7:0]temp;
always @(posedge Clk) begin
if (R_Data) begin
temp<=MEM[temp1];
end
end
assign Data=temp;
endmodule
MUX(数据选择器)
//数据选择器
module MUX(
input wire W_RA,
input wire R_SR,
input wire [7:0]fromSR,
input wire [7:0]fromData,
output reg [7:0]DBUS
);
wire temp;
assign temp=W_RA & ~R_SR;
always @ (*) begin
if(temp)DBUS<=fromData;
else DBUS<=fromSR;
end
endmodule
RegA(数据寄存器1 兼 累加器)
//数据寄存器A(兼累加器)
module RegA(
input wire Clk,
input wire W_RA,R_Reg,
input wire [7:0]Datain, //内部总线
output reg [7:0]busA
);
reg [7:0]R;
initial begin
R=8'b00000000;
end
always @(negedge Clk)begin
if(W_RA)begin
R<=Datain;
end
end
always@* begin if(R_Reg)busA=R; end
endmodule
RegB(数据寄存器2)
//数据寄存器B
module RegB(
input wire Clk,
input wire W_RB,R_Reg,
input wire [7:0]Datain, //内部总线
output reg [7:0]busB
);
reg [7:0]R;
initial begin
R=8'b00000000;
end
always @(negedge Clk)begin
if(W_RB)begin
R<=Datain;
end
end
always@* begin if(R_Reg)busB=R; end
endmodule
ALU(算术逻辑运算单元)
//算术逻辑单元
module ALU(
input wire E_ALU,
input wire [1:0]ALUctr, //10为减,01为加
input wire [7:0]busa,busb,
output wire [7:0]Result
);
ADD_SUB u10(
.Enable(E_ALU),
.T(ALUctr),
.Cin(1'b0),
.A(busa),
.B(busb),
.S(Result)
);
endmodule
module ADD_SUB(
input wire Enable,
input wire [1:0]T,
input wire Cin,
input wire [7:0]A,
input wire [7:0]B,
output reg [7:0]S
);
wire [7:0]NA;
assign NA=~A;
reg [8:0]C;
always @ (*) begin
if(Enable)begin
C[0]=Cin;
if(T[1] & ~T[0])begin
S[0]=A[0]^B[0]^C[0]; C[1]=(NA[0]&B[0])|(NA[0]&C[0])|(B[0]&C[0]);
S[1]=A[1]^B[1]^C[1]; C[2]=(NA[1]&B[1])|(NA[1]&C[1])|(B[1]&C[1]);
S[2]=A[2]^B[2]^C[2]; C[3]=(NA[2]&B[2])|(NA[2]&C[2])|(B[2]&C[2]);
S[3]=A[3]^B[3]^C[3]; C[4]=(NA[3]&B[3])|(NA[3]&C[3])|(B[3]&C[3]);
S[4]=A[4]^B[4]^C[4]; C[5]=(NA[4]&B[4])|(NA[4]&C[4])|(B[4]&C[4]);
S[5]=A[5]^B[5]^C[5]; C[6]=(NA[5]&B[5])|(NA[5]&C[5])|(B[5]&C[5]);
S[6]=A[6]^B[6]^C[6]; C[7]=(NA[6]&B[6])|(NA[6]&C[6])|(B[6]&C[6]);
S[7]=A[7]^B[7]^C[7]; C[8]=(NA[7]&B[7])|(NA[7]&C[7])|(B[7]&C[7]);
if(A<B)begin
S=~(S-1);
end
end
else if(~T[1] & T[0]) begin
S[0]=A[0]^B[0]^C[0]; C[1]=(A[0]&B[0])|(A[0]&C[0])|(B[0]&C[0]);
S[1]=A[1]^B[1]^C[1]; C[2]=(A[1]&B[1])|(A[1]&C[1])|(B[1]&C[1]);
S[2]=A[2]^B[2]^C[2]; C[3]=(A[2]&B[2])|(A[2]&C[2])|(B[2]&C[2]);
S[3]=A[3]^B[3]^C[3]; C[4]=(A[3]&B[3])|(A[3]&C[3])|(B[3]&C[3]);
S[4]=A[4]^B[4]^C[4]; C[5]=(A[4]&B[4])|(A[4]&C[4])|(B[4]&C[4]);
S[5]=A[5]^B[5]^C[5]; C[6]=(A[5]&B[5])|(A[5]&C[5])|(B[5]&C[5]);
S[6]=A[6]^B[6]^C[6]; C[7]=(A[6]&B[6])|(A[6]&C[6])|(B[6]&C[6]);
S[7]=A[7]^B[7]^C[7]; C[8]=(A[7]&B[7])|(A[7]&C[7])|(B[7]&C[7]);
end
else begin
S=8'bzzzzzzzz;
end
end
end
endmodule
SR(结果寄存器)
//结果寄存器(SR)
module SR(
input wire Clk,
input wire R_SR,
input wire [7:0]Result,
output reg [7:0]SR //内部总线
);
reg [7:0]Reg;
always @(*)begin Reg<=Result; end
always @(posedge Clk)begin
if(R_SR)begin
SR=Reg;
end
end
endmodule
模块连接
用于不同模块间的连接,生成美观的RTL视图
实际上在这一步可以直接写仿真程序进行仿真,但是为了让RTL视图美观因而单独写了仿真文件
module Link(
input wire Clk,Clr,
output wire T1,T2,T3,T4,T5,
output wire LD,ADD,SUB,HALT,
output wire E_PC,
output wire R_I,
output wire W_IR,R_IR,
output wire R_Data,
output wire W_RA,W_RB,R_Reg,
output wire E_ALU,
output wire [1:0]ALUctr,
output wire R_SR,
output wire [3:0]PC,
output wire [7:0]toIR,
output wire [3:0]toData,
output wire [7:0]fromData,fromSR,BUS, //fromData,toA,toB,fromSR
output wire [7:0]A,B,Result
);
wire tT1,tT2,tT3,tT4,tT5;
wire tLD,tADD,tSUB,tHALT;
wire tE_PC;
wire tR_I;
wire tW_IR,tR_IR;
wire tR_Data;
wire tW_RA,tW_RB,tR_Reg;
wire tE_ALU;
wire [1:0]tALUctr;
wire tR_SR;
wire [3:0]tPC;
wire [7:0]ttoIR;
wire [3:0]ttoData;
wire [7:0]tfromData,tfromSR; //fromData,toA,toB,fromSR
wire [7:0]tBUS;
wire [7:0]tA,tB,tResult;
Metronome u1(
.Clk(Clk),
.Clr(tHALT|Clr),
.Fetch(tT1),
.Decoding(tT2),
.Access(tT3),
.Operation(tT4),
.Write(tT5)
);
Controller u2(
.Fetch(tT1),
.Decoding(tT2),
.Access(tT3),
.Operation(tT4),
.Write(tT5),
.LD(tLD),
.ADD(tADD),
.SUB(tSUB),
.HALT(tHALT),
.E_PC(tE_PC),
.W_IR(tW_IR),
.R_I(tR_I),
.R_IR(tR_IR),
.R_Data(tR_Data),
.W_RA(tW_RA),
.W_RB(tW_RB),
.R_Reg(tR_Reg),
.E_ALU(tE_ALU),
.ALUctr(tALUctr),
.R_SR(tR_SR)
);
PC u3(
.Clk(Clk),
.Clr(tHALT|Clr),
.E_PC(tE_PC),
.PC(tPC)
);
Instructin u4(
.Clk(Clk),
.fromPC(tPC),
.R_I(tR_I),
.instr(ttoIR)
);
Data u9(
.Clk(Clk),
.R_Data(tR_Data),
.Dadder(ttoData),
.Data(tfromData)
);
IR u5(
.Clk(Clk),
.W_IR(tW_IR),
.R_IR(tR_IR),
.Instr(ttoIR),
.LD(tLD),
.ADD(tADD),
.SUB(tSUB),
.HALT(tHALT),
.Data_adder(ttoData)
);
MUX u12(
.W_RA(tW_RA),
.R_SR(tR_SR),
.fromData(tfromData),
.fromSR(tfromSR),
.DBUS(tBUS)
);
RegA u6(
.Clk(Clk),
.W_RA(tW_RA),
.R_Reg(tR_Reg),
.Datain(tBUS),
.busA(tA)
);
RegB u7(
.Clk(Clk),
.W_RB(tW_RB),
.R_Reg(tR_Reg),
.Datain(tfromData),
.busB(tB)
);
ALU u8(
.E_ALU(tE_ALU),
.ALUctr(tALUctr),
.busa(tA),
.busb(tB),
.Result(tResult)
);
SR u11(
.Clk(Clk),
.R_SR(tR_SR),
.Result(tResult),
.SR(tfromSR)
);
assign T1=tT1;
assign T2=tT2;
assign T3=tT3;
assign T4=tT4;
assign T5=tT5;
assign LD=tLD;
assign ADD=tADD;
assign SUB=tSUB;
assign HALT=tHALT;
assign E_PC=tE_PC;
assign R_I=tR_I;
assign W_IR=tW_IR;
assign R_IR=tR_IR;
assign W_RA=tW_RA;
assign W_RB=tW_RB;
assign R_Reg=tR_Reg;
assign E_ALU=tE_ALU;
assign ALUctr=tALUctr;
assign R_Data=tR_Data;
assign R_SR=tR_SR;
assign PC=tPC;
assign toIR=ttoIR;
assign toData=ttoData;
assign fromData=tfromData;
assign fromSR=tfromSR;
assign BUS=tBUS;
assign A=tA;
assign B=tB;
assign Result=tResult;
endmodule
CPU的仿真
仿真程序
`timescale 1ns / 1ps
module realize();
reg Clk,Clr;
wire T1,T2,T3,T4,T5;
wire LD,ADD,SUB,HALT;
wire E_PC;
wire R_I;
wire W_IR,R_IR;
wire R_Data;
wire W_RA,W_RB,R_Reg;
wire E_ALU;
wire [1:0]ALUctr;
wire R_SR;
wire [3:0]PC;
wire [7:0]toIR;
wire [3:0]toData;
wire [7:0]fromData,fromSR,BUS;
wire [7:0]A,B,Result;
Link DUT(
.Clk(Clk),
.Clr(Clr),
.T1(T1),
.T2(T2),
.T3(T3),
.T4(T4),
.T5(T5),
.LD(LD),
.ADD(ADD),
.SUB(SUB),
.HALT(HALT),
.E_PC(E_PC),
.R_I(R_I),
.W_IR(W_IR),
.R_IR(R_IR),
.R_Data(R_Data),
.W_RA(W_RA),
.W_RB(W_RB),
.R_Reg(R_Reg),
.E_ALU(E_ALU),
.ALUctr(ALUctr),
.R_SR(R_SR),
.PC(PC),
.toIR(toIR),
.toData(toData),
.fromData(fromData),
.fromSR(fromSR),
.BUS(BUS),
.A(A),
.B(B),
.Result(Result)
);
initial begin
Clk=1;Clr=1;#10
Clr=0;#300
$stop;
end
always #5 Clk=~Clk;
endmodule
仿真结果
仿真结果用modelsim显示
看了很多遍仿真结果,是没有问题的,剩下的就是能力有限,委屈各位凑合着看吧
对于刚学完数字逻辑的同学来说好多内容并不是那么好理解,可以多看看计算机组成原理的教材资料,便于更深入的理解。写的并不是很详细,而且各个模块的实现方式和具体细节都没有详细描述,后面有机会会在B站或平台上上传讲解视频,具体位置会放在评论区,到时候可以注意一下。剩下的问题家人们可以讨论讨论,有不足的地方也请大佬多多指教。