// buttontest.v
//
// Debounce a button to drive an 8-bit counter.
// Use a decoder to drive a custom pattern on 8 output LEDs.
//
// look in pins.pcf for all the pin names on the TinyFPGA BX board
// Pins 2 and 13 have internall pull-up resistors enabled
//
// Synthesize and download with:
// apio build
// tinyprog -p hardware.bin
//
// E.Torrence
// PHYS 432
// April 14, 2019
//
module top (
    input CLK,    // 16MHz clock
    input PIN_2,  // Button input
    input PIN_13, // Button input
    output LED,   // User/boot LED next to power LED
    output USBPU, // USB pull-up resistor
    output PIN_14, // 8 LED outputs
    output PIN_15,
    output PIN_16,
    output PIN_17,
    output PIN_18,
    output PIN_19,
    output PIN_20,
    output PIN_21
);
    // drive USB pull-up resistor to '0' to disable USB
    assign USBPU = 0;

    // This is our reset button, doesn't need to be debounced
    wire reset;
    assign reset = !PIN_13;

    ////////
    // drive a counter with a debounced button
    ////////

    // Output LED display, 8 bits with MSB first
    reg [7:0] LEDreg;

    // Continuously assign the value of ledreg to output pins 14-21
    assign {PIN_14, PIN_15, PIN_16, PIN_17, PIN_18, PIN_19, PIN_20, PIN_21} = LEDreg;

    // Internal counter value
    reg [7:0] countValue;

    // Instantiate a button debouncer module, output goes to button1
    wire button1;
    debounce b1(CLK, PIN_2, button1);

    // Instantiate a counter based on debounced button1 as a clock
    counter8 count8(button1, reset, countValue);

    // Alternately, drive counter directly with the raw button input
    // counter8 count8(PIN_2, reset, countValue);

    // Use counter value as input to display decoder
    displaydecoder lut(countValue, LEDreg);

    // Alternately, display counter value directly on LEDs
    // assign LEDreg = countValue;

    // Assign the user LED on the board to our button
    assign LED = !PIN_2;

endmodule

// Display decoder/Look-up table
module displaydecoder (
    input [7:0] state,
    output [7:0] display
);

    // LUT is 8 bits wide, 16 entries (4 bits) long
    reg [7:0] lut [0:15];
    initial begin
        lut[0] <= 8'h00;
        lut[1] <= 8'h01;
        lut[2] <= 8'h02;
        lut[3] <= 8'h04;
        lut[4] <= 8'h08;
        lut[5] <= 8'h10;
        lut[6] <= 8'h20;
        lut[7] <= 8'h40;
        lut[8] <= 8'h80;
        lut[9] <= 8'h40;
        lut[10] <= 8'h20;
        lut[11] <= 8'h10;
        lut[12] <= 8'h08;
        lut[13] <= 8'h04;
        lut[14] <= 8'h02;
        lut[15] <= 8'h01;
    end

    assign display = ~lut[state[3:0]];

endmodule

// Debounce function
//  Button input must be the same for 4x4ms in a row 
//    to trigger change in output value
//  Input is system 16 MHz clock
//
module debounce (
    input clock,
    input button,
    output value
);

    reg value;

    // Make a divide by 16 clock (16 MHz / 2^16 = 246 Hz => 4 mS)
    // Take overflow of c1 and use an input to c2
    // Overflow of c2 is the slow clock
    wire c1over;
    wire slow_clock;
    reg [7:0] c1v;
    reg [7:0] c2v;
    counter8 c1(clock, 0, c1v, c1over);
    counter8 c2(c1over, 0, c2v, slow_clock);

    // Four bits to keep track of last button values
    // Set output value if 4 in a row match
    reg [3:0] history;

    always @ (posedge slow_clock) begin    

        history = {history[2:0], button};  // Shift previous values 
	if (history == 4'b0000)
	   value <= 1'b0;
        
        else if (history == 4'b1111)
	   value <= 1'b1;

    end

endmodule

// Simple 8-bit counter with synchronous reset and overflow
module counter8 (
    input clock,
    input reset,
    output [7:0] count,
    output overflow
);

    // Be clear these are registers
    reg [7:0] count;
    reg overflow;

    always @ (posedge clock or posedge reset) begin
        if (reset)
            count <= 8'h00; // Set to zero

	else begin
	    count <= count + 1;
            // Overflow is set when counter is resetting to zero
            overflow <= (count == 8'hFF);
	end
    end

endmodule