FPGA Prototyping By Verilog Examples第四章 常用时序电路设计

通用移位寄存器

通用移位寄存器可以载入并行数据,左移,右移,保持;它能够实现并-串功能(先载入并行数据后移位),也可实现串并功能(先移位后并行输出)。

// Listing 4.8
module univ_shift_reg
#(
parameter N=8)
(
input wire clk, reset,
input wire [1:0] ctrl,
input wire [N-1:0] d,
output wire [N-1:0] q
);

//signal declaration
reg [N-1:0] r_reg, r_next;

// body
// register
always @(posedge clk, posedge reset)
if (reset)
r_reg
<= 0;
else
r_reg
<= r_next;

// next-state logic
always @*
case(ctrl)
2'b00: r_next = r_reg; // no op
2'b01: r_next = {r_reg[N-2:0], d[0]}; // shift left
2'b10: r_next = {d[N-1], r_reg[N-1:1]}; // shift right
default: r_next = d; // load
endcase
// output logic
assign q = r_reg;

endmodule

通用二进制计数器

module univ_bin_counter
#(
parameter N=8)
(
input wire clk, reset,
input wire syn_clr, load, en, up,
input wire [N-1:0] d,
output wire max_tick, min_tick,
output wire [N-1:0] q
);

//signal declaration
reg [N-1:0] r_reg, r_next;

// body
// register
always @(posedge clk, posedge reset)
if (reset)
r_reg
<= 0; //
else
r_reg
<= r_next;

// next-state logic
always @*
if (syn_clr)
r_next
= 0;
else if (load)
r_next
= d;
else if (en & up)
r_next
= r_reg + {{(N-1){1'b0}},1'b1};
else if (en & ~up)
r_next
= r_reg - {{(N-1){1'b0}},1'b1};
else
r_next
= r_reg;

// output logic
assign q = r_reg;
assign max_tick = (r_reg=={N{1'b1}}) ? 1'b1 : 1'b0;
assign min_tick = (r_reg=={N{1'b0}}) ? 1'b1 : 1'b0;

endmodule

测试文件

`timescale 1 ns/10 ps

// The `timescale directive specifies that
// the simulation time unit is 1 ns and
// the simulator timestep is 10 ps

module bin_counter_tb();

// declaration
localparam T=20; // clock period
reg clk, reset;
reg syn_clr, load, en, up;
reg [2:0] d;
wire max_tick, min_tick;
wire [2:0] q;

// uut instantiation
univ_bin_counter #(.N(3)) uut
(.clk(clk), .reset(reset), .syn_clr(syn_clr),
.load(load), .en(en), .up(up), .d(d),
.max_tick(max_tick), .min_tick(min_tick), .q(q));

// clock
// 20 ns clock running forever
always
begin
clk
= 1'b1;
#(T/2);
clk
= 1'b0;
#(T/2);
end

// reset for the first half cycle
initial
begin
reset
= 1'b1;
#(T/2);
reset
= 1'b0;
end

// other stimulus
initial
begin
// ==== initial input =====
syn_clr = 1'b0;
load = 1'b0;
en = 1'b0;
up = 1'b1; // count up
d = 3'b000;
@(negedge reset); // wait reset to deassert
@(negedge clk); // wait for one clock
// ==== test load =====
load = 1'b1;
d = 3'b011;
@(negedge clk); // wait for one clock
load = 1'b0;
repeat(2) @(negedge clk);
// ==== test syn_clear ====
syn_clr = 1'b1; // assert clear
@(negedge clk);
syn_clr
= 1'b0;
// ==== test up counter and pause ====
en = 1'b1; // count
up = 1'b1;
repeat(10) @(negedge clk);
en
= 1'b0; // pause
repeat(2) @(negedge clk);
en
= 1'b1;
repeat(2) @(negedge clk);
// ==== test down counter ====
up = 1'b0;
repeat(10) @(negedge clk);
// ==== wait statement ====
// continue until q=2
wait(q==2);
@(
negedge clk);
up
= 1'b1;
// continue until min_tick becomes 1
@(negedge clk);
wait(min_tick);
@(
negedge clk);
up
= 1'b0;
// ==== absolute delay ====
#(4*T); // wait for 80 ns
en = 1'b0; // pause
#(4*T); // wait for 80 ns
// ==== stop simulation ====
// return to interactive simulation mode
$stop;
end
endmodule

通用模m计数器

相似命题讨论:

http://www.cnblogs.com/yuphone/archive/2010/12/26/1917395.html

module mod_m_counter
#(
parameter N=4, // number of bits in counter
M=10 // mod-M
)
(
input wire clk, reset,
output wire max_tick,
output wire [N-1:0] q
);

//signal declaration
reg [N-1:0] r_reg;
wire [N-1:0] r_next;

// body
// register
always @(posedge clk, posedge reset)
if (reset)
r_reg
<= 0;
else
r_reg
<= r_next;

// next-state logic
assign r_next = (r_reg==(M-1)) ? 0 : r_reg + 1;
// output logic
assign q = r_reg;
assign max_tick = (r_reg==(M-1)) ? 1'b1 : 1'b0;

endmodule

一种自动计算N的实现:

module mod_m_counter_fc
#(
parameter M=10) // mod-M
(
input wire clk, reset,
output wire max_tick,
output wire [log2(M)-1:0] q
);

//signal declaration
localparam N = log2(M); // number of bits for M
reg [N-1:0] r_reg;
wire [N-1:0] r_next;

// body
// register
always @(posedge clk, posedge reset)
if (reset)
r_reg
<= 0;
else
r_reg
<= r_next;

// next-state logic
assign r_next = (r_reg==(M-1)) ? 0 : r_reg + 1;
// output logic
assign q = r_reg;
assign max_tick = (r_reg==(M-1)) ? 1'b1 : 1'b0;

// log2 constant function
function integer log2(input integer n);
integer i;
begin
log2
= 1;
for (i = 0; 2**i < n; i = i + 1)
log2
= i + 1;
end
endfunction

endmodule

基于循环队列的FIFO设计

http://www.cnblogs.com/yuphone/archive/2010/12/22/1913500.html

module fifo
#(
parameter B=8, // number of bits in a word
W=3 // number of address bits
)
(
// global clock and aysn reset
input clk,
input rst_n,
// fifo interface
// fifo control signnal
input rd,
input wr,
// fifo status signal
output empty,
output full,
// fifo data bus
input [B-1:0] w_data,
output reg [B-1:0] r_data,
output reg [W:0] cnt
);

// signal declaration
reg [B-1:0] array_reg [2**W-1:0]; // register array
reg [W-1:0] w_ptr_reg, w_ptr_next, w_ptr_succ;
reg [W-1:0] r_ptr_reg, r_ptr_next, r_ptr_succ;
reg full_reg, empty_reg, full_next, empty_next;
wire wr_en,rd_en;

// body
// register file write operation
// register file read operation
always @(posedge clk)
if (wr_en)
begin
array_reg[w_ptr_reg]
<= w_data;
cnt
<= cnt + 1'b1;
end
else if (rd_en)
begin
r_data
<= array_reg[r_ptr_reg];
cnt
<= cnt -1'b1;
end
// write enabled only when FIFO is not full
assign wr_en = wr & ~full_reg;
// write enabled only when FIFO is not empty
assign rd_en = rd & ~empty_reg;
// fifo control logic
// register for read and write pointers
always @(posedge clk, negedge rst_n)
if (!rst_n)
begin
cnt
<= 0;
w_ptr_reg
<= 0;
r_ptr_reg
<= 0;
full_reg
<= 1'b0;
empty_reg <= 1'b1;
end
else
begin
w_ptr_reg
<= w_ptr_next;
r_ptr_reg
<= r_ptr_next;
full_reg
<= full_next;
empty_reg
<= empty_next;
end

// next-state logic for read and write pointers
always @*
begin
// successive pointer values
w_ptr_succ = w_ptr_reg + 1;
r_ptr_succ
= r_ptr_reg + 1;
// default: keep old values
w_ptr_next = w_ptr_reg;
r_ptr_next
= r_ptr_reg;
full_next
= full_reg;
empty_next
= empty_reg;
case ({wr, rd})
// 2'b00: no op
2'b01: // read
if (~empty_reg) // not empty
begin
r_ptr_next
= r_ptr_succ;
full_next
= 1'b0;
if (r_ptr_succ==w_ptr_reg)
empty_next
= 1'b1;
end
2'b10: // write
if (~full_reg) // not full
begin
w_ptr_next
= w_ptr_succ;
empty_next
= 1'b0;
if (w_ptr_succ==r_ptr_reg)
full_next
= 1'b1;
end
2'b11: // write and read
begin
w_ptr_next
= w_ptr_succ;
r_ptr_next
= r_ptr_succ;
end
endcase
end

// output
assign full = full_reg;
assign empty = empty_reg;

endmodule

测试文件:

`timescale 1ns/1ns

module fifo_tb;
localparam T=20; // clock period
// global clock and asyn reset
reg clk, rst_n;
// fifo interface
reg rd, wr;
wire empty, full;
reg [7:0] w_data;
wire [7:0] r_data;
wire [3:0] cnt;
// fifo instantiation
fifo #(.B(8), .W(3)) fifo_inst
(
.clk(clk), .rst_n(rst_n),
.rd(rd), .wr(wr),
.empty(empty), .full(full),
.w_data(w_data), .r_data(r_data),
.cnt(cnt)
);


// clcok
always
begin
clk
= 1'b0;
#(T/2);
clk
= 1'b1;
#(T/2);
end


// reset
initial
begin
rst_n
= 1'b0;
#(T/2)
rst_n
= 1'b1;
end


// stimulus body
initial
begin
// initial input; empty
rd=0; wr=0; w_data=8'h00;
@(posedge rst_n); // wait to deassert rst_n
@(negedge clk); // wait for a clock
// 1 write
wr=1; w_data=8'h11;
@(negedge clk); // wait to assert wr
wr=0;
@(
negedge clk); // wait to deassert wr
// 3 writes
wr=1;
repeat(3)
begin
w_data
=w_data+8'h11;
@(negedge clk);
end
wr
=0;
@(
negedge clk);
// 1 read
rd=1;
@(
negedge clk); // wait to assert rd
rd=0;
@(
negedge clk) // wait to deassert rd
// 4 writes
wr=1;
repeat(4)
begin
w_data
=w_data+8'h11;
@(negedge clk);
end
wr
=0;
@(
negedge clk);
// 1 write; full
wr=1; w_data=8'hAA;
@(negedge clk);
wr
=0;
@(
negedge clk);
// 2 reads
rd=1;
repeat(2) @(negedge clk);
rd
=0;
@(
negedge clk);
// 5 reads
rd=1;
repeat(5) @(negedge clk);
rd
=0;
@(
negedge clk);
// 1 read; empty
rd=1;
@(
negedge clk);
rd
=0;
@(
negedge clk);
$stop;
end

endmodule

FIFO的另一种实现方式:

module fifo
#(
parameter stack_width=8,//位宽
stack_height=8,//深度,即数据总量
stack_ptr_width=4,//指针宽度
AE_level =2,
AF_level
=6,
HF_level
=4
)
(
output reg [stack_width-1:0] Data_out,
output stack_full,stack_almost_full,stack_half_full,
output stack_almost_empty,stack_empty,
input [stack_width-1:0] Data_in,
input wr,rd,
input clk,rst
);

reg [stack_ptr_width-1:0] rd_ptr,wr_ptr;//指针间读写间隔的地址
reg [stack_ptr_width:0] ptr_gap;
reg [stack_width-1:0] stack[stack_height-1:0];//存储器阵列

//堆栈状态信号
assign stack_full = (ptr_gap == stack_height);
assign stack_almost_full = (ptr_gap == AF_level);
assign stack_half_full = (ptr_gap == HF_level);
assign stack_almost_empty = (ptr_gap == AE_level);
assign stack_empty = (ptr_gap == 0);

always @ (posedge clk,negedge rst)
if(!rst)
begin
Data_out
<= 0;
rd_ptr
<= 0;
wr_ptr
<= 0;
ptr_gap
<= 0;
end
else if(wr && (!rd) && (!stack_full))
begin
stack[wr_ptr]
<= Data_in;
wr_ptr
<= wr_ptr + 1'b1;
ptr_gap <= ptr_gap + 1'b1;
end
else if((!wr) && (rd) && (!stack_empty))
begin
Data_out
<= stack[rd_ptr];
rd_ptr
<= rd_ptr + 1'b1;
ptr_gap <= ptr_gap - 1'b1;
end
else if((wr) && (rd) && (stack_empty))
begin
stack[wr_ptr]
<= Data_in;
wr_ptr
<= wr_ptr + 1'b1;
ptr_gap <= ptr_gap + 1'b1;
end
else if((wr) && (rd) && (stack_full))
begin
Data_out
<= stack[rd_ptr];
rd_ptr
<= rd_ptr + 1'b1;
ptr_gap <= ptr_gap - 1'b1;
end
else if((wr) && (rd) && (!stack_full) && (!stack_empty))
begin
Data_out
<= stack[rd_ptr];
stack[wr_ptr]
<= Data_in;
rd_ptr
<= rd_ptr + 1'b1;
wr_ptr <= wr_ptr + 1'b1;
end
endmodule

测试文件:

`timescale 1ns/1ns

module fifo_tb;
localparam T=20; // clock period
// global clock and asyn reset
reg clk, rst_n;
// fifo interface
reg rd, wr;
wire empty, full;
reg [7:0] w_data;
wire [7:0] r_data;
wire stack_almost_full,stack_half_full,stack_almost_empty;
// fifo instantiation
fifo #(.stack_height(8), .stack_ptr_width(3)) fifo_inst
(
.clk(clk), .rst(rst_n),
.rd(rd), .wr(wr),
.stack_empty(empty), .stack_full(full),
.stack_almost_full(stack_almost_full),
.stack_half_full(stack_half_full),
.stack_almost_empty(stack_almost_empty),
.Data_in(w_data), .Data_out(r_data)
);


// clcok
always
begin
clk
= 1'b0;
#(T/2);
clk
= 1'b1;
#(T/2);
end


// reset
initial
begin
rst_n
= 1'b0;
#(T/2)
rst_n
= 1'b1;
end


// stimulus body
initial
begin
// initial input; empty
rd=0; wr=0; w_data=8'h00;
@(posedge rst_n); // wait to deassert rst_n
@(negedge clk); // wait for a clock
// 1 write
wr=1; w_data=8'h11;
@(negedge clk); // wait to assert wr
wr=0;
@(
negedge clk); // wait to deassert wr
// 3 writes
wr=1;
repeat(3)
begin
w_data
=w_data+8'h11;
@(negedge clk);
end
wr
=0;
@(
negedge clk);
// 1 read
rd=1;
@(
negedge clk); // wait to assert rd
rd=0;
@(
negedge clk) // wait to deassert rd
// 4 writes
wr=1;
repeat(4)
begin
w_data
=w_data+8'h11;
@(negedge clk);
end
wr
=0;
@(
negedge clk);
// 1 write; full
wr=1; w_data=8'hAA;
@(negedge clk);
wr
=0;
@(
negedge clk);
// 2 reads
rd=1;
repeat(2) @(negedge clk);
rd
=0;
@(
negedge clk);
// 5 reads
rd=1;
repeat(5) @(negedge clk);
rd
=0;
@(
negedge clk);
// 1 read; empty
rd=1;
@(
negedge clk);
rd
=0;
@(
negedge clk);
$stop;
end

endmodule

Stack的设计

module stack
#(
  parameter B=8, // number of bits in a word
            W=3  // number of address bits
)
(
  // global clock and aysn reset
  input clk, 
  input rst_n,
  // stack interface
  //  stack control signnal
  input rd, 
  input wr,
  //  stack status signal
  output empty, 
  output full,
  // stack data bus
  input [B-1:0] w_data,
  output wire [B-1:0] r_data,
  output reg [W:0] top,
  output wire wr_en,rd_en,
  output reg [W:0] rd_ptr
);

// signal declaration
reg [B-1:0] array_reg [2**W-1:0];  // register array
wire full_reg, empty_reg;
//reg rpt;

assign r_data =(rd_en&clk)?array_reg[rd_ptr-1]:r_data;
// body   
always @(posedge clk,negedge rst_n)
  if(!rst_n)
    top <= 4'd0;
  else 
  begin
      case({wr_en,rd_en})
          2'b01:  //read
          begin
            rd_ptr   <= top;  
            top    <= top -1'b1;
          end
          2'b10:  //write
          begin
             top             <= top + 1'b1; 
             array_reg[top]  <= w_data;
          end
          2'b11:
          begin
              top <=top +1'b1;
              array_reg[top]  <= w_data;
              rd_ptr    <= top;
              top <= top - 1'b1;
              
          end
          default:;
       endcase
  end
  
// write enabled only when FIFO is not full
assign wr_en = wr & ~full_reg;
// write enabled only when FIFO is not empty
assign rd_en = rd & ~empty_reg;
// stack control logic
// register for read and write pointers
assign full_reg  = (top=={1'b1,{W{1'b0}}})? 1:0;
assign empty_reg = (top=={1'b0,{W{1'b0}}})? 1:0;
// output
assign full  = full_reg;
assign empty = empty_reg;

endmodule

测试文件

`timescale 1ns/1ns

module stack_tb;
localparam T=20; // clock period
// global clock and asyn reset
reg clk, rst_n;
// fifo interface
reg rd, wr;
wire rd_en,wr_en;
wire empty, full;
reg [7:0] w_data;
wire [7:0] r_data;
wire  [3:0] top;
wire  [3:0] rd_ptr;
// stack instantiation
stack #(.B(8), .W(3)) fifo_inst
(
  .clk(clk), .rst_n(rst_n),
  .rd(rd), .wr(wr),
  .empty(empty), .full(full),
  .w_data(w_data), .r_data(r_data),
  .top(top),.rd_en(rd_en),.wr_en(wr_en),
  .rd_ptr(rd_ptr)
);


// clcok
always
begin
  clk = 1'b0; 
  #(T/2);
  clk = 1'b1;
  #(T/2);
end


// reset
initial
begin
  rst_n = 1'b0;
  #(T/2)
  rst_n = 1'b1;
end


// stimulus body
initial 
begin
  // initial input; empty
  rd=0; wr=0; w_data=8'h00;
  @(posedge rst_n); // wait to deassert rst_n
  @(negedge clk); // wait for a clock
  // 1 write
  wr=1; w_data=8'h11;
  @(negedge clk); // wait to assert wr
  wr=0;
  @(negedge clk); // wait to deassert wr
  // 3 writes
  wr=1;
  repeat(3)
  begin
    w_data=w_data+8'h11;
    @(negedge clk); 
  end
  wr=0;
  @(negedge clk);
  // 1 read
  rd=1;
  @(negedge clk); // wait to assert rd
  //@(negedge clk); // wait to assert rd
  rd=0;
  @(negedge clk) // wait to deassert rd
  // 4 writes
  wr=1;
  repeat(4)
  begin
    w_data=w_data+8'h11;
    @(negedge clk);
  end
  wr=0;
  @(negedge clk); 
  // 1 write; full
  wr=1; w_data=8'hAA;
  @(negedge clk); 
  wr=0;
  @(negedge clk);
  // 2 reads
  rd=1;
  repeat(2) @(negedge clk);
  rd=0; 
  @(negedge clk);
  // 5 reads
  rd=1;
  repeat(5) @(negedge clk);
  rd=0;
  @(negedge clk);
  // 1 read; empty
  rd=1;
  @(negedge clk);
  rd=0;
  @(negedge clk);
  $stop;
end

endmodule

代码改进如下,也可以实现同样的功能:

module stack
#(
  parameter B=8, // number of bits in a word
            W=3  // number of address bits
)
(
  // global clock and aysn reset
  input clk, 
  input rst_n,
  // stack interface
  //  stack control signnal
  input rd, 
  input wr,
  //  stack status signal
  output empty, 
  output full,
  // stack data bus
  input [B-1:0] w_data,
  output reg [B-1:0] r_data,
  output reg [W:0] top,
  output wire wr_en,rd_en
);

// signal declaration
reg [B-1:0] array_reg [2**W-1:0];  // register array
wire full_reg, empty_reg;

assign r_data =(rd_en&clk)?array_reg[top]:r_data;
// body   
always @(posedge clk,negedge rst_n)
  if(!rst_n)
    top <= 4'd0;
  else 
  begin
      case({wr_en,rd_en})
          2'b01:  //read
          begin
            top    <= top -1'b1;
          end
          2'b10:  //write
          begin
             array_reg[top]  <= w_data;
             top             <= top + 1'b1; 
          end
          2'b11:
          begin    
              array_reg[top]  <= w_data;
          end
          default:;
       endcase
  end
  
// write enabled only when FIFO is not full
assign wr_en = wr & ~full_reg;
// write enabled only when FIFO is not empty
assign rd_en = rd & ~empty_reg;
// stack control logic
// register for read and write pointers
assign full_reg  = (top=={1'b1,{W{1'b0}}})? 1:0;
assign empty_reg = (top=={1'b0,{W{1'b0}}})? 1:0;
// output
assign full  = full_reg;
assign empty = empty_reg;

endmodule

posted on 2011-04-09 16:32  齐威王  阅读(2198)  评论(1编辑  收藏  举报

导航