Untitled

 avatar
unknown
verilog
a year ago
4.1 kB
3
Indexable
`timescale 1ns / 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_MODE = 0;
parameter ESCAPE_MODE = 1;
parameter SHINING_MODE = 2;

wire clk_div0, clk_div1, clk_div25, clk_div27;
reg [3:0] cnt;
reg [3:0] next_cnt;
reg [1:0] mode;
reg [1:0] next_mode;
reg [3:0] round;

clock_divider #(25) div1(.clk(clk), .clk_div(clk_div25));
clock_divider #(27) div2(.clk(clk), .clk_div(clk_div27));

assign clk_div0 = (speed)? clk_div25 : clk_div27;
//change speed by switch

// led display according to mode
always @(posedge clk_div0 or posedge rst) begin
    if(rst) begin
        led <= 0;
    end 
    else begin
        if (en) begin
            if(mode == REGULAR_MODE) begin
                case (cnt)
                    4'b0000: led <= 16'b0000000000000000;
                    4'b0001: led <= 16'b1000100010001000;
                    4'b0010: led <= 16'b1110111011101110;
                    4'b0011: led <= 16'b1111111111111111;
                    default: led <= 16'b0000000000000000; 
                endcase
            end
            else if(mode == ESCAPE_MODE) begin
                case (cnt)
                    4'b0000: led <= 16'b1111111111111111;
                    4'b0001: led <= 16'b0011111111111111;
                    4'b0010: led <= 16'b0000111111111111;
                    4'b0011: led <= 16'b0000001111111111;
                    4'b0100: led <= 16'b0000000011111111;
                    4'b0101: led <= 16'b0000000000111111;
                    4'b0110: led <= 16'b0000000000001111;
                    4'b0111: led <= 16'b0000000000000011;
                    4'b1000: led <= 16'b0000000000000000;
                    default: led <= 16'b0000000000000000; 
                endcase
            end
            else begin
                case (cnt)
                    4'b0000: led <= 16'b1111111111111111;
                    4'b0001: led <= 16'b0000000000000000;
                    default: led <= 16'b0000000000000000;
                endcase
            end
        end
        else
            led <= led;
    end
end

// update current cnt and mode
always @(posedge clk_div0 or posedge rst) begin
    if(rst) begin
        cnt <= 0;
        mode <= 0;
    end
    else begin
        cnt <= next_cnt;
        mode <= next_mode;
    end
end

// update the value of next_cnt and round
always @(*) begin
    case(mode)
    REGULAR_MODE: begin
        if(cnt == 4'b0101) begin
            next_cnt = 0;
            round = round + 1;
        end
        else
            next_cnt = cnt + 1;
    end
    ESCAPE_MODE: begin
        if(cnt == 4'b1000 && dir == 1) begin
            next_cnt = 0;
            round = round + 1;
        end
        else if(cnt == 4'b000 && dir == 0) begin
            next_cnt = 4'b1000;
            round = round + 1;
        end
        else
            next_cnt = cnt + 1;
    end
    SHINING_MODE: begin
        if(cnt == 4'b0010) begin
            next_cnt = 0;
            round = round + 1;
        end
        else
            next_cnt = cnt + 1;
    end
    endcase
end

// mode transtion
always @(*) begin
    case(mode)
    REGULAR_MODE: begin
        if(round == 2)
            next_mode = ESCAPE_MODE;
        else
            next_mode = REGULAR_MODE;
    end
    ESCAPE_MODE: begin
        if(round == 3 && dir == 1)
            next_mode = SHINING_MODE;
        else if(round == 3 && dir == 0)
            next_mode = REGULAR_MODE;
        else
            next_mode = ESCAPE_MODE;
    end
    SHINING_MODE: begin
        if(round == 8)
            next_mode = REGULAR_MODE;
        else
            next_mode = SHINING_MODE;
    end
    endcase
end

endmodule