Tuesday, 28 July 2015

Retrochallenge 2015/07--Some Semigraphics 6 Games from the Acorn Atom

In my ongoing search for 8-bit BASIC game ideas and bits of code, I began looking into the classic British computer, the Acorn Atom. This machine caught my attention because it uses the same graphics chip as the TRS-80 MC-10, the MC6847 VDG. However, it predated the MC-10 by at least 3 years, coming out in 1980 or so, whereas the MC-10 came out in 1983. In searching YouTube for some videos of Atom games I ran across a couple of program playthroughs by a programmer called Dino Dini. Dini, it turns out, cut his teeth on the Atom and then went on to program some significant sports games (football/soccer) for a bunch of 8-bit systems in the late 80s. In the playthroughs, though, he is simply playing some of his original Atom games that he had thought were lost but then discovered were included with someone's Atom emulator. Here's his video:


What was most interesting for me about his playthroughs were the games that clearly used the obscure Semigraphics 6 mode of the MC6847.This mode is little used in Color Computer or Dragon games (which also use this chip) because the resolution it offers is only 64 by 48 pixels in 4 Colors (kinda like the graphics on a ZX81). On these machines, with their access to large amounts of memory, the high resolution modes of 128 X 192, 4 color and 256 X 192, 2 color graphics were what obviously attracted serious game programmers. And Microsoft BASIC never supported the mode. It only had commands for the 8 color Semigraphics 4 mode, which is 64 X 32, using the SET/RESET commands or the high res modes using PCLEAR/PSET/LINE/CIRCLE etc.

However, on the MC-10, which started out as a 4K ZX81-like computer, the hardware shortcuts used by Tandy to produce a small less-expensive machine resulted in a more limited set of wiring of the CPU to the MC6847 chip. This meant that graphics modes of that chip can only be memory addressed to the original 4K memory space. The results of these limitations are multiple. For example, since the highest 4 Color and 2 color modes of the VDG require 6K of memory to bitmap, when these screens are displayed on an MC-10 you only can see about two thirds of a screen before the screen "wraps around" the 4K memory space and you see the top 2K of the graphic memory repeated on the screen again. This means the highest resolutions are simply off the menu for any MC-10 programmers, including machine language coders. It is an unavoidable hardware limit. However, this didn't prevent one clever programmer using interrupts and special tricks to fool the VDG by changing modes through mid screen display, but there are still limits:


The result of all this quirky wiring is that the MC-10 is very limited in the kinds of graphics games that can be made for it. For instance it has only been able to have hires games that use the still somewhat chunky 128 X 96, 4 color mode. This hasn't prevented some clever machine language coders from producing some real classics. The most famous of these (using the term "famous" in it relative sense of renowned among the few dozens of MC-10ers on the planet) was Greg Dionne's implementation of Pac-Man. This version even received praise from one contemporary retro-gaming on-line magazine for its fidelity to the real thing:



But such wonderful games aside, there really just aren't that many graphic games for the MC-10. Being a BASIC programmer, limited only to the SET/RESET commands and the massive chunky pixels of 64 X 32, 8 color mode really gave me a craving to try to make some higher res games for the MC-10. However, there are other limits to using graphics. The way that BASIC is implemented means that some of the memory locations it uses are stored just after the end of the 512 bytes of memory used for regular screen display, so that even if you switch into higher res modes, you can't even POKE into the larger screen area without POKING into BASIC itself (the start of graphics memory cannot be changed--another limitation), which of course will bring the system crashing down.This means you have to stick to modes that only use 512 bytes of the normal screen memory, or program in machine language, and this means that from BASIC, you're pretty much stuck with using the 8 color super chunky SG4 mode.

Discovering that there was an alternative to SG4 was one of those wonderful moments I can remember of my early years in 8-bit computing. I read somewhere that POKEing into memory location 49151 would change the graphics mode. As I poked in various numbers, the different screen resolutions sprang into existence. Of course all of those above SG6 showed flickering pixels in the areas just after the text screen area, representing the changing values being stored by BASIC for various functions. However, one of these modes filled the whole ordinary screen, with no flickering. Its pixels were slightly finer than those of SG4. What was it?  I figured out that I could turn the pixels on and off, but this required poking into screen mem different byte values representing different pixel combinations represented by different bit values encodes by those byte values. Eventually I was able to figure out a method for correlating specific X/Y values for the screen as a whole that needed to be poked to set the right bit in a screen memory location.  Here's the routine:

0 CLEAR100:DIML(1,2),X(1),Y(1),AB(90,3),X,Y,X1,Y1,BY,VL,MA:FORX=0TO1:FORY=0TO2:READL(X,Y):NEXT:NEXT:DATA32,8,2,16,4,1
1 DIMC(4,5),D(7),U(7),M(7,8),P,D,T,R,L,VCTRL,CH,W1,CA:VCTRL=49151:CH=16:GOTO100
3 POKEVCTRL,CHOR(PEEK(VCTRL)AND7):RETURN
4 POKEVCTRL,0:RETURN
5 X1=INT(X/2):Y1=INT(Y/3):L=16384+(X1+Y1*32):VL=L(INT(X-X1*2),INT(Y-Y1*3))
6 POKEL,VLORPEEK(L):RETURN
7 POKEL,(NOT(NOT(VLORPEEK(L))ORVL)):RETURN
100 CLS0:GOSUB3:FORX=0TO63:FORY=0TO47:GOSUB5:GOSUB7:NEXT:NEXT
110 GOTO110

This routine contains a lookup table that has to be READ into an array L(X,Y) first. If you set X and Y and GOSUB5 you can get a SG6 pixel turned on. GOSUBing 7 is used for erasing the pixel. Line 100-110 just uses these routines to draw a moving pixel to demo the routine. Line 3 is GOSUBed for turning SG6 on. Line 4 returns you to text mode (SG4). I had a new graphics mode! It was essentially equivalent to the resolution of an unmodified Timex 1000/Sinclair ZX81. One of the first useful programs that I made using these routines was a puzzle game called Monster based on the classic Theseus and the Minotaur puzzles:


As you can see, it also has some text. I created a routine for storing byte values for encoding two byte high by two byte wide characters (4X6 pixels). Still it was only a puzzle game, with limited animation of the characters (Theseus and the Minotaur). What I wanted was an arcade style game! My first attempt was to make a Missile Command like game. I eventually got one to work, but since line drawing was so slow, it really only involved moving flickering pixels. So I left the project aside for many years.  

However, in the early 2000s I was able to reconnect with other MC-10 users using the wonder of the age--The Internet! I was able to find a group of people still interested in the machine on Yahoo. It was there that I came across Greg Dionne's wonderful Pac-Man. In time I asked if anyone could provide a BASIC implemented machine language routine for drawing lines in SG6. I was surprised when Greg replied with a routine to do just that:

0 SOUND1,1:CLS:CLEAR200:DIMA(90,3),K(255),I,J,X,Y,Q,R,Z,M$,F,G,A,B,C,L,E,S,V:GOTO100
9 PRINT@F,CHR$(A(Z,0))CHR$(A(Z,1));:PRINT@F+32,CHR$(A(Z,2))CHR$(A(Z,3));:RETURN
10 FORG=1TOLEN(M$):Z=ASC(MID$(M$,G,1)):GOSUB9:F=F+2:NEXT:RETURN
100 GOSUB2018
110 REM PROGRAM CONTINUES HERE
120 GOTO120
2005 DATA128,128,128,128,149,128,132,128,152,128,128,128,128,128,134,128,128,128,132,128
2006 DATA154,138,164,160,149,128,148,128,179,170,172,136,177,170,140,168,171,170,128,168,187,162,140,168,187,162,172,168,176
2007 DATA170,128,168,187,170,172,168,187,170,128,168,177,168,132,128,155,138,168,168,187,136,172,160,186,160,172,136,186,138
2008 DATA172,160,187,160,172,136,187,160,168,128,186,160,172,160,171,170,168,168,149,128,148,128,128,170,172,168,171,168,168
2009 DATA168,170,128,172,136,174,170,168,168,186,138,168,168,154,138,164,160,187,170,168,128,154,138,164,168,187,136,168,168
2010 DATA187,162,140,168,181,160,148,128,170,170,172,168,170,170,148,128,170,170,184,168,169,168,168,168,171,170,148,128
2011 DATA177,168,172,136
2017 READA(X,0),A(X,1),A(X,2),A(X,3):RETURN
2018 X=32:GOSUB2017:X=33:GOSUB2017:X=39:GOSUB2017:X=44:GOSUB2017:X=46:GOSUB2017
2019 FORX=48TO57:GOSUB2017:NEXTX:X=63:GOSUB2017:FORX=65TO90:GOSUB2017:NEXTX
2020 REM LINE DRAW SUBROUTINE BY GREG DIONNE
2030 REM Z=USR((I*256+J)*65537) FOR SINGLE POINT
2040 REM Z=USR((I*256+J)*65536+Q*256+R) TO DRAW LINE
3000 DATALNPDALMMABABNNLLNMMMJAMKCCAJCFADHPAALLHAAALLEANAMLCCAJCFADHPAALMHAAALMFANNNGBBCDHCEPJHMOJHNLJGNGJHNMINDCJG
3001 DATAMKJBMMCHCIJLLLJHMKJGMOJLNHJHMOBGJANLCKABEANANMCKABFABBCFOANGNMNHNLNLNGNHNMNGMLNLLMNHMLCANAFPHOOMOCNMMKNNNI
3002 DATAJGNJMGKLDNIGIAMAFFEEEEMLFFMBFFCEPIHEAANICEABEEIKIAJHNKIGCADNNLNIIJAAIKEAIEEBNNNINONINGNKOKAAOHAADJEPJHMOJH
3003 DATANLJGNHJHNMINMAJGMLJBMNCHLGJLLMJHMLJGMOJLNGJHMOBGJANLCKABEANANMCKABFABBCFOANGNMNHNLNLNHNHNMNGMKNLLLNHMKCANA
3004 Z=32768:FORX=0TO3:READM$:GOSUB3005:NEXT:Z=16917:M$="HOIAAA"
3005 FORY=1TOLEN(M$)/2:POKEZ,(ASC(MID$(M$,2*Y-1,1))-65)*16+ASC(MID$(M$,2*Y,1))-65:Z=Z+1:NEXT:RETURN

For good measure I have also included my text drawing routine. Set the string value M$ for the message. Set variable F for the starting screen location (0-511) and then GOSUB 10 to print the message. Obviously there has to be space for the length of the message. Look at line 2030-2040 for the instructions on using Greg's pixel setting and line drawing routine. It's a USR call with values I,J,Q,R. With this routine I was able to make a better version of my Missile Command:


Lately on the Yahoo group some people were talking about the graphic limits of the MC-10 and lamenting the weird wiring of the CPU and the MC6847. What prompted this were the contributions of Emerson, a user of another orphan machine, the CCE MC1000 computer from Brazil. Like the MC-10 it was a small chicklet-keyed economy computer. Like the MC-10 it used the MC6847 VDG, but it had a variation of Applesoft BASIC. And like the MC-10 it had various limitations to its wiring that prevented the full use of the VDG. Emerson told the group about his various attempts to physically mod the machine so that a fuller array of it graphic modes could be accessed. This prompted a lot of discussion of the limits in the MC-10s graphic capabilities. Another such limitation that I haven't mentioned yet is that even the SG6 mode is not fully wired so two of the 4 possible colours (in principle) are not actually available:


The first screen shows SG6 mode while the second shows the screen in regular SG4 mode. The weird green black lines represent the first 128 bytes of the character set. Only the pixel/bit combinations for byte values 128-255 are available on the MC-10. This is a result of another economy wiring decision to keep the component complexity and costs down (to be fair, the Coco ad Dragon also suffer from this limitation--only machines like the NEC PC6001 and Sanyo PHC-25 fully implemented all the features of the MC6847). Still, there are two colours available: Blue on Black and Red on Black. You can also select an alternate mode (POKE 49151,68) which gives Purple on Black and Orange on Black.

All the talk about the limits of the graphic wiring of the MC-10 got me thinking about trying to use the SG6 mode for some truly arcade style games. If I could find some good ideas and use all my latest fast BASIC programming techniques and knowledge and routines obtained from the group about SG6 over the years, maybe I could get some truly interesting effects.

It was with these thoughts in mind that I stumbled across Dini's demos of his old programs. The result is two programs DRIVE (source) and SPACEWAL (source) that attempt to recreate the games I could see being played on YouTube. DRIVE uses Greg's helpful line and pixel plotting routine. Unfortunately, that routine does not provide a way to determine if a pixel is turned on (i.e. an equivalent to the POINT function in Micro Color Basic for determining whether a pixel has been SET), so I had to figure out a quick way to determine if the moving pixel you control actually moves into any existing bit that is already turned on. Finally I figured out that all I needed to do was PEEK the BYTE location in which a pixel is going to be set using Greg's routine and then PEEK it again after the pixel has been set. If the two values are the same, then that means the pixel has been set in a location that already has a pixel turned on. This means a collision has occurred. Otherwise, not, and your "player" can keep moving. This allowed me to get the collision detection down to the level of the specific pixels on the screen that are being turned on and off and not just the level of the character bytes encoding that information. Greg didn't provide an erase function either (equivalent to the RESET command), so I just poke back the results from the peek test before the pixel was set. Here's DRIVE (a version before I had implemented pixel level detection, but its hard to notice):


SpaceWal is a neat space shooter that uses a horizontal screen orientation, instead of having the aliens descend from above. This allows for longer more complex movements of the aliens before they reach you than would be possible in the more standard vertical orientation of games like Space Invaders, etc. I pre-calculate at program startup 32 tracks that the aliens can take, which avoids a lot of checking and calculation going on in the main loop of the game. Since you shoot aliens at differing times in their approach, the randomly chosen tracks quickly "complexify" in the interactions between the two aliens that are always descending on you at any time. It also means that there is a kind of a simple AI element to the game, as once the aliens punch through an area of the wall there is a strong likelihood that they will eventually return to that area to try complete the job of flying through to the green layer and victory. You be the judge whether this trick can allow a player to predict the paths of attackers.


Random modifications to the 32 tracks occurs between games while the program waits for a new player to hit a key to play again. Since all the "sprites" in this game represent single byte characters I didn't need to use Greg Dionne's M/L routine. Instead, because of the horizontal orientation, object like the laser blast can be made simply by printing a long string of appropriate characters. Otherwise the individual sprites can be POKED into the right locations, which is slightly faster than using the PRINT@ command. You'll notice if you view Dini's video that the Acorn Atom can display SG6 graphics pixels and regular text characters at the same, so its wiring must be more complex than that of the MC-10. I used my graphics character routine in DRIVE to overcome this limitation of the MC-10 and simply shift to a separate text screen for reporting scores in SPACEWAL at the end of each game.

Anyway, so ends my retrocomputing efforts for the month of July 2015. I send greetings to all the other Retrochallengers and look forward to exploring everyone's work. I'm sure I'll find other sources of inspiration there. Thanks for another Summer Retrochallenge Mark! Sorry for the last minute entry (again).

No comments:

Post a Comment