基于FPGA的8位模型计算机设计与仿真

 开发环境:vivado2018.3版本和modelsim10.6C版本

 

题目要求

基本要求

 

根据图1的8位模型计算机框图的工作原理,实现10个以上功能模块设计、仿真和调试,以及系统设计、仿真和调试。

  1. 基本8位模型计算机需设计4条指令:数据传送、加法、减法、暂停。
  2. 总线结构是单总线,数据总线位数8位、地址总线最少是3位。
  3. 存储器容量最少是7x8位。
  4. 操作码、操作数自行设计。

 

扩展要求

根据掌握的数字系统设计知识和能力,在基本要求的基础上自行扩展系统功能。也可以选择如下一个或一个以上的扩展功能。

  1. 改变系统结构,例如,取消图1中的内部数据总线。
  2. 在8位模型计算机结构基础上增加指令,例如:逻辑运算、乘法等。
  3. 将单总线结构改为双总线。
  4. 将数据总线位数从8位增加到16位。
  5. 存储器用RAM或双端口存储器。
  6. 将累加器改为寄存器组。

 

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站或平台上上传讲解视频,具体位置会放在评论区,到时候可以注意一下。剩下的问题家人们可以讨论讨论,有不足的地方也请大佬多多指教。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值