Retrochallenge 2017/04:
Personal Computer Space Transactor 2001

Addendum I: The Quest Continues

Updates and work in progress …

RetroChallenge may be over, but not our quest for Computer Space on the PET. Now that we may take whatever time it will need, we're free to coninue, at whatever pace, — until we're happy with what we achieved. Source code will be available on major iterations (only).

— Return to this page for brief updates and a link to the current state of affairs. —

Personal Computer Space Transactor 2001, Addendum

 Busy  Steady being born.

See this link for the current state of the program in in-browser emulation.

Or this one for the same in green.  :-)

Updates

2017-05-23/25:   Version 0.9.7 — 0.9.9, Fiddling around with rocket speed adjustments.
See the release page.


2017-05-23:   Version 0.9.6, added a pause function (STOP key); revised pace, rocket motion is now more "viscous". Also, a few changes "under the hood."
See the release page.


2017-05-21:   Version 0.9.5, slowed down the speed of the vessels (saucer velocity and maximum speed of the rocket ship) a little bit. (It was still a little frantic and even faster than the original.)
See the release page.


2017-05-14:   Version 0.9.3, increasing the potential user base quite dramatically by adding the C64 as an optional assembler target. The download now contains binaries for the C64, as well.
See the release page.

Here's how the game looks on the C64:

Personal Computer Space Transactor 2001, assembled for the C64

The title screen of Computer Space 2001 on the C64.
Apart from the bold font of the C64, it's the same game as on the PET.
(We stick with basic black and white, but add an unobtrusive color for the screen border masking the game.)

as compared to the PET:

Personal Computer Space Transactor 2001, assembled for the PET 2001

Computer Space 2001 (title screen) on the PET 2001.

Update: What it Needs for C64 Compatibility

So what does it need to port an assembler program for the PET 2001 to the C64? Not that much as the two systems share much of the approaches to a basic operating system as found in the kernel and, most importantly, the same screen dimensions (40 cols × 25 rows) and character encodings. Obviously, there are some differences, as in the hardware addresses at which the various peripheral chips are mapped to the address space, or the color screen of the C64. — Let's have a look.

Differences in hardware addresses may be handled in the assembler code by simply assigning these addresses to symbols based on the existence of a config-flag. In our case, these are

  1. the screen memory (1,000 bytes, starting on the PET at $8000 and on the C64 at $0400),
  2. the start of the BASIC or user area (PET: $0401, C64: $0801),
  3. the cassette buffer, we're using for the screen update buffers/queues (the PET has two of them, we're using the first one at $027A, while the C64 has just a single one at $033C), and
  4. the first of the hardware timers (PET, VIA time 1: $E844, C64: $DC04).

We decide to handle this on the existence of an assembler symbol named "C64" — if it's defined, we're targeting the C64, else we assemble for the PET by default. By this we arrive at following code for principal configuration:

; assembler flag for target system (uncomment for C64)
;C64 = 1

!ifndef C64 {

; PET (default)

BASIC  = $0401            ;start of BASIC/user meory
SCREEN = $8000            ;start of screen memory
CASS   = $027A            ;start of cassete buffer
TIMER  = $E844            ;source of random seed

} else {

; C64 specific setup

BASIC  = $0801            ;where to start the BASIC intro
SCREEN = $0400            ;start of screen memory
CASS   = $033C            ;start of cassete buffer
TIMER  = $DC04            ;source of random seed

screen colors to be used by the game
C64_FG_CLR =    1         ;foreground color
C64_BG_CLR =    0         ;background color
C64_FRAME_CLR = 6         ;frame color

}

Now, we may build on this basic values in the further code in order to abstract the system differences.

Another obvious difference is in the IRQ vector. We may introduce another piece of code for auto-detecting the system (like we're doing it already to differentiate between ROM 1.0 and the new ROMs for the PET), but, since we're addressing th C64 as a separate target already, there is no need to mess up the code for the PET. Thus we just add a piece of conditional code for the C64.

This is also the place to handle the C64's color screen, as we're setting it up only once. There's a background color and the color of the screen border, and the color RAM for any of the 1,000 screen positions. As we're already clearing the screen by a system call, sending the clear-screen character to the print routine, which happens to be the same across all Commodore 8-bit machines (lda #$93, jsr $FFD2), there's no need to fill the color RAM by hand, since this is already done by the clear-screen routine of the C64:

!ifndef C64 {

setup           ; setup irq vector for PETs (autodetects ROM version)
                ... (as before)

} else {

                ; setup irq vector for C64
                sei
                lda $314
                sta IRQVector
                lda $315
                sta IRQVector+1
                lda #<irqRoutine
                sta $314
                lda #>irqRoutine
                sta $315
                cli

                ; set up colors
                lda #C64_FG_CLR
                sta $0286
                lda #C64_BG_CLR
                sta $D021
                lda #C64_FRAME_CLR
                sta $D020

                ; set up keyboard repeat
                lda #$80
                sta $028A
}

The keyboard is handled a bit differently by the C64, but we may force it into the same behavior as on the PET by simply enforcing keyboard repeat by setting address $028A (see above). The rest is a simple matter of adjusting system addresses:

!ifndef C64 {                                   ;PET

readKbd ;reads a character from keyboard, returns char in AC (0 = empty)
                ... (as before)

} else {                                        ;same for C64

readKbd
                ldx $C6                         ;get # of chars in keyboard buffer
                beq .kbdEmpty
                lda $0276,x                     ;get char from buffer
                ldx #$40                        ;reset keboard matrix
                stx $CB                         ; for key repeat
                ldx #0                          ;reset index of keyboard buffer
                stx $C6                         ; to clear the queue
                rts
.kbdEmpty       lda #0
                rts

}

The last major difference is in the allocation of zero page addresses in the two systems. The PET manual refers to addresses in the range of $23 .. $5A as safe to be used for machine language programs running alongside BASIC. These are part of various addresses used as buffers in BASIC, starting with the product staging area for multiplication at $23. The C64 uses the the same properties in the same order as the PET, but starting at $26 for the the product staging area (RESHO). In order to set up the addresses in the zero page area used by our program, we define a base address "ZPAREA" and add to this basic offset when defining our address symbols:

!ifndef C64 {             ;PET

ZPAREA = $23              ;start of usable zero page area
; BASIC input buffer at $23 .. $5A may be reused safely (cf, PET 2001 manual)
; (beginning at $23, the product staging area for multiplication)

} else {                  ;C64

ZPAREA = $26              ;start of usable zero page area
; product staging area for multiplication (RESHO) starts at $26 on the C64

}

...

; symbols / zero-page addresses

!address {

gameState =      ZPAREA+ 0 ;0: attract, 1: active
fIRQ  =          ZPAREA+ 1 ;flag to synchronize irq operations
fRepaint =       ZPAREA+ 2 ;flag for video rendering/irq control
...

}

(In fact, we're adding the definition of ZPAREA to our very first config-block as shown above.)

Finally, there are some differences in the character ROM. First, there is no backslash character on the C64 (we're using it for the rocket ship), but we may substitute it by a PETSCII graphics character (top-left to bottom-right diagonal), even if this may look a bit crooked. Then, the C64 uses a bold font, providing 2-bits for any vertical stroke in order to accomodate to the blurry screens of common TV sets. (While color CRTs were generally not as sharp as monochrome CRTs, most of the blur is due to the TV optimizing the sharpening it applies to the incoming signal for moving images, which performs rather poorly with still video, typical for the output of home computers.) This results in a different alignment of some of the block characters in comparison to those found on the PET, but, again, we may address this by substitutes. In our code, we're defining a few symbols to handle these visual differences and use these symbols instead of any hard-coded values:

!ifndef C64 {             ;PET

; character definitions (there are minor differences on the C64)

BSL = $1C                 ;regular backslash character
TBR = $63                 ;horizontal top bar (thin)
BBR = $64                 ;horizontal bottom bar (thin)

} else {                  ;C64

BSL = $4D                 ;substitute for backslash (for rocket graphics)
TBR = $77                 ;horizontal top bar (thick)
BBR = $6F                 ;horizontal bottom bar (thick)

}

(Again, we're adding this to our very first config-block.)

And this is it. If the flag "C64" is set, our program will assemble to a functional equivalent to the PET program, we already have. If absent (commented out), the source will assemble for the PET to the same code as before.


2017-05-11:   Version 0.9.1, first release!

See the release page for details, source code and download.

Major improvements. Lost some time over an eratic bug regarding the conditions for clearing a missile (both in rocket missile and saucer missile handlers). In the end, it turned out to be a stupid error, where I got lost in homologous variable names, while I had been checking and rechecking the logic over and over again …

Anyway, we manage to close the project properly. :-)


2017-05-09:   We have a new info and setup screen — more options and even an animated saucer.

Personal Computer Space Transactor 2001, info & setup screen

The new setup screen.


2017-05-08:   Small update: We include the original instructions (from the cabinet) and let the user select the scoring mode (radix).

Personal Computer Space Transactor 2001, info & setup screen

Info and setup screen in Computer Space 2001.

The saucers are now moving a bit slower. (This was really a bit too hectic and even faster than in the original.)

This time, we also include the source code (as of v.0.8, current).


2017-05-08:   Yet another small addition, hexadecimal scoring for the player' rocket ship. For the purpose we implement the original Computer Space "hex garbage" display. Only for 15 ($A), which is just empty in the original, we add a dash, instead.

Personal Computer Space Transactor 2001, hex scores

Hexadecimal score numerals for Computer Space 2001.

2017-05-08:   Version 0.8. Added the missing pieces, like a proper setup for a new game. Also, there's now a bigger hit area for the rocket (now 2 screen locations, depending on the heading of the rocket) and the issue regarding excessive, consecutive stops by the saucers was addressed. (We now reset the random generator and force a movement at the third stop.)

Next, we'll revisit the saucer's AI (target acquisition), and v.0.9 will probably be the first official release, including source code and binaries.


2017-05-07:   Version 0.7. We've a basic game with all the effects, etc! Only thing really missing is a nice setup of the rocket ship and the saucers at the beginning of a game. Otherwise, the game is feature complete! Yet, a week late.

Personal Computer Space Transactor 2001, ready for a new game

Ready to play …

However, we will polish the game a little bit in the next days, e.g., refining the saucer(s) AI (the single character screen extent of the rocket is hard to hit) or tweak the random behavior a little bit (from time to time, there are excessive stops in the saucers' motion).


2017-05-07:   And a first effect: Rocket explosion (i.e., rotates on hit).


2017-05-06/07:   Version 0.5. Optimized the conditions for redrawing the various entities of the game display. (Lots of flags, one for each entity, and a look-up table for the score's screen area. Compare notes for 2017-05-03.) We should now get the most stable display at the least viable rate of updates. Moreover, the reset routine for the saucers recieved a bit of an hoverhaul and we make sure to reset the saucers to the visible screen area, just like the rocket ship. Also reformatted the source for a more organized view. — Now we're ready to add effects and make this a final game.


2017-05-04:   Minor Tweaks: Added a randomly blinking animation to the asterisk representing the rocket's thrust exhaust. The rocket is now always put inside the visible screen area, when reset. Also, we got rid of the now obsolete overhead regarding overlapping missile graphics.

Another minor tweak: The little saucer AI now tests against a random value before it engages, to address the problem of triggering early, which we already encountered with the PDP-1 version.


2017-05-03:   Rewrote the collision detection. It's now shorter, while more specialized (no test against epsilon values anymore). Also, we're now checking both emanations of the saucer (previously, it was just the 'real' one). And, you may now shoot the saucers missiles, as collisions between missiles are checked, as well.

Next, well optimize the screen update mechanism. (We'll redraw any elements when needed, but only then. E.g., currently, the scores are redrawn on any update, while an update is required only, if a background character is redrawn in the respective area. Also, we currently update a missile every frame, while we're only required to do so, if there's actually a change in position or block character. Moreover, now that missiles may collide, our algorithm for combined/overlapping block characters is pretty useless and will be stripped out.)


 

— Stay tuned! —

 

Next:  Addendum II: Release & Download

Previous:  Episode 10: Not the End, Yet, Still Some of a Wrap-Up

Back to the index.

— This series is part of Retrochallenge 2017/04. —