PrintStar's Blog
Ramblings of a Fortran Nut
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 31, 2011 by Jeff

Rainbow JZip Version 2.1

As Retrochallenge Winter Warm Up 2011 comes to a close, the time has come for me to make available my work for the month. I have successfully ported JZip Version 2.1, the standards-compliant Z-code interpreter, to Digital Equipment Corporation’s Rainbow 100 personal computer. The Rainbow, while it does run MS-DOS, has a completely different hardware architecture, meaning that the base JZip for DOS distribution could only be run under an IBM PC emulator.

This JZip port allows a plethora of text adventures, both commercial from Infocom and homemade using the Inform compiler, to run natively on the Rainbow. The Rainbow’s exotic 24-line video architecture, similar to text terminals developed by DEC, is now supported directly by JZip. Additionally, the Rainbow features rather fast video access, meaning that JZip executes a bit faster than on a comparable PC-XT.

This port involved updating JZip to support the Borland Turbo C compiler. Once a simplistic version could be compiled, the next step involved re-implementing screen access and keyboard input routines, including cursor positioning, scrolling, and timed keypresses, for the Rainbow’s unique video architecture. While a PC has video RAM simply mapped to a given address with all character positions located sequentially in RAM, the Rainbow uses a more sophisticated linked list in order to facilitate fast screen writes and scrolling. Because none of the C compilers of the time supported the Rainbow’s video architecture directly, new screen routines had to be authored to provide screen support to the Z-machine. The Rainbow JZip port supports all character attributes, such as blink, bold, underline, and reverse text, although no color support exists as Rainbows do not support color text (ironically).

The ported executable and source code are available below:

Hopefully some of the Rainbow code is useful to the three or four remaining Rainbow 100 hobbyists left in the world…

Congratulations to all the other Retrochallenge contestants as well!

  •   •   •   •   •
January 30, 2011 by Jeff

Following the Documentation

The last few days I’ve been attempting to transition my JZip port back to the Rainbow’s proper fast video access routines. As you might recall, I originally attempted to use direct video memory access for all screen output. The implementation did generally work, but I eventually failed when considering the Set Up screen use case, which modifies video memory away from what I assume it is.

The Rainbow’s fast video routines are all accessible via firmware interrupt 0×18, and specifically one function, DI=0×14, can be used to write text to the screen. Basically, this call is still modifying video memory, but it allows the firmware to handle all bookkeeping related to the linked lists the Rainbow uses to store each screen row.

I did run into significant problems, however. I have used the fast video routines before, but I have always worked in the simple land of the small memory model. In the small memory model, all variables exist in a single data segment. To call fast video output, the programmer must specify the address of the text to display by storing the offset in the SI register and the segment of the text in the BP register. Things are more complicated in the large memory model. The segment of the text is not necessarily simple to find, and all pointers (in the large memory model) are toting around a segment and offset. The joys of x86 programming!

Most C compilers offer macros for dealing with far pointers. To perform the fast video operation, I had been defining the data segment as FP_SEG(text), which should return the segment of the pointer “text.” The FP_OFF() function provides the same convenience for retrieving the offset. Neither of these operations resulted in the proper text display.

I spent a large portion of yesterday and today attempting to debug the issue. In the end, I had to settle for defining my text as a near pointer. The use of a near pointer, which does not include a data segment in the pointer itself, should reside in the “current” data segment, which is easily obtained via reading the data segment register. This final fix brought my Rainbow’s JZip implementation back to functioning form.

When the interpreter starts, I’ve written a custom loading screen which displays using the Rainbow’s double-height-double-width text, which I always get a kick out of using:

As yet another functionality test, I decided to try out Aliennerd’s text adventure on my JZip implementation. Unsurprisingly, it ran flawlessly being a true Version 3 Z-code game:

Other than some minor documentation, I think my programming is done for this Retrochallenge. JZip has been exhausting to work with, so I’m relieved.

  •   •   •   •   •
January 26, 2011 by Jeff

A Newly Found Bug

Today I decided to test my JZip implementation on a Rainbow 100A personal computer. The “A” model Rainbows have a few minor differences, only a handful of which a user would notice. Most notable is the 100A’s inability to boot directly from a hard drive, or the Winchester drive as it is referred to in the Rainbow world. A few other minor differences, like only 1024 colors available with the graphics options and a maximum memory of 768KB, are not really applicable here.

I pulled out a 100A, which ended up having some serious trouble booting from floppy. The error was somewhat cryptic and just said “CONSULT OWNERS MANUAL – boot error” or something along those lines. The 100B model would surely have issued an error code as well, so I was surprised not to see one. My usual solution is to swap out the RX50 drive with another until it works. However, two different drives resulted in a more severe error: “step error.” Because it had failed the same way on both drives, I was pretty sure the issue was the floppy controller.

Thankfully, I am a Rainbow hoarder and had spare floppy controllers. Swapping the controller and reinstalling the original RX50 drive resulted in what almost appeared to be failure until, snap, the computer booted into MS-DOS 3.10b. My 100A was working again.

Firing up JZip with Zork I was also encouraging. Everything displayed just fine. One feature that will not work is the keyboard bell as I implemented it via an interrupt call unavailable on 100A models. However, I was disappointed with the key click volume when typing. Rainbow, and all Digital, keyboards use a little speaker to generate the key click noise from depressing keys. An interesting side effect is that most Digital computers and terminals allow for changing the volume of the clicks. I like it somewhat loud, especially over the roaring AC fan of the 100A (B model Rainbows use quieter fans).

One amazing feature of the Rainbow is that you can enter the “BIOS” at any time while the computer is on. Pressing the Set Up key (F3 if you don’t have an “LK” keyboard) brings the user directly into system settings screens. I navigated to the volume selection and increased the click volume. Pressing Set Up again returned me to my adventure-in-progress.

My key clicks at this point were far more satisfying, so I proceeded with opening the mailbox in front of the white house. After typing my command, things rapidly became weird. The line after scrolling was performed appeared to be filled with some text that may have been from the Set Up interface. After that line, however, there was simply no text displayed ever again. The game was clearly working because typing in more commands caused scrolling to occur, pushing text off the top of the screen, and typing “quit[ENTER],” followed by “y[ENTER],” and finally pressing space bar successfully exited the game.

I had stumbled upon a use case I had not accounted for thus far. When I start the JZip interpreter, I reset the screen, placing all the screen rows at specific addresses in memory. Technically it is a linked list, but, since I was writing directly to memory, I never really needed to walk the list as the memory locations never changed. However, when the user enters Set Up, the screen obviously changes. When returning to the game, the Rainbow does not rebuild the identical linked list. Instead, it just places text back at the proper lines.

I think this nasty bug is the last reason I need to switch back from direct video RAM access to the Rainbow’s fast video interrupt methods. Walking the linked list in video RAM will be too computationally intensive, and the firmware surely does a much faster job than I ever could. Since I’ve modularized everything reasonably well, it should be a relatively quick fix, but we’ll have to see.

Another concern I have which isn’t related to my JZip port is the state of my poor Rainbows. Today I tried three machines from storage, and only one successfully booted after prodding. As a side task, I think I shall go back through all my stored Rainbows (I have seven in storage here in the house) and see if I can’t get every one to boot. I hate to see them not functioning.

  •   •   •   •   •
January 17, 2011 by Jeff

The Mystery of the Rainbow’s Cursor

My JZip port to the Rainbow 100 had been progressing reasonably well since I successfully implemented direct video RAM access. The screen “looks” right, attributes (reverse video, etc.) is working, and input is accepted. I’ve even successfully tested JZip with some version 5 Inform games.

The problem that I’ve been struggling with seems relatively minor: positioning the text input cursor. On the Rainbow, like most text-based computers, a blinking cursor is displayed where either text input is expected or the last bit of output text was produced. Generally its positioning is automatic, especially when using obvious output routines like printf(). However, I’ve switched to outputting text via direct video RAM writes, which skirts any firmware output routines that might actually handle the cursor positioning properly.

The big problem is that the Rainbow provides no firmware routines for positioning the cursor. The only method for cursor positioning endorsed by Digital Equipment Corporation was via ANSI escape sequences. I initially tried issuing printf() statements with the proper escape code to no avail.

The whole issue is that the Rainbow is obviously storing cursor positioning somewhere in RAM, but the documentation had absolutely no hints. After some searching of comp.sys.dec.micro, I stumbled upon some small mentions of a Pascal routine that might have contained some details about cursor positioning. Alan Vymetalik had long ago published some fast video code for the Rainbow, which apparently eventually morphed into a Turbo Pascal 4/5 console IO unit compatible with the stock IBM PC unit shipped with Borland’s compilers. I checked my archives, finding nothing. However, the fine people at the Update Computer Club had the demonstration software in their ancient mirror of the La Trobe University archives, long since disappeared from the Internet.

While I was grabbing the demo code (which I already have somewhere since I mirrored the Update archives long ago), I also pulled a few other interesting archives, namely a Turbo Pascal library and something called rbiodif.zip. I was surprised to find that modern zip (the archiver, not the Z-machine) implementations couldn’t unzip most of the archives because the “reduce” compression method was not supported. Notably, the Rainbow demo code would not unzip at all. However, unzipping the rbiodif.zip archive did expand a single file called rbdemo3.pas, which appeared to be the file I needed. The uncompressed Pascal routine had two functions returning the cursor’s row and column positions respectively directly from video RAM.

This little tidbit was a huge find. After unzipping the full demonstration code on a real Rainbow using PKWare’s pkunzip, I actually found out that these cursor routines weren’t present. Some initial tries did not seem to move the cursor, but I finally arrived at a working cursor. I now disable the cursor via an interrupt call, write the new position to the proper memory locations, and re-enable the cursor via interrupt call to force the computer to notice a change in cursor position.

I’ve had some minor issues concerning cursor placement, especially after text output. These issues are basically related to my sloppy overriding of text output routines. A little fine-tuning should clear things up.

For future generations, the Rainbow cursor information is located at:

  • Column: 0xEE00:0x0F41
  • Row: 0xEE00:0x0F42

I now need to focus on better implementing text output so that the cursor is always positioned properly, supporting timed input, and supporting backspace, Shift, capital letters, etc.

  •   •   •   •   •
January 13, 2011 by Jeff

The Slowest Debugging Ever

I made some progress porting my direct video RAM access routines to the Rainbow, but it was a painful journey. I started the port using the Microsoft C input/output routines because they seemed the simplest when compared to the Borland C routines. Additionally, the console routines for Microsoft C were somewhat limited, decreasing the number of ported routines I would need to write.

The problems began once the direct video RAM routines were in place. Upon first execution of the direct video version, I was greeted with what appears to be garbage on the screen. Specifically, JZip normally displays a version banner and a nice note stating “The story is loading…” at startup. My screen showed a pair of characters. Once the story apparently loaded, scrolling began and I was greeted with maybe a single character where all of the room description should be. Oddly enough, the program was running properly. Typing “quit” followed by “y” did in fact exit the interpreter.

To simplify matters, I blocked execution of the story and forced JZip to exit after displaying the banner. The banner, like most of the story, utilized Microsoft C’s _outtext() routine to display text directly to the screen. I have created a simple _outtext() definition that reroutes the call to a Rainbow-specific function I have authored along with a stored screen position. I also created a _settextposition() function that would effectively update the internally stored screen coordinates, similar to what Microsoft’s function would have done.

The problem turned out to be with my Rainbow-specific function, namely rputstr(char *string, int row, int col). The issue turned out to be that my Rainbow function, while walking the string, never actually advanced the column position. Instead, every single character in the string was being output at the specified starting position. After a quick fix, my JZip banner was appearing properly on the screen.

Excitedly, I re-enabled the story code, allowing the program to advance beyond the initial banner. After a lengthy recompile, I saw the banner followed by scrolling emptiness.

This issue didn’t make sense to me since the banner was displaying properly. I tried an initial debugging procedure that would display the last _outtext() requested position. This proved misleading as I thought for a solid day that my JZip implementation thought there were 25 lines on a Rainbow’s screen (there are 24, of course). Next, I thought that possibly my scrolling routines were broken, but after disabling screen clearing code, I saw that the banner scrolled right off the screen as one would expect. I was simply baffled.

As a last resort, I added code to my _outtext() to open a log file, append the file with the current screen position followed by the requested text. I should point out that my current Mitsubishi 40MB hard disk is painfully slow to the point where I’m pretty sure something is not working properly. I started up Zork I and walked away for maybe an hour and a half as the hard disk began grinding away, opening a log file, writing a line of text, closing the file and repeating on the next _outtext() call.

When I came back to see my Rainbow’s log file, I was shocked to hear the hard disk grinding away. Being reasonably late at night (this was yesterday), I switched power off. Don’t you miss MS-DOS and hardware power switches?

Today I opened the log file, which should have been reasonable small since it contained only the first room of Zork I at the most. Suprisingly, there were many, many lines in the file, each specifying the coordinates for the bottom of the screen in column one and a single character. Apparently, the JZip input/output interface is outputting a single character at a time via _outtext(). However, all the requests were in the first column. I pulled out my copy of the Microsoft C Runtime Library reference manual to look at exactly how _outtext() was expected to behave. The description was rather sparse, but one sentence caught my eye (paraphrased…):

_outtext does not allow formatting like printf.

This sentence may seem pretty innocuous, but the comparison to printf() struck me as interesting. Specifically, my _outtext() implementation never advanced the column position like a call to printf() might. It occured to me that JZip’s Microsoft C input/output routines were expecting _outtext() to advance the text position after each call.

I modified my code to advance the output position (not the cursor, that’s another story…) appropriately after each _outtext() call and recompiled. I was pleasantly surprised to see not only game output text to scroll by, but a status line appear at the top of the screen!

There are still a number of issues remaining. The status bar still needs some work. The keyboard handling is far less than ideal and does not support timed input. The game text seems to be requesting column zero, which seems odd as well, meaning that the first column isn’t appearing. Plenty more work to do, but my challenge is progressing.

  •   •   •   •   •
January 9, 2011 by Jeff

Direct Video RAM Success

In yet another about face, I decided today to take another crack at writing directly to the Rainbow’s video character RAM. In my last post, I had mentioned that I was going to use firmware interrupt 0×18, so called “fast video” operations, to place characters on the screen for JZip. I had already shown some success with doing so in an earlier post where I showed JZip output appearing properly on the screen. One aspect of that output, however, struck me as strange. Specifically, the screen initialization code specifies showing the JZip version and “Story is loading…” at initialization time in the center of the display. In my example, however, the both appear at the bottom of the screen as if “printf‘d” out.

Going back to look at the code, I was somewhat disappointed to learn that, in a fit of debugging, I had indeed defined _outtext (an old-school Microsoft C direct screen write call) as simply printf. I switched the definition back to use my custom Rainbow output routines and recompiled. When Zork was started, some garbage appeared on the screen.

This initial garbage was my fault entirely. I noticed that one compiler warning stated that a pointer being assigned was too large. It turns out that pointers in the large memory model contain both the segment and offset (yay x86!) rather than just the offset. I had to change some of the Rainbow interrupt call code to specify the data segment as the current string pointer’s data segment. Changing this to work properly caused an entirely different set of garbage characters to appear.

The Rainbow interrupt call itself is a little odd. Here’s an excerpt of how it should work:

    Send Data To Screen -

           ENTRY   DI = 14

                   AX = TRANSFER TYPE
                      0 = CHARACTERS AND ATTRIBUTES
                      1 = ATTRIBUTES ONLY
                      2 = CHARACTERS ONLY
                      3 - FFFF = UNDEFINED

                   BX = START LOCATION IN DISPLAY
                      BL = LINE NUMBER (1-24)
                      BH = COLUMN NUMBER (1-132)
                     NOTE: MAX COLUMN NUMBER IS A FUNCTION OF SCREEN
                           WIDTH (80,132) AND LINE WIDTH (SINGLE,DOUBLE)

                   CX = NUMBER OF CHARACTERS/ATTRIB TO TRANSFER, IN BYTES
                     NOTE: USER IS RESPONSIBLE FOR LIMITING SIZE OF
                           TRANSFER SO END-OF-LINE IS NOT EXCEEDED.

                   DX = OFFEST TO START OF ATTRIBUTES RELATIVE TO USER'S DS:

                   SI = OFFSET TO START OF CHARACTERS RELATIVE TO USER'S DS:

                   BP = CHARACTER/ATTRIB SEGMENT COPY OF USER'S DS: USED FOR
                        OFFSETS PASSED IN DX AND SI.

                     NOTE: CHARACTERS AND ATTRIBUTES MUST BE RELATIVE TO
                           SAME VALUE OF DS:
                           THIS WILL NOT MODIFY LINE ATTRIBUTES, ONLY
                           CHARACTER ATTRIBUTES

The oddest part of this call is that the current segment should be stored in the BP register. The BP register, however, is normally used for handling the current position in the stack. I’ve only seen a handful of examples that modify the BP register. The Microsoft C compiler doesn’t even provide a C interface for modifying this register.

While I’ve never had a problem with this function call before, I’ve also never worked with it under a large memory model. Debugging the issue seemed like it would be nearly impossible because outputting all text output calls to disk revealed that the text strings were intact and correct, meaning the screen output routine was the problem.

I cracked open my Rainbow’s MS-DOS Technical Documentation binder to see if I was perhaps missing something. The documentation for the interrupt didn’t reveal anything new. Flipping through the manual, though, brought me back to the linked list format.

I glanced at the table and noticed that the start address for the first row of screen text was different than the text file I had been working with. Indeed, it stated that the first row began at EE00:0012 rather than EE00:0013. I decided on a whim to check if any other table entries were wrong. Lo and behold, there were quite a few errors with the text file’s row listing. In my simple test code, I updated my address table to see if direct memory access could actually work. After compiling and fixing some issues with parentheses, I ran a simple test program to output the first 24 letters of the alphabet in the center of the screen. I was pleasantly surprised with the output:

Having direct video access both simplifies and complicates future development. Using direct access should be significantly faster and make positioning considerably easier. However, scrolling now becomes somewhat problematic as I’ll need to perform memory copies manually. I think working with video RAM directly, though, should be far more rewarding.

  •   •   •   •   •
January 7, 2011 by Jeff

Smart Decision Brings Mild Success

My last post was a bit of a rant about memory layout on the Rainbow 100. I believe I was talking about using the Rainbow’s character video RAM directly, which is organized in a linked list. However, I have made somewhat of an about face on that decision. I should explain further.

Some technical documentation stated that, after a screen reset, the linked list containing the 24 screen lines would be configured a certain way. Specifically, each row should reside at known addresses after a reset, negating the need to actually walk the linked list. However, after some minimal testing, I found this did not seem to be the case. While I do believe the documentation, there are some assumptions I had made, namely:

  • The video linked list after layout is identical for Rainbow 100A and 100B models
  • The linked list will not change after reset

The first assumption is actually quite bold as there are differences between the Rainbow 100A and 100B models. DEC never claimed themselves that the linked list would take on any particular form after reset, so the default for 100A and 100B computer could change while not actually hurting compatibility. Furthermore, writing to video RAM and performing actions that could lead to scrolling will almost certainly cause the linked list to reconfigure itself during operation. Finally, having to walk the linked list adds a layer of complexity that simply isn’t necessary.

I made the decision to switch back to using interrupt-based video RAM operations. The Rainbow allows writing text to the screen via interrupt 0×14, which is supposedly referred to as “fast video operations” on the ‘bow if I’m not mistaken. By utilizing the interrupt-based solution, I leave walking the linked list and managing video RAM to the firmware rather than having to deal with the overhead in C. Additionally, this method is the way DEC endorsed for fast text operations in contrast to writing directly to RAM (possibly faster) or using VT52/ANSI escape sequences (certainly slower).

I have worked with these interrupt operations during my porting of robotfindskitten. Text operations are indeed fast, but my application of the operations were somewhat limited in that port. The Z-machine actually accesses the screen one character position at a time. This scenario make sense because Infocom was attempting to port to architectures that supported 40 columns, 80 columns, and variable-width windows using a single story file. Therefore, Infocom needed to do text wrapping on the fly, making the ability to handle varied screen widths part of the Z-machine. My concern was that character-by-character screen access via interrupt calls in C would end up being prohibitively slow. I have found that the interrupt calls are plenty fast.

After switching to interrupt-based IO, I had a compilable Rainbow IO module for JZip. After compiling using Turbo C under DOSBox on my Debian-based laptop, I transferred the executable to the Rainbow and attempted to run Zork I. While the executable did “execute,” I was greeted with garbage in the upper left corner. With this failure, I went into the Rainbow IO code and deleted any code that utilized ANSI escape sequences, notably the cursor positioning, screen clearing, and scroll region code. Because I was using interrupt-based IO for screen writes, I was concerned that using another method might be gumming up the works. After recompiling on the Rainbow and listening to a few minutes of grinding hard drive motors, I retried Zork. Again, the upper left corner was garbage, and no text appeared on the screen.

My final idea was to disable some of the timed input functions. Code was present in the IO routines to request input for a specific period only, and the code was implemented via BDOS calls. I had left it in hoping that the calls were portable across all MS-DOS machines. I changed the routines with BDOS calls to skip any waiting and return instantly. Surprisingly, this change seemed to fix the garbage problems.

After another recompile and test run, I was greeted with a single column of characters with “[MORE]” preceeding every letter. I was disheartened until I examined the single column of text; the letters spelled out “Zork is a registered trademark of Infocom, Inc.” The output was working, but the Z-machine was apparently under the impression that my screen was 1 character wide.

Going back to the code, I discovered that all the other output functions would assign values to screen_rows and screen_cols, two apparently global variables. Again, after firing up SEDT, I modified my initialization code to set the values properly and recompiled. This version actually output something sensible:

There are countless issues still pending, but the screen IO is at least minimally working. Specifically, I do not reset or clear the screen ever still, and no status line exists. Also, the first line of text is definitely cut off at startup.

Plenty of work remains to be done. I’ll need to implement a status line, which is somewhat complicated. Specifically, the Rainbow firmware doesn’t provide a firmware routine to control the scroll region. Therefore, I’ll probably need to handle scrolling manually. Also, I currently have disabled all text attributes, such as bold, underlines, reverse video, etc., which the Z-machine expects to work. Finally, the IO doesn’t seem to work too well with Blue Chairs, which concerns me.

  •   •   •   •   •
January 4, 2011 by Jeff

Screen IO on the ‘bow

I’ve decided to proceed with creating a true, native port of JZip to the Rainbow this Retrochallenge. The biggest step necessary is accessing the Rainbow 100′s direct screen IO. Unlike the PC, the Rainbow’s video character RAM is not laid out at a simple address in sequential order. I have written software before to access the Rainbow video routines via interrupts, most notably the Rainbow port of robotfindskitten. My previous work utilized the interrupt calls to place text at specific locations on the screen. However, I thought it might be far more interesting to access video RAM directly.

On the PC, video RAM begins at segment 0xb800 and is laid out in a straightforward manner. To place something on the first row, column 10, for example, the address is at offset 20 in segment 0xb800 (two bytes per character position, one for the character, and one for attributes). To place something in the first column of the second row, the offset is simply 160 (or 80*2) in segment 0xb800. Writing characters directly to the screen is easy!

The Rainbow, however, has a dramatically different memory layout. Video RAM begins at segment 0xEE00, but the layout is nothing like the PC. The Rainbow stores everything in a linked list of screen rows. In its nominal state, the first row resides at offset 0×13, with the 80 bytes at this address representing the 80 columns in row 1. The Rainbow can also do 132 columns, but we’ll ignore that face for now. At offset 0×63, 80 bytes later, a termination character of the value 0xFF resides. The bytes at offset 0×64 and 0×65 store the address of the next screen line. Navigating to that address will provide access to the 80 columns of the second row and subsequently the address of the third row. This layout is far different from the PC, which is why there are just about no full-screen PC utilities that will work on the Rainbow. Attributes follow a similar structure starting at segment 0xEF00.

Most documentation suggests that all screen access be performed via firmware interrupt calls. I’ve always performed screen IO on the Rainbow via interrupts, but what’s the fun in that? I also suspect that setting up an interrupt call via DOS C interrupt interface might be needlessly slow. I’ll be experimenting some with direct memory writes in the next few days.

I’ve written a simple driver program, but thus far I’m having some difficulties with the Rainbow. I’ve been messing around with what segments and offsets are necessary. Those readers out there who haven’t had the pleasure of working in the segmented world of x86 are really missing out. Imagine having to specify all sorts of “special” pointers just to access memory outside of 64 KB. Good times… I ran into similar headaches during the 2009 Retrochallenge when working on a portable GEM program for the segmented hell that is x86 and the sensible flat memory space of the Atari ST.

  •   •   •   •   •
January 2, 2011 by Jeff

That Was Easy!

For my first attempt at bringing a modern Z-machine to the Rainbow, I decided to have a look at the JZip Z-code interpreter. As I mentioned in my previous post, JZip actually works on the Rainbow under the Code Blue IBM PC emulator, but the MS-DOS binary doesn’t “just work” due to hardware differences. I also mentioned it was as slow as molasses under the emulator. However, the JZip source code is freely available, and multiple output modules are provided.

By output modules, I meant that the source code provides ports to a few different output systems. The distribution contains makefiles and interface code for MS-DOS (on a PC), curses terminals on Linux/UNIX/*BSD, dumb terminals, OS/2 command prompts, and Atari ST machines. For MS-DOS, makefiles for the Borland C compiler and Microsoft QuickC are provided, which I thought were rather odd choices. Since I have Turbo C on my Rainbow, I decided it was a good place to start.

I modified the makefile to utilize dumbio.c rather than the PC input/output code in an attempt to get things running on the Rainbow. I quickly found out that “Borland C” did not mean “Turbo C.” Turbo C (2.0)’s make utility is quite dumb, although not nearly as dumb as Microsoft C’s make utility. I wrote a new makefile to use the Turbo C compiler and decided to hope for the best. My first compilation attempts were met with errors as I hadn’t set the FILES=20 in config.sys on my system, causing some MS-DOS errors due to too many files being opened simultaneously by the compiler. Once beyond that small error, I made some tweaks to the makefile, made sure to update my Rainbow’s date as it was causing make issues, and set off fixing the handful of errors. The errors I encountered were simple, related to a “set_colours()” function and an undefined maximum filename length for MS-DOS. After waiting for about 30 minutes for 15 files to compile, I finally managed to get an executable.

I quickly downloaded Zork I to the system to try out JZip. To my surprise, everything worked! However, I wasn’t sure if Zork I was a true version 5 game, so I decided to try another. I grabbed Blue Chairs, a text adventure written by Chris Klimas that I was quite fond of a few years back. I knew Blue Chairs was a true version 5 game, so I loaded it up in my new Rainbow JZip, and everything again seemed to work.

While I say that I have an executable that works on the Rainbow, there are quite a few caveats. First and foremost, the dumb terminal input output mode prints the current status immediately above the input prompt, an exceptionally annoying place for it to be located. Normally, this information would be placed on a status bar of some type. It would, of course, be beneficial to implement a true status line on the Rainbow. Second, JZip is exceptionally slow on the Rainbow. It is slow enough to be approaching unusable. Whether this can be rectified using the JZip interpreter itself or switching to a lighter weight Z-machine, I still don’t know. Infocom’s Z-machine implementations were super fast on the Rainbow, so I’m sure something can be done.

So while I now have a native Z-machine on the Rainbow per se, it certainly is in far from ideal shape.

  •   •   •   •   •