Written and Maintained by Gregory Nacu

NEWS, EDITORIALS, REFERENCE

Subscribe to C64OS.com with your favorite RSS Reader
January 11, 2019Programming Reference

C64 KERNAL ROM: Making Sense

The KERNAL is the heart of the Commodore 8-Bit computer family. Although each machine's KERNAL is slightly different, there is also substantial overlap in code and design.

The C64's KERNAL provides a standard jump table with 39 routines from $FF81 and $FFF3. The order of the entries in the jump table is stable, but not particularly logically organized. Most websites and books, including the C64 Programmers Reference Guide, list the routines in alphabetical order, or in the order in which they appear in the jump table. This makes it easy to find the details of any routine, if you already know which routine you want to use, but it can often lead to confusion trying to understand the relationship between the routines. Especially because many of them have similar sounding names, and in some cases similar functionality.

To improve clarity, and facilitate understanding of how the KERNAL should be used, I have grouped the routines into 7 conceptual KERNAL modules, shown in the table below.

C64 OS provides includable assembly headers which define labels for the KERNAL routines in each module. C64 OS itself is an extension of the KERNAL, and relies on the KERNAL for many tasks. For example, C64 OS's File module adds a thin abstraction layer over the KERNAL's file table and logical file numbering system. A C64 OS application that makes use of C64 OS File References can extract the logical file number from the file and use it to make manual KERNAL calls. The relationship of the KERNAL ROM to C64 OS, including a compatibility table, is discussed at the end of this post.

KERNAL Modules

Module Routines Include
File 6 ker_file.s
I/O 8 ker_io.s
IEC 9 ker_iec.s
Memory 6 ker_mem.s
Keyboard 3 ker_key.s
Screen 4 ker_scr.s
Time 3 ker_tim.s

I have never seen the routines grouped as these 7 modules before, but to me, they most logically and thematically fall into these groupings, which helps to understand how to use them.


File (6 Routines)

Among other things, the KERNAL recognizes 6 device types. Two of those device types, the Keyboard and Screen, it implements directly. And it provides implementations of the communications protocols with the other devices which may or may not be connected to the computer.

Each device is referenced by a unique device number, from 0 to 30. Device types are recognized by their fixed address or the address range they fall within. Some devices also support a secondary address, which is used to send it low–level commands.

Devices Table

Device I/O Device Number Secondary Address
Keyboard Input 0
Datasette Both 1 0, 1, 2
RS232 Both 2
Screen Both 3
Printers Output 4, 5 0, 7
Plotters Output 6, 7
Disk Drives Both 8... 30 0, 1, 2... 14, 15

The KERNAL provides a thin abstraction layer to reference devices, and in some cases subdivisions of a device. The abstract entity is called a logical file. Commodore may have been influenced by Unix, which treats everything—including devices—as files. On some devices, such as a Datasette or Disk Drive, logical files can also be associated with actual files, which are named collections of data stored on physical media.

January 11, 2019Help This Site Succeed

Dear reader and Commodore 64 enthusiast,

You've come here to read one of my high–quality, long–form, weblog posts. Thank you for your interest, time and input. It would be a lonely world without loyal and friendly readers like you.

I'm creating C64 OS and documenting my progress along the way, to give something to you and contribute to the Commodore community. Please consider buying a Commodore Logo Patch or making a small donation, to help me continue to bring you updates, in–depth technical discussions and programming reference. Your generous support is greatly appreciated.

Greg Naçu — C64OS.com

Want to support my hard work? Here's how!

January 4, 2019Programming Theory

Exceptions, Try/Catch 6502

I've been thinking about how to implement exception handling on the C64, for C64 OS. Exception handling would be useful for streamlining the handling of errors, and also for gracefully handling an application crashing under known exceptional conditions, with the ability to peacefully return back to the system's homebase application.

In this post, I'm going to talk about about why you would want to have exceptions, how they can improve your program design, and how they might be implemented for C64 OS.

Overview of Basic Program Flow Control

We're all familiar, even just from BASIC, with the usual program flow mechanisms. Execution of a program flows from top to bottom executing each step one after the next. The next simplest way to change program flow is with a branch which allows skipping over some code if a certain condition is not true. In BASIC this can be done with an IF statement that jumps over some code, to the following code.

The next most simple program flow control is the loop. In BASIC, there is a special language construct FOR/NEXT, which allows the program to return to the top of the loop and interate some number of times. In assembly, loops must be implemented with branches. But, instead of branching forward to skip some code, as in an IF statement, to loop the branch merely has to branch back to some previous part of the program so that it executes again. Usually the looping code contains a manual counter, and the branch returns to the top of the loop until the counter reaches some value.

Branching and its related offspring, looping, are the most fundamental flow control mechanisms of any program. They are what make a computer "compute" rather than merely calculate. The ability to check the state of a variable and make a decision about whether to continue execution here or there.1

The next flow control concept is the routine. A routine is a collection of instructions that are designed to go together, as a conceptual unit, that does something. In BASIC one can jump into a routine with the GOTO command. It redirects execution to the start of a routine, somewhere else. In assembly, the equivalent of GOTO is the JMP instruction. The problem with a JMP is that the end of that routine cannot return execution to the point following where the JMP was made. JMP or GOTO, in terms of flow control, is a one–way transfer of execution. It has its uses, but it isn't always enough.

December 20, 2018Editorial

World of Commodore '18

Happy holidays Commodore 8–Bit, Amiga and Retro Computer fans!

It's become something of a tradition now for me to write a review of the World of Commodore Expo put on every year in Canada by the Toronto Pet User's Group, TPUG. My first review was of WoC 2016, the year I came back to the scene after a lengthy hiatus. At the time, I was just excited and it felt like something meaningful to review. Last year I wrote an even longer review of WoC 2017. I wasn't sure if I'd keep it up and turn it into a tradition, but, I guess I have, so here we go.

The Road Trip

Every year is a negotiation with my wife, how much time do I get to myself, how much time should I be devoting to my family. My first year back I was only able to go for the Saturday, and last year, I was unfortunately only able to make it for the Sunday.

This year was my time. I had stuff to show, parties to attend, people to drink booze with and computer games to play! I said,

Honey. I've been blowin' money left, right and center on parts for this black wooden box for nearly two years. Now I can either hole up our basement for another year, or I can go show it off in a basement 200 miles away to the only people who care. Who would you rather be married to? Greg Nacu

She saw the wisdom. But I'll need a new plan for next year.

Last year, the show was anomalously not on the first weekend, which caused it to collide with a family christmas gathering. This year, it was back to the usual, first weekend of December. So this was the first year (since my return) that I was able to stay in the hotel and be there for the full show.

When I was a kid, I was only person I knew who had a Commodore computer. One kid I knew had an Atari 400. Another had an Apple IIc, and another had a Coleco Adam. I participated in an early start educational program, when I was in elementary school, for kids who showed an aptitude for computers and programming. We were asked to bring with us a sample of some software we'd written on our own. I brought with me a 1541 disk with some of my early BASIC programs I'm now too embarrassed to even look at. I was only one with a 1541 disk, and was told it was "incompatible." That dread word we all remember from the 80s. My isolation as a Commodore user was painfully obvious to me. Before I got online, my only knowledge of the community was through a couple of old LoadStar issues, and the cracked intros to some pirated games that came with the machine my parents bought for me. Wicked graphics, bouncing raster bars, pumpin' tunes and those greetz. Greetings to people, somewhere, out there, who used Commodore computers. I didn't know who they were, but I knew I wanted to be part of their world.

November 21, 2018Hardware Reference

Commodore Hardware Information

This post is divided into three sections. The first gives the CPU, memory, video and audio specifications for all models of C64 and c128. The second provides a list of common storage devices with information about their transfer speed, physical interface and software loader. The last section is a list of common storage devices along with their media type, capacity and additional usage notes.

Contents

Basic Information: C64 and c128

  C64
1
C64c
2
SX-64
3
c128
4
c128 D
5
c128 DCR
6
CPU Speed PAL:
985,248.4 Hz

NTSC:
1.022727 MHz
PAL:
985,248.4 Hz

NTSC:
1.022727 MHz
PAL:
985,248.4 Hz

NTSC:
1.022727 MHz
PAL:
985,248.4 Hz or
1.9704968 MHz

NTSC:
1.022727 MHz or
2.0454545 MHz
PAL:
985,248.4 Hz or
1.9704968 MHz
NTSC:
1.022727 MHz or
2.0454545 MHz
MIPS
(varies by instruction)
PAL:
0.1407143 to
0.4926242

NTSC:
0.1461039 to
0.5113635
PAL:
0.1407143 to
0.4926242

NTSC:
0.1461039 to
0.5113635
PAL:
0.1407143 to
0.4926242

NTSC:
0.1461039 to
0.5113635
PAL:
0.1407143 to
0.9852484

NTSC:
0.1461039 to
1.0227273
PAL:
0.1407143 to
0.9852484

NTSC:
0.1461039 to
1.0227273
PAL:
0.1407143 to
0.9852484

NTSC:
0.1461039 to
1.0227273
Base Memory 64 KB 64 KB 64 KB 128 KB 128 KB 128 KB
Maximum Internal Memory 256 KB ? ? 1 MB 15 1 MB 1 MB
Maximum Extended Memory 32 MB 32 MB 16 MB 7 32 MB 32 MB 32 MB
BASIC Free Memory 38,911 bytes 38,911 bytes 38,911 bytes 122,365 bytes 122,365 bytes 122,365 bytes
Display Device(s) VIC-II composite VIC-II composite VIC-II composite VIC-IIe composite and
VDC / RGBI
VIC-IIe composite and
VDC / RGBI
VIC-IIe composite and
VDC / RGBI
Resolutions
9
40x25 text
160x200 Multicolor mode
320x200 Hires color mode
40x25 text
160x200 Multicolor mode
320x200 Hires color mode
40x25 text
160x200 Multicolor mode
320x200 Hires color mode
VIC-IIe:
40x25 text
160x200 Multicolor mode
320x200 Hires color mode

VDC:
80x25 text
80x50 text
640x172 Hides color mode
640x200 monochrome mode
Interlacing available, but not useful
VIC-IIe:
40x25 text
160x200 Multicolor mode
320x200 Hires color mode

VDC:
80x25 text
80x50 text
640x172 Hides color mode
640x200 monochrome mode
Interlacing available, but not useful
VIC-IIe:
40x25 text
160x200 Multicolor mode
320x200 Hires color mode

VDC:
80x25 text
80x50 text
640x200 to 640x600 Hires color mode
640x200 to 720x750 Hires monochrome
Interlacing available where Y resolution exceeds about 300 lines.
Video RAM 1 K x 4 plus part of base memory
11
1 K x 4 plus part of base memory 1 K x 4 plus part of base memory VIC-IIe: 2 K x 4 plus part of base mem.
12
VDC: 16 KB 10
VIC-IIe: 2 K x 4 plus part of base mem.

VDC: 16 KB
VIC-IIe: 2 K x 4 plus part of base mem.

VDC: 64 KB
Color cell size 4x8 or 8x8 4x8 or 8x8 4x8 or 8x8 VIC-IIe:
4x8 or 8x8

VDC:
8x8 to 8x32
VIC-IIe:
4x8 or 8x8

VDC:
8x8 to 8x32
VIC-IIe:
4x8 or 8x8

VDC:
8x1 to 8x32
14
Colors 16 16 16 16 16 16
Hardware sprites Yes Yes Yes VIC-IIe: Yes
VDC: No
VIC-IIe: Yes
VDC: No
VIC-IIe: Yes
VDC: No
Sound Device 6581 8580 6581 6581 or 8580 8580 8580
Voices 13 3 3 3 3 3 3
Built-in Drive 1541 1571 1571
November 9, 2018Programming Practice

Character Animation

If you've been following along, you may know the progression of thought I've undergone with regards to the use of a custom character set. Initially, I argued in A Modern Character Set that it would be worthwhile using the Character ROM, because it would save us 2K of space. Then more recently, just earlier this year, I documented my change of heart in Rethinking the Memory Map. By rethinking the memory map, I found a way to crame in a custom character set without truly sacrificing a full usable 2K of memory. That's because, not every kilobyte of addressing space is exactly like every other, on the C64.

Designing C64 OS around the use of a custom character set has a few advantages:

  • Missing ASCII characters can be added (\, ^, { and } for starters.)
  • UI elements can be drawn in some spare characters
  • Special symbols such as the Commodore logo can be used on menu shortcuts
  • And, an alternative font can easily be swapped in

A custom font has opened the door for other creative possibilities I hadn't considered before.

Character Range Breakdown

If any of this is unclear, be sure to checkout my programming reference posts on PETSCII Codes, Screen Codes, and the Vic-20 / Commodore 64 SuperChart. Briefly, there are 256 screen codes, each a unique visual glyph, with one minor exception: space is identical to its reverse. The second set of 128 are the reverse of the first 128. So, there really are just 128 characters, as each character needs its reverse. 128 divides neatly into 4 groups of 32 characters. An operating system, meant to interact with the modern world of networked services, communications and productivity apps, definitely needs both uppercase and lowercase characters.

These are grouped roughly as, the first group of 32 characters are the lowercase letters, plus 6 typographical symbols. The second group of 32 characters are more typographical symbols, plus the digits 0 through 9. The third group of 32 characters are the uppercase letters, plus 6 more typographical symbols. For a total of 10 digits, 34 typographical symbols, and 52 letters.

November 2, 2018Programming Theory

Floating Point Math from BASIC (2/2)

This is Part 2 of a two part post on BASIC and floating point math. Originally I wanted to talk only about math and floating point numbers. However, because of the integration of floats into BASIC, I wanted to give a quick overview of how BASIC stores variables and manages memory. This prelude ended up being kind of long, so I split the post into two parts. If you haven't read part one yet, I recommend you read that first.

My interest in floating point math is because I want to use it in C64 OS. But it could just as easily be applied to any machine language program on the C64, which doesn't use BASIC but does not want to reimplement the concepts and the routines of floating point math. The first use case I have in mind is for a Scientific Calculator Utility.

Zany mock-up of a Scientific Calculator.
Here's a zany mock-up of how that could look.

C64 OS extends the KERNAL, it doesn't completely replace it. While some routines of the KERNAL are never called, others are absolutely depended upon. Despite this dependence, the KERNAL ROM can at times be mapped out, so C64 OS can make use of the RAM underneath. It uses this RAM either for Utilities or alternatively for bitmap data. There are rules to follow when mapping out the KERNAL so things continue to run smoothly. The same is true for use of the BASIC ROM in C64 OS, but with a few important differences.

Any operating system, or really any program, needs to decide how it will deal with the overlapping of ROMs and I/O with potentially usable RAM. As discussed in part one of this post, the standard C64 OS (KERNAL ROM and BASIC combined) "deal" with this overlap by ignoring a huge portion of RAM. 24K of 64K is essentially just never used. The system modules of C64 OS itself take up precious RAM, therefore we want to have available as much RAM as is possible to use.

The PLA, controlled by the 6510's processor port, handles mapping the ROMs and I/O overtop of the underlying RAM's addressing space. Only certain mapping combinations are permitted. I've frankly always found this confusing, but find it much clearer when all the possible combinations are laid out in a table, such as this one:

October 23, 2018Programming Theory

Memory Management in BASIC (1/2)

I'm working away on C64 OS. And I've got a few things on my plate, but some things have to come before some others. Here's a quick summary of the current state of dev.

Nominally, I'm working on the class hierarchy of the Toolkit. And I'll return to this subject soon to discuss how that's developing. Before I can dig deeper into that, though, I need to improve the memory manager. There is a page allocator, which works well and I'm currently using only that for all my memory allocation needs. There are also the regular malloc() and free() routines that deal with arbitrarily sized chunks of memory from within a memory pool. A memory pool is typically a block of consecutive pages, that have been allocated by the aforementioned page allocator, and initialized.

At the moment, malloc() is quite primitive. It searches for a range of memory that's bigger than the requested chunk size, that has never previously been allocated, and it carves off a chunk of that memory turns it into an allocated chunk and returns a pointer to it. Free() can mark a previously allocated chunk as available. Additionally, if malloc finds a previously allocated chunk, that is exactly the same size as the current request, that is available, it can mark that as allocated and return it again.

But what it can't yet do is take a previously allocated chunk, that is available and bigger than the current request, and split it into two chunks; One which it marks as allocated and returns, and another that remains available but smaller. The memory manager also cannot (yet) merge two small consecutive free blocks into one larger free block. Shouldn't be too hard, it just hasn't been a priority until now. The Toolkit's classes are all kinds of varying sizes, and their instantiation depends on malloc. So malloc can no longer afford to be only half implemented. Before now, though, I haven't actually needed malloc for anything.

This post is part one of a two part post which begins by looking at Memory Management of the C64 and BASIC's role in managing its region of memory. Part two is about how to extract Floating point numbers and math routines from the BASIC ROM, without making use of, or triggering, the memory management and execution environment of BASIC, as a language.

ZeroPage

Okay, now let's take another step back. The 6502 depends HEAVILY on zeropage to perform many common tasks. Zeropage (memory addresses $0000 to $00FF) has been described, by at least one paper I read, as almost an extended register set for the CPU. Because, it isn't just faster to access but many instructions need it for some addressing modes. Essentially, all instructions that support the Indirect–Indexed, and/or Indexed–Indirect addressing modes, can do so only by referencing a pointer that is in zeropage. Many other instructions can use zeropage addresses both to save memory and for faster execution than doing the same thing in any other page.

October 4, 2018Hardware

NES to C64 Controller, Part 2

You're writing ANOTHER post about NES to C64 Controller modding? Are you serious? You just wrote one in August!

I know, but there have been a few interesting developments, so I figured I'd come back with a Part 2 to finish what I started.

If you want the background on how a NES controller works, and how this modification for C64 works, then you should read the original post on this topic, first, NES to C64 Controller Mod. This post goes into additional features. It shows how to make use of the Select and Start buttons on a C64, as well as the software to test it, and a video demo.

This post also relates to my C64 Luggable project. C64 Luggable has 4 joystick controller ports on the front panel. I knew from the beginning of that project that I wanted it to have a PS/2 Mouse port on the back, plus 4 joystick controller ports on the front. You know, to make it the ultimate C64 party machine. Plus four controller ports makes it look extra cool. You can read about the front controller ports of C64 Luggable here: Front I/O: Controller Ports.

Now, if you're going to have a custom machine, with a built–in display, built–in speakers and a handle on top, you really want to have four joysticks that look like a set that belongs with the machine. All my other joysticks are a motley collection, one each of a wide assortment of totally different shapes and styles. Back in the day I'd converted a Nintendo NES controller for use on my C64, and that one, of all the joysticks I have, became my favorite and my go to controller for almost any game.

Wouldn't it be great to have a set of four perfectly matching NES controllers to go along with C64 Luggable? That was the goal I had in sight.

The in-progress Front I/O panel of C64 Luggable, with 4 controller ports.
The in-progress Front I/O panel of C64 Luggable, with 4 controller ports.
September 24, 2018Programming Theory

Distributed Jumptable

I've suffered a minor setback, I'd say it put me back maybe a week. Our work office was broken into last weekend. Front window smashed. My 2016 MacBook Pro was stolen right off my desk. Fortunately I had most things backed up. I didn't lose anything Commodore related, or anything personal really. But I have had to spend some significant amount of time reconstructing my work environment on a new iMac.

Also, very frustratingly, I lost perhaps a month of development on my current work project. As the sole developer, I wasn't committing to SVN very regularly. Which is something I'm going to start doing, probably once a week, in light of the rude awakening that fires and spinning disk failures are not the only way to lose data. Now back to the post I was working on.


Sometimes I feel like I'm climbing a mountain 1 inch at a time. This post is about some changes I've made to how the system jumptable works, and how modules are linked together.

I've been here before, and wrote about this general theme of development in at least four previous posts: (In chronological order, oldest first.)

To recap, C64 OS uses the C64's KERNAL ROM, and adds its own KERNAL on top of that. The C64 OS KERNAL is divided across 10 modules. These are units of code that get assembled independently, and that export routines that can be called either by other modules, or by application code.

The set of modules has been fairly stable for a while now, and consists of:

C64 OS KERNAL
Memory String Math File Timers
Input Screen Menu Service Toolkit

When assembled, all the modules pack together and end at $CFFF. As I write more code the amount of space the KERNAL consumes continues to grow down into memory. It currently ends somewhere around $A800. Which means it's approximately 10K. 6K overlaps where the BASIC ROM normally sits. And 4K in himem from $C000 to $CFFF.

August 27, 2018Software

Menu/Status Bar: File and Memory

I'm feeling good that I'm back on pace with my posting rhythm. This is my third post in August. Today I just wanted to show off a system feature that I built in last month or so. It's the system status bar, as well as new global, configurable keyboard shortcuts. And this also includes some work on the File and Memory modules to support the status bar.

Let's just dig right in. I was anticipating that this would be a briefer post than some of my others, but it's me after all. I'm very wordy and detailed. So, this may turn out to be longer than I'd originally expected.

Drive Status

You know, it's funny, I've been using a C64 since I was 9 years old, and it never fully dawned on me until just recently the importance of reading the drive's error channel.

As I discussed at some length in the post from earlier this year, KERNAL, File Refs and Services, the C64 itself really doesn't know anything about files or file systems, or anything else about disk management. I argued then that this is a strength, when you consider the nature of the system. The machine is small, with limited RAM and even less ROM. And yet, it can easily make use of modern storage media like CD roms, SD Cards, CF Cards and hard drives. This is because the DOS is entirely offloaded into the device.

The C64 merely opens a connection over the serial bus, and sends commands over the command channel. This allows the C64 to read and write files, and issue commands to the device's DOS to let it handle the nitty details of manipulating the data on the storage medium.

Consequently, though, the C64 itself doesn't know very much about error states in the devices it talks to. There are a couple of conditions it handles. For example, if you try to access a device number that doesn't exist, well, the C64 knows about that. And if you're reading in bytes and you hit the end of the file, the C64 knows about that too. But, imagine that what you really want to do is change a directory, then create and open a file, write some data to it, and close it. To do this, the C64 must send the change directory command, over the command channel, prior to trying to open the file. If all goes well, the file will end up being created inside the subdirectory.

But what happens if things don't go as planned? What happens if, for some reason, the directory doesn't exist? What will happen is that the C64 will issue the change directory command. That will produce an error internal to the drive, about which the C64 knows absolutely nothing. If the C64 then simply proceeds to open/create the file, it will be created in the wrong place. Even worse, if you open with an overwrite flag, who knows, you might accidentally overwrite a file with the same name that's not even supposed to be there, because you're not where you think you are.

There is only one way to deal with this: Read the error channel, religiously.

It's not like this hasn't been known for 40 years, it's right there in the User's Guide. But, when you actually get into the details of programming, somehow things that have always been there but that you've never thought much about suddenly pop up become noticeable.

1541 Users Guide, read the error channel.
Taken from 1541 User's Guide at archive.org.
Older Posts

Above are previews of the 10 most recent posts.
Below are titles of the 5 next most recent posts.

August 15, 2018Hardware

NES to C64 Controller Mod

August 9, 2018Software

Introduction to Utilities

July 16, 2018Programming Theory

Command and Control

June 26, 2018Technical Deep Dive

Menu Systems, a comparison

June 5, 2018Editorial

Review: 1541 Ultimate II+



View full archive ⇒

Want to support my hard work? Here's how!