侧边栏壁纸
    • 累计撰写 296 篇文章
    • 累计收到 520 条评论
    RAM与ROM及Verilog实现
    我的学记|刘航宇的博客

    RAM与ROM及Verilog实现

    刘航宇
    2023-02-10 / 0 评论 / 325 阅读 / 正在检测是否收录...

    概念

    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

    1
    VLSI设计基础1-数字IC引论:度量指标及版图基础
    « 上一篇 2023-02-23
    FPGA与数字IC设计中接口命名规范
    下一篇 » 2023-02-10

    评论 (0)

    取消