原文連結:https://blog.csdn.net/gemengxia/article/details/108014159
參考公衆号:FPGA探索者
1、設計一個可預置初值的7進制循環計數器。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiNx8FesU2cfdGLwczX0xiRGZkRGZ0Xy9GbvNGL58VZ6l2cscXWq1ENRpXTwEleYVHbHVGcWJDZBJUaUVkTxE1X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLxITO1UDOzQjMlNWM0YzN4YmM2QTMlFDN2EjZzQGNmJ2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
2、康威生命遊戲
3、将下面這段 C 語言描述的串行處理過程,轉換為單拍完成的并行處理,并用可綜合的 Verilog 來描述。
unsigned char cal_table_high_first(unsigned char value)
{
unsigned char i;
unsigned char checksum = value;
for (i=8; i>0; --i)
{
if (checksum & 0x80)
checksum = (checksum << 1) ^ 0x31;
else
checksum = (checksum << 1);
}
return checksum;
}
代碼為
checksum[0] <= data[0]^ data[3]^ data[4]^ data[6];
checksum[1] <= data[1]^ data[4]^ data[5]^ data[7];
checksum[2] <= data[2]^ data[5]^ data[6];
checksum[3] <= data[3]^ data[6]^ data[7];
checksum[4] <= data[0]^ data[3]^ data[6]^ data[7];
checksum[5] <= data[0]^ data[1]^ data[3]^ data[6]^ data[7];
checksum[6] <= data[1]^ data[2]^ data[4]^ data[7];
checksum[7] <= data[2]^ data[3]^ data[5];
4、用一條assign語句重寫代碼
wire [7:0] in,a,b;
reg [7:0] out;
genvar i;
generate
for (i=0;i<8;i++)
begin:gen_block
[email protected](*)begin
if(in[i])
out[i] = a[i] ^ b[i];
else begin
if(i==0)
out[i]=1’b0;
else
out[i]=in[i-1];
end
end
end
endgenerate
分析:用一條assign語句改寫,說明可以将if-else判斷和for循環去掉,其中必然有規律。
先從if-else 語句入手,if-else 可以寫成以下形式
等式左=(判斷條件成立 & 等式右)|(~判斷條件成立 & 等式右)
進而得出
out[i]= ( in[i] & ( a[i] ^ b[i]) ) | ( ~in[i] & ( !(!i) & in[i-1] ) ) ;
是以得到
out_3 = (in& (a^b)) | (~in & ( in <<1 ));
仿真代碼如下
reg [7:0]in,a,b;
reg[7:0]out;
wire[7:0]out_1;
reg[7:0]out_2;
genvar i;
generate
for (i=0;i<8;i=i+1)
begin:gen_block
[email protected](*)
begin
out_2[i]= ( in[i] & ( a[i] ^ b[i]) ) | ( ~in[i] & ( (!(!i)) & in[i-1] ) ) ;
if(in[i])
out[i] = a[i] ^ b[i];
else
begin
if(i==0)
out[i]=1'b0;
else
out[i]=in[i-1];
end
end
end
endgenerate
initial
begin
#0
in =0;
a=0;
b=0;
end
always #20 a=a+1;
always #20 b=b+3;
always #20 in=in+1;
assign out_1 = (in& (a^b)) | (~in & ( in<<1 ));
5、以下代碼綜合出來的D觸發器的D端邏輯表達式為
always @( posedge clk or negedge rst_n)
if(~rst_n)
q<= 1'b0;
else if(set)
q<= 1'b1;
else if(wr)
q<= wdata;
題中隐含着當條件不成立時q保持不變。
根據if-else 優先級可得如下
q=rst_n&(set,wr,wdata,q組合);
q=rst_n&( set | (wr,wdata,q組合) )
q=rst_n&( set | wr & wdata | ~ wr & q);
這裡需要注意操作符的優先級。
6、鎖存器(latch)和觸發器(filp-flop)的概念和差別?為什麼多用register。行為級描述中latch如何産生的?
解析:
1)鎖存器是什麼?
從概念上講,鎖存器是電平觸發的存儲單元,資料存儲的動作取決于輸入時鐘(或者使能)信号的電平值。簡單而言,鎖存器的輸入有資料信号和使能信号,當處于使能狀态時,輸出随着輸入變化而變化,當不處于使能狀态時,輸入信号怎麼變化都不會影響輸出。
2)觸發器是什麼?
觸發器是對脈沖邊沿敏感的器件,它的變化隻會在時鐘的上升沿或者下降沿到來的瞬間變化。
3)差別?
鎖存器是電平觸發的,觸發器是邊沿觸發的。如果是電平觸發的,當使能的時候,如果輸入信号不穩定,那麼輸出就會出現毛刺。而觸發器就不會出現這種情況,它的變化隻會在邊沿有效的時候觸發。
4)register是什麼?
register是寄存器,用來暫時存放參與運算的資料和運算結果。在實際的數字系統中,通常把能夠用來存儲一組二進制代碼的同步時序邏輯電路稱為寄存器。由于觸發器有記憶功能,是以利用觸發器可以友善地構成寄存器。由于一個觸發器能夠存儲一位二進制碼,是以把n個觸發器的時鐘端口連接配接起來就能構成一個存儲n位二進制碼的寄存器。
5)為什麼多用register?
換個角度講,為什麼少用latch呢?首先,latch是電平觸發的,這樣就容易産生毛刺;其次,latch将靜态時序變得極其複雜;再者latch會浪費硬體資源(對FPGA而言)。因為FPGA當中,是沒有latch單元的,要生成latch單元需要耗費其他資源。
以xilinx器件為例,如下圖所示,是slice的結構,每個slice包含兩列觸發器,第一列隻可以配置成觸發器,第二列可以配置成鎖存器和觸發器,如果第二列的觸發器被配置成鎖存器,第一列觸發器就不能用了。
7、設計一個1101序列檢測子產品,當檢測到1101時,将輸出置高。
原文連結:FPGA探索者公衆号
Mealy型:輸出信号不僅取決于目前狀态,還取決于輸入;
Moore型:輸出信号隻取決于目前狀态;
實作相同的功能時,**Mealy型比Moore型能節省一個狀态(**大部分情況下能夠節省一個觸發器資源,其餘情況下使用的資源相同,視狀态數和狀态編碼方式決定),Mealy型比Moore型輸出超前一個時鐘周期。
狀态機寫法
- 一段式:一個always塊,既描述狀态轉移,又描述狀态的輸入輸出,目前狀态用寄存器輸出。一段式寫法簡單,但是不利于維護,狀态擴充麻煩,狀态複雜時易出錯,不推薦;
- 二段式:兩個always塊,時序邏輯與組合邏輯分開,一個always塊采用同步時序描述狀态轉移;另一個always塊采用組合邏輯判斷狀态轉移條件,描述狀态轉移規律以及輸出,目前狀态用組合邏輯輸出,可能出現競争冒險,産生毛刺,而且不利于限制,不利于綜合器和布局布線器實作高性能的設計;
- 三段式:三個always塊,一個always子產品采用同步時序描述狀态轉移;一個always采用組合邏輯判斷狀态轉移條件,描述狀态轉移規律;第三個always塊使用同步時序描述狀态輸出,寄存器輸出。
解題:
使用三段式FSM有限狀态機進行序列檢測,使用摩爾型狀态機,最終輸出與輸入無關。
使用狀态機檢測“1101”,串行輸入的測試序列為“11101101011010”,輸出信号為valid有效信号,檢測到時輸出高,否則為低,考慮序列疊加情況,比如“1101101”,則有兩個“1101”,
module FSM_sequDection_1(
clk,
rst_n,
data_in,
data_valid
);
input clk;
input rst_n;
input data_in;
output reg data_valid;
//定義狀态,這裡采用的獨熱碼(One-Hot),FPGA中推薦用獨熱碼和格雷碼(Gray)
//狀态較少時(4-24個狀态)用獨熱碼效果好,狀态多時格雷碼(狀态數大于24)效果好
parameter IDLE = 5'b00001;
parameter S1 = 5'b00010;
parameter S2 = 5'b00100;
parameter S3 = 5'b01000;
parameter S4 = 5'b10000;
reg [4:0] current_state; //現态
reg [4:0] next_state; //次态
//三段式FSM,第一段,同步時序邏輯,描述狀态切換,這裡的寫法固定
always @ ( posedge clk )
begin
if(!rst_n ) begin
current_state<= IDLE;
end
elsebegin
current_state<= next_state;
end
end
//三段式FSM,第二段,組合邏輯,判斷狀态轉移條件,描述狀态轉移規律
//這裡面用"="指派和用"<="沒差別
always @ (*)
begin
if(!rst_n ) begin
next_state<= IDLE;
end
elsebegin
case(current_state )
IDLE: begin
if(data_in == 1 )
next_state<= S1;
else
next_state<= IDLE;
end
S1 : begin
if(data_in == 1 )
next_state<= S2;
else
next_state<= IDLE;
end
S2 : begin
if(data_in == 0 )
next_state<= S3;
else
next_state<= S2;
end
S3 : begin
if(data_in == 1 )
next_state<= S4;
else
next_state<= IDLE;
end
S4 : begin
if(data_in == 1 )
next_state<= S2;
else
next_state<= IDLE;
end
default : begin
next_state<= IDLE;
end
endcase
end
end
//三段式FSM,第三段,同步時序邏輯,描述狀态輸出,摩爾型輸出
always @ ( posedge clk )
begin
if(!rst_n ) begin
data_valid<= 1'b0;
end
elsebegin
case(next_state )
S4 : data_valid <= 1'b1;
default : data_valid <= 1'b0;
endcase
end
end
endmodule
仿真測試檔案(TestBench):
/************************************************************
** Author :FPGA探索者公衆号
** Times :2020-7-7
************************************************************/
`timescale 1 ns/1 ns
module FSM_2_tb();
reg clk;
reg rst_n;
reg data_in;
wire data_valid;
FSM_SequDetection U1(
.clk(clk),
.rst_n(rst_n),
.data_in(data_in),
.data_valid(data_valid)
);
initial
begin
clk = 0;
rst_n = 0;
#15;
rst_n = 1;
data_in = 1;#10;
data_in = 1;#10;
data_in = 1;#10;
data_in = 0;#10;
data_in = 1;#10;
data_in = 1;#10;
data_in = 0;#10;
data_in = 1;#10;
data_in = 0;#10;
data_in = 1;#10;
data_in = 1;#10;
data_in = 0;#10;
data_in = 1;#10;
data_in = 0;#10;
#50;
$stop; //停止仿真
end
always #5 clk = ~clk;
endmodule