vim技巧--提取文字與文字替換

郭同学的IC修炼笔记發表於2024-03-11

前幾天遇到一個使用情景,需要從一個包含各個讀取程式碼檔案路徑及名字的檔案中把檔案路徑提取出來,做一個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代表全部替換但是每次替換前要詢問。得到的程式碼如下:

到這裡基本就完成了,採用列操作或者上述辦法去除掉開頭的空格,再把之前複製的最後一個訊號複製上去就完成任務。

相關文章