I HAS SKILLS

Published March 08, 2008
Advertisement
Well, it's been a while since my last entry, so I figured I should spend the day getting back into my project. I was still trying to figure out to connect the damn NES controllers to the rest of the project. After scratching my head for a bit, I decided to solder them back into the Four Score and then doing some general mangling of the circuit board to make it do what I wanted. I soldered in a few jumpers, ripped out the turbo buttons, ripped out a few resistors, capacitors, the main Four Score processor, and the output wire, and ended up with this:



As you can see from the well placed and stylish ON/OFF labels, I have converted the selector switch into an On/Off switch for my system. The extended leads are easily pluggable into the breadboard system, so my task has been completed.

Next, I have to actually read the damn thing. Fortunately, there is tons of information on how the NES controllers work, and even some sample code on the Parallax forums that I could investigate and play with.

After a little experimenting to see what did what, I ended up with the following gamepad driver code:

CON       IO_JOY_CLK       = %00001000      IO_JOY_SHLDn     = %00010000      IO_JOY_DATAOUT0  = %00100000  IO_JOY_DATAOUT1  = %01000000      NES_LATCH_DELAY  = $40  NES_RIGHT  = %00000001  NES_LEFT   = %00000010  NES_DOWN   = %00000100  NES_UP     = %00001000  NES_START  = %00010000  NES_SELECT = %00100000  NES_B      = %01000000  NES_A      = %10000000  NES0_RIGHT  = %00000000_00000001  NES0_LEFT   = %00000000_00000010  NES0_DOWN   = %00000000_00000100  NES0_UP     = %00000000_00001000  NES0_START  = %00000000_00010000  NES0_SELECT = %00000000_00100000  NES0_B      = %00000000_01000000  NES0_A      = %00000000_10000000  NES1_RIGHT  = %00000001_00000000  NES1_LEFT   = %00000010_00000000  NES1_DOWN   = %00000100_00000000  NES1_UP     = %00001000_00000000  NES1_START  = %00010000_00000000  NES1_SELECT = %00100000_00000000  NES1_B      = %01000000_00000000  NES1_A      = %10000000_00000000VAR  long  cogon, cog  long  nes_bits_parm       ' local storage for NES state/bitsPUB start : okay'' Start the NES gamepad reading process'' returns false if no cog available''  stop  okay := cogon := (cog := cognew(@NES_Read_Gamepad_ASM_Entry, @nes_bits_parm)) > 0PUB stop'' Stops driver - frees a cog  if cogon~    cogstop(cog)PUB read'' Reads the NES state and sends it back to caller  return(nes_bits_parm)PUB button(nes_button)'' Return TRUE/FALSE if sent button is down  return(nes_button & nes_bits_parm)DATorg $000NES_Read_Gamepad_ASM_Entry        ' step 1: set I/Os,         or  DIRA, #(IO_JOY_CLK | IO_JOY_SHLDn)          ' JOY_CLK and JOY_SH/LDn to outputs        and DIRA, #(!(IO_JOY_DATAOUT0 | IO_JOY_DATAOUT1)) & $1ff ' JOY_DATAOUT0 and JOY_DATAOUT1 to inputs        NES_Latchbits        ' step 2: set latch and clock to 0        and OUTA, #(!(IO_JOY_CLK | IO_JOY_SHLDn)) & $1ff ' JOY_CLK = 0, JOY_SH/LDn = 0        ' initialize counter and delay to let NES settle        mov _counter, CNT        add _counter, #NES_LATCH_DELAY        waitcnt _counter, #NES_LATCH_DELAY                ' step 3: set latch to 1        or OUTA, #(IO_JOY_SHLDn) ' JOY_SH/LDn = 1        ' initialize counter and delay to let NES settle        mov _counter, CNT        add _counter, #NES_LATCH_DELAY        waitcnt _counter, #NES_LATCH_DELAY                                             ' step 4: set latch to 0        and OUTA,#(!(IO_JOY_SHLDn) & $1ff) ' JOY_SH/LDn = 0        ' clear gamepad storage word        xor _nes_bits, _nes_bits        ' step 5: read 8 bits, 1st bits are already latched and ready, simply save and clock remaining bits        mov _index, #8NES_Getbits_Loop        shl _nes_bits, #$1 '             ' shift results 1 bit to the left each time                mov _nes_gamepad0, INA           ' read all 32-bits of input including gamepads        mov _nes_gamepad1, _nes_gamepad0 ' copy all 32-bits of input including gamepads        ' now extract bits from inputs        and _nes_gamepad0, #(IO_JOY_DATAOUT0)        and _nes_gamepad1, #(IO_JOY_DATAOUT1)        ' shift bits into place, so that gamepad0 bits fall into bit 0 of 16-bit result and gamepad1 bits fall into bit 8 of 16-bit result        ' then continuously shift the entire result until every buttons has been shifted into position from both gamepads        shr _nes_gamepad0, #5        shl _nes_gamepad1, #2        ' finally OR results into accumulating result/sum        or _nes_bits, _nes_gamepad0        or _nes_bits, _nes_gamepad1        ' pulse clock...        or OUTA, #%00001000 ' JOY_CLK = 1        ' initialize counter and delay to let NES settle        mov _counter, CNT        add _counter, #NES_LATCH_DELAY        waitcnt _counter, #NES_LATCH_DELAY                and OUTA,#%11110111 ' JOY_CLK = 0        ' initialize counter and delay to let NES settle        mov _counter, CNT        add _counter, #NES_LATCH_DELAY        waitcnt _counter, #NES_LATCH_DELAY        djnz _index, #NES_Getbits_Loop        ' END NES_getbits_loop        ' invert bits to make positive logic        xor _nes_bits, _MAXINT        ' mask lower 16-bits only        and _nes_bits, _NES_GAMEPAD_MASK        ' finally write results back out to caller        wrlong _nes_bits, par ' now access main memory and write the value        ' continue looping...        jmp #NES_Latchbits_MAXINT                 long                    $ffff_ffff                      ' 32-bit maximum value constant_NES_GAMEPAD_MASK       long                    $0000_ffff                      ' mask for NES lower 16-bits _nes_bits               long                    $0                              ' storage for 16 NES gamepad bits (lower 16-bits)_nes_gamepad0           long                    $0                              ' left gamepad temp storage_nes_gamepad1           long                    $0                              ' right gamepad temp storage_index                  long                    $0                              ' general counter/index_counter                long                    $0                              ' general counter


Using this, I set up a simple tester program that would let me see the state of all the buttons visually. I downloaded the nice PropTerminal program, which talks to a Propeller hooked up through a USB port and reports any textual video information to the screen. That way I didn't need a real TV to hook up with.

Here is the result of the gamepad test (Note: I'm holding down the B and Up buttons on the first controller).



Not bad for a day's work. So I finally have some reliable input. Next step is graphical output to a TV, and from there, any game I want to make is up for grabs.

I have a few ideas of the first few games I want to make. I'm thinking of Pong as my first, since it's such a classic. After that, it's not as clear. I could go with Pac Man or Defender or Robotron, or maybe even asteroids. There are simply tons of cool old games that would be a blast to recreate. If anyone has any ideas for a great game, let me hear 'em!

On a final note, I started thinking seriously about the next step the project will take. The breadboard is nice for quick prototyping, but I need something more stable and more permanent. I found EAGLE, a freeware schematic diagramming application that seems to be highly recommended. Couple a board design from there and the cheap pricing of Batch PCB and I may be able to go with a custom PCB for a tidier solution.

Thoughts or comments? Let me hear 'em!
Previous Entry Running out of time
Next Entry Help Wanted
0 likes 1 comments

Comments

brandonman
Hey, I've been building robots on and off for a year, and have a fair handle on electronics, and a kind of "Meh" one on microcontrollers. I have a few atemga8's laying around and have been interested in building my own console for a long time. I'm thinking of having 3 or 4 Atmega's, one controlling input. Then, I would somehow arrange the screen into 64 pixels (large blocks) and the programmer for the game just decides how to use these pixels to make something. As in, if you had pong, you would have 3 or 4 turned on on each side, and if the up was pressed, the paddle's top would be moved up 1 pixel, and the same for the bottom. I need to figure out a way to interface to a TV though, or use an LED matrix, which would seem to be expensive and time-consuming. I also need to think of how I'm going to link up the atmega's. Do you have any ideas?
March 15, 2008 10:43 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement

Latest Entries

New Blog

1999 views

Progress Update

1544 views

Start of Project

1512 views

New Job

2193 views

The Downward Spiral

2851 views

Job Interviews

1456 views
Advertisement