verilog学习 (四)

这次写关于状态机的.vhdl或者verilog中都会用到这个的,其实很多时候我们都在中用到,只是没有定义或者没有感觉到而已,如一个简单的计数器,只要来一个信号就跳到比它大一的状态,由于是有序的,所以没有必要写一堆if else.直接加一就可以了.http://www.asic-world.com/verilog/memory_fsm2.html 以前没想过,这个作者这样说的,想想也是.

在c语言圣经K&R的书中第一章有个计算单词的个数的程序,其中用到了一个状态位,是在单词中还是在不可见字符中.其实也可以想想成一个状态机.一共有2中状态{单词中,不再单词中},有四个转移方向,还有转移引发的计数的改变,如果{单词中->不再单词中}单词的计数就加一,别的转移时不改变单词计数.

状态机的作用是很大的,游戏中也会用来模拟如.< 游戏开发中的人工智能>http://book.douban.com/subject/1899340/这本书中讲到使用状态机模拟蚁群的.在字符匹配中也会用到.

一般的状态机的例子好像是连续N个1的话就输出1,或者是投币机的例子,其实这两个是一样的.

状态集有2种模型一种是米莉型(Mealy) 一种是摩尔型(Moore)差别就在于一个输入依赖于输入和状态,一个只依赖于当前的状态.

编写状态机基本分三步.

1.确定状态编码.

2.编写组合逻辑部分.

3.编写时序逻辑部分.

状态编码就是确定当前程序中的所有的状态,如果在C语言中肯定是用enum来写.在verilog中有几种一种是按找二进制来进行编码.这种方法的优点是占用寄存器少,一种是直接每个状态使用一个寄存器n个.还有一种是使用格雷码http://www.asic-world.com/verilog/memory_fsm2.html.

好了说了大部分基础的.现在直接上代码吧.代码是Copy的上面地址的.o(︶︿︶)o .if case的代码真多.程序状态转换如下state_machine

module fsm_full(
clock , // Clock
reset , // Active high reset
req_0 , // Active high request from agent 0
req_1 , // Active high request from agent 1
req_2 , // Active high request from agent 2
req_3 , // Active high request from agent 3
gnt_0 , // Active high grant to agent 0
gnt_1 , // Active high grant to agent 1
gnt_2 , // Active high grant to agent 2
gnt_3 // Active high grant to agent 3
);
// Port declaration here
input clock ; // Clock
input reset ; // Active high reset
input req_0 ; // Active high request from agent 0
input req_1 ; // Active high request from agent 1
input req_2 ; // Active high request from agent 2
input req_3 ; // Active high request from agent 3
output gnt_0 ; // Active high grant to agent 0
output gnt_1 ; // Active high grant to agent 1
output gnt_2 ; // Active high grant to agent 2
output gnt_3 ; // Active high grant to agent

// Internal Variables
reg gnt_0 ; // Active high grant to agent 0
reg gnt_1 ; // Active high grant to agent 1
reg gnt_2 ; // Active high grant to agent 2
reg gnt_3 ; // Active high grant to agent

parameter [2:0] IDLE = 3'b000;
parameter [2:0] GNT0 = 3'b001;
parameter [2:0] GNT1 = 3'b010;
parameter [2:0] GNT2 = 3'b011;
parameter [2:0] GNT3 = 3'b100;

reg [2:0] state, next_state;

always @ (state or req_0 or req_1 or req_2 or req_3)
begin
next_state = 0;
case(state)
IDLE : if (req_0 == 1'b1) begin
next_state = GNT0;
end else if (req_1 == 1'b1) begin
next_state= GNT1;
end else if (req_2 == 1'b1) begin
next_state= GNT2;
end else if (req_3 == 1'b1) begin
next_state= GNT3;
end else begin
next_state = IDLE;
end
GNT0 : if (req_0 == 1'b0) begin
next_state = IDLE;
end else begin
next_state = GNT0;
end
GNT1 : if (req_1 == 1'b0) begin
next_state = IDLE;
end else begin
next_state = GNT1;
end
GNT2 : if (req_2 == 1'b0) begin
next_state = IDLE;
end else begin
next_state = GNT2;
end
GNT3 : if (req_3 == 1'b0) begin
next_state = IDLE;
end else begin
next_state = GNT3;
end
default : next_state = IDLE;
endcase
end

always @ (posedge clock)
begin : OUTPUT_LOGIC
if (reset) begin
gnt_0 <= #1 1'b0;
gnt_1 <= #1 1'b0;
gnt_2 <= #1 1'b0;
gnt_3 <= #1 1'b0;
state <= #1 IDLE;
end else begin
state <= #1 next_state;
case(state)
IDLE : begin
gnt_0 <= #1 1'b0;
gnt_1 <= #1 1'b0;
gnt_2 <= #1 1'b0;
gnt_3 <= #1 1'b0;
end
GNT0 : begin
gnt_0 <= #1 1'b1;
end
GNT1 : begin
gnt_1 <= #1 1'b1;
end
GNT2 : begin
gnt_2 <= #1 1'b1;
end
GNT3 : begin
gnt_3 <= #1 1'b1;
end
default : begin
state <= #1 IDLE;
end
endcase
end
end

endmodule

测试部分如下

module fsm_full_tb();

reg clock,reset;
reg req_0,req_1,req_2,req_3;
wire gnt_0,gnt_1,gnt_2,gnt3;

initial
begin
$dumpfile("vcd.vcd");
$dumpvars();
end
initial
begin
clock = 0;
reset = 0;
req_0 = 0;
req_1 = 0;
req_2 = 0;
req_3 = 0;
#10 reset = 1;
#10 reset = 0;
#10 req_0 = 1;
#20 req_0 = 0;
#10 req_1 = 1;
#20 req_1 = 0;
#10 req_2 = 1;
#20 req_2 = 0;
#10 req_3 = 1;
#20 req_3 = 0;
#10 $finish;
end

fsm_full U_0(
clock,
reset,
req_0,
req_1,
req_2,
req_3,
gnt_0,
gnt_1,
gnt_2,
gnt_3);


always
#2 clock = ~clock;
endmodule

结果如下:

好了睡觉.Zzzzzz.





posted @ 2012-04-02 21:45  zhuangzhuang1988  阅读(526)  评论(0编辑  收藏  举报