by Richard F. Drushel (drushel@apk.net)
Last week in my ADAMcon 0Ch report (TWWMCA 0007.30), I mentioned that one of the reasons that I brought a complete PC/ADAM/ADAMserve system with me to Toronto was so that I could debug some problems that Guy Bona was having with ADAMserve and SmartFiler. (For those who don't know, ADAMserve is software written by me to allow an ADAM to access PC drives and devices over a null-modem serial link. See TWWMCA 9709.26 for a complete technical description.) Guy had a database that he had created using SmartFiler under Marcel de Kogel's ADAMEM emulator, and wanted to use it under ADAMserve. Guy could read/write this database okay under ADAMEM, but when he cloned the .DSK image to a real 160K floppy and tried to read it under ADAMserve, SmartFiler would lock up the ADAM, forcing a hard reset to get out of it.
Guy demonstrated this behavior to me using my ADAMserve setup in my room at the convention. While it did turn out that the actual 160K floppy that we were using had been incorrectly cloned from the ADAMEM .DSK image, the fact remained that SmartFiler would hang whenever it tried to read/write an ADAMserve floppy disk drive. Moreover, two other Coleco programs which (I hypothesize) utilize the guts of the SmartFiler database engine, Recipe Filer and Address Book, *also* hang under ADAMserve when doing server drive I/O. So, I hypothesized that all three of these programs have the same "problem" with ADAMserve, and that the fix for one would fix all of them.
How do you "fix" a program which exists only as an executable binary image? You disassemble it--run a program which converts the binary image back into a text file of assembly code which, in principle, can be edited and then reassembled to give a new, "fixed" binary. Twelve years ago, when I was disassembling the EOS ROM and SmartBASIC 1.0 to see how they worked, I used a SmartBASIC program that I wrote, UNASMHEX, which did not attempt to create a re-assemblable source file. In the mid-1990s I discovered Kenneth Gielow's Z80DIS 2.2 for CP/M, a freeware Z80 disassembler which has some "artificial intelligence" to figure out what is code and what is data (always a hard problem: how do you know if the bytes represent instructions or just a message string?). Nowadays I run Z80DIS under a CP/M emulator for MS-DOS: formerly Joan Riff's Z80MU, but more recently (because of better emulation) Sydex's 22NICE. (Why not Simeon Cran's MYZ80, the "best" Z80 emulator for MS-DOS? Because it requires disk image files instead of being able to read/ write files directly from an MS-DOS directory; the latter is much more convenient.)
Even a "smart" disassembler's output requires manual inspection and tweaking. And once you have the disassembly, you have to interpret it--all of the original programmers' comments are gone! Now it's time for a good word processor to do global search/replace on all labels which represent EOS function calls, EOS global data structures, etc. Fortunately for me, I have compiled lists of all such EOS and OS-7 global symbols; and I also have commented source code for the EOS and OS-7 operating systems. These resources, combined with long experience, allow the creation of a reasonably interpretable disassembly listing.
If all you want to do is read the listing, *or* determine places to make patches to the existing binary which don't change the program's memory map footprint in any way, then you don't have to worry too much that you might not have completely or correctly resolved all of the code-vs.-data ambiguities. If, however, you'd like to make major changes which would cause data areas to be moved, then you must be absolutely sure that you've picked out every address or vector table and flagged them as such for the disassembler. Otherwise, the tables will get moved, but the address references won't (they will just be static binary data), so the "new" program will crash.
How can you tell that you have correctly resolved all of the ambiguities? The best way is to insert a NOP (no operation) statement after the first code statement in the program, reassemble, and run the new binary. This NOP will shift everything up by one byte. If *all* features of the program still work, then you have caught all the data references, and can go on to make whatever changes you like. If the program crashes, or if menu text strings display as shifted over by one letter, with the first letter being garbage, then you know that you have missed something.
I used this procedure to regenerate assemblable source code for both SmartWriter R80 (see TWWMCA 9710.20) and the ColecoVision cartridge game Pitfall (see TWWMCA 9701.19). Further hints and kinks about disassembly can be found in those articles.
SmartFiler (like all other Coleco software) is normally booted by placing the program tape/disk into the drive and pulling the reset switch. This action causes block 0 of the tape/disk to be loaded into RAM at address 0C800H, followed by a JP 0C800H to execute the code there. This "boot block" is responsible for loading the rest of the application into RAM and then executing it. For systems with third-party hard drives, applications are installed on disk such that all the block 0 boot blocks are stored as separate files, and the rest of the application binaries and support files are stored in different "volumes" (akin to subdirectories). Under HARDDISK, the user specifies which application he wants to launch; then HARDDISK loads the appropriate boot block and changes the current "volume" to be where the rest of that application's files are. This is a workaround for the fact that the ADAM was designed as a single-user, single-application system, and all the Coleco software assumes that it can take over the entire machine.
The user booting SmartFiler from tape or disk sees first a message screen which shows a blue block graphic "ADAM" and white text THE COLECOVISION(r) FAMILY COMPUTER SYSTEM PRESENTS SMART FILER(tm) (c) 1984 COLECO. This is followed shortly by a complex graphic screen depicting lots of sheets of paper being filed, and a graphic version of the words "Smart Filer". Finally, the SmartFiler data entry window appears. (At this point, if you type ^R, Control-R, you will see the version number appear on one of the SmartKey menu strings; the latest is 27D dated 8/16/1984.)
Since the stock ADAM came only with a tape drive, and tape drives are slow compared to disk drives (especially considering rewind time), an important design feature of Coleco software is to get something on the screen quickly, to distract the user while the rest of the application is loading in from disk. There are EOS function calls to do tape/disk I/O in the background, so that the user can start interacting with the program (especially in Super Games) while the tape drive is spinning. Still, the wait can seem long, especially to those accustomed to modern computers.
SmartFiler consists of the 1K boot block (BOOT), 3K of code and data for the graphic logo (LOGOS), and 33K of application (SMARTFILER). While these three pieces are organized as files on the SmartFiler tape/disk, the software (unfortunately) does not access them as files: instead, it assumes that they occupy certain contiguous blocks, and have certain specified lengths, and accesses them solely by absolute block number. LOGOS is assumed to be at blocks 2-4, and SMARTFILER at blocks 5-37. This is *bad* design! (The version of SmartFiler which was patched to run from hard drives must occupy a different set of absolute blocks in volume 0; if it is moved from those absolute blocks, it will crash.)
BOOT contains all the code and data necessary to load the first boot screen; it then loads and executes LOGOS, which creates the graphic boot screen; and then it loads SMARTFILER, finally jumping to the start of application code. SMARTFILER then relocates itself to a different address from which it was loaded by BOOT, before actually entering the main SmartFiler data entry screen. The relocator module of SMARTFILER is 1K in size and appears to have been tacked on to the beginning of a 32K debugger dump of addresses 0000H-7FFFH. About the first 2K (after the 1K relocator) and the last 2K of SMARTFILER are debugger code and menu strings which are orphaned from the main SmartFiler code. (Among other things, this debugger had a serial I/O module to communicate with a remote computer, using some unknown serial board which, I bet, is the same as the one used in the Coleco Graphics Processor cartridge. Hmm, maybe it even *is* CGP code...)
To date, I have completely disassembled and resolved, and partially commented both SmartFiler BOOT and LOGOS. The disassembly source can be reassembled (using SLR's Z80ASM+) to give binaries identical to the starting binaries. I haven't yet done the NOP-offset trick to absolutely verify that I have resolved the listings correctly; but these are short and straightforward programs, and I'm confident that I've gotten them right.
The disassembly source files are available:
I also have a fully-resolved disassembly of the 1K relocator module of SMARTFILER; but the remaining 32K module is still not completed. I have a lot of code tracing to do to disentangle all the debugger code (which is not executed by SmartFiler) from the rest. I also haven't yet started to look for where ADAMserve might be crashing. I won't do that until I am confident that I understand what the entire program is doing. It will take a few more weeks of study, I think. Stay tuned.
There are a number of programming design and style issues raised by the disassembly of the SmartFiler BOOT program (and a few rants to be ranted). I'll discuss these next time.
See you again next week!
*Rich*
Next Article
Previous Article
TWWMCA Archive Main Page