Macho programmers, drum memory and a forensic analysis of 1960s machine code

The "real programmer" trope has been a part of computing culture for nearly as long as the field has existed. In the early days of the industry in the 1950s and 60s, low-level assembly code was the norm and those who could cleverly optimize their code down to the bare metal were seen as "real programmers." Using higher-level languages like FORTRAN or COBOL was seen by some as a crutch for lesser developers.

As the field matured and new higher-level languages like Pascal emerged in the 1970s, the debate continued. A 1983 letter titled "Real Programmers Don‘t Use Pascal" by Ed Post, published in Datamation magazine, poked fun at this macho programmer mindset. A few weeks later, Usenet user Ed Nather replied with a story showcasing the prowess of a "real programmer" from his former company in the 1960s. Titled "The Story of Mel", it recounted the tale of a clever low-level hack on the company‘s RPC-4000 computer.

Drum memory and RPC-4000 architecture

To fully appreciate Mel‘s feat, it helps to understand a bit about the RPC-4000 and its predecessor, the LGP-30. Both were early computers that used drum memory for storage. Drum memory was an early form of computer memory that used a rotating cylinder coated with a magnetic material to store data. As the drum spun at a constant speed, a stationary row of read-write heads could access the data.

Drum memory had some advantages over other early storage methods like delay line memory or Williams tubes. It was non-volatile, meaning data wasn‘t lost when power was removed. It also allowed direct access to memory locations, unlike sequential access methods such as paper tape. However, it was much slower than modern random-access memory (RAM) – the LGP-30‘s drum rotated at just 3,700 RPM, allowing a paltry 250 accesses per second.

On the RPC-4000, instructions were 32 bits wide, composed of:

  • 5 bit operation code
  • 13 bit operand address
  • 13 bit address of next instruction
  • 1 index tag bit

Instructions were stored on the drum, read into the instruction register, executed, and the next instruction loaded from the specified next address. The index tag bit could be used with an index register for loops and iteration.

Recreating Mel‘s clever hack

The core of the story revolves around Mel exploiting an overflow bug to create an infinite loop that still allowed the program to function properly. Mel was rewriting a blackjack program for the RPC-4000 that had originally been used on the LGP-30.

He intentionally set things up so that after the last data item was processed, incrementing the operand address would cause an overflow into the next instruction address. This overflow also flipped the index tag bit from 1 to 0, which changed the instruction code, in this case creating a jump to the specified next address – which Mel had set to 0, the beginning of the program.

Here‘s what the actual 32-bit instruction might have looked like in RPC-4000 assembly:

; Initial clever instruction 
CLA 1111111111111, 1111111111111, 1 

; After overflow
CLA 0000000000000, 0000000000000, 0
JMP 0000000000000 ; Jump to beginning of memory

The first line is the initial instruction, which would clear the accumulator (CLA operation code 10110) and load the value at the specified memory address (all 1‘s, the end of available memory). The 1 index tag means it will increment the operand address after execution.

After the last data item is processed, incrementing the address causes an overflow, flipping all the bits. This changes the instruction to a jump (JMP opcode 10111) to location 0, the beginning of memory, while also resetting the index tag to 0.

Nather was surprised to find this jump with no obvious exit when maintaining the code later. Surely it was an infinite loop! Yet the program ran without issue. Only after some head scratching did he discover Mel‘s sneaky overflow trick.

The art of clever code

There‘s a certain art to "clever" code like Mel‘s. It relies on a deep understanding of the underlying architecture and a willingness to flout best practices for the sake of optimization. Hacks like using overflows, self-modifying code, and jumping to arbitrary memory locations are par for the course.

For "real programmers" of the era, this sort of cleverness was highly valued. Saving a few instructions or shaving a few milliseconds off execution time was worth almost any cost in readability or maintainability. Tales of these feats were passed around and celebrated, as in "The Story of Mel".

But as much as we may admire the ingenuity and skill behind clever code, it has some major downsides. Debugging and maintaining such code is a nightmare for anyone but the original author (and sometimes even for them!). Errors and edge cases can easily slip through. And as hardware evolves, once-clever optimizations can quickly become unnecessary or even detrimental.

There‘s also the issue of opportunity cost. Time spent squeezing every last bit of performance out of a piece of code often could be better spent improving functionality, fixing bugs, or working on new features. Premature optimization is the root of much cleverness.

The rise of high-level languages

In the decades since Mel‘s heyday, the computing landscape has changed dramatically. High-level languages have become the norm, with low-level assembly reserved for only the most performance-critical code.

A 2022 survey from Stack Overflow shows the dominance of high-level languages:

Language % of Professional Developers Using
JavaScript 65.36%
HTML/CSS 55.08%
SQL 49.43%
Python 48.07%
TypeScript 34.83%
Java 33.27%
C# 30.18%
PHP 21.98%
C++ 20.87%
C 16.35%

High-level, dynamically typed languages like JavaScript, Python, and PHP dominate, with lower-level languages like C and C++ further down the list. This reflects the shift towards web and application development over systems programming.

Even within systems development, the level of abstraction has increased dramatically. Developers can be productive in higher-level languages like Rust or Go that offer performance comparable to C or C++ with greater safety and expressiveness. Advances in compilers and optimization techniques mean cleverness at the assembly level is rarely needed.

Lessons for modern developers

So what lessons can modern developers take from Mel‘s story and the "real programmer" ethos? I think there are a few key points:

  1. Understand the systems you work with. Even if you primarily work in high-level languages, having some knowledge of the underlying architecture and implementation is valuable. It allows you to debug tricky issues, optimize performance-critical code, and generally reason about your programs more effectively.

  2. Clever code isn‘t always good code. As tempting as it can be to show off your technical wizardry, clever hacks often make code harder to understand and maintain. Aim for clarity and simplicity first.

  3. Use the right tool for the job. Low-level optimization has its place, but most of the time using the highest level of abstraction you can is better for productivity, collaboration, and maintainability. Don‘t be afraid to use frameworks and libraries that make your job easier.

  4. Programming culture has evolved. The macho, hyper-competitive attitudes of early programmer culture aren‘t healthy or conducive to doing good work. Foster environments of collaboration, mentorship, and psychological safety on your teams.

At the same time, I don‘t think we should entirely dismiss the "real programmer" mindset. There is something to be said for the curiosity, passion, and drive to really understand how things work under the hood. Those traits are valuable in any developer, regardless of what level of abstraction they work at.

Mel‘s overflow trick is an impressive feat of low-level ingenuity, and stories like it are fun to dissect and learn from. But as professional developers, our time is usually better spent on higher-level concerns – writing clear, maintainable, well-tested code that solves real problems for users. We can admire Mel‘s cleverness while recognizing it‘s not the best model for how we write software today. Real developers use the best tools for the job at hand, whether that‘s a high-level web framework or low-level assembly – and everything in between.

Similar Posts