UDP--DDR--SFP,FPGA实现之ddr读写控制模块
DDR读写控制模块实现介绍
由于该模块接口数量较多,为了详细说明模块实现,采用文字流程进行介绍
- 上级模块传输数据到来
- 捕捉数据有效上升沿
- 传输写指令,写有效,写指令成功被下一级模块缓存,进行写地址+一次读写长度(bit为单位)
- 传递写数据,每次写完1k数据,进行size+1,记录最终的KB大小(以1K为单位),提供给读取内存模块,指示可读取范围
- 接收到地址清除信号,地址回读信号,将读写输出地址置0,地址清除信号代表上位机要重写文件,将地址置0,即可表示擦除DDR数据,即将有效地址清零,标记为无效地址块;地址回读信号,即读取内存模块成功完成一次文件读取,回到0地址,进行第二次数据读取。所谓0地址,可根据所选用的DDR起始地址设定,不一定全为0,只要是数据块的起始写入位置即可,要求固定。
- 接收到读取指令,转换为op指令,进行数据读取
DDR读写控制模块代码编写
通过文字流程描述,逻辑梳理可以将代码清晰的进行写出
module ddr_rw_control(input i_ui_clk ,input i_ui_rst ,/*ASYNC_BUF_DDR*/input [31:0] i_send_data ,input i_send_valid ,input i_read_cmd ,input i_raddr_clear ,input i_read_back ,output [15:0] o_store_size ,/*op-->axi*/output [1 :0] o_op_cmd ,output [29:0] o_op_waddr ,output [29:0] o_op_raddr ,output o_op_valid ,input i_op_ready ,output [31:0] o_write_data ,output o_write_valid ,input [31:0] i_read_data ,input i_read_valid );localparam P_ADDR = 4*256 ;reg [31:0] ri_send_data ;
reg ri_send_valid ;
reg [31:0] ri_send_data_1d ;
reg ri_send_valid_1d;
reg ri_read_cmd ;
reg [1 :0] ro_op_cmd ;
reg [29:0] ro_op_waddr ;
reg [29:0] ro_op_raddr ;
reg ro_op_valid ;
reg ri_op_ready ;
reg [31:0] ri_read_data ;
reg ri_read_valid ;
reg [15:0] ro_store_size ;
(*mark_debug = "true"*)wire w_send_pos ;
(*mark_debug = "true"*)wire w_read_pos ;
wire w_send_neg ;
assign w_send_pos = ~ri_send_valid & i_send_valid ;
assign w_send_neg = ~ri_send_valid & ri_send_valid_1d;
assign w_read_pos = ~ri_read_cmd & i_read_cmd ;
assign o_op_cmd = ro_op_cmd ;
assign o_op_waddr = ro_op_waddr ;
assign o_op_raddr = ro_op_raddr ;
assign o_op_valid = ro_op_valid ;
assign o_write_data = ri_send_data ;
assign o_write_valid = ri_send_valid ;
assign o_store_size = ro_store_size ;always @(posedge i_ui_clk,posedge i_ui_rst) beginif(i_ui_rst)ri_op_ready <= 1'b0;elseri_op_ready <= i_op_ready;
endalways @(posedge i_ui_clk,posedge i_ui_rst) beginif(i_ui_rst) beginri_send_data <= 32'd0;ri_send_valid <= 1'b0 ;ri_send_data_1d <= 32'd0;ri_send_valid_1d <= 1'b0 ;endelse beginri_send_data <= i_send_data ;ri_send_valid <= i_send_valid ;ri_send_data_1d <= ri_send_data ;ri_send_valid_1d <= ri_send_valid;end
endalways @(posedge i_ui_clk,posedge i_ui_rst) beginif(i_ui_rst)ro_store_size <= 16'h0;else if(i_raddr_clear)ro_store_size <= 16'h0;else if(w_send_neg)ro_store_size <= ro_store_size + 1'b1;
endalways @(posedge i_ui_clk,posedge i_ui_rst) beginif(i_ui_rst)ri_read_cmd <= 1'b0;elseri_read_cmd <= i_read_cmd;
endalways @(posedge i_ui_clk,posedge i_ui_rst) beginif(i_ui_rst)ro_op_cmd <= 2'b00;else if(w_send_pos)ro_op_cmd <= 2'b01;else if(w_read_pos)ro_op_cmd <= 2'b10;else if(ro_op_valid && i_op_ready)ro_op_cmd <= 2'b00;
endalways @(posedge i_ui_clk,posedge i_ui_rst) beginif(i_ui_rst)ro_op_valid <= 1'b0;else if(ro_op_valid && i_op_ready)ro_op_valid <= 1'b0;else if(~ro_op_valid && w_send_pos)ro_op_valid <= 1'b1;else if(~ro_op_valid && w_read_pos)ro_op_valid <= 1'b1;
endalways @(posedge i_ui_clk,posedge i_ui_rst) beginif(i_ui_rst)ro_op_waddr <= 'd0;else if(i_raddr_clear || i_read_back)ro_op_waddr <= 'd0;else if(ro_op_valid && i_op_ready && ro_op_cmd == 2'b01)ro_op_waddr <= ro_op_waddr + P_ADDR;
endalways @(posedge i_ui_clk,posedge i_ui_rst) beginif(i_ui_rst)ro_op_raddr <= 'd0;else if(i_raddr_clear || i_read_back)ro_op_raddr <= 'd0;else if(ro_op_valid && i_op_ready && ro_op_cmd == 2'b10)ro_op_raddr <= ro_op_raddr + P_ADDR;
endalways @(posedge i_ui_clk,posedge i_ui_rst) beginif(i_ui_rst) beginri_read_data <= 32'd0;ri_read_valid <= 1'b0 ;endelse beginri_read_data <= i_read_data ;ri_read_valid <= i_read_valid;end
endendmodule
接下来对代码中几个比较关键的讲解
首先是ro_op_waddr 和ro_op_raddr ,为什么其要在op总线信号握手成功后,再进行地址递增操作
这是参考了AXIS的涉及,ro_op_valid信号指示读写地址、指令等信息的有效,i_op_ready指示下一级模块成功接收到这些信息,如果地址与op_valid同步处理,会造成基础地址,不会被写入数据,直接是基础地址+2000了,所以要在每次握手成功后,进行地址的加操作
cmd为1表示写操作,cmd为2表示读操作
同样对于ro_store_size 这个信号,其表示缓存了多少KB,则在每次传入有效信号的下降沿进行+1,则可以表示写入了DDR多少KB,若是在上升沿操作,其理论上也不会出现问题。
关于代码的说明便介绍到这里,接下来进行仿真实验。
DDR读写控制模块仿真
即在之前章节的基础上,添加对该模块的例化即可,另外,考虑到内存块读取模块尚未实现,对于输入的read_cmd指令,笔者便先通过仿真给信号实现。完整的tb文件代码如下
module tb_module();reg i_udp_clk = 1'b0;
reg i_udp_rst = 1'b0;
reg i_ui_clk = 1'b0;
reg i_ui_rst = 1'b0;
reg i_sfp_clk = 1'b0;
reg i_sfp_rst = 1'b0;
reg [7 :0] i_udp_data = 8'd0;
reg i_udp_valid = 1'd0;
reg i_rcmd = 1'b0;
wire [7 :0] w_store_udp_data ;
wire w_store_udp_valid ;
wire w_store_done ;
wire w_raddr_clear ;
wire w_sync_clear ;
wire w_read_cmd ;
reg [31:0] r_read_data = 32'd0;
reg r_read_valid = 1'd0 ;
wire [31:0] w_send_data ;
wire w_send_valid ;
wire [1 :0] w_op_cmd ;
wire [29:0] w_op_waddr ;
wire [29:0] w_op_raddr ;
wire w_op_valid ;
wire [31:0] w_write_data ;
wire w_write_valid ;
wire [15:0] w_store_size ;integer i = 0;
integer j = 0;
always #4 i_udp_clk = ~i_udp_clk;
always #2.5 i_ui_clk = ~i_ui_clk ;
always #2 i_sfp_clk = ~i_sfp_clk;
initial begini_udp_rst = 1;i_sfp_rst = 1;i_ui_rst = 1;#100@(i_sfp_clk) begini_udp_rst <= 1'b0;i_sfp_rst <= 1'b0;i_ui_rst <= 1'b0;end#100/*传输擦除指令*/@(posedge i_udp_clk)udp_cmd(64'HD5D5D5D5_FCFCFCFC);/*传输256KB*/@(posedge i_udp_clk)for(i = 0;i < 256; i = i + 1) begin@(posedge i_udp_clk)udp_send(1024);#500@(posedge i_udp_clk);end/*传输完成指令*/@(posedge i_udp_clk)udp_cmd(64'HA5A5A5A5_BCBCBCBC);#1000@(posedge i_udp_clk)i_rcmd <= 1'b1;@(posedge i_udp_clk)i_rcmd <= 1'b0;#100@(posedge i_udp_clk)udp_cmd(64'HD5D5D5D5_FCFCFCFC);
end/*指令监测,输出监测后数据*/
udp_cmd_check udp_cmd_check_u0(.i_clk (i_udp_clk ),.i_rst (i_udp_rst ),.i_udp_data (i_udp_data ),.i_udp_valid (i_udp_valid ),.o_udp_data (w_store_udp_data ),.o_udp_valid (w_store_udp_valid ),.o_store_done (w_store_done ),.o_raddr_clear (w_raddr_clear ));/*跨时钟域处理,1Byte-->4Bytes,udp-->ddr*/
ASYNC_BUF_DDR ASYNC_BUF_DDR_U0(.i_udp_clk (i_udp_clk ),.i_udp_rst (i_udp_rst ),.i_ui_clk (i_ui_clk ),.i_ui_rst (i_ui_rst ),.i_udp_data (w_store_udp_data ),.i_udp_valid (w_store_udp_valid ),.o_send_data (w_send_data ),.o_send_valid (w_send_valid ));/*读取地址清除信号跨时钟*/
sync_s2f sync_s2f_u0(.i_clk_slow (i_udp_clk ),.i_signal (w_raddr_clear ),.i_clk_fast (i_ui_clk ),.o_sync (w_sync_clear )
);ddr_rw_control ddr_rw_control_u0(.i_ui_clk (i_ui_clk ),.i_ui_rst (i_ui_rst ),.i_send_data (w_send_data ),.i_send_valid (w_send_valid ),.i_read_cmd (i_rcmd ),.i_raddr_clear (w_sync_clear ),.i_read_back (1'b0 ),.o_store_size (w_store_size ),.o_op_cmd (w_op_cmd ),.o_op_waddr (w_op_waddr ),.o_op_raddr (w_op_raddr ),.o_op_valid (w_op_valid ),.i_op_ready (1'b1 ),.o_write_data (w_write_data ),.o_write_valid (w_write_valid ),.i_read_data (32'd0 ),.i_read_valid (1'b0 ));task udp_send(input [15:0] byte_len);begin : datainteger i;i_udp_data = 8'd0;i_udp_valid = 1'd0;@(posedge i_udp_clk);for(i = 0;i < byte_len ;i = i + 1)begini_udp_data <= i_udp_data + 1'b1;i_udp_valid <= 1'b1;@(posedge i_udp_clk);endi_udp_data <= 8'd0;i_udp_valid <= 1'd0;
end
endtasktask udp_cmd(input [63:0] i_cmd);begin : cmdinteger i;i_udp_data = 8'd0;i_udp_valid = 1'd0;@(posedge i_udp_clk);for(i = 0;i < 8 ;i = i + 1)begini_udp_data <= i_cmd[63:56];i_cmd <= {i_cmd[55:0],8'h0};i_udp_valid <= 1'b1;@(posedge i_udp_clk);endi_udp_data <= 8'd0;i_udp_valid <= 1'd0;
end
endtask
endmodule
模拟仿真的流程与前两节类似,只是在udp文件传输完成后,加入了一次读操作,观察指令输出情况,以及一次擦除指令下发,因为初始时地址为0,无法观察擦除命令是否成功执行,需要注意,此时还没有链接DDR_AXI模块,所以不会有数据读出,只是检验指令输出过程是否正确。
由下图所示,为第一帧数据传输进来,op指令进行相应转译,cmd为1,写地址为0,握手成功后,写地址+0x2000,
观察最后一帧数据传输完成,size记录为256KB,记录正确,waddr的下一次写地址为30’h0x00200000,即256X1024X8,正确,注意使用AXI控制器读写地址时,单位为bit。
观察read_cmd以及DDR擦除指令传输情况,若下图所示,成功进行了一次读取指令译码,以及当clear指令拉高时,可以看出size以及操作地址等变量成功清零。
经过上述仿真,可以看出该模块正常工作,对于该模块的编写是较为简单的,在开发中,是十分常用的模块,有必要进行掌握。关于本节代码的问题,以及优化意见,欢迎大家在评论区指出,如果想要对应工程进行学习,欢迎大家私信。
相关文章:

UDP--DDR--SFP,FPGA实现之ddr读写控制模块
DDR读写控制模块实现介绍 由于该模块接口数量较多,为了详细说明模块实现,采用文字流程进行介绍 上级模块传输数据到来捕捉数据有效上升沿传输写指令,写有效,写指令成功被下一级模块缓存,进行写地址一次读写长度&…...

云计算与大数据进阶 | 26、解锁云架构核心:深度解析可扩展数据库的5大策略与挑战(上)
在云应用/服务的 5 层架构里,数据库服务层稳坐第 4 把交椅,堪称其中的 “硬核担当”。它的复杂程度常常让人望而生畏,不少人都将它视为整个架构中的 “终极挑战”。 不过,也有人觉得可扩展存储系统才是最难啃的 “硬骨头”&#…...

AI Agent | Coze 插件使用指南:从功能解析到实操步骤
一、前言 在人工智能技术飞速发展的今天,低代码开发模式正成为构建智能应用的主流趋势。对于希望快速搭建 AI Bot 的开发者和业务人员而言,coze作为一款强大的低代码 AI 开发平台,凭借其高度模块化的插件体系脱颖而出。这些插件就像搭建智能…...
06、基础入门-SpringBoot-依赖管理特性
06、基础入门-SpringBoot-依赖管理特性 Spring Boot 的依赖管理特性是其核心优势之一,极大地简化了项目的构建和维护过程。以下是其主要特点: ## 1. 父项目依赖管理 ### 1.1 继承 spring-boot-starter-parent 在 pom.xml 文件中,通过继承 spr…...

MK米客方德SD NAND:无人机存储的高效解决方案
在无人机技术迅猛发展的当下,飞控系统的数据记录对于飞行性能剖析、故障排查以及飞行安全保障极为关键。以往,SD 卡是飞控 LOG 记录常见的存储介质,但随着技术的革新,新的存储方案不断涌现。本文聚焦于以 ESP32 芯片为主控制器的无…...

【vscode】解决vscode无法安装远程服务器插件问题,显示正在安装
文章目录 现状分析采用VSIX离线安装第一步:离线下载插件包第二步:把下载好的插件文件上传到远程服务器上第三步:在windows下打开vscode,并链接远端,进行安装 现状分析 vscode无法远程安装扩展插件,显示正在…...
1688 数据接口调用秘籍:高效获取商品实时信息的开发指南
在电商行业竞争白热化的当下,企业想要抢占市场先机,实时掌握商品信息至关重要。作为国内 B2B 电商巨头,1688 平台汇聚海量商品资源,通过高效调用其数据接口获取商品实时信息,能为企业价格策略制定、库存管理、竞品分析…...

【Spring】Spring的请求处理
欢迎来到啾啾的博客🐱。 记录学习点滴。分享工作思考和实用技巧,偶尔也分享一些杂谈💬。 欢迎评论交流,感谢您的阅读😄。 目录 引言HTTP/HTTPS协议Spring Web与Spring Web MVCSpring WebFlux 自定义的TPC/IP协议FTP、S…...

粒子群算法(PSO算法)
粒子群算法概述 1.粒子群优化算法(Particle Swarm Optimization,简称PSO)。粒子群优化算法是在1995年由Kennedy博士和Eberhart博士一起提出的,它源于对鸟群捕食行为的研究。 2.基本核心是利用群体中的个体对信息的共享从而使得整…...
git提交库常用词
新功能 feat修改BUG fix文档修改 docs格式修改 style重构 refactor性能提升 perf测试 test构建系统 build对CI配置文件修改 ci修改构建流程、或增加依赖库、工具 chore回滚版本 revert...

LLM智能体新纪元:深入解析MCP与A2A协议,赋能智能自动化协作
LLM智能体(LLM agents)是能够自主行动以实现特定目标的AI系统。在实际应用中,智能体能够将用户请求拆解为多个步骤,利用知识库或API获取数据,最终整合出答案。这让智能体相比于传统独立聊天机器人拥有更强大的能力——…...

SAP学习笔记 - 开发豆知识01 - CDS SDK命令出乱码 (cds init CAP-Test03 --add java)
1,现象 安装完VSCode以及各种需要的插件(比如SAP CDS Language Support),就可以做CAP开发。 用这个命令创建Project:cds init CAP-Test03 --add java 然后出来一个乱码错误 adding java The derived package name c…...

(C语言)超市管理系统 (正式版)(指针)(数据结构)(清屏操作)(文件读写)(网页版预告)(html)(js)(json)
目录 前言: 源代码: product.h product.c fileio.h fileio.c main.c json_export.h json_export.c tasks.json idex.html script.js 相关步骤: 第一步: 第二步: 第三步: 第四步: 第五步…...

进阶-数据结构部分:2、常用排序算法
飞书文档https://x509p6c8to.feishu.cn/wiki/FfpIwIPtviMMb4kAn3Sc40ABnUh 常用排序算法 这几种算法都是常见的排序算法,它们的优劣和适用场景如下: 冒泡排序(Bubble Sort):简单易懂,时间复杂度较高&…...
解决 Three.js Raycaster 点击位置与实际交点偏差问题
当使用 Three.js 的 Raycaster 时,如果发现点击位置与显示的碰撞点之间存在较大偏差,这通常是由于坐标系统不匹配或参数设置不正确导致的。以下是系统性的排查和解决方案: 1. 检查鼠标坐标转换 最常见的偏差原因是鼠标坐标到标准化设备坐标…...

25、DeepSeek-R1论文笔记
DeepSeek-R1论文笔记 1、研究背景与核心目标2、核心模型与技术路线3、蒸馏技术与小模型优化4、训练过程简介5、COT思维链(Chain of Thought)6、强化学习算法(GRPO)7、冷启动**1. 冷启动的目的****2. 冷启动的实现步骤****3. 冷启动…...

LeetCode --- 156双周赛
题目列表 3541. 找到频率最高的元音和辅音 3542. 将所有元素变为 0 的最少操作次数 3543. K 条边路径的最大边权和 3544. 子树反转和 一、找到频率最高的元音和辅音 分别统计元音和辅音的出现次数最大值,然后相加即可,代码如下 // C class Solution {…...
模型量化AWQ和GPTQ哪种效果好?
环境: AWQ GPTQ 问题描述: 模型量化AWQ和GPTQ哪种效果好? 解决方案: 关于AWQ(Adaptive Weight Quantization)和GPTQ(Generative Pre-trained Transformer Quantization)这两种量化方法的…...

npm 报错 gyp verb `which` failed Error: not found: python2 解决方案
一、背景 npm 安装依赖报如下错: gyp verb check python checking for Python executable "python2" in the PATH gyp verb which failed Error: not found: python2 一眼看过去都觉得是Python环境问题,其实并不是你python环境问题…...

初识Linux · IP协议· 下
目录 前言: 内网IP和公网IP 内网IP 公网IP 路由 前言: 前文我们介绍了IP协议的协议头,通过源码等方式我们理解了IP协议中的字段,比如8位协议,比如通过环回问题引出的8位最大生存时间,比如8位协议&…...
5.27本日总结
一、英语 复习list2list29 二、数学 学习14讲部分内容 三、408 学习计组1.2内容 四、总结 高数和计网明天结束当前章节,计网内容学完之后主要学习计组和操作系统 五、明日计划 英语:复习lsit3list28,完成07年第二篇阅读 数学&#…...
JavaScript基础-创建对象的三种方式
在JavaScript中,对象是构建复杂数据结构和实现面向对象编程的核心。掌握如何创建对象对于每个开发者来说都是必不可少的技能。本文将介绍创建JavaScript对象的三种主要方式:对象字面量、构造函数以及类(ES6引入),并探讨…...

JAVA的常见API文档(上)
游戏打包 注意API文档中的方法不需要记忆!! 了解之后如果需要可以查询API文档 对Math的方法总结: 运用刚学的Math方法加快代码的运行效率 可以减少循环次数 找规律: 发现因子有规律: 必定一个大于平方根,…...
JavaScript 中的 for...in 和 for...of 循环详解
在 JavaScript 中,for...in 和 for...of 是两种常用的循环结构,但它们有着不同的用途和行为。很多初学者容易混淆这两者,本文将详细解析它们的区别、适用场景以及注意事项。 目录 for…in 循环 基本用法遍历对象属性注意事项 for…of 循环 …...
AtCoder AT_abc406_c [ABC406C] ~
前言 除了 A 题,唯一一道一遍过的题。 题目大意 我们定义满足以下所有条件的一个长度为 N N N 的序列 A ( A 1 , A 2 , … , A N ) A(A_1,A_2,\dots,A_N) A(A1,A2,…,AN) 为波浪序列: N ≥ 4 N\ge4 N≥4(其实满足后面就必须满足这…...

Spark,连接MySQL数据库,添加数据,读取数据
连接数据库 可以看到shell中我们读取出的数据 在IDEA中打代码如果能输出跟shell中一样的结果即证明连接成功 【出错反思】 像我前面出错的原因就是在打代码时将密码输入错误 添加数据 读取数据就是在上面代码中一起展示了,这里我就不单独说了...
Linux容器技术详解
容器技术基础 什么是容器 容器是一种轻量级的虚拟化技术,它将应用程序及其依赖(库、二进制文件、配置文件等)打包在一个独立的单元中,可以在任何支持容器运行时的环境中一致地运行。 Docker官网:https://www.docker…...

【EDA软件】【联合Modelsim仿真使用方法】
背景 业界EDA工具仿真功能是必备的,例如Vivado自带仿真工具,且无需联合外部仿真工具,例如MoodelSim。 FUXI工具仿真功能需要联合Modelsim,才能实现仿真功能。 方法一:FUXI联合ModelSim 1 添加testbench文件 新建to…...
STM32 __main
STM32开发中__main与用户main()函数的本质区别及工作机制 在STM32开发中,__main和用户定义的main()函数是启动过程中的两个关键节点,分别承担运行时初始化和用户程序入口的职责。以下是它们的核心差异及协作机制: 一、定义与层级差异 __ma…...

【离散化 线段树】P3740 [HAOI2014] 贴海报|普及+
本文涉及知识点 C线段树 [HAOI2014] 贴海报 题目描述 Bytetown 城市要进行市长竞选,所有的选民可以畅所欲言地对竞选市长的候选人发表言论。为了统一管理,城市委员会为选民准备了一个张贴海报的 electoral 墙。 张贴规则如下: electoral…...