NEWS, EDITORIALS, REFERENCE
Well, at the very least, this post has got the right number!1 Although I don't know if its content will live up to the hype of the number, I do have some fun stuff to show today. We'll be looking at the menu system in C64 OS, seeing it in action, and doing a comparison to GEOS. It's just as a friendly comparison, since GEOS is the quintessential OS-with-menus that people think about on the C64. So, how do they stack up?
The menu system was something I started designing a long time ago. In my head it was something I knew I wanted to have, and I spent a good deal of time pondering how it could all come together. Consequently, the menu system has been mentioned many times and is the subject of at least two posts from early last year. Recursion and C64 OS's Menu UI (3/3) from March 1st, 2017 when I did a technical deep dive on writing recursive code in 6502 ASM. And then again on May 9th 2017, in Pointers in Practice, Menus, which was a programming theory post about pointers and how they can be used in creating hierarchical data structures.
I'll be the first to admit that I'm apparently a slow coder. In the earliest days it was a huge hill for me to climb to understand how to do anything in assembly language. And I went through many stages of reforming the code in order to be able to sustain large project development coding natively on the C64 itself. Additionally, I've really had to educate myself about each new aspect of the computer as I've gone. Learning about how the CPU works, and the VIC modes, and how memory is mapped, and how the CIAs can be programmed, and how to use interrupts, etc. It's been quite a trip.
But it has all come to fruition. I had the menus actually functioning and doing what I wanted them to starting maybe 3 or 4 months ago. Since then I've been adjusting them, and experimenting with what I can do with them in the context of writing a real world application, or the new C64 OS utilities. This has lead to the addition of numerous small features and behavioral tweaks to get them to where they are now. I'm finally ready to show them in action, and I'm really eager to get into a technical discussion about how they work and all that you can do with them. So let's dig in.
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
I feel like I'm late to the party. When I started the Commodore 8 Bit Buyer's Guide, one of the things I knew I had to do was have a special feature section and put the 1541 Ultimate II+ top front and center.
It seemed like everyone was talking about it, and raving about how great it is. Sight unseen, I took a couple of quotes from people on Twitter, did my research online, and wrote a Buyer's Guide feature about this contraption, built and brought to us by Gideon's Logic Architectures. In that My Take, which is in essence a mini–review, I described the 1541UII+ (as it is frequently referred to for short) as the The Jesus Device. And that epithet is well earned, but there are a couple of small caveats.
Gideon's Logic Architectures — Webstore
Almost five months ago, Christmas 2017 was over, but daddy needed a little retro pick me up. At the very start of the year, January 2nd, 2018, I placed an order so I could finally get my hands on one and join the crowd. When I placed my order, they were temporarily on back order waiting for a new batch of stock to come in.
I didn't have to wait too long, just a hair over 6 weeks from time of order to the day it arrived, on February 16. And that time included the delay for getting the device back into stock. I tweeted out the day it arrived. As you can see, I got one of the white ones.
Reading other people's thoughts and reviews and some online documentation is one thing, but there is nothing quite like having something in your hands. The very first thing I noticed when I took it out of the package was the professional quality of the enclosure. It doesn't just look svelt and smooth, it feels really solid in your hand. The seams and cutouts are totally custom for the hardware features of this uber–cartridge. The buttons have a great clicky feel, and that's important, because you're gonna be pushing those buttons a lot.
There is so much to talk about with the 1541 Ultimate, it's hard to know where to start. So, I guess I'll start at the top, the unboxing. Then I'll work my way into exactly what it is this device is and what it can do. And I'll link to the reviews of others along the way. A lot has already been said and demonstrated, and I don't want to just repeat the work of others.
In this post we're going to talk about mouse tracking and the difference between proportionality, speed and acceleration.
I'm a big fan of acceleration for reasons that we'll get into shortly, including a video demonstration. But I didn't realize until fairly recently, when I started doing research on the topic, that mouse acceleration is actually a very contentious issue, particularly amongst PC gamers.1 But it's also a sticking point for switchers from PC to Mac (or vice versa) because the default acceleration curves are different between the two operating systems. This can lead to your muscle memory making wrong predictions about how the mouse cursor will move on the screen based on how you move the mouse around on the table. It's such an annoyance for some people that there are numerous third party utilities for both platforms that allow you to override the system defaults and customize the mouse movement much more finely.
Most C64 users back in the day had a joystick, or two or ten. But only a small number of those same users also had a mouse. I was one of the former for at least several years. My first C64 was a second–hand C64c, with a 1541-II, an EPYX Fastload cartridge and an original copy of GEOS v1.2 included in (and advertised on) the box. I also had several joysticks and no mouse.
When I discovered GEOS, it was my first experience with a graphical user interface and it positively captivated me. It is probably the reason I am still obsessed with operating systems 28 years later. GEOS comes with loadable drivers for different input devices, so it supports either a joystick or a mouse.
What is a Directional Input Device?
A C64 joystick is a directional input device. It essentially consists of 5 digital (on/off) buttons. Up/down/left/right and fire. If you press the left-button and hold it down, then every 60th of a second the computer uses the same CIA chip it uses to scan the keyboard to notice that the button is depressed. But from scan to scan there is fundamentally no change of input, it just notices that the button is still held down. Given this unchanging, digitally ON state, how far should the computer move the on–screen cursor at each 60th of a second?
This is a very short, practical, follow–up to my post earlier in the week about my final direction with how to implement timers in C64 OS.
I implemented the input module a long time ago, it was one of the very first modules of code I wrote for C64 OS. It is sort of a combination of mouse and keyboard driver, and maintains queues of the three broad categories of input events: Mouse Events, Keyboard Command Events and Printable Key Events. You can read all about this, from my post The Event Model, which was published in January 2017.
The mouse events consist of mostly mouse primitives, this excludes drag and drop events, for example. It also excludes boundary crossing events such as mouseover and mouseout. So the events that it supports are:
- left down
- left tracking
- left up
- right down
- right up
Additionally, I considered to be of sufficient primitiveness, left click, left double click and right click. These are ever so slightly more than purely primitive, because a click is a not a state of a button, but rather it is a sequence of button states with a temporal aspect. If you mouse down and then later mouse up, but too much time has passed, a click will not be generated. In order to really get it right, the whole thing turned out to be more complicated then I was anticipating.
I love learning. And let me tell you, working on a big project that pushes your boundaries is just one learning experience after another. I've got quite a bit of code in C64 OS now, and so after I've been working on some areas for a while and neglecting others, I sometimes go back to code I wrote months ago, look it over and say:
What the hell was I thinking back then? Greg Naçu — 2018
I'll give you a quick example.
I probably “finished” writing the majority of the code in the screen module what feels like a year ago. The screen module implements the main event loop, fetches events from the event queues and distributes them to screen layers. The code also tracks screen layers and lets you push them and pop them to and from the screen layer stack, among other things. I looked over that code, and realized the way I was doing the pushing and popping, the way I was tracking the screen layers and accessing them, it was almost insane. In the intervening months I've just learned and improved so much that when I go back and look at my old variable naming conventions, code formatting, and comment style, they look horrible.
Not to mention the way it actually works. I've done lots of silly amateur stuff, like, loading the accumulator and then immediately comparing it to zero with CMP before doing a branch on equal to zero. In case you're unaware, that's pretty dumb. Loading the accumulator accordingly sets the Zero flag automatically. Comparing to 0, in this case, is just busy work.
Another example can be found in technique. There are two ways you can make a table of pointers. You can make a single array of 2–byte elements. But if you do this, your byte–index into the table has to increment and decrement by two to track the array offset. And to get the high byte of one of the pointers, for example, you have to set the index to: (array offset)*2 + 1. Alternatively, you can split the pointers into two arrays of 1–byte elements, a table for lo bytes and a table for hi bytes. To move through these tables you just increment and decrement the index by one. To get the high byte, (if the X index register is already set,) it's just LDA HIBYTES,X. And to get the low byte the index stays exactly the same, and it's just LDA LOBYTES,X. And so on and so forth.
Live and learn, right? Learning the practicals of programming is like learning to play pool. You can know all about geometry, but if you don't have that muscle memory and instinctive experience, your pool game is gonna suck.
We're back. This is a quick post to discuss a cool little programming technique I came up with recently. It's a "Switch" Macro. Let's just hop right in.
If you've ever written code in a high level language you're familiar with the usual flow control statements. You have if, else and else if statements, a few types of loop, for, while and do while, and a few others.1 One of the things that tripped me up when starting to learn 6502 is how to replicate some of these fairly mundane flow mechanisms.
For example, in an if–statement you can use logical operators to chain numerous checks that together determine if the code inside that block should be executed or not. But how do you do that sort of thing in 6502 when you only have branch operations on single conditions? Well, you have to do it very manually. When conditions are ANDed together you check each condition one at a time, and if any one of them is not true you use it to branch past the whole block. And you do the opposite for ORing conditions. You check a condition, and if it's true you branch past the condition checking and straight into the block of code. If you make it past all the condition checking and nothing branched you into the code, then you have a default branch at the bottom that skips the block of code.
Here's an example of 3 conditions ANDed together:
And here's an example of 3 conditions ORed together:
Note how there is a bit of a shortcut on the last branch of the OR conditions. Because it's the last one being checked, if it doesn't pass you can branch to skip, otherwise flow will fall through to the code.
Happy Easter 6502 and C64 fans! Here's some long–weekend reading, going into more detail about sorting algorithms on the C64 than you probably ever thought you wanted to know. Enjoy!
C64s are interesting computers. They have lots of character. But it's hard to put your finger on exactly why that is sometimes. What is it that endears us to this humble little machine, all these years after its commercial decline in the late 80's early 90's? My guess is that it is a confluence of artsy factors that aren't replicated on other platforms, despite their technical superiority.
Let me give you an example.
Sourced from this Twitter Moment
The above is a directory listing, probably from a 1541 disk, but could also be from any other drive that supports the standard structure. And that is just amazing! It's so artistic. It's so novel and fun, and makes the C64 artsy and nonconformant. But how is this sort of thing even possible? Why don't we see this sort of thing on other platforms?
The directory art trick, to take this one example of what's fun about a C64, is enabled by three general factors. The first is PETSCII itself. While it's missing a bunch of important business characters from ASCII, it has a brilliant set of graphical symbols that makes it possible to draw clever and complex text-based images. Check out this older post of mine, Why PETSCII Anyway?
The next factor is the simple and unvalidated structure of the directory blocks on the disk. The structure is so simple that it can easily be understood from a description in a book. And numerous tools and utilities have popped over the years that allow direct editing of the disk sectors. This allows one to make a filename have odd properties, such as a quote mid file that allows the file to be loaded by its first two characters, but still spits out the remaining characters when loading a directory. Those remaining characters can be PETSCII'd to the max, in fulfillment of your artistic desires. Or, marking files as deleted, even though they still remain in the directory. These delightful hacks are possible due to the simplicity of the structure, but also because the code that outputs it does so quite blindly and doesn't care if it deviates from a more stringent norm.
But, for the purposes of this post today, it is the third factor which is the most relevant. Directory listings on a C64 are unsorted.
I've had my head down, programming away on C64 OS, and been making some great progress. I've tweeted a few things out, some of which are revealing of things I've either never talked about here or even seem to contradict what I've said here. So I'd like to take a breather and talk about some of these developments.
When I started working on C64 OS, I was really just beginning to learn to program in 6502. I'd had a bit of experience from the past, but nothing extensive. I extended the digital audio driver in WiNGs from mono to stereo, for example. But that only involved a handful of lines of code. I played around a bit back in the day with some demo techniques, like making a raster bar. Demo coding always felt like too much work to produce something that would be a mere demonstration of some visual capability of the machine. And I plinked around with Geos and Wheels coding after getting a SuperCPU, but before falling headlong in love with WiNGs. As I've said before though, most of my WiNGs coding was done in C. And the vast resources, standard C memory management coupled with many megabytes of ram, meant that coding for WiNGs kind of felt like coding for an old PC.
This time it's different. I can now say with confidence that I'm a 6502 programmer. I don't know all the tricks yet, there is a lot to learn, especially from experience, but I know how the game is played now, and I'm knee deep in the mud.
One of the most shocking and difficult–to–get–used–to qualities of the C64, (besides low screen resolution, low clock speed and slow disk I/O) is the sheer lack of ram. 64K may have seemed big in 1982, but today 64 megabytes feels impossibly small. The small size of 64 kilobytes is hard to even fathom. To help visualize it, I just whipped up this image, 256x256, with grid lines every 16 pixels, and 16 subdivisions, one for each pixel. Then I zoomed in enough so you can see the grid lines.
Here it is:
The question driving the creation of this reference table is simple: If I press a key, or a key combined with one of the modifier keys (Shift, C=, or Control) what is going to appear on the screen?
Surprisingly, the answer is not straightforward. The keycaps of the Commodore 8-Bit family are famous for including a series of foreign–looking graphical symbols, sometimes on the key surface, sometimes printed on the front vertical face of the key. If you've ever used a C64, 128 or Vic-20, you know that in the mode immediately after turning the machine one, pressing a letter key will give you an uppercase letter, pressing shift and a letter will give you the right symbol of the two graphic symbols that appear on the key. Pressing C=Key and a letter will give you the left graphic symbol on the key.
But this is only the beginning. Many of the non–letter keys also have symbols, but not every symbol that you can generate with modifier combinations is represented on every key. And to make matters more complicated, switching the character set to uppercase/lowercase introduces other symbols that are not visible on the keycaps.
The tables below show what glyph will be produced on the screen for every key on the keyboard, in each of four possible modifications (Unmodified, Shift, C=, Control), in both character sets. See below for a full discussion.
|Row 1||Uppercase / Graphics||Lowercase / Uppercase|
|9||reverse on||reverse on|
|0||reverse off||reverse off|
|£||$1C, red||$1C, red|
|Row 2||Uppercase / Graphics||Lowercase / Uppercase|
|CONTROL||modifier key||modifier key||modifier key||modifier key||modifier key||modifier key||modifier key||modifier key|
|Q||$11, cursor down||$11, cursor down|
|E||$05, white||$05, white|
|R||$12, reverse||$12, reverse|
|T||$14, delete||$14, delete|
|I||$09, unlock||$09, unlock|
|↑||$1E, green||$1E, green|
* RESTORE generates a hardware NMI signal direct to the CPU.
Happy Valentine's Day, 6502 freaks. Here's a new genre of post, I've tagged this as: Programming Practice, because it gets right into the nitty gritty of a practical problem and the steps taken to fix it. This post includes a 30 minute video of a realtime debugging session. If a picture is worth a thousand words, well then, a video has gotta be worth something.
Late last month I posted my first video update. A video update is kind of cool because as I build out C64 OS, there will be more and more interesting things to see. And pictures are handy, but a video really gives you a flavor for how fast something is loading, or how the mouse is responding and how the screen is refreshing, etc.
In my video update, which was only a couple of minutes long, I held the camera in my left hand and worked the computer and the demo with my right. That's fine for a short clip, but to really get into the weeds you need your hands free and therefore a stand for your camera. I banged together a decent makeshift camera stand out of nothing more than a stiff metal coat–hanger, with a grippy rubber coating. My workspace is under a stairwell, so the ceiling is quite low. Hanging the coat–hanger from the ceiling works perfectly and positions it to point straight at the monitor.
Let's get into this video debugging session, and take a glance into some native coding.
I began this video knowing I had an interesting bug to find. It's interesting because it has a clear visual artifact and involves several low–level code modules that I'm working through for the first time.
Before I started my hunt for this bug, it struck me, this would be a great opportunity to catch the entire process in a video. I spend the first few minutes talking about the general layout of the source code and the convention I use for filename extensions. Then I spend maybe a minute describing the basic problem I'm having, and then we just hop right into using some tools, like DraBrowse64, Turbo Macro Pro, SuperMon64+ and JiffyDOS commands. The goal is to show how one goes about using the tools available on a C64 to hypothesize about the problem, run some tests, modify the code, reassemble and test again.
The video concludes with me being very self–satisfied, having diagnosed the problem, found the bug and fixed it, and showing that the result of the fix has removed the offending visual artifact.
WAIT, hold on. That's not the end of the story...
Shortly after concluding the video I decided I really should run it against a couple of additional test files. I very quickly noticed that I was getting unexpected results. Off video, I ended up going back into the debugging process, and after about 2 hours of testing some things out, I finally realized what the real source of the problem was. The fix shown in the video is completely wrong. It solves the visual problem by fluke, and in fact the entire on–screen display is wrong, symptomatic of the real problem, but it's only subtly wrong in a way that is hard to notice.
So, watch the video, and see how the tools work and the general process of debugging native code. And then read on below for a full description: What went wrong? How did I mis-diagnose the problem? How did my bogus fix look like it solved the problem? And what was the real problem and the real fix?
Above are previews of the 10 most recent posts.
Below are titles of the 5 next most recent posts.