Altera PCI IP target设计分享

最近调试也有关于使用Altera 家的PCI IP,然后分享一下代码:

主要实现:主控作为主设备,FPGA作为从设备,主控对FPGA IO读写的功能
后续会分享FPGA作为主设备, 从 FPGA通过 memory写到主控内存,会涉及到DMA的设计。

设计核心:

  1. 触发lt_framen 和 lt_tsr[5:0] 与 BAR 范围命中相对应位通知本地端设备它正在声明读取事件或者写入事件 ,lt_tsr[0]被触发,表示BAR0命中
  2. lt_tsr[7] 被置位,表示待处理的事务是 64位
  3. lt_tsr[8] 被置位,表示pci ip 功能的pci侧在忙
  4. lt_tsr[10] 被置位,表示上一个时钟周期期间PCI端数据传输成功
  5. 取消断言lt_tsr[11:0]通知本地端设备事务已完成

具体参考PCI IP手册:
使用PCI IP的 下面模式:
在这里插入图片描述

参考时序:
IO写:
在这里插入图片描述
IO读:
在这里插入图片描述
具体RTL 代码:

`timescale 1 ns / 1 ns
//
// Company: 
// Engineer: felixgao
// 
// Create Date: 
// Design Name: 
// Module Name: 
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
//  date       version		  author		
//                      	
//				
// note :
//
// 1. 触发lt_framen 和 lt_tsr[5:0] 与 BAR 范围命中相对应位通知本地端设备它正在声明读取事件或者写入事件  ,lt_tsr[0]被触发,表示BAR0命中
// 2. lt_tsr[7] 被置位,表示待处理的事务是 64位
// 3. lt_tsr[8] 被置位,表示pci ip 功能的pci侧在忙
// 4. lt_tsr[10] 被置位,表示上一个时钟周期期间PCI端数据传输成功
// 5. 取消断言lt_tsr[11:0]通知本地端设备事务已完成
//module pci_local_target(input             i_clk                 ,input             i_rstn                ,output            o_lt_abortn           , output            o_lt_discn            , output            o_lt_rdyn             , input             i_lt_framen           , input             i_lt_ackn             , input             i_lt_dxfrn            , input    [11:0]   i_lt_tsr              , input     [31:0]  i_l_dat               , input     [31:0]  i_l_adr               , input     [3:0 ]  i_l_ben               , input     [3:0]   i_l_cmd               , output    [31:0]  o_l_adi               , output    [3:0]   o_l_cben              ,// io write data port for userinput             i_io_wrready          ,output    [31:0]  o_io_wrdata           ,output            o_io_wrvalid          ,output    [31:0]  o_io_wr_addr          ,output    [31:0]  o_io_rd_addr          ,// io read data port for userinput     [31:0]  i_io_rddata           ,input             i_io_rdvalid          ,output    reg     o_io_rdready           );parameter  S_IDLE    = 4'b0000   ,   //Idle S_WAIT    = 4'b0001   ,               S_TRGT_WR = 4'b0010   ,   //Target Write        S_TRGT_RD = 4'b0100   ,   //Target Read  S_END     = 4'b1000   ;        wire       w_target_write        ;
wire       w_target_read         ;
wire       w_io_write            ;
wire       w_io_read             ;
wire       w_lt_ackn_rise        ;
wire       w_lt_dxfrn_rise       ;   
wire       w_target_done         ; 
wire       w_frame_fall          ; 
wire       w_data_trans_success  ;reg [3:0]  r_cu_state            ;
reg [3:0]  r_nx_state            ;
reg [3:0]  r_sta_cnt             ;
reg        ri_lt_ackn            ;
reg        ri_lt_dxfrn           ;
reg        r_done                ;
reg        ri_lt_framen          ;
reg [31:0] ro_io_wrdata          ;
reg        ro_io_wrvalid         ;
reg [31:0] ro_io_wr_addr         ;
reg [31:0] ro_io_rd_addr         ;
reg [31:0] ro_l_adi              ;
reg        r_iowrite_it_rdyn     ;
reg        r_ioread_it_rdyn = 0  ;
reg        r_switch_itrdyn       ;assign w_frame_fall         = i_lt_framen && !ri_lt_framen                            ; // Get the falling edge of the i_lt_framen
assign w_io_write           = !i_lt_framen && ( i_l_cmd == 3) && i_lt_tsr[0]          ; // 接收 来自 主设备的 IO 写 命令,i_lt_tsr[0]为高同时BAR0 被选择
assign w_io_read            = !i_lt_framen && ( i_l_cmd == 2) && i_lt_tsr[0]          ; // 接收 来自 主设备的 IO 读 命令,i_lt_tsr[0]为高同时BAR0 被选择
assign w_target_read        = w_io_read                                               ;
assign w_target_write       = w_io_write                                              ;
assign w_lt_ackn_rise       = i_lt_ackn  && !ri_lt_ackn                               ; // 获取上升沿 此信号是 pci_mt32 IP输出
assign w_lt_dxfrn_rise      = i_lt_dxfrn && !ri_lt_dxfrn                              ; // 获取上升沿 此信号是 pci_mt32 IP输出 
assign w_target_done        = !i_lt_tsr[8] && r_done                                  ; // 事务传输完成
assign o_io_wrdata          = ro_io_wrdata                                            ; // 接收到主设备 向从设备 写的数据
assign o_io_wrvalid         = ro_io_wrvalid                                           ; // 接收到主设备 向从设备 写的数据有效
assign o_io_wr_addr         = ro_io_wr_addr                                           ; // 接收到主设备 向从设备 传来的地址,指示向什么地址写数据
assign o_io_rd_addr         = ro_io_rd_addr                                           ; // 接收到主设备 向从设备 传来的地址,指示向什么地址读数据
assign o_l_cben             = 4'h0                                                    ; // 用户给的 字节数据使能 ,每个字节默认都有效
// assign o_io_rdready         = (r_cu_state == S_TRGT_RD && r_sta_cnt == 0) ? 1'b1:1'b0 ; // 用户 读数据准备信号
// assign o_io_rdready         = (i_l_cmd == 2) ? 1'b1:1'b0 ;
assign o_l_adi              = ro_l_adi                                                ; 
assign o_lt_abortn          = 1                                                       ; // 从设备默认不终止
assign o_lt_discn           = 1                                                       ; // 从设备默认不断连
assign w_data_trans_success = !i_lt_ackn && !i_lt_dxfrn                               ; // 数据传输一次成功标志
assign o_lt_rdyn            = (r_switch_itrdyn)?r_ioread_it_rdyn:r_iowrite_it_rdyn    ; // 用户准备 接收 或者 发送数据//准备好读数据,送到pci ip
always @ (posedge i_clk or negedge i_rstn)
beginif (!i_rstn)o_io_rdready <= 0;else if (i_l_cmd == 2)o_io_rdready <= 1;   else o_io_rdready <= 0;                
endalways @ (posedge i_clk or negedge i_rstn)
beginif (!i_rstn) beginri_lt_framen <= 1;ri_lt_ackn  <= 1;ri_lt_dxfrn <= 1;end else beginri_lt_framen <= i_lt_framen;ri_lt_ackn   <= i_lt_ackn  ;ri_lt_dxfrn  <= i_lt_dxfrn ;     end
end// 确保传输完成,能够接收到 pci_mt32的  dxfrn 和 ackn 信号
always @ (posedge i_clk or negedge i_rstn)
beginif (!i_rstn)r_done <= 0;else if (r_cu_state == S_WAIT) r_done <= 0; else if (w_lt_ackn_rise && w_lt_dxfrn_rise)r_done <= 1;   else r_done <= r_done;                
end// 从模式 三段式状态机
always @ (posedge i_clk or negedge i_rstn)
beginif (!i_rstn)r_cu_state <= S_IDLE;else r_cu_state <= r_nx_state;       
endalways @ (*)
begincase(r_cu_state)S_IDLE     : begin    // 空闲状态等待10周期,状态跳转if (r_sta_cnt == 10)r_nx_state = S_WAIT;else r_nx_state = r_cu_state;           end S_WAIT     : begin    // 当接收到主设备写或者读命令时,状态跳转if (w_target_write)   r_nx_state = S_TRGT_WR;else if (w_target_read)r_nx_state = S_TRGT_RD;                   else r_nx_state = r_cu_state;                       end                  S_TRGT_WR  : begin    // 写传输结束,状态跳转if (w_target_done)r_nx_state = S_END;             else r_nx_state = r_cu_state;        end      S_TRGT_RD  : begin    // 读传输结束,状态跳转if (w_target_done)r_nx_state = S_END;             else r_nx_state = r_cu_state;      endS_END   :  r_nx_state = S_WAIT ;default :  r_nx_state = S_IDLE ;     endcase
end//状态计数器
always @ (posedge i_clk or negedge i_rstn)
beginif (!i_rstn)r_sta_cnt <= 0;else if (r_cu_state != r_nx_state)r_sta_cnt <= 0;  else r_sta_cnt <= r_sta_cnt + 1'b1;     
end// rdyn 切换控制信号,IO写和 IO读 控制lt_rdyn方式不一样
always @ (posedge i_clk or negedge i_rstn)
beginif (!i_rstn)r_switch_itrdyn <= 0;else if (w_target_write)r_switch_itrdyn <= 0;  else if (w_target_read)r_switch_itrdyn <= 1;  else r_switch_itrdyn <= r_switch_itrdyn;          
end// IO 写操作时,lt_rdyn的控制
always @ (posedge i_clk or negedge i_rstn)
beginif (!i_rstn)r_iowrite_it_rdyn <= 1;else if (r_cu_state == S_TRGT_WR && r_sta_cnt == 0)r_iowrite_it_rdyn <= 0;  else if (r_cu_state == S_TRGT_WR && w_data_trans_success)r_iowrite_it_rdyn <= 1;  else r_iowrite_it_rdyn <= r_iowrite_it_rdyn;          
end// IO 读操作时,lt_rdyn的控制
always @ (*)
beginif (r_nx_state == S_END)r_ioread_it_rdyn <= 1;      else if (r_cu_state == S_TRGT_RD)r_ioread_it_rdyn <= 0;  else r_ioread_it_rdyn <= r_ioread_it_rdyn;          
end// 主设备 写到 从设备的 数据 及 数据有效
always @ (posedge i_clk or negedge i_rstn)
beginif (!i_rstn) beginro_io_wrdata  <= 0;ro_io_wrvalid <= 0;end else if (r_cu_state == S_TRGT_WR && w_data_trans_success && i_io_wrready) beginro_io_wrdata  <= i_l_dat;ro_io_wrvalid <= 1;end else beginro_io_wrdata  <= 0;ro_io_wrvalid <= 0;     end
end// 主设备IO写操作时 写到 从设备的 地址
always @ (posedge i_clk or negedge i_rstn)
beginif (!i_rstn) beginro_io_wr_addr<= 0;end else if (r_cu_state == S_TRGT_WR && r_sta_cnt == 0) beginro_io_wr_addr  <= i_l_adr;end else beginro_io_wr_addr  <= ro_io_wr_addr;end
end// 主设备IO读操作时, 写到 从设备的 地址
always @ (posedge i_clk or negedge i_rstn)
beginif (!i_rstn) beginro_io_rd_addr<= 0;end else if (i_l_cmd == 2) beginro_io_rd_addr  <= i_l_adr;end else beginro_io_rd_addr  <= ro_io_rd_addr;end
end//从设备 发送给主设备数据
always @ (posedge i_clk or negedge i_rstn)
beginif (!i_rstn)ro_l_adi <= 0;else if (r_cu_state == S_TRGT_RD && !o_lt_rdyn && i_io_rdvalid && !i_lt_ackn)ro_l_adi <= i_io_rddata;  else ro_l_adi <= ro_l_adi;          
endendmodule

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/86571.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/86571.shtml

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

相关文章

基于机器学习的智能文本分类技术研究与应用

在当今数字化时代&#xff0c;文本数据的爆炸式增长给信息管理和知识发现带来了巨大的挑战。从新闻文章、社交媒体帖子到企业文档和学术论文&#xff0c;海量的文本数据需要高效地分类和管理&#xff0c;以便用户能够快速找到所需信息。传统的文本分类方法主要依赖于人工规则和…

前端项目3-01:登录页面

一、效果图 二、全部代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>码农魔盒</title><style>.bg{position: fixed;top: 0;left:0;object-fit: cover;width: 100vw;height: 100vh;}.box{width: 950px;he…

Nexus CLI:简化你的分布式计算贡献之旅

探索分布式证明网络的力量&#xff1a;Nexus CLI 项目深入解析 在今天的数字时代&#xff0c;分布式计算和去中心化技术正成为互联网发展的前沿。Nexus CLI 是一个为 Nexus 网络提供证明的高性能命令行界面&#xff0c;它不仅在概念上先进&#xff0c;更是在具体实现中为开发者…

IBW 2025: CertiK首席商务官出席,探讨AI与Web3融合带来的安全挑战

6月26日至27日&#xff0c;全球最大的Web3安全公司CertiK亮相伊斯坦布尔区块链周&#xff08;IBW 2025&#xff09;&#xff0c;首席商务官Jason Jiang出席两场圆桌论坛&#xff0c;分享了CertiK在AI与Web3融合领域的前沿观察与安全见解。他与普华永道土耳其网络安全服务主管Nu…

Vivado 五种仿真类型的区别

Vivado 五种仿真类型的区别 我们还是用“建房子”的例子来类比。您已经有了“建筑蓝图”&#xff08;HLS 生成的 RTL 代码&#xff09;&#xff0c;现在要把它建成真正的房子&#xff08;FPGA 电路&#xff09;。这五种仿真就是在这个过程中不同阶段的“质量检查”。 1. 行为…

小程序快速获取url link方法,短信里面快速打开链接

获取小程序链接方法 uni.request({url:https://api.weixin.qq.com/cgi-bin/token?grant_typeclient_credential&appidwxxxxxxxxxxxx&secret111111111111111111111111111111111,method:GET,success(res) {console.log(res.data)let d {"path": "/xxx/…

Spring 框架(1-4)

第一章&#xff1a;Spring 框架概述 1.1 Spring 框架的定义与背景 Spring 是一个开源的轻量级 Java 开发框架&#xff0c;于 2003 年由 Rod Johnson 创立&#xff0c;旨在解决企业级应用开发的复杂性。其核心设计思想是面向接口编程和松耦合架构&#xff0c;通过分层设计&…

RabitQ 量化:既省内存又提性能

突破高维向量内存瓶颈:Mlivus Cloud RaBitQ量化技术的工程实践与调优指南 作为大禹智库高级研究员,拥有三十余年向量数据库与AI系统架构经验的我发现,在当今多模态AI落地的核心场景中,高维向量引发的内存资源消耗问题已成为制约系统规模化部署的“卡脖子”因素。特别是在大…

创客匠人:创始人 IP 打造的得力助手

在当今竞争激烈的商业环境中&#xff0c;创始人 IP 的打造对于企业的发展愈发重要。一个鲜明且具有影响力的创始人 IP&#xff0c;能够为企业带来独特的竞争优势&#xff0c;提升品牌知名度与美誉度。创客匠人在创始人 IP 打造过程中扮演着不可或缺的角色&#xff0c;为创始人提…

如何为虚拟机上的 Manjaro Linux启用 VMware 拖放功能

如果你的Manjaro 发行版本是安装在 VMware Workstation Player 上使用的 &#xff0c;而且希望可以通过拖放功能将文件或文件夹从宿主机复制到客户端的Manjaro 里面&#xff0c;那么可以按照以下的步骤进行操作&#xff0c;开启拖放功能。 在 VMware 虚拟机上安装 Manjaro 后&…

【C/C++】单元测试实战:Stub与Mock框架解析

C 单元测试中的 Stub/Mock 框架详解 在单元测试中&#xff0c;Stub&#xff08;打桩&#xff09;和Mock都是替代真实依赖以简化测试的技术。通常&#xff0c;Stub&#xff08;或 Fake&#xff09;提供了一个简化实现&#xff0c;用于替代生产代码中的真实对象&#xff08;例如…

工厂 + 策略设计模式(实战教程)

在软件开发中&#xff0c;设计模式是解决特定问题的通用方案&#xff0c;而工厂模式与策略模式的结合使用&#xff0c;能在特定业务场景下发挥强大的威力。本文将基于新增题目&#xff08;题目类型有单选、多选、判断、解答&#xff09;这一业务场景&#xff0c;详细阐述如何运…

Nuxt3中使用 Ant-Design-Vue 的BackTop 组件实现自动返回页面顶部

在现代 Web 应用中&#xff0c;提供一个方便用户返回页面顶部的功能是非常重要的。Ant Design Vue 提供了 BackTop 组件&#xff0c;可以轻松实现这一功能。本文将详细介绍如何在 Nuxt 3 项目中使用 <a-back-top/> 组件&#xff0c;并通过按需引入的方式加载组件及其样式…

在统信UOS(Linux)中构建SQLite3桌面应用笔记

目录 1 下载lazarus 2 下载sqlite3源码编译生成库文件 3 新建项目 4 设置并编译 一次极简单的测试&#xff0c;记录一下。 操作系统&#xff1a;统信UOS&#xff0c; 内核&#xff1a;4.19.0-arm64-desktop 处理器&#xff1a;D3000 整个流程难点是生成so库文件并正确加…

Host ‘db01‘ is not allowed to connect to this MariaDB server 怎么解决?

出现错误 ERROR 1130 (HY000): Host db01 is not allowed to connect to this MariaDB server&#xff0c;表示当前用户 test 没有足够的权限从主机 db01 连接到 MariaDB 服务器。以下是逐步解决方案&#xff1a; 1. 检查用户权限 登录 MariaDB 服务器&#xff08;需本地或通过…

打造高可用的大模型推理服务:基于 DeepSeek 的企业级部署实战

&#x1f4dd;个人主页&#x1f339;&#xff1a;一ge科研小菜鸡-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 一、引言&#xff1a;从“能部署”到“可用、好用、能扩展” 近年来&#xff0c;随着 DeepSeek、Qwen、Yi 等开源大模型的持续发…

Spring Boot 使用 ElasticSearch

第一步&#xff0c;开启本地的 ElasticSearch 启动 elasticSearch.bat npm run start (head 插件) 第二步&#xff0c;在 Spring Boot 项目中引入依赖 <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-hig…

软件开发的“中庸之道”:因势而为,心中有数

【软件工程】软件开发的“中庸之道”&#xff1a;因势而为&#xff0c;心中有数 在软件开发的方法论讨论中&#xff0c;我们常常陷入非此即彼的二元对立&#xff1a;要么追求极致的规范化和流程化&#xff0c;严格遵循软件工程的各项标准&#xff1b;要么完全摒弃方法论&#x…

Go和Elixir极简HTTP服务对比

Go 和 Elixir 都是我非常喜欢的编程语言&#xff0c;这次来对比下它们实现一个原生极简 HTTP 服务的过程。 Go 语言标准库自带了网络服务库&#xff0c;只需要简单几行代码就可以实现一个网络服务&#xff0c;这也是一开始它吸引我的一个方面。而 Elixir 标准库本身没有网络服…

为何要学习Objective-C?从环境搭建开始

目录 前言 Swift时代为何还要学Objective-C&#xff1f; 开发环境搭建 1. 安装Xcode 2. 创建第一个Command Line Tool项目 初识Objective-C代码 编写"Hello, Objective-C!" 编译运行程序 为什么Objective-C中的NSLog和NSString前面都有"NS"前缀&a…