[PC-98] How an obscure fighting game for Japanese PCs can ruin your day

This is a guest post from spaztron64

Sometime in June 2023, I came across a Twitter post by kuma_neko24 where he detailed his struggles in getting Policenauts to work on his PC-9821 V166. As I own the exact same machine, I figured I should give it a shot myself and report the results.
Unfortunately, while I was experimenting, I had hit a strange situation where certain executable files would randomly corrupt themselves and become unusable:

I figured the game might’ve been the culprit, but after restoring the most recent backup, the same thing happened not long after, without even trying to play the game. I’ve done Memtests of the SDRAM, as well as block level diagnosis of the CF card, and they were fine, so I attributed it to a corrupt filesystem.

I then restored a much older backup, and moved over all the known good files from the recent backup. Things seemed fine for a while, but then the exact same situation happened again. I decided to look into the issue in more detail, and I’ve noticed that affected files like WIN.COM and KRNL386.EXE were 3KB larger…. as we’ll see later, this should’ve been an immediate red flag, but I yet again brushed it off as a bad filesystem or CF card.

Fast forward to March 2024, and I got myself a set of new CompactFlash cards. I had once again restored the last known good backup, and for about a day everything seemed alright, until….

Needless to say, all my previous hypotheses turned out to be wrong. As such, I investigated yet again into the corrupted files, and used windiff to take a closer look into what actually changed. Let’s take a look at WIN.COM, SCANREG.EXE and KRNL386.EXE:

We can observe the following pattern:

  1. The files always grow in size
  2. windiff shows that the header is modified and that a bunch of garbage is added at EOF
  3. It’s always the same exact garbage
  4. Additional examinations show that MEM.EXE also has these modifications
  5. MZ headers are present, so it’s certainly executable code

By every metric, this isn’t a set of accidental corruptions, these are deliberate infections.

I then proceeded to take a sample of the suspiciously added code, did a byte scan of every file on the card, and isolated the following programs as infected:

  • B:\WIN31\WIN.COM
  • B:\SBVGM\VGMPlay.exe

Most of these are self-explanatory, apart from the last two.
VGMPlay is a program by Scali that allows playback of OPN(A) and OPL3 VGM files even on PC-98s without a SoundBlaster 16/98. I know this program is not the culprit, since the original program I got is clean.
DGP, on the other hand, is a different story, and it needs a bit of a foreword.

Duelists and queens!

DGP is a shorthand for “Duelist Gaiden Plus”, which refers to the game “Queen of Duelist Gaiden Alpha Plus”.

The original Queen of Duelist is a rubbish game not worth anybody’s time or any further mentions.
Queen of Duelist Gaiden Alpha is the 1994 sequel, which is a significantly better game, and arguably one of the best fighters for any personal computer at the time, featuring:

  • 10 fully voiced characters
  • Adjustable game speed
  • Dual PWM sampling over the integrated PC beeper speaker
  • Decent performance on a 286, and more

At the end of 1994, Agumix released an upgrade for the game called “Queen of Duelist Gaiden Alpha+”, which introduces some quality of life improvements. This update requires the original Gaiden Alpha to already be installed, although it doesn’t do any differential patching, it just replaces existing files with newer variants, and adds the DGP.EXE executable to be used instead of DGA.EXE. Shockingly, all of my older backups containing the patch, as well as the dump of the disk itself (available on Neo Kobe PC-9801) contain the suspicious code.

I didn’t expect it to return any results at first, but I uploaded DGP.EXE to VirusTotal for scanning, and well…

Who would’ve thought, the update was distributed with a copy of the Yankee Doodle virus embedded within!

Yankee Doodle is a very simple COM and EXE self-injecting virus from 1989. When executed, it resides in memory and infects COM and EXE files that use certain INT 21h DOS API calls, which include the files in the above list. It’s payload is normally supposed to play the Yankee Doodle tune through the PC speaker at 17h every day, but on PC-98 what it does instead is catastrophically fail and crash the entire system. It’s infection routines, however, do work.

A thing worth pointing out is that the infection routine is not automated. It will only engage when executing other programs from DOS manually. This should never be possible after starting the game, since there’s no way to return to the DOS command line without a full system reboot…

… unless you tried to start the game with not enough free memory, after which the game will dump you back to DOS. Pretty much every DOS user would, in situations like this, start MEM (preferrably with the /C and /P flags) to check what uses so much memory and how little remains free.

Sadly, for us, Yankee Doodle remains memory resident in this case, and it infects MEM as soon as it’s run, which explains how it got infected. Now every time you check your memory, the virus will be waiting to spread further.

Well, now what?

No known clean copy of the Plus version is known to be in circulation, and the only available source currently is the compromised disk image on Neo Kobe.
Additionally, nobody knows if the game was originally distributed with the infection, or if the person sharing a dump of the game around through P2P back in the 1990s had infected his copy.
As such, unless an original physical copy is found on auction, dumped, and confirmed clean, the only solution is to patch out the infectious payload from the game. Until then, do not play Queen of Duelist Gaiden Alpha Plus on your PC-98 machine!

EDIT 2024-03-31:
Fortunately it appears that the “Alt 1” dump available on Neo Kobe has a clean copy of DGP.EXE.
DrNyquist has also confirmed that this torrent also has a clean dump.

Conclusion: steer clear of the primary dump on Neo Kobe, use the others mentioned above.

Using an AIM-VPN EPII Plus in a Cisco 3845 or how to convert an EPII to HPII

this is a guest post by night3719

I got a 3845 for cheap with an AIM-VPN/EPII-PLUS salvaged from a 2851. At the seller’s place I installed the card and tested the 3845 there. When IOS was booting up I noticed a message along the lines of “AIM type unsupported by this platform”. I didn’t think much of it and just thought maybe I was using a version of IOS that didn’t support the module.

When I got home I threw a bunch of different IOS versions at it and nothing worked. Something was off.
As it turns out, there are 3 variants of that card, one for 1800 (BPII), one for 2800 (EPII) and one for 3800 (HPII) (note: the cards support other routers too but compatibility is a mess).

When I looked up the other variants, I immediately noticed something interesting: the modules seem identical. After looking at questions people who had similar issues posted on the Cisco community forums, something caught my eye: the output from show diag. I noticed that command spits out an EEPROM dump. As it turns out, the only difference between the cards is the contents of that EEPROM.

my card
card I found online

There are two 93C46A EEPROMs on the board, one connected to the crypto chip which probably holds config data for it and the other connected to the connector that goes to the main board. Okay, all I have to do is flash that chip with the dump I found online, right?

circled red is the EEPROM for the card, circled blue is the crypto EEPROM


dump from my card

The contents are obfuscated. Luckily however, two friends far smarter than I am (special thanks to Rachel Mant <[email protected]> and nyanpasu64!) figured out the obfuscation technique and one of them wrote code that encodes/decodes it

def bitSwap(value: int) -> int:
    result = 0
    for bit in range(8):
        result |= ((value >> (7 - bit)) & 1) << bit
    return result

def addrSwap(value: int) -> int:
    result = value & 1
    for bit in range(1, 6+1):
        result |= ((value >> (7 - bit)) & 1) << bit
    return result

data = [
    #data to be encoded or decoded goes here

for i in range(0x80):
    byte = data[addrSwap(i)]
    print(f'{bitSwap(byte):02x}', end = '\n' if (i % 16) == 15 else ' ')

I used their code to encode the output from the show diag then flashed it with my TL866. To my surprise, it worked, and the card works even on the latest IOS for this thing (15.1(4)M12a as far as I know)!

it works!

And just like that, it works!

Win32Emu / DIY WOW

This is a guest post by CaptainWillStarblazer

When the AXP64 build tools for Windows 2000 were discovered back in May 2023, there was a crucial problem. Not only was it difficult to test the compiled applications since you needed an exotic and rare DEC Alpha machine running a leaked version of Windows, it was also difficult to even compile the programs, since you needed the same DEC Alpha machine to run the compiler; there was no cross-compiler.

As a result, I began writing a program conceptually similar to WOW64 on Itanium (or WX86, or FX-32), only in reverse, to allow RISC Win32 programs to run on x86.

The PE/COFF file format is surprisingly simple once you get the hang of it, so loading a basic Win32 EXE that I assembled with NASM  was pretty simple – just map the appropriate sections to the appropriate areas, fix up import tables, and start executing.

To start, I wrote a basic 386 emulator core. To complement it, I wrote my own set of Windows NT system DLLs (USER32, KERNEL32, GDI32) that execute inside of the emulator and then use an interrupt to signal a system call  which is trapped by the emulator and thunked up to execute the API call on the host.

For example, up above, you can see that the emulated app calls MessageBoxA inside of the emulated USER32, which puts 0 in EAX (the API call number for MessageBoxA) and then does the syscall interrupt (int 0x80 in my case), which causes the emulator to grab the arguments off of the stack and call MessageBoxA.

To ease communication between the host’s Win32 environment and the emulated Win32 environment, I ran the emulated CPU inside of the host’s memory space, which means that to run applications written for a 32-bit version of Windows NT, you need a 32-bit version of win32emu (or a 64-bit version with /LARGEADDRESSAWARE:NO passed to the linker) to avoid pointer truncation issues, to prevent Windows from mapping memory addresses inaccessible by the emulated CPU.

To get “real” apps working, a lot of single-stepping through the CRT was required, but eventually I did get Reversi – one of the basic Win32 SDK samples – to work, albeit with some bugs at first. Calling a window procedure essentially requires a thunk in reverse, so I inserted a thunk window procedure on the host side that calls the emulated window procedure and returns the result.

It’s amazing, it’s reversi!

After this, I got to work on getting more complicated applications to work. Several failed due to lack of floating-point support, some failed due to unsupported DLLs, but I was able to get FreeCell and WinMine to work (with some bugs) after adding SHELL32. I was able to run the real SHELL32.DLL from Windows NT 3.51 under this environment.


One might wonder why I put all this work into running x86 programs on x86, but the reason is that there’s the most information about, and I’m most proficient with, Windows on the 386. Not only does Windows on other CPUs use other CPUs, but also there’s different calling conventions and a lot of other stuff I didn’t want to mess with at first. But this was at least a proof-of-concept to build a framework where I could swap the CPU core for an emulator for MIPS or PPC or Alpha or whatever I wanted and get stuff running.

Astute readers might be wondering why I didn’t take the approach taken by WOW64. For those who don’t know, most system DLLs on WOW64 are the same as those in 32-bit Windows, the only ones that are different are ones with system call stubs that call down to the kernel (NTDLL, GDI32, and USER32, the first of which calls to NTOSKRNL and the latter two calling to WIN32K.SYS). WOW64 instead calls a function with a system call dispatch number, which does essentially the same thing. The reason for this is that the system call numbers are undocumented and change between versions of Windows. WOW64, being an integrated component of Windows, can stay up to date. If I took this approach, I’d either have to stay locked to one emulated set of DLLs (i.e. from NT 4.0) and use their system call numbers on the emulated side, or write my own emulated DLLs and stick to a fixed set of numbers, but either way I’d somehow have to map them to whatever syscall numbers are being used on the host.

As I went on, I should probably also mention that what I said earlier about loading Win32 apps being easy was wrong. Loading a PE image is pretty straightforward, but once you get into populating the TEB and PEB (many of whose fields are undocumented), it quickly gets gnarly, and my PEB emulation is incomplete.

Adding MIPS support wasn’t too much of a hassle, since the MIPS ISA (ignoring delay slots, which gave me no shortage of trouble) is pretty clean and writing  an emulator wasn’t difficult. The VirtuallyFun Discord pointed me to Embedded Visual C++ 4.0, which was invaluable to me during development, since it included a MIPS assembler and disassembler, which I haven’t seen elsewhere. After writing a set of MIPS thunk DLLs and doing some more debugging, I finally got Reversi working.

There’s still some DLL relocation/rebasing issues, but Reversi is finally working in this homebrewed WOW!

I’d encourage someone to write a CPU module for the DEC Alpha AXP (or even PowerPC if anyone for some reason wants that). The API isn’t too complicated, and the i386 emulator is available for reference to see how the CPU emulator interfaces with the Win32 thunking side. An Alpha backend for the thunk compiler can definitely be written without too much trouble. Obviously, the AXP presents the challenge that fewer people are familiar with its instruction set than MIPS or 386, but this approach does free one from having to emulate all of the intricate hardware connections in actual Alpha applications while still running applications designed for it, and I’ve heard the Alpha is actually quite nice and clean. MAME’s Digital Alpha core could be a good place to start, but it’ll need some adaptation to work in this codebase. Remember that while being a 64-bit CPU with 64-bit registers and operations, the Alpha still runs Windows with 32-bit pointers, so it should run in a 32-bit address space (i.e. pass /LARGEADDRESSAWARE:NO to the linker).

Theoretically, recompiling the application to support the full address space should enable emulation of AXP64 applications, since the Alpha’s 64-bit pointers will allow it to address the host’s 64-bit address space, but I’m not sure if my emulator is totally 64-bit clean, or if the AXP64’s calling convention is materially different from that on the AXP32 in such a way that would require substantial changes. In either case, most of the code should still be transferable.

I also want to get more “useful” applications running, like development tools (i.e. the MSVC command line utilities – CL, MAKE, LINK, etc.) and CMD. Most of that probably involves implementing more thunks and potentially fixing CPU bugs.

This project is obviously still in a quite early stage, but I’m hoping to see it grow and become something useful for those in the hobby.

For those who want to play along at home, you can download the binary snapshot here: w32emu.zip

A more complete version of the writeup is available here: https://bhty.github.io/og/win32emu_VirtuallyFun_Post.htm and you can find the project here https://github.com/BHTY/Win32Emu/.

Sun Ray adventures pt1

this is a guest post by night3719

A while back I was looking for a 19in 5:4 screen so I messaged a guy I know that would normally have something like it. When I asked him about it, he said he didn’t have any 19in screens, however, he has this “14in Sun LCD”. I was intrigued so I asked him to send pics of it. Lo and behold, this is what he sent me the next day:

Unfortunately, bad news came. He powered it on and told me it was flickering. Ok fine. These are hard to come by in my country (Vietnam) so I decided to get it anyways. He also cut the price by half, so it was reasonable-ish.

When I got home and powered it on…. yeah. It was flickering. I opened up the menu of the LCD and I quickly noticed something peculiar: the image was flickering but the LCD menu was not. When I opened it up, I made yet another interesting discovery: the whole thing is practically a sun ray duct taped to a normal LCD. The sun ray board is not driving the lcd directly, there’s a separate controller board (similar to what you would find in a normal standalone display without a sun ray shaped tumor on the back).

As it turns out the flickering was caused by a single cap that went bad. I replaced it and the image looks good.

There is a GUI thing I’ve read that allows you to configure various parameters of the sun ray so I tried to bring it up. No matter what key combo I pressed it didn’t show up. Once again, bad news came. My sun ray has the non-GUI firmware. The only way to enable it is to flash a GUI firmware or a firmware with GUI enabled (the firmware shipped with SRSS 5.1 and below has separate firmware files for GUI and non-GUI while SRSS 5.2 and later both GUI and non-GUI are a single file, GUI on/off is specified with a flag during flashing).

Okay then. No big deal, all I have to do is just flash the firmware, right? Well yes but no. I would very quickly find out that I don’t have the firmware. I had SRSS 5.4 installed and turns out, 5.3 and later stopped including the firmware and that was something you needed MOS for. Great job Larry!

Okay then. No big deal, all I have to do is just download SRSS 5.2, right? Once again, for the second time, yes but no.


2 days later I got access to edelivery again. I downloaded SRSS 5.2. I uninstalled SRSS 5.4 and installed 5.2, all I have to do now is just flash the firmware right? riiiight??? Once again, for the THIRD time, yes but no. For some reason I was able to flash the firmware with “utload“ (which has GUI disabled) but I couldn’t flash it with “utadm“ despite it being able to connect to my T5220 and start a session just fine. As I would find out after one whole day wasted, I was supposed to use a separate network served by the T5220, and this is what I did:
Setup NET1 port as a dedicated interface for Sun Ray

-bash-3.2$ sudo utadm -a e1000g1
### Warning: DHCP Service is in the maintenance mode
             There could be a problem with the DHCP configuration

### It is strongly recommended to fix the problem and then use:
### "/usr/sbin/svcadm clear svc:/network/dhcp-server:default"
### to get DHCP service out of the maintenance mode before running utadm

Do you want to Continue?  (Y/[N]): y
### Configuring /etc/nsswitch.conf
### Configuring Service information for Sun Ray
### configuring e1000g1 interface at subnet
  Selected values for interface "e1000g1"
    host address:
    net mask: 
    net address:
    host name:          t5220-e1000g1
    net name:           SunRay-e1000g1
    first unit address:
    last unit address:
    auth server list:
    firmware server:
  Accept as is? ([Y]/N):
### successfully setup "/etc/hostname.e1000g1" file
### successfully setup "/etc/inet/hosts" file
### successfully setup "/etc/inet/netmasks" file
### successfully setup "/etc/inet/networks" file
### Disabling Route Advertisement
### finished install of "e1000g1" interface

### Configuring firmware version for Sun Ray
        All the units served by "t5220" on the
        network interface, running firmware other than version
        "4.3_146928-01_2011." will be upgraded at their next power-on.      
### Configuring Sun Ray Logging Functions

DHCP is not currently running, should I start it? ([Y]/N): ### Error: unable to start dhcp services.
    Please restart dhcp manually after utadm has completed.

well… oops. Shouldn’t’ve ignored that. One “svcadm clear dhcp-server“ and one “svcadm restart dhcp-server“ later… Let’s try to flash the firmware.

-bash-3.2$ sudo utfwadm -A -e 00144F6F69CA -n e1000g1 -G force
-n interface option ignored.  It is no longer required with -e option.
        Unit "00144F6F69CA" will be upgraded at its next power-on
        if it is served by host "t5220" and is connected to
        the  network and is not already running firmware
        version "4.3_146928-01_2011.".

### stopped DHCP daemon
### started DHCP daemon
### reinitialized DHCP daemon

For those who are wondering what the flags do:

        -A            # add the specified unit(s) to the upgrade list
        -D            # delete the specified unit(s) from the upgrade list
        -P            # print version information
        -R            # remove firmware modules from boot directory
        -a            # apply to all units connected to the specific interface
                      #  or subnet
        -e enetAddr   # apply to the unit given by the six hex bytes
                      #  of its ethernet address
        -n intf       # name of a dedicated network interface to enable upgrades                                                                                                                                                              on
                      #  (e.g., hme0, vge1, etc. "all" = all interfaces)
        -G option     # control enabling of configuration GUI on Sun Rays
        -g option     # control disabling of configuration GUI on Sun Rays
        -i filename   # append contents of filename to config files
        -N subnetwork # shared subnetwork address to enable upgrades on
        -d            # actively disable firmware download (useful with "-e")
        -V            # only generate version files, do not configure DHCP
        -F            # force firmware load even if downgrading
        -u            # use frame buffer to do download and decompression
        -f firmware   # use the firmware described by the path "firmware"
                      #  for upgrades on the given network interface(s)

Power cycle with CTRL+Pause+A and…


Fun fact: the firmware is stored temporarily in the framebuffer (iirc at least) The GUI can now be accessed:

SoftWindows on OpenVMS

(This is a guest post by Antoni Sawicki aka Tenox)

I like exploring vintage hypervisors and emulators. In the past I did a whole series on Merge, VP/IX and others. This time I wanted to take look at something a little more exotic – SoftWindows on Alpha OpenVMS. I have in fact installed it a while back but I could never get it properly licensed. I looked everywhere, asked everyone and of course no one had a license pack for this. Fortunately there are two license generators for OpenVMS, pakgen and lmfgen. But how do you find out what is the exact product code and vendor? VMS provides a license debug facility:

$ reply/enable=license
$ define/sys/exec lmf$display_opcom_message true

Then, when starting an app, you will get an opcom log message with all the required product name, vendor, etc. The rest is easy. For the lazy, here is a complete license pack for SoftWindows:

        /ISSUER=DEC -
        /PRODUCER=DEC -
        /UNITS=0 -

Here is a screenshot for your viewing pleasure!

SoftWindows on OpenVMS Alpha

The install comes with it’s own version of Windows 3.1 plus some additional tools and apps, typical for Insignia products. You can map drives to folders, ports COM and LPT, etc. There are a variety of video modes – Hercules, CGA, EGA and VGA, even 256 colors. The performance is quite decent, however the CPU is pegged at 100%, as you can see in the system monitor. There is a CPU idle detection tool, however it doesn’t seem to work very well. I suspect that perhaps this may be to do with much never OpenVMS version, than the software has been designed for. The SoftWindows has been released in 1994 and not been updated since.

How do you install and run this thing? There is a full installation guide, however since this is just a PCSI file, you can simply use product install:

$ unzip softwin-v0100.zip
$ product install *

To start it you cast these magic spells:

$ @sys$sysroot:[sysmgr]softwin$startup.com
$ softwin

Since SoftWindows is essentially SoftPC you can run pure DOS mode. I will do a follow up on this and explore some DOS games.

You can find all the files on osarchive.org.

From a hindsight, it’s ironic how roles have reversed in 30 years. Back then MS-DOS / Windows was a toy OS, running on a toy “personal” computer, emulated in a little window on a “real” computer like DEC Alpha. In modern times you run OpenVMS as a guest VM on a Windows PC.

Have fun with virtualization!

Patching Touhou 6 (Embodiment of Scarlet Devil) to run on a 3dfx Voodoo 2

This is a guest post from spaztron64

One thing that’s been bugging me for years at this point is the ability to run Touhou 6 on my PC-9821 V166. For a good few years I’ve been stuck with nothing more than a Matrox Mystique graphics card in that thing, which can’t create a D3D6 HAL context for rendering the game’s 3D elements. In 2021 I snatched a 12MB 3dfx Voodoo 2, in hopes of being able to play more 3D games on that machine. There were two major problems….

1) The USBHID.SYS driver for PC-98 Windows 9x conflicts haaaard with Voodoo drivers. Moving the cursor around corrupts memory and makes the system unstable or kills the driver in mere seconds of use

2) None of the Touhou games support secondary Direct3D devices

For those not in the know in regards to the second issue, DirectX allows you to use multiple DDraw and D3D capable GPUs on one system. By default it’ll set the video card outputting a signal on the primary monitor as the primary DirectX device, the secondary output as secondary, and so on. Most people only used one monitor on their Win9x PC back in the day, hooked up to their 2D capable card. The Voodoo 1 and 2 aren’t meant to act as 2D video cards, yet they had to support D3D initialization somehow, so they presented themselves as non-primary DirectX devices, usually secondary, in hopes that game developers would allow the end user to select their 3D accelerator of choice.

This was standard practice at the tail end of the 1990s, but it was falling out of use at the turn of the millenium with the demise of 3dfx and the general lack of need for multiple graphics cards in one system for 3D gaming. This presented a problem, as games that technically could be played on a Voodoo 2… didn’t, as they could never be told to use it through normal means. Hacky solutions existed, like 3dfx’s unfinished, buggy attempt at a Voodoo 2 driver for Windows 2000 that allowed it to behave like a primary display adapter for general 2D and 3D use, but it’s notoriously unstable and isn’t possible to use on 9x. I’ve used this method before to play Touhou 6, Max Payne 1, GZDoom, GTA 3 and Vice City on the Voodoo 2 through Windows XP with mixed results.

Once I got an NEC bus mouse for use on my PC-98, I could finally use the Voodoo 2 on it without constant crashing. This got me interested in trying to get Touhou 6 to work on it, which lead me to a path of pure pain.

For starters, Touhou 6 is one of those games that only use primary DirectX devices, like the unsupported Mystique, so I had to somehow coax it into initializing the secondary device instead. My first approach to handling this was through direct binary patching. I didn’t know where to look for the init routines, so I asked 32th System for some heads up, and he pointed me to a rough location in process memory where the appropriate CreateDevice calls reside:

I then searched for the appropriate opcodes in the game binary, and patched all 6A 00 (push 0, A.K.A D3DADAPTER_DEFAULT) opcodes to be 6A 01 (push 1), forcing the game to init the secondary D3D device.

While this initially did in fact work, the approach ultimately sucked for two reasons.

1) Static binary patching only works for that specific binary, and doesn’t carry across different versions.

2) This requires manually patching every CreateDevice call, of which there are many in Touhou 6

It is at this point that I started sharing my progress with friends. jbit was quick to hop in and say “Why the fuck are you doing it this way? Just make a d3d8.dll wrapper DLL”. This was absolutely the smarter approach, I just didn’t know how to do it since I don’t know jack about DirectX programming. Fortunately, he handed me a little VS project he worked on called d3dcutter that, among other things, wrapped the CreateDevice function, which I promptly modified to always push 1 instead of 0 to the stack for the device selection parameter.

This solved the two patching problems, and I had something to show for starters:

Now, I’m sure you can tell that the performance is absolutely atrocious. This came as no surprise to me, as while the Voodoo can absolutely render the game at a full 60FPS most of the time, the dinky little Pentium MMX 166 struggles hard at doing triangle setup for the backgrounds every 16 milliseconds. Remember, 3dfx cards had no Hardware T&L, so the game has to fall back to Software T&L. I think the following wireframe screenshot will help illustrate the amount of work the CPU has to do every frame:

“Well, I’m in luck!”, one might think as they remember that older Touhou games support framerate division by 1/2 (30FPS) and 1/3 (20FPS) as options in custom.exe… There’s just one problem.

The game just… fails to initialize the D3D HAL on the Voodoo 2 in the frame divided modes. Why? Beats me, I still haven’t figured it out and likely never will. Just more ZUNcode bullshit I suppose.

I then figured out that framerate division is handled by a variable (that can be set even lower than 1/3, by the way) which could be set at runtime, even when the normal 60FPS mode is used. I suspected that the game uses a different initialization path for the two modes, so I once again tracked down opcodes that expect the variable to be set to 0 in process memory, this time with Cheat Engine, and patched them in the binary. Well guess fucking what, the game fails to initialize even when the regular init routines are modified to expect 30FPS or 20FPS frame division to be set.

This approach simply wasn’t going to work. so I went with trying to set the variable at runtime. Unfortunately, I had to go back to version specific patching once more for this, since there’s no way to wrap this functionality through DLL means. Additionally, while this wasn’t hard to do with the game running in windowed mode with Cheat Engine on the side on a modern system, it was basically impossible on a Voodoo 2 equipped machine, as the game ran in fullscreen and it wasn’t possible to restore the window after an Alt+Tab.

My final solution was to generate a trainer in Cheat Engine for version 1.02d of the game, as it’s the last one with a working logic speed limiter, that would forcibly set the frame divider variable at runtime with a hotkey:

This finally allowed me to play the game in 1/3 framerate mode on the Voodoo 2.
This allows the game to run at full logic speed most of the time, as the CPU now has 40 miliseconds per frame for triangle setup, however there’s something wrong with how the card handles buffer swaps in this mode of operation, leading to a very back-and-forth stuttery image that’s very unpleasant to look at.

Can we do better? Well yes! The game uses so-called STD scripts for certain stage-specific data setup, but also handling camera movement and geometry generation. Using Touhou Toolkit, I was able to unpack the appropriate DAT file, decompile all the STD scripts, remove all geometry commands, and recompile them for in-game use. As there are no more backgrounds to draw, there’s a trail effect left behind every frame, but thankfully custom.exe has an option to forcibly clear the back buffer every frame.

The end result? A nearly tripled framerate in 60FPS mode, recovered just by not drawing any 3D backgrounds. The game still lags when lots of bullets are on screen, but this doesn’t really come as a surprise.

Windows NT 3.1 on DEC Alpha AXP

(this is a guest post by Antoni Sawicki aka Tenox)

As I was preparing the Windows NT RISC exhibit for VCF west, I realized that I’m missing a rather important piece of the history. While I will be showing the potentially last DEC Alpha Windows build ever – AXP64 2210, I don’t have anything earlier than NT 3.51. It would be nice to showcase the very first RTM version – NT 3.1. From time perspective, NT did not get popular until the version 3.5 and later. Windows NT 3.1 would be considered rare even on a 386, let alone on a RISC CPU! So what RISC hardware does Windows NT 3.1 run on?


Not many! The HCL published on gunkies has a few more systems, but nothing that I have. The early MIPS based systems are all but unobtanium as of today. This is probably a good time to mention a little known port of Windows NT 3.1 to the DECstation 5000. However these builds are not found even on earliest NT betas. Not to mention lack of ARC firmware for this machine.

The Alphas were looking a little more reachable. The DEC 2000 Model 300 and DECpc AXP 150 are one and the same machine, packaged in a server and workstation cases. Code-named Jensen, DEC designed and marketed these specifically around Windows NT. Unlike prior Alphas, this model used a lot of “PC” components for increased compatibility and lower cost. Eventually paved way for the more well known DEC Multia. The Jensen has been seen floating here and there and many people have these.

I was able to get a loaner from Chris Satterfield aka Compgeke for the VCF. Having a working specimen at hand, I started looking at part numbers of various components. In an amazing streak of luck, in practically zero time I was able to find, buy and assemble a complete DECpc AXP 150 from spare parts on eBay! Without a case, but nevertheless. Also big thanks to Christopher Rivett for help with some fine details!

Franken Jensen built from spare parts off eBay.
Jensen running at VCF West 2023, with fans installed


  • Motherboard + CPU – DEC 70-29685-01
  • GPU – DEC/Compaq Qvision 1024/E (1024×768) – 126654-001
  • GPU – (Optional) Number 9 High Res (1280×1024) – 30-41800-01
  • HBA – Adaptec AHA-1742A EISA – 467806-00
  • NIC – DEC DE422-S EISA – 5021102-01
  • RAM – 4x 16MB, FPM, 60ns, 72-Pin, 12-Chip, True Parity SIMM
  • PSU – DEC/HP 30-37197-02, however a standard AT PSU may be OK

If you going to build one yourself, beware of overheating. Jensen runs rather hot and needs good cooling. Not only for the CPU. There is a section of the motherboard just under the EISA cards that runs incredibly hot. See the picture, where I have installed a large Noctua fan.

OS Install

There are many Windows NT 3.1 CDROMs floating around. I purchased a DEC branded, shrink-wrapped CD on eBay to use as a prop along with the machine. You can download the iso image here.

Installation of Windows NT 3.1 on DECpc AXP 150 is pretty straightforward and not that much different from the later versions. However as a prerequisite you will need the ECU floppy disk to configure the EISA slot assignments, card and jumper settings. After that you will have to go through various setup screens in ARC BIOS to configure system settings. Then you run arcinst to create a system partition and setupldr to install the OS. The rest of it is pretty uneventful. This is somewhat expected, as this was pretty much the only one and supported hardware combination, so must have been well tested. The only curious part is that the NT OS Kernel does not display any text during normal boot. Later versions of NT will display the build number and MP or UP kernel variant and dots indicating subsystem load progress. This is rather odd because I expected more text mode stuff from older NT version, but who knows.

Jensen NT 3.1 Boot Menu
Windows NT 3.1 on DEC Alpha AXP, DECpc 150 aka Jensen

Service Pack Saga

If you are even vaguely familiar with installing Windows NT at all, you will know that the very first thing you have to perform after installation, is to apply a service pack. NT 3.1 did have service packs, up to SP3. The problem is that, as you may very well expect, non-x86 editions were nowhere to be found in 2023. The only thing I could come up with was http://www.win31.de/ent31.htm, which had a German AXP and MIPS SP3, but no English! [It since has been updated…]. I had to do some real detective work to track down an US-English AXP SP3 version. I spent a few days going through various random CDs and ftp site mirrors of that era, with little luck. Eventually I stumbled on this README file, stating:

Due to space constraints on the Windows NT Service Packs for
International Versions CD, the USA Service Pack version 3 is located on
the Additional Windows NT Service Packs, Windows 3.11 versions, SDKs,
and DDKs CD in the NTSRVPC3\USA directory.

Bingo! After a few hits and missed I spotted this particular CDROM here: https://archive.org/details/microsoft-developer-network-january-1995-disc-4-of-15 – Now the OS is finally “servicepacked” 🙂


My general impression of NT 3.1 on DEC Alpha is pretty awesome. If you can overlook the age and some obvious shortcomings, the OS is pretty stable, solid and even snappy for such old hardware. An OS itself without apps is not much. While overall Alpha NT application outlook is pretty scanty I was able to find a several very interesting gems!

Most importantly, thanks to Chris, a DEC Windows NT Developers CD-ROM!

The disk has an incredible amount of demo, freeware, public domain and shareware applications as well as DEC marketing material.

Windows NT Developers CD for DEC Alpha NT 3.1

You can get a lot of DEC proprietary software like C++, Fortran, PATHWORKS, DECtalk, as well as X servers, etc.

However I was particularly interested in some 3rd party commercial apps.

For example there is an early version of DMC Calamus Desktop Publishing.

DMC Calamus desktop publishing on Windows NT 3.1 DEC Alpha AXP

Also a demo version of a vintage, text-mode SlickEdit, way before it was replaced by the Visual SlickEdit known today.

SlickEdit 2.3 on Windows NT 3.1 DEC Alpha AXP

There also is WinDev editior, which is quite superior to Notepad and has some code editing goodies and shortcuts to SDK tools, making it something of a simple IDE.

WinDev 1.56 on Windows NT 3.1 DEC Alpha AXP

Another big source is Windows NT Application Sampler CDROM, (also from Smithsonian).

One of the coolest thing found there is a graphical text editor called WinEdit. It has a ton of features and even syntax highlighting! It has since became my default to go editor / IDE on this system!

WinEdit 3.0E on Windows NT 3.1 DEC Alpha AXP

There of course is a Windows NT SDK with the M (MEP) editor.

Windows NT 3.1 SDK with M / MEP Editor on DEC Alpha AXP

There also are quite few public domain apps and games, ports of GNU software, Micro Emacs, Kermit, etc.

Update: CICA NT Shareware Collection has some interesting apps under the /alpha directory.

High Resolution GPU

One of things that was troubling me for some time was rather low resolution of the default QVision graphics card. The maximum being only 1024×768 is just not acceptable. Talking to several Jensen’s owners, no one even heard about anything better. However looking at the Windows setup options, I curiously noticed that the system does support one 1280×1024 video card – Number 9 GXE.

I simply assumed that such card would simply be unobtanium in 2023. However, digging through some old catalogs and spare part listings, I managed to find a DEC part number, which is 30-41800-01. Armed with this, I was able to find it via DEC spare part reseller that I often use. They had it in stock listed as “HIGH RES EISA 1280 x 1024 GRAPHICS”. The price wasn’t too bad either, at least compared to the whole endeavor. A few days later I received this:

After installation of the S3 driver (must be the Service Pack 3 version!) I was finally able to get 1280×1024 from the poor thing!

With this I should have a more cozy environment to compile and port even more apps 🙂

In future I want to try the Advanced Server edition as well as some early Betas with Alpha support.

Windows NT on IBM RS/6000 – Definitive Guide

(This is a guest post by Antoni Sawicki aka Tenox)

Preparing for Windows NT RISC Exhibition for VCFW 2023, I wanted to have NT running on an IBM RS/6000. This was previously covered in this excellent article by Shoutmon as well in this excellent video by NCommander. However both are missing some crucial information that I had to go through and learn myself the hard way. I hope it will help someone in the future.

Windows NT PowerPC was designed to run on PReP machines, however that by itself is not very useful. Which of the RS/6000 models are REeP and which are not? This is coincidentally answered by NetBSD/prep supported system models.

Firstly there are IBM PC Power Series. Yes IBM PC but with PowerPC CPU, and not to be confused with RS/6000 which is a different IBM product. However the IBM Power Series have equivalent RS/6000 “counterpart” models. WTF IBM.

IBM PC Power Series 440 6015 == IBM RS/6000 Model 7020 40P
IBM PC Power Series 830 6050 == IBM RS/6000 Model 7248 43P
IBM PC Power Series 850 6070 == IBM RS/6000 Model 7248 43P

There are also other models mentioned by Windows NT 4.0 HCL, namely E20, E30 and F30, and PowerPC ThinkPads. To summarize here is a more definitive list of IBM RS/6000 models supported by Windows NT 4.0:

Model 7020 40P
Model 7248 43P, 100 and 133 MHz
Model 7248 43P-140 (with a big asterisk)
Model 7024 E20 and E30
Model 7025 F30
ThinkPad 820, 850
ThinkPad 860 (with a big asterisk

If you could pick any RS/6000 machine, the 40P would probably be the most recommended. 40P can also run OS/2 PowerPC if you are in to this thing.

Unfortunately all I had on hand was 43P-140, which is PReP, but it’s not Power Series based and not supported by NT out of the box. WTF IBM. Chances are that you will run in to this as well. 43P-140 are way more popular and easier to acquire than any other hardware listed above.

The main trouble with 43P-140 is that the onboard GPU and NIC will not work with ARC and NT. Yes, you can hack in some generic S3 card. It will work in ARC/NT but not PROM and AIX. I wasn’t happy. Upon some collaboration with Shoutmon and NCcommander and my own research, I was able to find the one and only graphics card that will work in both the RS/6000 PROM as well as ARC BIOS, AIX and Windows NT. The lucky winner is:

IBM FRU 40H5838 aka GTX110P

Update: It’s been tried, tested and verified to use IBM ROM with a regular/stock S3 Trio64V+. You can download it here and program yourself.

It’s entirely possible that other adapters will work as well, however from all different cards that I tried this was the only one that worked in all combination.

As for NIC, there are way more options as it’s not used by PROM, ARC or AIX, just NT. In my case I opted for a standard Etherlink III card.

Once you have the correct hardware bits, NT installation is pretty straightforward. This is well covered elsewhere. In a nutshell you boot the ARC 1.51 floppy disk, setup partitions and install the OS. Note that the ARC BIOS will be installed in to a partition on your HDD and the floppy disk is not required beyond installation.

Installation on PowerPC ThinkPads, specifically the 860 is covered here.

Come meet Tenox & check out the NT RISC collection over at VCF

Billed as “NT RISC: Windows NT on RISC machines. Alpha, MIPS, PowerPC, Itanium.”, the exhibit demonstrates a lot of work in sourcing & repairing the machines along with some great rare example like

  • DEC AXPpc 150 Jensen NT 3.1
  • DEC PWS 500 Miata W2K axp64
  • DEC Multia NT 4.0
  • Motorola PowerStack NT 4.0
  • NetPower Fast MP NT 4.0
  • MVME 1600 NT 4.0
  • DeskStation Tyne NT 3.1
  • DeskStation Raptor Reflex

And yes, we’ve even had a few celebs pass by!

Dave Plummer and Chris Walker

Tenox will be there all day Saturday at the The Computer History Museum, Mountain View, CA, 1401 N Shoreline Blvd, Mountain View, CA 94043.

exhibit #16

H’es located at tables 37-38, exhibit 16.

Monitoring temperature of ancient hardware

(This is a guest post by Antoni Sawicki aka Tenox)

I’m preparing a Windows NT RISC exhibition for VCF West 2023. While the CHM building is air conditioned, it’s far far from ideal and we have a rather hot summer. Most of the vintage machines lack CPU power management. Some, such as Alphas, are notorious for overheating. Despite installing modern fans and heatsinks, this still makes me uneasy. I wanted to come up with some thermal monitoring system to see whats going on in real time. Maybe alert or shut down if things go out of hand.

For a while now I been thinking about using Arduino with a thermistor. It would read the temperature sensor and send the data via serial port to the host. This should universally work for most old computers, as they commonly have serial ports. However, upon some prototyping I realized that between custom pcb/wiring, power requirements and TTL to RS232 converter, the whole thing was becoming a little too complicated for what I really wanted. Fortunately I came across a rather ingenious solution – someone sells this item on eBay:


It’s basically a thermal probe with RS232 interface, emitting a plain text ASCII string output. No drivers or software required. They are a little bit pricey. Perhaps readers can find a cheaper version. However it’s absolutely a perfect solution for what I really wanted. Note that the seller can make shorter cables on request. The default 3m is insanely long for this purpose.

With help of some thermal glue, installed the probe in to the CPU heat sink and routed the cable to a COM port in the back.

Above pictures are from Multia and PWS.

You can simply read the temperature as an ASCII string from the COM port:

However since this is a prestigious event I wanted something fancier. Also a simple terminal can’t really tell when was the data received and therefore is current. I banged out a simple Win32 app to have something nice on the screen:

If there is no update from serial port in last 10 seconds, “no data” will be shown. The text label changes color if the temperature goes over a threshold to warn if things are getting too hot.

I even added a thermal shutdown, if it goes over a critical value. However this only works on Windows 2000 and above. Earlier Windows NT versions lacked ACPI HAL support to invoke power down. Fortunately this will work nicely for 2210 build on PWS 500 and Windows XP on Itanium!

After VCF I’ll make something for Unix and VMS as well. Perhaps also a service / daemon version that can run in the background and doesn’t require GUI.

Source code and binaries: https://github.com/tenox7/readtemp