




Reviving my R-Type clone for the Commodore PET – now reimagined in C using the CC65 compiler.
Back in 2021, I embarked on creating a game for the Commodore PET. Initially, it was developed in pure 6502 assembly via TRSE—an arduous yet fulfilling experience.
After some life events, the project lay dormant until this past weekend. I decided to revive it by converting the code to C using the CC65 compiler.
Embracing the Essence of a Classic
This project takes cues from Irem’s legendary 1987 arcade game R-Type, adapted considerably to suit the PET’s hardware limitations.
While I can’t replicate the arcade’s stunning 16-bit visuals or intricate sprite mechanics, I aim to capture the core elements that made R-Type memorable.
Commodore PET Technical Limits
- 1MHz CPU compared to Irem’s 16-bit M72 arcade system with co-processors
- Character-based movement and collision vs. pixel-perfect sprites with hardware scrolling
- Minimal sound capabilities vs. Yamaha synthesized sound with a dedicated Z80 co-processor
Core Mechanics (classical “dodge and shoot” gameplay loop):
R-Type featured smooth pixel-perfect scrolling. I’m implementing character-by-character scrolling while creatively using PETSCII characters to suggest a sci-fi atmosphere.
The scrolling maintains a sense of progression and exploration, despite the lack of colors and intricate designs.
- Player ship that moves in four directions and fires
- Predetermined enemy patterns and movements for players to master
- Basic collision detection
I plan to incorporate a tile system for R-Type-style level layouts, although not as expansive or detailed.
Key Missing Features
While my intention isn’t to duplicate R-Type, I aim to create an engaging shooter for the PET that honors the original.
- No Force pod, R-Type’s signature drone-like power-up system
- Simpler enemy patterns due to character-grid movement and restricted memory
- No charge-up beam system (although a basic version could be possible)
The Conversion Journey: From Assembly to C
Transitioning from TRSE and 6502 assembly to C with CC65 presented unique challenges. The original assembly code utilized direct hardware access for screen and keyboard interactions, and I aimed to maintain the good aspects while enhancing readability and flexibility by porting logic to C.
Key Challenges:
Memory Management
The assembly code directly accessed memory via labels, heavily utilizing zero-page locations. Most of the code shifted to named variables, but I retained zero-page usage for essential pointers.
Screen Handling
The assembly version manipulated screen memory directly with PETSCII character codes. I kept this direct memory access at 0x8000 but converted it to a more understandable functional approach.
I’m also testing double buffering for smoother, flicker-free animations.
The 40×20 character display constraints were maintained to give a widescreen effect while minimizing screen processing.
I mapped key PET hardware registers in C:
- Interrupt flag (
0xe813) - Timer location (
0xe840)
So Why Use C If Assembly Worked?
Despite the success of assembly, navigating and refactoring that complexity became challenging. Transitioning to a higher-level language like C—while retaining the option to dip into low-level assembly—offers improved maintainability and quality of life.
Structured Data Types
-
Function Organization
- Segmented my monolithic assembly into logical C functions and headers
- Established a clear separation between screen management, game logic, and input handling
- Kept direct hardware/memory access where necessary for performance
New Features
The C conversion allowed me to introduce several features difficult to implement in assembly:
-
Enhanced Enemy System
- Diverse enemy types with distinct movement patterns
- Structured enemy state management
- Timing animations through movement counters
-
Improved Bullet System
- Advanced projectile handling
- Enhanced collision detection
- Active state management
-
Enhanced Screen Management
- Option for double buffering
- More efficient screen updates
- Improved vsync handling
Although C code is often seen as less efficient than hand-coded assembly, much of this depends on the specific compiler. I’ve introduced various optimizations to preserve satisfactory performance:
-
Memory Access
- Smart usage of zero page for critical variables
- Direct memory writes for screen updates
- Effective buffer management
-
Display Updates
- In sync with vertical blank
- Character-based sprite architecture rather than simulating “chunky pixels”
- Optimized screen buffer transfers
Current Status
The game now boasts a robust foundation in C, retaining as much performance from the original assembly version as possible. The codebase is notably more maintainable and extendable, all while respecting the PET’s hardware constraints.
Future Enhancements
Currently, the game utilizes a hard-coded array for level data. My next significant update will introduce a proper tile-based mapping system:
Map Structure
struct MapTile {
unsigned char type; // Tile type (wall, floor, hazard, etc.)
unsigned char properties; // Collision, damage, etc.
};
- Tile properties will be defined in a separate configuration, with enemy placements indexed by ID.
- Simple text-based level files for easy visualization and editing—no map editor tool required (for now).
- Support for multiple levels with more memory-efficient tile and map storage (my initial array is bloated but allows quick rendering).
This will facilitate easier level creation and adjustments while allowing for different environments to be added to the game. The challenge will be to implement this without affecting gameplay speed.
Other Planned Features
- Basic sound effects utilizing the PET’s single-bit audio output (simple beeps for shooting, collisions, etc.)
- More varied enemy types and movement patterns
- A power-up system
- Enhanced collision detection
- Level progression
Note on sound: The original Commodore PET only features a single-bit output through the CB2 line, limiting me to basic beeps and buzzes. This is quite restrictive compared to later models like the C64 with its SID chip, but I can still integrate straightforward sound effects to enrich gameplay. Timing these will require careful CPU management, as there’s no dedicated sound hardware.
Technical Insights
Memory Constraints
- Screen Memory: 800 bytes (40×20)
- Tile Data: Approximately 256 bytes for tile attributes
- Level Data: Varies based on map dimensions
- Game Logic: Remaining available RAM
Performance Considerations
- Need to refine tile lookups
- Optimize map scrolling algorithms
- Careful monitoring of memory access patterns
- Balancing features with speed
The tile system requires meticulous optimization to ensure smooth gameplay while allowing for proper level design.
Final Thoughts
While I’m not an expert in C or 6502, I now have a better grasp of both, which is invaluable. Transitioning from assembly to C has broadened my options for expanding this game, teaching me significant lessons about each language.
Implementing the planned tile system will greatly enhance my current hard-coded method, making the game more dynamic and easier to develop.
This project remains a challenging yet enjoyable endeavor, working within the constraints of vintage hardware while implementing modern game design concepts!
Original article by retrogamecoders.com


