outputer 2022-03-31 23:10 采纳率: 100%
浏览 79
已结题

关于verilog设计单口同步RAM的问题

一.这是我的实现代码:


`timescale 1ns / 1ps

module single_port_synrdwr#(
    parameter DATA_WIDTH = 8,
    parameter ADDR_WIDTH = 4,
    parameter ADDR_DEPTH = 2**ADDR_WIDTH
    )
(
    input                  sys_clk,
    input                  spsy_oe,   //output enable
    input                  spsy_wr,   //1 for write and 0 for read
    input                  spsy_cs,    //chip slect
    input [ADDR_WIDTH-1:0] spsy_addr,
    inout [DATA_WIDTH-1:0] spsy_data
    );
    
reg [DATA_WIDTH-1:0] spsy_mem [0:ADDR_DEPTH-1];
reg [DATA_WIDTH-1:0] spsy_mid_data;
 
//initialization for spsy_mem    
integer i;
initial begin
    for(i=0;i<ADDR_DEPTH;i=i+1)
    spsy_mem[i] = 8'b0;
end

//out data(ram is reading for now)
//now inout port is a output port
assign spsy_data = (spsy_cs & !spsy_wr & spsy_oe) ? spsy_mid_data : 8'bz;    

//write port
 always@(posedge sys_clk)begin
    if(spsy_cs & spsy_wr)
        spsy_mem[spsy_addr] <= spsy_mid_data;
    else
        spsy_mem[spsy_addr] <= spsy_mem[spsy_addr];
end 

//read port
always@(posedge sys_clk)begin
    if(spsy_cs & !spsy_wr)
        spsy_mid_data <= spsy_mem[spsy_addr];
    else
        spsy_mem[spsy_addr] <= spsy_mem[spsy_addr];
end   
     
endmodule

二.这是我的仿真代码:

`timescale 1ns / 1ps

module tb_ip_ram_practice_02();

parameter DATA_WIDTH = 8;
parameter ADDR_WIDTH = 4;
parameter ADDR_DEPTH = 2**ADDR_WIDTH;//if unuseful_delete

reg                   sys_clk;
reg                   spsy_oe;
reg                   spsy_wr;
reg                   spsy_cs;
reg  [ADDR_WIDTH-1:0] spsy_addr;
wire [DATA_WIDTH-1:0] spsy_data;//wire for inout port
reg  [DATA_WIDTH-1:0] spsy_mid_data;

//in data
//now inout port is a input port
assign spsy_data  =  (spsy_cs & spsy_wr & !spsy_oe ) ? spsy_mid_data : 7'bz ;

initial begin
    sys_clk = 1'b0;
    forever 
        #10 sys_clk = ~sys_clk;
end

initial begin
    spsy_oe   = 1'b0; 
    spsy_wr   = 1'b0; 
    spsy_cs   = 1'b0; 
    spsy_addr = 4'b0;
    spsy_mid_data = 8'b0;
    
    //read
    #20
    @(posedge sys_clk) begin
        spsy_oe   = 1'b1;
        spsy_cs   = 1'b1;
    end
    repeat(15) #20 spsy_addr = spsy_addr + 4'b1;//read off 16 address's data
    
    //write
    #20
    @(posedge sys_clk) begin
        spsy_cs   = 1'b1;
        spsy_wr   = 1'b1;
    end
    repeat(15) #20 begin
        spsy_addr     = spsy_addr     + 4'b1;
        spsy_mid_data = spsy_mid_data + 4'b1;
    end

 //read agin
    #20
    @(posedge sys_clk) begin
        spsy_oe   = 1'b1;
        spsy_cs   = 1'b1;
    end
    repeat(15) #20 spsy_addr = spsy_addr + 4'b1;//read off 16 address's data
    
    @(posedge sys_clk)
    spsy_cs = 1'b0;
    #20
    $stop ;
    
end

single_port_synrdwr u(
    .sys_clk   (sys_clk),
    .spsy_oe   (spsy_oe),
    .spsy_wr   (spsy_wr),
    .spsy_cs   (spsy_cs),
    .spsy_addr (spsy_addr),
    .spsy_data (spsy_data)
);

endmodule

三.这是仿真之后的电路图
想请教大家的问题是:在wr拉高之后为什么mem里存的数据仍然是0,此时的spsy_mid_data已经开始递增了,为什么mem中存入的数据不随之递增?

img

*四.我改变了mem初始值
mem初始值全部赋1之后发现,最终的输出spsy_data是正确的,但是中间的spsy_mid_data和mem存储的数据是错误的。

img

  • 写回答

3条回答 默认 最新

  • 老皮芽子 2022-04-01 09:20
    关注

    代码,仿真都有问题
    代码这么改

    `timescale 1ns / 1ps
     
    module single_port_synrdwr#(
        parameter DATA_WIDTH = 8,
        parameter ADDR_WIDTH = 4,
        parameter ADDR_DEPTH = 2**ADDR_WIDTH
        )
    (
        input                  sys_clk,
        input                  spsy_oe,   //output enable
        input                  spsy_wr,   //1 for write and 0 for read
        input                  spsy_cs,    //chip slect
        input [ADDR_WIDTH-1:0] spsy_addr,
        inout [DATA_WIDTH-1:0] spsy_data
        );
        
    reg [DATA_WIDTH-1:0] spsy_mem [0:ADDR_DEPTH-1];
    reg [DATA_WIDTH-1:0] spsy_mid_data;
     
    //initialization for spsy_mem    
    integer i;
    initial begin
        for(i=0;i<ADDR_DEPTH;i=i+1)
        spsy_mem[i] = 8'b0;
    end
     
    //out data(ram is reading for now)
    //now inout port is a output port
    assign spsy_data = (spsy_cs & !spsy_wr & spsy_oe) ? spsy_mid_data : 8'bz;    
    
    //write port
    always@(posedge sys_clk)begin
        if(spsy_cs & spsy_wr)
            spsy_mem[spsy_addr] <= spsy_data;
    //    else
    //        spsy_mem[spsy_addr] <= spsy_mem[spsy_addr];
    end 
     
    //read port
    always@(posedge sys_clk)begin
        if(spsy_cs & !spsy_wr)
            spsy_mid_data <= spsy_mem[spsy_addr];
    //    else
    //        spsy_mem[spsy_addr] <= spsy_mem[spsy_addr];
    end   
    
    endmodule
     
    

    仿真这么改

    assign spsy_data  =  (spsy_cs & spsy_wr ) ? spsy_mid_data : 7'bz ;
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
  • wyong0306 2022-04-01 09:04
    关注

    always@(posedge sys_clk)begin
    if(spsy_cs & spsy_wr)
    spsy_mem[spsy_addr] <= spsy_mid_data;
    else
    spsy_mem[spsy_addr] <= spsy_mem[spsy_addr];
    end

    always@(posedge sys_clk)begin
    if(spsy_cs & !spsy_wr)
    spsy_mid_data <= spsy_mem[spsy_addr];
    else
    spsy_mem[spsy_addr] <= spsy_mem[spsy_addr];
    end

    spsy_mid_data这个信号在2个always模块里,在同一个时钟边沿,即被写,由被读。所有出现上面问题。
    同一个信号在多个always模块内,同一时间点,不能同时读,又同时写

    评论
  • 不认得学霸 2022-04-01 09:26
    关注

    一个信号只能在同一个always进行操作。
    读数据时,读使能有效,输出指定地址数据;写数据时,写使能有效,在指定地址写入指定数据;两者都需要片选有效,且不能读写不能同时进行。
    首先保证代码没有逻辑错误和这种语法错误,这时候看仿真的错误才有意义。

    评论 编辑记录
查看更多回答(2条)

报告相同问题?

问题事件

  • 系统已结题 4月10日
  • 已采纳回答 4月2日
  • 修改了问题 4月1日
  • 创建了问题 3月31日

悬赏问题

  • ¥15 相同型号电脑与配置,发现主板有一台貌似缺少了好多元器件似的,会影响稳定性和使用寿命吗?
  • ¥15 要求编写稀疏矩阵A的转置矩阵的算法
  • ¥15 编写满足以下要求的停车场管理程序,设停车场只有一个可停放n辆车的狭窄通道且只有一个大门可供车辆进出。
  • ¥20 powerbulider 导入excel文件,显示不完整
  • ¥15 用keil调试程序保证结果进行led相关闪烁
  • ¥15 paddle训练自己的数据loss降不下去
  • ¥20 用matlab的pdetool解决以下三个问题
  • ¥15 单个福来轮的平衡与侧向滑动是如何做到的?
  • ¥15 嵌入式Linux固件,能直接告诉我crc32校验的区域在哪不,内核的校验我已经找到了,uboot没有
  • ¥20 h3c静态路要求有详细过程