Untitled

mail@pastecode.io avatar
unknown
verilog
6 months ago
6.0 kB
4
Indexable
Never
`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;
reg [3:0] next_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'b1100110011001100;
                    4'b0011: led <= 16'b1110111011101110;
                    4'b0100: 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 <= REGULAR_MODE;
    end
    else if(en == 0) begin
        cnt <= cnt;
        mode <= mode;
    end
    else begin
        cnt <= next_cnt;
        mode <= next_mode;
    end
end

// update round
always @(posedge clk_div0 or posedge rst) begin
    if(rst) begin
        round <= 0;
    end
    else if(en == 0) begin
        round <= round;
    end
    else begin
        case(mode)
        REGULAR_MODE: begin
            if(cnt == 4'b0100)
                round <= next_round;
        end
        ESCAPE_MODE: begin
            if(cnt == 4'b0000 && dir == 1)
                round <= next_round;
            else if(cnt == 4'b1000 && dir == 0)
                round <= next_round;
        end
        SHINING_MODE: begin
            if(cnt == 4'b0001)
                round <= next_round;
        end
        endcase
    end
end

// update the value of next_cnt
always @(*) begin
    if(rst) begin
        next_cnt = 0;
    end
    else begin
        case(mode)
        REGULAR_MODE: begin
            if(cnt == 4'b0100) begin
                next_cnt = 0;
                if(next_mode == ESCAPE_MODE) begin
                    if(dir == 1)
                        next_cnt = 4'b1000;
                    else
                        next_cnt = 4'b0000;
                end
            end
            else
                next_cnt = cnt + 1;
        end
        ESCAPE_MODE: begin
            if(cnt == 4'b0000 && dir == 1) begin
                next_cnt = 0;
            end
            else if(cnt == 4'b1000 && dir == 0) begin
                next_cnt = 0;
            end
            else
                if(dir == 1)
                    next_cnt = cnt - 1;
                else
                    next_cnt = cnt + 1;
        end
        SHINING_MODE: begin
            if(cnt == 4'b0001) begin
                next_cnt = 0;
            end
            else
                next_cnt = cnt + 1;
        end
        endcase
    end
end

// mode transtion
always @(*) begin
    if(rst) begin
        next_mode = REGULAR_MODE;
    end
    else begin
        case(mode)
        REGULAR_MODE: begin
            if(round >= 3) begin
                next_mode = ESCAPE_MODE;
                next_round = 0;
            end
            else begin
                next_mode = REGULAR_MODE;
                next_round = round + 1;
            end
        end
        ESCAPE_MODE: begin
            if(cnt == 4'b0000 && dir == 1) begin
                next_mode = REGULAR_MODE;
                next_round = 0;
            end
            else if(cnt == 4'b1000 && dir == 0) begin
                next_mode = SHINING_MODE;
                next_round = 0;
            end
            else begin
                next_mode = ESCAPE_MODE;
                next_round = round + 1;
            end
        end
        SHINING_MODE: begin
            if(round >= 5) begin
                next_mode = REGULAR_MODE;
                next_round = 0;
            end
            else begin
                next_mode = SHINING_MODE;
                next_round = round + 1;
            end
        end
        endcase
    end
end

endmodule