简单周期CPU的Verliog代码的实现、通过在proteus上进行C51仿真LED流水灯实验

一、 单周期CPU的设计原理

1.1 单周期CPU概述

中央处理器,即CPU,作为计算机系统的运算和控制核心,是信息处理、程序运行的最终执行单元。在CPU内部,电平从低到高变化的瞬间称为时钟上升沿,两个相邻时钟上升沿之间的时间间隔称为一个时钟周期。单周期CPU指的是一条指令的执行在一个时钟周期内完成,然后开始下一条指令的执行,即一条指令用一个时钟周期完成。

1.2 CPU工作原理

CPU在处理指令时,一般需要经过以下几个步骤:
(1) 取指令(IF):根据程序计数器PC中的指令地址,从存储器中取出一条指令,同时,PC根据指令字长度自动递增产生下一条指令所需要的指令地址,但遇到“地址转移”指令时,则控制器把“转移地址”送入PC,当然得到的“地址”需要做些变换才送入PC。
(2) 指令译码(ID):对取指令操作中得到的指令进行分析并译码,确定这条指令需要完成的操作,从而产生相应的操作控制信号,用于驱动执行状态中的各种操作。
(3) 指令执行(EXE):根据指令译码得到的操作控制信号,具体地执行指令动作,然后转移到结果写回状态。
(4) 存储器访问(MEM):所有需要访问存储器的操作都将在这个步骤中执行,该步骤给出存储器的数据地址,把数据写入到存储器中数据地址所指定的存储单元或者从存储器中得到数据地址单元中的数据。
(5) 结果写回(WB):指令执行的结果或者访问存储器中得到的数据写回相应的目的寄存器中。
CPU的指令处理过程如下:
在这里插入图片描述

2.1 指令系统的设计

2.1.1 概述
本文所设计的单周期CPU的指令系统采用类似MIPS的设计风格,包括以下四类指令:

(1) 运算类指令;

(2) 传送类指令;

(3) 存储类指令;

(4) 控制类指令;

其中,所有指令的操作码部分用4位二进制表示,寄存器编号用3位二进制表示。在下述的具体设计表示中,以助记符表示的是汇编指令;以代码表示的则是二进制机器指令。

2.2 整体框架的设计

本文所设计的单周期CPU的整体框架主要包括七部分:程序计数器、指令寄存器、寄存器组、算术逻辑单元、数据存储器、控制单元和顶层模块。具体框架如下:
在这里插入图片描述

3.具体实现

程序计数器
代码如下:

module PC(    
    input clk,    
    input [15:0] PCin,    
    input PCWre,    
    input Reset,    
    output reg [15:0] PCout    
);    
      
    initial begin    
        PCout <= 0;   
    end  
        
    always@(posedge clk) begin    
        if(Reset == 0) begin    
            PCout <= 0;    
        end    
        else if(PCWre == 0) begin    
            PCout <= PCout;    
        end    
        else begin    
            PCout <= PCin;    
        end    
    end  
        
endmodule   

指令存储器
代码如下:

module InsMemory(    
    input InsMemRW,    
    input [15:0] address,    
    output reg [15:0] DataOut    
);    
 
    reg [7:0] mem [0:127];   
 
    initial begin    
        DataOut = 16'b1111000000000000;  
        $readmemb("Instructions.txt", mem);      
    end   
      
    always@(*) begin   
        DataOut[15:8] <= mem[address];    
        DataOut[7:0] <= mem[address+1];  
    end   
       
endmodule

寄存器组
代码如下:

module RegFile(    
    input CLK,    
    input RST,    
    input RegWre,    
    input [2:0] ReadReg1,    
    input [2:0] ReadReg2,    
    input [2:0] WriteReg,    
    input [15:0] WriteData,    
    output [15:0] ReadData1,    
    output [15:0] ReadData2    
);    
  
    reg [15:0] regFile[0:7];  
       
    integer i;    
      
    assign ReadData1 = regFile[ReadReg1];   
    assign ReadData2 = regFile[ReadReg2];  
        
    always @ (negedge CLK) begin    
        if (RST == 0) begin    
            for(i=1;i<8;i=i+1)    
                regFile[i] <= 0;    
        end    
        else if(RegWre == 1 && WriteReg != 0) begin    
            regFile[WriteReg] <= WriteData;    
        end    
    end    
            
endmodule   

算数逻辑单元
代码如下:

module ALU(    
    input [2:0] ALUopcode,    
    input [15:0] rega,    
    input [15:0] regb,    
    output reg [15:0] result,    
    output zero,    
    output sign    
);    
  
    assign zero = (result==0)?1:0;    
    assign sign = result[15];    
      
    always @( ALUopcode or rega or regb ) begin    
        case (ALUopcode)    
            3'b000 : result = rega + regb;    
            3'b001 : result = rega - regb;    
            3'b010 : result = regb << rega;    
            3'b011 : result = rega | regb;    
            3'b100 : result = rega & regb;    
            3'b101 : result = (rega < regb)?1:0;     
            3'b110 : begin    
                if (rega<regb &&(( rega[15] == 0 && regb[15]==0) ||    
                (rega[15] == 1 && regb[15]==1))) result = 1;    
                else if (rega[15] == 0 && regb[15]==1) result = 0;    
                else if ( rega[15] == 1 && regb[15]==0) result = 1;    
                else result = 0;    
            end    
            3'b111 : result = regb;    
        endcase    
    end   
       
endmodule   

数据存储器
代码如下:

module DataMemory(    
    input clk,    
    input [15:0] address,    
    input RD,    
    input WR,    
    input [15:0] DataIn,    
    output [15:0] DataOut    
);    
    
    reg [7:0] ram[0:127];  
        
    integer i;    
      
    initial begin;    
        for(i=0;i<128;i=i+1)    
            ram[i]<=0;    
    end    
       
    assign DataOut[7:0] = (RD == 0)? ram[address+1]:8'bz;    
    assign DataOut[15:8] = (RD == 0)? ram[address]:8'bz;    
   
    always@(negedge clk) begin    
        if(WR == 0) begin    
            if(address>=0 && address<128) begin    
                ram[address] <= DataIn[15:8];    
                ram[address+1] <= DataIn[7:0];     
            end    
        end    
    end  
        
endmodule 

控制单元
代码如下:

module ControlUnit(    
    input [3:0] opcode,    
    input zero,    
    input sign,    
    output reg PCWre,    
    output reg ALUSrcA,    
    output reg ALUSrcB,    
    output reg DBDataSrc,    
    output reg RegWre,    
    output reg InsMemRW,    
    output reg RD,    
    output reg WR,    
    output reg RegDst,    
    output reg ExtSel,    
    output reg [1:0] PCSrc,    
    output reg [2:0] ALUOp    
);    
  
    initial begin    
        RD = 1;    
        WR = 1;    
        RegWre = 0;   
        PCWre = 0;   
        InsMemRW = 1;    
    end   
       
    always@ (opcode) begin    
        case(opcode)     
            4'b0000:begin // add    
                PCWre = 1;    
                ALUSrcA = 0;    
                ALUSrcB = 0;    
                DBDataSrc = 0;    
                RegWre = 1;    
                InsMemRW = 1;    
                RD = 1;    
                WR = 1;    
                RegDst = 1;    
                ALUOp = 3'b000;    
            end    
            4'b0001:begin //addi    
                PCWre = 1;    
                ALUSrcA = 0;    
                ALUSrcB = 1;    
                DBDataSrc = 0;    
                RegWre = 1;    
                InsMemRW = 1;    
                RD = 1;    
                WR = 1;    
                RegDst = 0;    
                ExtSel = 1;    
                ALUOp = 3'b000;    
            end    
            4'b0010:begin //sub    
                PCWre = 1;    
                ALUSrcA = 0;    
                ALUSrcB = 0;    
                DBDataSrc = 0;    
                RegWre = 1;    
                InsMemRW = 1;    
                RD = 1;    
                WR = 1;    
                RegDst = 1;    
                ALUOp = 3'b001;    
            end  
            4'b0011:begin // or    
                PCWre = 1;    
                ALUSrcA = 0;    
                ALUSrcB = 0;    
                DBDataSrc = 0;    
                RegWre = 1;    
                InsMemRW = 1;    
                RD = 1;    
                WR = 1;    
                RegDst = 1;    
                ALUOp = 3'b011;    
            end     
            4'b0100:begin // ori    
                PCWre = 1;    
                ALUSrcA = 0;    
                ALUSrcB = 1;    
                DBDataSrc = 0;    
                RegWre = 1;    
                InsMemRW = 1;    
                RD = 1;    
                WR = 1;    
                RegDst = 0;    
                ExtSel = 0;    
                ALUOp = 3'b011;    
            end    
            4'b0101:begin //and    
                PCWre = 1;    
                ALUSrcA = 0;    
                ALUSrcB = 0;    
                DBDataSrc = 0;    
                RegWre = 1;    
                InsMemRW = 1;    
                RD = 1;    
                WR = 1;    
                RegDst = 1;    
                ALUOp = 3'b100;    
            end    
            4'b0110:begin //sll    
                PCWre = 1;    
                ALUSrcA = 1;    
                ALUSrcB = 0;    
                DBDataSrc = 0;    
                RegWre = 1;    
                InsMemRW = 1;    
                RD = 1;    
                WR = 1;    
                RegDst = 1;    
                ALUOp = 3'b010;    
            end    
            4'b0111:begin //slt    
                PCWre = 1;    
                ALUSrcA = 0;    
                ALUSrcB = 0;    
                DBDataSrc = 0;    
                RegWre = 1;    
                InsMemRW = 1;    
                RD = 1;    
                WR = 1;    
                RegDst = 1;    
                ALUOp = 3'b110;    
            end  
            4'b1000:begin //mov    
                PCWre = 1;    
                ALUSrcA = 0;    
                ALUSrcB = 0;    
                DBDataSrc = 0;    
                RegWre = 1;    
                InsMemRW = 1;    
                RD = 1;    
                WR = 1;    
                RegDst = 1;    
                ExtSel = 1;    
                ALUOp = 3'b111;    
            end  
            4'b1001:begin //movi    
                PCWre = 1;    
                ALUSrcA = 0;    
                ALUSrcB = 1;    
                DBDataSrc = 0;    
                RegWre = 1;    
                InsMemRW = 1;    
                RD = 1;    
                WR = 1;    
                RegDst = 0;    
                ExtSel = 1;    
                ALUOp = 3'b111;    
            end      
            4'b1010:begin //sw    
                PCWre = 1;    
                ALUSrcA = 0;    
                ALUSrcB = 1;    
                RegWre = 0;    
                InsMemRW = 1;    
                RD = 1;    
                WR = 0;    
                ExtSel =1;    
                ALUOp = 3'b000;    
            end    
            4'b1011:begin //lw    
                PCWre = 1;    
                ALUSrcA = 0;    
                ALUSrcB = 1;    
                DBDataSrc = 1;    
                RegWre = 1;    
                InsMemRW = 1;    
                RD = 0;    
                WR = 1;    
                RegDst = 0;    
                ExtSel = 1;    
                ALUOp = 3'b000;    
            end   
            4'b1100:begin //beq    
                PCWre = 1;    
                ALUSrcA = 0;    
                ALUSrcB = 0;    
                RegWre = 0;    
                InsMemRW = 1;    
                RD = 1;    
                WR = 1;    
                ExtSel = 1;    
                ALUOp = 3'b001;    
            end    
            4'b1101:begin  //bgtz  
                PCWre = 1;    
                ALUSrcA = 0;    
                ALUSrcB = 0;    
                RegWre = 0;    
                InsMemRW = 1;    
                RD = 1;    
                WR = 1;    
                ExtSel = 1;    
                ALUOp = 3'b001;    
            end    
            4'b1110:begin //j    
                PCWre = 1;    
                RegWre = 0;    
                InsMemRW = 1;    
                RD = 1;    
                WR = 1;    
                ALUOp = 3'b010;    
            end    
            4'b1111:begin //halt    
                PCWre = 0;    
                RegWre = 0;    
                InsMemRW = 1;    
                RD = 1;    
                WR = 1;    
            end    
            default:begin    
                RD = 1;    
                WR = 1;    
                RegWre = 0;    
                InsMemRW = 0;    
            end    
        endcase    
    end   
       
    always@(opcode or zero or sign) begin    
        if(opcode == 4'b1110) // j    
            PCSrc = 2'b10;    
        else if(opcode == 4'b1100) begin  
            if(zero == 1)  
                PCSrc = 2'b01;  
            else  
                PCSrc = 2'b00;  
        end  
        else if(opcode == 4'b1101) begin  
            if(zero == 0 && sign == 0)    
                PCSrc = 2'b01;    
            else    
                PCSrc = 2'b00;  
        end    
        else begin    
            PCSrc = 2'b00;    
        end    
    end   
       
endmodule    

顶层模块实现
在这里插入图片描述

二、通过在proteus上进行C51仿真LED流水灯实验

1、绘制原理图

1)添加元件
(1)点击绘制原理图按钮。

在这里插入图片描述
(2)左键单击元件,然后再点击P按钮,进入元件选择界面。

(3)在 Keywords 处输入 AT89C51 ,然后在中间的窗口内双击AT89C51芯片,即可添加到元件列表中,而后依次添加LED-YELLOW、RES

在这里插入图片描述

2)摆放元件

(1)左击元件列表窗内的 AT89C51 芯片,然后再原理图编辑窗口内左击摆放。
在这里插入图片描述
(2)左击元件列表内的 LED-YELLOW ,再点击 旋转按钮 ,可以在预览窗内看见元件顺时针旋转了下,再在原理图编辑框内一次摆放LED灯共8个。

在这里插入图片描述
(3)再按照(2)的步骤依次摆放8个电阻,然后左键双击“10K”,弹出修改值的对话框,将10K修改为300,以至于让LED更亮。
在这里插入图片描述
(4)拉一条主线。(左击一下起点,然后移动鼠标,然后双击一下终点,即可拉一条主线)
在这里插入图片描述
(5)连接管脚。(左击一下起点和左击一下终点即可连接)
在这里插入图片描述
(6)点击终端接口→选择POWER,放置电源,然后左键双击电源图标,修改为VCC,再点击OK。
在这里插入图片描述
(7)使用 LBL 为支线标记编号,连接到主线的支线,需要对支线进行编号才能正常连接,否则后面需要正常实验成功(使用方法:点击 LBL 后,在左键单击支线上,修改值)

在这里插入图片描述

2、编写51程序

1)创建一个工程
(1)打开 Keil 软件,点击 Project → New uVision Project …

(2)给工程命名。(这里我取名为 LED )
在这里插入图片描述
(3)在搜索框内输入 AT89C51 ,再选中 AT89C51 芯片,然后点击 OK 。
在这里插入图片描述
2)编写main.c文件
(1)点击左上角新建文件,再在文本框内复制粘贴51程序代码。`

//51单片机编程常用的头文件
    #include <reg51.h>
    #include <intrins.h>
    //延迟函数
    void delay_ms(int a)
    {
        int i,j;
        for(i=0;i<a;i++)
        {
            for(j=0;j<1000;j++) _nop_();
    
        }
    }
    
    void main(void)
    {
        while(1)
        {
            P0=0xfe;
            delay_ms(50);
            P0=0xfd;
            delay_ms(50);
            P0=0xfb;
            delay_ms(50);
            P0=0xf7;
            delay_ms(50);
            P0=0xef;
            delay_ms(50);
            P0=0xdf;
            delay_ms(50);
            P0=0xbf;
            delay_ms(50);
            P0=0x7f;
            delay_ms(50);
        }
    }

在这里插入图片描述
(2)点击保存按钮,再命名为main.c文件(一定要加.c后缀,不然就不是C文件了),再点击保存。
在这里插入图片描述
(3)右键点击 Source Group 1 ,再点击 Add Existing Files to Group “Source Group 1”…
在这里插入图片描述
(4)选中刚刚创建的 main.c 文件,并点击 Add 。
在这里插入图片描述
(5)可以看见 main.c 文件已经在 Source Group 1 目录下面了。
在这里插入图片描述
3)生成 .hex 文件
(1)点击魔法棒,在弹出的窗口内选择 Output ,再勾选 Create HEX File ,然后点击 OK。
在这里插入图片描述
(2)点击编译按钮,进行编译,编译成功并生成了两个头文件(这一步不可忽略,否则无法生成 .hex 文件)
在这里插入图片描述

3、开始仿真

(1)回到Proteus软件的原理图内,双击 AT89C51 芯片后,在弹出的窗口的 Program File 一栏从刚才 keil 软件编译后的路径中添加 .hex 文件,再点击 OK 。在这里插入图片描述(2)点击调试按钮,开始仿真。

(3)仿真结果
在这里插入图片描述
在这里插入图片描述

  • 32
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值