EECS151 / riscv-cpu / hardware / src / z1top.v
z1top.v
Raw
`timescale 1ns/10ps

module z1top #(
    // A 125 MHz clock comes into the FPGA
    // It is declared as a parameter so the testbench can override it if desired
    parameter SYSTEM_CLOCK_FREQ = 125_000_000,
    parameter BAUD_RATE = 115_200,
    // Warning: changing the CPU_CLOCK_FREQ parameter doesn't actually change the clock frequency coming out of the PLL
    parameter CPU_CLOCK_FREQ = 50_000_000,
    /* verilator lint_off REALCVT */
    // Sample the button signal every 500us
    parameter integer B_SAMPLE_COUNT_MAX = 0.0005 * CPU_CLOCK_FREQ,
    // The button is considered 'pressed' after 100ms of continuous pressing
    parameter integer B_PULSE_COUNT_MAX = 0.100 / 0.0005,
    /* lint_on */
    // The PC the RISC-V CPU should start at after reset
    parameter RESET_PC = 32'h4000_0000
) (
    input CLK_125MHZ_FPGA,
    input [3:0] BUTTONS,
    input [1:0] SWITCHES,
    output [5:0] LEDS,
    input FPGA_SERIAL_RX,
    output FPGA_SERIAL_TX,
    output aud_pwm,
    output aud_sd
);
    assign LEDS = 6'b111111;
    wire cpu_clk, cpu_clk_g, cpu_clk_pll_lock;
    wire cpu_clk_pll_fb_out, cpu_clk_pll_fb_in;

    BUFG  cpu_clk_buf     (.I(cpu_clk),               .O(cpu_clk_g));
    BUFG  cpu_clk_f_buf   (.I(cpu_clk_pll_fb_out),    .O (cpu_clk_pll_fb_in));

    // This PLL generates the cpu_clk from the 125 Mhz clock
    /* verilator lint_off PINMISSING */
    PLLE2_ADV #(
        .BANDWIDTH            ("OPTIMIZED"),
        .COMPENSATION         ("BUF_IN"),  // Not "ZHOLD"
        .STARTUP_WAIT         ("FALSE"),
        .DIVCLK_DIVIDE        (5),
        .CLKFBOUT_MULT        (34),
        .CLKFBOUT_PHASE       (0.000),
        .CLKOUT0_DIVIDE       (17),
        .CLKOUT0_PHASE        (0.000),
        .CLKOUT0_DUTY_CYCLE   (0.500),
        .CLKIN1_PERIOD        (8.000)
    ) plle2_cpu_inst (
        .CLKFBOUT            (cpu_clk_pll_fb_out),
        .CLKOUT0             (cpu_clk),
        // Input clock control
        .CLKFBIN             (cpu_clk_pll_fb_in),
        .CLKIN1              (CLK_125MHZ_FPGA),
        .CLKIN2              (1'b0),
        // Tied to always select the primary input clock
        .CLKINSEL            (1'b1),
        // Other control and status signals
        .LOCKED              (cpu_clk_pll_lock),
        .PWRDWN              (1'b0),
        .RST                 (1'b0)
    );
    /* lint_on */

    wire pwm_clk, pwm_clk_g, pwm_clk_pll_lock;
    wire pwm_clk_pll_fb_out, pwm_clk_pll_fb_in;

    BUFG  pwm_clk_buf     (.I(pwm_clk),               .O(pwm_clk_g));
    BUFG  pwm_clk_f_buf   (.I(pwm_clk_pll_fb_out),    .O (pwm_clk_pll_fb_in));

    // This PLL generates the pwm_clk from the 125 Mhz clock
    /* verilator lint_off PINMISSING */
    PLLE2_ADV #(
        .BANDWIDTH            ("OPTIMIZED"),
        .COMPENSATION         ("BUF_IN"),  // Not "ZHOLD"
        .STARTUP_WAIT         ("FALSE"),
        .DIVCLK_DIVIDE        (5),
        .CLKFBOUT_MULT        (36),
        .CLKFBOUT_PHASE       (0.000),
        .CLKOUT0_DIVIDE       (6),
        .CLKOUT0_PHASE        (0.000),
        .CLKOUT0_DUTY_CYCLE   (0.500),
        .CLKIN1_PERIOD        (8.000)
    ) plle2_pwm_inst (
        .CLKFBOUT            (pwm_clk_pll_fb_out),
        .CLKOUT0             (pwm_clk), // 150 Mhz
        // Input clock control
        .CLKFBIN             (pwm_clk_pll_fb_in),
        .CLKIN1              (CLK_125MHZ_FPGA),
        .CLKIN2              (1'b0),
        // Tied to always select the primary input clock
        .CLKINSEL            (1'b1),
        // Other control and status signals
        .LOCKED              (pwm_clk_pll_lock),
        .PWRDWN              (1'b0),
        .RST                 (1'b0)
    );
    /* lint_on */

    // The global system reset is asserted when the RESET button is
    // pressed by the user or when the PLL isn't locked
    wire [2:0] clean_buttons;
    wire reset_button, reset;
    assign reset = reset_button || ~cpu_clk_pll_lock;

    button_parser #(
        .width(4),
        .sample_count_max(B_SAMPLE_COUNT_MAX),
        .pulse_count_max(B_PULSE_COUNT_MAX)
    ) b_parser (
        .clk(cpu_clk_g),
        .in(BUTTONS),
        .out({clean_buttons, reset_button})
    );

    wire cpu_tx, cpu_rx;
    Riscv151 #(
        .CPU_CLOCK_FREQ(CPU_CLOCK_FREQ),
        .RESET_PC(RESET_PC),
        .BAUD_RATE(BAUD_RATE)
    ) cpu (
        .clk(cpu_clk_g),
        .rst(reset),
        .FPGA_SERIAL_RX(cpu_rx),
        .FPGA_SERIAL_TX(cpu_tx)
    );

    (* IOB = "true" *) reg fpga_serial_tx_iob;
    (* IOB = "true" *) reg fpga_serial_rx_iob;
    assign FPGA_SERIAL_TX = fpga_serial_tx_iob;
    assign cpu_rx = fpga_serial_rx_iob;
    always @(posedge cpu_clk_g) begin
        fpga_serial_tx_iob <= cpu_tx;
        fpga_serial_rx_iob <= FPGA_SERIAL_RX;
    end

    // PWM Controller
    (* IOB = "true" *) reg pwm_iob;
    wire pwm_out, pwm_rst, reset_button_sync;
    synchronizer rst_pwm_sync(.async_signal(reset_button), .sync_signal(reset_button_sync), .clk(pwm_clk_g));
    assign aud_pwm = pwm_iob;
    assign aud_sd = 1'b1;
    always @(posedge pwm_clk_g) begin
        pwm_iob <= pwm_out;
    end
    assign pwm_out = 1'b0;
    assign pwm_rst = reset_button_sync || ~pwm_clk_pll_lock;
endmodule