HDL檔案操作總結
VHDL
檔案操作都在tb中,因為涉及到作業系統,所以無法綜合。
在vhdl中,檔案被看作 行 組成的一維陣列。
預先要把兩個檔案讀寫相關的庫宣告。
1 use STD.TEXTIO.all;
2 use ieee.STD_LOGIC_TEXTIO.all;
首先要宣告用來儲存檔案資料的陣列,以一個80X64的32位浮點影象資料為例。
1 type TYPE_MdlImgDat32_r is array (0 to 79) of std_logic_vector(31 downto 0);
2 type TYPE_MdlImgDat32 is array (0 to 63) of TYPE_MdlImgDat32_r;
首先定義了一個80大小的一維陣列型別,陣列成員為32位std_logic_vector
然後再定義了一個64大小的一維陣列型別,陣列成員型別為一維陣列。
這樣我們就得到了一個二維陣列型別,當然我們也可以用下面的方法來直接定義:
type matrix is array(0 to 63, 79 downto 0) of std_logic_vector;
在定義完用來存數的陣列結構之後,我們需要申明檔案控制代碼。
1 file FILE_MdlImg : TEXT;
2 file FILE_MdlImg_rad : TEXT ;
3 file FILE_MdlImg_mag : TEXT;
4 file FILE_RefImg : TEXT;
5 file FILE_RefImg_Software : TEXT;
6 file FILE_MdlImg_Software : TEXT;
申明完檔案控制代碼之後,記得要把前面定義的陣列初始化。、
1 variable vMdlImgDat32 : TYPE_MdlImgDat32 := (others => (others => (others => '0')));
因為檔案內部是一行一個數據,而且是32位的HEX表示,所以還需要宣告行控制代碼
1 variable MdlL_OUT : LINE;
2
3 variable RefL_OUT : LINE;
4
5 variable RefL_OUT_Software : LINE;
6
7 variable MdlL_OUT_Software : LINE;
把檔案讀入二維陣列中
file_open,第一個引數是前面定義的檔案控制代碼,後面是檔案的絕對路徑,最後是讀或者寫模式。
readline,第一個引數還是檔案控制代碼,第二個是前面定義的行控制代碼。
hread,第一個引數是行控制代碼,第二個引數是二維數組裡面的某個元素。
file_close,關閉之前開啟的檔案。
1 FILE_OPEN(FILE_MdlImg_Software, "C:\Users\MekiX\Documents\Recorded_projects\cal_mag\mag_cal_ready_valid\Data\srcimg_oactave__80x64_hex.txt", READ_MODE);
2 ReadMdlImgFromFiles : for i in 0 to 63 loop
3 loopX : for j in 0 to 79 loop
4 READLINE(FILE_MdlImg_Software, MdlL_OUT_Software);
5 HREAD(MdlL_OUT_Software, vMdlImgDat32(i)(j));
6 end loop;
7 end loop;
8 FILE_CLOSE(FILE_MdlImg_Software);
總結一下就是,先把檔案開啟,再把檔案的行讀取,之後再把檔案的行內元素依次寫入到二維陣列中。(readline應該可以放到loopx上面,還未驗證)。
對於寫操作,基本類似。
先也是file_open,
HWRITE,第一個引數是行控制代碼,第二個資料,第三個是游標向右移動的位置,10是移動的長度。32位的HEX表示應該是8,寫成10留了點餘量。資料前面會有兩個空格。寫入方式也就是一個數據一行。
WRITELINE,第一個引數是檔案控制代碼,第二個是行變數。
最後再把檔案關閉。
生成的檔案在vivado工程的sim資料夾下.
1 FILE_OPEN(FILE_MdlImg_rad, "MdlImg_rad.txt", WRITE_MODE);
2 wait until rising_edge(aclk);
3
4 while m_axis_rad_tuser = '0' loop
5 wait until rising_edge(aclk);
6 if (m_axis_rad_tvalid and m_axis_rad_tready) = '1'then
7 HWRITE(MdlL_OUT, m_axis_rad_tdata, right, 10); 9 WRITELINE(FILE_MdlImg_rad, MdlL_OUT);
10 else
11 wait until (m_axis_rad_tvalid and m_axis_rad_tready) = '1';
12 wait until rising_edge(aclk);
13 HWRITE(MdlL_OUT, m_axis_rad_tdata, right, 10);15 WRITELINE(FILE_MdlImg_rad, MdlL_OUT);
16 end if;
17 end loop;
18 FILE_CLOSE(FILE_MdlImg_rad);
Verilog
以下都是task型別的.
讀檔案一般使用$readmemb,$readmemh,分別是讀二進位制和16進位制的檔案。
同樣需要先建立一個數組
1 reg[31:0] mem[79:0][63:0]//多維陣列是verilog2001的新功能,之前只支援一維
但是不需要再開啟檔案
1 $readmemb("file1.txt",mem);
上面的檔案可以使用絕對地址,只需要把"\"換成"/".
寫檔案一般是
首先定義一個整數型別的檔案指標,然後用$fopen開啟檔案.
$fopen實際上可以有兩個引數,中間用 , 隔開,後面一個是mode
常用mode包括
“w",“wb" 清除檔案內容並從檔案頭開始寫,如果不存在就建立檔案,只寫模式。(預設模式) .
“w+",'w+b","wb+"清除檔案內容並從檔案頭開始讀寫,如果不存在就建立檔案,可讀寫模式.
"a","ab" 從檔案末尾開始寫,如果不存在就建立檔案,只寫模式。
“a+","a+b","ab+" 檔案末尾開始讀寫,如果不存在就建立檔案,可讀寫模式.
"r","rb" 只讀模式.
"r+","r+b","rb+" 可讀寫方式.
多一個b為binary
1 integer hex_image_80X64; 2 hex_image_80X64 = $fopen("hex_image_80X64.txt")
然後我們向檔案寫入資訊,常用的task有:
$fdisplay,$fwrite,$fstrobe,$fmonitor.格式控制有
%c %C character (low 8 bits)
%d %D decimal %0d for minimum width field
%e %E E format floating point %15.7E
%f %F F format floating point %9.7F
%g %G G general format floating point
%h %H hexadecimal
%l %L library binding information
%m %M hierarchical name, no expression
%o %O octal
%s %S string, 8 bits per character, 2´h00 does not print
%t %T simulation time, expression is $time
%u %U unformatted two value data 0 and 1
%v %V net signal strength
%z %Z unformatted four value data 0, 1, x, z
%5d, %5b.前面的數字類似vhdl,也是長度控制.,也可以直接在task後面加b/h/o,也可以直接把預設格式切換成指定的格式,例如$fdisplayb,就是二進位制.
$fdisplay和 $fwrite在每次被執行的時候都會向檔案中寫入指定格式的資料,區別在於$fdisplay每次執行完畢會新增新的一行,而$fwrite不會.
$fstrobe也是寫入資料但是是在同一時刻所有語句執行完畢之後再執行,舉例:
1 initial
2 #1 a=1;
3 b=0;
4 $fstrobe(hand1,a,b); // 預設格式將ab寫入
5 b=1;
此時,檔名是hand1,寫入的ab都是1;
$fmonitor是在引數變化的時候往檔案裡寫數.
它們的具體格式非常類似c,這也是因為verilog開發的初衷就是為了比VHDL貼近C.舉例如下:
1 f = $fopen("output.txt","w");
2 $fmonitor(f, "%h", acc_out);
3 $fclose(f);
這些task前面的f去掉之後就是在螢幕上顯示而非寫入檔案.而具體的語法區別在於最前面的引數從檔案控制代碼(通過$fopen得到)換成了類似c的字串輸出,舉例如下
1 $monitor("monitor a:%h @ %0t", acc_out, $time);
分別將accout以16進位制替換%h,time替換%0t.同時,與c語言類似,也有
1 \t tab
2 \\ backslash反斜槓
3 \" quote引號
4 %% percent
如果這些task沒有指定輸出或者寫入格式會怎麼樣?
寫入完成之後,呼叫$fclose關閉檔案,引數是整數控制代碼變數而非檔名.
讀取和寫入一般只執行一次,放在initial塊中.
task還有很多,下次用到再寫.