【牛客】5 时序逻辑
VL33 非整数倍数据位宽转换8to12
和上一题一样的,注意valid_out输出时加一个valid_in(其实32题也要加,不过不加仿真也能过)。
`timescale 1ns/1ns module width_8to12( input clk , input rst_n , input valid_in , input [7:0] data_in , output reg valid_out, output reg [11:0] data_out ); reg [2:0]count; always@(posedge clk or negedge rst_n) begin if(~rst_n) count <= 0; else if(valid_in) count <= (count<2)?count + 1:0; end always@(posedge clk or negedge rst_n) begin if(~rst_n) valid_out <= 0; else if(valid_in&&(count==1||count==2)) valid_out <= 1; else valid_out <= 0; end reg [11:0]data_lock; always@(posedge clk or negedge rst_n) begin if(~rst_n)begin data_lock <= 0; data_out <= 0; end else if(valid_in)begin data_lock <= {data_lock[3:0],data_in}; if(count == 1) data_out <= {data_lock[7:0],data_in[7:4]}; else if(count == 2) data_out <= {data_lock[3:0],data_in}; end end endmodule
VL34 整数倍数据位宽转换8to16
越做越简单了,整数倍位宽转换就非常轻松了。
`timescale 1ns/1ns module width_8to16( input clk , input rst_n , input valid_in , input [7:0] data_in , output reg valid_out, output reg [15:0] data_out ); reg count; always@(posedge clk or negedge rst_n) begin if(~rst_n) count <= 0; else if(valid_in) count <= count + 1; end always@(posedge clk or negedge rst_n) begin if(~rst_n) valid_out <= 0; else if(valid_in && count) valid_out <= 1; else valid_out <= 0; end reg [7:0]data_lock; always@(posedge clk or negedge rst_n) begin if(~rst_n)begin data_lock <= 0; data_out <= 0; end else if(valid_in)begin data_lock <= data_in; if(count == 1) data_out <= {data_lock,data_in}; end end endmodule
VL35 状态机-非重叠的序列检测
也是一道比较简单的题,不过要注意是非重叠检测,用状态机比用移位寄存器更方便一点。
`timescale 1ns/1ns module sequence_test1( input wire clk , input wire rst , input wire data , output reg flag ); //*************code***********// reg [2:0]state,next_state; localparam S0=0,S1=1,S2=2,S3=3,S4=4; always@(posedge clk or negedge rst) begin if(~rst) state <= S0; else state <= next_state; end always@(*) begin case(state) S0:next_state = data ? S1 :S0; S1:next_state = data ? S1 :S2; S2:next_state = data ? S3 :S0; S3:next_state = data ? S4 :S2; S4:next_state = data ? S0 :S2; default:next_state = S0; endcase end always@(posedge clk or negedge rst) begin if(~rst) flag <= 0; else if(state == S4 && data) flag <= 1; else flag <= 0; end //*************code***********// endmodule
VL36 状态机-重叠序列检测
重叠序列用移位寄存器肯定更方便,不过题目要求用状态机,同样也是注意状态跳变就行了。注意输出延后了一个周期,可以通过加一个状态来实现。
`timescale 1ns/1ns module sequence_test2( input wire clk , input wire rst , input wire data , output reg flag ); //*************code***********// reg [2:0]state,next_state; localparam S0=0,S1=1,S2=2,S3=3,S4=4; always@(posedge clk or negedge rst) begin if(~rst) state <= S0; else state <= next_state; end always@(*) begin case(state) S0:next_state = data ? S1 :S0; S1:next_state = data ? S1 :S2; S2:next_state = data ? S3 :S0; S3:next_state = data ? S4 :S2; S4:next_state = data ? S1 :S2; default:next_state = S0; endcase end always@(posedge clk or negedge rst) begin if(~rst) flag <= 0; else if(state == S4) flag <= 1; else flag <= 0; end //*************code***********// endmodule
VL37 时钟分频(偶数)
一眼行波计数器,不过输出定义的是wire,懒得再去改了。
我这里是组合逻辑输出,其实也不大好。
`timescale 1ns/1ns module even_div ( input wire rst , input wire clk_in, output wire clk_out2, output wire clk_out4, output wire clk_out8 ); //*************code***********// reg [2:0]count; always@(posedge clk_in or negedge rst) begin if(~rst) count <= 0; else count <= count + 1; end assign clk_out2 = count[0]; assign clk_out4 = count[1:0]>0&&count[1:0]<3; assign clk_out8 = count>0&&count<5; //*************code***********// endmodule
VL38 自动贩售机1
写完发现题目出的有点垃圾,输入d直接在上升沿给值,下降沿恢复,只有半个周期,晕。
状态机折磨了半天,看了看题解,用计数器确实方便多了,一遍过。
`timescale 1ns/1ns module seller1( input wire clk , input wire rst , input wire d1 , input wire d2 , input wire d3 , output reg out1, output reg [1:0]out2 ); //*************code***********// reg[2:0]count; always@(posedge clk or negedge rst) begin if(~rst)begin count <= 0; out1 <= 0; out2 <= 0; end else begin if(d1) count <= count + 1; else if(d2) count <= count + 2; else if(d3) count <= count + 4; if(count>=3)begin count <= 0; out1 <= 1; out2 <= count -3; end else begin out1 <= 0; out2 <= 0; end end end //*************code***********// endmodule
VL39 自动贩售机2
和上一题是一样的,加了一个sel的判断。
`timescale 1ns/1ns module seller2( input wire clk , input wire rst , input wire d1 , input wire d2 , input wire sel , output reg out1, output reg out2, output reg out3 ); //*************code***********// reg [2:0]count; always@(posedge clk or negedge rst) begin if(~rst)begin count <= 0; out1 <= 0; out2 <= 0; out3 <= 0; end else begin if(d1) count <= count + 1; else if(d2) count <= count + 2; if(sel)begin if(count >= 5)begin out1 <= 0; out2 <= 1; out3 <= count - 5; count <= 0; end else begin out1 <= 0; out2 <= 0; out3 <= 0; end end else begin if(count >= 3)begin out1 <= 1; out2 <= 0; out3 <= count - 3; count <= 0; end else begin out1 <= 0; out2 <= 0; out3 <= 0; end end end end //*************code***********// endmodule
VL40 占空比50%的奇数分频
用两个计数器,一个上升沿计数,一个下降沿计数即可。
不过感觉题目还是有点问题,第一个下降沿复位还没结束,计数器应该不会累加才对。
`timescale 1ns/1ns module odo_div_or ( input wire rst , input wire clk_in, output wire clk_out7 ); //*************code***********// reg clk_out1; reg clk_out2; reg [2:0]count1; reg [2:0]count2; always@(posedge clk_in or negedge rst) begin if(~rst)begin count1 <= 0; clk_out1 <= 0; end else begin count1 <= (count1 < 6)?(count1 + 1):0; if(count1 == 3 || count1 ==6) clk_out1 <= ~clk_out1; end end always@(negedge clk_in or negedge rst) begin if(~rst)begin count2 <= 0; clk_out2 <= 0; end else begin count2 <= (count2 < 6)?(count2 + 1):0; if(count2 == 3 || count2 ==6) clk_out2 <= ~clk_out2; end end assign clk_out7 = clk_out1 | clk_out2; //*************code***********// endmodule
VL41 任意小数分频
题目给了明示,要先3次8分频再7次9分频,连时钟切换点都给出来了。
`timescale 1ns/1ns module div_M_N( input wire clk_in, input wire rst, output wire clk_out ); parameter M_N = 8'd87; parameter c89 = 8'd24; // 8/9时钟切换点 parameter div_e = 5'd8; //偶数周期 parameter div_o = 5'd9; //奇数周期 //*************code***********// reg [6:0]count; reg [3:0]count_e; reg [3:0]count_o; reg clk_MN; always@(posedge clk_in or negedge rst) begin if(~rst) count <= 0; else count <= (count < M_N -1)?(count + 1):0; end always@(posedge clk_in or negedge rst) begin if(~rst)begin count_e <= 0; count_o <= 0; clk_MN <= 0; end else begin if(count <= c89 - 1)begin count_e <= (count_e < div_e -1)?(count_e + 1):0; if(count_e == 0||count_e == div_e/2) clk_MN <= ~clk_MN; end else begin count_o <= (count_o < div_o -1)?(count_o + 1):0; if(count_o == 0||count_o == (div_o-1)/2) clk_MN <= ~clk_MN; end end end assign clk_out = clk_MN; //*************code***********// endmodule
VL42 无占空比要求的奇数分频
说是无占空比要求,其实tb还是要求的50%,无语。参照VL40即可。
写完发现其实要求占空比40%,乌鱼子。
`timescale 1ns/1ns module odd_div ( input wire rst , input wire clk_in, output wire clk_out5 ); //*************code***********// reg [2:0]count; reg clk_div; always@(posedge clk_in or negedge rst) begin if(~rst)begin count <= 0; clk_div <= 0; end else begin count <= (count < 4)?(count + 1):0; if(count == 0 ||count == 2) clk_div <= ~clk_div; end end assign clk_out5 = clk_div; //*************code***********// endmodule
`timescale 1ns/1ns module fsm1( input wire clk , input wire rst , input wire data , output reg flag ); //*************code***********// reg[1:0]state,next_state; localparam S0=0,S1=1,S2=2,S3=3; always@(posedge clk or negedge rst) begin if(~rst) state <= S0; else state <= next_state; end always@(*) begin case(state) S0:next_state = data?S1:S0; S1:next_state = data?S2:S1; S2:next_state = data?S3:S2; S3:next_state = data?S0:S3; default:next_state = S0; endcase end always@(posedge clk or negedge rst) begin if(~rst) flag <= 0; else begin if(state == S3 && data) flag <= 1; else flag <= 0; end end //*************code***********// endmodule
VL44 根据状态转移写状态机-二段式
两段式把输出和状态转移条件写一起,直接通过组合逻辑输出。
`timescale 1ns/1ns module fsm2( input wire clk , input wire rst , input wire data , output reg flag ); //*************code***********// reg[2:0]state,next_state; localparam S0=0,S1=1,S2=2,S3=3,S4=4; always@(posedge clk or negedge rst) begin if(~rst) state <= S0; else state <= next_state; end always@(*) begin case(state) S0:begin next_state = data?S1:S0; flag =0; end S1:begin next_state = data?S2:S1; flag =0; end S2:begin next_state = data?S3:S2; flag =0; end S3:begin next_state = data?S4:S3; flag =0; end S4:begin next_state = data?S1:S0; flag = 1; end default:begin next_state = S0; flag =0; end endcase end //*************code***********// endmodule