FPGA學習筆記-------狀態機結構02

用四段狀態機寫出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	
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章