`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Module Name: nexys_a7_uart_top
// Description: Top-Level Verilog RTL for Nexys A7 FPGA UART Interface
// 
// Functionality:
//  - Receives 4 bytes from host Python script over USB-UART (UART_TXD_IN pin C4).
//  - Updates LED[15:8] with each received byte.
//  - Displays 32-bit hex value of the 4 received bytes on 7-segment array DISP2 (AN[7:4]).
//  - Transmits 8 bytes back to host Python script over USB-UART (UART_RXD_OUT pin D4).
//  - Updates LED[7:0] with each transmitted byte.
//////////////////////////////////////////////////////////////////////////////////

module top (
    input  wire        CLK100MHZ,   // 100 MHz System Clock (Pin E3)
    input  wire        CPU_RESETN,  // CPU Reset Button (Pin C12, Active Low)
    
    // UART Physical Pins
    input  wire        UART_TXD_IN, // FPGA UART RX Line (Pin C4)
    output wire        UART_RXD_OUT,// FPGA UART TX Line (Pin D4)
    
    // Board Outputs
    output reg  [15:0] LED,         // LED[15:8] for RX bytes, LED[7:0] for TX bytes
    output reg  [7:0]  AN,          // 7-Segment Anodes (Active Low)
    output reg  [6:0]  SEG          // 7-Segment Cathodes CA..CG (Active Low)
);

    // Synchronous Reset Signal (Active High)
    wire reset = ~CPU_RESETN;

    // ------------------------------------------------------------------------
    // 1. UART Core Instantiation
    // ------------------------------------------------------------------------
    reg        ld_tx_data;
    reg  [7:0] tx_data;
    wire       tx_empty;
    reg        uld_rx_data;
    wire [7:0] rx_data;
    wire       rx_empty;

    uart #(
        .CLK_DIVISION(868) // 100MHz / 115200 Baud 
    ) uart_inst (
        .clk         (CLK100MHZ),
        .reset       (reset),
        .ld_tx_data  (ld_tx_data),
        .tx_data     (tx_data),
        .tx_enable   (1'b1),
        .tx_out      (UART_RXD_OUT),
        .tx_empty    (tx_empty),
        .uld_rx_data (uld_rx_data),
        .rx_data     (rx_data),
        .rx_enable   (1'b1),
        .rx_in       (UART_TXD_IN),
        .rx_empty    (rx_empty)
    );

    // ------------------------------------------------------------------------
    // 2. FSM and Registers for RX (4 bytes) & TX (8 bytes)
    // ------------------------------------------------------------------------
    localparam STATE_IDLE      = 3'd0;
    localparam STATE_RX_WAIT   = 3'd1;
    localparam STATE_RX_UNLOAD = 3'd2;
    localparam STATE_TX_LOAD   = 3'd3;
    localparam STATE_TX_WAIT   = 3'd4;

    reg [2:0]  state;
    reg [2:0]  rx_cnt;       // Counts 0..4 received bytes
    reg [3:0]  tx_cnt;       // Counts 0..8 transmitted bytes
    reg [31:0] rx_buffer;    // Stores 4 received bytes (32 bits) for DISP2
    reg [31:0] disp_hex_reg; // Latched 32-bit hex value for 7-segment display

    // Memory buffer holding 8 bytes to send back to Python script
    reg [7:0] tx_rom [0:7];
    ////assign LED = {rx_data,tx_data};
    //always @ (posedge CLK100MHZ) begin
    //   if (!rx_empty && uld_rx_data) begin
    //      LED[15:8] <=rx_data;
    //   end
    //   if (tx_empty && ld_tx_data) begin
    //      LED[7:0] <=tx_data;
    //   end
    //end


    always @(posedge CLK100MHZ or posedge reset) begin
        if (reset) begin
            state        <= STATE_IDLE;
            rx_cnt       <= 3'd0;
            tx_cnt       <= 4'd0;
            rx_buffer    <= 32'd0;
            disp_hex_reg <= 32'h12345678; // Initial default hex value
            ld_tx_data   <= 1'b0;
            uld_rx_data  <= 1'b0;
            tx_data      <= 8'd0;
        end else begin
            // Default single-cycle pulse clears
            uld_rx_data <= 1'b0;
            ld_tx_data  <= 1'b0;

            case (state)
                STATE_IDLE: begin
                    rx_cnt <= 3'd0;
                    tx_cnt <= 4'd0;
                    state <= STATE_RX_UNLOAD;
                end

                // Unload received byte from UART core
                STATE_RX_UNLOAD: begin
                   uld_rx_data <= 1'b1; // Trigger rx_data update
                   if (!rx_empty) begin
                      state       <= STATE_RX_WAIT;
                   end
                end

                STATE_RX_WAIT: begin
                    // Store byte and update LED[15:8]
                    rx_buffer <= {rx_buffer[23:0], rx_data}; // Shift in incoming byte
                    rx_cnt    <= rx_cnt + 1'b1;

                    if (rx_cnt + 1'b1 == 3'd4) begin
                        // Received full block of 4 bytes -> update DISP2 hex display
                        disp_hex_reg <= {rx_buffer[23:0], rx_data};

                        // Populate 8 response bytes (e.g. echo inverted + status/counters)
                        tx_rom[0] <= ~rx_buffer[23:16];
                        tx_rom[1] <= ~rx_buffer[15:8];
                        tx_rom[2] <= ~rx_buffer[7:0];
                        tx_rom[3] <= ~rx_data;
                        tx_rom[4] <= 8'hAA;
                        tx_rom[5] <= 8'hBB;
                        tx_rom[6] <= 8'hCC;
                        tx_rom[7] <= 8'hDD;

                        tx_cnt    <= 4'd0;
                        state     <= STATE_TX_LOAD;
                    end else begin
                        state     <= STATE_RX_UNLOAD;
                    end
                end

                // Start transmission of response byte
                STATE_TX_LOAD: begin
                    if (tx_empty) begin
                        tx_data    <= tx_rom[tx_cnt];
                        //LED[7:0]   <= tx_rom[tx_cnt]; // Update LED[7:0] with outgoing byte
                        ld_tx_data <= 1'b1;           // Trigger send
                        state      <= STATE_TX_WAIT;
                    end
                end

                STATE_TX_WAIT: begin
                    if (!tx_empty) begin
                        // Transmission started
                    end else if (tx_empty && !ld_tx_data) begin
                        // Byte transmission complete
                        if (tx_cnt + 1'b1 == 4'd8) begin
                            state <= STATE_IDLE; // Completed 8 byte transmit
                        end else begin
                            tx_cnt <= tx_cnt + 1'b1;
                            state  <= STATE_TX_LOAD;
                        end
                    end
                end

                default: state <= STATE_IDLE;
            endcase
        end
    end // always @ (posedge CLK100MHZ or posedge reset)


      // ------------------------------------------------------------------------
    // LED Probe Module Instantiation
    // ------------------------------------------------------------------------
    uart_to_led_probe uart_to_led_probe_inst (
					      .clk         (CLK100MHZ),
					      .reset       (reset),
					      .rx_data     (rx_data),
					      .rx_empty    (rx_empty),
					      .uld_rx_data (uld_rx_data),
					      .tx_data     (tx_data),
					      .tx_empty    (tx_empty),
					      .ld_tx_data  (ld_tx_data),
					      .LED         (LED)
					      );


    // ------------------------------------------------------------------------
    // 7-Segment Display Multiplexer Instantiation
    // ------------------------------------------------------------------------
    seven_seg_driver seven_seg_driver_inst (
                                            .clk          (CLK100MHZ),
                                            .reset        (reset),
                                            .disp_hex_val (disp_hex_reg),
                                            .AN           (AN),
                                            .SEG          (SEG)
                                            );

endmodule
