Clockwork

Z80 Disassembler

Some days ago, I was adding a Z80 disassembler to my tzxtools. I could not find one for Python, so I decided to write my own. The result fits into a single Python source file. This article is the Making-of…

The Zilog Z80 is an 8 bit processor. This means that (almost) all instructions only consume 1 byte. For example, the instruction ret (return from subroutine) has C9 as byte representation. Some commands are followed by another byte (as a constant to be used, or a relative jump displacement) or another two bytes (as a 16 bit constant or absolute address). Some examples:

C9------retReturn from subroutine
3E23----ld a,$23Load constant $23 into A register
C33412--jp $1234Jump to address $1234

Note that for 16 bit constants, the bytes seem to be reversed in memory. This is because the Z80 is a so-called little endian CPU, where the lower byte comes first. Some other processor families (like the 68000 ) are big endian and store the higher word first.

So there are 256 instructions only, which makes it pretty easy to disassemble them. I used an array of 256 entries, where each entry contains the instruction of the respective byte as a string. For constants, I have used placeholders like "##" or "$". If such a placeholder is found in the instruction string after decoding, the appropriate number of bytes are fetched, and the placeholder is replaced by the value that was found.

If we were to write a disassembler for the 8080 CPU, we were done now. However, the Z80 has some extensions that need to be covered, namely two extended instruction sets and two index registers.

One set of extended instructions is selected by an $ED prefix, and contains rarely used instructions. The other instruction set is selected by a $CB prefix and has bit manipulation and some rotation instructions.

EDB0----ldirCopy BC bytes from HL to DE
ED4B7856ld bc,($5678)Loads value from address $5678 into BC register pair
CBC7----set 0,aSet bit 0 in A register

For the $ED prefix, I used a separate array for decoding the instructions. The $CB instructions follow a simple bit scheme, so the instructions could be decoded by a few lines of Python code.

The Z80 provides two index registers, called IX and IY. They are used when the instruction is prefixed with a $DD or $FD byte, respectively. These prefixes basically use the selected index register instead of the HL register pair for the current instruction. However, if the (HL) addressing mode is used, an additional byte sized offset is provided. The index registers can be combined with the $CB prefix, which can make things complicated.

E5------push hlPush HL to stack
DDE5----push ixPush IX to stack (same opcode E5, but now with DD prefix)
FDE5----push iyPush IY to stack (now with FD prefix)
FD2180FFld iy,$FF80Load $FF80 constant into IY register
DD7E09--ld a,(ix+9)Load value at address IX+9 to A register (offset is after opcode)
CBC6----set 0,(hl)Set bit 0 at address in HL
FDCB03C6set 0,(iy+3)Set bit 0 at address IY+3 (offset is before opcode)

When the disassembler detects a $DD or $FD prefix, it sets a respective ix or iy flag. Later, when the instruction is decoded, every occurance of HL is replaced by either IX or IY. If (HL) was found, another byte is fetched from the byte stream and used as index offset for (IX+dd) or (IY+dd).

There is one exception. The examples above show that the index offset is always found at the third byte. This means that when the index register is combined with a $CB prefix, the actual instruction is located after the index. This is a case that needed special treatment in my disassembler. If this combination is detected, then the index offset is fetched and stored before the instruction is decoded.

Phew, this was complicated. Now we’re able to disassemble the official instruction set of the Z80 CPU. But we’re not done yet. There are a number of undocumented instructions. The manufacturer Zilog never documented them, they are not quite useful, but they still work on almost any Z80 CPU and are actually in use.

Most of them are covered just by extending the instruction arrays. Additionally, the $DD or $FD prefixes do not only affect the HL register pair, but also just the H and L registers, giving IXH/IYH and IXL/IYL registers. This is covered by the instruction post processing. A very special case is the $CB prefix in combination with index registers, giving a whole bunch of new instructions that store the result of a bit operation in another register. This actually needed special treatment by a separate $CB prefix instruction decoder.

Finally, the ZX Spectrum Next is going to bring some new instructions like multiplication or ZX Spectrum hardware related stuff. They were again covered by extending the instruction arrays. The only exceptions are the push [const] instruction where the constant is stored as big endian, and the nextreg [reg],[val] instruction that is (as the only instruction) followed by two constants.

And that’s it. 😄 This is how to write a Z80 disassembler in a single afternoon.

Shredzone à la Amiga

Look what I have found... This is my very first shredzone, as it was online from 1998 to 2003. First it was hosted by my internet provider. Then, on April 15th 2000, I registered my own domain – shredzone.de – and moved my site to a professional hoster.

The site did not use a fancy content mangagement system, but consisted only of static HTML pages. It was built on my Amiga using a preprocessor called HSC, an acronym for HTML Sucks Completely. 😜 Some parts like the gallery or the download area were generated by accompanying ARexx scripts. It was incredibly easy to add content to the site. Basically it was just adding or changing a file, and then invoking smake to rebuild the affected parts of the site within seconds, including the navigation. It was a big advantage that I was going to miss badly later.

At that time I did not use CVS yet, so sadly all the past versions and changes have been lost. The only version I still have is the final one on my Amiga harddisk. I have found the project today, by a rather lucky accident. It was only the source code though, the final compiled version has got lost over the years. There is a Linux port of HSC, so basically I could rebuild the site on my Linux machine. But the ARexx parts require an Amiga environment, and porting them to Linux would have consumed too much time.

So I started an Amiga emulator and, thanks to the good shape of the project that the past Amiga me has left the present Linux me, I actually only needed to run smake to rebuild the entire homepage in just 3 minutes.

The requirement to run on an Amiga, was what later broke the neck of this homepage. When the Amiga platform died, I moved on to Linux, but I could not move my homepage with me. So, in 2003, I replaced it with a self-made content management system that was written in PHP and was called Akiko. It had some nice features, but on the other hand it was rather tedious to add new content. Because of that, I badly neglected my homepage in those years.

In 2010, Akiko was replaced by a self-made blog system that is written in Java and is named Cilla. Even after a major redesign in 2018, it is still in use today. 🙂

Circuit Playground Halloween Ghost

Just in time for Halloween 🎃, I made a ghost decoration that uses an Adafruit Circuit Playground Express.

The ceramic ghost is from a home decoration shop. I have put a little sandwich paper inside, so the LED light can be seen.

The MicroPython source shows a candle light effect. For the flame, a mystic cyan color is used, so the ghost appears really spooky. 👻

If you copy .wav files to the Circuit Playground, a random sound effect is played from time to time. I found nice free sound effects on soundbible.com that surely give everyone the chills. The sound files should be converted to mono and 16 kHz sampling rate, so they fit into the tiny Playground Express memory. The sound effects can be muted using the switch on the Playground, if they should become too annoying. 😉

Read this article...
How acme4j handles POST-as-GET requests

In the latest ACME draft 15, Let's Encrypt introduced POST-as-GET requests. It is a breaking change that is not downward compatible to previous drafts.

This brought me into an uncomfortable position. While the Pebble server enforces the use of POST-as-GET, other servers don't support it yet, like the Let's Encrypt server. For this reason, acme4j needs to support both the pre-draft-15 GET requests and the post-draft-15 POST-as-GET requests. Luckily I have found a solution that is totally transparent to the user, at least as long as no other ACME server is used.

This is how acme4j v2.4 works:

  • If you connect to Boulder via an acme://letsencrypt.org URI, acme4j falls back to a compatibility mode that still sends GET requests. Let's Encrypt has announced a sunset date for GET requests on November 1st, 2019. You are safe to use acme4j v2.4 (and older versions) up to this date.
  • If you connect to a Pebble server via an acme://pebble URI, the new POST-as-GET requests are used.
  • If you connect to a different server implementation via http: or https: URI, acme4j sends POST-as-GET requests now. This is likely going to fail at runtime, if the server you connect to does not support draft-15 yet.
  • As a temporary workaround, you can add a postasget=false parameter to the server URI (e.g. https://localhost:14000/dir?postasget=false) to make acme4j enter the fallback mode and send GET requests again.

As soon as Let's Encrypt supports POST-as-GET on their production servers, I will remove the fallback mode from acme4j again. It just clutters the code, and I also have no proper way to test it after that.

Hint: Before updating acme4j, always have a look at the migration guide. It will show you where you can expect compatibility issues.

Google Earth Pro auf Fedora installieren

In dem Fedorablog, den ich ganz früher mal geschrieben hatte, hatte ich ein regelmäßig wiederkehrendes Thema: Die Installation von Google Earth. Lange Zeit war das echte Handarbeit, obwohl Google ein RPM-Paket bereitstellte.

Seitdem sind viele Jahre vergangen. Mittlerweile stellt Google die ehemals kostenpflichtige Pro-Version von Google Earth zum kostenlosen Download für Linux zur Verfügung. Und auch die Installation ist glücklicherweise kein Problem mehr. Es reicht schon, das RPM-Paket zu installieren:

sudo dnf install google-earth-pro-stable-current.x86_64.rpm

Auf deutschen und österreichischen Systemen¹ muss anschließend noch eine kleine manuelle Änderung vorgenommen werden. Der Grund dafür ist, dass die Google-Server bei der Ortssuche Geokoordinaten mit Dezimalpunkt ausliefern, das System aber das bei uns übliche Dezimalkomma erwartet und die Zahlen deshalb nicht verarbeiten kann. Die virtuelle Erdkugel dreht sich dann immer mitten auf den Atlantik statt auf die gewünschte Markierung.

Eine einfache Lösung ist, die Datei /opt/google/earth/pro/googleearth mit einem Texteditor zu bearbeiten (Root-Rechte erforderlich) und in der letzten Zeile der Datei ein LC_NUMERIC=us_US.UTF-8 einzufügen:

LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH LC_NUMERIC=us_US.UTF-8 ./googleearth-bin "$@"

Danach sollte Google Earth Pro problemlos und stabil laufen.


¹) Nach meinen Recherchen verwendet ein Linux mit schweizerdeutscher Einstellung den Dezimalpunkt. Die Anpassung ist dann nicht nötig, schadet aber auch nicht.