`timescale 1ns/1ps
module top(
    input clock,            // system clock
    input reset,            // BTNR
    input version,          // BTNU
    input adc_n, adc_p,     // VCAUX 6, P and N
    input [15:0] sw,        // slide switches
    output [15:0] led,      // 16  onboard LEDs above the switches
    output [6:0] segment,   // 4 digit LED display
    output dp,              // "." next to each LED digit
    output [3:0] digit,     // 7-segment display anode select
    output reg [7:0] JB,        // PMOD JB for debugging
    output [7:0] JA,        // PMOD JA for debugging
    input rx,               // UART receive
    output tx               // UART transmit
    );
    parameter VERSION = 'h0011;
    //
    //  generate a 25MHz and 8MHz clock for the UART and FIFO
    //
    wire locked, clock25, clock8;
    clocks  MYCLOCKS (
        .reset(reset),
        .clk_in1(clock),
        .locked(locked),
        .clk_out1(clock25),
        .clk_out2(clock8)
    );
    //
    //  divide clock8 by 8 to get the 1MHz ADC clock
    //
    reg [2:0] count8;
    always @ (posedge clock8) count8 <= count8 + 1;
    wire clock1;
    BUFG clk1buf (.I(count8[2]), .O(clock1));
    //
    //  next drive the 4 7-segment displays
    //
    wire [15:0] display_this;
    display4 DISPLAY (
        .clk100(clock),
        .number(display_this),
        .digit(digit),
        .segments(segment),
        .period(dp)
        );
    //
    //  instantiate the UART receiver.  run with the 50MHz clock so that
    //  we can run the transmitter FSM at 100MHz and not get lost
    //
    wire dv;
    wire [7:0] rx_data;
    uart_rx RECEIVER (
        .i_Clocks_per_Bit('d25),
        .i_Clock(clock25),
        .i_Reset(reset),
        .i_Rx_Serial(rx),       // tied to FPGA rx output
        .o_Rx_DV(dv),
        .o_Rx_Byte(rx_data)
        );
    //
    //  instantiate a fifo for the UART receiving from the RPi
    //  tie rx_wr_en to dv so that we can have the fifo write clock
    //  always going.  read will be controlled by the read/write FSM
    //  in the controller.v module which has clocks running at 1MHz.
    //
    wire rx_wr_en = dv;
    wire rx_full, rx_empty;
    wire rx_rd_en;
    wire [8:0] rx_dout;
    rxfifo FIFO_RX  (           // this fifo is 9 bits wide
        .rst(reset),
        .wr_clk(clock25),
        .rd_clk(clock1),
        .din({1'b0,rx_data}),   // remember, 9 bits in!
        .wr_en(rx_wr_en),
        .rd_en(rx_rd_en),
        .dout(rx_dout),         // and 9 bits out
        .full(rx_full),
        .empty(rx_empty)
    );
    //
    //  instantiate the UART transmitter
    //
    wire tx_active, tx_done;
    wire do_transmit;
    wire [7:0] transmit_byte;
    uart_tx TRANSMITTER (
        .i_Clocks_per_Bit('d25),
        .i_Clock(clock25),
        .i_Reset(reset),
        .i_Tx_DV(do_transmit),
        .i_Tx_Byte(transmit_byte), 
        .o_Tx_Active(tx_active),
        .o_Tx_Serial(tx),       // tied to FPGA tx output
        .o_Tx_Done(tx_done)
        );
    //
    //  note that the OUT FSM in controller waits for tx_done, which comes from uart_tx which
    //  runs with a 25HMz clock whereas this FSM here runs with a 1MHz clock
    //  (so that it can be in sync with the data fifo).  so we will need to
    //  stretch out the tx_done signal, which is only 40ns wide, to make it
    //  1us wide so the OUT FSM doesn't miss it
    //
    wire tx_done_1us;
    stretch TX_STRETCH (
        .clock(clock25),.reset(reset),.ticks('d25),.sigin(tx_done),.sigout(tx_done_1us)
    );
    //
    //  here is the XADC block
    //
    wire [6:0] daddr_in = 7'h16;
    wire adc_ready, isbusy, adc_data_ready, eos_out, alarm;
    wire [15:0] adc_data;
    wire [4:0] channel_out;
    myxadc XADC_INST (
        .daddr_in(7'h16),               // specifies vcaux6 pints to digitize
        .dclk_in(clock),                // 50MHz clock
        .den_in(adc_ready),             // tied to adc_ready, tells adc to convert, tieing causes continuous conversions
        .di_in(16'h0),                  // to set the data to something, not used here
        .dwe_in(1'b0),                  //  set to enable writing to di_in, which we don't want to do
        .vauxp6(adc_p),                 //  positive input to digitize
        .vauxn6(adc_n),                 //  negative input to digitize
        .busy_out(isbusy),              // tells you the adc is busy converting
        .channel_out(channel_out[4:0]), // for using more than 1 channel, tells you which one.  not used here
        .do_out(adc_data),              // adc value from conversion
        .drdy_out(adc_data_ready),      // tells you valid data is ready to be latched
        .eoc_out(adc_ready),            // specifies that the ADC is ready (conversion complete)
        .eos_out(eos_out),              // specifies that conversion sequence is complete
        .alarm_out(alarm),              // OR's output of all internal alarms, not used here
        .vp_in(1'b0),                   // dedicated analog input pair for differential, tied to 0 if not used
        .vn_in(1'b0)
    );
    //
    //  Wait for XADC to tell you something is ready to latch, and latch it into the 
    //  r_adc_data bus. Note this means continuous latching
    //
    reg [15:0] r_adc_data;
    always @ (posedge adc_data_ready) begin
        if (reset) r_adc_data <= 16'h0;
        else r_adc_data <= adc_data;
        end
    //
    //  make a ~1Hz clock so we can run the LED display slower
    //
    reg [19:0] counter;
    reg [15:0] s_adc_data;
    always @ (posedge clock1) begin
        if (reset) counter <= 0;
        else counter <= counter + 1;
        end
    wire clock_1hz = counter[19];
    always @ (posedge clock_1hz) s_adc_data <= r_adc_data;
    assign display_this = version ? VERSION : s_adc_data;
    //
    //  instantiate our data fifo next
    //
    wire triggered;         // comes out of the controller
    wire [17:0] din = {triggered,1'b0,r_adc_data};   // feed this directly into the FIFO data input
    wire [17:0] dout;
    wire [12:0] fifo_adc_out = {dout[17],dout[15:4]};  // send to controller the ADC bits and whether this triggered
    wire wr_en;
    wire rd_en, fifo_full, fifo_empty, wr_rst_busy, rd_rst_busy;
    wire [15:0] fifo_data_count;
    myfifo DATA_FIFO (
        .rst(reset),
        .wr_clk(clock1),
        .rd_clk(clock1),
        .din(din),
        .wr_en(wr_en),
        .rd_en(rd_en),
        .dout(dout),
        .full(fifo_full),
        .empty(fifo_empty),
        .rd_data_count(fifo_data_count),
        .wr_rst_busy(wr_rst_busy),
        .rd_rst_busy(rd_rst_busy)
    );
    //
    //  now make a state machine to deal with transmitting 2 bytes at a
    //  time, including the FIFO value that is present.
    //
    reg [2:0] tx_state;     // 8 states so 3 bits will do
    localparam [2:0] TX_IDLE=0, TX_BYTE1=1, TX_DO1=2, TX_WAIT1=3, TX_BYTE2=4,
                    TX_DO2=5, TX_WAIT2=6, TX_DONE=7;
    reg doit;
    wire [15:0] transmit_word;
    wire begin_transfer;
    reg [7:0] tx_data;
    always @ (posedge clock25) begin
        if (reset) begin
            tx_state <= TX_IDLE;
            doit <= 0;
            tx_data <= 0;
        end
        else 
            case (tx_state)
                TX_IDLE: begin
                    //
                    //  wait for begin_transfer to start
                    //
                    if (begin_transfer) tx_state <= TX_BYTE1;
                    else tx_state <= TX_IDLE;
                    doit <= 0;
                    tx_data <= 0;
                end
                TX_BYTE1: begin
                    //
                    //  latch the first byte of the transmit_word
                    //
                    tx_data <= transmit_word[7:0];
                    tx_state <= TX_DO1;
                end
                TX_DO1: begin
                    //
                    //  turn on uart_tx
                    //
                    doit <= 1;
                    tx_state <= TX_WAIT1;
                end
                TX_WAIT1: begin
                    //
                    //  turn off doit and wait for uart_tx to finish
                    //
                    doit <= 0;
                    if (tx_done) tx_state <= TX_BYTE2;
                    else tx_state <= TX_WAIT1;
                end
                TX_BYTE2: begin
                    //
                    //  latch the 2nd byte to transfer
                    //
                    tx_data <= transmit_word[15:8];
                    tx_state <= TX_DO2;
                end
                TX_DO2: begin
                    //
                    //  turn on uart_tx
                    //
                    doit <= 1;
                    tx_state <= TX_WAIT2;
                end
                TX_WAIT2: begin
                    //
                    //  wait for the 2nd byte to finish begin sent
                    //
                    doit <= 0;
                    if (tx_done) tx_state <= TX_DONE;
                    else tx_state <= TX_WAIT2;
                end
                TX_DONE: begin
                    //
                    //  wait for begin_transfer to go away
                    //
                    if (do_transmit) tx_state <= TX_DONE;
                    else tx_state <= TX_IDLE;
                end
                default: begin
                    tx_state <= TX_IDLE;
                end
            endcase
    end
    assign do_transmit = doit;
    assign transmit_byte = tx_data;
    //
    //  instantiate the controller that handles uart rx, and the data fifo
    //
    wire [31:0] c_debug;
    controller CONTROL (
        .clock(clock1),
        .reset(reset),
        .rx_fifo_empty(rx_empty),
        .rx_fifo_data(rx_dout[7:0]),
        .rx_fifo_rd(rx_rd_en),
        .tx_done(tx_done_1us),
        .tx_transmit(begin_transfer),
        .tx_out(transmit_word),
        .firmware_version(VERSION),
        .test_vector(sw),
        .r_adc_data(r_adc_data),
        .data_fifo_rd_en(rd_en),
        .data_fifo_wr_en(wr_en),
        .data_fifo_empty(fifo_empty),
        .data_fifo_full(fifo_full),
        .data_fifo_data(fifo_adc_out),
        .data_fifo_count(fifo_data_count),
        .led(led),
        .triggered(triggered),
        .debug(c_debug)
        );
    //
    //  use the output ports JA and JB, and the slide switches to get different
    //  debug data for the logic analyzer
    //
    //  c_debug:
    //
    //
    //  2:0 rx_state
    //  3   outgoing_done
    //  4   incoming_done
    //  5   do_outgoing
    //  6   do_incoming
    //  11:7    rx_instructions
    //  15:12   in_state
    //  19:16   out_state
    //  20      tx_transmit
    //  21      out_read_fifo   which is for the ADC fifo
    //  22      in_read_fifo   which is for the rx fifo
    //  23      do_read_fifo    also for the rx fifo
    //  26:24   f_state
    //  27      df_wr_en
    //  28      df_rd_en
    //  29      count_fill
    //  30      data_fifo_empty
    //  31      data_fifo_full
    assign JA = {rx_rd_en,rx_empty,begin_transfer,tx_done,tx,dv,rx,clock25};
    always @*
        case (sw[15:14])
            2'b00: JB = {c_debug[15:12],c_debug[6],c_debug[2:0]};    // in_state,do_incoming,rx_state
            2'b01: JB = {c_debug[19:16],c_debug[5],c_debug[2:0]};    // out_state,do_outgoing,rx_state
            2'b10: JB = c_debug[31:24];     // data_fifo_full,data_fifo_empty,count_fill,rd_en,wr_en,f_state
            2'b11: JB = {c_debug[6],c_debug[5],c_debug[11:7],clock1}; //do_in,do_out,rx_instructions,clock
        endcase
        
endmodule