My port of Conway’s Game of Life to the Apple II is now complete!
The whole code is available on GitHub.
Plus, there are four posts on this documenting my progression that could interest those who want to learn more about programming on the Apple II,
- Coding in C for an 8 bit 6502 CPU
- Coding in Assembly for an Apple II
- HIRES Graphics on the Apple II
- Making the Apple II sing
You’re welcome to try it in the emulator embedded below!
- It’s very, very slow, and won’t run real time on all but the most powerful smartphones
- In order to « play » it past the Title Screen, a keyboard is required anyway
- The loading time can last more than 30 seconds :/
- The display is way cleaner and crisper than it would be on an actual machine
You can also download this disk image and load it on your favorite emulator for a more faithful result.
A few screenshots if you are on a smartphone and cannot run the emulator:
Now that this small project is completed, I can say that I have a good grasp on how the Apple II actually works and how to make use of its main capabilities. Of course, no breakthrough here. But my « A Game of Life » makes use of:
- Keyboard inputs
- Access to the file system via the PRODOS‘ API
- Color graphics in both HIRES and LORES
- Sounds, and even music
Here I will sum up some lessons I learnt, how things could be improved in an eventual future project and what surprised me the most.
Coding for an Apple II in 2017
As I explained in my first article on the subject, it’s quite possible to code in plain C, thanks to the amazing work of the guys behind CC65. The binary produced is far from being optimized but usable enough to form a skeleton or hosts a state machine. CC65 also comes with an assembler if some routines require to be optimized.
On the plus side
- CC65 has a good compliance with the ANSI standard
- CC65 comes with a good support library with some standard functions such as printf and others inspired from conio.h
- There is a good integration with the assembler and the calling convention is well documented,
On the minus side
- Most of the zero page addresses are reserved for the « runtime library ». Meaning that, even in assembly, you will be restricted to using only 8 addresses!
- A lot of symbols are loaded by default, reducing the usable memory.
Testing and debugging
Using CC65, it is rather easy to develop and to cross-compile for the Apple II.
Fortunately, using an adequate emulator, it is also rather easy to debug code. Being mainly on Windows, I chose AppleWin. It is faithful to the hardware and, more important in this occasion, provides a debugger. If its debugging capabilities seem rather limited compared to a modern debugger, they are more than enough. And way more advanced that any debugger that can be found on the actual machine.
I was quite satisfied by AppleWin’s debugger and emulation!
The Apple II hardware
I learnt much about the hardware of the machine. I can sum up my feelings with two words: clever and primitive.
Indeed, everything about the Apple II was very cleverly engineered. But as the grandfather of the personal computers, it’s also way more primitive that what I expected.
The MOS 6502
The 6502 is a great microprocessor! Its instruction set is small and very lean. Quite easy to learn. For its time, it was quit an engineering achievement: as powerful as its main competitors of the time (the Intel 8080 and the Motorola 6800) for a fifth of the price! It was powerful enough to remain competitive during the first half of the eighties against its nemesis, the Zilog Z80.
But there is a catch. It comes with nothing superfluous.
For instance, there is, of course a LSR instruction (Logical Shift Right). But you can only shift by one bit. If you want to shift more? Use a loop! Furthermore, there is no LSL instruction! You can straight that out with the ROR instruction anyway. Same with subtraction: if you want to subtract by a number, add its negative!
And it is a true 8-bit CPU. Meaning that only 8-bit operations are permitted!
On other 8-bit CPU such as the Z80, you can manipulate 16 bit numbers and use in them in some arithmetic operations. Of course, it is suboptimal. As the ALU is not 16-bit wide, it will rely on some slow micro-coded operations to perform a 16-bit task.
But micro-codes cost transistors. Thus the 6502 does not provide any!
When programming the 6502, you are constantly reminded how limiting 8-bit arithmetic is. The result of your additions cannot exceed 256. Your loops are limited to 256 iterations. You cannot event jump to an address more than 256 byte away in memory!
If I had no trouble using the text mode and the low resolution graphical mode, using the “HIRES” high resolution mode was a lot more difficult that what I expected. Of course, as I knew, there is no dedicated hardware to assist you. But the most disturbing is the peculiar way the data is organized in memory. Saying nothing about the artifacts appearing if you’re not careful.
This color display was astonishing for the time. But it was also very difficult to program for. I now measure the troubles that programmers of the time had to overcome in order to offer us some of the best arcade games ever!
Bare-bone is what comes to my mind. I knew that the speaker had to be driven by the software but I did not expect the lack of an hardware counter or clock that could cadence it.
Programming a Game of Life on the Apple II was worth every bit of it. Using modern tools, it was not that difficult and was mainly a matter of reading (and understanding!) the documentation.
Now I wonder what will be my next move.
I still have to complete the restoration of my Apple II by fixing its Disk drive.
I could capitalize on my new knowledge of the 6502 to program a small game for the PC Engine (also known as the TurboGrafx-16 by our American friends). An impressive arcade machine!
But I’m also tempted to program something for the Amiga.