上一篇文章IC君介紹了二進位搜索算法(二分法查找)在實際電路中的應用,而且文末也給出了一個電路設計的spec,可惜也沒人給出代碼或者電路,沒辦法只能IC君自己上了
Linux 的創始人 Linus 曾經說過:
Talk is cheap. Show me the code.下面IC君就給出二進位搜索算法的verilog代碼實現。請注意下面的內容已經進入IC君相對不熟悉領域,很有可能犯錯誤。不過發現錯誤的過程就是成長的過程,所以大家要勇敢的去做,不要怕犯錯。若有錯誤,請大家不吝指教!
首先再寫出6位二進位搜索SAR logic電路的SPEC:
Input
OUTPUT
看到這張圖和spec很容易就想到用Verilog來實現,具體代碼如下:
`timescale 1ns/10ps
module sar (pucode,clk,incr,rstb);
input clk;
input incr;
input rstb;
output[5:0] pucode;
wire incr;
wire incrb;
reg [2:0] count;
reg [5:0] pucode;
always@(posedge clk or negedge rstb)
if(!rstb)
begin
//初始轉態
pucode<=6'b100000;
end
else
begin
case(count)
0:
begin
pucode[5]<=pucode[5]^~incr;
pucode[4]<=1'b1;
end
1:
begin
pucode[4]<=pucode[4]^~incr;
pucode[3]<=1'b1;
end
2:
begin
pucode[3]<=pucode[3]^~incr;
pucode[2]<=1'b1;
end
3:
begin
pucode[2]<=pucode[2]^~incr;
pucode[1]<=1'b1;
end
4:
begin
pucode[1]<=pucode[1]^~incr;
pucode[0]<=1'b1;
end
5:
begin
pucode[0]<=1'b1;
end
default: pucode<=6'b100000;
endcase
end
//6bit的SAR 一共需要走5步,也就是5個CLK周期後就可以得到最後的結果
//所以底下是一個計數為5的計數器
always@(posedge clk or negedge rstb)
if(!rstb)
begin
count<=3'b0;
end
else
begin
if(count<5)
count<=count+1'b1;
end
endmodule
在Design Complier下進行邏輯綜合,得到的電路如下
總共用到了97個cell:
一共用到了9個DFF,其中3個是給Counter計數用的,6個是給pucode[5:0]用的,符合我們的預期。但是看起來面積好像有點大,代碼風格也不太像時序狀態機的風格。
接下來我們修改一下代碼,讓它更符合時序狀態機的風格。
`timescale 1ns/10ps
module sar_new (pucode,clk,incr,rstb);
input clk;
input incr;
input rstb;
output[5:0] pucode;
wire incr;
wire incrb;
reg [2:0] count;
reg [5:0] pucode;
reg [5:0] nxt_pucode;
//狀態機的切換
always@(posedge clk or negedge rstb)
if(!rstb)
begin
pucode<=6'b100000;
end
else
pucode<=nxt_pucode;
always@(pucode or incr)
case (pucode)
//窮舉所有可能的code
6'b100000: nxt_pucode=incr?6'b110000:6'b010000;
6'b110000: nxt_pucode=incr?6'b111000:6'b101000;
6'b111000: nxt_pucode=incr?6'b111100:6'b110100;
6'b111100: nxt_pucode=incr?6'b111110:6'b111010;
6'b111110: nxt_pucode=incr?6'b111111:6'b111101;
6'b010000: nxt_pucode=incr?6'b011000:6'b001000;
6'b011000: nxt_pucode=incr?6'b011100:6'b010100;
6'b011100: nxt_pucode=incr?6'b011110:6'b011010;
6'b011110: nxt_pucode=incr?6'b011111:6'b011101;
6'b001000: nxt_pucode=incr?6'b001100:6'b000100;
6'b001100: nxt_pucode=incr?6'b001110:6'b001010;
6'b001110: nxt_pucode=incr?6'b001111:6'b001101;
6'b000100: nxt_pucode=incr?6'b000110:6'b000010;
6'b000110: nxt_pucode=incr?6'b000111:6'b000101;
6'b000010: nxt_pucode=incr?6'b000011:6'b000001;
//next group
6'b101000: nxt_pucode=incr?6'b101100:6'b100100;
6'b101100: nxt_pucode=incr?6'b101110:6'b101010;
6'b101110: nxt_pucode=incr?6'b101111:6'b101101;
6'b100100: nxt_pucode=incr?6'b100110:6'b100010;
6'b100110: nxt_pucode=incr?6'b100111:6'b100101;
6'b100010: nxt_pucode=incr?6'b100011:6'b100001;
//next group
6'b110100: nxt_pucode=incr?6'b110110:6'b110010;
6'b110110: nxt_pucode=incr?6'b110111:6'b110101;
6'b110010: nxt_pucode=incr?6'b110011:6'b110001;
//next group
6'b111010: nxt_pucode=incr?6'b111011:6'b111001;
6'b001010: nxt_pucode=incr?6'b001011:6'b001001;
//next group
6'b010100: nxt_pucode=incr?6'b010110:6'b010010;
6'b010110: nxt_pucode=incr?6'b010111:6'b010101;
6'b010010: nxt_pucode=incr?6'b010011:6'b010001;
6'b011010: nxt_pucode=incr?6'b011011:6'b011001;
6'b101010: nxt_pucode=incr?6'b101011:6'b101001;
//impossible code
6'b000000: nxt_pucode=6'b000001;
//the least bit=1 , keep code
default: nxt_pucode=pucode;
//6'bxxxxx1: nxt_pucode=pucode;
endcase
endmodule
最終綜合出來的電路如下:
總共用到了44個cell:
最終只用了5個DFF,總共只用了44個cell, 總面積是146;
而前一個代碼總共用了97個cell,總面積283,新代碼綜合出來的面積幾乎是前一個代碼的一半。
通過比較可以發現,不同的verilog代碼風格綜合出來的電路有著巨大的差異。數字前端工程師應該花更多的時間思考自己的代碼是不是可以用其它方式來實現,有沒有更好的風格。當然我在這方面也是初學者,希望大家多多指教。
下一篇文章預告:
如何驗證上面2個版本的verilog代碼,敬請繼續關注!