FPGA Prototyping By Verilog Examples第六章 状态机FSMD设计

FSMD(带数据通道的有限状态机)是FSM和常规时序电路的结合。

基于RT methodology的消抖电路设计

本设计中主要的数据通道是一个用户自定制的21位递减计数器,其作用为:

1:可初始化为一个指定的值;

2:具有递减计数和暂停计数的功能;

3:当计数器计数为0的时候,输出一个状态信号。

module debounce_explicit
(
input wire clk, reset,
input wire sw,
output reg db_level, db_tick
);

// symbolic state declaration
localparam [1:0]
zero
= 2'b00,
wait0 = 2'b01,
one = 2'b10,
wait1 = 2'b11;

// number of counter bits (2^N * 20ns = 40ms)
localparam N=21;

// signal declaration
reg [1:0] state_reg, state_next;
reg [N-1:0] q_reg;
wire [N-1:0] q_next;
wire q_zero;
reg q_load, q_dec;//q_load:load the initial value;q_dec:enable the counter

// body
// fsmd state & data registers
always @(posedge clk, posedge reset)
if (reset)
begin
state_reg
<= zero;
q_reg
<= 0;
end
else
begin
state_reg
<= state_next;
q_reg
<= q_next;
end

// FSMD data path (counter) next-state logic
assign q_next = (q_load) ? {N{1'b1}} : // load 1..1
(q_dec) ? q_reg - 1 : // decrement
q_reg;
// status signal
assign q_zero = (q_next==0);

// FSMD control path next-state logic
always @*
begin
state_next
= state_reg; // default state: the same
q_load = 1'b0; // default output: 0
q_dec = 1'b0; // default output: 0
db_tick = 1'b0; // default output: 0
case (state_reg)
zero:
begin
db_level
= 1'b0;
if (sw)
begin
state_next
= wait1;
q_load
= 1'b1;
end
end
wait1:
begin
db_level
= 1'b0;
if (sw)
begin
q_dec
= 1'b1;
if (q_zero)
begin
state_next
= one;
db_tick
= 1'b1;
end
end
else // sw==0
state_next = zero;
end
one:
begin
db_level
= 1'b1;
if (~sw)
begin
state_next
= wait0;
q_load
= 1'b1;
end
end
wait0:
begin
db_level
= 1'b1;
if (~sw)
begin
q_dec
= 1'b1;
if (q_zero)
state_next
= zero;
end
else // sw==1
state_next = one;
end
default: state_next = zero;
endcase
end

endmodule

另一种可替代的代码风格:

将RT(寄存器传输)的操作嵌入到FSM控制通路中,我们不需要明确的指定数据通路的元素,只需要在相应的FSM状态中列出RT操作即可。

// Listing 6.2
module debounce
(
input wire clk, reset,
input wire sw,
output reg db_level, db_tick
);

// symbolic state declaration
localparam [1:0]
zero
= 2'b00,
wait0 = 2'b01,
one = 2'b10,
wait1 = 2'b11;

// number of counter bits (2^N * 20ns = 40ms)
localparam N=21;

// signal declaration
reg [N-1:0] q_reg, q_next;
reg [1:0] state_reg, state_next;

// body
// fsmd state & data registers
always @(posedge clk, posedge reset)
if (reset)
begin
state_reg
<= zero;
q_reg
<= 0;
end
else
begin
state_reg
<= state_next;
q_reg
<= q_next;
end

// next-state logic & data path functional units/routing
always @*
begin
state_next
= state_reg; // default state: the same
q_next = q_reg; // default q: unchnaged
db_tick = 1'b0; // default output: 0
case (state_reg)
zero:
begin
db_level
= 1'b0;
if (sw)
begin
state_next
= wait1;
q_next
= {N{1'b1}}; // load 1..1
end
end
wait1:
begin
db_level
= 1'b0;
if (sw)
begin
q_next
= q_reg - 1;
if (q_next==0)
begin
state_next
= one;
db_tick
= 1'b1;
end
end
else // sw==0
state_next = zero;
end
one:
begin
db_level
= 1'b1;
if (~sw)
begin
state_next
= wait0;
q_next
= {N{1'b1}}; // load 1..1
end
end
wait0:
begin
db_level
= 1'b1;
if (~sw)
begin
q_next
= q_reg - 1;
if (q_next==0)
state_next
= zero;
end
else // sw==1
state_next = one;

end
default: state_next = zero;
endcase
end

endmodule

 

第二种描述方式(隐数据通道)基本上跟ASMD描述顺序一样,我们仅仅是把ASMD图转换成了HDL语言。虽然这种方法简单而且描述性强,但是数据通道的综合主要依赖于软件,不容易控制。

为了代码的可读性、明晰化和高效性,我们常常把复杂的数据通道提取出来单独描述。

Fibonacci number circuit(数列)

// Listing 6.4
module fib
   (
    input wire clk, reset,
    input wire start,
    input wire [4:0] i,
    output reg ready, done_tick,
    output wire [19:0] f
   );

   // symbolic state declaration
   localparam [1:0]
      idle = 2'b00,
      op   = 2'b01,
      done = 2'b10;

   // signal declaration
   reg [1:0] state_reg, state_next;
   reg [19:0] t0_reg, t0_next, t1_reg, t1_next;
   reg [4:0] n_reg, n_next;

   // body
   // FSMD state & data registers
   always @(posedge clk, posedge reset)
      if (reset)
         begin
            state_reg <= idle;
            t0_reg <= 0;
            t1_reg <= 0;
            n_reg <= 0;
         end
      else
         begin
            state_reg <= state_next;
            t0_reg <= t0_next;
            t1_reg <= t1_next;
            n_reg <= n_next;
         end
   // FSMD next-state logic
   always @*
   begin
      state_next = state_reg;
      ready = 1'b0;
      done_tick = 1'b0;
      t0_next = t0_reg;
      t1_next = t1_reg;
      n_next = n_reg;
      case (state_reg)
         idle:
            begin
               ready = 1'b1;
               if (start)
                  begin
                     t0_next = 0;
                     t1_next = 20'd1;
                     n_next = i;
                     state_next = op;
                  end
            end
         op:
            if (n_reg==0)
               begin
                  t1_next = 0;
                  state_next = done;
               end
            else if (n_reg==1)
               state_next = done;
            else
               begin
                  t1_next = t1_reg + t0_reg;
                  t0_next = t1_reg;
                  n_next = n_reg - 1;
              end
         done:
            begin
               done_tick = 1'b1;
               state_next = idle;
            end
         default: state_next = idle;
      endcase
   end
   // output
   assign f = t1_reg;

endmodule

除法器

// Listing 6.5
module div
   #(
     parameter W = 8,
               CBIT = 4   // CBIT=log2(W)+1
    )
   (
    input wire clk, reset,
    input wire start,
    input wire [W-1:0] dvsr, dvnd,
    output reg ready, done_tick,
    output wire [W-1:0] quo, rmd
   );

   // symbolic state declaration
   localparam [1:0]
      idle = 2'b00,
      op   = 2'b01,
      last = 2'b10,
      done = 2'b11;

   // signal declaration
   reg [1:0] state_reg, state_next;
   reg [W-1:0] rh_reg, rh_next, rl_reg, rl_next, rh_tmp;
   reg [W-1:0] d_reg, d_next;
   reg [CBIT-1:0] n_reg, n_next;
   reg q_bit;

   // body
   // FSMD state & data registers
   always @(posedge clk, posedge reset)
      if (reset)
         begin
            state_reg <= idle;
            rh_reg <= 0;
            rl_reg <= 0;
            d_reg <= 0;
            n_reg <= 0;
         end
      else
         begin
            state_reg <= state_next;
            rh_reg <= rh_next;
            rl_reg <= rl_next;
            d_reg <= d_next;
            n_reg <= n_next;
         end

   // FSMD next-state logic
   always @*
   begin
      state_next = state_reg;
      ready = 1'b0;
      done_tick = 1'b0;
      rh_next = rh_reg;
      rl_next = rl_reg;
      d_next = d_reg;
      n_next = n_reg;
      case (state_reg)
         idle:
            begin
               ready = 1'b1;
               if (start)
                  begin
                     rh_next = 0;
                     rl_next = dvnd;  // dividend
                     d_next = dvsr;   // divisor
                     n_next = CBIT;   // index
                     state_next = op;
                  end
            end
         op:
            begin
               // shift rh and rl left
               rl_next = {rl_reg[W-2:0], q_bit};
               rh_next = {rh_tmp[W-2:0], rl_reg[W-1]};
               // decrease index
               n_next = n_reg - 1;
               if (n_next==1)
                  state_next = last;
            end
         last: // last iteration
            begin
               rl_next = {rl_reg[W-2:0], q_bit};
               rh_next = rh_tmp;
               state_next = done;
            end
         done:
            begin
               done_tick = 1'b1;
               state_next = idle;
            end
         default: state_next = idle;
      endcase
   end

   // compare and subtract circuit
   always @*
      if (rh_reg >= d_reg)
         begin
            rh_tmp = rh_reg - d_reg;
            q_bit = 1'b1;
         end
      else
         begin
            rh_tmp = rh_reg;
            q_bit = 1'b0;
         end

   //output
   assign quo = rl_reg;
   assign rmd = rh_reg;

endmodule

周期测量器

// Listing 6.7
module period_counter
(
input wire clk, reset,
input wire start, si,
output reg ready, done_tick,
output wire [9:0] prd
);

// symbolic state declaration
localparam [1:0]
idle
= 2'b00,
waite = 2'b01,
count = 2'b10,
done = 2'b11;

// constant declaration
localparam CLK_MS_COUNT= 50000; // 1 ms tick

// signal declaration
reg [1:0] state_reg, state_next;
reg [15:0] t_reg, t_next; // up to 50000
reg [9:0] p_reg, p_next; // up to 1 sec
reg delay_reg;
wire edg;

// body
// FSMD state & data registers
always @(posedge clk, posedge reset)
if (reset)
begin
state_reg
<= idle;
t_reg
<= 0;
p_reg
<= 0;
delay_reg
<= 0;
end
else
begin
state_reg
<= state_next;
t_reg
<= t_next;
p_reg
<= p_next;
delay_reg
<= si;
end

// rising-edge tick
assign edg = ~delay_reg & si;

// FSMD next-state logic
always @*
begin
state_next
= state_reg;
ready
= 1'b0;
done_tick = 1'b0;
p_next = p_reg;
t_next
= t_reg;
case (state_reg)
idle:
begin
ready
= 1'b1;
if (start)
state_next
= waite;
end
waite:
// wait for the first edge
if (edg)
begin
state_next
= count;
t_next
= 0;
p_next
= 0;
end
count:
if (edg) // 2nd edge arrived
state_next = done;
else // otherwise count
if (t_reg == CLK_MS_COUNT-1) // 1 ms tick
begin
t_next
= 0;
p_next
= p_reg + 1;
end
else
t_next
= t_reg + 1;
done:
begin
done_tick
= 1'b1;
state_next = idle;
end
default: state_next = idle;
endcase
end

//ouput
assign prd = p_reg;

endmodule

数字频率计

// Listing 6.8
module low_freq_counter
(
input wire clk, reset,
input wire start, si,
output wire [3:0] bcd3, bcd2, bcd1, bcd0
);

// symbolic state declaration
localparam [1:0]
idle
= 2'b00,
count = 2'b01,
frq = 2'b10,
b2b = 2'b11;

// signal declaration
reg [1:0] state_reg, state_next;
wire [9:0] prd;
wire [19:0] dvsr, dvnd, quo;
reg prd_start, div_start, b2b_start;
wire prd_done_tick, div_done_tick, b2b_done_tick;

//===============================================
// component instantiation
//===============================================
// instantiate period counter
period_counter prd_count_unit
(.clk(clk), .reset(reset), .start(prd_start), .si(si),
.ready(), .done_tick(prd_done_tick), .prd(prd));
// instantiate division circuit
div #(.W(20), .CBIT(5)) div_unit
(.clk(clk), .reset(reset), .start(div_start),
.dvsr(dvsr), .dvnd(dvnd), .quo(quo), .rmd(),
.ready(), .done_tick(div_done_tick));
// instantiate binary-to-BCD convertor
bin2bcd b2b_unit
(.clk(clk), .reset(reset), .start(b2b_start),
.bin(quo[
12:0]), .ready(), .done_tick(b2b_done_tick),
.bcd3(bcd3), .bcd2(bcd2), .bcd1(bcd1), .bcd0(bcd0));
// signal width extension
assign dvnd = 20'd1000000;
assign dvsr = {10'b0, prd};

//===============================================
// master FSM
//===============================================
always @(posedge clk, posedge reset)
if (reset)
state_reg
<= idle;
else
state_reg
<= state_next;

always @*
begin
state_next
= state_reg;
prd_start
= 1'b0;
div_start = 1'b0;
b2b_start = 1'b0;
case (state_reg)
idle:
if (start)
begin
prd_start
= 1'b1;
state_next = count;
end
count:
if (prd_done_tick)
begin
div_start
= 1'b1;
state_next = frq;
end
frq:
if (div_done_tick)
begin
b2b_start
= 1'b1;
state_next = b2b;
end
b2b:
if (b2b_done_tick)
state_next
= idle;
endcase
end

endmodule

二进制---BCD码转换

// Listing 6.6
module bin2bcd
(
input wire clk, reset,
input wire start,
input wire [12:0] bin,
output reg ready, done_tick,
output wire [3:0] bcd3, bcd2, bcd1, bcd0
);

// symbolic state declaration
localparam [1:0]
idle
= 2'b00,
op = 2'b01,
done = 2'b10;

// signal declaration
reg [1:0] state_reg, state_next;
reg [12:0] p2s_reg, p2s_next;
reg [3:0] n_reg, n_next;
reg [3:0] bcd3_reg, bcd2_reg, bcd1_reg, bcd0_reg;
reg [3:0] bcd3_next, bcd2_next, bcd1_next, bcd0_next;
wire [3:0] bcd3_tmp, bcd2_tmp, bcd1_tmp, bcd0_tmp;


// body
// FSMD state & data registers
always @(posedge clk, posedge reset)
if (reset)
begin
state_reg
<= idle;
p2s_reg
<= 0;
n_reg
<= 0;
bcd3_reg
<= 0;
bcd2_reg
<= 0;
bcd1_reg
<= 0;
bcd0_reg
<= 0;
end
else
begin
state_reg
<= state_next;
p2s_reg
<= p2s_next;
n_reg
<= n_next;
bcd3_reg
<= bcd3_next;
bcd2_reg
<= bcd2_next;
bcd1_reg
<= bcd1_next;
bcd0_reg
<= bcd0_next;
end


// FSMD next-state logic
always @*
begin
state_next
= state_reg;
ready
= 1'b0;
done_tick = 1'b0;
p2s_next = p2s_reg;
bcd0_next
= bcd0_reg;
bcd1_next
= bcd1_reg;
bcd2_next
= bcd2_reg;
bcd3_next
= bcd3_reg;
n_next
= n_reg;
case (state_reg)
idle:
begin
ready
= 1'b1;
if (start)
begin
state_next
= op;
bcd3_next
= 0;
bcd2_next
= 0;
bcd1_next
= 0;
bcd0_next
= 0;
n_next
= 4'b1101; // index
p2s_next = bin; // shift register
state_next = op;
end
end
op:
begin
// shift in binary bit
p2s_next = p2s_reg << 1;
// shift 4 BCD digits
//{bcd3_next, bcd2_next, bcd1_next, bcd0_next}=
//{bcd3_tmp[2:0], bcd2_tmp, bcd1_tmp, bcd0_tmp,
// p2s_reg[12]}

bcd0_next
= {bcd0_tmp[2:0], p2s_reg[12]};
bcd1_next
= {bcd1_tmp[2:0], bcd0_tmp[3]};
bcd2_next
= {bcd2_tmp[2:0], bcd1_tmp[3]};
bcd3_next
= {bcd3_tmp[2:0], bcd2_tmp[3]};
n_next
= n_reg - 1;
if (n_next==0)
state_next
= done;
end
done:
begin
done_tick
= 1'b1;
state_next = idle;
end
default: state_next = idle;
endcase
end

// data path function units
assign bcd0_tmp = (bcd0_reg > 4) ? bcd0_reg+3 : bcd0_reg;
assign bcd1_tmp = (bcd1_reg > 4) ? bcd1_reg+3 : bcd1_reg;
assign bcd2_tmp = (bcd2_reg > 4) ? bcd2_reg+3 : bcd2_reg;
assign bcd3_tmp = (bcd3_reg > 4) ? bcd3_reg+3 : bcd3_reg;

// output
assign bcd0 = bcd0_reg;
assign bcd1 = bcd1_reg;
assign bcd2 = bcd2_reg;
assign bcd3 = bcd3_reg;

endmodule

posted on 2011-04-13 10:46  齐威王  阅读(2739)  评论(0编辑  收藏  举报

导航