PrintStar's Blog
Ramblings of a Fortran Nut
July 10, 2014 by Jeff

Switching to Microsoft

After a couple of days away from my Retrochallenge, I decided to dive back into trying to get that damn Z80 CPU to listen to me from MS-DOS.  A few days back, I actually stopped in frustration when I realized that I would definitely need to do some x86 assembly language programming to get things moving forwards.

I had posted a scanned page from the Rainbow 100′s CP/M technical documentation that seemed to outline how to pass a message to the Z80 properly:

The page outlined the values for the registers of the 8088 when trying to pass arbitrary code to the Z80.  To be honest, I have some serious doubts about the above scheme working when in MS-DOS; I can’t seem to see where anything similar is done in the MS-DOS BIOS code to trigger the Z80 to perform disk access.  There is a good chance that the CP/M BIOS is performing some extra work behind the scenes after the above call is made.  However, the method above is easy enough to try.

I foolishly assumed, though, that I would be able to first set the values of the 8088 registers and then signal the 8088 output port from C.  This idea is, of course, nonsense because C is too “high-level” to hope that any particular register would persist between being set and my calling a C outport() function.  I needed to use assembly, which annoyed me enough to stop for a bit.

Yesterday I decided to dive back in.  However, I did run into some speed bumps.  Normally on the Rainbow I work with Turbo C as opposed to Microsoft C.  This preference is based on:

  • Turbo C’s MAKE utility actually works (unlike Microsoft’s lobotomized MAKE)
  • Turbo C’s directory layout is considerably simpler

For an assembler, things became a bit trickier.  I do also have Turbo Assembler, but, when I ran it yesterday, I found that it did not work on the Rainbow at all.  It wouldn’t even run under Code Blue.  And why is doesn’t it work?

Borland is mildly famous in DEC Rainbow circles (is that a thing?) for being complete jerks.  Borland produced a number of compilers and applications for the Rainbow as native programs, both under MS-DOS and CP/M.  However, when Turbo C 2.0 was released, things went bad.  Rainbow users who bough the software were horrified to find that this “MS-DOS compatible” compiler didn’t run at all, while previous versions ran just fine.  Borland was completely silent on the issue, too.

One enterprising Rainbow user was able to determine what was actually happening.  Internally, the Borland compilers were unexpectedly using MS-DOS interrupt 0×18.  This interrupt is relatively harmless on an IBM PC, but it is used for communications ports on a Rainbow.  There was no reason for Borland to choose 0×18 in the first place; it is entirely arbitrary, which makes Borland’s choice so frustrating.  This helpful Rainbow user, though, was able to generate a set of patches for the Turbo C executables, the compiler and preprocessor specifically, that changed their internal interrupt calls to use 0×60 instead.  The same user went on to generate patches for a number of other Borland tools as they continued to use interrupt 0×18 all over their development tools, including Turbo Assembler..

My copy of Turbo C is obviously already patched.  However, I never did take the time to patch Turbo Assembler, apparently.  Additionally, I have no hard-copy documentation for any Borland tools.  The unpatched assembler and the lack of immediately available documentation convinced me that it was time to move on to Microsoft’s tooling.

I spent yesterday transferring Microsoft’s Macro Assembler and C Optimizing Compiler onto my Rainbow 190.  All these packages do add up to a considerable amount of disk space relative to its 20MB disk.  However, my 190 is not one of my long-held Rainbows, so it started the Retrochallenge with a relatively empty disk, only containing my essentials:

  • MS-DOS 3.10b
  • Borland Turbo C 2.0
  • BinkleyTerm 2.40
  • Kermit

The transfer of MASM to the Rainbow was simple and fast.  Although the archive was about 680KB in size, it goes relatively fast transferring it from a GNU/Linux server via ZModem at 19200 bps.  On the other hand, my stripped-down MSC 5.1 distribution, weighing in at about 900KB, was sitting on another Rainbow with a notoriously (in my house) slow hard disk.  I couldn’t transfer between the two Rainbows using ZModem because the receiving Rainbow would time out prior to the “slow hard disk” Rainbow even accessing the file to transfer.

Whenever serial transfers become problematic, it’s time to pull out old, slow, and reliable Kermit.  If ZModem were a sports car, Kermit would be a car that won’t start and is being pushed manually up a steep hill. In contrast, though, Kermit provides drastically more reliable error checking than ZModem to the point of overkill.  Back in the BBS days, I rarely had any issues with ZModem, but occasionally the speed of disks can become an issue, requiring a slower transfer rate.  I started the transfer and left the two Rainbows to talk it out.

In summary, I now have a fully function Microsoft C and MASM environment all set up and functioning.  Hopefully I can get on with my work.

  •   •   •   •   •
July 3, 2014 by Jeff

Finding the Z80

I started today’s Retrochallenge work by trying to hunt down exactly how to trigger the Z80 to execute code.  Unsurprisingly, the Rainbow’s MS-DOS technical documentation doesn’t actually provide an answer to this question directly.  Because the Rainbow’s MS-DOS BIOS only employs the Z80 for disk access, there would be no “practical” reason to do so otherwise.

The interrupt tables also suggest this inability to access the Z80.  The only interrupts available that appear to do anything similar are actually “Interrupt from the Z80A,” rather than asking the Z80 to do work.  So where to go now?

Digital’s Technical Documentation  for the Rainbow is an odd collection of massive binders containing a plethora of both useless, high-level information (“Available Peripherals: Keyboard…”) and low-level gems (the video memory’s linked-list layout and scrolling via changing pointers alone).  It also, oddly enough, contains the complete Microsoft Macro Assembler source code for its MS-DOS BIOS.  That’s right, Digital provided every last line of source code for their BIOS.

If we want access to the Z80, we just need to look up the RX50 disk driver source code in the BIOS.  Sure enough, when we look closely through the code, we come across the routine “execz80” in the assembly:

I’m not any sort of assembly language expert, but I can usually stumble through the code.  It appears, though, that simply pushing some data OUT to port 0 (the value of intz80) on the 8088, causing the Z80 to begin execution of code.  There is obviously some work to be done setting up what exactly the Z80 should be doing, but it appears that the process is rather straightforward.  The 8088 then sits in a waiting loop checking to see if the Z80 is done.

I’d rather like to avoid writing assembly language code for this challenge with the exception, possibly, of some Z80 assembly.  Peeking through Turbo C and Microsoft C headers, I ran across “outport” and “outp” respectively (MSVC still supports outp…).  These should allow me to fire off requests to the Z80 from C hopefully, but we’ll have to see.

As an aside, I’ll try to post any images to my SDF Gallery account for all to see and enjoy.  Some Twitter pictures might take a few days to show up, but I’ll do my best to consolidate everything.

  •   •   •   •   •
July 2, 2014 by Jeff

Retrochallenge 2014: More Rainbow Goodness

This summer I’ve once again decided to waste some time participate in another Retrochallenge!  I do love entering these contests because it gives me an excuse to spend some quality time with my favorite machines.  Unsurprisingly, I’ve decided once again to focus on my Rainbow 100 (or 190 depending on the day of the week).

My project will focus on executing arbitrary Z80 code on the Rainbow from within MS-DOS.  For those unfamiliar with these strange beasts, the Digital Equipment Corporation Rainbow 100 personal computer attempted to bridge the gap between 8- and 16-bit worlds by providing what is effectively two closely-knit machines in one box.  The Rainbow contains two separate data buses, one controlled by an 8-bit Zilog Z80, and another controlled by a quasi-16-bit Intel (or AMD…) 8088.  The two buses communicated using 62KB of shared RAM (that’s not a typo) and shared interrupt calls.  Each data bus contained a set of peripherals.  The Z80′s bus contained:

  • Floppy controller

And the 8088′s bus contained:

  • Video controller
  • Serial controllers (RS232, serial printer, and serial keyboard ports)
  • Graphics controller (if installed)
  • Hard disk controller (if installed)
  • Extended Communications Option (if installed

It’s clear that the Z80 wasn’t given all that much responsibility in the system.  However, the Rainbow had reasonably good floppy disk access speed thanks to the Z80.

The Rainbow also featured a version of CP/M called CP/M-86/80 that had the fascinating ability to detect if the executable was a Z80 or 8088 program and execute it on the proper CPU.  This feature allowed the Rainbow to run either legacy CP/M-80 8-bit code or newer CP/M-86 16-bit code.

One interesting detail about the design is that, outside of floppy access, the CPUs’ control over shared memory was relatively fine-grained.  There were systems built in to make sure that only the 8088 or Z80 was accessing the shared RAM at any given time, but each could go about running programs “simultaneously” as long as this conflict didn’t occur.  The manuals, though, do refer to the CPUs as “master” and “slave,” explaining that the Z80 and 8088 didn’t normally (or possibly ever) go about their business simultaneously.  It would appear that one would normally wait while the other would do work.

Anyways, the Rainbow’s CP/M BIOS provides a pretty easy method for communicating with the Z80 via 8088 interrupt 39.  From that interrupt, one can actually tell the Z80 to begin executing code at a specific memory address.  Doing this from MS-DOS, however, is a bit less documented.

Of course MS-DOS does speak with the Z80 because it requires floppy disk access.  There is some communication going on between the two.  The real question is whether arbitrary code can be executed, not just floppy disk requests.

Why would anyone want to execute Z80 code from MS-DOS?  Firstly, I’m not a huge fan of CP/M simply because it doesn’t support subdirectories.  When you’re working on a hard disk, CP/M gets old fast.

Secondly, most software I enjoy on the Rainbow runs under MS-DOS anyway.  I am a nut for my favorite editor, SEDT, which might be the only editor I ever bothered learning all the hotkeys for.  I still prefer Select as a word processor over most any others (although Select is available under CP/M as well, I believe).  BinkleyTerm is possibly the best terminal emulator ever created even if it was primarily designed to be a BBS front-end mailer.

Finally, I’d really love to see code executed on the Z80 and 8088 in a truly simultaneous fashion.  Be able to execute code on both CPUs at the same time would have wild consequences, including drastically improving performance in some situations.  It would also be an odd multiprocessing use, at least in todays terms, just because the CPUs are different architectures entirely.

Will it be successful?  We’ll have to see…

  •   •   •   •   •
January 31, 2014 by Jeff

Quietly Closing a Retrochallenge

This month has been quite trying, not in the Retrochallenge sense, but with both work and personal issues.  Nevertheless, I did meet my Retrochallenge goal of actually writing some delightful GW-BASIC source code.  After a long departure into writing a completely unusable text-mode game, I was able to build a workable game using GW-BASIC and the Rainbow 100′s Graphics Option.

My little game is rather lame.  It is simply called Bad Robots.  The point of the game is to shoot robots that chase you.  There is nothing more to it.  I’m pretty jazzed that I was able to get a high score table working alright.  Here’s some screenshots:

I’m quite proud of two minor aspects of the game.  First, the three sprites need to be drawn and copied into BASIC arrays right off the bat.  This is done on the title screen.  The game first displays the text you see in the first screenshot.  However, after the text is displayed, it proceeds to draw a small happy face (the player in this game) in the upper right corner, then abruptly delete it.  Similar subtle drawing operations are then done for the robot and the bullet.  After the three sprites are captured, the “Press any key…”  operation is actually handled.

Second, I like that the sort routine for the high scores list actually works.  It took some thinking on my part to figure out how best to insert a new high score in the proper position, but I figured it out eventually.  It isn’t hard, it’s just a bit more complicated when dealing with FOR  loops, GOTOs, and arrays rather than stacks.  I’m very pleased that it is handled in-place (no secondary array or anything) and it’s written out when appropriate.

This silly  little game is written in GW-BASIC, so it should work  on a PC as well.   The only things that would need to change are some assumptions about the screen resolution (the Rainbow has slightly higher resolution than a CGA card).  Additionally, GW-BASIC is “portable,” so this program should run in QBASIC as well.  If you do have QBASIC, everything should  work fine if you simply change the screen mode to something very hi-res  (it’ll look a little wierd, that’s all).

The game is kinda fun to play.  The enemy robots get progressively faster as you kill more of them.  There is little to no safety checking code for creating enemy robots, so you could very well have  one appear directly on top of you, causing you to lose instantly.  It’s a minor “bug.”  The bullets are infuriatingly slow, but that’s how I wanted them to behave.

All in all, I’d call this Retrochallenge  a success!  A game was actually  finished in GW-BASIC, and I wrote a cool version control tool along the way (which I used the whole time, by the way).  There is currently a bug in Prism, though, that causes the diff  operation to output garbage on the Rainbow.  It works on DOSBox, so I probably did something bad with a memory pointer somewhere.

The products of this challenge are here:

Now  that it’s over, I do wish I could have done more for this Retrochallenge.  However, just because January is over doesn’t mean I can’t continue to hack on the ‘bow!

  •   •   •   •   •
January 25, 2014 by Jeff

Graphics Are Faster!?!

I’ve been truly ignoring my Retrochallenge responsibilities this month, so I sat down to spend some time with my Rainbow 100 today.  Before calling it quits completely (I don’t feel like writing Berzerk in C…), I thought I’d try moving a character around the screen using GW-BASIC’s graphics commands.

I had originally dismissed this idea for two very good reasons.  First, because the Rainbow was historically known for rapid text routines (faster than the PC even), I was sure they’d be fast enough.  Second, the Rainbow’s graphics routines tend to be slow.

When I last reported on my text-only zombie/Berzerk game, I said that the GW-BASIC interpreter, even with some optimizations, was way too slow to handle it.  The Rainbow would have no problem with it, but the interpreter and all it’s collision checking and key capturing just couldn’t do it.

On a whim, I decided to implement basically the same code, along with some “lessons learned” like easing off on the GOSUB calls, using GW-BASIC’s GET and PUT commands.  This pair can be used to pull off a sprite-like experience using purely BASIC code.  These commands work wonders on the IBM PC architecture, where graphics memory is just mapped into the system memory address space.  However, the Rainbow has an entirely different architecture.  It’s graphics chip, an NEC 7220, sits off the system’s 8088 data bus (the Rainbow actually has two separate data buses, each corresponding to its 8088 and z80 CPUs, but let’s ignore that detail for now) with it’s own memory space.  Commands have to be used to copy data from the system memory to graphics memory in a somewhat kludgy way.  In addition, copying out of video memory is just as cumbersome.

The downside of this memory architecture is that it becomes difficult to store sprites off-screen in a manner that they can be copied to display memory with any sort of reasonable speed.  Furthermore, there are maximum sizes of bits that can be copied based on the time available between screen redraws performed by the 7220 graphics display controller.  It makes graphics programming on the Rainbow… unpleasant.

I originally dismissed any use of graphics routines in GW-BASIC on the Rainbow as possibly far too slow due to this architecture.  Furthermore, all that work would need to be done in the confines of the interpreter.

For my sample program, I switched the Rainbow to low-resolution mode (384×220) and printed the letter “X” to the screen.  Next, I dimensioned an array and retrieved my “X” graphically:

20 DIM XSPR(4+((7*16*20)/8)*20)
30 GET (0,0)-(20,20),XSPR

That glorious dimensioning formula was suggested by the GW-BASIC manual.  The 16 represents the “bits-per-pixel” (which is wrong above, actually – it should be 4…), the first 20 represents the width, and the second 20 represents the height.  Simple, right?  The second statement copies the visible picture into the dimensioned array.  The next step is to erase this initial drawing since we no longer need it.  The easiest way is to use the PUT command in the same way we’ll use it animating:

40 PUT (0,0),XSPR,XOR

The key element in the PUT command is the XOR action verb.  This instructs the graphics code to perform an exclusive-or while drawing the data in the array.  If the picture is already at that location, it is effectively erased.

I then wrote some simple code to allow my control of the “X” on the screen, although this time I stuck to GW-BASIC’s INKEY$ functionality rather than the ON KEY(n) GOSUB … constructs.  The INKEY$ function simply returns the last key pressed as a string or an empty string if nothing was pressed.  I had a sneaking suspicion that the complicated key capture routines I had used before may have been contributing to speed problems.  The only catch is that I now have to use WASD for direction control rather than the arrow keys.

When I debugged and ran the code, I was surprised by how quickly everything worked.  There didn’t seem to be any problem with speed.  The next test was to add one enemy and have it chase me around.  After throwing together the necessary code, including creating another “sprite, ” I was shocked to see that everything ran even faster than the equivalent text code!

I now suspect that the LOCATE statement in GW-BASIC is the main culprit.  There simply isn’t any reason for the graphics version to be faster.

Next, I want to get the graphics version up to the point where I had the unresponsive text version.  I should have some hacking time tomorrow to give it a shot.


  •   •   •   •   •
January 18, 2014 by Jeff

Speed and the Lack Thereof

It’s been a long time since I’ve posted a Retrochallenge update, and I do have a reasonable explanation for this lack of posts.  My silly little GW-BASIC program to move the copyright symbol around the Rainbow’s screen seemed like a good start to a game of some sort.  I next added the ability to shoot, basically drawing dashes and pipes when the player hit the space bar.

Adding the shooting reminded me of one of the Rainbow’s little oddities.  When you hold a key down on the Rainbow, it registers the press once.  Then, if the key is still down after 500ms or so, the Rainbow registers this and handles multiple keystrokes.  This generally makes sense, but it makes writing a game brutal.  There are ways around the behavior; however, it can be disabled (easily) in GW-BASIC.

Imagine you want to move left fast on the screen.  If you hold the key down, you’ll move left one space, then pause for half a second, and finally continue moving.  If someone is chasing you or shooting at you on the screen, the situation is not ideal.  Additionally, I did choose to use the ON KEY(x) GOSUB y construct in GW-BASIC.  This configuration launches GW-BASIC into subroutine any time the specified key is pressed.  My old-time game I wrote as a youngster suffered some serious issues from this construct, mostly because you have to go disabling the key handling before performing collision detection, screen updates, NPC updates, etc.  Otherwise, you can end up skipping right out of collision detection and walk through walls.  On my “tech demo” here, it meant that, if I held down an arrow, I could move all the way across the screen without the shot I had fired ever moving a single character position.

Barring those issues, I decided to proceed with adding an enemy to shoot at.  I added a small plus (+) sign that would chase you around the screen in a random fashion.  Some simple collision detection would detect if you a) shot the enemy or b) were killed by the enemy.  This addition actually worked great!

The whole “one enemy” on the screen thing made for an exceptionally boring game.  I thought that maybe a Berzerk clone would be fun and possible to play.  The next step was to add multiple enemies into the game.  I started with a reasonable 8 enemies even though I toyed with the idea of 100 or so to make it a zombie-style game.  However, even 8 enemies put an unbelievable strain on the system.  Many of the keystrokes were simply lost as the enemies were slowly and visibly updated on the screen during the unresponsive update period.  It was completely unusable.

I did perform some optimizations to get around unnecessary collision and border checks, which produced a maybe 30% improvement in performance.  However, the Rainbow’s implementation of GW-BASIC is just too damn slow to run a Berzerk clone.

I’m now faced with a quandary.  I can proceed with some further GW-BASIC programming, or I could try to see if a Berzerk-style game would work better written in C.  I’m not sure yet, but I’ll consider my options.


  •   •   •   •   •
January 12, 2014 by Jeff

Trying to Remember GW-BASIC

I’ve had a few delays in working on my Retrochallenge project thanks to some software releases for work and playing with my new laptop I purchased Friday.  Today, though, I did have some time to spend with my Rainbow 100 and GW-BASIC.

Last week I wanted to play with graphics just a bit on the Rainbow in BASIC, but I’ve since forgotten quite a bit of syntax.  I decided to do some warm-up exercises.  First, I wrote a simple program which performs the simple task of outputting text in different colors.  Not very interesting, right?  The Rainbow’s architecture is a bit odd in this respect, though.  On a PC, I believe, you can output text in multiple colors as long as a Color Graphics Adapter is installed.  Things are different on a Rainbow.  While my Rainbow does have the Color/Graphics Option installed, you can’t quite do the same thing.

The Rainbow’s text output is always generated by chips on the motherboard, and it is always monochrome.  If you want to output red text, tough, it isn’t possible.  When in text mode, all the text signals are being sent out over the monitor port’s monochrome line, even if you have a color monitor attached (that’s a whole different, wacky story, which we’ll ignore for now).

To get colored text, you have to enter a graphics mode and draw text.  This procedure in C/Fortran/Pascal/whatever is normally a nightmare; there are no “fonts” built into the graphics hardware.  In GW-BASIC, though, the software engineers at DEC were bright enough to notice that nobody was going to use a Rainbow if GW-BASIC couldn’t  enter graphics modes and continue to work exactly like a PC would work.  Text output works seamlessly under GW-BASIC in either low- or hi-resolution modes.

The side effect of the above is that the Rainbow’s full graphics potential isn’t available in GW-BASIC.  The graphics option supports, in low resolution mode, 16 colors from a palette of 4096 (unless you have a Rainbow 100A, but let’s continue…).  However, in GW-BASIC, the DEC software engineers have pre-selected a reasonable 16-color rainbow-themed palette for everyone to work with rather than allowing developers to define palettes themselves.  So be it…

After some struggling with syntax, I was able to create a simple program:

Very exciting, right?

With this epic program created, I decided to give Prism a chance to store it.  And did it all work on the Rainbow?

You might notice that I’m working from A:.  As usual, my 20MB hard drive is completely full, and that free 400KB on a blank floppy sure looks appealing rather than once again cleaning my hard disk.

For my next exercise, I wrote a simple GW-BASIC program to try moving a text character around the screen.  I don’t think I have it in me to do any graphics during this Retrochallenge.  It just becomes so difficult to get running properly.  I’m thinking at this point I’ll do some simple text-based game.  More to come!



  •   •   •   •   •
January 7, 2014 by Jeff

Prism Improvements and Fixes

Since I don’t have much time tonight, I decided to pop back into the Prism source code to add revision options.  I wanted to be able to diff a working copy against any revision in the repository.  The addition was actually rather simple, and it’s now integrated into the code.  Furthermore, I needed to be able to revert to a specific revision.  The -r switch does that as well when using the revert command.  Awesome!

In the process of checking if these two changes worked, however, I noticed something odd.  In my repository’s database file, I noticed one hash had an extra, extended ANSI character sitting at the end of it.  This mystery character is a sure sign of improper string handling somewhere in the code!  Turns out that, during commit, I don’t zero out the memory for the new hash prior to copying the bytes into it.  The final effect is an unterminated string.  Oops! I went back through the code this evening and sorted out the last of the leaky hashes.

Everything should be good and tight now.  A new executable is provided below:

All fixed!  And a bit better!

  •   •   •   •   •
January 6, 2014 by Jeff

Prism: Local, Nearly Awesome Source Control

After some nasty work, I finally have a workable version control program running on MS-DOS.  Prism now supports my basic requirements: users can add files to be committed, commit code with a message, clear the queue of files to be committed, revert to the previous revision, and perform a diff.  The whole thing is packed into a single, monolithic executable that should work delightfully well on most MS-DOS systems, including Rainbow 100s.

The last bits that needed to be added were reverting changes and performing diffs.  The first bit, allowing to revert local changes, was relatively simple.  The file is just retrieved from storage and extracted on top of the current working copy.  Ideally the user should be able to specify which revision to pull, but it isn’t supported just yet.  It would be a simple change that I just need to get to.

The second bit, performing a diff against the repository, was far nastier.  In keeping with the old “I only want one executable” paradigm, however misguided, I needed to find a clean diff implementation to build into Prism.  After significant searching, I basically realized that:

  1. The only straightforward diff program is GNU’s.
  2. Even the MS-DOS port of GNU diff isn’t simple to compile.

The MS-DOS port of GNU diff was ported to Microsoft C, but lately I prefer working with Open Watcom for MS-DOS development.  Pulling in the diff source and building resulted in plenty of failures.  Additionally, GNU diff is made up of a number of C files that I wasn’t really interested in flipping through in order to fix the port.

I had basically given up when I came across a link to a PDF that provided a diff algorithm from the 1970s.  I opened it and was baffled by much of the theory (in that I couldn’t see immediately how to apply it).  Just before I gave up, though, I saw that it contained the actual source code in C for a working diff program!  The fantastic PDF, a paper by Miller and Myers, can be seen at

After some modifications, I had a diff function built into Prism.  It is not a particularly great diff subprogram, though.  It doesn’t output in the same format as GNU, and it doesn’t include lines surrounding changes.  It does, however, work, which is the most important feature.

So now Prism can diff the working copy against its own repository.  At this point, it should be good enough to use for Retrochallenge.  If you’d like to try it out, have a look:

There’ll probably be more changes this month as I find more points of failure.

  •   •   •   •   •
January 3, 2014 by Jeff

Half of a Version Control Solution

This morning of the third day of the Retrochallenge I committed the third commit of a new program called Prism.  This ridiculous side project is designed to provide basic versioning for source control on MS-DOS, all to support writing what will most likely be a single-file BASIC program.

The goal of Prism is to provide a git-like experience on MS-DOS.  I had a few requirements for the versioning system:

  1. It can’t use timestamps.  Most DEC Rainbow’s do not contain a battery-backed clock chip.  Checking when a file was modified on a Rainbow will inevitably return some date in 1984.
  2. It should be a monolithic executable.  I like having only one command, like “git” or “svn.”
  3. It has to run on an 8088 efficiently-ish.

The above requirements are a bit odd.  Notice that they do not contain branching or any mention of support for subdirectories.  Both of these things will not be supported for now.

To get around the whole “time stamp” issue, I decided to use an MD5 hash of every file to determine if it changed.  It seemed a very git-ish thing to do.

How does Prism work?

To get started with Prism, the user just needs to navigate to their target directory and run:

    prism init

The executable then generates a directory PV in the current directory that contains two files, db.txt and messages.txt.  The first file, db.txt, contains the meat of the versioning system.  The first line contains the revision number, zero immediately following initialization.  All subsequent lines represent a single tracked file, one line each, containing:

  1. A file id number
  2. The last revision committed
  3. An md5 hash of the file from the last revision
  4. The file’s name

So where do the file contents live?  That’s the fun part.

Similar to git, files to be committed must be staged, or, in Prism-speak, queued.  The command

    prism add file.c

queues the file “file.c” for committing.  Files that are queued are added to another file in the PV directory: queue.txt.  You can add the file multiple times; Prism doesn’t particularly care.  Once files are queued, the commit can be made:

    prism commit

When the commit is initiated, the queue is opened and inspected.  A hash is computed for each file to be committed, and, if the file is already tracked in db.txt, it is checked to see if the hash had indeed changed.  If so, or if the file has not yet been tracked, the commit proceeds.

First, Prism adds or updates a line in db.txt. Next, the new file is GZip’d to a file with the format <file_id>.<revision> within the PV directory.  Notice that the filename is not used because of MS-DOS naming restrictions.  We can eliminate the whole issue of having 8+3 filenames in the PV directory by just using the file id numbers.  It does restrict us to 0xFFF revisions under MS-DOS, but that should be enough for most applications for now.  Finally, the commit is confirmed to be complete, and the file is marked as tracked.

When a file changes, Prism will always store a complete, compressed version of the file in its PV directory.  Prism knows nothing of deltas or diffs, so it is reasonably inefficient.  However, it is also extremely simple.  That’s a big plus when it’s only a side project for Retrochallenge.

At this point, Prism only accepts commits.  You can’t yet revert to a previous version because, well, I haven’t gotten to it yet.

Why the name Prism?

A prism refracts light into it’s component wavelengths (effectively, whatever…).  Similarly, Prism stores all the component changes of your programming work.  It’s a loose metaphor.  More importantly, though, it does relate to rainbows which is the namesake of my computing platform of choice.

When will it be ready?

Basically, as soon as Prism supports reverting and, possibly, deleting files, it will be ready for use.  It still lacks a diff utility, but that shouldn’t be too hard to add.  If I’ve missed anything that modern version control should have, please tweet!

I’ll also post some executables here shortly for others to try out.  It actually will work on other platforms (Windows, Linux, etc.), so everyone can give it a go.  Right now it won’t, though; it assumes MS-DOS directory separators…

  •   •   •   •   •