NEWS, EDITORIALS, REFERENCE

Subscribe to C64OS.com with your favorite RSS Reader
May 12, 2023#120 Software

Mounting and Mouse Wheel

Post Archive Icon

Mounting and mouse wheel? What the heck have those two things got to do with each other? Well, they're two new features available in the most recent update to C64 OS, version 1.03.

If you purchased a copy of C64 OS, either the Starter Bundle or the Standard Bundle, then you are a version 1.X licensed user. Congratulations. That entitles you to patches, bug fixes and updates with new features. If you didn't know that you get access to new features and updates, you may be missing out on cool new things being added to C64 OS.

You can download, for free, C64 OS system updates and other independent releases from the Official Software Updates page. These updates can be installed overtop of an existing C64 OS installation to update it to a newer version. This is all handled by the "Installer" Utility which was included as part of version 1.0. There are a few things you need to know before installing an update, such as updating your current system in steps. If you're currently on 1.0, you need to update to 1.01 first. Once you're on 1.01 you can update to 1.02, and from there to 1.03, and so on.

Everything you need to know is in a special guide called, C64 Archiver and Installer. And some of that information is repeated in condensed form at the top of the software updates page itself. In this blog post I'm going to talk about two new features in v1.03: Mouse Wheel Support, and Disk Image mounting in File Manager.

 

Blogging is pure fun

I have to tell you, blogging is pure fun. I get to write in a voice that is truly just me talking to whoever is reading. I get to say "I" without worrying that I'm being too informal. I get to crack little jokes, insert witticisms and give my candid opinions. This is a dramatically different writing style than the sort that I have been deeply embedded in for the past couple of months.

Now, why do I tell you this? Because, it has not escaped my attention that this is the first blog post in a while. It's the first one in 2023. Let me assure you, the lack of blogging is not an indication of a lack of enthusiasm, energy or time being devoted to the C64 and to C64 OS.

I have poured a huge amount of time into The Guides, which I can now use in the plural because there are several. I mentioned the C64 Archiver and Installer guide. There is also the (huge) C64 OS User's Guide and its smaller companion the C64 OS Getting Started Guide. I call the guides "living documents," but blog posts are different. I do occasionally update older blog posts, but I make it clear where new content has been inserted or corrections have been made. Other than that, blog posts are dated to when they were released. A blog post represents a moment in time, a stage of development, an exploration of something I've learned that I want to share, or an announcement of something new. The Guides are not like this at all. The Guides are living documents, more like Wikis (that only I and special guest authors get to edit.)

I "finished" the C64 OS User's Guide and published it alongside the C64 OS v1.0 release. I have since gone back in and added Chapter 11: Glossary of C64 OS Terminology, as a final chapter. And it's enormous; it's over 15,000 words long and defines and cross references over 175 terms related to the Commodore 64 and to C64-OS-specific technologies. This was published in February, so that more-or-less exhausted my writing allowance for the month. I link to it here so you know it exists, and so you can check it out, and hopefully find it useful and learn something cool from it.

C64 Programmer's Guide

In the meantime I've also been working on the C64 OS Programmer's Guide. It's being released one chapter at a time, although, I am now at a point where I will not necessarily be working on the chapters in order. The Guide is divided into 4 sections:

  • Core technologies
  • Story-based Tutorials
  • Advanced Topics, and
  • Appendices

Besides the introductory Chapter 1, so far, I've written:

Chapter 4: Using the KERNAL was just published a couple of weeks ago; it's a detailed reference guide to the complete C64 OS KERNAL. It has an introductory page about what the KERNAL is, how to link and make calls to it. Then there is a separate subpage for each of the 10 KERNAL modules.



C64 OS Programmer's Guide, extrusion image.
C64 OS Programmer's Guide, extrusion image.

Each KERNAL module subpage begins with a table of contents. In most modules the routines are grouped into categories. For example, in the File module there is a set of routines for opening and closing files and reading and writing data. The same module has another set of routines for opening and closing the clipboard, reading and writing data to it, and some quick clipboard helper routines. Each of these groups, in each module, has a heading and some explanatory prose about how these routines are intended to be used. Then each routine has a standard table that states its purpose, its communication registers, stack requirements, zero page usage, affected registers, and its input and output parameters. Following the table is a description in prose about how to use the routine, with notes and links to related routines. If applicable there are also tables of important constants and the header files those are defined by. In many cases, though not all, there is sample code showing how to use the routine, surrounded by a reasonable degree of context.



Taken together then, that's 15000 + 10000 + 16000 + 50000 = 91,000 words, written across these two guides this year. To put that in perspective, a short novel is anything over 40,000 words.1 Which means, I've written the equivalent of 2 short novels in 2023 alone!

Let's get into meat and potatoes of this post. Version 1.03 of C64 OS was released halfway through January, 2023. Since then I've been working on a new update, version 1.04. Before the hubbub of v1.04 becomes the news of the day, I wanted to talk about two great new features that were added in v1.03.


Mouse Wheel Support

C64 OS gains mouse wheel support via the MicroMys PS/2 mouse adapter and the MouSTer USB mouse adapter.

Apparently the MicroMys adapter has supported the wheel on PS/2 mice going all the way back to version 3 (currently version 5 is commercially available.) MouSTer also supports the mouse wheel with a recent firmware update. MouSTer supports the exact same protocol as MicroMys, so on the C64 there only needs to be explicit support for one these and the other comes along for the ride. MicroMys has been around longer, it defined the protocol and has more documentation, so I'll talk about that adapter specifically even though everything said here works with MouSTer too.

I asked Jens Schonfeld, (owner and operator of Individual Computers, which makes and sells the MicroMys,) and he's not aware of any C64 software that takes advantage of the mouse wheel feature. C64 OS might just be the very first Commodore 64 software to support scrolling through content using a mouse wheel. I'm going to go out on a limb here and suggest that this is because it's quite tricky. Reading the mouse wheel data is trivially easy. You can read the numbers with BASIC and spit them out on the screen. The tricky part is how to integrate that effectively into a user interface.

The MicroMys v5, PS/2 mouse adapter, slim connector.
The MicroMys v5, PS/2 mouse adapter, slim connector.

Support for the mouse wheel goes deep. There is a new MicroMys pointer driver, which can be selected with an updated version of the Configure Tool. The KERNAL (input module) now supports low-level mouse wheel events. And the Toolkit's TKView, TKScroll and TKSBar classes have been updated to support these new events.

Additionally, changes to the Mouse Utility let you customize the wheel sensitivity (different mice send the scroll messages at a faster rate for the same distance you rotate the wheel), and to let you choose between "classic" and "natural" scroll directions. "Classic" is when you pull the wheel towards yourself and the nub in the scroll bar moves downwards. "Natural" is the inverse of this, when you pull the wheel towards yourself the content within the scrollable region moves down thus scrolling you up towards the top of the content.

The new Mouse Utility in v1.03.
The new Mouse Utility in v1.03

Toolkit Events

Support for mouse wheel events was made much easier in C64 OS by the existence of the Toolkit. Let's take a brief tour of how Toolkit events work and how they propagate.


Toolkit (with a capital T) is an object-oriented user interface toolkit (with a lower case t) that is built into the C64 OS KERNAL (toolkit module). There are 9 core classes that are permanently memory resident, and this is extensible with runtime loadable classes that can be installed in the //os/tk/ directory.

Toolkit classes are capable of forming a nested, hierarchical, recursive, node tree2 by means of the properties and behaviors of TKView, from which all other user interface classes inherit. TKView has parent, child and sibling properties, as well as addchild and unparent methods allowing it to form node tree relationships with other classes that inherit from TKView.

Additionally, TKView provides the foundation for event handling. TKView provides the base methods:

  • dokeyeqv
  • keypress

  • musdown
  • musmovd
  • musup
  • musclik
  • musdclik
  • rmusdwn

...and formerly rmusup, but which has been rebranded musalt, more on this change later. "Mus" in these method names stands for "mouse". (I like it better than other short alternatives, such as "mos" or "mse", plus, mus- is the Esperanto word for mouse.)

These methods are overridden by subclasses of TKView in order to do something special in response to these event types. The default behavior of TKView is to pass the event up the view hierarchy by calling the same method on the parent object in the node tree. This is the underlying mechanism of event propagation.

Here's basically what happens:

The Interrupt Service Routine calls a routine in the mouse driver, and converts the results into a low-level mouse event, which it queues in the mouse events queue. The event has a pixel coordinate relative to the whole screen, and a single byte that represents modifier key flags in the upper nybble, and an event type (0 to 15) in the lower nybble. The Application is notified by the main event loop that a mouse event is queued. The Application then prepares its Toolkit environment and does a tkmouse KERNAL call.

Depending on the type of event bring processed, tkmouse does different things. The most common thing is to initiate hittesting. It takes the root view, the view in the node tree that is the parent of all other views, and calls its hittest method. The hittest method is also provided by TKView, and rarely (if ever) needs to be overridden by a subclass. To start the hittesting off, the coordinates of the mouse event on screen get re-oriented relative to the position of the root view. That view then checks if the mouse event falls within its bounds. For example, if the view is 80 pixels wide, but the relative mouse event X-coordinate is 88px, then the mouse event misses this view, because it's somewhere out of bounds, off its right side. But if the mouse event does fall within this view, then, this view is hit. The next stage is that, although this view is hit, this view might have children nested within it. The hittest method re-orients the event for the offset of each of its child views, and recursively calls the hittest method on each of them. Eventually this resolves to the topmost view that was under the mouse pointer, plus the coordinates relative to that view where the pointer was. (Topmost in terms of what gets drawn on the screen, or deepest nested in the node tree.)

There are numerous optimizations that make hittesting faster and more efficient than it sounds from the high-level description. Ultimately, a pointer to the hit view, called the first mouse view, gets recorded in the Toolkit environment for this Application. The low-level event type (a number from 0 to 15) gets converted to a corresponding method, and then that method is called on the hit view. For example, the mouse event "ldown" (left down) is number 1. This gets mapped to the "musdown" (mouse down) method, which gets called on the hit view. That particular object now has the opportunity to do something in response to a mouse down occurring somewhere on it. Or, if it doesn't respond to mouse down events, its superclass's musdown method gets called, and if no superclass handles mouse down events, eventually it's the TKView's own musdown method that handles it. TKView's default behavior is to pass the event up the node tree. To do this it looks up its own parent node, and then calls musdown on it. This recursive process propagates up the node tree back to the root view.

There are some kinds of mouse events that do not re-trigger a hittesting procedure. For example, mouse down does hittesting to find the view that was moused down on. That view gets recorded as the first mouse view, but when the subsequent mouse up event comes along, the "musup" method gets called on the first mouse view, not on whatever view happened to be under the mouse when the mouse button was released. Naïvely this sounds wrong, but trust me, this results in intuitively expected behavior.

By the way, not that I'm tossing GEOS under a bus, but people always ask me, how is C64 OS different from GEOS? Everything described above is one major way in which C64 OS is significantly more sophisticated than GEOS. The GEOS UI and mouse event system are very primitive compared to C64 OS. The Toolkit is simplified for the Commodore 64, but is essentially how modern OSes, like macOS, build their UIs and handle mouse events. I know because I studied the OpenStep source code and loosely modelled the C64 OS Toolkit on that. OpenStep is the open source version of NextStep, which was bought by Apple to become Mac OS X, which eventually became iOS. So, for a Commodore 64, the C64 OS Toolkit is remarkably modern.

Scanning Hardware using the Mouse Driver

The side trip into how mouse events get routed through Toolkit allows us to understand what needed to be done to add support for mouse wheel events throughout C64 OS.

A 1351 mouse is typically, though not always, connected to Controller Port 1. The X and Y axis of the analog rolling ball are connected to the SID chip's POT X and POT Y lines. If you're interested in a deep dive on how the analog movement of the ball is tracked, check out this earlier blog post, 1351 Mouse, and Mouse Driver.

The mouse buttons are much easier. Each Controller Port has 9 lines in total. Here's how they're wired up according to this segment of the C64 Schematic. (Some extraneous detail has been removed.)

Schematic segment showing the controller ports.
Schematic segment showing the controller ports on the C64.

What you can't see from this image is that the 5 digital signal lines: JOYA0, JOYA1, JOYA2, JOYA3 and BTNA, connect to the same chip (CIA #1) that scans the keyboard. The other 4 lines are occupied by non-digital signals: Power and Ground, POT X and POT Y. Power and Ground are what enable external adapters to be powered off the controller port, so that's pretty convenient. A 1351 mouse has two buttons, left and right, and those buttons are connected to the same lines the Joystick uses for Fire and Up, respectively. That leaves 3 additional unused lines, all digital signals. Wheel mice have a wheel that scrolls in two directions, plus, you can usually depress the wheel to function as a middle button. (Some older mice don't have a wheel, but do have a middle mouse button.)

Altogether then, here's how all the lines of the port are used. (This is confirmed by the table on the MicroMys Wiki.)

PIN Label Joystick Mouse Notes
9 POTAX X-Axis Analog 1351 standard
8 GND All Buttons All Buttons + Wheel Common Ground
7 +5 V Adapter Power
6 BTNA Fire Left Button 1351 standard
5 POTAY Y-Axis Analog 1351 standard
4 JOYA3 Right Wheel Down MicroMys/MouSTer standard
3 JOYA2 Left Wheel Up MicroMys/MouSTer standard
2 JOYA1 Down Middle Button MicroMys/MouSTer standard
1 JOYA0 Up Right Button 1351 standard

As you can see, this very beautifully uses all of the Controller Port's lines. MicroMys uses the same lines that the 1351 uses for the same purpose, making it backwards compatible. But it also adds the middle button and the wheel up and down signals on the 3 extra digital lines also used by a joystick.

On Controller Port 1 (the one we're focusing on, but it is possible to program a driver for a mouse on Controller Port 2,) those digital lines connect to CIA #1's Port B. Port B is an 8-bit port, but only 5 lines from the Controller Port are wired to it. They're wired up like this:

Port B Mouse
bit 7
bit 6
bit 5
bit 4 Left Button
bit 3 Wheel Down
bit 2 Wheel Up
bit 1 Middle Button
bit 0 Right Button

This can be seen by the table on the MicroMys Protocol wiki page. If you don't know how the CIA's port is used to scan input, you might be interested in my blog post, How the C64 Keyboard Works. It's been a very popular post over the years and I just recently updated it with some improvements and clarifications to the keyboard matrix layout.

To summarize the post about the keyboard, the CIA internally pulls its port bits high when the lines are left floating. In other words, when no button is being depressed, the computer reads the bit from the CIA port as a 1 (+5V) rather than as a 0 (GND). Thus, the only way for the keyboard, a joystick button, or a mouse button (or wheel activity) to register a change on its CIA port bit is to pull it low. This is accomplished in the Joystick or Mouse by having the button connect its line to ground. Very very simple. (It's a bit more complicated in the keyboard.) By connecting the CIA's port bit to GND, it's no longer floating, and its internal +5V pull up gets pulled down, which reads as a 0.

The buttons are easy then. If bit 0 is low, the right button is depressed. If bit 1 is low, the mouse wheel (or the middle mouse button) is depressed.

Rolling the wheel works as follows:

As you roll the wheel up, it pulls the wheel up bit (bit 2) low and holds it low for 50ms, then it raises it back to the default high state for 50ms. If you are still rolling the wheel up, it repeats this, pulls bit 2 low for 50ms, then raises it again for a minimum of 50ms.

The exact same thing happens while rolling the wheel down, except instead of twiddling the wheel up bit (bit 2), it twiddles the wheel down bit (bit 3.) The mouse driver is called on every interrupt service routine. On NTSC this causes the mouse to be checked 60 times a second, and on PAL to be checked 50 times a second.

MicroMys Wheel pulses.
MicroMys Wheel pulses, from the MicroMys Protocol wiki.

Inside the driver, if the wheel up bit is ever low, it increments a wheel up counter. It then checks to see if the wheel up counter is greater than a sensitivity threshold, which is configurable by the user to adjust for over-sensitive wheels. If the counter crosses the sensitivity threshold, it clears the counter and sets a bit in the mouse-button-flags byte. It is here that the driver checks if the user prefers natural scrolling or classic scrolling. If the user prefers natural scrolling, then a threshold overflow of the wheel up counter sets the scroll down bit, otherwise it sets the scroll up bit.

As expected, precisely the same thing happens for wheel down. If the driver ever sees that the wheel down bit (bit 3) is low, it increments a wheel down counter. If the wheel down counter exceeds the user-defined scroll sensitivity threshold, it clears the wheel down counter and checks the natural/classic scroll setting. If the user prefers natural scrolling it sets the sets the scroll up bit, otherwise it sets the scroll down bit.

And that's it for the driver!

You can see that the driver is responsible for implementing natural vs. classic scrolling, in exactly the same way that the driver is responsible for swapping the left and right buttons if the user indicates that they're left handed. The driver is also responsible for honoring the user's scroll sensitivity setting. The MicroMys/MouSTer driver is 275 lines of code, with comments, formatting, spacing and dividers for readability. It assembles to just 244 bytes, which neatly fits in a single page with very few left over bytes wasted. I like it.

Routing Mouse Wheel Events

Now we know how the driver reads the hardware and sets bits in the mouse-button-flags byte. (This flags byte is musbtns, in zero page, and defined by //os/s/:input.s.) These flags communicate to the KERNAL the state of the input device's buttons, in a way that is abstracted from the physical device. Below are the bit flags of the musbtns byte.

musbtns constant notes
bit 4 lbutmask Left Button
bit 3 wdnmask Wheel Down
bit 2 wupmask Wheel Up
bit 1 mbutmask Middle Button
bit 0 rbutmask Right Button

The KERNAL keeps a copy of this byte which it uses as a comparison to determine if a button has gone up, or down, or is being held down. It translates those transitions into low-level mouse events which it adds to the queue.

The main event loop notifies each screen layer, from top to bottom (until one of them prevents propagation to the next layer) that a mouse event is waiting on the queue. It is the job of the Application, or the Utility, to bridge the notification about the low-level mouse event to the Toolkit environment maintained for that screen layer. If an Application doesn't use Toolkit at all, then this is the place where the Application can perform manual processing of the low-level event.

It's generally quite easy for the Application to bridge the event to Toolkit. Its screen layer has a vector to a routine to process mouse events. That routine needs only load a RegPtr (X/Y -> low byte/high byte) to its Toolkit Environment structure and call tkmouse. The tkmouse routine handles reading the topmost low-level mouse event off the queue. Upon return, the Application also needs to check if the Toolkit Environment's dirty flag was set, and if so, to also mark its own screen layer as dirty. For Utilities, this is made even easier. The mouse events vector of the Utility's screen layer can point directly to uf_pmus, a routine in the Utility Framework for processing mouse events.

As we read earlier, for a mouse wheel event, the Toolkit performs a hittesting procedure. It does this by calling the hittest method on the root view. Eventually, on whichever view is returned as the hit view, the low-level event gets translated to a method call. Also mentioned earlier is that there was a method called rmusup. This was specifically for handling right mouse button up events. However, that is a very rare event that few Toolkit classes (none, at the moment,) support. Additionally, Wheel Up and Wheel Down events are also not likely to be supported, directly, with custom behavior, by the vast majority of Toolkit classes.

Object-oriented code is nice. It's well organized; it's flexible; it's clever in many ways. But it's not exactly memory efficient. To add new methods for wheel up and wheel down would require adding a fair bit of code. Instead, I renamed rmusup (which isn't being used yet anyway) to musalt. This is a sort of catch-all method for all low-level mouse event types that don't have their own explicit routine. Because most classes don't handle any of these events, they can just generically pass the message to their parent node. The few classes that want to handle wheel up, wheel down, right mouse up, or the new events, middle down, middle up, middle click, those classes need to check the type of the low-level event to see what event caused musalt to get called. I think this was a good trade off for supporting rare event types, but without using too much memory.


So what actually happens when you roll the wheel while the pointer is above some random Toolkit view, like a button? The hittesting procedure identifies and returns the button that is directly beneath your mouse pointer. A TKButton is a subclass of TKCtrl, which is a subclass of TKView. The musalt method is called on the TKButton. TKButton's own implementation of musalt is to call its superclass, TKCtrl's musalt method. But TKCtrl also doesn't do anything with musalt. Its implementation is to call its superclass, TKView's musalt method. TKView is what handles propagation of the event up through the view hierarchy.

TKView's musalt implementation is to look up this view's parent node, and call musalt on it. Let's suppose that the TKButton is embedded in a TKLabelBox. Now TKLabelBox has an opportunity to handle the event, but its musalt implementation calls its superclass, TKLabel's musalt method. It doesn't do anything with it either! So it calls its superclass, TKView's musalt method. Now we're back to TKView's implementation which passes once more to the next parent view in the view hierarchy.

This could propagate all the way back to the rootview, and then do nothing at all because there was nothing to scroll. Or, something more interesting could happen. We'll suppose that the TKLabelBox is inside a TKView, which is inside a TKScroll as its content view. The TKScroll manages a TKSBar which is a sibling to that content TKView. The musalt method gets propagated from the button, to the label box, to the content view and then to the TKScroll. The TKScroll actually has an implementation for musalt though. It checks to see if it has a vertical or a horizontal TKSBar, or both. And it calls musalt explicitly on the vertical scrollbar if there is one. Or, if there is only a horizontal one, it calls musalt on that one.

Event propagation through the view hierarchy.
Event propagation through the view hierarchy. An unrealistic amount of space is shown around each view. That's only for this diagram so there is a place for the labels and arrows.

This is the first time that the mouse event is no longer following a path through the view hierarchy from child to parent, to parent, to parent. The TKScroll redirects the call to one of its children, but a child which it knows handles the event and will not turn around and redirect it back to its parent (since that would cause an infinite loop.) The TKSBar takes the direction, (which has already been flipped by the driver, if the user's preference is for natural scrolling,) and it converts this into exactly what happens when you click the up or down arrows on the scroll bar. The nice thing about this is, it doesn't require any extra work to determine how far the nub should move, or how much scroll distance is available, or whether the scroll bar is actually enabled. I doesn't have to do any of that. It just calls that code that gets called when the user clicks one of the arrow buttons. This then does what was already implemented; it moves the scroll nub, it liaises with the TKScroll view to scroll its content, etc.

There is even one extra bonus. The code for the clicked arrow buttons checks if the LEFT-SHIFT key is held down, and does a slower, more precise, single-line scroll. It also checks if the COMMODORE key is held down. If it is, it does a big jump all the way to the top or bottom of the TKScroll. As if by magic, these keyboard shortcuts also work with mouse wheel events! Because at a very low level, if you were holding one or more modifier keys when the mouse event was generated, they get included in the low-level event. And when the arrow-clicked code runs, it doesn't care that the event is a wheel-up/-down rather than a left-click, it just checks the modifier keys on the event, and BOOM! Hold the COMMODORE key and roll the mouse wheel anywhere overtop of a TKScroll, and the view scrolls all the way in that direction.



Areas that gained mouse wheel support.
Areas that gained mouse wheel support, with no extra code required.

I know that got technical, and I hope it wasn't impossible to follow. But I hope you can also appreciate the detail and the sophistication that went into getting mouse wheel support. Without a single line of code being added to any pre-existing Application or Utility, every scrollable region, be it a list, or a table, or a text area, or a sidebar with other UI controls in it, they all automatically gained support for scrolling with the mouse wheel.

That is the power of building your user interface for C64 OS, and using its object-oriented UI Toolkit.


Let's change the topic now to another nice new feature that was added to C64 OS in v1.03, disk image mounting.

Getting Content From PC/Mac to your Commodore 64

Back in the 90's, it was a total pain to move content between your Commodore computer and the ever-growing world of Windows PCs. There were solutions, but they were not nearly as convenient as they are today. There was software, like Big Blue Reader (or Little Red Reader), that let you read PC floppy disks in a 1571, or a 1581, or a CMD FD-2000. Later there was software like CD-ROM Commander, which could read data directly from a PC's CD-ROM. But, you needed to have an external SCSI CD-ROM drive and a CMD HD. I had both of these and I did use CD-ROM Commander (I still use it today, in fact.) But convenient, it was not. Especially if you ended up burning a 170KB disk image to an 800MB, 25¢ CD-R. Something about that just feels very very wrong.

IDE64 eventually came along that offered its own solution, if you bought an IDE64. Most of the time I used a modem and terminal software.

There were other solutions that involved connecting a parallel cable between the User Port and a PC's Parallel port and running special DOS software. I never got into any of that, because, to be perfectly honest, I never owned a PC. I went straight from my C128 with SuperCPU/IDE64 to an iMac G3. Fiddly PC-based transfer solutions were just never for me.

When I came back to the Commodore 64 in 2016, the first thing I asked about on IRC was, what is the best and easiest way to get data from my present-day MacBook to my C64? Before I asked this, I'd already ordered a pair of 64NIC+ Ethernet cartridges. But, they were not nearly as easy to use as I'd hoped for.

In steps SD2IEC. Somehow, I had missed the revolution of SD2IEC while I'd been away. I looked back on photos I took from the last World of Commodore I went to, pre-hiatus, and I saw a photo of Jim Brain talking about uIEC/SD. But I have no memory of the actual event.

Jim Brain holding a uIEC/SD in 2008.
Jim Brain, showing uIEC/SD in a church basement, World of Commodore, 2008.

So I bought one of these on the recommendation of folks in IRC. It turns out, SD2IEC is extremely convenient for transferring content between your PC/Mac and your C64. You put an SD Card in your PC, and it can be read or written to directly because it's formatted FAT16 or FAT32. You put some stuff on the card, just as you would any thumb drive or media card. Then you pop the card out, pop it into the new SD Card slot on your Commodore 64, and BOOM! Instantaneously hundreds of megabytes, nay, gigabytes(!) are already on your Commodore 64.

It used to be that to be on your C64, you had to transfer from a non-native media to native media. Like, you use special software to read a PC formatted floppy disk, and that software copies (slowly) the content from the PC floppy to, say, a CMD HD. It only becomes truly usable, truly on your C64, when it's on that native storage device. But, SD2IEC makes SD Cards, formatted with a FAT FS, native. That's incredible.

The only complaint is that at the time I bought my first SD2IEC (a uIEC/SD with deluxe daughter card from Retro Innovations,) the documentation for SD2IEC was very poor. It consisted of a coder's readme file. It had no detail, it was written for other developers essentially, or for people who already know all about how CMD HD works, and just covered some ways in which SD2IEC is different. This is definitely not documentation for an end-user, not like the way a commercial product from Creative Micro Designs came with a thick User's Manual in a nice three-ring binder. That crufty readme (no offense) is not the sort of thing I personally enjoy reading. So I didn't read it. I'm certain the great majority of people who have ever bought an SD2IEC have never read it either, and consequently have no idea what their SD2IEC can do. And that's a shame.

Disk Image Mounting

I applied my knowledge of how the CMD HD works to using the SD2IEC. And, that actually takes you quite a distance. They are indeed, intentionally, quite similar. I bought my CMD HD in the mid 1990s. It's a stalwart drive, but lacks the ease of getting content onto it from a Mac or PC.

Starting way back when the first C64 emulators became a thing, maybe early 1990s, software started being passed around in the form of disk images, .D64 mainly. This makes sense, of course, because the great majority C64 games and demos and other software was (and still is) packaged for use on floppy disk. (You crazy tape users notwithstanding.) Disk images have the advantage that C64 software can be passed to and through PC and other file systems while maintaining C64-specific storage properties. 256-byte sectors, track and sector numbers and links, 16-character PETSCII filenames, CBM file types, and even whacky non-linear file structures like REL files or GEOS VLIR files. Disk images are a good solution. 3

Back in the day, using a .D64 on your real Commodore 64 required one of two things:

  1. Producing a real disk from the image
  2. Dumping the image to a 1541 emulation-mode partition

Obviously, you can dump the image to a disk. That was the way to be the most compatible. I did this a lot when I was younger.

  1. Fetch a .D64 from the internet (via dial-up shell account).
  2. Save it to my CMD HD over a modem using terminal software.
  3. Write the image out to a real 1541 floppy disk, with a software utility.
  4. Label the floppy and put it in one of many cases with all my other disks.

That was slow and required physical media, but it was very compatible, because it was a real 1541 disk drive. Alternatively, for things that were less strict about being 1541 compatible, Creative Micro Designs gave all of their drives (CMD HD, CMD FD, and RamLink) emulation-mode partitions. On a CMD HD, for example, you can create several native-mode partitions which can be up to 16MB each and have support for nested subdirectories, but you can also create partitions that match the size, track and sector layout of a 1541, 1571 or 1581 disk. The same software code that can write a .D64 to a 1541 drive can write to a CMD HD's 1541 emulation-mode partition, because the CMD HD-DOS supports the same block-read, block-write and related commands.

Once the .D64 is extracted, you can then access the data directly out of the 1541 emulation-mode partition, or, for longer, more permanent, more organized storage, you can copy files and programs from the emulation partition to some subdirectory of a native partition. That then frees up the 1541 emulation partition to be overwritten by a dump from another .D64 file. And so it goes.

On SD2IEC: O Emulation Partitions, where art thou?

When I first got my uIEC/SD, of course, it was fantastic for transferring .D64 images from the internet to my C64; much faster than downloading them over a 33.6Kbps modem. The only problem is, where are the emulation partitions? The CMD HD came with a Utilities Disk, which contained the HD Tools program. This program allows you to create and manage the partition table, and set up a mix of native-mode and emulation-mode partitions. An SD Card, on the other hand, comes out of the box with a single partition that's pre-formatted FAT-32 (or FAT-16.) And there is no SD Tools program.

The first thing I did was lean back on the old D64it program by KludgeSoft. It works, and allows a .D64 file to be written out from an SD2IEC to a real 1541 disk, or to a CMD HD's 1541 emulation-mode partition. D64it can also be used to rip a 1541 disk's contents, or a 1541 emulation-mode partition's contents, to a .D64 image file on an SD2IEC. But, if you're using an SD2IEC because you aren't fortunate enough to own a CMD HD (or FD or RamLink,) what then?

That's when the guys on IRC said, "you can just mount a .D64 file directly on the SD2IEC." I almost fell out of my chair. I had no idea you could "mount" a .D64 file directly on an SD2IEC. It was such a revelation, it was so huge—and the fact that I had no idea it could be done—that it inspired me to write this:

It's too much to ask for someone to first read the CMD HD User's Manual, then to read the SD2IEC readme text file, and try to grok what their SD2IEC can do, by some roundabout thinking, about what a CMD HD does, only to layer on top SD2IEC's exceptions and limitations in some places, and extensions and improvements in other places. This is far too complicated. Most of the SD2IEC's features are going to just slip through the cracks and never be discovered. The SD2IEC User's Manual can just be read, as one would have read the CMD HD User's Manual, except everything in it is exactly pertinent to SD2IEC.

Origin of the SD2IEC User's Manual

I spent an entire summer, a little over 2 months, recreating most of the sections found in the CMD HD User's Manual, but translated and updated to being a manual for SD2IEC. Many people have written to thank me for that work, and I'm glad that they have found it useful.

So please, do me a solid, and spread far and wide the link to the SD2IEC User's Manual. It will help everyone to know more about how their SD2IEC works and what it can do.

https://www.c64os.com/post/sd2iecdocumentation

How to mount a disk image

To mount a disk image, it must be stored in a partition on the SD Card in your SD2IEC. The mounting syntax is extremely simple. You just "CD" (change directory) into the image filename. It's almost like a subdirectory, but not quite. The filename of the image has to be treated as a filename, which is a bit different than a subdirectory path. Let's look at a couple of examples of what works and what doesn't.

To navigate into a subdirectory you can do this:

@cd//some/deep/path/finalsubdir

But you cannot mount a disk image like this:

@cd//some/deep/path/mygame.d64

Instead you have to mount it like this:

@cd//some/deep/path/:mygame.d64

Note the placement of the full colon (:). In the standard CBM/CMD DOS command structure, the full colon is used to separate the partition and path from the filename. On a CMD HD you can use the full colon with the CD command to specify the name of a subdirectory that is in the current directory. On SD2IEC, this is extended; it's how you mount an image.

There are some differences when the image is mounted too. SD2IEC can mount not just D64 images, but also D71, D81 and DNP. DNP is an image of a native-mode partition from a CMD device (HD, FD, or RamLink.) When a DNP image is mounted, you can use CD commands to navigate the path structure within the native partition image. It is not however possible to use a single path all the way from the root of the SD Card and into the DNP image path structure.

The following does not work:

@cd//some/deep/path/nativepart1.dnp/games/action/

That doesn't work, syntactically, because the CD command has to mount the image first, which needs to have the image name in the filename component of the command. After which the command cannot just continue on specifying more path.

In other words, this doesn't work either:

@cd//some/deep/path/:nativepart1.dnp/games/action/

To unmount a mounted image, you use the CD← command, which is the standard way (introduced in CMD's HD DOS) to navigate up to the parent directory. A mounted .D64, D71 or D81 doesn't have subdirectories, so CD← always works to unmount those. If a DNP is mounted though, and you are in some subdirectory of that native partition image, then CD← only takes you to the parent directory.

The way to reliably unmount an image, then, is to issue two commands in a row. First command takes you to the root directory. The second command then unmounts any image, for sure.

@cd//
@cd←

The Partition Directory

On a CMD HD, you use the HD Tools program to create some partitions. Now you have a mix of native and emulation-mode partitions. Each has a name and a type, and they're numbered. Native-mode partitions are of type NAT, and the others are 41, 71, and 81. An ordinary directory, of the current partition and current directory path, can be loaded as usual, by loading "$".

A special partition directory can be loaded by loading "$=p". On an SD2IEC, typically you see just the one NAT-type partition that the SD Card shipped with. Depending on what hardware your SD2IEC has and what firmware version you're on, you may also see a special EEPROM partition. This allows you to store a couple of small programs into the EEPROM storage of the device itself, which is always the same no matter what SD Card you swap in. I don't use this for anything, but I suppose it could be useful.

What happens then when you mount a disk image? This is where things become important.

Let's say you have an SD Card with just the one partition it shipped with. You put a .D64 image into that partition. Now you mount that partition with the CD command like this:

cd:mygame.d64

Wonderful, it's mounted. Now you load and list a directory:

load"$",8
list

Again, wonderful, you're now seeing the inside of the disk image, and it looks like the whole device is a 1541. You can now load and run the software that's in that disk image. The only problem is, you're not on a real 1541. You're not on a faithful reproduction of a 1541 (such as 1541 Ultimate II+, Ultimate 64, or Pi1541), and, slightly worse for compatibility even than a CMD HD, the underlying hardware is not running on a real 6502 CPU either.

This combination of traits (D64 is mountable, lists a directory like a 1541, but it's not fully 1541 compatible) has led people to conclude: «SD2IEC is a 1541 emulator... but it's a crappy one.» This is WRONG. Wrong, wrong, wrong. And it breaks my heart to hear people say this.

Remember, the SD2IEC can load and list a partition directory. What happens when you load and list a partition directory while a disk image is mounted? If a D64 is mounted, the partition lists as type 41, not as type NAT! If a D71 or D81 is mounted the partition lists as type 71 or 81, respectively. If a DNP image is mounted, it still lists as NAT, which is maybe a bit weird, but NAT comes to mean, it supports nested subdirectories.

We've solved the mystery; we've answered the question: O Emulation Partitions, where art thou? On SD2IEC, when you mount a disk image, the partition in which that image file is stored is transformed (temporarily) into the functional equivalent of a CMD HD's emulation-mode partition. The CMD HD is not a 1541 emulator; it's a hard drive. It's a mass storage device for your Commodore 64. BUT, it gives you 1541, 1571, and 1581 emulation-mode partitions, which only reproduce the track and sector layout, for some modicum of compatibility, and to help you work with disks and disk images. That is almost a perfect description of what SD2IEC does. But rather than creating fixed emulation-mode partitions, into and out of which you must dump image files (which takes a few minutes), it allows you to mount an image file in place of, or over top of, the current partition (and it's available instantly).

Therefore, it is wrong to conceptualize an SD2IEC as a disk drive emulator. Its closest spiritual (i.e., conceptual) antecedent is the CMD HD.


<rant>
<!-- Ranty aside... if you'll indulge me -->

Somehow, no one has any mental difficulty distinguishing between the left- and the right-hand columns in "The Land of PCs," shown below. A floppy drive is a floppy drive; it's for floppy disks, low-speed, low-capacity, swappable media, not used anymore. A hard disk (or its modern SSD equivalent) is a high-speed, high-capacity, fixed media storage device. A hard disk is what you store your operating system, its applications, and all of your media on: music, movies, photographs and documents.

Matrix of floppy and hard drives.
Matrix of floppy and hard drives.

In the Commodore 64 world, though, somehow, the 1541 floppy disk drive got typecast as the canonical storage device of the machine. Which is a bit weird, considering that it is a whole separate device that you only connect to the C64 with a cable via its generic, daisy-chained, multi-device, serial bus. Nonetheless, because of this unfortunate typecasting, for some people, all other devices no matter how modern get conceptualized as a derivative of a 1541. They're measured in terms of 1541-disk-sides of capacity, they're evaluated in 1541-compatibility-scores, and so on.

The CMD HD became available, primarily for the C64 and C128, in 1990. In 1990 the Amiga 500+ was released, and it was an entirely floppy disk based computer, with optional hard drive. The Amiga 600 came out shortly thereafter, and it too could be used entirely by floppy, with an optional hard drive. And even in 1992 when the Amiga 1200 came out, the A1200 could still be used entirely by floppy, but you were missing out if you weren't using a hard drive. Everyone knows the difference between an Amiga's floppy disk drive and an Amiga's hard disk drive. The C64's hard disk availability tracks the Amiga fairly closely. Yet somehow, for some reason, a "hard drive" on a "Commodore 64" almost doesn't compute for some people; like it's an oxymoron.

</rant>


Multiple Partitions to the Rescue

Although it's very cool that on an SD2IEC you can mount a .D64 to the partition in which it is stored, it has a downside. Once mounted, the native partition in which it was stored temporarily disappears.

Mount a .D64, list the partition directory, and suddently you have only one partition and its type is 41. That's like a CMD HD that has just a single 1541 emulation-mode partition. Neat, but rather limiting. The point of the emulation-mode partitions was so you could dump a disk image (or a disk) into a partition. Then you could freely copy files, with the standard CBM/CMD DOS copy command, between a native-mode partition and the emulation-mode partition. The ability to copy between partitions and between subdirectories is part of the DOS built into the device. Let's look at an example situation (the @ commands assume JiffyDOS or some other DOS Wedge):

Change to partition #1, let's say it's a native-mode partition:

@cp1

Change into its HD tools directory, assuming you've created this already:

@cd//tools/HD Tools/

Change to partition #2, let's say it's a 1541 emulation-mode partition:

@cp2

If you've dumped the HD-tools.d64 to this partition, you can list its contents:

@$

Copy the hd-tools program to the tools directory in the native, partition 1:

@c1:hd-tools=2:hd-tools

Bingo bango. Without a file copy program, you're copying the hd-tools program (which in no way depends on running from a real 1541, anyway,) from a partition with a dump of a .D64 you fetched from the net, into a nicely organized subdirectory of tools on your main native partition. This is, in large part, how the CMD HD was intended to be used.

The solution for SD2IEC is to take the SD Card that you want to use as your main C64 storage medium, and partition it into at minimum 2 partitions. Most SD2IEC hardware is running a version of the firmware that only supports 2 partitions (plus the special EEPROM partition.) uIEC/SD is somewhat special, it supports up to 16 partitions! This is, in my opinion, more than necessary. I would be happiest if the standard 2 were more like 4, but two is much better than one. Two partitions are enough to do most things.

The intention behind this is that you can store your disk images in a second partition. They don't all have to be in the root directory, you can create a nice directory tree to organize your various disk images. When you mount a disk image stored anywhere in partition 2, it takes over partition 2, and the partition directory shows something like the following:

PART# LABEL TYPE
1 C64 OS NAT
2 SOME GAME DISK 41

Now, this is useful. It's very much like how the CMD HD intended for emulation-mode partitions to be used. You can use exactly those commands listed in the scenario above, to copy files betwen the mounted disk image and the directory structure found in the native, partition 1. It's even better than the CMD HD in some ways, because that partition 2 is a chameleon; it can instantly become a 1541 emulation-mode partition by mounting a .D64. But it can just as quickly become a 1571 or 1581 emulation-mode partition simply by mounting a .D71 or .D81 image. Mounting is instantaneous. And anything you copy to that partition is being saved to the disk image file. When you unmount, all the changes are conserved within the .D64 (D71, D81 or DNP) file, ready to be shared with the world again.

All of this, including instructions for how to create partitions using the diskutil command line program in macOS, is described and covered by the Partitions chapter of the SD2IEC User's Manual.

C64 OS and Disk Mounting

Starting in version 1.03, C64 OS gains the ability to mount disk images on SD2IEC, right from inside the File Manager.

When a file is opened (by double-click or by the File → Open menu option) File Manager handles all files the same way; it opens the Opener Utility. At first, the Opener starts up but doesn't create its Toolkit-based user interface or show its window. It's the job of the Opener to extract the CBM File Type (PRG, SEQ, USR, etc.) and the file's extension: 1 to 6 characters, at the end of a filename (postfix), following a dot, or, 1 to 6 characters at the start of a filename (prefix), before a dot. Postfix is always given preferential consideration.

Opener then looks for an assign file. It searches //os/settings/assigns/ for a filename that matches the pattern:

ft.type.ext

Some example assign files:

//os/settings/assigns/:ft.prg.koa
//os/settings/assigns/:ft.seq.car
//os/settings/assigns/:ft.seq.txt
...

ft stands for "file type", as there may be other kinds of assigns in the future. If an assign file is not found, the Opener Utility creates its UI and shows its window. This lets you pick an Application or a Utility in which to open that file, and optionally lets you assign the selected Application or Utility to open this kind of file by default.

Learn more about assigns and the Opener Utility in Chapter 7: Utilities → Helper Utilities → Opener of the C64 OS User's Guide.



In C64 OS v1.03, there is a new Utility called "Mount", plus there are 4 default assigns already set up that assign Mount as the Utility for handling .D64, .D71, .D81 and .DNP files. (All assigns are case insensitive, by the way.) Thus, you double-click a .D64, it opens the Opener Utility (silently), it pulls out the type and extension and looks up the assign, it finds the assign and reads it in. The assign indicates that the Mount Utility is assigned to open .D64 files. Opener then closes itself and opens the Mount Utility.

The new Mount Utility in v1.03
The new Mount Utility in v1.03

The Mount Utility displays the filename that is to be mounted, hawksmill.d64 in the above example. It then extracts some information to display. The image type and size. And it states the device number and partition to which it will be mounted. Finally it has a short status message. "This image can be mounted here."

That status message is important. Because, not every selected file can be mounted. We'll go through these one at a time to see why not. Here's the complete list of status messages that Mount can show:

  1. Selected file is not a disk image
  2. Cannot mount to boot partition
  3. Device cannot mount images
  4. Already within a mounted image
  5. This image can be mounted here


Selected file is not a disk image

Mount doesn't do anything too sophisticated here. It just checks to make sure the file's extension is valid. It supports D41, D64, D71, D81 and DNP. It checks it case insensitively, and only supports postfix extensions.

Unlike C64 OS more generally, SD2IEC does not allow mounting an image file with a prefixed extension. If the file doesn't have a valid extension, you get this message. You might think, but Mount only opens when you try to open one of these files. C64 OS is more flexible than that. You can manually open the Mount Utility. And you can change what file is selected while leaving Mount open. Each time the file selection changes, Mount refreshes to show information and status of the selected file.

Cannot mount to boot partition

C64 OS must always have access to its system directory. There is no way around that. C64 OS system processes simply take for granted that the system directory is always present. This is why, for example, in the Drives Utility there is a flag beside the system device, and the eject button is disabled when it's selected.

Mounting an image takes over and temporarily converts the partition into an emulation-mode partition. If an image is stored in the same partition that hosts the C64 OS system directory, then mounting it there would, in effect, temporarily unmount the C64 OS system partition! This is simply not permitted. So Mount checks to see if the device # and partition # match those of the system file reference. If they do, the mount button is disabled and you get this status message.

Device cannot mount images

Remember, C64 OS doesn't only support SD2IEC devices. It is entirely possible that you have a RamLink, or a CMD HD, or an IDE64. Even a 1581 disk can hold a .D64 or .D71 image file. Mount consults the C64 OS detected drives table to determine if the device # is an SD2IEC.

We're out in the complex situations here, but, there is nothing limiting you from having 2 or more SD2IEC devices connected to the same computer at the same time. However, only an SD2IEC (for now) has this magical ability to mount disk images. If the device on which the image is stored is not an SD2IEC you'll get this status message.

Already within a mounted image

Here's another interesting situation. It is entirely possible that a DNP image, or even a D81 image, could itself contain other disk image files. If that's the case, if you have a DNP image mounted, and inside you find a .D64 and double-click it, now you have a situation in which you're trying to mount an image that is found within an image. This is not supported by SD2IEC.

Ironically, by some tired, sleepless-night logic, I mistakenly thought it was possible. Turns out I had a genuine subdirectory whose name was "hostages.d64". In my late-night stupor I failed to notice that, although the extension was .d64, the CBM file type was DIR not PRG (nor SEQ). I knew I had a .DNP image already mounted and attempted the CD:hostages.d64 command, and was blown away that it worked! It mounted an image from within an image. Embarrasingly, I even took a video of my amazement and posted it on Twitter. The video was viewed a pile of times, but no one else seemed to notice either!

It is, in fact, not possible to mount an image from within a mounted image, as cool as that would be. There is some low-level trickery that can be used to determine if an image is currently mounted, and Mount performs that check. If you're already within an image, you get this message.

This image can be mounted here

Lastly, finally, if the image is on an SD2IEC, but not within another image, and the image is stored in a partition that is not the C64 OS system partition, then the image is mountable and you get this lovely status message.

This is the only status message for which the mount button is also enabled. To mount the image, simply click the Mount button. The Utility closes, and the directory beneath refreshes to show you the root directory of the image.


Unmounting a Disk Image

Once an image is mounted, you can navigate around your devices and change partitions, and navigate through directories, and that image remains mounted, just as though that partition were a genuine emulation-mode partition on a CMD HD.

If you click on the SD2IEC device from the list of devices in the top half of the lefthand sidebar, you're taken back to the partition directory of the device. You can see that the partition directory shows one of the partitions as type "4" (or 7 or 8) for 1541 (or 1571 or 1581).

You can use any of File Manager's features for working with any of those files. For example, to move or copy files between any directory, of any partition, of any device, and that mounted disk image. Or to rename files in the disk image, or lock or unlock files, or scratch files on the disk image.

What about when you want to unmount the disk image? Starting in v1.03, File Manager's Options menu now has an "unmount" menu item. It doesn't do a complete check to absolutely confirm that you are in a mounted image, but it does some simple checks. If the current device is not an SD2IEC, the unmount menu item is disabled. If the current partition (of the selected tab) is the C64 OS system partition, the unmount menu item is disabled. Otherwise, it's enabled whether you're actually in a mounted image or not.

To unmount a mounted image, then, you simply have the current tab anywhere within a mounted image, and choose unmount from the Options menu. File Manager goes through the standard procedure. First it issues a cd// to get back to the root directory if it's a DNP image. Then it issues a cd← to unmount the image.

Finding our way back

We have a problem though. And that problem is, finding our way back to where we were before mounting the image. Let me explain.

Early on in the development of C64 OS, I was trying to figure out how or if it is possible to query the drive itself to determine the current directory path. It turns out, this is really complicated, but its doable on a CMD HD (or RamLink or CMD FD.) It requires a lot of manual block reading and pointer following, and directory parsing. It's brutally inefficient, but it's technically possible. On an SD2IEC, however, which, under the hood, is based on a FAT file system, even this technical trickery is not available.

I stumbled upon an old discussion thread about this on Google groups, where Glenn Holmer was asking this very question to Jim Brain. Eventually, as development of C64 OS progressed, it became obvious to me what the solution is. The solution is to write your software in such a way that it doesn't depend on querying the drive to obtain the path. Rather, use your software to keep a path string in memory. You want to navigate into a directory? Append that directory name to your path string. You want to go up a directory? Remove that last path component from your path string. The sky is the limit to how you can display and manipulate that path string.

This essential technique became the foundation of C64 OS File References. In File Manager, each tab has its own file reference. As you navigate around within a tab, its file reference is continually updated.

The problem is, let's say your disk image ("hostages.d64") is stored on device 8, partition 2, in the directory //games/h/. While you're in that tab, and that image is selected and the Mount Utility is open ready to mount it, the file reference for that tab looks like this:

8:2:hostages.d64://games/h/

Now, you mount the image. Whoa! Wait a second here. Suddenly partition 2 isn't a native partition anymore. Now it's a 1541 emulation-mode partition, and those don't support subdirectories. So, that means the path component of this file reference is invalid. The solution of course is to replace the path with //, so that you're in the root directory of the image.

That works, but now we have a new problem. What happens when we unmount the disk image? When the disk image is unmounted, the device ends up in a directory where the disk image is stored, and we'd like to present that directory to the user. That's the most intuitive thing. You're in //games/h/ when you mount hostages.d64 to see what's inside, you immediately unmount and you want to find yourself back in //games/h/ ready to try to mount a different game image that starts with h. Right? But, we've obliterated the path name in the tab's file reference, and we can't query the device to know what path it's at.

One solution is to copy the path name to some temporary memory variable. Like, maybe each tab gets its own special string variable to hold the original path of a tab that can be restored when whatever's in that tab gets unmounted. That would work, but there is nothing saying you have to unmount that image right away. You could leave the image mounted, and switch to App Launcher or open some other Application. When you come back to File Manager, those temporary variables would be gone, and you're back to the problem. Or, alternatively, you could quit from C64 OS back to BASIC! The image will still be mounted. When you reboot into C64 OS, all the temporary variables are gone again.

The solution I came up with is as follows. When you mount an image, the Mount Utility first creates a file called ".here" in the current directory, and writes the path component of the tab's file reference into that file. Then it mounts the image, and replaces the path with "//" (root directory).

You can now leave File Manager, by launching another App, or switching to App Launcher, or even leaving C64 OS altogether. When you return to File Manager, and unmount that image, without knowing what the current directory is, File Manager reads the contents of ".here" into the file reference, and then scratches the ".here" file. When the directory is reloaded by way of the file reference, the .here file no longer exists, so you don't even see that it was ever created. If for some reason the .here file couldn't be found, it defaults the tab's file reference back to the root directory.

It is possible that you'll see the .here file. If you quit to BASIC, and then reset or power cycle the computer, SD2IEC will automatically unmount the image when it resets. You could also manually unmount the image from the READY prompt. At this point, the .here file is still there, and when you reboot C64 OS, you'll see it in File Manager. In my opinion, that's a small price to pay for the standard workflow of being able to use File Manager and Mount to be able to move into and out of a disk image seamlessly.

At some point in the future, the C64 OS directory library will probably gain the ability to treat files whose names begin with a dot as hidden files, and have the ability to skip them while loading the directory. In which case, you won't see the orphaned .here file anyway. And one final point, if you do see a .here file, it's likely to be found in a directory also containing a disk image that you have at some point in the past mounted. If you simply ignore the .here file, and mount a disk image from that directory again, then when you unmount it, that .here file will get automatically cleaned up again. I.e., it will become unorphaned.


Final Thoughts

Well, that was fun! It's been a while since I've blogged. And I realize that, while the User's Guide is a useful document for telling you how to use a feature in C64 OS, it is an inappropriate medium for going off into the weeds to talk about the technical details, the challenges, the solutions to problems, etc.

Weblog posts are allowed to get as deep in the weeds as I want to go. You, dear reader, are free to explore them to get a deeper understanding of what's going in C64 OS. And the posts can link to the User's Guide where it makes sense to do that, AND, the User's Guide can link to the weblog posts too, to let the reader know that if they're interested in a deeper exploration of how something works, there's a place for that.

There are tons of new technologies in C64 OS that I've been unable to blog about because I've been so busy fullfilling orders, fixing bugs, working on new updates, writing the User's Guide and now the Programmer's Guide, and discussing stuff with beta testers and developers on Discord. I'm really hoping to keep being able to find the time to write posts like this one. Until next time. Enjoy using your Commodore 64!

  1. According to this site at least. https://blog.reedsy.com/how-many-words-in-a-novel/
  2. That sounds impressive, doesn't it?
  3. As long as the content is small enough to fit in the disk image, and the content doesn't require subdirectories. But most C64 software does and doesn't, respectively.
  4. Although you're welcome to change this, of course.

Do you like what you see?

You've just read one of my high-quality, long-form, weblog posts, for free! First, thank you for your interest, it makes producing this content feel worthwhile. I love to hear your input and feedback in the forums below. And I do my best to answer every question.

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 purchasing one of the items I am currently offering 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!