计算机组成原理实验——实现寄存器堆模块Verilog

寄存器

寄存器是中央处理器内的组成部分
寄存器是有限存贮容量的高速存贮部件
用来暂存指令、数据和地址

寄存器堆

MIPS指令需要32个寄存器,采用寄存器-寄存器结构
需要用数组表示寄存器堆
寄存器堆需要有两个数据输出接口,同时输出;一个输入接口

0号寄存器不保存数据,固定为0【用来完成一些简单指令


raddr1读地址
若raddr=00111,则rdata1写入7号寄存器的数据

写四个要求
1 waddr哪个寄存器
2 wdata数据
3 clk等脉冲上升沿
4 WE读写信号高电平

寄存器堆接口

module registers(
	input clk,
	input oc,	//可不要
	input [4:0] raddr1,
	input [4:0] raddr2,
	input [4:0] waddr,
	input [31:0] wdata,
	input we,	//使能端,读写信号
	output reg[31:0] rdata1,
	output reg[31:0] rdata2
	);
	reg [31:0] rdata1;
    reg [31:0] rdata2;
    reg [31:0] regts[1:31];
//读端口1读端口2用两个独立的always模块来实现
//读端口1
	always @(*)	//组合逻辑电路,只要有输入马上就有输出
	begin
		if(oc==1'b1)	//禁止输出
		begin
			radata1<=32'b0;
		end
		else if(raddr1==5'b00000)	//$0号寄存器只保存0
		begin
			rdata1<=32'b0;
		end
		else
		begin
			rdata1<=regts[raddr1]
		end
		end
	
	//读端口2
	
	//写端口
	always @(posedge clk)	//脉冲信号作用下才能写
	begin
		if((we==1'b1)&&(waddr!=5'b00000))	//判断使能端是否为1,是否为0号地址,0号不可写
		begin
			regts[waddr]<=wdata;
		end
end

ALU&&寄存器堆

寄存器堆rdata1接ALU a端口,寄存器堆rdata2接ALU b端口
ALU输出f端口接寄存器堆wdata端口
在这里插入图片描述

reg(…out)输出端口与alu(a…)输入端口位数一致
wire[3:0]w, //声明wire电线连接,两两之间
reg r(…w),
alu a(w…),
fib整体框架图
在这里插入图片描述
操作确定:加法
默认:WE=1
初始除了0号寄存器其他寄存器均为空
通过写端口写入数据
rada1 rdata2数据来自寄存器

有限状态机fsm
always@(posedge clk)//时钟脉冲的作用下
if(reset)//复位信号有效,直接跳转到初始状况

else case(state)
STATE1: … //指出每个状态执行完跳转到哪个状态
STATE1: …

default:state <= STATE1;
endcase
在这里插入图片描述
fib&fsm

//申请状态
wire [31:0] a, b ,f;
reg [31:0] wdata;
wire we = 1'b1;
parameter op = 4'b0001;	//加法运算
reg [4:0] ra1,ra2,wa;
reg [3:0] count;

//实例化寄存器
registers myregs(.clk(clk),.oc(~rst),.raddr1(ra1),.raddr2(ra2),.waddr(wa),.wda(wdata),.we(we),.rdata1(a),.rdata2(b));
//实例化ALU
alu myalu(a, b, op, f);	//a b与rdata1(a),rdata2(b)连接
assign result = wdata;

reg[1:0]status = 2'b00;	//状态
always@(posedge clk)
begin
	if(rst == 1'b0)	//复位信号
	begin
		status <= 2'b00;	//初始化为0
		count <= 3;	//从3开始算
	end else
	case(status)
	2’b00:
		begin
			ra1 <= 5'b1;
			ra2 <= 5'b10;
			wa <= 5'b1;	//1号寄存器
			wdata <= 32'b1;	//1写入1号寄存器
			status <= 2'b01;	//跳转到下一状态
		end
	2’b01:
		begin
			wa <= 5'b10;
			wdata <= 32'b1;
			status <= 2'b10;
		end
	2'b10:
		begin
			wa <= ra2+1;
			wdata <= f;
			status <= 2'b11;
			count <= count + 1;
		end
	2'b11:
		begin
			if(count < n)
			begin
				ra1 <= ra2;		//ra1=ra1+1
				ra2 <= wa;		//ra2=ra2+1
				status <= 2'b10;
			end
		end
	endcase

最后补充-所有模块代码

//top模块:
module top2(
    input clk,
    input rst,
    input [3:0] n,
    output [11:0] result
    );
    wire [31:0] out;
    assign result=out[11:0];
    fib1 f(clk,rst,n,out);
    
    initial
    $monitor($time,,"top:result=%h",result);

endmodule

//
//fib模块:
module fib1(
    input clk,
    input rst,
    input [3:0] n,
    output [31:0] result
    );
    wire [31:0] a,b,f;
    reg [31:0] wdata;
    wire we = 1'b1;
    reg [4:0] ra1,ra2,wa;
    reg [3:0] count;
    parameter op = 4'b0001;		//加法运算
   
//实例化寄存器
    registers myregs(.clk(clk),.oc(~rst),.raddr1(ra1),.raddr2(ra2),.waddr(wa),.wdata(wdata),.we(we),.rdata1(a),.rdata2(b));
 	//实例化ALU
    alu myalu1(a, b, op, f);    //a b与rdata1(a),rdata2(b)连接
    assign result = wdata;
    
    reg[1:0]status = 2'b00;    //状态
    always@(posedge clk)
    begin
        if(rst == 1'b0)    //复位信号
        begin
            status <= 2'b00;    //初始化为0
            count <= 3;    //从3开始算
        end else
        case(status)
        2'b00:
            begin
                ra1 <= 5'b1;
                ra2 <= 5'b10;
                wa <= 5'b1;    //1号寄存器
                wdata <= 32'b1;    //1写入1号寄存器
                status <= 2'b01;    //跳转到下一状态
            end
        2'b01:
            begin
                wa <= 5'b10;
                wdata <= 32'b1;
                status <= 2'b10;
            end
        2'b10:
            begin
                wa <= ra2+1;
                wdata <= f;
                status <= 2'b11;
                count <= count + 1;
            end
        2'b11:
            begin
                if(count < n)
                begin
                    ra1 <= ra2;        //ra1=ra1+1
                    ra2 <= wa;        //ra2=ra2+1
                    status <= 2'b10;
                end
            end
        endcase
    end
    initial
            $monitor($time,,"fib:rst=%b,wdata=%h,count=%h",rst,wdata,count);
            
        initial
            $monitor($time,,"fib:result=%h",result); 
endmodule

//
//alu模块:
module alu(
    input [31:0] a,
    input [31:0] b,
    input [3:0] operation,
    output [31:0] f,
    output z
    );
     reg[31:0]result;
       always@(*)
       begin
           case(operation)
               4'b0000:result=32'b0;
               4'b0001:result=a+b;
               4'b0010:result=a-b;
               4'b0011:result=a&b;
               4'b0100:result=a|b;
               4'b0101:result=a^b;
               default:result=32'b0;
           endcase
       end
       assign f=result;
       assign z=~(|result);
       
       initial
           $monitor($time,,"alu:a=%h,b=%h,operation=%b",a,b,operation);
       initial
           $monitor($time,,"alu:f=%h,z=%b",f,z);

endmodule

//
//registers模块:
module registers(
    input clk,
    input oc,	//可不要
    input [4:0] raddr1,
    input [4:0] raddr2,
    input [4:0] waddr,
    input [31:0] wdata,
    input we,		//使能端,读写信号
    output [31:0] rdata1,
    output [31:0] rdata2
    );
    reg [31:0] rdata1;
    reg [31:0] rdata2;
reg [31:0] regts[1:31];
//读端口1
    always @(*)		//只要有输入就立即输出
    begin
        if(oc == 1'b1)		//禁止输出
        begin
            rdata1 <= 32'b0;
        end
        else if(raddr1 == 5'b00000)		//$0号寄存器只保存0
        begin
            rdata1 <= 32'b0;
        end
        begin
            rdata1 <= regts[raddr1];
        end
    end
    //读端口2
    always @(*)
        begin
            if(oc == 1'b1)
            begin
                rdata2 <= 32'b0;
            end
            else if(raddr2 == 5'b00000)
            begin
                rdata2 <= 32'b0;
            end
            begin
                rdata2 <= regts[raddr2];
            end
        end
        
    always @(posedge clk)		//脉冲信号作用下才能写
        begin
            #1 if((we == 1'b1) &&(waddr != 5'b00000))		//判断使能端是否为1,是否为0号地址,0号寄存器不可写
            begin
                regts[waddr] <= wdata;
            end
        end
endmodule

//仿真程序
module fib_sim(
    output [11:0] result
    );
     //parameter clk_period=10;
       reg clk;
       initial 
       begin
           clk=1'b0;
           forever
              #2 clk=~clk;
       end
       
       reg rst=1'b1;
       reg[3:0] n=4'b1111;
       top2 t(clk,rst,n,result);
       
       initial
       begin
           #2 rst=1'b0;
           #4 rst=1'b1;
       end

endmodule

仿真波形图
仿真波形图
仿真到179’h即停止的原因是输入n的位数为4位。在这里插入图片描述
在这里插入图片描述

  • 13
    点赞
  • 115
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Verilog代码中,RAM(Random Access Memory)和寄存器堆(Register File)的代码有一些区别,主要体现在以下几个方面: 1. 数据存储方式:RAM的Verilog代码通常使用内存模块(memory)来表示,可以通过地址信号进行读写操作。RAM的代码会包括内存模块的定义、读写使能信号、地址信号以及数据输入输出端口。而寄存器堆Verilog代码通常使用寄存器数组(register array)来表示,可以通过索引信号选择相应的寄存器进行读写操作。寄存器堆的代码会包括寄存器数组的定义、读写使能信号、索引信号以及数据输入输出端口。 2. 存储容量:RAM的Verilog代码会指定内存模块的容量,即内存单元的数量和每个单元的数据位宽。而寄存器堆Verilog代码会指定寄存器数组的大小,即寄存器的数量和每个寄存器的数据位宽。 3. 读写操作:RAM的Verilog代码需要使用读写使能信号和地址信号来进行读写操作,通常使用非阻塞赋值(non-blocking assignment)语句来实现。而寄存器堆Verilog代码通常是在时钟上升沿进行读写操作,使用阻塞赋值(blocking assignment)语句或非阻塞赋值语句来实现。 4. 时钟域:RAM和寄存器堆Verilog代码可能在不同的时钟域中工作。RAM通常由外部时钟控制,而寄存器堆通常与CPU的时钟同步。 需要注意的是,RAM和寄存器堆Verilog代码在具体实现时可能会根据设计需求和工具特性有所不同。因此,在编写代码时,应根据设计要求和综合工具的要求进行适当的调整和优化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值