dakies/OSS_Verilog huggingface dataset:
module vram(
    input clk,

    input [13:0] even_address,
    input [13:0] odd_address,
    input even_write_en,
    input odd_write_en,
    input [31:0] write_data,

    output [31:0] read_data
);
    spram_256k vram_0 (
        .clk(clk),
        .address(even_address),
        .write_data(write_data[15:0]),
        .mask(4'b1111),
        .write_en(even_write_en),
        .cs(1),
        .read_data(read_data[15:0])
    );

    spram_256k vram_1 (
        .clk(clk),
        .address(odd_address),
        .write_data(write_data[31:16]),
        .mask(4'b1111),
        .write_en(odd_write_en),
        .cs(1),
        .read_data(read_data[31:16])
    );

endmodule
module flash_reader #(
    parameter [0:0] ASSUME_QPI = 0
) (
    input clk,
    input reset,

    input valid,
    input [23:0] address,
    input size,
    output reg [31:0] data,
    output reg ready,

    output reg flash_clk_en,
    output reg flash_csn,
    output reg [3:0] flash_in,
    output reg [3:0] flash_in_en,
    input [3:0] flash_out
);
    localparam DUMMY_CYCLES = ASSUME_QPI ? 0 : 4;

    // Winbond: byte[5:4] == 2'b10
    // ISSI: byte[7:4] == 4'b1001
    localparam [7:0] CRM_BYTE = 8'h20 | 8'h80;

    reg [4:0] state;
    
    wire [3:0] byte_state = state[4:1];
    wire nybble_state = state[0];

    reg [3:0] read_buffer;
    wire [7:0] read_byte = {read_buffer, flash_out};

    always @(posedge clk) begin
        if (nybble_state) begin
            read_buffer <= flash_out;
        end
    end

    reg [7:0] selected_byte;

    always @* begin
        case (byte_state)
            0: selected_byte = address[23:16];
            1: selected_byte = address[15:8];
            2: selected_byte = address[7:0];
            default: selected_byte = CRM_BYTE;
        endcase
    end

    always @* begin
        flash_in = nybble_state ? selected_byte[3:0] : selected_byte[7:4];
    end

    always @(posedge clk) begin
        if (!nybble_state) begin
            case (byte_state - (DUMMY_CYCLES / 2))
                5: data[7:0] <= read_byte;
                6: data[15:8] <= read_byte;
                7: data[23:16] <= read_byte;
                8: data[31:24] <= read_byte;
            endcase
        end
    end

    wire halted = (reset || !valid || ready);

    always @* begin
        if (halted) begin
            flash_in_en = 0;
            flash_csn = 1;
        end else begin
            flash_csn = 0;

            case (byte_state)
                0, 1, 2, 3: flash_in_en = 4'hf;
                default: flash_in_en = 0;
            endcase
        end
    end

    wire [4:0] state_final = 5'h0b + (size ? 4 : 0) + DUMMY_CYCLES;

    always @(posedge clk) begin
        if (halted) begin
            flash_clk_en <= 0;
            state <= 0;
            ready <= 0;
        end else begin
            if (flash_clk_en) begin
                state <= state + 1;
            end

            flash_clk_en <= 1;

            if (state == state_final) begin
                ready <= 1;
            end
        end
    end

endmodule
module debouncer #(
    parameter integer BTN_COUNT = 8
) (
    input clk,
    input reset,

    input [BTN_COUNT - 1:0] btn,

    output reg [BTN_COUNT - 1:0] level,
    output reg [BTN_COUNT - 1:0] trigger,
    output reg [BTN_COUNT - 1:0] released
);
    localparam BTN_WIDTH = BTN_COUNT - 1;

    reg [BTN_WIDTH:0] btn_r [0:1];

    reg [15:0] debounce_counter_common;
    wire debounce_counter_common_tick = debounce_counter_common[15];

    reg [4:0] debounce_counter_button [0:BTN_WIDTH];

    always @(posedge clk) begin
        btn_r[1] <= btn_r[0];
        btn_r[0] <= btn;
    end

    reg [BTN_WIDTH:0] level_r;

    always @(posedge clk) begin
        if (reset) begin
            level <= 0;
            trigger <= 0;
            released <= 0;
        end else begin
            for (i = 0; i < BTN_COUNT; i = i + 1) begin
                if (debounce_counter_button[i][4]) begin
                    level[i] <= btn_r[1][i];
                end

                trigger[i] <= level[i] & ~level_r[i];
                released[i] <= ~level[i] & level_r[i];
                level_r[i] <= level[i];
            end
        end
    end

    always @(posedge clk) begin
        if (reset) begin
            debounce_counter_common <= 0;
        end else begin
            debounce_counter_common <= (debounce_counter_common_tick ? 0 : debounce_counter_common + 1);
        end
    end

    always @(posedge clk) begin
        if (reset) begin
            for (i = 0; i < BTN_COUNT; i = i + 1) begin
                debounce_counter_button[i] <= 0;
            end
        end else begin
            for (i = 0; i < BTN_COUNT; i = i + 1) begin
                if ((btn_r[0][i] == btn_r[1][i])) begin
                    if (debounce_counter_common_tick && !debounce_counter_button[i][4]) begin
                        debounce_counter_button[i] <= debounce_counter_button[i] + 1;
                    end
                end else begin
                    debounce_counter_button[i] <= 0;
                end
            end
        end
    end

    integer i;

endmodule
module cpu_peripheral_sync(
    input clk_1x,
    input clk_2x,

    // 1x inputs
    input [3:0] cpu_wstrb,
    input [31:0] cpu_address,
    input [31:0] cpu_write_data,
    input cpu_mem_valid,

    // 2x inputs
    input cpu_mem_ready,
    input [31:0] cpu_read_data,

    output reg [3:0] cpu_wstrb_2x,
    output reg [31:0] cpu_write_data_2x,
    output reg [31:0] cpu_address_2x,
    output reg cpu_mem_valid_2x,

    output reg cpu_mem_ready_1x,
    output reg [31:0] cpu_read_data_1x
);

    // --- 1x -> 2x ---

    always @(negedge clk_2x) begin
        cpu_write_data_2x <= cpu_write_data;
        cpu_address_2x <= cpu_address;
        cpu_wstrb_2x <= cpu_wstrb;
        cpu_mem_valid_2x <= cpu_mem_valid;
    end

    // --- 2x -> 1x ---

    reg [31:0] cpu_read_data_r;
    reg cpu_mem_ready_r, cpu_mem_ready_d;

    reg cpu_mem_ready_rose, cpu_mem_ready_rose_r;

    always @(negedge clk_2x) begin
        cpu_read_data_r <= cpu_read_data;

        cpu_mem_ready_r <= cpu_mem_ready;
        cpu_mem_ready_d <= cpu_mem_ready_r;
        cpu_mem_ready_rose <= cpu_mem_ready_r && !cpu_mem_ready_d;
        cpu_mem_ready_rose_r <= cpu_mem_ready_rose;
    end

    // eliminating this stage causes problems
    // negedge 2x clk -> posedge 1x clk gives these signals half a 2x clk cycle to propagate through CPU

    always @(posedge clk_1x) begin
        cpu_read_data_1x <= cpu_read_data_r;
        cpu_mem_ready_1x <= cpu_mem_ready_rose || cpu_mem_ready_rose_r;
    end

endmodule
module address_decoder #(
    parameter REGISTERED_INPUTS = 0
) (
    input clk,
    input reset,

    input [24:0] cpu_address,
    input cpu_mem_valid,
    input [3:0] cpu_wstrb,
    output reg [3:0] cpu_wstrb_decoder,

    output reg bootloader_en,

    output reg vdp_en,
    output reg vdp_write_en,

    output reg audio_ctrl_en,
    output reg audio_ctrl_write_en,

    output reg cpu_ram_en,
    output reg cpu_ram_write_en,

    output reg status_en,
    output reg status_write_en,

    output reg flash_read_en,

    output reg dsp_en,
    output reg dsp_write_en,

    output reg pad_en,
    output reg pad_write_en,

    output reg cop_ram_write_en,

    output reg flash_ctrl_en,
    output reg flash_ctrl_write_en
);
    reg [24:0] cpu_address_r;
    reg cpu_mem_valid_r;

    generate
        if (REGISTERED_INPUTS) begin
            always @(posedge clk) begin
                cpu_address_r <= cpu_address;
                cpu_mem_valid_r <= cpu_mem_valid;
                cpu_wstrb_decoder <= cpu_wstrb;
            end
        end else begin
            always @* begin
                cpu_address_r = cpu_address;
                cpu_mem_valid_r = cpu_mem_valid;
                cpu_wstrb_decoder = cpu_wstrb;
            end
        end
    endgenerate

    // this doesn't need to be exposed but is here for consistency
    reg cop_ram_en;

    always @* begin
        bootloader_en = 0;
        flash_read_en = 0;
        audio_ctrl_en = 0; audio_ctrl_write_en = 0;
        cpu_ram_en = 0; cpu_ram_write_en = 0;
        status_en = 0; status_write_en = 0;
        vdp_en = 0; vdp_write_en = 0;
        dsp_en = 0; dsp_write_en = 0;
        pad_en = 0; pad_write_en = 0;
        cop_ram_en = 0; cop_ram_write_en = 0;
        flash_ctrl_en = 0; flash_ctrl_write_en = 0;

        if (cpu_mem_valid_r && !reset) begin
            if (cpu_address_r[24]) begin
                flash_read_en = 1;
            end else begin
                case (cpu_address_r[19:16])
                    0: cpu_ram_en = 1;
                    1: vdp_en = 1;
                    2: status_en = 1;
                    3: dsp_en = 1;
                    4: pad_en = 1;
                    5: cop_ram_en = 1;
                    6: bootloader_en = 1;
                    7: flash_ctrl_en = 1;
                    8: audio_ctrl_en = 1;
                endcase    
            end

            cpu_ram_write_en = cpu_ram_en && cpu_wstrb_decoder;
            vdp_write_en = vdp_en && cpu_wstrb_decoder;
            status_write_en = status_en && cpu_wstrb_decoder;
            dsp_write_en = dsp_en && cpu_wstrb_decoder;
            pad_write_en = pad_en && cpu_wstrb_decoder;
            cop_ram_write_en = cop_ram_en && cpu_wstrb_decoder;
            flash_ctrl_write_en = flash_ctrl_en && cpu_wstrb_decoder;
            audio_ctrl_write_en = audio_ctrl_en && cpu_wstrb_decoder;
        end
    end
 
endmodule
module mock_gamepad(
    input clk,

    // Parallel button inputs
    
    input [11:0] pad_btn,

    // Serial control

    input pad_clk,
    input pad_latch,

    // Serial out

    output [1:0] pad_out
);
    reg pad_clk_r;
    reg [11:0] pad_shift;

    // P1 reading only for now
    assign pad_out[0] = pad_shift[0];
    assign pad_out[1] = 1'b0;

    always @(posedge clk) begin
        if (pad_latch) begin
            pad_shift <= pad_btn;
        end

        if (pad_clk && !pad_clk_r) begin
            pad_shift <= pad_shift >> 1;
        end

        pad_clk_r <= pad_clk;
    end

endmodule
module cpu_ram(
    input clk,

    input [13:0] address,
    input cs,
    input write_en,
    input [3:0] wstrb,
    input [31:0] write_data,

    output [31:0] read_data  
);
    wire [7:0] mask_write_en = {
        wstrb[3], wstrb[3],
        wstrb[2], wstrb[2],
        wstrb[1], wstrb[1],
        wstrb[0], wstrb[0]
    };

    spram_256k cpu_ram_0(
        .clk(clk),
        .address(address),
        .write_data(write_data[15:0]),
        .mask(mask_write_en[3:0]),
        .write_en(write_en),
        .cs(cs),
        .read_data(read_data[15:0])
    );

    spram_256k cpu_ram_1(
        .clk(clk),
        .address(address),
        .write_data(write_data[31:16]),
        .mask(mask_write_en[7:4]),
        .write_en(write_en),
        .cs(cs),
        .read_data(read_data[31:16])
    );

endmodule
module dpram #(
    parameter integer DATA_WIDTH = 16,
    parameter integer ADDRESS_WIDTH = 8,

    parameter integer DATA_BITS = DATA_WIDTH - 1,
    parameter integer ADDRESS_BITS = ADDRESS_WIDTH - 1
) (
    input clk,

    input write_en,
    input [ADDRESS_BITS:0] write_address,
    input [DATA_BITS:0] write_data,

    input [ADDRESS_BITS:0] read_address,
    output reg [DATA_BITS:0] read_data
);
    localparam WORDS = 1 << ADDRESS_WIDTH;

    reg [DATA_BITS:0] mem [0:WORDS - 1];

    always @(posedge clk) begin
        if (write_en) begin
            mem[write_address] <= write_data;
        end

        read_data <= mem[read_address];
    end

endmodule
module esp32_spi_gamepad #(
    parameter integer PAD_BUTTONS = 12
) (
    input clk,
    input reset,

    // ESP32 reset support

    input user_reset,
    output esp32_en,
    output esp32_gpio0,
    output esp32_gpio12,

    // SPI gamepad input

    input spi_csn,
    input spi_clk,
    input spi_mosi,

    output reg [PAD_BUTTONS - 1:0] pad_btn
);
    localparam PAD_WIDTH = PAD_BUTTONS - 1;

    // --- ESP32 resetting ---

    assign esp32_en = !user_reset;

    // ESP32 "strapping pins" for boot:
    // MTDI (GPIO12) apparently has pull down in ESP32 but still need this for whatever reason
    // Serial console shows ESP32 stuck in reset loop otherwise

    // GPIO0 = 1 (SPI flash boot, instead of serial bootloader)
    assign esp32_gpio0 = 1;

    // MTDI = 0 (VDD_SDIO = 3.3v, instead of 1.8v)
    assign esp32_gpio12 = 0;

    // --- SPI gamepad ---

    reg spi_clk_r;
    reg spi_csn_r;

    reg [PAD_WIDTH:0] receive_buffer;

    wire spi_csn_rose = spi_csn && !spi_csn_r;
    wire spi_csn_fell = !spi_csn && spi_csn_r;
    wire spi_clk_rose = spi_clk && !spi_clk_r;

    always @(posedge clk) begin
        if (reset) begin
            pad_btn <= 0;
            spi_clk_r <= 0;
            spi_csn_r <= 1;
        end else begin
            spi_clk_r <= spi_clk;
            spi_csn_r <= spi_csn;

            if (!spi_csn && spi_clk_rose) begin
                receive_buffer <= {spi_mosi, receive_buffer[PAD_WIDTH:1]};
            end else if (spi_csn_rose) begin
                pad_btn <= receive_buffer;
            end
        end
    end

endmodule
module pll_ecp5 #(
    parameter ENABLE_FAST_CLK = 1
) (
    input clk_25m,

    output locked,
    output clk_1x,
    output clk_2x,
    output clk_10x
);
    generate
        if (ENABLE_FAST_CLK) begin
            generated_pll_33_75 generated_pll(
                .clkin(clk_25m),
                .clkout0(clk_10x),
                .clkout3(clk_1x),
                .clkout2(clk_2x),
                .locked(locked)
            );
        end else begin
            generated_pll_25 generated_pll(
                .clkin(clk_25m),
                .clkout0(clk_10x),
                .clkout3(clk_1x),
                .clkout2(clk_2x),
                .locked(locked)
            );
        end
    endgenerate

endmodule
module generated_pll_usb
(
    input clkin, // 25 MHz, 0 deg
    output clkout0, // 60 MHz, 0 deg
    output clkout1, // 6 MHz, 0 deg
    output locked
);
(* FREQUENCY_PIN_CLKI="25" *)
(* FREQUENCY_PIN_CLKOP="60" *)
(* FREQUENCY_PIN_CLKOS="6" *)
(* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *)
EHXPLLL #(
        .PLLRST_ENA("DISABLED"),
        .INTFB_WAKE("DISABLED"),
        .STDBY_ENABLE("DISABLED"),
        .DPHASE_SOURCE("DISABLED"),
        .OUTDIVIDER_MUXA("DIVA"),
        .OUTDIVIDER_MUXB("DIVB"),
        .OUTDIVIDER_MUXC("DIVC"),
        .OUTDIVIDER_MUXD("DIVD"),
        .CLKI_DIV(5),
        .CLKOP_ENABLE("ENABLED"),
        .CLKOP_DIV(10),
        .CLKOP_CPHASE(4),
        .CLKOP_FPHASE(0),
        .CLKOS_ENABLE("ENABLED"),
        .CLKOS_DIV(100),
        .CLKOS_CPHASE(4),
        .CLKOS_FPHASE(0),
        .FEEDBK_PATH("CLKOP"),
        .CLKFB_DIV(12)
    ) pll_i (
        .RST(1'b0),
        .STDBY(1'b0),
        .CLKI(clkin),
        .CLKOP(clkout0),
        .CLKOS(clkout1),
        .CLKFB(clkout0),
        .CLKINTFB(),
        .PHASESEL0(1'b0),
        .PHASESEL1(1'b0),
        .PHASEDIR(1'b1),
        .PHASESTEP(1'b1),
        .PHASELOADREG(1'b1),
        .PLLWAKESYNC(1'b0),
        .ENCLKOP(1'b0),
        .LOCK(locked)
	);
endmodule
module dacpwm
#(
  parameter C_pcm_bits = 12, // input: how many bits PCM (including sign bit)
  parameter C_dac_bits = 4  // output: how many bits DAC output, unsigned
)
(
  input clk, // required to run PWM
  input signed [C_pcm_bits-1:0] pcm, // 12-bit signed PCM input
  output [C_dac_bits-1:0] dac // 4-bit unsigned DAC output
);
    parameter C_pwm_bits = C_pcm_bits-C_dac_bits; // how many bits for PWM that increases DAC resolution

    // generate 2 DAC output optional values: PCM+0 and PCM+1
    reg [C_dac_bits-1:0] R_dac0, R_dac1;
    reg [C_pwm_bits-1:0] R_pcm_low;
    always @(posedge clk)
    begin
      R_dac0 <= { ~pcm[C_pcm_bits-1], pcm[C_pcm_bits-2:C_pcm_bits-C_dac_bits]};
      R_dac1 <= { ~pcm[C_pcm_bits-1], pcm[C_pcm_bits-2:C_pcm_bits-C_dac_bits]} + 1;
      R_pcm_low <= pcm[C_pwm_bits-1:0];
    end
    
    // constantly running PWM counter
    reg [C_pwm_bits-1:0] R_pwm_counter;
    always @(posedge clk)
      R_pwm_counter <= R_pwm_counter + 1; // constantly running

    // the comparator
    // using PWM to switch between dac0 and dac1
    reg [C_dac_bits-1:0] R_dac_output;
    always @(posedge clk)
    begin
      R_dac_output <= R_pwm_counter >= R_pcm_low ? R_dac0 : R_dac1;
    end

    assign dac = R_dac_output;
endmodule
module generated_pll_33_75
(
    input clkin, // 25 MHz, 0 deg
    output clkout0, // 168.75 MHz, 0 deg
    output clkout2, // 33.75 MHz, 0 deg
    output clkout3, // 16.875 MHz, 0 deg
    output locked
);
(* FREQUENCY_PIN_CLKI="25" *)
(* FREQUENCY_PIN_CLKOP="168.75" *)
(* FREQUENCY_PIN_CLKOS2="33.75" *)
(* FREQUENCY_PIN_CLKOS3="16.875" *)
(* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *)
EHXPLLL #(
        .PLLRST_ENA("DISABLED"),
        .INTFB_WAKE("DISABLED"),
        .STDBY_ENABLE("DISABLED"),
        .DPHASE_SOURCE("DISABLED"),
        .OUTDIVIDER_MUXA("DIVA"),
        .OUTDIVIDER_MUXB("DIVB"),
        .OUTDIVIDER_MUXC("DIVC"),
        .OUTDIVIDER_MUXD("DIVD"),
        .CLKI_DIV(4),
        .CLKOP_ENABLE("ENABLED"),
        .CLKOP_DIV(4),
        .CLKOP_CPHASE(2),
        .CLKOP_FPHASE(0),
        .CLKOS2_ENABLE("ENABLED"),
        .CLKOS2_DIV(20),
        .CLKOS2_CPHASE(2),
        .CLKOS2_FPHASE(0),
        .CLKOS3_ENABLE("ENABLED"),
        .CLKOS3_DIV(40),
        .CLKOS3_CPHASE(2),
        .CLKOS3_FPHASE(0),
        .FEEDBK_PATH("CLKOP"),
        .CLKFB_DIV(27)
    ) pll_i (
        .RST(1'b0),
        .STDBY(1'b0),
        .CLKI(clkin),
        .CLKOP(clkout0),
        .CLKOS2(clkout2),
        .CLKOS3(clkout3),
        .CLKFB(clkout0),
        .CLKINTFB(),
        .PHASESEL0(1'b0),
        .PHASESEL1(1'b0),
        .PHASEDIR(1'b1),
        .PHASESTEP(1'b1),
        .PHASELOADREG(1'b1),
        .PLLWAKESYNC(1'b0),
        .ENCLKOP(1'b0),
        .LOCK(locked)
	);
endmodule
module hdmi_encoder(
  input  wire pixel_clk,
  input  wire pixel_clk_x5,
  input  wire [7:0] red, green, blue,
  input  wire vde, hsync, vsync,
  output wire [3:0] gpdi_dp, gpdi_dn
);

  // 10b8b TMDS encoding of RGB and Sync
  //
  wire [9:0] TMDS_red, TMDS_green, TMDS_blue;
  TMDS_encoder encode_R(.clk(pixel_clk), .VD(red  ), .CD(2'b00)        , .VDE(vde), .TMDS(TMDS_red));
  TMDS_encoder encode_G(.clk(pixel_clk), .VD(green), .CD(2'b00)        , .VDE(vde), .TMDS(TMDS_green));
  TMDS_encoder encode_B(.clk(pixel_clk), .VD(blue ), .CD({vsync,hsync}), .VDE(vde), .TMDS(TMDS_blue));

  // shift out 10 bits each pix clock (2 DDR bits at a 5x rate)
  //
  reg [2:0] ctr_mod5 = 0;
  reg shift_ld = 0;

  always @(posedge pixel_clk_x5)
  begin
    shift_ld <= (ctr_mod5==4'd4);
    ctr_mod5 <= (ctr_mod5==4'd4) ? 4'd0 : ctr_mod5 + 4'd1;
  end
  
  reg [9:0] shift_R = 0, shift_G = 0, shift_B = 0, shift_C = 0;

  always @(posedge pixel_clk_x5)
  begin
    shift_R <= shift_ld ? TMDS_red   : shift_R[9:2];
    shift_G <= shift_ld ? TMDS_green : shift_G[9:2];
    shift_B <= shift_ld ? TMDS_blue  : shift_B[9:2];	
    shift_C <= shift_ld ? 10'h3e0    : shift_C[9:2];
  end

`ifdef __ICARUS__
  // (pseudo-) differential DDR driver (pure verilog version)
  //
  assign gpdi_dp[3] = pixel_clk_x5 ? shift_C[0] : shift_C[1];
  assign gpdi_dp[2] = pixel_clk_x5 ? shift_R[0] : shift_R[1];
  assign gpdi_dp[1] = pixel_clk_x5 ? shift_G[0] : shift_G[1];
  assign gpdi_dp[0] = pixel_clk_x5 ? shift_B[0] : shift_B[1];

  assign gpdi_dn = ~ gpdi_dp;
`else
  // (pseudo-) differential DDR driver (ECP5 synthesis version)
  //*
  ODDRX1F ddr3p( .Q(gpdi_dp[3]), .SCLK(pixel_clk_x5), .D0(shift_C[0]),  .D1(shift_C[1]),  .RST(0) );
  ODDRX1F ddr2p( .Q(gpdi_dp[2]), .SCLK(pixel_clk_x5), .D0(shift_R[0]),  .D1(shift_R[1]),  .RST(0) );
  ODDRX1F ddr1p( .Q(gpdi_dp[1]), .SCLK(pixel_clk_x5), .D0(shift_G[0]),  .D1(shift_G[1]),  .RST(0) );
  ODDRX1F ddr0p( .Q(gpdi_dp[0]), .SCLK(pixel_clk_x5), .D0(shift_B[0]),  .D1(shift_B[1]),  .RST(0) );

  ODDRX1F ddr3n( .Q(gpdi_dn[3]), .SCLK(pixel_clk_x5), .D0(~shift_C[0]), .D1(~shift_C[1]), .RST(0) );
  ODDRX1F ddr2n( .Q(gpdi_dn[2]), .SCLK(pixel_clk_x5), .D0(~shift_R[0]), .D1(~shift_R[1]), .RST(0) );
  ODDRX1F ddr1n( .Q(gpdi_dn[1]), .SCLK(pixel_clk_x5), .D0(~shift_G[0]), .D1(~shift_G[1]), .RST(0) );
  ODDRX1F ddr0n( .Q(gpdi_dn[0]), .SCLK(pixel_clk_x5), .D0(~shift_B[0]), .D1(~shift_B[1]), .RST(0) );
`endif

endmodule
module TMDS_encoder(
  input clk,       // pix clock
  input [7:0] VD,  // video data (red, green or blue)
  input [1:0] CD,  // control data
  input VDE,       // video data enable, to choose between CD (when VDE=0) and VD (when VDE=1)
  output reg [9:0] TMDS = 0
);

  reg  [3:0] dc_bias = 0;

  // compute data word
  wire [3:0] ones = VD[0] + VD[1] + VD[2] + VD[3] + VD[4] + VD[5] + VD[6] + VD[7];
  wire       XNOR = (ones>4'd4) || (ones==4'd4 && VD[0]==1'b0);
  wire [8:0] dw;
  assign dw[8] = ~XNOR;
  assign dw[7] = dw[6] ^ VD[7] ^ XNOR;
  assign dw[6] = dw[5] ^ VD[6] ^ XNOR;
  assign dw[5] = dw[4] ^ VD[5] ^ XNOR;
  assign dw[4] = dw[3] ^ VD[4] ^ XNOR;
  assign dw[3] = dw[2] ^ VD[3] ^ XNOR;
  assign dw[2] = dw[1] ^ VD[2] ^ XNOR;
  assign dw[1] = dw[0] ^ VD[1] ^ XNOR;
  assign dw[0] = VD[0];

  // calculate 1/0 disparity & invert as needed to minimize dc bias
  wire [3:0] dw_disp = dw[0] + dw[1] + dw[2] + dw[3] + dw[4] + dw[5] + dw[6] + dw[7] + 4'b1100;
  wire       sign_eq = (dw_disp[3] == dc_bias[3]);
  
  wire [3:0] delta  = dw_disp - ({dw[8] ^ ~sign_eq} & ~(dw_disp==0 || dc_bias==0));
  wire       inv_dw = (dw_disp==0 || dc_bias==0) ? ~dw[8] : sign_eq;
  
  wire [3:0] dc_bias_d = inv_dw ? dc_bias - delta : dc_bias + delta;
  
  // set output signals
  wire [9:0] TMDS_data = { inv_dw, dw[8], dw[7:0] ^ {8{inv_dw}} };
  wire [9:0] TMDS_code = CD[1] ? (CD[0] ? 10'b1010101011 : 10'b0101010100)
                               : (CD[0] ? 10'b0010101011 : 10'b1101010100);

  always @(posedge clk) TMDS    <= VDE ? TMDS_data : TMDS_code;
  always @(posedge clk) dc_bias <= VDE ? dc_bias_d : 0;

endmodule
module generated_pll_25
(
    input clkin, // 25 MHz, 0 deg
    output clkout0, // 125 MHz, 0 deg
    output clkout2, // 25 MHz, 0 deg
    output clkout3, // 12.5 MHz, 0 deg
    output locked
);
(* FREQUENCY_PIN_CLKI="25" *)
(* FREQUENCY_PIN_CLKOP="125" *)
(* FREQUENCY_PIN_CLKOS2="25" *)
(* FREQUENCY_PIN_CLKOS3="12.5" *)
(* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *)
EHXPLLL #(
        .PLLRST_ENA("DISABLED"),
        .INTFB_WAKE("DISABLED"),
        .STDBY_ENABLE("DISABLED"),
        .DPHASE_SOURCE("DISABLED"),
        .OUTDIVIDER_MUXA("DIVA"),
        .OUTDIVIDER_MUXB("DIVB"),
        .OUTDIVIDER_MUXC("DIVC"),
        .OUTDIVIDER_MUXD("DIVD"),
        .CLKI_DIV(1),
        .CLKOP_ENABLE("ENABLED"),
        .CLKOP_DIV(5),
        .CLKOP_CPHASE(2),
        .CLKOP_FPHASE(0),
        .CLKOS2_ENABLE("ENABLED"),
        .CLKOS2_DIV(25),
        .CLKOS2_CPHASE(2),
        .CLKOS2_FPHASE(0),
        .CLKOS3_ENABLE("ENABLED"),
        .CLKOS3_DIV(50),
        .CLKOS3_CPHASE(2),
        .CLKOS3_FPHASE(0),
        .FEEDBK_PATH("CLKOP"),
        .CLKFB_DIV(5)
    ) pll_i (
        .RST(1'b0),
        .STDBY(1'b0),
        .CLKI(clkin),
        .CLKOP(clkout0),
        .CLKOS2(clkout2),
        .CLKOS3(clkout3),
        .CLKFB(clkout0),
        .CLKINTFB(),
        .PHASESEL0(1'b0),
        .PHASESEL1(1'b0),
        .PHASEDIR(1'b1),
        .PHASESTEP(1'b1),
        .PHASELOADREG(1'b1),
        .PLLWAKESYNC(1'b0),
        .ENCLKOP(1'b0),
        .LOCK(locked)
	);
endmodule
module spram_256k (
    input clk,
    input cs,
    input [13:0] address,
    input [15:0] write_data,
    input [3:0] mask,
    input write_en,
    output reg [15:0] read_data
);
    // This verilator comment is required for the C++ TB to do the IPL
    // It slows the sim down, revise this at some point

    reg [15:0] mem [0:16383] /* verilator public */ ;

    always @(posedge clk) begin
        if (cs) begin
            if (!write_en) begin
                read_data <= mem[address];
            end else begin
                if (mask[0]) mem[address][ 3: 0] <= write_data[ 3: 0];
                if (mask[1]) mem[address][ 7: 4] <= write_data[ 7: 4];
                if (mask[2]) mem[address][11: 8] <= write_data[11: 8];
                if (mask[3]) mem[address][15:12] <= write_data[15:12];
                read_data <= 0;
            end
        end
    end
    
endmodule
module vdp_layer_priority_select(
    input clk,

    input [4:0] layer_mask,

    input [7:0] scroll0_pixel,
    input [7:0] scroll1_pixel,
    input [7:0] scroll2_pixel,
    input [7:0] scroll3_pixel,

    input [1:0] sprite_priority,
    input [7:0] sprite_pixel,

    output reg [4:0] prioritized_layer,
    output reg [7:0] prioritized_pixel,
    output reg [2:0] resolved_priority
);
    wire sprite_opaque_r = layer_mask_r[`LAYER_SPRITES];

    // 1a: Register inputs for output (2.)

    reg [7:0] scroll_pixel_r [0:3];
    reg [7:0] sprite_pixel_r;
    reg [1:0] sprite_priority_r;
    reg [4:0] layer_mask_r;

    always @(posedge clk) begin
        scroll_pixel_r[0] <= scroll0_pixel;
        scroll_pixel_r[1] <= scroll1_pixel;
        scroll_pixel_r[2] <= scroll2_pixel;
        scroll_pixel_r[3] <= scroll3_pixel;

        sprite_pixel_r <= sprite_pixel;
        sprite_priority_r <= sprite_priority;

        layer_mask_r <= layer_mask;
    end

    // 1b: Determine priority of layers / sprites

    wire [2:0] sprite_priority_score = {sprite_priority_r, 1'b1};
    wire [2:0] layer_priority_score = {layer_encoded_priority, 1'b0};
    reg [1:0] layer_encoded_priority;
    reg [3:0] layer_prioritized_ohe;

    always @(posedge clk) begin
        // if (layer_mask[3]) begin...
        layer_encoded_priority <= 0;
        layer_prioritized_ohe <= `LAYER_SCROLL3_OHE; 

        if (layer_mask[2]) begin
            layer_encoded_priority <= 1;
            layer_prioritized_ohe <= `LAYER_SCROLL2_OHE;
        end
        if (layer_mask[1]) begin
            layer_encoded_priority <= 2;
            layer_prioritized_ohe <= `LAYER_SCROLL1_OHE;
        end
        if (layer_mask[0]) begin
            layer_encoded_priority <= 3;
            layer_prioritized_ohe <= `LAYER_SCROLL0_OHE;
        end
    end

    // 2a: Use above priorities to select the topmost pixel

    always @* begin
        if (sprite_opaque_r && (sprite_priority_score > layer_priority_score)) begin
            prioritized_layer = `LAYER_SPRITES_OHE;
            resolved_priority = sprite_priority_score;
        end else if (|layer_mask_r[3:0]) begin
            prioritized_layer = layer_prioritized_ohe;
            resolved_priority = layer_priority_score;
        end else begin
            prioritized_layer = 0;
            resolved_priority = 0;
        end
    end

    // 2b: Output pixel according to topmost pixel using the outputs from above 

    always @* begin
        // 0 at the end of this ternary is required to default to color 0 when no others are on screen
        prioritized_pixel =
            prioritized_layer[0] ? scroll_pixel_r[0] :
            prioritized_layer[1] ? scroll_pixel_r[1] :
            prioritized_layer[2] ? scroll_pixel_r[2] :
            prioritized_layer[3] ? scroll_pixel_r[3] :
            sprite_opaque_r ? sprite_pixel_r : 0;
    end

endmodule
module vdp_scroll_pixel_generator #(
    parameter STAGE_PIXEL_ROW = 1
) (
    input clk,
    input [2:0] scroll_x_granular,
    input [2:0] raster_x_granular,
    input [31:0] pixel_row,
    input [3:0] palette_number,

    input tile_row_load_enable,
    input meta_load_enable,
    input shifter_preload_load_enable,

    output reg [7:0] pixel
);

    reg [31:0] pixel_row_preloaded;
    reg [31:0] output_pixel_row_t;
    reg [31:0] output_pixel_row;
    
    reg [3:0] output_palette_number;
    reg [3:0] palette_number_preloaded;
    reg [3:0] output_palette_number_t;

    wire [7:0] pixel_nx = {output_palette_number, output_pixel_row[31:28]};

    always @(posedge clk) begin
        pixel <= pixel_nx;
    end

    always @(posedge clk) begin
        if (STAGE_PIXEL_ROW && tile_row_load_enable) begin
            pixel_row_preloaded <= pixel_row;
        end

        if (meta_load_enable) begin
            palette_number_preloaded <= palette_number;
        end
    end

    always @(posedge clk) begin
        if (shifter_preload_load_enable) begin
            output_pixel_row_t <= STAGE_PIXEL_ROW ? pixel_row_preloaded : pixel_row;
            output_palette_number_t <= palette_number_preloaded;
        end
    end

    always @(posedge clk) begin
        if (~(scroll_x_granular) == raster_x_granular) begin
            output_pixel_row <= output_pixel_row_t;
            output_palette_number <= output_palette_number_t;
        end else begin
            output_pixel_row <= {output_pixel_row[27:0], 4'b0000};
        end
    end

endmodule
module vdp_map_address_generator #(
    parameter [0:0] REGISTERED_INPUTS = 0
) (
    input clk,

    input [9:0] scroll_y,
    input [6:0] scroll_x_coarse,

    input [9:0] raster_y,
    input [6:0] raster_x_coarse,

    input [14:0] map_base_address,
    input [7:0] stride,

    output [14:0] map_address_16b
);
    reg [9:0] scroll_y_r;
    reg [6:0] scroll_x_coarse_r;
    reg [9:0] raster_y_r;
    reg [6:0] raster_x_coarse_r;
    reg [14:0] map_base_address_r;
    reg [7:0] stride_r;

    generate
        if (REGISTERED_INPUTS) begin
            always @(posedge clk) begin
                scroll_y_r <= scroll_y;
                scroll_x_coarse_r <= scroll_x_coarse;
                raster_y_r <= raster_y;
                raster_x_coarse_r <= raster_x_coarse;
                map_base_address_r <= map_base_address;
                stride_r <= stride;
            end
        end else begin
            always @* begin
                scroll_y_r = scroll_y;
                scroll_x_coarse_r = scroll_x_coarse;
                raster_y_r = raster_y;
                raster_x_coarse_r = raster_x_coarse;
                map_base_address_r = map_base_address;
                stride_r = stride;
            end
        end
    endgenerate

    wire [6:0] column = scroll_x_coarse_r + raster_x_coarse_r;
    wire [5:0] row = (scroll_y_r + raster_y_r) >> 3;

    // cheap, only requires +1 LUT
    wire map_page_select = (stride_r & 8'h80) && column[6];

    assign map_address_16b = {map_page_select, row, column[5:0]} + map_base_address_r;

endmodule
module vdp_host_interface(
    input clk,
    input reset,

    input [5:0] host_address,
    output reg [4:0] register_write_address,
    input vram_write_pending,

    // Writes..

    output reg register_write_en,
    output reg [15:0] register_write_data,
    output reg ready,

    // ..from CPU

    input host_write_en,
    input [15:0] host_write_data,
    
    // ..from copper

    input cop_write_en,
    input [4:0] cop_write_address,
    input [15:0] cop_write_data,

    // Reads (only from CPU)

    input host_read_en,
    output reg [4:0] read_address
);
    reg host_write_en_r;
    reg host_write_pending;
    reg host_read_en_r;

    wire host_write_en_gated = host_write_en && !host_write_pending && !vram_write_pending;

    always @(posedge clk) begin
        host_write_en_r <= host_write_en;
        host_read_en_r <= host_read_en;
    end

    always @(posedge clk) begin
        // Reads use the registered input as a 1 cycle delay is required before output valid
        // Writes only need to be delayed if a subsequent write risks clobbering VRAM
        ready <= (host_write_en_gated || host_read_en_r);
    end

    always @(posedge clk) begin
        if (reset) begin
            register_write_en <= 0;
        end else begin
            register_write_en <= cop_write_en || host_write_en_gated;
        end
    end

    always @(posedge clk) begin
        if (reset) begin
            host_write_pending <= 0;
        end else if (host_write_en_gated) begin
            host_write_pending <= 1;
        end else if (!host_write_en) begin
            host_write_pending <= 0;
        end
    end

    always @(posedge clk) begin
        if (host_write_en) begin
            register_write_address <= host_address;
            register_write_data <= host_write_data;
        end else begin
            register_write_address <= cop_write_address;
            register_write_data <= cop_write_data;
        end

        // CPU is always free to read
        read_address <= host_address;
    end

    always @(posedge clk) begin
        if (!reset && cop_write_en && host_write_en) begin
            // Must be a software or hardware bug so flag it accordingly
            `stop($display("CPU / VDP copper write conflict. CPU: %x, COP: %x", host_address, cop_write_address);)
        end
    end

endmodule
module vdp_priority_compute(
    input clk,

    input [7:0] scroll0_pixel,
    input scroll0_is_8bpp,

    input [7:0] scroll1_pixel,
    input [7:0] scroll2_pixel,
    input [7:0] scroll3_pixel,

    input [7:0] sprite_pixel,
    input [1:0] sprite_priority,

    input [4:0] layer_enable,
    input [4:0] layer_mask,

    output reg [7:0] prioritized_pixel,
    output reg [4:0] prioritized_layer,

    output reg [7:0] prioritized_masked_pixel,
    output reg [4:0] prioritized_masked_layer
);

    wire [4:0] layer_opacity = {
        |sprite_pixel[3:0],
        |scroll3_pixel[3:0],
        |scroll2_pixel[3:0],
        |scroll1_pixel[3:0],
        |(scroll0_is_8bpp ? scroll0_pixel[7:0] : scroll0_pixel[3:0])
    };

    wire [4:0] primary_layers = layer_enable & layer_opacity & layer_mask;
    wire [4:0] masked_layers = layer_enable & layer_opacity & ~layer_mask;

    wire [4:0] prioritized_layer_nx;
    wire [7:0] prioritized_pixel_nx;

    wire [4:0] masked_layer_nx;
    wire [7:0] masked_pixel_nx;

    wire [2:0] primary_resolved_priority;
    wire [2:0] masked_resolved_priority;

    vdp_layer_priority_select primary_priority_select(
        .clk(clk),

        .layer_mask(primary_layers),
        .sprite_priority(sprite_priority),

        .scroll0_pixel(scroll0_pixel),
        .scroll1_pixel(scroll1_pixel),
        .scroll2_pixel(scroll2_pixel),
        .scroll3_pixel(scroll3_pixel),
        .sprite_pixel(sprite_pixel),

        .prioritized_layer(prioritized_layer_nx),
        .prioritized_pixel(prioritized_pixel_nx),
        .resolved_priority(primary_resolved_priority)
    );

    vdp_layer_priority_select masked_priority_select(
        .clk(clk),

        .layer_mask(masked_layers),
        .sprite_priority(sprite_priority),

        .scroll0_pixel(scroll0_pixel),
        .scroll1_pixel(scroll1_pixel),
        .scroll2_pixel(scroll2_pixel),
        .scroll3_pixel(scroll3_pixel),
        .sprite_pixel(sprite_pixel),

        .prioritized_layer(masked_layer_nx),
        .prioritized_pixel(masked_pixel_nx),
        .resolved_priority(masked_resolved_priority)
    );

    // if primary layer beats masked layer, force masked layer to 0
    // this lets a higher priority alpha-over layer win over an otherwise prioritised layer
    wire force_masked_layer_off = primary_resolved_priority > masked_resolved_priority;

    always @(posedge clk) begin
        prioritized_layer <= prioritized_layer_nx;
        prioritized_pixel <= prioritized_pixel_nx;

        prioritized_masked_layer <= force_masked_layer_off ? 0 : masked_layer_nx;
        prioritized_masked_pixel <= masked_pixel_nx;
    end 

endmodule
module vdp_tile_address_generator(
    input clk,

    input [2:0] scroll_y_granular,
    input [2:0] raster_y_granular,
    input [15:0] vram_data,
    input [13:0] tile_base_address,

    output [13:0] tile_address
);
    reg [2:0] scroll_y_granular_h;
    reg [2:0] raster_y_granular_h;
    reg [15:0] map_data_h;
    reg [13:0] tile_base_address_h;

    always @(posedge clk) begin
        scroll_y_granular_h <= scroll_y_granular;
        raster_y_granular_h <= raster_y_granular;
        map_data_h <= vram_data;
        tile_base_address_h <= tile_base_address;
    end

    wire is_yflipped = map_data_h[10];
    wire [2:0] tile_row = scroll_y_granular_h + raster_y_granular_h;
    wire [2:0] resolved_tile_row = is_yflipped ? ~tile_row : tile_row;
    wire [8:0] tile_number = map_data_h[8:0];

    assign tile_address = tile_base_address_h + {tile_number, resolved_tile_row};

endmodule
module spram_256k (
    input clk,
    input cs,
    input [13:0] address,
    input [15:0] write_data,
    input [3:0] mask,
    input write_en,
    output reg [15:0] read_data
);
    SB_SPRAM256KA ram (
        .ADDRESS(address),
        .DATAIN(write_data),
        .MASKWREN(mask),
        .WREN(write_en),
        .CHIPSELECT(cs),
        .CLOCK(clk),
        .STANDBY(0),
        .SLEEP(0),
        .POWEROFF(1),
        .DATAOUT(read_data)
    );
    
endmodule
module pdm_dac #(
    parameter integer WIDTH = 16
) (
    input clk,
    input reset,

    input [WIDTH - 1:0] pcm_in,
    input pcm_valid,

    output pdm_out
);
    reg [WIDTH - 1:0] pdm_level;
    reg [WIDTH + 1:0] pdm_sigma;
    assign pdm_out = ~pdm_sigma[WIDTH + 1];

    always @(posedge clk) begin
        if (reset) begin
            pdm_level <= 0;
            pdm_sigma <= 0;
        end else begin
            if (pcm_valid) begin
                pdm_level <= pcm_in + ((1 << (WIDTH - 1)));
            end

            pdm_sigma <= pdm_sigma + {pdm_out, pdm_out, pdm_level};
        end
    end

endmodule
module pll_ice40 #(
    parameter ENABLE_FAST_CLK = 1
) (
    // verilator lint_off UNUSED
    input clk_12m,
    // verilator lint_on UNUSED

    output locked,
    output clk_1x /* verilator clocker */,
    output clk_2x /* verilator clocker */
);
    localparam PLL_DIVR_25M = 4'b0000;
    localparam PLL_DIVF_25M = 7'b1000010;
    localparam PLL_DIVQ_25M = 7'b101;

    localparam PLL_DIVR_33M = 4'b0000;
    localparam PLL_DIVF_33M = 7'b0101100;
    localparam PLL_DIVQ_33M = 7'b100;

    localparam PLL_DIVR = ENABLE_FAST_CLK ? PLL_DIVR_33M : PLL_DIVR_25M;
    localparam PLL_DIVF = ENABLE_FAST_CLK ? PLL_DIVF_33M : PLL_DIVF_25M;
    localparam PLL_DIVQ = ENABLE_FAST_CLK ? PLL_DIVQ_33M : PLL_DIVQ_25M;

    SB_PLL40_2F_PAD #(
        .FEEDBACK_PATH("SIMPLE"),
        .PLLOUT_SELECT_PORTA("GENCLK_HALF"),
        .PLLOUT_SELECT_PORTB("GENCLK"),
        .DIVR(PLL_DIVR),
        .DIVF(PLL_DIVF),
        .DIVQ(PLL_DIVQ),
        .FILTER_RANGE(3'b001)
    ) pll (
        .LOCK(locked),
        .RESETB(1'b1),
        .BYPASS(1'b0),
        .PACKAGEPIN(clk_12m),
        .PLLOUTGLOBALA(clk_1x),
        .PLLOUTGLOBALB(clk_2x)
    );

endmodule
module vexriscv_shared_bus(
    input clk,
    input reset,

    input mem_ready,
    output mem_valid,

    output [31:0] mem_addr,
    input [31:0] mem_rdata,
    output [31:0] mem_wdata,
    output [3:0] mem_wstrb
);
    // PicoRV32-style bus interface

    assign mem_addr = vex_address_r;
    assign mem_wdata = vex_data_r;
    assign mem_wstrb = vex_wstrb;

    assign mem_valid = vex_bus_active;

    // VexRiscV simple ibus / dbus <-> PicoRV32 bus adapter

    reg vex_bus_active;

    reg vex_i_bus_active;
    wire vex_d_bus_active = !vex_i_bus_active;

    reg [31:0] vex_address_r;
    reg [31:0] vex_data_r;
    reg [3:0] vex_wstrb;

    wire vex_mem_ready = vex_bus_active && mem_ready;
    wire vex_i_rsp_valid = vex_i_bus_active && vex_mem_ready;
    wire vex_d_rsp_valid = vex_d_bus_active && vex_mem_ready;

    wire [1:0] vex_write_size;
    wire vex_d_write_en;
    wire [31:0] vex_d_write_data;

    wire vex_i_valid, vex_d_valid;
    wire [31:0] vex_i_address;
    wire [31:0] vex_d_address;

    // iBus_cmd_ready can be driven using comb. logic with iBus_cmd_valid..
    wire vex_i_ready = vex_i_valid && !vex_bus_active;
    // ..but dBus_cmd_ready can't usse iBus_cmd_valid without logic loops, so register it
    reg vex_d_started;
    wire vex_d_ready = vex_d_started && vex_d_valid && vex_bus_active;

    always @(posedge clk) begin
        if (reset) begin
            vex_bus_active <= 0;
            vex_d_started <= 0;
        end else begin
            vex_d_started <= 0;

            if (!vex_bus_active) begin
                if (vex_i_valid) begin
                    vex_i_bus_active <= 1;
                    vex_bus_active <= 1;

                    vex_address_r <= vex_i_address;
                end else if (vex_d_valid) begin
                    vex_i_bus_active <= 0;
                    vex_bus_active <= 1;
                    vex_d_started <= 1;

                    vex_address_r <= vex_d_address;
                    vex_data_r <= vex_d_write_data;
                    vex_wstrb <= vex_d_write_en ? (((1 << (1 << vex_write_size)) - 1) << vex_d_address[1:0]) : 0;
                end
            end else if (vex_mem_ready) begin
                vex_bus_active <= 0;
                vex_wstrb <= 0;
                vex_d_started <= 0;
            end
        end
    end

    VexRiscv vex(
        .clk(clk),
        .reset(reset),

        .iBus_cmd_payload_pc(vex_i_address),
        .iBus_cmd_valid(vex_i_valid),
        .iBus_cmd_ready(vex_i_ready),

        .iBus_rsp_payload_inst(mem_rdata),
        .iBus_rsp_valid(vex_i_rsp_valid),

        .dBus_cmd_payload_address(vex_d_address),
        .dBus_cmd_payload_data(vex_d_write_data),
        .dBus_cmd_payload_size(vex_write_size),
        .dBus_cmd_payload_wr(vex_d_write_en),
        .dBus_cmd_valid(vex_d_valid),
        .dBus_cmd_ready(vex_d_ready),

        .dBus_rsp_ready(vex_d_rsp_valid),
        .dBus_rsp_data(mem_rdata),

        .dBus_rsp_error(0),
        .iBus_rsp_payload_error(0)
    );

endmodule
module usbh_crc16
(
    input [15:0]    crc_i,
    input [7:0]     data_i,
    output [15:0]   crc_o
);
 
//-----------------------------------------------------------------
// Implementation
//-----------------------------------------------------------------
assign crc_o[15] =    data_i[0] ^ data_i[1] ^ data_i[2] ^ data_i[3] ^ data_i[4] ^
                        data_i[5] ^ data_i[6] ^ data_i[7] ^ crc_i[7] ^ crc_i[6] ^
                        crc_i[5] ^ crc_i[4] ^ crc_i[3] ^ crc_i[2] ^
                        crc_i[1] ^ crc_i[0];
assign crc_o[14] =    data_i[0] ^ data_i[1] ^ data_i[2] ^ data_i[3] ^ data_i[4] ^ data_i[5] ^
                        data_i[6] ^ crc_i[6] ^ crc_i[5] ^ crc_i[4] ^
                        crc_i[3] ^ crc_i[2] ^ crc_i[1] ^ crc_i[0];
assign crc_o[13] =    data_i[6] ^ data_i[7] ^ crc_i[7] ^ crc_i[6];
assign crc_o[12] =    data_i[5] ^ data_i[6] ^ crc_i[6] ^ crc_i[5];
assign crc_o[11] =    data_i[4] ^ data_i[5] ^ crc_i[5] ^ crc_i[4];
assign crc_o[10] =    data_i[3] ^ data_i[4] ^ crc_i[4] ^ crc_i[3];
assign crc_o[9] =     data_i[2] ^ data_i[3] ^ crc_i[3] ^ crc_i[2];
assign crc_o[8] =     data_i[1] ^ data_i[2] ^ crc_i[2] ^ crc_i[1];
assign crc_o[7] =     data_i[0] ^ data_i[1] ^ crc_i[15] ^ crc_i[1] ^ crc_i[0];
assign crc_o[6] =     data_i[0] ^ crc_i[14] ^ crc_i[0];
assign crc_o[5] =     crc_i[13];
assign crc_o[4] =     crc_i[12];
assign crc_o[3] =     crc_i[11];
assign crc_o[2] =     crc_i[10];
assign crc_o[1] =     crc_i[9];
assign crc_o[0] =     data_i[0] ^ data_i[1] ^ data_i[2] ^ data_i[3] ^ data_i[4] ^ data_i[5] ^
                        data_i[6] ^ data_i[7] ^ crc_i[8] ^ crc_i[7] ^ crc_i[6] ^
                        crc_i[5] ^ crc_i[4] ^ crc_i[3] ^ crc_i[2] ^
                        crc_i[1] ^ crc_i[0];
 
endmodule
module usbh_crc5
(
    input [4:0]     crc_i,
    input [10:0]    data_i,
    output [4:0]    crc_o
);
 
//-----------------------------------------------------------------
// Implementation
//-----------------------------------------------------------------
assign crc_o[0] =    data_i[10] ^ data_i[9] ^ data_i[6] ^ data_i[5] ^ data_i[3] ^ data_i[0] ^
                       crc_i[0] ^ crc_i[3] ^ crc_i[4];
 
assign crc_o[1] =    data_i[10] ^ data_i[7] ^ data_i[6] ^ data_i[4] ^ data_i[1] ^
                       crc_i[0] ^ crc_i[1] ^ crc_i[4];
 
assign crc_o[2] =    data_i[10] ^ data_i[9] ^ data_i[8] ^ data_i[7] ^ data_i[6] ^ data_i[3] ^ data_i[2] ^ data_i[0] ^
                       crc_i[0] ^ crc_i[1] ^ crc_i[2] ^ crc_i[3] ^ crc_i[4];
 
assign crc_o[3] =    data_i[10] ^ data_i[9] ^ data_i[8] ^ data_i[7] ^ data_i[4] ^ data_i[3] ^ data_i[1] ^ 
                       crc_i[1] ^ crc_i[2] ^ crc_i[3] ^ crc_i[4];
 
assign crc_o[4] =    data_i[10] ^ data_i[9] ^ data_i[8] ^ data_i[5] ^ data_i[4] ^ data_i[2] ^
                       crc_i[2] ^ crc_i[3] ^ crc_i[4];
 
endmodule
module usbh_report_decoder_wingman(
    input  wire        i_clk,
    input  wire [63:0] i_report,
    input  wire        i_report_valid,
    output reg   [11:0] o_btn
);
// HID report layout:
//
//  [7:0]   Left stick X
//  [15:8]  Left stick Y
//  [23:16] Throttle slider
//  [31:24] Right stick X
//  [39:32] Right stick Y
//  [43:40] Hat (clockwise)
//  [44]    Button A
//  [45]    Button B
//  [46]    Button C
//  [47]    Button X
//  [48]    Button Y
//  [49]    Button Z
//  [50]    Button L
//  [51]    Button R
//  [52]    Button S
//  [53]    Application 1
//  [54]    Application 2
//  [55]    Application 3: Rumble
//  [56]    Application 4: Mode
//  [57]    Application 5
//  [58]    Application 6
//  [59]    Application 7
//  [60]    Application 8
//  [61]    Application 9
//  [62]    Application 10
//  [63]    Application 11
//
// Hat switch values:
//
//                     LRUD
//    0 = up           0010
//    1 = right-up     0110
//    2 = right        0100
//    3 = right-down   0101
//    4 = down         0001
//    5 = left-down    1001
//    6 = left         1000
//    7 = left-up      1010
//    8 = unpressed    0000
//
// Layout (Logitech):
//
//          Z
//    Y
//            C
// X     B
//
//    A
//
// Layout (SNES):
//
//                  X   A
//
// Select  Start  Y   B
//
// Mapping:
//
//   LEFT/RIGHT/UP/DOWN = Hat, ignore analog sticks for now
//   A = B
//   B = A
//   X = Y
//   Y = X
//   L = L
//   R = R
//   Select = C
//   Start = S
//
    wire [3:0] hat = i_report[43:40];
    wire left = hat == 5 | hat == 6 | hat == 7;
    wire right = hat == 1 | hat == 2 | hat == 3;
    wire up = hat == 0 | hat == 1 | hat == 7;
    wire down = hat == 3 | hat == 4 | hat == 5;

    wire a = i_report[45];
    wire b = i_report[44];
    wire x = i_report[48];
    wire y = i_report[47];

    wire l = i_report[50];
    wire r = i_report[51];

    wire select = i_report[46];
    wire start = i_report[52];

    always @(posedge i_clk) begin
        if (i_report_valid) begin
            o_btn <= {
                r, l, x, a,
                right, left, down, up,
                start, select, y, b
            };
        end
    end

endmodule
module usbh_report_decoder_buffalo(
    input  wire        i_clk,
    input  wire [63:0] i_report,
    input  wire        i_report_valid,
    output reg   [11:0] o_btn
);
    wire left = i_report[7:0] == 0;
    wire right = i_report[7:0] == 8'hff;
    wire up = i_report[15:8] == 0;
    wire down = i_report[15:8] == 8'hff;

    wire a = i_report[16];
    wire b = i_report[17];
    wire x = i_report[18];
    wire y = i_report[19];

    wire l = i_report[20];
    wire r = i_report[21];

    wire select = i_report[22];
    wire start = i_report[23];

    always @(posedge i_clk) begin
        if (i_report_valid) begin
            o_btn <= {
                r, l, x, a,
                right, left, down, up,
                start, select, y, b
            };
        end
    end

endmodule