NVMe协议是工作在PCIE的最上层协议层的,故需要先搞清楚PCIE。本文基于Xilinx的UltraScale+,开发工具为Vivado2021.2。学习中以spec为主,其它资料辅助参考(重点介绍学习方法及资料,有时间再加细节)。请勿转载!
主要参考的文章是《老男孩读PCIe》,同时参考《古猫先生》,重点学习TLP报文部分,数据链路层和物理层的内容可以先不看。再买一本书《PCI Express 体系结构导读-王齐》用来查阅做笔记。

老男孩读PCIe介绍系列_Ha-Ha-Interesting的博客-CSDN博客_老男孩读pcie
PCIe最全科普贴流出!不说了,赶快Mark!_古猫先生的博客-CSDN博客
还有2本MindShare的英文书籍参考,备用即可。

https://www.mindshare.com/files/ebooks/PCI%20Express%20System%20Architecture.pdf
https://www.mindshare.com/files/ebooks/PCI%20Express%20Technology%203.0.pdf
在NVMe工程中用到的TLP类型为mem读写、config、中断:
在Xilinx的Vivado中关于PCIe的IP有3个:PCIE4,XDMA,QDMA。后两个IP都基于前一个,使用难度递增、速率递增、资源占用也递增。
下列文章中详细介绍了7系列PCIE(此IP使用标准TLP格式,不同于UP系列PCIE4)、XDMA IP的基础配置、官方Demo的生成、仿真分析。Demo中用Verilog代码设计了一个RootPort来和EP通信,模拟了上电后Bar扫描、分配地址、速率宽度等协商配置。Demo中的EP代码可以用于实际的设计中。在7系Demo与UP demo中PCIE HEAD扩展reg的偏移地址有个别不同,以实际PG为准。
开发板可以用黑金、米联客的板子。

PCIe基础知识及Xilinx相关IP核介绍_lu-ming.xyz的博客-CSDN博客_pcie ip核 xilinx
NVMe Base Specification – NVM Express
https://nvmexpress.org/developers/nvme-specification/
蛋蛋读NVMe之一(cmd processing)
蛋蛋读NVMe之二 (SQ,CQ和DB)
蛋蛋读NVMe之三 (PRP)
蛋蛋读NVMe之四(Trace)
蛋蛋读NVMe之五(Protection Information)
蛋蛋读NVMe之六(Namespace)
以下的系列4篇文章也可以参考对比:
NVMe 协议详解(一)_IFappy的博客-CSDN博客_nvme协议
NVMe详解(四)_IFappy的博客-CSDN博客_nvme smart-log 详解
下面文章对spec1.3做了部分翻译,有个别内容不准确,可以参考
【NVMe】NVMe 1.3协议中文翻译——第一章简介_ljyyyyyyyyy的博客-CSDN博客_nvme1.3协议
下面的文章实际抓取了NVMe报文,并做了分析,有助于理解NVMe工作的完整流程。PCIE协议可以使用分析仪抓取报文,分析仪串在链路中,抓取上行、下行报文。目前看到的文章中主要有2家:力科、Saniffer。
从PCIe trace中分析NVMe_Ingram14的博客-CSDN博客_pcie trace
【71】力科PCIe 协议分析仪常见操作_linjiasen的博客-CSDN博客_pcie协议分析仪
Saniffer公司的分析仪及软件,可以联系他们获取软件及SSD启动抓取的完整报文、分析仪的使用培训教程等等。
PCIe和NVMe SSD初始化过程简介_SSD学院_SSDtime
PCIe和NVMe SSD初始化过程简介-面包板社区 同一篇文章的不同链接。
1、spec1.2中7.6.1 Initialization 介绍了上电后整个通信链路建立的过程:host写NVMe reg、创建Admin Queue,通过Admin创建IO Queue。之后才能进行数据的读写。
2、spec 7.2.1command processing 介绍了取SQ,执行,返回CQ,中断的详细过程。注意在步骤4指令执行时,可能包含多个纯TLP报文完成数据读写,图中并未标出;
3、第1章主要是一些名词解释,重点1.6节。
4、第2章是PCIE的寄存器配置,此部分内容在使用Xilinx IP时用户不能直接访问,而是通过IP GUI设置参数即可。在IP中必须注意class code要改为下方协议中值,否则无法识别为NVMe控制器。电源管理PM、中断MSI\MSI-X\等都在GUI配置,由IP负责维护reg。
5、第3章重点3.1节,是NVMe协议层reg,需要mem TLP来读写,这些reg有专门的地址,即TLP中的地址段。先不展开细说了,重点提示如下:
6、第4章 Memory structure,介绍了NVMe中一些基本的定义。重点4.1SQCQ定义,4.2SQE,4.3PRP,4.6CQE格式。其他的SGL、MR、CMB、Fused Operation都不用,arbitration只用默认的RoundRobin即可。
7、第5章是Admin指令。重点关注强制cmd中红圈部分,是初始化使用到的,顺序参见spec1.2 的7.6.1 Initialization 章节。5.11 Identify command中的data structure和namespace structure特别重要,至于figure91 电源可以只要一种即可,不支持切换。先创建CQ,后创建SQ;先删除SQ,后删除CQ。删除cmd就是把创建指令设置的各项参数都复位。
8、第6章是NVM=IO 指令,重点是读写。flush指令若没有用缓存,或确定数据已全部写入外部存储,可以不做操作,直接回复CQE即可。
9、第7章重点关注7.2指令的处理流程,7.6 控制器初始化过程(整理链路建立过程)。
10、第8章大部分都不用看,关注8.6 Doorbell Stride。在硬件使用时=0,用在doorbell reg 地址分配上,=0则紧凑排布。
三种实现方案NVMe协议,基于3种不同的IP,QDMA仅支持ultralscale+器件。
PCIE4是ultralscale+器件中的型号,手册为PG213。与7 Series Integrated Block for PCI Express IP(PG054)略有不同,7系的IP用户数据stream接口分为tx,rx两个,报文格式基本与标准TLP相同;
PCIE4 IP的用户接口分为4个:CQ/CC,RQ/RC。XX中前一位是用户的角色:C代表用户是完成方被动响应,R代表用户请求方主动发起;后一位表示请求数据or完成数据。报文格式与标准TLP略有不同。
Admin,IO指令都用PL纯逻辑实现,节约资源。用于和ASMedia USB转NVMe芯片的通信,此转接芯片的协议严格遵守了NVMe spec,不需要PC端有NVMe的驱动,PC将其识别为USB设备。
Controller data structure和Namespace data structure各占用4KB的空间,可以把参数提前配好,用一个ROM+.coe初始化文件的方式,供Admin读取。
调试时先确保PCIE层通信正常,可以使用WinDriver来调试CQ/CC口,即调试NVMe reg。注意使用金手指上的复位来复位PCIE4 IP。根据SQE中LBA的个数决定PRP List长度,读写数据前先读取PRPList,并压入FIFO中,用一个出一个。
该方案用MicroBlaze核解析Admin指令,IO指令用PL逻辑实现,MB核占用资源。该方案需要PC端驱动的配合,无法与ASMedia芯片配合使用。
Demo由复旦大学设计,并且有配套论文,硬件基于KCU105开发板。设计中创建了一个Admin Queue,8个IO Queue。启用了XDMA的4条stream通道、descriptor bypass通道、AXI-master、AXI-slave。


https://github.com/yhqiu16/NVMeCHA
Xilinx官方提供了Demo,使用QDMA+收费的NVMeTC。其Admin指令由MB核解析,且MB上运行了linux系统,占用大量资源。仅用于和PC通信。
在手册中搜索 Download the reference design files,下载工程。
crystal disk mark:测速更准确。
HD_speed:可以长时间连续测试,由写+读+验证模式。
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
我怎样才能完成http://php.net/manual/en/function.call-user-func-array.php在ruby中?所以我可以这样做:classAppdeffoo(a,b)putsa+benddefbarargs=[1,2]App.send(:foo,args)#doesn'tworkApp.send(:foo,args[0],args[1])#doeswork,butdoesnotscaleendend 最佳答案 尝试分解数组App.send(:foo,*args)
我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2