Untitled

 avatar
unknown
verilog
2 years ago
3.3 kB
10
Indexable
`timescale 1ps/1ps

module clock_divider
    #(parameter n = 25)(
    input clk,
    output clk_div
    );

    reg[n-1:0]num;
    wire[n-1:0]next_num;

    always@(posedge clk)begin
        num <= next_num;
    end

    assign next_num = num + 1;
    assign clk_div = num[n-1];
endmodule

module lab3_2 (
    input clk,
    input rst,
    input en,
    input speed,
    input dir,
    output reg [15:0] led
    );
    
    parameter Regular = 2'b00;
    parameter Escape = 2'b01;
    parameter Shining = 2'b10;

    wire clk_used, clk_div_24, clk_div_26;
    reg [3:0] cnt, nxt_cnt;
    reg [2:0] state, nxt_state;
	reg [15:0] nxt_led;
    reg [3:0] reg_tmp;

    //directly use two clock in our mudule
	clock_divider #(24) div1(.clk(clk), .clk_div(clk_div_24));
    clock_divider #(26) div2(.clk(clk), .clk_div(clk_div_26));

    //change speed by switch    
    assign clk_used = (!speed) ? clk_div_26 : clk_div_24;

    // Use a counter to deal with the light;
    always @(posedge clk_used, posedge rst) begin
        if(rst) cnt <= 0;
        else if(en) cnt <= nxt_cnt;
        else cnt <= cnt;
    end

    always @(*) begin
        if(nxt_state != state) nxt_cnt = 0;
        else nxt_cnt = cnt + 1;
    end

    // State transition
    always @(posedge clk_used, posedge rst) begin
        if(rst) state <= Regular;
        else state <= nxt_state;
    end

    always @(*) begin
        case (state)
            Regular: begin
                if(cnt == 4'b1110) nxt_state = Escape;
                else nxt_state = Regular;
            end
            Escape: begin
                if(led == 16'b0000000000000000 && dir == 0) nxt_state = Shining;
                else if(led == 16'b1111111111111111 && dir == 1) nxt_state = Regular;
                else nxt_state = Escape;
            end
            Shining: begin
                if(cnt == 4'b1001) nxt_state = Regular;
                else nxt_state = Shining;
            end
            default: nxt_state = state;
        endcase
    end

    // Deal with the output
    always @(posedge clk_used, posedge rst) begin
        if(rst) begin
            led <= 16'b0000000000000000;
        end
        else if(en) begin
            if(state == Regular) begin
                reg_tmp = cnt % 5;
                    case(reg_tmp) 
                    4'b0000: led <= 16'b0000000000000000;
                    4'b0001: led <= 16'b1000100010001000;
                    4'b0010: led <= 16'b1100110011001100;
                    4'b0011: led <= 16'b1110111011101110;
                    4'b0100: led <= 16'b1111111111111111;
                    default: led <= 16'b1111111111111111;
                endcase
            end 
            else led <= nxt_led;
        end
        else led <= led;
    end

    reg [15:0] led_tmp;
    always @(*) begin
        case(state)
            Escape: begin
                if(dir == 0) begin
                    nxt_led = led >> 2;
                end
                else begin
                    led_tmp = led;
                    nxt_led = (led << 2) | led_tmp;
                end
            end
            Shining: begin
                if(led == 16'b1111111111111111) nxt_led = 16'b0000000000000000;
                else nxt_led = 16'b1111111111111111;
            end
            default: nxt_led = led;
        endcase
    end

endmodule
Editor is loading...