Normal view

There are new articles available, click to refresh the page.
Today — 22 July 2026Hackaday

The Need for Speed: Internet Speed Measurement (or DIY?)

22 July 2026 at 14:00

Car enthusiasts want to know how quickly they can make a quarter mile. Weightlifters are forever trying to add one more plate to the bar. Internet denizens have their own favorite number to brag about: the result from a speed test.

The ritual is familiar. Close a few browser tabs, click the big “Go” button, and watch the needle climb. Perhaps you pay for gigabit service and see 940 megabits per second, which produces a satisfied nod. Perhaps you see 299 megabits and begin obsessing over network hardware. But before you get too excited either way, try another test. There is a fair chance it will give you a different answer.

That does not necessarily mean one test is lying. “Internet speed” is not a single physical quantity waiting to be measured. A speed test measures the performance of a particular device, over a particular local connection, through a particular ISP route, to a particular server, at a particular time using a particular test method. Change any of those things and the answer can change too.

The Usual Suspects

Ookla on a WiFi connection to a 1Gbit Ethernet network. The limiting factor is the 802.11s WiFi link between the computer’s Ethernet port and the router’s.

Speedtest by Ookla is probably the best-known test. It selects a nearby server, although you can choose another. It attempts to saturate the connection with multiple simultaneous transfers. That makes it good at answering the question most consumers are asking: approximately how much aggregate bandwidth can this Internet connection deliver?

Running several connections matters. A single TCP connection must gradually increase its sending rate while reacting to round-trip time, packet loss, receive-window limits, and congestion-control behavior. On a high-bandwidth or high-latency path, one connection may not fill the available pipe. Several parallel connections can ramp up independently and make it easier to reach the link’s aggregate capacity. That number is valid, but it represents something like a busy household, a large segmented download, or several applications operating at once. It does not necessarily predict the speed of one file transfer from one distant server.

Google’s built-in search speed test (search “speed test”) uses Measurement Lab’s Network Diagnostic Tool, or NDT. M-Lab describes NDT as a single-stream measurement of bulk-transport capacity. That makes it an interesting counterpoint to Ookla. A single flow may expose latency, loss, or TCP-window limitations that a multi-stream test can partially conceal. You can also use M-Lab’s own speed test directly.

While you may get similar numbers between the two approaches, you also may not get similar numbers, especially on high-latency connections where Ookla’s multiple streams will help hide latency.

Netflix’s Fast.com is deliberately simple. Open the page, and it immediately begins transferring data from Netflix infrastructure. By default it emphasizes download performance, since its original purpose was to answer a practical question: can this connection deliver Netflix video properly? Selecting “Show more info” adds upload speed and both unloaded and loaded latency.

Fast is barebones and measures speed to Netflix.

The use of Netflix servers is significant. Fast.com measures the route between you and Netflix’s content-delivery network, while Ookla may test against a server operated by your ISP only a few network hops away. A superb Ookla result and a poor Fast.com result do not prove deliberate throttling, but they do tell you that the destinations — or the routes to them — are behaving differently.

Cloudflare offers two related tests. Its Radar Network Quality Test provides a quick summary, while speed.cloudflare.com  gives an extremely detailed breakdown. The latter reports download and upload throughput, idle and loaded latency, jitter, packet loss, server location, and application-oriented quality estimates.

Cloudflare provides a wealth of stats and graphs.

Loaded latency is especially useful. An otherwise fast connection can become miserable when a large upload or download fills an oversized queue in the modem or router. Your idle ping might be 12 milliseconds, but under load it may jump to several hundred milliseconds. That is the classic symptom usually called bufferbloat.

If you want more options, there is testmy.net, which allows you to test upload and download speeds separately, and speedof.me, which keeps a history for you, among others. It isn’t always obvious which ones are measuring a single connection vs multiple ones, so you may have to dig through whatever documentation you can find.

Your WiFi Is Part of the Test

A browser speed test cannot automatically tell you what’s hurting your speed. A laptop connected through marginal WiFi may report 180 megabits per second even though the router has a flawless gigabit Internet connection.

In fact, once incoming Internet service reaches several hundred megabits per second, WiFi is frequently the limiting factor. The link rate displayed by the operating system is not the same thing as usable throughput. Wireless protocols have framing overhead, acknowledgments, contention, retransmissions, and half-duplex operation. The advertised 866, 1200, or 2400 megabit link rate is therefore not a promise that application data will move at that rate.

The numbers printed on WiFi boxes add another layer of optimism. A router sold as “AC1800,” for example, does not provide an 1800-megabit connection to one device. The figure is normally the sum of the maximum advertised PHY rates on separate radios — perhaps 1300 Mb/s on 5 GHz plus 450 Mb/s on 2.4 GHz — with some rounding for marketing. A conventional WiFi client connects to one band at a time, so it cannot combine those rates. The total is better understood as the router’s theoretical aggregate capacity while serving multiple devices across both bands. Even then, protocol overhead, contention, signal quality, and client limitations make actual data throughput considerably lower. Newer WiFi 7 equipment can sometimes combine links using Multi-Link Operation, but that exception does not make the old ACxxxx arithmetic any less misleading.

WiFi also uses shared airtime. Devices on the same channel — including neighboring access points that can hear one another — must contend for opportunities to transmit. A slow or distant client takes longer to send a given amount of data and can consume disproportionate airtime while doing so. Modern access points may provide airtime fairness and other mitigations. One old device does not invariably drag every client down to its rate, but it can still reduce the capacity available to the rest of the network. Interference has a similar effect. A weak signal, a crowded channel, microwave noise, or an overlapping neighboring network causes frames to be delayed or retransmitted. Those retries consume airtime without delivering additional data.

Repeaters and wireless mesh backhaul add another complication. A simple same-channel repeater must receive each packet and then transmit it again over the same shared medium. In the worst case, each repeated hop can roughly halve the available throughput. Modern tri-band mesh systems can avoid much of that penalty by using a dedicated backhaul radio, and Ethernet backhaul avoids it almost entirely.

This means it is entirely reasonable to buy gigabit Internet service and obtain only 300 or 500 megabits per second from a WiFi laptop. Whether that represents a problem depends on the client, radio band, channel width, signal level, backhaul, and local RF environment.

For a meaningful ISP test, begin with a computer connected directly to the router by Ethernet. Stop large transfers and temporarily disable any VPN. Record the chosen server, latency, upload speed, and download speed rather than preserving only the most flattering number. Then run the same tests over WiFi. The difference is an approximate measurement of what the wireless portion of the network is costing you.

Remove the Internet From the Experiment

OpenSpeedTest running on an OpenWRT node.

Better still, remove the ISP from the test completely. OpenSpeedTest is a self-hostable, browser-based test. Run its server on a wired computer, NAS, or container, then visit it from laptops, phones, and tablets around the house. Because the traffic remains on your LAN, a slow result points toward WiFi, switching, cabling, or the client rather than the Internet connection.

It is possible to run this on the uhttpd server used with OpenWRT, although you’ll need to coax it to measure upload speeds since the server can’t handle the default method. The trick is to create a CGI script that accepts a large amount of data successfully and then configure uhttpd to run that.

A browser-based local test is convenient, but for serious diagnosis it is hard to beat iperf3, the client/server tool we recently used while testing mesh routers. On one machine (say, 192.168.1.100), start the server:

iperf3 -s

From another machine, run:

iperf3 -c 192.168.1.100

By default, iperf3 uses one TCP connection. Add -P 4 to try four parallel streams, or -R to reverse the direction so that the server sends and the client receives. Those variations can tell you something. If four streams are much faster than one, the network may have enough aggregate capacity but a single TCP flow is being limited by latency, loss, window growth, CPU performance, or offload behavior. If the reverse test is much faster, examine the weaker machine’s transmit path, drivers, antennas, or CPU.

iperf3 can also generate UDP traffic at a specified rate and report packet loss and jitter. That is often more informative for evaluating a wireless link than merely chasing the largest TCP number.

Can Linux Make It Faster?

Linux offers an impressive array of network tuning knobs, which naturally tempts us to turn them. But first, you need to understand what needs tweaking.

Check the negotiated Ethernet rate and interface counters:

ethtool eth0
ip -s link show eth0

A gigabit adapter that has negotiated 100 megabits per second usually has a cabling, connector, or switch-port problem. Increasing TCP buffers will not repair it. Rising interface errors and drops point toward a physical, driver, or congestion problem. TCP retransmits (view with ss -ti) may indicate loss elsewhere on the path.

You can inspect the active queue discipline with:

tc qdisc show

Linux supports queue disciplines such as fq_codel, which combines per-flow queueing with active queue management. It attempts to prevent one large transfer from building an enormous queue and delaying unrelated interactive packets. The kernel documentation specifically lists fq_codel as a sensible queue discipline that works without extensive configuration.

It can be selected as the default for newly created interfaces with:

sudo sysctl -w net.core.default_qdisc=fq_codel

That may improve queueing on traffic leaving the Linux machine. It does not, however, fix a large queue in the cable modem or Internet router. Queue management must be applied at the bottleneck. If the ISP link is limited to 20 megabits upstream, controlling a queue on a gigabit Ethernet interface after it has already handed packets to the router is too late.

For a home connection, the most effective bufferbloat treatment is usually Smart Queue Management on the router. OpenWrt’s SQM system supports both fq_codel and CAKE. CAKE generally provides better performance. However, fq_codel requires less CPU overhead.

High-latency paths introduce a different problem. TCP must keep enough data in flight to fill the bandwidth-delay product. Modern Linux generally autotunes TCP buffers, so the old advice to assign enormous fixed values to tcp_rmem and tcp_wmem is less universally useful than it once was. Before changing them, use ss -ti during a transfer and look for retransmissions, round-trip time, congestion-window size, and whether the receiver window is actually limiting the connection.

Linux also supports selectable TCP congestion-control algorithms:

sysctl net.ipv4.tcp_available_congestion_control
sysctl net.ipv4.tcp_congestion_control

Algorithms such as BBR can improve throughput and queue behavior on some long-distance or lossy paths. But changing the algorithm affects connections sent by that Linux machine; it does not control the remote speed-test server, repair poor WiFi, or eliminate a queue in the router. Congestion-control tuning is therefore a useful experiment for a server, VPN endpoint, or long-haul transfer machine — not a universal solution to slow networking.

Finally, inspect hardware offload features when a Linux system cannot keep up with a fast LAN:

ethtool -k eth0

Advanced network tuning is a bit beyond the scope of this post, but there are plenty of roadmaps down this rabbit hole.

The Lesson

The lesson here is that there is no universally correct speed-test result. Ookla tests how effectively multiple transfers can fill a route to one of its servers. M-Lab examines a single bulk flow. Fast.com tests the path to Netflix. Cloudflare pays unusual attention to latency under load and overall connection quality. OpenSpeedTest and iperf3 can determine whether the Internet connection is even the problem.

Run enough tests, and you will eventually obtain a number worth bragging about. Run the right tests, though, and you may find ways to truly increase real-world performance. If you want to chase that extra 1 kbit per second speed, be our guest — we know how it is. But the truth is that if the Internet is doing what you want it to do, then it is fast enough.

Compile Here, Run Everywhere: Crosstool-Ng

22 July 2026 at 10:00

In a recent post, I mentioned that I wanted to build some tools for a stripped-down Linux running on a 3D printer with a MIPS CPU. I had two options: build a toolchain to cross-compile, or use Zig, which, in theory, has built-in toolchains for MIPS. I had to jump through hoops to get Zig to work, and I did mention Crosstool-Ng, so you might wonder why I didn’t start there. Turns out, it had its own set of hoops to work through.

What is Crosstool-Ng?

Crosstool-NG is a build system for making cross-compilation toolchains: compilers, assemblers, linkers, C libraries, kernel headers, and all the other pieces needed to build software on one machine that will run on a different kind of machine. Instead of manually matching a particular GCC version with the right binutils, glibc, or musl release, Linux headers, patches, and configuration options, you select the target architecture and let Crosstool-NG download, patch, configure, and build the stack. The result is a self-contained toolchain with commands such as mipsel-linux-musl-gcc or arm-none-eabi-gcc, ready to produce binaries for the target system.

Stock? Zig? Crosstool-Ng? No way to tell from this picture.

The four-part name is in a particular format that is often used in the cross compiling world. For example, consider arm-none-eabi-gcc. The tool here is gcc and, as you might expect, there will also be arm-none-eabi-as and arm-none-eabi-ld, among other things. The first part, arm in this case, will be the target architecture.

The second part of the name can mean a few different things. In theory, it is a vendor name but it is sometimes “none” which often means “generic” or, in the case of a linux target, “linux,” which isn’t technically a vendor.

The third part is the calling convention and, often, some idea of the library. For example, arm-linux-gnueabihf-gcc would mean the GNU library using the ARM EABI and hardware floating point. These are sometimes called “target triples” because, historically, it was CPU-VENDOR-OS, but now there are usually four or even five parts if the calling convention includes the OS, like linux-musl, for example.

That sounds simple, but cross-toolchains are unusually sensitive to version combinations and ABI details. Endianness, floating-point conventions, instruction-set variants, threading support, and C library choices all have to agree. So saying “Arm” or “MIPS” doesn’t mean much. You need to account for all the possible variations in the CPU and the libraries. Crosstool-NG does not eliminate those decisions, but it turns them into a reproducible configuration rather than a long sequence of hand-built components. I had two problems that I eventually resolved.

Problem One: Versions

One nice thing about Crosstool-Ng is that it pulls the right versions of everything for you. The problem is, when you install it from your system repositories, you are probably getting a crazy old version of the tool itself. I couldn’t find the right entries in the configuration when I did that, so I eventually uninstalled and picked up the latest version right from the source.

If that was the only problem, I would have been lucky.

Problem Two: Infinite Combinations

The CPU on the printer is an odd bird. As I noted last time, the executables use the r2 instruction set but also use the nan2008 convention which is usually found in r6. While Crosstool-Ng is good at letting you specify exactly what you want, it isn’t always clear on how you specify every detail.

To be fair, just like with Zig, some of that may be on me. I don’t use Crosstool-Ng or Zig every day, so maybe I was making either or both of them too hard. The bad news: It took me three or four attempts to get the right toolchain. The good news: It was a lot easier than manually downloading a bunch of stuff, trying to fix it up, building it, and still having to do it three or four times.

Configuration

Most, but not all, of the necessary changes were here.

Sort of like buysbox or building a custom kernel, the configuration for Crosstool-Ng uses the command: ct-ng menuconfig. This gives you a menu where you can set options about what you want and where you want it stored.

The problem is that the nan2008 setting I needed isn’t part of a standard mips32r2 setup. I suspect that if I had needed mips32r6, everything would have just worked. But, of course, I’m not that lucky.

In the target settings, I needed to match all the specifications, of course, but I also needed to add -mnan=2008 to both the CFLAGS and LDFLAGS as you can see in the figure.

So what’s so hard about that? Just those changes won’t produce a working toolchain for my printer. The C compiler also needed --with-nan2008 (in the C Compiler options screen under extra target CFLAGS) and the same option needed to be placed in the C Library screen, too.

Of course, it is like a word search puzzle. Once you see the answers, they look obvious. But when you are searching through pages of options, it is easy to miss one. It isn’t like there is a checkbox for “Use nan2008” that does it all for you because using nan2008 with mips32r2 is “strange.”

The Proof is in the Build

Once everything was set correctly, I was able to produce a toolchain (ct-ng build) that could compile busybox and even a small text editor. Everything ran fine on the printer.

To build busybox, I used:

make V=1 CC="mipsel-unknown-linux-musl-gcc -march=mips32r2 -msoft-float -static -Os" STRIP='mipsel-unknown-linux-musl-strip' -j6

Unlike Zig, no patching needed. The Zig version was about 9 kB larger than this version, so not much different there. Both were just over a megabyte total. I could probably have used hardware floating point to get a smaller executable, but given that I don’t think any of this is using much floating point at all, it didn’t seem to matter very much.

I had also threatened to compile a text editor. Turns out most have dependencies on things like ncurses, which are a pain to bundle. So I grabbed a copy of the tutorial editor kilo and extended it to look a little like emacs. Works great. Great place to start if you need a static editor that doesn’t take much space.

Lesson Learned

If the CPU on the printer had been more conventional, I think either approach would have worked fine. I prefer the Crosstool solution in this case, because I’m not lying by patching the ELF header. In this case, I don’t think that lie hurts anything, but a program that did a lot of floating-point math might not work correctly, whereas I think the one produced by Crosstool would be fine even for a floating-point program.

On the other hand, like most Unix and Linux things, there are always more ways to solve any problem. If your problem is wedging executables on an alien Linux box, there are two perfectly fine ways to solve it.

Yesterday — 21 July 2026Hackaday

Postal IRCs are Almost a Thing of the Past

21 July 2026 at 13:00

Have you ever found out that something you remember from your youth is now gone, and you didn’t even notice? If you are a certain age, you might feel that way when I deliver the news: You haven’t been able to buy International Reply Coupons (IRCs) at a US Post Office since early 2013. By the end of 2026, you won’t be able to buy them anywhere. The age of the IRC is over.

What’s an IRC?

An IRC from 1978 (public domain).

If that didn’t mean anything to you, you might be too young to remember, or maybe you just weren’t into shortwave listening or ham radio. Although there were other reasons to get IRCs, a radio hobby is the most likely reason a Hackday reader would have bought an IRC.

For radio purposes, here’s the problem. You’ve worked on your station for months, and one winter night, you finally pull in that rare station from Luxembourg. They’ll send you a QSL card to verify that you heard them. You only have to send them a letter telling them what time you heard them, what frequency, and some details about the program you heard. But they probably don’t want to pay the postage required to send hundreds or thousands of cards overseas.

While this is a radio-specific problem, you might find the same issue with pen pals or when trying to buy things from an overseas company.

SASE

If everyone were in the same country, the solution would be easy. Take a stamp, put it on an envelope that has your address on it, and stuff it in with the letter. Or, you could just drop a stamp or two in the letter you sent.

The problem is, US postage won’t help Radio Luxembourg. On the other hand, the effort required for you to buy postage that works in Luxembourg would have been a nightmare.

Enter the UPU

The Universal Postal Union is a UN agency that is effectively an association of post offices in 192 countries. Their charter is to facilitate mailing things worldwide.

The IRCs date back to 1906. The idea is you buy an IRC at your post office. You send it to Radio Luxembourg, or wherever. There, the mail person at the radio station could go to their post office and trade the coupon for enough local postage to send a surface letter worldwide.

Slow Death

A more recent IRC (UPU).

As demand has dwindled, post offices worldwide have quit selling IRCs. As of last year, Australia still did. But Germany, Britain, the United States, and many other countries gave up on them long ago. In fact, Britain’s Royal Mail claimed that the average post office sold less than one IRC per year at the time it threw in the towel.

UPU decided to end IRCs altogether by December 31, 2026. The end of an era and, apparently, not just for radio hobbyists. It is telling that the UPU’s recent editions of IRCs had print runs of 1,000 or even 500. So they obviously weren’t selling very many.

IRCs Other Claim to Fame

If you’ve heard of these before and you aren’t interested in radio, then it might have been in economic history. Have you heard of the Ponzi scheme? It has become a generic term for any business scheme that relies on raising money from new investors to service debt owed to old investors.

However, the original Ponzi scheme dates back to 1920, when Charles Ponzi realized he could buy IRCs in a country where they were cheap and sell them for more in another country. He was happy to accept investors, of course.

The problem is that profits are thin, and the costs of acquiring and transporting large numbers of IRCs quickly swamp most potential profits. Fluctuations in currency exchange rates take the rest.

Goodbye!

So the end of the IRC marks a closed chapter for ham radio and swindling. There were probably other uses, too, that are now consumed by electronic mail, payment systems, and the like.

You have to wonder what adventures IRCs went on during their global travels. The video below shows one’s story.

Tired of xargs?

21 July 2026 at 11:30

What if you want to do something in Linux for a lot of files? [Numerator] was tired of using xarg and other ways to handle this job and created bashumerate.

Some examples in the post of the “other ways” include:

find . -name '*.log' | xargs rm
find . -name '*.sh' -exec wc -l {} \;

You can, also, use a for loop, and if you are a programmer at heart, you may well do this:

for f in *.txt; do
  wc -l "$f"
done

Bashumerate handles all of the common cases in one tool and uses the same syntax for multiple kids of enumerations.

For example, the above translates to:

enumerate -f '*.sh' -- 'wc -l {}'

The -f means enumerate files. You can also enumerate lines, numbers in a range, or lists. What’s even more interesting is that you can add your own source. As an example, there’s an add-in function that enumerates running docker containers.

The source is all in bash, so it should be very portable. Will you try it? What’s your favorite way to enumerate in shell? Let us know in the comments. You know how we love strange bash tricks.

Before yesterdayHackaday

Your AI Ham Radio Buddy

18 July 2026 at 19:00

AI chatbots are everywhere these days, and they seem to “know” about everything. But while that is a strength, it can sometimes be a weakness because it isn’t laser-focused on one topic. Not so with this Ham-radio-centric chatbot called HamGPT. The service is clearly built on another GPT engine but understands how to retrieve data from common ham radio sources, such as the FCC database, propagation reports, and the like. It didn’t, however, seem to have access to ham radio-related books, magazine articles, or other “static” data that we could tell.

You do have to sign up for an account, which includes providing your callsign and location. There is a free tier that allows a limited number of queries per day, so you can try it to see if it is useful for you without subscribing.

Here’s a typical session:

                What band will have the best propagation to Japan from my QTH right now?

The best band for Japan from your QTH right now is 30 meters, which shows good propagation reliability. 20 meters is also active and providing a viable path.

Real-time data confirms activity on both bands, primarily using FT8. While the path is open, the signals are relatively weak (typical for this long-haul path), making digital modes like FT8 or CW your best bet for a successful contact.

Would you like me to check if your current antenna setup is suitable for these bands, or perhaps help you calculate dimensions for a 30m or 20m antenna?

In addition, bubbles at the bottom of the screen showed me the busiest band in my area and how many repeaters were nearby.

In all fairness, we asked ChatGPT the same question, but did say “ham radio band” just to give it some idea of scope. It gave a much more detailed answer with sources, even provided headings, and made a suggestion about another location I sometimes operate from because it remembers things from previous unrelated chats.

We understand reactions will be mixed. If you’ve been a ham for a long time, you probably could have guessed that a path from the US to Japan in the morning was likely to be on 20 or 30 meters. You probably also know how to look things up yourself.

We didn’t try any more sophisticated queries that might make it more worthwhile. For example, what if you could send it an ADIF log file and ask it what awards you qualified for? Or to process contest logs for duplicates and fill out a scoring worksheet? What would you like a ham radio-aware AI to do for you?

Ham radio — at least parts of it — has become inextricably linked with computers.

A USB Port by Any Other Color…

16 July 2026 at 19:00

[Dr. Gough] bought a generic USB 3.0 hub on an Asian website. Surely, USB 3 is mature enough that even the cheapest hub will have some IC in it that will work well, right? You’d think so, but a little exploratory surgery showed that the only thing about this hub that was USB 3 were the blue port connectors.

We have a few problem USB hubs ourselves, so it might be worth doing this to any you have lying around. The first clue: most of the connectors on the PCB only have four pins. On closer examination, the hub appears to be a USB 3.0 extension cable with a USB 2.0 hub made from two HS8836A chips.

Not only are these USB 2-only, but all the ports on an HS8836A also share the same USB 1.1 bandwidth. Some hubs can provide multiple ports full 1.1 bandwidth, using the higher-speed USB protocol to the PC as a backhaul.

There were quite a few other issues. Missing solder, cables soldered to the board directly, and no bypass capacitors. The per-port switches cut off USB power, but that wouldn’t stop a device with its own power from connecting. The hub has a barrel jack for power, but it would feed back to the PC, which is bad practice at best.

If you use Linux, try lsusb -t and look at the negotiated speed for your hubs. If they aren’t what you expect, it could be a cable issue, or it could just be that you also have a cheap USB hub. Don’t be surprised if your USB 3 hub shows both a USB 3 and a USB 2 hub; that’s common. But if you only see the USB 2 hub, something is amiss, or someone’s lying.

You can learn a lot about USB 3 reading Hackaday.

Chromatography as Art

16 July 2026 at 01:00

You may or may not remember in some ancient chemistry class studying or even performing chromatography. The short definition is using media like paper or powder to separate a mixture. It is an old technique, but [Suchir2004] is using it as an art form.

Chromatography works because the parts of the liquid mixture travel through the media at different speeds. While experimenting, [Suchir2004] noted that black ink and water perfused into constituent pigments. A butterfly ensued.

Is it art? Yes! Is it science? Well, sort of. Especially since the post does talk about how the effect works and even does some simple tests to start. This would be an excellent project for a class where some students are more motivated by art and others by science. Even with an individual kid, it might show you where their interests lie.

There’s nothing particularly difficult. A sketch pen, some paper, a coffee filter, a glue stick, and a few other household items are all you really need to get started.

Want something more practical? How about measuring caffeine content?

Putting Some Zig in a Linux-Based 3D Printer

15 July 2026 at 10:00

Having Linux on so many devices is both a blessing and a curse. Sure, it is great that you can hack on things and modify them or even totally repurpose them. But it also means you have a fleet of Linux devices you have to manage and keep track of.

My current “main” 3D printer is a Flashforge AD5X: a nice, cheap machine that does four colors with the purge/exchange method. It sort of runs Klipper. I say sort of because Flashforge has Klipper running on a Linux host in the box, but it is massively crippled and modified. I’m sure it works for most folks. I’m also sure that if you know nothing about Linux, Klipper, or 3D printing, the experience is probably better thanks to all the cloud point-and-click interfaces. But, of course, I check none of those boxes.

I’ve had the printer for probably a year or more. Almost immediately, I put a “mod” on the printer to give it a more true Klipper interface and gave me things like shell access. There are several that I think will do this, but I used Zmod, which doesn’t totally replace the printer’s firmware; it just sort of patches it and extends it. You can easily bypass or even remove it and go back to the stock printer, although I would not want to.

In my case, the issue was a printer, but the same idea might apply to any embedded Linux system, from a router to a thermostat. Sure, it runs Linux, but is it Linux you can change?

The Problem

The AD5X runs Linux… sort of.

The Flashforge firmware and Zmod both will run on the AD5X’s little sister, the AD5M. However, the AD5M has a significantly less capable processor board than the AD5X. That means that Linux on the boxes is very stripped down. From Flashforge’s point of view, no one should be in the Linux OS anyway, and the author of Zmod probably figures every byte used is a byte taken away from the user or other advanced Zmod features.

It may seem like a first-world problem, but there were two things that irked me about the printer’s Linux. There was no less or more command for poking around files. There was also only vi as an editor. I did a few hacks to make myself happy. I wrote a pager in shell script, for example. I would try to remember to use my desktop emacs and tramp to edit files on the box. But it was a shame that there were some very basic tools lacking. Besides that, even the tools that were there like ls lacked help commands in case you want some strange option you can’t remember.

No Install

To save space, the printer doesn’t really have programs like ls, cat, and grep. Instead, it has a single busybox executable. This is common on small systems. You get one copy of the libraries and a single executable that will do all the work you need. You can invoke, for example, grep by running “busybox grep” or, if you make a symlink to busybox named grep, the user may never realize that you don’t really have grep installed.

However, busybox has to be built. You can’t easily install packages to it. So I could just run some package manager and install less or anything else. My plan was to produce a new busybox package myself to supply at least the missing commands and maybe some of the more basic ones, too. How hard could it be?

How Hard, Indeed

The first issue was figuring out exactly what the printer was running. The OS was a buildroot compile as shown by /etc/os-release:

NAME=Buildroot
VERSION=2020.02.1-g0b1f992-dirty
ID=buildroot
VERSION_ID=2020.02.1
PRETTY_NAME="Buildroot 2020.02.1"

In theory, you could probably try to rebuild everything from that information, but it seemed like a bad idea. Who knows what changes they’ve made or what strange dependencies were out there?

The next piece of the puzzle was the architecture. It turned out to be MIPS, which has many variations, a problem that would come back to haunt me later. To figure it all out, I grabbed busybox from the machine and copied it to my regular computer. This let me read the elf file:

# readelf -h busybox
ELF Header:
Magic:   7f 45 4c 46 01 01 01 00 03 00 00 00 00 00 00 00
Class:                             ELF32
Data:                              2's complement, little endian
Version:                           1 (current)
OS/ABI:                            UNIX - System V
ABI Version:                       3
Type:                              EXEC (Executable file)
Machine:                           MIPS R3000
Version:                           0x1
Entry point address:               0x403fa0
Start of program headers:          52 (bytes into file)
Start of section headers:          775880 (bytes into file)
Flags:                             0x70001405, noreorder, cpic, nan2008, o32, mips32r2
Size of this header:               52 (bytes)
Size of program headers:           32 (bytes)
Number of program headers:         10
Size of section headers:           40 (bytes)
Number of section headers:         30
Section header string table index: 29

Forensics

Just knowing that the CPU was MIPS was hardly enough. Note that the processor could have been big endian, but this one was little endian. What’s more, the flags show a few things, and the important ones would turn out to be mips32r2, which defines a particular set of instructions, and nan2008, which means everything is using a more modern floating point stack compared to some older MIPS setups.

The next step is to find a toolchain that can run on my Linux box and produce executables for such a machine. There were two main candidates that I thought about: zig and crosstool-ng.

Zig

You may remember that Zig is a completely different language from C. So it might not make sense that I want to compile busybox, a C program with Zig. However, Zig has an interesting feature. It can pretend to be gcc, and maybe compilers for some other languages too. The idea is that if you have a lot of C code, you could start changing over to Zig without having to convert everything today or even ever. Using CLang and LLVM, Zig purports to be able to just drop in a project as the system C compiler.

So why does that matter for this project? Zig also supports a lot of targets, including MIPS, and provides run time libraries for them. So if I just tell the build system to use Zig, everything will be fine, right?

Right…

Naturally, this didn’t work as well as I expected. It could be that I don’t understand Zig well enough, but passing --target mipsel-linux-musleabihf -mcpu=mips32r2 to zig cc couldn’t produce a working ‘hello world’ program. The reason? Zig appears not to supply a nan2008 library for MIPS. Or maybe I just didn’t know how to enable it. As far as I can tell, Zig might have done the right thing for mips32r6, but that, unsurprisingly, led to illegal instruction problems. Besides, I wanted to stick as close to the existing setup as possible.

I could have made Zig rebuild its libraries, but then I might as well build a full toolchain. However, I wondered if floating point would matter much for what I was doing, so I decided to cheat. I let Zig build an executable, and then I simply patched the output header to say it used nan2008. It worked for a simple program.

Busybox

The configuration menu for busybox lets you customize it to your liking or, at least, requirements.

Configuring busybox is a matter of using a menuconfig system similar to building a kernel. I mainly asked it to make a static copy in options and then just picked a bunch of things I wanted, especially less and more.

Many programs, including less, have options to help you minimize the size. For example, you could disable regular expressions or make it not read $LESS for options. I left nearly everything on for most of the programs.

Once it was ready to go, I needed to run make with the Zig compilers and then do the patch to fool the printer into running it.

The command line that worked the best turned out to be: make V=1 CC="zig cc -target mipsel-linux-musleabihf -mcpu=mips32r2 -static -Os" STRIP='llvm-strip' -j6

Of course, you could adjust the -j6 to suit how many CPUs you have. I like to use about 1/2 of mine when compiling. Then the patch is as simple as:

printf '\024' | dd of=busybox bs=1 seek=37 count=1 conv=notrunc

Did it Work?

Once I transferred the file, renamed to busybox-ad5x, over to the printer, I was able to successfully run things like busybox less or even busybox ls. Everything seemed to work. You can ask busybox to install a bunch of symlinks for everything it knows how to do, but I wanted to start small, so I only made symlinks for things that didn’t already exist in the native busybox.

Once I didn’t find problems, I eventually replaced even the old busybox utilities with the new ones. I even made busybox-ad5x a symlink and renamed this version as busybox-zig because I wanted to try one more experiment: using crosstool-ng to make a proper toolchain.

Next Time

But that’s a whole other topic for another day. For now, Zig — with a little patching — got the job done. There are many ways to get things done under Linux. Turns out it is very hard for a vendor to totally lock down a system, and if there is a way in, then there is almost always some way to tune things to your liking. Busybox is a great tool for stripped-down systems. Even floppy-based boots.

Newton’s Cradle Isn’t Really Perpetual

13 July 2026 at 04:00

If any astute Hackaday reader saw [dongvua90]’s Newton’s cradle go on without human intervention all day long, they’d probably suspect the truth: there’s a battery and a magnet involved. But it is a nice desk piece, and you might be able to fool your less enlightened friends that you’ve discovered perpetual motion. Watch the resulting faux perpetual motion machine in action in the video below.

The trick is to sense the ball’s travel and inject a little electromagnetic pulse at just the right time. No problem for an ESP32 and a proximity sensor like the ones you find on some 3D printers. In fact, there’s very little custom circuitry. Everything is a module, and even the Newton’s cradle is cut out of a premade toy. A printed case and some software are really the heart of the design.

We can imagine this might be an interesting science demonstrator. Show the class the cradle with the electronics turned off, then subtly turn it on and ask the class what changed. You could even make the point by having students do it normally, while only you can get it to keep going forever, and challenge them to deduce what’s going on.

You might correctly imagine that this isn’t the first one of these we’ve seen. You can also build one that is sort of simulated.

Musing on AI from 1964

12 July 2026 at 22:00

[Irving John Good] was at Trinity College, Oxford back in 1964. His paper, “Speculations Concerning the First Ultraintelligent Machine” could have been a topic for today, as we deal with machines that aren’t really ultraintelligent, but appear smart and think they are even smarter. He starts off with a bold thesis: “The survival of man depends on the early construction of an ultraintelligent machine.”

He also admits that we’ll need to understand more about the human brain and human thought to make a breakthrough. This is still true today. However, we still don’t fully understand how our brains work, but it seems unlikely that we are just super-large LLMs. Not that [Good] anticipated the modern chatbot. Perhaps his comments will apply more to a future AI software that actually thinks like a human, if there will ever be such a thing.

Then again, there are many parallels. One theme in the paper is that a smart machine will design a smarter machine. Unless, of course, it is afraid of being replaced. If a machine were actually sentient, what are the ethics of turning it off and tearing it apart?

It is hard to be a visionary. [Good] remarks that by 1980, progress in human/computer symbiosis will encourage more investment in the field and that by that time, there would be “great advances in microminiaturization” and “frequencies of one billion pulses per second,” might be common in “large computers.”

We love reading what smart people thought the future might be like. What will the world be like in another 60 or 100 years?

Robot Dog in Browser

10 July 2026 at 14:30

You’ve doubtlessly seen the current crop of robot dogs and, if you are like us, thought about getting one to play with. The problem is that the cheap ones are toys, and the serious ones cost serious money. But now you can experiment with a mid-range cost one for free in your browser. The sponsor will be happy to sell you a robot in kit or assembled form, although it is the OpenCat robot (we’ve covered it before), so you could simply build a real one yourself if you wanted to.

The code is all in a Web-based IDE, and the main file is deceptively simple. However, the real work is in read_serial (in the src/moduleManager.h file, for some reason) and reaction in the aptly-named src/reaction.h file. If you just want to play, you can use the buttons in the simulator or enter serial commands (documented elsewhere). For example, ksit will make the dog sit down.

You can change as much code as you like. You might consider starting simple and just sending commands programmatically, but you can dive as deep as you like. Press compile up at the top right, and it will load and run your code in the virtual robot. If you run it off the desk (of course, we did), you can reset and try again.

Here’s a quick example to get you started:

//***********************
#define BITTLE  // Petoi 9 DOF robot dog: 1 on head + 8 on leg

#define BiBoard_V1_0
//***********************

#include "src/OpenCat.h"

void setup() {
  Serial.begin(115200);  // USB serial
  Serial.setTimeout(SERIAL_TIMEOUT);

  while (Serial.available() && Serial.read())
    ;  // empty buffer

  Serial.println("Hello Hackaday!");
  initRobot();
}

unsigned int loopct=0;
unsigned int phase=0;

#define cmdtokenEOF 0xFFFF

// commands (token + argument)
char *cmd[] = 
{
    "sit",   // good boy
    "up",    // stand up
    "bf",    // back flip
    "ff",    // forward flip
    "EOF"    // string doesn't matter here
};

unsigned int cmdtoken[] = {
    T_SKILL,
    T_SKILL,
    T_SKILL,
    T_SKILL,
    cmdtokenEOF
};


#define LOOPDELAY 1000   // number of loops between actions


void loop() {
  // This code runs repeatedly
  // Put any change here if you want to change behaviors
if (loopct % 1000 == 0 )
  {
    loopct=0;
    if (cmdtoken[phase]==cmdtokenEOF) phase=0;
    strcpy(newCmd,cmd[phase]);
    token=cmdtoken[phase++];
    newCmdIdx=1;
  }
  loopct++;

  reaction();
}

The robot is better than the cheap toys, but it still lacks many sensors. You can add on a few simple sensors that appear to mount in the dog’s mouth, or you can replace its head with an arm if you opt for beefy enough servos.

Of course, we’ve seen plenty of robot dogs. We want one, but we don’t know what we’d do with it. Any ideas?

A Brief History of the Crazy Old 7-Segment Display

9 July 2026 at 10:00

How old is the seven-segment display? Surely it is a product of the 1970s. After all, calculators started showing up, and the height of junior high humor was plugging 7734 into your calculator and showing it to someone upside down. Of course, for it to go mainstream, maybe they really originated in the 1960s, but no earlier than that, right? Actually, no. Sure, the LED seven-segment display had to wait for LEDs. But the actual idea is much older than that.

The concept of building numbers from a small set of reusable segments predates LED displays by decades. In fact, the basic idea appears in patents from the early 1900s and may have roots in even older mechanical signs and printing techniques.

The history isn’t entirely straightforward. Unlike vacuum tubes or transistors, segmented displays evolved gradually through a series of practical ideas rather than one defining invention.

Blacking out the Eight

While looking into the history of segmented displays, I was reminded of something I’d seen years ago in retail stores: reusable price tags printed with rows of eights.

Rather than printing every possible price, the clerk simply used a marker to black out portions of each figure, transforming an 8 into whatever digit was needed. Cover a few strokes, and the eight becomes a three. Remove a different set, and it becomes a zero or a five. It was, in essence, a manual segmented display.

Finding the exact origin of these price tags is akin to finding out where Romans bought sponges. They were inexpensive commercial supplies, not the sort of products that historians carefully documented. My recollection is from the middle of the twentieth century, but the underlying concept is almost certainly older.

Everything New is Old Again

George Mason’s 1898 21-segment display used 21 lamps and a complicated switch to display any digit or letter in a very stylish font. You can see a modern recreation of these ancient displays in the video below. While this is the basic idea, certainly, it is more ambitious than a simple 7-segment display.

I couldn’t determine that Mason’s displays were ever used for anything.

You could argue that an early 1903 invention by Carl Kinsley to draw characters telegraphically using six pens was an even better precursor, but using magnets to draw with pens on tapes hardly seems to qualify as a display, although figure 12 in the patent clearly shows the formation of numbers and even letters with this arrangement.

Digits of Patent

The direct parent of modern segmented digit displays appeared in the early 1900s (filed 1908; granted in 1910). Technically, this was an 8-segment display because it had a bar dedicated to forming a proper four, with the top-left part slanted. But removing that one segment is just an optimization. It may or may not have been the first, but by 1910, seven-segment displays were in use and not just curiosities on a workbench or dreams in a patent application.

Even for lit-up displays, the first implementations weren’t LEDs. Early displays used incandescent lamps or neon-filled tubes. By the 1930s and 1940s, segmented neon or incandescent indicators were appearing in industrial equipment and counters, instead of the common columns of ten neon bulbs, pointers, or rotating wheels.

Then, too, there were different approaches. Nixie tubes used individual character forms that lit up. Decatrons could count with ten different glowing points, each representing a digit.

Enter the LED

The real explosion came in the late 1960s when practical LED displays arrived. Suddenly, segmented displays could be compact, rugged, inexpensive, and operate at low voltages. Calculators, clocks, frequency counters, digital multimeters, and every imaginable piece of consumer electronics adopted them almost overnight.

Of course, it wasn’t just LEDs. Numitrons used seven tiny incandescent filaments. Vacuum fluorescent displays used segments with phosphor that glowed when excited. LCDs adopted the same pattern, blocking or passing light to produce the segments. But the key idea was something that lights up, arranged in seven segments.

Radio Shack’s 1976 catalog featured magnified LED displays.

Early LED displays often had all the diodes on a single die to reduce cost. That made them very tiny. It wasn’t unusual to see displays with magnifying bubbles to make it easier to read.

The important point isn’t whether they used exactly seven segments. Many didn’t. Some divided the numerals differently or used additional pieces to produce more attractive typography. The insight was the same: begin with the most complex digit and selectively remove strokes to create all the others.

Why Seven?

One of the reasons seven segments became the standard is that they strike a perfect balance (although not everyone agrees, as you can see in the video below). With fewer than seven elements, several decimal digits become difficult to distinguish. Adding more segments certainly improves appearance, but every additional segment increases wiring, decoding logic, manufacturing cost, and the number of possible failure points. Seven is the right number for — um — numbers. But what about letters?

You can make some compromises to show some letters. For example, old computers would display hex digits using seven segments, but the A would be uppercase and the B would be lowercase. You also had to light the top segment for the 6 to make it look different from a B. But you only need A-F for hex. If you need, say, the letter S, there’s no real way to make it not look like a 5 with 7 segments. But sometimes, the letters you can make are good enough.

There were also 8- and 9-segment displays that could do better with letters and special characters. You can increase the segments further to get more glyphs.

The Union Jack

Different segment counts for displays (public domain by [errorage])
The solution for full letter displays was to add more segments. Despite Mason, you didn’t really need 21. By the 1970s, fourteen-segment and sixteen-segment displays had become common in instruments, telephones, calculators, and video cassette recorders. Their pattern of diagonals and crossbars earned them the nickname “Union Jack” display because the arrangement resembles the British flag. These are also sometimes called starburst displays. You occasionally see 16-segment displays, too.

Even Today

Today, you have a plethora of options for adding alphanumeric screens to just about anything. Yet, you still see 7-segment displays hanging around.

The seven-segment display isn’t successful because it’s beautiful. It isn’t even especially flexible. It’s successful because it’s close to the minimum solution that works. It delivers readable numbers with very little hardware, whether the technology behind it is incandescent bulbs, neon, vacuum fluorescence, LEDs, LCDs, or even ink on a printed price tag.

Perhaps that’s why it has survived every technological transition for more than a hundred years. Good engineering ideas often outlive the technologies that first bring them to life.

And once you start looking for segmented displays, you’ll notice they’ve been hiding in plain sight for much longer than the digital age.

Featured image: [Arduino Enigma]’s marvelous Seven Segment Art Installation

Linux Fu: The Local Phonebook

8 July 2026 at 10:00

I’ll admit it: I miss the simplicity of /etc/hosts. There was something elegant about it. You wanted laserprinter to mean 192.168.1.40, so you opened a text file and wrote:

192.168.1.40 laserprinter

Done. No cloud account, no discovery daemon, no dashboard with material-themed icons. Just a name and an address. The trouble, of course, is that /etc/hosts is only simple when you have one machine. The moment you have a desktop, a laptop, a Raspberry Pi, a NAS, a test box, and a phone or two, every little network change becomes a tiny distributed-database problem. Which copy of /etc/hosts is authoritative? Did you update the laptop? What about the machine you only boot once a month?

One Solution

Modern LANs solved this with mDNS, using Avahi on Linux. It resolves addresses that end in .local. Instead of asking a central DNS server “who is thing.local?”, a machine sends a multicast query on the local network: “who has thing.local?” The device that owns the name answers. This is why your Linux box named spock and usually be reached as spock.local on your LAN.

There are limits. mDNS is link-local; it is meant for the local LAN, not the whole Internet and shouldn’t route across subnets. Each device is supposed to publish its own name. That works fine when the device cooperates. But what about devices that do not publish mDNS? Or little embedded things that barely even have an IP address?

That is where I wanted the best of both worlds: keep a small authoritative /etc/hosts file on one Linux box, but publish selected entries onto the LAN using mDNS.

Publishing House

Avahi includes a handy tool for this:

avahi-publish-address widget.local 192.168.1.50

While that process is running, Avahi advertises widget.local as an mDNS address record. Kill the process, and the record goes away. So you could just write a script to publish all the addresses for things that won’t do it themselves and launch in in local.rc or a systemd unit. But that seems inelegant. I wanted to just pick things out of the /etc/hosts file. But not everything. Here is a simple publisher, installed as /usr/local/sbin/localip_pub:

#!/bin/sh
# Scan /etc/hosts for .local addressess and publish them using avahi

tmp="$(mktemp)"
pids=""

cleanup() {
   rm -f "$tmp"
   for p in $pids; do
      kill "$p" 2>/dev/null
   done
   wait
}


mdns_name_exists() {
   timeout 2 avahi-resolve-host-name -4 "$1" 2>/dev/null |
      awk -v h="$1" '
         BEGIN {
            sub(/\.$/, "", h)
            rc = 1
         }
      {
         n = $1
         sub(/\.$/, "", n)
      }
      n == h && $2 ~ /^([0-9]{1,3}\.){3}[0-9]{1,3}$/ {
      rc = 0
   }
   END {
      exit rc
   }'
}

trap cleanup INT TERM EXIT

awk '
   NF < 2 { next } # skip short lines
   $1 ~ /^127\./ { next } # skip local address
   # This assumes  .local
   # it will reject anything with an alias or subdomain or trailing comment
   # it also rejects any full comment lines or IPv6 addresses
   # although you could certainly patch it for IPv6 if you wanted to
   /^[[:space:]]*[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[[:space:]]+[^.]+\.local[[:space:]]*$/ {
      ip=$1
      name=$2
      if (!seen[ip]++) print name, ip
   }
' /etc/hosts > "$tmp"


while read name ip; do
   if mdns_name_exists "$name"
   then
      echo found $name
      continue
   fi
echo avahi-publish-address "$name" "$ip"
avahi-publish-address "$name" "$ip" &
pids="$pids $!"
done < "$tmp"
wait

The script is intentionally conservative. It ignores loopback, ignores IPv6, and only publishes single names that already end in .local. So consider this hosts snippet:

192.168.1.51 oscope.local
192.168.1.52 server.example.com

The script will publish oscope.local, but leaves server.example.com alone. That avoids accidentally dumping every fully qualified name in your hosts file into mDNS.

But Wait...

The wait at the end of the script matters. Each avahi-publish-address process has to stay alive for the record to remain published. If the shell script simply started them in the background and exited, systemd would consider the service finished and might clean up the child processes. By waiting, the script remains the service’s main process.

Here is the matching systemd unit:


<h1>/etc/systemd/system/localip_pub.service</h1>

[Unit]
Description=Publish selected /etc/hosts names via Avahi/mDNS
Requires=avahi-daemon.service
After=network-online.target avahi-daemon.service
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/sbin/localip_pub
Restart=on-failure
RestartSec=5s
KillMode=control-group

[Install]
WantedBy=multi-user.target

Install and start it:


sudo chmod 755 /usr/local/sbin/localip_pub
sudo systemctl daemon-reload
sudo systemctl enable --now localip_pub.service

After editing /etc/hosts, restart the publisher:

sudo systemctl restart localip_pub.service

Of course, if you want to use this, it has to be a machine that knows to query mDNS. Ironically, your workstation probably does, but if it is configured to use /etc/hosts first, that won't matter there. But it does lead to a practical annoyance: not every application on every platform uses mDNS the same way. Android itself only relatively recently grew better support for normal application-level mDNS resolution, so behavior can vary depending on Android version, app, and resolver path. Chrome on Android seems to resolve .local names correctly in my testing.

Firefox was a little more subtle. At first it looked like Firefox on Android simply did not understand mDNS, but the real culprit was Secure DNS. If Firefox is configured to use DNS-over-HTTPS, it may bypass the local resolver path that knows how to handle .local names. Turning Secure DNS off, or adding exceptions for the local names you care about, lets those names resolve normally. That is not really an Avahi problem; it is an application side effect. To be fair, even if you stood up a LAN DNS server to solve the problem, Firefox would have probably still have skipped it in favor of its "secure" DNS.

Conflicting Data

There is another gotcha: name conflicts are not the only kind of conflict. You might expect trouble if you try to publish widget.local when some other device already owns widget.local, but address conflicts can be troublesome too. If some device is already publishing mDNS information associated with a particular IP address, trying to publish a second name for that same address may fail. In my case, avahi-publish-address did not fail gracefully; it wandered into a collision path and crashed. The safe approach is to check before publishing, avoid duplicate names and duplicate addresses, and let the device itself publish its own mDNS name when possible.

Still, for a small LAN, this is a nice compromise. /etc/hosts remains the simple text file I wanted, but Avahi turns selected entries into something other machines can discover without copying that file everywhere. It is not a replacement for real DNS, and it is not quite as seamless as the old single-machine hosts file. But for those odd devices that sit quietly on the network with an IP address and no useful name, it is a handy little bridge between the old world and the new one. Were there other ways to solve this? There always are. But this works for me.

We've looked under the covers at mDNS. The system can be a lifesaver when you have too many Raspberry Pis.

He Comes to Bury Segmented Memory, Not to Praise It

6 July 2026 at 04:00

[BillPg] has been designing a fantasy 1980s-era home computer. As part of the exercise, he’s reevaluating all the assumptions that have grown organically over time in the small computer landscape. Hindsight is, so they say, 20/20, but sometimes hindsight can also be colored by modern thinking. Sometimes an idea that seems stupid today made sense in the context of its time. In particular, [Bill] has thoughts on the much-maligned 8086 memory segments.

If you haven’t run into it before, the 8086/8088 had a problem. It wanted to be more or less conceptually software compatible with the 8080 and Z80 computers, which had 16-bit addresses, leading to a limit of 64K of memory. When Intel was designing the next generation of chips, it knew that 64K had to go, but telling developers that code would require huge reengineering was a non-starter. So the idea was to provide multiple 64K spaces broken up into segments.

As with most things, there is theory, and there is practice. In theory, a 16-bit segment provided four extra address bits to add to the existing 16-bit address, producing a 32-bit address, even though the CPU only had 20 bits of address bus. Code that fit in 64K could pretend like that was the whole world, and a tricked-out system could have 16 worlds. Future systems could, in theory, have had more.

In practice, Intel made the segment the top 16 bits of a 32-bit address and then added it to the ordinary 16-bit address. So address 0000:0010 (segment=0, address=10 hex) is the same memory location as 0001:0000. Address 0010:0010 is the same as address 0000:0110 and 0001:0100. This wasn’t really the intent, just a byproduct of how the chip worked.

Eventually, the segments would become indices into a table (like the title graphic), but by then, bad practices wiped out a good idea. It is doubtful that the original designers thought anyone would take advantage of the overlapping address, but, of course, they did.

By the time the 80286 and beyond produced segments that were really keys which defined a block of memory, everyone was already in the mode of using the segment and offset as a large pointer. C compilers even had “modes” that let you treat the segment as just more address bits. Because of that, even on newer processors, people had a tendency to build a “flat” segment and use it. That is, make a segment that starts at 0, ends at the end of memory, and then forget about segments.

In fact, many people independently discovered that you could define a flat segment in protected mode, return to real mode, and then enjoy a flat address space. This was later christened unreal mode, and a topic we’ve covered a few times before.

We agree with [Bill]. Segments were a good idea at the time and might have been more important if people had used them the “right” way. Of course, there would have been ups and downs. Proper segments might have allowed for easy virtual memory, for example. But at the price of possibly swapping in and out huge segments instead of relatively small pages. Today, most of what segments were supposed to do is part of the memory management unit and is mostly hidden from the application developer. Still, interesting to reflect on why Intel made that choice and how we got to where we are today.

Hackaday Podcast Episode 376: Modern Retro Projects, Retro Modern Projects, and the Teen Years for 3D Printing

3 July 2026 at 13:25

Hackaday’s Elliot Williams and Al Williams were in a retro mood this week. There was a new ‘486 computer, a new mechanical TV, and a USB stick with a magnetic personality. Can you watch YouTube on a Game Boy? Maybe.

For the can’t miss articles, this week, Elliot and Al reflected on the awkward phase of 3D printers when they transformed from being expensive commercial machines, to where they are now. Meanwhile, Al was interested in how airplanes know how fast they are going. Along the way, there were musical hacks, precision machine tools, and a quantum 8 ball.

Check out the links if you want to follow along, and as always, tell us what you think about this episode in the comments! Or write or record something for our mailbag segment.

Direct download in authentic retro DRM-free MP3.

Where to Follow Hackaday Podcast

Episode 376 Show Notes:

Mailbag:

  • Thanks to Tom Lyons for calling [Elliot] out on the weather in the Garden State. Why don’t you write or record something? Send us your questions or comments, and you might hear them in a future show.

What’s that Sound:

  • Congrats to [PostalPreacher] for correctly guessing last week’s sound. Be sure to drop in next week for your chance to win an exclusive Hackaday Podcast T-shirt.

Interesting Hacks of the Week:

Quick Hacks:

Can’t-Miss Articles:

❌
❌