Skip to content

Commit

Permalink
hw: Connect P2 gamepad input
Browse files Browse the repository at this point in the history
The user button used to accept the boot prompt as previously used as the P2 input
Now it is the actual P2 gamepad input on the iCEBreaker gamepad PMOD
  • Loading branch information
dan-rodrigues committed Dec 23, 2020
1 parent 0458573 commit 8072465
Show file tree
Hide file tree
Showing 12 changed files with 96 additions and 23 deletions.
2 changes: 1 addition & 1 deletion firmware/boot_defines.S
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
.equ FLASH_SR2_QE, (1 << 1)

.equ PAD_DATA, 0x40000
.equ PAD_USER_BUTTON, (1 << 1)
.equ PAD_USER_BUTTON, (1 << 2)

.equ LED_DATA, 0x20000

Expand Down
4 changes: 2 additions & 2 deletions hardware/bus_arbiter.v
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ module bus_arbiter #(
input [31:0] flash_read_data,
input [15:0] vdp_read_data,
input [31:0] dsp_read_data,
input [1:0] pad_read_data,
input [2:0] pad_read_data,
input [3:0] flash_ctrl_read_data,
input [7:0] audio_cpu_read_data,

Expand Down Expand Up @@ -107,7 +107,7 @@ module bus_arbiter #(
end else if (dsp_en && (READ_SOURCES & `BA_DSP)) begin
cpu_read_data_ps = dsp_read_data;
end else if (pad_en && (READ_SOURCES & `BA_PAD)) begin
cpu_read_data_ps[1:0] = pad_read_data;
cpu_read_data_ps[2:0] = pad_read_data;
end else if (bootloader_en && (READ_SOURCES & `BA_BOOT)) begin
cpu_read_data_ps = bootloader_read_data;
end else if (cpu_ram_en && (READ_SOURCES & `BA_CPU_RAM)) begin
Expand Down
49 changes: 39 additions & 10 deletions hardware/icebreaker/ics32_top_icebreaker.v
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,9 @@ module ics32_top_icebreaker #(
.D_OUT_1(flash_clk_ddr[1])
);

// --- Gamepad reading ---
// --- User inputs ---

// Gamepads:

wire [1:0] pad_read_data;

Expand All @@ -192,6 +194,7 @@ module ics32_top_icebreaker #(
assign pad_read_data = ~pad_read_data_n;

// Gamepad CLK + Latch

SB_IO #(
.PIN_TYPE(6'b010100),
.PULLUP(1'b0),
Expand All @@ -204,15 +207,17 @@ module ics32_top_icebreaker #(
.D_OUT_0({pad_clk, pad_latch}),
);

// Gamepad data (P1 only for now)
// Gamepad data

// There are actually 4 controller ports on the PMOD but the system is 2P only

SB_IO #(
.PIN_TYPE(6'b100000),
.PULLUP(1'b0),
.NEG_TRIGGER(1'b0),
.IO_STANDARD("SB_LVCMOS")
) gp_data_sbio [1:0] (
.PACKAGE_PIN({ /*pmod2_9, pmod2_3, pmod2_8,*/ btn_u, pmod2_2}),
.PACKAGE_PIN({pmod2_8, pmod2_2}),
.OUTPUT_ENABLE(1'b0),
.INPUT_CLK(clk_2x),
.CLOCK_ENABLE(1'b1),
Expand All @@ -224,15 +229,15 @@ module ics32_top_icebreaker #(
end else begin
// Breakout board buttons:

wire [3:0] btn_r;
wire [2:0] btn_r;

SB_IO #(
.PIN_TYPE(6'b100000),
.PULLUP(1'b0),
.NEG_TRIGGER(1'b0),
.IO_STANDARD("SB_LVCMOS")
) btn_sbio [3:0] (
.PACKAGE_PIN({btn_u, pmod2_10, pmod2_4, pmod2_9}),
) btn_sbio [2:0] (
.PACKAGE_PIN({pmod2_10, pmod2_4, pmod2_9}),
.OUTPUT_ENABLE(1'b0),
.INPUT_CLK(clk_2x),
.CLOCK_ENABLE(1'b1),
Expand All @@ -242,13 +247,10 @@ module ics32_top_icebreaker #(
.OUTPUT_CLK(clk_2x)
);

// Only the 3 buttons on the breakboard are used as a partial gamepad
// This can be extended later with an actual gamepad PMOD
// P1 has limited inputs using the breakout board

wire [11:0] pad_btn = {btn_r[0], btn_r[2], 5'b0, btn_r[1]};

assign pad_read_data[1] = ~btn_r[3];

mock_gamepad mock_gamepad(
.clk(clk_2x),

Expand All @@ -258,9 +260,34 @@ module ics32_top_icebreaker #(

.pad_out(pad_read_data[0])
);

// P2 has no inputs when just using the breakout board

assign pad_read_data[1] = 0;
end
endgenerate

// User button:

wire user_button;
wire user_button_n = !user_button;

SB_IO #(
.PIN_TYPE(6'b100000),
.PULLUP(1'b0),
.NEG_TRIGGER(1'b0),
.IO_STANDARD("SB_LVCMOS")
) btn_sbio (
.PACKAGE_PIN(btn_u),
.OUTPUT_ENABLE(1'b0),
.INPUT_CLK(clk_2x),
.CLOCK_ENABLE(1'b1),
.D_IN_0(user_button),

// This isn't used but nextpnr will error without this:
.OUTPUT_CLK(clk_2x)
);

// --- icestation-32 ---

wire reset_1x, reset_2x;
Expand Down Expand Up @@ -306,6 +333,8 @@ module ics32_top_icebreaker #(
.pad_clk(pad_clk),
.pad_data(pad_read_data),

.user_button(user_button_n),

.led({led_r, led_b}),

.flash_clk_ddr(flash_clk_ddr),
Expand Down
4 changes: 3 additions & 1 deletion hardware/ics32.v
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ module ics32 #(
output pad_clk,
input [1:0] pad_data,

input user_button,

output [1:0] flash_clk_ddr,
output flash_csn,
output [3:0] flash_in,
Expand Down Expand Up @@ -553,7 +555,7 @@ module ics32 #(
.flash_read_data(flash_read_data),
.dsp_read_data(dsp_result),
.vdp_read_data(vdp_read_data),
.pad_read_data(pad_data),
.pad_read_data({user_button, pad_data}),
.flash_ctrl_read_data(flash_ctrl_read_data),
.audio_cpu_read_data(audio_ctrl_cpu_read_data),

Expand Down
29 changes: 24 additions & 5 deletions hardware/ulx3s/ics32_top_ulx3s.v
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,7 @@ module ics32_top_ulx3s #(
wire [11:0] pad_btn;
wire [1:0] pad_read_data;

// P2 input is used as a special user button
// (This needs to move if an actual P2 is needed)

wire btn_u = btn[3];
assign pad_read_data[1] = btn_u;
// P1 is supported using the gamepad_state instance below

mock_gamepad mock_gamepad(
.clk(clk_2x),
Expand All @@ -262,9 +258,15 @@ module ics32_top_ulx3s #(
.pad_out(pad_read_data[0])
);

// P2 currently not supported on ULX3S

assign pad_read_data[1] = 0;

// The mock_gamepad above is driven by gamepad data from one of the sources below.
// GAMEPAD_SOURCE is used to detmine which one:

wire user_button;

ulx3s_gamepad_state #(
.GAMEPAD_SOURCE(GAMEPAD_SOURCE),
.USB_GAMEPAD(USB_GAMEPAD)
Expand Down Expand Up @@ -303,6 +305,21 @@ module ics32_top_ulx3s #(
.pad_btn(pad_btn)
);

// Unlike the gamepads, user button input is always provided by PCB
// btn[0] is shared with the ESP32 reset if (GAMEPAD_SOURCE == "BLUETOOTH")

wire user_button;

debouncer #(
.BTN_COUNT(1)
) user_button_debouncer (
.clk(clk_2x),
.reset(reset_2x),

.btn(!btn[0]),
.level(user_button)
);

// --- icestation-32 ---

assign led = GAMEPAD_LED ? pad_btn : status_led;
Expand Down Expand Up @@ -350,6 +367,8 @@ module ics32_top_ulx3s #(
.pad_clk(pad_clk),
.pad_data(pad_read_data),

.user_button(user_button),

.led(status_led),

.flash_clk_ddr(flash_clk_ddr),
Expand Down
2 changes: 1 addition & 1 deletion hardware/ulx3s/ulx3s_gamepad_state.v
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ module ulx3s_gamepad_state #(
.reset(reset),

.btn(!btn[0]),
.level(esp32_reset),
.level(esp32_reset)
);

// SPI gamepad reader:
Expand Down
2 changes: 1 addition & 1 deletion simulator/CXXRTLSimulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ void CXXRTLSimulation::step(uint64_t time) {
top.p_clk__1x = value<1>{clk_1x};
top.p_clk__2x = value<1>{clk_2x};

top.p_btn__u.set(!button_user);
top.p_btn__u.set(button_user);
top.p_btn__1.set(button_1);
top.p_btn__2.set(button_2);
top.p_btn__3.set(button_3);
Expand Down
2 changes: 1 addition & 1 deletion simulator/VerilatorSimulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ void VerilatorSimulation::step(uint64_t time) {
tb->clk_1x = clk_1x;
tb->clk_2x = clk_2x;

tb->btn_u = !button_user;
tb->btn_u = button_user;
tb->btn_1 = button_1;
tb->btn_2 = button_2;
tb->btn_3 = button_3;
Expand Down
10 changes: 9 additions & 1 deletion simulator/ics32_tb.v
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ module ics32_tb(
.pad_clk(pad_clk),
.pad_data(pad_read_data),

.user_button(btn_u),

.led(led),

.flash_clk_ddr(flash_clk_ddr),
Expand All @@ -97,10 +99,11 @@ module ics32_tb(
};

wire [1:0] pad_read_data;
assign pad_read_data[1] = ~btn_u;

wire pad_latch, pad_clk;

// P1 is currently controllable in the sim

mock_gamepad mock_gamepad(
.clk(clk_2x),

Expand All @@ -111,6 +114,11 @@ module ics32_tb(
.pad_out(pad_read_data[0])
);

// P2 isn't

assign pad_read_data[1] = 0;


// --- Flash sim blackbox ---

wire [1:0] flash_clk_ddr;
Expand Down
8 changes: 8 additions & 0 deletions software/gamepad_test/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ int main() {
const uint8_t p2_base_x = 60;
const uint8_t p2_base_y = 10;

const uint8_t user_base_x = 47;
const uint8_t user_base_y = 25;

while (true) {
vdp_wait_frame_ended();

Expand All @@ -67,6 +70,11 @@ int main() {

vp_printf(p2_base_x, p2_base_y, TEXT_PALETTE_ID, SCROLL0, MAP_VRAM_BASE, "Player 2");
print_gamepad(p2_current, p2_base_x, p2_base_y + 2);

vp_printf(user_base_x, user_base_y,
TEXT_PALETTE_ID, SCROLL0, MAP_VRAM_BASE,
"User button: %d",
pad_read_user_button());
}
}

Expand Down
5 changes: 5 additions & 0 deletions software/lib/gamepad.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ static volatile uint32_t * const PAD_BASE = (uint32_t *)0x40000;

static const uint32_t PAD_LATCH = 1 << 0;
static const uint32_t PAD_CLK = 1 << 1;
static const uint32_t USER_BUTTON = 1 << 2;

#define PAD_IO (*((volatile uint32_t *) PAD_BASE + 0))

Expand Down Expand Up @@ -73,6 +74,10 @@ void pad_decode_input(uint16_t encoded_input, PadInputDecoded *decoded_input) {
}
}

bool pad_read_user_button() {
return (PAD_IO & USER_BUTTON);
}

const PadInputDecoded PAD_INPUT_DECODED_NO_INPUT = {
.b = 0, .y = 0, .select = 0, .start = 0,
.up = 0, .down = 0, .left = 0, .right = 0,
Expand Down
2 changes: 2 additions & 0 deletions software/lib/gamepad.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,6 @@ extern const PadInputDecoded PAD_INPUT_DECODED_NO_INPUT;
void pad_read(uint16_t *p1_current, uint16_t *p2_current, uint16_t *p1_edge, uint16_t *p2_edge);
void pad_decode_input(uint16_t encoded_input, PadInputDecoded *decoded_input);

bool pad_read_user_button(void);

#endif /* gamepad_h */

0 comments on commit 8072465

Please sign in to comment.