Skip to content

Commit adcb3cc

Browse files
authored
Low-speed game gamepad support (#23)
Add support for 2 usb gamepads based on hi631's ukp code. Add doc/usb_gamepad.md.
1 parent d4f928d commit adcb3cc

16 files changed

+1426
-40
lines changed

doc/images/usb_gamepad1.jpg

221 KB
Loading

doc/images/usb_gamepad2.jpg

173 KB
Loading

doc/usb_gamepad.md

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
2+
## USB Gamepad Setup
3+
4+
NESTang 0.6 now supports USB gamepads, allowing you to use your existing controllers without the need to purchase new ones.
5+
6+
<img src="images/usb_gamepad2.jpg" width=400>
7+
<img src="images/usb_gamepad1.jpg" width=400>
8+
9+
To enable this functionality, you will need the following,
10+
* Two USB-A Female to 2.54mm adapters, which can be found [here](https://www.aliexpress.us/item/2255800203914149.html?spm=a2g0o.productlist.main.17.6e617e229i3qAm&algo_pvid=89ee64ce-a2c8-41f6-9e3b-45e8396569fd&algo_exp_id=89ee64ce-a2c8-41f6-9e3b-45e8396569fd-8&pdp_npi=4%40dis%21USD%210.28%210.25%21%21%210.28%21%21%402132a25516924371147167093ec531%2110000001592482118%21sea%21US%214484896846%21A&curPageLogUid=dAeFgl6FWDAf).
11+
* Four 15K ohm resistors as USB pulldown resistor.
12+
13+
Then wire things up correctly, refer to the image above and the [Tang Nano 20K pinout](https://wiki.sipeed.com/hardware/en/tang/tang-nano-20k/nano-20k.html)). Follow these steps,
14+
* Connect USB VBUS to the 5V pin of Tang Nano 20K, and USB GND to the Tang GND.
15+
* For controller 1, connect D+ to pin 42 and D- to pin 41.
16+
* For controller 2, connect D+ to pin 56 and D- to pin 54.
17+
* Connect four 15K ohm resistors from D-/D+ to GND.
18+
19+
Please note that using the resistors is necessary for stability.
20+
21+
That's all you need to do.
22+
23+
**Limitation**: Note that only USB low-speed gamepads are currently supported. So controllers like PS5 or Xbox 360 pads are not compatible.
24+

nes.gprj

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
<File path="src/gowin_clkdiv/gowin_clkdiv.v" type="file.verilog" enable="1"/>
1717
<File path="src/gowin_rpll_hdmi/gowin_rpll.v" type="file.verilog" enable="1"/>
1818
<File path="src/gowin_rpll_nes/gowin_rpll.v" type="file.verilog" enable="1"/>
19+
<File path="src/gowin_rpll_usb.v" type="file.verilog" enable="1"/>
1920
<File path="src/hdmi2/audio_clock_regeneration_packet.sv" type="file.verilog" enable="1"/>
2021
<File path="src/hdmi2/audio_info_frame.sv" type="file.verilog" enable="1"/>
2122
<File path="src/hdmi2/audio_sample_packet.sv" type="file.verilog" enable="1"/>
@@ -39,6 +40,8 @@
3940
<File path="src/sdcmd_ctrl.sv" type="file.verilog" enable="1"/>
4041
<File path="src/sdram.v" type="file.verilog" enable="1"/>
4142
<File path="src/uart_tx_V2.v" type="file.verilog" enable="1"/>
43+
<File path="src/usb_gamepad.v" type="file.verilog" enable="1"/>
44+
<File path="src/usb_gamepad_rom.v" type="file.verilog" enable="1"/>
4245
<File path="src/nestang.cst" type="file.cst" enable="1"/>
4346
<File path="src/nestang_dock.cst" type="file.cst" enable="0"/>
4447
<File path="src/nestang.sdc" type="file.sdc" enable="1"/>

src/gowin_rpll_hdmi/gowin_rpll.v

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,6 @@ defparam rpll_inst.CLKOUTD_BYPASS = "false";
6060
defparam rpll_inst.DYN_SDIV_SEL = 2;
6161
defparam rpll_inst.CLKOUTD_SRC = "CLKOUT";
6262
defparam rpll_inst.CLKOUTD3_SRC = "CLKOUT";
63-
defparam rpll_inst.DEVICE = "GW2A-18C";
63+
defparam rpll_inst.DEVICE = "GW2AR-18";
6464

6565
endmodule //Gowin_rPLL

src/gowin_rpll_nes/gowin_rpll.v

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,6 @@ defparam rpll_inst.CLKOUTD_BYPASS = "false";
8181
defparam rpll_inst.DYN_SDIV_SEL = 2;
8282
defparam rpll_inst.CLKOUTD_SRC = "CLKOUT";
8383
defparam rpll_inst.CLKOUTD3_SRC = "CLKOUT";
84-
defparam rpll_inst.DEVICE = "GW2AR-18C";
84+
defparam rpll_inst.DEVICE = "GW2AR-18";
8585

8686
endmodule //Gowin_rPLL

src/gowin_rpll_usb.v

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
2+
module Gowin_rPLL_usb (clkout, clkoutp, lock, reset, clkin);
3+
4+
output clkout;
5+
output clkoutp;
6+
output lock;
7+
input reset;
8+
input clkin;
9+
10+
wire clkoutd_o;
11+
wire clkoutd3_o;
12+
wire gw_gnd;
13+
14+
assign gw_gnd = 1'b0;
15+
16+
rPLL rpll_inst (
17+
.CLKOUT(clkout),
18+
.LOCK(lock),
19+
.CLKOUTP(clkoutp),
20+
.CLKOUTD(clkoutd_o),
21+
.CLKOUTD3(clkoutd3_o),
22+
.RESET(reset),
23+
.RESET_P(gw_gnd),
24+
.CLKIN(clkin),
25+
.CLKFB(gw_gnd),
26+
.FBDSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}),
27+
.IDSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}),
28+
.ODSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}),
29+
.PSDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}),
30+
.DUTYDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}),
31+
.FDLY({gw_gnd,gw_gnd,gw_gnd,gw_gnd})
32+
);
33+
34+
// 27 -> 12 Mhz low-speed USB clock
35+
defparam rpll_inst.FCLKIN = "27";
36+
defparam rpll_inst.IDIV_SEL = 8;
37+
defparam rpll_inst.FBDIV_SEL = 3;
38+
defparam rpll_inst.ODIV_SEL = 64;
39+
40+
defparam rpll_inst.DYN_IDIV_SEL = "false";
41+
defparam rpll_inst.DYN_FBDIV_SEL = "false";
42+
defparam rpll_inst.DYN_ODIV_SEL = "false";
43+
defparam rpll_inst.PSDA_SEL = "1000";
44+
defparam rpll_inst.DYN_DA_EN = "false";
45+
defparam rpll_inst.DUTYDA_SEL = "1000";
46+
defparam rpll_inst.CLKOUT_FT_DIR = 1'b1;
47+
defparam rpll_inst.CLKOUTP_FT_DIR = 1'b1;
48+
defparam rpll_inst.CLKOUT_DLY_STEP = 0;
49+
defparam rpll_inst.CLKOUTP_DLY_STEP = 0;
50+
defparam rpll_inst.CLKFB_SEL = "internal";
51+
defparam rpll_inst.CLKOUT_BYPASS = "false";
52+
defparam rpll_inst.CLKOUTP_BYPASS = "false";
53+
defparam rpll_inst.CLKOUTD_BYPASS = "false";
54+
defparam rpll_inst.DYN_SDIV_SEL = 2;
55+
defparam rpll_inst.CLKOUTD_SRC = "CLKOUT";
56+
defparam rpll_inst.CLKOUTD3_SRC = "CLKOUT";
57+
defparam rpll_inst.DEVICE = "GW2AR-18";
58+
59+
endmodule //Gowin_rPLL

src/nes_tang20k.v

+93-37
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ module NES_Tang20k(
4949
input joystick_miso2,
5050
output reg joystick_cs2,
5151

52+
// USB
53+
inout usbdm,
54+
inout usbdp,
55+
inout usbdm2,
56+
inout usbdp2,
57+
// output clk_usb,
58+
5259
// HDMI TX
5360
output tmds_clk_n,
5461
output tmds_clk_p,
@@ -64,12 +71,21 @@ always @(posedge clk) begin
6471
end
6572

6673
`ifndef VERILATOR
67-
// NES PPU clock 5.369 * 7 = 37.6
68-
Gowin_rPLL_nes pll_nes(
69-
.clkin(sys_clk),
70-
.clkout(clk), // FREQ main clock
71-
.clkoutp(clk_sdram) // FREQ main clock phase shifted
72-
);
74+
// Gowin_rPLL_nes pll_nes(
75+
// .clkin(sys_clk),
76+
// .clkout(clk), // FREQ main clock
77+
// .clkoutp(clk_sdram) // FREQ main clock phase shifted
78+
// );
79+
wire clk = sys_clk;
80+
wire clk_sdram = ~sys_clk;
81+
wire clk_usb;
82+
83+
// USB clock 12Mhz
84+
Gowin_rPLL_usb pll_nes(
85+
.clkin(sys_clk),
86+
.clkout(clk_usb), // 12Mhz usb clock
87+
.clkoutp()
88+
);
7389

7490
// HDMI domain clocks
7591
wire clk_p; // 720p pixel clock: 74.25 Mhz
@@ -161,11 +177,16 @@ UartDemux #(.FREQ(FREQ), .BAUDRATE(BAUDRATE)) uart_demux(
161177
O is A, X is B
162178
*/
163179
wire [7:0] joy_rx[0:1], joy_rx2[0:1]; // 6 RX bytes for all button/axis state
180+
wire [7:0] usb_btn, usb_btn2;
181+
wire usb_btn_x, usb_btn_y, usb_btn_x2, usb_btn_y2;
182+
wire usb_conerr, usb_conerr2;
164183
wire auto_square, auto_triangle, auto_square2, auto_triangle2;
165184
wire [7:0] nes_btn = {~joy_rx[0][5], ~joy_rx[0][7], ~joy_rx[0][6], ~joy_rx[0][4],
166-
~joy_rx[0][3], ~joy_rx[0][0], ~joy_rx[1][6] | auto_square, ~joy_rx[1][5] | auto_triangle};
185+
~joy_rx[0][3], ~joy_rx[0][0], ~joy_rx[1][6] | auto_square, ~joy_rx[1][5] | auto_triangle} |
186+
usb_btn;
167187
wire [7:0] nes_btn2 = {~joy_rx2[0][5], ~joy_rx2[0][7], ~joy_rx2[0][6], ~joy_rx2[0][4],
168-
~joy_rx2[0][3], ~joy_rx2[0][0], ~joy_rx2[1][6] | auto_square2, ~joy_rx2[1][5] | auto_triangle2};
188+
~joy_rx2[0][3], ~joy_rx2[0][0], ~joy_rx2[1][6] | auto_square2, ~joy_rx2[1][5] | auto_triangle2} |
189+
usb_btn2;
169190

170191
// Joypad handling
171192
always @(posedge clk) begin
@@ -349,18 +370,32 @@ dualshock_controller controller2 (
349370
.I_VIB_SW(2'b00), .I_VIB_DAT(8'hff) // no vibration
350371
);
351372

352-
Autofire af_square (.clk(clk), .resetn(sys_resetn), .btn(~joy_rx[1][7]), .out(auto_square));
353-
Autofire af_triangle (.clk(clk), .resetn(sys_resetn), .btn(~joy_rx[1][4]), .out(auto_triangle));
354-
Autofire af_square2 (.clk(clk), .resetn(sys_resetn), .btn(~joy_rx2[1][7]), .out(auto_square2));
355-
Autofire af_triangle2 (.clk(clk), .resetn(sys_resetn), .btn(~joy_rx2[1][4]), .out(auto_triangle2));
373+
Autofire af_square (.clk(clk), .resetn(sys_resetn), .btn(~joy_rx[1][7] | usb_btn_y), .out(auto_square)); // B
374+
Autofire af_triangle (.clk(clk), .resetn(sys_resetn), .btn(~joy_rx[1][4] | usb_btn_x), .out(auto_triangle)); // A
375+
Autofire af_square2 (.clk(clk), .resetn(sys_resetn), .btn(~joy_rx2[1][7] | usb_btn_y2), .out(auto_square2));
376+
Autofire af_triangle2 (.clk(clk), .resetn(sys_resetn), .btn(~joy_rx2[1][4] | usb_btn_x2), .out(auto_triangle2));
377+
378+
wire [63:0] dbg_hid_report;
379+
wire [3:0] dbg_dev;
380+
wire [15:0] dbg_vid, dbg_pid;
381+
usb_gamepad usb_controller (
382+
.usbclk(clk_usb), .usbrst_n(sys_resetn),
383+
.usb_dm(usbdm), .usb_dp(usbdp), .btn_nes(usb_btn), .btn_x(usb_btn_x), .btn_y(usb_btn_y), .conerr(usb_conerr),
384+
.dbg_hid_report(), .dbg_dev(), .dbg_vid(), .dbg_pid()
385+
);
386+
usb_gamepad usb_controller2 (
387+
.usbclk(clk_usb), .usbrst_n(sys_resetn),
388+
.usb_dm(usbdm2), .usb_dp(usbdp2), .btn_nes(usb_btn2), .btn_x(usb_btn_x2), .btn_y(usb_btn_y2), .conerr(usb_conerr2),
389+
.dbg_hid_report(dbg_hid_report), .dbg_dev(dbg_dev), .dbg_vid(dbg_vid), .dbg_pid(dbg_pid)
390+
);
356391

357392
//
358393
// Print control
359394
//
360395
`include "print.v"
361396
defparam tx.uart_freq=BAUDRATE;
362397
defparam tx.clk_freq=FREQ;
363-
assign print_clk = clk;
398+
assign print_clk = sys_clk;
364399
assign UART_TXD = uart_txp;
365400

366401
reg[3:0] state_0;
@@ -378,23 +413,15 @@ reg [15:0] indata_clk_count = 0;
378413

379414
reg [3:0] sd_state0 = 0;
380415

381-
reg [19:0] timer; // 27 times per second
416+
reg [19:0] timer; // 37 times per second
382417
always @(posedge clk) timer <= timer + 1;
383418

419+
// `define HID_REPORT
420+
384421
always@(posedge clk)begin
385422
state_0<={2'b0, loader_done};
386423
state_1<=state_0;
387424

388-
/*
389-
if (timer == 0) begin
390-
`print({joy_rx[0], joy_rx[1], joy_rx2[0], joy_rx2[1], nes_btn, nes_btn2}, 6);
391-
// `print({3'b0, sd_active, 3'b0, sd_total, sd_rsector, sd_last_sector}, 8);
392-
end
393-
if (timer == 20'b1000_0000_0000_0000_0000) begin
394-
`print("\n", STR);
395-
end
396-
*/
397-
398425
if (uart_demux.write)
399426
recv_packets <= recv_packets + 1;
400427

@@ -407,18 +434,46 @@ always@(posedge clk)begin
407434
end
408435
end
409436

410-
// if (sd_state != sd_state0) begin
411-
// if (sd_state == SD_READ_META) begin
412-
// `print("Reading SDcard\n", STR);
413-
// end
414-
// if (sd_state == SD_START_SECTOR) begin
415-
// if (sd_rsector[15:0] == 16'b0) begin
416-
// `print(sd_romlen, 3);
417-
// end else
418-
// `print(sd_rsector[15:0], 2);
419-
// end
420-
// sd_state0 <= sd_state;
421-
// end
437+
`ifdef HID_REPORT
438+
if (timer == 20'h00000)
439+
`print("hid=", STR);
440+
if (timer == 20'h10000)
441+
`print(dbg_hid_report, 8);
442+
if (timer == 20'h20000)
443+
`print(", vidpid=", STR);
444+
if (timer == 20'h30000)
445+
`print({dbg_vid, dbg_pid}, 4);
446+
if (timer == 20'h40000)
447+
`print(", dev=", STR);
448+
if (timer == 20'h50000)
449+
`print({4'b0, dbg_dev}, 1);
450+
if (timer == 20'h60000)
451+
`print(", ds2[2]=", STR);
452+
if (timer == 20'h70000)
453+
`print({joy_rx[0], joy_rx[1], joy_rx2[0], joy_rx2[1]}, 4);
454+
if (timer == 20'h80000)
455+
`print(", usb_btn[2]=", STR);
456+
if (timer == 20'h90000)
457+
`print({usb_btn, usb_btn2}, 2);
458+
459+
if (timer == 20'hf0000)
460+
`print("\n", STR);
461+
`endif
462+
463+
`ifdef PRINT_SD
464+
if (sd_state != sd_state0) begin
465+
if (sd_state == SD_READ_META) begin
466+
`print("Reading SDcard\n", STR);
467+
end
468+
if (sd_state == SD_START_SECTOR) begin
469+
if (sd_rsector[15:0] == 16'b0) begin
470+
`print(sd_romlen, 3);
471+
end else
472+
`print(sd_rsector[15:0], 2);
473+
end
474+
sd_state0 <= sd_state;
475+
end
476+
`endif
422477

423478
`ifdef COLOR_TRACING
424479
// print some color values
@@ -490,6 +545,7 @@ end
490545

491546
`endif
492547

493-
assign led = ~{~UART_RXD, loader_done};
548+
assign led = ~{~UART_RXD, usb_conerr, loader_done};
549+
// assign led = ~usb_btn;
494550

495551
endmodule

src/nes_tang20k.vh

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ localparam FREQ=27_000_000; // at least 10x baudrate
33
// localparam FREQ=37_800_000;
44

55
// UART baudrate: BAUDRATE <= FREQ/10
6+
// localparam BAUDRATE=115200;
67
localparam BAUDRATE=921600;
78

89
// define this to execute one NES cycle per 0.01 second and print the operation done

src/nestang.cst

+21
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,30 @@ IO_PORT "UART_TXD" IO_TYPE=LVCMOS33;
7171
//IO_LOC "UART_RXD" 31;
7272
//IO_PORT "UART_RXD" IO_TYPE=LVCMOS33 PULL_MODE=NONE;
7373

74+
// USB ports
75+
IO_LOC "usbdp" 42;
76+
IO_PORT "usbdp" PULL_MODE=DOWN IO_TYPE=LVCMOS33;
77+
IO_LOC "usbdm" 41;
78+
IO_PORT "usbdm" PULL_MODE=DOWN IO_TYPE=LVCMOS33;
79+
IO_LOC "usbdp2" 56;
80+
IO_PORT "usbdp2" PULL_MODE=DOWN IO_TYPE=LVCMOS33;
81+
IO_LOC "usbdm2" 54;
82+
IO_PORT "usbdm2" PULL_MODE=DOWN IO_TYPE=LVCMOS33;
83+
84+
// USB debug board
85+
//IO_LOC "usbdp" 41; // LCD_R4
86+
//IO_PORT "usbdp" PULL_MODE=DOWN IO_TYPE=LVCMOS33;
87+
//IO_LOC "usbdm" 42; // LCD_R3
88+
//IO_PORT "usbdm" PULL_MODE=DOWN IO_TYPE=LVCMOS33;
89+
//IO_LOC "clk_usb" 56; // for logic analyzer
90+
//IO_PORT "clk_usb" PULL_MODE=NONE IO_TYPE=LVCMOS33;
91+
92+
7493
// 2 LEDs for debug
7594
IO_LOC "led[1]" 16;
7695
IO_PORT "led[1]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
7796
IO_LOC "led[0]" 15;
7897
IO_PORT "led[0]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
7998

99+
100+
// pinout: https://wiki.sipeed.com/hardware/zh/tang/tang-nano-20k/assets/nano_20k/tang_nano_20k_pinlabel.png

src/nestang.sdc

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11

22
// NES clocks
3-
create_clock -name clk -period 37.04 [get_nets {clk}] // 27 Mhz
3+
create_clock -name clk -period 37.04 [get_nets {sys_clk}] // 27 Mhz
44
//create_generated_clock -name clk -source [get_nets {pclk}] -master_clock pclk -divide_by 3 [get_nets {clk}] // 32.25 Mhz
55

6+
// USB clock
7+
create_clock -name clk_usb -period 83.33 [get_nets {clk_usb}] // 12 Mhz
8+
69
// HDMI clocks
710
create_clock -name clk_p5 -period 2.6936 [get_nets {clk_p5}] // 371.25 Mhz
811
//create_generated_clock -name clk_p -source [get_nets {clk_p}] -master_clock clk_p5 -divide_by 5 [get_nets {clk_p}] // 74.25 Mhz: 720p pixel clock

0 commit comments

Comments
 (0)