Verilog 文件操作

2023-02-28 14:09 更新

Verilog 提供了很多可以對(duì)文件進(jìn)行操作的系統(tǒng)任務(wù)。經(jīng)常使用的系統(tǒng)任務(wù)主要包括:

  • 文件開(kāi)、閉:?$fopen?, ?$fclose?, ?$ferror ?
  • 文件寫(xiě)入:?$fdisplay?, ?$fwrite?, ?$fstrobe?, ?$fmonitor ?
  • 字符串寫(xiě)入:?$sformat?, ?$swrite ?
  • 文件讀?。?$fgetc?, ?$fgets?, ?$fscanf?, ?$fread ?
  • 文件定位:?$fseek?, ?$ftell?, ?$feof?, ?$frewind ?
  • 存儲(chǔ)器加載:?$readmemh?, ?$readmemb?

使用文件操作任務(wù)(尤其注意 ?$sforamt?, ?$gets?, ?$sscanf? 等)對(duì)文件進(jìn)行操作時(shí),需要根據(jù)文件性質(zhì)和變量?jī)?nèi)容確定使用哪一種系統(tǒng)任務(wù),并保證參數(shù)及讀寫(xiě)變量類型與文件內(nèi)容的一致性,不要將字符串類型和多進(jìn)制類型相混淆。

文件打開(kāi)/關(guān)閉

系統(tǒng)任務(wù) 調(diào)用格式 任務(wù)描述
文件打開(kāi) fd = $fopen("fname", mode) ; fname 為打開(kāi)文件的名字
fd 為返回的 32bit 文件描述符
--- 正確打開(kāi)時(shí),fd 為非零值
--- 打開(kāi)出錯(cuò)時(shí),fd為零值
mode 用于指定文件打開(kāi)的方式
文件關(guān)閉 $fclose(fd) ; 關(guān)閉 fd 描述的對(duì)應(yīng)文件
文件錯(cuò)誤 err = $ferror(fd, str) ; 正常打開(kāi)文件時(shí):
--- err 與 str 均為零值,
打開(kāi)文件出錯(cuò)時(shí):
--- err 返回非零值表示錯(cuò)誤
--- str 返回非零值存儲(chǔ)錯(cuò)誤類型
--- 官方建議 str 長(zhǎng)度為 640bit 位寬

舉例代碼如下:

  //open/close file
   integer fd1, fd2 ;
   integer err1, err2 ;
   reg [320:0] str1, str2 ; //錯(cuò)誤類型的變量也可以為可支持的 string 類型
   initial begin
      //existing file
      fd1 = $fopen("./DATA_RD.HEX", "r");    //打開(kāi)存在的文件
      err1 = $ferror(fd1, str1);
      $display("File1 descriptor is: %h.", fd1 );//非零值
      $display("Error1 number is: %h.", err1 );  //0
      $display("Error2 info is: %s.", str1 );    //0
      $fclose(fd1);
      //not existing file
      fd2 = $fopen("../../FILE_NOEXIST.HEX", "r");//打開(kāi)的文件不存在
      err2 = $ferror(fd2, str2);
      $display("File2 descriptor is: %h.", fd2 ); //0
      $display("Error2 number is: %h.", err2 );   //非零值
      $display("Error2 info is: %s.", str2 );     //非零值
      $fclose(fd2);
   end


文件打開(kāi)方式 mode 類型及其描述如下:

r 只讀打開(kāi)一個(gè)文本文件,只允許讀數(shù)據(jù)。
w 只寫(xiě)打開(kāi)一個(gè)文本文件,只允許寫(xiě)數(shù)據(jù)。如果文件存在,則原文件內(nèi)容會(huì)被刪除。如果文件不存在,則創(chuàng)建新文件。
a 追加打開(kāi)一個(gè)文本文件,并在文件末尾寫(xiě)數(shù)據(jù)。如果文件如果文件不存在,則創(chuàng)建新文件。
rb 只讀打開(kāi)一個(gè)二進(jìn)制文件,只允許讀數(shù)據(jù)。
wb 只寫(xiě)打開(kāi)或建立一個(gè)二進(jìn)制文件,只允許寫(xiě)數(shù)據(jù)。
ab 追加打開(kāi)一個(gè)二進(jìn)制文件,并在文件末尾寫(xiě)數(shù)據(jù)。
r+ 讀寫(xiě)打開(kāi)一個(gè)文本文件,允許讀和寫(xiě)
w+ 讀寫(xiě)打開(kāi)或建立一個(gè)文本文件,允許讀寫(xiě)。如果文件存在,則原文件內(nèi)容會(huì)被刪除。如果文件不存在,則創(chuàng)建新文件。
a+ 讀寫(xiě)打開(kāi)一個(gè)文本文件,允許讀和寫(xiě)。如果文件不存在,則創(chuàng)建新文件。讀取文件會(huì)從文件起始地址的開(kāi)始,寫(xiě)入只能是追加模式。
rb+ 讀寫(xiě)打開(kāi)一個(gè)二進(jìn)制文本文件,功能與 "r+" 類似。
wb+ 讀寫(xiě)打開(kāi)或建立一個(gè)二進(jìn)制文本文件,功能與 "w+" 類似。
ab+ 讀寫(xiě)打開(kāi)一個(gè)二進(jìn)制文本文件,功能與 "a+" 類似。

文件寫(xiě)入

寫(xiě)文件的系統(tǒng)任務(wù)主要包括:?$fdisplay?, ?$fwrite?, ?$fstrobe?, ?$fmonitor?,以及它們對(duì)應(yīng)的自帶格式的系統(tǒng)任務(wù) ?$fdisplayb?, ?$fdisplayh?, ?$fdisplayo? 等。

調(diào)用格式 任務(wù)描述
$fdisplay(fd, arguments) ; 按順序或條件寫(xiě)文件,自動(dòng)換行
$fwrite(fd, arguments) ; 按順序或條件寫(xiě)文件,不自動(dòng)換行
$fstrobe(fd, arguments) ; 語(yǔ)句執(zhí)行完畢后選通寫(xiě)文件
$fmonitor(fd, arguments) ; 只要數(shù)據(jù)有變化就寫(xiě)文件

相對(duì)于標(biāo)準(zhǔn)顯示任務(wù) ?$display?, ?$write?, ?$strobe?, ?$monitor?,寫(xiě)文件系統(tǒng)任務(wù)除了用法格式上需要多指定文件描述符 fd,其余打印條件、時(shí)刻特性等均與其對(duì)應(yīng)的顯示任務(wù)保持一致。

利用追加寫(xiě)的方式,對(duì)文件進(jìn)行寫(xiě)操作的舉例如下:

  //(2) write file
   integer fd ;
   integer err, str ;
   initial begin
      fd = $fopen("./DATA_RD.HEX", "a+");  //末尾追加的方式打開(kāi)
      err = $ferror(fd, str);
      if (!err) begin
         $fdisplay(fd, "New data1: %h", fd) ;
         $fdisplay(fd, "New data2: %h", str) ;
         $fdisplay(fd, "New data3: %h", err) ;
         //$write(fd, "New data3: %h", err) ; //最后一行不換行打印
      end
      $fclose(fd);
   end

打開(kāi)文件 DATA_RD.HEX,則可以看到文件末端新增了 3 行數(shù)據(jù)。


字符串寫(xiě)入

Verilog 還提供了往字符串里寫(xiě)數(shù)據(jù)的系統(tǒng)任務(wù) ?$swrite? 和 ?$sformat?。

調(diào)用格式 任務(wù)描述
$swrite(reg, list_of_arguments) ; 按順序或條件寫(xiě)字符串到變量 reg 中
len = $sformat(reg, format_str, arguments) ; 按格式 format_str 寫(xiě)字符串到變量 reg 中
格式與 $display 指定格式時(shí)一致
不建議省略第二個(gè)參數(shù) format_str
可返回字符串長(zhǎng)度 len

?$sformat? 第二個(gè)參數(shù) format 為字符串類型,一般建議不要省略。該參數(shù)指定了輸入變量的類型,指定類型時(shí)也可以包含其他字符串信息,類型種類及用法可參考顯示函數(shù) ?$display?。該參數(shù)也可以為寄存器類型,但要求存儲(chǔ)的數(shù)據(jù)為正常的字符串?dāng)?shù)據(jù)。

寫(xiě)字符串代碼舉例如下:

   //(3) write string
   reg [299:0] str_swrite, str_sformat;
   reg [63:0] str_buf ;
   integer    len, age ;
   initial begin
      #20 ;
      str_buf   = "w3cschool" ;
      age       = 9 ;

      //$swrite 指定格式寫(xiě)包含變量的字符串
      $swrite(str_swrite, "%s age is %d", str_buf, age) ;
      $display("%s", str_swrite);
      //$swrite 直接寫(xiě)不含有變量的字符串
      $swrite(str_swrite, "years ", "old.") ;
      $display("%s", str_swrite);
      //$swrite 不指定格式寫(xiě)包含變量的字符串,不建議
      $swrite(str_swrite, age) ;
      $display("$swrite err test: %d", str_swrite);

      $display();
     //$sformat 指定格式寫(xiě)包含變量的字符串
      $sformat(str_sformat, "I have learnt in %s", str_buf) ;
      $display("%s", str_sformat);
      //$sformat 直接寫(xiě)不含有變量的字符串,并獲取字符串長(zhǎng)度
      len = $sformat(str_sformat, "for 4 years!") ;
      $display("%s", str_sformat);
      $display("$sformat len: %d", len);
      //$sformat 直接一次寫(xiě)多個(gè)不含有變量的字符串,不建議
      $sformat(str_sformat, "for", "4", "years!") ;
      $display("$sformat err test: %s", str_sformat);
   end

忽略打印信息的空格,調(diào)試信息輸出如下:

1653013551410520

由此可知,?$sformat? 與 ?$swrite? 用法可以一致,例如 ?$sformat? 可采用指定格式的寫(xiě)字符串,或只寫(xiě)一次不含變量的字符串。此時(shí) ?$sformat? 相當(dāng)于在第二個(gè)參數(shù)中未指定變量類型,所以第三個(gè)參數(shù)應(yīng)該忽略不寫(xiě)。

?$swrite? 還可以一次寫(xiě)多個(gè)不包含變量的字符串,而 ?$sformat? 不允許如此調(diào)用。

也建議,使用 ?$swrite? 寫(xiě)包含變量的字符串時(shí)要指定變量類型,否則結(jié)果可能不可預(yù)測(cè)。

文件讀取

 系統(tǒng)任務(wù)  調(diào)用格式及說(shuō)明
 按字符讀文件  c = $fgetc( fd ) ;
 按字符格式將 fd 數(shù)據(jù)輸出給變量 c,c 位寬最少為 8 讀取錯(cuò)誤時(shí) c 值為 EOF(-1),可以用 $ferror 檢查錯(cuò)誤類型
 按字符寫(xiě)緩沖區(qū)  code = $ungetc(c, fd ) ;
 向文件 fd 緩沖區(qū)寫(xiě)字符 c c 值在下次調(diào)用 $fgetc 時(shí)返回,文件 fd 自身內(nèi)容不會(huì)發(fā)生變化 正常寫(xiě)緩沖時(shí)返回值 code 為 0,發(fā)生錯(cuò)誤時(shí)返回值 code 為 EOF
 按行讀文件  code = $fgets(str, fd)
 按字符連續(xù)讀,直至變量 str 被填滿,或一行內(nèi)容讀取完畢,或文件結(jié)束 正常讀取時(shí)返回值 code 為讀取行數(shù)(次數(shù)),發(fā)生錯(cuò)誤時(shí) code 為 0
 按格式讀文件  code = $fscanf(fd, format, args) ;
 按格式 format 將文件 fd 中的數(shù)據(jù)讀取到變量 args 中 format 可參考 $display 指定格式說(shuō)明 讀取一次的停止條件為空格或換行 讀取發(fā)生錯(cuò)誤時(shí)返回值 code 為 0
 按格式讀字符串  code = $sscanf(str, format, args) ;
 按格式 format 將字符串型變量 str 讀取到變量 args 中 調(diào)用格式方法和 $fscanf 一致
 按二進(jìn)制讀文件  code = $fread(store, fd, start, count) ;
 按二進(jìn)制數(shù)據(jù)流格式將數(shù)據(jù)從文件 fd 讀取到數(shù)組或寄存器變量 store 中 start 為文件起始地址,count 為讀取長(zhǎng)度 若 start/count 未指定,數(shù)據(jù)會(huì)全部填充至變量 store 中 若 store 為寄存器類型,則 start/count 參數(shù)無(wú)效,store 變量填充滿一次數(shù)據(jù)后便會(huì)停止讀取

以"文件寫(xiě)入"仿真中的文件 DATA_RD.HEX 為讀取的參考文件,進(jìn)行舉例,該文件內(nèi)容如下。

c0dec0de
5555aaaa
12345678
aaaa5555
New data1: 80000003
New data2: 00000000
New data3: 00000000

$fgetc,$ungetc 調(diào)用舉例

   //(4.1) read char
   integer      i ;
   reg [31:0]   char_buf ;
   initial begin
      #30 ;
      fd = $fopen("DATA_RD.HEX", "r");
      $write("Read char: ");
      err = $ferror(fd, str);
      if (!err) begin
         for (i=0; i<13; i++) begin
            char_buf[7:0] = $fgetc(fd) ;  //按單個(gè)字符讀取
            $write("%c", char_buf[7:0]) ; //不換行逐次打印單個(gè)字符
         end
         $write(".\n") ;
      end

      $ungetc("1", fd) ;            //連續(xù)寫(xiě)3次文件緩沖區(qū)
      $ungetc("2", fd) ;
      $ungetc("3", fd) ;
      char_buf[7:0]   = $fgetc(fd) ;  //read 3
      char_buf[15:8]  = $fgetc(fd) ;  //read 2
      char_buf[23:16] = $fgetc(fd) ;  //read 1,read buffer end
      char_buf[31:24] = $fgetc(fd) ;  //read a
      $display("Read char after $ungetc: %s", char_buf);
      $fclose(fd);
   end

仿真結(jié)果如下。

由圖可知,?$fgetc? 讀取的 13 個(gè)字符正確,讀取字符包括了換行符。

?$ungetc? 向文件緩沖區(qū)寫(xiě)字符數(shù)據(jù)后,再用 ?$fgetc? 可讀取文件緩沖區(qū)的字符數(shù)據(jù)。讀寫(xiě)遵循先寫(xiě)后出(FILO, First in Last out)原則,相當(dāng)于壓棧。字符數(shù)據(jù)先寫(xiě)"123"時(shí),讀出數(shù)據(jù)為"321"。

文件緩沖區(qū)讀取完畢后,再進(jìn)行字符數(shù)據(jù)讀取時(shí),讀出的數(shù)據(jù)依然緊隨上一次文件讀取的位置,即 log 中"a123"中的字符"a"。

此過(guò)程中,文件 DATA_RD.HEX 內(nèi)容一直沒(méi)有改變。


$fgets 調(diào)用舉例

   //(4.2) read line
   integer      code ;
   reg [99:0]   line_buf [9:0] ;
   initial begin
      #31 ;
      fd = $fopen("DATA_RD.HEX", "r");
      err = $ferror(fd, str);
      if (!err) begin
         for (i=0; i<6; i++) begin  //按字符串格式逐行讀取
            code = $fgets(line_buf[i], fd) ;  //末尾含"\n",將打印2行
            $display("Get line data%d: %s", i, line_buf[i]) ;
         end
      end
      //十六進(jìn)制顯示,將顯示對(duì)應(yīng)的 ASCIII 碼字
      $display("Show hex line data%d: %h", 2, line_buf[2]) ;
      $display("Show hex line data%d: %h", 4, line_buf[4]) ;
      $fclose(fd) ;
   end

仿真結(jié)果如下。

前 4 行數(shù)據(jù)按照字符串類型讀取和顯示,結(jié)果正常。

讀取文件第 5 行數(shù)據(jù)時(shí),由于變量 line_buf 位寬 100 的限制,文件內(nèi)容"New data1: 80000003 "需要分 2 次才能完成讀取。

因?yàn)槊恳恍心┪舶瑩Q行符"\n",所以使用 ?$display? 函數(shù)打印時(shí),會(huì)多出一行空行。

按照字符串型讀取、并對(duì)數(shù)據(jù)進(jìn)行十六進(jìn)制顯示時(shí),并不能直觀的顯示出文件對(duì)應(yīng)的數(shù)據(jù)內(nèi)容。例如第二行內(nèi)容并沒(méi)有顯示"12345678,"而是顯示其對(duì)應(yīng)的 ASCII 碼。所以 $fgets 任務(wù)讀取時(shí)是按照字符串類型讀取的,這里需要注意。


$fscanf,$sscanf 調(diào)用舉例

   //(4.3) $fscanf/$sscanf
   reg [31:0]   data_buf [9:0] ;
   reg [63:0]   string_buf [9:0] ;
   reg [31:0]   data_get ;
   reg [63:0]   data_test ;
   initial begin
      #32 ;
      fd = $fopen("DATA_RD.HEX", "r");
      err = $ferror(fd, str);
      if (!err) begin
         for (i=0; i<4; i++) begin
            //前4行數(shù)據(jù)按照十六進(jìn)制讀取和顯示
            code = $fscanf(fd, "%h", data_buf[i]);
            $display("$fscanf read data%d: %h", i, data_buf[i]) ;
         end
         for (i=4; i<6; i++) begin
            //后2行數(shù)據(jù)按照字符串類型讀取和顯示
            code = $fscanf(fd, "%s", string_buf[i]);
            $display("$fscanf read data%d: %s", i, string_buf[i]) ;
         end
      end

      //(1) $sscanf 源變量 data_test 為字符串類型
      data_test = "fedcba98" ;
      code = $sscanf(data_test, "%h", data_get);
      $display("$sscanf read data0: %h", data_get) ;
      //(2) $sscanf: 將源變量 data_test 先轉(zhuǎn)為字符串變量
      code = $sformat(data_test, "%h", data_buf[2]);
      code = $sscanf(data_test, "%h", data_get);
      //直接輸入十六進(jìn)制變量是不建議的
      //code = $sscanf(data_buf[2], "%h", data_get);
      $display("$sscanf read data0: %h", data_get) ;
      $fclose(fd) ;
   end

仿真結(jié)果如下。

利用 ?$fscanf? 對(duì)文件前 4 行內(nèi)容按照十六進(jìn)制讀取和顯示,后 2 行內(nèi)容按照字符串型讀取和顯示,均正常。

利用 ?$sscanf? 讀取源寄存器內(nèi)容然后搬移到目的寄存器時(shí),源寄存器中的內(nèi)容應(yīng)該為字符串型數(shù)據(jù)。

例如,利用 ?$sscanf? 將十六進(jìn)制的數(shù)據(jù) data_buf[2] 搬移到寄存器變量 data_get 時(shí),可以先利用寫(xiě)字符串任務(wù) ?$sformat? 將源變量 data_buf[2] 的內(nèi)容轉(zhuǎn)為字符串型,存放在變量 data_test 中。然后再利用 ?$sscanf? 按照十六進(jìn)制將 data_test 中的內(nèi)容搬移到變量 data_get 中。此時(shí)按照十六進(jìn)制格式打印變量 data_get 會(huì)顯示正常。

如果直接利用 ?$sscanf? 將十六進(jìn)制格式的數(shù)據(jù) data_buf[2] 直接搬移到變量 data_get 中,則 data_get 中的內(nèi)容將會(huì)是異常的。

偷偷告訴你,寄存器之間是可以直接賦值的!??!


$fread 調(diào)用舉例

   //(4.4) $fread
   reg [71:0]   bin_buf [3:0] ; //每行有8個(gè)字型數(shù)據(jù)和1個(gè)換行符
   reg [143:0]  bin_reg ;
   initial begin
      #40 ;
      fd = $fopen("DATA_RD.HEX", "r");
      err = $ferror(fd, str);
      if (!err) begin
         code = $fread(bin_buf, fd, 0, 4); //數(shù)組型讀取,讀取4次
         $display("$fread read data %h", bin_buf[0]) ;//十六進(jìn)制顯示
         $display("$fread read data %h", bin_buf[1]) ;
         $display("$fread read data %s", bin_buf[2]) ;//字符串顯示
         $display("$fread read data %s", bin_buf[3]) ;
      end

      fd = $fopen("DATA_RD.HEX", "r");
      code = $fread(bin_reg, fd); //單個(gè)寄存器讀取
      $display("$fread read data %h", bin_reg) ;
      $fclose(fd) ;
   end

仿真結(jié)果如下。

?$fread? 按二進(jìn)制讀取文件時(shí) ,起始地址和讀取長(zhǎng)度都是設(shè)置數(shù)組型變量的參數(shù)。

如果存儲(chǔ)數(shù)據(jù)的變量類型是非數(shù)組的 reg 型,則只會(huì)進(jìn)行一次讀取,直至 reg 型變量被填充完畢。


文件定位

系統(tǒng)任務(wù) 調(diào)用格式 任務(wù)描述
獲取文件位置 pos = $ftell( fd ) ; 返回文件當(dāng)前位置距離文件首部的偏移量,初始地址為 0
偏移量按照字節(jié)為一單位(8bits)
配合 $fseek 使用
重定位 code = $fseek(fd, offset, type) ; 設(shè)置文件下一個(gè)輸入或輸出的位置
offset 為設(shè)置的偏移量
type 為偏移量的操作類型
--- 0: 設(shè)置位置到偏移地址
--- 1: 設(shè)置位置到當(dāng)前位置加偏移量
--- 2: 設(shè)置位置到文件尾加偏移量,經(jīng)常使用負(fù)數(shù)來(lái)表示文件尾向前的偏移量
無(wú)偏移重定位 code = $rewind( fd ) ; 等價(jià)于 $fseek( fd, 0, 0) ;
判斷文件尾部 code = $feof(fd) ; 判讀是否到文件尾部
檢測(cè)到文件尾部時(shí)返回值為 1,否則為 0

文件 DATA_RD.HEX 內(nèi)容可表示如下。

換行符"\n"為結(jié)束符,則文件大小為:4x9 + 3x20 = 96 byte。


文件定位測(cè)試代碼如下:

   // file position
   reg [31:0]   data4 ;      //寄存器變量長(zhǎng)度為 4bytes
   reg [199:0]  str_long ;
   integer      pos ;
   initial begin
      #40 ;
      fd = $fopen("DATA_RD.HEX", "r");
      err = $ferror(fd, str);
      if (!err) begin
         //first read
         code = $fscanf(fd, "%h", data4);//從0位置開(kāi)始讀
         pos  = $ftell(fd);      //讀8byte后位置為8,坐標(biāo)為(0,8)
         $display("Position after read: %d", pos) ;
         $display("1st read data: %h", data4) ;

         //type = 0
         code = $fseek(fd, 4, 0) ; //從位置4、坐標(biāo)(0,4)開(kāi)始讀
         code = $fscanf(fd, "%h", data4); //讀到換行符停止
         pos  = $ftell(fd);      //讀4byte后位置為8,坐標(biāo)為(0,8)
         $display("type 0: current position: %d", pos) ;
         $display("type 0: read data: %h", data4) ;
         //type = 1
         code = $fseek(fd, 4, 1) ; //從位置4+9=12、坐標(biāo)(1,3)據(jù)開(kāi)始讀
         code = $fscanf(fd, "%h", data4); //讀到換行符停止
         pos  = $ftell(fd);      //讀5byte后位置為17,坐標(biāo)為(1,8)
         $display("type 1: current position: %d", pos) ;
         $display("type 1: read data: %h", data4) ;
         //type = 2
         code = $fseek(fd, -(96-31), 2) ; //從位置31、坐標(biāo)(3,4)開(kāi)始讀
         code = $fscanf(fd, "%h", data4);
         pos  = $ftell(fd);      //讀4byte后位置為35,坐標(biāo)為(3,8)
         $display("type 2: current position: %d", pos) ;
         $display("type 2: read data: %h", data4) ;

         //rewind read
         code   = $rewind(fd) ;//重新將文件指針的位置指向文件首部
         pos    = $ftell(fd);  //此時(shí)位置為 0
         $display("Position after $rewind: %d", pos) ;
         //read all content of file
         while (!$feof(fd)) begin
            code   = $fgets(str_long, fd);
            $write("Read : %s", str_long) ;
         end
         $fclose(fd) ;
      end
   end

仿真結(jié)果如下。

由圖可知 log 末尾多打了一行數(shù)據(jù),這是因?yàn)槲募?nbsp;DATA_RD.TXT 末尾還有一行空白行(換行操作之后的結(jié)果),系統(tǒng)任務(wù) ?$feof? 并不認(rèn)為該空白行為文件尾部,所以返回值仍然為 0。但實(shí)際該行并沒(méi)有數(shù)據(jù),所以讀取的數(shù)據(jù)具有不可控制性。

為消除文件最后一行數(shù)據(jù)中換行符的影響,可將"文件寫(xiě)入"例子中最后一個(gè)寫(xiě)文件系統(tǒng)任務(wù) ?$fdisplay? 替換為 ?$write? 。

其余 log 結(jié)合代碼注釋可知仿真正確,這里不再做統(tǒng)一解釋。


加載存儲(chǔ)器

系統(tǒng)任務(wù) 調(diào)用格式及說(shuō)明
加載十六進(jìn)制文件 $readmemh("fname", mem, start_addr, finish_addr)
  fname 為數(shù)據(jù)文件名字
mem 為數(shù)組型/存儲(chǔ)器型變量
start_addr、finish_addr 分別為起始地址和終止地址
start_addr、finish_addr 可以省略,此時(shí)加載數(shù)據(jù)的停止條件為存儲(chǔ)器變量 mem 被填充完畢,或文件讀取完畢
文件內(nèi)容只應(yīng)該有空白符(或換行、空格符)、二進(jìn)制或十六進(jìn)制數(shù)據(jù)
注釋用"http://"進(jìn)行標(biāo)注,數(shù)據(jù)間建議用換行符區(qū)分
加載二進(jìn)制文件 $readmemb("fname", mem, start_addr, finish_addr)
  用法格式同 $readmemb

文件 DATA_WITHNOTE.HEX 內(nèi)容如下,將此文件的內(nèi)容加載到存儲(chǔ)器變量中。


舉例代碼如下:

   //6 load mem
   reg [31:0]   mem_load [3:0] ;
   initial begin
      #50 ;
      $readmemh("./DATA_WITHNOTE.HEX", mem_load);
      $display("Read memory1: %h", mem_load[0]) ;
      $display("Read memory2: %h", mem_load[1]) ;
      $display("Read memory3: %h", mem_load[2]) ;
      $display("Read memory4: %h", mem_load[3]) ;
   end

仿真結(jié)果如下:


點(diǎn)擊這里下載源碼


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)