/***
 * nexys_a7_top.sv - top level design module specific to Nexys A7100T.
 *
 * @author: Waylon Cude, Dilanthi Prentice
 * @date: 6/12/2025
 *
 * **/
`ifdef VERILATOR
    `include "sdvd_defs.sv"
`endif
import sdvd_defs::SPEED;
module nexys_a7_top(
    input logic CLK100MHZ, CPU_RESETN,
    input logic BTNC, BTNR,
    output logic AUD_PWM, AUD_SD,
    output logic CA,CB,CC,CD,CE,CF,CG,
    output logic [7:0] AN,
    output wire LED[0:0],
    output wire SD_RESET,SD_SCK,
    inout wire [3:0] SD_DAT,
    inout wire SD_CMD,
    input wire SD_CD
);

// Active high reset
wire reset;
assign reset = ~CPU_RESETN;

logic clk_1khz, clk_10hz;
logic clk_48khz, clk_1mhz;
logic seconds_pulse;

SPEED speed;

audio_buffer_interface audio_interface();

// Map C{A-G} to an array of 7-segment displays
wire [6:0] segments [7:0];
wire [2:0] segment_mux_select;

// These segments are currently unused
assign segments[7] = 0;
assign segments[6] = 0;
// These are the ones we're using
assign {CA,CB,CC,CD,CE,CF,CG} = ~segments[segment_mux_select];

logic [$clog2(60)-1:0] seconds;
logic [$clog2(60)-1:0] minutes;
logic [$clog2(60)-1:0] hours;

logic [15:0] audio_sample;
logic sd_ready;
logic playing;

assign LED[0] = playing;
assign AUD_SD = playing;

low_freq_clock_gen clockGen(CLK100MHZ, reset, speed, 'z, clk_10hz, seconds_pulse);

modular_clock_gen #(100_000) anodeClock(CLK100MHZ, reset, clk_1khz);

// Create a clock with a divisor of 2083, making ~48khz
modular_clock_gen #(2083) audioClock(CLK100MHZ, reset, clk_48khz);
modular_clock_gen #(100) pwmClock(CLK100MHZ, reset, clk_1mhz);


// Count the number on seconds, hours, and minutes elapsed
// If the speed is faster this will pulse more often than once a second
// but will still theoretically be a second of video time
always_ff @(posedge seconds_pulse or posedge reset) begin
    if (reset) begin
        seconds <= 0;
        minutes <= 0;
        hours <= 0;
    end
    else if (seconds == 59) begin
        seconds <= 0;
        if (minutes == 59) begin
            minutes <= 0;
            hours <= hours + 1;
        end
        else
            minutes <= minutes + 1;
    end
    else
        seconds <= seconds + 1;
end

display_anode_driver anodeDriver(clk_1khz,reset,AN,segment_mux_select);

seconds_display secondsSegment (seconds, segments[1], segments[0]);
seconds_display minutesSegment (minutes, segments[3], segments[2]);
seconds_display hoursSegment (hours, segments[5], segments[4]);

// Run the playback speed state machine at a lower rate
// Gets rid of button bouncing
playback_controller playbackController (clk_10hz,reset,BTNC, BTNR, speed);

pwm audioOutput(CLK100MHZ, reset, clk_48khz, audio_sample, AUD_PWM);
audio_buffer audioBuffer(
    clk_48khz, 
    reset, 
    sd_ready, 
    '0, // stop signal not used right now 
    speed, 
    playing,
    audio_sample, 
    audio_interface.receiver
);

`ifdef ROM
    rom_sd #("even_flow_16.mem") romSdPlayer(clk_1mhz,reset,sd_ready,audio_interface.driver);
    assign {SD_RESET,SD_DAT,SD_CMD,SD_SCK} = 'z;
`else
    // Power the sd slot
    assign SD_RESET = 0;
    // We don't use more than one dat line
    assign SD_DAT[3:1] = 'z;
    logic clk_100khz;
    logic clk_25mhz;
    // We can clock this at around 200khz before things start breaking
    // Even at 200khz sometimes things break
    modular_clock_gen #(1000) slowSdClock(CLK100MHZ, reset, clk_100khz);
    // Try clocking this slower than max speed
    // To see if that makes it actually work 
    //
    // NOTE: It did not make it work
    modular_clock_gen #(1000) fastSdClock(CLK100MHZ, reset, clk_25mhz);
    sd_controller realSdPlayer(
        clk_100khz,
        clk_25mhz,
        CLK100MHZ,
        reset,
        SD_DAT[0],
        SD_CMD,
        sd_ready,
        SD_SCK,
        audio_interface.driver
    );

`endif


endmodule
