这里测试数据从ROM里读,用两个64words的RAM来实现乒乓。
先看一下RAM ipcore的特征,在配置时先看一下配置方式就是有锁存器
在生成的ipcore中 altsyncram_component.outdata_reg_a ="UNREGISTERED",就是无寄存器 altsyncram_component.outdata_reg_a ="CLOCK0",就是有寄存器 发现连了时钟线的就是有锁存器,没连时钟线的就是没锁存器。很可能有时钟触发的就是always@(edge clk),没有时钟就是assign A=B,所以有时钟触发里有锁存器,没有就是总线输入输出,没锁存器。 双口RAM,不选择输出有寄存器的使用方法: 1. 写使能,第一个写地址,第一个写数据在同步赋值。 2. 读使能一直有效,读地址在和读出第一个数据间有一个时钟延时,那么第一个数据 读出时正好读地址开始递增1。 虽然读出数据没有寄存器,但读地址有寄存器,所以读地址比读出数据快一个时钟;而写RAM时,地址和数据都有寄存器,所以两个是同步赋值,触发条件就是这里的写使能信号,所以三者要同时赋值,在写使能赋值下一个时钟,读进去地址和数据锁存器里的值。
自己编写pingpang 读出ROM里1024个点,用两个64 words的RAM做乒乓读出 随着第一个数据有效信号,出现了第一个数据。 写RAM部分: 1. 初始的复位状态:写片选默认为第一个片,写地址为0; 2. 第一个数据进来,写地址判断数据有效信号自增1,由于是时钟触发,地址寄存器 出现锁存器,要到下一个时钟才递增,故地址与读入数据同步对应; 3. 当地址为最后一个地址时,实时触发一个flag,时钟采集这个flag,下一个时钟采 集到,地址回到0,此时片选RAM写使能切换到下一块RAM,如此循环反复。 读RAM部分: 1. 初始状态:默认读第一个芯片,读地址为0,写使能一直有效; 2. 时钟采集第一次写末地址的flag时,写地址使能(写地址使能不是写使能),此时 已经是写地址归0,读地址为0; 3. 写地址采集到写地址使能,此时已经是又下一个时钟,此时写地址为1,读地址自 增1,也为1,读出第一个片子的第一个数据,而第二个片子准备好了写入数据和写入数据地址,实际写入的也是第一个数据,此时读地址和写地址同步; 4. 读地址为末时,读出前一个数据,实时触发一个flag,时钟采集这个flag,下一个 时钟采集到,给读片选切换,读地址清零,保留一次片选寄存器,即在用时钟赋值片选寄存器值,此时已经过去了两个时钟,也就是说读地址为1,读出的数据为另一块片子的0地址,即首地址,实时判断片选寄存器值来选择从哪块RAM中读数据。
这里两个芯片切换,写切换的是使能切换,读切换是哪个芯片读出数据切换。写地址增加使能和数据有效同步,读地址使能要等到写到完第一个片子才有效。读写的地址都是可以复用的,用写使能和读数据确定片子。 写RAM地址和数据同步,读RAM地址比数据快一个时钟,所以读切换时多一个时钟延迟。
64个words RAM做乒乓代码: module pp64( input rst, input clk, input[15:0] din, input din_valid,
output[15:0] dout, output reg dout_valid );
parameter RAM_ADDR=64; parameter RAM_WIDTH=6;
reg wr_cs; wire wr_en_ram0; wire wr_en_ram1; reg[RAM_WIDTH-1:0] wr_addr; wire wr_addr_end;
reg rd_cs; reg rd_cs_dl; reg rd_en; reg[RAM_WIDTH-1:0] rd_addr; wire rd_addr_end; wire[15:0] data_ram0; wire[15:0] data_ram1;
always @(negedge rst,posedge clk) begin if(!rst)begin wr_cs<=1'b0; end elseif(wr_addr_end) begin wr_cs<=~wr_cs; end else begin wr_cs<=wr_cs; end end |