// ring.v
//
// iCE40 FPGA communication ring test
//
// Erik Strand 9/30/21
//
// This work may be reproduced, modified, distributed,
// performed, and displayed for any purpose, but must
// acknowledge this project. Copyright is retained and
// must be preserved. The work is provided as is; no
// warranty is provided, and users accept all liability.
//

// Cause yosys to throw an error when we implicitly declare nets
`default_nettype none

`include "uart.v"

module top (
    input CLK_12MHZ,
    output P1A1,
    input P1A2,
    input BTN_N,
    output P1A3,
    output P1A4,
    output LEDR_N,
    output LEDG_N
);
    // We use the PLL to generate a 39.75 MHz clock.
    // Any faster than this and icetime complains.
    wire clk;
    wire clk_lock;
    SB_PLL40_PAD #(
        .FEEDBACK_PATH("SIMPLE"),
        .PLLOUT_SELECT("GENCLK"),
        .DIVR(4'b0000),
        .DIVF(7'b0110100),
        .DIVQ(3'b100),
        .FILTER_RANGE(3'b001)
    ) pll_clk (
        .PACKAGEPIN(CLK_12MHZ),
        .PLLOUTGLOBAL(clk),
        .LOCK(clk_lock),
        .RESETB(1'b1),
        .BYPASS(1'b0)
    );

    // We use BTN_N to start the loop.
    // BTN_N is low when pressed.
    // This code produces a 1 clock cycle pulse on btn_up_pulse whenever the button is released.
    wire btn_pressed = !BTN_N;
    reg btn_sample_1 = 1'b0;
    reg btn_sample_2 = 1'b0;
    reg btn_sample_3 = 1'b0;
    reg btn_sample_4 = 1'b0;
    reg btn_up_pulse = 1'b0;
    assign LEDR_N = !btn_pressed;
    always @(posedge clk or negedge clk_lock) begin
        if (!clk_lock) begin
            btn_sample_1 <= 1'b0;
            btn_sample_2 <= 1'b0;
            btn_sample_3 <= 1'b0;
            btn_sample_4 <= 1'b0;
        end else begin
            btn_sample_1 <= btn_sample_2;
            btn_sample_2 <= btn_sample_3;
            btn_sample_3 <= btn_sample_4;
            btn_sample_4 <= btn_pressed;

            btn_up_pulse <= 1'b0;
            if (btn_sample_1 && btn_sample_2 && !btn_sample_3 && !btn_sample_4) begin
                btn_up_pulse <= 1'b1;
            end
        end
    end

    // This is the UART module we use to send byte data.
    // For receiving data, we use 8x oversampling.
    // This restricts our baud rate to one eight the clock rate.
    reg respond = 1'b0;
    wire is_transmitting;
    wire transmit = (btn_up_pulse || respond) && !is_transmitting;
    reg [7:0] tx_byte = 8'd0;
    wire received;
    wire [7:0] rx_byte;
    wire is_receiving;
    wire receive_error;
    uart #(
        // We're running a little slower than this.
        // But it's only the ratio sys_clk_freq / baud_rate that matters anyway.
        .baud_rate(5000000),
        .sys_clk_freq(40000000)
    ) instance_name(
        .clk(clk),                        // The master clock for this module
        .rst(!clk_lock),                  // Synchronous reset
        .rx(P1A2),                        // Incoming serial line
        .tx(P1A1),                        // Outgoing serial line
        .transmit(transmit),              // Signal to transmit
        .tx_byte(tx_byte),                // Byte to transmit
        .received(received),              // Indicated that a byte has been received
        .rx_byte(rx_byte),                // Byte received
        .is_receiving(is_receiving),      // Low when receive line is idle
        .is_transmitting(is_transmitting),// Low when transmit line is idle
        .recv_error(receive_error)        // Indicates error in receiving packet.
    );

    // We use pins P1A3 and P1A4 to monitor the loop.
    // P1A3 goes high for one clock cycle when we receive a byte.
    // It's a helpful scope trigger if you want to catch every round trip.
    // P1A4 goes high for one clock cycle whenever we reset the sent byte.
    // It's a helpful scope trigger if you want to catch every 256 round trips.
    reg tx_byte_overflow_pulse = 1'b0;
    assign P1A3 = received;
    assign P1A4 = tx_byte_overflow_pulse;

    // We toggle the LED every time we complete 256 round trips.
    // If things are going well this isn't all that useful, since it happens nearly 1,000 times per
    // second. But if you try to overclock it you'll know when it stops working since you'll see it
    // blink sporadically.
	reg led_reg = 1'b0;
	assign LEDG_N = led_reg;

    // This is the main loop.
    always @(posedge clk or negedge clk_lock) begin
        // These are pulses that should always be reset.
        respond <= 1'b0;
        tx_byte_overflow_pulse <= 1'b0;

        if (!clk_lock) begin
            led_reg <= 1'b0;
        end else begin
            if (received) begin
                tx_byte <= rx_byte + 1;
                if (tx_byte == 8'd255) begin
                    tx_byte <= 8'd0;
                    led_reg <= !led_reg;
                    tx_byte_overflow_pulse <= 1'b1;
                end
                respond <= 1'b1;
            end
        end
    end

endmodule
