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

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

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

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

pin配置はこちらを参考に
NES DEV controller port pin out

NESファミコン本体パッド P1、ファミコン本体外付けPADはpin配置が異なるだけで
同じ回路がつ変えます。
pad FPGA
GND <- 0V

  1. 5V <- +3.3V

CLK <- SCK_o
OUT <- XLATCH_o
D0 -> DAT_i
D4 ->N.C.
D3 -> N.C.

とりあえす REQ_i はHに釣ってください。
C_F_CKにはclock/CK_EE_iの周波数を設定してください。
1Mbpsに合わせます。

PADのICは3.0から8.0Vで動くので、FPGAのポート耐圧に合わせてください。

// NES_PAD_IF.v
//  NES_PAD_IF()
// @manga_koji
//2020-05-13we
//K59sK1 :ok maybe...
//K51xxx :1st

`default_nettype none
`include "../MISC/define.vh"
module NES_PAD_IF
#(    
       `p C_DBG_ACC = 0
    ,  `p C_F_CK = 135_000_000
)(    
      `in `tri1             CK_i
    , `in `tri1             XARST_i
    , `in `tri1             CK_EE_i
    , `in `tri0             REQ_i       //at level H
    , `in `tri1             DAT_i
    , `out `w               XLATCH_o
    , `out `w               SCK_o
    , `out `w               A_o         //H:push
    , `out `w               B_o         //H:push
    , `out `w               SELECT_o    //H:push
    , `out `w               START_o     //H:push
    , `out `w               UP_o        //H:push
    , `out `w               DOWN_o      //H:push
    , `out `w               LEFT_o      //H:push
    , `out `w               RIGHT_o     //H:push
)  ;
    // log2() for calc bit width from data N
    // $clog2() is same constant function on Verilog 2001
    `func `int log2 ;
        `in `int value ;
    `b  value = value - 1 ;
        for(log2=0 ; value>0 ; log2=log2+1)
            value = value>>1 ;
    `e `efunc

    `lp C_F_PDIV_CK     = (C_DBG_ACC)? C_F_CK/4 : 500_000 ;

    // mastar prescaler
    `lp C_PDIV_N = C_F_CK / C_F_PDIV_CK ;
    `int PCTRs ;
    `w PCTR_cy = &( PCTRs | (~(C_PDIV_N-1))) ;
    `r[7:0] REGs ;
    `r[4:0] PC ;
    `r      XLATCH  ;
    `r      SCK     ;
    `ack
        `xar `b                     PCTRs <= (C_PDIV_N-1) ;
                                    XLATCH <= 1'b1 ;
                                    SCK <= 1'b0 ;
                                    REGs <= ~0 ;
                                    PC<=0;
        `e else `cke
        `b
            PCTRs <= (PCTR_cy)? (C_PDIV_N-1) : (PCTRs + 1) ;
            if(PCTR_cy)
            `b
                PC <= PC + 1 ;
                case( PC )
                    0:
                        `b //Idle
                            if( ~ REQ_i )
                            `b          SCK <= 1'b0 ;
                                        XLATCH <= 1'b1 ;
                                        PC<=PC ; //PAUSE
                            `e else
                            `b          SCK  <= 1'b0 ;
                                        XLATCH <= 1'b0 ;
                                        PCTRs <= 0 ;
                                        PC <= 8 ;
                            `e
                        `e
                    8,10,12,14,16,18,20,22 :
                        `b              SCK  <= 1'b0 ;
                                        REGs[{PC[3],~PC[2:1]}] <= ~ DAT_i ;
                                        PCTRs <= 0 ;
                        `e
                    9,11,13,15,17,19,21:
                        `b           SCK  <= 1'b1 ;
                                    PCTRs <= 0 ;
                        `e
                    23: `b        XLATCH <= 1'b1 ;
                                    PCTRs <= 0 ;
                                    PC <= 0 ;
                        `e
                    default : 
                        `b          XLATCH <= 1'b1 ;
                                    SCK <= 1'b0 ;
                                    PC<=0;
                        `e
                `ecase
            `e
        `e
    `a SCK_o = SCK ;
    `a XLATCH_o = XLATCH ;
    `a {
          A_o      
        , B_o      
        , SELECT_o 
        , START_o  
        , UP_o     
        , DOWN_o   
        , LEFT_o   
        , RIGHT_o  
        } = REGs 
    ;
endmodule


こちらはコマンド短縮用のマクロ。パスの通る場所においてください。

// ../MISC/define.vh
//@manga_koji
//2020-05-13we
    `define ack always@(posedge CK_i or negedge XARST_i)
    `define sck always@(posedge CK_i)
    `define xar if(~XARST_i)
    `define xsr if(~XSRST_i)
    `define cke if(CK_EE_i)
    `define b   begin
    `define C   begin
    `define e   end
    `define J   end
    `define D   end
    `define a   assign
    `define func function
    `define efunc endfunction
    `define s   signed
    `define Ds  $signed
    `define in  input
    `define out output
    `define io inout
    `define w   wire
    `define r   reg
    `define int integer
    `define gen generate
    `define egen endgenerate
    `define gv genvar
    `define p   parameter
    `define param parameter
    `define lp  localparam
    `define pe  posedge
    `define ne  negedge
    `define rep repeat
    `define init initial
    `define al always
    `define elif else if
    `define ecase endcase
    `define emodule endmodule
    `ifdef TANG_FPGA
        `define tri0 wire
        `define tri1 wire
    `else
        `define tri0 tri0
        `define tri1 tri1
    `endif

enjoy! make ;-)