Life in UNIX® V7: an attempt at a simple task

(This is a guest post by xorhash.)

1. Introduction

ChuckMcM on Hacker News ( reacted to my previous entry here about trying to typeset old troff sources with groff. It was said that ‘‘you really can’t appreciate troff (and runoff and scribe) unless you do all of your document preparation on a fixed width font 24 line by 80 column terminal’’.

‘‘Challenge accepted’’ I said to myself. However, it would be quite boring to just do my document preparation in this kind of situation. Thus, I raised the ante: I will do my document preparation on a fixed width font 24 line by 80 column terminal on an ancient UNIX . That document is the one you are reading here.

2. Getting an old version of UNIX

While it would have been interesting to run my experiment on SIMH with a genuine UNIX , I was feeling far too lazy for that. Another constraint I made for myself is that I wanted to use the Internet as little as possible. Past the installation phase, only resources that are on the filesystem or part of the Seventh Edition Manual should be consulted. However, if I have to work with SIMH, chances are I’d be possibly fighting the emulator and the old emulated hardware much more than the software.

2.1. FreeBSD 1.0

My first thought was that I could just go for FreeBSD 1.0 or something. FreeBSD 1.0 dates from around 1993. That was surprisingly recent, but I needed a way to get the data off this thing again, so I did want networking. As luck would have it, FreeBSD 1.0 refused to install, giving me a hard read error when trying to read the floppy. FreeBSD 2.0 was from 1995 and already had colorful menus to install itself (!). That’s no use for an exercise in masochism.

2.2. V7/x86

I turned to browsing for a bit, hoping to find something to work with. Lo and behold, it pointed me to! V7/x86 is a port of UNIX version 7 to the x86. It made some changes to V7, among those are:


including the more pager,


including the vi editor,


providing a console for the screen, rather than expecting a teletype, and


including an installation script.

The version of vi that ships with it is surprisingly usable, even by today’s standards. I believe I would’ve gone mad if I’d had to use ed to write this text with.

3. Installing V7/x86

The V7/x86 installer requires that a partition exists with the correct partition type. It ships with a tool called ptdisk to do that, but because /boot/mbr does not exist on the installation environment, it cannot initialize a disk that does not already have a partition table ( Thus I used a (recent) release of FreeBSD to create it. At first, FreeBSD couldn’t find its own CD-ROM, which left me quite confused. As it turns out, it being unable to find the CD-ROM was a side effect of assigning only 64 megabytes of RAM to the virtual machine. Once I’d bumped the RAM to 1GB, the FreeBSD booting procedure worked and I could create the partition for V7/x86. V7/x86 itself comes packaged on a standard ISO file and with a simple installation script. It seems it requires an IDE drive, but I did not investigate support for other types of hard drives, in particular SATA drives, much further. There seem to be no USB drivers, so USB keyboards may not work, either.

During the installation, my hard drive started making a lot of scary noises for a few minutes, so I aborted the installation procedure. After moving the disk image to a RAM disk (thank you, Linux, for giving me the power of tmpfs), I restarted the installation and it went in a flash. The scary noises were probably related to copying data with a block size of 20, which I assume was 20 bytes per block: The virtual hard disk was opened with O_DIRECT, i.e., all writes got flushed to it immediately. Rewriting the hard drive sector 20 bytes at a time must’ve been rather stressful for the drive.

4. Using V7/x86

I thought I knew my UNIX , but the 70s apparently had a few things to teach me. Fortunately, getting the system into a usable state was fairly simple because got me started. The most important notes are:


V7 boots in single-user mode by default. Only when you exit single-user mode, /etc/rc is actually run and the system comes up in multi-user mode.


Using su is recommended because root has an insane environment by default. To erase, # is used, rather than backspace (^H). The TERM variable is not set, breaking vi. /usr/ucb is not on the path, making more unavailable.


The character to interrupt a running command is DEL, not ^C. It does not seem possible to remap this.

more is a necessity on a console. I do not have a teletype, meaning I cannot just ‘‘scroll’’ by reading the text on the sheet so far. Therefore, man is fairly useless without also piping its output to more.

Creating a user account was simple enough, though: Edit /etc/passwd, run passwd for the new user, make the home directory, done. However, my first attempt failed hard because I was not aware of the stty erase situation. I now have a directory in /usr that reads ‘‘xorhash’’, but is definitely not the ASCII string ‘‘xorhash’’. It’s ‘‘o^Hxorhash’’. The same problem applies to hitting the arrow keys out of habit to access the command history, only to butcher the partial command you were writing that way.

Another mild inconvenience is the lack of alternative keyboard layouts. There is only the standard US English keyboard layout. I’m not used to it and it took me a while to figure out where some relevant keys ($, ^, &, / and – in particular) are. Though I suppose if I really wanted to, I could mess around with the kernel and the console driver, which is probably the intended way to change the keyboard layout in the first place.

5. Writing a document

Equipped with a new user, I turned to writing this text down before my memory fails me on the installation details.

5.1. The vi Editor

I am infinitely thankful for having vi in the V7/x86 distribution. Truly, I cannot express enough gratitude after just seeing a glimpse of ed in the V7/x86 introduction document. It has some quirks compared to my daily vim setup, though. Backspacing across lines is not possible. c only shows you until where you’re deleting by marking the end with $. You only get one undo, and undoing the undo is its own undo entry. And of course, there’s no syntax highlighting in that day and age.

5.2. troff/nroff

And now for the guests of this show for which the whole exercise was undertaken. The information in volume 2A of the 7th Edition manuals was surprisingly useful to get me started with the ms macros. I didn’t bother reading the troff/nroff User’s Manual as I only wanted to use the program, not write a macro package myself. The ms macro set seemed to be the way to go for that. In this case, nroff did much more heavy lifting than troff. After all, troff is designed the Graphic Systems C/A/T phototypesetter. I don’t have one of those. M. E. Lesk’s Typing Documents on the UNIX System: Using the −ms Macros with Troff and Nroff and Brian W. Kernighan’s A TROFF Tutorial proved invaluable trying to get this text formatted in nroff.

The ‘‘testing’’ cycle is fairly painful, too. When reading the nroff output, some formatting information (italics, bold) is lost. more can only advance pagewise, which makes it difficult to observe paragraphs in their entirety. It also cannot jump or scroll very fast so that finding issues in the later pages becomes infuriating, which I solved by splitting the file up into multiple files, one for each section heading.

5.3. The refer program and V7/x86

Since I was writing this in roff anyway, I figured I might as well take advantage of its capabilities – I wanted to use refer. It is meant to keep a list of references (think BibTeX). Trying to run it, I got this:

$ /bin/refer
/bin/refer: syntax error at line 1: ‘)’

The system was trying to run the file as shell script. This also happens for tbl. It was actually an executable for which support got removed during the port (see I contacted Robert Nordier about this; he suggested I remove the -i and -n flags and recompile refer. Now it runs, exhibiting strange behavior instead: For all intents and purposes, refer is quite unusable like this. Fixing this is beyond my capacity, unfortunately, and (understandably) Robert Nordier does not feel up to diving into it, either. Thus, we’ll have to live without the luxury of a list of references.

6. Getting the Data off the Disk

I’m writing this text on V7/x86 in a virtual machine. There are multiple ways I could try to get it off the disk image, such as via a floppy image or something. However, that sounds like effort. I’ll try to search for it in the raw disk image instead and just copy it out from there. Update: I’ve had to go through the shared floppy route. The data in this file is split up on the underlying file system. Fortunately, /dev/ entries are just really fancy files. Therefore, I could just write with tar to the floppy directly without having to first create an actual file system. The host could then use that “floppy” as a tar file directly.

Even when I have these roff sources, I still need to get them in a readable format. I’ll have to cheat and use groff -Thtml to generate an HTML version to put on the blog. However, to preserve some semblance of authenticity, I’ll also put the raw roff source up, along with the result of running nroff over it on the version running on V7/x86. That version of nroff attributes the trademark to Bell Laboratories. This is wrong. UNIX is a registered trademark of The Open Group.

7. Impressions

ChuckMcM was right. When you’re grateful for vi, staring at a blob of text with no syntax highlighting and with limited space, you start appreciating troff/nroff much more. In particular, LaTeX tends to have fairly verbose commands. Scanning through those without syntax highlighting becomes more difficult. However, ‘‘parsing’’ troff/nroff syntax is much easier on one’s mind. Additionally, the terse commands help because


stands out much less than


That can be helped by adding whitespace, but then you remove some precious context on your tiny 80×24 screen. troff/nroff are very much children of their time, but they’re not as bad as I may have made them look last time. Having said that, there’s no way you’ll ever convince me to actually touch troff/nroff macros.

As for the system as a whole, I was positively surprised how usable it was by today’s standards. The biggest challenge is getting the system up and shutting it down again, as well as moving data to and from it. I did miss having a search function whenever I was looking for information on roff in volume 2A of the manual.

I have the greatest of respect for the V7/x86 project. Porting an ancient operating system that hardcoded various aspects of the PDP-11 in scattered places must have been extremely frustrating. The drivers were written in the ancient version of C that is used on V7 (see /usr/sys/dev).


learn: Ancient troff sources vs. modern-day groff

(This is a guest post by xorhash.)


I’ve been on a trip on the memory lane lately, digging around old manuals of UNIX® operating system before BSD.† In doing so, I’ve come across the sources for the 7th Edition manuals. I wanted to show one part of volume 2A to other people, but didn’t want to make them download the entire 336 pages of volume 2A for the part in question. The part I wanted to extract was “LEARN — Computer-Aided Instruction on UNIX”, starting at p. 107 in the volume 2A PDF file).

A normal person would, I presume, try to split the PDF file. That is straightforward and produces the expected results. I believe I needn’t state that you wouldn’t be reading this if I solved this problem like any sane person would. Instead, I opted to rebuild the PDF from the troff sources provided at the link above.

I am not a very clever man, and thus I completely disregarded the generation procedure that was already spelled out. However, it wasn’t exactly specific anyway, so I didn’t miss out on much.

Getting the sources

So I knew what I needed to do: Get the troff sources. I asked that the Heavens have mercy on my poor soul if this requires a lot of adjustment for 2017 text processing tools. However, a man must do what a man must do. The file in question was called “vol2/learn.bun”. I had no idea what a bun file is, hoped it wasn’t related to steamed buns and clicked it. As it turns out, it’s just what we would call a self-extracting archive today. The shell commands are not very weird, so the extraction process actually worked out just fine. Now I had files “p0” through “p7”. Except what happened to “p1”, the world will never know.

First Steps

I’ve dabbled in man pages before, but that was mostly mandoc, not actual troff.
Accordingly, the first attempt at getting something going was as naive as it could get:
$ groff -Tpdf p* | zathura -
It led to, shall we say, varying results.

really butchered rendering attempt

Clearly, I was doing something very fundamentally wrong. Conveniently, volume 2A also had a lot of troff documentation. Apparently I was supposed to pass -ms and first run tbl(1) over the troff source before actually giving it to groff. That sounded like a good idea, but the results were still somewhat off:

not very butchered rendering attempt

Allow me to express my doubts that this text was written in 2017. If you compare the output with the known-good PDF, you’ll also notice that, somehow, “Bell Laboratories, Murray Hill, New Jersey 07974” turned into “CAI”. Unfortunate.

Back to Square One and Pick Up the Breadcrumbs

Continuing to read the page I got the learn.bun from, I also spied a section called “Macros and References”. That sounds relevant to my interests. tmac.s, which after studying groff(1) seems to be what would get used with -ms references some files in /usr/lib/tmac. I was not in the mood to let this flood over into my system, so I had to make minor adjustments and turn it into relative paths. I also renamed tmac.s to tmac.os to avoid colliding with the one provided by groff, making the new invocation:

$ tbl p* | groff -M./macros -mos -Tpdf | zathura -

Now we’re getting somewhere:

almost not butchered rendering attempt

It’s better than the previous attempts. But there are also some warnings and problems that need cleaning up:

  1. There’s a note that Bell Laboratories holds the UNIX®
    trademark, which is no longer true.†
  2. Now, this most certainly was not written in December 21,
    19117, either.
  3. tmac.os:806: warning: numeric expression expected (got `\')
  4. Every time the .UX macro was requested, I got:
    warning: macro `ev1' not defined (possibly missing space after `ev')
    environment stack underflow

Point 1 was easy to address, it’s a simple text change. Point 2 was caused by spurious dots in front of a call to .ND. However, the actual volume 2A PDF said a different date than in the file, so I adjusted that to match (June 18, 1976 to January 30, 1979).

And Down the Slippery Slope

As for points 3 and 4… Let’s just say groff/troff macros are definitely not meant to be written or read by humans and it’s a feat comparable to magic that someone wrote this set of troff macros. Line 806 is .ch FO \\n(YYu. Supposedly, that changes the location of a page trap when the given macro is invoked. The second argument is meant to be a distance, which explains why groff is complaining. I tried to checked what groff does and left none the wiser. FO seems related to the page footer, I seemed to get away with just deleting that line, though.

Finally, point 4. Apparently, .ev1 was used multiple times in the tmac.os. This looked like it should’ve been .ev 1 instead. Changing those, lo and behold, .UX stopped behaving funky for the most part. Yet for some reason, I’d still get multiple footnotes about the trademark ownership of the UNIX® trademark.† tmac.os sets a troff register (GA) when the .UX macro is first encountered so that the footnote is only made once. The footnote is being made twice. Something does not add up here..AI (author’s institution) resets GA, but the first .UX comes after .AI, so that’s not the problem. Removing the .AB/.AE macros from page 1 caused only one footnote to be made. Thus, I infer it’s actually intended behavior that the footnote is made once for the abstract and once for the main body. Checking with the volume 2A PDF again, I realized that point 4 was, in fact, fixed just by the ev1 changes and I was just chasing a bug that does not exist. I really should’ve checked the PDF twice.

The abstract finally looks okay.

good rendering attempt

Done! Wait, No, Almost

Okay, we’re done, we can go home, right? Almost, one last thing to do: On the last page, there’s something really important missing: the bibliography. Instead, there’s just “$LIST$” there. We can’t just turn Brian W. Kernighan and Michael E. Lesk into plagiarists!

Back to the troff documentation in volume 2A, there’s a match for “$LIST$” on p. 183. Apparently I need a reference file and preprocess the file with refer(1). That sounds simple enough. Fortunately, I got the reference file along with the macros above, so I didn’t have to look for that separately.

$ refer -pRv7man -e p* | tbl | groff -M./macros -mos -Tpdf | zathura -

half of the references are blank

Of course. Why would it work? That’d have been too much to ask for.
At least I get some nice hints:

refer:p2:148: no matches for `skinner teaching 1961'
refer:p3:114: no matches for `kernighan editor tutorial 1974'

The troff documentation conveniently explains the format for the reference file, so I could just add these two entries to Rv7man and be done with it. Thankfully, the pre-compiled PDF of the volume 2A manual had the information necessary to compile the bibliography entries with.

%T Why We Need Teaching Machines
%A B. F. Skinner
%J Harvard Educational Review
%V 31
%P 377-398
%D 1961

%T A Tutorial Introduction to the Unix Editor ed
%A B. W. Kernighan
%D 1974

now that’s what I call a bibliography

And of course, here is the product of this whole ordeal.

Closing Remarks

The Heavens were feeling somewhat merciful, but only just enough that I could waste no more than a day on this project. They really wanted me to spend that day on it, though.

On a side note, “the missing learn references” aren’t available from the link that was
provided. is now down, though the web archive still has it. Needless to say, I didn’t read that.

I will never, ever touch troff/groff again. mandoc is good at what it does and I’ll stick to mandoc for writing man pages. But if I ever need to get something typeset nicely from plain text?

LaTeX is the answer.
Not troff.
Never troff.
Not even once.

UNIX® is a registered trademark of The Open Group.

IRC necromancy

I’m xorhash, a guest poster, here to talk about my tale going down a trip on the memory lane with QuakeNet’s service bot Q. If you’re not interested in IRC, you can probably skip this one.

On the Trails of Q

As far as I know, QuakeNet’s service bot Q went through these three major codebases:

a. the old Perl Q,
b. the first version written in C, and
c. Q as part of newserv.

There’s a reason I didn’t have anything to link for (a). That’s because to the best of my knowledge and research, no version has survived these past decades.

As for (b), it seems only the linked version 3.99 from the year 2003 was saved.
The CVS repository and thus commit history has been lost.

If anyone has either actual code for the old Perl Q or the CVS repo for the old
Q written in C, please reach out to me via `xorhash ++at++’.
I’m most interested in looking through it.

However, not all hope was lost with the old Perl Q. As it turns out, most likely, the old Perl Q was actually based on an off-the-shelf product called “CServe”. What makes me think so?

Let’s take a look at [the QuakeNet Q command listing from 1998.

I picked the command “WHOIS” and googled its use “Will calculate a [email protected] mask for you from the whois information of this nick.” This lead me to a help file for StarLink IRC. At the top, it reads:

CStar3.x User Command Help File **** 09/10/99
Information extracted from CServe Channel Service
Version 2.0 and up Copyright (c)1997 by Michael Dabrowski
Help Text (c)1997 (c)1997 StarLink-IRC (with permission)

Wait a second, “CServe Channel Service”? I know that from somewhere.

[email protected]

So the commands between that help file and the QuakeNet Q command listing match up and so does Q’s host today. Most likely, I’m on the right track with this. What’s left is to track down a copy of CServe.

Note: I’ve been on the old Perl Q for a while and this strategy didn’t use to work. It seems Google newly indexed these pages. For once I can sincerely say: Thank you, Google.

I found that CServe was hosted on these websites:

a. Version 3.0 on,
b. Version 3.1 on,
c. Version 4.0 on, and
d. Version 5.0 and above on

The only surviving versions are 3.0 and 5.1. CServe got renamed to “CS” starting with 5.0 and was rewritten in C by someone other than the original CServe author, going by the comments in the file header of CS5.1 `src/show_access.c’. CS was actually sold as a commercial product. I wonder how many people bought it.

QuakeNet most likely took a version between 2.0 and 4.0, inclusive, as the basis for the old Perl Q. Which one in particular it was, we may never know. If you have any details, please reach out to me at the e-mail address above.

I can’t make any clever guesses anyway since the only versions that the web archive has are 3.0 and 5.1. The latter is written in C, so it quite obviously can’t be the old Perl Q.

Making It Run

So now that I have CServe 3.0, I wanted to actually see it running.

There are three ways to reasonably accomplish this:

a. port CServe to a modern IRCd’s server-to-server protocol,
b. port an old IRCd to a modern platform,
c. emulate an old platform and run both IRCd and CServe there.

I chose option (b).
Once upon a time, I did option (a) for the old UnderNet X bot. It was a very painful exercise to port a bot that predates the concept of UIDs (or numeric nicks/numnicks as ircu’s P10 server-to-server protocol calls them). There’s nothing too exciting about doing (c) by just emulating a 486 or so and FreeBSD, just sounds like a boring roundtrip of emulation and network bridging.

Fortunately, the author was a nice person and wrote on the CServe website that version 3.0 requires “ircu2.9.32 and above”.

It seems the ircu2.10 series followed right after ircu2.9.32. While I’m sure there’s some linking backwards compatibility, determining which ircu in the ircu2.10 series still spoke enough P09 to link with CServe sounded like an exercise in boring excruciating pain. Modern-day ircu most certainly no longer speaks P09. Besides, what’s the fun in just doing the manual equivalent of `git bisect’?

So after grabbing ircu2.9.32, I tried to just straightforward compile and run it.

There’s a `Config’ script that’s supposed to be kind of like autoconf `configure’, but I’ve found it extremely non-deterministic. It generates `include/setup.h’. I’ve made a diff for your convenience. It targets Debian stable, and should work with any reasonably modern Linux. There are special `#ifdef’ branches for  FreeBSD/NetBSD in the code. This patchset may break for BSDs in general.

Do not touch `Config’, meddle with `include/setup.h’ manually. Remember this is an ancient IRCd, there are actual tunables in `include/config.h’.

The included example configuration file is correct for the most part, but the documentation on U:lines is wrong. U:lines do what modern-day U:lines do, i.e., designate services servers with uber privileges.


Excuse Me, But What The Fuck?

Of course, I’m dealing with old code. It wouldn’t be old code if I didn’t have some things that just make me go “Excuse me, but what the fuck?”

Looping at the speed of light

aClient *find_match_server(mask)
char *mask;
  aClient *acptr;
  if (BadPtr(mask))
    return NULL;
  for (acptr = client, (void)collapse(mask); acptr; acptr = acptr->next) 
  if (!IsServer(acptr) && !IsMe(acptr))
    if (!match(mask, acptr->name))
      break;                                                                                                    continue;
  return acptr;

See that `continue’ way on the left? What is it doing there? Telling the compiler to loop faster?

Carol of the Old Varargs

So apparently some of this code predates C89. Which means it uses old-style declarations, but that’s okay. It also uses old-style varargs, which is adorable.

The hacks around not even that being there are adorable, too:

voidsendto_realops(pattern, p1, p2, p3, p4, p5, p6, p7)
char*pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7;
voidsendto_realops(pattern, va_alist)
  va_list vl;
  Reg1 aClient *cptr;
  Reg2 int i;
  char fmt[1024];
  Reg3 char *fmt_target;


  (void)sprintf(fmt, ":%s NOTICE ",;
  fmt_target = &fmt[strlen(fmt)];

  for (i = 0; i <= highest_fd; i++)
if ((cptr = local[i]) && IsOper(cptr))
  strcpy(fmt_target, cptr->name);
  strcat(fmt_target, " :*** Notice -- ");
  strcat(fmt_target, pattern);
  #ifdef USE_VARARGS
  vsendto_one(cptr, fmt, vl);
  sendto_one(cptr, fmt, p1, p2, p3, p4, p5, p6, p7);

These functions were declared like this (the example chosen above actually has
no declaration because why not):
extern    void    sendto_ops();


There are `mycmp’ and `myncmp’ for doing RFC1459 casemapping string comparisons. `strcasecmp’ got `#define’d to `mycmp’, but in one case `mycmp’ got `#define’d back to `strcasecmp’. It seemed easier to just remove `mycmp’, replacing it with `strcasecmp’ and forgo RFC1459 casemapping. This is doubly useful because CServe doesn’t actually honor RFC1459 casemapping.

Waiting for the Cookie

ircu uses PING cookies. I was rather confused when I didn’t get one immediately after sending `NICK’ and `USER’. In fact, it took so long that I thought the IRCd got stuck in a deadloop somewhere. That would’ve been a disaster since the last thing I wanted to do is get up close and personal with the networking stack.

As it turns out, it can’t send the cookie:

 * Nasty.  Cant allow any other reads from client fd while we're
 * waiting on the authfd to return a full valid string.  Use the
 * client's input buffer to buffer the authd reply.
 * Oh. this is needed because an authd reply may come back in more
 * than 1 read! -avalon

Nasty indeed.

I lowered `CONNECTTIMEOUT’ to 10 in the diff linked above. This makes the wait noticeably shorter when you aren’t running an identd.

CServe Isn’t Much Better

Not that CServe is much better. I have to hand it to Perl, I only needed to undo the triple-`undef’ on line 450 of `’ and it worked with no modifications. God bless the backwards compatibility of Perl 5.

That said, it has its own interesting ideas of code. This is the main command execution:

foreach $i (keys %commands)
    if($com eq $i)
    { $found = 1; break; }
if($found == 1)
    open(COMMAND, "<./include/$com");
    @evalstring = <COMMAND>; close(COMMAND);
    foreach $i (@evalstring) { $evals .= $i; }
    &notice("2No such command 1[4$com1]. /msg $unick SHOWCOMMANDS\n");

Yep, it opens, reads into an array, closes and then evals. For every command it recognizes. Of course, this means code hot swapping, but it also means terrible performance with any non-trivial amount of users.

Oh, and all passwords are hashed. But they’re hashed with `crypt()’. And a never-changing salt of ZZ.

End Result
up & running

Was it worth it?
No, not really.
Would I do it again?

You probably do not want to expose this to the outside world.
The IRCd code is scary in all the wrong ways.

Further Links

Some other things if you’re into ancient IRC stuff:

WYSE Unix Virtualized

(this is a guest post from Tenox)


WYSE Unix Virtualization Challenge has been officially won by Mihai Gaitos of He received $100 prize via PayPal. Congratulations!

WYSE Unix has now been virtualized and can run in Qemu via Curses mode, or modified Bochs due to character map issues and vanilla VirtualBox!

wyse_on_bochswyse_on_vboxMihai has posted some gory details of the installation challenges on his website.

Ready to run image with modified Bochs binary for Linux is available here.
VirtualBox OVA file available here.

For hard core fanatics, the system comes with SLIP/slattach so you should be able to network it much like Dell Unix.

Special thanks to:
Andrew Gong for finding a tape image on eBay
Al Kossow of for recovering the tape image
Michal Necasek for patching up the original floppy disk image


Porting Quake II to MS-DOS pt5 – 3DFX, GameSpy, Quake 2, and The Universe

The following is a guest post / wrap-up of the Q2DOS adventure by [HCI]Mara’akate.q2dos_3dfx_4
In the last update sezero and I([HCI]Mara’akate) tied up most loose ends with regards to Q2DOS.  Specifically: adding in DXE support for mods and cleaning up some code from the early efforts.  During this time, a forum user by the name of ggorts (strogg spelled backwards!) mentioned the possibility of using an old Mesa version with 3DFX support in DOS. I worked on separating the ref_soft from being statically linked into a DXE form and sezero cleaned up any potential problems there.

I mentioned the possibility of attempting the Mesa port to sezero and he thought it was probably a wasted effort and thought making a ref_glide depending only on glide3x.dxe would be a better way to go with less overhead.  I started some initial work on it but quickly abandoned this side-project as I have no real glide (or even OpenGL) knowledge and didn’t have enough time on my hands to play around with it.

Around this time, we also separated the GameSpy browser code into a separate DXE for potential legal issues.  The GameSpy code was publicly released, but never officially GPL’d.  Using this method, other port authors could link against a gamespy.dll to add in the browser capabilities that connect to my GameSpy master server emulator (see QDOS branch for source code to that particular project).

Ggorts also came up with some code for us to be able to finally use the banked modes and Mode-X 320×240.  Though 320×240 Mode-X seems to have some issues with certain emulator configurations, for the most part it works OK.  This also helped us to get some ASM rendering code in from Q1 and help clean up the original mess that was the SVGA driver; a lot of unused code from Q1 was removed and sezero found a clever way to send the video modes list between the game binary and renderer DXE.

In any event, one night I figured I’d take a stab at trying to get Mesa working in Q2DOS.  Checking out the Mesa3d FTP and researching the various changelogs it appears as if Mesa 5 series was the last true effort with Mesa 6.4.x series being the last maintained version with 3DFX specific code.  I got everything to compile but ran into hard-lock issues no matter what I attempted.  During this time, ggorts found out some various small, but now obvious issues. Including increasing the stack size to 1MB and he hard-coded the ref_gl to only work in 640×480.  It took a lot of pleading but eventually he released his source with a static compile for Voodoo 1 cards only as he was testing this on emulators like DOSBox with glide support and PCem dev branch.

I worked on cleaning up the source and he produced some glide3x libraries for me for Voodoo 2 and Voodoo 5 as these were the only cards I personally owned.  Imagine my surprise as I first loaded it up and it actually worked!  And it was smooth with no rendering issues!


At this point, sezero became involved and worked very hard to clean up the Mesa compile issues, including various scary warnings and helped to update us to the final glide3x commit pushed to the development branch and Mesa v6.4.3 which was an unreleased maintenance update for Mesa v6.4.2.

It was a long journey to get the code all working together just right, and a big thanks goes out to the early Mesa crew including Brian Paul, Daniel Borca, and “KoolSmoky” and the mysterious ggorts fellow who pushed hard for this feature.

To recap, Q2DOS from the last time we talked now has:

  • 3DFX Rendering with Mesa v6.4.3 for all Voodoo cards.
  • Separated renderer so it is no longer statically linked.
  • GameSpy is now a DXE.
  • WAV streaming, which is practically free as opposed to the OGG format.


We are about at the end of our Q2DOS journey.  A few odds and ends with Mesa and Voodoo 5 SLI issues remain (though nothing too show stopping) and there’s a small wishlist of some unnecessary features but it’s come a long way from the initial null driver effort!


I have to say it is simply incredible to see how Q2DOS went from a very primitive ‘wow it works’ port to a full featured port.  Simply amazing!

For those who missed the adventure it starts in Part 1, continued in Part 2, Part 3 and Part 4. Virtual Machines

(this is a guest post by Tenox)

Ran across this curiosity today: Microsoft Edge Dev Center provides a bunch of ready made virtual machines with different versions of IE web browser. But they can be used for different purposes if you need to quickly spin up a specific version of Windows quickly.

This is whats available:

modeirnie1Different hypervisor type images on Windows, Mac and Linux are available:

modeirnie3Very handy stuff. This is beloved Windows XP after it booted first time:
modeirnie2Very handy and not only for browser testing.

There also is a Remote IE which opens IE window straight from Azure. I wonder what are implications of it for censorship in some countries as well as piracy etc.

VenturComm Venix/86 on MESS/MAME

(This is a guest post by Tenox)

This is follow up to a previously posted challenge to virtualize VenturComm Venix/86 so that it can be run on a modern machine under an emulator. The competition was a huge success and the rest of this post is an entry by the winner – Jim Carpenter. Enjoy!

Install MAME/MESS 0.164 and get the “at386” machine running. Standard issue ROMs.

Create a new hard drive image with “chdman createhd -chs 615,4,17 -c none -o hd.chd“. This is only 20MB. You can certainly use larger drives but make them a standard type, something that is a defined drive type in the BIOS. I’d stay away from user defined types.

Start the emulator, configure the first floppy drive to be DD and the second to be HD. Restart so it takes effect. Attach XFER.IMG to the first floppy and your hard drive image to the hard drive. Restart again. (Venix uses the BIOS for *everything*. So if you attach without rebooting, chances are the BIOS missed your hard drive which means Venix won’t see it either.)

Go into the BIOS and configured the floppy and hard disk types. The command above creates a type 2 drive:venix1Save and exit and let it reboot.

We wish to prepare the winchester hard disk:
venix2 Continue reading “VenturComm Venix/86 on MESS/MAME”

My experience with the Gravis UltraSound Part 2: Synergy ViperMax / Gravis UltraSound Extreme

(guest post from Frank Sapone)

Synergy ViperMax / Gravis UltraSound Extreme

A few months ago I made a guest-post about my personal experiences with the
Gravis UltraSound cards.  In this article I mentioned there were a few variants
besides the standard GUS “Classic”, MAX, and PnP series.  I was unable to
comment on the other cards since I did not own them.  Well, that all changed
a few weeks ago when I contacted someone who wrote some pack-in software that
was included with most GUS cards and surprisingly he still had all his cards.
Even better, he was willing to give them to me!

One of the cards I received was the Synergy ViperMax.  I have read some usenet
posts and have talked to other people who were active in the demoscene in the
mid-90s and apparently this card was originally designed by STB and then STB
produced their own card that has an ESS1688 chipset (for SB Pro compatibility
and better Windows drivers) and the GF1 chipset (the IC that makes the GUS
it’s own).  How true is this story?  I have no clue, as I have never seen an
STB variant of this card, but I have seen STB GUS PnP (the AMD Interwave
version) as Compaq OEM clones for sale occasionally.

In any case, Synergy started producing this card and it’s kind of a rare
number.  Again, rumours afloat, that the guy from Synergy was coming to
demoparties and giving these away to groups that won competitions in an
effort to stir up some interest/sales.  And before Advanced Gravis all but
gave up on the sound card market they took the Synergy ViperMax cards and
simply placed stickers over the Synergy logo and card name.  Gravis also maxed
out the onboard RAM to 1MB (the ViperMax comes with 512kb by default). It is
exactly the same board, which leads me to believe Gravis may have purchased
remaining stock of the Synergy cards and unloaded them.  The UltraSound Extreme
may be even more rare than the ViperMax.  It’s hard to say as I have personally
never seen either of these cards for sale on ebay.

Keeping the GUS roots, the card is almost completely plug and play. The only
thing you must change is a jumper for CD-ROM Enable/Disable.  Like the GUS MAX
there is CD-ROM interface support.  Contrary to rumours, this card is NOT GUS
MAX compatible!  It does not contain the Crystal CS4231 CODEC chip or emulate
it.  This means no MAXSBOS and no special demos that will output 48khz (I only
know of one, The Secret Live of Mr. Black by Orange).  I feel this
misinformation was started because of the CD-ROM interface that was also unique
to the GUS MAX.  To setup your card you just run viprinit in DOS with your
appropriate SET BLASTER and SET ULTRASND variables and it configures the rest.
However, I noticed viprinit will not properly change your base address for the
ESS chipset (i.e. you want to change it from A220 to something else).  No fear,
Synergy included the ESSCFG.EXE utility as well allowing you to change the
base address.  Initial configuration is set with VSETUP.EXE from DOS.

Windows 95 installation is basically the same as the earlier cards. You
run the setup.exe and it will install the ESS drivers.  It tries to setup
some extra stuff for UltraSound as MIDI device.  And it does work just fine
but a gotcha is that the DOS stuff will break.  I never had a reason to use
GUS’ MIDI capabilities from within Windows so this wasn’t a deal breaker
for me.  After a reboot you will likely have to reconfigure your card
manually from the device manager but after that it’s smooth sailing.  And yes,
you can install the updated ESS1688 drivers with no ill-effects. However,
if there are any differences in performance I have yet to notice it. Last known
official ESS drivers for Windows 9x at

The ESS chip is really nice, it sounds very similar to the OPL3 and it has
SB PRO compatibility (take THAT SB16!).  Whats the difference?  The SB16 only
states that it’s Sound Blaster compatible, not Sound Blaster PRO compatible.
This means some earlier titles like Wolfenstein 3D will only output in mono
on the SB16.  With the ViperMax, you can hear stereo sounds again.

Wolfenstein 3-D
Wolfenstein 3-D

Someone asked me if SBOS and MegaEm work.  SBOS, no.  MegaEm, yes but with no SB emulation.  You can probably make MegaEm work with the SB emulation if you
want to play around with running ESSCFG, changing your PnP settings, updating
your BLASTER and ULTRASND variables then running viprinit.  But, you’ll need
a lot of free resources and quite frankly I fail to see a point.  If anyone
out there has pulled it off drop me a comment.

Since the card has a GF1 IC there is no comparision between the earlier GUS
cards.  They will all sound the same.  The signal-to-noise ratio is acceptable
though I haven’t measured what it truly is, but for gaming and watching some
demos it’s capable.

All in all, this is a great card.  If it was released earlier and through
Advanced Gravis they could have still been in the market.  Another nice
side effect of this card is that Windows XP has ESS1688 drivers. Just install
the cards as a non-pnp legacy device, configure manually and enjoy sound!

I made a few more rips comparing the differences between the ESS mode and GUS.
The few module files are played with XTC-Play and two of them (ATBIA3 and
Parallel Universe) are XM modules over 1MB.  XTC-Play has a way of quadrupling
the RAM usage by downsampling.  However, the modules still sound quite good
and it’s quite a thing to hear the GUS playing large high-quality modules.


Before I bring this article to a close, here is some ViperMax/GUS Extreme

* Gravis UltraSound Extreme Manual:
* Gravis UltraSound Extreme CD ISO:
* Synergy ViperMax CD ISO:

Enjoy the rips!  In a few weeks I’ll have a write up on the Gravis UltraSound
Plug and Play Pro (waiting for my RAM upgrade) and finally some last minute
thoughts and information about a few other OEM cards and the GUS ACE.

For comparison here is DOOM II Map 06


Sound Blaster

I don’t use Windows XP very often, but when I do…

(this is a guest post by Tenox)

I recently needed to install Windows XP. Because I don’t do that very often nowadays I decided to document the “pro way” of doing it.

First you should consider getting a volume license copy of Windows XP CD because it doesn’t require activation over the internet. The process below will work with any version, but it will require activation.

Then you need to download and install nLite which lets you add SATA/AHCI, network, display, audio, drivers and customize a fully unattended installation, including the product keys, and some tweaks like autologin, themes or show extensions/hidden files in explorer. Create your own bootable XP .iso file. You should probably test it in VMware/Vbox/Qemu first to see that all the settings are to your liking and the setup prompt screens are gone.

Second you need WSUS Offline Update, version 9.2.1 (which is the LAST version supporting Windows XP). It will let you roll out your own Service Pack 4 for Windows XP, including all the updates and goodies like .NET framework, Silverlight and DirectX updates. Create your own SP4 .iso file.

Booting Windows XP from a regular USB pen drive is notoriously difficult, so this is where ISOSTICK comes handy. Put both of the iso files on to the stick, insert to the PC and watch the magic happen.

It’s quite easy to integrate the SP4 in to the boot cd itself, but then it outgrows size of a physical CD, which is not a big deal with ISOSTICK, but I don’t mind installing the updates in a second step.

Finally if you need to install apps automatically you can consider something like Ninite.


Atari System V UNIX Saga – Part III – SCSI Disk Replacement

(note this is a guest post by Tenox)

In previous posts from ASV series I have explained why I got hooked on Atari System V UNIX and what I had to do to get a decent resolution out of Atari TT. Having built the VGA monitor adapter, the next challenge was to replace the internal SCSI hard disk with a flash storage of some sort. I really don’t like spinning hard disks and especial the old ones.

I have mentioned that there are two surviving ASV disk images. The better one was made out of a rather large old, loud and obnoxious Maxtor. I’m definitely not having this monstrosity inside of my beloved Atari!

Maxtor LXT340SY
Maxtor LXT340SY


So how can you replace an old SCSI hard disk with a modern flash device? There actually are several different ways.

If you have the money you can go industrial route, which is a SCSI disk replacement for various machinery and embedded systems produced by ReactiveData. You can buy one of these for a little over $1000 USD. The good part is that they substitute a specific real hard disk model and are exceptionally good in quality of emulation. However, spending a lot of money on my TT and TenoxVGA already, this really wasn’t an option without getting a divorce.

Another approach is to use SCSI to IDE bridge combined with IDE to CF adapter or possibly SCSI to SATA bridge and SATA SSD disk. These are widely used by Atari / Amiga / Mac 68k community. The most popular bridge come from a company called Acard. I actually had one of these at hand, AEC-7220U which I used for TOS/GEM work.

acard front
acard front


Did it work? As you can guess – of course it didn’t! The initial boot loader errors out unable to read disk capacity.

Atari SYS V failed to boot
Atari SYS V failed to boot


Atari ST/TT, somewhat similarly to 68k Macs require a hard disk driver, present on the hard disk itself. There are several 3rd party implementations, some of them, like HDDRIVER maintained up to present date. Unfortunately these drivers are TOS specific and obviously don’t work with Atari Unix. The system comes with it’s own hard disk driver which seems to be obsolete and with limited hardware support.

The next step was to research and try out some other SCSI to IDE bridges in hope one would just work. And surprisingly there are several to choose from.

The second on the line was I-O Data R-IDSC21-E/R. No longer produced and supported, however still fairly popular. Usually regarded as the ultimate bridge with most fancy options bells and whistles. It has most jumpers and modes of all tested devices. For instance ATA PIO and DMA modes.  Unfortunately this didn’t help at all and same error was observed.



Another device tried was Yamaha v769970. This bridge was conceived to allow use IDE CDROM and Hard Disks with Yamaha samplers. No longer produced and obsolete, it’s somewhat most easy to set up, robust and stable. It’s actually my favorite bridge for day to day use, except for ASV where it just doesn’t work.



More recent kid on the block is an integrated SCSI2IDE + IDE2CF in one device called Aztec Monster. Recently designed and currently produced in Japan (you can buy one on eBay) is a fairly decent choice, which I recommend to every one. I had a lot of luck with these, except for ASV of course…



I also looked in to SCSI to SATA bridges, like this one, but they have additional issues, like need to convert LVD to SE on one end and SATA to IDE to CF on the other. Little bit too complex for what I wanted.

Being out of luck I started researching if it would be possible to build an open source version, which can be easily diagnosed and fixed. Doing so I found out that there in fact is one open source SCSI adapter called SCSI2SD.



I was bit skeptical in the beginning but then I though that being open source it can be debugged and fixed if it needs to be. So I immediately ordered one.

Once it arrived, I plugged it in, applied the image to the card and BAM! It worked! The system booted fully and worked flawlessly!

Atari Unix System V – Boot Sequence from Antoni Sawicki on Vimeo.


Over time SCSI2SD proven stable and flawless. One feature that Mac users will appreciate:

--apple Set the vendor, product ID and revision fields to simulate an
        apple-suppled disk. Provides support for the Apple Drive Setup

In the next article I will write about my first steps in the system post boot and then bringing it to a more or less usable state. Stay tuned!