EECS151 / fpga_labs_fa20 / lab6 / src / piano.v
piano.v
Raw
// Max ASCII = 255 (extended) 

module piano #(
    parameter CLOCK_FREQ = 125_000_000
) (
    input clk,
    input rst,

    input [2:0] buttons,
    input [1:0] switches,
    output [5:0] leds,

    output reg [7:0] ua_tx_din,
    output reg ua_tx_wr_en,
    input ua_tx_full,

    input [7:0] ua_rx_dout,
    input ua_rx_empty,
    output reg ua_rx_rd_en,

    output [23:0] tone
);
    reg  [7:0]  address;
    wire [7:0]  last_addr;
    wire [23:0] rom_out;
    
    assign tone = (curr_state == PLAY) ? rom_out : 24'd0;

    assign leds[0] = (ua_rx_rd_en & !ua_rx_empty);
    assign leds[1] = ua_rx_empty;
    assign leds[2] = (ua_rx_dout != 8'd0);
    assign leds[3] = (curr_state == PLAY);
    assign leds[4] = (ua_rx_rd_en);
    assign leds[5] = temp;

    piano_scale_rom rom (
        .address(address),
        .data(rom_out),
        .last_address(last_addr)
    );

    // Delay
    
    /* verilator lint_off WIDTH */
    localparam [22:0] BASE_DELAY  = 5_000_000;
    localparam [18:0] DELTA_TEMPO = 500_000;
    localparam [24:0] MAX_DELAY   = ~0 - DELTA_TEMPO;

    reg [24:0] delay;

    always @(posedge clk) begin
        casez ({switches[0], buttons[0], rst})  
            3'b??1 : delay <= BASE_DELAY;
            3'b110 : begin 
                if (delay > DELTA_TEMPO)
                    delay <= delay - DELTA_TEMPO;
            end
            3'b010 : begin
                if (delay < MAX_DELAY) 
                    delay <= delay + DELTA_TEMPO;
            end
            default : delay <= delay;
        endcase
    end
    /* lint_on */


    // Tone generator
    reg [24:0] clk_counter;

    always @(posedge clk) begin
        if (rst) clk_counter <= 0;
        else if (clk_counter == delay - 1) clk_counter <= 0;
        else clk_counter <= clk_counter + 1;
    end

    
    // FSM 
    reg [1:0] next_state,
              curr_state;

    localparam [1:0] READ  = 2'b00,
                     PAD   = 2'b01,
                     WRITE = 2'b10,
                     PLAY  = 2'b11;

    reg temp = 0;

    always @(posedge clk) begin
        if (rst) begin
            address <= 0;
            ua_rx_rd_en <= 0;
            ua_tx_wr_en <= 0;
            ua_tx_din <= 0;
        end else begin
            next_state = curr_state;
            case (curr_state)
                READ : begin
                    if (!ua_rx_empty) begin
                        ua_rx_rd_en <= 1;
                        temp <= 1;
                        ua_tx_wr_en <= 0;
                        next_state = PAD; 
                    end
                end
                PAD : begin
                    ua_rx_rd_en <= 0;
                    ua_tx_wr_en <= 0;
                    next_state = WRITE;
                end
                WRITE : begin
                    if (!ua_tx_full) begin
                        ua_rx_rd_en <= 0;
                        ua_tx_wr_en <= 1;
                        ua_tx_din <= ua_rx_dout;
                        address <= ua_rx_dout; // for clarity
                        next_state = PLAY;
                    end
                end
                PLAY : begin
                    if (clk_counter != delay - 1) begin
                        ua_rx_rd_en <= 0;
                        ua_tx_wr_en <= 0;
                    end else next_state = READ;
                end
                default : begin
                    next_state = READ;
                end
            endcase
        end
    end

    always @ (posedge clk) begin
        if (rst) begin
            curr_state <= READ;
        end
        else curr_state <= next_state;
    end

endmodule