Hi all,
This is a long post, so TL;DR: I’ve rebuilt enough of Edinburgh’s EMAS3 Operating System to get the loader, supervisor, Director, spooler and mailer running on Hercules. It’s still not fully functional due to system processes failed to start. Project files and instructions are avaialble at:
LLM is assisted me in coding but not writing this post. I have carefully reviewed LLM generated code and make sure there is no slop, I also discussed how LLM assisted me over the process in the post.
I’m a Computer Systems PhD student at the University of Edinburgh, where I also did my undergrad. I’ve always been interested in older systems, both out of curiosity and for ideas I might borrow for my own work.
I learned about EMAS and Edinburgh IMP at the Informatics 60 Years of History event. There’s also an earlier thread about EMAS here. I wanted to try it myself, but there wasn’t a straightforward way to run it. It felt like a missed opportunity: here was an operating system developed at my own university that I knew almost nothing about. I’ve wanted to get it running ever since.
The IMP compilers I found weren’t in a state where I could use them to bootstrap EMAS. During my third year of undergrad, the wonderful Compiling Techniques course, introduced me to xDSL. It’s a compiler framework written in Python, also developed here at Edinburgh. Having that available made writing an IMP compiler seem much more achievable. I started with a RISC-V target, wrote lexers and parsers for IMP77 and IMP80, and got Hello World running. Then other work took over and I put it aside.
Recently, feeling burnt out with mobile wireless research, I picked this up again as a change of subject. I discovered that xDSL now had an LLVM backend. That meant I could lower IMP to LLVM IR and let LLVM deal with instruction selection, register allocation and machine-code generation. It removed a big chunk of the work that had been left in my original attempt.
LLM coding tools had also improved enough to take on a lot of the work. I brought back my old lexer and parser and got a new backend and runtime library working well enough to run simple test cases. From there, I could explain the high-level design to LLM coding agent and let it iterate through the many corner cases using old IMP tests.
One design choice was to keep INTEGER at 32 bits and LONG INTEGER at 64 bits, while making ADDR return a pointer-sized LONG INTEGER on 64-bit targets. This is violating the IMP80 spec, but it follows LP64 data model used by other languages. For code that needs different declarations on different machines, I added overrides for ordinary IMP constants used in constant %if statements. The source can still declare a default for older compilers to use.
I also wanted IMP and C code to be able to call each other. The ABI uses the target’s C calling convention, with an imp_ prefix for ordinary external IMP symbols and explicit aliases for calling existing C functions. IMP strings keep their length byte, and generic NAME and array parameters use documented descriptors that C code can construct.
The result is ximplang, now available at:
There was some discussion here about bootstrapping EMAS a few years ago. My approach is to use ximplang to compile the historical IMP compiler into a native Linux executable. That executable retains the original IBM code generator and compiles the EMAS sources into IBM object files.
Unforunately LLM is not so good at dealing with IMP code, persubalely due to lack of training material. I wrote/fixed most of IMP code by hand, but it’s helpful to have LLM on help me fixing syntax issues based on compiler errors given that I’m not that familair with the language.
The historical compiler needed some care to run on a modern host. First I had to write a lot of supporting routing and wrappers to get the compiler running on Unix as it’s origitally designed to run on EMAS.
There a a couple of missing code pieces like opcode list files for the compiler and some wrapper files and I was managed to restore them based on their interfaces.
The compiler stores pointers in INTEGER, so it won’t work on 64bit target. I quickly fixed that, but then I found it also uses INTEGERs for IBM addresses and packed fields. I had to separate the host pointers, which need to be wider, from values that must stay 32-bit. Record overlays also assume big-endian byte order in places: on a little-endian host. To deal with endian and word size issues, I just try to get everything working on a PowerPC 32bit BigE ndian host first, and then gradually fix x86_64 support by comparing the output.
Floating-point constants needed similar attention. The host uses IEEE floating point, while the IBM target expects hexadecimal floating point, so copying the host’s bytes into an object file gives the wrong value. I also fixed the handling of 128-bit constants and preserved the IBM bit patterns of raw constants.
On the EMAS side, I had to get the disk layout, device assignments and console handling to agree with what the system expected. Filesystem initialisation needed to leave enough room for the system images, and Director’s startup checks needed two filesystems configured. A lot of Python scripts are written to deal binary formats and provisioning the disk.
The old 3270 console code needed a compatibility adjustment for screen addressing through Hercules.
There are far too many details I have dealt with to list here, but the end result is that EMAS now boots on Hercules. It’s not a complete system yet, but it’s a start. Mailer process failed to start for some unknown reason.
I’m too excited to share my progress, so I just asked LLM to go over my shell history and make a set of makefiles and scripts out of it so the process can be reproduced.
All the code and instructions are available at EMAS3-Revived. I hope it will be useful to others who want to explore EMAS. I’m also happy to answer questions about the project and help others get it running.
I think there are still a few people from the EMAS days around here. If you used it or worked on it, I’d love to hear from you whether it’s technical details or just memories of what it was like to use. I’m still working towards usable terminal session, and any pointers would be very welcome

