├── .gitignore ├── docs ├── SegaPad.png └── Interface Protocol of SEGA MegaDrive's 6-Button-Controller.pdf ├── README.md ├── LICENSE └── src ├── smdsixbutton_tb.v └── smdsixbutton.v /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.out 3 | *.vvp 4 | *.vcd 5 | -------------------------------------------------------------------------------- /docs/SegaPad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootsector/smd-sixbutton-encoder/HEAD/docs/SegaPad.png -------------------------------------------------------------------------------- /docs/Interface Protocol of SEGA MegaDrive's 6-Button-Controller.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootsector/smd-sixbutton-encoder/HEAD/docs/Interface Protocol of SEGA MegaDrive's 6-Button-Controller.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # smd-sixbutton-encoder 2 | Sega Genesis/Mega Drive controller encoder in Verilog 3 | 4 | This is a full implementation of a 6 button Sega Genesis controller in Verilog. 5 | 6 | It features: 7 | 8 | - Full support to the 6 button protocol, including timeout feature for the SEL signal 9 | - Full support to the 3 button protocol if started with MODE button state as LOW 10 | 11 | Tested with an Altera EPM7064SLC44-10N CPLD. 12 | 13 | This is perfect to be used on custom Sega Genesis controllers without having to mess with pad-hacks! 14 | 15 | This is a FREE implementation licensed under MIT license. 16 | 17 | Let me know about your cool projectes featuring this implementation. Enjoy! 18 | 19 | bootsector 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 bootsector 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/smdsixbutton_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 100ps // time-unit = 1 ns, precision = 100 ps 2 | module smdsixbutton_tb; 3 | // Inputs 4 | reg p7; // Clock from Sega Mega Drive 5 | reg up; // Up button 6 | reg dw; // Down button 7 | reg lf; // Left button 8 | reg rg; // Right button 9 | reg a; // A button 10 | reg b; // B button 11 | reg c; // C button 12 | reg st; // Start button 13 | reg x; // X button 14 | reg y; // Y button 15 | reg z; // Z button 16 | reg md; // Mode button 17 | reg hm; // Home button 18 | 19 | reg clk = 1'd0; 20 | 21 | integer j, k; 22 | 23 | // Outputs 24 | wire [5:0] p; 25 | 26 | // Instantiate the Unit Under Test (UUT) 27 | smdsixbutton joystick ( 28 | .p7(p7), 29 | .up(up), 30 | .dw(dw), 31 | .lf(lf), 32 | .rg(rg), 33 | .a(a), 34 | .b(b), 35 | .c(c), 36 | .st(st), 37 | .x(x), 38 | .y(y), 39 | .z(z), 40 | .md(md), 41 | .clk(clk), 42 | .hm(hm), 43 | 44 | .p(p) 45 | ); 46 | 47 | //always #50 clk <= !clk; // 20Mhz 48 | always #100 clk <= !clk; // 10Mhz 49 | 50 | initial begin 51 | $timeformat(-3, 2, " ms", 10); 52 | $dumpfile("smdsixbutton.vcd"); 53 | $dumpvars(0, joystick); 54 | 55 | // Initialize Inputs 56 | up = 0; 57 | dw = 1; 58 | lf = 1; 59 | rg = 1; 60 | a = 1; 61 | b = 1; 62 | c = 1; 63 | st = 1; 64 | x = 1; 65 | y = 0; 66 | z = 1; 67 | md = 1; 68 | hm = 1; 69 | 70 | p7 = 1; 71 | 72 | #1660000 $display("delay"); 73 | 74 | for(j = 0; j < 20; j=j+1) begin 75 | #13000 p7 = 0; 76 | #13000 p7 = 1; 77 | #13000 p7 = 0; 78 | #13000 p7 = 1; 79 | #13000 p7 = 0; 80 | #13000 p7 = 1; 81 | #13000 p7 = 0; 82 | #13000 p7 = 1; 83 | #1660000 $display("delay"); 84 | end 85 | 86 | $finish(); 87 | end 88 | 89 | initial begin 90 | $monitor("p7=%d,p1=%d,p2=%d,p3=%d,p4=%d,p6=%d,p9=%d,time=%t \n",p7,p[5],p[4],p[3],p[2],p[1],p[0],$time); 91 | end 92 | 93 | endmodule -------------------------------------------------------------------------------- /src/smdsixbutton.v: -------------------------------------------------------------------------------- 1 | /* 2 | Verilog Sega Genesis/Mega Drive Joystick Encoder v2.5 3 | (C) Bruno Freitas - 03/2019 - http://www.brunofreitas.com/ 4 | Released under MIT License. 5 | */ 6 | 7 | module smdsixbutton ( 8 | input clk, 9 | input p7, // DB9_PIN7 (SEL) 10 | output reg [5:0] p = 6'b111111, // {DB9_PIN1, DB9_PIN2, DB9_PIN3, DB9_PIN4, DB9_PIN6, DB9_PIN9} 11 | input up, // Up button 12 | input dw, // Down button 13 | input lf, // Left button 14 | input rg, // Right button 15 | input a, // A button 16 | input b, // B button 17 | input c, // C button 18 | input st, // Start button 19 | input x, // X button 20 | input y, // Y button 21 | input z, // Z button 22 | input md, // Mode button 23 | input hm // Home button (Analogue Mega Sg) 24 | ); 25 | 26 | parameter TIMEOUT = 14'd8000; // For 10Mhz oscillator 27 | //parameter TIMEOUT = 14'd16000; // For 20Mhz oscillator 28 | 29 | reg [13:0] clk_counter = TIMEOUT; 30 | 31 | reg [1:0] hi_count = 2'b0; 32 | 33 | reg mode_set = 1'b0; 34 | reg three_button_mode = 1'b0; 35 | 36 | reg last_p7_1 = 1'b0; 37 | reg last_p7_2 = 1'b0; 38 | 39 | always @(posedge clk) begin 40 | last_p7_1 <= p7; 41 | last_p7_2 <= last_p7_1; 42 | 43 | if(!mode_set) begin 44 | three_button_mode <= !md; 45 | mode_set <= 1'b1; 46 | end 47 | 48 | if(!three_button_mode) begin 49 | if (clk_counter == 0) begin 50 | $display("Reset!"); 51 | clk_counter <= TIMEOUT; 52 | hi_count <= 0; 53 | end else begin 54 | if (last_p7_1 && !last_p7_2) begin 55 | hi_count <= hi_count + 2'b1; 56 | clk_counter <= TIMEOUT; 57 | end else begin 58 | clk_counter <= clk_counter - 2'b1; 59 | end 60 | end 61 | end 62 | end 63 | 64 | always @(*) begin 65 | $display("hi_count=%d", hi_count); 66 | case ({hi_count, last_p7_2}) 67 | 3'b000: p = {up, dw, 1'b0, 1'b0, a, st}; 68 | 3'b001: p = {up, dw, lf, rg, b, c}; 69 | 3'b010: p = {up, dw, 1'b0, 1'b0, a, st}; 70 | 3'b011: p = {up, dw, lf, rg, b, c}; 71 | 3'b100: p = {1'b0, 1'b0, 1'b0, 1'b0, a, st}; 72 | 3'b101: p = {up, dw, lf, rg, b, c}; 73 | 3'b110: p = {hm, 1'b1, 1'b1, 1'b1, a, st}; 74 | 3'b111: p = {z, y, x, md, 1'b1, 1'b1}; 75 | endcase 76 | end 77 | 78 | endmodule 79 | --------------------------------------------------------------------------------