用四段狀態機寫出spi時序
//四段狀態機
//第一段
//一個always模塊採用同步時序的方式描述狀態轉移
always @(posedge clk or negedge rst_n)
begin
if(!rst_n == 1'b0)
begin
state_c <= HEAD;
end
else
begin
state_c <= state_n;
end
end
//第二段
//一個always採用組合邏輯的方式判斷狀態轉移條件
always @(*)
begin
case(state_c)
HEAD:
begin
if(hea2typ_start)
begin
state_n = TYPE;
end
else
begin
state_n = state_c;
end
end
TYPE:
begin
if(typ2len_start)
begin
state_n = LEN;
end
else if(typ2dat_start)
begin
state_n = DATA;
end
else
begin
state_n = state_c;
end
end
LEN:
begin
if(len2dat_start)
begin
state_n = DATA;
end
else
begin
state_n = state_c;
end
end
DATA:
begin
if(dat2fcs_start)
begin
state_n = FCS;
end
else
begin
state_n = state_c;
end
end
FCS:
begin
if(fcs2hea_start)
begin
state_n = HEAD;
end
else
begin
state_n = state_c;
end
end
endcase
end
//第三段
//用assign定義轉移條件。注意一定要加上現態
assign hea2typ_start = state_c == HEAD && din_ff0 == 8'h55 && din == 8'hd5;
assign typ2len_start = state_c == TYPE && din != 0;
assign len2dat_start = state_c == LEN && end_cnt;
assign typ2dat_start = state_c == TYPE && din = 0;
assign dat2fcs_start = state_c == DATA && end_cnt;
assign fcs2hea_start = state_c == FCS && end_cnt;
//第四段
//採用同步時序電路設計每一個狀態的輸出
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
cnt <= 1'b0;
end
else if(add_cnt)
begin
if(end_cnt)
begin
cnt <= 1'b0;
end
else
begin
cnt <= cnt + 1'b1;
end
end
end
assign add_cnt = state_c != HEAD;
assign end_cnt = add_cnt && cnt = x - 1;
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
din_ff0 <= 0;
end
else
begin
din_ff0 <= din;
end
end
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
length <= 0;
end
else if(state_c == LEN)
begin
length <= {length[7:0],din}; //length爲最大計數65535的16位計數器
end
end
always @(*)
begin
if(state_c == LEN)
x = 2;
else if(state_c == DATA)
x = length;
else if(state_c == TYPE)
x = 1;
else
x = 4;
end
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
dout <= 1'b0;
end
else
begin
dout <= din;
end
end
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
dout_sop <= 1'b0;
end
else if(state_c == TYPE)
begin
dout_sop <= 1'b1;
end
else
begin
dout_sop <= 1'b0;
end
end
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
dout_eop <= 1'b0;
end
else if(state_c == FCS && end_cnt)
begin
dout_eop <= 1'b1;
end
else
begin
dout_eop <= 1'b0;
end
end
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
dout_vld <= 1'b0;
end
else if(state_c != HEAD)
begin
dout_vld <= 1'b1;
end
else
begin
dout_vld <= 1'b0;
end
end
//spi
//四段狀態機
//第一段
//一個always模塊採用同步時序的方式描述狀態轉移
always @(posedge clk or negedge rst_n)
begin
if(!rst_n == 1'b0)
begin
state_c <= IDLE;
end
else
begin
state_c <= state_n;
end
end
//第二段
//一個always採用組合邏輯的方式判斷狀態轉移條件
always @(*)
begin
case(state_c)
IDLE:
begin
if(idl2wrd_start)
begin
state_n = WR_RD;
end
else
begin
state_n = state_c;
end
end
WR_RD:
begin
if(wrd2tcs_start)
begin
state_n = TCS;
end
else
begin
state_n = state_c;
end
end
TCS:
begin
if(tcs2idl_start)
begin
state_n = IDLE;
end
else if(tcs2do_start)
begin
state_n = DO;
end
else
begin
state_n = state_c;
end
end
DO:
begin
if(do2idl_start)
begin
state_n = IDLE;
end
else
begin
state_n = state_c;
end
end
default:
begin
state_n = IDLE;
end
endcase
end
//第三段
//用assign定義轉移條件。注意一定要加上現態
assign idl2wrd_start = state_c = IDLE && start == 1;
assign wrd2tcs_start = state_c = WR_RD && end_cnt1;
assign tcs2idl_start = state_c = TCS && end_cnt && (mode_reg == EWEN || mode_reg == READ);
assign tcs2do_start = state_c = state_c = TCS && mode_reg == WRITE && end_cnt;
assign do2idl_start = state_c = state_c = DO && mode_reg == WRITE && do_ff1 == 1;
//第四段
//採用同步時序電路設計每一個狀態的輸出
always (posedge clk or negedge rst_n)
begin
if(rst_n = 1'b0)
begin
cnt <= 1'b0;
end
else if(add_cnt)
begin
if(end_cnt)
begin
cnt <= 1'b0;
end
else
begin
cnt <= cnt + 1'b0;
end
end
end
assign add_cnt = state_c == WR_RD || state_c == TCS;
assign end_cnt = add_cnt && cnt = 100 - 1;
always (posedge clk or negedge rst_n)
begin
if(rst_n = 1'b0)
begin
cnt1 <= 1'b0;
end
else if(add_cnt1)
begin
if(end_cnt1)
begin
cnt1 <= 1'b0;
end
else
begin
cnt1 <= cnt1 + 1'b0;
end
end
end
assign add_cnt1 = end_cnt;
assign end_cnt1 = add_cnr1 && add_cnt1 = X - 1;
always @(*)
begin
if(mode_reg == EWEN)
begin
x = 10;
end
else if(mode_reg == WRITE)
begin
x = 18;
end
else if(mode_reg == READ)
begin
x = 18;
end
else
begin
x = 0;
end
end
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
do_ff0 <= 1'b0;
do_ff1 <= 1'b1;
end
else
begin
din_ff0 <= d0;
din_ff1 <= din_ff0;
end
end
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
sk <= 0;
end
else if(sk_high)
begin
sk <= 1;
end
else if(sk_low)
begin
sk <= 0;
end
end
assign sk_high = state_c == WR_RD && add_cnt && cnt == 50 - 1;
assign sk_low = state_c == WR_RD && end_cnt == 1;
always @(posedge clk or negedge rst_n)
begin
if(rst_n = 1'b0)
begin
di <= 1'b0;
end
else if(di_en)
begin
di <= dout[17 - cnt1];
end
end
assign di_en = cnt == 0 && state_c == WR_RD ;
always @(posedge clk or negedge rst_n)
begin
if(rst_n = 1'b0)
begin
cs <= 1'b0;
end
else if(cs_high)
begin
cs <= 1;
end
else if(cs_low)
begin
cs <= 0;
end
end
assign cs_high = idl2wrd_start || tcs2do_start;
assign cs_low = wrd2tcs_start || do2idl_start;
always @(*)
begin
if(rdy_low)
rdy = 0;
else
rdy = 1;
end
assign rdy_low = start || state_c != IDLE;
always @(posedge clk or negedge rst_n)
begin
if(rst_n = 1'b0)
begin
rdata <= 1'b0;
end
else if(rdata_en)
begin
rdata <= {rdata[6:0],do};
end
end
assign rdata_en = mode_reg == READ && state_c == WR_RD && end_cnt && cnt1 >= 10 && cnt1 < 18;
always @(posedge clk or negedge rst_n)
begin
if(rst_n = 1'b0)
begin
rdata_vld <= 1'b0;
end
else if(rdata_vld_en)
begin
rdata_vld <= 1;
end
else
begin
rdata_vld <= 0;
end
end
assign rdata_vld_en = mode_reg == READ && tcs2idl_start;
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
dout <= 0;
end
else if(start && mode = 0)
begin
dout <= {3'b100,2'b11,13'b0};
end
else if(start && mode = 1)
begin
dout <= {3'b101,adder,wdata};
end
else if(start && mode = 2)
begin
dout <= {3'b110,adder,8'b0};
end
end
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
mode_reg <= 0;
end
else if(start && mode = 0)
begin
mode_reg <= EWEN;
end
else if(start && mode = 1)
begin
mode_reg <= WRITE;
end
else if(start && mode = 2)
begin
mode_reg <= READ;
end
end