【牛客】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

VL43 根据状态转移写状态机-三段式

 
`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

 

posted @ 2023-02-28 21:30  Magnolia666  阅读(101)  评论(0编辑  收藏  举报