通用移位寄存器可以载入并行数据,左移,右移,保持;它能够实现并-串功能(先载入并行数据后移位),也可实现串并功能(先移位后并行输出)。
// 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
相似命题讨论:
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
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
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