BMOW title
Floppy Emu banner

Meltdown and Spectre Vulnerabilities Explained

This week brought some fascinating news for CPU nerds: the revelation of security vulnerabilities in the basic hardware architecture of many modern processors. The Meltdown and Spectre vulnerabilities affect virtually all modern computers, according to a sensationalist headline at The Register which called them the “worst ever” CPU bugs. Unlike bugs in a specific software program or operating system that can be fixed with a patch, these are fundamental flaws in the very design of the CPU.

What are these vulnerabilities exactly, how do they work, and how are Meltdown and Spectre different from each other? I must have read twenty different news stories without finding a clear answer. The best I could get was that these vulnerabilities somehow involve the CPU’s use of speculative execution: an optimization trick that executes code before it’s known whether the code should really be executed, discarding the results if it’s later determined that the code wasn’t needed. But as a guy who designs custom CPUs as a hobby, I needed a better answer than that. So I started poking beyond the news headlines into the gory tech details.

What follows below is my attempt to explain Meltdown and Spectre to myself, and by extension to readers of this blog. It assumes readers already have some basic knowledge of concepts like CPU internals, caches, and operating systems. But moreso than normal for this blog, I’ll be discussing details that I don’t fully understand myself, and my explanations may be flawed. If you find an error or omission, kindly post a comment and let me know.

Speculative Execution + Caching = Vulnerability

Both Meltdown and Spectre exploit the fact that speculatively executed code can modify the CPU cache. Even if the code is never “really” executed, meaning that it never modifies CPU registers or memory or other processor state, the cache effects of the speculatively executed code can be observed by cleverly-constructed code that follows it, by testing what is and isn’t cached. Consider this example, taken from Google’s Project Zero Blog:

struct array {
  unsigned long length;
  unsigned char data[];

struct array *arr1 = ...;
unsigned long untrusted_offset_from_caller = ...;

if (untrusted_offset_from_caller < arr1->length) {
  unsigned char value = arr1->data[untrusted_offset_from_caller];

If arr1->length is not presently in the cache, the CPU won’t immediately know whether the if clause will evaluate true or false. If it guesses true, then the if body will execute speculatively while arr1->length is fetched from main memory. Speculative execution will cause arr1->data[untrusted_offset_from_caller] to be loaded from main memory into the cache. This behavior can be leveraged in several different ways (see below) to gain information about protected regions of memory that are supposed to be private: memory owned by other processes or the kernel. The ability to observe protected memory makes it possible to read passwords, Bitcoin keys, emails, or other sensitive information.

Spectre: Speculative Execution in Branch Prediction

The Spectre vulnerability requires getting the victim (the kernel or another process) to run specially-constructed code, which then leaks information through the cache effects of speculative execution. Consider an expanded version of the previous example.

struct array {
struct array {
  unsigned long length;
  unsigned char data[];

struct array *arr1 = ...; /* small array */
struct array *arr2 = ...; /* array of size 0x400 */
unsigned long untrusted_offset_from_caller = ...;

if (untrusted_offset_from_caller < arr1->length) {
  unsigned char value = arr1->data[untrusted_offset_from_caller];
  unsigned long index2 = ((value&1)*0x100)+0x200;
  if (index2 < arr2->length) {
    unsigned char value2 = arr2->data[index2];

If arr1->length is not currently in the cache, speculative execution will continue inside the body of the if clause. Either arr2->data[0x200] or arr2->data[0x300] will be fetched from main memory and cached, depending on the least significant bit of arr1->data[untrusted_offset_from_caller]. After the speculative execution has ended, the attacking user mode code can measure how much time is required to load arr2->data[0x200] and arr2->data[0x300]. Whichever one was cached will load faster, revealing whether the LSB of arr1->data[untrusted_offset_from_caller] is 0 or 1. By repeating this process with other bit masks, the attacker can eventually read all of arr1->data[untrusted_offset_from_caller]. And by the choice of untrusted_offset_from_caller, the attacker can read any memory location.

That’s the general idea. Some implementation details and optimization methods are described in the Project Zero blog. The blog also describes another Spectre variant exploiting speculative execution through indirect branches, which I didn’t examine.

How can a user process get the kernel to run this kind of specially-constructed code? It turns out that the Linux kernel has a feature called eBPF that’s designed for this exact purpose, presumably to allow for device drivers or socket filters or other snippets of user-provided code that need to run in the kernel. I’m assuming Windows and Mac OS have something similar. Since running arbitrary user-provided code in the kernel would be a huge security vulnerability itself, eBPF actually runs the code in an interpreter or a JIT engine. But that’s enough to exploit this vulnerability.

Note: after writing this post, I found a second explanation of Spectre from a group of academic researchers working independently from Google Project Zero. Their paper describes Spectre slightly differently, and discusses attacking other processes rather than the kernel. It also includes a proof of concept Javascript attack, in which a malicious bit of Javascript is able to read private memory from the web browser process. Relying on the fact that Javascript is typically JIT compiled to native code, and using debug tools to examine the native output, the authors were able to iteratively tweak the Javascript source code until it produced native code containing an exploitable conditional branch of the kind shown above.

Spectre affects essentially all modern CPUs, given the proper conditions: Intel, AMD, ARM, etc.

Meltdown: Exploiting Out of Order Execution

Meltdown is similar to Spectre, in that they both leak information through the cache from instructions that were never “really” executed. However, with Meltdown there’s no branching involved. The attack relies on the way modern CPUs optimize performance by employing out of order instruction execution. Due to the availability of CPU execution units and dependent data, instructions are sometimes executed in a different order than they appear in a program, but they are retired (registers and state are updated) in order. The fact that they were executed out of order should be invisible to the program, but Meltdown shows that’s not always true. The details are described at and in a separate academic paper.

When instructions are executed out of order, but aren’t yet retired, their results exist in a kind of limbo that’s very similar to speculatively executed code from branch prediction. However, it’s not clear whether this should properly be called speculative execution. The Meltdown paper refers to these as “transient instructions”, which seems like a good term.

Consider this code:

mov rax, [someKernelAddress]
and rax, 1
mov rbx,[rax+someUserModeAddress]

The first instruction should cause an exception if executed from a user mode process, because it’s an attempt to access kernel memory. However, at least on Intel architectures, it appears that the exception doesn’t occur until the instruction is actually retired. If this code is executing as part of a transient instruction sequence, no exception will yet occur, the privilege violation (bypassing kernel memory protection) will be ignored, and the transient read will succeed. The following transient instructions that use the read value will also succeed, and will affect the cache state in the same way as Spectre, creating a side-channel for leaking information about kernel memory.

Eventually, the first instruction will be retired and the exception will occur. The state changes related to the following instructions will be discarded, because those instructions were never really executed, but their cache side effects will remain. After an exception handler resolves the exception, further code can measure how long it takes to load from address someUserModeAddress vs someUserModeAddress+1, thereby inferring the LSB of someKernelAddress. Further iterations can read the other bits.

To ensure that the Meltdown code sequence executes as an out-of-order transient sequence, the technique includes a long series of filler instructions ahead of it. These filler instructions all use a different execution unit than the units needed by the Meltdown sequence, and create a long chain of interdependent instructions. So the CPU must sequentially execute the filler instructions one at a time, but meanwhile it can also jump ahead and execute the Meltdown instructions out of order.

Note that “out of order” here refers to the Meltdown code being executed out of order relative to the filler instructions. The Meltdown instructions themselves are executed in order relative to each other, since each one is dependent on the previous one.

At this time, Meltdown appears to be limited to Intel CPUs only. It’s uncertain whether this is due to a fundamental difference in how Intel handles memory protection with respect to out-of-order execution, or is simply due to differences in the size of the reorder buffer between CPU vendors. In a short aside on Meltdown, the Spectre paper states “Meltdown exploits a privilege escalation vulnerability specific to Intel processors, due to which speculatively executed instructions can bypass memory protection.” However, the Meltdown paper reports that the authors were able to observe bypassing of memory protection during out of order execution on ARM and AMD processors too, but were unable to construct a working exploit.

Impact and Mitigation

Both of these vulnerabilities are very bad, enabling user mode code to read other protected memory. However, they’re both local exploits: the attacking code must be running on the machine being attacked, so an attacker must somehow get their code onto your machine first. For this reason, the greatest risk is probably to cloud computing environments, where processes from many different people are running on the same machine, supposedly isolated from one another thanks to memory protection. But there’s also a risk in any situation where one computer runs code received from another, even inside a VM or sandbox.

It’s not clear how Spectre can be fixed in software, because it relies on CPU features that are fundamental to all modern processors. In fact, I don’t think it can be fixed in software – at least not in any general way. One web site says, “as Spectre is not easy to fix, it will haunt us for a long time.” The only good news is that convincing the kernel to run an attacker’s special code with eBPF or other methods isn’t easy. And web browsers can be patched to protect against the sort of Javascript Spectre attacks described in the research paper. But other opportunities for Spectre attacks will remain. Future CPUs may contain hardware fixes for Spectre, but they’ll likely come with a complexity and performance penalty. Maybe cache lines will have to be treated as process-specific data instead of as shared resources.

Meltdown is the more serious of these two vulnerabilities, because it happens entirely in a single user space program and doesn’t require any special code in the victim process or kernel. In the real world, this makes it much easier for an attacker to exploit. Fortunately Meltdown can be fixed at the operating system level, but the fix carries a performance penalty that may be as high as 30%.

In the Meltdown sample code, readers may have wondered how an instruction like mov rax, [someKernelAddress] could possibly work in user mode code, even speculatively, since the kernel uses a different virtual to physical address mapping than the user mode process. It turns out that Linux (and I assume other operating systems too) maps the kernel’s memory into the address space of every user process, for performance reasons. By keeping the kernel permanently mapped, there’s no need to flush the TLB when switching between user and kernel space, and TLB entries for kernel space never need to be flushed. The processor’s MMU can normally be trusted to prevent user processes from accessing this kernel memory – except in the case we’ve just seen. The details are nicely explained in the description of a related technology named KAISER.

The “fix” is KPTI: kernel page table isolation. This ends the longstanding practice of mapping kernel memory into the address space of user processes. This ensures that mov rax, [someKernelAddress] won’t be able to reveal any information. However, it means that the TLB must be flushed every time there’s a switch between user and kernel code. If a user process makes frequent kernel calls, the constant TLB flushing will be expensive and have a significant negative performance impact.

The Future

Meltdown and Spectre are scary, not only because of what they can do themselves, but because they introduce a Pandora’s Box of new vulnerability types we’re sure to see more of in the future. We can no longer think about security analysis as something that gets applied to specific software programs or operating systems, examining the code and imagining it being executed instruction by instruction in an abstract environment. We must now consider the specific highly complex CPU (often not fully documented) that runs this software, and understand the many subtle ways in which the true hardware behavior differs from the instruction-by-instruction conceptual model.

The KAISER document mentions techniques like exploiting timing differences in fault handling, observing the behavior of prefetch instructions, and forcing faults using the Intel TSX (transactional memory) instructions. This will be a new frontier for most developers, forcing them to peel back a layer of abstraction when evaluating future computer security issues. The world just got a lot more complicated.

Read 4 comments and join the conversation 

FPGA-Based Disk Controller for Apple II

Apple II disk controller cards are weird, there are a crazy number of different types, and many are rare and expensive. Can an FPGA-based solution save the day for retro collectors? You bet! Nearly all the existing disk controllers connect the same 8-bit bus to the same 19-pin disk interface, so a universal clone is merely a question of replacing the vintage 80s guts of the card with a modern reprogrammable FPGA. This hypothetical universal controller card could connect to almost any Apple II disk drive, or a Floppy Emu. Here’s my first attempt.

An Idea Takes Root

This project has been nearly finished since August, but I’d hoped to delay announcing it until it was 100% done. Back in July there was a surge of interest in the Liron disk controller, when I updated the Floppy Emu firmware to add Liron support. For the first time, it was now possible to emulate a 32 MB Smartport disk on an Apple II, II+, or IIe with the Floppy Emu. But only Liron card owners could benefit, and the Liron card is fairly obscure and difficult to find. People started asking about the possibility of a Liron clone card, so I went to work.

Mapping out the complete schematic of the Liron took a couple of days. It’s a single IWM (the famous Integrated Wozniak Machine), combined with a small number of standard 7400-series logic chips, and a ROM to hold the boot code. Writing Verilog code for the FPGA to duplicate the 7400 chips’ functions was easy. Creating a Verilog reimplementation of the IWM was harder, but with the aid of the IWM spec and a logic analyzer I got it done. By selecting a moderately roomy FPGA, I was able to incorporate the boot ROM functionality too, so no actual ROM chips are needed. The entire design boiled down to some 3.3V level converters and a single FPGA, with a bunch of connectors and passive components. I realized the design wasn’t limited to being a Liron clone, but could also probably be a Disk 5.25 or Disk 3.5 controller with just a change of firmware. Maybe even a UDC controller. Ooh, the possibilities!


I worked like mad to finish the design in late July, just before a trip to Yellowstone National Park, which gave this project its codename. The core of the prototype board is a Lattice MachXO2 FPGA, specifically the LCMXO2-1200HC. This 100-pin bad boy has 1280 LUTs for implementing logic, and 8 KB of embedded block RAM to serve as the boot ROM or for other functions. It also has some nice features like a built-in PLL oscillator and integrated programmable pull-up and pull-down resistors. Unlike some FPGAs, the MachXO2 family also has built-in flash memory to store the FPGA configuration, so it doesn’t need to be reloaded from an external source at power-up. The FPGA can be programmed through a JTAG header on the card.

The external disk is connected to the card with a standard 20-pin ribbon cable, just like what you’d find inside an Apple IIc, or on the Floppy Emu. In fact for the Floppy Emu, you can connect a 20-pin ribbon cable directly from the Emu to the FPGA card, with no DB-19 required. For other external disk drives, I built a small adapter that converts a short length of 20-pin ribbon cable to a DB-19 female connector.

Because the FPGA’s maximum supported I/O voltage is 3.3V, but the Apple II has a 5V bus, some level conversion is needed. I used four 74LVC245 chips as bus drivers. These chips operate at 3.3V but are fully 5V tolerant, and the Apple II happily accepts their 3.3V output as a valid logic “high”. One of the chips operates bidirectionally on the data bus, and the others handle the unidirectional address bus and control signals.

There’s a tiny 3.3V voltage regular on the board, which you can see at the lower-right at U3. It’s barely any bigger than a 0805 size SMD capacitor. Even with these small components, I was still able to solder the entire prototype board myself by hand.

Just for grins I added a 2 MB serial EEPROM to the board, which you can see at U2. 2 MB is enough to store 14 disk images of 5.25 inch disks, or a single larger disk image. It’s not central to the design, but if it works then the card could function as an all-in-one virtual disk like the CFFA3000, in addition to functioning as a disk controller for external drives. More options!


Here comes the embarrassing part. After July’s spurt of activity, the PCBs and parts arrived in the mail. And then I did…. nothing. Finally in October I assembled one prototype board, stuck it in my Apple IIe, and played with it for a bit. But since that day I’ve done…. nothing. I’m struggling with some internal dilemma about the balance between a hobby and a business, and doing things because I want to or because I think I should want to. I’m hoping that by publishing this summary, I may spur myself into further action.

The prototype board works as far as I’ve tested it, but that’s not very far. I verified that I can program the FPGA via JTAG, and that it responds to address and data on the Apple II bus, but that’s about it. I haven’t yet looked at what it’s doing on the external disk interface, or tried connecting a real drive. My attention has just been focused on other things, and even though I always mean to return to this project “soon”, somehow I never do.

There’s at least one serious bug with JTAG programming that needs to be addressed. When the board is outside the Apple IIe and powered from a separate 5V supply, JTAG programming works fine. But when the board is actually inserted in the IIe and powered from the slot, JTAG programming doesn’t work. It always fails with a communication error. I thought this might be some kind of noise or poor signal integrity on the JTAG traces when the board is in the IIe, but the traces are quite short and don’t cross any other signal traces that might carry interfering signals. I also thought maybe I had power problems, and the IIe’s 5V supply was drooping briefly when I tried to program the FPGA via JTAG. But as far as I can tell with a logic analyzer’s analog functions, the 5V and 3.3V supplies remain stable. It’s a mystery that will require some better tools and more careful testing.

Next Steps

What’s next for this FPGA disk controller, assuming I ever finish it? Will it become a new product in the BMOW store? That was certainly my original plan, although my lack of motivation these past months has cast some doubt on that idea. I want to keep fun hobbies fun, and not have them become an obligation and a chore, which I fear is already happening with the other retro computer gizmos I’ve developed in the past few years. We’ll see how it plays out.

Assuming this eventually becomes a new product, how will users reprogram the FPGA in order to clone a different type of disk controller? It’s not reasonable to expect that everyone will own a stand-alone JTAG programmer and know how to use it. Unfortunately I can’t see any alternative solution that wouldn’t require extra hardware and complexity, and push up the cost of the board. I might add a microcontroller and an SD card socket for loading alternate firmware, but that would be a fairly ridiculous amount of extra baggage if it were used only for JTAG. Perhaps the Apple II itself could be used as a JTAG programmer, with some extra hardware that optionally bridged the data bus to the JTAG interface? Sounds complicated, and it would leave the question of how to get the firmware onto the Apple II first. Or maybe the user could choose between a few different built-in firmwares using a switch, but would be unable to load new ones? That sounds more plausible, but would mean a bug in the firmware couldn’t be easily fixed.

Fortunately those questions can wait. The first priority is to finish debugging the prototype, connect it to some real disk drives, and verify that it works. Maybe by Christmas…

Read 31 comments and join the conversation 

Weather Logger with Losant and Amazon Alexa

Like a million other people on the Internet, I’ve been experimenting with home weather logging. I roll my eyes at the phrase “Internet of Things”, but it’s hard to deny the potential of cheap networked sensors and switches, and a weather logging system is like this field’s Hello World application. Back in June I posted about my initial experiments in ESP8266 weather logging. Since then I’ve finalized the hardware setup, installed multiple nodes around the house, organized a nice web page to analyze all the data, and integrated everything with Amazon Alexa. Time for an update.


I’ve placed four sensor nodes around the house. At the heart of each one is a Wemos D1 Mini, a $4 Arduino-compatible ESP8266 microcontroller board with built-in WiFi. A Wemos OLED shield is used to display live stats at each node, and a Wemos SHT30 sensor shield collects temperature and humidity data.

My original prototype stacked the three modules on top of each other, but I found that this configuration caused the heat from the Wemos D1 Mini to skew the temperature readings from the SHT30 sensor. The final hardware setup uses a Wemos tripler base to mount the three modules side-by-side. The module is powered by a standard USB cable connected to a power adapter scavenged from some other long-forgotten device. The total hardware cost for the entire node is about $10, which seems amazingly inexpensive.

Three of the nodes are indoors. The fourth is outside on a patio, plugged into an outdoor electric outlet and protected from the elements by a sheet of cardboard. This node doesn’t have any OLED display (nobody is there to see it), and it uses a BMP085 sensor that measures temperature and air pressure instead of temperature and humidity. The outdoor node is unfortunately prone to crazy temperature readings when the direct sun hits its cardboard shield. The cardboard quickly warms in the sunlight, creating an oven effect that boosts the temperature readings to over 100 F, even when there are many holes in the cardboard to encourage airflow. I need to design a better enclosure for the outdoor sensor that’s not as sensitive to the sun.

This hardware setup works nicely where WiFi and electric outlets are easily available. For sensor nodes “in the field” outside WiFi range and requiring battery power, something like a Moteino may be more appropriate.


The software running on each node is very simple: it’s little more than a combination of standard Arduino libraries for each of the modules. There are standard libraries for the SHT30 and BMP085 sensors, for the Wemos D1 Mini’s built-in WiFi, for the OLED display, and for the Losant data logging service. For anyone who’s done much Arduino programming, the glue code that’s needed to tie everything together is simple and can be written in an hour. See my example code.

When first powered on, the node software connects to the local WiFi network using a hard-coded SSID and password. It then connects to the data logging server, as well as an NNTP server to get the current date and time. Once that’s done, it polls the sensor every 15 seconds to get the latest data. The data is displayed on the OLED, and also transmitted to the logging server. Easy peasy.

Logging and Analysis

Displaying live data is nice, but the most interesting part of a weather logger is analyzing the collected data. By examining data over time, and comparing data from multiple nodes, it’s possible to answer burning questions like:

  • When it’s slightly warmer outside than in, will opening the windows cool the house by creating a breeze, or warm the house by admitting warmer air?
  • Does kitchen cooking have a measurable effect on indoor humidity?
  • How slowly or quickly does indoor temperature change in response to outdoor changes?
  • Is it always cooler downstairs than upstairs?
  • What’s the effect of opening specific windows around the house?

After experimenting with many different data logging and display services, I settled on Losant. Their web page looks very business-oriented and intimidating, so I initially thought it would be a poor match for my needs, but I was wrong. The system is easy to use, and is free as long as you don’t have a crazy number of nodes or data records.

Losant powers a custom web dashboard with a mix of graphs and other widgets. The layout, size, and data details are highly configurable, and a single widget can do more than simply displaying the latest sensor reading. For example, it can display the average, min, or max reading from a sensor over a window of time, or compute an aggregate value from several sensors.

My dashboard shows live data from the four nodes, as well as temperature, dewpoint, and atmospheric pressure graphs for the past 24 hours and past 7 days. I learned that downstairs is reliably cooler than upstairs, and that opening those windows really does create a cooling breeze. I found that a person entering a closed room for a few minutes can substantially raise its humidity (all that exhaling). My furnace has a cycle time of 20 minutes, visible in the ripple of the 24 hour temperature graph shown above. The kitchen temperature often shoots up around 4 PM when the afternoon sun comes in the windows. Outdoor low temperature was 51.9 F, reached at 7:15 AM this morning. Saturday’s outdoor low was 41.7 F at 5:40 AM. Lots of interesting stuff.

Amazon Alexa Integration

One of the most interesting features of Losant is its webhook integration. In addition to logging and displaying data, it can also interact with 3rd-party web services. A data update from a sensor node can trigger some related web request, or a web request to Losant’s servers can retrieve stored data, or even trigger a command to the sensors. There are some powerful options, and it’s all configured through a visual programming interface that Losant calls a workflow.

Using this tutorial, I created an Amazon Alexa skill for querying my weather logging nodes. The setup was a bit complex, but the tutorial does a good job of explaining the skill configuration that’s required in the Amazon developer admin interface, and the Losant workflow design. Within an afternoon of fiddling it was all working great. I can ask for the temperature or dewpoint of a specific weather node, using generic language like “temperature” or “how warm is it”. I can also make a general inquiry and have Alexa prompt me for necessary details:

“Alexa, ask the house how hot it is.”
“Which station? You can say kitchen, study, downstairs, or outside.”
“The current outside temperature is 63.1 degrees.”

Most of the interesting configuration work is done in the Amazon admin interface. This is where the various “intents” are defined (specific actions or requests that can be made by the user), and the vocabulary words related to each intent. It’s also where the Alexa skill is given a name, which in my example is “the house”. By beginning a request with “ask the house”, Amazon knows to process the rest of the sentence through my skill template instead of its built-in response templates. Once it determines what I’m asking for, Amazon’s server makes a web request to Losant. The Losant server looks up the desired data and returns it to Amazon, who sends it back to my Echo to be articulated as a spoken reply. Asking for the dewpoint in the kitchen may be pointless, but feels almost like conversing with the Star Trek computer. The future is here!

Read 4 comments and join the conversation 

Zeroplus LAP-C 322000 Logic Analyzer Review

Who needs a logic analyzer? You do! If you enjoy working with electronics, a good logic analyzer is an indispensable tool. It lets you examine exactly what’s happening with your data signals, so you can troubleshoot problems quickly or reverse-engineer unknown protocols. Developing digital electronics without a logic analyzer is like navigating without a map.

In decades past, logic analyzers were bulky and expensive purpose-built machines from companies like Hewlett Packard. There’s still a place for such high-end equipment, but today most engineers can get everything they need from a small USB device that costs just a few hundred dollars. Saleae is one of the better-known names here, but it’s a crowded market with many worthy competitors. Which one is right for you?

Hello Zeroplus

Today I’ll take a look at an example of the Zeroplus “Logic Cube” series. Zeroplus is based in Taiwan, and their logic analyzer products have a good reputation among Taiwanese IT companies, but are less well known in the West. Full disclosure: Zeroplus sent me a demo unit for the purpose of this review. What you’ll read below are my own unfiltered opinions of the hardware’s strengths and weaknesses.

The members of this product family are buffered logic analyzers, with a few megabits of high speed on-board memory for storing the captured sample data. This is the more traditional approach to designing a logic analyzer, and it provides some advantages versus the on-the-fly USB streaming approach used by Saleae and other similar low-cost logic analyzers. Buffered LAs aren’t reliant on the PC’s USB bandwidth, so they can capture many channels at high sample rates without fear of saturating the USB link and losing data. The tradeoff is that buffered LAs have finite storage space, so the maximum amount of data that can be captured is limited. Data compression helps, but once the on-board memory is full, signal acquisition stops. In contrast, streaming LAs support “infinite” capture sizes limited only by the PC’s available RAM and disk space, but have limited bandwidth.

The Zeroplus logic analyzers in this Logic Cube series are commonly called “LAP-C” for the common prefix in all of their model numbers, and you’ll find the most pertinent resources on the web by searching for this term. LAP-C models are sold in seven different versions, differing mainly in the number of channels and amount of on-board memory. For this review, I tested the top of the line LAP-C 322000, with a retail price of $1699 in the United States. Here are the specs:

Logic Analyzer: Zeroplus LAP-C 322000
Number of Channels: 32
Sample Memory: 64 Mbits (2 Mbits per channel)
Max Sample Rate: 200 MHz
Vinput of Testing Channels: -30V to +30V DC
Retail Price: USD $1699

In comparison, the mid-range members of the LAP-C family pare back the number of channels and memory size in exchange for lower prices. For example, LAP-C 16064 is 16 channels / 1 Mbit / 100 MHz for $249, and LAP-C 16128 is 16 channels / 4 Mbits / 200 MHz for $399.

Unboxing and Hardware

While the front of the box has English text, the technical bullet points on the back are primarily in Chinese. This probably doesn’t matter much, since very few people will ever be browsing store shelves when shopping for a logic analyzer, but it shows that Zeroplus’ marketing team has additional translation work to do if they hope to attract more Western customers.

The 34-page instruction manual inside the box is also Chinese, but a well-written English-language manual can be downloaded here.

The logic analyzer unit and its accessories all fit inside a hardshell zippered case that’s included. While it’s a small thing, this is a very nice touch, and it makes it easy to pack up your project when you’re finished debugging hardware. The pulse width trigger module included with the LAP-C 322000 model is the only accessory that doesn’t go in the hardshell case.

The LAP-C 322000 package includes:

  • logic analyzer main unit
  • USB cable
  • 32 flying lead wires
  • 36 IC test hooks
  • printed manual (Chinese)
  • installation software CD
  • hardshell case
  • pulse width trigger module
  • hookup wires for trigger module

The pulse width trigger module is made from brushed aluminum. When connected to the main unit, this module upgrades the logic analyzer with a new feature: the ability to trigger on a high or low pulse whose duration is outside a user-selected range. This may be useful when working on PWM applications like dimmable lighting.

The main logic analyzer unit is made from an attractive gloss white plastic. The external interface is minimal: a button to start immediate captures, and status lights for Run, Read, and Trigger. The external connector is two rows of standard 0.1 inch male headers. In addition to the 32 data channel connections and ground pins, there’s also an external clock input, and a few special I/O pins for connecting the pulse width trigger module or a second LAP-C unit.

The LAP-C does not offer any analog measurement capability. While serious analog work demands an oscilloscope, some newer logic analyzers are starting to add low-bandwidth analog capability too. This can be useful for verifying that signal voltage levels are in a valid range, or that power supplies are behaving as expected. Analog measurement is a nice extra feature, but its absence here isn’t a deal-breaker.


The LAP-C software is Windows-only. That’s not a big limitation, since any halfway-serious engineer will have access to a Windows machine even if it’s not their main system, but Macintosh and Linux software versions would have been nice. Windows 7, 8, and 10 compatibility is advertised. I used software V3.13.05 with Windows 7. You can download the software and try it out in demo mode, even if you don’t have the LAP-C hardware. The English-language software translations are generally well done and easy to understand.

The graphical interface appears geared towards advanced users, with a very large number of tools, measurements, and options visible directly on the main screen. This is great for power users, but may be overwhelming for newbies, or to anyone accustomed to the minimal interface of Saleae’s software. I found it a bit daunting at first, but after 30 minutes of experimenting and checking the manual, I had mastered the basics.

Some aspects of the UI would benefit from more polish. When viewing large data ranges, panning and zooming the waveform can be glitchy, with a laggy response to mouse input and different portions of the waveform scrolling a fraction of a second after others. Compared to the smooth pan and zoom of competing logic analyzer software, or to tools like Google Maps, that’s a little disappointing. Other minor graphical glitches and goofs sometimes appear, like waveforms that aren’t a uniform height or scale values that are the wrong units. The intervals of the ruler are also oddly chosen, with tickmarks at 0.409374912 seconds followed by 1.91042 seconds and then 3.411465 seconds, instead of divisions at even intervals using powers of 10. None of this prevents you from analyzing captured sample data, but it can be confusing and distracting.

A data capture can be started immediately by pressing a button in the software, or by pressing the physical button on the logic analyzer unit. Captures can also be triggered by a level or edge condition on a single channel, or by more complex functions like a specific value on a parallel bus, or a protocol-level event like an I2C NACK.

There are an impressive number of powerful features embedded in the LAP-C software. Repetitive run triggers the logic analyzer over and over, so you can look for one instance that’s different from the others. Noise filter ignores pulses with a duration below the threshold you specify. Data can be captured with an asynchronous internal clock, or synchronously using an external clock connection. Captured data can be searched in several different ways to find a region of interest. Waveforms and data can be imported and exported for additional examination with other tools. There are many more advanced analysis features that I didn’t have time to explore deeply. Some of these may only be valuable in specific circumstances, like the memory analyzer for examining address/data information, but they’re great when they provide the special capabilities you need.

One small but curious shortcoming: in the software’s list of choices for the sampling rate, it skips directly from 1 MHz to 10 MHz with no intermediate options. Most of my electronics projects operate a speeds faster than 1 MHz but slower than 10 MHz, so the missing sample rate options are a bigger issue for me than they might be for others.

Capturing and viewing sets of raw waveforms is great, and is the core of logic analyzer usage. But to really get the most out of the tool, you’ll want to use the software’s protocol analyzers to provide a high-level representation of the data. A protocol analyzer is a software module that converts raw waveforms into decoded data packets. For example, if the software offers an I2C protocol analyzer, then you can view the captured sample data as a series of device addresses, data bytes, and ACKs, instead of counting raw transitions of the SCK and SCL signals while you thumb through an I2C reference guide. The LAP-C software offers over 100 protocol analyzers, including I2C, SPI, serial (RS-232C/422/485), JTAG, PS/2, USB, 1-WIRE, CAN, IRDA, 3-WIRE, and many more. Some of these used to be extra cost options, but since 2016 all the protocol analyzers are available free. Here’s a typical protocol analyzer example from Zeroplus:

How Much Sample Memory Do You Need?

When purchasing a buffered logic analyzer, you need to predict in advance how much sample memory you’re likely to need. Underestimating is bad: if there’s not enough sample memory, you won’t be able to capture as many channels for as long a duration as needed for your debugging work. But overestimating is bad too: it means you’ll pay hundreds of dollars extra for additional sample memory you don’t need. So how can you decide how much memory is enough?

This is a difficult question to answer, because it depends heavily on the type of electronics work that you do. You might work primarily with low speed serial signals, or you might need to analyze a wide parallel bus running at high speeds. Your data might be highly compressible with the LAP-C’s compression algorithm, or it might not. This leads to a frustrating “it depends” answer that satisfies no one.

For my own hobby electronics work over the past few years, I typically need to analyze systems with 5 to 10 signals running at speeds between 1 MHz and 10 MHz. My normal work pattern with a streaming logic analyzer is to manually start the capture, and record a few seconds of data, then examine it afterwards to zoom in on the interesting parts. Using a buffered logic analyzer, without the benefit of compression, this would require a worst case of 10 signals times 10 MHz times 10 seconds, or 1000 Mbits total. My simple experiments with LAP-C compression found that it provided about a 10x improvement for my data, so that reduces the memory requirement to 100 Mbits – close enough to the LAP-C 322000’s 64 Mbits. So with the top of the line LAP-C model, I could probably support my existing work pattern, but anything with less memory would be insufficient.

To really get the benefit of the LAP-C hardware, I would need to stop using 10 second long captures, and instead set up triggers to capture only the few hundred milliseconds or microseconds I’m really interested in. That would require some extra time for setup, but would greatly reduce the amount of memory needed.

Other Thoughts

Zeroplus’ web site lists two official US distributors, and one appears to only stock the entry level LAP-C 16032, leaving a single source for most LAP-C models in the US. With a bit of Google searching, you can also find third-party LAP-C sellers from Asia who will ship directly to the US. Direct sales from the Zeroplus web site would be a welcome addition, but are not currently an option.

Is the Zeroplus LAP-C series right for you? It depends on what you plan to do with it. For the casual electronics hobbyists who are typical readers of this blog, the $1699 price tag of the LAP-C 322000 may be more than they’re willing to spend, but they probably don’t need all the features of the LAP-C 322000 either. Zeroplus offers three LAP-C models with slightly lower specs all priced below $400, which are probably a better fit for part-time garage hackers. I expect that most hobbyists will be fine stepping down from 32 to 16 channels, although stepping down from 64 Mbits of memory to 4 Mbits or 1 Mbit may be a concern.

With 4 Mbits and 16 channels, at a 10 MHz sample rate and using compression, you’ll get a capture window of a couple hundred milliseconds. That’s small enough so that manual triggering is unrealistic. Instead, you’ll need to plan ahead of time to decide what your goal is with this capture, and how you can construct a trigger to capture exactly the region you need to examine. For power users working with high speed systems and large numbers of channels, this will already be familiar. They’re more likely to know specifically what they’re looking for, and to see complex trigger setup as a normal and expected part of debugging. They’re also more likely to benefit from some of the LAP-C’s advanced features and hardware options like external clock input, pulse width triggering, and detailed software analysis. The breadth and depth of the LAP-C software’s various tools and analyzers is impressive, and will surely be a boon for hardcore electronics engineers. Beginners and others with more basic needs may be better off with an 8-channel streaming logic analyzer with a simple and friendly software interface.

What about the general merits of buffered vs streaming logic analyzer designs? For situations where there’s enough USB bandwidth to stream the sample data on the fly, I believe that approach provides a better user experience. There’s no need to worry about trading off sample rate for sample depth, or worrying whether the capture window will be large enough to contain all the events of interest. But for more demanding situations with large numbers of channels and high sample rates, streaming just doesn’t work. 32 channels at 200 Mhz sampling rate is 6.4 Gbits/sec, which is more than USB 3.0’s total maximum theoretical bandwidth and far more than its real-world bandwidth. So depending on the application, both streaming and buffered designs have their place.

My ideal logic analyzer would be one that operates in streaming mode where sufficient USB bandwidth is available, and falls back to buffered operation when streaming won’t work. That would probably be needlessly complex and expensive, but I can dream!

Read 4 comments and join the conversation 

Floppy Emu and the Apple Pippin

Remember the Pippin, Apple’s ill-fated attempt to enter the video game market? The hardware was effectively a modified Macintosh, running a customized version of System 7.5. The Pippin lacks any standard floppy disk connector (internal or external), but it does have a proprietary PCI-based docking connector for expansion. 20 years after its release, Pierre Dandumont has developed an adapter for the Pippin’s docking connector, making it possible to attach a Floppy Emu disk emulator. And it works!

During the Pippin’s lifetime, Apple and Bandai sold a floppy adapter for the console, and many games can use it. Pierre describes the official accessories on his blog here (French language). These accessories are very rare. Working with a colleague, Pierre made a copy of the PCB inside the official adapter, which is now available on OSH Park.

Pierre has also been busy with other floppy hacking exploits. He successfully added a Floppy Emu to a first generation Bondi Blue iMac, which famously lacks a floppy connector – it was the first Macintosh without a floppy. Apple included an unpopulated connector footprint on the motherboard, so with a little bit of soldering and the proper ROM, the iMac can have a floppy drive where it never did before.

Here’s the explanation from Pierre:

I’m a big fan of Macintosh, and when I discovered the Floppy Emu, I decided to order one. I used it in old Macs to transfer some data, play Prince of Persia or retrieve data without going through a network. Like all buyers, I guess.

But on my blog, the Journal du Lapin (mostly in French, sorry), I like to show hacks, or curiosities. I had sent some of my tests to Steve and he offered to publish here.

The Pippin

For those who do not know the console of Apple and Bandai, it is a game console released in 1996, and very few copies were sold (about 40 000). Apple offered an optional floppy drive, which was to be placed under the console. It contains a simple PCB with a standard 20-pin connector. With a friend, we designed an adapter and then I plugged the Floppy Emu on the console. Some games allow you to save data on a floppy disk rather than on the internal flash memory (128 Kb). For example, it is possible to save images from a Dragon Ball Z game.

The iMac Bondi Blue

More amazing, the iMac. The first iMac (Bondi Blue, in 1998) did not officially have floppy drive, but Apple had left the traces of a connector on the motherboard. Obviously, the drive had been planned until a rather late date in the development of the iMac.

So I opened my iMac, soldered a 20-pin connector and connected the Floppy Emu. With the appropriate version of Mac OS, it works perfectly and it is possible to use the floppy drive with an iMac. In practice, it works with Mac OS 8.1 (the original system) and Mac OS 8.5, but not with Mac OS 8.6 or Mac OS 9 (and of course Mac OS X). Apple has actually blocked the floppy drive directly into the ROM from version 1.2. The iMac is the first Mac with a NewWorld architecture, that is, it uses a “ROM” that is loaded from the hard drive, while the previous Macintosh used a real ROM, that can not be easily updated. Since Mac OS 8.6 was delivered with a 1.4 ROM version, the floppy drive does not work with this version of the OS.

In both cases, the Floppy Emu perfectly replaces a conventional floppy disk drive and greatly simplifies testing. Thank you Steve for your work.

Great stuff!

Read 3 comments and join the conversation 

Custom Key Mappings for ADB-USB Wombat


Here’s an exciting new feature for the ADB-USB Wombat input adapter: custom key mappings.
With firmware version 0.3.0 or later, you can replace the built-in mappings between USB and ADB scan codes, and create your own customized key mapping tables. Change which keys behave as Command and Option, reassign the function keys to new purposes, select a different key to behave as ADB power/wake-up, and design other custom key mappings. Go crazy!

The code framework to support custom mappings has been in place for a while, and it’s little more than a lookup table of USB to ADB scan code equivalents, and a complementary table of ADB to USB equivalents. There are two separate tables, instead of a single bidirectional table, because there’s not always a one-to-one mapping between USB and ADB scan codes (in mathematical terms it’s not a bijection). Use a custom lookup table, and you’ll get custom key assignments.

The harder part was designing a user-friendly interface for viewing and editing the tables. It would be awkward and error-prone to expect people to manually fill in a few hundred numbers in a hex editor. After considering various cross-platform frameworks like Qt, I decided to implement the keymap editor as a web page. All of the logic is implemented in Javascript, so you can see how it works by viewing the page source. I’m not the world’s greatest UI designer, so if you’re a web UI specialist and want to contribute some interface improvements, they would be very welcome.

Because the control, shift, and capslock keys are used to access the Wombat’s help commands, those keys shouldn’t be remapped. A few other mapping details are called out in the editor for ISO keyboards and certain ADB keyboards.

Installing the custom key mappings to your Wombat board is very similar to installing new firmware. Copy a file to a USB flash drive, put the flash drive in the Wombat’s USB port, and hold the board’s power key button while it powers on. Complete instructions are on the keymap editor page. If you accidentally mess up the key mappings so badly that you can’t recover, the keymap editor can also be used to download and reinstall the default keymap.

Be the first to comment! 

Older Posts »