# 狀態機的一些小小的coding style ###### tags: `verilog` 之前在網路上看到一些實例 狀態機基本上分為三個區塊(我比較喜歡這樣寫) 第一個always 用來做時序的控制 一個rising edge 來就做狀態的轉變 將目前的state 轉成next_state 第二個always 用來推算出目前這個state 所對應到的下一個next stage是什麼stage 第三個always 專門用來處理在目前這個state 所要得到的輸出是什麼 e.g code (之前的serial) ```=verilog module top_module( input clk, input in, input reset, // Synchronous reset output reg done ); reg [3:0]state,nextstate; always@(posedge clk) //第一個always begin if (reset) state<=1'd0; else state<=nextstate; end always@(*) //第二個always begin case(state) 4'd0: if (in) nextstate<=4'd0; else nextstate<=4'd1; 4'd1: nextstate<=4'd2; 4'd2: nextstate<=4'd3; 4'd3: nextstate<=4'd4; 4'd4: nextstate<=4'd5; 4'd5: nextstate<=4'd6; 4'd6: nextstate<=4'd7; 4'd7: nextstate<=4'd8; 4'd8: nextstate<=4'd9; 4'd9: if (in) nextstate<=4'd10; else nextstate<=4'd11; 4'd10: if (in) nextstate<=4'd0; else nextstate<=4'd1; 4'd11: if (in) nextstate<=4'd0; else nextstate<=4'd11; default:nextstate<=4'd0; endcase end always@(*)//第三個always begin case (state) 4'd10: done<=1'd1; default: done<=1'd0; endcase end endmodule ``` 有一些東西需要改善 比較好的coding style 1. parameter 把每個state都透過parameter去做處理 可以直接用state的變數名進行使用 (比較直觀 好debug) 例如在第二個always的時候 case裡面可以直接用變數名 只用數字之後會不好debug 2. 在第三個always裡面 用nextstate對輸出進行控制 因為state的改變是check clock是否有rising edge 所以在這邊 case裡面以state來決定輸出不太好 因為不知道現在的這個stage 是clk來之前的舊state 還是已經更新的新的state 沒有考慮到延遲的情況之下 也就是理想的狀況 這裡的state是舊的state 沒有更新的state 但是考慮到真實的電路設計 這裡還是用next_state判斷輸出會比較好 因為next_state不用考慮到clk是否已經更新到值 (已經用組合邏輯算好了) 3. 多一個state就是多一個ff 所以可以少用到state就可以少用到硬體資源 這邊的data 8bit循序存取我是用8個state去做 基本上可以合併成一個state 裡面用counter去做狀態的改變 (數8 0~8變化8次 8個rising edge 數到8就進去下個state) 然後counter也不用想的太複雜 考慮到很多的state counter的功能也不一樣 (要歸0 +1 原值等等) 這邊就將counter的輸出用一個多工器去做 sel用state去選就對了 總之我就繼續來寫寫看 來做一個比較好的版本 (serial)