module top_module (
input clk,
input reset, // Synchronous reset
input data,
output [3:0] count,
output counting,
output done,
input ack );
parameter s0=3'd0,s1=3'd1,s2=3'd2,s3=3'd3,s4=3'd4,s_count=3'd5,s_done=3'd6;
reg [2:0] n_s,s;
reg [1:0] cnt;
reg [3:0] reg_count;
reg [15:0] delay,cnt1;
always@(*) begin
case(s)
s0:n_s=data?s1:s0;
s1:n_s=data?s2:s0;
s2:n_s=data?s2:s3;
s3:n_s=data?s4:s0;
s4:n_s=(cnt==3'd3)?s_count:s4;
s_count:n_s=(cnt1==delay-1)?s_done:s_count;
s_done:n_s=ack?s0:s_done;
endcase
end
always@(posedge clk) begin
if(reset)
s<=s0;
else
s<=n_s;
end
//shift_cnt_block
always@(posedge clk) begin
if(reset)
cnt<=0;
else if(s==s4) begin
if(cnt<3'd3)
cnt<=cnt+1;
else
cnt<=0;
end
end
//shift_block
always@(posedge clk) begin
if(s==s4)
reg_count<={reg_count[2:0],data};
else
reg_count<=reg_count;
end
//delay_counting_block
always@(*) begin
if(s==s_count)
delay=(reg_count+1'd1)*10'd1000;
else
delay=0;
end
//cnt1_counting_block
always@(posedge clk) begin
if(reset)
cnt1<=0;
else if(s==s_count)
cnt1<=cnt1+1;
else
cnt1<=0;
end
assign counting=(s==s_count);
assign done=(s==s_done);
assign count = reg_count - cnt1/1000; //cnt1每1000个周期后count递减
endmodule
相比上一题,本题增加了实际的计数逻辑以取代输入信号 done_counting,但状态以及转移关系与上一题相同。
设计 dly_val [3:0] ,在 shft_ena 移位使能的情况下,从数据流中读取 4bit 延迟值。
计数逻辑为一个周期为 1000 的计数器,当计数器输出 16’d999 时,将 dly_val 减 1。
功能是不是听上去很熟悉,没错,我们可以分别使用之前实现的 移位寄存器 以及 周期为 1000 的计数器。并在相应状态产生使能信号控制这两个下层模块。
module shft_reg_cntr (
input clk,
input shift_ena,
input count_ena,
input data,
output reg [3:0] q);
always @(posedge clk ) begin
if(shift_ena)
q <= {q[2:0],data};
else if(count_ena) begin
q <= q - 4'd1;
end
end
endmodule
module cntr_1k (
input clk,
input reset,
output reg [9:0] q);
always @(posedge clk ) begin
if(reset | q == 10'd999)
q <= 10'd0;
else begin
q <= q + 10'd1;
end
end
endmodule
module top_module (
input clk,
input reset, // Synchronous reset
input data,
output [3:0] count,
output counting,
output done,
input ack );
localparam FSM_W = 8;
localparam FSM_W1 = FSM_W - 1'b1;
reg [FSM_W1:0] state;
reg [FSM_W1:0] nxt_state;
localparam IDLE = 0;
localparam S_0 = 1;
localparam S_1 = 2;
localparam S_11 = 3;
localparam S_110 = 4;
localparam S_SHFT_ENA = 5;
localparam WAT_CNT_FIN = 6;
localparam WAT_ACK = 7;
wire done_counting;
//assert signal cntr
reg [1:0] asrt_cntr;
wire asrt_cntr_add;
wire asrt_cntr_clr;
//delay val
wire[3:0] dly_val;
wire dly_val_shft_ena;
wire dly_val_dec;
//delay cntr
wire [9:0] dly_cntr;
wire dly_cntr_ena;
//assert signal cntr
always @(posedge clk) begin
if(reset) begin
asrt_cntr <= 'b0;
end else if(asrt_cntr_add)begin
asrt_cntr <= asrt_cntr + 1'b1;
end else if(asrt_cntr_clr)begin
asrt_cntr <= 'b0;
end
end
assign asrt_cntr_add = state[S_SHFT_ENA];
assign asrt_cntr_clr = 1'b0; // cntr clear itself
//delay cntr
cntr_1k U_cntr_1k(
.clk (clk),
.reset (~dly_cntr_ena),
.q (dly_cntr)
);
assign dly_cntr_ena = state[WAT_CNT_FIN ];
//delay val
shft_reg_cntr U_shft_reg_cntr
(
.clk (clk),
.shift_ena (dly_val_shft_ena),
.count_ena (dly_val_dec),
.data (data),
.q (dly_val)
);
assign dly_val_shft_ena = state[S_SHFT_ENA ];
assign dly_val_dec = (dly_cntr == 16'd999 ) && ~(dly_val == 4'd0);
assign done_counting = dly_cntr == 16'd999 && dly_val == 4'd0;
// State transition logic (combinational)
always @(*) begin
nxt_state[IDLE ] = 1'b0; // never reach for nxt_state
nxt_state[S_0 ] = (state[IDLE ] && ~data) || (state[S_1 ] && ~data) || (state[S_0 ] && ~data)
|| (state[S_110 ] && ~data) || (state[WAT_ACK ] && ack);
nxt_state[S_1 ] = (state[IDLE ] && data) || (state[S_0 ] && data);
nxt_state[S_11 ] = (state[S_1 ] && data) || (state[S_11 ] && data);
nxt_state[S_110 ] = (state[S_11 ] && ~data);
nxt_state[S_SHFT_ENA ] = (state[S_110 ] && data) || (state[S_SHFT_ENA ] && ~(asrt_cntr == 2'd3));
nxt_state[WAT_CNT_FIN ] = (state[S_SHFT_ENA] && asrt_cntr == 2'd3)
|| (state[WAT_CNT_FIN ] && ~done_counting);
nxt_state[WAT_ACK ] = (state[WAT_CNT_FIN ] && done_counting)
|| (state[WAT_ACK ] && ~ack);
end
// State flip-flops (sequential)
always @(posedge clk) begin
if(reset)
state <= 'b10; //SEQ_RCGN
else begin
state <= nxt_state;
end
end
//output logic
assign done = state[WAT_ACK] ;
assign counting = state[WAT_CNT_FIN];
assign count = dly_val;
endmodule
三、
module shift_count_module (
input clk,
input data,
input shift_ena,
input count_ena,
output reg [3:0] q
);
always@(posedge clk) begin
if(shift_ena)
q<={q[2:0],data};
else if(count_ena)
q<=q-1;
end
endmodule
module count_1000_module (
input clk,
input reset,
output reg [9:0] q);
always@(posedge clk) begin
if(reset)
q<=0;
else if(q<10'd999)
q<=q+1;
else
q<=0;
end
endmodule
module top_module (
input clk,
input reset, // Synchronous reset
input data,
output [3:0] count,
output counting,
output done,
input ack );
reg [6:0] n_state,state;
parameter s0=0,s1=1,s2=2,s3=3,s_shift=4,s_count=5,s_done=6;
always@(*) begin
case(state)
s0:n_state=data?s1:s0;
s1:n_state=data?s2:s0;
s2:n_state=data?s2:s3;
s3:n_state=data?s_shift:s0;
s_shift:n_state=(cnt1==3'd3)?s_count:s_shift;
s_count:n_state=(counting_finish_ena)?s_done:s_count;
s_done:n_state=ack?s0:s_done;
endcase
end
reg [1:0] cnt1;
always@(posedge clk) begin
if(reset)
cnt1<=0;
else if(state==s_shift)
cnt1<=cnt1+1;
else
cnt1<=0;
end
wire [9:0] counting_doing;
count_1000_module u_1 (
.clk(clk),
.reset(state!=s_count),
.q(counting_doing)
);
wire [3:0] count_delay;
wire counting_finish_ena;
shift_count_module u_2 (
.clk(clk),
.data(data),
.shift_ena(state==s_shift),
.count_ena(((counting_doing==10'd999)&&(count_delay!=0))),
.q(count_delay)
);
assign counting_finish_ena= (counting_doing==10'd999)&&(count_delay==0);
always@(posedge clk) begin
if(reset)
state<=0;
else
state<=n_state;
end
assign count=count_delay;
assign counting=(state==s_count);
assign done=(state==s_done);
endmodule