散歩師・漫画居士のくだらなクラブ日記

ども、散歩師・漫画居士っす。散歩したり実働模型作ったりが趣味なんで、その時に思いついたこととか書くッス

SNES(スーパーファミコン)用パッドの IF回路 for FPGA

SNES(スーパーファミコン)用のパッド IFの RTLコードです。
FPGAにでも使ってください。(license:PDS)で

先週のファミコンパッド記事は珍しくアクセスがあったので(ほんのちょっとですが)
今週はスーファミ編です。

pin配置はこちらを参考に
SFC Development Wiki Controller : Controller Ports

SNES(スーパーファミコン)のパッドは、ファミコン同様電源GND+3本しか使ってません
なので、先週のファミコン用の回路を恐竜進化させるだけでOKでした。

Pin# pad FPGA
1 +5V <- +3.3V
2 clock <- SCK_o
3 Latch <- XLATCH_o
4 Data1 -> DAT_i
5 Data2 ->N.C.
6 IOBIt -> N.C.
7 GND <- 0V
丸い方を7pinとしています。

とりあえす REQ_i はHに釣ってください。
C_F_CKにはCK_EE_iの周波数を記載してください。
CK_EE_iをHに吊った場合は、clockの周波数を記述してください。
これで分周比を約1Mbps用に合わせます。

PADのICは、前期は3.0から8.0Vで動きますが、
中期以降はミツミのV520Bというカスタム品に変わってて、電源保証囲が分かりませんが
とりあえず供給した3.3Vでは動いてる様です。


ソースは以下。

// SNES_PAD_IF.v
//        SNES_PAD_IF()
// @manga_koji
//
//K5OuK7 :start SNES_PAD_IF base on NES_PAD_IF
//K59sK1 :ok maye...
//K51xxx :1st

`default_nettype none
module SNES_PAD_IF
#(    parameter C_F_CK = 135_000_000
)(    input tri1    CK_i
    , input tri1    XARST_i
    , input tri1    CK_EE_i
    , input tri0    REQ_i       //at level H
    , input tri1    DAT_i
    , output wire   XLATCH_o
    , output wire   SCK_o
    , output wire   B_o         //H:push
    , output wire   Y_o
    , output wire   SELECT_o
    , output wire   START_o
    , output wire   UP_o
    , output wire   DOWN_o
    , output wire   LEFT_o
    , output wire   RIGHT_o
    , output wire   A_o
    , output wire   X_o
    , output wire   L_o
    , output wire   R_o
) ;
    // log2() for calc bit width from data N
    // constant function on Verilog 2001
    function integer log2 ;
        input integer value ;
    begin  value = value - 1 ;
        for(log2=0 ; value>0 ; log2=log2+1)
            value = value>>1 ;
    end endfunction

    localparam C_F_PDIV_CK =  500_000 ;

    // mastar prescaler
    localparam C_PDIV_N = C_F_CK / C_F_PDIV_CK ;
    integer PCTRs ;
    wire PCTR_cy = &( PCTRs | (~(C_PDIV_N-1))) ;
    reg[11:0] REGs ;
    reg[4:0] PC ;
    reg      XLATCH  ;
    reg      SCK     ;
    always@(posedge CK_i or negedge XARST_i)
        if(~XARST_i) 
        begin                       PCTRs <= (C_PDIV_N-1) ;
                                        XLATCH <= 1'b1 ;
                                        SCK <= 1'b0 ;
                                        REGs <= ~0 ;
                                        PC<=0;
        end else if(CK_EE_i)
        begin
            PCTRs <= (PCTR_cy)? (C_PDIV_N-1) : (PCTRs + 1) ;
            if(PCTR_cy)
            begin
                PC <= PC + 1 ;
                case( PC )
                    0: begin //Idle
                            if( ~ REQ_i )
                            begin   SCK <= 1'b0 ;
                                        XLATCH <= 1'b1 ;
                                        PC<=PC ; //PAUSE
                            end else
                            begin   SCK  <= 1'b0 ;
                                        XLATCH <= 1'b0 ;
                                        PCTRs <= 0 ;
                                        PC <= 8 ;
                            end
                        end
                    8,10,12,14,16,18,20,22,24,26,28,30 :
                        begin       SCK  <= 1'b0 ;
                                        REGs[
                                          {   ~PC[4] ^ PC[3]
                                            , ~PC[3]
                                            , PC[2:1]
                                          }
                                        ] <= ~ DAT_i ;
                                        PCTRs <= 0 ;
                        end
                    9,11,13,15,17,19,21,23,25,27,29:
                        begin       SCK  <= 1'b1 ;
                                        PCTRs <= 0 ;
                        end
                    31: begin      XLATCH <= 1'b1 ;
                                        PCTRs <= 0 ;
                                        PC <= 0 ;
                        end
                    default : 
                        begin       XLATCH <= 1'b1 ;
                                        SCK <= 1'b0 ;
                                        PC<=0;
                        end
                endcase
            end
        end
    assign SCK_o = SCK ;
    assign XLATCH_o = XLATCH ;
    assign {
          R_o
        , L_o
        , X_o
        , A_o
        , RIGHT_o
        , LEFT_o
        , DOWN_o
        , UP_o
        , START_o
        , SELECT_o
        , Y_o
        , B_o
        } = REGs 
    ;
endmodule
//SNES_PAD_IF()

enjoy! make ;-)