More complex lighting control verilog fsm

`define N_LED 4
`define LEDS_OFF {`N_LED{1'b1}}
`define LEDS_ON {`N_LED{1'b0}}
`define RIGHT_ON {{`N_LED-1{1'b1}}, 1'b0}
`define LEFT_ON { 1'b0, {`N_LED-1{1'b1}}}
module LedFsm (
    input clk, input rst_n,
    output [`N_LED-1:0] leds); //0:on, 1:off
    parameter N_MODE = 4;
    parameter N_TICK = 50_000_0; //50Mhz, tick on 100ms
        
    // led change:
    // all on, off
    // left to right
    // right to left
    // arrive from both side

    /* Tick counter*/    
    reg[15:0] cnt;
    wire tick;
    assign tick = cnt == N_TICK ? 1: 0;
    always @(posedge clk or negedge rst_n) begin //tick counter
        cnt <= !rst_n || tick ? 0 : cnt + 1;
    end
    
    /* Mode fsm */
    reg [7:0] mode_fsm; //sequence fsm
    wire [2:0] mode_enable; //0: flash 1: walk 2: backward walk
    wire [2:0] step_last;  //last step of each mode
    always @(posedge tick, negedge rst_n) //1, shift left, 0(stop)
            mode_fsm <= !rst_n ? 1: //reset
            !mode_enable && step_last ? 0 : // end if hit 0
            step_last ? mode_fsm + 1 : mode_fsm;

    /* Program your mode sequence here */
    assign mode_enable = !rst_n ? 0 :  
        mode_fsm == 1 ? 'b001 : //flash
        mode_fsm == 2 ? 'b010 : //walk
        mode_fsm == 3 ? 'b100 : //walk back
        mode_fsm == 4 ? 'b110 : //walk bi-direction
        mode_fsm == 5 ? 'b001 : //flash
        0; //end

    wire [`N_LED-1:0] flash_leds;
    FlashLeds flash(tick, rst_n, mode_enable[0], step_last[0], flash_leds);
    
    wire [`N_LED-1:0] walk_leds;
    WalkLeds #(1) walk(tick, rst_n, mode_enable[1], step_last[1], walk_leds);
    
    wire [`N_LED-1:0] walk_back_leds;
    WalkLeds #(0) walk_back(tick, rst_n, mode_enable[2], step_last[2], walk_back_leds);

    assign leds = flash_leds & walk_leds & walk_back_leds;
endmodule

/* Flash Mode*/
module FlashLeds(
    input tick, rst_n, enable,
    output last, output [`N_LED-1:0] leds);
    reg[0:0] fsm; //0:on, 1:0ff, 2: end
    always @(posedge tick, negedge rst_n)
        fsm <= !rst_n || !enable ? 0 : //reset, default to on
            fsm == 0 ? 1 : 0; //toggle
    assign last = !rst_n || !enable ? 0 : fsm == 1; //last step
    assign leds = !rst_n || !enable ? `LEDS_OFF : //default off
        fsm[0] ? `LEDS_OFF : `LEDS_ON;
endmodule

/* Walk */
module WalkLeds(
    input tick, rst_n, enable,
    output last, output [`N_LED-1:0] leds);
    parameter R_TO_L = 1; //walk from right to left
    localparam INIT_LEDS = R_TO_L ? `RIGHT_ON : `LEFT_ON ;
    localparam LAST_LEDS = R_TO_L ? `LEFT_ON : `RIGHT_ON ;
    reg[`N_LED-1:0] fsm;  //n bits, shift left or right
    always @(posedge tick, negedge rst_n)
        fsm <= (!rst_n || !enable) ? INIT_LEDS : //reset
            last ? INIT_LEDS : //end?
            R_TO_L ? ~(~fsm << 1) : ~(~fsm >> 1); //walk
    assign last = !rst_n || !enable ? 0 : fsm == LAST_LEDS; //last step
    assign leds = !rst_n || !enable ? `LEDS_OFF : fsm;
endmodule

module TestLedFsm;
    reg clk, rst_n;
    wire [3:0] leds;
    initial clk = 0;
    initial rst_n = 0;
    always #10 clk = ~clk;
    initial #25 rst_n = 1;
    
    LedFsm #(.N_MODE(4), .N_TICK(4)) fsm(clk, rst_n, leds);
    initial $display("\t\t\t\ttime, leds, fsm.mode_fsm");
    initial $monitor("%d\t%b\t%b",
                       $time, leds,  fsm.mode_fsm);
    
endmodule

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326334970&siteId=291194637