owned this note
owned this note
Published
Linked with GitHub
F# verilog練習紀錄
## Moore Machine (摩爾狀態機)
摩爾型有限狀態機(英語:Moore machine)是指輸出只由當前的狀態所確定的有限狀態自動機。具體來說會結合一個輸入,然後根據現在狀態判斷下一個狀態,摩爾型有限狀態機的狀態圖對每個狀態包含一個輸出訊號
### Lemmings1
```verilog=
module top_module(
input clk,
input areset, // Freshly brainwashed Lemmings walk left.
input bump_left,
input bump_right,
output walk_left,
output walk_right); //
// parameter LEFT=0, RIGHT=1, ...
parameter LEFT = 0, RIGHT = 1;
reg state, next_state;
always @(*) begin
next_state = state;
case(state)
LEFT : next_state = bump_left? RIGHT : LEFT;
RIGHT : next_state = bump_right? LEFT : RIGHT;
endcase
// State transition logic
end
always @(posedge clk, posedge areset) begin
// State flip-flops with asynchronous reset
if (areset)
state <= LEFT;
else
state <= next_state ;
end
// Output logic
assign walk_left = (state == LEFT);
assign walk_right = (state == RIGHT);
endmodule
```
### Lemmings2
跟Lemmings1差異在於,除了能夠向左和向右行走之外,當下面的地面消失時,Lemmings 會掉落(會喊 "aaah!")。
除了向左和向右行走以及在撞到障礙物時改變方向之外,當 ground=0 時,Lemming 會掉落。當地面重新出現(ground=1)時,Lemming 會恢復到掉落前相同的行走方向。掉落時受到撞擊不會影響其行走方向,而且在地面消失(ground = 0)或在地面重新出現時仍處於掉落狀態時(aash = 1)受到撞擊,也不會影響行走方向。
```verilog=
module top_module(
input clk,
input areset, // Freshly brainwashed Lemmings walk left.
input bump_left,
input bump_right,
input ground,
output walk_left,
output walk_right,
output aaah );
parameter LEFT = 0, RIGHT = 1, GROUND_LEFT = 2 , GROUND_RIGHT = 3;
reg [1:0]state;
reg [1:0]next;
always@(*)begin
case(state)
LEFT : next = ground? (bump_left?RIGHT:LEFT) : GROUND_LEFT;
RIGHT : next = ground? (bump_right? LEFT : RIGHT) : GROUND_RIGHT;
GROUND_LEFT : next = ground ? LEFT : GROUND_LEFT;
GROUND_RIGHT: next =ground ? RIGHT : GROUND_RIGHT;
default: next = LEFT;
endcase
end
always@(posedge clk, posedge areset)begin
if (areset)
state <= LEFT;
else
state <= next;
end
assign walk_left = (state == LEFT);
assign walk_right = (state == RIGHT);
assign aaah = (state == GROUND_LEFT || state == GROUND_RIGHT);
endmodule
```
### Lemmings3
跟 Lemmings2 類似,只是要多新增兩個的digging狀態,如果有在地面(ground == 1),就要先判斷是否挖洞,否則就可以往左或右前進
```verilog=
module top_module(
input clk,
input areset, // Freshly brainwashed Lemmings walk left.
input bump_left,
input bump_right,
input ground,
input dig,
output walk_left,
output walk_right,
output aaah,
output digging );
parameter LEFT = 0, RIGHT = 1, GROUND_LEFT = 2 , GROUND_RIGHT = 3, DIGGING_LEFT = 4, DIGGING_RIGHT = 5;
reg [2:0]state;
reg [2:0]next;
always@(*)begin
case(state)
LEFT : next = ground? (dig ? DIGGING_LEFT: (bump_left?RIGHT:LEFT)) : GROUND_LEFT;
RIGHT : next = ground? (dig ? DIGGING_RIGHT : (bump_right? LEFT : RIGHT)) : GROUND_RIGHT;
GROUND_LEFT : next = ground ? LEFT : GROUND_LEFT;
GROUND_RIGHT: next =ground ? RIGHT : GROUND_RIGHT;
DIGGING_LEFT: next= ground ? DIGGING_LEFT : GROUND_LEFT;
DIGGING_RIGHT : next = ground ? DIGGING_RIGHT :GROUND_RIGHT;
default: next = LEFT;
endcase
end
always@(posedge clk, posedge areset)begin
if (areset)
state <= LEFT;
else
state <= next;
end
assign walk_left = (state == LEFT);
assign walk_right = (state == RIGHT);
assign digging =(state == DIGGING_LEFT || state == DIGGING_RIGHT);
assign aaah = (state == GROUND_LEFT || state == GROUND_RIGHT);
endmodule
```
### Lemmings4
```verilog=
module top_module(
input clk,
input areset, // Freshly brainwashed Lemmings walk left.
input bump_left,
input bump_right,
input ground,
input dig,
output walk_left,
output walk_right,
output aaah,
output digging );
parameter LEFT = 0, RIGHT = 1, GROUND_LEFT = 2 , GROUND_RIGHT = 3, DIGGING_LEFT = 4, DIGGING_RIGHT = 5;
parameter SPLATTER = 6, AAAH_END = 7;
reg [2:0]state;
reg [2:0]next;
reg [4:0]counter;
always@(*)begin
case(state)
LEFT : next = ground? (dig ? DIGGING_LEFT: (bump_left?RIGHT:LEFT)) : GROUND_LEFT;
RIGHT : next = ground? (dig ? DIGGING_RIGHT : (bump_right? LEFT : RIGHT)) : GROUND_RIGHT;
GROUND_LEFT : next = ground ? LEFT : (counter == 20 ? SPLATTER : GROUND_LEFT);
GROUND_RIGHT: next =ground ? RIGHT : (counter == 20 ? SPLATTER : GROUND_RIGHT);
DIGGING_LEFT: next= ground ? DIGGING_LEFT : GROUND_LEFT;
DIGGING_RIGHT : next = ground ? DIGGING_RIGHT :GROUND_RIGHT;
SPLATTER: next = ground? AAAH_END : SPLATTER;
AAAH_END : next = AAAH_END;
default: next = LEFT;
endcase
end
always@(posedge clk, posedge areset)begin
if (areset)begin
state <= LEFT;
counter <= 0;
end else if(next == GROUND_LEFT || next == GROUND_RIGHT)begin
state <= next;
counter <= counter + 1;
end else begin
state <= next;
counter <= 0;
end
end
assign walk_left = (state == LEFT);
assign walk_right = (state == RIGHT);
assign digging =(state == DIGGING_LEFT || state == DIGGING_RIGHT);
assign aaah = (state == GROUND_LEFT || state == GROUND_RIGHT || state == SPLATTER);
endmodule
```
正確ex1: https://github.com/M-HHH/HDLBits_Practice_verilog/blob/master/130.%20Lemmings%204.v
```verilog=
//csdn網友提供解答
module top_module(
input clk,
input areset, // Freshly brainwashed Lemmings walk left.
input bump_left,
input bump_right,
input ground,
input dig,
output walk_left,
output walk_right,
output aaah,
output digging
);
parameter LEFT=0, RIGHT=1, FALL_L=2, FALL_R=3, DIG_L=4, DIG_R=5, SPLAT=6;
reg [2:0] state, next;
reg [6:0] counter;
//State Transition Logic
always@(*) begin
case (state)
LEFT : next = ground ? (dig ? DIG_L:(bump_left ? RIGHT:LEFT)):FALL_L;
RIGHT : next = ground ? (dig ? DIG_R:(bump_right ? LEFT:RIGHT)):FALL_R;
FALL_L: next = ground ? (counter > 5'd20 ? SPLAT:LEFT) :FALL_L;
FALL_R: next = ground ? (counter > 5'd20 ? SPLAT:RIGHT):FALL_R;
DIG_L : next = ground ? DIG_L:FALL_L;
DIG_R : next = ground ? DIG_R:FALL_R;
SPLAT : next = SPLAT;
default next = 'x;
endcase
end
//State Flip-flops
always@(posedge clk, posedge areset) begin
if (areset) state <= LEFT; //The only way to jump out of SPLAT
else state <= next;
end
//Counter for falling period
always@(posedge clk, posedge areset) begin
if (areset) begin
counter <= 5'd0;
end
else begin
if (~ground) counter <= counter+1'b1;
else counter <= 5'd0;
end
end
//Output Logic
assign walk_left = (state == LEFT);
assign walk_right = (state == RIGHT);
assign aaah = (state == FALL_L || state == FALL_R);
assign digging = (state == DIG_L || state == DIG_R);
endmodule
```
本題關鍵在於,觀察error錯誤波形會發現提示的cycle根本不足20,所以可以推斷其實前面可能有很長很長的一段(ground == 0),這裡計數器要設的大一點或者是設計一個state來鎖住counter>20後 再碰到地板會splat的結果。reg預設是unsigned 但還是會因為 11111 + 1 -> 100000,然後捨去高位bits,保留低5位導致計數錯誤。
```verilog=
//思考一下錯在?
module top_module(
input clk,
input areset, // Freshly brainwashed Lemmings walk left.
input bump_left,
input bump_right,
input ground,
input dig,
output walk_left,
output walk_right,
output aaah,
output digging
);
reg [2:0] state, next_state;
parameter LEFT = 3'b000, RIGHT = 3'b001,
FALL_RIGHT = 3'b010, FALL_LEFT = 3'b011,
DIG_RIGHT = 3'b100, DIG_LEFT = 3'b101,
SPLAT = 3'b110; // **新增 SPLAT 狀態**
reg [4:0] fall_counter; // 記錄掉落時鐘數 (最多 31 cycles) // 改成32bit就可以了:)))
// **狀態轉移邏輯**
always @(*) begin
case (state)
LEFT: begin
if (!ground)
next_state = FALL_LEFT;
else if (dig)
next_state = DIG_LEFT;
else if (bump_left)
next_state = RIGHT;
else
next_state = LEFT;
end
RIGHT: begin
if (!ground)
next_state = FALL_RIGHT;
else if (dig)
next_state = DIG_RIGHT;
else if (bump_right)
next_state = LEFT;
else
next_state = RIGHT;
end
FALL_RIGHT: begin
if (ground)
next_state = (fall_counter >= 20) ? SPLAT : RIGHT; // ✅ **確保落地時才進 SPLAT**
else
next_state = FALL_RIGHT;
end
FALL_LEFT: begin
if (ground)
next_state = (fall_counter >= 20) ? SPLAT : LEFT; // ✅ **確保落地時才進 SPLAT**
else
next_state = FALL_LEFT;
end
DIG_RIGHT: begin
if (!ground)
next_state = FALL_RIGHT;
else
next_state = DIG_RIGHT;
end
DIG_LEFT: begin
if (!ground)
next_state = FALL_LEFT;
else
next_state = DIG_LEFT;
end
SPLAT: begin
next_state = SPLAT; // **永遠停留在 SPLAT 狀態**
end
default: next_state = LEFT;
endcase
end
// **時序邏輯:狀態轉移與計數器**
always @(posedge clk or posedge areset) begin
if (areset) begin
state <= LEFT;
fall_counter <= 0;
end else begin
state <= next_state;
if (state == FALL_LEFT || state == FALL_RIGHT)
fall_counter <= fall_counter + 1;
else
fall_counter <= 0; // **落地時,重置計數器**
end
end
// **輸出邏輯**
assign walk_left = (state == LEFT) && (state != SPLAT);
assign walk_right = (state == RIGHT) && (state != SPLAT);
assign aaah = (state == FALL_RIGHT || state == FALL_LEFT);
assign digging = (state == DIG_RIGHT || state == DIG_LEFT);
endmodule
```
### Fsm onehot
```verilog=
module top_module(
input in,
input [9:0] state,
output [9:0] next_state,
output out1,
output out2);
always@(*)begin
next_state[0] <= (state[0]&!in)||(state[1]&!in)||(state[2]&!in)||(state[3]&!in)||(state[4]&!in)||(state[7]&!in)||(state[8]&!in)||(state[9]&!in);
next_state[1] <= (state[0]&in)||(state[8]&in)||(state[9]&in);
next_state[2] <= (state[1]&in);
next_state[3] <= (state[2]&in);
next_state[4] <= (state[3]&in);
next_state[5] <= (state[4]&in);
next_state[6] <= (state[5]&in);
next_state[7] <= (state[6]&in)||(state[7]&in);
next_state[8] <= (state[5]&!in);
next_state[9] <= (state[6]&!in);
end
assign out1 = state[8] || state[9];
assign out2 = state[7] || state[9];
endmodule
```
### Fsm ps2
```verilog=
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output done
);
parameter S1 = 0, S2 = 1, S3 = 2, DONE = 3;
reg[2:0] state ;
reg[2:0] next ;
// State transition logic (combinational)
always@(*)begin
case(state)
S1: next = in[3] ? S2: S1;
S2: next = S3;
S3: next = DONE;
DONE : next = in[3] ? S2: S1;
endcase
end
// State flip-flops (sequential)
always@(posedge clk, posedge reset)begin
if (reset)
state <= S1;
else
state <= next;
end
// Output logic
assign done = (state == DONE)? 1 : 0;
endmodule
```
### Fsm ps2data
```verilog=
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output [23:0] out_bytes,
output done
);
// FSM from fsm_ps2
parameter S1 = 0, S2 = 1, S3 = 2, DONE = 3;
reg[2:0] state ;
reg[2:0] next ;
reg[23:0] out_bytes_reg;
// State transition logic (combinational)
always@(*)begin
case(state)
S1: next = in[3] ? S2: S1;
S2: next = S3;
S3: next = DONE;
DONE : next = in[3] ? S2: S1;
default : next = S1;
endcase
end
// State flip-flops (sequential)
always@(posedge clk)begin
if (reset)
state <= S1;
else
state <= next;
end
always@(posedge clk)begin
if (next== S2) begin
if (state == S1)begin
out_bytes_reg[23:16] <= in;
end
else if (state == DONE) begin
out_bytes_reg[23:16] <= in;
end
end
end
always@(posedge clk)begin
if(next == S3)begin
out_bytes_reg[15:8] <= in;
end
end
always@(posedge clk)begin
if(next == DONE)begin
out_bytes_reg[7:0] <= in;
end
end
// New: Datapath to store incoming bytes.
assign done = (state == DONE);
assign out_bytes = done ? out_bytes_reg : 0;
endmodule
```
### Fsm serial
```verilog=
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output done
);
parameter IDLE = 0, START = 1, S1 = 2, S2 = 3, S3 = 4, S4 = 5, S5 = 6, S6 = 7, S7 = 8, S8 = 9, STOP = 10, WAIT = 11;
reg [3:0] state ;
reg [3:0] next ;
always@(*)begin
case(state)
IDLE : next = in? IDLE : START;
START : next = S1;
S1 : next = S2;
S2 : next = S3;
S3 : next = S4;
S4 : next = S5;
S5 : next = S6;
S6 : next = S7;
S7 : next = S8;
S8 : next = in ? STOP : WAIT;
WAIT : next = in ? IDLE : WAIT;
STOP : next = in ? IDLE : START;
default next = IDLE;
endcase
end
always@(posedge clk)begin
if(reset)begin
state <= IDLE;
end
else begin
state <= next;
end
end
assign done = (state == STOP);
endmodule
```
## shift register(移位暫存器)
### Lfsr5

```verilog=
module top_module(
input clk,
input reset, // Active-high synchronous reset to 5'h1
output [4:0] q
);
always@(posedge clk)begin
if (reset)begin
q <= 5'd1; // 11111
end
else begin
q[4] <= q[0];// q[0] ^ 0的簡化
q[3] <= q[4];
q[2] <= q[3] ^ q[0];
q[1] <= q[2];
q[0] <= q[1];
end
end
endmodule
```
### Mt2015 lfsr

```verilog=
module top_module (
input [2:0] SW, // R
input [1:0] KEY, // L and clk
output reg [2:0] LEDR // Q: 改為 reg 型態
);
wire d1, d2, d3;
reg [2:0] q; // 改為 reg 型態
assign d1 = KEY[1] ? SW[0] : q[2];
assign d2 = KEY[1] ? SW[1] : q[0];
assign d3 = KEY[1] ? SW[2] : q[2]^q[1];
// 這個 always 塊可以用阻塞賦值,因為它是純粹的組合邏輯
always @(*) begin
LEDR[0] = q[0];
LEDR[1] = q[1];
LEDR[2] = q[2];
end
always @(posedge KEY[0]) begin
q[0] <= d1;
q[1] <= d2;
q[2] <= d3;
end
endmodule
```
以下這個版本可讀性較佳,把組合跟序向電路分開來撰寫 [參考來源](https://blog.csdn.net/wangkai_2019/article/details/106290065#3.2.3.4%205-bit%20LFSR%EF%BC%88Lfsr5%EF%BC%89)
```verilog=
module top_module (
input [2:0] SW, // R
input [1:0] KEY, // L and clk
output [2:0] LEDR // Q
);
reg[2:0] LEDR_next;
always@(*)begin
if (KEY[1])begin
LEDR_next = SW;
end
else begin
LEDR_next[0] = LEDR[2];
LEDR_next[1] = LEDR[0];
LEDR_next[2] = LEDR[2] ^ LEDR[1];
end
end
always@(posedge KEY[0]) begin
LEDR <= LEDR_next;
end
endmodule
```
### Lfsr32
設計圖可以參考 [lfsr5](https://hackmd.io/qtU92XTvTp6vxNMlP9IiLw#Lfsr5)
```verilog=
module top_module(
input clk,
input reset, // Active-high synchronous reset to 32'h1
output [31:0] q
);
reg[31:0] q_next;
always@(*) begin
q_next = {q[0], q[31:1]};
q_next[21] = q[0] ^ q[22];
q_next[1] = q[0] ^ q[2];
q_next[0] = q[0] ^ q[1];
end
always@(posedge clk)begin
if (reset)begin
q <= 32'd1;
end
else begin
q <= q_next;
end
end
endmodule
```
## Mealy Machine (米利狀態機)
米利型有限狀態機(英語:Mealy machine)是基於它的當前狀態和輸入生成輸出的有限狀態自動機(更精確的叫有限狀態變換器)。這意味著它的狀態圖將為每個轉移邊包括輸入和輸出二者。
白話來說
mealy machine 『輸出output』要依靠「狀態state」+「輸入input」來決定
moore machine 『輸出output』由「狀態state」決定。
```
S0 + input1 -> S1, S2
S0 + input1 -> S3
```
### Exams/ece241 2013 q8
```verilog=
module top_module (
input clk,
input aresetn, // Asynchronous active-low reset
input x,
output z );
parameter S0 = 0, S1 = 1, S2 = 2;
reg [1:0] state;
reg [1:0] next;
//注意狀態轉移階段跟摩爾型的差異
always@(*)begin
case(state)
S0 :begin
next = x ? S1 : S0; // x
end
S1 :begin
next = x ? S1 : S2; // 1x, x = 1 -> S1 , x = 0 -> S2
end
S2 : begin
next = x ? S1: S0; //10
end
endcase
end
always@(posedge clk, negedge aresetn)begin
if (aresetn == 1'b0) begin
state <= S0;
end
else begin
state <= next;
end
end
always@(*)begin
case(state)
S0 : z = 1'b0;
S1 : z = 1'b0;
S2 : z = x; // S2 是 10 所以要結合x來判斷是否輸出1
endcase
end
endmodule
```
### [Exams/ece241 2014 q5b](https://hdlbits.01xz.net/wiki/Exams/ece241_2014_q5b)
二補數算法 Mealy FSM
```verilog=
module top_module (
input clk,
input areset,
input x,
output z
);
parameter A = 0, B = 1;
reg state, next;
always@(*)begin
case(state)
A : next = x? B : A;
B : next = B;
endcase
end
always@(posedge clk, posedge areset)begin
if (areset)begin
state <= A;
end
else begin
state <= next;
end
end
always@(*)begin
z = (!state&&x)||(state&&!x);
end
endmodule
```
### [Exams/ece241 2014 q5a](https://hdlbits.01xz.net/wiki/Exams/ece241_2014_q5a)
[二補數算法](https://zh.wikipedia.org/zh-tw/%E4%BA%8C%E8%A3%9C%E6%95%B8#:~:text=\)-,%E6%96%B9%E6%B3%95%E4%BA%8C,-%5B%E7%B7%A8%E8%BC%AF%5D)
本題使用3個狀態的摩爾電路解題
**STATE_A** 若該位元為0,將二補數對應位元填0,繼續檢查下一位元(較高的位元),直到找到1然後進入SB。
**STATE_B** 此狀態輸出1,因為前一個input是0,或是剛從SA轉移過來。根據輸入`1 -> SC , 0 -> SB`。
**STATE_C** 此狀態輸出0,因為前一個input是1。根據輸入 `1 -> SC , 0 -> SB`。
```verilog=
module top_module (
input clk,
input areset,
input x,
output z
);
parameter A = 2'd0, B = 2'd1, C = 2'd2;
reg [1:0] current_state;
reg [1:0] next_state;
always@(*)begin
case(current_state)
A:begin
next_state = x ? B : A;
end
B:begin
next_state = x ? C : B;
end
C:begin
next_state = x ? C : B;
end
default:begin
next_state = A;
end
endcase
end
always@(posedge clk or posedge areset)begin
if(areset)begin
current_state <= A;
end
else begin
current_state <= next_state;
end
end
assign z = current_state == B;
endmodule
```
### Exams/2014 q3fsm
```verilog
module top_module (
input clk,
input reset, // Synchronous reset
input s,
input w,
output z
);
parameter A = 0, B = 1;
reg state;
reg next;
// 組合電路 -> 判斷 State
always@(*)begin
case(state)
A : next = s? B :A;
B : next = B;
default: next = A;
endcase
end
always@(posedge clk)begin
if (reset)begin
state <= A;
end
else begin
state <= next;
end
end
reg [1:0]Count;
reg [1:0]Time;
always@(posedge clk)begin
if (reset || state == A) begin
Count <= 0;
Time <= 0;
z <= 0;
end
else if (state == B)begin
if (Time < 2) begin
Time <= Time + 1;
Count <= Count + (w ? 1 : 0);
z <= 0;
end
else begin
if ((Count + (w ? 1 : 0)) == 2)
z <= 1;
else begin
z <= 0;
end
Time <= 0;
Count <= 0;
end
end
end
endmodule
```
### [Exams/2014 q3b](https://hdlbits.01xz.net/wiki/Exams/2014_q3bfsm)
```verilog=
module top_module (
input clk,
input reset, // Synchronous reset
input x,
output z
);
parameter S0 = 0, S1 = 1, S2 = 2, S3 = 3, S4 = 4;
reg [2:0] state, next;
always@(*)begin
case(state)
S0 : next = x? S1 : S0;
S1 : next = x? S4 : S1;
S2 : next = x? S1 : S2;
S3 : next = x? S2 : S1;
S4 : next = x? S4 : S3;
default : next = S0;
endcase
end
always@(posedge clk)begin
if (reset)begin
state <= S0;
end
else begin
state <= next;
end
end
assign z = (state == S3 || state == S4) ;
endmodule
```
## 其他
### Synchronous FIFO
來源 : [VL46 同步FIFO](https://www.nowcoder.com/practice/3ece2bed6f044ceebd172a7bf5cfb416?tpId=302&tqId=5000603&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3DVerilog%25E7%25AF%2587%26topicId%3D302)

[FPGA数字IC的Verilog刷题进阶版22-同步FIFO](https://www.bilibili.com/video/BV1S5411d7Vq/?spm_id_from=333.788&vd_source=ee346ab269e4eba3052dfd39001b45f7)
[笔试 | 同步FIFO设计详解及代码分享(这一篇就足够~)](https://mp.weixin.qq.com/s/WguYBqXZzsfJ4eSI6ROn9g)
[FPGA数字IC芯片设计求职必备-同步FIFO详解](https://www.bilibili.com/video/BV1Du411z7gN?spm_id_from=333.788.videopod.sections&vd_source=ee346ab269e4eba3052dfd39001b45f7)
```verilog=
`timescale 1ns/1ns
/**********************************RAM************************************/
module dual_port_RAM #(parameter DEPTH = 16,
parameter WIDTH = 8)(
input wclk,
input wenc,
input [$clog2(DEPTH)-1:0] waddr // 深度對2取對數,得到位址的位寬。
,input [WIDTH-1:0] wdata // 資料寫入
,input rclk,
input renc,
input [$clog2(DEPTH)-1:0] raddr // 深度對2取對數,得到位址的位寬。
,output reg [WIDTH-1:0] rdata // 資料輸出
);
reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];
always @(posedge wclk) begin
if(wenc)
RAM_MEM[waddr] <= wdata;
end
always @(posedge rclk) begin
if(renc)
rdata <= RAM_MEM[raddr];
end
endmodule
/**********************************SFIFO************************************/
module sfifo#(
parameter WIDTH = 8,
parameter DEPTH = 16
)(
input clk,
input rst_n,
input winc,
input rinc,
input [WIDTH-1:0] wdata,
output reg wfull,
output reg rempty,
output wire [WIDTH-1:0] rdata
);
localparam ADDR_WIDTH = $clog2(DEPTH);
reg [ADDR_WIDTH:0] waddr;
reg [ADDR_WIDTH:0] raddr;
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
waddr <= 'b0;
end
else begin
if(winc && ~wfull) begin
waddr <= waddr + 1'b1;
end
else begin
waddr <= waddr;
end
end
end
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
raddr <= 'b0;
end
else begin
if(rinc && ~rempty) begin
raddr <= raddr + 1'b1;
end
else begin
raddr <= raddr;
end
end
end
// assign wfull = (raddr == {~waddr[ADDR_WIDTH], waddr[ADDR_WIDTH-1:0]});
// assign rempty = (raddr == waddr);
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
wfull <= 'b0;
rempty <= 'b0;
end
else begin
wfull <= (raddr == {~waddr[ADDR_WIDTH], waddr[ADDR_WIDTH-1:0]});
rempty <= (raddr == waddr);
end
end
// RAM例化,注意讀寫使能端的訊號
dual_port_RAM
#(
.DEPTH(DEPTH),
.WIDTH(WIDTH)
)
dual_port_RAM_U0
(
.wclk(clk),
.wenc(winc && ~wfull),
.waddr(waddr[ADDR_WIDTH-1:0]), // 深度對2取對數,得到位址的位寬。
.wdata(wdata), // 資料寫入
.rclk(clk),
.renc(rinc && ~rempty),
.raddr(raddr[ADDR_WIDTH-1:0]), // 深度對2取對數,得到位址的位寬。
.rdata(rdata) // 資料輸出
);
endmodule
```
### Asynchronous FIFO
```verilog
`timescale 1ns/1ns
/******** 雙埠RAM (Dual Port RAM) ***********/
module dual_port_RAM #(
parameter DEPTH = 16, // 記憶體深度
parameter WIDTH = 8 // 資料寬度
)(
input wclk, // 寫入時脈
input wenc, // 寫入使能
input [$clog2(DEPTH)-1:0] waddr, // 寫入位址(以記憶體深度取對數決定位寬)
input [WIDTH-1:0] wdata, // 寫入資料
input rclk, // 讀取時脈
input renc, // 讀取使能
input [$clog2(DEPTH)-1:0] raddr, // 讀取位址(以記憶體深度取對數決定位寬)
output reg [WIDTH-1:0] rdata // 讀出資料
);
// 宣告一個記憶體陣列,大小為 DEPTH,每個單元寬度為 WIDTH
reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];
// 寫入操作:在 wclk 上升沿,若寫入使能有效則將資料寫入指定位址
always @(posedge wclk) begin
if (wenc)
RAM_MEM[waddr] <= wdata;
end
// 讀取操作:在 rclk 上升沿,若讀取使能有效則從指定位址讀出資料
always @(posedge rclk) begin
if (renc)
rdata <= RAM_MEM[raddr];
end
endmodule
/******** 非同步 FIFO (Asynchronous FIFO) *********/
/**********************************************
* 說明: 非同步 FIFO 用於在不同時脈域間傳遞資料,
* 因寫入與讀取時脈可能不同,故需特殊同步機制。
**********************************************/
module asyn_fifo #(
parameter WIDTH = 8, // FIFO 資料寬度
parameter DEPTH = 16 // FIFO 深度(可儲存資料個數)
)(
input wclk, // 寫入時脈
input rclk, // 讀取時脈
input wrstn, // 寫入時脈域非同步低有效復位
input rrstn, // 讀取時脈域非同步低有效復位
input winc, // 寫入增量訊號(嘗試寫入)
input rinc, // 讀取增量訊號(嘗試讀取)
input [WIDTH-1:0] wdata, // 寫入資料
output wire wfull, // FIFO 滿的標誌
output wire rempty, // FIFO 空的標誌
output wire [WIDTH-1:0] rdata // 讀出資料
);
// 位址位寬,由 FIFO 深度決定(取對數後進位)
localparam ADDR_WIDTH = $clog2(DEPTH);
// 寫入與讀取二進位計數器(多一位用於區分循環)
reg [ADDR_WIDTH:0] waddr;
reg [ADDR_WIDTH:0] raddr;
// 寫入計數器:在 wclk 上升沿或 wrstn 低電平時更新
always @ (posedge wclk or negedge wrstn) begin
if (~wrstn) begin
waddr <= 'b0;
end
else begin
if (winc && ~wfull) begin
waddr <= waddr + 1'b1;
end
else begin
waddr <= waddr;
end
end
end
// 讀取計數器:在 rclk 上升沿或 rrstn 低電平時更新
always @ (posedge rclk or negedge rrstn) begin
if (~rrstn) begin
raddr <= 'b0;
end
else begin
if (rinc && ~rempty) begin
raddr <= raddr + 1'b1;
end
else begin
raddr <= raddr;
end
end
end
// 將二進位位址轉換成格雷碼,降低跨時脈同步時的錯誤機率
wire [ADDR_WIDTH:0] waddr_gray;
wire [ADDR_WIDTH:0] raddr_gray;
assign waddr_gray = waddr ^ (waddr >> 1);
assign raddr_gray = raddr ^ (raddr >> 1);
// 在寫入時脈域內暫存轉換後的格雷碼(waddr_gray_reg)
reg [ADDR_WIDTH:0] waddr_gray_reg;
always @ (posedge wclk or negedge wrstn) begin
if (~wrstn) begin
waddr_gray_reg <= 'd0;
end
else begin
waddr_gray_reg <= waddr_gray;
end
end
// 在讀取時脈域內暫存轉換後的格雷碼(raddr_gray_reg)
reg [ADDR_WIDTH:0] raddr_gray_reg;
always @ (posedge rclk or negedge rrstn) begin
if (~rrstn) begin
raddr_gray_reg <= 'd0;
end
else begin
raddr_gray_reg <= raddr_gray;
end
end
// 將讀取時脈域的格雷碼同步到寫入時脈域(兩級同步器)
reg [ADDR_WIDTH:0] addr_r2w_t;
reg [ADDR_WIDTH:0] addr_r2w;
always @ (posedge wclk or negedge wrstn) begin
if (~wrstn) begin
addr_r2w_t <= 'd0;
addr_r2w <= 'd0;
end
else begin
addr_r2w_t <= raddr_gray_reg;
addr_r2w <= addr_r2w_t;
end
end
// 將寫入時脈域的格雷碼同步到讀取時脈域(兩級同步器)
reg [ADDR_WIDTH:0] addr_w2r_t;
reg [ADDR_WIDTH:0] addr_w2r;
always @ (posedge rclk or negedge rrstn) begin
if (~rrstn) begin
addr_w2r_t <= 'd0;
addr_w2r <= 'd0;
end
else begin
addr_w2r_t <= waddr_gray_reg;
addr_w2r <= addr_w2r_t;
end
end
// 判斷 FIFO 滿的條件:
// 當寫入時脈域的格雷碼(waddr_gray_reg)與同步過來的讀取位址(addr_r2w),
// 經過最高位反轉後相等,表示寫指標已超前一個循環 => FIFO 滿
assign wfull = (waddr_gray_reg == {~addr_r2w[ADDR_WIDTH:ADDR_WIDTH-1], addr_r2w[ADDR_WIDTH-2:0]});
// 判斷 FIFO 空的條件:
// 當讀取時脈域的格雷碼(raddr_gray_reg)與同步過來的寫指標(addr_w2r)相等,表示 FIFO 空
assign rempty = (raddr_gray_reg == addr_w2r);
// 例化雙埠RAM作為 FIFO 的資料儲存單元
dual_port_RAM
#(
.DEPTH(DEPTH),
.WIDTH(WIDTH)
)
dual_port_RAM_U0
(
.wclk(wclk),
.wenc(winc && ~wfull),
.waddr(waddr[ADDR_WIDTH-1:0]), // 僅使用低位作為 RAM 的位址
.wdata(wdata), // 寫入資料
.rclk(rclk),
.renc(rinc && ~rempty),
.raddr(raddr[ADDR_WIDTH-1:0]), // 僅使用低位作為 RAM 的位址
.rdata(rdata) // 讀出資料
);
endmodule
```
### 簡易秒表
[本題來源](https://www.nowcoder.com/practice/6493ca8c7b67499f918e1fa33b4cdeda?tpId=302&tqId=5000633&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3DVerilog%25E7%25AF%2587%26topicId%3D302)
```verilog=
`timescale 1ns/1ns
// 正確
module count_module(
input clk,
input rst_n,
output reg [5:0]second,
output reg [5:0]minute
);
always@(posedge clk, negedge rst_n)begin
if (~rst_n)begin
minute <= 0;
second <= 0;
end
else if (minute == 6'd60) begin
minute <= minute;
second <= second;
end
else if (second == 6'd60) begin
second <= 6'd1;
minute <= minute + 1;
end
else begin
second <= second + 1;
end
end
endmodule
```
```verilog=
//錯誤寫法
//
`timescale 1ns/1ns
module count_module(
input clk,
input rst_n,
output reg [5:0]second,
output reg [5:0]minute
);
reg [5:0]min;
reg [5:0]sec;
always@(posedge clk, negedge rst_n)begin
if (~rst_n)begin
min <= 0;
sec <= 0;
end
else if (min == 6'd60) begin
min <= min;
sec <= sec;
end
else if (sec == 6'd60) begin
sec <= 6'd1;
min <= min + 1;
end
else begin
sec <= sec + 1;
end
minute <= min;// 這裡使用non-blocking assign 會抓到前一個時脈的值而不是更新後的答案
second <= sec;// 這裡使用non-blocking assign 會抓到前一個時脈的值而不是更新後的答案
end
endmodule
```
### 單端口RAM
[VL53 单端口RAM](https://www.nowcoder.com/practice/a1b0c13edba14a2984e7369d232d9793?tpId=302&tqId=5000609&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3DVerilog%25E7%25AF%2587%26topicId%3D302)
```verilog=
`timescale 1ns/1ns
module RAM_1port(
input clk,
input rst,
input enb,
input [6:0]addr,
input [3:0]w_data,
output wire [3:0]r_data
);
//*************code***********//
reg [3:0] ram[127:0];
//reg [3:0] ram_data;
integer i;
always@(posedge clk, negedge rst)begin
if (~rst)begin
for(i=0 ; i < 128 ; i =i +1)begin
ram[i] <= 0;
end
end
else begin
if (enb)begin
ram[addr] <= w_data;
end
end
end
assign r_data = enb? 4'b0 : ram[addr];
//*************code***********//
endmodule
```
### 多bit MUX同步器
```verilog=
`timescale 1ns/1ns
module mux(
input clk_a, // clk_a 時鐘域
input clk_b, // clk_b 時鐘域
input arstn, // 非同步重置訊號,低有效 (用於 clk_a 時鐘域)
input brstn, // 非同步重置訊號,低有效 (用於 clk_b 時鐘域)
input [3:0] data_in, // 4 位元資料輸入訊號
input data_en, // 資料使能訊號
output reg [3:0] dataout // 4 位元資料輸出訊號
);
// clk_a 時鐘域中對 data_en 訊號進行寄存
reg data_en_a_reg;
always @ (posedge clk_a or negedge arstn) begin
if (~arstn) begin
data_en_a_reg <= 1'b0; // 非同步重置時將寄存器歸零
end else begin
data_en_a_reg <= data_en; // 在 clk_a 時鐘上取樣 data_en 訊號
end
end
// clk_a 時鐘域中對 data_in 訊號進行寄存
reg [3:0] data_in_a_reg;
always @ (posedge clk_a or negedge arstn) begin
if (~arstn) begin
data_in_a_reg <= 4'b0; // 非同步重置時將寄存器歸零
end else begin
data_in_a_reg <= data_in; // 在 clk_a 時鐘上取樣 data_in 訊號
end
end
// 在 clk_b 時鐘域中,利用雙級同步器同步來自 clk_a 域的 data_en 訊號
reg data_en_b_t;
reg data_en_b;
always @ (posedge clk_b or negedge brstn) begin
if (~brstn) begin
data_en_b_t <= 1'b0; // 非同步重置時清零
data_en_b <= 1'b0; // 非同步重置時清零
end else begin
data_en_b_t <= data_en_a_reg; // 第一級取樣來自 clk_a 時鐘域的 data_en 訊號
data_en_b <= data_en_b_t; // 第二級取樣,降低亞穩態風險
end
end
// 在 clk_b 時鐘域中,根據同步後的 data_en 訊號控制資料輸出
always @ (posedge clk_b or negedge brstn) begin
if (~brstn) begin
dataout <= 4'b0; // 非同步重置時清零資料輸出
end else begin
if (data_en_b)
dataout <= data_in_a_reg; // 當使能訊號有效時,將 clk_a 時鐘域取樣到的資料輸出
else
dataout <= dataout; // 否則保持目前輸出狀態
end
end
endmodule
```
### RAM簡單實現
[來源](https://www.nowcoder.com/practice/2c17c36120d0425289cfac0855c28796?tpId=302&tqId=5000627&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page)
```verilog=
`timescale 1ns/1ns
module ram_mod(
input clk,
input rst_n,
input write_en,
input [7:0]write_addr,
input [3:0]write_data,
input read_en,
input [7:0]read_addr,
output reg [3:0]read_data
);
reg [3:0] ram[7:0];
integer i;
//write
always@(posedge clk, negedge rst_n)begin
if (!rst_n) begin
for (i = 0 ; i < 128 ; i = i + 1)begin
ram[i] <= 4'b000;
end
end
else if (write_en)begin
ram[write_addr] <= write_data;
end
end
//read
always@(posedge clk, negedge rst_n)begin
if (!rst_n)begin
read_data <= 4'b000;
end
else if (read_en) begin
read_data <= ram[read_addr];
end
end
endmodule
```
### 數據累加輸出
[來源](https://www.nowcoder.com/practice/956fa4fa03e4441d85262dc1ec46a3bd?tpId=302&tqId=5000601&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3DVerilog%25E7%25AF%2587%26topicId%3D302)
熟悉valid/ready設計觀念 : [流水线中的valid-ready握手控制打拍](https://zhuanlan.zhihu.com/p/620498057)
```verilog=
`timescale 1ns/1ns
module valid_ready(
input clk ,
input rst_n ,
input [7:0] data_in ,
input valid_a ,
input ready_b ,
output ready_a ,
output reg valid_b ,
output reg [9:0] data_out
);
reg [1:0] count;
//計數區塊
always@(posedge clk, negedge rst_n)begin
if (!rst_n)begin
count <= 2'b00;
end
else begin
if (valid_a & ready_a)begin
if (count == 2'd3)
count <= 2'd0;
else
count <= count + 1 ;
end
end
end
//累加區塊
always@(posedge clk, negedge rst_n)begin
if (!rst_n)begin
data_out <= 10'b0;
end
else begin
if (valid_a & ready_a)begin
if(count == 2'd0) begin
data_out <= data_in;
end
else begin
data_out <= data_out + data_in;
end
end
end
end
// 對下游輸出valid_b指示信號
always@(posedge clk, negedge rst_n)begin
if (!rst_n)begin
valid_b <= 1'b0;
end
else begin
// 當累加計數器達到3,且此時有 valid_a 與 ready_a 為有效狀態時,
// 代表已完成四次資料累加,輸出結果有效,因此將 valid_b 設為 1。
if (count == 2'd3 && valid_a && ready_a)begin
valid_b <= 1'b1; // 累加完成,設定輸出數據有效 (valid_b = 1)
end
// 當輸出有效 (valid_b 為 1) 且下游已準備好接收資料 (ready_b 為 1) 時,
// 表示資料已被下游接收,因此將 valid_b 清零以便開始下一輪累加。
else if (valid_b && ready_b) begin
valid_b <= 1'b0; // 下游已接收,清除輸出有效旗標 (valid_b = 0)
end
// 其他情況下,保持 valid_b 的原狀態不變。
else begin
valid_b <= valid_b; // 保持目前狀態,不做改變
end
end
end
assign ready_a = !valid_b | ready_b;
// 如果ready_a : 代表下一個clk posedge 就會通過 line52 的判斷
endmodule
```
```verilog=67
//解釋
assign ready_a = !valid_b | ready_b;
```
* 當 valid_b 為低(0)時,表示目前模組還沒有累加完成一組資料,輸出資料尚未有效,此時模組可以持續接受上游輸入的資料,所以 ready_a 為高(1)。
* 當 valid_b 為高(1)時,表示已累加好一組資料且輸出有效,但如果下游的 ready_b 為高(1),表示下游已準備好接收該筆資料,那麼模組便可以接收新的資料,因此 ready_a 也會為高。
總結來說,這行的邏輯確保了:
* 若累加結果尚未準備好(valid_b = 0),模組能夠持續接受資料。
* 若累加結果已準備好(valid_b = 1),則只有當下游接收了資料(ready_b = 1)後,模組才會接受新資料。
#### 相關閱讀
1. [skid buffer](https://blog.csdn.net/weixin_42415266/article/details/126291919)
2. [Half-Buffer与Skid-Buffer介绍及其在流水线中的应用](https://fpga.eetrend.com/blog/2024/100581076.html)
3. [FPGACPU.CA](https://fpgacpu.ca/index.html)
### 狀態機非重疊檢測
[來源](https://www.nowcoder.com/practice/2e35c5c0798249aaa2e1044dbaf218f2?tpId=302&tqId=5000610&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3DVerilog%25E7%25AF%2587%26topicId%3D302)
```verilog
`timescale 1ns/1ns
module sequence_test1(
input wire clk ,
input wire rst ,
input wire data ,
output reg flag
);
//*************code***********//
reg[4:0] state, next;
always@(*)begin
case(state)
5'd0: next = data? 1 : 0; //
5'd1: next = data? 1 : 2; // 1
5'd2: next = data? 3 : 0; // 10
5'd3: next = data? 4 : 2; // 101
5'd4: next = data? 5 : 2; // 1011
5'd5: next = data? 1 : 0; // 10111
default: next = 0;
endcase
end
always @(posedge clk or negedge rst) begin
if (!rst)
state <= 0;
else
state <= next;
end
always @(posedge clk or negedge rst) begin
if (!rst)
flag <= 1'b0;
else begin
if(state == 4 && data == 1'b1) begin
flag <= 1'b1;
end
else begin
flag <= 1'b0;
end
end
end
//*************code***********//
endmodule
```
#### 錯誤檢討
以下寫法會延遲一個clock後輸出(moore machine)。雖然題目沒有明確表達,題目希望是使用mealy machine也就是在 1011時就要立刻根據輸入判斷,所以不可以延遲一個時脈輸出。
但以下這個寫法會是moore machine 所以會延遲輸出。

```verilog=
`timescale 1ns/1ns
module sequence_test1(
input wire clk ,
input wire rst ,
input wire data ,
output reg flag
);
//*************code***********//
reg[3:0] state, next;
always@(*)begin
if (!rst)begin
next = 0;
end
else begin
case(state)
4'd0: next = data? 1 : 0; //
4'd1: next = data? 1 : 2; // 1
4'd2: next = data? 3 : 0; // 10
4'd3: next = data? 4 : 2; // 101
4'd4: next = data? 5 : 2; // 1011
4'd5: next = data? 1 : 0; // 10111
default: next = 0;
endcase
end
end
always @(posedge clk, negedge rst)begin
if (!rst)
state <= 0;
else
state <= next;
end
always @(posedge clk or negedge rst) begin
if (!rst)
flag <= 1'b0;
else
//moore machine
flag <= (state == 4'd5) ? 1'b1 : 1'b0;
end
//*************code***********//
endmodule
```
### 重疊序列檢測
[來源](https://www.nowcoder.com/practice/10be91c03f5a412cb26f67dbd24020a9?tpId=302&tqId=5000611&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page)
用摩爾狀態機(moore machine)
```verilog=
`timescale 1ns/1ns
module sequence_test2(
input wire clk,
input wire rst,
input wire data,
output reg flag
);
//*************code***********//
// Moore machine
reg[3:0] state, next;
always@(*)begin
if (!rst)begin
next = 0;
end
else begin
case(state)
4'd0: next = data? 1 : 0; //
4'd1: next = data? 1 : 2; // 1
4'd2: next = data? 3 : 0; // 10
4'd3: next = data? 4 : 2; // 101
4'd4: next = data? 1 : 2; // 1011
default: next = 0;
endcase
end
end
always @(posedge clk, negedge rst)begin
if (!rst)
state <= 0;
else
state <= next;
end
always @(posedge clk or negedge rst) begin
if (!rst)
flag <= 1'b0;
else
//moore machine
flag <= (state == 4'd4) ? 1'b1 : 1'b0;
end
//*************code***********//
endmodule
```
### VL60 使用握手信号实现跨时钟域数据传输
[來源](https://www.nowcoder.com/practice/2bf1b28a4e634d1ba447d3495134baac?tpId=311&tqId=5000697&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page)
參考資料
1. [【牛客】VL60 使用握手信号实现跨时钟域数据传输](https://blog.csdn.net/qq_45434284/article/details/136400889)
2. [【数字IC】_跨时钟域专题_01_概念、亚稳态、同步时钟](https://www.bilibili.com/video/BV1YYDLYPEuM?spm_id_from=333.788.videopod.sections&vd_source=ee346ab269e4eba3052dfd39001b45f7)
```
```
### Exams/ece241 2013 q4

```verilog=
module top_module (
input clk,
input reset,
input [3:1] s,
output fr3,
output fr2,
output fr1,
output dfr
);
reg[3:0] p_state, n_state;
parameter A = 4'b0000, B0 = 4'b0010, B1 = 4'b0011, C0 = 4'b0110, C1 = 4'b0111, D = 4'b1111;
always @(posedge clk) begin
if (reset) begin
{dfr,fr3,fr2,fr1} <= 4'b1111;
p_state <= A;
end
else begin
case(p_state)
A: if(s==1) n_state = B0;
else if(s==3) n_state = C0;
else if(s==7) n_state = D;
else n_state = A;
B0: if(s==0) n_state = A;
else if(s==3) n_state = C0;
else if(s==7) n_state = D;
else n_state = B0;
B1: if(s==0) n_state = A;
else if(s==3) n_state = C0;
else if(s==7) n_state = D;
else n_state = B1;
C0: if(s==0) n_state = A;
else if(s==1) n_state = B1;
else if(s==7) n_state = D;
else n_state = C0;
C1: if(s==0) n_state = A;
else if(s==1) n_state = B1;
else if(s==7) n_state = D;
else n_state = C1;
D: if(s==0) n_state = A;
else if(s==1) n_state = B1;
else if(s==3) n_state = C1;
else n_state = D;
endcase
p_state = n_state;
case (p_state)
A: {dfr,fr3,fr2,fr1} = 4'b1111;
B0: {dfr,fr3,fr2,fr1} = 4'b0011;
B1: {dfr,fr3,fr2,fr1} = 4'b1011;
C0: {dfr,fr3,fr2,fr1} = 4'b0001;
C1: {dfr,fr3,fr2,fr1} = 4'b1001;
D: {dfr,fr3,fr2,fr1} = 4'b0000;
endcase
end
end
endmodule
```
```verilog=
//優化解provided by 俊廷
module top_module (
input clk,
input reset,
input [3:1] s,
output fr3,
output fr2,
output fr1,
output dfr
);
reg[3:0] p_state, n_state;
parameter A = 4'b0000, B0 = 4'b0010, B1 = 4'b0011, C0 = 4'b0110, C1 = 4'b0111, D = 4'b1111;
always @(posedge clk) begin
if (reset) begin
{dfr,fr3,fr2,fr1} <= 4'b1111;
p_state <= A;
end
else begin
case(p_state)
A: if(s==1) n_state = B0;
else n_state = A;
B0: if(s==0) n_state = A;
else if(s==3) n_state = C0;
else n_state = B0;
B1: if(s==0) n_state = A;
else if(s==3) n_state = C0;
else n_state = B1;
C0: if(s==1) n_state = B1;
else if(s==7) n_state = D;
else n_state = C0;
C1: if(s==1) n_state = B1;
else if(s==7) n_state = D;
else n_state = C1;
D: if(s==3) n_state = C1;
else n_state = D;
endcase
p_state = n_state;
case (p_state)
A: {dfr,fr3,fr2,fr1} = 4'b1111;
B0: {dfr,fr3,fr2,fr1} = 4'b0011;
B1: {dfr,fr3,fr2,fr1} = 4'b1011;
C0: {dfr,fr3,fr2,fr1} = 4'b0001;
C1: {dfr,fr3,fr2,fr1} = 4'b1001;
D: {dfr,fr3,fr2,fr1} = 4'b0000;
endcase
end
end
endmodule
```
## 參考資料
1. [10620王俊堯教授數位邏輯設計_第12講 Analysis of Clocked Sequential Circuits](https://youtu.be/8mKQ1LdztQo?si=5Tmz2BkVBfcghsDg) // 省時間可以看DE講即可
2. [Verilog刷题58道——FPGA数字IC笔试题、面试手撕代码](https://zhuanlan.zhihu.com/p/524916728)