前幾天遇到一個使用情景,需要從一個包含各個讀取代碼文件路徑及名字的文件中把文件路徑提取出來,做一個filelist,這裡用到了文本的提取和替換,這裡做個小總結記錄一下。 從網上找了一個作者寫的代碼用來練習。 module asyn_fifo #( //parameter declaration pa ...
前幾天遇到一個使用情景,需要從一個包含各個讀取代碼文件路徑及名字的文件中把文件路徑提取出來,做一個filelist,這裡用到了文本的提取和替換,這裡做個小總結記錄一下。
從網上找了一個作者寫的代碼用來練習。
module asyn_fifo #(
//parameter declaration
parameter ADDR_WIDTH = 4 ,
parameter DATA_WIDTH = 16 ,
parameter ALMOST_FULL_GAP = 3 ,//將滿,離滿還有ALMOST_FULL_GAP時,almost_full有效
parameter ALMOST_EMPTY_GAP = 3 ,//將空,離空還有ALMOST_EMPTY_GAP時,almost_empty有效
parameter FIFO_DEEP = 16
)
(
//fifo write
wr_clk ,
wr_en ,
almost_full ,
full ,
wr_data ,
//fifo read
rd_clk ,
rd_en ,
almost_empty,
empty ,
rd_data ,
wr_reset ,
rd_reset
);
1)先思考寫時鐘方向,首先是寫請求,在不滿且寫使能有效拉高寫請求.
assign wen = wr_en && (!full)
2)其次是寫地址,
always @(posedge wr_clk or negedge wr_reset)
if(!wr_reset)
waddr <= {(ADDR_WIDTH+1){1'b0}};
else if(wen)
waddr <= waddr + 1'b1;
else
waddr <= waddr;
3)將寫地址轉換為格雷碼
always @(posedge wr_clk or negedge wr_reset)
if(!wr_reset)
waddr_gray <= {(ADDR_WIDTH + 1){1'b0}};
else
waddr_gray<= waddr^(waddr>>1);
4)將讀格雷碼轉換到寫時鐘域,準備計算將滿和滿信號了
always @(posedge wr_clk or negedge wr_reset)
if(!wr_reset) begin
raddr_gray_sync <= {(ADDR_WIDTH+1){1'b0}};
raddr_gray_sync_d1 <= {(ADDR_WIDTH+1){1'b0}};
end
else begin
raddr_gray_sync <= raddr_gray;
raddr_gray_sync_d1 <= raddr_gray_sync;
end
5)將讀格雷碼轉換為二進位(這樣有利於將滿信號和FIFO usdws(used words,使用了多少字)的計算)
integer i;
always @(*)
begin
for(i=0;i<ADDR_WIDTH+1;i=i+1)
raddr_gray2bin = ^(raddr_gray_sync_d1>>i);
end
6)寫地址與讀地址間隔計算,寫了多少個字了
always @(*)begin
if(raddr_gray2bin[ADDR_WIDTH] ^ waddr[ADDR_WIDTH])//二進位擴展位為迴圈指示位
wr_gap = raddr_gray2bin[ADDR_WIDTH-1:0] - waddr[ADDR_WIDTH-1:0];
else
wr_gap = FIFO_DEEP + raddr_gray2bin - waddr;
end
7)almost full信號產生
always @(posedge wr_clk or negedge wr_reset)begin
if(!wr_reset)
almost_full <= 1'b0;
else begin
if(wr_gap < ALMOST_FULL_GAP)
almost_full <= 1'b1;
else
almost_full <= 1'b0;
end
end
8)full信號產生
always @(posedge wr_clk or negedge wr_reset)begin
if(!wr_reset)
full <= 1'b0;
else
full <= (wr_gap==1)&&wen;
9)再來寫讀時鐘方向,其實與寫時鐘方向堆成,首先是讀請求,
assign ren = rd_en &&(!empty);
10)FIFO讀地址的產生
always @(posedge rd_clk or negedge rd_reset)
if(!rd_reset)
raddr <= {(ADDR_WIDTH+1){1'b0}};
else if(ren)
raddr <= raddr + 1'b1;
else
raddr <= raddr;
11)讀地址轉變為讀格雷碼
always @(posedge rd_clk or negedge rd_reset)
if(!rd_reset)
raddr_gray <= {(ADDR_WIDTH + 1){1'b0}};
else
raddr_gray <= raddr^(raddr>>1);
12)寫地址同步到讀時鐘域
always @(posedge rd_clk or negedge rd_reset)begin
if(!rd_reset) begin
waddr_gray_sync <= {(ADDR_WIDTH+1){1'b0}};
waddr_gray_sync_d1 <= {(ADDR_WIDTH+1){1'b0}};
end
else begin
waddr_gray_sync <= waddr_gray;
waddr_gray_sync_d1 <= waddr_gray_sync;
end
end
13)寫地址格雷碼變成二進位,便於讀格子的計算
integer j;
always @(*)begin
for(j=0;j<ADDR_WIDTH+1;j=j+1)
waddr_gray2bin = ^(waddr_gray_sync_d1>>i);
end
14)讀格子的計算—即還有多少數據未讀
always @(*)
rd_gap = waddr_gray2bin - raddr;
15)almost_empty信號產生
always @(posedge rd_clk or negedge rd_reset)begin
if(!rd_reset)
almost_empty <= 1'b1;
else begin
if(rd_gap < ALMOST_EMPTY_GAP)
almost_empty <= 1'b1;
else
almost_empty <= 1'b0;
end
end
16)產生empty信號
always @(posedge rd_clk or negedge rd_reset)begin
if(rd_reset)
empty <= 1'b1;//複位了FIFO為空
else
empty <= (rd_gap == 1) & rd_en;
end
17)例化雙口RAM,在寫請求有效時將數據存放到裡面,併在讀請求有效時讀出數據。
ram ram_inst#(
parameter RAM_WIDTH = 4
)(
.wr_clk(wr_clk),
.addra(wr_addr),
.dina(wr_data),
.wra(wen),
///////
.rd_clk(rd_clk),
.addrb(rd_addr),
.dina(rd_data),
.rdb(ren)
);
練習1-將作者寫的步驟文字,即x)開頭的文字提取出來
使用v/pattern/d來實現,這個命令的意思是將匹配pattern的行提取出來,其中pattern就是你定義的匹配模式,如下圖所示。其中^代表匹配行首,\d代表匹配一個數字,這樣我們就完成了提取。那如果我想刪除掉這些而只保留代碼呢?
:v/^\d/d
我們使用g/pattern/d來實現,這個命令的意思是將匹配pattern的行刪除而保留其他。
:g/^\d/d
以此類推,重點是會寫pattern,這裡有個作者已經總結的很好了,可以參考這個作者的總結,已經總結很全了。 https://blog.csdn.net/lazyclough/article/details/6193398
練習3-獲取該模塊的信號列表(先提取再替換)
第一步:
可以看出信號列表都是以,結尾,除了最後一個,所以可以先複製最後一個信號,然後使用如下命令開始提取。
:v/.*,/d
其中.*分別代表任意字元,任意多個,“,”就是匹配“,”,得到瞭如下代碼。
第二步:
可以看到,還有些以“.”開頭的和以“parameter”開頭的我們不需要,所以可以使用如下命令去除(這個時候代碼已經很少了其實可以用“ndd”刪除n行,或者滑鼠選中按“d”的方法來操作了,但這裡是為了做練習,所以不用它們):
:g/^\s\s\./d
其中^匹配行首,\s\s匹配兩個空格,也可以用\s{2},{2}代表匹配兩次,.匹配“.”,然後代碼如下。
然後輸入命令
:g/parameter/d
得到如下代碼
第三步:
然後我們需要將“,”全部去除,使用替換命令:range s/pattern/new string/command(其實這列逗號排列是整齊的,可以用列操作很方便的刪除,但是我們為了練習)。
:%s/,//g
其中range的%代表全局匹配替換,也可以用行號來指定匹配替換的範圍,g代表匹配到的全部替換,gc代表全部替換但是每次替換前要詢問。得到的代碼如下:
到這裡基本就完成了,採用列操作或者上述辦法去除掉開頭的空格,再把之前複製的最後一個信號複製上去就完成任務。