当前位置: 首页 > news >正文

基于FPGA的实时图像处理系统(1)——SDRAM回环测试

SDRAM回环设计

文章目录

  • SDRAM回环设计
    • 一、SDRAM简介
      • 1、引脚
      • 2、内部结构框图
      • 3、操作指令
    • 二、系统设计
    • 三、实现流程
      • 1、SDRAM接口
      • 2、FIFO设置
      • 3、内部SDRAM的控制模块
      • 4、其他
    • 四、实现效果
    • 五、总结
    • 六、代码
      • 1、top
      • 2、sdram_top
      • 3、sdram_ctrl

一、SDRAM简介

SDRAM英文全称“Synchronous Dynamic Random Access Memory”,译为“同步动态随机存取内存”或“同步动态随机存储器”,是动态随机存储器(Dynamic Random Access Memory,简称DRAM)家族的一份子。同步、动态、随机是其性能特点的外在说明,也是其区别其他存储器的特色标签。这三个概念性的标签,我们要好好理解掌握。

同步(Synchronous):与通常的异步DRAM不同, SDRAM存在一个同步接口,其工作时钟的时钟频率与对应控制器(CPU/FPGA)的时钟频率相同,并且SDRAM内部的命令发送与数据传输均以此时钟为基准,实现指令或数据的同步操作;

动态(Dynamic): SDRAM需要不断的刷新来保证存储阵列内数据不丢失;

随机(Random):数据在SDRAM中并不是按照线性依次存储,而是可以自由指定地址进行数据的读写。

空间存储量大、读写速度快以及价格相对便宜等优点使其在存储界屹立不倒、经久不衰,广泛应用在计算机中。随着时代的不断发展、技术的不断更新,SDRAM使用至今已过数十载,产品更新历经五代,分别是:第一代SDR SDRAM,第二代DDR SDRAM,第三代DDR2 SDRAM,第四代DDR3 SDRAM,第五代,DDR4 SDRAM。

第一代SDR SDRAM采用单端时钟信号,SDRAM只在时钟的上升沿进行数据采样;而后面的四代SDRAM由于工作频率比较快,所以采用可降低干扰的差分时钟信号作为同步时钟,双沿采样,速度更快,且功耗更低。同时技术的不断发展、制造工艺的不断提高,使得五代SDRAM的更新过程中,集成度越来越高、内核电压越来越低(SDR:3.3V 、DDR:2.5V、DDR2:1.8V、DDR3:1.5V、DDR4:1.2V),这也是SDRAM速度提高、功耗降低的重要原因。

本次运用的SDRAM为海力士公司的H57V2562GTR-75C,内存大小为256Mbit,有4个bank,每个bank有4M(8192行*512列)存储单元,每个单元可存16bit数据

1、引脚

信号类型描述
clkin时钟,所有其他输入在CLK的上升沿被寄存到SDRAM
ckein时钟使能,控制内部时钟信号,当禁用时,SDRAM将处于电源关闭、暂停或自刷新状态之一
cs_nin片选,启用或禁用除CLK、CKE和DQM之外的所有输入
BA0,BA1inbank地址线
A0-A12in行列地址线,行地址:RA0 ~ RA12,列地址:CA0 ~ CA8自动预充电标志:A10
RAS_n,CAS_n,WE_Nin行地址选通,列地址选通,写使能
LDQM,UDQMI/O数据掩码,16位高低字节,可控制读写数据
DQ0-DQ15I/O数据输入输出

2、内部结构框图

在这里插入图片描述
由图可知,SDRAM内部包含一个状态机左上角state machine),外部通过控制CS_N、RAS_N、CAS_N、WE_N、A0-A12数据地址线以及BA0、BA1 BANK地址线来发送命令,命令经过解码器进行译码后,将控制参数保存到模式寄存器中,逻辑控制单元进而控制逻辑运行。

外部通过地址总线输入地址信息,地址信息在逻辑控制单元进行逻辑控制时起到辅助作用,除此之外,复用的地址总线与Bank控制逻辑、行地址复用器、列地址计数锁存器、列地址解码器等内部器件共同作用,精确选定存储阵列中与行列地址相对应的存储单元,进而进行数据存取操作。

DQM数据掩码线控制这数据是否有效,其又L低位与U高位两条线,每条控制着8bit数据。

DQ0-DQ15为数据线,其为双向,读写共用一条线。

3、操作指令

在这里插入图片描述

1、预充电(precharge)

预充电命令:关闭特定bank中激活的行,或关闭所有bank中激活的行。

A10决定预充电模式:

当预充电命令中的地址A10为高时,预充电所有bank;当预充电命令中A10为低时,预充电特定bank。

当write/read命令中的A10为高时,自动预充电(auto-precharge)被使能;反之。

预充电命令发送之后,这些bank等待tRP才能接收命令

2、自动预充电(auto-precharge)

自动预充电是非显示命令,即使能自动预充电是需要发送write/read命令时将地址中A10拉高,在读写

突发结束后,立即预充电那个bank/row。

3、NOP

NOP 指令用以表明对 sdram 芯片(CS# == 0)进行空操作。NOP 指令的目的是在 sdram 在空闲

或者等待状态下,避免去执行一些潜在的不需要的指令。已经在执行过程中的指令不受影响。

4、自动刷新(auto-refresh)与自刷新(self-refresh)

为使数据不丢失,电容的两次刷新时间不能超过64ms,刷新都是针对行的。共性:都不需要外部提供地址信息,SDRAM内部有一个行地址生成器(刷新计数器)。刷新都是针对

一行的,不需要对列地址寻址,但也不需要对行进行寻址,因为内部有刷新计数器

自动刷新:SDRAM正常工作模式中为了数据不丢失进行的操作,需要外部时钟参与,刷新的行地址也

是由内部刷新计算器控制

自刷新:休眠模式低功耗状态下存储数据,不需要外部时钟参与,刷新的行地址内部刷新计算器控

制。

发送自动刷新命令需要的时间为tRRC(自动刷新周期),由于是对行操作,等效于行选通时间(RAS)

SDRAM中每次刷新操作所需要的时间为自动刷新周期(tRC),在自动刷新指令发出后需要等待tRC才能发

送其他指令。

5、行激活

行激活命令也叫做bank激活命令,作用是在指定bank中激活一行;

行激活后会一直处于激活状态(即列寻址处于激活状态),直到预充电命令被发送到这个bank;

行激活命令之后,需要延时tRCD(即发出行地址到发出列地址的时间间隔),才能发送READ/WRITE命令(读写操作必须先激活对应bank)

6、读操作

读数据命令用来开启数据的突发读,bank,row都可选,注意A10的值决定是否执行自动预充电操作,若执行自动预充电,突发读结束后就进行预充电,此行关闭,若不执行自动预充电,该行保持激活,仍能被访问。

CAS latency :读延迟(读潜伏周期,CL)Burst length:突发长度(BL)

读命令发出后,输出buffer(理解为SDRAM的dq_out)会在(CL-1)个时钟后期后变为低阻,然后会在突发读结束后重新变为高阻态,

7、写操作

DM(数据掩码)高有效,当为低时,数据能正确被写入DM;当为高时,数据将被忽略。

写突发时,第一个数据与写命令同步;

突发写–>预充电中间需要间隔tDPL。

二、系统设计

在这里插入图片描述
所实现功能 :pc发送数据,存入fifo的数据达到所设阈值,进行突发写操作(此处用的ip核不支持多bit突发读写操作,故在控制模块中实现突发读写操作),当按键(经过消抖)按下,进行突发读操作,将读取的数据发送回pc显示出来。

三、实现流程

1、SDRAM接口

在这里插入图片描述

SDRAM接口部分由ip核实现
1) 选择Platform Designer
在这里插入图片描述
2) 在左上角处搜索sdram,在下方双击选中ip添加
在这里插入图片描述
3) 配置各个参数
在这里插入图片描述
本次运用的SDRAM的数据宽度为16bit,有4个bank,每个bank有13行9列

在这里插入图片描述

参数含义典型值意义
CAS latency cycles读命令发出后,到第一个有效数据出现在总线上的时钟周期数设为 3 → 3 个时钟
Initialization refresh cycles上电后、正式初始化前,控制器自动发出的 Auto-Refresh 命令次数8 次
Issue one refresh command every两次刷新命令之间的间隔时间7.8 µs(SDRAM 要求 64 ms 内刷完所有行,因此 7.8 µs/行≈8192 行)
Delay after powerup, before initialization芯片上电稳定后再开始初始化的等待时间200 µs(JEDEC 规范建议 ≥100 µs)
Duration of refresh command (t_rfc)单个 Auto-Refresh 命令占用总线的最短时间70 ns
Duration of precharge command (t_rp)关闭当前行(Precharge)所需时间20 ns
ACTIVE to READ or WRITE delay (t_rcd)行激活到列读/写命令之间的最小间隔20 ns
Access time (t_ac)时钟沿到数据有效输出的延迟(器件参数,非用户设)5 ns
Write recovery time (t_wr)写命令结束后到允许 Precharge 的最小间隔20 ns

配置完如下

在这里插入图片描述
4) 点击右下角finish左边按钮出现以下界面

在这里插入图片描述
改为生成verilog代码,路径自行选择,更改完成点击生成,等待完成,等待时间因电脑配置有差异

在这里插入图片描述

生成完成,依次点击close、finish

5) finish后出现以下界面提示添加文件

在这里插入图片描述
添加完成在ip查看界面才会有显示

在这里插入图片描述

生成的例化模板:

	sdram_ip u0 (.clk_clk           (), //   clk.clk.reset_reset_n     (), // reset.reset_n.sdram_addr        (), // sdram.addr.sdram_ba          (), //      .ba.sdram_cas_n       (), //      .cas_n.sdram_cke         (), //      .cke.sdram_cs_n        (), //      .cs_n.sdram_dq          (), //      .dq.sdram_dqm         (), //      .dqm.sdram_ras_n       (), //      .ras_n.sdram_we_n        (), //      .we_n.avs_address       (), //   avs.address.avs_byteenable_n  (), //      .byteenable_n.avs_chipselect    (), //      .chipselect.avs_writedata     (), //      .writedata.avs_read_n        (), //      .read_n.avs_write_n       (), //      .write_n.avs_readdata      (), //      .readdata.avs_readdatavalid (), //      .readdatavalid.avs_waitrequest   () //      .waitrequest);
端口名称方向位宽含义说明
clk_clkinput1全局系统时钟,用于 SDRAM 控制器内部逻辑以及 SDRAM 芯片。
reset_reset_ninput1全局异步复位,低有效。
sdram_addr[12:0]output13SDRAM 地址总线,行列地址复用。
sdram_ba[1:0]output2Bank 地址,选择 SDRAM 的 4 个 bank。
sdram_cas_noutput1列地址选通,低有效。
sdram_ckeoutput1时钟使能,高时 SDRAM 响应时钟。
sdram_cs_noutput1片选,低有效。
sdram_dq[15:0]inout16双向数据总线。
sdram_dqm[1:0]output2数据掩码/字节使能,对应 16bit 数据的高低字节。
sdram_ras_noutput1行地址选通,低有效。
sdram_we_noutput1写使能,低有效。
avs_address[21:0]input22Avalon-MM 总线地址(字节地址)。
avs_byteenable_n[1:0]input2字节使能,低有效,对应 16bit 数据高低字节。
avs_chipselectinput1Avalon-MM 片选,高有效。
avs_writedata[15:0]input16写数据。
avs_read_ninput1读请求,低有效。
avs_write_ninput1写请求,低有效。
avs_readdata[15:0]output16读回数据。
avs_readdatavalidoutput1读数据有效指示,高有效。
avs_waitrequestoutput1控制器忙,拉低时表示需要等待。

sdram前缀为输出给sdram芯片的接口,avs前缀为内部的控制的Avalon协议接口。

2、FIFO设置

//---------<写FIFO例化>------------------------------------------------- wr_fifo	wr_fifo_inst (.aclr       ( ~rst_n        ),.data       ( {2{rx_data}}  ),.rdclk      ( clk           ),.rdreq      ( wr_rden       ),.wrclk      ( clk_in        ),.wrreq      ( wr_wren       ),.q          ( wr_q          ),.rdempty    ( wr_rdempty    ),.rdusedw    ( wr_rdusedw    ),.wrfull     ( wr_wrfull     ));assign  wr_wren = ~wr_wrfull && rx_vld;
assign  wr_rden = ~wr_rdempty && (state_c == WRITE) && ~avm_waitrequest;

由于所设置SDRAM宽度为16,但uart_rx传入为8bit,所以拼两个传入的数据存入SDRAM。

写使能(wr_wren):fifo未满且rx传入的数据有效,就将数据写入fifo
读使能(wr_rden):fifo不空且处于写状态,且sdram处于不忙状态(waitrequest为低)将数据传给sdram

//---------<读FIFO例化>------------------------------------------------- rd_fifo	rd_fifo_inst (.aclr       ( ~rst_n        ),.data       ( avm_readdata  ),.rdclk      ( clk_out       ),.rdreq      ( rd_rden       ),.wrclk      ( clk           ),.wrreq      ( rd_wren       ),.q          ( rd_q          ),.rdempty    ( rd_rdempty    ),.wrfull     ( rd_wrfull     )
);assign  rd_wren = ~rd_wrfull && avm_readdatavalid;
assign  rd_rden = ~rd_rdempty && tx_done;

写使能(rd_wren):fifo未满且sdram处于不忙状态(waitrequest为低)将数据传给读fifo
读使能(rd_rden):fifo不空且tx发送模块不忙,将数据传给tx发送到pc

3、内部SDRAM的控制模块

在这里插入图片描述
由于uart时钟与sdram的时钟不同,这里用了两个异步fifo,一个用于写,一个用于读;wrfifo写侧为uart_rx输入的系统时钟,即为clk_in,读侧为输出到sdram的时钟,为clk_100m;rdfifo写侧为sdram传出的数据,时钟为clk_100m,读侧为通过uart_tx传回pc的数据接口,时钟为系统时钟。

在此设置一个简单的状态机实现读写操作,此处的burst_lenth为 10。

//---------<突发计数器>------------------------------------------------- always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_burst <= 'd0;end else if(add_cnt_burst)begin if(end_cnt_burst)begin cnt_burst <= 'd0;endelse begin cnt_burst <= cnt_burst + 1'b1;end end
end assign add_cnt_burst = ((state_c == READ) || (state_c == WRITE)) && ~avm_waitrequest;
assign end_cnt_burst = add_cnt_burst && cnt_burst == (BURST_LENTH-1);

在这里插入图片描述
当按键按下进入读数据状态,开始从sdram读取数据,当读fifo中读了10个数据时跳出。
当写fifo的数据大于所设突发操作的阈值,就进行写入操作,跳转到write状态,将10个数据写入sdram,写完10个后跳到空闲状态。

读写地址通过计数器实现

//---------<读写地址>------------------------------------------------- 
//写地址计数
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginwr_addr <= 'd0;end else if(add_wr_addr)begin if(end_wr_addr)begin wr_addr <= 'd0;endelse begin wr_addr <= wr_addr + 1'b1;end end
end assign add_wr_addr = (state_c == WRITE) && ~avm_waitrequest;
assign end_wr_addr = add_wr_addr && wr_addr == 24'hff_ff_ff-1;//读地址计数
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginrd_addr <= 'd0;end else if(add_rd_addr)begin if(end_rd_addr)begin rd_addr <= 'd0;endelse begin rd_addr <= rd_addr + 1'b1;end end
end assign add_rd_addr = (state_c == READ) && ~avm_waitrequest;
assign end_rd_addr = add_rd_addr && rd_addr == 24'hff_ff_ff-1;

由于地址线共用,所以要判断现在是读状态还是写状态

//---------<状态判断>------------------------------------------------- 
assign  avm_address = (state_c == WRITE) ?  {wr_addr[23],wr_addr[21:9],wr_addr[22],wr_addr[8:0]} : {rd_addr[23],rd_addr[21:9],rd_addr[22],rd_addr[8:0]} ;

其他输出

assign  tx_data = rd_q [7:0];
assign  tx_vld  = rd_rden;
assign  avm_writedata = wr_q;
assign  avm_read_n = ~(state_c == READ);
assign  avm_write_n = ~(state_c == WRITE);

4、其他

其他模块复用之前的。

四、实现效果

在这里插入图片描述
直接按下按键读出错乱的数据,按下复位,发送数据,将数据写入sdram

在这里插入图片描述
按下两次按键读出数据

在这里插入图片描述
读出的20个数据与发送的前20个相同,验证成功。

五、总结

相较于之前的几个存储器来说,sdram是并行的,且有其他的各种信号,端口较多比较复杂,且内部要用avalon协议传输数据,连线和数据之间的传输较为复杂,需要认真理解,本实验主要目的为理解sdram的操作和工作原理。

六、代码

1、top

/*******************************************************************
Engineer: Turing_kun
Create Date: 2025-07-30 14:03:14
Description: 项目顶层
********************************************************************/module top (input               clk             ,input               rst_n           ,input    [1:0]      sw              ,
//---------<sdram>------------------------------------------------- output   [12:0]     sdram_addr      ,output   [1:0]      sdram_ba        ,output              sdram_cas_n     ,output              sdram_cke       ,output              sdram_cs_n      ,inout    [15:0]     sdram_dq        ,output   [1:0]      sdram_dqm       ,output              sdram_ras_n     ,output              sdram_we_n      ,output              sdram_clk       ,
//---------<uart>------------------------------------------------- input               rx              ,output              tx              ,
//---------<key>------------------------------------------------- input    [0:0]      key_in
);wire            clk_100ms;
wire            clk_100ms_s;
wire            locked;//---------<uart_rx>------------------------------------------------- 
wire    [7:0]   rx_data;
wire            rx_vld;
//---------<uart_tx>------------------------------------------------- 
wire    [7:0]   tx_data;
wire            tx_vld;
wire            tx_done;
//---------<key>-------------------------------------------------
wire            key_down; assign sdram_clk = clk_100ms_s;
sdram_top   inst_sdram_top(.clk        (clk_100ms  ),.clk_in     (clk        ),.clk_out    (clk        ),.rst_n      (rst_n      ),.rx_data    (rx_data    ),.rx_vld     (rx_vld     ),.tx_done    (tx_done    ),.tx_data    (tx_data    ),.tx_vld     (tx_vld     ),.key_down   (key_down   ),.sdram_addr (sdram_addr ),.sdram_ba   (sdram_ba   ),.sdram_cas_n(sdram_cas_n),.sdram_cke  (sdram_cke  ),.sdram_cs_n (sdram_cs_n ),.sdram_dq   (sdram_dq   ),.sdram_dqm  (sdram_dqm  ),.sdram_ras_n(sdram_ras_n),.sdram_we_n (sdram_we_n )
);sdram_pll	sdram_pll_inst (.areset ( ~rst_n ),.inclk0 ( clk ),.c0     ( clk_100ms    ),.c1     ( clk_100ms_s   ),.locked ( locked ));uart_rx     inst_uart_rx(.clk     (clk     ),.rst_n   (rst_n   ),.rx      (rx      ),.sw      (sw      ),.rx_data (rx_data ),.rx_done (rx_vld  )
);uart_tx     inst_uart_tx(.clk     (clk     ),.rst_n   (rst_n   ),.tx_data (tx_data ),.tx_start(tx_vld  ),.sw      (sw      ),.tx      (tx      ),.tx_done (tx_done )
);fsm_key     inst_fsm_key(.clk		(clk    ),.rst_n	    (rst_n	),.key_in	    (key_in	),.key_down   (key_down)
);
endmodule

2、sdram_top

/*******************************************************************
Engineer: Turing_kun
Create Date: 2025-07-30 14:02:40
Description: SDRAM子顶层
********************************************************************/module sdram_top( input               clk             ,   //100mHzinput               clk_in          ,   //50mHzinput               clk_out         ,   //50mHzinput               rst_n           ,
//---------<uart_rx>------------------------------------------------- input    [7:0]      rx_data         ,input               rx_vld          ,
//---------<uart_tx>------------------------------------------------- input               tx_done         ,output   [7:0]      tx_data         ,output              tx_vld          ,
//---------<key>------------------------------------------------- input               key_down        ,
//---------<sdram_ip>-------------------------------------------------      output   [12:0]     sdram_addr      ,output   [1:0]      sdram_ba        ,output              sdram_cas_n     ,output              sdram_cke       ,output              sdram_cs_n      ,inout    [15:0]     sdram_dq        ,output   [1:0]      sdram_dqm       ,output              sdram_ras_n     ,output              sdram_we_n      
);wire    [23:0]    avm_address           ;
wire    [15:0]    avm_writedata         ;
wire              avm_read_n            ;
wire              avm_write_n           ;
wire    [15:0]    avm_readdata          ;
wire              avm_readdatavalid     ;
wire              avm_waitrequest       ;sdram_ctrl      inst_sdram_ctrl(.clk              (clk              ),.clk_in           (clk_in           ),.clk_out          (clk_out          ),.rst_n            (rst_n            ),.rx_data          (rx_data          ),.rx_vld           (rx_vld           ),.tx_done          (tx_done          ),.tx_data          (tx_data          ),.tx_vld           (tx_vld           ),.key_down         (key_down         ),.avm_address      (avm_address      ),.avm_writedata    (avm_writedata    ),.avm_read_n       (avm_read_n       ),.avm_write_n      (avm_write_n      ),.avm_readdata     (avm_readdata     ),.avm_readdatavalid(avm_readdatavalid),.avm_waitrequest  (avm_waitrequest  )
);sdram_ip        inst_sdram_ip(.avs_address      (avm_address      ),      .avs_byteenable_n (2'b00            ), .avs_chipselect   (1'b1             ),   .avs_writedata    (avm_writedata    ),    .avs_read_n       (avm_read_n       ),       .avs_write_n      (avm_write_n      ),      .avs_readdata     (avm_readdata     ),     .avs_readdatavalid(avm_readdatavalid),.avs_waitrequest  (avm_waitrequest  ),  .clk_clk          (clk              ),          .reset_reset_n    (rst_n            ),    .sdram_addr       (sdram_addr       ),       .sdram_ba         (sdram_ba         ),         .sdram_cas_n      (sdram_cas_n      ),      .sdram_cke        (sdram_cke        ),        .sdram_cs_n       (sdram_cs_n       ),       .sdram_dq         (sdram_dq         ),         .sdram_dqm        (sdram_dqm        ),        .sdram_ras_n      (sdram_ras_n      ),      .sdram_we_n       (sdram_we_n       ) 
);    endmodule

3、sdram_ctrl

/*******************************************************************
Engineer: Turing_kun
Create Date: 2025-07-30 14:05:40
Description: SDRAM控制模块
********************************************************************/module sdram_ctrl #(parameter BURST_LENTH = 10)(input               clk                 ,   //100mHzinput               clk_in              ,   //50mHzinput               clk_out             ,   //50mHzinput               rst_n               ,
//---------<uart_rx>---------------------------------input    [7:0]      rx_data             ,input               rx_vld              ,
//---------<uart_tx>---------------------------------input               tx_done             ,output   [7:0]      tx_data             ,output              tx_vld              ,
//---------<key>-------------------------------------input               key_down            ,
//---------<sdram_ip>------------------------------------------------- output    [23:0]    avm_address         ,      output    [15:0]    avm_writedata       ,    output              avm_read_n          ,output              avm_write_n         ,input     [15:0]    avm_readdata        ,input               avm_readdatavalid   ,input               avm_waitrequest     
);//rd_fifo
wire                    rd_rden     ;
wire                    rd_wren     ;
wire        [15:0]      rd_q        ;
wire                    rd_rdempty  ;
wire                    rd_wrfull   ;//wr_fifo
wire                    wr_rden     ;
wire                    wr_wren     ;
wire        [15:0]      wr_q        ;
wire                    wr_rdempty  ;
wire                    wr_wrfull   ;
wire        [8:0]       wr_rdusedw  ;//---------<状态参数>------------------------------------------------- reg     [1:0]   state_c ;
reg     [1:0]   state_n ;localparam              IDLE    =       2'd0,READ    =       2'd1,WRITE   =       2'd2,DONE    =       2'd3;wire                    IDLE_2_READ;
wire                    READ_2_DONE;
wire                    IDLE_2_WRITE;
wire                    WRITE_2_DONE;reg		[8:0]	cnt_burst	    ;
wire			add_cnt_burst   ;
wire			end_cnt_burst   ;//写地址
reg		[23:0]	wr_addr	   ;
wire			add_wr_addr;
wire			end_wr_addr;
//读地址
reg		[23:0]	rd_addr	   ;
wire			add_rd_addr;
wire			end_rd_addr;//---------<读FIFO例化>------------------------------------------------- rd_fifo	rd_fifo_inst (.aclr       ( ~rst_n        ),.data       ( avm_readdata  ),.rdclk      ( clk_out       ),.rdreq      ( rd_rden       ),.wrclk      ( clk           ),.wrreq      ( rd_wren       ),.q          ( rd_q          ),.rdempty    ( rd_rdempty    ),.wrfull     ( rd_wrfull     )
);assign  rd_wren = ~rd_wrfull && avm_readdatavalid;
assign  rd_rden = ~rd_rdempty && tx_done;//---------<写FIFO例化>------------------------------------------------- wr_fifo	wr_fifo_inst (.aclr       ( ~rst_n        ),.data       ( {2{rx_data}}  ),.rdclk      ( clk           ),.rdreq      ( wr_rden       ),.wrclk      ( clk_in        ),.wrreq      ( wr_wren       ),.q          ( wr_q          ),.rdempty    ( wr_rdempty    ),.rdusedw    ( wr_rdusedw    ),.wrfull     ( wr_wrfull     ));assign  wr_wren = ~wr_wrfull && rx_vld;
assign  wr_rden = ~wr_rdempty && (state_c == WRITE) && ~avm_waitrequest;//---------<突发计数器>------------------------------------------------- always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_burst <= 'd0;end else if(add_cnt_burst)begin if(end_cnt_burst)begin cnt_burst <= 'd0;endelse begin cnt_burst <= cnt_burst + 1'b1;end end
end assign add_cnt_burst = ((state_c == READ) || (state_c == WRITE)) && ~avm_waitrequest;
assign end_cnt_burst = add_cnt_burst && cnt_burst == (BURST_LENTH-1);//---------<state>------------------------------------------------- //第一段:同步时序描述状态转移
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginstate_c <= IDLE;end else begin state_c <= state_n;end 
end//第二段:组合逻辑判断状态转移条件,描述状态转移规律
always @(*) begincase(state_c)IDLE  : beginif(IDLE_2_READ)state_n = READ;else if(IDLE_2_WRITE)state_n = WRITE;else state_n = state_c;endREAD  : state_n = (READ_2_DONE ) ? DONE : state_c;WRITE : state_n = (WRITE_2_DONE) ? DONE : state_c;DONE  : state_n = IDLE;default : state_n = IDLE;endcase
endassign      IDLE_2_READ     =   (state_c == IDLE ) && key_down;
assign      READ_2_DONE     =   (state_c == READ ) && end_cnt_burst;
assign      IDLE_2_WRITE    =   (state_c == IDLE ) && wr_rdusedw >= BURST_LENTH;
assign      WRITE_2_DONE    =   (state_c == WRITE) && end_cnt_burst;//---------<读写地址>------------------------------------------------- 
//写地址计数
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginwr_addr <= 'd0;end else if(add_wr_addr)begin if(end_wr_addr)begin wr_addr <= 'd0;endelse begin wr_addr <= wr_addr + 1'b1;end end
end assign add_wr_addr = (state_c == WRITE) && ~avm_waitrequest;
assign end_wr_addr = add_wr_addr && wr_addr == 24'hff_ff_ff-1;//读地址计数
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginrd_addr <= 'd0;end else if(add_rd_addr)begin if(end_rd_addr)begin rd_addr <= 'd0;endelse begin rd_addr <= rd_addr + 1'b1;end end
end assign add_rd_addr = (state_c == READ) && ~avm_waitrequest;
assign end_rd_addr = add_rd_addr && rd_addr == 24'hff_ff_ff-1;//---------<tx_data tx_vld>------------------------------------------------- 
assign  tx_data = rd_q [7:0];
assign  tx_vld  = rd_rden;//---------<状态判断>------------------------------------------------- 
assign  avm_address = (state_c == WRITE) ?  {wr_addr[23],wr_addr[21:9],wr_addr[22],wr_addr[8:0]} : {rd_addr[23],rd_addr[21:9],rd_addr[22],rd_addr[8:0]} ;assign  avm_writedata = wr_q;
assign  avm_read_n = ~(state_c == READ);
assign  avm_write_n = ~(state_c == WRITE);
endmodule

其他复用之前的项目

http://www.dtcms.com/a/334516.html

相关文章:

  • python---异常处理
  • Redis知识整理
  • 【论文笔记】STORYWRITER: A Multi-Agent Framework for Long Story Generation
  • 云服务平台主流架构的相关知识体系剖析
  • ABM和强化学习-2015年全国大学生数学建模竞赛B题
  • 安卓11 12系统修改定制化_____修改系统 解锁system分区 去除data加密 自由删减系统应用
  • JetPack系列教程(七):Palette——让你的APP色彩“飞”起来!
  • sql链接的url中serverTimezone的作用
  • 【大模型微调系列-04】 神经网络基础与小项目实战
  • windows环境下使用vscode以及相关插件搭建c/c++的编译,调试环境
  • GIMP:功能强大的跨平台图像处理软件
  • 嵌入式硬件篇---电容本质
  • leetcodehot100 矩阵置零
  • Jenkins安装部署(Win11)和常见配置镜像加速
  • B3837 [GESP202303 二级] 画三角形
  • csrf攻击
  • 11、软件需求工程
  • AMD Ryzen AI Max+ 395四机并联:大语言模型集群推理深度测试
  • 智能二维码刷卡人脸识别梯控控制器硬件规格书​
  • 【C++】高效资源管理四剑客:RVO、NRVO、std::move、RAII 深度解析
  • 【3D重建技术】如何基于遥感图像和DEM等数据进行城市级高精度三维重建?
  • 【Vibe Coding 工程之 StockAnalyzerPro 记录】- EP3.Phase 2股票列表管理功能
  • Font shape `TU/ptm/m/n‘ undefined(Font) using `TU/lmr/m/n‘ instead
  • UE5多人MOBA+GAS 45、制作冲刺技能
  • Business Magic
  • [创业之路-550]:公司半年度经营分析会 - 解决方案汇总
  • 【Java web】Servlet 详解
  • Linux -- 文件【下】
  • MATLAB R2010b系统环境(二)MATLAB环境的准备
  • 基于Transformer的机器翻译——模型篇