Vim on the 5160, and the int 22h refusal
Vim 5.8 runs on the 5160 under DOS 5. The smoke test passed on the real machine both times I ran it, and :!MAKE now swaps Vim out to disk so MAKE and TCC get the memory. On the 86Box 5160, MAKE went from 61,903 bytes free to 540,763 on DOS 5. The swap takes about 10 seconds on the ST-251, which isn’t fast, but it beats quitting Vim every time.
The fork is public at github.com/robertrico/vim-xt. GitHub Actions builds it with Open Watcom on every push and checks it for 186 or later instructions, and the build there comes out the same size as the one on my Mac, 388,790 bytes.
The 5.8 tags in vim-history are 6.0d alpha
My first assumption was that github.com/vim/vim-history had a clean 5.8 to start from. It doesn’t. The CVS import breaks at commit c3cba927 (“vim-5.7 pl 002 –> vim-6.0d”), and every tag from vim-5-7-003 through vim-5-8-009 holds 6.0d alpha sources with 5.8 version strings on them. You can tell because they have fold.c, FEAT_TINY, Make_bc3.mak and Make_tcc.mak, none of which exist in 5.8.
If you want real Vim 5.8 source, use the release tarballs and patches from ftp.nluug.nl/pub/vim/: unix/vim-5.8-src.tar.gz, unix/vim-5.8-rt.tar.gz, extra/vim-5.8-extra.tar.gz (that one has the DOS files) and patches/5.8.001 to 5.8.009. I imported those onto an upstream branch and forked from there. That branch and the tag vim-5.8.009 are in the public repo, so git diff vim-5.8.009 main shows every change I made.
Open Watcom instead of Borland
5.8’s DOS build was made with Borland C++ and leans on Borland’s conio text-window calls (window(), gotoxy(), insline(), delline()). Watcom doesn’t have them. I wrote a small direct-video layer that keeps Borland’s behavior, because Vim sets the cursor relative to the scroll region and depends on it. It writes characters straight into B000 or B800, waits for horizontal retrace on a real CGA to avoid snow, and scrolls with BIOS int 10h. The hardware cursor only moves when Vim is waiting for a key, since moving it on every character costs time on a 4.77 MHz part.
Everything else was library mapping: bioskey, biostime, coreleft, findfirst and friends. A disassembly of every object in the link map, Vim’s and the C library’s, found no 186 or later opcodes in 117,237 instructions.
Vim held most of the 640K
With a small file open, Vim took about 483K: a 385.5K main block plus heap blocks of 64K and 32K. That left MAKE about 60K, which isn’t enough for MAKE plus TCC. The 5.8 Borland build used a commercial library called SPAWNO for this.
So I wrote dosswap.asm, a 1.5K stub linked first so it sits right after the PSP. On :! it writes the rest of Vim and every heap block to $TEMP\VIMxxxx.SWP, frees the memory, runs the command through COMMAND.COM with DOS EXEC, then grows the blocks back at the same segments and reads everything in. While the program runs, Vim holds about 1.8K.
86Box 5160, :!MAKE | Bytes free for MAKE |
|---|---|
| Before the swapper | 61,903 |
| PC DOS 3.30 | 550,603 |
| MS-DOS 5.00 | 540,763 |
I also turned QUICKFIX back on, which 5.8 left out of the DOS build. It costs 10.5K of exe. The default DOS errorformat already matches Turbo C’s Error FILE.C 12: message lines, so in 86Box :make on a broken file lands on the first error line and :cn on the next.
The 5160 refused to swap: “interrupt 22 points into Vim”
On the real machine :! printed Not swapping Vim out: interrupt 22 points into Vim, with TEMP set.
The stub checks for interrupt vectors that changed since Vim started and now point into memory it’s about to swap out, because a handler there would run garbage. Int 22h is the DOS terminate address. DOS EXEC points it at whoever called EXEC, and leaves it there afterward. So once any :! falls back to plain system(), int 22h points into Vim for good, and the check refuses every swap from then on. The child gets its own copy of int 22h anyway, so it doesn’t matter while Vim is on disk. The fix was to skip 22h.
86Box never hit this because the first :! there always swapped, and the swap’s own EXEC returns into the stub, which stays resident. I added a step to the swap test that forces one fallback first. The old build fails it, and the fixed one passes on DOS 5 and 3.3.
How it gets tested
The 86Box machine is an IBM 5160, 8088 at 4.77 MHz, 640K, CGA or MDA. Disk images for MS-DOS 5.00 and 6.22 are built straight from setup disk 1 with mtools, without running SETUP. A flag file makes AUTOEXEC.BAT run the smoke test, which writes RESULT.TXT, and the Mac polls the image with mtools and kills 86Box when it’s done. 86Box ignores SIGTERM, so it takes kill -9.
None of that runs on GitHub, because it needs DOS and Turbo C images I can’t put in a public repo. CI only builds and runs the opcode check. The emulator tests stay on the Mac.
What the licenses asked for before going public
Vim 5.8 is charityware, and the license is in runtime/doc/uganda.txt. It lets you hand out a modified Vim as long as the license text stays with it, you don’t strip its restrictions, and the source of your changes is available to the maintainer. A public repo covers that. It also asks for a donation to the Kibaale Children’s Centre through ICCF Holland, which the README now mentions. I put my own new files under the same license so the repo has one.
The one I didn’t expect was Open Watcom. vim.exe has Watcom’s C run-time library linked into it, and section 2.2(d) of the Sybase Open Watcom Public License says that if you hand out its code in executable form you need a notice “in the code itself as well as in related documentation” that the source is available and where to get it. So :version now prints that, along with a line saying this is a fork and not an official Vim. It costs a few hundred bytes.
What stayed out: the DOS disk images, the MS-DOS setup disks and Turbo C, which aren’t mine to redistribute. My local paths moved into an untracked xt/local.sh. I also pushed only main, upstream and the one tag, and left behind the roughly 1,500 vim-history tags, so nobody clones the bad vim-5-8-* ones from me.
Open threads
- Why the first
:!on the 5160 fell back at all. Whatever it was happened before the int 22h problem and I didn’t catch the message. :makewith real Turbo C errors on the real machine. It’s only been checked in 86Box.- Editing a large file (vim.exe itself) hung in 86Box.
- Stack use isn’t measured. It’s 8K.
- The 10 second swap. Whether that’s the ST-251, the 32K chunks, or just 480K of disk I/O at 4.77 MHz.
- CI artifacts expire and need a GitHub login. A release on a tag would give a plain download link.