RAM与ROM及Verilog实现
我的学记|刘航宇的博客

RAM与ROM及Verilog实现

刘航宇
2年前发布 /正在检测是否收录...
温馨提示:
本文最后更新于2023年06月03日,已超过664天没有更新,若内容或图片失效,请留言反馈。

概念

RAM(random access memory)即随机存储内存,这种存储器在断电时将丢失其存储内容,故主要用于存储短时间使用的程序。
ROM 指的是“只读存储器”,即Read-Only Memory。只读存储器(Read-Only Memory,ROM)以非破坏性读出方式工作,只能读出无法写入信息。信息一旦写入后就固定下来,即使切断电源,信息也不会丢失,所以又称为固定存储器。ROM所存数据通常是装入整机前写入的,整机工作过程中只能读出,不像随机存储器能快速方便地改写存储内容。ROM所存数据稳定 ,断电后所存数据也不会改变,并且结构较简单,使用方便,因而常用于存储各种固定程序和数据。
PROM 指的是“可编程只读存储器”既Programmable Red-Only Memory。这样的产品只允许写入一次,所以也被称为“一次可编程只读存储器”(One Time Progarmming ROM,OTP-ROM)。最初从工厂中制作完成的PROM内部并没有资料,用户可以用专用的编程器将自己的资料写入,但是这种机会只有一次,一旦写入后也无法修改。
EPROM 指的是“可擦写可编程只读存储器”,即Erasable Programmable Read-Only Memory。它的特点是具有可擦除功能,擦除后即可进行再编程,但是缺点是擦除需要使用紫外线照射一定的时间。
EEPROM 指的是“电可擦除可编程只读存储器”,即Electrically Erasable Programmable Read-Only Memory。它的最大优点是可直接用电信号擦除,也可用电信号写入。EEPROM不能取代RAM的原因是其工艺复杂, 耗费的门电路过多,且重编程时间比较长,同时其有效重编程次数也比较低。
Flash memory 指的是“闪存”,所谓“闪存”,它也是一种非易失性的内存,属于EEPROM的改进产品。它的最大特点是必须按块(Block)擦除(每个区块的大小不定,不同厂家的产品有不同的规格), 而EEPROM则可以一次只擦除一个字节(Byte)。目前“闪存”被广泛用在PC机的主板上,用来保存BIOS程序,便于进行程序的升级。其另外一大应用领域是用来作为硬盘的替代品,具有抗震、速度快、无噪声、耗电低的优点,但是将其用来取代RAM就显得不合适,因为RAM需要能够按字节改写,而Flash ROM做不到。

二、编程

1.要求:
编程实现512x8的ROM和RAM。
ROM、RAM至少应该包含的端口包括地址线、数据线、片选线、读写使能端,复位端和时钟端(其中部分信号线只适用于RAM)。
ROM、RAM和总测试模块分别包含在不同的.v文件中。
端口意义:

2.设计思路:
512x8的ROM和RAM,至少需要9位地址线和8位数据位。
3.RAM实现代码

//模块声明,指定模块名和端口引脚
module RAM (Data,Addr,CS,RWEnable,Reset,Clk);
  //参数定义,指定数据总线和地址总线的宽度,以及内存单元的数量
  parameter width=8,msize=512;
  //端口引脚的方向和位宽定义
  input CS,RWEnable,Reset,Clk; //输入信号,分别为芯片选择、读写使能、复位和时钟
  input[width:0] Addr; //输入地址总线,宽度由width参数决定
  inout[width-1:0] Data; //双向数据总线,宽度由width参数决定
  //内部信号和寄存器的定义
  reg [width-1:0] Data_temp; //用于暂存读出的数据的寄存器,宽度与Data总线相同
  reg [width-1:0] Mem [msize-1:0]; //用于存储所有数据的内存数组,大小与内存单元数量相同
  integer i; //用于遍历内存单元的整数变量
  //always块,指定模块中所有操作的逻辑
  always @(posedge Clk or posedge Reset)
  begin
    //复位条件,当Reset为1时,所有内存单元都被置为0
    if(Reset)
        begin
           for(i=0;i<msize;i=i+1) //用一个for循环遍历所有内存单元
           Mem[i] <= 0; //将每个内存单元赋值为0
        end
    //写操作条件,当RWEnable为1且CS为1时,将Data总线上的数据写入到Addr指定的内存单元中
    else if((RWEnable==1'b1)&&(CS==1'b1))
        begin
          Mem[Addr] <= Data; //将Data总线上的数据赋值给Mem[Addr]
        end
        
    //读操作条件,当RWEnable为0且CS为1时,将Addr指定的内存单元中的数据读出并暂存在Data_temp中
    else if((RWEnable==1'b0)&&(CS==1'b1))
        begin
          Data_temp<=Mem[Addr]; //将Mem[Addr]中的数据赋值给Data_temp
        end
    //其他条件,当CS为0或RWEnable为不确定值时,将Data_temp置为高阻抗状态
    else
        begin
          Data_temp <= 8'bz; //将Data_temp赋值为高阻抗状态
        end
  end
  //assign语句,指定Data总线与Data_temp之间的连接关系
  assign Data=RWEnable?8'bz:Data_temp; //当RWEnable为1时,Data总线处于高阻抗状态;当RWEnable为0时,Data总线接收Data_temp中的数据
endmodule //模块结束

测试代码如下:

//模块声明,指定模块名为RAM_TS
module RAM_TS; 
 //信号和寄存器的定义,指定与RAM模块相连的端口引脚和内部变量
 reg CS_t,RWEnable_t,Reset_t,Clk_t; //芯片选择、读写使能、复位和时钟信号,都是1位的寄存器
 wire [7:0] Data_t; //数据总线,是8位的线网
 reg [8:0] Addr_t; //地址总线,是9位的寄存器
 reg [7:0] Data_temp_t; //用于暂存写入数据的寄存器,也是8位的
 //initial块,指定测试RAM模块的过程,只会在仿真开始时执行一次
 initial
 begin
 RWEnable_t = 1;//w //初始化读写使能信号为1,表示写模式
 Reset_t = 1; //初始化复位信号为1,表示复位模式
 Clk_t = 0; //初始化时钟信号为0
 Addr_t = 0; //初始化地址总线为0
 Data_temp_t = 0; //初始化暂存数据为0
 CS_t=1; //初始化芯片选择信号为1,表示使能模式
 #5 Reset_t=0;  //延迟5个时间单位后,将复位信号置为0,表示正常工作模式
 repeat(10) //重复10次以下操作
 begin
 #5 //延迟5个时间单位后
 Addr_t=Addr_t+10; //将地址总线加10,表示访问下一个内存单元
 Data_temp_t=Addr_t; //将地址总线上的值赋给暂存数据,表示要写入的数据与地址相同
 end
 #70  //延迟70个时间单位后
 RWEnable_t = 0;//r //将读写使能信号置为0,表示读模式
 Addr_t=0; //将地址总线置为0,表示从第一个内存单元开始读取数据
 repeat(10) //重复10次以下操作
 begin
 #5 //延迟5个时间单位后
 Addr_t=Addr_t+10;  //将地址总线加10,表示访问下一个内存单元 
 end 
 end
 //assign语句,指定数据总线与暂存数据之间的连接关系
 assign Data_t=RWEnable_t?Data_temp_t:8'bz; 
 always #5 Clk_t=~Clk_t;

//实例化一个RAM模块,并且用定义好的信号和寄存器与之相连 
 RAM myRAM(
 .Data(Data_t), //将数据总线与RAM模块的Data端口相连
 .Addr(Addr_t), //将地址总线与RAM模块的Addr端口相连
 .CS(CS_t), //将芯片选择信号与RAM模块的CS端口相连
 .RWEnable(RWEnable_t), //将读写使能信号与RAM模块的RWEnable端口相连
 .Reset(Reset_t), //将复位信号与RAM模块的Reset端口相连
 .Clk(Clk_t) //将时钟信号与RAM模块的Clk端口相连
 );
endmodule //模块结束

4.RAM仿真测试:
① 数据写入操作
image.png
② 数据读取操作
image.png
5.ROM实现代码:

ROM代码如下:

//模块声明,指定模块名和端口引脚
module ROM(Data,Addr,CS,RDEnable,Reset,Clk);
 //参数定义,指定数据总线和地址总线的宽度,以及内存单元的数量
 parameter width=8,msize=512;
 //端口引脚的方向和位宽定义
 input CS,RDEnable,Reset,Clk; //输入信号,分别为芯片选择、读使能、复位和时钟
 input[width:0] Addr; //输入地址总线,宽度由width参数决定
 output [width-1:0] Data; //输出数据总线,宽度由width参数决定
 //内部信号和寄存器的定义
 reg [width-1:0] Data_read; //用于暂存读出的数据的寄存器,宽度与Data总线相同
 reg [width-1:0] Mem [msize-1:0]; //用于存储所有数据的内存数组,大小与内存单元数量相同
 integer i; //用于遍历内存单元的整数变量
 //always块,指定模块中所有操作的逻辑
 always @(posedge Clk or posedge Reset)
    begin

 //复位条件,当Reset为1时,所有内存单元都被置为其地址值
    if(Reset)
    begin
        for(i=0;i<msize;i=i+1) //用一个for循环遍历所有内存单元
        Mem[i] <= i; //将每个内存单元赋值为其地址值
    end
 //读操作条件,当RDEnable为1且CS为1时,将Addr指定的内存单元中的数据读出并暂存在Data_read中
    else if((RDEnable==1'b1)&&(CS==1'b1))
    begin
    Data_read<=Mem[Addr]; //将Mem[Addr]中的数据赋值给Data_read
    end 
 //其他条件,当CS为0或RDEnable为不确定值时,将Data_read置为高阻抗状态
    else
    Data_read <= 8'bz; //将Data_read赋值为高阻抗状态
    end
 //assign语句,指定Data总线与Data_read之间的连接关系
 assign Data=Data_read; //当RDEnable为1时,Data总线输出Data_read中的数据;当RDEnable为0时,Data总线处于高阻抗状态
endmodule //模块结束

测试代码如下:

//模块声明,指定模块名为R0M98_TS
module R0M_TS; 
  //信号和寄存器的定义,指定与ROM98模块相连的端口引脚和内部变量
  reg CS_t,RDEnable_t,Reset_t,Clk_t; //芯片选择、读使能、复位和时钟信号,都是1位的寄存器
  wire [7:0] Data_t; //数据总线,是8位的线网
  reg [8:0] Addr_t; //地址总线,是9位的寄存器
  //initial块,指定测试ROM98模块的过程,只会在仿真开始时执行一次
  initial
    begin
      RDEnable_t = 1;//r //初始化读使能信号为1,表示读模式
      Reset_t = 1; //初始化复位信号为1,表示复位模式
      Clk_t = 0; //初始化时钟信号为0
      Addr_t = 0; //初始化地址总线为0
     // Data_read_ts = 0; //初始化暂存数据为0
      CS_t=1; //初始化芯片选择信号为1,表示使能模式
      #5 Reset_t=0; //延迟5个时间单位后,将复位信号置为0,表示正常工作模式
            
      repeat(10) //重复10次以下操作
        begin
          #10 //延迟10个时间单位后
          Addr_t=Addr_t+10; //将地址总线加10,表示访问下一个内存单元
        end    
    end
  //always块,指定时钟信号的变化规律,每隔5个时间单位翻转一次
  always #5 Clk_t=~Clk_t;
  //实例化一个ROM98模块,并且用定义好的信号和寄存器与之相连 
  ROM myROM(
  .Data(Data_t), //将数据总线与ROM98模块的Data端口相连
  .Addr(Addr_t), //将地址总线与ROM98模块的Addr端口相连
  .CS(CS_t), //将芯片选择信号与ROM98模块的CS端口相连
  .RDEnable(RDEnable_t), //将读使能信号与ROM98模块的RDEnable端口相连
  .Reset(Reset_t), //将复位信号与ROM98模块的Reset端口相连
  .Clk(Clk_t) //将时钟信号与ROM98模块的Clk端口相连
  );
endmodule //模块结束

6.ROM仿真测试:
image.png

© 版权声明
THE END
喜欢就支持一下吧
点赞 1 分享 赞赏
评论 抢沙发
取消