
Beetle Bailey – Thu, September 24, 2026
Source: Beetle Bailey
Speed and availability, paid for in consistency
Replicas and caches put data closer to readers and survive failures, but every extra copy can lag behind the source of truth. The real question is how stale a read the product can tolerate.
Source: Hacker News
Conway’s Game of Life running directly from a 512-byte x86 boot sector, using VGA memory as the simulation grid.
Usage • Why • Contributing • Author
To build and run bootlife you need:
Use the following commands to run it:
nasm -f bin -o life.img life.asm
qemu-system-i386 -drive file=life.img,format=raw,if=floppy
Or just:
make run
Just for fun 💾
Bug reports and pull requests are welcome – see CONTRIBUTING.md.
Source: Hacker News
I’ve spent the last few weeks working with the security architecture of the
nRF54L series from Nordic
Semiconductor (in case you missed it, I recently
joined Nordic!).
While doing so, I have engaged my typical low-level learning technique of
eschewing writing firmware for manually poking at registers using the debugger.
A few nights ago I found myself observing unexpected values in memory when
working with the key management unit. It turned out to be a familiar issue, but
one that requires an understanding of the internal system on chip (SoC)
components, and how the debugger interacts with them, to diagnose.
For a bit of background, the nRF54L series has a fairly advanced set of security
capabilities, headlined by Arm
TrustZone support in
the Cortex-M33
core, a
CRACEN cryptographic
accelerator,
and a Key Management Unit
(KMU). The
KMU is used for storing sensitive data, such as key seeds and associated
metadata, in the Secure Information Configuration Region
(SICR).
The SICR is divided into slots. These slots are targeted by issuing tasks to the
KMU, which can only be accessed in secure mode. Typically, application firmware
doesn’t interact with the KMU directly. Instead, PSA
drivers are implemented
to abstract the generation, storage, and usage of keys. For example, if
invoking
psa_generate_key(),
the operation eventually results in a call to
import_key_for_kmu()
in the CRACEN PSA
driver.
static psa_status_t import_key_for_kmu(const psa_key_attributes_t *attributes, const uint8_t *data,
size_t data_length, uint8_t *key_buffer,
size_t key_buffer_size, size_t *key_buffer_length,
size_t *key_bits)
{
size_t opaque_key_size;
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
int slot_id =
CRACEN_PSA_GET_KMU_SLOT(MBEDTLS_SVC_KEY_ID_GET_KEY_ID(psa_get_key_id(attributes)));
psa_key_attributes_t stored_attributes;
status = cracen_get_opaque_size(attributes, &opaque_key_size);
if (status != PSA_SUCCESS) {
return status;
}
if (key_buffer_size < opaque_key_size) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
status = cracen_kmu_provision(attributes, slot_id, data, data_length);
if (status != PSA_SUCCESS) {
return status;
}
status = cracen_kmu_get_builtin_key(slot_id, &stored_attributes, key_buffer,
key_buffer_size, key_buffer_length);
if (status != PSA_SUCCESS) {
return status;
}
*key_bits = psa_get_key_bits(&stored_attributes);
return status;
}
A slot can either be erased, provisioned, or revoked. The
datasheet
includes a helpful diagram of the state machine.
Slots have an ID (0 – 249) and can store metadata (32 bits), a destination
address (32 bits), a value (128 bits), and a revocation policy (2 bits). The
latter determines how state changes when a key is in the provisioned state and
various tasks that reference its slot ID are issued to the KMU. When
experimenting with the KMU, it is easiest to use the ROTATING revocation
policy, which dictates that the slot transitions back to the erased state when a
revoke task is issued.
When the PUSH task is issued, the value in the slot is written to the
destination address that was specified when the key was provisioned. The
provisioning process is documented in the
datasheet,
but it can also be seen in the cracen_kmu_key_slot_provision()
implementation:
static int cracen_kmu_key_slot_provision(const nrfx_kmu_key_slot_data_t *key_slot_data,
uint32_t slot_id)
{
int kmu_status;
uint8_t orig_write_buf_size;
cracen_kmu_key_slot_provision_write_enable_set(true, &orig_write_buf_size);
kmu_status = nrfx_kmu_key_slot_provision(key_slot_data, slot_id);
cracen_kmu_key_slot_provision_write_enable_set(false, &orig_write_buf_size);
return kmu_status;
}
The nrfx_kmu_key_slot_data_t definition can be found in the Nordic Zephyr
Hardware Abstraction Layer
(HAL).
typedef struct __PACKED
{
uint32_t keyslot_value[KEY_SLOT_WORDS_COUNT]; ///< Key data to be provisioned.
#if NRF_KMU_HAS_REVOKE_POLICY || defined(__NRFX_DOXYGEN__)
uint32_t revoke_policy; /**< Key revoke policy.
* @ref nrfx_kmu_rpolicy_t
* holds possible values. */
#endif
uint32_t keyslot_dest; /**< Key slot destination when
* performing key push. */
#if NRF_KMU_HAS_METADATA || defined(__NRFX_DOXYGEN__)
nrfx_kmu_key_slot_metadata_t metadata; ///< Metadata to write to keyslot.
#endif
} nrfx_kmu_key_slot_data_t;
You could write some fairly straightforward firmware, or even use the CRACEN
KMU
sample,
build it, then flash it onto a development kit to easily provision a key to the
KMU. However, if using the supported drivers (which you absolutely should),
additional restrictions are placed on the values that you can use when
provisioning a key slot. For example, while the KMU supports any 32 bit value
for metadata, the PSA driver assigns
meaning
to each of the bits.
typedef struct kmu_metadata {
uint32_t metadata_version: 4;
uint32_t key_usage_scheme: 2;
uint32_t reserved: 8;
uint32_t algorithm: 6;
uint32_t size: 3;
uint32_t rpolicy: 2;
uint32_t usage_flags: 7;
} kmu_metadata;
Similarly, there are restrictions on the values that you can write and the
destination to which a given type of key is pushed. If manually interacting with
the KMU, the metadata, value, and destination are much more flexible. However,
if you provision non-conformant data into slots in the KMU, then attempt to
interact with it using the supported drivers, you are going to have a bad time.
Knowing the risks, and that I could restore the SICR on nRF54LM20
DK with
an
ERASEALL
operation on the control access port
(CTRL-AP),
I had powered up the board and connected with
GDB. As previously mentioned, the
KMU can only be accessed in secure mode. However, when access port protection
is not
enabled,
the Secure Privileged Invasive Debug Enable
(SPIDEN)
signal is driven high, and the on-board J-Link debugger (J-Link
OB) can
operate with secure privileges.
With the CPU halted, I tested that I was able to access the KMU and determined
that it was ready for operations by reading from the STATUS
register
(0x50049400).
(gdb) x/1xw 0x50049400
0x50049400: 0x00000000
To test the actual functionality, I followed the
provisioning
and
push
steps described in the datasheet. The first step was to build the SRC data
structure in memory, which is of the format specified in the packed
nrfx_kmu_key_slot_data_t struct definition. To make testing multiple values
simpler, I wrote a tiny Python script to build the struct.
import struct
open("kmu_src.bin", "wb").write(
bytes.fromhex("abc123abc123abc123abc123abc123ab") # Value
+ struct.pack(
"<III",
3, # Revocation Policy
0x20000000, # Destination Address
0xDEF678DE, # Metadata
)
)
The produced kmu_src.bin contained the following contents.
xxd kmu_src.bin
00000000: abc1 23ab c123 abc1 23ab c123 abc1 23ab ..#..#..#..#..#.
00000010: 0300 0000 0000 0020 de78 f6de ....... .x..
To write the data to memory, I used the GDB restore command.
(gdb) restore kmu_src.bin binary 0x20001000
The next step was to write the address of the struct (0x20001000) to the KMU
SRC
register
(0x50049504) and specify the desired key slot (9) in the KEY_SLOT
register
(0x50049500).
(gdb) set *(unsigned int*)(0x50049504) = 0x20001000
(gdb) set *(unsigned int*)(0x50049500) = 9
Before actually issuing the task, the resistive random access memory controller
(RRAMC)
must be configured to allow unbuffered writes. I stored the current RRAMC
CONFIG
register
(0x5004e500) in a variable to be restored after completion of the task, then
wrote the value 1, which sets write enable (WEN) field to 1 and the buffer
size (WRITEBUFSIZE) to 0 (unbuffered).
(gdb) set $rramc_config = *(unsigned int*)(0x5004e500)
(gdb) set *(unsigned int*)(0x5004e500) = 1
Finally, I wrote 1 to the TASKS_PROVISION
register
(0x50049000), instructing the KMU to store the value and its metadata in key
slot 9. I verified the event was generated by subsequently reading the
EVENTS_PROVISIONED
register
(0x50049100).
(gdb) set *(unsigned int*)(0x50049000) = 1
(gdb) x/1wx 0x50049100
0x50049100: 0x00000001
With the task completed, I then reset the RRAMC CONFIG register.
(gdb) set *(unsigned int*)(0x5004e500) = $rramc_config
These exact operations can also be seen in the CRACEN PSA
driver’s
cracen_kmu_key_slot_provision() and the underlying
nrfx_kmu_key_slot_provision()
function.
static int cracen_kmu_key_slot_provision(const nrfx_kmu_key_slot_data_t *key_slot_data,
uint32_t slot_id)
{
int kmu_status;
uint8_t orig_write_buf_size;
cracen_kmu_key_slot_provision_write_enable_set(true, &orig_write_buf_size);
kmu_status = nrfx_kmu_key_slot_provision(key_slot_data, slot_id);
cracen_kmu_key_slot_provision_write_enable_set(false, &orig_write_buf_size);
return kmu_status;
}
int nrfx_kmu_key_slot_provision(nrfx_kmu_key_slot_data_t const * p_key_slot_data, uint32_t slot_id)
{
NRFX_ASSERT((m_cb.state == NRFX_DRV_STATE_INITIALIZED) &&
(p_key_slot_data) &&
(slot_id < KMU_KEYSLOTNUM));
bool is_ready = false;
NRFX_WAIT_FOR(nrf_kmu_status_get(NRF_KMU) == 0, 500, 10, is_ready);
if (!is_ready)
{
return -EAGAIN;
}
nrf_kmu_src_set(NRF_KMU, (uint32_t)p_key_slot_data);
nrf_kmu_keyslot_set(NRF_KMU, slot_id);
nrf_kmu_task_trigger(NRF_KMU, NRF_KMU_TASK_PROVISION_KEYSLOT);
return wait_for_task_result(NRF_KMU_EVENT_EVENTS_PROVISIONED);
}
The push operation is significantly simpler, only requiring that the desired
slot be configured in the KEY_SLOT
register,
and the task be triggered by a write to the TASKS_PUSH
register
(0x50049004).
(gdb) set *(unsigned int*)(0x50049500) = 9
(gdb) set *(unsigned int*)(0x50049004) = 1
Similarly to the provision operation, I then checked the EVENTS_PUSHED
register
(0x50049104) to ensure the operation was successful.
(gdb) x/1wx 0x50049104
0x50049104: 0x00000001
With the EVENTS_PUSHED register indicating a successful operation, I finally
checked the destination address (0x20000000) that I had specified in the SRC
struct, which I expected to now hold the value.
(gdb) x/4wx 0x20000000
0x20000000: 0xab23c1ab 0xc1ab23c1 0x23c1ab23 0xab23c1ab
Pleased that I had successfully completed the operation, I attempted to repeat
the sequence of steps, this time using key slot 10 instead of 9, and 16
bytes of a def456 sequence instead of abc123 as the value. I issued the same
4 word read on 0x20000000 because I had reused the same destination address in
slot 10 as I had in slot 9. To my surprise the contents still matched the
previous value.
(gdb) x/4wx 0x20000000
0x20000000: 0xab23c1ab 0xc1ab23c1 0x23c1ab23 0xab23c1ab
This seemed rather peculiar, and my initial assumption was that I must have
missed a step when repeating the operation. However, no matter how many times I
attempted to push to same address (0x20000000), the value remained the same.
After erasing the device, I observed that the first push would correctly update
the value at the destination address, while subsequent pushes would not.
While astute readers may already be smelling a stale cache, it is worth taking a
step back and examining the debug architecture of the nRF54LM20. Like most Arm
systems, it implements to the Arm Debug Interface
(ADI), specifically leveraging
the Arm CoreSight SoC-400
implementation. It has three access ports: two standard
AHB-AP
and one custom CTRL-AP. The first AHB-AP is used to communicate with the main
Cortex-M33 CPU, while the latter is used for accessing auxiliary units,
specifically the RISC-V VPR
coprocessor. The
aforementioned CTRL-AP enables a small subset of functionality that is typically
leveraged in a scenario in which the AHB-APs have been disabled (i.e. access
port protection is enabled).
In order for GDB to interact with the J-Link OB, it needs something to translate
between the commands it supports and those supported by the underlying debugger.
JLinkGDBServer
plays that role when working with J-Link debuggers. GDB effectively acts as a
consistent interface to heterogeneous backends, so when you want to read the
contents of a given memory address, you can use the same command whether you are
debugging a microcontroller or a process on your local development machine.
You can also issue commands directly to the GDB server implementation using the
the GDB monitor command. For example, JLinkGDBServer supports a ReadMemAP
command, which allows you to
directly specify the access port to target, the memory address, the number of
items, and a set of flags. Suspecting that my push operations may be succeeding,
but my reads returning stale values, I issued a ReadMemAP command with the
same parameters as my GDB memory read commands.
(gdb) monitor ReadMemAP 0x0 0x20000000 4 0
O.K.:0xDE56F4DE,0xF4DE56F4,0x56F4DE56,0xDE56F4DE
Sure enough, reading directly from the AHB-AP showed the expected value.
Furthermore, after issuing the read, subsequent examine (x) commands from GDB
continued to return stale values. GDB and JLinkGDBServer communicate using the
GDB Remote Serial Protocol
(RSP),
and the specific packets transmitted between them can be observed by enabling
remote debug logging.
(gdb) set debug remote 1
Given the observed behavior, I suspected that the two different memory read
strategies used different RSP packets. This was confirmed after issuing commands
with the debug logging enabled.
(gdb) x/4wx 0x20000000
[remote] Packet received: b??}03?
0xab23c1ab [remote] Sending packet: $x20000004,4#5e
[remote] Packet received: b?}03??
0xc1ab23c1 [remote] Sending packet: $x20000008,4#62
[remote] Packet received: b}03??}03
0x23c1ab23 [remote] Sending packet: $x2000000c,4#8d
[remote] Packet received: b??}03?
0xab23c1ab
(gdb) monitor ReadMemAP 0x0 0x20000000 4 0
[remote] Sending packet: $qRcmd,526561644d656d415020307830203078323030303030303020342030#a0
[remote] Packet received: 4f2e4b2e3a307844453536463444452c307846344445353646342c307835364634444535362c307844453536463444450D0A
O.K.:0xDE56F4DE,0xF4DE56F4,0x56F4DE56,0xDE56F4DE
In fact, the ReadMemAP command is passed hex encoded directly to
JLinkGDBServer using a qRcmd (remote command query) packet.
echo 526561644d656d415020307830203078323030303030303020312030 | xxd -r -p
ReadMemAP 0x0 0x20000000 4 0
The question of why JLinkGDBServer opted to return stale values for one read
and not the other remained. Though the documentation on JLinkArm.dll, the
underlying library that most J-Link tooling depends on, is fairly light, there
is a list of supported command
strings that gives a clue as to
its internal caching behavior. Specifically, the SetEnableMemCache
command is
defined as controlling memory caching mechanisms, and is on by default. There is
even a somewhat ominous note about turning it off.
This command may not be used by any IDE, listed as a supported IDE, to disable
memory cache mechanisms by default. It may only be used by specific customers
for very specific test cases that needs the cache mechanisms to be disabled.
Eager to observe if disabling the memory cache actually resulted in fresh values
being returned when issuing examine commands, I once again erased the device and
connected GDB. Before performing any operations, I disabled the memory cache.
(gdb) monitor exec SetEnableMemCache = 0
Running through the provision and push operations for the first slot, I observed
the expected value as before. Then on the second provision and push, the examine
command finally returned the updated value.
(gdb) x/4wx 0x20000000
0x20000000: 0xde56f4de 0xf4de56f4 0x56f4de56 0xde56f4de
However, as the J-Link documentations states, you typically do not want to turn
off caching. The reason why the JLinkArm.dll memory cache returns stale values
in this case is because the CPU is halted and we are attempting to read from a
memory address that we have already accessed without advancing the CPU. With the
memory cache enabled, advancing the CPU a few instructions (stepi) results in
the cache being cleared and a fresh value being returned on the next read.
Outside of use cases where a peripheral, such as the nRF54LM20’s KMU, has
direct memory access (DMA)
and can write while the core is halted, you typically won’t encounter issues
with stale debugger memory cache values. In the event that you do, it can be
helpful to understand the underlying bus architecture and how to bypass the
cache by reading directly from an access port.
Source: Hacker News
July 15, 2024KUBIC is a Nintendo-themed, 3D Printable Mini-ITX case
September 05, 2017Choosing the right DC-DC PSU
August 27, 2015AMD's Project Quantum
August 13, 2015The Redstone PC is the ultimate Mini-ITX Minecraft Machine
October 09, 2014The "Restomod TV"
April 09, 2013Installing NAS4Free
February 28, 2013Building an XBMC 12 Home Theatre PC
January 25, 2011XBMC Guide updated to version 10.0
August 06, 2010Building a Green PC
February 15, 2010Building an ION powered HTPC with XBMC
October 10, 2008The "Cambridge Autonomous Underwater Vehicle 2008"
September 12, 2008"Florian", the DVD burning robot
September 05, 2008The "i-EPIA"
January 19, 2007The "ITX-Laptop"
December 07, 2006The "Tortoise Beetle"
October 02, 2006The "DOS Head Unit"
August 31, 2006The "Janus Project"
June 26, 2006Nano-ITX in a Football
May 17, 2006The "EPIA Alloy Mod"
April 11, 2006Neatorama's Collection of Case Mods
February 18, 2006The "Rundfunker"
August 05, 2005The "Waffle Iron PC"
July 21, 2005The "Supra-Server"
July 07, 2005The "Encyclomedia"
May 25, 2005The "Accordion ITX"
May 16, 2005The "FileServerRouterSwitch"
January 30, 2005First Nano-ITX Project?
January 15, 2005The "Gumball PC"
December 15, 2004The "Deco Box"
December 03, 2004The "TERA-ITX"
October 06, 2004The "Coealacanth-PC"
September 17, 2004The "Gramaphone-ITX-HD"
August 26, 2004The "C1541 Disk Drive ITX"
August 13, 2004The "Quiet Cubid"
July 14, 2004The "Moo Cow Moo"
Full alphabetical archive on right hand side of page…
I needed a small Windows XP machine and a Mini-ITX board was the obvious choice. So I decided to build my "Windows XP Box" in a Windows XP box. The external dimensions of the box are a tiny 243mm x 200mm x 48mm.
Fortunately there is no longer any requirement for an internal floppy drive. That would have have defeated me.
The bits arrive and it looks like an impossible task, with too many bits to fit in a small space.
I nearly gave up and decided it was an impossible task. The Windows XP box was 3mm thinner and 12 mm narrower than the Adobe Acrobat box I had measured up when first deciding if the project was going to be possible. The challenge was to arrange the components into a 3D jigsaw, then decide how to build enough of an internal support case to get everything to stay in place.
Eventually it looked like I might have a possible layout, but the tolerances were tight. I had 6mm to spare on the long internal dimension of the box and only 3mm to spare on the thickness of the box, and this was not allowing for any thickness for the internal support case that holds everything in place.
In order to mount all the bits I was going to have to make an inner support case that would tightly slide into the cardboard box. I chose Wonderboard plastic as my construction material because it is reasonably strong and very easy to work with (it cuts with a Stanley knife). It would have been nice to use aluminium, but the cramped design made the chances of a short circuit too great.
The first construction step was to cut out a base plate the exact size of the inside of the cardboard box and double check where the bits will fit.
As the Wonderboard was 3mm thick this reduced my tolerance in two dimensions to zero. The CD drive would touch one side of the inner support case. The deep part of the CD drive would touch the heat sink on the motherboard, with the narrow bit being able to overlap it, and the far side of the motherboard touches the other side of the Wonderboard case. In the other dimension it was even harder. The top of the sound connector would touch the support case, and the underside of the motherboard would touch the cardboard box. Fortunately the hard drive can slide under the motherboard as this is above (below?) the unused PCI slot. The only place left for the PSU was above the hard drive with the bulky connectors facing down towards the CD both to the front and the back of the hard drive.
Now I could position the CD drive hard against the side and start assembling the support case. In the next picture you can see the step up between the thin part of the CD drive and the thicker part of the main body of the drive. The heat sink on the Mini-ITX board touches this step.
After much cutting and half a tube of glue the case was finished. I built pillars to support three corners of the motherboard and the power supply and added brackets to support the CD and the hard drive. In such a compact design cooling was a concern so I made fan mounting points in opposite corners of the case. To keep the CPU nice and cool I cut a hole for it it the side of the case and glued in a couple of plates to act as ducting so the CPU fan will only suck in cold outside air. The other two fans are the exhaust points. The fan guards were cut out of a metal speaker grill using an angle grinder as neatly drilling that many holes is just not fun. Angle grinders are almost as much fun to use as chain saws.
Accordion-ITXAircraft CarrierAmbulator 1AMD CaseAmmo BoxAmmo TuxAmmoLANamPCAnimal SNESAtari 800 ITXAttache ServerAunt Hagar's Mini-ITXBantam PCBBC ITX BBender PCBiscuit Tin PCBlue PlateBlueBoxBMW PCBorg ApplianceBriefcase PCBubbacompC1541 Disk DriveC64 @ 933MHzCardboardCubeCAUV 2008CBM ITX-64Coelacanth-PCCool CubeDeco BoxDevilcatDOS Head UnitDreamcast PCE.T.PCEden VAXEdenStation IPXEncyclomediaFalcon-ITXFlorianFrameFS-RouterSwitchG4 Cube PCGasCan PCGingerbreadGramaphone-ITX-HDGTA-PCGuitar PCGuitar WorkstationGumball PCHirschmannHTPCHTPC2Humidor 64Humidor CLHumidor IIHumidor MHumidor PCHumidor VI.C.E. Uniti64XBOXi-EPIAiGrillITX HelmetITX TVITX-LaptopJeannieJukebox ITXKiSA 444K'nex ITXLeela PCLego 0933 PCLegoboxLog Cabin PCLunchbox PCMac-ITXManga DollMantle RadioMediaboxMega-ITXMicro TVMini FalconMini Mesh BoxMini-ClusterMobile-BlackBoxMoo Cow MooMr OMNINAS4FreeNESPCOpenELECOsh KoshPet ITXPictureframe PCPlaystation 2 PCPlaystation PCProject NFFPSU PCQuiet CubidR2D2PCRacing The LightRadioSphereRestomod TVRobotica 2003RundfunkerSaturnPCS-CUBESEGA-ITXSpaceCaseSpacePanelSpartan BluebirdSpider CaseSupra-ServerTeddybearTelefunken 2003TERA-ITXThe ClockToAsTOrTortoise BeetleTux ServerUnderwood No.5Waffle Iron PCWindows XP BoxWraith SE/30XBMC-ION
Privacy Policy & Cookie Statement | Terms & Conditions | Contact Us | © Mini-ITX.com 2002-
Source: Hacker News
Warren Zevon appeared on The Late Show with David Letterman in October of 2002.
I drew my remembrance of the appearance below. (Apologies to Dave, who has been rendered here in a way that kind of makes him look like Richard Nixon. This was not intentional, but here we are. I’m still learning.)
Zevon had appeared on Letterman’s show many times through the years …
… but this time was different. Zevon knew he was going to die.
He was walking through the final days of a diagnosis with terminal cancer.
What could’ve been deeply unsettling instead became something deeply compelling. Something that has remained with me for years. The two talked about music and family, but also life and death. It was all somehow beautiful and human and … also funny and incredibly moving. All at once.
This part of their exchange has stuck with me probably every day since:
Dave: From your perpsective now, do you know something about life and death that maybe I don’t know now?
Warren: Not unless I know how much … how much you’re supposed to enjoy every sandwich.
Warren:
You put more value on every minute. You do. I mean I always thought I kind of did that. I really always enjoyed myself, but it’s more valuable now. You’re reminded to enjoy every sandwich and every minute of playing with the guys and being with the kids and everything.
I’d just finished re-reading (this time listening) to Jason Zinoman’s book on Letterman. My Youtube algorithm has been, wonderfully, feeding me classic Letterman clips. Last week, this clip snuck up on me from a different angle (and this time with an actual sandwich in my hand).
During a quick layover on my way home from a speaking engagement, I was sitting in a terminal. Traveling from Canada to Nashville. Happy to have had the work. Grateful for the experience. Anxious about upcoming work. Tired. Worried about all sorts of things. Laughing at a picture Kristi sent me from the kids. Hungry.
I bought a sandwich.
It was not a great sandwich.
Soggy and overpriced and maybe “food’“? (not sure) … it was what was available.
I thought of Warren’s words. It hit me that maybe he didn’t necessarily mean every sandwich is going to actually be great. Some sandwiches are bad. They just are. Some days will be a challenge, too. There will be disappointments. Hurts. Things that simply aren’t at all what we hoped they would be.
I don’t think the answer is to pretend everything is wonderful.
Maybe I’ve been hearing Zevon’s words a little differently lately. Against the backdrop of lots of good, but so many uncertainties and challenges, I find myself forgetting the point.
The goal might not be to exactly enjoy every sandwich. Some sandwiches are just straight up trash. Maybe the goal is to notice that you’re eating one.
That’s enough.
Life is strange. Twenty-four years ago a dying rock-and-roll star said something weird and funny on television. Last week I was in an aiprort eating a bad sandwich wondering if maybe I’ve finally understood what he meant.
Take a bite. Taste it. You’re here.
1. hire me to speak.
2. buy a book.
3. send this to a friend.
Source: Hacker News
In my 2023 article on the evolution of the calculator, I griped about the way we teach the history of computers. I felt that we’re giving far too much credit to Charles Babbage. We have known how to make mechanical calculators at least since the 17th century; the concept of programmable machinery predated the English polymath’s writings by a wide margin, too. The remaining bottleneck was mostly technological: past a very modest scale, sprockets and cams made it too cumbersome to shuffle data back and forth inside a sufficiently complex computing machine.
The breakthrough was an electronically-controlled data register. These circuits allowed computation results to be locked in place and then effortlessly routed where needed, no matter how complex and sprawling the overall design. In contrast to the musings of Mr. Babbage, the history of this “working memory” has gotten less attention than it deserves. We conflate it with the evolution of bulk data storage and computer I/O and keep forgetting that RAM constraints were the most significant drag on personal computing until the final years of the 20th century.
The first practical form of electronic memory was a relay. A relay is essentially a mechanical switch actuated by an electromagnet. Its switching action can be momentary — lasting only as long as the electromagnet is powered — or it can be sustained, latching in the “on” state until a separate “reset” coil is energized.
Latching relays can be used to store bits in a fairly obvious way; a momentary relay can also be wired to latch by having the relay supply its own power once the contacts are closed. A simple illustration of this principle is shown below:
In this circuit, pressing the “set” button will energize the relay, therefore also closing the parallel relay-actuated switch. The current will continue flowing through this path even after the “set” button is released. To unlatch the circuit, the normally-closed (NC) “reset” button must be pressed to interrupt the flow of electricity.
Relay-based main memory featured prominently in what was probably the first true electronic computer, Konrad Zuse’s Z3:
Electromechanical relays have switching speeds measured in tens of hertz; Mr. Zuse understood from the get go that the technology is a dead end. He took the expedient path in hopes of securing longer-term funding from the Nazi regime. Unfortunately for him — and fortunately for much of Europe — the officials were unimpressed and the funding never came through.
Zuse’s counterparts on the Allied side had more luck: early successes in codebreaking allowed them to pursue more costly and complicated vacuum tube designs. The blueprint for a tube-based memory cell came from William Eccles and Frank Wilfred Jordan — a largely-forgotten duo of British inventors who proposed the following bistable circuit as a replacement for an electromechanical relay:
The circuit latches when an input current flows through the transformer winding on the left. This momentarily makes the G1 grid voltage more positive, upsetting the current balance between the tubes in a self-reinforcing feedback loop.
In modern terms, both of these circuits would be described as set-reset (SR) latches. Their fundamental operation is shared with the cells that make up high-speed, low-power SRAM memories found on the dies of most microcontrollers and microprocessors today. A contemporary textbook example of an SR architecture could be this:
To analyze the circuit, let’s consider what happens if the “reset” line is high. In this scenario, one input of the AND gate is always zero, so the circuit outputs “0” no matter what’s happening on the OR side.
Conversely, if “reset” is low, the AND gate works as a pass-through for the OR. As for the OR itself, if “set” is high, it unconditionally outputs “1”. But if “set” is not asserted, the OR passes through the circuit’s previous output value via the feedback loop on top of the schematic. In effect, at S = R = 0, the device is latched and stores a single bit of data representing what previously appeared on the S and R input lines.
We could wrap up here, except for one tiny detail: most vacuum tube computers did not use vacuum tube memory for the bulk of their needs. The reason is clear if we consider that the memory unit in Zuse’s Z3 required about 2,000 relays, compared to 600 for the rest of the machine. The math for the relatively costly tubes was even worse, and that’s before we consider that each tube needed substantial, constant power for the heater filament. In short, until the advent of large-scale integration (LSI) chips in the mid-1970s, main memory usually had to be done some other way.
The solution to this problem were “dynamic” memories that relied on relatively short-lived physical phenomena — say, static electricity or acoustics — to store information in an inexpensive medium. Because the underlying physical process lasted only a brief while, the data had to be regularly retrieved and refreshed (or retransmitted) again.
One of the earliest examples of this was the Atanasoff-Berry “computer” (ABC) — in reality, a sophisticated but non-programmable calculator that used a spinning drum with an array of mechanically-switched capacitors:
The charge state of each capacitor conveyed digital information; the gradual self-discharge of the cells necessitated regular refresh. This was, in many respects, the precursor to modern-day DRAM. The DRAM chips in our desktop computers and smartphones still use capacitors; we just make them in bulk on a silicon die and have a way to address them electronically. Although this type of memory is slower and more power-hungry than SRAM, the enduring advantage of DRAM is that it requires far fewer components — and thus, less die space — per every bit stored.
But back to early computing: another fascinating incarnation of the idea were delay-line memories. These devices encoded data as sound waves pumped into a length of material and then sensed on the other side. Because sound takes time to propagate, some number of bits could be “stored” in flight in an electro-acoustic loop. The main advantage was that sound waves propagate pretty briskly, so the latency of this system was far better than that of a spinning capacitor drum.
The wackiest example of this genre is the mercury delay line. As the name implies, these devices relied on the toxic metal as the medium for sound waves:
Wikipedia will tell you that mercury was chosen because it uniquely matched the acoustic impedance of piezoelectric transducers, but I think that’s a misreading of the original patent (US2629827A). The problem with solid metal was presumably just that the longitudinal speed of sound was much higher than in liquids — so at a given clock speed and column length, you couldn’t store as many bits. Conversely, the issue with less dense and more compressible liquids might have been that they attenuated high frequencies, reducing the maximum transmit rate. All in all, I suspect that mercury simply offered the optimal storage capacity for the era — as long as you didn’t care about safety or weight.
Thankfully, this “mad scientist” period ended the moment someone thought of coiling the metal to accommodate more data in flight. Meet torsion memory:
The approach relied on acoustic waves traveling through spring wire, but this time, it used torsion (twisting) instead of longitudinal (push-pull) motion. This allowed the wire to be loosely coiled and held in place with rubber spacers; with longitudinal waves, much of the acoustic energy would be lost at every turn.
Yet another fascinating class of early dynamic memories included the Williams tube and the RCA Selectron tube. Both had no moving parts; the latter device is pictured below:
These memories operated somewhat like a CRT, selectively firing electrons at a phosphor substrate and storing several hundred bits as a pattern of illuminated dots. Although the stored data was visible to the naked eye, the readout relied on sensing changes to electrostatic fields instead. In essence, electrons were getting knocked around in the phosphor layer, creating a net charge which could be picked up for a while by a nearby electrode.
Today, even among computer history buffs, magnetic media is typically associated with bulk, at-rest data storage: hard disks, floppies, and LTO tapes. But for about two decades — roughly between 1950 and 1970 — magnetic main memories were quite common too.
The earliest incarnation of this is the magnetic drum memory, a sort of an in-between stage between the capacitor-based memory of the Atanasoff-Berry computer and the modern hard drive:
In this design, read and write heads hovered above a fast-spinning ferromagnetic cylinder. The relatively small diameter of the cylinder, along with the high number of parallel heads that didn’t need to make contact with the surface, kept the read times reasonably short. But still not short enough: the computers of that era were already running at multi-megahertz speeds. We needed a better approach.
The best we came up with in pre-IC era was solid-state magnetic core memory. These devices consisted of an array of microscopic ferrite beads (“cores”) with a pattern of insulated copper wires woven through:
The key property of the cores is that they could be magnetized by an external field, but their magnetic polarity flipped only if the magnetizing field exceeded a certain threshold. Below that threshold, they retained their previous state.
To write to a specific cell, a sub-threshold magnetic field would be induced around a specific horizontal wire by supplying a calibrated current through its length. Another sub-threshold field would be created along a vertical wire. At the intersection of the two wires, the intensity of the combined fields would exceed the magnetization threshold and “flip” the selected core.
The readout process was a bit more involved: it relied on overwriting a cell and then sensing the induced current that’s expected if the polarity flips. If no such current pulse was detected, it meant that the written value must have been the same as what was stored in the cell before.
Magnetic memories were fast and quite tiny; the microscope photo above shows about 63 bits of a 32 kB module that measured 8×8” overall.
Interestingly, the legacy of magnetic RAM lives on: a company called Everspin Technologies sells magnetoresistive (MRAM) chips for embedded applications in sizes up to 16 MB. The chips behave just like SRAM, except they retain data with no power. At the moment, the tech doesn’t seem to be particularly competitive; I think it might have some uses in aerospace and defense applications because it is more resistant to radiation and EMP. That said, given the meandering path we’ve taken with memory technology, so knows what the future holds?
Other history-related articles you might like:
I write well-researched, original articles about geek culture, computing history, and more. If you like the content, please subscribe.
Source: Hacker News
One problem that I’ve had in physics is remembering physical laws. I want to be able to use physical law in the same way that I can fry an egg, string together a sentence, or add up numbers. I think the world ‘fluency’, comes to mind. Imagine manipulating the physical world as fluently as one can communicate ideas – ‘oh my chicken gets overcooked, that’s fine, I know how to solve the heat equation so I just need to reduce the temperature by X and make my chicken a bit more spherical next time!’.
Sure, I could just look up Coulomb’s law or Maxwell’s equations, or ask an LLM, but I’m always amazed that the Greeks managed to learn so much about the world with much less tools. And I kinda want to be able to do the same. One time my friend Cyrus and I we were sitting on the beach in Brighton and then challenged each other to try to compute the radius of the Earth from first principles using the angle of the horizon. I think these types of challenges are both fun and revealing.
There is piece of advice in one of Shankar’s texts that stuck with me whilst I was chilling by the pool in Malaysia, from his textbook ‘On Fundamental Physics II’. Shankar writes that to get deep understanding of physics, one should think hard about how physical law could actually be tested and measured with real life instrumentation. Lest, we might get lost in ‘factors of 2pi’ just doing symbolic manipulations like the Cambridge Masters theoretical physics student I was.
I’ve always had trouble trying to remember something like Coulombs law, so I had a bit of a think about how I could feel it and test it with my own hands. After all, Coulomb’s law deals with point charges. And those are abstract ideas, it’s not straightforward to just magic up a piece of electric charge. One starting point might be to use something like a pen and rub it against your hair, but
Coulombs law is meant to tell us the force between two charged particles. If we have two charged particles q1 and q2, then observations like two charged balloons tells us that there should be a force between the two charged particles. Coulomb’s law quantifies this force.
It states that if the distance between the charged particles is x, then the force between them should be
Ok but let’s think critically about this equation to see if there are any new insights to become of it. How could one have come to a reasonable conclusion that this is indeed the law of force between charges? Presumably, the law is a function of distance between the charges, and the charge on both. So we have the force being a function of the following
To help us slim down what this function might be, we might ask what happens when one of the bodies are not charged. If one isn’t charged, then intuition says that there should be no forces in between the two things. This means that the charges should enter the equation as multiplicative factors. This would imply then that the force law looks like below, where a and b are some constants
But then by symmetry, we require a and b to be the same. So the force should look like
But it’s not at all obvious to me why the exponent a is 1 in nature. I think if I tried to write about a physical rabbit hole is out of scope but I will keep thinking about it.
The next question then is then figuring out the force varies as the distance between the two increases. A logical guess would be that the force law might obey something similar to the inverse square law observed in the intensity of light, or the gravitational constant. For example, Newton’s law of gravity reads that the force between two bodies is
And so then the question is – how would you check that Coulomb’s law indeed obeys inverse square law? It’s not entirely clear. And in fact, a few scientists in the 16th century actually proposed that the original Coulomb’s law was close to inverse square but not quite. To do this at home, you would probably need to figure out how to charge two electric balls with the same level of charge, hold one fixed, hold the other one by a string, and then measure the difference in angle deflection that the string makes with a vertical line to calculate how much force the ball experiences.
Coulomb did this with a sensitive piece of equipment called a torsion spring, but I’m trying to find easier ways.
Charging an metal ball cleanly and with home materials is proving kind of tricky. Supposedly, one way to make two equal charges is to charge one thing and then put it in contact with the other thing, so that the charge splits by symmetry. But then how would we check that indeed we have two equally charged things?
I thought of maybe trying to make a Faraday cage. But instead, today I tried to make an aluminium foil electroscope. To do this I took some insulated wire from by breadboarding kit, drilled a hole through the top of a jar, made the end of a wire a hook and then cut a thin piece of aluminium foil. I then folded this piece of foil and hung it on the wire. the other side of the wire lies on the outside of the jar where I scrunched up some more foil. And when I charge an object by rubbing it against my hair, putting it on the contact causes the tin foil in the jar to separate because of the repulsion of charge in both sides of the strip!
But right now this is a super messy and non quantitative way to do this. One of the main reasons is because of charge decay, usually because the air is humid and so takes away charge from the object. So I’m trying to think of a more robust way to create a repeatable charge at home to measure inverse square law more accurately as part of a killer experiment.
Source: Hacker News
Web-based emulator and operating environment for the IBM 1620 Model-2 computer system.
The IBM 1620 was a 1960s transistorized, decimal, variable field-length, magnetic-core memory computer system designed primarily as an inexpensive solution for scientific and engineering applications. There were two models, the original Model 1 released in 1959, and the object-code compatible but significantly redesigned Model 2, released in 1962. A total of about 2,000 systems were produced, roughly half each Model-1s and Model-2s. IBM supported the system until 1970.
The 1620 used a two-address, memory-to-memory architecture. There were no software-accessible registers. Instructions were a fixed 12 digits, consisting of an operation code of two digits, a “P” address of five digits (usually the destination operand), and a “Q” address or literal value of five digits (usually the source operand). The basic memory size was 20,000 digits, expandable to 60,000 digits. Each digit contained a four-bit binary-coded decimal value, a fifth “flag” bit used for both the arithmetic sign and as a field delimiter, and an odd-parity “check” bit. All arithmetic and data movement was done digit-sequentially.
The Model 1 featured a memory cycle time of 20µs per two digits. Addition and multiplication were done via a lookup table in memory. Hardware division, floating-point arithmetic, and indirect addressing were optional features.
The Model 2 featured a memory cycle time of 10µs per two digits. Many instructions were optimized to process two Q-operand digits from a single memory fetch. Addition was done in hardware, but multiplication was still done by table lookup. Hardware division and indirect addressing were standard features, with floating-point still an extra-cost option. The Model 2 had two additional options, index register address modification (with the index registers stored in memory at 00300-00399, where the Model 1 add table had resided) and support for binary (actually, octal) bit-wise operations, octal/decimal conversion, and binary paper tape I/O.
Initially, the Model 1 supported only paper-tape and typewriter input/output devices, but the 1622 card reader/punch unit (derived from the IBM 1401’s model 1402 reader/punch) was made available soon after the initial release. Additional peripherals were the 1443 line printer, 1311 disk drive with removable disk packs, and 1627 plotter. The typewriter, paper tape, punched card, and printer devices supported alphanumeric data in memory as pairs of adjacent digits.
The 1620 was also used as the computing and control component of the IBM 1710 and 1720 process-control systems. When configured for this role, the 1620 supported several additional instructions and a multi-level interrupt system.
The 1620 had a vast collection of IBM-supplied and user-written software. Most programming was done using the SPS assembler or FORTRAN II. For systems with the 1311 disk drive, there was a simple batch operating system known as “Monitor.”
The main goals of this project are creation of a web browser-based emulator for the Model 2 variant of the system and recovery of as much software for the system as we are able to find.
The contents of this project are licensed under the MIT License.
| Related Sites | URL |
|---|---|
| Emulator hosting site | http://www.phkimpel.us/IBM-1620/ |
| Project Wiki | https://github.com/pkimpel/retro-1620/wiki/ |
| Project Blog | https://retro-emulation.blogspot.com/ |
| 1620 Documents at bitsavers | http://bitsavers.org/pdf/ibm/1620/ |
| 1620 Software at bitsavers | http://www.bitsavers.org/bits/IBM/1620/ |
| 1620 Wikipedia page | https://en.wikipedia.org/wiki/IBM_1620 |
Source: Hacker News