VOGONS


First post, by Pling

User metadata
Rank Newbie
Rank
Newbie

Hi everyone,

I would like to introduce a project that has been in the making for nearly three decades: GALAXEUS. It is a custom arcade engine written entirely in pure 16-bit x86 Assembly, specifically optimized to push low-end vintage hardware to its absolute limits.

The main goal was to achieve an uncompromising arcade feel on the slowest 386 system I could get my hands on: a cache-less AMD Am386SX-33 system with a narrow 16-bit bus and using only 8-bit ISA cards. The engine runs at a rock-solid, fixed 67 Hz / 67 FPS with zero frame drops, driving a standard 8-bit ISA VGA card at a highly customized native resolution of 544x480 in 16 colors.

It delivers an authentic, industrial-grade arcade experience straight out of the early '80s - not just from a technical standpoint, but in its presentation. The engine features a fully functional attract mode that cycles through different gameplay demos, a high-score player TAG input, an arcade-accurate test and diagnostics screen, dedicated coin impulse handling, and full 1 or 2 player game modes. You could drop this setup into a physical arcade cabinet and hardly anyone would notice the difference from an original early-'80s machine, except for the significantly sharper screen resolution and higher refresh rate. 😉

To prove it runs on real iron, I just uploaded a gameplay video showing the current state of the engine:

https://www.youtube.com/watch?v=UHV5c2CAAtw

(Please excuse the amateur video production; it's my first YouTube video ever, and I am definitely no 'stage animal'. I am not active in any forums, and let's just say: I don't go out very often 😄)

Technical Details & Cycle-Squeezing Tricks

Getting this level of performance out of an un-cached 386SX required bypassing standard BIOS/DOS interrupts. I used rather aggressive Assembly techniques, many of them developed by myself, e.g.:

  • Extensive Self-Modifying Code (SMC): Used to eliminate slow branches and minimize the binary footprint.
  • Opcode Misalignment: Jumping directly into the middle of instructions for dual-purpose execution.
  • Data Embedding: Embedding variables directly into the code stream to save critical memory bandwidth.
  • Register and Flag Abuse: Heavy use of the somehow nearly forgotten Parity Flag and the undocumented SALC opcode to replace conditional branches with pure logic.
  • PIT Manipulation: Driving the PIT (Programmable Interrupt Timer) up and down like crazy.
  • Alignment Detection: Custom algorithms to optimize data structures.
  • CPU Halting: Completely halting the CPU (HLT) when there is nothing to do on faster systems.
  • Stack Hijacking: The slooow VRAM over the also slooow ISA BUS was the biggest bottleneck. I solved it by hijacking the system stack to handle high-speed bookkeeping for dirty VRAM bytes.
  • VRAM Optimization: The game works with 8-bit VGA Cards @ 67 FPS on an 8.33 MHz ISA Bus. I implemented a very fast alignment detection for word reads and writes from the VRAM. I estimate that with fast 16-bit ISA VGA cards and a higher ISA bus frequency, the engine could easily handle over 100 to 120 active sprites at 67 FPS. I will run a test in the coming days.
  • Custom CRT Timings: Completely avoiding low-res Mode X, manipulating VGA registers of the standard hi-res planar modes directly for the 544x480 output at 67 Hz.

The entire monolithic binary is currently only 57.2 KB. This includes all game logic, graphics, and full 11 kHz 8-bit digital audio samples for the Sound Blaster. I opted out of FM synthesis, as I always found its specific sound slightly weird and depressing — digital samples just bring that authentic, high-energy arcade vibe!

Hardware Integration & Cabinet Readiness

The engine is completely tailored for real hardware and arcade cabinet deployment. It features coin impulse support using the MAME layout, parallel port output for arcade cabinet LEDs (missile status/credits), and an attract mode that mimics actual gameplay sessions.

One of my favorite features during development was implementing a dual-monitor setup: while the main game runs on the VGA screen, real-time hardware telemetry and live debugging info are pushed to a secondary 8-bit ISA MDA monochrome card.

The engine runs completely bare-metal (bootable from a floppy disk or via a 64KB EPROM in a network card socket) and stores high scores directly in the system's battery-backed CMOS RAM in the ROM version. However, for convenience, the codebase also compiles natively into a standard DOS executable (GALAXEUS.COM) that works flawlessly under real DOS, while DOSBox just works "okay-ish".

My experience during development: real hardware absolutely loves Self-Modifying Code (SMC), but DOSBox hates it. I guess the DOSBox Just-In-Time (JIT) compiler simply cannot handle the stress of hotfixing its pre-compiled guts at 50,000 Hz, 🤣.

Furthermore, standard DOSBox, DOSBox-X, and DOSBox Staging all seem to struggle heavily with non-standard VGA timings. I actually had to implement a DOSBox detection routine and patch in a few custom workarounds just to get it running satisfyingly under emulation. It was quite a headache, as one emulator variant does X better but sucks at Y, while another variant does well at Y but completely sucks at X! I spent so much time fiddling around with different DOSBox forks and tweaking their config parameters that I actually started dreaming in INI files, 🤣.

The 28-Year Journey

This project originally started back in the late 1990s when I was a student on a 486. It sat completely untouched in a backup folder from 1998 until the COVID lockdowns in 2020. Over the last few years, after exactly 809 code revisions, I finally stripped it down to its bare essentials and got it running perfectly on my test bench.

The current test setup consists of:

  • Motherboard: Ocean Information Systems (OPTi chipset)
  • CPU: AMD Am386SX-33 (No cache)
  • RAM: 2MB of low-performance DRAM
  • VGA: OTI-VGA Bi034D card
  • Mono: Winbond HGC monochrome clone (for dual-monitor debugging)
  • Sound: Media Vision Thunder Board (Sound Blaster 1.5 compatible) on an 8.33 MHz ISA bus.

There is no public download link available yet as I am still polishing the final build. If the community here is interested, I would love to do some technical deep-dives in this thread, sharing the source code procedure by procedure, discussing the ROM burning process, and showing my custom physical cabinet.

I would highly appreciate your technical feedback, questions, or suggestions!

A note on AI

This project is old, very old indeed. The core logic was written way before AI was anything more than science fiction or procedural tech-babble. There is absolutely NO AI involved in the programming, algorithms, ideas, or optimization tricks. It would have been completely paradoxical to use AI to code anyway, because the entire hate-fun was in the thinking and the making of it — I became totally addicted to that emotional up-and-down rollercoaster during the last few years, as I had to solve new problems on old hardware and invent completely new methods of debugging bare-metal binaries. Plus: AI hates inventing anything truly new, it hates going off the rails, and it absolutely hates Assembly going off the rails.

However, there are exactly two minor exceptions where I used a bit of AI magic:

  1. I originally commented the entire source code mixed in German language, with some passages in horrible English, 🤣. I used ChatGPT to abracadabra those comments into clean English.
  2. I used it to help me wrestle with variable lengths. In 16-bit assembly, names need to be short to save sanity, but still "speaking" enough to be readable.

Aside from translating comments and brainstorming short variable names, every single line of assembly code and cycle-squeezing trick is 100% pure human engineering.

(And Google AI helped me to make me look smart in this text, 🤣 😉)

Greetings,

Pling

Reply 2 of 15, by Pling

User metadata
Rank Newbie
Rank
Newbie

Hello vets,

Thanks for the compliment! I really appreciate that (more than you think).

My background is pretty much defined by the fact that I had absolutely no online presence until yesterday. I usually stay away from modern trends; I am more the guy standing in the background, just watching.

To be honest, I dislike the increasing level of abstraction in every aspect of technology—and life. I work in IT, and I feel that all those rising, endless IT problems we face today are rooted in this cheap abstraction. I am totally stressed out by it. It feels like everything is built on sand, which is just horrible. In contrast, I find my inner freedom in things I can still fully understand down to their very roots. Modern electronics and operating systems can't give me that—modern programming is like cooking with pre-made sauces. It just does not feel real.

With GALAXEUS, I wanted to chop every vegetable and blend every spice from scratch, right down to the bare metal. It was surely about the final result, but it was also about the process—dealing with old hardware and understanding its inner workings. That might not be the reason I started this in the first place, but it is definitely the reason I finished it.

To tell you the truth about why I started it in the first place: when I was an 11-year-old child back in 1981, the magic of computers impressed me deeply. After I saw my very first arcade machine ever—it was inside a showman's caravan at a local funfair in my village—I couldn't stop thinking about it. It was real magic to me, a real wonder before my eyes. The game was Galaxian (GALAXEUS... you see? 😉). That exact moment was where my fascination for computers began, and after all these years, I just had to bring that specific feeling back to life once in a while to keep my mental batteries charged.

Funny thing: in the early years of making GALAXEUS, I was hunting for fast ISA hardware just to get it working. In the later years, I was hunting for the opposite - trying to see how slow the system could go while still maintaining that performance. Classic retro logic: the slower the hardware, the higher the price tag nowadays because of its age, 🤣. You can't make this stuff up -paying extra for slower components. Oh, how the turntables...

For me, in the '80s, there was a real closeness to the hardware: your ear against the case, hearing the tape drive spin, feeling the machine getting warm under your hands, and the static aura of the CRT's glass screen nearly touching your nose. I got my first computer (a ZX81) in November 1982, and those rainy November evenings stayed with me throughout my life: that first-time brightness, and how a small screen could make a little room feel like open space. But the arcade machines in the greasy German Imbissstuben just played in a league of their own back then. At home, we only got pale imitations - clumsy downgrades that never reached that arcade-grade quality. So as a child I always wondered: if you just tried hard enough, if you pushed the machine to its absolute limit, couldn't you achieve that arcade perfection right on your own desk? GALAXEUS grew out of exactly that feeling. I wanted the most control one could think of - the fluid motion, the clean shot - and I wanted to, no, I had to, understand the machine from its roots. Assembly was the only choice: directly optimized, with an OCD-ish attention to detail, where every single line of code is so close to the hardware you can almost feel its heartbeat.

So that's my background. If you asked for my professional background, it is actually much more boring: I am a graduate biologist with an interdisciplinary degree combining Biology and Systems Science. Today, I work in IT at the University of Osnabrück's data center, but I am not a professional coder. I am a full-time System Administrator dealing with storage, virtualization, and backups. I code my own tools in C, C++, and Shell of course. When it comes to professional coding, I am a self-taught autodidact; my real strength is that I have ideas when others only see a dead end.

Greetings from Germany,

Stephan

Reply 3 of 15, by keropi

User metadata
Rank l33t++
Rank
l33t++

this is very impressive indeed - considering you also get this performance with an 8bit OAK vga that is considered junk for anything other than a XT system
kudos!
I will look forward to try it when it gets released!

🎵 🎧 SoundVision PRO,MK1869 , PCMIDI MPU , OrpheusII , Megacard and 🎶GoldLib soundcard website
💾💾💾 Looking for a full version of LIST ENHANCED 2.4y1 by V. Buerg, message me if you have it for sale! 💾💾💾

Reply 4 of 15, by Pling

User metadata
Rank Newbie
Rank
Newbie

Hey keropi,

Thank you! And thank you for the interest. This keeps me going. I am currently preparing everything for the downloads. I'm still polishing up the readme.txt and the game tools need a bit of polish, too. But things are moving along!

Right now, I am going through my precious hardware collection (which my wife refers to as "the junkyard") to test different motherboards and VGA cards. I still even have to re-test my old Sound Blaster 1.0 with all its possible IRQs. It worked perfectly last year, but I've made quite a lot of changes to the IRQ handler since then, so wish me luck! If all goes well, I plan to release the 64k ROM (GALXEUS.BIN), the PC Booter (GALXEUS.IMG), and the DOS version (GALAXEUS.COM) on 16.08.2026. I will also include a full compatibility list of all the VGA cards, NICs (for the Boot ROM), and mainboards that successfully survived my testing 😉

Greetings

Stephan

Reply 5 of 15, by Sneakernets

User metadata
Rank Newbie
Rank
Newbie

This is definitely going on my Commodore SX25 when I get a chance to install and run it.

Reply 6 of 15, by Pling

User metadata
Rank Newbie
Rank
Newbie

Hello Sneakernets,

Thanks for your interest. That gives me exactly the motivation finish the project. I need four more weeks – after 30 years, I refuse to release something that isn't fully baked. This here is just a probe to see if anyone even gives a byte about my stuff.

Look, I know no software is ever perfect. Maybe RollerCoaster Tycoon is, but Chris Sawyer is an Assembler entity sent to us from a parallel universe, and I’m just a mortal with a keyboard. For instance, right now, the BLASTER var in the DOS version has to be fed manually via the command line. It’s ugly. It's amateur. It's totally non-feng-shui, and it’s definitely not good code-fu. I need to fix that so command line arguments only overwrite an existing setup, instead of acting as life support.

While I’m at it, I’m also compiling a definitive list of vintage hardware that GALAXEUS actually runs on. So far, I haven't found any regular desktop hardware that fails. However, portable computers with built-in LCD screens are struggling – their vintage LCD controllers just refuse to handle 67 Hz, though 60 Hz works perfectly. I thought about adding a /60Hz switch, but nah, I’ll keep it as it is. If they die, they die, 🤣.

I also need to whip the readme.txt into shape with some clean, solid English, arguing with a narrow-minded, humorless AI until we're at each other's throats, just so I don't look like Forrest Gump trying to explain a DOS config, or on the other side of the skale like Rain Man because the AI and me are.not.smart.men. 🤣

I really takes really longer as I thought to test my old hardware collection. Each Mainboard, RAM in the right sockert, BIOS settings, it takes so much longer than I thought. I am on vacation and praise the Lord the weather is bad in Germany! Wife has no problems we're both doing indoor stuff - perfect.

Greetings

Stephan

Reply 7 of 15, by zyzzle

User metadata
Rank Oldbie
Rank
Oldbie
Pling wrote on 2026-07-19, 19:38:

While I’m at it, I’m also compiling a definitive list of vintage hardware that GALAXEUS actually runs on. So far, I haven't found any regular desktop hardware that fails. However, portable computers with built-in LCD screens are struggling – their vintage LCD controllers just refuse to handle 67 Hz, though 60 Hz works perfectly. I thought about adding a /60Hz switch, but nah, I’ll keep it as it is. If they die, they die, 🤣.

This is the type of coding I live for. It gives me great joy to know that some are still working in this late year of 2026, pushing the old hardware to its limits, optimizing code, and working in Assembly. It is really becoming a lost art. I thank you for this pursuit. Truly amazing work.

As to a 60 hz setting and a /60 flag, I highly recommend that you reconsider. I do not think any laptop made in the last 20 years will run at 67 hz with their LCD screens, which are usually stuck at 60 or 70 hz in bare metal DOS. The customized resolution of 544x480 is highly impressive for an 8-bit ISA VGA card with 256kb of VRAM. Your goal is admirable in supporting old systems, but I think a "compatibility" mode for new systems should also be considered for folks like myself who don't want to spend thousands on vintage hardware, but still would like to appreciate your magic on a $50 laptop. At this point, the oldest x86 desktop system I have that still works is a P5 233. And it might be dead by now, for it's 30 years old by now.

(I've got dozens of cheap "modern" laptops, however which happily run bare metal DOS when booted from a USB stick! DOSBOX is not my cup of poison. I still use DOS bare metal on "modern" systems as much as I can).

Once again, thanks for sharing GALAXEUS with the community and for being brave enough to espouse your techniques and coding knowledge here. I'm very impressed.

Reply 8 of 15, by Thandor

User metadata
Rank Member
Rank
Member

Impressive, very nice 😀.

What is the reason to run it at 67Hz?

thandor.net - hardware
And the rest of us would be carousing the aisles, stuffing baloney.

Reply 9 of 15, by Pling

User metadata
Rank Newbie
Rank
Newbie
zyzzle wrote on 2026-07-20, 03:39:

As to a 60 hz setting and a /60 flag, I highly recommend that you reconsider. I do not think any laptop made in the last 20 years will run at 67 hz with their LCD screens, which are usually stuck at 60 or 70 hz in bare metal DOS.
(I've got dozens of cheap "modern" laptops, however which happily run bare metal DOS when booted from a USB stick! DOSBOX is not my cup of poison. I still use DOS bare metal on "modern" systems as much as I can).

This is the type of coding I live for.

Hello zyzzle,

I'll definitely reconsider. It would be pretty easy to parse for a /60 Hz switch and set this frequency for the DOS version. For the Floppy Booter it would be much harder, as it must be squeezed into the 512-byte GALAXEUS boot sector loader and config code. There is only one byte of free space left - seriously, no joke! 😀. And since the fixed 67Hz timing dictates the game speed, running it at 60Hz makes it way too easy. Still, there's a certain charm to running it on old mobile hardware. I actually own an old Dolch Portable 386 that just couldn't handle the 67Hz - and that's been bugging the hell out of me for years now.

And this kind of coding is exactly what keeps me going, too. I’ve always had quirky interests since I was a kid. You could say football was completely off my radar while I was busy with sci-fi stuff. Luckily, I wasn't an outcast, but there was simply no one around to share my early interests with. Fortunately, I had a brother who was 16 years older - an engineering student by this time - who answered my weirdest questions.

Greetings

Stephan

Reply 11 of 15, by Pling

User metadata
Rank Newbie
Rank
Newbie
Thandor wrote on 2026-07-20, 06:20:

Impressive, very nice 😀.

What is the reason to run it at 67Hz?

Hello Thandor,

thank you fro your friendly words. The reason for the 67Hz is, that on IBM-compatible VGA chipsets, you can set something called the master hardware clock .

00 = 25.175 MHz (default for standard 640x480 graphics)
01 = 28.322 MHz (reserved for 720-pixel wide text modes, like 720x400)
10 = external <- that's where you have to drop the code and heat up the soldering iron 😀
11 = ?? 1.21 Gigawatts? summons Cthulhu?

When you change the pixel clock via the Sequencer the absolute frame grid remains exactly the same. Switching the clock source in the graphic modes to the text-mode oscillator, the graphics card spits out frames at accelerated speed. It's a 12.5 % faste rate, actually exactly 67,43 Hz every CRT and TFT can handle this. In the code it looks this:

; adjust pixel clock
cli ; IRQs off, when the Sequencer Controller is on its tuning spree
mov dl,0C4h ; DX = 3C4h I/O sequencer controller
mov ax,0100h ; sequencer: start synch. reset
out dx,ax ; note: when changing VGA clocking always reset

; boost vertical refresh rate up to 67.4Hz at 640x480
mov dl,0CCh ; DX = 3CCh VGA miscellaneous output register 3CCh/3C2h
in al,dx ; AL = current clocking configuration byte
and al,11110011b ; AL = clock select bits masked out
or al,00000100b ; set clock to 28MHz (xx=01: 28MHz, xx=00: 25MHz)
mov dl,0C2h ; DX = 3C2h (VGA misc output write port)
out dx,al

And this following code can get one even further. It reduces the horizontal total, which works very well with CRTs but really stresses out most TFTs,
that may fail to center the picture properly and it causes other weird TFT issues like drifting the border color into a not-quite-black border.

The code:
; further attempts to pimp the refresh rate (unused due to vandalism)
; achieving a clean custom 70Hz mode would be the Mona Lisa of broken VGA timing, but sadly TFTs prefer chaos over art on these settings.

; mov dx,03d4h ; exceeding 67Hz disrupts flipclip
; xor ax,ax ; (we do not want to go above 67hz/67fps anyway)
; out dx,al
; inc dx ; dx = 0x3d5
; in al,dx ; get horizontal total in al
; sub al,4 ; reducing horizontal total increases the refresh rate
; out dx,al

Greetings

Stephan

Reply 12 of 15, by Pling

User metadata
Rank Newbie
Rank
Newbie
vetz wrote on 2026-07-20, 08:10:

I have a 386SX running at 16mhz, but with a much quicker VGA card than the Oak you've been testing on. What would you expect in terms of performance, is GALAXEUS more CPU or VGA bound at the moment?

Hello vetz,

I am quite sure it is VGA-bound. The slower the VRAM, the more likely it affects performance - and actually, it's still quite easy to reduce the CPU cycles. Even in this state of optimization, there is still some breathing room. For example, I am using a very small Sound Blaster DMA buffer of only 44 bytes, which fires 250 mixing IRQs per second. I have my reasons for this tiny buffer, but it's more aesthetic than practical. When setting the length to 88, 166, or even 220 bytes, there is no sound delay anyone could possibly notice, but it results in much less IRQ overhead. A 220-byte buffer would mean a maximum of 20ms between action and sound (and on average even just 10ms, as the buffer is constantly being filled while playing a sample). I think DOSBox uses a massive 1024-byte buffer in its engine by default and nobody complains. I remember this well from my DOSBox INI-orgy days.

Actually I am quite curious about this, I have no 16 MHz 386SX Board to test. If the slow 386SX has a chache, it would be no problem at all. I have no cache and run the RAM with states r/w 1/1 and fast refresh clock (wich makes it even slower). What was the slowest 386sx they made at all? 12 MHz? - nah, I dont think so, or did they, 🤣? But after this post I go though my collection ("the junkyard" ). I recently got a bunch of old oscillators, maybe a board has an oscillator in a socket taht I can change without soldering. When you get the game, I would de happy for a feedback. Actually I would be upset, if there is a regular 386sx system with stadard VGA that could not handle the engine.

Greetings Stephan

PS sorry for writing your nicname wrong in the first comment, I am new here and currently doing 10 things to do at once. I am taking advantage of the bad weather in germany to prepare the publishing of my engine.

Reply 13 of 15, by Pling

User metadata
Rank Newbie
Rank
Newbie
zyzzle wrote on 2026-07-20, 03:39:
Pling wrote on 2026-07-19, 19:38:

As to a 60 hz setting and a /60 flag, I highly recommend that you reconsider. I do not think any laptop made in the last 20 years will run at 67 hz with their LCD screens, which are usually stuck at 60 or 70 hz in bare metal DOS. The customized resolution of 544x480 is highly impressive for an 8-bit ISA VGA card with 256kb of VRAM. Your goal is admirable in supporting old systems, but I think a "compatibility" mode for new systems should also be considered for folks like myself who don't want to spend thousands on vintage hardware, but still would like to appreciate your magic on a $50 laptop. At this point, the oldest x86 desktop system I have that still works is a P5 233. And it might be dead by now, for it's 30 years old by now.

Hello zyzzle,
as you recommended, I added the /60 switch. Now I am struggeling if I should add a /70 switch, too. I got it running quite well with 70Hz by pimping the horizontal timing further. But it's more a much complex modification for the VGA init. 70Hz work well with the real CRTs that I tested, but TFTs struggle with the aggessive horizontal Timing, e.g. they come up with borders that are not quite black (the black tends to have a n ugly dark grey touch). Seems the TFT controllers have struggle to translate the analog Cathode Ray's behavior to their fixed pixels.

Greeting

Stephan

Reply 14 of 15, by Pling

User metadata
Rank Newbie
Rank
Newbie
Thandor wrote on 2026-07-20, 06:20:

Impressive, very nice 😀.
What is the reason to run it at 67Hz?

67Hz were quite easy to achieve via the VGA registers. I even got to higher frequencies and fps like 70Hz/70fps with a more complex VGA setup, but TFTs began to show problem under this stress. CRTs worked well though. I attached a picture: under 70 Hz vertial grey lines maily in the border regions start show up. So I dropped the 70Hz branch completly.

Reply 15 of 15, by Thandor

User metadata
Rank Member
Rank
Member

Thanks for your extensive reply 😀.

386SX16 is indeed the slowest available. There are 12MHz 386DX CPU around but they are very rare. All the official documentation from Intel I’ve found states that the 386DX launched at 16MHz.

thandor.net - hardware
And the rest of us would be carousing the aisles, stuffing baloney.