Freshwater Crocodile

Multiplication on a Z80 processor

The one thing computers are really good at is calculating. You might now expect that all CPUs are capable of the four basic arithmetic operations, but that isn't the case. The first 8 bit processors were only able to add and subtract numbers, and even the subtraction was performed by adding the negated subtrahend. Multiplication and division instructions first appeared on 16 bit processors, albeit they were still very slow in the first generation.

Simple multiplications and divisions with powers of two can be achieved by shifting a value bitwise to the left or right, respectively. This is, shifting a value by one bit to the left is the same as multiplying it by 2, while shifting by two bits to the left multiplies it by 4, and so on.

But how can we multiply any two numbers? It has to be done step by step, by using basic operations like addition or bit rotation. This article will explain how it works on a Z80 CPU.

Back at school, we have learned to multiply large numbers by long multiplication. Basically, we break up the problem by multiplying the multiplier with each digit of the multiplicand, and then summing the products. For example, if we want to compute the product of 27 and 12, we compute 27×2 = 54 and 27×1 = 27, and then sum the products 57+270 = 324.

  27 × 12
———————————
       54
 +    27∙
———————————
      324

We can use the same algorithm on a computer. But wait, wouldn't we still have to multiply, even if with smaller numbers? Actually, no! Since computers use binary digits, we only need to multiply either by 1, giving the value itself, or by 0, always giving 0.

This is the the same long multiplication of 27 (11011) and 12 (1100) with binary numbers:

  11011 × 1100
————————————————
         00000
        00000∙
       11011∙∙
 +    11011∙∙∙
————————————————
     101000100

The steps can be executed in a loop. At the beginning, a result register is initialized with zero. If the rightmost bit of the multiplicand is 1, the multiplier is added to the result register. After that, the multiplicand is rotated to the right by one bit, and the multiplier is rotated to the left by one bit. This loop is repeated until the multiplicand is zero, because the result won't change after that anymore.

The following Z80 assembler code example multiplies the values in the BC and DE register pairs, and returns the product in the HL register pair. If an overflow occured during multiplication, the Carry flag will be set.

The multiplicant is kept in the BC register pair. To rotate it one bit to the right, we first use the srl b instruction. It rotates the B register, moving the value of bit 0 to the Carry flag, and inserting a 0 to bit 7, so the multiplicant is filled up with zeros with each rotation. After that, rr c rotates the C register and moves the content of the Carry flag to bit 7. Both instructions combined rotate the BC register pair one bit to the right, insert a 0 to the highest bit. The lowest bit is moved to the Carry flag, where it can be tested.

image/svg+xml0010010110011010Carry0BCCarrysrl brr c7654321076543210

We essentially do the same with the multiplier in the DE register pair, but in the opposite direction. As a rotation to the left by one bit essentially just doubles the value, we also could have used add de, de. Sadly the Z80 does not offer such an instruction.

multiply:	ld	hl, 0		; clear the result register
.loop:		ld	a, b		; is BC == 0?
		or	c		;   (also resets carry flag)
		ret     z		; then we're done!
		srl	b		; logical right shift of BC
		rr	c		; bit 0 goes to carry flag
		jr	nc, .zerobit	; unless bit 0 was 0
		add	hl, de		; add multiplier to result
		ret	c		;   return on overflow
.zerobit:	sla	e		; shift multiplier to the left
		rl	d		;   topmost bit goes to carry flag
		ret	c		;   return on overflow
		jr	.loop		; next iteration

The example only multiplies positive integers. To multiply negative integers, we first need to change all factors to positive numbers and do the multiplication. The result then needs to be negated if one of the factors was negative, but not both.

Reading Amiga Harddisks with Linux

While cleaning up the cellar, I found my Amiga 500 and also a GVP Impact Series II SCSI host adapter. Inside, there was a Fujitsu M2611SA harddisk. After about 25 years, I had totally forgotten about it, and I wondered what was stored on it. So let me take you on the adventure trip of how to salvage old Amiga harddisks on modern Linux machines.

The Amiga ecosystem has always been very SCSI friendly. Commodore broke this tradition only with the final AGA models, where they switched to the IDE bus to reduce costs. The Amiga community never approved this change, and many accelerator cards that were sold for these machines also came with a SCSI host adapter. The SCSI bus was a lot faster than the IDE bus. Also a single ribbon cable could connect up to seven SCSI devices, where the IDE bus only permitted two devices.

Today this SCSI affinity turns out to be a problem though. SCSI was never a topic on consumer PCs, so there are no SCSI-to-USB adapters on the market (I wish they were), and SCSI cards for the PCIe bus are very expensive. I'm still having an Adaptec SCSI card in my cupboard that I bought many years ago, but it is for the old-style PCI bus. Luckily there are PCI-to-PCIe adapters available on the market, so I could reuse this old card in my computer. The card stack looks adventurous, but it will do for a few hours of operation to backup the data.

The big question is: Can a modern Linux machine even read Amiga formatted harddisks?

Mounting Amiga Harddisks

Yes, it can. It seems that there are a lot of Amiga fans among the Linux kernel developers. The Amiga uses a different partition table scheme than PCs, but if you're lucky, your Linux will still detect the Amiga partitions and offer them as e.g. /dev/sdg1. Then all you need to do is to mount the partition via mount.

It didn't work on Fedora though, so I had to do some more typing. First I had to find out the offsets of the individual partitions. GNU Parted can be used for that, as it is able to decode Amiga partition tables:

# parted /dev/sdg
GNU Parted 3.3
Using /dev/sdg
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) u
Unit?  [compact]? b
(parted) p
Model: FUJITSU M2611S (scsi)
Disk /dev/sdg: 45078528B
Sector size (logical/physical): 512B/512B
Partition Table: amiga
Disk Flags:

Number  Start   End        Size       File system  Name  Flags
 1      52224B  45078015B  45025792B  affs1        DH0   boot

(parted) q

So there is only one partition on the HD. It starts at offset 52224 and is Amiga FFS formatted. Luckily most Linux distributions are able to mount this file system out of the box. The start offset is needed to mount the partition. I also mount it read-only to make sure that I won't accidentally change or delete my precious old data.

mount -o ro,offset=52224 -t affs /dev/sdg /mnt/

Et voilà:

# ll /mnt/
drwx------. 1 root root    0 Apr 16  1997 C
drwx------. 1 root root    0 Jun 11  1994 Devs
-rw-------. 1 root root 1233 Apr 16  1997 Devs.info
drwx------. 1 root root    0 Apr 16  1997 Fonts
drwx------. 1 root root    0 Apr 16  1997 L
drwx------. 1 root root    0 Apr 16  1997 Libs
drwx------. 1 root root    0 Feb 27  1992 Locale
drwx------. 1 root root    0 Apr 16  1997 Prefs
-rw-------. 1 root root 1238 Apr 16  1997 Prefs.info
drwx------. 1 root root    0 Apr 16  1997 S
drwx------. 1 root root    0 Apr 16  1997 Storage
-rw-------. 1 root root 1233 Apr 16  1997 Storage.info
drwx------. 1 root root    0 Jan  4  1992 System
-rw-------. 1 root root 1233 Apr 16  1997 System.info
drwx------. 1 root root    0 Feb 27  1992 Tools
-rw-------. 1 root root 1233 Apr 16  1997 Tools.info
drwx------. 1 root root    0 Jan  4  1992 Trashcan
-rw-------. 1 root root 1588 Apr 16  1997 Trashcan.info
drwx------. 1 root root    0 Feb  3  1992 Utilities
-rw-------. 1 root root 1233 Apr 16  1997 Utilities.info
drwx------. 1 root root    0 Apr 16  1997 WBStartup
-rw-------. 1 root root 1233 Apr 16  1997 WBStartup.info

Disk Dumps

As old harddisks are quite noisy, it might be a good idea to dump the entire content first, and salvage the partitions later. dd is the classic tool for creating a dump:

dd if=/dev/sdg of=amiga-hd.dd bs=512 status=progress

Later a loop device will simulate a real harddisk device:

losetup /dev/loop1 amiga-hd.dd

/dev/loop1 can now be used for parted and for mount.

To remove the loop device again:

losetup -d /dev/loop1

Smart File System

Back in the Amiga days, the Smart File System was very popular as an alternative to the original Fast File System. It was freeware, it was a lot faster than FFS, and it even had a stateless defragmentation that ran in the background.

The Linux kernel does not support SFS out of the box. However, Marek Szyprowski implemented a kernel module in 2003, which (sadly) never left the experimental stage and thus never found its way into the official set of supported Linux file systems.

To use it, you first need to set up a Linux with a 2.6.27 kernel, for example Fedora 10. After that, download the kernel patch and compile it to a kernel module. If you managed that, you can also mount Amiga SFS partitions. I was able to recover all files from an SFS partition that way, though it wasn't much fun.

PS: Sadly the harddisk I've found didn't contain forgotten source codes or other secrets. It just had a standard Amiga Workbench on it, and a copy of the game Scorched Tanks.

Read this article...
#Advertisement? This blog is free of ads. All shown products have been paid by myself.
Saturday, January 16, 2021
Restauring an old iRiver iHP-120, Part 2

In the first part, we have replaced the old Li-Po battery by a new one. In this part, we will replace the mechanical hard disk by a modern (and much larger) MicroSD card. Both parts are independent, this is, you could also replace the HDD but keep the old battery.

First of all, you need to install Rockbox on your player. This is an alternate firmware that will not only make your iRiver experience more enjoyable, but will also support larger hard disk sizes. The installation procedure is out of scope of this article, but Rockbox is providing a great installer tool that does most of the work for you.

You must install Rockbox before replacing the harddisk. The reason is that the original iRiver firmware won't boot from larger harddisks, but you need a running player to install a patched Rockbox bootloader via firmware update.

Your shopping list:

  • Toshiba 50-pin to CF card adapter – I use an HXSP-09CF69 adapter. I have tried an Adaptare 48012 adapater first, but always got ATA errors with that one. The adapter must be set to "Master" mode, usually by a switch or a jumper.
  • CF card to MicroSD card adapter – I use a DeLock adapter, but any other brand should work as well. You can also just use a CF memory card, but the combination of MicroSD cards and CF card adapaters is cheaper than CF cards of equal size.
  • MicroSD card – I use a 128 GB SanDisk Ultra MicroSDXC card, but any other brand should work as well. The card speed is not really a factor here. I couldn't find a maximum size that is supported by Rockbox, so maybe even larger cards will work.

As there are a lot of different adapters and MicroSD cards on the market, there is no guarantee that your combination will work. Remember that you use parts that have been totally utopian back in 2003. Also be warned that your hardware can be damaged by this modification. You do it at your own risk.

Before you move on, make sure that Rockbox is properly installed and started. Then connect your player to your computer via USB, and backup the .rockbox directory, and any other stuff on the old harddisk that you want to keep.

Also, please read the entire article first, before you start with the modification.

Prepare the MicroSD card on your PC. It must be FAT32 formatted and should be named like your player model (e.g. IHP-120). Copy the .rockbox directory from your backup to the MicroSD card. And while you're at it, use the chance and copy your music collection to the card. The access speed will be much slower once the card is in your player.

Now turn off your player, and open it again (as described in part 1). You only need to remove the back cover this time. No more disassembling is necessary.

Remove the harddisk by gently lifting it and pulling it out of the connector. Now try to insert the 50-pin adapter. For many adapters, a plastic nose on the connector will keep you from inserting it, so you may need to remove protruding parts of the adapter with a file.

It is normal that the connector has more holes than the header has pins. Just make sure that the position marked as "PIN 1" is properly aligned with the first pin of the header. This is what it looks like when the adapter and the CF card is correctly mounted.

The next step is important. The adapter might have a jumper for mode selection. If it sticks out, it may punctuate the battery when the casing is closed later, so bend it away (like in the photo) or just unsolder it and replace it with a wire bridge.

Now make sure that the CF card stays in place and won't touch the PCB even when the player is carried around. You can use some isolating tape, or a silicone mat cut to size. I constructed a small 3D printed piece that fills the space and keeps the CF card from loosening. You can put back the original silicone HDD frame on top of that, to keep the construction from vibrating or touching the battery.

It is a good idea to do a short test drive of your modified player now. It should boot up and start Rockbox. In the Rockbox file manager, you should see all the files on your MicroSD card.

You can close your player now. Be careful and don't use force if the back cover cannot be closed, but locate and remove the obstacle. Remember that the Li-Po battery on the back cover must not be damaged or punctuated.

Enjoy your new retro mp3 player!

Troubleshooting

If you should get ATA or "check HDD" errors, it can have a lot of different causes:

  • Make sure that your MicroSD card has a single primary partition, which must be FAT32 formatted. Other file systems (e.g. FAT16, NTFS) are not supported. Try a different formatter tool.
  • Check all the connections. Is the adapter properly aligned and connected to the header? Is it switched to "Master" mode? Is a header pin bent or broken? (A few pins may be a bit longer or shorter than the other pins though, that's normal.)
  • Remove the adapter and insert the original HDD. If your player still shows an error, the daugherboard may have been dislocated. Gently press it to the main board and try again.
  • Your combination of adapters and MicroSD card brands may be incompatible. Try to boot from a real CF memory card. Try other adapter or MicroSD card brands.

If you happen to have an iHP with a broken original hard disk, you can start with the replacement right away, but use a FAT32 formatted 16 GB or 32 GB MicroSD card first. The original firmware should start in this configuration, and allow you to install the Rockbox firmware, but this is untested. After the Rockbox firmware has been installed, you can use larger MicroSD cards.

Final words…

  • You do this modification at your own risk. It might not work, damage your hardware, and turn out to be an utter waste of money.
  • I cannot help you if your modification won't boot or won't run stable. I have already said all I know about it in this article. Maybe you can find help in the Rockbox forum.
  • I cannot print the 3D printed part for you. The stl file is available for free and can be printed by commercial print services.
Restauring an old iRiver iHP-120, Part 1

In a time before smartphones, people used so called "digital music players" for portable music. One of them was the iRiver iHP-100 series, which came to the market in October 2003. It had up to 40 GB of storage, which was really a lot these days. It had a playback time of up to 16 hours. It had a remote control with a separate display. And it is the only pocket-size player I know that is also equipped with an optical line-in and line-out.

I got my player in 2004, and I used it for many years, until the hard disk started to show first signs of failing. Then I stored it away to save it for "special occasions" that never came. Many years later, I did not dare to charge it again, as I distrust over-aged Li-Po batteries that have been discharged for a long time. So my player became a Sleeping Beauty, waiting for the day it would be rediscovered and properly restored. The day was now.

In this first part, I will replace the original battery. In a second part, I will replace the 20 GB hard disk with a modern 128 GB MicroSD card, which is a lot more than the size of my entire music collection. After more than 16 years, it will be a modern portable music player again. (Well, sort of… I know it's still inferior to a smartphone.)

Before we start: Li-Po batteries are delicate. A damaged battery can cause severe damage to your home and your health. Please be very careful. If you're not confident enough for the operation, please ask someone for help.

The player is opened by removing the eight screws from the top and the bottom cap with a T6 screwdriver. The caps are glued in place, but can be pulled off with a bit of force. After that, the back cover can just be lifted off. The attached battery cable is very short, so be careful when lifting.

This is a photo of the inside. To the left is the battery pack that we are going to replace. To the right, we see the 1.8" HDD. Yes, the iHP uses an actual hard disk, with spinning platters and arms and all. In part 2, it will be replaced by a MicroSD card.

The battery connector is on the other side of the PCB, so we have to disassemble more. First we remove the HDD, it just needs to be gently lifted and then pulled out of the connector. There is a screw on each of the two side panels, they need to be removed as well. Then we remove all visible screws on the PCB.

The display frame is glued to the front cover, so we need to use a bit of force to remove the PCB. Be careful, the display is very sensitive to scratches. Also we don't want to have hairs and dust caught between the display and the front cover when we reassemble the device, so make sure you work in a clean and dust-free room.

Now we can disconnect the battery from the main PCB. Sadly, the power connector is in the way, so we need to twiddle with the connector and use a bit of force to get it removed. If you use a screwdriver, take care not to slip off and damage the PCB. Also, take care not short circuit the battery cable.

In the next step, we can remove the old battery pack. It is glued to the back cover, so we need a lever tool (e.g. a plastic opening tool) and some patience to gently remove it.

Be very careful when you remove the old battery pack. Do not use blades or pointy tools, and do not use force. The battery pack may burn if bent, damaged, or punctured.

You got the old battery removed now? Please don't just throw it away, but make sure it is properly recycled.

Before we insert the new battery, we should have a look at the cable first. On my replacement, the cable was considerably longer than the original one, so I decided to align it with the other corner of the back cover. If your cable is shorter, or if you are not sure, use the same corner as the original battery. In any case make sure that the cable is at the bottom edge of the back cover. If there is some of the glue tape left, it will firmly hold the new battery in its place.

If you think it was difficult to disconnect the old battery, you will find out that it is even more difficult to connect the new one. Check that the polarity of the connector is correct, the black wire must be closer to the USB connector than the red wire. Take care not to cut or break the wires while inserting the connector. If there is absolutely no way to push the connector into the socket, you need to remove the USB daughterboard. It can be unplugged after unsoldering the wires on its four corners.

I was lucky. After a few attempts and some frustration, I finally got the new battery connected.

When reassembling, make sure the battery cable is correctly routed like in the next photo. It must not be pinched anywhere. Now the PCB can be placed back onto the top cover again.

This is the right moment to check if there are visible dust particles or hairs caught between the display and the front cover. If so, use a photo lens brush to gently brush them away. Do not use a cloth, as it may cause tiny scratches.

Now close the bottom cover for a test. The battery cable should fit properly and should be tension-free.

After that, you can reassemble the device in the opposite order. Congratulations, you have given a new life to this amazing piece of hardware!

In the next part, we will replace the HDD with a MicroSD card. It will not just conserve some battery power, make your player faster and keep it cooler, but also greatly extend hard disk space for your music.

Access alternate certificates with acme4j

On January 11 2021, Let's Encrypt will change the default intermediate certificate from the cross-sign IdenTrust DST Root X3 certificate to their own ISRG Root X1 certificate.

The good news: The ISRG certificate is widely trusted by browsers by now, so the transition will be unnoticed by most users.

The bad news: The ISRG certificate is not included in Android devices before "Nougat" 7.1. These devices will show an error when trying to access sites that are signed with the new intermediate certificate. According to Let's Encrypt, stunning 34% of the Android devices out there shall be affected.

To mitigate the problem, Let's Encrypt provides an alternate certificate that is still cross-signed with the IdenTrust DST Root X3 certificate. If you have a web service that is accessed by a relevant number of older Android devices, you may want to use that alternate certificate. It will be available until September 29 2021. The IdenTrust DST Root X3 certificate itself will expire after that date, so this is a hard limit. Let's hope that the problem is going to be solved on Android side in time.

As acme4j fully implements the RFC 8555, it is easy to change your code so it will use the alternate certificate. Based on the acme4j example, this code block will use the first alternate certificate if present, and falls back to the main certificate if not:

Certificate certificate = order.getCertificate();
certificate = certificate.getAlternateCertificates().stream()
        .findFirst()
        .orElse(certificate);

Remember to remove the workaround after September 29 2021 January 2024, so you won't accidentally use other alternate certificates that may become available in the future.

PS: getAlternateCertificates() was added to the latest acme4j v2.11. If you have an older version, fear not: you just need to have a Login object, so you can bind the alternate certificate yourself. This is how it would look like in the example client:

Login login = session.login(acct.getLocation(), userKeyPair);

Certificate certificate = order.getCertificate();
certificate = certificate.getAlternates().stream()
        .map(login::bindCertificate)
        .findFirst()
        .orElse(certificate);

UPDATE: Let's Encrypt found a way to extend the Android compatibility until January 2024. However, this extension may only work for Android devices. To quote the article:

The new cross-sign will be somewhat novel because it extends beyond the expiration of DST Root CA X3. This solution works because Android intentionally does not enforce the expiration dates of certificates used as trust anchors.