A project log for OMNI 4 - a Kaypro 2x Logic Analyzer

A while back I acquired a rare logic-analyzer, whose lone system-diskette needed backing-up. Now this page is all things OMNI 4

Eric HertzEric Hertz 09/25/2017 at 11:2610 Comments

the serially transferred files are duds.

Apparently pip decided to translate tabs to spaces.... even in binaries, even in binary mode.

On that note... cpmtools seems to work with the disk image when using the kpiv format.

Only one hiccup (besides discovering the tab to space conversion)... a large text file ends with a bunch of 0x1a's... (ascii substitute?) Dunno why, but doubtful they belong there.


ziggurat29 wrote 09/25/2017 at 15:24 point

0x1a (ctrl-Z) was often used as an end-of-file marker; it's possible that those are intentional, especially on a text file.  I'm not 100% sure, but I don't believe CP/M filesystem otherwise knows the length of files to byte resolution -- I believe it is granular to the 'record', which is 128 bytes.
EDIT: I can now confirm from the disassembly of the TYPE command, that 0x1a is used to terminate sending of content to the screen, so it does seem to be normal end-of-file marker for text files.

With the alternative configuration for cpmtools you mention, the extracted files look much much much more sane now; so I guess the 2048k block size was the missing parameter!  The disassembly of the extracted so far also looks sane.  One thing that seems to stand out:

*  ports 0xe0-0xef seem to be the logic analyzer's IO range

*  this lends further credence to your hypothesis that the ports 0x80-0x87 that I found in the ROM code are actually for hard disk operations (maybe inherited codebase from the Kaypro 10), rather than for LA features as I had conjectured.  I don't think HD was an option for the KP2x, but it was a separate option board for the KP10, and that probably explains why the decoders are not on the mobo, and are in the high range.

Also, I did a little more (very cursory) analysis on the differences between the 'stock' Kaypro 2x ROM and the Omni4 ROM.  There were many differences, but the port range 0x80-0x87 was not among them, so that seems to be from the factory, furthering your hard-drive hypothesis.  I'm pretty sure that the HDD used was the then-popular WD-1010, which had 8 registers.  I have not yet analyzed the code to see if the access patterns for the 80-87 are consistent with those register's functions.

Lastly, looking at the two ROM's code, the differences seem to be more bugfixes than radical functionality.  (they were often like the presence or absence of a 'or a' instruction prior to a conditional jump like 'jp z, xxx'.  The 'or a' would cause the flags to be set prior to the conditional.  Without it, you would be hoping that the flags would already be set as needed.)  So I think that the Omni4 ROM is simply derived from a different revision of the stock KP2x firmware.  Guessing by the nature of the changes, I am suspecting earlier.  The other ROM seems to be bugfixes relative to the Omni4 ROM (just a working theory, might change mind on that).

  Are you sure? yes | no

Eric Hertz wrote 09/25/2017 at 20:31 point

great findings. Spose one option would be to burn a stock ROM and see if the logic analyzer still works... 

  Are you sure? yes | no

ziggurat29 wrote 09/25/2017 at 21:17 point

my bet is it will /possibly/ work OK.  The routines moved because of the code changes, but if the ROM routines are reached through a vector table, then it should be OK to swap ROMs.  On the other hand, the ROM and the BIOS are things the customer (Kaypro, relative to Digital Research, who wrote the OS) is expected to produce, and if they are tightly coupled (e.g. call addresses), then that will be a problem in many cases.

It's probably about time for me to post some disassembly listings.  It is by no means complete, but I imagine it is less fun to not be able to see the code I'm talking about.  Anyway, since I'm still working on it, I think I'll post it with a date stamp in the name, so I can continue to update the file, but make it obvious to folks if the currently posted one is newer than one that might have been downloaded before.  There's still many days left of work to do on the system stuff alone, not to mention all the apps on the disk.

You're probably already familiar with the CP/M memory layout from prior research, but here's the scoop for this particular machine:

0000-00ff   system stuff
0100-d7ff   'Transient Program Area'; where your programs get loaded
d800-dfff   'CCP'; handles the command line with the user
e000-edff   'BDOS'; the operating system in a platform neutral way
ee00-xxxx   'BIOS'; platform specific implementation
xxxx-ffff   system variables

(the xxxx boundary is still a little blurry to me)

And the boot rom is at 0000-1fff.  As we've seen, the ROM in this system can be up to 32k, and the whole lower 32k is switched out when the ROM is active.  The ROM on typical CP/M systems is just a bootloader which probably switched out forever once the OS is loaded, but we know that in this system it also contains a bunch of utility routines (probably to help keep the BIOS smaller, saving precious RAM), and is 8K, but could be up to 32K if Kaypro needed it.

Because the OS design of CP/M is so simple, I have made a combined disassembly of the whole 64k address space that includes the ROM and also the OS after it is loaded in -- it makes it easier to translate call addresses to function names and see the flow-of-control amongst the parts.  I have done work in all the areas, but the CCP I now pronounce 'complete', and I am working on the BDOS now, then back to the low-level implementation in BIOS and the ROM.  My thinking is that having this in-hand will then also make the reversing of the apps much more straightforward.

  Are you sure? yes | no

Eric Hertz wrote 09/26/2017 at 03:53 point

sounds impressive.. looking forward to it! You're gonna post a log entry with it?

  Are you sure? yes | no

ziggurat29 wrote 09/26/2017 at 04:48 point

I was planning on holding off on the log entry until after it is a little more complete, and then I'll write up a walkthrough.  For now, I just wanted you or anyone else curious to be able to use the listing without waiting for it to be fully analyzed and commented.

I had put one up earlier today in the files section, but I am just now fixing to put an updated one with the BDOS section more-or-less finished.  Then on to the BIOS, and finally finishing up back in the ROM.  It has been a journey!

Then the logic analyzer program itself, which was the original task before all this OS excursion, haha.

  Are you sure? yes | no

Eric Hertz wrote 09/26/2017 at 07:29 point

ah hah! I saw it in the files section... am trying to view it on my phone... stupid me. Cat in a terminal window 400pix wide just doesn't cut it... but a quick glance gives me the impression.... that... wow. You're good at this!

Wish I could tell yah there's a budget for your work!

  Are you sure? yes | no

ziggurat29 wrote 09/26/2017 at 15:44 point

It's a labour of love. And an addiction. But there are worse obsessions? I wish I /could/ get paid to do it for a living; but very occasionally I am effectively compensated for it when it helps in my regular work. But that's a rarity. Ultimately, it's just the challenge of puzzle-solving that impells me.

OK, speaking of things found, now I can better comment on the feasibility of swapping ROMs or not, and I can be specific.  Short story: I believe it is.  Here is my reasoning:

*  it appears that BIOS invokes ROM routines through a single 'service request' mechanism.  This involves setting up parameters in registers, one of which is a 'selector', and invoking a single, common, routine.  The common routine does some common prologue/epilogue, and then dispatches through a table of function pointers.

*  you can see the the common service routine at BOOTROM:0074, where D holds the service code.  And the table of function pointers is at BOOTROM:008A

*  the dispatch routine is actually reached indirectly via a thunk at BOOTROM:004B (which simply jumps to BOOTROM:0074).  There's a bunch of these thunks in that area, so it seems that the author intended the ROM routines to be reached through a set of well-known addresses, rather than directly.

*  Sometimes you can reach the same code through multiple means!  My current fave:  routine BOOTROM:022F, which I have named 'ldHL_BC_22F'.  Really, it just loads HL with BC -- that's it.  Two bytes of instructions.  But you can reach it via well-known addresses BOOTROM:000C, and BOOTROM:0021, and also via rom service dispatch codes 1f, and 27.  Haha, wow! that's many and circuitous routes to do very little!  It probably made much more sense in the original source, but we don't have that and so we may never know what was the original intent.  But we do know what is the effect, at least, so we can motor on.

*  Anyway, back to ROM swapping; the BIOS invokes the ROM routines through two dispatch routines at BIOS:EFD2 and BIOS:EFF0.  (The second seems to be used in the context of an Interrupt Service Routine.)  They each do the bulk of saving/restoring context before they jump to hyperspace by mapping in the ROM, and dispatching through the thunk at BOOTROM:004B that I mentioned above.  If those are the only ways BIOS invokes the ROM routines, then it should be safe to swap the ROMs.

I need to do a more detailed cross-reference analysis to prove that there are no other direct references, though, to be sure.  But I can do a quicky analysis right now by grepping some patters.  'CD....[01].' should match all 'CALL xx' into the ROM.  I can see that the only CALLs made are to the dispatch routine I mentioned, and to location 0005 which is actually made only when RAM is mapped in, anyway (it's how you make BDOS calls from application code), and to location 0100, which is your application program.  Similarly, matching on 'C3....[01].' should match all the 'JP xxx' instructions, and there is only one to location 0000 which done when RAM is mapped in, anyway, so who cares.  To be thorough, I need to also test the opcodes for the various conditional call/jump instructions as well, but this is pretty good evidence already.

*  Anyway, back to buried treasure, the ROM dispatch table I mentioned has 55 entries.  55.  That's a lot of services!  More interesting:  only a subset of them are used!  Hmm.  Now why would the authors create a bunch of services in a chunk of internal code.  Applications are not meant to call ROM directly, and it would be a little challenge since they would have to hyperspace themselves out of existence to map the ROM in to execute, and then no more instruction stream to make the actual call; whoops!  The code in the ROM is pretty clear to be intended for BIOS's implementation only, and you get to through BIOS calls.  Anyway, BIOS seems only to be invokes a small subset of the 55 services.  I need to catalog the definitive list for more analysis.  It's possible that those are for features not present on this unit -- like the hard disk, and it is also possible that the ROM was even licensed from by a third (4th?) party who provides it along with a reference design for a system that Kaypro then tweaks for their product offering.  That's highly speculative, but it definitely was practice at the time (as it is even now).

Sorry for my (characteristically) long posts!

  Are you sure? yes | no

Eric Hertz wrote 09/27/2017 at 00:23 point

It sounds like much of that BIOS jump table stuff is probably not specific to the Omni4... since other kaypro (2x) boot disks and software run on this system (presumably making use of said BIOS calls, etc.) Which... now makes you one of the leading experts on kaypro 2x system architecture in this era ;)

you're more than welcome to keep going as you have... commenting on this project/logs... but, man, your detective-work and detailed explantions are truly worthy of at the least a project page of its own, rather'n being burried in random places!

  Are you sure? yes | no

ziggurat29 wrote 09/27/2017 at 02:18 point

Haha, yes.  Andy Kay passed away a couple years back, so the living memory is certainly becoming thinner.  Anyway, I found many of the apparently unreferenced APIs were referenced directly, not through the table, within the ROM code itself.  There are still maybe 5 or so that I can't see used, but they may turn up later.  More buried treasure:  I found some self-modifying code (my favorite; well, second the old jumping-into-the-middle-of-an-instruction trick (which Bill Gates purely loved; I've disassembled some of his old BASIC from the 70's)); that might cover some of the apparently unused ones.

I will continue to work; every time I put it down, I think of another curiousity I want to explore, so I've got plenty of fun for a while.

At the moment, I'm in the interrupt system.  This system uses the Z80 Interrupt Mode 2, and a peculiar scheme with the Non-Maskable Interrupt.  I had never worked with an IM2 system, so that's fun.  The NMI scheme is amusing to me because the ISR simply does a RET -- that's it; there's no 'servicing', so that sounds boring and pointless.  Why?  Well, an interrupt breaks out of a HALT instruction.  So, you effectively turn HALT into 'Wait For Event'.  This is also true of regular interrupts, though, so how do you know which one you are waiting for?  Well, the NMI is non-maskable, so if you Disable Interrupts, then you know the one that broke you must be the NMI.  So it's also flimsy priority scheme.  Ha!  The NMI gives me the heeby-jeebies, though.  It's only valid when the ROM is mapped in -- it's vector is in the middle of user data otherwise.  Get an NMI when you're not ready for it, and crashy-crashy.

In retrospect, the scope of this activity has grown that it would probably have made sense to make a companion project ('Deconstructing KayPro'), but here we are, and that's fine by me.  On the other hand, we still have in front of us all the Omni4 software (and it's hardware), so you might get your wish.  That is, if you're not already put-off 'portables', mouldering magnetics, and crusty CRTs....

  Are you sure? yes | no

Dr. Cockroach wrote 09/25/2017 at 11:36 point

At each step you are learning more about the whole system and I am sure that you will correct for this issue :-)

  Are you sure? yes | no