<< INTRODUCTION >>


<< OVERVIEW >>


<< AUDIO >>


<< GAMEPLAY >>


<< VIDEO >>


<< IMPROVEMENTS >>


<< ZBT RAMS >>


<< TIPS AND TRICKS >>


<< NES INPUT FSM >>


<< TOOLS >>


Appendix: NES Input FSM

/*
       NINTENDO CONTROLLER INPUT FSM
       The NES controller connects to the system via 5 wires.
       2 wires are power and ground
       The others are latch, pulse and data.
       Latch and pulse are signals from the FSM to the controller.
       Data is a signal from the controller to the FSM.
       
       The data read process starts on the gameclock signal.
       The data protocol (exactly as used by Nintento itself) is as follows:
       1. FSM sends latch signal high for 12 us to controller (LATCH)
       2. "A" button data (high or low) is ready on data line (READ_A)
       3. FSM waits 6 us (WAIT)
       4. FSM sends pulse signal high for 6 us to controller (PULSE)
       5. "B" button data (high or low) is ready on data line (READ_B)
       6. Repeat steps 3-5 for (in order):
              select button        (READ_SELECT)
              start button         (READ_START)
              up button                  (READ_UP)
              down button          (READ_DOWN)
              left button          (READ_LEFT)
              right button         (READ_RIGHT)
       For each WAIT-PULSE sequence, the return read state is stored in returnstate.
       Output data is registered with the 27 MHz clock before passing it on.
*/
 
module gameinput(clock, gameclock, reset, latch, pulse, data, plyr_input);
       input clock, gameclock, reset, data;
       output latch, pulse;
       reg latch, latch1, pulse, pulse1, data1;
       output [7:0] plyr_input;
       
       reg left, right, up, down, A, B, select, start;
       reg left1, right1, up1, down1, A1, B1, select1, start1;
       assign plyr_input = {left, right, up, down, A, B, select, start};              

       reg [3:0] state, nextstate, returnstate, nextreturnstate;
       reg [11:0] count, nextcount; 

       parameter INIT = 0;
       parameter IDLE = 1;
       parameter LATCH = 2;
       parameter WAIT = 3;
       parameter PULSE = 4;
       parameter READ_A = 5;
       parameter READ_B = 6;
       parameter READ_SEL = 7;
       parameter READ_STRT = 8;
       parameter READ_UP = 9;
       parameter READ_DOWN = 10;
       parameter READ_LEFT = 11;
       parameter READ_RIGHT = 12;

       parameter TWELVE_US = 12'h144;    //count for 12 us on a 27 MHz clock
       parameter SIX_US = 12'h0A2; //count for 6 us on a 27 MHz clock
 
       always @ (posedge clock)
       begin
              if (!reset) begin
                     state <= INIT;
                     returnstate <= INIT;
                     count <= 0;
              end    
              else   begin
                     state <= nextstate;
                     returnstate <= nextreturnstate;
                     count <= nextcount;
              end

              data1 <= data;
              latch <= latch1;
              pulse <= pulse1;
              left <= left1;
              right <= right1;
              up <= up1;
              down <= down1;
              A <= A1;
              B <= B1;
              select <= select1;
              start <= start1;
       end
 
       always @ (state or returnstate or count or gameclock or data1)
       begin
              //defaults
              nextstate = state;
              nextreturnstate = returnstate;
              nextcount = count;
              latch1 = latch;
              pulse1 = pulse;
              left1 = left;
              right1 = right;
              up1 = up;
              down1 = down;
              A1 = A;
              B1 = B;
              select1 = select;
              start1 = start;
 
              case (state)
              INIT:
              begin
                     nextstate = IDLE;
                     nextcount = 0;
              end
              IDLE:
              begin
                     nextcount = 0;
                     //get input at input rate specified by game clock
                     if (gameclock)             nextstate = LATCH;
              end
              LATCH:
              begin
                     //latch 12 us, then go to read A
                     latch1 = 1;
                     if (count == TWELVE_US) begin
                           nextcount = 0;
                           latch1 = 0;
                           nextstate = READ_A;
                     end
                     else   nextcount = count + 1;
              end
              WAIT:
              begin
                     //wait 6 us, then go to pulse
                     if (count == SIX_US) begin
                           nextcount = 0;
                           nextstate = PULSE;

                     end
                     else   nextcount = count + 1;
              end
              PULSE:

              begin
                     //pulse 6 us, then go to returnstate and read data
                     pulse1 = 1;
                     if (count == SIX_US) begin
                           nextcount = 0;
                           pulse1 = 0;

                           nextstate = returnstate;

                     end

                     else   nextcount = count + 1;

              end

              READ_A:

              begin

                     A1 = ~data1;

                     nextreturnstate = READ_B;

                     nextstate = WAIT;

              end

              READ_B:

              begin

                     B1 = ~data1;

                     nextreturnstate = READ_SEL;

                     nextstate = WAIT;

              end

              READ_SEL:

              begin

                     select1 = ~data1;

                     nextreturnstate = READ_STRT;

                     nextstate = WAIT;

              end

              READ_STRT:

              begin

                     start1 = ~data1;

                     nextreturnstate = READ_UP;

                     nextstate = WAIT;

              end

              READ_UP:

              begin

                     up1 = ~data1;

                     nextreturnstate = READ_DOWN;

                     nextstate = WAIT;

              end

              READ_DOWN:

              begin

                     down1 = ~data1;

                     nextreturnstate = READ_LEFT;

                     nextstate = WAIT;

              end

              READ_LEFT:

              begin

                     left1 = ~data1;

                     nextreturnstate = READ_RIGHT;

                     nextstate = WAIT;

              end

              READ_RIGHT:

              begin

                     right1 = ~data1;

                     nextstate = IDLE;

              end

 

              endcase

       end

 

endmodule