Загрузка данных


module multi_melody_player_final #(
    parameter CLK_FREQ    = 12_000_000, // Тактовая частота
    parameter DEBOUNCE_MS = 20,         // Дребезг (мс)
    parameter SEG_ANODE   = 1'b0        // 1 – общий анод, 0 – общий катод
)(
    input  wire         clk,
    input  wire [7:0]   btn,          // активный 0
    output wire [7:0]   led,
    output wire [7:0]   dig0, dig1, dig2, dig3,
    output wire         speaker
);

// ------------------- Вычисляемые параметры -------------------
localparam DEBOUNCE_TICKS = (CLK_FREQ / 1000) * DEBOUNCE_MS; // тактов до 20 мс
localparam CNT_W          = $clog2(DEBOUNCE_TICKS+1);        // разрядность счётчика
localparam TEMPO_MAX      = CLK_FREQ / 4;                    // 0.25 с на 1/16 (♩=60)

// ------------------- Синхронизация кнопок -------------------
reg [7:0] btn_sync0, btn_sync1;
always @(posedge clk) begin
    btn_sync0 <= ~btn;      // активный 0 -> 1
    btn_sync1 <= btn_sync0;
end

// ------------------- Антидребезг + однотактовый импульс -------------------
reg [CNT_W-1:0] btn_cnt [0:7];
reg [7:0]       btn_pressed;     // импульс 1 такт
reg [7:0]       btn_pressed_d;   // флаг, что импульс уже выдан

genvar i;
generate for (i = 0; i < 8; i = i + 1) begin : debounce
    always @(posedge clk) begin
        if (btn_sync1[i]) begin
            if (btn_cnt[i] < DEBOUNCE_TICKS)
                btn_cnt[i] <= btn_cnt[i] + 1'b1;
        end else begin
            btn_cnt[i] <= 0;
            btn_pressed_d[i] <= 1'b0;  // сброс флага при отпускании
        end

        // Генерация однотактового импульса
        if (btn_cnt[i] == DEBOUNCE_TICKS-1 && !btn_pressed_d[i]) begin
            btn_pressed[i] <= 1'b1;
            btn_pressed_d[i] <= 1'b1;
        end else begin
            btn_pressed[i] <= 1'b0;
        end
    end
end
endgenerate

// ------------------- Выбор мелодии и счётчик темпа -------------------
reg [2:0] melody;
reg [7:0] step;
reg [23:0] tempo_cnt;
reg        step_tick;  // импульс при смене шага

always @(posedge clk) begin
    step_tick <= 1'b0; // по умолчанию сброс

    if (btn_pressed[0]) begin
        melody    <= 3'd0;
        step      <= 8'd0;
        tempo_cnt <= 0;
    end else if (btn_pressed[1]) begin
        melody    <= 3'd1;
        step      <= 8'd0;
        tempo_cnt <= 0;
    end else if (btn_pressed[2]) begin
        melody    <= 3'd2;
        step      <= 8'd0;
        tempo_cnt <= 0;
    end else if (btn_pressed[3]) begin
        melody    <= 3'd3;
        step      <= 8'd0;
        tempo_cnt <= 0;
    end else if (btn_pressed[4]) begin
        melody    <= 3'd4;
        step      <= 8'd0;
        tempo_cnt <= 0;
    end else if (btn_pressed[5]) begin
        melody    <= 3'd5;
        step      <= 8'd0;
        tempo_cnt <= 0;
    end else if (btn_pressed[6]) begin
        melody    <= 3'd6;
        step      <= 8'd0;
        tempo_cnt <= 0;
    end else if (btn_pressed[7]) begin
        melody    <= 3'd7;
        step      <= 8'd0;
        tempo_cnt <= 0;
    end else begin
        if (tempo_cnt == TEMPO_MAX) begin
            tempo_cnt <= 0;
            step      <= step + 1'b1;
            step_tick <= 1'b1;        // импульс на смене шага
        end else begin
            tempo_cnt <= tempo_cnt + 1'b1;
        end
    end
end

// ------------------- Таблица нот (нота -> код 0..15) -------------------
reg [3:0] note;
always @* begin
    case(melody)
        3'd0: note = 4'd0;   // пусто

        // 1: Ода к радости
        3'd1: case(step)
            8'd0,8'd1: note = 4'd3; 8'd2,8'd3: note = 4'd3;
            8'd4,8'd5: note = 4'd4; 8'd6,8'd7: note = 4'd5;
            8'd8,8'd9: note = 4'd5; 8'd10,8'd11: note = 4'd4;
            8'd12,8'd13: note = 4'd3; 8'd14,8'd15: note = 4'd2;
            8'd16,8'd17: note = 4'd1; 8'd18,8'd19: note = 4'd1;
            8'd20,8'd21: note = 4'd2; 8'd22,8'd23: note = 4'd3;
            8'd24,8'd25: note = 4'd3; 8'd26,8'd27: note = 4'd2;
            8'd28,8'd29: note = 4'd2;
            // повтор фразы
            8'd30,8'd31: note = 4'd3; 8'd32,8'd33: note = 4'd3;
            8'd34,8'd35: note = 4'd4; 8'd36,8'd37: note = 4'd5;
            8'd38,8'd39: note = 4'd5; 8'd40,8'd41: note = 4'd4;
            8'd42,8'd43: note = 4'd3; 8'd44,8'd45: note = 4'd2;
            8'd46,8'd47: note = 4'd1; 8'd48,8'd49: note = 4'd1;
            8'd50,8'd51: note = 4'd2; 8'd52,8'd53: note = 4'd3;
            8'd54,8'd55: note = 4'd3; 8'd56,8'd57: note = 4'd2;
            8'd58,8'd59: note = 4'd2;
            default: note = 4'd0;
        endcase

        // 2: Happy Birthday
        3'd2: case(step)
            8'd0,8'd1: note = 4'd5; 8'd2,8'd3: note = 4'd5;
            8'd4,8'd5: note = 4'd6; 8'd6,8'd7: note = 4'd5;
            8'd8,8'd9,8'd10,8'd11: note = 4'd8;
            8'd12,8'd13,8'd14,8'd15: note = 4'd7;
            8'd16,8'd17: note = 4'd5; 8'd18,8'd19: note = 4'd5;
            8'd20,8'd21: note = 4'd6; 8'd22,8'd23: note = 4'd5;
            8'd24,8'd25,8'd26,8'd27: note = 4'd9;
            8'd28,8'd29,8'd30,8'd31: note = 4'd8;
            8'd32,8'd33: note = 4'd5; 8'd34,8'd35: note = 4'd5;
            8'd36,8'd37: note = 4'd3; 8'd38,8'd39: note = 4'd8;
            8'd40,8'd41: note = 4'd7; 8'd42,8'd43: note = 4'd6;
            8'd44,8'd45: note = 4'd4; 8'd46,8'd47: note = 4'd4;
            8'd48,8'd49: note = 4'd3; 8'd50,8'd51: note = 4'd8;
            8'd52,8'd53: note = 4'd7; 8'd54,8'd55,8'd56,8'd57: note = 4'd6;
            default: note = 4'd0;
        endcase

        // 3: Имперский марш
        3'd3: case(step)
            8'd0: note = 4'd3; 8'd1: note = 4'd3; 8'd2: note = 4'd3;
            8'd3,8'd4: note = 4'd1; 8'd5: note = 4'd5; 8'd6: note = 4'd3;
            8'd7,8'd8: note = 4'd1; 8'd9: note = 4'd5; 8'd10: note = 4'd3;
            // расширение
            8'd11: note = 4'd0; 8'd12: note = 4'd3; 8'd13: note = 4'd3;
            8'd14: note = 4'd3; 8'd15,8'd16: note = 4'd1; 8'd17: note = 4'd5;
            8'd18: note = 4'd3; 8'd19,8'd20: note = 4'd1; 8'd21: note = 4'd5;
            8'd22: note = 4'd3;
            default: note = 4'd0;
        endcase

        // 4: Jingle Bells
        3'd4: case(step)
            8'd0,8'd1: note = 4'd3; 8'd2,8'd3: note = 4'd3; 8'd4,8'd5: note = 4'd3;
            8'd6,8'd7: note = 4'd3; 8'd8,8'd9: note = 4'd3; 8'd10,8'd11: note = 4'd3;
            8'd12,8'd13: note = 4'd3; 8'd14,8'd15: note = 4'd5;
            8'd16,8'd17: note = 4'd1; 8'd18,8'd19: note = 4'd2; 8'd20,8'd21: note = 4'd3;
            // повтор
            8'd22,8'd23: note = 4'd4; 8'd24,8'd25: note = 4'd4; 8'd26,8'd27: note = 4'd4;
            8'd28,8'd29: note = 4'd4; 8'd30,8'd31: note = 4'd4; 8'd32,8'd33: note = 4'd3;
            8'd34,8'd35: note = 4'd3; 8'd36,8'd37: note = 4'd3;
            8'd38,8'd39: note = 4'd2; 8'd40,8'd41: note = 4'd2;
            8'd42,8'd43: note = 4'd3; 8'd44,8'd45: note = 4'd2;
            8'd46,8'd47: note = 4'd5;
            default: note = 4'd0;
        endcase

        // 5: Маленькая ночная серенада
        3'd5: case(step)
            8'd0: note = 4'd5; 8'd1,8'd2: note = 4'd2; 8'd3: note = 4'd3;
            8'd4: note = 4'd4; 8'd5: note = 4'd3; 8'd6: note = 4'd2;
            8'd7: note = 4'd1; 8'd8: note = 4'd2; 8'd9: note = 4'd3;
            8'd10: note = 4'd4; 8'd11: note = 4'd3; 8'd12: note = 4'd2;
            8'd13: note = 4'd1;
            // вторая фраза
            8'd14: note = 4'd5; 8'd15,8'd16: note = 4'd2; 8'd17: note = 4'd3;
            8'd18: note = 4'd4; 8'd19: note = 4'd3; 8'd20: note = 4'd2;
            8'd21: note = 4'd1; 8'd22: note = 4'd2; 8'd23: note = 4'd3;
            8'd24: note = 4'd4; 8'd25: note = 4'd3; 8'd26: note = 4'd2;
            8'd27: note = 4'd1;
            default: note = 4'd0;
        endcase

        // 6: Yesterday
        3'd6: case(step)
            8'd0: note = 4'd4; 8'd1: note = 4'd3; 8'd2: note = 4'd3;
            8'd3: note = 4'd4; 8'd4,8'd5: note = 4'd5; 8'd6,8'd7: note = 4'd6;
            8'd8: note = 4'd5; 8'd9: note = 4'd4; 8'd10: note = 4'd3;
            8'd11: note = 4'd2; 8'd12: note = 4'd1;
            8'd13: note = 4'd0;
            8'd14: note = 4'd4; 8'd15: note = 4'd3; 8'd16: note = 4'd3;
            8'd17: note = 4'd4; 8'd18,8'd19: note = 4'd5; 8'd20,8'd21: note = 4'd6;
            8'd22: note = 4'd5; 8'd23: note = 4'd4; 8'd24: note = 4'd3;
            8'd25: note = 4'd2; 8'd26: note = 4'd1;
            default: note = 4'd0;
        endcase

        // 7: Коробейники
        3'd7: case(step)
            8'd0: note = 4'd3; 8'd1: note = 4'd7; 8'd2: note = 4'd8;
            8'd3: note = 4'd9; 8'd4: note = 4'd10; 8'd5: note = 4'd9;
            8'd6: note = 4'd8; 8'd7: note = 4'd7; 8'd8: note = 4'd6;
            8'd9: note = 4'd6; 8'd10: note = 4'd8; 8'd11: note = 4'd10;
            8'd12: note = 4'd9; 8'd13: note = 4'd8; 8'd14: note = 4'd7;
            8'd15: note = 4'd3; 8'd16: note = 4'd7; 8'd17: note = 4'd8;
            8'd18: note = 4'd9; 8'd19: note = 4'd10; 8'd20: note = 4'd9;
            8'd21: note = 4'd8; 8'd22: note = 4'd7; 8'd23: note = 4'd6;
            8'd24: note = 4'd6; 8'd25: note = 4'd8; 8'd26: note = 4'd10;
            8'd27: note = 4'd9; 8'd28: note = 4'd8; 8'd29: note = 4'd7;
            default: note = 4'd0;
        endcase

        default: note = 4'd0;
    endcase
end

// ------------------- Делители частоты (12 МГц) -------------------
reg [15:0] divider;
always @* begin
    case(note)
        4'd0:  divider = 16'd0;
        4'd1:  divider = 16'd22932; // C4
        4'd2:  divider = 16'd20420; // D4
        4'd3:  divider = 16'd18186; // E4
        4'd4:  divider = 16'd17167; // F4
        4'd5:  divider = 16'd15306; // G4
        4'd6:  divider = 16'd13632; // A4
        4'd7:  divider = 16'd12148; // B4
        4'd8:  divider = 16'd11467; // C5
        4'd9:  divider = 16'd10215; // D5
        4'd10: divider = 16'd9099;  // E5
        4'd11: divider = 16'd8583;  // F5
        4'd12: divider = 16'd7647;  // G5
        4'd13: divider = 16'd6818;  // A5
        4'd14: divider = 16'd12868; // Bb4
        4'd15: divider = 16'd21653; // C#4
        default: divider = 16'd0;
    endcase
end

// ------------------- Генератор звука -------------------
reg [15:0] cnt = 0;
reg spk = 0;
always @(posedge clk) begin
    if (divider == 16'd0) begin
        cnt <= 0;
        spk <= 1'b0;
    end else begin
        if (cnt == 16'd0) begin
            cnt <= divider;
            spk <= ~spk;
        end else begin
            cnt <= cnt - 1'b1;
        end
    end
end
assign speaker = spk;

// ------------------- Светодиоды: прогресс и ритм -------------------
reg [7:0] melody_length;
always @* begin
    case(melody)
        3'd0: melody_length = 8'd1;
        3'd1: melody_length = 8'd60;
        3'd2: melody_length = 8'd58;
        3'd3: melody_length = 8'd23;
        3'd4: melody_length = 8'd48;
        3'd5: melody_length = 8'd28;
        3'd6: melody_length = 8'd27;
        3'd7: melody_length = 8'd30;
        default: melody_length = 8'd1;
    endcase
end

wire [7:0] progress_index = (step * 8) / melody_length;  // 0..7
wire [7:0] progress_led = (progress_index == 0) ? 8'b00000001 :
                          (progress_index == 1) ? 8'b00000010 :
                          (progress_index == 2) ? 8'b00000100 :
                          (progress_index == 3) ? 8'b00001000 :
                          (progress_index == 4) ? 8'b00010000 :
                          (progress_index == 5) ? 8'b00100000 :
                          (progress_index == 6) ? 8'b01000000 :
                          (progress_index == 7) ? 8'b10000000 : 8'b00000000;

assign led = {step_tick, progress_led[6:0]}; // старший бит – ритм, остальные – прогресс

// ------------------- Читаемый дисплей -------------------
// Коды символов для дешифратора
localparam SYM_0  = 5'd0,  SYM_1 = 5'd1,  SYM_2 = 5'd2,  SYM_3 = 5'd3,
           SYM_4  = 5'd4,  SYM_5 = 5'd5,  SYM_6 = 5'd6,  SYM_7 = 5'd7,
           SYM_8  = 5'd8,  SYM_9 = 5'd9,
           SYM_A  = 5'd10, SYM_B = 5'd11, SYM_C = 5'd12, SYM_D = 5'd13,
           SYM_E  = 5'd14, SYM_F = 5'd15, SYM_G = 5'd16,
           SYM_DASH = 5'd17, SYM_BLANK = 5'd18,
           SYM_P  = 5'd19, SYM_SHARP = 5'd20, SYM_FLAT = 5'd21;

reg [4:0] dig_letter, dig_octave, dig_alter;
always @* begin
    case(note)
        4'd1:  begin dig_letter = SYM_C; dig_octave = SYM_4; dig_alter = SYM_BLANK; end // C4
        4'd2:  begin dig_letter = SYM_D; dig_octave = SYM_4; dig_alter = SYM_BLANK; end // D4
        4'd3:  begin dig_letter = SYM_E; dig_octave = SYM_4; dig_alter = SYM_BLANK; end // E4
        4'd4:  begin dig_letter = SYM_F; dig_octave = SYM_4; dig_alter = SYM_BLANK; end // F4
        4'd5:  begin dig_letter = SYM_G; dig_octave = SYM_4; dig_alter = SYM_BLANK; end // G4
        4'd6:  begin dig_letter = SYM_A; dig_octave = SYM_4; dig_alter = SYM_BLANK; end // A4
        4'd7:  begin dig_letter = SYM_B; dig_octave = SYM_4; dig_alter = SYM_BLANK; end // B4
        4'd8:  begin dig_letter = SYM_C; dig_octave = SYM_5; dig_alter = SYM_BLANK; end // C5
        4'd9:  begin dig_letter = SYM_D; dig_octave = SYM_5; dig_alter = SYM_BLANK; end // D5
        4'd10: begin dig_letter = SYM_E; dig_octave = SYM_5; dig_alter = SYM_BLANK; end // E5
        4'd11: begin dig_letter = SYM_F; dig_octave = SYM_5; dig_alter = SYM_BLANK; end // F5
        4'd12: begin dig_letter = SYM_G; dig_octave = SYM_5; dig_alter = SYM_BLANK; end // G5
        4'd13: begin dig_letter = SYM_A; dig_octave = SYM_5; dig_alter = SYM_BLANK; end // A5
        4'd14: begin dig_letter = SYM_B; dig_octave = SYM_4; dig_alter = SYM_FLAT; end // Bb4
        4'd15: begin dig_letter = SYM_C; dig_octave = SYM_4; dig_alter = SYM_SHARP; end // C#4
        default: begin dig_letter = SYM_P; dig_octave = SYM_BLANK; dig_alter = SYM_BLANK; end // пауза
    endcase
end

// ------------------- Дешифратор 7 сегментов (5 бит -> 8 бит) -------------------
function [7:0] seg_decode(input [4:0] sym);
    reg [7:0] code;
    begin
        case(sym)
            5'd0:  code = 8'b00111111; // 0
            5'd1:  code = 8'b00000110; // 1
            5'd2:  code = 8'b01011011; // 2
            5'd3:  code = 8'b01001111; // 3
            5'd4:  code = 8'b01100110; // 4
            5'd5:  code = 8'b01101101; // 5
            5'd6:  code = 8'b01111101; // 6
            5'd7:  code = 8'b00000111; // 7
            5'd8:  code = 8'b01111111; // 8
            5'd9:  code = 8'b01101111; // 9
            5'd10: code = 8'b01110111; // A
            5'd11: code = 8'b01111100; // b
            5'd12: code = 8'b00111001; // C
            5'd13: code = 8'b01011110; // d
            5'd14: code = 8'b01111001; // E
            5'd15: code = 8'b01110001; // F
            5'd16: code = 8'b00111101; // G
            5'd17: code = 8'b01000000; // -
            5'd18: code = 8'b00000000; // пусто
            5'd19: code = 8'b01110011; // P
            5'd20: code = 8'b00100010; // # (упрощённо)
            5'd21: code = 8'b01111100; // b (как b)
            default: code = 8'b00000000;
        endcase
        seg_decode = SEG_ANODE ? ~code : code;
    end
endfunction

assign dig3 = seg_decode(dig_letter);
assign dig2 = seg_decode(dig_octave);
assign dig1 = seg_decode(dig_alter);
assign dig0 = seg_decode(SYM_BLANK);  // четвёртый разряд свободен

endmodule