compact musings of a multi faceted geek

I'll be talking about re-implementing the BASIC interpreter from the Commodore C-64 in Ruby at the Baltic Ruby conference in Malmö in less than two weeks (if time permits, I'll try to betatest it at the Ruby Unconf in Hamburg where I'll be MCing).

In this post I want to summarize my high level findings and the challenges.

Reading 6502 assembler code (which is what Paul Allen and Bill Gates used to implement their BASIC interpreter) and trying to understand what's going on is tricky. Assembler code, even from back in the early days of the 6502 is full of mad scientist level tricks that are often necessary to get something relatively complex like a full BASIC interpreter running with the very limited resources available.

Some really good resources

Luckily, there are a ton of resources that explain the code, the best one probably being the multi source commented ROM listing from Pagetable that pulls in commentary from various sources.

There are two main parts to the functionality of Commodore BASIC V2 as this version is called: The editor loop and the interpreter loop.

The editor loop, as the name suggests is, a very simple, yet somewhat effective line editor for both BASIC programs and for executing BASIC code directly. Think of this as if you would be writing your Ruby code in IRB. The line editor takes input and copies it over into a buffer until you hit Enter. After that, the line is “tokenized” which means that keywords are turned into single bytes (sitting in the upper half of the 8 bit spectrum). Everything else is more or less untouched. If the line started with a number, that number is interpreted as a line number and saved to the BASIC memory. If no line number is added, the code is directly thrown at the interpreter itself and executed.

The interpreter

The interpreter itself can be divided into several interesting pieces of code. The inner loop is actually relatively short, it checks for the before mentioned tokens and uses a jump table to run the commands behind the tokens. If non-token characters turn up in the inner loop, there aren't a ton of possibilities: normal letters are probably variable assignments (the LET keyword is optional here), colons divide commands, etc.

Expression evaluation

Commands consume their own arguments and one of the most important routines to do that is the formula evaluator that condenses down expressions to a single value (either a string or a number) in the end. This is the part I am currently working on and it is infuriatingly difficult to trace different inputs through the code. The inner code already starts with this neat trick:

6502 asm .BYTE $24 PHA On first run, when the code goes through this, the byte 0x24 (the BIT opcode) turns the following PHA into the argument for BIT, thus skipping the PHA. The interpreter later jumps directly to the PHA opcode instead, so this is only skipped on the first run.

About the Status Register

One interesting bit about assembler (and specifically about 6502 machine code) is that a ton of instructions set processor flags in the so called Status Register (SR) like the Zero Bit, the Carry bit and so on. This is used a lot and often a ton of tests follow after the initial operation that set the flags. If reading the code, it is important to keep in mind all the different instructions that do change the flags, because if you don't, the code does not make any sense. For example, a simple LDA that loads a value (or the contents of a memory address) into the accumulator, already sets the Zero flag and the Negative flag depending on the incoming value. So basically, a zero test is “free” in the sense that it does not involve an extra opcode for the test.

That RTS trick.

Another thing that happens regularly is to “misuse” JSR and RTS. JSR is “Jump to Subroutine” and it works by placing the program counter (PC) on the stack, then jumping to the address given. RTS takes the address from the stack, jumps back to it (and increases the PC afterwards so that you end up on the instruction after the JSR). There are two important things here: When you put things on the stack yourself (with PHA), you need to make sure you don't accidentally end up at an RTS instruction and you've made yourself a nice bug jumping into whoknowswhere. The other part is that of course you can use this for some trickery. If you, say, in a subroutine put an address on the stack you created by referencing a lookup table, and you RTS, then the address gets called and if that subroutine also ends with an RTS, it will jump directly back to your original call site. Neat. This trick gets used in Micro-Soft BASIC a lot and not always in that rather simple form I just described.

This all does make the formula evaluator really tricky to fully understand, but admittedly, it does have a pretty big job: It does comparisons, math, string concatenation, evaluates functions and needs to respect precedence rules (think: multiplication before addition etc.), so it more or less resolves the various arguments and operations into a form that resembles reverse polish notation on the stack which then can be collapsed into a single result.

Global state of emergency

The last thing I wanted to quickly mention is the amount of global state that is at play here. The 6502 has a concept of a “zero page”, which are the first 256 bytes of memory, which then can be addressed directly. There are separate opcodes for instructions using the zero page and using these as much as possible is beneficial because it saves space, even though they are only sometimes faster. If you look at how the basic interpreter uses the zero page, for example at the memory map at Pagetable, you can see that it is filled to the brim.

It's a really interesting challenge to somehow transfer this to somewhat idiomatic ruby code and still convey some of the trickery. Only time will tell if I did a good job but it definitely feels like I will need to do a few loops of refactoring to make it readable and instructive and still somewhat in the spirit of the original.

Somehow I used to think that with Windows 11 and WSL2 and Windows Terminal, I finally found my daily driver for good. And it worked for what I had to do. Never mind that this crappy laptop (Just a Dell XPS15, nothing fancy, he says and cries himself to sleep) is quite unstable and the graphics card still freezes from time to time, an error the Dell support still denies to be a systematic problem, despite hundreds of reports on forums and despite the fact that nothing in this laptop except for screen, keyboard and case are original, as the support slowly went through all the components.

Never mind that Windows 11 started out quite nicely and now gets seemingly worse with every update while Microsoft is trying to force feed us their brand of AI companion BS.

But then, after I wrapped up a contract that more or less required me to use Windows (or MacOS, but that's a different rabbit hole), I thought to myself that it would be interesting to try out Linux as a daily driver again. I still make music on Windows, as my DAW of choice requires it (or MacOS, but that's a different rabbit hole) but machines boot fast these days and switching operating systems isn't as painful as it maybe was.

I am running Pop!OS on my XPS now, with Windows on a separate SSD (the one thing the XPS has going for it is that most components are swappable).

And I have to say, for the most part, it does feel a lot nicer. Pop!OS is quite the polished experience for the most part, basically being a slightly unfucked Ubuntu. There are some drawbacks. Funnily, from a day-to-day annoyances perspective the worst is the usage of systemd-boot, as the version used by Pop!OS doesn't have a config to always reboot into the last choice and if you have ever watched a Windows system update itself you know how painful that omission can be. I am hopeful that this gets fixed with Pop!OS 24.04 and hopefully that isn't too far out.

Another annoyance is that the default theme has the exact same colors for active and non active window titles. Easily fixed by choosing another theme, but really, who did make that decision? It seems so weird given the rest of the UI polish.

And then I changed my default browser. I was using Vivaldi for quite some time now and really enjoyed it for its special features such as the sidebar. But it had a tendency to block up the computer for extended amounts of time when a particularly gnarly website was trying to do its thing and also, on Windows, it sometimes wouldn't want to start for the first 15 minutes after booting. Not ideal. I must admit, I never really tried to debug this with the Vivaldi folks and I am sorry for that. They are good people and if Vivaldi works for you, I think it is a really good browser.

Instead I went back to Firefox. I still don't understand the tab design, but I have to say, it is a damn good browser. And with a good ad blocker and the Multi-Account containers, it has become essential to my daily work.

And so I seem to currently slowly drift towards FOSS. It's not super surprising to me that this happens now, given my daily struggle with end time capitalism etc. etc. but it is funny to look at a ton of decisions I made throughout the last few months and see the patterns emerge even though the decisions were made in isolation.

Bit of a weird time right now. For the first time in my career I feel like I am actually in trouble of not finding enough work to sustain my lifestyle. Not sure if that's really the case (I have yet to really start actively looking for jobs as I am currently busy with finishing old jobs), but it certainly feels that way.

I could probably write a whole blog post about how the landscape has changed and why the beginning of 2024 feels so challenging, but this post is not about that.

Instead, one of the things I'm pondering is to take this as a signal to bring my own ideas to life – I am fine, financially, at least for now and it could be a good time to be doing that – Crowdfunding does still seem to somewhat work and people may be able to shell out some money for really useful services.

I have a bunch of old ideas lying around, a wide bouquet of things and not all of these ideas aged particularly well, but some of them seem to be worth revisiting. And so that's what I'm doing. Looking at old notes, existing code, etc.

Thing is: I have been terrible at executing my own ideas for a long time. Depfu really is the first thing that worked, and I do credit Florian for being the force that keeps me going. I am relatively sure I wouldn't have been able to pull that off on my own. Well, maybe he would claim the same thing.

So, one of the things I am considering for these ideas is to put them out there and look for collaborators. I am not sure how one does that, but if the last few years have shown me something is that I am really great at working alone and also really bad at working alone on my own stuff.

I will probably describe some of my ideas here in later blog posts to see if any of them garner interest. I long felt that playing with the cards close to my chest might be the right thing so that people don't steal my ideas, but I do feel different about that now. Ideas are cheap. It's the execution that matters, and that's the hard part. If someone steals my idea and executes them, I can't really complain, can I?`

Anyway. Let me scan through these ideas and see if there's anything there that feels that it's still relevant in 2024.

CW: Personal health, somewhat detailed descriptions of illnesses, negative thoughts

For some reason, both my SO's and my birthdays seem to attract smaller and bigger catastrophes like a magnet for a while now. This time, my SO spent her birthday in a hospital, recovering from foot surgery (I luckily was able to pick her up later that day. With somewhat of a fever because of a very bad cold that luckily turned out to be not COVID).

I am currently recovering from a rather frightening gastrointestinal incident, quite possibly caused by a new medication I was trying out for my diabetes. The frightening part was not only that I spent a ton of time on the big porcelain telephone (“Hello? Yes, you're talking to your local waste water treating plant, what can I do for you?”) and everything that usually comes with that (loss of fluids, sore throat, feeling very weak) but that I a) lost a frightening amount of weight really quickly and b) this was the second time in two weeks that this has happened.

Okay, maybe time to cancel that new medication and try something else. It's the “something else” that initially frightened me more, which made me endure the severe side effects the drug has.

In any case, I'm sitting here, slowly transitioning back to normal food, still feeling quite weak but at least I feel now that my brain is almost back to 100%, and am having one of my more underwhelming birthdays. The “official party” with the family traditionally is moved to the next weekend, so it's not too bad, but it's not like I can go out and celebrate this with a nice lunch or so. Maybe I'll sneak in a treat later.

So. Much. Snow.

At least the weather is fitting. It's almost never snowing on my birthday. Except for, well, today, and my actual birthday in 1976. During that time period, Germany had a couple of pretty nasty winters culminating in the snow chaos of 1978/1979. Surprisingly, I don't remember much.

Given that I live in a part of the world that has seen some of the higher temperature changes over the last decade (Sitting well over 2K by now), this is a surprisingly cold winter. Don't get me wrong, I understand the mechanisms, this is not a “how can climate change be real if the winters are so cold” post, but somehow it does come unexpected. I bought some tires for my non electrified bike with studs and already made good use of them. My biggest takeaway of this harsh weather is that (in similar ways that COVID did) it gives you an insight into how society has subtly changed since I was little.

The authorities tasked with removing snow are all severely understaffed (Don't forget we're in still in the thick of a full infection wave of every viral respiratory disease thinkable, including COVID, of course), under-equipped and probably under-maintained because of, you know, budget cuts that happened and still happen everywhere. Bike lanes, even those that are supposed to be priority cleared by official statement of our “Stadtreinigung” are basically unusable since the fall when all leaves started to accumulate there and turned into a slippery mush. Which now has ice on top with snow falling on it.

Private property owners to a large extent ignore their obligation to clear or secure the pavements in front of their houses because a) that costs money and b) well, fuck you. And guess what happened to the authorities that are supposed to fine those property owners: Severely understaffed.

Ah, that elephant, yes

Almost worse than these symptoms to me is that nobody seems to be able to address this in a way that points out the underlying issues. The Stadtreinigung simply says: “We're doing all we can” and they are probably right, but they can't even bring themselves to say “We're doing all we can with the reduced amount of staff and budget we have to work with since so and so. We know that we are supposed to do better”.

Long articles in online newspapers about the horrible weather conditions (At least I think the flooding situation somewhat relaxed? I have no idea.), but not a single word about the root causes of all of these issues. You know, climate change, that stupid budget limit etc.

Of course this is all discussed at length in my Mastodon bubble and when privately talking to friends and family, but the places where the public discourse picks up these threads with the exception of explicitly left wing publications is ... underwhelming.

By the way, this might be the correct time to inform you that if you think this post is going anywhere, well, you'll be disappointed.

A new hope

The glimpse of hope this and last week was the amount of people that took it to the street after that Correctiv article about a secret meeting of several Nazi types of several parties present in the German parliament to discuss plans for deporting a ton of people when in power. If my strength permits, I'll try to be on the streets in Hamburg on Friday.

The way the established political parties, including the greens (and even to some extent the leftist “Die Linke”, although that might change with Sarah Wagenknechts departure) so far dealt with the onslaught of the “Alternative für Deutschland” with their (probably largely Russian funded) misinformation campaigns is quite frankly mind-boggling. My faint hope is that a sustained effort in protesting against this at least pulls some of the parties out of this rut. But I guess one of the main issues is that the media actually likes the polarisation because it drives engagement. Oh, I guess we're back at the capitalism-is-actually-bad-if-not-properly-regulated thing?

Yeah, I know I sound pretty miserable even in a paragraph that started promising.

Okay, enough is enough

Oh, guess what, looks like my heating system has a defect. Luckily, a plumber will be on site tomorrow anyway, so at least it will be looked at. That's something, I guess.

In good news I had a kardamombulle today, and any day you have a kardamombulle can't really be a bad day. Pavements were slippery in places but not catastrophically so. I made it back up to my third story flat without a break, but with very slow steps. But I take that as a win anyway.

Here comes the usual but necessary disclaimer that I am aware of my incredible privilege to have these kind of problems which are, for the most part, not life threatening and, for the most part, solvable. And while this is true, neither basking in that privilege does make me feel better personally, nor am I, at least right now, in a position of such strength that I can just pull through and carry on as usual, “because other people have it worse, you dip-shit”. Damn I am built close to water today, wonder why.

And yeah, it's hexadecimal. I'm getting old.

So, I had this idea for a piece of software that would listen to the MIDI output of the Woovebox and instead of just displaying the surface of the Woovebox verbatim as Woovebox Connect does, it would display additional help information for the screen and parameter you're on. The Woovebox display doesn't always do the best job to show where you're at.

The Woovebox micro music workstation sitting on a nondescript table

For this I wanted to see what kind of information the Woovebox actually sends.

To figure this out, I could do two things: I could try to look at the source code (Woovebox Connect is a web application, after all) or I could just try to analyse the MIDI messages. Unfortunately, the code is (probably) written in a language other than JavaScript for the most part and then compiled to JavaScript and a Webassembly module using Emscripten. This could be disassembled but I would rather not try that as the first approach.

Instead, I connected the Woovebox via my CMI Bluetooth MIDI interface interface to my computer and started a MIDI monitor and watched what was coming in.

First things first: When the device is at idle (Say in the Song mode, not playing), the device sends three message every few seconds

(I'll show the received bytes in hex here once and then a more descriptive form I will use exclusively after this)

0xB0 0x09 0x03 (CC:9 on Ch1, Value 3)
0xB0 0x09 0x04 (CC:9 on Ch1, Value 4)
0xB1 0x09 0x23 (CC:9 on Ch2, Value 35)

The 3 and 4 seem to be part of an actual heartbeat scheme for Woovebox connect, as the device sends the 3 regularly even if not connected to Woovebox Connect. If connected, Woovebox Connect seems to answer with a 4, which then the Woovebox answers with both the 4 and the CC:9 on Channel 2.

The third message (CC:9 on Ch 2) changes in value and looking at the Woovebox Connect screen, it is reasonable to assume that this is the battery percentage.

Unsurprisingly, more interesting things happen when you interact with the device. I was hoping for some usable information on where in the page/menu structure the device is currently in, but the implementation seems to be very focused on getting the Woovebox Connect mirroring working (Fair enough!).

Let's start with the input. Every time you interact with either the encoder or any of the fake or real buttons, some control changes are sent.

For buttons (and this includes pressing the encoder in), there's always a CC:3 on Channel 1 for button down and a CC:3 on Channel 2 for button up. The value encodes the actual button pressed:

  • 3 is the encoder click
  • 4 is the play button
  • 5 is the write button
  • 6-21 are the 16 matrix buttons, starting at the top corner going row by row

The encoder sends either 1 or 2 on CC:3 on Channel 2 for a left or a right turn (One for each step of the encoder)

That's the input covered. The state of the display of the Woovebox is, when ever needed, dumped as a bunch of CCs as well, but this took me a while to figure out. The easier one to explain is how the device sends the status of the button LEDs. There are two messages, CC:14/15 (I'll explain THAT in a sec) on Channel 9 and 10, sending the state of the upper and lower 8 LEDs as a bitfield, the lowest bit addressing the last bit in the 8 LED block. Now, MIDI aficionados will have spotted a problem: Addressing 8 bits with a CC value is a bit of an issue, because MIDI value bytes are 7 bit only. Here's where the two different CC's come into play: CC14 will clear the 8th bit, CC15 will set it. So to switch all LEDs on, you would send: CC:15 on Channel 9 as 127 and CC:15 on Channel 10 as 127.

Now for the fun part: The state of the 7-segment display is dumped in a series of messages in similar fashion: CC:14/15 for Channels 1-8 (For the 8 digits). But what are the values? I first thought of maybe ASCII or something similar, but playing around with the values the Woovebox sent, this didn't make any sense. Then I realised that a 7-segment display (at least one that has dots next to the digit) is an 8-bit value as well. Looking up how the seven segments are usually addressed and staring at binary numbers for a while confirmed that this was indeed what I was looking for.

f b
e c

One interesting thing is that the Woovebox even sends every frame of the (slightly obnoxious) scrolling when paging.

Unfortunately, this seems to be all there is to it. I don't think I have seen messages that aren't covered by the above.

Just as a note, as someone who had to work with, or implement MIDI addressing schemes a couple of times, the whole thing feels a bit wild. There's not a lot of room to send other messages and it's not

So, how hard would it be to build that thing I want to build? Well, for one, harder than I thought, but I think there's a chance. Here's what I'm thinking:

  1. Have a representation of the display in memory and update it according to the MIDI messages that come in
  2. Match the display contents to a list of known content variations that we know represent the pages. This could be either done by matching arrays or, more efficiently, turn the 8 bytes into one big number.
  3. Show the help for that page

There are issues with this approach. For example, holding a parameter button for a longer period of time (because you want to read the help) will first switch to the long parameter name (We could also match) but then switches back to the page header and only if you modify the value, it will switch back to the parameter screen.

This can probably be overcome by some clever selection on what screens contents to act on and which ones to ignore (and probably also listen to the button up so as to when to actually switch back to the overview help.

I will see if I can find some time soon to hack together a prototype.

I am not a keyboard geek by any means. I got into mechanical keyboards after I switched back from Mac to Windows as my daily driver and I didn't find any compact keyboards that were satisfactory. The usual Logitech offerings felt oddd and while I still use a K380 occasionally on the road because it is so compact and fits into the bag with the roost laptop stand, it is not a great keyboard in comparison to the ridiculously expensive but very, very nice Magic Keyboard from Apple.

So I looked for keyboards that would take a little less space on my desk than a standard size PC keyboard (with numpad and all) and ended up with a Ducky mechanical keyboard (brown switches) in the TKL (Ten-Key-Less. Yeah. Great name) form factor.

I was (and still am) quite happy with this keyboard, but then I learned about Keychron and their low profile keyboards. As soon as an ISO version of that became available, I bought the K3. This is an interesting one. I initially bought it with red switches and those are wayyyy too sensitive for me. Also, the compact layout somehow made typing really error prone for me. I later switched out the switches for low profile browns but as much as I like that keyboard visually, I never really managed to get used to it without still hitting the occasional wrong key. At the same time as I got the replacement switches, I got me a K2, which is basically the non-low-profile version of the K3 (also with brown switches). Typing on it is much better, so I assume it's something about the low profile keys of the K3 that makes it weird for me.

I was more or less happy with the Ducky and the K2 sitting at my two computer stations (at home and in the office).

And then Keychron started to put out their QMK series of keyboards (QMK being an open source for mechanical keyboards which has some really nice features and allows for full customisation with open tools) and I was suddenly thinking about getting yet another keyboard.

What needs to be said here is that the V-Series from Keychron has an almost insane value-for-money factor. Both V-Series keyboards I got since they came out (I now own a V1 and a V3) are below 100 money units. They have a plastic housing but weigh a ton, have the best keyboard feeling I have ever felt on a keyboard (much better than both the Ducky and the K2), the keyboard has a knob with an integrated button that makes adjusting the system volume and quick muting a breeze, and they are basically the cheaper variants of the Q series that has full metal housings and are available in more options for switches and colors of the housing and the keycaps. The designs are nice, but I am happy with the subdued blue tints with the orange esc key.

I got the V3 first, which is a TKL layout keyboard and then most recently I got the V1, which has a slightly roomier 60% layout than the K2, with the cursor keys slightly outdented and the row with the knob and the pgup/pgdown/home keys also slightly shifted away from the main keys, which probably makes this even a bit more reliable for me than the K2.

This is not a sponsored post, I just really fell in love with these two keyboards – They are amazing out of the box and I am perfectly content with how they are right now (That being said, I may, if they ever become available again, be tempted to get some more interestingly colored keycaps). I don't think I will ever go down that rabbit hole of lubing and shimming and what not and I don't think I would particularly enjoy that anyway (Soooo many keys on a keyboard, no, thank you)

This summer is definitely peak cognitive dissonance. In every corner of the world we have some form of environmental disaster, be it massive flooding, heat waves or burning forests. At the same time, air traffic is at an all time high with record numbers that beat 2019 before the pandemic.

So yeah.

One argument that is always heard when people say that every mode of transportation fueled by fossil fuels needs to have a proper price that prices in the environmental cost is “but what about all the people that will suddenly no longer be able to afford air travel then”.

I recently thought about this a bit more and here's my (probably somewhat shallow) take on it:

If, as so many claim, the market is to regulate itself, then there are actually no alternatives to higher prices. If our goal is to get rid of air travel emissions (and there are many good reasons to do so), and we want to do this without outright banning certain forms of travel, then pricing is the only option. Yes, that will price a lot of people out of those modes of transportation. Yes, that isn't ideal.

But I think the argument that we need to keep the prices down to make/keep air travel affordable is a red herring. Air travel is still, even though while being massively subsidised all over the world, very unaffordable for large parts of the earths population. It's just in rich western countries and some recent emerging countries that air travel became generally affordable for a majority of people.

At the same time what this argument is not addressing is that we're dealing with an increase in inequality in many parts of the world, making the problem worse.

And here lies the crux of the issue, I think. Billionaires and Millionaires will never be priced out of the market for air travel, be it long distance or short distance – which probably means that this field of the market needs some hard regulation that, for example, drastically reduces the amount of private jet travel (Very needed, but also very unlikely to happen anytime soon, I'm afraid). For everyone else, the goal cannot be to keep air travel as cheap as possible so that everyone can fly as much as possible, because regardless of how we do it, we must reduce air travel as much as we can. Trying to reduce inequality as much as possible, both on a global level but also within societies seems like a much better way of giving everyone an equal opportunity, not just for that one trip to the far east you've been dreaming about your whole life (it me!) but for life in general.

And yes, I know that this is not how capitalism likes to run things. I know.

As I wrote in my last post one of the things I wanted to try with the Agon was to build a MIDI interface for it and write some software to use it.

I started with a tiny prototype where I would simply connect the Agon Light's serial lines to an FTDI usb adapter so that I could open up a terminal on my desktop computer to see if I could get serial comms to work at all.

It was a bit of a steep learning curve but looking at a lot of other people's examples, I finally got it to work.

Frames shifting and other issues

Kind of. A bunch of weird things happened all at once and it made debugging really hard. At low baud rates (And low in that case meant MIDI speed and downwards), for the most part only the first byte would transfer correctly, everything after that would be mangled. I only later noticed that my terminal (RealTerm is a really great open source program for debugging serial connections) complained about so-called “frame errors”.

Also, even at higher baud rates, where I didn't get these frame errors, the last byte of my transmission would always be cut short. And with that I mean, literally, electrically. The transmission would just stop after 3 bits.

The latter one was easy to diagnose: I simply closed down the serial port too quickly and the UART part of the eZ80 would just stop pushing out the bits. Took me a while but I got there eventually.

The frame errors were a bit more complicated. My hunch was that somehow, something with the baud rate generation went wrong at lower baud rates. Didn't make a ton of sense to me but if you know how serial comms ala RS232 work, you know that one of the few things that can really throw it of is frequency drift.

This type of serial communications works with a single line (plus a ground connection for good measure). There is no additional clock signal. Instead both sender and receiver rely on somewhat stable timing of the signal. (Ben Eater, as usual, does a pretty good job of explaining this in one of his videos).

I didn't have any good tools to diagnose the signals. My analog oscilloscope would probably have trouble properly putting the bits on the screen to measure the timing and the only other alternative I had was my tiny DSO scope, where I was also struggling to get good measurements.

Proper measurements

So I finally caved in and ordered one of these relatively cheap USB scopes, in my case the Hantek 6022BL. People hate these scopes for their shoddy quality but I'd argue that for the kind of stuff I usually do they are actually quite sufficient. The BL variant additionally has a logic analyser (16 channels) built in that luckily works with a chipset that is compatible with the Saleae logic analyser software, which is one of the better tools and one of the things you can do with Logic is automatically decode serial comms. I tried this with my code and Logic complained about frame errors as well. In Logic I was now able to measure the length of individual bits. If you do the math, at 9600 baud (Which I was testing with), each “bit” should take roughly 104 microseconds. “My” bits were consistently around 112 microseconds, so somewhere around 8% off.

So I asked on the AgonLight group if someone could explain this. At the same time, I dug into the source for the AgonLight firmware, called agon-mos to see how the calculation works and if I can find something there.

You see, with a microcontroller like the eZ80, which has two UARTS on board, you cannot simply say to the chip, hey, use 9600 baud. Instead, you have to calculate the ratio between the baud rate you need, the frequency the microcontroller is driven with and a factor of 16.

And there I saw something. The header file defining the constants used in that calculation had the processor clock defined as 20 MHz. But the oscillator that generates the clock runs at 18.4320 Hz. (A very interesting number, as we will see in a sec). If you do the math, the difference between these two numbers is, oddly enough, roughly 8%. Could it be?

I did some quick maths and tried to adjust in my requested baud rate for that specific error and got it to work reliably. So I made a comment to that effect on the group – Dean Belfield, the author of agon-mos was a bit dismissive at first, and rightly so, as we'll see, but later he confirmed that indeed, this was a mistake and he would fix it for the next version.

The fun of integer maths

Now, there's some interesting questions to be asked: The AgonLight heavily relies on UART usage. The ESP32 which acts as Agon Lights main I/O processor talks to the eZ80 via UART0. So why wasn't this noticed earlier? Shouldn't the error be present there as well?

Here we need to get into the details of the calculation I mentioned above: At the end of that calculation you end up with a number you'll write into a register on the processor. The higher your baud rate, the lower that number will be. And it will always be rounded to an integer number, of course. And, of course, agon-mos is trying to communicate with the ESP32 as quickly as possible which means that given the baud rates and the CPU frequency, that number will be either 1 or 3 (depending on how well that link works) and it really doesn't matter if you start with 20 MHz or 18.4320 MHz. Here's where that 18.4320 number has some interesting properties: It makes it so that all commonly used baud rates result in a non fractional number for this calculation. (This unfortunately isn't true for MIDIs odd baud rate, but I think we can make it work with the tiny error we'll get).

So, for very large baud rates, the error introduced by using 20 MHz is either non existing or neglegible and it was easy to overlook. I guess I was just the first one to try out lower baud rates.


I now have a test build in my hands and will do some additional testing to see if the baud rate error I'm getting for the MIDI baud rate has any real life effects. I hope it is not the case and I can continue with the project. The next steps are going to be both in hardware and software: I want to try to write a piece of assembler that will receive MIDI. for that I'll need to build a receiver circuit as well, which is a bit more involved than the sending circuit.

And then the next step would be to build a first version of the MIDI circuit on perfboard, after which I will hopefully be able to turn it into a real circuit board design. I will try to document by code and hardware design on this github project

I watch a lot of Youtube videos about retro computing. I am not a huge retro computing person myself, after all, I gave away all of my old computers to a friend when I last moved (they were just taking up shelf space in our basement), but I am a fan.

Every now and then, when watching these videos, you come across some new “old” computer projects, like the Retrogames TheC64 (which is, unfortunately, essentially just an emulator running on an SBC like thing), the ZX Spectrum Next and then completely new designs like the Commander X16. If you look deeper, there are a ton of these projects, but a lot of them have really small communities or are just someone's pet project. This seems to now radically change for one particularly interesting platform: The Agon Light, designed by Bernado Kastrup aka TheByteAttic, Dean Belfield and Jeroen Venema. One of the reason their community is currently exploding is because Olimex, the Bulgarian electronics powerhouse, decided to build a cost optimised version of it you can buy for 50 EUR.

Introducing the Agon Light

A photo showing the Agon Light 2 board inside the Olimex metal case with VGA, USB keyboard and USB power connected and two LEDs showing the status of the board

The Agon Light is a very interesting platform. It uses a modern derivate of the Z80 processor that runs at much faster speeds. But that's not even the most interesting thing about it. Because it runs an ESP32 (yes, that big brother of the ubiquitous ESP8266 internet-of-shit microcontroller) sans the antenna (So no built in Wifi, unfortunately) as the universal I/O controller, sort of. The ESP32 runs a software called VDP (Video Data Processor) that is based on an almost magical open source project called FabGL that, among other things, implements a full graphics processor capable of running VGA output. It also does sound and is responsible for keyboard input as well.

In other words, the ESP32 is AgonLight's VIC/SID/CIA (you can probably tell I grew up with a C64 as my main machine?) and the cool thing about it is that it's all defined in software. Basically, a very cheap version of what most projects try to solve with FPGAs.

The Agon Light runs BBC Basic, a very good basic dialect, ported over from 6502 assembly to Z80 by R.T.Russell and adapted by Dean Belfield to the AgonLight.

Keyboard Error, press any key to continue...

The biggest issue with the AgonLight currently seems to be to find a compatible keyboard, it only supports PS/2 keyboards. Interestingly, the Olimex variant (which I have) comes with a USB port, so it only supports keyboards that have a USB plug but can fall back to PS/2 (which was a very helpful feature of USB keyboards back when they were uncommon).

The Agon Light software side is currently improving quickly. You can now flash the Z80 ROM in situ (no need for Zilog tooling anymore) and the ESP32 can be updated via the USB port (otherwise only needed to power the device) via the Arduino IDE.

People are working on getting various games to run on the machine. People have made the VDP work with CP/M as well which opens up a huge world of retro software.

And me? I have a couple of ideas, which I'll list here for future reference:


The Agon Light exposes (similarly to the RaspberryPI) GPIO pins through a pinheader. Among other things, this exposes the second UART of the eZ80 (the first one is used to communicate with the ESP32) which should be MIDIfiable with a fitting interface. I have already looked up how to build such an interface and ordered a couple of missing parts. On the software side, the second UART is already exposed via the system software (called MOS) and should be callable via BASIC, probably with a bit of inline assembler. All in all, this should be doable in 1-2 days.

After that it would be interesting to try to build something on top of that, like maybe a simple MIDI based tracker or so.


If I can, I would love to help with the software side of exposing more of the sound features of FabGL in the VDP so that it's accessible from the main processor. I assume that designing an interface that will allow expressiveness while not overloading the serial bus will be tricky, but it's worth a shot. There are people already working on that so'll try to chime in there if I can find the time and I think I have something to contribute.

A simple sprite editor

I would love to dip my toes back into BASIC to see if I can build a simple sprite editor. My idea would be to build something similar to the tooling Pico-8 has built in, sans mouse support, of course.


This looks like a fun retro computer. A throwback to simpler times. An interesting target for experiments. Let's see how it goes.

Okay, that's probably an exaggeration. I am neither in the Ukraine nor am I part of the Russian troops, so unless something goes extremely sideways within the next few weeks, I'm probably fine for now.

The reason for this drastic, probably a bit clickbaity headline is a serious one, though. The very thinly veiled threat of Putin to use his (to be fair, so far rather underutilised nuclear arsenal) did trigger some deeply ingrained fears in me. I grew up in the 80's (Born 1976) and as a rather astute (If I do say so myself) and curious young child, I unfortunately was a bit more influenced by the cold war antics of the day when a nuclear meltdown was essentially on the table on a day to day basis than you would think. So deeply ingrained were those fears, in fact, that my subconcious transported me directly into the centre of a nuclear explosion one morning in a dream when in fact, the only thing that happened was that some rather noisy construction work had started on the roof I was directly sleeping under. I was probably 14 or so and the risk of a sudden nuclear war was suddenly very low after the collapse of the soviet union and the german reuinfication. Still.

All goes to say, of course I am relatively safe here in Germany, all things considered, especially in contrast to my Ukrainian brothers and sisters but that doesn't mean that this doesn't trigger traumata in many of us born before the official end of the cold war.

The full on invasion of the Ukraine by Russia, a clear breach of international law and a couple of existing treaties, once again, changed everything.

Ah, ye olde militarism, can't say I missed ya

My country, Germany, usually obsessed with being as frugal as possible, suddenly found 100 Billion EUR to throw at our mismanaged and especially mis-consulted military. And our parliament, instead of bemoaning the necessities of war, gives itself standing ovations, as if every other member also sits on the board of directors of one of our countless weapons manufacturers (Actually, now that I think about that, that's probably closer to truth than I want to admit) or, worse, actually looks forward to finally show the world again that Germany is a strong country with a strong military.

Sorry, I had to puke and some of it got into my keyboard, it took a while to clean up.

The only silver lining seems to be that there seem to be some (finally) understanding that being completely dependent for energy sources (Coal, Oil, Gas) on a, shall we say slightly less democratic country like Russia is probably not a good idea and that renewables are actually a pretty clever idea to get rid of those dependencies.

Apart from that the new military budget, paired with the so called “debt brake” which disallows the state to increase the debt beyond certain limits makes for a rather bleak outlook in terms of investments into a more climate friendly future. Pretty sure all those new tanks and war planes we'll be getting will be hydrogen powered, right? Right?

Get to the fecken point, man!

After a lot of rambling, fuled by my very odd combination of a epidemic induced tiredness, excessive fear for our future (a nuclear winter might counteract global warming for some time, maybe?) and white hot rage, let's try to bring this to a point, because a point I wanted to make.

In the last couple of years, political commentators have often bemoaned the obvious lack of long term thinking in modern democratic politics. The (only recently ended) era of Chancellor Merkel was pretty much this very short term thinking and focus on reactive policing personified.

We have always said, that with the climate crisis, this short term thinking will fall on our feet at some point. Of course, this has already happened almost everywhere in the world, with Floods and Fires, Hurricanes, etc, but it is clear that a bit of global strategic, long term thinking could have prevented a lot of all of these terrible things.

To me, the Russian war on Ukraine and the limits of our space of possibilities to help Ukraine is also a result of that.

We could have made ourself less dependent on Russian energy sources a long time ago. Nord Stream 2, the gas pipeline now completed but probably doomed to never actually go into service (don't get me wrong, that's probably for the better, but what a waste of time and resources) is one of those examples where at every step someone should have said “No, this is not a great idea”.

Diamonds are an oligarchs best friend

Of course, the short term thinking was also paired with a healthy dose of greed (or should we just call it Capitalism?) as one could witness in the early talks about the sanctions against Russia where the dependencies on oligarch money became painfully clear – Milan wanted to be able to still sell overpriced bags, Antwerpen wanted to please be able to continue to sell Diamonds.

Do we need more lenses?

My friends and I often remarked during the pandemic how the coronavirus created a sort of lens through which faulting in our societies suddenly became visible (with the obviously terrible state of our health care work being the most drastic example).

It is both my hope and my fear that the next weeks shaped by this travesty of a war caused by a hurt ego of a very small man and his nationalist “thinkers” will create a lens that will inform our thinking and our actions for a very long time. Seeing the usually well buried but obviously not irradicated militarism awaken with such force in my home country does make me fear we might not only learn the correct lessons. It is our responsibility as citizens, as humans, to watch this closely and do everything we can to keep us from tumbling down the slippery slope that small man has so artfully created for us.

Glory to Ukraine!

All of that being said: A country led by a man who once played a piano with his penis on national television and who was the Ukrainian voice of Paddington Bear should be in a good position against any aggressor. And for once I am not even joking. Slava Ukraini!

Enter your email to subscribe to updates.