Tuesday, August 21, 2018

Apple II 4joy - Serial interfacing through the game port

The Apple II 4Joy is an adapter that lets you connect four digital joysticks to the Apple II via the game port.

In my last blog I looked at running a digital joystick interface via the IIc's serial port. Technically I wasn't correct in saying that the serial interface is the only available option for communication on the IIc. Obviously there are other options such as the floppy disk interface, the keyboard interface and the game port interface but these are most likely already being used for dedicated functions. The game port however can be used for general communications but it's only unidirectional. In our case this is enough to get by on. I evaluated a few methods of communicating using this interface.

Method 1: The first method I looked into involved transferring a byte of information by generating a resistive circuit that mimics an Apple II paddle / joystick axis. This could be done by outputting eight digital lines from the microcontroller and switching parts of a resistive ladder to form the zero to 150k ohm resistance range needed by the Apple II. Alternately an extra chip such as the AD5206 could be used to generate the resistance. This method would require multitasking to put through four digital joystick status bytes over the IIc's only two paddle lines and each Apple II would need to be tuned because the game port's analog circuit contains discrete components that vary slightly from one machine to another. The other factor is that reading analog values via the Apple IIs games port is very slow. Even if the format is modified to be limited to a low analog value I estimate it would still take about 2000 microseconds to read, process and store the four joystick status values. This method is not preferred for serial data communications.

Method 2: This method involves running digital signals though the analog paddle lines. Each analog port would be reduced to a value of zero ("False") and non-zero ("True"). Reading an analog value from the paddle port takes about 4 microseconds if the value is zero all the way up to about 3000 microseconds if the value is 255. If the data is digital then we can read the port after 4 microseconds and get an answer straight away. This translates into a transfer rate of about 200 microseconds per byte instead of up to 3000. Most Apple IIs have four paddle lines (PDL0, PLD1, PDL2 and PLD3) so we could send though a nibble of data at a time (this is not as great as it sounds because you still need to read each bit at a time). The push button lines could be used to handle the synchronisation. The software would require some overheads in putting the two nibbles and the format back together but this would be straight forward. The hardware would require something like a 4066 chip to switch each analog port from 0k resistance to about 1.5k or greater. This should result in enough time to read all four analog ports and determine if each is "True" or "False". The IIc however does not have PDL2 and PLC3 lines. These were removed to make way for the mouse interface. Instead these lines are TTL compatible digital input lines (XDIR and YDIR). We don't need to change our method by much because we are already dealing with digital signals. The only change needed would be to add a toggle switch which allows the microcontroller to connect to XDIR and YDIR directly on the IIc or to the 4066 chip for non-IIc Apples. The result of all this would be to have all four joystick status bytes sent over in about 1000 microseconds. This is not a bad solution but can we do better? 

Method 3: The last method I looked at was to send a serial stream of bits though the game port's push button lines. One push button would be used for data and the other would be used for synchronisation. It's unlikely that the microcontroller's clock rate will be a direct multiple of the Apple II's clock rate so synchronisation needs to happen quite often, possible once every byte. A byte could be sent through in under 100 microseconds. The software would be relatively simple (simpler than the above methods). The routine to do the synchronisation, data transfer, processing and storage would not be as compact as running data through the serial port but should result in a much faster transfer rate. With this setup the hardware becomes simple too. Only the microcontroller is needed and a few discrete components. The result of all this is being able to transfer the four joystick status bytes in around 500 microseconds.

Once I looked at method three it was clear that this was going to be the best option to tackle. A good amount of the work was already done in the serial port project so I reused as much as I could. In terms of hardware the TTL to RS232 converter was removed and in its place I added a small breadboard with the DE9 pin plug, some discrete components and some headers for testing. This project was all about getting the software right which meant timing was critical and counting cycles on the Apple II as well as the microcontroller was needed.

Showing microcontroller output is too fast and then after delays have been added.

The first step was to write the fastest read loop on the Apple II. After obtaining a few pointers from Michael's NadaNet project, I was able to nut this out. This was going to be the bottle neck since the microcontroller was capable of outputting data much quicker than the Apple II could read it. The microcontroller code was written to stream a sync signal followed by an eight bit byte for each joystick. The dilemma now was how to view what the microcontroller was outputting and compare that to when the Apple II was expecting a read. The timing was sub-microsecond critical and the Apple II was reading (inputting) signals and not outputting them. The easiest thing to do was to move the development from the Apple IIc over to the Apple IIe. What this allowed me to do was to take a copy of the code, change the read instructions into write instructions but at the same time keep the cycle timing the same. These write instructions were then sent to the IIe's 16pin game port output (annunciator) pin. By adding this output to the logic analyser I was able so see exactly when the Apple II was going to be performing a read operation. I could then tune the microcontroller outputs to match the requirements of the Apple II.

Since the joystick number was going to be extracted from the data (just like in the serial port version) there was no need to synchronise starting at a specific byte. So long as four bytes were read in a row it did not matter which joystick status byte was read first.

In tuning the interface there were several critical points to get right:

1. Apple II read pulse length.

To get the microcontroller to match the Apple II, read pulse lengths measurements from the logic analyser were used and delays were added in the appropriate places. The faster the microcontroller can be run the more resolution is available to match the Apple II. Since one speed is not a subset of the other then the best we can ever do is an approximation.

2. Sync pulse length.

The Apple II code that checks for the sync pulse is seven cycles long. Therefore the sync pulse length needs to be at least seven cycles long but less than twice that.

3. Time between bytes.

Once the Apple II has read a byte of data the microcontroller needs to pause for while until the Apple II catches up with processing and storing that data. For this project that amount was roughly forty five microseconds.

We can see from the above screen shot that if the sync pulse is too short or if the delay between bytes is too short then a gap is generated between the joystick status bytes. This condition would be too short to affect any game play but it is undesirable and easy to eliminate by performing more tuning.

4. Time between the start of sync and the start of first read.

These screen shots show how much the time between the start of the sync pulse and the start of the read pulse can vary.

The last critical point was to fine tune the time between the start of the sync pulse and the start of the first read. This is where all the fun began. This start time variance is determined by the length of the sync check.

The sync check takes seven cycles to execute and looks like this

LOOP CPX $C061 - 4 cycles
   BCS LOOP - 3 cycles on jump

however the initial read loop takes six cycles and looks like this

   CPX $C062 - 4 cycles
   ROL - 2 cycles

Therefore the read pulse is going to be shorter than the variance of the start time. In other words this is not going to work. The read pulse needed to be extended. The longer the read pulse is, the less significant the start time variance becomes but also at the same time this slows down communications. By adding just one extra delay into the read loop it takes the cycle count to eight which is larger than the sync check.

Even though the sync check pulse is now less than the read pulse when you take into account that the microprocessor timings are not directly linked to the Apple II clock, this becomes our border line condition. I can get communications working at this speed but it's not stable. It can be tuned to a given computer but the aim is to have the device working on any Apple II computer. This translates into a communication rate of around 80kbps. This includes reading the data, processing the data (extracting the joystick number) and storing the data.

Testing for stability was quite easy to do. The microcontroller was setup to transmit a specific byte. The Apple II side was setup to read this byte and if it was different from what was expected then a counter was incremented. As the timing was adjusted on the microcontroller you could see the rate at which the counter was ticking over slowed down until it stopped counting. It had reached stability.

To make the interface stable I ended up expanding the read loop, not by adding an extra NOP instruction but by making the read routine into a loop (instead of just having the same read code duplicated for every bit). This resulted in a read pulse of eleven cycles but it makes the code a lot shorter. A good compromise in my book. This translates into a communication rate of around 60kbps which is still six times faster than reading analog data or several times faster than what I was able to achieve through the serial port. For processing joystick data it is still an overkill.

At first I thought that running communications over the two game port push button lines would be the perfect solution especially in making a device that would work on all models of the Apple II. Well it didn't turn out as straight forward as I had hoped. These were the issues:-

1. Apple added filtering capacitors to the Apple IIe platinum model so I suspect the 4Joy in its current setup will not work on this machine. Without removing the filtering capacitors the only option would be to slow down the communication rate. I don't have one of these models to test on.

2. I've had mixed results trying to get these high speed communications going over the push button lines on the Apple IIc. Sometimes it works but then other times it does not. I suspect this is to do with the resistor pack on the IIc's game port interface. I tried replacing the general signal diodes with ones that have a lower breakdown voltage however this made the timings worse. On the IIc I found that diverting the communications from the PB0/PB1 pins over to the XDIR/YDIR pins bypasses the resistor pack and makes the interface work very well (similar to my tests on a IIe and a IIgs). The other option would be to slow down the communication speed.

3. The game port push button pins (PB0 and PB1) on some Apple II models are tied into the reboot function and the self-diagnostic function. Since the sync pulse on time is much less then the data on time I swapped my PB0 with PB1 signals so that the probability of starting the self-diagnostic function on a control-reset is very low. It does happen occasionally but I get around this by doing a second control-reset. However this means that the probability of getting a reboot from doing a control-reset is quite high. I prefer it to be this way around than the reverse.

The next phase will be to add USB support and combine it with the "Bluetooth Game Port Receiver". With a flick of a switch it should be possible to swap from being a single USB/Bluetooth analog joystick receiver to a multi USB/Bluetooth digital joystick solution.

All the project files are contained here. https://docs.google.com/open?id=1CGB9NA_eKHfWACUQh_alhHitOMYklRSN

Wednesday, July 4, 2018

Apple II 4serjoy - Gaming through the serial port

The 4Serjoy is a device that allows you to connect four digital joysticks to an Apple II computer using a serial port.

With the release of the 4Play card, the Apple II models now have a great option for multiplayer gaming using digital joysticks. But what about the poor ole Apple IIc, the slotless Apple II? Having a slotless Apple II is like having your arms and legs chopped off. It really limits the expandability of the machine. Any interaction with external devices is reduced to what you can put through the serial ports. Some IIc motherboard revisions allow special expansion cards but I'm talking about compatibility on all IIc systems. Not only did the IIc have to contend with not having any of the standard Apple II expansion slots but existing functionality, that a hacker would come to expect, was removed in the name of compactness. This includes the 16pin game port (which was more than just a dual analog joystick port) and the second joystick port which made way for the mouse interface.

So what options could there be for multiplayer joystick control on the IIc? Well, like I said, the interface is limited to the serial ports. I wondered how well games would perform if having the joystick control flow through this interface. Would it even be feasible to begin with? I did some rough calculations. The maximum time for the Apple II's analog paddle read to reach stability is just under three milliseconds and all the paddle/joystick reads are in parallel so that's still three milliseconds. Now for the serial port solution. At 9600 baud in a typical N81 setup, 8 data bits, 1 start bit and 1 stop bit results in a transfer rate of about 960 bytes per second or one byte every millisecond. Four joystick bytes should work out to four milliseconds. A baud rate of 19200 should yield a time of about two milliseconds for four joysticks bytes. The serial times seem like they are on par with the analog circuits. Therefore if the overheads are small I figured that this was certainly possible. That was enough for me to proceeded with the challenge. 

The hardware comprises of an ATmega1284P microcontroller, a breakout board and a "Serial TTL to Serial RS232" converter. For the software I started off by using an existing 4Play modified multiplayer game. Using an already converted 4Play game saved me time because the analog joystick/ keyboard handler to digital control was already done. I didn't have any four player games so the closest I could find was Mario Bros which is a two player game. The microcontroller can handle reading four joysticks but only two are currently hooked up. I threw together a simple assembly program to test the serial stream.

The way this device works is that it uses the microcontroller to read the digital signals from four joysticks (four direction positions and two fire buttons per joystick). This information is encoded into four bytes that is similar to the 4Play protocol. The four least significant bits are kept the same (direction signals), the two most significant bits are kept the same (two fire buttons) and the remaining two bits now encode the joystick number instead of the 4Play card identifier (bits 00: joystick 1, 01: joystick 2, 10: joystick 3 and 11:joystick 4). These four joystick status bytes are continually streamed to the Apple II via the serial port. Software running on the Apple II reads these values and replaces the existing direction commands that came from the game port / keyboard with the new digital signals.

The biggest issue with this setup is the need to modify the original software. The software needs to be modified to read the serial port instead of the game port or keyboard. This is a lot more work than modifying software to handle the 4Play card. Unlike the 4Play card which uses up less code then the original software (when hard coding the card's slot location ie not using the 4Play identification bits) the 4Serjoy needs to find space for 1. Serial port initiation (roughly 15 bytes), 2. Routine to read the serial port and store the joystick status bytes (roughly 25 bytes), 3. Storage of the joystick status bytes (4 bytes), 4. Call to the serial processing routine (roughly 20 bytes because there are multiple calls per loop) and then 5. As per the 4Play card you need to change the existing joystick/keyboard handler to use digital signals.

Apart form the usual great tools that I use to put together a project like this, having Hex Ray (a part of Nick's Virtu Apple II emulator) was a life saver. It allowed me to work out which parts of the Apple II memory were free to add in all the extra code that I needed for this game. Mario Bros is a resource hungry game so it wasn't easy to find available space.

Within the Mario Bros game there is a loop in which the joystick/keyboard handler gets called. When adding in the new call for the "check serial port" routine I found that every now and again the trigger button would not register. This seemed reasonable because there are four joystick status bytes to transport and checking one byte each loop means that a single joystick will only be read once every four loops. I added a second call to the loop however this did nothing to fix the trigger button issue. The problem was that the calls were too close to each other. By placing multiple calls within the loop and placing them further apart made all the difference. This means that joysticks 1 and 2 are being read every odd time through the loop and joysticks 3 and 4 every even time. This produced the game play that I was expecting.

My first lot of testing was using the default baud rate of 9600 but I wanted to know how the buad rate affected signal lag so I setup the system with baud rates 19200, 9600, 4800, 2400, 1200, 600 and 300. I had a preconceived idea that the game would not work below 9600 but I found that having baud rates between 19200 and 1200 did not change the game play enough for me to notice a difference. Maybe on a different game the lag would be more noticeable at the lower rates. Mario Bros is more of your "get the timing right" then a "test your reflexes" type of game. However the lag was obvious once 600 baud was used and 300 baud was even worse. What surprised me the most was that the lag was pretty bad at 300 baud but the game was still relatively playable. Using this baud rate I still managed to complete the first five levels without a problem. I could have continued playing the game further but the lag was annoying the crap out of me. This shows that the positioning of the code to read the serial port within the game loop is far more critical then the baud rate.

I built this device to full-fill the problem for the IIc but it will work just as well on an Apple II/II+/IIe (with a serial card) and the IIgs.

There are a few small changes I would need to make if I was to get this product up and running. These includes adding in the resistors to make it compatible with the Sega Genesis (Maga Drive) / Amiga CD32 type controllers and turning off the JTAG fuse on the microcontroller to free up port C which would then allow the connection with four joysticks instead of two.

Even though I don't see much of a demand for this device it answered a few of my questions and with surprising results. However on the rare chance that a landslide of multiplayer games becomes available for the Apple II then I know I'll be ready to go.

All the project files are contained here. https://docs.google.com/open?id=1m-IbGrzWqj3kRNCGpvAYJO-W6phvg0IZ