基于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.pswp.cn/news/919046.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/919046.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一键检测接口是否存活:用 Python/Shell 写个轻量级监控脚本

网罗开发&#xff08;小红书、快手、视频号同名&#xff09;大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等方…

优秀工具包-Hutool工具详解

优秀工具包-Hutool工具详解 课程概述 Hutool简介 定位&#xff1a; 小而全的Java工具库&#xff0c;简化开发流程。对文件、流、加密解密、转码、正则、线程、XML等JDK方法进行封装。 核心优势&#xff1a;零依赖、高性能、中文网页完善。 应用场景&#xff1a;Web开发、数…

《深度解构:构建浏览器端Redis控制台的WebSocket协议核心技术》

Redis作为高性能的内存数据库,其原生客户端多依赖命令行或桌面应用,而浏览器端控制台的缺失,成为制约Web化管理的关键瓶颈,WebSocket协议的出现,打破了HTTP协议单向通信的局限,为浏览器与Redis服务之间建立持久、双向的实时连接提供了可能。本文将从协议本质、交互逻辑、…

Pushgateway安装和部署,以及对应Prometheus调整

目录Pushgateway简介安装验证Prometheus的配置&#xff1a;其它命令Pushgateway简介 Pushgateway 是 Prometheus 生态系统中的一个组件。主要特点是推送而非拉取&#xff1a;Prometheus 默认采用拉取&#xff08;pull&#xff09;模式收集指标&#xff0c;但 Pushgateway 允许…

JAVA面试汇总(四)JVM(一)

久违的重新写了一篇面试汇总的&#xff0c;关于JVM的一篇&#xff0c;一共三篇&#xff0c;今天写了第一篇&#xff0c;继续重新学习&#xff0c;重新卷起来&#xff0c;come on baby 1.什么情况下会触发类的初始化&#xff1f; &#xff08;1&#xff09;首先是类未被初始化时…

Agent中的memory

rag系列文章目录 文章目录rag系列文章目录前言一、Memory机制作用二、memory分类三、langgraph实践总结前言 众所周知&#xff0c;大模型是无状态的。但是基于大模型的agent一般是有状态的&#xff0c;也就是它有记忆功能。在AI Agent框架中&#xff0c;Memory机制是核心组件之…

AI与IT从业者的未来:替代焦虑还是协作革命?

​​引言&#xff1a;技术渗透与核心命题​​2025年&#xff0c;人工智能技术已从实验室走向产业核心。国务院《关于深入实施“人工智能”行动的意见》推动AI在医疗、制造、金融等领域的规模化落地&#xff0c;全球AI应用用户规模突破2.3亿&#xff0c;生成式AI工具渗透率达16.…

手机版碰一碰发视频系统批量剪辑功能开发,支持OEM贴牌

引言在当今短视频盛行的时代&#xff0c;视频内容的快速生产与分享变得愈发重要。手机版碰一碰发视频系统&#xff0c;借助 NFC 等近场通信技术&#xff0c;实现了便捷的数据交互与视频分享&#xff0c;而在此基础上集成的批量剪辑功能&#xff0c;更是为内容创作者和商家带来了…

Spring AMQP如何通过配置文件避免硬编码实现解耦

在使用Spring AMQP基于注解声明监听者时&#xff0c;可通过抽取常量来避免硬编码&#xff1a;RabbitListener(bindings QueueBinding(exchange Exchange(MQConstant.USER_EXCHANGE),value Queue(MQConstant.USER_QUEUE),key MQConstant.USER_REDIS_BINDING))public void de…

解决zabbix图片中文乱码

要把 Zabbix 前端字体替换为 simkai.ttf&#xff08;楷体&#xff0c;解决乱码常用&#xff09;&#xff0c;按以下步骤操作&#xff1a;1. 确认 simkai.ttf 路径 先找到系统里 simkai.ttf 字体文件&#xff0c;若没有&#xff0c;可从 Windows 系统&#xff08;C:\Windows\Fon…

实例分割-动手学计算机视觉13

介绍 实例分割(instance segmentation)的目的是从图像中分割出每个目标实例的掩模(mask)。与语义分割相比&#xff0c;实例分割不但要区分不同的类别&#xff0c;还要区分出同一种类别下的不同目标实例。如图13-1所示 语义分割的结果中&#xff0c;不同的羊对应的标签是一样的…

水环境遥感分析!R语言编程+多源遥感数据预处理;水体指数计算、水深回归分析、水温SVM预测、水质神经网络建模及科研级可视化制图

系统性地整合R语言编程、遥感数据处理及机器学习建模&#xff0c;涵盖水线提取&#xff08;水体指数与阈值法&#xff09;、水深反演&#xff08;多元回归&#xff09;、水温预测&#xff08;支持向量机&#xff09;、水质评估&#xff08;神经网络&#xff09;等核心内容&…

微信公众号/小程序百万级OpenID自动化获取工具

摘要 本报告详细阐述了微信用户列表数据获取与处理工具的设计思路,包括分页处理机制、频率控制策略、断点续传功能和分布式存储方案。针对微信API调用限制和用户数据规模特点,该工具旨在高效、安全地获取和存储微信用户列表数据,同时严格遵守微信API调用频率限制,确保系统…

物联网系统中传感器到网关到物联网平台的传输路径、协议、原理、用途与架构详解

摘要物联网&#xff08;IoT&#xff09;系统通过传感器、网关和物联网平台实现数据的采集、传输、处理和应用。本文详细分析了传感器到网关再到物联网平台的传输路径&#xff0c;涵盖直接连接、网关中继、边缘计算、多级网关和混合路径五种方式&#xff1b;介绍了短距离&#x…

SpringBoot自动注入配置类初步实现

一.SpringBoot自动装配SpringBoot 的 自动装配&#xff08;Auto-Configuration&#xff09; 是它的核心特性之一&#xff0c;它让开发者可以 "开箱即用"&#xff0c;避免手动配置大量的 XML 或 Java Config。它的核心思想是&#xff1a;"约定优于配置"&…

直播预告|鸿蒙生态中的AI新玩法

想知道鸿蒙生态里 AI 能玩出啥新花样&#xff1f; 8 月 14 日&#xff08;周四&#xff09;20:00 &#xff0c;「开发者・面对面 坚果派特辑 —— 鸿蒙生态中的 AI 新玩法」直播来袭&#xff01; &#x1f50d; 直播亮点抢先看 AI赋能鸿蒙产品开发&#xff1a;将分享如何利用AI…

智能合约:区块链时代的“数字契约革命”

一、技术原理与核心特征1. 定义与本质智能合约是运行在区块链上的自动化程序&#xff0c;通过代码定义业务规则&#xff0c;在预设条件满足时自动执行操作&#xff08;如资金转移、信息更新&#xff09;&#xff0c;无需人工干预。其核心特性包括&#xff1a;自动执行&#xff…

【数据分析】比较SparCC、Pearson和Spearman相关性估计方法在合成组学数据上的表现

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍 加载R包 模拟数据 构建网络 RMSE指数计算 画图 总结 系统信息 介绍 在生物信息学和生态学研究中,组学数据的分析越来越依赖于对微生物群落或基因表达数据中物种或基因间相关性的…

Google C++ 风格指南

文章目录背景介绍风格指南的目标C 版本头文件自包含头文件#define 防护包含所需内容前置声明在头文件中定义函数头文件包含顺序与命名规范作用域命名空间内部链接非成员函数、静态成员函数与全局函数局部变量静态与全局变量关于析构的决策关于初始化的决策常见模式thread_local…

安装部署_WVP流媒体

文章目录一、DEV_WVP流媒体开发手册1、搭建流媒体服务clone代码&#xff1a;安装编译器cmake构建和编译项目修改配置文件启动项目2、搭建GB28181协议视频平台安装 jdk, nodejs, maven, git安装redis安装postgresqlclone代码编译前端代码编译后端代码配置文件修改3、设备接入测测…