30.数据串转并电路
reg [2:0]count;
always@(posedge clk or negedge rst_n)begin
if(~rst_n)begin
count <= 3'd0;
ready_a <= 1'b0;
end
else begin
ready_a <= 1'b1;
if(valid_a)begin
if(count == 3'd5)begin
count <= 3'd0;
end
else count <= count + 3'd1;
end
end
end
reg [5:0] data_b_reg;
always@(posedge clk or negedge rst_n)begin
if(~rst_n)begin
data_b <= 6'b0;
valid_b <= 1'b0;
data_b_reg <= 6'b0;
end
else begin
if(valid_a)begin
data_b_reg <= {data_a, data_b_reg[5:1]};//串并联转换
if(count == 3'd5)begin
valid_b <= 1'b1;
data_b <= {data_a, data_b_reg[5:1]};
end
else begin
valid_b <= 1'b0;
data_b <= data_b;
end
end
end
end
32.非整数倍数据位宽转换24to128
- 输入数据是24bit,输出数据是128bit。因为128×3=24×16,所以每输入16个有效数据,就可以产生三个完整的输出。因此设置一个仅在输入数据有效时工作的计数器cnt,计数范围是0-15。
- 设置一个数据暂存器
data_lock
,每当输入有效时,将数据从低位移入。 - 每当计数器
cnt
计数到5、10、15时,data_out
要进行更新,并拉高valid_out
一个周期。
reg[3:0] cnt;
reg[127:0] data_lock;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt <= 0;
else
cnt <= ~valid_in ? cnt : cnt+ 1;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
valid_out <= 1'b0;
else
valid_out <= (cnt ==5 || cnt == 10 || cnt ==15) && valid_in;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
data_lock <= 0;
else
data_lock <= valid_in ? {data_lock[103:0],data_in}:data_lock;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
data_out <= 0;
else if(cnt == 5)
data_out <= valid_in ? {data_lock[119:0],data_in[23:16]}:data_out;
else if(cnt == 10)
data_out <= valid_in ? {data_lock[111:0],data_in[23:8]}:data_out;
else if(cnt == 15)
data_out <= valid_in ? {data_lock[103:0],data_in[23:0]}:data_out;
else
data_out <= data_out;
end
37.时钟分频(偶数)
reg clk_out2_r,clk_out4_r,clk_out8_r;
always@(posedge clk_in or negedge rst)begin
if(!rst)
clk_out2_r <=0;
else
clk_out2_r <= ~clk_out2_r;
end
always@(posedge clk_out2_r or negedge rst)begin
if(!rst)
clk_out4_r <=0;
else
clk_out4_r <= ~clk_out4_r;
end
always@(posedge clk_out4_r or negedge rst)begin
if(!rst)
clk_out8_r <=0;
else
clk_out8_r <= ~clk_out8_r;
end
assign clk_out2 = clk_out2_r;
assign clk_out4 = clk_out4_r;
assign clk_out8 = clk_out8_r;
38.自动贩售机
parameter S0 = 'd0, S1 = 'd1, S2 = 'd2, S3 = 'd3 , S4 = 'd4, S5 = 'd5 , S6 = 'd6;
reg [2:0] current_state;
reg [2:0] next_state;
wire [2:0] input_state;//将输入组合起来
assign input_state = {d1,d2,d3};
always@(posedge clk or negedge rst)begin
if(rst == 1'b0)begin
current_state <= S0;
end
else begin
current_state <= next_state;
end
end
always@(*)begin
case(current_state)
S0:begin
case(input_state)
3'b100:next_state = S1 ;
3'b010:next_state = S2 ;
3'b001:next_state = S4 ;
default:next_state = next_state;
endcase
end
S1:begin
case(input_state)
3'b100:next_state = S2 ;
3'b010:next_state = S3 ;
3'b001:next_state = S5 ;
default:next_state = next_state;
endcase
end
S2:begin
case(input_state)
3'b100:next_state = S3 ;
3'b010:next_state = S4 ;
3'b001:next_state = S6 ;
default:next_state = next_state;
endcase
end
default:begin
next_state = S0;
end
endcase
end
always@(posedge clk or negedge rst)begin
if(rst == 1'b0)begin
out1 <= 1'b0;
out2 <= 2'b0;
end
else begin
case(next_state)
S3: begin out1 <= 1'b1;out2 <= 2'b0; end
S4: begin out1 <= 1'b1;out2 <= 2'b1; end
S5: begin out1 <= 1'b1;out2 <= 2'b10; end
S6: begin out1 <= 1'b1;out2 <= 2'b11; end
default: begin out1 <= 1'b0;out2 <= 2'b0; end
endcase
end
end
40.占空比50%的奇数分频
奇数分频比偶数分频复杂一些,当不要求分频的占空比时,对输入时钟clk上升沿计数,可以设置两个计数的翻转点,一个是(N-1)/2,一个是(N-1),计数到(N-1)时输出时钟翻转且将计数器清零,假设计数器计数0~(N-1)/2区间输出低电平,则输出时钟的低电平有(N-1)/2 + 1个clk周期,高电平的计数是(N-1)/2+1 ~ (N-1),共(N-1)/2个clk周期,可见不是50%占空比。
当要求占空比为50%时,对输入时钟clk的上升沿和下降沿分别计数,根据两个计数器得到两个错位输出的时钟,将两个时钟做“或”运算,可以弥补相差的时钟,达到50%占空比。
reg clk_neg,clk_pos;
reg [2:0] cnt;
always@(posedge clk_in or negedge rst)begin
if(!rst)
cnt <= 0;
else
cnt <= cnt ==6 ? 0 :cnt + 1;
end
always@(posedge clk_in or negedge rst)begin
if(!rst)
clk_pos <= 0;
else
clk_pos <= cnt ==3 || cnt ==6 ? ~clk_pos : clk_pos;
end
always@(negedge clk_in or negedge rst)begin
if(!rst)
clk_neg <= 0;
else
clk_neg <= cnt ==3 || cnt ==6 ? ~clk_neg : clk_neg;
end
assign clk_out7 = clk_neg | clk_pos;
41.小数分频
假设输出clk_out
是输入clk_in
的N分频。首先要将分频系数N化为分数形式,比如4.75—>19/4。本题中8.7 —>87/10,这意味着在87个clk_in
周期内输出10个clk_out
周期就可以实现分频。
然后采用若干种(一般是两种)整数分频在87个原周期clk_in
内产生10个新时钟周期clk_out
。整数分频的分频系数有很多种选择,但要尽可能接近,提高clk_out
的均匀度。一般推荐在小数分频系数N的附近选取。因为8<N<9,所以两个整数分频系数是8和9。接着要计算87个clk_out
周期分别有多少个是8分频和9分频的。
可得x=3x=3x=3,y=7y=7y=7。也就是3个8分频和7个9分频一组,循环输出,就等效于8.7分频。 最后安排组内8分频和9分频的位置。
reg [3:0] clk_cnt;//用于产生分频输出。当div_flag==0时,计数最大值是div_e-1;当div_flag==1时,计数最大值是div_o-1
reg [6:0] cyc_cnt;//对clk_in进行计数,达到M_N后清零
reg div_flag;//8/9分频标志。当div_flag==0时是8分频;当div_flag==1时是9分频。cyc_cnt==M_N-1或者cyc_cnt==c89-1时该标志位翻转
reg clk_out_r;
always@(posedge clk_in or negedge rst) begin
if(~rst)
clk_cnt <= 0;
else if(~div_flag)
clk_cnt <= clk_cnt==(div_e-1)? 0: clk_cnt+1;
else
clk_cnt <= clk_cnt==(div_o-1)? 0: clk_cnt+1;
end
always@(posedge clk_in or negedge rst) begin
if(~rst)
cyc_cnt <= 0;
else
cyc_cnt <= cyc_cnt==(M_N-1)? 0: cyc_cnt+1;
end
always@(posedge clk_in or negedge rst) begin
if(~rst)
div_flag <= 0;
else
div_flag <= cyc_cnt==(M_N-1)||cyc_cnt==(c89-1)? ~div_flag: div_flag;
end
always@(posedge clk_in or negedge rst) begin
if(~rst)
clk_out_r <= 0;
else if(~div_flag)
clk_out_r <= clk_cnt<=((div_e>>2)+1);
else
clk_out_r <= clk_cnt<=((div_o>>2)+1);
end
assign clk_out = clk_out_r;