Skip to content

JCAP Log #5: Input

Connor Spangler edited this page Apr 25, 2018 · 2 revisions

Arcade Controls

Arcade Controls

Every arcade game needs a way for the user to actually interact with it, through the use of joysticks and buttons and trackballs and steering wheels and more. Based on the JAMMA connector, I've decided to implement ALL of the possible basic user controls for player 1 and player 2: joystick up, down, left, and right, start button, and buttons 1, 2, and 3. This means 16 controls total, which conveniently enough fits perfectly into a 16-bit WORD on the Propeller. The state of service, tilt, and test switches will also need to be queried, with their values likely going into a status register. For now we'll ignore these and focus on strictly the player controls. But with 16 inputs, assigning a Propeller pin to each one would mean losing half of the GPIO pins to just input. This won't do, with video and sound and other peripheral interfaces still to be added. Therefore I'm taking a leaf out of Nintendo's book and emulating the Nintendo Entertainment System's (NES) input system. The controller takes the 8 button inputs, loads them into a parallel-to-serial shift register, and sends them out to the NES one-by-one. This means the difference between 16 pins and as few as 3!


Inside of NES Controller

Inside of NES Controller - Notice the Shift Register IC

The 74HC165

In order to send the control input states to the Propeller, I decided on the 74HC165 asynchronous 8-bit parallel-to-serial shift register. It can be daisy-chained to extend the number of bits it can serialize without taking up more pins on the Propeller. The only ones needed are a clock, active-low parallel load, and output pin. The 74HC165 also has an active-low clock enable input, however this can simply be pulled low on the board. It operates by pulling the parallel load pin low to latch the signals on its data pins into an internal shift register, and then shifting them out one by one each time there's a rising edge on the clock pin. At the same time, bits are shifted into the register from the serial data input pin, allowing the ICs to be daisy-chained. Thanks to the very simple behavior of the 74HC165, it's easy to emulate via a verilog module. Therefore I decided to create one and connect a couple to the Propeller design on the FPGA to allow me to create a PASM routine to query them.


74HC165

75HC165 Shift Register

The Verilog Model

The resulting verilog code is relatively trivial. Using a simple testbench, two 74HC165s were connected, dummy data was loaded into each, and then parallel load and clock signals were applied to poll the units. The following waveform was produced proving the accuracy of the models with the test inputs 1010101010101010 (several more were used however they are not shown here). Note the parallel load going low to latch the test inputs:


74HC165 Verilog Model Waveform

74HC165 Verilog Model Waveform

With the accuracy of the verilog model verified, it was time to connect it to the Propeller on the FPGA.

Integrating the Model

To test the design with the Propeller, an include file was generated from the 74HC165.v model and was used to instantiate two of the units in the P8X32A top-level AHDL top.tdf file via the Quartus Prime IDE. Then all that had to be done was connect the appropriate pins of the virtual 74HC165s to the Propeller and DE0-Nano GPIO pins, compile and synthesize the design, and load it onto the DE0-Nano's EEPROM. In this configuration, power-cycling the board will always result in the Propeller model with attached 74HC165s being loaded onto the FPGA. Next came getting the Propeller to generate the right signals and interact with the shift registers to poll the user inputs. This was a relatively simple exercise in PASM, to generate the clock and parallel load pin signals and reading the resulting state of the output pin.

A proof-of-concept feature was implemented in the code as well: polling an extra input, in this case a tilt sensor, by connecting it to the serial data input pin of the first 74HC165. This essentially gave me an extra bit to be able to shift in, for a total of 17. Additionally, the code performs the task of storing the input and tilt states into an address in Main RAM for use by game logic in other cogs. Using an Analog Discovery logic analyzer, the same test input (1010101010101010) was applied with the addition of a high tilt sensor input on the end, resulting in the following waveform:


74HC165 FPGA Waveform

74HC165 FPGA Waveform

Notice how this and the verilog simulation waveform are practically identical, showcasing the value and accuracy of verilog simulation and FPGA development. To verify that the values were being stored in and could be retrieved from Main RAM by other cogs, a small testing routine was written to display the state of the user inputs on the DE0-Nano's 8 LEDs (only the first 8 of the 16 input bits were displayed, with a feature added to switch to displaying the status register where the tilt state was stored). This test confirmed that the input system worked perfectly, and could now be used to provide user inputs to any other code running on the Propeller:


DE0-Nano LEDs Displaying User Inputs

DE0-Nano LEDs Displaying User Inputs