Sunday, January 18, 2015

Halftime for RC2015/01

We are now roughly half way through the Retrochallenge 2015/01 event!  I am still making progress, but I don't have a very cohesive topic for a blog post at the moment.  Since it has been a few days since the last update, I will just touch on a few random bits here and there...

Line By Line

In an earlier post, I mentioned that the video memory in the Apple II has a peculiar layout.  For example, the data for line six is offset in memory from the data for line seven by a different amount than the offset between the data for lines seven and eight.  This makes moving an object on the screen from line to line more complicated than simply adding or subtracting a fixed offset from the previous address.

Previously I wrote a routine that would convert a screen line number to a base address in video memory.  I have since rewritten that routine by replacing a shift-and-add multiplication with some bitwise operations, thereby improving its performance.  Nevertheless, the routine is long enough that I would like to limit how much it is used.

I was able to implement somewhat simpler routines for moving up or down one line at a time.  These routines combine simple offset adjustments with checks and adjustments for crossing 8-line boundaries.  The results are somewhat simpler than the direct calculation routine, with corresponding performance improvements.  A single-line offset is simple enough to be practical and common enough to be useful, especially for Fahrfall.


Point Break

The 6502 only has a handful of registers for use by the programmer, none of which are large enough to hold an actual address.  Addresses for data access can be embedded in the program code, but either that would limit a given function to accessing only predetermined memory locations or it would require the use of self-modifying code that rewrites the addresses whenever different memory locations are used -- ugh!

Fortunately, the 6502 does provide a couple of means for storing an address in memory and then using that address as the object of an indirect memory access.  Unfortunately, those options require storing the address somewhere within the 256-byte "zero page".  Those locations are in high demand, and the Apple II firmware pre-allocates most of that memory for its own use.  Fortunately I was able to find enough space to fill my immediate need for a drawing pointer.

When I only had platforms on the screen, I could get by with a single drawing pointer.  Even though there are three rows of platforms, their relative positions makes it easy to adjust the drawing pointer to point to each platform in turn.  Unfortunately, the player object needs its own drawing pointer value which is independent of the platform drawing pointer.  Of course, the player drawing pointer needs the same sorts of manipulations as the platform drawing pointer needs.

One option would be to use separate "zero page" locations for each pointer and to duplicate the pointer manipulation routines for the player object drawing pointer.  A better alternative is to use a single "zero page" location for the active drawing pointer and to save/restore this value to/from separate memory locations for different uses.  The second option effectively treats the "zero page" drawing pointer as a 16-bit register, providing me with the flexibility I need for what I want to do.


Ode To Joy

Fahrfall is an arcade-style game, so it makes sense to use a joystick to play the game.  The joysticks on the Apple II use an analog circuit based on an RC time delay.  The actual timing is done at the CPU by counting the number of cycles that are spent executing a tight loop while a capacitor is charged.  Coding such a loop seems simple enough, but doing so is unnecessary -- the Apple II firmware already contains such a function at a well-known location.

Reviewing the actual code of the firmware's joystick reading function reveals that there is little opportunity for improving its performance.  Consequently, I used the Apple II firmware to read the Y-axis of the joystick.  This returns an 8-bit number which represents the position of the joystick on that axis.  Fahrfall only needs to know the general direction for movement, not the actual position.  So, I added code to take the number representing the joystick position and to test it for left and right ranges.  I also included a dead zone in the middle to represent "no movement".

Well, that covers a few micro-topics related to my port of Fahrfall to the Apple II.  I also finished reading Assembly Lines: The Complete Book, so I guess I am now a trained Apple II programmer...

Things are coming together, but there is still more to come.  I hope you will stay tuned!

Tuesday, January 13, 2015

Trivial Triumph

Today I did something clever on the Apple II.  I applied some recently acquired knowledge to address a gap in the random number generation for my Fahrfall port, and I was proud of it.  Unfortunately, I may have solved a problem that didn't exist...

Standing Start

Previously I discussed the use of a software-based linear feedback shift register (LFSR) for generating pseudo-random number sequences.  The LFSR is really just an equation that generates a sequence of numbers, each based upon the value of the previous number in the sequence.  Given a fixed starting point, the LFSR will always generate the exact same number sequence.  Consequently it is important to "seed" the LFSR so that it starts at an unpredictable point in its sequence.  A common technique for seeding an LFSR would be to use a rapidly changing variable (such as a time-based counter) to seed the LFSR.  Since the Apple II lacks any timing source, I looked for other options.

Clever Display

After a while, I recalled learning about a quirk of the Apple II hardware that allows a program to read the byte of video data currently being displayed on the screen by reading from one of the "soft switches".  Others have used this mechanism to synchronize a program for the proper timing of video updates by writing appropriate "sentinel" data to the video buffer.  That method of synchronization relies on precise cycle counting and seems unsuitable for a game or other interactive program.  But maybe the mechanism it uses could be pressed into service here?

It is very difficult for a human to know what portion of the video buffer is being displayed at any given moment, so reading the displayed video data during program setup should yield the data from a more-or-less random position in the video buffer.  Of course, the video buffer will often contain largely uniform values (e.g. spaces on the text screen).  For best results, steps should be taken to minimize the duplication of data values within the video buffer.  Consequently, I wrote an ordered sequence of values to the video buffer.  During program initialization I read from a video "soft switch" to retrieve values to use for seeding the LFSR.  This yielded satisfactorily random sequences across multiple program starts.

Reality Bites

With my LFSR getting a reasonable seed value, I was feeling rather pleased with myself.  After just a couple of weeks of playing with the Apple II, I may have just invented a new technique for generating a random number seed!  Even if it turns out that others have done this before me, I still discovered this all on my own!  Nevertheless, I wondered if I could find any evidence of someone else doing something like this?

For what its worth, I did not find any documentation of anyone using this technique for generating a random number seed on an Apple II.  That doesn't mean that no one has ever done it, and it doesn't even mean that no one ever wrote it down.  It only means that I didn't find any evidence of that in a few minutes with Google -- YMMV!

However, in my search of Apple II random number generation techniques I did find another interesting tidbit.  Apparently the firmware on the Apple II updates a loop counter in the zero page (at locations $4e and $4f) every time the keyboard is checked for input.  While the value of this number might be predictable if a program is automatically started after boot (perhaps when using an emulator?), in the real world this method is just as good and it is a lot easier to use.

So, I guess I'll just seed the LFSR the easy way -- at least I got to feel smart for a little while!  This is the sort of stuff that makes the Retrochallenge lots of fun, so I wanted to post this update for everyone's enjoyment.  There will still be more to come, so I hope everyone will stay tuned!

Sunday, January 11, 2015

Any Port In A Storm

Well, I guess by now the jig is up...  Having so far demonstrated a lack of imagination in the Retrochallenge 2015/01 event, I am falling back to something familiar.  I am porting Fahrfall as an exercise in learning to program the Apple II.  At least that lets me concentrate on learning Apple II software architecture and 6502 assembly language rather than toying with game design...?


Random Patterns

Almost any game needs a source of random numbers.  The most obvious use of random numbers in Fahrfall is the generation of randomized platforms, but they are also used in the "game over" audio and for a few behind the scenes functions.  Of course, computers really have no way to pick truly random numbers, so some technique must be used to generate "pseudo random" number sequences that are not easily predictable by humans.

There are several techniques available for generating "pseudo random" numbers.  The one that I tend to use is a software implementation of a linear feedback shift register (LFSR).  In the CoCo version of Fahrfall, I implemented a "Fibonacci" LFSR.  This time I implemented a "Galois" LFSR because it seemed a bit easier for the 6502 to process.  The code is so simple and fast, I may go back and reimplement a "Galois" LFSR for the CoCo version of Fahrfall as well!

Step By Step

I am using the low resolution graphics mode on the Apple II.  This mode provides a broad array of colors while minimizing the amount of data required to paint a screen.  The resolution is lower than the video mode used on the CoCo version of Fahrfall, but I think it is adequate to provide enjoyable gameplay.

The encoding of pixel data in the low resolution mode is a bit easier to wrap one's mind around than the encoding used for the other Apple II video modes, but it is still a bit odd.  Sixteen colors are available and two pixels are encoded in a single byte -- so far, so good.  What is weird is that the two pixels represented by a single byte are stacked vertically rather than horizontally, so the two pixels in a byte represent parts of different lines.  Weirder still (at least to me), the most significant nibble of the byte represents the lower line.

In any case, this pairing of pixel data caused me to implement my earlier "moving platforms" code experiment using 24 line pairs rather than 48 separate lines.  This code structure seemed a bit awkward, since I will likely want to process player inputs and do other things in between platform movements without having to duplicate code for odd and even platform locations.  So, I refactored the code to handle 48 different platform positions and to plot the platforms with properly encoded pixel data.

Refactoring

Continuing along the same path, I did more refactoring of the remaining bits of my code.  That code was developed organically as I initially toyed with the Apple II.  Now that the code is going to be a game, it needs to adopt a structure conducive to that end.  That means moving various bits of inline code into reusable subroutines, minimizing and/or removing duplicate code segments, changing labels here and there, etc.  This also includes beating the overall structure of the code into a traditional game loop.  As it now stands, the code forms a skeleton upon which I can hang the rest of Fahrfall.

Now that I've confirmed that I am working on a port of Fahrfall, it might make sense to move further coverage of this effort to the Fahrfall blog.  I considered doing that, but that might be a bit confusing for folks following the Retrochallenge contest.  I'll just keep the cover here for now.  If the effort is a success, then I'll move further coverage to the Fahrfall blog later.  So if you want to watch the progress of porting Fahrfall to the Apple II, then you just have to stay tuned!

Wednesday, January 7, 2015

Taking Shape

I'm still plodding along with the Apple II, and getting more comfortable with programming the 6502.  So far, I am having some good fun!  I'm still not committed to any specific programming goal, but an idea is starting to take shape...

Fill In The Blank 

Old-fashioned video monitors (including televisions) literally drew images one line at a time, sweeping across and down the screen in the process.  Image data in a computer generally is stored in RAM, and the contents of that memory is scanned by the video hardware as the video signal is generated and sent to the monitor.  Computer programs that do not account for the timing of those scans while updating image data in memory tend to generate transient video "glitches" when a screen in shown on the monitor while that screen is being updated.  A common technique for avoiding such glitches is to ensure that image data is updated during the vertical blanking interval.  This is a period in the video signal which is literally reserved for the time it takes to move the electron beams in a CRT from one corner of the screen to the other.  During this period, nothing is drawn on the screen.  This is an ideal time for updating image data in memory.

The original Apple II and Apple II+ hardware did not provide any mechanism intended for software to synchronize with the vertical blanking interval, but the later Apple II models were more accommodating.  Unfortunately, dealing with vertical blank synchronization seems to have been a creative outlet for the engineers at Apple back in the day -- the IIe, IIgs, and IIc all do it differently!  I even found a Google Groups discussion about the topic.  For now I am just going to use the method for the machine I am actually using in my coding experiments, the IIe.  Something more robust can come later, if necessary.

Oversize Load

The early coding examples in Assembly Lines: The Complete Book place code into memory starting at address 768, an open area of memory not used either by Applesoft BASIC or by the system monitor.  However, that unused chunk of memory is not unlimited.  As I added code in my own experiments, the size of that code crept slowly up.  At one point, the program would immediately crash when it was run from the monitor -- not cool.  Of course, the tail end of my code was overwriting something important to the proper functioning of the monitor program.  So the lesson is "know where your code lives"... :-)

Serial Killer

As I mentioned in an earlier post, my development environment includes a serial (i.e. RS-232 over Bluetooth) link between the Apple II and my workstation across the room.  This provides me with a number of conveniences, but it has the drawback that I can't touch the Apple II when I'm running code on it.  The only way to interact with a program (including telling it to stop) is over the serial port, which means my code experiments need to know how to talk to the serial port.  So, I figured-out how the 6551 on the Super Serial Card is addressed and I wrote some code to let me poll the serial port for input -- remote access problem solved.


Well, that wraps up this progress report.  I am having fun, and I am expanding my retro computing horizons.  There is still more to come, so I really hope you will stay tuned!

Sunday, January 4, 2015

Apple On The Bench

So, my annual goofing-off and retrocomputing bacchanalia is coming to an end.  Tomorrow I will have to reacquaint myself with the dayjob and starting being a lot more responsive to email and such.  But before I get buried by my email, I thought it would be worthwhile to post another update on my Retrochallenge progress so far...

Toying With Graphics

Using a monitor program makes experimenting with hardware really easy.  Manipulating memory or flipping bits in hardware registers is nearly trivial, making it very easy to fiddle with what the system offers.  I took advantage of this to experiment with the graphics modes on my Apple II.  I used the monitor program to experiment with setting different colors on the screen, to change between the text and graphics modes, etc.  This is a great way to get a feel for how things work.

During my experiments, I was reminded of the peculiar way that screen memory is arranged on the Apple II.  One might expect that the data for the first pixel on the second line of the display would immediately follow the data for the last pixel on the first line, but on the Apple II that is not the case at all.  This is a by-product of a simplification in the Apple II hardware design, but it certainly complicates things when writing software to plot graphics to specific lines on the screen.  If you have ever noticed the "window blinds" effect when loading a graphic on an Apple II screen, you are observing what it looks like to write to the Apple II screen when accessing memory locations in a straight linear fashion.

Clearing Lines In On-Screen Order
As a coding experiment, I wrote something to blank-out parts of the screen in the order of lines as they appear on the screen rather than how they are stored in memory.  The algorithm for this wasn't too tricky, but it did require a bit of code to do some bit manipulations and to simulate what are essentially a pair of multiplications.  Even after some optimization, the code to calculate the base address of a line, to write the data for that line, and to loop through the requested lines took almost 100 bytes!  In a game, this sort of thing may merit a look-up table for finding line base addresses in the video buffer...

Unobstructed View

As I mentioned in an earlier post, I am redirecting the Apple II console through the serial port so that I can drive the Apple II from my development machine.  This works fine, but by default the output continues to be sent to the screen too.  That is fine when I'm only accessing the monitor program, but it is a problem at least for low resolution graphics mode since the text and graphics screens share the same memory -- typing commands messes-up the low-res graphics screen!  What to do?

There might be a way to convince the Apple II to stop sending output from the monitor program to the screen, but right now I don't know how to do that.  Fortunately, the Apple II actually maintains two separate screen buffers and the monitor program only modifies one of them.  Which buffer gets used for graphics output is determined by a set of registers in the Apple II that are called "soft switches".  By using the right "soft switch" to change the graphics to use the other screen buffer allowed me to do graphics experiments from the monitor program without messing-up the graphics on the screen.

Reading Log

I am still working on Assembly Lines: The Complete Book.  I have completed reading volume 1 and the original appendices, which should be equivalent to reading Assembly Lines: The Book (i.e. the original version).  So as a 6502 programmer, I am now as qualified as a young John Romero!  At least, that is how I interpret his quotation from the back cover... :-)

But seriously, there is plenty more to read.  With that said, I am feeling a bit more qualified to code for the 6502.  Plus, I am learning a bit about Apple II architecture and such -- I found some interesting stuff online about timing code to the vertical blank interval on the Apple IIe, IIc, and IIgs (all done differently).  I'm still not sure what coding project I will do, but some options are coming into focus.  If you want to read more about it then I hope you will stay tuned!

Friday, January 2, 2015

Out Of The Gate

Ending the second day of 2015, I think I've made a healthy start on my Retrochallenge project!  The goal is to familiarize myself a bit with the Apple II line of computers and learn enough about programming the 6502 to be dangerous...or something.  I have had a few bumps along the way while establishing my development environment, but now I think I've got a good level set...

Serial Offender

I like to use a monitor program when developing code for retro computers or any other sort of "small" target system.  The low level interface a monitor program offers is great for taking full control of a system, manipulating hardware registers, loading code, etc.  Fortunately for me, the Apple II machines actually shipped with such a monitor in the built-in ROMs!  Even better, the Apple II makes it easy to control the system over a serial port...or so it seemed!

Like many people with an interest in retro computing, I'm old enough to remember when a serial port was a gateway to the world, or at least a gateway to the BBS on the other side of town.  I'm no stranger to RS-232 communications, but talking to the serial console on the Apple II sprouted a few extra gray hairs on my head.  "IN #2" and setting the baud rate caused the Apple II to accept input over the serial port, but "PR #2" only produced junk on my terminal screen.  Adjusting the communications parameters seemed obvious, but none of the sane options worked.  Ultimately I used settings of 7 data bits and "mark" parity, but 8 data bits and/or "space" parity seemed to work just as well.  I wouldn't be surprised if technically I'm still using the wrong values and just getting lucky...?

That almost sorted the physical setup, except that my TV is on one side of the room and my desk is on the other side of the room.  I could use a long cable, but that can be a bit awkward.  Bluetooth provides a convenient means of replacing a cable with a wireless connection, and I happen to have an unused Bluetooth<->RS-232 adapter available.  Deploying that device made the required connection from across the room.

Super Serial Over Bluetooth
Varies By Model

Not all Apple II machines are the same!  I knew that, of course.  But I did not appreciate just how much variation there is even among similar models.  What illustrated this for me was trying to run the Apple II mini-assembler.  "Assembly Lines: The Complete Book" describes starting the mini-assembler by typing "F666G" from the monitor prompt.  Unfortunately, this simply didn't work.

I was under the impression that the Apple IIe included the mini-assembler in its ROM.  But deeper research uncovered that this was only true for the "Enhanced IIe" models.  Closer inspection revealed that my IIe was in fact a non-enhanced model.

Not An Enhanced IIe!
My research also indicated that the mini-assembler _is_ included in the ROM for the Apple IIc.  I swapped the IIe in my setup for a IIc, but "F666G" still didn't work!  Again I consulted the Google, eventually showing that in the later ROMs (like the IIc and the Enhanced IIe) the mini-assembler is entered by typing "!" at the monitor prompt (rather than "F666G").  After toying with the mini-assembler, I returned the IIe to my setup mostly because the Super Serial card in the IIe does not require setting the baud rate after every "IN #2" command.  The mini-assembler is useful, but significant coding will require a real assembler.

Peaceful Assembly

I'm not sure what assembler most Apple II coders use these days, but for now any 6502 assembler that produces raw machine code will work for me.  My development platform of choice is Fedora, and it so happens that there are (at least) three 6502 assemblers available in the Fedora repositories.  I chose to install ATasm, mostly because I was somewhat familiar with it from earlier Atari 2600 dabbling.  I realize that ATasm is geared toward the Atari 8-bit line of computers rather than the Apple II, but for now its raw output format will suffice.

How do I get the assembled code onto the Apple II?  Well, I wrote a little Bash script to take the machine code binary from the assembler and format it into commands that can be typed into the Apple II monitor program.  I then copy that command text and paste it into my terminal window connected to the Apple II -- voila!  In the long run I may want a different or more traditional solution for loading my programs on the Apple II, but this works great right now.

So, now what?  Well, I still have a lot of pages left for me to read in "Assembly Lines: The Complete Book".  Along the way there will probably be some fun code experiments.  If you want to see what happens, then I guess you will have to stay tuned!

Wednesday, December 31, 2014

RC2015/01 Contest Entry

Once again the turn of the year approaches, bringing with it a Retrochallenge event.  Generally, for Retrochallenge I want an entry that scratches an itch of some sort while maintaining the desired level of "why would anyone do that?"  I had a few items under consideration, but none felt quite right for a variety of reasons.  Also complicating things are some home repairs that will likely require us to vacate our house for several days sometime this month -- not very friendly to a hobby project with a deadline! :-)

As fate would have it, a few things came together to give me a bit of a "sign" as to what the project should be:
  • A recent eBay search led me to taking an interest in "Assembly Lines: The Book" by Robert Wagner;
  • Shortly thereafter I became aware of "Assembly Lines: The Complete Book", which is a modern reprinting and extended edition;
  • I ordered the book from Lulu.com, and it arrived yesterday just as I was getting desperate about finding a Retrochallenge project.
While I have dabbled a bit with programming the 6502, that has been confined to toying with the Atari 2600.  Similarly, my experience with the Apple II is limited mostly to some LOGO programming back in elementary school and a few more recent retro computing experiences here and there.  Clearly, there are a couple of related gaps in my retro computing prowess that I would like to address...

So, my project will be an attempt to read and absorb "Assembly Lines: The Complete Book" with the goal of writing some sort of program for the Apple II series of computers.  I'm not promising anything as good as Threshold.  But if I succeed, then maybe I can go to KansasFest this year without feeling like too much of a poser!

Wanna see how I do with this?  Then you'll just have to stay tuned... :-)