Showing posts with label 6502. Show all posts
Showing posts with label 6502. Show all posts

Wednesday, 14 October 2026

Enter the Matrix with Neo6502 and Morpheus

Neo6502 from Olimex

I ordered this cheap small 6502-themed board in about 2023, wasn't that interested with the Apple II material that came with it, and didn't find the moment to flash the Morpheus BASIC environment.

What postponed the flashing was a lack of a strange item called USB-A-to-A (male/male) cable, which I didn't have around. Some kind of adapter could work, but at least my USB-C to A cables didn't perform here.

Now I finally bought a real USB-A-to-A 2.0 cable and flashed the Morpheus BASIC into the board. Connect the Neo6502 USB-A ("host") to the computer (only this one cable) while holding BOOT key, then release it and the device shows as a drive. After copying the firmware to it, the on-board speaker gives a sound and it's done.

Now connect the power USB and HDMI, preferably also a keyboard, and this screen should appear:

Neo6502 Splash screen

The Neo6502 has a 6502 chip of sorts, hence the name. It's a W65C02 running at 6Mhz, yet a lot of heavy video and memory lifting is done by the RP2040 co-processor. So although notionally the computer does have a 6502-type chip as a CPU, the RP can support in math and shifting memory areas.

For example, drawing a rectangle RECT SOLID 0,0 TO 319,239 will instantly fill the screen, but doing FOR...NEXT loops to fill the screen with the PLOT command will be ploddingly slow. 

A 320x240 16 color video image is produced for HDMI, featuring tile maps and sprites. The 65C02/RP symbiosis is reasonable as otherwise the package might have been a little underwhelming. It's not an FPGA if that's important.

The board has USB-C for power, USB-A for flash/hub, HDMI, 10-pin UEXT (original to Olimex) for communicating with the microcontroller and a 6502 bus connector. USB HID devices such as keyboards, mice and memory sticks work on it, but as there's only the one USB, a hub is almost a necessity.

A number of cables is required

The NeoBasic looks like fun, fast and feature-packed. Reading the manual I see the authors are quite aware of later day BASICs such as Amos on Amiga and STOS on Atari ST, so it's not a bare-bones proposition. It doesn't follow all conventions, there's no STEP to the FOR...NEXT loop. There's also inline assembly, a separate simple BASIC editor, and many other features. Cross-development should also be possible.

I can print text (fast), pixels and lines and other graphic elements with ease. The 16 colour palette can be adjusted, not full 24-bit RGB but apparently a 8-bit subset. It looks like they opted for a 6x8 character set instead of 8x8, so the screen is 53 characters wide instead of 40, leaving 2 pixels to the edges. With the HDMI precision it makes sense. It's a bitmap display anyway, not a character mode.

BASIC

Using a memory stick (the "usb key" in the manual) I could also save and load BASIC programs. I did find a few editing idiosyncrasies and other things I didn't quite like. The screen doesn't scroll when the cursor gets to the bottom, the cursor just wraps around to the top. I couldn't easily find a SHIFT+HOME type combination that would clear the screen. HOME and END and many keys don't seem to do anything useful or what I would expect them to do.

If I return from the EDIT screen, the listing insists on renumbering on 1,2,3... and doesn't care about GOSUB values. I accidentally did this a few times, thinking that EDIT 20 would bring me the line 20 under the full screen editor, as some BASIC interpreters do. The manual does suggest sticking to the EDIT editor and not use line numbers at all, though.

Hardware side, some red horizontal lines occasionally flicker into sight. This problem is acknowledged but it looks like it cannot be helped by firmware updates alone. The board can be picky about the USB hub I suppose, I used a 4xUSB 2.0 hub from Nedis and while keyboard and memory stick work, I also encountered some problems. The AUTOSTART.BAS file refused to boot automatically, although with my old Aten USB switcher hub, it did.

With the Nedis USB hub

Olimex now sells a package that integrates the Neo6502, an USB hub and a keyboard into the same package. I would expect a selected hardware combination to have as few quirks as possible. The price is still cheap, but it's also worth knowing that this is a very narrowly focused hobbyist/tinkerer/enthusiast computer.

Sunday, 30 July 2023

Lancess Priya C64

I made a 3D-ish shoot'em up game for the Commodore 64. At the moment, the file can be downloaded from CSDb. Grab a joystick and play.

The following is mostly about the background inspiration for the game.


Star Wars Arcade 1983

The Star Wars arcade game by Atari is maybe the greatest arcade experience I ever had.

I'd like to reminisce how I poured coins endlessly into the machine, but in truth I likely played the real coin-op only a handful of times.

And maybe for the better, as the home version on C64 and Amiga showed the game in itself doesn't have that much longevity. It's perfect for arcade, an audio-visual-physical experience leaving you hungry for more.

I can pinpoint my likely first encounter with the game to July/August in 1984, when a cabinet was present at the Space 2000 (Avaruus 2000) exhibition in Dipoli building, Espoo, Finland.

At that time I didn't quite get the 3D perspective and probably the colorful Zaxxon next to it made a bigger impression on me. I'm even unsure if I personally played Star Wars at that occasion. Later I experienced it both as upright and cockpit versions in amusement parks.

Commodore 64 versions

Domark/Vektor Graphics: Star Wars, Space battle and navigating the surface

There's a brave conversion made for the Commodore 64 by Vektor Graphics and published by Domark in 1988. 

Although this version is nearly complete, it is also slow on the C64. Using a smoothly moving sprite for the crosshair does mitigate it somewhat. Some 8-bit computers lacked this advantage, but the BBC Micro version looks rather fast, although it has other problems.

Domark/Vektor Graphics: Star Wars trench run

The space battle is faster, but I also notice the enemy ships rarely come very close, and the action is often obfuscated by the ever-growing mass of fireballs.

The tower scene is very impressive, the ship rolls and there are many towers and bunkers approaching. There's also slowdown at times. The tunnel works very well, it has a lot going on and yet it isn't that slow.

The earlier Parker Brothers' version of the arcade game made around 1984 is also well known among Commodore 64 users.

Parker Brothers' Star Wars: Tower scene and Trench Run

The Parker game is not very impressive, but it is fast and the tunnel section is nice, it has lot of catwalks and a three dimensional projection of sorts. That portion isn't especially fast, though.

The tower scene does not have ship roll and the towers chug along in steps, not well synced to the dot effects on the ground. The on-screen player ship elements don't move at all, further adding to the stiff feel of the game.

The space battle is especially lazy, there is no attempt at all to have the TIE fighters in different depths. It is still nice to play. The Atari 2600 version is in some ways a bigger achievement, considering the limitations of that platform.

Parker Brothers' Star Wars: Space Battle


Lancess Priya

I began asking myself if there was a third path, something that was faster than proper vectors yet would not look so silly as the sprite-based enemies.

The result, Lancess Priya, is more of an "inspired" mini-game and not any kind of attempt at full conversion. All my games tend to be quite short, partly because of necessity and secondly because I usually prefer short games when I go vintage (Blue Max, Rambo, Saboteur, Bruce Lee...)

The game lacks many elements you'd find in the Star Wars game, and adds some that weren't really there. For example, here you have a direct control the ship even in the space battle, and you can dodge the fireballs more easily as they are not "stuck" to the screen position.

Lancess Priya: Space battle and the Trench Scene

I could say I'm using the the Parker Brothers' version as a springboard, building up from the compromises present in that game. Here the lasers aren't full beams, but small bolts, and pre-calculated character graphics instead of full vectors are used to draw the enemy fighters.

The number of objects and lines has been reduced to the minimum where I could still get it work at 1/2 frame rate, also using the full frame rate reticle trick from the Domark game.

It's tricky to get a screenshot that would make the game look very interesting, but it does look a little better in motion, I think!

Lancess Priya: The tower scene


Some technical notes

One day I might make a more thorough technical breakdown of the development process, here I only give a brief explanation to why the game looks like it does.

I toyed with the idea of making a PETSCII character-based game, but after a couple of doodles of TIE fighter frames I felt it would not be the route. The idea of using pre-stored animation frames did stay, though.

The PETSCII experiments gravitated towards using the 2x2 blocks for more motion accuracy, which made me ask whether it would make more sense to use self-defined characters.

So, this new game would use a pseudo-bitmap display built from characters, but not the ones included in the PETSCII set. Splitting one character into 8 cells gives me an 80x100 resolution.

This is quarter the amount of pixels compared to 160x200 resolution, and the benefit with a character mode is that it uses less memory and can be faster. Animation frames can use less memory than sprites for a comparable screen area. Line graphics aren't enormously faster than I guess bitmap drawing would be, probably because I can't write fast routines.

One byte defines a physical screen area that would need 8 bytes in a bitmap mode, this also means I can use 1000 bytes to define the full screen instead of 8000 bytes of bitmap. Or 2K versus 16K in double-buffering.

There are 256 characters ranging from empty to full, based on the above bit pattern.

More technically, there are some occasions where left/right can be adjusted by ROL/ROR instructions, and vertical shifting isn't that expensive either.

I decided the routine should work on 25fps if possible, or it would not be worth it. I worked with 1/3 framerate in Digiloi (2018) , but that was full color 2D character graphics.

So, the end result works on a double buffered character display with 80x100 effective resolution.

Sunday, 21 March 2021

Leilei Relay


Baby UFOs in UFOland have to train arduously before they can leave their homeworld.

Historically, the most infamous of these training grounds was the Lei Lei Relay.

Collect the lanterns to advance to the next field, up until you reach the UFO cathedral. There you will attain the title of UFO master.

Guide the UFO using Joystick in Joystick port 2. Left and Right turns the ship, while Up is thrust and so is Fire. Pressing key '1' on the keyboard switches the musics on/off.

*

On and off I have been working on new Commodore 64 games. Most of them do not get much farther than early stages, so I really, really wanted to do something so small that it would get finished.

Even then, this game turned out to be somewhat bloated compared to my original intentions. So it's a small game that became slightly bigger than I wanted to.

It does have multicolor character graphics, sprites, smooth vertical scrolling, inertia, polar coordinate tables, multiple SID tunes and sound effects.


My original intention was to make a one-screen lander-type game. Some inspiration has been drawn from lander games and Space Taxi.

But it's closer to a gravity game like Thrust in the sense there's no actual landing involved. Instead, you need to collect all the lanterns from each room to proceed to the next one. The quicker this can be done, the more bonus points can be achieved. And that's it.

The weird shape of the player ship gives the game some additional spice. It needs to be turned into a vertical position to help squeeze it through some of the more narrow passages.

Unlike with Fort Django and Digiloi, there's no shooting, which makes this game simpler. But it's likely to be infernally difficult.

There's no PETSCII character graphics this time, I have some ideas about their use for other games, which may or may not be completed!


Tile map layout

As usual, I have come to trust Tiled for map-making. Instead of PETSCII I now used multicolor character graphics. The pipeline from character editing to "meta-tiles" would deserve a closer look but I'll leave that for another time. Let's just say experience in PETSCII gives a good start for optimizing character graphics, but it does have its own peculiarities.

First level in Tiled

At the center of the game routine is the scrolling screen buffer. Instead of updating screen portions piece by piece, the whole screen is redrawn for each frame.

I abandoned the character-specific colors to make this easier. This gives the game a somewhat monochromatic appearance. I tried to alleviate it by using different colors for different levels, and mixing the colors when possible.

There's a huge ordered buffer in the memory, but at least it made some other things easier for me. The level data in itself takes very little space, but testing levels and putting them in a reasonable order is time consuming so I went for a fairly low number.


More technical parts

The brutal redraw routine means I can scroll the area in whatever speed I like, and also if I draw changes into the buffer, these are rather simple to calculate, as all Y-coordinates work as increments to the HI-portion of the address. So if the first line of the buffer is at $8000, the next line is at $8100 and so on.

A new thing to me was polar coordinates and inertia, although I already made the routines for a more complex game idea, they found a better home in Leilei Relay.

The UFO coordinates are 24-bit values, but this is less complex than might sound.

24-bit coordinate:

[Low byte][High byte ][Highest byte  ]

Sprite coordinate:

          [Sprite LSB][Sprite MSB bit]
  

The high and highest byte are transferred directly to sprite screen coordinates, so that "highest" gives the MSB bit for the sprite coordinates higher than 255.

Low byte is kind of sub-pixel coordinates, as they increment over 255, the sprite has moved visibly one pixel.

For thrusting the craft forward, a polar coordinate table is needed. These are 8-bit values centred around the point 128,128 ($80,$80). They have been generated using Processing.

move_anglex:
.byte $80,$80,$81,$81,$82,$82,$82,$83,$83,$84,$84, [...]
move_angley:
.byte $70,$70,$70,$70,$70,$70,$70,$70,$70,$70,$70, [...]

So the first values are $80 and $70, which indicates 128 and 112, denoting a 0,-16 vector.

I have 256 values in the table although the UFO has only 32 visible angles. I won't go into the confusion this might create, I initially thought it would be nice to have more functional angles than visible angles, but after experimenting with it, this is really a no-no. 

It's really annoying to see the ship move to a direction it is not pointing at even if the difference is very subtle.

So, it may be just as well assumed the table is 32 values long.

Oh, and the above table is not directly applied to the sprite coordinates, but to the ship inertia X/Y values, which are in turn 16-bit values.

These again have the initial value of $8000, $8000. (low byte=$0, high byte=$80)

If the ship angle is stored in register Y, then the above table can be used to alter inertia.

sec
lda inertia_x_lo
sbc #$80
sta inertia_x_lo

lda inertia_x_hi
sbc #$0
sta inertia_x_hi

sec
lda inertia_y_lo
sbc #$80
sta inertia_y_lo

lda inertia_y_hi
sbc #$0
sta inertia_y_hi

clc
lda inertia_x_lo
adc move_anglex,y
sta inertia_x_lo

lda inertia_x_hi
adc #$0
sta inertia_x_hi

clc
lda inertia_y_lo
adc move_angley,y
sta inertia_y_lo

lda inertia_y_hi
adc #$0
sta inertia_y_hi

Sooo the $80 is first subtracted from the inertia values, and then the motion (with the $80 baked in the values) is added. There must be a more clever way but this is the one I used.

The inertia values are then used similarly to affect the ship (24-bit) coordinates.

This is for the x coordinate, for the y coordinate it's the same. It may be useful to keep them separate.

sec
lda ship_x_lo
sbc #$0
sta ship_x_lo

lda ship_x_hi
sbc #$80
sta ship_x_hi

lda ship_x_highest
sbc #$0
sta ship_x_highest

clc
lda ship_x_lo
adc inertia_x_lo
sta ship_x_lo

lda ship_x_hi
adc inertia_x_hi
sta ship_x_hi

lda ship_x_highest
adc #$0
sta ship_x_highest

The main game sprite is simple, but it does have a layer of anti-aliasing, using another sprite. These were generated using Processing. There are 32 frames, making a total of 64 sprite frames for the UFO.

For each frame, the sprite graphics data are copied from outside the video bank area to the visible sprite frame, as 64 sprites would take a huge chunk of the video bank and this didn't fit into my plan. I'm now getting to understand how important it is in C64 programming to have a good plan for locating the graphic data and the video bank.

With this technique I could have had 64 frames (128 with anti-aliasing), but I felt it easier for the player if the vertical and horizontal positions can be more clearly discerned.

The thruster flame has only one frame but it is positioned differently in alternating frames to give it more direction and a tiny bit of transparency, again using a polar coordinate shift.

Four sprites are used on the lanterns, although with multiplexing they could have used up less. But I didn't want to practice multiplexing this time, it was enough to handle the above issues and sprite-to-sprite and sprite-to-background collisions.


Wrap up

Looking at my notes, I worked on the game intensively for a few weeks in May 2020. Some of the routines had been done previously so I didn't have to "invent" the inertia, polar coordinate and precision coordinate routines then. So adding that I might have worked on this for about month.


It appears I considered a release at end of June 2020, but decided to wait. Then I picked it up on this weekend, with the idea I might be heading towards a phase of adding things to the game. 

But instead I simply cut off loose ends, adjusted some of the musics, added some graphic variety, removed anything that still looked like a bug, tested it on a real C64 and released it.

Design-wise, there was a lot that could have been added, but at this point every addition would have needed another round of testing and assessing the whole game, so it was better to keep the original promise of a "small game".

Leilei Relay at csdb


Thursday, 27 December 2018

Digiloi: Action game with C64 default characters


Digiloi is a game I made for Commodore 64, using only the default character graphics (PETSCII) for visuals. For some time I've wanted to use this approach. Fort Django used PETSCII for the backgrounds, but all the gameplay worked with sprites.

There's nothing special about using PETSCII for games, it was done a lot back in the day. However, not many full screen action games were done using the technique, probably because sprites are far more useful and the clunky char-by-char movement was not that attractive.

This visual style is closer to ZX Spectrum game programming techniques, even if the Speccy does not have a character display. Many ZX games had movement restricted to the color grid, with big player "sprites" to compensate. Don Priestley used his unique techniques in Benny Hill, Popeye, Trap Door, Flunky etc.

Left: The old-style forest. Right: UFO attacks
Later, others made fast arcade type games with a more streamlined approach, for example Dan Dare III, Savage!, and Extreme. What I've done is a bit of a compromise between these, an arcade game following Priestley's non-scrolling style but ignoring the more complex aspects of his routines.

I could not achieve 50 frames per second for these big dudes. I wondered if I could stick to 1/2 or 1/4 framerate, knowing that each frame would add greatly to the amount of code that can be executed. I went for 1/3, which is something like 16.67 frames per second on a PAL machine.

I use 256-byte aligned buffers for holding the current screen background and building the screen for displaying. I discarded the idea of double-buffered page swapping routines as the color memory in this mode is fixed at $D800 anyway.

The visuals and game logic are orchestrated like this:

Frame 1:
The background screen & colors, which were built on entering the "room", are copied to the respective 256-byte aligned buffers using speedcode. Copying 2K of characters and colors takes nearly the entire frame.

+joystick poll, music/fx play

Frame 2:
The 8 x 8 character "sprites" are drawn over the 256-byte aligned buffers. Each large "sprite" graphic is stored in 143 reverse-ordered data bytes including color and line-padding zeroes. Some smaller graphic elements, like bullets, are drawn using hardcoded routines.

This uses something like third of a frame, depending on how many movable objects there are on screen.

+joystick poll, music/fx play

Frame 3:
The 256-byte aligned background buffer is copied to the visible screen using speedcode. Again, this is 2K and takes nearly the entire frame.

+joystick poll, music/fx play

During each frame the interrupt plays a GoatTracker SID tune and polls the joystick.

With this approach I balanced speed, memory and convenience. Especially I like convenience. The 256-aligned buffers are quite handy. When transfering the 8x8 character elements to the buffer, the writing address hi byte is INCed with self-modifying code to reach the next vertical line whereas X register handles the horizontal coordinate.

I already think I might have the graphic shapes erased with routines similar to drawing them, resulting in a faster screen clean-up. Also, I probably could use the X/Y registers without having to resort to the INC gimmick. But once I had my routines in place, I kind of prefer the 1/3 because it gives automatically a nice gameplay speed without having to slow things artificially. Convenience.

With the visuals, I took the easiest, black-background PETSCII approach. I noticed that PETSCII game visuals need a somewhat different approach than static screens: The overlaid "sprites" have to go well with the background without too large black outlines. I initially gave the main character a more rounded look as I would do in a picture, but this did not work with the background. I took most of the rounding off.

This not only influenced the character design but the backgrounds too, so there's more black empty space than would look good in a static picture.

2017? Well, um... I've been sitting on it for a while.
The game is pretty much 100% written in assembler, unlike Fort Django, which still had a fair amount of C code in it. There is still a short C scaffolding for initializing stuff, but after kicking off the main loop it's all asm.

I now feel it's not that much more difficult as the assembler can work quite easily with "variables" and tables, and the X and Y index registers make it easy to have array-like structures for game objects. Using the stack to store registers, it's possible to have hierarchical subroutines and sub-subroutines for various tasks and associated labeled memory locations as "local variables" if need arises.

Tools used:
  • CC65 cross-development package. This has C and assembler together. C is nice for initializing and testing ideas, though it seems I'm relying less and less on it. The included assembler has some things lacking in the code alignment and positioning department (stuff promised in the manual does not seem to work).
  • The text editor included with Linux Mint Mate, Xed or whatever it's called nowadays. Later in the project, I moved to Sublime Text with added 6502 asm highlighting.
  • VICE emulator. Obviously.
  • C64Debugger from Samar Productions. A neat tool for examining C64 memory content live as it is emulated. This was useful in getting the 256-byte aligned buffers working.
  • Marq's PETSCII editor. Not only it is good for creating static PETSCII screens, it does a good job with tiles and animated graphics. I did add custom ordered exporting code, though.
  • GoatTracker 2.73. Does the job well and has simple to understand sound fx routines (after understanding them, that is) and easy export.
  • Tiled. A friendly enough map editor that outputs csv. It's nice to be able to grab larger entities from the map or the tilesheet and paint with them. The tiles are exported as PNGs from the PETSCII editor straight into a tile sheet for Tiled.
  • Processing. For generating some of the tables and converting the Tiled csv directly into ordered room list in an assembler-friendly format. Also, the PETSCII editor modifications are made with Processing.

Commodore Plus/4 conversion note

As the game routine operates most heavily in an invisible back-buffer, there are not that many unique routines and addresses in use. So I could convert the game fairly fast to plus/4 simply by changing the speedcode to point to plus/4 character and color memory addresses.

The joystick reading needed a bit more investigating, but it's not that much more complex than on a C64. I added a keyboard key reading too to switch the music on and off. Sadly, there's only SID support on the sound side.

plus4 version
I re-painted the graphics using the PETSCII editor's plus/4 conversion as a starting point. Some coloring was hard-coded to the source (tut-tut!) but not at too many places. The result is not that different from the C64 original, but it has a bit more shine here and there.

It's more interesting to see that the code runs roughly 30% faster at places, even without trying any plus/4 specific tricks. More could be achieved with plus/4 on this type of game, than on a C64.

I can also see that despite having twice as fast processor, it does not mean a 2x speed. But, certainly the 1/2 framerate might be a more realistic goal even without modifying the routines too much.

*** 28.12.2018 plus/4 addition: The speed-up I'm talking about is not really present in the originally released Plus/4 conversion of the game. I have made a speeded up demo for plus/4 available at the download links below so you can see the game running at 25fps.

However this is a rough-at-the-edges implementation and I have no guarantee it works well all the time. Also, as the game runs faster it may be less playable. The plus/4 is quite a neat computer!


Some reflections

I've wondered why I don't finish more stuff. It's not really about available time.

My projects tend to follow this script:

1. Become enthusiastic about a visual/logical solution for graphics and animation routines, which are at first built with care and reason
2. Start building the game logic with fundamental routines, still maintaining neat hierarchy
3. Lose momentum. Become bored and make new additions without much thought, adding stuff outside the existing hierarchy, generating potential problems difficult to solve later
4. Hastily wrap up. Instead of creating more gameplay & narrative, be happy with finishing the thing

If something disturbs the game within phase 1-2, it's possible that the project never gets completed. If it gets past phase 2, I can at least stubbornly make a finished piece out of it.

One antidote is to try to make the start/game over/finishing logic fairly early on in the project, so it's basically "finished", although there might be a lot to do on the other parts. This is something I did here.

It might seem that more game content would be just incremental work. But again, creating and testing game content becomes increasingly painful as the game gains size. Add a level, it has to be tested. Add a monster type, all the rooms with it have to be tested. Add a weapon, all the areas have to be tested again.

No wonder games are sometimes pre-planned before coding anything. But I find it infinitely boring to try to design a whole game beforehand and then just code it, as lot of the fun arises from trying varieties and discovering things as I go along.

I'm also speculating that fatigue strikes because incremental work stages are boring. The first coding stages often bring an euphoria of seeing exponential results as a result of tiny amount of work or changes.

You'll need a Commodore 64 computer or a C64 emulator to play this game.

Direct download of D64 disk image with Commodore 64 and Plus/4 programs
Digiloi at csdb
At plus4world

Download the prg for the Commodore plus/4 speeded-up demo version here

Friday, 15 December 2017

ak tronic EPROMkarte 256k


This is an ancient device for the Commodore 64 I got a few years back. The on-board chip appeared to be corrupt and only now I've had a chance to re-write the binary, which gave it life.

What is it? Truth be told, I'm not exactly sure what it is intended for. I guess it can be seen as an alternative storage device. It works as a 8-chip "carousel" cartridge EPROM switcher with the software-based selector menu burned in the 9th chip.

Hold your horses, though, it won't run your freeze/fastload cartridge collection. Even if the device accepts 8K, 16K and 32K chips, it will only run 8K-sized chunks which rules out most games. I tried Gateway to Apshai 16K binary, but it won't run.

(As an aside, it seems some early C64 games were a bit minimal not because the programmers couldn't do more, but because they wanted to fit the games inside a 16K cartridge space...)

This is model 2140 from ak tronic, perhaps from around 1984. There's some info on net but less binaries to replace the corrupt chip. After some searching, I could find the binary for the on-board EPROM, for a similar REX 9574 card from Rex Datentechnik.

The device binary was inside a D64 disk, so I had to take two bytes off the beginning to get the 8192 byte length. A similar procedure needs to be done for any emulator cartridge files (.crt), but more bytes have to be stripped off. The CBM80 identifier is helpful, but I don't see it in all binaries, what's with those carts?

The file length is usually the best clue, 16384 for true 16K binary, 8192 for 8K and so on.


Running the C64 I am greeted with a menu for selecting one of the 8 chip slots, show the directory or enter the "modul master", which I guess is a tool for annotating the chip contents.

After selecting the chip I have to select what kind of chip it is, a 2764, 27128 or 27256. If the chip is larger than 8K, I also have to select which half or quadrant of the chip I am running.

A couple of boring 8K things I got up and working:

-Assembler and Monitor (SYS 700 for asm and SYS 32777 for monitor)
-Calc Result (needs a disk so it's a dongle really)

If you insert 8 x 32Kb EPROMs on board, you get the theoretical 256k, but in 32 x 8k portions.

For burning a 16K EPROM I can append two 8K files to make up a 16K binary with the cat command on Linux:

cat filename1 filename2 > output_filename



Switching EPROMs from software:

Looking at the manual, there are a couple of routines to access the chip memory without resorting to the main menu.

After exiting the card menu, this should run it again (if the control EPROM has been selected).

X=PEEK(57280): SYS 64738

BIT $DFC0
JMP $FCE2

Card addresses:

$DFC0 (57280) : Switch the card on/off
$DFE0 (57312) : Switch control/user EPROM
$DFA0 (57248) : Select the EPROM chip #

This way an EPROM can be selected:

POKE 57248, half/slot
X=PEEK(57280): REM switch on/off the card

The user EPROM needs to be on too.

The half/slot value is construed this way:

2764 8KB chip:$30 = 48

27128 First half: $10 = 16
27128 Second half: $30 = 48

27256 1/4: $00 = 00
27256 2/4: $10 = 16
27256 3/4: $20 = 32
27256 4/4: $30 = 48

The lower nybble indicates the eprom slot 0-7. So $31 (49) selects the second half of the 27128 at slot #2.

In assembler, this subroutine selects/deselects an EPROM:

* = $C000
C000        LDA #$10        A9 10
C002        STA $DFA0       8D A0 DF
C005        BIT $DFE0       2C E0 DF
C008        BIT $DFC0       2C C0 DF
C00B        RTS             60

Then call $C000 (49152).

The first half of the first 27128 EPROM now occupies space from 32768 onwards. Then SYS 64738 ($FCE2) runs the cartridge if that's what is needed.

For some reason, selecting slots was not always successful, the manual indicates $10 and $30 for selecting the 8K halves of a 27128 chip, I tend to find that $20 and $30 work more consistently... but perhaps not always.

I've not been able to reproduce these anomalies reliably. I found myself checking whether the cart memory was truly present, scanning the memory contents from $8000 (32768) onward. Possibly I don't understand something, or the card is a bit faulty from age.

For this reason I've not tried to change the control EPROM code, because the selector there at least works reliably. This also makes me think there is more to know about the routines.

Oh, and when the cart is on (57280), Basic seems to behave erratically and the disk device fails to work.

Sooo... Maybe it's not a too useful device in these days, but let's see if I can come up with something fun. As the EPROM memories can be paged in via software, for example some kind of animation could be played back from the chips.

Saturday, 3 December 2016

6502 notes

I've been dabbling in 6502 machine code for a long time, but only recently started to get a hold of it. My initial touchpoint was the machine code monitor on the Action Replay VI module on the C64 and a battered copy of the Commodore 64 Programmer's Reference I found from a flea market in early 1990s.

Which I obviously still have.

These days, I know a bit more, but certain things are difficult to remember. Here's some.


How the Carry (C) affects the ADC and SBC instructions (and the difference)

For the longest time I did not get this. For additions, carry is cleared (with CLC) and then becomes set if the addition crosses the 255 boundary. The C flag is then carried (duh) over to the next ADC instruction as a +1. With subtraction, it's the reverse: the carry is previously set and then becomes cleared if the subtraction crosses 0. When clear, the SBC #$00 performs a SBC #$01, for example. After this, 16-bit addition and subtraction became easier to understand.

;Incrementing a 16-bit value at $C000-$C001 with ADC

    CLC          ;Clear Carry
    LDA $C000
    ADC #$01     ;if $FF is crossed Carry becomes set
    STA $C000
    LDA $C001
    ADC #$00     ;is like 1 if Carry is set
    STA $C001

;Decrementing a 16-bit value at $C000-$C001 with SBC

    SEC          ;Set Carry
    LDA $C000
    SBC #$01     ;if $FF is crossed Carry becomes clear
    STA $C000
    LDA $C001
    SBC #$00     ;is like 1 if Carry is clear
    STA $C001


When is the Overflow (V) flag set?

This flag is not that useful to me, but I don't want to forget what it does.

As two bytes are added together with ADC, as above, the calculation is at the same time evaluated as unsigned and "signed". If the numbers as "signed" cross a boundary of (-127...128) the overflow will be set.

I've come across a misconception that says "if the 7th bit of the original value and the resulting calculation are different, then the overflow is set."

However, the following will not trigger the overflow flag, even though the 7th bit clearly changes:

    CLC
    LDA #$FF     ; 0b11111111 (-1) is the original value
    ADC #$02     ; 0b00000010
                 ; 0b00000001 (+1) is the result

I won't go around doing the two's complement explanation, which frankly just makes it more difficult to understand for me. Let's just have a look at how the signed numbers work:

Positive values:

00000000 = 0
00000001 = 1
00000010 = 2
00000011 = 3
00000100 = 4
...
00001000 = 8
...
00010000 = 16
...
00100000 = 32
...
01000000 = 64
...
01111111 = 127

The negative numbers have their minus sign bit set:

11111111 = -1
11111110 = -2
11111101 = -3
11111100 = -4
11111011 = -5
...
11110111 = -9
...
11101111 = -17
...
11011111 = -33
...
10111111 = -65
...
10000000 = -128

There's no special "signed mode" for the ADC command. Simply, if within the above representation, you do a calculation that crosses over 127, or under -128, the V flag will be set. Just like the C will be used when crossing over 0...255 in the ordinary representation.

So what the above example does is -1+2, which does not cross this boundary any more than 1+2 would set the C flag.

The reformulated rule: "If values with a similar 7th bit are added together, and the 7th bit changes, the V flag is set."

For the most part I don't see the point of the signed-system, as I can usually pretend that 128 or 32768 is the zero point in an unsigned calculation.

Here, have a picture of a silly robot that makes it all easier to understand.

How the Indexed Indirect and Indirect Indexed addressing modes work

Most of these things have no place in fast code, hence I had not really looked at them.

Perhaps the funniest personal discovery was to see that it's possible to point to a 16-bit address using the indirect indexed addressing mode. I did not know the 6502 was capable of doing this so directly (relatively speaking). It's like z80's ld (de),a but not really. Because there is no 16-bit register as such, incrementing the address is a matter of using the ADC on the stored value as described in the first topic above.

Usually a memory fill is done effectively with something like this, which would fill the C64 default screen area with a "space".

    LDA #$20
    LDX #$FF
loop:
    STA $0400,X
    STA $0500,X
    STA $0600,X
    STA $0700,X
    DEX
    BNE loop
    RTS

We can write the start address to a location in a zero page and use the indexed indirect mode to write to the address, at the same time incrementing the stored value with a 16-bit addition.

Some have suggested that the zero-page works as a bunch of additional "registers" for the 6502 and this seems to validate that idea slightly.

(It is extremely slow, though)

    LDA #$04    ;high byte of start address $0400
    STA $11     ;store at zero page
    LDA #$00    ;low byte of start address $0400
    STA $10     ;store at zero page
    LDY #$00    ;we won't change the Y in the following
loop:
    LDA #$20    ;fill with ASCII space       
    STA ($10),Y ;write to address stored at zp $10-$11
    CLC         ;clear Carry
    LDA #$01    ;low byte of 16-bit addition
    ADC $10     ;add to low byte

    STA $10
    LDA #$00    ;high byte of 16-bit addition
    ADC $11     ;add to high byte (+Carry)
    STA $11
    CMP #$08    ;are we at $08xx?
    BEQ exit
    JMP loop
exit: 
    RTS



When to use BPL, BMI, BCS, BCC branching operations

Some of my earliest code tended to work with BEQ and BNE only. Quite a lot can be achieved with them. The classic loop already used above, works without comparison instructions at all. Besides this, it can make a big speed difference how the '0' is used in data/tables.

    LDX #$0B
loop:
    INC $d020
    DEX
    BNE loop

My first instinct has been to use the BPL and BMI opcodes as they sounded nice and simple: Branch on PLus and Branch on MInus.

However, the BPL/BMI work with the signed interpretation discussed above. Parts of code might work as intended if the numbers happened to be in the +0...127 boundary, which probably confused me in the past.

So the BCC (Branch if Carry Clear) and BCS (Branch if Carry Set) are used instead when dealing with unsigned number comparisons, even if they sound less friendly.

    LDA #$20
    CMP #$21
;C=0

    LDA #$20
    CMP #$20
;C=1

    LDA #$20
    CMP #$1F
;C=1

This ought to branch if the A value is lesser than the one it is compared to:

    LDA #$1F   ; $00-$1F will result in C=0
    CMP #$20
    BCC branch ; (branches in this case)

The next one branches if the A value is equal or greater than the one it is compared to:

    LDA #$20   ; $20-$FF will result in C=1
    CMP #$20
    BCS branch ; (branches in this case)


So, yeah.

Strangely enough many of the webpages and even books about 6502 are incomplete when it comes to explaining in detail what each of the commands do. Even the books might just state that a particular opcode "affects" a certain flag, but may not open up how exactly that flag is affected.

Saturday, 23 July 2016

Fort Django

A little reflection on the making of a Commodore 64 game. It's the first C64 machine-code game project I've really finished. All right, it was made with cc65 C with inline assembler but what I mean it's not made in BASIC. Significantly, it's the first 8-bit game I've made public in some way.

I guess making an 8-bit game is something I would have liked to do for a long time. Fort Django was started in 2014, and after a long pause I found the energy to make it into a release.

Djangooooooooohh....!
The game

You guide the character with a joystick in port 2. You can run, climb, crouch, jump and shoot. Shoot down the baddies, collect money bags and find the exit. The descending bonus timer means the faster you can collect the next bag the more $ you can get.

The game is very short and not at all hard. The only challenge comes from trying to be faster, for example it's possible to break the $10000 barrier on completion.

Get that bag, shoot that baddie
Inspired by Saboteur! from Durell, I at first thought about making a beat 'em up oriented game. As I needed to scale down the project I found it would be simpler to turn the game into a shooter with a western theme. The map is very small, but then again I like short games such as Saboteur! and Bruce Lee, as they have a strange kind of replay value. Much like with Saboteur!, I wanted to ensure there was a definite ending to the game and score could not be milked forever.

Making of

I created the game with cc65 C compiler, using inline-assembler for speed critical parts such as the sprite routines. The C64 has eight sprites, eight 8-bit addresses for the horizontal coordinate (0-255) and one address that holds the highest bits for all the X coordinates, so the sprites can also reach the right hand part of the screen. (256-320)

For a beginner it can be a bit tricky to decode these 9-bit sprite coordinates, especially in pure assembler. I have eight separate 16-bit memory locations for storing the X coordinates. These are then broken down into the hardware sprite coordinate values. This approach is a compromise between ease of use and speed.

The figure below shows how the 16-bit X coordinates are stored in $C000/$C001, $C008/$C009, $C010/$C018 byte pairs (the grey stuff in the middle). The less significant byte of these 16-bit values can be copied directly to the $D000, $D002, $D004... but the high bit is taken from the lowest bit of the most significant byte of the 16-bit values and combined into a value that is stored in $D010.


This is done once in a frame, so the high-bit issue can be forgotten in other parts of the code. The handiness of this is only really apparent in C, where you can then move the sprite x coordinate around with:

*(unsigned*)0xc000=*(unsigned*)0xc000+1;

Comparisons between coordinates become easier, too.  This checks if sprite 7 is right of the sprite 0:

if(*(unsigned*)0xc038>*(unsigned*)0xc000){do_stuff();}

Basically all the "collision detection" is built from this type of statements instead of the hardware sprite collision address, and as such is not pixel perfect. In these box-collision cases it's better to be lenient toward the player and a bit biased against the enemies.

The "16-bit" coordinate ought not to exceed 511, because only one bit is taken from the more significant byte.

The sprite Y coordinates are 8-bit values anyway and can be handled directly with the $D001, $D003, $D005... hardware addresses.

The whole X coordinate copying is achieved with the code below, starting from the less significant byte copying and ending with the high-bit construction. Obviously other locations than $C000- can be used for the coordinate storage.

     lda $C038
     sta $D00E
     lda $C030
     sta $D00C
     lda $C028
     sta $D00A
     lda $C020
     sta $D008
     lda $C018
     sta $D006
     lda $C010
     sta $D004
     lda $C008
     sta $D002
     lda $C000
     sta $D000

     lda $C039
     clc
     rol a
     ora $C031
     rol a
     ora $C029
     rol a
     ora $C021
     rol a
     ora $C019
     rol a
     ora $C011
     rol a
     ora $C009
     rol a
     ora $C001
     sta $D010

This is a starting point for a fairly generic solution, but of course it can be adapted for any particular needs. For example, the top sprite coordinates of the dudes in the game are copied and transformed from the bottom part coordinates, which changes the above routine a bit. Also, if less sprites are used why bother going through all the eight?

About the graphics

The graphics are made with PETSCII editor. Not only the background tiles, but the game map and even the sprites have been edited there. It goes to show that the PETSCII editor multiframe-editing is surprisingly powerful way for controlling this type of game "assets".
The game map tiles.
Another PETSCII screen was wasted for defining the movement rules for the above tiles. These are used for building a movement table every time the player enters a room, just as the room is drawn from tiles. How all these sprite, tile and movement table elements exactly relate to each other is a bit too intense to explain here, especially as they are not that well thought out.
The tile movement rules. @=space, A=block, B=platform, C=ladder
The map was also edited in the PETSCII editor. The 40x25 area is divided into 5x3 tile elements, giving 64 simple screens. Coloring indicates enemies and money bags. Not everything is absolutely visible in the picture below, as some spaces can be "colored" too. The game engine allows only certain combinations and positions for the enemies and objects.
The game map.
The map memory area is also used for indicating whether objects or enemies are removed, from the 1 (white=enemy) and 2(red=bag) status into 255 and 254. After the game is over these are changed back into 1 and 2.

Editing a multicolor sprite in PETSCII editor. The sprite export is not a standard feature!

What next?

I dropped many game elements I toyed with at some point. For instance, the chests could have contained items, and the doors could have potentially led to other areas in the fort.

The gold bags were a fairly late addition when I felt that only shooting bad guys would be far too minimal. From adding the bags it was a small leap to increase the jumping elements in the game. The bags also inspired the time-based "bonus dollars" mechanic. Still there might have been a bit more to do.

Code-wise, a music routine would have been nice but in the beginning I was a bit scared to sync the animation with a music interrupt. The sound effects are also sparse due to my inexperience with SID.

Yet, all additions would have also expanded the complexity of the game and the testing time exponentially. I'm glad I could finish it as it is. With this experience I already have some ideas about how to approach this type of project better.

Links

You'll need a Commodore 64 or an emulator to play the game.

Fort Django v1.1 at CSDb
Read the blog post about the v1.1

1.0 (older version):
Direct download
Alternative link
Page at CSDb
A cracked version in a T64 format