circuitcellar.com
Magazine Support   Digital Library   Products & Services   Suppliers Directory 
 
 





 

Issue 147 October 2002
Watch Me Pull A Rabbit Out of My Hat


by Tom Cantrell

Start Rabbit 3000No-Risk CISCPeck-O-PeriphsTime TravelerOne-Stop ShoppingKeep MotoringSources and PDF

NO-RISK CISC

The Rabbit 3000 is by no means object-code compatible with the Z80/180, because a number of opcodes were deleted or moved around. I don’t really consider this a problem and indeed argue that the ostensible virtue of object-code compatibility is overblown in the embedded world.

For embedded applications, you almost always have to change your software when you use a new chip. As a practical matter, with software defining so many of an embedded product’s features, the scenario is usually, new chip = new product = new features = new software.

And even if you really want the new chip to run old software, you’re going to have to tweak the files at least a little bit. For instance, the Z180 is considered object-code compatible with the Z80 because all of the opcodes are the same. But still, to upgrade from a Z80 you would have to add some ’180-specific initialization code and be ready to hack around subtle changes in timing.

What matters isn’t compatibility, but rather familiarity. Z80/180 users will feel right at home with a Rabbit 3000, and it’s easy to discern the relatively few significant changes.

One of the novel features added to the Z80 was an extra register bank, which is a concept that remains popular to this day. The premise behind the scheme was that it would allow faster interrupt response by virtue of simply switching between register banks rather than pushing and popping all of the registers on and off the stack.

This makes a lot of sense in principle, but how about in practice? As someone who’s dabbled a fair bit with Z80s and Z180s over the years, I personally can’t recall ever using the alternate register set in this manner, or in fact at all.

Similar experience presumably inspired the Rabbit designers to make better use of these valuable, underutilized registers. Instead of being restricted to just exchanges, the alternate registers can be accessed directly by using an alternate destination (ALTD) prefix (e.g., via loads and stores and pushes and pops).

Another use of the prefix trick is with I/O, which is handled in a different manner than before. On the earlier Z80/180 models, I/O devices were accessed with unique opcodes (IN, OUT, and variations). I’m not sure that this was ever a good idea to begin with, but it’s certainly archaic at this point. Instead, for the Rabbit 3000, an I/O prefix (IOI for internal and IOE for external I/O) can be used with any conventional memory access instruction to cause the memory address to be interpreted as a 16-bit I/O address.

Going way back, the 8080 did have an advantage over other 8-bit chips at the time; it had the ability to perform some 16-bit operations (e.g., load, store, add, etc.), albeit a limited set. Rabbit has boosted the 16-bit capability significantly to include, for example, shifts and other logical operations such as AND and OR.

There’s also the interesting new BOOL instruction that works with the 16-bit HL register pair, the de facto 16-bit accumulator. It’s really simple: BOOL HL sets HL to one if the contents of HL are nonzero and leaves it zeroed otherwise. This proves useful to the C compiler for handling conditional evaluation; it also provides the basis for short instruction sequences that perform 16-bit signed and unsigned compares.

The traditional vector table interrupt system is enhanced with a four-level priority scheme. The worst-case interrupt latency for the highest priority is just the length of the longest instruction (or longest sequence of uninterruptible instructions), which is approximately 20 clocks.

The MMU is tweaked to manage the 1-MB address space differently than before. The basic notion that a 64-KB portion of the physical memory is always present remains the same. However, the details have been changed to better suit the memory management strategy employed by the C compiler.