Full Width [alt+shift+f] Shortcuts [alt+shift+k]
Sign Up [alt+shift+s] Log In [alt+shift+l]
1

AAA gaming on Asahi Linux

from On Life and Lisp [alt+shift+b] in programming

Gaming on Linux on M1 is here! We’re thrilled to release our Asahi game playing toolkit, which integrates our Vulkan 1.3 drivers with x86 emulation and Windows compatibility. Plus a bonus: conformant OpenCL 3.0. Asahi Linux now ships the only conformant OpenGL®, OpenCL™, and Vulkan® drivers for this hardware. As for gaming… while today’s release is an alpha, Control runs well! Installation First, install Fedora Asahi Remix. Once installed, get the latest drivers with dnf upgrade --refresh && reboot. Then just dnf install steam and play. While all M1/M2-series systems work, most games require 16GB of memory due to emulation overhead. The stack Games are typically x86 Windows binaries rendering with DirectX, while our target is Arm Linux with Vulkan. We need to handle each difference: FEX emulates x86 on Arm. Wine translates Windows to Linux. DXVK and vkd3d-proton translate DirectX to Vulkan. There’s one curveball: page size. Operating systems allocate memory in fixed size “pages”. If an application expects smaller pages than the system uses, they will break due to insufficient alignment of allocations. That’s a problem: x86 expects 4K pages but Apple systems use 16K pages. While Linux can’t mix page sizes between processes, it can virtualize another Arm Linux kernel with a different page size. So we run games inside a tiny virtual machine using muvm, passing through devices like the GPU and game controllers. The hardware is happy because the system is 16K, the game is happy because the virtual machine is 4K, and you’re happy because you can play Fallout 4. Vulkan The final piece is an adult-level Vulkan driver, since translating DirectX requires Vulkan 1.3 with many extensions. Back in April, I wrote Honeykrisp, the only Vulkan 1.3 driver for Apple hardware. I’ve since added DXVK support. Let’s look at some new features. Tessellation Tessellation enables games like The Witcher 3 to generate geometry. The M1 has hardware tessellation, but it is too limited for...
10th Oct 2024

Stay updated

Get a weekly newsletter with the top 5 articles worth reading every week.

More from On Life and Lisp

Dissecting the Apple M1 GPU, the end

In 2020, Apple released the M1 with a custom GPU. We got to work reverse-engineering the hardware and porting Linux. Today, you can run Linux on a range of M1 and M2 Macs, with almost all hardware working: wireless, audio, and full graphics acceleration. Our story begins in December 2020, when Hector Martin kicked off Asahi Linux. I was working for Collabora working on Panfrost, the open source Mesa3D driver for Arm Mali GPUs. Hector put out a public call for guidance from upstream open source maintainers, and I bit. I just intended to give some quick pointers. Instead, I bought myself a Christmas present and got to work. In between my university coursework and Collabora work, I poked at the shader instruction set. One thing led to another. Within a few weeks, I drew a triangle. In 3D graphics, once you can draw a triangle, you can do anything. Pretty soon, I started work on a shader compiler. After my final exams that semester, I took a few days off from Collabora to bring up an OpenGL driver capable of spinning gears with my new compiler. Over the next year, I kept reverse-engineering and improving the driver until it could run 3D games on macOS. Meanwhile, Asahi Lina wrote a kernel driver for the Apple GPU. My userspace OpenGL driver ran on macOS, leaving her kernel driver as the missing piece for an open source graphics stack. In December 2022, we shipped graphics acceleration in Asahi Linux. In January 2023, I started my final semester in my Computer Science program at the University of Toronto. For years I juggled my courses with my part-time job and my hobby driver. I faced the same question as my peers: what will I do after graduation? Maybe Panfrost? I started reverse-engineering of the Mali Midgard GPU back in 2017, when I was still in high school. That led to an internship at Collabora in 2019 once I graduated, turning into my job throughout four years of university. During that time, Panfrost grew from a kid’s pet project based on blackbox reverse-engineering, to a professional driver engineered by a team with Arm’s backing and hardware documentation. I did what I set out to do, and the project succeeded beyond my dreams. It was time to move on. What did I want to do next? Finish what I started with the M1. Ship a great driver. Bring full, conformant OpenGL drivers to the M1. Apple’s drivers are not conformant, but we should strive for the industry standard. Bring full, conformant Vulkan to Apple platforms, disproving the myth that Vulkan isn’t suitable for Apple hardware. Bring Proton gaming to Asahi Linux. Thanks to Valve’s work for the Steam Deck, Windows games can run better on Linux than even on Windows. Why not reap those benefits on the M1? Panfrost was my challenge until we “won”. My next challenge? Gaming on Linux on M1. Once I finished my coursework, I started full-time on gaming on Linux. Within a month, we shipped OpenGL 3.1 on Asahi Linux. A few weeks later, we passed official conformance for OpenGL ES 3.1. That put us at feature parity with Panfrost. I wanted to go further. OpenGL (ES) 3.2 requires geometry shaders, a legacy feature not supported by either Arm or Apple hardware. The proprietary OpenGL drivers emulate geometry shaders with compute, but there was no open source prior art to borrow. Even though multiple Mesa drivers need geometry/tessellation emulation, nobody did the work to get there. My early progress on OpenGL was fast thanks to the mature common code in Mesa. It was time to pay it forward. Over the rest of the year, I implemented geometry/tessellation shader emulation. And also the rest of the owl. In January 2024, I passed conformance for the full OpenGL 4.6 specification, finishing up OpenGL. Vulkan wasn’t too bad, either. I polished the OpenGL driver for a few months, but once I started typing a Vulkan driver, I passed 1.3 conformance in a few weeks. What remained was wiring up the geometry/tessellation emulation to my shiny new Vulkan driver, since those are required for Direct3D. Et voilà, Proton games. Along the way, Karol Herbst passed OpenCL 3.0 conformance on the M1, running my compiler atop his “rusticl” frontend. Meanwhile, when the Vulkan 1.4 specification was published, we were ready and shipped a conformant implementation on the same day. After that, I implemented sparse texture support, unlocking Direct3D 12 via Proton. …Now what? Ship a great driver? Check. Conformant OpenGL 4.6, OpenGL ES 3.2, and OpenCL 3.0? Check. Conformant Vulkan 1.4? Check. Proton gaming? Check. That’s a wrap. We’ve succeeded beyond my dreams. The challenges I chased, I have tackled. The drivers are fully upstream in Mesa. Performance isn’t too bad. With the Vulkan on Apple myth busted, conformant Vulkan is now coming to macOS via LunarG’s KosmicKrisp project building on my work. Satisfied, I am now stepping away from the Apple ecosystem. My friends in the Asahi Linux orbit will carry the torch from here. As for me? Onto the next challenge!

26th Aug 2025 • 1 votes
Vulkan 1.4 sur Asahi Linux

English version follows. Aujourd’hui, Khronos Group a sorti la spécification 1.4 de l’API graphique standard Vulkan. Le projet Asahi Linux est fier d’annoncer le premier pilote Vulkan 1.4 pour le matériel d’Apple. En effet, notre pilote graphique Honeykrisp est reconnu par Khronos comme conforme à cette nouvelle version dès aujourd’hui. Ce pilote est déjà disponible dans nos dépôts officiels. Après avoir installé Fedora Asahi Remix, executez dnf upgrade --refresh pour obtenir la dernière version du pilote. Vulkan 1.4 standardise plusieurs fonctionnalités importantes, y compris les horodatages et la lecture locale avec le rendu dynamique. L’industrie suppose que ces fonctionnalités devront être plus courantes, et nous y sommes préparés. Sortir un pilote conforme reflète notre engagement en faveur des standards graphiques et du logiciel libre. Asahi Linux est aussi compatible avec OpenGL 4.6, OpenGL ES 3.2, et OpenCL 3.0, tous conformes aux spécifications pertinentes. D’ailleurs, les nôtres sont les seuls pilotes conformes pour le materiel d’Apple de n’importe quel standard graphique. Même si le pilote est sorti, il faut encore compiler une version expérimentale de Vulkan-Loader pour utiliser la nouvelle version de Vulkan. Toutes les nouvelles fonctionnalités sont néanmoins disponibles comme extensions à notre pilote Vulkan 1.3 pour en profiter tout de suite. Pour plus d’informations, consultez l’article du blog de Khronos. Today, the Khronos Group released the 1.4 specification of Vulkan, the standard graphics API. The Asahi Linux project is proud to announce the first Vulkan 1.4 driver for Apple hardware. Our Honeykrisp driver is Khronos-recognized as conformant to the new version since day one. That driver is already available in our official repositories. After installing Fedora Asahi Remix, run dnf upgrade --refresh to get the latest drivers. Vulkan 1.4 standardizes several important features, including timestamps and dynamic rendering local read. The industry expects that these features will become more common, and we are prepared. Releasing a conformant driver reflects our commitment to graphics standards and software freedom. Asahi Linux is also compatible with OpenGL 4.6, OpenGL ES 3.2, and OpenCL 3.0, all conformant to the relevant specifications. For that matter, ours are the only conformant drivers on Apple hardware for any graphics standard. Although the driver is released, you still need to build an experimental version of Vulkan-Loader to access the new Vulkan version. Nevertheless, you can immediately use all the new features as extensions in our Vulkan 1.3 driver. For more information, see the Khronos blog post.

2nd Dec 2024 • 1 votes
Vulkan 1.3 on the M1 in 1 month

u{text-decoration-thickness:0.09em;text-decoration-color:skyblue} Finally, conformant Vulkan for the M1! The new “Honeykrisp” driver is the first conformant Vulkan® for Apple hardware on any operating system, implementing the full 1.3 spec without “portability” waivers. Honeykrisp is not yet released for end users. We’re continuing to add features, improve performance, and port to more hardware. Source code is available for developers. HoloCure running on Honeykrisp ft. DXVK, FEX, and Proton. Honeykrisp is not based on prior M1 Vulkan efforts, but rather Faith Ekstrand’s open source NVK driver for NVIDIA GPUs. In her words: All Vulkan drivers in Mesa trace their lineage to the Intel Vulkan driver and started by copying+pasting from it. My hope is that NVK will eventually become the driver that everyone copies and pastes from. To that end, I’m building NVK with all the best practices we’ve developed for Vulkan drivers over the last 7.5 years and trying to keep the code-base clean and well-organized. Why spend years implementing features from scratch when we can reuse NVK? There will be friction starting out, given NVIDIA’s desktop architecture differs from the M1’s mobile roots. In exchange, we get a modern driver designed for desktop games. We’ll need to pass a half-million tests ensuring correctness, submit the results, and then we’ll become conformant after 30 days of industry review. Starting from NVK and our OpenGL 4.6 driver… can we write a driver passing the Vulkan 1.3 conformance test suite faster than the 30 day review period? It’s unprecedented… Challenge accepted. April 2 It begins with a text. Faith… I think I want to write a Vulkan driver. Her advice? Just start typing. There’s no copy-pasting yet – we just add M1 code to NVK and remove NVIDIA as we go. Since the kernel mediates our access to the hardware, we begin connecting “NVK” to Asahi Lina’s kernel driver using code shared with OpenGL. Then we plug in our shader compiler and hit the hay. April 3 To access resources, GPUs use “descriptors” containing the address, format, and size of a resource. Vulkan bundles descriptors into “sets” per the application’s “descriptor set layout”. When compiling shaders, the driver lowers descriptor accesses to marry the set layout with the hardware’s data structures. As our descriptors differ from NVIDIA’s, our next task is adapting NVK’s descriptor set lowering. We start with a simple but correct approach, deleting far more code than we add. April 4 With working descriptors, we can compile compute shaders. Now we program the fixed-function hardware to dispatch compute. We first add bookkeeping to map Vulkan command buffers to lists of M1 “control streams”, then we generate a compute control stream. We copy that code from our OpenGL driver, translate the GL into Vulkan, and compute works. That’s enough to move on to “copies” of buffers and images. We implement Vulkan’s copies with compute shaders, internally dispatched with Vulkan commands as if we were the application. The first copy test passes. April 5 Fleshing out yesterday’s code, all copy tests pass. April 6 We’re ready to tackle graphics. The novelty is handling graphics state like depth/stencil. That’s straightforward, but there’s a lot of state to handle. Faith’s code collects all “dynamic state” into a single structure, which we translate into hardware control words. As usual, we grab that translation from our OpenGL driver, blend with NVK, and move on. April 7 What makes state “dynamic”? Dynamic state can change without recompiling shaders. By contrast, static state is baked into shader binaries called “pipelines”. If games create all their pipelines during a loading screen, there is no compiler “stutter” during gameplay. The idea hasn’t quite panned out: many game developers don’t know their state ahead-of-time so cannot create pipelines early. In response, Vulkan has made ever more state dynamic, punctuated with the EXT_shader_object extension that makes pipelines optional. We want full dynamic state and shader objects. Unfortunately, the M1 bakes random state into shaders: vertex attributes, fragment outputs, blending, even linked interpolation qualifiers. Like most of the industry in the 2010s, the M1’s designers bet on pipelines. Faced with this hardware, a reasonable driver developer would double-down on pipelines. DXVK would stutter, but we’d pass conformance. I am not reasonable. To eliminate stuttering in OpenGL, we make state dynamic with four strategies: Conditional code. Precompiled variants. Indirection. Prologs and epilogs. Wait, what-a-logs? AMD also bakes state into shaders… with a twist. They divide the hardware binary into three parts: a prolog, the shader, and an epilog. Confining dynamic state to the periphery eliminates shader variants. They compile prologs and epilogs on the fly, but that’s fast and doesn’t stutter. Linking shader parts is a quick concatenation, or long jumps avoid linking altogether. This strategy works for the M1, too. For Honeykrisp, let’s follow NVK’s lead and treat all state as dynamic. No other Vulkan driver has implemented full dynamic state and shader objects this early on, but it avoids refactoring later. Today we add the code to build, compile, and cache prologs and epilogs. Putting it together, we get a (dynamic) triangle: April 8 Guided by the list of failing tests, we wire up the little bits missed along the way, like translating border colours. /* Translate an American VkBorderColor into a Canadian agx_border_colour */ enum agx_border_colour translate_border_color(VkBorderColor color) { switch (color) { case VK_BORDER_COLOR_INT_TRANSPARENT_BLACK: return AGX_BORDER_COLOUR_TRANSPARENT_BLACK; ... } } Test results are getting there. Pass: 149770, Fail: 7741, Crash: 2396 That’s good enough for vkQuake. April 9 Lots of little fixes bring us to a 99.6% pass rate… for Vulkan 1.1. Why stop there? NVK is 1.3 conformant, so let’s claim 1.3 and skip to the finish line. Pass: 255209, Fail: 3818, Crash: 599 98.3% pass rate for 1.3 on our 1 week anniversary. Not bad. April 10 SuperTuxKart has a Vulkan renderer. April 11 Zink works too. April 12 I tracked down some fails to a test bug, where an arbitrary verification threshold was too strict to pass on some devices. I filed a bug report, and it’s resolved within a few weeks. April 16 The tests for “descriptor indexing” revealed a compiler bug affecting subgroup shuffles in non-uniform control flow. The M1’s shuffle instruction is quirky, but it’s easy to workaround. Fixing that fixes the descriptor indexing tests. April 17 A few tests crash inside our register allocator. Their shaders contain a peculiar construction: if (condition) { while (true) { } } condition is always false, but the compiler doesn’t know that. Infinite loops are nominally invalid since shaders must terminate in finite time, but this shader is syntactically valid. “All loops contain a break” seems obvious for a shader, but it’s false. It’s straightforward to fix register allocation, but what a doozy. April 18 Remember copies? They’re slow, and every frame currently requires a copy to get on screen. For “zero copy” rendering, we need enough Linux window system integration to negotiate an efficient surface layout across process boundaries. Linux uses “modifiers” for this purpose, so we implement the EXT_image_drm_format_modifier extension. And by implement, I mean copy. Copies to avoid copies. April 20 “I’d like a 4K x86 Windows Direct3D PC game on a 16K arm64 Linux Vulkan Mac.” … “Ma’am, this is a Wendy’s.” April 22 As bug fixing slows down, we step back and check our driver architecture. Since we treat all state as dynamic, we don’t pre-pack control words during pipeline creation. That adds theoretical CPU overhead. Is that a problem? After some optimization, vkoverhead says we’re pushing 100 million draws per second. I think we’re okay. April 24 Time to light up YCbCr. If we don’t use special YCbCr hardware, this feature is “software-only”. However, it touches a lot of code. It touches so much code that Mohamed Ahmed spent an entire summer adding it to NVK. Which means he spent a summer adding it to Honeykrisp. Thanks, Mohamed ;-) April 25 Query copies are next. In Vulkan, the application can query the number of samples rendered, writing the result into an opaque “query pool”. The result can be copied from the query pool on the CPU or GPU. For the CPU, the driver maps the pool’s internal data structure and copies the result. This may require nontrivial repacking. For the GPU, we need to repack in a compute shader. That’s harder, because we can’t just run C code on the GPU, right? …Actually, we can. A little witchcraft makes GPU query copies as easy as C. void copy_query(struct params *p, int i) { uintptr_t dst = p->dest + i * p->stride; int query = p->first + i; if (p->available[query] || p->partial) { int q = p->index[query]; write_result(dst, p->_64, p->results[q]); } ... } April 26 The final boss: border colours, hard mode. Direct3D lets the application choose an arbitrary border colour when creating a sampler. By contrast, Vulkan only requires three border colours: (0, 0, 0, 0) – transparent black (0, 0, 0, 1) – opaque black (1, 1, 1, 1) – opaque white We handled these on April 8. Unfortunately, there are two problems. First, we need custom border colours for Direct3D compatibility. Both DXVK and vkd3d-proton require the EXT_custom_border_color extension. Second, there’s a subtle problem with our hardware, causing dozens of fails even without custom border colours. To understand the issue, let’s revisit texture descriptors, which contain a pixel format and a component reordering swizzle. Some formats are implicitly reordered. Common “BGRA” formats swap red and blue for historical reasons. The M1 does not directly support these formats. Instead, the driver composes the swizzle with the format’s reordering. If the application uses a BARB swizzle with a BGRA format, the driver uses an RABR swizzle with an RGBA format. There’s a catch: swizzles apply to the border colour, but formats do not. We need to undo the format reordering when programming the border colour for correct results after the hardware applies the composed swizzle. Our OpenGL driver implements border colours this way, because it knows the texture format when creating the sampler. Unfortunately, Vulkan doesn’t give us that information. Without custom border colour support, we “should” be okay. Swapping red and blue doesn’t change anything if the colour is white or black. There’s an even subtler catch. Vulkan mandates support for a packed 16-bit format with 4-bit components. The M1 supports a similar format… but with reversed “endianness”, swapping red and alpha. That still seems okay. For transparent black (all zero) and opaque white (all one), swapping components doesn’t change the result. The problem is opaque black: (0, 0, 0, 1). Swapping red and alpha gives (1, 0, 0, 0). Transparent red? Uh-oh. We’re stuck. No known hardware configuration implements correct Vulkan semantics. Is hope lost? Do we give up? A reasonable person would. I am not reasonable. Let’s jump into the deep end. If we implement custom border colours, opaque black becomes a special case. But how? The M1’s custom border colours entangle the texture format with the sampler. A reasonable person would skip Direct3D support. As you know, I am not reasonable. Although the hardware is unsuitable, we control software. Whenever a shader samples a texture, we’ll inject code to fix up the border colour. This emulation is simple, correct, and slow. We’ll use dirty driver tricks to speed it up later. For now, we eat the cost, advertise full custom border colours, and pass the opaque black tests. April 27 All that’s left is some last minute bug fixing, and… Pass: 686930, Fail: 0 Success. The future The next task is implementing everything that DXVK and vkd3d-proton require to layer Direct3D. That includes esoteric extensions like transform feedback. Then Wine and an open source x86 emulator will run Windows games on Asahi Linux. That’s getting ahead of ourselves. In the mean time, enjoy Linux games with our conformant OpenGL 4.6 drivers… and stay tuned. Baby Storm running on Honeykrisp ft. DXVK, FEX, and Proton.

5th Jun 2024 • 1 votes
Conformant OpenGL 4.6 on the M1

For years, the M1 has only supported OpenGL 4.1. That changes today – with our release of full OpenGL® 4.6 and OpenGL® ES 3.2! Install Fedora for the latest M1/M2-series drivers. Already installed? Just dnf upgrade --refresh. Unlike the vendor’s non-conformant 4.1 drivers, our open source Linux drivers are conformant to the latest OpenGL versions, finally promising broad compatibility with modern OpenGL workloads, like Blender. Conformant 4.6/3.2 drivers must pass over 100,000 tests to ensure correctness. The official list of conformant drivers now includes our OpenGL 4.6 and ES 3.2. While the vendor doesn’t yet support graphics standards like modern OpenGL, we do. For this Valentine’s Day, we want to profess our love for interoperable open standards. We want to free users and developers from lock-in, enabling applications to run anywhere the heart wants without special ports. For that, we need standards conformance. Six months ago, we became the first conformant driver for any standard graphics API for the M1 with the release of OpenGL ES 3.1 drivers. Today, we’ve finished OpenGL with the full 4.6… and we’re well on the road to Vulkan. Compared to 4.1, OpenGL 4.6 adds dozens of required features, including: Robustness SPIR-V Clip control Cull distance Compute shaders Upgraded transform feedback Regrettably, the M1 doesn’t map well to any graphics standard newer than OpenGL ES 3.1. While Vulkan makes some of these features optional, the missing features are required to layer DirectX and OpenGL on top. No existing solution on M1 gets past the OpenGL 4.1 feature set. How do we break the 4.1 barrier? Without hardware support, new features need new tricks. Geometry shaders, tessellation, and transform feedback become compute shaders. Cull distance becomes a transformed interpolated value. Clip control becomes a vertex shader epilogue. The list goes on. For a taste of the challenges we overcame, let’s look at robustness. Built for gaming, GPUs traditionally prioritize raw performance over safety. Invalid application code, like a shader that reads a buffer out-of-bounds, can trigger undefined behaviour. Drivers exploit that to maximize performance. For applications like web browsers, that trade-off is undesirable. Browsers handle untrusted shaders, which they must sanitize to ensure stability and security. Clicking a malicious link should not crash the browser. While some sanitization is necessary as graphics APIs are not security barriers, reducing undefined behaviour in the API can assist “defence in depth”. “Robustness” features can help. Without robustness, out-of-bounds buffer access in a shader can crash. With robustness, the application can opt for defined out-of-bounds behaviour, trading some performance for less attack surface. All modern cross-vendor APIs include robustness. Many games even (accidentally?) rely on robustness. Strangely, the vendor’s proprietary API omits buffer robustness. We must do better for conformance, correctness, and compatibility. Let’s first define the problem. Different APIs have different definitions of what an out-of-bounds load returns when robustness is enabled: Zero (Direct3D, Vulkan with robustBufferAccess2) Either zero or some data in the buffer (OpenGL, Vulkan with robustBufferAccess) Arbitrary values, but can’t crash (OpenGL ES) OpenGL uses the second definition: return zero or data from the buffer. One approach is to return the last element of the buffer for out-of-bounds access. Given the buffer size, we can calculate the last index. Now consider the minimum of the index being accessed and the last index. That equals the index being accessed if it is valid, and some other valid index otherwise. Loading the minimum index is safe and gives a spec-compliant result. As an example, a uniform buffer load without robustness might look like: load.i32 result, buffer, index Robustness adds a single unsigned minimum (umin) instruction: umin idx, index, last load.i32 result, buffer, idx Is the robust version slower? It can be. The difference should be small percentage-wise, as arithmetic is faster than memory. With thousands of threads running in parallel, the arithmetic cost may even be hidden by the load’s latency. There’s another trick that speeds up robust uniform buffers. Like other GPUs, the M1 supports “preambles”. The idea is simple: instead of calculating the same value in every thread, it’s faster to calculate once and reuse the result. The compiler identifies eligible calculations and moves them to a preamble executed before the main shader. These redundancies are common, so preambles provide a nice speed-up. We usually move uniform buffer loads to the preamble when every thread loads the same index. Since the size of a uniform buffer is fixed, extra robustness arithmetic is also moved to the preamble. The robustness is “free” for the main shader. For robust storage buffers, the clamping might move to the preamble even if the load or store cannot. Armed with robust uniform and storage buffers, let’s consider robust “vertex buffers”. In graphics APIs, the application can set vertex buffers with a base GPU address and a chosen layout of “attributes” within each buffer. Each attribute has an offset and a format, and the buffer has a “stride” indicating the number of bytes per vertex. The vertex shader can then read attributes, implicitly indexing by the vertex. To do so, the shader loads the address: Some hardware implements robust vertex fetch natively. Other hardware has bounds-checked buffers to accelerate robust software vertex fetch. Unfortunately, the M1 has neither. We need to implement vertex fetch with raw memory loads. One instruction set feature helps. In addition to a 64-bit base address, the M1 GPU’s memory loads also take an offset in elements. The hardware shifts the offset and adds to the 64-bit base to determine the address to fetch. Additionally, the M1 has a combined integer multiply-add instruction imad. Together, these features let us implement vertex loads in two instructions. For example, a 32-bit attribute load looks like: imad idx, stride/4, vertex, offset/4 load.i32 result, base, idx The hardware load can perform an additional small shift. Suppose our attribute is a vector of 4 32-bit values, densely packed into a buffer with no offset. We can load that attribute in one instruction: load.v4i32 result, base, vertex << 2 …with the hardware calculating the address: What about robustness? We want to implement robustness with a clamp, like we did for uniform buffers. The problem is that the vertex buffer size is given in bytes, while our optimized load takes an index in “vertices”. A single vertex buffer can contain multiple attributes with different formats and offsets, so we can’t convert the size in bytes to a size in “vertices”. Let’s handle the latter problem. We can rewrite the addressing equation as: That is: one buffer with many attributes at different offsets is equivalent to many buffers with one attribute and no offset. This gives an alternate perspective on the same data layout. Is this an improvement? It avoids an addition in the shader, at the cost of passing more data – addresses are 64-bit while attribute offsets are 16-bit. More importantly, it lets us translate the vertex buffer size in bytes into a size in “vertices” for each vertex attribute. Instead of clamping the offset, we clamp the vertex index. We still make full use of the hardware addressing modes, now with robustness: umin idx, vertex, last valid load.v4i32 result, base, idx << 2 We need to calculate the last valid vertex index ahead-of-time for each attribute. Each attribute has a format with a particular size. Manipulating the addressing equation, we can calculate the last byte accessed in the buffer (plus 1) relative to the base: The load is valid when that value is bounded by the buffer size in bytes. We solve the integer inequality as: The driver calculates the right-hand side and passes it into the shader. One last problem: what if a buffer is too small to load anything? Clamping won’t save us – the code would clamp to a negative index. In that case, the attribute is entirely invalid, so we swap the application’s buffer for a small buffer of zeroes. Since we gave each attribute its own base address, this determination is per-attribute. Then clamping the index to zero correctly loads zeroes. Putting it together, a little driver math gives us robust buffers at the cost of one umin instruction. In addition to buffer robustness, we need image robustness. Like its buffer counterpart, image robustness requires that out-of-bounds image loads return zero. That formalizes a guarantee that reasonable hardware already makes. …But it would be no fun if our hardware was reasonable. Running the conformance tests for image robustness, there is a single test failure affecting “mipmapping”. For background, mipmapped images contain multiple “levels of detail”. The base level is the original image; each successive level is the previous level downscaled. When rendering, the hardware selects the level closest to matching the on-screen size, improving efficiency and visual quality. With robustness, the specifications all agree that image loads return… Zero if the X- or Y-coordinate is out-of-bounds Zero if the level is out-of-bounds Meanwhile, image loads on the M1 GPU return… Zero if the X- or Y-coordinate is out-of-bounds Values from the last level if the level is out-of-bounds Uh-oh. Rather than returning zero for out-of-bounds levels, the hardware clamps the level and returns nonzero values. It’s a mystery why. The vendor does not document their hardware publicly, forcing us to rely on reverse engineering to build drivers. Without documentation, we don’t know if this behaviour is intentional or a hardware bug. Either way, we need a workaround to pass conformance. The obvious workaround is to never load from an invalid level: if (level <= levels) { return imageLoad(x, y, level); } else { return 0; } That involves branching, which is inefficient. Loading an out-of-bounds level doesn’t crash, so we can speculatively load and then use a compare-and-select operation instead of branching: vec4 data = imageLoad(x, y, level); return (level <= levels) ? data : 0; This workaround is okay, but it could be improved. While the M1 GPU has combined compare-and-select instructions, the instruction set is scalar. Each thread processes one value at a time, not a vector of multiple values. However, image loads return a vector of four components (red, green, blue, alpha). While the pseudo-code looks efficient, the resulting assembly is not: image_load R, x, y, level ulesel R[0], level, levels, R[0], 0 ulesel R[1], level, levels, R[1], 0 ulesel R[2], level, levels, R[2], 0 ulesel R[3], level, levels, R[3], 0 Fortunately, the vendor driver has a trick. We know the hardware returns zero if either X or Y is out-of-bounds, so we can force a zero output by setting X or Y out-of-bounds. As the maximum image size is 16384 pixels wide, any X greater than 16384 is out-of-bounds. That justifies an alternate workaround: bool valid = (level <= levels); int x_ = valid ? x : 20000; return imageLoad(x_, y, level); Why is this better? We only change a single scalar, not a whole vector, compiling to compact scalar assembly: ulesel x_, level, levels, x, #20000 image_load R, x_, y, level If we preload the constant to a uniform register, the workaround is a single instruction. That’s optimal – and it passes conformance. Blender “Wanderer” demo by Daniel Bystedt, licensed CC BY-SA.

14th Feb 2024 • 1 votes

More in programming

Refurb weekend II: Alpha Micro Eagle 300 and friends

This Refurb Weekend is a sequel in two ways. Six years ago I fixed the power supply and case fan in my 68EC030-based Alpha Microsystems Eagle 300, a more modernized and substantially faster Alpha Micro running AMOS, their unique DEC-inspired multiuser operating system. These blue-collar boxes were very common in many vertical markets due to their tightly integrated business-specific software packages, and are especially unusual for running their big-endian 68000-series processors little-endian (for data file backwards compatibility with their WD-16 ancestors). The 1990s-era Alpha Micro Eagle family improves on the originals with later 68K and even ColdFire CPUs, plus Ethernet and faster SCSI. The second way it's a sequel is to our previous Alpha Micro refurb weekend, a double header restoring an Alpha Micro AM-1000 and AM-1200, two members of Alpha Micro's most popular series of computers and some of the closest things they made in the early '80s to desktop workstations. From the outside, the Eagle comes in a PC-style case, but it's not a PC: ampm.floodgap.com using the webserver provided with AlphaTCP — yes, Alpha Micros can be networked — and its own on-board Ethernet. At the time the cooling fan failure was putting a lot of strain on the hard disk because it was overheating, and since this was my first Alpha Micro and I wanted to keep it in good nick, I decided I would put a SCSI2SD in it after the repair and get rid of the spinning disk entirely. Fast-forward to last fall, a little over a year ago, when I tried to do exactly that with a ZuluSCSI. And then it wouldn't start. thought was a replacement unit I could raid for parts, but it turned out to be something rather more special — and then I was even more fortunate when I got the Eagle 300 back out of storage to make one last attempt at reviving it. To cap it off we'll go stick ZuluSCSIs in everybody else, including my Motorola ColdFire-based Eagle 450, the first ColdFire server ever produced and what used to be the fastest Eagle in the house until the new hotness came. I even converted the external BlueSCSI the AM-1200 was using to an internal ZuluSCSI too. Now nearly everybody's got a solid-state boot disk and they're all a good bit more zippy, so we'll gawk at the internals, compare 68K CPU and storage benchmarks and most importantly learn from my mistakes, because as my late father always said, "I'd rather be lucky than good." On a more solemn note, we'll also observe a moment of silence for one of the line's creators who passed away last year. It's time for a Refurb Multi-Weekend Sequel. Alpha Microsystems, founded in Orange County, California in 1977, produced what were considered some of the earliest "poor man's minicomputers," smaller and more affordable multi-user systems that run a bespoke, Digital Equipment Corporation-influenced operating system named AMOS. In our previous entry we discussed their history in detail. First-generation Alpha Micros like the AM-100, designed by Dick Wilcox who also wrote most of the operating system, used large S-100 cases and a CPU chipset called the WD-16, derived from the Western Digital MCP-1600 chipset — the same one used in DEC's LSI-11 CPU — but with higher performance microcode developed by Rich Notari. These machines thoroughly outclassed low-end PDP-11s yet were substantially cheaper, and Alpha Micro found a ready audience initially with hobbyists and then later corporate turnkey environments, where its integrated AlphaBASIC and database functionality gave it a competitive advantage. As the WD-16 had little elbow room to evolve, in 1982 Alpha Micro introduced new systems based on the Motorola 68000, porting AlphaBASIC and AMOS to run natively, but swapping address lines to make it appear little-endian for compatibility with WD-16 data files and AlphaBASIC P-code. These new machines included the AM-1000, Alpha Micro's most popular single model, and by 1984 it constituted the majority of the over 20,000 Alpha Micro machines then in active use. An idealized Alpha Micro office from the 1980s might look like this photo, from their actual advertising of the period. The main system is an AM-1042E, the S-100 box sitting on the pedestal next to the printer, using an AM-100/L CPU with an 8MHz 68000 (the same as the AM-1000, which was integrated into a desktop case), and in the factory-standard configuration shipped with 512K of RAM and a 60MB Winchester ST-506 hard disk. The system served some number of local users connected directly via serial ports, in this case the two administrative assistants with AM-60 terminals (a modified and rebadged Wyse WY-100). The fact everyone here was in the same room with the machine was helpful, because AMOS is a strictly real-memory operating system and executable code ran from where it was loaded in the user's fixed memory allocation — there was no memory protection. Although the admin assistants' explicit permissions were limited by which account they were logged into, using the same style of project-programmer numbers as DEC (e.g., [1,2] being the operator account), an errant job of theirs could readily stomp on another and it was not rare for busy systems with buggy software to regularly crash. On the other hand, this also made it fast and efficient with little separation between you and the hardware, and even Alpha Micros with fairly modest specifications could support hundreds of simultaneous users. Alpha Microsystems tried multiple times to broaden the line technologically, though these efforts were largely for naught. Early attempts to put equivalent hardware onto a PC ISA co-processor card, with software to interchange between MS-DOS and AMOS, yielded only an expensive and poorly-selling PC that wasn't good at either OS (eventually the company gave up producing turnkey systems and just sold the card). In 1984 Alpha Micro introduced UNIMOS, a licensed version of AT&T System V UNIX which ran on modified AM-1000 hardware with an MMU, but it was likewise too expensive and garnered little interest from new users nor demand from existing ones. The cost of its development, the Unix license and its associated royalties, and a simultaneous lawsuit from DEC over AMOS's similarities subsequently caused lasting damage to the company, and by the end of the decade Alpha Micro found itself almost entirely dependent on legacy AMOS users. In the wake of Wilcox's 1990 retirement and original investor Bob Hitchcock's own departure in 1991, new management tried once more with Unix systems based on the Motorola 88000 — which Motorola abandoned shortly afterwards for the PowerPC AIM alliance, and so no hardware ever shipped. anybody — yes, really, just two months after the '030's October introduction — initially offering a 20MHz CPU, 32K of L2 cache and supporting up to 360 simultaneous terminals, but even the lowliest 30-user configuration started north of $40,000 [about $117,600 in 2026 dollars]. By contrast, Alpha Micro was uncharacteristically tardy in adopting the 68040 and didn't release the 33MHz AM-4000 until 1993. It was nevertheless nearly as expensive, and for most small offices, which were now increasingly Alpha Micro's financial anchor, that kind of money was simply beyond consideration. In 1993 the company settled on a two-board approach to solve both problems at once. The CPU board, dubbed the Roadrunner and designed by engineer Joshua Stumpf, contained the new processor, standard RAM SIMM slots, L2 cache (if present), and SCSI controller. This board was specifically designed to also fit in legacy machines, specifically the desktop AM-1000, AM-1200 and AM-1600 and server AM-2000 and AM-3000 systems, and initially came in a 68030 and two 68040 versions. A second board served as the CPU board's system interface, linked together using a custom "X-BUS" interconnect over twin 34-pin cables. For legacy installs, this second board was an active interposer physically replacing the original processor, which in elderly units sometimes needed to be desoldered (though that was also true for the few third-party CPU upgrades then extant, like InterLink's Dimension-030, so the Roadrunner was at least no worse). But this second board could be a whole new system architecture of its own, and that was what the I/O board was, designed by Rod Hewitt. It carried the power supply connectors, controlled the system front panel, contained the System Security Device for licensing (more on this later), presented built-in external ports for parallel, SCSI and (for certain loadouts) Ethernet, had an internal port for an optional floppy drive, and provided SIMM-format "paddle card" slots for option cards. Best of all, these boards were smaller and — by using off-the-shelf commodity hardware — cheaper to manufacture, and could be paired into multiple configurations, together becoming the company's long-promised updated low-end and mid-range systems. reasons I've related elsewhere, and I managed to land it for just a couple hundred bucks in fully working order. (Boy, are those days gone.) Based on the software still on the hard disk, this machine was previously used at a chain of three party stores in Washington state as a centralised rental and point-of-sale system, a common turnkey application. On arrival it sported the same loadout as in this article's first picture except for its original smaller-capacity Tandberg QIC tape drive, which in Alpha Micro parlance is called a tape streamer. Since these systems don't boot from CD, QIC tape is your only way to cold start and restore most 68K Alpha Micro computers if the hard disk fails. These systems also don't support the old Alpha Micro VHS backup system, hopefully to be the subject of a future article, which was ubiquitous in their early hardware. There is a single hard disk in the second 5.25" bay, though these first-generation systems also supported 5.25" and 3.5" floppy drives using an AM-219 controller board. original Refurb Weekend. our previous Alpha Micro foray we discussed the SSD's role, a chip installed in every 68K (and later x86) Alpha Micro, even the earliest S-100 boards, used by the operating system and any installed VAR software packages to enforce copy protection and license caps. The SSD number on the rear is just a serial number, printed on the rear plate for convenience and engraved on the SSD chip inside, which I'll show you in a moment. This number is not the key stored inside the chip, up to 256 bytes in length, which only Alpha Micro recorded. When a VAR wanted to lock an install to a particular system, they would provide their private code to Alpha Micro plus the user's SSD serial number, and Alpha Micro would look up the key and generate an alphanumeric PIC (Product Installation Code) that the VAR either used for direct installation or to provide to the user. During the installation process the PIC (usually irreversibly) encoded a binary overlay for the protected executable(s), making it impossible to run them on a system where the SSD didn't match. To facilitate logic board swaps and upgrades, the SSD is socketed and easily transplanted into a new board, but PICs were expensive then and unobtanium now, another reason hard disk backups were so critical. % curl -I http://ampm.floodgap.com/ HTTP/1.0 200 OK Date: Sun, 11 Oct 2026 23:43:03 GMT Server: AMOS-HTTPD/1.3C(111) MIME-version: 1.0 Content-type: text/html Last-modified: Sun, 11 Oct 2026 23:42:00 GMT Content-length: 30242 Content-encoding: 7bit in our most recent article. In this picture it's also attached to an AM-401 CD-ROM, which is the trusty Toshiba XM-5401B in an external case, though only specific ROM versions are supported. It can't boot from this drive, but it can read AMOS-formatted partitions, and with external software can also access ISO 9660 filesystems. Onscreen is a performance estimate using the built-in SI.LIT tool, which we'll be using to benchmark our new solid-state disks when we get them in there. Here's that output. .si dsk0: SI--AMOS System Information, (C) Copyright 1990, Alpha Microsystems Inc. Version 3.0(114) Computer Type: Eagle Main Processor: 68030 Co-Processor: None MMU present: Yes Operating System: AMOS 2.3A(484) Boot PROM revision: M00 Number of SSDs: 1 Total Memory: 16384 K-bytes Resident Monitor Memory: 6218 K-bytes Computing Index (CX), relative to AM-100: 36.9 48 bit FP Index (4X), relative to AM-100: 36.3 Floating Point Index (FX), relative to AM-100/L: 5.6 Disk Index (DX), relative to ST-506: 15.3 I don't know why it identified the 68EC030 as having an MMU, because it doesn't, but we're mostly interested in the "computing index" figure (SI's equivalent of an integer score) which is 36.9 times faster than Alpha Micro's original AM-100, and the "disk index" hard disk throughput test, which rates the spinning disk it came with as 15.3 times faster than their early ST-506 drives. Remember these figures as a baseline; we'll be referring to them again. On the front panel in both pictures you can see the number "0" in the LEDs. That's where the system status is displayed, initially by the firmware, then the OS monitor during boot and then in operation. We'll come back to this as well. original Refurb Weekend involved replacing the old AT supply with an ATX one and a converter. Since that post I found a NOS AT supply for cheap and I needed the ATX supply for something else, so I removed the converter and installed the new AT supply. This is that unit. The CPU and the 53C710 are both clocked by an 80MHz crystal divided down to 40MHz; there are also 16MHz and 50MHz oscillators on the board which appear to be used for the PLD and bus logic. Likely for cost reasons there is no L2 cache, though another thing to keep in mind is — so I'm told — that for compatibility reasons with 68000 and 68010-era AMOS software it is not possible to enable the data cache (or at least not without substantial difficulty). In fact, we observed exactly this phenomenon when looking at the driver for the InterLink Dimension-030 CPU upgrade, which puts a 68030 in an AM-1000: it never set the data cache bit in the '030's CACR at all. Although some machines can accept an external L2 cache, including one we'll look at in detail, anything it would provide is strictly I-cache. but is functionally equivalent in AMOS. not). I have such an example later on. Other serial paddlecards can also be installed. The AM-314 provides only four serial ports, but is not merely a cut-down AM-318 — the AM-314 can also be configured for RS-422 (the AM-318 is strictly RS-232) and supports all RS-232 handshake lines (the AM-318 only RTS/CTS), and in certain configurations can trigger a remote reboot from a connected distant console by grounding pin 1 with pin 7. By contrast, the more exotic AM-338 provides an IBM Binary Synchronous Communication "Bisync" link, typically used for Remote Job Entry (RJE) or CICS connections with IBM mainframes, but could theoretically have also worked with some early point-to-point networks like BITNET. It connects to an AM-339 which provides the physical port. a future article. Notice how many of these PCBs say "Made in USA"! A different era. from my SGI Indigo^2 retrofit to see if it could sit on them. It did, so I sheathed them in electrical tape as a "bed," put the ZuluSCSI into initiator mode, connected the old hard disk and the ZuluSCSI to my copy rig, and left it to image the drive to the SD card. didn't change: the boot sequence wasn't starting. I freaked out, immediately powered it off, and checked everything inside that I'd touched to find I had not properly reconnected the CPU board's power connector. original. I dug up Rod's old E-mail to see if there were any clues in it and recalled what he'd said about the PLDs being dynamically reprogrammed on every startup — from the CPU board. I also knew from the service manual that the X-BUS cables, the only connection between the I/O board and the CPU board, had to be correctly connected or the service manual warned damage could result. A horrible theory stirred in my head: perhaps I had managed to accidentally corrupt the PLDs by effectively bringing up the I/O board without the CPU board, where the boot PROMs used to reprogram them are located. However, that also suggested a solution — there are many undocumented jumpers on the AM-319 and I wondered if one of them could be used to trigger a clean reset of the programmable logic. in a future article). He also had an interest in digital television, developing TSReader, a way to analyse the MPEG-2 transport streams commonly used for satellite, cable and IPTV transmissions. ZTERM and in particular TSReader became far and away his most popular software packages. However, a few years prior and unbeknownst to many, he had quietly entrusted a copy of the TSReader source code to a friend officially "just in case," and sold ZTERM to MicroSabio, a long-time Alpha Micro support company that maintains A-Shell, a way of running AlphaBASIC applications on modern operating systems. The reason became clear later — he was dying, and it was not treatable. The source code for TSReader was duly posted after his passing and remains today as his most popular legacy. Rest in peace, Rod, and thank you. Without Rod's guidance, though, there wasn't much more I could think of to do at that point. I unplugged it, pulled the clock battery and let it sit for a couple days to see if that was enough to reset the PLDs, assuming that was the actual problem, and it didn't. It still seemed like it should be repairable if I could only figure out how, but as there was little point in having it sit fruitlessly on the workbench I removed all the remaining cables from the system board and moved the machine to cold storage until I could come up with something else. In the meantime I turned to my alternative system to get ampm.floodgap.com back up and running, though to discuss it we need to bring the history forward some more. only in the E500: a junior-varsity 68040, which is what the E400 was, didn't have much appeal. Both the E200 and E400 were quietly dropped. For large installs that required substantial numbers of serial ports, the existing AM-319 board had to be expanded. The revised AM-319-20 board, providing four built-in serial and parallel ports with a UPS monitor port and a higher-performance DP83902 Ethernet NIC, still had two paddlecard slots, but these slots were widened to 60 pins and could now be part of a bus connected to an external chassis. Alpha Micro had long sold the AM-990, a large capacity case (in this image as used for the AM-4000, though I apologise I don't have a better image of it) and the AM-990 Jumbo, which was even larger. A new higher-performance serial card was developed to take advantage of the widened paddlecard slots, an optically-isolated eight-port card called the AM-359. Twelve AM-359s could be installed in the AM-990, yielding 96 ports when connected to a fan-out in one of the AM-319-20's paddlecard slots (the four on-board ones made an even hundred); the Jumbo could take another twelve AM-359s for another 96 ports connected to the second, a whopping total of 196 serial ports when combined with the base four. If you needed even more, the AM-3501 sidecar chassis could take you well beyond. There was no point in supporting the 68EC030 with such a monster: this new Eagle, officially the Eagle 550 Super Eagle, was 68040 or bust. that large, a Super Eagle in the standard case could support up to 60 ports, four on the AM-319-20 and then seven AM-359 cards in the usual position. The E550 Super Eagle additionally came as a separate upgrade kit for the E500 and the few E400s that sold, essentially a system board swap, though when sold as a turnkey system it was always with the 40/80MHz CPU. The E550 introduced a new Seiko timekeeper chip as well which not only maintained the time but also the "CMOS settings," the first Alpha Micro with an on-screen setup utility in ROM allowing boot configuration. Subsequently the company was tardy once again in adopting Motorola's newest 68K CPU, this time the superscalar 68060, which had come out in 1994 aimed squarely at the Intel Pentium but didn't reach Alpha Micro customers until mid-1997. This took two forms, a new 66MHz '060 Roadrunner upgrade option for the E550 Super Eagle and the AM-4000 (lesser Eagles need not apply), and a new AM-6000 large system. Interestingly, the AM-6000 is strongly based on the E550, reflected in its internal designation as the AM-3500-6000 making it a "stealth" Eagle. The '060 Roadrunner not only included the new CPU but also 64K of L2 cache, support for up to 256MB of RAM in four SIMM slots, and 68-pin Fast and Wide SCSI-2 using the NCR 53C770. along with E100s and a smattering of E500s and Super Eagles. However, it was not lost on company management that Motorola believed the 68000 family was fast approaching a performance wall. This was made most clear by their then-enthusiastic participation in the PowerPC AIM alliance, but also the rise of ColdFire, which Motorola had first announced in 1994 as well. ColdFire was in its own way Motorola's oblique admission that 68K was losing desktop competitiveness to x86, an attempt to scale the ISA down to embedded markets where its familiarity could be an asset. Approximately 20% of the instruction set such as BCD and certain addressing modes were eliminated, meaning the canonical ColdFire could not be fully binary-compatible with any extant 68K. On the other hand, such cuts enabled the core to execute nearly every remaining instruction in a single clock cycle, and the initial die was a miniscule 4.4mm² at 0.5μm, a third the size of Motorola's own 68300-series CPU32+. Some amount of this work was done by altering the microcode of the 68040V, a fully static 68LC040. Mindful that ColdFire's incompatibility might impair adoption, Motorola chose to create a bridge first-generation chip from this altered 68040V where omitted user mode instructions were left in, demonstrated on die photos. While the new chip had smaller 2K instruction and 1K data caches than the 68040V, and the MMU was also eliminated, this deviation from spec was still sufficient to run regular 68EC040 code at the user level. Motorola called this first-generation ColdFire chip the MCF5102, produced on a 0.6μm process, and introduced it in 1995 drawing 0.8W at 20MHz and reaching 33MHz. Clock-for-clock there was no way this chip could eclipse an '060, and the emerging "true" ColdFire 520x series couldn't run existing Alpha Micro software, but the MCF5102 was still faster than an '030 and nearly as fast as an '040 — in fact, we'll prove it. On top of that it was cheaper and AMOS didn't need the MMU anyway, making for a plausible mid-range machine that wouldn't imperil (much) sales of the E500 or E550. alt.sys.alpha-micro, though credit must be given to John F. G. Leighton, then Alpha Micro's VAR marketing manager, who chose to print the review unedited in marketing materials, even Rod's gentle complaints. Since this is the only E450 I have personally laid my hands on, we will be referring to his comments liberally as a point of comparison, and consequently the E450's history is probably the best documented of any 68K Eagle. It rolled out to users in October at the annual meeting in nearby Riverside, California. This particular system was a gift from someone who inherited it from an 9-1-1 emergency dispatch centre and wanted to find it a good home, another way that running an Alpha Micro-powered web server has paid off. I was able to quickly get into the system (if it's not clear by now, I love hacking into Alpha Micros) and reconfigure it, and it had lurked as the E300's work spare and a test unit since then. Like the E300 it has a bootable tape drive, but this time it's a more modern DDS/DAT. E450, and it claims not to have an SSD at all (untrue). As such, I'm not sure I can believe the stated manufacturing date of September 2002, and at least one date inside directly contradicts it. It's possible this was a case with a transplanted board. 1999 as prerequisites for the AM-370, an unidentified off-the-shelf 100Mbit PCI NIC that goes into the "slot" at J5. To access these PCI slots, that rear panel I pointed out needs to be removed. The AM-370's availability implies all shipping E450s should have had them by then — there was even an alleged board-swap program to do so. I've yet to find another one, so I don't know if that's true, but it would be interesting to find out because with this card or the OEM equivalent you would have two fully operational NICs and multihoming was reportedly supported. I also don't know what's going on with the unpopulated "option connector" at P5 to the right/east of the AT power connectors. other slots. The E450 is one of only a few Alpha Micro systems that can accept an optional external L2 cache, though as mentioned this cache is only enabled for instructions, and the form factor does not match any PC cache stick — in fact, it's the same as a 72-pin SIMM, so don't put the wrong one in the wrong place (Rod also objected to this). The only size supported is 64K, the same cache stick used for the AM-6000 and the '060 Roadrunner, part #PDB-00701-00. I've never seen this cache stick and comparison of his numbers with my cacheless E450 suggests it only yields around a fourteen percent boost, not nothing but not much, likely because it can't do anything for the data cache (though stand by for a very important observation on actual clock speed). The E450 also has two 72-pin SIMM slots, which need not be paired and support up to 256MB, though as with the earlier systems the machine needs to be jumpered to tell it how much is there. The tag on the one in J11 (service order 13009, apparently) is dated January 18, 2002: that makes this machine at least eight months older than its alleged manufacturing date, and to have received an upgrade suggests it's even older than that. Between the two sticks this system has 72MB of RAM. Below/south of the RAM SIMMs are the three paddlecard slots. Also in this image is another obvious non-populated area: a pin-grid array marked "PGA040" at U89 in the northeast/upper right hand corner. That sounds like somewhere the CPU would go, and the footprint looks like an '040. So where's the actual processor? fast is it doing it, though? While Rod's review stated his prerelease system was apparently running at 33MHz, the oscillator closest to the CPU can be seen clearly in this photograph, and it's ... 25MHz. There are no other crystals on the board except for the serial port one you saw earlier, the official marketing announcement has a board layout that also clearly labels this crystal as 25MHz, and nothing in the MCF5102 user's manual says the chip does anything tricky with the clock. As it happens, the only place in Alpha Micro documentation where the E450's CPU speed is given is Rod's review: everywhere else, even the data sheet, simply says it's a ColdFire and nothing more. Since mine is only 14% slower than his, and his had the cache, his can't possibly have been running at 33MHz either. The E450 is a 25MHz ColdFire, full stop. In a backwards way, however, this is nothing less than validation of how performant early ColdFires could be. Recall that our E300, a 40MHz 68EC030, had a "CX" computing index score on the SI.LIT benchmark of 36.9. The same benchmark on this E450 with a 25MHz MCF5102 gets a score of 59.9, and Rod's with 64K L2 came in at a whopping 68 (Alpha Micro said 68.5; either one is around 14% higher). By contrast, the E550 Super Eagle, with a full 40MHz ("80MHz") 68040 Roadrunner clocked 60% faster and 32K of L2 cache, officially gets ... 79.9 (note from the future: my figure is 83.6) — the full cached-up faster-clocked 68040's performance on the same code is only around 33-40% better, and just 16-22% or so if the E450 has its cache too. Put another way, the CX/MHz ratio of the faster 68040 was right around 2.0, while the CX/MHz ratio of the MCF5102 is 2.4 without the cache, and almost 2.75 with it. Likely because the lower clock speed would have looked bad in marketing materials, similar to why General Magic never mentioned the clock speed of the DataRover 840, Alpha Micro simply chose not to mention it either. Still, this machine's surprising efficiency proves ColdFire, at least early on, definitely had legs. I'm not sure how Rod got it wrong except that an earlier version may indeed have run that part, though with these numbers, if there had ever been a production 33MHz E450 it might have seriously endangered sales of Alpha Micro's remaining '040s — perhaps that's why they didn't use it even though the faster part existed. Best guess is that the AM-138 was originally designed for the 68040 and then quickly retrofitted for ColdFire, leaving the PGA region as an "R&D test point" (as documented). our prior entry, and he referred me to a longtime Alpha Micro vendor that they still partner with for existing installations. It took a few months, but this vendor was able to locate what appeared to be another E300 with working boards and we negotiated a price and getting it shipped. "everything console" connected to the top left port (G1) via the dongle at the typical speed of 19200bps. Good, it booted fine, we got a dot prompt, we can get into it, networking is already configured, and (as is typical for most Alpha Micro installations of the era) there is no password on the operator account. I powered it off and now that we know where the system thinks the console is, we'll get a proper self-test readout. I powered it back on with the reset button held in and the self-test came right up. The self-test can autosense the baud rate by mashing the spacebar when the front LED flashes "5b," and then the test runs, with the LED showing the current state and additional details sent to the serial port. ---------------- SYSTEM SELF-TEST ---------------- Version 2.1(120) Prom Rev. N00 for the AM-174 board. polling complete. Boot configuration: Processor - 68040 Memory detected - 32M bytes Primary serial ports - 4 SCSI Controller press [space] to bypass memory test MEMORY TEST passed - 32M bytes TIMER TEST passed SERIAL PORT TEST Primary serial ports - 4 Port # 0 passed Port # 1 passed Port # 2 passed Port # 3 passed SCSI Controller Controller Self-test passed SCSI drive Self-test passed Find diagnostic cylinder passed Write/read test passed 40?! This is not a Eagle 300! We need to open this thing up. didn't expect was the CPU board on the bottom: it's a full 68040, just like the test said. Bclk for the bus clock, and then a second exactly twice as fast labeled Pclk as the so-called processor clock. In the 68020 and 68030, which accept a single clock signal, their internal ALU runs at only half the bus speed such that the 40MHz 68EC030 in the Eagle 300 actually has an ALU running at just 20MHz. For the 68040 Motorola removed this limitation to run its ALU at full bus speed, but the chip designers also studied trace data to optimize for the most common instructions, implementing a 7-stage pipeline where most effective address calculations and fetches occur with no penalty. The upshot of this was to cut most instructions' cycle count in half or more. The 2x processor clock is truly used, but not to speed up the ALU, so it's wrong to say the 68040 is "double-clocked." In a two-part 1990 article in IEEE Micro, Motorola explains that "Pclk provides timing reference points within each Bclk period," employing it for synchronous sub-cycle timing, and furthermore explicitly states that "all internal operations cycle at the Bclk rate." Still, the fact this clock signal was present at all gave Apple an excuse to tout both timings for '040 Macintoshes, and Alpha Micro cheerfully reported just the faster one, even though the chip only appears to run at that comparative speed from its larger 4K L1 cache, unhindered ALU and reduced cycles per instruction. On this board, Pclk is provided by the same 80MHz crystal we saw on the AM-172, divided down by two to yield Bclk in the same way the 68EC030 board does for its single 40MHz clock. (For the E400's AM-174-00, this crystal would have been 66MHz divided down to 33MHz.) The single parity FPM SIMM slot and 16MHz and 50MHz oscillators are also present, as well as the same 53C710 SCSI controller, here a genuine NCR part. However, new for this board is 32K of L2 cache at the upper right/northeast corner, implemented with two IDT 71B74 8K cache-tag RAMs together providing 29 bits (512MB) of address comparison, and then four Cypress CY78C185 8K SRAMs for the cache itself. Remember, however, that in AMOS all cache is I-cache. Effectively this 40/80MHz AM-174 makes our new system a full Eagle 500, so why is it labeled as "only" an E300? I don't how how these systems originally shipped from the factory nor whether the E500 designation actually appeared on the back, but Alpha Micro did run a promotion in late 1997 where you could upgrade any Roadrunner '030 to a Roadrunner '040 by swapping the CPU board. My guess is this is one of those systems, and because that upgrade kit wouldn't have changed the plate on the back itself, the reseller simply noted it to be a working E300 and sold it to me as such. While that wasn't exactly what I was hoping for, it's a really nice bonus, as evidenced by the system benchmark (taken on the SCSI hard disk it shipped with): That score officially makes it the new fastest Alpha Micro in the shop by far (this is where that prior 83.6 number came from, compared to the E450's 59.9 and E300's 36.9). It seemed a shame to carve it up as spare parts, so let's have a little look around. A surprising thing about the system configuration file (SYS:AMOS32.INI, a/k/a AMOS32.INI[1,4]) is that only one terminal is actually defined, which makes you wonder what those two RJ-21s are doing. Best guess is that this machine passed through a couple hands and ended its prior service as a single user's toy, much as my own machines are now. In a related phenomenon an annoyingly small number of terminal types are defined, all inconvenient, likely to save memory. On the other hand, the full AlphaTCP suite (based on SpiderTCP and SpiderStreams, best known as the Windows NT TCP/IP stack before 3.5) is defined and present, and we saw it running before, so we ought to be able to make use of that. That's its IP address, and we saw Telnet was running (TCP:TELNED.LIT), but there's a snag: The TCP:CONFIG. file sets up TCPEMU, AlphaTCP's master daemon, acting as its service description file (really a sort of up-script). This line for the Telnet daemon causes an automatic log-on from a Telnet session and inconveniently forces the FWYCOL terminal type, intended for a real Wyse WY-370. That's also the terminal setting for the single serial port which our "everything console" doesn't speak, meaning I can't visually edit anything without making a big mess. Ironically, that AM-75 colour head my E300 uses is itself a modified WY-370, but no longer speaks that terminal emulation either. But we have another option! Now knowing its IP address, I set up a small wired network to my MacBook Air. Although some terminal programs like Kermit 95 can speak WY-370 over Telnet, using MacWise — now freeware and runs on Tiger and Power Macs all the way to Tahoe on Apple silicon — I managed to discover that its TeleVideo 925 emulation will partially match FWYCOL. This was just enough to, with some care, edit TCP:CONFIG. and remove all the defaults so that I could manually select the terminal type on Telnet login. I then reset the FTP user credentials in TCP:FTPUSR., uploaded a copy of ANSI.TDV from the Eagle 450, and changed the TDVDEF line in a test copy of SYS:AMOS32.INI to allow it as a terminal type, which at last got me a proper session. I'm not sure of this system's most recent owner and the seller didn't know either, but there were two interesting domains in its TCP:HOSTS. file (identical to /etc/hosts) for that IP address. One domain name belongs to someone who appears to have been a recording engineer (!). This domain still exists, but is only partially functional, so I've chosen not to link it here. The other domain name was for a personal genealogy site, now parked, and that site appeared to be what it was currently offering via the Web server on HTM:, mapped to PPN [7,77]. However, because the HTML files were not on an extended directory device, I can't tell when the site was created because the old AM file system doesn't preserve modification times: Looking up this domain in the Wayback Machine, it seems to have been active in the early 2000s. Still, not bad assuming it was still serving it then. differently on the AM-172 and AM-174s, so it seemed safer just to never separate them in the first place. I wasn't even going to move the SSD and hard disk — since TCP/IP networking was already set up on the E500, I could just upload the site to the E500's hard disk instead. Only the E300's power supply, serial port cards and Tandberg QIC streamer would stay. Once the new transplanted system was working, then I'd see about doing the ZuluSCSI upgrade again. It tried to boot. Startled, I powered it off, connected the everything console, and turned it back on with the reset button held in to force a self-test. Except for the missing hard disk, it passed the self-test — even the SCSI controller tested good. I decided to push my luck and connect the ZuluSCSI, and this time it did throw a 2d. I freaked out again, powered it off, let it sit and then gingerly turned it back on. It still did it. However, when I disconnected the ZuluSCSI, it went back to trying to boot, and a repeated self-test was still clean. This was clearly new behaviour — beforehand, it wouldn't do anything, not even enter the self-test, let alone attempt booting. Recall that error 2d had two mentions in the manual, the second one referencing the primary and secondary boot devices. Since the self-test said the SCSI controller was fine, this made me suspicious that there was something about the ZuluSCSI's configuration the machine didn't like. Knowing some systems can get finicky about sluggish devices immediately after power-up, I reconnected the ZuluSCSI and powered the E300 back on. Code 2d duly appeared, but this time instead of turning it off, I hit the reset button just to see what it would do. SI.LIT had actually dropped to around 10, which was 33% slower than its original hard disk. .scsi Dispatched SCSI port: SCSI id 7: (reserved) SCSI bus host adaptor SCSI id 6: No device or unable to report SCSI id 5: No device or unable to report SCSI id 4: No device or unable to report SCSI id 3: SCSI-2 (tape) TANDBERG TDC 4200 =08:01CREATED12119 SCSI id 2: No device or unable to report SCSI id 1: No device or unable to report SCSI id 0: SCSI-2 (disk) ZULUSCSIHARDDRIVE 2.3BZuluSCSI .si dsk0: SI--AMOS System Information, (C) Copyright 1990, Alpha Microsystems Inc. Version 3.0(114) Computer Type: Eagle Main Processor: 68030 Co-Processor: None MMU present: Yes Operating System: AMOS 2.3A(484) Boot PROM revision: M00 Number of SSDs: 1 Total Memory: 16384 K-bytes Resident Monitor Memory: 6218 K-bytes Computing Index (CX), relative to AM-100: 36.8 48 bit FP Index (4X), relative to AM-100: 36.3 Floating Point Index (FX), relative to AM-100/L: 5.6 Disk Index (DX), relative to ST-506: 41.2 .si dsk0: SI--AMOS System Information, (C) Copyright 1990, Alpha Microsystems Inc. Version 3.0(114) Computer Type: Eagle Main Processor: 68030 Co-Processor: None MMU present: Yes Operating System: AMOS 2.3A(484) Boot PROM revision: M00 Number of SSDs: 1 Total Memory: 16384 K-bytes Resident Monitor Memory: 6218 K-bytes Computing Index (CX), relative to AM-100: 36.9 48 bit FP Index (4X), relative to AM-100: 36.3 Floating Point Index (FX), relative to AM-100/L: 5.6 Disk Index (DX), relative to ST-506: 100.4 six times faster than the original hard disk). There's no obvious caching in the Blaster's firmware that I could see, and although the AMOS system-wide disk cache was on, the test is supposed to be unaffected by OS-level caching. On the other hand, when I rebooted AMOS from software, its score went back to 41 and 100 thereafter. More on this phenomenon later. Termination power was sufficient to power the Blaster. But what the Blaster didn't fix, even with its later firmware, was the 2d code the E300 kept throwing from a cold start. Although booting after a manual reset was still fine, it refused to start after a power cycle without assistance, which I need it to be able to do if there's a power outage when I'm not around. .ini file, but since the issue appeared to be what the E300 thought was the secondary device and I knew the streamer was connected and working, I had a look at the back boot DIP switches first. The previous setting was #1 and #3 on, which would attempt a boot from the (non-existent) floppy drive first, and then try the SCSI hard disk. This had always worked before, but we have no floppy drive and I'm not likely to find an AM-219 anytime soon, so I tried the other boot position where it attempts a boot from the streamer first — again, known good electronics — by switching #4 on. And that worked: now it boots reliably. The conversion is complete. So, with the E300 resurrected and finally successfully converted to solid state, let's really push our luck here ... by doing the same with the others! (I should note I excluded the E100s this time around; I haven't found a special task or physical location for them yet.) SI.LIT disk score of 30.9. For this system I bought a ZuluSCSI Wide, which tops out at 34 MB/s read and 15 MB/s write, and which I already use in my Apple Network Servers with a similar NCR 53C825A. .scsi Dispatched SCSI port: SCSI id 15: No device or unable to report SCSI id 14: No device or unable to report SCSI id 13: No device or unable to report SCSI id 12: No device or unable to report SCSI id 11: No device or unable to report SCSI id 10: No device or unable to report SCSI id 9: No device or unable to report SCSI id 8: No device or unable to report SCSI id 7: (reserved) SCSI bus host adaptor SCSI id 6: No device or unable to report SCSI id 5: No device or unable to report SCSI id 4: No device or unable to report SCSI id 3: No device or unable to report SCSI id 2: SCSI-2 (tape) HP C1533A A907 9 SCSI id 1: No device or unable to report SCSI id 0: SCSI-2 (disk) ZULUSCSIHARDDRIVE 2.3WZuluSCSI .si dsk0: SI--AMOS System Information, (C) Copyright 1990, Alpha Microsystems Inc. Version 3.0(114) Computer Type: Eagle Main Processor: 68040 Co-Processor: None MMU present: Yes Operating System: AMOS 2.3A(484)-15 Boot PROM revision: D00 Number of SSDs: 1 Total Memory: 73728 K-bytes Resident Monitor Memory: 4366 K-bytes Computing Index (CX), relative to AM-100: 59.9 48 bit FP Index (4X), relative to AM-100: 58.2 Floating Point Index (FX), relative to AM-100/L: 7.9 Disk Index (DX), relative to ST-506: 51.0 .si dsk0: [...] Disk Index (DX), relative to ST-506: 52.2 . the last Alpha Micro article we booted our AM-1200 desktop system using a BlueSCSI attached to its external 50-pin Centronics-style SASI port, which with some tweaks to the settings file can be made compatible enough for its very old bus. But I'd like to use that device for other things, so we'll put the old ZuluSCSI card — more than fast enough for this thing — inside. To avoid me having to dismantle it every time I want to switch the disk image, I disconnected one of its unused serial ports and threaded a USB cable there. SUB0:. It's as fast as the BlueSCSI was, probably because both devices can easily saturate its slow SASI bus: AMOS 1.4 misdetects its 68010 as a 68000 (AMOS 2.3A detects the CPU correctly), but like the E450, there was no second test bump either. "everything console." I should point out that the E500 has a slightly later version of AMOS than the E300 and E450 and we get a little more explanation with the bus readout: While all three systems support synchronous SCSI, this version of AMOS actually reports it, along with the width (8-bit, because it's only Fast SCSI, not Wide). Now, what about performance? The ST32272N we replaced is a 7200rpm drive while the ST310151N in the E300 was only 5400rpm, thus accounting for the E500's better baseline disk score, and the E500's faster CPU probably explains its slightly higher first-run result of 46.3. But the second run is even more lopsided than what we saw with the E300, a massive 180.7. Since two of the systems were doing it, it was time to dig in a little more. The ZuluSCSI Blaster has a debug mode switch which echoes status and current operation to a connected machine over USB serial at 115200bps, so I hooked up both the E500's serial console and the USB port of the Blaster simultaneously to the MacBook Air to watch what SCSI operations occurred during the benchmark test. very unusual: there wasn't any. In fact, even though the baseline score had sunk down to a dismal 10 or so because of all the debugging data it was emitting, the second run was still a blistering 180.7. This really sounded like operating system caching, but except for the AM-1200 where I wasn't running it to save memory, the other three systems were running the standard disk cache as virtually any performance Alpha Micro would — and allegedly SI.LIT should be unswayed by it. For some reason the E450's cache configuration wasn't locking UFDs (user file directories, i.e., PPNs), but turning that off on the E500 and E300 didn't make a difference, and all three were caching everything else including the MFD (master file directory). However, when I turned off caching altogether at runtime (using the CACHE.LIT tool and disabling with OFF), though the scores got really low, they were now consistent from run to run. Do note our observation isn't enough to fully explain the E450, which also runs the OS disk cache, but didn't have a second run bump. If you disable the cache on the E450, although its overall score declines, it still remains consistent from run to run. One possibility is that the driver for its later SCSI controller just isn't as aggressive. Although the overall issue certainly calls into question how useful SI.LIT is as a disk benchmark, despite being likely the only Alpha Micro benchmark tool you can expect most recent systems to come with, the question then becomes how comparative disk performance on an Alpha Micro should be measured. Was it still fine for me to continue with my usual practice of leaving the cache on and testing immediately after boot? It's probable that there'd be little in the cache by that point, whatever would be there would likely be similar from system to system (assuming the same version of the operating system), and likelier still that whatever was present in the cache wouldn't be very germane to SI.LIT. Under my current knowledge of AMOS I think these numbers are still broadly comparable; I just have to keep in mind that the score on subsequent runs is likely to be bogus. precisely even with our E450 here). The E100 was discontinued shortly afterwards in 2001. SI.LIT CX score of 816 (!) on dual Athlon 2800+ CPUs. Later AM-113 SuperFalcons were just serial ports and a socket for the SSD; the main system was now more than suitable to service them, and Motorola wasn't making any more 5102 CPUs either. The Eagle 800 that same year ran the same technology in miniature, bringing the great experiment to a close with the discontinuation of the last E250 and E450 systems, and today's systems sold by the reformulated Alpha Microsystems LLC use the same x86-based architecture. Over their production lifetime, analysis of known serial numbers suggests around ten thousand 68K Eagles were ultimately sold, and now I've got five of them. Rest in peace, Rod. They're still great machines.

44 minutes ago • 1 votes
CalVer 26.0: 10th Anniversary Edition

A decade ago, a little bit of history was made. I didn't realize it, but a colleague made a great point, one of those real mind-changing points that seem too obvious to admit same-day. But, the next day, calver.org was born. At the time my team maintained the Python infrastructure for eBay and PayPal, and we were stuck deciding whether we were really ready for a "major" 1.0 release. Semantic Versioning was the only game in town and "major" means "big", right?! Thankfully, a wiser colleague mentioned: Ubuntu and Twisted don't struggle with version number debates. They slap a date on it and keep shipping. In fact, their date-based versions were even better because you always knew where it stood, in terms of updatedness and support. The only problem is that no one really knew about it. Somehow, this problem solving versioning alternative, arguably as old as history itself, had gone nameless for millenia, conspiring to make me feel foolish in an office meeting. Never again! Ten years of adoption Fast forward 10 years, we've seen CalVer adopted by Apple, Nvidia, JetBrains, and countless others. (We have a timeline!) The site may have more inbound links than any other project of mine. Apple made the biggest jump, at WWDC 2025: iOS went from 18 to 26 macOS from 15 to 26 watchOS from 11 to 26 and visionOS from 2 to 26 All landing on one, consistent number like a car's model year. I still remember the texts from the Venn diagram fanbase of my friends who love Apple and reasonable versioning. No such texts from when NVIDIA announced calendar versions across the GPU Operator, RAPIDS, and its monthly NGC containers, but still very cool. Open source, too: Home Assistant, pip, CockroachDB, and yt-dlp all ship on dates, with plenty more on the users page. The conversation even reached the language core; PEP 2026 proposed versioning CPython as 3.YY, and it almost happened, too. And it's never too late, time marches on! Fixing the notation But I don't think I got every detail right from day 1. That's the main motivator for CalVer 26. It's high time to start righting a couple idiosyncratic token design choices, starting with some additions: Meaning Before 26.0 26.0 Full year YYYY YYYY Short year (6, 16) YY YY Zero-padded year (06, 16) 0Y 0Y Short month (1 ... 12) MM M Zero-padded month (01 ... 12) 0M 0M Short week (1 ... 52) WW W Zero-padded week (01 ... 52) 0W 0W Short day (1 ... 31) DD D Zero-padded day (01 ... 31) 0D 0D Seeing double First, the doubled letters. From the first version (16.6), MM and DD meant the unpadded month and day, which reads backwards to anyone who knows date formats (ISO 8601's YYYY-MM-DD, Java, moment.js, day.js), as some community members correctly pointed out. I was ready to flip them, until I checked what people actually use: most projects with a YY.MM.MICRO badge (conda, Twisted, Ansible's tooling) don't pad, and more than a dozen other version management tools (like bumpver and bump-my-version) implement the old meaning. So, it's too late to flip MM's meaning. Instead, 26.0 deprecates it and offers a more explicit and hopefully clearer option: M is the short month, 0M the padded one, and MM is a technically-retired synonym for M. In case you're wondering, the explicit 0M was me being overinspired by Ubuntu's approach, perhaps: 6.06 pads its month but not its year, and YY.0M says exactly that. To pad or not to pad I think it's worth a detour into why padding is even a thing anyways. It's become important now that new ecosystems have emerged that enforced SemVer formatting semantics, and I wanted clear guidance about on the spec site. SemVer forbids leading zeros outright, so Cargo rejects 26.04.0 and Go modules reject v26.04.0. Even Python's packaging spec normalizes leading zeros away, so you can tag 2026.08.19 if you want, but PyPI will still show 2026.8.19. NVIDIA's GPU Operator docs put it this way: "Zero padding is omitted for month to be still compatible with semantic versioning." CalVer was always intended to drop in where SemVer was used. So 26.0 recommends unpadded (YYYY.M.D) as a sane "pure" default for software libraries. But libraries are not the only objects of versioning schemes. The exception is a version that becomes a filename, an image tag, or an object-store key that gets listed lexically. There, padding keeps 26.10 sorted after 26.09, which is why Ubuntu, NixOS, and NVIDIA's own NGC containers pad. More evidence of teams designing their versions. We love to see it. Our FAQ has a longer discussion of the padding issue, as well. Optional segments There was never any rule against them, but 26.0 makes optional trailing segments more explicit with square brackets. Now, yt-dlp's scheme can finally be written down: YYYY.0M.0D[.MICRO]. For the CalVer badges I could find on GitHub, they all stay valid for now. I've got a note on the deprecated spellings and a new copy-paste badge section for new ones. What else is new? It's always a great time to add more citations to the site. A spec changelog; the spec now versions itself: 16.6, 19.7, 26.0. A FAQ: breaking changes, same-day releases, and padding. The users page, rebuilt by category, with past users of note (schemes change; that's fine) and tooling. Case studies: Apple and NVIDIA in, yt-dlp replacing youtube-dl. Much of the thinking behind these changes happened in the GitHub issue tracker over the years, and 19 or so issues close with this release. That's where ideas for CalVer should go, so by all means, open an issue, and we'll get it sorted! In due time, of course. In closing, I can't believe I still love belaboring these numbers so much. Thanks to all (but especially Mark, Glyph, Hugo, issue reporters, translators, and maintainers) for the discussion, and ultimately making the most timely versioning system a timeless classic. See also 2016 announcement Designing a version My Yap on Why CalVer beats Semver

19 hours ago • 1 votes
"You didn't do it right"

Four sincere attempts at OKRs, four failures, and every time: "you didn't do it right." Maybe the framework doesn't fit you -- so how do you find one that does?

yesterday • 1 votes
We solved SQLite's single-writer limitation

Multiple concurrent writers. Multiple processes. Same SQLite. No modifications.

3 days ago • 1 votes
If your team is happy, are you doing a good job?

Brilliant jerks, ZIRP-era managers, and how psychological safety lost the plot. Part 3 of my conversation with Dr. Cat Hicks.

4 days ago • 1 votes
📚 BoredReading

You seem to be enjoying this.

Join free to unlock everything.

Create free account

Already have an account? Sign in