traffic_light_fsm

Modified

2025-11-11

Source: HW6/traffic_light_fsm.sv (modified 2025-11-09 23:50)

// traffic_light_fsm.sv
`timescale 1ns/1ps

module TrafficLightFSM #(
    // 时钟与“秒拍”设置
    parameter int unsigned CLK_HZ    = 50_000_000,
    parameter int unsigned TICK_HZ   = 1,            // 1Hz = 每秒一次 tick

    // 各相位持续“秒数”(Moore)
    parameter int unsigned T_A_GREEN = 4,
    parameter int unsigned T_A_YEL   = 2,
    parameter int unsigned T_B_GREEN = 4,
    parameter int unsigned T_B_YEL   = 2,
    parameter int unsigned T_ALL_RED = 5             // 关键:双红 5 秒
)(
    input  logic clk,
    input  logic rst_n,

    // 便于上色的独立 RGB 端口
    output logic LA_R, LA_Y, LA_G,
    output logic LB_R, LB_Y, LB_G,

    // 兼容作业图的 3 位总线(约定 [2]=R, [1]=Y, [0]=G)
    output logic [2:0] LA,
    output logic [2:0] LB
);

    // =========================
    // 1) 1Hz tick 分频器
    // =========================
    localparam int unsigned DIVISOR = (TICK_HZ == 0) ? 1 : (CLK_HZ / TICK_HZ);
    logic [$clog2(DIVISOR)-1:0] div_cnt;
    logic tick_1hz;

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            div_cnt  <= '0;
            tick_1hz <= 1'b0;
        end else begin
            if (div_cnt == DIVISOR-1) begin
                div_cnt  <= '0;
                tick_1hz <= 1'b1;
            end else begin
                div_cnt  <= div_cnt + 1'b1;
                tick_1hz <= 1'b0;
            end
        end
    end

    // =========================
    // 2) 状态机(Moore)
    // =========================
    typedef enum logic [2:0] {
        S_A_G,        // A 绿
        S_A_Y,        // A 黄
        S_ALL_RED1,   // 双红(A->B 过渡)
        S_B_G,        // B 绿
        S_B_Y,        // B 黄
        S_ALL_RED2    // 双红(B->A 过渡)
    } state_t;

    state_t state, state_n;

    // =========================
    // 3) 当前状态计秒
    // =========================
    // 计算最长持续时间以决定计数器位宽
    localparam int unsigned MAX_AB1   = (T_A_GREEN > T_A_YEL)   ? T_A_GREEN : T_A_YEL;
    localparam int unsigned MAX_AB2   = (T_B_GREEN > T_B_YEL)   ? T_B_GREEN : T_B_YEL;
    localparam int unsigned MAX_AB3   = (MAX_AB1   > MAX_AB2)   ? MAX_AB1   : MAX_AB2;
    localparam int unsigned MAX_DUR   = (MAX_AB3   > T_ALL_RED) ? MAX_AB3   : T_ALL_RED;
    localparam int unsigned SECW      = (MAX_DUR <= 1) ? 1 : $clog2(MAX_DUR);

    logic [SECW-1:0] sec_cnt;
    logic            sec_done;

    function automatic int unsigned dur_of(state_t s);
        case (s)
            S_A_G      : return T_A_GREEN;
            S_A_Y      : return T_A_YEL;
            S_ALL_RED1 : return T_ALL_RED;
            S_B_G      : return T_B_GREEN;
            S_B_Y      : return T_B_YEL;
            S_ALL_RED2 : return T_ALL_RED;
            default    : return T_ALL_RED;
        endcase
    endfunction

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            sec_cnt <= '0;
        end else if (tick_1hz) begin
            if (sec_cnt == dur_of(state)-1)
                sec_cnt <= '0;
            else
                sec_cnt <= sec_cnt + 1'b1;
        end
    end
    assign sec_done = tick_1hz && (sec_cnt == dur_of(state)-1);

    // 次态组合逻辑
    always_comb begin
        state_n = state;
        unique case (state)
            S_A_G      : if (sec_done) state_n = S_A_Y;
            S_A_Y      : if (sec_done) state_n = S_ALL_RED1;
            S_ALL_RED1 : if (sec_done) state_n = S_B_G;
            S_B_G      : if (sec_done) state_n = S_B_Y;
            S_B_Y      : if (sec_done) state_n = S_ALL_RED2;
            S_ALL_RED2 : if (sec_done) state_n = S_A_G;
            default    :              state_n = S_A_G;
        endcase
    end

    // 状态寄存器
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) state <= S_A_G;
        else        state <= state_n;
    end

    // =========================
    // 4) Moore 输出(仅依赖状态)
    // =========================
    always_comb begin
        LA_R=0; LA_Y=0; LA_G=0;
        LB_R=0; LB_Y=0; LB_G=0;

        unique case (state)
            S_A_G      : begin LA_G=1; LB_R=1; end
            S_A_Y      : begin LA_Y=1; LB_R=1; end
            S_ALL_RED1 : begin LA_R=1; LB_R=1; end
            S_B_G      : begin LA_R=1; LB_G=1; end
            S_B_Y      : begin LA_R=1; LB_Y=1; end
            S_ALL_RED2 : begin LA_R=1; LB_R=1; end
        endcase
    end

    // 汇总 3 位总线([2]=R, [1]=Y, [0]=G)
    assign LA = {LA_R, LA_Y, LA_G};
    assign LB = {LB_R, LB_Y, LB_G};

    // (可选)安全断言:在 ALL_RED 状态时两灯必须红
    // property p_allred; @(posedge clk) (state inside {S_ALL_RED1,S_ALL_RED2}) |-> (LA_R && LB_R && !LA_Y && !LA_G && !LB_Y && !LB_G); endproperty
    // assert property (p_allred);

    // 把内部信号对外可见(便于 .do 抓)
    // synthesis translate_off
    // (* keep = "true" *)  // 某些综合器的保留指示;仿真无影响
    // synthesis translate_on

endmodule