Back in 2021, I started working on a game for the Commodore PET. The original version was written in pure 6502 assembly, via TRSE – a challenging but rewarding experience.
Life happened, and the project sat dormant until this weekend when I decided to dust it off and give it new life by converting it to C using the CC65 compiler.
Capturing the Spirit of a Classic
My project draws inspiration from Irem’s iconic 1987 arcade game R-Type, though obviously with significant adaptations for the PET’s limited hardware.

While I can’t match the arcade’s beautiful 16-bit graphics or complex sprite system, I can capture some of the core elements that made R-Type special.

Commodore PET Technical Constraints
- 1MHz CPU vs Irem’s 16-bit M72 arcade system with co-processors in the original
- Character-based movement and collision vs pixel-perfect sprites and scrolling via hardware
- Limited to no sound capabilities vs Yahama synthesised sound with dedicated z80 co-processor
Core Mechanics (classic “dodge and shoot” gameplay loop):

R-Type had smooth pixel-perfect scrolling, I’m implementing character-by-character scrolling and using PETSCII characters creatively to suggest a sci-fi environment.
The scrolling still creates a sense of progression and discovery, even without the colours and details.
- Player ship that move in 4 directions and can shoot
- Pre-set enemy patterns and movement – Players learn the patterns to make significant progress.
- Basic collision detection
My planned tile system will allow for R-Type-style level layouts, but not be as large or as detailed.
Key Missing Features
My goal isn’t to clone R-Type (even if that was possible), but to create an engaging shooter for the PET that pays homage to it.
- No Force pod (R-Type’s iconic drone-like power-up system)
- Simpler enemy patterns due to character-grid movement and lack of memory
- No charge-up beam system (though I could implement a more basic version)
The Conversion Journey: Assembly to C
Converting from TRSE and 6502 assembly to C using CC65 was an interesting challenge. My original assembly code used direct hardware access for screen manipulation and keyboard input. I needed to preserve what was good while making it more readable and extendable for me by porting the logic to C.
Key Challenges:
Memory Management
My original assembly code, by nature of assembly, used direct memory access via labels, and especially used zero-page locations. Most of the code switched over to using named variables, but I kept zero page usage for: text pointer (0x68), destination (0x6A), map pointer (0x6C), and screen destination (0x6E)
Screen Handling
Assembly version had direct screen memory manipulation using PETSCII character codes. I kept the direct screen memory access at 0x8000 but converted to an easier to read and understand functional approach.
I am also experimenting with double buffering for smoother, flicker-free screen updates / animation.
Maintained the 40×20 character display constraints to give the widescreen effect and also keep screen processing to a minimum.
Had to map key PET hardware registers in C:
- Interrupt flag (
0xe813) - Timer location (
0xe840)
So why use C if the assembly obviously worked?
Yes, the assembly and TRSE development environment worked to get an initial demo working, I increasingly was getting lost or refactoring just so I understood my own project. Using a more familiar higher level language, with the option to drop down to low-level assembly, provides quality of life and maintainability benefits.
Structured Data Types
- Introduced proper C structures for game entities:
struct Enemy {
int x, y;
unsigned char active;
unsigned char sprite;
unsigned char move_type;
unsigned char move_counter;
};
- Introduced proper C structures for game entities:
Function Organization
- Broke down my monolithic assembly code into logical C functions and header files
- Created clear separation between screen management, game logic, and input handling
- Maintained direct hardware/memory access where needed for performance
New Features
The C conversion allowed me to add several features that would have been more challenging in assembly:

Enhanced Enemy System
- Multiple enemy types with different movement patterns
- Proper enemy state management
- Movement counter for timing animations
Improved Bullet System
- More sophisticated projectile handling
- Better collision detection
- Active state management
Better Screen Management
- The option of double buffering implementation
- More efficient screen updates
- Better vsync handling
While C code is naturally thought of as being less efficient than hand-crafted assembly, a lot of the bloat is highly dependent on the specific compiler, plus I’ve implemented several optimizations to maintain good-enough performance:
Memory Access
- Strategic use of zero page for critical variables
- Direct memory writes for screen updates
- Efficient buffer management
Display Updates
- Synchronized with vertical blank
- Character-based sprite system rather than simulate “chunky pixels”
- Optimized screen buffer copying
Current State of Play
The game right now has a fairly solid foundation in C while maintaining as much as possible of the performance of my original assembly version. The codebase is definitely more maintainable and easier to extend, while still taking into account the hardware limitations of the PET.
Planned Improvements
Currently, the game uses a hard-coded array for level data. My next major update will implement a proper tile-based map system:
Map Structure
struct MapTile {
unsigned char type; // Tile type (wall, floor, hazard, etc.)
unsigned char properties; // Collision, damage, etc.
};
- Tile properties defined in the separate configuration above, with enemy placement via ID.
- Simple text-based level files for easy visualisation and editing without having to make a map editor tool (yet).
- Support for multiple levels with more memory-efficient tile and map storage (my original array stores a lot of unnecessary data but makes it quick and easy to render)

This will make it much easier for me to create and modify levels, as well as add different types of environments to the game. The trick will be implementing this without causing any added slow-downs in gameplay.
Other Planned Features
- Simple sound effects using the PET’s single-bit audio output (basic beeps for shooting, collisions, etc.)
- More enemy types and patterns
- Power-up system
- Enhanced collision detection
- Level progression
Note about sound: The stock Commodore PET only has a single-bit output through the CB2 line, which means I’m limited to basic beeps and buzzes. While this is quite limiting compared to later Commodore machines like the C64 with its SID chip, I can still use simple sound effects to enhance the gameplay experience. These will need to be carefully timed using the CPU, as there’s no dedicated sound hardware to offload to.
Technical Considerations
Memory Budget
- Screen Memory: 800 bytes (40×20)
- Tile Data: ~256 bytes for tile properties
- Level Data: Variable based on map size
- Game Logic: Remaining available RAM
Performance Impact
- Need to optimize tile lookups
- Efficient map scrolling algorithms
- Careful memory access patterns
- Balance between features and speed
The tile system will need careful optimization to maintain a smooth gameplay experience while adding the flexibility of proper level design.
Bottom Line
I am no more an expert in C than I am in 6502 but I can at least understand it better than I did, which counts for a lot. Converting from assembly to C has opened up new possibilities for extending my game while teaching me valuable lessons about both languages.
The planned tile system will significantly improve my current hard-coded approach, making the game more engaging and easier to expand.
This project continues to be a difficult but fun exercise in working within the constraints of truly vintage hardware while attempting/implementing modern game design patterns!


Program the BBC Micro in C with VBCC for 6502 on MacOS Using Docker