上一篇文章中,介紹了一個(gè)基本的NVMe VIP測(cè)試用例,包括一些基本的設(shè)置,發(fā)送命令和接收完成。在這里,我們將再看一些NVMe命令,涉及VIP的一些特性和功能。
在這里,您可以了解有關(guān)適用于 NVMe 和 PCIe 的 Synopsys VC 驗(yàn)證 IP 的更多信息。
貴賓的(提醒)視圖
我們上次簡(jiǎn)要介紹了這一點(diǎn)。這次我們將更深入地介紹,因此我們將繼續(xù)參考此圖:
NVMe VIP 提供了一組功能來幫助測(cè)試。其中包括隨機(jī)化、功能窺探、簡(jiǎn)化的 PRP 和數(shù)據(jù)緩沖區(qū)處理、內(nèi)存屏蔽和內(nèi)置記分板。我們將依次通過另一個(gè)示例來查看其中的每一個(gè)。
繼續(xù)我們的測(cè)試用例...
繼上一篇文章中的“瑣碎測(cè)試用例”之后(同樣,我們沒有顯示一些任務(wù)參數(shù)或檢查錯(cuò)誤),讓我們?cè)倏磶讉€(gè)命令來啟動(dòng)我們的 NVMe 測(cè)試用例。
提醒一下:以腳本一詞開頭的任務(wù)是 NVMe 命令。其他(不以腳本開頭)是 VIP 狀態(tài)/控制/配置任務(wù)。
// We will assume that the PCIe stack is setup and running bit [63:0] base_addr = 32’h0001_0000; // Ctlr BAR base addr dword_t num_q_entries, ctlr_id; // Tell the host where the controller has its base address AllocateControllerID(base_addr, ctlr_id, status); num_q_entries = 2; // Create the Admin Completion and Submission Queues ScriptCreateAdminCplQ(ctlr_id, num_q_entries, status); ScriptCreateAdminSubQ(ctlr_id, num_q_entries, status); // Send an “Identify Controller” Command data_buf_t #(dword_t) identify_buffer; // identify data identify_buffer = new(1024); ScriptIdentify(ctlr_id, 0, identify_buffer, 0, status); |
我們以調(diào)用標(biāo)識(shí)控制器結(jié)束了最后一個(gè)示例。現(xiàn)在,繼續(xù)在這一點(diǎn)上,我們讀取字節(jié) 519:516 以獲取有效命名空間 ID 的數(shù)量。我們通過 SetNumNamespaces() 調(diào)用將其傳遞給主機(jī) VIP。請(qǐng)注意,我們必須對(duì)識(shí)別控制器緩沖區(qū)中返回的(小端序)數(shù)據(jù)進(jìn)行字節(jié)交換。
int num_ns, nsid, blk_size_pow2, blk_size_in_bytes; bit [63:0] ns_size_in_blks; feature_identifier_t feature_id; nvme_feature_t set_feature; // We’ll grab the Number of valid namespaces (NN) from the // identify buffer. Note index converted from bytes to dword. num_ns = ByteSwap32(identify_buffer[516 >> 2]); // bytes 519:516 // Tell the VIP how many active NSIDs the controller has SetNumNamespaces(ctlr_id, num_ns, status); |
接下來,我們讀取其中一個(gè)命名空間(命名空間 ID=1)的信息。請(qǐng)注意,我們?cè)谶@里“作弊”了一點(diǎn),因?yàn)槲覀儜?yīng)該遍歷所有有效的命名空間。對(duì)于這個(gè)例子,我們只假設(shè)我們只有 NSID=1。盡管標(biāo)識(shí)調(diào)用不采用 PRP 列表,但其主機(jī)內(nèi)存緩沖區(qū)可以具有偏移量。如果需要,請(qǐng)選擇參數(shù)“use_offset=1”。實(shí)際偏移通過約束 MIN/MAX_PRP_DWORD_OFFSET_VAR 隨機(jī)化。
// Now send an “Identify Namespace” command for nsid=1 nsid = 1; use_offset = 1; // Randomize buffer offset ScriptIdentify(ctlr_id, nsid, identify_buffer, use_offset, status); // Pull information from format[0] blk_size_pow2 = ByteSwap32(identify_buffer.GetData(128 >> 2))); blk_size_pow2 = (blk_size_pow2 >> 16) & 32’hff; // dword[23:16] blk_size_in_bytes = 1 << blk_size_pow2;???? ???? // Convert ns_size_in_blks = ByteSwap64({identify_buffer.GetData(8 >> 2), identify_buffer.GetData(12 >> 2)}); // Before we create queues, we need to configure the num queues // on the controller. feature_id = FEATURE_NUM_QUEUES; set_feature = new(feature_id); |
一旦識(shí)別命名空間返回,我們現(xiàn)在有了塊大小和命名空間大小。我們使用設(shè)置功能設(shè)置請(qǐng)求的隊(duì)列數(shù)量。通過 VIP 的功能偵聽,這將(透明地)將 VIP 設(shè)置為當(dāng)前支持的提交和完成隊(duì)列數(shù)量(用于以后的檢查和錯(cuò)誤注入支持)。
接下來的步驟設(shè)置命名空間的格式(使用標(biāo)識(shí)命名空間數(shù)據(jù)結(jié)構(gòu)中的格式 0)。然后,我們更新命名空間信息的 VIP 視圖。VIP 需要此命名空間信息來保留每個(gè)命名空間的記分板。
set_features.SetNumCplQ(2); // Request number of sub & set_features.SetNumSubQ(3); // cpl queues // Call Set Features command to set the queues on the ctlr ScriptSetFeatures(ctlr_id, set_features, …, status); // Note that Set Features Number of Queues command need not // return the same amount of queues that were requested. We can // check by examining set_features.GetNumCplQ() and // GetNumSubQ(), but in this case we’ll just trust it… // Format the Namespace sec_erase = 0; // Don’t use secure erase pi_md_settings = 0; // Don’t use prot info or metadata format_number = 0; // From Identify NS data structure ScriptFormatNVM(ctlr_id, nsid, sec_erase, pi_md_settings, format_number, …, status); // Tell the VIP about this NS SetNamespaceInfo(ctlr_id, nsid, blk_size_in_bytes, ns_size_in_blks, md_bytes_per_blk, pi_md_settings, 0, status); |
接下來,我們創(chuàng)建一對(duì) I/O 隊(duì)列。由于提交隊(duì)列需要與其一起傳遞其配套完成隊(duì)列,因此我們首先創(chuàng)建完成隊(duì)列。請(qǐng)注意,隊(duì)列創(chuàng)建例程采用參數(shù)重疊群。如果設(shè)置了重疊群,則隊(duì)列將放置在連續(xù)內(nèi)存中,否則將為該隊(duì)列創(chuàng)建 PRP 列表。除了創(chuàng)建實(shí)際隊(duì)列之外,VIP 還會(huì)在隊(duì)列周圍創(chuàng)建圍欄,以驗(yàn)證對(duì)隊(duì)列的內(nèi)存訪問。從控制器(例如)從完成隊(duì)列讀取的嘗試將被標(biāo)記為無效的訪問嘗試。實(shí)際隊(duì)列 ID 是隨機(jī)的(在法律和用戶可配置的約束范圍內(nèi))。
// Create the I/O Queues num_q_entries = 10; contig = 1; // Contiguous queue ScriptCreateIOCplQ(ctlr_id, num_q_entries, contig, …, cplq_id, …, status); contig = 0; // PRP-based queue ScriptCreateIOSubQ(ctlr_id, num_q_entries, contig, cplq_id …, subq_id, …, status); |
一旦我們創(chuàng)建了 I/O 隊(duì)列,我們就可以開始執(zhí)行 I/O.使用 ScriptWrite() 和 ScriptRead() 調(diào)用,我們將數(shù)據(jù)發(fā)送到控制器并立即檢索相同的數(shù)據(jù)。數(shù)據(jù)的底層數(shù)據(jù)結(jié)構(gòu)(在主機(jī)內(nèi)存中)由 VIP 自動(dòng)構(gòu)建。請(qǐng)注意 use_offset 參數(shù)(與我們的隊(duì)列創(chuàng)建任務(wù)一樣)來控制我們是否生成 PRP 和 PRP 列表偏移量(分別由 MIN/MAX_PRP_DWORD_OFFSET_VAR 和 MIN/MAX_PRP_LIST_DWORD_OFFSET 控制)。由于我們內(nèi)置了記分板,我們不必比較從寫入的數(shù)據(jù)讀取的數(shù)據(jù),VIP 正在根據(jù)其卷影副本檢查返回的數(shù)據(jù),該卷影副本正在跟蹤成功向控制器寫入的 VIP。
// Do our I/O write then read with a random LBA/length data_buf_t #(dword_t) wbuf, rbuf; // Write/Read Data buffers num_blks = RandBetween(1, ns_size_in_blks); lba = RandBetween(0, ns_size_in_blks – num_blks); num_dwords = (blk_size_in_bytes / 4) * num_blks; wbuf = new(num_dwords); for (int idx = 0 ; idx < num_dwords ; idx++) // Fill the buffer wbuf.SetData(idx, { 16’hdada, idx[15:0] } ); ScriptWrite(ctlr_id, subq_id, lba, nsid, wbuf, num_blks, use_offset, …, status); // We’ll read the same LBA since we know it’s been written ScriptRead(ctlr_id, subq_id, lba, nsid, rbuf, num_blks, use_offset, …, status); // Do what you’d like with the rbuf (that’s the data we just read). |
大功告成!
希望這能讓我們完成大部分基礎(chǔ)知識(shí)。您應(yīng)該對(duì)VIP的操作有很好的感覺。同樣,其中許多任務(wù)都有更多的參數(shù),允許更多的控制和錯(cuò)誤注入,但我們的目標(biāo)是在不處理更深?yuàn)W的功能的情況下完成。如果您有VIP手邊的VIP,請(qǐng)隨意瀏覽示例:它們應(yīng)該看起來很熟悉。
審核編輯:郭婷
-
控制器
+關(guān)注
關(guān)注
112文章
16393瀏覽量
178475 -
PCIe
+關(guān)注
關(guān)注
15文章
1241瀏覽量
82761 -
nvme
+關(guān)注
關(guān)注
0文章
221瀏覽量
22669
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論