453 lines
29 KiB
Plaintext
453 lines
29 KiB
Plaintext
Episode: 4614
|
||||
|
|
Title: Dauug|18: Faster Than a '286, but Inspectable Like a Soroban
|
|||
|
|
Source: https://hub.hackerpublicradio.org/ccdn.php?filename=/eps/hpr4614/hpr4614.mp3
|
|||
|
|
Transcribed: 2026-07-31 16:15:11 (official HPR transcript)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
This is Hacker Public Radio Episode 4614, for 2026-04-09
|
|||
|
|
Today's show is entitled, "Dauug|18: Faster Than a ’286, but Inspectable Like a Soroban"
|
|||
|
|
The host is Marc W. Abel and the duration is 00:37:06
|
|||
|
|
The flag is Clean, and the license is CC-BY
|
|||
|
|
The summary is "What would MacGyver build when he can't trust complex VLSI? I don't know, so here's what I'd build."
|
|||
|
|
Welcome back, Hacker Public Radio listeners!
|
|||
|
|
My name is Marc Abel, and I'm online at dauug.org, spelled D A U U G dot O R G.
|
|||
|
|
Today we'll take a first look at an 18-bit controller being designed by The Dauug House
|
|||
|
|
that doesn't use any complex VLSI.
|
|||
|
|
It doesn't have a microprocessor or anything like one—no FPGA, PLD, ASIC, or even DRAM.
|
|||
|
|
Now why would someone want a controller that doesn't use complex VLSI today?
|
|||
|
|
Because complex VLSI has a long history of containing defects that hacking and malware
|
|||
|
|
can exploit.
|
|||
|
|
Even dynamic RAM has been shown to not work as designed when adversaries are present.
|
|||
|
|
And even if we open-source our microprocessors and whatnot, we have no tools as makers that
|
|||
|
|
can audit delivered chips against their open-source specs.
|
|||
|
|
So from the standpoint of maybe someone who needs to automate some aspect of critical
|
|||
|
|
infrastructure, or maybe someone who lives under an authoritarian regime, it can be valuable
|
|||
|
|
to have modern electronics that operate transparently,
|
|||
|
|
don't use any black-box components, and can be inspected by their owners clear down to
|
|||
|
|
the logic-gate level.
|
|||
|
|
I've thought about this need for about 20 years in hope of finding a way forward.
|
|||
|
|
I was encouraged by modern surface mount techniques.
|
|||
|
|
Individual transistors can be packaged so small that 25,000 can fit in a teaspoon.
|
|||
|
|
Robots that can place and solder them require skill to set up and use, but they
|
|||
|
|
aren't expensive.
|
|||
|
|
And because a 32-bit microprocessor already existed that only had 25,000 transistors
|
|||
|
|
(it was the original ARM CPU), I was sure right off that maker-constructable computers that
|
|||
|
|
remain inspectable at the logic-gate level even after delivery could be made practical.
|
|||
|
|
So I kept thinking.
|
|||
|
|
My discrete transistor idea had several weaknesses, but I think it was looking at recently-built
|
|||
|
|
relay computers—
|
|||
|
|
there are hobbyists that like to build these—that exposed the most serious drawback, and
|
|||
|
|
that's primary storage.
|
|||
|
|
If a computer has even a million bits of random-access memory, it would take on the order
|
|||
|
|
of a million components to build that memory.
|
|||
|
|
Now a million transistors is way more than 25 thousand, and we'd need about six transistors
|
|||
|
|
per bit to build a reliable memory.
|
|||
|
|
So I could probably build a processor from discrete components, but the memory supporting
|
|||
|
|
it would have to be VLSI, probably in the form of static random access memory, or SRAM.
|
|||
|
|
But what about the security consequences of using VLSI SRAM?
|
|||
|
|
Could SRAM introduce concealed security defects that hacking and malware could exploit?
|
|||
|
|
Whether or not to trust SRAM is a judgment call.
|
|||
|
|
We need to consider whether SRAM supply chain attacks are viable enough for someone to mount
|
|||
|
|
one, what transparently functioning alternatives to SRAM could be, and how far we're willing
|
|||
|
|
to go to have transparently functioning computers in the first place.
|
|||
|
|
Exploring these questions is outside the scope of this episode, but I'll say a few
|
|||
|
|
words in SRAM's favor.
|
|||
|
|
As circuits, static random-access memory components are not proprietary.
|
|||
|
|
In fact they're the exact opposite of proprietary in that their behavior and pinouts are standardized.
|
|||
|
|
And although the chips are very large scale integration, this largeness is in cell count
|
|||
|
|
rather than complexity.
|
|||
|
|
An SRAM is the same 6 transistor flip-flop over and over again, millions of them, and
|
|||
|
|
they're all isolated from each other.
|
|||
|
|
In fact, if you read the datasheet for an SRAM IC alongside a datasheet for an AND gate,
|
|||
|
|
you'll find they're not much different in length.
|
|||
|
|
Even if a sophisticated adversary is warned that I plan to build a computer out of static
|
|||
|
|
RAM, it will be hard to attack the machine by manipulating the SRAM supply chain.
|
|||
|
|
The attacker would need to know what I was building, where in the circuit each RAM they
|
|||
|
|
supply would go, when and where I would obtain the components, and how to know whether their
|
|||
|
|
chip went into my computer or someone else's.
|
|||
|
|
An attacker would also typically need access to the tainted components at their point of
|
|||
|
|
use.
|
|||
|
|
I can't tell you that an attacker this sophisticated won't come around, but I suggest that until
|
|||
|
|
transparently functioning SRAM computers are in such widespread use that the number of
|
|||
|
|
targets is large, attacks through the SRAM supply chain will be too expensive compared
|
|||
|
|
to simpler offensives that cost less.
|
|||
|
|
In light of SRAM's characteristics, I decided I would still be interested in building a
|
|||
|
|
transparently functioning computer even if it uses VLSI for primary storage—as long
|
|||
|
|
as it isn't complex VLSI that could easily conceal exploitable defects.
|
|||
|
|
But with SRAM chips now permitted in the bill of materials, a question arises as to whether
|
|||
|
|
SRAM is permissible for storage only, or if it could be used for computing as well.
|
|||
|
|
I estimate that more likely than not, SRAM is actually safer for use in computing logic
|
|||
|
|
than it is for storage.
|
|||
|
|
If SRAM could be used as a logic gate, data passing through that part isn't at rest, it's
|
|||
|
|
just a few bits at a time, not enough bits to identify structure and meaning in.
|
|||
|
|
When I use SRAM to implement CPU logic thus far, no SRAM ever sees more than 6 bits
|
|||
|
|
of data at a time.
|
|||
|
|
That's not even a byte.
|
|||
|
|
Also, consider where an attacker might buffer data for exfiltration.
|
|||
|
|
When an SRAM is used for primary storage, there's lots of room to store and aggregate
|
|||
|
|
information.
|
|||
|
|
But SRAM used as a logic gate doesn't store data—
|
|||
|
|
it only holds firmware.
|
|||
|
|
So let's consider how SRAM can be used to design transparently functioning computers.
|
|||
|
|
In Hacker Public Radio episode 4333, I described a minicomputer with preemptive multitasking,
|
|||
|
|
paged virtual memory, no complex VLSI, and a refreshingly capable instruction set,
|
|||
|
|
and I named this architecture Dauug|36 after its 36-bit word size.
|
|||
|
|
Here again, the spelling is D A U U G.
|
|||
|
|
The CPU, memory subsystem, firmware, and real-time operating system kernel work in
|
|||
|
|
simulation today, but the architecture still needs I/O and initialization that call for
|
|||
|
|
significant logic outside the CPU.
|
|||
|
|
So after a couple false starts designing the missing logic from basic gates and flip-flops,
|
|||
|
|
I decided the way forward is to build in a very small controller that has no complex
|
|||
|
|
VLSI.
|
|||
|
|
I named this smaller architecture Dauug|18 because it can't do as much as Dauug|36, and happens
|
|||
|
|
to use 18-bit words.
|
|||
|
|
Like Dauug|36, Dauug|18 is built principally from two kinds of components.
|
|||
|
|
The simpler kind is basic glue logic from the Advanced Ultra-Low Voltage CMOS family
|
|||
|
|
from Texas Instruments.
|
|||
|
|
These are a modern take on the 7400 series of basic gates—AND, NAND, OR, NOR, XOR,
|
|||
|
|
buffer, inverter, and D flip-flop, and they're insanely fast.
|
|||
|
|
These ICs come in a variety of packages, but to simplify soldering I only use the packages
|
|||
|
|
that have leads.
|
|||
|
|
Most of these chips only operate on a single bit at a time, but the buffers and flip-flops
|
|||
|
|
are available in widths up to 16 bits, which let us direct the flow of data within the
|
|||
|
|
CPU.
|
|||
|
|
There are places in Dauug|18 where buffers need to be installed facing both directions because
|
|||
|
|
data sometimes flows either way.
|
|||
|
|
Conveniently TI sells buffers with an extra pin to specify their direction.
|
|||
|
|
You'd think these are called something natural like "bidirectional buffers," but they're actually
|
|||
|
|
called "bus transceivers."
|
|||
|
|
The name sounds like they do something complex, but instead they're just buffers that pass
|
|||
|
|
bits in either direction.
|
|||
|
|
The other kind of component in Dauug|18 is synchronous static RAM.
|
|||
|
|
The word "synchronous" here means that the SRAMs' input is clocked through D flip-flops.
|
|||
|
|
For read operations, the outputs will be ready five and a half nanoseconds after the clock rises.
|
|||
|
|
I'm going to share specifics about the CPU's bill of materials and topology here because
|
|||
|
|
they directly impact Dauug|18's capabilities and how it's programmed.
|
|||
|
|
This being a radio program, I'll do my best to not lose you in these details.
|
|||
|
|
But if you'd like a visual aid, I've uploaded a PDF with this show, and if you can't find it there,
|
|||
|
|
you can visit 18.dauug.org (that's 1 8 dot D A U U G dot O R G), and you'll find a
|
|||
|
|
PDF link near the bottom of the page.
|
|||
|
|
The Dauug|18 processor contains just six SRAMs.
|
|||
|
|
Each SRAM is 18 bits wide and has 262,144 words of storage,
|
|||
|
|
so their address space is also 18 bits.
|
|||
|
|
It's noteworthy that this capacity is more or less the smallest synchronous RAM on the
|
|||
|
|
market, and we want to use the smallest chips we can because of their lower cost
|
|||
|
|
and smaller firmware size.
|
|||
|
|
Of these six SRAMs, one is data memory.
|
|||
|
|
You more or less know what that does, and one of the architecture's limitations is that
|
|||
|
|
it doesn't support any more data memory than the 256 kibiwords that it comes with.
|
|||
|
|
Fortunately, code goes in a separate SRAM, which means code and data live in separate
|
|||
|
|
18-bit address spaces.
|
|||
|
|
Code is inefficiently stored because Dauug|18 doesn't have a control decoder and doesn't
|
|||
|
|
have any concept of opcodes.
|
|||
|
|
Dauug|36 has both, but Dauug|18 has neither because it's a simpler processor.
|
|||
|
|
Instead, Dauug|18's control signals for each instruction are written directly into words
|
|||
|
|
of the code memory.
|
|||
|
|
Of the code SRAM's 18-bit width, six bits are used to tell the arithmetic logic unit
|
|||
|
|
what it's doing, and the remaining 12 bits are all that are left to control the rest
|
|||
|
|
of the CPU.
|
|||
|
|
So that's two SRAMs out of six: the data memory and the code memory.
|
|||
|
|
The third RAM is called "literal memory" and is wired in parallel lockstep with the
|
|||
|
|
code memory.
|
|||
|
|
This third RAM stores 18 bits of information for every instruction that needs literal data
|
|||
|
|
attached.
|
|||
|
|
So if you need to read from data memory location 1000, the code memory has the control signals
|
|||
|
|
to produce the read, and the literal memory has the address to read from, which in this
|
|||
|
|
case is 1000.
|
|||
|
|
So in effect, Dauug|18 instructions are 36 bits wide, with 18 of those bits being optional
|
|||
|
|
literal data, 12 bits being control signals, and 6 bits telling the arithmetic logic unit
|
|||
|
|
what its function is.
|
|||
|
|
The code and literal data are stored on different chips because the literal output sometimes
|
|||
|
|
has to be turned off to accommodate other signals, while the control output must never
|
|||
|
|
be turned off.
|
|||
|
|
We've knocked out three SRAMs: data memory, code memory control signals, and literal data
|
|||
|
|
attached to these control signals.
|
|||
|
|
There are only three SRAMs left, and they implement the arithmetic logic unit's lowest
|
|||
|
|
six bits, middle six bits, and highest six bits.
|
|||
|
|
So how exactly do we use SRAM to compute?
|
|||
|
|
The answer is we don't actually use SRAM to compute.
|
|||
|
|
Instead, we use SRAM to look up answers we computed previously.
|
|||
|
|
Here's how this works.
|
|||
|
|
Recall that the smallest synchronous SRAMs on the market have 18 address bits, and consider
|
|||
|
|
a sample problem like C = A + B. Since A is on the left side of the expression A
|
|||
|
|
+ B, we call A the left operand, and B the right operand.
|
|||
|
|
If we limit the left operand to 6 bits, it can be an integer between 0 and 63 inclusive,
|
|||
|
|
and we can do the same with the right operand so that it's also an integer between 0 and
|
|||
|
|
63.
|
|||
|
|
And for the moment, let's say that our result of adding A + B wraps around so that C
|
|||
|
|
will fall between 0 and 63.
|
|||
|
|
So to make SRAM into a gate that can compute any 6-bit sum, we'll need a truth table with
|
|||
|
|
a 12-bit address space (that's 4096 rows) where each row is 6 bits wide.
|
|||
|
|
So it's easy for an SRAM to behave like it's adding 6-bit numbers for us; we just have
|
|||
|
|
to store all the sums in advance.
|
|||
|
|
So how do we get the other operations we need, like subtraction, bitwise AND, exclusive OR,
|
|||
|
|
short multiplication, and so on?
|
|||
|
|
Well, our SRAM has 18 address bits, and two 6-bit operands only come to 12 bits, so we
|
|||
|
|
have 6 bits left.
|
|||
|
|
These 6 are our room to say what we want done,
|
|||
|
|
so we can put 64 operations on our menu so to speak.
|
|||
|
|
Maybe operation 0 is addition, operation 1 is subtraction, operation 2 is bitwise AND,
|
|||
|
|
and so on.
|
|||
|
|
We're constrained to limit the number of operations we support to 64 at most, but that's
|
|||
|
|
plenty for our purpose.
|
|||
|
|
You've probably figured out that what I'm describing is something called a bit-sliced
|
|||
|
|
ALU.
|
|||
|
|
Rather than try to compute on 18-bit operands directly, which would take almost 70 billion
|
|||
|
|
words of memory per operation, we split the processor's 18-bit words into 6-bit chunks,
|
|||
|
|
where we only need about 4 thousand words of memory per operation.
|
|||
|
|
If you're having trouble confirming the numbers here, remember that both the left and right
|
|||
|
|
operands need address space, so the difference is between needing 2**36 rows
|
|||
|
|
and 2**12 rows for each operation.
|
|||
|
|
A constraint with bit-sliced arithmetic logic units is that each slice is isolated during
|
|||
|
|
processing.
|
|||
|
|
During addition, carries from bit 5 into bit 6 and bit 11 into bit 12 are lost.
|
|||
|
|
We don't have this problem for bitwise logic such as NOT, NAND, and exclusive NOR, but
|
|||
|
|
tasks such as addition, subtraction, shifts, and rotates need to look across entire words
|
|||
|
|
to obtain their final answer.
|
|||
|
|
How can this constraint be overcome with Dauug|18?
|
|||
|
|
The answer involves three architectural features.
|
|||
|
|
All three are simple, but this is a radio show, so let's try together to build a picture
|
|||
|
|
in our minds.
|
|||
|
|
The first architectural feature for overcoming isolation between bit slices is that each
|
|||
|
|
Dauug|18 ALU operation produces two results instead of one result.
|
|||
|
|
I'll explain in more detail in a moment, but for right now take it on faith that when
|
|||
|
|
an SRAM looks up the 6-bit sum of A and B, it produces two different answers.
|
|||
|
|
The second architectural feature is that wiring exists to scramble the order of the bits in
|
|||
|
|
an 18-bit word.
|
|||
|
|
I use this term wiring very literally.
|
|||
|
|
It's not logic,
|
|||
|
|
it's really just copper.
|
|||
|
|
The third architectural feature is that, unsurprisingly, you can pass any given problem through the
|
|||
|
|
arithmetic logic unit more than once, meaning you can compute the answer for a hard problem
|
|||
|
|
using more than one step.
|
|||
|
|
So let's consider how these three features work together to solve multi-step problems.
|
|||
|
|
Dauug|18 takes a question like C = A + B, looks up small hints about the answer for
|
|||
|
|
each slice separately, shuffles those hints between the slices in some magic way to produce
|
|||
|
|
a new problem that is closer to the final answer, and then feeds the new problem through
|
|||
|
|
the same arithmetic logic unit.
|
|||
|
|
That's the big picture.
|
|||
|
|
Let's go through these features a second time and explain what they mean more fully.
|
|||
|
|
The first feature was that ALU computations produce two results instead of one.
|
|||
|
|
We actually get that for free.
|
|||
|
|
Each SRAM, remember it's the smallest size we can buy, has 18 address bits we use for
|
|||
|
|
input, and 18 data bits we use for results.
|
|||
|
|
But the result computed by each SRAM is only 6 bits, meaning we have 12 bits left over
|
|||
|
|
in every row to use however we need for supplementary results.
|
|||
|
|
So when we compute the 6-bit sum of 10 + 10, the answer is 20 and won't carry into
|
|||
|
|
a 7th bit.
|
|||
|
|
So that SRAM's main output, I actually call it the left output, is 20.
|
|||
|
|
But that SRAM also has a 6-bit right output, and one of those bits is whether or not a
|
|||
|
|
carry occurred, and that bit is zero.
|
|||
|
|
Now suppose we compute the 6-bit sum of 60 + 3.
|
|||
|
|
The answer is 63, which is six ones that go to that SRAM's left output.
|
|||
|
|
Does a carry occur?
|
|||
|
|
Not immediately,
|
|||
|
|
so the carry in the right output is zero.
|
|||
|
|
But there might need to be a carry if the SRAM with the next-lower place value outputs
|
|||
|
|
a carry.
|
|||
|
|
If there's no carry from the right, 63 just stays 63,
|
|||
|
|
but if there's a carry coming in, that 63 wraps around to 0.
|
|||
|
|
That's called carry propagation.
|
|||
|
|
To handle propagation, the SRAM's right output has a bit named propagate alongside its companion
|
|||
|
|
bit named carry.
|
|||
|
|
The propagate bit will be 1 if and only if the local sum is exactly 63, while the carry
|
|||
|
|
bit will be 1 if and only if the local sum is more than 63.
|
|||
|
|
So each 6-bit addition on an SRAM produces two results.
|
|||
|
|
The left result is the 6-bit sum, and the right result has a carry bit and a propagate bit.
|
|||
|
|
We just need to get the carry and propagate bits over to any SRAMs that have greater place
|
|||
|
|
value, and then account for them during a future instruction.
|
|||
|
|
This is where our second architectural feature comes in, specifically, wires that move bits
|
|||
|
|
of an 18-bit word outside of their immediate 6-bit slices.
|
|||
|
|
Recall that each of the three SRAMs in the arithmetic logic unit have a left and right operand.
|
|||
|
|
When given the appropriate control signal within a CPU instruction, a bus transceiver
|
|||
|
|
will feed the ALU's left output (that's the sum) to become the left operand of the next
|
|||
|
|
instruction.
|
|||
|
|
Simultaneously, the ALU's right output (that's the carry and propagate information) are fed
|
|||
|
|
through buffers to become the right operand of the next instruction.
|
|||
|
|
The right operand is actually fed by two buffers, with only one of the buffers active at a time.
|
|||
|
|
One buffer copies the right result straight back to become the next right operand with
|
|||
|
|
no changes.
|
|||
|
|
The other buffer transposes the order of the bits so the 6-bit result from each slice is
|
|||
|
|
distributed two bits at a time into the three SRAMs for the next operation.
|
|||
|
|
The upshot is that after the clock cycle where each 6-bit subword is added separately, on
|
|||
|
|
the next clock every SRAM in the ALU sees the 6-bit sum it just generated as its left
|
|||
|
|
operand, and carry and propagation information for all three subwords as the right operand.
|
|||
|
|
The ALU SRAMs use this information to add any carries that are needed within each subword.
|
|||
|
|
This second pass through the ALU is the third and final architecture feature Dauug|18 uses
|
|||
|
|
to overcome subword isolation.
|
|||
|
|
You may pick up that when an SRAM generates a carry bit in its right output, it has to
|
|||
|
|
supply three copies of the carry bit,
|
|||
|
|
so it can be distributed to all three SRAMs on the
|
|||
|
|
next clock cycle.
|
|||
|
|
For the same reason, it outputs three copies of its propagate bit, so all six bits in the
|
|||
|
|
right result of addition operations have a purposeful use.
|
|||
|
|
As I mentioned, addition is not the only operation to benefit from allowing the ALU to shuffle
|
|||
|
|
a few bits between subwords.
|
|||
|
|
You've probably guessed that subtraction uses the same mechanism, and it also turns out
|
|||
|
|
that shifts and rotates of any number of bits can likewise be done in constant time.
|
|||
|
|
Another operation this bit shuffling enables is population count, sometimes called just
|
|||
|
|
popcount, or sometimes more formally Hamming weight.
|
|||
|
|
Popcount computes the number of 1 bits in a given 18-bit word, and the result can be
|
|||
|
|
as small as 0, when the input word is all zeros, and as large as 18, when the input word is
|
|||
|
|
all ones.
|
|||
|
|
It only takes three clock cycles for Dauug|18's ALU to compute a popcount, although the surrounding
|
|||
|
|
CPU will use a few more clocks to fetch the operand from memory and store the result back.
|
|||
|
|
Another operation that uses few clock cycles in this ALU design is computing hash values
|
|||
|
|
for associative arrays.
|
|||
|
|
This operation is closely related to another task this ALU does in a few clocks, which
|
|||
|
|
is generate pseudorandom numbers that have good statistical properties.
|
|||
|
|
Yet another is arbitrary permutations of the bits in an 18-bit word.
|
|||
|
|
These three operations are efficient because the ALU effectively forms a substitution-permutation
|
|||
|
|
network.
|
|||
|
|
In the substitution step, the three SRAMs replace 6-bit subwords of the left operand
|
|||
|
|
controlled by 6-bit keys in the right operand.
|
|||
|
|
This substitution takes one clock cycle.
|
|||
|
|
In the permutation step, which takes no clock cycle, each subword's output is split three
|
|||
|
|
ways among the subwords of a future right operand.
|
|||
|
|
If you're interested in the general theory of SRAM arithmetic logic units, including
|
|||
|
|
how multiplication and division work without additional hardware, the Dauug|36 documentation
|
|||
|
|
at 36.dauug.org goes into much detail.
|
|||
|
|
Be sure to check out the download section.
|
|||
|
|
That's 3 6 dot D A U U G dot O R G.
|
|||
|
|
And if there's something you can't find or need explained better, I hope you'll drop
|
|||
|
|
me a line.
|
|||
|
|
Since the Dauug|18 virtual machine is pre-alpha and hasn't released any files as of March
|
|||
|
|
2026, I'm probably the only person who's tried to write code for the architecture.
|
|||
|
|
I'm happy to share it's not an easy CPU to write assembly code for.
|
|||
|
|
You might think well, assembly code isn't easy in general, or maybe I'm not good at
|
|||
|
|
writing assembly code.
|
|||
|
|
You're probably right both times, but this is different.
|
|||
|
|
I've written thousands of lines of Dauug|36 assembly code, and I've found Dauug|36 a joy to write
|
|||
|
|
code for.
|
|||
|
|
But Dauug|18 is more contorted to code due to its economy of components and bottlenecks
|
|||
|
|
in data handling.
|
|||
|
|
Here are some of the issues one faces coding for Dauug|18.
|
|||
|
|
First off, the instruction pointer doesn't count linearly.
|
|||
|
|
There's no end-user benefit to ordering the code addresses 0, 1, 2, and so on, and implementing
|
|||
|
|
a linear order would require a counter that doesn't exist as an off-the-shelf component
|
|||
|
|
with the speed and transparency of operation we need.
|
|||
|
|
Dauug|36 manages to count linearly, but it uses a 27-bit incrementer comprising 70 gates that
|
|||
|
|
only work because Dauug|36 can absorb two clock cycles of latency while counting.
|
|||
|
|
In contrast, Dauug|18 has no extra clock cycles for incrementing a counter between instructions.
|
|||
|
|
Both CPUs have a 40 MHz clock, but Dauug|18 pulls 40 MIPS while Dauug|36 only gets 10 MIPS.
|
|||
|
|
Fortunately, there's no technical problem if an instruction pointer counts in a nonlinear
|
|||
|
|
order, as long as it's deterministic and has a long enough period.
|
|||
|
|
The only hardware needed, other than 18 flip-flops that hold the current address, is one XOR gate.
|
|||
|
|
The circuit is called a Galois linear feedback shift register, abbreviated LFSR, and LFSRs
|
|||
|
|
have been used for more than 50 years as a lightweight alternative to linear instruction
|
|||
|
|
counters.
|
|||
|
|
Another issue coding for Dauug|18 is it has no return address stack.
|
|||
|
|
What you ideally want to do is write your program so no subroutines are reentrant.
|
|||
|
|
Then each subroutine can allocate one word of data memory for its return address, and
|
|||
|
|
a caller can save the return address before branching to the subroutine.
|
|||
|
|
When it's time to return, the subroutine can fetch the return address and branch directly
|
|||
|
|
to it.
|
|||
|
|
For subroutines that must be reentrant, you'll need to brute force some kind of return address
|
|||
|
|
stack in software.
|
|||
|
|
Likewise there is no hardware-based stack pointer, so reentrant code (if there is any)
|
|||
|
|
has to do extra work spilling local variables.
|
|||
|
|
This brings up the further limitation that Dauug|18 really has only one address mode for
|
|||
|
|
data memory;
|
|||
|
|
specifically, the memory location being read or written is whatever address happens to
|
|||
|
|
be at node 1 of the circuit board.
|
|||
|
|
Node 1 can be driven by literal data in an instruction, or the most recent data memory
|
|||
|
|
read, or the most recent ALU output, but no further adjustments are made to the address.
|
|||
|
|
If you need an offset from a base pointer, for example, you're going to need to use the
|
|||
|
|
ALU to compute that offset, and I'll point out that this can spill whatever ALU result
|
|||
|
|
you were looking to store in the first place.
|
|||
|
|
If you're familiar with the riddle where a farmer needs to move a wolf, goat, and cabbage
|
|||
|
|
across a river one at a time, that's what Dauug|18 memory handling is like in practice.
|
|||
|
|
It would be different if Dauug|18 had any registers other than the clocked outputs that are inherently
|
|||
|
|
part of the SRAMs that comprise the CPU.
|
|||
|
|
Unfortunately, no. Dauug|18 doesn't have any registers,
|
|||
|
|
that's another limitation that the programmer is called on to overcome.
|
|||
|
|
Another issue is that although most ALU operations are binary in the sense that they combine
|
|||
|
|
two operands, as opposed to unary where only one operand is used, there is no direct access
|
|||
|
|
to supply the ALU with its right operand.
|
|||
|
|
The only place where the right operand electrically reaches the ALU comes from the ALU's own right
|
|||
|
|
output.
|
|||
|
|
This isn't the end of the world, but it adds clock cycles and consumes code memory.
|
|||
|
|
For instance, if you want to add two numbers, you have to first pass the right operand through
|
|||
|
|
the ALU from the left side to the right side, which adds a clock cycle to an already-tricky
|
|||
|
|
addition sequence.
|
|||
|
|
Another issue with Dauug|18 is that it has no freestanding controller for input or output,
|
|||
|
|
nor is it designed to have I/O ports that are wider than perhaps a couple of bits.
|
|||
|
|
On top of all that, all I/O would have to be polled because Dauug|18 has no interrupts
|
|||
|
|
to facilitate transfers.
|
|||
|
|
Another limitation in programming and using Dauug|18 is lack of any mechanism that can programmatically
|
|||
|
|
change code memory.
|
|||
|
|
You can't just launch a program from a command prompt, not unless the program you want already
|
|||
|
|
resides in memory.
|
|||
|
|
The reason this can't work is Dauug|18 doesn't have any microcoding or control decoder, so
|
|||
|
|
the code memory is needed during every clock to control the CPU.
|
|||
|
|
No cycles are left when the code memory is free and can be updated.
|
|||
|
|
One challenge Dauug|18 assembly language programmers will face, and right now there are no other
|
|||
|
|
languages implemented, is the architecture doesn't have any opcodes.
|
|||
|
|
Instead, the language describes a collection of control signals that operate the processor.
|
|||
|
|
The present assembler has rudimental macro support that can somewhat approximate opcodes,
|
|||
|
|
but the strange flows that result from not having any registers make for complex instructions
|
|||
|
|
and an appreciable learning curve.
|
|||
|
|
Dauug|18 is certainly Turing complete and can overcome the aforementioned limitations
|
|||
|
|
if given enough attention and clock cycles, but only within the umbrella of the architecture's
|
|||
|
|
18-bit address space.
|
|||
|
|
Once you're out of code or data memory, neither will expand, and although you could dive into
|
|||
|
|
the tarpit of swapped external pages, the architecture's near-total lack of I/O support
|
|||
|
|
make swapping even less realistic than it was on historic architectures.
|
|||
|
|
The problem is even more acute for code memory, which stores programs inefficiently and can't
|
|||
|
|
be changed at all by the CPU.
|
|||
|
|
So with all these constraints imposed on programming and use, is Dauug|18 a lost cause?
|
|||
|
|
I certainly don't think so.
|
|||
|
|
In fact, Dauug|18 is on track to be the world's most advanced transparently functioning computer
|
|||
|
|
when its first prototype is built.
|
|||
|
|
Here is a machine that's entire operation is determined by open-source firmware and
|
|||
|
|
a builder's soldering.
|
|||
|
|
No "black box" parts at all, yet a footprint the size of a postcard.
|
|||
|
|
Its 18-bit address space might sound small if you're very young, but I was once an MS-DOS
|
|||
|
|
power user, and 256K is more than most people realize, especially when an architecture has
|
|||
|
|
18-bit bytes instead of 8-bit bytes.
|
|||
|
|
And remember that code for your programs doesn't count against the 256K limit for data.
|
|||
|
|
And in terms of my need—a coprocessor to load firmware and handle I/O for Dauug|36, Dauug|18
|
|||
|
|
checks my boxes about perfectly.
|
|||
|
|
It's also hard for me to ignore Dauug|18's potential as an educational tool that implements an
|
|||
|
|
entire architecture succinctly, transparently, and uniquely.
|
|||
|
|
I've stressed on this show that Dauug|18 is missing a lot in terms of functionality, but it's
|
|||
|
|
also missing a lot of headaches.
|
|||
|
|
There's no dynamic RAM at all, so there are no RowHammer-like vulnerabilities.
|
|||
|
|
There's no VLSI complex logic except in peripherals you choose to attach
|
|||
|
|
that could hide exploitable defects.
|
|||
|
|
There's no writable CPU persistent state;
|
|||
|
|
the only state that survives a power cycle is its open-source firmware.
|
|||
|
|
There's no electrical path for the CPU to modify its code memory, strongly reducing
|
|||
|
|
an attacker's options for injecting code.
|
|||
|
|
There's no CPU microcode to poison, and the CPU's only firmware is a completely disconnected
|
|||
|
|
set of one-clock-cycle ALU operations that occur only in the order specified by a running
|
|||
|
|
program.
|
|||
|
|
Even this firmware can't be modified without physical access to the machine.
|
|||
|
|
Dauug|18's clock is generated by a crystal oscillator directly, not a micro-electromechanical system
|
|||
|
|
with a programmable frequency synthesizer.
|
|||
|
|
MEMS oscillators are very popular now, but they create opportunities for age-selected
|
|||
|
|
and frequency-selected attacks that simple crystal oscillators aren't vulnerable to.
|
|||
|
|
Because the Dauug|18 firmware uses a substitution-permutation network to produce pseudorandom
|
|||
|
|
numbers and associative array hashes, there are S-boxes in the firmware, but unlike some
|
|||
|
|
of history's notorious ciphers where S-boxes were manipulated, Dauug|18's S-boxes have no
|
|||
|
|
unexplained constants.
|
|||
|
|
Instead, they're extracted from the square root of two using 29 lines of Python, and no
|
|||
|
|
imported modules whatsoever. Even from the Python standard library.
|
|||
|
|
No one has any unfair or unlevel knowledge of how Dauug|18's S-boxes work.
|
|||
|
|
All Dauug|18 components are hand-solderable and can be probed after assembly to confirm that
|
|||
|
|
all connections match the open-source netlist.
|
|||
|
|
There is no secret functionality, no vendor lock-in, no encrypted or closed-source firmware,
|
|||
|
|
no license fees to build, use or modify the machine, no purpose-of-use limitations,
|
|||
|
|
no proprietary components to be discontinued without substitutes, no planned obsolescence,
|
|||
|
|
and no right-to-repair infringements.
|
|||
|
|
You can learn more about Dauug|18 and Dauug|36, including how to support both projects, at
|
|||
|
|
dauug.org, spelled D A U U G dot O R G.
|
|||
|
|
My name is Marc Abel, spelled MARC : ABEL.
|
|||
|
|
Thank you for listening.
|
|||
|
|
You have been listening to the Hacker Public Radio podcast, at hackerpublicradio.org.
|
|||
|
|
Today's show was contributed by a HPR listener like yourself.
|
|||
|
|
If you ever thought of recording a podcast, then visit the HPR site to find out how easy it really is.
|
|||
|
|
Hosting for HPR has been kindly provided by anhonesthost.com, the Internet Archive, rsync.net, and the HPR Community Content Delivery Network.
|
|||
|
|
Unless otherwise stated, today's show is released under a Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.
|