pax_global_header00006660000000000000000000000064130660361460014517gustar00rootroot0000000000000052 comment=ea5b695062feed8d433f11135c657f421e8d66c9 xtrs-4.9d/000077500000000000000000000000001306603614600125375ustar00rootroot00000000000000xtrs-4.9d/ChangeLog000066400000000000000000001477031306603614600143250ustar00rootroot000000000000004.9d -- Mon Jun 15 16:46:34 PDT 2009 -- Tim Mann * Fixed gcc warnings. * Some small cleanups to reset and power-on. * Added a workaround to a current X bug that made F11 repeat infinitely. See http://bugs.freedesktop.org/show_bug.cgi?id=21454. * Added a keybinding help window contributed by Branden Robinson. Press F11 to see the help. * Fixed one more spot that was assuming "char" is signed by default. * Changed mem_read() to automatically mod the address by 0xffff. Requiring callers to take care of that was ugly and error prone. A bug report from Kevin P. Rauch alerted me to the fact that at least one caller to mem_read_word() wasn't doing it, causing segfaults. * Added patch from Branden Robinson so that extra Enter events synthesized by the X unclutter app (or potentially other X apps, I guess) don't cause xtrs to lose track of whether to reenble X key repeat when the cursor leaves the xtrs window. * Added patch from Joe Peterson and Ulrich Mueller that makes NEWDOS/80 boot up knowing the date and time, similar to the existing feature for LDOS. * Added assignment to a volatile to the delay/autodelay loop. Without this some compilers will optimize the loop into nothingness, so it fails to delay. Thanks to Ulrich Mueller and Joe Peterson. * Fixed a bug I introduced in 4.9b, where the KBWAIT feature would stop working after F7, F9, or F10 was pressed. Thanks to Joe Peterson for a bug report and analysis. * Deleted all SIGIO code. The code was a kludge to begin with and it no longer worked with current X libraries and Linux kernels, causing xtrs to hang. It was also reported to cause hangs when xtrs was compiled for Windows using Cygwin. Thanks to Howard Pepper, Dennis Lovelady, Arumin Nueckel, Christopher Currie, and Joe Peterson for bug reports. * Replaced "Last modified" lines in source files with RCS $Id$ keywords. It's been years since I've had the DEC SRC macros that update these lines loaded in my emacs, so they don't stay up to date. And I've kept the file history in RCS for even more years. 4.9c -- Sun May 14 17:54:25 PDT 2006 -- Tim Mann * Fixed the new -e flag on import/cmd and export/cmd to actually work. Oops. Tested on Model I DOSPLUS 3.5. 4.9b -- Sat May 13 11:54:26 PDT 2006 -- Tim Mann * Bundled in the latest version of Roland Gerlach's CP/M utilties for xtrs and their documentation (as of 5/13/2006). * Added -emtsafe feature to turn off ability for emts to write to unexpected places in the host filesystem. Thanks to Joe Peterson. * Added -e flag to import/cmd and export/cmd. Dropped DOSPLUS patches for those programs, which were outdated anyway. * Dropped old method of importing/exporting files using fake I/O ports and deleted import/bas and export/bas. * Small cleanups in load_cmd.c. * Renamed Z-80 source files to .z80 instead of .z to prevent Linux utilities from thinking they're compressed files. * Moved key queuing code from trs_interface.c to trs_keyboard.c and cleaned it up a little. * Applied patches from Branden Robinson to add watchpoints and the zbxinfo command to the debugger and clean up a few things. Thanks! * Added some signed/unsigned type casts; thanks to Andreas Jochens. 4.9a -- Mon Apr 25 22:35:51 PDT 2005 -- Tim Mann * Changed the DISKDEBUG options in trs_disk.c to be runtime flag bits instead of #ifdefs. Added diskdebug command in zbx to set the bits, with terse documentation in zbx's help command. 2 (FDC commands) is the most useful. 1 (FDC register I/O) is extremely verbose but sometimes useful. * Added code to export.cmd and import.cmd to ignore the TRSDOS/LDOS 6 advisory error code when we open a file with the "wrong" LRL. * Fixed a typo in the usage message for mkdisk. * Increased the maximum accepted track length for DMK to the hard limit of 0x4000. Previously it had been 0x2940, but cw2dmk is writing longer tracks than that by default for 8" disks now! Oops. * Small cleanup patches from Branden Robinson for cassette.sh. 4.9 -- Sat May 11 13:42:06 PDT 2002 Tim Mann This release has various bug fixes and tiny features that have accumulated since the last one. * Added a hint about floppy drive BIOS settings to the man page. * Fixed a bug in the cassette shell script. The cassette image type wasn't being determined from the file extension due to a shell programming error. * Got rid of #ifdef HRG1B" and just put all the code for that in-line. Moved documentation to where most of the implementation is. * Added -iconic option. Thanks to Jean-Marc Le Peuvedic. * Bugfix: check_endian would crash if it failed; it was calling fatal() before program_name was set. Thanks to Sot Aliadis for the bug report. * Bugfix: the SIGUSR1 feature wasn't turning off the needchange flag after doing the disk change, so it would do the change over and over. Thanks to Jean-Marc Le Peuvedic for the bug report. * Bugfix: The change that was made in version 4.6 to get the 500bps loader that came on a 250bps tape to work turned out to break writing 1500bps tapes. The tape-based 500bps loader needed a special heuristic, because it does a write just after turning on the motor but before its first read. But the 1500bps writer does a read after all its writes but before turning off the motor. This was erroneously activating the heuristic for the loader case, causing us to switch to read mode without flushing the last transition from the write. The heuristic is now changed so that it won't activate if more than one write has been done since the motor was turned on. This makes both cases work. * Changed the sound code to be less picky about sample format on /dev/dsp. Needed because some hardware doesn't do the 8-bit formats. We still prefer to use 8-bit mono for game sound and 8-bit stereo for Orchestra-85/90, but we can also use 16-bit signed little endian for either, and stereo when we want mono (but not vice versa). * Fixed a bug in FDC emulation that was stopping CopyCat from booting. After starting a read, the CopyCat boot loader reads from the data register once immediately, before DRQ has come high. This read must not capture the first byte of data from the sector. * Fixed a bug in FDC emulation that was keeping CopyCat from seeing sectors on a track other than the first. When client software used the Model III/4/4P feature that lets you put the Z-80 into a wait state until the FDC raises DRQ, the amount of time waited was not being added to the T-state counter. Thus repeated Read Address commands that used the wait state feature would read the same sector ID over and over instead of rotating to the next one. * The change in version 4.2 to wait a few T-states after a floppy Read or Read Address command before raising DRQ was only implemented for floppy image files. It's now implemented for real floppies too. * The change in version 4.2 to set the track and sector registers on a Read Address to the track and sector numbers read from the ID field was implemented only for real floppies. It's now implemented for floppy image files too. * A few minor cleanups to floppy emulation code. * Bugfix: When a real Z-80 takes an interrupt or NMI from a halt instruction, it pushes the address of the next instruction after the halt as the return address (and later returns there, thus breaking out of the halt). Previously xtrs was erroneously pushing the address of the halt instruction instead. If no interrupt or NMI is taken, xtrs still repeatedly executes the halt instruction; you can see this if you use zbx to single-step or trace a halt. A real Z-80 supposedly executes nops internally instead of re-executing the halt, but the difference is not visible to Z-80 programs running in xtrs. 4.8 -- Fri Aug 31 11:39:49 PDT 2001 Tim Mann * This release has quick fixes for some troublesome bugs. Better fixes may be forthcoming in a later version. Thanks to Jean-Marc Le Peuvedic and Frederic Vecoven for problem reports and suggestions. * Changed my email address, as I have left Compaq. * Bug fix: Output to the X server was not always being flushed in a timely manner. It is now flushed at the frequency of the timer interrupt on the machine being emulated (30 to 60 times per second). This fixes problems with the display not being updated when it should have been in certain games and operating systems. * Added a heuristic to flush the key transition queue if the Z-80 program does not poll the keyboard often enough. Right now this is set to go off if more than 2 timer interrupt ticks go by without a poll. This change should get rid of the unwanted typeahead effect previously seen in certain situations, such as when a game does some screen flashing or sound effects between levels without polling the keyboard. * Fixed a compile error on non-Linux platforms. 4.7 -- Sun Jul 8 16:37:14 PDT 2001 Tim Mann * Fixed a silly bug that caused a crash if no -diskdir was specified. I had inadvertently deleted the initialization. 4.6 -- Sat Jul 7 13:56:33 PDT 2001 Tim Mann * The value of -diskdir can now begin with "~/" (or just be "~") to make it relative to the user's home directory. Suggested by Jean-Marc Le Peuvedic. * Fixed the heuristic that decides whether the TRS-80 is loading or saving to tape to work with the 500bps loader that came on a 250bps cassette with the tape Editor/Assembler. This code does an OUT to the cassette port first thing after turning on the motor, which was confusing us. Now if the TRS-80 does an IN from the cassette port with the motor on, we switch to reading even if we initially saw an OUT and guessed it was writing. * Added feature: sending SIGUSR1 to xtrs causes a disk change (as if F7 were pressed). This is for use by external disk-manipulating programs. Suggested by Jean-Marc Le Peuvedic. * Changed to a new keystretch algorithm that stretches for a fixed number of T-states instead of a fixed number of keyboard matrix reads. This should hopefully eliminate the need to tweak the keystretch setting to different values for games. Inspired by suggestions from Jean-Marc Le Peuvedic. To make this work, also had to change the KBWAIT algorithm to wait only after the ROM wait-for-key routine has been called several times with no keyboard state change. * I noticed that the X server on my development machine is now reporting Shift+F1 as F13 instead of F11, so I changed the table in trs_keyboard.c to match, but I left an #if setting that can accommodate the old behavior. It looks like newer versions of XFree86 don't do either translation, thankfully. 4.5a -- Fri May 4 23:17:46 PDT 2001 Tim Mann * Corrected some typos in xtrs.man and Makefile. Thanks to Branden Robinson. 4.5 -- Wed May 2 20:48:10 PDT 2001 Tim Mann * All undocumented instructions and almost all undocumented flag settings from http://www.msxnet.org/tech/Z80/z80undoc.txt are now emulated. * Added code to parse resources from $HOME/.Xdefaults, $HOME/Xtrs, and /usr/X11/lib/X11/app-defaults/Xtrs. Normally Xt would handle this, but xtrs doesn't use Xt. Branden Robinson noted the absence of this feature back in 1998; it's finally fixed. * Added -shiftbracket command line option, inspired by mail from Jean-Marc Le Peuvedic. Defaults to true on Model 4/4P. * Added man pages for hex2cmd and cmddump; thanks to Branden Robinson. * Raised JV1/JV3 cylinder limit from 96 to 255 after someone sent me a JV1 with 143 cylinders. I wonder which DOS that was made with! * Fixed syntax errors in debug.c that gcc had been allowing through. * Corrected some man page errors and unclear passages. 4.4 -- Fri Feb 16 23:52:32 PST 2001 Tim Mann * Added some DOSPLUS patches for import/cmd and export/cmd from Knut Roll-Lund. * Removed kludge from MSM5832 clock chip emulation; now it provides a plain 2-digit year (i.e., "01" for 2001) as the real hardware did. * Cleaned up a bit and eliminated C compiler warnings. * Added break command to debugger as a synonym for "stop at". * Modified the debugger's reset and run commands, and added softreset. Now reset does a powerup initialization of the Z-80 and all devices, while softreset just pushes the TRS-80's reset button. The run command does a hard reset and starts execution at address 0000. On the Model I and III, softreset resets external devices and gives the Z-80 a nonmaskable interrupt, but on the Model 4 and 4P, it is the same as reset. * Added emulation of the Alpha Products joystick, mapped at port 0 only. For the moment it doesn't work with a real joystick; instead, it uses the numeric keypad keys with NumLock off. Keys 2, 4, 6, 8 (KP_Down, KP_Left, KP_Right, KP_Up) are the main directions; keys 1, 3, 7, and 9 (KP_End, KP_Page_Down, KP_Home, KP_Page_Up) work as diagonal directions by activating two main directions at once; and key 0 (KP_Insert) or 5 (KP_Begin) is the fire button. At some point I may acquire a real PC joystick, read about the X input extension, and make that work too. 4.3 -- Fri Jul 21 20:44:48 PDT 2000 Tim Mann * Added emulation of the serial port for all models. Note: Model I LDOS 5.3.1 has a bug in the RS232 driver (RS232R/DVR). You must set the break parameter to a nonzero value for it to work. Try "SET *CL RS232R (BREAK=1)", for example. * Added emulation of the Radio Shack graphics card for Model III. This is just like the Model 4 card, except that there is no overlay mode, there are no scrolling registers, and the graphics are always 640x240 (never 512x192). Changed default graphics card from -microlabs to -nomicrolabs. Changed the -resize flag to be meaningful in Model III mode, and changed the default to be off for Model III mode, but still on for Model 4/4P mode. * Added emulation of the Micro Labs graphics card for Model III. This is quite different from the Model 4 card. I deduced how it works by looking at what the software for it was trying to do, so there could be bugs in the emulation. * Enable the hard disk controller at powerup. NEWDOS is said to need this. * Minor changes to compile on Solaris. Thanks to Frederic Vecoven. * Bugfix: The MSM5832 clock chip returns a leap year indication in bit 2 of port base+8. * Bugfix: When running an emulated model 4/4P in model 3 mode, characters were being drawn only 10 scaled pixels high instead of 12. * Added a unified debug() routine to print all debugging messages. * Patch to fix zbx listing up to 0xffff, from Ulrich Mueller. * Patch to correct disassembly of DD and FD prefixes that have no effect, from Ulrich Mueller. * Patches to remove unneeded cast and fix indentation, from Ulrich Mueller. 4.2 -- Sat Jun 24 01:05:13 PDT 2000 Tim Mann * Emulation of the Model I HRG1B 384*192 graphics card, sold in Germany for Model I and Video Genie by RB-Elektronik. Contributed by Ulrich Mueller. * Fixed a bug that would crash xtrs if the Z-80 SP pointed into keyboard memory. Contributed by Ulrich Mueller. * The -scale command line option now allows independent scaling in the X and Y dimensions. The scaling mechanism is also used to eliminate the need for the bitmaps in trs_chars.c to be double-height, and to eliminate the need for the separate double-width bitmaps formerly in trs_wide_chars.c. The German characters in trs_chars.c were corrected to make this work. Contributed by Ulrich Mueller. * Fixed an obscure bug in the heuristic to identify whether a disk image is JV1, JV3, or DMK. * In trs_disk.c, reading a sector now waits a while before raising DRQ. The old behavior broke the boot loader for self-booting Zork. * In trs_disk.c, Read Address now sets the track register to the track number read and the sector register to the sector number read. The 1771 data sheet says that Read Address sets the sector register to the sector number, but nothing about the track register. The 179x data sheet says that Read Address sets the sector register to the track number, and nothing about the track register, which seems wrong. "The Institute" game loader assumes that Read Address will set the track register to the track number on a 1771. * Minor accuracy tweaks to trs_hard.[ch]. 4.1 -- Fri May 19 00:40:29 PDT 2000 Tim Mann * Fixed a Y2K problem in settime/cmd (as assembled from settime.z). For some random reason, Model I/III LDOS 5.3.1 stores a 2-digit year, so 2000 => 0, but Model 4 LS-DOS 6.3.1 stores an offset from 1900, so 2000 => 100. Previously we were getting it right for 5.3.1 but wrong for 6.3.1. * Fixed a bug in the floppy drive motor timeout interrupt. It was not being cancelled immediately when a drive was reselected. This sometimes made the floppy driver in the Montezuma CP/M boot sector fail, and could have caused problems in other software too. * Now only Models I/III/4, not Model 4P, are emulated as having no floppy controller when they have no disks mounted. A Model 4P always has an FDC, and it can boot off the hard drive with suitable software (such as Montezuma CP/M), so it is possible to boot an operating system with no floppies mounted, then mount and access some later. This isn't possible on the other models. * Bugfix: If a JV3 or DMK floppy was not writable, but did not have its internal write-protected flag set, we were not emulating a write protect tab as intended. * F9 will now get you into the debugger (zbx) even if you didn't start xtrs with the -debug flag. Also, starting with -debug no longer causes the emulator to run more slowly; it runs at full speed as long as no traps are set. * Formerly, executing a halt instruction caused entry into the debugger (zbx) if xtrs had been started with the -debug flag. This feature has been removed. As a replacement, executing the new emt_debug emulator trap (ed2f) always causes the program to enter the debugger. * Fixed the debugger reset and run commands to reset the whole machine, not just the processor. * Installed a small patch that makes the emulator control its window size in the correct way, by passing a size hint to the window manager instead of noticing when its size has changed and changing it back. Thanks to Joseph Wang. * Added emulation of real Radio Shack hard drive controllers (WD1010). * Changed xtrshard/dct to set the directory cylinder field in the Reed header automagically. (Heuristic: when a byte is written to cylinder 0, sector 0, byte 2, assume that's the right value.) The WD1010 emulation does this too. There is now no need for mkdisk to have a flag to set this field, or for the user to remember to use the right value with FORMAT, so that stuff is deleted from the man pages. * Deleted references to cassette "autodetect" format, since I'm not going to get around to implementing it. The current autodetection in the cassette shell script based on file extension works well enough. Rephrased the caveats about reading and writing real cassettes, since I just tried it again and got fairly good results this time. 4.0 -- Sat Apr 1 20:52:53 PST 2000 Tim Mann * Fixed bugs in switching between 80x24 and 64x16 screen sizes in -usefont mode. Thanks to Al Petrofsky for noticing back in 1998 that the code looked wrong; I finally got around to cleaning it up for 4.0 and found the bugs. * Worked around an X problem. If you start xtrs with the -resize flag and a Model 4 operating system is already mounted, the window gets resized very soon after being created. This was triggering some sort of X race condition that would make the window get confused about how big it was. * Fixed obscure bugs in the Model 4 hi-res graphics card emulation. * Added -scale option. Thanks to Denis Leconte for some of the code. * Emulate software-switchable 3.54Mhz clock speedup kit on Model I. Useful with Orchestra-85 emulation. * Changed -samplerate default to 44,100 for better sound. * Added emulation of Orchestra-85 and Orchestra-90. Thanks to David Keil for some information on how Orchestra-90 works. * Fixed a bug that sometimes caused the F10 reboot key to hang the emulator until the next X event. * Added emulation of TimeDate80, TChron1, TRSWatch, and T-Timer, based on code from Joe Peterson and information in LDOS Quarterly 1-6. I'm not sure it's completely right; see the comments in trs_io.c. If you have software that uses these devices, let me know how well it works, especially with regard to the Y2K issue. * Added support for Level 1 Basic .cas files. * Worked around a problem that kept Model I Level 2 Basic from being able to read .cas files. When Basic records a 500bps cassette, it puts an extra delay after the initial 0xA5 sync byte. This delay is required when reading a cassette because Basic executes quite a bit of code right after reading the sync byte. As a kludge, I put in an extra delay whenever a 0xA5 is read from a 500bps cassette; ugly, but it works. * Updated documentation for EXPORT.COM in xtrs.man; this change should have been in 3.9. 3.9a -- Sun Nov 28 14:17:49 PST 1999 Tim Mann * Fixed a bug in the GENIE support and added one more GENIE feature: printer interface at port 0xFD. 3.9 -- Fri Nov 26 11:07:24 PST 1999 Tim Mann * Fixed a problem in the sound support which (for reasons I don't fully understand) was making xtrs hang when playing sound on Linux kernel 2.2.12. Thanks to Roland Gerlach for the bug report. Version 3.8 of xtrs worked on kernel 2.2.5, but not 2.2.12. Also fixed a bug where too many samples could be generated if the Z-80 program repeatedly wrote the same value to the sound/cassette port; this makes the CP/M bell sound much better, and also seems to fix the remaining problem with the Talking Adventure 1 title screen. * Corrected a small error in emulating Model I floppy disk controller interrupts (a feature that's unused by any known software anyway!). * Installed a pile of changes from Branden Robinson, which he says are "mostly to satisfy the vagaries of Debian's packaging policy." They are as follows: * main.c: canonicalize program_name here, not in trs_xinterface.c, so that error messages are consistent * Makefile: - clean rule deletes compile_rom binary, and keeps deroffed manpages - veryclean rule deletes deroffed manpages - use Debian-canonical file modes when installing - install cmddump, hex2cmd, and mkdisk * Makefile.local: - compile-in expected paths for ROM files - build using readline and ncurses (for zbx internal debugger) - Debian-canonical flags to cc - LDFLAGS and IFLAGS that make sense with our X directories - create a PREFIX variable that gets prepended to BINDIR and MANDIR * trs_xinterface.c: - remove canonicalization of program_name, this is now in main.c - change logic for finding romfiles; check command line options, X resources, compiled-in path to rom files, then finally fall back on a built-in ROM image * cassette.sh: rewrote csh cassette script in Bourne I undid or modified a few of Branden's changes: I left the old cassette script as the default since I'm not confident that every Unix system has a new enough version of /bin/sh to support cassette.sh. I left -Wall out of the C flags, since I see no reason to worry users with the small number of harmless warnings I've left in the code. I put the default installation locations back to places that are appropriate for add-on code in most non-Debian systems: /usr/local/bin and /usr/local/man. * Merged in support for the GENIE, a German Model I clone, from Jenz Guenther. I simplified it a bit along the way; I hope I haven't left out anything essential. * Fetched updated cpmutil.dsk from Roland Gerlach's Web page, http://www.rkga.com.au/~roland/trs-80/cpm-xtrs/. 3.8 -- Sat Jul 17 19:25:57 PDT 1999 Tim Mann * Made several tweaks to the sound support. The title screen of "Talking Adventure 1: Forbidden Planet" for Model III now works somewhat better, at least at -samplerate 44100, but there still seems to be a problem. Also, it still looks like the speed boost when a sound begins (trs_suspend_delay) may be making games run too fast when a sound plays. * Lost Data is now set if a read or write is not completed in 500ms. This is not an exact emulation, but is enough to make DOSPLUS 3.3 and Floppy Doctor work. * Seeking and stepping slowed down a little to make Floppy Doctor notice that the Busy bit does get set. * Head Engaged bit emulated correctly now. Was needed for Talking Adventure loader (!). * DMK writing emulation more accurate, handles case of writing to a sector that was formatted with no DAM. Thanks to David Keil. * zbx "dump" command prints T-state counter and delay value. "diskdump" prints T-states to next motor timeout, not T-state counter value at timeout. 3.7 -- Sat Jul 3 15:57:04 PDT 1999 Tim Mann * Completely rewrote the cassette support. Instead of trapping the Model I ROM routines, it now observes I/O requests to the cassette port and uses xtrs's T-state counter to measure (or generate) the correct signal timing. Real cassettes can even be read/written using the OSS sound driver or .wav files, though this could use some work. * Completely rewrote the sound support to use the OSS sound driver. Most code is shared with the cassette support. The old code is still there too, but #if'ed out. * Modified import/cmd and export/cmd to work on Model III TRSDOS 1.3. Tested and verified that setdate/cmd works there too. * Recompiled cd/ccc, mount/ccc, pwd/ccc, truedam/ccc, umount/ccc, and unix/ccc with the LDOS I/O redirection option turned off. This makes them work on Model I/III TRSDOS and NEWDOS too. * Added -l (force lowercase) to cd/cmd, mount/cmd, and unix/cmd. Useful with Model I/III TRSDOS and NEWDOS. * Fixed a bug in printing exit status from unix/cmd. * Added -p/-u flags to mkdisk for turning write protection on/off. * Added display of IFF1, IFF2, IM, and undocumented F register bits to the zbx dump command. * Fixed a 1-byte memory smash in emt_opendisk. * Fixed a bug that could crash xtrs when accessing an empty real floppy drive. * Made error() and fatal() more capable and cleaned up some stray places where fprintf(stderr, ...) was being used instead. 3.6 -- Sun Jun 20 16:13:05 PDT 1999 Tim Mann * Implemented the DMK emulated floppy format. This format supports essentially everything the original hardware could do, including "protected" disk formats, non-IBM sectors on the Model I, partially reformatting a track to achieve mixed density, Read Track, and more. It is compatible with David Keil's Model 4 emulator; thanks to David for designing and documenting it. * Added support for the Motor Off NMI on Model III/4. * Added emulated CRCs on Read Address. * Added diskdump command to zbx; dumps the state of the emulated floppy disk controller and drives. 3.5 -- Sun May 16 21:55:38 PDT 1999 Tim Mann * Changed physical disk handling to report the correct WD17xx error bits upon reading (or writing) a sector with a CRC error in the ID field. In this case both CRC and RNF bits should be set. Fixing this lets us boot physical Scott Adams Adventure disks that use the Kim Watt loader. Unfortunately, the WD17xx behavior with "read address" on such a sector cannot be emulated, because a 765-style FDC's "read id" command ignores IDs with CRC errors rather than returning an error when it sees one. Also, of course, .DSK format has no way to represent a sector with a CRC error in the ID field. * Always use a recalibrate if seeking a real disk to track 0. This should help us recover from confusion about what track the disk is really on. Such confusion should not arise unless two copies of xtrs are both seeking the disk, or the disk is mapped twice to the same xtrs and both virtual drives seek -- but there are sometimes reasons for doing that. * Updated xtrsrom4p.README file with material inadvertently left out in 3.4 release. 3.4 -- Sun Apr 4 22:27:46 PDT 1999 Tim Mann * Corrected the Model 4 reset switch to send RESET instead of NMI. Thanks to Lamar Owen for pointing out the error. * Corrected the default charset for Model III to be katakana. Thanks to Gary Shanafelt and others for pointing out the error. * Fixed minor bugs in cassette support. F10 (Reset button) now gets you out of cloading something that isn't there, even if you aren't using the SIGIO support. Also, autodelay measurement is turned off while cloading. * Added a free minimal Model 4P ROM, written by Pete Cervasio (with a few hacks of my own). Thanks, Pete! The free ROM can boot only Model 4 mode operating systems; it doesn't know how to load MODELA/III. 3.3 -- Sat Jan 23 15:42:36 PST 1999 Tim Mann * Added an emt_misc code to query/set the -truedam flag, and added a Misosys C program to invoke it. Made -truedam more rigorous for real floppies, and clarified (I hope) DAM documentation in the man page. * Much improved behavior when accessing a real floppy drive with no disk in it. Previously this would generate a raft of error messages to stderr, subsequent accessses to the drive would not work until the user pressed F7 to reset the error condition, and the TRS-80 program would always see the problem as a sector not found or a write fault instead of an empty drive. Now we check whether a disk is present whenever the drive is selected, unless we have already checked in the last T seconds (including the implicit check that occurs when you read or write to the drive). If the drive is empty, the TRS-80 program sees this correctly, there are no stderr messages, and F7 is not needed. F7 will still force a check before the timeout T. T is currently set to 3 seconds. * Drive motor timeout is now emulated. Formerly drive motors were emulated as never timing out; now they time out after two seconds (measured in T-states). This is useful for a few programs that fail to handle error cases properly unless the motor eventually times out and causes Not Ready to be asserted. Model I SuperUtility has been observed to do this, at least in some unusual cases. Minor bug: the T-state counter doesn't run during HALT instructions or when the emulator has detected that the TRS-80 program is blocked waiting for keyboard input (but it does run while the TRS-80 program is handling timer interrupts out of those states). * Fixed bugs in maintaining the track position on real floppies. Part of the fix causes a restore (recalibrate) on each real floppy drive when xtrs is first started, and when an emulated drive is changed from a .dsk file to a real drive and F7 is pressed. The other part avoids forgetting the head positions when F7 is pressed. * Detect attempts to format a track with a sector ID that is not followed by any sector data (i.e., no data address mark). We can't represent this on either a .dsk file or a real floppy, so we print an error message. In the JV3 .dsk file case, we record it as an intentional CRC error instead, even though that is not the same thing. * Made -truedam affect reading real floppies. Without -truedam, single density F8 is translated to FA upon reading; with it, F8 reads as F8. On writing to real floppies, it is still the case that all non-FB DAMs are written as F8, but with -truedam you now get an non-fatal error message for F9 and FA. * Changed delayed event scheduler to work in terms of T-states, not instructions. * Used delayed events to emulate semi-correct timing for the Read Address command on emulated floppies. Unfortunately, there were so many problems making this work with real floppies that I had to give up. The timing emulation does make the HyperZap "A" command produce reasonable-looking results on emulated floppies, for what that's worth. * Tweaked the FDC emulation so that the method for formatting mixed density tracks that Model III and 4 Super Utility uses will work on emulated floppies (but not real floppies) -- they toggle the MFM input to the FDC during formatting. I had no idea that would work on real hardware, but evidently it does. The method that Model I SU and HyperZap use still does not work -- they format the track first in one density with a very large gap at the beginning, then reformat over the gap in the other density, aborting the format in the middle using the Force Interrupt command to avoid overwriting the first set of sectors. It's hard to see how to do this reliably with a .DSK file, which carries no information about gaps; how do you decide which sectors (if any) from the old track should remain valid? It also would be a pain to implement. Neither method works on real floppies; it does not seem feasible to implement mixed density formatting on a PC-style FDC, especially not working at arm's length through the Linux driver. * Fixed a few small problems with FDC emulation that were revealed by HyperZap. I still can't really say that xtrs supports HyperZap well enough to be useful. 3.2 -- Sat Jan 2 20:43:42 PST 1999 Tim Mann * Reworked JV3 DAM support to be more accurate by default, or fully accurate with the new -truedam flag. 3.1 -- Tue Dec 15 19:37:30 PST 1998 Tim Mann * Added cd/cmd, pwd/cmd, unix/cmd, mount/cmd, and umount/cmd. They are compiled with Misosys C and therefore probably work only on LDOS and LS-DOS. (They definitely don't work on Model I TRSDOS 2.3 or Model I Newdos/80.) * Changed import/cmd and export/cmd to default the destination filename. * Added emt_getddir and emt_setddir. Changed MC names of some emts in xtrsemt.h because MC's linker requires names to be unique in the first seven characters. Fixed several bugs in xtrsemt.h and xtrsemt.ccc. 3.0 -- Sat Dec 12 11:19:58 PST 1998 Tim Mann * Fixed a bug in the retry loop that's used to read real floppies with sector sizes other than 256. It would screw up if the sector could not be read at all. * Fixed a bug in reflecting CRC errors on real floppies to the emulated controller. Formerly this was done in an incorrect way that would typically hang the floppy driver in the Z-80 DOS. * Minor portability changes. 2.9 -- Fri Nov 6 23:14:20 PST 1998 Tim Mann * Fixed a nasty bug in formatting emulated floppies with sector sizes other than 256 bytes. Sector data would be written to the wrong offset in the file during the format and during any subsequent writes, until the next F7 disk change or the next time the emulator was run. * New version of cpmutil.dsk from Roland Gerlach with a bug fix. IMPORT.COM would crash if the CP/M filename you specified already existed and you gave a different name in response to the error message. 2.8 -- Sat Oct 31 15:00:52 PST 1998 Tim Mann * The default XFree86 keymap reports the shifted F1-F10 keys as keysyms F11-F20, so I changed xtrs's mapping from keysym to TRS-80 key to compensate. Shift+F6 now works as TRS-80 Shift+0, as documented. The remapping entailed some small user-visible changes to seldom used keys: (1) F11-F14 no longer have distinct functions of their own. (2) Home is no longer a synonym for Clear; instead it takes over the obscure duty of letting you activate the Model III/4 RightShift position even if you're in Model I mode. * Replaced the incorrect DAA implementation with a correct one, fixed a few obscure bugs in documented Z-80 flag settings, and implemented all the undocumented flag settings. I used a test program included with the yaze CP/M emulator to check for errors, and I read the yaze code for guidance on fixing them. Thanks to the author of yaze for checking his implementation so carefully and making his code available to others under the GPL. * Bug fix: due to a race condition between the main thread and the SIGALRM handler, autodelay could cause xtrs to hang when the delay changed from nonzero to zero. * Bug fix: trying to do a Write Track on an emulated drive with no disk in it could crash xtrs. Some other operations also failed to check for an empty drive, but with less dire consequences. * We now compute a reasonable gap3 size on real floppies instead of using a small constant value (0x0c). The small gap3 seemed to cause problems at times. The formulas might still need tweaking. * Added code to measure the gap sizes that Z-80 software is trying to format. These are not actually used for anything, but can be printed if debugging is turned on. It's not possible to feed them directly to a PC FDC due to interface differences. * Formatting a real floppy now tries to use the fill data byte given by the Z-80 program. Since the WD17xx let you fill with (almost) any data, but PC FDCs let you choose only one byte, we can't fully emulate this. We just pick the last fill byte given in the last sector and use that throughout. This is needed for CP/M, which looks for its E5 fill byte to find free directory space! * Changed the real floppy sector-not-found error handling heuristic for reads to try each possible sector size once internally before returning an error to the Z-80 program. Of necessity, however, a sector-not-found error on write is still returned immediately to the Z-80 program; on the retry with a different sector size, we will need to run around the Z-80 program's loop more or fewer times to pick up the number of bytes we are trying with. * Fixed a bug in reading/writing 1024-byte sectors on real floppies: the error handling heuristic was not trying that size. * Minor bug fix: executing a HALT instruction would pause the emulator even if a disk interrupt was scheduled to happen a few cycles later. We now check the event schedule before pausing. * Fixed a bug in doing inverse video with -usefont. * Changed the default font for -usefont to have fewer *'s, to eliminate problems where the wide version didn't scale the intended font. 2.7 -- Sat Oct 24 16:21:17 PDT 1998 Tim Mann * Fixed a bug that would have prevented the Z-80 emulation from working on machines where char is unsigned by default. * Implemented the alternate characters for Model III/4, corrected all the character generator fonts and added several options. Decommissioned the .bdf fonts; they are inaccurate and (for unknown reasons) they don't work with the font scaler in XFree86. Decommissioned the -trsfont feature; now graphics blocks are always generated at runtime, not taken from the font. Thanks to Todd Cromwell III for supplying real Model III character generator ROM data obtained using a ROM reader. * Added a fake boot ROM to use as a default. It just prints a message that you don't have a ROM installed for this TRS-80 model. Maybe in the future it could be beefed up to do more: the Model 4 (when not in Model III mode) and the Model 4P don't require a great deal from the ROM. * Updated xtrsemt.h and xtrsemt.ccc. * Added a bunch more functions to emt_misc. * Cleaned up code to remove most warnings. * Added -sizemap and -stepmap. * Added signal blocking around calls to readline in debug.c, allowing it to work again. See Makefile for details. 2.6 -- Wed Oct 14 23:05:01 PDT 1998 Tim Mann * Sector sizes other than 256 are now supported! 128, 256, 512, and 1024 all work, on both JV3 floppy images and real floppies. This feature uses a backward compatible extension to the JV3 format; xtrs JV3 floppy images that use only 256-byte sectors will still work with other emulators. I could find very little TRS-80 software to test this feature with. Super Utility crashes when reading sectors larger than 256 bytes. Trakcess works well, though. * Fixed a bug in delivering FDC completion INTRQs. Previously an interrupt could be lost if Z-80 software read the status register just at the moment the interrupt was to be delivered. * Fixed bugs in the FDC "read address" command on real floppy drives. * Added the -doubler option, and added a more accurate emulation of having two separate FDC chips in Model I mode. Super Utility now works properly with double density if -doubler is set to either "percom" or "radioshack" (not the default value "both"). * Bug fix: The floppy controller's BUSY bit was not set while the FDC completion INTRQ was being delayed. That was the real reason why increasing the delay caused problems (as noted under 2.5 below). 2.5 -- Mon Oct 12 14:59:14 PDT 1998 Tim Mann * Fixed a bug in graphics-only mode. When there is no text overlay, graphics should always be 640x240. Graphics should be 512x192 only when 64x16 text is actually overlayed. Thanks to Mark McDougall for the bug report. * In the fix for CP/M described under 2.3 below, I increased the delay for disk INTRQ in too many cases. The increased delay for seek commands was causing Model III NEWDOS/80 to fail to boot. For now, I reduced the delay on seek (and related commands) back to the pre-2.3 level, while leaving the increased delay for reads on a blank track (and related commands) in place. Thanks to Mark McDougall for the bug report. 2.4 -- Sun Oct 11 08:14:36 PDT 1998 Tim Mann * Oops. The fixes for Montezuma CP/M mentioned below were inadvertently left out. They are included in this version. 2.3 -- Sun Oct 11 01:05:17 PDT 1998 Tim Mann * Added import and export utilities for Montezuma CP/M, written by Roland Gerlach. Thanks! * Fixed bugs in 512x192 graphics mode, reported by Mark McDougall. * Fixed a problem that prevented Montezuma CP/M from formatting diskettes. The number of instructions of delay between trying to read a sector on a blank track and getting a disk INTRQ interrupt was too short. Also, reading the disk status register would cancel a pending interrupt even if it was still being delayed (i.e., had not yet actually happened). * Fixed bug in Model 4 @ICNFG chaining in xtrshard/dct. If you have the old version of xtrshard sysgened, you should remove your config.sys and re-sysgen with the new version. The bug could prevent other sysgened drivers from initializing at boot time, and could even cause crashes while booting due to an address being executed as instructions. * Fixed Expose event support to do fewer redraws. This reduces the problem of xtrs hanging for a long time (doing repeated redraws) after the window is moved, which shows up on window managers that display the coordinates on top of the window while it's moving. * Fixed bugs in -borderwidth, and changed default to 2. * Added emulation of the Radio Shack hi-res graphics card, including undocumented ports. This card is similar to the Micro Labs card but not identical. * Added mouse support and a mouse driver. 2.2 -- Sun Sep 27 19:59:00 PDT 1998 Tim Mann * Added hints on configuring for games to the man page. * Improved the -autodelay algorithm. It now finds the correct speed much faster. 2.1 -- Sat Sep 26 14:06:49 PDT 1998 Tim Mann * Added emulation of the Micro Labs Grafyx Solution Model 4 hi-res graphics card. Thanks to Mark McDougall for typing up a summary of the documentation for me! I checked the behavior on doubtful points against Matthew Reed's emulator -- thanks to Matthew for pioneering here. * Added -autodelay. This dynamically adjusts the -delay setting to try to make programs run at about the speed they would have on a real machine. It works by monitoring how many T-states are executed during each heartbeat clock period and adjusting the delay value up or down by one on each tick. It doesn't track very precisely, but is good enough to make realtime games a lot more playable. * Deleted the -spinfast option, which is no longer needed. * Disk index holes are now emulated in virtual time, locked to the rate at which T-states would be executed by a real TRS-80. Thus programs that measure the disk rotational speed with timing loops will get the answers they expect. In particular, this will correct problems with the FORMAT programs in TRSDOS 2.3, VTOS 3.0, and at least some NEWDOS versions. * Added a T-state counter. * Keyboard repeat is automatically turned off when focus enters the window and restored to the previous state when it leaves. Thanks to Marcelo Fernandes Vianna for the idea and an initial version of the code. * Partial support for 16-byte non-IBM sectors in the 1771 FDC emulation, just enough to support VTOS 3.0's copy protection scheme. Bit position 0x04 in the JV3 sector flags field is now used to indicate a non-IBM sector. Thanks to D. J. Dubay for inspiration. * Parameters to the keystretch algorithm can now be controlled from the command line. Tweaking them might be of help in getting games or other software that polls the keyboard in unusual ways to work well. * Bugfix: in Model 4 mode, we could try to access the SoundBlaster hardware even when the -sb switch was not given, typically resulting in a crash. Thanks to Roland Gerlach for the bug report. 2.0 -- Sun May 24 18:14:52 PDT 1998 Tim Mann * Added -delay flag, a crude speed control. * Added Model 4P emulation. Please don't pirate Model 4P ROMs. Frank Durda IV has expressed interest in creating a freely redistributable, simplified 4P ROM for use in emulators, but it is not yet available. * Added a somewhat more general mechanism for scheduling events to happen several instructions in the future. This supports software that sometimes starts an I/O operation that will trigger a completion interrupt in the near future, but relies on the fact that the real I/O device could not interrupt until the CPU had had time to execute a few more instructions. Previously I had a more kludgey case-by-case solution for this problem, but that method didn't work for the Model 4P ROM. * The cmddump program (a TRS-80 DOS load module analyzer) is now included in the release, but there is no man page. See the top of cmddump.c for brief documentation. * Added ability to use a TRS-80 load module file directly as the ROM. In particular, the MODELA/III file is in this format. * mkdisk now puts the original filename in the header of a .hdv file. * Added missing code to initialize the SoundBlaster DSP and turn on the DAC speaker. This was required to make sound work properly on my machine, which has the ESS1688 AudioDrive sound chip, a SoundBlaster clone. It's probably needed for older true SoundBlaster models too. * Changed sound resource to have same name ("sb") as command line option. * Moved sound init code to fix bug I introduced in 1.10. * Older Linux kernels don't have ; 2.0.29 does not, 2.0.32 does. Added comment saying to delete the include if it causes an error. * Fixed bugs in assembly version of settime: it did not work on an emulated Model III/4/4P in Model III mode using MODELA/III as its ROM, and it caused JCLs to abort on Model 4 LDOS. * Fixed bug in emulating the SLA instruction: the Z flag was not getting set when 0x80 was shifted left to yield zero. The bug was affecting the MultiDOS 4 keyboard driver, causing problems with key repeat. 1.10 -- Thu Apr 16 19:20:30 PDT 1998 Tim Mann * Fixed bug in setting data rate for real floppy drives that spin at 300 RPM (3.5-inch and 360KB 5-inch). This bug caused disks written by xtrs in such drives to be unreadable on a real TRS-80 (and vice versa). Disks written by old xtrs versions in 1.2MB 5-inch drives (which spin at 360 RPM) are OK. * Finished implementing emulation of 8-inch floppy drives. Added xtrs8/dct, an LDOS/LS-DOS driver for the emulated 8-inch floppy hardware. Corrected index hole emulation for 8-inch drives to run at 360 RPM. Added support for real 8-inch drives (untested) and emulation of 8-inch drives by real 5.25-inch and 3.5-inch drives (tested and working). * Added emt_system. Updated xtrsemt.ccc. * Added sound emulation based on code from Fabio Ferrari. Linux with SoundBlaster only. * Fixed bug in returning error (or success) code from emt_strerror. Reported by Roland Gerlach. * Give an error message and don't crash if diskM-U is linked to a floppy device that we don't have read/write permission for. * Undocumented equivalents for documented instructions are now commented in disassemblies. * import.z and export.z modified to also work with Newdos/80. settime.ccc rewritten in assembly language and made to also work on Newdos/80. Thanks to Ulrich Mueller for this code! * Corrected disassembly of ld a,r. Added borderwidth resource. Minor fix to import.bas for Newdos/80. Thanks to Ulrich Mueller for this code! 1.9 -- Thu Feb 12 20:44:02 PST 1998 Tim Mann * Added a hard disk emulation driver, xtrshard/dct. It basically uses the plain file I/O emts, but I added minor variants of open and close to allow the names to be relative to -diskdir and keep rebooting from causing file descriptor leaks. Renamed mkfloppy to mkdisk and added support for making an empty hard disk. Hard disk format is compatible with Matthew Reed's emulators; thanks to Matthew for supplying documentation on his format. * Distinguished between fatal and nonfatal errors. Now an unimplemented opcode is a nonfatal error. It's treated as a no-op. * Added the raw code bytes to disassembler printout. Fixed bugs in disassembling ld (ix+dd),nn and ld (iy+dd),nn. Corrected disassembly of rlca and rrca. * Fixed a fatal bug in emt_lseek. Added emt_ftruncate. Fixed portability bug in emt_open that affected import/cmd and export/cmd. Added disk change count on emt_misc. * "next" in debugger now will step over RSTs. Note this won't work right with the funny RST 8 calling convention in the Model I/III Basic ROM, which puts a 1-byte argument after the instruction. * Added import, export, and settime for Model 4 TRSDOS/LDOS 6. * Fixed problems compiling trs_disk.c on some Linux versions. 1.8 -- Mon Dec 1 16:00:52 PST 1997 Tim Mann * Moved queueing of keys to after the translation from X keysyms to TRS-80 keyboard transitions. This lets shift transitions that are forced by other keystrokes (where X and TRS-80 keyboards have opposite shift states to get the same character) be queued separately and thus separated in time from the basic key transitions. This separation is required by the Montezuma CP/M keyboard driver, which sometimes misses a shift transition if another transition occurs at exactly the same instant. * Bug fix: an FDC restore command was erroneously zeroing the sector register instead of just the track register. Montezuma CP/M tickled this bug. * Bug fix to mem_bank from Roland Gerlach. Switching banks in the low-order half of the address space was switching in the wrong memory. Montezuma CP/M tickled this bug and crashed. * Removed use of pre-POSIX signal code; thanks to Al Petrofsky. * Added the delayed_intrq_kludge in more cases in trs_disk.c. This fixes additional problems with SuperUtility and Trakcess that I didn't notice earlier. Also fixed some problems with error handling on real floppies. 1.0.tpm1 to 1.7 -- Tim Mann * Added floppy disk emulation, timer interrupt emulation, a kludge to import and export data to the host system, Model III mode, Model 4 mode, a rewrite of the keyboard handling, support for most of the undocumented Z-80 instructions, and a bunch of bug fixes and minor improvements. * Fixed bugs in the instructions rrc, inc ix, inc iy, sra, and neg. I didn't notice the sra bug until I tried to get Model III mode working; the Model III LDOS disk driver uses it. The neg bug was keeping the break key from working right under LDOS in xtrs-1.3 and earlier. * Got the emulator running on both Linux and Digital Unix. Now it might have minor problems elsewhere, on less ANSI- and POSIX-compliant systems. * Fixed two bugs in the disassembler. The ld (bc),a instruction was erroneously disassembled as ld bc,a, and instructions that start "dd cb" or "fd cb" were not disassembled; for example: bit 7,(iy+03h). * Fixed some bugs in emulated cassettes. Formerly if you tried to append more stuff to an emulated cassette, it would smash whatever was already there. If you tried to read from a cassette with nothing on it, it would lock up so hard that even the emulated boot button wouldn't work. Now at least the boot button works. * SIGIO is now used in a much safer way than before, and the emulator will work without it if needed. * Reworked the keyboard support substantially. A full state vector is now kept, including all 64 possible TRS-80 keys. Key queueing is now always used, and a "stretching" feature prevents the emulated keyboard state from changing too often, to avoid losing keystrokes. Keyboard response is quite snappy and reliable now. I added enough key mappings that it should be possible to do about everything you could do with a real TRS-80 keyboard (and more than on a Model I, because modern keyboards have N-key rollover). More key mappings are easily added by changing tables; there is very little special-case code. * Did some work on the KBWAIT feature, which tries to avoid burning host CPU cycles when the emulated program is sitting in a loop polling the keyboard. It now works in a lot more cases. * More accurate character bitmaps are now used, contributed by Al Petrofsky. The Model I bitmaps are still not the real ones, which used a 5x7 matrix, not 7x8. * The halt instruction is now emulated correctly. Formerly it caused xtrs to exit. 1.0 -- David Gingold and Alec Wolman * Initial release. Emulated a TRS-80 Model I with 48K of RAM, cassette drive, and uppercase-only screen. See README. xtrs-4.9d/Makefile000066400000000000000000000076101306603614600142030ustar00rootroot00000000000000# # Makefile for xtrs, the TRS-80 emulator. # $Id: Makefile,v 1.33 2008/06/26 04:39:56 mann Exp $ # OBJECTS = \ z80.o \ main.o \ load_cmd.o \ load_hex.o \ trs_memory.o \ trs_keyboard.o \ error.o \ debug.o \ dis.o \ trs_io.o \ trs_cassette.o \ trs_xinterface.o \ trs_chars.o \ trs_printer.o \ trs_rom1.o \ trs_rom3.o \ trs_rom4p.o \ trs_disk.o \ trs_interrupt.o \ trs_imp_exp.o \ trs_hard.o \ trs_uart.o CR_OBJECTS = \ compile_rom.o \ error.o \ load_cmd.o \ load_hex.o MD_OBJECTS = \ mkdisk.o HC_OBJECTS = \ cmd.o \ error.o \ load_hex.o \ hex2cmd.o CD_OBJECTS = \ cmddump.o \ load_cmd.o SOURCES = \ cmd.c \ cmddump.c \ compile_rom.c \ debug.c \ dis.c \ error.c \ hex2cmd.c \ load_cmd.c \ load_hex.c \ main.c \ mkdisk.c \ trs_cassette.c \ trs_chars.c \ trs_disk.c \ trs_hard.c \ trs_imp_exp.c \ trs_interrupt.c \ trs_io.c \ trs_keyboard.c \ trs_memory.c \ trs_printer.c \ trs_uart.c \ trs_xinterface.c \ z80.c HEADERS = \ cmd.h \ config.h \ reed.h \ trs.h \ trs_disk.h \ trs_hard.h \ trs_imp_exp.h \ trs_iodefs.h \ trs_uart.h \ z80.h MISC = \ ChangeLog \ Makefile \ Makefile.local \ README \ cassette \ cassette.txt \ cmddump.txt \ export.cmd \ export.lst \ export.z80 \ hardfmt.txt \ hex2cmd.txt \ import.cmd \ import.lst \ import.z80 \ m1format.fix \ mkdisk.txt \ settime.ccc \ settime.cmd \ settime.lst \ settime.z80 \ utility.dsk \ utility.jcl \ cpmutil.dsk \ xtrs.txt \ xtrsemt.ccc \ xtrsemt.h \ xtrshard.dct \ xtrshard.lst \ xtrshard.z80 \ xtrsmous.cmd \ xtrsmous.lst \ xtrsmous.z80 Z80CODE = export.cmd import.cmd settime.cmd xtrsmous.cmd \ xtrs8.dct xtrshard.dct \ fakerom.hex xtrsrom4p.hex MANSOURCES = cassette.man \ cmddump.man \ hex2cmd.man \ mkdisk.man \ xtrs.man MANPAGES = xtrs.txt mkdisk.txt cassette.txt cmddump.txt hex2cmd.txt PROGS = xtrs mkdisk hex2cmd cmddump default: xtrs mkdisk hex2cmd cmddump manpages manpages: $(MANPAGES) z80code: $(Z80CODE) # Local customizations for make variables are done in Makefile.local: include Makefile.local CFLAGS = $(DEBUG) $(ENDIAN) $(DEFAULT_ROM) $(READLINE) $(DISKDIR) $(IFLAGS) \ $(APPDEFAULTS) -DKBWAIT LIBS = $(XLIB) $(READLINELIBS) $(EXTRALIBS) ZMACFLAGS = -h .SUFFIXES: .z80 .cmd .dct .man .txt .hex .z80.cmd: zmac $(ZMACFLAGS) $< hex2cmd $*.hex > $*.cmd rm -f $*.hex .z80.dct: zmac $(ZMACFLAGS) $< hex2cmd $*.hex > $*.dct rm -f $*.hex .z80.hex: zmac $(ZMACFLAGS) $< .man.txt: nroff -man -c -Tascii $< | colcrt - | cat -s > $*.txt xtrs: $(OBJECTS) $(CC) $(LDFLAGS) -o xtrs $(OBJECTS) $(LIBS) compile_rom: $(CR_OBJECTS) $(CC) -o compile_rom $(CR_OBJECTS) trs_rom1.c: compile_rom $(BUILT_IN_ROM) ./compile_rom 1 $(BUILT_IN_ROM) > trs_rom1.c trs_rom3.c: compile_rom $(BUILT_IN_ROM3) ./compile_rom 3 $(BUILT_IN_ROM3) > trs_rom3.c trs_rom4p.c: compile_rom $(BUILT_IN_ROM4P) ./compile_rom 4p $(BUILT_IN_ROM4P) > trs_rom4p.c mkdisk: $(MD_OBJECTS) $(CC) -o mkdisk $(MD_OBJECTS) hex2cmd: $(HC_OBJECTS) $(CC) -o hex2cmd $(HC_OBJECTS) cmddump: $(CD_OBJECTS) $(CC) -o cmddump $(CD_OBJECTS) tar: $(SOURCES) $(HEADERS) tar cvf xtrs.tar $(SOURCES) $(HEADERS) $(MANSOURCES) $(MISC) rm -f xtrs.tar.Z compress xtrs.tar clean: rm -f $(OBJECTS) $(MD_OBJECTS) $(CR_OBJECTS) $(HC_OBJECTS) \ $(CD_OBJECTS) trs_rom*.c *~ \ $(PROGS) compile_rom veryclean: clean rm -f $(Z80CODE) $(MANPAGES) *.lst link: rm -f xtrs make xtrs install: install-progs install-man install-progs: $(PROGS) $(INSTALL) -c -m 755 $(PROGS) $(BINDIR) install-man: $(MANPAGES) $(INSTALL) -c -m 644 xtrs.man $(MANDIR)/man1/xtrs.1 $(INSTALL) -c -m 644 cassette.man $(MANDIR)/man1/cassette.1 $(INSTALL) -c -m 644 mkdisk.man $(MANDIR)/man1/mkdisk.1 $(INSTALL) -c -m 644 cmddump.man $(MANDIR)/man1/cmddump.1 $(INSTALL) -c -m 644 hex2cmd.man $(MANDIR)/man1/hex2cmd.1 depend: makedepend -- $(CFLAGS) -- $(SOURCES) # DO NOT DELETE THIS LINE -- make depend depends on it. xtrs-4.9d/Makefile.local000066400000000000000000000066061306603614600153000ustar00rootroot00000000000000# # Makefile.local: local customizations for the xtrs Makefile # $Id: Makefile.local,v 1.16 2009/06/15 23:32:53 mann Exp $ # # If your machine is not a sun, vax, or DEC MIPS, uncomment the line below # if the processor has big-endian byte ordering. If you're not sure what # to do, don't worry -- the program will complain if it's not right. # ENDIAN = -Dbig_endian # If you would like the TRS-80 ROM to be built into the application, # use the following lines (with the appropriate file names). You can # get a ROM image from a real TRS-80 with moderate effort, if you have # one. There are also Web sites with TRS-80 ROMs that can be # downloaded, but none are included with this package due to copyright # concerns. As another alternative, for -model III or 4, you can # export the MODELA/III file from a Model III or 4 TRSDOS or # LDOS/LS-DOS diskette and use it as BUILT_IN_ROM3. # The default ROM for -model I, III and 4 (fakerom.hex) just prints a # message saying that you don't have a ROM. The default ROM for # -model 4P (xtrsrom4p.hex) is a free minimal ROM that can boot a # Model 4 mode operating system (such as TRSDOS/LDOS 6); source code # is included in this package. This ROM cannot boot a Model III mode # operating system. # for -model I BUILT_IN_ROM = fakerom.hex # for -model III and -model 4 BUILT_IN_ROM3 = fakerom.hex # for -model 4P BUILT_IN_ROM4P = xtrsrom4p.hex # If you would like the application to load a default ROM file at startup # time, use these lines (with the appropriate file names). The default file # name is ignored and can be omitted if the ROM for that model is built in. DEFAULT_ROM = -DDEFAULT_ROM='"/usr/local/lib/xtrs/level2rom.hex"' \ -DDEFAULT_ROM3='"/usr/local/lib/xtrs/romimage.m3"' \ -DDEFAULT_ROM4P='"/usr/local/lib/xtrs/romimage.m4p"' # If you would like to change where xtrs looks for disk?-? files, edit # this line. "." of course means the current working directory. DISKDIR = -DDISKDIR='"."' # If you have the GNU readline package (the README file tells you where to # get it) and would like to use it with the built-in Z-80 debugger, use # these lines. As of xtrs 2.7, it is now OK to use this feature again. READLINE = -DREADLINE READLINELIBS = -lreadline -lncurses # Select debugging symbols (-g) and/or optimization (-O2, etc.) DEBUG = -O2 -g -Wall #DEBUG = -g -DKBDEBUG -DXDEBUG #DEBUG = -g #DEBUG = -Wall # If you have gcc, and you want to use it: #CC = gcc # If you need a different path for libraries: LDFLAGS = -L/usr/X11R6/lib #LDFLAGS = -non_shared -L/usr/X11/lib # If you need a different path for include files: IFLAGS = -I/usr/include/X11 # Re-define this if your X library is strangely named: XLIB = -lX11 # Use this if you need yet more libraries: #EXTRALIBS = -ldnet #EXTRALIBS = -lots #EXTRALIBS = -ldnet_stub # If you want xtrs to look for a global app-defaults file # at runtime in $APPDEFAULTS/Xtrs: APPDEFAULTS = -DAPPDEFAULTS='"/usr/X11/lib/X11/app-defaults"' # prefix directory PREFIX=/usr/local #If included in distribution: PREFIX=/usr # Set these to where you want installed stuff to go, if you install them. BINDIR = $(PREFIX)/bin MANDIR = $(PREFIX)/share/man # Change this if you have a BSD-compatible install program that is # not the first program named "install" on your $PATH INSTALL = install # If you are building in a subdirectory: #vpath %.c .. #vpath %.h .. #vpath %.man .. #old way: #VPATH = .. xtrs-4.9d/README000066400000000000000000000210121306603614600134130ustar00rootroot00000000000000xtrs README Tim Mann http://tim-mann.org/ 1/12/98 As computer scientists, we always long for something bigger and better than what we have now. Give us a megabyte, and we want a gigabyte. Give us an emulated TRS-80 Model I with Level II BASIC and cassette, and we long for the Expansion Interface and floppy disk drives. Give us that, and we want a Model III. Give us a Model III, and we want a Model 4! This is a snapshot of the work I've been doing on xtrs to add these niceties. My main additions over xtrs-1.0 have been floppy disk and hard disk emulation, timer interrupt emulation, a kludge to import and export data to the host system, Model III mode, Model 4 mode, a rewrite of the keyboard handling, support for most of the undocumented Z-80 instructions, and a bunch of bug fixes and minor improvements. This project has been a real (48KB?) trip down memory lane for me. I worked as a programmer for Logical Systems, the company that produced LDOS, during 1980-81 before I went to grad school. I no longer own a TRS-80, but I recently found a box in my storage closet containing all my Model I hardware manuals, schematics, ROM disassemblies, and even the assembly listing for a version of the LDOS Percom Doubler driver that I helped write, giving me enough information to get my additions to xtrs off the ground. Since then I've done much more. Check out my TRS-80 Web page at http://www.tim-mann.org/trs80.html for details! ************************************************************************* Below is the original README file from xtrs 1.0. It is outdated, but I've kept it for historical reasons and to credit the original authors. XTRS A TRS-80 Model I Emulator for X Windows by David Gingold and Alec Wolman Version 1.0 April 1, 1992 WHAT IS XTRS? As computer scientists, we and our colleagues now and then experience a strange yet powerful desire to write some BASIC code on the computer system that was for many of us the first we owned or programmed: the TRS-80 Model I. In our modern systems of networked workstations and window systems, this capability has been strangely neglected. Xtrs is our attempt to fill this important void in our computing environment. Xtrs is an X Windows client which runs under Unix and emulates a TRS-80 Model I. Version 1.0 is our first release of this software; it provides a simple yet powerful Level II BASIC environment and cassette emulation. We expect to provide some more sophisticated functionality in future releases. OBTAINING XTRS: If you have Internet access, you can get a copy of the latest xtrs software via anonymous FTP: Host: think.com Directory: /users/gingold/xtrs File: xtrs-1.0.tar.Z We will also be posting the sources to alt.sources and perhaps to comp.sources.x. OBTAINING THE ROM: You will need a copy of the Level II ROM software in order to use xtrs. The Level II ROM software may be covered by copyrights; for this reason we are not distributing it with our xtrs software. However, if you already own the Level II ROM software, then you can make yourself a copy of this for use with xtrs (as long as you obey the legal restrictions for its fair use). You can get such a copy via anonymous FTP. Please do not make illegal copies of the ROM software. You already own a legal copy of the Level II ROM software if: - You own a TRS-80 Model I with Level II Basic, - You own a TRSDOS disk which has a copy of the ROM image on it, or - You own a copy of Farvour's "Microsoft Basic Decoded" which contains the ROM code listing. If you have Internet access, you can get a copy of the ROM software via anonymous ftp: Host: think.com Directory: /users/gingold/xtrs/rom File: level2rom.hex If you are obtaining the ROM software through other means (such as getting it directly out of your TRS-80), you'll need to end up with an ASCII file which is in what we believe to be an "Intel Hex" format -- this is a format used with PROM programmers. Our disclaimer: We have neither sought nor received permission from anybody to distribute copies of the ROM software. We discourage your making illegal copies of this or any software. Neither we nor our employers will accept any sort of responsibility if you illegaly copy the ROM software. We are not lawyers, and are in no position to advise you on what is legal. (For the legally curious: the TRS-80 we own has a copyright notice on the ROM PC board, but none on the ROMs themselves or within the software. We don't know if Farvour had permission to publish the ROM code.) BUILDING THE PROGRAM: You can uncompress and extract the software from the tar file as follows: % uncompress xtrs-1.0.tar.Z % tar xvf xtrs-1.0.tar You can then build the program using "make". You will probably need to edit the file "Makefile.local" in order to compile the program properly. Notes in that file explain how to do this. It is possible either to compile the ROM image into the program or to keep the rom file separate, optionally specified on the command line. The "Makefile.local" describes how to do this. If you would like to use the Gnu "readline" facility with the our built-in Z-80 debugger, you can get this software via anonymous FTP: Host: athena-dist.mit.edu File: /pub/gnu/readline-1.1.tar.Z RUNNING THE PROGRAM: See the manual page. DETAILS: Xtrs is built on top of a (mostly) full Z-80 emulator, with added routines to support keyboard and video I/O through an X Windows interface. The hardware emulation is based on the TRS-80 Model I design. Xtrs supports 48K of RAM. There is support for a rudimentary cassette I/O emulation which uses files for cassette tapes. A printer is emulated by sending its output to standard output. There is no support (yet) for a disk or a serial port. The speed of the emulator is pretty good. On a decent Sun-4 compiled with gcc, it computes a little faster than the real thing. Some operations (such as writing to the screen) will naturally be slower. The Z-80 emulator is written to be portable to most C environments. It is possible to build a faster emulator by sacrificing this portability (such emulators have been built for 80x86 and 680x0 machines), but that wasn't our goal. Memory accesses are handled through a function call interface, allowing us to cleanly emulate memory-mapped devices. The Z-80 emulator has a way-cool debugger called zbx. It works sort of like dbx. If you run with the -debug switch you'll enter the debugger, and you can type "help" for more information. Some Z-80 things are not supported: interrupts other than the non-maskable interrupt, other esoteric signals not used by the TRS-80, and any of the "undocumented" Z-80 instructions. Reading the memory refresh register gives a pseudo-random value. The execution speed of instructions bears no relationship to actual Z-80 timings. Special support in the emulator allows the program to block when waiting for information from the keyboard. This will only work for programs which get keyboard input via the standard ROM calls. We do similar tricks to make the cassette I/O work. BUGS: The manual page lists a few known bugs. If you discover bugs (or write fixes for any of these), please let us know (you can send us mail at the above addresses). We expect to incorporate fixes into future releases. FUTURE ENHANCEMENTS: Here are some features we are thinking of adding to xtrs in the future: - A better name for the application. We're not too happy with "xtrs". - An emulator for disk drives. - A mechanism for digitizing cassette tapes. - A nicer mechanism for controlling the cassette emulator. - A cut and paste mechanism in the X window. - An emulator for the serial port. - A Macintosh implementation. CREDITS: David Gingold wrote the Z-80 emulator, zbx, and much of the TRS-80 emulation. Alec Wolman wrote the X windows interface and some of the associated routines. Bruce Norskog is the suspected author of a program called "zdis" which was incorporated into the debugger to disassemble Z-80 instructions. Rodnay Zach's "Programming the Z-80" was the reference for implementing the Z-80 emulator. James Farvour's "Microsoft Basic Decoded and Other Mysteries" and George Blank's "Pathways through the ROM" helped us to debug the emulator and figure out how to make the gnarly keyboard and cassette hacks work. Thanks go to David Librik and Marty Brilliant for providing these books. Jim Cathey, Charlie Gibbs, and Willi Kusche wrote SimCPM, a CPM simulator for the Amiga. This was used (don't ask how) to help debug our Z-80 emulator. xtrs-4.9d/cassette000077500000000000000000000055161306603614600143070ustar00rootroot00000000000000#!/bin/csh -f # Try cassette.sh instead if you do not have /bin/csh. # $Id: cassette,v 1.9 2008/06/26 04:39:56 mann Exp $ set done = 0 set control_file = '.cassette.ctl' set default_format = '1' set format_name = ( 'cas' 'cpt' 'wav' 'direct' 'debug' ) if(! -e $control_file) then echo "Creating" $control_file echo "cassette.$format_name[$default_format] 0 $default_format" \ > $control_file endif while($done != 1) set control = `cat $control_file` set filename = $control[1] set position = $control[2] if (${#control} < 3) then set format = $default_format else set format = $control[3] endif if ({ test -e $filename }) then set isnew = "" else set isnew = " (new)" endif echo "" echo "Tape loaded: " $filename$isnew echo "Type: " $format_name[$format] echo "Position: " $position echo "" echo -n "Command: " set command = "$<" set command = ( $command ) if($#command < 1) then set command = "help" endif switch($command[1]) case "pos": breaksw case "load": case "file": if($#command != 2) then echo "Must specify a file name" else switch($command[2]) case *.cas: case *.bin: set format = 1 breaksw case *.cpt: set format = 2 breaksw case *.wav: set format = 3 breaksw case "/dev/dsp*": set format = 4 breaksw case *.debug: set format = 5 breaksw default: set format = $default_format breaksw endsw echo $command[2] 0 $format > $control_file endif breaksw case "type": if($#command != 2) then echo "Types are:" echo " " $format_name else switch($command[2]) case "cas": set format = 1 breaksw case "cpt": set format = 2 breaksw case "wav": set format = 3 breaksw case "direct": set format = 4 set filename = "/dev/dsp" set position = 0 breaksw case "debug": set format = 5 breaksw default: echo "Types are:" echo " " $format_name breaksw endsw echo $filename $position $format > $control_file endif breaksw case "rew": if($#command == 2) then @ position = $command[2] else @ position = 0 endif echo $filename $position $format > $control_file breaksw case "ff": if($#command == 2) then @ position = $command[2] else set wcout = `wc -c $filename` @ position = $wcout[1] endif echo $filename $position $format > $control_file breaksw case "quit": case "exit": case "done": set done = 1 breaksw case "help": default: echo "Commands are:" echo " pos" echo " load filename" echo " type {$format_name}" echo " rew [position]" echo " ff [position]" echo " quit" breaksw endsw end exit 0 xtrs-4.9d/cassette.man000066400000000000000000000153101306603614600150470ustar00rootroot00000000000000.TH cassette 1 .SH Name cassette \- data cassette image manipulator for xtrs TRS-80 emulator .SH Syntax .B cassette .SH Description To control the emulated cassette used by \fBxtrs\fP, a file called ".cassette.ctl" in the current directory keeps track of what file is currently "loaded" as the cassette tape and the current position within that file. The \fBcassette\fP shell script provides a way to manipulate this file; typing "help" at its prompt shows its commands. You may use this script to load and position cassette tape files. The operation works very much like an actual tape recorder. This manual page also describes the image formats that the emulator supports and their limitations. In this release, two cassette programs are supplied. The original \fBcassette\fP is a C-shell script; it should work with most versions of /bin/csh. If you do not have /bin/csh installed, you can use \fBcassette.sh\fP, which is a Bourne shell script. It requires a modern version of the Bourne shell that supports user-defined functions, so it may not work on older Unix systems. .SH Commands .B pos generates a status message including the filename being used as the cassette image and the current position within the image, in bytes. .B load .I [filename] changes the cassette image currently being used to the file specified, and resets the position counter to zero. .B type .I typename tells the emulator what type of image is loaded. Usually this is detected from the file extension, but you can override the detected value with this command. The supported types are listed in the next section. .B rew .I [position] changes the position counter to the position specified. If no position is given, the counter is reset to zero. .B ff .I [position] changes the position counter to the position specified. If no position is given, the counter is set to the end of the file. .B quit exits the \fBcassette\fP shell script. .SH Types \fBxtrs\fP supports several different types of cassette images, each of which represents cassette data in a different format. .I cas format is fairly compact and is compatible with other TRS-80 emulators that have cassette support. This format represents the bit stream that (the emulator thinks) the TRS-80 cassette routines were trying to save to the tape, not the actual electrical signals on the tape. On writing, the emulator monitors the values that the TRS-80 software is sending to the cassette port and their timing, auto-recognizes whether a 250-bps, 500-bps, or 1500-bps format is being written, decodes the signals into a string of 0 and 1 bits, packs the bits into bytes, and writes them to the cas file. On reading, the emulator auto-detects whether software is trying to read at 250, 500, or 1500 bps and encodes the 0's and 1's back into the signals that the TRS-80 software is expecting. This somewhat roundabout method should work with most TRS-80 cassette routines that read and write signals compatible with the ROM cassette routines, but it may fail with custom routines that are too different. Note that generally nothing useful will happen if you try to write a cas image at one speed and read it at another. There are differences in the actual bit streams that standard TRS-80 software records at each of the three different speeds, not just differences in encoding the electrical signals on the tape. Thus an incoming bit stream that was originally recorded at one speed will not be understood when read back in at a different speed. For example, Level 2 Basic programs are tokenized, while Level 1 Basic programs are not, and the two Basic implementations record different binary information at the start of the program and between lines. Also, when a file is saved at 1500 bps, standard TRS-80 software puts an extra 0 bit after every 8 data bits, and these extra bits are packed into the cas file along with the data bits. .I cpt format (for "cassette pulse train") encodes the exact values and timing of the signals that the TRS-80 cassette routine sends to the cassette output port to be recorded on the tape. Timing is to the nearest microsecond. This format emulates a perfect, noise-free cassette, so any cassette routines that even halfway worked on real hardware should work with it. .I wav format is a standard sound file format. The wav format is intermediate in emulation accuracy between cas and cpt. It does represent actual signals, not decoded bits, but its timing precision is limited by the sample rate used. The default rate for new wav files is 44,100 Hz; you can change this with the -samplerate command line option to \fBxtrs\fP. You can play wav files written by \fBxtrs\fP through your sound card and hear roughly what a real TRS-80 cassette sounds like. A real TRS-80 should be able to read wav files written by \fBxtrs\fP if you copy them to a cassette or connect the TRS-80 directly to the sound card's output. This feature has not been tested extensively, but it does seem to work, at least for short programs. \fBxtrs\fP can also read wav files. It can read back the wav files that it writes without error. Reading wav files sampled from real cassettes is more difficult because of the noise introduced, but in brief testing it does seem to work. The signal processing algorithms used are very crude, and better ones could probably do a better job of reading old, noisy cassettes, but I don't have any such cassettes to test with (and I don't know much about signal processing!). Help in this area would be welcome. The wav file parsing code has several limitations. Samples must be 8-bit mono, and the wav file must contain only one data chunk and no extra optional RIFF chunks in the header. If you have a wav file whose header xtrs rejects, try using sox(1) to convert it to a more vanilla format. .I direct format is similar to wav format, except that the samples go to (or come from) your sound card directly, not a wav file. Direct format requires the Open Sound System /dev/dsp device. Extending the code to work with other sound interfaces would probably not be hard, but is left as an exercise for the reader. Please send me the changes if you do this. .I debug format is the same as cpt format except that the data is written in human-readable ASCII. The cassette output is assumed to be 0 initially. Each line of output gives a new value (0, 1, or 2), and the amount of time (in microseconds) to wait before changing the output to this value. .SH Authors \fBxtrs\fP 1.0 was written by David Gingold and Alec Wolman. The current version was revised and much extended by Timothy Mann (see http://tim-mann.org/). An initial version of this man page, and the translation from C-shell (cassette) to Bourne shell (cassette.sh), are due to Branden Robinson. $Id: cassette.man,v 1.10 2008/06/26 04:39:56 mann Exp $ xtrs-4.9d/cassette.sh000077500000000000000000000054251306603614600147170ustar00rootroot00000000000000#!/bin/sh # $Id: cassette.sh,v 1.4 2008/06/26 04:39:56 mann Exp $ arrayitem () { INDEX=$1 shift eval echo \$$INDEX; } arraycount () { echo $#; } DONE=no CONTROL_FILE=.cassette.ctl DEFAULT_FORMAT=1 FORMAT_NAME='cas cpt wav direct debug' if [ ! -e "$CONTROL_FILE" ]; then echo Creating $CONTROL_FILE echo "cassette.$(arrayitem $DEFAULT_FORMAT $FORMAT_NAME) 0 $DEFAULT_FORMAT" > \ $CONTROL_FILE fi while [ "$DONE" != "yes" ]; do CONTROL=$(cat $CONTROL_FILE) FILENAME=$(arrayitem 1 $CONTROL) POSITION=$(arrayitem 2 $CONTROL) if [ $(arraycount $CONTROL) -lt 3 ]; then FORMAT=$DEFAULT_FORMAT else FORMAT=$(arrayitem 3 $CONTROL) fi if [ -e "$FILENAME" ]; then ISNEW= else ISNEW=" (new)" fi echo echo "Tape loaded: $FILENAME$ISNEW" echo 'Type: '$(arrayitem $FORMAT $FORMAT_NAME) echo 'Position: '$POSITION echo echo -n 'Command: ' read COMMAND if [ $(arraycount $COMMAND) -lt 1 ]; then COMMAND=help fi TOKEN1="$(arrayitem 1 $COMMAND)" case $TOKEN1 in pos) ;; load|file) if [ $(arraycount $COMMAND) -ne 2 ]; then echo "Must specify a file name" else TOKEN2="$(arrayitem 2 $COMMAND)" case $TOKEN2 in *.cas|*.bin) FORMAT=1 ;; *.cpt) FORMAT=2 ;; *.wav) FORMAT=3 ;; /dev/dsp*) FORMAT=4 ;; *.debug) FORMAT=5 ;; *) FORMAT=1 ;; esac echo "$(arrayitem 2 $COMMAND) $FORMAT" > $CONTROL_FILE fi ;; type) if [ $(arraycount $COMMAND) -ne 2 ]; then echo Types are: echo ' '$FORMAT_NAME else TOKEN2="$(arrayitem 2 $COMMAND)" case $TOKEN2 in cas) FORMAT=1 ;; cpt) FORMAT=2 ;; wav) FORMAT=3 ;; direct) FORMAT=4 FILENAME=/dev/dsp POSITION=0 ;; debug) FORMAT=5 ;; *) echo Types are: echo ' '$FORMAT_NAME ;; esac echo "$FILENAME $POSITION $FORMAT" > $CONTROL_FILE fi ;; rew) if [ $(arraycount $COMMAND) -lt 2 ]; then POSITION=0 else POSITION=$(arrayitem 2 $COMMAND) fi echo "$FILENAME $POSITION $FORMAT" > $CONTROL_FILE ;; ff) if [ $(arraycount $COMMAND) -lt 2 ]; then POSITION=$(wc -c $FILENAME) else POSITION=$(arrayitem 2 $COMMAND) fi echo "$FILENAME $POSITION $FORMAT" > $CONTROL_FILE ;; quit|exit|done) DONE=yes ;; *) echo Commands are: echo ' 'pos echo ' 'load filename echo ' 'type {$FORMAT_NAME} echo ' 'rew [position] echo ' 'ff [position] echo ' 'quit ;; esac done exit xtrs-4.9d/cassette.txt000066400000000000000000000172011306603614600151140ustar00rootroot00000000000000cassette(1) cassette(1) Name cassette - data cassette image manipulator for xtrs TRS-80 emulator Syntax cassette Description To control the emulated cassette used by xtrs, a file called ".cas- sette.ctl" in the current directory keeps track of what file is cur- rently "loaded" as the cassette tape and the current position within that file. The cassette shell script provides a way to manipulate this file; typing "help" at its prompt shows its commands. You may use this script to load and position cassette tape files. The operation works very much like an actual tape recorder. This manual page also describes the image formats that the emulator supports and their limitations. In this release, two cassette programs are supplied. The original cas- sette is a C-shell script; it should work with most versions of /bin/csh. If you do not have /bin/csh installed, you can use cas- sette.sh, which is a Bourne shell script. It requires a modern version of the Bourne shell that supports user-defined functions, so it may not work on older Unix systems. Commands pos generates a status message including the filename being used as the cassette image and the current position within the image, in bytes. load [filename] changes the cassette image currently being used to the file specified, and resets the position counter to zero. type typename tells the emulator what type of image is loaded. Usually this is detected from the file extension, but you can override the detected value with this command. The supported types are listed in the next section. rew [position] changes the position counter to the position specified. If no position is given, the counter is reset to zero. ff [position] changes the position counter to the position specified. If no position is given, the counter is set to the end of the file. quit exits the cassette shell script. Types xtrs supports several different types of cassette images, each of which represents cassette data in a different format. cas format is fairly compact and is compatible with other TRS-80 emula- tors that have cassette support. This format represents the bit stream that (the emulator thinks) the TRS-80 cassette routines were trying to save to the tape, not the actual electrical signals on the tape. On writing, the emulator monitors the values that the TRS-80 software is sending to the cassette port and their timing, auto-recognizes whether a 250-bps, 500-bps, or 1500-bps format is being written, decodes the signals into a string of 0 and 1 bits, packs the bits into bytes, and writes them to the cas file. On reading, the emulator auto- detects whether software is trying to read at 250, 500, or 1500 bps and encodes the 0's and 1's back into the signals that the TRS-80 software is expecting. This somewhat roundabout method should work with most TRS-80 cassette routines that read and write signals compatible with the ROM cassette routines, but it may fail with custom routines that are too different. Note that generally nothing useful will happen if you try to write a cas image at one speed and read it at another. There are differences in the actual bit streams that standard TRS-80 software records at each of the three different speeds, not just differences in encoding the electrical signals on the tape. Thus an incoming bit stream that was originally recorded at one speed will not be understood when read back in at a different speed. For example, Level 2 Basic programs are tok- enized, while Level 1 Basic programs are not, and the two Basic imple- mentations record different binary information at the start of the pro- gram and between lines. Also, when a file is saved at 1500 bps, stan- dard TRS-80 software puts an extra 0 bit after every 8 data bits, and these extra bits are packed into the cas file along with the data bits. cpt format (for "cassette pulse train") encodes the exact values and timing of the signals that the TRS-80 cassette routine sends to the cassette output port to be recorded on the tape. Timing is to the nearest microsecond. This format emulates a perfect, noise-free cas- sette, so any cassette routines that even halfway worked on real hard- ware should work with it. wav format is a standard sound file format. The wav format is interme- diate in emulation accuracy between cas and cpt. It does represent actual signals, not decoded bits, but its timing precision is limited by the sample rate used. The default rate for new wav files is 44,100 Hz; you can change this with the -samplerate command line option to xtrs. You can play wav files written by xtrs through your sound card and hear roughly what a real TRS-80 cassette sounds like. A real TRS-80 should be able to read wav files written by xtrs if you copy them to a cas- sette or connect the TRS-80 directly to the sound card's output. This feature has not been tested extensively, but it does seem to work, at least for short programs. xtrs can also read wav files. It can read back the wav files that it writes without error. Reading wav files sampled from real cassettes is more difficult because of the noise introduced, but in brief testing it does seem to work. The signal processing algorithms used are very crude, and better ones could probably do a better job of reading old, noisy cassettes, but I don't have any such cassettes to test with (and I don't know much about signal processing!). Help in this area would be welcome. The wav file parsing code has several limitations. Samples must be 8-bit mono, and the wav file must contain only one data chunk and no extra optional RIFF chunks in the header. If you have a wav file whose header xtrs rejects, try using sox(1) to convert it to a more vanilla format. direct format is similar to wav format, except that the samples go to (or come from) your sound card directly, not a wav file. Direct format requires the Open Sound System /dev/dsp device. Extending the code to work with other sound interfaces would probably not be hard, but is left as an exercise for the reader. Please send me the changes if you do this. debug format is the same as cpt format except that the data is written in human-readable ASCII. The cassette output is assumed to be 0 ini- tially. Each line of output gives a new value (0, 1, or 2), and the amount of time (in microseconds) to wait before changing the output to this value. Authors xtrs 1.0 was written by David Gingold and Alec Wolman. The current version was revised and much extended by Timothy Mann (see http://tim- mann.org/). An initial version of this man page, and the translation from C-shell (cassette) to Bourne shell (cassette.sh), are due to Bran- den Robinson. $Id: cassette.man,v 1.10 2008/06/26 04:39:56 mann Exp $ cassette(1) xtrs-4.9d/cd.ccc000066400000000000000000000027461306603614600136100ustar00rootroot00000000000000/* cd.ccc -- Misosys C program to change Unix working directory on xtrs */ /* Copyright (c) 1998, Timothy Mann */ /* $Id: cd.ccc,v 1.3 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ #option redirect 0 #include "xtrsemt.h" #include "xtrsemt.ccc" /* could use separate compilation instead */ usage() { fprintf(stderr, "usage: cd [-l] unixdir\n"); exit(1); } #define ERRBUFSIZE 256 #define NAMEBUFSIZE 256 int main(argc, argv) int argc; char **argv; { int ret, lower, i; char errbuf[ERRBUFSIZE]; char namebuf[NAMEBUFSIZE]; char *p, *q; if (argc < 2) { usage(); } i = 1; if (argv[i][0] == '-') { if (tolower(argv[i][1]) != 'l') { usage(); } i++; lower = 1; } else { lower = 0; } if (argc - i != 1) { usage(); } p = namebuf; q = argv[i]; if (lower) { while (*q) { if (*q == '[' && *(q+1)) { q++; *p++ = *q++; } else if (isalpha(*q)) { *p++ = tolower(*q++); } else { *p++ = *q++; } } } else { while (*q) *p++ = *q++; } *p = '\000'; ret = emt_chdir(namebuf); if (ret != 0) { emt_strerror(errno, errbuf, ERRBUFSIZE); fprintf(stderr, "%s: %s\n", namebuf, errbuf); exit(1); } exit(0); } xtrs-4.9d/cd.cmd000066400000000000000000000137351306603614600136230ustar00rootroot00000000000000%RÃLW%s: %s usage: cd [-l] unixdir <'RÐiQRWR]R@ @ @eRÃLWñáåõí(`iÈOíC&bÉñáÁÅåõí*ÈOíC&b!Éñáåõí+!ÈOíC&b!ÿÿÉñáÁÑÕÅåõí0bkÈOíC&bÉñÑÕõí1!ÈOíC&b!ÿÿÉñÑáÁÅåÕõí2`iÈOíC&bÉñÑáÁÅåÕõí3`iÈOíC&bÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o"&bÉñÑáÁÅåÕõ{í5`iÈOíC&bÉñáåõ}í6Éñáåõí7bkÈOíC&bÉñÑÕõíeS8!ÈOíC&b!ÿÿÉñÑáÁÅåÕõí9`iÈOíC&bÉñáåõí:!ÈOíC&b!ÿÿÉñáÁÅåõí;ÈOíC&b!Éñáåõ}í<ÉÝåÝ!Ý9ÝnÝfN#FÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfs#rÑÝnÝfs#rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o"&bÉñáÁÑÕÅåõí>bkÈOíC&bÉñÑÕõí?!ÈOíC&b!ÿÿÉ!eT Rå!3RåÍ Xññ!åÍÐ`ñÉöý͹i! 9ͪiå!ÑÍVi|µÊ—TÍdT!9å!Ñͯi!9ͪiå!9ͪiÍ}iÑͪiå!Ñn&å!-ÑÍ=i|µÊ(U!9ͪiå!9ͪiÍ}iÑͪiå!Ñn&åÍ»fñå!lÑÍCi|µÊ UÍdT!9åͪi#Ñͯi+!9å!ÑͯiÃ4U!9å!Ñͯi! 9ͪiå!9ͪiÑÍ‘iå!ÑÍCi|µÊWUÍdT!9å!9Ñͯi!eU9å!9ͪiå!9ͪiÍ}iÑͪiÑͯi!9ͪi|µÊ”V!9ͪin&|µÊ‘V!9ͪin&å![ÑÍ=i|µÊÉU!9ͪiå!Ñn&|µÊV!9åͪiÑͯiÿÿ!9åͪiÑͯiÿÿå!9åͪiÑͯiÿÿn&Ñ}ÃŽV!9ͪin&åÍÑfñ|µÊ_V!9åͪiÑͯiÿÿå!9åͪiÑͯiÿÿn&åÍ»fñÑ}ÃŽV!9åÍeVªiÑͯiÿÿå!9åͪiÑͯiÿÿn&Ñ}ÓUÃÕV!9ͪin&|µÊÕV!9åͪiÑͯiÿÿå!9åͪiÑͯiÿÿn&Ñ}ÔV!9ͪiå!Ñ}!9å!9åÍŠSñÑͯi!9ͪiå!ÑÍCi|µÊ=W!å!9å*&båÍ1Sñññ!9å!9å!Rå!3RåÍ Xññññ!åÍÐ`ñ!åÍÐ`ñ ͹iÉísaR*I@͵f *D"cRùÍlWÍzTeW!åÍÐ`*-R"#R"%RÍÿWí[#RÍôW( Õ ͲW òÅÝáË!ë "#R"%RË9AÑ+r+sùÁåÝåÅÉÃßdÃdÅ~þ"(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( þ\ G#Ú#¯Á> ¾Ø> ¾È#õ!C͵fÀ!%BÉõÝåýå!9å! 9Ñͯi!9åͪi##Ñͯiå!ÿÿ)Ñͪi"€X!‰a"‚X!9åͪi##Ñͯiå!ÿÿ)ÑͪiåÝá!9åÝåáåÍ YñeXñåýáýåáå!9ÍÀi!9ÍÈiáñññÉÕX0B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"†X!"„X*†Xn&|µÊR`*†Xn&%ÍCi|µÊXY*‚Xå*€Xãå*†X#"†X+n&ãå͵iññ*„X#"„XÃO`!"X"›X"™X"—X"•X*†X#"†Xn&åÑ!+ÍriˆY!"•XÃjY!-ÍrišY!"—XÃjY! Íri¬Y!"™XÃjY!#Íri¾Y!"›XÃjY!0ÍriÂÐY!"XÃjY*†Xn&ÕY*Í=i|µÊ&ZñÁáåÅõåͪi##Ñͯiå!ÿÿ)Ñͪi"ŒX*ŒXëÍVi|µÊZ*ŒXÍ–i"ŒX!"—X*†X#"†XÃ^Z!"ŒX*†Xn&åÍäfñ|µÊ^Z*ŒX Í}iå*†X#"†X+n&å͹`ñÑ"ŒXÃ,Z*†Xn&.Í=i|µÊæZ*†X#"†Xn&*Í=i|µÊ«ZñÁáåÅõåͪi##Ñͯiå!ÿÿ)Ñͪi"ŽX*†X#"†XÃãZ!"ŽX*†Xn&åÍäfñ|µÊãZ*ŽX Í}iå*†X#"†X+n&ÕZå͹`ñÑ"ŽXñZÃìZ!ÿÿ"ŽX!"“X*†Xn&åÑ!lÍri [!"“XÃ[!hÍriÂ[*†X#"†X!"‘X! Y"ŸX*†X#"†X+n&}2XåÑ!dÍriÂE[ÃN[!uÍriÂW[!"ÑXâ[!oÍriÂi[!"ÑXâ[!XÍriÂu[Ã~[!xÍri‡[!"ÑXâ[!BÍri“[Ü[!bÍriÂU^!"ÑX*ŽXëÍVi|µÊ·[!"ŽX*“X|µÊå[ñÁáåÅõåͪiÑͯiå!ÿÿÕ[))ÑÍ(i!ÉXÍ0iÃ?\:Xo&dÍ=i|µÊ\ñÁáåÅõåͪi##Ñͯiå!ÿÿ)ÑͪiÍi!ÉXÍ0iÃ?\ñÁáåÅõåͪi##Ñͯiå!ÿÿ)ÑͪiÍi!ÉXÍ0i:Xo&dÍ=i|µÊ³\!ÉXÍ(iÅÕÍzg|µÊ”\!Y"ŸX!ÉXÍ(iÅÕ€Ípg|µÊ‘\!ÉXÍ(iÍôh!ÉXÍ0ió\*•X|µÊ¥\!Y"ŸXó\*™X|µÊ³\!Y"ŸX*X|µÊê\õ!9å*ŒXå*ŸXåÍdñÑÍ‘iÑͯiÕ\áåå*ŽXÑÍOi|µÊé\áå"ŽXñ:Xo&XÍ=i|µÊ]!òXÃ]!áXÃ]"ÍX!¡X("ˆX"ŠX!ÉXÍ(iÍûg|µÊµ]!ÉXÍ(iÅÕÍ©gë"ÓX!ÉXÍ(iÅÕ;gÅÕ€ÍÝgÍ©g!ÉXÍ0i*ˆX+"ˆXå*ÍXå!ÉXÍ(iÅÕ*ÑXÍiÍgÅÕÍ6gÅÕ*ÓXÍiÍggëÑn&Ñ}!ÉXÍ(iÅÕ*ÑXÍiÍg!ÉXÍ0iÃ]*ˆXå*ŠXÑÍ‘iå*ŽXÑ"‘X*›X|µÊÜ]*ˆXåÕ]*ŠXÑÍCi|µÊR^:Xo&åÑ!oÍri ^*‘XëÍVi|µÊ^!"‘XÃR^!xÍriÂ^!ÞX"ŸXÃR^!XÍriÂ.^!ÛX"ŸXÃR^!bÍriÂ@^!ØX"ŸXÃR^!BÍriÂR^!ÕX"ŸXÃR^Ã?_!cÍriÂ^!¡Xå!9ͪiåͪi##Ñͯiå!ÿÿ)ÑͪiÑ}!¡X"ˆX*ˆX#"ŠXÃ?_!sÍriÂ_ñÁáåÅõåͪi##Ñͯiå!ÿÿ)Ñͪi"ˆX*ŽXëÍVi|µÊË^!ÿ"ŽX!"ÏXÃÛ^*Õ^ÏX#"ÏX*ˆX#"ˆX+n&|µÊö^*ÏXå*ŽXÑÍVi|µÊþ^ÃÔ^*ˆX+"ˆX"ŠX*ˆXå*ÏXÑÍ‘i"ˆXÃ?_!ÍriÂ,_*†X+"†XÃ?_!X"ˆX"ŠX*ŠX#"ŠXÃ?_:Xo&|µÊO`õ!9å*ŒXå*ŠXå*ˆXÑÍ‘iÑÍ‘iå*‘XëÍVi|µÊy_!Ã_*‘XÃ_ÑÍ‘iå*ŸXåÍdñÑÍ‘iÑͯi*—XÍ¢i|µÊÃ_!9åͪi+ÑͯiëÍIi|µÊÃ_! åÍt`ñß_*ŸXn&|µÊá_*ŸX#"ŸXÕ_+n&åÍt`ñÃÃ_*‘X+"‘XëÍIi|µÊÿ_!0åÍt`ñÃá_*ˆXå*ŠXÑÍli|µÊ"`*ˆX#"ˆX+n&åÍt`ñÃÿ_*—X|µÊN`!9åͪi+ÑͯiëÍIi|µÊN`! åÍt`ñÃ*`ñÃY*€X|µÊb`*€XåÍjañ|µÊm`!ÿÿÃs`*„XÃs`É*‚Xå*€Xãå!9n&ãå͵iññ*„X#"„XÉñáåõå!9ͪiÑÍVi|µÊ¯`ñáåõø`ñÁáåÅõø`É!9n&0·íRÉñáåõ0ÉÍß`ñá(Õ`åõ|µÊ-@Ã0@!/RA^#V#{²( ÅåëË^ÌaáÁìÉý`!ÿÿ"û`ñáåõÝååÝáÍûc(MË^ M¯ÝwÝwÝååÝá++å##íCû`~q#Ë~(ëÝnÝfåËo Í(D( ÍUb!ÿÿ"û`ͬWÁͬWá*û`ÝáÉ!Ý!("&bîÝåÍñcÝá(~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáÍûc(WËN(SËv OT]åÝá:QRþ*(Ë^#ĪiëÅyþ Ý~ÿæ 4yÍõÝ4þñë(Ë~á }Ö ÝwþÝáÉëËöËî!Ë^(wÍUb!ÿÿå yÍ(+ýaË~ ÉÍb ïÂÝ4þÕÝ^þÝ~ÿæ?Ëq(ö@ö€Í DåÍ|bñ"&báÉñáåõ&}íKWc ¹0þ@Ðþ-.@Ð!(b…oŒ•gn&ɱb¿bÑbábòbcc Í3áÍgD!fÍgD!ÿÿåÍÓ`: BAD BLOCK X'xxxx', LEN X'xxxx' zÍDf{õÍMfñæÆ'Î@'w#ÉýååÕý!)RÕýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý!)RÕýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌ:%þIÉñÑÕõÕÕÍôfÁÑëz³È}ö &oÉñáåõ}!ö þa8ßfþ{Ø+Éñáåõ}!þ0Øþ:Ð#Éñáåõ}!þAØþ[Ð#ÉÍ8iͺhÊiÍìhõÍ¿hÍhñüôhÃiÍ8iͺhÊiÍ¿hõÍhñáÑÁüôhéÍ8iÅÕå!9PXå~#¶#¶#¶áÊag¯Í«hãÜ‹h¯ÍhãÃEgñññÃiÍ8iÍ‹hÃiÍ„gÂ#i+Ã#iÍ„gÚ#i+Ã#i!9###xî€G~¥g+~¹Â¥g+~ºÂ¥g+~»!ÉÍ8i{¦_#z¦W#y¦O#x¦GÃiÍ8iͺh(###Ë+Ë+Ë+ËÍêgèáÑÁé{/ßg_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉͺh!À+ÉÝåõõÝ!Ý9;å~Ýw6#~Ýw6#~Ýw6#~Ýw6.xæ€Â?hËËËË,Ã-hÝuÿÝåáÍÚhåÍsháÊShÒZhÍ…hÍôh7ãÍhÝ5ÿÊlhã¯Í«hÃHhñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍôhËhå~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õüôhÍìhòØhÍÚhÍôhÍÚhñî€ÉñÉå~s_#óßh~rW#~qO#~pGáÉå###~·áÉ{· ² ± xþ€Èå¯o›_}šW}™O}˜GáÉÍiz·ð ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#pÉ!9ÉÍ\iÈ+ÉÍ\iÀ+ÉÍ\iÐ+ÉëÍ\iØ+ÉÍ\iØ+É|î€gz {½!ÉÍriØ+Éz¼Âyi{½!ÉDM¯og>Ë#Ë0 =È)Äië¯íRÉÍ›i#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉLWxtrs-4.9d/cd6.cmd000066400000000000000000000137061306603614600137070ustar00rootroot00000000000000%0ÃN5%s: %s usage: cd [-l] unixdir <'0»GQ0W0]0  g0ÃN5ñáåõí(`iÈOíC;@ÉñáÁÅåõí*ÈOíC;@!Éñáåõí+!ÈOíC;@!ÿÿÉñáÁÑÕÅåõí0bkÈOíC;@ÉñÑÕõí1!ÈOíC;@!ÿÿÉñÑáÁÅåÕõí2`iÈOíC;@ÉñÑáÁÅåÕõí3`iÈOíC;@ÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o";@ÉñÑáÁÅåÕõ{í5`iÈOíC;@Éñáåõ}í6Éñáåõí7bkÈOíC;@ÉñÑÕõíg18!ÈOíC;@!ÿÿÉñÑáÁÅåÕõí9`iÈOíC;@Éñáåõí:!ÈOíC;@!ÿÿÉñáÁÅåõí;ÈOíC;@!Éñáåõ}í<ÉÝåÝ!Ý9ÝnÝfN#FÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfs#rÑÝnÝfs#rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o";@ÉñáÁÑÕÅåõí>bkÈOíC;@ÉñÑÕõí?!ÈOíC;@!ÿÿÉ!g2 0å!30åÍ,6ññ!åÍò>ñÉöýͤG! 9Í•Gå!ÑÍAG|µÊ™2Íf2!9å!ÑÍšG!9Í•Gå!9Í•GÍhGÑÍ•Gå!Ñn&å!-ÑÍ(G|µÊ*3!9Í•Gå!9Í•GÍhGÑÍ•Gå!Ñn&åͦDñå!lÑÍ.G|µÊ 3Íf2!9åÍ•G#ÑÍšG+!9å!ÑÍšGÃ63!9å!ÑÍšG! 9Í•Gå!9Í•GÑÍ|Gå!ÑÍ.G|µÊY3Íf2!9å!9ÑÍšG!g39å!9Í•Gå!9Í•GÍhGÑÍ•GÑÍšG!9Í•G|µÊ–4!9Í•Gn&|µÊ“4!9Í•Gn&å![ÑÍ(G|µÊË3!9Í•Gå!Ñn&|µÊ4!9åÍ•GÑÍšGÿÿ!9åÍ•GÑÍšGÿÿå!9åÍ•GÑÍšGÿÿn&Ñ}Ã4!9Í•Gn&åͼDñ|µÊa4!9åÍ•GÑÍšGÿÿå!9åÍ•GÑÍšGÿÿn&åͦDñÑ}Ã4!9åÍg4•GÑÍšGÿÿå!9åÍ•GÑÍšGÿÿn&Ñ}Õ3Ã×4!9Í•Gn&|µÊ×4!9åÍ•GÑÍšGÿÿå!9åÍ•GÑÍšGÿÿn&Ñ}Ö4!9Í•Gå!Ñ}!9å!9åÍŒ1ñÑÍšG!9Í•Gå!ÑÍ.G|µÊ?5!å!9å*;@åÍ31ñññ!9å!9å!0å!30åÍ,6ññññ!åÍò>ñ!åÍò>ñ ͤGÉísc0íCa0>d!Eï"e0ë!ÿóíRëg50 >eïý~þ` !ÿóùÍ„5Í|2!åÍò>*-0"#0"%0KI>Rï"R0DO>Rï"X0"^0*a0í[#0Í!6( Õ Íß5 òÅÝáË!ë "#0"%0Ë9AÑ+r+sùÁåÝåÅÉÃéBà BÅ~þ"(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( þ\ G#Ú#¯Á> ¾Ø> ¾È#õõÝåýå!9å! 9ÑÍšG!9åÍ•G##ÑÍšGå!ÿÿ)ÑÍ•G"¢6!¨?"¤6!9åÍ•G=g6##ÑÍšGå!ÿÿ)ÑÍ•GåÝá!9åÝåáåÍ,7ññåýáýåáå!9Í«G!9ͳGáñññÉ÷60B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"¨6!"¦6*¨6n&|µÊt>*¨6n&%Í.G|µÊz7*¤6å*¢6ãå*¨6#"¨6+n&ãåÍ Gññ*¦6#"¦6Ãq>!"¿6"½6"»6"¹6"·6*¨6#"¨6n&åÑ!+Í]Gª7!"·6ÃŒ7!-Í]G¼7!"¹6ÃŒ7! Í]GÂÎ7!"»6ÃŒ7!#Í]GÂà7!"½6ÃŒ7!0Í]GÂò7!"¿6ÃŒ7*¨6n&÷7*Í(G|µÊH8ñÁáåÅõåÍ•G##ÑÍšGå!ÿÿ)ÑÍ•G"®6*®6ëÍAG|µÊ>8*®6ÍG"®6!"¹6*¨6#"¨6À8!"®6*¨6n&åÍÏDñ|µÊ€8*®6 ÍhGå*¨6#"¨6+n&åÍÛ>ñÑ"®6ÃN8*¨6n&.Í(G|µÊ9*¨6#"¨6n&*Í(G|µÊÍ8ñÁáåÅõåÍ•G##ÑÍšGå!ÿÿ)ÑÍ•G"°6*¨6#"¨6Ã9!"°6*¨6n&åÍÏDñ|µÊ9*°6 ÍhGå*¨6#"¨6+n&÷8åÍÛ>ñÑ"°6ÃÓ8Ã9!ÿÿ"°6!"µ6*¨6n&åÑ!lÍ]GÂ.9!"µ6Ã79!hÍ]GÂ>9*¨6#"¨6!"³6!+7"Á6*¨6#"¨6+n&}2²6åÑ!dÍ]GÂg9Ãp9!uÍ]GÂy9!"ó6ÃÄ9!oÍ]G‹9!"ó6ÃÄ9!XÍ]G—9à9!xÍ]G©9!"ó6ÃÄ9!BÍ]Gµ9þ9!bÍ]GÂw:ñÁáåÅõåÍ•G##ÑÍšGå!ÿÿ)ÑÍ•GÍýF!ë6ÍGÃa:ñÁáåÅõåÍ•G##ÑÍšGå!ÿÿ)ÑÍ•GÍG!ë6ÍG:²6o&dÍ(G|µÊÕ:!ë6ÍGÅÕÍeE|µÊ¶:!)7"Á6!ë6ÍGÅÕ€Í[E|µÊ³:!ë6ÍGÍßF!ë6ÍGÃÕ:*·6|µÊÇ:!'7"Á6ÃÕ:*»6|µÊÕ:!%7"Á6*¿6|µÊ ;õ!9å*®6å*Á6åÍBñÑÍ|GÑÍšG÷:áåå*°6ÑÍ:G|µÊ ;áå"°6ñ:²6o&XÍ(G|µÊ#;!7Ã);!7Ã);"ï6!Ã6("ª6"¬6!ë6ÍGÍæE|µÊ×;!ë6ÍGÅÕÍ”Eë"õ6!ë6ÍGÅÕÍ©EÅÕ€ÍÈEÍ”E!ë6ÍG*ª6+"ª6å*ï6å!ë6ÍGÅÕ*ó6ÍýFÍïDÅÕÍ!EÅÕ*õ6ÍýFÍREëÑn&Ñ}!ë6ÍGÅÕ*ó6ÍýFÍ E!ë6ÍGÃ9;*ª6å*¬6ÑÍ|Gå*°6Ñ"³6*½6|µÊþ;*ª6å÷;*¬6ÑÍ.G|µÊt<:²6o&åÑ!oÍ]GÂ,<*³6ëÍAG|µÊ)õ!9å*®6å*¬6å*ª6ÑÍ|GÑÍ|Gå*³6ëÍAG|µÊ›=!á=*³6á=ÑÍ|Gå*Á6åÍBñÑÍ|GÑÍšG*¹6ÍG|µÊå=!9åÍ•G+ÑÍšGëÍ4G|µÊå=! åÍ–>ñÃÁ=*Á6n&|µÊ>*Á6#"Á6÷=+n&åÍ–>ñÃå=*³6+"³6ëÍ4G|µÊ!>!0åÍ–>ñÃ>*ª6å*¬6ÑÍWG|µÊD>*ª6#"ª6+n&åÍ–>ñÃ!>*¹6|µÊp>!9åÍ•G+ÑÍšGëÍ4G|µÊp>! åÍ–>ñÃL>ñÃ97*¢6|µÊ„>*¢6å͉?ñ|µÊ>!ÿÿÕ>*¦6Õ>É*¤6å*¢6ãå!9n&ãåÍ Gññ*¦6#"¦6Éñáåõå!9Í•GÑÍAG|µÊÑ>ñáåõÃÚ>ñÁáåÅõÃÚ>É!9n&0·íRÉñáåõ0ÉÍþ>ñá%÷>åõí{c0É!/0A^#V#{²( ÅåëË^Ì=?áÁìÉ?!ÿÿ"?ñáåõÝååÝáÍB(MË^ M¯ÝwÝwÝååÝá++å##íC?~q#Ë~(ëÝnÝfåËo ><ï( Íj@!ÿÿ"?ÍÙ5ÁÍÙ5á*?ÝáÉ!Ý!(";@îÝåÍûAÝá(~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáÍB(RËN(NËv JT]åÝá:Q0þ*(Ë^#Ä•GëÅyþ Ý~ÿæ />ïõÝ4þñëá }Ö ÝwþÝáÉëËöËî!Ë^(wÍj@!ÿÿå >ï ÒÍ@ ô!@ËÝ4þÕÝ^þÝ~ÿæ?Ëq(ö@ö€O>ïåÍ’@ñ";@áÉñáåõ&}íKmA ¹0þ@Ðþ-.@Ð!=@…oŒ•gn&ÉÇ@Õ@ç@÷@AA3ARAcAUnknown errorArg list too longNot a directoryInvalid argumentToo many open filesNot a character deviceMath arg oá=Aut of domain of funcResult too largeI/O errorHñÑÕõ{þ@8Ö@o&þ 8l)µ@ÕGöÀOýå>eïýËþýá«A>ïbk> Pí±+pëÉñáÑÝáÝåÕåõÝnÝf|µÉñÑÕõ!·È#ùÉ BñÑÕõÝåýå!"Bý!'0*'0ý"BÝåýáÝnÝfåÝá|µ(7ÝnÝfí[B·íR8ÜíB0ÝnÝfýuýt ÝuÝtDMÝ ÝsÝr*BåÍ´BÁ|¥< !#";@åÝáÝqÝpÝåÍIDágoýáÝáÉñÑÕõz³('!9íBíK#0íB8 íR8Åë "#0áÉ!#";@!ÿÿÉ*#0ÉéBñÑÕõÝåýåÍùBýáÝáÉ!ÒCÍ×CÝ!üÿÝÍ~Dý!'0 ý"çBýnýfåýáý^ýVz³(ÝåáíR0âÍ·CÝåÁýqýpýå!'0Ñ·íR('ýnýf·íB ÍÄCýuýtÝnÝfýuýtýåÝáý"çBÝNÝFÅýáx±(ÝåáÝ^ÝV·íB ÍÄCÝuÝtÍ·Cý*çBÝåáÝ^ÝVíK#0¯íBÀýwýwÝ"#0ÉýnýfÝuÝtÉýnýfÝ^ÝVÉFREEÝåÅÕåë+F+N++ÍìCáÑÁéCÝáÉëÝ!)0ÝnÝf|µ(åÝáíRÈ8îñ!6D>cïYP!CD>cï >ïá> ï!(D> ï!ÿÿåÍõ>: BAD BLOCK X'xxxx', LEN X'xxxx' ýååÕý!)0Õýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý!)0Õýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌñÑÕõÕÕÍßDÁÑëz³È}ö &oÉñáåõ}!ö þa8þ{Ø+Éñáåõ}!þ0Øþ:Ð#Éñáåõ}!þAéDØþ[Ð#ÉÍ#GÍ¥FÊ GÍ×FõͪFÍïEñüßFà GÍ#GÍ¥FÊ GͪFõÍïEñáÑÁüßFéÍ#GÅÕå!9PXå~#¶#¶#¶áÊLE¯Í–FãÜvF¯ÍˆFãÃ0Eñññà GÍ#GÍvFà GÍoEÂG+ÃGÍoEÚG+ÃG!9###xî€G~ÂE+~¹ÂE+~ºÂE+~»!ÉÍ#G{¦_#z¦W#y¦O#x¦Gà GÍ#GÍ¥F(###Ë+Ë+Ë+ËÍÕEèáÑÁé{/_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍ¥FéE!À+ÉÝåõõÝ!Ý9;å~Ýw6#~Ýw6#~Ýw6#~Ýw6.xæ€Â*FËËËË,ÃFÝuÿÝåáÍÅFåÍ^FáÊ>FÒEFÍpFÍßF7ã͈FÝ5ÿÊWFã¯Í–FÃ3Fñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍßFÃvFå~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õüßFÍ×FòÃFÍÅFÍßFÍÅFñî€ÉñÉå~s_#~rW#~qO#~pGáÉå###~·áÉ{· ² ± ÔéFxþ€Èå¯o›_}šW}™O}˜GáÉÍGz·ð ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#pÉ!9ÉÍGGÈ+ÉÍGGÀ+ÉÍGGÐ+ÉëÍGGØ+ÉÍGGØ+É|î€gz {½!ÉÍ]GØ+Éz¼ÂdG{½!ÉDM¯og>Ë#Ë0 =È)ÃoGë¯íRÉ͆G#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉN5xtrs-4.9d/cmd.c000066400000000000000000000032641306603614600134530ustar00rootroot00000000000000/* Routines to write a TRS-80 DOS "/cmd" file */ /* Copyright (c) 1996, Timothy Mann */ /* $Id: cmd.c,v 1.3 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ #include static int last_address, block_address; static int block_size, got_transfer; static unsigned char block[256]; static FILE* file; void cmd_init(FILE* f) { last_address = block_address = -2; block_size = 0; got_transfer = 0; file = f; } void cmd_data(int address, int value) { unsigned char* p; if (value < 0 || address != last_address + 1 || block_size >= 256) { if (block_size > 0) { /* close off current block */ putc(1, file); putc((block_size + 2) & 0xff, file); putc(block_address & 0xff, file); putc((block_address >> 8) & 0xff, file); p = block; while (block_size) { putc(*p++, file); block_size--; } } last_address = block_address = address; if (value == -2) { /* transfer address */ putc(2, file); putc(2, file); putc(block_address & 0xff, file); putc((block_address >> 8) & 0xff, file); return; } if (value == -3) { /* eof, no transfer address */ putc(3, file); return; } } /* continue current block */ block[block_size++] = value; last_address = address; return; } void cmd_transfer_address(int address) { cmd_data(address, -2); got_transfer = 1; } void cmd_end_of_file() { if (!got_transfer) cmd_data(0, -3); } xtrs-4.9d/cmd.h000066400000000000000000000011111306603614600134450ustar00rootroot00000000000000/* Routines to write a TRS-80 DOS "/cmd" file */ /* Copyright (c) 1996, Timothy Mann */ /* $Id: cmd.h,v 1.4 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ extern void cmd_init(FILE *outf); extern void cmd_data(int address, int value); extern void cmd_transfer_address(int address); extern void cmd_end_of_file(void); xtrs-4.9d/cmddump.c000066400000000000000000000111731306603614600143370ustar00rootroot00000000000000/* Copyright (c) 1996-98, Timothy Mann */ /* $Id: cmddump.c,v 1.3 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* Simulated TRS-80 DOS /cmd file loader. * * See the LDOS Quarterly, April 1, 1982 (Vol 1, No 4), for documentation * of the TRS-80 DOS /cmd file format. * * Usage: cmddump [-flags] infile [outfile startbyte nbytes] * If the optional arguments are given, the given byte range is dumped * from the simulated memory after loading. * * Flags: -q quiet: turn off -t, -m, -d, -s (later flags can override). * -t print text of module headers, pds headers, * patch names, and copyright notices. * -m print running load map as file is parsed, * coalescing adjacent blocks (implies -t). (default) * -d print detailed map; same as -m, but don't coalesce. * -s print summary load map after file is parsed. * -i n select ISAM entry n (0x notation OK) * -p foo select PDS entry "foo" (padded to 8 bytes with spaces) * -x ignore anything after the first xfer address */ #include #include #include #include #include "load_cmd.h" unsigned char memory[64*1024] = { 0 }; unsigned char loadmap[64*1024]; #define ARGS "qtmdsi:p:x" int main(int argc, char* argv[]) { FILE* f; int verbosity = VERBOSITY_MAP; int isam = -1; char *pds = NULL; int xferaddr, stopxfer = 0; int print_summary = 0; char pdsbuf[9]; int res; int c, errflg = 0; optarg = NULL; while (!errflg && (c = getopt(argc, argv, ARGS)) != -1) { switch (c) { case 'q': verbosity = VERBOSITY_QUIET; break; case 't': verbosity = VERBOSITY_TEXT; break; case 'm': verbosity = VERBOSITY_MAP; break; case 'd': verbosity = VERBOSITY_DETAILED; break; case 's': print_summary = 1; break; case 'i': isam = strtol(optarg, NULL, 0); break; case 'p': strncpy(pdsbuf, optarg, 8); pdsbuf[8] = '\000'; strncat(pdsbuf, " ", 8 - strlen(pdsbuf)); pds = pdsbuf; break; case 'x': stopxfer = 1; break; default: errflg++; break; } } if (errflg || !(argc == optind + 1 || argc == optind + 4)) { fprintf(stderr, "Usage: %s [-%s] infile [outfile startbyte nbytes]\n", argv[0], ARGS); exit(1); } f = fopen(argv[optind], "r"); if (f == NULL) { perror(argv[optind]); exit(1); } res = load_cmd(f, memory, print_summary ? loadmap : NULL, verbosity, stdout, isam, pds, &xferaddr, stopxfer); switch (res) { case LOAD_CMD_OK: if (isam != -1) { fprintf(stderr, "warning: not ISAM file but -i flag given\n"); } else if (pds) { fprintf(stderr, "warning: not PDS file but -p flag given\n"); } break; case LOAD_CMD_EOF: fprintf(stderr, "premature end of file\n"); exit(1); case LOAD_CMD_NOT_FOUND: if (pds) { fprintf(stderr, "PDS entry \"%s\" not found\n", pds); } else { fprintf(stderr, "ISAM entry 0x%02x not found\n", isam); } exit(1); case LOAD_CMD_ISAM: if (isam == -1) { fprintf(stderr, "warning: ISAM file but -i flag not given\n"); } break; case LOAD_CMD_PDS: if (pds == NULL) { fprintf(stderr, "warning: PDS file but -p flag not given\n"); } break; default: fprintf(stderr, "load file format error, bad block type 0x%02x\n", res); break; } if (print_summary) { /* Print load map */ int lastaddr = -1; int lastcount = -1; int addr; for (addr = 0; addr < sizeof(memory); addr++) { if (loadmap[addr] != lastcount) { if (lastcount == 1) { printf("loaded 0x%04x - 0x%04x\n", lastaddr, addr-1); } else if (lastcount > 1) { printf("loaded 0x%04x - 0x%04x (%d times!)\n", lastaddr, addr-1, lastcount); } lastaddr = addr; lastcount = loadmap[addr]; } } printf("transfer address = 0x%04x\n", xferaddr); } /* Dump memory - optional */ if (argc == optind + 4) { FILE* outf; int addr, count; outf = fopen(argv[optind + 1], "w"); if (outf == NULL) { perror(argv[optind + 1]); exit(1); } addr = strtol(argv[optind + 2], (char**)NULL, 0); count = strtol(argv[optind + 3], (char**)NULL, 0); while (count-- > 0) { putc(memory[addr++], outf); } fclose(outf); } return 0; } xtrs-4.9d/cmddump.man000066400000000000000000000031471306603614600146720ustar00rootroot00000000000000.TH cmddump 1 2001-02-22 .SH Name cmddump \- simulated TRS-80 CMD file loader .SH Syntax \fBcmddump\fP \fI[flags] infile [outfile startbyte nbytes]\fP .SH Description .B cmddump displays information about TRS-80 DOS binary (command) files. It takes an optional set of \fIflags\fP (described below), an input /cmd file, and an optional \fIoutfile\fP, an optional starting offset of \fIstartbyte\fP into the /cmd file, and an optional \fInbytes\fP number of bytes to dump. Non-flag arguments must be given in the order shown. If the optional arguments are given, the given byte range is dumped from the simulated memory after loading. .SH Options .TP \fB-d\fP print detailed map; same as -m, but don't coalesce .TP \fB-i\fP \fIn\fP select ISAM entry \fIn\fP (0x notation OK) .TP \fB-m\fP print running load map as file is parsed, coalescing adjacent blocks (implies -t) (default) .TP \fB-p\fP \fIfoo\fP select PDS entry \fIfoo\fP (padded to 8 bytes with spaces) .TP \fB-q\fP quiet; turns off -t, -m, -d, -s (later flags can override) .TP \fB-s\fP print summary load map after file is parsed .TP \fB-t\fP print text of module headers, pds headers, patch names, and copyright notices .TP \fB-x\fP ignore anything after the first transfer address .SH Author .B cmddump was written by Timothy Mann. This man page was generated by Branden Robinson from comments in the source code. .SH See also .IR xtrs (1) .PP See the LDOS Quarterly, April 1, 1982 (Vol 1, No 4), for documentation of the TRS-80 DOS /cmd file format. It is available on the Web at http://www.tim-mann.org/misosys.html. $Id: cmddump.man,v 1.2 2008/06/26 04:39:56 mann Exp $ xtrs-4.9d/cmddump.txt000066400000000000000000000035031306603614600147320ustar00rootroot00000000000000cmddump(1) cmddump(1) Name cmddump - simulated TRS-80 CMD file loader Syntax cmddump [flags] infile [outfile startbyte nbytes] Description cmddump displays information about TRS-80 DOS binary (command) files. It takes an optional set of flags (described below), an input /cmd file, and an optional outfile, an optional starting offset of startbyte into the /cmd file, and an optional nbytes number of bytes to dump. Non-flag arguments must be given in the order shown. If the optional arguments are given, the given byte range is dumped from the simulated memory after loading. Options -d print detailed map; same as -m, but don't coalesce -i n select ISAM entry n (0x notation OK) -m print running load map as file is parsed, coalescing adjacent blocks (implies -t) (default) -p foo select PDS entry foo (padded to 8 bytes with spaces) -q quiet; turns off -t, -m, -d, -s (later flags can override) -s print summary load map after file is parsed -t print text of module headers, pds headers, patch names, and copyright notices -x ignore anything after the first transfer address Author cmddump was written by Timothy Mann. This man page was generated by Branden Robinson from comments in the source code. See also xtrs(1) See the LDOS Quarterly, April 1, 1982 (Vol 1, No 4), for documentation of the TRS-80 DOS /cmd file format. It is available on the Web at http://www.tim-mann.org/misosys.html. $Id: cmddump.man,v 1.2 2008/06/26 04:39:56 mann Exp $ 2001-02-22 cmddump(1) xtrs-4.9d/compile_rom.c000066400000000000000000000060071306603614600152130ustar00rootroot00000000000000/* * Copyright (C) 1992 Clarendon Hill Software. * * Permission is granted to any individual or institution to use, copy, * or redistribute this software, provided this copyright notice is retained. * * This software is provided "as is" without any expressed or implied * warranty. If this software brings on any sort of damage -- physical, * monetary, emotional, or brain -- too bad. You've got no one to blame * but yourself. * * The software may be modified for your own purposes, but modified versions * must retain this notice. */ /* Modified by Timothy Mann, 1996 and later $Id: compile_rom.c,v 1.9 2008/06/26 04:39:56 mann Exp $ */ #include "z80.h" #include "load_cmd.h" char *program_name; static int highest_address = 0; static Uchar memory[Z80_ADDRESS_LIMIT]; static Uchar loadmap[Z80_ADDRESS_LIMIT]; /* Called by load_hex */ void hex_data(int address, int value) { address &= 0xffff; memory[address] = value; if(highest_address < address) highest_address = address; } void hex_transfer_address(int address) { /* Ignore */ } static void load_rom(char *filename) { FILE *program; int c, a; if((program = fopen(filename, "r")) == NULL) { char message[100]; sprintf(message, "could not read %s", filename); fatal(message); } c = getc(program); if (c == ':') { /* Assume Intel hex format */ rewind(program); load_hex(program); fclose(program); return; } else if (c == 1 || c == 5) { /* Assume MODELA/III file */ int res; rewind(program); res = load_cmd(program, memory, loadmap, 0, NULL, -1, NULL, NULL, 1); if (res == LOAD_CMD_OK) { highest_address = Z80_ADDRESS_LIMIT; while (highest_address > 0) { if (loadmap[--highest_address] != 0) { break; } } fclose(program); return; } else { /* Guess it wasn't one */ rewind(program); c = getc(program); } } a = 0; while (c != EOF) { hex_data(a++, c); c = getc(program); } } static void write_output(char *which) { int address = 0; int i; highest_address++; printf("int trs_rom%s_size = %d;\n", which, highest_address); printf("unsigned char trs_rom%s[%d] = \n{\n", which, highest_address); while(address < highest_address) { printf(" "); for(i = 0; i < 8; ++i) { printf("0x%.2x,", memory[address++]); if(address == highest_address) break; } printf("\n"); } printf("};\n"); } static void write_norom_output(char *which) { printf("int trs_rom%s_size = -1;\n", which); printf("unsigned char trs_rom%s[1];\n", which); } int main(int argc, char *argv[]) { program_name = argv[0]; if(argc == 2) { fprintf(stderr, "%s: no specified ROM file, ROM %s will not be built into program.\n", program_name, argv[1]); write_norom_output(argv[1]); } else if(argc != 3) { fprintf(stderr, "Usage: %s model hexfile", program_name); } else { load_rom(argv[2]); write_output(argv[1]); } return 0; } xtrs-4.9d/config.h000066400000000000000000000013271306603614600141600ustar00rootroot00000000000000/* * Copyright (C) 1992 Clarendon Hill Software. * * Permission is granted to any individual or institution to use, copy, * or redistribute this software, provided this copyright notice is retained. * * This software is provided "as is" without any expressed or implied * warranty. If this software brings on any sort of damage -- physical, * monetary, emotional, or brain -- too bad. You've got no one to blame * but yourself. * * The software may be modified for your own purposes, but modified versions * must retain this notice. */ /* $Id */ #if defined(sun) && !defined(i386) #define big_endian #endif #ifdef vax #undef big_endian #endif #if defined(mips) && defined(ultrix) #undef big_endian #endif xtrs-4.9d/cpmutil.dsk000066400000000000000000006410001306603614600147200ustar00rootroot00000000000000ƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒƒƒƒƒƒƒƒƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ!ƒ!ƒ!ƒ!ƒ!ƒ!ƒ!ƒ!ƒ! ƒ! ƒ"ƒ"ƒ"ƒ"ƒ"ƒ"ƒ"ƒ"ƒ" ƒ" ƒ#ƒ#ƒ#ƒ#ƒ#ƒ#ƒ#ƒ#ƒ# ƒ# ƒ$ƒ$ƒ$ƒ$ƒ$ƒ$ƒ$ƒ$ƒ$ ƒ$ ƒ%ƒ%ƒ%ƒ%ƒ%ƒ%ƒ%ƒ%ƒ% ƒ% ƒ&ƒ&ƒ&ƒ&ƒ&ƒ&ƒ&ƒ&ƒ& ƒ& ƒ'ƒ'ƒ'ƒ'ƒ'ƒ'ƒ'ƒ'ƒ' ƒ' ƒÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿREADME TXTCPM MLBLIBCFN MLB LIBHEX MLB LIBHFN MLB LIBSTR MLB! LIBXTRS MLB. EXPORT MAC9IMPORT MACq !LIBCFN MAC("#$LIBHEX MAC0%&'LIBHFN MAC)()*LIBSTR MAC4+,-.LIBXTRS MACS/01234TESTLIB MAC)567XTRS MAC 89:;<=>?@ååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååXTRS COMABIMPORT COMCEXPORT COMDEåIMPORT COM CåEXPORT COMDEååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååCP/M Utilities for the XTRS Emulator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ http://members.optusnet.com.au/~rgerlach/trs-80/cpmutil.html åIMPORT MACq åLIBCFN MAC(!"#åLIBHEX MAC-$%&åLIBHFN MAC)'()åLIBSTR MAC4*+,-åLIBXTRS MACY./0123åTESTLIB MAC+456åXTRS MAC 789:;<=>?åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå equ 0Ah cr equ 0Dh sub equ 1Ah space equ 20h ;============================================================================== ; system addresses ;============================================================================== c_boot equ 0000h ; warm start (jp xxxxh) c_iob equ 0003h ; i/o byte c_du equ 0004h ; current disk & user c_bdos equ 0005h ; bdos entry (jp xxxxh) c_fcb1 equ 005Ch ; first file control block c_fcb1_drive equ c_fcb1 ; drive c_fcb1_fname equ c_fcb1+01h ; filename c_fcb1_type equ c_fcb1+09h ; filetype c_fcb1_ex equ c_fcb1+0Ch ; extent c_fcb1_s1 equ c_fcb1+0Dh ; s1 c_fbc1_s2 equ c_fcb1+0Eh ; s2 c_fcb2 equ 006Ch ; second file control block c_fcb2_drive equ c_fcb2 ; drive c_fcb2_fname equ c_fcb2+01h ; filename c_fcb2_type equ c_fcb2+09h ; filetype c_fcb2_ex equ c_fcb2+0Ch ; extent c_fcb2_s1 equ c_fcb2+0Dh ; s1 c_fbc2_s2 equ c_fcb2+0Eh ; s2 ; note c_fcb2 is overwritten if c_fcb1 is used default buffer c_cmdlen equ 0080h ; length of command arguments c_cmdstr equ 0081h ; start of command arguments ;============================================================================== ; bdos macro and service definitions ;============================================================================== bdos macro svc,param ifnb ld de,param endif ld c,svc call c_bdos endm b_term equ 00h ; terminate program b_cinb equ 01h ; console input byte ; exit: a = c_iobuf equ 0080h ; default i/o buffer c_iobufsize equ 80h ; i/o buffer size c_defbuf equ 0080h ; default buffer c_cmdlen equ 0080h ; length of command arguments c_cmdstr equ 0081h ; start of command arguments ;============================================================================== ; bdos ;============================================================================== bdos macro svc,param ifnb ld de,param endif ld c,svc call c_bdos endm b_term equcharacter b_coutb equ 02h ; console output bute ; entry: e = character b_couts equ 09h ; console output string ; entry: de -> string (terminate with '$') b_cins equ 0Ah ; console input line ; entry: de -> buffer (max, cnt, space for string) ; exit: de -> buffer (with cnt and string set) b_seld equ 0Eh ; select drive ; entry: e = drive (0=A:) b_fopen equ 0Fh ; open existing file ; entry: de -> fcb ; exit: a = status (0,1,2,3 or FFh if file not found) b_fclose equ 10h ; clo; CPM.MLB ; ~~~~~~~ ; ; Contents: ; Macro library ; ; Purpose: ; Defines CP/M equates and bdos calls ; ; Usage: ; MACLIB CPM.MLB ; ; Amendment history: ; 14AUG99 RKG 1.0 Initial release. ; 02APR03 RKG 1.1 Added dbgmsg macro. ;============================================================================== ; ascii characters ;============================================================================== nul equ 00h tab equ 09h lf equ 0Ah cr equ 0Dh sub equ 1Ah spc equ 20h ;=se output file ; entry: de -> fcb ; exit: a = status ; notes: no need to close file used only for input b_ffirst equ 11h ; search for first file ; entry: de -> fcb ; exit: a = offset (FFh=>file not found) ; notes: a = 0,1,2,3 (offset into current file buffer=>0,32,64,96 bytes) b_fnext equ 12h ; search for next file ; entry: de -> fcb ; exit: a = offset (FFh=>file not found) ; notes: a = 0,1,2,3 (offset into current file buffer=>0,32,64,96 bytes) b_frseq equ 14h ; sequential read b_============================================================================= ; system addresses ;============================================================================== c_boot equ 0000h ; warm start (jp xxxxh) c_iob equ 0003h ; i/o byte c_du equ 0004h ; current disk & user c_bdos equ 0005h ; bdos entry (jp xxxxh) c_fcb1 equ 005Ch ; first file control block c_fcb1_drive equ c_fcb1 ; drive c_fcb1_fname equ c_fcb1+01h ; filename c_fcb1_type equ c_fcb1+09h ; filetype c_fcfwseq equ 15h ; sequential write b_fnew equ 16h ; make new file b_getd equ 19h ; get default drive ; exit a = 0..15 (0=>A:) ;============================================================================== ; dbgmsg macro - display a message ;============================================================================== dbgmsg macro text local msg local jump push af ; preserve regs push bc push de push hl jr jump msg: defb text defb cr,lf,'$' jump: b1_ex equ c_fcb1+0Ch ; extent c_fcb1_s1 equ c_fcb1+0Dh ; s1 c_fbc1_s2 equ c_fcb1+0Eh ; s2 c_fcb2 equ 006Ch ; second file control block c_fcb2_drive equ c_fcb2 ; drive c_fcb2_fname equ c_fcb2+01h ; filename c_fcb2_type equ c_fcb2+09h ; filetype c_fcb2_ex equ c_fcb2+0Ch ; extent c_fcb2_s1 equ c_fcb2+0Dh ; s1 c_fbc2_s2 equ c_fcb2+0Eh ; s2 ; note c_fcb2 is overwritten if c_fcb1 is used c_iobuf equ 0080h ; default i/o buffer c_iobufsize equ 80h ; i/o buffer size c_defbuf equ 0080h ; bdos b_couts,msg ; display message pop hl ; restore regs pop de pop bc pop af endm  (0=>A:) ;============================================================================== ; dbgmsg macro - display a message ;============================================================================== dbgmsg macro text local msg local jump push af ; preserve regs push bc push de push hl jr jump msg: defb text defb cr,lf,'$' jump: ; LIBCFN.MLB auto generated from LIBCFN.MAC ; ~~~~~~~~~~ ; ; Contents: ; Z80 assembler program for CP/M. ; ; Purpose: ; Functions to manipulate CP/M filenames and FCBs ; ; Amendment History: ; 22MAR2003 RKG 1.0 Initial release. EXTRN cfntofcb ;============================================================================== ; Store a cpm filename into a fcb ; entry: de -> fcb ; hl -> cpm filename (nul or space terminated) ; exit: a = terminator of cpm filename, z flag set if nul encountere EXTRN hexa ;============================================================================== ; Display a byte in hex ; entry: a = byte to convert ; exit: a = trashed ;============================================================================== EXTRN hexhl ;============================================================================== ; Display a word in hex ; entry: hl = word to print ; exit: a = trashed ;============================================================================== d ; de -> fcb ; hl -> terminator at end of cpm filename ;============================================================================== EXTRN cfntotext ;============================================================================== ; Convert a fcb into a cpm filename ; entry: de -> fcb ; hl -> buffer to store filename ; exit: a = nul (last character transferred) ; de -> fcb ; hl -> buffer containing filename ;==============================================================================EXTRN hexmemory ;============================================================================== ; Dump memory in hex and ascii ; entry: hl = memory to print ; c = bytes to dump ; exit: all registers preserved ;============================================================================== EXTRN hexregs ;============================================================================== ; Display registers ;==============================================================================  ============ EXTRN cfntotext ;============================================================================== ; Convert a fcb into a cpm filename ; entry: de -> fcb ; hl -> buffer to store filename ; exit: a = nul (last character transferred) ; de -> fcb ; hl -> buffer containing filename ;========================================================================================================================================================= ; entry: bc = nbytes ; de = fd ; hl -> buffer ; exit: a = 0 if OK, error number if not (Z flag affected) ; bc = nbytes read, 0xFFFF if error ;============================================================================== EXTRN xtrswrite ;============================================================================== ; entry: bc = nbytes ; de = fd ; hl -> buffer ; exit: a = 0 if OK, error number if not (Z fytes read, 0xFFFF if error ;============================================================================== EXTRN xtrswrite ;============================================================================== ; entry: bc = nbytes ; de = fd ; hl -> buffer ; exit: a = 0 if OK, error number if not (Z flag affected) ; bc = nbytes read, 0xFFFF if error ;============================================================================== EXTRN xtrslseek ;================================================; LIBHFN.MLB auto generated from LIBHFN.MAC ; ~~~~~~~~~~ ; ; Contents: ; Z80 assembler program for CP/M. ; ; Purpose: ; Function to manipulate host filenames ; ; Amendment History: ; 22MAR2003 RKG 1.0 Initial Release. EXTRN hfnlower ;============================================================================== ; Set the host filename lowercase conversion flag ; entry: a = 0 keep case, else convert to lowercase ;=============================================================================; LIBHEX.MLB auto generated from LIBHEX.MAC ; ~~~~~~~~~~ ; ; Contents: ; Z80 assembler program for CP/M. ; ; Purpose: ; Hex conversion functions ; ; Amendment History: ; 22MAR2003 RKG 1.0 Initial Release. EXTRN hexaac ;============================================================================== ; Convert a byte into two hex digits ; entry: a = byte to convert ; exit: a = msn in hex ; c = lsn in hex ;============================================================================== = EXTRN hfnconvert ;============================================================================== ; Store host filename, perform case conversion if required ; entry: de -> buffer to store hfn ; hl -> source string, nul or space terminated (in uppercase) ; exit: a = last character examined (nul or space), Z flag affected ; bc = preserved ; de -> nul in buffer at end of host filename ; hl -> nul or space in original buffer at end of host filename ;============================================================================== EXTRN hfnfromfcb ;============================================================================== ; Obtain host filename from cpm fcb (ignores drive code) ; entry: de -> fcb ; hl -> buffer for host filename ; exit: a = trashed ; de -> fcb ; hl -> buffer containing host filename ;==============================================================================  ; Convert a nul terminated string to uppercase ; entry: hl -> nul terminated string ; exit: a = nul (last character examined) ; hl -> nul terminated string (converted to uppercase) ;============================================================================== EXTRN copy_hl ;============================================================================== ; Copy nul terminated string ; entry: de -> destination buffer ; hl -> source nul terminated string ; exit: a = nul (last character copied: bc = nbytes ; de = fd ; hl -> buffer ; exit: a = status: 0 if OK, error number if not (Z flag affected) ; bc = nbytes read, 0xFFFF if error ;============================================================================== EXTRN xtrswrite ;============================================================================== ; entry: bc = nbytes ; de = fd ; hl -> buffer ; exit: a = status: 0 if OK, error number if not (Z flag affected) ; bc = nbytes read, 0xFFFF if error ;=======================) ; hl -> nul at end of source ; de -> nul at end of destination ;============================================================================== EXTRN copy_de ;============================================================================== ; Copy nul terminated string ; entry: de -> source nul terminated string ; hl -> destination buffer ; exit: a = nul (last character copied) ; de -> nul at end of source ; hl -> nul at end of destination ;================================================; LIBSTR.MLB auto generated from LIBSTR.MAC ; ~~~~~~~~~~ ; ; Contents: ; Z80 assembler program for CP/M. ; ; Purpose: ; Character and string functions ; ; Amendment History: ; 22MAR2003 RKG 1.0 Initial Release. EXTRN caselc ;============================================================================== ; Convert a character to lowercase ; entry: a = character to convert ; exit: a = converted character ;============================================================================== EX============================== EXTRN nextword ;============================================================================== ; Skip word and subsequent spaces ; entry: hl -> buffer of characters to examine ; exit: a = last character examined, z flag set if nul encountered ; hl -> buffer - first character in next word ;============================================================================== EXTRN skipword ;============================================================================== TRN caseuc ;============================================================================== ; Convert a character to uppercase ; entry: a = character to convert ; exit: a = converted character ;============================================================================== EXTRN casecc ;============================================================================== ; Change case of a character ; entry: a = character to convert ; exit: a = converted character ;==============================; Skip characters until a space or a nul are encountered. ; entry: hl -> buffer of characters to skip ; exit: a = last character examined, z flag set if nul encountered ; hl -> buffer - nul or space at end of current word ;============================================================================== EXTRN skipspaces ;============================================================================== ; Skip space characters ; entry: hl -> buffer of spaces to examin ; exit: a = last character exam================================================ EXTRN casels ;============================================================================== ; Convert a nul terminated string to lowercase ; entry: hl -> nul terminated string ; exit: a = nul (last character examined) ; hl -> nul terminated string (converted to lowercase) ;============================================================================== EXTRN caseus ;============================================================================== ined, z set if nul encountered ; hl -> buffer - first non-space character ;============================================================================== EXTRN printnul ;============================================================================== ; Print a nul terminated string with bdos couts call ; Note: nul is converted to a '$' for printing and back to a nul again ; entry: hl -> buffer with nul terminated string ; exit: a trashed ;============================================================================== ============================ EXTRN printnul ;============================================================================== ; Print a nul terminated string with bdos couts call ; Note: nul is converted to a '$' for printing and back to a nul again ; entry: hl -> buffer with nul terminated string ; exit: a trashed ;================================================================================= EXTRN xtrsopen ;============================================================================== ; entry: hl -> path, nul terminated ; bc = oflag (use eo_ values defined below) ; de = mode ; exit: a = status: 0 if OK, error number if not (Z flag affected) ; de = fd, 0xFFFF if error ;------------------------------------------------------------------------------ ; eo_accmode equ 03q eo_rdonly equ 00q eo_wronly equ 01q eo_rdwr equ 02q ; eo_creat equ 0100q ; eo_excl EXTRN hfnconvert ;============================================================================== ; Store host filename, perform case conversion if required ; entry: de -> buffer to store hfn ; hl -> source string, nul or space terminated (in uppercase) ; exit: a = last character examined (nul or space), Z flag affected ; bc = preserved ; de -> nul in buffer at end of host filename ; hl -> nul or space in original buffer at end of host filename ;===============================================equ 0200q ; eo_trunc equ 01000q ; eo_append equ 02000q ; ;============================================================================== EXTRN xtrsclose ;============================================================================== ; entry: de = fd ; exit: a = status: 0 if OK, error number if not (Z flag affected) ;============================================================================== EXTRN xtrsread ;============================================================================== ; =============================== EXTRN hfnfromfcb ;============================================================================== ; Obtain host filename from cpm fcb (ignores drive code) ; entry: de -> fcb ; hl -> buffer for host filename ; exit: a = trashed ; de -> fcb ; hl -> buffer containing host filename ;============================================================================== entry: bc = nbytes ; de = fd ; hl -> buffer ; exit: a = status: 0 if OK, error number if not (Z flag affected) ; bc = nbytes read, 0xFFFF if error ;============================================================================== EXTRN xtrswrite ;============================================================================== ; entry: bc = nbytes ; de = fd ; hl -> buffer ; exit: a = status: 0 if OK, error number if not (Z flag affected) ; bc = nbytes read, 0xFFFF if error ;==================; exit: a = nul (last character copied) ; hl -> nul at end of source ; de -> nul at end of destination ;============================================================================== EXTRN copy_de ;============================================================================== ; Copy nul terminated string ; entry: de -> source nul terminated string ; hl -> destination buffer ; exit: a = nul (last character copied) ; de -> nul at end of source ; hl -> nul at end of destination ;==================================================================== EXTRN xtrslseek ;============================================================================== ; entry: bc = whence ; de = fd ; hL -> offset (8-byte little-endian integer) ; exit: a = status: 0 if OK, error number if not (Z flag affected) ; hl -> location in file, 0xFFFFFFFF if error ;============================================================================== EXTRN xtrsstrerror ;================================================; LIBXTRS.MLB auto generated from LIBXTRS.MAC ; ~~~~~~~~~~~ ; ; Contents: ; Z80 assembler program for CP/M. ; ; Purpose: ; XTRS emulator functions ; ; Amendment History: ; 22MAR2003 RKG 1.0 Initial Release. EXTRN xtrssystem ;============================================================================== ; entry: hl -> nul terminated command ; exit: a = status: 0 if OK, error number if not (Z flag affected) ; bc = command exit status ;====================================================================================== ; entry: a = error number ; bc = buffer size ; hl -> buffer for error string ; exit: a = status: 0 if OK, new error number if not (Z flag affected) ; bc = strlen(buffer), 0xFFFF if error ; hl -> same buffer, containing \r\0 terminated string ;============================================================================== EXTRN xtrsmisc ;============================================================================== ; entry: a = function code (see em_ codes defined below) ; other registers as listed below ; exit: other registers as listed below ;------------------------------------------------------------------------------ ; em_disk_change equ 0 ; disk change ; exit: hl = disk change count ; em_exit equ 1 ; exit emulator ; em_debug equ 2 ; enter debugger ; em_reset equ 3 ; press reset button ; em_modelquery equ 5 ; query model ; exit: hl = model: 1, 3, 4, or 5 (4P) ; em_graphicquery equ 10 ; query graphics type ; exit: hl = 0 (Radio Shack), is bad (z flag set) otherwise unchanged ; de -> buffer containing disk filename ;============================================================================== name ;============================================================================== ; Generate the appropriate disk filename ; entry: a = disk number '0', '1', '2', or '3' ; de -> buffer to store disk filename "diskXX-X" ; exit: a = 0 if disk number 1 (Micro Labs) ; em_graphicset equ 11 ; set graphics type ; entry: hl = 0 (Radio Shack), 1 (Micro Labs) ; em_delayquery equ 12 ; query delay ; exit: bc = autodelay flag ; hl = delay ; em_delayset equ 13 ; query set ; entry: bc = autodelay flag ; hl = delay ; ;============================================================================== EXTRN xtrserrmsg ;============================================================================== ; Display error message ; entry: a = error number ; EXPORT.MAC ; ~~~~~~~~~~ ; ; Contents: ; Z80 assembler program for CP/M. ; ; Purpose: ; Export CP/M file(s) to the host operating system. ; ; Usage: ; EXPORT [-H][-L][-T][-V] cpmfileref [hostfilename] ; ; Where: ; cpmfileref is the local file to export ; (use "?" and "*" to specify multiple files) ; hostfilename is the name of the file to create on the host ; (converted to uppercase by default), use -L to convert ; to lowercase and [ to toggle case of next character. ; -H switche; de -> text to display before error message (0=>no message) ; exit: a = preserved ; bc = trashed ; de = trashed ; hl = trashed ; notes: c_iobuf is overwritten with error message ;============================================================================== EXTRN xtrsmodel ;============================================================================== ; Obtain model name ; exit: a = 'P' for Model 4P, 0 if single character (z flag set) ; e = first character of model name '1', '3', or '4' s emulator to high speed and restores speed when done. ; -L converts hostfilename to lowercase. ; -T export text file (CR LF becomes LF, stop at SUB character). ; -V (verbose) display "r" for block read, "w" for block written. ; ; Notes: ; The CP/M CCP converts all command line parameters to uppercase, ; hence the need of the -L option and the use of [ to toggle the ; case of the next character within the hostfilename. ; ; Also, CP/M does not keep an accurate file size. Binary files ; are always;============================================================================== EXTRN xtrsrstrspd ;============================================================================== ; Restore original speed ;============================================================================== EXTRN xtrshighspd ;============================================================================== ; Switch to high speed, save current settings ;======================================================================== multiples of 128 byte blocks; text file end at the ; first sub character. ; ; There are bdos calls to locate matching file references - Find ; First and Find Next. It would be simple to uses these calls ; to find each file and export each file as it is found. Wrong! ; In the Find Next bdos call, my CP/M bible states "No other ; file operation should be done between two search requests ; because the BDOS may lose its position in the directory. In ; some version of the system this request can use ====== EXTRN xtrsnrmlspd ;============================================================================== ; Switch to normal speed, save current settings ;============================================================================== EXTRN xtrsdiskname ;============================================================================== ; Generate the appropriate disk filename ; entry: a = disk number '0', '1', '2', or '3' ; de -> buffer to store disk filename "diskXX-X" ; exit: a = 0 if disk numberused following ; Close File to find the next file after the one closed. This ; technique is not recommended". I tested this and after ; opening the first file, Find Next returns file not found. So ; I first create a list of matching files and then export each ; file in the list. A "STAT DSK:" reports that my disks can ; hold 128 directory entries. At 11 bytes a file this would ; require less than 1.5KBytes - just be careful if you have a ; hard disk with *HEAPS* of directory entries. ; ; Todo (Known Bugs): ; Export of text file will hang if sub character not detected. ; ; Amendment History: ; 22MAR03 RKG 3.0 Initial release. ; 02APR03 RKG 3.1 Re-wrote text export to fix bug when exporting text ; files that don't contain a sub character. ;############################################################################## ; Macro Libraries and External Functions ;############################################################################## MACLIB CPM.MLB MACLIB LIBCFN.MLB MACLIB Lile: $' m_nosub:: defb 'WARNING: No sub character found in text file',cr,lf,'$' ;############################################################################## ; Storage ;############################################################################## f_highspeed:: defb 0 ; 0 means normal, other values mean high f_textfile:: defb 0 ; 0 means binary, other values mean text f_verbose:: defb 0 ; 0 means quiet, other values mean verbose hostfname:: defs 128 ; host filename hostfd:: defw 0 ; IBHFN.MLB MACLIB LIBSTR.MLB MACLIB LIBXTRS.MLB ;############################################################################## ; Offset assembly so that print file matches linked output ;############################################################################## .phase 103h ;############################################################################## ; Messages ;############################################################################## m_usage:: defb cr,lf,'Export CP/M file(host file descriptor hostbuf:: defs 128 ; space for host text buffer savedchar: defb 0 ; temp char for text export filelist equ 2000h ; start of buffer for list of cpm files defs 64 ; space for the stack stack_top:: defw 0 ; stack grows down from here ;############################################################################## ; Code ;############################################################################## main:: ; set up the stack ld sp,stack_top ; check parameterss) to the host operating system.',cr,lf defb cr,lf,'Usage:' defb tab,'EXPORT [-H][-L][-T][-V] cpmfileref [hostfilename]',cr,lf defb cr,lf,'Where:' defb tab,'cpmfileref is the local file to export',cr,lf defb tab,spc,spc,spc,'(use "?" and "*" to specify multiple files).',cr,lf defb tab,'hostfilename is the name of the file to create on the host',cr,lf defb tab,spc,spc,spc,'(converted to uppercase by default), use -L to convert',cr,lf defb tab,spc,spc,spc,'to lowercase and [ to toggle ld a,(c_cmdlen) ; get length of parameters or a jp z,usage ; no parameters? ld hl,c_cmdstr ; start of command arg buffer call skipspaces jp z,usage ; only spaces? ; possible options call options ; cpm fileref jp z,no_cpmfref ; end of parameters? ld de,c_fcb1 ; fcb to fill call cfntofcb ; put cpm fname into fcb call skipspaces ; host filename (optional) jr z,exp_prep ; end of parameters? ld de,hostfname ; buffer for host filename call hfnconvecase of next character.',cr,lf defb tab,'-H switches emulator to high speed and restores speed when done.',cr,lf defb tab,'-L converts hostfilename to lowercase.',cr,lf defb tab,'-T export text file (CR LF becomes LF, stop at SUB character).',cr,lf defb tab,'-V (verbose) display "r" for block read, "w" for block written.' m_crlf:: defb cr,lf,'$' m_boption:: defb 'Invalid option "' invalid:: defb 'x"',cr,lf,'$' m_nocpmfn:: defb 'ERROR: Must specify cpmfileref',cr,lf,'$' m_nofiles:: defrt ; save hfname jr exp_prep options:: ;============================================================================== ; Process options ; entry: hl -> command line with possible options ; exit: a = last character examined (z flag affected) ; hl -> next character in command line ;============================================================================== ; optional options ld a,(hl) or a ret z ; nul? end of options cp '-' ret nz ; not an options? ; have options b 'Sorry, no files to export',cr,lf,'$' m_hfnign:: defb 'WARNING: Multiple matching files' defb ' - ignoring specified hostfilename',cr,lf,'$' m_arrow:: defb ' -> $' m_copen:: defb 'ERROR: Unable to open CP/M file',cr,lf,'$' m_cread:: defb 'ERROR: Unable to read CP/M file',cr,lf,'$' m_cclose:: defb 'ERROR: Unable to close CP/M file',cr,lf,'$' m_uopen:: defb 'ERROR: Unable to open HOST file: $' m_uwrite:: defb 'ERROR: Unable to write HOST file: $' m_uclose:: defb 'ERROR: Unable to close HOST f inc hl ld a,(hl) opt_next: call opt_action ; process option ; check for more options inc hl ld a,(hl) or a ret z ; nul? end of options cp spc jr nz,opt_next ; more options in this group? call skipspaces jr options ; check for next group of options opt_action: ; process option call caseuc ; make case-insensitive cp 'H' jr z,opt_h cp 'L' jr z,opt_l cp 'T' jr z,opt_t cp 'V' jr z,opt_v ; invalid option ld (invalid),a bdos b_couts,m_boption jp usage opt_h: ; "-H" switch to high speed ld a,1 ld (f_highspeed),a ; set speed flag ret opt_l: ; "-L" convert host filename to lowercase ld a,1 call hfnlower ; set hfname lowercase flag ret opt_t: ; "-T" transfer text file (cr lf -> lf, end at sub) ld a,1 ld (f_textfile),a ; set text file flag ret opt_v: ; "-V" verbose ld a,1 ld (f_verbose),a ; set verbose flag ret no_cpmfref:: ;============================================================ny:: ;============================================================================== ; Export multiple files ; entry: (hostfname) contains possible host filename ; (filelist) contains cpm filename ;============================================================================== ; was a hfname specified? ld a,(hostfname) or a jr z,do_many ; no hfname? ; have irrelevant hfname bdos b_couts,m_hfnign do_many: ; initialise pointer to list of files to export ld hl,filelist do_m================== ; CP/M filename not specified ;============================================================================== bdos b_couts,m_nocpmfn ; fall thru usage:: ;============================================================================== ; Display program usage ; exit: does not return ;============================================================================== bdos b_couts,m_usage ; fall thru done:: ;==================================================================any1: ; test for last file ld a,(hl) or a jr z,exp_done ; load fcb with filename from list call listtofcb ; save position in filelist push hl ; save pos in file list ; convert fcb to host filename ld de,c_fcb1 ld hl,hostfname call hfnfromfcb ; store hfname from fcb ; perform the export call export ; restore position in file list pop hl ; around again jr do_many1 exp_done:: ;================================================================================= ; Single exit point of program ;============================================================================== jp c_boot exp_prep:: ;============================================================================== ; Determine how many files to export and act accordingly ;============================================================================== ; switch speed if necessary, remember current settings ld a,(f_highspeed) or a call nz,xtrshighspd ; make list of files to========= ; Export complete ;============================================================================== ; restore speed setting ld a,(f_highspeed) or a call nz,xtrsrstrspd ; finish jp done export:: ;============================================================================== ; Export a file ; entry: (c_fcb1) contains cpm file details ; (hostfname) contains unix filename ;============================================================================== ; print details export call listbuild ; bc contains count of files to export ; check count of files to export ld a,b or c jp z,exp_none ; no files to export? dec bc ld a,b or c jp z,exp_one ; only 1 file to export? jp exp_many ; more than 1 file to export exp_none:: ;============================================================================== ; No files to export ;============================================================================== bdos b_couts,m_nofiles jp exp_do ld hl,c_iobuf ; temporary buffer for cpm filename ld de,c_fcb1 call cfntotext call printnul ; cpm filename bdos b_couts,m_arrow ; arrow ld hl,hostfname call printnul ; host filename bdos b_couts,m_crlf ; open local file call copen ret nz ; open host file call uopen ret nz ; export ld a,(f_textfile) or a jr z,exp_binary exp_text: call text jr exp_finish exp_binary: call binary ; fall thru exp_finish: ; export complete ld e,cr cane exp_one:: ;============================================================================== ; Export one file ; entry: (hostfname) contains possible host filename ; (filelist) contains cpm filename ;============================================================================== ; check for a hfname ld a,(hostfname) or a jr z,do_many ; no hfn, treat as multiple files ; fetch the cpm filename ld hl,filelist call listtofcb ; export it call export jp exp_done exp_mall verbose ld e,lf call verbose ; close local file ; not really necessary for read-only files call cclose ; close host file call uclose ret binary:: ;============================================================================== ; Export a binary file ; entry: (c_fcb1) contains an open CP/M file ; (hostfd) contains an open host file ; during: hl -> host buffer ; de -> cpm buffer ; b = bytes available in host buffer ; c = bytes remaining in cp/m buffer ; exit: a = 0 indicates a successful export (z flag set) ; all other registers trashed ; note: binary files are always multiples of 128 byte blocks ;============================================================================== ld de,c_iobuf ; all i/o thru cp/m io buffer ld hl,c_iobuf ; all i/o thru cp/m io buffer binary1: ; read block from local file call cread jr nz,binary2 ; eof or error ; write block to host file ld b,c ; bytes in buffer call uwrite ret nz ; error ountered while writing to host file ret ;############################################################################## ; File list functions ;############################################################################## listbuild:: ;============================================================================== ; Build a list of filenames to export ; entry: (c_fcb1) contains fileref ; exit: bc = count of matching files ; all other registers trashed ;======================================= jr binary1 binary2: ; eof or error during read (1=>eof) dec a ; 0=eof ret z ; eof? inc a ; restore ret text:: ;============================================================================== ; Export a text file ; entry: (c_fcb1) contains an open CP/M file ; (hostfd) contains an open host file ; during: hl -> host buffer ; de -> cpm buffer ; b = bytes available in host buffer ; c = bytes remaining in cp/m buffer ; exit: a = 0 indicates a successful export (z flag======================================= bdos b_ffirst,c_fcb1 ; find first matching file ld de,filelist ; point to area for next entry in list ld bc,0 listbuild1: ; check for file not found or a ; not found if a=FFh jp m,listbuild2 ; we have a matching file ; a=0,1,2,3 file number in buffer sla a ; a=0,2,4,6 sla a ; a=0,4,8,12 sla a ; a=0,8,16,24 sla a ; a=0,16,32,48 sla a ; a=0,32,64,96 offset in buffer inc bc ; bump count push bc ; save set) ; all other registers trashed ; note: convert cr lf to lf and stop at sub character ;============================================================================== ld hl,hostbuf ; host buffer ld b,c_iobufsize ; empty ld de,c_iobuf ; cp/m buffer ld c,0 ; empty textloop: ; fetch character call cgetc ; fetch character jr nz,textierr ; error or eof? ; cr? cp cr call z,textcr ; cr? ; sub? cp sub ; sub is eof for text file jr z,texteof ; eof? ; count ; copy name and type (ignore drive) ld b,0 ld c,a ; bc=offset ld hl,c_defbuf add hl,bc inc hl ; first char of filename ld bc,11 ; length of filename & type ldir ; copy it ; find next matching file push de bdos b_fnext,c_fcb1 pop de pop bc ; restore count jr listbuild1 listbuild2: ; append a null file to list. xor a ld (de),a ret listtofcb:: ;============================================================================== ; entrysave character call uputc jr nz,textoerr ; error? jr textloop texteof: ; sub encountered call uflush xor a ; clear z flag ret textcr: ; cr in cp/m file ; fetch next character call cgetc ; fetch character jr nz,textcr1 ; error or eof? ; cr followed by lf? cp lf ret z ; output just the lf ; cr followed by other character ld (savedchar),a ; save character ld a,cr call uputc ; output cr jr nz,textcr2 ; error? ld a,(savedchar) ret : hl -> file in list ; exit: a = nul ; bc = trashed ; de = trashed ; hl -> next file in list ;============================================================================== ; load fcb with filename from list ld de,c_fcb1_fname ; destination ld bc,11 ; length of filename & type ldir ; zero remainder of fcb xor a ld b,24 do_many2: ld (de),a inc de djnz do_many2 ret ;############################################################################## ; CP/M file routin ; output the other character textcr1: ; eof or error encountered while reading cpm file pop de ; remove return address jr textierr textcr2: ; error encountered while writing to host file pop de ; remove return address jr textoerr textierr: ; eof or error encountered while reading cpm file push af call uflush pop af cp 1 ; eof jr nz,textierr1 ; error? (wasn't eof) bdos b_couts,m_nosub textierr1: xor a dec a ret ; ret nz textoerr: ; error ences ;############################################################################## copen:: ;============================================================================== ; open the cp/m filename in fcb1 ; entry: (c_fcb1) contains cp/m fcb ; exit: a = 0 indicates a successful open (z flag set) ; all other registers trashed ;============================================================================== bdos b_fopen,c_fcb1 ; open existing file (a=FFh is error) or a jp m,copenerr xor a ret ; open ok copenerr: bdos b_couts,m_copen ; error message xor a dec a ret ; ret nz cread:: ;============================================================================== ; read a block from the cp/m file ; entry: (c_fcb1) contains the cp/m fcb ; de -> start of cpm buffer ; exit: a = 0 indicates a successful read (z flag set) ; b = preserved ; c = bytes in cpm buffer ; de -> start of cpm buffer ; hl = preserved ;==================================================successful open ; (hostfd) contains host file descriptor ; all registers trashed. ;============================================================================== ld hl,hostfname ld bc,eo_wronly+eo_creat+eo_trunc ld de,0666q ; permissions call xtrsopen ld (hostfd),de ; save host fd ret z ; ok ; display error message ld de,m_uopen jp xtrserrmsg uwrite:: ;============================================================================== ; write a block to the host file ; ============================ ; preserve regs push bc push de push hl ; display actions ld e,'r' call verbose ; preform read bdos b_frseq,c_fcb1 ; a=0 is ok, a=1 is eof ; restore regs pop hl pop de pop bc ; full buffer ld c,c_iobufsize or a ; set flags ret z ; ok ; eof? cp 1 ; eof jr nz,creaderr ; not eof? or a ; set flags ret ; ret nz creaderr: ; display error message bdos b_couts,m_cread ; error message xor a entry: hl -> start of buffer ; b = contains the number of bytes to write ; (hostfd) contains host file descriptor ; exit: f = z indicates sucessful write ; af trashed (bc,de,hl saved) ;============================================================================== ; preserve regs push bc push de push hl ; perform write ld c,b ; length in bc ld b,0 ld de,(hostfd) ; get host fd call xtrswrite ; show action ld e,'w' call verbose ; restore regs pop hl dec a ret ; ret nz cgetc:: ;============================================================================== ; get a character from the cp/m file ; entry: c = bytes remaining in cp/m buffer ; de -> position in cpm buffer ; exit: a = character ; f = z indicates get ok, nz indicates error or eof ; c = bytes remaining in cp/m buffer ; de -> position in cpm buffer ;============================================================================== ld a,c or a jr nz,cgetc1 ; stil pop de pop bc ; empty buffer ld b,c_iobufsize ; empty ret z ; ok ; display error message ld de,m_uwrite jp xtrserrmsg uputc:: ;============================================================================== ; put a character into the host file ; entry: a = character to put ; b = bytes free in host buffer ; hl -> position in host buffer ; exit: f = z indicates ok, nz indicates error ;============================================================================== l have data in buffer ld de,c_iobuf ; cp/m buffer call cread ; bytes read in c ret nz cgetc1: dec c ; dec characters remaining xor a ; set z flag ld a,(de) ; fetch inc de ; bump pointer ret cclose:: ;============================================================================== ; close the cp/m filename in fcb1 ; entry: (c_fcb1) contains cp/m fcb ; exit: z indicates a sucessful close ; all registers trashed ;==================================================== ld (hl),a ; store inc hl ; bump pointer dec b ; dec bytes free ld a,b or a jr z,uputcfull ; buffer full xor a ret ; ret z uputcfull: ld hl,hostbuf ; reset pointer and counter ld b,c_iobufsize ; bytes to write call uwrite ret uflush:: ;============================================================================== ; flush host buffer ; entry: b = bytes free in host buffer ; hl -> position in host buffer ; exit: f = z indicates ok, nz indicates error ;========================== bdos b_fclose,c_fcb1 ret z ; display error message bdos b_couts,m_cclose xor a dec a ret ; ret nz ;############################################################################## ; Host file routines ;############################################################################## uopen:: ;============================================================================== ; open host file ; entry: (hostfname) contains host file name ; exit: z indicates ============================================================================== ; anything in host buffer ld a,c_iobufsize sub b ; a has bytes used in host buffer ret z ; buffer empty ; flush host buffer ld hl,hostbuf ; buffer start ld b,a ; bytes to write call uwrite ret uclose:: ;============================================================================== ; close the host file ; entry: (hostfd) contains host file descriptor ; exit: z indicates a sucessful close ; all registers trashed ;============================================================================== ld de,(hostfd) ; get host fd call xtrsclose ret z ; ok ; display error message ld de,m_uclose jp xtrserrmsg ;############################################################################## ; Verbose ;############################################################################## verbose:: ;============================================================================== ; Disilename will be ; assumed to have the same name. ; ; Also note that the CP/M CCP converts all command line arguments to ; uppercase, therefore if hostfilename is specified on the command ; line then it will be taken as all uppercase. ; ; Amendment History: ; 27MAR03 RKG 2.0 Initial release. ;############################################################################## ; Macro Libraries and External Functions ;############################################################################## MACplay a character if verbose ; entry: e = character to display ; exit: af = preserved ; bc = trashed ; de = trashed ; hl = trashed ;============================================================================== push af ld a,(f_verbose) or a jr z,verbose1 bdos b_coutb verbose1: pop af ret ;############################################################################## ; End ;############################################################################## end:: end main LIB CPM.MLB MACLIB LIBCFN.MLB MACLIB LIBHFN.MLB MACLIB LIBSTR.MLB MACLIB LIBXTRS.MLB ;############################################################################## ; Offset assembly so that print file matches linked output ;############################################################################## .phase 103h ;############################################################################## ; Messages ;#############################################################################  hl = trashed ;============================================================================== push af ld a,(f_verbose) or a jr z,verbose1 bdos b_coutb verbose1: pop af ret ;############################################################################## ; End ;############################################################################## end:: end main # m_usage: defb cr,lf,'Usage:',tab defb 'IMPORT [-F][-H][-L][-T][-V] hostfilename [cpmfilename]' m_crlf: defb cr,lf,'$' m_boption:: defb 'Invalid option "' invalid:: defb 'x"',cr,lf,'$' m_nohfname:: defb 'ERROR: Must specify hostfilename',cr,lf,'$' m_arrow:: defb ' -> $' m_uopen: defb 'ERROR: Unable to open HOST file: $' m_uread: defb 'ERROR: Unable to read HOST file: $' m_uclose: defb 'ERROR: Unable to close HOST file: $' m_cexists: defb 'ERROR: CP/M file already exists',cr,lf,'$' m_usage: defb cr,lf,'Usage:',tab defb 'IMPORT [-F][-H][-L][-T][-V] hostfilename [cpmfilename]' m_crlf: defb cr,lf,'$' m_boption:: defb 'Invalid option "' invalid:: defb 'x"',cr,lf,'$' m_nohfname:: defb 'ERROR: Must specify hostfilename',cr,lf,'$' m_arrow:: defb ' -> $' m_uopen: defb 'ERROR: Unable to open HOST file: $' m_uread: defb 'ERROR: Unable to read HOST file: $' m_uclose: defb 'ERROR: Unable to close HOST file: $' m_cexists: defb 'ERROR: CP/M file already exists',cr,lf,'$' m_copen: defb 'ERROR: Unable to open CP/M file',cr,lf,'$' m_cwrite: defb 'ERROR: Unable to write CP/M file',cr,lf,'$' m_cclose: defb 'ERROR: Unable to close CP/M file',cr,lf,'$' ;############################################################################## ; Storage ;############################################################################## f_overwrite:: defb 0 ; 0 means preserve, others mean overwrite f_textfile:: defb 0 ; 0 means binary, other values mean text f_highspeed:: defb 0 ; ; IMPORT.MAC ; ~~~~~~~~~~ ; ; Contents: ; Z80 assembler program for CP/M. ; ; Purpose: ; Import a file from host into the xtrs emulator. ; ; Usage: ; IMPORT [-F][-H][-L][-T][-V] hostfilename [cpmfilename] ; ; Where: ; -n converts host lf to CP/M cr lf; ; hostfilename - name of the host file to import; and ; cpmfilename - name of the file in CP/M (must not exist); ; ; Notes: ; When started with no arguments, import will prompt for all args. ; If only the hostfilename is specified, the cpmf0 means normal, other values mean high f_verbose:: defb 0 ; 0 means quiet, other values mean verbose hostfname:: defs 128 ; host filename hostfd:: defw 0 ; host file descriptor hostbuf:: defs 128 ; space for host text buffer defs 32 ; space for the stack stack_top:: defw 0 ; stack grows down from this (wasted) ;############################################################################## ; Code ;############################################################################## main:: ; set up the stack ld sp,stack_top ; check parameters ld a,(c_cmdlen) ; get length of parameters or a jp z,usage ; no parameters? ld hl,c_cmdstr ; start of command arg buffer call skipspaces jp z,usage ; only spaces? ; possible options call options ; host filename jp z,no_hfname ; end of paramters ld de,hostfname ; buffer for host filename call hfnconvert ; save hfname call skipspaces ; cpm filename (optional) jr z,mkcpmname ; end of paramet-------------- bdos b_couts,m_nohfname ; fall thru usage:: ;============================================================================== ; Display program usage ; exit: does not return ;============================================================================== bdos b_couts,m_usage ; fall thru done:: ;============================================================================== ; Single exit point of program ;====================================================================ers? ld de,c_fcb1 ; buffer for cpm filename call cfntofcb ; put cpm filename into fcb jp import mkcpmname: ; make cpm filename from host filename ld hl,hostfname ; examine host filename ld de,c_fcb1 ; buffer for cpm filename call cfntofcb ; put filename into fcb jp import options:: ;------------------------------------------------------------------------------ ; Process options ; entry: hl -> command line with possible options ; exit: a = last character examined (z fl========== jp c_boot import:: ;============================================================================== ; Import a file ; entry: (hostfname) contains unix filename ; (c_fcb1) contains cpm file details ;============================================================================== ; print details ld hl,hostfname call printnul ; host filename bdos b_couts,m_arrow ld hl,c_iobuf ; temporary buffer for cpm filename ld de,c_fcb1 call cfntotext call printnul ; cpm fileag affected) ; hl -> next character in command line ;------------------------------------------------------------------------------ ; optional options ld a,(hl) or a ret z ; nul? end of options cp '-' ret nz ; not an options? ; have options inc hl ld a,(hl) opt_next: call opt_action ; process option ; check for more options inc hl ld a,(hl) or a ret z ; nul? end of options cp spc jr nz,opt_next ; more options in this group? call skipspaces name bdos b_couts,m_crlf ; open host file call uopen jp nz,done ; open local file call copen jp nz,done ; import ld a,(f_textfile) or a jr z,imp_binary imp_text: call text jr imp_finish imp_binary: call binary ; fall thru imp_finish: ; import complete ld e,cr call verbose ld e,lf call verbose ; close host file call uclose ; close local file call cclose jp done binary: ;==================================================== jr options ; check for next group of options opt_action: ; process option call caseuc ; make case-insensitive cp 'F' jr z,opt_f cp 'H' jr z,opt_h cp 'L' jr z,opt_l cp 'T' jr z,opt_t cp 'V' jr z,opt_v ; invalid option ld (invalid),a bdos b_couts,m_boption jp usage opt_f: ; "-F" overwrite exisiting file ld a,1 ld (f_overwrite),a ; set overwrite flag ret opt_h: ; "-H" switch to high speed ld a,1 ld (f_highspeed),a ; set speed flag re========================== ; import a binary file ; exit: z indicates a successful import ; all registers trashed ;============================================================================== ld hl,c_iobuf ; all io thru cp/m io buffer call uread ; length in b ; check for zero length read ld a,b or a ; set flags ret z ; nothing to write, must be finished push bc ; save length cp c_iobufsize jr z,binary2 ; full block ; partial block - pad with nuls ldt opt_l: ; "-L" convert host filename to lowercase ld a,1 call hfnlower ; set hfname lowercase flag ret opt_t: ; "-T" transfer text file (cr lf -> lf, end at sub) ld a,1 ld (f_textfile),a ; set text file flag ret opt_v: ; "-V" verbose ld a,1 ld (f_verbose),a ; set verbose flag ret no_hfname:: ;------------------------------------------------------------------------------ ; Host filename not specified ;---------------------------------------------------------------- c,b ld b,0 add hl,bc ; point to garbage ld a,c_iobufsize sub b ; a has number bytes to nul binary1: jr z,binary2 ld (hl),nul inc hl dec a jr binary1 ; write cpm block binary2: call cwrite pop bc ; restore length ret nz ; check if file complete binary3: ld a,b ; check length cp c_iobufsize jr z,binary ; full read, read more ; partial read must be last read, fall thru... xor a ; set zero flag ret text: ;============================================================================== ; import an text file (convert lf to cr lf and add sub at end) ; during: (hl) host buffer ; (de) cpm buffer ; b bytes remaining in host buffer ; c bytes remaining in cp/m buffer ; exit: z indicates a successful export ; all registers trashed ;============================================================================== ; setup cpm buffer ld de,c_iobuf ld c,c_iobufsize ; read a block from host file text1: ld hl,hostbuf ====================================================== ; preserve regs push bc push de push hl ; perform write bdos b_fwseq,c_fcb1 ; display action push af ld e,'w' call verbose pop af ; restore regs pop hl pop de pop bc ret z ; display error message bdos b_couts,m_cwrite xor a dec a ret ; ret nz cclose: ;============================================================================== ; close the cp/m filename in fcb1 ; entry: (c_fcb1 call uread ret nz ld a,b or a jr z,text4 ; nothing was read ; scan thru all bytes in host buffer text2: ld a,(hl) cp lf jr nz,text3 ld a,cr call textput ld a,lf text3: call textput inc hl djnz text2 jr text1 text4: ; end of file reached ld a,sub ; add a sub character call textput ld a,c cp c_iobufsize ret z ; cp/m buffer was already written ; fill cpm buffer with nul chars ld b,c ld a,nul text5: ld (de),a inc de dj) contains cp/m fcb ; exit: z indicates a sucessful close ; all registers trashed ;============================================================================== bdos b_fclose,c_fcb1 ret z ; display error message bdos b_couts,m_cclose xor a dec a ret ; ret nz ;############################################################################## ; Host file routines ;############################################################################## uopen:: ;=========================nz text5 call cwrite ; write last cp/m buffer ret ; put a character into the cp/m buffer textput: ld (de),a inc de ; bump pointer dec c ; dec count ld a,c or a ret nz ; buffer not full yet call cwrite ld de,c_iobuf ; reset pointer and counter ld c,c_iobufsize ret ;############################################################################## ; CP/M file routines ;############################################################################## copen:: ;===================================================== ; open host file ; entry: (hostfname) start of host filename ; exit: z indicates successful open ; (hostfd) contains host file descriptor ; all registers trashed. ;============================================================================== ld hl,hostfname ld bc,eo_rdonly ld de,0 ; permissions call xtrsopen ld (hostfd),de ; save host fd ret z ; ok ; display error message ld de,m_uopen jp xtrserrmsg uread:: ;============================================================================== ; open the cp/m filename in fcb1 ; entry: (c_fcb1) contains cp/m fcb ; exit: z indicates a successful open ; af,bd,de,hl trashed ;============================================================================== ld a,(f_overwrite) or a jr nz,copen1 ; overwrite bdos b_fopen,c_fcb1 ; open existing file (a=0ffh is error) inc a jr z,copen1 ; file doesn't exist (good) bdos b_fclose,c_fcb1 ; close the exis============================================================================== ; read a block from the host file ; entry: (hl) start of buffer (c_iobufsize length) ; (hostfd) contains host file descriptor ; exit: z indicates sucessful read ; b contains number of bytes read ; af trashed (c,de,hl saved) ;============================================================================== ; preserve regs push hl push de push bc ; show action ld e,'r' call verbose ; perform readting file bdos b_couts,m_cexists xor a dec a ret ; ret nz copen1: bdos b_fnew,c_fcb1 ; make new file (a=0FFh is error) inc a jp z,copen2 xor a ret copen2: bdos b_couts,m_copen xor a dec a ret ; ret nz cwrite:: ;============================================================================== ; write a block to the cp/m file ; entry: (c_fcb1) contains the cp/m fcb ; exit: z indicates a successful write ; af trashed (bc,de,hl saved) ;======================== ld bc,c_iobufsize ; length ld de,(hostfd) ; get host fd call xtrsread ; bytes read in bc but since iobufsize is only 0x80h ; bytes, the c register will contains the full count ; restore regs ld d,c ; save count in d pop bc ; recover contents of bc ld b,d ; count now in b pop de pop hl ret z ; display error message ld de,m_uread jp xtrserrmsg uclose:: ;============================================================================== ; close the host file ; entry: (hostfd) contains host file descriptor ; exit: z indicates a sucessful close ; all registers trashed ;============================================================================== ld de,(hostfd) ; get host fd call xtrsclose ret z ; ok ; display error message ld de,m_uclose jp xtrserrmsg ;############################################################################## ; Verbose ;############################################################################## verbdrive ld (de),a jr cfntofcb2 cfntofcb1: ; drive specified ld a,(hl) call caseuc ; ensure uppercase sub 'A'-1 ; 'A' becomes 1, 'B' becomes 2, etc. ld (de),a ; store drive code inc hl ; skip over the ':' inc hl cfntofcb2: inc de ; skip drive code ; name ld b,8 call cgetname ; 8 char name ; type ld b,3 call cgetname ; 3 char type ; zero remainder of fcb ld a,0 ld b,24 cfntofcb3: ld (de),a inc de djnz cfntofcb3 cfntofcb4: ; eaose:: ;============================================================================== ; Display an 'r' if verbose ; entry: e = character to display ; exit: af = preserved ; bc = trashed ; de = trashed ; hl = trashed ;============================================================================== push af ld a,(f_verbose) or a jr z,verbose1 bdos b_coutb verbose1: pop af ret ;############################################################################## ; End ;##########; LIBCFN.MAC ; ~~~~~~~~~~ ; ; Contents: ; Z80 assembler program for CP/M. ; ; Purpose: ; Functions to manipulate CP/M filenames and FCBs ; ; Amendment History: ; 22MAR2003 RKG 1.0 Initial release. ;############################################################################## ; Macro Libraries and External Functions ;############################################################################## MACLIB CPM.MLB MACLIB LIBSTR.MLB ;############################################################################################################################ end:: end main  = character to display ; exit: af = preserved ; bc = trashed ; de = trashed ; hl = trashed ;============================================================================== push af ld a,(f_verbose) or a jr z,verbose1 bdos b_coutb verbose1: pop af ret ;############################################################################## ; End ;################################ ; Start ;############################################################################## cfn_start:: defb 'LIBCFN',nul ;############################################################################## ; Code ;############################################################################## cfntofcb:: ;============================================================================== ; Store a cpm filename into a fcb ; entry: de -> fcb ; hl -> cpm filename (nul or space termina################## ; Start ;############################################################################## cfn_start:: defb 'LIBCFN',nul ;############################################################################## ; Code ;############################################################################## cfntofcb:: ;============================================================================== ; Store a cpm filename into a fcb ; entry: de -> fcb ; hl -> cpm filename (nul or space terminated)ted) ; exit: a = terminator of cpm filename, z flag set if nul encountered ; de -> fcb ; hl -> terminator at end of cpm filename ;============================================================================== push bc push de ; drive (optional) inc hl ; test 2nd character ld a,(hl) dec hl ; back to the start cp ':' ; a ':' indicates a drive jr z,cfntofcb1 ; found a ':', must be a drive code ; drive not specified - use current drive xor a ld (de),a jr cfnto ; exit: a = terminator of cpm filename, z flag set if nul encountered ; de -> fcb ; hl -> terminator at end of cpm filename ;============================================================================== push bc push de ; drive (optional) inc hl ; test 2nd character ld a,(hl) dec hl ; back to the start cp ':' ; a ':' indicates a drive jr z,cfntofcb1 ; found a ':', must be a drive code ; drive not specified - use current drive ld a,0 ; zero indicates current fcb2 cfntofcb1: ; drive specified ld a,(hl) call caseuc ; ensure uppercase sub 'A'-1 ; 'A' becomes 1, 'B' becomes 2, etc. ld (de),a ; store drive code inc hl ; skip over the ':' inc hl cfntofcb2: inc de ; skip drive code ; name ld b,8 call cgetname ; 8 char name ; type ld b,3 call cgetname ; 3 char type ; zero remainder of fcb xor a ld b,24 cfntofcb3: ld (de),a inc de djnz cfntofcb3 cfntofcb4: ; eat any extra characters after filename ld a,(hl) or a jr z,cfntofcb5 ; nul? cp spc jr z,cfntofcb5 ; space? inc hl jr cfntofcb4 ; again cfntofcb5: ; set flags or a pop de pop bc ret cgetname: ;------------------------------------------------------------------------------ ; Transribe bytes and pad with spaces until a nul, space, or a '.' found ; entry: b = bytes to transribe/pad ; de -> destination ; hl -> source ; exit: a = last character examined ; de -> next byte in destination ,ncopyskip ; space? ld (hl),a ; store inc de ; bump inc hl djnz ncopy ; again ret ncopyskip: ; skip remainder of fcb until b becomes 0 inc de djnz ncopyskip ret ;############################################################################## ; End ;############################################################################## cfn_end:: end  ; hl -> next byte in source (nul or space), or byte after '.' ;------------------------------------------------------------------------------ ld a,(hl) ; fetch cp nul jr z,cgetshort ; nul? cp spc jr z,cgetshort ; space? cp '.' jr z,cgetshort ; '.'? cp '*' jr z,cgetwild ; '*'? call caseuc ; uppercase ld (de),a ; store inc hl ; bump inc de djnz cgetname ; again ; fall thru cgetskip: ; eat extra chars in source ; stop on nul or space, stop after push af push bc push de push hl ld e,a bdos b_coutb pop hl pop de pop bc pop af ret hex_msn: ;------------------------------------------------------------------------------ ; Convert most significant nibble of a byte to hex ; entry: a = byte to convert ; exit: a = hex character of msn of byte ;------------------------------------------------------------------------------ srl a srl a srl a srl a ; fall thru hex_lsn: ;--------------------------'.' ld a,(hl) ; fetch cp nul ret z ; nul? cp spc ret z ; space? inc hl ; bump cp '.' ret z ; '.'? jr cgetskip ; again cgetshort: ; pad fcb with spaces ld a,spc call cgetfill jr cgetskip cgetwild: ; '*' encountered inc hl ; skip over the '*' ; fill remainder of destination with '?' ld a,'?' call cgetfill jr cgetskip cgetfill: ; fill remainder of destination with character in a reg ld (de),a inc de djnz cgetfill ret ---------------------------------------------------- ; Convert least significant nibble of a byte to hex ; entry: a = byte to convert ; exit: a = hex character of lsn of byte ;------------------------------------------------------------------------------ and 0Fh ; mask cp 0Ah jr c,hex_c ; less than 10 add a,'A'-3Ah hex_c: add a,'0' ret hexaac:: ;============================================================================== ; Convert a byte into two hex digits ; entry: a =cfntotext:: ;============================================================================== ; Convert a fcb into a cpm filename ; entry: de -> fcb ; hl -> buffer to store filename ; exit: a = nul (last character transferred) ; de -> fcb ; hl -> buffer containing filename ;============================================================================== push bc push de push hl ; possible drive code ld a,(de) or a jr z,cpmcname ; drive code add a,'A'-1 ; 1=>A, 2=>B l; LIBHEX.MAC ; ~~~~~~~~~~ ; ; Contents: ; Z80 assembler program for CP/M. ; ; Purpose: ; Hex conversion functions ; ; Amendment History: ; 22MAR2003 RKG 1.0 Initial Release. ;############################################################################## ; Macro Libraries ;############################################################################## MACLIB CPM.MLB ;############################################################################## ; Start ;#################################d (hl),a inc hl ld (hl),':' inc hl cpmcname: inc de ; skip over drive code ; name ld b,8 call ncopy ; possible type ld a,(de) and 7Fh ; strip high bit cp spc jr z,cpmterm ; no type? ld (hl),'.' inc hl ; type ld b,3 call ncopy cpmterm: ; terminate ld a,nul ld (hl),a pop hl pop de pop bc ret ncopy: ; transcribe characters until a space or b becomes 0 ld a,(de) ; fetch and 7Fh ; strip high bit cp spc jr z############################################# hex_start:: defb 'LIBHEX',nul ;############################################################################## ; Code ;############################################################################## cout: ;------------------------------------------------------------------------------ ; Display a character ; extry: a = character to display ; exit: all registers preserved ;------------------------------------------------------------------------------ push af push bc push de push hl ld e,a bdos b_coutb pop hl pop de pop bc pop af ret coutprn: ;------------------------------------------------------------------------------ ; Display a character (unprintable characters displayed as '.') ; extry: a = character to display ; exit: all registers preserved ;------------------------------------------------------------------------------ push af and 7Fh ; strip high bit cp spc jr nc,coutprn1 ld a,'.; exit: all registers preserved ;============================================================================== push af push bc push de push hl hexaddr: push bc ; save count push hl ; save start address for ascii dump ; address call hexhl ; a colon ld a,':' call cout ; 16 bytes in hex ld b,16 hexhex: ld a,spc ; space before each hex byte call cout ld a,c or a jr nz,hexhex1 ; no more data to dump? ld a,spc ; dump spaces not hex call co' ; replace unprintable characters coutprn1: call cout pop af ret hexmsn: ;------------------------------------------------------------------------------ ; Convert most significant nibble of a byte to hex ; entry: a = byte to convert ; exit: a = hex character of msn of byte ;------------------------------------------------------------------------------ srl a srl a srl a srl a ; fall thru hexlsn: ;-------------------------------------------------------------------------ut call cout jr hexhex2 hexhex1: ld a,(hl) ; dump hex call hexa dec c hexhex2: inc hl ; bump djnz hexhex ; again ; a space ld a,spc call cout ; back to starting values pop hl ; restore start address pop bc ; restore count ; 16 bytes in ascii ld b,16 hexchr: ld a,c or a jr nz,hexchr1 ld a,spc ; dump space not ascii call cout call cout jr hexchr2 hexchr1: ld a,(hl) call coutprn dec c hexchr2: inc hl ; bump djnz hex----- ; Convert least significant nibble of a byte to hex ; entry: a = byte to convert ; exit: a = hex character of lsn of byte ;------------------------------------------------------------------------------ and 0Fh ; mask cp 0Ah jr c,hexlsn1 ; less than 10 add a,'A'-3Ah hexlsn1: add a,'0' ret hexaac:: ;============================================================================== ; Convert a byte into two hex digits ; entry: a = byte to convert ; exit: a = msn in hex chr ; cr lf ld a,cr call cout ld a,lf call cout ; more to dump? ld a,c or a jr nz,hexaddr ; more? pop hl pop de pop bc pop af ret hexregs:: ;============================================================================== ; Display registers ;============================================================================== push af push bc push de push hl ; label push af ld a,'R' call cout ld a,'E' call cout ld a,'G' call co ; c = lsn in hex ;============================================================================== push af call hexlsn ld c,a ; lsn into c pop af call hexmsn ; msn into a ret hexa:: ;============================================================================== ; Display a byte in hex ; entry: a = byte to convert ; exit: a = trashed ;============================================================================== push af call hexmsn call cout pop af call hexlut ld a,'S' call cout ld a,':' call cout pop af ; a push de ld e,'A' call coutlbl pop de push af call hexa ld a,' ' call cout pop af call coutprn ; bc push de ld e,'B' call coutlbl pop de push hl push bc ; ld hl,bc pop hl call hexhl pop hl ; bc push de ld e,'D' call coutlbl pop de push hl push de ; ld hl,de pop hl call hexhl pop hl ; hl ld e,'H' call coutlbl call hexhl ; cr lf sn call cout ret hexhl:: ;============================================================================== ; Display a word in hex ; entry: hl = word to print ; exit: a = trashed ;============================================================================== ld a,h call hexa ld a,l call hexa ret hexmemory:: ;============================================================================== ; Dump memory in hex and ascii ; entry: hl = memory to print ; c = bytes to dump ld a,cr call cout ld a,lf call cout pop hl pop de pop bc pop af ret coutlbl: push af push bc push de push hl push de ld e,spc bdos b_coutb pop de bdos b_coutb ld e,'=' bdos b_coutb pop hl pop de pop bc pop af ret ;############################################################################## ; End ;############################################################################## hex_end:: end ; LIBHFN.MAC ; ~~~~~~~~~~ ; ; Contents: ; Z80 assembler program for CP/M. ; ; Purpose: ; Function to manipulate host filenames ; ; Amendment History: ; 22MAR2003 RKG 1.0 Initial Release. ;############################################################################## ; Macro Libraries and External Functions ;############################################################################## MACLIB CPM.MLB MACLIB LIBSTR.MLB ;##################################################################asels ; convert to lowercase? ; process escaped characters call hfn_esc ; restore pop hl pop af pop bc ret hfn_esc: ;------------------------------------------------------------------------------ ; Process escape characters in host filename ; A '[' in the host filename causes next character to be converted to uppercase ; Note: conversion takes place in the same buffer - luckily the converted ; host filename becomes shorter (or the same size) as the original. ; entry: hl -> b############ ; Start ;############################################################################## hfn_start:: defb 'LIBHFN',nul ;############################################################################## ; Storage ;############################################################################## hfn_lcf: defb 0 ; lowercase flag ;############################################################################## ; Code ;######################################################################uffer ; exit: a = trashed ; de -> new nul at end of buffer ; hl -> original nul at end of buffer ;------------------------------------------------------------------------------ push hl ; ld de,hl pop de hfn_e1: ; transcribe buffer (hl->src,de->dst) ld a,(hl) ; fetch or a jr z,hfn_e3 ; nul? ; check for escape character cp '[' jr nz,hfn_e2 ; normal character? ; process escape character inc hl ; fetch next character ld a,(hl) cp nul jr z,hfn_e3 ; nu######## hfnlower:: ;============================================================================== ; Set the host filename lowercase conversion flag ; entry: a = 0 keep case, else convert to lowercase ;============================================================================== ld (hfn_lcf),a ret hfnconvert:: ;============================================================================== ; Store host filename, perform case conversion if required ; entry: de -> buffer to store hfn ; l? (can't escape a nul) call casecc ; change case hfn_e2: ; store character in dest and bump pointers ld (de),a ; store inc de ; bump inc hl jr hfn_e1 ; again hfn_e3: ; terminate ld a,nul ld (de),a ; terminate dest ret hfnfromfcb:: ;============================================================================== ; Obtain host filename from cpm fcb (ignores drive code) ; entry: de -> fcb ; hl -> buffer for host filename ; exit: a = trashed ; de -> fcb ; hl - hl -> source string, nul or space terminated (in uppercase) ; exit: a = last character examined (nul or space), Z flag affected ; bc = preserved ; de -> nul in buffer at end of host filename ; hl -> nul or space in original buffer at end of host filename ;============================================================================== push bc ; save start of host filename buffer push de ; ld bc,de pop bc hfn_s1: ; copy host filename to buffer (hl->src, de->dst) ld a,(hl) ; > buffer containing host filename ;============================================================================== push bc push de push hl inc de ; skip over drive code ; name ld b,8 call ncopy ; possible type ld a,(de) and 7Fh ; strip high bit cp spc jr z,hfnterm ; no type? ; type ld (hl),'.' inc hl ld b,3 call ncopy hfnterm: ; terminate ld a,nul ld (hl),a pop hl pop de pop bc ; convert case as required (currently uppercasfetch or a jr z,hfn_s2 ; nul? cp spc jr z,hfn_s2 ; space? ld (de),a ; store inc hl ; bump inc de jr hfn_s1 ; again hfn_s2: ; save last character examined or a push af ; terminate host filename in buffer ld a,nul ld (de),a ; save current location in source push hl ; get start of host filename buffer push bc ; ld hl,bc pop hl ; convert case as required (currently uppercase) ld a,(hfn_lcf) or a ; check lowercase flag call nz,ce) ld a,(hfn_lcf) or a ; check lowercase flag call nz,casels ; convert to lowercase? ret ncopy: ; transcribe characters until a space or b becomes 0 ld a,(de) ; fetch and 7Fh ; strip high bit cp spc jr z,ncopyskip ; space? ld (hl),a ; store inc de ; bump inc hl djnz ncopy ; again ret ncopyskip: ; skip remainder of fcb until b becomes 0 inc de djnz ncopyskip ret ;############################################################################## ; End ;############################################################################## hfn_end:: end  characters until a space or b becomes 0 ld a,(de) ; fetch and 7Fh ; strip high bit cp spc jr z,ncopyskip ; space? ld (hl),a ; store inc de ; bump inc hl djnz ncopy ; again ret ncopyskip: ; skip remainder of fcb until b becomes 0 inc de djnz ncopyskip ret ;#########################################################################' ; convert ret casecc:: ;============================================================================== ; Change case of a character ; entry: a = character to convert ; exit: a = converted character ;============================================================================== ; must test for a letter first xor 'a'-'A' ; convert ret ;############################################################################## ; String functions ;##########################################; convert ret casecc:: ;============================================================================== ; Change case of a character ; entry: a = character to convert ; exit: a = converted character ;============================================================================== ; must test for a letter first xor 'a'-'A' ; convert ret ;############################################################################## ; String functions ;################################################################################# casels:: ;============================================================================== ; Convert a nul terminated string to lowercase ; entry: hl -> nul terminated string ; exit: a = nul (last character examined) ; hl -> nul terminated string (converted to lowercase) ;============================================================================== push hl casels1: ld a,(hl) ; fetch cp nul jr z,casels2 ; nul? call caselc ; convert ld (hl),; LIBSTR.MAC ; ~~~~~~~~~~ ; ; Contents: ; Z80 assembler program for CP/M. ; ; Purpose: ; Character and string functions ; ; Amendment History: ; 22MAR2003 RKG 1.0 Initial Release. ;############################################################################## ; Macro Libraries ;############################################################################## MACLIB CPM.MLB ;############################################################################## ; Start ;###########################a ; store inc hl ; bump jr casels1 ; again casels2: pop hl ret caseus:: ;============================================================================== ; Convert a nul terminated string to uppercase ; entry: hl -> nul terminated string ; exit: a = nul (last character examined) ; hl -> nul terminated string (converted to uppercase) ;============================================================================== push hl caseus1: ld a,(hl) ; fetch cp nul jr z,caseus2 ; ################################################### str_start:: defb 'LIBSTR',nul ;############################################################################## ; Character functions ;############################################################################## caselc:: ;============================================================================== ; Convert a character to lowercase ; entry: a = character to convert ; exit: a = converted character ;=====================================nul? call caselc ; convert ld (hl),a ; store inc hl ; bump jr caseus1 ; again caseus2: pop hl ret copy_hl:: ;============================================================================== ; Copy nul terminated string ; entry: de -> destination buffer ; hl -> source nul terminated string ; exit: a = nul (last character copied) ; hl -> nul at end of source ; de -> nul at end of destination ;============================================================================== ========================================= cp 'A' ret c ; before 'A' cp 'Z'+1 ret nc ; after 'Z' add a,'a'-'A' ; convert ret caseuc:: ;============================================================================== ; Convert a character to uppercase ; entry: a = character to convert ; exit: a = converted character ;============================================================================== cp 'a' ret c ; before 'a' cp 'z'+1 ret nc ; after 'z' sub 'a'-'A ld a,(hl) ; fetch ld (de),a ; store or a ret z ; nul? inc hl ; bump inc de jr copy_hl ; again copy_de:: ;============================================================================== ; Copy nul terminated string ; entry: de -> source nul terminated string ; hl -> destination buffer ; exit: a = nul (last character copied) ; de -> nul at end of source ; hl -> nul at end of destination ;============================================================================== ld a,(de) ; fetch ld (hl),a ; store or a ret z ; nul? inc de ; bump inc hl jr copy_de ; again nextword:: ;============================================================================== ; Skip word and subsequent spaces ; entry: hl -> buffer of characters to examine ; exit: a = last character examined, z flag set if nul encountered ; hl -> buffer - first character in next word ;============================================================================== call skipwordandom errors ; Higher values should produce more errors, max value is 127. ;############################################################################## ;RANDERRS equ 15 ;############################################################################## ; Start ;############################################################################## xtrs_start:: defb 'LIBXTRS',nul ;############################################################################## ; Messages ;############################## ret z call skipspaces ret setflags: or a ; A won't be nul, clear Z flag ret skipword:: ;============================================================================== ; Skip characters until a space or a nul are encountered. ; entry: hl -> buffer of characters to skip ; exit: a = last character examined, z flag set if nul encountered ; hl -> buffer - nul or space at end of current word ;============================================================================== ld a,(hl) ################################################ m_unkerr: defb 'Unable to obtain HOST error message',cr,lf,'$' m_spdnrml: defb '** normal speed **',cr,lf,'$' m_spdhigh: defb '** high speed **',cr,lf,'$' ;############################################################################## ; Storage ;############################################################################## f_spdchg: defb 0 ; speed change flag f_spdold: defb 0 ; original speed setting (autodelay) ;######################### or a ret z ; nul detected cp spc jr z,setflags ; space detected inc hl jr skipword skipspaces:: ;============================================================================== ; Skip space characters ; entry: hl -> buffer of spaces to examin ; exit: a = last character examined, z set if nul encountered ; hl -> buffer - first non-space character ;============================================================================== ld a,(hl) or a ret z ; nul detected cp##################################################### ; Raw emulator traps ;############################################################################## xtrssystem:: ;============================================================================== ; entry: hl -> nul terminated command ; exit: a = status: 0 if OK, error number if not (Z flag affected) ; bc = command exit status ;============================================================================== defw 28EDh ifdef RANDERRS call ran spc ret nz ; non space detected inc hl jr skipspaces printnul:: ;============================================================================== ; Print a nul terminated string with bdos couts call ; Note: nul is converted to a '$' for printing and back to a nul again ; entry: hl -> buffer with nul terminated string ; exit: a trashed ;============================================================================== push bc push de push hl push hl ; ld de,hl pop de nulp; LIBXTRS.MAC ; ~~~~~~~~~~~ ; ; Contents: ; Z80 assembler program for CP/M. ; ; Purpose: ; XTRS emulator functions ; ; Amendment History: ; 22MAR2003 RKG 1.0 Initial Release. ;############################################################################## ; Macro Libraries ;############################################################################## MACLIB CPM.MLB MACLIB LIBSTR.MLB ;############################################################################## ; Start ;###########1: ; find nul ld a,(hl) or a jr z,nulp2 inc hl jr nulp1 nulp2: ; terminate for printing ld (hl),'$' ; print push hl bdos b_couts ; de already points to message pop hl ; terminate with nul ld (hl),nul ; nul terminate pop hl pop de pop bc ret ;############################################################################## ; End ;############################################################################## str_end:: end ################################################################### xtrs_start:: defb 'LIBXTRS',nul ;############################################################################## ; Messages ;############################################################################## m_unkerr: defb 'Unable to obtain HOST error message',cr,lf,'$' m_spdnrml: defb '** normal speed **',cr,lf,'$' m_spdhigh: defb '** high speed **',cr,lf,'$' ;############################################################################## ; Storage ;############################################################################## f_spdchg: defb 0 ; speed change flag f_spdold: defb 0 ; original speed setting (autodelay) ;############################################################################## ; Raw emulator traps ;############################################################################## xtrssystem:: ;============================================================================== ; entry: hl -> nul terminats: 0 if OK, error number if not (Z flag affected) ; hl -> location in file, 0xFFFFFFFF if error ;============================================================================== defw 34EDh ret xtrsstrerror:: ;============================================================================== ; entry: a = error number ; bc = buffer size ; hl -> buffer for error string ; exit: a = status: 0 if OK, new error number if not (Z flag affected) ; bc = strlen(buffer), 0xFFFF if error ; hl -> same bufed command ; exit: a = status: 0 if OK, error number if not (Z flag affected) ; bc = command exit status ;============================================================================== defw 28EDh ret xtrsopen:: ;============================================================================== ; entry: hl -> path, nul terminated ; bc = oflag (use eo_ values defined below) ; de = mode ; exit: a = status: 0 if OK, error number if not (Z flag affected) ; de = fd, 0xFFFF if error ;-----------fer, containing \r\0 terminated string ;============================================================================== defw 35EDh ; unix error string ret xtrsmisc:: ;============================================================================== ; entry: a = function code (see em_ codes defined below) ; other registers as listed below ; exit: other registers as listed below ;------------------------------------------------------------------------------ ; em_disk_change equ 0 ; disk change------------------------------------------------------------------- ; eo_accmode equ 03q eo_rdonly equ 00q eo_wronly equ 01q eo_rdwr equ 02q ; eo_creat equ 0100q ; eo_excl equ 0200q ; eo_trunc equ 01000q ; eo_append equ 02000q ; ;============================================================================== defw 30EDh ret xtrsclose:: ;============================================================================== ; entry: de = fd ; exit: a = status: 0 if OK, error number if not ( ; exit: hl = disk change count ; em_exit equ 1 ; exit emulator ; em_debug equ 2 ; enter debugger ; em_reset equ 3 ; press reset button ; em_modelquery equ 5 ; query model ; exit: hl = model: 1, 3, 4, or 5 (4P) ; em_graphicquery equ 10 ; query graphics type ; exit: hl = 0 (Radio Shack), 1 (Micro Labs) ; em_graphicset equ 11 ; set graphics type ; entry: hl = 0 (Radio Shack), 1 (Micro Labs) ; em_delayquery equ 12 ; query delay ; exit: bc = autodelay flag ; hl = delay ; em_delaysZ flag affected) ;============================================================================== defw 31EDh ret xtrsread:: ;============================================================================== ; entry: bc = nbytes ; de = fd ; hl -> buffer ; exit: a = status: 0 if OK, error number if not (Z flag affected) ; bc = nbytes read, 0xFFFF if error ;============================================================================== defw 32EDh ret xtrswrite:: ;======================et equ 13 ; query set ; entry: bc = autodelay flag ; hl = delay ; ;============================================================================== defw 3CEDh ; emulator functions ret ;############################################################################## ; Extra functions ;############################################################################## xtrserrmsg:: ;============================================================================== ; Display error message ; entry: a ======================================================== ; entry: bc = nbytes ; de = fd ; hl -> buffer ; exit: a = status: 0 if OK, error number if not (Z flag affected) ; bc = nbytes read, 0xFFFF if error ;============================================================================== defw 33EDh ret xtrslseek:: ;============================================================================== ; entry: bc = whence ; de = fd ; hL -> offset (8-byte little-endian integer) ; exit: a = statu= error number ; de -> text to display before error message (0=>no message) ; exit: a = preserved ; bc = trashed ; de = trashed ; hl = trashed ; notes: c_iobuf is overwritten with error message ;============================================================================== push af ; save push af ld a,d or e jr z,xtrserr1 bdos b_couts ; display optional message xtrserr1: pop af ld de,c_iobuf ; buffer to store msg push de pop hl ; ld hl,de ld bc,c_iobufsize-2 call xtrsstrerror jp nz,xtrserr3 ; another error?! add hl,bc ld (hl),lf ; already has cr, add lf inc hl ld (hl),'$' ; add terminator bdos b_couts,c_iobuf xtrserr2: pop af ; restore ret xtrserr3: bdos b_couts,m_unkerr jr xtrserr2 xtrsmodel:: ;============================================================================== ; Obtain model name ; exit: a = 'P' for Model 4P, 0 if single character (z flag set) ; e = first character of model name '1', '3', or '4' ;======================== ; preserve regs push af push bc push de push hl ; get current speed ld a,em_delayquery call xtrsmisc ld a,c ; autodelay or a jr nz,speed_done ; already normal speed? ; save original settings ld (f_spdold),a ; save current setting ld a,1 ld (f_spdchg),a ; set speed change speed_nrml: ; switch to fast speed ld a,em_delayset ld hl,0 ; as fast as possible ld bc,1 ; turn on autodelay call xtrsmisc bdos b_couts,m_spdnrml ======================================================================= push hl ; fetch model info ld a,em_modelquery call xtrsmisc ld a,l ; model: 1, 3, 4, or 5 (4P) pop hl ; model 4P check cp 5 jr z,model4p ; model 4P? ; single digit model add a,'0' ; convert to ascii ld e,a xor a ; clear and set flags ret model4p: ; model 4P ld e,'4' ld a,'P' or a ; set flags ret xtrsrstrspd:: ;==================================================== jr speed_done xtrsdiskname:: ;============================================================================== ; Generate the appropriate disk filename ; entry: a = disk number '0', '1', '2', or '3' ; de -> buffer to store disk filename "diskXX-X" ; exit: a = 0 if disk number is bad (z flag set) otherwise unchanged ; de -> buffer containing disk filename ;============================================================================== cp '0' jr c,dsk_bad ; too small? cp '3'+1 jr nc,ds========================== ; Restore original speed ;============================================================================== ; preserve regs push af push bc push de push hl ; check if the speed was changed ld a,(f_spdchg) or a jr z,speed_done ; reset speed changed flag xor a ld (f_spdchg),a ; restore original speed ld a,(f_spdold) or a jr z,speed_high ; auto delay was 0, restore high speed jr speed_nrml ; auto delay was 1, restore normal speed k_bad ; too big? ; valid disk number push hl ; save hl push af ; save disk number push de ; ld hl,de pop hl ; "disk" ld (hl),'d' inc hl ld (hl),'i' inc hl ld (hl),'s' inc hl ld (hl),'k' inc hl ; model push de ; save de call xtrsmodel ld (hl),e inc hl jr z,modeldone call caselc ld (hl),a inc hl modeldone: pop de ; restore de ; hyphen ld (hl),'-' inc hl ; disk num pop af ; restore disk number ld (hl),a speed_done: ; restore regs pop hl pop de pop bc pop af ret xtrshighspd:: ;============================================================================== ; Switch to high speed, save current settings ;============================================================================== ; preserve regs push af push bc push de push hl ; get current speed ld a,em_delayquery call xtrsmisc ld a,c ; autodelay or a jr z,speed_done ; already fast speed? ; sa inc hl ; terminate ld (hl),nul pop hl ; restore hl ret dsk_bad: xor a ; zero ret ;############################################################################## ; End ;############################################################################## xtrs_end:: end done: pop de ; restore de ; hyphen ld (hl),'-' inc hl ; disk num pop af ; restore disk number ld (hl),a ve original settings ld (f_spdold),a ; save current setting ld a,1 ld (f_spdchg),a ; set speed change speed_high: ; switch to fast speed ld a,em_delayset ld hl,0 ; as fast as possible ld bc,0 ; turn off autodelay call xtrsmisc bdos b_couts,m_spdhigh jr speed_done xtrsnrmlspd:: ;============================================================================== ; Switch to normal speed, save current settings ;============================================================= MACLIB LIBXTRS.MLB ;############################################################################## ; Messages ;############################################################################## m_crlf: defb cr,lf,'$' ;############################################################################## ; Code ;############################################################################## main:: call hex_test call cfn_test call hfn_test call ch_fn_test call xtrs_test done:: ;============================================================================== ; Single exit point of program ;============================================================================== jp c_boot hex_test:: ;============================================================================== ; Test hex functions ;============================================================================== bdos b_couts,hex_msg ld a,0 call hexa bdos b_couts,m_crlf ld hl,1234h call hexhl bdos b_os b_couts,m_crlf ld a,091h ld b,0A2h ld c,0B3h ld d,0C4h ld e,0D5h ld h,0E6h ld l,0F7h call hexregs ld hl,100h ld c,30 call hexmemory ret cfn_test:: ;============================================================================== ; Test cpm filename functions ;============================================================================== dbgmsg '** cfn_test **' ; test1 ld hl,cfn_t1 call cfn_dotest ; test2 ld hl,cfn_t2 call cfn_dotest ;couts,m_crlf ld a,091h ld b,0A2h ld c,0B3h ld d,0C4h ld e,0D5h ld h,0E6h ld l,0F7h call hexregs ld hl,100h ld c,30 call hexmemory ret hex_msg: defb cr,lf,'** hex_test **',cr,lf,'$' cfn_test:: ;============================================================================== ; Test cpm filename functions ;============================================================================== bdos b_couts,cfn_msg ; test1 ld hl,cfn_t1 call cfn_dotest ; te test3 ld hl,cfn_t3 call cfn_dotest ; test4 ld hl,cfn_t4 call cfn_dotest ; test5 ld hl,cfn_t5 call cfn_dotest ret cfn_dotest: ; display source call printnul ; becomes push hl bdos b_couts,cfn_becomes pop hl ; store cfn into fcb ld de,c_fcb1 call cfntofcb ; from (hl) into (de) ; dump fcb ld e,'"' bdos b_coutb ld hl,c_fcb1 ld a,(hl) ; 1=A:, 2=B:, ... add a,'A'-1 ld e,a bdos b_coutb ; print drive ld e,':' bdos b_cou; TESTLIB.MAC ; ~~~~~~~~~~~ ; ; Contents: ; Z80 assembler program for CP/M. ; ; Purpose: ; Test library functions ; ; Usage: ; LIBTEST ; ; Amendment History: ; 14MAR2003 RKG 1.0 Initial release. ;############################################################################## ; Macro Libraries and External Functions ;############################################################################## MACLIB CPM.MLB MACLIB LIBCFN.MLB MACLIB LIBHEX.MLB MACLIB LIBHFN.MLB MACLIB LIBSTR.tb ld hl,c_fcb1_fname call printnul ; print name and type ld e,'"' bdos b_coutb ; becomes bdos b_couts,cfn_becomes ; convert fcb into filename ld hl,c_iobuf ld de,c_fcb1 call cfntotext ; convert fcb to filename call printnul ; print filename bdos b_couts,m_crlf ret cfn_becomes: defb ' -> $' cfn_t1: defb 'A',nul cfn_t2: defb 'A:',nul cfn_t3: defb 'A:ABCDEFGHIJ.ABCDE',nul cfn_t4: defb 'A:AB?D*FGHI.?B*D',nul cfn_t5: defb 'A:A.B.C.D',nul hfn_test::MLB MACLIB LIBXTRS.MLB ;############################################################################## ; Messages ;############################################################################## m_crlf: defb cr,lf,'$' ;############################################################################## ; Code ;############################################################################## main:: call hex_test call cfn_test call hfn_test call ch_fn_test call xtrs_test done:: ;= ;============================================================================== ; Test host filename functions ;============================================================================== dbgmsg '** hfn_test **' ; test1a ld hl,hfn_t1 xor a call hfnlower call hfn_dotest ; test1b ld hl,hfn_t1 ld a,1 call hfnlower call hfn_dotest ; test2a ld hl,hfn_t2 xor a call hfnlower call hfn_dotest ; test2b ld hl,hfn_t2 ld a,1 call hfnlower call hfn============================================================================= ; Single exit point of program ;============================================================================== jp c_boot hex_test:: ;============================================================================== ; Test hex functions ;============================================================================== dbgmsg '** hex_test **' xor a call hexa bdos b_couts,m_crlf ld hl,1234h call hexhl bd_dotest ret hfn_dotest: ld de,c_iobuf call hfnconvert ; from (hl) into (de) ld hl,c_iobuf call printnul bdos b_couts,m_crlf ret hfn_t1: defb 'TESTHOSTFILENAME',nul hfn_t2: defb '[ANOTHER[TEST[HOST[FILENAME',nul ch_fn_test:: ;============================================================================== ; Test cpm and host filename functions ;============================================================================== dbgmsg '** ch_fn_test **' ; test1 xor a call hfnlower ld hl,chfn_t1 ld de,c_fcb1 call cfntofcb ; from (hl) into (de) ld hl,c_iobuf call hfnfromfcb call printnul bdos b_couts,m_crlf ; test2 ld a,1 call hfnlower ld hl,chfn_t1 ld de,c_fcb1 call cfntofcb ; from (hl) into (de) ld hl,c_iobuf call hfnfromfcb call printnul bdos b_couts,m_crlf ret chfn_t1: defb 'A:ABCD.EF',nul xtrs_test:: ;============================================================================== ; Test xtrs functireport status ; SYSTEM command - execute command on host ; UMOUNT disknum - umount disk ; hostfilename is the name of the virtual disk file on the host ; (converted to uppercase by default), use -L to convert to ; lowercase and [ to toggle case of next character. ; command is the command (and parameters) to execute on the host ; (converted to lowercase by default), use [ to toggle case. ; Note output from command is NOT displayed in the XTRS window. ; disknum is disk drive number ons ;============================================================================== dbgmsg '** xtrs_test **' ld de,c_iobuf ld a,'1' call xtrsdiskname ld hl,c_iobuf call printnul bdos b_couts,m_crlf ld de,c_iobuf ld a,'D' call xtrsdiskname ld hl,c_iobuf call printnul bdos b_couts,m_crlf ret ;############################################################################## ; End ;############################################################################## (between 0 and 3 inclusive). ; -L converts hostfilename to lowercase. ; ; Notes: ; When changing disks, remember that CP/M must also be told of the disk ; change. This is usually done by pressing ctrl-C at the prompt. ; ; Amendment History: ; 22MAR2003 RKG 1.0 Initial release. ;############################################################################## ; Macro Libraries and External Functions ;############################################################################## MACLIB CPM.MLB end main buf ld a,'1' call xtrsdiskname ld hl,c_iobuf call printnul bdos b_couts,m_crlf ld de,c_iobuf ld a,'D' call xtrsdiskname ld hl,c_iobuf call printnul bdos b_couts,m_crlf ret ;############################################################################## ; End ;############################################################################## MACLIB LIBHEX.MLB MACLIB LIBHFN.MLB MACLIB LIBSTR.MLB MACLIB LIBXTRS.MLB ;############################################################################## ; Offset assembly so that print file matches linked output ;############################################################################## .phase 103h ;############################################################################## ; Messages ;############################################################################## m_usage:LIB LIBHEX.MLB MACLIB LIBHFN.MLB MACLIB LIBSTR.MLB MACLIB LIBXTRS.MLB ;############################################################################## ; Offset assembly so that print file matches linked output ;############################################################################## .phase 103h ;############################################################################## ; Messages ;############################################################################## m_usage:: def: defb 'XTRS - controls miscellaneous functions of the XTRS emulator',cr,lf defb cr,lf,'Usage:' defb tab,'XTRS action [parameters]',cr,lf defb cr,lf,'Where:' defb tab,'action is one of the following:',cr,lf defb tab,spc,spc,spc,'BOOT - reboot emulator',cr,lf defb tab,spc,spc,spc,'CHANGE - signal disk change',cr,lf defb tab,spc,spc,spc,'DEBUG - enter debugger',cr,lf defb tab,spc,spc,spc,'EXIT - end emulator',cr,lf defb tab,spc,spc,spc,'HIGHSPEED - high speed (autodelay off)',cr,lf ; XTRS.MAC ; ~~~~~~~~ ; ; Contents: ; Z80 assembler program for CP/M. ; ; Purpose: ; Controls miscellaneous functions of the xtrs emulator ; ; Usage: ; XTRS action [parameters] ; ; Where: ; action is one of the following: ; BOOT - reboot emulator ; CHANGE - signal disk change ; DEBUG - enter debugger ; EXIT - end emulator ; HIGHSPEED - high speed (autodelay off) ; MOUNT [-L] hostfilename disknum - mount disk ; NORMALSPEED - normal speed (autodelay on) ; REPORT - defb tab,spc,spc,spc,'MOUNT [-L] hostfilename disknum - mount disk',cr,lf defb tab,spc,spc,spc,'NORMALSPEED - normal speed (autodelay on)',cr,lf defb tab,spc,spc,spc,'REPORT - report status',cr,lf defb tab,spc,spc,spc,'SYSTEM command - execute command on host',cr,lf defb tab,spc,spc,spc,'UMOUNT disknum - umount disk',cr,lf defb tab,'hostfilename is the name of the virtual disk file on the host',cr,lf defb tab,spc,spc,spc,'(converted to uppercase by default), use -L to convert to',cr,lf defb tab,spc,spc,spc,'lowercase and [ to toggle case of next character.',cr,lf defb tab,'command is the command (and parameters) to execute on the host',cr,lf defb tab,spc,spc,spc,'(converted to lowercase by default), use [ to toggle case.',cr,lf defb tab,spc,spc,spc,'Note output from command is NOT displayed in the XTRS window.',cr,lf defb tab,'disknum is disk drive number (between 0 and 3 inclusive).',cr,lf defb tab,'-L converts hostfilename to lowercase.$' m_crlf:: defb cr,lf,'$' ; only spaces? ; action ld a,(hl) ; first character of action call caseuc ; ensure uppercase cp 'B' jp z,cmd_boot ; BOOT? cp 'C' jp z,cmd_change ; CHANGE? cp 'D' jp z,cmd_debug ; DEBUG? cp 'E' jp z,cmd_exit ; EXIT? cp 'H' jp z,cmd_highspd ; HIGHSPEED? cp 'M' jp z,cmd_mount ; MOUNT? cp 'N' jp z,cmd_normspd ; NORMALSPEED? cp 'R' jp z,cmd_report ; REPORT? cp 'S' jp z,cmd_system ; SYSTEM? cp 'U' jp z,cmd_umount ; UMOUNT? ; inm_ehfn:: defb 'ERROR: Expecting hostfilename',cr,lf,'$' m_edisk:: defb 'ERROR: Expecting disknum',cr,lf,'$' m_ecmd:: defb 'ERROR: Expecting command',cr,lf,'$' m_extraparams:: defb 'ERROR: Extra parameter: $' m_baction:: defb 'ERROR: Bad action',cr,lf,'$' m_bdisknum:: defb 'ERROR: Bad disknum',cr,lf,'$' m_boption:: defb 'ERROR: Bad option "' option: defb 'x"',cr,lf,'$' m_hcmd:: defb 'HOST COMMAND: $' m_hfail:: defb 'HOST COMMAND failed: $' m_mntfail:: defb 'MOUNT failed - does hostfilename evalid action bdos b_couts,m_baction ; fall thru usage:: ;============================================================================== ; Display program usage ;============================================================================== bdos b_couts,m_usage ; fall thru done:: ;============================================================================== ; Single exit point of program ;============================================================================== jp c_boot ;xist?',cr,lf,'$' m_umtfail:: defb 'UMOUNT failed',cr,lf,'$' m_sysfail:: defb 'SYSTEM command returned non-zero status',cr,lf,'$' m_diskchange:: defb '** disk change **',cr,lf,'$' m_graphics:: defb 'Graphics ..: $' m_grars:: defb 'Radio Shack',cr,lf,'$' m_graml:: defb 'Micro Labs',cr,lf,'$' m_speed:: defb 'Speed .....: $' m_normal:: defb 'Normal',cr,lf,'$' m_fast:: defb 'High',cr,lf,'$' m_model:: defb 'Model .....: $' m_bvar:: defb 'Internal Error: bad variable in command skeleton',cr,lf############################################################################## ; Subcommands ;############################################################################## cmd_boot:: ;============================================================================== ; BOOT ;============================================================================== ld a,em_reset call xtrsmisc jp done cmd_change:: ;============================================================================== ; CHANGE ,'$' ;############################################################################## ; Storage ;############################################################################## hfnbuffer:: defs 128 ; host filename dfnbuffer:: defs 9 ; disk filename "diskXX-X" ; cmd skeletons: %d becomes disk filename, %h becomes host filename mnt_cmd:: defb 'rm -f %d;test -f %h && ln -s %h %d',nul umt_cmd:: defb 'rm -f %d',nul cmdbuffer:: defs 300 ; buffer to store expanded host commands ; space for th;============================================================================== ld a,em_disk_change call xtrsmisc bdos b_couts,m_diskchange jp done cmd_debug:: ;============================================================================== ; DEBUG ;============================================================================== ld a,em_debug call xtrsmisc jp done cmd_exit:: ;============================================================================== ; EXIT ;================e stack defs 32 stack_top:: defw 0 ; stack down from here (this word wasted) ;############################################################################## ; Code ;############################################################################## main:: ; set up the stack ld sp,stack_top ; display usage if no parameters ld a,(c_cmdlen) ; get length of parameters or a jr z,usage ; no parameters? ld hl,c_cmdstr ; start of command arg buffer call skipspaces jr z,usage ============================================================== ld a,em_exit call xtrsmisc jp done cmd_highspd:: ;============================================================================== ; HIGHSPEED ;============================================================================== call xtrshighspd jp done cmd_mount:: ;============================================================================== ; MOUNT [-L] hostfilename disknum ; entry: hl -> start of MOUNT ;============================================================================== ; skip word "MOUNT" call nextword ; options call options ; host filename jp z,expect_hfname ; no more parameters? ld de,hfnbuffer ; buffer to store hfn call hfnconvert ; store host filename call skipspaces ; disk number jp z,expect_disknum ; no more parameters? ld de,dfnbuffer ; buffer for disk filename call xtrsdiskname ; check and store disk number jp z,bad_disknum ; bad disk number? ; end of misc ld a,l ; 0=>RS, 1=>ML or a jr z,gph_rs bdos b_couts,m_graml ret gph_rs: bdos b_couts,m_grars ret cmd_system:: ;============================================================================== ; SYSTEM command ; entry: hl -> start of SYSTEM ;============================================================================== ; skip word "SYSTEM" call nextword ; always treat as lowercase ld a,1 call hfnlower ; convert to lowercase ; command jp z,expect_commancommand inc hl ; skip over disk number call skipspaces ; can tolerate spaces jp nz,extra_params ; unexpected parameters? ; prepare host command ld hl,cmdbuffer ; buffer for command ld de,mnt_cmd ; skeleton for command call cmd_copy ; display and execute command call cmd_display call xtrssystem jp nz,mnt_error ; host cmd error? ; check result ld a,b or c jp nz,mnt_fail ; bad result? ; signal disk change jp cmd_change ; signal disk change cmd_nd ; no command? ld de,cmdbuffer ; buffer to store command copy_word: call hfnconvert ; convert as per host filename call copyspaces ; copy spaces too jr nz,copy_word ; keep appending until nul ; display and execute command ld hl,cmdbuffer call cmd_display call xtrssystem jp nz,sys_error ; host cmd error? ; check result ld a,b or c jp nz,sys_fail ; bad result? ; done jp done cmd_umount:: ;=================================================================ormspd:: ;============================================================================== ; NORMALSPEED ;============================================================================== call xtrsnrmlspd jp done cmd_report:: ;============================================================================== ; REPORT ;============================================================================== call rep_model ; model call rep_speed ; speed call rep_graphic ; graphics jp done rep_mode============= ; UMOUNT disknum ; entry: hl -> start of UMOUNT ;============================================================================== ; skip word "UMOUNT" call nextword ; disk number jp z,expect_disknum ; no more parameters? ld de,dfnbuffer ; buffer for disk filename call xtrsdiskname ; check and store disk number jp z,bad_disknum ; bad disk number? ; end of command inc hl ; skip over disk number call skipspaces ; can tolerate spaces jp nz,extra_params ; unl: ;------------------------------------------------------------------------------ ; Display model details ;------------------------------------------------------------------------------ bdos b_couts,m_model call xtrsmodel push af bdos b_coutb pop af jr z,model1char ld e,a bdos b_coutb model1char: bdos b_couts,m_crlf ret rep_speed: ;------------------------------------------------------------------------------ ; Display speed setting ;------------------------------------expected parameters? ; prepare host command ld hl,cmdbuffer ; buffer for command ld de,umt_cmd ; skeleton for command call cmd_copy ; display and execute command call cmd_display call xtrssystem jp nz,umt_error ; host cmd error? ; check result ld a,b or c jp nz,umt_fail ; bad result? ; signal disk change jp cmd_change ; signal disk change ;############################################################################## ; MOUNT, SYSTEM, and UMOUNT support ------------------------------------------ bdos b_couts,m_speed ld a,em_delayquery call xtrsmisc ld a,c ; 0=>autodelay off (i.e. fast) or a jr z,spd_fast bdos b_couts,m_normal ret spd_fast: bdos b_couts,m_fast ret rep_graphic: ;------------------------------------------------------------------------------ ; Display graphics system ;------------------------------------------------------------------------------ bdos b_couts,m_graphics ld a,em_graphicquery call xtrsfunctions ;############################################################################## options: ;------------------------------------------------------------------------------ ; Process mount options (currently only "-L") ; entry: hl -> command line with possible options ; exit: a = last character examined (z flag affected) ; hl -> next character in command line ;------------------------------------------------------------------------------ ; possible options ld a,(hl) or a ret z ; nul? end of options cp '-' ret nz ; not an option? ; have options inc hl ; skip past '-' ld a,(hl) opt_next: call opt_action ; check for more options inc hl ld a,(hl) or a ret z ; nul? end of options cp spc jr nz,opt_next ; more options in this group? call skipspaces jr options ; check for next group of options opt_action: ; process option call caseuc ; make case-insensitive cp 'L' jp z,opt_l ; invalid option ld (option),a b exit: a = last characters examined, z set if nul encounterd ; de -> nul at end of destination ; hl -> first non space in source ;------------------------------------------------------------------------------ ld a,(hl) ; fetch or a ret z ; nul? cp spc ret nz ; non-space? ld (de),a ; store inc hl ; bump inc de push af ld a,nul ld (de),a ; always terminate destination pop af jr copyspaces ; again ;------------------------------------------------------dos b_couts,m_boption jp usage opt_l: ; "-L" convert hostfilename to lowercase ld a,1 call hfnlower ; set lowercase flag ret cmd_copy: ;------------------------------------------------------------------------------ ; Copy a nul terminated command string with variable substitution ; Variables: %d (dfnbuffer) and %h (hfbuffer) ; entry: de -> command skeleton ; hl -> buffer to store command ; exit: af = trashed ; de = preserved ; hl = preserved ;------------------------------------------------------- ; Error routines ;------------------------------------------------------------------------------ expect_hfname: bdos b_couts,m_ehfn jp usage expect_disknum: bdos b_couts,m_edisk jp usage expect_command: bdos b_couts,m_ecmd jp usage bad_disknum: bdos b_couts,m_bdisknum jp usage extra_params: push hl bdos b_couts,m_extraparams pop hl call printnul bdos b_couts,m_crlf jp usage mnt_error: ld de,m_hfail call nz,xtrserrmsg jp cmd_change----------------------------------------------- push bc push de push hl cmd_fetch: ; transcribe command ld a,(de) ; fetch cp '%' jr z,variable ; special action for variables ld (hl),a ; store or a inc hl ; bump inc de jr nz,cmd_fetch ; again pop hl pop de pop bc ret variable: ; check variable name inc de ; check next character ld a,(de) cp 'd' jr z,var_d ; d? cp 'h' jr z,var_h ; h? bdos b_couts,m_bvar jp done var_d ; must signal disk change mnt_fail: bdos b_couts,m_mntfail jp cmd_change ; must signal disk change umt_error: ld de,m_hfail call nz,xtrserrmsg jp cmd_change ; must signal disk change umt_fail: bdos b_couts,m_umtfail jp cmd_change ; must signal disk change sys_error: ld de,m_hfail call nz,xtrserrmsg jp done sys_fail: bdos b_couts,m_sysfail jp done ;############################################################################## ; End ;##############################: ; insert disk filename push de ; save de ld de,dfnbuffer call copy_de ; insert disk filename pop de ; restore de jr var_endvar var_h: ; insert host filename push de ; save de ld de,hfnbuffer call copy_de ; insert host filename pop de ; restore de ; fall thru var_endvar: ; move past variable inc de jr cmd_fetch cmd_display: ;------------------------------------------------------------------------------ ; Display the host command ; entry: hl ->################################################ end:: end main m_hfail call nz,xtrserrmsg jp cmd_change ; must signal disk change umt_fail: bdos b_couts,m_umtfail jp cmd_change ; must signal disk change sys_error: ld de,m_hfail call nz,xtrserrmsg jp done sys_fail: bdos b_couts,m_sysfail jp done ;############################################################################## ; End ;############################## buffer containing nul terminated command ; exit: hl = preserved ;------------------------------------------------------------------------------ push af push bc push de push hl bdos b_couts,m_hcmd pop hl ; refresh addr of buffer push hl call printnul bdos b_couts,m_crlf pop hl pop de pop bc pop af ret copyspaces: ;------------------------------------------------------------------------------ ; Copy spaces ; entry: de -> destination ; hl -> source ;rm -f %d;test -f %h && ln -s %h %drm -f %d1°:€·(F!Íy (>~Í+ þBÊ þCÊ þDÊ$ þEÊ, þHÊ4 þMÊ: þNÊy þRÊ þSÊô þUÊ I ÍòXTRS - controls miscellaneous functions of the XTRS emulator Usage: XTRS action [parameters] Where: action is one of the following: BOOT - reboot emulator CHANGE - signal disk change DEBUG - enter debugger EXIT - end emulator HIGHSPEED - high speed (autodelay off) MOUNT [-L] hostfilename disknum - mount disk NORMALSPEED - normal speed (autodelay on) REPORT - report status SYSTEM command - execute command on host UMOUNT disknum - umount disk hostfi  Íà ] Íà å0 ÍáÍ’ × Íà ™Äà ¯ Íà ™Äà ٠Íà ™Äà é Íà LIBHEXõÅÕå_ÍáÑÁñÉõæþ 0>.Ís ñÉË?Ë?Ë?Ë?æþ 8ÆÆ0Éõ͘ OñÍ ÉõÍ Ís ñ͘ Ís É|Í­ }Í­ ÉõÅÕåÅåͼ >:Ís > Ís y· > Ís Ís ~Í­ #å> Ís áÁy· > Ís Ís ~Í‚ #ê> Ís > Ís y· ¬áÑÁñÉõÅÕåõ>RÍs >EÍs >GÍs >SÍs >:Ís ñÕA͈ ÑõÍ­ > Ís ñÍ‚ ÕB͈ ÑåÅáͼ áÕD͈ ÑåÕáͼ áH͈ ͼ > Ís > Ís áÑÁñÉõÅÕåÕ ÍÑÍ=ÍáÑÁñÉLIBHFN2­ ÉÅÕÁ~·( þ (#ó·õ>åÅá:­ ·ÄG ÍØ áñÁÉåÑ~·(þ[ #~þ(ÍD #ê>ÉÅÕåÍ ælename is the name of the virtual disk file on the host (converted to uppercase by default), use -L to convert to lowercase and [ to toggle case of next character. command is the command (and parameters) to execute on the host (converted to lowercase by default), use [ to toggle case. Note output from command is NOT displayed in the XTRS window. disknum is disk drive number (between 0 and 3 inclusive). -L converts hostfilename to lowercase.$ $ERROR: Expecting hostfilename $ERROR:þ (6.#Í >wáÑÁ:­ ·ÄG Éæþ (w#ôÉýÉLIBSTRþAØþ[ÐÆ ÉþaØþ{ÐÖ Éî Éå~þ(Í2 w#ôáÉå~þ(Í2 w#ôáÉ~·È#øw·È#øÍ È͉ É·É~·Èþ (÷#ö~·Èþ À#÷ÅÕååÑ~·(#ù6$å Íá6áÑÁÉLIBXTRSUnable to obtain HOST error message $** normal speed ** $** high speed ** $í(Éí0Éí1Éí2Éí3Éí4Éí5Éí<Éõõz³( Íñ€Õá~ÍÂG 6 #6$€ Íñɵ  Íôå>Í}áþ(Æ0_¯É4>P·ÉõÅÕå:·( ¯2:·(DáÑÁñÉõÅÕå> Íy·(î2>2> !Íð  ÍÑõÅÕå> Íy· Ä2>2> !ÍÛ  ͧþ08,þ40(åõÕá6d#6i#6s#6k#ÕÍQs#(Í2 w#Ñ6-# Expecting disknum $ERROR: Expecting command $ERROR: Extra parameter: $ERROR: Bad action $ERROR: Bad disknum $ERROR: Bad option "x" $HOST COMMAND: $HOST COMMAND failed: $MOUNT failed - does hostfilename exist? $UMOUNT failed $SYSTEM command returned non-zero status $** disk change ** $Graphics ..: $Radio Shack $Micro Labs $Speed .....: $Normal $High $Model .....: $Internal Error: bad variable in command skeleton $ñw#6áɯÉÍy·(î2>2> !Íð  ÍÑõÅÕå> Íy· Ä2>2> !ÍÛ  ͧþ08,þ40(åõÕá6d#6i#6s#6k#ÕÍQs#(Í2 w#Ñ6-#·Èþ (÷#ö~·Èþ À#÷ÅÕååÑ~·(#ù6$å Íá6áÑÁÉLIBXTRSUnable to obtain HOST error message $** normal speed ** $** high speed ** $í(Éí0Éí1Éí2Éí3Éí4Éí5Éí<Éõõz³( Íñ€Õá~ÍÂG 6 #6$€ Íñɵ  Íôå>Í}áþ(Æ0_¯É4>P·ÉõÅÕå:·( ¯2:·(DáÑÁñÉõÅÕå> Íy·(î2>2> !Íð  ÍÑõÅÕå> Íy· Ä2>2> !ÍÛ  ͧþ08,þ40(åõÕá6d#6i#6s#6k#ÕÍQs#(Í2 w#Ñ6-#rm -f %d;test -f %h && ln -s %h %drm -f %d1°:€·(F!͉ (>~Í; þBÊ þCÊ þDÊ$ þEÊ, þHÊ4 þMÊ: þNÊy þRÊ þSÊô þUÊ I ÍÛ Usage: IMPORT [-F][-H][-L][-T][-V] hostfilename [cpmfilename] $Invalid option "x" $ERROR: Must specify hostfilename $ -> $ERROR: Unable to open HOST file: $ERROR: Unable to read HOST file: $ERROR: Unable to close HOST file: $ERROR: CP/M file already exists $ERROR: Unable to open CP/M file $ERROR: Unable to write CP/M file $ERROR: Unable to close CP/M file $ ÍÃ>Íà >Í Íà >Íà >Íà ̓à Íu ÍN Êì ¯Ͳ ͉ Ê÷ /Í×Ê #͉  !d8Í‚ ; ÍÂ0 x±Â9 à ͭà ͋ Í® ÍÑ Ã n ÍÍQõÍñ(_Í× ÍÉP Í> Íy·( ^ ÍÉg ÍÉ' Í> Í}·( C ÍÉ5 ÍÉÍu >Í® Ê dͲ ÍÜ ø!d; ÍÂX x±Âa à Íu Ê÷ /Í×Ê #͉  !d[Í‚ ; ÍÂD x±ÂM à ~·Èþ-À#~Íf #~·Èþ õ͉ èÍ; þLÊ| 2…r Íà >Í® ÉÅÕåþ%( w·# õáÑÁÉþd(þh(| Íà Õ/Ím ÑÕ¯Ím ÑÇõÅÕåŠ ÍáåÍ’ × ÍáÑÁñÉ~·Èþ À#õ>ñðÚ Íà ú ÍÃ1™:€·Ê7!ÍZÊ7ÍÔÊ/w̓ÍZ( \ÍËÃB!w\ÍËÃB~·Èþ-À#~Íì#~·Èþ õÍZèÍ þF(þH( þL("þT($þV(&2UE ÍÃ7>2sÉ>2uÉ>ÍÉ>2tÉ>2vÉZ Í ÍÃ!wÍc} Í!€\Í<ÍcB ÍÍsÂ?ÍÂ?:t·(ͺÍ‘ Ͷ ͶͨÍ_Ã?!€ÍŠx·ÈÅþ€(H >€(6#=øÍ>ÁÀxþ€(ٯɀ€!ùÍŠÀx·(~þ > Íò> Íò#îá>Íòyþ€ÈA>üÍ>É y·ÀÍ>€€É:s· \Í<(\Íé ͯ=É\Í<Ê3¯É  ͯ=ÉÅÕå\ÍõwͶñáÑÁÈ- ͯ=É\ÍÈP ͯ=É!wÍÙíS÷È‚ÃîåÕÅrͶ€í[÷ÍßQÁBÑáȤÃîí[÷ÍÜÈÆÃîõ:v·(ÍñÉLIBCFNÅÕ#~+þ:(¯ ~Í Ö@##Íͯü~·(þ (#õ·ÑÁÉ~þ(!þ (þ.(þ*(Í #ç~þÈþ È#þ.Èó> Í7ì#>?Í7äüÉÅÕå·(Æ@w#6:#Ífæþ (6.#Íf>wáÑÁÉæþ (w#ôÉýÉLIBHFN2~ÉÅÕÁ~·( þ (#ó·õ>åÅá:~·ÄÍ©áñÁÉåÑ~·(þ[ #~þ(Í#ê>ÉÅÕåÍëæþ (6.#Íë>wáÑÁ:~·ÄÉæþ (w#ôÉýÉLIBSÃ!° ÍÃI:·(! ÍBÍSÃI:·(Ì Í! ~·(ÍBå\!Í' ÍSáé:·Ä› Ãé!€\Íž ÍÅ  Í!ÍÅ w ÍÍRÀÍ·À:·(ͲÍœ Í  Í Í£Í É€!€Ík AÍÎÀô=È<É!™€€Í“ 1þ ÌÖþ(Íì 7ëÍþ¯ÉÍ“ þ È2> Íì :ÉÑÑõÍþñþ å ͯ=ÉÉ\Í ·ú?Ë'Ë'Ë'Ë'Ë'ÅO!€ # í°Õ\ÍÑÁÖ¯É] í°¯üÉ\Í·ú`¯É ͯ=ÉÅÕårÍ \ÍáÑÁ€·Èþ ·É8 ͯ=Éy· €ÍkÀ ¯É\ÍÈZ ͯ=É!A¶Í; íS—È}ÃP ÅÕåHí[—ÍD wÍ áÑÁ€ÈŸÃP w#x·(¯É!™€ÍÎÉ>€TRþAØþ[ÐÆ ÉþaØþ{ÐÖ Éî Éå~þ(Íw#ôáÉå~þ(Íw#ôáÉ~·È#øw·È#øÍPÈÍZÉ·É~·Èþ (÷#ö~·Èþ À#÷ÅÕååÑ~·(#ù6$å Íá6áÑÁÉLIBXTRSUnable to obtain HOST error message $** normal speed ** $** high speed ** $í(Éí0Éí1Éí2Éí3Éí4Éí5Éí<Éõõz³( Íñ€Õá~Íè 6 #6$€ ÍñɆ Íôå>Íë}áþ(Æ0_¯É4>P·ÉõÅÕå:Ô·( ¯2Ô:Õ·(DáÑÁñÉõÅÕå> Íëy·(î2Õ>2Ô> !ÍëÁ ÍÑõÅÕå> Íëy· Ä2Õ>2Ô> !Íë¬ Í§þ08,þ40(åõÕá6d#6i#6s#6k#ÕÍ"s#(Íw#Ñ6-#ñw#6áɯÉÍëy·(î2Õ>2Ô> !ÍëÁ ÍÑõÅÈ!™GÍÎÉí[—Í> ÈÂÃP õ:·(ÍñÉLIBCFNÅÕ#~+þ:(¯ ~Ín Ö@##Íd Íd ¯ü~·(þ (#õ·ÑÁÉ~þ(!þ (þ.(þ*(Ín #ç~þÈþ È#þ.Èó> Í™ ì#>?Í™ äüÉÅÕå·(Æ@w#6:#ÍÈ æþ (6.#ÍÈ >wáÑÁÉæþ (w#ôÉýÉLIBHFN2à ÉÅÕÁ~·( þ (#ó·õ>åÅá:à ·Äz Í áñÁÉåÑ~·(þ[ #~þ(Íw #ê>ÉÅÕåÍM æþ (6.#ÍM >wáÑÁ:à ·Äz Éæþ (w#ôÉýÉLIBSTRþAØþ[ÐÆ ÉþaØþ{ÐÖ Éî Éå~þ(Íe w#ôáÉå~þ(Íe w#ôáÉ~·È#øw·È#øÍ² Èͼ É·É~·Èþ (÷#ö~·Èþ À#÷ÅÕååÑ~·(#ù6$å Íá6áÑÁÉLIBXTRSUnable to obtain HOST erÃ\ Export CP/M file(s) to the host operating system. Usage: EXPORT [-H][-L][-T][-V] cpmfileref [hostfilename] Where: cpmfileref is the local file to export (use "?" and "*" to specify multiple files). hostfilename is the name of the file to create on the host (converted to uppercase by default), use -L to convert to lowercase and [ to toggle case of next character. -H switches emulator to high speed and restores speed when done. -L converts hostfilename to lowercase. -T exportror message $** normal speed ** $** high speed ** $í(Éí0Éí1Éí2Éí3Éí4Éí5Éí<Éõõz³( Íñ€Õá~ÍJ Âz 6 #6$€ ÍñÉè  Íôå>ÍM }áþ(Æ0_¯É4>P·ÉõÅÕå:6 ·( ¯26 :7 ·(DáÑÁñÉõÅÕå> ÍM y·(î27 >26 > !ÍM #  ÍÑõÅÕå> ÍM y· Ä27 >26 > !ÍM   ͧþ08,þ40(åõÕá6d#6i#6s#6k#ÕÍ„ s#(Íe w#Ñ6-#ñw#6áɯÉÍM y·(î27 >26 > !ÍM #  ÍÑõÅÕå> ÍM y· Ä27 >26 > !ÍM Íe w#ôáÉå~þ(Íe w#ôáÉ~·È#øw·È#øÍ² Èͼ É·É~·Èþ (÷#ö~·Èþ À#÷ÅÕååÑ~·(#ù6$å Íá6áÑÁÉLIBXTRSUnable to obtain HOST er text file (CR LF becomes LF, stop at SUB character). -V (verbose) display "r" for block read, "w" for block written. $Invalid option "x" $ERROR: Must specify cpmfileref $Sorry, no files to export $WARNING: Multiple matching files - ignoring specified hostfilename $ -> $ERROR: Unable to open CP/M file $ERROR: Unable to read CP/M file $ERROR: Unable to close CP/M file $ERROR: Unable to open HOST file: $ERROR: Unable to write HOST file: $ERROR: Unable to close HOST file: $WARNING: No sub character f----------------------------------------------- ; open the cp/m filename in fcb1 ; entry: (c_fcb1) contains cp/m fcb ; exit: z indicates a successful open ; af,bd,de trashed (hl saved) ;------------------------------------------------------------------------------ 0392' E5 push hl ound in text file $1Z:€·Êá!ͼ Êá͈ÊÙ\Í- ͼ (lÍå d~·Èþ-À#~Í #~·Èþ õͼ èÍn þH(þL(þT(þV( 2Šz ÍÃá>2É>Íá É>2É>2É Í ÍÃ:·Ä¶ Íx±Ê x±Ê bdos b_fopen,c_fcb1 ; open existing file (a=0ffh is error) 0393' 11 005C + ld de,c_fcb1 0396' 0E 0F + ld c,b_fopen 0398' CD 0005 + call c_bdos 039B' E1 pop hl 039C' 3C inc a 039D' C2 044C' jp nz,retz ; ok bdos b_couts,m_c_open 03A0' 11 0130' + ld de,m_c_open 03A3' 0E 09 + ld c,b_couts 03A5' CD 0005 + call c_bdos 03A8' C3 044E' jp retnz ; error MACRO-80 3.44 09-Dec-81 PAGE 1-15 03AB' cread: ;------------------------------------------------------------------------------ ; read a block from the cp/m file ; entry: (c_fcb1) contains the cp/m fcb ; exit: z indicates a sucessful close ; all registers trashed ;------------------------------------------------------------------------------ bdos b_fclose,c_fcb1 03CC' 11 005C + ld de,c_fcb1 03CF' 0E 10 + ld c,b_fclose 03D1' CD 0005 + call c_bdos 03D4' C8 ret z ; exit: z indicates a successful read ; af trashed (bc,de,hl saved) ;------------------------------------------------------------------------------ 03AB' C5 push bc 03AC' D5 push de 03AD' E5 push hl bdos b_frseq,c_fcb1 ; a=0 is ok, a=0FFh is eof 03AE' 11 005C + ld de,c_fcb1 bdos b_couts,m_c_close 03D5' 11 0166' + ld de,m_c_close 03D8' 0E 09 + ld c,b_couts 03DA' CD 0005 + call c_bdos 03DD' C3 044E' jp retnz MACRO-80 3.44 09-Dec-81 PAGE 1-16 $eject MACRO-80 3.44 09-Dec-81 PAGE 1-17 03E0' binary: ;================================================== 03B1' 0E 14 + ld c,b_frseq 03B3' CD 0005 + call c_bdos ; show action 03B6' F5 push af ; 21JUL99 save A 03B7' 1E 63 ld e,'c' bdos b_coutb 03B9' 0E 02 + ld c,b_coutb 03BB' CD 0005 + call c_bdos 03BE' F1 pop af ; 21JUL99 restore A ============================ ; export a binary file ; exit: z indicates a successful export ; all registers trashed ;============================================================================== 03E0' 21 0080 ld hl,c_iobuf ; all i/o thru cp/m io buffer 03E3' 06 80 ld b,c_iobufsize ; fixed block siz 03BF' E1 pop hl 03C0' D1 pop de 03C1' C1 pop bc 03C2' B7 or a 03C3' C8 ret z ; ok 03C4' 3C inc a ; a now 0 for eof 03C5' 28 03 jr z,cread1 ; eof ; hey! I'm getting a=01h at the end of the file, don't print ANY message! ; bdos b_couts,m_c_read ; erre 03E5' binary1: ; read cp/m block 03E5' CD 03AB' call cread 03E8' 20 06 jr nz,binary2 ; eof or error ; write unix block 03EA' CD 02E1' call uwrite 03ED' C0 ret nz ; error 03EE' 18 F5 jr binary1 03F0' bor 03C7' C3 044E' jp retnz 03CA' 3D cread1: dec a ; reverse the "inc a" for eof 03CB' C9 ret 03CC' cclose: ;------------------------------------------------------------------------------ ; close the cp/m filename in fcb1 ; entry: (c_fcb1) contains cp/m fcb inary2: ; error reading cp/m file 03F0' 3C inc a ; was 0FFh for eof 03F1' C8 ret z ; eof was encountered 03F2' 3D dec a ; reverse the "inc a" 03F3' C9 ret ; error $eject MACRO-80 3.44 09-Dec-81 PAGE 1-18 03F4' ascii: ;============================================================================== ; export an ascii file (convert cr lf to lf and stop at sub character) ; during: (hl) unix buffer ; (de) cpm buffer ; b bytes remaining in unix buffer ; c bytes remaining in cp/m buffer ; exit: z indicates a successful export ; all registers tr jr z,ascii5 ; yes 0425' ascii4: ; store current character 0425' F5 push af 0426' CD 043D' call asciiput 0429' F1 pop af MACRO-80 3.44 09-Dec-81 PAGE 1-19 042A' ascii5: ; finished with current character 042A' 32 0184' ld (lastchar),a ; remember it as last character 0ashed ;============================================================================== ; setup unix buffer 03F4' 21 046E' ld hl,unixbuf 03F7' 06 80 ld b,c_iobufsize ; setup cp/m buffer 03F9' 11 0080 ld de,c_iobuf 03FC' 0E 00 ld c,0 42D' 13 inc de ; bump pointer 042E' 0D dec c ; one less char in buffer 042F' 18 CD jr ascii1 0431' ascii6: ; cp/m eof - anything in unix buffer 0431' 3E 80 ld a,c_iobufsize 0433' 90 sub b ; a has bytes used in unix buffer 0434' C8 ret z ; buffer empty 03FE' 79 ascii1: ld a,c 03FF' B7 or a 0400' 20 08 jr nz,ascii2 ; cp/m buffer not empty 0402' 11 0080 ld de,c_iobuf 0405' 0E 80 ld c,c_iobufsize 0407' CD 03AB' call cread 040A' ascii2: ; check for end of file 040A' 1A ld a,(de) 040B' FE 1A cp ; flush unix buffer 0435' 21 046E' ld hl,unixbuf ; buffer start 0438' 47 ld b,a ; bytes to write 0439' CD 02E1' call uwrite 043C' C9 ret ; put a character into the unix buffer 043D' 77 asciiput: ld (hl),a 043E' 23 inc hl ; bump pointer 043F' 05 sub ; sub is eof for ascii file 040D' 28 22 jr z,ascii6 ; done ; was last character a cr? 040F' 3A 0184' ld a,(lastchar) 0412' FE 0D cp cr 0414' 20 0A jr nz,ascii3 ; no ; current character a lf? 0416' 1A ld a,(de) ; get current char 0417' FE 0A dec b ; dec count 0440' 78 ld a,b 0441' B7 or a 0442' C0 ret nz ; buffer not full yet 0443' 21 046E' ld hl,unixbuf ; reset pointer and counter 0446' 06 80 ld b,c_iobufsize ; bytes to write 0448' CD 02E1' call uwrite 044B' C9 ret $eject MACRO-80 3.44 09-Dec-81 PAGE 1-20 cp lf 0419' 28 0A jr z,ascii4 ; yes ; store cr which was not followed by lf 041B' 3E 0D ld a,cr 041D' CD 043D' call asciiput 0420' 1A ascii3: ld a,(de) ; get current char ; current character a cr? 0421' FE 0D cp cr 0423' 28 05 ;============================================================================== ; misc routines ;============================================================================== 044C' retz: ;------------------------------------------------------------------------------ ; loads a with zero and sets flags ; exit: a is zero and flags set ;------------------------------------------------------------------------------ 044C' AF xor a 044D' C9 ret 044E' retnz: ;-------------------------------------------------- cp nul 045D' C8 ret z ; found nul 045E' FE 20 cp blank 0460' C0 ret nz ; found non-space 0461' 23 inc hl MACRO-80 3.44 09-Dec-81 PAGE 1-21 0462' 18 F6 jr skipblanks 0464' termstring: ;-------------------------------------------------------------------------------------- ; load a with non-zero and sets flags ; exit: a set to 1 and flags set ;------------------------------------------------------------------------------ 044E' AF xor a 044F' 3C inc a 0450' C9 ret 0451' -------------------- ; append a nul to the end of a bdos console input line buffer ; entry: (hl) 1 byte length field followed by string ; exit: (hl) first byte of string ; f,bc trashed ;------------------------------------------------------------------------------ 0464' 06 00 ld b,0 04 upcase: ;------------------------------------------------------------------------------ ; convert character to upper case ; entry: a is the character to convert ; exit: a is now upper case ;------------------------------------------------------------------------------ 0451' FE 61 66' 4E ld c,(hl) ; bc has length 0467' 23 inc hl ; point to first byte 0468' E5 push hl ; save start of response 0469' 09 add hl,bc 046A' 36 00 ld (hl),nul ; terminate input 046C' E1 pop hl ; restore start of response 046D' C9 ret 046E' cp 'a' 0453' D8 ret c ; smaller than 'a' 0454' FE 7B cp 'z'+1 0456' D0 ret nc ; larger than 'z' 0457' D6 20 sub 'a'-'A' ; convert '[a-z]' to '[A-Z]' 0459' C9 ret 045A' skipblanks: ;------------------------------------------------------------ unixbuf equ $ ; space for unix ascii buffer end export MACRO-80 3.44 09-Dec-81 PAGE S Macros: BDOS Symbols: 03F4' ASCII 03FE' ASCII1 040A' ASCII2 0420' ASCII3 0425' ASCII4 042A' ASCII5 0431' ASCII6 043D' ASCIIPUT 03E0' BINARY 03E5' BINARY1 03F0' BINARY2 0020 BLANK 000A B_CINS 0002 B_C------------------ ; skip blanks at the front of a buffer ; entry: (hl) start of buffer ; exit: (hl) first non blank ; z flag set if a nul character was found ;------------------------------------------------------------------------------ 045A' 7E ld a,(hl) 045B' FE 00 OUTB 0009 B_COUTS 0010 B_FCLOSE 0016 B_FNEW 000F B_FOPEN 0014 B_FRSEQ 0015 B_FWSEQ 03CC' CCLOSE 0340' CFILLFCB 034F' CFILLFCB1 0358' CFILLFCB2 0364' CGETNAME 0386' CGETSHORT 0388' CGETSHORT1 0379' CGETSKIP 0392' COPEN 000D CR 03AB' CREAD 03CA' CREAD1 0005 C_BDOS 0000 C_BOOT 0080 C_CMDLEN 0081 C_CMDSTR 005C C_FCB1 006C C_FCB2 0080 C_IOBUF 0080 C_IOBUFSIZE 31ED EMT_CLOSE 30ED EMT_OPEN 32ED EMT_READ 35ED EMT_STRERROR 33ED EMT_WRITE 01D2' END 0040 EO_CREAT 0000 EO_RDONLY 0200 EO_TRUNC 0001 EO_WRONLY 01A5' EXPORT 01B5' EXPORT1 01B8' EXPORT2 01BF' EXPORT3 01C2' EXPORT4 0184' LASTCHAR 000A LF 002B' M_COMPLETE 0166' M_C_CLOååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååSE 0113' M_C_MISSING 0130' M_C_OPEN 00F4' M_C_PROMPT 014B' M_C_READ 005E' M_F_INVALID 003F' M_F_PROMPT 0000' M_NL 0003' M_USAGE 00C3' M_U_CLOSE 008C' M_U_OPEN 006D' M_U_PROMPT 00DF' M_U_UNKERR 00A7' M_U_WRITE 0000 NUL 01DF' PARSE 01E9' PARSE1 01F4' PARSE2 0200' PARSE3 0207' PARSE4 0212' PARSE5 0225' PARSE6 0226' PARSE7 023è $ Usage: export [[-n] cpmfn [unixfn]] $ export complete $Convert cr lf to lf.........: $Invalid flag $UNIX filename...............: $Unable to open UNIX file: $Unable to write UNIX file: $Unable to close UNIX file: $Unknown UNIX error $CP/M filename...............: $No CP/M filename specified $Unable to open CP/M file $Unable to read CP/M file $Unable to close CP/M file $ 1¨!Í] Í>Íâ(ÍãÍ÷ ÍÍÏ. Íà Íóþ- #~þN( a ÍÃØ#~þ( þ Â2' PARSE8 023B' PROMPT 0240' PROMPT1 026A' PROMPT2 026C' PROMPT3 029B' PROMPT4 044E' RETNZ 044C' RETZ 045A' SKIPBLANKS 01A5' STACK_TOP 001A SUB 0009 TAB 0464' TERMSTRING 0304' UCLOSE 0317' UERROR 0335' UERROR1 046E' UNIXBUF 0182' UNIXFD 02C8' UOPEN 0451' UPCASE 01D5' USAGE 02E1' UWRITE No Fatal 쯷õÍ]  ÍÃØåÍCÍ•ÂØÍ]ÁÂ(Åáå#~þ(þ ö6áÍËÂØñÉ> 2‚B Í€> Í Í:‚ÍTþN(þY ׯ·õ÷ Í€> Í Í!ÍgÍ](ÚÍCÍ•Äop Í€>F Í Í!ÍgÍ](ÚÍË ÕñÉA¶í0íS…Èõ Íñ6åÕÅHí[…í3uÍÁÑáÈõª Íñí[…í1ÈõÆ Íñ€Õá€í5Â8 6 #6$€ ÍÃQâ ÍÃQ\#~þ:+(> ~ÍTÖ@##ÍgÍgÉ~þ(þ (þ.(ÍT#ë~þÈþ È#þ.Èó> ü~þ.À#Éå\Íá<ÂO3 ÍÃQÅÕå\ÍõcÍñáÑÁ·È<(ÃQ=É\ÍÈi ÍÃQ!€€Í® ÍäÀõ<È=É!q€€error(s)  023B' PROMPT 0240' PROMPT1 026A' PROMPT2 026C' PROMPT3 029B' PROMPT4 044E' RETNZ 044C' RETZ 045A' SKIPBLANKS 01A5' STACK_TOP 001A SUB 0009 TAB 0464' TERMSTRING 0304' UCLOSE 0317' UERROR 0335' UERROR1 046E' UNIXBUF 0182' UNIXFD 02C8' UOPEN 0451' UPCASE 01D5' USAGE 02E1' UWRITE No Fatal y· €€Í®þ(":‡þ þ ( > Í@þ (õÍ@ñ2‡ Í>€È!qGÍäÉw#x·À!q€Íäɯɯ<ÉþaØþ{ÐÖ É~þÈþ À#öN#å 6áÉõ<È=É!q€€ Í!ÍgÍ](ÚÍCÍ•Äop Í€>F Í Í!ÍgÍ](ÚÍË ÕñÉA¶í0íS…Èõ Íñ6åÕÅHí[…í3uÍÁÑáÈõª Íñí[…í1ÈõÆ Íñ€Õá€í5Â8 6 #6$€ ÍÃQâ ÍÃQ\#~þ:+(> ~ÍTÖ@##ÍgÍgÉ~þ(þ (þ.(ÍT#ë~þÈþ È#þ.Èó> ü~þ.À#Éå\Íá<ÂO3 ÍÃQÅÕå\ÍõcÍñáÑÁ·È<(ÃQ=É\ÍÈi ÍÃQ!€€Í® ÍäÀõ<È=É!q€€åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå…‘VÔ•%Và@h(H Nf9”t 2žó‘Ð@[-‹MÅÑŒàm3„³©¸Òx3‹¥Ðh(H OyÈè 1›Í§a”èe‚„„3y¸ìe93€Øf âa˜\. …Âáp¸\: &㱄Øi2 ÆÃ œ IÄ’À€Ìi6MÆi”\. …Âáp¸\. …Âápè@$*›Œ&#a”@t7ˆ ç)¸@U'K1¤Øe…Sq„Äl2ˆ†ñÜäi:DRq$° 3M†QЀHU7LFÃ(€èo͆ó™”@U'K1¤Øe…Sq¬Üo;›„Rq$° 2œŽFó4$!”äјÒl2›Œ&Ó(¸\. …Âáp¸\. …ÂáЀHN7ˆey4@f4› ¦ã ´Ê 9œ ¦3I˜Òe2ABB©¸Âb6DCx€Þp2›„2€¼š 3M†Ph(HU7LFÃ(€èoŒ¦ €†P“DcI°Ê  ¦ã ˆØe â°Þs2ˆey4@f4›  ÐP m(…fÕ A›NÀƒ6mßYåååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå·€ 0fß@19›AÙ·0 #JÀÀ–hÃ4  f@‡›øZ ˆÏÏâp «ÀàK4 aÝPùü_ÂéW­Þ¬Ú´ „h˜8Í€wTÊͨlÛ$º ,Ú´ÁaRP&+…Ê#??€€3ø@ { €mÈa]P‹$|  €~³@ Š>À¦h àK4  € Ú¢þ' ¯âÈ®¯[½B7Ð f@| LÐ(#@À–h!@€µ›V ¦m@fÙ 6%lÖÐp%šPñ$3@ Y P…fÖ@FmZ6™· @Õx²@$ElvŒ¥;Èz„l`8Í€!³•ªÅ$€ÒÝ‚vŒÃÇPp š0Z.CÔ#iÀÀ–hñ Ý¥»í²¡†³@ ˆ`@® í°©¨$l „ f@ :œ»ààK4 aÔà@‰p#??‡B±@| 'æmQkB1L fÖ@00 ›YÙ'çðP—ð¸PfÕ@Œ&uŸŸÀååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååCø@È¿…Ì€ÃÌ| ÂÃóø\À²\¡àf@ã ¦i€8Í€u8ŠÕr„K€pQš=CÆ0p š<\- Ý<Øu8zÉ—àƒ4 dk08Í€u8B€ ÛV 3o0õ2¬‘ n (8y[ˆ€fÚ°0Óø4(¬ ø ŸÀ¡@(| fÓÐ@Óø(½Y´ôâ2°€!0haš>@$ÜGfÞ&IÜF<-ØÜ@3o%^ÉW/ã aü{h5„ “óøÈ0ÃØ 'Ü ‘°ÂɜҀ€ž\¡àf@ã ¦i€8Í€u8ŠÕr„K€pQš=CÆ0p š<\- Ý<Øu8zÉ—àƒ4 dk08Í€u8B€ ÛV 3o¡†³@ ˆ`@® í°©¨$l „ f@ :œ»ààK4 aÔà@‰p#??‡B±@| 'æmQkB1L fÖ@00 ›YÙ'çðP—ð¸PfÕ@Œ&uŸŸÀåååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå  €€Í®þ(":‡þ þ ( > Í@þ (õÍ@ñ2‡ Í>€È!qGÍäÉw#x·À!q€Íäɯɯ<ÉþaØþ{ÐÖ É~þÈþ À#öN#å 6áÉõ<È=É!q€€ååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååEXPORT PRN%DEFGHIJKLMNEXPORT COM OEXPORT REL PEXPORT $$$ååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååxtrs-4.9d/cpmutil.html000066400000000000000000000201641306603614600151050ustar00rootroot00000000000000Roland Gerlach : TRS-80 : CP/M Utilities for the xtrs Emulator
UP HOME

CP/M Utilities for the xtrs Emulator

Contents

Programs
EXPORT
IMPORT
XTRS
Bug Reports
Download

Programs

These programs were written for CP/M and make use of the emulator traps in Tim Mann's xtrs Emulator.

IMPORT and EXPORT also work (with the exception of the -H option) when running CP/M on David Keil's Model 4/4P Emulator.

EXPORT

Export CP/M file(s) to the host operating system.

Usage

Usage:	EXPORT [-H][-L][-T][-V] cpmfileref [hostfilename]

Where:	cpmfileref is the local file to export
	   (use "?" and "*" to specify multiple files)
	hostfilename is the name of the file to create on the host
	   (converted to uppercase by default), use -L to convert
	   to lowercase and [ to toggle case of next character.
	-H switches emulator to high speed and restores speed when done.
	-L converts hostfilename to lowercase.
	-T export text file (CR LF becomes LF, stop at SUB character).
	-V (verbose) display "r" for block read, "w" for block written.

Notes

CP/M does not keep an accurate file size. Binary files are always multiples of 128 byte blocks; text files end at the first sub character.

The CP/M CCP converts all command line parameters to uppercase, hence the need of the -L option and the use of [ to toggle the case of the next character within the hostfilename.

Examples

EXPORT -LT HELPFILE.TXT README.TXT
Export local file "HELPFILE.TXT" as a text file to "readme.txt" on the host.

EXPORT RUNME.COM
Export local file "RUNME.COM" as a binary file to "RUNME.COM" on the host.

IMPORT

Imports a file from the host operating system to CP/M.

Usage

Usage:	IMPORT [-F][-H][-L][-T][-V] hostfilename [cpmfilename]

Where:	hostfilename is the name of the file on the host
	   (converted to uppercase by default), use -L to convert
	   to lowercase and [ to toggle case of next character.
	cpmfilename is the name of the CP/M file to create,
	   existing files will not be overwritten unless -F is used.
	-F overwrite existing files.
	-H switches emulator to high speed and restores speed when done.
	-L convert hostfilename to lowercase.
	-T import text file (LF becomes CR LF, add SUB at end of file).
	-V (verbose) display "r" for block read, "w" for block written.

Notes

CP/M does not keep an accurate file size, both binary and text files will be padded to multiples of 128 byte blocks.

The CP/M CCP converts all command line parameters to uppercase, hence the need of the -L option and the use of [ to toggle the case of the next character within the hostfilename.

Examples

IMPORT -LT README.TXT HELPFILE.TXT
Import "readme.txt" from the host as a text file to "HELPFILE.TXT".

IMPORT RUNME.COM
Import "RUNME.COM" from the host as a binary file to "RUNME.COM".

XTRS

Controls miscellaneous functions of the xtrs emulator.

Usage

Usage:	XTRS action [parameters]

Where:	action is one of the following:
	   BOOT - reboot emulator
	   CHANGE - signal disk change
	   DEBUG - enter debugger
	   EXIT - end emulator
	   HIGHSPEED - high speed (autodelay off)
	   MOUNT [-L] hostfilename disknum - mount disk
	   NORMALSPEED - normal speed (autodelay on)
	   REPORT - report status
	   SYSTEM command - execute command on host
	   UMOUNT disknum - umount disk
	hostfilename is the name of the virtual disk file on the host
	   (converted to uppercase by default), use -L to convert to
	   lowercase and [ to toggle case of next character.
	command is the command (and parameters) to execute on the host
	   (converted to lowercase by default), use [ to toggle case.
	   Note output from command is NOT displayed in the XTRS window.
	disknum is disk drive number (between 0 and 3 inclusive).
	-L converts hostfilename to lowercase.

Warning

The XTRS program assumes that the emulator's virtual disk files - diskM-U (where M is the TRS-80 model and U is the drive number) - are symbolic links. For example:

$ ls -l
-rw-r--r--    1 user  group    213504 Mar 21 15:24 cpmutil.dsk
lrwxrwxrwx    1 user  group        10 Mar  5 12:40 disk4p-0 -> system.dsk
lrwxrwxrwx    1 user  group        11 Mar  7 13:49 disk4p-3 -> cpmutil.dsk
-rw-r--r--    1 user  group    745984 Mar 24 17:38 system.dsk

The MOUNT action deletes the diskM-U file, replaces it with a symbolic link to the given filename and signals a disk change (as if F7 had been pressed).

The UMOUNT action deletes the diskM-U file and signals a disk change.

Notes

When changing disks, remember that CP/M must also be told of the disk change. This is usually done by pressing ctrl-C at the prompt.

Examples

XTRS MOUNT -L DATA.DSK 1
Mount the virtual disk file "data.dsk" on drive 1. The actual command that would be executed on the host is:
rm -f disk4p-1;test -f data.dsk && ln -s data.disk disk4p-1

XTRS UMOUNT 1
Unmount the virtual disk file associated with drive 1. The actual command that would be executed on the host is:
rm -f disk4p-1

Bug Reports

Send Bug Reports and comments to Roland Gerlach.

Download

cpmutil.tgz
Source code and programs in a gzipped tar file.

cpmutil.dsk.gz
All of these programs (including source code) on a virtual disk formatted as a "Montezuma Micro Standard DATA disk (40T, SS, DD, 200K)" with 512-byte sectors. Be careful to configure CP/M with the proper disk format and drive parameters (40 tracks, not 80 tracks), or you will have problems reading this disk.


Comments and suggestions are welcome, send them to Roland Gerlach.

xtrs-4.9d/cpmutil.tgz000066400000000000000000000551731306603614600147550ustar00rootroot00000000000000‹®”>ì\olGv§þ©Ø1í$Ç©1ÓÊG)äJ¢*VN–­Ø=Ëv%'gØ Ü%¹7^réÝ¥)¹ˆÎýó¡¸/mчàж@ ´ýäë0¢ì8Äܱ8up ôÔí¥‰¸7w‡–è{3»Ë]Š’ì”+å ¯ajwæÍ›÷Þ̼ù½Ù™:=34sâ°ÇÍ+Å##žX,Ûÿâ•ã‡=±±Ä?’ŽÅà>‹yHÌU©Œ«¤é‚JˆGUd¡YŸn³ü_ÑkœL±'Kì ŽÃý”RÐÅ‚®%ƒã!­*D–Rª .ÒÜÓ%µ¨h"f³RAÔ€Íó3D¼TtxK‘TFÑHZeyUæi™É©Ç7ª…¼É¼XÈÀä$MWÔE¤‹L¾úÊ‹/’Ùo¼BâC1r¼ é’ U”EA‡€$ÆOžž $q2™Éˆ’IÍçµy’G©‡‚ÁñCm½@\AKKIçUH뢪µ½Š`¡$`Ì@,– êBÊxx1”³Æýd.˜Vû#¹ V2ˆâ¡Óì‡â.@[Ôt1O„LF5MtÁé )EÑM€qRÔ<ÁáªîÍ"Y€+7€´’’²H‡)©ô¼BR‹ºˆ¹™’•9B3Ó%UÅΖ‘´‹ä«¤¤‰*­:¬E9J)iRu±©Æl:7iG§(mVR5~e‘¤að€¿ )YI_4¨/dTé²H‹˜ÅÇ M3 ²!o'øZ,ž£|esL2}±è¤zѤ“J\pÐL!¸€CÚ¤ÐâŠ#H¡Å17•†\Þ‘{”æò†ê¼©z‚©®‰ qf]ÝùfÝù&ÝùfÝù–ºóMºó-uçºó-tçºóMºóÝù†îð[PtЦI#ÊeQ-«’¬‰”eqÌ€.•1:fɰ±X/ΈY¡$묋–²YÖù(¥&]aê¤ ‚Y´3‹YdÙ’cƒ[:ŸÃ9© a^ÏäTòyôЂ:_B¯«±š®š%â¬YéPkYÀ§BÇuÚtú€AyYJ‹¨œ„ž_)¸àfØg•j—ÓÑ"¸ô|0 e )ò}˜2Ì)¢™3•”e‰é(”[œäóð„Sp¾3CÞrâhNL 0?’¢ªÌ#3 JKÓw1£ÃøÑGR¡XÒ™ˆ ’ž äPcÖ¡…•’n–æ¥!ƒ/±âèÁ’±UyÍš[Z”‡.!æ2"œ0R ×P¨,AÏê?Ð?`¨¤Y“ÔZ•d€ ÍNÎå……(Iô(ÑŠ4~VQÚ,+8KК¡ë3L0MÔ© š(g AŽ~JÓºáyf¡I„‹šLÒ¢Y¥㇕¦e1¼à¬]N³0øMÃG/iÀ4òÑaºLOçÐQPG ¾ô+2¬Â´ €ŠÍ଻г!¾>HB/¥%á)ˆ€‡tÅàE«E×D”‚¼HK›„ÖO§/V¿1úEAMç(UcjÛL%›ë=4Ѭ¦%RšVáŒ"Rå4ffZ’5ñ¡‰Xt˜&F¢/&èpИ½ àÑ ÄÃ7Ë‹y_2qUM¼dˆ;bˆ{©e¢2”¨Ü m&ÂyF44/D J”.‚Üb™i ó¢nôû8Õ`MVç#0͆†â£Øõ'hßo¿c·ãq2ˆ¨«( ‹D y´ß­Y•¦gס; ÇVÀQH·îß,å‹Ax*–´`¢[ÒÂÔ#B«Ìkf^*mÞeDó.'cÑ7Uƒ ðM8=Œúè}ZÊÙ(¸Æ`逄Îs†ï¢”ã–ILƒ`Jj @5‚&Ü0ÁàFÈ͹ç‘â?Ŧ¦Oº»°Iüañÿh,Æóü(Æÿc±øãø+®qÒèD(S› ¢ “:àyUÉ[Ù“S‚V‹ç^ˆA`¬‰ù” ó²p¨7Æ•¡æeƒéR!MANO.¥bIF$A—LØÏ¦§kMËÇË·±ˆ’+$+ !Ö@†b¼ 4• QÉx •6~‚ô™f¶íwÒ¶F¡³ý­Ý4µÙN¥6haB!æ~í…l-öådð‘­‰®  «¬á6àŽÑ²ñ)]±ô†ã†÷±£g·Õÿóc±Äÿ{ìÿ·â¢þßèëùšÝfÿL\ÀÎãSƒY€dÍéà‹8úÙ&GŸ!íªCAdÏ<Š^V°BÀpó’®5< ó”#V²Éwäµ0ÁâèÒ4M¶¥µY›y\0Î ×Æ1ôz{€ßÔr8GµY¸†âÚÝÔ¼¬¨™5šƒÃÝhh^T¡Ûl¹Þy1¯à»›6WºCPCwCqŠÙè+’fd6#}žÆÉ˜žÁPʲŒn<8 +.sÓJ4Âr¯XÊlí¿á…î}›ã?~4ÑbþçÏÿ[q±ùãøï˜‹ñ_Sø—SŒ…Fþµ d ²RU7¢>ˆ°ô\“Є֖ø"²æ¹0F.Šb‘ i”ˆ²U@G›X\\swÙ‚5 ·¹3vØ%JŠ¢ Ý!OšmAª*^*I,:mõ^ÀŠÁ@èF¥)%‚d¶è%ëD΄ƒi©T,2k6ÇÑM #(†…ìܢ䋩iJ#Û´dÆyXê4do„Ós4ÔpÈ ådzòf ÚÜj~ãÞu’S)Œv› u34,‡(“æ ÐÒšñF&­dX›m¦££i6pKˆõѸ»¶Þn¯ß¸À½Ï™ÝÖù,‘ˆ¯™ÿGïÿÚ’‹ÎÿFXoþ§Ùmžÿ§,Ÿk{qÛÖUt÷²»«¶?ÇŒíœçT­_#lÞx?ïÖ‚+HXÚB³XSï—ß,iWÌ’ ó"=0‡ vU¾ì‘݈†ý‘ ¨N õPj`¥5%bAÞÄuNص¶r®aa»®ŽÆm²r‹‘¹-V¶ƒó6ÛÁ´²R\¼àÊÒßp^ß^vКqç@c^c£^s$óEíêIk¬Þwg|ÒȵÉåªù3íGÑbþMLl®e#=‚ù[¸aþV³æÇÝP¸úìFœQ*²•mŠâJ)cËfµfÇb„YøjÙÚ<Àp›?Ä nGmƒÆöµ'ˆ@é1WŒb]˸it›Aq º”±‚€oðYSE»]†¶1Pr·Z±ÖaÛh`ì£s»AÌ^ÙæŒ&aZÙ…¬gp&G£ç?¼¹±Ï”Â`“XnÙ—¾Ò¹\°îid½.’¡;€Ùa#ÜRGA¡“Š.&ÙZœFxCÀÊ42¥2#z^IH_dÙtôÌ ¬]Z´ ­q³ÉÚ­wzmŽÿ!¼‡æ›suhãõŸøp,Æ7­ÿð±Äã÷?[rÑõ³¬·Äò›V€þÏK@È•ˆy|ñƒ{ÌÛ¹ö³ «;¤Ö~w´a¬dœ”i±/?Ibè¹O}#JDUÅMê¥| ÁH–î9çšÞ0 X¯ÌÃ7ÈÐÚãßf¥lfÃsn­(è¹h“é,}j®¤|Q.Ë‚\Â×ô˜)xi‚rk"y%#¶ÉØ”_fÙØÂ4\HKËÇÛzAÿ½„teg'L†/a’šÁcƉ!šRV)qƒ¦lúä/1NiUtƒËÑDq!mž å­D]…1fQš©„ß…ŒEK“]ì_ô(Š{ÌhŶô‰6Ëh3=ñáš è0*ÐM5¶ŽÝ Ûé£Xeô K‹ñÓf=mvd‡bò‹éi3¤¬‰âE— YÎAÈ"6òÒ<‡õÂ Ý (Kº.‹ƒxÔRÀݺ8/ªm²3k:<D—y¤}ÍkZ{Ë,ƒ;uØÞ*rXÅêdö#Å­Þ£³Bk"šFÇSgÖÁ«,8VÛ@‹>n­‰âÖFµ¿˜]}=Ö*ðj³m-•—4^ Ù[Éľt»á`,.¾@ŸZ!EÏ©[# FŒ¦›4V“mJ×~`“¿€U¸¦/½¦°n K´¤£{Bm„.g0&ôp";Á ‡÷úš‘‚Q˜*ͳo\P \!4q^4HpgFÃæÁ>ô¬èhR%]ÇW$C&_*‰*Z£HK)¸”òÒ¤$‰GÉp”ŒDq1k”p#§/xŠ9)ÍŠ³³¼ vF¦Fè· lc„›2’BærBú" ‹8áf$<»xBHiNæ¦Rñ8;!ª¯elÛtûPœA'a±a‚8ßšfYÂÒ!ŒA"M6wµMÉ(-~–œÃ nÖ4)lÂÌÅa þÏ‚º·Ý—9FëëFn™½7ÀcPt´Á %fqÓ›ƒ=¨[PÌGç¤èØŒFÍëÜöäx¦vn<g/Q4Ý‚.y5)ÔfÃÙ=.xm®ÀÚ~FÙ“¦Mb‡Hÿi¶*8C³GNGÙ<§Áô"ÛP ×Xõ¦î˜‚™¦W JÖV é÷GIÿp?õý#ý®†0!jE7Þ;Ìç­ ŠZQto;>ê’“æsîè2:ÃÁ†u0M¢€9pË¡ñ2š׆]]l)¨yÙm Šš7kTÄÞ•=”ãäc¡’nŠEU)ª>ST±ö§`¬öÇpXÒ±Écs¸¿áŽ›7;¸’>|<{vðlŸÃ‰P—a¯iJÈ8œ¡À¬,i"àGÁOfMµ6ÈÛ¤N›í¸Ý+Ð¯í¼Žž=}jöÌÐÔ©÷êØdÿïh"³ÞÿPºx|lìñûŸ-¹n½îÛ<ºPTT½ñíN@·gmQŠègé§•èK•¡ÁAöAÇë@äüà±7Ξ€ÿgàÿkoà†~d¥ŠYr™˜þë ,ûMðPÖFn«cße¡ßÓ¡oÇQ®Á!ì…@ßË}ô]mßÁ>ê—‹bZÊB V’u©(³3úÚˆ°Wi2§÷€ÌðÞ¬‚®žCjÁÒÖ¨®õ5’Z4¿¤±Š4x¶]“•µï¤âž§ÖTæ)Ž46‚Ò(`D‘ÎÚô[¯Å…23>£I¸ªF2JA¤,N˜’hÄa»H”ðŒa\tPkpS³äÄ4Di?½qb:Š_÷i̽z¸!+µïàk„ƒzRŠ&XKŸÚG4ýöŸ±ˆÙW¶§ñp8p¼pY¥ t.ºôѷЉGggOÍ&É ŒJ«u½æU]Œ¨ammï%¾99{òøÉW°¸Ñò˜Óü¸‚F =]B;2e.ív&8›b¼ZR¬›Ð¯Yã£!hƒµÝ˜‚}„kCZͱSsg(E²… tÅ{cVÄ2ÌI7iÙâú©+\µºˆµÝ>éÿË?çK^õTÞ_ñíÿmOí‚pSû}ßûúB¯{jƒHáäÐW¼µ{pf©²\¼Yªý¹/‚÷„<€üðOk…`ý··~‚{®~†ÛW#ü·»BWºvj^Ï­ßDÿ”·:ÑQ[ À/ÿ4ÞóÏx«¡?`$¡®Fêñ$ŸòVÞ½Þ[ó÷,üíûÝþ^ø}Òk¿?ô=ƒÛqò+Þ ·w¿‡Ô÷ÔæüfJO臌r–*ÜȽJìáûƒ@·þˆ2ÿnï­|û¯zPÁ? ÔnC¡nV(á©Ì¸Ôf{nÔ*=7’OooíûþpWíOüûvÔÂ}Aø©ýEO-¨†®z€WíbñOÖþ±çFø³CË/U÷¿íõ]…¬žÚ÷x}Ç?ð×÷rþÚ'=d,üq­Þs­Š9¡zp™Ö7±3üÉg}Õ;á®;á§Åýzé Ýc²];T­‚À;Ch-éðx*¿|¹çýæ¿®Û>Ï)$éèõ¬~ï.ÒîÚ;7Ã\Û] ½á¡é×|áÝ{vý7eõ$dW~ù› Iè«’ÛwïíSA;$x ’VîÜÜyšºƒtVª¡,ºÅ ñ‡¨Þ7v\Û»‡2ÜYË¡s سc²3t½£6Þ»:÷ïrè­î[§{¡Šc>ÏêùïxkGz÷•¡2¨Äwu9ôg˜[Žx*\ç5fB°huâê.ÃÃ+xOKMô.‡ÞAÚÉg°mvvB}÷«ì#PžÛw#K_«'¹îk»Ã%èš|}w$²Ç×SË|]ðcغˆ¿N¸®HøAåÎÍêRÝÃí‡ç_«qÏÖrÏAÉÝ‘=»þ2 §/GêCËáŸMÚÛð'‘‰—ñï¿R[‚>{×{_/GIZÑr`ï¿} xõ$†"Pår`ÂS«,ÕWÞÙõYuÏ®ÿ©²sËÿ“°¹ "€À õ†Vy0áÙ}ïöJò'Ê»W‚µÞàÊý›Õ{w€hwý< DPâžZ9¸{O$ü@‹‚`í3AGí3AV»Á§¥sgf=õÉ×Ïÿè=R­ ?®ÿÖ> ÕOIõV⯉Ár$üÙJóãÒîÊ2ˆúó½åÊ2ñóÚ÷ƒËક*õÜç‘ðÑ»‘ðç  þ‹Ä{´“¬$°ƒUÝ;ÛÃÁèüàXÑÏð c¹€<Èm„&y<«\u5V]WWùêêpuu¤º:Z]}©úàÁ•¿ƒnƒ܇N|w¥cÉSûõÞw®ôÁHâ\šY ý4HïŸݛðÖfzßZ©{9ï{± תûF&NWª@­d¢·Â=qOô&Çàî¹ðPê>Íšx -V¸Où±^py‰Þ‰û=½Šô2Þwl”ä]'e¥ÜiPþU=öB´>ãî=¸»’ÈDR$¡E#wk¿×«EÀMaÓÜI FîCgô¬TÁË´¡þ힣ŽÏl{ü7kÿŽ<Žÿ¶âºõÝ.+”c}B¹é7Ö„sŽhâ¼Éxîá¡üÃcí .ÅÚˆ  ~AF6‹ì›¾Úºh|C¼ÎÐø#¢þínò_•+þv…ÏcÝŸÏùá¦öO]ï?ß*wÖ~×)b©Ú¼·wï/wZ÷–þ¤ËÂÒçü€¥Ÿð×§Cãàé>ÀÓO•µ#tÔÉcÝà µNÄÐ%ü­}ˇ÷:M¹ÜY ëhFÕPs-í½Å ðû’Ó³´šæ}çåîZþ&õN„¼ß ÷ºò^÷ä½î­ýµ·vÁ{ëånD¼ßœ¶|»~•{Ð\@çKx"‡LxoÞX€Œ¯!:Þyuÿ/:úÀº§–êAâ´ûŸÝAø‰ìú4¼2±îëW—'Ä ‚òÕÝ{v,VnÀePMj²Ï­/q{L¸ú¨ÃD›˜ô æ¾?ì…Š{;m󞆧7¯{ïÃô¼ì´—dØõ´•ƒY2å‡þÕ¹Ï;—C¿ÓqëSÿ½»·_÷v\ûygí_ü¿qóð•åÐ_b.Múgÿrè=|z¼Ü¹:}Âo¡ÓN€µNßâÓ'ü-Ñ阡Sø»:Íúø0ëÛ.ùÖG§K¾Ê»aío|-ÑéÓþftú±³öÚÿ·½oý‘#»î³$KT×.i²‘…€,Ê”V=³î™íîrW= Crøˆø2ÒÚkgPÝ]=Ýb¿¶«{‡\Ø2à Aœ|1ò)ù,;1øKÀ’ãX øA€Îë‹>(pâ °€ òÈyÝgUO÷ »†ËÝii‡ÝU÷yî¹÷ž{î9¿#åJ:ýÜ G:U?SÒéSìå”NÿúÄ÷_ûbJ:ýG',éôoNdK§y‚¤Ó¿½jz¥^»~õÚ½;ÛÛ—á­µ–,Û¤A«µÌioÞ~p EäžHL×Ü“”ÐC36úÍ9nݾ{së†*ßYÀìúRÁÝm‘¤Ÿg›K~wï×îÝß¾©=B /âÆCÒÈ“AߺÂxÀm5-›8M›uCòAg4ž(“ļ KøÊÙsI¢z* V?—ðaºe¾`âÌh¶iEªÙ~“VeD1 ÌAàU¦Q·nßW×!1+ÖÕ”oö°5"œˆËPWb/°TÇ{1<ÊD•5(£Ñ$byþž¯™“Èö#8{¤•uøJ½—fe½’گƣÈÜœ¯.ÂÉŒ§¹IŒÏR…ãCç¼H[>ìD7·n]†òìŸa+‚v7á)³4ÿÄXƒØ#æ6¡¸vR¼8rçÎ(OFhV‹.²ÆÿG&J¶Y*‰W•‰åê*´Â²¨„wÆœ«¡‰½ŠHx‹f;v–LJ6aêíu\¤pÛFA§Fv"D£ÉB¾nkò0îÆc¢è‹Þ.ôg J+|£¹1Žá|_Ûá׿vûáJ‚ßßhê$/º©Ÿ°Oå_~ÅKWðTü{'—.|÷éÆÉgŸ¼ZxvéÉ/ž]~òµÂ³í'¥Â³kOÖ Ïn>©žÝzò¸ðìî“ß)<»÷äž=xòzpúúçý“ì…Ï=ýÊ© ~þ=ýå/ðsøýYyþþ÷é? ¿““OoOþgpú¾ðô_…¦<ù?Áé·N<ý«SON¾òUøýý×^ù忉Óïœxú»ÁÓ<ýü©ï—_yô¯¾ÿW~ð‹…§ß£Bþiáéžþ¨ßO÷¹Æ§¿zêg|²[úÂ}9ýW|ññÃÓw8 ÈÌ_9Òmáôßÿ‚¼ÙU_Š’$€$¿I.©7gå ´ºò‡¯>ùì+§›'°íÿ5ÿ/4Uù.62z…û8¥SïYºŒéob§´æ¡hÍÃï|í¯q„n<ù­ ú?zÄtÿÁg Ô:E>{c)Øû“¯~9üžŠ¾ü•gÍ¥_xÖ^ú¥Ó¿¥á#lEïä^ûâGHpøöå×þ=žNÿ.ðÇ?yúÏN*JÑ9„O`p¦ÄåO_ûÛÓÿùçUÕ§ÿŸùúKºA§SýÉé²k•ŠIþÅçÿìïž‚®žþ#Iû‹Ö³ÿä?ƒQýïŸW]`(ùŸÃFó¸òi ¥åÏ^X}š¼òÓþ‡Mþßû…gÁ;Ÿýó^þáÏžþóWnÿôéï¿ß~ÿLàŸþÖÓï½òÛð¸þÝOžþ›W.Ôàù¾‡õî}ÿ¿öùïBº“_ýÒOèÉÿô _ò_ÿ.¾þNÂO`Êþú4÷³ wñù6þ¹Šîá¬ì§½¾õô¿ú£ŸAùTÜO¡¤^¿ˆÏà múñG¯_¦_ѯׯÁlª®I×òÑë!‘åGô÷õó†FZ]ð½W§« ¾÷êŸüÙÕ“Oÿã«™ê‚Ë'}uÁWN:ꂯœu—s(uAõ¤£.P?Sê‚ß9ù0/^NuÁß9õý«§Rê‚}ÒRÀ“©.øÜ)R|îTíçO¥Ô´ ý¯êÏŸ‚ãúçNéã:¬Ä{ÒU`ÊðÏÜ”Ÿ¡”ÿåäLuÁ¯ž"u«.x1õ¿èÝôÓþûÏ›[—ò«cýÏÙõêÚYÒÿ¬¯—×Ö*e¾ÿ;w¬ÿ9ŠÏFh8`¡¯¶)u£„ج”²³ž ²ÏgY fY oX*µJgÂycX 9Ÿ×°‹˜Kí€ ŸË° x>ÃRbƒ[äË…ÝoËÕë¥KwL(\¯œ­1­¥8rƤ„Ã>ë<ÈHd ‡è.° |2aâÛ‘eX¸{hÈ©®cøCÑ”úPØê&ƒ7ž´èVMñ"¨´Ñ˜ã ‘ý¸W áÅN?=fF…üÿu÷¢Ç‰fbRáVªïp¢[²ajF£±´›=ÚkQnØ}œc„.Ç [@̈́٠MrLna¨Zºß ãÛ+BƹB%Sd?xÞ‚úWÃð:¿Mºè› =ê yYiŠaĬ²Ñôu¸F{¥›|BÇ!¦³&agŒ”L\W ß ú»¿ ù¯3Åuݦ¥°÷˜)^ï |‰!¨þÌ­{ìUPÊKŒ~ÒVMƉ*ÕÆ„’p´Ùæ6ø?B6ÁÚ/^¾}Hõ8$ë€0%¬›H€)šQÜ@ä#¤ "‘%0yB3AŠ—NøÚITMГ>q#úÕÊu„ܦº®ÈúD4ÔLÉ$køp;&õ<.áîCáHö¸Ñîw  ¤)2ã§3Â4ÅÍ3«…ë!*‚pQöP c£!ÎÒ⨠—¬`]\â…E†~ßàx)çJ^P#òa'K׸[fbßf5bBSÌ Ån…gîÝߺ^¾÷ÍÚѳ#—ï îù¡O‹=Œ.Î=x³0êÄ 3+‰]ɺ'6†ÌÔ"ì¢ß9”Þ+«g¿y‘Ò¯„ßA»˜:²5ÌD©k…“°þyVXkʾ·o^ÛÞºsïM‚ Mµ…½ûƒæ \úf°×/Nv“ekFvÑü×õu›äÝꘃ#ñ›°"fÃê .áZËŠ¸¹Q(W·î˜$•ðn¼²7B½9µCmȆÂúd—w~LÌB! …‚XùãØÀ+Ž•_â]ºkS°ñÕ…~ ó7)|ðN}!‰Å¶‰ÒöŠ,[pÅÈbpÔ…¥è&¢²éß&R«ýèZú‘àùÛÄ[dºÍè-">“Á+2ÏÑ\¢ÿ·Qºjµ@°·&C«Ó…“aIw>Àd°C§Ž‰“E¥¥ÆN£×¶XFÒìBað}Îz@j'5BúÃ?߆–HHÄô°%˜D›Úî–¨ÐdªD?ˆe<®Õ”ÅBÛòô†ó´+Oï;OÇòô[ÎÓˆÞGÂgò.ÉÃå—ôÃõŠ.QÒG^Ýh±ä^¶kPÚ™•kgäôå¹Ô¸U¤KÒZd3á“!Ò˜rÁ].øÆm@ë.iNÀ4«µÑK…ÉËuÐôksm÷Ï 6`?!,spk€4Ð"üÜVIÝ€0ºœîž’ÄLïL1~pß:£…©TqêÀ§K“NYf§ÉeAÕ "!.úÈ´ðÚRl'ÇÊ€¶GÙq{4 Qåc©nz' Æ’¶}'ÅÊûüûÏÕ{½G}E.¿Ç <; Å¦D}…•¤±ƒþA dƒ|Æ4fädTsíaÜõǾ^¯nc¼cŒšH†Ç¹ìÓ²Hò’‡°Ñ1n t>Ž˜láS8…jó³WO³ Ò‚Û› ¨MEb¼þªløº>ét›$Þ5Ô5C¨ÄYÍf=5‰4·ÎMl(‡¸œ+b¼—k“W hÄ~ù%;ÉèO±ºÉ 1±ÞåùÊ·Tsrá¸[©þÅRɧTM\&¸ŸyuSݳõY­ldí%}nX6<¥íTHø%u*·R«#U>Qß!.2Ç‘2uë­s( PÍæ-`aÈUy!ŽðÈSÎS­˜$"ôر{£­ª×öl¤Óe–•©£_ëé•_lSžìuí¥æ½(Ñl$—ÍCŒ5¤±Ž?Þû~õdž{¼Éúiܯy„Xð¦KcDA¥V¢hO]¦=NQeU¨0òB!]U$¤Î>(é?³ äì¢&é謥;RLMgI:ÒÛ&'IšZ(XéT.’&Èò¢êðÕ¶FDw^%ÝcCE-Â0µ2ÀÔÕÜa<âôhºûžµ™É…Pª[Š ÃÁ ˜4‘Ê™ƒäUÕhð4ÌM.“iØ P¡_l:°h"²ÇD…ÀMëpyÒæ•J¯RЃ<‰ù[sQÆRƒ¶Q‡¬ª²W°I¿ó(ßE‰mT;Œ“Pè•{0BË6Ké–ÞDìÉbô…¤×—*@eÁÒRf¯VtÉE\ÿNŸ|vþôõJÄûFÑNÅ}ë2\7–¢®)m“I©‹U 'é„®¬iŸ¼3–=¾áI:6Z)¡“¨&…i“A’Inïf²Ô¬ÝZOQjŒŽV9;gü˜ow´<Ò•˜C© 9oBÒÇæ¸@ü€—„+$ +ÉÉÊÁÆLyizª¬@Þæ:9ëÆNs¿9JšFûÖÔLÒfF2Ó³Bs‚÷¹µu°ôÆDgqœæYô»bÉöÌDåêåmXéà&ðä¨Õ¾Õ˘]†×ÍN#b#¹dÒÀaC{7a?˜éH½¸5nŠZÁ¢`ÎiçšÃ©C­:z©Â¶wÞд`’tæº%µ²í—\8‘…ºg#KÒë”Sê]ÎËqqP+X¤ j.Ì;¸õRƒÄâNß»,âÛoW+®ŠÆº¥ÑªõU^¬&„̚ܣ¥Êù ðrYλW>6üÞõ7'‘ýYÍYZÆr±Zqy<_5_•¨ËÊcò[/^l~k†|&ªìß2ól2)¾çy‰¶ôÈs½áøq5ÇmÊÑëF©ÌlÊYWºƒÁ°fN½¦kj¶îÂóBæ{žÀXH&Œž_4pÐV6Úäû ³¥r–eÀ×tD™Ô%|ãÃй“ЄÔÖ2÷I@ÀðRO:}ÐIõ`2œŒNsvs7e=PÄ`²@™5i˜¼\•ÙêNHT~„B 5¸Ñ£‘™·§{cTcBh^¦n’»÷Ž¢{cT™Fv±¦Çøi‡…º]w¹\2ï&ËÇVVnž2v ðšC›pÈ5‡O{’ðî(Xu6üžT­Qò¡©ƒ›m7šLÿ½– Á+éµÜÃp¯ÍÞQ“àBD¼–Cc3–u»7ø – ƒ0j61 ›adxU›ìSªÁ]ˆŒÄÝýkþªYƒB j=l×ðœµRü‹íàÇ𢶰ÔÜ6\¶.íE Ú¶Ën˜RgŒѭÔx‚¨]ÓEu(P]< iŽ-ÞçŠÒ#Øq¾\K uø¹ˆ±dËýDöÕötù@Å8¡ôôÍkŸ9sc]pç4˵ÈÕFâl°“»ß8-Ô;£6"#ó <Ê1@$ŒMQjQ#áv ›¦-^ZŒÚu’C¬¶ÀcG Î_¹"š•^IVe)7G¯Ùœ ŠÎ—K•Rµ´&•I¨&KÞMº‘TŠi«¥õÒ¹ÔÓõÒ;¥J5õž+U×SÏáéôNê<=·^úÆ9×´CäÞºHå4æ£(™²úÈ Þ(談ÙÒ|¢ãp‰¬|c†šZVBOY‰0Ü–zã<·À:­ )áW/XDñ ÝJ±) å1ïì9èqæ(•ưM+X¿ÎÑ*1]gÄ»=6»3Vz³&³ÏwÔ殮cia2£üá] oB ¥ÒS4µØðŸµrTÑ#¢óô']ã´@ÎcJ<‘ »³‰­šZCœÇòãÚn)§6šR®mÖÑSá½øÊBË-nÁMŸOÇn«ðvØÎnÍaÇæWæÌÍPÄDëÅçž&Çdd+Akë8QEw co)29ñYó;ý•~»šßi©G°ñwúy8‰™~»#jù~ï-£[¥+œ—û*£ßâ‹ /Œ^ö1”ê9Ð!tÁ]5ë6Ål•Ô0BŸÓÎÏK´EÑ‘ …0[‹{ I¢š#µ<Ž… Ê€¡(—Ò(ã -Þ©˜¬…™²¡x[äÀ¤Ó‰l=•Ãû±€IHl :c½<<¨²‚õK—°Öĉ‘k+Hè(ÙKi^²[ÁÑsíÂLO¾áÒ‘«³å;› \6Rzå 5,Ë׸T³4ìP:Ý ŠêPqõ(‰ß7\ â Áµ>,Á׊hœ[2Õ6¾Ôû¯Ú~y7Ç}ÔUšXú–ÀñPþÁQKÜCõà 0ªÀÌs1¶(!PN”´Ó NO u`jf†oθÒ<‡™€¨„Èe¢Ad»í3çÔ Ê°o„§NFKƒW(´èчÖüÄÖ!õ퇶–å ËÍZ0e•ÞŹNCŽÃ‘ä ìcv©‡©ÚŒÆ‘+ÀÏP!ý½Q¼Óò… ÌM×VÎb±–¾)²[s”hÈøZ…Æ: q´LK:æˆ!æJÔQ^v9°,ßÊ-FløÐß d/à>‘ŽR> ŠÍÁ„V³à + ·|ö’²xYôšöHËOä+‹Ú,ûiç;' ¼ÍMžø™}±“éÄ7ëVs½å°LøàÀvöFx7þ+ð|ÝñËx4é7ôêT>wîÜû6êu’ÄöîB“±:Àã‘t¼ÔŒku½™µcOcu®V|pY Æz Y/ÙÞ7Û˜ƒ/@#sª±\fáã±çiÄHGvý&£õ[9ˆS˜ïÒ§YÉt™QK1R¸#ŒÞi] ô½Z0Å#ˆ*s3u]LßAÉÁwȆ§†‚n(b)‡HÃYš¹LºGBv–uµ¨»—)êDV¥{¼ù.ÎíŠ >»ãEN.ÜŽ·:‘ã7ã=1¹˜@ZÜûæÖ(κjæébKdn‚iÜ-æ³<¢)(ª:ÅRÒUdz’Yàk!Ët]ÉPõÀ5®¢!ÄsŽí:!÷Uÿp/‚€ÎQK_Pã|k³XÔâÊõM6Gz«N†µTG×S¹0•ì7óÔ'€sàÜ£ðò 5Á‹Gþ|$þï Äÿ^[+¯½Âÿ^?Žÿ{$ŸÐpÀBñ¿¯÷,gÁùÁRŸ@pÓøtú÷á"»à+}²NlOéš•,Q7|4ïÐÈ$«C½AQ°iÐÅ32©›tªe©‡F€t÷‚Ë.8õ·qd74Ê›ñ>ÚÎìNn5)I × äÑ}4á'¤BÔ×Âõ{ûÒxQ£=üJÊïR¿¥"ë¸a€BucHêkÂ2"tˆ;3¨çx>HmÝ( 1˜ÚXÝ<ŸuOm´‚c”B¡*–~;cÕƒp=„7@W²tíÛº¶š]{ #{ #û €‘Í‚-£z ·ÄjðLvà™m Bo zæ4xÊ}ð)ù²á`Pd)±/,åœÇÂ<68½—mZ zsv¿¦ag²Š} Ëýq7»ùRQ`ss?DHuxPHƒÔyžò9¡0_j0Ë@&ת‹˜$L34²'tºc¤ÉOÒ¤ïr­°&Û¥ÑFs4äX$–cÞ¤í[ž7Ù{ ²Z8 sºßût`LcH¡±1>|¢ÆRm¨ix$'—9­¥ZÒ ä¾à‡èÁŒÖ[˜™+ ý¼˜™ îó1fæ'3óŠƒx)Niw$ÍÃA^9c„)~;c×ÿÈÆ‡Ô) B¤ÉìãMCu~ :ÕI/‡eüšCu©sÁµeøkjùàªó“ ÕÉI.r´ç3,=¦Â\€O nñt(§çMr˜^,(” á4˜ Ø£ˆy‚.7ïÉK-îl('H¨¡œð{&”¾PPN&þPN&KÍ´g1PNÓ¡—2Áž\ü&Ÿ&ÈaÊuzÙMÙ6(ÊE†ìȬP²f MƒbZ+ÿËü’¡mq”ü%%…x9¶nû8èÀöÒ4¹JaOâ2;‘T•rYæºX¤t­¨ˆË-#ö B“]Õl83ÓÅ Ûñ®Àou‰6Q«OƒZ®MLµ³ã¬¾êÚg–1—újë*t¶UHMN›cpˆi¬“ˆ2â·á’¸G,«’# uT(É\P–\nÍšŽÎÙûÈšYÌå®Õdp­¤s‡²EŠp<ùÃ/„ èÌôr³ºªÝ©£ ² ÷’çlï;"³í|SÌ4)³€s"D3 ³º‚lÂö ѽ&Ø”áÓ”kš¨iêZ¤A(Žn-’qƒ¬ÕaÏçIMFÏåØ÷5ÛŽ Ì*×êÑYÐ ÃO1ÊÅ"Öíå !p)§j:Ë¥u“öDåj –Q­¹…úc]Öôú¡×\|Œ·“ò2PÂZêµYÐÑœê 4TM…§Àz,ZŠ–@Ò4Úæ¸J(OÄ«^lÔ)-jdMt³¤[¬ÇÐÁr %qô [xo_¯ÁT}¢Ö_eŽ«!¶ãlÍEPp½í)…–hå3+$ëÔ':Z*dù™fñnçJd9üO3·<îÃ÷ ´Ô^B Â+Á¥òqDb†«ÂRÂ¥ÝÁ iÁV9~ÛÜ©5ã„ÅÜÁ>ÔÔžš ³g*$}(<1óQt熪sÕÀñÓ*ªµt#åä6³‰GìÁvœ…|þÒº›)®Ø3Pøgoé=¦ÑÜâFv__Õö™|ŦǾØótêØ{¾J^°/¶6ðãd|]±GM4vÐâcÇ~\¼®(“-ºË©´K–à+:ŠåC¸Vg;UÓqŽèºß[%±÷Á¼·Á©û ï8î>(®ËYÑS°dÇ4Z¾zÃó)Õº ¹½Þ¤°‚bRoÀ@ŽÃ¤.ØMô@"¬Úý”½Sn[ùÄ\]ÏT¶õvd:S¼Co_Æ—|`DlHÓמ5P^¦¢ÉR\;¥7“óö®¤2õöz‹Ù{‰žv ¥Ý›vÇn˜èÔ±æ<%f?„õåØóØóøó²~”3Ћóÿ¬TªÕ5ßÿóܹò±ÿçQ|6Bà õÿÔ~m¸ö÷¢~gˆžž±D™}á®\º˜ìã±W½¹u·ZŸ½Ê§ÖgO{ãåáBƒ"‹Wó·ú;t–ÓYÌkEºziÜ0”yz>Öktr‰2¬ö#¥Qc‰Š!/ W¬ÑO¼sƒÉȾ2æ9ËrÛ"]½Œ¨­*¢À\ŠÈŒWÊVœ»é4Â*¯Çýbó’Ò…0Iõˆmïz\XøN!´Š—j~@¹ÔEžÂ‚ŠŒb]ë Õs­(¶ ðÍ9 QÕú¶Dø…/L8P&æ061’^NÓ;ÕpAƒtlUCú<Ôªê¬vå° \²±~õ.²]Kò¸ŸÀÕøQlSÜ*®Pgà 4¿1À…»R ‹ÍÏj)ŒÇU»ehËî­3&h$OwVDi ‘¹ ×ÝÀP0öÕ,åñÈg)ÙJïènÁ©P9ª¼Ã $4Á†AЇ kYÖ8¥;”¼jõÚ~Xò:‘éå:ÇjÁøÉ}ôô„ŽìµÐ×1nÌ m«Ê;«üבÁKA‹Åf`Ù X¼D–âU·ó¬vGS6`Tû´K†­eO£Å[yßG«÷Q&”„Bƒ™¦ÍÀØù"„Å«ÓåP%~V )Ðuqµ(F2ÁÊpö«âßFÖêg%Ы`2˜Œq0—ó)Šü?(H!j§²ÊuRp%îJ¿LÝ¡Ì$ЯLÜ5¿Ù¸ÁÀXlÜÆŒ#´ì&—Ízv Íz¸°®3ÓÀs•âM'Å^§KæŒðX{ܘeÌ^¿Ò«Q‚ýKOPk%P1Ž;Yj%,DzÖš›˜‘ ¸Ê!bYØcV’Èwz¼fÑ×uU²éjÞxSÙ°I-”ÅÙ.]±'»v?²cwh—&69¢6èÅMÜB¹,-* †Ë‹ü6}3€”y‘³ðZó„ÛTÜÔä¯3„Ïks–îxâE¨àôvß4ëHµ¼þ)‹ó\¤ÇKb°H²¢]ákùQ®W oÓ©›7Q&\òÖ2åp4×Å饋rY™}™Dè™(7MGÑhèþ.:ì5´¬àä 뺒ˆ*ç/l•Âêù Õ=]×0…r<¤‡žp#dÉ64æpú0Éí‘kt¿pS|ûJ›Ë òt«wÆéõyˆnÒ=ñùƲ6í¬Ú=˜&DI£¤(šdú,¢ZÆ‹š!W0Ë–"¨X. 9¯A»¾% ©mžO?¸#jÉ´lÄ^^@ª^­’z¥ )kY¾}'eo,¦zG!>ð¥Mé£Û1wñÑ¥¼dZgT°æþëœòƒÈOÛï¾PýïZõlJÿûvyíXÿ{Òÿ ,Tÿ{-~$NÐh×b‡ý<¸¢÷îÑ)zó×è¾4êÛvü(­¾VyÙÔ·ƒÉ8íC1 ÎÓ°ôS÷ߎ¹„u¾à–Ú—Úû‹Él2ä5Ôgˆgî57æŽúGDïpiÒ'^B³ÄA¡uÜDhH\—?ö#3·0Úo”„È}ê]-²=ô¤ßlš¨¡©(Ây¹ÃS¾—ä2zê¤ÚC3¤³Ûï´:m«:u‚Ïi¡} ª±‹#~䇥P¯ÄEÏ;¢¶q³ÑCŠñ”“¾²ßËaØ’Q—‹ÓþutEжn¾4ÅÍñ(ˆÚÍ•¨8Ê2zQòù¾¼Õ N‰ )á_´ŒúaEyöò©| ’Kºš~^.ZüEùDZ1ªQ×¢yÈ ÌngœŒúÈÁèŠH£&ñºÖ³w Ξ©8¢¹~l²½r¨äÐb;•(²©žs<¥"?0“…)™E ­ôV_—ävEÁv7gî FÍ ÙÞŽ^a8 ÜWŽŒ€´·µ-âDêa×{¨÷®¸‡g‰\è„¡\¾‰=ÓF§ã“K’Ys[¢Äš¡™âÆ‚;1· ˆTm6Gµi1æuRó‚Mö1®ÌSŽ”áŽì–Œ¯¬-"ˆsƒ®2XDOj&&©œ³\³;EçX9Gó"~T3×-´Îãè#M£E»–[ò”¸ž\hEÔ „õFQ=eÜ6uN©ªëF¼Âç&ÚsØþupÕ@š_©¹×?TžUˆ09¹«<ÕZÆ=éù½u›C4¦æe]Û(+“HTÖ3*¬–ý¼ g´õaÀIb¬óíÑãéâŒ_£=ªí3ðº2àŒ/(…îOq(ˆ)Ž%Z·ƒxìóìGhxÏø5#Æð¤~åþ8K3Õ>4@B+ØÁÍÇ 3:Eäºsè¥ëÅ-X(šDõ¸ëäàåän1k4ŠÛÙ¯f?¾—ý¸æ?¶|E#§¥ì‹³å¤ïÖÝL‰ z»+†S*òX—æq#£â‹3+6^E2»‚•cs›µrë§Së¼|€:径ët½k¦Õ©.× ¦k5y›Ìa&èÁ”Pmm~E‹G,^¥‹U«÷œ;}¾è¿9H‹_’{!Ô@ß åúQ‘?^¤ýÿ¹µjÊþÿíÊñýÏQ|6BùØÿ{æÿŽ‹÷Çý2èØêÿàåí,«ÿk9Zýç{Òm´¸!»ê{hÌ/Í-˜—Îlj!»NÆpµ}ŒTó4tåðaCwu†±‹—SLhd6ÛâC“ø£Ç‡Cª’vÈ÷ÉÕiÁùêýI‡ý/S>ßzšíÛ#ÓMR·Nñ Axvc-ë{ŠL]àÙÿºÊÀ8ò:¾½bñŒ©}Õvã0â#(óg»Ýo0êìvp-žUÀ‚GÍÃY0/¿fIçl7Éä¼J²‹m¥qâöE»»r!5JPÖÊ…f2Öøí¾µ°mÀH¥W§b›×Ž-ÛAì¤Q©B]°4M\lM“hšý»n«:/9V‚)4·¨~ëA¶ÀÕÕ)WÄV¡Ä•!¶£+@¸€¹†oêY˜‡×(š²„+Éó4\’†tÛsKš¬7…©+è«>Ð?T~XÂg]‘±.JÄ 'h7í‹_^`ÞÚˆþ‘‘®Žá¥äÊ3Ö 7Ù¾¾ïôýùn…Å÷ŠkÃçF4IPõêÆMÁ)¤7Žpiü8 gÍ^i1’dò ºT“ŽWÂî¤ñ°#±6u±Á†Ï@bœIöó8UÐ*|‰¸'ËÈ+øD­e«~îÕ»f1¾#{´<š%Ð@Ér9z±ÌN¶àñt/IÃÖE0'U|^™;è*¯éUÎãs/‚ÀDF³ŠÙy‘¤Xj&mÖ”rJ²Fj˜Ç|vãßOÆm5¬a)r%ä¨äxæ5¼BDý]Žò"””u–•í¶z0ÐÁÅ1Mö[⧘+ËûK|¼V ÷µêÖ•˜5e-)•—Gíí:úxÓ’0§È1¢Q©gF&©±²_žÇQ""lÆáqT2Ë%ä,ǃ#ó;†Hù¸i„)~RÔóû|¼vøc/ˆçñ‚xiÔÝ/À B©˜^ þÕ¾)ûÿêÙcýïQ|6Bà Õÿ^Ò2 ®0¬ˆ8öxù¼`äÒê\`˜ü¼4ã´òS¸Ó†›·!¨sµô˜®öÓI•m¤hN±–«Á‚ÎÇ£-å&Κ1¢ËxÿëÅ_QøÉ}N"^쿎)ÄÞ6*®@KšÑå䢔T·ŽücªGÙTÕ?œFõ1A´ìKóFN47‡R65wa>–ÔÞ` "+Ű[eD'Tt™NÌ\–mg\p¼Öåcff꘬‹Ùï³×=£ÛOå˜z@©‘—Ýk‚tåKŽòO·cñ`ÍÖ©šií[tNL¡´Ž–^)}º —ù¦ž±\í<ºIpl4®¦æ ËZü¸"c]~!\a_~-˜WLÀ“<¸b’âŠIWÀÑy''WƒKxÏ5u|må› Ââkµåfó°|줸Ä(Ç5Ž“u_iÞ:M ¦Ï}w¦Ò63‚ùÌû:[› ðI3èùG{ƈÊ8eòÄF;k<ÍhgñÂQŒ¶§ŒËœÑûötÕ½Œ­5ÚxGž<ùX5 ²Žü„è¸?©'ñû<Ú bTæAEõ%¬Ç²ŒÏg‰0`¥SÛ Kyîu ÝÜ`ÃóíqåFM$•¯BXÏ5œ-¾Ð BÕ«½ñ4 ¯‡ê1#Ø5ºq4‹ M*Èo\÷S1ó&¡«!ý”;Íôx“š6§ÁvŒG,lR1ÈiÌ3™‹²ÙNÆW¯«á7>LVR{jkŽ å7øÜËž`êЊ”žÆóì'pÐ_ñšõqI+$´rö8Ê ¨@乌ãŠÌ>M'˜;r% hW!®NÚB‚ ¶׎" ‹_+Òñ™ZeÐ}³¸ÉŠ@›N6¯è¡ûIp9{æÎpΘnÇíV=z­/3ñX1qÕv*€Ë©º•Mí›Ï¯Å"¡c»_n˜2r‹uœVºùgôuàÄ2_2•ªÑ°*„_ŠÉÍ-ê~×¥/—_ ê´ýJèsãúÅwïß½—ëàþ÷Õµskïþ¯Z>Žÿp4ºÿSà\>÷ –Æ=ôûŒŽ¯þ>Î +}ˆ#Û}àMÞ½r˜ÞΤÿ0TOô 3 vÌÛ]»}ï¾$¬XjŒJÝïȽdØìz]UÀ›o*SÂdƒLóæ›vzJŽÆ5Vr²µÉJü2ùÉ´°cö®ô«Ì˜˜¯rð†ˆN«”jÐmÚ©´‰*'‡cI“KÑdž$µ°ŒÇ¬Ûß, WK¤KH‡I÷£¤ûAÒÍoزâ¤Vhìt°ãàmzú¡ð9Ž%ȕסN;úk¼PóHÝ *€¢)#Yɺã"ª@ŸºÝjøíàë|'}gS6xŽ4p—#8H1(Z¬T•‡-ð`ë‡èÐ'-¡‰õy¢›¿,vò Q@]¹u©uêò® ;UDLIÈté€R_#eL`B°zÔR V„©*ÂØPöVM®¹E(%)Œ*H$Ú rt⥠BÏÕö|X¼Ã×Ï7éõúËl .6æ}¸dLFHl 9Ý3B°x]KX¬Kaq­HûZq½˜§U¨vçú;ýÖ@ÍgS¶ e1•ˆ™tú~ìÞ÷ö„VìŠÊ& gÕl£—땎]p…¤`.Ò€«î9¬Zè®Fâ‘ñ%»%2 ³b‡ßIÝ5»‘ª‚y§Xµ©bHOó0æcuW€m]•õâùcC¯õ(·&ÎJ9 •½Œa&â©Ô÷p!!éÒÄþUúzßXrì4ýX„ÄcG‘ßTvgvb]š`±Œ² åT>è6³+ÇûZÖ&¸[’T„=(—t±æÆDŒh(ÞÂd䫘|öÅL˜®Öì6+ŠÏ‹£‰L‡ Ê‹éîÁî FoÐÝ.¹h7rg’ƒ>þy8!vt íñwdíi+›ø8)Áx*›Ú;f‹b`à«M dxPQÉâYdB±´Í ¨jK%Íæjý±§†b)ºß£úõЙ–ùDÀÃ=a€áå€g)9ü«À´ôÁ)Æ“Fáh9äñ©èíàrïhOžå˜§NþükO¿O9÷6l“è…ò0]içÃˇûdalV6 £…©æÁÃWã~ˆº¦MÏr“惷ŸN&3ÿ§@c]4 gìÃWÓ‡¢áÇìÇIöã‡^@]%_Û âÇΑdªœ8píKEœ§éáxYy¬Å:qMÄ'Žƒ n?¶ã¾Ýø¯ñЍZFr‹qÆ)£€=ÊÕdœ"Óš°HÍ:o|9ê±ò0J%Óª#·J½¿}ïþë_ ýg¥²^IÛ®ÛÉg#´8`±öŸ÷ÑɾKv•=óϨ¯Ã4P1Ö?Ý&´²>Í&tô©Â¿„íî#ŠÚë=J§Ò6¦æ›ûæcwš§µfcÔmÕ l>˜«¥d>Üdª N²3fTDÞ¢[}çwÛûÝhïxOhàmß¹àXÿG×äP‚úR™ù9Ȉ߆ú`À¡‹¨s¹t‹–&Œ f-K ®ø´¾ÛKvC2ó•Π‘o`éÏìP?Þ™=Ð'«JumÝ…—rþqsD¥ò7*âP\/•·ªò½Q*_\“ïÍRùÒz[iZË—ÏÊ÷v©¼}N¾Ã‘îÊÛv½tŒ6­*—uÁke+GÀS˜bíü†’=5ÖçÑŒ©ê•ŒéÊT4mèuÅžÝÍOVIZu“V÷Iºæ&]Û'麛t}Ÿ¤gݤg3“šäGµÀºÓèÚ”O¹0rL(†g´”*þÕi%2‡-´mIQÄP5×xð˦éxÈñ]ñÀÀ™ƒ”ZЏºˆ¸T<“Š›¤‰  wp*ç·j¥°zþ"ü]]] ì`³Uª2» |õNUW^›Q9¬ð ¸êÐÓ”F첈AFÍì’;SÉncœ"´&Ó[iLÓøqŸAÀëí‚W˜[Ô”éSV3‹ý¤ÑÊwu¸ùó4SRŒ yF™§5ëñšõxëâ¥ËÛW®^»þ÷Vé«•lÝI¶yùML¶ºyñÍËV¢³v¢Õ‹«—VåmÐÎ}ÍóŽh#Ë\ô"Í,mµê¹;œ±eo1ªÔÓehÝå¼…T½†TÑj=]ÆbPóe½t-¬<2Y¦­^ééç.²ûN˜¶;+ðˆ…¾LW®ßؾµuSؼíN’÷¶nݾmûî{˜ú=Lþž›>0"h¾;9®p/„»MS›ú46’A²yöUöX ô9Gß-²yöcÖbYáÇÚ+óêöá<}ÔÉñ°Š£â3Ýuð×¶x¨èÀ–ö%Ç!W†©µ\^p-/“倪ÖÌ?­(¹;ÿÿÜ,ýïzùíª¯ÿ­œ=ÖÿÍg#ÌpþnìoÈ ôJB¼Ë»@¸x0±VWT"ám*­¹–U»¥&ð€ˆ}ÞFP]Œü¿I©¾ÝŽG”J Ik?V¥¶]Øë:ý]L†áÅÛ·ï‡+á(FÅ’U¾»tmëÖÕmx›tvQ·ëšéC‚ËÛ\…÷¾y=¾Û~÷ú}zÕôJ½výêµ{w¶·/Ã[ËÃÛ¸5£Ç2§½yûÁ­ûá{+7~“d-òÐB<éA =ô  ßœãÖí»7·n¨ò‡s»†¾TpwûÎí»L€á`dÜwñݽ_»wû¦vï…¾<Š“q¬Ÿ 8 §~Àm5-›8Msšßá Gô]ÆåƒÎhˆFúýõ¾HüÛAvÙð¾CØr¾ƒä!EÆ.Ÿ¿L¨o° ±9÷<)Tªïà}Õ´é§ú†FCÈ2r‡ÔӴIjáMêÑÉU ßhë7n0Ùvì‰;‚]¿mÊ¿¶Ã¯=ìöÕ¿¿Ñäk˜_™ùÔõW¯éve­\Îò(Ž a|c¹Ã’áæÛv†ƒn©˜Ðãˆ<1¹°j@¿wƃ!W°'HzøVˆ½>ïm(T‡Kc<1Þþ^”ÉKgÇ(“¡C‹. þ°¤)Øæ&tâaKÑ <`²Û@÷ø¾;n“ÅšÚö%£"%ð¬I´i_pA¡Éx$#Á1ãÕŽF»&b|Ôß­qÓ"=x›ó N2ü“uBmË?i0äG2^0±töŸ¸H^C &Ók’9¦Æ£“ò°¸ä¤¬HÃ%•겓ŠñF ‰Tšm' £–lfT¥¸æ¤oIH£<*áM'! éXmr*Í-' ®í\˜uVQIï:IùèåñiD¥ºç¤bÄFLŦJõÀI5Ñm{ ÃáìôÙ%E–w?V×/`q ÇíÑ$äŸ#Z…R×OrwðákÜéå'Ð@5‡­zR×»Åâ£ÀÉRË(àÚ’W…cdßR‹ Œ;šU,ŸXF´,æØA 2*£›Þ3R¹OZ¢óYKpÍÏ“ØòY#Lþyô·«;‡ížÕ·Á)ꋞÙ8”žøjšvš4$ÓŠËD—¤–cS`‘ÅR³Úv³ü3Ú~ÍjÏnVª¸)ÍrìL§þƒ˜7#5²óhΑ‹Y–óTÜ(+ìiš„4à댰¡G´RÌÆì32Zå&h ÚÙÆhd1¥yÀ€Íé½>7ô»Q䶉ŒàíM`R²Ž½5Ó~òe¢ÌRø!m¬hI<÷)îT<²àñy4V‚Of•l¨Ö‡5—­AÖQ­X09| 9Ù2e5[8sDÍþ 5Sาº{Â>›ª†ùÇ)DéÆÔlr(æªå]å’l*‹g 2>A|„fÄ‹¿«œ[é”â:æ»f#ºª‘Zè§'‡ÐŒ ²(¥3ð`Ò[úŽTk”ï€WQMÔ¦”9Ž öê0©Mß“*< ñЪ%2ˆã¥NõäJ›u´Ww§©^‹ËÁ Ó:Œ…7Sé5ÒÑ…zo¦ÖzÎßLy”¢3Õ ñ—°Ó¾$&Œ8&áapLîno]¾¹½zÿÝû¹ÀKÐgür¹Š˜oŸ[Gص³ëˆÿñöú1þÇ‘|ÈOÿÁ¸ÓíŒÑe]¹&ƒÜ¶µøîŸ hÇÃÚ[o1 @²:Ž'I?¯Â¾MÞúîh7u£Fû-˜š+ï”ßj {°;uWÛã^÷Ó ¿sü9þŽ?ÇŸãÏñçøsü9þŽ?Göùÿ¿yçxtrs-4.9d/crc.c000066400000000000000000000064571306603614600134660ustar00rootroot00000000000000/* crc.c Compute CCITT CRC-16 using the correct bit order for floppy disks. $Id: crc.c,v 1.2 2008/06/26 04:39:56 mann Exp $ */ /* Accelerator table to compute the CRC eight bits at a time */ unsigned short const crc16_table[256] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 }; /* Slow way, not using table */ unsigned short CALC_CRC1a(unsigned short crc, unsigned char byte) { int i = 8; unsigned short b = byte << 8; while (i--) { crc = (crc << 1) ^ (((crc ^ b) & 0x8000) ? 0x1021 : 0); b <<= 1; } return crc; } /* Fast way, using table */ #define CALC_CRC1b(crc, c) (((crc) << 8) ^ crc16_table[((crc) >> 8) ^ (c)]) #ifndef calc_crc1 #define calc_crc1 CALC_CRC1b #endif /* Recompute the CRC with len bytes appended. */ unsigned short calc_crc(unsigned short crc, unsigned char const *buf, int len) { while (len--) { crc = calc_crc1(crc, *buf++); } return crc; } #if TEST #include int main(int argc, char **argv) { char buf[2048]; int count, c, res; unsigned short preset; if (argc > 1) { preset = strtol(argv[1], NULL, 0); } else { preset = 0xffff; } count = 0; for (;;) { res = scanf("%2x", &c); if (res != 1) break; buf[count++] = c; } printf("\n%04x\n", calc_crc(preset, buf, count)); return 0; } #endif xtrs-4.9d/debug.c000066400000000000000000000512451306603614600140000ustar00rootroot00000000000000/* * Copyright (C) 1992 Clarendon Hill Software. * * Permission is granted to any individual or institution to use, copy, * or redistribute this software, provided this copyright notice is retained. * * This software is provided "as is" without any expressed or implied * warranty. If this software brings on any sort of damage -- physical, * monetary, emotional, or brain -- too bad. You've got no one to blame * but yourself. * * The software may be modified for your own purposes, but modified versions * must retain this notice. */ /* Modified by Timothy Mann, 1996 and later $Id: debug.c,v 1.28 2009/06/16 00:10:39 mann Exp $ */ #include "z80.h" #include "trs.h" #include #include #include #include #ifdef READLINE #include #include #endif /*SUPPRESS 112*/ #define MAXLINE (256) #define ADDRESS_SPACE (0x10000) #define MAX_TRAPS (100) #define BREAKPOINT_FLAG (0x1) #define TRACE_FLAG (0x2) #define DISASSEMBLE_ON_FLAG (0x4) #define DISASSEMBLE_OFF_FLAG (0x8) #define BREAK_ONCE_FLAG (0x10) #define WATCHPOINT_FLAG (0x20) static Uchar *traps; static int num_traps; static int print_instructions; static int stop_signaled; static unsigned int num_watchpoints = 0; static char help_message[] = "(zbx) commands:\n\ \n\ Running:\n\ run\n\ Hard reset the Z-80 and devices and commence execution.\n\ cont\n\ Continue execution.\n\ step\n\ Execute one instruction, disallowing all interrupts.\n\ stepint\n\ Execute one instruction, allowing an interrupt afterwards.\n\ next\n\ nextint\n\ Execute one instruction. If the instruction is a CALL, continue\n\ until the return. Interrupts are always allowed inside the call,\n\ but only the nextint form allows an interrupt afterwards.\n\ reset\n\ Hard reset the Z-80 and devices.\n\ softreset\n\ Press the system reset button. On Model I/III, softreset resets the\n\ devices and posts a nonmaskable interrupt to the CPU; on Model 4/4P,\n\ softreset is the same as hard reset.\n\ Printing:\n\ dump\n\ Print the values of the Z-80 registers.\n\ list\n\ list \n\ list , \n\ Disassemble 10 instructions at the current pc, 10 instructions at\n\ the specified hex address, or the instructions in the range of hex\n\ addresses.\n\ , /\n\ / \n\ =\n\ Print the memory values in the specified range. All values are hex.\n\ traceon\n\ Enable tracing of all instructions.\n\ traceoff\n\ Disable tracing.\n\ diskdump\n\ Print the state of the floppy disk controller emulation.\n\ Traps:\n\ status\n\ Show all traps (breakpoints, trace points).\n\ clear\n\ Delete the trap at the current address.\n\ delete \n\ delete *\n\ Delete trap n, or all traps.\n\ stop at
\n\ break
\n\ Set a breakpoint at the specified hex address.\n\ trace
\n\ Set a trap to trace execution at the specified hex address.\n\ traceon at
\n\ Set a trap to enable tracing at the specified hex address.\n\ traceoff at
\n\ Set a trap to disable tracing at the specified hex address.\n\ watch
\n\ Set a trap to watch specified hex address for changes.\n\ Miscellaneous:\n\ assign $ = \n\ assign = \n\ Change the value of a register, register pair, or memory byte.\n\ timeroff\n\ timeron\n\ Disable/enable the emulated TRS-80 real time clock interrupt.\n\ diskdebug \n\ Set floppy disk controller debug flags to hexval.\n\ 1=FDC register I/O, 2=FDC commands, 4=VTOS 3.0 JV3 kludges, 8=Gaps,\n\ 10=Phys sector sizes, 20=Readadr timing, 40=DMK, 80=ioctl errors.\n\ zbxinfo\n\ Display information about this debugger.\n\ help\n\ ?\n\ Print this message.\n\ quit\n\ Exit from xtrs.\n"; static struct { int valid; int address; int flag; Uchar byte; /* used only by watchpoints */ } trap_table[MAX_TRAPS]; static char *trap_name(int flag) { switch(flag) { case BREAKPOINT_FLAG: return "breakpoint"; case TRACE_FLAG: return "trace"; case DISASSEMBLE_ON_FLAG: return "traceon"; case DISASSEMBLE_OFF_FLAG: return "traceoff"; case BREAK_ONCE_FLAG: return "temporary breakpoint"; case WATCHPOINT_FLAG: return "watchpoint"; default: return "unknown trap"; } } static void show_zbxinfo() { printf("zbx: Z-80 debugger by David Gingold, Alex Wolman, and Timothy" " Mann\n"); printf("\n"); printf("Traps set: %d (maximum %d)\n", num_traps, MAX_TRAPS); printf("Size of address space: 0x%x\n", ADDRESS_SPACE); printf("Maximum length of command line: %d\n", MAXLINE); #ifdef READLINE printf("GNU Readline library support enabled.\n"); #else printf("GNU Readline library support disabled.\n"); #endif } static void clear_all_traps() { int i; for(i = 0; i < MAX_TRAPS; ++i) { if(trap_table[i].valid) { traps[trap_table[i].address] &= ~(trap_table[i].flag); trap_table[i].valid = 0; } } num_traps = 0; } static void print_traps() { int i; if(num_traps) { for(i = 0; i < MAX_TRAPS; ++i) { if(trap_table[i].valid) { printf("[%d] %.4x (%s)\n", i, trap_table[i].address, trap_name(trap_table[i].flag)); } } } else { printf("No traps are set.\n"); } } static void set_trap(int address, int flag) { int i; if(num_traps == MAX_TRAPS) { printf("Cannot set more than %d traps.\n", MAX_TRAPS); } else { i = 0; while(trap_table[i].valid) ++i; trap_table[i].valid = 1; trap_table[i].address = address; trap_table[i].flag = flag; if (trap_table[i].flag == WATCHPOINT_FLAG) { /* Initialize the byte field to current memory contents. */ trap_table[i].byte = mem_read(address); /* Increment number of set watchpoints. */ num_watchpoints++; } traps[address] |= flag; num_traps++; printf("Set %s [%d] at %.4x\n", trap_name(flag), i, address); } } static void clear_trap(int i) { if((i < 0) || (i > MAX_TRAPS) || !trap_table[i].valid) { printf("[%d] is not a valid trap.\n", i); } else { traps[trap_table[i].address] &= ~(trap_table[i].flag); trap_table[i].valid = 0; if (trap_table[i].flag == WATCHPOINT_FLAG) { /* Decrement number of set watchpoints. */ num_watchpoints--; } num_traps--; printf("Cleared %s [%d] at %.4x\n", trap_name(trap_table[i].flag), i, trap_table[i].address); } } static void clear_trap_address(int address, int flag) { int i; for(i = 0; i < MAX_TRAPS; ++i) { if(trap_table[i].valid && (trap_table[i].address == address) && ((flag == 0) || (trap_table[i].flag == flag))) { clear_trap(i); } } } void debug_print_registers() { printf("\n S Z - H - PV N C IFF1 IFF2 IM\n"); printf("Flags: %d %d %d %d %d %d %d %d %d %d %d\n\n", (SIGN_FLAG != 0), (ZERO_FLAG != 0), (REG_F & UNDOC5_MASK) != 0, (HALF_CARRY_FLAG != 0), (REG_F & UNDOC3_MASK) != 0, (OVERFLOW_FLAG != 0), (SUBTRACT_FLAG != 0), (CARRY_FLAG != 0), z80_state.iff1, z80_state.iff2, z80_state.interrupt_mode); printf("A F: %.2x %.2x IX: %.4x AF': %.4x\n", REG_A, REG_F, REG_IX, REG_AF_PRIME); printf("B C: %.2x %.2x IY: %.4x BC': %.4x\n", REG_B, REG_C, REG_IY, REG_BC_PRIME); printf("D E: %.2x %.2x PC: %.4x DE': %.4x\n", REG_D, REG_E, REG_PC, REG_DE_PRIME); printf("H L: %.2x %.2x SP: %.4x HL': %.4x\n", REG_H, REG_L, REG_SP, REG_HL_PRIME); printf("\nT-state counter: %" TSTATE_T_LEN " ", z80_state.t_count); printf("Delay setting: %d (%s)\n", z80_state.delay, trs_autodelay ? "auto" : "fixed"); } static void signal_handler() { stop_signaled = 1; if (trs_continuous > 0) trs_continuous = 0; } void trs_debug() { stop_signaled = 1; if (trs_continuous > 0) trs_continuous = 0; } void debug_init() { int i; traps = (Uchar *) malloc(ADDRESS_SPACE * sizeof(Uchar)); bzero(traps, ADDRESS_SPACE * sizeof(Uchar)); for(i = 0; i < MAX_TRAPS; ++i) trap_table[i].valid = 0; printf("Type \"help\" for a list of commands.\n"); } static void print_memory(Ushort address, int num_bytes) { int bytes_to_print, i; int byte; while(num_bytes > 0) { bytes_to_print = 16; if(bytes_to_print > num_bytes) bytes_to_print = num_bytes; printf("%.4x:\t", address); for(i = 0; i < bytes_to_print; ++i) { printf("%.2x ", mem_read(address + i)); } for(i = bytes_to_print; i < 16; ++i) { printf(" "); } printf(" "); for(i = 0; i < bytes_to_print; ++i) { byte = mem_read(address + i); if(isprint(byte)) { printf("%c", byte); } else { printf("."); } } printf("\n"); num_bytes -= bytes_to_print; address += bytes_to_print; } } static void debug_run() { void (*old_signal_handler)(); Uchar t; Uchar byte; int continuous; int i; int watch_triggered = 0; /* catch control-c signal */ old_signal_handler = signal(SIGINT, signal_handler); stop_signaled = 0; t = traps[REG_PC]; while(!stop_signaled) { if(t) { if(t & TRACE_FLAG) { printf("Trace: "); disassemble(REG_PC); } if(t & DISASSEMBLE_ON_FLAG) { print_instructions = 1; } if(t & DISASSEMBLE_OFF_FLAG) { print_instructions = 0; } } if(print_instructions) disassemble(REG_PC); continuous = (!print_instructions && num_traps == 0); if (z80_run(continuous)) { printf("emt_debug instruction executed.\n"); stop_signaled = 1; } t = traps[REG_PC]; if(t & BREAKPOINT_FLAG) { stop_signaled = 1; } if(t & BREAK_ONCE_FLAG) { stop_signaled = 1; clear_trap_address(REG_PC, BREAK_ONCE_FLAG); } /* * Iterate over the trap list looking for watchpoints only if we * know there are any to be found. */ if (num_watchpoints) { for (i = 0; i < MAX_TRAPS; ++i) { if (trap_table[i].flag == WATCHPOINT_FLAG) { byte = mem_read(trap_table[i].address); if (byte != trap_table[i].byte) { /* * If a watched memory location has changed, report * it, update the watch entry in the trap table to * reflect the new value, and set the * watch_triggered flag so that we stop after all * watchpoints have been processed. */ printf("Memory location 0x%.4x changed value from " "0x%.2x to 0x%.2x.\n", trap_table[i].address, trap_table[i].byte, byte); trap_table[i].byte = byte; watch_triggered = 1; } } } if (watch_triggered) { stop_signaled = 1; } } } signal(SIGINT, old_signal_handler); printf("Stopped at %.4x\n", REG_PC); } void debug_shell() { char input[MAXLINE]; char command[MAXLINE]; int done = 0; sigset_t set, oldset; #ifdef READLINE char *line; char history_file[MAXLINE]; char *home = (char *)getenv ("HOME"); if (!home) home = "."; sprintf (history_file, "%s/.zbx-history", home); read_history(history_file); #endif while(!done) { printf("\n"); disassemble(REG_PC); sigemptyset(&set); sigaddset(&set, SIGALRM); sigprocmask(SIG_BLOCK, &set, &oldset); #ifdef READLINE /* * Use the way cool gnu readline() utility. Get completion, * history, way way cool. */ { line = readline("(zbx) "); if(line) { if(strlen(line) > 0) { add_history(line); } strncpy(input, line, MAXLINE - 1); free(line); } else { break; } } #else printf("(zbx) "); fflush(stdout); if (fgets(input, MAXLINE, stdin) == NULL) break; #endif sigprocmask(SIG_SETMASK, &oldset, NULL); if(sscanf(input, "%s", command)) { if(!strcmp(command, "help") || !strcmp(command, "?")) { fputs(help_message, stdout); } else if (!strcmp(command, "zbxinfo")) { show_zbxinfo(); } else if(!strcmp(command, "clear")) { clear_trap_address(REG_PC, 0); } else if(!strcmp(command, "cont")) { debug_run(); } else if(!strcmp(command, "dump")) { debug_print_registers(); } else if(!strcmp(command, "delete")) { int i; if(!strncmp(input, "delete *", 8)) { clear_all_traps(); } else if(sscanf(input, "delete %d", &i) != 1) { printf("A trap must be specified.\n"); } else { clear_trap(i); } } else if(!strcmp(command, "list")) { int x, y; Ushort start, old_start; int bytes = 0; int lines = 0; if(sscanf(input, "list %x , %x", &x, &y) == 2) { start = x; bytes = (y - x) & 0xffff; } else if(sscanf(input, "list %x", &x) == 1) { start = x; lines = 10; } else { start = REG_PC; lines = 10; } if(lines) { while(lines--) { start = disassemble(start); } } else { while (bytes >= 0) { start = disassemble(old_start = start); bytes -= (start - old_start) & 0xffff; } } } else if(!strcmp(command, "next") || !strcmp(command, "nextint")) { int is_call = 0, is_rst = 0; switch(mem_read(REG_PC)) { case 0xCD: /* call address */ is_call = 1; break; case 0xC4: /* call nz, address */ is_call = !ZERO_FLAG; break; case 0xCC: /* call z, address */ is_call = ZERO_FLAG; break; case 0xD4: /* call nc, address */ is_call = !CARRY_FLAG; break; case 0xDC: /* call c, address */ is_call = CARRY_FLAG; break; case 0xE4: /* call po, address */ is_call = !PARITY_FLAG; break; case 0xEC: /* call pe, address */ is_call = PARITY_FLAG; break; case 0xF4: /* call p, address */ is_call = !SIGN_FLAG; break; case 0xFC: /* call m, address */ is_call = SIGN_FLAG; break; case 0xC7: case 0xCF: case 0xD7: case 0xDF: case 0xE7: case 0xEF: case 0xF7: case 0xFF: is_rst = 1; break; default: break; } if (is_call) { set_trap((REG_PC + 3) % ADDRESS_SPACE, BREAK_ONCE_FLAG); debug_run(); } else if (is_rst) { set_trap((REG_PC + 1) % ADDRESS_SPACE, BREAK_ONCE_FLAG); debug_run(); } else { z80_run((!strcmp(command, "nextint")) ? 0 : -1); } } else if(!strcmp(command, "quit")) { done = 1; } else if(!strcmp(command, "reset")) { printf("Performing hard reset."); trs_reset(1); } else if(!strcmp(command, "softreset")) { printf("Pressing reset button."); trs_reset(0); } else if(!strcmp(command, "run")) { printf("Performing hard reset and running.\n"); trs_reset(1); debug_run(); } else if(!strcmp(command, "status")) { print_traps(); } else if(!strcmp(command, "set") || !strcmp(command, "assign")) { char regname[MAXLINE]; int addr, value; if(sscanf(input, "%*s $%[a-zA-Z] = %x", regname, &value) == 2) { if(!strcasecmp(regname, "a")) { REG_A = value; } else if(!strcasecmp(regname, "f")) { REG_F = value; } else if(!strcasecmp(regname, "b")) { REG_B = value; } else if(!strcasecmp(regname, "c")) { REG_C = value; } else if(!strcasecmp(regname, "d")) { REG_D = value; } else if(!strcasecmp(regname, "e")) { REG_E = value; } else if(!strcasecmp(regname, "h")) { REG_H = value; } else if(!strcasecmp(regname, "l")) { REG_L = value; } else if(!strcasecmp(regname, "sp")) { REG_SP = value; } else if(!strcasecmp(regname, "pc")) { REG_PC = value; } else if(!strcasecmp(regname, "af")) { REG_AF = value; } else if(!strcasecmp(regname, "bc")) { REG_BC = value; } else if(!strcasecmp(regname, "de")) { REG_DE = value; } else if(!strcasecmp(regname, "hl")) { REG_HL = value; } else if(!strcasecmp(regname, "af'")) { REG_AF_PRIME = value; } else if(!strcasecmp(regname, "bc'")) { REG_BC_PRIME = value; } else if(!strcasecmp(regname, "de'")) { REG_DE_PRIME = value; } else if(!strcasecmp(regname, "hl'")) { REG_HL_PRIME = value; } else if(!strcasecmp(regname, "ix")) { REG_IX = value; } else if(!strcasecmp(regname, "iy")) { REG_IY = value; } else if(!strcasecmp(regname, "i")) { REG_I = value; } else { printf("Unrecognized register name %s.\n", regname); } } else if(sscanf(input, "%*s %x = %x", &addr, &value) == 2) { mem_write(addr, value); } else { printf("Syntax error. (Type \"help\" for commands.)\n"); } } else if(!strcmp(command, "step")) { z80_run(-1); } else if(!strcmp(command, "stepint")) { z80_run(0); } else if(!strcmp(command, "stop") || !strcmp(command, "break")) { int address; if(sscanf(input, "stop at %x", &address) != 1 && sscanf(input, "break %x", &address) != 1) { address = REG_PC; } address %= ADDRESS_SPACE; set_trap(address, BREAKPOINT_FLAG); } else if(!strcmp(command, "trace")) { int address; if(sscanf(input, "trace %x", &address) != 1) { address = REG_PC; } address %= ADDRESS_SPACE; set_trap(address, TRACE_FLAG); } else if(!strcmp(command, "untrace")) { printf("Untrace not implemented.\n"); } else if(!strcmp(command, "traceon")) { int address; if(sscanf(input, "traceon at %x", &address) == 1) { set_trap(address, DISASSEMBLE_ON_FLAG); } else { print_instructions = 1; printf("Tracing enabled.\n"); } } else if(!strcmp(command, "traceoff")) { int address; if(sscanf(input, "traceoff at %x", &address) == 1) { set_trap(address, DISASSEMBLE_OFF_FLAG); } else { print_instructions = 0; printf("Tracing disabled.\n"); } } else if(!strcmp(command, "watch")) { int address; if(sscanf(input, "watch %x", &address) == 1) { address %= ADDRESS_SPACE; set_trap(address, WATCHPOINT_FLAG); } } else if(!strcmp(command, "timeroff")) { /* Turn off emulated real time clock interrupt */ trs_timer_off(); } else if(!strcmp(command, "timeron")) { /* Turn off emulated real time clock interrupt */ trs_timer_on(); } else if(!strcmp(command, "diskdump")) { trs_disk_debug(); } else if(!strcmp(command, "diskdebug")) { trs_disk_debug_flags = 0; sscanf(input, "diskdebug %x", &trs_disk_debug_flags); } else { int start_address, end_address, num_bytes; if(sscanf(input, "%x , %x / ", &start_address, &end_address) == 2) { print_memory(start_address, end_address - start_address); } else if(sscanf(input, "%x / %x ", &start_address, &num_bytes) == 2) { print_memory(start_address, num_bytes); } else if(sscanf(input, "%x = ", &start_address) == 1) { print_memory(start_address, 1); } else { printf("Syntax error. (Type \"help\" for commands.)\n"); } } } } #ifdef READLINE write_history(history_file); #endif } #ifdef NEVER /* * Test code: */ carry_in(a, b, r) { return (a ^ b ^ r); } carry_out(a, b, r) { return (a & b) | ((a | b) & ~r); } overflow(a, b, r) { return carry_in(a, b, r) ^ carry_out(a, b, r); } test_add(int a, int b) { Uchar result; Uchar flags; result = a + b; flags = 0; if(result & 0x80) flags |= SIGN_MASK; if(result == 0) flags |= ZERO_MASK; if(carry_out(a, b, result) & 0x8) flags |= HALF_CARRY_MASK; if(overflow(a, b, result) & 0x80) flags |= OVERFLOW_MASK; if(carry_out(a, b, result) & 0x80) flags |= CARRY_MASK; do_add_flags(a, b, result); if(REG_F != flags) { printf("error: %d + %d = %d, expected %.2x, got %.2x\n", a, b, result, flags, REG_F); } } test_sub(int a, int b) { Uchar result; Uchar flags; result = a - b; flags = 0; if(result & 0x80) flags |= SIGN_MASK; if(result == 0) flags |= ZERO_MASK; if(carry_out(a, - b, result) & 0x8) flags |= HALF_CARRY_MASK; if(overflow(a, - b, result) & 0x80) flags |= OVERFLOW_MASK; flags |= SUBTRACT_MASK; if(carry_out(a, - b, result) & 0x80) flags |= CARRY_MASK; do_sub_flags(a, b, result); if(REG_F != flags) { printf("error: %d - %d = %d, expected %.2x, got %.2x\n", a, b, result, flags, REG_F); } } test_all() { int a, b; for(a = 0; a < 256; ++a) { for(b = 0; b < 256; ++b) { test_add(a, b); test_sub(a, b); } } } #endif xtrs-4.9d/dis.c000066400000000000000000002312451306603614600134710ustar00rootroot00000000000000/* * Copyright (C) 1992 Clarendon Hill Software. * * Permission is granted to any individual or institution to use, copy, * or redistribute this software, provided this copyright notice is retained. * * This software is provided "as is" without any expressed or implied * warranty. If this software brings on any sort of damage -- physical, * monetary, emotional, or brain -- too bad. You've got no one to blame * but yourself. * * The software may be modified for your own purposes, but modified versions * must retain this notice. */ /* Modified by Timothy Mann, 1996 and later $Id: dis.c,v 1.20 2009/06/16 00:10:06 mann Exp $ */ /* * dis.c -- a hacked version of "zdis" which can print out instructions * as they are executed. */ #include "z80.h" /* Argument printing */ #define A_0 0 /* No arguments */ #define A_8 1 /* 8-bit number */ #define A_16 2 /* 16-bit number */ #define A_0B 0xff /* No arguments, backskip over last opcode byte */ #define A_8P 0x100 /* 8-bit number preceding last opcode byte */ #define A_8R 0x101 /* 8-bit relative address */ #define A_8X2 0x102 /* Two 8-bit numbers */ #define arglen(a) ((signed char)((a)&0xff)) static char undefined[] = "undefined"; struct opcode { char *name; int args; }; static struct opcode major[256] = { { "nop", A_0 }, /* 00 */ { "ld bc,%02x%02xh", A_16 }, /* 01 */ { "ld (bc),a", A_0 }, /* 02 */ { "inc bc", A_0 }, /* 03 */ { "inc b", A_0 }, /* 04 */ { "dec b", A_0 }, /* 05 */ { "ld b,%02xh", A_8 }, /* 06 */ { "rlca", A_0 }, /* 07 */ { "ex af,af'", A_0 }, /* 08 */ { "add hl,bc", A_0 }, /* 09 */ { "ld a,(bc)", A_0 }, /* 0a */ { "dec bc", A_0 }, /* 0b */ { "inc c", A_0 }, /* 0c */ { "dec c", A_0 }, /* 0d */ { "ld c,%02xh", A_8 }, /* 0e */ { "rrca", A_0 }, /* 0f */ { "djnz %04xh", A_8R }, /* 10 */ { "ld de,%02x%02xh", A_16 }, /* 11 */ { "ld (de),a", A_0 }, /* 12 */ { "inc de", A_0 }, /* 13 */ { "inc d", A_0 }, /* 14 */ { "dec d", A_0 }, /* 15 */ { "ld d,%02xh", A_8 }, /* 16 */ { "rla", A_0 }, /* 17 */ { "jr %04xh", A_8R }, /* 18 */ { "add hl,de", A_0 }, /* 19 */ { "ld a,(de)", A_0 }, /* 1a */ { "dec de", A_0 }, /* 1b */ { "inc e", A_0 }, /* 1c */ { "dec e", A_0 }, /* 1d */ { "ld e,%02xh", A_8 }, /* 1e */ { "rra", A_0 }, /* 1f */ { "jr nz,%04xh", A_8R }, /* 20 */ { "ld hl,%02x%02xh", A_16 }, /* 21 */ { "ld (%02x%02xh),hl",A_16 }, /* 22 */ { "inc hl", A_0 }, /* 23 */ { "inc h", A_0 }, /* 24 */ { "dec h", A_0 }, /* 25 */ { "ld h,%02xh", A_8 }, /* 26 */ { "daa", A_0 }, /* 27 */ { "jr z,%04xh", A_8R }, /* 28 */ { "add hl,hl", A_0 }, /* 29 */ { "ld hl,(%02x%02xh)",A_16 }, /* 2a */ { "dec hl", A_0 }, /* 2b */ { "inc l", A_0 }, /* 2c */ { "dec l", A_0 }, /* 2d */ { "ld l,%02xh", A_8 }, /* 2e */ { "cpl", A_0 }, /* 2f */ { "jr nc,%04xh", A_8R }, /* 30 */ { "ld sp,%02x%02xh", A_16 }, /* 31 */ { "ld (%02x%02xh),a", A_16 }, /* 32 */ { "inc sp", A_0 }, /* 33 */ { "inc (hl)", A_0 }, /* 34 */ { "dec (hl)", A_0 }, /* 35 */ { "ld (hl),%02xh", A_8 }, /* 36 */ { "scf", A_0 }, /* 37 */ { "jr c,%04xh", A_8R }, /* 38 */ { "add hl,sp", A_0 }, /* 39 */ { "ld a,(%02x%02xh)", A_16 }, /* 3a */ { "dec sp", A_0 }, /* 3b */ { "inc a", A_0 }, /* 3c */ { "dec a", A_0 }, /* 3d */ { "ld a,%02xh", A_8 }, /* 3e */ { "ccf", A_0 }, /* 3f */ { "ld b,b", A_0 }, /* 40 */ { "ld b,c", A_0 }, /* 41 */ { "ld b,d", A_0 }, /* 42 */ { "ld b,e", A_0 }, /* 43 */ { "ld b,h", A_0 }, /* 44 */ { "ld b,l", A_0 }, /* 45 */ { "ld b,(hl)", A_0 }, /* 46 */ { "ld b,a", A_0 }, /* 47 */ { "ld c,b", A_0 }, /* 48 */ { "ld c,c", A_0 }, /* 49 */ { "ld c,d", A_0 }, /* 4a */ { "ld c,e", A_0 }, /* 4b */ { "ld c,h", A_0 }, /* 4c */ { "ld c,l", A_0 }, /* 4d */ { "ld c,(hl)", A_0 }, /* 4e */ { "ld c,a", A_0 }, /* 4f */ { "ld d,b", A_0 }, /* 50 */ { "ld d,c", A_0 }, /* 51 */ { "ld d,d", A_0 }, /* 52 */ { "ld d,e", A_0 }, /* 53 */ { "ld d,h", A_0 }, /* 54 */ { "ld d,l", A_0 }, /* 55 */ { "ld d,(hl)", A_0 }, /* 56 */ { "ld d,a", A_0 }, /* 57 */ { "ld e,b", A_0 }, /* 58 */ { "ld e,c", A_0 }, /* 59 */ { "ld e,d", A_0 }, /* 5a */ { "ld e,e", A_0 }, /* 5b */ { "ld e,h", A_0 }, /* 5c */ { "ld e,l", A_0 }, /* 5d */ { "ld e,(hl)", A_0 }, /* 5e */ { "ld e,a", A_0 }, /* 5f */ { "ld h,b", A_0 }, /* 60 */ { "ld h,c", A_0 }, /* 61 */ { "ld h,d", A_0 }, /* 62 */ { "ld h,e", A_0 }, /* 63 */ { "ld h,h", A_0 }, /* 64 */ { "ld h,l", A_0 }, /* 65 */ { "ld h,(hl)", A_0 }, /* 66 */ { "ld h,a", A_0 }, /* 67 */ { "ld l,b", A_0 }, /* 68 */ { "ld l,c", A_0 }, /* 69 */ { "ld l,d", A_0 }, /* 6a */ { "ld l,e", A_0 }, /* 6b */ { "ld l,h", A_0 }, /* 6c */ { "ld l,l", A_0 }, /* 6d */ { "ld l,(hl)", A_0 }, /* 6e */ { "ld l,a", A_0 }, /* 6f */ { "ld (hl),b", A_0 }, /* 70 */ { "ld (hl),c", A_0 }, /* 71 */ { "ld (hl),d", A_0 }, /* 72 */ { "ld (hl),e", A_0 }, /* 73 */ { "ld (hl),h", A_0 }, /* 74 */ { "ld (hl),l", A_0 }, /* 75 */ { "halt", A_0 }, /* 76 */ { "ld (hl),a", A_0 }, /* 77 */ { "ld a,b", A_0 }, /* 78 */ { "ld a,c", A_0 }, /* 79 */ { "ld a,d", A_0 }, /* 7a */ { "ld a,e", A_0 }, /* 7b */ { "ld a,h", A_0 }, /* 7c */ { "ld a,l", A_0 }, /* 7d */ { "ld a,(hl)", A_0 }, /* 7e */ { "ld a,a", A_0 }, /* 7f */ { "add a,b", A_0 }, /* 80 */ { "add a,c", A_0 }, /* 81 */ { "add a,d", A_0 }, /* 82 */ { "add a,e", A_0 }, /* 83 */ { "add a,h", A_0 }, /* 84 */ { "add a,l", A_0 }, /* 85 */ { "add a,(hl)", A_0 }, /* 86 */ { "add a,a", A_0 }, /* 87 */ { "adc a,b", A_0 }, /* 88 */ { "adc a,c", A_0 }, /* 89 */ { "adc a,d", A_0 }, /* 8a */ { "adc a,e", A_0 }, /* 8b */ { "adc a,h", A_0 }, /* 8c */ { "adc a,l", A_0 }, /* 8d */ { "adc a,(hl)", A_0 }, /* 8e */ { "adc a,a", A_0 }, /* 8f */ { "sub b", A_0 }, /* 90 */ { "sub c", A_0 }, /* 91 */ { "sub d", A_0 }, /* 92 */ { "sub e", A_0 }, /* 93 */ { "sub h", A_0 }, /* 94 */ { "sub l", A_0 }, /* 95 */ { "sub (hl)", A_0 }, /* 96 */ { "sub a", A_0 }, /* 97 */ { "sbc a,b", A_0 }, /* 98 */ { "sbc a,c", A_0 }, /* 99 */ { "sbc a,d", A_0 }, /* 9a */ { "sbc a,e", A_0 }, /* 9b */ { "sbc a,h", A_0 }, /* 9c */ { "sbc a,l", A_0 }, /* 9d */ { "sbc a,(hl)", A_0 }, /* 9e */ { "sbc a,a", A_0 }, /* 9f */ { "and b", A_0 }, /* a0 */ { "and c", A_0 }, /* a1 */ { "and d", A_0 }, /* a2 */ { "and e", A_0 }, /* a3 */ { "and h", A_0 }, /* a4 */ { "and l", A_0 }, /* a5 */ { "and (hl)", A_0 }, /* a6 */ { "and a", A_0 }, /* a7 */ { "xor b", A_0 }, /* a8 */ { "xor c", A_0 }, /* a9 */ { "xor d", A_0 }, /* aa */ { "xor e", A_0 }, /* ab */ { "xor h", A_0 }, /* ac */ { "xor l", A_0 }, /* ad */ { "xor (hl)", A_0 }, /* ae */ { "xor a", A_0 }, /* af */ { "or b", A_0 }, /* b0 */ { "or c", A_0 }, /* b1 */ { "or d", A_0 }, /* b2 */ { "or e", A_0 }, /* b3 */ { "or h", A_0 }, /* b4 */ { "or l", A_0 }, /* b5 */ { "or (hl)", A_0 }, /* b6 */ { "or a", A_0 }, /* b7 */ { "cp b", A_0 }, /* b8 */ { "cp c", A_0 }, /* b9 */ { "cp d", A_0 }, /* ba */ { "cp e", A_0 }, /* bb */ { "cp h", A_0 }, /* bc */ { "cp l", A_0 }, /* bd */ { "cp (hl)", A_0 }, /* be */ { "cp a", A_0 }, /* bf */ { "ret nz", A_0 }, /* c0 */ { "pop bc", A_0 }, /* c1 */ { "jp nz,%02x%02xh", A_16 }, /* c2 */ { "jp %02x%02xh", A_16 }, /* c3 */ { "call nz,%02x%02xh", A_16 }, /* c4 */ { "push bc", A_0 }, /* c5 */ { "add a,%02xh", A_8 }, /* c6 */ { "rst 0", A_0 }, /* c7 */ { "ret z", A_0 }, /* c8 */ { "ret", A_0 }, /* c9 */ { "jp z,%02x%02xh", A_16 }, /* ca */ { 0, 0 }, /* cb */ { "call z,%02x%02xh", A_16 }, /* cc */ { "call %02x%02xh", A_16 }, /* cd */ { "adc a,%02xh", A_8 }, /* ce */ { "rst 8", A_0 }, /* cf */ { "ret nc", A_0 }, /* d0 */ { "pop de", A_0 }, /* d1 */ { "jp nc,%02x%02xh", A_16 }, /* d2 */ { "out (%02xh),a", A_8 }, /* d3 */ { "call nc,%02x%02xh", A_16 }, /* d4 */ { "push de", A_0 }, /* d5 */ { "sub %02xh", A_8 }, /* d6 */ { "rst 10h", A_0 }, /* d7 */ { "ret c", A_0 }, /* d8 */ { "exx", A_0 }, /* d9 */ { "jp c,%02x%02xh", A_16 }, /* da */ { "in a,(%02xh)", A_8 }, /* db */ { "call c,%02x%02xh", A_16 }, /* dc */ { 0, 1 }, /* dd */ { "sbc a,%02xh", A_8 }, /* de */ { "rst 18h", A_0 }, /* df */ { "ret po", A_0 }, /* e0 */ { "pop hl", A_0 }, /* e1 */ { "jp po,%02x%02xh", A_16 }, /* e2 */ { "ex (sp),hl", A_0 }, /* e3 */ { "call po,%02x%02xh", A_16 }, /* e4 */ { "push hl", A_0 }, /* e5 */ { "and %02xh", A_8 }, /* e6 */ { "rst 20h", A_0 }, /* e7 */ { "ret pe", A_0 }, /* e8 */ { "jp (hl)", A_0 }, /* e9 */ { "jp pe,%02x%02xh", A_16 }, /* ea */ { "ex de,hl", A_0 }, /* eb */ { "call pe,%02x%02xh", A_16 }, /* ec */ { 0, 2 }, /* ed */ { "xor %02xh", A_8 }, /* ee */ { "rst 28h", A_0 }, /* ef */ { "ret p", A_0 }, /* f0 */ { "pop af", A_0 }, /* f1 */ { "jp p,%02x%02xh", A_16 }, /* f2 */ { "di", A_0 }, /* f3 */ { "call p,%02x%02xh", A_16 }, /* f4 */ { "push af", A_0 }, /* f5 */ { "or %02xh", A_8 }, /* f6 */ { "rst 30h", A_0 }, /* f7 */ { "ret m", A_0 }, /* f8 */ { "ld sp,hl", A_0 }, /* f9 */ { "jp m,%02x%02xh", A_16 }, /* fa */ { "ei", A_0 }, /* fb */ { "call m,%02x%02xh", A_16 }, /* fc */ { 0, 3 }, /* fd */ { "cp %02xh", A_8 }, /* fe */ { "rst 38h", A_0 }, /* ff */ }; static struct opcode minor[6][256] = { { /* cb */ { "rlc b", A_0 }, /* cb00 */ { "rlc c", A_0 }, /* cb01 */ { "rlc d", A_0 }, /* cb02 */ { "rlc e", A_0 }, /* cb03 */ { "rlc h", A_0 }, /* cb04 */ { "rlc l", A_0 }, /* cb05 */ { "rlc (hl)", A_0 }, /* cb06 */ { "rlc a", A_0 }, /* cb07 */ { "rrc b", A_0 }, /* cb08 */ { "rrc c", A_0 }, /* cb09 */ { "rrc d", A_0 }, /* cb0a */ { "rrc e", A_0 }, /* cb0b */ { "rrc h", A_0 }, /* cb0c */ { "rrc l", A_0 }, /* cb0d */ { "rrc (hl)", A_0 }, /* cb0e */ { "rrc a", A_0 }, /* cb0f */ { "rl b", A_0 }, /* cb10 */ { "rl c", A_0 }, /* cb11 */ { "rl d", A_0 }, /* cb12 */ { "rl e", A_0 }, /* cb13 */ { "rl h", A_0 }, /* cb14 */ { "rl l", A_0 }, /* cb15 */ { "rl (hl)", A_0 }, /* cb16 */ { "rl a", A_0 }, /* cb17 */ { "rr b", A_0 }, /* cb18 */ { "rr c", A_0 }, /* cb19 */ { "rr d", A_0 }, /* cb1a */ { "rr e", A_0 }, /* cb1b */ { "rr h", A_0 }, /* cb1c */ { "rr l", A_0 }, /* cb1d */ { "rr (hl)", A_0 }, /* cb1e */ { "rr a", A_0 }, /* cb1f */ { "sla b", A_0 }, /* cb20 */ { "sla c", A_0 }, /* cb21 */ { "sla d", A_0 }, /* cb22 */ { "sla e", A_0 }, /* cb23 */ { "sla h", A_0 }, /* cb24 */ { "sla l", A_0 }, /* cb25 */ { "sla (hl)", A_0 }, /* cb26 */ { "sla a", A_0 }, /* cb27 */ { "sra b", A_0 }, /* cb28 */ { "sra c", A_0 }, /* cb29 */ { "sra d", A_0 }, /* cb2a */ { "sra e", A_0 }, /* cb2b */ { "sra h", A_0 }, /* cb2c */ { "sra l", A_0 }, /* cb2d */ { "sra (hl)", A_0 }, /* cb2e */ { "sra a", A_0 }, /* cb2f */ { "slia b", A_0 }, /* cb30 [undoc] */ { "slia c", A_0 }, /* cb31 [undoc] */ { "slia d", A_0 }, /* cb32 [undoc] */ { "slia e", A_0 }, /* cb33 [undoc] */ { "slia h", A_0 }, /* cb34 [undoc] */ { "slia l", A_0 }, /* cb35 [undoc] */ { "slia (hl)", A_0 }, /* cb36 [undoc] */ { "slia a", A_0 }, /* cb37 [undoc] */ { "srl b", A_0 }, /* cb38 */ { "srl c", A_0 }, /* cb39 */ { "srl d", A_0 }, /* cb3a */ { "srl e", A_0 }, /* cb3b */ { "srl h", A_0 }, /* cb3c */ { "srl l", A_0 }, /* cb3d */ { "srl (hl)", A_0 }, /* cb3e */ { "srl a", A_0 }, /* cb3f */ { "bit 0,b", A_0 }, /* cb40 */ { "bit 0,c", A_0 }, /* cb41 */ { "bit 0,d", A_0 }, /* cb42 */ { "bit 0,e", A_0 }, /* cb43 */ { "bit 0,h", A_0 }, /* cb44 */ { "bit 0,l", A_0 }, /* cb45 */ { "bit 0,(hl)", A_0 }, /* cb46 */ { "bit 0,a", A_0 }, /* cb47 */ { "bit 1,b", A_0 }, /* cb48 */ { "bit 1,c", A_0 }, /* cb49 */ { "bit 1,d", A_0 }, /* cb4a */ { "bit 1,e", A_0 }, /* cb4b */ { "bit 1,h", A_0 }, /* cb4c */ { "bit 1,l", A_0 }, /* cb4d */ { "bit 1,(hl)", A_0 }, /* cb4e */ { "bit 1,a", A_0 }, /* cb4f */ { "bit 2,b", A_0 }, /* cb50 */ { "bit 2,c", A_0 }, /* cb51 */ { "bit 2,d", A_0 }, /* cb52 */ { "bit 2,e", A_0 }, /* cb53 */ { "bit 2,h", A_0 }, /* cb54 */ { "bit 2,l", A_0 }, /* cb55 */ { "bit 2,(hl)", A_0 }, /* cb56 */ { "bit 2,a", A_0 }, /* cb57 */ { "bit 3,b", A_0 }, /* cb58 */ { "bit 3,c", A_0 }, /* cb59 */ { "bit 3,d", A_0 }, /* cb5a */ { "bit 3,e", A_0 }, /* cb5b */ { "bit 3,h", A_0 }, /* cb5c */ { "bit 3,l", A_0 }, /* cb5d */ { "bit 3,(hl)", A_0 }, /* cb5e */ { "bit 3,a", A_0 }, /* cb5f */ { "bit 4,b", A_0 }, /* cb60 */ { "bit 4,c", A_0 }, /* cb61 */ { "bit 4,d", A_0 }, /* cb62 */ { "bit 4,e", A_0 }, /* cb63 */ { "bit 4,h", A_0 }, /* cb64 */ { "bit 4,l", A_0 }, /* cb65 */ { "bit 4,(hl)", A_0 }, /* cb66 */ { "bit 4,a", A_0 }, /* cb67 */ { "bit 5,b", A_0 }, /* cb68 */ { "bit 5,c", A_0 }, /* cb69 */ { "bit 5,d", A_0 }, /* cb6a */ { "bit 5,e", A_0 }, /* cb6b */ { "bit 5,h", A_0 }, /* cb6c */ { "bit 5,l", A_0 }, /* cb6d */ { "bit 5,(hl)", A_0 }, /* cb6e */ { "bit 5,a", A_0 }, /* cb6f */ { "bit 6,b", A_0 }, /* cb70 */ { "bit 6,c", A_0 }, /* cb71 */ { "bit 6,d", A_0 }, /* cb72 */ { "bit 6,e", A_0 }, /* cb73 */ { "bit 6,h", A_0 }, /* cb74 */ { "bit 6,l", A_0 }, /* cb75 */ { "bit 6,(hl)", A_0 }, /* cb76 */ { "bit 6,a", A_0 }, /* cb77 */ { "bit 7,b", A_0 }, /* cb78 */ { "bit 7,c", A_0 }, /* cb79 */ { "bit 7,d", A_0 }, /* cb7a */ { "bit 7,e", A_0 }, /* cb7b */ { "bit 7,h", A_0 }, /* cb7c */ { "bit 7,l", A_0 }, /* cb7d */ { "bit 7,(hl)", A_0 }, /* cb7e */ { "bit 7,a", A_0 }, /* cb7f */ { "res 0,b", A_0 }, /* cb80 */ { "res 0,c", A_0 }, /* cb81 */ { "res 0,d", A_0 }, /* cb82 */ { "res 0,e", A_0 }, /* cb83 */ { "res 0,h", A_0 }, /* cb84 */ { "res 0,l", A_0 }, /* cb85 */ { "res 0,(hl)", A_0 }, /* cb86 */ { "res 0,a", A_0 }, /* cb87 */ { "res 1,b", A_0 }, /* cb88 */ { "res 1,c", A_0 }, /* cb89 */ { "res 1,d", A_0 }, /* cb8a */ { "res 1,e", A_0 }, /* cb8b */ { "res 1,h", A_0 }, /* cb8c */ { "res 1,l", A_0 }, /* cb8d */ { "res 1,(hl)", A_0 }, /* cb8e */ { "res 1,a", A_0 }, /* cb8f */ { "res 2,b", A_0 }, /* cb90 */ { "res 2,c", A_0 }, /* cb91 */ { "res 2,d", A_0 }, /* cb92 */ { "res 2,e", A_0 }, /* cb93 */ { "res 2,h", A_0 }, /* cb94 */ { "res 2,l", A_0 }, /* cb95 */ { "res 2,(hl)", A_0 }, /* cb96 */ { "res 2,a", A_0 }, /* cb97 */ { "res 3,b", A_0 }, /* cb98 */ { "res 3,c", A_0 }, /* cb99 */ { "res 3,d", A_0 }, /* cb9a */ { "res 3,e", A_0 }, /* cb9b */ { "res 3,h", A_0 }, /* cb9c */ { "res 3,l", A_0 }, /* cb9d */ { "res 3,(hl)", A_0 }, /* cb9e */ { "res 3,a", A_0 }, /* cb9f */ { "res 4,b", A_0 }, /* cba0 */ { "res 4,c", A_0 }, /* cba1 */ { "res 4,d", A_0 }, /* cba2 */ { "res 4,e", A_0 }, /* cba3 */ { "res 4,h", A_0 }, /* cba4 */ { "res 4,l", A_0 }, /* cba5 */ { "res 4,(hl)", A_0 }, /* cba6 */ { "res 4,a", A_0 }, /* cba7 */ { "res 5,b", A_0 }, /* cba8 */ { "res 5,c", A_0 }, /* cba9 */ { "res 5,d", A_0 }, /* cbaa */ { "res 5,e", A_0 }, /* cbab */ { "res 5,h", A_0 }, /* cbac */ { "res 5,l", A_0 }, /* cbad */ { "res 5,(hl)", A_0 }, /* cbae */ { "res 5,a", A_0 }, /* cbaf */ { "res 6,b", A_0 }, /* cbb0 */ { "res 6,c", A_0 }, /* cbb1 */ { "res 6,d", A_0 }, /* cbb2 */ { "res 6,e", A_0 }, /* cbb3 */ { "res 6,h", A_0 }, /* cbb4 */ { "res 6,l", A_0 }, /* cbb5 */ { "res 6,(hl)", A_0 }, /* cbb6 */ { "res 6,a", A_0 }, /* cbb7 */ { "res 7,b", A_0 }, /* cbb8 */ { "res 7,c", A_0 }, /* cbb9 */ { "res 7,d", A_0 }, /* cbba */ { "res 7,e", A_0 }, /* cbbb */ { "res 7,h", A_0 }, /* cbbc */ { "res 7,l", A_0 }, /* cbbd */ { "res 7,(hl)", A_0 }, /* cbbe */ { "res 7,a", A_0 }, /* cbbf */ { "set 0,b", A_0 }, /* cbc0 */ { "set 0,c", A_0 }, /* cbc1 */ { "set 0,d", A_0 }, /* cbc2 */ { "set 0,e", A_0 }, /* cbc3 */ { "set 0,h", A_0 }, /* cbc4 */ { "set 0,l", A_0 }, /* cbc5 */ { "set 0,(hl)", A_0 }, /* cbc6 */ { "set 0,a", A_0 }, /* cbc7 */ { "set 1,b", A_0 }, /* cbc8 */ { "set 1,c", A_0 }, /* cbc9 */ { "set 1,d", A_0 }, /* cbca */ { "set 1,e", A_0 }, /* cbcb */ { "set 1,h", A_0 }, /* cbcc */ { "set 1,l", A_0 }, /* cbcd */ { "set 1,(hl)", A_0 }, /* cbce */ { "set 1,a", A_0 }, /* cbcf */ { "set 2,b", A_0 }, /* cbd0 */ { "set 2,c", A_0 }, /* cbd1 */ { "set 2,d", A_0 }, /* cbd2 */ { "set 2,e", A_0 }, /* cbd3 */ { "set 2,h", A_0 }, /* cbd4 */ { "set 2,l", A_0 }, /* cbd5 */ { "set 2,(hl)", A_0 }, /* cbd6 */ { "set 2,a", A_0 }, /* cbd7 */ { "set 3,b", A_0 }, /* cbd8 */ { "set 3,c", A_0 }, /* cbd9 */ { "set 3,d", A_0 }, /* cbda */ { "set 3,e", A_0 }, /* cbdb */ { "set 3,h", A_0 }, /* cbdc */ { "set 3,l", A_0 }, /* cbdd */ { "set 3,(hl)", A_0 }, /* cbde */ { "set 3,a", A_0 }, /* cbdf */ { "set 4,b", A_0 }, /* cbe0 */ { "set 4,c", A_0 }, /* cbe1 */ { "set 4,d", A_0 }, /* cbe2 */ { "set 4,e", A_0 }, /* cbe3 */ { "set 4,h", A_0 }, /* cbe4 */ { "set 4,l", A_0 }, /* cbe5 */ { "set 4,(hl)", A_0 }, /* cbe6 */ { "set 4,a", A_0 }, /* cbe7 */ { "set 5,b", A_0 }, /* cbe8 */ { "set 5,c", A_0 }, /* cbe9 */ { "set 5,d", A_0 }, /* cbea */ { "set 5,e", A_0 }, /* cbeb */ { "set 5,h", A_0 }, /* cbec */ { "set 5,l", A_0 }, /* cbed */ { "set 5,(hl)", A_0 }, /* cbee */ { "set 5,a", A_0 }, /* cbef */ { "set 6,b", A_0 }, /* cbf0 */ { "set 6,c", A_0 }, /* cbf1 */ { "set 6,d", A_0 }, /* cbf2 */ { "set 6,e", A_0 }, /* cbf3 */ { "set 6,h", A_0 }, /* cbf4 */ { "set 6,l", A_0 }, /* cbf5 */ { "set 6,(hl)", A_0 }, /* cbf6 */ { "set 6,a", A_0 }, /* cbf7 */ { "set 7,b", A_0 }, /* cbf8 */ { "set 7,c", A_0 }, /* cbf9 */ { "set 7,d", A_0 }, /* cbfa */ { "set 7,e", A_0 }, /* cbfb */ { "set 7,h", A_0 }, /* cbfc */ { "set 7,l", A_0 }, /* cbfd */ { "set 7,(hl)", A_0 }, /* cbfe */ { "set 7,a", A_0 }, /* cbff */ }, { /* dd */ { undefined, A_0B }, /* dd00 */ { undefined, A_0B }, /* dd01 */ { undefined, A_0B }, /* dd02 */ { undefined, A_0B }, /* dd03 */ { undefined, A_0B }, /* dd04 */ { undefined, A_0B }, /* dd05 */ { undefined, A_0B }, /* dd06 */ { undefined, A_0B }, /* dd07 */ { undefined, A_0B }, /* dd08 */ { "add ix,bc", A_0 }, /* dd09 */ { undefined, A_0B }, /* dd0a */ { undefined, A_0B }, /* dd0b */ { undefined, A_0B }, /* dd0c */ { undefined, A_0B }, /* dd0d */ { undefined, A_0B }, /* dd0e */ { undefined, A_0B }, /* dd0f */ { undefined, A_0B }, /* dd10 */ { undefined, A_0B }, /* dd11 */ { undefined, A_0B }, /* dd12 */ { undefined, A_0B }, /* dd13 */ { undefined, A_0B }, /* dd14 */ { undefined, A_0B }, /* dd15 */ { undefined, A_0B }, /* dd16 */ { undefined, A_0B }, /* dd17 */ { undefined, A_0B }, /* dd18 */ { "add ix,de", A_0 }, /* dd19 */ { undefined, A_0B }, /* dd1a */ { undefined, A_0B }, /* dd1b */ { undefined, A_0B }, /* dd1c */ { undefined, A_0B }, /* dd1d */ { undefined, A_0B }, /* dd1e */ { undefined, A_0B }, /* dd1f */ { undefined, A_0B }, /* dd20 */ { "ld ix,%02x%02xh", A_16 }, /* dd21 */ { "ld (%02x%02xh),ix",A_16 }, /* dd22 */ { "inc ix", A_0 }, /* dd23 */ { "inc ixh", A_0 }, /* dd24 [undoc] */ { "dec ixh", A_0 }, /* dd25 [undoc] */ { "ld ixh,%02xh", A_8 }, /* dd26 [undoc] */ { undefined, A_0B }, /* dd27 */ { undefined, A_0B }, /* dd28 */ { "add ix,ix", A_0 }, /* dd29 */ { "ld ix,(%02x%02xh)",A_16 }, /* dd2a */ { "dec ix", A_0 }, /* dd2b */ { "inc ixl", A_0 }, /* dd2c [undoc] */ { "dec ixl", A_0 }, /* dd2d [undoc] */ { "ld ixl,%02xh", A_8 }, /* dd2e [undoc] */ { undefined, A_0B }, /* dd2f */ { undefined, A_0B }, /* dd30 */ { undefined, A_0B }, /* dd31 */ { undefined, A_0B }, /* dd32 */ { undefined, A_0B }, /* dd33 */ { "inc (ix+%02xh)", A_8 }, /* dd34 */ { "dec (ix+%02xh)", A_8 }, /* dd35 */ { "ld (ix+%02xh),%02xh",A_8X2 }, /* dd36 */ { undefined, A_0B }, /* dd37 */ { undefined, A_0B }, /* dd38 */ { "add ix,sp", A_0 }, /* dd39 */ { undefined, A_0B }, /* dd3a */ { undefined, A_0B }, /* dd3b */ { undefined, A_0B }, /* dd3c */ { undefined, A_0B }, /* dd3d */ { undefined, A_0B }, /* dd3e */ { undefined, A_0B }, /* dd3f */ { undefined, A_0B }, /* dd40 */ { undefined, A_0B }, /* dd41 */ { undefined, A_0B }, /* dd42 */ { undefined, A_0B }, /* dd43 */ { "ld b,ixh", A_0 }, /* dd44 [undoc] */ { "ld b,ixl", A_0 }, /* dd45 [undoc] */ { "ld b,(ix+%02xh)", A_8 }, /* dd46 */ { undefined, A_0B }, /* dd47 */ { undefined, A_0B }, /* dd48 */ { undefined, A_0B }, /* dd49 */ { undefined, A_0B }, /* dd4a */ { undefined, A_0B }, /* dd4b */ { "ld c,ixh", A_0 }, /* dd4c [undoc] */ { "ld c,ixl", A_0 }, /* dd4d [undoc] */ { "ld c,(ix+%02xh)", A_8 }, /* dd4e */ { undefined, A_0B }, /* dd4f */ { undefined, A_0B }, /* dd50 */ { undefined, A_0B }, /* dd51 */ { undefined, A_0B }, /* dd52 */ { undefined, A_0B }, /* dd53 */ { "ld d,ixh", A_0 }, /* dd54 [undoc] */ { "ld d,ixl", A_0 }, /* dd55 [undoc] */ { "ld d,(ix+%02xh)", A_8 }, /* dd56 */ { undefined, A_0B }, /* dd57 */ { undefined, A_0B }, /* dd58 */ { undefined, A_0B }, /* dd59 */ { undefined, A_0B }, /* dd5a */ { undefined, A_0B }, /* dd5b */ { "ld e,ixh", A_0 }, /* dd5c [undoc] */ { "ld e,ixl", A_0 }, /* dd5d [undoc] */ { "ld e,(ix+%02xh)", A_8 }, /* dd5e */ { undefined, A_0B }, /* dd5f */ { "ld ixh,b", A_0 }, /* dd60 [undoc] */ { "ld ixh,c", A_0 }, /* dd61 [undoc] */ { "ld ixh,d", A_0 }, /* dd62 [undoc] */ { "ld ixh,e", A_0 }, /* dd63 [undoc] */ { "ld ixh,ixh", A_0 }, /* dd64 [undoc] */ { "ld ixh,ixl", A_0 }, /* dd65 [undoc] */ { "ld h,(ix+%02xh)", A_8 }, /* dd66 */ { "ld ixh,a", A_0 }, /* dd67 [undoc] */ { "ld ixl,b", A_0 }, /* dd68 [undoc] */ { "ld ixl,c", A_0 }, /* dd69 [undoc] */ { "ld ixl,d", A_0 }, /* dd6a [undoc] */ { "ld ixl,e", A_0 }, /* dd6b [undoc] */ { "ld ixl,ixh", A_0 }, /* dd6c [undoc] */ { "ld ixl,ixl", A_0 }, /* dd6d [undoc] */ { "ld l,(ix+%02xh)", A_8 }, /* dd6e */ { "ld ixl,a", A_0 }, /* dd6f [undoc] */ { "ld (ix+%02xh),b", A_8 }, /* dd70 */ { "ld (ix+%02xh),c", A_8 }, /* dd71 */ { "ld (ix+%02xh),d", A_8 }, /* dd72 */ { "ld (ix+%02xh),e", A_8 }, /* dd73 */ { "ld (ix+%02xh),h", A_8 }, /* dd74 */ { "ld (ix+%02xh),l", A_8 }, /* dd75 */ { undefined, A_0B }, /* dd76 */ { "ld (ix+%02xh),a", A_8 }, /* dd77 */ { undefined, A_0B }, /* dd78 */ { undefined, A_0B }, /* dd79 */ { undefined, A_0B }, /* dd7a */ { undefined, A_0B }, /* dd7b */ { "ld a,ixh", A_0 }, /* dd7c [undoc] */ { "ld a,ixl", A_0 }, /* dd7d [undoc] */ { "ld a,(ix+%02xh)", A_8 }, /* dd7e */ { undefined, A_0B }, /* dd7f */ { undefined, A_0B }, /* dd80 */ { undefined, A_0B }, /* dd81 */ { undefined, A_0B }, /* dd82 */ { undefined, A_0B }, /* dd83 */ { "add a,ixh", A_0 }, /* dd84 [undoc] */ { "add a,ixl", A_0 }, /* dd85 [undoc] */ { "add a,(ix+%02xh)", A_8 }, /* dd86 */ { undefined, A_0B }, /* dd87 */ { undefined, A_0B }, /* dd88 */ { undefined, A_0B }, /* dd89 */ { undefined, A_0B }, /* dd8a */ { undefined, A_0B }, /* dd8b */ { "adc a,ixh", A_0 }, /* dd8c [undoc] */ { "adc a,ixl", A_0 }, /* dd8d [undoc] */ { "adc a,(ix+%02xh)", A_8 }, /* dd8e */ { undefined, A_0B }, /* dd8f */ { undefined, A_0B }, /* dd90 */ { undefined, A_0B }, /* dd91 */ { undefined, A_0B }, /* dd92 */ { undefined, A_0B }, /* dd93 */ { "sub ixh", A_0 }, /* dd94 [undoc] */ { "sub ixl", A_0 }, /* dd95 [undoc] */ { "sub (ix+%02xh)", A_8 }, /* dd96 */ { undefined, A_0B }, /* dd97 */ { undefined, A_0B }, /* dd98 */ { undefined, A_0B }, /* dd99 */ { undefined, A_0B }, /* dd9a */ { undefined, A_0B }, /* dd9b */ { "sbc ixh", A_0 }, /* dd9c [undoc] */ { "sbc ixl", A_0 }, /* dd9d [undoc] */ { "sbc a,(ix+%02xh)", A_8 }, /* dd9e */ { undefined, A_0B }, /* dd9f */ { undefined, A_0B }, /* dda0 */ { undefined, A_0B }, /* dda1 */ { undefined, A_0B }, /* dda2 */ { undefined, A_0B }, /* dda3 */ { "and ixh", A_0 }, /* dda4 [undoc] */ { "and ixl", A_0 }, /* dda5 [undoc] */ { "and (ix+%02xh)", A_8 }, /* dda6 */ { undefined, A_0B }, /* dda7 */ { undefined, A_0B }, /* dda8 */ { undefined, A_0B }, /* dda9 */ { undefined, A_0B }, /* ddaa */ { undefined, A_0B }, /* ddab */ { "xor ixh", A_0 }, /* ddac [undoc] */ { "xor ixl", A_0 }, /* ddad [undoc] */ { "xor (ix+%02xh)", A_8 }, /* ddae */ { undefined, A_0B }, /* ddaf */ { undefined, A_0B }, /* ddb0 */ { undefined, A_0B }, /* ddb1 */ { undefined, A_0B }, /* ddb2 */ { undefined, A_0B }, /* ddb3 */ { "or ixh", A_0 }, /* ddb4 [undoc] */ { "or ixl", A_0 }, /* ddb5 [undoc] */ { "or (ix+%02xh)", A_8 }, /* ddb6 */ { undefined, A_0B }, /* ddb7 */ { undefined, A_0B }, /* ddb8 */ { undefined, A_0B }, /* ddb9 */ { undefined, A_0B }, /* ddba */ { undefined, A_0B }, /* ddbb */ { "cp ixh", A_0 }, /* ddbc [undoc] */ { "cp ixl", A_0 }, /* ddbd [undoc] */ { "cp (ix+%02xh)", A_8 }, /* ddbe */ { undefined, A_0B }, /* ddbf */ { undefined, A_0B }, /* ddc0 */ { undefined, A_0B }, /* ddc1 */ { undefined, A_0B }, /* ddc2 */ { undefined, A_0B }, /* ddc3 */ { undefined, A_0B }, /* ddc4 */ { undefined, A_0B }, /* ddc5 */ { undefined, A_0B }, /* ddc6 */ { undefined, A_0B }, /* ddc7 */ { undefined, A_0B }, /* ddc8 */ { undefined, A_0B }, /* ddc9 */ { undefined, A_0B }, /* ddca */ { 0, 4 }, /* ddcb */ { undefined, A_0B }, /* ddcc */ { undefined, A_0B }, /* ddcd */ { undefined, A_0B }, /* ddce */ { undefined, A_0B }, /* ddcf */ { undefined, A_0B }, /* ddd0 */ { undefined, A_0B }, /* ddd1 */ { undefined, A_0B }, /* ddd2 */ { undefined, A_0B }, /* ddd3 */ { undefined, A_0B }, /* ddd4 */ { undefined, A_0B }, /* ddd5 */ { undefined, A_0B }, /* ddd6 */ { undefined, A_0B }, /* ddd7 */ { undefined, A_0B }, /* ddd8 */ { undefined, A_0B }, /* ddd9 */ { undefined, A_0B }, /* ddda */ { undefined, A_0B }, /* dddb */ { undefined, A_0B }, /* dddc */ { undefined, A_0B }, /* dddd */ { undefined, A_0B }, /* ddde */ { undefined, A_0B }, /* dddf */ { undefined, A_0B }, /* dde0 */ { "pop ix", A_0 }, /* dde1 */ { undefined, A_0B }, /* dde2 */ { "ex (sp),ix", A_0 }, /* dde3 */ { undefined, A_0B }, /* dde4 */ { "push ix", A_0 }, /* dde5 */ { undefined, A_0B }, /* dde6 */ { undefined, A_0B }, /* dde7 */ { undefined, A_0B }, /* dde8 */ { "jp (ix)", A_0 }, /* dde9 */ { undefined, A_0B }, /* ddea */ { undefined, A_0B }, /* ddeb */ { undefined, A_0B }, /* ddec */ { undefined, A_0B }, /* dded */ { undefined, A_0B }, /* ddee */ { undefined, A_0B }, /* ddef */ { undefined, A_0B }, /* ddf0 */ { undefined, A_0B }, /* ddf1 */ { undefined, A_0B }, /* ddf2 */ { undefined, A_0B }, /* ddf3 */ { undefined, A_0B }, /* ddf4 */ { undefined, A_0B }, /* ddf5 */ { undefined, A_0B }, /* ddf6 */ { undefined, A_0B }, /* ddf7 */ { undefined, A_0B }, /* ddf8 */ { "ld sp,ix", A_0 }, /* ddf9 */ { undefined, A_0B }, /* ddfa */ { undefined, A_0B }, /* ddfb */ { undefined, A_0B }, /* ddfc */ { undefined, A_0B }, /* ddfd */ { undefined, A_0B }, /* ddfe */ { undefined, A_0B }, /* ddff */ }, { /* ed */ { undefined, A_0 }, /* ed00 */ { undefined, A_0 }, /* ed01 */ { undefined, A_0 }, /* ed02 */ { undefined, A_0 }, /* ed03 */ { undefined, A_0 }, /* ed04 */ { undefined, A_0 }, /* ed05 */ { undefined, A_0 }, /* ed06 */ { undefined, A_0 }, /* ed07 */ { undefined, A_0 }, /* ed08 */ { undefined, A_0 }, /* ed09 */ { undefined, A_0 }, /* ed0a */ { undefined, A_0 }, /* ed0b */ { undefined, A_0 }, /* ed0c */ { undefined, A_0 }, /* ed0d */ { undefined, A_0 }, /* ed0e */ { undefined, A_0 }, /* ed0f */ { undefined, A_0 }, /* ed10 */ { undefined, A_0 }, /* ed11 */ { undefined, A_0 }, /* ed12 */ { undefined, A_0 }, /* ed13 */ { undefined, A_0 }, /* ed14 */ { undefined, A_0 }, /* ed15 */ { undefined, A_0 }, /* ed16 */ { undefined, A_0 }, /* ed17 */ { undefined, A_0 }, /* ed18 */ { undefined, A_0 }, /* ed19 */ { undefined, A_0 }, /* ed1a */ { undefined, A_0 }, /* ed1b */ { undefined, A_0 }, /* ed1c */ { undefined, A_0 }, /* ed1d */ { undefined, A_0 }, /* ed1e */ { undefined, A_0 }, /* ed1f */ { undefined, A_0 }, /* ed20 [vavasour emt] */ { undefined, A_0 }, /* ed21 [vavasour emt] */ { undefined, A_0 }, /* ed22 */ { undefined, A_0 }, /* ed23 */ { undefined, A_0 }, /* ed24 */ { undefined, A_0 }, /* ed25 */ { undefined, A_0 }, /* ed26 */ { undefined, A_0 }, /* ed27 */ /* xtrs emulator traps; not real Z80 instructions */ { "emt_system", A_0 }, /* ed28 */ { "emt_mouse", A_0 }, /* ed29 */ { "emt_getdir", A_0 }, /* ed2a */ { "emt_setdir", A_0 }, /* ed2b */ { undefined, A_0 }, /* ed2c */ { undefined, A_0 }, /* ed2d */ { undefined, A_0 }, /* ed2e */ { "emt_debug", A_0 }, /* ed2f */ { "emt_open", A_0 }, /* ed30 */ { "emt_close", A_0 }, /* ed31 */ { "emt_read", A_0 }, /* ed32 */ { "emt_write", A_0 }, /* ed33 */ { "emt_lseek", A_0 }, /* ed34 */ { "emt_strerror", A_0 }, /* ed35 */ { "emt_time", A_0 }, /* ed36 */ { "emt_opendir", A_0 }, /* ed37 */ { "emt_closedir", A_0 }, /* ed38 */ { "emt_readdir", A_0 }, /* ed39 */ { "emt_chdir", A_0 }, /* ed3a */ { "emt_getcwd", A_0 }, /* ed3b */ { "emt_misc", A_0 }, /* ed3c */ { "emt_ftruncate", A_0 }, /* ed3d */ { "emt_opendisk", A_0 }, /* ed3e */ { "emt_closedisk", A_0 }, /* ed3f */ /* end xtrs emulator traps */ { "in b,(c)", A_0 }, /* ed40 */ { "out (c),b", A_0 }, /* ed41 */ { "sbc hl,bc", A_0 }, /* ed42 */ { "ld (%02x%02xh),bc",A_16 }, /* ed43 */ { "neg", A_0 }, /* ed44 */ { "retn", A_0 }, /* ed45 */ { "im 0", A_0 }, /* ed46 */ { "ld i,a", A_0 }, /* ed47 */ { "in c,(c)", A_0 }, /* ed48 */ { "out (c),c", A_0 }, /* ed49 */ { "adc hl,bc", A_0 }, /* ed4a */ { "ld bc,(%02x%02xh)",A_16 }, /* ed4b */ { "neg\t\t\t;undoc equiv",A_0 }, /* ed4c [undoc] */ { "reti", A_0 }, /* ed4d */ { undefined, A_0 }, /* ed4e */ { "ld r,a", A_0 }, /* ed4f */ { "in d,(c)", A_0 }, /* ed50 */ { "out (c),d", A_0 }, /* ed51 */ { "sbc hl,de", A_0 }, /* ed52 */ { "ld (%02x%02xh),de",A_16 }, /* ed53 */ { "neg\t\t\t;undoc equiv",A_0 }, /* ed54 [undoc] */ { "ret\t\t\t;undoc equiv",A_0 }, /* ed55 [undoc] */ { "im 1", A_0 }, /* ed56 */ { "ld a,i", A_0 }, /* ed57 */ { "in e,(c)", A_0 }, /* ed58 */ { "out (c),e", A_0 }, /* ed59 */ { "adc hl,de", A_0 }, /* ed5a */ { "ld de,(%02x%02xh)",A_16 }, /* ed5b */ { "neg\t\t\t;undoc equiv",A_0 }, /* ed5c [undoc] */ { "ret\t\t\t;undoc equiv",A_0 }, /* ed5d [undoc] */ { "im 2", A_0 }, /* ed5e */ { "ld a,r", A_0 }, /* ed5f */ { "in h,(c)", A_0 }, /* ed60 */ { "out (c),h", A_0 }, /* ed61 */ { "sbc hl,hl", A_0 }, /* ed62 */ { "ld (%02x%02xh),hl\t;undoc equiv",A_16 }, /* ed63 [semi-documented] */ { "neg\t\t\t;undoc equiv",A_0 }, /* ed64 [undoc] */ { "ret\t\t\t;undoc equiv",A_0 }, /* ed65 [undoc] */ { "im\t0\t\t;undoc equiv",A_0 }, /* ed66 [undoc] */ { "rrd", A_0 }, /* ed67 */ { "in l,(c)", A_0 }, /* ed68 */ { "out (c),l", A_0 }, /* ed69 */ { "adc hl,hl", A_0 }, /* ed6a */ { "ld hl,(%02x%02xh)\t;undoc equiv",A_16 }, /* ed6b [semi-documented] */ { "neg\t\t\t;undoc equiv",A_0 }, /* ed6c [undoc] */ { "ret\t\t\t;undoc equiv",A_0 }, /* ed6d [undoc] */ { undefined, A_0 }, /* ed6e */ { "rld", A_0 }, /* ed6f */ { "in (c)", A_0 }, /* ed70 [undoc] */ { "out (c),0", A_0 }, /* ed71 [undoc] */ { "sbc hl,sp", A_0 }, /* ed72 */ { "ld (%02x%02xh),sp",A_16 }, /* ed73 */ { "neg\t\t\t;undoc equiv",A_0 }, /* ed74 [undoc] */ { "ret\t\t\t;undoc equiv",A_0 }, /* ed75 [undoc] */ { "im\t1\t\t;undoc equiv",A_0 }, /* ed76 [undoc] */ { undefined, A_0 }, /* ed77 */ { "in a,(c)", A_0 }, /* ed78 */ { "out (c),a", A_0 }, /* ed79 */ { "adc hl,sp", A_0 }, /* ed7a */ { "ld sp,(%02x%02xh)",A_16 }, /* ed7b */ { "neg\t\t\t;undoc equiv",A_0 }, /* ed7c [undoc] */ { "ret\t\t\t;undoc equiv",A_0 }, /* ed7d [undoc] */ { "im\t2\t\t;undoc equiv",A_0 }, /* ed7e [undoc] */ { undefined, A_0 }, /* ed7f */ { undefined, A_0 }, /* ed80 */ { undefined, A_0 }, /* ed81 */ { undefined, A_0 }, /* ed82 */ { undefined, A_0 }, /* ed83 */ { undefined, A_0 }, /* ed84 */ { undefined, A_0 }, /* ed85 */ { undefined, A_0 }, /* ed86 */ { undefined, A_0 }, /* ed87 */ { undefined, A_0 }, /* ed88 */ { undefined, A_0 }, /* ed89 */ { undefined, A_0 }, /* ed8a */ { undefined, A_0 }, /* ed8b */ { undefined, A_0 }, /* ed8c */ { undefined, A_0 }, /* ed8d */ { undefined, A_0 }, /* ed8e */ { undefined, A_0 }, /* ed8f */ { undefined, A_0 }, /* ed90 */ { undefined, A_0 }, /* ed91 */ { undefined, A_0 }, /* ed92 */ { undefined, A_0 }, /* ed93 */ { undefined, A_0 }, /* ed94 */ { undefined, A_0 }, /* ed95 */ { undefined, A_0 }, /* ed96 */ { undefined, A_0 }, /* ed97 */ { undefined, A_0 }, /* ed98 */ { undefined, A_0 }, /* ed99 */ { undefined, A_0 }, /* ed9a */ { undefined, A_0 }, /* ed9b */ { undefined, A_0 }, /* ed9c */ { undefined, A_0 }, /* ed9d */ { undefined, A_0 }, /* ed9e */ { undefined, A_0 }, /* ed9f */ { "ldi", A_0 }, /* eda0 */ { "cpi", A_0 }, /* eda1 */ { "ini", A_0 }, /* eda2 */ { "outi", A_0 }, /* eda3 */ { undefined, A_0 }, /* eda4 */ { undefined, A_0 }, /* eda5 */ { undefined, A_0 }, /* eda6 */ { undefined, A_0 }, /* eda7 */ { "ldd", A_0 }, /* eda8 */ { "cpd", A_0 }, /* eda9 */ { "ind", A_0 }, /* edaa */ { "outd", A_0 }, /* edab */ { undefined, A_0 }, /* edac */ { undefined, A_0 }, /* edad */ { undefined, A_0 }, /* edae */ { undefined, A_0 }, /* edaf */ { "ldir", A_0 }, /* edb0 */ { "cpir", A_0 }, /* edb1 */ { "inir", A_0 }, /* edb2 */ { "otir", A_0 }, /* edb3 */ { undefined, A_0 }, /* edb4 */ { undefined, A_0 }, /* edb5 */ { undefined, A_0 }, /* edb6 */ { undefined, A_0 }, /* edb7 */ { "lddr", A_0 }, /* edb8 */ { "cpdr", A_0 }, /* edb9 */ { "indr", A_0 }, /* edba */ { "otdr", A_0 }, /* edbb */ { undefined, A_0 }, /* edbc */ { undefined, A_0 }, /* edbd */ { undefined, A_0 }, /* edbe */ { undefined, A_0 }, /* edbf */ { undefined, A_0 }, /* edc0 */ { undefined, A_0 }, /* edc1 */ { undefined, A_0 }, /* edc2 */ { undefined, A_0 }, /* edc3 */ { undefined, A_0 }, /* edc4 */ { undefined, A_0 }, /* edc5 */ { undefined, A_0 }, /* edc6 */ { undefined, A_0 }, /* edc7 */ { undefined, A_0 }, /* edc8 */ { undefined, A_0 }, /* edc9 */ { undefined, A_0 }, /* edca */ { undefined, A_0 }, /* edcb */ { undefined, A_0 }, /* edcc */ { undefined, A_0 }, /* edcd */ { undefined, A_0 }, /* edce */ { undefined, A_0 }, /* edcf */ { undefined, A_0 }, /* edd0 */ { undefined, A_0 }, /* edd1 */ { undefined, A_0 }, /* edd2 */ { undefined, A_0 }, /* edd3 */ { undefined, A_0 }, /* edd4 */ { undefined, A_0 }, /* edd5 */ { undefined, A_0 }, /* edd6 */ { undefined, A_0 }, /* edd7 */ { undefined, A_0 }, /* edd8 */ { undefined, A_0 }, /* edd9 */ { undefined, A_0 }, /* edda */ { undefined, A_0 }, /* eddb */ { undefined, A_0 }, /* eddc */ { undefined, A_0 }, /* eddd */ { undefined, A_0 }, /* edde */ { undefined, A_0 }, /* eddf */ { undefined, A_0 }, /* ede0 */ { undefined, A_0 }, /* ede1 */ { undefined, A_0 }, /* ede2 */ { undefined, A_0 }, /* ede3 */ { undefined, A_0 }, /* ede4 */ { undefined, A_0 }, /* ede5 */ { undefined, A_0 }, /* ede6 */ { undefined, A_0 }, /* ede7 */ { undefined, A_0 }, /* ede8 */ { undefined, A_0 }, /* ede9 */ { undefined, A_0 }, /* edea */ { undefined, A_0 }, /* edeb */ { undefined, A_0 }, /* edec */ { undefined, A_0 }, /* eded */ { undefined, A_0 }, /* edee */ { undefined, A_0 }, /* edef */ { undefined, A_0 }, /* edf0 */ { undefined, A_0 }, /* edf1 */ { undefined, A_0 }, /* edf2 */ { undefined, A_0 }, /* edf3 */ { undefined, A_0 }, /* edf4 */ { undefined, A_0 }, /* edf5 */ { undefined, A_0 }, /* edf6 */ { undefined, A_0 }, /* edf7 */ { undefined, A_0 }, /* edf8 */ { undefined, A_0 }, /* edf9 */ { undefined, A_0 }, /* edfa */ { undefined, A_0 }, /* edfb */ { undefined, A_0 }, /* edfc */ { undefined, A_0 }, /* edfd */ { undefined, A_0 }, /* edfe */ { undefined, A_0 }, /* edff */ }, { /* fd */ { undefined, A_0B }, /* fd00 */ { undefined, A_0B }, /* fd01 */ { undefined, A_0B }, /* fd02 */ { undefined, A_0B }, /* fd03 */ { undefined, A_0B }, /* fd04 */ { undefined, A_0B }, /* fd05 */ { undefined, A_0B }, /* fd06 */ { undefined, A_0B }, /* fd07 */ { undefined, A_0B }, /* fd08 */ { "add iy,bc", A_0 }, /* fd09 */ { undefined, A_0B }, /* fd0a */ { undefined, A_0B }, /* fd0b */ { undefined, A_0B }, /* fd0c */ { undefined, A_0B }, /* fd0d */ { undefined, A_0B }, /* fd0e */ { undefined, A_0B }, /* fd0f */ { undefined, A_0B }, /* fd10 */ { undefined, A_0B }, /* fd11 */ { undefined, A_0B }, /* fd12 */ { undefined, A_0B }, /* fd13 */ { undefined, A_0B }, /* fd14 */ { undefined, A_0B }, /* fd15 */ { undefined, A_0B }, /* fd16 */ { undefined, A_0B }, /* fd17 */ { undefined, A_0B }, /* fd18 */ { "add iy,de", A_0 }, /* fd19 */ { undefined, A_0B }, /* fd1a */ { undefined, A_0B }, /* fd1b */ { undefined, A_0B }, /* fd1c */ { undefined, A_0B }, /* fd1d */ { undefined, A_0B }, /* fd1e */ { undefined, A_0B }, /* fd1f */ { undefined, A_0B }, /* fd20 */ { "ld iy,%02x%02xh", A_16 }, /* fd21 */ { "ld (%02x%02xh),iy",A_16 }, /* fd22 */ { "inc iy", A_0 }, /* fd23 */ { undefined, A_0B }, /* fd24 */ { undefined, A_0B }, /* fd25 */ { undefined, A_0B }, /* fd26 */ { undefined, A_0B }, /* fd27 */ { undefined, A_0B }, /* fd28 */ { "add iy,iy", A_0 }, /* fd29 */ { "ld iy,(%02x%02xh)",A_16 }, /* fd2a */ { "dec iy", A_0 }, /* fd2b */ { undefined, A_0B }, /* fd2c */ { undefined, A_0B }, /* fd2d */ { undefined, A_0B }, /* fd2e */ { undefined, A_0B }, /* fd2f */ { undefined, A_0B }, /* fd30 */ { undefined, A_0B }, /* fd31 */ { undefined, A_0B }, /* fd32 */ { undefined, A_0B }, /* fd33 */ { "inc (iy+%02xh)", A_8 }, /* fd34 */ { "dec (iy+%02xh)", A_8 }, /* fd35 */ { "ld (iy+%02xh),%02xh",A_8X2 }, /* fd36 */ { undefined, A_0B }, /* fd37 */ { undefined, A_0B }, /* fd38 */ { "add iy,sp", A_0 }, /* fd39 */ { undefined, A_0B }, /* fd3a */ { undefined, A_0B }, /* fd3b */ { undefined, A_0B }, /* fd3c */ { undefined, A_0B }, /* fd3d */ { undefined, A_0B }, /* fd3e */ { undefined, A_0B }, /* fd3f */ { undefined, A_0B }, /* fd40 */ { undefined, A_0B }, /* fd41 */ { undefined, A_0B }, /* fd42 */ { undefined, A_0B }, /* fd43 */ { undefined, A_0B }, /* fd44 */ { undefined, A_0B }, /* fd45 */ { "ld b,(iy+%02xh)", A_8 }, /* fd46 */ { undefined, A_0B }, /* fd47 */ { undefined, A_0B }, /* fd48 */ { undefined, A_0B }, /* fd49 */ { undefined, A_0B }, /* fd4a */ { undefined, A_0B }, /* fd4b */ { undefined, A_0B }, /* fd4c */ { undefined, A_0B }, /* fd4d */ { "ld c,(iy+%02xh)", A_8 }, /* fd4e */ { undefined, A_0B }, /* fd4f */ { undefined, A_0B }, /* fd50 */ { undefined, A_0B }, /* fd51 */ { undefined, A_0B }, /* fd52 */ { undefined, A_0B }, /* fd53 */ { undefined, A_0B }, /* fd54 */ { undefined, A_0B }, /* fd55 */ { "ld d,(iy+%02xh)", A_8 }, /* fd56 */ { undefined, A_0B }, /* fd57 */ { undefined, A_0B }, /* fd58 */ { undefined, A_0B }, /* fd59 */ { undefined, A_0B }, /* fd5a */ { undefined, A_0B }, /* fd5b */ { undefined, A_0B }, /* fd5c */ { undefined, A_0B }, /* fd5d */ { "ld e,(iy+%02xh)", A_8 }, /* fd5e */ { undefined, A_0B }, /* fd5f */ { undefined, A_0B }, /* fd60 */ { undefined, A_0B }, /* fd61 */ { undefined, A_0B }, /* fd62 */ { undefined, A_0B }, /* fd63 */ { undefined, A_0B }, /* fd64 */ { undefined, A_0B }, /* fd65 */ { "ld h,(iy+%02xh)", A_8 }, /* fd66 */ { undefined, A_0B }, /* fd67 */ { undefined, A_0B }, /* fd68 */ { undefined, A_0B }, /* fd69 */ { undefined, A_0B }, /* fd6a */ { undefined, A_0B }, /* fd6b */ { undefined, A_0B }, /* fd6c */ { undefined, A_0B }, /* fd6d */ { "ld l,(iy+%02xh)", A_8 }, /* fd6e */ { undefined, A_0B }, /* fd6f */ { "ld (iy+%02xh),b", A_8 }, /* fd70 */ { "ld (iy+%02xh),c", A_8 }, /* fd71 */ { "ld (iy+%02xh),d", A_8 }, /* fd72 */ { "ld (iy+%02xh),e", A_8 }, /* fd73 */ { "ld (iy+%02xh),h", A_8 }, /* fd74 */ { "ld (iy+%02xh),l", A_8 }, /* fd75 */ { undefined, A_0B }, /* fd76 */ { "ld (iy+%02xh),a", A_8 }, /* fd77 */ { undefined, A_0B }, /* fd78 */ { undefined, A_0B }, /* fd79 */ { undefined, A_0B }, /* fd7a */ { undefined, A_0B }, /* fd7b */ { undefined, A_0B }, /* fd7c */ { undefined, A_0B }, /* fd7d */ { "ld a,(iy+%02xh)", A_8 }, /* fd7e */ { undefined, A_0B }, /* fd7f */ { undefined, A_0B }, /* fd80 */ { undefined, A_0B }, /* fd81 */ { undefined, A_0B }, /* fd82 */ { undefined, A_0B }, /* fd83 */ { undefined, A_0B }, /* fd84 */ { undefined, A_0B }, /* fd85 */ { "add a,(iy+%02xh)", A_8 }, /* fd86 */ { undefined, A_0B }, /* fd87 */ { undefined, A_0B }, /* fd88 */ { undefined, A_0B }, /* fd89 */ { undefined, A_0B }, /* fd8a */ { undefined, A_0B }, /* fd8b */ { undefined, A_0B }, /* fd8c */ { undefined, A_0B }, /* fd8d */ { "adc a,(iy+%02xh)", A_8 }, /* fd8e */ { undefined, A_0B }, /* fd8f */ { undefined, A_0B }, /* fd90 */ { undefined, A_0B }, /* fd91 */ { undefined, A_0B }, /* fd92 */ { undefined, A_0B }, /* fd93 */ { undefined, A_0B }, /* fd94 */ { undefined, A_0B }, /* fd95 */ { "sub (iy+%02xh)", A_8 }, /* fd96 */ { undefined, A_0B }, /* fd97 */ { undefined, A_0B }, /* fd98 */ { undefined, A_0B }, /* fd99 */ { undefined, A_0B }, /* fd9a */ { undefined, A_0B }, /* fd9b */ { undefined, A_0B }, /* fd9c */ { undefined, A_0B }, /* fd9d */ { "sbc a,(iy+%02xh)", A_8 }, /* fd9e */ { undefined, A_0B }, /* fd9f */ { undefined, A_0B }, /* fda0 */ { undefined, A_0B }, /* fda1 */ { undefined, A_0B }, /* fda2 */ { undefined, A_0B }, /* fda3 */ { undefined, A_0B }, /* fda4 */ { undefined, A_0B }, /* fda5 */ { "and (iy+%02xh)", A_8 }, /* fda6 */ { undefined, A_0B }, /* fda7 */ { undefined, A_0B }, /* fda8 */ { undefined, A_0B }, /* fda9 */ { undefined, A_0B }, /* fdaa */ { undefined, A_0B }, /* fdab */ { undefined, A_0B }, /* fdac */ { undefined, A_0B }, /* fdad */ { "xor (iy+%02xh)", A_8 }, /* fdae */ { undefined, A_0B }, /* fdaf */ { undefined, A_0B }, /* fdb0 */ { undefined, A_0B }, /* fdb1 */ { undefined, A_0B }, /* fdb2 */ { undefined, A_0B }, /* fdb3 */ { undefined, A_0B }, /* fdb4 */ { undefined, A_0B }, /* fdb5 */ { "or (iy+%02xh)", A_8 }, /* fdb6 */ { undefined, A_0B }, /* fdb7 */ { undefined, A_0B }, /* fdb8 */ { undefined, A_0B }, /* fdb9 */ { undefined, A_0B }, /* fdba */ { undefined, A_0B }, /* fdbb */ { undefined, A_0B }, /* fdbc */ { undefined, A_0B }, /* fdbd */ { "cp (iy+%02xh)", A_8 }, /* fdbe */ { undefined, A_0B }, /* fdbf */ { undefined, A_0B }, /* fdc0 */ { undefined, A_0B }, /* fdc1 */ { undefined, A_0B }, /* fdc2 */ { undefined, A_0B }, /* fdc3 */ { undefined, A_0B }, /* fdc4 */ { undefined, A_0B }, /* fdc5 */ { undefined, A_0B }, /* fdc6 */ { undefined, A_0B }, /* fdc7 */ { undefined, A_0B }, /* fdc8 */ { undefined, A_0B }, /* fdc9 */ { undefined, A_0B }, /* fdca */ { 0, 5 }, /* fdcb */ { undefined, A_0B }, /* fdcc */ { undefined, A_0B }, /* fdcd */ { undefined, A_0B }, /* fdce */ { undefined, A_0B }, /* fdcf */ { undefined, A_0B }, /* fdd0 */ { undefined, A_0B }, /* fdd1 */ { undefined, A_0B }, /* fdd2 */ { undefined, A_0B }, /* fdd3 */ { undefined, A_0B }, /* fdd4 */ { undefined, A_0B }, /* fdd5 */ { undefined, A_0B }, /* fdd6 */ { undefined, A_0B }, /* fdd7 */ { undefined, A_0B }, /* fdd8 */ { undefined, A_0B }, /* fdd9 */ { undefined, A_0B }, /* fdda */ { undefined, A_0B }, /* fddb */ { undefined, A_0B }, /* fddc */ { undefined, A_0B }, /* fddd */ { undefined, A_0B }, /* fdde */ { undefined, A_0B }, /* fddf */ { undefined, A_0B }, /* fde0 */ { "pop iy", A_0 }, /* fde1 */ { undefined, A_0B }, /* fde2 */ { "ex (sp),iy", A_0 }, /* fde3 */ { undefined, A_0B }, /* fde4 */ { "push iy", A_0 }, /* fde5 */ { undefined, A_0B }, /* fde6 */ { undefined, A_0B }, /* fde7 */ { undefined, A_0B }, /* fde8 */ { "jp (iy)", A_0 }, /* fde9 */ { undefined, A_0B }, /* fdea */ { undefined, A_0B }, /* fdeb */ { undefined, A_0B }, /* fdec */ { undefined, A_0B }, /* fded */ { undefined, A_0B }, /* fdee */ { undefined, A_0B }, /* fdef */ { undefined, A_0B }, /* fdf0 */ { undefined, A_0B }, /* fdf1 */ { undefined, A_0B }, /* fdf2 */ { undefined, A_0B }, /* fdf3 */ { undefined, A_0B }, /* fdf4 */ { undefined, A_0B }, /* fdf5 */ { undefined, A_0B }, /* fdf6 */ { undefined, A_0B }, /* fdf7 */ { undefined, A_0B }, /* fdf8 */ { "ld sp,iy", A_0 }, /* fdf9 */ { undefined, A_0B }, /* fdfa */ { undefined, A_0B }, /* fdfb */ { undefined, A_0B }, /* fdfc */ { undefined, A_0B }, /* fdfd */ { undefined, A_0B }, /* fdfe */ { undefined, A_0B }, /* fdff */ }, { /* dd cb */ { "ld b,rlc (ix+%02xh)", A_8P }, /* ddcb..00 [undoc] */ { "ld c,rlc (ix+%02xh)", A_8P }, /* ddcb..01 [undoc] */ { "ld d,rlc (ix+%02xh)", A_8P }, /* ddcb..02 [undoc] */ { "ld e,rlc (ix+%02xh)", A_8P }, /* ddcb..03 [undoc] */ { "ld h,rlc (ix+%02xh)", A_8P }, /* ddcb..04 [undoc] */ { "ld l,rlc (ix+%02xh)", A_8P }, /* ddcb..05 [undoc] */ { "rlc (ix+%02xh)", A_8P }, /* ddcb..06 */ { "ld a,rlc (ix+%02xh)", A_8P }, /* ddcb..07 [undoc] */ { "ld b,rrc (ix+%02xh)", A_8P }, /* ddcb..08 [undoc] */ { "ld c,rrc (ix+%02xh)", A_8P }, /* ddcb..09 [undoc] */ { "ld d,rrc (ix+%02xh)", A_8P }, /* ddcb..0a [undoc] */ { "ld e,rrc (ix+%02xh)", A_8P }, /* ddcb..0b [undoc] */ { "ld h,rrc (ix+%02xh)", A_8P }, /* ddcb..0c [undoc] */ { "ld l,rrc (ix+%02xh)", A_8P }, /* ddcb..0d [undoc] */ { "rrc (ix+%02xh)", A_8P }, /* ddcb..0e */ { "ld a,rrc (ix+%02xh)", A_8P }, /* ddcb..0f [undoc] */ { "ld b,rl (ix+%02xh)", A_8P }, /* ddcb..10 [undoc] */ { "ld c,rl (ix+%02xh)", A_8P }, /* ddcb..11 [undoc] */ { "ld d,rl (ix+%02xh)", A_8P }, /* ddcb..12 [undoc] */ { "ld e,rl (ix+%02xh)", A_8P }, /* ddcb..13 [undoc] */ { "ld h,rl (ix+%02xh)", A_8P }, /* ddcb..14 [undoc] */ { "ld l,rl (ix+%02xh)", A_8P }, /* ddcb..15 [undoc] */ { "rl (ix+%02xh)", A_8P }, /* ddcb..16 */ { "ld a,rl (ix+%02xh)", A_8P }, /* ddcb..17 [undoc] */ { "ld b,rr (ix+%02xh)", A_8P }, /* ddcb..18 [undoc] */ { "ld c,rr (ix+%02xh)", A_8P }, /* ddcb..19 [undoc] */ { "ld d,rr (ix+%02xh)", A_8P }, /* ddcb..1a [undoc] */ { "ld e,rr (ix+%02xh)", A_8P }, /* ddcb..1b [undoc] */ { "ld h,rr (ix+%02xh)", A_8P }, /* ddcb..1c [undoc] */ { "ld l,rr (ix+%02xh)", A_8P }, /* ddcb..1d [undoc] */ { "rr (ix+%02xh)", A_8P }, /* ddcb..1e */ { "ld a,rr (ix+%02xh)", A_8P }, /* ddcb..1f [undoc] */ { "ld b,sla (ix+%02xh)", A_8P }, /* ddcb..20 [undoc] */ { "ld c,sla (ix+%02xh)", A_8P }, /* ddcb..21 [undoc] */ { "ld d,sla (ix+%02xh)", A_8P }, /* ddcb..22 [undoc] */ { "ld e,sla (ix+%02xh)", A_8P }, /* ddcb..23 [undoc] */ { "ld h,sla (ix+%02xh)", A_8P }, /* ddcb..24 [undoc] */ { "ld l,sla (ix+%02xh)", A_8P }, /* ddcb..25 [undoc] */ { "sla (ix+%02xh)", A_8P }, /* ddcb..26 */ { "ld a,sla (ix+%02xh)", A_8P }, /* ddcb..27 [undoc] */ { "ld b,sra (ix+%02xh)", A_8P }, /* ddcb..28 [undoc] */ { "ld c,sra (ix+%02xh)", A_8P }, /* ddcb..29 [undoc] */ { "ld d,sra (ix+%02xh)", A_8P }, /* ddcb..2a [undoc] */ { "ld e,sra (ix+%02xh)", A_8P }, /* ddcb..2b [undoc] */ { "ld h,sra (ix+%02xh)", A_8P }, /* ddcb..2c [undoc] */ { "ld l,sra (ix+%02xh)", A_8P }, /* ddcb..2d [undoc] */ { "sra (ix+%02xh)", A_8P }, /* ddcb..2e */ { "ld a,sra (ix+%02xh)", A_8P }, /* ddcb..2f [undoc] */ { "ld b,slia (ix+%02xh)", A_8P }, /* ddcb..30 [undoc] */ { "ld c,slia (ix+%02xh)", A_8P }, /* ddcb..31 [undoc] */ { "ld d,slia (ix+%02xh)", A_8P }, /* ddcb..32 [undoc] */ { "ld e,slia (ix+%02xh)", A_8P }, /* ddcb..33 [undoc] */ { "ld h,slia (ix+%02xh)", A_8P }, /* ddcb..34 [undoc] */ { "ld l,slia (ix+%02xh)", A_8P }, /* ddcb..35 [undoc] */ { "slia (ix+%02xh)", A_8P }, /* ddcb..36 [undoc] */ { "ld a,slia (ix+%02xh)", A_8P }, /* ddcb..37 [undoc] */ { "ld b,srl (ix+%02xh)", A_8P }, /* ddcb..38 [undoc] */ { "ld c,srl (ix+%02xh)", A_8P }, /* ddcb..39 [undoc] */ { "ld d,srl (ix+%02xh)", A_8P }, /* ddcb..3a [undoc] */ { "ld e,srl (ix+%02xh)", A_8P }, /* ddcb..3b [undoc] */ { "ld h,srl (ix+%02xh)", A_8P }, /* ddcb..3c [undoc] */ { "ld l,srl (ix+%02xh)", A_8P }, /* ddcb..3d [undoc] */ { "srl (ix+%02xh)", A_8P }, /* ddcb..3e */ { "ld a,srl (ix+%02xh)", A_8P }, /* ddcb..3f [undoc] */ { "bit 0,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..40 [undoc] */ { "bit 0,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..41 [undoc] */ { "bit 0,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..42 [undoc] */ { "bit 0,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..43 [undoc] */ { "bit 0,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..44 [undoc] */ { "bit 0,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..45 [undoc] */ { "bit 0,(ix+%02xh)", A_8P }, /* ddcb..46 */ { "bit 0,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..47 [undoc] */ { "bit 1,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..48 [undoc] */ { "bit 1,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..49 [undoc] */ { "bit 1,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..4a [undoc] */ { "bit 1,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..4b [undoc] */ { "bit 1,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..4c [undoc] */ { "bit 1,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..4d [undoc] */ { "bit 1,(ix+%02xh)", A_8P }, /* ddcb..4e */ { "bit 1,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..4f [undoc] */ { "bit 2,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..50 [undoc] */ { "bit 2,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..51 [undoc] */ { "bit 2,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..52 [undoc] */ { "bit 2,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..53 [undoc] */ { "bit 2,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..54 [undoc] */ { "bit 2,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..55 [undoc] */ { "bit 2,(ix+%02xh)", A_8P }, /* ddcb..56 */ { "bit 2,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..57 [undoc] */ { "bit 3,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..58 [undoc] */ { "bit 3,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..59 [undoc] */ { "bit 3,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..5a [undoc] */ { "bit 3,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..5b [undoc] */ { "bit 3,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..5c [undoc] */ { "bit 3,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..5d [undoc] */ { "bit 3,(ix+%02xh)", A_8P }, /* ddcb..5e */ { "bit 3,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..5f [undoc] */ { "bit 4,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..60 [undoc] */ { "bit 4,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..61 [undoc] */ { "bit 4,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..62 [undoc] */ { "bit 4,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..63 [undoc] */ { "bit 4,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..64 [undoc] */ { "bit 4,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..65 [undoc] */ { "bit 4,(ix+%02xh)", A_8P }, /* ddcb..66 */ { "bit 4,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..67 [undoc] */ { "bit 5,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..68 [undoc] */ { "bit 5,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..69 [undoc] */ { "bit 5,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..6a [undoc] */ { "bit 5,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..6b [undoc] */ { "bit 5,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..6c [undoc] */ { "bit 5,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..6d [undoc] */ { "bit 5,(ix+%02xh)", A_8P }, /* ddcb..6e */ { "bit 5,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..6f [undoc] */ { "bit 6,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..70 [undoc] */ { "bit 6,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..71 [undoc] */ { "bit 6,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..72 [undoc] */ { "bit 6,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..73 [undoc] */ { "bit 6,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..74 [undoc] */ { "bit 6,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..75 [undoc] */ { "bit 6,(ix+%02xh)", A_8P }, /* ddcb..76 */ { "bit 6,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..77 [undoc] */ { "bit 7,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..78 [undoc] */ { "bit 7,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..79 [undoc] */ { "bit 7,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..7a [undoc] */ { "bit 7,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..7b [undoc] */ { "bit 7,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..7c [undoc] */ { "bit 7,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..7d [undoc] */ { "bit 7,(ix+%02xh)", A_8P }, /* ddcb..7e */ { "bit 7,(ix+%02xh)\t;undoc equiv", A_8P }, /* ddcb..7f [undoc] */ { "ld b,res 0,(ix+%02xh)", A_8P }, /* ddcb..80 [undoc] */ { "ld c,res 0,(ix+%02xh)", A_8P }, /* ddcb..81 [undoc] */ { "ld d,res 0,(ix+%02xh)", A_8P }, /* ddcb..82 [undoc] */ { "ld e,res 0,(ix+%02xh)", A_8P }, /* ddcb..83 [undoc] */ { "ld h,res 0,(ix+%02xh)", A_8P }, /* ddcb..84 [undoc] */ { "ld l,res 0,(ix+%02xh)", A_8P }, /* ddcb..85 [undoc] */ { "res 0,(ix+%02xh)", A_8P }, /* ddcb..86 */ { "ld a,res 0,(ix+%02xh)", A_8P }, /* ddcb..87 [undoc] */ { "ld b,res 1,(ix+%02xh)", A_8P }, /* ddcb..88 [undoc] */ { "ld c,res 1,(ix+%02xh)", A_8P }, /* ddcb..89 [undoc] */ { "ld d,res 1,(ix+%02xh)", A_8P }, /* ddcb..8a [undoc] */ { "ld e,res 1,(ix+%02xh)", A_8P }, /* ddcb..8b [undoc] */ { "ld h,res 1,(ix+%02xh)", A_8P }, /* ddcb..8c [undoc] */ { "ld l,res 1,(ix+%02xh)", A_8P }, /* ddcb..8d [undoc] */ { "res 1,(ix+%02xh)", A_8P }, /* ddcb..8e */ { "ld a,res 1,(ix+%02xh)", A_8P }, /* ddcb..8f [undoc] */ { "ld b,res 2,(ix+%02xh)", A_8P }, /* ddcb..90 [undoc] */ { "ld c,res 2,(ix+%02xh)", A_8P }, /* ddcb..91 [undoc] */ { "ld d,res 2,(ix+%02xh)", A_8P }, /* ddcb..92 [undoc] */ { "ld e,res 2,(ix+%02xh)", A_8P }, /* ddcb..93 [undoc] */ { "ld h,res 2,(ix+%02xh)", A_8P }, /* ddcb..94 [undoc] */ { "ld l,res 2,(ix+%02xh)", A_8P }, /* ddcb..95 [undoc] */ { "res 2,(ix+%02xh)", A_8P }, /* ddcb..96 */ { "ld a,res 2,(ix+%02xh)", A_8P }, /* ddcb..97 [undoc] */ { "ld b,res 3,(ix+%02xh)", A_8P }, /* ddcb..98 [undoc] */ { "ld c,res 3,(ix+%02xh)", A_8P }, /* ddcb..99 [undoc] */ { "ld d,res 3,(ix+%02xh)", A_8P }, /* ddcb..9a [undoc] */ { "ld e,res 3,(ix+%02xh)", A_8P }, /* ddcb..9b [undoc] */ { "ld h,res 3,(ix+%02xh)", A_8P }, /* ddcb..9c [undoc] */ { "ld l,res 3,(ix+%02xh)", A_8P }, /* ddcb..9d [undoc] */ { "res 3,(ix+%02xh)", A_8P }, /* ddcb..9e */ { "ld a,res 3,(ix+%02xh)", A_8P }, /* ddcb..9f [undoc] */ { "ld b,res 4,(ix+%02xh)", A_8P }, /* ddcb..a0 [undoc] */ { "ld c,res 4,(ix+%02xh)", A_8P }, /* ddcb..a1 [undoc] */ { "ld d,res 4,(ix+%02xh)", A_8P }, /* ddcb..a2 [undoc] */ { "ld e,res 4,(ix+%02xh)", A_8P }, /* ddcb..a3 [undoc] */ { "ld h,res 4,(ix+%02xh)", A_8P }, /* ddcb..a4 [undoc] */ { "ld l,res 4,(ix+%02xh)", A_8P }, /* ddcb..a5 [undoc] */ { "res 4,(ix+%02xh)", A_8P }, /* ddcb..a6 */ { "ld a,res 4,(ix+%02xh)", A_8P }, /* ddcb..a7 [undoc] */ { "ld b,res 5,(ix+%02xh)", A_8P }, /* ddcb..a8 [undoc] */ { "ld c,res 5,(ix+%02xh)", A_8P }, /* ddcb..a9 [undoc] */ { "ld d,res 5,(ix+%02xh)", A_8P }, /* ddcb..aa [undoc] */ { "ld e,res 5,(ix+%02xh)", A_8P }, /* ddcb..ab [undoc] */ { "ld h,res 5,(ix+%02xh)", A_8P }, /* ddcb..ac [undoc] */ { "ld l,res 5,(ix+%02xh)", A_8P }, /* ddcb..ad [undoc] */ { "res 5,(ix+%02xh)", A_8P }, /* ddcb..ae */ { "ld a,res 5,(ix+%02xh)", A_8P }, /* ddcb..af [undoc] */ { "ld b,res 6,(ix+%02xh)", A_8P }, /* ddcb..b0 [undoc] */ { "ld c,res 6,(ix+%02xh)", A_8P }, /* ddcb..b1 [undoc] */ { "ld d,res 6,(ix+%02xh)", A_8P }, /* ddcb..b2 [undoc] */ { "ld e,res 6,(ix+%02xh)", A_8P }, /* ddcb..b3 [undoc] */ { "ld h,res 6,(ix+%02xh)", A_8P }, /* ddcb..b4 [undoc] */ { "ld l,res 6,(ix+%02xh)", A_8P }, /* ddcb..b5 [undoc] */ { "res 6,(ix+%02xh)", A_8P }, /* ddcb..b6 */ { "ld a,res 6,(ix+%02xh)", A_8P }, /* ddcb..b7 [undoc] */ { "ld b,res 7,(ix+%02xh)", A_8P }, /* ddcb..b8 [undoc] */ { "ld c,res 7,(ix+%02xh)", A_8P }, /* ddcb..b9 [undoc] */ { "ld d,res 7,(ix+%02xh)", A_8P }, /* ddcb..ba [undoc] */ { "ld e,res 7,(ix+%02xh)", A_8P }, /* ddcb..bb [undoc] */ { "ld h,res 7,(ix+%02xh)", A_8P }, /* ddcb..bc [undoc] */ { "ld l,res 7,(ix+%02xh)", A_8P }, /* ddcb..bd [undoc] */ { "res 7,(ix+%02xh)", A_8P }, /* ddcb..be */ { "ld a,res 7,(ix+%02xh)", A_8P }, /* ddcb..bf [undoc] */ { "ld b,set 0,(ix+%02xh)", A_8P }, /* ddcb..c0 [undoc] */ { "ld c,set 0,(ix+%02xh)", A_8P }, /* ddcb..c1 [undoc] */ { "ld d,set 0,(ix+%02xh)", A_8P }, /* ddcb..c2 [undoc] */ { "ld e,set 0,(ix+%02xh)", A_8P }, /* ddcb..c3 [undoc] */ { "ld h,set 0,(ix+%02xh)", A_8P }, /* ddcb..c4 [undoc] */ { "ld l,set 0,(ix+%02xh)", A_8P }, /* ddcb..c5 [undoc] */ { "set 0,(ix+%02xh)", A_8P }, /* ddcb..c6 */ { "ld a,set 0,(ix+%02xh)", A_8P }, /* ddcb..c7 [undoc] */ { "ld b,set 1,(ix+%02xh)", A_8P }, /* ddcb..c8 [undoc] */ { "ld c,set 1,(ix+%02xh)", A_8P }, /* ddcb..c9 [undoc] */ { "ld d,set 1,(ix+%02xh)", A_8P }, /* ddcb..ca [undoc] */ { "ld e,set 1,(ix+%02xh)", A_8P }, /* ddcb..cb [undoc] */ { "ld h,set 1,(ix+%02xh)", A_8P }, /* ddcb..cc [undoc] */ { "ld l,set 1,(ix+%02xh)", A_8P }, /* ddcb..cd [undoc] */ { "set 1,(ix+%02xh)", A_8P }, /* ddcb..ce */ { "ld a,set 1,(ix+%02xh)", A_8P }, /* ddcb..cf [undoc] */ { "ld b,set 2,(ix+%02xh)", A_8P }, /* ddcb..d0 [undoc] */ { "ld c,set 2,(ix+%02xh)", A_8P }, /* ddcb..d1 [undoc] */ { "ld d,set 2,(ix+%02xh)", A_8P }, /* ddcb..d2 [undoc] */ { "ld e,set 2,(ix+%02xh)", A_8P }, /* ddcb..d3 [undoc] */ { "ld h,set 2,(ix+%02xh)", A_8P }, /* ddcb..d4 [undoc] */ { "ld l,set 2,(ix+%02xh)", A_8P }, /* ddcb..d5 [undoc] */ { "set 2,(ix+%02xh)", A_8P }, /* ddcb..d6 */ { "ld a,set 2,(ix+%02xh)", A_8P }, /* ddcb..d7 [undoc] */ { "ld b,set 3,(ix+%02xh)", A_8P }, /* ddcb..d8 [undoc] */ { "ld c,set 3,(ix+%02xh)", A_8P }, /* ddcb..d9 [undoc] */ { "ld d,set 3,(ix+%02xh)", A_8P }, /* ddcb..da [undoc] */ { "ld e,set 3,(ix+%02xh)", A_8P }, /* ddcb..db [undoc] */ { "ld h,set 3,(ix+%02xh)", A_8P }, /* ddcb..dc [undoc] */ { "ld l,set 3,(ix+%02xh)", A_8P }, /* ddcb..dd [undoc] */ { "set 3,(ix+%02xh)", A_8P }, /* ddcb..de */ { "ld a,set 3,(ix+%02xh)", A_8P }, /* ddcb..df [undoc] */ { "ld b,set 4,(ix+%02xh)", A_8P }, /* ddcb..e0 [undoc] */ { "ld c,set 4,(ix+%02xh)", A_8P }, /* ddcb..e1 [undoc] */ { "ld d,set 4,(ix+%02xh)", A_8P }, /* ddcb..e2 [undoc] */ { "ld e,set 4,(ix+%02xh)", A_8P }, /* ddcb..e3 [undoc] */ { "ld h,set 4,(ix+%02xh)", A_8P }, /* ddcb..e4 [undoc] */ { "ld l,set 4,(ix+%02xh)", A_8P }, /* ddcb..e5 [undoc] */ { "set 4,(ix+%02xh)", A_8P }, /* ddcb..e6 */ { "ld a,set 4,(ix+%02xh)", A_8P }, /* ddcb..e7 [undoc] */ { "ld b,set 5,(ix+%02xh)", A_8P }, /* ddcb..e8 [undoc] */ { "ld c,set 5,(ix+%02xh)", A_8P }, /* ddcb..e9 [undoc] */ { "ld d,set 5,(ix+%02xh)", A_8P }, /* ddcb..ea [undoc] */ { "ld e,set 5,(ix+%02xh)", A_8P }, /* ddcb..eb [undoc] */ { "ld h,set 5,(ix+%02xh)", A_8P }, /* ddcb..ec [undoc] */ { "ld l,set 5,(ix+%02xh)", A_8P }, /* ddcb..ed [undoc] */ { "set 5,(ix+%02xh)", A_8P }, /* ddcb..ee */ { "ld a,set 5,(ix+%02xh)", A_8P }, /* ddcb..ef [undoc] */ { "ld b,set 6,(ix+%02xh)", A_8P }, /* ddcb..f0 [undoc] */ { "ld c,set 6,(ix+%02xh)", A_8P }, /* ddcb..f1 [undoc] */ { "ld d,set 6,(ix+%02xh)", A_8P }, /* ddcb..f2 [undoc] */ { "ld e,set 6,(ix+%02xh)", A_8P }, /* ddcb..f3 [undoc] */ { "ld h,set 6,(ix+%02xh)", A_8P }, /* ddcb..f4 [undoc] */ { "ld l,set 6,(ix+%02xh)", A_8P }, /* ddcb..f5 [undoc] */ { "set 6,(ix+%02xh)", A_8P }, /* ddcb..f6 */ { "ld a,set 6,(ix+%02xh)", A_8P }, /* ddcb..f7 [undoc] */ { "ld b,set 7,(ix+%02xh)", A_8P }, /* ddcb..f8 [undoc] */ { "ld c,set 7,(ix+%02xh)", A_8P }, /* ddcb..f9 [undoc] */ { "ld d,set 7,(ix+%02xh)", A_8P }, /* ddcb..fa [undoc] */ { "ld e,set 7,(ix+%02xh)", A_8P }, /* ddcb..fb [undoc] */ { "ld h,set 7,(ix+%02xh)", A_8P }, /* ddcb..fc [undoc] */ { "ld l,set 7,(ix+%02xh)", A_8P }, /* ddcb..fd [undoc] */ { "set 7,(ix+%02xh)", A_8P }, /* ddcb..fe */ { "ld a,set 7,(ix+%02xh)", A_8P }, /* ddcb..ff [undoc] */ }, { /* fd cb */ { "ld b,rlc (iy+%02xh)", A_8P }, /* fdcb..00 [undoc] */ { "ld c,rlc (iy+%02xh)", A_8P }, /* fdcb..01 [undoc] */ { "ld d,rlc (iy+%02xh)", A_8P }, /* fdcb..02 [undoc] */ { "ld e,rlc (iy+%02xh)", A_8P }, /* fdcb..03 [undoc] */ { "ld h,rlc (iy+%02xh)", A_8P }, /* fdcb..04 [undoc] */ { "ld l,rlc (iy+%02xh)", A_8P }, /* fdcb..05 [undoc] */ { "rlc (iy+%02xh)", A_8P }, /* fdcb..06 */ { "ld a,rlc (iy+%02xh)", A_8P }, /* fdcb..07 [undoc] */ { "ld b,rrc (iy+%02xh)", A_8P }, /* fdcb..08 [undoc] */ { "ld c,rrc (iy+%02xh)", A_8P }, /* fdcb..09 [undoc] */ { "ld d,rrc (iy+%02xh)", A_8P }, /* fdcb..0a [undoc] */ { "ld e,rrc (iy+%02xh)", A_8P }, /* fdcb..0b [undoc] */ { "ld h,rrc (iy+%02xh)", A_8P }, /* fdcb..0c [undoc] */ { "ld l,rrc (iy+%02xh)", A_8P }, /* fdcb..0d [undoc] */ { "rrc (iy+%02xh)", A_8P }, /* fdcb..0e */ { "ld a,rrc (iy+%02xh)", A_8P }, /* fdcb..0f [undoc] */ { "ld b,rl (iy+%02xh)", A_8P }, /* fdcb..10 [undoc] */ { "ld c,rl (iy+%02xh)", A_8P }, /* fdcb..11 [undoc] */ { "ld d,rl (iy+%02xh)", A_8P }, /* fdcb..12 [undoc] */ { "ld e,rl (iy+%02xh)", A_8P }, /* fdcb..13 [undoc] */ { "ld h,rl (iy+%02xh)", A_8P }, /* fdcb..14 [undoc] */ { "ld l,rl (iy+%02xh)", A_8P }, /* fdcb..15 [undoc] */ { "rl (iy+%02xh)", A_8P }, /* fdcb..16 */ { "ld a,rl (iy+%02xh)", A_8P }, /* fdcb..17 [undoc] */ { "ld b,rr (iy+%02xh)", A_8P }, /* fdcb..18 [undoc] */ { "ld c,rr (iy+%02xh)", A_8P }, /* fdcb..19 [undoc] */ { "ld d,rr (iy+%02xh)", A_8P }, /* fdcb..1a [undoc] */ { "ld e,rr (iy+%02xh)", A_8P }, /* fdcb..1b [undoc] */ { "ld h,rr (iy+%02xh)", A_8P }, /* fdcb..1c [undoc] */ { "ld l,rr (iy+%02xh)", A_8P }, /* fdcb..1d [undoc] */ { "rr (iy+%02xh)", A_8P }, /* fdcb..1e */ { "ld a,rr (iy+%02xh)", A_8P }, /* fdcb..1f [undoc] */ { "ld b,sla (iy+%02xh)", A_8P }, /* fdcb..20 [undoc] */ { "ld c,sla (iy+%02xh)", A_8P }, /* fdcb..21 [undoc] */ { "ld d,sla (iy+%02xh)", A_8P }, /* fdcb..22 [undoc] */ { "ld e,sla (iy+%02xh)", A_8P }, /* fdcb..23 [undoc] */ { "ld h,sla (iy+%02xh)", A_8P }, /* fdcb..24 [undoc] */ { "ld l,sla (iy+%02xh)", A_8P }, /* fdcb..25 [undoc] */ { "sla (iy+%02xh)", A_8P }, /* fdcb..26 */ { "ld a,sla (iy+%02xh)", A_8P }, /* fdcb..27 [undoc] */ { "ld b,sra (iy+%02xh)", A_8P }, /* fdcb..28 [undoc] */ { "ld c,sra (iy+%02xh)", A_8P }, /* fdcb..29 [undoc] */ { "ld d,sra (iy+%02xh)", A_8P }, /* fdcb..2a [undoc] */ { "ld e,sra (iy+%02xh)", A_8P }, /* fdcb..2b [undoc] */ { "ld h,sra (iy+%02xh)", A_8P }, /* fdcb..2c [undoc] */ { "ld l,sra (iy+%02xh)", A_8P }, /* fdcb..2d [undoc] */ { "sra (iy+%02xh)", A_8P }, /* fdcb..2e */ { "ld a,sra (iy+%02xh)", A_8P }, /* fdcb..2f [undoc] */ { "ld b,slia (iy+%02xh)", A_8P }, /* fdcb..30 [undoc] */ { "ld c,slia (iy+%02xh)", A_8P }, /* fdcb..31 [undoc] */ { "ld d,slia (iy+%02xh)", A_8P }, /* fdcb..32 [undoc] */ { "ld e,slia (iy+%02xh)", A_8P }, /* fdcb..33 [undoc] */ { "ld h,slia (iy+%02xh)", A_8P }, /* fdcb..34 [undoc] */ { "ld l,slia (iy+%02xh)", A_8P }, /* fdcb..35 [undoc] */ { "slia (iy+%02xh)", A_8P }, /* fdcb..36 [undoc] */ { "ld a,slia (iy+%02xh)", A_8P }, /* fdcb..37 [undoc] */ { "ld b,srl (iy+%02xh)", A_8P }, /* fdcb..38 [undoc] */ { "ld c,srl (iy+%02xh)", A_8P }, /* fdcb..39 [undoc] */ { "ld d,srl (iy+%02xh)", A_8P }, /* fdcb..3a [undoc] */ { "ld e,srl (iy+%02xh)", A_8P }, /* fdcb..3b [undoc] */ { "ld h,srl (iy+%02xh)", A_8P }, /* fdcb..3c [undoc] */ { "ld l,srl (iy+%02xh)", A_8P }, /* fdcb..3d [undoc] */ { "srl (iy+%02xh)", A_8P }, /* fdcb..3e */ { "ld a,srl (iy+%02xh)", A_8P }, /* fdcb..3f [undoc] */ { "bit 0,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..40 [undoc] */ { "bit 0,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..41 [undoc] */ { "bit 0,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..42 [undoc] */ { "bit 0,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..43 [undoc] */ { "bit 0,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..44 [undoc] */ { "bit 0,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..45 [undoc] */ { "bit 0,(iy+%02xh)", A_8P }, /* fdcb..46 */ { "bit 0,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..47 [undoc] */ { "bit 1,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..48 [undoc] */ { "bit 1,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..49 [undoc] */ { "bit 1,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..4a [undoc] */ { "bit 1,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..4b [undoc] */ { "bit 1,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..4c [undoc] */ { "bit 1,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..4d [undoc] */ { "bit 1,(iy+%02xh)", A_8P }, /* fdcb..4e */ { "bit 1,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..4f [undoc] */ { "bit 2,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..50 [undoc] */ { "bit 2,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..51 [undoc] */ { "bit 2,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..52 [undoc] */ { "bit 2,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..53 [undoc] */ { "bit 2,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..54 [undoc] */ { "bit 2,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..55 [undoc] */ { "bit 2,(iy+%02xh)", A_8P }, /* fdcb..56 */ { "bit 2,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..57 [undoc] */ { "bit 3,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..58 [undoc] */ { "bit 3,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..59 [undoc] */ { "bit 3,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..5a [undoc] */ { "bit 3,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..5b [undoc] */ { "bit 3,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..5c [undoc] */ { "bit 3,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..5d [undoc] */ { "bit 3,(iy+%02xh)", A_8P }, /* fdcb..5e */ { "bit 3,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..5f [undoc] */ { "bit 4,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..60 [undoc] */ { "bit 4,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..61 [undoc] */ { "bit 4,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..62 [undoc] */ { "bit 4,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..63 [undoc] */ { "bit 4,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..64 [undoc] */ { "bit 4,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..65 [undoc] */ { "bit 4,(iy+%02xh)", A_8P }, /* fdcb..66 */ { "bit 4,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..67 [undoc] */ { "bit 5,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..68 [undoc] */ { "bit 5,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..69 [undoc] */ { "bit 5,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..6a [undoc] */ { "bit 5,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..6b [undoc] */ { "bit 5,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..6c [undoc] */ { "bit 5,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..6d [undoc] */ { "bit 5,(iy+%02xh)", A_8P }, /* fdcb..6e */ { "bit 5,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..6f [undoc] */ { "bit 6,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..70 [undoc] */ { "bit 6,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..71 [undoc] */ { "bit 6,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..72 [undoc] */ { "bit 6,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..73 [undoc] */ { "bit 6,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..74 [undoc] */ { "bit 6,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..75 [undoc] */ { "bit 6,(iy+%02xh)", A_8P }, /* fdcb..76 */ { "bit 6,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..77 [undoc] */ { "bit 7,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..78 [undoc] */ { "bit 7,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..79 [undoc] */ { "bit 7,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..7a [undoc] */ { "bit 7,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..7b [undoc] */ { "bit 7,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..7c [undoc] */ { "bit 7,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..7d [undoc] */ { "bit 7,(iy+%02xh)", A_8P }, /* fdcb..7e */ { "bit 7,(iy+%02xh)\t;undoc equiv", A_8P }, /* fdcb..7f [undoc] */ { "ld b,res 0,(iy+%02xh)", A_8P }, /* fdcb..80 [undoc] */ { "ld c,res 0,(iy+%02xh)", A_8P }, /* fdcb..81 [undoc] */ { "ld d,res 0,(iy+%02xh)", A_8P }, /* fdcb..82 [undoc] */ { "ld e,res 0,(iy+%02xh)", A_8P }, /* fdcb..83 [undoc] */ { "ld h,res 0,(iy+%02xh)", A_8P }, /* fdcb..84 [undoc] */ { "ld l,res 0,(iy+%02xh)", A_8P }, /* fdcb..85 [undoc] */ { "res 0,(iy+%02xh)", A_8P }, /* fdcb..86 */ { "ld a,res 0,(iy+%02xh)", A_8P }, /* fdcb..87 [undoc] */ { "ld b,res 1,(iy+%02xh)", A_8P }, /* fdcb..88 [undoc] */ { "ld c,res 1,(iy+%02xh)", A_8P }, /* fdcb..89 [undoc] */ { "ld d,res 1,(iy+%02xh)", A_8P }, /* fdcb..8a [undoc] */ { "ld e,res 1,(iy+%02xh)", A_8P }, /* fdcb..8b [undoc] */ { "ld h,res 1,(iy+%02xh)", A_8P }, /* fdcb..8c [undoc] */ { "ld l,res 1,(iy+%02xh)", A_8P }, /* fdcb..8d [undoc] */ { "res 1,(iy+%02xh)", A_8P }, /* fdcb..8e */ { "ld a,res 1,(iy+%02xh)", A_8P }, /* fdcb..8f [undoc] */ { "ld b,res 2,(iy+%02xh)", A_8P }, /* fdcb..90 [undoc] */ { "ld c,res 2,(iy+%02xh)", A_8P }, /* fdcb..91 [undoc] */ { "ld d,res 2,(iy+%02xh)", A_8P }, /* fdcb..92 [undoc] */ { "ld e,res 2,(iy+%02xh)", A_8P }, /* fdcb..93 [undoc] */ { "ld h,res 2,(iy+%02xh)", A_8P }, /* fdcb..94 [undoc] */ { "ld l,res 2,(iy+%02xh)", A_8P }, /* fdcb..95 [undoc] */ { "res 2,(iy+%02xh)", A_8P }, /* fdcb..96 */ { "ld a,res 2,(iy+%02xh)", A_8P }, /* fdcb..97 [undoc] */ { "ld b,res 3,(iy+%02xh)", A_8P }, /* fdcb..98 [undoc] */ { "ld c,res 3,(iy+%02xh)", A_8P }, /* fdcb..99 [undoc] */ { "ld d,res 3,(iy+%02xh)", A_8P }, /* fdcb..9a [undoc] */ { "ld e,res 3,(iy+%02xh)", A_8P }, /* fdcb..9b [undoc] */ { "ld h,res 3,(iy+%02xh)", A_8P }, /* fdcb..9c [undoc] */ { "ld l,res 3,(iy+%02xh)", A_8P }, /* fdcb..9d [undoc] */ { "res 3,(iy+%02xh)", A_8P }, /* fdcb..9e */ { "ld a,res 3,(iy+%02xh)", A_8P }, /* fdcb..9f [undoc] */ { "ld b,res 4,(iy+%02xh)", A_8P }, /* fdcb..a0 [undoc] */ { "ld c,res 4,(iy+%02xh)", A_8P }, /* fdcb..a1 [undoc] */ { "ld d,res 4,(iy+%02xh)", A_8P }, /* fdcb..a2 [undoc] */ { "ld e,res 4,(iy+%02xh)", A_8P }, /* fdcb..a3 [undoc] */ { "ld h,res 4,(iy+%02xh)", A_8P }, /* fdcb..a4 [undoc] */ { "ld l,res 4,(iy+%02xh)", A_8P }, /* fdcb..a5 [undoc] */ { "res 4,(iy+%02xh)", A_8P }, /* fdcb..a6 */ { "ld a,res 4,(iy+%02xh)", A_8P }, /* fdcb..a7 [undoc] */ { "ld b,res 5,(iy+%02xh)", A_8P }, /* fdcb..a8 [undoc] */ { "ld c,res 5,(iy+%02xh)", A_8P }, /* fdcb..a9 [undoc] */ { "ld d,res 5,(iy+%02xh)", A_8P }, /* fdcb..aa [undoc] */ { "ld e,res 5,(iy+%02xh)", A_8P }, /* fdcb..ab [undoc] */ { "ld h,res 5,(iy+%02xh)", A_8P }, /* fdcb..ac [undoc] */ { "ld l,res 5,(iy+%02xh)", A_8P }, /* fdcb..ad [undoc] */ { "res 5,(iy+%02xh)", A_8P }, /* fdcb..ae */ { "ld a,res 5,(iy+%02xh)", A_8P }, /* fdcb..af [undoc] */ { "ld b,res 6,(iy+%02xh)", A_8P }, /* fdcb..b0 [undoc] */ { "ld c,res 6,(iy+%02xh)", A_8P }, /* fdcb..b1 [undoc] */ { "ld d,res 6,(iy+%02xh)", A_8P }, /* fdcb..b2 [undoc] */ { "ld e,res 6,(iy+%02xh)", A_8P }, /* fdcb..b3 [undoc] */ { "ld h,res 6,(iy+%02xh)", A_8P }, /* fdcb..b4 [undoc] */ { "ld l,res 6,(iy+%02xh)", A_8P }, /* fdcb..b5 [undoc] */ { "res 6,(iy+%02xh)", A_8P }, /* fdcb..b6 */ { "ld a,res 6,(iy+%02xh)", A_8P }, /* fdcb..b7 [undoc] */ { "ld b,res 7,(iy+%02xh)", A_8P }, /* fdcb..b8 [undoc] */ { "ld c,res 7,(iy+%02xh)", A_8P }, /* fdcb..b9 [undoc] */ { "ld d,res 7,(iy+%02xh)", A_8P }, /* fdcb..ba [undoc] */ { "ld e,res 7,(iy+%02xh)", A_8P }, /* fdcb..bb [undoc] */ { "ld h,res 7,(iy+%02xh)", A_8P }, /* fdcb..bc [undoc] */ { "ld l,res 7,(iy+%02xh)", A_8P }, /* fdcb..bd [undoc] */ { "res 7,(iy+%02xh)", A_8P }, /* fdcb..be */ { "ld a,res 7,(iy+%02xh)", A_8P }, /* fdcb..bf [undoc] */ { "ld b,set 0,(iy+%02xh)", A_8P }, /* fdcb..c0 [undoc] */ { "ld c,set 0,(iy+%02xh)", A_8P }, /* fdcb..c1 [undoc] */ { "ld d,set 0,(iy+%02xh)", A_8P }, /* fdcb..c2 [undoc] */ { "ld e,set 0,(iy+%02xh)", A_8P }, /* fdcb..c3 [undoc] */ { "ld h,set 0,(iy+%02xh)", A_8P }, /* fdcb..c4 [undoc] */ { "ld l,set 0,(iy+%02xh)", A_8P }, /* fdcb..c5 [undoc] */ { "set 0,(iy+%02xh)", A_8P }, /* fdcb..c6 */ { "ld a,set 0,(iy+%02xh)", A_8P }, /* fdcb..c7 [undoc] */ { "ld b,set 1,(iy+%02xh)", A_8P }, /* fdcb..c8 [undoc] */ { "ld c,set 1,(iy+%02xh)", A_8P }, /* fdcb..c9 [undoc] */ { "ld d,set 1,(iy+%02xh)", A_8P }, /* fdcb..ca [undoc] */ { "ld e,set 1,(iy+%02xh)", A_8P }, /* fdcb..cb [undoc] */ { "ld h,set 1,(iy+%02xh)", A_8P }, /* fdcb..cc [undoc] */ { "ld l,set 1,(iy+%02xh)", A_8P }, /* fdcb..cd [undoc] */ { "set 1,(iy+%02xh)", A_8P }, /* fdcb..ce */ { "ld a,set 1,(iy+%02xh)", A_8P }, /* fdcb..cf [undoc] */ { "ld b,set 2,(iy+%02xh)", A_8P }, /* fdcb..d0 [undoc] */ { "ld c,set 2,(iy+%02xh)", A_8P }, /* fdcb..d1 [undoc] */ { "ld d,set 2,(iy+%02xh)", A_8P }, /* fdcb..d2 [undoc] */ { "ld e,set 2,(iy+%02xh)", A_8P }, /* fdcb..d3 [undoc] */ { "ld h,set 2,(iy+%02xh)", A_8P }, /* fdcb..d4 [undoc] */ { "ld l,set 2,(iy+%02xh)", A_8P }, /* fdcb..d5 [undoc] */ { "set 2,(iy+%02xh)", A_8P }, /* fdcb..d6 */ { "ld a,set 2,(iy+%02xh)", A_8P }, /* fdcb..d7 [undoc] */ { "ld b,set 3,(iy+%02xh)", A_8P }, /* fdcb..d8 [undoc] */ { "ld c,set 3,(iy+%02xh)", A_8P }, /* fdcb..d9 [undoc] */ { "ld d,set 3,(iy+%02xh)", A_8P }, /* fdcb..da [undoc] */ { "ld e,set 3,(iy+%02xh)", A_8P }, /* fdcb..db [undoc] */ { "ld h,set 3,(iy+%02xh)", A_8P }, /* fdcb..dc [undoc] */ { "ld l,set 3,(iy+%02xh)", A_8P }, /* fdcb..dd [undoc] */ { "set 3,(iy+%02xh)", A_8P }, /* fdcb..de */ { "ld a,set 3,(iy+%02xh)", A_8P }, /* fdcb..df [undoc] */ { "ld b,set 4,(iy+%02xh)", A_8P }, /* fdcb..e0 [undoc] */ { "ld c,set 4,(iy+%02xh)", A_8P }, /* fdcb..e1 [undoc] */ { "ld d,set 4,(iy+%02xh)", A_8P }, /* fdcb..e2 [undoc] */ { "ld e,set 4,(iy+%02xh)", A_8P }, /* fdcb..e3 [undoc] */ { "ld h,set 4,(iy+%02xh)", A_8P }, /* fdcb..e4 [undoc] */ { "ld l,set 4,(iy+%02xh)", A_8P }, /* fdcb..e5 [undoc] */ { "set 4,(iy+%02xh)", A_8P }, /* fdcb..e6 */ { "ld a,set 4,(iy+%02xh)", A_8P }, /* fdcb..e7 [undoc] */ { "ld b,set 5,(iy+%02xh)", A_8P }, /* fdcb..e8 [undoc] */ { "ld c,set 5,(iy+%02xh)", A_8P }, /* fdcb..e9 [undoc] */ { "ld d,set 5,(iy+%02xh)", A_8P }, /* fdcb..ea [undoc] */ { "ld e,set 5,(iy+%02xh)", A_8P }, /* fdcb..eb [undoc] */ { "ld h,set 5,(iy+%02xh)", A_8P }, /* fdcb..ec [undoc] */ { "ld l,set 5,(iy+%02xh)", A_8P }, /* fdcb..ed [undoc] */ { "set 5,(iy+%02xh)", A_8P }, /* fdcb..ee */ { "ld a,set 5,(iy+%02xh)", A_8P }, /* fdcb..ef [undoc] */ { "ld b,set 6,(iy+%02xh)", A_8P }, /* fdcb..f0 [undoc] */ { "ld c,set 6,(iy+%02xh)", A_8P }, /* fdcb..f1 [undoc] */ { "ld d,set 6,(iy+%02xh)", A_8P }, /* fdcb..f2 [undoc] */ { "ld e,set 6,(iy+%02xh)", A_8P }, /* fdcb..f3 [undoc] */ { "ld h,set 6,(iy+%02xh)", A_8P }, /* fdcb..f4 [undoc] */ { "ld l,set 6,(iy+%02xh)", A_8P }, /* fdcb..f5 [undoc] */ { "set 6,(iy+%02xh)", A_8P }, /* fdcb..f6 */ { "ld a,set 6,(iy+%02xh)", A_8P }, /* fdcb..f7 [undoc] */ { "ld b,set 7,(iy+%02xh)", A_8P }, /* fdcb..f8 [undoc] */ { "ld c,set 7,(iy+%02xh)", A_8P }, /* fdcb..f9 [undoc] */ { "ld d,set 7,(iy+%02xh)", A_8P }, /* fdcb..fa [undoc] */ { "ld e,set 7,(iy+%02xh)", A_8P }, /* fdcb..fb [undoc] */ { "ld h,set 7,(iy+%02xh)", A_8P }, /* fdcb..fc [undoc] */ { "ld l,set 7,(iy+%02xh)", A_8P }, /* fdcb..fd [undoc] */ { "set 7,(iy+%02xh)", A_8P }, /* fdcb..fe */ { "ld a,set 7,(iy+%02xh)", A_8P }, /* fdcb..ff [undoc] */ } }; int disassemble(unsigned short pc) { int i, j; struct opcode *code; int addr; addr = pc; i = mem_read(pc++); if (!major[i].name) { j = major[i].args; i = mem_read(pc++); if (!minor[j][i].name) { /* dd cb or fd cb; offset comes *before* instruction */ j = minor[j][i].args; pc++; /* skip over offset */ i = mem_read(pc++); } code = &minor[j][i]; } else { code = &major[i]; } printf ("%04x ", addr); for (i = 0; i < ((pc + arglen(code->args) - addr) & 0xffff); i++) printf("%02x ", mem_read(addr + i)); for (; i < 4; i++) printf(" "); printf(" "); switch (code->args) { case A_16: /* 16-bit number */ printf (code->name, mem_read(pc + 1), mem_read(pc)); break; case A_8X2: /* Two 8-bit numbers */ printf (code->name, mem_read(pc), mem_read(pc + 1)); break; case A_8: /* One 8-bit number */ printf (code->name, mem_read(pc)); break; case A_8P: /* One 8-bit number before last opcode byte */ printf (code->name, mem_read(pc - 2)); break; case A_0: /* No args */ case A_0B: /* No args, backskip over last opcode byte */ fputs (code->name, stdout); break; case A_8R: /* One 8-bit relative address */ printf (code->name, (pc + 1 + (signed char) mem_read(pc)) & 0xffff); break; } putchar ('\n'); pc += arglen(code->args); return pc; /* return the location of the next instruction */ } xtrs-4.9d/do6.jcl000066400000000000000000000006101306603614600137160ustar00rootroot00000000000000. Avoid running Model I/III-only xtrs utilities on Model 4 remove cd/cmd:#D# remove pwd/cmd:#D# remove unix/cmd:#D# remove mount/cmd:#D# remove umount/cmd:#D# remove truedam/cmd:#D# rename cd6/cmd:#D# cd/cmd:#D# rename pwd6/cmd:#D# pwd/cmd:#D# rename unix6/cmd:#D# unix/cmd:#D# rename mount6/cmd:#D# mount/cmd:#D# rename umount6/cmd:#D# umount/cmd:#D# rename truedam6/cmd:#D# truedam/cmd:#D# xtrs-4.9d/dskspec.html000066400000000000000000000427341306603614600150730ustar00rootroot00000000000000 Common File Formats for Emulated TRS-80 Floppy Disks

Common File Formats for Emulated TRS-80 Floppy Disks

Tim Mann
http://tim-mann.org
Last revised 4 Jul 2008

Most current TRS-80 Model I/III/4 emulators use one of three common file formats for emulated floppy disk media. The extension .DSK is usually used for all three formats, and some emulators transparently support two or three of them, while others support only one. The two most common formats both originated with emulators written by Jeff Vavasour, while the third originated with an emulator written by David Keil, so I'll take the liberty of giving the formats names that use their initials.

  • The JV1 format originated in Jeff's Model I emulator for MS-DOS. It's a very simple, limited format that can represent only single-density media with 256 byte sectors and a Model I directory on track 17.

  • The JV3 format originated in Jeff's Model III/4 emulator for MS-DOS. It is much more flexible than JV1, but still cannot represent everything the real hardware can do, so some copy-protected disks cannot be represented. The format has been extended to support 8-inch floppies and sector sizes of other than 256 bytes, but not all emulators support these extensions. I indicate below which features are extensions and which emulators are known to support which extensions.

  • The DMK format originated in David's Model III/4 emulator for Windows. Unlike JV1 and JV3, DMK is able to represent essentially everything that a real TRS-80 floppy disk controller could do, including copy protected TRS-80 disks.

This document describes the JV1 and JV3 formats in complete detail and indicates (where known) which emulators support which. DMK is quite different from JV1 and JV3 and is not described in this document, but there is a description on David Keil's Web page. You probably don't need any of this information unless you are writing an emulator or working with unusual disks.

The JV1 Format

The JV1 format is simply an array of 256-byte sectors stored in a file. Byte 0 of the file is byte 0 of track 0, sector 0; byte 256 is byte 0 of track 0, sector 1, and so forth. There are 10 sectors per track (i.e., single density), numbered 0 through 9, and only one side. Tracks are numbered starting at 0. All sectors on track 17 are formatted with the nonstandard data address mark 0xFA, indicating a TRSDOS 2.3 directory. All other sectors are formatted with the standard data address mark 0xFB.

Note: In emulations of the WD1791/3 floppy disk controller used in the Model III and 4, it is best to present track 17 as being formatted with the standard deleted data address mark 0xF8. The WD1791/3 cannot write 0xFA, and upon reading, returns it as 0xFB. So Model III/4 operating systems use 0xF8 on the directory track instead.

The JV3 Format

The JV3 format consists of a fixed-size array of sector headers, followed by an area containing the data for each sector. As an extension to allow for more sectors, a second block of sector headers and data can follow. Here is the format in pseudo-C notation. The length of each data area depends on the content of the headers, as described below.
typedef struct {
  SectorHeader headers1[2901];
  unsigned char writeprot;
  unsigned char data1[];
  SectorHeader headers2[2901];
  unsigned char padding;
  unsigned char data2[];
} JV3;

Write Protect and Padding

The field writeprot should normally contain 0xFF. As an extension, a value of 0x00 in his field indicates that the disk is write-protected (i.e., it is not writable).

The field padding is currently unused. It should contain 0xFF.

The Sector Header

Each sector in a JV3 file is described by a three-byte header. The first byte gives the sector's track number, the second gives its sector number on the track, and the third is a set of flags.
typedef struct {
  unsigned char track;
  unsigned char sector;
  unsigned char flags;
} SectorHeader;

#define JV3_DENSITY     0x80  /* 1=dden, 0=sden */
#define JV3_DAM         0x60  /* data address mark code; see below */
#define JV3_SIDE        0x10  /* 0=side 0, 1=side 1 */
#define JV3_ERROR       0x08  /* 0=ok, 1=CRC error */
#define JV3_NONIBM      0x04  /* 0=normal, 1=short */
#define JV3_SIZE        0x03  /* in used sectors: 0=256,1=128,2=1024,3=512
                                 in free sectors: 0=512,1=1024,2=128,3=256 */

#define JV3_FREE        0xFF  /* in track and sector fields of free sectors */
#define JV3_FREEF       0xFC  /* in flags field, or'd with size code */

The track field gives both the physical track number on which the sector lies and the logical track number that is formatted in the sector's ID. Numbering starts from 0. Thus it is not possible to represent a copy-protected disk where sectors were deliberately formatted with incorrect track numbers. The format allows for 255 tracks (numbered 0 through 0xFE), but emulators may impose lower limits. You can expect at least 80 tracks to be supported; xtrs currently allows up to 96.

The sector field gives the logical sector number that is formatted into the sector's ID field. The physical order of sectors on the track is not explicitly represented, but xtrs (and perhaps other emulators) present them in the order they are recorded in the JV3 file; thus when a TRS-80 program formats a track with interleave and reads back the sector ids, they come back in the same interleaved order.

The flags field packs in a lot of information:

  • If JV3_DENSITY is set, the sector was formatted in double density (MFM); if not, it was formatted in single density (FM).

  • The 2-bit JV3_DAM field encodes the sector's data address mark. Here are the basic meanings of the codes:
    JV3_DAM value Single density Double density
    0x00 0xFB (Normal) 0xFB (Normal)
    0x20 0xFA (User-defined) 0xF8 (Deleted)
    0x40 0xF9 (User-defined) Invalid; unused
    0x60 0xF8 (Deleted) Invalid; unused

    The treatment of single density data address marks by the Western Digital 1771 and 179x controllers used in original TRS-80 hardware is rather inconvenient. The WD1771 (used in the TRS-80 Model I) is capable of writing any of the four DAMs shown above, and can distinguish amongst all four on reading. The WD179x (used in the Model III and 4), however, can write only 0xFB or 0xF8, and on reading, it cannot distinguish between 0xFB and 0xFA, or between 0xF8 and 0xF9.

    TRS-80 operating systems differentiate directory sectors from ordinary data sectors by giving them different data address marks. Unfortunately, Model I TRSDOS uses 0xFA on directory sectors, which a WD179x cannot write and cannot distinguish from the 0xFB used on data sectors. Other Model I operating systems (such as LDOS) typically write 0xF8 on directory sectors but accept either 0xFA or 0xF8 when reading them, allowing them to read TRSDOS disks. Compatibility problems remain when attempting to use Model I TRSDOS disks on a Model III or 4, and when attempting to use LDOS disks with Model I TRSDOS.

    An emulator can easily paper over these compatibility problems by behaving differently from the real hardware. All currently known emulators do so, making (at least) the following changes to strictly correct behavior: (1) If TRS-80 software attempts to write or format a 0xF8 DAM in single density, it is instead recorded in the JV3 header as 0xFA. (2) If TRS-80 software reads a single density sector that has the 0xFA DAM using an emulated WD179x, it is returned as 0xF8 instead. These changes hide all the DOS compatibility problems described in the previous paragraph.

    It might be worthwhile to make precisely correct behavior available as a run-time emulator option, as this might allow more types of "protected" self-booting TRS-80 disks to work correctly. This option is available in xtrs version 3.2 and later, but not in any other known emulators.

    The following tables summarize the DAM behavior of both the WD1771 and the WD179x. On the WD1771, read status bits 6,5 are used to report the DAM of the sector just read, while write command bits 1,0 select the DAM to write; on the WD179x, only read status bit 5 and write command bit 0 are significant: read status bit 6 is always 0, while write command bit 1 is used for a function unrelated to DAM selection. The behavior of these bits on the actual hardware is shown first in each cell; the modifications typically made by emulators follow in parentheses. It should be emphasized that WD1771 behavior shown here correctly describes the actual hardware, even though it contradicts the Western Digital data sheet; the data sheet erroneously transposes the column headings for status bits 6 and 5. As an aside, it seems likely that the engineers who designed the WD179x were misled by this error, as the value that the WD179x returns in bit 5 is the value that the WD1771 was documented as returning in bit 5, but that it actually returns in bit 6.

    Read status bits 6,5:
    DAM WD1771 WD179x single WD179x double
    0xFB 0,0 0,0 0,0
    0xFA 0,1 0,0 (0,1) impossible
    0xF9 1,0 0,1 impossible
    0xF8 1,1 0,1 0,1

    Write command bits 1,0:
    Bits WD1771 WD179x single WD179x double
    0,0 0xFB 0xFB 0xFB
    0,1 0xFA 0xF8 (0xFA) 0xF8
    1,0 0xF9 0xFB 0xFB
    1,1 0xF8 (0xFA) 0xF8 (0xFA) 0xF8

  • JV3_SIDE reflects both the physical side on which the sector is recorded and the side number formatted in the sector's ID. Thus it is not possible to represent a copy-protected disk where sectors were formatted with incorrect side numbers or with values other than 0 or 1 in the sector ID's 8-bit side field.

  • JV3_ERROR, if set, indicates that the sector should show a data CRC error when read. The actual value of the two CRC bytes is not represented.

  • JV3_NONIBM is an xtrs-specific extension that partially supports the WD1771's feature of "non-IBM" sector sizes. Only a small subset of the functionality is supported, with some special kludges specifically to make the VTOS 3.0 copy protection scheme work. It is probably best to treat this bit as a "must be zero" field in other emulators; see the xtrs source code if you are really sure you want to know how it works, and keep your barf bag handy.

  • JV3_SIZE is an extension to support sector sizes of other than 256 bytes. This field is encoded differently depending on whether the sector is in use or free (not in use):

    Size IBM size code in sector ID JV3_SIZE field value if in use JV3_SIZE field value if free
    128 00 1 2
    256 01 0 3
    512 02 3 0
    1024 03 2 1

    Thus, if a sector is in use, xor'ing its JV3_SIZE field with 1 gives the IBM size code that appears in its sector ID size field. If a sector is free, xor'ing its JV3_SIZE field with 2 gives its IBM size code. This representation was chosen because the original JV3 format supports only 256-byte sectors, always places zeros in the JV3_SIZE field for sectors that are in use, and always places ones in the field for sectors that are free.

If a sector header is not in use (free), its track and sector fields must contain 0xFF. Its flags field must contain 0xFC plus the appropriate free JV3_SIZE field value given above.

The Data Blocks

For each sector header, there is one data block. The blocks are placed in the same order as the headers that describe them, and are tightly packed. Thus to find the data block for the nth header, you need to know the total size of data blocks 0 to n - 1. A sector header marked as free does have a corresponding data block, of the size indicated in its size field. However, the file can (and in fact should; see below) end immediately after the last in-use data block.

The Second Header Block

The second header block is present if and only if the file is long enough to contain it. It starts immediately after the last data block described by the first header block. Thus to find the second header block, you need to know the total size of all data blocks described by the first header block.

It's obvious, by the way, how to extend the format to more than two header blocks, but no known emulators support more than two. Having more than two is not useful to describe any floppy format that was supported by any real TRS-80. One block is sufficient for 5.25-inch DD drives, and two are sufficient for 8-inch drives, 5.25-inch HD drives, or 3.5-inch HD drives.

Allocating and Freeing Sectors

Allocating and freeing sectors is a little tricky (if you support the extension to sizes other than 256 bytes). When a new emulated disk is first created, it should have one header block, filled with free 256-byte sectors. When a new sector is formatted, if a free sector of the correct size exists, it can be reused; otherwise, the next sector after the highest in-use sector can be chosen and changed to the correct size. In the latter case, since there is no data after the sector that is being resized, resizing it does not require anything to move. When a sector is erased (because the track it is on is being reformatted), it should normally be freed without changing its size, so that the data of later sectors need not be moved.

If the highest in-use sector is freed, the emulator should search backward for the new highest in-use sector, and should truncate the file to eliminate any sector data for trailing free sectors, as well as the second header block if it is no longer needed. Why do this? If the user reformats some sectors to be shorter or longer than they used to be, the nominal start of the second header block (as defined above) will shift. If you have garbage at the end of the file, and the block shifts to start somewhere in the garbage, then when you read the file back in again later, you'll have a second header block full of garbage that will confuse you.

Support

Here is a summary of which emulators support which formats and which features. The data is believed current as of this document's revision date. Future versions of some of these emulators may support more (or fewer!) features. If an emulator does not support a feature, it will still work with disks created by emulators that do support the feature, as long as those disks didn't require that feature when they were created. For example, an emulator that supports the second header block will not create a second header block unless you format more that 2901 sectors on one disk; note that an 80 track, double sided, double density 5.25-inch disk contains less than 2901 sectors.
 
  JV1 JV3 Basic features JV3 Write protect JV3 Second header block JV3 Sizes other than  256 JV3 Non-IBM kludge DMK
Jeff Vavasour Model I v3.02u Yes No No No No No No
Jeff Vavasour Model III/4 v2.3 No Yes No (future) No No No No
Matthew Reed Model I/III v1.10 Yes Yes No (future) No (future) No No No
Matthew Reed Model 4 v1.01 Yes Yes Yes Yes No No No
Matthew Reed TRS32 1.0 Yes Yes Yes Yes Yes Yes No
xtrs Model I/III/4 v3.7 Yes Yes Yes Yes Yes Yes Yes
WinTRS80 Model I/III/4 v1.02 Yes Yes Respected but not generated Yes No No No
Yves Lempereur Model I Yes No No No No No No
David Keil Model III/4 Yes Yes, with some limitations Respected but not generated No Yes No Yes

Additional information or corrections for this table are welcome.


Back to the TRS-80 Page | My home page xtrs-4.9d/error.c000066400000000000000000000027231306603614600140400ustar00rootroot00000000000000/* * Copyright (C) 1992 Clarendon Hill Software. * * Permission is granted to any individual or institution to use, copy, * or redistribute this software, provided this copyright notice is retained. * * This software is provided "as is" without any expressed or implied * warranty. If this software brings on any sort of damage -- physical, * monetary, emotional, or brain -- too bad. You've got no one to blame * but yourself. * * The software may be modified for your own purposes, but modified versions * must retain this notice. */ /* Modified by Timothy Mann, 1996 and later $Id: error.c,v 1.8 2008/06/26 04:39:56 mann Exp $ */ #include "z80.h" #include #include #include extern char *program_name; void debug(const char *fmt, ...) { va_list args; char xfmt[2048]; strcpy(xfmt, "debug: "); strcat(xfmt, fmt); /*strcat(xfmt, "\n");*/ va_start(args, fmt); vfprintf(stderr, xfmt, args); va_end(args); } void error(const char *fmt, ...) { va_list args; char xfmt[2048]; strcpy(xfmt, program_name); strcat(xfmt, " error: "); strcat(xfmt, fmt); strcat(xfmt, "\n"); va_start(args, fmt); vfprintf(stderr, xfmt, args); va_end(args); } void fatal(const char *fmt, ...) { va_list args; char xfmt[2048]; strcpy(xfmt, program_name); strcat(xfmt, " fatal error: "); strcat(xfmt, fmt); strcat(xfmt, "\n"); va_start(args, fmt); vfprintf(stderr, xfmt, args); va_end(args); exit(1); } xtrs-4.9d/expall.bas000066400000000000000000000013701306603614600145140ustar00rootroot0000000000000020 CLEAR 1000 40 REM-- List an LDOS directory by opening and reading DIR/SYS 50 REM-- and use the xtrs export program to export all files 60 LINE INPUT "Drive? "; DR$ 80 OPEN "ri", 1, "dir/sys.rs0lt0ff:" + DR$, 32 100 FIELD 1, 1 AS AT$, 1 AS FL$, 1 AS DT$, 1 AS EF$, 1 AS RL$, 8 AS NM$, 3 AS NX$, 2 AS OP$, 2 AS UP$, 2 AS ER$, 10 AS XT$ 120 GET 1, 16 140 N = 0 160 IF EOF(1) THEN END 180 N = N + 1 200 GET 1 220 IF (ASC(AT$) AND 16) = 0 THEN GOTO 160 240 I=INSTR(NM$, " ") 260 IF I THEN NH$ = LEFT$(NM$, I-1) ELSE NH$ = NM$ 280 I = INSTR(NX$, " ") 300 IF I THEN NT$ = LEFT$(NX$, I-1) ELSE NT$ = NX$ 320 REM print n; " "; 340 NF$ = NH$ + "/" + NT$ 360 PRINT NF$ 380 UF$ = NH$ + "." + NT$ 400 CMD "export -l " + NF$ + ".rs0lt0ff:" + DR$ + " " + UF$ 420 GOTO 160 xtrs-4.9d/export.cmd000066400000000000000000000011721306603614600145460ustar00rootroot00000000000000RÍDÉÍ DÉÍ$DÉÍ(DÉÍ6DÉÍ9DÉÍ DÉÍ-@ÉÍ0@É͵SÉÍçSÉ>NïÉ>:ïÉ>;ïÉ><ïÉ>CïÉ>KïÉ>ïÉ>ïÉ>ïÉ> ïÉÍ÷SÉ: þ@( åR!,R,í°á:'DÖ‚(:DÖ2XR~þ Ú™S #õþ- ,#~ö þe —2XRþl >2üS þn™S>2ýS#~þ Ù#ÅjT"þSÍR™S~þ 8 #öšT> ¾í 8û—*þSšT~þ:(þ!8 þ/ >.#ì—!šTjTSÍRá( þ*(OÍRà R!šT:üS·ÄÊSA¶í0(!)TâSÍ(RÕjTÍRÑ( þ(?OÍRà R Å:ýS§(!šT>  ¾ q#ùÁy°Å G:rTO !šTí3Á(!>T+y° ³í1(!TTjTÍ R(OÍRà R!ÃR!TÍ$Rà RõÍ$Rñ!šTí5Í$Rà R@å~þ( õÍñ#þ ñáÉåT]~þ[ #~ ÖAþ~0ö #· èáÉíKvT:XR§À:rT§ÈÉíKvTÉlTUsage: EXPORT [-lne] fromfile [unixfile] Error in Unix open: Error in Unix write: Error in Unix close: YRxtrs-4.9d/export.lst000066400000000000000000000452071306603614600146140ustar00rootroot00000000000000 1: ;; export.z80 2: ;; Timothy Mann, 8/24/97 3: ;; $Id: export.z80,v 1.14 2008/06/26 04:39:56 mann Exp $ 4: ;; 5: ;; Copyright (c) 1997, Timothy Mann 6: ;; 7: ;; This software may be copied, modified, and used for any 8: ;; purpose without fee, provided that (1) the above copyright 9: ;; notice is retained, and (2) modified versions are clearly 10: ;; marked as having been modified, with the modifier's name and 11: ;; the date included. 12: ;; 13: ;; Use xtrs emulator traps to copy a file from TRS-80 to Unix 14: ;; Usage: EXPORT [-lne] fromfile [unixfile] 15: ;; Parameter -l will convert the Unix file to lower case. 16: ;; (Needed for NEWDOS/80. They insist on uppercasing the command line.) 17: ;; If the -n parameter is given, each carriage return ('\r') 18: ;; in the TRS-80 file is converted to a newline ('\n') in the Unix file. 19: ;; The program tries to determine what DOS it is running on and use 20: ;; the correct FCB end of file convention, but this works only on 21: ;; TRSDOS, LDOS, and NEWDOS/80. For other DOSes that use the 22: ;; NEWDOS/80 convention (such as DOSPLUS), give the -e paramter. 23: ;; If the unixfile parameter is omitted, the fromfile parameter is used, 24: ;; with '/' changed to '.'. 25: 26: ;; Model I/III addresses 27: 441C @fspec equ 441ch 28: 4420 @init equ 4420h 29: 4424 @open equ 4424h 30: 4428 @close equ 4428h 31: 4436 @read equ 4436h 32: 4439 @write equ 4439h 33: 4409 @error equ 4409h 34: 402D @exit equ 402dh 35: 4030 @abort equ 4030h 36: 001B @put equ 001bh 37: 401D dodcb$ equ 401dh 38: 39: ;; Model 4 SVCs 40: 0028 @svc equ 40 ; rst address for SVCs 41: ;@svc equ 5 ; older zmac requires 8080-style "rst 5" 42: 004E @fspec6 equ 78 43: 003A @init6 equ 58 44: 003B @open6 equ 59 45: 003C @close6 equ 60 46: 0043 @read6 equ 67 47: 004B @write6 equ 75 48: 001A @error6 equ 26 49: 0016 @exit6 equ 22 50: 0015 @abort6 equ 21 51: 000A @dsply6 equ 10 52: 53: ;; Model 4 only: file init or open with wrong LRL. Can be ignored. 54: 002A lrlerr equ 42 55: 56: 5200 org 5200h 57: 58: ;; Jump tables for OS independence 59: 5200 startj: 60: 5200 CD1C44 fspec: call @fspec 61: 5203 C9 ret 62: 5204 CD2044 init: call @init 63: 5207 C9 ret 64: 5208 CD2444 open: call @open 65: 520B C9 ret 66: 520C CD2844 close: call @close 67: 520F C9 ret 68: 5210 CD3644 reed: call @read 69: 5213 C9 ret 70: 5214 CD3944 write: call @write 71: 5217 C9 ret 72: 5218 CD0944 error: call @error 73: 521B C9 ret 74: 521C CD2D40 exit: call @exit 75: 521F C9 ret 76: 5220 CD3040 abort: call @abort 77: 5223 C9 ret 78: 5224 CDB553 dsply: call dsply5 79: 5227 C9 ret 80: 5228 CDE753 getern: call getern5 81: 522B C9 ret 82: 522C endj: 83: 84: ; Model 4 85: 522C startj6: 86: 522C 3E4E ld a, @fspec6 87: 522E EF rst @svc 88: 522F C9 ret 89: 5230 3E3A ld a, @init6 90: 5232 EF rst @svc 91: 5233 C9 ret 92: 5234 3E3B ld a, @open6 93: 5236 EF rst @svc 94: 5237 C9 ret 95: 5238 3E3C ld a, @close6 96: 523A EF rst @svc 97: 523B C9 ret 98: 523C 3E43 ld a, @read6 99: 523E EF rst @svc 100: 523F C9 ret 101: 5240 3E4B ld a, @write6 102: 5242 EF rst @svc 103: 5243 C9 ret 104: 5244 3E1A ld a, @error6 105: 5246 EF rst @svc 106: 5247 C9 ret 107: 5248 3E16 ld a, @exit6 108: 524A EF rst @svc 109: 524B C9 ret 110: 524C 3E15 ld a, @abort6 111: 524E EF rst @svc 112: 524F C9 ret 113: 5250 3E0A ld a, @dsply6 114: 5252 EF rst @svc 115: 5253 C9 ret 116: 5254 CDF753 call getern6 117: 5257 C9 ret 118: 119: ; Nonzero for LDOS ern convention 120: 5258 01 ernldos: db 1 121: 122: ; Emulator trap instructions, byte-reversed for use in defw: 123: 30ED emt_open equ 30edh 124: 31ED emt_close equ 31edh 125: 32ED emt_read equ 32edh 126: 33ED emt_write equ 33edh 127: 34ED emt_lseek equ 34edh 128: 35ED emt_strerror equ 35edh 129: 130: 0003 EO_ACCMODE equ 3q 131: 0000 EO_RDONLY equ 0q 132: 0001 EO_WRONLY equ 1q 133: 0002 EO_RDWR equ 2q 134: 0040 EO_CREAT equ 100q 135: 0080 EO_EXCL equ 200q 136: 0200 EO_TRUNC equ 1000q 137: 0400 EO_APPEND equ 2000q 138: 139: 5259 export: 140: 5259 3A0A00 ld a, (000ah) ; Model 4? 141: 525C FE40 cp 40h 142: 525E 280D jr z, not4 143: 5260 E5 push hl 144: 5261 110052 ld de, startj 145: 5264 212C52 ld hl, startj6 146: 5267 012C00 ld bc, endj - startj 147: 526A EDB0 ldir 148: 526C E1 pop hl 149: 526D not4: 150: 526D 3A2744 ld a, (4427h) ; system id for Newdos/80... 151: 5270 D682 sub 82h ; ...should be 82h (v2.0) 152: 5272 2805 jr z, gotid 153: 5274 3A1F44 ld a, (441fh) ; system version number for most other DOSes 154: 5277 D613 sub 13h ; TRSDOS 1.3? 155: 5279 325852 gotid: ld (ernldos), a 156: 157: 527C 7E flag0: ld a, (hl) ; look for flags 158: 527D FE20 cp ' ' 159: 527F DA9953 jp c, usage ; error if line ends here 160: 5282 2003 jr nz, flag1 161: 5284 23 inc hl 162: 5285 18F5 jr flag0 163: 5287 FE2D flag1: cp '-' 164: 5289 202C jr nz, fromf 165: 528B 23 inc hl 166: 528C 7E ld a, (hl) 167: 528D F620 flag3: or 20h 168: 528F FE65 cp 'e' 169: 5291 2006 jr nz, flagl 170: 5293 97 sub a 171: 5294 325852 ld (ernldos), a 172: 5297 1815 jr flag2 173: 5299 FE6C flagl: cp 'l' 174: 529B 2007 jr nz, flagn ; check for next flag 175: 529D 3E01 ld a, 1 176: 529F 32FC53 ld (lflag), a 177: 52A2 180A jr flag2 178: 52A4 FE6E flagn: cp 'n' 179: 52A6 C29953 jp nz, usage ; unknown flag 180: 52A9 3E01 ld a, 1 181: 52AB 32FD53 ld (nflag), a 182: 52AE 23 flag2: inc hl 183: 52AF 7E ld a, (hl) 184: 52B0 FE20 cp ' ' 185: 52B2 20D9 jr nz, flag3 ; another flag follows 186: 52B4 23 inc hl 187: 52B5 18C5 jr flag0 188: 189: 52B7 116A54 fromf: ld de, dcb ; ready to get LDOS filename from (HL) 190: 52BA 22FE53 ld (lfname), hl ; save if needed to default Unix name 191: 52BD CD0052 call fspec 192: 52C0 C29953 jp nz, usage 193: 194: 52C3 7E unix0: ld a, (hl) ; scan over Unix filename 195: 52C4 FE20 cp ' ' ; first skip spaces 196: 52C6 3814 jr c, usetrs ; if no Unix name, use translated TRS name 197: 52C8 2003 jr nz, unix1 198: 52CA 23 inc hl 199: 52CB 18F6 jr unix0 200: 52CD 119A54 unix1: ld de, iobuf ; copy Unix filename 201: 52D0 3E20 ld a, ' ' 202: 52D2 BE unix2: cp (hl) 203: 52D3 EDA0 ldi 204: 52D5 38FB jr c, unix2 205: 52D7 1B dec de 206: 52D8 97 sub a 207: 52D9 12 ld (de), a ; NUL terminate Unix name 208: 52DA 181C jr gotu 209: 210: 52DC 2AFE53 usetrs: ld hl, (lfname) ; translate TRS-80 name to Unix 211: 52DF 119A54 ld de, iobuf 212: 52E2 7E ut1: ld a, (hl) 213: 52E3 FE3A cp ':' ; drivespec? 214: 52E5 280F jr z, utdone ; done if so 215: 52E7 FE21 cp ' '+1 ; end of line? 216: 52E9 380B jr c, utdone ; done if so 217: 52EB FE2F cp '/' ; change '/' to '.' for extension 218: 52ED 2002 jr nz, notsl 219: 52EF 3E2E ld a, '.' 220: 52F1 12 notsl: ld (de), a 221: 52F2 23 inc hl 222: 52F3 13 inc de 223: 52F4 18EC jr ut1 224: 52F6 97 utdone: sub a ; NUL-terminate Unix name 225: 52F7 12 ld (de), a 226: 227: 52F8 219A54 gotu: ld hl, iobuf 228: 52FB 116A54 ld de, dcb 229: 52FE 0600 ld b, 0 230: 5300 CD0852 call open ; open the TRS-80 file 231: 5303 E1 pop hl 232: 5304 280B jr z, uname 233: 5306 FE2A cp lrlerr 234: 5308 2807 jr z, uname 235: 530A 4F ld c, a 236: 530B CD1852 call error 237: 530E C32052 jp abort 238: 239: 5311 219A54 uname: ld hl, iobuf ; path 240: 5314 3AFC53 ld a, (lflag) 241: 5317 B7 or a 242: 5318 C4CA53 call nz, lcconv ; convert filename to lower case 243: 531B 014102 ld bc, EO_WRONLY|EO_CREAT|EO_TRUNC 244: 531E 11B601 ld de, 0666q ; mode 245: 5321 ED30 defw emt_open ; open the Unix file 246: 5323 2806 jr z, opn2ok ; go if OK 247: 5325 212954 ld hl, uopner ; error message and exit 248: 5328 C3A253 jp uerror 249: 250: ;; Read 251: 532B CD2852 opn2ok: call getern ; count down records in bc 252: 253: 532E D5 loop: push de ; save fd 254: 532F 116A54 ld de, dcb 255: 5332 CD1052 call reed ; read 256 bytes from file 256: 5335 D1 pop de 257: 5336 280B jr z, rdok ; got a full 256 bytes 258: 5338 FE1C cp 28 ; eof? 259: 533A 283F jr z, closit ; yes, OK 260: 533C 4F ld c, a 261: 533D CD1852 call error ; oops, i/o error 262: 5340 C32052 jp abort 263: 5343 0B rdok: dec bc 264: 265: ;; Translate 266: 5344 C5 push bc ; save record count 267: 5345 3AFD53 ld a, (nflag) ; check for NL feature 268: 5348 A7 and a 269: 5349 280F jr z, nlfals 270: 534B 219A54 ld hl, iobuf 271: 534E 3E0D ld a, 0dh 272: 5350 010A00 ld bc, 000ah ; b := 0, c := 0ah 273: 5353 BE tloop: cp (hl) 274: 5354 2001 jr nz, notlf 275: 5356 71 ld (hl), c 276: 5357 23 notlf: inc hl 277: 5358 10F9 djnz tloop 278: 535A C1 nlfals: pop bc ; restore record count 279: 280: ;; Write 281: 535B 79 ld a, c 282: 535C B0 or b ; last record? 283: 535D C5 push bc ; save record count 284: 535E 010001 ld bc, 0100h ; byte count 285: 5361 2007 jr nz, notlst 286: 5363 47 ld b, a 287: 5364 3A7254 ld a, (dcb+8) 288: 5367 4F ld c, a 289: 5368 0D dec c ; EOF offset 0: write 256 bytes 290: 5369 03 inc bc 291: 536A notlst: 292: 536A 219A54 ld hl, iobuf 293: 536D ED33 defw emt_write 294: 536F C1 pop bc 295: 5370 2805 jr z, wrok 296: 5372 213E54 ld hl, uwrer ; write error 297: 5375 182B jr uerror 298: 5377 79 wrok: ld a, c 299: 5378 B0 or b 300: 5379 20B3 jr nz, loop 301: 302: ;; Close 303: 537B ED31 closit: defw emt_close ; close Unix file 304: 537D 2805 jr z, closok 305: 537F 215454 ld hl, uclser ; close error 306: 5382 181E jr uerror 307: 5384 116A54 closok: ld de, dcb 308: 5387 CD0C52 call close ; close the TRS-80 file 309: 538A 2807 jr z, cls2ok 310: 538C 4F ld c, a 311: 538D CD1852 call error ; oops, i/o error 312: 5390 C32052 jp abort 313: 5393 210000 cls2ok: ld hl, 0 ; all is well 314: 5396 C31C52 jp exit 315: 316: ;; Usage message 317: 5399 210054 usage: ld hl, usager ; error message and exit 318: 539C CD2452 call dsply 319: 539F C32052 jp abort 320: 321: ;; Unix error, msg in hl, errno in a 322: 53A2 F5 uerror: push af 323: 53A3 CD2452 call dsply 324: 53A6 F1 pop af 325: 53A7 219A54 ld hl, iobuf 326: 53AA 010001 ld bc, 256 327: 53AD ED35 defw emt_strerror 328: 53AF CD2452 call dsply 329: 53B2 C32052 jp abort 330: 331: ;; Display message in HL. 03h terminate, 0dh newline and terminate. 332: 53B5 111D40 dsply5: ld de, dodcb$ 333: 53B8 E5 push hl 334: 53B9 7E dsply0: ld a, (hl) 335: 53BA FE03 cp 03h 336: 53BC 280A jr z, dsply1 337: 53BE F5 push af 338: 53BF CD1B00 call @put 339: 53C2 F1 pop af 340: 53C3 23 inc hl 341: 53C4 FE0D cp 0dh 342: 53C6 20F1 jr nz, dsply0 343: 53C8 E1 dsply1: pop hl 344: 53C9 C9 ret 345: 346: ;; Convert (NUL terminated) string in HL to lower case. 347: 53CA E5 lcconv: push hl 348: 53CB 54 ld d, h 349: 53CC 5D ld e, l 350: 53CD 7E lcloop: ld a, (hl) 351: 53CE FE5B cp 5bh ; use '[' or uparrow as escape 352: 53D0 2004 jr nz, lconv1 353: 53D2 23 inc hl 354: 53D3 7E ld a, (hl) 355: 53D4 1809 jr lconv2 ; char after esc: don't convert 356: 53D6 D641 lconv1: sub 'A' 357: 53D8 FE1A cp 26 358: 53DA 7E ld a, (hl) 359: 53DB 3002 jr nc, lconv2 360: 53DD F620 or 20h ; convert to lower case 361: 53DF 12 lconv2: ld (de), a 362: 53E0 23 inc hl 363: 53E1 13 inc de 364: 53E2 B7 or a ; NUL terminator? 365: 53E3 20E8 jr nz, lcloop 366: 53E5 E1 pop hl 367: 53E6 C9 ret 368: 369: ;; EOF handling differs between TRS-80 DOSes: 370: ;; For TRSDOS 2.3 and LDOS, word (dcb+12) contains the number of 371: ;; 256 byte records in the file, byte (dcb+8) contains the EOF 372: ;; offset in the last record (0=256). 373: ;; For NEWDOS/80 and TRSDOS 1.3, byte (dcb+8) and word (dcb+12) 374: ;; form a 24 bit number containing the relative byte address of EOF. 375: ;; Thus (dcb+12) differs by one if the file length is not a 376: ;; multiple of 256 bytes. DOSPLUS also uses this convention, 377: ;; and NEWDOS 2.1 probably does too (not checked). 378: 379: ; Returns number of (partial or full) records in BC, destroys A 380: 53E7 getern5: 381: 53E7 ED4B7654 ld bc, (dcb+12) 382: 53EB 3A5852 ld a, (ernldos) ; get ERN convention 383: 53EE A7 and a 384: 53EF C0 ret nz ; done if TRSDOS 2.3/LDOS convention 385: 53F0 3A7254 ld a, (dcb+8) ; length multiple of 256 bytes? 386: 53F3 A7 and a 387: 53F4 C8 ret z ; done if so 388: 53F5 03 inc bc ; no, # of records = last full record + 1 389: 53F6 C9 ret 390: 391: ; All Model 4 mode operating systems should be TRSDOS/LS-DOS 6.x compatible 392: 53F7 getern6: 393: 53F7 ED4B7654 ld bc, (dcb+12) 394: 53FB C9 ret 395: 396: 53FC 00 lflag: defb 0 397: 53FD 00 nflag: defb 0 398: 53FE 0000 lfname: defw 0 399: 400: 5400 55736167 usager: defb 'Usage: EXPORT [-lne] fromfile [unixfile]', 0dh 653A2045 58504F52 54205B2D 6C6E655D 2066726F 6D66696C 65205B75 6E697866 696C655D 0D 401: 5429 4572726F uopner: defb 'Error in Unix open: ', 03h 7220696E 20556E69 78206F70 656E3A20 03 402: 543E 4572726F uwrer: defb 'Error in Unix write: ', 03h 7220696E 20556E69 78207772 6974653A 2003 403: 5454 4572726F uclser: defb 'Error in Unix close: ', 03h 7220696E 20556E69 7820636C 6F73653A 2003 404: 405: 546A dcb: defs 48 ; 48 for Model III TRSDOS 1.3 406: 549A iobuf: defs 256 407: 408: 5259 end export Statistics: 102 symbols 618 bytes Symbol Table: @abort =4030 emt_read =32ed+ lflag 53fc @abort6 = 15 emt_strerror =35ed lfname 53fe @close =4428 emt_write =33ed loop 532e @close6 = 3c endj 522c lrlerr = 2a @dsply6 = a eo_accmode = 3+ nflag 53fd @error =4409 eo_append = 400+ nlfals 535a @error6 = 1a eo_creat = 40 not4 526d @exit =402d eo_excl = 80+ notlf 5357 @exit6 = 16 eo_rdonly = 0+ notlst 536a @fspec =441c eo_rdwr = 2+ notsl 52f1 @fspec6 = 4e eo_trunc = 200 open 5208 @init =4420 eo_wronly = 1 opn2ok 532b @init6 = 3a ernldos 5258 rdok 5343 @open =4424 error 5218 reed 5210 @open6 = 3b exit 521c startj 5200 @put = 1b export 5259 startj6 522c @read =4436 flag0 527c tloop 5353 @read6 = 43 flag1 5287 uclser 5454 @svc = 28 flag2 52ae uerror 53a2 @write =4439 flag3 528d uname 5311 @write6 = 4b flagl 5299 unix0 52c3 abort 5220 flagn 52a4 unix1 52cd close 520c fromf 52b7 unix2 52d2 closit 537b fspec 5200 uopner 5429 closok 5384 getern 5228 usage 5399 cls2ok 5393 getern5 53e7 usager 5400 dcb 546a getern6 53f7 usetrs 52dc dodcb =401d gotid 5279 ut1 52e2 dsply 5224 gotu 52f8 utdone 52f6 dsply0 53b9 init 5204+ uwrer 543e dsply1 53c8 iobuf 549a write 5214+ dsply5 53b5 lcconv 53ca wrok 5377 emt_close =31ed lcloop 53cd emt_lseek =34ed+ lconv1 53d6 emt_open =30ed lconv2 53df xtrs-4.9d/export.z80000066400000000000000000000205631306603614600144310ustar00rootroot00000000000000;; export.z80 ;; Timothy Mann, 8/24/97 ;; $Id: export.z80,v 1.14 2008/06/26 04:39:56 mann Exp $ ;; ;; Copyright (c) 1997, Timothy Mann ;; ;; This software may be copied, modified, and used for any ;; purpose without fee, provided that (1) the above copyright ;; notice is retained, and (2) modified versions are clearly ;; marked as having been modified, with the modifier's name and ;; the date included. ;; ;; Use xtrs emulator traps to copy a file from TRS-80 to Unix ;; Usage: EXPORT [-lne] fromfile [unixfile] ;; Parameter -l will convert the Unix file to lower case. ;; (Needed for NEWDOS/80. They insist on uppercasing the command line.) ;; If the -n parameter is given, each carriage return ('\r') ;; in the TRS-80 file is converted to a newline ('\n') in the Unix file. ;; The program tries to determine what DOS it is running on and use ;; the correct FCB end of file convention, but this works only on ;; TRSDOS, LDOS, and NEWDOS/80. For other DOSes that use the ;; NEWDOS/80 convention (such as DOSPLUS), give the -e paramter. ;; If the unixfile parameter is omitted, the fromfile parameter is used, ;; with '/' changed to '.'. ;; Model I/III addresses @fspec equ 441ch @init equ 4420h @open equ 4424h @close equ 4428h @read equ 4436h @write equ 4439h @error equ 4409h @exit equ 402dh @abort equ 4030h @put equ 001bh dodcb$ equ 401dh ;; Model 4 SVCs @svc equ 40 ; rst address for SVCs ;@svc equ 5 ; older zmac requires 8080-style "rst 5" @fspec6 equ 78 @init6 equ 58 @open6 equ 59 @close6 equ 60 @read6 equ 67 @write6 equ 75 @error6 equ 26 @exit6 equ 22 @abort6 equ 21 @dsply6 equ 10 ;; Model 4 only: file init or open with wrong LRL. Can be ignored. lrlerr equ 42 org 5200h ;; Jump tables for OS independence startj: fspec: call @fspec ret init: call @init ret open: call @open ret close: call @close ret reed: call @read ret write: call @write ret error: call @error ret exit: call @exit ret abort: call @abort ret dsply: call dsply5 ret getern: call getern5 ret endj: ; Model 4 startj6: ld a, @fspec6 rst @svc ret ld a, @init6 rst @svc ret ld a, @open6 rst @svc ret ld a, @close6 rst @svc ret ld a, @read6 rst @svc ret ld a, @write6 rst @svc ret ld a, @error6 rst @svc ret ld a, @exit6 rst @svc ret ld a, @abort6 rst @svc ret ld a, @dsply6 rst @svc ret call getern6 ret ; Nonzero for LDOS ern convention ernldos: db 1 ; Emulator trap instructions, byte-reversed for use in defw: emt_open equ 30edh emt_close equ 31edh emt_read equ 32edh emt_write equ 33edh emt_lseek equ 34edh emt_strerror equ 35edh EO_ACCMODE equ 3q EO_RDONLY equ 0q EO_WRONLY equ 1q EO_RDWR equ 2q EO_CREAT equ 100q EO_EXCL equ 200q EO_TRUNC equ 1000q EO_APPEND equ 2000q export: ld a, (000ah) ; Model 4? cp 40h jr z, not4 push hl ld de, startj ld hl, startj6 ld bc, endj - startj ldir pop hl not4: ld a, (4427h) ; system id for Newdos/80... sub 82h ; ...should be 82h (v2.0) jr z, gotid ld a, (441fh) ; system version number for most other DOSes sub 13h ; TRSDOS 1.3? gotid: ld (ernldos), a flag0: ld a, (hl) ; look for flags cp ' ' jp c, usage ; error if line ends here jr nz, flag1 inc hl jr flag0 flag1: cp '-' jr nz, fromf inc hl ld a, (hl) flag3: or 20h cp 'e' jr nz, flagl sub a ld (ernldos), a jr flag2 flagl: cp 'l' jr nz, flagn ; check for next flag ld a, 1 ld (lflag), a jr flag2 flagn: cp 'n' jp nz, usage ; unknown flag ld a, 1 ld (nflag), a flag2: inc hl ld a, (hl) cp ' ' jr nz, flag3 ; another flag follows inc hl jr flag0 fromf: ld de, dcb ; ready to get LDOS filename from (HL) ld (lfname), hl ; save if needed to default Unix name call fspec jp nz, usage unix0: ld a, (hl) ; scan over Unix filename cp ' ' ; first skip spaces jr c, usetrs ; if no Unix name, use translated TRS name jr nz, unix1 inc hl jr unix0 unix1: ld de, iobuf ; copy Unix filename ld a, ' ' unix2: cp (hl) ldi jr c, unix2 dec de sub a ld (de), a ; NUL terminate Unix name jr gotu usetrs: ld hl, (lfname) ; translate TRS-80 name to Unix ld de, iobuf ut1: ld a, (hl) cp ':' ; drivespec? jr z, utdone ; done if so cp ' '+1 ; end of line? jr c, utdone ; done if so cp '/' ; change '/' to '.' for extension jr nz, notsl ld a, '.' notsl: ld (de), a inc hl inc de jr ut1 utdone: sub a ; NUL-terminate Unix name ld (de), a gotu: ld hl, iobuf ld de, dcb ld b, 0 call open ; open the TRS-80 file pop hl jr z, uname cp lrlerr jr z, uname ld c, a call error jp abort uname: ld hl, iobuf ; path ld a, (lflag) or a call nz, lcconv ; convert filename to lower case ld bc, EO_WRONLY|EO_CREAT|EO_TRUNC ld de, 0666q ; mode defw emt_open ; open the Unix file jr z, opn2ok ; go if OK ld hl, uopner ; error message and exit jp uerror ;; Read opn2ok: call getern ; count down records in bc loop: push de ; save fd ld de, dcb call reed ; read 256 bytes from file pop de jr z, rdok ; got a full 256 bytes cp 28 ; eof? jr z, closit ; yes, OK ld c, a call error ; oops, i/o error jp abort rdok: dec bc ;; Translate push bc ; save record count ld a, (nflag) ; check for NL feature and a jr z, nlfals ld hl, iobuf ld a, 0dh ld bc, 000ah ; b := 0, c := 0ah tloop: cp (hl) jr nz, notlf ld (hl), c notlf: inc hl djnz tloop nlfals: pop bc ; restore record count ;; Write ld a, c or b ; last record? push bc ; save record count ld bc, 0100h ; byte count jr nz, notlst ld b, a ld a, (dcb+8) ld c, a dec c ; EOF offset 0: write 256 bytes inc bc notlst: ld hl, iobuf defw emt_write pop bc jr z, wrok ld hl, uwrer ; write error jr uerror wrok: ld a, c or b jr nz, loop ;; Close closit: defw emt_close ; close Unix file jr z, closok ld hl, uclser ; close error jr uerror closok: ld de, dcb call close ; close the TRS-80 file jr z, cls2ok ld c, a call error ; oops, i/o error jp abort cls2ok: ld hl, 0 ; all is well jp exit ;; Usage message usage: ld hl, usager ; error message and exit call dsply jp abort ;; Unix error, msg in hl, errno in a uerror: push af call dsply pop af ld hl, iobuf ld bc, 256 defw emt_strerror call dsply jp abort ;; Display message in HL. 03h terminate, 0dh newline and terminate. dsply5: ld de, dodcb$ push hl dsply0: ld a, (hl) cp 03h jr z, dsply1 push af call @put pop af inc hl cp 0dh jr nz, dsply0 dsply1: pop hl ret ;; Convert (NUL terminated) string in HL to lower case. lcconv: push hl ld d, h ld e, l lcloop: ld a, (hl) cp 5bh ; use '[' or uparrow as escape jr nz, lconv1 inc hl ld a, (hl) jr lconv2 ; char after esc: don't convert lconv1: sub 'A' cp 26 ld a, (hl) jr nc, lconv2 or 20h ; convert to lower case lconv2: ld (de), a inc hl inc de or a ; NUL terminator? jr nz, lcloop pop hl ret ;; EOF handling differs between TRS-80 DOSes: ;; For TRSDOS 2.3 and LDOS, word (dcb+12) contains the number of ;; 256 byte records in the file, byte (dcb+8) contains the EOF ;; offset in the last record (0=256). ;; For NEWDOS/80 and TRSDOS 1.3, byte (dcb+8) and word (dcb+12) ;; form a 24 bit number containing the relative byte address of EOF. ;; Thus (dcb+12) differs by one if the file length is not a ;; multiple of 256 bytes. DOSPLUS also uses this convention, ;; and NEWDOS 2.1 probably does too (not checked). ; Returns number of (partial or full) records in BC, destroys A getern5: ld bc, (dcb+12) ld a, (ernldos) ; get ERN convention and a ret nz ; done if TRSDOS 2.3/LDOS convention ld a, (dcb+8) ; length multiple of 256 bytes? and a ret z ; done if so inc bc ; no, # of records = last full record + 1 ret ; All Model 4 mode operating systems should be TRSDOS/LS-DOS 6.x compatible getern6: ld bc, (dcb+12) ret lflag: defb 0 nflag: defb 0 lfname: defw 0 usager: defb 'Usage: EXPORT [-lne] fromfile [unixfile]', 0dh uopner: defb 'Error in Unix open: ', 03h uwrer: defb 'Error in Unix write: ', 03h uclser: defb 'Error in Unix close: ', 03h dcb: defs 48 ; 48 for Model III TRSDOS 1.3 iobuf: defs 256 end export xtrs-4.9d/fakerom.hex000066400000000000000000000006501306603614600146720ustar00rootroot00000000000000:10000000F321370011C03D013000EDB03E05ED3C5D :100010003E3085FE35281632F03DFE34280218FEAB :1000200021670011003E012B00EDB018FE21F03DCC :10003000363423365018FE596F7520646F206E6F6A :10004000742068617665206120524F4D20696D6192 :10005000676520696E7374616C6C656420666F728D :10006000204D6F64656C20284D6F64656C203420D2 :100070006D6F6465207265717569726573206120AA :100080004D6F64656C203320524F4D20696D616760 :020090006529E0 :00000001FF xtrs-4.9d/fakerom.lst000066400000000000000000000037631306603614600147200ustar00rootroot00000000000000 1: ; 2: ; Fake ROM for xtrs, initial hack 3: ; $Id: fakerom.z80,v 1.2 2008/06/26 04:39:56 mann Exp $ 4: ; 5: 6: 3DC0 video equ 3c00h+7*64 7: 8: 0000 org 0 9: 0000 F3 start: di 10: 0001 213700 ld hl,fakemsg 11: 0004 11C03D ld de,video 12: 0007 013000 ld bc,fmend-fakemsg 13: 000A EDB0 ldir 14: 000C 3E05 ld a,5 ;query model 15: 000E ED3C defw 3cedh ;emt_misc 16: 0010 3E30 ld a,'0' 17: 0012 85 add a,l 18: 0013 FE35 cp '5' 19: 0015 2816 jr z,mod4p 20: 0017 32F03D ld (model-fakemsg+video),a 21: 001A FE34 cp '4' 22: 001C 2802 jr z,mod4 23: 001E 18FE jr $ 24: 25: 0020 216700 mod4: ld hl,m4msg 26: 0023 11003E ld de,video+64 27: 0026 012B00 ld bc,m4end-m4msg 28: 0029 EDB0 ldir 29: 002B 18FE jr $ 30: 31: 002D 21F03D mod4p: ld hl,model-fakemsg+video 32: 0030 3634 ld (hl),'4' 33: 0032 23 inc hl 34: 0033 3650 ld (hl),'P' 35: 0035 18FE jr $ 36: 37: 0037 596F7520 fakemsg:defb 'You do not have a ROM image installed for Model ' 646F206E 6F742068 61766520 6120524F 4D20696D 61676520 696E7374 616C6C65 6420666F 72204D6F 64656C20 38: 0067 model equ $ 39: 0067 fmend equ $ 40: 0067 284D6F64 m4msg: defb '(Model 4 mode requires a Model 3 ROM image)' 656C2034 206D6F64 65207265 71756972 65732061 204D6F64 656C2033 20524F4D 20696D61 676529 41: 0092 m4end equ $ 42: 43: 0000 end start Statistics: 9 symbols 146 bytes Symbol Table: fakemsg 37 mod4 20 video =3dc0 fmend = 67 mod4p 2d m4end = 92 model = 67 m4msg 67 start 0 xtrs-4.9d/fakerom.z80000066400000000000000000000011751306603614600145320ustar00rootroot00000000000000; ; Fake ROM for xtrs, initial hack ; $Id: fakerom.z80,v 1.2 2008/06/26 04:39:56 mann Exp $ ; video equ 3c00h+7*64 org 0 start: di ld hl,fakemsg ld de,video ld bc,fmend-fakemsg ldir ld a,5 ;query model defw 3cedh ;emt_misc ld a,'0' add a,l cp '5' jr z,mod4p ld (model-fakemsg+video),a cp '4' jr z,mod4 jr $ mod4: ld hl,m4msg ld de,video+64 ld bc,m4end-m4msg ldir jr $ mod4p: ld hl,model-fakemsg+video ld (hl),'4' inc hl ld (hl),'P' jr $ fakemsg:defb 'You do not have a ROM image installed for Model ' model equ $ fmend equ $ m4msg: defb '(Model 4 mode requires a Model 3 ROM image)' m4end equ $ end start xtrs-4.9d/hex2cmd.c000066400000000000000000000021301306603614600142310ustar00rootroot00000000000000/* Convert Intel Hex format to TRS-80 CMD format */ /* Copyright (c) 1996, Timothy Mann */ /* $Id: hex2cmd.c,v 1.6 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ #include #include #include #include "cmd.h" #include "z80.h" char *program_name; /* Called by load_hex */ void hex_data(int address, int value) { cmd_data(address, value); } void hex_transfer_address(int address) { cmd_transfer_address(address); } int main(int argc, char *argv[]) { FILE *f; program_name = argv[0]; cmd_init(stdout); if (argc == 1) { f = stdin; } else if (argc == 2) { f = fopen(argv[1], "r"); if (f == NULL) { perror(argv[1]); exit(1); } } else { fprintf(stderr, "Usage: %s [<] file.hex > file.cmd\n", program_name); exit(2); } load_hex(f); cmd_end_of_file(); return 0; } xtrs-4.9d/hex2cmd.man000066400000000000000000000015251306603614600145710ustar00rootroot00000000000000.TH hex2cmd 1 .SH Name hex2cmd \- convert Intel hex format to TRS-80 CMD format .SH Syntax \fBhex2cmd\fP \fI[infile]\fP .SH Description .B hex2cmd reads the specified \fIinfile\fP (or standard input if none is given) in Intel hex format (also known as S-record format), and writes a TRS-80 CMD file to standard output. An S-record that asks for 0 bytes to be loaded at address A sets the transfer address (entry point) of the CMD file to A; otherwise the CMD file is given no transfer address. .SH Author .B hex2cmd was written by Timothy Mann. This man page was created by Branden Robinson. .SH See also .IR xtrs (1) .PP See the LDOS Quarterly, April 1, 1982 (Vol 1, No 4), for documentation of the TRS-80 DOS /cmd file format. It is available on the Web at http://www.tim-mann.org/misosys.html. $Id: hex2cmd.man,v 1.2 2008/06/26 04:39:56 mann Exp $ xtrs-4.9d/hex2cmd.txt000066400000000000000000000020571306603614600146360ustar00rootroot00000000000000hex2cmd(1) hex2cmd(1) Name hex2cmd - convert Intel hex format to TRS-80 CMD format Syntax hex2cmd [infile] Description hex2cmd reads the specified infile (or standard input if none is given) in Intel hex format (also known as S-record format), and writes a TRS-80 CMD file to standard output. An S-record that asks for 0 bytes to be loaded at address A sets the transfer address (entry point) of the CMD file to A; otherwise the CMD file is given no transfer address. Author hex2cmd was written by Timothy Mann. This man page was created by Branden Robinson. See also xtrs(1) See the LDOS Quarterly, April 1, 1982 (Vol 1, No 4), for documentation of the TRS-80 DOS /cmd file format. It is available on the Web at http://www.tim-mann.org/misosys.html. $Id: hex2cmd.man,v 1.2 2008/06/26 04:39:56 mann Exp $ hex2cmd(1) xtrs-4.9d/import.cmd000066400000000000000000000011541306603614600145370ustar00rootroot00000000000000RÍDÉÍ DÉÍ$DÉÍ(DÉÍ6DÉÍ9DÉÍ DÉÍ-@ÉÍ0@ÉÍ©SÉÍÛSÉ>NïÉ>:ïÉ>;ïÉ><ïÉ>CïÉ>KïÉ>ïÉ>ïÉ>ïÉ> ïÉÍìSÉ: þ@( åR!,R,í°á:'DÖ‚(:DÖ2XR~þ ÚS #õþ- +#~ö þe —2XRþl >2óS þn l>2ôS#~þ Ú#ÆŒT> ¾í 8û>(++~þ. 6/þ/(þ ð#\TÍR 4!ŒT:óS·Ä¾Sí0(!TÖSÕ!ŒT\STÍRÑ(þ*(OÍRà R!õSÍ$Rà R!ŒT í2(!1TjÕ:ôS§(!ŒTÅ>  ¾ r# øöÁÅ!ŒT\Ty§("_TÍR(OÍRà R$îÁÑy§ ¸ ¬í1(!FTy2dTÍ(R\TÍ R(OÍRà R!ÃRõÍ$Rñ!ŒTí5Í$Rà R@å~þ( õÍñ#þ ñáÉåT]~þ[ #~ ÖAþ~0ö #· èáÉ*fT:XR· ±(+"hTÉ*fT"hTÉUsage: IMPO^TRT [-lne] unixfile [tofile] Error in Unix open: Error in Unix read: Error in Unix close: YRxtrs-4.9d/import.lst000066400000000000000000000451061306603614600146030ustar00rootroot00000000000000 1: ;; import.z80 2: ;; Timothy Mann, 8/24/97 3: ;; $Id: import.z80,v 1.16 2008/06/26 04:39:56 mann Exp $ 4: ;; 5: ;; Copyright (c) 1997, Timothy Mann 6: ;; 7: ;; This software may be copied, modified, and used for any 8: ;; purpose without fee, provided that (1) the above copyright 9: ;; notice is retained, and (2) modified versions are clearly 10: ;; marked as having been modified, with the modifier's name and 11: ;; the date included. 12: ;; 13: ;; Use xtrs emulator traps to copy a file from Unix to TRS-80 14: ;; Usage: IMPORT [-lne] unixfile [tofile] 15: ;; Parameter -l will convert the Unix file to lower case. 16: ;; (Needed for NEWDOS/80. They insist on uppercasing the 17: ;; command line.) 18: ;; If the -n parameter is given, each newline ('\n') in the Unix 19: ;; file is converted to a carriage return ('\r'), the TRS-80 end of 20: ;; line character. 21: ;; The program tries to determine what DOS it is running on and use 22: ;; the correct FCB end of file convention, but this works only on 23: ;; TRSDOS, LDOS, and NEWDOS/80. For other DOSes that use the 24: ;; NEWDOS/80 convention (such as DOSPLUS), give the -e paramter. 25: ;; If the tofile parameter is omitted, the last component of the 26: ;; Unix pathname is used, with '.' changed to '/'. If this is 27: ;; not a legal TRS-80 filename, you get an error message. 28: 29: ;; Model I/III addresses 30: 441C @fspec equ 441ch 31: 4420 @init equ 4420h 32: 4424 @open equ 4424h 33: 4428 @close equ 4428h 34: 4436 @read equ 4436h 35: 4439 @write equ 4439h 36: 4409 @error equ 4409h 37: 402D @exit equ 402dh 38: 4030 @abort equ 4030h 39: 001B @put equ 001bh 40: 401D dodcb$ equ 401dh 41: 42: ;; Model 4 SVCs 43: 0028 @svc equ 40 ; rst address for SVCs 44: ;@svc equ 5 ; older zmac requires 8080-style "rst 5" 45: 004E @fspec6 equ 78 46: 003A @init6 equ 58 47: 003B @open6 equ 59 48: 003C @close6 equ 60 49: 0043 @read6 equ 67 50: 004B @write6 equ 75 51: 001A @error6 equ 26 52: 0016 @exit6 equ 22 53: 0015 @abort6 equ 21 54: 000A @dsply6 equ 10 55: 56: ;; Model 4 only: file init or open with wrong LRL. Can be ignored. 57: 002A lrlerr equ 42 58: 59: 5200 org 5200h 60: 61: ;; Jump tables for OS independence 62: 5200 startj: 63: 5200 CD1C44 fspec: call @fspec 64: 5203 C9 ret 65: 5204 CD2044 init: call @init 66: 5207 C9 ret 67: 5208 CD2444 open: call @open 68: 520B C9 ret 69: 520C CD2844 close: call @close 70: 520F C9 ret 71: 5210 CD3644 reed: call @read 72: 5213 C9 ret 73: 5214 CD3944 write: call @write 74: 5217 C9 ret 75: 5218 CD0944 error: call @error 76: 521B C9 ret 77: 521C CD2D40 exit: call @exit 78: 521F C9 ret 79: 5220 CD3040 abort: call @abort 80: 5223 C9 ret 81: 5224 CDA953 dsply: call dsply5 82: 5227 C9 ret 83: 5228 CDDB53 setern: call setern5 84: 522B C9 ret 85: 522C endj: 86: 87: ; Model 4 88: 522C startj6: 89: 522C 3E4E ld a, @fspec6 90: 522E EF rst @svc 91: 522F C9 ret 92: 5230 3E3A ld a, @init6 93: 5232 EF rst @svc 94: 5233 C9 ret 95: 5234 3E3B ld a, @open6 96: 5236 EF rst @svc 97: 5237 C9 ret 98: 5238 3E3C ld a, @close6 99: 523A EF rst @svc 100: 523B C9 ret 101: 523C 3E43 ld a, @read6 102: 523E EF rst @svc 103: 523F C9 ret 104: 5240 3E4B ld a, @write6 105: 5242 EF rst @svc 106: 5243 C9 ret 107: 5244 3E1A ld a, @error6 108: 5246 EF rst @svc 109: 5247 C9 ret 110: 5248 3E16 ld a, @exit6 111: 524A EF rst @svc 112: 524B C9 ret 113: 524C 3E15 ld a, @abort6 114: 524E EF rst @svc 115: 524F C9 ret 116: 5250 3E0A ld a, @dsply6 117: 5252 EF rst @svc 118: 5253 C9 ret 119: 5254 CDEC53 call setern6 120: 5257 C9 ret 121: 122: ; Nonzero for LDOS ern convention 123: 5258 01 ernldos: db 1 124: 125: ; Emulator trap instructions, byte-reversed for use in defw: 126: 30ED emt_open equ 30edh 127: 31ED emt_close equ 31edh 128: 32ED emt_read equ 32edh 129: 33ED emt_write equ 33edh 130: 34ED emt_lseek equ 34edh 131: 35ED emt_strerror equ 35edh 132: 133: 0003 EO_ACCMODE equ 3q 134: 0000 EO_RDONLY equ 0q 135: 0001 EO_WRONLY equ 1q 136: 0002 EO_RDWR equ 2q 137: 0040 EO_CREAT equ 100q 138: 0080 EO_EXCL equ 200q 139: 0200 EO_TRUNC equ 1000q 140: 0400 EO_APPEND equ 2000q 141: 142: 2000 iobsize equ 8192 ; must be divisible by 256 143: 144: 5259 import: 145: 5259 3A0A00 ld a, (000ah) ; Model 4? 146: 525C FE40 cp 40h 147: 525E 280D jr z, not4 148: 5260 E5 push hl 149: 5261 110052 ld de, startj 150: 5264 212C52 ld hl, startj6 151: 5267 012C00 ld bc, endj - startj 152: 526A EDB0 ldir 153: 526C E1 pop hl 154: 526D not4: 155: 526D 3A2744 ld a, (4427h) ; system id for Newdos/80... 156: 5270 D682 sub 82h ; ...should be 82h (v2.0) 157: 5272 2805 jr z, gotid 158: 5274 3A1F44 ld a, (441fh) ; system version number for most other DOSes 159: 5277 D613 sub 13h ; TRSDOS 1.3? 160: 5279 325852 gotid: ld (ernldos), a 161: 162: 527C 7E flag0: ld a, (hl) ; look for flags 163: 527D FE20 cp ' ' 164: 527F DA1453 jp c, usage ; error if line ends here 165: 5282 2003 jr nz, flag1 166: 5284 23 inc hl 167: 5285 18F5 jr flag0 168: 5287 FE2D flag1: cp '-' 169: 5289 202B jr nz, unix1 170: 528B 23 inc hl 171: 528C 7E ld a, (hl) 172: 528D F620 flag3: or 20h 173: 528F FE65 cp 'e' 174: 5291 2006 jr nz, flagl 175: 5293 97 sub a 176: 5294 325852 ld (ernldos), a 177: 5297 1814 jr flag2 178: 5299 FE6C flagl: cp 'l' 179: 529B 2007 jr nz, flagn ; check for next flag 180: 529D 3E01 ld a, 1 181: 529F 32F353 ld (lflag), a 182: 52A2 1809 jr flag2 183: 52A4 FE6E flagn: cp 'n' 184: 52A6 206C jr nz, usage ; unknown flag 185: 52A8 3E01 ld a, 1 186: 52AA 32F453 ld (nflag), a 187: 52AD 23 flag2: inc hl 188: 52AE 7E ld a, (hl) 189: 52AF FE20 cp ' ' 190: 52B1 20DA jr nz, flag3 ; another flag follows 191: 52B3 23 inc hl 192: 52B4 18C6 jr flag0 193: 194: 52B6 118C54 unix1: ld de, iobuf ; copy Unix filename 195: 52B9 3E20 ld a, ' ' 196: 52BB BE unix2: cp (hl) 197: 52BC EDA0 ldi 198: 52BE 38FB jr c, unix2 199: 52C0 1B dec de ; NUL terminate Unix name 200: 52C1 3E00 ld a, 0 201: 52C3 12 ld (de), a 202: 52C4 2812 jr z, trs80 ; go if two names given 203: 204: ;; Translate last component of Unix name to TRS-80 name 205: 52C6 2B dec hl ; back up to terminator 206: 52C7 2B unix3: dec hl ; back up to last byte of name 207: 52C8 7E ld a, (hl) 208: 52C9 FE2E cp '.' ; change '.' to '/' 209: 52CB 2002 jr nz, notdot 210: 52CD 362F ld (hl), '/' 211: 52CF FE2F notdot: cp '/' 212: 52D1 2804 jr z, unix4 213: 52D3 FE20 cp ' ' 214: 52D5 20F0 jr nz, unix3 215: 52D7 23 unix4: inc hl ; point to start of modified last component 216: 217: 52D8 115C54 trs80: ld de, dcb ; ready to get TRS-80 filename from (HL) 218: 52DB CD0052 call fspec 219: 52DE 2034 jr nz, usage 220: 52E0 218C54 ld hl, iobuf ; Unix path 221: 52E3 3AF353 ld a, (lflag) 222: 52E6 B7 or a 223: 52E7 C4BE53 call nz, lcconv ; convert path to lower case 224: 52EA 010000 ld bc, EO_RDONLY 225: 52ED 110000 ld de, 0 ; mode (ignored) 226: 52F0 ED30 defw emt_open 227: 52F2 2806 jr z, openok ; go if OK 228: 52F4 211C54 ld hl, uopner ; error message and exit 229: 52F7 C39653 jp uerror 230: 231: 52FA D5 openok: push de ; save fd 232: 52FB 218C54 ld hl, iobuf 233: 52FE 115C54 ld de, dcb 234: 5301 0600 ld b, 0 235: 5303 CD0452 call init ; open the file 236: 5306 D1 pop de 237: 5307 2814 jr z, opn2ok 238: 5309 FE2A cp lrlerr 239: 530B 2810 jr z, opn2ok 240: 530D 4F ld c, a 241: 530E CD1852 call error 242: 5311 C32052 jp abort 243: 5314 21F553 usage: ld hl, usager ; error message and exit 244: 5317 CD2452 call dsply 245: 531A C32052 jp abort 246: 247: ;; Read 248: 531D rloop: 249: 531D 218C54 opn2ok: ld hl, iobuf ; read a buffer 250: 5320 010020 ld bc, iobsize 251: 5323 ED32 defw emt_read 252: 5325 2805 jr z, readok 253: 5327 213154 ld hl, urder ; read error (!!code in A) 254: 532A 186A jr uerror 255: 532C D5 readok: push de ; save fd 256: 257: ;; Translate 258: 532D 3AF453 ld a, (nflag) ; check for NL feature 259: 5330 A7 and a 260: 5331 2817 jr z, nlfals 261: 5333 218C54 ld hl, iobuf 262: 5336 C5 push bc ; save byte count 263: 5337 3E0A ld a, 0ah 264: 5339 160D ld d, 0dh 265: 533B 0C inc c ; deal with b=0 and/ c=0 266: 533C 04 inc b 267: 533D 1805 jr tstrt 268: 533F BE tloop: cp (hl) 269: 5340 2001 jr nz, notcr 270: 5342 72 ld (hl), d 271: 5343 23 notcr: inc hl 272: 5344 0D tstrt: dec c 273: 5345 20F8 jr nz, tloop 274: 5347 10F6 djnz tloop 275: 5349 C1 pop bc ; restore byte count 276: 277: ;; Write 278: 534A C5 nlfals: push bc ; save byte count 279: 534B 218C54 ld hl, iobuf 280: 534E 115C54 ld de, dcb 281: 5351 04 inc b ; deal with b=0 and/or c=0 282: 5352 79 ld a, c 283: 5353 A7 and a 284: 5354 2810 jr z, wstrt 285: 5356 225F54 wloop: ld (dcb+3), hl 286: 5359 CD1452 call write ; write 256 bytes to file 287: 535C 2807 jr z, wrok 288: 535E 4F ld c, a 289: 535F CD1852 call error ; oops, i/o error 290: 5362 C32052 jp abort 291: 5365 24 wrok: inc h 292: 5366 10EE wstrt: djnz wloop 293: 5368 C1 pop bc ; restore byte count 294: 295: ;; Done? 296: 5369 D1 pop de ; restore fd 297: 536A 79 ld a, c 298: 536B A7 and a 299: 536C 2003 jr nz, closit ; done for sure 300: 536E B8 cp b 301: 536F 20AC jr nz, rloop ; maybe not done (sloppy) 302: 303: 5371 ED31 closit: defw emt_close ; close Unix file 304: 5373 2805 jr z, closok 305: 5375 214654 ld hl, uclser ; close error (!!code in A) 306: 5378 181C jr uerror 307: 537A 79 closok: ld a, c 308: 537B 326454 ld (dcb+8), a ; set EOF offset 309: 537E CD2852 call setern ; set ERN (in case shortening file) 310: 5381 115C54 ld de, dcb 311: 5384 CD0C52 call close ; close the TRS-80 file 312: 5387 2807 jr z, cls2ok 313: 5389 4F ld c, a 314: 538A CD1852 call error ; oops, i/o error 315: 538D C32052 jp abort 316: 5390 210000 cls2ok: ld hl, 0 ; all is well 317: 5393 C31C52 jp exit 318: 319: ;; Unix error, msg in hl, errno in a 320: 5396 F5 uerror: push af 321: 5397 CD2452 call dsply 322: 539A F1 pop af 323: 539B 218C54 ld hl, iobuf 324: 539E 010001 ld bc, 256 325: 53A1 ED35 defw emt_strerror 326: 53A3 CD2452 call dsply 327: 53A6 C32052 jp abort 328: 329: ;; Display message in HL. 03h terminate, 0dh newline and terminate. 330: 53A9 111D40 dsply5: ld de, dodcb$ 331: 53AC E5 push hl 332: 53AD 7E dsply0: ld a, (hl) 333: 53AE FE03 cp 03h 334: 53B0 280A jr z, dsply1 335: 53B2 F5 push af 336: 53B3 CD1B00 call @put 337: 53B6 F1 pop af 338: 53B7 23 inc hl 339: 53B8 FE0D cp 0dh 340: 53BA 20F1 jr nz, dsply0 341: 53BC E1 dsply1: pop hl 342: 53BD C9 ret 343: 344: ;; Convert (NUL terminated) string in HL to lower case. 345: 53BE E5 lcconv: push hl 346: 53BF 54 ld d, h 347: 53C0 5D ld e, l 348: 53C1 7E lcloop: ld a, (hl) 349: 53C2 FE5B cp 5bh ; use '[' or uparrow as escape 350: 53C4 2004 jr nz, lconv1 351: 53C6 23 inc hl 352: 53C7 7E ld a, (hl) 353: 53C8 1809 jr lconv2 ; char after esc: don't convert 354: 53CA D641 lconv1: sub 'A' 355: 53CC FE1A cp 26 356: 53CE 7E ld a, (hl) 357: 53CF 3002 jr nc, lconv2 358: 53D1 F620 or 20h ; convert to lower case 359: 53D3 12 lconv2: ld (de), a 360: 53D4 23 inc hl 361: 53D5 13 inc de 362: 53D6 B7 or a ; NUL terminator? 363: 53D7 20E8 jr nz, lcloop 364: 53D9 E1 pop hl 365: 53DA C9 ret 366: 367: ;; EOF handling differs between TRS-80 DOSes: 368: ;; For TRSDOS 2.3 and LDOS, word (dcb+12) contains the number of 369: ;; 256 byte records in the file, byte (dcb+8) contains the EOF 370: ;; offset in the last record (0=256). 371: ;; For NEWDOS/80 and TRSDOS 1.3, byte (dcb+8) and word (dcb+12) 372: ;; form a 24 bit number containing the relative byte address of EOF. 373: ;; Thus (dcb+12) differs by one if the file length is not a 374: ;; multiple of 256 bytes. DOSPLUS also uses this convention, 375: ;; and NEWDOS 2.1 probably does too (not checked). 376: 377: ; Set ending record number of file to current position 378: ; EOF offset in C; destroys A, HL 379: 53DB setern5: 380: 53DB 2A6654 ld hl, (dcb+10) ; current record number 381: 53DE 3A5852 ld a, (ernldos) ; get ERN convention 382: 53E1 B7 or a 383: 53E2 2004 jr nz, noadj ; go if TRSDOS 2.3/LDOS convention 384: 53E4 B1 adj: or c ; length multiple of 256 bytes? 385: 53E5 2801 jr z, noadj ; go if so 386: 53E7 2B dec hl ; no, # of records - 1 387: 53E8 226854 noadj: ld (dcb+12), hl 388: 53EB C9 ret 389: 390: ; All Model 4 mode operating systems should be TRSDOS/LS-DOS 6.x compatible 391: 53EC setern6: 392: 53EC 2A6654 ld hl, (dcb+10) 393: 53EF 226854 ld (dcb+12), hl 394: 53F2 C9 ret 395: 396: 53F3 00 lflag: defb 0 397: 53F4 00 nflag: defb 0 398: 399: 53F5 55736167 usager: defb 'Usage: IMPORT [-lne] unixfile [tofile]', 0dh 653A2049 4D504F52 54205B2D 6C6E655D 20756E69 7866696C 65205B74 6F66696C 655D0D 400: 541C 4572726F uopner: defb 'Error in Unix open: ', 03h 7220696E 20556E69 78206F70 656E3A20 03 401: 5431 4572726F urder: defb 'Error in Unix read: ', 03h 7220696E 20556E69 78207265 61643A20 03 402: 5446 4572726F uclser: defb 'Error in Unix close: ', 03h 7220696E 20556E69 7820636C 6F73653A 2003 403: 404: 545C dcb: defs 48 ; 48 for Model III TRSDOS 1.3 405: 548C iobuf: defs iobsize 406: 407: 5259 end import Statistics: 103 symbols 604 bytes Symbol Table: @abort =4030 emt_open =30ed nlfals 534a @abort6 = 15 emt_read =32ed noadj 53e8 @close =4428 emt_strerror =35ed not4 526d @close6 = 3c emt_write =33ed+ notcr 5343 @dsply6 = a endj 522c notdot 52cf @error =4409 eo_accmode = 3+ open 5208+ @error6 = 1a eo_append = 400+ openok 52fa @exit =402d eo_creat = 40+ opn2ok 531d @exit6 = 16 eo_excl = 80+ readok 532c @fspec =441c eo_rdonly = 0 reed 5210+ @fspec6 = 4e eo_rdwr = 2+ rloop 531d @init =4420 eo_trunc = 200+ setern 5228 @init6 = 3a eo_wronly = 1+ setern5 53db @open =4424 ernldos 5258 setern6 53ec @open6 = 3b error 5218 startj 5200 @put = 1b exit 521c startj6 522c @read =4436 flag0 527c tloop 533f @read6 = 43 flag1 5287 trs80 52d8 @svc = 28 flag2 52ad tstrt 5344 @write =4439 flag3 528d uclser 5446 @write6 = 4b flagl 5299 uerror 5396 abort 5220 flagn 52a4 unix1 52b6 adj 53e4+ fspec 5200 unix2 52bb close 520c gotid 5279 unix3 52c7 closit 5371 import 5259 unix4 52d7 closok 537a init 5204 uopner 541c cls2ok 5390 iobsize =2000 urder 5431 dcb 545c iobuf 548c usage 5314 dodcb =401d lcconv 53be usager 53f5 dsply 5224 lcloop 53c1 wloop 5356 dsply0 53ad lconv1 53ca write 5214 dsply1 53bc lconv2 53d3 wrok 5365 dsply5 53a9 lflag 53f3 wstrt 5366 emt_close =31ed lrlerr = 2a emt_lseek =34ed+ nflag 53f4 xtrs-4.9d/import.z80000066400000000000000000000205431306603614600144200ustar00rootroot00000000000000;; import.z80 ;; Timothy Mann, 8/24/97 ;; $Id: import.z80,v 1.16 2008/06/26 04:39:56 mann Exp $ ;; ;; Copyright (c) 1997, Timothy Mann ;; ;; This software may be copied, modified, and used for any ;; purpose without fee, provided that (1) the above copyright ;; notice is retained, and (2) modified versions are clearly ;; marked as having been modified, with the modifier's name and ;; the date included. ;; ;; Use xtrs emulator traps to copy a file from Unix to TRS-80 ;; Usage: IMPORT [-lne] unixfile [tofile] ;; Parameter -l will convert the Unix file to lower case. ;; (Needed for NEWDOS/80. They insist on uppercasing the ;; command line.) ;; If the -n parameter is given, each newline ('\n') in the Unix ;; file is converted to a carriage return ('\r'), the TRS-80 end of ;; line character. ;; The program tries to determine what DOS it is running on and use ;; the correct FCB end of file convention, but this works only on ;; TRSDOS, LDOS, and NEWDOS/80. For other DOSes that use the ;; NEWDOS/80 convention (such as DOSPLUS), give the -e paramter. ;; If the tofile parameter is omitted, the last component of the ;; Unix pathname is used, with '.' changed to '/'. If this is ;; not a legal TRS-80 filename, you get an error message. ;; Model I/III addresses @fspec equ 441ch @init equ 4420h @open equ 4424h @close equ 4428h @read equ 4436h @write equ 4439h @error equ 4409h @exit equ 402dh @abort equ 4030h @put equ 001bh dodcb$ equ 401dh ;; Model 4 SVCs @svc equ 40 ; rst address for SVCs ;@svc equ 5 ; older zmac requires 8080-style "rst 5" @fspec6 equ 78 @init6 equ 58 @open6 equ 59 @close6 equ 60 @read6 equ 67 @write6 equ 75 @error6 equ 26 @exit6 equ 22 @abort6 equ 21 @dsply6 equ 10 ;; Model 4 only: file init or open with wrong LRL. Can be ignored. lrlerr equ 42 org 5200h ;; Jump tables for OS independence startj: fspec: call @fspec ret init: call @init ret open: call @open ret close: call @close ret reed: call @read ret write: call @write ret error: call @error ret exit: call @exit ret abort: call @abort ret dsply: call dsply5 ret setern: call setern5 ret endj: ; Model 4 startj6: ld a, @fspec6 rst @svc ret ld a, @init6 rst @svc ret ld a, @open6 rst @svc ret ld a, @close6 rst @svc ret ld a, @read6 rst @svc ret ld a, @write6 rst @svc ret ld a, @error6 rst @svc ret ld a, @exit6 rst @svc ret ld a, @abort6 rst @svc ret ld a, @dsply6 rst @svc ret call setern6 ret ; Nonzero for LDOS ern convention ernldos: db 1 ; Emulator trap instructions, byte-reversed for use in defw: emt_open equ 30edh emt_close equ 31edh emt_read equ 32edh emt_write equ 33edh emt_lseek equ 34edh emt_strerror equ 35edh EO_ACCMODE equ 3q EO_RDONLY equ 0q EO_WRONLY equ 1q EO_RDWR equ 2q EO_CREAT equ 100q EO_EXCL equ 200q EO_TRUNC equ 1000q EO_APPEND equ 2000q iobsize equ 8192 ; must be divisible by 256 import: ld a, (000ah) ; Model 4? cp 40h jr z, not4 push hl ld de, startj ld hl, startj6 ld bc, endj - startj ldir pop hl not4: ld a, (4427h) ; system id for Newdos/80... sub 82h ; ...should be 82h (v2.0) jr z, gotid ld a, (441fh) ; system version number for most other DOSes sub 13h ; TRSDOS 1.3? gotid: ld (ernldos), a flag0: ld a, (hl) ; look for flags cp ' ' jp c, usage ; error if line ends here jr nz, flag1 inc hl jr flag0 flag1: cp '-' jr nz, unix1 inc hl ld a, (hl) flag3: or 20h cp 'e' jr nz, flagl sub a ld (ernldos), a jr flag2 flagl: cp 'l' jr nz, flagn ; check for next flag ld a, 1 ld (lflag), a jr flag2 flagn: cp 'n' jr nz, usage ; unknown flag ld a, 1 ld (nflag), a flag2: inc hl ld a, (hl) cp ' ' jr nz, flag3 ; another flag follows inc hl jr flag0 unix1: ld de, iobuf ; copy Unix filename ld a, ' ' unix2: cp (hl) ldi jr c, unix2 dec de ; NUL terminate Unix name ld a, 0 ld (de), a jr z, trs80 ; go if two names given ;; Translate last component of Unix name to TRS-80 name dec hl ; back up to terminator unix3: dec hl ; back up to last byte of name ld a, (hl) cp '.' ; change '.' to '/' jr nz, notdot ld (hl), '/' notdot: cp '/' jr z, unix4 cp ' ' jr nz, unix3 unix4: inc hl ; point to start of modified last component trs80: ld de, dcb ; ready to get TRS-80 filename from (HL) call fspec jr nz, usage ld hl, iobuf ; Unix path ld a, (lflag) or a call nz, lcconv ; convert path to lower case ld bc, EO_RDONLY ld de, 0 ; mode (ignored) defw emt_open jr z, openok ; go if OK ld hl, uopner ; error message and exit jp uerror openok: push de ; save fd ld hl, iobuf ld de, dcb ld b, 0 call init ; open the file pop de jr z, opn2ok cp lrlerr jr z, opn2ok ld c, a call error jp abort usage: ld hl, usager ; error message and exit call dsply jp abort ;; Read rloop: opn2ok: ld hl, iobuf ; read a buffer ld bc, iobsize defw emt_read jr z, readok ld hl, urder ; read error (!!code in A) jr uerror readok: push de ; save fd ;; Translate ld a, (nflag) ; check for NL feature and a jr z, nlfals ld hl, iobuf push bc ; save byte count ld a, 0ah ld d, 0dh inc c ; deal with b=0 and/ c=0 inc b jr tstrt tloop: cp (hl) jr nz, notcr ld (hl), d notcr: inc hl tstrt: dec c jr nz, tloop djnz tloop pop bc ; restore byte count ;; Write nlfals: push bc ; save byte count ld hl, iobuf ld de, dcb inc b ; deal with b=0 and/or c=0 ld a, c and a jr z, wstrt wloop: ld (dcb+3), hl call write ; write 256 bytes to file jr z, wrok ld c, a call error ; oops, i/o error jp abort wrok: inc h wstrt: djnz wloop pop bc ; restore byte count ;; Done? pop de ; restore fd ld a, c and a jr nz, closit ; done for sure cp b jr nz, rloop ; maybe not done (sloppy) closit: defw emt_close ; close Unix file jr z, closok ld hl, uclser ; close error (!!code in A) jr uerror closok: ld a, c ld (dcb+8), a ; set EOF offset call setern ; set ERN (in case shortening file) ld de, dcb call close ; close the TRS-80 file jr z, cls2ok ld c, a call error ; oops, i/o error jp abort cls2ok: ld hl, 0 ; all is well jp exit ;; Unix error, msg in hl, errno in a uerror: push af call dsply pop af ld hl, iobuf ld bc, 256 defw emt_strerror call dsply jp abort ;; Display message in HL. 03h terminate, 0dh newline and terminate. dsply5: ld de, dodcb$ push hl dsply0: ld a, (hl) cp 03h jr z, dsply1 push af call @put pop af inc hl cp 0dh jr nz, dsply0 dsply1: pop hl ret ;; Convert (NUL terminated) string in HL to lower case. lcconv: push hl ld d, h ld e, l lcloop: ld a, (hl) cp 5bh ; use '[' or uparrow as escape jr nz, lconv1 inc hl ld a, (hl) jr lconv2 ; char after esc: don't convert lconv1: sub 'A' cp 26 ld a, (hl) jr nc, lconv2 or 20h ; convert to lower case lconv2: ld (de), a inc hl inc de or a ; NUL terminator? jr nz, lcloop pop hl ret ;; EOF handling differs between TRS-80 DOSes: ;; For TRSDOS 2.3 and LDOS, word (dcb+12) contains the number of ;; 256 byte records in the file, byte (dcb+8) contains the EOF ;; offset in the last record (0=256). ;; For NEWDOS/80 and TRSDOS 1.3, byte (dcb+8) and word (dcb+12) ;; form a 24 bit number containing the relative byte address of EOF. ;; Thus (dcb+12) differs by one if the file length is not a ;; multiple of 256 bytes. DOSPLUS also uses this convention, ;; and NEWDOS 2.1 probably does too (not checked). ; Set ending record number of file to current position ; EOF offset in C; destroys A, HL setern5: ld hl, (dcb+10) ; current record number ld a, (ernldos) ; get ERN convention or a jr nz, noadj ; go if TRSDOS 2.3/LDOS convention adj: or c ; length multiple of 256 bytes? jr z, noadj ; go if so dec hl ; no, # of records - 1 noadj: ld (dcb+12), hl ret ; All Model 4 mode operating systems should be TRSDOS/LS-DOS 6.x compatible setern6: ld hl, (dcb+10) ld (dcb+12), hl ret lflag: defb 0 nflag: defb 0 usager: defb 'Usage: IMPORT [-lne] unixfile [tofile]', 0dh uopner: defb 'Error in Unix open: ', 03h urder: defb 'Error in Unix read: ', 03h uclser: defb 'Error in Unix close: ', 03h dcb: defs 48 ; 48 for Model III TRSDOS 1.3 iobuf: defs iobsize end import xtrs-4.9d/load_cmd.c000066400000000000000000000175651306603614600144630ustar00rootroot00000000000000/* Copyright (c) 1996-98, Timothy Mann */ /* $Id: load_cmd.c,v 1.4 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* TRS-80 DOS /cmd file loader. * * See the LDOS Quarterly, April 1, 1982 (Vol 1, No 4), for documentation * of the TRS-80 DOS /cmd file format. */ #include #include #include "load_cmd.h" int load_cmd(FILE* f, unsigned char memory[1<<16], unsigned char* loadmap, int verbosity, FILE* outf, int isam, char* pds, int* xferaddr, int stopxfer) { int lastaddr = -1, lastcount = -1; int c, a1, a2, a3, v, count, dummy, i; int pflags1, pflags2; char pentry[9]; int ientry, iaddr, iseek, ilen; int status = LOAD_CMD_OK; unsigned short addr; /* wrap at 2**16 */ if (loadmap) { memset(loadmap, 0, 1<<16); } if (xferaddr) { *xferaddr = -1; } else { xferaddr = &dummy; } for (;;) { c = getc(f); /* get block type code */ if (c != 1 /* not loading bytes into memory */) { if (verbosity >= VERBOSITY_MAP) { if (lastaddr != -1) { fprintf(outf, "loaded 0x%04x - 0x%04x\n", lastaddr, lastaddr + lastcount - 1); } lastaddr = -1; } } if (c == EOF) return status; count = getc(f); if (count == EOF) { if (c == 3) return status; return LOAD_CMD_EOF; } if (count == 0) count = 256; switch (c) { case 0: /* skip (used by Model I TRSDOS BOOT/SYS easter egg) */ if (verbosity >= VERBOSITY_MAP) { fprintf(outf, "skip block, %d bytes\n", count); } while (count-- > 0) { v = getc(f); if (v == EOF) return LOAD_CMD_EOF; } break; case 1: /* load bytes into memory */ a1 = getc(f); if (a1 == EOF) return LOAD_CMD_EOF; a2 = getc(f); if (a2 == EOF) return LOAD_CMD_EOF; addr = a1 + a2 * 256; count -= 2; if (count <= 0) count += 256; if (verbosity >= VERBOSITY_MAP) { if (verbosity >= VERBOSITY_DETAILED || addr != lastaddr + lastcount) { if (lastaddr != -1) { fprintf(outf, "loaded 0x%04x - 0x%04x\n", lastaddr, lastaddr + lastcount - 1); } lastaddr = addr; lastcount = count; } else { lastcount += count; } } while (count-- > 0) { v = getc(f); if (v == EOF) return LOAD_CMD_EOF; /* Don't load PDS front end if specific member requested */ if (!(pds && isam == -1)) { memory[addr] = v; if (loadmap) loadmap[addr]++; } addr++; } break; case 2: /* transfer address and end of file */ if (count != 2) return c; a1 = getc(f); if (a1 == EOF) return LOAD_CMD_EOF; a2 = getc(f); if (a2 == EOF) return LOAD_CMD_EOF; *xferaddr = a1 + a2 * 256; if (verbosity >= VERBOSITY_MAP) { fprintf(outf, "transfer address = 0x%04x\n", *xferaddr); } if (stopxfer) return status; break; case 3: /* end of file with no transfer address */ while (count-- > 0) { v = getc(f); if (v == EOF) return LOAD_CMD_EOF; } return status; case 4: /* end of ISAM/PDS member */ if (verbosity >= VERBOSITY_MAP) { fprintf(outf, "end of ISAM/PDS member\n"); } while (count-- > 0) { v = getc(f); if (v == EOF) return LOAD_CMD_EOF; } if (isam != -1) return status; if (verbosity >= VERBOSITY_MAP) { fprintf(outf, "seek ptr = 0x%06lx\n", ftell(f)); } break; case 5: /* module header */ if (verbosity >= VERBOSITY_TEXT) { fprintf(outf, "module header = \""); while (count-- > 0) { v = getc(f); if (v == EOF) return LOAD_CMD_EOF; putc(v, outf); } fprintf(outf, "\"\n"); } else { while (count-- > 0) { v = getc(f); if (v == EOF) return LOAD_CMD_EOF; } } break; case 6: /* PDS header */ if (verbosity >= VERBOSITY_TEXT) { fprintf(outf, "PDS header = \""); while (count-- > 0) { v = getc(f); if (v == EOF) return LOAD_CMD_EOF; putc(v, outf); } fprintf(outf, "\"\n"); } else { while (count-- > 0) { v = getc(f); if (v == EOF) return LOAD_CMD_EOF; } } break; case 7: /* Patch name header */ if (verbosity >= VERBOSITY_TEXT) { fprintf(outf, "patch name = \""); while (count-- > 0) { v = getc(f); if (v == EOF) return LOAD_CMD_EOF; putc(v, outf); } fprintf(outf, "\"\n"); } else { while (count-- > 0) { v = getc(f); if (v == EOF) return LOAD_CMD_EOF; } } break; case 8: /* ISAM directory entry */ if (status == LOAD_CMD_OK) status = LOAD_CMD_ISAM; if (count == 6 || count == 9) { v = getc(f); if (v == EOF) return LOAD_CMD_EOF; ientry = v; a1 = getc(f); if (a1 == EOF) return LOAD_CMD_EOF; a2 = getc(f); if (a2 == EOF) return LOAD_CMD_EOF; iaddr = a1 + a2 * 256; a1 = getc(f); if (a1 == EOF) return LOAD_CMD_EOF; a2 = getc(f); if (a2 == EOF) return LOAD_CMD_EOF; a3 = getc(f); if (a3 == EOF) return LOAD_CMD_EOF; iseek = (a2 << 16) + (a1 << 8) + a3; } else { return c; } if (count == 9) { /* Is this right? */ a1 = getc(f); if (a1 == EOF) return LOAD_CMD_EOF; a2 = getc(f); if (a2 == EOF) return LOAD_CMD_EOF; a3 = getc(f); if (a3 == EOF) return LOAD_CMD_EOF; ilen = (a2 << 16) + (a1 << 8) + a3; /*???*/ } else { ilen = -1; } if (verbosity >= VERBOSITY_MAP) { fprintf(outf, "ISAM entry 0x%02x, transfer 0x%04x, seek ptr 0x%06x", ientry, iaddr, iseek); if (ilen != -1) { fprintf(outf, ", length 0x%06x\n", ilen); } else { fprintf(outf, "\n"); } } if (ientry == isam) { fseek(f, iseek, 0); *xferaddr = iaddr; } break; case 0x0a: /* end of ISAM directory */ if (verbosity >= VERBOSITY_MAP) { fprintf(outf, "end of ISAM directory\n"); } while (count-- > 0) { v = getc(f); if (v == EOF) return LOAD_CMD_EOF; } if (isam != -1) return LOAD_CMD_NOT_FOUND; break; case 0x0c: /* PDS directory entry */ status = LOAD_CMD_PDS; if (count != 11) { return c; } for (i=0; i<8; i++) { v = getc(f); if (v == EOF) return LOAD_CMD_EOF; pentry[i] = v; } pentry[8] = '\000'; v = getc(f); if (v == EOF) return LOAD_CMD_EOF; ientry = v; v = getc(f); if (v == EOF) return LOAD_CMD_EOF; pflags1 = v; v = getc(f); if (v == EOF) return LOAD_CMD_EOF; pflags2 = v; if (pds && strcmp(pds, pentry) == 0) { isam = ientry; } if (verbosity >= VERBOSITY_MAP) { fprintf(outf, "PDS entry \"%s\", ISAM 0x%02x, flags 0x%02x 0x%02x\n", pentry, ientry, pflags1, pflags2); } break; case 0x0e: /* end of PDS directory */ if (verbosity >= VERBOSITY_MAP) { fprintf(outf, "end of PDS directory\n"); } while (count-- > 0) { v = getc(f); if (v == EOF) return LOAD_CMD_EOF; } if (pds != NULL && isam == -1) return LOAD_CMD_NOT_FOUND; break; case 0x10: /* yanked load block */ a1 = getc(f); if (a1 == EOF) return LOAD_CMD_EOF; a2 = getc(f); if (a2 == EOF) return LOAD_CMD_EOF; addr = a1 + a2 * 256; count -= 2; if (count <= 0) count += 256; if (verbosity >= VERBOSITY_MAP) { fprintf(outf, "yanked load block 0x%04x - 0x%04x\n", addr, addr + count - 1); } while (count-- > 0) { v = getc(f); if (v == EOF) return LOAD_CMD_EOF; } break; case 0x1f: /* copyright block */ if (verbosity >= VERBOSITY_TEXT) { fprintf(outf, "====copyright block====\n"); while (count-- > 0) { v = getc(f); if (v == EOF) return LOAD_CMD_EOF; putc(v, outf); } fprintf(outf, "\n=======================\n"); } else { while (count-- > 0) { v = getc(f); if (v == EOF) return LOAD_CMD_EOF; } } break; default: return c; } } return status; } xtrs-4.9d/load_cmd.h000066400000000000000000000051751306603614600144620ustar00rootroot00000000000000/* Copyright (c) 1996-98, Timothy Mann */ /* $Id: load_cmd.h,v 1.3 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* TRS-80 DOS /cmd file loader */ #define LOAD_CMD_OK 0 #define LOAD_CMD_EOF -1 #define LOAD_CMD_NOT_FOUND -2 #define LOAD_CMD_ISAM -3 #define LOAD_CMD_PDS -4 #define VERBOSITY_QUIET 0 #define VERBOSITY_TEXT 1 #define VERBOSITY_MAP 2 #define VERBOSITY_DETAILED 3 #define ISAM_NONE -1 /* Load the /cmd file f into the given memory, optionally selecting * out an ISAM or PDS member. Return LOAD_CMD_OK for success if f was a * normal /cmd file, LOAD_CMD_ISAM for success if it was an ISAM file, * LOAD_CMD_PDS for success if this was a PDS file, LOAD_CMD_EOF for * failure due to premature end of file, LOAD_CMD_NOT_FOUND for ISAM * or PDF member not found, or a positive number B for an unknown or * badly formatted load block of typecode B (load file format error). * * Optional flags: * * If loadmap is not NULL, it must point to an array of 2**16 * bytes. Each byte in the return value will have a count (mod 256) * of the number of times that memory location was loaded. Usually each * count will be 0 or 1, of course. * * If verbosity is VERBOSITY_QUIET, print nothing. If verbosity is * VERBOSITY_TEXT, print module headers, PDS headers, patch names, and * copyright notices. If verbosity is VERBOSITY_MAP, also print load * map information as we go along, but coalesce adjacent blocks that * load contiguously into memory. If verbosity is VERBOSITY_DETAILED, * don't coalesce. * * If isam is not -1, search for the given isam member number and load * it instead of loading the whole file. * * If pds is not NULL, search for the given pds member name and * load it instead of loading the whole file. isam and pds cannot * both be used. * * If xferaddr is not NULL, return the transfer address there, or if * there is no transfer address, return -1. * * If stopxfer is 1, stop loading when a transfer address is seen; if * 0, continue loading. stopxfer = 0 is needed if you want to parse * a PDS file with a front end loader. stopxfer = 1 is useful to deal * with ordinary /cmd files that have extra garbage at the end, as * sometimes happens. stopxfer = 0 should be considered the default. */ int load_cmd(FILE* f, unsigned char memory[65536], unsigned char* loadmap, int verbosity, FILE* outf, int isam, char* pds, int* xferaddr, int stopxfer); xtrs-4.9d/load_hex.c000066400000000000000000000037321306603614600144730ustar00rootroot00000000000000/* * Copyright (C) 1992 Clarendon Hill Software. * * Permission is granted to any individual or institution to use, copy, * or redistribute this software, provided this copyright notice is retained. * * This software is provided "as is" without any expressed or implied * warranty. If this software brings on any sort of damage -- physical, * monetary, emotional, or brain -- too bad. You've got no one to blame * but yourself. * * The software may be modified for your own purposes, but modified versions * must retain this notice. */ /* Modified by Timothy Mann, 1996 and later $Id: load_hex.c,v 1.8 2008/06/26 04:39:56 mann Exp $ */ #include "z80.h" #include #define BUFFER_SIZE 256 extern void hex_transfer_address(int address); extern void hex_data(int address, int value); static int hex_byte(char *string) { char buf[3]; buf[0] = string[0]; buf[1] = string[1]; buf[2] = '\0'; return(strtol(buf, (char **)NULL, 16)); } int load_hex(FILE *file) { char buffer[BUFFER_SIZE]; char *b; int num_bytes; int address; int check; int value; int high = 0; while(fgets(buffer, BUFFER_SIZE, file)) { if(buffer[0] == ':') { /* colon */ b = buffer + 1; /* number of bytes on the line */ num_bytes = hex_byte(b); b += 2; check = num_bytes; /* the starting address */ address = hex_byte(b) << 8; b += 2; address |= hex_byte(b); b+= 2; check += (address >> 8) + (address & 0xff); /* a zero? */ b += 2; /* the data */ if(num_bytes == 0) { /* Transfer address */ hex_transfer_address(address); } else { while(num_bytes--) { value = hex_byte(b); b += 2; hex_data(address++, value); check += value; } if (address > high) high = address; /* the checksum */ value = hex_byte(b); if(((0x100 - check) & 0xff) != value) { fatal("bad checksum from hex file"); } } } } return high; } xtrs-4.9d/m1format.fix000066400000000000000000000007161306603614600150010ustar00rootroot00000000000000. M1FORMAT/FIX - 01/24/98 - Tim Mann . Patch to Model I LDOS 5.3.1 FORMAT to allow formatting a hard . drive. NOPs out some buggy code that makes it fail. Odd . that this bug is still present; README/TXT suggests it was . fixed. This patch is required to format an emulated hard . drive with XTRSHARD/DCT on an emulated Model I. . . Apply with PATCH FORMAT/CMD.RS0LT0FF USING M1FORMAT . Do not apply to Model III LDOS or Model 4 LS-DOS! . X'630B'=00 00 xtrs-4.9d/main.c000066400000000000000000000060751306603614600136370ustar00rootroot00000000000000/* * Copyright (C) 1992 Clarendon Hill Software. * * Permission is granted to any individual or institution to use, copy, * or redistribute this software, provided this copyright notice is retained. * * This software is provided "as is" without any expressed or implied * warranty. If this software brings on any sort of damage -- physical, * monetary, emotional, or brain -- too bad. You've got no one to blame * but yourself. * * The software may be modified for your own purposes, but modified versions * must retain this notice. */ /* Modified by Timothy Mann, 1996 and later $Id: main.c,v 1.16 2009/06/15 23:33:53 mann Exp $ */ #include #include #include "z80.h" #include "trs.h" #include "trs_disk.h" #include "load_cmd.h" int trs_model = 1; int trs_paused = 1; int trs_autodelay = 0; char *program_name; static void check_endian() { wordregister x; x.byte.low = 1; x.byte.high = 0; if(x.word != 1) { fatal("Program compiled with wrong ENDIAN value -- adjust the Makefile.local, type \"rm *.o\", recompile, and try again."); } } void trs_load_rom(char *filename) { FILE *program; int c; if((program = fopen(filename, "r")) == NULL) { char message[100]; sprintf(message, "could not read %s", filename); fatal(message); } c = getc(program); if (c == ':') { /* Assume Intel hex format */ rewind(program); trs_rom_size = load_hex(program); fclose(program); return; } else if (c == 1 || c == 5) { /* Assume MODELA/III file */ int res; extern Uchar *rom; /*!! fixme*/ Uchar loadmap[Z80_ADDRESS_LIMIT]; rewind(program); res = load_cmd(program, rom, loadmap, 0, NULL, -1, NULL, NULL, 1); if (res == LOAD_CMD_OK) { trs_rom_size = Z80_ADDRESS_LIMIT; while (trs_rom_size > 0) { if (loadmap[--trs_rom_size] != 0) { trs_rom_size++; break; } } fclose(program); return; } else { /* Guess it wasn't one */ rewind(program); c = getc(program); } } trs_rom_size = 0; while (c != EOF) { mem_write_rom(trs_rom_size++, c); c = getc(program); } } void trs_load_compiled_rom(int size, unsigned char rom[]) { int i; trs_rom_size = size; for(i = 0; i < size; ++i) { mem_write_rom(i, rom[i]); } } int main(int argc, char *argv[]) { int debug = FALSE; /* program_name must be set first because the error * printing routines use it. */ program_name = strrchr(argv[0], '/'); if (program_name == NULL) { program_name = argv[0]; } else { program_name++; } check_endian(); argc = trs_parse_command_line(argc, argv, &debug); if (argc > 1) { fprintf(stderr, "%s: erroneous argument %s\n", program_name, argv[1]); exit(1); } mem_init(); trs_screen_init(); trs_timer_init(); trs_reset(1); if (!debug) { /* Run continuously until exit or request to enter debugger */ z80_run(TRUE); } printf("Entering debugger.\n"); debug_init(); debug_shell(); printf("Quitting.\n"); exit(0); } xtrs-4.9d/mkdisk.c000066400000000000000000000220521306603614600141660ustar00rootroot00000000000000/* Copyright (c) 1996-98, Timothy Mann */ /* $Id: mkdisk.c,v 1.12 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* * mkdisk.c * Make a blank (unformatted) emulated floppy or hard drive in a file, * or write protect/unprotect an existing one. */ #include #include #include #include #include #include #include typedef unsigned char Uchar; #include "reed.h" ReedHardHeader rhh; void Usage(char *progname) { fprintf(stderr, "Usage:\t%s -1 file\n" "\t%s [-3] file\n" "\t%s -k [-s sides] [-d density] [-8] [-i] file\n" "\t%s -h [-c cyl] [-s sec] [-g gran] file\n" "\t%s {-p|-u} {-1|-3|-k|-h} file\n", progname, progname, progname, progname, progname); exit(2); } int main(int argc, char *argv[]) { int jv1 = 0, jv3 = 0, dmk = 0, hard = 0; int cyl = -1, sec = -1, gran = -1, dir = -1, eight = 0, ignden = 0; int writeprot = 0, unprot = 0; int i, c, oumask; char *fname; FILE *f; opterr = 0; for (;;) { c = getopt(argc, argv, "13khc:s:g:d:8ipu"); if (c == -1) break; switch (c) { case '1': jv1 = 1; break; case '3': jv3 = 1; break; case 'k': dmk = 1; break; case 'h': hard = 1; break; case 'c': cyl = atoi(optarg); break; case 's': sec = atoi(optarg); break; case 'g': gran = atoi(optarg); break; case 'd': dir = atoi(optarg); break; case '8': eight = 1; break; case 'i': ignden = 1; break; case 'p': writeprot = 1; break; case 'u': unprot = 1; break; case '?': default: Usage(argv[0]); break; } } if (argc - optind != 1) Usage(argv[0]); fname = argv[optind]; if (writeprot || unprot) { /* Completely different functionality here */ struct stat st; int newmode; if (writeprot && unprot) { fprintf(stderr, "%s: -p and -u are mutually exclusive\n", argv[0]); exit(2); } if (jv1 + jv3 + dmk + hard != 1) { fprintf(stderr, "%s: %s requires exactly one of -1, -3, -k, or -h\n", argv[0], writeprot ? "-p" : "-u"); exit(2); } if (stat(fname, &st) < 0) { perror(fname); exit(1); } /* Make writable so we can poke inside if need be */ if (chmod(fname, st.st_mode | (S_IWUSR|S_IWGRP|S_IWOTH)) < 0) { perror(fname); exit(1); } f = fopen(fname, "r+"); if (f == NULL) { perror(fname); exit(1); } /* Poke inside */ if (jv1) { /* No indication inside; nothing to do here */ } else if (jv3) { /* Set the magic byte */ fseek(f, 256*34-1, 0); putc(writeprot ? 0 : 0xff, f); } else if (dmk) { /* Set the magic byte */ putc(writeprot ? 0xff : 0, f); } else if (hard) { /* Set the magic bit */ fseek(f, 7, 0); newmode = getc(f); if (newmode == EOF) { perror(fname); exit(1); } newmode = (newmode & 0x7f) | (writeprot ? 0x80 : 0); fseek(f, 7, 0); putc(newmode, f); } /* Finish by chmoding the file appropriately */ if (writeprot) { newmode = st.st_mode & ~(S_IWUSR|S_IWGRP|S_IWOTH); } else { oumask = umask(0); umask(oumask); newmode = st.st_mode | (( (st.st_mode & (S_IRUSR|S_IRGRP|S_IROTH)) >> 1 ) & ~oumask); } if (fchmod(fileno(f), newmode)) { perror(fname); exit(1); } fclose(f); exit(0); } switch (jv1 + jv3 + dmk + hard) { case 0: jv3 = 1; break; case 1: break; default: fprintf(stderr, "%s: -1, -3, -k, and -h are mutually exclusive\n", argv[0]); exit(2); } if ((jv1 || jv3) && (cyl >= 0 || sec >= 0 || gran >= 0 || dir >= 0)) { fprintf(stderr, "%s: -c, -s, -g, -d are not meaningful with -1 or -3\n", argv[0]); exit(2); } if (dmk && (cyl >= 0 || gran >= 0)) { fprintf(stderr, "%s: -c and -g are not meaningful with -k\n", argv[0]); exit(2); } if (!dmk && (eight || ignden)) { fprintf(stderr, "%s: -8 and -i are only meaningful with -k\n", argv[0]); exit(2); } if (jv1) { /* Unformatted JV1 disk - just an empty file! */ f = fopen(fname, "w"); if (f == NULL) { perror(fname); exit(1); } } else if (jv3) { /* Unformatted JV3 disk. */ f = fopen(fname, "w"); if (f == NULL) { perror(fname); exit(1); } for (i=0; i<(256*34); i++) { putc(0xff, f); } } else if (dmk) { /* Unformatted DMK disk */ /* Reuse flag letters s, d */ #define sides sec #define density dir if (sides == -1) sides = 2; if (density == -1) density = 2; if (sides != 1 && sides != 2) { fprintf(stderr, "%s error: sides must be 1 or 2\n", argv[0]); exit(2); } if (density < 1 || density > 2) { fprintf(stderr, "%s error: density must be 1 or 2\n", argv[0]); exit(2); } f = fopen(fname, "w"); putc(0, f); /* 0: not write protected */ putc(0, f); /* 1: initially zero tracks */ if (eight) { if (density == 1) i = 0x14e0; else i = 0x2940; } else { if (density == 1) i = 0x0cc0; else i = 0x1900; } putc(i & 0xff, f); /* 2: LSB of track length */ putc(i >> 8, f); /* 3: MSB of track length */ i = 0; if (sides == 1) i |= 0x10; if (density == 1) i |= 0x40; if (ignden) i |= 0x80; putc(i, f); /* 4: options */ putc(0, f); /* 5: reserved */ putc(0, f); /* 6: reserved */ putc(0, f); /* 7: reserved */ putc(0, f); /* 8: reserved */ putc(0, f); /* 9: reserved */ putc(0, f); /* a: reserved */ putc(0, f); /* b: reserved */ putc(0, f); /* c: MBZ */ putc(0, f); /* d: MBZ */ putc(0, f); /* e: MBZ */ putc(0, f); /* f: MBZ */ } else /* hard */ { /* Unformatted hard disk */ /* We don't care about most of this header, but we generate it just in case some user wants to exchange hard drives with Matthew Reed's emulator or with Pete Cervasio's port of xtrshard/dct to Jeff Vavasour's Model III/4 emulator. */ time_t tt = time(0); struct tm *lt = localtime(&tt); Uchar *rhhp; int cksum; if (cyl == -1) cyl = 202; if (sec == -1) sec = 256; if (gran == -1) gran = 8; if (dir == -1) dir = 1; if (cyl < 3) { fprintf(stderr, "%s error: cyl < 3\n", argv[0]); exit(2); } if (cyl > 256) { fprintf(stderr, "%s error: cyl > 256\n", argv[0]); exit(2); } if (cyl > 203) { fprintf(stderr, "%s warning: cyl > 203 is incompatible with XTRSHARD/DCT\n", argv[0]); } if (sec < 4) { fprintf(stderr, "%s error: sec < 4\n", argv[0]); exit(2); } if (sec > 256) { fprintf(stderr, "%s error: sec > 256\n", argv[0]); exit(2); } if ((sec % 32) != 0) { fprintf(stderr, "%s warning: %s\n", argv[0], "(sec % 32) != 0 is incompatible with WD1000/1010 emulation"); if (sec > 32) { fprintf(stderr, "%s warning: %s\n", argv[0], "(sec % 32) != 0 and sec > 32 " "is incompatible with Matthew Reed's emulators"); } } if (gran < 1) { fprintf(stderr, "%s error: gran < 1\n", argv[0]); exit(2); } if (gran > 8) { fprintf(stderr, "%s error: gran > 8\n", argv[0]); exit(2); } if (sec < gran) { fprintf(stderr, "%s error: sec < gran\n", argv[0]); exit(2); } if (sec % gran != 0) { fprintf(stderr, "%s error: sec %% gran != 0\n", argv[0]); exit(2); } if (sec / gran > 32) { fprintf(stderr, "%s error: sec / gran > 32\n", argv[0]); exit(2); } if (dir < 1) { fprintf(stderr, "%s error: dir < 1\n", argv[0]); exit(2); } if (dir >= cyl) { fprintf(stderr, "%s error: dir >= cyl\n", argv[0]); exit(2); } rhh.id1 = 0x56; rhh.id2 = 0xcb; rhh.ver = 0x10; rhh.cksum = 0; /* init for cksum computation */ rhh.blks = 1; rhh.mb4 = 4; rhh.media = 0; rhh.flag1 = 0; rhh.flag2 = rhh.flag3 = 0; rhh.crtr = 0x42; rhh.dfmt = 0; rhh.mm = lt->tm_mon + 1; rhh.dd = lt->tm_mday; rhh.yy = lt->tm_year; rhh.dparm = 0; rhh.cyl = cyl; rhh.sec = sec; rhh.gran = gran; rhh.dcyl = dir; strcpy(rhh.label, "xtrshard"); strcpy(rhh.filename, fname); /* note we don't limit to 8 chars */ cksum = 0; rhhp = (Uchar *) &rhh; for (i=0; i<=31; i++) { cksum += rhhp[i]; } rhh.cksum = ((Uchar) cksum) ^ 0x4c; f = fopen(fname, "w"); if (f == NULL) { perror(fname); exit(1); } fwrite(&rhh, sizeof(rhh), 1, f); } fclose(f); return 0; } xtrs-4.9d/mkdisk.man000066400000000000000000000317141306603614600145240ustar00rootroot00000000000000.TH mkdisk 1 .SH Name mkdisk \- Make a blank emulated floppy or hard disk for xtrs, or add/remove an emulated write protect tab .SH Syntax .B mkdisk -1 filename .br .B mkdisk [-3] filename .br .B mkdisk -k [-s sides] [-d density] [-8] [-i] filename .br .B mkdisk -h [-c cyl] [-s sec] [-g gran] filename .br .B mkdisk {-p|-u} {-1|-3|-k|-h} filename .SH Description The mkdisk program is part of the \fBxtrs\fP(1) package. It has two distinct functions: (1) It can make a blank (unformatted) emulated floppy or hard drive in a file. (2) With the -p or -u flag, it can turn the write protect flag on or off for an existing emulated floppy or hard drive file. See the xtrs man page for background information. The conventional file extensions are .dsk for emulated floppies and .hdv for emulated hard drives, but \fBmkdisk\fP does not enforce this convention; you can use any filename. Other extensions sometimes used for emulated floppies are .jv1, .jv3, .8in, and .dmk. .SH Making Emulated Floppies With the -1 flag, \fBmkdisk\fP makes an unformatted emulated floppy of type JV1. No additional flags are accepted. With the -3 flag (which is the default and should normally be used), \fBmkdisk\fP makes an unformatted emulated floppy of type JV3. No additional flags are accepted. With the -k flag, \fBmkdisk\fP makes an unformatted emulated floppy of type DMK. With -k, the optional flags -s, -d, -8, and -i can be used to give the emulated floppy special properties. Specifying -s1 limits the floppy to one side; with -s2 (the default), the floppy can be formatted as either one- or two-sided. Specifying -d1 limits the floppy to single density; with -d2 (the default), the floppy can be formatted in either single or double density. Specifying -8 allows the floppy to be formatted in an emulated 8" drive; by default it will work properly only in an emulated 5" drive. Setting -s1 or -d1 saves space after the floppy is formatted; setting -8 consumes additional space. Specifying -i activates a peculiar feature in some TRS-80 emulators that causes each formatted sector to appear to be both single and double density. .SH Making Emulated Hard Drives With the -h flag, \fBmkdisk\fP makes an unformatted emulated hard drive with \fIcyl\fP cylinders, \fIsec\fP sectors, and \fIgran\fP granules (LDOS allocation units) per cylinder. The hard drive will have cylinder \fIdir\fP marked for use as its directory. You will usually want to use the default values for all these parameters. The default is 202 cylinders, 256 sectors per cylinder (that is, 8 heads and 32 sectors per track), and 8 granules per cylinder. This is the largest hard drive that can be used by all LDOS/LS-DOS operating systems without partitioning the drive or patching the FORMAT command. The details on what nondefault values are possible vary, depending on which of xtrs's two hard drive emulations you are using and which other emulators you want to be compatible with, and it is probably best not to delve into these complexities, but read on if you really want to. For \fIcyl\fP, the number of cylinders on the drive, the default value is 202, the minimum is 3, and the maximum that can be represented in the HDV file's header is 256. You can use 203 cylinders with LDOS and LS-DOS if you format the drive with Model 4 LS-DOS; a minor bug in Model I/III FORMAT/CMD prevents more than 202 cylinders from being formatted, but the system can use 203 thereafter. 203 cylinders is the absolute maximum for LDOS/LS-DOS drivers that do not support partitioning, including the emulator-specific drivers supplied with xtrs (XTRSHARD/DCT), with Matthew Reed's emulator (HARD/CMD), and with David Keil's emulator (EHARD/DCT). In xtrs 4.1 and later, and in David Keil's emulator version 6.0 and later, a true emulation of Radio Shack's WD1010-based hard disk controller is also available, which works with the native drivers for the original hardware, such as RSHARDx/DCT and the hard disk drivers for NEWDOS and CP/M. In xtrs, the WD1010 emulation ignores the maximum number of cylinders specified in the HDV file's header and allows the driver to format up to 65536 cylinders. This may be useful if your drivers support partitioning (but why would anyone want to partition an emulated hard drive instead of just making two smaller ones?), or if your operating system supports more than 203 cylinders per partition. Note that although RSHARDx/DCT allows up to 406 cylinders per partition, if you use more than 203, the maximum number of sectors per cylinder is limited to 128, so you gain nothing; the maximum size of a partition is still the same. For \fIsec\fP, the number of sectors per cylinder, the default value is 256, the maximum is 256, and the minimum is 4. There are some restrictions on the values that will work. For the greatest portability, choose a value that is divisible by 32. With xtrs's XTRSHARD/DCT and David Keil's EHARD/DCT, any value is allowed that can be evenly divided into granules; see the next paragraph. With Matthew Reed's HARD/CMD, if \fIsec\fP is greater than 32, it must be divisible by 32. With the emulation of a real WD1010 in newer versions of xtrs (and probably David Keil's emulator too), \fIsec\fP must always be divisible by 32, because we always emulate a drive with 32 sectors per track and from 1 to 8 heads (tracks per cylinder). The RSHARDx/DCT driver assumes that there are always 32 sectors per track. For \fIgran\fP, the default value is 8, the maximum is 8, and the minimum is 1. In addition, it is necessary that \fIsec\fP be evenly divisible by \fIgran\fP, and that \fIsec/gran\fP be less than or equal to 32. This value is used only with the emulator-specific drivers listed above; it is ignored when xtrs is using native hardware drivers such as RSHARDx/DCT. The maximum size of a hard drive image is controlled by \fIcyl\fP and \fIsec\fP: it can be at most \fIcyl*sec\fP 256-byte sectors. The image file starts out small and grows as you write to more cylinders. The allocation efficiency is controlled by the granule size: LDOS allocates file space in granules. Therefore (1) \fIgran\fP should always be set as large as possible and (2) reducing \fIsec\fP, thereby making the granules smaller, reduces wasted space due to fragmentation but limits the maximum size of the drive. Seeing that the maximum unpartitioned drive size is less than 13 MB and that the maximum granule size is only 8 KB, wasted space should not be much of a concern for most \fBxtrs\fP users. Therefore the default parameters have been chosen to give you the largest drive possible without partitioning. .SH Write Protection With the -p flag, \fBmkdisk\fP turns on write protection for an existing emulated floppy or hard drive. It turns off all Unix write permission bits on the file, and (except for JV1 floppies) also sets a write-protected flag inside the file. With the -u flag, \fBmkdisk\fP turns off write protection for an existing emulated floppy or hard drive. It turns on Unix write permissions to the file, masked by your current umask and the file's current read permissions. It also clears a write-protected flag inside the file (except on JV1 floppies, which don't have such a flag). \fBmkdisk\fP currently does not have code to auto-recognize file formats, so the -p or -u flag must be accompanied by either -1 (JV1), -3 (JV3), -k (DMK), or -h (hard disk) to identify the file format. There is also no checking for the correct file format, so if you give the wrong flag, the wrong byte inside your file will be changed. .SH Technical data The JV1 format is just an array of 256-byte sectors, in the order (track 0 sector 0, track 0 sector 1, ... track 0 sector 9, track 1 sector 0, ...). It can represent only single-sided, single-density floppies. The directory is assumed to be track 17. The original JV3 format is documented in the printed manual for Jeff Vavasour's commercial Model III/4 emulator. The xtrs implementation includes some extensions. Full documentation for both JV1 and JV3 can be found at http://www.tim-mann.org/trs80/dskspec.html. A copy of this html file is also included in the \fBxtrs\fP distribution. The DMK format is documented in a file on David Keil's web site, http://discover-net.net/~dmkeil/trsdoc.htm#Technical-disks; this file is also included with his emulator. Some updates to the 4.00 version of the document: (1) If neither the single density nor ignore density option is set and single density data is recorded, each single density byte is written twice (i.e., the four bytes 12345678 would be written as 1212343456567878). This ensures that when single and double density sectors are mixed, each type occupies the correct relative amount of space in the track. This update will be effective in version 4.3 of David's emulator; it is incompatible with previous versions. (2) Bit 15 of an IDAM offset is 1 if the sector is double-density, 0 if single density. Bit 14 is reserved; it currently must be 0. The actual offset is in bits 13-0. These offsets are relative to the start of the track header, they must be in ascending order (I hope!!), and an offset of 0 or 0xffff terminates the list. An HDV (hard disk) image has the following format. This information is based on email from Matthew Reed. There is an initial 256-byte header block, followed by an array of sectors. The geometry of the drive is defined in the header block, which looks like this (from mkdisk.c): .nf typedef unsigned char Uchar; typedef struct { Uchar id1; /* 0: Identifier #1: 56H */ Uchar id2; /* 1: Identifier #2: CBH */ Uchar ver; /* 2: Version of format: 10H = version 1.0 */ Uchar cksum; /* 3: Simple checksum: To calculate, add together bytes 0 to 31 of header (excepting byte 3), then XOR result with 4CH */ Uchar blks; /* 4: Number of 256 byte blocks in header: should be 1 */ Uchar mb4; /* 5: Not used, currently set to 4 */ Uchar media; /* 6: Media type: 0 for hard disk */ Uchar flag1; /* 7: Flags #1: bit 7: Write protected: 0 for no, 1 for yes [warning: xtrs currently ignores this flag] bit 6: Must be 0 bit 5 - 0: reserved */ Uchar flag2; /* 8: Flags #2: reserved */ Uchar flag3; /* 9: Flags #3: reserved */ Uchar crtr; /* 10: Created by: 14H = HDFORMAT 42H = xtrs mkdisk 80H = Cervasio xtrshard port to Vavasour M4 emulator */ Uchar dfmt; /* 11: Disk format: 0 = LDOS/LS-DOS */ Uchar mm; /* 12: Creation month: mm */ Uchar dd; /* 13: Creation day: dd */ Uchar yy; /* 14: Creation year: yy (offset from 1900) */ Uchar res1[12]; /* 15 - 26: reserved */ Uchar dparm; /* 27: Disk parameters: (unused with hard drives) bit 7: Density: 0 = double, 1 = single bit 6: Sides: 0 = one side, 1 = 2 sides bit 5: First sector: 0 if sector 0, 1 if sector 1 bit 4: DAM convention: 0 if normal (LDOS), 1 if reversed (TRSDOS 1.3) bit 3 - 0: reserved */ Uchar cyl; /* 28: Number of cylinders per disk */ Uchar sec; /* 29: Number of sectors per track (floppy); cyl (hard) */ Uchar gran; /* 30: Number of granules per track (floppy); cyl (hard)*/ Uchar dcyl; /* 31: Directory cylinder [mkdisk sets to 1; xtrs ignores, but value must be correct if image is to be used with Reed emulators.] */ char label[32]; /* 32: Volume label: 31 bytes terminated by 0 */ char filename[8];/* 64 - 71: 8 characters of filename (without extension) [Cervasio addition. xtrs actually doesn't limit this to 8 chars or strip the extension] */ Uchar res2[184]; /* 72 - 255: reserved */ } ReedHardHeader; .fi .SH See also .BR xtrs (1) http://www.tim-mann.org/trs80/dskspec.html .SH Authors \fBmkdisk\fP was written by Timothy Mann (see http://tim-mann.org/). The floppy file formats here called JV1 and JV3 were developed by Jeff Vavasour for his MSDOS-based Model I and Model III/4 emulators (respectively). They have become a de facto standard in the TRS-80 emulation community, and much TRS-80 software is available on the Internet in .dsk format. Thanks to Jeff for designing and documenting the formats. The format here called DMK was developed by David Keil for his MSDOS-based Model 4 emulator. This format has the advantage that it can represent essentially everything the original TRS-80 floppy disk controllers can write, including all forms of copy protected disk. Thanks to David for designing and documenting this format. The hard drive format was developed by Matthew Reed for his MSDOS-based Model I/III and Model 4 emulators. I have duplicated his format to allow users to exchange .hdv hard drive images between \fBxtrs\fP and Matthew's emulators. Thanks to Matthew for designing the format and providing documentation. $Id: mkdisk.man,v 1.12 2008/06/26 04:39:56 mann Exp $ xtrs-4.9d/mkdisk.txt000066400000000000000000000350741306603614600145730ustar00rootroot00000000000000mkdisk(1) mkdisk(1) Name mkdisk - Make a blank emulated floppy or hard disk for xtrs, or add/remove an emulated write protect tab Syntax mkdisk -1 filename mkdisk [-3] filename mkdisk -k [-s sides] [-d density] [-8] [-i] filename mkdisk -h [-c cyl] [-s sec] [-g gran] filename mkdisk {-p|-u} {-1|-3|-k|-h} filename Description The mkdisk program is part of the xtrs(1) package. It has two distinct functions: (1) It can make a blank (unformatted) emulated floppy or hard drive in a file. (2) With the -p or -u flag, it can turn the write protect flag on or off for an existing emulated floppy or hard drive file. See the xtrs man page for background information. The conventional file extensions are .dsk for emulated floppies and .hdv for emulated hard drives, but mkdisk does not enforce this conven- tion; you can use any filename. Other extensions sometimes used for emulated floppies are .jv1, .jv3, .8in, and .dmk. Making Emulated Floppies With the -1 flag, mkdisk makes an unformatted emulated floppy of type JV1. No additional flags are accepted. With the -3 flag (which is the default and should normally be used), mkdisk makes an unformatted emulated floppy of type JV3. No additional flags are accepted. With the -k flag, mkdisk makes an unformatted emulated floppy of type DMK. With -k, the optional flags -s, -d, -8, and -i can be used to give the emulated floppy special properties. Specifying -s1 limits the floppy to one side; with -s2 (the default), the floppy can be formatted as either one- or two-sided. Specifying -d1 limits the floppy to sin- gle density; with -d2 (the default), the floppy can be formatted in either single or double density. Specifying -8 allows the floppy to be formatted in an emulated 8" drive; by default it will work properly only in an emulated 5" drive. Setting -s1 or -d1 saves space after the floppy is formatted; setting -8 consumes additional space. Specifying -i activates a peculiar feature in some TRS-80 emulators that causes each formatted sector to appear to be both single and double density. Making Emulated Hard Drives With the -h flag, mkdisk makes an unformatted emulated hard drive with cyl cylinders, sec sectors, and gran granules (LDOS allocation units) per cylinder. The hard drive will have cylinder dir marked for use as its directory. You will usually want to use the default values for all these parame- ters. The default is 202 cylinders, 256 sectors per cylinder (that is, 8 heads and 32 sectors per track), and 8 granules per cylinder. This is the largest hard drive that can be used by all LDOS/LS-DOS operating systems without partitioning the drive or patching the FORMAT command. The details on what nondefault values are possible vary, depending on which of xtrs's two hard drive emulations you are using and which other emulators you want to be compatible with, and it is probably best not to delve into these complexities, but read on if you really want to. For cyl, the number of cylinders on the drive, the default value is 202, the minimum is 3, and the maximum that can be represented in the HDV file's header is 256. You can use 203 cylinders with LDOS and LS- DOS if you format the drive with Model 4 LS-DOS; a minor bug in Model I/III FORMAT/CMD prevents more than 202 cylinders from being formatted, but the system can use 203 thereafter. 203 cylinders is the absolute maximum for LDOS/LS-DOS drivers that do not support partitioning, including the emulator-specific drivers supplied with xtrs (XTR- SHARD/DCT), with Matthew Reed's emulator (HARD/CMD), and with David Keil's emulator (EHARD/DCT). In xtrs 4.1 and later, and in David Keil's emulator version 6.0 and later, a true emulation of Radio Shack's WD1010-based hard disk con- troller is also available, which works with the native drivers for the original hardware, such as RSHARDx/DCT and the hard disk drivers for NEWDOS and CP/M. In xtrs, the WD1010 emulation ignores the maximum number of cylinders specified in the HDV file's header and allows the driver to format up to 65536 cylinders. This may be useful if your drivers support partitioning (but why would anyone want to partition an emulated hard drive instead of just making two smaller ones?), or if your operating system supports more than 203 cylinders per partition. Note that although RSHARDx/DCT allows up to 406 cylinders per parti- tion, if you use more than 203, the maximum number of sectors per cylinder is limited to 128, so you gain nothing; the maximum size of a partition is still the same. For sec, the number of sectors per cylinder, the default value is 256, the maximum is 256, and the minimum is 4. There are some restrictions on the values that will work. For the greatest portability, choose a value that is divisible by 32. With xtrs's XTRSHARD/DCT and David Keil's EHARD/DCT, any value is allowed that can be evenly divided into granules; see the next paragraph. With Matthew Reed's HARD/CMD, if sec is greater than 32, it must be divisible by 32. With the emulation of a real WD1010 in newer versions of xtrs (and probably David Keil's emu- lator too), sec must always be divisible by 32, because we always emu- late a drive with 32 sectors per track and from 1 to 8 heads (tracks per cylinder). The RSHARDx/DCT driver assumes that there are always 32 sectors per track. For gran, the default value is 8, the maximum is 8, and the minimum is 1. In addition, it is necessary that sec be evenly divisible by gran, and that sec/gran be less than or equal to 32. This value is used only with the emulator-specific drivers listed above; it is ignored when xtrs is using native hardware drivers such as RSHARDx/DCT. The maximum size of a hard drive image is controlled by cyl and sec: it can be at most cyl*sec 256-byte sectors. The image file starts out small and grows as you write to more cylinders. The allocation effi- ciency is controlled by the granule size: LDOS allocates file space in granules. Therefore (1) gran should always be set as large as possible and (2) reducing sec, thereby making the granules smaller, reduces wasted space due to fragmentation but limits the maximum size of the drive. Seeing that the maximum unpartitioned drive size is less than 13 MB and that the maximum granule size is only 8 KB, wasted space should not be much of a concern for most xtrs users. Therefore the default parame- ters have been chosen to give you the largest drive possible without partitioning. Write Protection With the -p flag, mkdisk turns on write protection for an existing emu- lated floppy or hard drive. It turns off all Unix write permission bits on the file, and (except for JV1 floppies) also sets a write-pro- tected flag inside the file. With the -u flag, mkdisk turns off write protection for an existing emulated floppy or hard drive. It turns on Unix write permissions to the file, masked by your current umask and the file's current read per- missions. It also clears a write-protected flag inside the file (except on JV1 floppies, which don't have such a flag). mkdisk currently does not have code to auto-recognize file formats, so the -p or -u flag must be accompanied by either -1 (JV1), -3 (JV3), -k (DMK), or -h (hard disk) to identify the file format. There is also no checking for the correct file format, so if you give the wrong flag, the wrong byte inside your file will be changed. Technical data The JV1 format is just an array of 256-byte sectors, in the order (track 0 sector 0, track 0 sector 1, ... track 0 sector 9, track 1 sec- tor 0, ...). It can represent only single-sided, single-density flop- pies. The directory is assumed to be track 17. The original JV3 format is documented in the printed manual for Jeff Vavasour's commercial Model III/4 emulator. The xtrs implementation includes some extensions. Full documentation for both JV1 and JV3 can be found at http://www.tim- mann.org/trs80/dskspec.html. A copy of this html file is also included in the xtrs distribution. The DMK format is documented in a file on David Keil's web site, http://discover-net.net/~dmkeil/trsdoc.htm#Technical-disks; this file is also included with his emulator. Some updates to the 4.00 version of the document: (1) If neither the single density nor ignore density option is set and single density data is recorded, each single density byte is written twice (i.e., the four bytes 12345678 would be written as 1212343456567878). This ensures that when single and double density sectors are mixed, each type occupies the correct relative amount of space in the track. This update will be effective in version 4.3 of David's emulator; it is incompatible with previous versions. (2) Bit 15 of an IDAM offset is 1 if the sector is double-density, 0 if single density. Bit 14 is reserved; it currently must be 0. The actual off- set is in bits 13-0. These offsets are relative to the start of the track header, they must be in ascending order (I hope!!), and an offset of 0 or 0xffff terminates the list. An HDV (hard disk) image has the following format. This information is based on email from Matthew Reed. There is an initial 256-byte header block, followed by an array of sectors. The geometry of the drive is defined in the header block, which looks like this (from mkdisk.c): typedef unsigned char Uchar; typedef struct { Uchar id1; /* 0: Identifier #1: 56H */ Uchar id2; /* 1: Identifier #2: CBH */ Uchar ver; /* 2: Version of format: 10H = version 1.0 */ Uchar cksum; /* 3: Simple checksum: To calculate, add together bytes 0 to 31 of header (excepting byte 3), then XOR result with 4CH */ Uchar blks; /* 4: Number of 256 byte blocks in header: should be 1 */ Uchar mb4; /* 5: Not used, currently set to 4 */ Uchar media; /* 6: Media type: 0 for hard disk */ Uchar flag1; /* 7: Flags #1: bit 7: Write protected: 0 for no, 1 for yes [warning: xtrs currently ignores this flag] bit 6: Must be 0 bit 5 - 0: reserved */ Uchar flag2; /* 8: Flags #2: reserved */ Uchar flag3; /* 9: Flags #3: reserved */ Uchar crtr; /* 10: Created by: 14H = HDFORMAT 42H = xtrs mkdisk 80H = Cervasio xtrshard port to Vavasour M4 emulator */ Uchar dfmt; /* 11: Disk format: 0 = LDOS/LS-DOS */ Uchar mm; /* 12: Creation month: mm */ Uchar dd; /* 13: Creation day: dd */ Uchar yy; /* 14: Creation year: yy (offset from 1900) */ Uchar res1[12]; /* 15 - 26: reserved */ Uchar dparm; /* 27: Disk parameters: (unused with hard drives) bit 7: Density: 0 = double, 1 = single bit 6: Sides: 0 = one side, 1 = 2 sides bit 5: First sector: 0 if sector 0, 1 if sector 1 bit 4: DAM convention: 0 if normal (LDOS), 1 if reversed (TRSDOS 1.3) bit 3 - 0: reserved */ Uchar cyl; /* 28: Number of cylinders per disk */ Uchar sec; /* 29: Number of sectors per track (floppy); cyl (hard) */ Uchar gran; /* 30: Number of granules per track (floppy); cyl (hard)*/ Uchar dcyl; /* 31: Directory cylinder [mkdisk sets to 1; xtrs ignores, but value must be correct if image is to be used with Reed emulators.] */ char label[32]; /* 32: Volume label: 31 bytes terminated by 0 */ char filename[8];/* 64 - 71: 8 characters of filename (without extension) [Cervasio addition. xtrs actually doesn't limit this to 8 chars or strip the extension] */ Uchar res2[184]; /* 72 - 255: reserved */ } ReedHardHeader; See also xtrs(1) http://www.tim-mann.org/trs80/dskspec.html Authors mkdisk was written by Timothy Mann (see http://tim-mann.org/). The floppy file formats here called JV1 and JV3 were developed by Jeff Vavasour for his MSDOS-based Model I and Model III/4 emulators (respec- tively). They have become a de facto standard in the TRS-80 emulation community, and much TRS-80 software is available on the Internet in .dsk format. Thanks to Jeff for designing and documenting the formats. The format here called DMK was developed by David Keil for his MSDOS- based Model 4 emulator. This format has the advantage that it can rep- resent essentially everything the original TRS-80 floppy disk con- trollers can write, including all forms of copy protected disk. Thanks to David for designing and documenting this format. The hard drive format was developed by Matthew Reed for his MSDOS-based Model I/III and Model 4 emulators. I have duplicated his format to allow users to exchange .hdv hard drive images between xtrs and Matthew's emulators. Thanks to Matthew for designing the format and providing documentation. $Id: mkdisk.man,v 1.12 2008/06/26 04:39:56 mann Exp $ mkdisk(1) xtrs-4.9d/mount.ccc000066400000000000000000000045301306603614600143550ustar00rootroot00000000000000/* mount.ccc -- Misosys C program to switch emulated floppies on xtrs */ /* Copyright (c) 1998, Timothy Mann */ /* $Id: mount.ccc,v 1.3 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ #option redirect 0 #include "xtrsemt.h" #include "xtrsemt.ccc" /* could use separate compilation instead */ usage() { fprintf(stderr, "usage: mount [-l] file.dsk unit#\n"); exit(1); } #define DDIRSIZE 256 #define DNAMESIZE 512 #define FNAMESIZE 256 #define CMDSIZE 512 #define ERRBUFSIZE 512 int main(argc, argv) int argc; char **argv; { char ddir[DDIRSIZE]; char dname[DNAMESIZE], fname[FNAMESIZE], cmd[CMDSIZE]; char errbuf[ERRBUFSIZE]; char model[4]; int hl, bc, de, ret, lower, i; char *retp, *p, *q; if (argc < 2) { usage(); } i = 1; if (argv[i][0] == '-') { if (tolower(argv[i][1]) != 'l') { usage(); } i++; lower = 1; } else { lower = 0; } if (argc - i != 2 || !isdigit(argv[i+1][0])) { usage(); } retp = emt_gtddir(ddir, DDIRSIZE); if (retp == NULL) { emt_strerror(errno, errbuf, ERRBUFSIZE); fprintf(stderr, "emt_getddir: %s\n", errbuf); exit(1); } emt_4misc(EMT_MISC_QUERY_MODEL, &hl, &bc, &de); if (hl == 5) { strcpy(model, "4p"); } else { sprintf(model, "%d", hl); } sprintf(dname, "%s/disk%s-%s", ddir, model, argv[i+1]); sprintf(cmd, "rm -f %s", dname); /*printf("$ %s\n", cmd);*/ ret = emt_system(cmd); if (ret != 0) { emt_strerror(errno, errbuf, ERRBUFSIZE); fprintf(stderr, "emt_system: %s\n", errbuf); exit(1); } p = fname; q = argv[i]; if (lower) { while (*q) { if (*q == '[' && *(q+1)) { q++; *p++ = *q++; } else if (isalpha(*q)) { *p++ = tolower(*q++); } else { *p++ = *q++; } } } else { while (*q) *p++ = *q++; } *p = '\000'; sprintf(cmd, "ln -s %s %s", fname, dname); /*printf("$ %s\n", cmd);*/ ret = emt_system(cmd); if (ret != 0) { emt_strerror(errno, errbuf, ERRBUFSIZE); fprintf(stderr, "emt_system: %s\n", errbuf); exit(1); } emt_misc(EMT_MISC_DISK_CHANGE); exit(0); } xtrs-4.9d/mount.cmd000066400000000000000000000152161306603614600143730ustar00rootroot00000000000000€RÃLYemt_system: %s ln -s %s %semt_system: %s rm -f %s%s/disk%s-%s%d4pemt_getddir: %s usage: mount [-l] file.dsk unit# <‚R{l¬R²R¸R@ @ @ÀRÃLYñáåõí(`iÈOíCÁdÉñáÁÅåõí*ÈOíCÁd!Éñáåõí+!ÈOíCÁd!ÿÿÉñáÁÑÕÅåõí0bkÈOíCÁdÉñÑÕõí1!ÈOíCÁd!ÿÿÉñÑáÁÅåÕõí2`iÈOíCÁdÉñÑáÁÅåÕõí3`iÈOíCÁdÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o"ÁdÉñÑáÁÅåÕõ{í5`iÈOíCÁdÉñáåõ}í6Éñáåõí7bkÈOíCÁdÉñÑÕõíÀS8!ÈOíCÁd!ÿÿÉñÑáÁÅåÕõí9`iÈOíCÁdÉñáåõí:!ÈOíCÁd!ÿÿÉñáÁÅåõí;ÈOíCÁd!Éñáåõ}í<ÉÝåÝ!Ý9ÝnÝfN#FÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfs#rÑÝnÝfs#rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o"ÁdÉñáÁÑÕÅåõí>bkÈOíCÁdÉñÑÕõí?!ÈOíCÁd!ÿÿÉ!ÀT\Rå!ŽRåÍ Zññ!åÍkcñÉê÷Ídl!9ÍUlå!ÑÍl|µÊòTÍ¿T!9å!ÑÍZl!9ÍUlå!9ÍUlÍ(lÑÍUlå!Ñn&å!-ÑÍèk|µÊƒU!9ÍUlå!9ÍUlÍ(lÑÍUlå!Ñn&åÍfiñå!lÑÍîk|µÊfUÍ¿T!9åÍUl#ÑÍZl+!9å!ÑÍZlÃU!9å!ÑÍZl!9ÍUlå!9ÍUlÑÍ ¾Ø> ¾È#õ!CÍ`iÀ!%BÉõÝåýå!9å! 9ÑÍZl!9åÍUl##ÑÍZlå!ÿÿ)ÑÍUl"[!$d"[!9åÍUl##ÑÍZlå!ÿÿ)ÑÍUlåÝá!9åÝåáåÍ¥[ññåýáýåáå!9Íkl!9ÍsláñññÉ›‚ZõÝåýå!9å! 9ÑÍZl!9åÍUl##ÑÍZlå!ÿÿ)ÑÍUl"€Z!9åÍUl##ÑÍZlå!ÿÿ)ÑÍUlåÝá!"[!["[!9åÝåáåÍ¥[ññåýá*€Zë}ýåáå!9Íkl!9ÍsláñññÉ*€Z#"€Z+å!9n&Ñ}Ép[0B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"![!"[*![n&|µÊíb*![n&%Íîk|µÊó[*[å*[ãå*![#"![+n&ãåÍ`lññ*[#"[Ãêb!"8["6["4["2["0[*![#"![n&åÑ!+ÍlÂ#\!"0[Ã\!-ÍlÂ5\!"2[Ã\! ÍlÂG\!"4[Ã\!#ÍlÂY\!"6[Ã\!0ÍlÂk\!"8[Ã\*![n&p\*Íèk|µÊÁ\ñÁáåÅõåÍUl##ÑÍZlå!ÿÿ)ÑÍUl"'[*'[ëÍl|µÊ·\*'[ÍAl"'[!"2[*![#"![Ãù\!"'[*![n&åÍiñ|µÊù\*'[ Í(lå*![#"![+n&åÍTcñÑ"'[ÃÇ\*![n&.Íèk|µÊ]*![#"![n&*Íèk|µÊF]ñÁáåÅõåÍUl##ÑÍZlå!ÿÿ)ÑÍUl")[*![#"![Ã~]!")[*![n&åÍiñ|µÊ~]*)[ Í(lå*![#"![+n&p]åÍTcñÑ")[ÃL]Ç]!ÿÿ")[!".[*![n&åÑ!lÍl§]!".[ð]!hÍl·]*![#"![!",[!¤[":[*![#"![+n&}2+[åÑ!dÍlÂà]Ãé]!uÍlÂò]!"l[Ã=^!oÍlÂ^!"l[Ã=^!XÍlÂ^Ã^!xÍlÂ"^!"l[Ã=^!BÍlÂ.^Ã7^!bÍlÂð`!"l[*)[ëÍl|µÊR^!")[*.[|µÊ€^ñÁáåÅõåÍUlÑÍZlå!ÿÿp^))ÑÍÓk!d[ÍÛkÃÚ^:+[o&dÍèk|µÊ·^ñÁáåÅõåÍUl##ÑÍZlå!ÿÿ)ÑÍUlͽk!d[ÍÛkÃÚ^ñÁáåÅõåÍUl##ÑÍZlå!ÿÿ)ÑÍUlÍÅk!d[ÍÛk:+[o&dÍèk|µÊN_!d[ÍÓkÅÕÍ%j|µÊ/_!¢[":[!d[ÍÓkÅÕ€Íj|µÊ,_!d[ÍÓkÍŸk!d[ÍÛkÃN_*0[|µÊ@_! [":[ÃN_*4[|µÊN_!ž[":[*8[|µÊ…_õ!9å*'[å*:[åͯfñÑÍ?Ëq(ö@ö€Í DåÍeñ"ÁdáÉñáåõ&}íKòe ¹0þ@Ðþ-.@Ð!Ãd…oŒ•gn&ÉLeZele|ee¡e¸e×eèeUnknown errorArg list too longNot a directoryInvalid argumentToo many open filesNot a character deviceMath arg ouüÃet of domain of funcResult too largeI/O errorHñÑÕõ{þ@8Ö@o&þ 8l):eÃUlöÀõ!|DÍ`i !‹B"GfT]ÍUl"Df!6fÍZlñÍ D!LfÉLf~#Ö ø!ÃZlñáÑÝáÝåÕåõÝnÝf|µÉñÑÁÅÕõbk ·ÈøñÑÕõ!·È#ùÉÁfñÑÕõÝåýå!"½fý!‚R*‚Rý"¿fÝåýáÝnÝfåÝá|µ(7ÝnÝfí[½f·íR8ÜíB0ÝnÝfýuýt ÝuÝtDMÝ ÝsÝr*½fåÍUgÁ|¥< !#"ÁdåÝáÝqÝpÝåÍiágoýáÝáÉñÑÕõz³('!9íBíK~RíB8 íR8Åë "~RáÉ!#"Ád!ÿÿÉ*~RÉŠgñÑÕõÝåýåÍšgýáÝáÉ!shÍxhÝ!üÿÝÍ8iý!‚R ý"ˆgýnýfåýáý^ýVz³(ÝåáíR0âÍXhÝåÁýqýpýå!‚RÑ·íR('ýnýf·íB ÍehýuýtÝnÝfýuýtýåÝáý"ˆgÝNÝFÅýáx±(ÝåáÝ^ÝV·íB ÍehÝuÝtÍXhý*ˆgÝåáÝ^ÝVíK~R¯íBÀýwýwÝ"~RÉýnýfÝuÝtÉýnýfÝ^ÝVÉFREEÝåÅÕåë+F+N++ÍháÑÁŠhÝáÉëÝ!„RÝnÝf|µ(åÝáíRÈ8îñ!×hÍêhYP!ähÍêh> Í3áÍgD!ÉhÍgD!ÿÿåÍnc: BAD BLOCK X'xxxx', LEN X'xxxx' zÍïh{õÍøhñæÆ'Î@'w#ÉýååÕý!„RÕýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý!„RÕýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌ:%þIÉñÑÕõÕÕÍŸiÁÑëz³È}ö &oÉñáåõ}!ö þa8Šiþ{Ø+Éñáåõ}!þ0Øþ:Ð#Éñáåõ}!þAØþ[Ð#ÉÍãkÍekÊÊkÍ—kõÍjkͯjñüŸkÃÊkÍãkÍekÊÊkÍjkõͯjñáÑÁüŸkéÍãkÅÕå!9PXå~#¶#¶#¶áÊ j¯ÍVkãÜ6k¯ÍHkãÃðiñññÃÊkÍãkÍ6kÃÊkÍ/jÂÎk+ÃÎkÍ/jÚÎk+ÃÎk!9###xî€G~ÂPj+~¹ÂPj+~ºÂPj+~»!ÉÍãk{¦_#z¦W#y¦O#x¦GÃÊkÍãkÍek(###Ë+Ë+Ë+ËÍ•jèáÑÁé{/Šj_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍek!À+ÉÝåõõÝ!Ý9;å~Ýw6#~Ýw6#~Ýw6#~Ýw6.xæ€ÂêjËËËË,ÃØjÝuÿÝåáÍ…kåÍkáÊþjÒkÍ0kÍŸk7ãÍHkÝ5ÿÊkã¯ÍVkÃójñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍŸkÃ6kå~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õüŸkÍ—kòƒkÍ…kÍŸkÍ…kñî€ÉñÉå~s_#óŠk~rW#~qO#~pGáÉå###~·áÉ{· ² ± xþ€Èå¯o›_}šW}™O}˜GáÉÍÅkz·ð ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#pÉ!9ÉÍlÈ+ÉÍlÀ+ÉÍlÐ+ÉëÍlØ+ÉÍlØ+É|î€gz {½!ÉÍlØ+Éz¼Â$l{½!ÉDM¯og>Ë#Ë0 =È)Ã/lë¯íRÉÍFl#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉLYxtrs-4.9d/mount6.cmd000066400000000000000000000151671306603614600144660ustar00rootroot00000000000000€0ÃN7emt_system: %s ln -s %s %semt_system: %s rm -f %s%s/disk%s-%s%d4pemt_getddir: %s usage: mount [-l] file.dsk unit# <‚0fJ¬0²0¸0  Â0ÃN7ñáåõí(`iÈOíCÖBÉñáÁÅåõí*ÈOíCÖB!Éñáåõí+!ÈOíCÖB!ÿÿÉñáÁÑÕÅåõí0bkÈOíCÖBÉñÑÕõí1!ÈOíCÖB!ÿÿÉñÑáÁÅåÕõí2`iÈOíCÖBÉñÑáÁÅåÕõí3`iÈOíCÖBÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o"ÖBÉñÑáÁÅåÕõ{í5`iÈOíCÖBÉñáåõ}í6Éñáåõí7bkÈOíCÖBÉñÑÕõíÂ18!ÈOíCÖB!ÿÿÉñÑáÁÅåÕõí9`iÈOíCÖBÉñáåõí:!ÈOíCÖB!ÿÿÉñáÁÅåõí;ÈOíCÖB!Éñáåõ}í<ÉÝåÝ!Ý9ÝnÝfN#FÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfs#rÑÝnÝfs#rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o"ÖBÉñáÁÑÕÅåõí>bkÈOíCÖBÉñÑÕõí?!ÈOíCÖB!ÿÿÉ!Â2\0å!Ž0åÍ,8ññ!åÍAñÉê÷ÍOJ!9Í@Jå!ÑÍìI|µÊô2ÍÁ2!9å!ÑÍEJ!9Í@Jå!9Í@JÍJÑÍ@Jå!Ñn&å!-ÑÍÓI|µÊ…3!9Í@Jå!9Í@JÍJÑÍ@Jå!Ñn&åÍQGñå!lÑÍÙI|µÊh3ÍÁ2!9åÍ@J#ÑÍEJ+!9å!ÑÍEJÑ3!9å!ÑÍEJ!9Í@Jå!9Í@JÑÍ'Jå!ÑÍÙI|µÂâ3!9Í@Jå!9Í@Jå!Â3ÑÍJÑÍ@Jå!Ñn&åÍzGñÍ8J|µÊê3ÍÁ2!9å!å!9åÍÖ0ññÑÍEJ!9Í@Jå!ÑÍÓI|µÊC4!å!9å*ÖBåÍŽ1ñññ!9å!K0å!Ž0åÍ,8ñññ!åÍAñ! 9å!9å!9å!åÍ2ññññ!9Í@Jå!ÑÍÓI|µÊ‚4!H0å!9åÍ©DññÙ4!9Í@Jå!E0å!9åͤ8ñññ!9Í@Jå!9Í@Jå!ÑÍJÑÍ@Jå!9å!Â49å!80å!9åͤ8ñññññ!9å!/0å!9åͤ8ñññ! 9å!9åÍÅ0ñÑÍEJ! 9Í@Jå!ÑÍÙI|µÊ=5!å!9å*ÖBåÍŽ1ñññ!9å!0å!Ž0åÍ,8ñññ!åÍAñ!9å!9ÑÍEJ!9å!9Í@Jå! 9Í@JÍJÑÍ@JÑÍEJ!9Í@J|µÊz6!9Í@Jn&|µÊw6!9Í@Jn&å![ÑÍÓI|µÊ¯5!9Í@Jå!Ñn&|µÊú5!9åÍ@JÑÍÂ5EJÿÿ!9åÍ@JÑÍEJÿÿå!9åÍ@JÑÍEJÿÿn&Ñ}Ãt6!9Í@Jn&åÍgGñ|µÊE6!9åÍ@JÑÍEJÿÿå!9åÍ@JÑÍEJÿÿn&åÍQGñÑ}Ãt6!9åÍ@JÑÍEJÿÿå!9åÍ@JÑÍEJÿÿn&Ñ}Ãy5û6!9Í@Jn&|µÊ»6!9åÍ@JÑÍEJÿÿå!9åÍ@JÑÍEJÿÿn&Ñ}Ãz6!9Í@JÂ6å!Ñ}!9å!9å!0å!9åͤ8ññññ! 9å!9åÍÅ0ñÑÍEJ! 9Í@Jå!ÑÍÙI|µÊ77!å!9å*ÖBåÍŽ1ñññ!9å!0å!Ž0åÍ,8ñññ!åÍAñ!åÍ2ñ!åÍAñÍOJÉís¾0íC¼0>d!Eï"À0ë!ÿóíRë0 >eïý~þ` !ÿóùÍ„7Í×2!åÍA*ˆ0"~0"€0KI>Rï"­0DO>Rï"³0"¹0*¼0í[~0Í!8( Õ Íß7 òÅÝáË!ëâÂ7 "~0"€0Ë9AÑ+r+sùÁåÝåÅÉÔEÃËDÅ~þ"(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( þ\ G#Ú#¯Á> ¾Ø> ¾È#õõÝåýå!9å! 9ÑÍEJ!9åÍ@J##ÑÍEJå!ÿÿ)ÑÍ@J"=9!CB"?9!9åÍ@J##ÑÍEJå!ÿÿ)ÑÍ@JåÝá!9åÝåáåÍÇ9ññåýáýåáå!9ÍVJ!9Í^JáñññÉ›¤8õÝåýå!9å! 9ÑÍEJ!9åÍ@J##ÑÍEJå!ÿÿ)ÑÍ@J"¢8!9åÍ@J##ÑÍEJå!ÿÿ)ÑÍ@JåÝá!"=9!)9"?9!9åÝåáåÍÇ9ññåýá*¢8ë}ýåáå!9ÍVJ!9Í^JáñññÉ*¢8#"¢8+å!9n&Ñ}É’90B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"C9!"A9*C9n&|µÊA*C9n&%ÍÙI|µÊ:*?9å*=9ãå*C9#"C9+n&ãåÍKJññ*A9#"A9à A!"Z9"X9"V9"T9"R9*C9#"C9n&åÑ!+ÍJÂE:!"R9Ã':!-ÍJÂW:!"T9Ã':! ÍJÂi:!"V9Ã':!#ÍJÂ{:!"X9Ã':!0ÍJÂ:!"Z9Ã':*C9n&’:*ÍÓI|µÊã:ñÁáåÅõåÍ@J##ÑÍEJå!ÿÿ)ÑÍ@J"I9*I9ëÍìI|µÊÙ:*I9Í,J"I9!"T9*C9#"C9Ã;!"I9*C9n&åÍzGñ|µÊ;*I9 ÍJå*C9#"C9+n&åÍvAñÑ"I9Ãé:*C9n&.ÍÓI|µÊ£;*C9#"C9n&*ÍÓI|µÊh;ñÁáåÅõåÍ@J##ÑÍEJå!ÿÿ)ÑÍ@J"K9*C9#"C9à;!"K9*C9n&åÍzGñ|µÊ ;*K9 ÍJå*C9#"C9+n&’;åÍvAñÑ"K9Ãn;é;!ÿÿ"K9!"P9*C9n&åÑ!lÍJÂÉ;!"P9ÃÒ;!hÍJÂÙ;*C9#"C9!"N9!Æ9"\9*C9#"C9+n&}2M9åÑ!dÍJÂ<à !†9;IÅÕÍ?Hë"9!†9;IÅÕÍTHÅÕ€ÍsHÍ?H!†9ÍÆI*E9+"E9å*Š9å!†9;IÅÕ*Ž9ͨIÍšGÅÕÍÌGÅÕ*9ͨIÍýGëÑn&Ñ}!†9;IÅÕ*Ž9ͨIÍ´G!†9ÍÆIÃÔ=*E9å*G9ÑÍ'Jå*K9Ñ"N9*X9|µÊ™>*E9å’>*G9ÑÍÙI|µÊ?:M9o&åÑ!oÍJÂÇ>*N9ëÍìI|µÊÄ>!"N9Ã?!xÍJÂÙ>!›9"\9Ã?!XÍJÂë>!˜9"\9Ã?!bÍJÂý>!•9"\9Ã?!BÍJÂ?!’9"\9Ã?Ãü?!cÍJÂM?!^9å!9Í@JåÍ@J##ÑÍEJå!ÿÿ)ÑÍ@JÑ}!^9"E9*E9#"G9Ãü?!sÍJÂÖ?ñÁáåÅõåÍ@J##ÑÍEJå!ÿÿ)ÑÍ@J"E9*K9ëÍìI|µÊˆ?!ÿ"K9!"Œ9Ø?*’?Œ9#"Œ9*E9#"E9+n&|µÊ³?*Œ9å*K9ÑÍìI|µÊ»?Ñ?*E9+"E9"G9*E9å*Œ9ÑÍ'J"E9Ãü?!ÍJÂé?*C9+"C9Ãü?!M9"E9"G9*G9#"G9Ãü?:M9o&|µÊ Aõ!9å*I9å*G9å*E9ÑÍ'JÑÍ'Jå*N9ëÍìI|µÊ6@!Ã<@*N9Ã<@ÑÍ'Jå*\9å͹DñÑÍ'JÑÍEJ*T9Í8J|µÊ€@!9åÍ@J+ÑÍEJëÍßI|µÊ€@! åÍ1AñÃ\@*\9n&|µÊž@*\9#"\9’@+n&åÍ1AñÀ@*N9+"N9ëÍßI|µÊ¼@!0åÍ1AñÞ@*E9å*G9ÑÍJ|µÊß@*E9#"E9+n&åÍ1Añü@*T9|µÊ A!9åÍ@J+ÑÍEJëÍßI|µÊ A! åÍ1AñÃç@ñÃÔ9*=9|µÊA*=9åÍ$Bñ|µÊ*A!ÿÿÃ0A*A9Ã0AÉ*?9å*=9ãå!9n&ãåÍKJññ*A9#"A9Éñáåõå!9Í@JÑÍìI|µÊlAñáåõÃuAñÁáåÅõÃuAÉ!9n&0·íRÉñáåõ0ÉÍ™Añá%’Aåõí{¾0É!Š0A^#V#{²( ÅåëË^ÌØAáÁìÉ·A!ÿÿ"µAñáåõÝååÝáÍ D(MË^ M¯ÝwÝwÝååÝá++å##íCµA~q#Ë~(ëÝnÝfåËo ><ï( ÍC!ÿÿ"µAÍÙ7ÁÍÙ7á*µAÝáÉ!Ý!("ÖBîÝåÍ–DÝá(~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáÍ D(RËN(NËv JT]åÝá:¬0þ*(Ë^#Ä@JëÅyþ Ý~ÿæ />ïõÝ4þñëá }Ö ÝwþÝáÉëËöËî!Ë^(wÍC!ÿÿå >ï Ò͸B ô!·BËÝ4þÕÝ^þÝ~ÿæ?Ëq(ö@ö€O>ïåÍ-Cñ"ÖBáÉñáåõ&}íKD ¹0þ@Ðþ-.@Ð!ØB…oŒ•gn&ÉbCpC‚C’C£C·CÎCíCþCUnknown errorArg list too longNot a directoryInvalid argumentToo many open filesNot a character deviceMath arg oñØCut of domain of funcResult too largeI/O errorHñÑÕõ{þ@8Ö@o&þ 8l)PCÃ@JöÀOýå>eïýËþýáFD>ïbk> Pí±+pëÉñáÑÝáÝåÕåõÝnÝf|µÉñÑÁÅÕõbk ·ÈøñÑÕõ!·È#ùÉËDñÑÕõÝåýå!"ÇDý!‚0*‚0ý"ÉDÝåýáÝnÝfåÝá|µ(7ÝnÝfí[ÇD·íR8ÜíB0ÝnÝfýuýt ÝuÝtDMÝ ÝsÝr*ÇDåÍ_EÁ|¥< !#"ÖBåÝáÝqÝpÝåÍôFágoýáÝáÉñÑÕõz³('!9íBíK~0íB8 íR8Åë "~0áÉ!#"ÖB!ÿÿÉ*~0É”EñÑÕõÝåýåͤEýáÝáÉ!}FÍ‚FÝ!üÿÝÍ)Gý!‚0 ý"’Eýnýfåýáý^ýVz³(ÝåáíR0âÍbFÝåÁýqýpýå!‚0Ñ·íR('ýnýf·íB ÍoFýuýtÝnÝfýuýtýåÝáý"’EÝNÝFÅýáx±(ÝåáÝ^ÝV·íB ÍoFÝuÝtÍbFý*’EÝåáÝ^ÝVíK~0¯íBÀýwýwÝ"~0ÉýnýfÝuÝtÉýnýfÝ^ÝVÉFREEÝåÅÕåë+F+N++Í—FáÑÁ”FÝáÉëÝ!„0ÝnÝf|µ(åÝáíRÈ8îñ!áF>cïYP!îF>cï >ïá> ï!ÓF> ï!ÿÿåÍA: BAD BLOCK X'xxxx', LEN X'xxxx' ýååÕý!„0Õýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý!„0Õýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌñÑÕõÕÕÍŠGÁÑëz³È}ö &oÉñáåõ}!ö þa8þ{Ø+Éñáåõ}!þ0Øþ:Ð#Éñáåõ}!þA”GØþ[Ð#ÉÍÎIÍPIʵIÍ‚IõÍUIÍšHñüŠIõIÍÎIÍPIʵIÍUIõÍšHñáÑÁüŠIéÍÎIÅÕå!9PXå~#¶#¶#¶áÊ÷G¯ÍAIãÜ!I¯Í3IãÃÛGñññõIÍÎIÍ!IõIÍH¹I+ùIÍHÚ¹I+ùI!9###xî€G~Â;H+~¹Â;H+~ºÂ;H+~»!ÉÍÎI{¦_#z¦W#y¦O#x¦GõIÍÎIÍPI(###Ë+Ë+Ë+ËÍ€HèáÑÁé{/_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍPI”H!À+ÉÝåõõÝ!Ý9;å~Ýw6#~Ýw6#~Ýw6#~Ýw6.xæ€ÂÕHËËËË,ÃÃHÝuÿÝåáÍpIåÍ IáÊéHÒðHÍIÍŠI7ãÍ3IÝ5ÿÊIã¯ÍAIÃÞHñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍŠIÃ!Iå~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õüŠIÍ‚IònIÍpIÍŠIÍpIñî€ÉñÉå~s_#~rW#~qO#~pGáÉå###~·áÉ{· ² ± Ô”Ixþ€Èå¯o›_}šW}™O}˜GáÉͰIz·ð ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#pÉ!9ÉÍòIÈ+ÉÍòIÀ+ÉÍòIÐ+ÉëÍòIØ+ÉÍòIØ+É|î€gz {½!ÉÍJØ+Éz¼ÂJ{½!ÉDM¯og>Ë#Ë0 =È)ÃJë¯íRÉÍ1J#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉN7xtrs-4.9d/pwd.ccc000066400000000000000000000020271306603614600140040ustar00rootroot00000000000000/* pwd.ccc -- Misosys C program to print the Unix working directory of xtrs */ /* Copyright (c) 1998, Timothy Mann */ /* $Id: pwd.ccc,v 1.3 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ #option redirect 0 #include "xtrsemt.h" #include "xtrsemt.ccc" /* could use separate compilation instead */ usage() { fprintf(stderr, "usage: pwd\n"); exit(1); } #define ERRBUFSIZE 256 #define DIRBUFSIZE 512 int main(argc, argv) int argc; char **argv; { int i; char *ret; char errbuf[ERRBUFSIZE]; char dirbuf[DIRBUFSIZE]; if (argc != 1) { usage(); } ret = emt_getcwd(dirbuf, DIRBUFSIZE); if (ret == NULL) { emt_strerror(errno, errbuf, ERRBUFSIZE); fprintf(stderr, "pwd: %s\n", errbuf); exit(1); } printf("%s\n", dirbuf); exit(0); } xtrs-4.9d/pwd.cmd000066400000000000000000000126671306603614600140320ustar00rootroot00000000000000RÃU%s pwd: %s usage: pwd < R²gJRPRVR@ @ @^RÃUñáåõí(`iÈOíCA`ÉñáÁÅåõí*ÈOíCA`!Éñáåõí+!ÈOíCA`!ÿÿÉñáÁÑÕÅåõí0bkÈOíCA`ÉñÑÕõí1!ÈOíCA`!ÿÿÉñÑáÁÅåÕõí2`iÈOíCA`ÉñÑáÁÅåÕõí3`iÈOíCA`ÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o"A`ÉñÑáÁÅåÕõ{í5`iÈOíCA`Éñáåõ}í6Éñáåõí7bkÈOíCA`ÉñÑÕõí^S8!ÈOíCA`!ÿÿÉñÑáÁÅåÕõí9`iÈOíCA`Éñáåõí:!ÈOíCA`!ÿÿÉñáÁÅåõí;ÈOíCA`!Éñáåõ}í<ÉÝåÝ!Ý9ÝnÝfN#FÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfs#rÑÝnÝfs#rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o"A`ÉñáÁÑÕÅåõí>bkÈOíCA`ÉñÑÕõí?!ÈOíCA`!ÿÿÉ!^TRå!,RåÍ%Vññ!åÍë^ñÉüüÍ›g!9ÍŒgå!ÑÍ%g|µÊTÍ]T!9å!å!9å͘SññÑÍ‘g!9ÍŒgå!ÑÍg|µÊéT!å!9å*A`åÍ*Sñññ!9å!Rå!,RåÍ%Vñññ!åÍë^ñ!9å!RåÍÄUññ!åÍë^ñÍ›gÉísZR*I@ÍÐd *D"\RùÍ&UÍsT!åÍë^*&R"R"R͹Uí[RÍ®U( Õ ÍlU òÅÝáË!ë "R"RË9AÑ+r+s^UùÁåÝåÅÉÃúbÃ1bÅ~þ"(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( þ\ G#Ú#¯Á> ¾Ø> ¾È#õ!CÍÐdÀ!%BÉõÝåýå!9å! 9ÑÍ‘g!9åÍŒg##ÑÍ‘gå!ÿÿ)ÑÍŒgåÝá!*R"›V!¤_"V!9åÝåáåÍ%Wññåýáýåáå!9Í¢g!9ͪgáñññÉõÝåýå!9å! 9ÑÍ‘g!9åÍŒg##ÑÍ‘gå!ÿÿ)ÑÍŒg"›V!¤_"V!9åÍ?^VŒg##ÑÍ‘gå!ÿÿ)ÑÍŒgåÝá!9åÝåáåÍ%Wññåýáýåáå!9Í¢g!9ͪgáñññÉðV0B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"¡V!"ŸV*¡Vn&|µÊm^*¡Vn&%Í%g|µÊsW*Vå*›Vãå*¡V#"¡V+n&ãåÍ—gññ*ŸV#"ŸVÃj^!"¸V"¶V"´V"²V"°V*¡V#"¡Vn&åÑ!+ÍTg£W!"°VÃ…W!-ÍTgµW!"²VÃ…W! ÍTgÂÇW!"´VÃ…W!#ÍTgÂÙW!"¶VÃ…W!0ÍTgÂëW!"¸VÃ…W*¡Vn&ðW*Íg|µÊAXñÁáåÅõåÍŒg##ÑÍ‘gå!ÿÿ)ÑÍŒg"§V*§VëÍ8g|µÊ7X*§VÍxg"§V!"²V*¡V#"¡VÃyX!"§V*¡Vn&åÍÖdñ|µÊyX*§V Í_gå*¡V#"¡V+n&åÍÔ^ñÑ"§VÃGX*¡Vn&.Íg|µÊY*¡V#"¡Vn&*Íg|µÊÆXñÁáåÅõåÍŒg##ÑÍ‘gå!ÿÿ)ÑÍŒg"©V*¡V#"¡VÃþX!"©V*¡Vn&åÍÖdñ|µÊþX*©V Í_gå*¡V#"¡V+n&ðXåÍÔ^ñÑ"©VÃÌXÃY!ÿÿ"©V!"®V*¡Vn&åÑ!lÍTgÂ'Y!"®VÃ0Y!hÍTgÂ7Y*¡V#"¡V!"¬V!$W"ºV*¡V#"¡V+n&}2«VåÑ!dÍTgÂ`YÃiY!uÍTgÂrY!"ìVýY!oÍTg„Y!"ìVýY!XÍTgÂYÙY!xÍTg¢Y!"ìVýY!BÍTg®Y÷Y!bÍTgÂp\!"ìV*©VëÍ8g|µÊÒY!"©V*®V|µÊZñÁáåÅõåÍŒgÑÍ‘gå!ÿÿðY))ÑÍ g!äVÍgÃZZ:«Vo&dÍg|µÊ7ZñÁáåÅõåÍŒg##ÑÍ‘gå!ÿÿ)ÑÍŒgÍôf!äVÍgÃZZñÁáåÅõåÍŒg##ÑÍ‘gå!ÿÿ)ÑÍŒgÍüf!äVÍg:«Vo&dÍg|µÊÎZ!äVÍ gÅÕÍ\e|µÊ¯Z!"W"ºV!äVÍ gÅÕ€ÍRe|µÊ¬Z!äVÍ gÍÖf!äVÍgÃÎZ*°V|µÊÀZ! W"ºVÃÎZ*´V|µÊÎZ!W"ºV*¸V|µÊ[õ!9å*§Vå*ºVåÍbñÑÍsgÑÍ‘gðZáåå*©VÑÍ1g|µÊ[áå"©Vñ:«Vo&XÍg|µÊ[! WÃ"[!üVÃ"["èV!¼V("£V"¥V!äVÍ gÍÝe|µÊÐ[!äVÍ gÅÕÍ‹eë"îV!äVÍ gÅÕÍ eÅՀͿeÍ‹e!äVÍg*£V+"£Vå*èVå!äVÍ gÅÕ*ìVÍôfÍædÅÕÍeÅÕ*îVÍôfÍIeëÑn&Ñ}!äVÍ gÅÕ*ìVÍôfÍe!äVÍgÃ2[*£Vå*¥VÑÍsgå*©VÑ"¬V*¶V|µÊ÷[*£Våð[*¥VÑÍ%g|µÊm\:«Vo&åÑ!oÍTgÂ%\*¬VëÍ8g|µÊ"\!"¬VÃm\!xÍTgÂ7\!ùV"ºVÃm\!XÍTgÂI\!öV"ºVÃm\!bÍTgÂ[\!óV"ºVÃm\!BÍTgÂm\!ðV"ºVÃm\ÃZ]!cÍTg«\!¼Vå!9ÍŒgåÍŒg##ÑÍ‘gå!ÿÿ)ÑÍŒgÑ}!¼V"£V*£V#"¥VÃZ]!sÍTgÂ4]ñÁáåÅõåÍŒg##ÑÍ‘gå!ÿÿ)ÑÍŒg"£V*©VëÍ8g|µÊæ\!ÿ"©V!"êVÃö\*ð\êV#"êV*£V#"£V+n&|µÊ]*êVå*©VÑÍ8g|µÊ]Ãï\*£V+"£V"¥V*£Vå*êVÑÍsg"£VÃZ]!ÍTgÂG]*¡V+"¡VÃZ]!«V"£V"¥V*¥V#"¥VÃZ]:«Vo&|µÊj^õ!9å*§Vå*¥Vå*£VÑÍsgÑÍsgå*¬VëÍ8g|µÊ”]!Ú]*¬VÚ]ÑÍsgå*ºVåÍbñÑÍsgÑÍ‘g*²VÍ„g|µÊÞ]!9åÍŒg+ÑÍ‘gëÍ+g|µÊÞ]! åÍ^ñú]*ºVn&|µÊü]*ºV#"ºVð]+n&åÍ^ñÃÞ]*¬V+"¬VëÍ+g|µÊ^!0åÍ^ñÃü]*£Vå*¥VÑÍNg|µÊ=^*£V#"£V+n&åÍ^ñÃ^*²V|µÊi^!9åÍŒg+ÑÍ‘gëÍ+g|µÊi^! åÍ^ñÃE^ñÃ2W*›V|µÊ}^*›VåÍ…_ñ|µÊˆ^!ÿÿÃŽ^*ŸVÃŽ^É*Vå*›Vãå!9n&ãåÍ—gññ*ŸV#"ŸVÉñáåõå!9ÍŒgÑÍ8g|µÊÊ^ñáåõÃÓ^ñÁáåÅõÃÓ^É!9n&0·íRÉñáåõ0ÉÍú^ñá(ð^åõ|µÊ-@Ã0@!(RA^#V#{²( ÅåëË^Ì9_áÁìÉ_!ÿÿ"_ñáåõÝååÝáÍb(MË^ M¯ÝwÝwÝååÝá++å##íC_~q#Ë~(ëÝnÝfåËo Í(D( Íp`!ÿÿ"_ÍfUÁÍfUá*_ÝáÉ!Ý!("A`îÝåÍ bÝá(~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáÍb(WËN(SËv OT]åÝá:JRþ*(Ë^#ÄŒgëÅyþ Ý~ÿæ 4yÍõÝ4þñë(Ë~á }Ö ÝwþÝáÉëËöËî!Ë^(wÍp`!ÿÿå yÍ(+`Ë~ ÉÍ#` ïÂÝ4þÕÝ^þÝ~ÿæ?Ëq(ö@ö€Í DåÍ—`ñ"A`áÉñáåõ&}íKra ¹0þ@Ðþ-.@Ð!C`…oŒ•gn&ÉÌ`Ú`ì`ü` a!a8aWahaUnknown errorArg list too longNot a directoryInvalid argumentToo many open filesNot a character deviceMath arg ouìCat of domain of funcResult too largeI/O errorHñÑÕõ{þ@8Ö@o&þ 8l)º`ÃŒgöÀõ!|DÍÐd !‹B"ÇaT]ÍŒg"Äa!¶aÍ‘gñÍ D!ÌaÉÌa~#Ö ø!ÑgñáÑÝáÝåÕåõÝnÝf|µÉñÑÕõ!·È#ùÉ1bñÑÕõÝåýå!"-bý! R* Rý"/bÝåýáÝnÝfåÝá|µ(7ÝnÝfí[-b·íR8ÜíB0ÝnÝfýuýt ÝuÝtDMÝ ÝsÝr*-båÍÅbÁ|¥< !#"A`åÝáÝqÝpÝåÍsdágoýáÝáÉñÑÕõz³('!9íBíKRíB8 íR8Åë "RáÉ!#"A`!ÿÿÉ*RÉúbñÑÕõÝåýåÍ cýáÝáÉ!ãcÍècÝ!üÿÝͨdý! R ý"øbýnýfåýáý^ýVz³(ÝåáíR0âÍÈcÝåÁýqýpýå! RÑ·íR('ýnýf·íB ÍÕcýuýtÝnÝfýuýtýåÝáý"øbÝNÝFÅýáx±(ÝåáÝ^ÝV·íB ÍÕcÝuÝtÍÈcý*øbÝåáÝ^ÝVíKR¯íBÀýwýwÝ"RÉýnýfÝuÝtÉýnýfÝ^ÝVÉFREEÝåÅÕåë+F+N++ÍýcáÑÁúcÝáÉëÝ!"RÝnÝf|µ(åÝáíRÈ8îñ!GdÍZdYP!TdÍZd> Í3áÍgD!9dÍgD!ÿÿåÍî^: BAD BLOCK X'xxxx', LEN X'xxxx' zÍ_d{õÍhdñæÆ'Î@'w#ÉýååÕý!"RÕýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý!"RÕýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌ:%þIÉñáåõ}!þ0Øþ:Ð#ÉÍgÍœfÊgÍÎfõÍ¡fÍæeñúdüÖfÃgÍgÍœfÊgÍ¡fõÍæeñáÑÁüÖféÍgÅÕå!9PXå~#¶#¶#¶áÊCe¯ÍfãÜmf¯ÍfãÃ'eñññÃgÍgÍmfÃgÍfeÂg+ÃgÍfeÚg+Ãg!9###xî€G~‡e+~¹Â‡e+~ºÂ‡e+~»!ÉÍg{¦_#z¦W#y¦O#x¦GÃgÍgÍœf(###Ë+Ë+Ë+ËÍÌeèáÑÁé{/_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍœf!À+ÉÝåõõÝ!Ý9;å~Ýw6#~úeÝw6#~Ýw6#~Ýw6.xæ€Â!fËËËË,ÃfÝuÿÝåáͼfåÍUfáÊ5fÒgÈ+ÉÍ>gÀ+ÉÍ>gÐ+ÉëÍ>gØ+ÉÍ>gØ+É|î€gz {½!ÉÍTgØ+Éz¼Â[g{½!ÉDM¯og>Ë#Ë0 =È)Ãfgë¯íRÉÍ}g#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉUxtrs-4.9d/pwd6.cmd000066400000000000000000000126401306603614600141070ustar00rootroot000000000000000Ã3%s pwd: %s usage: pwd < 0EJ0P0V0  `0Ã3ñáåõí(`iÈOíCV>ÉñáÁÅåõí*ÈOíCV>!Éñáåõí+!ÈOíCV>!ÿÿÉñáÁÑÕÅåõí0bkÈOíCV>ÉñÑÕõí1!ÈOíCV>!ÿÿÉñÑáÁÅåÕõí2`iÈOíCV>ÉñÑáÁÅåÕõí3`iÈOíCV>ÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o"V>ÉñÑáÁÅåÕõ{í5`iÈOíCV>Éñáåõ}í6Éñáåõí7bkÈOíCV>ÉñÑÕõí`18!ÈOíCV>!ÿÿÉñÑáÁÅåÕõí9`iÈOíCV>Éñáåõí:!ÈOíCV>!ÿÿÉñáÁÅåõí;ÈOíCV>!Éñáåõ}í<ÉÝåÝ!Ý9ÝnÝfN#FÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfs#rÑÝnÝfs#rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o"V>ÉñáÁÑÕÅåõí>bkÈOíCV>ÉñÑÕõí?!ÈOíCV>!ÿÿÉ!`20å!,0åÍG4ññ!åÍ =ñÉüü͆E!9ÍwEå!ÑÍE|µÊ’2Í_2!9å!å!9åÍš1ññÑÍ|E!9ÍwEå!ÑÍ E|µÊë2!å!9å*V>åÍ,1ñññ!9å!0å!,0åÍG4ñññ!åÍ =ñ!9å!0åÍæ3ññ!åÍ =ñ͆EÉís\0íCZ0>d!Eï"^0ë!ÿóíRë0 >eïý~þ` !ÿóùÍ>3Íu2!åÍ =*&0"0"0KI>Rï"K0DO>Rï"Q0"W0*Z0`3í[0ÍÛ3( Õ Í™3 òÅÝáË!ë "0"0Ë9AÑ+r+sùÁåÝåÅÉÃAÃ;@Å~þ"(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( þ\ G#Ú#¯Á> ¾Ø> ¾È#õõÝåýå!9å! 9ÑÍ|E!9åÍwE##ÑÍ|Eå!ÿÿ)ÑÍwEåÝá!*0"½4!Ã="¿4!9åÝåáåÍG5ññåýáýåáå!9ÍE!9Í•EáñññÉõÝåýå!9å! 9ÑÍ|E!9åÍw_`4E##ÑÍ|Eå!ÿÿ)ÑÍwE"½4!Ã="¿4!9åÍwE##ÑÍ|Eå!ÿÿ)ÑÍwEåÝá!9åÝåáåÍG5ññåýáýåáå!9ÍE!9Í•EáñññÉ50B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"Ã4!"Á4*Ã4n&|µÊ<*Ã4n&%ÍE|µÊ•5*¿4å*½4ãå*Ã4#"Ã4+n&ãåÍ‚Eññ*Á4#"Á4ÃŒ9!/5ÃD9!5ÃD9" 5!Þ4("Å4"Ç4!5ÍõDÍÈC|µÊò9!5ÍõDÅÕÍvCë"5!5ÍõDÅÕÍ‹CÅÕ€ͪCÍvC!5ÍýD*Å4+"Å4å* 5å!5ÍõDÅÕ*5ÍßDÍÑBÅÕÍCÅÕ*5ÍßDÍ4CëÑn&Ñ}!5ÍõDÅÕ*5ÍßDÍëB!5ÍýDÃT9*Å4å*Ç4ÑÍ^Eå*Ë4Ñ"Î4*Ø4|µÊ:*Å4å:*Ç4ÑÍE|µÊ::Í4o&åÑ!oÍ?EÂG:*Î4ëÍ#E|µÊD:!"Î4Ã:!xÍ?EÂY:!5"Ü4Ã:!XÍ?EÂk:!5"Ü4Ã:!bÍ?EÂ}:!5"Ü4Ã:!BÍ?EÂ:!5"Ü4Ã:Ã|;!cÍ?EÂÍ:!Þ4å!9ÍwEåÍwE##ÑÍ|Eå!ÿÿ)ÑÍwEÑ}!Þ4"Å4*Å4#"Ç4Ã|;!sÍ?EÂV;ñÁáåÅõåÍwE##ÑÍ|Eå!ÿÿ)ÑÍwE"Å4*Ë4ëÍ#E|µÊ;!ÿ"Ë4!" 5Ã;*; 5#" 5*Å4#"Å4+n&|µÊ3;* 5å*Ë4ÑÍ#E|µÊ;;Ã;*Å4+"Å4"Ç4*Å4å* 5ÑÍ^E"Å4Ã|;!Í?EÂi;*Ã4+"Ã4Ã|;!Í4"Å4"Ç4*Ç4#"Ç4Ã|;:Í4o&|µÊŒ<õ!9å*É4å*Ç4å*Å4ÑÍ^EÑÍ^Eå*Î4ëÍ#E|µÊ¶;!ü;*Î4ü;ÑÍ^Eå*Ü4åÍ)@ñÑÍ^EÑÍ|E*Ô4ÍoE|µÊ<ï( Í…>!ÿÿ"5=Í“3ÁÍ“3á*5=ÝáÉ!Ý!("V>îÝåÍ@Ýá(~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáÍ @(RËN(NËv JT]åÝá:J0þ*(Ë^#ÄwEëÅyþ Ý~ÿæ />ïõÝ4þñëá }Ö ÝwþÝáÉëËöËî!Ë^(wÍ…>!ÿÿå >ï ÒÍ8> ô!7>ËÝ4þÕÝ^þÝ~ÿæHHHHHHHHHHHHHHCHHHHHCC"##%'CCCå!$0No&ËA(þ@8>?Ëq(ö@ö€O>ïåÍ­>ñ"V>áÉñáåõ&}íKˆ? ¹0þ@Ðþ-.@Ð!X>…oŒ•gn&Éâ>ð>??#?7?N?m?~?Unknown errorArg list too longNot a directoryInvalid argumentToo many open filesNot a character deviceMath arg oáX?ut of domain of funcResult too largeI/O errorHñÑÕõ{þ@8Ö@o&þ 8l)Ð>ÃwEöÀOýå>eïýËþýáÆ?>ïbk> Pí±+pëÉñáÑÝáÝåÕåõÝnÝf|µÉñÑÕõ!·È#ùÉ;@ñÑÕõÝåýå!"7@ý! 0* 0ý"9@ÝåýáÝnÝfåÝá|µ(7ÝnÝfí[7@·íR8ÜíB0ÝnÝfýuýt ÝuÝtDMÝ ÝsÝr*7@åÍÏ@Á|¥< !#"V>åÝáÝqÝpÝåÍdBágoýáÝáÉñÑÕõz³('!9íBíK0íB8 íR8Åë "0áÉ!#"V>!ÿÿÉ*0ÉAñÑÕõÝåýåÍAýáÝáÉ!íAÍòAÝ!üÿÝÍ™Bý! 0 ý"Aýnýfåýáý^ýVz³(ÝåáíR0âÍÒAÝåÁýqýpýå! 0Ñ·íR('ýnýf·íB ÍßAýuýtÝnÝfýuýtýåÝáý"AÝNÝFÅýáx±(ÝåáÝ^ÝV·íB ÍßAÝuÝtÍÒAý*AÝåáÝ^ÝVíK0¯íBÀýwýwÝ"0ÉýnýfÝuÝtÉýnýfÝ^ÝVÉFREEÝåÅÕåë+F+N++ÍBáÑÁBÝáÉëÝ!"0ÝnÝf|µ(åÝáíRÈ8îñ!QB>cïYP!^B>cï >ïá> ï!CB> ï!ÿÿåÍ=: BAD BLOCK X'xxxx', LEN X'xxxx' ýååÕý!"0Õýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý!"0Õýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌñáåõ}!þ0Øþ:Ð#ÉÍE͇DÊìD͹DõÍŒDÍÑCñüÁDÃìDÍE͇DÊìDÍŒDõÍÑCñáÑÁüÁDéÍCEÅÕå!9PXå~#¶#¶#¶áÊ.C¯ÍxDãÜXD¯ÍjDãÃCñññÃìDÍEÍXDÃìDÍQCÂðD+ÃðDÍQCÚðD+ÃðD!9###xî€G~ÂrC+~¹ÂrC+~ºÂrC+~»!ÉÍE{¦_#z¦W#y¦O#x¦GÃìDÍE͇D(###Ë+Ë+Ë+ËÍ·CèáÑÁé{/_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉ͇D!À+ÉÝåõõÝ!Ý9;å~Ýw6#~Ýw6#~Ýw6#~Ýw6.xæ€Â DËËDËË,ÃúCÝuÿÝåáͧDåÍ@DáÊ DÒ'DÍRDÍÁD7ãÍjDÝ5ÿÊ9Dã¯ÍxDÃDñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍÁDÃXDå~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õüÁD͹Dò¥DͧDÍÁDͧDñî€ÉñÉå~s_#~rW#~qO#~pGáÉå###~·áÉ{· ² ± xþ€Èå¯o›_}šW}™O}˜GáÉÍçDz·ð ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#p›EÉ!9ÉÍ)EÈ+ÉÍ)EÀ+ÉÍ)EÐ+ÉëÍ)EØ+ÉÍ)EØ+É|î€gz {½!ÉÍ?EØ+Éz¼ÂFE{½!ÉDM¯og>Ë#Ë0 =È)ÃQEë¯íRÉÍhE#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉ3xtrs-4.9d/reed.h000066400000000000000000000046121306603614600136320ustar00rootroot00000000000000/* Matthew Reed's hard drive format. Thanks to Matthew for providing documentation. The comments below are copied from his mail messages, with some additions. */ /* $Id: reed.h,v 1.2 2008/06/26 04:39:56 mann Exp $ */ typedef struct { Uchar id1; /* 0: Identifier #1: 56H */ Uchar id2; /* 1: Identifier #2: CBH */ Uchar ver; /* 2: Version of format: 10H = version 1.0 */ Uchar cksum; /* 3: Simple checksum: To calculate, add together bytes 0 to 31 of header (excepting byte 3), then XOR result with 4CH */ Uchar blks; /* 4: Number of 256 byte blocks in header: should be 1 */ Uchar mb4; /* 5: Not used, but HDFORMAT sets to 4 */ Uchar media; /* 6: Media type: 0 for hard disk */ Uchar flag1; /* 7: Flags #1: bit 7: Write protected: 0 for no, 1 for yes [xtrshard/dct ignores for now] bit 6: Must be 0 bit 5 - 0: reserved */ Uchar flag2; /* 8: Flags #2: reserved */ Uchar flag3; /* 9: Flags #3: reserved */ Uchar crtr; /* 10: Created by: 14H = HDFORMAT 42H = xtrs mkdisk 80H = Cervasio xtrshard port to Vavasour M4 emulator */ Uchar dfmt; /* 11: Disk format: 0 = LDOS/LS-DOS */ Uchar mm; /* 12: Creation month: mm */ Uchar dd; /* 13: Creation day: dd */ Uchar yy; /* 14: Creation year: yy (offset from 1900) */ Uchar res1[12]; /* 15 - 26: reserved */ Uchar dparm; /* 27: Disk parameters: (unused with hard drives) bit 7: Density: 0 = double, 1 = single bit 6: Sides: 0 = one side, 1 = 2 sides bit 5: First sector: 0 if sector 0, 1 if sector 1 bit 4: DAM convention: 0 if normal (LDOS), 1 if reversed (TRSDOS 1.3) bit 3 - 0: reserved */ Uchar cyl; /* 28: Number of cylinders per disk */ Uchar sec; /* 29: Number of sectors per track (floppy); cyl (hard) */ Uchar gran; /* 30: Number of granules per track (floppy); cyl (hard)*/ Uchar dcyl; /* 31: Directory cylinder [mkdisk sets to 1; xtrs ignores]*/ char label[32]; /* 32: Volume label: 31 bytes terminated by 0 */ char filename[8];/* 64 - 71: 8 characters of filename (without extension) [Cervasio addition. xtrs actually doesn't limit this to 8 chars or strip the extension] */ Uchar res2[184]; /* 72 - 255: reserved */ } ReedHardHeader; xtrs-4.9d/settime.ccc000066400000000000000000000016541306603614600146710ustar00rootroot00000000000000/* settime.ccc -- Misosys C program to set time using xtrs emulator traps */ /* Copyright (c) 1997, Timothy Mann */ /* $Id: settime.ccc,v 1.3 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ #option redirect 0 #include "xtrsemt.h" #include "xtrsemt.ccc" /* could use separate compilation instead */ main() { time_t now; struct tm *nowtm; char cmd[81]; now = emt_time(EMT_TIME_LOCAL); nowtm = localtime(&now); sprintf(cmd, "date %02d/%02d/%02d", nowtm->tm_mon + 1, nowtm->tm_mday, nowtm->tm_year % 100); system(cmd); sprintf(cmd, "time %02d:%02d:%02d", nowtm->tm_hour, nowtm->tm_min, nowtm->tm_sec); system(cmd); system("time"); } xtrs-4.9d/settime.cmd000066400000000000000000000003531306603614600146770ustar00rootroot00000000000000åRÍ´Rÿÿ>í6x¡<ÊRó*“R><ÍtRw#><ÍtRw#>ÍtRwëEm yÖd8OxæÖíR0ïíZå*•RÍ—R#ãæÆOPxYþ(æ âcRíR0ííZMáq#pû!åíDg—.!„8”ËËËË- ðáÉÃ-@Ã0@A@D@ÃÐRÃ-@Ã0@BBÃÐR>ï>ï-3ÃÒR!§R: þ@ !šR:%þIÀR í°ÉqÉõÅxÖGy(ÆdüwÁñÉRxtrs-4.9d/settime.lst000066400000000000000000000174301306603614600147420ustar00rootroot00000000000000 1: ;; settime.z80 2: ;; 3: ;; Read date and time from xtrs 1.9 emulator trap and set 4: ;; TRS-80 system date and time. 5: ;; 6: ;; Copyright (c) 1998 Ulrich Mueller 7: ;; 8: ;; This software may be copied, modified, and used for any 9: ;; purpose without fee, provided that (1) the above copyright 10: ;; notice is retained, and (2) modified versions are clearly 11: ;; marked as having been modified, with the modifier's name and 12: ;; the date included. 13: 14: ;; Modified on Fri May 19 00:38:41 PDT 2000 by Timothy Mann 15: ;; $Id: settime.z80,v 1.5 2008/06/26 04:39:56 mann Exp $ 16: 17: ;; Model I/III addresses 18: 402D @exit equ 402dh 19: 4030 @abort equ 4030h 20: 21: ;; Model 1 and 3 store the last 2 digits of the year in the year byte 22: 4041 time1$ equ 4041h ; seconds/minutes/hours 23: 4044 date1$ equ 4044h ; year/day/month 24: 4217 time3$ equ 4217h 25: 421A date3$ equ 421ah 26: 27: ;; Model 4 SVCs 28: 0028 @svc equ 40 ; rst address for SVCs 29: ;@svc equ 5 ; older zmac requires 8080-style "rst 5" 30: 0016 @exit6 equ 22 31: 0015 @abort6 equ 21 32: 33: ;; Model 4 stores the offset from 1900 in the year byte 34: 002D time4$ equ 002dh 35: 0033 date4$ equ 0033h 36: 37: ;; Emulator trap instructions 38: 36ED emt_time equ 36edh 39: 40: 5200 org 5200h 41: 5200 settime: 42: 5200 CDB452 call initj ; init OS-dependent tables 43: 5203 01FFFF ld bc, 0ffffh 44: 5206 3E01 ld a, 1 ; get local time from Unix 45: 5208 ED36 defw emt_time ; BCDE: seconds since 1970 46: 520A 78 ld a, b 47: 520B A1 and c 48: 520C 3C inc a 49: 520D CA9052 jp z, abort 50: 5210 F3 di 51: 5211 2A9352 ld hl, (time) 52: 5214 3E3C ld a, 60 53: 5216 CD7452 call divide 54: 5219 77 ld (hl), a ; seconds 55: 521A 23 inc hl 56: 521B 3E3C ld a, 60 57: 521D CD7452 call divide 58: 5220 77 ld (hl), a ; minutes 59: 5221 23 inc hl 60: 5222 3E18 ld a, 24 61: 5224 CD7452 call divide 62: 5227 77 ld (hl), a ; hours 63: 5228 EB ex de, hl ; HL: days since 1970 64: 5229 014513 ld bc, 19*256+70-1 65: 522C 116D01 ld de, 365 66: 522F 0C year1: inc c ; count years in C 67: 5230 79 ld a, c 68: 5231 D664 sub 100 69: 5233 3803 jr c, year2 70: 5235 4F ld c, a 71: 5236 04 inc b ; centuries 72: 5237 78 ld a, b 73: 5238 E603 year2: and 3 74: 523A D601 sub 1 75: 523C ED52 sbc hl, de 76: 523E 30EF jr nc, year1 77: 5240 07 rlca 78: 5241 ED5A adc hl, de ; HL: days since 1 january 79: 5243 E5 push hl 80: 5244 2A9552 ld hl, (date) 81: 5247 CD9752 call putyr ; year to (hl) 82: 524A 23 inc hl 83: 524B E3 ex (sp), hl 84: 524C E601 and 1 ; A=1 for leap year, 0 else 85: 524E C61C add a, 28 86: 5250 4F ld c, a 87: 5251 0600 ld b, 0 88: 5253 50 ld d, b 89: 5254 04 month1: inc b ; count months in B 90: 5255 78 ld a, b 91: 5256 59 ld e, c 92: 5257 FE02 cp 2 93: 5259 2808 jr z, month2 ; february 94: 525B 1E1F ld e, 31 95: 525D E609 and 9 96: 525F E26352 jp po, month2 ; 31 days 97: 5262 1D dec e ; 30 days 98: 5263 ED52 month2: sbc hl, de ; subtract length of month 99: 5265 30ED jr nc, month1 100: 5267 ED5A adc hl, de 101: 5269 4D ld c, l 102: 526A E1 pop hl 103: 526B 71 ld (hl), c ; day 104: 526C 23 inc hl 105: 526D 70 ld (hl), b ; month 106: 526E FB ei 107: 526F 210000 ld hl,0 ; needed on Model 4 --mann 108: 5272 1819 jr exit 109: 110: ;; divide BCDE / A 111: ;; returns quotient in BCDE, remainder in A 112: 5274 E5 divide: push hl 113: 5275 ED44 neg 114: 5277 67 ld h, a 115: 5278 97 sub a 116: 5279 2E21 ld l, 33 117: 527B 17 div1: rla 118: 527C 84 add a, h 119: 527D 3801 jr c, div2 120: 527F 94 sub h 121: 5280 CB13 div2: rl e 122: 5282 CB12 rl d 123: 5284 CB11 rl c 124: 5286 CB10 rl b 125: 5288 2D dec l 126: 5289 20F0 jr nz, div1 127: 528B E1 pop hl 128: 528C C9 ret 129: 130: ;; Jump tables for OS independence 131: ;; Model 1 132: 528D startj: 133: 528D C32D40 exit: jp @exit 134: 5290 C33040 abort: jp @abort 135: 5293 4140 time: defw time1$ 136: 5295 4440 date: defw date1$ 137: 5297 C3D052 putyr: jp putyr1 138: 529A endj: 139: 140: ;; Model 3 141: 529A startj3: 142: 529A C32D40 jp @exit 143: 529D C33040 jp @abort 144: 52A0 1742 defw time3$ 145: 52A2 1A42 defw date3$ 146: 52A4 C3D052 jp putyr3 147: 148: ;; Model 4 149: 52A7 startj4: 150: 52A7 3E16 ld a, @exit6 151: 52A9 EF rst @svc 152: 52AA 3E15 ld a, @abort6 153: 52AC EF rst @svc 154: 52AD 2D00 defw time4$ 155: 52AF 3300 defw date4$ 156: 52B1 C3D252 jp putyr4 157: 158: ;; Initialize tables 159: ;; Changed to work even on a Model III (or Model 4 in III mode) 160: ;; using MODELA/III as its ROM. Previous version didn't. --mann 161: ;; 162: 52B4 21A752 initj: ld hl, startj4 ; model 4? 163: 52B7 3A0A00 ld a, (000ah) 164: 52BA FE40 cp 40h 165: 52BC 2009 jr nz, movej ; go if so 166: 52BE 219A52 ld hl, startj3 ; model 3? 167: 52C1 3A2501 ld a, (0125h) 168: 52C4 FE49 cp 'I' 169: 52C6 C0 ret nz ; return if not 170: 52C7 118D52 movej: ld de, startj 171: 52CA 010D00 ld bc, endj - startj 172: 52CD EDB0 ldir 173: 52CF C9 ret 174: 175: ;; Create year byte. 176: ;; On entry, c has 2-digit year, b has century. 177: ;; On exit, (hl) has year byte. 178: 179: ;; Model I/III, put 2-digit year 180: 52D0 putyr1: 181: 52D0 71 putyr3: ld (hl), c 182: 52D1 C9 ret 183: 184: ;; Model 4, put offset from 1900 (laboriously recomputed, sigh) 185: 52D2 F5 putyr4: push af 186: 52D3 C5 push bc 187: 52D4 78 ld a, b 188: 52D5 D613 sub 19 189: 52D7 47 ld b, a 190: 52D8 79 ld a, c 191: 52D9 2804 jr z, py41 192: 52DB C664 py40: add a, 100 193: 52DD 10FC djnz py40 194: 52DF 77 py41: ld (hl), a 195: 52E0 C1 pop bc 196: 52E1 F1 pop af 197: 52E2 C9 ret 198: 199: 5200 end settime Statistics: 36 symbols 227 bytes Symbol Table: @abort =4030 emt_time =36ed settime 5200 @abort6 = 15 endj 529a startj 528d @exit =402d exit 528d startj3 529a @exit6 = 16 initj 52b4 startj4 52a7 @svc = 28 month1 5254 time 5293 abort 5290 month2 5263 time1 =4041 date 5295 movej 52c7 time3 =4217 date1 =4044 putyr 5297 time4 = 2d date3 =421a putyr1 52d0 year1 522f date4 = 33 putyr3 52d0 year2 5238 div1 527b putyr4 52d2 div2 5280 py40 52db divide 5274 py41 52df xtrs-4.9d/settime.z80000066400000000000000000000066171306603614600145660ustar00rootroot00000000000000;; settime.z80 ;; ;; Read date and time from xtrs 1.9 emulator trap and set ;; TRS-80 system date and time. ;; ;; Copyright (c) 1998 Ulrich Mueller ;; ;; This software may be copied, modified, and used for any ;; purpose without fee, provided that (1) the above copyright ;; notice is retained, and (2) modified versions are clearly ;; marked as having been modified, with the modifier's name and ;; the date included. ;; Modified on Fri May 19 00:38:41 PDT 2000 by Timothy Mann ;; $Id: settime.z80,v 1.5 2008/06/26 04:39:56 mann Exp $ ;; Model I/III addresses @exit equ 402dh @abort equ 4030h ;; Model 1 and 3 store the last 2 digits of the year in the year byte time1$ equ 4041h ; seconds/minutes/hours date1$ equ 4044h ; year/day/month time3$ equ 4217h date3$ equ 421ah ;; Model 4 SVCs @svc equ 40 ; rst address for SVCs ;@svc equ 5 ; older zmac requires 8080-style "rst 5" @exit6 equ 22 @abort6 equ 21 ;; Model 4 stores the offset from 1900 in the year byte time4$ equ 002dh date4$ equ 0033h ;; Emulator trap instructions emt_time equ 36edh org 5200h settime: call initj ; init OS-dependent tables ld bc, 0ffffh ld a, 1 ; get local time from Unix defw emt_time ; BCDE: seconds since 1970 ld a, b and c inc a jp z, abort di ld hl, (time) ld a, 60 call divide ld (hl), a ; seconds inc hl ld a, 60 call divide ld (hl), a ; minutes inc hl ld a, 24 call divide ld (hl), a ; hours ex de, hl ; HL: days since 1970 ld bc, 19*256+70-1 ld de, 365 year1: inc c ; count years in C ld a, c sub 100 jr c, year2 ld c, a inc b ; centuries ld a, b year2: and 3 sub 1 sbc hl, de jr nc, year1 rlca adc hl, de ; HL: days since 1 january push hl ld hl, (date) call putyr ; year to (hl) inc hl ex (sp), hl and 1 ; A=1 for leap year, 0 else add a, 28 ld c, a ld b, 0 ld d, b month1: inc b ; count months in B ld a, b ld e, c cp 2 jr z, month2 ; february ld e, 31 and 9 jp po, month2 ; 31 days dec e ; 30 days month2: sbc hl, de ; subtract length of month jr nc, month1 adc hl, de ld c, l pop hl ld (hl), c ; day inc hl ld (hl), b ; month ei ld hl,0 ; needed on Model 4 --mann jr exit ;; divide BCDE / A ;; returns quotient in BCDE, remainder in A divide: push hl neg ld h, a sub a ld l, 33 div1: rla add a, h jr c, div2 sub h div2: rl e rl d rl c rl b dec l jr nz, div1 pop hl ret ;; Jump tables for OS independence ;; Model 1 startj: exit: jp @exit abort: jp @abort time: defw time1$ date: defw date1$ putyr: jp putyr1 endj: ;; Model 3 startj3: jp @exit jp @abort defw time3$ defw date3$ jp putyr3 ;; Model 4 startj4: ld a, @exit6 rst @svc ld a, @abort6 rst @svc defw time4$ defw date4$ jp putyr4 ;; Initialize tables ;; Changed to work even on a Model III (or Model 4 in III mode) ;; using MODELA/III as its ROM. Previous version didn't. --mann ;; initj: ld hl, startj4 ; model 4? ld a, (000ah) cp 40h jr nz, movej ; go if so ld hl, startj3 ; model 3? ld a, (0125h) cp 'I' ret nz ; return if not movej: ld de, startj ld bc, endj - startj ldir ret ;; Create year byte. ;; On entry, c has 2-digit year, b has century. ;; On exit, (hl) has year byte. ;; Model I/III, put 2-digit year putyr1: putyr3: ld (hl), c ret ;; Model 4, put offset from 1900 (laboriously recomputed, sigh) putyr4: push af push bc ld a, b sub 19 ld b, a ld a, c jr z, py41 py40: add a, 100 djnz py40 py41: ld (hl), a pop bc pop af ret end settime xtrs-4.9d/trs.h000066400000000000000000000126431306603614600135260ustar00rootroot00000000000000/* * Copyright (C) 1992 Clarendon Hill Software. * * Permission is granted to any individual or institution to use, copy, * or redistribute this software, provided this copyright notice is retained. * * This software is provided "as is" without any expressed or implied * warranty. If this software brings on any sort of damage -- physical, * monetary, emotional, or brain -- too bad. You've got no one to blame * but yourself. * * The software may be modified for your own purposes, but modified versions * must retain this notice. */ /* Modified by Timothy Mann, 1996-2008 $Id: trs.h,v 1.30 2009/06/15 23:36:54 mann Exp $ */ /* * trs.h */ #ifndef _TRS_H #define _TRS_H #include "z80.h" #define NORMAL 0 #define EXPANDED 1 #define INVERSE 2 #define ALTERNATE 4 extern int trs_model; /* 1, 3, 4, 5(=4p) */ extern int trs_paused; extern int trs_autodelay; void trs_suspend_delay(void); void trs_restore_delay(void); extern int trs_continuous; /* 1= run continuously, 0= enter debugger after instruction, -1= suppress interrupt and enter debugger */ extern int trs_disk_debug_flags; extern int trs_emtsafe; extern int trs_parse_command_line(int argc, char **argv, int *debug); extern void trs_screen_init(void); extern void trs_screen_write_char(int position, int char_index); extern void trs_screen_expanded(int flag); extern void trs_screen_alternate(int flag); extern void trs_screen_80x24(int flag); extern void trs_screen_inverse(int flag); extern void trs_screen_scroll(void); extern void trs_screen_refresh(void); extern void trs_screen_batch(); extern void trs_screen_unbatch(); extern void trs_reset(int poweron); extern void trs_exit(void); extern void trs_kb_reset(void); extern void trs_kb_bracket(int shifted); extern int trs_kb_mem_read(int address); extern int trs_next_key(int wait); extern void trs_kb_heartbeat(void); extern void trs_xlate_keysym(int keysym); extern void queue_key(int key); extern int dequeue_key(void); extern void clear_key_queue(void); extern void trs_skip_next_kbwait(void); extern int stretch_amount; extern void trs_get_event(int wait); extern volatile int x_poll_count; extern void trs_x_flush(void); extern void trs_printer_write(int value); extern int trs_printer_read(void); extern void trs_cassette_motor(int value); extern void trs_cassette_out(int value); extern int trs_cassette_in(void); extern void trs_sound_out(int value); extern void trs_sound_init(int ioport, int vol); extern int trs_joystick_in(void); extern int trs_rom_size; extern int trs_rom1_size; extern int trs_rom3_size; extern int trs_rom4p_size; extern unsigned char trs_rom1[]; extern unsigned char trs_rom3[]; extern unsigned char trs_rom4p[]; extern void trs_load_compiled_rom(int size, unsigned char rom[]); extern void trs_load_rom(char *filename); extern unsigned char trs_interrupt_latch_read(void); extern unsigned char trs_nmi_latch_read(void); extern void trs_interrupt_mask_write(unsigned char); extern void trs_nmi_mask_write(unsigned char); extern void trs_reset_button_interrupt(int state); extern void trs_disk_intrq_interrupt(int state); extern void trs_disk_drq_interrupt(int state); extern void trs_disk_motoroff_interrupt(int state); extern void trs_uart_err_interrupt(int state); extern void trs_uart_rcv_interrupt(int state); extern void trs_uart_snd_interrupt(int state); extern void trs_timer_interrupt(int state); extern void trs_timer_init(void); extern void trs_timer_off(void); extern void trs_timer_on(void); extern void trs_timer_speed(int flag); extern void trs_cassette_rise_interrupt(int dummy); extern void trs_cassette_fall_interrupt(int dummy); extern void trs_cassette_clear_interrupts(void); extern int trs_cassette_interrupts_enabled(void); extern void trs_cassette_update(int dummy); extern int cassette_default_sample_rate; extern void trs_orch90_out(int chan, int value); extern void trs_cassette_reset(void); extern void trs_disk_change(int drive); extern void trs_disk_change_all(void); extern void trs_disk_debug(void); extern int trs_disk_motoroff(void); extern void mem_video_page(int which); extern void mem_bank(int which); extern void mem_map(int which); extern void mem_romin(int state); extern void trs_debug(void); typedef void (*trs_event_func)(int arg); void trs_schedule_event(trs_event_func f, int arg, int tstates); void trs_schedule_event_us(trs_event_func f, int arg, int us); void trs_do_event(void); void trs_cancel_event(void); trs_event_func trs_event_scheduled(void); void grafyx_write_x(int value); void grafyx_write_y(int value); void grafyx_write_data(int value); int grafyx_read_data(void); void grafyx_write_mode(int value); void grafyx_write_xoffset(int value); void grafyx_write_yoffset(int value); void grafyx_write_overlay(int value); void grafyx_set_microlabs(int on_off); int grafyx_get_microlabs(void); void grafyx_m3_reset(); int grafyx_m3_active(); /* true if currently intercepting video i/o */ void grafyx_m3_write_mode(int value); unsigned char grafyx_m3_read_byte(int position); int grafyx_m3_write_byte(int position, int value); void hrg_onoff(int enable); void hrg_write_addr(int addr, int mask); void hrg_write_data(int data); int hrg_read_data(void); void trs_get_mouse_pos(int *x, int *y, unsigned int *buttons); void trs_set_mouse_pos(int x, int y); void trs_get_mouse_max(int *x, int *y, unsigned int *sens); void trs_set_mouse_max(int x, int y, unsigned int sens); int trs_get_mouse_type(void); void sb_set_volume(int vol); int sb_get_volume(void); #endif /*_TRS_H*/ xtrs-4.9d/trs_cassette.c000066400000000000000000001216341306603614600154150ustar00rootroot00000000000000/* * Copyright (C) 1992 Clarendon Hill Software. * * Permission is granted to any individual or institution to use, copy, * or redistribute this software, provided this copyright notice is retained. * * This software is provided "as is" without any expressed or implied * warranty. If this software brings on any sort of damage -- physical, * monetary, emotional, or brain -- too bad. You've got no one to blame * but yourself. * * The software may be modified for your own purposes, but modified versions * must retain this notice. */ /* Modified by Timothy Mann, 1996 and later $Id: trs_cassette.c,v 1.26 2008/06/26 04:39:56 mann Exp $ */ /* * This module implements cassette I/O, game sound, and Orchestra * 85/90 sound. "Game sound" is defined as output to the cassette * port when the cassette motor is off, or output to the Model III/4 * sound option card (a 1-bit DAC). * * Compile time options: * * HAVE_OSS You have the Open Sound System. If this is set, cassettes * can be read/written directly from/to /dev/dsp. This should work on * Linux and other systems with OSS. * * OSS_SOUND Game sound is emulated using the Open Sound System. * HAVE_OSS must also be set. * * SB_SOUND Game sound is emulated by read/writing SoundBlaster * hardware registers directly. This probably works only on Linux, * and of course only with true SoundBlaster-compatible hardware. * Requires root privileges and the -sb command line option. If you * define both SB_SOUND and OSS_SOUND, then SB_SOUND will be used if * the -sb command line option is given, OSS_SOUND otherwise. * OSS_SOUND seems to work much better than SB_SOUND now, so * SB_SOUND is off by default and -sb has been removed from the * man page. In case you turn it on, here is how it works: * * -sb portbase,vol * Enable sound support using direct I/O to a SoundBlaster with I/O * port base at portbase, playing sounds at vol percent of * maximum volume. A typical setting would be -sb 0x220,30. * Fabio Ferrari contributed the SB_SOUND implementation. */ #if __linux #define HAVE_OSS 1 #define OSS_SOUND 1 #endif /*#define CASSDEBUG 1*/ /*#define CASSDEBUG2 1*/ /*#define CASSDEBUG3 1*/ /*#define CASSDEBUG4 1*/ #include "trs.h" #include "z80.h" #include #include #include #include #include #if SB_SOUND /*#include delete this line if it gives you a compile error */ #include #endif #if HAVE_OSS #include #include #include #endif #define CLOSE 0 #define READ 1 #define WRITE 2 #define SOUND 3 /* used for OSS_SOUND only */ #define ORCH90 4 /* used for OSS_SOUND only */ #define FAILED 5 #define CAS_FORMAT 1 /* recovered bit/byte stream */ #define CPT_FORMAT 2 /* cassette pulse train w/ exact timing */ #define WAV_FORMAT 3 /* wave file */ #define DIRECT_FORMAT 4 /* direct to sound card */ #define DEBUG_FORMAT 5 /* like cpt but in ASCII */ static char *format_name[] = { NULL, "cas", "cpt", "wav", "direct", "debug" }; #define DEFAULT_SAMPLE_RATE 44100 /* samples/sec to use for .wav files */ #define NOISE_FLOOR 64 #define CONTROL_FILENAME ".cassette.ctl" #define DEFAULT_FILENAME "cassette.cas" #define DSP_FILENAME "/dev/dsp" /* for sound output */ #define DEFAULT_FORMAT CAS_FORMAT #define FLUSH -500 /* special fake signal value used when turning off motor */ static char cassette_filename[256]; static int cassette_position; static int cassette_format; static int cassette_state = CLOSE; static int cassette_motor = 0; static FILE *cassette_file; static float cassette_avg; static float cassette_env; static int cassette_noisefloor; static int cassette_sample_rate; int cassette_default_sample_rate = DEFAULT_SAMPLE_RATE; static int cassette_stereo = 0; #if HAVE_OSS static int cassette_afmt = AFMT_U8; #endif /* For bit-level emulation */ static tstate_t cassette_transition; static tstate_t last_sound; static tstate_t cassette_firstoutread; static int cassette_value, cassette_next, cassette_flipflop; static int cassette_lastnonzero; static int cassette_transitionsout; static unsigned long cassette_delta; static float cassette_roundoff_error; /* For bit/byte conversion (.cas file i/o) */ static int cassette_byte; static int cassette_bitnumber; static int cassette_pulsestate; #define SPEED_500 0 #define SPEED_1500 1 #define SPEED_250 2 int cassette_speed = SPEED_500; /* Pulse shapes for conversion from .cas on input */ #define CAS_MAXSTATES 8 struct { int delta_us; int next; } pulse_shape[3][2][CAS_MAXSTATES] = { {{ /* Low-speed zero: clock 1 data 0 */ { 0, 1 }, { 128, 2 }, { 128, 0 }, { 1871, 0 }, /* normally 1757; 1871 after 8th bit */ { -1, -1 } }, { /* Low-speed one: clock 1 data 1 */ { 0, 1 }, { 128, 2 }, { 128, 0 }, { 748, 1 }, { 128, 2 }, { 128, 0 }, { 860, 0 }, /* normally 748; 860 after 8th bit; 1894 after a5 sync */ { -1, -1 } }}, {{ /* High-speed zero: wide pulse */ { 0, 1 }, { 376, 2 }, { 376, 1 }, { -1, -1 } }, { /* High-speed one: narrow pulse */ { 0, 1 }, { 188, 2 }, { 188, 1 }, { -1, -1 } }}, {{ /* Level I zero: clock 1 data 0 */ { 0, 1 }, { 125, 2 }, { 125, 0 }, { 3568, 0 }, { -1, -1 } }, { /* Level I one: clock 1 data 1 */ { 0, 1 }, { 128, 2 }, { 128, 0 }, { 1673, 1 }, { 128, 2 }, { 128, 0 }, { 1673, 0 }, { -1, -1 } }} }; /* States and thresholds for conversion to .cas on output */ #define ST_INITIAL 0 #define ST_500GOTCLK 1 #define ST_500GOTDAT 2 #define ST_1500 3 #define ST_250 4 #define ST_250GOTCLK 5 #define ST_250GOTDAT 6 #define ST_500THRESH 1250.0 /* us threshold between 0 and 1 */ #define ST_1500THRESH 282.0 /* us threshold between 1 and 0 */ #define ST_250THRESH 2500.0 /* us threshold between 0 and 1 */ #define DETECT_250 1200.0 /* detect level 1 input routine */ /* Values for conversion to .wav on output */ /* Values in comments are from Model I technical manual. Model III/4 are close though not quite the same, as one resistor in the network was changed; we ignore the difference. Actually, we ignore more than that; we convert the values as if 0 were really halfway between high and low. */ Uchar value_to_sample[] = { 127, /* 0.46 V */ 254, /* 0.85 V */ 0, /* 0.00 V */ 127, /* unused, but close to 0.46 V */ }; /* .wav file definitions */ #define WAVE_FORMAT_PCM (0x0001) #define WAVE_FORMAT_MONO 1 #define WAVE_FORMAT_STEREO 2 #define WAVE_FORMAT_8BIT 8 #define WAVE_FORMAT_16BIT 16 #define WAVE_RIFFSIZE_OFFSET 0x04 #define WAVE_RIFF_OFFSET 0x08 #define WAVE_DATAID_OFFSET 0x24 #define WAVE_DATASIZE_OFFSET 0x28 #define WAVE_DATA_OFFSET 0x2c static long wave_dataid_offset = WAVE_DATAID_OFFSET; static long wave_datasize_offset = WAVE_DATASIZE_OFFSET; static long wave_data_offset = WAVE_DATA_OFFSET; /* Orchestra 80/85/90 stuff */ static int orch90_left = 128, orch90_right = 128; #if SB_SOUND /* ioport of the SoundBlaster command register. 0 means none */ static unsigned char sb_cassette_volume[4]; static unsigned char sb_sound_volume[2]; #endif /*SB_SOUND*/ static unsigned int sb_address=0; static int sb_volume = 0; /* Put a 2-byte quantity to a file in little-endian order */ /* Return -1 on error, 0 otherwise */ static int put_twobyte(Ushort n, FILE* f) { int c; struct twobyte *p = (struct twobyte *) &n; c = putc(p->low, f); if (c == -1) return c; c = putc(p->high, f); if (c == -1) return c; return 0; } /* Put a 4-byte quantity to a file in little-endian order */ /* Return -1 on error, 0 otherwise */ static int put_fourbyte(Uint n, FILE* f) { int c; struct fourbyte *p = (struct fourbyte *) &n; c = putc(p->byte0, f); if (c == -1) return c; c = putc(p->byte1, f); if (c == -1) return c; c = putc(p->byte2, f); if (c == -1) return c; c = putc(p->byte3, f); if (c == -1) return c; return 0; } /* Get a 2-byte quantity from a file in little-endian order */ /* Return -1 on error, 0 otherwise */ static int get_twobyte(Ushort *pp, FILE* f) { int c; struct twobyte *p = (struct twobyte *) pp; c = getc(f); if (c == -1) return c; p->low = c; c = getc(f); if (c == -1) return c; p->high = c; return 0; } /* Get a 4-byte quantity from a file in little-endian order */ /* Return -1 on error, 0 otherwise */ static int get_fourbyte(Uint *pp, FILE* f) { int c; struct fourbyte *p = (struct fourbyte *) pp; c = getc(f); if (c == -1) return c; p->byte0 = c; c = getc(f); if (c == -1) return c; p->byte1 = c; c = getc(f); if (c == -1) return c; p->byte2 = c; c = getc(f); if (c == -1) return c; p->byte3 = c; return 0; } /* Output an 8-byte unsigned sample, if necessary converting to a * different sample format. */ static void put_sample(Uchar sample, int convert, FILE* f) { if (convert) { #if HAVE_OSS switch (cassette_afmt) { case AFMT_U8: putc(sample, f); break; case AFMT_S16_LE: put_twobyte((sample << 8) - 0x8000, f); break; default: error("sample format 0x%x not supported", cassette_afmt); break; } return; #endif } putc(sample, f); } /* Get an 8-byte unsigned sample, if necessary converting from a * different sample format and/or reducing stereo to mono. */ static int get_sample(int convert, FILE* f) { #if HAVE_OSS if (convert) { int ret = 0; short s = 0; switch (cassette_afmt) { case AFMT_U8: ret = getc(f); break; case AFMT_S16_LE: ret = get_twobyte((Ushort *)&s, cassette_file); if (ret == EOF) break; ret = ((s + 0x8000) >> 8) & 0xff; break; default: error("sample format 0x%x not supported", cassette_afmt); break; } return ret; } #endif return getc(f); } /* Write a new .wav file header to a file. Return -1 on error. */ static int create_wav_header(FILE *f) { Uint field; /* Chunk sizes don't count the 4-byte chunk type name nor the 4-byte size field itself. The RIFF chunk is the whole file, so its size is the actual length of the file minus WAVE_RIFF_OFFSET (=8). The data chunk is the actual sample data, so its size is the size of the file minus wave_data_offset. */ wave_dataid_offset = WAVE_DATAID_OFFSET; wave_datasize_offset = WAVE_DATASIZE_OFFSET; wave_data_offset = WAVE_DATA_OFFSET; if (cassette_position < wave_data_offset) { cassette_position = wave_data_offset; } if (fputs("RIFF", f) < 0) return -1; if (put_fourbyte(0, f) < 0) return -1; /* RIFF chunk size */ if (fputs("WAVEfmt ", f) < 0) return -1; if (put_fourbyte(16, f) < 0) return -1; /* fmt chunk size */ if (put_twobyte(WAVE_FORMAT_PCM, f) < 0) return -1; if (put_twobyte(WAVE_FORMAT_MONO, f) < 0) return -1; if (put_fourbyte(cassette_sample_rate, f) < 0) return -1; field = (WAVE_FORMAT_MONO * cassette_sample_rate * WAVE_FORMAT_8BIT/8); if (put_fourbyte(field, f) < 0) return -1; field = (WAVE_FORMAT_MONO * WAVE_FORMAT_8BIT/8); if (put_twobyte(field, f) < 0) return -1; if (put_twobyte(WAVE_FORMAT_8BIT, f) < 0) return -1; /* end of fmt chunk */ if (fputs("data", f) < 0) return -1; if (put_fourbyte(0, f) < 0) return -1; /* size of data chunk payload */ /* payload starts here */ return 0; } /* Error message generator */ static int check_chunk_id(char *expected, FILE* f) { char c4[5]; c4[4] = '\0'; if (fread(c4, 4, 1, f) != 1) return -1; if (strcmp(c4, expected) != 0) { error("unusable wav file: expected chunk id '%s', got '%s'", expected, c4); return -1; } return 0; } /* Parse a .wav file's RIFF header. We don't understand much about the RIFF format, so we might fail on valid .WAV files. For now, that's just tough. Try running the file through sox to convert it to something more vanilla. */ static int parse_wav_header(FILE *f) { Uint n4; Uint fmt_size; Ushort n2, expect2; if (check_chunk_id("RIFF", f) < 0) return -1; if (get_fourbyte(&n4, f) < 0) return -1; /* ignore this field */ if (check_chunk_id("WAVE", f) < 0) return -1; if (check_chunk_id("fmt ", f) < 0) return -1; if (get_fourbyte(&fmt_size, f) < 0) return -1; if (get_twobyte(&n2, f) < 0) return -1; if (n2 != WAVE_FORMAT_PCM) { error("unusable wav file: must be pcm"); return -1; } if (get_twobyte(&n2, f) < 0) return -1; if (n2 != WAVE_FORMAT_MONO) { error("unusable wav file: must be mono"); return -1; } if (get_fourbyte(&n4, f) < 0) return -1; cassette_sample_rate = n4; if (get_fourbyte(&n4, f) < 0) return -1; /* ignore this field */ expect2 = WAVE_FORMAT_MONO * WAVE_FORMAT_8BIT/8; if (get_twobyte(&n2, f) < 0) return -1; if (n2 != expect2) { error("unusable wav file: must be %d bytes/sample", expect2); return -1; } expect2 = WAVE_FORMAT_8BIT; if (get_twobyte(&n2, f) < 0) return -1; if (n2 != expect2) { error("unusable wav file: must be %d bits/sample", expect2); return -1; } fmt_size -= 16; /* size read so far */ while (fmt_size-- > 0) getc(f); /* ignore additional */ wave_dataid_offset = ftell(f); if (check_chunk_id("data", f) < 0) return -1; wave_datasize_offset = ftell(f); if (get_fourbyte(&n4, f) < 0) return -1; /* ignore this field */ wave_data_offset = ftell(f); if (cassette_position < wave_data_offset) { cassette_position = wave_data_offset; } return 0; } #if !USESOX static int set_audio_format(FILE *f, int state) { #if HAVE_OSS int audio_fd = fileno(f); int format, stereo, speed, req; req = format = AFMT_U8; /* unsigned 8-bit */ if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format)==-1) return -1; if (format != req) { req = format = AFMT_S16_LE; /* signed 16-bit little-endian */ if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format)==-1) return -1; if (format != req) { error("requested audio format 0x%x, got 0x%x", req, format); errno = EINVAL; return -1; } } cassette_afmt = format; req = stereo = (state == ORCH90); if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo)==-1) return -1; if (req && !stereo) { error("requested stereo, got mono"); errno = EINVAL; return -1; } cassette_stereo = stereo; req = speed = cassette_sample_rate; if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &speed)==-1) return -1; if (abs(speed - req) > req/20) { error("requested sample rate %d Hz, got %d Hz", req, speed); errno = EINVAL; return -1; } #else /* Hope for the best. Might work on Suns with /dev/audio (mu-law). */ #endif return 0; } #endif static void get_control() { FILE *f; f = fopen(CONTROL_FILENAME, "r"); cassette_format = DEFAULT_FORMAT; if ((!f) || (fscanf(f, "%s %d %d", cassette_filename, &cassette_position, &cassette_format) < 2)) { error("can't read %s (%s);\n cassette file will be: %s, format %s", CONTROL_FILENAME, strerror(errno), DEFAULT_FILENAME, format_name[DEFAULT_FORMAT]); strcpy(cassette_filename, DEFAULT_FILENAME); cassette_position = 0; } if (f) { fclose(f); } } static void put_control() { FILE *f; f = fopen(CONTROL_FILENAME, "w"); if (f) { trs_paused = 1; /* disable speed measurement for this round */ fprintf(f, "%s %d %d\n", cassette_filename, cassette_position, cassette_format); fclose(f); } } /* Return value: 1 = already that state; 0 = state changed; -1 = failed */ static int assert_state(int state) { if (cassette_state == state) { return 1; } if (cassette_state == FAILED && state != CLOSE) { return -1; } #if CASSDEBUG debug("state %d -> %d\n", cassette_state, state); #endif if (cassette_state == ORCH90) { trs_orch90_out(0, FLUSH); } if (cassette_state != CLOSE && cassette_state != FAILED) { if (cassette_format == DIRECT_FORMAT) { #if USESOX pclose(cassette_file); #else sigset_t set, oldset; sigemptyset(&set); sigaddset(&set, SIGALRM); sigprocmask(SIG_BLOCK, &set, &oldset); trs_paused = 1; /* disable speed measurement for this round */ fclose(cassette_file); sigprocmask(SIG_SETMASK, &oldset, NULL); #endif cassette_position = 0; } else { cassette_position = ftell(cassette_file); if (cassette_format == WAV_FORMAT && cassette_state == WRITE) { fseek(cassette_file, WAVE_RIFFSIZE_OFFSET, 0); put_fourbyte(cassette_position - WAVE_RIFF_OFFSET, cassette_file); fseek(cassette_file, wave_datasize_offset, 0); put_fourbyte(cassette_position - wave_data_offset, cassette_file); } fclose(cassette_file); } if (cassette_state != SOUND && cassette_state != ORCH90) { put_control(); } #if HAVE_OSS cassette_stereo = 0; cassette_afmt = AFMT_U8; #endif } switch (state) { case READ: get_control(); if (cassette_format == DIRECT_FORMAT) { #if USESOX char command[256]; cassette_sample_rate = cassette_default_sample_rate; sprintf(command, "sox -t ossdsp -r %d -u -b /dev/dsp -t raw -r %d -u -b -", cassette_sample_rate, cassette_sample_rate); cassette_file = popen(command, "r"); if (cassette_file == NULL) { error("couldn't read from sound card: %s", strerror(errno)); cassette_state = FAILED; return -1; } #else cassette_file = fopen(cassette_filename, "r"); if (cassette_file == NULL) { error("couldn't read %s: %s", cassette_filename, strerror(errno)); cassette_state = FAILED; return -1; } /*setbuf(cassette_file, NULL);*/ /* seems no need for this */ cassette_sample_rate = cassette_default_sample_rate; if (set_audio_format(cassette_file, state) < 0) { error("couldn't set audio format on %s: %s", cassette_filename, strerror(errno)); cassette_file = NULL; cassette_state = FAILED; return -1; } #endif } else { cassette_file = fopen(cassette_filename, "r"); if (cassette_format == WAV_FORMAT && cassette_file != NULL && parse_wav_header(cassette_file) < 0) { cassette_file = NULL; } if (cassette_file == NULL) { error("couldn't read %s: %s", cassette_filename, strerror(errno)); cassette_state = FAILED; return -1; } fseek(cassette_file, cassette_position, 0); } break; case SOUND: case ORCH90: case WRITE: if (state == SOUND || state == ORCH90) { cassette_format = DIRECT_FORMAT; strcpy(cassette_filename, DSP_FILENAME); } else { get_control(state); } if (cassette_format == DIRECT_FORMAT) { #if USESOX char command[256]; cassette_sample_rate = cassette_default_sample_rate; sprintf(command, "sox -t raw -r %d -u -b -c %d - -t ossdsp /dev/dsp", cassette_sample_rate, (state == ORCH90) ? 2 : 1); cassette_file = popen(command, "w"); #else cassette_sample_rate = cassette_default_sample_rate; cassette_file = fopen(cassette_filename, "w"); if (cassette_file == NULL) { error("couldn't write %s: %s", cassette_filename, strerror(errno)); cassette_state = FAILED; return -1; } setbuf(cassette_file, NULL); /* ??hangs on some OSS drivers */ #if OSS_SOUND && HAVE_OSS if (state == SOUND || state == ORCH90) { /*int arg = 0x7fff0008;*/ /* unlimited fragments of size (1 << 8) */ int arg = 0x00200008; /* 32 fragments of size (1 << 8) */ if (ioctl(fileno(cassette_file), SNDCTL_DSP_SETFRAGMENT, &arg) < 0) { error("warning: couldn't set sound fragment size: %s", strerror(errno)); } } #endif if (set_audio_format(cassette_file, state) < 0) { error("couldn't set audio format on %s: %s", cassette_filename, strerror(errno)); cassette_file = NULL; cassette_state = FAILED; return -1; } #endif } else if (cassette_format == WAV_FORMAT) { cassette_file = fopen(cassette_filename, "r+"); if (cassette_file == NULL) { cassette_sample_rate = cassette_default_sample_rate; cassette_file = fopen(cassette_filename, "w"); if (cassette_file && create_wav_header(cassette_file) < 0) { cassette_file = NULL; } } else { if (parse_wav_header(cassette_file) < 0) { fclose(cassette_file); cassette_file = NULL; } } if (cassette_file != NULL) { fseek(cassette_file, cassette_position, 0); } } else { cassette_file = fopen(cassette_filename, "r+"); if (cassette_file == NULL) { cassette_file = fopen(cassette_filename, "w"); } if (cassette_file != NULL) { fseek(cassette_file, cassette_position, 0); } } if (cassette_file == NULL) { error("couldn't write %s: %s", cassette_filename, strerror(errno)); cassette_state = FAILED; return -1; } break; } cassette_state = state; return 0; } /* Record an output transition. value is either the new port value or FLUSH. */ static void transition_out(int value) { Uchar sample; long nsamples, delta_us; Ushort code; float ddelta_us; sigset_t set, oldset; cassette_transitionsout++; if (value != FLUSH && value == cassette_value) return; sigemptyset(&set); sigaddset(&set, SIGALRM); sigprocmask(SIG_BLOCK, &set, &oldset); ddelta_us = (z80_state.t_count - cassette_transition) / z80_state.clockMHz - cassette_roundoff_error; switch (cassette_format) { case DEBUG_FORMAT: /* Print value and delta_us in ASCII for easier examination */ if (value == FLUSH) value = cassette_value; delta_us = (unsigned long) (ddelta_us + 0.5); cassette_roundoff_error = delta_us - ddelta_us; fprintf(cassette_file, "%d %lu\n", value, delta_us); break; case CPT_FORMAT: /* Encode value and delta_us in two bytes if delta_us is small enough. Pack bits as ddddddddddddddvv and store this value in little- endian order. */ if (value == FLUSH) value = cassette_value; delta_us = (unsigned long) (ddelta_us + 0.5); cassette_roundoff_error = delta_us - ddelta_us; if (delta_us < 0x3fff) { code = value | (delta_us << 2); put_twobyte(code, cassette_file); } else { /* Else write 0xffff escape code and encode in five bytes: 1-byte value, then 4-byte delta_us in little-endian order */ put_twobyte(0xffff, cassette_file); putc(value, cassette_file); put_fourbyte(delta_us, cassette_file); } break; case WAV_FORMAT: case DIRECT_FORMAT: #if OSS_SOUND && HAVE_OSS if (cassette_state == SOUND) { if (ddelta_us > 20000.0) { /* Truncate silent periods */ ddelta_us = 20000.0; cassette_roundoff_error = 0.0; } if (trs_event_scheduled() == transition_out || trs_event_scheduled() == (trs_event_func) assert_state) { trs_cancel_event(); } if (value == FLUSH) { trs_schedule_event((trs_event_func)assert_state, CLOSE, 5000000); } else { trs_schedule_event(transition_out, FLUSH, (int)(25000 * z80_state.clockMHz)); } } #endif sample = value_to_sample[cassette_value]; nsamples = (unsigned long) (ddelta_us / (1000000.0/cassette_sample_rate) + 0.5); if (nsamples == 0) nsamples = 1; /* always at least one sample */ cassette_roundoff_error = nsamples * (1000000.0/cassette_sample_rate) - ddelta_us; #if CASSDEBUG debug("%d %4lu %d -> %3lu\n", cassette_value, z80_state.t_count - cassette_transition, value, nsamples); #endif if (cassette_format == DIRECT_FORMAT && cassette_stereo) nsamples *= 2; while (nsamples-- > 0) { put_sample(sample, cassette_format == DIRECT_FORMAT, cassette_file); } if (value == FLUSH) { value = cassette_value; #if OSS_SOUND && HAVE_OSS if (cassette_format == DIRECT_FORMAT) { ioctl(fileno(cassette_file), SNDCTL_DSP_POST, 0); } trs_restore_delay(); #endif } break; case CAS_FORMAT: if (value == FLUSH && cassette_bitnumber != 0) { putc(cassette_byte, cassette_file); cassette_byte = 0; break; } sample = 2; /* i.e., no bit */ switch (cassette_pulsestate) { case ST_INITIAL: if (cassette_value == 2 && value == 0) { /* Low speed, end of first pulse. Assume clock */ cassette_pulsestate = ST_500GOTCLK; } else if (cassette_value == 2 && value == 1) { /* High speed, nothing interesting yet. */ cassette_pulsestate = ST_1500; } break; case ST_500GOTCLK: if (cassette_value == 0 && value == 1) { /* Low speed, start of next pulse. */ if (ddelta_us > ST_250THRESH) { /* Oops, really ultra-low speed */ /* It's the next clock; bit was 0 */ sample = 0; /* Watch for end of this clock */ cassette_pulsestate = ST_250; } else if (ddelta_us > ST_500THRESH) { /* It's the next clock; bit was 0 */ sample = 0; /* Watch for end of this clock */ cassette_pulsestate = ST_INITIAL; } else { /* It's a data pulse; bit was 1 */ sample = 1; /* Ignore the data pulse falling edge */ cassette_pulsestate = ST_500GOTDAT; } } break; case ST_500GOTDAT: if (cassette_value == 2 && value == 0) { /* End of data pulse; watch for end of next clock */ cassette_pulsestate = ST_INITIAL; } break; case ST_1500: if (cassette_value == 1 && value == 2) { sample = (ddelta_us < ST_1500THRESH); } break; case ST_250: if (cassette_value == 2 && value == 0) { /* Ultra-low speed, end of first pulse. Assume clock */ cassette_pulsestate = ST_250GOTCLK; } break; case ST_250GOTCLK: if (cassette_value == 0 && value == 1) { /* Low speed, start of next pulse. */ if (ddelta_us > ST_250THRESH) { /* It's the next clock; bit was 0 */ sample = 0; /* Watch for end of this clock */ cassette_pulsestate = ST_250; } else { /* It's a data pulse; bit was 1 */ sample = 1; /* Ignore the data pulse falling edge */ cassette_pulsestate = ST_250GOTDAT; } } break; case ST_250GOTDAT: if (cassette_value == 2 && value == 0) { /* End of data pulse; watch for end of next clock */ cassette_pulsestate = ST_250; } break; } if (sample == 2) break; cassette_bitnumber--; if (cassette_bitnumber < 0) cassette_bitnumber = 7; cassette_byte |= (sample << cassette_bitnumber); if (cassette_bitnumber == 0) { putc(cassette_byte, cassette_file); cassette_byte = 0; } break; default: error("output format %s not implemented", cassette_format < (sizeof(format_name)/sizeof(char *)) ? format_name[cassette_format] : "out of range;"); break; } sigprocmask(SIG_SETMASK, &oldset, NULL); if (cassette_value != value) last_sound = z80_state.t_count; cassette_transition = z80_state.t_count; cassette_value = value; } /* Read a new transition, updating cassette_next and cassette_delta. If file read fails (perhaps due to eof), return 0, else 1. Set cassette_delta to (unsigned long) -1 on failure. */ static int transition_in() { unsigned long delta_us, nsamples, maxsamples; Ushort code; Uint d; int next, ret = 0; int c, cabs; float delta_ts; sigset_t set, oldset; sigemptyset(&set); sigaddset(&set, SIGALRM); sigprocmask(SIG_BLOCK, &set, &oldset); switch (cassette_format) { case DEBUG_FORMAT: if (fscanf(cassette_file, "%d %lu\n", &next, &delta_us) == 2) { delta_ts = delta_us * z80_state.clockMHz - cassette_roundoff_error; cassette_delta = (unsigned long)(delta_ts + 0.5); cassette_roundoff_error = cassette_delta - delta_ts; cassette_next = next; #if CASSDEBUG debug("%d %4lu %d\n", cassette_value, cassette_delta, cassette_next); #endif ret = 1; } break; case CPT_FORMAT: c = get_twobyte(&code, cassette_file); if (c == -1) break; if (code == 0xffff) { c = getc(cassette_file); if (c == EOF) break; cassette_next = c; c = get_fourbyte(&d, cassette_file); if (c == -1) break; delta_us = d; } else { cassette_next = code & 3; delta_us = code >> 2; } delta_ts = delta_us * z80_state.clockMHz - cassette_roundoff_error; cassette_delta = (unsigned long)(delta_ts + 0.5); cassette_roundoff_error = cassette_delta - delta_ts; #if CASSDEBUG debug("%d %4lu %d\n", cassette_value, cassette_delta, cassette_next); #endif ret = 1; break; case DIRECT_FORMAT: case WAV_FORMAT: nsamples = 0; maxsamples = cassette_sample_rate / 100; do { int direct = (cassette_format == DIRECT_FORMAT); c = get_sample(direct, cassette_file); if (direct && cassette_stereo) { /* Discard right channel */ (void) get_sample(direct, cassette_file); } if (c == EOF) goto fail; if (c > 127 + cassette_noisefloor) { next = 1; } else if (c <= 127 - cassette_noisefloor) { next = 2; } else { next = 0; } if (cassette_speed == SPEED_1500) { cassette_noisefloor = 2; } else { /* Attempt to learn the correct noise cutoff adaptively. * This code is just a hack; it would be nice to know a * real signal-processing algorithm for this application */ cabs = abs(c - 127); #if CASSDEBUG2 debug("%f %f %d %d -> %d\n", cassette_avg, cassette_env, cassette_noisefloor, cabs, next); #endif if (cabs > 1) { cassette_avg = (99*cassette_avg + cabs)/100; } if (cabs > cassette_env) { cassette_env = (cassette_env + 9*cabs)/10; } else if (cabs > 10) { cassette_env = (99*cassette_env + cabs)/100; } cassette_noisefloor = (cassette_avg + cassette_env)/2; } nsamples++; /* Allow reset button */ trs_get_event(0); if (z80_state.nmi) break; } while (next == cassette_value && maxsamples-- > 0); cassette_next = next; delta_ts = nsamples * (1000000.0/cassette_sample_rate) * z80_state.clockMHz - cassette_roundoff_error; cassette_delta = (unsigned long) delta_ts + 0.5; cassette_roundoff_error = cassette_delta - delta_ts; #if CASSDEBUG debug("%3lu -> %d %4lu %d\n", nsamples, cassette_value, cassette_delta, cassette_next); #endif ret = 1; break; case CAS_FORMAT: if (cassette_pulsestate == 0) { cassette_bitnumber--; } if (cassette_bitnumber < 0) { c = getc(cassette_file); if (c == EOF) { /* Add one extra zero byte to work around an apparent bug in the Vavasour Model I emulator's .CAS files */ if (cassette_byte == 0x100) goto fail; c = 0x100; } cassette_byte = c; cassette_bitnumber = 7; } c = (cassette_byte >> cassette_bitnumber) & 1; delta_us = pulse_shape[cassette_speed][c][cassette_pulsestate].delta_us; cassette_next = pulse_shape[cassette_speed][c][cassette_pulsestate].next; cassette_pulsestate++; if (pulse_shape[cassette_speed][c][cassette_pulsestate].next == -1) { cassette_pulsestate = 0; /* Kludge to emulate extra delay that's needed after the initial 0xA5 sync byte to let Basic execute the CLEAR routine. */ if (cassette_byte == 0xa5 && cassette_speed == SPEED_500) { delta_us += 1034; } } delta_ts = delta_us * z80_state.clockMHz - cassette_roundoff_error; cassette_delta = (unsigned long)(delta_ts + 0.5); cassette_roundoff_error = cassette_delta - delta_ts; #if CASSDEBUG debug("%d %4lu %d\n", cassette_value, cassette_delta, cassette_next); #endif ret = 1; break; default: error("input format %s not implemented", cassette_format < (sizeof(format_name)/sizeof(char *)) ? format_name[cassette_format] : "out of range;"); break; } fail: if (ret == 0) { cassette_delta = (unsigned long) -1; } sigprocmask(SIG_SETMASK, &oldset, NULL); return ret; } /* If the motor has been on for 1 second (emulated time), the i/o port has been neither read nor written, and the Z-80 program has 1500 bps rise or fall interrupts enabled, then give it one of each just to get things going. */ void trs_cassette_kickoff(int dummy) { if (cassette_motor && cassette_state == CLOSE && trs_cassette_interrupts_enabled()) { cassette_speed = SPEED_1500; cassette_transition = z80_state.t_count; trs_cassette_fall_interrupt(1); trs_cassette_rise_interrupt(1); } } /* Z-80 program is turning motor on or off */ void trs_cassette_motor(int value) { if (value) { /* motor on */ if (!cassette_motor) { #if CASSDEBUG3 debug("motor on %ld\n", z80_state.t_count); #endif cassette_motor = 1; cassette_transition = z80_state.t_count; cassette_value = 0; cassette_next = 0; cassette_delta = 0; cassette_flipflop = 0; cassette_byte = 0; cassette_bitnumber = 0; cassette_pulsestate = 0; cassette_speed = SPEED_500; cassette_roundoff_error = 0.0; cassette_avg = NOISE_FLOOR; cassette_env = 127; cassette_noisefloor = NOISE_FLOOR; cassette_firstoutread = 0; cassette_transitionsout = 0; if (trs_model > 1) { /* Get 1500bps reading started after 1 second */ trs_schedule_event(trs_cassette_kickoff, 0, (tstate_t) (1000000 * z80_state.clockMHz)); } } } else { /* motor off */ if (cassette_motor) { if (cassette_state == WRITE) { transition_out(FLUSH); } assert_state(CLOSE); cassette_motor = 0; } } } void trs_cassette_out(int value) { #if CASSDEBUG3 debug("out %ld\n", z80_state.t_count); #endif if (cassette_motor) { if (cassette_state == READ) { trs_cassette_update(0); cassette_flipflop = 0; if (cassette_firstoutread == 0) { cassette_firstoutread = z80_state.t_count; } } if (cassette_state != READ && value != cassette_value) { if (assert_state(WRITE) < 0) return; transition_out(value); } } #if SB_SOUND /* Do sound emulation by wiggling SoundBlaster output in real time */ if ((cassette_motor == 0) && sb_address) { while (inb(sb_address + 0xC) & 0x80) /*poll*/ ; outb(0x10, sb_address + 0xC); while (inb(sb_address + 0xC) & 0x80) /*poll*/ ; outb(sb_cassette_volume[value], sb_address + 0xC); } #endif #if OSS_SOUND && HAVE_OSS /* Do sound emulation by sending samples to /dev/dsp */ if (cassette_motor == 0 && !sb_address) { if (cassette_state != SOUND && value == 0) return; if (assert_state(SOUND) < 0) return; trs_suspend_delay(); transition_out(value); } #endif } /* Model 4 sound port */ void trs_sound_out(int value) { #if SB_SOUND /* Do sound emulation */ if (sb_address) { while (inb(sb_address + 0xC) & 0x80) /*poll*/ ; outb(0x10, sb_address + 0xC); while (inb(sb_address + 0xC) & 0x80) /*poll*/ ; outb(sb_sound_volume[value], sb_address + 0xC); } #endif #if HAVE_OSS if (cassette_motor == 0 && !sb_address) { if (assert_state(SOUND) < 0) return; trs_suspend_delay(); transition_out(value ? 1 : 2); } #endif } static void orch90_flush(int dummy) { trs_orch90_out(0, FLUSH); } /* Orchestra 85/90 */ /* Not supported in obsolescent SB_SOUND mode */ /* Implementation shares some global state with cassette and game sound implementations. */ void trs_orch90_out(int channels, int value) { #if HAVE_OSS long nsamples; float ddelta_us; sigset_t set, oldset; int new_left, new_right; int v; /* Convert 8-bit signed to 8-bit unsigned */ v = (value & 0xff) ^ 0x80; if (cassette_motor != 0) return; if (assert_state(ORCH90) < 0) return; trs_suspend_delay(); if (channels & 1) { new_left = v; } else { new_left = orch90_left; } if (channels & 2) { new_right = v; } else { new_right = orch90_right; } if (value != FLUSH && new_left == orch90_left && new_right == orch90_right) return; sigemptyset(&set); sigaddset(&set, SIGALRM); sigprocmask(SIG_BLOCK, &set, &oldset); ddelta_us = (z80_state.t_count - cassette_transition) / z80_state.clockMHz - cassette_roundoff_error; if (ddelta_us > 300000.0) { /* Truncate silent periods */ ddelta_us = 300000.0; } nsamples = (unsigned long) (ddelta_us / (1000000.0/cassette_sample_rate) + 0.5); cassette_roundoff_error = nsamples * (1000000.0/cassette_sample_rate) - ddelta_us; while (nsamples-- > 0) { put_sample(orch90_left, TRUE, cassette_file); put_sample(orch90_right, TRUE, cassette_file); } if (trs_event_scheduled() == orch90_flush || trs_event_scheduled() == (trs_event_func) assert_state) { trs_cancel_event(); } if (value == FLUSH) { trs_schedule_event((trs_event_func)assert_state, CLOSE, 5000000); } else { trs_schedule_event(orch90_flush, FLUSH, (int)(250000 * z80_state.clockMHz)); } sigprocmask(SIG_SETMASK, &oldset, NULL); last_sound = z80_state.t_count; cassette_transition = z80_state.t_count; orch90_left = new_left; orch90_right = new_right; #endif } void trs_cassette_update(int dummy) { if (cassette_motor && cassette_state != WRITE && assert_state(READ) >= 0) { int newtrans = 0; while ((z80_state.t_count - cassette_transition) >= cassette_delta) { /* Simulate analog signal processing on the 500-bps cassette input */ if (cassette_next != 0 && cassette_value == 0) { cassette_flipflop = 0x80; } /* Deliver the previously read transition from the file */ cassette_value = cassette_next; cassette_transition += cassette_delta; /* Remember last nonzero value to get hysteresis in 1500 bps zero-crossing detector */ if (cassette_value != 0) cassette_lastnonzero = cassette_value; /* Read the next transition */ newtrans = transition_in(); /* Allow reset button */ trs_get_event(0); if (z80_state.nmi) return; } /* Schedule an interrupt on the 1500-bps cassette input if needed */ if (newtrans && cassette_speed == SPEED_1500) { if (cassette_next == 2 && cassette_lastnonzero != 2) { trs_schedule_event(trs_cassette_fall_interrupt, 1, cassette_delta - (z80_state.t_count - cassette_transition)); } else if (cassette_next == 1 && cassette_lastnonzero != 1) { trs_schedule_event(trs_cassette_rise_interrupt, 1, cassette_delta - (z80_state.t_count - cassette_transition)); } else { trs_schedule_event(trs_cassette_update, 0, cassette_delta - (z80_state.t_count - cassette_transition)); } } } } int trs_cassette_in() { #if CASSDEBUG3 debug("in %ld\n", z80_state.t_count); #endif if (cassette_motor && cassette_transitionsout <= 1) { assert_state(READ); } /* Heuristic to detect reading with Level 1 routines. If the routine paused too long after resetting the flipflop before reading it again, assume it must be Level 1 code. */ if (cassette_firstoutread > 1) { if ((z80_state.t_count - cassette_firstoutread) / z80_state.clockMHz > DETECT_250) { cassette_speed = SPEED_250; } else { cassette_speed = SPEED_500; } #if CASSDEBUG4 debug("250 detector = %s (%f)\n", (cassette_speed == SPEED_250) ? "yes" : "no", (z80_state.t_count - cassette_firstoutread) / z80_state.clockMHz); #endif cassette_firstoutread = 1; /* disable detector */ } trs_cassette_clear_interrupts(); trs_cassette_update(0); if (trs_model == 1) { return cassette_flipflop; } else { return cassette_flipflop | (cassette_lastnonzero == 1); } } void trs_cassette_reset() { assert_state(CLOSE); } void trs_sound_init(int ioport, int vol) { #if SB_SOUND /* try to initialize SoundBlaster. Usual ioport is 0x220 */ #define MAX_TRIES 65536 int tries; #ifdef SOUNDDEBUG int major, minor; #endif if (sb_address != 0) return; if ((ioport & 0xFFFFFF0F) != 0x200) { error("Invalid SoundBlaster I/O port"); return; } sb_address = ioport; if (ioperm(ioport, 0x10, 1)) { error("unable to access SoundBlaster I/O ports: %s", strerror(errno)); sb_address = 0; return; } /* Reset SoundBlaster DSP */ outb(0x01, sb_address + 0x6); usleep(3); outb(0x00, sb_address + 0x6); for (tries = 0; tries < MAX_TRIES; tries++) { if ((inb(sb_address + 0xE) & 0x80) && (inb(sb_address + 0xA) == 0xAA)) break; } if (tries == MAX_TRIES) { error("unable to detect SoundBlaster"); sb_address = 0; return; } #ifdef SOUNDDEBUG /* Get DSP version number */ while (inb(sb_address + 0xC) & 0x80) /*poll*/ ; outb(0xE1, sb_address + 0xC); while ((inb(sb_address + 0xE) & 0x80) == 0) /*poll*/ ; major = inb(sb_address + 0xA); while ((inb(sb_address + 0xE) & 0x80) == 0) /*poll*/ ; minor = inb(sb_address + 0xA); debug("SoundBlaster DSP version %d.%d detected\n", major, minor); #endif /* Turn on DAC speaker */ while (inb(sb_address + 0xC) & 0x80) /*poll*/ ; outb(0xD1, sb_address + 0xC); sb_set_volume(vol); #else /*!SB_SOUND*/ error("xtrs: -sb is obsolete; see the man page"); #endif } void sb_set_volume(int vol) { #if SB_SOUND if (sb_address == 0) return; /* Set up volume values */ if (vol < 0) vol = 0; if (vol > 100) vol = 100; sb_volume = vol; /* Values in comments from Model I technical manual. Model III/4 used a different value for one resistor in the network, so these voltages are not exactly right. In particular 3 and 0 are no longer almost identical, but as far as I know, 3 is still unused. */ sb_cassette_volume[0] = (vol*255)/200; /* 0.46 V */ sb_cassette_volume[1] = (vol*255)/100; /* 0.85 V */ sb_cassette_volume[2] = 0; /* 0.00 V */ sb_cassette_volume[3] = (vol*255)/200; /* unused, but about 0.46 V */ sb_sound_volume[0] = 0; sb_sound_volume[1] = (vol*255)/100; #endif } int sb_get_volume() { return sb_volume; } xtrs-4.9d/trs_chars.c000066400000000000000000004461721306603614600147110ustar00rootroot00000000000000/* * trs_chars.c * $Id: trs_chars.c,v 1.9 2008/06/26 04:39:56 mann Exp $ * * This file contains the bitmap data for all 256 characters in the * TRS-80 character set, for both Model I and Model III/4. Thanks to * Al Petrofsky for supplying some of the data in .bdf format. Thanks * to Todd P. Cromwell III for supplying exact dumps of two different * Model III character generator ROMs. */ #include "trs_iodefs.h" char trs_char_data[][MAXCHARS][TRS_CHAR_HEIGHT] = { { /* CG 0 - for Model I */ /* Source: MCM6674 Data Sheet */ /* This is a very old version of the Model I font, found in only a few machines, that has standard ASCII [ \ ] ^ instead of directional arrows. It also has odd symbols in positions 0-31, and the lowercase letters with descenders (plus 'a') are raised. Level II Basic put the odd symbols on the screen instead of uppercase if you did a homebrew lowercase conversion and did not replace the CG. */ { 0x00,0x1f,0x11,0x11,0x11,0x11,0x11,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x04,0x08,0x1e,0x04,0x08,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x11,0x1b,0x15,0x1b,0x11,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x10,0x08,0x05,0x03,0x01,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x11,0x1f,0x0a,0x0a,0x1b,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x02,0x0f,0x12,0x14,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x04,0x08,0x1f,0x08,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x00,0x00,0x1f,0x00,0x00,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x04,0x04,0x15,0x0e,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x15,0x0e,0x04,0x15,0x0e,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x04,0x02,0x1f,0x02,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x1b,0x15,0x1b,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x11,0x15,0x11,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x11,0x11,0x1f,0x11,0x11,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x15,0x15,0x1d,0x11,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x11,0x1d,0x15,0x15,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x11,0x17,0x15,0x15,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x15,0x15,0x17,0x11,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x14,0x08,0x15,0x03,0x01,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x0a,0x0a,0x0a,0x0a,0x0a,0x1b,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x10,0x1f,0x10,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x11,0x0a,0x04,0x0a,0x11,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x04,0x0e,0x0e,0x04,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x01,0x02,0x04,0x00,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x11,0x1f,0x11,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x15,0x15,0x17,0x11,0x11,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x11,0x11,0x17,0x15,0x15,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x11,0x11,0x1d,0x15,0x15,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x15,0x15,0x1d,0x11,0x11,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x04,0x04,0x04,0x04,0x00,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x0a,0x0a,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x0a,0x0a,0x1f,0x0a,0x1f,0x0a,0x0a,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x1e,0x05,0x0e,0x14,0x0f,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x03,0x13,0x08,0x04,0x02,0x19,0x18,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x05,0x05,0x02,0x15,0x09,0x16,0x00,0x00,0x00,0x00 }, { 0x00,0x06,0x06,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x04,0x02,0x02,0x02,0x04,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x04,0x08,0x08,0x08,0x04,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x15,0x0e,0x1f,0x0e,0x15,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x04,0x04,0x1f,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x06,0x06,0x02,0x01,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x06,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x10,0x08,0x04,0x02,0x01,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x19,0x15,0x13,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x06,0x04,0x04,0x04,0x04,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x10,0x0e,0x01,0x01,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x10,0x0c,0x10,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x0c,0x0a,0x09,0x1f,0x08,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x01,0x0f,0x10,0x10,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x02,0x01,0x0f,0x11,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x10,0x08,0x04,0x02,0x01,0x01,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x11,0x0e,0x11,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x11,0x1e,0x10,0x08,0x06,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x06,0x06,0x00,0x06,0x06,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x06,0x06,0x00,0x06,0x06,0x02,0x01,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x04,0x02,0x01,0x02,0x04,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x1f,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x04,0x08,0x10,0x08,0x04,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x10,0x08,0x04,0x00,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x10,0x16,0x15,0x15,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x0a,0x11,0x11,0x1f,0x11,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x0f,0x12,0x12,0x0e,0x12,0x12,0x0f,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x01,0x01,0x01,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0f,0x12,0x12,0x12,0x12,0x12,0x0f,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x01,0x01,0x07,0x01,0x01,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x01,0x01,0x07,0x01,0x01,0x01,0x00,0x00,0x00,0x00 }, { 0x00,0x1e,0x01,0x01,0x19,0x11,0x11,0x1e,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x11,0x11,0x1f,0x11,0x11,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x04,0x04,0x04,0x04,0x04,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x10,0x10,0x10,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x09,0x05,0x03,0x05,0x09,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x1b,0x15,0x15,0x11,0x11,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x13,0x15,0x19,0x11,0x11,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x11,0x11,0x11,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0f,0x11,0x11,0x0f,0x01,0x01,0x01,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x11,0x11,0x15,0x09,0x16,0x00,0x00,0x00,0x00 }, { 0x00,0x0f,0x11,0x11,0x0f,0x05,0x09,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x01,0x0e,0x10,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x04,0x04,0x04,0x04,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x11,0x11,0x11,0x11,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x11,0x11,0x0a,0x0a,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x11,0x11,0x11,0x15,0x1b,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x11,0x0a,0x04,0x0a,0x11,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x11,0x0a,0x04,0x04,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x10,0x08,0x04,0x02,0x01,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x02,0x02,0x02,0x02,0x02,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x08,0x08,0x08,0x08,0x08,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x0a,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x0c,0x04,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x10,0x1e,0x11,0x1e,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x01,0x01,0x0d,0x13,0x11,0x13,0x0d,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x0e,0x11,0x01,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x16,0x19,0x11,0x19,0x16,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x0e,0x11,0x1f,0x01,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x14,0x04,0x0e,0x04,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x16,0x19,0x19,0x16,0x10,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x01,0x01,0x0d,0x13,0x11,0x11,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x00,0x06,0x04,0x04,0x04,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x00,0x10,0x10,0x10,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x01,0x01,0x09,0x05,0x03,0x05,0x09,0x00,0x00,0x00,0x00 }, { 0x00,0x06,0x04,0x04,0x04,0x04,0x04,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x0b,0x15,0x15,0x15,0x15,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x0d,0x13,0x11,0x11,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x0e,0x11,0x11,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0d,0x13,0x11,0x13,0x0d,0x01,0x01,0x00,0x00,0x00,0x00 }, { 0x00,0x16,0x19,0x11,0x19,0x16,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x0d,0x13,0x01,0x01,0x01,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x1e,0x01,0x0e,0x10,0x0f,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x04,0x1f,0x04,0x04,0x14,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x11,0x11,0x11,0x19,0x16,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x11,0x11,0x11,0x0a,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x11,0x11,0x15,0x15,0x0a,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x11,0x0a,0x04,0x0a,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x11,0x11,0x1e,0x10,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x1f,0x08,0x04,0x02,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x04,0x04,0x02,0x04,0x04,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x04,0x04,0x00,0x04,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x04,0x04,0x08,0x04,0x04,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x15,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x0a,0x15,0x0a,0x15,0x0a,0x15,0x0a,0x00,0x00,0x00,0x00 }, }, { /* CG 1 - for Model I */ /* Source: MCM6674 Data Sheet, modified by mann (from memory) to add arrows. */ /* This is the standard Model I character generator found in machines without the Radio Shack lower case modification, including the arrows. It has odd symbols in positions 0-31, and lowercase letters with descenders (plus 'a') are raised. Level II Basic put the odd symbols on the screen if you did a homebrew lowercase conversion and did not replace the CG. */ { 0x00,0x1f,0x11,0x11,0x11,0x11,0x11,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x04,0x08,0x1e,0x04,0x08,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x11,0x1b,0x15,0x1b,0x11,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x10,0x08,0x05,0x03,0x01,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x11,0x1f,0x0a,0x0a,0x1b,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x02,0x0f,0x12,0x14,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x04,0x08,0x1f,0x08,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x00,0x00,0x1f,0x00,0x00,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x04,0x04,0x15,0x0e,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x15,0x0e,0x04,0x15,0x0e,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x04,0x02,0x1f,0x02,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x1b,0x15,0x1b,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x11,0x15,0x11,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x11,0x11,0x1f,0x11,0x11,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x15,0x15,0x1d,0x11,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x11,0x1d,0x15,0x15,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x11,0x17,0x15,0x15,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x15,0x15,0x17,0x11,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x14,0x08,0x15,0x03,0x01,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x0a,0x0a,0x0a,0x0a,0x0a,0x1b,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x10,0x1f,0x10,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x11,0x0a,0x04,0x0a,0x11,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x04,0x0e,0x0e,0x04,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x01,0x02,0x04,0x00,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x11,0x1f,0x11,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x15,0x15,0x17,0x11,0x11,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x11,0x11,0x17,0x15,0x15,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x11,0x11,0x1d,0x15,0x15,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x15,0x15,0x1d,0x11,0x11,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x04,0x04,0x04,0x04,0x00,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x0a,0x0a,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x0a,0x0a,0x1f,0x0a,0x1f,0x0a,0x0a,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x1e,0x05,0x0e,0x14,0x0f,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x03,0x13,0x08,0x04,0x02,0x19,0x18,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x05,0x05,0x02,0x15,0x09,0x16,0x00,0x00,0x00,0x00 }, { 0x00,0x06,0x06,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x04,0x02,0x02,0x02,0x04,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x04,0x08,0x08,0x08,0x04,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x15,0x0e,0x1f,0x0e,0x15,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x04,0x04,0x1f,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x06,0x06,0x02,0x01,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x06,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x10,0x08,0x04,0x02,0x01,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x19,0x15,0x13,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x06,0x04,0x04,0x04,0x04,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x10,0x0e,0x01,0x01,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x10,0x0c,0x10,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x0c,0x0a,0x09,0x1f,0x08,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x01,0x0f,0x10,0x10,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x02,0x01,0x0f,0x11,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x10,0x08,0x04,0x02,0x01,0x01,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x11,0x0e,0x11,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x11,0x1e,0x10,0x08,0x06,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x06,0x06,0x00,0x06,0x06,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x06,0x06,0x00,0x06,0x06,0x02,0x01,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x04,0x02,0x01,0x02,0x04,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x1f,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x04,0x08,0x10,0x08,0x04,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x10,0x08,0x04,0x00,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x10,0x16,0x15,0x15,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x0a,0x11,0x11,0x1f,0x11,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x0f,0x12,0x12,0x0e,0x12,0x12,0x0f,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x01,0x01,0x01,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0f,0x12,0x12,0x12,0x12,0x12,0x0f,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x01,0x01,0x07,0x01,0x01,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x01,0x01,0x07,0x01,0x01,0x01,0x00,0x00,0x00,0x00 }, { 0x00,0x1e,0x01,0x01,0x19,0x11,0x11,0x1e,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x11,0x11,0x1f,0x11,0x11,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x04,0x04,0x04,0x04,0x04,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x10,0x10,0x10,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x09,0x05,0x03,0x05,0x09,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x1b,0x15,0x15,0x11,0x11,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x13,0x15,0x19,0x11,0x11,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x11,0x11,0x11,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0f,0x11,0x11,0x0f,0x01,0x01,0x01,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x11,0x11,0x15,0x09,0x16,0x00,0x00,0x00,0x00 }, { 0x00,0x0f,0x11,0x11,0x0f,0x05,0x09,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x11,0x01,0x0e,0x10,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x04,0x04,0x04,0x04,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x11,0x11,0x11,0x11,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x11,0x11,0x0a,0x0a,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x11,0x11,0x11,0x15,0x1b,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x11,0x0a,0x04,0x0a,0x11,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x11,0x0a,0x04,0x04,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x10,0x08,0x04,0x02,0x01,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x0e,0x15,0x04,0x04,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x04,0x04,0x04,0x15,0x0e,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x04,0x02,0x1f,0x02,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x04,0x08,0x1f,0x08,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x0c,0x04,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x10,0x1e,0x11,0x1e,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x01,0x01,0x0d,0x13,0x11,0x13,0x0d,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x0e,0x11,0x01,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x16,0x19,0x11,0x19,0x16,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x0e,0x11,0x1f,0x01,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x14,0x04,0x0e,0x04,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x16,0x19,0x19,0x16,0x10,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x01,0x01,0x0d,0x13,0x11,0x11,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x00,0x06,0x04,0x04,0x04,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x00,0x10,0x10,0x10,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x01,0x01,0x09,0x05,0x03,0x05,0x09,0x00,0x00,0x00,0x00 }, { 0x00,0x06,0x04,0x04,0x04,0x04,0x04,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x0b,0x15,0x15,0x15,0x15,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x0d,0x13,0x11,0x11,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x0e,0x11,0x11,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x0d,0x13,0x11,0x13,0x0d,0x01,0x01,0x00,0x00,0x00,0x00 }, { 0x00,0x16,0x19,0x11,0x19,0x16,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x0d,0x13,0x01,0x01,0x01,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x1e,0x01,0x0e,0x10,0x0f,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x04,0x1f,0x04,0x04,0x14,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x11,0x11,0x11,0x19,0x16,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x11,0x11,0x11,0x0a,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x11,0x11,0x15,0x15,0x0a,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x11,0x0a,0x04,0x0a,0x11,0x00,0x00,0x00,0x00 }, { 0x00,0x11,0x11,0x11,0x1e,0x10,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x1f,0x08,0x04,0x02,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x04,0x04,0x02,0x04,0x04,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x04,0x04,0x00,0x04,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x04,0x04,0x08,0x04,0x04,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x15,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x0a,0x15,0x0a,0x15,0x0a,0x15,0x0a,0x00,0x00,0x00,0x00 }, }, { /* CG 2 - for Model I */ /* Source: MCM6674 Data Sheet, modified by mann (from memory). */ /* This is the replacement Model I character generator you got with the Radio Shack lowercase modification. Positions 0-31 are a copy of the uppercase letters, to work around a bug (?) in the Level II ROM. All characters without descenders are moved up one row. I'm not sure I got all the changes exactly right -- help? */ { 0x0e,0x11,0x10,0x16,0x15,0x15,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x0a,0x11,0x11,0x1f,0x11,0x11,0x00,0x00,0x00,0x00,0x00 }, { 0x0f,0x12,0x12,0x0e,0x12,0x12,0x0f,0x00,0x00,0x00,0x00,0x00 }, { 0x0e,0x11,0x01,0x01,0x01,0x11,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x0f,0x12,0x12,0x12,0x12,0x12,0x0f,0x00,0x00,0x00,0x00,0x00 }, { 0x1f,0x01,0x01,0x07,0x01,0x01,0x1f,0x00,0x00,0x00,0x00,0x00 }, { 0x1f,0x01,0x01,0x07,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00 }, { 0x1e,0x01,0x01,0x19,0x11,0x11,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x11,0x11,0x11,0x1f,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00 }, { 0x0e,0x04,0x04,0x04,0x04,0x04,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x10,0x10,0x10,0x11,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x11,0x09,0x05,0x03,0x05,0x09,0x11,0x00,0x00,0x00,0x00,0x00 }, { 0x01,0x01,0x01,0x01,0x01,0x01,0x1f,0x00,0x00,0x00,0x00,0x00 }, { 0x11,0x1b,0x15,0x15,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00 }, { 0x11,0x13,0x15,0x19,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00 }, { 0x0e,0x11,0x11,0x11,0x11,0x11,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x0f,0x11,0x11,0x0f,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00 }, { 0x0e,0x11,0x11,0x11,0x15,0x09,0x16,0x00,0x00,0x00,0x00,0x00 }, { 0x0f,0x11,0x11,0x0f,0x05,0x09,0x11,0x00,0x00,0x00,0x00,0x00 }, { 0x0e,0x11,0x01,0x0e,0x10,0x11,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x1f,0x04,0x04,0x04,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x11,0x11,0x11,0x11,0x11,0x11,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x11,0x11,0x11,0x0a,0x0a,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x11,0x11,0x11,0x11,0x15,0x1b,0x11,0x00,0x00,0x00,0x00,0x00 }, { 0x11,0x11,0x0a,0x04,0x0a,0x11,0x11,0x00,0x00,0x00,0x00,0x00 }, { 0x11,0x11,0x0a,0x04,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x1f,0x10,0x08,0x04,0x02,0x01,0x1f,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x0e,0x15,0x04,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x04,0x04,0x04,0x15,0x0e,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x02,0x1f,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x08,0x1f,0x08,0x04,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x04,0x04,0x04,0x04,0x00,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x0a,0x0a,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x0a,0x0a,0x1f,0x0a,0x1f,0x0a,0x0a,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x1e,0x05,0x0e,0x14,0x0f,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x03,0x13,0x08,0x04,0x02,0x19,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x02,0x05,0x05,0x02,0x15,0x09,0x16,0x00,0x00,0x00,0x00,0x00 }, { 0x06,0x06,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x04,0x02,0x02,0x02,0x04,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x02,0x04,0x08,0x08,0x08,0x04,0x02,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x15,0x0e,0x1f,0x0e,0x15,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x04,0x1f,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x06,0x06,0x02,0x01,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x06,0x06,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x08,0x04,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x0e,0x11,0x19,0x15,0x13,0x11,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x06,0x04,0x04,0x04,0x04,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x0e,0x11,0x10,0x0e,0x01,0x01,0x1f,0x00,0x00,0x00,0x00,0x00 }, { 0x0e,0x11,0x10,0x0c,0x10,0x11,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x0c,0x0a,0x09,0x1f,0x08,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x1f,0x01,0x0f,0x10,0x10,0x11,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x02,0x01,0x0f,0x11,0x11,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x1f,0x10,0x08,0x04,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00 }, { 0x0e,0x11,0x11,0x0e,0x11,0x11,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x0e,0x11,0x11,0x1e,0x10,0x08,0x06,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x06,0x06,0x00,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x06,0x06,0x00,0x06,0x06,0x02,0x01,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x04,0x02,0x01,0x02,0x04,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x1f,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x02,0x04,0x08,0x10,0x08,0x04,0x02,0x00,0x00,0x00,0x00,0x00 }, { 0x0e,0x11,0x10,0x08,0x04,0x00,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x0e,0x11,0x10,0x16,0x15,0x15,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x0a,0x11,0x11,0x1f,0x11,0x11,0x00,0x00,0x00,0x00,0x00 }, { 0x0f,0x12,0x12,0x0e,0x12,0x12,0x0f,0x00,0x00,0x00,0x00,0x00 }, { 0x0e,0x11,0x01,0x01,0x01,0x11,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x0f,0x12,0x12,0x12,0x12,0x12,0x0f,0x00,0x00,0x00,0x00,0x00 }, { 0x1f,0x01,0x01,0x07,0x01,0x01,0x1f,0x00,0x00,0x00,0x00,0x00 }, { 0x1f,0x01,0x01,0x07,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00 }, { 0x1e,0x01,0x01,0x19,0x11,0x11,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x11,0x11,0x11,0x1f,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00 }, { 0x0e,0x04,0x04,0x04,0x04,0x04,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x10,0x10,0x10,0x11,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x11,0x09,0x05,0x03,0x05,0x09,0x11,0x00,0x00,0x00,0x00,0x00 }, { 0x01,0x01,0x01,0x01,0x01,0x01,0x1f,0x00,0x00,0x00,0x00,0x00 }, { 0x11,0x1b,0x15,0x15,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00 }, { 0x11,0x13,0x15,0x19,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00 }, { 0x0e,0x11,0x11,0x11,0x11,0x11,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x0f,0x11,0x11,0x0f,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00 }, { 0x0e,0x11,0x11,0x11,0x15,0x09,0x16,0x00,0x00,0x00,0x00,0x00 }, { 0x0f,0x11,0x11,0x0f,0x05,0x09,0x11,0x00,0x00,0x00,0x00,0x00 }, { 0x0e,0x11,0x01,0x0e,0x10,0x11,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x1f,0x04,0x04,0x04,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x11,0x11,0x11,0x11,0x11,0x11,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x11,0x11,0x11,0x0a,0x0a,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x11,0x11,0x11,0x11,0x15,0x1b,0x11,0x00,0x00,0x00,0x00,0x00 }, { 0x11,0x11,0x0a,0x04,0x0a,0x11,0x11,0x00,0x00,0x00,0x00,0x00 }, { 0x11,0x11,0x0a,0x04,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x1f,0x10,0x08,0x04,0x02,0x01,0x1f,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x0e,0x15,0x04,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x04,0x04,0x04,0x15,0x0e,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x02,0x1f,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x08,0x1f,0x08,0x04,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x0c,0x04,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x0e,0x10,0x1e,0x11,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x01,0x01,0x0d,0x13,0x11,0x13,0x0d,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x0e,0x11,0x01,0x11,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x16,0x19,0x11,0x19,0x16,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x0e,0x11,0x1f,0x01,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x14,0x04,0x0e,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x16,0x19,0x19,0x16,0x10,0x0e,0x00,0x00,0x00,0x00 }, { 0x01,0x01,0x0d,0x13,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x00,0x06,0x04,0x04,0x04,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x00,0x10,0x10,0x10,0x10,0x11,0x0e,0x00,0x00,0x00,0x00 }, { 0x01,0x01,0x09,0x05,0x03,0x05,0x09,0x00,0x00,0x00,0x00,0x00 }, { 0x06,0x04,0x04,0x04,0x04,0x04,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x0b,0x15,0x15,0x15,0x15,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x0d,0x13,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x0e,0x11,0x11,0x11,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x0d,0x13,0x13,0x0d,0x01,0x01,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x16,0x19,0x19,0x16,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x0d,0x13,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x1e,0x01,0x0e,0x10,0x0f,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x04,0x1f,0x04,0x04,0x14,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x11,0x11,0x11,0x19,0x16,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x11,0x11,0x11,0x0a,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x11,0x11,0x15,0x15,0x0a,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x11,0x0a,0x04,0x0a,0x11,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x11,0x11,0x11,0x1e,0x10,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x1f,0x08,0x04,0x02,0x1f,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x04,0x04,0x02,0x04,0x04,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x04,0x04,0x00,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x02,0x04,0x04,0x08,0x04,0x04,0x02,0x00,0x00,0x00,0x00,0x00 }, { 0x02,0x15,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x0a,0x15,0x0a,0x15,0x0a,0x15,0x0a,0x00,0x00,0x00,0x00,0x00 }, }, { /* CG 3 - for Model I */ /* Source: BDF font from Al Petrofsky, probably adapted from another emulator. This is not the real Model I font, which used a 6x12 matrix; it seems to be a modified version of the 8x12 Model III font. */ { 0x7c,0x82,0x80,0x8c,0x92,0x92,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x48,0x84,0x84,0xfc,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x88,0x88,0x78,0x88,0x88,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x04,0x04,0x04,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x88,0x88,0x88,0x88,0x88,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0xfc,0x04,0x04,0x3c,0x04,0x04,0xfc,0x00,0x00,0x00,0x00,0x00 }, { 0xfc,0x04,0x04,0x3c,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0xf8,0x04,0x04,0xe4,0x84,0x84,0xf8,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x84,0x84,0xfc,0x84,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x80,0x80,0x80,0x80,0x80,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x44,0x24,0x1c,0x24,0x44,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x04,0x04,0x04,0x04,0x04,0xfc,0x00,0x00,0x00,0x00,0x00 }, { 0x82,0xc6,0xaa,0x92,0x82,0x82,0x82,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x8c,0x94,0xa4,0xc4,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x84,0x84,0x7c,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x84,0x84,0xa4,0x44,0xb8,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x84,0x84,0x7c,0x24,0x44,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x04,0x78,0x80,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0xfe,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x82,0x82,0x82,0x82,0x44,0x28,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x82,0x82,0x82,0x92,0xaa,0xc6,0x82,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x84,0x48,0x30,0x48,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x82,0x82,0x44,0x38,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0xfe,0x40,0x20,0x10,0x08,0x04,0xfe,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x54,0x92,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x10,0x92,0x54,0x38,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x04,0xfe,0x04,0x08,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x40,0xfe,0x40,0x20,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x10,0x10,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x48,0x48,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x48,0x48,0xfc,0x48,0xfc,0x48,0x48,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0xfc,0x12,0x7c,0x90,0x7e,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x8c,0x40,0x20,0x10,0x08,0xc4,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x44,0x28,0x18,0xa4,0x44,0xb8,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x30,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x20,0x10,0x08,0x08,0x08,0x10,0x20,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x20,0x20,0x20,0x10,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x54,0x38,0xfe,0x38,0x54,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x7c,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x30,0x30,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x40,0x20,0x10,0x08,0x04,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0xc4,0xa4,0x94,0x8c,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x18,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x80,0x78,0x04,0x04,0xfc,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x80,0x70,0x80,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x40,0x60,0x50,0x48,0xfc,0x40,0x40,0x00,0x00,0x00,0x00,0x00 }, { 0xfc,0x04,0x7c,0x80,0x80,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x70,0x08,0x04,0x7c,0x84,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0xfc,0x80,0x40,0x20,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x84,0x78,0x84,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x84,0xf8,0x80,0x40,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x30,0x00,0x00,0x30,0x30,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0xfc,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x40,0x30,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x82,0x80,0x8c,0x92,0x92,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x48,0x84,0x84,0xfc,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x88,0x88,0x78,0x88,0x88,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x04,0x04,0x04,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x88,0x88,0x88,0x88,0x88,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0xfc,0x04,0x04,0x3c,0x04,0x04,0xfc,0x00,0x00,0x00,0x00,0x00 }, { 0xfc,0x04,0x04,0x3c,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0xf8,0x04,0x04,0xe4,0x84,0x84,0xf8,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x84,0x84,0xfc,0x84,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x80,0x80,0x80,0x80,0x80,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x44,0x24,0x1c,0x24,0x44,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x04,0x04,0x04,0x04,0x04,0xfc,0x00,0x00,0x00,0x00,0x00 }, { 0x82,0xc6,0xaa,0x92,0x82,0x82,0x82,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x8c,0x94,0xa4,0xc4,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x84,0x84,0x7c,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x84,0x84,0xa4,0x44,0xb8,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x84,0x84,0x7c,0x24,0x44,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x04,0x78,0x80,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0xfe,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x82,0x82,0x82,0x82,0x44,0x28,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x82,0x82,0x82,0x92,0xaa,0xc6,0x82,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x84,0x48,0x30,0x48,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x82,0x82,0x44,0x38,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0xfe,0x40,0x20,0x10,0x08,0x04,0xfe,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x54,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x10,0x10,0x54,0x38,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x04,0xfe,0x04,0x08,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x40,0xfe,0x40,0x20,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0x00 }, { 0x30,0x48,0x08,0x1c,0x08,0x88,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x78,0x80,0xf8,0x84,0xf8,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x04,0x74,0x8c,0x84,0x8c,0x74,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x78,0x84,0x04,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x80,0x80,0xb8,0xc4,0x84,0xc4,0xb8,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x78,0x84,0xfc,0x04,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x70,0x88,0x08,0x1c,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x78,0x84,0x84,0xf8,0x80,0x78,0x00,0x00,0x00,0x00 }, { 0x04,0x04,0x74,0x8c,0x84,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x00,0x18,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x80,0x00,0xc0,0x80,0x80,0x84,0x84,0x78,0x00,0x00,0x00,0x00 }, { 0x04,0x04,0x84,0x44,0x3c,0x44,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x18,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x6e,0x92,0x92,0x92,0x82,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x74,0x8c,0x84,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x78,0x84,0x84,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x74,0x8c,0x8c,0x74,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0xb8,0xc4,0xc4,0xb8,0x80,0x80,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x74,0x8c,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0xf8,0x04,0x78,0x80,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x7c,0x10,0x10,0x90,0x60,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x44,0x44,0x44,0x44,0xb8,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x82,0x82,0x44,0x28,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x82,0x92,0x92,0x92,0x6c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x84,0x48,0x30,0x48,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x84,0x84,0x84,0xf8,0x80,0x78,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x7c,0x20,0x10,0x08,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x60,0x10,0x10,0x0c,0x10,0x10,0x60,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x10,0x00,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x10,0x10,0x60,0x10,0x10,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x82,0x44,0x38,0xfe,0x10,0xfe,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0xaa,0x54,0xaa,0x54,0xaa,0x54,0xaa,0x54,0x00,0x00,0x00,0x00 }, }, { /* CG 4 - for Model III */ /* Source: A model III CG ROM, read by Todd P. Cromwell III (todd2.bin) */ /* This is the older CG with Katakana alternate characters */ /* Letters start at top of cell, Model III style */ { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x48,0x08,0x3e,0x08,0x48,0x3e,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x20,0x10,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x00,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x10,0x28,0x44,0x7c,0x44,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7e,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x28,0x00,0x38,0x44,0x44,0x44,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0xb8,0x44,0x64,0x54,0x4c,0x44,0x3a,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x4c,0x32,0x00,0x34,0x4c,0x44,0x44,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x20,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x1c,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x5e,0x22,0x22,0x1e,0x12,0x22,0x00,0x00,0x00,0x00,0x00 }, { 0x28,0x00,0x10,0x28,0x44,0x7c,0x44,0x00,0x00,0x00,0x00,0x00 }, { 0x4c,0x32,0x10,0x28,0x44,0x7c,0x44,0x00,0x00,0x00,0x00,0x00 }, { 0x4c,0x32,0x44,0x4c,0x54,0x64,0x44,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x28,0x38,0x44,0x44,0x44,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x90,0x68,0x64,0x54,0x4c,0x2c,0x12,0x00,0x00,0x00,0x00,0x00 }, { 0x4c,0x32,0x00,0x3c,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x44,0x44,0x3c,0x44,0x44,0x3e,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x00,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x4c,0x32,0x00,0x18,0x24,0x24,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x54,0x50,0x38,0x14,0x54,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x14,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x08,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x02,0x3e,0x42,0x7c,0x40,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x20,0x10,0x7c,0x04,0x7c,0x04,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x78,0x24,0x64,0x3c,0x24,0x64,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x44,0x04,0x04,0x44,0x38,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x4c,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x10,0x10,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x24,0x7e,0x24,0x7e,0x24,0x24,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x78,0x14,0x38,0x50,0x3c,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x46,0x26,0x10,0x08,0x64,0x62,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x12,0x12,0x0c,0x52,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x20,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x20,0x10,0x08,0x08,0x08,0x10,0x20,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x08,0x10,0x10,0x10,0x08,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x54,0x38,0x7c,0x38,0x54,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x7c,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x40,0x20,0x10,0x08,0x04,0x02,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x62,0x5a,0x46,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x18,0x14,0x10,0x10,0x10,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x40,0x30,0x0c,0x02,0x7e,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x40,0x38,0x40,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x20,0x30,0x28,0x24,0x7e,0x20,0x20,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x02,0x1e,0x20,0x40,0x22,0x1c,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x04,0x02,0x3e,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x42,0x20,0x10,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x42,0x3c,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x42,0x7c,0x40,0x20,0x1c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x10,0x00,0x00,0x10,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x60,0x30,0x18,0x0c,0x18,0x30,0x60,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x7e,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x06,0x0c,0x18,0x30,0x18,0x0c,0x06,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x40,0x30,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x44,0x52,0x6a,0x32,0x04,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x18,0x24,0x42,0x7e,0x42,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x3e,0x44,0x44,0x3c,0x44,0x44,0x3e,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x44,0x02,0x02,0x02,0x44,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x1e,0x24,0x44,0x44,0x44,0x24,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x02,0x02,0x1e,0x02,0x02,0x7e,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x02,0x02,0x1e,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x44,0x02,0x72,0x42,0x44,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x42,0x42,0x42,0x7e,0x42,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x70,0x20,0x20,0x20,0x20,0x22,0x1c,0x00,0x00,0x00,0x00,0x00 }, { 0x42,0x22,0x12,0x0e,0x12,0x22,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x02,0x02,0x02,0x02,0x02,0x02,0x7e,0x00,0x00,0x00,0x00,0x00 }, { 0x42,0x66,0x5a,0x5a,0x42,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x42,0x46,0x4a,0x52,0x62,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x3e,0x42,0x42,0x3e,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x42,0x42,0x52,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x3e,0x42,0x42,0x3e,0x12,0x22,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x02,0x3c,0x40,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x42,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x42,0x42,0x42,0x24,0x24,0x18,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x42,0x42,0x42,0x5a,0x5a,0x66,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x44,0x44,0x44,0x38,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x40,0x20,0x18,0x04,0x02,0x7e,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x04,0x04,0x04,0x04,0x04,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x20,0x20,0x20,0x20,0x20,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x02,0x02,0x3a,0x46,0x42,0x46,0x3a,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3c,0x42,0x02,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x40,0x40,0x5c,0x62,0x42,0x62,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x48,0x08,0x3e,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x5c,0x62,0x62,0x5c,0x40,0x3c,0x00,0x00,0x00,0x00 }, { 0x02,0x02,0x3a,0x46,0x42,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x00,0x18,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x20,0x00,0x30,0x20,0x20,0x20,0x22,0x1c,0x00,0x00,0x00,0x00 }, { 0x02,0x02,0x22,0x12,0x0a,0x16,0x22,0x00,0x00,0x00,0x00,0x00 }, { 0x18,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x6e,0x92,0x92,0x92,0x92,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3a,0x46,0x42,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3c,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3a,0x46,0x46,0x3a,0x02,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x5c,0x62,0x62,0x5c,0x40,0x40,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3a,0x46,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x7c,0x02,0x3c,0x40,0x3e,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x08,0x3e,0x08,0x08,0x48,0x30,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x42,0x42,0x42,0x24,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x82,0x92,0x92,0x92,0x6c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x42,0x24,0x18,0x24,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x42,0x42,0x62,0x5c,0x40,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x7e,0x20,0x18,0x04,0x7e,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x08,0x08,0x04,0x08,0x08,0x30,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x10,0x00,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x10,0x10,0x20,0x10,0x10,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x92,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x7c,0x10,0x10,0x00,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x7c,0xfe,0xfe,0x7c,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x6c,0xfe,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x7c,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x38,0x10,0xd6,0xfe,0xd6,0x10,0x38,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0xa5,0x81,0xa5,0x99,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0xa5,0x81,0x99,0xa5,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x3c,0x00,0x00,0x00,0x00 }, { 0x04,0x08,0x10,0x20,0x10,0x08,0x04,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x9c,0x62,0x62,0x9c,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x44,0x3c,0x44,0x44,0x3c,0x04,0x02,0x00,0x00,0x00,0x00 }, { 0x86,0x48,0x28,0x18,0x08,0x0c,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x48,0x08,0x30,0x50,0x48,0x30,0x00,0x00,0x00,0x00,0x00 }, { 0x60,0x10,0x08,0x7c,0x08,0x10,0x60,0x00,0x00,0x00,0x00,0x00 }, { 0x68,0x60,0x10,0x08,0x38,0x40,0x30,0x00,0x00,0x00,0x00,0x00 }, { 0x34,0x4a,0x48,0x48,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x44,0x7c,0x44,0x28,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x04,0x04,0x44,0x44,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x02,0x12,0x0a,0x06,0x0a,0x52,0x22,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x08,0x08,0x08,0x18,0x24,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x24,0x24,0x24,0x5c,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x4c,0x48,0x28,0x18,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x04,0x18,0x04,0x38,0x40,0x30,0x00,0x00,0x00,0x00 }, { 0x00,0x18,0x24,0x42,0x42,0x24,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x7c,0x2a,0x28,0x28,0x28,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x18,0x24,0x24,0x1c,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x7c,0x12,0x12,0x0c,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x7c,0x12,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x40,0x26,0x24,0x24,0x24,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x54,0x54,0x54,0x38,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x46,0x28,0x10,0x28,0xc4,0x00,0x00,0x00,0x00,0x00 }, { 0x92,0x54,0x54,0x38,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x44,0x82,0x92,0x92,0x6c,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x44,0x82,0x82,0xc6,0x44,0xc6,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x08,0x08,0x08,0x0a,0x0c,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x00,0x7c,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x04,0x08,0x30,0x08,0x04,0x7e,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x4c,0x32,0x00,0x4c,0x32,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x10,0x28,0x44,0xfe,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x20,0x10,0x08,0x08,0x10,0x10,0x08,0x04,0x00,0x00,0x00,0x00 }, { 0x80,0x40,0xfe,0x10,0xfe,0x04,0x02,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x20,0x7c,0x08,0x10,0x20,0x00,0x00,0x00,0x00,0x00 }, { 0xfc,0x4a,0x24,0x10,0x48,0xa4,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x44,0x82,0x82,0xfe,0x44,0x44,0xc6,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x6c,0x92,0x92,0x6c,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x40,0x20,0x12,0x0a,0x06,0x02,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x04,0x38,0x44,0x38,0x40,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x44,0xaa,0x54,0x28,0x54,0xaa,0x44,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0xb9,0x85,0x85,0xb9,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x42,0x24,0x18,0x24,0x18,0x24,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x52,0x52,0x5c,0x50,0x50,0x50,0x50,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x54,0x14,0x54,0x38,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x5e,0xa5,0xa5,0x9d,0x95,0x66,0x3c,0x00,0x00,0x00,0x00 }, { 0xfa,0x06,0xc6,0x46,0x26,0xde,0x06,0xfa,0x00,0x00,0x00,0x00 }, { 0xff,0x20,0xc0,0x3f,0x40,0x3f,0x20,0x1f,0x00,0x00,0x00,0x00 }, { 0x3f,0x40,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x1e,0x22,0x22,0x1e,0x52,0x22,0xd2,0x00,0x00,0x00,0x00,0x00 }, { 0x86,0x41,0x21,0x16,0x68,0x94,0x92,0x61,0x00,0x00,0x00,0x00 }, { 0x70,0x60,0x50,0x0e,0x09,0x09,0x06,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x44,0x44,0x44,0x38,0x10,0x38,0x10,0x00,0x00,0x00,0x00 }, { 0x70,0x10,0x10,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0xff,0xc7,0xbb,0xcf,0xef,0xff,0xef,0xff,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x10,0x38,0x54,0x10,0x28,0x44,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x10,0x38,0x54,0x28,0x7c,0x28,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x44,0x44,0x44,0x54,0x6c,0x44,0x00,0x00,0x00,0x00 }, { 0x44,0x28,0x10,0x7c,0x10,0x7c,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x04,0x0a,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x04,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x20,0x20,0x20,0x20,0x3e,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x02,0x04,0x08,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3c,0x20,0x3c,0x10,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x7c,0x40,0x30,0x10,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x20,0x10,0x18,0x14,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x10,0x7c,0x44,0x40,0x20,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x38,0x10,0x10,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x10,0x3c,0x18,0x14,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x08,0x7c,0x48,0x08,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x38,0x20,0x20,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x7c,0x40,0x78,0x40,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x54,0x54,0x44,0x20,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x40,0x28,0x18,0x08,0x08,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x40,0x20,0x10,0x18,0x14,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x7c,0x44,0x44,0x20,0x10,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x7e,0x10,0x18,0x14,0x12,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x7e,0x48,0x48,0x48,0x44,0x72,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x10,0x7c,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x44,0x44,0x42,0x20,0x10,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x04,0x7c,0x14,0x12,0x10,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x40,0x40,0x40,0x40,0x40,0x7e,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x7e,0x24,0x24,0x20,0x10,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x1c,0x40,0x4e,0x40,0x40,0x24,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x40,0x20,0x10,0x18,0x24,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x7e,0x48,0x28,0x08,0x48,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x42,0x44,0x48,0x20,0x10,0x08,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x42,0x42,0x50,0x20,0x10,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x50,0x3e,0x10,0x7c,0x10,0x10,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x00,0x7e,0x40,0x20,0x10,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x00,0x7c,0x10,0x10,0x08,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x04,0x1c,0x24,0x44,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x7c,0x10,0x10,0x10,0x08,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x00,0x00,0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x40,0x40,0x28,0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x7e,0x40,0x20,0x30,0x58,0x14,0x00,0x00,0x00,0x00,0x00 }, { 0x60,0x40,0x20,0x10,0x08,0x04,0x02,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x20,0x50,0x50,0x50,0x48,0x44,0x00,0x00,0x00,0x00,0x00 }, { 0x02,0x02,0x7e,0x02,0x02,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x40,0x40,0x20,0x10,0x08,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x08,0x14,0x22,0x40,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x7c,0x10,0x54,0x54,0x54,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x40,0x40,0x28,0x10,0x20,0x40,0x00,0x00,0x00,0x00,0x00 }, { 0x02,0x3c,0x42,0x3c,0x42,0x3c,0x40,0x00,0x00,0x00,0x00,0x00 }, { 0x20,0x10,0x08,0x04,0x12,0x22,0x5e,0x00,0x00,0x00,0x00,0x00 }, { 0x40,0x44,0x28,0x10,0x28,0x04,0x02,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x08,0x3c,0x08,0x08,0x48,0x30,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x7e,0x48,0x28,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x20,0x20,0x20,0x10,0x08,0x7e,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x40,0x40,0x7c,0x40,0x40,0x7e,0x00,0x00,0x00,0x00,0x00 }, { 0x54,0x54,0x44,0x40,0x20,0x10,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x42,0x42,0x42,0x42,0x22,0x10,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x0a,0x0a,0x0a,0x4a,0x4a,0x2a,0x1a,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x04,0x04,0x44,0x44,0x24,0x1c,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x42,0x42,0x42,0x42,0x42,0x7e,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x42,0x42,0x40,0x20,0x10,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x4e,0x40,0x40,0x40,0x20,0x12,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x12,0x24,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x0a,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, }, { /* CG 5 - for Model III */ /* Source: see corresponding Model 4/4P CG below */ /* This is the newer CG with international alternate characters. Characters 0-31 are also different from the older CG. I'm not certain this CG was available in the Model III; it may have been introduced in the Model 4 */ /* Letters shifted up 1 to start at top of cell, Model III style */ { 0x24,0x18,0x24,0x42,0x7e,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x3c,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x08,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x44,0x3c,0x44,0x44,0x3c,0x02,0x00,0x00,0x00,0x00 }, { 0x10,0x08,0x3c,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x18,0x24,0x04,0x0e,0x04,0x44,0x3e,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x02,0x3c,0x42,0x3c,0x40,0x3e,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x00,0x3c,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x00,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x18,0x24,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x00,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x00,0x18,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x14,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x18,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x3c,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3c,0x42,0x02,0x42,0x3c,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0xfe,0x82,0xfe,0x00,0x00,0x00,0x00 }, { 0x00,0x1c,0x20,0x20,0x14,0x0c,0x1c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x42,0x3c,0x24,0x24,0x3c,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x00,0x00,0x00,0x00 }, { 0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f,0xff,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x10,0x38,0x38,0x28,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x48,0x08,0x3e,0x08,0x08,0x06,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x10,0x10,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x24,0x7e,0x24,0x7e,0x24,0x24,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x78,0x14,0x38,0x50,0x3c,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x46,0x26,0x10,0x08,0x64,0x62,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x12,0x12,0x0c,0x52,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x20,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x20,0x10,0x08,0x08,0x08,0x10,0x20,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x08,0x10,0x10,0x10,0x08,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x54,0x38,0x7c,0x38,0x54,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x7c,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x40,0x20,0x10,0x08,0x04,0x02,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x62,0x5a,0x46,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x18,0x14,0x10,0x10,0x10,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x40,0x30,0x0c,0x02,0x7e,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x40,0x38,0x40,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x20,0x30,0x28,0x24,0x7e,0x20,0x20,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x02,0x1e,0x20,0x40,0x22,0x1c,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x04,0x02,0x3e,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x42,0x20,0x10,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x42,0x3c,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x42,0x7c,0x40,0x20,0x1c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x10,0x00,0x00,0x10,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x60,0x30,0x18,0x0c,0x18,0x30,0x60,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x7e,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x06,0x0c,0x18,0x30,0x18,0x0c,0x06,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x40,0x30,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x44,0x52,0x6a,0x32,0x04,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x18,0x24,0x42,0x7e,0x42,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x3e,0x44,0x44,0x3c,0x44,0x44,0x3e,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x44,0x02,0x02,0x02,0x44,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x1e,0x24,0x44,0x44,0x44,0x24,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x02,0x02,0x1e,0x02,0x02,0x7e,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x02,0x02,0x1e,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x44,0x02,0x72,0x42,0x44,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x42,0x42,0x42,0x7e,0x42,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x70,0x20,0x20,0x20,0x20,0x22,0x1c,0x00,0x00,0x00,0x00,0x00 }, { 0x42,0x22,0x12,0x0e,0x12,0x22,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x02,0x02,0x02,0x02,0x02,0x02,0x7e,0x00,0x00,0x00,0x00,0x00 }, { 0x42,0x66,0x5a,0x5a,0x42,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x42,0x46,0x4a,0x52,0x62,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x3e,0x42,0x42,0x3e,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x42,0x42,0x52,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x3e,0x42,0x42,0x3e,0x12,0x22,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x02,0x3c,0x40,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x42,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x42,0x42,0x42,0x24,0x24,0x18,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x42,0x42,0x42,0x5a,0x5a,0x66,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x44,0x44,0x44,0x38,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x40,0x20,0x18,0x04,0x02,0x7e,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x04,0x04,0x04,0x04,0x04,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x20,0x20,0x20,0x20,0x20,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x02,0x02,0x3a,0x46,0x42,0x46,0x3a,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3c,0x42,0x02,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x40,0x40,0x5c,0x62,0x42,0x62,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x48,0x08,0x3e,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x5c,0x62,0x62,0x5c,0x40,0x3c,0x00,0x00,0x00,0x00 }, { 0x02,0x02,0x3a,0x46,0x42,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x00,0x18,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x20,0x00,0x30,0x20,0x20,0x20,0x22,0x1c,0x00,0x00,0x00,0x00 }, { 0x02,0x02,0x22,0x12,0x0a,0x16,0x22,0x00,0x00,0x00,0x00,0x00 }, { 0x18,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x6e,0x92,0x92,0x92,0x92,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3a,0x46,0x42,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3c,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3a,0x46,0x46,0x3a,0x02,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x5c,0x62,0x62,0x5c,0x40,0x40,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3a,0x46,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x7c,0x02,0x3c,0x40,0x3e,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x08,0x3e,0x08,0x08,0x48,0x30,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x42,0x42,0x42,0x24,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x82,0x92,0x92,0x92,0x6c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x42,0x24,0x18,0x24,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x42,0x42,0x62,0x5c,0x40,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x7e,0x20,0x18,0x04,0x7e,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x08,0x08,0x04,0x08,0x08,0x30,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x10,0x00,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x10,0x10,0x20,0x10,0x10,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x92,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x7c,0x10,0x10,0x00,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x7c,0xfe,0xfe,0x7c,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x6c,0xfe,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x7c,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x38,0x10,0xd6,0xfe,0xd6,0x10,0x38,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0xa5,0x81,0xa5,0x99,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0xa5,0x81,0x99,0xa5,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x3c,0x00,0x00,0x00,0x00 }, { 0x04,0x08,0x10,0x20,0x10,0x08,0x04,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x9c,0x62,0x62,0x9c,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x44,0x3c,0x44,0x44,0x3c,0x04,0x02,0x00,0x00,0x00,0x00 }, { 0x86,0x48,0x28,0x18,0x08,0x0c,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x48,0x08,0x30,0x50,0x48,0x30,0x00,0x00,0x00,0x00,0x00 }, { 0x60,0x10,0x08,0x7c,0x08,0x10,0x60,0x00,0x00,0x00,0x00,0x00 }, { 0x68,0x60,0x10,0x08,0x38,0x40,0x30,0x00,0x00,0x00,0x00,0x00 }, { 0x34,0x4a,0x48,0x48,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x44,0x7c,0x44,0x28,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x04,0x04,0x44,0x44,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x02,0x12,0x0a,0x06,0x0a,0x52,0x22,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x08,0x08,0x08,0x18,0x24,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x24,0x24,0x24,0x5c,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x4c,0x48,0x28,0x18,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x04,0x18,0x04,0x38,0x40,0x30,0x00,0x00,0x00,0x00 }, { 0x00,0x18,0x24,0x42,0x42,0x24,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x7c,0x2a,0x28,0x28,0x28,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x18,0x24,0x24,0x1c,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x7c,0x12,0x12,0x0c,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x7c,0x12,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x40,0x26,0x24,0x24,0x24,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x54,0x54,0x54,0x38,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x46,0x28,0x10,0x28,0xc4,0x00,0x00,0x00,0x00,0x00 }, { 0x92,0x54,0x54,0x38,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x44,0x82,0x92,0x92,0x6c,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x44,0x82,0x82,0xc6,0x44,0xc6,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x08,0x08,0x08,0x0a,0x0c,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x00,0x7c,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x04,0x08,0x30,0x08,0x04,0x7e,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x4c,0x32,0x00,0x4c,0x32,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x10,0x28,0x44,0xfe,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x20,0x10,0x08,0x08,0x10,0x10,0x08,0x04,0x00,0x00,0x00,0x00 }, { 0x80,0x40,0xfe,0x10,0xfe,0x04,0x02,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x20,0x7c,0x08,0x10,0x20,0x00,0x00,0x00,0x00,0x00 }, { 0xfc,0x4a,0x24,0x10,0x48,0xa4,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x44,0x82,0x82,0xfe,0x44,0x44,0xc6,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x6c,0x92,0x92,0x6c,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x40,0x20,0x12,0x0a,0x06,0x02,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x04,0x38,0x44,0x38,0x40,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x44,0xaa,0x54,0x28,0x54,0xaa,0x44,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0xb9,0x85,0x85,0xb9,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x42,0x24,0x18,0x24,0x18,0x24,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x52,0x52,0x5c,0x50,0x50,0x50,0x50,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x54,0x14,0x54,0x38,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x5e,0xa5,0xa5,0x9d,0x95,0x66,0x3c,0x00,0x00,0x00,0x00 }, { 0xfa,0x06,0xc6,0x46,0x26,0xde,0x06,0xfa,0x00,0x00,0x00,0x00 }, { 0xff,0x20,0xc0,0x3f,0x40,0x3f,0x20,0x1f,0x00,0x00,0x00,0x00 }, { 0x3f,0x40,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x1e,0x22,0x22,0x1e,0x52,0x22,0xd2,0x00,0x00,0x00,0x00,0x00 }, { 0x86,0x41,0x21,0x16,0x68,0x94,0x92,0x61,0x00,0x00,0x00,0x00 }, { 0x70,0x60,0x50,0x0e,0x09,0x09,0x06,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x44,0x44,0x44,0x38,0x10,0x38,0x10,0x00,0x00,0x00,0x00 }, { 0x70,0x10,0x10,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0xff,0xc7,0xbb,0xcf,0xef,0xff,0xef,0xff,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x10,0x38,0x54,0x10,0x28,0x44,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x10,0x38,0x54,0x28,0x7c,0x28,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x44,0x44,0x44,0x54,0x6c,0x44,0x00,0x00,0x00,0x00 }, { 0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3c,0x42,0x02,0x42,0x3c,0x08,0x00,0x00,0x00,0x00 }, { 0x18,0x24,0x04,0x0e,0x04,0x44,0x3e,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x44,0x44,0x44,0x64,0x5c,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x18,0x24,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x1c,0x14,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x1c,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x02,0x3c,0x42,0x3c,0x40,0x3e,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x9d,0xa5,0x9d,0xa5,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0xb9,0x85,0x85,0xb9,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x04,0x44,0x24,0x14,0x08,0x54,0x72,0x40,0x00,0x00,0x00,0x00 }, { 0x06,0x44,0x26,0x14,0x0e,0x54,0x72,0x40,0x00,0x00,0x00,0x00 }, { 0x04,0x44,0x24,0x14,0x68,0x44,0x22,0x60,0x00,0x00,0x00,0x00 }, { 0x7c,0x52,0x52,0x5c,0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00 }, { 0x44,0x28,0x10,0x7c,0x10,0x7c,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x18,0x24,0x42,0x7e,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x3c,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x54,0x14,0x54,0x38,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x4c,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x00,0x3c,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x00,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x44,0x3c,0x44,0x44,0x3c,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x07,0x52,0xaa,0xaa,0x8a,0x8a,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x08,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x48,0x08,0x3e,0x08,0x08,0x06,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x14,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x18,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x3c,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x00,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x00,0x18,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x08,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x08,0x18,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x08,0x3c,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x08,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x4c,0x32,0x00,0x3a,0x46,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x4c,0x32,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x4c,0x32,0x00,0x3c,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x14,0x12,0x72,0x1e,0x12,0x72,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x2e,0x50,0x7c,0x12,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x18,0x18,0x24,0x42,0x7e,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x62,0x5a,0x46,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3c,0x62,0x5a,0x46,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x4c,0x32,0x46,0x4a,0x52,0x62,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x08,0x7e,0x02,0x1e,0x02,0x7e,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x08,0x18,0x24,0x7e,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x20,0x10,0x38,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x08,0x3c,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x08,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x00,0x08,0x04,0x02,0x22,0x1c,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x7e,0x02,0x1e,0x02,0x7e,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x18,0x24,0x7e,0x42,0x42,0x00,0x00,0x00,0x00,0x00 }, }, { /* CG 6 - for Model III */ /* Source: a Model III CG ROM, read by Todd P. Cromwell III (todd2_4.bin) */ /* I'm guessing this was a 3rd party replacement CG, not from Radio Shack. The ROM was marked as "Model III/4 character generator". The normal ASCII characters are bold, and alternates are the upper case and numbers in inverse video. This ROM doesn't seem especially suited for the Model 4, which had inverse video in hardware. */ /* Letters start at top of cell, Model III style */ { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x48,0x08,0x3e,0x08,0x48,0x3e,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x20,0x10,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x00,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x10,0x28,0x44,0x7c,0x44,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7e,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x28,0x00,0x38,0x44,0x44,0x44,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0xb8,0x44,0x64,0x54,0x4c,0x44,0x3a,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x4c,0x32,0x00,0x34,0x4c,0x44,0x44,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x20,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x1c,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x5e,0x22,0x22,0x1e,0x12,0x22,0x00,0x00,0x00,0x00,0x00 }, { 0x28,0x00,0x10,0x28,0x44,0x7c,0x44,0x00,0x00,0x00,0x00,0x00 }, { 0x4c,0x32,0x10,0x28,0x44,0x7c,0x44,0x00,0x00,0x00,0x00,0x00 }, { 0x4c,0x32,0x44,0x4c,0x54,0x64,0x44,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x28,0x38,0x44,0x44,0x44,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x90,0x68,0x64,0x54,0x4c,0x2c,0x12,0x00,0x00,0x00,0x00,0x00 }, { 0x4c,0x32,0x00,0x3c,0x42,0x42,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x44,0x44,0x3c,0x44,0x44,0x3e,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x00,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x4c,0x32,0x00,0x18,0x24,0x24,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x54,0x50,0x38,0x14,0x54,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x14,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x08,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x02,0x3e,0x42,0x7c,0x40,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x20,0x10,0x7c,0x04,0x7c,0x04,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x78,0x24,0x64,0x3c,0x24,0x64,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x44,0x04,0x04,0x44,0x38,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x4c,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x1e,0x1e,0x0c,0x0c,0x00,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x36,0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x36,0x36,0x7f,0x36,0x7f,0x36,0x36,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x3e,0x03,0x1e,0x30,0x1f,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x36,0x33,0x18,0x0c,0x66,0x63,0x00,0x00,0x00,0x00,0x00 }, { 0x1c,0x36,0x1c,0x6e,0x3b,0x33,0x6e,0x00,0x00,0x00,0x00,0x00 }, { 0x06,0x06,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x18,0x0c,0x06,0x06,0x06,0x0c,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x06,0x0c,0x18,0x18,0x18,0x0c,0x06,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x0c,0x3f,0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x0c,0x0c,0x06,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x0c,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x60,0x30,0x18,0x0c,0x06,0x03,0x00,0x00,0x00,0x00,0x00 }, { 0x3e,0x63,0x63,0x6b,0x63,0x63,0x3e,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x0e,0x0c,0x0c,0x0c,0x0c,0x3f,0x00,0x00,0x00,0x00,0x00 }, { 0x1e,0x33,0x30,0x1c,0x06,0x33,0x3f,0x00,0x00,0x00,0x00,0x00 }, { 0x1e,0x33,0x30,0x1c,0x30,0x33,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x3c,0x36,0x33,0x7f,0x30,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x3f,0x03,0x1f,0x30,0x30,0x30,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x1c,0x06,0x03,0x1f,0x33,0x33,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x3f,0x33,0x30,0x18,0x0c,0x0c,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x1e,0x33,0x33,0x1e,0x33,0x33,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x1e,0x33,0x33,0x3e,0x30,0x18,0x0e,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x0c,0x00,0x00,0x0c,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x0c,0x00,0x00,0x0c,0x0c,0x06,0x00,0x00,0x00,0x00 }, { 0x18,0x0c,0x06,0x03,0x06,0x0c,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3f,0x00,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x06,0x0c,0x18,0x30,0x18,0x0c,0x06,0x00,0x00,0x00,0x00,0x00 }, { 0x1e,0x33,0x30,0x18,0x0c,0x00,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x3e,0x63,0x7b,0x7b,0x7b,0x03,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x1e,0x33,0x33,0x3f,0x33,0x33,0x00,0x00,0x00,0x00,0x00 }, { 0x3f,0x66,0x66,0x3e,0x66,0x66,0x3f,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x66,0x03,0x03,0x03,0x66,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x1f,0x36,0x66,0x66,0x66,0x36,0x1f,0x00,0x00,0x00,0x00,0x00 }, { 0x7f,0x46,0x16,0x1e,0x16,0x46,0x7f,0x00,0x00,0x00,0x00,0x00 }, { 0x7f,0x46,0x16,0x1e,0x16,0x06,0x0f,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x66,0x03,0x03,0x73,0x66,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x33,0x33,0x33,0x3f,0x33,0x33,0x33,0x00,0x00,0x00,0x00,0x00 }, { 0x1e,0x0c,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x30,0x30,0x30,0x33,0x33,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x67,0x66,0x36,0x1e,0x36,0x66,0x67,0x00,0x00,0x00,0x00,0x00 }, { 0x0f,0x06,0x06,0x06,0x46,0x66,0x7f,0x00,0x00,0x00,0x00,0x00 }, { 0x63,0x77,0x7f,0x7f,0x6b,0x63,0x63,0x00,0x00,0x00,0x00,0x00 }, { 0x63,0x67,0x6f,0x7b,0x73,0x63,0x63,0x00,0x00,0x00,0x00,0x00 }, { 0x3e,0x63,0x63,0x63,0x63,0x63,0x3e,0x00,0x00,0x00,0x00,0x00 }, { 0x3f,0x66,0x66,0x3e,0x06,0x06,0x0f,0x00,0x00,0x00,0x00,0x00 }, { 0x1e,0x33,0x33,0x33,0x3b,0x1e,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x3f,0x66,0x66,0x3e,0x36,0x66,0x67,0x00,0x00,0x00,0x00,0x00 }, { 0x1e,0x33,0x07,0x0e,0x38,0x33,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x3f,0x2d,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x33,0x33,0x33,0x33,0x33,0x33,0x3f,0x00,0x00,0x00,0x00,0x00 }, { 0x33,0x33,0x33,0x33,0x33,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x63,0x63,0x63,0x6b,0x7f,0x77,0x63,0x00,0x00,0x00,0x00,0x00 }, { 0x63,0x63,0x36,0x1c,0x1c,0x36,0x63,0x00,0x00,0x00,0x00,0x00 }, { 0x33,0x33,0x33,0x1e,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x7f,0x63,0x31,0x18,0x4c,0x66,0x7f,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x04,0x04,0x04,0x04,0x04,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x06,0x0c,0x18,0x30,0x60,0xc0,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x20,0x20,0x20,0x20,0x20,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x6c,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00 }, { 0x18,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x1e,0x30,0x3e,0x33,0x6e,0x00,0x00,0x00,0x00,0x00 }, { 0x07,0x06,0x3e,0x66,0x66,0x66,0x3b,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x1e,0x33,0x03,0x33,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x30,0x3e,0x33,0x33,0x33,0x6e,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x1c,0x36,0x06,0x0f,0x06,0x06,0x0f,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x6e,0x33,0x33,0x3e,0x30,0x1f,0x00,0x00,0x00,0x00 }, { 0x07,0x06,0x36,0x6e,0x66,0x66,0x67,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x00,0x30,0x30,0x30,0x33,0x33,0x1e,0x00,0x00,0x00,0x00 }, { 0x07,0x06,0x66,0x36,0x1e,0x36,0x67,0x00,0x00,0x00,0x00,0x00 }, { 0x0e,0x0c,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x33,0x7f,0x7f,0x6b,0x63,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x1f,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x1e,0x33,0x33,0x33,0x1e,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3b,0x66,0x66,0x3e,0x06,0x0f,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x6e,0x33,0x33,0x3e,0x30,0x78,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3b,0x6e,0x66,0x06,0x0f,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3e,0x03,0x1e,0x30,0x1f,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x0c,0x3e,0x0c,0x0c,0x2c,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x33,0x33,0x33,0x33,0x6e,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x33,0x33,0x33,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x63,0x6b,0x7f,0x7f,0x36,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x63,0x36,0x1c,0x36,0x63,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x33,0x33,0x33,0x3e,0x30,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3f,0x19,0x0c,0x26,0x3f,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x08,0x08,0x04,0x08,0x08,0x30,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x30,0x30,0x00,0x30,0x30,0x30,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x10,0x10,0x20,0x10,0x10,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x92,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x7c,0x10,0x10,0x00,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x7c,0xfe,0xfe,0x7c,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x6c,0xfe,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x7c,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x38,0x10,0xd6,0xfe,0xd6,0x10,0x38,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0xa5,0x81,0xa5,0x99,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0xa5,0x81,0x99,0xa5,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x3c,0x00,0x00,0x00,0x00 }, { 0x04,0x08,0x10,0x20,0x10,0x08,0x04,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x9c,0x62,0x62,0x9c,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x44,0x3c,0x44,0x44,0x3c,0x04,0x02,0x00,0x00,0x00,0x00 }, { 0x86,0x48,0x28,0x18,0x08,0x0c,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x48,0x08,0x30,0x50,0x48,0x30,0x00,0x00,0x00,0x00,0x00 }, { 0x60,0x10,0x08,0x7c,0x08,0x10,0x60,0x00,0x00,0x00,0x00,0x00 }, { 0x68,0x60,0x10,0x08,0x38,0x40,0x30,0x00,0x00,0x00,0x00,0x00 }, { 0x34,0x4a,0x48,0x48,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x44,0x7c,0x44,0x28,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x04,0x04,0x44,0x44,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x02,0x12,0x0a,0x06,0x0a,0x52,0x22,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x08,0x08,0x08,0x18,0x24,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x24,0x24,0x24,0x24,0x5c,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x4c,0x48,0x28,0x18,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x04,0x18,0x04,0x38,0x40,0x30,0x00,0x00,0x00,0x00 }, { 0x00,0x18,0x24,0x42,0x42,0x24,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x7c,0x2a,0x28,0x28,0x28,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x18,0x24,0x24,0x1c,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x7c,0x12,0x12,0x0c,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x7c,0x12,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x40,0x26,0x24,0x24,0x24,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x54,0x54,0x54,0x38,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x46,0x28,0x10,0x28,0xc4,0x00,0x00,0x00,0x00,0x00 }, { 0x92,0x54,0x54,0x38,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x44,0x82,0x92,0x92,0x6c,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x44,0x82,0x82,0xc6,0x44,0xc6,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x08,0x08,0x08,0x0a,0x0c,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x00,0x7c,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x04,0x08,0x30,0x08,0x04,0x7e,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x4c,0x32,0x00,0x4c,0x32,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x10,0x28,0x44,0xfe,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x20,0x10,0x08,0x08,0x10,0x10,0x08,0x04,0x00,0x00,0x00,0x00 }, { 0x80,0x40,0xfe,0x10,0xfe,0x04,0x02,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x20,0x7c,0x08,0x10,0x20,0x00,0x00,0x00,0x00,0x00 }, { 0xfc,0x4a,0x24,0x10,0x48,0xa4,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x44,0x82,0x82,0xfe,0x44,0x44,0xc6,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x6c,0x92,0x92,0x6c,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x40,0x20,0x12,0x0a,0x06,0x02,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x04,0x38,0x44,0x38,0x40,0x3c,0x00,0x00,0x00,0x00,0x00 }, { 0x44,0xaa,0x54,0x28,0x54,0xaa,0x44,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x99,0x85,0x85,0x99,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x42,0x24,0x18,0x24,0x18,0x24,0x42,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x52,0x52,0x5c,0x50,0x50,0x50,0x50,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x54,0x14,0x54,0x38,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x5e,0xa5,0xa5,0x9d,0x95,0x66,0x3c,0x00,0x00,0x00,0x00 }, { 0xfa,0x06,0xc6,0x46,0x26,0xde,0x06,0xfa,0x00,0x00,0x00,0x00 }, { 0xff,0x20,0xc0,0x3f,0x40,0x3f,0x20,0x1f,0x00,0x00,0x00,0x00 }, { 0x3f,0x40,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x1e,0x22,0x22,0x1e,0x52,0x22,0xd2,0x00,0x00,0x00,0x00,0x00 }, { 0x06,0x41,0x21,0x16,0x68,0x94,0x92,0x60,0x00,0x00,0x00,0x00 }, { 0x70,0x60,0x50,0x0e,0x09,0x09,0x06,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x44,0x44,0x44,0x38,0x10,0x38,0x10,0x00,0x00,0x00,0x00 }, { 0x70,0x10,0x10,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0xff,0xc7,0xbb,0xcf,0xef,0xff,0xef,0xff,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x10,0x38,0x54,0x10,0x28,0x44,0x00,0x00,0x00,0x00 }, { 0x10,0x28,0x10,0x38,0x54,0x28,0x7c,0x28,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x38,0x28,0x28,0x6c,0xfe,0xc6,0x00,0x00,0x00,0x00 }, { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00 }, { 0xf3,0xe1,0xe1,0xf3,0xf3,0xff,0xf3,0xff,0x00,0x00,0x00,0x00 }, { 0xc9,0xc9,0xc9,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00 }, { 0xc9,0xc9,0x80,0xc9,0x80,0xc9,0xc9,0xff,0x00,0x00,0x00,0x00 }, { 0xf3,0xc1,0xfc,0xe1,0xcf,0xe0,0xf3,0xff,0x00,0x00,0x00,0x00 }, { 0xff,0xc9,0xcc,0xe7,0xf3,0x99,0x9c,0xff,0x00,0x00,0x00,0x00 }, { 0xe3,0xc9,0xe3,0x91,0xc4,0xcc,0x91,0xff,0x00,0x00,0x00,0x00 }, { 0xf9,0xf9,0xfc,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00 }, { 0xe7,0xf3,0xf9,0xf9,0xf9,0xf3,0xe7,0xff,0x00,0x00,0x00,0x00 }, { 0xf9,0xf3,0xe7,0xe7,0xe7,0xf3,0xf9,0xff,0x00,0x00,0x00,0x00 }, { 0xff,0x99,0xc3,0x00,0xc3,0x99,0xff,0xff,0x00,0x00,0x00,0x00 }, { 0xff,0xf3,0xf3,0xc0,0xf3,0xf3,0xff,0xff,0x00,0x00,0x00,0x00 }, { 0xff,0xff,0xff,0xff,0xff,0xf3,0xf3,0xf9,0x00,0x00,0x00,0x00 }, { 0xff,0xff,0xff,0xc0,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00 }, { 0xff,0xff,0xff,0xff,0xff,0xf3,0xf3,0xff,0x00,0x00,0x00,0x00 }, { 0xff,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0xff,0x00,0x00,0x00,0x00 }, { 0xc1,0x9c,0x9c,0x94,0x9c,0x9c,0xc1,0xff,0x00,0x00,0x00,0x00 }, { 0xf3,0xf1,0xf3,0xf3,0xf3,0xf3,0xc0,0xff,0x00,0x00,0x00,0x00 }, { 0xe1,0xcc,0xcf,0xe3,0xf9,0xcc,0xc0,0xff,0x00,0x00,0x00,0x00 }, { 0xe1,0xcc,0xcf,0xe3,0xcf,0xcc,0xe1,0xff,0x00,0x00,0x00,0x00 }, { 0xc7,0xc3,0xc9,0xcc,0x80,0xcf,0x87,0xff,0x00,0x00,0x00,0x00 }, { 0xc0,0xfc,0xe0,0xcf,0xcf,0xcf,0xe1,0xff,0x00,0x00,0x00,0x00 }, { 0xe3,0xf9,0xfc,0xe0,0xcc,0xcc,0xe1,0xff,0x00,0x00,0x00,0x00 }, { 0xc0,0xcc,0xcf,0xe7,0xf3,0xf3,0xf3,0xff,0x00,0x00,0x00,0x00 }, { 0xe1,0xcc,0xcc,0xe1,0xcc,0xcc,0xe1,0xff,0x00,0x00,0x00,0x00 }, { 0xe1,0xcc,0xcc,0xc1,0xcf,0xe7,0xf1,0xff,0x00,0x00,0x00,0x00 }, { 0xff,0xf3,0xf3,0xff,0xff,0xf3,0xf3,0xff,0x00,0x00,0x00,0x00 }, { 0xff,0xf3,0xf3,0xff,0xff,0xf3,0xf3,0xf9,0x00,0x00,0x00,0x00 }, { 0xe7,0xf3,0xf9,0xfc,0xf9,0xf3,0xe7,0xff,0x00,0x00,0x00,0x00 }, { 0xff,0xff,0xc0,0xff,0xc0,0xff,0xff,0xff,0x00,0x00,0x00,0x00 }, { 0xf9,0xf3,0xe7,0xcf,0xe7,0xf3,0xf9,0xff,0x00,0x00,0x00,0x00 }, { 0xe1,0xcc,0xcf,0xe7,0xf3,0xff,0xf3,0xff,0x00,0x00,0x00,0x00 }, { 0xc1,0x9c,0x84,0x84,0x84,0xfc,0xe1,0xff,0x00,0x00,0x00,0x00 }, { 0xf3,0xe1,0xcc,0xcc,0xc0,0xcc,0xcc,0xff,0x00,0x00,0x00,0x00 }, { 0xc0,0x99,0x99,0xc1,0x99,0x99,0xc0,0xff,0x00,0x00,0x00,0x00 }, { 0xc3,0x99,0xfc,0xfc,0xfc,0x99,0xc3,0xff,0x00,0x00,0x00,0x00 }, { 0xe0,0xc9,0x99,0x99,0x99,0xc9,0xe0,0xff,0x00,0x00,0x00,0x00 }, { 0x80,0xb9,0xe9,0xe1,0xe9,0xb9,0x80,0xff,0x00,0x00,0x00,0x00 }, { 0x80,0xb9,0xe9,0xe1,0xe9,0xf9,0xf0,0xff,0x00,0x00,0x00,0x00 }, { 0xc3,0x99,0xfc,0xfc,0x8c,0x99,0xc3,0xff,0x00,0x00,0x00,0x00 }, { 0xcc,0xcc,0xcc,0xc0,0xcc,0xcc,0xcc,0xff,0x00,0x00,0x00,0x00 }, { 0xe1,0xf3,0xf3,0xf3,0xf3,0xf3,0xe1,0xff,0x00,0x00,0x00,0x00 }, { 0x87,0xcf,0xcf,0xcf,0xcc,0xcc,0xe1,0xff,0x00,0x00,0x00,0x00 }, { 0x98,0x99,0xc9,0xe1,0xc9,0x99,0x98,0xff,0x00,0x00,0x00,0x00 }, { 0xf0,0xf9,0xf9,0xf9,0xb9,0x99,0x80,0xff,0x00,0x00,0x00,0x00 }, { 0x9c,0x88,0x80,0x80,0x94,0x9c,0x9c,0xff,0x00,0x00,0x00,0x00 }, { 0x9c,0x98,0x90,0x84,0x8c,0x9c,0x9c,0xff,0x00,0x00,0x00,0x00 }, { 0xc1,0x9c,0x9c,0x9c,0x9c,0x9c,0xc1,0xff,0x00,0x00,0x00,0x00 }, { 0xc0,0x99,0x99,0xc1,0xf9,0xf9,0xf0,0xff,0x00,0x00,0x00,0x00 }, { 0xe1,0xcc,0xcc,0xcc,0xc4,0xe1,0xc7,0xff,0x00,0x00,0x00,0x00 }, { 0xc0,0x99,0x99,0xc1,0xc9,0x99,0x98,0xff,0x00,0x00,0x00,0x00 }, { 0xe1,0xcc,0xf8,0xf1,0xc7,0xcc,0xe1,0xff,0x00,0x00,0x00,0x00 }, { 0xc0,0xd2,0xf3,0xf3,0xf3,0xf3,0xe1,0xff,0x00,0x00,0x00,0x00 }, { 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xc0,0xff,0x00,0x00,0x00,0x00 }, { 0xcc,0xcc,0xcc,0xcc,0xcc,0xe1,0xf3,0xff,0x00,0x00,0x00,0x00 }, { 0x9c,0x9c,0x9c,0x94,0x80,0x88,0x9c,0xff,0x00,0x00,0x00,0x00 }, { 0x9c,0x9c,0xc9,0xe3,0xe3,0xc9,0x9c,0xff,0x00,0x00,0x00,0x00 }, { 0xcc,0xcc,0xcc,0xe1,0xf3,0xf3,0xe1,0xff,0x00,0x00,0x00,0x00 }, { 0x80,0x9c,0xce,0xe7,0xb3,0x99,0x80,0xff,0x00,0x00,0x00,0x00 }, { 0xc3,0xfb,0xfb,0xfb,0xfb,0xfb,0xc3,0xff,0x00,0x00,0x00,0x00 }, { 0xff,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f,0xff,0x00,0x00,0x00,0x00 }, { 0xc3,0xdf,0xdf,0xdf,0xdf,0xdf,0xc3,0xff,0x00,0x00,0x00,0x00 }, { 0xef,0xc7,0x93,0x39,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00 }, { 0x1c,0x2a,0x3e,0x14,0x1c,0x63,0x1c,0x63,0x00,0x00,0x00,0x00 }, }, { /* CG 7 - for Model 4/4P */ /* Source: A model III CG ROM, read by Todd P. Cromwell III (todd2.bin) */ /* This is the older CG with Katakana alternate characters */ /* Letters shifted 1 line down by mann to match M4 style */ { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x30,0x48,0x08,0x3e,0x08,0x48,0x3e,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x10,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x00,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x10,0x28,0x44,0x7c,0x44,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x7e,0x40,0x40,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x28,0x00,0x38,0x44,0x44,0x44,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0xb8,0x44,0x64,0x54,0x4c,0x44,0x3a,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x10,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x4c,0x32,0x00,0x34,0x4c,0x44,0x44,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x20,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x1c,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x7c,0x5e,0x22,0x22,0x1e,0x12,0x22,0x00,0x00,0x00,0x00 }, { 0x00,0x28,0x00,0x10,0x28,0x44,0x7c,0x44,0x00,0x00,0x00,0x00 }, { 0x00,0x4c,0x32,0x10,0x28,0x44,0x7c,0x44,0x00,0x00,0x00,0x00 }, { 0x00,0x4c,0x32,0x44,0x4c,0x54,0x64,0x44,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x28,0x38,0x44,0x44,0x44,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x90,0x68,0x64,0x54,0x4c,0x2c,0x12,0x00,0x00,0x00,0x00 }, { 0x00,0x4c,0x32,0x00,0x3c,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x44,0x44,0x3c,0x44,0x44,0x3e,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x00,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x4c,0x32,0x00,0x18,0x24,0x24,0x18,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x54,0x50,0x38,0x14,0x54,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x14,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x08,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x02,0x3e,0x42,0x7c,0x40,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x10,0x7c,0x04,0x7c,0x04,0x7c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x78,0x24,0x64,0x3c,0x24,0x64,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x44,0x04,0x04,0x44,0x38,0x10,0x08,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x4c,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x10,0x10,0x10,0x00,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x24,0x7e,0x24,0x7e,0x24,0x24,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x78,0x14,0x38,0x50,0x3c,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x46,0x26,0x10,0x08,0x64,0x62,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x12,0x12,0x0c,0x52,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x10,0x08,0x08,0x08,0x10,0x20,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x08,0x10,0x10,0x10,0x08,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x54,0x38,0x7c,0x38,0x54,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x10,0x10,0x7c,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x08,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x62,0x5a,0x46,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x18,0x14,0x10,0x10,0x10,0x7c,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x40,0x30,0x0c,0x02,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x40,0x38,0x40,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x30,0x28,0x24,0x7e,0x20,0x20,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x02,0x1e,0x20,0x40,0x22,0x1c,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x04,0x02,0x3e,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x42,0x20,0x10,0x08,0x08,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x42,0x3c,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x42,0x7c,0x40,0x20,0x1c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x10,0x00,0x00,0x10,0x10,0x08,0x00,0x00,0x00 }, { 0x00,0x60,0x30,0x18,0x0c,0x18,0x30,0x60,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7e,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x06,0x0c,0x18,0x30,0x18,0x0c,0x06,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x40,0x30,0x08,0x00,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x44,0x52,0x6a,0x32,0x04,0x78,0x00,0x00,0x00,0x00 }, { 0x00,0x18,0x24,0x42,0x7e,0x42,0x42,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x3e,0x44,0x44,0x3c,0x44,0x44,0x3e,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x44,0x02,0x02,0x02,0x44,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x1e,0x24,0x44,0x44,0x44,0x24,0x1e,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x02,0x02,0x1e,0x02,0x02,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x02,0x02,0x1e,0x02,0x02,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x44,0x02,0x72,0x42,0x44,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x42,0x42,0x42,0x7e,0x42,0x42,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x70,0x20,0x20,0x20,0x20,0x22,0x1c,0x00,0x00,0x00,0x00 }, { 0x00,0x42,0x22,0x12,0x0e,0x12,0x22,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x02,0x02,0x02,0x02,0x02,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x42,0x66,0x5a,0x5a,0x42,0x42,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x42,0x46,0x4a,0x52,0x62,0x42,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x3e,0x42,0x42,0x3e,0x02,0x02,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x42,0x42,0x52,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x3e,0x42,0x42,0x3e,0x12,0x22,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x02,0x3c,0x40,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x42,0x42,0x42,0x24,0x24,0x18,0x18,0x00,0x00,0x00,0x00 }, { 0x00,0x42,0x42,0x42,0x5a,0x5a,0x66,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x44,0x44,0x44,0x38,0x10,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x40,0x20,0x18,0x04,0x02,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x04,0x04,0x04,0x04,0x04,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x20,0x20,0x20,0x20,0x20,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00 }, { 0x00,0x08,0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x02,0x3a,0x46,0x42,0x46,0x3a,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3c,0x42,0x02,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x40,0x40,0x5c,0x62,0x42,0x62,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x30,0x48,0x08,0x3e,0x08,0x08,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x5c,0x62,0x62,0x5c,0x40,0x3c,0x00,0x00,0x00 }, { 0x00,0x02,0x02,0x3a,0x46,0x42,0x42,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x00,0x18,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x00,0x30,0x20,0x20,0x20,0x22,0x1c,0x00,0x00,0x00 }, { 0x00,0x02,0x02,0x22,0x12,0x0a,0x16,0x22,0x00,0x00,0x00,0x00 }, { 0x00,0x18,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x6e,0x92,0x92,0x92,0x92,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3a,0x46,0x42,0x42,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3c,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3a,0x46,0x46,0x3a,0x02,0x02,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x5c,0x62,0x62,0x5c,0x40,0x40,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3a,0x46,0x02,0x02,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7c,0x02,0x3c,0x40,0x3e,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x08,0x3e,0x08,0x08,0x48,0x30,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x42,0x42,0x42,0x24,0x18,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x82,0x92,0x92,0x92,0x6c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x42,0x24,0x18,0x24,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x42,0x42,0x62,0x5c,0x40,0x3c,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7e,0x20,0x18,0x04,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x30,0x08,0x08,0x04,0x08,0x08,0x30,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x10,0x00,0x10,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x10,0x10,0x20,0x10,0x10,0x0c,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x92,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x7c,0x10,0x10,0x00,0x7c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x38,0x7c,0xfe,0xfe,0x7c,0x10,0x10,0x00,0x00,0x00 }, { 0x00,0x00,0x6c,0xfe,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x38,0x7c,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x38,0x10,0xd6,0xfe,0xd6,0x10,0x38,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0xa5,0x81,0xa5,0x99,0x42,0x3c,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0xa5,0x81,0x99,0xa5,0x42,0x3c,0x00,0x00,0x00 }, { 0x00,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x3c,0x00,0x00,0x00 }, { 0x00,0x04,0x08,0x10,0x20,0x10,0x08,0x04,0x3c,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x9c,0x62,0x62,0x9c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x44,0x3c,0x44,0x44,0x3c,0x04,0x02,0x00,0x00,0x00 }, { 0x00,0x86,0x48,0x28,0x18,0x08,0x0c,0x0c,0x00,0x00,0x00,0x00 }, { 0x00,0x30,0x48,0x08,0x30,0x50,0x48,0x30,0x00,0x00,0x00,0x00 }, { 0x00,0x60,0x10,0x08,0x7c,0x08,0x10,0x60,0x00,0x00,0x00,0x00 }, { 0x00,0x68,0x60,0x10,0x08,0x38,0x40,0x30,0x00,0x00,0x00,0x00 }, { 0x00,0x34,0x4a,0x48,0x48,0x40,0x40,0x40,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x44,0x7c,0x44,0x28,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x04,0x04,0x04,0x44,0x44,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x12,0x0a,0x06,0x0a,0x52,0x22,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x08,0x08,0x08,0x18,0x24,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x24,0x24,0x24,0x5c,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x4c,0x48,0x28,0x18,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x38,0x04,0x18,0x04,0x38,0x40,0x30,0x00,0x00,0x00 }, { 0x00,0x00,0x18,0x24,0x42,0x42,0x24,0x18,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7c,0x2a,0x28,0x28,0x28,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x18,0x24,0x24,0x1c,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7c,0x12,0x12,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7c,0x12,0x10,0x10,0x10,0x10,0x00,0x00,0x00 }, { 0x00,0x00,0x40,0x26,0x24,0x24,0x24,0x18,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x38,0x54,0x54,0x54,0x38,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x46,0x28,0x10,0x28,0xc4,0x00,0x00,0x00,0x00 }, { 0x00,0x92,0x54,0x54,0x38,0x10,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x44,0x82,0x92,0x92,0x6c,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x44,0x82,0x82,0xc6,0x44,0xc6,0x00,0x00,0x00,0x00 }, { 0x00,0x78,0x08,0x08,0x08,0x0a,0x0c,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x10,0x00,0x7c,0x00,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x04,0x08,0x30,0x08,0x04,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x4c,0x32,0x00,0x4c,0x32,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x10,0x28,0x44,0xfe,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x10,0x08,0x08,0x10,0x10,0x08,0x04,0x00,0x00,0x00 }, { 0x00,0x80,0x40,0xfe,0x10,0xfe,0x04,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x10,0x20,0x7c,0x08,0x10,0x20,0x00,0x00,0x00,0x00 }, { 0x00,0xfc,0x4a,0x24,0x10,0x48,0xa4,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x44,0x82,0x82,0xfe,0x44,0x44,0xc6,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x6c,0x92,0x92,0x6c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x40,0x20,0x12,0x0a,0x06,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x78,0x04,0x38,0x44,0x38,0x40,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x44,0xaa,0x54,0x28,0x54,0xaa,0x44,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0xb9,0x85,0x85,0xb9,0x42,0x3c,0x00,0x00,0x00 }, { 0x00,0x42,0x24,0x18,0x24,0x18,0x24,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x7c,0x52,0x52,0x5c,0x50,0x50,0x50,0x50,0x00,0x00,0x00 }, { 0x00,0x10,0x38,0x54,0x14,0x54,0x38,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x5e,0xa5,0xa5,0x9d,0x95,0x66,0x3c,0x00,0x00,0x00 }, { 0x00,0xfa,0x06,0xc6,0x46,0x26,0xde,0x06,0xfa,0x00,0x00,0x00 }, { 0x00,0xff,0x20,0xc0,0x3f,0x40,0x3f,0x20,0x1f,0x00,0x00,0x00 }, { 0x00,0x3f,0x40,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x1e,0x22,0x22,0x1e,0x52,0x22,0xd2,0x00,0x00,0x00,0x00 }, { 0x00,0x86,0x41,0x21,0x16,0x68,0x94,0x92,0x61,0x00,0x00,0x00 }, { 0x00,0x70,0x60,0x50,0x0e,0x09,0x09,0x06,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x44,0x44,0x44,0x38,0x10,0x38,0x10,0x00,0x00,0x00 }, { 0x00,0x70,0x10,0x10,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0xff,0xc7,0xbb,0xcf,0xef,0xff,0xef,0xff,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x10,0x38,0x54,0x10,0x28,0x44,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x10,0x38,0x54,0x28,0x7c,0x28,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x44,0x44,0x44,0x54,0x6c,0x44,0x00,0x00,0x00 }, { 0x00,0x44,0x28,0x10,0x7c,0x10,0x7c,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x04,0x0a,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x7c,0x04,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x3e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x02,0x04,0x08,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3c,0x20,0x3c,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7c,0x40,0x30,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x20,0x10,0x18,0x14,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x10,0x7c,0x44,0x40,0x20,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x38,0x10,0x10,0x7c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x10,0x3c,0x18,0x14,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x08,0x7c,0x48,0x08,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x38,0x20,0x20,0x7c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7c,0x40,0x78,0x40,0x7c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x54,0x54,0x44,0x20,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x40,0x28,0x18,0x08,0x08,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x40,0x20,0x10,0x18,0x14,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x7c,0x44,0x44,0x20,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x7e,0x10,0x18,0x14,0x12,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x7e,0x48,0x48,0x48,0x44,0x72,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x38,0x10,0x7c,0x10,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x7c,0x44,0x44,0x42,0x20,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x04,0x7c,0x14,0x12,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x40,0x40,0x40,0x40,0x40,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x7e,0x24,0x24,0x20,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x1c,0x40,0x4e,0x40,0x40,0x24,0x18,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x40,0x20,0x10,0x18,0x24,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x7e,0x48,0x28,0x08,0x48,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x42,0x44,0x48,0x20,0x10,0x08,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x42,0x42,0x50,0x20,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x50,0x3e,0x10,0x7c,0x10,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x00,0x7e,0x40,0x20,0x10,0x0c,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x00,0x7c,0x10,0x10,0x08,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x04,0x1c,0x24,0x44,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x7c,0x10,0x10,0x10,0x08,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x40,0x40,0x28,0x10,0x28,0x44,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x7e,0x40,0x20,0x30,0x58,0x14,0x00,0x00,0x00,0x00 }, { 0x00,0x60,0x40,0x20,0x10,0x08,0x04,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x20,0x50,0x50,0x50,0x48,0x44,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x02,0x7e,0x02,0x02,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x40,0x40,0x20,0x10,0x08,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x08,0x14,0x22,0x40,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x7c,0x10,0x54,0x54,0x54,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x40,0x40,0x28,0x10,0x20,0x40,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x3c,0x42,0x3c,0x42,0x3c,0x40,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x10,0x08,0x04,0x12,0x22,0x5e,0x00,0x00,0x00,0x00 }, { 0x00,0x40,0x44,0x28,0x10,0x28,0x04,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x08,0x3c,0x08,0x08,0x48,0x30,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x7e,0x48,0x28,0x08,0x08,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x20,0x20,0x20,0x10,0x08,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x40,0x40,0x7c,0x40,0x40,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x54,0x54,0x44,0x40,0x20,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x42,0x42,0x42,0x42,0x22,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x0a,0x0a,0x0a,0x4a,0x4a,0x2a,0x1a,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x04,0x04,0x44,0x44,0x24,0x1c,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x42,0x42,0x42,0x42,0x42,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x42,0x42,0x40,0x20,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x4e,0x40,0x40,0x40,0x20,0x12,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x12,0x24,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x0a,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, }, { /* CG 8 - for Model 4/4P */ /* Source: Reed M4 emulator (reedm4l.xbm, reedm4la.xbm). Checked by eye against my Model 4P. I should really pull out the ROM and read it directly to be sure this is right. Apologies to Matthew Reed. */ /* This is the newer CG with international alternate characters. Characters 0-31 are also different from the older CG. */ /* Letters start one line from top of cell, Model 4 style */ { 0x00,0x24,0x18,0x24,0x42,0x7e,0x42,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x3c,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x08,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x38,0x44,0x3c,0x44,0x44,0x3c,0x02,0x00,0x00,0x00 }, { 0x00,0x10,0x08,0x3c,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x18,0x24,0x04,0x0e,0x04,0x44,0x3e,0x00,0x00,0x00,0x00 }, { 0x00,0x7c,0x02,0x3c,0x42,0x3c,0x40,0x3e,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x00,0x3c,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x00,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x10,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x10,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x10,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x18,0x24,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x00,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x00,0x18,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x14,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x18,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x3c,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3c,0x42,0x02,0x42,0x3c,0x08,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x82,0xfe,0x00,0x00,0x00 }, { 0x00,0x00,0x1c,0x20,0x20,0x14,0x0c,0x1c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x42,0x3c,0x24,0x24,0x3c,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x00,0x00,0x00 }, { 0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f,0xff,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x10,0x38,0x38,0x28,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x30,0x48,0x08,0x3e,0x08,0x08,0x06,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x10,0x10,0x10,0x00,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x24,0x7e,0x24,0x7e,0x24,0x24,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x78,0x14,0x38,0x50,0x3c,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x46,0x26,0x10,0x08,0x64,0x62,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x12,0x12,0x0c,0x52,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x10,0x08,0x08,0x08,0x10,0x20,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x08,0x10,0x10,0x10,0x08,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x54,0x38,0x7c,0x38,0x54,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x10,0x10,0x7c,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x08,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x62,0x5a,0x46,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x18,0x14,0x10,0x10,0x10,0x7c,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x40,0x30,0x0c,0x02,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x40,0x38,0x40,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x30,0x28,0x24,0x7e,0x20,0x20,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x02,0x1e,0x20,0x40,0x22,0x1c,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x04,0x02,0x3e,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x42,0x20,0x10,0x08,0x08,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x42,0x3c,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x42,0x7c,0x40,0x20,0x1c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x10,0x00,0x00,0x10,0x10,0x08,0x00,0x00,0x00 }, { 0x00,0x60,0x30,0x18,0x0c,0x18,0x30,0x60,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7e,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x06,0x0c,0x18,0x30,0x18,0x0c,0x06,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x40,0x30,0x08,0x00,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x44,0x52,0x6a,0x32,0x04,0x78,0x00,0x00,0x00,0x00 }, { 0x00,0x18,0x24,0x42,0x7e,0x42,0x42,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x3e,0x44,0x44,0x3c,0x44,0x44,0x3e,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x44,0x02,0x02,0x02,0x44,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x1e,0x24,0x44,0x44,0x44,0x24,0x1e,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x02,0x02,0x1e,0x02,0x02,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x02,0x02,0x1e,0x02,0x02,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x44,0x02,0x72,0x42,0x44,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x42,0x42,0x42,0x7e,0x42,0x42,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x70,0x20,0x20,0x20,0x20,0x22,0x1c,0x00,0x00,0x00,0x00 }, { 0x00,0x42,0x22,0x12,0x0e,0x12,0x22,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x02,0x02,0x02,0x02,0x02,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x42,0x66,0x5a,0x5a,0x42,0x42,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x42,0x46,0x4a,0x52,0x62,0x42,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x3e,0x42,0x42,0x3e,0x02,0x02,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x42,0x42,0x52,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x3e,0x42,0x42,0x3e,0x12,0x22,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x02,0x3c,0x40,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x42,0x42,0x42,0x24,0x24,0x18,0x18,0x00,0x00,0x00,0x00 }, { 0x00,0x42,0x42,0x42,0x5a,0x5a,0x66,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x44,0x44,0x44,0x38,0x10,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x40,0x20,0x18,0x04,0x02,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x04,0x04,0x04,0x04,0x04,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x20,0x20,0x20,0x20,0x20,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00 }, { 0x00,0x08,0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x02,0x3a,0x46,0x42,0x46,0x3a,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3c,0x42,0x02,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x40,0x40,0x5c,0x62,0x42,0x62,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x30,0x48,0x08,0x3e,0x08,0x08,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x5c,0x62,0x62,0x5c,0x40,0x3c,0x00,0x00,0x00 }, { 0x00,0x02,0x02,0x3a,0x46,0x42,0x42,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x00,0x18,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x00,0x30,0x20,0x20,0x20,0x22,0x1c,0x00,0x00,0x00 }, { 0x00,0x02,0x02,0x22,0x12,0x0a,0x16,0x22,0x00,0x00,0x00,0x00 }, { 0x00,0x18,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x6e,0x92,0x92,0x92,0x92,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3a,0x46,0x42,0x42,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3c,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3a,0x46,0x46,0x3a,0x02,0x02,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x5c,0x62,0x62,0x5c,0x40,0x40,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3a,0x46,0x02,0x02,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7c,0x02,0x3c,0x40,0x3e,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x08,0x3e,0x08,0x08,0x48,0x30,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x42,0x42,0x42,0x24,0x18,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x82,0x92,0x92,0x92,0x6c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x42,0x24,0x18,0x24,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x42,0x42,0x62,0x5c,0x40,0x3c,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7e,0x20,0x18,0x04,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x30,0x08,0x08,0x04,0x08,0x08,0x30,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x10,0x00,0x10,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x10,0x10,0x20,0x10,0x10,0x0c,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x92,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x7c,0x10,0x10,0x00,0x7c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x38,0x7c,0xfe,0xfe,0x7c,0x10,0x10,0x00,0x00,0x00 }, { 0x00,0x00,0x6c,0xfe,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x38,0x7c,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x38,0x10,0xd6,0xfe,0xd6,0x10,0x38,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0xa5,0x81,0xa5,0x99,0x42,0x3c,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0xa5,0x81,0x99,0xa5,0x42,0x3c,0x00,0x00,0x00 }, { 0x00,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x3c,0x00,0x00,0x00 }, { 0x00,0x04,0x08,0x10,0x20,0x10,0x08,0x04,0x3c,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x9c,0x62,0x62,0x9c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x44,0x3c,0x44,0x44,0x3c,0x04,0x02,0x00,0x00,0x00 }, { 0x00,0x86,0x48,0x28,0x18,0x08,0x0c,0x0c,0x00,0x00,0x00,0x00 }, { 0x00,0x30,0x48,0x08,0x30,0x50,0x48,0x30,0x00,0x00,0x00,0x00 }, { 0x00,0x60,0x10,0x08,0x7c,0x08,0x10,0x60,0x00,0x00,0x00,0x00 }, { 0x00,0x68,0x60,0x10,0x08,0x38,0x40,0x30,0x00,0x00,0x00,0x00 }, { 0x00,0x34,0x4a,0x48,0x48,0x40,0x40,0x40,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x44,0x7c,0x44,0x28,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x04,0x04,0x04,0x44,0x44,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x12,0x0a,0x06,0x0a,0x52,0x22,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x08,0x08,0x08,0x18,0x24,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x24,0x24,0x24,0x5c,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x4c,0x48,0x28,0x18,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x38,0x04,0x18,0x04,0x38,0x40,0x30,0x00,0x00,0x00 }, { 0x00,0x00,0x18,0x24,0x42,0x42,0x24,0x18,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7c,0x2a,0x28,0x28,0x28,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x18,0x24,0x24,0x1c,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7c,0x12,0x12,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7c,0x12,0x10,0x10,0x10,0x10,0x00,0x00,0x00 }, { 0x00,0x00,0x40,0x26,0x24,0x24,0x24,0x18,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x38,0x54,0x54,0x54,0x38,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x46,0x28,0x10,0x28,0xc4,0x00,0x00,0x00,0x00 }, { 0x00,0x92,0x54,0x54,0x38,0x10,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x44,0x82,0x92,0x92,0x6c,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x44,0x82,0x82,0xc6,0x44,0xc6,0x00,0x00,0x00,0x00 }, { 0x00,0x78,0x08,0x08,0x08,0x0a,0x0c,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x10,0x00,0x7c,0x00,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x04,0x08,0x30,0x08,0x04,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x4c,0x32,0x00,0x4c,0x32,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x10,0x28,0x44,0xfe,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x10,0x08,0x08,0x10,0x10,0x08,0x04,0x00,0x00,0x00 }, { 0x00,0x80,0x40,0xfe,0x10,0xfe,0x04,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x10,0x20,0x7c,0x08,0x10,0x20,0x00,0x00,0x00,0x00 }, { 0x00,0xfc,0x4a,0x24,0x10,0x48,0xa4,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x44,0x82,0x82,0xfe,0x44,0x44,0xc6,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x6c,0x92,0x92,0x6c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x40,0x20,0x12,0x0a,0x06,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x78,0x04,0x38,0x44,0x38,0x40,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x44,0xaa,0x54,0x28,0x54,0xaa,0x44,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0xb9,0x85,0x85,0xb9,0x42,0x3c,0x00,0x00,0x00 }, { 0x00,0x42,0x24,0x18,0x24,0x18,0x24,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x7c,0x52,0x52,0x5c,0x50,0x50,0x50,0x50,0x00,0x00,0x00 }, { 0x00,0x10,0x38,0x54,0x14,0x54,0x38,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x5e,0xa5,0xa5,0x9d,0x95,0x66,0x3c,0x00,0x00,0x00 }, { 0x00,0xfa,0x06,0xc6,0x46,0x26,0xde,0x06,0xfa,0x00,0x00,0x00 }, { 0x00,0xff,0x20,0xc0,0x3f,0x40,0x3f,0x20,0x1f,0x00,0x00,0x00 }, { 0x00,0x3f,0x40,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x1e,0x22,0x22,0x1e,0x52,0x22,0xd2,0x00,0x00,0x00,0x00 }, { 0x00,0x86,0x41,0x21,0x16,0x68,0x94,0x92,0x61,0x00,0x00,0x00 }, { 0x00,0x70,0x60,0x50,0x0e,0x09,0x09,0x06,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x44,0x44,0x44,0x38,0x10,0x38,0x10,0x00,0x00,0x00 }, { 0x00,0x70,0x10,0x10,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0xff,0xc7,0xbb,0xcf,0xef,0xff,0xef,0xff,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x10,0x38,0x54,0x10,0x28,0x44,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x10,0x38,0x54,0x28,0x7c,0x28,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x44,0x44,0x44,0x54,0x6c,0x44,0x00,0x00,0x00 }, { 0x00,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x10,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3c,0x42,0x02,0x42,0x3c,0x08,0x00,0x00,0x00 }, { 0x00,0x18,0x24,0x04,0x0e,0x04,0x44,0x3e,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x44,0x44,0x44,0x64,0x5c,0x02,0x00,0x00,0x00 }, { 0x00,0x00,0x18,0x24,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x1c,0x14,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x08,0x1c,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x7c,0x02,0x3c,0x42,0x3c,0x40,0x3e,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x9d,0xa5,0x9d,0xa5,0x42,0x3c,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0xb9,0x85,0x85,0xb9,0x42,0x3c,0x00,0x00,0x00 }, { 0x00,0x04,0x44,0x24,0x14,0x08,0x54,0x72,0x40,0x00,0x00,0x00 }, { 0x00,0x06,0x44,0x26,0x14,0x0e,0x54,0x72,0x40,0x00,0x00,0x00 }, { 0x00,0x04,0x44,0x24,0x14,0x68,0x44,0x22,0x60,0x00,0x00,0x00 }, { 0x00,0x7c,0x52,0x52,0x5c,0x50,0x50,0x50,0x00,0x00,0x00,0x00 }, { 0x00,0x44,0x28,0x10,0x7c,0x10,0x7c,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x18,0x24,0x42,0x7e,0x42,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x3c,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x38,0x54,0x14,0x54,0x38,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x4c,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x00,0x3c,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x00,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x38,0x44,0x3c,0x44,0x44,0x3c,0x02,0x00,0x00,0x00 }, { 0x00,0x00,0x07,0x52,0xaa,0xaa,0x8a,0x8a,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x08,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x10,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x10,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x30,0x48,0x08,0x3e,0x08,0x08,0x06,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x14,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x18,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x3c,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x00,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x00,0x18,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x08,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x08,0x18,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x08,0x3c,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x08,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x4c,0x32,0x00,0x3a,0x46,0x42,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x4c,0x32,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x4c,0x32,0x00,0x3c,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x78,0x14,0x12,0x72,0x1e,0x12,0x72,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x2e,0x50,0x7c,0x12,0x7c,0x00,0x00,0x00,0x00 }, { 0x00,0x18,0x18,0x24,0x42,0x7e,0x42,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x62,0x5a,0x46,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3c,0x62,0x5a,0x46,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x4c,0x32,0x46,0x4a,0x52,0x62,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x08,0x7e,0x02,0x1e,0x02,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x08,0x18,0x24,0x7e,0x42,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x10,0x38,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x08,0x3c,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x08,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x00,0x08,0x04,0x02,0x22,0x1c,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x10,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x10,0x7e,0x02,0x1e,0x02,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x10,0x18,0x24,0x7e,0x42,0x42,0x00,0x00,0x00,0x00 }, }, { /* CG 9 - for Model 4/4P */ /* Source: a Model III CG ROM, read by Todd P. Cromwell III (todd2_4.bin) */ /* I'm guessing this was a 3rd party replacement CG, not from Radio Shack. The ROM was marked as "Model III/4 character generator". The normal ASCII characters are bold, and alternates are the upper case and numbers in inverse video. This ROM doesn't seem especially suited for the Model 4, which had inverse video in hardware. */ /* Letters shifted 1 line down by mann to match M4 style */ { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x30,0x48,0x08,0x3e,0x08,0x48,0x3e,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x10,0x3c,0x42,0x7e,0x02,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x00,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x10,0x28,0x44,0x7c,0x44,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x7e,0x40,0x40,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x28,0x00,0x38,0x44,0x44,0x44,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0xb8,0x44,0x64,0x54,0x4c,0x44,0x3a,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x10,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x4c,0x32,0x00,0x34,0x4c,0x44,0x44,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x20,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x1c,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x7c,0x5e,0x22,0x22,0x1e,0x12,0x22,0x00,0x00,0x00,0x00 }, { 0x00,0x28,0x00,0x10,0x28,0x44,0x7c,0x44,0x00,0x00,0x00,0x00 }, { 0x00,0x4c,0x32,0x10,0x28,0x44,0x7c,0x44,0x00,0x00,0x00,0x00 }, { 0x00,0x4c,0x32,0x44,0x4c,0x54,0x64,0x44,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x28,0x38,0x44,0x44,0x44,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x90,0x68,0x64,0x54,0x4c,0x2c,0x12,0x00,0x00,0x00,0x00 }, { 0x00,0x4c,0x32,0x00,0x3c,0x42,0x42,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x44,0x44,0x3c,0x44,0x44,0x3e,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x00,0x42,0x42,0x42,0x62,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x4c,0x32,0x00,0x18,0x24,0x24,0x18,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x54,0x50,0x38,0x14,0x54,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x14,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x08,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x00,0x1c,0x20,0x3c,0x22,0x5c,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x02,0x3e,0x42,0x7c,0x40,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x10,0x7c,0x04,0x7c,0x04,0x7c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x78,0x24,0x64,0x3c,0x24,0x64,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x44,0x04,0x04,0x44,0x38,0x10,0x08,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x4c,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x1e,0x1e,0x0c,0x0c,0x00,0x0c,0x00,0x00,0x00,0x00 }, { 0x00,0x36,0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x36,0x36,0x7f,0x36,0x7f,0x36,0x36,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x3e,0x03,0x1e,0x30,0x1f,0x0c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x36,0x33,0x18,0x0c,0x66,0x63,0x00,0x00,0x00,0x00 }, { 0x00,0x1c,0x36,0x1c,0x6e,0x3b,0x33,0x6e,0x00,0x00,0x00,0x00 }, { 0x00,0x06,0x06,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x18,0x0c,0x06,0x06,0x06,0x0c,0x18,0x00,0x00,0x00,0x00 }, { 0x00,0x06,0x0c,0x18,0x18,0x18,0x0c,0x06,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x0c,0x0c,0x3f,0x0c,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x0c,0x06,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x0c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x60,0x30,0x18,0x0c,0x06,0x03,0x00,0x00,0x00,0x00 }, { 0x00,0x3e,0x63,0x63,0x6b,0x63,0x63,0x3e,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x0e,0x0c,0x0c,0x0c,0x0c,0x3f,0x00,0x00,0x00,0x00 }, { 0x00,0x1e,0x33,0x30,0x1c,0x06,0x33,0x3f,0x00,0x00,0x00,0x00 }, { 0x00,0x1e,0x33,0x30,0x1c,0x30,0x33,0x1e,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x3c,0x36,0x33,0x7f,0x30,0x78,0x00,0x00,0x00,0x00 }, { 0x00,0x3f,0x03,0x1f,0x30,0x30,0x30,0x1e,0x00,0x00,0x00,0x00 }, { 0x00,0x1c,0x06,0x03,0x1f,0x33,0x33,0x1e,0x00,0x00,0x00,0x00 }, { 0x00,0x3f,0x33,0x30,0x18,0x0c,0x0c,0x0c,0x00,0x00,0x00,0x00 }, { 0x00,0x1e,0x33,0x33,0x1e,0x33,0x33,0x1e,0x00,0x00,0x00,0x00 }, { 0x00,0x1e,0x33,0x33,0x3e,0x30,0x18,0x0e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x0c,0x0c,0x00,0x00,0x0c,0x0c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x0c,0x0c,0x00,0x00,0x0c,0x0c,0x06,0x00,0x00,0x00 }, { 0x00,0x18,0x0c,0x06,0x03,0x06,0x0c,0x18,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3f,0x00,0x3f,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x06,0x0c,0x18,0x30,0x18,0x0c,0x06,0x00,0x00,0x00,0x00 }, { 0x00,0x1e,0x33,0x30,0x18,0x0c,0x00,0x0c,0x00,0x00,0x00,0x00 }, { 0x00,0x3e,0x63,0x7b,0x7b,0x7b,0x03,0x1e,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x1e,0x33,0x33,0x3f,0x33,0x33,0x00,0x00,0x00,0x00 }, { 0x00,0x3f,0x66,0x66,0x3e,0x66,0x66,0x3f,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x66,0x03,0x03,0x03,0x66,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x1f,0x36,0x66,0x66,0x66,0x36,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x7f,0x46,0x16,0x1e,0x16,0x46,0x7f,0x00,0x00,0x00,0x00 }, { 0x00,0x7f,0x46,0x16,0x1e,0x16,0x06,0x0f,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x66,0x03,0x03,0x73,0x66,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x33,0x33,0x33,0x3f,0x33,0x33,0x33,0x00,0x00,0x00,0x00 }, { 0x00,0x1e,0x0c,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00 }, { 0x00,0x78,0x30,0x30,0x30,0x33,0x33,0x1e,0x00,0x00,0x00,0x00 }, { 0x00,0x67,0x66,0x36,0x1e,0x36,0x66,0x67,0x00,0x00,0x00,0x00 }, { 0x00,0x0f,0x06,0x06,0x06,0x46,0x66,0x7f,0x00,0x00,0x00,0x00 }, { 0x00,0x63,0x77,0x7f,0x7f,0x6b,0x63,0x63,0x00,0x00,0x00,0x00 }, { 0x00,0x63,0x67,0x6f,0x7b,0x73,0x63,0x63,0x00,0x00,0x00,0x00 }, { 0x00,0x3e,0x63,0x63,0x63,0x63,0x63,0x3e,0x00,0x00,0x00,0x00 }, { 0x00,0x3f,0x66,0x66,0x3e,0x06,0x06,0x0f,0x00,0x00,0x00,0x00 }, { 0x00,0x1e,0x33,0x33,0x33,0x3b,0x1e,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x3f,0x66,0x66,0x3e,0x36,0x66,0x67,0x00,0x00,0x00,0x00 }, { 0x00,0x1e,0x33,0x07,0x0e,0x38,0x33,0x1e,0x00,0x00,0x00,0x00 }, { 0x00,0x3f,0x2d,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00 }, { 0x00,0x33,0x33,0x33,0x33,0x33,0x33,0x3f,0x00,0x00,0x00,0x00 }, { 0x00,0x33,0x33,0x33,0x33,0x33,0x1e,0x0c,0x00,0x00,0x00,0x00 }, { 0x00,0x63,0x63,0x63,0x6b,0x7f,0x77,0x63,0x00,0x00,0x00,0x00 }, { 0x00,0x63,0x63,0x36,0x1c,0x1c,0x36,0x63,0x00,0x00,0x00,0x00 }, { 0x00,0x33,0x33,0x33,0x1e,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00 }, { 0x00,0x7f,0x63,0x31,0x18,0x4c,0x66,0x7f,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x04,0x04,0x04,0x04,0x04,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x06,0x0c,0x18,0x30,0x60,0xc0,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x20,0x20,0x20,0x20,0x20,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x38,0x6c,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00 }, { 0x00,0x18,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x1e,0x30,0x3e,0x33,0x6e,0x00,0x00,0x00,0x00 }, { 0x00,0x07,0x06,0x3e,0x66,0x66,0x66,0x3b,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x1e,0x33,0x03,0x33,0x1e,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x30,0x3e,0x33,0x33,0x33,0x6e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x00,0x00,0x00 }, { 0x00,0x1c,0x36,0x06,0x0f,0x06,0x06,0x0f,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x6e,0x33,0x33,0x3e,0x30,0x1f,0x00,0x00,0x00 }, { 0x00,0x07,0x06,0x36,0x6e,0x66,0x66,0x67,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00 }, { 0x00,0x30,0x00,0x30,0x30,0x30,0x33,0x33,0x1e,0x00,0x00,0x00 }, { 0x00,0x07,0x06,0x66,0x36,0x1e,0x36,0x67,0x00,0x00,0x00,0x00 }, { 0x00,0x0e,0x0c,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x33,0x7f,0x7f,0x6b,0x63,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x1f,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x1e,0x33,0x33,0x33,0x1e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3b,0x66,0x66,0x3e,0x06,0x0f,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x6e,0x33,0x33,0x3e,0x30,0x78,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3b,0x6e,0x66,0x06,0x0f,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3e,0x03,0x1e,0x30,0x1f,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x0c,0x3e,0x0c,0x0c,0x2c,0x18,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x33,0x33,0x33,0x33,0x6e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x33,0x33,0x33,0x1e,0x0c,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x63,0x6b,0x7f,0x7f,0x36,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x63,0x36,0x1c,0x36,0x63,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x33,0x33,0x33,0x3e,0x30,0x1f,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x3f,0x19,0x0c,0x26,0x3f,0x00,0x00,0x00,0x00 }, { 0x00,0x30,0x08,0x08,0x04,0x08,0x08,0x30,0x00,0x00,0x00,0x00 }, { 0x00,0x30,0x30,0x30,0x00,0x30,0x30,0x30,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x10,0x10,0x20,0x10,0x10,0x0c,0x00,0x00,0x00,0x00 }, { 0x00,0x0c,0x92,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x7c,0x10,0x10,0x00,0x7c,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x38,0x7c,0xfe,0xfe,0x7c,0x10,0x10,0x00,0x00,0x00 }, { 0x00,0x00,0x6c,0xfe,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x38,0x7c,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x38,0x10,0xd6,0xfe,0xd6,0x10,0x38,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0xa5,0x81,0xa5,0x99,0x42,0x3c,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0xa5,0x81,0x99,0xa5,0x42,0x3c,0x00,0x00,0x00 }, { 0x00,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x3c,0x00,0x00,0x00 }, { 0x00,0x04,0x08,0x10,0x20,0x10,0x08,0x04,0x3c,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x9c,0x62,0x62,0x9c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x44,0x3c,0x44,0x44,0x3c,0x04,0x02,0x00,0x00,0x00 }, { 0x00,0x86,0x48,0x28,0x18,0x08,0x0c,0x0c,0x00,0x00,0x00,0x00 }, { 0x00,0x30,0x48,0x08,0x30,0x50,0x48,0x30,0x00,0x00,0x00,0x00 }, { 0x00,0x60,0x10,0x08,0x7c,0x08,0x10,0x60,0x00,0x00,0x00,0x00 }, { 0x00,0x68,0x60,0x10,0x08,0x38,0x40,0x30,0x00,0x00,0x00,0x00 }, { 0x00,0x34,0x4a,0x48,0x48,0x40,0x40,0x40,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x44,0x7c,0x44,0x28,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x04,0x04,0x04,0x44,0x44,0x38,0x00,0x00,0x00,0x00 }, { 0x00,0x02,0x12,0x0a,0x06,0x0a,0x52,0x22,0x00,0x00,0x00,0x00 }, { 0x00,0x04,0x08,0x08,0x08,0x18,0x24,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x24,0x24,0x24,0x24,0x5c,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x4c,0x48,0x28,0x18,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x38,0x04,0x18,0x04,0x38,0x40,0x30,0x00,0x00,0x00 }, { 0x00,0x00,0x18,0x24,0x42,0x42,0x24,0x18,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7c,0x2a,0x28,0x28,0x28,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x18,0x24,0x24,0x1c,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7c,0x12,0x12,0x0c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x7c,0x12,0x10,0x10,0x10,0x10,0x00,0x00,0x00 }, { 0x00,0x00,0x40,0x26,0x24,0x24,0x24,0x18,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x38,0x54,0x54,0x54,0x38,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x46,0x28,0x10,0x28,0xc4,0x00,0x00,0x00,0x00 }, { 0x00,0x92,0x54,0x54,0x38,0x10,0x10,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x44,0x82,0x92,0x92,0x6c,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x44,0x82,0x82,0xc6,0x44,0xc6,0x00,0x00,0x00,0x00 }, { 0x00,0x78,0x08,0x08,0x08,0x0a,0x0c,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x10,0x00,0x7c,0x00,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x7e,0x04,0x08,0x30,0x08,0x04,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x4c,0x32,0x00,0x4c,0x32,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x10,0x28,0x44,0xfe,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x10,0x08,0x08,0x10,0x10,0x08,0x04,0x00,0x00,0x00 }, { 0x00,0x80,0x40,0xfe,0x10,0xfe,0x04,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x10,0x20,0x7c,0x08,0x10,0x20,0x00,0x00,0x00,0x00 }, { 0x00,0xfc,0x4a,0x24,0x10,0x48,0xa4,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x44,0x82,0x82,0xfe,0x44,0x44,0xc6,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x6c,0x92,0x92,0x6c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x40,0x20,0x12,0x0a,0x06,0x02,0x00,0x00,0x00,0x00 }, { 0x00,0x78,0x04,0x38,0x44,0x38,0x40,0x3c,0x00,0x00,0x00,0x00 }, { 0x00,0x44,0xaa,0x54,0x28,0x54,0xaa,0x44,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x42,0x99,0x85,0x85,0x99,0x42,0x3c,0x00,0x00,0x00 }, { 0x00,0x42,0x24,0x18,0x24,0x18,0x24,0x42,0x00,0x00,0x00,0x00 }, { 0x00,0x7c,0x52,0x52,0x5c,0x50,0x50,0x50,0x50,0x00,0x00,0x00 }, { 0x00,0x10,0x38,0x54,0x14,0x54,0x38,0x10,0x00,0x00,0x00,0x00 }, { 0x00,0x3c,0x5e,0xa5,0xa5,0x9d,0x95,0x66,0x3c,0x00,0x00,0x00 }, { 0x00,0xfa,0x06,0xc6,0x46,0x26,0xde,0x06,0xfa,0x00,0x00,0x00 }, { 0x00,0xff,0x20,0xc0,0x3f,0x40,0x3f,0x20,0x1f,0x00,0x00,0x00 }, { 0x00,0x3f,0x40,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x1e,0x22,0x22,0x1e,0x52,0x22,0xd2,0x00,0x00,0x00,0x00 }, { 0x00,0x06,0x41,0x21,0x16,0x68,0x94,0x92,0x60,0x00,0x00,0x00 }, { 0x00,0x70,0x60,0x50,0x0e,0x09,0x09,0x06,0x00,0x00,0x00,0x00 }, { 0x00,0x38,0x44,0x44,0x44,0x38,0x10,0x38,0x10,0x00,0x00,0x00 }, { 0x00,0x70,0x10,0x10,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0xff,0xc7,0xbb,0xcf,0xef,0xff,0xef,0xff,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x10,0x38,0x54,0x10,0x28,0x44,0x00,0x00,0x00 }, { 0x00,0x10,0x28,0x10,0x38,0x54,0x28,0x7c,0x28,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x38,0x28,0x28,0x6c,0xfe,0xc6,0x00,0x00,0x00 }, { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00 }, { 0x00,0xf3,0xe1,0xe1,0xf3,0xf3,0xff,0xf3,0xff,0x00,0x00,0x00 }, { 0x00,0xc9,0xc9,0xc9,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00 }, { 0x00,0xc9,0xc9,0x80,0xc9,0x80,0xc9,0xc9,0xff,0x00,0x00,0x00 }, { 0x00,0xf3,0xc1,0xfc,0xe1,0xcf,0xe0,0xf3,0xff,0x00,0x00,0x00 }, { 0x00,0xff,0xc9,0xcc,0xe7,0xf3,0x99,0x9c,0xff,0x00,0x00,0x00 }, { 0x00,0xe3,0xc9,0xe3,0x91,0xc4,0xcc,0x91,0xff,0x00,0x00,0x00 }, { 0x00,0xf9,0xf9,0xfc,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00 }, { 0x00,0xe7,0xf3,0xf9,0xf9,0xf9,0xf3,0xe7,0xff,0x00,0x00,0x00 }, { 0x00,0xf9,0xf3,0xe7,0xe7,0xe7,0xf3,0xf9,0xff,0x00,0x00,0x00 }, { 0x00,0xff,0x99,0xc3,0x00,0xc3,0x99,0xff,0xff,0x00,0x00,0x00 }, { 0x00,0xff,0xf3,0xf3,0xc0,0xf3,0xf3,0xff,0xff,0x00,0x00,0x00 }, { 0x00,0xff,0xff,0xff,0xff,0xff,0xf3,0xf3,0xf9,0x00,0x00,0x00 }, { 0x00,0xff,0xff,0xff,0xc0,0xff,0xff,0xff,0xff,0x00,0x00,0x00 }, { 0x00,0xff,0xff,0xff,0xff,0xff,0xf3,0xf3,0xff,0x00,0x00,0x00 }, { 0x00,0xff,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0xff,0x00,0x00,0x00 }, { 0x00,0xc1,0x9c,0x9c,0x94,0x9c,0x9c,0xc1,0xff,0x00,0x00,0x00 }, { 0x00,0xf3,0xf1,0xf3,0xf3,0xf3,0xf3,0xc0,0xff,0x00,0x00,0x00 }, { 0x00,0xe1,0xcc,0xcf,0xe3,0xf9,0xcc,0xc0,0xff,0x00,0x00,0x00 }, { 0x00,0xe1,0xcc,0xcf,0xe3,0xcf,0xcc,0xe1,0xff,0x00,0x00,0x00 }, { 0x00,0xc7,0xc3,0xc9,0xcc,0x80,0xcf,0x87,0xff,0x00,0x00,0x00 }, { 0x00,0xc0,0xfc,0xe0,0xcf,0xcf,0xcf,0xe1,0xff,0x00,0x00,0x00 }, { 0x00,0xe3,0xf9,0xfc,0xe0,0xcc,0xcc,0xe1,0xff,0x00,0x00,0x00 }, { 0x00,0xc0,0xcc,0xcf,0xe7,0xf3,0xf3,0xf3,0xff,0x00,0x00,0x00 }, { 0x00,0xe1,0xcc,0xcc,0xe1,0xcc,0xcc,0xe1,0xff,0x00,0x00,0x00 }, { 0x00,0xe1,0xcc,0xcc,0xc1,0xcf,0xe7,0xf1,0xff,0x00,0x00,0x00 }, { 0x00,0xff,0xf3,0xf3,0xff,0xff,0xf3,0xf3,0xff,0x00,0x00,0x00 }, { 0x00,0xff,0xf3,0xf3,0xff,0xff,0xf3,0xf3,0xf9,0x00,0x00,0x00 }, { 0x00,0xe7,0xf3,0xf9,0xfc,0xf9,0xf3,0xe7,0xff,0x00,0x00,0x00 }, { 0x00,0xff,0xff,0xc0,0xff,0xc0,0xff,0xff,0xff,0x00,0x00,0x00 }, { 0x00,0xf9,0xf3,0xe7,0xcf,0xe7,0xf3,0xf9,0xff,0x00,0x00,0x00 }, { 0x00,0xe1,0xcc,0xcf,0xe7,0xf3,0xff,0xf3,0xff,0x00,0x00,0x00 }, { 0x00,0xc1,0x9c,0x84,0x84,0x84,0xfc,0xe1,0xff,0x00,0x00,0x00 }, { 0x00,0xf3,0xe1,0xcc,0xcc,0xc0,0xcc,0xcc,0xff,0x00,0x00,0x00 }, { 0x00,0xc0,0x99,0x99,0xc1,0x99,0x99,0xc0,0xff,0x00,0x00,0x00 }, { 0x00,0xc3,0x99,0xfc,0xfc,0xfc,0x99,0xc3,0xff,0x00,0x00,0x00 }, { 0x00,0xe0,0xc9,0x99,0x99,0x99,0xc9,0xe0,0xff,0x00,0x00,0x00 }, { 0x00,0x80,0xb9,0xe9,0xe1,0xe9,0xb9,0x80,0xff,0x00,0x00,0x00 }, { 0x00,0x80,0xb9,0xe9,0xe1,0xe9,0xf9,0xf0,0xff,0x00,0x00,0x00 }, { 0x00,0xc3,0x99,0xfc,0xfc,0x8c,0x99,0xc3,0xff,0x00,0x00,0x00 }, { 0x00,0xcc,0xcc,0xcc,0xc0,0xcc,0xcc,0xcc,0xff,0x00,0x00,0x00 }, { 0x00,0xe1,0xf3,0xf3,0xf3,0xf3,0xf3,0xe1,0xff,0x00,0x00,0x00 }, { 0x00,0x87,0xcf,0xcf,0xcf,0xcc,0xcc,0xe1,0xff,0x00,0x00,0x00 }, { 0x00,0x98,0x99,0xc9,0xe1,0xc9,0x99,0x98,0xff,0x00,0x00,0x00 }, { 0x00,0xf0,0xf9,0xf9,0xf9,0xb9,0x99,0x80,0xff,0x00,0x00,0x00 }, { 0x00,0x9c,0x88,0x80,0x80,0x94,0x9c,0x9c,0xff,0x00,0x00,0x00 }, { 0x00,0x9c,0x98,0x90,0x84,0x8c,0x9c,0x9c,0xff,0x00,0x00,0x00 }, { 0x00,0xc1,0x9c,0x9c,0x9c,0x9c,0x9c,0xc1,0xff,0x00,0x00,0x00 }, { 0x00,0xc0,0x99,0x99,0xc1,0xf9,0xf9,0xf0,0xff,0x00,0x00,0x00 }, { 0x00,0xe1,0xcc,0xcc,0xcc,0xc4,0xe1,0xc7,0xff,0x00,0x00,0x00 }, { 0x00,0xc0,0x99,0x99,0xc1,0xc9,0x99,0x98,0xff,0x00,0x00,0x00 }, { 0x00,0xe1,0xcc,0xf8,0xf1,0xc7,0xcc,0xe1,0xff,0x00,0x00,0x00 }, { 0x00,0xc0,0xd2,0xf3,0xf3,0xf3,0xf3,0xe1,0xff,0x00,0x00,0x00 }, { 0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xc0,0xff,0x00,0x00,0x00 }, { 0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xe1,0xf3,0xff,0x00,0x00,0x00 }, { 0x00,0x9c,0x9c,0x9c,0x94,0x80,0x88,0x9c,0xff,0x00,0x00,0x00 }, { 0x00,0x9c,0x9c,0xc9,0xe3,0xe3,0xc9,0x9c,0xff,0x00,0x00,0x00 }, { 0x00,0xcc,0xcc,0xcc,0xe1,0xf3,0xf3,0xe1,0xff,0x00,0x00,0x00 }, { 0x00,0x80,0x9c,0xce,0xe7,0xb3,0x99,0x80,0xff,0x00,0x00,0x00 }, { 0x00,0xc3,0xfb,0xfb,0xfb,0xfb,0xfb,0xc3,0xff,0x00,0x00,0x00 }, { 0x00,0xff,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f,0xff,0x00,0x00,0x00 }, { 0x00,0xc3,0xdf,0xdf,0xdf,0xdf,0xdf,0xc3,0xff,0x00,0x00,0x00 }, { 0x00,0xef,0xc7,0x93,0x39,0xff,0xff,0xff,0xff,0x00,0x00,0x00 }, { 0x00,0x1c,0x2a,0x3e,0x14,0x1c,0x63,0x1c,0x63,0x00,0x00,0x00 }, }, { /* CG 10 - charset including the German special chars ("Umlauts"). * Version of CG 3 modified by Jenz Guenther to add the national * characters used in the GENIE, a German TRS-80 clone. */ { 0x7c,0x82,0x80,0x8c,0x92,0x92,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x48,0x84,0x84,0xfc,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x88,0x88,0x78,0x88,0x88,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x04,0x04,0x04,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x88,0x88,0x88,0x88,0x88,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0xfc,0x04,0x04,0x3c,0x04,0x04,0xfc,0x00,0x00,0x00,0x00,0x00 }, { 0xfc,0x04,0x04,0x3c,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0xf8,0x04,0x04,0xe4,0x84,0x84,0xf8,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x84,0x84,0xfc,0x84,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x80,0x80,0x80,0x80,0x80,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x44,0x24,0x1c,0x24,0x44,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x04,0x04,0x04,0x04,0x04,0xfc,0x00,0x00,0x00,0x00,0x00 }, { 0x82,0xc6,0xaa,0x92,0x82,0x82,0x82,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x8c,0x94,0xa4,0xc4,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x84,0x84,0x7c,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x84,0x84,0xa4,0x44,0xb8,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x84,0x84,0x7c,0x24,0x44,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x04,0x78,0x80,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0xfe,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x82,0x82,0x82,0x82,0x44,0x28,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x82,0x82,0x82,0x92,0xaa,0xc6,0x82,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x84,0x48,0x30,0x48,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x82,0x82,0x44,0x38,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0xfe,0x40,0x20,0x10,0x08,0x04,0xfe,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x38,0x54,0x92,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x10,0x92,0x54,0x38,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x08,0x04,0xfe,0x04,0x08,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x20,0x40,0xfe,0x40,0x20,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x10,0x10,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x48,0x48,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x48,0x48,0xfc,0x48,0xfc,0x48,0x48,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0xfc,0x12,0x7c,0x90,0x7e,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x8c,0x40,0x20,0x10,0x08,0xc4,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x44,0x28,0x18,0xa4,0x44,0xb8,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x30,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x20,0x10,0x08,0x08,0x08,0x10,0x20,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x20,0x20,0x20,0x10,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x54,0x38,0xfe,0x38,0x54,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x10,0x10,0x7c,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x30,0x30,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x40,0x20,0x10,0x08,0x04,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0xc4,0xa4,0x94,0x8c,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x18,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x80,0x78,0x04,0x04,0xfc,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x80,0x70,0x80,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x40,0x60,0x50,0x48,0xfc,0x40,0x40,0x00,0x00,0x00,0x00,0x00 }, { 0xfc,0x04,0x7c,0x80,0x80,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x70,0x08,0x04,0x7c,0x84,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0xfc,0x80,0x40,0x20,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x84,0x78,0x84,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x84,0xf8,0x80,0x40,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x30,0x00,0x00,0x30,0x30,0x10,0x08,0x00,0x00,0x00,0x00 }, { 0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0xfc,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x3c,0x42,0x40,0x30,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x82,0x80,0x8c,0x92,0x92,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x48,0x84,0x84,0xfc,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x88,0x88,0x78,0x88,0x88,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x04,0x04,0x04,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x88,0x88,0x88,0x88,0x88,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0xfc,0x04,0x04,0x3c,0x04,0x04,0xfc,0x00,0x00,0x00,0x00,0x00 }, { 0xfc,0x04,0x04,0x3c,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0xf8,0x04,0x04,0xe4,0x84,0x84,0xf8,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x84,0x84,0xfc,0x84,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x38,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x80,0x80,0x80,0x80,0x80,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x44,0x24,0x1c,0x24,0x44,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x04,0x04,0x04,0x04,0x04,0xfc,0x00,0x00,0x00,0x00,0x00 }, { 0x82,0xc6,0xaa,0x92,0x82,0x82,0x82,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x8c,0x94,0xa4,0xc4,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x84,0x84,0x7c,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x84,0x84,0xa4,0x44,0xb8,0x00,0x00,0x00,0x00,0x00 }, { 0x7c,0x84,0x84,0x7c,0x24,0x44,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x78,0x84,0x04,0x78,0x80,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0xfe,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x82,0x82,0x82,0x82,0x44,0x28,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x82,0x82,0x82,0x92,0xaa,0xc6,0x82,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x84,0x48,0x30,0x48,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x82,0x82,0x44,0x38,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0xfe,0x40,0x20,0x10,0x08,0x04,0xfe,0x00,0x00,0x00,0x00,0x00 }, { 0x84,0x30,0x48,0x84,0xfc,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, /* =C4 */ { 0x84,0x00,0x78,0x84,0x84,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, /* =D6 */ { 0x84,0x00,0x84,0x84,0x84,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, /* =DC */ { 0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, /* - */ { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0x00 }, { 0x08,0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x78,0x80,0xf8,0x84,0xf8,0x00,0x00,0x00,0x00,0x00 }, { 0x04,0x04,0x74,0x8c,0x84,0x8c,0x74,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x78,0x84,0x04,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x80,0x80,0xb8,0xc4,0x84,0xc4,0xb8,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x78,0x84,0xfc,0x04,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x70,0x88,0x08,0x1c,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x78,0x84,0x84,0xf8,0x80,0x78,0x00,0x00,0x00,0x00 }, { 0x04,0x04,0x74,0x8c,0x84,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x00,0x18,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x80,0x00,0xc0,0x80,0x80,0x84,0x84,0x78,0x00,0x00,0x00,0x00 }, { 0x04,0x04,0x84,0x44,0x3c,0x44,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x18,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x6e,0x92,0x92,0x92,0x82,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x74,0x8c,0x84,0x84,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x78,0x84,0x84,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x74,0x8c,0x8c,0x74,0x04,0x04,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0xb8,0xc4,0xc4,0xb8,0x80,0x80,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x74,0x8c,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0xf8,0x04,0x78,0x80,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x10,0x10,0x7c,0x10,0x10,0x90,0x60,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x44,0x44,0x44,0x44,0xb8,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x82,0x82,0x44,0x28,0x10,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x82,0x92,0x92,0x92,0x6c,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x84,0x48,0x30,0x48,0x84,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x84,0x84,0x84,0xf8,0x80,0x78,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x7c,0x20,0x10,0x08,0x7c,0x00,0x00,0x00,0x00,0x00 }, { 0x48,0x00,0x78,0x80,0xf8,0x84,0xf8,0x00,0x00,0x00,0x00,0x00 }, /* =E4 */ { 0x48,0x00,0x78,0x84,0x84,0x84,0x78,0x00,0x00,0x00,0x00,0x00 }, /* =F6 */ { 0x44,0x00,0x44,0x44,0x44,0x44,0xb8,0x00,0x00,0x00,0x00,0x00 }, /* =FC */ { 0x38,0x44,0x44,0x74,0x84,0x84,0x74,0x00,0x00,0x00,0x00,0x00 }, /* =DF */ { 0xaa,0x54,0xaa,0x54,0xaa,0x54,0xaa,0x54,0x00,0x00,0x00,0x00 }, } }; xtrs-4.9d/trs_disk.c000066400000000000000000003135761306603614600145440ustar00rootroot00000000000000/* Copyright (c) 1996, Timothy Mann */ /* $Id: trs_disk.c,v 1.55 2009/06/16 00:06:20 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* * Emulate Model I or III/4 disk controller */ /* * Debug flags. Update help_message in debug.c if these change. */ #define DISKDEBUG_FDCREG (1<<0) /* FDC register reads and writes */ #define DISKDEBUG_FDCCMD (1<<1) /* FDC commands */ #define DISKDEBUG_VTOS3 (1<<2) /* VTOS 3.0 JV3 kludges */ #define DISKDEBUG_GAPS (1<<3) /* Gaps and real_writetrk */ #define DISKDEBUG_REALSIZE (1<<4) /* REAL sector size detection */ #define DISKDEBUG_READADR (1<<5) /* Read Address timing */ #define DISKDEBUG_DMK (1<<6) /* DMK support */ #define DISKDEBUG_REALERR (1<<7) /* ioctl errors accessing real disks */ #define TSTATEREV 1 /* Index holes timed by T-states, not real time */ #define SIZERETRY 1 /* Retry in different sizes on real_read */ #define DMK_MARK_IAM 0 /* Mark IAMs in track header; poor idea */ #include "z80.h" #include "trs.h" #include "trs_disk.h" #include "trs_hard.h" #include #include #include #include #include #include #include #include #include #include "crc.c" #if __linux #include #include #include #include #include #endif #define NDRIVES 8 int trs_disk_nocontroller = 0; int trs_disk_doubler = TRSDISK_BOTH; char *trs_disk_dir = DISKDIR; unsigned short trs_disk_changecount = 0; static int trs_disk_needchange = 0; float trs_disk_holewidth = 0.01; int trs_disk_truedam = 0; int trs_disk_debug_flags = 0; typedef struct { /* Registers */ unsigned char status; unsigned char track; unsigned char sector; unsigned char data; /* Other state */ unsigned char currcommand; int lastdirection; int bytecount; /* bytes left to transfer this command */ int format; /* write track state machine */ int format_bytecount; /* bytes left in this part of write track */ int format_sec; /* current sector number or id_index */ int format_gapcnt; /* measure requested gaps */ int format_gap[5]; unsigned short crc; unsigned curdrive; unsigned curside; unsigned density; /* sden=0, dden=1 */ unsigned char controller; /* TRSDISK_P1771 or TRSDISK_P1791 */ int last_readadr; /* id index found by last readadr */ tstate_t motor_timeout; /* 0 if stopped, else time when it stops */ } FDCState; FDCState state, other_state; /* Format states - what is expected next? */ #define FMT_GAP0 0 #define FMT_IAM 1 #define FMT_GAP1 2 #define FMT_IDAM 3 #define FMT_TRACKID 4 #define FMT_HEADID 5 #define FMT_SECID 6 #define FMT_SIZEID 7 #define FMT_IDCRC 8 #define FMT_GAP2 9 #define FMT_DAM 10 #define FMT_DATA 11 #define FMT_DCRC 12 #define FMT_GAP3 13 #define FMT_GAP4 14 #define FMT_DONE 15 #define FMT_PREAM 16 /* DDEN DMK only -- just saw preamble to an AM */ #define FMT_IPREAM 17 /* DDEN DMK only -- just saw preamble to an IAM */ /* Gap 0+1 and gap 4 angular size, used in Read Address timing emulation. Units: fraction of a complete circle. */ #define GAP1ANGLE 0.020 #define GAP4ANGLE 0.050 /* How long does emulated motor stay on after drive selected? (us of emulated time) */ #define MOTOR_USEC 2000000 /* Heuristic: how often are we willing to check whether real drive has a disk in it? (seconds of real time) */ #define EMPTY_TIMEOUT 3 /* * The following rather quirky data structure is designed to be * compatible with what Jeff Vavasour's Model III/4 emulator uses to * represent disk formatting information. My interpretation is based * on reading his documentation, looking at some disk images, and * experimenting with his emulator to generate odd cases, so the * compatibility should be excellent. * * I have compatibly extended the format to allow for more sectors, so * that 8" DSDD drives can be supported, by adding a second block of * ids after the block of data sectors that is described by the first * block. JV himself says that sounds like a good idea. Matthew * Reed's emulators now support this extension. * * I've further extended the format to add a flag bit for non-IBM * sectors. Only a subset of the non-IBM functionality is supported, * rigged to make the VTOS 3.0 copy-protection system work. Non-IBM * sectors were a feature of the 1771 only. Using this feature, you * could have a sector of any length from 16 to 4096 bytes in * multiples of 16. xtrs supports only 16-byte non-IBM sectors (with * their data stored in a 256-byte field), and has some special kludges * to detect and support VTOS's trick of formatting these sectors with * inadequate gaps between so that writing to one would smash the * index block of the next one. * * Finally, I've extended the format to support (IBM) sector lengths * other than 256 bytes. The standard lengths 128, 256, 512, and 1024 * are supported, using the last two available bits in the header * flags byte. The data area of a floppy image thus becomes an array * of *variable length* sectors, making it more complicated to find * the sector data corresponding to a given header and to manage freed * sectors. * * NB: JV's model I emulator uses no auxiliary data structure for disk * format. It simply assumes that all disks are single density, 256 * bytes/sector, 10 sectors/track, single sided, with nonstandard FA * data address mark on all sectors on track 17. */ /* Values for flags below */ #define JV3_DENSITY 0x80 /* 1=dden, 0=sden */ #define JV3_DAM 0x60 /* data address mark; values follow */ #define JV3_DAMSDFB 0x00 #define JV3_DAMSDFA 0x20 #define JV3_DAMSDF9 0x40 #define JV3_DAMSDF8 0x60 #define JV3_DAMDDFB 0x00 #define JV3_DAMDDF8 0x20 #define JV3_SIDE 0x10 /* 0=side 0, 1=side 1 */ #define JV3_ERROR 0x08 /* 0=ok, 1=CRC error */ #define JV3_NONIBM 0x04 /* 0=normal, 1=short (for VTOS 3.0, xtrs only) */ #define JV3_SIZE 0x03 /* in used sectors: 0=256,1=128,2=1024,3=512 in free sectors: 0=512,1=1024,2=128,3=256 */ #define JV3_FREE 0xff /* in track/sector fields */ #define JV3_FREEF 0xfc /* in flags field, or'd with size code */ typedef struct { unsigned char track; unsigned char sector; unsigned char flags; } SectorId; #define MAXTRACKS 255 #define JV1_SECSIZE 256 #define MAXSECSIZE 1024 /* Max bytes per unformatted track. */ /* Select codes 1, 2, 4, 8 are emulated 5" drives, disk?-0 to disk?-3 */ #define TRKSIZE_SD 3125 /* 250kHz / 5 Hz [300rpm] / (2 * 8) */ /* or 300kHz / 6 Hz [360rpm] / (2 * 8) */ #define TRKSIZE_DD 6250 /* 250kHz / 5 Hz [300rpm] / 8 */ /* or 300kHz / 6 Hz [360rpm] / 8 */ /* Select codes 3, 5, 6, 7 are emulated 8" drives, disk?-4 to disk?-7 */ #define TRKSIZE_8SD 5208 /* 500kHz / 6 Hz [360rpm] / (2 * 8) */ #define TRKSIZE_8DD 10416 /* 500kHz / 6 Hz [360rpm] / 8 */ /* TRS-80 software has no concept of HD, so these constants are unused, * but expanded JV3 would be big enough even for 3.5" HD. */ #define TRKSIZE_5HD 10416 /* 500kHz / 6 Hz [360rpm] / 8 */ #define TRKSIZE_3HD 12500 /* 500kHz / 5 Hz [300rpm] / 8 */ #define JV3_SIDES 2 #define JV3_IDSTART 0 #define JV3_SECSTART (34*256) /* start of sectors within file */ #define JV3_SECSPERBLK ((int)(JV3_SECSTART/3)) #define JV3_SECSMAX (2*JV3_SECSPERBLK) #define JV1_SECPERTRK 10 /* Values for emulated disk image type (emutype) below */ #define JV1 1 /* compatible with Vavasour Model I emulator */ #define JV3 3 /* compatible with Vavasour Model III/4 emulator */ #define DMK 4 /* compatible with Keil Model III/4 emulator */ #define REAL 100 /* real floppy drive, PC controller */ #define CATW 101 /* real floppy drive, Catweasel controller (future) */ #define NONE 0 typedef struct { int free_id[4]; /* first free id, if any, of each size */ int last_used_id; /* last used index */ int nblocks; /* number of blocks of ids, 1 or 2 */ int sorted_valid; /* sorted_id array valid */ SectorId id[JV3_SECSMAX + 1]; /* extra one is a loop sentinel */ int offset[JV3_SECSMAX + 1]; /* offset into file for each id */ short sorted_id[JV3_SECSMAX + 1]; short track_start[MAXTRACKS][JV3_SIDES]; } JV3State; typedef struct { int rps; /* phys rotations/sec; emutype REAL only */ int size_code; /* most recent sector size; REAL only */ int empty; /* 1=emulate empty drive */ time_t empty_timeout; /* real_empty valid until this time */ int fmt_nbytes; /* number of PC format command bytes */ int fmt_fill; /* fill byte for data sectors */ unsigned char buf[MAXSECSIZE]; } RealState; /* Some constants for DMK format */ #define DMK_WRITEPROT 0 #define DMK_NTRACKS 1 #define DMK_TRACKLEN 2 #define DMK_TRACKLEN_SIZE 2 #define DMK_OPTIONS 4 #define DMK_FORMAT 0x0c #define DMK_FORMAT_SIZE 4 #define DMK_HDR_SIZE 0x10 #define DMK_TKHDR_SIZE 0x80 /* Space reserved for IDAM pointers */ #define DMK_TRACKLEN_MAX 0x4000 /* Bit assignments in options */ #define DMK_SSIDE_OPT 0x10 #define DMK_SDEN_OPT 0x40 #define DMK_IGNDEN_OPT 0x80 /* Bit assignments in IDAM pointers */ #define DMK_DDEN_FLAG 0x8000 #define DMK_EXTRA_FLAG 0x4000 /* unused */ #define DMK_IDAMP_BITS 0x3fff #define dmk_incr(d) \ (((d)->u.dmk.ignden || (d)->u.dmk.sden || state.density) ? 1 : 2) typedef struct { int ntracks; /* max number of tracks formatted */ int tracklen; /* bytes reserved per track in file */ int nsides; /* 1 or 2 (single-sided flag in header) */ int sden; /* single-density-only flag in header */ int ignden; /* ignore-density flag in header */ int curtrack, curside; /* track/side in track buffer, or -1/-1 */ int curbyte; /* index in buf for current op */ int nextidam; /* index in buf to put next idam */ unsigned char buf[DMK_TRACKLEN_MAX]; } DMKState; typedef struct { int writeprot; /* emulated write protect tab */ int phytrack; /* where are we really? */ int emutype; int inches; /* 5 or 8, as seen by TRS-80 */ int real_step; /* 1=normal, 2=double-step if REAL */ FILE* file; union { JV3State jv3; /* valid if emutype = JV3 */ RealState real; /* valid if emutype = REAL */ DMKState dmk; /* valid if emutype = DMK */ } u; } DiskState; DiskState disk[NDRIVES]; /* Emulate interleave in JV1 mode */ unsigned char jv1_interleave[10] = {0, 5, 1, 6, 2, 7, 3, 8, 4, 9}; /* Forward */ void real_verify(); void real_restore(int curdrive); void real_seek(); void real_read(); void real_write(); void real_readadr(); void real_readtrk(); void real_writetrk(); int real_check_empty(DiskState *d); /* Entry point for the zbx debugger */ void trs_disk_debug() { int i; printf("Floppy disk controller state:\n"); printf(" status 0x%02x, track %d (0x%02x), sector %d (0x%02x), " "data 0x%02x\n", state.status, state.track, state.track, state.sector, state.sector, state.data); printf(" currcommand 0x%02x, bytecount left %d, last step direction %d\n", state.currcommand, state.bytecount, state.lastdirection); printf(" curdrive %d, curside %d, density %d, controller %s\n", state.curdrive, state.curside, state.density, state.controller == TRSDISK_P1771 ? "WD1771" : "WD1791/93"); printf(" crc state 0x%04x, last_readadr %d, motor timeout %ld\n", state.crc, state.last_readadr, (long) (state.motor_timeout - z80_state.t_count)); printf(" last (non-DMK) format gaps %d %d %d %d %d\n", state.format_gap[0], state.format_gap[1], state.format_gap[2], state.format_gap[3], state.format_gap[4]); printf(" debug flags: %#x\n", trs_disk_debug_flags); for (i=0; iwriteprot, d->phytrack, d->phytrack, d->inches, d->real_step); if (d->file == NULL) { printf("EMPTY\n"); } else { switch (d->emutype) { case JV1: printf("JV1\n"); break; case JV3: printf("JV3\n"); printf(" last used id %d, id blocks %d\n", d->u.jv3.last_used_id, d->u.jv3.nblocks); break; case DMK: printf("DMK\n"); printf(" ntracks %d (0x%02x), tracklen 0x%04x, nsides %d, sden %d, " "ignden %d\n", d->u.dmk.ntracks, d->u.dmk.ntracks, d->u.dmk.tracklen, d->u.dmk.nsides, d->u.dmk.sden, d->u.dmk.ignden); printf(" buffered track %d, side %d, curbyte %d, nextidam %d\n", d->u.dmk.curtrack, d->u.dmk.curside, d->u.dmk.curbyte, d->u.dmk.nextidam); break; case REAL: printf("REAL\n"); printf(" rpm %d, empty %d, last size code %d, last fmt fill 0x%02x\n", d->u.real.rps * 60, d->u.real.empty, d->u.real.size_code, d->u.real.fmt_fill); break; default: printf("UNKNOWN\n"); break; } } } } void trs_disk_setsize(int unit, int value) { if (unit < 0 || unit > 7) return; disk[unit].inches = (value == 8) ? 8 : 5; } void trs_disk_setstep(int unit, int value) { if (unit < 0 || unit > 7) return; disk[unit].real_step = (value == 2) ? 2 : 1; } int trs_disk_getsize(int unit) { if (unit < 0 || unit > 7) return 0; return disk[unit].inches; } int trs_disk_getstep(int unit) { if (unit < 0 || unit > 7) return 0; return disk[unit].real_step; } void trs_sigusr1(int signo) { trs_disk_needchange = 1; } void trs_disk_init(int poweron) { int i; struct sigaction sa; state.status = TRSDISK_NOTRDY|TRSDISK_TRKZERO; state.track = 0; state.sector = 0; state.data = 0; state.currcommand = TRSDISK_RESTORE; state.lastdirection = 1; state.bytecount = 0; state.format = FMT_DONE; state.format_bytecount = 0; state.format_sec = 0; state.curdrive = state.curside = 0; state.density = 0; state.controller = (trs_model == 1) ? TRSDISK_P1771 : TRSDISK_P1791; state.last_readadr = -1; state.motor_timeout = 0; if (poweron) { for (i=0; iu.jv3.id[i1].track - d->u.jv3.id[i2].track; if (r != 0) return r; r = (d->u.jv3.id[i1].flags & JV3_SIDE) - (d->u.jv3.id[i2].flags & JV3_SIDE); if (r != 0) return r; return i1 - i2; } /* (Re-)create the sorted_id data structure for the given drive */ void jv3_sort_ids(int drive) { DiskState *d = &disk[drive]; int olddrive = state.curdrive; int i, track, side; for (i=0; i<=JV3_SECSMAX; i++) { d->u.jv3.sorted_id[i] = i; } state.curdrive = drive; qsort((void*) d->u.jv3.sorted_id, JV3_SECSMAX, sizeof(short), jv3_id_compare); state.curdrive = olddrive; for (track=0; tracku.jv3.track_start[track][0] = -1; d->u.jv3.track_start[track][1] = -1; } track = side = -1; for (i=0; iu.jv3.id[d->u.jv3.sorted_id[i]]; if (sid->track != track || (sid->flags & JV3_SIDE ? 1 : 0) != side) { track = sid->track; if (track == JV3_FREE) break; side = sid->flags & JV3_SIDE ? 1 : 0; d->u.jv3.track_start[track][side] = i; } } d->u.jv3.sorted_valid = 1; } /* JV3 only */ int id_index_to_size_code(DiskState *d, int id_index) { return (d->u.jv3.id[id_index].flags & JV3_SIZE) ^ ((d->u.jv3.id[id_index].track == JV3_FREE) ? 2 : 1); } /* IBM formats only */ int size_code_to_size(int code) { return 128 << code; } /* JV3 only */ int id_index_to_size(DiskState *d, int id_index) { return 128 << id_index_to_size_code(d, id_index); } /* Return the offset of the data block for the id_index'th sector in an emulated-disk file. Not used for DMK. */ static off_t offset(DiskState *d, int id_index) { if (d->emutype == JV1) { return id_index * JV1_SECSIZE; } else if (d->emutype == JV3) { return d->u.jv3.offset[id_index]; } else { trs_disk_unimpl(state.currcommand, "DMK offset (internal error)"); return 0; } } /* Return the offset of the id block for the id_index'th sector in an emulated-disk file. Initialize a new block if needed. JV3 only. */ static off_t idoffset(DiskState *d, int id_index) { if (d->emutype == JV1 || d->emutype == DMK) { trs_disk_unimpl(state.currcommand, "JV1 or DMK idoffset (internal error)"); return -1; } else { if (id_index < JV3_SECSPERBLK) { return JV3_IDSTART + id_index * sizeof(SectorId); } else { int idstart2 = d->u.jv3.offset[JV3_SECSPERBLK-1] + id_index_to_size(d, JV3_SECSPERBLK-1); if (d->u.jv3.nblocks == 1) { /* Initialize new block of ids */ int c; fseek(d->file, idstart2, 0); c = fwrite((void*)&d->u.jv3.id[JV3_SECSPERBLK], JV3_SECSTART, 1, d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; c = fflush(d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; d->u.jv3.nblocks = 2; } return idstart2 + (id_index - JV3_SECSPERBLK) * sizeof(SectorId); } } } int jv3_alloc_sector(DiskState *d, int size_code) { int maybe = d->u.jv3.free_id[size_code]; d->u.jv3.sorted_valid = 0; while (maybe <= d->u.jv3.last_used_id) { if (d->u.jv3.id[maybe].track == JV3_FREE && id_index_to_size_code(d, maybe) == size_code) { d->u.jv3.free_id[size_code] = maybe + 1; return maybe; } maybe++; } d->u.jv3.free_id[size_code] = JV3_SECSMAX; /* none are free */ if (d->u.jv3.last_used_id >= JV3_SECSMAX-1) { return -1; } d->u.jv3.last_used_id++; d->u.jv3.offset[d->u.jv3.last_used_id + 1] = d->u.jv3.offset[d->u.jv3.last_used_id] + size_code_to_size(size_code); if (d->u.jv3.last_used_id + 1 == JV3_SECSPERBLK) { d->u.jv3.offset[d->u.jv3.last_used_id + 1] += JV3_SECSTART; } return d->u.jv3.last_used_id; } void jv3_free_sector(DiskState *d, int id_index) { int c; int size_code = (d->u.jv3.id[id_index].flags & JV3_SIZE) ^ 1; if (d->u.jv3.free_id[size_code] > id_index) { d->u.jv3.free_id[size_code] = id_index; } d->u.jv3.sorted_valid = 0; d->u.jv3.id[id_index].track = JV3_FREE; d->u.jv3.id[id_index].sector = JV3_FREE; d->u.jv3.id[id_index].flags = (d->u.jv3.id[id_index].flags | JV3_FREEF) ^ JV3_SIZE; fseek(d->file, idoffset(d, id_index), 0); c = fwrite(&d->u.jv3.id[id_index], sizeof(SectorId), 1, d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; if (id_index == d->u.jv3.last_used_id) { int newlen; while (d->u.jv3.id[d->u.jv3.last_used_id].track == JV3_FREE) { d->u.jv3.last_used_id--; } c = fflush(d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; rewind(d->file); if (d->u.jv3.last_used_id >= 0) { newlen = offset(d, d->u.jv3.last_used_id) + id_index_to_size(d, d->u.jv3.last_used_id); } else { newlen = offset(d, 0); } c = ftruncate(fileno(d->file), newlen); if (c == EOF) state.status |= TRSDISK_WRITEFLT; } } /* Heuristic to decide what file format we have */ /* Also decodes write-protect state */ void trs_disk_emutype(DiskState *d) { int c; char fmt[4]; int count; fseek(d->file, 0, 0); c = getc(d->file); if (c == -1) { d->emutype = JV1; return; } if (c == 0 || c == 0xff) { fseek(d->file, DMK_FORMAT, 0); count = fread(fmt, 1, DMK_FORMAT_SIZE, d->file); if (count != DMK_FORMAT_SIZE) { d->emutype = JV1; return; } if (fmt[0] == 0 && fmt[1] == 0 && fmt[2] == 0 && fmt[3] == 0) { fseek(d->file, DMK_TRACKLEN, 0); count = (unsigned char) getc(d->file); count += (unsigned char) getc(d->file) << 8; if (count >= 16 && count <= DMK_TRACKLEN_MAX) { d->emutype = DMK; d->writeprot = d->writeprot || (c == 0xff); return; } } if (fmt[0] == 0x78 && fmt[1] == 0x56 && fmt[2] == 0x34 && fmt[3] == 0x12) { error("Real disk specifier file from DMK emulator not supported"); d->emutype = NONE; fclose(d->file); d->file = NULL; return; } } if (c == 0) { fseek(d->file, 1, 0); if (getc(d->file) == 0xfe) { d->emutype = JV1; return; } } fseek(d->file, JV3_SECSPERBLK*sizeof(SectorId), 0); c = getc(d->file); if (c == 0 || c == 0xff) { d->emutype = JV3; d->writeprot = d->writeprot || (c == 0); return; } d->emutype = JV1; } void trs_disk_change(int drive) { char diskname[1024]; DiskState *d = &disk[drive]; struct stat st; int c, res; if (d->file != NULL) { c = fclose(d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; } if (trs_model == 5) { sprintf(diskname, "%s/disk4p-%d", trs_disk_dir, drive); } else { sprintf(diskname, "%s/disk%d-%d", trs_disk_dir, trs_model, drive); } res = stat(diskname, &st); if (res == -1) { d->file = NULL; return; } #if __linux if (S_ISBLK(st.st_mode)) { /* Real floppy drive */ int fd; int reset_now = 0; struct floppy_drive_params fdp; fd = open(diskname, O_ACCMODE|O_NDELAY); if (fd == -1) { error("%s: %s", diskname, strerror(errno)); d->file = NULL; d->emutype = JV3; return; } d->file = fdopen(fd, "r+"); if (d->file == NULL) { error("%s: %s", diskname, strerror(errno)); d->emutype = JV3; return; } d->writeprot = 0; ioctl(fileno(d->file), FDRESET, &reset_now); ioctl(fileno(d->file), FDGETDRVPRM, &fdp); d->u.real.rps = fdp.rps; d->u.real.size_code = 1; /* initial guess: 256 bytes */ d->u.real.empty_timeout = 0; if (d->emutype != REAL) { d->emutype = REAL; d->phytrack = 0; real_restore(drive); } } else #endif { d->file = fopen(diskname, "r+"); if (d->file == NULL) { d->file = fopen(diskname, "r"); if (d->file == NULL) return; d->writeprot = 1; } else { d->writeprot = 0; } trs_disk_emutype(d); } if (d->emutype == JV3) { int id_index, n; int ofst; memset((void*)d->u.jv3.id, JV3_FREE, sizeof(d->u.jv3.id)); /* Read first block of ids */ fseek(d->file, JV3_IDSTART, 0); (void) fread((void*)&d->u.jv3.id[0], 3, JV3_SECSPERBLK, d->file); /* Scan to find their offsets */ ofst = JV3_SECSTART; for (id_index=0; id_indexu.jv3.offset[id_index] = ofst; ofst += id_index_to_size(d, id_index); } /* Read second block of ids, if any */ fseek(d->file, ofst, 0); n = fread((void*)&d->u.jv3.id[JV3_SECSPERBLK], 3, JV3_SECSPERBLK, d->file); d->u.jv3.nblocks = n > 0 ? 2 : 1; /* Scan to find their offsets */ ofst += JV3_SECSTART; for (id_index=JV3_SECSPERBLK; id_indexu.jv3.offset[id_index] = ofst; ofst += id_index_to_size(d, id_index); } /* Find u.jv3.last_used_id value and u.jv3.free_id hints */ for (n=0; n<4; n++) { d->u.jv3.free_id[n] = JV3_SECSMAX; } d->u.jv3.last_used_id = -1; for (id_index=0; id_indexu.jv3.id[id_index].track == JV3_FREE) { int size_code = id_index_to_size_code(d, id_index); if (d->u.jv3.free_id[size_code] == JV3_SECSMAX) { d->u.jv3.free_id[size_code] = id_index; } } else { d->u.jv3.last_used_id = id_index; } } jv3_sort_ids(drive); } else if (d->emutype == DMK) { fseek(d->file, DMK_NTRACKS, 0); d->u.dmk.ntracks = (unsigned char) getc(d->file); d->u.dmk.tracklen = (unsigned char) getc(d->file) + (((unsigned char) getc(d->file)) << 8); c = getc(d->file); d->u.dmk.nsides = (c & DMK_SSIDE_OPT) ? 1 : 2; d->u.dmk.sden = (c & DMK_SDEN_OPT) != 0; d->u.dmk.ignden = (c & DMK_IGNDEN_OPT) != 0; d->u.dmk.curtrack = d->u.dmk.curside = -1; if (trs_disk_debug_flags & DISKDEBUG_DMK) { debug("DMK drv=%d wp=%d #tk=%d tklen=0x%x nsides=%d sden=%d ignden=%d\n", drive, d->writeprot, d->u.dmk.ntracks, d->u.dmk.tracklen, d->u.dmk.nsides, d->u.dmk.sden, d->u.dmk.ignden); } } } static int cmd_type(unsigned char cmd) { switch (cmd & TRSDISK_CMDMASK) { case TRSDISK_RESTORE: case TRSDISK_SEEK: case TRSDISK_STEP: case TRSDISK_STEPU: case TRSDISK_STEPIN: case TRSDISK_STEPINU: case TRSDISK_STEPOUT: case TRSDISK_STEPOUTU: return 1; case TRSDISK_READ: case TRSDISK_READM: case TRSDISK_WRITE: case TRSDISK_WRITEM: return 2; case TRSDISK_READADR: case TRSDISK_READTRK: case TRSDISK_WRITETRK: return 3; case TRSDISK_FORCEINT: return 4; } return -1; /* not reached */ } /* Called by the interrupt code to determine whether a motoroff NMI is required. Called even if this NMI is masked, so we also use it here to set NOTRDY and LOSTDATA. */ int trs_disk_motoroff() { int stopped; int cmdtype; stopped = (state.motor_timeout - z80_state.t_count > TSTATE_T_MID); if (stopped) { state.status |= TRSDISK_NOTRDY; cmdtype = cmd_type(state.currcommand); if ((cmdtype == 2 || cmdtype == 3) && (state.status & TRSDISK_DRQ)) { /* Also end the command and set Lost Data for good measure */ state.status = (state.status | TRSDISK_LOSTDATA) & ~(TRSDISK_BUSY | TRSDISK_DRQ); state.bytecount = 0; } } return stopped; } /* Get the on-disk track data from the current track/side into the buffer */ void dmk_get_track(DiskState* d) { int res; if (d->phytrack == d->u.dmk.curtrack && state.curside == d->u.dmk.curside) return; d->u.dmk.curtrack = d->phytrack; d->u.dmk.curside = state.curside; if (d->u.dmk.curtrack >= d->u.dmk.ntracks || (d->u.dmk.curside && d->u.dmk.nsides == 1)) { memset(d->u.dmk.buf, 0, sizeof(d->u.dmk.buf)); return; } fseek(d->file, (DMK_HDR_SIZE + (d->u.dmk.curtrack * d->u.dmk.nsides + d->u.dmk.curside) * d->u.dmk.tracklen), 0); res = fread(d->u.dmk.buf, d->u.dmk.tracklen, 1, d->file); if (res != 1) { memset(d->u.dmk.buf, 0, sizeof(d->u.dmk.buf)); return; } } /* Search for a sector on the current physical track. For JV1 or JV3, return its index within the emulated disk's array of sectors. For DMK, get the track into the buffer, return the index of the next byte after the header CRC, and set state.bytecount to its size code. Set status and return -1 if there is no such sector. If sector == -1, return the first sector found if any. If side == 0 or 1, perform side compare against sector ID; if -1, don't. */ static int search(int sector, int side) { DiskState *d = &disk[state.curdrive]; if (d->file == NULL) { state.status |= TRSDISK_NOTFOUND; return -1; } if (d->emutype == JV1) { if (d->phytrack < 0 || d->phytrack >= MAXTRACKS || state.curside > 0 || sector >= JV1_SECPERTRK || d->file == NULL || d->phytrack != state.track || state.density == 1 || side == 1) { state.status |= TRSDISK_NOTFOUND; return -1; } return JV1_SECPERTRK * d->phytrack + (sector < 0 ? 0 : sector); } else if (d->emutype == JV3) { int i; SectorId *sid; if (d->phytrack < 0 || d->phytrack >= MAXTRACKS || state.curside >= JV3_SIDES || (side != -1 && side != state.curside) || d->phytrack != state.track || d->file == NULL) { state.status |= TRSDISK_NOTFOUND; return -1; } if (!d->u.jv3.sorted_valid) jv3_sort_ids(state.curdrive); i = d->u.jv3.track_start[d->phytrack][state.curside]; if (i != -1) { for (;;) { sid = &d->u.jv3.id[d->u.jv3.sorted_id[i]]; if (sid->track != d->phytrack || (sid->flags & JV3_SIDE ? 1 : 0) != state.curside) break; if ((sector == -1 || sid->sector == sector) && ((sid->flags & JV3_DENSITY) ? 1 : 0) == state.density) { return d->u.jv3.sorted_id[i]; } i++; } } state.status |= TRSDISK_NOTFOUND; return -1; } else /* d->emutype == DMK */ { /* !!maybe someday start at a point determined by angle() and wrap back. would deal more realistically with disks that have more than one of the same sector. */ int i; int incr = dmk_incr(d); /* get current phytrack into buffer */ dmk_get_track(d); /* loop through IDAMs in track */ for (i = 0; i < DMK_TKHDR_SIZE; i+=2) { unsigned char *p; /* fetch index of next IDAM */ int idamp = d->u.dmk.buf[i] + (d->u.dmk.buf[i+1] << 8); /* fail if no more IDAMs */ if (idamp == 0) break; /* skip IDAM if wrong density */ if (!d->u.dmk.ignden && state.density != ((idamp & DMK_DDEN_FLAG) != 0)) continue; /* point p to IDAM */ idamp &= DMK_IDAMP_BITS; p = &d->u.dmk.buf[idamp]; /* fail if IDAM out of range */ if (idamp >= DMK_TRACKLEN_MAX) break; /* initialize ID CRC */ state.crc = state.density ? 0xcdb4 /* CRC of a1 a1 a1 */ : 0xffff; /* sanity check; is this an IDAM at all? */ if (*p != 0xfe) continue; state.crc = calc_crc1(state.crc, *p); p += incr; /* compare track field of ID */ if (*p != state.track) continue; state.crc = calc_crc1(state.crc, *p); p += incr; /* compare side field of ID if desired */ if ((*p & 1) != side && side != -1) continue; state.crc = calc_crc1(state.crc, *p); p += incr; /* compare sector field of ID if desired */ if (*p != sector && sector != -1) continue; state.crc = calc_crc1(state.crc, *p); p += incr; /* save size code field of ID; caller converts to actual byte count */ state.bytecount = *p; state.crc = calc_crc1(state.crc, *p); p += incr; /* fold CRC field into computation; result should be 0 */ state.crc = calc_crc1(state.crc, *p); p += incr; state.crc = calc_crc1(state.crc, *p); p += incr; if (state.crc != 0) { /* set CRC error flag and look for another ID that matches */ state.status |= TRSDISK_CRCERR; continue; } else { /* clear CRC error flag in case set for an earlier ID match */ state.status &= ~TRSDISK_CRCERR; } /* Found an ID that matches */ d->u.dmk.nextidam = i + 2; /* remember where the next one is */ return p - d->u.dmk.buf; } state.status |= TRSDISK_NOTFOUND; return -1; } } /* Search for the first sector on the current physical track (in either density) and return its index within the sorted index array (JV3), or index within the sector array (JV1). Not used for DMK. Return -1 if there is no such sector, or if reading JV1 in double density. Don't set TRSDISK_NOTFOUND; leave the caller to do that. */ static int search_adr() { DiskState *d = &disk[state.curdrive]; if (d->file == NULL) { return -1; } if (d->emutype == JV1) { if (d->phytrack < 0 || d->phytrack >= MAXTRACKS || state.curside > 0 || d->file == NULL || state.density == 1) { return -1; } return JV1_SECPERTRK * d->phytrack; } else { if (d->phytrack < 0 || d->phytrack >= MAXTRACKS || state.curside >= JV3_SIDES || d->file == NULL) { return -1; } if (!d->u.jv3.sorted_valid) jv3_sort_ids(state.curdrive); return d->u.jv3.track_start[d->phytrack][state.curside]; } } void verify() { /* Verify that head is on the expected track */ DiskState *d = &disk[state.curdrive]; if (d->emutype == REAL) { real_verify(); } else if (d->emutype == JV1) { if (d->file == NULL) { state.status |= TRSDISK_NOTFOUND; } if (state.density == 1) { state.status |= TRSDISK_NOTFOUND; } else if (state.track != d->phytrack) { state.status |= TRSDISK_SEEKERR; } } else { search(-1, -1); /* TRSDISK_SEEKERR == TRSDISK_NOTFOUND */ } } /* Return a value in [0,1) indicating how far we've rotated * from the leading edge of the index hole */ float angle() { DiskState *d = &disk[state.curdrive]; float a; /* Set revus to number of microseconds per revolution */ int revus = d->inches == 5 ? 200000 /* 300 RPM */ : 166666 /* 360 RPM */; #if TSTATEREV /* Lock revolution rate to emulated time measured in T-states */ /* Minor bug: there will be a glitch when t_count wraps around on a 32-bit machine */ int revt = (int)(revus * z80_state.clockMHz); a = ((float)(z80_state.t_count % revt)) / ((float)revt); #else /* Old way: lock revolution rate to real time */ struct timeval tv; gettimeofday(&tv, NULL); /* Ignore the seconds field; this is OK if there are a round number of revolutions per second */ a = ((float)(tv.tv_usec % revus)) / ((float)revus); #endif return a; } static void type1_status() { DiskState *d = &disk[state.curdrive]; switch (cmd_type(state.currcommand)) { case 1: case 4: break; default: return; } if (d->file == NULL || (d->emutype == REAL && d->u.real.empty)) { state.status |= TRSDISK_INDEX; } else { if (angle() < trs_disk_holewidth) { state.status |= TRSDISK_INDEX; } else { state.status &= ~TRSDISK_INDEX; } if (d->writeprot) { state.status |= TRSDISK_WRITEPRT; } else { state.status &= ~TRSDISK_WRITEPRT; } } if (d->phytrack == 0) { state.status |= TRSDISK_TRKZERO; } else { state.status &= ~TRSDISK_TRKZERO; } /* RDY and HLT inputs are wired together on TRS-80 I/III/4/4P */ if (state.status & TRSDISK_NOTRDY) { state.status &= ~TRSDISK_HEADENGD; } else { state.status |= TRSDISK_HEADENGD; } } void trs_disk_select_write(unsigned char data) { static int old_data = -1; if ((trs_disk_debug_flags & DISKDEBUG_FDCREG) && data != old_data) { debug("select_write(0x%02x) pc 0x%04x\n", data, REG_PC); old_data = data; } state.status &= ~TRSDISK_NOTRDY; if (trs_model == 1) { /* Disk 3 and side select share a bit. You can't have a drive :3 on a real Model I if any drive is two-sided. Here we are more generous and just forbid drive :3 from being 2-sided. */ state.curside = ( (data & (TRSDISK_0|TRSDISK_1|TRSDISK_2)) != 0 && (data & TRSDISK_SIDE) != 0 ); if (state.curside) data &= ~TRSDISK_SIDE; } else { state.curside = (data & TRSDISK3_SIDE) != 0; state.density = (data & TRSDISK3_MFM) != 0; if (data & TRSDISK3_WAIT) { /* If there was an event pending, simulate waiting until it was due. */ if (trs_event_scheduled() != NULL && trs_event_scheduled() != trs_disk_lostdata) { z80_state.t_count = z80_state.sched; trs_do_event(); } } } switch (data & (TRSDISK_0|TRSDISK_1|TRSDISK_2|TRSDISK_3)) { case 0: state.status |= TRSDISK_NOTRDY; break; case TRSDISK_0: state.curdrive = 0; break; case TRSDISK_1: state.curdrive = 1; break; case TRSDISK_2: state.curdrive = 2; break; case TRSDISK_3: state.curdrive = 3; break; case TRSDISK_4: /* fake value for emulator only */ state.curdrive = 4; break; case TRSDISK_5: /* fake value for emulator only */ state.curdrive = 5; break; case TRSDISK_6: /* fake value for emulator only */ state.curdrive = 6; break; case TRSDISK_7: /* fake value for emulator only */ state.curdrive = 7; break; default: trs_disk_unimpl(data, "bogus drive select"); state.status |= TRSDISK_NOTRDY; break; } /* If a drive was selected... */ if (!(state.status & TRSDISK_NOTRDY)) { DiskState *d = &disk[state.curdrive]; /* Retrigger emulated motor timeout */ state.motor_timeout = z80_state.t_count + MOTOR_USEC * z80_state.clockMHz; trs_disk_motoroff_interrupt(0); /* If a SIGUSR1 disk change is pending, accept it here */ if (trs_disk_needchange) { trs_disk_change_all(); trs_disk_needchange = 0; } /* Update our knowledge of whether there is a real disk present */ if (d->emutype == REAL) real_check_empty(d); } } unsigned char trs_disk_track_read(void) { if (trs_disk_debug_flags & DISKDEBUG_FDCREG) { debug("track_read() => 0x%02x pc 0x%04x\n", state.track, REG_PC); } return state.track; } void trs_disk_track_write(unsigned char data) { if (trs_disk_debug_flags & DISKDEBUG_FDCREG) { debug("track_write(0x%02x) pc 0x%04x\n", data, REG_PC); } state.track = data; } unsigned char trs_disk_sector_read(void) { if (trs_disk_debug_flags & DISKDEBUG_FDCREG) { debug("sector_read() => 0x%02x pc 0x%04x\n", state.sector, REG_PC); } return state.sector; } void trs_disk_set_controller(int controller) { /* Support for more accurate Doubler emulation */ FDCState tmp_state; if (state.controller == controller) return; tmp_state.status = state.status; tmp_state.track = state.track; tmp_state.sector = state.sector; tmp_state.data = state.data; tmp_state.lastdirection = state.lastdirection; state.controller = controller; state.status = other_state.status; state.track = other_state.track; state.sector = other_state.sector; state.data = other_state.data; state.lastdirection = other_state.lastdirection; other_state.status = tmp_state.status; other_state.track = tmp_state.track; other_state.sector = tmp_state.sector; other_state.data = tmp_state.data; other_state.lastdirection = tmp_state.lastdirection; } void trs_disk_sector_write(unsigned char data) { if (trs_disk_debug_flags & DISKDEBUG_FDCREG) { debug("sector_write(0x%02x) pc 0x%04x\n", data, REG_PC); } if (trs_model == 1 && (trs_disk_doubler & TRSDISK_TANDY)) { switch (data) { /* Emulate Radio Shack doubler */ case TRSDISK_R1791: trs_disk_set_controller(TRSDISK_P1791); state.density = 1; break; case TRSDISK_R1771: trs_disk_set_controller(TRSDISK_P1771); state.density = 0; break; case TRSDISK_NOPRECMP: case TRSDISK_PRECMP: /* Nothing for emulator to do */ break; default: break; } } state.sector = data; } unsigned char trs_disk_data_read(void) { DiskState *d = &disk[state.curdrive]; SectorId *sid; switch (state.currcommand & TRSDISK_CMDMASK) { case TRSDISK_READ: if (state.bytecount > 0 && (state.status & TRSDISK_DRQ)) { int c; if (d->emutype == REAL) { c = d->u.real.buf[size_code_to_size(d->u.real.size_code) - state.bytecount]; } else if (d->emutype == DMK) { c = d->u.dmk.buf[d->u.dmk.curbyte]; state.crc = calc_crc1(state.crc, c); d->u.dmk.curbyte += dmk_incr(d); } else { c = getc(d->file); if (c == EOF) { c = 0xe5; if (d->emutype == JV1) { state.status &= ~TRSDISK_RECTYPE; state.status |= (state.controller == TRSDISK_P1771) ? TRSDISK_1771_FB : TRSDISK_1791_FB; } } } state.data = c; state.bytecount--; if (state.bytecount <= 0) { if (d->emutype == DMK) { state.crc = calc_crc1(state.crc, d->u.dmk.buf[d->u.dmk.curbyte]); d->u.dmk.curbyte += dmk_incr(d); state.crc = calc_crc1(state.crc, d->u.dmk.buf[d->u.dmk.curbyte]); if (state.crc != 0) { state.status |= TRSDISK_CRCERR; } } state.bytecount = 0; state.status &= ~TRSDISK_DRQ; trs_disk_drq_interrupt(0); if (trs_event_scheduled() == trs_disk_lostdata) { trs_cancel_event(); } trs_schedule_event(trs_disk_done, 0, 64); } } break; case TRSDISK_READADR: if (state.bytecount <= 0 || !(state.status & TRSDISK_DRQ)) break; if (d->emutype == REAL) { #if 0 state.sector = d->u.real.buf[0]; /*179x data sheet says this*/ #else state.track = d->u.real.buf[0]; /*let's guess it meant this*/ state.sector = d->u.real.buf[2]; /*1771 data sheet says this*/ #endif state.data = d->u.real.buf[6 - state.bytecount]; } else if (d->emutype == DMK) { state.data = d->u.dmk.buf[d->u.dmk.curbyte]; #if 0 if (state.bytecount == 6) { state.sector = state.data; /*179x data sheet says this*/ } #else if (state.bytecount == 6) { state.track = state.data; /*let's guess it meant this!!*/ } else if (state.bytecount == 4) { state.sector = state.data; /*1771 data sheet says this*/ } #endif d->u.dmk.curbyte += dmk_incr(d); } else if (state.last_readadr >= 0) { if (d->emutype == JV1) { switch (state.bytecount) { case 6: state.data = d->phytrack; #if 0 state.sector = d->phytrack; /*179x data sheet says this*/ #else state.track = d->phytrack; /*let's guess it meant this*/ #endif break; case 5: state.data = 0; break; case 4: state.data = jv1_interleave[state.last_readadr % JV1_SECPERTRK]; state.sector = state.data; /*1771 data sheet says this*/ break; case 3: state.data = 0x01; /* 256 bytes always */ break; case 2: case 1: state.data = state.crc >> 8; break; } } else if (d->emutype == JV3) { sid = &d->u.jv3.id[d->u.jv3.sorted_id[state.last_readadr]]; switch (state.bytecount) { case 6: state.data = sid->track; #if 0 state.sector = sid->track; /*179x data sheet says this*/ #else state.track = sid->track; /*let's guess it meant this*/ #endif break; case 5: state.data = (sid->flags & JV3_SIDE) != 0; break; case 4: state.data = sid->sector; state.sector = sid->sector; /*1771 data sheet says this*/ break; case 3: state.data = id_index_to_size_code(d, d->u.jv3.sorted_id[state.last_readadr]); break; case 2: case 1: state.data = state.crc >> 8; break; } } } state.crc = calc_crc1(state.crc, state.data); state.bytecount--; if (state.bytecount <= 0) { if (d->emutype == DMK && state.crc != 0) { state.status |= TRSDISK_CRCERR; } state.bytecount = 0; state.status &= ~TRSDISK_DRQ; trs_disk_drq_interrupt(0); if (trs_event_scheduled() == trs_disk_lostdata) { trs_cancel_event(); } trs_schedule_event(trs_disk_done, 0, 64); } break; case TRSDISK_READTRK: /* assert(emutype == DMK) */ if (!(state.status & TRSDISK_DRQ)) break; if (state.bytecount > 0) { state.data = d->u.dmk.buf[d->u.dmk.curbyte]; d->u.dmk.curbyte += dmk_incr(d); state.bytecount = state.bytecount - 2 + state.density; } if (state.bytecount <= 0) { state.bytecount = 0; state.status &= ~TRSDISK_DRQ; trs_disk_drq_interrupt(0); if (trs_event_scheduled() == trs_disk_lostdata) { trs_cancel_event(); } trs_schedule_event(trs_disk_done, 0, 64); } break; default: break; } if (trs_disk_debug_flags & DISKDEBUG_FDCREG) { debug("data_read() => 0x%02x pc 0x%04x\n", state.data, REG_PC); } return state.data; } void trs_disk_data_write(unsigned char data) { DiskState *d = &disk[state.curdrive]; int c; if (trs_disk_debug_flags & DISKDEBUG_FDCREG) { debug("data_write(0x%02x) pc 0x%04x\n", data, REG_PC); } switch (state.currcommand & TRSDISK_CMDMASK) { case TRSDISK_WRITE: if (state.bytecount > 0) { if (d->emutype == REAL) { d->u.real.buf[size_code_to_size(d->u.real.size_code) - state.bytecount] = data; state.bytecount--; if (state.bytecount <= 0) { real_write(); } break; } c = putc(data, d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; if (d->emutype == DMK) { d->u.dmk.buf[d->u.dmk.curbyte++] = data; if (dmk_incr(d) == 2) { d->u.dmk.buf[d->u.dmk.curbyte++] = data; c = putc(data, d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; } state.crc = calc_crc1(state.crc, data); } state.bytecount--; if (state.bytecount <= 0) { if (d->emutype == DMK) { int idamp, i, j; c = state.crc >> 8; d->u.dmk.buf[d->u.dmk.curbyte++] = c; c = putc(c, d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; if (dmk_incr(d) == 2) { d->u.dmk.buf[d->u.dmk.curbyte++] = c; c = putc(c, d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; } c = state.crc & 0xff; d->u.dmk.buf[d->u.dmk.curbyte++] = c; c = putc(c, d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; if (dmk_incr(d) == 2) { d->u.dmk.buf[d->u.dmk.curbyte++] = c; c = putc(c, d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; } /* Check if we smashed one or more following IDAMs; can happen with weird "protected" formats */ i = j = d->u.dmk.nextidam; while (i < DMK_TKHDR_SIZE) { idamp = (d->u.dmk.buf[i] + (d->u.dmk.buf[i+1] << 8)) & DMK_IDAMP_BITS; if (idamp != 0 && idamp != DMK_IDAMP_BITS && d->u.dmk.curbyte /*!!+ erase shutoff slop?*/ > idamp) { /* Yes, smashed this one */ i += 2; if (trs_disk_debug_flags & DISKDEBUG_DMK) { debug("DMK smashed phytk %d physec %d\n", d->phytrack, i/2); } } else { /* No, keep this one */ if (j == i) break; /* none were smashed; early exit */ d->u.dmk.buf[j++] = d->u.dmk.buf[i++]; d->u.dmk.buf[j++] = d->u.dmk.buf[i++]; } } if (j != i) { /* Smashed at least one; rewrite the track header */ while (j < DMK_TKHDR_SIZE) { d->u.dmk.buf[j++] = 0; } fseek(d->file, DMK_HDR_SIZE + (d->phytrack * d->u.dmk.nsides + state.curside) * d->u.dmk.tracklen, 0); c = fwrite(d->u.dmk.buf, DMK_TKHDR_SIZE, 1, d->file); if (c != 1) state.status |= TRSDISK_WRITEFLT; } } state.bytecount = 0; state.status &= ~TRSDISK_DRQ; trs_disk_drq_interrupt(0); if (trs_event_scheduled() == trs_disk_lostdata) { trs_cancel_event(); } trs_schedule_event(trs_disk_done, 0, 64); c = fflush(d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; } } break; case TRSDISK_WRITETRK: state.bytecount = state.bytecount - 2 + state.density; if (d->emutype == DMK) { if (state.bytecount <= 0) { if (state.format != FMT_DONE) { if (trs_disk_debug_flags & DISKDEBUG_DMK) { debug("complete track format dens %d tk %d side %d\n", state.density, d->phytrack, state.curside); } state.format = FMT_DONE; state.status &= ~TRSDISK_DRQ; /* Done: write modified track */ fseek(d->file, DMK_HDR_SIZE + (d->phytrack * d->u.dmk.nsides + state.curside) * d->u.dmk.tracklen, 0); c = fwrite(d->u.dmk.buf, d->u.dmk.tracklen, 1, d->file); if (c != 1) state.status |= TRSDISK_WRITEFLT; if (d->phytrack >= d->u.dmk.ntracks) { d->u.dmk.ntracks = d->phytrack + 1; fseek(d->file, DMK_NTRACKS, 0); putc(d->u.dmk.ntracks, d->file); } c = fflush(d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; trs_disk_drq_interrupt(0); if (trs_event_scheduled() == trs_disk_lostdata) { trs_cancel_event(); } trs_schedule_event(trs_disk_done, 0, 64); } } else { switch (data) { case 0xf5: if (state.density) { data = 0xa1; state.format = FMT_PREAM; state.crc = 0x968b; /* CRC of a1 a1 */ } else { state.format = FMT_DATA; } break; case 0xf6: if (state.density) { data = 0xc2; state.format = FMT_IPREAM; } else { state.format = FMT_DATA; } break; case 0xf7: data = state.crc >> 8; d->u.dmk.buf[d->u.dmk.curbyte++] = data; if (dmk_incr(d) == 2) { d->u.dmk.buf[d->u.dmk.curbyte++] = data; } state.bytecount = state.bytecount - 2 + state.density; data = state.crc & 0xff; state.format = FMT_DATA; break; case 0xfe: if (!state.density || state.format == FMT_PREAM) { unsigned short idamp = d->u.dmk.curbyte + (state.density ? DMK_DDEN_FLAG : 0); if (d->u.dmk.nextidam >= DMK_TKHDR_SIZE) { error("DMK formatting too many address marks on track"); } else if (d->u.dmk.curbyte > d->u.dmk.tracklen) { error("DMK address mark past end of track"); } else { d->u.dmk.buf[d->u.dmk.nextidam++] = idamp & 0xff; d->u.dmk.buf[d->u.dmk.nextidam++] = idamp >> 8; } } state.format = FMT_DATA; if (!state.density) { state.crc = 0xffff; } break; #if DMK_MARK_IAM /* Mark IAMs in the track header like IDAMs. This turns out to cause bogus errors when doing Read Address commands both in current versions of David Keil's emulator and in xtrs 4.5a and earlier, so we disable it, at least for now. */ case 0xfc: if (!state.density || state.format == FMT_IPREAM) { unsigned short idamp = d->u.dmk.curbyte + (state.density ? DMK_DDEN_FLAG : 0); if (d->u.dmk.nextidam >= DMK_TKHDR_SIZE) { error("DMK formatting too many address marks on track"); } else if (d->u.dmk.curbyte > d->u.dmk.tracklen) { error("DMK address mark past end of track"); } else { d->u.dmk.buf[d->u.dmk.nextidam++] = idamp & 0xff; d->u.dmk.buf[d->u.dmk.nextidam++] = idamp >> 8; } } state.format = FMT_DATA; break; #endif case 0xf8: case 0xf9: case 0xfa: case 0xfb: if (!state.density) { state.crc = 0xffff; } state.format = FMT_DATA; break; default: state.format = FMT_DATA; break; } d->u.dmk.buf[d->u.dmk.curbyte++] = data; if (dmk_incr(d) == 2) { d->u.dmk.buf[d->u.dmk.curbyte++] = data; } state.crc = calc_crc1(state.crc, data); } break; } if (state.bytecount <= 0) { if (state.format == FMT_DONE) break; if (state.format == FMT_GAP2) { /* False ID: there was no DAM for following data */ if (d->emutype != JV3) { trs_disk_unimpl(state.currcommand, "false sector ID (no data)"); } else { /* We do not have a flag for this; try using CRC error */ d->u.jv3.id[state.format_sec].flags |= JV3_ERROR; error("warning: recording false sector ID as CRC error"); /* Write the sector id */ fseek(d->file, idoffset(d, state.format_sec), 0); c = fwrite(&d->u.jv3.id[state.format_sec], sizeof(SectorId), 1, d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; } } else if (state.format != FMT_GAP3) { /* If not in FMT_GAP3 state, format data was either too long, had extra garbage following, or was intentionally non- standard. SuperUtility does a few tricks like "software bulk erase" and duplication of protected disks, so we do not complain about this any more. */ #if BOGUS error("format data end is not in gap4"); #endif state.format_gap[4] = 0; } else { /* This was really GAP4 */ state.format_gap[4] = state.format_gapcnt; state.format_gapcnt = 0; } if (trs_disk_debug_flags & DISKDEBUG_GAPS) { debug("trk %d side %d gap0 %d gap1 %d gap2 %d gap3 %d gap4 %d\n", d->phytrack, state.curside, state.format_gap[0], state.format_gap[1], state.format_gap[2], state.format_gap[3], state.format_gap[4]); } state.format = FMT_DONE; state.status &= ~TRSDISK_DRQ; if (d->emutype == REAL) { real_writetrk(); } else { c = fflush(d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; } trs_disk_drq_interrupt(0); if (trs_event_scheduled() == trs_disk_lostdata) { trs_cancel_event(); } trs_schedule_event(trs_disk_done, 0, 64); break; } switch (state.format) { case FMT_GAP0: if (data == 0xfc) { state.format = FMT_GAP1; state.format_gap[0] = state.format_gapcnt; state.format_gapcnt = 0; } else if (data == 0xfe) { /* There wasn't a gap 0; we were really in gap 1 */ state.format_gap[0] = 0; goto got_idam; } else { state.format_gapcnt++; } break; case FMT_GAP1: if (data == 0xfe) { got_idam: /* We've received the first ID address mark */ state.format_gap[1] = state.format_gapcnt; state.format_gapcnt = 0; state.format = FMT_TRACKID; } else { state.format_gapcnt++; } break; case FMT_GAP3: if (data == 0xfe) { got_idam2: /* We've received an ID address mark */ state.format_gap[3] = state.format_gapcnt; state.format_gapcnt = 0; state.format = FMT_TRACKID; } else { state.format_gapcnt++; } break; case FMT_TRACKID: if (d->emutype == REAL) { if (d->u.real.fmt_nbytes >= sizeof(d->u.real.buf)) { /* Data structure full */ state.status |= TRSDISK_WRITEFLT; state.bytecount = 0; state.format_bytecount = 0; state.format = FMT_DONE; } else { d->u.real.buf[d->u.real.fmt_nbytes++] = data; state.format = FMT_HEADID; } } else { if (data != d->phytrack) { trs_disk_unimpl(state.currcommand, "false track number"); } state.format = FMT_HEADID; } break; case FMT_HEADID: if (d->emutype == REAL) { d->u.real.buf[d->u.real.fmt_nbytes++] = data; } else if (d->emutype == JV1) { if (data != 0) { trs_disk_unimpl(state.currcommand, "JV1 double sided"); } if (state.density) { trs_disk_unimpl(state.currcommand, "JV1 double density"); } } else { if (data != state.curside) { trs_disk_unimpl(state.currcommand, "false head number"); } } state.format = FMT_SECID; break; case FMT_SECID: if (d->emutype == REAL) { d->u.real.buf[d->u.real.fmt_nbytes++] = data; } else if (d->emutype == JV1) { if (data >= JV1_SECPERTRK) { trs_disk_unimpl(state.currcommand, "JV1 sector number >= 10"); } } else { state.format_sec = data; } state.format = FMT_SIZEID; break; case FMT_SIZEID: if (data > 0x03) { trs_disk_unimpl(state.currcommand, "invalid sector size"); } if (d->emutype == JV3) { int id_index; id_index = jv3_alloc_sector(d, data); if (id_index == -1) { /* Data structure full */ state.status |= TRSDISK_WRITEFLT; state.bytecount = 0; state.format_bytecount = 0; state.format = FMT_DONE; break; } d->u.jv3.sorted_valid = 0; d->u.jv3.id[id_index].track = d->phytrack; d->u.jv3.id[id_index].sector = state.format_sec; d->u.jv3.id[id_index].flags = (state.curside ? JV3_SIDE : 0) | (state.density ? JV3_DENSITY : 0) | ((data & 3) ^ 1); state.format_sec = id_index; } else if (d->emutype == REAL) { d->u.real.buf[d->u.real.fmt_nbytes++] = data; if (d->u.real.size_code != -1 && d->u.real.size_code != data) { trs_disk_unimpl(state.currcommand, "varying sector size on same track on real floppy"); } d->u.real.size_code = data; } else { if (data != 0x01) { trs_disk_unimpl(state.currcommand, "sector size != 256"); } } state.format = FMT_GAP2; break; case FMT_GAP2: if ((data & 0xfc) == 0xf8) { /* Found a DAM */ if (d->emutype == REAL) { switch (data) { case 0xfb: /* Standard DAM */ break; case 0xfa: if (state.density) { /* This DAM is illegal, but SuperUtility uses it, so ignore the error. This seems to be a bug in SU for Model I, where it meant to use F8 instead. I think the WD controller would read back the FA as FB, so we treat it as FB here. */ } else { if (trs_disk_truedam) { error("format DAM FA on real floppy"); } } break; case 0xf9: if (trs_disk_truedam) { error("format DAM F9 on real floppy"); } break; case 0xf8: /* This is probably needed by Model III TRSDOS, but it is a pain to implement. We would have to remember to do a Write Deleted after the format is complete to change the DAM. */ error("format DAM F8 on real floppy"); break; } } else if (d->emutype == JV1) { switch (data) { case 0xf9: trs_disk_unimpl(state.currcommand, "JV1 DAM cannot be F9"); break; case 0xf8: case 0xfa: if (d->phytrack != 17) trs_disk_unimpl(state.currcommand, "JV1 directory track must be 17"); break; default: /* impossible */ case 0xfb: break; } } else /* JV3 */ { if (state.density) { /* Double density */ switch (data) { case 0xf8: /* Standard deleted DAM */ case 0xf9: /* Illegal, probably never used; ignore error. */ d->u.jv3.id[state.format_sec].flags |= JV3_DAMDDF8; break; case 0xfb: /* Standard DAM */ case 0xfa: /* Illegal, but SuperUtility uses it! */ default: /* Impossible */ d->u.jv3.id[state.format_sec].flags |= JV3_DAMDDFB; break; } } else { /* Single density */ switch (data) { case 0xf8: if (trs_disk_truedam) { d->u.jv3.id[state.format_sec].flags |= JV3_DAMSDF8; } else { d->u.jv3.id[state.format_sec].flags |= JV3_DAMSDFA; } break; case 0xf9: d->u.jv3.id[state.format_sec].flags |= JV3_DAMSDF9; break; case 0xfa: d->u.jv3.id[state.format_sec].flags |= JV3_DAMSDFA; break; default: /* impossible */ case 0xfb: d->u.jv3.id[state.format_sec].flags |= JV3_DAMDDFB; break; } } } if (d->emutype == JV3) { /* Prepare to write the data */ fseek(d->file, offset(d, state.format_sec), 0); state.format_bytecount = id_index_to_size(d, state.format_sec); } else if (d->emutype == JV1) { state.format_bytecount = JV1_SECSIZE; } else if (d->emutype == REAL) { state.format_bytecount = size_code_to_size(d->u.real.size_code); } state.format_gap[2] = state.format_gapcnt; state.format_gapcnt = 0; state.format = FMT_DATA; } else if (data == 0xfe) { /* False ID: there was no DAM for following data */ if (d->emutype != JV3) { trs_disk_unimpl(state.currcommand, "false sector ID (no data)"); } else { /* We do not have a flag for this; try using CRC error */ error("warning: recording false sector ID as CRC error"); d->u.jv3.id[state.format_sec].flags |= JV3_ERROR; /* Write the sector id */ fseek(d->file, idoffset(d, state.format_sec), 0); c = fwrite(&d->u.jv3.id[state.format_sec], sizeof(SectorId), 1, d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; } goto got_idam2; } else { state.format_gapcnt++; } break; case FMT_DATA: if (data == 0xfe) { /* Short sector with intentional CRC error */ if (d->emutype == JV3) { d->u.jv3.id[state.format_sec].flags |= JV3_NONIBM | JV3_ERROR; if (trs_disk_debug_flags & DISKDEBUG_VTOS3) { debug("non-IBM sector: drv 0x%02x, sid %d," " trk 0x%02x, sec 0x%02x\n", state.curdrive, state.curside, d->u.jv3.id[state.format_sec].track, d->u.jv3.id[state.format_sec].sector); } /* Write the sector id */ fseek(d->file, idoffset(d, state.format_sec), 0); c = fwrite(&d->u.jv3.id[state.format_sec], sizeof(SectorId), 1, d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; goto got_idam; } else { trs_disk_unimpl(state.currcommand, "JV1 non-IBM sector"); } } if (d->emutype == JV3) { c = putc(data, d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; } else if (d->emutype == REAL) { d->u.real.fmt_fill = data; } if (--state.format_bytecount <= 0) { state.format = FMT_DCRC; } break; case FMT_DCRC: if (data == 0xf7) { state.bytecount--; /* two bytes are written */ } else { /* Intentional CRC error */ if (d->emutype != JV3) { trs_disk_unimpl(state.currcommand, "intentional CRC error"); } else { d->u.jv3.id[state.format_sec].flags |= JV3_ERROR; } } if (d->emutype == JV3) { /* Write the sector id */ fseek(d->file, idoffset(d, state.format_sec), 0); c = fwrite(&d->u.jv3.id[state.format_sec], sizeof(SectorId), 1, d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; } state.format = FMT_GAP3; break; case FMT_DONE: break; case FMT_GAP4: case FMT_IAM: case FMT_IDAM: case FMT_IDCRC: case FMT_DAM: default: error("error in format state machine"); break; } default: break; } state.data = data; return; } unsigned char trs_disk_status_read(void) { static int last_status = -1; if (trs_disk_nocontroller) return 0xff; type1_status(); if (!(state.status & TRSDISK_NOTRDY)) { if (state.motor_timeout - z80_state.t_count > TSTATE_T_MID) { /* Subtraction wrapped; motor stopped */ state.status |= TRSDISK_NOTRDY; } } if ((trs_disk_debug_flags & DISKDEBUG_FDCREG) && state.status != last_status) { debug("status_read() => 0x%02x pc 0x%04x\n", state.status, REG_PC); last_status = state.status; } #if BOGUS /* Clear intrq unless user did a Force Interrupt with immediate interrupt. */ /* The 17xx data sheets say this is how it is supposed to work, but it * makes Model I SuperUtility hang due to the interrupt routine failing * to clear the interrupt. I suspect the data sheets are wrong. */ if (!(((state.currcommand & TRSDISK_CMDMASK) == TRSDISK_FORCEINT) && ((state.currcommand & 0x08) != 0))) #else /* Clear intrq always */ #endif { /* Don't call trs_schedule_event, which could cancel a pending * interrupt that should occur later and prevent it from ever * happening; just clear the interrupt right now. */ trs_disk_intrq_interrupt(0); } return state.status; } void trs_disk_command_write(unsigned char cmd) { int id_index, non_ibm, goal_side, new_status; DiskState *d = &disk[state.curdrive]; trs_event_func event; if (trs_disk_debug_flags & DISKDEBUG_FDCREG) { debug("command_write(0x%02x) pc 0x%04x\n", cmd, REG_PC); } /* Handle DMK partial track reformat */ if (d->emutype == DMK && (state.currcommand & ~TRSDISK_EBIT) == TRSDISK_WRITETRK && state.format != FMT_DONE) { /* Interrupted format: must write out partial track */ unsigned char oldtkhdr[DMK_TKHDR_SIZE]; int c, i, j, idamp; if (trs_disk_debug_flags & DISKDEBUG_DMK) { debug("partial track format dens %d tk %d side %d\n", state.density, d->phytrack, state.curside); } /* Fetch old IDAM pointers if any */ fseek(d->file, DMK_HDR_SIZE + (d->phytrack * d->u.dmk.nsides + state.curside) * d->u.dmk.tracklen, 0); c = fread(oldtkhdr, DMK_TKHDR_SIZE, 1, d->file); if (c == 1) { /* Copy any pointers to IDAMs that are not being overwritten */ i = 0; j = d->u.dmk.nextidam; while (i < DMK_TKHDR_SIZE) { idamp = (oldtkhdr[i] + (oldtkhdr[i+1] << 8)) & DMK_IDAMP_BITS; if (idamp == 0 || idamp == DMK_IDAMP_BITS) break; if (idamp < d->u.dmk.curbyte) { /* IDAM overwritten; don't copy */ i += 2; if (trs_disk_debug_flags & DISKDEBUG_DMK) { debug(" discarding physec %d\n", i); } } else { /* IDAM not overwritten; need to copy in */ if (j >= DMK_TKHDR_SIZE) { /* No room */ error("DMK reformatting adds too many sectors to track"); break; } d->u.dmk.buf[j++] = oldtkhdr[i++]; d->u.dmk.buf[j++] = oldtkhdr[i++]; if (trs_disk_debug_flags & DISKDEBUG_DMK) { debug(" preserving physec %d as %d\n", i, j); } } } } else { if (trs_disk_debug_flags & DISKDEBUG_FDCREG) { debug(" no existing sectors\n"); } } /* Write modified portion of track only */ fseek(d->file, DMK_HDR_SIZE + (d->phytrack * d->u.dmk.nsides + state.curside) * d->u.dmk.tracklen, 0); fwrite(d->u.dmk.buf, d->u.dmk.curbyte, 1, d->file); if (d->phytrack >= d->u.dmk.ntracks) { d->u.dmk.ntracks = d->phytrack + 1; fseek(d->file, DMK_NTRACKS, 0); putc(d->u.dmk.ntracks, d->file); } fflush(d->file); /* Invalidate buffer since not all data is here */ d->u.dmk.curtrack = d->u.dmk.curside = -1; state.format = FMT_DONE; } /* Cancel any ongoing command */ event = trs_event_scheduled(); if (event == trs_disk_lostdata || event == trs_disk_intrq_interrupt) { trs_cancel_event(); } trs_disk_intrq_interrupt(0); state.bytecount = 0; state.currcommand = cmd; switch (cmd & TRSDISK_CMDMASK) { case TRSDISK_RESTORE: if (trs_disk_debug_flags & DISKDEBUG_FDCCMD) { debug("restore 0x%02x drv %d\n", cmd, state.curdrive); } state.last_readadr = -1; d->phytrack = 0; state.track = 0; state.status = TRSDISK_TRKZERO|TRSDISK_BUSY; if (d->emutype == REAL) real_restore(state.curdrive); /* Should this set lastdirection? */ if (cmd & TRSDISK_VBIT) verify(); trs_schedule_event(trs_disk_done, 0, 2000); break; case TRSDISK_SEEK: if (trs_disk_debug_flags & DISKDEBUG_FDCCMD) { debug("seek 0x%02x drv %d ptk %d otk %d ntk %d\n", cmd, state.curdrive, d->phytrack, state.track, state.data); } state.last_readadr = -1; d->phytrack += (state.data - state.track); state.track = state.data; if (d->phytrack <= 0) { d->phytrack = 0; /* state.track too? */ state.status = TRSDISK_TRKZERO|TRSDISK_BUSY; } else { state.status = TRSDISK_BUSY; } if (d->emutype == REAL) real_seek(); /* Should this set lastdirection? */ if (cmd & TRSDISK_VBIT) verify(); trs_schedule_event(trs_disk_done, 0, 2000); break; case TRSDISK_STEP: case TRSDISK_STEPU: step: if (trs_disk_debug_flags & DISKDEBUG_FDCCMD) { debug("step%s %s 0x%02x drv %d ptk %d otk %d\n", (cmd & TRSDISK_UBIT) ? "u" : "", (state.lastdirection < 0) ? "out" : "in", cmd, state.curdrive, d->phytrack, state.track); } state.last_readadr = -1; d->phytrack += state.lastdirection; if (cmd & TRSDISK_UBIT) { state.track += state.lastdirection; } if (d->phytrack <= 0) { d->phytrack = 0; /* state.track too? */ state.status = TRSDISK_TRKZERO|TRSDISK_BUSY; } else { state.status = TRSDISK_BUSY; } if (d->emutype == REAL) real_seek(); if (cmd & TRSDISK_VBIT) verify(); trs_schedule_event(trs_disk_done, 0, 2000); break; case TRSDISK_STEPIN: case TRSDISK_STEPINU: state.lastdirection = 1; goto step; case TRSDISK_STEPOUT: case TRSDISK_STEPOUTU: state.lastdirection = -1; goto step; case TRSDISK_READ: if (trs_disk_debug_flags & DISKDEBUG_FDCCMD) { debug("read 0x%02x drv %d ptk %d tk %d sec %d %sden\n", cmd, state.curdrive, d->phytrack, state.track, state.sector, state.density ? "d" : "s"); } state.last_readadr = -1; state.status = 0; non_ibm = 0; goal_side = -1; new_status = 0; if (state.controller == TRSDISK_P1771) { if (!(cmd & TRSDISK_BBIT)) { if (trs_disk_debug_flags & DISKDEBUG_VTOS3) { debug("non-IBM read: drv 0x%02x, sid %d, trk 0x%02x, sec 0x%02x\n", state.curdrive, state.curside, state.track, state.sector); } if (d->emutype == REAL) { trs_disk_unimpl(cmd, "non-IBM read on real floppy"); } non_ibm = 1; } else { if (trs_disk_debug_flags & DISKDEBUG_VTOS3) { if (state.sector >= 0x7c) { debug("IBM read: drv 0x%02x, sid %d, trk 0x%02x, sec 0x%02x\n", state.curdrive, state.curside, state.track, state.sector); } } } } else { if (cmd & TRSDISK_CBIT) { goal_side = (cmd & TRSDISK_BBIT) != 0; } } if (d->emutype == REAL) { real_read(); break; } id_index = search(state.sector, goal_side); if (id_index == -1) { state.status |= TRSDISK_BUSY; trs_schedule_event(trs_disk_done, 0, 512); } else { if (d->emutype == JV1) { if (d->phytrack == 17) { if (state.controller == TRSDISK_P1771) { new_status = TRSDISK_1771_FA; } else { new_status = TRSDISK_1791_F8; } } state.bytecount = JV1_SECSIZE; fseek(d->file, offset(d, id_index), 0); } else if (d->emutype == JV3) { if (state.controller == TRSDISK_P1771) { switch (d->u.jv3.id[id_index].flags & JV3_DAM) { case JV3_DAMSDFB: new_status = TRSDISK_1771_FB; break; case JV3_DAMSDFA: new_status = TRSDISK_1771_FA; break; case JV3_DAMSDF9: new_status = TRSDISK_1771_F9; break; case JV3_DAMSDF8: new_status = TRSDISK_1771_F8; break; } } else if (state.density == 0) { /* single density 179x */ switch (d->u.jv3.id[id_index].flags & JV3_DAM) { case JV3_DAMSDFB: new_status = TRSDISK_1791_FB; break; case JV3_DAMSDFA: if (trs_disk_truedam) { new_status = TRSDISK_1791_FB; } else { new_status = TRSDISK_1791_F8; } break; case JV3_DAMSDF9: new_status = TRSDISK_1791_F8; break; case JV3_DAMSDF8: new_status = TRSDISK_1791_F8; break; } } else { /* double density 179x */ switch (d->u.jv3.id[id_index].flags & JV3_DAM) { default: /*impossible*/ case JV3_DAMDDFB: new_status = TRSDISK_1791_FB; break; case JV3_DAMDDF8: new_status = TRSDISK_1791_F8; break; } } if (d->u.jv3.id[id_index].flags & JV3_ERROR) { new_status |= TRSDISK_CRCERR; } if (non_ibm) { state.bytecount = 16; } else { state.bytecount = id_index_to_size(d, id_index); } fseek(d->file, offset(d, id_index), 0); } else /* d->emutype == DMK */ { /* max distance past ID CRC to search for DAM */ int damlimit = state.density ? 43 : 30; /* ref 1791 datasheet */ unsigned char dam = 0; /* DMK search dumps the size code into state.bytecount; adjust to real bytecount here */ if (non_ibm) { state.bytecount = 16 * (((state.bytecount - 1)&0xff)+1); } else { state.bytecount = 128 << (state.bytecount & 3); } /* search for valid DAM */ while (--damlimit >= 0) { dam = d->u.dmk.buf[id_index]; id_index += dmk_incr(d); if (0xf8 <= dam && dam <= 0xfb) { /* got one! */ break; } } if (damlimit < 0) { /* found ID with good CRC but no following DAM; fail */ state.status |= TRSDISK_BUSY; trs_schedule_event(trs_disk_done, TRSDISK_NOTFOUND, 512); break; } /* Set flags for DAM */ if (state.controller == TRSDISK_P1771) { /* 1771 */ switch (dam) { case 0xfb: new_status = TRSDISK_1771_FB; break; case 0xfa: new_status = TRSDISK_1771_FA; break; case 0xf9: new_status = TRSDISK_1771_F9; break; case 0xf8: new_status = TRSDISK_1771_F8; break; } } else /* state.controller == TRSDISK_P1791 */ { switch (dam) { case 0xfb: new_status = TRSDISK_1791_FB; break; case 0xfa: /* Note: Illegal in DDEN but Write Track can still generate it, and of course 1771 can generate in SDEN */ if (trs_disk_truedam) { new_status = TRSDISK_1791_FB; } else { new_status = TRSDISK_1791_F8; } break; case 0xf9: /* Note: Illegal in DDEN but Write Track can still generate it, and of course 1771 can generate in SDEN */ new_status = TRSDISK_1791_F8; break; case 0xf8: new_status = TRSDISK_1791_F8; break; } } state.crc = calc_crc1((state.density ? 0xcdb4 /* CRC of a1 a1 a1 */ : 0xffff), dam); d->u.dmk.curbyte = id_index; } /* end if (d->emutype == ...) */ state.status |= TRSDISK_BUSY; trs_schedule_event(trs_disk_firstdrq, new_status, 64); } break; case TRSDISK_READM: state.last_readadr = -1; trs_disk_unimpl(cmd, "read multiple"); break; case TRSDISK_WRITE: if (trs_disk_debug_flags & DISKDEBUG_FDCCMD) { debug("write 0x%02x drv %d ptk %d tk %d sec %d %sden\n", cmd, state.curdrive, d->phytrack, state.track, state.sector, state.density ? "d" : "s"); } state.last_readadr = -1; state.status = 0; non_ibm = 0; goal_side = -1; if (state.controller == TRSDISK_P1771) { if (!(cmd & TRSDISK_BBIT)) { if (trs_disk_debug_flags & DISKDEBUG_VTOS3) { debug("non-IBM write drv 0x%02x, sid %d, trk 0x%02x, sec 0x%02x\n", state.curdrive, state.curside, state.track, state.sector); } if (d->emutype == REAL) { trs_disk_unimpl(cmd, "non-IBM write on real floppy"); } non_ibm = 1; } else { if (trs_disk_debug_flags & DISKDEBUG_VTOS3) { if (state.sector >= 0x7c) { debug("IBM write: drv 0x%02x, sid %d, trk 0x%02x, sec 0x%02x\n", state.curdrive, state.curside, state.track, state.sector); } } } } else { if (cmd & TRSDISK_CBIT) { goal_side = (cmd & TRSDISK_BBIT) != 0; } } if (d->emutype == REAL) { state.status = TRSDISK_BUSY|TRSDISK_DRQ; trs_disk_drq_interrupt(1); trs_schedule_event(trs_disk_lostdata, state.currcommand, 500000 * z80_state.clockMHz); state.bytecount = size_code_to_size(d->u.real.size_code); break; } if (d->writeprot) { state.status = TRSDISK_WRITEPRT; break; } id_index = search(state.sector, goal_side); if (id_index == -1) { state.status |= TRSDISK_BUSY; trs_schedule_event(trs_disk_done, 0, 512); } else { int jv3dam = 0, dam = 0; if (state.controller == TRSDISK_P1771) { switch (cmd & (TRSDISK_CBIT|TRSDISK_DBIT)) { case 0: dam = 0xfb; jv3dam = JV3_DAMSDFB; break; case 1: dam = 0xfa; jv3dam = JV3_DAMSDFA; break; case 2: dam = 0xf9; jv3dam = JV3_DAMSDF9; break; case 3: if (trs_disk_truedam) { dam = 0xf8; jv3dam = JV3_DAMSDF8; } else { dam = 0xfa; jv3dam = JV3_DAMSDFA; } break; } } else if (state.density == 0) { /* 179x single */ switch (cmd & TRSDISK_DBIT) { case 0: dam = 0xfb; jv3dam = JV3_DAMSDFB; break; case 1: if (trs_disk_truedam) { dam = 0xf8; jv3dam = JV3_DAMSDF8; } else { dam = 0xfa; jv3dam = JV3_DAMSDFA; } break; } } else { /* 179x double */ switch (cmd & TRSDISK_DBIT) { case 0: dam = 0xfb; jv3dam = JV3_DAMDDFB; break; case 1: dam = 0xf8; jv3dam = JV3_DAMDDF8; break; } } if (d->emutype == JV1) { if (dam == 0xf9) { trs_disk_unimpl(state.currcommand, "JV1 DAM cannot be F9"); } else if ((dam == 0xfb) == (d->phytrack == 17)) { trs_disk_unimpl(state.currcommand, "JV1 directory must be track 17"); break; } state.bytecount = JV1_SECSIZE; fseek(d->file, offset(d, id_index), 0); } else if (d->emutype == JV3) { SectorId *sid = &d->u.jv3.id[id_index]; unsigned char newflags = sid->flags; newflags &= ~(JV3_ERROR|JV3_DAM); /* clear CRC error and DAM */ newflags |= jv3dam; if (newflags != sid->flags) { int c; fseek(d->file, idoffset(d, id_index) + ((char *) &sid->flags) - ((char *) sid), 0); c = putc(newflags, d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; c = fflush(d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; sid->flags = newflags; } /* Kludge for VTOS 3.0 */ if (sid->flags & JV3_NONIBM) { int i, j, c; /* Smash following sectors. This is especially a kludge because it uses the sector numbers, not the known physical sector order. */ for (i = state.sector+1; i <= 0x7f; i++) { j = search(i, -1); if (j != -1) { if (trs_disk_debug_flags & DISKDEBUG_VTOS3) { debug("smashing tk %d sector 0x%02x id_index %d\n", state.track, i, j); } jv3_free_sector(d, j); c = fflush(d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; } /* Smash only one for non-IBM write */ if (non_ibm) break; } } /* end kludge */ if (non_ibm) { state.bytecount = 16; } else { state.bytecount = id_index_to_size(d, id_index); } fseek(d->file, offset(d, id_index), 0); } else /* d->emutype == DMK */ { int c, nzeros, i; /* DMK search dumps the size code into state.bytecount; adjust to real bytecount here */ if (non_ibm) { state.bytecount = 16 * (((state.bytecount - 1)&0xff)+1); } else { state.bytecount = 128 << (state.bytecount & 3); } /* Skip initial part of gap, per 1771 and 179x data sheets */ id_index += 11 * (state.density ? 2 : 1) * dmk_incr(d); fseek(d->file, (DMK_HDR_SIZE + (d->u.dmk.curtrack*d->u.dmk.nsides + d->u.dmk.curside) * d->u.dmk.tracklen + id_index), 0); /* Write remaining gap (per data sheets) and DAM */ nzeros = 6 * (state.density ? 2 : 1) * dmk_incr(d); for (i=0; ifile); if (c == EOF) state.status |= TRSDISK_WRITEFLT; d->u.dmk.buf[id_index++] = 0; } if (state.density) { for (i=0; i<3; i++) { c = putc(0xa1, d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; d->u.dmk.buf[id_index++] = 0xa1; } } c = putc(dam, d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; d->u.dmk.buf[id_index++] = dam; if (dmk_incr(d) == 2) { c = putc(dam, d->file); if (c == EOF) state.status |= TRSDISK_WRITEFLT; d->u.dmk.buf[id_index++] = dam; } /* Initialize CRC */ state.crc = calc_crc1((state.density ? 0xcdb4 /* CRC of a1 a1 a1 */ : 0xffff), dam); d->u.dmk.curbyte = id_index; } /* end if (d->emutype == ...) */ state.status |= TRSDISK_BUSY|TRSDISK_DRQ; trs_disk_drq_interrupt(1); trs_schedule_event(trs_disk_lostdata, state.currcommand, 500000 * z80_state.clockMHz); } break; case TRSDISK_WRITEM: state.last_readadr = -1; if (d->writeprot) { state.status = TRSDISK_WRITEPRT; break; } trs_disk_unimpl(cmd, "write multiple"); break; case TRSDISK_READADR: if (trs_disk_debug_flags & DISKDEBUG_FDCCMD) { debug("readadr 0x%02x drv %d ptk %d tk %d last %d %sden\n", cmd, state.curdrive, d->phytrack, state.track, state.last_readadr, state.density ? "d" : "s"); } state.data = 0; /* workaround for apparent SU1 bug */ if (state.density) { state.crc = 0xb230; /* CRC of a1 a1 a1 fe */ } else { state.crc = 0xef21; /* CRC of fe */ } if (d->emutype == REAL) { real_readadr(); break; } else if (d->emutype == JV1 || d->emutype == JV3) { int totbyt, i, ts, denok; float a, b, bytlen; id_index = search_adr(); if (id_index == -1) { state.status = TRSDISK_BUSY; state.bytecount = 0; trs_schedule_event(trs_disk_done, TRSDISK_NOTFOUND, 1000000*z80_state.clockMHz); break; } /* Compute how long it should have taken for this sector to come by and delay by an appropriate number of t-states. This makes the "A" command in HyperZap work (on emulated floppies only). It is not terribly useful, since other important HyperZap functions (like mixed-density formatting) do not work, while SuperUtility and Trakcess both work fine without the delay feature. Note: it would probably be better to assume the sectors are positioned using nominal gap sizes (say, the ones that HyperZap uses when generating tracks using the D/G subcommand) instead of the even spacing nonsense below. */ if (d->emutype == JV1) { /* Which sector header is next? Use a rough assumption that the sectors are all the same angular length (bytlen). */ a = angle(); bytlen = (1.0 - GAP1ANGLE - GAP4ANGLE)/((float)JV1_SECPERTRK); i = (int)( (a - GAP1ANGLE) / bytlen + 1.0 ); if (i >= JV1_SECPERTRK) { /* Wrap around to start of track */ i = 0; } b = ((float)i) * bytlen + GAP1ANGLE; if (b < a) b += 1.0; i += id_index; } else { /* Count data bytes on track. Also check if there are any sectors of the correct density. */ i = id_index; totbyt = 0; denok = 0; for (;;) { SectorId *sid = &d->u.jv3.id[d->u.jv3.sorted_id[i]]; int dden = (sid->flags & JV3_DENSITY) != 0; if (sid->track != d->phytrack || (sid->flags & JV3_SIDE ? 1 : 0) != state.curside) break; totbyt += (dden ? 1 : 2) * id_index_to_size(d, d->u.jv3.sorted_id[i]); if (dden == state.density) denok = 1; i++; } if (!denok) { /* No sectors of the correct density */ state.status = TRSDISK_BUSY; state.bytecount = 0; trs_schedule_event(trs_disk_done, TRSDISK_NOTFOUND, 1000000*z80_state.clockMHz); break; } /* Which sector header is next? Use a rough assumption that sectors are evenly spaced, taking up room proportional to their data length (and twice as much for single density). Here bytlen = angular size per byte. */ a = angle(); b = GAP1ANGLE; bytlen = (1.0 - GAP1ANGLE - GAP4ANGLE)/((float)totbyt); i = id_index; for (;;) { SectorId *sid = &d->u.jv3.id[d->u.jv3.sorted_id[i]]; if (sid->track != d->phytrack || (sid->flags & JV3_SIDE ? 1 : 0) != state.curside) { /* Wrap around to start of track */ i = id_index; b = 1 + GAP1ANGLE; break; } if (b > a && (((sid->flags & JV3_DENSITY) != 0) == state.density)) { break; } b += ((sid->flags & JV3_DENSITY) ? 1 : 2) * id_index_to_size(d, d->u.jv3.sorted_id[i]) * bytlen; i++; } } /* Convert angular delay to t-states */ ts = (d->inches == 5 ? 200000 : 166667) * (b - a) * z80_state.clockMHz; state.status = TRSDISK_BUSY; state.last_readadr = i; state.bytecount = 6; trs_schedule_event(trs_disk_firstdrq, 0, ts); if (trs_disk_debug_flags & DISKDEBUG_READADR) { debug("readadr phytrack %d angle %f i %d ts %d\n", d->phytrack, a, i, ts); } } else /* d->emutype == DMK */ { /* Compute how far it will be to the next ID in the correct density */ float a = angle(); int ia = a * (d->inches ? TRKSIZE_DD : TRKSIZE_8DD); int ib = 0; int i, j, idamp, dden, prev_idamp, prev_dden, ts; dmk_get_track(d); for (j = 0; j < 2; j++) { idamp = d->u.dmk.buf[0] + (d->u.dmk.buf[1] << 8); dden = (idamp & DMK_DDEN_FLAG) != 0; idamp = DMK_TKHDR_SIZE; for (i = 0; i < DMK_TKHDR_SIZE; i+=2) { prev_idamp = idamp; prev_dden = dden; idamp = d->u.dmk.buf[i] + (d->u.dmk.buf[i+1] << 8); if (idamp == 0) break; dden = (idamp & DMK_DDEN_FLAG) != 0; idamp &= DMK_IDAMP_BITS; if (idamp >= DMK_TRACKLEN_MAX) break; ib += (idamp - prev_idamp) * ((!prev_dden && (d->u.dmk.sden || d->u.dmk.ignden)) ? 2 : 1); if (ib > ia && dden == state.density && d->u.dmk.buf[idamp] == 0xfe) goto found; } /* Next ID (if any) is past the index hole */ ib = (d->inches ? TRKSIZE_DD : TRKSIZE_8DD); } /* no suitable ID found */ state.status = TRSDISK_BUSY; state.bytecount = 0; trs_schedule_event(trs_disk_done, TRSDISK_NOTFOUND, 1000000*z80_state.clockMHz); break; found: /* Convert dden byte count to t-states */ ts = ((float) ((ib - ia) * (d->inches == 5 ? 32 : 16))) * z80_state.clockMHz; state.status = TRSDISK_BUSY; state.last_readadr = i; state.bytecount = 6; state.crc = calc_crc1((state.density ? 0xcdb4 /* CRC of a1 a1 a1 */ : 0xffff), d->u.dmk.buf[idamp]); d->u.dmk.curbyte = idamp + dmk_incr(d); trs_schedule_event(trs_disk_firstdrq, 0, ts); if (trs_disk_debug_flags & DISKDEBUG_READADR) { debug("readadr phytrack %d angle %f i %d ts %d\n", d->phytrack, a, i, ts); } } break; case TRSDISK_READTRK: if (trs_disk_debug_flags & DISKDEBUG_FDCCMD) { debug("readtrk 0x%02x drv %d ptk %d tk %d %sden\n", cmd, state.curdrive, d->phytrack, state.track, state.density ? "d" : "s"); } state.last_readadr = -1; if (d->file == NULL) { /* Data sheet says we wait forever for an index pulse, ugh */ state.status = TRSDISK_BUSY; state.bytecount = 0; break; } if (d->emutype == REAL) { real_readtrk(); break; } if (d->emutype != DMK) { trs_disk_unimpl(cmd, "read track"); break; } dmk_get_track(d); d->u.dmk.curbyte = DMK_TKHDR_SIZE; if (disk[state.curdrive].inches == 5) { state.bytecount = TRKSIZE_DD; /* decrement by 2's if SD */ } else { state.bytecount = TRKSIZE_8DD; /* decrement by 2's if SD */ } state.status = TRSDISK_BUSY|TRSDISK_DRQ; trs_disk_drq_interrupt(1); trs_schedule_event(trs_disk_lostdata, state.currcommand, 500000 * z80_state.clockMHz); break; case TRSDISK_WRITETRK: state.last_readadr = -1; /* Really a write track? */ if (trs_model == 1 && (cmd == TRSDISK_P1771 || cmd == TRSDISK_P1791)) { /* No; emulate Percom Doubler */ state.currcommand = TRSDISK_FORCEINT; if (trs_disk_doubler & TRSDISK_PERCOM) { trs_disk_set_controller(cmd); /* The Doubler's 1791 is hardwired to double density */ state.density = (state.controller == TRSDISK_P1791); } } else { if (trs_disk_debug_flags & DISKDEBUG_FDCCMD) { debug("writetrk 0x%02x drv %d ptk %d tk %d %sden\n", cmd, state.curdrive, d->phytrack, state.track, state.density ? "d" : "s"); } /* Yes; a real write track */ if (d->emutype != REAL && d->writeprot) { state.status = TRSDISK_WRITEPRT; break; } state.status = 0; if (d->file == NULL) { /* Data sheet says we wait forever for an index pulse, ugh */ state.status = TRSDISK_BUSY; state.bytecount = 0; break; } if (d->emutype == JV3) { /* Erase track if already formatted */ int i; for (i=0; i<=d->u.jv3.last_used_id; i++) { if (d->u.jv3.id[i].track == d->phytrack && ((d->u.jv3.id[i].flags & JV3_SIDE) != 0) == state.curside) { jv3_free_sector(d, i); } } } else if (d->emutype == REAL) { d->u.real.size_code = -1; /* watch for first, then check others match*/ d->u.real.fmt_nbytes = 0; /* size of PC formatting command buffer */ } else if (d->emutype == DMK) { if (state.density && d->u.dmk.sden) { error("DMK disk created as single density only"); state.status |= TRSDISK_WRITEFLT; } if (state.curside && d->u.dmk.nsides == 1) { error("DMK disk created as single sided only"); state.status |= TRSDISK_WRITEFLT; } d->u.dmk.curtrack = d->phytrack; d->u.dmk.curside = state.curside; memset(d->u.dmk.buf, 0, sizeof(d->u.dmk.buf)); d->u.dmk.curbyte = DMK_TKHDR_SIZE; d->u.dmk.nextidam = 0; } state.status |= TRSDISK_BUSY|TRSDISK_DRQ; trs_disk_drq_interrupt(1); trs_schedule_event(trs_disk_lostdata, state.currcommand, 500000 * z80_state.clockMHz); state.format = FMT_GAP0; state.format_gapcnt = 0; if (disk[state.curdrive].inches == 5) { state.bytecount = TRKSIZE_DD; /* decrement by 2's if SD */ } else { state.bytecount = TRKSIZE_8DD; /* decrement by 2's if SD */ } } break; case TRSDISK_FORCEINT: if (trs_disk_debug_flags & DISKDEBUG_FDCCMD) { debug("forceint 0x%02x\n", cmd); } /* Stop whatever is going on and forget it */ trs_cancel_event(); state.status = 0; type1_status(); if ((cmd & 0x07) != 0) { /* Conditional interrupt features not implemented. */ trs_disk_unimpl(cmd, "force interrupt with condition"); } else if ((cmd & 0x08) != 0) { /* Immediate interrupt */ trs_disk_intrq_interrupt(1); } else { trs_disk_intrq_interrupt(0); } break; } } /* Interface to real floppy drive */ int real_rate(DiskState *d) { if (d->inches == 5) { if (d->u.real.rps == 5) { return 2; } else if (d->u.real.rps == 6) { return 1; } } else if (d->inches == 8) { return 0; } trs_disk_unimpl(state.currcommand, "real_rate internal error"); return 1; } void real_error(DiskState *d, unsigned int flags, char *msg) { time_t now = time(NULL); if (now > d->u.real.empty_timeout) { d->u.real.empty_timeout = time(NULL) + EMPTY_TIMEOUT; d->u.real.empty = 1; } if (trs_disk_debug_flags & DISKDEBUG_REALERR) { debug("error on real_%s\n", msg); } } void real_ok(DiskState *d) { d->u.real.empty_timeout = time(NULL) + EMPTY_TIMEOUT; d->u.real.empty = 0; } int real_check_empty(DiskState *d) { #if __linux int reset_now = 0; struct floppy_raw_cmd raw_cmd; int res, i = 0; sigset_t set, oldset; if (time(NULL) <= d->u.real.empty_timeout) return d->u.real.empty; if (d->file == NULL) { d->u.real.empty = 1; return 1; } ioctl(fileno(d->file), FDRESET, &reset_now); /* Do a read id command. Assume a disk is in the drive iff we get a nonnegative status back from the ioctl. */ memset(&raw_cmd, 0, sizeof(raw_cmd)); raw_cmd.rate = real_rate(d); raw_cmd.flags = FD_RAW_INTR; raw_cmd.cmd[i++] = state.density ? 0x4a : 0x0a; /* read ID */ raw_cmd.cmd[i++] = state.curside ? 4 : 0; raw_cmd.cmd_count = i; raw_cmd.data = NULL; raw_cmd.length = 0; sigemptyset(&set); sigaddset(&set, SIGALRM); sigprocmask(SIG_BLOCK, &set, &oldset); trs_paused = 1; res = ioctl(fileno(d->file), FDRAWCMD, &raw_cmd); sigprocmask(SIG_SETMASK, &oldset, NULL); if (res < 0) { real_error(d, raw_cmd.flags, "check_empty"); } else { real_ok(d); } #else trs_disk_unimpl(state.currcommand, "check for empty on real floppy"); #endif return d->u.real.empty; } void real_verify() { /* Verify that head is on the expected track */ /*!! ignore for now*/ } void real_restore(curdrive) { #if __linux DiskState *d = &disk[curdrive]; struct floppy_raw_cmd raw_cmd; int res, i = 0; sigset_t set, oldset; raw_cmd.flags = FD_RAW_INTR; raw_cmd.cmd[i++] = FD_RECALIBRATE; raw_cmd.cmd[i++] = 0; raw_cmd.cmd_count = i; sigemptyset(&set); sigaddset(&set, SIGALRM); sigprocmask(SIG_BLOCK, &set, &oldset); trs_paused = 1; res = ioctl(fileno(d->file), FDRAWCMD, &raw_cmd); sigprocmask(SIG_SETMASK, &oldset, NULL); if (res < 0) { real_error(d, raw_cmd.flags, "restore"); state.status |= TRSDISK_SEEKERR; return; } #else trs_disk_unimpl(state.currcommand, "restore real floppy"); #endif } void real_seek() { #if __linux DiskState *d = &disk[state.curdrive]; struct floppy_raw_cmd raw_cmd; int res, i = 0; sigset_t set, oldset; /* Always use a recal if going to track 0. This should help us recover from confusion about what track the disk is really on. I'm still not sure why the confusion sometimes arises. */ if (d->phytrack == 0) { real_restore(state.curdrive); return; } state.last_readadr = -1; memset(&raw_cmd, 0, sizeof(raw_cmd)); raw_cmd.length = 256; raw_cmd.data = NULL; raw_cmd.rate = real_rate(d); raw_cmd.flags = FD_RAW_INTR; raw_cmd.cmd[i++] = FD_SEEK; raw_cmd.cmd[i++] = 0; raw_cmd.cmd[i++] = d->phytrack * d->real_step; raw_cmd.cmd_count = i; sigemptyset(&set); sigaddset(&set, SIGALRM); sigprocmask(SIG_BLOCK, &set, &oldset); trs_paused = 1; res = ioctl(fileno(d->file), FDRAWCMD, &raw_cmd); sigprocmask(SIG_SETMASK, &oldset, NULL); if (res < 0) { real_error(d, raw_cmd.flags, "seek"); state.status |= TRSDISK_SEEKERR; return; } #else trs_disk_unimpl(state.currcommand, "seek real floppy"); #endif } void real_read() { #if __linux DiskState *d = &disk[state.curdrive]; struct floppy_raw_cmd raw_cmd; int res, i, retry, new_status; sigset_t set, oldset; /* Try once at each supported sector size */ retry = 0; for (;;) { state.status = 0; new_status = 0; memset(&raw_cmd, 0, sizeof(raw_cmd)); raw_cmd.rate = real_rate(d); raw_cmd.flags = FD_RAW_READ | FD_RAW_INTR; i = 0; raw_cmd.cmd[i++] = state.density ? 0x46 : 0x06; raw_cmd.cmd[i++] = state.curside ? 4 : 0; raw_cmd.cmd[i++] = state.track; raw_cmd.cmd[i++] = state.curside; raw_cmd.cmd[i++] = state.sector; raw_cmd.cmd[i++] = d->u.real.size_code; raw_cmd.cmd[i++] = 255; raw_cmd.cmd[i++] = 0x0a; raw_cmd.cmd[i++] = 0xff; /* unused */ raw_cmd.cmd_count = i; raw_cmd.data = (void*) d->u.real.buf; raw_cmd.length = 128 << d->u.real.size_code; sigemptyset(&set); sigaddset(&set, SIGALRM); sigprocmask(SIG_BLOCK, &set, &oldset); trs_paused = 1; res = ioctl(fileno(d->file), FDRAWCMD, &raw_cmd); sigprocmask(SIG_SETMASK, &oldset, NULL); if (res < 0) { real_error(d, raw_cmd.flags, "read"); new_status |= TRSDISK_NOTFOUND; } else { real_ok(d); /* premature? */ if (raw_cmd.reply[1] & 0x04) { /* Could have been due to wrong sector size, so we'll retry internally in each other size before returning an error. */ if (trs_disk_debug_flags & DISKDEBUG_REALSIZE) { debug("real_read not fnd: side %d tk %d sec %d size 0%d phytk %d\n", state.curside, state.track, state.sector, d->u.real.size_code, d->phytrack*d->real_step); } #if SIZERETRY d->u.real.size_code = (d->u.real.size_code + 1) % 4; if (++retry < 4) { continue; /* retry */ } #endif new_status |= TRSDISK_NOTFOUND; } if (raw_cmd.reply[1] & 0x81) new_status |= TRSDISK_NOTFOUND; if (raw_cmd.reply[1] & 0x20) { new_status |= TRSDISK_CRCERR; if (!(raw_cmd.reply[2] & 0x20)) new_status |= TRSDISK_NOTFOUND; } if (raw_cmd.reply[1] & 0x10) new_status |= TRSDISK_LOSTDATA; if (raw_cmd.reply[2] & 0x40) { if (state.controller == TRSDISK_P1771) { if (trs_disk_truedam) { new_status |= TRSDISK_1771_F8; } else { new_status |= TRSDISK_1771_FA; } } else { new_status |= TRSDISK_1791_F8; } } if (raw_cmd.reply[2] & 0x20) new_status |= TRSDISK_CRCERR; if (raw_cmd.reply[2] & 0x13) new_status |= TRSDISK_NOTFOUND; if ((new_status & TRSDISK_NOTFOUND) == 0) { /* Start read */ state.status = TRSDISK_BUSY; trs_schedule_event(trs_disk_firstdrq, new_status, 64); state.bytecount = size_code_to_size(d->u.real.size_code); return; } } break; /* exit retry loop */ } /* Sector not found; fail */ state.status = TRSDISK_BUSY; trs_schedule_event(trs_disk_done, new_status, 512); #else trs_disk_unimpl(state.currcommand, "read real floppy"); #endif } void real_write() { #if __linux DiskState *d = &disk[state.curdrive]; struct floppy_raw_cmd raw_cmd; int res, i = 0; sigset_t set, oldset; state.status = 0; memset(&raw_cmd, 0, sizeof(raw_cmd)); raw_cmd.rate = real_rate(d); raw_cmd.flags = FD_RAW_WRITE | FD_RAW_INTR; if (trs_disk_truedam && !state.density) { switch (state.currcommand & 0x03) { case 0: case 3: break; case 1: error("writing FA DAM on real floppy"); break; case 2: error("writing F9 DAM on real floppy"); break; } } /* Use F8 DAM for F8, F9, or FA */ raw_cmd.cmd[i++] = ((state.currcommand & (state.controller == TRSDISK_P1771 ? 0x03 : 0x01)) ? 0x09 : 0x05) | (state.density ? 0x40 : 0x00); raw_cmd.cmd[i++] = state.curside ? 4 : 0; raw_cmd.cmd[i++] = state.track; raw_cmd.cmd[i++] = state.curside; raw_cmd.cmd[i++] = state.sector; raw_cmd.cmd[i++] = d->u.real.size_code; raw_cmd.cmd[i++] = 255; raw_cmd.cmd[i++] = 0x0a; raw_cmd.cmd[i++] = 0xff; /* 256 */ raw_cmd.cmd_count = i; raw_cmd.data = (void*) d->u.real.buf; raw_cmd.length = 128 << d->u.real.size_code; sigemptyset(&set); sigaddset(&set, SIGALRM); sigprocmask(SIG_BLOCK, &set, &oldset); trs_paused = 1; res = ioctl(fileno(d->file), FDRAWCMD, &raw_cmd); sigprocmask(SIG_SETMASK, &oldset, NULL); if (res < 0) { real_error(d, raw_cmd.flags, "write"); state.status |= TRSDISK_NOTFOUND; } else { real_ok(d); /* premature? */ if (raw_cmd.reply[1] & 0x04) { state.status |= TRSDISK_NOTFOUND; /* Could have been due to wrong sector size. Presumably the Z-80 software will do some retries, so we'll cause it to try the next sector size next time. */ if (trs_disk_debug_flags & DISKDEBUG_REALSIZE) { debug("real_write not found: side %d tk %d sec %d size 0%d phytk %d\n", state.curside, state.track, state.sector, d->u.real.size_code, d->phytrack*d->real_step); } #if SIZERETRY d->u.real.size_code = (d->u.real.size_code + 1) % 4; #endif } if (raw_cmd.reply[1] & 0x81) state.status |= TRSDISK_NOTFOUND; if (raw_cmd.reply[1] & 0x20) { state.status |= TRSDISK_CRCERR; if (!(raw_cmd.reply[2] & 0x20)) state.status |= TRSDISK_NOTFOUND; } if (raw_cmd.reply[1] & 0x10) state.status |= TRSDISK_LOSTDATA; if (raw_cmd.reply[1] & 0x02) { state.status |= TRSDISK_WRITEPRT; d->writeprot = 1; } else { d->writeprot = 0; } if (raw_cmd.reply[2] & 0x20) state.status |= TRSDISK_CRCERR; if (raw_cmd.reply[2] & 0x13) state.status |= TRSDISK_NOTFOUND; } state.bytecount = 0; trs_disk_drq_interrupt(0); state.status |= TRSDISK_BUSY; if (trs_event_scheduled() == trs_disk_lostdata) { trs_cancel_event(); } trs_schedule_event(trs_disk_done, 0, 512); #else trs_disk_unimpl(state.currcommand, "write real floppy"); #endif } void real_readadr() { #if __linux DiskState *d = &disk[state.curdrive]; struct floppy_raw_cmd raw_cmd; int res, i, new_status; sigset_t set, oldset; state.status = 0; new_status = 0; memset(&raw_cmd, 0, sizeof(raw_cmd)); raw_cmd.rate = real_rate(d); raw_cmd.flags = FD_RAW_INTR; i = 0; raw_cmd.cmd[i++] = state.density ? 0x4a : 0x0a; raw_cmd.cmd[i++] = state.curside ? 4 : 0; raw_cmd.cmd_count = i; raw_cmd.data = NULL; raw_cmd.length = 0; sigemptyset(&set); sigaddset(&set, SIGALRM); sigprocmask(SIG_BLOCK, &set, &oldset); trs_paused = 1; res = ioctl(fileno(d->file), FDRAWCMD, &raw_cmd); sigprocmask(SIG_SETMASK, &oldset, NULL); state.bytecount = 0; if (res < 0) { real_error(d, raw_cmd.flags, "readadr"); new_status |= TRSDISK_NOTFOUND; } else { real_ok(d); /* premature? */ if (raw_cmd.reply[1] & 0x85) new_status |= TRSDISK_NOTFOUND; if (raw_cmd.reply[1] & 0x20) new_status |= TRSDISK_CRCERR; if (raw_cmd.reply[1] & 0x10) new_status |= TRSDISK_LOSTDATA; if (raw_cmd.reply[2] & 0x40) { if (state.controller == TRSDISK_P1771) { new_status |= TRSDISK_1771_FA; } else { new_status |= TRSDISK_1791_F8; } } if (raw_cmd.reply[2] & 0x20) new_status |= TRSDISK_CRCERR; if (raw_cmd.reply[2] & 0x13) new_status |= TRSDISK_NOTFOUND; if ((new_status & TRSDISK_NOTFOUND) == 0) { state.status = TRSDISK_BUSY; trs_schedule_event(trs_disk_firstdrq, new_status, 64); memcpy(d->u.real.buf, &raw_cmd.reply[3], 4); d->u.real.buf[4] = d->u.real.buf[5] = 0; /* CRC not emulated */ state.bytecount = 6; d->u.real.size_code = d->u.real.buf[3]; /* update hint */ return; } } state.last_readadr = -1; /* Sector not found; fail */ state.status = TRSDISK_BUSY; trs_schedule_event(trs_disk_done, new_status, 200000*z80_state.clockMHz); #else trs_disk_unimpl(state.currcommand, "read address on real floppy"); #endif } void real_readtrk() { trs_disk_unimpl(state.currcommand, "read track on real floppy"); } void real_writetrk() { #if __linux DiskState *d = &disk[state.curdrive]; struct floppy_raw_cmd raw_cmd; int res, i, gap3; sigset_t set, oldset; state.status = 0; /* Compute a usable gap3 */ /* Constants based on IBM format as explained in "The floppy user guide" by Michael Haardt, Alain Knaff, and David C. Niemi */ /* The formulas and constants are not factored out, in case some of those that are the same now need to change when I learn more. */ if (state.density) { /* MFM recording */ if (d->inches == 5) { /* 5" DD = 250 kHz MFM */ gap3 = (TRKSIZE_DD - 161 - /*slop*/16)/(d->u.real.fmt_nbytes / 4) - 62 - (128 << d->u.real.size_code) - /*slop*/2; } else { /* 8" DD = 5" HD = 500 kHz MFM */ gap3 = (TRKSIZE_8DD - 161 - /*slop*/16)/(d->u.real.fmt_nbytes / 4) - 62 - (128 << d->u.real.size_code) - /*slop*/2; } } else { /* FM recording */ if (d->inches == 5) { /* 5" SD = 250 kHz FM (125 kbps) */ gap3 = (TRKSIZE_SD - 99 - /*slop*/16)/(d->u.real.fmt_nbytes / 4) - 33 - (128 << d->u.real.size_code) - /*slop*/2; } else { /* 8" SD = 5" HD operated in FM = 500 kHz FM (250 kbps) */ gap3 = (TRKSIZE_8SD - 99 - /*slop*/16)/(d->u.real.fmt_nbytes / 4) - 33 - (128 << d->u.real.size_code) - /*slop*/2; } } if (gap3 < 1) { error("gap3 too small"); gap3 = 1; } else if (gap3 > 0xff) { gap3 = 0xff; } /* Do the actual write track */ memset(&raw_cmd, 0, sizeof(raw_cmd)); raw_cmd.rate = real_rate(d); raw_cmd.flags = FD_RAW_WRITE | FD_RAW_INTR; i = 0; raw_cmd.cmd[i++] = 0x0d | (state.density ? 0x40 : 0x00); raw_cmd.cmd[i++] = state.curside ? 4 : 0; raw_cmd.cmd[i++] = d->u.real.size_code; raw_cmd.cmd[i++] = d->u.real.fmt_nbytes / 4; raw_cmd.cmd[i++] = gap3; raw_cmd.cmd[i++] = d->u.real.fmt_fill; raw_cmd.cmd_count = i; raw_cmd.data = (void*) d->u.real.buf; raw_cmd.length = d->u.real.fmt_nbytes; if (trs_disk_debug_flags & DISKDEBUG_GAPS) { debug("real_writetrk size 0%d secs %d gap3 %d fill 0x%02x hex data ", d->u.real.size_code, d->u.real.fmt_nbytes/4, gap3, d->u.real.fmt_fill); for (i=0; iu.real.fmt_nbytes; i+=4) { debug("%02x%02x%02x%02x ", d->u.real.buf[i], d->u.real.buf[i+1], d->u.real.buf[i+2], d->u.real.buf[i+3]); } debug("\n"); } sigemptyset(&set); sigaddset(&set, SIGALRM); sigprocmask(SIG_BLOCK, &set, &oldset); trs_paused = 1; res = ioctl(fileno(d->file), FDRAWCMD, &raw_cmd); sigprocmask(SIG_SETMASK, &oldset, NULL); if (res < 0) { real_error(d, raw_cmd.flags, "writetrk"); state.status |= TRSDISK_WRITEFLT; } else { real_ok(d); /* premature? */ if (raw_cmd.reply[1] & 0x85) state.status |= TRSDISK_NOTFOUND; if (raw_cmd.reply[1] & 0x20) state.status |= TRSDISK_CRCERR; if (raw_cmd.reply[1] & 0x10) state.status |= TRSDISK_LOSTDATA; if (raw_cmd.reply[1] & 0x02) { state.status |= TRSDISK_WRITEPRT; d->writeprot = 1; } else { d->writeprot = 0; } if (raw_cmd.reply[2] & 0x20) state.status |= TRSDISK_CRCERR; if (raw_cmd.reply[2] & 0x13) state.status |= TRSDISK_NOTFOUND; } state.bytecount = 0; trs_disk_drq_interrupt(0); state.status |= TRSDISK_BUSY; if (trs_event_scheduled() == trs_disk_lostdata) { trs_cancel_event(); } trs_schedule_event(trs_disk_done, 0, 512); #else trs_disk_unimpl(state.currcommand, "write track on real floppy"); #endif } xtrs-4.9d/trs_disk.h000066400000000000000000000157651306603614600145500ustar00rootroot00000000000000/* Copyright (c) 1996, Timothy Mann */ /* $Id: trs_disk.h,v 1.12 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* * Emulate Model-I or Model-III disk controller */ extern void trs_disk_init(int reset_button); extern void trs_disk_select_write(unsigned char data); extern unsigned char trs_disk_track_read(void); extern void trs_disk_track_write(unsigned char data); extern unsigned char trs_disk_sector_read(void); extern void trs_disk_sector_write(unsigned char data); extern unsigned char trs_disk_data_read(void); extern void trs_disk_data_write(unsigned char data); extern unsigned char trs_disk_status_read(void); extern void trs_disk_command_write(unsigned char cmd); extern unsigned char trs_disk_interrupt_read(void); /* M3 only */ extern void trs_disk_interrupt_write(unsigned char mask); /* M3 only */ extern void trs_disk_setstep(int unit, int value); extern int trs_disk_getstep(int unit); extern void trs_disk_setsize(int unit, int value); extern int trs_disk_getsize(int unit); extern int trs_disk_doubler; extern char* trs_disk_dir; extern unsigned short trs_disk_changecount; extern int trs_disk_truedam; /* Values for trs_disk_doubler flag word */ #define TRSDISK_NODOUBLER 0 #define TRSDISK_PERCOM 1 #define TRSDISK_TANDY 2 #define TRSDISK_BOTH 3 /* Model I drive select register -- address bits 0,1 not decoded */ #define TRSDISK_SELECT(addr) (((addr)&~3) == 0x37e0) #define TRSDISK_0 0x1 #define TRSDISK_1 0x2 #define TRSDISK_2 0x4 #define TRSDISK_3 0x8 #define TRSDISK_SIDE 0x8 /* shared on Model I */ #define TRSDISK_4 0x3 /* fake value for emulator only */ #define TRSDISK_5 0x5 /* fake value for emulator only */ #define TRSDISK_6 0x6 /* fake value for emulator only */ #define TRSDISK_7 0x7 /* fake value for emulator only */ /* FDC address space in Model I */ #define TRSDISK_FDC 0x37ec #define TRSDISK_FDCLEN 4 /* 4 bytes are mapped, offsets as follows: */ #define TRSDISK_COMMAND 0x37ec /* writing */ #define TRSDISK_STATUS 0x37ec /* reading */ #define TRSDISK_TRACK 0x37ed #define TRSDISK_SECTOR 0x37ee #define TRSDISK_DATA 0x37ef /* FDC port space in Model III */ #define TRSDISK3_INTERRUPT 0xe4 #define TRSDISK3_COMMAND 0xf0 /* writing */ #define TRSDISK3_STATUS 0xf0 /* reading */ #define TRSDISK3_TRACK 0xf1 #define TRSDISK3_SECTOR 0xf2 #define TRSDISK3_DATA 0xf3 #define TRSDISK3_SELECT 0xf4 /* write-only */ /* Interrupt register bits (M3 only) */ #define TRSDISK3_INTRQ 0x80 #define TRSDISK3_DRQ 0x40 #define TRSDISK3_RESET 0x20 /* reset button, not really disk related */ /* Select register bits (M3 only). Drives 0-3 same as model 1. */ #define TRSDISK3_MFM 0x80 #define TRSDISK3_WAIT 0x40 #define TRSDISK3_PRECOMP 0x20 #define TRSDISK3_SIDE 0x10 /* not shared! */ /* Commands */ #define TRSDISK_CMDMASK 0xf0 /* high nybble selects which command */ /* Type I commands: cccchvrr, where cccc = command number h = head load v = verify (i.e., read next address to check we're on the right track) rr = step rate: 00=6ms, 01=12ms, 10=20ms, 11=40ms */ #define TRSDISK_RESTORE 0x00 #define TRSDISK_SEEK 0x10 #define TRSDISK_STEP 0x20 /* don't update track reg */ #define TRSDISK_STEPU 0x30 /* do update track reg */ #define TRSDISK_STEPIN 0x40 #define TRSDISK_STEPINU 0x50 #define TRSDISK_STEPOUT 0x60 #define TRSDISK_STEPOUTU 0x70 #define TRSDISK_UBIT 0x10 #define TRSDISK_HBIT 0x08 #define TRSDISK_VBIT 0x04 /* Type II commands: ccccbecd, where cccc = command number e = delay for head engage (10ms) 1771: b = 1=IBM format, 0=nonIBM format cd = select data address mark (writes only, 00 for reads): 00=FB (normal), 01=FA, 10=F9, 11=F8 (deleted) 1791: b = side expected c = side compare (0=disable, 1=enable) d = select data address mark (writes only, 0 for reads): 0=FB (normal), 1=F8 (deleted) */ #define TRSDISK_READ 0x80 /* single sector */ #define TRSDISK_READM 0x90 /* multiple sectors */ #define TRSDISK_WRITE 0xa0 #define TRSDISK_WRITEM 0xb0 #define TRSDISK_MBIT 0x10 #define TRSDISK_BBIT 0x08 #define TRSDISK_EBIT 0x04 #define TRSDISK_CBIT 0x02 #define TRSDISK_DBIT 0x01 /* Type III commands: ccccxxxs (?), where cccc = command number xxx = ?? (usually 010) s = 1=READTRK no synchronize; otherwise 0 */ #define TRSDISK_READADR 0xc0 #define TRSDISK_READTRK 0xe0 #define TRSDISK_WRITETRK 0xf0 /* These commands are peculiar to the Percom Doubler */ #define TRSDISK_P1771 0xfe /* Select 1771 single density controller */ #define TRSDISK_P1791 0xff /* Select 1791 double density controller */ /* Type IV command: cccciiii, where cccc = command number iiii = bitmask of events to terminate and interrupt on (unused on trs80); 0000 for immediate terminate with no interrupt. */ #define TRSDISK_FORCEINT 0xd0 /* These "commands" are peculiar to the Radio Shack Doubler. They are written to the sector register, not the command register! */ #define TRSDISK_R1791 0x80 #define TRSDISK_R1771 0xa0 #define TRSDISK_NOPRECMP 0xc0 #define TRSDISK_PRECMP 0xe0 /* Type I status bits */ #define TRSDISK_BUSY 0x01 #define TRSDISK_INDEX 0x02 #define TRSDISK_TRKZERO 0x04 #define TRSDISK_CRCERR 0x08 #define TRSDISK_SEEKERR 0x10 #define TRSDISK_HEADENGD 0x20 #define TRSDISK_WRITEPRT 0x40 #define TRSDISK_NOTRDY 0x80 /* Read status bits */ /* TRSDISK_BUSY 0x01*/ #define TRSDISK_DRQ 0x02 #define TRSDISK_LOSTDATA 0x04 /* TRSDISK_CRCERR 0x08*/ #define TRSDISK_NOTFOUND 0x10 #define TRSDISK_RECTYPE 0x60 #define TRSDISK_1771_FB 0x00 #define TRSDISK_1771_FA 0x20 #define TRSDISK_1771_F9 0x40 #define TRSDISK_1771_F8 0x60 #define TRSDISK_1791_FB 0x00 #define TRSDISK_1791_F8 0x20 /* TRSDISK_NOTRDY 0x80*/ /* Write status bits */ /* TRSDISK_BUSY 0x01*/ /* TRSDISK_DRQ 0x02*/ /* TRSDISK_LOSTDATA 0x04*/ /* TRSDISK_CRCERR 0x08*/ /* TRSDISK_NOTFOUND 0x10*/ #define TRSDISK_WRITEFLT 0x20 /* TRSDISK_WRITEPRT 0x40*/ /* TRSDISK_NOTRDY 0x80*/ /* Read address status bits */ /* TRSDISK_BUSY 0x01*/ /* TRSDISK_DRQ 0x02*/ /* TRSDISK_LOSTDATA 0x04*/ /* TRSDISK_CRCERR 0x08*/ /* TRSDISK_NOTFOUND 0x10*/ /* unused, mbz 0x60*/ /* TRSDISK_NOTRDY 0x80*/ /* Read track status bits */ /* TRSDISK_BUSY 0x01*/ /* TRSDISK_DRQ 0x02*/ /* TRSDISK_LOSTDATA 0x04*/ /* unused, mbz 0x78*/ /* TRSDISK_NOTRDY 0x80*/ /* Write track status bits */ /* TRSDISK_BUSY 0x01*/ /* TRSDISK_DRQ 0x02*/ /* TRSDISK_LOSTDATA 0x04*/ /* unused, mbz 0x18*/ /* TRSDISK_WRITEFLT 0x20*/ /* TRSDISK_WRITEPRT 0x40*/ /* TRSDISK_NOTRDY 0x80*/ xtrs-4.9d/trs_hard.c000066400000000000000000000313551306603614600145200ustar00rootroot00000000000000/* Copyright (c) 2000, Timothy Mann */ /* $Id: trs_hard.c,v 1.8 2009/06/15 23:40:47 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* * Emulation of the Radio Shack TRS-80 Model I/III/4/4P * hard disk controller. This is a Western Digital WD1000/WD1010 * mapped at ports 0xc8-0xcf, plus control registers at 0xc0-0xc1. */ #include #include #include "trs.h" #include "trs_hard.h" #include "reed.h" /*#define HARDDEBUG1 1*/ /* show detail on all port i/o */ /*#define HARDDEBUG2 1*/ /* show all commands */ /*#define HARDDEBUG3 1*/ /* show failure to open a drive */ /* Private types and data */ /* Structure describing one drive */ typedef struct { FILE* file; /* Values decoded from rhh */ int writeprot; int cyls; /* cyls per drive */ int heads; /* tracks per cyl */ int secs; /* secs per track */ } Drive; /* Structure describing controller state */ typedef struct { /* Controller present? Yes if we have any drives, no if none */ int present; /* Controller register images */ Uchar control; Uchar data; Uchar error; Uchar seccnt; Uchar secnum; Ushort cyl; Uchar drive; Uchar head; Uchar status; Uchar command; /* Number of bytes already done in current read/write */ int bytesdone; /* Drive geometries and files */ Drive d[TRS_HARD_MAXDRIVES]; } State; static State state; /* Forward */ static int hard_data_in(); static void hard_data_out(int value); static void hard_restore(int cmd); static void hard_read(int cmd); static void hard_write(int cmd); static void hard_verify(int cmd); static void hard_format(int cmd); static void hard_init(int cmd); static void hard_seek(int cmd); static int open_drive(int drive); static int find_sector(int newstatus); static int open_drive(int n); static void set_dir_cyl(int cyl); /* Powerup or reset button */ void trs_hard_init(void) { int i; state.control = 0; state.data = 0; state.error = 0; state.seccnt = 0; state.secnum = 0; state.cyl = 0; state.drive = 0; state.head = 0; state.status = 0; state.command = 0; for (i=0; i> 8) & 0xff; break; case TRS_HARD_SDH: v = (state.drive << 3) | state.head; break; case TRS_HARD_STATUS: v = state.status; break; default: v = 0xff; break; } } else { v = 0xff; } #if HARDDEBUG1 debug("%02x -> %02x\n", port, v); #endif return v; } /* Write to an I/O port mapped to the controller */ void trs_hard_out(int port, int value) { #if HARDDEBUG1 debug("%02x <- %02x\n", port, value); #endif switch (port) { case TRS_HARD_WP: break; case TRS_HARD_CONTROL: if (value & TRS_HARD_SOFTWARE_RESET) { trs_hard_init(); } if ((value & TRS_HARD_DEVICE_ENABLE) && state.present == 0) { int i; for (i=0; i> TRS_HARD_DRIVESHIFT; state.head = (value & TRS_HARD_HEADMASK) >> TRS_HARD_HEADSHIFT; #if 0 if (!open_drive(state.drive)) state.status &= ~TRS_HARD_READY; #else /* Ready, but perhaps not able! This way seems to work better; it * avoids a long delay in the Model 4P boot ROM when there is no * unit 0. */ state.status = TRS_HARD_READY | TRS_HARD_SEEKDONE; #endif break; case TRS_HARD_COMMAND: state.bytesdone = 0; state.command = value; switch (value & TRS_HARD_CMDMASK) { default: error("trs_hard: unknown command 0x%02x", value); break; case TRS_HARD_RESTORE: hard_restore(value); break; case TRS_HARD_READ: hard_read(value); break; case TRS_HARD_WRITE: hard_write(value); break; case TRS_HARD_VERIFY: hard_verify(value); break; case TRS_HARD_FORMAT: hard_format(value); break; case TRS_HARD_INIT: hard_init(value); break; case TRS_HARD_SEEK: hard_seek(value); break; } break; default: break; } } static void hard_restore(int cmd) { #if HARDDEBUG2 debug("hard_restore drive %d\n", state.drive); #endif state.cyl = 0; /*!! should anything else be zeroed? */ state.status = TRS_HARD_READY | TRS_HARD_SEEKDONE; } static void hard_read(int cmd) { #if HARDDEBUG2 debug("hard_read drive %d cyl %d hd %d sec %d\n", state.drive, state.cyl, state.head, state.secnum); #endif if (cmd & TRS_HARD_MULTI) { error("trs_hard: multi-sector read not supported (0x%02x)", cmd); state.status = TRS_HARD_READY | TRS_HARD_SEEKDONE | TRS_HARD_ERR; state.error = TRS_HARD_ABRTERR; return; } find_sector(TRS_HARD_READY | TRS_HARD_SEEKDONE | TRS_HARD_DRQ); } static void hard_write(int cmd) { #if HARDDEBUG2 debug("hard_write drive %d cyl %d hd %d sec %d\n", state.drive, state.cyl, state.head, state.secnum); #endif if (cmd & TRS_HARD_MULTI) { error("trs_hard: multi-sector write not supported (0x%02x)", cmd); state.status = TRS_HARD_READY | TRS_HARD_SEEKDONE | TRS_HARD_ERR; state.error = TRS_HARD_ABRTERR; return; } find_sector(TRS_HARD_READY | TRS_HARD_SEEKDONE | TRS_HARD_DRQ); } static void hard_verify(int cmd) { #if HARDDEBUG2 debug("hard_verify drive %d cyl %d hd %d sec %d\n", state.drive, state.cyl, state.head, state.secnum); #endif find_sector(TRS_HARD_READY | TRS_HARD_SEEKDONE); } static void hard_format(int cmd) { #if HARDDEBUG2 debug("hard_format drive %d cyl %d hd %d\n", state.drive, state.cyl, state.head); #endif if (state.seccnt != TRS_HARD_SEC_PER_TRK) { error("trs_hard: can only do %d sectors/track, not %d", TRS_HARD_SEC_PER_TRK, state.seccnt); } if (state.secnum != TRS_HARD_SECSIZE_CODE) { error("trs_hard: can only do %d bytes/sectors (code %d), not code %d", TRS_HARD_SECSIZE, TRS_HARD_SECSIZE_CODE, state.secnum); } /* !!should probably set up to read skew table here */ state.status = TRS_HARD_READY | TRS_HARD_SEEKDONE; } static void hard_init(int cmd) { #if HARDDEBUG2 debug("hard_init drive %d cyl %d hd %d sec %d\n", state.drive, state.cyl, state.head, state.secnum); #endif /* I don't know what this command does */ error("trs_hard: init command (0x%02x) not implemented", cmd); state.status = TRS_HARD_READY | TRS_HARD_SEEKDONE; } static void hard_seek(int cmd) { #if HARDDEBUG2 debug("hard_seek drive %d cyl %d hd %d sec %d\n", state.drive, state.cyl, state.head, state.secnum); #endif find_sector(TRS_HARD_READY | TRS_HARD_SEEKDONE); } /* * 1) Make sure the file for the current drive is open. If the file * cannot be opened, return 0 and set the controller error status. * * 2) If newly opening the file, establish the hardware write protect * status and geometry in the Drive structure. * * 3) Return 1 if all OK. */ static int open_drive(int drive) { Drive *d = &state.d[drive]; char diskname[1024]; ReedHardHeader rhh; size_t res; if (d->file != NULL) return 1; /* Compute the filename */ if (trs_model == 5) { sprintf(diskname, "%s/hard4p-%d", trs_disk_dir, drive); } else { sprintf(diskname, "%s/hard%d-%d", trs_disk_dir, trs_model, drive); } /* First try opening for reading and writing */ d->file = fopen(diskname, "r+"); if (d->file == NULL) { /* No luck, try for reading only */ d->file = fopen(diskname, "r"); if (d->file == NULL) { #if HARDDEBUG3 error("trs_hard: could not open hard drive image %s: %s", diskname, strerror(errno)); #endif goto fail; } d->writeprot = 1; } else { d->writeprot = 0; } /* Read in the Reed header and check some basic magic numbers (not all) */ res = fread(&rhh, sizeof(rhh), 1, d->file); if (res != 1 || rhh.id1 != 0x56 || rhh.id2 != 0xcb || rhh.ver != 0x10) { error("trs_hard: unrecognized hard drive image %s", diskname); goto fail; } if (rhh.flag1 & 0x80) d->writeprot = 1; /* Use the number of cylinders specified in the header */ d->cyls = rhh.cyl ? rhh.cyl : 256; /* Use the number of secs/track that RSHARD requires */ d->secs = TRS_HARD_SEC_PER_TRK; /* Header gives only secs/cyl. Compute number of heads from this and the assumed number of secs/track. */ d->heads = (rhh.sec ? rhh.sec : 256) / d->secs; if ((rhh.sec % d->secs) != 0 || d->heads <= 0 || d->heads > TRS_HARD_MAXHEADS) { error("trs_hard: unusable geometry in image %s", diskname); goto fail; } state.status = TRS_HARD_READY | TRS_HARD_SEEKDONE; return 1; fail: if (d->file) fclose(d->file); d->file = NULL; state.status = TRS_HARD_READY | TRS_HARD_SEEKDONE | TRS_HARD_ERR; state.error = TRS_HARD_NFERR; return 0; } /* * Check whether the current position is in bounds for the geometry. * If not, return 0 and set the controller error status. If so, fseek * the file to the start of the current sector, return 1, and set * the controller status to newstatus. */ static int find_sector(int newstatus) { Drive *d = &state.d[state.drive]; if (open_drive(state.drive) == 0) return 0; if (/**state.cyl >= d->cyls ||**/ /* ignore this limit */ state.head >= d->heads || state.secnum > d->secs /* allow 0-origin or 1-origin */ ) { error("trs_hard: requested cyl %d hd %d sec %d; max cyl %d hd %d sec %d\n", state.cyl, state.head, state.secnum, d->cyls, d->heads, d->secs); state.status = TRS_HARD_READY | TRS_HARD_SEEKDONE | TRS_HARD_ERR; state.error = TRS_HARD_NFERR; return 0; } fseek(d->file, sizeof(ReedHardHeader) + TRS_HARD_SECSIZE * (state.cyl * d->heads * d->secs + state.head * d->secs + (state.secnum % d->secs)), 0); state.status = newstatus; return 1; } static int hard_data_in() { Drive *d = &state.d[state.drive]; if ((state.command & TRS_HARD_CMDMASK) == TRS_HARD_READ && (state.status & TRS_HARD_ERR) == 0) { if (state.bytesdone < TRS_HARD_SECSIZE) { state.data = getc(d->file); state.bytesdone++; } } return state.data; } static void hard_data_out(int value) { Drive *d = &state.d[state.drive]; int res = 0; state.data = value; if ((state.command & TRS_HARD_CMDMASK) == TRS_HARD_WRITE && (state.status & TRS_HARD_ERR) == 0) { if (state.bytesdone < TRS_HARD_SECSIZE) { if (state.cyl == 0 && state.head == 0 && state.secnum == 0 && state.bytesdone == 2) { set_dir_cyl(value); } res = putc(state.data, d->file); state.bytesdone++; if (res != EOF && state.bytesdone == TRS_HARD_SECSIZE) { res = fflush(d->file); } } } if (res == EOF) { error("trs_hard: errno %d while writing drive %d", errno, state.drive); state.status = TRS_HARD_READY | TRS_HARD_SEEKDONE | TRS_HARD_ERR; state.error = TRS_HARD_DATAERR; /* arbitrary choice */ } } /* Sleazy trick to update the "directory cylinder" byte in the Reed header. This value is only needed by the Reed emulator itself, and we would like xtrs to set it automatically so that the user doesn't have to know about it. */ static void set_dir_cyl(int cyl) { Drive *d = &state.d[state.drive]; long where = ftell(d->file); fseek(d->file, 31, 0); putc(cyl, d->file); fseek(d->file, where, 0); } xtrs-4.9d/trs_hard.h000066400000000000000000000124551306603614600145250ustar00rootroot00000000000000/* Copyright (c) 2000, Timothy Mann */ /* $Id: trs_hard.h,v 1.6 2009/06/15 23:41:03 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* * Definitions for the Radio Shack TRS-80 Model I/III/4/4P * hard disk controller. This is a Western Digital WD1000/WD1010 * mapped at ports 0xc8-0xcf, plus control registers at 0xc0-0xc1. * * Definitions inferred from various drivers and sketchy documents * found in odd corners. Anyone have a real WD10xx data sheet? */ extern void trs_hard_init(void); extern int trs_hard_in(int port); extern void trs_hard_out(int port, int value); extern char* trs_disk_dir; /* Sector size is always 256 for TRSDOS/LDOS/etc. */ /* Other sizes currently not emulated */ #define TRS_HARD_SECSIZE 256 #define TRS_HARD_SECSIZE_CODE 0x0f /* size code for 256 byte sectors?!! */ /* RSHARD assumes 32 sectors/track */ /* Other sizes currently not emulated */ #define TRS_HARD_SEC_PER_TRK 32 /* * Tandy-specific registers */ /* Write protect switch register (read only): * abcd--pi * a = drive 0 write protected * b = drive 1 write protected * c = drive 2 write protected * d = drive 3 write protected * p = at least one drive write protected * i = interrupt request */ #define TRS_HARD_WP 0xc0 #define TRS_HARD_WPBIT(d) (0x80 >> (d)) #define TRS_HARD_WPSOME 0x02 #define TRS_HARD_INTRQ 0x01 /* not emulated */ /* Control register (read(?)/write): * ---sdw-- * s = software reset * d = device enable * w = wait enable */ #define TRS_HARD_CONTROL 0xc1 #define TRS_HARD_SOFTWARE_RESET 0x10 #define TRS_HARD_DEVICE_ENABLE 0x08 #define TRS_HARD_WAIT_ENABLE 0x04 /* ID register (Model II only!) */ #define TRS_HARD_ID0 0xc2 #define TRS_HARD_ID1 0xc3 /* CTC channels (Model II only!) */ #define TRS_HARD_CTC0 0xc4 #define TRS_HARD_CTC1 0xc5 #define TRS_HARD_CTC2 0xc6 #define TRS_HARD_CTC3 0xc7 /* * WD1010 registers */ /* Data register (read/write) */ #define TRS_HARD_DATA 0xc8 /* Error register (read only): * bdin-atm * b = block marked bad * e = uncorrectable error in data * i = uncorrectable error in id (unused?) * n = id not found * - = unused * a = command aborted * t = track 0 not found * m = bad address mark */ #define TRS_HARD_ERROR (TRS_HARD_DATA+1) #define TRS_HARD_BBDERR 0x80 #define TRS_HARD_DATAERR 0x40 #define TRS_HARD_IDERR 0x20 /* unused? */ #define TRS_HARD_NFERR 0x10 #define TRS_HARD_MCRERR 0x08 /* unused */ #define TRS_HARD_ABRTERR 0x04 #define TRS_HARD_TRK0ERR 0x02 #define TRS_HARD_MARKERR 0x01 /* Write precompensation register (write only) */ /* Value *4 is the starting cylinder for write precomp */ #define TRS_HARD_PRECOMP (TRS_HARD_DATA+1) /* Sector count register (read/write) */ /* Used only for multiple sector accesses; otherwise ignored. */ /* Autodecrements when used. */ #define TRS_HARD_SECCNT (TRS_HARD_DATA+2) /* Sector number register (read/write) */ #define TRS_HARD_SECNUM (TRS_HARD_DATA+3) /* Cylinder low byte register (read/write) */ #define TRS_HARD_CYLLO (TRS_HARD_DATA+4) /* Cylinder high byte register (read/write) */ #define TRS_HARD_CYLHI (TRS_HARD_DATA+5) /* Size/drive/head register (read/write): * essddhhh * e = 0 if CRCs used; 1 if ECC used * ss = sector size; 00=256, 01=512, 10=1024, 11=128 * dd = drive * hhh = head */ #define TRS_HARD_SDH (TRS_HARD_DATA+6) #define TRS_HARD_ECCMASK 0x80 #define TRS_HARD_ECCSHIFT 7 #define TRS_HARD_SIZEMASK 0x60 #define TRS_HARD_SIZESHIFT 5 #define TRS_HARD_DRIVEMASK 0x18 #define TRS_HARD_DRIVESHIFT 3 #define TRS_HARD_MAXDRIVES 4 #define TRS_HARD_HEADMASK 0x07 #define TRS_HARD_HEADSHIFT 0 #define TRS_HARD_MAXHEADS 8 /* Status register (read only): * brwsdcie * b = busy * r = drive ready * w = write error * s = seek complete * d = data request * c = corrected ecc (reserved) * i = command in progress (=software reset required) * e = error */ #define TRS_HARD_STATUS (TRS_HARD_DATA+7) #define TRS_HARD_BUSY 0x80 #define TRS_HARD_READY 0x40 #define TRS_HARD_WRERR 0x20 #define TRS_HARD_SEEKDONE 0x10 #define TRS_HARD_DRQ 0x08 #define TRS_HARD_ECC 0x04 #define TRS_HARD_CIP 0x02 #define TRS_HARD_ERR 0x01 /* Command register (write only) */ #define TRS_HARD_COMMAND (TRS_HARD_DATA+7) /* * WD1010 commands */ #define TRS_HARD_CMDMASK 0xf0 /* Restore: * 0001rrrr * rrrr = step rate; 0000=35us, else rrrr*0.5ms */ #define TRS_HARD_RESTORE 0x10 /* Read sector: * 0010dm00 * d = 0 for interrupt on DRQ, 1 for interrupt at end (DMA style) * TRS-80 always uses programmed I/O, INTRQ not connected, I believe. * m = multiple sector flag (not emulated!) */ #define TRS_HARD_READ 0x20 #define TRS_HARD_DMA 0x08 #define TRS_HARD_MULTI 0x04 /* Write sector: * 00110m00 * m = multiple sector flag (not emulated!) */ #define TRS_HARD_WRITE 0x30 /* Verify sector (or "Scan ID"): * 01000000 */ #define TRS_HARD_VERIFY 0x40 /* Format track: * 01010000 */ #define TRS_HARD_FORMAT 0x50 /* Init (??): * 01100000 */ #define TRS_HARD_INIT 0x60 /* Seek to specified sector/head/cylinder: * 0111rrrr * rrrr = step rate; 0000=35us, else rrrr*0.5ms */ #define TRS_HARD_SEEK 0x70 xtrs-4.9d/trs_imp_exp.c000066400000000000000000000315221306603614600152370ustar00rootroot00000000000000/* Copyright (c) 1996, Timothy Mann */ /* $Id: trs_imp_exp.c,v 1.19 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* * trs_imp_exp.c * * Features to make transferring files into and out of the emulator * easier. */ #include #include #include #include #include #include #include #include #include #include "trs_imp_exp.h" #include "z80.h" #include "trs.h" #include "trs_disk.h" /* If the following option is set, potentially dangerous emulator traps will be blocked, including file writes to the host filesystem and shell command execution. */ int trs_emtsafe = 0; /* New emulator traps */ #define MAX_OPENDIR 32 DIR *dir[MAX_OPENDIR] = { NULL, }; typedef struct { int fd; int inuse; } OpenDisk; #define MAX_OPENDISK 32 OpenDisk od[MAX_OPENDISK]; void do_emt_system() { int res; if (trs_emtsafe) { error("potentially dangerous emulator trap blocked"); REG_A = EACCES; REG_F &= ~ZERO_MASK; return; } res = system((char *)mem_pointer(REG_HL, 0)); if (res == -1) { REG_A = errno; REG_F &= ~ZERO_MASK; } else { REG_A = 0; REG_F |= ZERO_MASK; } REG_BC = res; } void do_emt_mouse() { int x, y; unsigned int buttons, sens; switch (REG_B) { case 1: trs_get_mouse_pos(&x, &y, &buttons); REG_HL = x; REG_DE = y; REG_A = buttons; if (REG_A) { REG_F &= ~ZERO_MASK; } else { REG_F |= ZERO_MASK; } break; case 2: trs_set_mouse_pos(REG_HL, REG_DE); REG_A = 0; REG_F |= ZERO_MASK; break; case 3: trs_get_mouse_max(&x, &y, &sens); REG_HL = x; REG_DE = y; REG_A = sens; if (REG_A) { REG_F &= ~ZERO_MASK; } else { REG_F |= ZERO_MASK; } break; case 4: trs_set_mouse_max(REG_HL, REG_DE, REG_C); REG_A = 0; REG_F |= ZERO_MASK; break; case 5: REG_A = trs_get_mouse_type(); if (REG_A) { REG_F &= ~ZERO_MASK; } else { REG_F |= ZERO_MASK; } break; default: error("undefined emt_mouse function code"); break; } } void do_emt_getddir() { if (REG_HL + REG_BC > 0x10000 || REG_HL + strlen(trs_disk_dir) + 1 > REG_HL + REG_BC) { REG_A = EFAULT; REG_F &= ~ZERO_MASK; REG_BC = 0xFFFF; return; } strcpy((char *)mem_pointer(REG_HL, 1), trs_disk_dir); REG_A = 0; REG_F |= ZERO_MASK; REG_BC = strlen(trs_disk_dir); } void do_emt_setddir() { if (trs_emtsafe) { error("potentially dangerous emulator trap blocked"); REG_A = EACCES; REG_F &= ~ZERO_MASK; return; } trs_disk_dir = strdup((char *)mem_pointer(REG_HL, 0)); if (trs_disk_dir[0] == '~' && (trs_disk_dir[1] == '/' || trs_disk_dir[1] == '\0')) { char* home = getenv("HOME"); if (home) { char *p = (char*)malloc(strlen(home) + strlen(trs_disk_dir) + 2); sprintf(p, "%s/%s", home, trs_disk_dir+1); free(trs_disk_dir); trs_disk_dir = p; } } REG_A = 0; REG_F |= ZERO_MASK; } void do_emt_open() { int fd, oflag, eoflag; eoflag = REG_BC; switch (eoflag & EO_ACCMODE) { case EO_RDONLY: default: oflag = O_RDONLY; break; case EO_WRONLY: oflag = O_WRONLY; break; case EO_RDWR: oflag = O_RDWR; break; } if (eoflag & EO_CREAT) oflag |= O_CREAT; if (eoflag & EO_EXCL) oflag |= O_EXCL; if (eoflag & EO_TRUNC) oflag |= O_TRUNC; if (eoflag & EO_APPEND) oflag |= O_APPEND; if (trs_emtsafe && oflag != O_RDONLY) { error("potentially dangerous emulator trap blocked"); REG_A = EACCES; REG_F &= ~ZERO_MASK; return; } fd = open((char *)mem_pointer(REG_HL, 0), oflag, REG_DE); if (fd >= 0) { REG_A = 0; REG_F |= ZERO_MASK; } else { REG_A = errno; REG_F &= ~ZERO_MASK; } REG_DE = fd; } void do_emt_close() { int res; res = close(REG_DE); if (res >= 0) { REG_A = 0; REG_F |= ZERO_MASK; } else { REG_A = errno; REG_F &= ~ZERO_MASK; } } void do_emt_read() { int size; if (REG_HL + REG_BC > 0x10000) { REG_A = EFAULT; REG_F &= ~ZERO_MASK; REG_BC = 0xFFFF; return; } size = read(REG_DE, mem_pointer(REG_HL, 1), REG_BC); if (size >= 0) { REG_A = 0; REG_F |= ZERO_MASK; } else { REG_A = errno; REG_F &= ~ZERO_MASK; } REG_BC = size; } void do_emt_write() { int size; if (trs_emtsafe) { error("potentially dangerous emulator trap blocked"); REG_A = EACCES; REG_F &= ~ZERO_MASK; return; } if (REG_HL + REG_BC > 0x10000) { REG_A = EFAULT; REG_F &= ~ZERO_MASK; REG_BC = 0xFFFF; return; } size = write(REG_DE, mem_pointer(REG_HL, 0), REG_BC); if (size >= 0) { REG_A = 0; REG_F |= ZERO_MASK; } else { REG_A = errno; REG_F &= ~ZERO_MASK; } REG_BC = size; } void do_emt_lseek() { int i; off_t offset; if (REG_HL + 8 > 0x10000) { REG_A = EFAULT; REG_F &= ~ZERO_MASK; return; } offset = 0; for (i=0; i<8; i++) { offset = offset + (mem_read(REG_HL + i) << i*8); } offset = lseek(REG_DE, offset, REG_BC); if (offset != (off_t) -1) { REG_A = 0; REG_F |= ZERO_MASK; } else { REG_A = errno; REG_F &= ~ZERO_MASK; } for (i=REG_HL; i<8; i++) { mem_write(REG_HL + i, offset & 0xff); offset >>= 8; } } void do_emt_strerror() { char *msg; int size; if (REG_HL + REG_BC > 0x10000) { REG_A = EFAULT; REG_F &= ~ZERO_MASK; REG_BC = 0xFFFF; return; } errno = 0; msg = strerror(REG_A); size = strlen(msg); if (errno != 0) { REG_A = errno; REG_F &= ~ZERO_MASK; } else if (REG_BC < size + 2) { REG_A = ERANGE; REG_F &= ~ZERO_MASK; size = REG_BC - 1; } else { REG_A = 0; REG_F |= ZERO_MASK; } memcpy(mem_pointer(REG_HL, 1), msg, size); mem_write(REG_HL + size++, '\r'); mem_write(REG_HL + size, '\0'); if (errno == 0) { REG_BC = size; } else { REG_BC = 0xFFFF; } } void do_emt_time() { time_t now = time(0); if (REG_A == 1) { #if __alpha struct tm *loctm = localtime(&now); now += loctm->tm_gmtoff; #else struct tm loctm = *(localtime(&now)); struct tm gmtm = *(gmtime(&now)); int daydiff = loctm.tm_mday - gmtm.tm_mday; now += (loctm.tm_sec - gmtm.tm_sec) + (loctm.tm_min - gmtm.tm_min) * 60 + (loctm.tm_hour - gmtm.tm_hour) * 3600; switch (daydiff) { case 0: case 1: case -1: now += 24*3600 * daydiff; break; case 30: case 29: case 28: case 27: now -= 24*3600; break; case -30: case -29: case -28: case -27: now += 24*3600; break; default: error("trouble computing local time in emt_time"); } #endif } else if (REG_A != 0) { error("unsupported function code to emt_time"); } REG_BC = (now >> 16) & 0xffff; REG_DE = now & 0xffff; } void do_emt_opendir() { int i; for (i = 0; i < MAX_OPENDIR; i++) { if (dir[i] == NULL) break; } if (i == MAX_OPENDIR) { REG_DE = 0xffff; REG_A = EMFILE; return; } dir[i] = opendir((char *)mem_pointer(REG_HL, 0)); if (dir[i] == NULL) { REG_DE = 0xffff; REG_A = errno; REG_F &= ~ZERO_MASK; } else { REG_DE = i; REG_A = 0; REG_F |= ZERO_MASK; } } void do_emt_closedir() { int i = REG_DE; int ok; if (i < 0 || i >= MAX_OPENDIR || dir[i] == NULL) { REG_A = EBADF; REG_F &= ~ZERO_MASK; return; } ok = closedir(dir[i]); dir[i] = NULL; if (ok >= 0) { REG_A = 0; REG_F |= ZERO_MASK; } else { REG_A = errno; REG_F &= ~ZERO_MASK; } } void do_emt_readdir() { int size, i = REG_DE; struct dirent *result; if (i < 0 || i >= MAX_OPENDIR || dir[i] == NULL) { REG_A = EBADF; REG_F &= ~ZERO_MASK; REG_BC = 0xFFFF; return; } if (REG_HL + REG_BC > 0x10000) { REG_A = EFAULT; REG_F &= ~ZERO_MASK; REG_BC = 0xFFFF; return; } result = readdir(dir[i]); if (result == NULL) { REG_A = errno; REG_F &= ~ZERO_MASK; REG_BC = 0xFFFF; return; } size = strlen(result->d_name); if (size + 1 > REG_BC) { REG_A = ERANGE; REG_F &= ~ZERO_MASK; REG_BC = 0xFFFF; return; } strcpy((char *)mem_pointer(REG_HL, 1), result->d_name); REG_A = 0; REG_F |= ZERO_MASK; REG_BC = size; } void do_emt_chdir() { int ok; if (trs_emtsafe) { error("potentially dangerous emulator trap blocked"); REG_A = EACCES; REG_F &= ~ZERO_MASK; return; } ok = chdir((char *)mem_pointer(REG_HL, 0)); if (ok < 0) { REG_A = errno; REG_F &= ~ZERO_MASK; } else { REG_A = 0; REG_F |= ZERO_MASK; } } void do_emt_getcwd() { char *result; if (REG_HL + REG_BC > 0x10000) { REG_A = EFAULT; REG_F &= ~ZERO_MASK; REG_BC = 0xFFFF; return; } result = getcwd((char *)mem_pointer(REG_HL, 1), REG_BC); if (result == NULL) { REG_A = errno; REG_F &= ~ZERO_MASK; REG_BC = 0xFFFF; return; } REG_A = 0; REG_F |= ZERO_MASK; REG_BC = strlen(result); } void do_emt_misc() { switch (REG_A) { case 0: trs_disk_change_all(); REG_HL = trs_disk_changecount; break; case 1: trs_exit(); break; case 2: trs_debug(); break; case 3: trs_reset(0); break; case 4: REG_HL = trs_disk_changecount; break; case 5: REG_HL = trs_model; break; case 6: REG_HL = trs_disk_getsize(REG_BC); break; case 7: trs_disk_setsize(REG_BC, REG_HL); break; case 8: REG_HL = trs_disk_getstep(REG_BC); break; case 9: trs_disk_setstep(REG_BC, REG_HL); break; case 10: REG_HL = grafyx_get_microlabs(); break; case 11: grafyx_set_microlabs(REG_HL); break; case 12: REG_HL = z80_state.delay; REG_BC = trs_autodelay; break; case 13: z80_state.delay = REG_HL; trs_autodelay = REG_BC; break; case 14: REG_HL = stretch_amount; break; case 15: stretch_amount = REG_HL; break; case 16: REG_HL = trs_disk_doubler; break; case 17: trs_disk_doubler = REG_HL; break; case 18: REG_HL = sb_get_volume(); break; case 19: sb_set_volume(REG_HL); break; case 20: REG_HL = trs_disk_truedam; break; case 21: trs_disk_truedam = REG_HL; break; default: error("unsupported function code to emt_misc"); break; } } void do_emt_ftruncate() { int i, result; off_t offset; if (trs_emtsafe) { error("potentially dangerous emulator trap blocked"); REG_A = EACCES; REG_F &= ~ZERO_MASK; return; } if (REG_HL + 8 > 0x10000) { REG_A = EFAULT; REG_F &= ~ZERO_MASK; return; } offset = 0; for (i=0; i<8; i++) { offset = offset + (mem_read(REG_HL + i) << i*8); } result = ftruncate(REG_DE, offset); if (result == 0) { REG_A = 0; REG_F |= ZERO_MASK; } else { REG_A = errno; REG_F &= ~ZERO_MASK; } } void do_emt_opendisk() { char *name = (char *)mem_pointer(REG_HL, 0); char *qname; int i; int oflag, eoflag; eoflag = REG_BC; switch (eoflag & EO_ACCMODE) { case EO_RDONLY: default: oflag = O_RDONLY; break; case EO_WRONLY: oflag = O_WRONLY; break; case EO_RDWR: oflag = O_RDWR; break; } if (eoflag & EO_CREAT) oflag |= O_CREAT; if (eoflag & EO_EXCL) oflag |= O_EXCL; if (eoflag & EO_TRUNC) oflag |= O_TRUNC; if (eoflag & EO_APPEND) oflag |= O_APPEND; if (trs_emtsafe && oflag != O_RDONLY) { error("potentially dangerous emulator trap blocked"); REG_A = EACCES; REG_F &= ~ZERO_MASK; return; } if (*name == '/' || *trs_disk_dir == '\0') { qname = strdup(name); } else { qname = (char *)malloc(strlen(trs_disk_dir) + 1 + strlen(name) + 1); strcpy(qname, trs_disk_dir); strcat(qname, "/"); strcat(qname, name); } for (i = 0; i < MAX_OPENDISK; i++) { if (!od[i].inuse) break; } if (i == MAX_OPENDISK) { REG_DE = 0xffff; REG_A = EMFILE; REG_F &= ~ZERO_MASK; free(qname); return; } od[i].fd = open(qname, oflag, REG_DE); free(qname); if (od[i].fd >= 0) { od[i].inuse = 1; REG_A = 0; REG_F |= ZERO_MASK; } else { REG_A = errno; REG_F &= ~ZERO_MASK; } REG_DE = od[i].fd; } void do_emt_closedisk() { int i; int res; if (REG_DE == 0xffff) { for (i = 0; i < MAX_OPENDISK; i++) { if (od[i].inuse) { close(od[i].fd); od[i].inuse = 0; } } REG_A = 0; REG_F |= ZERO_MASK; return; } for (i = 0; i < MAX_OPENDISK; i++) { if (od[i].inuse && od[i].fd == REG_DE) break; } if (i == MAX_OPENDISK) { REG_A = EBADF; REG_F &= ~ZERO_MASK; return; } od[i].inuse = 0; res = close(od[i].fd); if (res >= 0) { REG_A = 0; REG_F |= ZERO_MASK; } else { REG_A = errno; REG_F &= ~ZERO_MASK; } } xtrs-4.9d/trs_imp_exp.h000066400000000000000000000237121306603614600152460ustar00rootroot00000000000000/* Copyright (c) 1996, Timothy Mann */ /* $Id: trs_imp_exp.h,v 1.16 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* * trs_imp_exp.h * * Features to make transferring files into and out of the emulator * (etc.) easier, using a set of emulator traps (instructions that * don't exist in a real Z-80). * * ED20-ED21 reserved; used by Jeff Vavasour Model III/4 emulator * * ED28 emt_system * Before, HL => shell command, null terminated * After, AF = 0 if OK, error number if not (Z flag affected) * BC = command exit status, normally 0 if OK * * ED29 emt_mouse * Implements Goben/Reed-style mouse driver in one instruction. * Documentation adapted from original Misosys Quarterly V.iii article. * (Notes: 1. The emt does not affect registers that do not have * documented return values. 2. Different versions of the native * drivers varied in whether coordinate values ranged from 0 to * XSIZE or 0 to XSIZE-1. This driver will return values up to * XSIZE if XSIZE is odd, up to XSIZE-1 if XSIZE is even, thus * finessing the issue. 3. The sensitivity value is ignored. 4. The * mouse is assumed to have 3 buttons. 5. The set operations always * return success.) * * GET MOUSE CURSOR POSITION * Before, B = 1 * After, HL = mouse cursor X value (0 to XSIZE-1) * DE = mouse cursor Y value (0 to YSIZE-1) * A = button status * Bit 0: Reset if right button pressed * Bit 1: Reset if middle button pressed (both buttons) * Bit 2: Reset if left button pressed * * SET MOUSE CURSOR POSITION * Before, B = 2 * HL = X value (0 - XSIZE-1) * DE = Y value (0 - YSIZE-1) * After, AF = Z flag set if operation was successful * * GET SENSITIVITY AND MAXIMUM VALUES * Before, B = 3 * After, HL = current X maximum (XSIZE) * DE = current Y maximum (YSIZE) * A = current sensitivity (0 - 3) * * SET SENSITIVITY AND MAXIMUM VALUES * Before, B = 4 * HL = new X maximum (XSIZE) * DE = new Y maximum (YSIZE) * C = sensitivity (0 - 3); 3 is most sensitive * After, AF = Z flag set if operation was successful * * GET MOUSE TYPE * Before, B = 5 * After, A = 0 if 2-button, 1 if 3-button * * ED2A emt_getddir * Get the value of the -diskdir command-line parameter. * Before, BC = nbytes * HL => buffer * After, AF = 0 if OK, error number if not (Z flag affected) * HL => same buffer, containing NUL-terminated pathname * BC = strlen(buffer), 0xFFFF if error * * ED2B emt_setddir * Change the value of the -diskdir command-line parameter. Does not * force a disk change; use emt_misc afterwards if you want one. * Before, HL => path, null terminated * After, AF = 0 if OK, error number if not (Z flag affected) * * ED2C-ED2E reserved * * ED2F emt_debug * Enter zbx, the xtrs debugger. * * ED30 emt_open * Before, HL => path, null terminated * BC = oflag (use EO_ values defined below) * DE = mode * After, AF = 0 if OK, error number if not (Z flag affected) * DE = fd, 0xFFFF if error * * ED31 emt_close * Before, DE = fd * After, AF = 0 if OK, error number if not (Z flag affected) * * ED32 emt_read * Before, BC = nbytes * DE = fd * HL => buffer * After, AF = 0 if OK, error number if not (Z flag affected) * BC = nbytes read, 0xFFFF if error * * ED33 emt_write * Before, BC = nbytes * DE = fd * HL => buffer * After, AF = 0 if OK, error number if not (Z flag affected) * BC = nbytes written, 0xFFFF if error * * ED34 emt_lseek * Before, BC = whence * DE = fd * HL => offset (8-byte little-endian integer) * After, AF = 0 if OK, error number if not (Z flag affected) * HL => location in file, 0xFFFFFFFF if error * * ED35 emt_strerror * Before, A = error number * HL => buffer for error string * BC = buffer size * After, AF = 0 if OK, new error number if not (Z flag affected) * HL => same buffer, containing \r\0-terminated error string * BC = strlen(buffer), 0xFFFF if error * * ED36 emt_time * Before, A = 0 for UTC (GMT), 1 for local time * After, BCDE= time in seconds since Jan 1, 1970 00:00:00 * * ED37 emt_opendir * Before, HL => path, null terminated * After, AF = 0 if OK, error number if not (Z flag affected) * DE = dirfd, 0xFFFF if error * * ED38 emt_closedir * Before, DE = dirfd * After, AF = 0 if OK, error number if not (Z flag affected) * * ED39 emt_readdir * Before, BC = nbytes * DE = dirfd * HL => buffer * After, AF = 0 if OK, error number if not (Z flag affected) * HL => same buffer, containing NUL-terminated filename * BC = strlen(buffer), 0xFFFF if error * * ED3A emt_chdir * Warning: Changing the working directory will change where the disk*-* * files are found on the next disk-change command, unless -diskdir has * been specified as an absolute pathname. * Before, HL => path, null terminated * After, AF = 0 if OK, error number if not (Z flag affected) * * ED3B emt_getcwd * Before, BC = nbytes * HL => buffer * After, AF = 0 if OK, error number if not (Z flag affected) * HL => same buffer, containing NUL-terminated pathname * BC = strlen(buffer), 0xFFFF if error * * ED3C emt_misc * Before, A = function code, other registers as listed * After, other registers as listed * * Function codes: * 0 = disk change * After, HL = disk change count (F7 presses + emt_misc 0 calls) * 1 = exit emulator * 2 = enter debugger (if active) * 3 = press reset button * 4 = query disk change count * After, HL = disk change count (F7 presses + emt_misc 0 calls) * 5 = query model * After, HL = model: 1, 3, 4, or 5 (=4P) * 6 = query disk size * Before, BC = unit number, 0-7 * After, HL = size, 5 or 8 * 7 = set disk size * Before, BC = unit number, 0-7 * HL = new size, 5 or 8 * 8 = query disk single/double step * Before, BC = unit number, 0-7 * After, HL = step, 1 or 2 * 9 = set disk single/double step * Before, BC = unit number, 0-7 * HL = new step, 1 or 2 * 10 = query graphics type * Before, HL = 0 Radio Shack, 1 Micro Labs * 11 = set graphics type * Before, HL = 0 Radio Shack, 1 Micro Labs * 12 = query delay * After, HL = delay * BC = autodelay flag (0 or 1) * 13 = set delay * Before, HL = new delay * BC = autodelay flag (0 or 1) * 14 = query keystretch * After, HL = amount (in T-states) * 15 = set keystretch * Before, HL = amount (in T-states) * 16 = query doubler * After, HL = 0 none, 1 Percom, 2 Tandy, 3 both * 17 = set doubler * Before, HL = 0 none, 1 Percom, 2 Tandy, 3 both * 18 = query SoundBlaster volume (obsolete) * After, HL = 0-100 * 19 = set SoundBlaster volume (obsolete) * Before, HL = 0-100 * 20 = query truedam flag * After, HL = 0 or 1 * 21 = set truedam flag * Before, HL = 0 or 1 * * ED3D emt_ftruncate * Before, DE = fd * HL => offset (8-byte little-endian integer) * After, AF = 0 if OK, error number if not (Z flag affected) * * ED3E emt_opendisk * Similar to emt_open, except that (1) the path, if not absolute, is * interpreted relative to -diskdir, (2) emt_closedisk must be * used in place of emt_close. * Before, HL => path, null terminated * BC = oflag (use EO_ values defined below) * DE = mode * After, AF = 0 if OK, error number if not (Z flag affected) * DE = fd, 0xFFFF if error * * ED3F emt_closedisk * Similar to emt_close, but pairs with emt_opendisk. * Before, DE = fd, or -1 to close all fds opened with emt_opendisk * After, AF = 0 if OK, error number if not (Z flag affected) * */ /* Minimal subset of standard O_ flags. We have to define our own for portability; the numeric values differ amongst Unix implementations. */ #define EO_ACCMODE 03 #define EO_RDONLY 00 #define EO_WRONLY 01 #define EO_RDWR 02 #define EO_CREAT 0100 #define EO_EXCL 0200 #define EO_TRUNC 01000 #define EO_APPEND 02000 extern void do_emt_system(); extern void do_emt_getddir(); extern void do_emt_setddir(); extern void do_emt_mouse(); extern void do_emt_open(); extern void do_emt_close(); extern void do_emt_read(); extern void do_emt_write(); extern void do_emt_lseek(); extern void do_emt_strerror(); extern void do_emt_time(); extern void do_emt_opendir(); extern void do_emt_closedir(); extern void do_emt_readdir(); extern void do_emt_chdir(); extern void do_emt_getcwd(); extern void do_emt_misc(); extern void do_emt_ftruncate(); extern void do_emt_opendisk(); extern void do_emt_closedisk(); xtrs-4.9d/trs_interrupt.c000066400000000000000000000325611306603614600156360ustar00rootroot00000000000000/* Copyright (c) 1996, Timothy Mann */ /* $Id: trs_interrupt.c,v 1.27 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* * Emulate interrupts */ #include "z80.h" #include "trs.h" #include #include #include #include /*#define IDEBUG 1*/ /*#define IDEBUG2 1*/ /* IRQs */ #define M1_TIMER_BIT 0x80 #define M1_DISK_BIT 0x40 #define M3_UART_ERR_BIT 0x40 #define M3_UART_RCV_BIT 0x20 #define M3_UART_SND_BIT 0x10 #define M3_IOBUS_BIT 0x80 /* not emulated */ #define M3_TIMER_BIT 0x04 #define M3_CASSFALL_BIT 0x02 #define M3_CASSRISE_BIT 0x01 static unsigned char interrupt_latch = 0; static unsigned char interrupt_mask = 0; /* NMIs (M3/4/4P only) */ #define M3_INTRQ_BIT 0x80 /* FDC chip INTRQ line */ #define M3_MOTOROFF_BIT 0x40 /* FDC motor timed out (stopped) */ #define M3_RESET_BIT 0x20 /* User pressed Reset button */ static unsigned char nmi_latch = 1; /* ?? One diagnostic program needs this */ static unsigned char nmi_mask = M3_RESET_BIT; #define TIMER_HZ_1 40 #define TIMER_HZ_3 30 #define TIMER_HZ_4 60 static int timer_hz; #define CLOCK_MHZ_1 1.77408 #define CLOCK_MHZ_3 2.02752 #define CLOCK_MHZ_4 4.05504 /* Kludge: LDOS hides the date (not time) in a memory area across reboots. */ /* We put it there on powerup, so LDOS magically knows the date! */ #define LDOS_MONTH 0x4306 #define LDOS_DAY 0x4307 #define LDOS_YEAR 0x4466 #define LDOS3_MONTH 0x442f #define LDOS3_DAY 0x4457 #define LDOS3_YEAR 0x4413 #define LDOS4_MONTH 0x0035 #define LDOS4_DAY 0x0034 #define LDOS4_YEAR 0x0033 /* Kludge, continued: On NEWDOS/80, both date and time are stored in memory across reboots, but a test is done on boot to decide whether to use the stored values. Here's how it works: NEWDOS/80 writes a special byte value to the memory address right before the stored date and time. On reboot, this address is checked, and if it contains that special byte, the stored date and time are considered valid and are therefore used. By putting this info in memory on powerup, NEWDOS/80 gets initialized with the system date and time. */ #define NEWDOS_DATETIME_VALID_BYTE 0xa5 // Model 1 #define NEWDOS_DATETIME_VALID_ADDR 0x43ab #define NEWDOS_MONTH 0x43b1 #define NEWDOS_DAY 0x43b0 #define NEWDOS_YEAR 0x43af #define NEWDOS_HOUR 0x43ae #define NEWDOS_MIN 0x43ad #define NEWDOS_SEC 0x43ac // Model 3 #define NEWDOS3_DATETIME_VALID_ADDR 0x42cb #define NEWDOS3_MONTH 0x42d1 #define NEWDOS3_DAY 0x42d0 #define NEWDOS3_YEAR 0x42cf #define NEWDOS3_HOUR 0x42ce #define NEWDOS3_MIN 0x42cd #define NEWDOS3_SEC 0x42cc static int timer_on = 1; #ifdef IDEBUG long lost_timer_interrupts = 0; #endif /* Note: the independent interrupt latch and mask model is not correct for all interrupts. The cassette rise/fall interrupt enable is clocked into the interrupt latch when the event occurs (we get this right), and is *not* masked against the latch output (we get this wrong, but it doesn't really matter). */ void trs_cassette_rise_interrupt(int dummy) { interrupt_latch = (interrupt_latch & ~M3_CASSRISE_BIT) | (interrupt_mask & M3_CASSRISE_BIT); z80_state.irq = (interrupt_latch & interrupt_mask) != 0; trs_cassette_update(0); } void trs_cassette_fall_interrupt(int dummy) { interrupt_latch = (interrupt_latch & ~M3_CASSFALL_BIT) | (interrupt_mask & M3_CASSFALL_BIT); z80_state.irq = (interrupt_latch & interrupt_mask) != 0; trs_cassette_update(0); } void trs_cassette_clear_interrupts() { interrupt_latch &= ~(M3_CASSRISE_BIT|M3_CASSFALL_BIT); z80_state.irq = (interrupt_latch & interrupt_mask) != 0; } int trs_cassette_interrupts_enabled() { return interrupt_mask & (M3_CASSRISE_BIT|M3_CASSFALL_BIT); } void trs_timer_interrupt(int state) { if (trs_model == 1) { if (state) { #ifdef IDEBUG if (interrupt_latch & M1_TIMER_BIT) lost_timer_interrupts++; #endif interrupt_latch |= M1_TIMER_BIT; z80_state.irq = 1; } else { interrupt_latch &= ~M1_TIMER_BIT; } } else { if (state) { #ifdef IDEBUG if (interrupt_latch & M3_TIMER_BIT) lost_timer_interrupts++; #endif interrupt_latch |= M3_TIMER_BIT; } else { interrupt_latch &= ~M3_TIMER_BIT; } z80_state.irq = (interrupt_latch & interrupt_mask) != 0; } } void trs_disk_intrq_interrupt(int state) { if (trs_model == 1) { if (state) { interrupt_latch |= M1_DISK_BIT; z80_state.irq = 1; } else { interrupt_latch &= ~M1_DISK_BIT; } } else { if (state) { nmi_latch |= M3_INTRQ_BIT; } else { nmi_latch &= ~M3_INTRQ_BIT; } z80_state.nmi = (nmi_latch & nmi_mask) != 0; if (!z80_state.nmi) z80_state.nmi_seen = 0; } } void trs_disk_motoroff_interrupt(int state) { /* Drive motor timed out (stopped). */ if (trs_model == 1) { /* no such interrupt */ } else { if (state) { nmi_latch |= M3_MOTOROFF_BIT; } else { nmi_latch &= ~M3_MOTOROFF_BIT; } z80_state.nmi = (nmi_latch & nmi_mask) != 0; if (!z80_state.nmi) z80_state.nmi_seen = 0; } } void trs_disk_drq_interrupt(int state) { /* no effect */ } void trs_uart_err_interrupt(int state) { if (trs_model > 1) { if (state) { interrupt_latch |= M3_UART_ERR_BIT; } else { interrupt_latch &= ~M3_UART_ERR_BIT; } z80_state.irq = (interrupt_latch & interrupt_mask) != 0; } } void trs_uart_rcv_interrupt(int state) { if (trs_model > 1) { if (state) { interrupt_latch |= M3_UART_RCV_BIT; } else { interrupt_latch &= ~M3_UART_RCV_BIT; } z80_state.irq = (interrupt_latch & interrupt_mask) != 0; } } void trs_uart_snd_interrupt(int state) { if (trs_model > 1) { if (state) { interrupt_latch |= M3_UART_SND_BIT; } else { interrupt_latch &= ~M3_UART_SND_BIT; } z80_state.irq = (interrupt_latch & interrupt_mask) != 0; } } void trs_reset_button_interrupt(int state) { if (trs_model == 1) { z80_state.nmi = state; } else { if (state) { nmi_latch |= M3_RESET_BIT; } else { nmi_latch &= ~M3_RESET_BIT; } z80_state.nmi = (nmi_latch & nmi_mask) != 0; } if (!z80_state.nmi) z80_state.nmi_seen = 0; } unsigned char trs_interrupt_latch_read() { unsigned char tmp = interrupt_latch; if (trs_model == 1) { trs_timer_interrupt(0); /* acknowledge this one (only) */ z80_state.irq = (interrupt_latch != 0); return tmp; } else { return ~tmp; } } void trs_interrupt_mask_write(unsigned char value) { interrupt_mask = value; z80_state.irq = (interrupt_latch & interrupt_mask) != 0; } /* M3 only */ unsigned char trs_nmi_latch_read() { return ~nmi_latch; } void trs_nmi_mask_write(unsigned char value) { nmi_mask = value | M3_RESET_BIT; z80_state.nmi = (nmi_latch & nmi_mask) != 0; #if IDEBUG2 if (z80_state.nmi && !z80_state.nmi_seen) { debug("mask write caused nmi, mask %02x latch %02x\n", nmi_mask, nmi_latch); } #endif if (!z80_state.nmi) z80_state.nmi_seen = 0; } static int saved_delay; /* Temporarily reduce the delay, until trs_restore_delay is called. Useful if we know we're about to do something that's emulated more slowly than most instructions, such as video or real-time sound. In case the boost is too big or too small, we allow the normal autodelay algorithm to continue to run and adjust the new delay. */ void trs_suspend_delay() { if (!saved_delay) { saved_delay = z80_state.delay; z80_state.delay /= 2; /* dividing by 2 is arbitrary */ } } /* Put back the saved delay */ void trs_restore_delay() { if (saved_delay) { z80_state.delay = saved_delay; saved_delay = 0; trs_paused = 1; } } #define UP_F 1.50 #define DOWN_F 0.50 void trs_timer_event(int signo) { struct timeval tv; struct itimerval it; gettimeofday(&tv, NULL); if (trs_autodelay) { static struct timeval oldtv; static int increment = 1; static int oldtoofast = 0; #if __GNUC__ static unsigned long long oldtcount; #else static unsigned long oldtcount; #endif if (!trs_paused /*&& !saved_delay*/) { int toofast = (z80_state.t_count - oldtcount) > ((tv.tv_sec*1000000 + tv.tv_usec) - (oldtv.tv_sec*1000000 + oldtv.tv_usec))*z80_state.clockMHz; if (toofast == oldtoofast) { increment = (int)(increment * UP_F + 0.5); } else { increment = (int)(increment * DOWN_F + 0.5); } oldtoofast = toofast; if (increment < 1) increment = 1; if (toofast) { z80_state.delay += increment; } else { z80_state.delay -= increment; if (z80_state.delay < 0) { z80_state.delay = 0; increment = 1; } } } trs_paused = 0; oldtv = tv; oldtcount = z80_state.t_count; } if (timer_on) { trs_timer_interrupt(1); /* generate */ trs_disk_motoroff_interrupt(trs_disk_motoroff()); trs_kb_heartbeat(); /* part of keyboard stretch kludge */ } x_poll_count = 0; /* be sure to flush and check for X events */ /* Schedule next tick. We do it this way because the host system probably didn't wake us up at exactly the right time. For instance, on Linux i386 the real clock ticks at 10ms, but we want to tick at 25ms. If we ask setitimer to wake us up in 25ms, it will really wake us up in 30ms. The algorithm below compensates for such an error by making the next tick shorter. */ it.it_value.tv_sec = 0; it.it_value.tv_usec = (1000000/timer_hz) - (tv.tv_usec % (1000000/timer_hz)); it.it_interval.tv_sec = 0; it.it_interval.tv_usec = 1000000/timer_hz; /* fail-safe */ setitimer(ITIMER_REAL, &it, NULL); } void trs_timer_init() { struct sigaction sa; struct tm *lt; time_t tt; if (trs_model == 1) { timer_hz = TIMER_HZ_1; z80_state.clockMHz = CLOCK_MHZ_1; } else { /* initially... */ timer_hz = TIMER_HZ_3; z80_state.clockMHz = CLOCK_MHZ_3; } sa.sa_handler = trs_timer_event; sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGALRM); sa.sa_flags = SA_RESTART; sigaction(SIGALRM, &sa, NULL); trs_timer_event(SIGALRM); /* Also initialize the clock in memory - hack */ tt = time(NULL); lt = localtime(&tt); if (trs_model == 1) { mem_write(LDOS_MONTH, (lt->tm_mon + 1) ^ 0x50); mem_write(LDOS_DAY, lt->tm_mday); mem_write(LDOS_YEAR, lt->tm_year - 80); mem_write(NEWDOS_DATETIME_VALID_ADDR, NEWDOS_DATETIME_VALID_BYTE); mem_write(NEWDOS_MONTH, lt->tm_mon + 1); mem_write(NEWDOS_DAY, lt->tm_mday); mem_write(NEWDOS_YEAR, lt->tm_year % 100); mem_write(NEWDOS_HOUR, lt->tm_hour); mem_write(NEWDOS_MIN, lt->tm_min); mem_write(NEWDOS_SEC, lt->tm_sec); } else { mem_write(LDOS3_MONTH, (lt->tm_mon + 1) ^ 0x50); mem_write(LDOS3_DAY, lt->tm_mday); mem_write(LDOS3_YEAR, lt->tm_year - 80); mem_write(NEWDOS3_DATETIME_VALID_ADDR, NEWDOS_DATETIME_VALID_BYTE); mem_write(NEWDOS3_MONTH, lt->tm_mon + 1); mem_write(NEWDOS3_DAY, lt->tm_mday); mem_write(NEWDOS3_YEAR, lt->tm_year % 100); mem_write(NEWDOS3_HOUR, lt->tm_hour); mem_write(NEWDOS3_MIN, lt->tm_min); mem_write(NEWDOS3_SEC, lt->tm_sec); if (trs_model >= 4) { extern Uchar memory[]; memory[LDOS4_MONTH] = lt->tm_mon + 1; memory[LDOS4_DAY] = lt->tm_mday; memory[LDOS4_YEAR] = lt->tm_year; } } } void trs_timer_off() { timer_on = 0; } void trs_timer_on() { if (!timer_on) { timer_on = 1; trs_timer_event(SIGALRM); } } void trs_timer_speed(int fast) { if (trs_model >= 4) { timer_hz = fast ? TIMER_HZ_4 : TIMER_HZ_3; z80_state.clockMHz = fast ? CLOCK_MHZ_4 : CLOCK_MHZ_3; } else if (trs_model == 1) { /* Typical 2x clock speedup kit */ z80_state.clockMHz = CLOCK_MHZ_1 * ((fast&1) + 1); } } static trs_event_func event_func = NULL; static int event_arg; /* Schedule an event to occur after "countdown" more t-states have * executed. 0 makes the event happen immediately -- that is, at * the end of the current instruction, but before the emulator checks * for interrupts. It is legal for an event function to call * trs_schedule_event. * * Only one event can be buffered. If you try to schedule a second * event while one is still pending, the pending event (along with * any further events that it schedules) is executed immediately. */ void trs_schedule_event(trs_event_func f, int arg, int countdown) { while (event_func) { #if EDEBUG error("warning: trying to schedule two events"); #endif trs_do_event(); } event_func = f; event_arg = arg; z80_state.sched = z80_state.t_count + (tstate_t) countdown; if (z80_state.sched == 0) z80_state.sched--; } /* * If an event is scheduled, do it now. (If the event function * schedules a new event, however, leave that one pending.) */ void trs_do_event() { trs_event_func f = event_func; if (f) { event_func = NULL; z80_state.sched = 0; f(event_arg); } } /* * Cancel scheduled event, if any. */ void trs_cancel_event() { event_func = NULL; z80_state.sched = 0; } /* * Check event scheduled */ trs_event_func trs_event_scheduled() { return event_func; } xtrs-4.9d/trs_io.c000066400000000000000000000264211306603614600142070ustar00rootroot00000000000000/* * Copyright (C) 1992 Clarendon Hill Software. * * Permission is granted to any individual or institution to use, copy, * or redistribute this software, provided this copyright notice is retained. * * This software is provided "as is" without any expressed or implied * warranty. If this software brings on any sort of damage -- physical, * monetary, emotional, or brain -- too bad. You've got no one to blame * but yourself. * * The software may be modified for your own purposes, but modified versions * must retain this notice. */ /* Modified by Timothy Mann, 1996 and following. $Id: trs_io.c,v 1.24 2009/06/15 23:40:18 mann Exp $ */ /*#define PORTDEBUG1 1*/ /*#define PORTDEBUG2 1*/ #include #include "z80.h" #include "trs.h" #include "trs_disk.h" #include "trs_hard.h" #include "trs_uart.h" static int modesel = 0; /* Model I */ static int modeimage = 0x8; /* Model III/4/4p */ static int ctrlimage = 0; /* Model 4/4p */ static int rominimage = 0; /* Model 4p */ /*ARGSUSED*/ void z80_out(int port, int value) { #if PORTDEBUG1 debug("out (0x%02x), 0x%02x; pc 0x%04x\n", port, value, z80_state.pc.word); #endif /* First, ports common to all models */ switch (port) { case TRS_HARD_WP: /* 0xC0 */ case TRS_HARD_CONTROL: /* 0xC1 */ case TRS_HARD_DATA: /* 0xC8 */ case TRS_HARD_ERROR: /* 0xC9 */ /*=TRS_HARD_PRECOMP*/ case TRS_HARD_SECCNT: /* 0xCA */ case TRS_HARD_SECNUM: /* 0xCB */ case TRS_HARD_CYLLO: /* 0xCC */ case TRS_HARD_CYLHI: /* 0xCD */ case TRS_HARD_SDH: /* 0xCE */ case TRS_HARD_STATUS: /* 0xCF */ /*=TRS_HARD_COMMAND*/ trs_hard_out(port, value); break; case TRS_UART_RESET: /* 0xE8 */ trs_uart_reset_out(value); break; case TRS_UART_BAUD: /* 0xE9 */ trs_uart_baud_out(value); break; case TRS_UART_CONTROL: /* 0xEA */ trs_uart_control_out(value); break; case TRS_UART_DATA: /* 0xEB */ trs_uart_data_out(value); break; } if (trs_model == 1) { /* Next, Model I only */ switch (port) { case 0x00: /* HRG off */ case 0x01: /* HRG on */ hrg_onoff(port); break; case 0x02: /* HRG write address low byte */ hrg_write_addr(value, 0xff); break; case 0x03: /* HRG write address high byte */ hrg_write_addr(value << 8, 0x3f00); break; case 0x05: /* HRG write data byte */ hrg_write_data(value); break; case 0xB9: /* Orchestra-85 left channel */ trs_orch90_out(1, value); break; case 0xB5: /* Orchestra-85 right channel */ trs_orch90_out(2, value); break; case 0xFD: /* GENIE location of printer port */ trs_printer_write(value); break; case 0xFE: /* Typical location for clock speedup kits */ trs_timer_speed(value); break; case 0xFF: /* screen mode select is on D3 line */ modesel = (value >> 3) & 1; trs_screen_expanded(modesel); /* do cassette emulation */ trs_cassette_motor((value >> 2) & 1); trs_cassette_out(value & 0x3); break; default: break; } } else { /* Next, Models III/4/4P only */ switch (port) { case 0x79: /* Orchestra-90 left channel */ trs_orch90_out(1, value); break; case 0x75: /* Orchestra-90 right channel */ trs_orch90_out(2, value); break; case 0x80: if (trs_model >= 3) grafyx_write_x(value); break; case 0x81: if (trs_model >= 3) grafyx_write_y(value); break; case 0x82: if (trs_model >= 3) grafyx_write_data(value); break; case 0x83: if (trs_model >= 3) grafyx_write_mode(value); break; case 0x84: case 0x85: case 0x86: case 0x87: if (trs_model >= 4) { int changes = value ^ ctrlimage; if (changes & 0x80) { mem_video_page((value & 0x80) >> 7); } if (changes & 0x70) { mem_bank((value & 0x70) >> 4); } if (changes & 0x08) { trs_screen_inverse((value & 0x08) >> 3); } if (changes & 0x04) { trs_screen_80x24((value & 0x04) >> 2); } if (changes & 0x03) { mem_map(value & 0x03); } ctrlimage = value; } break; case 0x8c: if (trs_model >= 4) grafyx_write_xoffset(value); break; case 0x8d: if (trs_model >= 4) grafyx_write_yoffset(value); break; case 0x8e: if (trs_model >= 4) grafyx_write_overlay(value); break; case 0x90: case 0x91: case 0x92: case 0x93: trs_sound_out(value & 1); break; case 0x9C: case 0x9D: /* !!? */ case 0x9E: /* !!? */ case 0x9F: /* !!? */ if (trs_model == 5 /*4p*/) { rominimage = value & 1; mem_romin(rominimage); } break; case 0xE0: trs_interrupt_mask_write(value); break; case TRSDISK3_INTERRUPT: /* 0xE4 */ case 0xE5: case 0xE6: case 0xE7: trs_nmi_mask_write(value); break; case 0xEC: case 0xED: case 0xEE: case 0xEF: modeimage = value; /* cassette motor is on D1 */ trs_cassette_motor((modeimage & 0x02) >> 1); /* screen mode select is on D2 */ trs_screen_expanded((modeimage & 0x04) >> 2); /* alternate char set is on D3 */ trs_screen_alternate(!((modeimage & 0x08) >> 3)); /* clock speed is on D6; it affects timer HZ too */ trs_timer_speed((modeimage & 0x40) >> 6); break; case TRSDISK3_COMMAND: /* 0xF0 */ trs_disk_command_write(value); break; case TRSDISK3_TRACK: /* 0xF1 */ trs_disk_track_write(value); break; case TRSDISK3_SECTOR: /* 0xF2 */ trs_disk_sector_write(value); break; case TRSDISK3_DATA: /* 0xF3 */ trs_disk_data_write(value); break; case TRSDISK3_SELECT: /* 0xF4 */ case 0xF5: case 0xF6: case 0xF7: trs_disk_select_write(value); break; case 0xF8: case 0xF9: case 0xFA: case 0xFB: trs_printer_write(value); break; case 0xFC: case 0xFD: case 0xFE: case 0xFF: if (trs_model == 3 && (value & 0x20) && grafyx_get_microlabs()) { /* do Model III Micro Labs graphics card */ grafyx_m3_write_mode(value); } else { /* do cassette emulation */ trs_cassette_out(value & 3); } break; default: break; } } return; } /*ARGSUSED*/ int z80_in(int port) { /* First, ports common to all models */ #if PORTDEBUG2 debug("in (0x%02x); pc %04x\n", port, z80_state.pc.word); #endif /* Support for a special HW real-time clock (TimeDate80?) * I used to have. It was a small card-edge unit with a * battery that held the time/date with power off. * - Joe Peterson (joe@skyrush.com) * * According to the LDOS Quarterly 1-6, TChron1, TRSWatch, and * TimeDate80 are accessible at high ports 0xB0-0xBC, while * T-Timer is accessible at high ports 0xC0-0xCC. It does * not say where the low ports were; Joe's code had 0x70-0x7C, * so I presume that's correct at least for the TimeDate80. * Note: 0xC0-0xCC conflicts with Radio Shack hard disk, so * clock access at these ports is disabled starting in xtrs 4.1. * * These devices were based on the MSM5832 chip, which returns only * a 2-digit year. It's not clear what software will do with the * date in years beyond 1999. */ if ((port >= 0x70 && port <= 0x7C) || (port >= 0xB0 && port <= 0xBC) /*|| (port >= 0xC0 && port <= 0xCC)*/) { struct tm *time_info; time_t time_secs; time_secs = time(NULL); time_info = localtime(&time_secs); switch (port & 0x0F) { case 0xC: /* year (high) */ return (time_info->tm_year / 10) % 10; case 0xB: /* year (low) */ return (time_info->tm_year % 10); case 0xA: /* month (high) */ return ((time_info->tm_mon + 1) / 10); case 0x9: /* month (low) */ return ((time_info->tm_mon + 1) % 10); case 0x8: /* date (high) and leap year (bit 2) */ return ((time_info->tm_mday / 10) | ((time_info->tm_year % 4) ? 0 : 4)); case 0x7: /* date (low) */ return (time_info->tm_mday % 10); case 0x6: /* day-of-week */ return time_info->tm_wday; case 0x5: /* hours (high) and PM (bit 2) and 24hr (bit 3) */ return ((time_info->tm_hour / 10) | 8); case 0x4: /* hours (low) */ return (time_info->tm_hour % 10); case 0x3: /* minutes (high) */ return (time_info->tm_min / 10); case 0x2: /* minutes (low) */ return (time_info->tm_min % 10); case 0x1: /* seconds (high) */ return (time_info->tm_sec / 10); case 0x0: /* seconds (low) */ return (time_info->tm_sec % 10); } } switch (port) { case 0x00: return trs_joystick_in(); case TRS_HARD_WP: /* 0xC0 */ case TRS_HARD_CONTROL: /* 0xC1 */ case TRS_HARD_DATA: /* 0xC8 */ case TRS_HARD_ERROR: /* 0xC9 */ /*=TRS_HARD_PRECOMP*/ case TRS_HARD_SECCNT: /* 0xCA */ case TRS_HARD_SECNUM: /* 0xCB */ case TRS_HARD_CYLLO: /* 0xCC */ case TRS_HARD_CYLHI: /* 0xCD */ case TRS_HARD_SDH: /* 0xCE */ case TRS_HARD_STATUS: /* 0xCF */ /*=TRS_HARD_COMMAND*/ return trs_hard_in(port); case TRS_UART_MODEM: /* 0xE8 */ return trs_uart_modem_in(); case TRS_UART_SWITCHES: /* 0xE9 */ return trs_uart_switches_in(); case TRS_UART_STATUS: /* 0xEA */ return trs_uart_status_in(); case TRS_UART_DATA: /* 0xEB */ return trs_uart_data_in(); default: break; } if (trs_model == 1) { /* Model I only */ switch (port) { #if 0 // Conflicts with joystick port case 0x00: /* HRG off (undocumented) */ #endif case 0x01: /* HRG on (undocumented) */ hrg_onoff(port); break; case 0x04: /* HRG read data byte */ return hrg_read_data(); case 0xFD: /* GENIE location of printer port */ return trs_printer_read(); case 0xFF: return (modesel ? 0x7f : 0x3f) | trs_cassette_in(); default: break; } } else { /* Models III/4/4P only */ switch (port) { case 0x82: if (trs_model >= 3) { return grafyx_read_data(); } break; case 0x9C: /* !!? */ case 0x9D: /* !!? */ case 0x9E: /* !!? */ case 0x9F: /* !!? */ if (trs_model == 5 /*4p*/) { return rominimage; } break; case TRS_HARD_WP: /* 0xC0 */ case TRS_HARD_CONTROL: /* 0xC1 */ case TRS_HARD_DATA: /* 0xC8 */ case TRS_HARD_ERROR: /* 0xC9 */ /*=TRS_HARD_PRECOMP*/ case TRS_HARD_SECCNT: /* 0xCA */ case TRS_HARD_SECNUM: /* 0xCB */ case TRS_HARD_CYLLO: /* 0xCC */ case TRS_HARD_CYLHI: /* 0xCD */ case TRS_HARD_SDH: /* 0xCE */ case TRS_HARD_STATUS: /* 0xCF */ /*=TRS_HARD_COMMAND*/ return trs_hard_in(port); break; case 0xE0: return trs_interrupt_latch_read(); case 0xEC: case 0xED: case 0xEE: case 0xEF: trs_timer_interrupt(0); /* acknowledge */ return 0xFF; case TRSDISK3_INTERRUPT: /* 0xE4 */ return trs_nmi_latch_read(); case TRSDISK3_STATUS: /* 0xF0 */ return trs_disk_status_read(); case TRSDISK3_TRACK: /* 0xF1 */ return trs_disk_track_read(); case TRSDISK3_SECTOR: /* 0xF2 */ return trs_disk_sector_read(); case TRSDISK3_DATA: /* 0xF3 */ return trs_disk_data_read(); case 0xF8: return trs_printer_read(); case 0xFF: return (modeimage & 0x7e) | trs_cassette_in(); default: break; } } /* other ports -- unmapped */ return 0xFF; } xtrs-4.9d/trs_iodefs.h000066400000000000000000000013741306603614600150560ustar00rootroot00000000000000/* * Copyright (C) 1992 Clarendon Hill Software. * * Permission is granted to any individual or institution to use, copy, * or redistribute this software, provided this copyright notice is retained. * * This software is provided "as is" without any expressed or implied * warranty. If this software brings on any sort of damage -- physical, * monetary, emotional, or brain -- too bad. You've got no one to blame * but yourself. * * The software may be modified for your own purposes, but modified versions * must retain this notice. */ /* Modified by Timothy Mann, 1996 and later $Id: trs_iodefs.h,v 1.6 2008/06/26 04:39:56 mann Exp $ */ #define MAXCHARS 256 #define TRS_CHAR_WIDTH 8 #define TRS_CHAR_HEIGHT 12 #define TRS_CHAR_HEIGHT4 10 xtrs-4.9d/trs_keyboard.c000066400000000000000000001161311306603614600153760ustar00rootroot00000000000000/* * Copyright (C) 1992 Clarendon Hill Software. * * Permission is granted to any individual or institution to use, copy, * or redistribute this software, provided this copyright notice is retained. * * This software is provided "as is" without any expressed or implied * warranty. If this software brings on any sort of damage -- physical, * monetary, emotional, or brain -- too bad. You've got no one to blame * but yourself. * * The software may be modified for your own purposes, but modified versions * must retain this notice. */ /* Modified by Timothy Mann, 1996 and later $Id: trs_keyboard.c,v 1.27 2009/06/15 23:41:21 mann Exp $ */ /*#define KBDEBUG 1*/ /*#define JOYDEBUG 1*/ #define KP_JOYSTICK 1 /* emulate joystick with keypad */ /*#define KPNUM_JOYSTICK 1*/ /* emulate joystick with keypad + NumLock */ #define SHIFT_F1_IS_F13 1 /* use if X reports Shift+F1..F8 as F13..F20 */ /*#define SHIFT_F1_IS_F11 1*/ /* use if X reports Shift+F1..F10 as F11..F20 */ #include "z80.h" #include "trs.h" #include #include #include /* * Key event queue */ #define KEY_QUEUE_SIZE (32) static int key_queue[KEY_QUEUE_SIZE]; static int key_queue_head; static int key_queue_entries; static int skip_next_kbwait; /* * TRS-80 key matrix */ #define TK(a, b) (((a)<<4)+(b)) #define TK_ADDR(tk) (((tk) >> 4)&0xf) #define TK_DATA(tk) ((tk)&0xf) #define TK_DOWN(tk) (((tk)&0x10000) == 0) #define TK_AtSign TK(0, 0) /* @ */ #define TK_A TK(0, 1) #define TK_B TK(0, 2) #define TK_C TK(0, 3) #define TK_D TK(0, 4) #define TK_E TK(0, 5) #define TK_F TK(0, 6) #define TK_G TK(0, 7) #define TK_H TK(1, 0) #define TK_I TK(1, 1) #define TK_J TK(1, 2) #define TK_K TK(1, 3) #define TK_L TK(1, 4) #define TK_M TK(1, 5) #define TK_N TK(1, 6) #define TK_O TK(1, 7) #define TK_P TK(2, 0) #define TK_Q TK(2, 1) #define TK_R TK(2, 2) #define TK_S TK(2, 3) #define TK_T TK(2, 4) #define TK_U TK(2, 5) #define TK_V TK(2, 6) #define TK_W TK(2, 7) #define TK_X TK(3, 0) #define TK_Y TK(3, 1) #define TK_Z TK(3, 2) #define TK_LeftBracket TK(3, 3) /* [ { */ /* not really on keyboard */ #define TK_Backslash TK(3, 4) /* \ | */ /* not really on keyboard */ #define TK_RightBracket TK(3, 5) /* ] } */ /* not really on keyboard */ #define TK_Caret TK(3, 6) /* ^ ~ */ /* not really on keyboard */ #define TK_Underscore TK(3, 7) /* _ */ /* not really on keyboard */ #define TK_0 TK(4, 0) /* 0 */ #define TK_1 TK(4, 1) /* 1 ! */ #define TK_2 TK(4, 2) /* 2 " */ #define TK_3 TK(4, 3) /* 3 # */ #define TK_4 TK(4, 4) /* 4 $ */ #define TK_5 TK(4, 5) /* 5 % */ #define TK_6 TK(4, 6) /* 6 & */ #define TK_7 TK(4, 7) /* 7 ' */ #define TK_8 TK(5, 0) /* 8 ( */ #define TK_9 TK(5, 1) /* 9 ) */ #define TK_Colon TK(5, 2) /* : * */ #define TK_Semicolon TK(5, 3) /* ; + */ #define TK_Comma TK(5, 4) /* , < */ #define TK_Minus TK(5, 5) /* - = */ #define TK_Period TK(5, 6) /* . > */ #define TK_Slash TK(5, 7) /* / ? */ #define TK_Enter TK(6, 0) #define TK_Clear TK(6, 1) #define TK_Break TK(6, 2) #define TK_Up TK(6, 3) #define TK_Down TK(6, 4) #define TK_Left TK(6, 5) #define TK_Right TK(6, 6) #define TK_Space TK(6, 7) #define TK_LeftShift TK(7, 0) #define TK_RightShift TK(7, 1) /* M3/4 only; both shifts are 7, 0 on M1 */ #define TK_Ctrl TK(7, 2) /* M4 only */ #define TK_CapsLock TK(7, 3) /* M4 only */ #define TK_F1 TK(7, 4) /* M4 only */ #define TK_F2 TK(7, 5) /* M4 only */ #define TK_F3 TK(7, 6) /* M4 only */ #define TK_Unused TK(7, 7) /* Fake keycodes with special meanings */ #define TK_NULL TK(8, 0) #define TK_Neutral TK(8, 1) #define TK_ForceShift TK(8, 2) #define TK_ForceNoShift TK(8, 3) #define TK_ForceShiftPersistent TK(8, 4) #define TK_AllKeysUp TK(8, 5) #define TK_Joystick TK(10, 0) #define TK_North TK(10, 1) #define TK_Northeast TK(10, 9) #define TK_East TK(10, 8) #define TK_Southeast TK(10, 10) #define TK_South TK(10, 2) #define TK_Southwest TK(10, 5) #define TK_West TK(10, 4) #define TK_Northwest TK(10, 6) #define TK_Fire TK(10, 16) typedef struct { int bit_action; int shift_action; } KeyTable; /* Keysyms in the extended ASCII range 0x0000 - 0x00ff */ KeyTable ascii_key_table[] = { /* 0x0 */ { TK_NULL, TK_Neutral }, /* undefined keysyms... */ /* 0x1 */ { TK_NULL, TK_Neutral }, /* 0x2 */ { TK_NULL, TK_Neutral }, /* 0x3 */ { TK_NULL, TK_Neutral }, /* 0x4 */ { TK_NULL, TK_Neutral }, /* 0x5 */ { TK_NULL, TK_Neutral }, /* 0x6 */ { TK_NULL, TK_Neutral }, /* 0x7 */ { TK_NULL, TK_Neutral }, /* 0x8 */ { TK_NULL, TK_Neutral }, /* 0x9 */ { TK_NULL, TK_Neutral }, /* 0xa */ { TK_NULL, TK_Neutral }, /* 0xb */ { TK_NULL, TK_Neutral }, /* 0xc */ { TK_NULL, TK_Neutral }, /* 0xd */ { TK_NULL, TK_Neutral }, /* 0xe */ { TK_NULL, TK_Neutral }, /* 0xf */ { TK_NULL, TK_Neutral }, /* 0x10 */ { TK_NULL, TK_Neutral }, /* 0x11 */ { TK_NULL, TK_Neutral }, /* 0x12 */ { TK_NULL, TK_Neutral }, /* 0x13 */ { TK_NULL, TK_Neutral }, /* 0x14 */ { TK_NULL, TK_Neutral }, /* 0x15 */ { TK_NULL, TK_Neutral }, /* 0x16 */ { TK_NULL, TK_Neutral }, /* 0x17 */ { TK_NULL, TK_Neutral }, /* 0x18 */ { TK_NULL, TK_Neutral }, /* 0x19 */ { TK_NULL, TK_Neutral }, /* 0x1a */ { TK_NULL, TK_Neutral }, /* 0x1b */ { TK_NULL, TK_Neutral }, /* 0x1c */ { TK_NULL, TK_Neutral }, /* 0x1d */ { TK_NULL, TK_Neutral }, /* 0x1e */ { TK_NULL, TK_Neutral }, /* 0x1f */ { TK_NULL, TK_Neutral }, /* ...end undefined keysyms */ /* 0x20 */ { TK_Space, TK_Neutral }, /* 0x21 */ { TK_1, TK_ForceShift }, /* 0x22 */ { TK_2, TK_ForceShift }, /* 0x23 */ { TK_3, TK_ForceShift }, /* 0x24 */ { TK_4, TK_ForceShift }, /* 0x25 */ { TK_5, TK_ForceShift }, /* 0x26 */ { TK_6, TK_ForceShift }, /* 0x27 */ { TK_7, TK_ForceShift }, /* 0x28 */ { TK_8, TK_ForceShift }, /* 0x29 */ { TK_9, TK_ForceShift }, /* 0x2a */ { TK_Colon, TK_ForceShift }, /* 0x2b */ { TK_Semicolon, TK_ForceShift }, /* 0x2c */ { TK_Comma, TK_ForceNoShift }, /* 0x2d */ { TK_Minus, TK_ForceNoShift }, /* 0x2e */ { TK_Period, TK_ForceNoShift }, /* 0x2f */ { TK_Slash, TK_ForceNoShift }, /* 0x30 */ { TK_0, TK_ForceNoShift }, /* 0x31 */ { TK_1, TK_ForceNoShift }, /* 0x32 */ { TK_2, TK_ForceNoShift }, /* 0x33 */ { TK_3, TK_ForceNoShift }, /* 0x34 */ { TK_4, TK_ForceNoShift }, /* 0x35 */ { TK_5, TK_ForceNoShift }, /* 0x36 */ { TK_6, TK_ForceNoShift }, /* 0x37 */ { TK_7, TK_ForceNoShift }, /* 0x38 */ { TK_8, TK_ForceNoShift }, /* 0x39 */ { TK_9, TK_ForceNoShift }, /* 0x3a */ { TK_Colon, TK_ForceNoShift }, /* 0x3b */ { TK_Semicolon, TK_ForceNoShift }, /* 0x3c */ { TK_Comma, TK_ForceShift }, /* 0x3d */ { TK_Minus, TK_ForceShift }, /* 0x3e */ { TK_Period, TK_ForceShift }, /* 0x3f */ { TK_Slash, TK_ForceShift }, /* 0x40 */ { TK_AtSign, TK_ForceNoShift }, /* 0x41 */ { TK_A, TK_ForceShift }, /* 0x42 */ { TK_B, TK_ForceShift }, /* 0x43 */ { TK_C, TK_ForceShift }, /* 0x44 */ { TK_D, TK_ForceShift }, /* 0x45 */ { TK_E, TK_ForceShift }, /* 0x46 */ { TK_F, TK_ForceShift }, /* 0x47 */ { TK_G, TK_ForceShift }, /* 0x48 */ { TK_H, TK_ForceShift }, /* 0x49 */ { TK_I, TK_ForceShift }, /* 0x4a */ { TK_J, TK_ForceShift }, /* 0x4b */ { TK_K, TK_ForceShift }, /* 0x4c */ { TK_L, TK_ForceShift }, /* 0x4d */ { TK_M, TK_ForceShift }, /* 0x4e */ { TK_N, TK_ForceShift }, /* 0x4f */ { TK_O, TK_ForceShift }, /* 0x50 */ { TK_P, TK_ForceShift }, /* 0x51 */ { TK_Q, TK_ForceShift }, /* 0x52 */ { TK_R, TK_ForceShift }, /* 0x53 */ { TK_S, TK_ForceShift }, /* 0x54 */ { TK_T, TK_ForceShift }, /* 0x55 */ { TK_U, TK_ForceShift }, /* 0x56 */ { TK_V, TK_ForceShift }, /* 0x57 */ { TK_W, TK_ForceShift }, /* 0x58 */ { TK_X, TK_ForceShift }, /* 0x59 */ { TK_Y, TK_ForceShift }, /* 0x5a */ { TK_Z, TK_ForceShift }, /* 0x5b */ { TK_LeftBracket, TK_ForceNoShift }, /* 0x5c */ { TK_Backslash, TK_ForceNoShift }, /* 0x5d */ { TK_RightBracket, TK_ForceNoShift }, /* 0x5e */ { TK_Caret, TK_ForceNoShift }, /* 0x5f */ { TK_Underscore, TK_ForceNoShift }, /* 0x60 */ { TK_AtSign, TK_ForceShift }, /* 0x61 */ { TK_A, TK_ForceNoShift }, /* 0x62 */ { TK_B, TK_ForceNoShift }, /* 0x63 */ { TK_C, TK_ForceNoShift }, /* 0x64 */ { TK_D, TK_ForceNoShift }, /* 0x65 */ { TK_E, TK_ForceNoShift }, /* 0x66 */ { TK_F, TK_ForceNoShift }, /* 0x67 */ { TK_G, TK_ForceNoShift }, /* 0x68 */ { TK_H, TK_ForceNoShift }, /* 0x69 */ { TK_I, TK_ForceNoShift }, /* 0x6a */ { TK_J, TK_ForceNoShift }, /* 0x6b */ { TK_K, TK_ForceNoShift }, /* 0x6c */ { TK_L, TK_ForceNoShift }, /* 0x6d */ { TK_M, TK_ForceNoShift }, /* 0x6e */ { TK_N, TK_ForceNoShift }, /* 0x6f */ { TK_O, TK_ForceNoShift }, /* 0x70 */ { TK_P, TK_ForceNoShift }, /* 0x71 */ { TK_Q, TK_ForceNoShift }, /* 0x72 */ { TK_R, TK_ForceNoShift }, /* 0x73 */ { TK_S, TK_ForceNoShift }, /* 0x74 */ { TK_T, TK_ForceNoShift }, /* 0x75 */ { TK_U, TK_ForceNoShift }, /* 0x76 */ { TK_V, TK_ForceNoShift }, /* 0x77 */ { TK_W, TK_ForceNoShift }, /* 0x78 */ { TK_X, TK_ForceNoShift }, /* 0x79 */ { TK_Y, TK_ForceNoShift }, /* 0x7a */ { TK_Z, TK_ForceNoShift }, /* 0x7b */ { TK_LeftBracket, TK_ForceShift }, /* 0x7c */ { TK_Backslash, TK_ForceShift }, /* 0x7d */ { TK_RightBracket, TK_ForceShift }, /* 0x7e */ { TK_Caret, TK_ForceShift }, /* 0x7f */ { TK_NULL, TK_Neutral }, /* 0x80 */ { TK_NULL, TK_Neutral }, /* 0x81 */ { TK_NULL, TK_Neutral }, /* 0x82 */ { TK_NULL, TK_Neutral }, /* 0x83 */ { TK_NULL, TK_Neutral }, /* 0x84 */ { TK_NULL, TK_Neutral }, /* 0x85 */ { TK_NULL, TK_Neutral }, /* 0x86 */ { TK_NULL, TK_Neutral }, /* 0x87 */ { TK_NULL, TK_Neutral }, /* 0x88 */ { TK_NULL, TK_Neutral }, /* 0x89 */ { TK_NULL, TK_Neutral }, /* 0x8a */ { TK_NULL, TK_Neutral }, /* 0x8b */ { TK_NULL, TK_Neutral }, /* 0x8c */ { TK_NULL, TK_Neutral }, /* 0x8d */ { TK_NULL, TK_Neutral }, /* 0x8e */ { TK_NULL, TK_Neutral }, /* 0x8f */ { TK_NULL, TK_Neutral }, /* 0x90 */ { TK_NULL, TK_Neutral }, /* 0x91 */ { TK_NULL, TK_Neutral }, /* 0x92 */ { TK_NULL, TK_Neutral }, /* 0x93 */ { TK_NULL, TK_Neutral }, /* 0x94 */ { TK_NULL, TK_Neutral }, /* 0x95 */ { TK_NULL, TK_Neutral }, /* 0x96 */ { TK_NULL, TK_Neutral }, /* 0x97 */ { TK_NULL, TK_Neutral }, /* 0x98 */ { TK_NULL, TK_Neutral }, /* 0x99 */ { TK_NULL, TK_Neutral }, /* 0x9a */ { TK_NULL, TK_Neutral }, /* 0x9b */ { TK_NULL, TK_Neutral }, /* 0x9c */ { TK_NULL, TK_Neutral }, /* 0x9d */ { TK_NULL, TK_Neutral }, /* 0x9e */ { TK_NULL, TK_Neutral }, /* 0x9f */ { TK_NULL, TK_Neutral }, /* 0xa0 */ { TK_NULL, TK_Neutral }, /* 0xa1 */ { TK_NULL, TK_Neutral }, /* 0xa2 */ { TK_NULL, TK_Neutral }, /* 0xa3 */ { TK_NULL, TK_Neutral }, /* 0xa4 */ { TK_NULL, TK_Neutral }, /* 0xa5 */ { TK_NULL, TK_Neutral }, /* 0xa6 */ { TK_NULL, TK_Neutral }, /* 0xa7 */ { TK_NULL, TK_Neutral }, /* 0xa8 */ { TK_NULL, TK_Neutral }, /* 0xa9 */ { TK_NULL, TK_Neutral }, /* 0xaa */ { TK_NULL, TK_Neutral }, /* 0xab */ { TK_NULL, TK_Neutral }, /* 0xac */ { TK_NULL, TK_Neutral }, /* 0xad */ { TK_NULL, TK_Neutral }, /* 0xae */ { TK_NULL, TK_Neutral }, /* 0xaf */ { TK_NULL, TK_Neutral }, /* 0xb0 */ { TK_NULL, TK_Neutral }, /* 0xb1 */ { TK_NULL, TK_Neutral }, /* 0xb2 */ { TK_NULL, TK_Neutral }, /* 0xb3 */ { TK_NULL, TK_Neutral }, /* 0xb4 */ { TK_NULL, TK_Neutral }, /* 0xb5 */ { TK_NULL, TK_Neutral }, /* 0xb6 */ { TK_NULL, TK_Neutral }, /* 0xb7 */ { TK_NULL, TK_Neutral }, /* 0xb8 */ { TK_NULL, TK_Neutral }, /* 0xb9 */ { TK_NULL, TK_Neutral }, /* 0xba */ { TK_NULL, TK_Neutral }, /* 0xbb */ { TK_NULL, TK_Neutral }, /* 0xbc */ { TK_NULL, TK_Neutral }, /* 0xbd */ { TK_NULL, TK_Neutral }, /* 0xbe */ { TK_NULL, TK_Neutral }, /* 0xbf */ { TK_NULL, TK_Neutral }, /* 0xc0 */ { TK_NULL, TK_Neutral }, /* 0xc1 */ { TK_NULL, TK_Neutral }, /* 0xc2 */ { TK_NULL, TK_Neutral }, /* 0xc3 */ { TK_NULL, TK_Neutral }, /* 0xc4 */ { TK_LeftBracket, TK_ForceShift }, /* Ä */ /* 0xc5 */ { TK_NULL, TK_Neutral }, /* 0xc6 */ { TK_NULL, TK_Neutral }, /* 0xc7 */ { TK_NULL, TK_Neutral }, /* 0xc8 */ { TK_NULL, TK_Neutral }, /* 0xc9 */ { TK_NULL, TK_Neutral }, /* 0xca */ { TK_NULL, TK_Neutral }, /* 0xcb */ { TK_NULL, TK_Neutral }, /* 0xcc */ { TK_NULL, TK_Neutral }, /* 0xcd */ { TK_NULL, TK_Neutral }, /* 0xce */ { TK_NULL, TK_Neutral }, /* 0xcf */ { TK_NULL, TK_Neutral }, /* 0xd0 */ { TK_NULL, TK_Neutral }, /* 0xd1 */ { TK_NULL, TK_Neutral }, /* 0xd2 */ { TK_NULL, TK_Neutral }, /* 0xd3 */ { TK_NULL, TK_Neutral }, /* 0xd4 */ { TK_NULL, TK_Neutral }, /* 0xd5 */ { TK_NULL, TK_Neutral }, /* 0xd6 */ { TK_Backslash, TK_ForceShift }, /* Ö */ /* 0xd7 */ { TK_NULL, TK_Neutral }, /* 0xd8 */ { TK_NULL, TK_Neutral }, /* 0xd9 */ { TK_NULL, TK_Neutral }, /* 0xda */ { TK_NULL, TK_Neutral }, /* 0xdb */ { TK_NULL, TK_Neutral }, /* 0xdc */ { TK_RightBracket, TK_ForceShift }, /* Ü */ /* 0xdd */ { TK_NULL, TK_Neutral }, /* 0xde */ { TK_NULL, TK_Neutral }, /* 0xdf */ { TK_Caret, TK_ForceNoShift }, /* ß */ /* 0xe0 */ { TK_NULL, TK_Neutral }, /* 0xe1 */ { TK_NULL, TK_Neutral }, /* 0xe2 */ { TK_NULL, TK_Neutral }, /* 0xe3 */ { TK_NULL, TK_Neutral }, /* 0xe4 */ { TK_LeftBracket, TK_ForceNoShift }, /* ä */ /* 0xe5 */ { TK_NULL, TK_Neutral }, /* 0xe6 */ { TK_NULL, TK_Neutral }, /* 0xe7 */ { TK_NULL, TK_Neutral }, /* 0xe8 */ { TK_NULL, TK_Neutral }, /* 0xe9 */ { TK_NULL, TK_Neutral }, /* 0xea */ { TK_NULL, TK_Neutral }, /* 0xeb */ { TK_NULL, TK_Neutral }, /* 0xec */ { TK_NULL, TK_Neutral }, /* 0xed */ { TK_NULL, TK_Neutral }, /* 0xee */ { TK_NULL, TK_Neutral }, /* 0xef */ { TK_NULL, TK_Neutral }, /* 0xf0 */ { TK_NULL, TK_Neutral }, /* 0xf1 */ { TK_NULL, TK_Neutral }, /* 0xf2 */ { TK_NULL, TK_Neutral }, /* 0xf3 */ { TK_NULL, TK_Neutral }, /* 0xf4 */ { TK_NULL, TK_Neutral }, /* 0xf5 */ { TK_NULL, TK_Neutral }, /* 0xf6 */ { TK_Backslash, TK_ForceNoShift }, /* ö */ /* 0xf7 */ { TK_NULL, TK_Neutral }, /* 0xf8 */ { TK_NULL, TK_Neutral }, /* 0xf9 */ { TK_NULL, TK_Neutral }, /* 0xfa */ { TK_NULL, TK_Neutral }, /* 0xfb */ { TK_NULL, TK_Neutral }, /* 0xfc */ { TK_RightBracket, TK_ForceNoShift }, /* ü */ /* 0xfd */ { TK_NULL, TK_Neutral }, /* 0xfe */ { TK_NULL, TK_Neutral }, /* 0xff */ { TK_NULL, TK_Neutral } }; /* Keysyms in the function key range 0xff00 - 0xffff */ KeyTable function_key_table[] = { /* 0xff00 */ { TK_NULL, TK_Neutral }, /* 0xff01 */ { TK_NULL, TK_Neutral }, /* 0xff02 */ { TK_NULL, TK_Neutral }, /* 0xff03 */ { TK_NULL, TK_Neutral }, /* 0xff04 */ { TK_NULL, TK_Neutral }, /* 0xff05 */ { TK_NULL, TK_Neutral }, /* 0xff06 */ { TK_NULL, TK_Neutral }, /* 0xff07 */ { TK_NULL, TK_Neutral }, /* 0xff08 XK_BackSpace */ { TK_Left, TK_Neutral }, /* 0xff09 XK_Tab */ { TK_Right, TK_Neutral }, /* 0xff0a XK_Linefeed */ { TK_Down, TK_Neutral }, /* 0xff0b XK_Clear */ { TK_Clear, TK_Neutral }, /* 0xff0c */ { TK_NULL, TK_Neutral }, /* 0xff0d XK_Return */ { TK_Enter, TK_Neutral }, /* 0xff0e */ { TK_NULL, TK_Neutral }, /* 0xff0f */ { TK_NULL, TK_Neutral }, /* 0xff10 */ { TK_NULL, TK_Neutral }, /* 0xff11 */ { TK_NULL, TK_Neutral }, /* 0xff12 */ { TK_NULL, TK_Neutral }, /* 0xff13 XK_Pause */ { TK_NULL, TK_Neutral }, /* 0xff14 XK_ScrollLock */ { TK_AtSign, TK_Neutral }, /* 0xff15 XK_Sys_Req */ { TK_NULL, TK_Neutral }, /* 0xff16 */ { TK_NULL, TK_Neutral }, /* 0xff17 */ { TK_NULL, TK_Neutral }, /* 0xff18 */ { TK_NULL, TK_Neutral }, /* 0xff19 */ { TK_NULL, TK_Neutral }, /* 0xff1a */ { TK_NULL, TK_Neutral }, /* 0xff1b XK_Escape */ { TK_Break, TK_Neutral }, /* 0xff1c */ { TK_NULL, TK_Neutral }, /* 0xff1d */ { TK_NULL, TK_Neutral }, /* 0xff1e */ { TK_NULL, TK_Neutral }, /* 0xff1f */ { TK_NULL, TK_Neutral }, /* 0xff20 XK_Multi_key */ { TK_AtSign, TK_Neutral }, /* 0xff21 */ { TK_NULL, TK_Neutral }, /* 0xff22 */ { TK_NULL, TK_Neutral }, /* 0xff23 */ { TK_NULL, TK_Neutral }, /* 0xff24 */ { TK_NULL, TK_Neutral }, /* 0xff25 */ { TK_NULL, TK_Neutral }, /* 0xff26 */ { TK_NULL, TK_Neutral }, /* 0xff27 */ { TK_NULL, TK_Neutral }, /* 0xff28 */ { TK_NULL, TK_Neutral }, /* 0xff29 */ { TK_NULL, TK_Neutral }, /* 0xff2a */ { TK_NULL, TK_Neutral }, /* 0xff2b */ { TK_NULL, TK_Neutral }, /* 0xff2c */ { TK_NULL, TK_Neutral }, /* 0xff2d */ { TK_NULL, TK_Neutral }, /* 0xff2e */ { TK_NULL, TK_Neutral }, /* 0xff2f */ { TK_NULL, TK_Neutral }, /* 0xff30 */ { TK_NULL, TK_Neutral }, /* 0xff31 */ { TK_NULL, TK_Neutral }, /* 0xff32 */ { TK_NULL, TK_Neutral }, /* 0xff33 */ { TK_NULL, TK_Neutral }, /* 0xff34 */ { TK_NULL, TK_Neutral }, /* 0xff35 */ { TK_NULL, TK_Neutral }, /* 0xff36 */ { TK_NULL, TK_Neutral }, /* 0xff37 */ { TK_NULL, TK_Neutral }, /* 0xff38 */ { TK_NULL, TK_Neutral }, /* 0xff39 */ { TK_NULL, TK_Neutral }, /* 0xff3a */ { TK_NULL, TK_Neutral }, /* 0xff3b */ { TK_NULL, TK_Neutral }, /* 0xff3c */ { TK_NULL, TK_Neutral }, /* 0xff3d */ { TK_NULL, TK_Neutral }, /* 0xff3e */ { TK_NULL, TK_Neutral }, /* 0xff3f */ { TK_NULL, TK_Neutral }, /* 0xff40 */ { TK_NULL, TK_Neutral }, /* 0xff41 */ { TK_NULL, TK_Neutral }, /* 0xff42 */ { TK_NULL, TK_Neutral }, /* 0xff43 */ { TK_NULL, TK_Neutral }, /* 0xff44 */ { TK_NULL, TK_Neutral }, /* 0xff45 */ { TK_NULL, TK_Neutral }, /* 0xff46 */ { TK_NULL, TK_Neutral }, /* 0xff47 */ { TK_NULL, TK_Neutral }, /* 0xff48 */ { TK_NULL, TK_Neutral }, /* 0xff49 */ { TK_NULL, TK_Neutral }, /* 0xff4a */ { TK_NULL, TK_Neutral }, /* 0xff4b */ { TK_NULL, TK_Neutral }, /* 0xff4c */ { TK_NULL, TK_Neutral }, /* 0xff4d */ { TK_NULL, TK_Neutral }, /* 0xff4e */ { TK_NULL, TK_Neutral }, /* 0xff4f */ { TK_NULL, TK_Neutral }, /* 0xff50 XK_Home */ { TK_Clear, TK_Neutral }, /* 0xff51 XK_Left */ { TK_Left, TK_Neutral }, /* 0xff52 XK_Up */ { TK_Up, TK_Neutral }, /* 0xff53 XK_Right */ { TK_Right, TK_Neutral }, /* 0xff54 XK_Down */ { TK_Down, TK_Neutral }, /* 0xff55 XK_Prior, XK_Page_Up */ { TK_LeftShift, TK_Neutral }, /* 0xff56 XK_Next, XK_Page_Down */ { TK_RightShift, TK_Neutral }, /* 0xff57 XK_End */ { TK_Unused, TK_Neutral }, /* 0xff58 XK_Begin */ { TK_NULL, TK_Neutral }, /* 0xff59 */ { TK_NULL, TK_Neutral }, /* 0xff5a */ { TK_NULL, TK_Neutral }, /* 0xff5b */ { TK_NULL, TK_Neutral }, /* 0xff5c */ { TK_NULL, TK_Neutral }, /* 0xff5d */ { TK_NULL, TK_Neutral }, /* 0xff5e */ { TK_NULL, TK_Neutral }, /* 0xff5f */ { TK_NULL, TK_Neutral }, /* 0xff60 XK_Select */ { TK_NULL, TK_Neutral }, /* 0xff61 XK_Print */ { TK_NULL, TK_Neutral }, /* 0xff62 XK_Execute */ { TK_NULL, TK_Neutral }, /* 0xff63 XK_Insert */ { TK_Underscore, TK_Neutral }, /* 0xff64 */ { TK_NULL, TK_Neutral }, /* 0xff65 XK_Undo */ { TK_NULL, TK_Neutral }, /* 0xff66 XK_Redo */ { TK_NULL, TK_Neutral }, /* 0xff67 XK_Menu */ { TK_NULL, TK_Neutral }, /* 0xff68 XK_Find */ { TK_NULL, TK_Neutral }, /* 0xff69 XK_Cancel */ { TK_NULL, TK_Neutral }, /* 0xff6a XK_Help */ { TK_NULL, TK_Neutral }, /* 0xff6b XK_Break */ { TK_Break, TK_Neutral }, /* 0xff6c */ { TK_NULL, TK_Neutral }, /* 0xff6d */ { TK_NULL, TK_Neutral }, /* 0xff6e */ { TK_NULL, TK_Neutral }, /* 0xff6f */ { TK_NULL, TK_Neutral }, /* 0xff70 */ { TK_NULL, TK_Neutral }, /* 0xff71 */ { TK_NULL, TK_Neutral }, /* 0xff72 */ { TK_NULL, TK_Neutral }, /* 0xff73 */ { TK_NULL, TK_Neutral }, /* 0xff74 */ { TK_NULL, TK_Neutral }, /* 0xff75 */ { TK_NULL, TK_Neutral }, /* 0xff76 */ { TK_NULL, TK_Neutral }, /* 0xff77 */ { TK_NULL, TK_Neutral }, /* 0xff78 */ { TK_NULL, TK_Neutral }, /* 0xff79 */ { TK_NULL, TK_Neutral }, /* 0xff7a */ { TK_NULL, TK_Neutral }, /* 0xff7b */ { TK_NULL, TK_Neutral }, /* 0xff7c */ { TK_NULL, TK_Neutral }, /* 0xff7d */ { TK_NULL, TK_Neutral }, /* 0xff7e XK_Mode_switch */ { TK_NULL, TK_Neutral }, /* 0xff7f XK_Num_Lock */ { TK_NULL, TK_Neutral }, /* 0xff80 XK_KP_Space */ { TK_Space, TK_Neutral }, /* 0xff81 */ { TK_NULL, TK_Neutral }, /* 0xff82 */ { TK_NULL, TK_Neutral }, /* 0xff83 */ { TK_NULL, TK_Neutral }, /* 0xff84 */ { TK_NULL, TK_Neutral }, /* 0xff85 */ { TK_NULL, TK_Neutral }, /* 0xff86 */ { TK_NULL, TK_Neutral }, /* 0xff87 */ { TK_NULL, TK_Neutral }, /* 0xff88 */ { TK_NULL, TK_Neutral }, /* 0xff89 XK_KP_Tab */ { TK_Right, TK_Neutral }, /* 0xff8a */ { TK_NULL, TK_Neutral }, /* 0xff8b */ { TK_NULL, TK_Neutral }, /* 0xff8c */ { TK_NULL, TK_Neutral }, /* 0xff8d XK_KP_Enter */ { TK_Enter, TK_Neutral }, /* 0xff8e */ { TK_NULL, TK_Neutral }, /* 0xff8f */ { TK_NULL, TK_Neutral }, /* 0xff90 */ { TK_NULL, TK_Neutral }, /* 0xff91 XK_KP_F1 */ { TK_F1, TK_Neutral }, /* 0xff92 XK_KP_F2 */ { TK_F2, TK_Neutral }, /* 0xff93 XK_KP_F3 */ { TK_F3, TK_Neutral }, /* 0xff94 XK_KP_F4 */ { TK_CapsLock, TK_Neutral }, #if KP_JOYSTICK /* 0xff95 XK_KP_Home */ { TK_Northwest, TK_Neutral }, /* 0xff96 XK_KP_Left */ { TK_West, TK_Neutral }, /* 0xff97 XK_KP_Up */ { TK_North, TK_Neutral }, /* 0xff98 XK_KP_Right */ { TK_East, TK_Neutral }, /* 0xff99 XK_KP_Down */ { TK_South, TK_Neutral }, /* 0xff9a XK_KP_Prior, XK_KP_Page_Up */ { TK_Northeast, TK_Neutral }, /* 0xff9b XK_KP_Next, XK_KP_Page_Down */ { TK_Southeast, TK_Neutral }, /* 0xff9c XK_KP_End */ { TK_Southwest, TK_Neutral }, /* 0xff9d XK_KP_Begin */ { TK_Fire, TK_Neutral }, /* 0xff9e XK_KP_Insert */ { TK_Fire, TK_Neutral }, #else /* 0xff95 XK_KP_Home */ { TK_Clear, TK_Neutral }, /* 0xff96 XK_KP_Left */ { TK_Left, TK_Neutral }, /* 0xff97 XK_KP_Up */ { TK_Up, TK_Neutral }, /* 0xff98 XK_KP_Right */ { TK_Right, TK_Neutral }, /* 0xff99 XK_KP_Down */ { TK_Down, TK_Neutral }, /* 0xff9a XK_KP_Prior, XK_KP_Page_Up */ { TK_LeftShift, TK_Neutral }, /* 0xff9b XK_KP_Next, XK_KP_Page_Down */ { TK_RightShift, TK_Neutral }, /* 0xff9c XK_KP_End */ { TK_Unused, TK_Neutral }, /* 0xff9d XK_KP_Begin */ { TK_NULL, TK_Neutral }, /* 0xff9e XK_KP_Insert */ { TK_Underscore, TK_Neutral }, #endif /* 0xff9f XK_KP_Delete */ { TK_Left, TK_Neutral }, /* 0xffa0 */ { TK_NULL, TK_Neutral }, /* 0xffa1 */ { TK_NULL, TK_Neutral }, /* 0xffa2 */ { TK_NULL, TK_Neutral }, /* 0xffa3 */ { TK_NULL, TK_Neutral }, /* 0xffa4 */ { TK_NULL, TK_Neutral }, /* 0xffa5 */ { TK_NULL, TK_Neutral }, /* 0xffa6 */ { TK_NULL, TK_Neutral }, /* 0xffa7 */ { TK_NULL, TK_Neutral }, /* 0xffa8 */ { TK_NULL, TK_Neutral }, /* 0xffa9 */ { TK_NULL, TK_Neutral }, /* 0xffaa XK_KP_Multiply */ { TK_Colon, TK_ForceShift }, /* 0xffab XK_KP_Add */ { TK_Semicolon, TK_ForceShift }, /* 0xffac XK_KP_Separator*/ { TK_Comma, TK_Neutral }, /* 0xffad XK_KP_Subtract */ { TK_Minus, TK_Neutral }, /* 0xffae XK_KP_Decimal */ { TK_Period, TK_Neutral }, /* 0xffaf XK_KP_Divide */ { TK_Slash, TK_Neutral }, #if KPNUM_JOYSTICK /* 0xffb0 XK_KP_0 */ { TK_Fire, TK_Neutral }, /* 0xffb1 XK_KP_1 */ { TK_Southwest, TK_Neutral }, /* 0xffb2 XK_KP_2 */ { TK_South, TK_Neutral }, /* 0xffb3 XK_KP_3 */ { TK_Southeast, TK_Neutral }, /* 0xffb4 XK_KP_4 */ { TK_West, TK_Neutral }, /* 0xffb5 XK_KP_5 */ { TK_Fire, TK_Neutral }, /* 0xffb6 XK_KP_6 */ { TK_East, TK_Neutral }, /* 0xffb7 XK_KP_7 */ { TK_Northwest, TK_Neutral }, /* 0xffb8 XK_KP_8 */ { TK_North, TK_Neutral }, /* 0xffb9 XK_KP_9 */ { TK_Northeast, TK_Neutral }, #else /* 0xffb0 XK_KP_0 */ { TK_0, TK_Neutral }, /* 0xffb1 XK_KP_1 */ { TK_1, TK_Neutral }, /* 0xffb2 XK_KP_2 */ { TK_2, TK_Neutral }, /* 0xffb3 XK_KP_3 */ { TK_3, TK_Neutral }, /* 0xffb4 XK_KP_4 */ { TK_4, TK_Neutral }, /* 0xffb5 XK_KP_5 */ { TK_5, TK_Neutral }, /* 0xffb6 XK_KP_6 */ { TK_6, TK_Neutral }, /* 0xffb7 XK_KP_7 */ { TK_7, TK_Neutral }, /* 0xffb8 XK_KP_8 */ { TK_8, TK_Neutral }, /* 0xffb9 XK_KP_9 */ { TK_9, TK_Neutral }, #endif /* 0xffba */ { TK_NULL, TK_Neutral }, /* 0xffbb */ { TK_NULL, TK_Neutral }, /* 0xffbc */ { TK_NULL, TK_Neutral }, /* 0xffbd XK_KP_Equal */ { TK_Minus, TK_ForceShift }, /* 0xffbe XK_F1 */ { TK_F1, TK_Neutral }, /* 0xffbf XK_F2 */ { TK_F2, TK_Neutral }, /* 0xffc0 XK_F3 */ { TK_F3, TK_Neutral }, /* 0xffc1 XK_F4 */ { TK_CapsLock, TK_Neutral }, /* 0xffc2 XK_F5 */ { TK_AtSign, TK_Neutral }, /* 0xffc3 XK_F6 */ { TK_0, TK_Neutral }, /* 0xffc4 XK_F7 */ { TK_NULL, TK_Neutral }, /* 0xffc5 XK_F8 */ { TK_NULL, TK_Neutral }, /* 0xffc6 XK_F9 */ { TK_NULL, TK_Neutral }, /* 0xffc7 XK_F10 */ { TK_NULL, TK_Neutral }, /* In some versions of XFree86, XK_F11 to XK_F20 are produced for the shifted F1 to F10 keys, in some XK_F13 to XK_F20 are produced for the shifted F1 to F8 keys, and in some the keysyms are not altered. Arrgh. */ #if SHIFT_F1_IS_F11 /* 0xffc8 XK_F11 */ { TK_F1, TK_Neutral }, /* 0xffc9 XK_F12 */ { TK_F2, TK_Neutral }, /* 0xffca XK_F13 */ { TK_F3, TK_Neutral }, /* 0xffcb XK_F14 */ { TK_CapsLock, TK_Neutral }, /* 0xffcc XK_F15 */ { TK_AtSign, TK_Neutral }, /* 0xffcd XK_F16 */ { TK_0, TK_Neutral }, /* 0xffce XK_F17 */ { TK_NULL, TK_Neutral }, /* 0xffcf XK_F18 */ { TK_NULL, TK_Neutral }, #elif SHIFT_F1_IS_F13 /* 0xffc8 XK_F11 */ { TK_NULL, TK_Neutral }, /* 0xffc9 XK_F12 */ { TK_NULL, TK_Neutral }, /* 0xffca XK_F13 */ { TK_F1, TK_Neutral }, /* 0xffcb XK_F14 */ { TK_F2, TK_Neutral }, /* 0xffcc XK_F15 */ { TK_F3, TK_Neutral }, /* 0xffcd XK_F16 */ { TK_CapsLock, TK_Neutral }, /* 0xffce XK_F17 */ { TK_AtSign, TK_Neutral }, /* 0xffcf XK_F18 */ { TK_0, TK_Neutral }, #else /* 0xffc8 XK_F11 */ { TK_NULL, TK_Neutral }, /* 0xffc9 XK_F12 */ { TK_NULL, TK_Neutral }, /* 0xffca XK_F13 */ { TK_NULL, TK_Neutral }, /* 0xffcb XK_F14 */ { TK_NULL, TK_Neutral }, /* 0xffcc XK_F15 */ { TK_NULL, TK_Neutral }, /* 0xffcd XK_F16 */ { TK_NULL, TK_Neutral }, /* 0xffce XK_F17 */ { TK_NULL, TK_Neutral }, /* 0xffcf XK_F18 */ { TK_NULL, TK_Neutral }, #endif /* 0xffd0 XK_F19 */ { TK_NULL, TK_Neutral }, /* 0xffd1 XK_F20 */ { TK_NULL, TK_Neutral }, /* 0xffd2 XK_F21 */ { TK_NULL, TK_Neutral }, /* 0xffd3 XK_F22 */ { TK_NULL, TK_Neutral }, /* 0xffd4 XK_F23 */ { TK_NULL, TK_Neutral }, /* 0xffd5 XK_F24 */ { TK_NULL, TK_Neutral }, /* 0xffd6 XK_F25 */ { TK_NULL, TK_Neutral }, /* 0xffd7 XK_F26 */ { TK_NULL, TK_Neutral }, /* 0xffd8 XK_F27 */ { TK_NULL, TK_Neutral }, /* 0xffd9 XK_F28 */ { TK_NULL, TK_Neutral }, /* 0xffda XK_F29 */ { TK_NULL, TK_Neutral }, /* 0xffdb XK_F30 */ { TK_NULL, TK_Neutral }, /* 0xffdc XK_F31 */ { TK_NULL, TK_Neutral }, /* 0xffdd XK_F32 */ { TK_NULL, TK_Neutral }, /* 0xffde XK_F33 */ { TK_NULL, TK_Neutral }, /* 0xffdf XK_F34 */ { TK_NULL, TK_Neutral }, /* 0xffe0 XK_F35 */ { TK_NULL, TK_Neutral }, /* 0xffe1 XK_Shift_L */ { TK_LeftShift, TK_Neutral }, /* 0xffe2 XK_Shift_R */ { TK_RightShift, TK_Neutral }, /* 0xffe3 XK_Control_L */ { TK_Ctrl, TK_Neutral }, /* 0xffe4 XK_Control_R */ { TK_Ctrl, TK_Neutral }, /* 0xffe5 XK_Caps_Lock */ { TK_NULL, TK_Neutral }, /* 0xffe6 XK_Shift_Lock */ { TK_NULL, TK_Neutral }, /* 0xffe7 XK_Meta_L */ { TK_Clear, TK_Neutral }, /* 0xffe8 XK_Meta_R */ { TK_Down, TK_ForceShiftPersistent }, /* 0xffe9 XK_Alt_L */ { TK_Clear, TK_Neutral }, /* 0xffea XK_Alt_R */ { TK_Down, TK_ForceShiftPersistent }, /* 0xffeb XK_Super_L */ { TK_NULL, TK_Neutral }, /* 0xffec XK_Super_R */ { TK_NULL, TK_Neutral }, /* 0xffed XK_Hyper_L */ { TK_NULL, TK_Neutral }, /* 0xffee XK_Hyper_R */ { TK_NULL, TK_Neutral }, /* 0xffef */ { TK_NULL, TK_Neutral }, /* 0xfff0 */ { TK_NULL, TK_Neutral }, /* 0xfff1 */ { TK_NULL, TK_Neutral }, /* 0xfff2 */ { TK_NULL, TK_Neutral }, /* 0xfff3 */ { TK_NULL, TK_Neutral }, /* 0xfff4 */ { TK_NULL, TK_Neutral }, /* 0xfff5 */ { TK_NULL, TK_Neutral }, /* 0xfff6 */ { TK_NULL, TK_Neutral }, /* 0xfff7 */ { TK_NULL, TK_Neutral }, /* 0xfff8 */ { TK_NULL, TK_Neutral }, /* 0xfff9 */ { TK_NULL, TK_Neutral }, /* 0xfffa */ { TK_NULL, TK_Neutral }, /* 0xfffb */ { TK_NULL, TK_Neutral }, /* 0xfffc */ { TK_NULL, TK_Neutral }, /* 0xfffd */ { TK_NULL, TK_Neutral }, /* 0xfffe */ { TK_NULL, TK_Neutral }, /* 0xffff XK_Delete */ { TK_Left, TK_Neutral } }; static int keystate[8] = { 0, }; static int force_shift = TK_Neutral; static int joystate = 0; /* Avoid changing state too fast so keystrokes aren't lost. */ #define STRETCH_AMOUNT 4000 static tstate_t key_stretch_timeout; int stretch_amount = STRETCH_AMOUNT; void trs_kb_reset() { key_stretch_timeout = z80_state.t_count; } int key_heartbeat = 0; void trs_kb_heartbeat() { /* Don't hold keys in queue too long */ key_heartbeat++; } void trs_kb_bracket(int shifted) { /* Set the shift state for the emulation of the "[ {", "\ |", "] }", "^ ~", and "_ DEL" keys. Some Model 4 keyboard drivers decode these with [ shifted and { unshifted, etc., while most other keyboard drivers either ignore them or decode them with [ unshifted and { shifted. We default to the latter. Note that these keys didn't exist on real machines anyway. */ int i; for (i=0x5b; i<=0x5f; i++) { ascii_key_table[i].shift_action = shifted ? TK_ForceShift : TK_ForceNoShift; } for (i=0x7b; i<=0x7f; i++) { ascii_key_table[i].shift_action = shifted ? TK_ForceNoShift : TK_ForceShift; } } /* Emulate joystick with the keypad */ int trs_emulate_joystick(int key_down, int bit_action) { if (bit_action < TK_Joystick) return 0; if (key_down) { joystate |= (bit_action & 0x1f); } else { joystate &= ~(bit_action & 0x1f); } return 1; } int trs_joystick_in() { #if JOYDEBUG debug("joy %02x ", joystate); #endif return (Uchar) ~joystate; } void trs_xlate_keysym(int keysym) { int key_down; KeyTable* kt; static int shift_action = TK_Neutral; if (keysym == 0x10000) { /* force all keys up */ queue_key(TK_AllKeysUp); shift_action = TK_Neutral; return; } key_down = (keysym & 0x10000) == 0; if (keysym & 0xff00) { kt = &function_key_table[keysym & 0xff]; } else { kt = &ascii_key_table[keysym & 0xff]; } if (kt->bit_action == TK_NULL) return; if (trs_emulate_joystick(key_down, kt->bit_action)) return; if (key_down) { if (shift_action != TK_ForceShiftPersistent && shift_action != kt->shift_action) { shift_action = kt->shift_action; queue_key(shift_action); } queue_key(kt->bit_action); } else { queue_key(kt->bit_action | 0x10000); if (shift_action != TK_Neutral && shift_action == kt->shift_action) { shift_action = TK_Neutral; queue_key(shift_action); } } } static void change_keystate(int action) { int key_down; int i; #ifdef KBDEBUG debug("change_keystate: action 0x%x\n", action); #endif switch (action) { case TK_AllKeysUp: /* force all keys up */ for (i=0; i<7; i++) { keystate[i] = 0; } force_shift = TK_Neutral; break; case TK_Neutral: case TK_ForceShift: case TK_ForceNoShift: case TK_ForceShiftPersistent: force_shift = action; break; default: key_down = TK_DOWN(action); if (key_down) { keystate[TK_ADDR(action)] |= (1 << TK_DATA(action)); } else { keystate[TK_ADDR(action)] &= ~(1 << TK_DATA(action)); } } } static int kb_mem_value(int address) { int i, bitpos, data = 0; for (i=0, bitpos=1; i<7; i++, bitpos<<=1) { if (address & bitpos) { data |= keystate[i]; } } if (address & 0x80) { int tmp = keystate[7]; if (trs_model == 1) { if (force_shift == TK_ForceNoShift) { /* deactivate shift key */ tmp &= ~1; } else if (force_shift != TK_Neutral) { /* activate shift key */ tmp |= 1; } } else { if (force_shift == TK_ForceNoShift) { /* deactivate both shift keys */ tmp &= ~3; } else if (force_shift != TK_Neutral) { /* if no shift keys are down, activate left shift key */ if ((tmp & 3) == 0) tmp |= 1; } } data |= tmp; } return data; } int trs_kb_mem_read(int address) { int key = -1; int i, wait; static int recursion = 0; static int timesseen; /* Prevent endless recursive calls to this routine (by mem_read_word below) if REG_SP happens to point to keyboard memory. */ if (recursion) return 0; /* Avoid delaying key state changes in queue for too long */ if (key_heartbeat > 2) { do { key = trs_next_key(0); if (key >= 0) { change_keystate(key); timesseen = 1; } } while (key >= 0); } /* After each key state change, impose a timeout before the next one so that the Z-80 program doesn't miss any by polling too rarely, and so that we don't tickle the bugs in some common TRS-80 keyboard drivers that strike if two keys change simultaneously */ if (key_stretch_timeout - z80_state.t_count > TSTATE_T_MID) { /* Check if we are in the system keyboard driver, called from the wait-for-input routine. If so, and there are no keystrokes queued, and the current state has been seen by at least 16 such reads, then trs_next_key will pause the process to avoid burning host CPU needlessly. The test below works on both Model I and III and is insensitive to what keyboard driver is being used, as long as it is called through the wait-for-key routine at ROM address 0x0049 and has not pushed too much on the stack yet when it first reads from the key matrix. The search is needed (at least) for NEWDOS80, which pushes 2 extra bytes on the stack. */ wait = 0; if (timesseen++ >= 16) { recursion = 1; for (i=0; i<=4; i+=2) { if (mem_read_word(REG_SP + 2 + i) == 0x4015) { wait = mem_read_word(REG_SP + 10 + i) == 0x004c; break; } } recursion = 0; } /* Get the next key */ key = trs_next_key(wait); key_stretch_timeout = z80_state.t_count + stretch_amount; } if (key >= 0) { change_keystate(key); timesseen = 1; } key_heartbeat = 0; return kb_mem_value(address); } void clear_key_queue() { key_queue_head = 0; key_queue_entries = 0; #if QDEBUG debug("clear_key_queue\n"); #endif } void queue_key(int state) { key_queue[(key_queue_head + key_queue_entries) % KEY_QUEUE_SIZE] = state; #if QDEBUG debug("queue_key 0x%x\n", state); #endif if (key_queue_entries < KEY_QUEUE_SIZE) { key_queue_entries++; } else { #if QDEBUG debug("queue_key overflow\n"); #endif } } int dequeue_key() { int rval = -1; if(key_queue_entries > 0) { rval = key_queue[key_queue_head]; key_queue_head = (key_queue_head + 1) % KEY_QUEUE_SIZE; key_queue_entries--; #if QDEBUG debug("dequeue_key 0x%x\n", rval); #endif } return rval; } void trs_skip_next_kbwait() { skip_next_kbwait = 1; } int trs_next_key(int wait) { #if KBWAIT if (wait) { int rval; for (;;) { if ((rval = dequeue_key()) >= 0) break; if ((z80_state.nmi && !z80_state.nmi_seen) || (z80_state.irq && z80_state.iff1) || trs_event_scheduled() || skip_next_kbwait) { skip_next_kbwait = 0; rval = -1; break; } trs_paused = 1; pause(); /* Wait for SIGALRM */ trs_get_event(0); } return rval; } #endif return dequeue_key(); } xtrs-4.9d/trs_memory.c000066400000000000000000000346201306603614600151100ustar00rootroot00000000000000/* * Copyright (C) 1992 Clarendon Hill Software. * * Permission is granted to any individual or institution to use, copy, * or redistribute this software, provided this copyright notice is retained. * * This software is provided "as is" without any expressed or implied * warranty. If this software brings on any sort of damage -- physical, * monetary, emotional, or brain -- too bad. You've got no one to blame * but yourself. * * The software may be modified for your own purposes, but modified versions * must retain this notice. */ /* Modified by Timothy Mann, 1996 and later $Id: trs_memory.c,v 1.24 2009/06/15 23:41:56 mann Exp $ */ /* * trs_memory.c -- memory emulation functions for the TRS-80 emulator * * Routines in this file perform operations such as mem_read and mem_write, * and are the top level emulation points for memory-mapped devices such * as the screen and keyboard. */ #include "z80.h" #include "trs.h" #include #include "trs_disk.h" #include "trs_hard.h" #define MAX_ROM_SIZE (0x3800) #define MAX_VIDEO_SIZE (0x0800) /* Locations for Model I, Model III, and Model 4 map 0 */ #define ROM_START (0x0000) #define IO_START (0x3000) #define KEYBOARD_START (0x3800) #define MORE_IO_START (0x3c00) #define VIDEO_START (0x3c00) #define RAM_START (0x4000) #define PRINTER_ADDRESS (0x37E8) /* Interrupt latch register in EI (Model 1) */ #define TRS_INTLATCH(addr) (((addr)&~3) == 0x37e0) Uchar memory[0x20001]; /* +1 so strings from mem_pointer are NUL-terminated */ Uchar *rom; int trs_rom_size; Uchar *video; int trs_video_size; int memory_map = 0; int bank_offset[2]; #define VIDEO_PAGE_0 0 #define VIDEO_PAGE_1 1024 int video_offset = (-VIDEO_START + VIDEO_PAGE_0); int romin = 0; /* Model 4p */ /*SUPPRESS 53*/ /*SUPPRESS 112*/ void mem_video_page(int which) { video_offset = -VIDEO_START + (which ? VIDEO_PAGE_1 : VIDEO_PAGE_0); } void mem_bank(int command) { switch (command) { case 0: bank_offset[0] = 0 << 15; bank_offset[1] = 0 << 15; break; case 2: bank_offset[0] = 0 << 15; bank_offset[1] = 1 << 15; break; case 3: bank_offset[0] = 0 << 15; bank_offset[1] = 2 << 15; break; case 6: bank_offset[0] = 2 << 15; bank_offset[1] = 0 << 15; break; case 7: bank_offset[0] = 3 << 15; bank_offset[1] = 0 << 15; break; default: error("unknown mem_bank command %d", command); break; } } void trs_exit() { exit(0); } /* Handle reset button if poweron=0; handle hard reset or initial poweron if poweron=1 */ void trs_reset(int poweron) { /* Reset devices (Model I SYSRES, Model III/4 RESET) */ trs_cassette_reset(); trs_timer_speed(0); trs_disk_init(poweron); // also inits trs_hard and trs_stringy /* I'm told that the hard disk controller is enabled on powerup */ /* XXX should trs_hard_init do this, then? */ trs_hard_out(TRS_HARD_CONTROL, TRS_HARD_SOFTWARE_RESET|TRS_HARD_DEVICE_ENABLE); if (trs_model == 5) { /* Switch in boot ROM */ z80_out(0x9C, 1); } if (trs_model >= 4) { /* Turn off various memory map and video mode bits */ z80_out(0x84, 0); } if (trs_model >= 3) { grafyx_write_mode(0); trs_interrupt_mask_write(0); trs_nmi_mask_write(0); } if (trs_model == 3) { grafyx_m3_reset(); } if (trs_model == 1) { hrg_onoff(0); /* Switch off HRG1B hi-res graphics. */ } trs_kb_reset(); /* Part of keyboard stretch kludge */ trs_cancel_event(); trs_timer_interrupt(0); if (poweron || trs_model >= 4) { /* Reset processor */ z80_reset(); } else { /* Signal a nonmaskable interrupt. */ trs_reset_button_interrupt(1); trs_schedule_event(trs_reset_button_interrupt, 0, 2000); } } void mem_map(int which) { memory_map = which + (trs_model << 4) + (romin << 2); } void mem_romin(state) { romin = (state & 1); memory_map = (memory_map & ~4) + (romin << 2); } void mem_init() { if (trs_model <= 3) { rom = &memory[ROM_START]; video = &memory[VIDEO_START]; trs_video_size = 1024; } else { /* +1 so strings from mem_pointer are NUL-terminated */ rom = (Uchar *) calloc(MAX_ROM_SIZE+1, 1); video = (Uchar *) calloc(MAX_VIDEO_SIZE+1, 1); trs_video_size = MAX_VIDEO_SIZE; } mem_map(0); mem_bank(0); mem_video_page(0); if (trs_model == 5) { z80_out(0x9C, 1); } } /* * hack to let us initialize the ROM memory */ void mem_write_rom(int address, int value) { address &= 0xffff; rom[address] = value; } /* Called by load_hex */ void hex_data(int address, int value) { mem_write_rom(address, value); } /* Called by load_hex */ void hex_transfer_address(int address) { /* Ignore */ } int mem_read(int address) { address &= 0xffff; /* allow callers to be sloppy */ switch (memory_map) { case 0x10: /* Model I */ if (address >= VIDEO_START) return memory[address]; if (address < trs_rom_size) return memory[address]; if (address == TRSDISK_DATA) return trs_disk_data_read(); if (TRS_INTLATCH(address)) return trs_interrupt_latch_read(); if (address == TRSDISK_STATUS) return trs_disk_status_read(); if (address == PRINTER_ADDRESS) return trs_printer_read(); if (address == TRSDISK_TRACK) return trs_disk_track_read(); if (address == TRSDISK_SECTOR) return trs_disk_sector_read(); if (address >= KEYBOARD_START) return trs_kb_mem_read(address); return 0xff; case 0x30: /* Model III */ if (address >= RAM_START) return memory[address]; if (address == PRINTER_ADDRESS) return trs_printer_read(); if (address < trs_rom_size) return memory[address]; if (address >= VIDEO_START) { return grafyx_m3_read_byte(address - VIDEO_START); } if (address >= KEYBOARD_START) return trs_kb_mem_read(address); return 0xff; case 0x40: /* Model 4 map 0 */ if (address >= RAM_START) { return memory[address + bank_offset[address>>15]]; } if (address == PRINTER_ADDRESS) return trs_printer_read(); if (address < trs_rom_size) return rom[address]; if (address >= VIDEO_START) { return video[address + video_offset]; } if (address >= KEYBOARD_START) return trs_kb_mem_read(address); return 0xff; case 0x54: /* Model 4P map 0, boot ROM in */ case 0x55: /* Model 4P map 1, boot ROM in */ if (address < trs_rom_size) return rom[address]; /* else fall thru */ case 0x41: /* Model 4 map 1 */ case 0x50: /* Model 4P map 0, boot ROM out */ case 0x51: /* Model 4P map 1, boot ROM out */ if (address >= RAM_START || address < KEYBOARD_START) { return memory[address + bank_offset[address>>15]]; } if (address >= VIDEO_START) { return video[address + video_offset]; } if (address >= KEYBOARD_START) return trs_kb_mem_read(address); return 0xff; case 0x42: /* Model 4 map 2 */ case 0x52: /* Model 4P map 2, boot ROM out */ case 0x56: /* Model 4P map 2, boot ROM in */ if (address < 0xf400) { return memory[address + bank_offset[address>>15]]; } if (address >= 0xf800) return video[address-0xf800]; return trs_kb_mem_read(address); case 0x43: /* Model 4 map 3 */ case 0x53: /* Model 4P map 3, boot ROM out */ case 0x57: /* Model 4P map 3, boot ROM in */ return memory[address + bank_offset[address>>15]]; } /* not reached */ return 0xff; } void mem_write(int address, int value) { address &= 0xffff; switch (memory_map) { case 0x10: /* Model I */ if (address >= RAM_START) { memory[address] = value; } else if (address >= VIDEO_START) { int vaddr = address + video_offset; #if UPPERCASE /* * Video write. Hack here to make up for the missing bit 6 * video ram, emulating the gate in Z30. */ if (trs_model == 1) { if(value & 0xa0) value &= 0xbf; else value |= 0x40; } #endif if (video[vaddr] != value) { video[vaddr] = value; trs_screen_write_char(vaddr, value); } } else if (address == PRINTER_ADDRESS) { trs_printer_write(value); } else if (address == TRSDISK_DATA) { trs_disk_data_write(value); } else if (address == TRSDISK_STATUS) { trs_disk_command_write(value); } else if (address == TRSDISK_TRACK) { trs_disk_track_write(value); } else if (address == TRSDISK_SECTOR) { trs_disk_sector_write(value); } else if (TRSDISK_SELECT(address)) { trs_disk_select_write(value); } break; case 0x30: /* Model III */ if (address >= RAM_START) { memory[address] = value; } else if (address >= VIDEO_START) { int vaddr = address + video_offset; if (grafyx_m3_write_byte(vaddr, value)) return; if (video[vaddr] != value) { video[vaddr] = value; trs_screen_write_char(vaddr, value); } } else if (address == PRINTER_ADDRESS) { trs_printer_write(value); } break; case 0x40: /* Model 4 map 0 */ case 0x50: /* Model 4P map 0, boot ROM out */ case 0x54: /* Model 4P map 0, boot ROM in */ if (address >= RAM_START) { memory[address + bank_offset[address>>15]] = value; } else if (address >= VIDEO_START) { int vaddr = address+ video_offset; if (video[vaddr] != value) { video[vaddr] = value; trs_screen_write_char(vaddr, value); } } else if (address == PRINTER_ADDRESS) { trs_printer_write(value); } break; case 0x41: /* Model 4 map 1 */ case 0x51: /* Model 4P map 1, boot ROM out */ case 0x55: /* Model 4P map 1, boot ROM in */ if (address >= RAM_START || address < KEYBOARD_START) { memory[address + bank_offset[address>>15]] = value; } else if (address >= VIDEO_START) { int vaddr = address + video_offset; if (video[vaddr] != value) { video[vaddr] = value; trs_screen_write_char(vaddr, value); } } break; case 0x42: /* Model 4 map 2 */ case 0x52: /* Model 4P map 2, boot ROM out */ case 0x56: /* Model 4P map 2, boot ROM in */ if (address < 0xf400) { memory[address + bank_offset[address>>15]] = value; } else if (address >= 0xf800) { int vaddr = address - 0xf800; if (video[vaddr] != value) { video[vaddr] = value; trs_screen_write_char(vaddr, value); } } break; case 0x43: /* Model 4 map 3 */ case 0x53: /* Model 4P map 3, boot ROM out */ case 0x57: /* Model 4P map 3, boot ROM in */ memory[address + bank_offset[address>>15]] = value; break; } } /* * Words are stored with the low-order byte in the lower address. */ int mem_read_word(int address) { int rval; rval = mem_read(address++); rval |= mem_read(address & 0xffff) << 8; return rval; } void mem_write_word(int address, int value) { mem_write(address++, value & 0xff); mem_write(address, value >> 8); } /* * Get a pointer to the given address. Note that there is no checking * whether the next virtual address is physically contiguous. The * caller is responsible for making sure his strings don't span * memory map boundaries. */ Uchar *mem_pointer(int address, int writing) { address &= 0xffff; switch (memory_map + (writing << 3)) { case 0x10: /* Model I reading */ case 0x30: /* Model III reading */ if (address >= VIDEO_START) return &memory[address]; if (address < trs_rom_size) return &rom[address]; return NULL; case 0x18: /* Model I writing */ case 0x38: /* Model III writing */ if (address >= VIDEO_START) return &memory[address]; return NULL; case 0x40: /* Model 4 map 0 reading */ if (address >= RAM_START) { return &memory[address + bank_offset[address>>15]]; } if (address < trs_rom_size) return &rom[address]; if (address >= VIDEO_START) { return &video[address + video_offset]; } return NULL; case 0x48: /* Model 4 map 0 writing */ case 0x58: /* Model 4P map 0, boot ROM out, writing */ case 0x5c: /* Model 4P map 0, boot ROM in, writing */ if (address >= RAM_START) { return &memory[address + bank_offset[address>>15]]; } if (address >= VIDEO_START) { return &video[address + video_offset]; } return NULL; case 0x54: /* Model 4P map 0, boot ROM in, reading */ case 0x55: /* Model 4P map 1, boot ROM in, reading */ if (address < trs_rom_size) return &rom[address]; /* else fall thru */ case 0x41: /* Model 4 map 1 reading */ case 0x49: /* Model 4 map 1 writing */ case 0x50: /* Model 4P map 0, boot ROM out, reading */ case 0x51: /* Model 4P map 1, boot ROM out, reading */ case 0x59: /* Model 4P map 1, boot ROM out, writing */ case 0x5d: /* Model 4P map 1, boot ROM in, writing */ if (address >= RAM_START || address < KEYBOARD_START) { return &memory[address + bank_offset[address>>15]]; } if (address >= VIDEO_START) { return &video[address + video_offset]; } return NULL; case 0x42: /* Model 4 map 1, reading */ case 0x4a: /* Model 4 map 1, writing */ case 0x52: /* Model 4P map 2, boot ROM out, reading */ case 0x5a: /* Model 4P map 2, boot ROM out, writing */ case 0x56: /* Model 4P map 2, boot ROM in, reading */ case 0x5e: /* Model 4P map 2, boot ROM in, writing */ if (address < 0xf400) { return &memory[address + bank_offset[address>>15]]; } if (address >= 0xf800) return &video[address-0xf800]; return NULL; case 0x43: /* Model 4 map 3, reading */ case 0x4b: /* Model 4 map 3, writing */ case 0x53: /* Model 4P map 3, boot ROM out, reading */ case 0x5b: /* Model 4P map 3, boot ROM out, writing */ case 0x57: /* Model 4P map 3, boot ROM in, reading */ case 0x5f: /* Model 4P map 3, boot ROM in, writing */ return &memory[address + bank_offset[address>>15]]; } /* not reached */ return NULL; } /* * Block move instructions, for LDIR and LDDR instructions. * * Direction is either +1 or -1. * * Note that a count of zero => move 64K bytes. * * These can be special cased to do fun stuff like fast * video scrolling. */ int mem_block_transfer(Ushort dest, Ushort source, int direction, Ushort count) { int ret; /* special case for screen scroll */ if((trs_model <= 3 || (memory_map & 3) < 2) && (dest == VIDEO_START) && (source == VIDEO_START + 0x40) && (count == 0x3c0) && (direction > 0) && !grafyx_m3_active()) { /* scroll screen one line */ unsigned char *p = video, *q = video + 0x40; trs_screen_scroll(); do { *p++ = ret = *q++; } while (count--); } else { trs_screen_batch(); if(direction > 0) { do { mem_write(dest++, ret = mem_read(source++)); count--; } while(count); } else { do { mem_write(dest--, ret = mem_read(source--)); count--; } while(count); } trs_screen_unbatch(); } return ret; } xtrs-4.9d/trs_printer.c000066400000000000000000000015471306603614600152650ustar00rootroot00000000000000/* * Copyright (C) 1992 Clarendon Hill Software. * * Permission is granted to any individual or institution to use, copy, * or redistribute this software, provided this copyright notice is retained. * * This software is provided "as is" without any expressed or implied * warranty. If this software brings on any sort of damage -- physical, * monetary, emotional, or brain -- too bad. You've got no one to blame * but yourself. * * The software may be modified for your own purposes, but modified versions * must retain this notice. */ /* $Id: trs_printer.c,v 1.3 2008/06/26 04:39:56 mann Exp $ */ #include "z80.h" #include "trs.h" void trs_printer_write(value) { if(value == 0x0D) { putchar('\n'); } else { putchar(value); } } int trs_printer_read() { return 0x30; /* printer selected, ready, with paper, not busy */ } xtrs-4.9d/trs_uart.c000066400000000000000000000224041306603614600145500ustar00rootroot00000000000000/* Copyright (c) 2000, Timothy Mann */ /* $Id: trs_uart.c,v 1.5 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* * Emulation of the Radio Shack TRS-80 Model I/III/4/4P serial port. */ #include #include #include #include #include #include #include #include #include #include "trs.h" #include "trs_uart.h" #ifndef FNONBLOCK #define FNONBLOCK O_NONBLOCK #endif #define BUFSIZE 256 /*#define UARTDEBUG 1*/ /*#define UARTDEBUG2 1*/ #if __linux char *trs_uart_name = "/dev/ttyS0"; #else char *trs_uart_name = "/dev/tty00"; #endif int trs_uart_switches = 0x7 | TRS_UART_NOPAR | TRS_UART_WORD8; /* Default: 9600 8N1 */ static int initialized = 0; static struct { int modem; int switches; int baud; int status; int control; int idata; int odata; Uchar buf[BUFSIZE]; Uchar* bufp; int bufleft; int tstates; int fd; int fdflags; struct termios t; } uart; static int trs_uart_wordbits[] = TRS_UART_WORDBITS_TABLE; static float trs_uart_baud[] = TRS_UART_BAUD_TABLE; static int xlate_baud(int trs_baud) { switch (trs_baud) { case TRS_UART_50: return B50; case TRS_UART_75: return B75; case TRS_UART_110: return B110; case TRS_UART_134: return B134; case TRS_UART_150: return B150; case TRS_UART_300: return B300; case TRS_UART_600: return B600; case TRS_UART_1200: return B1200; case TRS_UART_1800: return B1800; case TRS_UART_2000: error("unix does not support 2000 baud, using 38400"); return B38400; case TRS_UART_2400: return B2400; case TRS_UART_3600: #ifdef B57600 error("unix does not support 3600 baud, using 57600"); return B57600; #else error("unix does not support 3600 baud"); return B0; #endif case TRS_UART_4800: return B4800; case TRS_UART_7200: #ifdef B115200 error("unix does not support 7200 baud, using 115200"); return B115200; #else error("unix does not support 7200 baud"); return B0; #endif case TRS_UART_9600: return B9600; case TRS_UART_19200: return B19200; } return B0; /* not reached */ } void trs_uart_init(int reset_button) { int err; #if UARTDEBUG debug("trs_uart_init\n"); #endif if (initialized == 1 && uart.fd != -1) close(uart.fd); if (trs_uart_name == NULL || trs_uart_name[0] == '\000') { /* Emulate having no serial port */ initialized = -1; return; } initialized = 1; uart.fd = open(trs_uart_name, O_RDWR|O_NOCTTY|O_NONBLOCK); if (uart.fd == -1) { error("can't open %s: %s", trs_uart_name, strerror(errno)); } else { uart.fdflags = FNONBLOCK; err = tcgetattr(uart.fd, &uart.t); if (err < 0) { error("can't get attributes of %s: %s", trs_uart_name, strerror(errno)); } } uart.t.c_iflag = 0; uart.t.c_oflag = 0; uart.t.c_lflag = 0; memset(uart.t.c_cc, 0, sizeof(uart.t.c_cc)); /* Not readable from a user process on unix */ uart.modem = TRS_UART_CTS | TRS_UART_DSR | TRS_UART_CD; uart.switches = (trs_model == 1) ? trs_uart_switches : 0xff; /* arbitrary default */ uart.baud = -1; trs_uart_baud_out((TRS_UART_9600 << 4) + TRS_UART_9600); /* arbitrary default */ uart.control = -1; trs_uart_control_out(TRS_UART_NOPAR | TRS_UART_WORD8 | TRS_UART_NOTBREAK | TRS_UART_DTR | TRS_UART_RTS); uart.status = TRS_UART_SENT; trs_uart_snd_interrupt(1); uart.bufp = uart.buf; uart.bufleft = 0; } int trs_uart_modem_in() { /* should poll hardware here, if we could */ if (initialized == 0) trs_uart_init(0); if (initialized == -1) return 0xff; #if UARTDEBUG2 debug("trs_uart_modem_in returns 0x%02x\n", uart.modem); #endif return uart.modem; } void trs_uart_reset_out(int value) { #if UARTDEBUG debug("trs_uart_reset_out\n"); #endif if (initialized == 0) trs_uart_init(0); if (initialized == -1) { error("serial port emulation is not enabled"); return; } } int trs_uart_switches_in() { if (initialized == 0) trs_uart_init(0); if (initialized == -1) return 0xff; #if UARTDEBUG debug("trs_uart_switches_in returns 0x%02x\n", uart.switches); #endif return uart.switches; } void trs_uart_baud_out(int value) { int err; int bits; #if UARTDEBUG debug("trs_uart_baud_out 0x%02x\n", value); #endif if (initialized == 1 && uart.baud == value) return; if (initialized == 0) trs_uart_init(0); if (initialized == -1) return; uart.baud = value; cfsetispeed(&uart.t, xlate_baud(TRS_UART_RCVBAUD(value))); cfsetospeed(&uart.t, xlate_baud(TRS_UART_SNDBAUD(value))); bits = 1 + trs_uart_wordbits[TRS_UART_WORDBITS(uart.control)] + ((uart.control & TRS_UART_NOPAR) ? 0 : 1) + ((uart.control & TRS_UART_STOP2) ? 2 : 1); uart.tstates = (z80_state.clockMHz * 1000000.0 * bits) / trs_uart_baud[TRS_UART_SNDBAUD(value)]; #if UARTDEBUG debug("total bits %d; tstates per word %d\n", bits, uart.tstates); #endif if (uart.fd != -1) { err = tcsetattr(uart.fd, TCSADRAIN, &uart.t); if (err == -1) { error("can't set attributes of %s: %s", trs_uart_name, strerror(errno)); } } } void trs_uart_set_avail(int dummy) { uart.status |= TRS_UART_RCVD; trs_uart_rcv_interrupt(1); } void trs_uart_set_empty(int dummy) { uart.status |= TRS_UART_SENT; trs_uart_snd_interrupt(1); } int trs_uart_check_avail() { if (initialized == 1 && uart.bufleft == 0 && uart.fd != -1) { /* check for data available */ int rc; if (!(uart.fdflags & FNONBLOCK)) { #if UARTDEBUG debug("trs_uart nonblocking\n"); #endif uart.fdflags |= FNONBLOCK; fcntl(uart.fd, F_SETFL, uart.fdflags); } do { rc = read(uart.fd, uart.buf, BUFSIZE); } while (rc < 0 && errno == EINTR); #if UARTDEBUG #if !UARTDEBUG2 if (rc >= 0 || errno != EAGAIN) #endif debug("trs_uart read returns %d, errno %d\n", rc, errno); #endif if (rc < 0) { if (errno != EAGAIN) { error("can't read from %s: %s", trs_uart_name, strerror(errno)); } rc = 0; } uart.bufp = uart.buf; uart.bufleft = rc; if (rc > 0) { /* be sure events don't happen too fast */ trs_schedule_event(trs_uart_set_avail, 1, uart.tstates); } } #if UARTDEBUG2 debug("trs_uart_check_avail returns %d\n", uart.bufleft); #endif return uart.bufleft; } int trs_uart_status_in() { #if UARTDEBUG static int oldstatus = -1; #endif if (initialized == 0) trs_uart_init(0); if (initialized == -1) return 0xff; trs_uart_check_avail(); #if UARTDEBUG if (uart.status != oldstatus) { debug("trs_uart_status_in returns 0x%02x\n", uart.status); oldstatus = uart.status; } #endif return uart.status; } void trs_uart_control_out(int value) { int err; int cflag = HUPCL|CREAD|CLOCAL; #if UARTDEBUG debug("trs_uart_control_out 0x%02x\n", value); #endif if (initialized == 1 && uart.control == value) return; if (initialized == 0) trs_uart_init(0); if (initialized == -1) return; uart.control = value; if (!(value & TRS_UART_EVENPAR)) cflag |= PARODD; switch (value & TRS_UART_WORDMASK) { case TRS_UART_WORD5: cflag |= CS5; break; case TRS_UART_WORD6: cflag |= CS6; break; case TRS_UART_WORD7: cflag |= CS7; break; case TRS_UART_WORD8: cflag |= CS8; break; } if (value & TRS_UART_STOP2) cflag |= CSTOPB; if (!(value & TRS_UART_NOPAR)) cflag |= PARENB; uart.t.c_cflag = cflag; if (uart.fd != -1) { err = tcsetattr(uart.fd, TCSADRAIN, &uart.t); if (err == -1) { error("can't set attributes of %s: %s", trs_uart_name, strerror(errno)); } } if (!(value & TRS_UART_NOTBREAK) && uart.fd != -1) { sigset_t set, oldset; sigemptyset(&set); sigaddset(&set, SIGALRM); sigprocmask(SIG_BLOCK, &set, &oldset); err = tcsendbreak(uart.fd, 0); sigprocmask(SIG_SETMASK, &oldset, NULL); if (err == -1) { error("can't send break on %s: %s", trs_uart_name, strerror(errno)); } } } int trs_uart_data_in() { if (initialized == 0) trs_uart_init(0); if (initialized == -1) return 0xff; trs_uart_check_avail(); if (uart.status & TRS_UART_RCVD) { uart.status &= ~TRS_UART_RCVD; trs_uart_rcv_interrupt(0); uart.bufleft--; uart.idata = *uart.bufp++; if (uart.bufleft) { trs_schedule_event(trs_uart_set_avail, 1, uart.tstates); } } #if UARTDEBUG debug("trs_uart_data_in returns 0x%02x\n", uart.idata); #endif return uart.idata; } void trs_uart_data_out(int value) { int err; #if UARTDEBUG debug("trs_uart_data_out 0x%02x\n", value); #endif if (initialized == 0) trs_uart_init(0); if (initialized == -1) return; uart.odata = value; if (uart.fd != -1) { for (;;) { err = write(uart.fd, &uart.odata, 1); if (err >= 0) return; if (errno != EAGAIN) { error("can't read from %s: %s", trs_uart_name, strerror(errno)); return; } /* Oops, here we didn't really want nonblocking i/o */ #if UARTDEBUG debug("trs_uart blocking\n"); #endif uart.fdflags &= ~FNONBLOCK; fcntl(uart.fd, F_SETFL, uart.fdflags); } trs_uart_snd_interrupt(0); trs_schedule_event(trs_uart_set_empty, 1, uart.tstates); } } xtrs-4.9d/trs_uart.h000066400000000000000000000056411306603614600145610ustar00rootroot00000000000000/* Copyright (c) 2000, Timothy Mann */ /* $Id: trs_uart.h,v 1.2 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* * Emulation of the Radio Shack TRS-80 Model I/III/4/4P serial port. */ #include #include "trs.h" #include "trs_hard.h" extern void trs_uart_init(int reset_button); extern int trs_uart_check_avail(); extern int trs_uart_modem_in(); extern void trs_uart_reset_out(int value); extern int trs_uart_switches_in(); extern void trs_uart_baud_out(int value); extern int trs_uart_status_in(); extern void trs_uart_control_out(int value); extern int trs_uart_data_in(); extern void trs_uart_data_out(int value); extern char *trs_uart_name; extern int trs_uart_switches; #define TRS_UART_MODEM 0xE8 /* in */ #define TRS_UART_RESET 0xE8 /* out */ #define TRS_UART_SWITCHES 0xE9 /* in, model I only */ #define TRS_UART_BAUD 0xE9 /* out */ #define TRS_UART_STATUS 0xEA /* in */ #define TRS_UART_CONTROL 0xEA /* out */ #define TRS_UART_DATA 0xEB /* in/out */ /* Bits in TRS_UART_MODEM port */ #define TRS_UART_CTS 0x80 #define TRS_UART_DSR 0x40 #define TRS_UART_CD 0x20 #define TRS_UART_RI 0x10 #define TRS_UART_RCVIN 0x02 /* Bits in TRS_UART_BAUD port */ #define TRS_UART_SNDBAUD(v) (((v)&0xf0)>>4) #define TRS_UART_RCVBAUD(v) (((v)&0x0f)>>0) #define TRS_UART_50 0x00 #define TRS_UART_75 0x01 #define TRS_UART_110 0x02 #define TRS_UART_134 0x03 #define TRS_UART_150 0x04 #define TRS_UART_300 0x05 #define TRS_UART_600 0x06 #define TRS_UART_1200 0x07 #define TRS_UART_1800 0x08 #define TRS_UART_2000 0x09 #define TRS_UART_2400 0x0a #define TRS_UART_3600 0x0b #define TRS_UART_4800 0x0c #define TRS_UART_7200 0x0d #define TRS_UART_9600 0x0e #define TRS_UART_19200 0x0f #define TRS_UART_BAUD_TABLE \ { 50.0, 75.0, 110.0, 134.5, 150.0, 300.0, 600.0, 1200.0, 1800.0, \ 2000.0, 2400.0, 3600.0, 4800.0, 7200.0, 9600.0, 19200.0 } /* Bits in TRS_UART_STATUS port */ #define TRS_UART_RCVD 0x80 #define TRS_UART_SENT 0x40 #define TRS_UART_OVRERR 0x20 #define TRS_UART_FRMERR 0x10 #define TRS_UART_PARERR 0x08 /* Bits in TRS_UART_CONTROL port */ #define TRS_UART_EVENPAR 0x80 #define TRS_UART_WORDMASK 0x60 #define TRS_UART_WORD5 0x00 #define TRS_UART_WORD6 0x40 #define TRS_UART_WORD7 0x20 #define TRS_UART_WORD8 0x60 #define TRS_UART_WORDBITS(v) (((v)&TRS_UART_WORDMASK)>>5) #define TRS_UART_WORDBITS_TABLE { 5, 7, 6, 8 } #define TRS_UART_STOP2 0x10 #define TRS_UART_NOPAR 0x08 #define TRS_UART_NOTBREAK 0x04 #define TRS_UART_DTR 0x02 /* mislabelled as RTS in Model I manual */ #define TRS_UART_RTS 0x01 /* mislabelled as DTR in Model I manual */ xtrs-4.9d/trs_xinterface.c000066400000000000000000001732761306603614600157430ustar00rootroot00000000000000/* * Copyright (C) 1992 Clarendon Hill Software. * * Permission is granted to any individual or institution to use, copy, * or redistribute this software, provided this copyright notice is retained. * * This software is provided "as is" without any expressed or implied * warranty. If this software brings on any sort of damage -- physical, * monetary, emotional, or brain -- too bad. You've got no one to blame * but yourself. * * The software may be modified for your own purposes, but modified versions * must retain this notice. */ /* Modified by Timothy Mann, 1996 and later $Id: trs_xinterface.c,v 1.47 2009/06/16 02:37:16 mann Exp $ */ /*#define MOUSEDEBUG 1*/ /*#define XDEBUG 1*/ /*#define QDEBUG 1*/ /* * trs_xinterface.c * * X Windows interface for TRS-80 simulator */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "trs_iodefs.h" #include "trs.h" #include "z80.h" #include "trs_disk.h" #include "trs_uart.h" #include "trs_imp_exp.h" #define DEF_FONT1 "-misc-fixed-medium-r-normal--20-200-75-75-*-100-iso8859-1" #define DEF_WIDEFONT1 "-misc-fixed-medium-r-normal--20-200-75-75-*-200-iso8859-1" #define DEF_FONT3 "-misc-fixed-medium-r-normal--20-200-75-75-*-100-iso8859-1" #define DEF_WIDEFONT3 "-misc-fixed-medium-r-normal--20-200-75-75-*-200-iso8859-1" #define DEF_USEFONT 0 extern char trs_char_data[][MAXCHARS][TRS_CHAR_HEIGHT]; #define EVENT_MASK \ ExposureMask | KeyPressMask | MapRequest | KeyReleaseMask | \ StructureNotifyMask | LeaveWindowMask #define MAX_SCALE 4 /* Private data */ static unsigned char trs_screen[2048]; static int screen_chars = 1024; static int row_chars = 64; static int col_chars = 16; static int resize = 0; static int top_margin = 0; static int left_margin = 0; static int border_width = 2; static Pixmap trs_char[2][MAXCHARS]; static Pixmap trs_box[2][64]; static Display *display; static int screen; static Window window; static Window help_window; static int unmap_help_window = 0; static GC gc; static GC gc_inv; static GC gc_xor; static int currentmode = NORMAL; static int OrigHeight,OrigWidth; static int usefont = DEF_USEFONT; static int cur_char_width = TRS_CHAR_WIDTH; static int cur_char_height = TRS_CHAR_HEIGHT * 2; static int text80x24 = 0, screen640x240 = 0; static XFontStruct *myfont, *mywidefont, *curfont; static XKeyboardState repeat_state; static int trs_charset; static int scale_x = 1; static int scale_y = 2; static XrmOptionDescRec opts[] = { /* Option */ /* Resource */ /* Value from arg? */ /* Value if no arg */ {"-iconic", "*iconic", XrmoptionNoArg, (caddr_t)""}, {"-background", "*background", XrmoptionSepArg, (caddr_t)NULL}, {"-bg", "*background", XrmoptionSepArg, (caddr_t)NULL}, {"-foreground", "*foreground", XrmoptionSepArg, (caddr_t)NULL}, {"-fg", "*foreground", XrmoptionSepArg, (caddr_t)NULL}, {"-borderwidth","*borderwidth", XrmoptionSepArg, (caddr_t)NULL}, {"-usefont", "*usefont", XrmoptionNoArg, (caddr_t)"on"}, {"-nofont", "*usefont", XrmoptionNoArg, (caddr_t)"off"}, {"-font", "*font", XrmoptionSepArg, (caddr_t)NULL}, {"-widefont", "*widefont", XrmoptionSepArg, (caddr_t)NULL}, {"-display", "*display", XrmoptionSepArg, (caddr_t)NULL}, {"-debug", "*debug", XrmoptionNoArg, (caddr_t)"on"}, {"-nodebug", "*debug", XrmoptionNoArg, (caddr_t)"off"}, {"-romfile", "*romfile", XrmoptionSepArg, (caddr_t)NULL}, {"-romfile3", "*romfile3", XrmoptionSepArg, (caddr_t)NULL}, {"-romfile4p", "*romfile4p", XrmoptionSepArg, (caddr_t)NULL}, {"-resize", "*resize", XrmoptionNoArg, (caddr_t)"on"}, {"-noresize", "*resize", XrmoptionNoArg, (caddr_t)"off"}, {"-doublestep", "*doublestep", XrmoptionNoArg, (caddr_t)"on"}, {"-nodoublestep","*doublestep", XrmoptionNoArg, (caddr_t)"off"}, {"-model", "*model", XrmoptionSepArg, (caddr_t)NULL}, {"-model1", "*model", XrmoptionNoArg, (caddr_t)"1"}, {"-model3", "*model", XrmoptionNoArg, (caddr_t)"3"}, {"-model4", "*model", XrmoptionNoArg, (caddr_t)"4"}, {"-model4p", "*model", XrmoptionNoArg, (caddr_t)"4p"}, {"-diskdir", "*diskdir", XrmoptionSepArg, (caddr_t)NULL}, {"-delay", "*delay", XrmoptionSepArg, (caddr_t)NULL}, {"-autodelay", "*autodelay", XrmoptionNoArg, (caddr_t)"on"}, {"-noautodelay","*autodelay", XrmoptionNoArg, (caddr_t)"off"}, {"-keystretch", "*keystretch", XrmoptionSepArg, (caddr_t)NULL}, {"-microlabs", "*microlabs", XrmoptionNoArg, (caddr_t)"on"}, {"-nomicrolabs","*microlabs", XrmoptionNoArg, (caddr_t)"off"}, {"-doubler", "*doubler", XrmoptionSepArg, (caddr_t)NULL}, {"-sizemap", "*sizemap", XrmoptionSepArg, (caddr_t)NULL}, {"-stepmap", "*stepmap", XrmoptionSepArg, (caddr_t)NULL}, {"-charset", "*charset", XrmoptionSepArg, (caddr_t)NULL}, {"-truedam", "*truedam", XrmoptionNoArg, (caddr_t)"on"}, {"-notruedam", "*truedam", XrmoptionNoArg, (caddr_t)"off"}, {"-samplerate", "*samplerate", XrmoptionSepArg, (caddr_t)NULL}, {"-title", "*title", XrmoptionSepArg, (caddr_t)NULL}, {"-scale", "*scale", XrmoptionSepArg, (caddr_t)NULL}, {"-scale1", "*scale", XrmoptionNoArg, (caddr_t)"1"}, {"-scale2", "*scale", XrmoptionNoArg, (caddr_t)"2"}, {"-scale3", "*scale", XrmoptionNoArg, (caddr_t)"3"}, {"-scale4", "*scale", XrmoptionNoArg, (caddr_t)"4"}, {"-serial", "*serial", XrmoptionSepArg, (caddr_t)NULL}, {"-switches", "*switches", XrmoptionSepArg, (caddr_t)NULL}, {"-shiftbracket","*shiftbracket",XrmoptionNoArg, (caddr_t)"on"}, {"-noshiftbracket","*shiftbracket",XrmoptionNoArg, (caddr_t)"off"}, #if __linux {"-sb", "*sb", XrmoptionSepArg, (caddr_t)NULL}, #endif /* linux */ {"-emtsafe", "*emtsafe", XrmoptionNoArg, (caddr_t)"on"}, {"-noemtsafe", "*emtsafe", XrmoptionNoArg, (caddr_t)"off"}, }; static int num_opts = (sizeof opts / sizeof opts[0]); /* Support for Micro Labs Grafyx Solution and Radio Shack hi-res card */ /* True size of graphics memory -- some is offscreen */ #define G_XSIZE 128 #define G_YSIZE 256 char grafyx[(2*G_YSIZE*MAX_SCALE) * (G_XSIZE*MAX_SCALE)]; unsigned char grafyx_unscaled[G_YSIZE][G_XSIZE]; unsigned char grafyx_microlabs = 0; unsigned char grafyx_x = 0, grafyx_y = 0, grafyx_mode = 0; unsigned char grafyx_enable = 0; unsigned char grafyx_overlay = 0; unsigned char grafyx_xoffset = 0, grafyx_yoffset = 0; /* Port 0x83 (grafyx_mode) bits */ #define G_ENABLE 1 #define G_UL_NOTEXT 2 /* Micro Labs only */ #define G_RS_WAIT 2 /* Radio Shack only */ #define G_XDEC 4 #define G_YDEC 8 #define G_XNOCLKR 16 #define G_YNOCLKR 32 #define G_XNOCLKW 64 #define G_YNOCLKW 128 /* Port 0xFF (grafyx_m3_mode) bits */ #define G3_COORD 0x80 #define G3_ENABLE 0x40 #define G3_COMMAND 0x20 #define G3_YLOW(v) (((v)&0x1e)>>1) XImage image = { /*width, height*/ 8*G_XSIZE, 2*G_YSIZE, /* if scale_x=1, scale_y=2 */ /*xoffset*/ 0, /*format*/ XYBitmap, /*data*/ (char*)grafyx, /*byte_order*/ LSBFirst, /*bitmap_unit*/ 8, /*bitmap_bit_order*/ MSBFirst, /*bitmap_pad*/ 8, /*depth*/ 1, /*bytes_per_line*/ G_XSIZE, /* if scale = 1 */ /*bits_per_pixel*/ 1, /*red_mask*/ 1, /*green_mask*/ 1, /*blue_mask*/ 1, /*obdata*/ NULL, /*f*/ { NULL, NULL, NULL, NULL, NULL, NULL } }; #define HRG_MEMSIZE (1024 * 12) /* 12k * 8 bit graphics memory */ static unsigned char hrg_screen[HRG_MEMSIZE]; static int hrg_pixel_x[2][6+1]; static int hrg_pixel_y[12+1]; static int hrg_pixel_width[2][6]; static int hrg_pixel_height[12]; static int hrg_enable = 0; static int hrg_addr = 0; static void hrg_update_char(int position); /* dummy buffer for stat() call */ struct stat statbuf; /* Private routines */ void bitmap_init(); void screen_init(); void trs_event_init(); void trs_event(); static XrmDatabase x_db = NULL; static XrmDatabase command_db = NULL; extern char *program_name; char *title; int trs_parse_command_line(int argc, char **argv, int *debug) { char option[512]; char *type; XrmValue value; char *xrms, *tmp; int stepdefault, i, s[8]; title = program_name; /* default */ XrmInitialize(); /* parse command line options */ XrmParseCommand(&command_db,opts,num_opts,program_name,&argc,argv); (void) sprintf(option, "%s%s", program_name, ".display"); (void) XrmGetResource(command_db, option, "Xtrs.Display", &type, &value); /* open display */ if ( (display = XOpenDisplay (value.addr)) == NULL) { fprintf(stderr, "Unable to open display."); exit(-1); } /* get defaults from server */ xrms = XResourceManagerString(display); if (xrms != NULL) { x_db = XrmGetStringDatabase(xrms); XrmMergeDatabases(command_db,&x_db); } else { x_db = command_db; } /* get defaults from $HOME/.Xdefaults and $HOME/Xtrs */ if ((tmp = getenv("HOME"))) { sprintf(option, "%s/%s", tmp, ".Xdefaults"); XrmCombineFileDatabase(option, &x_db, False); sprintf(option, "%s/%s", tmp, "Xtrs"); XrmCombineFileDatabase(option, &x_db, False); } /* get defaults from /usr/X11/lib/X11/app-defaults/Xtrs */ #ifdef APPDEFAULTS sprintf(option, "%s/%s", APPDEFAULTS, "Xtrs"); XrmCombineFileDatabase(option, &x_db, False); #endif (void) sprintf(option, "%s%s", program_name, ".scale"); if (XrmGetResource(x_db, option, "Xtrs.Scale", &type, &value)) { if (sscanf(value.addr, "%d,%d", &scale_x, &scale_y) < 2) scale_y = scale_x * 2; if (scale_x <= 0) scale_x = 1; if (scale_x > MAX_SCALE) scale_x = MAX_SCALE; if (scale_y <= 0) scale_y = 1; if (scale_y > MAX_SCALE * 2) scale_y = MAX_SCALE * 2; } image.width *= scale_x; image.height = image.height * scale_y / 2; image.bytes_per_line *= scale_x; #if __linux (void) sprintf(option, "%s%s", program_name, ".sb"); if (XrmGetResource(x_db, option, "Xtrs.Sb", &type, &value)) { char *next; int ioport, vol; ioport = strtol(value.addr, &next, 0); if(*next == ',') { next++; vol=atoi(next); trs_sound_init(ioport, vol); /* requires root privilege */ } } setuid(getuid()); #endif /* linux */ (void) sprintf(option, "%s%s", program_name, ".emtsafe"); if (XrmGetResource(x_db, option, "Xtrs.Emtsafe", &type, &value)) { if (strcmp(value.addr,"on") == 0) { trs_emtsafe = True; } else if (strcmp(value.addr,"off") == 0) { trs_emtsafe = False; } } (void) sprintf(option, "%s%s", program_name, ".debug"); if (XrmGetResource(x_db, option, "Xtrs.Debug", &type, &value)) { if (strcmp(value.addr,"on") == 0) { *debug = True; } else if (strcmp(value.addr,"off") == 0) { *debug = False; } } (void) sprintf(option, "%s%s", program_name, ".autodelay"); if (XrmGetResource(x_db, option, "Xtrs.Autodelay", &type, &value)) { if (strcmp(value.addr,"on") == 0) { trs_autodelay = True; } else if (strcmp(value.addr,"off") == 0) { trs_autodelay = False; } } (void) sprintf(option, "%s%s", program_name, ".model"); if (XrmGetResource(x_db, option, "Xtrs.Model", &type, &value)) { if (strcmp(value.addr, "1") == 0 || strcasecmp(value.addr, "I") == 0) { trs_model = 1; } else if (strcmp(value.addr, "3") == 0 || strcasecmp(value.addr, "III") == 0) { trs_model = 3; } else if (strcmp(value.addr, "4") == 0 || strcasecmp(value.addr, "IV") == 0) { trs_model = 4; } else if (strcasecmp(value.addr, "4P") == 0 || strcasecmp(value.addr, "IVp") == 0) { trs_model = 5; } else { fatal("TRS-80 Model %s not supported", value.addr); } } /* !!Note: charset numbers must match trs_chars.c */ if (trs_model == 1) { char *charset_name = "wider"; /* default */ (void) sprintf(option, "%s%s", program_name, ".charset"); if (XrmGetResource(x_db, option, "Xtrs.Charset", &type, &value)) { charset_name = (char*) value.addr; } if (isdigit(*charset_name)) { trs_charset = atoi(charset_name); cur_char_width = 8 * scale_x; } else { if (charset_name[0] == 'e'/*early*/) { trs_charset = 0; cur_char_width = 6 * scale_x; } else if (charset_name[0] == 's'/*stock*/) { trs_charset = 1; cur_char_width = 6 * scale_x; } else if (charset_name[0] == 'l'/*lcmod*/) { trs_charset = 2; cur_char_width = 6 * scale_x; } else if (charset_name[0] == 'w'/*wider*/) { trs_charset = 3; cur_char_width = 8 * scale_x; } else if (charset_name[0] == 'g'/*genie or german*/) { trs_charset = 10; cur_char_width = 8 * scale_x; } else { fatal("unknown charset name %s", value.addr); } } cur_char_height = TRS_CHAR_HEIGHT * scale_y; } else /* trs_model > 1 */ { char *charset_name; /* Set default */ if (trs_model == 3) { charset_name = "katakana"; } else { charset_name = "international"; } (void) sprintf(option, "%s%s", program_name, ".charset"); if (XrmGetResource(x_db, option, "Xtrs.Charset", &type, &value)) { charset_name = (char*) value.addr; } if (isdigit(*charset_name)) { trs_charset = atoi(charset_name); } else { if (charset_name[0] == 'k'/*katakana*/) { trs_charset = 4 + 3*(trs_model > 3); } else if (charset_name[0] == 'i'/*international*/) { trs_charset = 5 + 3*(trs_model > 3); } else if (charset_name[0] == 'b'/*bold*/) { trs_charset = 6 + 3*(trs_model > 3); } else { fatal("unknown charset name %s", value.addr); } } cur_char_width = TRS_CHAR_WIDTH * scale_x; cur_char_height = TRS_CHAR_HEIGHT * scale_y; } (void) sprintf(option, "%s%s", program_name, ".diskdir"); if (XrmGetResource(x_db, option, "Xtrs.Diskdir", &type, &value)) { trs_disk_dir = strdup(value.addr); } if (trs_disk_dir[0] == '~' && (trs_disk_dir[1] == '/' || trs_disk_dir[1] == '\0')) { char* home = getenv("HOME"); if (home) { char *p = (char*)malloc(strlen(home) + strlen(trs_disk_dir) + 1); sprintf(p, "%s/%s", home, trs_disk_dir+1); trs_disk_dir = p; } } (void) sprintf(option, "%s%s", program_name, ".delay"); if (XrmGetResource(x_db, option, "Xtrs.Delay", &type, &value)) { z80_state.delay = strtol(value.addr, NULL, 0); } (void) sprintf(option, "%s%s", program_name, ".keystretch"); if (XrmGetResource(x_db, option, "Xtrs.Keystretch", &type, &value)) { if (strchr(value.addr, ',')) { fatal("-keystretch now takes only one argument; see man page"); } stretch_amount = strtol(value.addr, NULL, 0); } (void) sprintf(option, "%s%s", program_name, ".microlabs"); if (XrmGetResource(x_db, option, "Xtrs.Microlabs", &type, &value)) { if (strcmp(value.addr,"on") == 0) { grafyx_set_microlabs(True); } else if (strcmp(value.addr,"off") == 0) { grafyx_set_microlabs(False); } } (void) sprintf(option, "%s%s", program_name, ".doubler"); if (XrmGetResource(x_db, option, "Xtrs.Doubler", &type, &value)) { switch (*(char*)value.addr) { case 'p': case 'P': trs_disk_doubler = TRSDISK_PERCOM; break; case 'r': case 'R': case 't': case 'T': trs_disk_doubler = TRSDISK_TANDY; break; case 'b': case 'B': default: trs_disk_doubler = TRSDISK_BOTH; break; case 'n': case 'N': trs_disk_doubler = TRSDISK_NODOUBLER; break; } } /* Defaults for sizemap */ s[0] = 5; s[1] = 5; s[2] = 5; s[3] = 5; s[4] = 8; s[5] = 8; s[6] = 8; s[7] = 8; (void) sprintf(option, "%s%s", program_name, ".sizemap"); if (XrmGetResource(x_db, option, "Xtrs.Sizemap", &type, &value)) { sscanf((char*)value.addr, "%d,%d,%d,%d,%d,%d,%d,%d", &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7]); } for (i=0; i<=7; i++) { if (s[i] != 5 && s[i] != 8) { fatal("bad value %d for disk %d size", s[i], i); } else { trs_disk_setsize(i, s[i]); } } /* Defaults for stepmap */ (void) sprintf(option, "%s%s", program_name, ".doublestep"); stepdefault = 1; if (XrmGetResource(x_db, option, "Xtrs.doublestep", &type, &value)) { if (strcmp(value.addr,"on") == 0) { stepdefault = 2; } else if (strcmp(value.addr,"off") == 0) { stepdefault = 1; } } for (i=0; i<=7; i++) { s[i] = stepdefault; } (void) sprintf(option, "%s%s", program_name, ".stepmap"); if (XrmGetResource(x_db, option, "Xtrs.Stepmap", &type, &value)) { sscanf((char*)value.addr, "%d,%d,%d,%d,%d,%d,%d,%d", &s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6], &s[7]); } for (i=0; i<=7; i++) { if (s[i] != 1 && s[i] != 2) { fatal("bad value %d for disk %d single/double step\n", s[i], i); } else { trs_disk_setstep(i, s[i]); } } (void) sprintf(option, "%s%s", program_name, ".truedam"); if (XrmGetResource(x_db, option, "Xtrs.Truedam", &type, &value)) { if (strcmp(value.addr,"on") == 0) { trs_disk_truedam = True; } else if (strcmp(value.addr,"off") == 0) { trs_disk_truedam = False; } } (void) sprintf(option, "%s%s", program_name, ".samplerate"); if (XrmGetResource(x_db, option, "Xtrs.Samplerate", &type, &value)) { cassette_default_sample_rate = strtol(value.addr, NULL, 0); } (void) sprintf(option, "%s%s", program_name, ".title"); if (XrmGetResource(x_db, option, "Xtrs.title", &type, &value)) { title = strdup(value.addr); } (void) sprintf(option, "%s%s", program_name, ".serial"); if (XrmGetResource(x_db, option, "Xtrs.serial", &type, &value)) { trs_uart_name = strdup(value.addr); } (void) sprintf(option, "%s%s", program_name, ".switches"); if (XrmGetResource(x_db, option, "Xtrs.serial", &type, &value)) { trs_uart_switches = strtol(value.addr, NULL, 0); } (void) sprintf(option, "%s%s", program_name, ".shiftbracket"); if (XrmGetResource(x_db, option, "Xtrs.Shiftbracket", &type, &value)) { if (strcmp(value.addr,"on") == 0) { trs_kb_bracket(True); } else if (strcmp(value.addr,"off") == 0) { trs_kb_bracket(False); } } else { trs_kb_bracket(trs_model >= 4); } return argc; } static void save_repeat() { XGetKeyboardControl(display, &repeat_state); XAutoRepeatOff(display); XSync(display, False); } static void restore_repeat() { if (repeat_state.global_auto_repeat == AutoRepeatModeOn) { XAutoRepeatOn(display); XSync(display, False); } } void trs_fix_size (Window window, int width, int height) { XSizeHints sizehints; sizehints.flags = PMinSize | PMaxSize | PBaseSize; sizehints.min_width = width; sizehints.max_width = width; sizehints.base_width = width; sizehints.min_height = height; sizehints.max_height = height; sizehints.base_height = height; XSetWMNormalHints(display, window, &sizehints); } int trs_screen_batched = 0; void trs_screen_batch() { #if BATCH /* Defer screen updates until trs_screen_unbatch, then redraw screen if anything changed. Unfortunately, this seems to slow things down, so it's disabled. Probably what we should really be doing is rendering into an offscreen buffer when trs_screen_batched is set, then copying to the real screen in trs_screen_unbatch. Also (and orthogonally) we should probably be keeping track of what part of the screen changed and only redrawing that part. */ trs_screen_batched = 1; #endif } void trs_screen_unbatch() { #if BATCH if (trs_screen_batched > 1) { trs_screen_batched = 0; trs_screen_refresh(); } else { trs_screen_batched = 0; } #endif } /* * show help */ void trs_show_help() { XWindowAttributes parent_attrs; unsigned int help_width = 495; unsigned int help_height = 365; unsigned int help_xpos, help_ypos; unsigned long foreground, background; GC help_gc; XGCValues values; char *help_font_name = "9x15"; XFontStruct *help_font_info; int font_height; int text_line; int i; static char *helpitems[] = { "F1: Model 4/4P F1 key", "F2: Model 4/4P F2 key", "F3: Model 4/4P F3 key", "F4: Model 4/4P caps lock key", "F5: TRS-80 @ key", "F6: TRS-80 0 key", "F7: signal disk change in emulated floppy drive", "F8: exit emulator", "F9: enter zbx debugger", "F10: TRS-80 reset button", "", "LeftArrow, Backspace, Delete: TRS-80 left arrow key", "RightArrow, Tab: TRS-80 right arrow key", "UpArrow: TRS-80 up arrow key", "DownArrow, Linefeed: TRS-80 down arrow key", "", "Esc, Break: TRS-80 break key", "Home, Clear, LeftAlt: TRS-80 clear key", "Control: Model 4/4P control key", "RightAlt: shifted TRS-80 down arrow key", "", "F11 toggles this help.", "See the xtrs(1) manual page for more information.", NULL }; foreground = BlackPixel(display, screen); background = WhitePixel(display, screen); (void) XGetWindowAttributes(display, window, &parent_attrs); if ((parent_attrs.width < help_width) || (parent_attrs.height < help_height)) { (void) fprintf(stderr, "%s: cannot display help window; parent window" " dimensions not large enough to contain it\n", program_name); return; } help_xpos = (parent_attrs.width - help_width) / 2; help_ypos = (parent_attrs.height - help_height) / 2; help_window = XCreateSimpleWindow(display, window, help_xpos, help_ypos, help_width, help_height, 1, foreground, background); help_font_info = XLoadQueryFont(display, help_font_name); if (NULL == help_font_info) { (void) fprintf(stderr, "%s: cannot display help window; cannot open" " \"%s\" font\n", program_name, help_font_name); return; } help_gc = XCreateGC(display, help_window, 0, &values); XSetFont(display, help_gc, help_font_info->fid); XSetBackground(display, help_gc, WhitePixel(display,screen)); XSetForeground(display, help_gc, BlackPixel(display,screen)); font_height = help_font_info->ascent + help_font_info->descent; text_line = font_height; XMapWindow(display, help_window); for (i = 0; NULL != helpitems[i]; i++) { size_t len; int text_width; len = strlen(helpitems[i]); text_width = XTextWidth(help_font_info, helpitems[i], len); XDrawString(display, help_window, help_gc, 10, text_line, helpitems[i], len); text_line += font_height; } return; } /* exits if something really bad happens */ void trs_screen_init() { Window root_window; unsigned long fore_pixel, back_pixel, foreground, background; char option[512]; char *type; XrmValue value; Colormap color_map; XColor cdef; XGCValues gcvals; char *fontname = NULL; char *widefontname = NULL; int len; char *romfile = NULL; screen = DefaultScreen(display); color_map = DefaultColormap(display,screen); (void) sprintf(option, "%s%s", program_name, ".foreground"); if (XrmGetResource(x_db, option, "Xtrs.Foreground", &type, &value)) { /* debug("foreground is %s\n",value.addr); */ XParseColor(display, color_map, value.addr, &cdef); XAllocColor(display, color_map, &cdef); fore_pixel = cdef.pixel; } else { fore_pixel = WhitePixel(display, screen); } (void) sprintf(option, "%s%s", program_name, ".background"); if (XrmGetResource(x_db, option, "Xtrs.Background", &type, &value)) { XParseColor(display, color_map, value.addr, &cdef); XAllocColor(display, color_map, &cdef); back_pixel = cdef.pixel; } else { back_pixel = BlackPixel(display, screen); } (void) sprintf(option, "%s%s", program_name, ".borderwidth"); if (XrmGetResource(x_db, option, "Xtrs.Borderwidth", &type, &value)) { if ((border_width = atoi(value.addr)) < 0) border_width = 0; } else { border_width = 2; } (void) sprintf(option, "%s%s", program_name, ".usefont"); if (XrmGetResource(x_db, option, "Xtrs.Usefont", &type, &value)) { if (strcmp(value.addr,"on") == 0) { usefont = 1; } else if (strcmp(value.addr,"off") == 0) { usefont = 0; } } if (usefont) { (void) sprintf(option, "%s%s", program_name, ".font"); if (XrmGetResource(x_db, option, "Xtrs.Font", &type, &value)) { len = strlen(value.addr); fontname = malloc(len + 1); strcpy(fontname,value.addr); } else { char *def_font = (trs_model == 1 ? DEF_FONT1 : DEF_FONT3); len = strlen(def_font); fontname = malloc(len+1); strcpy(fontname, def_font); } (void) sprintf(option, "%s%s", program_name, ".widefont"); if (XrmGetResource(x_db, option, "Xtrs.Widefont", &type, &value)) { len = strlen(value.addr); widefontname = malloc(len + 1); strcpy(widefontname,value.addr); } else { char *def_widefont = (trs_model == 1 ? DEF_WIDEFONT1 : DEF_WIDEFONT3); len = strlen(def_widefont); widefontname = malloc(len+1); strcpy(widefontname, def_widefont); } } switch (trs_model) { case 1: (void) sprintf(option, "%s%s", program_name, ".romfile"); if (XrmGetResource(x_db, option, "Xtrs.Romfile", &type, &value)) { if ((stat(value.addr, &statbuf)) == 0) { /* romfile exists */ romfile = value.addr; } #ifdef DEFAULT_ROM } else if ((stat(DEFAULT_ROM, &statbuf)) == 0) { romfile = DEFAULT_ROM; #endif } if (romfile != NULL) { trs_load_rom(romfile); } else if (trs_rom1_size > 0) { trs_load_compiled_rom(trs_rom1_size, trs_rom1); } else { fatal("ROM file not specified!"); } break; case 3: case 4: (void) sprintf(option, "%s%s", program_name, ".romfile3"); if (XrmGetResource(x_db, option, "Xtrs.Romfile3", &type, &value)) { if ((stat(value.addr, &statbuf)) == 0) { /* romfile exists */ romfile = value.addr; } #ifdef DEFAULT_ROM3 } else if ((stat(DEFAULT_ROM3, &statbuf)) == 0) { romfile = DEFAULT_ROM3; #endif } if (romfile != NULL) { trs_load_rom(romfile); } else if (trs_rom3_size > 0) { trs_load_compiled_rom(trs_rom3_size, trs_rom3); } else { fatal("ROM file not specified!"); } break; default: /* 4P */ (void) sprintf(option, "%s%s", program_name, ".romfile4p"); if (XrmGetResource(x_db, option, "Xtrs.Romfile4p", &type, &value)) { if ((stat(value.addr, &statbuf)) == 0) { /* romfile exists */ romfile = value.addr; } #ifdef DEFAULT_ROM4P } else if ((stat(DEFAULT_ROM4P, &statbuf)) == 0) { romfile = DEFAULT_ROM4P; #endif } if (romfile != NULL) { trs_load_rom(romfile); } else if (trs_rom4p_size > 0) { trs_load_compiled_rom(trs_rom4p_size, trs_rom4p); } else { fatal("ROM file not specified!"); } break; } (void) sprintf(option, "%s%s", program_name, ".resize"); if (XrmGetResource(x_db, option, "Xtrs.Resize", &type, &value)) { if (strcmp(value.addr,"on") == 0) { resize = 1; } else if (strcmp(value.addr,"off") == 0) { resize = 0; } } else { resize = (trs_model == 3); } clear_key_queue(); /* init the key queue */ /* setup root window, and gc */ root_window = DefaultRootWindow(display); /* save keyboard repeat state */ XGetKeyboardControl(display, &repeat_state); atexit(restore_repeat); foreground = fore_pixel; background = back_pixel; gcvals.graphics_exposures = False; gc = XCreateGC(display, root_window, GCGraphicsExposures, &gcvals); XSetForeground(display, gc, fore_pixel); XSetBackground(display, gc, back_pixel); gc_inv = XCreateGC(display, root_window, GCGraphicsExposures, &gcvals); XSetForeground(display, gc_inv, back_pixel); XSetBackground(display, gc_inv, fore_pixel); gc_xor = XCreateGC(display, root_window, GCGraphicsExposures, &gcvals); XSetForeground(display, gc_xor, back_pixel^fore_pixel); XSetBackground(display, gc_xor, 0); XSetFunction(display, gc_xor, GXxor); if (usefont) { if ((myfont = XLoadQueryFont(display,fontname)) == NULL) { fatal("can't open font %s!\n", fontname); } if ((mywidefont = XLoadQueryFont(display,widefontname)) == NULL) { fatal("can't open font %s!", widefontname); } curfont = myfont; XSetFont(display,gc,myfont->fid); XSetFont(display,gc_inv,myfont->fid); cur_char_width = myfont->max_bounds.width; cur_char_height = myfont->ascent + myfont->descent; } if (trs_model >= 3 && !resize) { OrigWidth = cur_char_width * 80 + 2 * border_width; left_margin = cur_char_width * (80 - row_chars)/2 + border_width; if (usefont) { OrigHeight = cur_char_height * 24 + 2 * border_width; top_margin = cur_char_height * (24 - col_chars)/2 + border_width; } else { OrigHeight = TRS_CHAR_HEIGHT4 * scale_y * 24 + 2 * border_width; top_margin = (TRS_CHAR_HEIGHT4 * scale_y * 24 - cur_char_height * col_chars)/2 + border_width; } } else { OrigWidth = cur_char_width * row_chars + 2 * border_width; left_margin = border_width; OrigHeight = cur_char_height * col_chars + 2 * border_width; top_margin = border_width; } window = XCreateSimpleWindow(display, root_window, 400, 400, OrigWidth, OrigHeight, 1, foreground, background); #if XDEBUG debug("XCreateSimpleWindow(%d, %d)\n", OrigWidth, OrigHeight); #endif /*XDEBUG*/ trs_fix_size(window, OrigWidth, OrigHeight); XStoreName(display,window,title); XSelectInput(display, window, EVENT_MASK); (void) sprintf(option, "%s%s", program_name, ".iconic"); if (XrmGetResource(x_db, option, "Xtrs.Iconic", &type, &value)) { XWMHints * hints = XAllocWMHints(); hints->flags = StateHint; hints->initial_state = IconicState; XSetWMHints(display, window, hints); XFree(hints); } XMapWindow(display, window); bitmap_init(foreground, background); screen_init(); XClearWindow(display,window); } KeySym last_key[256]; /* * Flush output to X server */ inline void trs_x_flush() { XFlush(display); } /* * Get and process X event(s). * If wait is true, process one event, blocking until one is available. * If wait is false, process as many events as are available, returning * when none are left. * Handle interrupt-driven uart input here too. */ void trs_get_event(int wait) { XEvent event; KeySym key; char buf[10]; XComposeStatus status; /* * Of Enter and Leave events, track which kind we saw last. X clients * like "unclutter" will sythesize an Enter event on their own. * * Historically, xtrs assumed that every Enter would be preceded by a * Leave. When this was not the case, xtrs would clobber the global * autorepeat state to off; it wrongly stored the off state because the * xtrs window already had focus. * * This enum is tri-valued with the zero value being UNDEF because we * don't want to fake a Leave event the first time we Enter; that would * cause restore_repeat() to read from repeat_state before it has been * initialized, possibly storing a bogus global autorepeat state. */ enum enter_leave_t { UNDEF, ENTER, LEAVE }; static enum enter_leave_t enter_leave; if (trs_model > 1) { (void)trs_uart_check_avail(); } do { if (wait) { XNextEvent(display, &event); } else { if (!XCheckMaskEvent(display, ~0, &event)) return; } switch(event.type) { case Expose: #if XDEBUG debug("Expose\n"); #endif if (event.xexpose.count == 0) { while (XCheckMaskEvent(display, ExposureMask, &event)) /*skip*/; trs_screen_refresh(); } break; case MapNotify: #if XDEBUG debug("MapNotify\n"); #endif trs_screen_refresh(); break; case EnterNotify: #if XDEBUG debug("EnterNotify\n"); #endif if (enter_leave == ENTER) { /* * The last Enter/Leave event we saw was an Enter; pretend we saw a * Leave event first. */ #if XDEBUG debug("faking a LeaveNotify event first\n"); #endif restore_repeat(); } enter_leave = ENTER; save_repeat(); trs_xlate_keysym(0x10000); /* all keys up */ break; case LeaveNotify: #if XDEBUG debug("LeaveNotify\n"); #endif enter_leave = LEAVE; restore_repeat(); trs_xlate_keysym(0x10000); /* all keys up */ break; case KeyPress: (void) XLookupString((XKeyEvent *)&event,buf,10,&key,&status); #if XDEBUG debug("KeyPress: state 0x%x, keycode 0x%x, key 0x%x\n", event.xkey.state, event.xkey.keycode, (unsigned int) key); #endif switch (key) { /* Trap some function keys here */ case XK_F11: if (!help_window) { trs_show_help(); } else { /* * Work around the most painful case of * http://bugs.freedesktop.org/show_bug.cgi?id=21454. This * bug causes infinite key repeat if a key is down when an * application disables key repeat. When we unmap the help * window, that causes an EnterNotify event for the main * window. In the EnterNotify event handler we disable key * repeat, which will cause F11 to repeat infinitely if it * is still down. So we wait until F11 is released before * unmapping the window. */ unmap_help_window = 1; } key = 0; trs_skip_next_kbwait(); break; case XK_F10: trs_reset(0); key = 0; trs_skip_next_kbwait(); break; case XK_F9: trs_debug(); key = 0; trs_skip_next_kbwait(); break; case XK_F8: trs_exit(); key = 0; trs_skip_next_kbwait(); break; case XK_F7: trs_disk_change_all(); key = 0; trs_skip_next_kbwait(); break; default: break; } if ( ((event.xkey.state & (ShiftMask|LockMask)) == (ShiftMask|LockMask)) && key >= 'A' && key <= 'Z' ) { /* Make Shift + CapsLock give lower case */ key = (int) key + 0x20; } if (key == XK_Shift_R && trs_model == 1) { key = XK_Shift_L; } if (last_key[event.xkey.keycode] != 0) { trs_xlate_keysym(0x10000 | last_key[event.xkey.keycode]); } last_key[event.xkey.keycode] = key; if (key != 0) { trs_xlate_keysym(key); } break; case KeyRelease: if (unmap_help_window) { /* See comment under KeyPress XK_F11 case above. */ XUnmapWindow(display, help_window); help_window = 0; unmap_help_window = 0; } key = last_key[event.xkey.keycode]; last_key[event.xkey.keycode] = 0; if (key != 0) { trs_xlate_keysym(0x10000 | key); } #if XDEBUG debug("KeyRelease: state 0x%x, keycode 0x%x, last_key 0x%x\n", event.xkey.state, event.xkey.keycode, (unsigned int) key); #endif break; default: #if XDEBUG debug("Unhandled event: type %d\n", event.type); #endif break; } } while (!wait); } void trs_screen_expanded(int flag) { int bit = flag ? EXPANDED : 0; if ((currentmode ^ bit) & EXPANDED) { currentmode ^= EXPANDED; if (usefont) { curfont = (flag ? mywidefont : myfont); XSetFont(display,gc,curfont->fid); XSetFont(display,gc_inv,curfont->fid); } XClearWindow(display,window); trs_screen_refresh(); } } void trs_screen_inverse(int flag) { int bit = flag ? INVERSE : 0; int i; if ((currentmode ^ bit) & INVERSE) { currentmode ^= INVERSE; for (i = 0; i < screen_chars; i++) { if (trs_screen[i] & 0x80) trs_screen_write_char(i, trs_screen[i]); } } } void trs_screen_alternate(int flag) { int bit = flag ? ALTERNATE : 0; int i; if ((currentmode ^ bit) & ALTERNATE) { currentmode ^= ALTERNATE; for (i = 0; i < screen_chars; i++) { if (trs_screen[i] >= 0xc0) trs_screen_write_char(i, trs_screen[i]); } } } void trs_screen_640x240(int flag) { if (flag == screen640x240) return; screen640x240 = flag; if (flag) { row_chars = 80; col_chars = 24; if (!usefont) cur_char_height = TRS_CHAR_HEIGHT4 * scale_y; } else { row_chars = 64; col_chars = 16; if (!usefont) cur_char_height = TRS_CHAR_HEIGHT * scale_y; } screen_chars = row_chars * col_chars; if (resize) { OrigWidth = cur_char_width * row_chars + 2 * border_width; OrigHeight = cur_char_height * col_chars + 2 * border_width; left_margin = border_width; top_margin = border_width; trs_fix_size(window, OrigWidth, OrigHeight); XResizeWindow(display, window, OrigWidth, OrigHeight); XClearWindow(display,window); XFlush(display); #if XDEBUG debug("XResizeWindow(%d, %d)\n", OrigWidth, OrigHeight); #endif /*XDEBUG*/ } else { left_margin = cur_char_width * (80 - row_chars)/2 + border_width; if (usefont) { top_margin = cur_char_height * (24 - col_chars)/2 + border_width; } else { top_margin = (TRS_CHAR_HEIGHT4 * scale_y * 24 - cur_char_height * col_chars)/2 + border_width; } if (left_margin > border_width || top_margin > border_width) { XClearWindow(display,window); } } trs_screen_refresh(); } void trs_screen_80x24(int flag) { if (!grafyx_enable || grafyx_overlay) { trs_screen_640x240(flag); } text80x24 = flag; } void screen_init() { int i; /* initially, screen is blank (i.e. full of spaces) */ for (i = 0; i < sizeof(trs_screen); i++) trs_screen[i] = ' '; } void boxes_init(int foreground, int background, int width, int height, int expanded) { int graphics_char, bit, p; XRectangle bits[6]; XRectangle cur_bits[6]; /* * Calculate what the 2x3 boxes look like. */ bits[0].x = bits[2].x = bits[4].x = 0; bits[0].width = bits[2].width = bits[4].width = bits[1].x = bits[3].x = bits[5].x = width / 2; bits[1].width = bits[3].width = bits[5].width = width - bits[1].x; bits[0].y = bits[1].y = 0; bits[0].height = bits[1].height = bits[2].y = bits[3].y = height / 3; bits[4].y = bits[5].y = (height * 2) / 3; bits[2].height = bits[3].height = bits[4].y - bits[2].y; bits[4].height = bits[5].height = height - bits[4].y; for (graphics_char = 0; graphics_char < 64; ++graphics_char) { trs_box[expanded][graphics_char] = XCreatePixmap(display, window, width, height, DefaultDepth(display, screen)); /* Clear everything */ XSetForeground(display, gc, background); XFillRectangle(display, trs_box[expanded][graphics_char], gc, 0, 0, width, height); /* Set the bits */ XSetForeground(display, gc, foreground); for (bit = 0, p = 0; bit < 6; ++bit) { if (graphics_char & (1 << bit)) { cur_bits[p++] = bits[bit]; } } XFillRectangles(display, trs_box[expanded][graphics_char], gc, cur_bits, p); } } /* DPL 20000129 * This routine creates a rescaled charater bitmap, and then * calls XCreateBitmapFromData. It then can be used pretty much * as a drop-in replacement for XCreateBitmapFromData. */ Pixmap XCreateBitmapFromDataScale(Display *display, Drawable window, char *data, unsigned int width, unsigned int height, unsigned int scale_x, unsigned int scale_y) { static unsigned char *mydata; static unsigned char *mypixels; int i, j, k; if (mydata == NULL) { /* * Allocate a bit more room than necessary - There shouldn't be * any proportional characters, but just in case... * These arrays never get released, but they are really not * too big, so we should be OK. */ mydata = (unsigned char *)malloc(width * height * scale_x * scale_y * 4); mypixels= (unsigned char *)malloc(width * height * 4); } /* Read the character data */ for (j= 0; j< width * height; j += 8) { for (i= j + 7; i >= j; i--) { *(mypixels + i)= (*(data + (j >> 3)) >> (i - j)) & 1; } } /* Clear out the rescaled character array */ for (i= 0; i< width / 8 * height * scale_x * scale_y * 4; i++) { *(mydata + i)= 0; } /* And prepare our rescaled character. */ k= 0; for (j= 0; j< height * scale_y; j++) { for (i= 0; i< width * scale_x; i++) { *(mydata + (k >> 3)) = *(mydata + (k >> 3)) | (*(mypixels + ((int)(j / scale_y) * width) + (int)(i / scale_x)) << (k & 7)); k++; } } return XCreateBitmapFromData(display,window, (char*)mydata, width * scale_x, height * scale_y); } void bitmap_init(unsigned long foreground, unsigned long background) { if (usefont) { int dwidth, dheight; boxes_init(foreground, background, cur_char_width, cur_char_height, 0); dwidth = 2*cur_char_width; dheight = 2*cur_char_height; if (dwidth > mywidefont->max_bounds.width) { dwidth = mywidefont->max_bounds.width; } if (dheight > mywidefont->ascent + mywidefont->descent) { dheight = mywidefont->ascent + mywidefont->descent; } boxes_init(foreground, background, dwidth, dheight, 1); } else { /* Initialize from built-in font bitmaps. */ int i; for (i = 0; i < MAXCHARS; i++) { trs_char[0][i] = XCreateBitmapFromDataScale(display,window, trs_char_data[trs_charset][i], TRS_CHAR_WIDTH,TRS_CHAR_HEIGHT, scale_x,scale_y); trs_char[1][i] = XCreateBitmapFromDataScale(display,window, trs_char_data[trs_charset][i], TRS_CHAR_WIDTH,TRS_CHAR_HEIGHT, scale_x*2,scale_y); } boxes_init(foreground, background, cur_char_width, TRS_CHAR_HEIGHT * scale_y, 0); boxes_init(foreground, background, cur_char_width*2, TRS_CHAR_HEIGHT * scale_y, 1); } } void trs_screen_refresh() { int i, srcx, srcy, dunx, duny; if (trs_screen_batched) { trs_screen_batched++; return; } #if XDEBUG debug("trs_screen_refresh\n"); #endif if (grafyx_enable && !grafyx_overlay) { srcx = cur_char_width * grafyx_xoffset; srcy = scale_y * grafyx_yoffset; XPutImage(display, window, gc, &image, srcx, srcy, left_margin, top_margin, cur_char_width*row_chars, cur_char_height*col_chars); /* Draw wrapped portions if any */ dunx = image.width - srcx; if (dunx < cur_char_width*row_chars) { XPutImage(display, window, gc, &image, 0, srcy, left_margin + dunx, top_margin, cur_char_width*row_chars - dunx, cur_char_height*col_chars); } duny = image.height - srcy; if (duny < cur_char_height*col_chars) { XPutImage(display, window, gc, &image, srcx, 0, left_margin, top_margin + duny, cur_char_width*row_chars, cur_char_height*col_chars - duny); if (dunx < cur_char_width*row_chars) { XPutImage(display, window, gc, &image, 0, 0, left_margin + dunx, top_margin + duny, cur_char_width*row_chars - dunx, cur_char_height*col_chars - duny); } } } else { for (i = 0; i < screen_chars; i++) { trs_screen_write_char(i, trs_screen[i]); } } } void trs_screen_write_char(int position, int char_index) { int row,col,destx,desty; int plane; char temp_char; trs_screen[position] = char_index; if (position >= screen_chars) { return; } if ((currentmode & EXPANDED) && (position & 1)) { return; } if (grafyx_enable && !grafyx_overlay) { return; } if (trs_screen_batched) { trs_screen_batched++; return; } row = position / row_chars; col = position - (row * row_chars); destx = col * cur_char_width + left_margin; desty = row * cur_char_height + top_margin; if (trs_model == 1 && char_index >= 0xc0) { /* On Model I, 0xc0-0xff is another copy of 0x80-0xbf */ char_index -= 0x40; } if (char_index >= 0x80 && char_index <= 0xbf && !(currentmode & INVERSE)) { /* Use graphics character bitmap instead of font */ switch (currentmode & EXPANDED) { case NORMAL: XCopyArea(display, trs_box[0][char_index-0x80],window,gc,0,0, cur_char_width,cur_char_height,destx,desty); break; case EXPANDED: /* use expanded graphics character bitmap instead of font */ XCopyArea(display, trs_box[1][char_index-0x80],window,gc,0,0, cur_char_width*2,cur_char_height,destx,desty); break; } } else if (usefont) { /* Draw character using a font */ if (trs_model == 1) { #if !UPPERCASE /* Emulate Radio Shack lowercase mod. The replacement character generator ROM had another copy of the uppercase characters in the control character positions, to compensate for a bug in the Level II ROM that stores such values instead of uppercase. */ if (char_index < 0x20) char_index += 0x40; #endif } if (trs_model > 1 && char_index >= 0xc0 && (currentmode & (ALTERNATE+INVERSE)) == 0) { char_index -= 0x40; } desty += curfont->ascent; if (currentmode & INVERSE) { temp_char = (char)(char_index & 0x7f); XDrawImageString(display, window, (char_index & 0x80) ? gc_inv : gc, destx, desty, &temp_char, 1); } else { temp_char = (char)char_index; XDrawImageString(display, window, gc, destx, desty, &temp_char, 1); } } else { /* Draw character using a builtin bitmap */ if (trs_model > 1 && char_index >= 0xc0 && (currentmode & (ALTERNATE+INVERSE)) == 0) { char_index -= 0x40; } plane = 1; switch (currentmode & ~ALTERNATE) { case NORMAL: XCopyPlane(display,trs_char[0][char_index], window,gc,0,0,cur_char_width, cur_char_height,destx,desty,plane); break; case EXPANDED: XCopyPlane(display,trs_char[1][char_index], window,gc,0,0,cur_char_width*2, cur_char_height,destx,desty,plane); break; case INVERSE: XCopyPlane(display,trs_char[0][char_index & 0x7f],window, (char_index & 0x80) ? gc_inv : gc, 0,0,cur_char_width,cur_char_height,destx,desty,plane); break; case EXPANDED+INVERSE: XCopyPlane(display,trs_char[1][char_index & 0x7f],window, (char_index & 0x80) ? gc_inv : gc, 0,0,cur_char_width*2,cur_char_height,destx,desty,plane); break; } } if (grafyx_enable) { /* assert(grafyx_overlay); */ int srcx, srcy, duny; srcx = ((col+grafyx_xoffset) % G_XSIZE)*cur_char_width; srcy = (row*cur_char_height + grafyx_yoffset*scale_y) % (G_YSIZE*scale_y); XPutImage(display, window, gc_xor, &image, srcx, srcy, destx, desty, cur_char_width, cur_char_height); /* Draw wrapped portion if any */ duny = image.height - srcy; if (duny < cur_char_height) { XPutImage(display, window, gc_xor, &image, srcx, 0, destx, desty + duny, cur_char_width, cur_char_height - duny); } } if (hrg_enable) { hrg_update_char(position); } } /* Copy lines 1 through col_chars-1 to lines 0 through col_chars-2. Doesn't need to clear line col_chars-1. */ void trs_screen_scroll() { int i = 0; for (i = row_chars; i < screen_chars; i++) trs_screen[i-row_chars] = trs_screen[i]; if (trs_screen_batched) { trs_screen_batched++; return; } if (grafyx_enable) { if (grafyx_overlay) { trs_screen_refresh(); } } else if (hrg_enable) { trs_screen_refresh(); } else { XCopyArea(display,window,window,gc, left_margin,cur_char_height+top_margin, (cur_char_width*row_chars),(cur_char_height*col_chars), left_margin,top_margin); } } void grafyx_write_byte(int x, int y, char byte) { int i, j; char exp[MAX_SCALE]; int screen_x = ((x - grafyx_xoffset + G_XSIZE) % G_XSIZE); int screen_y = ((y - grafyx_yoffset + G_YSIZE) % G_YSIZE); int on_screen = screen_x < row_chars && screen_y < col_chars*cur_char_height/scale_y; if (grafyx_enable && grafyx_overlay && on_screen) { if (trs_screen_batched) { trs_screen_batched++; } else { /* Erase old byte, preserving text */ XPutImage(display, window, gc_xor, &image, x*cur_char_width, y*scale_y, left_margin + screen_x*cur_char_width, top_margin + screen_y*scale_y, cur_char_width, scale_y); } } /* Save new byte in local memory */ grafyx_unscaled[y][x] = byte; switch (scale_x) { case 1: exp[0] = byte; break; case 2: exp[1] = ((byte & 0x01) + ((byte & 0x02) << 1) + ((byte & 0x04) << 2) + ((byte & 0x08) << 3)) * 3; exp[0] = (((byte & 0x10) >> 4) + ((byte & 0x20) >> 3) + ((byte & 0x40) >> 2) + ((byte & 0x80) >> 1)) * 3; break; case 3: exp[2] = ((byte & 0x01) + ((byte & 0x02) << 2) + ((byte & 0x04) << 4)) * 7; exp[1] = (((byte & 0x08) >> 2) + (byte & 0x10) + ((byte & 0x20) << 2)) * 7 + ((byte & 0x04) >> 2); exp[0] = (((byte & 0x40) >> 4) + ((byte & 0x80) >> 2)) * 7 + ((byte & 0x20) >> 5) * 3; break; case 4: exp[3] = ((byte & 0x01) + ((byte & 0x02) << 3)) * 15; exp[2] = (((byte & 0x04) >> 2) + ((byte & 0x08) << 1)) * 15; exp[1] = (((byte & 0x10) >> 4) + ((byte & 0x20) >> 1)) * 15; exp[0] = (((byte & 0x40) >> 6) + ((byte & 0x80) >> 3)) * 15; break; default: fatal("scaling graphics by %dx not implemented\n", scale_x); } for (j=0; j <-------port 3 (MSB)-------> * Bit: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 * <-column addr.-> <-line addr.-> * * Reading from port 4 or writing to port 5 will access six * neighbouring pixels corresponding (from left to right) to bits * 0-5 of the data byte. Bits 6 and 7 are present in memory, but * are ignored. * * In expanded mode (32 chars per line), the graphics screen has * only 192*192 pixels. Pixels with an odd column address (i.e. * every second group of 6 pixels) are suppressed. */ /* Initialize HRG. */ static void hrg_init() { int i; /* Precompute arrays of pixel sizes and offsets. */ for (i = 0; i <= 6; i++) { hrg_pixel_x[0][i] = cur_char_width * i / 6; hrg_pixel_x[1][i] = cur_char_width*2 * i / 6; if (i != 0) { hrg_pixel_width[0][i-1] = hrg_pixel_x[0][i] - hrg_pixel_x[0][i-1]; hrg_pixel_width[1][i-1] = hrg_pixel_x[1][i] - hrg_pixel_x[1][i-1]; } } for (i = 0; i <= 12; i++) { hrg_pixel_y[i] = cur_char_height * i / 12; if (i != 0) hrg_pixel_height[i-1] = hrg_pixel_y[i] - hrg_pixel_y[i-1]; } if (cur_char_width % 6 != 0 || cur_char_height % 12 != 0) error("character size %d*%d not a multiple of 6*12 HRG raster", cur_char_width, cur_char_height); } /* Switch HRG on (1) or off (0). */ void hrg_onoff(int enable) { static int init = 0; if ((hrg_enable!=0) == (enable!=0)) return; /* State does not change. */ if (!init) { hrg_init(); init = 1; } hrg_enable = enable; trs_screen_refresh(); } /* Write address to latch. */ void hrg_write_addr(int addr, int mask) { hrg_addr = (hrg_addr & ~mask) | (addr & mask); } /* Write byte to HRG memory. */ void hrg_write_data(int data) { int old_data; int position, line; int bits0, bits1; if (hrg_addr >= HRG_MEMSIZE) return; /* nonexistent address */ old_data = hrg_screen[hrg_addr]; hrg_screen[hrg_addr] = data; if (!hrg_enable) return; if ((currentmode & EXPANDED) && (hrg_addr & 1)) return; if ((data &= 0x3f) == (old_data &= 0x3f)) return; if (trs_screen_batched) { trs_screen_batched++; return; } position = hrg_addr & 0x3ff; /* bits 0-9: "PRINT @" screen position */ line = hrg_addr >> 10; /* vertical offset inside character cell */ bits0 = ~data & old_data; /* pattern to clear */ bits1 = data & ~old_data; /* pattern to set */ if (bits0 == 0 || trs_screen[position] == 0x20 || trs_screen[position] == 0x80 /*|| (trs_screen[position] < 0x80 && line >= 8 && !usefont)*/ ) { /* Only additional bits set, or blank text character. No need for update of text. */ int destx = (position % row_chars) * cur_char_width + left_margin; int desty = (position / row_chars) * cur_char_height + top_margin + hrg_pixel_y[line]; int *x = hrg_pixel_x[(currentmode&EXPANDED)!=0]; int *w = hrg_pixel_width[(currentmode&EXPANDED)!=0]; int h = hrg_pixel_height[line]; XRectangle rect0[3]; /* 6 bits => max. 3 groups of adjacent "0" bits */ XRectangle rect1[3]; int n0 = 0; int n1 = 0; int flag = 0; int j, b; /* Compute arrays of rectangles to clear and to set. */ for (j = 0, b = 1; j < 6; j++, b <<= 1) { if (bits0 & b) { if (flag >= 0) { /* Start new rectangle. */ rect0[n0].x = destx + x[j]; rect0[n0].y = desty; rect0[n0].width = w[j]; rect0[n0].height = h; n0++; flag = -1; } else { /* Increase width of rectangle. */ rect0[n0-1].width += w[j]; } } else if (bits1 & b) { if (flag <= 0) { rect1[n1].x = destx + x[j]; rect1[n1].y = desty; rect1[n1].width = w[j]; rect1[n1].height = h; n1++; flag = 1; } else { rect1[n1-1].width += w[j]; } } else { flag = 0; } } if (n0 != 0) XFillRectangles(display, window, gc_inv, rect0, n0); if (n1 != 0) XFillRectangles(display, window, gc, rect1, n1); } else { /* Unfortunately, HRG1B combines text and graphics with an (inclusive) OR. Thus, in the general case, we cannot erase the old graphics byte without losing the text information. Call trs_screen_write_char to restore the text character (erasing the graphics). This function will in turn call hrg_update_char and restore 6*12 graphics pixels. Sigh. */ trs_screen_write_char(position, trs_screen[position]); } } /* Read byte from HRG memory. */ int hrg_read_data() { if (hrg_addr >= HRG_MEMSIZE) return 0xff; /* nonexistent address */ return hrg_screen[hrg_addr]; } /* Update graphics at given screen position. Called by trs_screen_write_char. */ static void hrg_update_char(int position) { int destx = (position % row_chars) * cur_char_width + left_margin; int desty = (position / row_chars) * cur_char_height + top_margin; int *x = hrg_pixel_x[(currentmode&EXPANDED)!=0]; int *w = hrg_pixel_width[(currentmode&EXPANDED)!=0]; XRectangle rect[3*12]; int byte; int prev_byte = 0; int n = 0; int np = 0; int i, j, flag; /* Compute array of rectangles. */ for (i = 0; i < 12; i++) { if ((byte = hrg_screen[position+(i<<10)] & 0x3f) == 0) { } else if (byte != prev_byte) { np = n; flag = 0; for (j = 0; j < 6; j++) { if (!(byte & 1<", win_x, win_y, mask); #endif if (win_x >= 0 && win_x < OrigWidth && win_y >= 0 && win_y < OrigHeight) { /* Mouse is within emulator window */ if (win_x < left_margin) win_x = left_margin; if (win_x >= OrigWidth - left_margin) win_x = OrigWidth - left_margin - 1; if (win_y < top_margin) win_y = top_margin; if (win_y >= OrigHeight - top_margin) win_y = OrigHeight - top_margin - 1; *x = mouse_last_x = (win_x - left_margin) * mouse_x_size / (OrigWidth - 2*left_margin); *y = mouse_last_y = (win_y - top_margin) * mouse_y_size / (OrigHeight - 2*top_margin); mouse_last_buttons = 7; /* !!Note: assuming 3-button mouse */ if (mask & Button1Mask) mouse_last_buttons &= ~4; if (mask & Button2Mask) mouse_last_buttons &= ~2; if (mask & Button3Mask) mouse_last_buttons &= ~1; } *x = mouse_last_x; *y = mouse_last_y; *buttons = mouse_last_buttons; #if MOUSEDEBUG debug("%d %d 0x%x\n", mouse_last_x, mouse_last_y, mouse_last_buttons); #endif } void trs_set_mouse_pos(int x, int y) { int dest_x, dest_y; if (x == mouse_last_x && y == mouse_last_y) { /* Kludge: Ignore warp if it says to move the mouse to where we last said it was. In general someone could really want to do that, but with MDRAW, gratuitous warps to the last location occur frequently. */ return; } dest_x = left_margin + x * (OrigWidth - 2*left_margin) / mouse_x_size; dest_y = top_margin + y * (OrigHeight - 2*top_margin) / mouse_y_size; #if MOUSEDEBUG debug("set_mouse %d %d -> %d %d\n", x, y, dest_x, dest_y); #endif XWarpPointer(display, window, window, 0, 0, OrigWidth, OrigHeight, dest_x, dest_y); } void trs_get_mouse_max(int *x, int *y, unsigned int *sens) { *x = mouse_x_size - (mouse_old_style ? 0 : 1); *y = mouse_y_size - (mouse_old_style ? 0 : 1); *sens = mouse_sens; } void trs_set_mouse_max(int x, int y, unsigned int sens) { if ((x & 1) == 0 && (y & 1) == 0) { /* "Old style" mouse drivers took the size here; new style take the maximum. As a heuristic kludge, we assume old style if the values are even, new style if not. */ mouse_old_style = 1; } mouse_x_size = x + (mouse_old_style ? 0 : 1); mouse_y_size = y + (mouse_old_style ? 0 : 1); mouse_sens = sens; } int trs_get_mouse_type() { /* !!Note: assuming 3-button mouse */ return 1; } xtrs-4.9d/truedam.ccc000066400000000000000000000021111306603614600146450ustar00rootroot00000000000000/* truedam.ccc -- Misosys C program to query/set truedam flag on xtrs */ /* Copyright (c) 1998, Timothy Mann */ /* $Id: truedam.ccc,v 1.3 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ #option redirect 0 #include "xtrsemt.h" #include "xtrsemt.ccc" /* could use separate compilation instead */ usage(n) int n; { fprintf(stderr, "usage: truedam [0|1]\n"); exit(1); } int main(argc, argv) int argc; char **argv; { int hl, bc, de, ret; char *retp; int func; if (argc == 1) { func = EMT_MISC_QUERY_TRUEDAM; } else if ((argc == 2) && isdigit(argv[1][0])) { func = EMT_MISC_SET_TRUEDAM; if (strlen(argv[1]) != 1) usage(); hl = atoi(argv[1]); if (hl > 1) usage(); } else { usage(); } emt_4misc(func, &hl, &bc, &de); printf("truedam = %d\n", hl); exit(0); } xtrs-4.9d/truedam.cmd000066400000000000000000000137711306603614600146760ustar00rootroot00000000000000)RÚUtruedam = %d usage: truedam [0|1] <+RìiUR[RaR@ @ @iRÚUñáåõí(`iÈOíCÕ`ÉñáÁÅåõí*ÈOíCÕ`!Éñáåõí+!ÈOíCÕ`!ÿÿÉñáÁÑÕÅåõí0bkÈOíCÕ`ÉñÑÕõí1!ÈOíCÕ`!ÿÿÉñÑáÁÅåÕõí2`iÈOíCÕ`ÉñÑáÁÅåÕõí3`iÈOíCÕ`ÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o"Õ`ÉñÑáÁÅåÕõ{í5`iÈOíCÕ`Éñáåõ}í6Éñáåõí7bkÈOíCÕ`ÉñÑÕõíiS8!ÈOíCÕ`!ÿÿÉñÑáÁÅåÕõí9`iÈOíCÕ`Éñáåõí:!ÈOíCÕ`!ÿÿÉñáÁÅåõí;ÈOíCÕ`!Éñáåõ}í<ÉÝåÝ!Ý9ÝnÝfN#FÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfs#rÑÝnÝfs#rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o"Õ`ÉñáÁÑÕÅåõí>bkÈOíCÕ`ÉñÑÕõí?!ÈOíCÕ`!ÿÿÉ!iTRå!7Rå͹Vññ!åÍ_ñÉôÿÍÕi!9ÍÆiå!ÑÍYi|µÊ§T!9å!ÑÍËiÃ\U!9ÍÆiå!ÑÍYi|µÊßT!9ÍÆiå!Í™iÑÍÆiå!Ñn&åÍìfñ|µÊYU!9å!ÑÍËi!9ÍÆiå!Í™iÑÍÆiåÍdñå!ÑÍ_i|µÊUÍhT! 9å!9ÍÆiå!Í™iÑÍÆiåͳbñÑÍËi! 9ÍÆiå!ÑÍki|µÊVUÍhTÃ\UÍhT!9å! 9å!iU9å!9ÍÆiåÍ¿Sññññ! 9ÍÆiå!RåÍXVññ!åÍ_ñ ÍÕiÉíseR*I@ÍÐf *D"gRùͺUÍ~T!åÍ_*1R"'R")RÍMVí['RÍBV( Õ ÍV òÅÝáË!ë "'R")RË9AÑ+r+sùÁåÝåÅÉÃúdÃ1dÅ~þ"(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( þ\ G#Ú#¯Á> ¾Ø> ¾È#õ!CÍÐfÀ!%BÉõÝåýå!9å! 9ÑÍËÈiVi!9åÍÆi##ÑÍËiå!ÿÿ)ÑÍÆiåÝá!5R"/W!8`"1W!9åÝåáå͹Wññåýáýåáå!9ÍÜi!9ÍäiáñññÉõÝåýå!9å! 9ÑÍËi!9åÍÆi##ÑÍËiå!ÿÿ)ÑÍÆi"/W!8`"1W!9åÍÆi##ÑÍËiå!ÿÿ)ÑÍÆiåÝá!9åÝåáå͹Wññåýáýåáå!9ÍÜi!9ÍäiáñññÉ„W0B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"5W!"3W*5Wn&|µÊ_*5Wn&%Í_i|µÊX*1Wå*/Wãå*5W#"5W+n&ãåÍÑiññ*3W#"3WÃþ^!"LW"JW"HW"FW"DW*5W#"5Wn&åÑ!+ÍŽiÂ7X!"DWÃX!-ÍŽiÂIX!"FWÃX! ÍŽiÂ[X!"HWÃX!#ÍŽiÂmX!"JWÃX!0ÍŽiÂX!"LWÃX*5Wn&„X*ÍYi|µÊÕXñÁáåÅõåÍÆi##ÑÍËiå!ÿÿ)ÑÍÆi";W*;WëÍri|µÊËX*;WͲi";W!"FW*5W#"5Wà Y!";W*5Wn&åÍìfñ|µÊ Y*;W Í™iå*5W#"5W+n&åÍh_ñÑ";WÃÛX*5Wn&.ÍYi|µÊ•Y*5W#"5Wn&*ÍYi|µÊZYñÁáåÅõåÍÆi##ÑÍËiå!ÿÿ)ÑÍÆi"=W*5W#"5WÃ’Y!"=W*5Wn&åÍìfñ|µÊ’Y*=W Í™iå*5W#"5W+n&„YåÍh_ñÑ"=WÃ`YÛY!ÿÿ"=W!"BW*5Wn&åÑ!lÍŽi»Y!"BWÃÄY!hÍŽiÂËY*5W#"5W!"@W!¸W"NW*5W#"5W+n&}2?WåÑ!dÍŽiÂôYÃýY!uÍŽiÂZ!"€WÃQZ!oÍŽiÂZ!"€WÃQZ!XÍŽiÂ$ZÃ-Z!xÍŽiÂ6Z!"€WÃQZ!BÍŽiÂBZÃKZ!bÍŽiÂ]!"€W*=WëÍri|µÊfZ!"=W*BW|µÊ”ZñÁáåÅõåÍÆiÑÍËiå!ÿÿ„Z))ÑÍDi!xWÍLiÃîZ:?Wo&dÍYi|µÊËZñÁáåÅõåÍÆi##ÑÍËiå!ÿÿ)ÑÍÆiÍ.i!xWÍLiÃîZñÁáåÅõåÍÆi##ÑÍËiå!ÿÿ)ÑÍÆiÍ6i!xWÍLi:?Wo&dÍYi|µÊb[!xWÍDiÅÕÍ–g|µÊC[!¶W"NW!xWÍDiÅՀ͌g|µÊ@[!xWÍDiÍi!xWÍLiÃb[*DW|µÊT[!´W"NWÃb[*HW|µÊb[!²W"NW*LW|µÊ™[õ!9å*;Wå*NWåÍdñÑÍ­iÑÍËi„[áåå*=WÑÍki|µÊ˜[áå"=Wñ:?Wo&XÍYi|µÊ°[!¡Wö[!Wö["|W!PW("7W"9W!xWÍDiÍh|µÊd\!xWÍDiÅÕÍÅgë"‚W!xWÍDiÅÕÍÚgÅÕ€ÍùgÍÅg!xWÍLi*7W+"7Wå*|Wå!xWÍDiÅÕ*€WÍ.iÍ gÅÕÍRgÅÕ*‚WÍ.i̓gëÑn&Ñ}!xWÍDiÅÕ*€WÍ.iÍ:g!xWÍLiÃÆ[*7Wå*9WÑÍ­iå*=WÑ"@W*JW|µÊ‹\*7Wå„\*9WÑÍ_i|µÊ]:?Wo&åÑ!oÍŽi¹\*@WëÍri|µÊ¶\!"@WÃ]!xÍŽiÂË\!W"NWÃ]!XÍŽiÂÝ\!ŠW"NWÃ]!bÍŽiÂï\!‡W"NWÃ]!BÍŽiÂ]!„W"NWÃ]Ãî]!cÍŽiÂ?]!PWå!9ÍÆiåÍÆi##ÑÍËiå!ÿÿ)ÑÍÆiÑ}!PW"7W*7W#"9WÃî]!sÍŽiÂÈ]ñÁáåÅõåÍÆi##ÑÍËiå!ÿÿ)ÑÍÆi"7W*=WëÍri|µÊz]!ÿ"=W!"~WÊ]*„]~W#"~W*7W#"7W+n&|µÊ¥]*~Wå*=WÑÍri|µÊ­]Ã]*7W+"7W"9W*7Wå*~WÑÍ­i"7WÃî]!ÍŽiÂÛ]*5W+"5WÃî]!?W"7W"9W*9W#"9WÃî]:?Wo&|µÊþ^õ!9å*;Wå*9Wå*7WÑÍ­iÑÍ­iå*@WëÍri|µÊ(^!Ã.^*@WÃ.^ÑÍ­iå*NWåÍdñÑÍ­iÑÍËi*FW;i|µÊr^!9åÍÆi+ÑÍËiëÍei|µÊr^! åÍ#_ñÃN^*NWn&|µÊ^*NW#"NW„^+n&åÍ#_ñÃr^*@W+"@WëÍei|µÊ®^!0åÍ#_ñÃ^*7Wå*9WÑ͈i|µÊÑ^*7W#"7W+n&åÍ#_ñî^*FW|µÊý^!9åÍÆi+ÑÍËiëÍei|µÊý^! åÍ#_ñÃÙ^ñÃÆW*/W|µÊ_*/WåÍ`ñ|µÊ_!ÿÿÃ"_*3WÃ"_É*1Wå*/Wãå!9n&ãåÍÑiññ*3W#"3WÉñáåõå!9ÍÆiÑÍri|µÊ^_ñáåõÃg_ñÁáåÅõÃg_É!9n&0·íRÉñáåõ0ÉÍŽ_ñá(„_åõ|µÊ-@Ã0@!3RA^#V#{²( ÅåëË^ÌÍ_áÁìɬ_!ÿÿ"ª_ñáåõÝååÝáͪb(MË^ M¯ÝwÝwÝååÝá++å##íCª_~q#Ë~(ëÝnÝfåËo Í(D( Ía!ÿÿ"ª_ÍúUÁÍúUá*ª_ÝáÉ!Ý!("Õ`îÝåÍ bÝá(~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáͪb(WËN(SËv OT]åÝá:URþ*(Ë^#ÄÆiëÅyþ Ý~ÿæ 4yÍõÝ4þñë(Ë~á }Ö ÝwþÝáÉëËöËî!Ë^(wÍa!ÿÿå yÍ(+¬`Ë~ ÉÍ·` ïÂÝ4þÕÝ^þÝ~ÿæ?Ëq(ö@ö€Í DåÍ+añ"Õ`áÉñáåõ&}íKb ¹0þ@Ðþ-.@Ð!×`…oŒ•gn&É`ana€aa¡aµaÌaëaüaUnknown errorArg list too longNot a directoryInvalid argumentToo many open filesNot a character deviceMath arg ou×at of domain of funcResult too largeI/O errorHñÑÕõ{þ@8Ö@o&þ 8l)NaÃÆiöÀõ!|DÍÐf !‹B"[bT]ÍÆi"Xb!JbÍËiñÍ D!`bÉ`b~#Ö ø!ÃËiñáÑÝáÝåÕåõÝnÝf|µÉõõ!9å!9ÍÆiåÍùcñÑÍËi!9å!9ÍÆin×b&-ÍYiÑÍËi|µÊõb!9åÍÆi#ÑÍËi!9å!´cå!ìfå! å!9ÍÆiåÍ4cññññÑÍËiáå|µÊ*cñáåõͲiÃ1cñáåõÃ1cññÉõ!9ëÍËi!9å!9ÍÆiåÍùcñÑÍËi!9ÍÆiå!9ÍÆin&ãåÍÑiñ|µÊ°c!9åñáåõå! 9ÍÆiÑÍ™iå!9ÍÆiå! 9åÍÆi#ÑÍËi+n&ãåÍÑiñÑÑÍËiÃUcáåñÉ!9n&0·íRÉ!9n&åÍìfñ|µÊãc!9X×cn&0·íRÃøc!9n&åÍÖfñ7·íRÃøcÉñáåõn&åÍ gñ|µÊd!9åÍÆi#ÑÍËiÃùcñáåõÉñÑÕõ!·È#ùÉ1dñÑÕõÝåýå!"-dý!+R*+Rý"/dÝåýáÝnÝfåÝá|µ(7ÝnÝfí[-d·íR8ÜíB0ÝnÝfýuýt ÝuÝtDMÝ ÝsÝr*-dåÍÅdÁ|¥< !#"Õ`åÝáÝqÝpÝåÍsfágoýáÝáÉñÑÕõz³('!9íBíK'RíB8 íR8Åë "'RáÉ!#"Õ`!ÿÿÉ*'RÉúdñÑÕõÝåýåÍ eýáÝáÉ!ãeÍèeÝ!üÿÝͨfý!+R ý"ødýnýfåýáý^ýVz³(ÝåáíR0âÍÈeÝåÁýqýpýå!+RÑ·íR('ýnýf·íB ÍÕeýuýtÝnÝfýuýtýåÝáý"ødÝNÝFÅýáx±(ÝåáÝ^ÝV·íB ÍÕeÝuÝtÍÈeý*ødÝåáÝ^ÝVíK'R¯íBÀýwýwÝ"'RÉýnýfÝuÝtÉýnýfÝ^ÝVÉFREEÝåÅÕåë+F+N++ÍýeáÑÁúeÝáÉëÝ!-RÝnÝf|µ(åÝáíRÈ8îñ!GfÍZfYP!TfÍZf> Í3áÍgD!9fÍgD!ÿÿåÍ‚_: BAD BLOCK X'xxxx', LEN X'xxxx' zÍ_f{õÍhfñæÆ'Î@'w#ÉýååÕý!-RÕýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý!-RÕýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌ:%þIÉñÑÕõÕÕÍüfÁÑëz³È}î &oÉñáåõ}!þ0Øþ:Ðúf#Éñáåõ}!þaØþ{Ð#Éñáåõ}!þ È-þ ØþÐ,ÉÍTiÍÖhÊ;iÍiõÍÛhÍ hñüiÃ;iÍTiÍÖhÊ;iÍÛhõÍ hñáÑÁüiéÍTiÅÕå!9PXå~#¶#¶#¶áÊ}g¯ÍÇhãܧh¯Í¹hãÃagñññÃ;iÍTiͧhÃ;iÍ gÂ?i+Ã?iÍ gÚ?i+Ã?i!9###xî€G~ÂÁg+~¹ÂÁg+~ºÂÁg+~»!ÉÍTi{¦_#z¦W#y¦O#x¦GÃ;iÍTiÍÖh(###Ë+Ë+Ë+ËÍhèáÑÁé{úg/_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍÖh!À+ÉÝåõõÝ!Ý9;å~Ýw6#~Ýw6#~Ýw6#~Ýw6.xæ€Â[hËËËË,ÃIhÝuÿÝåáÍöhåÍháÊohÒvhÍ¡hÍi7ã͹hÝ5ÿʈhã¯ÍÇhÃdhñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍiçhå~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õüiÍiòôhÍöhÍiÍöhñî€ÉñÉå~s_ôúh#~rW#~qO#~pGáÉå###~·áÉ{· ² ± xþ€Èå¯o›_}šW}™O}˜GáÉÍ6iz·ð ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#pÉ!9ÉÍxiÈ+ÉÍxiÀ+ÉÍxiÐ+ÉëÍxiØ+ÉÍxiØ+É|î€gz {½!ÉÍŽiØ+Éz¼Â•i{½!ÉDM¯og>Ë#Ë0 =È)àië¯íRÉÍ·i#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉšUxtrs-4.9d/truedam6.cmd000066400000000000000000000137421306603614600147620ustar00rootroot00000000000000)0Ü3truedam = %d usage: truedam [0|1] <+0×GU0[0a0  k0Ü3ñáåõí(`iÈOíCê>ÉñáÁÅåõí*ÈOíCê>!Éñáåõí+!ÈOíCê>!ÿÿÉñáÁÑÕÅåõí0bkÈOíCê>ÉñÑÕõí1!ÈOíCê>!ÿÿÉñÑáÁÅåÕõí2`iÈOíCê>ÉñÑáÁÅåÕõí3`iÈOíCê>ÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o"ê>ÉñÑáÁÅåÕõ{í5`iÈOíCê>Éñáåõ}í6Éñáåõí7bkÈOíCê>ÉñÑÕõík18!ÈOíCê>!ÿÿÉñÑáÁÅåÕõí9`iÈOíCê>Éñáåõí:!ÈOíCê>!ÿÿÉñáÁÅåõí;ÈOíCê>!Éñáåõ}í<ÉÝåÝ!Ý9ÝnÝfN#FÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfs#rÑÝnÝfs#rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o"ê>ÉñáÁÑÕÅåõí>bkÈOíCê>ÉñÑÕõí?!ÈOíCê>!ÿÿÉ!k20å!70åÍÛ4ññ!åÍ¡=ñÉôÿÍÀG!9ͱGå!ÑÍDG|µÊ©2!9å!ÑͶGÃ^3!9ͱGå!ÑÍDG|µÊá2!9ͱGå!Í„GÑͱGå!Ñn&åÍ×Dñ|µÊ[3!9å!ÑͶG!9ͱGå!Í„GÑͱGåÍ)Bñå!ÑÍJG|µÊ3Íj2! 9å!9ͱGå!Í„GÑͱGåͽ@ñÑͶG! 9ͱGå!ÑÍVG|µÊX3Íj2Ã^3Íj2!9å! 9å!k39å!9ͱGåÍÁ1ññññ! 9ͱGå!0åÍz4ññ!åÍ¡=ñ ÍÀGÉísg0íCe0>d!Eï"i0ë!ÿóíRë0 >eïý~þ` !ÿóùÍÒ3Í€2!åÍ¡=*10"'0")0KI>Rï"V0DO>Rï"\0"b0*e0í['0Ío4( Õ Í-4 òÅÝáË!ë "'0")0Ë9AÑ+r+sùÁåÝåÅÉÃCÃ;BÅ~þ"(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( þ\ G#Ú#èk4¯Á> ¾Ø> ¾È#õõÝåýå!9å! 9ÑͶG!9åͱG##ÑͶGå!ÿÿ)ÑͱGåÝá!50"Q5!W>"S5!9åÝåáåÍÛ5ññåýáýåáå!9ÍÇG!9ÍÏGáñññÉõÝåýå!9å! 9ÑͶG!9åͱG##ÑͶGå!ÿÿ)ÑͱG"Q5!W>"S5!9åͱG##ÑͶGå!ÿÿ)ÑͱGåÝá!9åÝåáåÍÛ5ññåýáýåáå!9ÍÇG!9ÍÏGáñññɦ50B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"W5!"U5*W5n&|µÊ#=*W5n&%ÍJG|µÊ)6*S5å*Q5ãå*W5#"W5+n&ãåͼGññ*U5#"U5à =!"n5"l5"j5"h5"f5*W5#"W5n&åÑ!+ÍyGÂY6!"f5Ã;6!-ÍyGÂk6!"h5Ã;6! ÍyGÂ}6!"j5Ã;6!#ÍyGÂ6!"l5Ã;6!0ÍyG¡6!"n5Ã;6*W5n&¦6*ÍDG|µÊ÷6ñÁáåÅõåͱG##ÑͶGå!ÿÿ)ÑͱG"]5*]5ëÍ]G|µÊí6*]5ÍG"]5!"h5*W5#"W5Ã/7!"]5*W5n&åÍ×Dñ|µÊ/7*]5 Í„Gå*W5#"W5+n&åÍŠ=ñÑ"]5Ãý6*W5n&.ÍDG|µÊ·7*W5#"W5n&*ÍDG|µÊ|7ñÁáåÅõåͱG##ÑͶGå!ÿÿ)ÑͱG"_5*W5#"W5ô7!"_5*W5n&åÍ×Dñ|µÊ´7*_5 Í„Gå*W5#"W5+n&¦7åÍŠ=ñÑ"_5Â7ý7!ÿÿ"_5!"d5*W5n&åÑ!lÍyGÂÝ7!"d5Ãæ7!hÍyGÂí7*W5#"W5!"b5!Ú5"p5*W5#"W5+n&}2a5åÑ!dÍyGÂ8Ã8!uÍyGÂ(8!"¢5Ãs8!oÍyGÂ:8!"¢5Ãs8!XÍyGÂF8ÃO8!xÍyGÂX8!"¢5Ãs8!BÍyGÂd8Ãm8!bÍyGÂ&;!"¢5*_5ëÍ]G|µÊˆ8!"_5*d5|µÊ¶8ñÁáåÅõåͱGÑͶGå!ÿÿ¦8))ÑÍ/G!š5Í7GÃ9:a5o&dÍDG|µÊí8ñÁáåÅõåͱG##ÑͶGå!ÿÿ)ÑͱGÍG!š5Í7GÃ9ñÁáåÅõåͱG##ÑͶGå!ÿÿ)ÑͱGÍ!G!š5Í7G:a5o&dÍDG|µÊ„9!š5Í/GÅÕÍE|µÊe9!Ø5"p5!š5Í/GÅÕ€ÍwE|µÊb9!š5Í/GÍûF!š5Í7GÄ9*f5|µÊv9!Ö5"p5Ä9*j5|µÊ„9!Ô5"p5*n5|µÊ»9õ!9å*]5å*p5åÍ)BñÑ͘GÑͶG¦9áåå*_5ÑÍVG|µÊº9áå"_5ñ:a5o&XÍDG|µÊÒ9!Ã5ÃØ9!²5ÃØ9"ž5!r5("Y5"[5!š5Í/GÍF|µÊ†:!š5Í/GÅÕͰEë"¤5!š5Í/GÅÕÍÅEÅÕ€ÍäEͰE!š5Í7G*Y5+"Y5å*ž5å!š5Í/GÅÕ*¢5ÍGÍ EÅÕÍ=EÅÕ*¤5ÍGÍnEëÑn&Ñ}!š5Í/GÅÕ*¢5ÍGÍ%E!š5Í7GÃè9*Y5å*[5Ñ͘Gå*_5Ñ"b5*l5|µÊ­:*Y5å¦:*[5ÑÍJG|µÊ#;:a5o&åÑ!oÍyGÂÛ:*b5ëÍ]G|µÊØ:!"b5Ã#;!xÍyGÂí:!¯5"p5Ã#;!XÍyGÂÿ:!¬5"p5Ã#;!bÍyGÂ;!©5"p5Ã#;!BÍyGÂ#;!¦5"p5Ã#;Ãñ|µÊ>=!ÿÿÃD=*U5ÃD=É*S5å*Q5ãå!9n&ãåͼGññ*U5#"U5Éñáåõå!9ͱGÑÍ]G|µÊ€=ñáåõÉ=ñÁáåÅõÉ=É!9n&0·íRÉñáåõ0ÉÍ­=ñá%¦=åõí{g0É!30A^#V#{²( ÅåëË^Ìì=áÁìÉË=!ÿÿ"É=ñáåõÝååÝáÍ´@(MË^ M¯ÝwÝwÝååÝá++å##íCÉ=~q#Ë~(ëÝnÝfåËo ><ï( Í?!ÿÿ"É=Í'4ÁÍ'4á*É=ÝáÉ!Ý!("ê>îÝåͪ@Ýá(~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáÍ´@(RËN(NËv JT]åÝá:U0þ*(Ë^#ıGëÅyþ Ý~ÿæ />ïõÝ4þñëá }Ö ÝwþÝáÉëËöËî!Ë^(wÍ?!ÿÿå >ï ÒÍÌ> ô!Ë>ËÝ4þÕÝ^þÝ~ÿæHHHHHHHHHHHHHHCHHHHHCC"##%'CCCå!/0No&ËA(þ@8>?Ëq(ö@ö€O>ïåÍA?ñ"ê>áÉñáåõ&}íK@ ¹0þ@Ðþ-.@Ð!ì>…oŒ•gn&Év?„?–?¦?·?Ë?â?@@Unknown errorArg list too longNot a directoryInvalid argumentToo many open filesNot a character deviceMath arg oì?ut of domain of funcResult too largeI/O errorHñÑÕõ{þ@8Ö@o&þ 8l)d?ñGöÀOýå>eïýËþýáZ@>ïbk> Pí±+pëÉñáÑÝáÝåÕåõÝnÝf|µÉõõ!9å!9ͱGåÍBñÑͶG!9å!9ͱGn&-ÍDGÑͶì@G|µÊÿ@!9åͱG#ÑͶG!9å!¾Aå!×Då! å!9ͱGåÍ>AññññÑͶGáå|µÊ4AñáåõÍGÃ;AñáåõÃ;AññÉõ!9ëͶG!9å!9ͱGåÍBñÑͶG!9ͱGå!9ͱGn&ãåͼGñ|µÊºA!9åñáåõå! 9ͱGÑÍ„Gå!9ͱGå! 9åͱG#ÑͶG+n&ãåͼGñÑÑͶGÃ_AáåñÉ!9n&0·íRÉ!9n&åÍ×Dñ|µÊíA!9n&0·íRÃMìAB!9n&åÍÁDñ7·íRÃBÉñáåõn&åÍ÷Dñ|µÊ$B!9åͱG#ÑͶGÃBñáåõÉñÑÕõ!·È#ùÉ;BñÑÕõÝåýå!"7Bý!+0*+0ý"9BÝåýáÝnÝfåÝá|µ(7ÝnÝfí[7B·íR8ÜíB0ÝnÝfýuýt ÝuÝtDMÝ ÝsÝr*7BåÍÏBÁ|¥< !#"ê>åÝáÝqÝpÝåÍdDágoýáÝáÉñÑÕõz³('!9íBíK'0íB8 íR8Åë "'0áÉ!#"ê>!ÿÿÉ*'0ÉCñÑÕõÝåýåÍCýáÝáÉ!íCÍòCÝ!üÿÝÍ™Dý!+0 ý"Cýnýfåýáý^ýVz³(ÝåáíR0âÍÒCÝåÁýqýpýå!+0Ñ·íR('ýnýf·íB ÍßCýuýtÝnÝfýuýtýåÝáý"CÝNÝFÅýáx±(ÝåáÝ^ÝV·íB ÍßCÝuÝtÍÒCý*CÝåáÝ^ÝVíK'0¯íBÀýwýwÝ"'0ÉýnýfÝuÝtÉýnýfÝ^ÝVÉFREEÝåÅÕåë+F+N++ÍDáÑÁDÝáÉëÝ!-0ÝnÝf|µ(åÝáíRÈ8îñ!QD>cïYP!^D>cï >ïá> ï!CD> ï!ÿÿåͤ=: BAD BLOCK X'xxxx', LEN X'xxxx' ýååÕý!-0Õýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý!-0Õýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌñÑÕõÕÕÍçDÁÑëz³È}î &oÉñáåõ}!þ0Øþ:Ð#Éñáåõ}!þaØþ{Ð#Éñáåõ}!þ È-þE ØþÐ,ÉÍ?GÍÁFÊ&GÍóFõÍÆFÍ FñüûFÃ&GÍ?GÍÁFÊ&GÍÆFõÍ FñáÑÁüûFéÍ?GÅÕå!9PXå~#¶#¶#¶áÊhE¯Í²FãÜ’F¯Í¤FãÃLEñññÃ&GÍ?GÍ’FÃ&GÍ‹EÂ*G+Ã*GÍ‹EÚ*G+Ã*G!9###xî€G~¬E+~¹Â¬E+~ºÂ¬E+~»!ÉÍ?G{¦_#z¦W#y¦O#x¦GÃ&GÍ?GÍÁF(###Ë+Ë+Ë+ËÍñEèáÑÁé{/_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍÁFF!À+ÉÝåõõÝ!Ý9;å~Ýw6#~Ýw6#~Ýw6#~Ýw6.xæ€ÂFFËËËË,Ã4FÝuÿÝåáÍáFåÍzFáÊZFÒaFÍŒFÍûF7ãͤFÝ5ÿÊsFã¯Í²FÃOFñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍûFÃ’Få~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õüûFÍóFòßFÍáFÍûFÍáFñî€ÉñÉå~s_#~rW#~qO#~pGáÉå###~·áÉ{· ² ± ÕGxþ€Èå¯o›_}šW}™O}˜GáÉÍ!Gz·ð ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#pÉ!9ÉÍcGÈ+ÉÍcGÀ+ÉÍcGÐ+ÉëÍcGØ+ÉÍcGØ+É|î€gz {½!ÉÍyGØ+Éz¼Â€G{½!ÉDM¯og>Ë#Ë0 =È)ËGë¯íRÉÍ¢G#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉœ3xtrs-4.9d/umount.ccc000066400000000000000000000031261306603614600145420ustar00rootroot00000000000000/* umount.ccc -- Misosys C program to unmount an emulated floppy on xtrs */ /* Copyright (c) 1998, Timothy Mann */ /* $Id: umount.ccc,v 1.3 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ #option redirect 0 #include "xtrsemt.h" #include "xtrsemt.ccc" /* could use separate compilation instead */ usage() { fprintf(stderr, "usage: umount unit#\n"); exit(1); } #define DDIRSIZE 256 #define DNAMESIZE 512 #define CMDSIZE 512 #define ERRBUFSIZE 512 int main(argc, argv) int argc; char **argv; { char ddir[DDIRSIZE]; char dname[DNAMESIZE], cmd[CMDSIZE]; char errbuf[ERRBUFSIZE]; char model[4]; int hl, bc, de, ret; char *retp; if (argc != 2 || !isdigit(argv[1][0])) { usage(); } retp = emt_gtddir(ddir, DDIRSIZE); if (retp == NULL) { emt_strerror(errno, errbuf, ERRBUFSIZE); fprintf(stderr, "emt_getddir: %s\n", errbuf); exit(1); } emt_4misc(EMT_MISC_QUERY_MODEL, &hl, &bc, &de); if (hl == 5) { strcpy(model, "4p"); } else { sprintf(model, "%d", hl); } sprintf(dname, "%s/disk%s-%s", ddir, model, argv[1]); sprintf(cmd, "rm -f %s", dname); /*printf("$ %s\n", cmd);*/ ret = emt_system(cmd); if (ret != 0) { emt_strerror(errno, errbuf, ERRBUFSIZE); fprintf(stderr, "emt_system: %s\n", errbuf); exit(1); } emt_misc(EMT_MISC_DISK_CHANGE); exit(0); } xtrs-4.9d/umount.cmd000066400000000000000000000135221306603614600145560ustar00rootroot00000000000000WRÃUVemt_system: %s rm -f %s%s/disk%s-%s%d4pemt_getddir: %s usage: umount unit# bkÈOíCÊaÉñÑÕõí?!ÈOíCÊa!ÿÿÉ!—T@Rå!eRåÍWññ!åÍt`ñÉòøÍ4i!9Í%iå!Ñ;h|µÂíT!9Í%iå!ÍøhÑÍ%iå!Ñn&åÍofñÍi|µÊõTÍ–T!9å!å!9åÍ«RññÑÍ*i!9Í%iå!Ñ͸h|µÊNU!å!9å*ÊaåÍcSñññ!9å!/Rå!eRåÍWñññ!åÍt`ñ!9å!9å! 9å!åÍíSññññ!9Í%iå!Ñ͸h|µÊU!,Rå! 9åͨcññäU!9Í%iå!)—URå!9åÍ‹Wñññ!9Í%iå!ÍøhÑÍ%iå! 9å!9å!Rå!9åÍ‹Wñññññ!9å!Rå!9åÍ‹Wñññ!9å!9åÍšRñÑÍ*i!9Í%iå!Ñ;h|µÊ>V!å!9å*ÊaåÍcSñññ!9å!Rå!eRåÍWñññ!åÍt`ñ!åÍåSñ!åÍt`ñÍ4iÉís“R*I@Íif *D"•RùÍuVͬT!åÍt`*_R"UR"WRÍWí[URÍýV( Õ Í»V òô—VÅÝáË!ë "UR"WRË9AÑ+r+sùÁåÝåÅÉÓdÃÊcÅ~þ"(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( þ\ G#Ú#¯Á> ¾Ø> ¾È#õ!CÍifÀ!%BÉõÝåýå!9å! 9ÑÍ*i!9åÍ%i##ÑÍ*iå!ÿÿ)ÑÍ%i"$X!-a"&X!9åÍ%i##ÑÍ*iå!ÿÿ)ÑÍ%iåÝá!9åÝåáåÍ®Xññåýáýåáå!9Í;i!9ÍCiáñññÉ›‹WõÝåýå!9å! 9ÑÍ*i!9åÍ%i##ÑÍ*iå!ÿÿ)ÑÍ%i"‰W!9åÍ%i##ÑÍ*iå!ÿÿ)ÑÍ%iåÝá!"$X!X"&X!9åÝåáåÍ®Xññåýá*‰Wë}ýåáå!9Í;i!9ÍCiáñññÉ*‰W#"‰W+å!9n&Ñ}ÉyX0B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"*X!"(X**Xn&|µÊö_**Xn&%;h|µÊüX*&Xå*$Xãå**X#"*X+n&ãåÍ0iññ*(X#"(XÃó_!"AX"?X"=X";X"9X**X#"*Xn&åÑ!+ÍíhÂ,Y!"9XÃY!-ÍíhÂ>Y!";XÃY! ÍíhÂPY!"=XÃY!#ÍíhÂbY!"?XÃY!0ÍíhÂtY!"AXÃY**Xn&yY*͸h|µÊÊYñÁáåÅõåÍ%i##ÑÍ*iå!ÿÿ)ÑÍ%i"0X*0XëÍÑh|µÊÀY*0XÍi"0X!";X**X#"*XÃZ!"0X**Xn&åÍofñ|µÊZ*0X Íøhå**X#"*X+n&åÍ]`ñÑ"0XÃÐY**Xn&.͸h|µÊŠZ**X#"*Xn&*͸h|µÊOZñÁáåÅõåÍ%i##ÑÍ*iå!ÿÿ)ÑÍ%i"2X**X#"*XÇZ!"2X**Xn&åÍofñ|µÊ‡Z*2X Íøhå**X#"*X+n&yZåÍ]`ñÑ"2XÃUZÃZ!ÿÿ"2X!"7X**Xn&åÑ!lÍíh°Z!"7XùZ!hÍíhÂÀZ**X#"*X!"5X!­X"CX**X#"*X+n&}24XåÑ!dÍíhÂéZÃòZ!uÍíhÂûZ!"uXÃF[!oÍíh [!"uXÃF[!XÍíhÂ[Ã"[!xÍíhÂ+[!"uXÃF[!BÍíhÂ7[Ã@[!bÍíhÂù]!"uX*2XëÍÑh|µÊ[[!"2X*7X|µÊ‰[ñÁáåÅõåÍ%iÑÍ*iå!ÿÿy[))ÑÍ£h!mXÍ«hÃã[:4Xo&d͸h|µÊÀ[ñÁáåÅõåÍ%i##ÑÍ*iå!ÿÿ)ÑÍ%iÍh!mXÍ«hÃã[ñÁáåÅõåÍ%i##ÑÍ*iå!ÿÿ)ÑÍ%iÍ•h!mXÍ«h:4Xo&d͸h|µÊW\!mXÍ£hÅÕÍõf|µÊ8\!«X"CX!mXÍ£hÅÕ€Íëf|µÊ5\!mXÍ£hÍoh!mXÍ«hÃW\*9X|µÊI\!©X"CXÃW\*=X|µÊW\!§X"CX*AX|µÊŽ\õ!9å*0Xå*CXå͸cñÑÍ iÑÍ*iy\áåå*2XÑÍÊh|µÊ\áå"2Xñ:4Xo&X͸h|µÊ¥\!–Xë\!…Xë\"qX!EX(",X".X!mXÍ£hÍvg|µÊY]!mXÍ£hÅÕÍ$gë"wX!mXÍ£hÅÕÍ9gÅÕ€ÍXgÍ$g!mXÍ«h*,X+",Xå*qXå!mXÍ£hÅÕ*uXÍhÍfÅÕͱfÅÕ*wXÍhÍâfëÑn&Ñ}!mXÍ£hÅÕ*uXÍhÍ™f!mXÍ«hû\*,Xå*.XÑÍ iå*2XÑ"5X*?X|µÊ€]*,Xåy]*.XÑ;h|µÊö]:4Xo&åÑ!oÍíh®]*5XëÍÑh|µÊ«]!"5XÃö]!xÍíhÂÀ]!‚X"CXÃö]!XÍíhÂÒ]!X"CXÃö]!bÍíhÂä]!|X"CXÃö]!BÍíhÂö]!yX"CXÃö]Ãã^!cÍíhÂ4^!EXå!9Í%iåÍ%i##ÑÍ*iå!ÿÿ)ÑÍ%iÑ}!EX",X*,X#".XÃã^!sÍíh½^ñÁáåÅõåÍ%i##ÑÍ*iå!ÿÿ)ÑÍ%i",X*2XëÍÑh|µÊo^!ÿ"2X!"sXÃ^*y^sX#"sX*,X#",X+n&|µÊš^*sXå*2XÑÍÑh|µÊ¢^Ãx^*,X+",X".X*,Xå*sXÑÍ i",XÃã^!ÍíhÂÐ^**X+"*XÃã^!4X",X".X*.X#".XÃã^:4Xo&|µÊó_õ!9å*0Xå*.Xå*,XÑÍ iÑÍ iå*5XëÍÑh|µÊ_!Ã#_*5XÃ#_ÑÍ iå*CXå͸cñÑÍ iÑÍ*i*;XÍi|µÊg_!9åÍ%i+ÑÍ*iëÍÄh|µÊg_! åÍ`ñÃC_*CXn&|µÊ…_*CX#"CXy_+n&åÍ`ñÃg_*5X+"5XëÍÄh|µÊ£_!0åÍ`ñÃ…_*,Xå*.XÑÍçh|µÊÆ_*,X#",X+n&åÍ`ñã_*;X|µÊò_!9åÍ%i+ÑÍ*iëÍÄh|µÊò_! åÍ`ñÃÎ_ñûX*$X|µÊ`*$XåÍañ|µÊ`!ÿÿÃ`*(XÃ`É*&Xå*$Xãå!9n&ãåÍ0iññ*(X#"(XÉñáåõå!9Í%iÑÍÑh|µÊS`ñáåõÃ\`ñÁáåÅõÃ\`É!9n&0·íRÉñáåõ0É̓`ñá(y`åõ|µÊ-@Ã0@!aRA^#V#{²( ÅåëË^ÌÂ`áÁìÉ¡`!ÿÿ"Ÿ`ñáåõÝååÝáÍŸc(MË^ M¯ÝwÝwÝååÝá++å##íCŸ`~q#Ë~(ëÝnÝfåËo Í(D( Íùa!ÿÿ"Ÿ`͵VÁ͵Vá*Ÿ`ÝáÉ!Ý!("ÊaîÝåÍ•cÝá(~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáÍŸc(WËN(SËv OT]åÝá:ƒRþ*(Ë^#Ä%iëÅyþ Ý~ÿæ 4yÍõÝ4þñë(Ë~á }Ö ÝwþÝáÉëËöËî!Ë^(wÍùa!ÿÿå yÍ(+¡aË~ Éͬa ïÂÝ4þÕÝ^þÝ~ÿæ?Ëq(ö@ö€Í DåÍ bñ"ÊaáÉñáåõ&}íKûb ¹0þ@Ðþ-.@Ð!Ìa…oŒ•gn&ÉUbcbub…b–bªbÁbàbñbUnknown errorArg list too longNot a directoryInvalid argumentToo many open filesNot a character deviceMath arg ouüÌbt of domain of funcResult too largeI/O errorHñÑÕõ{þ@8Ö@o&þ 8l)CbÃ%iöÀõ!|DÍif !‹B"PcT]Í%i"Mc!?cÍ*iñÍ D!UcÉUc~#Ö ø!Ã*iñáÑÝáÝåÕåõÝnÝf|µÉñÑÁÅÕõbk ·ÈøñÑÕõ!·È#ùÉÊcñÑÕõÝåýå!"Æcý!YR*YRý"ÈcÝåýáÝnÝfåÝá|µ(7ÝnÝfí[Æc·íR8ÜíB0ÝnÝfýuýt ÝuÝtDMÝ ÝsÝr*ÆcåÍ^dÁ|¥< !#"ÊaåÝáÝqÝpÝåÍ fágoýáÝáÉñÑÕõz³('!9íBíKURíB8 íR8Åë "URáÉ!#"Êa!ÿÿÉ*URÉ“dñÑÕõÝåýåÍ£dýáÝáÉ!|eÍeÝ!üÿÝÍAfý!YR ý"‘dýnýfåýáý^ýVz³(ÝåáíR0âÍaeÝåÁýqýpýå!YRÑ·íR('ýnýf·íB ÍneýuýtÝnÝfýuýtýåÝáý"‘dÝNÝFÅýáx±(ÝåáÝ^ÝV·íB ÍneÝuÝtÍaeý*‘dÝåáÝ^ÝVíKUR¯íBÀýwýwÝ"URÉýnýfÝuÝtÉýnýfÝ^ÝVÉFREEÝåÅÕåë+F+N++Í–eáÑÁ“eÝáÉëÝ![RÝnÝf|µ(åÝáíRÈ8îñ!àeÍóeYP!íeÍóe> Í3áÍgD!ÒeÍgD!ÿÿåÍw`: BAD BLOCK X'xxxx', LEN X'xxxx' zÍøe{õÍfñæÆ'Î@'w#ÉýååÕý![RÕýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý![RÕýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌ:%þIÉñáåõ}!þ0Øþ:Ð#ÉͳhÍ5hÊšhÍghõÍ:hÍgñ“füohÚhͳhÍ5hÊšhÍ:hõÍgñáÑÁüohéͳhÅÕå!9PXå~#¶#¶#¶áÊÜf¯Í&hãÜh¯ÍhãÃÀfñññÚhͳhÍhÚhÍÿfžh+ÞhÍÿfÚžh+Þh!9###xî€G~ g+~¹Â g+~ºÂ g+~»!Éͳh{¦_#z¦W#y¦O#x¦GÚhͳhÍ5h(###Ë+Ë+Ë+ËÍegèáÑÁé{/_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍ5h!À+ÉÝåõõÝ!Ý9;å~Ýw6#~“gÝw6#~Ýw6#~Ýw6.xæ€ÂºgËËËË,ègÝuÿÝåáÍUhåÍîgáÊÎgÒÕgÍhÍoh7ãÍhÝ5ÿÊçgã¯Í&hÃÃgñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍohÃhå~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õüohÍghòShÍUhÍohÍUhñî€ÉñÉå~s_#~rW#~qO#~pGáÉå###~·áÉ{· ² ± xþ€Èå¯o›_}šW}™O}˜GáÉÍ•hz·ðº“h ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#pÉ!9ÉÍ×hÈ+ÉÍ×hÀ+ÉÍ×hÐ+ÉëÍ×hØ+ÉÍ×hØ+É|î€gz {½!ÉÍíhØ+Éz¼Âôh{½!ÉDM¯og>Ë#Ë0 =È)Ãÿhë¯íRÉÍi#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉUVxtrs-4.9d/umount6.cmd000066400000000000000000000134771306603614600146550ustar00rootroot00000000000000W0ÃW4emt_system: %s rm -f %s%s/disk%s-%s%d4pemt_getddir: %s usage: umount unit# bkÈOíCß?ÉñÑÕõí?!ÈOíCß?!ÿÿÉ!™2@0å!e0åÍ55ññ!åÍ–>ñÉòøÍG!9ÍGå!ÑÍ©F|µÂï2!9ÍGå!ÍãFÑÍGå!Ñn&åÍZDñÍG|µÊ÷2͘2!9å!å!9åÍ­0ññÑÍG!9ÍGå!ÑÍ£F|µÊP3!å!9å*ß?åÍe1ñññ!9å!/0å!e0åÍ55ñññ!åÍ–>ñ!9å!9å! 9å!åÍï1ññññ!9ÍGå!ÑÍ£F|µÊ3!,0å! 9åͲAññæ3!9ÍGå!)™30å!9åÍ­5ñññ!9ÍGå!ÍãFÑÍGå! 9å!9å!0å!9åÍ­5ñññññ!9å!0å!9åÍ­5ñññ!9å!9åÍœ0ñÑÍG!9ÍGå!ÑÍ©F|µÊ@4!å!9å*ß?åÍe1ñññ!9å!0å!e0åÍ55ñññ!åÍ–>ñ!åÍç1ñ!åÍ–>ñÍGÉís•0íC“0>d!Eï"—0ë!ÿóíRë0 >eïý~þ` !ÿóùÍ4Í®2!åÍ–>*_0"U0"W0KI™4>Rï"„0DO>Rï"Š0"0*“0í[U0Í*5( Õ Íè4 òÅÝáË!ë "U0"W0Ë9AÑ+r+sùÁåÝåÅÉÃBÃÔAÅ~þ"(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( þ\ G#Ú#¯Á> ¾Ø> ¾È#õõÝåýå!9å! 9ÑÍG!9åÍG##ÑÍGå!ÿÿ)ÑÍG"F6!L?"H6!9åÍG##ÑÍGå!ÿÿ)ÑÍGåÝá!9åÝåáåÍÐ6ññåýáýåáå!™59Í&G!9Í.GáñññÉ›­5õÝåýå!9å! 9ÑÍG!9åÍG##ÑÍGå!ÿÿ)ÑÍG"«5!9åÍG##ÑÍGå!ÿÿ)ÑÍGåÝá!"F6!26"H6!9åÝåáåÍÐ6ññåýá*«5ë}ýåáå!9Í&G!9Í.GáñññÉ*«5#"«5+å!9n&Ñ}É›60B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"L6!"J6*L6n&|µÊ>*L6n&%Í©F|µÊ7*H6å*F6ãå*L6#"L6+n&ãåÍGññ*J6#"J6Ã>!"c6"a6"_6"]6"[6*L6#"L6n&åÑ!+ÍØFÂN7!"[6Ã07!-ÍØFÂ`7!"]6Ã07! ÍØFÂr7!"_6Ã07!#ÍØF„7!"a6Ã07!0ÍØF–7!"c6Ã07*L6n&›7*Í£F|µÊì7ñÁáåÅõåÍG##ÑÍGå!ÿÿ)ÑÍG"R6*R6ëͼF|µÊâ7*R6ÍüF"R6!"]6*L6#"L6Ã$8!"R6*L6n&åÍZDñ|µÊ$8*R6 ÍãFå*L6#"L6+n&åÍ>ñÑ"R6Ãò7*L6n&.Í£F|µÊ¬8*L6#"L6n&*Í£F|µÊq8ñÁáåÅõåÍG##ÑÍGå!ÿÿ)ÑÍG"T6*L6#"L6é8!"T6*L6n&åÍZDñ|µÊ©8*T6 ÍãFå*L6#"L6+n&›8åÍ>ñÑ"T6Ãw8ò8!ÿÿ"T6!"Y6*L6n&åÑ!lÍØFÂÒ8!"Y6ÃÛ8!hÍØFÂâ8*L6#"L6!"W6!Ï6"e6*L6#"L6+n&}2V6åÑ!dÍØF 9Ã9!uÍØFÂ9!"—6Ãh9!oÍØFÂ/9!"—6Ãh9!XÍØFÂ;9ÃD9!xÍØFÂM9!"—6Ãh9!BÍØFÂY9Ãb9!bÍØFÂõ!9å*R6å*P6å*N6ÑÍ÷FÑÍ÷Få*W6ëͼF|µÊ?=!ÃE=*W6ÃE=ÑÍ÷Få*e6åÍÂAñÑÍ÷FÑÍG*]6ÍG|µÊ‰=!9åÍG+ÑÍGëͯF|µÊ‰=! åÍ:>ñÃe=*e6n&|µÊ§=*e6#"e6›=+n&åÍ:>ñÉ=*W6+"W6ëͯF|µÊÅ=!0åÍ:>ñç=*N6å*P6ÑÍÒF|µÊè=*N6#"N6+n&åÍ:>ñÃÅ=*]6|µÊ>!9åÍG+ÑÍGëͯF|µÊ>! åÍ:>ñÃð=ñÃÝ6*F6|µÊ(>*F6åÍ-?ñ|µÊ3>!ÿÿÃ9>*J6Ã9>É*H6å*F6ãå!9n&ãåÍGññ*J6#"J6Éñáåõå!9ÍGÑͼF|µÊu>ñáåõÃ~>ñÁáåÅõÃ~>É!9n&0·íRÉñáåõ0ÉÍ¢>ñá%›>åõí{•0É!a0A^#V#{²( ÅåëË^Ìá>áÁìÉÀ>!ÿÿ"¾>ñáåõÝååÝáÍ©A(MË^ M¯ÝwÝwÝååÝá++å##íC¾>~q#Ë~(ëÝnÝfåËo ><ï( Í@!ÿÿ"¾>Íâ4ÁÍâ4á*¾>ÝáÉ!Ý!("ß?îÝåÍŸAÝá(~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáÍ©A(RËN(NËv JT]åÝá:ƒ0þ*(Ë^#ÄGëÅyþ Ý~ÿæ />ïõÝ4þñëá }Ö ÝwþÝáÉëËöËî!Ë^(wÍ@!ÿÿå >ï ÒÍÁ? ô!À?ËÝ4þÕÝ^þÝ~ÿæ?Ëq(ö@ö€O>ïåÍ6@ñ"ß?áÉñáåõ&}íKA ¹0þ@Ðþ-.@Ð!á?…oŒ•gn&Ék@y@‹@›@¬@À@×@ö@AUnknown errorArg list too longNot a directoryInvalid argumentToo many open filesNot a character deviceMath arg oñá@ut of domain of funcResult too largeI/O errorHñÑÕõ{þ@8Ö@o&þ 8l)Y@ÃGöÀOýå>eïýËþýáOA>ïbk> Pí±+pëÉñáÑÝáÝåÕåõÝnÝf|µÉñÑÁÅÕõbk ·ÈøñÑÕõ!·È#ùÉÔAñÑÕõÝåýå!"ÐAý!Y0*Y0ý"ÒAÝåýáÝnÝfåÝá|µ(7ÝnÝfí[ÐA·íR8ÜíB0ÝnÝfýuýt ÝuÝtDMÝ ÝsÝr*ÐAåÍhBÁ|¥< !#"ß?åÝáÝqÝpÝåÍýCágoýáÝáÉñÑÕõz³('!9íBíKU0íB8 íR8Åë "U0áÉ!#"ß?!ÿÿÉ*U0ÉBñÑÕõÝåýåÍ­BýáÝáÉ!†CÍ‹CÝ!üÿÝÍ2Dý!Y0 ý"›Býnýfåýáý^ýVz³(ÝåáíR0âÍkCÝåÁýqýpýå!Y0Ñ·íR('ýnýf·íB ÍxCýuýtÝnÝfýuýtýåÝáý"›BÝNÝFÅýáx±(ÝåáÝ^ÝV·íB ÍxCÝuÝtÍkCý*›BÝåáÝ^ÝVíKU0¯íBÀýwýwÝ"U0ÉýnýfÝuÝtÉýnýfÝ^ÝVÉFREEÝåÅÕåë+F+N++Í CáÑÁCÝáÉëÝ![0ÝnÝf|µ(åÝáíRÈ8îñ!êC>cïYP!÷C>cï >ïá> ï!ÜC> ï!ÿÿåÍ™>: BAD BLOCK X'xxxx', LEN X'xxxx' ýååÕý![0Õýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý![0Õýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌñáåõ}!þ0Øþ:Ð#ÉÍžFÍ FÊ…FÍRFõÍ%FÍjEñüZFÃ…FÍžFÍ FÊ…FÍ%FõÍjEñáÑÁüZFéÍDžFÅÕå!9PXå~#¶#¶#¶áÊÇD¯ÍFãÜñE¯ÍFãëDñññÃ…FÍžFÍñEÃ…FÍêD‰F+ÉFÍêDÚ‰F+ÉF!9###xî€G~ E+~¹Â E+~ºÂ E+~»!ÉÍžF{¦_#z¦W#y¦O#x¦GÃ…FÍžFÍ F(###Ë+Ë+Ë+ËÍPEèáÑÁé{/_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍ F!À+ÉÝåõõÝ!Ý9;å~Ýw6#~Ýw6#~Ýw6#~Ýw6.xæ€Â¥EËËEËË,ÓEÝuÿÝåáÍ@FåÍÙEáʹEÒÀEÍëEÍZF7ãÍFÝ5ÿÊÒEã¯ÍFîEñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍZFÃñEå~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õüZFÍRFò>FÍ@FÍZFÍ@Fñî€ÉñÉå~s_#~rW#~qO#~pGáÉå###~·áÉ{· ² ± xþ€Èå¯o›_}šW}™O}˜GáÉÍ€Fz·ð ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#p›FÉ!9ÉÍÂFÈ+ÉÍÂFÀ+ÉÍÂFÐ+ÉëÍÂFØ+ÉÍÂFØ+É|î€gz {½!ÉÍØFØ+Éz¼ÂßF{½!ÉDM¯og>Ë#Ë0 =È)ÃêFë¯íRÉÍG#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉW4xtrs-4.9d/unix.ccc000066400000000000000000000032641306603614600142010ustar00rootroot00000000000000/* unix.ccc -- Misosys C program to execute a Unix shell command from xtrs */ /* Copyright (c) 1998, Timothy Mann */ /* $Id: unix.ccc,v 1.3 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ #option redirect 0 #include "xtrsemt.h" #include "xtrsemt.ccc" /* could use separate compilation instead */ usage() { fprintf(stderr, "usage: unix [-l] command\n"); exit(1); } #define ERRBUFSIZE 256 #define CMDBUFSIZE 512 int main(argc, argv) int argc; char **argv; { int ret, i, lower; char errbuf[ERRBUFSIZE]; char cmdbuf[CMDBUFSIZE]; char *p, *q; if (argc < 2) { usage(); } i = 1; if (argv[i][0] == '-') { if (tolower(argv[i][1]) != 'l') { usage(); } i++; lower = 1; } else { lower = 0; } p = cmdbuf; for (; i> 8, ret & 0xff); exit(1); } exit(0); } xtrs-4.9d/unix.cmd000066400000000000000000000142421306603614600142120ustar00rootroot00000000000000RRÃûWunix: error (exit status %d, signal %d) unix: %s usage: unix [-l] command bkÈOíCÕbÉñÑÕõí?!ÈOíCÕb!ÿÿÉ!’T6Rå!`Rå͹Xññ!åÍañÉöüÍzj! 9Íkjå!ÑÍj|µÊÄTÍ‘T!9å!ÑÍpj!9Íkjå!9ÍkjÍ,jÑÍkjå!Ñn&å!-ÑÍìi|µÊUU!9Íkjå!9ÍkjÍ,jÑÍkjå!Ñn&åÍjgñå!lÑÍòi|µÊ8UÍ‘T!9åÍkj#ÑÍpj+!9å!ÑÍpjÃaU!9å!ÑÍpj!9å!9ÑÍpjÃU!9åÍkj#ÑÍpj+!9Íkjå!9ÍkjÑÍj’U|µÊ&W!9å!9Íkjå! 9ÍkjÍ,jÑÍkjÑÍpj!9Íkj|µÊÇV!9Íkjn&|µÊÄV!9Íkjn&å![ÑÍìi|µÊüU!9Íkjå!Ñn&|µÊGV!9åÍkjÑÍpjÿÿ!9åÍkjÑÍpjÿÿå!9åÍkjÑÍpjÿÿn&Ñ}ÃÁV!9Íkjn&åÍ€gñ|µÊ’V!9åÍkjÑÍpjÿÿå!9åÍkjÑÍpjÿÿn&åÍjgñÑ}ÃÁV’V!9åÍkjÑÍpjÿÿå!9åÍkjÑÍpjÿÿn&Ñ}ÃÆUÃW!9Íkjn&|µÊW!9åÍkjÑÍpjÿÿå!9åÍkjÑÍpjÿÿn&Ñ}ÃÇV!9åÍkjÑÍpjÿÿå! Ñ}ÃqU!9Íkjå!Ñ}!9å!9åÍ•RñÑÍpj!9Íkjå!ÍWjÑÍìi|µÊŽW!å!9å*ÕbåÍ^Sñññ!9å!,Rå!`Rå͹Xñññ!åÍañÃìW!9’WÍkjå!ÑÍòi|µÊìW!å!9å*ÕbåÍ^Sñññ!9Íkjå!ÿÑÍEjå! 9Íkjå!ÑÍLjå!Rå!`Rå͹Xññññ!åÍañ!åÍañ ÍzjÉísŽR*I@Ídg *D"RùÍXͧT!åÍa*ZR"PR"RRÍ®Xí[PRÍ£X( Õ ÍaX òÅÝáË!ë "PR"RRË9AÑ+r+sùÁåÝåÅÉÃŽeÃÅdÅ~þ"(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( Ÿ’Xþ\ G#Ú#¯Á> ¾Ø> ¾È#õ!CÍdgÀ!%BÉõÝåýå!9å! 9ÑÍpj!9åÍkj##ÑÍpjå!ÿÿ)ÑÍkj"/Y!8b"1Y!9åÍkj##ÑÍpjå!ÿÿ)ÑÍkjåÝá!9åÝåáå͹Yññåýáýåáå!9Íj!9͉jáñññÉ„Y0B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"5Y!"3Y*5Yn&|µÊa*5Yn&%Íòi|µÊZ*1Yå*/Yãå*5Y#"5Y+n&ãåÍvjññ*3Y#"3YÃþ`!"LY"JY"HY"FY"DY*5Y#"5Yn&åÑ!+Í!jÂ7Z!"DYÃZ!-Í!jÂIZ!"FYÃZ! Í!jÂ[Z!"HYÃZ!#Í!jÂmZ!"JYÃZ!0Í!jÂZ!"LYÃZ*5Yn&„Z*Íìi|µÊÕZñÁáåÅõåÍkj##ÑÍpjå!ÿÿ)ÑÍkj";Y*;YëÍj|µÊËZ*;YÍWj";Y!"FY*5Y#"5Yà [!";Y*5Yn&åÍ“gñ|µÊ [*;Y Í,jå*5Y#"5Y+n&åÍhañÑ";YÃÛZ*5Yn&.Íìi|µÊ•[*5Y#"5Yn&*Íìi|µÊZ[ñÁáåÅõåÍkj##ÑÍpjå!ÿÿ)ÑÍkj"=Y*5Y#"5YÃ’[!"=Y*5Yn&åÍ“gñ|µÊ’[*=Y Í,jå*5Y#"5Y+n&„[åÍhañÑ"=YÃ`[Û[!ÿÿ"=Y!"BY*5Yn&åÑ!lÍ!j»[!"BYÃÄ[!hÍ!jÂË[*5Y#"5Y!"@Y!¸Y"NY*5Y#"5Y+n&}2?YåÑ!dÍ!jÂô[Ãý[!uÍ!jÂ\!"€YÃQ\!oÍ!jÂ\!"€YÃQ\!XÍ!jÂ$\Ã-\!xÍ!jÂ6\!"€YÃQ\!BÍ!jÂB\ÃK\!bÍ!jÂ_!"€Y*=YëÍj|µÊf\!"=Y*BY|µÊ”\ñÁáåÅõåÍkjÑÍpjå!ÿÿ„\))ÑÍ×i!xYÍßiÃî\:?Yo&dÍìi|µÊË\ñÁáåÅõåÍkj##ÑÍpjå!ÿÿ)ÑÍkjÍÁi!xYÍßiÃî\ñÁáåÅõåÍkj##ÑÍpjå!ÿÿ)ÑÍkjÍÉi!xYÍßi:?Yo&dÍìi|µÊb]!xYÍ×iÅÕÍ)h|µÊC]!¶Y"NY!xYÍ×iÅÕ€Íh|µÊ@]!xYÍ×iÍ£i!xYÍßiÃb]*DY|µÊT]!´Y"NYÃb]*HY|µÊb]!²Y"NY*LY|µÊ™]õ!9å*;Yå*NYåͳdñÑÍ@jÑÍpj„]áåå*=YÑÍþi|µÊ˜]áå"=Yñ:?Yo&XÍìi|µÊ°]!¡Yö]!Yö]"|Y!PY("7Y"9Y!xYÍ×iͪh|µÊd^!xYÍ×iÅÕÍXhë"‚Y!xYÍ×iÅÕÍmhÅՀ͌hÍXh!xYÍßi*7Y+"7Yå*|Yå!xYÍ×iÅÕ*€YÍÁiͳgÅÕÍågÅÕ*‚YÍÁiÍhëÑn&Ñ}!xYÍ×iÅÕ*€YÍÁiÍÍg!xYÍßiÃÆ]*7Yå*9YÑÍ@jå*=YÑ"@Y*JY|µÊ‹^*7Yå„^*9YÑÍòi|µÊ_:?Yo&åÑ!oÍ!j¹^*@YëÍj|µÊ¶^!"@YÃ_!xÍ!jÂË^!Y"NYÃ_!XÍ!jÂÝ^!ŠY"NYÃ_!bÍ!jÂï^!‡Y"NYÃ_!BÍ!jÂ_!„Y"NYÃ_Ãî_!cÍ!jÂ?_!PYå!9ÍkjåÍkj##ÑÍpjå!ÿÿ)ÑÍkjÑ}!PY"7Y*7Y#"9YÃî_!sÍ!jÂÈ_ñÁáåÅõåÍkj##ÑÍpjå!ÿÿ)ÑÍkj"7Y*=YëÍj|µÊz_!ÿ"=Y!"~YÊ_*„_~Y#"~Y*7Y#"7Y+n&|µÊ¥_*~Yå*=YÑÍj|µÊ­_Ã_*7Y+"7Y"9Y*7Yå*~YÑÍ@j"7YÃî_!Í!jÂÛ_*5Y+"5YÃî_!?Y"7Y"9Y*9Y#"9YÃî_:?Yo&|µÊþ`õ!9å*;Yå*9Yå*7YÑÍ@jÑÍ@jå*@YëÍj|µÊ(`!Ã.`*@YÃ.`ÑÍ@jå*NYåͳdñÑÍ@jÑÍpj*FYÍcj|µÊr`!9åÍkj+ÑÍpjëÍøi|µÊr`! åÍ#añÃN`*NYn&|µÊ`*NY#"NY„`+n&åÍ#añÃr`*@Y+"@YëÍøi|µÊ®`!0åÍ#añÃ`*7Yå*9YÑÍj|µÊÑ`*7Y#"7Y+n&åÍ#añî`*FY|µÊý`!9åÍkj+ÑÍpjëÍøi|µÊý`! åÍ#añÃÙ`ñÃÆY*/Y|µÊa*/YåÍbñ|µÊa!ÿÿÃ"a*3YÃ"aÉ*1Yå*/Yãå!9n&ãåÍvjññ*3Y#"3YÉñáåõå!9ÍkjÑÍj|µÊ^añáåõÃgañÁáåÅõÃgaÉ!9n&0·íRÉñáåõ0ÉÍŽañá(„aåõ|µÊ-@Ã0@!\RA^#V#{²( ÅåëË^ÌÍaáÁìɬa!ÿÿ"ªañáåõÝååÝáͪd(MË^ M¯ÝwÝwÝååÝá++å##íCªa~q#Ë~(ëÝnÝfåËo Í(D( Íc!ÿÿ"ªaÍ[XÁÍ[Xá*ªaÝáÉ!Ý!("ÕbîÝåÍ dÝá(~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáͪd(WËN(SËv OT]åÝá:~Rþ*(Ë^#ÄkjëÅyþ Ý~ÿæ 4yÍõÝ4þñë(Ë~á }Ö ÝwþÝáÉëËöËî!Ë^(wÍc!ÿÿå yÍ(+¬bË~ ÉÍ·b ïÂÝ4þÕÝ^þÝ~ÿæ?Ëq(ö@ö€Í DåÍ+cñ"ÕbáÉñáåõ&}íKd ¹0þ@Ðþ-.@Ð!×b…oŒ•gn&É`cnc€cc¡cµcÌcëcücUnknown errorArg list too longNot a directoryInvalid argumentToo many open filesNot a character deviceMath arg ouì×ct of domain of funcResult too largeI/O errorHñÑÕõ{þ@8Ö@o&þ 8l)NcÃkjöÀõ!|DÍdg !‹B"[dT]Íkj"Xd!JdÍpjñÍ D!`dÉ`d~#Ö ø!ÃpjñáÑÝáÝåÕåõÝnÝf|µÉñÑÕõ!·È#ùÉÅdñÑÕõÝåýå!"Ádý!TR*TRý"ÃdÝåýáÝnÝfåÝá|µ(7ÝnÝfí[Ád·íR8ÜíB0ÝnÝfýuýt ÝuÝtDMÝ ÝsÝr*ÁdåÍYeÁ|¥< !#"ÕbåÝáÝqÝpÝåÍgágoýáÝáÉñÑÕõz³('!9íBíKPRíB8 íR8Åë "PRáÉ!#"Õb!ÿÿÉ*PRÉŽeñÑÕõÝåýåÍžeýáÝáÉ!wfÍ|fÝ!üÿÝÍ Í3áÍgD!ÍfÍgD!ÿÿåÍ‚a: BAD BLOCK X'xxxx', LEN X'xxxx' zÍóf{õÍüfñæÆ'Î@'w#ÉýååÕý!VRÕýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý!VRÕýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌ:%þIÉñÑÕõÕÕÍ£gÁÑëz³È}ö &oÉñáåõ}!ö þa8Žgþ{Ø+Éñáåõ}!þ0Øþ:Ð#Éñáåõ}!þAØþ[Ð#ÉÍçiÍiiÊÎiÍ›iõÍniͳhñü£iÃÎiÍçiÍiiÊÎiÍniõͳhñáÑÁü£iéÍçiÅÕå!9PXå~#¶#¶#¶áÊh¯ÍZiãÜ:i¯ÍLiãÃôgñññÃÎiÍçiÍ:iÃÎiÍ3hÂÒi+ÃÒiÍ3hÚÒi+ÃÒi!9###xî€G~ÂTh+~¹ÂTh+~ºÂTh+~»!ÉÍçi{¦_#z¦W#y¦O#x¦GÃÎiÍçiÍii(###Ë+Ë+Ë+ËÍ™hèáÑÁé{/Žh_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍii!À+ÉÝåõõÝ!Ý9;å~Ýw6#~Ýw6#~Ýw6#~Ýw6.xæ€ÂîhËËËË,ÃÜhÝuÿÝåá͉iåÍ"iáÊiÒ iÍ4iÍ£i7ãÍLiÝ5ÿÊiã¯ÍZiÃ÷hñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍ£iÃ:iå~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õü£iÍ›iò‡i͉iÍ£i͉iñî€ÉñÉå~s_#Ži~rW#~qO#~pGáÉå###~·áÉ{· ² ± xþ€Èå¯o›_}šW}™O}˜GáÉÍÉiz·ð ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#pÉ!9ÉÍ jÈ+ÉÍ jÀ+ÉÍ jÐ+ÉëÍ jØ+ÉÍ jØ+É|î€gz {½!ÉÍ!jØ+Éz¼Â(j{½!ÉDM¯og>Ë#Ë0 =È)Ã3jë¯íRÉ}£o|¢gÉëz³ÈË<ËöÍ\j#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåŽjýáÉûWxtrs-4.9d/unix6.cmd000066400000000000000000000142071306603614600143010ustar00rootroot00000000000000R0Ãý5unix: error (exit status %d, signal %d) unix: %s usage: unix [-l] command bkÈOíCê@ÉñÑÕõí?!ÈOíCê@!ÿÿÉ!”260å!`0åÍÛ6ññ!åÍ¡?ñÉöüÍeH! 9ÍVHå!ÑÍðG|µÊÆ2Í“2!9å!ÑÍ[H!9ÍVHå!9ÍVHÍHÑÍVHå!Ñn&å!-ÑÍ×G|µÊW3!9ÍVHå!9ÍVHÍHÑÍVHå!Ñn&åÍUEñå!lÑÍÝG|µÊ:3Í“2!9åÍVH#ÑÍ[H+!9å!ÑÍ[HÃc3!9å!ÑÍ[H!9å!9ÑÍ[HÃ3!9åÍVH#ÑÍ[H+!9ÍVHå!9ÍVHÑÍðG”3|µÊ(5!9å!9ÍVHå! 9ÍVHÍHÑÍVHÑÍ[H!9ÍVH|µÊÉ4!9ÍVHn&|µÊÆ4!9ÍVHn&å![ÑÍ×G|µÊþ3!9ÍVHå!Ñn&|µÊI4!9åÍVHÑÍ[Hÿÿ!9åÍVHÑÍ[Hÿÿå!9åÍVHÑÍ[Hÿÿn&Ñ}ÃÃ4!9ÍVHn&åÍkEñ|µÊ”4!9åÍVHÑÍ[Hÿÿå!9åÍVHÑÍ[Hÿÿn&åÍUEñÑ}ÃÃ4”4!9åÍVHÑÍ[Hÿÿå!9åÍVHÑÍ[Hÿÿn&Ñ}ÃÈ3à 5!9ÍVHn&|µÊ 5!9åÍVHÑÍ[Hÿÿå!9åÍVHÑÍ[Hÿÿn&Ñ}ÃÉ4!9åÍVHÑÍ[Hÿÿå! Ñ}Ãs3!9ÍVHå!Ñ}!9å!9åÍ—0ñÑÍ[H!9ÍVHå!ÍBHÑÍ×G|µÊ5!å!9å*ê@åÍ`1ñññ!9å!,0å!`0åÍÛ6ñññ!åÍ¡?ñÃî5!9”5ÍVHå!ÑÍÝG|µÊî5!å!9å*ê@åÍ`1ñññ!9ÍVHå!ÿÑÍ0Hå! 9ÍVHå!ÑÍ7Hå!0å!`0åÍÛ6ññññ!åÍ¡?ñ!åÍ¡?ñ ÍeHÉís0íCŽ0>d!Eï"’0ë!ÿóíRë0 >eïý~þ` !ÿóùÍ36Í©2!åÍ¡?*Z0"P0"R0KI>Rï"0DO>Rï"…0"‹0*Ž0í[P0ÍÐ6( Õ ÍŽ6 òÅÝáË!ë "P0"R0Ë9AÑ+r+sùÁåÝåÅÉØCÃÏBÅ~þ"¿”6(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( þ\ G#Ú#¯Á> ¾Ø> ¾È#õõÝåýå!9å! 9ÑÍ[H!9åÍVH##ÑÍ[Hå!ÿÿ)ÑÍVH"Q7!W@"S7!9åÍVH##ÑÍ[Hå!ÿÿ)ÑÍVHåÝá!9åÝåáåÍÛ7ññåýáýåáå!9ÍlH!9ÍtHáñññɦ70B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"W7!"U7*W7n&|µÊ#?*W7n&%ÍÝG|µÊ)8*S7å*Q7ãå*W7#"W7+n&ãåÍaHññ*U7#"U7à ?!"n7"l7"j7"h7"f7*W7#"W7n&åÑ!+Í HÂY8!"f7Ã;8!-Í HÂk8!"h7Ã;8! Í HÂ}8!"j7Ã;8!#Í HÂ8!"l7Ã;8!0Í H¡8!"n7Ã;8*W7n&¦8*Í×G|µÊ÷8ñÁáåÅõåÍVH##ÑÍ[Hå!ÿÿ)ÑÍVH"]7*]7ëÍðG|µÊí8*]7ÍBH"]7!"h7*W7#"W7Ã/9!"]7*W7n&åÍ~Eñ|µÊ/9*]7 ÍHå*W7#"W7+n&åÍŠ?ñÑ"]7Ãý8*W7n&.Í×G|µÊ·9*W7#"W7n&*Í×G|µÊ|9ñÁáåÅõåÍVH##ÑÍ[Hå!ÿÿ)ÑÍVH"_7*W7#"W7ô9!"_7*W7n&åÍ~Eñ|µÊ´9*_7 ÍHå*W7#"W7+n&¦9åÍŠ?ñÑ"_7Â9ý9!ÿÿ"_7!"d7*W7n&åÑ!lÍ HÂÝ9!"d7Ãæ9!hÍ HÂí9*W7#"W7!"b7!Ú7"p7*W7#"W7+n&}2a7åÑ!dÍ HÂ:Ã:!uÍ HÂ(:!"¢7Ãs:!oÍ HÂ::!"¢7Ãs:!XÍ HÂF:ÃO:!xÍ HÂX:!"¢7Ãs:!BÍ HÂd:Ãm:!bÍ HÂ&=!"¢7*_7ëÍðG|µÊˆ:!"_7*d7|µÊ¶:ñÁáåÅõåÍVHÑÍ[Hå!ÿÿ¦:))ÑÍÂG!š7ÍÊGÃ;:a7o&dÍ×G|µÊí:ñÁáåÅõåÍVH##ÑÍ[Hå!ÿÿ)ÑÍVHͬG!š7ÍÊGÃ;ñÁáåÅõåÍVH##ÑÍ[Hå!ÿÿ)ÑÍVHÍ´G!š7ÍÊG:a7o&dÍ×G|µÊ„;!š7ÍÂGÅÕÍF|µÊe;!Ø7"p7!š7ÍÂGÅÕ€Í F|µÊb;!š7ÍÂGÍŽG!š7ÍÊGÄ;*f7|µÊv;!Ö7"p7Ä;*j7|µÊ„;!Ô7"p7*n7|µÊ»;õ!9å*]7å*p7åͽBñÑÍ+HÑÍ[H¦;áåå*_7ÑÍéG|µÊº;áå"_7ñ:a7o&XÍ×G|µÊÒ;!Ã7ÃØ;!²7ÃØ;"ž7!r7("Y7"[7!š7ÍÂGÍ•F|µÊ†!cÍ HÂa=!r7å!9ÍVHåÍVH##ÑÍ[Hå!ÿÿ)ÑÍVHÑ}!r7"Y7*Y7#"[7Ã>!sÍ HÂê=ñÁáåÅõåÍVH##ÑÍ[Hå!ÿÿ)ÑÍVH"Y7*_7ëÍðG|µÊœ=!ÿ"_7!" 7ì=*¦= 7#" 7*Y7#"Y7+n&|µÊÇ=* 7å*_7ÑÍðG|µÊÏ=Ã¥=*Y7+"Y7"[7*Y7å* 7ÑÍ+H"Y7Ã>!Í HÂý=*W7+"W7Ã>!a7"Y7"[7*[7#"[7Ã>:a7o&|µÊ ?õ!9å*]7å*[7å*Y7ÑÍ+HÑÍ+Hå*b7ëÍðG|µÊJ>!ÃP>*b7ÃP>ÑÍ+Hå*p7åͽBñÑÍ+HÑÍ[H*h7ÍNH|µÊ”>!9åÍVH+ÑÍ[HëÍãG|µÊ”>! åÍE?ñÃp>*p7n&|µÊ²>*p7#"p7¦>+n&åÍE?ñÔ>*b7+"b7ëÍãG|µÊÐ>!0åÍE?ñò>*Y7å*[7ÑÍH|µÊó>*Y7#"Y7+n&åÍE?ñÃÐ>*h7|µÊ?!9åÍVH+ÑÍ[HëÍãG|µÊ?! åÍE?ñÃû>ñÃè7*Q7|µÊ3?*Q7åÍ8@ñ|µÊ>?!ÿÿÃD?*U7ÃD?É*S7å*Q7ãå!9n&ãåÍaHññ*U7#"U7Éñáåõå!9ÍVHÑÍðG|µÊ€?ñáåõÉ?ñÁáåÅõÉ?É!9n&0·íRÉñáåõ0ÉÍ­?ñá%¦?åõí{0É!\0A^#V#{²( ÅåëË^Ìì?áÁìÉË?!ÿÿ"É?ñáåõÝååÝáÍ´B(MË^ M¯ÝwÝwÝååÝá++å##íCÉ?~q#Ë~(ëÝnÝfåËo ><ï( ÍA!ÿÿ"É?͈6Á͈6á*É?ÝáÉ!Ý!("ê@îÝåͪBÝá(~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáÍ´B(RËN(NËv JT]åÝá:~0þ*(Ë^#ÄVHëÅyþ Ý~ÿæ />ïõÝ4þñëá }Ö ÝwþÝáÉëËöËî!Ë^(wÍA!ÿÿå >ï ÒÍÌ@ ô!Ë@ËÝ4þÕÝ^þÝ~ÿæ?Ëq(ö@ö€O>ïåÍAAñ"ê@áÉñáåõ&}íKB ¹0þ@Ðþ-.@Ð!ì@…oŒ•gn&ÉvA„A–A¦A·AËAâABBUnknown errorArg list too longNot a directoryInvalid argumentToo many open filesNot a character deviceMath arg oáìAut of domain of funcResult too largeI/O errorHñÑÕõ{þ@8Ö@o&þ 8l)dAÃVHöÀOýå>eïýËþýáZB>ïbk> Pí±+pëÉñáÑÝáÝåÕåõÝnÝf|µÉñÑÕõ!·È#ùÉÏBñÑÕõÝåýå!"ËBý!T0*T0ý"ÍBÝåýáÝnÝfåÝá|µ(7ÝnÝfí[ËB·íR8ÜíB0ÝnÝfýuýt ÝuÝtDMÝ ÝsÝr*ËBåÍcCÁ|¥< !#"ê@åÝáÝqÝpÝåÍøDágoýáÝáÉñÑÕõz³('!9íBíKP0íB8 íR8Åë "P0áÉ!#"ê@!ÿÿÉ*P0ɘCñÑÕõÝåýåͨCýáÝáÉ!D͆DÝ!üÿÝÍ-Eý!T0 ý"–Cýnýfåýáý^ýVz³(ÝåáíR0âÍfDÝåÁýqýpýå!T0Ñ·íR('ýnýf·íB ÍsDýuýtÝnÝfýuýtýåÝáý"–CÝNÝFÅýáx±(ÝåáÝ^ÝV·íB ÍsDÝuÝtÍfDý*–CÝåáÝ^ÝVíKP0¯íBÀýwýwÝ"P0ÉýnýfÝuÝtÉýnýfÝ^ÝVÉFREEÝåÅÕåë+F+N++Í›DáÑÁ˜DÝáÉëÝ!V0ÝnÝf|µ(åÝáíRÈ8îñ!åD>cïYP!òD>cï >ïá> ï!×D> ï!ÿÿåͤ?: BAD BLOCK X'xxxx', LEN X'xxxx' ýååÕý!V0Õýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý!V0Õýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌñÑÕõÕÕÍŽEÁÑëz³È}ö &oÉñáåõ}!ö þa8þ{Ø+Éñáåõ}!þ0Øþ:Ð#Éñáåõ}!þA˜EØþ[Ð#ÉÍÒGÍTGʹG͆GõÍYGÍžFñüŽGùGÍÒGÍTGʹGÍYGõÍžFñáÑÁüŽGéÍÒGÅÕå!9PXå~#¶#¶#¶áÊûE¯ÍEGãÜ%G¯Í7GãÃßEñññùGÍÒGÍ%GùGÍF½G+ýGÍFÚ½G+ýG!9###xî€G~Â?F+~¹Â?F+~ºÂ?F+~»!ÉÍÒG{¦_#z¦W#y¦O#x¦GùGÍÒGÍTG(###Ë+Ë+Ë+ËÍ„FèáÑÁé{/_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍTG˜F!À+ÉÝåõõÝ!Ý9;å~Ýw6#~Ýw6#~Ýw6#~Ýw6.xæ€ÂÙFËËËË,ÃÇFÝuÿÝåáÍtGåÍ GáÊíFÒôFÍGÍŽG7ãÍ7GÝ5ÿÊGã¯ÍEGÃâFñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍŽGÃ%Gå~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õüŽG͆GòrGÍtGÍŽGÍtGñî€ÉñÉå~s_#~rW#~qO#~pGáÉå###~·áÉ{· ² ± æ˜Gxþ€Èå¯o›_}šW}™O}˜GáÉÍ´Gz·ð ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#pÉ!9ÉÍöGÈ+ÉÍöGÀ+ÉÍöGÐ+ÉëÍöGØ+ÉÍöGØ+É|î€gz {½!ÉÍ HØ+Éz¼ÂH{½!ÉDM¯og>Ë#Ë0 =È)ÃHë¯íRÉ}£o|¢gÉëz³ÈË<ËöÍGH#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉý5xtrs-4.9d/utility.dsk000066400000000000000000006410001306603614600147460ustar00rootroot00000000000000                                                                                     !!!!!!!!! !"" """"""""##### #####$$$$$$$$ $$% %%%%%%%%%&&&& &&&&&&''''''' '''(((((((((( ))) )))))))****** ****+++++++++ +,, ,,,,,,,,----- -----........ ../ /////////0000 0000001111111 1112222222222 333 3333333444444 4444555555555 566 6666666677777 7777788888888 889 999999999:::: ::::::;;;;;;; ;;;<<<<<<<<<< === =======>>>>>> >>>>????????? ?@@ @@@@@@@@AAAAA AAAAABBBBBBBB BBC CCCCCCCCCDDDD DDDDDDEEEEEEE EEEFFFFFFFFFF GGG GGGGGGGHHHHHH HHHHIIIIIIIII IJJ JJJJJJJJKKKKK KKKKKLLLLLLLL LLM MMMMMMMMMNNNN NNNNNNOOOOOOO OOOÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþóû!)Cí°>!)Cí°Ã&CCannot boot, DATA DISK!ååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååþóû!)Cí°>!)Cí°Ã&CCannot boot, DATA DISK!ååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååb ååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååýüüüüüüüüüüüüüüüüÿüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿb-àBXTRSUTIL12/31/87LSIBO $ååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååram tries to determine what DOS it is running on and use ;; the correct FCB end of file convention, but this works only on ;; TRSDOS, LDOS, and NEWDOS/80. For other DOSes that use the ;; NEWDOS/80 convention (such as DOSPLUS), give the -e paramter. ;; ååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååIf the unixfile parameter is omitted, the fromfile parameter is used, ;; with '/' changed to '.'. ;; Model I/III addresses @fspec equ 441ch @init equ 4420h @open equ 4424h @close equ 4428h @read equ 4436h @write equ 4439h @error equ 4409h @exitRÍDÉÍ DÉÍ$DÉÍ(DÉÍ6DÉÍ9DÉÍ DÉÍ-@ÉÍ0@É͵SÉÍçSÉ>NïÉ>:ïÉ>;ïÉ><ïÉ>CïÉ>KïÉ>ïÉ>ïÉ>ïÉ> ïÉÍ÷SÉ: þ@( åR!,R,í°á:'DÖ‚(:DÖ2XR~þ Ú™S #õþ- ,#~ö þe —2XRþl >2üS þn™S>2ýS#~þ Ù#ÅjT"þSÍR™S~þ 8 #öšT> ¾í 8û—*þSšT~þ:(þ!8 þ/ >.#ì—!šT;; export.z ;; Timothy Mann, 8/24/97 ;; $Date: 2006/05/13 22:57:59 $ ;; ;; Copyright (c) 1997, Timothy Mann ;; ;; This software may be copied, modified, and used for any ;; purpose without fee, provided that (1) the above copyright ;; notice is retained, ajTSÍRá( þ*(OÍRà R!šT:üS·ÄÊSA¶í0(!)TâSÍ(RÕjTÍRÑ( þ(?OÍRà R Å:ýS§(!šT>  ¾ q#ùÁy°Å G:rTO !šTí3Á(!>T+y° ³í1(!TTjTÍ R(OÍRà R!ÃR!TÍ$Rà RõÍ$Rñ!šTí5Í$Rà R@å~þ( õÍñ#þ ñáÉåT]~þ[ #~ ÖAþ~0ö #· èáÉíKvT:XR§À:rT§ÈÉínd (2) modified versions are clearly ;; marked as having been modified, with the modifier's name and ;; the date included. ;; ;; Use xtrs emulator traps to copy a file from TRS-80 to Unix ;; Usage: EXPORT [-lne] fromfile [unixfile] ;; Parameter -l will cKvTÉlTUsage: EXPORT [-lne] fromfile [unixfile] Error in Unix open: Error in Unix write: Error in Unix close: YRonvert the Unix file to lower case. ;; (Needed for NEWDOS/80. They insist on uppercasing the command line.) ;; If the -n parameter is given, each carriage return ('\r') ;; in the TRS-80 file is converted to a newline ('\n') in the Unix file. ;; The progååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååen: call @open ret close: call @close ret reed: call @read ret write: call @write ret error: call @error ret exit: call @exit ret abort: call @abort ret dsply: call dsply5 ret getern: call getern5 ret endj: ; Model 4 startj6: ld a, @fspec6 rst S 1.3? gotid: ld (ernldos), a flag0: ld a, (hl) ; look for flags cp ' ' jp c, usage ; error if line ends here jr nz, flag1 inc hl jr flag0 flag1: cp '-' jr nz, fromf inc hl ld a, (hl) flag3: or 20h cp 'e' jr nz, flagl sub a ld (ernldos), a @svc ret ld a, @init6 rst @svc ret ld a, @open6 rst @svc ret ld a, @close6 rst @svc ret ld a, @read6 rst @svc ret ld a, @write6 rst @svc ret ld a, @error6 rst @svc ret ld a, @exit6 rst @svc ret ld a, @abort6 rst @svc ret ld a, @ds jr flag2 flagl: cp 'l' jr nz, flagn ; check for next flag ld a, 1 ld (lflag), a jr flag2 flagn: cp 'n' jp nz, usage ; unknown flag ld a, 1 ld (nflag), a flag2: inc hl ld a, (hl) cp ' ' jr nz, flag3 ; another flag follows inc hl jr flag0 frply6 rst @svc ret call getern6 ret ; Nonzero for LDOS ern convention ernldos: db 1 ; Emulator trap instructions, byte-reversed for use in defw: emt_open equ 30edh emt_close equ 31edh emt_read equ 32edh emt_write equ 33edh emt_lseek equ 34edh emt_streomf: ld de, dcb ; ready to get LDOS filename from (HL) ld (lfname), hl ; save if needed to default Unix name call fspec jp nz, usage unix0: ld a, (hl) ; scan over Unix filename cp ' ' ; first sk equ 402dh @abort equ 4030h @put equ 001bh dodcb$ equ 401dh ;; Model 4 SVCs @svc equ 40 ; rst address for SVCs ;@svc equ 5 ; older zmac requires 8080-style "rst 5" @fspec6 equ 78 @init6 equ 58 @open6 equ 59 @close6 equ 60 @read6 equ 67 @writerror equ 35edh EO_ACCMODE equ 3q EO_RDONLY equ 0q EO_WRONLY equ 1q EO_RDWR equ 2q EO_CREAT equ 100q EO_EXCL equ 200q EO_TRUNC equ 1000q EO_APPEND equ 2000q export: ld a, (000ah) ; Model 4? cp 40h jr z, not4 6 equ 75 @error6 equ 26 @exit6 equ 22 @abort6 equ 21 @dsply6 equ 10 ;; Model 4 only: file init or open with wrong LRL. Can be ignored. lrlerr equ 42 org 5200h ;; Jump tables for OS independence startj: fspec: call @fspec ret init: call @init ret op push hl ld de, startj ld hl, startj6 ld bc, endj - startj ldir pop hl not4: ld a, (4427h) ; system id for Newdos/80... sub 82h ; ...should be 82h (v2.0) jr z, gotid ld a, (441fh) ; system version number for most other DOSes sub 13h ; TRSDOsave fd ld de, dcb call reed ; read 256 bytes from file pop de jr z, rdok ; got a full 256 bytes cp 28 ; eof? jr z, closit ; yes, OK ld c, a call error ; oops, i/o error jp abort rdok: dec bc ;;terminate Unix name jr gotu usetrs: ld hl, (lfname) ; translate TRS-80 name to Unix ld de, iobuf ut1: ld a, (hl) cp ':' ; drivespec? jr z, utdone ; done if so cp ' '+1 ; end of line? jr c, utdone ; done if so cp '/' ; change '/' to ' Translate push bc ; save record count ld a, (nflag) ; check for NL feature and a jr z, nlfals ld hl, iobuf ld a, 0dh ld bc, 000ah ; b := 0, c := 0ah tloop: cp (hl) jr nz, notlf ld (hl), c notlf: inc hl djnz tloop nlfals: pop bc ; re.' for extension jr nz, notsl ld a, '.' notsl: ld (de), a inc hl inc de jr ut1 utdone: sub a ; NUL-terminate Unix name ld (de), a gotu: ld hl, iobuf ld de, dcb ld b, 0 call open ; open the TRS-80 file store record count ;; Write ld a, c or b ; last record? push bc ; save record count ld bc, 0100h ; byte count jr nz, notlst ld b, a ld a, (dcb+8) ld c, a dec c ; EOF offset 0: write 256 bytes inc bc notlst: ld hl, iobuf defw emt_write pop hl jr z, uname cp lrlerr jr z, uname ld c, a call error jp abort uname: ld hl, iobuf ; path ld a, (lflag) or a call nz, lcconv ; convert filename to lower case ld bc, EO_WRONLY|EO_CREAT|EO_TRUNC ld de,pop bc jr z, wrok ld hl, uwrer ; write error jr uerror wrok: ld a, c or b jr nz, loop ;; Close closit: defw emt_close ; close Unix file jr z, closok ld hl, uclser ; close error jr uerror closok: ld de, dcb 0666q ; mode defw emt_open ; open the Unix file jr z, opn2ok ; go if OK ld hl, uopner ; error message and exit jp uerror ;; Read opn2ok: call getern ; count down records in bc loop: push de ; call close ; close the TRS-80 file jr z, cls2ok ld c, a call error ; oops, i/o error jp abort cls2ok: ld hl, 0 ; all is well jp exit ;; Usage message usage: ld hl, usager ; error meip spaces jr c, usetrs ; if no Unix name, use translated TRS name jr nz, unix1 inc hl jr unix0 unix1: ld de, iobuf ; copy Unix filename ld a, ' ' unix2: cp (hl) ldi jr c, unix2 dec de sub a ld (de), a ; NUL ecord (0=256). ;; For NEWDOS/80 and TRSDOS 1.3, byte (dcb+8) and word (dcb+12) ;; form a 24 bit number containing the relative byte address of EOF. ;; Thus (dcb+12) differs by one if the file length is not a ;; multiple of 256 bytes. DOSPLUS also useååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååssage and exit call dsply jp abort ;; Unix error, msg in hl, errno in a uerror: push af call dsply pop af ld hl, iobuf ld bc, 256 defw emt_strerror call dsply jp abort ;; Display message in HL. 03h terminate, 0dh newline ans this convention, ;; and NEWDOS 2.1 probably does too (not checked). ; Returns number of (partial or full) records in BC, destroys A getern5: ld bc, (dcb+12) ld a, (ernldos) ; get ERN convention and a ret nz ; done if TRSDOSd terminate. dsply5: ld de, dodcb$ push hl dsply0: ld a, (hl) cp 03h jr z, dsply1 push af call @put pop af inc hl cp 0dh jr nz, dsply0 dsply1: pop hl ret ;; Convert (NUL terminated) string in HL to lower case. lcconv: push hl ld d, h ld e, l l 2.3/LDOS convention ld a, (dcb+8) ; length multiple of 256 bytes? and a ret z ; done if so inc bc ; no, # of records = last full record + 1 ret ; All Model 4 mode operating systems should be TRSDOS/LS-DOS 6.x compatible getern6cloop: ld a, (hl) cp 5bh ; use '[' or uparrow as escape jr nz, lconv1 inc hl ld a, (hl) jr lconv2 ; char after esc: don't convert lconv1: sub 'A' cp 26 ld a, (hl) jr nc, lconv2 or 20h ; convert to lower case lconv2: ld (de), a inc hl inc de: ld bc, (dcb+12) ret lflag: defb 0 nflag: defb 0 lfname: defw 0 usager: defb 'Usage: EXPORT [-lne] fromfile [unixfile]', 0dh uopner: defb 'Error in Unix open: ', 03h uwrer: defb 'Error in Unix write: ', 03h uclser: defb 'Error in Unix close: ', 03h d or a ; NUL terminator? jr nz, lcloop pop hl ret ;; EOF handling differs between TRS-80 DOSes: ;; For TRSDOS 2.3 and LDOS, word (dcb+12) contains the number of ;; 256 byte records in the file, byte (dcb+8) contains the EOF ;; offset in the last rcb: defs 48 ; 48 for Model III TRSDOS 1.3 iobuf: defs 256 end export r's name and ;; the date included. ;; ;; Use xtrs emulator traps to copy a file from TRS-80 to Unix ;; Usage: EXPORT [-lne] fromfile [unixfile] ;; Parameter -l will cvert the Unix file to lower case. ;; (Needed for NEWDOS/80. They insist on uppercasing the ;; command line.) ;; If the -n parameter is given, each newline ('\n') in the Unix ;; file is converted to a carriage return ('\r'), the TRS-80 end of ;; line cååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååharacter. ;; The program tries to determine what DOS it is running on and use ;; the correct FCB end of file convention, but this works only on ;; TRSDOS, LDOS, and NEWDOS/80. For other DOSes that use the ;; NEWDOS/80 convention (such as DOSPLUS), giveåååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå the -e paramter. ;; If the tofile parameter is omitted, the last component of the ;; Unix pathname is used, with '.' changed to '/'. If this is ;; not a legal TRS-80 filename, you get an error message. ;; Model I/III addresses @fspec equ 441ch @init RÍDÉÍ DÉÍ$DÉÍ(DÉÍ6DÉÍ9DÉÍ DÉÍ-@ÉÍ0@ÉÍ©SÉÍÛSÉ>NïÉ>:ïÉ>;ïÉ><ïÉ>CïÉ>KïÉ>ïÉ>ïÉ>ïÉ> ïÉÍìSÉ: þ@( åR!,R,í°á:'DÖ‚(:DÖ2XR~þ ÚS #õþ- +#~ö þe —2XRþl >2óS þn l>2ôS#~þ Ú#ÆŒT> ¾í 8û>(++~þ. 6/þ/(þ ð#\TÍR 4!ŒT:óS·Ä¾Sí0(!TÖSÕ!;; import.z ;; Timothy Mann, 8/24/97 ;; $Date: 2006/05/13 22:57:59 $ ;; ;; Copyright (c) 1997, Timothy Mann ;; ;; This software may be copied, modified, and used for any ;; purpose without fee, provided that (1) the above copyright ;; notice is retained, aŒT\STÍRÑ(þ*(OÍRà R!õSÍ$Rà R!ŒT í2(!1TjÕ:ôS§(!ŒTÅ>  ¾ r# øöÁÅ!ŒT\Ty§("_TÍR(OÍRà R$îÁÑy§ ¸ ¬í1(!FTy2dTÍ(R\TÍ R(OÍRà R!ÃRõÍ$Rñ!ŒTí5Í$Rà R@å~þ( õÍñ#þ ñáÉåT]~þ[ #~ ÖAþ~0ö #· èáÉ*fT:XR· ±(+"hTÉ*fT"hTÉUsand (2) modified versions are clearly ;; marked as having been modified, with the modifier's name and ;; the date included. ;; ;; Use xtrs emulator traps to copy a file from Unix to TRS-80 ;; Usage: IMPORT [-lne] unixfile [tofile] ;; Parameter -l will conge: IMPO^TRT [-lne] unixfile [tofile] Error in Unix open: Error in Unix read: Error in Unix close: YR) ;; If the -n parameter is given, each carriage return ('\r') ;; in the TRS-80 file is converted to a newline ('\n') in the Unix file. ;; The prog requires 8080-style "rst 5" @fspec6 equ 78 @init6 equ 58 @open6 equ 59 @close6 equ 60 @read6 equ 67 @write6 equ 75 @error6 equ 26 @exit6 equ 22 @abort6 equ 21 @dsply6 equ 10 ;; Model 4 only: file init or open with wrong LRL. Can be ignored. lrlerr equ 200q EO_TRUNC equ 1000q EO_APPEND equ 2000q iobsize equ 8192 ; must be divisible by 256 import: ld a, (000ah) ; Model 4? cp 40h jr z, not4 push hl ld de, startj ld hl, startj6 ld bc, endj - startj ldir pop hl not4: ld a, (4427h) ; sy42 org 5200h ;; Jump tables for OS independence startj: fspec: call @fspec ret init: call @init ret open: call @open ret close: call @close ret reed: call @read ret write: call @write ret error: call @error ret exit: call @exit ret abort: call @stem id for Newdos/80... sub 82h ; ...should be 82h (v2.0) jr z, gotid ld a, (441fh) ; system version number for most other DOSes sub 13h ; TRSDOS 1.3? gotid: ld (ernldos), a flag0: ld a, (hl) ; look for flags cp ' ' jp c, usage ; error if labort ret dsply: call dsply5 ret setern: call setern5 ret endj: ; Model 4 startj6: ld a, @fspec6 rst @svc ret ld a, @init6 rst @svc ret ld a, @open6 rst @svc ret ld a, @close6 rst @svc ret ld a, @read6 rst @svc ret ld a, @write6 rst @sine ends here jr nz, flag1 inc hl jr flag0 flag1: cp '-' jr nz, unix1 inc hl ld a, (hl) flag3: or 20h cp 'e' jr nz, flagl sub a ld (ernldos), a jr flag2 flagl: cp 'l' jr nz, flagn ; check for next flag ld a, 1 ld (lflag), a jr flag2 flagn: vc ret ld a, @error6 rst @svc ret ld a, @exit6 rst @svc ret ld a, @abort6 rst @svc ret ld a, @dsply6 rst @svc ret call setern6 ret ; Nonzero for LDOS ern convention ernldos: db 1 ; Emulator trap instructions, byte-reversed for use in defw:cp 'n' jr nz, usage ; unknown flag ld a, 1 ld (nflag), a flag2: inc hl ld a, (hl) cp ' ' jr nz, flag3 ; another flag follows inc hl jr flag0 unix1: ld de, iobuf ; copy Unix filename ld a, ' ' unix2: cp (hl) ldi jr c, unix2 dec de ; NUL te equ 4420h @open equ 4424h @close equ 4428h @read equ 4436h @write equ 4439h @error equ 4409h @exit equ 402dh @abort equ 4030h @put equ 001bh dodcb$ equ 401dh ;; Model 4 SVCs @svc equ 40 ; rst address for SVCs ;@svc equ 5 ; older zmac emt_open equ 30edh emt_close equ 31edh emt_read equ 32edh emt_write equ 33edh emt_lseek equ 34edh emt_strerror equ 35edh EO_ACCMODE equ 3q EO_RDONLY equ 0q EO_WRONLY equ 1q EO_RDWR equ 2q EO_CREAT equ 100q EO_EXCL equ (in case shortening file) ld de, dcb call close ; close the TRS-80 file jr z, cls2ok ld c, a call error ; oops, i/o error jp abort cls2ok: ld hl, 0 ; all is well jp exit ;; Unix rminate Unix name ld a, 0 ld (de), a jr z, trs80 ; go if two names given ;; Translate last component of Unix name to TRS-80 name dec hl ; back up to terminator unix3: dec hl ; back up to last byte of name ld a, (hl) cp '.' ; ve fd ;; Translate ld a, (nflag) ; check for NL feature and a jr z, nlfals ld hl, iobuf push bc ; save byte count ld a, 0ah ld d, 0dh inc c ; deal with b=0 and/ c=0 inc b jr tstrt tloop: cp (hl) jr nz, notcr ld (hl), d notcr: inc hchange '.' to '/' jr nz, notdot ld (hl), '/' notdot: cp '/' jr z, unix4 cp ' ' jr nz, unix3 unix4: inc hl ; point to start of modified last component trs80: ld de, dcb ; ready to get TRS-80 filename from (HL) call fspec l tstrt: dec c jr nz, tloop djnz tloop pop bc ; restore byte count ;; Write nlfals: push bc ; save byte count ld hl, iobuf ld de, dcb inc b ; deal with b=0 and/or c=0 ld a, c and a jr z, wstrt wloop: ld (dcb+3), hl call write jr nz, usage ld hl, iobuf ; Unix path ld a, (lflag) or a call nz, lcconv ; convert path to lower case ld bc, EO_RDONLY ld de, 0 ; mode (ignored) defw emt_open jr z, openok ; go if OK ld hl, uopner ; error message and exit jp uerror openok ; write 256 bytes to file jr z, wrok ld c, a call error ; oops, i/o error jp abort wrok: inc h wstrt: djnz wloop pop bc ; restore byte count ;; Done? pop de ; restore fd ld a, c and a jr nz, closit ; done : push de ; save fd ld hl, iobuf ld de, dcb ld b, 0 call init ; open the file pop de jr z, opn2ok cp lrlerr jr z, opn2ok ld c, a call error jp abort usage: ld hl, usager ; errofor sure cp b jr nz, rloop ; maybe not done (sloppy) closit: defw emt_close ; close Unix file jr z, closok ld hl, uclser ; close error (!!code in A) jr uerror closok: ld a, c ld (dcb+8), a ; set EOF offset call setern ; set ERNr message and exit call dsply jp abort ;; Read rloop: opn2ok: ld hl, iobuf ; read a buffer ld bc, iobsize defw emt_read jr z, readok ld hl, urder ; read error (!!code in A) jr uerror readok: push de ; saOF handling differs between TRS-80 DOSes: ;; For TRSDOS 2.3 and LDOS, word (dcb+12) contains the number of ;; 256 byte records in the file, byte (dcb+8) contains the EOF ;; offset in the last record (0=256). ;; For NEWDOS/80 and TRSDOS 1.3, byte (dcb+8Model III TRSDOS 1.3 iobuf: defs iobsize end import with the modifier's name and ;; the date included. ;; ;; Use xtrs emulator traps to copy a file from Unix to TRS-80 ;; Usage: IMPORT [-lne] unixfile [tofile] ;; Parameter -l will con) and word (dcb+12) ;; form a 24 bit number containing the relative byte address of EOF. ;; Thus (dcb+12) differs by one if the file length is not a ;; multiple of 256 bytes. DOSPLUS also uses this convention, ;; and NEWDOS 2.1 probably does too (notååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååerror, msg in hl, errno in a uerror: push af call dsply pop af ld hl, iobuf ld bc, 256 defw emt_strerror call dsply jp abort ;; Display message in HL. 03h terminate, 0dh newline and terminate. dsply5: ld de, dodcb$ push hl dsply0: ld a, (h checked). ; Set ending record number of file to current position ; EOF offset in C; destroys A, HL setern5: ld hl, (dcb+10) ; current record number ld a, (ernldos) ; get ERN convention or a jr nz, noadj ; go if TRSDOS 2.3/LDOS conl) cp 03h jr z, dsply1 push af call @put pop af inc hl cp 0dh jr nz, dsply0 dsply1: pop hl ret ;; Convert (NUL terminated) string in HL to lower case. lcconv: push hl ld d, h ld e, l lcloop: ld a, (hl) cp 5bh ; use '[' or uparrow as escape vention adj: or c ; length multiple of 256 bytes? jr z, noadj ; go if so dec hl ; no, # of records - 1 noadj: ld (dcb+12), hl ret ; All Model 4 mode operating systems should be TRSDOS/LS-DOS 6.x compatible setern6: ld hl, (dcb+10) ldjr nz, lconv1 inc hl ld a, (hl) jr lconv2 ; char after esc: don't convert lconv1: sub 'A' cp 26 ld a, (hl) jr nc, lconv2 or 20h ; convert to lower case lconv2: ld (de), a inc hl inc de or a ; NUL terminator? jr nz, lcloop pop hl ret ;; E (dcb+12), hl ret lflag: defb 0 nflag: defb 0 usager: defb 'Usage: IMPORT [-lne] unixfile [tofile]', 0dh uopner: defb 'Error in Unix open: ', 03h urder: defb 'Error in Unix read: ', 03h uclser: defb 'Error in Unix close: ', 03h dcb: defs 48 ; 48 for jr c, year2 ld c, a inc b ; centuries ld a, b year2: and 3 sub 1 sbc hl, de jr nc, year1 rlca adc hl, de ; HL: days since 1 january push hl ld hl, (date) call putyr ; year to (hl) inc hl ex (sp), hl and 1 ; A=1 for leap year, 0 else a:27:13 CET 1998 by ulm ;; Model I/III addresses @exit equ 402dh @abort equ 4030h ;; Model 1 and 3 store the last 2 digits of the year in the year byte time1$ equ 4041h ; seconds/minutes/hours date1$ equ 4044h ; year/day/month time3$ equ 4217h date3$ eqdd a, 28 ld c, a ld b, 0 ld d, b month1: inc b ; count months in B ld a, b ld e, c cp 2 jr z, month2 ; february ld e, 31 and 9 jp po, month2 ; 31 days dec e ; 30 days month2: sbc hl, de ; subtract length of month jr nc, month1 adc hl, du 421ah ;; Model 4 SVCs @svc equ 40 ; rst address for SVCs ;@svc equ 5 ; older zmac requires 8080-style "rst 5" @exit6 equ 22 @abort6 equ 21 ;; Model 4 stores the offset from 1900 in the year byte time4$ equ 002dh date4$ equ 0033h ;; Emulator trap ine ld c, l pop hl ld (hl), c ; day inc hl ld (hl), b ; month ei ld hl,0 ; needed on Model 4 --mann jr exit ;; divide BCDE / A ;; returns quotient in BCDE, remainder in A divide: push hl neg ld h, a sub a ld l, 33 div1: rla add a, h jr c, structions emt_time equ 36edh org 5200h settime: call initj ; init OS-dependent tables ld bc, 0ffffh ld a, 1 ; get local time from Unix defw emt_time ; BCDE: seconds since 1970 ld a, b and c inc a jp z, abort di ld hl, (time) ld a, 60 caldiv2 sub h div2: rl e rl d rl c rl b dec l jr nz, div1 pop hl ret ;; Jump tables for OS independence ;; Model 1 startj: exit: jp @exit abort: jp @abort time: defw time1$ date: defw date1$ putyr: jp putyr1 endj: ;; Model 3 startj3: jp @exit jp @;; settime.z ;; ;; Read date and time from xtrs 1.9 emulator trap and set ;; TRS-80 system date and time. ;; ;; Copyright (c) 1998 Ulrich Mueller ;; ;; This software may be copied, modified, and used for any ;; purpose without fee, provided that (1) the abl divide ld (hl), a ; seconds inc hl ld a, 60 call divide ld (hl), a ; minutes inc hl ld a, 24 call divide ld (hl), a ; hours ex de, hl ; HL: days since 1970 ld bc, 19*256+70-1 ld de, 365 year1: inc c ; count years in C ld a, c sub 100 ove copyright ;; notice is retained, and (2) modified versions are clearly ;; marked as having been modified, with the modifier's name and ;; the date included. ;; ;; Last modified on Fri May 19 00:38:41 PDT 2000 by mann ;; modified on Sun Feb 22 21abort defw time3$ defw date3$ jp putyr3 ;; Model 4 startj4: ld a, @exit6 rst @svc ld a, @abort6 rst @svc defw time4$ defw date4$ jp putyr4 ;; Initialize tables ;; Changed to work even on a Model III (or Model 4 in III mode) ;; using MODELA/IIIåRÍ´Rÿÿ>í6x¡<ÊRó*“R><ÍtRw#><ÍtRw#>ÍtRwëEm yÖd8OxæÖíR0ïíZå*•RÍ—R#ãæÆOPxYþ(æ âcRíR0ííZMáq#pû!åíDg—.!„8”ËËËË- ðáÉÃ-@Ã0@A@D@ÃÐRÃ-@Ã0@BBÃÐR>ï>ï-3ÃÒR!§R: þ@ !šR:%þIÀR í°ÉqÉõÅxÖGy(ÆdüwÁñÉRvided that (1) the ab as its ROM. Previous version didn't. --mann ;; initj: ld hl, startj4 ; model 4? ld a, (000ah) cp 40h jr nz, movej ; go if so ld hl, startj3 ; model 3? ld a, (0125h) cp 'I' ret nz ; return if not movej: ld de, startj ld bc, endj - startj ldååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååir ret ;; Create year byte. ;; On entry, c has 2-digit year, b has century. ;; On exit, (hl) has year byte. ;; Model I/III, put 2-digit year putyr1: putyr3: ld (hl), c ret ;; Model 4, put offset from 1900 (laboriously recomputed, sigh) putyr4: push afåååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå push bc ld a, b sub 19 ld b, a ld a, c jr z, py41 py40: add a, 100 djnz py40 py41: ld (hl), a pop bc pop af ret end settime d (ernldos), a jr flag2 flagl: cp 'l' jr nz, flagn ; check for next flag ld a, 1 ld (lflag), a jr flag2 flagn: ååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååe to errno LD C,A LD (ERRNO),BC LD HL,0FFFFH ;return -1 #endasm } int emt_read(fd, buffer, bytes) int fd; char *buffer; int bytes; { #asm POP AF ;save return address POP DE ;fd to DE POP HL ;buffer to HL POP Bgetddir RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC LD HL,0 #endasm } int emt_stddir(fname) char *fname; { #asm POP AF ;save return address POP HL ;fname to HL PUSH HL PUSH AF DEFW 2BEDH ;emt_setC ;bytes to BC PUSH BC PUSH HL PUSH DE PUSH AF DEFW 32EDH ;emt_read LD H,B ;return count from BC LD L,C RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC #endasm } int emt_write(fd, buffer, bytes) /* xtrsemt.ccc -- Misosys C interface to xtrs emulator traps */ /* Copyright (c) 1997, Timothy Mann */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) ddir LD HL,0 ;return 0 if OK RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC LD HL,0FFFFH ;return -1 #endasm } int emt_open(fname, oflag, mode) char *fname; int oflag; int mode; { #asm POP AF ;save retmodified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* Last modified on Tue Dec 15 14:40:25 PST 1998 by mann */ #include #ifndef _TIME_T #include #endif int emt_system(curn address POP HL ;fname to HL POP BC ;oflag to BC POP DE ;mode to DE PUSH DE ;restore stack PUSH BC PUSH HL PUSH AF DEFW 30EDH ;emt_open LD H,D ;return fd from DE LD L,E RET Z LD B,0 ;error code to emd) char *cmd; { #asm POP AF ;save return address POP HL ;cmd to HL PUSH HL ;restore stack PUSH AF DEFW 28EDH ;emt_system LD H,B ;return exit status from BC LD L,C RET Z LD B,0 ;error code to errno rrno LD C,A LD (ERRNO),BC #endasm } int emt_close(fd) int fd; { #asm POP AF ;save return address POP DE ;fd to DE PUSH DE PUSH AF DEFW 31EDH ;emt_close LD HL,0 ;return 0 if no error RET Z LD B,0 ;error cod LD C,A LD (ERRNO),BC #endasm } char * emt_gtddir(buffer, bytes) char *buffer; int bytes; { #asm POP AF ;save return address POP HL ;buffer to HL POP BC ;bytes to BC PUSH BC PUSH HL PUSH AF DEFW 2AEDH ;emt_ame, skipping ADD IX,SP ; return address and old IX value LD E,(IX+0) ;fd to DE LD D,(IX+1) LD HL,0 ;extend offset to 8 bytes, push on stack PUSH HL PUSH HL LD L,(IX+4) ;high 2 bytes of 4-byte offset LD H,(IX+5 ;return value is in BCDE (time_t == long) #endasm } int emt_dropen(fname) char *fname; { #asm POP AF ;save return address POP HL ;fname to HL PUSH HL PUSH AF DEFW 37EDH ;emt_opendir LD H,D ) PUSH HL LD L,(IX+2) ;low 2 bytes LD H,(IX+3) PUSH HL LD HL,0 ;point HL to 8-byte offset ADD HL,SP LD C,(IX+6) ;whence to BC LD B,(IX+7) DEFW 34EDH ;emt_lseek POP DE ;return tell value in BCDE POP BC PO ;return dirfd LD L,E RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC #endasm } int emt_drclose(dirfd) int dirfd; { #asm POP AF ;save return address POP DE ;dirfd to DE PUSH DE PUSH AF DEFW 38EDH ;P HL ;ignore high-order 4 bytes POP HL POP IX RET Z LD H,0 ;error code to errno LD L,A LD (ERRNO),HL #endasm } int emt_strerror(err, buffer, size) int err; char *buffer; int size; { #asm POP AF ;save return ademt_closedir LD HL,0 ;return 0 if no error RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC LD HL,0FFFFH ;return -1 #endasm } int emt_drread(dirfd, buffer, bytes) int dirfd; char *buffer; int bytes; { #asm int fd; char *buffer; int bytes; { #asm POP AF ;save return address POP DE ;fd to DE POP HL ;buffer to HL POP BC ;bytes to BC PUSH BC PUSH HL PUSH DE PUSH AF DEFW 33EDH ;emt_write LD H,B ;return countdress POP DE ;err to DE temporarily POP HL ;buffer to HL POP BC ;size to BC PUSH BC PUSH HL PUSH DE PUSH AF LD A,E ;move err to A DEFW 35EDH ;emt_strerror LD H,B LD L,C RET Z LD B,0 ;new error code from BC LD L,C RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC #endasm } long emt_lseek(fd, offset, whence) int fd; long offset; /* 4 bytes */ int whence; { #asm PUSH IX LD IX,4 ;point IX to argument frto errno LD C,A LD (ERRNO),BC #endasm } time_t emt_time(local) int local; { #asm POP AF ;save return address POP HL ;local flag to HL temporarily PUSH HL PUSH AF LD A,L ;local flag to A DEFW 36EDH ;emt_time ; return address and old IX value LD L,(IX+4) ;bc arg to HL LD H,(IX+5) LD C,(HL) ;*bc to BC INC HL LD B,(HL) LD L,(IX+6) ;de arg to HL LD H,(IX+7) LD E,(HL) ;*de to DE INC LD (ERRNO),BC #endasm } int emt_chdir(fname) char *fname; { #asm POP AF ;save return address POP HL ;fname to HL PUSH HL PUSH AF DEFW 3AEDH ;emt_chdir LD HL,0 ;return 0 if OK RET Z LD B,0 ;error code to errno HL LD D,(HL) LD L,(IX+2) ;hl arg to HL LD H,(IX+3) LD A,(HL) ;*hl to HL INC HL LD H,(HL) LD L,A LD A,(IX+0) ;func to A DEFW 3CEDH ;emt_misc PUSH HL ;save HL return LD L,(IX LD C,A LD (ERRNO),BC LD HL,0FFFFH ;return -1 #endasm } char * emt_getcwd(buffer, bytes) char *buffer; int bytes; { #asm POP AF ;save return address POP HL ;buffer to HL POP BC ;bytes to BC PUSH BC PUSH HL +4) ;bc arg to HL LD H,(IX+5) LD (HL),C ;BC return to *bc INC HL LD (HL),B LD L,(IX+6) ;de arg to HL LD H,(IX+7) LD (HL),E ;DE return to *de INC HL LD (HL),D POP DE ;H PUSH AF DEFW 3BEDH ;emt_getcwd RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC LD HL,0 ;return NULL #endasm } int emt_misc(func) int func; { #asm POP AF ;save return address POP HL ;func to HL PUSH HL L return to DE LD L,(IX+2) ;hl arg to HL LD H,(IX+3) LD (HL),E ;DE (HL return) to *hl INC HL LD (HL),D EX DE,HL ;HL return back to HL (not needed) POP IX #endasm } int emt_ftruncate(fd, length) int fd; PUSH AF LD A,L ;func to A DEFW 3CEDH ;emt_misc, return HL #endasm } void emt_4misc(func, hl, bc, de) int func; int *hl; int *bc; int *de; { #asm PUSH IX LD IX,4 ;point IX to argument frame, skipping ADD IX,SP long length; /* 4 bytes */ { #asm PUSH IX LD IX,4 ;point IX to argument frame, skipping ADD IX,SP ; return address and old IX value LD E,(IX+0) ;fd to DE LD D,(IX+1) LD HL,0 ;extend length to 8 bytes, push on stack POP AF ;save return address POP DE ;fd to DE POP HL ;buffer to HL POP BC ;bytes to BC PUSH BC PUSH HL PUSH DE PUSH AF DEFW 39EDH ;emt_readdir LD H,B LD L,C RET Z LD B,0 ;error code to errno LD C,AT Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC LD HL,0FFFFH ;return -1 #endasm } ;restore stack PUSH AF DEFW 28EDH ;emt_system LD H,B ;return exit status from BC LD L,C RET Z LD B,0 ;error code to errno ror(/* int err, char *buffer, int size */); extern time_t emt_time(/* int local */); extern int /*emt_opendir*/ emt_dropen(/* char *fname */); extern int /*emt_closedir*/ emt_drclose(/* int dirfd */); extern int /*emt_readdir*/ emt_drread(/*int dirfd, char PUSH HL PUSH HL LD L,(IX+4) ;high 2 bytes of 4-byte offset LD H,(IX+5) PUSH HL LD L,(IX+2) ;low 2 bytes LD H,(IX+3) PUSH HL LD HL,0 ;point HL to 8-byte offset ADD HL,SP DEFW 3DEDH ;emt_ftruncate POP DE /* xtrsemt.h -- Misosys C interface to xtrs emulator traps */ /* Copyright (c) 1997, Timothy Mann */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) mo;pop length from stack POP BC POP HL POP HL POP IX ;restore RET Z LD H,0 ;error code to errno LD L,A LD (ERRNO),HL #endasm } int emt_dkopen(fname, oflag, mode) char *fname; int oflag; int mode; { #asm Pdified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* Last modified on Tue Dec 15 14:41:02 PST 1998 by mann */ #ifndef _TIME_T #include #endif /* Some names are changed to keep theOP AF ;save return address POP HL ;fname to HL POP BC ;oflag to BC POP DE ;mode to DE PUSH DE ;restore stack PUSH BC PUSH HL PUSH AF DEFW 3EEDH ;emt_opendisk LD H,D ;return fd from DE LD L,E RET Z LD Bm unique in the first seven characters */ extern int emt_system(/* char *cmd */); extern char* /*emt_getddir*/ emt_gtddir(/* char *buffer, int bytes */); extern int /*emt_setddir*/ emt_stddir(/* char *fname */); extern int emt_open(/* char *fname, int ofla,0 ;error code to errno LD C,A LD (ERRNO),BC #endasm } int emt_dkclose(fd) int fd; { #asm POP AF ;save return address POP DE ;fd to DE PUSH DE PUSH AF DEFW 3FEDH ;emt_closedisk LD HL,0 ;return 0 if no error REg, int mode */); extern int emt_close(/* int fd */); extern int emt_read(/* int fd, char *buffer, int bytes */); extern int emt_write(/* int fd, char *buffer, int bytes */); extern long emt_lseek(/* int fd, long offset, int whence */); extern int emt_streråååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå#define EMT_MISC_DISK_CHANGE 0 #define EMT_MISC_EXIT 1 #define EMT_MISC_DEBUG 2 #define EMT_MISC_RESET_BUTTON 3 #define EMT_MISC_QUERY_DISK_CHANGE 4 #define EMT_MISC_QUERY_MODEL 5 #define EMT_MISC_QUERY_DISK_SIZE åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå 6 #define EMT_MISC_SET_DISK_SIZE 7 #define EMT_MISC_QUERY_DBL_STEP 8 #define EMT_MISC_SET_DBL_STEP 9 #define EMT_MISC_QUERY_MICROLABS 10 #define EMT_MISC_SET_MICROLABS 11 #define EMT_MISC_QUERY_DELAY 12 #define EMT_MISC_SET_DELAY åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå *buffer, int bytes*/); extern int emt_chdir(/* char *fname */); extern char* emt_getcwd(/* char *buffer, int bytes */); extern int emt_misc(/* int func */); extern void emt_4misc(/* int func, int *hl, int *bc, int *de */); extern int emt_ftruncate(/* int 13 #define EMT_MISC_QUERY_KEYSTRETCH 14 #define EMT_MISC_SET_KEYSTRETCH 15 #define EMT_MISC_QUERY_DOUBLER 16 #define EMT_MISC_SET_DOUBLER 17 #define EMT_MISC_QUERY_VOLUME 18 #define EMT_MISC_SET_VOLUME 19 #define EMT_MISC_QUERY_TRUEDfd, long length */); extern int /*emt_opendisk*/ emt_dkopen(/* char *fname, int oflag, int mode */); extern int /*emt_closedisk*/ emt_dkclose(/* int fd */); /* oflag values for emt_open and emt_opendisk */ #define EO_ACCMODE 03 #define EO_RDONLY 00 #AM 20 #define EMT_MISC_SET_TRUEDAM 21 or code to errno LD C,A LD (ERRNO),BC #endasm } long emt_lseek(fd, offset, whence) int fd; long offset; /* 4 bytes */ int whence; { #asm PUSH IX LD IX,4 ;point IX to argument frdefine EO_WRONLY 01 #define EO_RDWR 02 #define EO_CREAT 0100 #define EO_EXCL 0200 #define EO_TRUNC 01000 #define EO_APPEND 02000 /* local values for emt_time */ #define EMT_TIME_GMT 0 #define EMT_TIME_LOCAL 1 /* func values for emt_misc */ ned, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* Last modified on Sat Sep 20 13:41:00 PDT 1997 by mann */ #option redirect 0 #include "xtrsemt.h" #include "xtrsemt.ccc" d to format an emulated hard . drive with XTRSHARD/DCT on an emulated Model I. . . Apply with PATCH FORMAT/CMD.RS0LT0FF USING M1FORMAT . Do not apply to Model III LDOS or Model 4 LS-DOS! . X'630B'=00 00 ct 0 #include "xtrsemt.h" #include "xtrsemt.ccc" /* could use separate compilation instead */ main() { time_t now; struct tm *nowtm; char cmd[81]; now = emt_time(EMT_TIME_LOCAL); nowtm = localtime(&now); sprintf(cmd, "date %02d/%02d/%02d", nowtm->tm_mon + 1, nowtm->tm_mday,åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå nowtm->tm_year % 100); system(cmd); sprintf(cmd, "time %02d:%02d:%02d", nowtm->tm_hour, nowtm->tm_min, nowtm->tm_sec); system(cmd); system("time"); } extern long emt_lseek(/* int fd, long offset, int whence */); extern int emt_streråååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå/* settime.ccc -- Misosys C program to set time using xtrs emulator traps */ /* Copyright (c) 1997, Timothy Mann */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retai. M1FORMAT/FIX - 01/24/98 - Tim Mann . Patch to Model I LDOS 5.3.1 FORMAT to allow formatting a hard . drive. NOPs out some buggy code that makes it fail. Odd . that this bug is still present; README/TXT suggests it was . fixed. This patch is requireLÿ.XTRSEMT H –B–B "ÿÿÿÿÿÿÿÿLÿNXTRSMOUSZ80–B–Bÿÿÿÿÿÿÿÿ ÿ¢UNIX CMD–B–B+ÿÿÿÿÿÿÿÿ ÿ?UMOUNT6 CMD–B–B@ÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüüüüüüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿb-àBXTRSUTIL12/31/87LSIBO $LÿHIMPORT Z80–B–B"&ÿÿÿÿÿÿÿÿLÿ„XTRSHARDZ80–B–BD ÿÿÿÿÿÿÿÿLÿ[MOUNT CCC–B–B $ÿÿÿÿÿÿÿÿ ÿÆCD6 CMD–B–B5$ÿÿÿÿÿÿÿÿ¢Ä9Ì ø|‰ŒŸ¿Ý™Lñ$)ÜäøÖñÒÎà0ÇzþØëµ(ŠLÿ‹SETTIME Z80–B–B ÿÿÿÿÿÿÿÿLÿŽXTRS8 DCT–B–BÿÿÿÿÿÿÿÿLÿXUMOUNT CCC–B–B%ÿÿÿÿÿÿÿÿ ÿ PWD6 CMD–B–B8ÿÿÿÿÿÿÿÿ^BOOT SYSö7õœÿÿÿÿÿÿÿÿ ÿzEXPORT CMD–B–BÿÿÿÿÿÿÿÿLÿ­SETTIME CCC–B–BÿÿÿÿÿÿÿÿLÿìCD CCC–B–B!!ÿÿÿÿÿÿÿÿ ÿŽMOUNT CMD–B–B-%ÿÿÿÿÿÿÿÿ ÿâTRUEDAM6CMD–B–BB$ÿÿÿÿÿÿÿÿ ÿëSETTIME CMD–B–B ÿÿÿÿÿÿÿÿLÿ×XTRS8 Z80–B–B&'ÿÿÿÿÿÿÿÿ ÿÝCD CMD–B–B&ÿÿÿÿÿÿÿÿ ÿ‡UNIX6 CMD–B–B:$ÿÿÿÿÿÿÿÿ]DIR SYSö7–B ÿÿLÿXEXPORT Z80–B–B"&ÿÿÿÿÿÿÿÿLÿÎM1FORMATFIX–B–B ÿÿÿÿÿÿÿÿLÿPWD CCC–B–B" ÿÿÿÿÿÿÿÿ ÿRUMOUNT CMD–B–B0$ÿÿÿÿÿÿÿÿLÿøEXPALL BAS–B–BEÿÿÿÿÿÿÿÿLÿiXTRSEMT CCC–B–B# ÿÿÿÿÿÿÿÿ ÿ±XTRSMOUSCMD–B–B ÿÿÿÿÿÿÿÿ ÿ·PWD CMD–B–B($ÿÿÿÿÿÿÿÿ ÿwMOUNT6 CMD–B–B=ÿÿÿÿÿÿÿÿ ÿlIMPORT CMD–B–BÿÿÿÿÿÿÿÿLÿ‘XTRSHARDDCT–B–BÿÿÿÿÿÿÿÿLÿ¸UNIX CCC–B–B#ÿÿÿÿÿÿÿÿ ÿùTRUEDAM CMD–B–B3ÿÿÿÿÿÿÿÿLÿˆDO6 JCL–B–BE ÿÿÿÿÿÿÿÿis not availwcable! Must install via SYSTEM (DRIVE=,DRIVER=)! DRIVE= must be specified! Enter unit number ([0]-7): Aborted! wd'Vfxtrshard˜dÝåÍ™eÍ«dÝáÉ> Àx§Èþ(0—É—ÉËP Xþ (G0Nþ (> §Éý~º0>ÉÕåÍoeá> í2>ÑÀx± ÕåÅ6åT]ÿí°ååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååÁáÑ—Ézý– ÆÉ—Éý~º0ï>É> §ÉýË~(>Éþ()0Eþ (ý6 ÿÕåÝ^ÝV!"™d!˜dí=áÑ>À—Éz³Ìfý~º0> ÉÕåÍoeá> í3> ÑÀ—É> §É—gý†o $JCy>[ïTXeo#ë!šdr+s+qÝ^ÝVí4í˜eÉÝ!ˆdÕý~æ_ÝÑÝ~ݦ<(—ÉÕÅå¶!Ofý~æÆ02Ufí>ÝsÝr Í2Bb!{D"Cb2{e!K"|e2úe!{K"ûe>12Sf!bÍgD:XGË_Ê7bí[scz³Ê3b!JcÍgD!ucÍ@Ú?bÂ?b:ucþ08äþ80à*I@ÍpbÊïa*I@"qcà—íR"I@ÍAfÍIb:C2>f*C"?f!6f"C>Ã2CÃáa>Í2Bb!ŠB"Cb2{e!ND"|e2úe!zK"ûe>32Sf!bÍgD:XGË_Ê7bí[scz³Ê3b!JcÍgD!ucÍ@Ú?bÂ?b:ucþ08äþ8#NXy>]ï= Ë Ë Ë ±ýwýwý6 ÿ—áÁÑÉåÅÕ!˜dBKÝ^ÝV6íC™dí4ý~ wí3ÑÁáÉÿÿí?ÍAfTim!ˆdT]6ÿí°Éhard1-0ydÙd›e£dYe¿e¦d:e=eÉeÕaf*B"?f!6f"B>Ã2BÃáa>42Sf!b> ï>eïý~Ë_Ê7bí[scz³Ê3b!Jc> ï!uc> ïÚ?bÂ?b:ucþ08äþ80à|d>SïÊïaKI>RïÂ/b+V+^å!àT]—íBá0 s#ríSqc!E>dïÂ;b"qcà—íR>dïÍAfÍIb>eïý~ýnýf2>f"?f!6fýuýtý6Ãí[qc!Vfàí¸ë#ý*scý6Ãýååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååuýtý6b :ucæöýwý6ý6Éý6ÿý6ÿý6 ÿÍ™e!È!wcí5Ý!ÕbÝ!0cÝ!cÝ!èbÝ!fc> ï!ÿÿÉ*qcý!WfVf—íRDMýnýf|µÈ^#Vë ër+sý#ý#è#|µ =É~þÀå####~þ G|d#¾ #øáÉá##^#VëÓXTRSHARD - Emulated hard disk driver for xtrs - 5/17/00 LS-DOS is curdled! High memory ååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååand 6 ;*=*=* org 6000h ;*=*=* ; Relocator for disk driver ;*=*=* instal: ld (dct),de ;Save DCT address ld a,(000ah) ;Determine TRS-80 model cp 40h jp nz,lsdos6 ;Model 4 (or other LS-DOS, I hope) ld a,(m3flag$) cp 'I' jp z,model3 ;Go if Model III ;II chars LF equ 10 CR equ 13 ETX equ 3 ; Model 4 SVC numbers @high equ 100 @dsply equ 10 @flags equ 101 @logot equ 12 @gtdcb equ 82 @gtmod equ 83 @div8 equ 93 @mul16 equ 91 @keyin equ 9 ; Model I/III hard addresses m3flag$*=*=* ; LDOS 5 Model I - See LS-DOS 6 version for comments ;*=*=* ld a,0cdh ;Insert Model I @LOGOT ld (logot),a ld hl,@logot1 ld (logot+1),hl ld (domul),a ;Insert Model I MULT ld hl,@mult1 ld (domul+1),hl ld (dodiv),a ;Insert Model I DIVEA ld hl equ 0125h ; 'I' in ROM on Model III @logot1 equ 447bh @logot3 equ 428ah @dsply1 equ 4467h @dsply3 equ 4467h high$1 equ 4049h high$3 equ 4411h cflag$1 equ 4758h cflag$3 equ 4758h @icnfg1 equ 4303h @icnfg3 equ 421dh @mult1 equ 4b8fh @m,@divea1 ld (dodiv+1),hl ld a,'1' ;Modify filename ld (hmod),a ld hl,hello_ call @dsply1 ld a,(cflag$1) bit 3,a ;System request? jp z,viaset ld de,(dct) ld a,d ;DRIVE= must be specified or e jp z,needdr asku1: ld hl,unit_ ;Ask ult3 equ 444eh @divea1 equ 4b7bh @divea3 equ 4b7ah @keyin1 equ 0040h @keyin3 equ 0040h ; Emulator trap instructions in byte-reversed form emt_read equ 32EDH emt_write equ 33EDH emt_lseek equ 34EDH emt_strerror equ 35EDH emt_ftruncate equ 3DEDH emt_opendiswhich unit number call @dsply1 ld hl,unit ld bc,100h call @keyin1 jp c,hitbrk jp nz,hitbrk ld a,(unit) cp '0' jr c,asku1 cp '0'+ndrive jr nc,asku1 ld hl,(high$1) call xgtmod ;Module already loaded? jp z,setdct ld hl,(high$1) ld (;*=*=* ; xtrshard/dct ; Emulate hard disk in a Unix file under xtrs ; ; Copyright (c) 1998, Timothy Mann ; ; This software may be copied, modified, and used for any ; purpose without fee, provided that (1) the above copyright ; notice is retained, and (2) k equ 3EEDH emt_closedisk equ 3FEDH ; Constants for emt_opendisk EO_RDONLY equ 00o EO_WRONLY equ 01o EO_RDWR equ 02o EO_CREAT equ 0100o EO_EXCL equ 0200o EO_TRUNC equ 01000o EO_APPEND equ 02000o ;*=*=* ; Set origin to be safe on both LDOS 5 modified versions are clearly ; marked as having been modified, with the modifier's name and ; the date included. ; ; Created 1-10-98 ; Last modified on Wed May 17 00:08:52 PDT 2000 by mann ;*=*=* ; Number of drives to allow ndrive equ 8 ; ASCnewend),hl ld de,length sub a sbc hl,de ld (high$1),hl call dvrini call relo ld a,(@icnfg1) ld (link),a ld hl,(@icnfg1+1) ld (link+1),hl ld hl,dvrcfg rx16 equ $-2 ld (@icnfg1+1),hl ld a,0c3h ld (@icnfg1),a jp movOS 6 ;*=*=* lsdos6: ld a,'4' ;Modify filename ld (hmod),a ld hl,hello_ ld a,@dsply ;Display hello rst 40 ;*=*=* ; Check if entry from SYSTEM command. ;*=*=* ld a,@flags ;Get flags pointer into IY rst 40 lde ;*=*=* ; LDOS 5 Model III ;*=*=* model3: ld a,0cdh ;Insert Model III @LOGOT ld (logot),a ld hl,@logot3 ld (logot+1),hl ld (domul),a ;Insert Model III MULT ld hl,@mult3 ld (domul+1),hl ld (dodiv),a ;Insert Model III DIVEA ld hl,@divea3 ld (dod a,(iy+'C'-'A') ;Get CFLAG$ bit 3,a ;System request? jp z,viaset ld de,(dct) ld a,d ;DRIVE= must be specified or e jp z,needdr ;*=*=* ; Ask which unit number ;*=*=* asku4: ld hl,unit_ ;Ask which unit number ld a,@dsply rst 40 ld hiv+1),hl ld a,'3' ;Modify filename ld (hmod),a ld hl,hello_ call @dsply3 ld a,(cflag$3) bit 3,a ;System request? jp z,viaset ld de,(dct) ld a,d ;DRIVE= must be specified or e jp z,needdr asku3: ld hl,unit_ ;Ask which unit numberl,unit ld bc,100h ld a,@keyin rst 40 jp c,hitbrk jp nz,hitbrk ld a,(unit) cp '0' jr c,asku4 cp '0'+ndrive jr nc,asku4 ;*=*=* ; Check if driver already loaded ;*=*=* ld de,modnam ld a,@gtmod rst 40 jp z,setdct ;Already loaded, skip loadi call @dsply3 ld hl,unit ld bc,100h call @keyin3 jp c,hitbrk jp nz,hitbrk ld a,(unit) cp '0' jr c,asku3 cp '0'+ndrive jr nc,asku3 ld hl,(high$3) call xgtmod ;Module already loaded? jp z,setdct ld hl,(high$3) ld (newend),hl ld deng ;*=*=* ; Obtain low memory driver pointer. Bizarre API here! ;*=*=* ld e,'K' ;Locate pointer to *KI DCB ld d,'I' ; via @GTDCB SVC ld a,@gtdcb rst 40 jp nz,curdl ;No er,length sub a sbc hl,de ld (high$3),hl call dvrini call relo ld a,(@icnfg3) ld (link),a ld hl,(@icnfg3+1) ld (link+1),hl ld hl,dvrcfg rx17 equ $-2 ld (@icnfg3+1),hl ld a,0c3h ld (@icnfg3),a jp move ;*=*=* ; LS-Dror unless KI clobbered! dec hl ;Decrement to driver pointer ld d,(hl) ;P/u hi-order of pointer, dec hl ; decrement to and p/u ld e,(hl) ; lo-order of pointer ;iy+2),h ld (iy+3),00001100b ;Flags: rigid, fixed, step rate 0 ld a,(unit) and 0fh or 00010000b ;Flags: alien (=no index pulses), unit# ld (iy+4),a ld (iy+5),0 ;LDOS undefined; we use as sec/cyl (0=256). ld (iy+6),201 ;high cylinder numbe of driver. ;*=*=* dorelo: call dvrini ;Final driver init before move call relo ;*=*=* ; Link to @ICNFG (must follow address relocation and precede movement) ;*=*=* ld a,@flags ;Get flags pointer into IY rst 40 ld a,(iy+28er ld (iy+7),11111111b ;high head # (111), high sec/trak (11111) ld (iy+8),11111111b ;high gran # (111), high sec/gran (11111) ld (iy+9),0ffh ;Directory cylinder ;*=*=* ; Open file now so user can get error if any, and so geometry ; is established a*=*=* ; Check if driver will fit into [(LCPTR), X'12FF'] ;*=*=* push hl ;Save address of pointer ld hl,length ;New pointer will be add hl,de ; pointer + LENGTH ld d,h ;Save a copy in DE ld e,l ld bc,1301h ) ;Copy current @ICNFG into LINK ld l,(iy+29) ld h,(iy+30) ld (link),a ld (link+1),hl ld hl,dvrcfg ;Get relocated init address rx10 equ $-2 ld (iy+29),l ;Save in @ICNFG vector ld ;If > 1300H, driver won't fit sub a ;Reset carry flag sbc hl,bc pop hl ;Get back address of pointer jr nc,usehi ;Go if driver won't fit ld (hl),e ;Store new value of pointer inc hl ld ( (iy+30),h ld (iy+28),0c3h ;Insert JP opcode ;*=*=* ; Move driver into low or high memory. ;*=*=* move: ld de,(newend) ;Destination address ld hl,dvrend ;Last byte of module ld bc,length ;Length of filter lddr exhl),d dec de ;Last byte of driver goes here ld (newend),de jr dorelo ;*=*=* ; Put in high memory instead. ;*=*=* usehi: ld hl,0 ;Get current HIGH$ ld b,l ld a,@high rst 40 jp nz,nomem ld (newend) de,hl inc hl ;Bump to driver entry ;*=*=* ; Setup DCT (iy+5 to iy+9 are reset by ckopen if successful) ;*=*=* setdct: ld iy,(dct) ld (iy),0c3h ;JP instruction (enable driver) ld (iy+1),l ;Driver address ld (,hl ;Last byte of driver goes here ld de,length sub a ;Reset carry flag sbc hl,de ;Compute new HIGH$ ld a,@high ;Set new HIGH$ into the system rst 40 ;*=*=* ; Relocate internal references in driver. ; HL = address for last bytver. ; HL = address for last byte of driver. ;*=*=* relo: ld hl,(newend) ld iy,reltab ;Point to relocation tbl ld de,dvrend sub a ;Clear carry flag sbc hl,de ld b,h ;Move to BC ld c,l rloop:erent - skip inc de inc hl djnz xgtm2 pop hl ;same - found ret nextmd: pop hl ;get back start of module inc hl inc hl ld e,(hl) ;pointer to last byte inc hl ld d,(hl) ex de,hl jr xgtmod ;*=*=* ; Messages and globals ;*=*=* hello_: defb ' ld l,(iy) ;Get address to change ld h,(iy+1) ld a,h or l ret z ld e,(hl) ;P/U address inc hl ld d,(hl) ex de,hl ;Offset it add hl,bc ex de,hl ld (hl),d ;XTRSHARD - Emulated hard disk driver for xtrs - 5/17/00',CR curdl_: defb 'LS-DOS is curdled!',CR nomem_: defb 'High memory is not available!',CR viaset_:defb 'Must install via SYSTEM (DRIVE=,DRIVER=)!',CR needdr_:defb 'DRIVE= must be specified!',CR uAnd put back dec hl ld (hl),e inc iy inc iy jr rloop ;Loop till done ;*=*=* ; Search for existing copy of driver. ; Rough Model I/III emulation of Model 4 @GTMOD, ; hardcoded with driver address. ; Entry:nit_: defb 'Enter unit number ([0]-','0'+ndrive-1,'): ',ETX hitbrk_:defb 'Aborted!',CR lcptr: defw 0 newend: defw 0 dct: defw 0 unit: defs 2 errbuf: defs 256 ; ; Driver - Based on skeletal driver from the Guide ; entry: jr begin ;Thes early as possible. ;*=*=* call ckopen ld hl,0 ;Successful completion ret z ;Fall thru if error ;*=*=* uerror: ld hl,errbuf ;Unix error ld bc,256 defw emt_strerror defb 0ddh curdl: ld hl,curdl_ ;Other error defb 0ddh needdr: ld hl, HL holds HIGH$ ; Exit Z: HL holds driver address ; NZ: driver not found ;*=*=* xgtmod: inc hl ld a,h or l jr nz,xgtm1 dec a ;not found ret xgtm1: ld a,(hl) cp 18h ;unconditional jr? ret nz ;not a module header push hl ;save start adneeddr_ defb 0ddh viaset: ld hl,viaset_ defb 0ddh nomem: ld hl,nomem_ defb 0ddh hitbrk: ld hl,hitbrk_ logot: ld a,@logot rst 40 ld hl,-1 ;Unuccessful completion ret ;*=*=* ; Relocate internal references in dridress inc hl ;skip jr inc hl ;skip offset inc hl ;skip start address inc hl ld a,(hl) ;compare name length cp modptr-modnam jr nz,nextmd ;different - skip ld b,a ;compare name ld de,modnam inc hl xgtm2: ld a,(de) cp (hl) jr nz,nextmd ;diffTransfer if functions <12-15> cp 10 jr z,vrsec jr nc,rdtrk cp 9 jr z,rdsec rdhdr: ld a,32 ;Not supported ("Illegal drive number") and a ret ;*=*=* rdsec: ;Read a sector of data ld a,(iy+6) ;Get high cyl # cp d ;At or below: defs ndrive*2 ;Unix file descriptors offset: defw 0,0,0,0 ;lseek offset buffer begin: ;*=*=* ; First make sure the file is open and correct the geometry ; in the DCT if needed. ;*=*=* push ix call ckopen rx03 equ $-2 call body rx06 equ $-2 p it? jr nc,rdok ld a,2 ;"Seek error during read" ret ;NZ already set rdok: push de push hl call doseek ;Setup and do lseek rx01 equ $-2 pop hl ld a,5 ;"Data record not found during read" jr nz,rddun ld bc,256 defw emt_read ld a,4 ;"Parity op ix ret body: ld a,32 ;"Illegal drive number" ret nz ld a,b ;The first test will return and a ; to the caller on @DCSTAT ret z ; and set the Z-flag with A=0 notdcs: cp 7 jr z,rslct ;Traerror during read" rddun: pop de ret nz ld a,b ;Check for end of file or c jr nz,rddun2 push de push hl ;Return a block full of 0E5H push bc ld (hl),0e5h ld d,h ld e,l inc de ld bc,0ffh ldir pop bc pop hl pop de sub a ret rddun2: ld ansfer on @RSLCT jr nc,diskio ;Transfer on physical I/O request ;*=*=* ; @SLCT, @DCINIT, @DCRES, @RSTOR, @STEPI or @SEEK: no-op ;*=*=* retzer: sub a ret ;*=*=* ; The RSLCT function should return with the hardware ; write protection ,d sub (iy+9) jr nz,rddun1 add a,6 ;"Attempted to read system data record" ret rddun1: sub a ret ;*=*=* vrsec: ;Read/verify -- we don't bother reading ld a,(iy+6) ;Get high cyl # cp d ;At or below it? jr nc,rddun2 ;Go if so ld a,2 ;"Seek errstatus. Set bit 6 of the accumulator ; to indicate the drive is write-protected ;*=*=* rslct: sub a ;No emulated hardware WP for now ret ;*=*=* diskio: bit 2,b ;Test if read or write commands jr nz,wrcmd ;or during read" ret ;NZ already set ;*=*=* ; On RDSEC and VRSEC, if the read referenced the ; directory cylinder and was successful, ; then you need to return an error code 6. A floppy ; disk controller will provide the indicated driver starts with the defw dvrend ; DOS standard header rx00 equ $-2 defb modptr-modnam ;Length of name modnam: defb 'xtrshard' ;Name for @GTMOD requests modptr: defw 0 ;These pointers are unused defw 0 fd*=* wrssc: ;Write with X'F8' data address mark ld a,(iy+6) ;Get high cyl # cp d ;Beyond it? jr nc,wrok1 ld a,10 ;"Seek error during write" ret ;NZ already set ;*=*=* wrok1: push de push hl call doseek rx04 equ $-2 pop hl ld a,13 ;"Data repop de ld a,(ix) ;fd == -1? and (ix+1) inc a jr z,doopen sub a ret doopen: push de push bc push hl ld bc,EO_RDWR ;Prepare to open ld de,0666o ;mode ld hl,hard_ ;name rx05 equ $-2 ld a,(iy+4) and 0fh add a,'0' ld (hadr),a rx09 equ $-2 defw status. ; Hard disk users may have to compare the requested ; cylinder to DIRCYL in the DCT. ;*=*=* rdtrk: ld a,32 ;Not supported ("Illegal drive number") and a ret ;*=*=* wrcmd: bit 7,(iy+3) ;Check for softwcord not found during write" jr nz,wrdun ld bc,256 defw emt_write ld a,12 ;"Parity error during write" wrdun: pop de ret nz sub a ret ;*=*=* wrtrk: ld a,32 ;Write track and a ;Not supported ("Illegal drive number") ret ;*=*are write protect jr z,wrcmd1 ;Transfer if no soft WP ld a,15 ;Set "Write protected disk" error ret wrcmd1: cp 14 ;Now parse functions 12-15 jr z,wrssc jr nc,wrtrk cp 13 jr z,wrsec ;*=*=* hdfmt: =* ; Perform lseek before r/w ;*=*=* doseek: sub a ;sec/cyl to hl, xlate 0 to 256 ld h,a add a,(iy+5) ld l,a jr nz,noinc inc h noinc: ld c,d ;cyl# to c ld b,e ;sec# to b ld a,c ;model I/III call uses a, not c domul: ld a,@mul16 ;hla = hl * c, sm ;Low-level format (=erase) ld (iy+9),0ffh ;Invalidate directory cylinder push de push hl ld e,(ix) ;Get fd ld d,(ix+1) exists: ld hl,256 ;Truncate file to just the header ld (offset+1),hl rx07 equ $-2 ld hl,offset rx08 equ $-2 defw emt_ftrunash de rst 40 ld d,h ;sec# to de (h is 0) ld e,b ld h,l ;product to hl ld l,a inc hl ;add 1 extra for header add hl,de ex de,hl ;offset to de ld hl,offset+2 rx15 equ $-2 ld (hl),d dec hl ld (hl),e dec hl ld bc,0 ld (hl),c ld e,(ix) ;Gecate creatd: pop hl pop de ld a,14 ;"Write fault on disk drive" ret nz sub a ret ;*=*=* wrsec: ;Write with X'FB' data address mark ld a,d ;Check if writing track 0, sector 0 or e call z,setdir ;Set directory cyl in Reed header rx20 equ $-2 ;*=t fd ld d,(ix+1) defw emt_lseek ret ;*=*=* ; Open file and read geometry if needed, and ; get address of correct fd to ix. ;*=*=* ckopen: ld ix,fd ;Compute fd address rx02 equ $-2 push de ld d,0 ld a,(iy+4) and 0fh rlca ld e,a add ix,de 0,rx01,rx02,rx03,rx04,rx05,rx06,rx07,rx08,rx09 defw rx10,rx11,rx12,rx13,rx14,rx15,rx16,rx17,rx18,rx19 defw rx20,0 end instal dec a ;not found ret xgtm1: ld a,(hl) cp 18h ;unconditional jr? ret nz ;not a module header push hl ;save start ad;*=*=* ; Sleazy trick to update dir cyl in Reed header: do ; it whenever track 0, sector 0 is written. ; Only important if sharing images with Reed emulator. ;*=*=* setdir: push hl push bc push de ld hl,offset rx18 equ $-2 ld b,d ;de is known to be 0 ååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååhere ld c,e ld e,(ix) ;Get fd ld d,(ix+1) ld (hl),31 ;offset to dir cyl param ld (offset+1),bc rx19 equ $-2 defw emt_lseek ld a,(iy+9) ;dir cyl value to write ld (hl),a inc bc defw emt_write pop de ;cheat, ignore errors pop bc pop hl ret ;ååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååemt_opendisk ld (ix),e ld (ix+1),d jr nz,opnerr ld hl,offset ;Prepare to read geometry rx13 equ $-2 ld (hl),28 ;offset to cyl/sec/gran params ld bc,0 ld (offset+1),bc rx14 equ $-2 defw emt_lseek jr nz,opnerr ld bc,3 ;length defw emt_read ;use*=*=* ; Boot-time initialization ;*=*=* dvrcfg: ld de,-1 ;@ICNFG chains in here defw emt_closedisk ;close any files left from before reboot call dvrini rx11 equ $-2 link: defb 'Tim' ;Replaced by next link in @ICNFG chain dvrini: ld hl,fd rx12 equ $-2 offset buffer jr nz,opnerr ld a,(hl) ;cyl dec a ld (iy+6),a ;max cylinder inc hl ld b,(hl) ;sec ld (iy+5),b inc hl ld c,(hl) ;gran ld e,b ;compute sec/gran ld a,c ;model I/III call uses a, not c dodiv: ld a,@div8 ;a = e / c, e = e % c rs ld d,h ld e,l inc de ld (hl),0ffh ld bc,ndrive*2-1 ldir ret ;*=*=* ; Disk name: hardM-N for model M (1,3,4), number N (0-7) ;*=*=* hard_: defb 'hard' hmod: defb '1-' hadr: defb '0',0 dvrend equ $-1 length equ $-entry reltab: defw rx0t 40 ;remainder mbz, but we don't check here dec a dec c rrc c rrc c rrc c or c ld (iy+7),a ;heads, secs per track ld (iy+8),a ;grans, secs per gran ld (iy+9),0ffh ;dircyl unknown sub a ;no error opnerr: pop hl pop bc pop de ret > ï>aeïý~Ë_ÊÜaí[3cz³ÊØa!ðb> ï!5c> ïÚäaÂäa:5cþ08äþ80àMd>SïÊ—aDd>SïÂÔa"WdKI>RïÂÔa+V+^å!,T]—íBá0 s#ríS1c!E>dïÂàa"1c,—íR>dïÍîaí[1c!sd,í¸ë#ý*3cýuýtý6 :5cæO!7d ~ö@ýwý6ý6Lý6ý6'ý6 &!—É!cÝ!{bÝ!ÖbÝ!¬bÝ!ŽbÝ! c> ï!ÿÿÉ*1cý!tdsdified versions are clearly ; marked as having been modified, with the modifier's name and ; the date included. ; ; Created 4-9-98 ; Last modified on Thu Apr 9 17:26:29 PDT 1998 by mann ;*=*=* ; Number of floppy drives xtrs allows ndrive equ 8 —íRDMýnbýf|µÈ^#Vë ër+sý#ý#è#|µ =É~þÀÕå####F#þ 8¾ #ôþ 0áÑ—Éá##^#VëÑÎXTRS8 - Emulated 8" floppy driver for xtrs - 4/9/98 LS-DOS is curdled! High memory is not available! Must install via SYSTEM (DRIVE=,DRIVER=)! DRIVE= must be specified! Ente; ASCII chars LF equ 10 CR equ 13 ETX equ 3 ; Model 4 SVC numbers @high equ 100 @dsply equ 10 @flags equ 101 @logot equ 12 @gtdcb equ 82 @gtmod equ 83 @keyin equ 9 ; Model I/III hard addresses m3flag$ equ 0125h ; 'I' in ROr unit numbe7cr (4-7): Aborted! FDUBL must be loaded first! C7d$FDD$FD sdxtrs8ÍõýËn(IýËv 'ýpýqñÉJd`not found ret xgtm1: ld a,(hl) cp 18h ;unconditional jr? ret nz ;not a module header push hl ;save start adM on Model III @logot1 equ 447bh @logot3 equ 428ah @dsply1 equ 4467h @dsply3 equ 4467h high$1 equ 4049h high$3 equ 4411h cflag$1 equ 4758h cflag$3 equ 4758h @keyin1 equ 0040h @keyin3 equ 0040h osver$3 equ 441fh ; Very undocumented! uåååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååågh! flop31 equ 4585h ;Model III LDOS 5.1.x floppy driver flop33 equ 4583h ;Model III LDOS 5.3.x floppy driver ;*=*=* ; Set origin to be safe on both LDOS 5 and 6 ;*=*=* org 6000h ;*=*=* ; Relocator for disk driver ;*=*=* instal: ld (dct),de ;Save DCT`íS3c: þ@Âù`:%þIʆ`>Í2ça!{D"èa!GbÍgD:XGË_ÊÜaí[3cz³ÊØa!ðbÍgD!5cÍ@ÚäaÂäa:5cþ08äþ80àMd*I@ÍbÊ—a?d*I@ÍbÂÐa"Wd*I@"1c,—íR"I@ÍîaÉa>Í2ça!ŠB"èa!GbÍgD:XGË_ÊÜaí[3cz³ÊØa!ðbÍgD!5cÍ@ÚäaÂäa:5cþ08äþ80àMd*DÍbÊ—a:DþQ!…E(!ƒE"Wd*D"1c,—íR"DÍîaÉa!Gb;*=*=* ; xtrs8/dct ; LDOS driver for xtrs emulation of 8" floppy ; ; Copyright (c) 1998, Timothy Mann ; ; This software may be copied, modified, and used for any ; purpose without fee, provided that (1) the above copyright ; notice is retained, and (2) modumber ld a,@dsply rst 40 ld hl,unit ld bc,100h ld a,@keyin rst 40 jp c,hitbrk jp nz,hitbrk ld a,(unit) cp '0' jr c,asku4 cp '0'+ndrive jr nc,asku4 ;*=*=* ; Check if driver already loaded ;*=*=* ld de,modnam ld a,@gtmod rst 40 jp z,se address ld a,(000ah) ;Determine TRS-80 model cp 40h jp nz,lsdos6 ;Model 4 (or other LS-DOS, I hope) ld a,(m3flag$) cp 'I' jp z,model3 ;Go if Model III ;*=*=* ; LDOS 5 Model I - See LS-DOS 6 version for comments ;*=*=* ld a,0cdh ;Insert Model I @Lber call @dsply3 ld hl,unit ld bc,100h call @keyin3 jp c,hitbrk jp nz,hitbrk ld a,(unit) cp '0' jr c,asku3 cp '0'+ndrive jr nc,asku3 ld de,modnam ;Module already loaded? ld hl,(high$3) call xgtmod jp z,setdct ; ; Doesn't work on Model III: ;OGOT ld (logot),a ld hl,@logot1 ld (logot+1),hl ld hl,hello_ call @dsply1 ld a,(cflag$1) bit 3,a ;System request? jp z,viaset ld de,(dct) ld a,d ;DRIVE= must be specified or e jp z,needdr asku1: ld hl,unit_ ;Ask which unit numbe ld de,fd3 ;Find floppy driver ; ld hl,(high$3) ; call xgtmod ; jp nz,needfd ;go if missing ; ; Cheat instead: ld a,(osver$3) cp 51h ld hl,flop31 jr z,gotit ld hl,flop33 gotit: ; ld (flop),hl ld hl,(high$3) ld (newend),hl ld de,length r call @dsply1 ld hl,unit ld bc,100h call @keyin1 jp c,hitbrk jp nz,hitbrk ld a,(unit) cp '0' jr c,asku1 cp '0'+ndrive jr nc,asku1 ld de,modnam ;Module already loaded? ld hl,(high$1) call xgtmod jp z,setdct ld de,fd1 ;Find fdubl driver ldsub a sbc hl,de ld (high$3),hl call relo jp move ;*=*=* ; LS-DOS 6 ;*=*=* lsdos6: ld hl,hello_ ld a,@dsply ;Display hello rst 40 ;*=*=* ; Check if entry from SYSTEM command. ;*=*=* ld a,@flags ;Get flags hl,(high$1) call xgtmod jp nz,needfd ;go if missing ld (flop),hl ld hl,(high$1) ld (newend),hl ld de,length sub a sbc hl,de ld (high$1),hl call relo jp move ;*=*=* ; LDOS 5 Model III ;*=*=* model3: ld a,0cdh ;Insert Model III pointer into IY rst 40 ld a,(iy+'C'-'A') ;Get CFLAG$ bit 3,a ;System request? jp z,viaset ld de,(dct) ld a,d ;DRIVE= must be specified or e jp z,needdr ;*=*=* ; Ask which unit number ;*=*=* asku4: ld hl,unit_ ;Ask which unit n@LOGOT ld (logot),a ld hl,@logot3 ld (logot+1),hl ld hl,hello_ call @dsply3 ld a,(cflag$3) bit 3,a ;System request? jp z,viaset ld de,(dct) ld a,d ;DRIVE= must be specified or e jp z,needdr asku3: ld hl,unit_ ;Ask which unit numpointer ld hl,length ;New pointer will be add hl,de ; pointer + LENGTH ld d,h ;Save a copy in DE ld e,l ld bc,1301h ;If > 1300H, driver won't fit sub a ;Reset carry flag sb ld (iy+1),l ;Driver address ld (iy+2),h ld (iy+3),00100000b ;Flags: 8" floppy ld a,(unit) ;Xlate unit number to select code and 07h ld c,a ld b,0 ld hl,utab add hl,bc ld a,(hl) or 01000000b ;Flags: dden capable, selc hl,bc pop hl ;Get back address of pointer jr nc,usehi ;Go if driver won't fit ld (hl),e ;Store new value of pointer inc hl ld (hl),d dec de ;Last byte of driver goes here ld (newend),de jr dorelo ;*=*=* ; Put ect code ld (iy+4),a ld (iy+5),0 ;current cylinder number ld (iy+6),76 ;high cylinder number ld (iy+7),0fh ;init to sden head/sec/gran config ld (iy+8),27h ld (iy+9),38 ;Directory cylinder (guess) ld hl,0 ;Successful cotdct ;Already loaded, skip loading ;*=*=* ; Find system floppy driver ;*=*=* ld de,fd4 ld a,@gtmod rst 40 jp nz,curdl ;Fatal error if not found ld (flop),hl ;*=*=* ; Obtain low memory driver pointer. Bizarre API here! ;*=*=* ld e,'in high memory instead. ;*=*=* usehi: ld hl,0 ;Get current HIGH$ ld b,l ld a,@high rst 40 jp nz,nomem ld (newend),hl ;Last byte of driver goes here ld de,length sub a ;Reset carry flag sbc hl,de ;Compute nK' ;Locate pointer to *KI DCB ld d,'I' ; via @GTDCB SVC ld a,@gtdcb rst 40 jp nz,curdl ;No error unless KI clobbered! dec hl ;Decrement to driver pointer ld ew HIGH$ ld a,@high ;Set new HIGH$ into the system rst 40 ;*=*=* ; Relocate internal references in driver. ; HL = address for last byte of driver. ;*=*=* dorelo: call relo ;*=*=* ; Move driver into low or high memory. ;*=*=* d,(hl) ;P/u hi-order of pointer, dec hl ; decrement to and p/u ld e,(hl) ; lo-order of pointer ;*=*=* ; Check if driver will fit into [(LCPTR), X'12FF'] ;*=*=* push hl ;Save address of move: ld de,(newend) ;Destination address ld hl,dvrend ;Last byte of module ld bc,length ;Length of filter lddr ex de,hl inc hl ;Bump to driver entry ;*=*=* ; Setup DCT ;*=*=* setdct: ld iy,(dct) ffset inc hl ;skip start address inc hl ld b,(hl) ;get name length inc hl xgtm2: ld a,(de) cp 20h jr c,nextmd ;desired name shorter - skip cp (hl) jr nz,nextmd ;character different - skip inc de inc hl djnz xgtm2 ld a,(de) cp 20h jr nc,nextrend sub a ;Clear carry flag sbc hl,de ld b,h ;Move to BC ld c,l rloop: ld l,(iy) ;Get address to change ld h,(iy+1) ld a,h or l ret z ld e,(hl) ;P/U address md ;desired name longer - skip pop hl ;same - found pop de sub a ret nextmd: pop hl ;get back start of module inc hl inc hl ld e,(hl) ;pointer to last byte inc hl ld d,(hl) ex de,hl pop de jr xgtmod ;*=*=* ; Messages and globals ;*=*=* hellinc hl ld d,(hl) ex de,hl ;Offset it add hl,bc ex de,hl ld (hl),d ;And put back dec hl ld (hl),e inc iy inc iy jr rloop ;Loop till done ;*=*=* ; Search for existing co_: defb 'XTRS8 - Emulated 8" floppy driver for xtrs - 4/9/98',CR curdl_: defb 'LS-DOS is curdled!',CR nomem_: defb 'High memory is not available!',CR viaset_:defb 'Must install via SYSTEM (DRIVE=,DRIVER=)!',CR needdr_:defb 'DRIVE= must be specifiopy of driver. ; Rough Model I/III emulation of Model 4 @GTMOD, ; hardcoded with driver address. ; Entry: HL = (HIGH$) ; DE => module name, terminated with a character <= 0x1f ; Exit Z: HL = driver address ; NZ: drivered!',CR unit_: defb 'Enter unit number (4-7): ',ETX hitbrk_:defb 'Aborted!',CR needfd_:defb 'FDUBL must be loaded first!',CR lcptr: defw 0 newend: defw 0 dct: defw 0 unit: defs 2 errbuf: defs 256 utab: defb 1,2,4,8,3,5,6,7 fd1: defb '$FDD',ETX fd4: mpletion sub a ret ;*=*=* needfd: ld hl,needfd_ defb 0ddh curdl: ld hl,curdl_ ;Other error defb 0ddh needdr: ld hl,needdr_ defb 0ddh viaset: ld hl,viaset_ defb 0ddh nomem: ld hl,nomem_ defb 0ddh hitbrk: ld hl,hitbrk_ logot: ld a,@lo not found ;*=*=* xgtmod: inc hl ld a,h or l jr nz,xgtm1 dec a ;not found ret xgtm1: ld a,(hl) cp 18h ;unconditional jr? ret nz ;not a module header push de ;save desired name ptr push hl ;save start address inc hl ;skip jr inc hl ;skip ogot rst 40 ld hl,-1 ;Unuccessful completion ret ;*=*=* ; Relocate internal references in driver. ; HL = address for last byte of driver. ;*=*=* relo: ld hl,(newend) ld iy,reltab ;Point to relocation tbl ld de,dvdefb '$FD',ETX ; ; Driver - just a tiny wrapper around LDOS dden floppy driver ; entry: jr begin ;The driver starts with the defw dvrend ; DOS standard header rx00 equ $-2 defb modptr-modnam ;Length of name modnam: def0k1>ï•0!Ò0> ï1>SïÊ™0x±((KI>RïÂ0+V+^å!T]—íBá0 s#ríSi1!E>dï¡0"i1—íR>dïÍ«0>eïý~ýnýf2‘1"’1!Ž1ýuýtý6Ãí[i1!š1í¸ë#Í”1!—É!W1Ý!71Ý!1Ý!1> ï!ÿÿÉ*i1ý!›1š1—íRDMýnýf|µÈ^#Vë ër+sý#ý#èXTRSMOUS - Emulated mouse driver for xtrs b 'xtrs8' ;Name for @GTMOD requests modptr: defw 0 ;These pointers are unused, but 1st byte MBZ defw 0 begin: call $-$ ;call the real driver flop equ $-2 push af bit 5,(iy+3) ;8" drive? jr z,done ;go if not ld bc,1- 9/§128/98 LS-DOS is curdled! High memory is not available! Mouse driver is already loaded! Bad parameters! LOW 0L 0 š1$MOUSEí)ÉÍ”1Tim!|1"ðÉ~1s01•10t install via SYSTEM (DRIVE=,DRIVER=)!',CR needdr_:defb 'DRIVE= must be specifid49h ;init for dden bit 6,(iy+3) ;dden? jr nz,ldden ;go if so ld bc,0f27h ldden: ld (iy+7), b ld (iy+8), c done: pop af ret dvrend equ $-1 length equ $-entry reltab: defw rx00,0 end instal nts ;*=*=* ld a,0cdh ;Insert Model I @Låååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå ;P/u hi-order of pointer, dec hl ; decrement to and p/u ld e,(hl) ; lo-order of pointer ;*=*=* ; Check if driver will fit into [(LCPTR), X'12FF'] ;*=*=* push hl ;Save address of pointer ld equ 100 @dsply equ 10 @flags equ 101 @logot equ 12 @gtdcb equ 82 @gtmod equ 83 @keyin equ 9 @param equ 17 @mouse equ 120 ;unofficial value svcvec equ 100h + 2*@mouse ; xtrs emts (byte-reversed) emt_mouse equ 029edh org hl,length ;New pointer will be add hl,de ; pointer + LENGTH ld d,h ;Save a copy in DE ld e,l ld bc,1301h ;If > 1300H, driver won't fit sub a ;Reset carry flag sbc hl,bc pop hl;*=*=* ; xtrsmous/cmd ; LS-DOS driver for xtrs emulation of mouse ; ; Copyright (c) 1998, Timothy Mann ; ; This software may be copied, modified, and used for any ; purpose without fee, provided that (1) the above copyright ; notice is retained, and (2) mo3000h ;*=*=* ; Relocator for disk driver ;*=*=* instal: ld de,prmtab ld a,@param ;Parse parameters rst 40 jp nz,prmerr ld hl,hello_ ld a,@dsply ;Display hello rst 40 ;*=*=* ; Check if driver already loaded ;*=*=* ld de,modified versions are clearly ; marked as having been modified, with the modifier's name and ; the date included. ; ; Created 9-28-98 ; Last modified on Sat Oct 10 20:57:36 PDT 1998 by mann ; ; Usage: ; xtrsmous To load driver in high memory. ; dnam ld a,@gtmod rst 40 jp z,loaded ;Already loaded ;*=*=* ; Check if OK to use low memory. ;*=*=* lparm: ld bc,0 ld a,b or c jr z,usehi ;*=*=* ; Obtain low memory driver pointer. Bizarre API here! ;*=*=* ld e,'K' ;Locatxtrsmous (low) To load driver in low memory if possible, ; or in high memory if low memory is full. ; ; The default is to use high memory because MDRAW/BAS contains a ; PEEK in the first line of code that looks for the driver in ; high memory; if it e pointer to *KI DCB ld d,'I' ; via @GTDCB SVC ld a,@gtdcb rst 40 jp nz,curdl ;No error unless KI clobbered! dec hl ;Decrement to driver pointer ld d,(hl) is in low memory, MDRAW thinks the driver ; is not installed and exits. If you edit this line of code to ; remove the test, the driver will work fine in low memory. ;*=*=* ; ASCII chars LF equ 10 CR equ 13 ETX equ 3 ; Model 4 SVC numbers @high,@high ;Set new HIGH$ into the system rst 40 ;*=*=* ; Relocate internal references in driver. ; HL = address for last byte of driver. ;*=*=* dorelo: call relo ;*=*=* ; Link to @ICNFG (must follow address relocation and precede movement) ful completion ret ;*=*=* ; Relocate internal references in driver. ; HL = address for last byte of driver. ;*=*=* relo: ld hl,(newend) ld iy,reltab ;Point to relocation tbl ld de,dvrend sub a ;Clear carry flag ;*=*=* ld a,@flags ;Get flags pointer into IY rst 40 ld a,(iy+28) ;Copy current @ICNFG into LINK ld l,(iy+29) ld h,(iy+30) ld (link),a ld (link+1),hl ld hl,dvrcfg ;Get relocated sbc hl,de ld b,h ;Move to BC ld c,l rloop: ld l,(iy) ;Get address to change ld h,(iy+1) ld a,h or l ret z ld e,(hl) ;P/U address inc hl ld d,(hl) ex de,hl init address rx01 equ $-2 ld (iy+29),l ;Save in @ICNFG vector ld (iy+30),h ld (iy+28),0c3h ;Insert JP opcode ;*=*=* ; Move driver into low or high memory. ;*=*=* move: ld de,(newend) ;Destination address ld ;Offset it add hl,bc ex de,hl ld (hl),d ;And put back dec hl ld (hl),e inc iy inc iy jr rloop ;Loop till done ;*=*=* ; Messages and globals ;*=*=* hello_: defb 'XTRSMOUS - Emulated mous ;Get back address of pointer jr nc,usehi ;Go if driver won't fit ld (hl),e ;Store new value of pointer inc hl ld (hl),d dec de ;Last byte of driver goes here ld (newend),de jr dorelo ;*=*=* ; Put in high memory inst hl,dvrend ;Last byte of module ld bc,length ;Length of filter lddr ex de,hl inc hl ;Bump to driver entry ;*=*=* ; Driver is loaded; finish up. ;*=*=* call dvrini ;Hook into SVC table ld hl,0 ead. ;*=*=* usehi: ld hl,0 ;Get current HIGH$ ld b,l ld a,@high rst 40 jp nz,nomem ld (newend),hl ;Last byte of driver goes here ld de,length sub a ;Reset carry flag sbc hl,de ;Compute new HIGH$ ld a ;Successful completion sub a ret ;*=*=* ; Error vectors ;*=*=* prmerr: ld hl,prmerr_ defb 0ddh loaded: ld hl,loaded_ defb 0ddh curdl: ld hl,curdl_ defb 0ddh nomem: ld hl,nomem_ logot: ld a,@logot rst 40 ld hl,-1 ;Unuccess/* cd.ccc -- Misosys C program to change Unix working directory on xtrs */ /* Copyright (c) 1998, Timothy Mann */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retainele ;*=*=* prmtab: defb 'LOW ' defw lparm+1 defb 'L ' defw lparm+1 defb 0 ;*=*=* ; Driver ;*=*=* entry: jr begin ;The driver starts with the defw dvrend ; DOS standard header rx00 equ $-2 defb modptr-modnam ;Led, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* Last modified on Tue Dec 15 16:59:03 PST 1998 by mann */ #option redirect 0 #include "xtrsemt.h" #include "xtrsemt.ccc" /*ngth of name modnam: defb '$MOUSE' ;Name for @GTMOD requests modptr: defw 0 ;These pointers are unused, but 1st byte MBZ defw 0 ;*=*=* ; Do the real work using an emulator trap ;*=*=* begin: defw emt_mouse ret ;*=*=* ; Boot- could use separate compilation instead */ usage() { fprintf(stderr, "usage: cd [-l] unixdir\n"); exit(1); } #define ERRBUFSIZE 256 #define NAMEBUFSIZE 256 int main(argc, argv) int argc; char **argv; { int ret, lower, i; char etime initialization ;*=*=* dvrcfg: ;@ICNFG chains in here call dvrini rx02 equ $-2 link: defb 'Tim' ;Replaced by next link in @ICNFG chain ;*=*=* ; Hook into SVC table ;*=*=* dvrini: ld hl,entry rx03 equ $-2 ld (svcvec),hl ret dvrend equ $-1 rrbuf[ERRBUFSIZE]; char namebuf[NAMEBUFSIZE]; char *p, *q; if (argc < 2) { usage(); } i = 1; if (argv[i][0] == '-') { if (tolower(argv[i][1]) != 'l') { usage(); } i++; lower = 1; } else { lower = 0; } length equ $-entry reltab: defw rx00,rx01,rx02,rx03,0 end instal ;high cylinder number ld (iy+7),0fh ;init to sden head/sec/gran config ld (iy+8),27h ld (iy+9),38 ;Directory cylinder (guess) ld hl,0 ;Successful coif (argc - i != 1) { usage(); } p = namebuf; q = argv[i]; if (lower) { while (*q) { if (*q == '[' && *(q+1)) { q++; *p++ = *q++; } else if (isalpha(*q)) { *p++ = tolower(*q++); } else { *p++ = *q++; } e driver for xtrs - 9/28/98',CR curdl_: defb 'LS-DOS is curdled!',CR nomem_: defb 'High memory is not available!',CR loaded_:defb 'Mouse driver is already loaded!',CR prmerr_:defb 'Bad parameters!',CR lcptr: defw 0 newend: defw 0 ;*=*=* ; Parameter tabåååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååån", dirbuf); exit(0); } ); } p = namebuf; q = argv[i]; if (lower) { while (*q) { if (*q == '[' && *(q+1)) { q++; *p++ = *q++; } else if (isalpha(*q)) { *p++ = tolower(*q++); } else { *p++ = *q++; } } } else { while (*q) *p++ = *q++; } *p = '\000'; ret = emt_chdir(namebuf); if (ret != 0) { emt_strerror(errno, errbuf, ERRBUFSIZE); fprintf(stderr, "%s: %s\n", namebuf, errbuf); exit(1); } exit(0); } ded ;*=*=* ld de,mo/* pwd.ccc -- Misosys C program to print the Unix working directory of xtrs */ /* Copyright (c) 1998, Timothy Mann */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* Last modified on Tue Dec 15 16:59:26 PST 1998 by mann */ #option redirect 0 #include "xtrsemt.h" #include "xtrsemt.ccc"åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå /* could use separate compilation instead */ usage() { fprintf(stderr, "usage: pwd\n"); exit(1); } #define ERRBUFSIZE 256 #define DIRBUFSIZE 512 int main(argc, argv) int argc; char **argv; { int i; char *ret; char errbuf[ååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååERRBUFSIZE]; char dirbuf[DIRBUFSIZE]; if (argc != 1) { usage(); } ret = emt_getcwd(dirbuf, DIRBUFSIZE); if (ret == NULL) { emt_strerror(errno, errbuf, ERRBUFSIZE); fprintf(stderr, "pwd: %s\n", errbuf); exit(1); } printf("%s\ååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååar errbuf[ERRBUFSIZE]; char cmdbuf[CMDBUFSIZE]; char *p, *q; if (argc < 2) { usage(); } i = 1; if (argv[i][0] == '-') { if (tolower(argv[i][1]) != 'l') { usage(); } i++; lower = 1; } else { lower = 0; } åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå p = cmdbuf; for (; i> 8, ret & 0xff); exit(1); } exit(0); } ointer. Bizarre API here! ;*=*=* ld e,'K' ;Locat /* could use separate compilation instead */ usage() { fprintf(stderr, "usage: unix [-l] command\n"); exit(1); } #define ERRBUFSIZE 256 #define CMDBUFSIZE 512 int main(argc, argv) int argc; char **argv; { int ret, i, lower; ch and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* Last modified on Tue Dec 15 14:54:58 PST 1998 by mann */ #option redirect 0 #include "xtrsemt.h" #include "xtrsemt.ccc" /* c "%d", hl); } sprintf(dname, "%s/disk%s-%s", ddir, model, argv[i+1]); sprintf(cmd, "rm -f %s", dname); /*printf("$ %s\n", cmd);*/ ret = emt_system(cmd); if (ret != 0) { emt_strerror(errno, errbuf, ERRBUFSIZE); fprintf(stderr, "emtould use separate compilation instead */ usage() { fprintf(stderr, "usage: mount [-l] file.dsk unit#\n"); exit(1); } #define DDIRSIZE 256 #define DNAMESIZE 512 #define FNAMESIZE 256 #define CMDSIZE 512 #define ERRBUFSIZE 512 int main(argc, argv)_system: %s\n", errbuf); exit(1); } p = fname; q = argv[i]; if (lower) { while (*q) { if (*q == '[' && *(q+1)) { q++; *p++ = *q++; } else if (isalpha(*q)) { *p++ = tolower(*q++); } else { *p++ = *q++; int argc; char **argv; { char ddir[DDIRSIZE]; char dname[DNAMESIZE], fname[FNAMESIZE], cmd[CMDSIZE]; char errbuf[ERRBUFSIZE]; char model[4]; int hl, bc, de, ret, lower, i; char *retp, *p, *q; if (argc < 2) { usage()} } } else { while (*q) *p++ = *q++; } *p = '\000'; sprintf(cmd, "ln -s %s %s", fname, dname); /*printf("$ %s\n", cmd);*/ ret = emt_system(cmd); if (ret != 0) { emt_strerror(errno, errbuf, ERRBUFSIZE); fprintf(stderr, "emt_; } i = 1; if (argv[i][0] == '-') { if (tolower(argv[i][1]) != 'l') { usage(); } i++; lower = 1; } else { lower = 0; } if (argc - i != 2 || !isdigit(argv[i+1][0])) { usage(); } retp = emt_gtddir(ddir, DDIRSsystem: %s\n", errbuf); exit(1); } emt_misc(EMT_MISC_DISK_CHANGE); exit(0); } ve a copy in DE ld e,l ld bc,1301h ;If > 1300H, driver won't fit sub a ;Reset carry flag sbc hl,bc pop hl/* mount.ccc -- Misosys C program to switch emulated floppies on xtrs */ /* Copyright (c) 1998, Timothy Mann */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained,IZE); if (retp == NULL) { emt_strerror(errno, errbuf, ERRBUFSIZE); fprintf(stderr, "emt_getddir: %s\n", errbuf); exit(1); } emt_4misc(EMT_MISC_QUERY_MODEL, &hl, &bc, &de); if (hl == 5) { strcpy(model, "4p"); } else { sprintf(model,åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå/* umount.ccc -- Misosys C program to unmount an emulated floppy on xtrs */ /* Copyright (c) 1998, Timothy Mann */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retain%d", hl); } sprintf(dname, "%s/disk%s-%s", ddir, model, argv[1]); sprintf(cmd, "rm -f %s", dname); /*printf("$ %s\n", cmd);*/ ret = emt_system(cmd); if (ret != 0) { emt_strerror(errno, errbuf, ERRBUFSIZE); fprintf(stderr, "emt_sysed, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ /* Last modified on Tue Dec 15 15:21:16 PST 1998 by mann */ #option redirect 0 #include "xtrsemt.h" #include "xtrsemt.ccc" /tem: %s\n", errbuf); exit(1); } emt_misc(EMT_MISC_DISK_CHANGE); exit(0); } f(cmd, "rm -f %s", dname); /*printf("$ %s\n", cmd);*/ ret = emt_system(cmd); if (ret != 0) { emt_strerror(errno, errbuf, ERRBUFSIZE); fprintf(stderr, "emt* could use separate compilation instead */ usage() { fprintf(stderr, "usage: umount unit#\n"); exit(1); } #define DDIRSIZE 256 #define DNAMESIZE 512 #define CMDSIZE 512 #define ERRBUFSIZE 512 int main(argc, argv) int argc; char **argvåååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå; { char ddir[DDIRSIZE]; char dname[DNAMESIZE], cmd[CMDSIZE]; char errbuf[ERRBUFSIZE]; char model[4]; int hl, bc, de, ret; char *retp; if (argc != 2 || !isdigit(argv[1][0])) { usage(); } retp = emt_gtddir(ddir, DDIRSIZååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååE); if (retp == NULL) { emt_strerror(errno, errbuf, ERRBUFSIZE); fprintf(stderr, "emt_getddir: %s\n", errbuf); exit(1); } emt_4misc(EMT_MISC_QUERY_MODEL, &hl, &bc, &de); if (hl == 5) { strcpy(model, "4p"); } else { sprintf(model, "&åÍ»fñå!lÑÍCi|µÊ UÍdT!9åͪi#Ñͯi+!9å!ÑͯiÃ4U!9å!Ñͯi! 9ͪiå!9ͪiÑÍ‘iå!ÑÍCi|µÊWUÍdT!9å!9Ñͯi!eU9å!9ͪiå!9ͪiÍ}iÑͪiÑͯi!9ͪi|µÊ”V!9ͪin&|µÊ‘V!9ͪin&å![ÑÍ=i|µÊÉU!9ͪiå!Ñn&|µÊV!9åͪiÑͯiÿÿ!9åͪiÑÍåÍäfñ|µÊ^Z*ŒX Í}iå*†X#"†X+n&å͹`ñÑ"ŒXÃ,Z*†Xn&.Í=i|µÊæZ*†X#"†Xn&*Í=i|µÊ«ZñÁáåÅõåͪi##Ñͯiå!ÿÿ)Ñͪi"ŽX*†X#"†XÃãZ!"ŽX*†Xn&åÍäfñ|µÊãZ*ŽX Í}iå*†X#"†X+n&ÕZå͹`ñÑ"ŽXñZÃìZ!ÿÿ"ŽX!"“X*†Xn&åÑ!lÍri [!"“XÃ[!hÍriÂ[*†X#"†X!"‘X! Y"ŸX*†X#"¯iÿÿå!9åͪiÑͯiÿÿn&Ñ}ÃŽV!9ͪin&åÍÑfñ|µÊ_V!9åͪiÑͯiÿÿå!9åͪiÑͯiÿÿn&åÍ»fñÑ}ÃŽV!9åÍeVªiÑͯiÿÿå!9åͪiÑͯiÿÿn&Ñ}ÓUÃÕV!9ͪin&|µÊÕV!9åͪiÑͯiÿÿå!9åͪiÑͯiÿÿn&Ñ}ÔV!9ͪiå!Ñ}!9å!9†X+n&}2XåÑ!dÍriÂE[ÃN[!uÍriÂW[!"ÑXâ[!oÍriÂi[!"ÑXâ[!XÍriÂu[Ã~[!xÍri‡[!"ÑXâ[!BÍri“[Ü[!bÍriÂU^!"ÑX*ŽXëÍVi|µÊ·[!"ŽX*“X|µÊå[ñÁáåÅõåͪiÑͯiå!ÿÿÕ[))ÑÍ(i!ÉXÍ0iÃ?\:Xo&dÍ=i|µÊ\ñÁáåÅõåͪi##Ñͯiå!ÿÿ)ÑͪiÍi!ÉXÍ0iÃ?\ñÁáåÅõåͪi##Ñ%RÃLW%s: %s usage: cd [-l] unixdir <'RÐiQRWR]R@ @ @eRÃLWñáåõí(`iÈOíC&bÉñáÁÅåõí*ÈOíC&b!Éñáåõí+!ÈOíC&b!ÿÿÉñáÁÑÕÅåõí0bkÈOíC&bÉñÑÕõí1!ÈOíC&b!ÿÿÉñÑáÁÅåÕõí2`iÈOíC&bÉñÑáÁÅåÕõí3`iÈOíC&bÉÝåÝ!åÍŠSñÑͯi!9ͪiå!ÑÍCi|µÊ=W!å!9å*&båÍ1Sñññ!9å!9å!Rå!3RåÍ Xññññ!åÍÐ`ñ!åÍÐ`ñ ͹iÉísaR*I@͵f *D"cRùÍlWÍzTeW!åÍÐ`*-R"#R"%RÍÿWí[#RÍôW( Õ ͲW òÅÝáË!ë "#R"%RË9AÑ+r+sùÁåÝåÅÉÃßdÃdÅ~þ"(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( þ\ GÝ9Ý^ÝV!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o"&bÉñÑáÁÅåÕõ{í5`iÈOíC&bÉñáåõ}í6Éñáåõí7bkÈOíC&bÉñÑÕõíeS8!ÈOíC&b!ÿÿÉñÑáÁÅåÕõí9`iÈOíC&bÉñáåõí:!ÈOíC&b!ÿÿÉñáÁÅåõí;ÈOíC&b!Éñáåõ}í<ÉÝåÝ!Ý9ÝnÝfN#FÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfs#rÑ#Ú#¯Á> ¾Ø> ¾È#õ!C͵fÀ!%BÉõÝåýå!9å! 9Ñͯi!9åͪi##Ñͯiå!ÿÿ)Ñͪi"€X!‰a"‚X!9åͪi##Ñͯiå!ÿÿ)ÑͪiåÝá!9åÝåáåÍ YñeXñåýáýåáå!9ÍÀi!9ÍÈiáñññÉÕX0B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"†X!"„X*†Xn&|µÊR`*†Xn&%ÍCi|µÊXY*‚ÝnÝfs#rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o"&bÉñáÁÑÕÅåõí>bkÈOíC&bÉñÑÕõí?!ÈOíC&b!ÿÿÉ!eT Rå!3RåÍ Xññ!åÍÐ`ñÉöý͹i! 9ͪiå!ÑÍVi|µÊ—TÍdT!9å!Ñͯi!9ͪiå!9ͪiÍ}iÑͪiå!Ñn&å!-ÑÍ=i|µÊ(U!9ͪiå!9ͪiÍ}iÑͪiå!ÑnXå*€Xãå*†X#"†X+n&ãå͵iññ*„X#"„XÃO`!"X"›X"™X"—X"•X*†X#"†Xn&åÑ!+ÍriˆY!"•XÃjY!-ÍrišY!"—XÃjY! Íri¬Y!"™XÃjY!#Íri¾Y!"›XÃjY!0ÍriÂÐY!"XÃjY*†Xn&ÕY*Í=i|µÊ&ZñÁáåÅõåͪi##Ñͯiå!ÿÿ)Ñͪi"ŒX*ŒXëÍVi|µÊZ*ŒXÍ–i"ŒX!"—X*†X#"†XÃ^Z!"ŒX*†Xn&Ý~ÿæ?Ëq(ö@ö€Í DåÍ|bñ"&báÉñáåõ&}íKWc ¹0þ@Ðþ-.@Ð!(b…oŒ•gn&ɱb¿bÑbábòbcc Í3áÍgD!fÍgD!ÿÿåÍÓ`: BAD BLOCK X'xxxx', LEN X'xxxx' zÍDf{õÍMfñæÆ'Î@'w#ÉýååÕý!)RÕýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý!)RÕýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌ:%þIÉñÑÕõÕÕÍôfÁÑëz³È}ö &oÉñáåõ}!ö þa8ßfþ{Ø+Éñáåõ}!þ0Øþ:Ð#Éñáåõ}!þAØRÃU%s pwd: %s usage: pwd < R²gJRPRVR@ @ @^RÃUñáåõí(`iÈOíCA`ÉñáÁÅåõí*ÈOíCA`!Éñáåõí+!ÈOíCA`!ÿÿÉñáÁÑÕÅåõí0bkÈOíCA`ÉñÑÕõí1!ÈOíCA`!ÿÿÉñÑáÁÅåÕõí2`iÈOíCA`ÉñÑáÁÅåÕõí3`iÈOíCA`ÉÝåÝ!Ý9Ý^ÝVþ[Ð#ÉÍ8iͺhÊiÍìhõÍ¿hÍhñüôhÃiÍ8iͺhÊiÍ¿hõÍhñáÑÁüôhéÍ8iÅÕå!9PXå~#¶#¶#¶áÊag¯Í«hãÜ‹h¯ÍhãÃEgñññÃiÍ8iÍ‹hÃiÍ„gÂ#i+Ã#iÍ„gÚ#i+Ã#i!9###xî€G~¥g+~¹Â¥g+~ºÂ¥g+~»!ÉÍ8i{¦_#z¦W#y¦O#x¦GÃiÍ8iͺh(###Ë+Ë+Ë+ËÍêgèáÑÁé{/ßg_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉ!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o"A`ÉñÑáÁÅåÕõ{í5`iÈOíCA`Éñáåõ}í6Éñáåõí7bkÈOíCA`ÉñÑÕõí^S8!ÈOíCA`!ÿÿÉñÑáÁÅåÕõí9`iÈOíCA`Éñáåõí:!ÈOíCA`!ÿÿÉñáÁÅåõí;ÈOíCA`!Éñáåõ}í<ÉÝåÝ!Ý9ÝnÝfN#FÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfs#rÑÝnÝfsͺh!À+ÉÝåõõÝ!Ý9;å~Ýw6#~Ýw6#~Ýw6#~Ýw6.xæ€Â?hËËËË,Ã-hÝuÿÝåáÍÚhåÍsháÊShÒZhÍ…hÍôh7ãÍhÝ5ÿÊlhã¯Í«hÃHhñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍôhËhå~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õüôhÍìhòØhÍÚhÍôhÍÚhñî€ÉñÉå~s_#óßh~rW#~qO#~pGáÉå###~·áÉ{· #rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o"A`ÉñáÁÑÕÅåõí>bkÈOíCA`ÉñÑÕõí?!ÈOíCA`!ÿÿÉ!^TRå!,RåÍ%Vññ!åÍë^ñÉüüÍ›g!9ÍŒgå!ÑÍ%g|µÊTÍ]T!9å!å!9å͘SññÑÍ‘g!9ÍŒgå!ÑÍg|µÊéT!å!9å*A`åÍ*Sñññ!9å!Rå!,RåÍ%Vñññ!åÍë^ñ!9å!RåÍÄ ² ± xþ€Èå¯o›_}šW}™O}˜GáÉÍiz·ð ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#pÉ!9ÉÍ\iÈ+ÉÍ\iÀ+ÉÍ\iÐ+ÉëÍ\iØ+ÉÍ\iØ+É|î€gz {½!ÉÍriØ+Éz¼Âyi{½!ÉDM¯og>Ë#Ë0 =È)Äië¯íRÉÍ›i#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉLWcvec),hl ret dvrend equ $-1 Uññ!åÍë^ñÍ›gÉísZR*I@ÍÐd *D"\RùÍ&UÍsT!åÍë^*&R"R"R͹Uí[RÍ®U( Õ ÍlU òÅÝáË!ë "R"RË9AÑ+r+s^UùÁåÝåÅÉÃúbÃ1bÅ~þ"(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( þ\ G#Ú#¯Á> ¾Ø> ¾È#õ!CÍÐdÀ!%BÉõÝåýå!9å! 9ÑÍ‘g!9åÍŒg##ÑÍ‘gå!ÿÿ)ÑÍŒgåÝååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååá!*R"›V!¤_"V!9åÝåáåÍ%Wññåýáýåáå!9Í¢g!9ͪgáñññÉõÝåýå!9å! 9ÑÍ‘g!9åÍŒg##ÑÍ‘gå!ÿÿ)ÑÍŒg"›V!¤_"V!9åÍ?^VŒg##ÑÍ‘gå!ÿÿ)ÑÍŒgåÝá!9åÝåáåÍ%Wññåýáýåáå!9Í¢g!9ͪgáñññÉðV0B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"¡V!"ŸV*¡Vn&|µÊm^"_ñáåõÝååÝáÍb(MË^ M¯ÝwÝwÝååÝá++å##íC_~q#Ë~(ëÝnÝfåËo Í(D( Íp`!ÿÿ"_ÍfUÁÍfUá*_ÝáÉ!Ý!("A`îÝåÍ bÝá(~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáÍb(WËN(SËv OT]åÝá:JRþ*(Ë^#ÄŒgëÅyþ Ý~ÿæ 4yÍõÝ4þñë(Ë~á }Ö ÝwþÝáÉëËöËî!Ë^(wÍp`!ÿÿå yÍ(+£V"¥V!äVÍ gÍÝe|µÊÐ[!äVÍ gÅÕÍ‹eë"îV!äVÍ gÅÕÍ eÅՀͿeÍ‹e!äVÍg*£V+"£Vå*èVå!äVÍ gÅÕ*ìVÍôfÍædÅÕÍeÅÕ*îVÍôfÍIeëÑn&Ñ}!äVÍ gÅÕ*ìVÍôfÍe!äVÍgÃ2[*£Vå*¥VÑÍsgå*©VÑ"¬V*¶V|µÊ÷[*£Våð[*¥VÑÍ%g|µÊm\:«Vo&åÑ!oÍTgÂ%\*¬VëÍ8g|µÊ"\!"¬VÃm\!xÍ`Ë~ ÉÍ#` ïÂÝ4þÕÝ^þÝ~ÿæ?Ëq(ö@ö€Í DåÍ—`ñ"A`áÉñáåõ&}íKra ¹0þ@Ðþ-.@Ð!C`…oŒ•gn&ÉÌ`Ú`ì`ü` a!a8aWahaUnknown errorArg list too longNot a directoryInvalid argumentToo many*¡Vn&%Í%g|µÊsW*Vå*›Vãå*¡V#"¡V+n&ãåÍ—gññ*ŸV#"ŸVÃj^!"¸V"¶V"´V"²V"°V*¡V#"¡Vn&åÑ!+ÍTg£W!"°VÃ…W!-ÍTgµW!"²VÃ…W! ÍTgÂÇW!"´VÃ…W!#ÍTgÂÙW!"¶VÃ…W!0ÍTgÂëW!"¸VÃ…W*¡Vn&ðW*Íg|µÊAXñÁáåÅõåÍŒg##ÑÍ‘gå!ÿÿ)ÑÍŒg"§V*§VëÍ8g|µÊ7X*§VÍxg"§V!"²V*¡TgÂ7\!ùV"ºVÃm\!XÍTgÂI\!öV"ºVÃm\!bÍTgÂ[\!óV"ºVÃm\!BÍTgÂm\!ðV"ºVÃm\ÃZ]!cÍTg«\!¼Vå!9ÍŒgåÍŒg##ÑÍ‘gå!ÿÿ)ÑÍŒgÑ}!¼V"£V*£V#"¥VÃZ]!sÍTgÂ4]ñÁáåÅõåÍŒg##ÑÍ‘gå!ÿÿ)ÑÍŒg"£V*©VëÍ8g|µÊæ\!ÿ"©V!"êVÃö\*ð\êV#"êV*£V#"£V+n&|µÊ]*êVå*©VÑÍ8g|µÊ]Ãï\*£V+"£V"¥V*£V#"¡VÃyX!"§V*¡Vn&åÍÖdñ|µÊyX*§V Í_gå*¡V#"¡V+n&åÍÔ^ñÑ"§VÃGX*¡Vn&.Íg|µÊY*¡V#"¡Vn&*Íg|µÊÆXñÁáåÅõåÍŒg##ÑÍ‘gå!ÿÿ)ÑÍŒg"©V*¡V#"¡VÃþX!"©V*¡Vn&åÍÖdñ|µÊþX*©V Í_gå*¡V#"¡V+n&ðXåÍÔ^ñÑ"©VÃÌXÃY!ÿÿ"©V!"®V*¡Vn&åÑ!lÍTgÂ'Y!"®VÃ0Y!hÍTgÂ7Y*¡V#"Vå*êVÑÍsg"£VÃZ]!ÍTgÂG]*¡V+"¡VÃZ]!«V"£V"¥V*¥V#"¥VÃZ]:«Vo&|µÊj^õ!9å*§Vå*¥Vå*£VÑÍsgÑÍsgå*¬VëÍ8g|µÊ”]!Ú]*¬VÚ]ÑÍsgå*ºVåÍbñÑÍsgÑÍ‘g*²VÍ„g|µÊÞ]!9åÍŒg+ÑÍ‘gëÍ+g|µÊÞ]! åÍ^ñú]*ºVn&|µÊü]*ºV#"ºVð]+n&åÍ^ñÃÞ]*¬V+"¬VëÍ+g|µÊ^!0åÍ^ñÃü]*£Vå*¥V¡V!"¬V!$W"ºV*¡V#"¡V+n&}2«VåÑ!dÍTgÂ`YÃiY!uÍTgÂrY!"ìVýY!oÍTg„Y!"ìVýY!XÍTgÂYÙY!xÍTg¢Y!"ìVýY!BÍTg®Y÷Y!bÍTgÂp\!"ìV*©VëÍ8g|µÊÒY!"©V*®V|µÊZñÁáåÅõåÍŒgÑÍ‘gå!ÿÿðY))ÑÍ g!äVÍgÃZZ:«Vo&dÍg|µÊ7ZñÁáåÅõåÍŒg##ÑÍ‘gå!ÿÿ)ÑÍŒgÍôf!äVÑÍNg|µÊ=^*£V#"£V+n&åÍ^ñÃ^*²V|µÊi^!9åÍŒg+ÑÍ‘gëÍ+g|µÊi^! åÍ^ñÃE^ñÃ2W*›V|µÊ}^*›VåÍ…_ñ|µÊˆ^!ÿÿÃŽ^*ŸVÃŽ^É*Vå*›Vãå!9n&ãåÍ—gññ*ŸV#"ŸVÉñáåõå!9ÍŒgÑÍ8g|µÊÊ^ñáåõÃÓ^ñÁáåÅõÃÓ^É!9n&0·íRÉñáåõ0ÉÍú^ñá(ð^åõ|µÊ-@Ã0@!(RA^#V#{²( ÅåëË^Ì9_áÁìÉ_!ÿÿÍgÃZZñÁáåÅõåÍŒg##ÑÍ‘gå!ÿÿ)ÑÍŒgÍüf!äVÍg:«Vo&dÍg|µÊÎZ!äVÍ gÅÕÍ\e|µÊ¯Z!"W"ºV!äVÍ gÅÕ€ÍRe|µÊ¬Z!äVÍ gÍÖf!äVÍgÃÎZ*°V|µÊÀZ! W"ºVÃÎZ*´V|µÊÎZ!W"ºV*¸V|µÊ[õ!9å*§Vå*ºVåÍbñÑÍsgÑÍ‘gðZáåå*©VÑÍ1g|µÊ[áå"©Vñ:«Vo&XÍg|µÊ[! WÃ"[!üVÃ"["èV!¼V("cÝ!üÿÝͨdý! R ý"øbýnýfåýáý^ýVz³(ÝåáíR0âÍÈcÝåÁýqýpýå! RÑ·íR('ýnýf·íB ÍÕcýuýtÝnÝfýuýtýåÝáý"øbÝNÝFÅýáx±(ÝåáÝ^ÝV·íB ÍÕcÝuÝtÍÈcý*øbÝåáÝ^ÝVíKR¯íBÀýwýwÝ"RÉýnýfÝuÝtÉýnýfÝ^ÝVÉFREEÝåÅÕåë+F+N++ÍýcáÑÁúcÝáÉëÝ!"RÝnÝf|µ(åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååÝáíRÈ8îñ!GdÍZdYP!TdÍZd> Í3áÍgD!9dÍgD!ÿÿåÍî^: BAD BLOCK X'xxxx', LEN X'xxxx' zÍ_d{õÍhdñæÆ'Î@'w#ÉýååÕý!"RÕýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý!"RÕýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌ:%þIÉñáåõ}!þ0Øþ:Ð#ÉÍgÍœfÊgÍÎfõÍ¡fÍæeñúdüÖfÃgÍgÍœfÊåååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååågÍ¡fõÍæeñáÑÁüÖféÍgÅÕå!9PXå~#¶#¶#¶áÊCe¯ÍfãÜmf¯ÍfãÃ'eñññÃgÍgÍmfÃgÍfeÂg+ÃgÍfeÚg+Ãg!9###xî€G~‡e+~¹Â‡e+~ºÂ‡e+~»!ÉÍg{¦_#z¦W#y¦O#x¦GÃgÍgÍœf(###Ë+Ë+Ë+ËÍÌeèáÑÁé{/_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍœf!À+ÉÝåõõÝ!Ý9;å~Ýw6#~úeÝw6#~Ýwåååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå open filesNot a character deviceMath arg ouìCat of domain of funcResult too largeI/O errorHñÑÕõ{þ@8Ö@o&þ 8l)º`ÃŒgöÀõ!|DÍÐd !‹B"ÇaT]ÍŒg"Äa!¶aÍ‘gñÍ D!ÌaÉÌa~#Ö ø!ÑgñáÑÝá6#~Ýw6.xæ€Â!fËËËË,ÃfÝuÿÝåáͼfåÍUfáÊ5fÒgÈ+ÉÍ>gÀ+ÉÍ>gÐ+ÉëÍ>gØ+ÉÍ>gØ+É|î€gz {½!ÉÍTgØ+Éz¼Â[g{½!ÉDM¯og>Ë#Ë0 =È)Ãfgë¯íRÉÍ}g#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉUO#x¦GÃiÍ8iͺh(###Ë+Ë+Ë+ËÍêgèáÑÁé{/ßg_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉ9åÍkjÑÍpjÿÿn&Ñ}ÃÇV!9åÍkjÑÍpjÿÿå! Ñ}ÃqU!9Íkjå!Ñ}!9å!9åÍ•RñÑÍpj!9Íkjå!ÍWjÑÍìi|µÊŽW!å!9å*ÕbåÍ^Sñññ!9å!,Rå!`Rå͹Xñññ!åÍañÃìW!9’WÍkjå!ÑÍòi|µÊìW!å!9å*ÕbåÍ^Sñññ!9Íkjå!ÿÑÍEjå! 9Íkjå!ÑÍLjå!Rå!`Rå͹Xññññ!åÁÅåÕõí2`iÈOíCÕbÉñÑáÁÅåÕõí3`iÈOíCÕbÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o"ÕbÉñÑáÁÅåÕõ{í5`iÈOíCÕbÉñáåõ}í6Éñáåõí7bkÈOíCÕbÉñÑÕõí’S8!ÈOíCÕb!ÿÿÉñÑáÁÅåÕõí9`iÈOíCÕbÉñáåõí:!ÈOíCÕb!ÿÿÉñáÁÅåõí;ÈOíCÕb!Éñáåõ}í<ÉÝåÝ!Ý9ÝnÝfN#Íañ!åÍañ ÍzjÉísŽR*I@Ídg *D"RùÍXͧT!åÍa*ZR"PR"RRÍ®Xí[PRÍ£X( Õ ÍaX òÅÝáË!ë "PR"RRË9AÑ+r+sùÁåÝåÅÉÃŽeÃÅdÅ~þ"(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( Ÿ’Xþ\ G#Ú#¯Á> ¾Ø> ¾È#õ!CÍdgÀ!%BÉõÝåýå!9å! 9ÑÍpj!9åÍkj##ÑÍpjå!ÿÿ)ÑÍkj"FÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfs#rÑÝnÝfs#rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o"ÕbÉñáÁÑÕÅåõí>bkÈOíCÕbÉñÑÕõí?!ÈOíCÕb!ÿÿÉ!’T6Rå!`Rå͹Xññ!åÍañÉöüÍzj! 9Íkjå!ÑÍj|µÊÄTÍ‘T!9å!ÑÍpj!9Íkjå!9ÍkjÍ,jÑÍkjå!Ñn&å/Y!8b"1Y!9åÍkj##ÑÍpjå!ÿÿ)ÑÍkjåÝá!9åÝåáå͹Yññåýáýåáå!9Íj!9͉jáñññÉ„Y0B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"5Y!"3Y*5Yn&|µÊa*5Yn&%Íòi|µÊZ*1Yå*/Yãå*5Y#"5Y+n&ãåÍvjññ*3Y#"3YÃþ`!"LY"JY"HY"FY"DY*5Y#"5Yn&åÑ!+Í!jÂ7Z!"DYÃ!-ÑÍìi|µÊUU!9Íkjå!9ÍkjÍ,jÑÍkjå!Ñn&åÍjgñå!lÑÍòi|µÊ8UÍ‘T!9åÍkj#ÑÍpj+!9å!ÑÍpjÃaU!9å!ÑÍpj!9å!9ÑÍpjÃU!9åÍkj#ÑÍpj+!9Íkjå!9ÍkjÑÍj’U|µÊ&W!9å!9Íkjå! 9ÍkjÍ,jÑÍkjÑÍpj!9Íkj|µÊÇV!9Íkjn&|µÊÄV!9Íkjn&å![ÑÍìi|µÊüU!9Z!-Í!jÂIZ!"FYÃZ! Í!jÂ[Z!"HYÃZ!#Í!jÂmZ!"JYÃZ!0Í!jÂZ!"LYÃZ*5Yn&„Z*Íìi|µÊÕZñÁáåÅõåÍkj##ÑÍpjå!ÿÿ)ÑÍkj";Y*;YëÍj|µÊËZ*;YÍWj";Y!"FY*5Y#"5Yà [!";Y*5Yn&åÍ“gñ|µÊ [*;Y Í,jå*5Y#"5Y+n&åÍhañÑ";YÃÛZ*5Yn&.Íìi|µÊ•[*5Y#"5Yn&*Íìi|µÊÍkjå!Ñn&|µÊGV!9åÍkjÑÍpjÿÿ!9åÍkjÑÍpjÿÿå!9åÍkjÑÍpjÿÿn&Ñ}ÃÁV!9Íkjn&åÍ€gñ|µÊ’V!9åÍkjÑÍpjÿÿå!9åÍkjÑÍpjÿÿn&åÍjgñÑ}ÃÁV’V!9åÍkjÑÍpjÿÿå!9åÍkjÑÍpjÿÿn&Ñ}ÃÆUÃW!9Íkjn&|µÊW!9åÍkjÑÍpjÿÿå!Z[ñÁáåÅõåÍkj##ÑÍpjå!ÿÿ)ÑÍkj"=Y*5Y#"5YÃ’[!"=Y*5Yn&åÍ“gñ|µÊ’[*=Y Í,jå*5Y#"5Y+n&„[åÍhañÑ"=YÃ`[Û[!ÿÿ"=Y!"BY*5Yn&åÑ!lÍ!j»[!"BYÃÄ[!hÍ!jÂË[*5Y#"5Y!"@Y!¸Y"NY*5Y#"5Y+n&}2?YåÑ!dÍ!jÂô[Ãý[!uÍ!jÂ\!"€YÃQ\!oÍ!jÂ\!"€YÃQ\!XÍ!jÂ$\Ã-\!xÍ!jÂ6\RRÃûWunix: error (exit status %d, signal %d) unix: %s usage: unix [-l] command ?Ëq(ö@ö€Í DåÍ+cñ"ÕbáÉñáåõ&}íKd ¹0þ@Ðþ-.@Ð!×b…oŒ•gn&É`cnc€cc¡cµcÌcëcücUnknown errorArg list too longNot a directoryInvalid argumentToo many open filesNot a character deviceMath arg ouì×ct of domain of funcResult too largeI/O errorHñjå!ÿÿ)ÑÍkjÑ}!PY"7Y*7Y#"9YÃî_!sÍ!jÂÈ_ñÁáåÅõåÍkj##ÑÍpjå!ÿÿ)ÑÍkj"7Y*=YëÍj|µÊz_!ÿ"=Y!"~YÊ_*„_~Y#"~Y*7Y#"7Y+n&|µÊ¥_*~Yå*=YÑÍj|µÊ­_Ã_*7Y+"7Y"9Y*7Yå*~YÑÍ@j"7YÃî_!Í!jÂÛ_*5Y+"5YÃî_!?Y"7Y"9Y*9Y#"9YÃî_:?Yo&|µÊþ`õ!9å*;Yå*9Yå*7YÑÍ@jÑÍ@jå*@YëÍjÑÕõ{þ@8Ö@o&þ 8l)NcÃkjöÀõ!|DÍdg !‹B"[dT]Íkj"Xd!JdÍpjñÍ D!`dÉ`d~#Ö ø!ÃpjñáÑÝáÝåÕåõÝnÝf|µÉñÑÕõ!·È#ùÉÅdñÑÕõÝåýå!"Ádý!TR*TRý"ÃdÝåýáÝnÝfåÝá|µ(7ÝnÝfí[Ád·íR8ÜíB0ÝÿÉñáÁÅåõí;ÈOíCÁd!Éñáåõ}í<ÉÝåÝ!Ý9ÝnÝfN#FÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfs#rÑÝnÝfs#rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o"ÁdÉñáÁÑÕÅåõí>bkÈOíCÁdÉñÑÕõí?!ÈOíCÁd!ÿÿÉ!ÀT\Rå!ŽRåÍ Zññ!åÍkcñÉê÷Ídl!9ÍUlå!ÑÍl|µÊòTÍ¿T!áÊiÒ iÍ4iÍ£i7ãÍLiÝ5ÿÊiã¯ÍZiÃ÷hñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍ£iÃ:iå~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õü£iÍ›iò‡i͉iÍ£i͉iñî€ÉñÉå~s_#Ži~rW#~qO#~pGáÉå###~·áÉ{· ² ± xþ€Èå¯o›_}šW}™O}˜GáÉÍÉiz·ð ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#pÉ!9ÉÍ jÈ+ÉÍ jÀ+9å!ÑÍZl!9ÍUlå!9ÍUlÍ(lÑÍUlå!Ñn&å!-ÑÍèk|µÊƒU!9ÍUlå!9ÍUlÍ(lÑÍUlå!Ñn&åÍfiñå!lÑÍîk|µÊfUÍ¿T!9åÍUl#ÑÍZl+!9å!ÑÍZlÃU!9å!ÑÍZl!9ÍUlå!9ÍUlÑÍË#Ë0 =È)Ã3jë¯íRÉ}£o|¢gÉëz³ÈË<ËöÍ\j#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåŽjýáÉûWiy+8),27h ld (iy+9),38 ;Directory cylinder (guess) ld hl,0 ;Successful coå!9åÍÔRññÑÍZl!9ÍUlå!ÑÍèk|µÊAV!å!9å*ÁdåÍŒSñññ!9å!KRå!ŽRåÍ Zñññ!åÍkcñ! 9å!9å!9å!åÍTññññ!9ÍUlå!ÑÍèk|µÊ€V!HRå!9åÍŸfññ×V!9ÍUlå!ERå!9åÍ‚Zñññ!9ÍUlå!9ÍUlå!ÑÍ(lÑÍUlå!9å!ÀV9å!8Rå!9åÍ‚Zñññññ!9å!/Rå!9åÍ‚Zñññ! 9åtýåÝáý"ŒeÝNÝFÅýáx±(ÝåáÝ^ÝV·íB ÍifÝuÝtÍ\fý*ŒeÝåáÝ^ÝVíKPR¯íBÀýwýwÝ"PRÉýnýfÝuÝtÉýnýfÝ^ÝVÉFREEÝåÅÕåë+F+N++Í‘fáÑÁŽfÝáÉëÝ!VRÝnÝf|µ(åÝáíRÈ8îñ!ÛfÍîfYP!èfÍîf> Í3áÍgD!ÍfÍgD!ÿÿåÍ‚a: BAD BLOCK X'xxxx', LEN X'xxxx' zÍóf{õÍüfñæÆ'Î@€RÃLYemt_system: %s ln -s %s %semt_system: %s rm -f %s%s/disk%s-%s%d4pemt_getddir: %s usage: mount [-l] file.dsk unit# <‚R{l¬R²R¸R@ @ @ÀRÃLYñáåõí(`iÈOíCÁdÉñáÁÅåõí*ÈOíCÁd!Éñáåõí+!ÈOíCÁd!ÿÿ'w#ÉýååÕý!VRÕýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý!VRÕýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌ:%þIÉñÑÕõÕÕÍ£gÁÑëz³È}ö &oÉñáåõ}!ö þa8Žgþ{Ø+Éñáåõ}!þ0Øþ:Ð#Éñáåõ}!þAØþ[Ð#ÉÍçiÍiiÊÎiÍ›iõÍniͳhñü£iÃÎiÍçiÍiiÊÎiÍniõͳhñáÑÁü£iéÍçiÅÕå!9PXå~#¶#¶#¶áÊÉñáÁÑÕÅåõí0bkÈOíCÁdÉñÑÕõí1!ÈOíCÁd!ÿÿÉñÑáÁÅåÕõí2`iÈOíCÁdÉñÑáÁÅåÕõí3`iÈOíCÁdÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o"ÁdÉñÑáÁÅåÕõ{í5`iÈOíCÁdÉñáåõ}í6Éñáåõí7bkÈOíCÁdÉñÑÕõíÀS8!ÈOíCÁd!ÿÿÉñÑáÁÅåÕõí9`iÈOíCÁdÉñáåõí:!ÈOíCÁd!ÿh¯ÍZiãÜ:i¯ÍLiãÃôgñññÃÎiÍçiÍ:iÃÎiÍ3hÂÒi+ÃÒiÍ3hÚÒi+ÃÒi!9###xî€G~ÂTh+~¹ÂTh+~ºÂTh+~»!ÉÍçi{¦_#z¦W#y¦O#x¦GÃÎiÍçiÍii(###Ë+Ë+Ë+ËÍ™hèáÑÁé{/Žh_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍii!À+ÉÝåõõÝ!Ý9;å~Ýw6#~Ýw6#~Ýw6#~Ýw6.xæ€ÂîhËËËË,ÃÜhÝuÿÝåá͉iåÍ"iÍZlÿÿn&Ñ}ÃrX!9ÍUln&åÍ|iñ|µÊCX!9åÍUlÑÍZlÿÿå!9åÍUlÑÍZlÿÿn&åÍfiñÑ}ÃrX!9åÍUlÑÍZlÿÿå!9åÍUlÑÍZlÿÿn&Ñ}ÃwWùX!9ÍUln&|µÊ¹X!9åÍUlÑÍZlÿÿå!9åÍUlÑÍZlÿÿn&Ñ}ÃxX!9ÍUlÀXå!Ñ}!9å!9å!Rå!9åÍ‚Zññññ! ÑÍZlå!ÿÿ)ÑÍUl")[*![#"![Ã~]!")[*![n&åÍiñ|µÊ~]*)[ Í(lå*![#"![+n&p]åÍTcñÑ")[ÃL]Ç]!ÿÿ")[!".[*![n&åÑ!lÍl§]!".[ð]!hÍl·]*![#"![!",[!¤[":[*![#"![+n&}2+[åÑ!dÍlÂà]Ãé]!uÍlÂò]!"l[Ã=^!oÍlÂ^!"l[Ã=^!XÍlÂ^Ã^!xÍlÂ"^!"l[Ã=^!BÍ9å!9åÍÃRñÑÍZl! 9ÍUlå!ÑÍîk|µÊ5Y!å!9å*ÁdåÍŒSñññ!9å!Rå!ŽRåÍ Zñññ!åÍkcñ!åÍTñ!åÍkcñÍdlÉís¼R*I@Í`i *D"¾RùÍlYÍÕT!åÍkc*ˆR"~R"€RÍÿYí[~RÍôY( Õ ͲY òÅÝáË!ë "~R"€RË9AÑ+r+sùÁåÝåÅÉÊgÃÁfÅ~þ"(þ' #OÂÀYx·(y~þ 8"þ!0 ( ( lÂ.^Ã7^!bÍlÂð`!"l[*)[ëÍl|µÊR^!")[*.[|µÊ€^ñÁáåÅõåÍUlÑÍZlå!ÿÿp^))ÑÍÓk!d[ÍÛkÃÚ^:+[o&dÍèk|µÊ·^ñÁáåÅõåÍUl##ÑÍZlå!ÿÿ)ÑÍUlͽk!d[ÍÛkÃÚ^ñÁáåÅõåÍUl##ÑÍZlå!ÿÿ)ÑÍUlÍÅk!d[ÍÛk:+[o&dÍèk|µÊN_!d[ÍÓkÅÕÍ%j|µÊ/_!¢[":[!d[ÍÓkÅÕ€Íj|µÊ,_!d[ÍÓk¹( þ\ G#Ú#¯Á> ¾Ø> ¾È#õ!CÍ`iÀ!%BÉõÝåýå!9å! 9ÑÍZl!9åÍUl##ÑÍZlå!ÿÿ)ÑÍUl"[!$d"[!9åÍUl##ÑÍZlå!ÿÿ)ÑÍUlåÝá!9åÝåáåÍ¥[ññåýáýåáå!9Íkl!9ÍsláñññÉ›‚ZõÝåýå!9å! 9ÑÍZl!9åÍUl##ÑÍZlå!ÿÿ)ÑÍUl"€Z!9åÍUl##ÑÍZlå!ÿÿ)ÑÍUlåÝá!"[!["[!9åÝåáÍŸk!d[ÍÛkÃN_*0[|µÊ@_! [":[ÃN_*4[|µÊN_!ž[":[*8[|µÊ…_õ!9å*'[å*:[åͯfñÑÍ Í3áÍgD!ÉhÍgD!ÿÿåÍnc: BAD BLOCK X'xxxx', LEN X'xxxx' zÍïh{õÍøhñæÆ'~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáÍ–f(WËN(SËv OT]åÝá:¬Rþ*(Ë^#ÄUlëÅyþ Ý~ÿæ 4yÍõÝ4þñë(Ë~á }Ö ÝwþÝáÉëËöËî!Ë^(wÍðd!ÿÿå yÍ(+˜dË~ ÉÍ£d ïÂÝ4þÕÝ^þÝ~ÿæ?Ëq(öÎ@'w#ÉýååÕý!„RÕýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý!„RÕýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌ:%þIÉñÑÕõÕÕÍŸiÁÑëz³È}ö &oÉñáåõ}!ö þa8Šiþ{Ø+Éñáåõ}!þ0Øþ:Ð#Éñáåõ}!þAØþ[Ð#ÉÍãkÍekÊÊkÍ—kõÍjkͯjñüŸkÃÊkÍãkÍekÊÊkÍjkõͯjñáÑÁüŸkéÍãkÅÕå!9PXå~#¶#¶#¶á@ö€Í DåÍeñ"ÁdáÉñáåõ&}íKòe ¹0þ@Ðþ-.@Ð!Ãd…oŒ•gn&ÉLeZele|ee¡e¸e×eèeUnknown errorArg list too longNot a directoryInvalid argumentToo many open filesNot a character deviceMath arg ouüÃet of domain of funcResult too largeI/O errorHñÑÕõ{þ@8Ö@o&þååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååT!9å!å!9åÍ«RññÑÍ*i!9Í%iå!Ñ͸h|µÊNU!å!9å*ÊaåÍcSñññ!9å!/Rå!eRåÍWñññ!åÍt`ñ!9å!9å! 9å!åÍíSññññ!9Í%iå!Ñ͸h|µÊU!,Rå! 9åͨcññäU!9Í%iå!)—URå!9åÍ‹Wñññ!9Í%iå!ÍøhÑÍ%iå! 9å!9å!Rå!9åÍ‹Wñññññ!9å!Rå!9åÍ‹Wñññ!9å!åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå9åÍšRñÑÍ*i!9Í%iå!Ñ;h|µÊ>V!å!9å*ÊaåÍcSñññ!9å!Rå!eRåÍWñññ!åÍt`ñ!åÍåSñ!åÍt`ñÍ4iÉís“R*I@Íif *D"•RùÍuVͬT!åÍt`*_R"UR"WRÍWí[URÍýV( Õ Í»V òô—VÅÝáË!ë "UR"WRË9AÑ+r+sùÁåÝåÅÉÓdÃÊcÅ~þ"(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( káÊþjÒkÍ0kÍŸk7ãÍHkÝ5ÿÊkã¯ÍVkÃójñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍŸkÃ6kå~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õüŸkÍ—kòƒkÍ…kÍŸkÍ…kñî€ÉñÉå~s_#óŠk~rW#~qO#~pGáÉå###~·áÉ{· ² ± xþ€Èå¯o›_}šW}™O}˜GáÉÍÅkz·ð ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#pÉ!9ÉÍlÈ+ÉÍlWRÃUVemt_system: %s rm -f %s%s/disk%s-%s%d4pemt_getddir: %s usage: umount unit# Ë#Ë0 =È)Ã/lë¯íRÉÍFl#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉLY last byte of driver. ;*=*=* relo: ld hl,(newend) ld iy,reltab ;Point to relocation tbl ld de,dvÿÉñÑáÁÅåÕõí2`iÈOíCÊaÉñÑáÁÅåÕõí3`iÈOíCÊaÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o"ÊaÉñÑáÁÅåÕõ{í5`iÈOíCÊaÉñáåõ}í6Éñáåõí7bkÈOíCÊaÉñÑÕõí—S8!ÈOíCÊa!ÿÿÉñÑáÁÅåÕõí9`iÈOíCÊaÉñáåõí:!ÈOíCÊa!ÿÿÉñáÁÅåõí;ÈOíCÊa!Éñáåõ}í<ÉÝåÝ!Ý9ÝnååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååÝfN#FÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfs#rÑÝnÝfs#rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o"ÊaÉñáÁÑÕÅåõí>bkÈOíCÊaÉñÑÕõí?!ÈOíCÊa!ÿÿÉ!—T@Rå!eRåÍWññ!åÍt`ñÉòøÍ4i!9Í%iå!Ñ;h|µÂíT!9Í%iå!ÍøhÑÍ%iå!Ñn&åÍofñÍi|µÊõTÍ–ÅÕ*wXÍhÍâfëÑn&Ñ}!mXÍ£hÅÕ*uXÍhÍ™f!mXÍ«hû\*,Xå*.XÑÍ iå*2XÑ"5X*?X|µÊ€]*,Xåy]*.XÑ;h|µÊö]:4Xo&åÑ!oÍíh®]*5XëÍÑh|µÊ«]!"5XÃö]!xÍíhÂÀ]!‚X"CXÃö]!XÍíhÂÒ]!X"CXÃö]!bÍíhÂä]!|X"CXÃö]!BÍíhÂö]!yX"CXÃö]Ãã^!cÍíhÂ4^!EXå!9Í%iåÍ%i##ÑÍ*iå!ÿÿ)ÑÍ%iÑ}!EXÃY! ÍíhÂPY!"=XÃY!#ÍíhÂbY!"?XÃY!0ÍíhÂtY!"AXÃY**Xn&yY*͸h|µÊÊYñÁáåÅõåÍ%i##ÑÍ*iå!ÿÿ)ÑÍ%i"0X*0XëÍÑh|µÊÀY*0XÍi"0X!";X**X#"*XÃZ!"0X**Xn&åÍofñ|µÊZ*0X Íøhå**X#"*X+n&åÍ]`ñÑ"0XÃÐY**Xn&.͸h|µÊŠZ**X#"*Xn&*͸h|µÊOZñÁáåÅõåÍ%i##ÑÍ*",X*,X#".XÃã^!sÍíh½^ñÁáåÅõåÍ%i##ÑÍ*iå!ÿÿ)ÑÍ%i",X*2XëÍÑh|µÊo^!ÿ"2X!"sXÃ^*y^sX#"sX*,X#",X+n&|µÊš^*sXå*2XÑÍÑh|µÊ¢^Ãx^*,X+",X".X*,Xå*sXÑÍ i",XÃã^!ÍíhÂÐ^**X+"*XÃã^!4X",X".X*.X#".XÃã^:4Xo&|µÊó_õ!9å*0Xå*.Xå*,XÑÍ iÑÍ iå*5XëÍÑh|µÊ_!Ã#_*5XÃ#_iå!ÿÿ)ÑÍ%i"2X**X#"*XÇZ!"2X**Xn&åÍofñ|µÊ‡Z*2X Íøhå**X#"*X+n&yZåÍ]`ñÑ"2XÃUZÃZ!ÿÿ"2X!"7X**Xn&åÑ!lÍíh°Z!"7XùZ!hÍíhÂÀZ**X#"*X!"5X!­X"CX**X#"*X+n&}24XåÑ!dÍíhÂéZÃòZ!uÍíhÂûZ!"uXÃF[!oÍíh [!"uXÃF[!XÍíhÂ[Ã"[!xÍíhÂ+[!"uXÃF[!BÍíhÂ7ÑÍ iå*CXå͸cñÑÍ iÑÍ*i*;XÍi|µÊg_!9åÍ%i+ÑÍ*iëÍÄh|µÊg_! åÍ`ñÃC_*CXn&|µÊ…_*CX#"CXy_+n&åÍ`ñÃg_*5X+"5XëÍÄh|µÊ£_!0åÍ`ñÃ…_*,Xå*.XÑÍçh|µÊÆ_*,X#",X+n&åÍ`ñã_*;X|µÊò_!9åÍ%i+ÑÍ*iëÍÄh|µÊò_! åÍ`ñÃÎ_ñûX*$X|µÊ`*$XåÍañ|µÊ`!ÿÿÃ`*(XÃ`É*&Xå*$X[Ã@[!bÍíhÂù]!"uX*2XëÍÑh|µÊ[[!"2X*7X|µÊ‰[ñÁáåÅõåÍ%iÑÍ*iå!ÿÿy[))ÑÍ£h!mXÍ«hÃã[:4Xo&d͸h|µÊÀ[ñÁáåÅõåÍ%i##ÑÍ*iå!ÿÿ)ÑÍ%iÍh!mXÍ«hÃã[ñÁáåÅõåÍ%i##ÑÍ*iå!ÿÿ)ÑÍ%iÍ•h!mXÍ«h:4Xo&d͸h|µÊW\!mXÍ£hÅÕÍõf|µÊ8\!«X"CX!mXÍ£hÅÕ€Íëf|µÊ5\!mXÍ£hÍohãå!9n&ãåÍ0iññ*(X#"(XÉñáåõå!9Í%iÑÍÑh|µÊS`ñáåõÃ\`ñÁáåÅõÃ\`É!9n&0·íRÉñáåõ0É̓`ñá(y`åõ|µÊ-@Ã0@!aRA^#V#{²( ÅåëË^ÌÂ`áÁìÉ¡`!ÿÿ"Ÿ`ñáåõÝååÝáÍŸc(MË^ M¯ÝwÝwÝååÝá++å##íCŸ`~q#Ë~(ëÝnÝfåËo Í(D( Íùa!ÿÿ"Ÿ`͵VÁ͵Vá*Ÿ`ÝáÉ!Ý!("ÊaîÝåÍ•cÝá(~æþ\ G#Ú#¯Á> ¾Ø> ¾È#õ!CÍifÀ!%BÉõÝåýå!9å! 9ÑÍ*i!9åÍ%i##ÑÍ*iå!ÿÿ)ÑÍ%i"$X!-a"&X!9åÍ%i##ÑÍ*iå!ÿÿ)ÑÍ%iåÝá!9åÝåáåÍ®Xññåýáýåáå!9Í;i!9ÍCiáñññÉ›‹WõÝåýå!9å! 9ÑÍ*i!9åÍ%i##ÑÍ*iå!ÿÿ)ÑÍ%i"‰W!9åÍ%i##ÑÍ*iå!ÿÿ)ÑÍ%iåÝá!"$X!X"&X!9åÝåáåÍ®!mXÍ«hÃW\*9X|µÊI\!©X"CXÃW\*=X|µÊW\!§X"CX*AX|µÊŽ\õ!9å*0Xå*CXå͸cñÑÍ iÑÍ*iy\áåå*2XÑÍÊh|µÊ\áå"2Xñ:4Xo&X͸h|µÊ¥\!–Xë\!…Xë\"qX!EX(",X".X!mXÍ£hÍvg|µÊY]!mXÍ£hÅÕÍ$gë"wX!mXÍ£hÅÕÍ9gÅÕ€ÍXgÍ$g!mXÍ«h*,X+",Xå*qXå!mXÍ£hÅÕ*uXÍhÍfÅÕͱfXññåýá*‰Wë}ýåáå!9Í;i!9ÍCiáñññÉ*‰W#"‰W+å!9n&Ñ}ÉyX0B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"*X!"(X**Xn&|µÊö_**Xn&%;h|µÊüX*&Xå*$Xãå**X#"*X+n&ãåÍ0iññ*(X#"(XÃó_!"AX"?X"=X";X"9X**X#"*Xn&åÑ!+ÍíhÂ,Y!"9XÃY!-ÍíhÂ>Y!";X (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáÍŸc(WËN(SËv OT]åÝá:ƒRþ*(Ë^#Ä%iëÅyþ Ý~ÿæ 4yÍõÝ4þñë(Ë~á }Ö ÝwþÝáÉëËöËî!Ë^(wÍùa!ÿÿå yÍ(+¡aË~ Éͬa ïÂÝ4þÕÝ^þÝ~ÿæ?Ëq(ö@ö€w#ÉýååÕý![RÕýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý![RÕýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌ:%þIÉñáåõ}!þ0Øþ:Ð#ÉͳhÍ5hÊšhÍghõÍ:hÍgñ“füohÚhͳhÍ5hÊšhÍ:hõÍgñáÑÁüohéͳhÅÕå!9PXå~#¶#¶#¶áÊÜf¯Í&hãÜh¯ÍhãÃÀfñññÚhͳhÍhÚhÍÿfžh+ÞhÍÿfÚžh+Þh!9##Í DåÍ bñ"ÊaáÉñáåõ&}íKûb ¹0þ@Ðþ-.@Ð!Ìa…oŒ•gn&ÉUbcbub…b–bªbÁbàbñbUnknown errorArg list too longNot a directoryInvalid argumentToo many open filesNot a character deviceMath arg ouüÌbt of domain of funcResult too largeI/O errorHñÑÕõ{þ@8Ö@o&þ 8#xî€G~ g+~¹Â g+~ºÂ g+~»!Éͳh{¦_#z¦W#y¦O#x¦GÚhͳhÍ5h(###Ë+Ë+Ë+ËÍegèáÑÁé{/_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍ5h!À+ÉÝåõõÝ!Ý9;å~Ýw6#~“gÝw6#~Ýw6#~Ýw6.xæ€ÂºgËËËË,ègÝuÿÝåáÍUhåÍîgáÊÎgÒÕgÍhÍoh7ãÍhÝ5ÿÊçgã¯Í&hÃÃgñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍl)CbÃ%iöÀõ!|DÍif !‹B"PcT]Í%i"Mc!?cÍ*iñÍ D!UcÉUc~#Ö ø!Ã*iñáÑÝáÝåÕåõÝnÝf|µÉñÑÁÅÕõbk ·ÈøñÑÕõ!·È#ùÉÊcñÑÕõÝåýå!"Æcý!YR*YRý"ÈcÝåýáÝnÝfåÝá|µ(7ÝnÝfí[Æc·íR8ÜíB0ÝnohÃhå~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õüohÍghòShÍUhÍohÍUhñî€ÉñÉå~s_#~rW#~qO#~pGáÉå###~·áÉ{· ² ± xþ€Èå¯o›_}šW}™O}˜GáÉÍ•hz·ðº“h ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#pÉ!9ÉÍ×hÈ+ÉÍ×hÀ+ÉÍ×hÐ+ÉëÍ×hØ+ÉÍ×hØ+É|î€gz {½!ÉÍíhØ+Éz¼Âôh{½!ÉDM¯ogÝfýuýt ÝuÝtDMÝ ÝsÝr*ÆcåÍ^dÁ|¥< !#"ÊaåÝáÝqÝpÝåÍ fágoýáÝáÉñÑÕõz³('!9íBíKURíB8 íR8Åë "URáÉ!#"Êa!ÿÿÉ*URÉ“dñÑÕõÝåýåÍ£dýáÝáÉ!|eÍeÝ!üÿÝÍAfý!YR ý"‘dýnýfåýáý^ýVz³(ÝåáíR0âÍaeÝåÁýqýpýå!YRÑ·íR('ýnýf·íB ÍneýuýtÝnÝfýuýt>Ë#Ë0 =È)Ãÿhë¯íRÉÍi#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉUVÝåáíR8Ý êÝnÝfÌ:%þIÉñÑÕõÕÕÍŸiÁÑëz³È}ö &oÉñáåõ}!ö þa8Šiþ{Ø+Éñáåõ}!þ0Øþ:Ð#Éñáåõ}!þAØþ[Ð#ÉÍãkÍekÊÊkÍ—kõÍjkͯjñüŸkÃÊkÍãkÍekÊÊkÍjkõͯjñáÑÁüŸkéÍãkÅÕå!9PXå~#¶#¶#¶áýåÝáý"‘dÝNÝFÅýáx±(ÝåáÝ^ÝV·íB ÍneÝuÝtÍaeý*‘dÝåáÝ^ÝVíKUR¯íBÀýwýwÝ"URÉýnýfÝuÝtÉýnýfÝ^ÝVÉFREEÝåÅÕåë+F+N++Í–eáÑÁ“eÝáÉëÝ![RÝnÝf|µ(åÝáíRÈ8îñ!àeÍóeYP!íeÍóe> Í3áÍgD!ÒeÍgD!ÿÿåÍw`: BAD BLOCK X'xxxx', LEN X'xxxx' zÍøe{õÍfñæÆ'Î@'ååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååZ!BÍŽiÂBZÃKZ!bÍŽiÂ]!"€W*=WëÍri|µÊfZ!"=W*BW|µÊ”ZñÁáåÅõåÍÆiÑÍËiå!ÿÿ„Z))ÑÍDi!xWÍLiÃîZ:?Wo&dÍYi|µÊËZñÁáåÅõåÍÆi##ÑÍËiå!ÿÿ)ÑÍÆiÍ.i!xWÍLiÃîZñÁáåÅõåÍÆi##ÑÍËiå!ÿÿ)ÑÍÆiÍ6i!xWÍLi:?Wo&dÍYi|µÊb[!xWÍDiÅÕÍ–g|µÊC[!¶W"NW!xWÍDiÅՀ͌g|µÊ@[+sùÁåÝåÅÉÃúdÃ1dÅ~þ"(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( þ\ G#Ú#¯Á> ¾Ø> ¾È#õ!CÍÐfÀ!%BÉõÝåýå!9å! 9ÑÍËÈiVi!9åÍÆi##ÑÍËiå!ÿÿ)ÑÍÆiåÝá!5R"/W!8`"1W!9åÝåáå͹Wññåýáýåáå!9ÍÜi!9ÍäiáñññÉõÝåýå!9å! 9ÑÍËi!9åÍÆi##ÑÍËiå!ÿÿ)ÑÍÆi"/W!8`"1W!xWÍDiÍi!xWÍLiÃb[*DW|µÊT[!´W"NWÃb[*HW|µÊb[!²W"NW*LW|µÊ™[õ!9å*;Wå*NWåÍdñÑÍ­iÑÍËi„[áåå*=WÑÍki|µÊ˜[áå"=Wñ:?Wo&XÍYi|µÊ°[!¡Wö[!Wö["|W!PW("7W"9W!xWÍDiÍh|µÊd\!xWÍDiÅÕÍÅgë"‚W!xWÍDiÅÕÍÚgÅÕ€ÍùgÍÅg!xWÍLi*7W+"7Wå*|Wå!xWÍDiÅÕ*€WÍ.iÍ gÅÕ)RÚUtruedam = %d usage: truedam [0|1] <+RìiUR[RaR@ @ @iRÚUñáåõí(`iÈOíCÕ`ÉñáÁÅåõí*ÈOíCÕ`!Éñáåõí+!ÈOíCÕ`!ÿÿÉñáÁÑÕÅåõí0bkÈOíCÕ`ÉñÑÕõí1!ÈOíCÕ`!ÿÿÉñÑáÁÅåÕõí2`iÈOíCÕ`ÉñÑáÁÅåÕõí3`iÈOíCÕ`ÉÝå!9åÍÆi##ÑÍËiå!ÿÿ)ÑÍÆiåÝá!9åÝåáå͹Wññåýáýåáå!9ÍÜi!9ÍäiáñññÉ„W0B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"5W!"3W*5Wn&|µÊ_*5Wn&%Í_i|µÊX*1Wå*/Wãå*5W#"5W+n&ãåÍÑiññ*3W#"3WÃþ^!"LW"JW"HW"FW"DW*5W#"5Wn&åÑ!+ÍŽiÂ7X!"DWÃX!-ÍŽiÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o"Õ`ÉñÑáÁÅåÕõ{í5`iÈOíCÕ`Éñáåõ}í6Éñáåõí7bkÈOíCÕ`ÉñÑÕõíiS8!ÈOíCÕ`!ÿÿÉñÑáÁÅåÕõí9`iÈOíCÕ`Éñáåõí:!ÈOíCÕ`!ÿÿÉñáÁÅåõí;ÈOíCÕ`!Éñáåõ}í<ÉÝåÝ!Ý9ÝnÝfN#FÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfÂIX!"FWÃX! ÍŽiÂ[X!"HWÃX!#ÍŽiÂmX!"JWÃX!0ÍŽiÂX!"LWÃX*5Wn&„X*ÍYi|µÊÕXñÁáåÅõåÍÆi##ÑÍËiå!ÿÿ)ÑÍÆi";W*;WëÍri|µÊËX*;WͲi";W!"FW*5W#"5Wà Y!";W*5Wn&åÍìfñ|µÊ Y*;W Í™iå*5W#"5W+n&åÍh_ñÑ";WÃÛX*5Wn&.ÍYi|µÊ•Y*5W#"5Wn&*ÍYi|µÊZYñÁáåÅõs#rÑÝnÝfs#rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o"Õ`ÉñáÁÑÕÅåõí>bkÈOíCÕ`ÉñÑÕõí?!ÈOíCÕ`!ÿÿÉ!iTRå!7Rå͹Vññ!åÍ_ñÉôÿÍÕi!9ÍÆiå!ÑÍYi|µÊ§T!9å!ÑÍËiÃ\U!9ÍÆiå!ÑÍYi|µÊßT!9ÍÆiå!Í™iÑÍÆiå!Ñn&åÍìfñ|µÊYU!9å!ÑÍËi!9åÍÆi##ÑÍËiå!ÿÿ)ÑÍÆi"=W*5W#"5WÃ’Y!"=W*5Wn&åÍìfñ|µÊ’Y*=W Í™iå*5W#"5W+n&„YåÍh_ñÑ"=WÃ`YÛY!ÿÿ"=W!"BW*5Wn&åÑ!lÍŽi»Y!"BWÃÄY!hÍŽiÂËY*5W#"5W!"@W!¸W"NW*5W#"5W+n&}2?WåÑ!dÍŽiÂôYÃýY!uÍŽiÂZ!"€WÃQZ!oÍŽiÂZ!"€WÃQZ!XÍŽiÂ$ZÃ-Z!xÍŽiÂ6Z!"€WÃQÍÆiå!Í™iÑÍÆiåÍdñå!ÑÍ_i|µÊUÍhT! 9å!9ÍÆiå!Í™iÑÍÆiåͳbñÑÍËi! 9ÍÆiå!ÑÍki|µÊVUÍhTÃ\UÍhT!9å! 9å!iU9å!9ÍÆiåÍ¿Sññññ! 9ÍÆiå!RåÍXVññ!åÍ_ñ ÍÕiÉíseR*I@ÍÐf *D"gRùͺUÍ~T!åÍ_*1R"'R")RÍMVí['RÍBV( Õ ÍV òÅÝáË!ë "'R")RË9AÑ+rÃ.^*@WÃ.^ÑÍ­iå*NWåÍdñÑÍ­iÑÍËi*FW;i|µÊr^!9åÍÆi+ÑÍËiëÍei|µÊr^! åÍ#_ñÃN^*NWn&|µÊ^*NW#"NW„^+n&åÍ#_ñÃr^*@W+"@WëÍei|µÊ®^!0åÍ#_ñÃ^*7Wå*9WÑ͈i|µÊÑ^*7W#"7W+n&åÍ#_ñî^*FW|µÊý^!9åÍÆi+ÑÍËiëÍei|µÊý^! åÍ#_ñÃÙ^ñÃÆW*/W|µÊ_*/WåÍ`ñ|µÊ_!ÿÿÃ"_*3WÃ"åÍ4cññññÑÍËiáå|µÊ*cñáåõͲiÃ1cñáåõÃ1cññÉõ!9ëÍËi!9å!9ÍÆiåÍùcñÑÍËi!9ÍÆiå!9ÍÆin&ãåÍÑiñ|µÊ°c!9åñáåõå! 9ÍÆiÑÍ™iå!9ÍÆiå! 9åÍÆi#ÑÍËi+n&ãåÍÑiñÑÑÍËiÃUcáåñÉ!9n&0·íRÉ!9n&åÍìfñ|µÊãc!9X×cn&0·íRÃøc!9n&åÍÖfñ7·íRÃøcÉñáåõn&åÍ gñ|µÊ_É*1Wå*/Wãå!9n&ãåÍÑiññ*3W#"3WÉñáåõå!9ÍÆiÑÍri|µÊ^_ñáåõÃg_ñÁáåÅõÃg_É!9n&0·íRÉñáåõ0ÉÍŽ_ñá(„_åõ|µÊ-@Ã0@!3RA^#V#{²( ÅåëË^ÌÍ_áÁìɬ_!ÿÿ"ª_ñáåõÝååÝáͪb(MË^ M¯ÝwÝwÝååÝá++å##íCª_~q#Ë~(ëÝnÝfåËo Í(D( Ía!ÿÿ"ª_ÍúUÁÍúUá*ª_ÝáÉ!Ý!("Õ`îÝåd!9åÍÆi#ÑÍËiÃùcñáåõÉñÑÕõ!·È#ùÉ1dñÑÕõÝåýå!"-dý!+R*+Rý"/dÝåýáÝnÝfåÝá|µ(7ÝnÝfí[-d·íR8ÜíB0ÝnÝfýuýt ÝuÝtDMÝ ÝsÝr*-dåÍÅdÁ|¥< !#"Õ`åÝáÝqÝpÝåÍsfágoýáÝáÉñÑÕõz³('!9íBíK'RíB8 íR8Åë "'RáÉ!#"Õ`!ÿÿÉ*'RÉúdñÑÕõÝåýåÍ eýáÍ bÝá(~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáͪb(WËN(SËv OT]åÝá:URþ*(Ë^#ÄÆiëÅyþ Ý~ÿæ 4yÍõÝ4þñë(Ë~á }Ö ÝwþÝáÉëËöËî!Ë^(wÍa!ÿÿå yÍ(+¬`Ë~ ÉÍ·` ïÂÝ4þÕÝ^þÝ~ÿæÝáÉ!ãeÍèeÝ!üÿÝͨfý!+R ý"ødýnýfåýáý^ýVz³(ÝåáíR0âÍÈeÝåÁýqýpýå!+RÑ·íR('ýnýf·íB ÍÕeýuýtÝnÝfýuýtýåÝáý"ødÝNÝFÅýáx±(ÝåáÝ^ÝV·íB ÍÕeÝuÝtÍÈeý*ødÝåáÝ^ÝVíK'R¯íBÀýwýwÝ"'RÉýnýfÝuÝtÉýnýfÝ^ÝVÉFREEÝåÅÕåë+F+N++ÍýeáÑÁúeÝáÉëÝ!-RÝÍRgÅÕ*‚WÍ.i̓gëÑn&Ñ}!xWÍDiÅÕ*€WÍ.iÍ:g!xWÍLiÃÆ[*7Wå*9WÑÍ­iå*=WÑ"@W*JW|µÊ‹\*7Wå„\*9WÑÍ_i|µÊ]:?Wo&åÑ!oÍŽi¹\*@WëÍri|µÊ¶\!"@WÃ]!xÍŽiÂË\!W"NWÃ]!XÍŽiÂÝ\!ŠW"NWÃ]!bÍŽiÂï\!‡W"NWÃ]!BÍŽiÂ]!„W"NWÃ]Ãî]!cÍŽiÂ?]!PWå!9ÍÆiåÍÆi##ÑÍËiå!ÿÿ)Ñ?Ëq(ö@ö€Í DåÍ+añ"Õ`áÉñáåõ&}íKb ¹0þ@Ðþ-.@Ð!×`…oŒ•gn&É`ana€aa¡aµaÌaëaüaUnknown errorArg list too longNot a directoryInvalid argumentToo many open filesNot a character deviceMath arg ou×at of domain of funcResult too largeI/O errorHñÑÕõ{þ@8ÍÆiÑ}!PW"7W*7W#"9WÃî]!sÍŽiÂÈ]ñÁáåÅõåÍÆi##ÑÍËiå!ÿÿ)ÑÍÆi"7W*=WëÍri|µÊz]!ÿ"=W!"~WÊ]*„]~W#"~W*7W#"7W+n&|µÊ¥]*~Wå*=WÑÍri|µÊ­]Ã]*7W+"7W"9W*7Wå*~WÑÍ­i"7WÃî]!ÍŽiÂÛ]*5W+"5WÃî]!?W"7W"9W*9W#"9WÃî]:?Wo&|µÊþ^õ!9å*;Wå*9Wå*7WÑÍ­iÑÍ­iå*@WëÍri|µÊ(^!Ö@o&þ 8l)NaÃÆiöÀõ!|DÍÐf !‹B"[bT]ÍÆi"Xb!JbÍËiñÍ D!`bÉ`b~#Ö ø!ÃËiñáÑÝáÝåÕåõÝnÝf|µÉõõ!9å!9ÍÆiåÍùcñÑÍËi!9å!9ÍÆin×b&-ÍYiÑÍËi|µÊõb!9åÍÆi#ÑÍËi!9å!´cå!ìfå! å!9ÍÆi%0ÃN5%s: %s usage: cd [-l] unixdir <'0»GQ0W0]0  g0ÃN5ñáåõí(`iÈOíC;@ÉñáÁÅåõí*ÈOíC;@!Éñáåõí+!ÈOíC;@!ÿÿÉñáÁÑÕÅåõí0bkÈOíC;@ÉñÑÕõí1!ÈOíC;@!ÿÿÉñÑáÁÅåÕõí2`iÈOíC;@ÉñÑáÁÅåÕõí3`iÈOíC;@ÉÝåÝ!õ}!þaØþ{Ð#Éñáåõ}!þ È-þ ØþÐ,ÉÍTiÍÖhÊ;iÍiõÍÛhÍ hñüiÃ;iÍTiÍÖhÊ;iÍÛhõÍ hñáÑÁüiéÍTiÅÕå!9PXå~#¶#¶#¶áÊ}g¯ÍÇhãܧh¯Í¹hãÃagñññÃ;iÍTiͧhÃ;iÍ gÂ?i+Ã?iÍ gÚ?i+Ã?i!9###xî€G~ÂÁg+~¹ÂÁg+~ºÂÁg+~»!ÉÍTi{¦_#z¦W#y¦O#x¦GÃ;iÍTiÍÖh(###Ë+Ë+Ë+ËÍhèáÑÁé{úg/Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o";@ÉñÑáÁÅåÕõ{í5`iÈOíC;@Éñáåõ}í6Éñáåõí7bkÈOíC;@ÉñÑÕõíg18!ÈOíC;@!ÿÿÉñÑáÁÅåÕõí9`iÈOíC;@Éñáåõí:!ÈOíC;@!ÿÿÉñáÁÅåõí;ÈOíC;@!Éñáåõ}í<ÉÝåÝ!Ý9ÝnÝfN#FÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfs#rÑ_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍÖh!À+ÉÝåõõÝ!Ý9;å~Ýw6#~Ýw6#~Ýw6#~Ýw6.xæ€Â[hËËËË,ÃIhÝuÿÝåáÍöhåÍháÊohÒvhÍ¡hÍi7ã͹hÝ5ÿʈhã¯ÍÇhÃdhñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍiçhå~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õüiÍiòôhÍöhÍiÍöhñî€ÉñÉå~s_ÝnÝfs#rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o";@ÉñáÁÑÕÅåõí>bkÈOíC;@ÉñÑÕõí?!ÈOíC;@!ÿÿÉ!g2 0å!30åÍ,6ññ!åÍò>ñÉöýͤG! 9Í•Gå!ÑÍAG|µÊ™2Íf2!9å!ÑÍšG!9Í•Gå!9Í•GÍhGÑÍ•Gå!Ñn&å!-ÑÍ(G|µÊ*3!9Í•Gå!9Í•GÍhGÑÍ•Gå!Ñnôúh#~rW#~qO#~pGáÉå###~·áÉ{· ² ± xþ€Èå¯o›_}šW}™O}˜GáÉÍ6iz·ð ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#pÉ!9ÉÍxiÈ+ÉÍxiÀ+ÉÍxiÐ+ÉëÍxiØ+ÉÍxiØ+É|î€gz {½!ÉÍŽiØ+Éz¼Â•i{½!ÉDM¯og>Ë#Ë0 =È)àië¯íRÉÍ·i#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉšU#¶#¶#¶á&åͦDñå!lÑÍ.G|µÊ 3Íf2!9åÍ•G#ÑÍšG+!9å!ÑÍšGÃ63!9å!ÑÍšG! 9Í•Gå!9Í•GÑÍ|Gå!ÑÍ.G|µÊY3Íf2!9å!9ÑÍšG!g39å!9Í•Gå!9Í•GÍhGÑÍ•GÑÍšG!9Í•G|µÊ–4!9Í•Gn&|µÊ“4!9Í•Gn&å![ÑÍ(G|µÊË3!9Í•Gå!Ñn&|µÊ4!9åÍ•GÑÍšGÿÿ!9åÍ•GÑÍååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååšGÿÿå!9åÍ•GÑÍšGÿÿn&Ñ}Ã4!9Í•Gn&åͼDñ|µÊa4!9åÍ•GÑÍšGÿÿå!9åÍ•GÑÍšGÿÿn&åͦDñÑ}Ã4!9åÍg4•GÑÍšGÿÿå!9åÍ•GÑÍšGÿÿn&Ñ}Õ3Ã×4!9Í•Gn&|µÊ×4!9åÍ•GÑÍšGÿÿå!9åÍ•GÑÍšGÿÿn&Ñ}Ö4!9Í•Gå!Ñ}!9å!9nÝf|µ(åÝáíRÈ8îñ!GfÍZfYP!TfÍZf> Í3áÍgD!9fÍgD!ÿÿåÍ‚_: BAD BLOCK X'xxxx', LEN X'xxxx' zÍ_f{õÍhfñæÆ'Î@'w#ÉýååÕý!-RÕýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý!-RÕýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌ:%þIÉñÑÕõÕÕÍüfÁÑëz³È}î &oÉñáåõ}!þ0Øþ:Ðúf#ÉñáåhÍ]GÂ>9*¨6#"¨6!"³6!+7"Á6*¨6#"¨6+n&}2²6åÑ!dÍ]GÂg9Ãp9!uÍ]GÂy9!"ó6ÃÄ9!oÍ]G‹9!"ó6ÃÄ9!XÍ]G—9à9!xÍ]G©9!"ó6ÃÄ9!BÍ]Gµ9þ9!bÍ]GÂw:ñÁáåÅõåÍ•G##ÑÍšGå!ÿ–>ñÃ>*ª6å*¬6ÑÍWG|µÊD>*ª6#"ª6+n&åÍ–>ñÃ!>*¹6|µÊp>!9åÍ•G+ÑÍšGëÍ4G|µÊp>! åÍ–>ñÃL>ñÃ97*¢6|µÊ„>*¢6å͉?ñ|µÊ>!ÿÿÕ>*¦6Õ>É*¤6å*¢6ãå!9n&ãåÍ Gññ*¦6#"¦6Éñáåõå!9Í•GÑÍAG|µÊÑ>ñáåõÃÚ>ñÁáåÅõÃÚ>É!9n&0·íRÉñáåõ0ÉÍþ>ñá%÷>åõí{c0É!/0A^#V#{²( ÅåëË^Ì=?áÁåÍŒ1ñÑÍšG!9Í•Gå!ÑÍ.G|µÊ?5!å!9å*;@åÍ31ñññ!9å!9å!0å!30åÍ,6ññññ!åÍò>ñ!åÍò>ñ ͤGÉísc0íCa0>d!Eï"e0ë!ÿóíRëg50 >eïý~þ` !ÿóùÍ„5Í|2!åÍò>*-0"#0"%0KI>Rï"R0DO>Rï"X0"^0*a0í[#0Í!6( Õ Íß5 òÅÝáË!ë "#0"%0Ë9AÑ+r+sùÁåÝåÅÉÃéBà BÅ~þ"(þ' ÿ)ÑÍ•GÍýF!ë6ÍGÃa:ñÁáåÅõåÍ•G##ÑÍšGå!ÿÿ)ÑÍ•GÍG!ë6ÍG:²6o&dÍ(G|µÊÕ:!ë6ÍGÅÕÍeE|µÊ¶:!)7"Á6!ë6ÍGÅÕ€Í[E|µÊ³:!ë6ÍGÍßF!ë6ÍGÃÕ:*·6|µÊÇ:!'7"Á6ÃÕ:*»6|µÊÕ:!%7"Á6*¿6|µÊ ;õ!9å*®6å*Á6åÍBñÑÍ|GÑÍšG÷:áåå*°6ÑÍ:G|µÊ ;áå"°6ñ:²6o&XÍ(G|µÊ#;!7Ã);!7Ã#Ox·(y~þ 8"þ!0 ( ( ¹( þ\ G#Ú#¯Á> ¾Ø> ¾È#õõÝåýå!9å! 9ÑÍšG!9åÍ•G##ÑÍšGå!ÿÿ)ÑÍ•G"¢6!¨?"¤6!9åÍ•G=g6##ÑÍšGå!ÿÿ)ÑÍ•GåÝá!9åÝåáåÍ,7ññåýáýåáå!9Í«G!9ͳGáñññÉ÷60B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"¨6!");"ï6!Ã6("ª6"¬6!ë6ÍGÍæE|µÊ×;!ë6ÍGÅÕÍ”Eë"õ6!ë6ÍGÅÕÍ©EÅÕ€ÍÈEÍ”E!ë6ÍG*ª6+"ª6å*ï6å!ë6ÍGÅÕ*ó6ÍýFÍïDÅÕÍ!EÅÕ*õ6ÍýFÍREëÑn&Ñ}!ë6ÍGÅÕ*ó6ÍýFÍ E!ë6ÍGÃ9;*ª6å*¬6ÑÍ|Gå*°6Ñ"³6*½6|µÊþ;*ª6å÷;*¬6ÑÍ.G|µÊt<:²6o&åÑ!oÍ]GÂ,<*³6ëÍAG|µÊ)<¦6*¨6n&|µÊt>*¨6n&%Í.G|µÊz7*¤6å*¢6ãå*¨6#"¨6+n&ãåÍ Gññ*¦6#"¦6Ãq>!"¿6"½6"»6"¹6"·6*¨6#"¨6n&åÑ!+Í]Gª7!"·6ÃŒ7!-Í]G¼7!"¹6ÃŒ7! Í]GÂÎ7!"»6ÃŒ7!#Í]GÂà7!"½6ÃŒ7!0Í]GÂò7!"¿6ÃŒ7*¨6n&÷7*Í(G|µÊH8ñÁáåÅõåÍ•G##ÑÍšGå!ÿÿ)ÑÍ•G"®6*®6ëÍAG|µÊ>8*®6Í!"³6ÃtñÑ"®6ÃN8*¨6n&.Í(G|µÊ9*¨6#"¨6n&*Í(G|µÊÍ8ñÁáåÅõåÍ•G##ÑÍšGå!ÿÿ)ÑÍ•G"°6*¨6#"¨6Ã9!"°6*¨6n&åÍÏDñ|µÊ9*°6 ÍhGå*¨6#"¨6+n&÷8åÍÛ>ñÑ"°6ÃÓ8Ã9!ÿÿ"°6!"µ6*¨6n&åÑ!lÍ]GÂ.9!"µ6Ã79!<*ª6+"ª6"¬6*ª6å*ñ6ÑÍ|G"ª6Ãa=!Í]GÂN=*¨6+"¨6Ãa=!²6"ª6"¬6*¬6#"¬6Ãa=:²6o&|µÊq>õ!9å*®6å*¬6å*ª6ÑÍ|GÑÍ|Gå*³6ëÍAG|µÊ›=!á=*³6á=ÑÍ|Gå*Á6åÍBñÑÍ|GÑÍšG*¹6ÍG|µÊå=!9åÍ•G+ÑÍšGëÍ4G|µÊå=! åÍ–>ñÃÁ=*Á6n&|µÊ>*Á6#"Á6÷=+n&åÍ–>ñÃå=*³6+"³6ëÍ4G|µÊ!>!0åÍw6#~Ýw6#~Ýw6#~Ýw6.xæ€Â*FËËËË,ÃFÝuÿÝåáÍÅFåÍ^FáÊ>FÒEFÍpFÍßF7ã͈FÝ5ÿÊWFã¯Í–FÃ3Fñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍßFÃvFå~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õüßFÍ×FòÃFÍÅFÍßFÍÅFñî€ÉñÉå~s_#~rW#~qO#~pGáÉå###~·áÉ{· ² ± ÔéFxþ€Èå¯o›_}šW}™O}|µÉñÑÕõ!·È#ùÉ BñÑÕõÝåýå!"Bý!'0*'0ý"BÝåýáÝnÝfåÝá|µ(7ÝnÝfí[B·íR8ÜíB0ÝnÝfýuýt ÝuÝtDMÝ ÝsÝr*BåÍ´BÁ|¥< !#";@åÝáÝqÝpÝåÍIDágoýáÝáÉñÑÕõz³('!9íBíK#0íB8 íR8Åë "#0áÉ!#";@!ÿÿÉ*#0ÉéBñÑÕõÝåýåÍùBýáÝáÉ!ÒCÍ×CÝ!üÿÝÍ~Dý˜GáÉÍGz·ð ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#pÉ!9ÉÍGGÈ+ÉÍGGÀ+ÉÍGGÐ+ÉëÍGGØ+ÉÍGGØ+É|î€gz {½!ÉÍ]GØ+Éz¼ÂdG{½!ÉDM¯og>Ë#Ë0 =È)ÃoGë¯íRÉ͆G#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉN5É|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉšU#¶#¶#¶á!'0 ý"çBýnýfåýáý^ýVz³(ÝåáíR0âÍ·CÝåÁýqýpýå!'0Ñ·íR('ýnýf·íB ÍÄCýuýtÝnÝfýuýtýåÝáý"çBÝNÝFÅýáx±(ÝåáÝ^ÝV·íB ÍÄCÝuÝtÍ·Cý*çBÝåáÝ^ÝVíK#0¯íBÀýwýwÝ"#0ÉýnýfÝuÝtÉýnýfÝ^ÝVÉFREEÝåÅÕåë+F+N++ÍìCáÑÁéCÝáÉëÝ!)0ÝnÝf|µ(åÝáíRÈ8îñ!ååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååìÉ?!ÿÿ"?ñáåõÝååÝáÍB(MË^ M¯ÝwÝwÝååÝá++å##íC?~q#Ë~(ëÝnÝfåËo ><ï( Íj@!ÿÿ"?ÍÙ5ÁÍÙ5á*?ÝáÉ!Ý!(";@îÝåÍûAÝá(~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáÍB(RËN(NËv JT]åÝá:Q0þ*(Ë^#Ä•GëÅyþ Ý~ÿæ />ïõÝ4þñëá }Ö ÝwþÝáÉëËöËî!Ë^(wÍj@!ÿÿå >ï 6D>cïYP!CD>cï >ïá> ï!(D> ï!ÿÿåÍõ>: BAD BLOCK X'xxxx', LEN X'xxxx' ýååÕý!)0Õýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý!)0Õýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌñÑÕõÕÕÍßDÁÑëz³È}ö &oÉñáåõ}!ö þa8þ{Ø+Éñáåõ}!þ0Øþ:Ð#Éñáåõ}!þAéDØþ[Ð#ÉÍ#GÍ¥FÊ GÍ×FõͪFÍïÒÍ@ ô!@ËÝ4þÕÝ^þÝ~ÿæ?Ëq(ö@ö€O>ïåÍ’@ñ";@áÉñáåõ&}íKmA ¹0þ@Ðþ-.@Ð!=@…oŒ•gn&ÉÇ@Õ@ç@÷@AA3ARAcAUnknown errorArg list too longNot a directoryInvalid argumentToo manEñüßFà GÍ#GÍ¥FÊ GͪFõÍïEñáÑÁüßFéÍ#GÅÕå!9PXå~#¶#¶#¶áÊLE¯Í–FãÜvF¯ÍˆFãÃ0Eñññà GÍ#GÍvFà GÍoEÂG+ÃGÍoEÚG+ÃG!9###xî€G~ÂE+~¹ÂE+~ºÂE+~»!ÉÍ#G{¦_#z¦W#y¦O#x¦Gà GÍ#GÍ¥F(###Ë+Ë+Ë+ËÍÕEèáÑÁé{/_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍ¥FéE!À+ÉÝåõõÝ!Ý9;å~Ýy open filesNot a character deviceMath arg oá=Aut of domain of funcResult too largeI/O errorHñÑÕõ{þ@8Ö@o&þ 8l)µ@ÕGöÀOýå>eïýËþýá«A>ïbk> Pí±+pëÉñáÑÝáÝåÕåõÝnÝf!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o"V>ÉñÑáÁÅåÕõ{í5`iÈOíCV>Éñáåõ}í6Éñáåõí7bkÈOíCV>ÉñÑÕõí`18!ÈOíCV>!ÿÿÉñÑáÁÅåÕõí9`iÈOíCV>Éñáåõí:!ÈOíCV>!ÿÿÉñáÁÅåõí;ÈOíCV>!Éñáåõ}í<ÉÝåÝ!Ý9ÝnÝfN#FÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfs#rÑÝnÝfs*É4ëÍ#E|µÊY6*É4ÍcE"É4!"Ô4*Ã4#"Ã4Û6!"É4*Ã4n&åÍÁBñ|µÊ›6*É4 ÍJEå*Ã4#"Ã4+n&åÍö<ñÑ"É4Ãi6*Ã4n&.Í E|µÊ#7*Ã4#"Ã4n&*Í E|µÊè6ñÁáåÅõåÍwE##ÑÍ|Eå!ÿÿ)ÑÍwE"Ë4*Ã4#"Ã4à 7!"Ë4*Ã4n&åÍÁBñ|µÊ 7*Ë4 ÍJEå*Ã4#"Ã4+n&7åÍö<ñÑ"Ë4Ãî6Ã)7!ÿÿ"Ë4!"Ð4*Ã4n&åÑ#rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o"V>ÉñáÁÑÕÅåõí>bkÈOíCV>ÉñÑÕõí?!ÈOíCV>!ÿÿÉ!`20å!,0åÍG4ññ!åÍ =ñÉüü͆E!9ÍwEå!ÑÍE|µÊ’2Í_2!9å!å!9åÍš1ññÑÍ|E!9ÍwEå!ÑÍ E|µÊë2!å!9å*V>åÍ,1ñññ!9å!0å!,0åÍG4ñññ!åÍ =ñ!9å!0åÍæ!lÍ?EÂI7!"Ð4ÃR7!hÍ?EÂY7*Ã4#"Ã4!"Î4!F5"Ü4*Ã4#"Ã4+n&}2Í4åÑ!dÍ?E‚7Ë7!uÍ?E”7!"5Ãß7!oÍ?E¦7!"5Ãß7!XÍ?E²7û7!xÍ?EÂÄ7!"5Ãß7!BÍ?EÂÐ7ÃÙ7!bÍ?EÂ’:!"5*Ë4ëÍ#E|µÊô7!"Ë4*Ð4|µÊ"8ñÁáåÅõåÍwEÑÍ|Eå!ÿÿ8))ÑÍõD!5ÍýDÃ|8:Í4o&dÍ E|µÊY83ññ!åÍ =ñ͆EÉís\0íCZ0>d!Eï"^0ë!ÿóíRë0 >eïý~þ` !ÿóùÍ>3Íu2!åÍ =*&0"0"0KI>Rï"K0DO>Rï"Q0"W0*Z0`3í[0ÍÛ3( Õ Í™3 òÅÝáË!ë "0"0Ë9AÑ+r+sùÁåÝåÅÉÃAÃ;@Å~þ"(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( þ\ G#Ú#¯Á> ¾Ø> ¾È#õõÝåýå!9å! ñÁáåÅõåÍwE##ÑÍ|Eå!ÿÿ)ÑÍwEÍßD!5ÍýDÃ|8ñÁáåÅõåÍwE##ÑÍ|Eå!ÿÿ)ÑÍwEÍçD!5ÍýD:Í4o&dÍ E|µÊð8!5ÍõDÅÕÍGC|µÊÑ8!D5"Ü4!5ÍõDÅÕ€Í=C|µÊÎ8!5ÍõDÍÁD!5ÍýDÃð8*Ò4|µÊâ8!B5"Ü4Ãð8*Ö4|µÊð8!@5"Ü4*Ú4|µÊ'9õ!9å*É4å*Ü4åÍ)@ñÑÍ^EÑÍ|E9áåå*Ë4ÑÍE|µÊ&9áå"Ë4ñ:Í4o&X9ÑÍ|E!9åÍwE##ÑÍ|Eå!ÿÿ)ÑÍwEåÝá!*0"½4!Ã="¿4!9åÝåáåÍG5ññåýáýåáå!9ÍE!9Í•EáñññÉõÝåýå!9å! 9ÑÍ|E!9åÍw_`4E##ÑÍ|Eå!ÿÿ)ÑÍwE"½4!Ã="¿4!9åÍwE##ÑÍ|Eå!ÿÿ)ÑÍwEåÝá!9åÝåáåÍG5ññåýáýåáå!9ÍE!9Í•EáñññÉ50B0b0X0x0123456789abcdef0123456789ABCDEFÍ E|µÊ>9!/5ÃD9!5ÃD9" 5!Þ4("Å4"Ç4!5ÍõDÍÈC|µÊò9!5ÍõDÅÕÍvCë"5!5ÍõDÅÕÍ‹CÅÕ€ͪCÍvC!5ÍýD*Å4+"Å4å* 5å!5ÍõDÅÕ*5ÍßDÍÑBÅÕÍCÅÕ*5ÍßDÍ4CëÑn&Ñ}!5ÍõDÅÕ*5ÍßDÍëB!5ÍýDÃT9*Å4å*Ç4ÑÍ^Eå*Ë4Ñ"Î4*Ø4|µÊ:*Å4å:*Ç4ÑÍE|µÊ::Í4o&åÑ!oÍ?0Ã3%s pwd: %s usage: pwd < 0EJ0P0V0  `0Ã3ñáåõí(`iÈOíCV>ÉñáÁÅåõí*ÈOíCV>!Éñáåõí+!ÈOíCV>!ÿÿÉñáÁÑÕÅåõí0bkÈOíCV>ÉñÑÕõí1!ÈOíCV>!ÿÿÉñÑáÁÅåÕõí2`iÈOíCV>ÉñÑáÁÅåÕõí3`iÈOíCV>ÉÝåÝ!Ý9Ý^ÝV +-ñáåõ"Ã4!"Á4*Ã4n&|µÊ<*Ã4n&%ÍE|µÊ•5*¿4å*½4ãå*Ã4#"Ã4+n&ãåÍ‚Eññ*Á4#"Á4ÃŒÃwEöÀOýå>eïýËþýáÆ?>ïbk> Pí±+pëÉ;* 5å*Ë4ÑÍ#E|µÊ;;Ã;*Å4+"Å4"Ç4*Å4å* 5ÑÍ^E"Å4Ã|;!Í?EÂi;*Ã4+"Ã4Ã|;!Í4"Å4"Ç4*Ç4#"Ç4Ã|;:Í4o&|µÊŒ<õ!9å*É4å*Ç4å*Å4ÑÍ^EÑÍ^Eå*Î4ëÍ#E|µÊ¶;!ü;*Î4ü;ÑÍ^Eå*Ü4åÍ)@ñÑÍ^EÑÍ|E*Ô4ÍoE|µÊåÝáÝqÝpÝåÍdBágoýáÝáÉñÑÕõz³('!9íBíK0íB8 íR8Åë "0áÉ!#"V>!ÿÿÉ*0ÉAñÑÕõÝåýåÍAýáÎ4ëÍE|µÊ<<ï( Í…>!ÿÿ"5=Í“3ÁÍ“3á*5=ÝáÉ!Ý!("V>îÝåÍ@Ýá(~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáÍ @(RËN(NËv JT]åÝá:J0þ*(Ë^#ÄwEëÅyþ Ý~ÿæ />ïõÝ4þñëá }Ö ÝwþÝáÉëËöËî!Ë^(nÝf|µ(åÝáíRÈ8îñ!QB>cïYP!^B>cï >ïá> ï!CB> ï!ÿÿåÍ=: BAD BLOCK X'xxxx', LEN X'xxxx' ýååÕý!"0Õýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý!"0Õýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌñáåõ}!þ0Øþ:Ð#ÉÍE͇DÊìD͹DõÍŒDÍÑCñüÁDÃìDÍE͇DÊìDÍŒDõÍÑCñáÑÁüÁDéÍCEÅÕåwÍ…>!ÿÿå >ï ÒÍ8> ô!7>ËÝ4þÕÝ^þÝ~ÿæHHHHHHHHHHHHHHCHHHHHCC"##%'CCCå!$0No&ËA(þ@8>?Ëq(ö@ö€O>ïåÍ­>ñ"V>áÉñáåõ&}íKˆ? ¹0þ@Ðþ-.@Ð!X>…oŒ•gn&Éâ>ð>??#?7?N?m?~?Unknown errorArg list too longNot a directoryInvalåååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå!-ÑÍ×G|µÊW3!9ÍVHå!9ÍVHÍHÑÍVHå!Ñn&åÍUEñå!lÑÍÝG|µÊ:3Í“2!9åÍVH#ÑÍ[H+!9å!ÑÍ[HÃc3!9å!ÑÍ[H!9å!9ÑÍ[HÃ3!9åÍVH#ÑÍ[H+!9ÍVHå!9ÍVHÑÍðG”3|µÊ(5!9å!9ÍVHå! 9ÍVHÍHÑÍVHÑÍ[H!9ÍVH|µÊÉ4!9ÍVHn&|µÊÆ4!9ÍVHn&å![ÑÍ×G|µÊþ3!9ååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååÍVHå!Ñn&|µÊI4!9åÍVHÑÍ[Hÿÿ!9åÍVHÑÍ[Hÿÿå!9åÍVHÑÍ[Hÿÿn&Ñ}ÃÃ4!9ÍVHn&åÍkEñ|µÊ”4!9åÍVHÑÍ[Hÿÿå!9åÍVHÑÍ[Hÿÿn&åÍUEñÑ}ÃÃ4”4!9åÍVHÑÍ[Hÿÿå!9åÍVHÑÍ[Hÿÿn&Ñ}ÃÈ3à 5!9ÍVHn&|µÊ 5!9åÍVHÑÍ[Hÿÿå!Ë,ÃúCÝuÿÝåáͧDåÍ@DáÊ DÒ'DÍRDÍÁD7ãÍjDÝ5ÿÊ9Dã¯ÍxDÃDñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍÁDÃXDå~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õüÁD͹Dò¥DͧDÍÁDͧDñî€ÉñÉå~s_#~rW#~qO#~pGáÉå###~·áÉ{· ² ± xþ€Èå¯o›_}šW}™O}˜GáÉÍçDz·ð ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#pR0Ãý5unix: error (exit status %d, signal %d) unix: %s usage: unix [-l] command Ë#Ë0 =È)ÃQEë¯íRÉÍhE#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉ3O#x¦Gà GÍ#GÍ¥F(###Ë+Ë+Ë+ËÍÕEèáÑÁé{/_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍ¥FéE!À+ÉÝåõõÝ!Ý9;å~ÝÁÅåÕõí2`iÈOíCê@ÉñÑáÁÅåÕõí3`iÈOíCê@ÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o"ê@ÉñÑáÁÅåÕõ{í5`iÈOíCê@Éñáåõ}í6Éñáåõí7bkÈOíCê@ÉñÑÕõí”18!ÈOíCê@!ÿÿÉñÑáÁÅåÕõí9`iÈOíCê@Éñáåõí:!ÈOíCê@!ÿÿÉñáÁÅåõí;ÈOíCê@!Éñáåõ}í<ÉÝåÝ!Ý9ÝnÝfN#ååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååFÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfs#rÑÝnÝfs#rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o"ê@ÉñáÁÑÕÅåõí>bkÈOíCê@ÉñÑÕõí?!ÈOíCê@!ÿÿÉ!”260å!`0åÍÛ6ññ!åÍ¡?ñÉöüÍeH! 9ÍVHå!ÑÍðG|µÊÆ2Í“2!9å!ÑÍ[H!9ÍVHå!9ÍVHÍHÑÍVHå!Ñn&åÍF|µÊe;!Ø7"p7!š7ÍÂGÅÕ€Í F|µÊb;!š7ÍÂGÍŽG!š7ÍÊGÄ;*f7|µÊv;!Ö7"p7Ä;*j7|µÊ„;!Ô7"p7*n7|µÊ»;õ!9å*]7å*p7åͽBñÑÍ+HÑÍ[H¦;áåå*_7ÑÍéG|µÊº;áå"_7ñ:a7o&XÍ×G|µÊÒ;!Ã7ÃØ;!²7ÃØ;"ž7!r7("Y7"[7!š7ÍÂGÍ•F|µÊ†!cÍ HÂa=!r7å!9ÍVHåÍVH##ÑÍ[Hå!ÿÿ)ÑÍVHÑ}!r7"Y7*Y7#"[7Ã>!sÍ HÂê=ñÁáåÅõåÍVH##ÑÍ[Hå!ÿÿ)ÑÍVH"Y7*_7ëÍðG|µÊœ=!ÿ"_7!" 7ì=*¦= 7#" 7*Y7#"Y7+n&|µÊÇ=* 7å*_7ÑÍðG|µÊÏ=Ã¥=*Y7+"Y7"[7*Y7å* 7ÑÍ+H"Y7Ã>!Í HÂý=*W7+"W7Ã>!a7"Y7"[7*[7#"[7Ã>:a7o&|µÊ ?õ!&.Í×G|µÊ·9*W7#"W7n&*Í×G|µÊ|9ñÁáåÅõåÍVH##ÑÍ[Hå!ÿÿ)ÑÍVH"_7*W7#"W7ô9!"_7*W7n&åÍ~Eñ|µÊ´9*_7 ÍHå*W7#"W7+n&¦9åÍŠ?ñÑ"_7Â9ý9!ÿÿ"_7!"d7*W7n&åÑ!lÍ HÂÝ9!"d7Ãæ9!hÍ HÂí9*W7#"W7!"b7!Ú7"p7*W7#"W7+n&}2a7åÑ!dÍ HÂ:Ã:!uÍ HÂ(:!"¢7Ãs:!oÍ HÂ9å*]7å*[7å*Y7ÑÍ+HÑÍ+Hå*b7ëÍðG|µÊJ>!ÃP>*b7ÃP>ÑÍ+Hå*p7åͽBñÑÍ+HÑÍ[H*h7ÍNH|µÊ”>!9åÍVH+ÑÍ[HëÍãG|µÊ”>! åÍE?ñÃp>*p7n&|µÊ²>*p7#"p7¦>+n&åÍE?ñÔ>*b7+"b7ëÍãG|µÊÐ>!0åÍE?ñò>*Y7å*[7ÑÍH|µÊó>*Y7#"Y7+n&åÍE?ñÃÐ>*h7|µÊ?!9åÍVH+ÑÍ[HëÍãG|µÊ?! åÍE?9åÍVHÑÍ[Hÿÿn&Ñ}ÃÉ4!9åÍVHÑÍ[Hÿÿå! Ñ}Ãs3!9ÍVHå!Ñ}!9å!9åÍ—0ñÑÍ[H!9ÍVHå!ÍBHÑÍ×G|µÊ5!å!9å*ê@åÍ`1ñññ!9å!,0å!`0åÍÛ6ñññ!åÍ¡?ñÃî5!9”5ÍVHå!ÑÍÝG|µÊî5!å!9å*ê@åÍ`1ñññ!9ÍVHå!ÿÑÍ0Hå! 9ÍVHå!ÑÍ7Hå!0å!`0åÍÛ6ññññ!å::!"¢7Ãs:!XÍ HÂF:ÃO:!xÍ HÂX:!"¢7Ãs:!BÍ HÂd:Ãm:!bÍ HÂ&=!"¢7*_7ëÍðG|µÊˆ:!"_7*d7|µÊ¶:ñÁáåÅõåÍVHÑÍ[Hå!ÿÿ¦:))ÑÍÂG!š7ÍÊGÃ;:a7o&dÍ×G|µÊí:ñÁáåÅõåÍVH##ÑÍ[Hå!ÿÿ)ÑÍVHͬG!š7ÍÊGÃ;ñÁáåÅõåÍVH##ÑÍ[Hå!ÿÿ)ÑÍVHÍ´G!š7ÍÊG:a7o&dÍ×G|µÊ„;!š7ÍÂGÅÕÍ¡?ñ!åÍ¡?ñ ÍeHÉís0íCŽ0>d!Eï"’0ë!ÿóíRë0 >eïý~þ` !ÿóùÍ36Í©2!åÍ¡?*Z0"P0"R0KI>Rï"0DO>Rï"…0"‹0*Ž0í[P0ÍÐ6( Õ ÍŽ6 òÅÝáË!ë "P0"R0Ë9AÑ+r+sùÁåÝåÅÉØCÃÏBÅ~þ"¿”6(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( þ\ G#Ú#¯Á> ¾Ø> ¾È#õõÝåýå!9å!ñÃû>ñÃè7*Q7|µÊ3?*Q7åÍ8@ñ|µÊ>?!ÿÿÃD?*U7ÃD?É*S7å*Q7ãå!9n&ãåÍaHññ*U7#"U7Éñáåõå!9ÍVHÑÍðG|µÊ€?ñáåõÉ?ñÁáåÅõÉ?É!9n&0·íRÉñáåõ0ÉÍ­?ñá%¦?åõí{0É!\0A^#V#{²( ÅåëË^Ìì?áÁìÉË?!ÿÿ"É?ñáåõÝååÝáÍ´B(MË^ M¯ÝwÝwÝååÝá++å##íCÉ?~q#Ë~(ëÝnÝfåËo ><ï( ÝfýuýtýåÝáý"–CÝNÝFÅýáx±(ÝåáÝ^ÝV·íB ÍsDÝuÝtÍfDý*–CÝåáÝ^ÝVíKP0¯íBÀýwýwÝ"P0ÉýnýfÝuÝtÉýnýfÝ^ÝVÉFREEÝåÅÕåë+F+N++Í›DáÑÁ˜DÝáÉëÝ!V0ÝnÝf|µ(åÝáíRÈ8îñ!åD>cïYP!òD>cï >ïá> ï!×D> ï!ÿÿåͤ?: BAD BLOCK X'xxxx', LEN X'xxxx' ýååÕý!V0ÕýáÍA!ÿÿ"É?͈6Á͈6á*É?ÝáÉ!Ý!("ê@îÝåͪBÝá(~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáÍ´B(RËN(NËv JT]åÝá:~0þ*(Ë^#ÄVHëÅyþ Ý~ÿæ />ïõÝ4þñëá }Ö ÝwþÝáÉëËöËî!Ë^(wÍA!ÿÿå >ï ÒÍÌ@ ô!Ë@ËÝ4þÕÝ^þÝ~ÿæ?Ëq(ö@ö€O>ïåÍAAñ"ê@áÉñáåõ&}íKB ¹0þ@Ðþ-.@Ð!ì@…oŒ•gn&ÉvA„A–A¦A·AËAâABBUnknown errorArg list too longNot a directoryInvalid argumentToo many open filesNot a character deviceMath arg oáìAut of domain of funcResult tooÍÒGÍ%GùGÍF½G+ýGÍFÚ½G+ýG!9###xî€G~Â?F+~¹Â?F+~ºÂ?F+~»!ÉÍÒG{¦_#z¦W#y¦O#x¦GùGÍÒGÍTG(###Ë+Ë+Ë+ËÍ„FèáÑÁé{/_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍTG˜F!À+ÉÝåõõÝ!Ý9;å~Ýw6#~Ýw6#~Ýw6#~Ýw6.xæ€ÂÙFËËËË,ÃÇFÝuÿÝåáÍtGåÍ GáÊíFÒôFÍGÍŽG7ãÍ7GÝ5ÿÊ largeI/O errorHñÑÕõ{þ@8Ö@o&þ 8l)dAÃVHöÀOýå>eïýËþýáZB>ïbk> Pí±+pëÉñáÑÝáÝåÕåõÝnÝf|µÉñÑÕõ!·È#ùÉÏBñÑÕõÝåýå!"ËBý!T0*T0ý"ÍBÝåýáÝnÝfåÝá|µ(7ÝnÝfí[ËB·íR8ÜGã¯ÍEGÃâFñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍŽGÃ%Gå~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õüŽG͆GòrGÍtGÍŽGÍtGñî€ÉñÉå~s_#~rW#~qO#~pGáÉå###~·áÉ{· ² ± æ˜Gxþ€Èå¯o›_}šW}™O}˜GáÉÍ´Gz·ð ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#pÉ!9ÉÍöGÈ+ÉÍöGÀ+ÉÍöGÐ+ÉëÍöGØ+ÉÍöGØ+É|î€íB0ÝnÝfýuýt ÝuÝtDMÝ ÝsÝr*ËBåÍcCÁ|¥< !#"ê@åÝáÝqÝpÝåÍøDágoýáÝáÉñÑÕõz³('!9íBíKP0íB8 íR8Åë "P0áÉ!#"ê@!ÿÿÉ*P0ɘCñÑÕõÝåýåͨCýáÝáÉ!D͆DÝ!üÿÝÍ-Eý!T0 ý"–Cýnýfåýáý^ýVz³(ÝåáíR0âÍfDÝåÁýqýpýå!T0Ñ·íR('ýnýf·íB ÍsDýuýtÝngz {½!ÉÍ HØ+Éz¼ÂH{½!ÉDM¯og>Ë#Ë0 =È)ÃHë¯íRÉ}£o|¢gÉëz³ÈË<ËöÍGH#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉý5•jèáÑÁé{/Šj_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍek!À+ÉÝåõõÝ!Ý9;å~Ýw6#~Ýw6#~Ýw6#~Ýw6.xæ€ÂêjËËËË,ÃØjÝuÿÝåáÍ…kåÍ~þ"(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( þ\ G#Ú#¯Á> ¾Ø> ¾È#õõÝåýå!9å! 9ÑÍEJ!9åÍ@J##ÑÍEJå!ÿÿ)ÑÍ@J"=9!CB"?9!9åÍ@J##ÑÍEJå!ÿÿ)ÑÍ@JåÝá!9åÝåáåÍÇ9ññåýáýåáå!9ÍVJ!9Í^JáñññÉ›¤8õÝåýå!9å! 9ÑÍEJ!9åÍ@J##ÑÍEJå!ÿÿ)ÑÍ@J"¢8!9åÍ@J##ÑÍEJåå!9åÍÖ0ññÑÍEJ!9Í@Jå!ÑÍÓI|µÊC4!å!9å*ÖBåÍŽ1ñññ!9å!K0å!Ž0åÍ,8ñññ!åÍAñ! 9å!9å!9å!åÍ2ññññ!9Í@Jå!ÑÍÓI|µÊ‚4!H0å!9åÍ©DññÙ4!9Í@Jå!E0å!9åͤ8ñññ!9Í@Jå!9Í@Jå!ÑÍJÑÍ@Jå!9å!Â49å!80å!9åͤ8ñññññ!9å!/0å!9åͤ8ñññ! 9å!ÿÿ)ÑÍ@JåÝá!"=9!)9"?9!9åÝåáåÍÇ9ññåýá*¢8ë}ýåáå!9ÍVJ!9Í^JáñññÉ*¢8#"¢8+å!9n&Ñ}É’90B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"C9!"A9*C9n&|µÊA*C9n&%ÍÙI|µÊ:*?9å*=9ãå*C9#"C9+n&ãåÍKJññ*A9#"A9à A!"Z9"X9"V9"T9"R9*C9#"C9n&€0ÃN7emt_system: %s ln -s %s %semt_system: %s rm -f %s%s/disk%s-%s%d4pemt_getddir: %s usage: mount [-l] file.dsk unit# <‚0fJ¬0²0¸0  Â0ÃN7ñáåõí(`iÈOíCÖBÉñáÁÅåõí*ÈOíCÖB!Éñáåõí+!ÈOíCÖB!ÿÿ!9åÍÅ0ñÑÍEJ! 9Í@Jå!ÑÍÙI|µÊ=5!å!9å*ÖBåÍŽ1ñññ!9å!0å!Ž0åÍ,8ñññ!åÍAñ!9å!9ÑÍEJ!9å!9Í@Jå! 9Í@JÍJÑÍ@JÑÍEJ!9Í@J|µÊz6!9Í@Jn&|µÊw6!9Í@Jn&å![ÑÍÓI|µÊ¯5!9Í@Jå!Ñn&|µÊú5!9åÍ@JÑÍÂ5EJÿÿ!9åÍ@JÑÍEJÿÿå!9åÍ@JÑÉñáÁÑÕÅåõí0bkÈOíCÖBÉñÑÕõí1!ÈOíCÖB!ÿÿÉñÑáÁÅåÕõí2`iÈOíCÖBÉñÑáÁÅåÕõí3`iÈOíCÖBÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o"ÖBÉñÑáÁÅåÕõ{í5`iÈOíCÖBÉñáåõ}í6Éñáåõí7bkÈOíCÖBÉñÑÕõíÂ18!ÈOíCÖB!ÿÿÉñÑáÁÅåÕõí9`iÈOíCÖBÉñáåõí:!ÈOíCÖB!ÿÍEJÿÿn&Ñ}Ãt6!9Í@Jn&åÍgGñ|µÊE6!9åÍ@JÑÍEJÿÿå!9åÍ@JÑÍEJÿÿn&åÍQGñÑ}Ãt6!9åÍ@JÑÍEJÿÿå!9åÍ@JÑÍEJÿÿn&Ñ}Ãy5û6!9Í@Jn&|µÊ»6!9åÍ@JÑÍEJÿÿå!9åÍ@JÑÍEJÿÿn&Ñ}Ãz6!9Í@JÂ6å!Ñ}!9å!9å!0å!9åͤ8ññññ! ÿÉñáÁÅåõí;ÈOíCÖB!Éñáåõ}í<ÉÝåÝ!Ý9ÝnÝfN#FÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfs#rÑÝnÝfs#rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o"ÖBÉñáÁÑÕÅåõí>bkÈOíCÖBÉñÑÕõí?!ÈOíCÖB!ÿÿÉ!Â2\0å!Ž0åÍ,8ññ!åÍAñÉê÷ÍOJ!9Í@Jå!ÑÍìI|µÊô2ÍÁ2!9å!9åÍÅ0ñÑÍEJ! 9Í@Jå!ÑÍÙI|µÊ77!å!9å*ÖBåÍŽ1ñññ!9å!0å!Ž0åÍ,8ñññ!åÍAñ!åÍ2ñ!åÍAñÍOJÉís¾0íC¼0>d!Eï"À0ë!ÿóíRë0 >eïý~þ` !ÿóùÍ„7Í×2!åÍA*ˆ0"~0"€0KI>Rï"­0DO>Rï"³0"¹0*¼0í[~0Í!8( Õ Íß7 òÅÝáË!ëâÂ7 "~0"€0Ë9AÑ+r+sùÁåÝåÅÉÔEÃËDÅ9å!ÑÍEJ!9Í@Jå!9Í@JÍJÑÍ@Jå!Ñn&å!-ÑÍÓI|µÊ…3!9Í@Jå!9Í@JÍJÑÍ@Jå!Ñn&åÍQGñå!lÑÍÙI|µÊh3ÍÁ2!9åÍ@J#ÑÍEJ+!9å!ÑÍEJÑ3!9å!ÑÍEJ!9Í@Jå!9Í@JÑÍ'Jå!ÑÍÙI|µÂâ3!9Í@Jå!9Í@Jå!Â3ÑÍJÑÍ@Jå!Ñn&åÍzGñÍ8J|µÊê3ÍÁ2!9å!ÍJÂ2<Ã;<ï( ÍC!ÿÿ"µAÍÙ7ÁÍ9"\9!†9;IÅÕ€ÍH|µÊN=!†9;IÍŠI!†9ÍÆIÃp=*R9|µÊb=!Â9"\9Ãp=*V9|µÊp=!À9"\9*Z9|µÊ§=õ!9å*I9å*\9å͹DñÑÍ'JÑÍEJ’=áåå*K9ÑÍåI|µÊ¦=áå"K9ñ:M9o&XÍÓI|µÊ¾=!¯9ÃÄ=!ž9ÃÄ="Š9!^9("E9"G9!†9;IÍ‘H|µÊr>!†9;IÅÕÍ?Hë"9!†9;IÅÕÍTHÅÕ€ÍsHÍ?H!†9ÍÆI*E9+"Ù7á*µAÝáÉ!Ý!("ÖBîÝåÍ–DÝá(~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáÍ D(RËN(NËv JT]åÝá:¬0þ*(Ë^#Ä@JëÅyþ Ý~ÿæ />ïõÝ4þñëá }Ö ÝwþÝáÉëËöËî!Ë^(wÍC!ÿÿå >ï Ò͸B ô!·BËÝ4þÕÝ^þÝ~ÿæ*E9å’>*G9ÑÍÙI|µÊ?:M9o&åÑ!oÍJÂÇ>*N9ëÍìI|µÊÄ>!"N9Ã?!xÍJÂÙ>!›9"\9Ã?!XÍJÂë>!˜9"\9Ã?!bÍJÂý>!•9"\9Ã?!BÍJÂ?!’9"\9Ã?Ãü?!cÍJÂM?!^No&ËA(þ@8>?Ëq(ö@ö€O>ïåÍ-Cñ"ÖBáÉñáåõ&}íKD ¹0þ@Ðþ-.@Ð!ØB…oŒ•gn&ÉbCpC‚C’C£C·CÎCíCþCUnknown errorArg list too longNot a directoryInvalid argumentToo many open filesNot a character deviceMath arg oñØCut of domain of funcResult too largeI/O erråÑ!+ÍJÂE:!"R9Ã':!-ÍJÂW:!"T9Ã':! ÍJÂi:!"V9Ã':!#ÍJÂ{:!"X9Ã':!0ÍJÂ:!"Z9Ã':*C9n&’:*ÍÓI|µÊã:ñÁáåÅõåÍ@J##ÑÍEJå!ÿÿ)ÑÍ@J"I9*I9ëÍìI|µÊÙ:*I9Í,J"I9!"T9*C9#"C9Ã;!"I9*C9n&åÍzGñ|µÊ;*I9 ÍJå*C9#"C9+n&åÍvAñÑ"I9Ãé:*C9n&.ÍÓI|µÊ£;*9å!9Í@JåÍ@J##ÑÍEJå!ÿÿ)ÑÍ@JÑ}!^9"E9*E9#"G9Ãü?!sÍJÂÖ?ñÁáåÅõåÍ@J##ÑÍEJå!ÿÿ)ÑÍ@J"E9*K9ëÍìI|µÊˆ?!ÿ"K9!"Œ9Ø?*’?Œ9#"Œ9*E9#"E9+n&|µÊ³?*Œ9å*K9ÑÍìI|µÊ»?Ñ?*E9+"E9"G9*E9å*Œ9ÑÍ'J"E9Ãü?!ÍJÂé?*C9+"C9Ãü?!M9"E9"G9*G9#"G9Ãü?:M9o&|µÊ Aõ!9å*I9å*G9å*E9ÑC9#"C9n&*ÍÓI|µÊh;ñÁáåÅõåÍ@J##ÑÍEJå!ÿÿ)ÑÍ@J"K9*C9#"C9à;!"K9*C9n&åÍzGñ|µÊ ;*K9 ÍJå*C9#"C9+n&’;åÍvAñÑ"K9Ãn;é;!ÿÿ"K9!"P9*C9n&åÑ!lÍJÂÉ;!"P9ÃÒ;!hÍJÂÙ;*C9#"C9!"N9!Æ9"\9*C9#"C9+n&}2M9åÑ!dÍJÂ<à Ë#Ë0 =È)ÃJë¯íRÉÍ1J#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉN7ëÅÉ~#foåÝáÉ~#foåýáÉLY last byte of driver. ;*=*=* relo: ld hl,(newend) ld iy,reltab ;Point to relocation tbl ld de,dvÝnÝfýuýtýåÝáý"’EÝNÝFÅýáx±(ÝåáÝ^ÝV·íB ÍoFÝuÝtÍbFý*’EÝåáÝ^ÝVíK~0¯íBÀýwýwÝ"~0ÉýnýfÝuÝtÉýnýfÝ^ÝVÉFREEÝåÅÕåë+F+N++Í—FáÑÁ”FÝáÉëÝ!„0ÝnÝf|µ(åÝáíRÈ8îñ!áF>cïYP!îF>cï >ïá> ï!ÓF> ï!ÿÿåÍA: BAD BLOCK X'xxxx', LEN X'xxxx' ýååÕý!„0Õååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý!„0Õýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌñÑÕõÕÕÍŠGÁÑëz³È}ö &oÉñáåõ}!ö þa8þ{Ø+Éñáåõ}!þ0Øþ:Ð#Éñáåõ}!þA”GØþ[Ð#ÉÍÎIÍPIʵIÍ‚IõÍUIÍšHñüŠIõIÍÎIÍPIʵIÍUIõÍšHñáÑÁüŠIéÍÎIÅÕå!9PXå~#¶#¶#¶áÊ÷G¯ÍAIãÜ!I¯Í3IãÃÛGñññÃååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååµIÍÎIÍ!IõIÍH¹I+ùIÍHÚ¹I+ùI!9###xî€G~Â;H+~¹Â;H+~ºÂ;H+~»!ÉÍÎI{¦_#z¦W#y¦O#x¦GõIÍÎIÍPI(###Ë+Ë+Ë+ËÍ€HèáÑÁé{/_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍPI”H!À+ÉÝåõõÝ!Ý9;å~Ýw6#~Ýw6#~Ýw6#~Ýw6.xæ€ÂÕHËËËË,ÃÃHÝuÿÝåáÍpIåÍ IáÊéHÒðHÍIÍŠI7ãÍ3IÝ5ÿååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååorHñÑÕõ{þ@8Ö@o&þ 8l)PCÃ@JöÀOýå>eïýËþýáFD>ïbk> Pí±+pëÉñáÑÝáÝåÕåõÝnÝf|µÉñÑÁÅÕõbk ·ÈøñÑÕõ!·È#ùÉËDñÑÕõÝåýå!"ÇDý!‚0*‚0ý"ÉDÝåýáÝnÝfåÝá|µ(7ÝnÝfí[ÇD·íR9åÍœ0ñÑÍG!9ÍGå!ÑÍ©F|µÊ@4!å!9å*ß?åÍe1ñññ!9å!0å!e0åÍ55ñññ!åÍ–>ñ!åÍç1ñ!åÍ–>ñÍGÉís•0íC“0>d!Eï"—0ë!ÿóíRë0 >eïý~þ` !ÿóùÍ4Í®2!åÍ–>*_0"U0"W0KI™4>Rï"„0DO>Rï"Š0"0*“0í[U0Í*5( Õ Íè4 òÅÝáË!ë "U0"W0Ë9AÑ+r+sùÁåÝåÅÉÃBÃÔAÅ~þ"ÍØFÂ;9ÃD9!xÍØFÂM9!"—6Ãh9!BÍØFÂY9Ãb9!bÍØF ¾Ø> ¾È#õõÝåýå!9å! 9ÑÍG!9åÍG##ÑÍGå!ÿÿ)ÑÍG"F6!L?"H6!9åÍG##ÑÍGå!ÿÿ)ÑÍGåÝá!9åÝåáåÍÐ6ññåýáýåáå!™59Í&G!9Í.GáñññÉ›­5õÝåýå!9å! 9ÑÍG!9åÍG##ÑÍGå!ÿÿ)ÑÍG"«5!9åÍG##ÑÍGÿÉñÑáÁÅåÕõí2`iÈOíCß?ÉñÑáÁÅåÕõí3`iÈOíCß?ÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o"ß?ÉñÑáÁÅåÕõ{í5`iÈOíCß?Éñáåõ}í6Éñáåõí7bkÈOíCß?ÉñÑÕõí™18!ÈOíCß?!ÿÿÉñÑáÁÅåÕõí9`iÈOíCß?Éñáåõí:!ÈOíCß?!ÿÿÉñáÁÅåõí;ÈOíCß?!Éñáåõ}í<ÉÝåÝ!Ý9Ýnå!ÿÿ)ÑÍGåÝá!"F6!26"H6!9åÝåáåÍÐ6ññåýá*«5ë}ýåáå!9Í&G!9Í.GáñññÉ*«5#"«5+å!9n&Ñ}É›60B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"L6!"J6*L6n&|µÊ>*L6n&%Í©F|µÊ7*H6å*F6ãå*L6#"L6+n&ãåÍGññ*J6#"J6Ã>!"c6"a6"_6"]6"[6*L6#"L6n&ÝfN#FÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfs#rÑÝnÝfs#rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o"ß?ÉñáÁÑÕÅåõí>bkÈOíCß?ÉñÑÕõí?!ÈOíCß?!ÿÿÉ!™2@0å!e0åÍ55ññ!åÍ–>ñÉòøÍG!9ÍGå!ÑÍ©F|µÂï2!9ÍGå!ÍãFÑÍGå!Ñn&åÍZDñÍG|µÊ÷2͘åÑ!+ÍØFÂN7!"[6Ã07!-ÍØFÂ`7!"]6Ã07! ÍØFÂr7!"_6Ã07!#ÍØF„7!"a6Ã07!0ÍØF–7!"c6Ã07*L6n&›7*Í£F|µÊì7ñÁáåÅõåÍG##ÑÍGå!ÿÿ)ÑÍG"R6*R6ëͼF|µÊâ7*R6ÍüF"R6!"]6*L6#"L6Ã$8!"R6*L6n&åÍZDñ|µÊ$8*R6 ÍãFå*L6#"L6+n&åÍ>ñÑ"R6Ãò7*L6n&.Í£F|µÊ¬82!9å!å!9åÍ­0ññÑÍG!9ÍGå!ÑÍ£F|µÊP3!å!9å*ß?åÍe1ñññ!9å!/0å!e0åÍ55ñññ!åÍ–>ñ!9å!9å! 9å!åÍï1ññññ!9ÍGå!ÑÍ£F|µÊ3!,0å! 9åͲAññæ3!9ÍGå!)™30å!9åÍ­5ñññ!9ÍGå!ÍãFÑÍGå! 9å!9å!0å!9åÍ­5ñññññ!9å!0å!9åÍ­5ñññ!9å!*L6#"L6n&*Í£F|µÊq8ñÁáåÅõåÍG##ÑÍGå!ÿÿ)ÑÍG"T6*L6#"L6é8!"T6*L6n&åÍZDñ|µÊ©8*T6 ÍãFå*L6#"L6+n&›8åÍ>ñÑ"T6Ãw8ò8!ÿÿ"T6!"Y6*L6n&åÑ!lÍØFÂÒ8!"Y6ÃÛ8!hÍØFÂâ8*L6#"L6!"W6!Ï6"e6*L6#"L6+n&}2V6åÑ!dÍØF 9Ã9!uÍØFÂ9!"—6Ãh9!oÍØFÂ/9!"—6Ãh9!XrorHñÑÕõ{þ@8Ö@o&þ 8l)Y@ÃGöÀOýå>eïýËþýáOA>ïbk> Pí±+pëÉñáÑÝáÝåÕåõÝnÝf|µÉñÑÁÅÕõbk ·ÈøñÑÕõ!·È#ùÉÔAñÑÕõÝåýå!"ÐAý!Y0*Y0ý"ÒAÝåýáÝnÝfåÝá|µ(7ÝnÝfí[ÐA·íÑÍ÷FÑÍ÷Få*W6ëͼF|µÊ?=!ÃE=*W6ÃE=ÑÍ÷Få*e6åÍÂAñÑÍ÷FÑÍG*]6ÍG|µÊ‰=!9åÍG+ÑÍGëͯF|µÊ‰=! åÍ:>ñÃe=*e6n&|µÊ§=*e6#"e6›=+n&åÍ:>ñÉ=*W6+"W6ëͯF|µÊÅ=!0åÍ:>ñç=*N6å*P6ÑÍÒF|µÊè=*N6#"N6+n&åÍ:>ñÃÅ=*]6|µÊ>!9åÍG+ÑÍGëͯF|µÊ>! åÍ:>ñÃð=ñÃÝ6*F6|µR8ÜíB0ÝnÝfýuýt ÝuÝtDMÝ ÝsÝr*ÐAåÍhBÁ|¥< !#"ß?åÝáÝqÝpÝåÍýCágoýáÝáÉñÑÕõz³('!9íBíKU0íB8 íR8Åë "U0áÉ!#"ß?!ÿÿÉ*U0ÉBñÑÕõÝåýåÍ­BýáÝáÉ!†CÍ‹CÝ!üÿÝÍ2Dý!Y0 ý"›Býnýfåýáý^ýVz³(ÝåáíR0âÍkCÝåÁýqýpýå!Y0Ñ·íR('ýnýf·íB ÍxCýuýtÊ(>*F6åÍ-?ñ|µÊ3>!ÿÿÃ9>*J6Ã9>É*H6å*F6ãå!9n&ãåÍGññ*J6#"J6Éñáåõå!9ÍGÑͼF|µÊu>ñáåõÃ~>ñÁáåÅõÃ~>É!9n&0·íRÉñáåõ0ÉÍ¢>ñá%›>åõí{•0É!a0A^#V#{²( ÅåëË^Ìá>áÁìÉÀ>!ÿÿ"¾>ñáåõÝååÝáÍ©A(MË^ M¯ÝwÝwÝååÝá++å##íC¾>~q#Ë~(ëÝnÝfåËo ><ï( Í@!ÿÿ"¾>Íâ4ÁÝnÝfýuýtýåÝáý"›BÝNÝFÅýáx±(ÝåáÝ^ÝV·íB ÍxCÝuÝtÍkCý*›BÝåáÝ^ÝVíKU0¯íBÀýwýwÝ"U0ÉýnýfÝuÝtÉýnýfÝ^ÝVÉFREEÝåÅÕåë+F+N++Í CáÑÁCÝáÉëÝ![0ÝnÝf|µ(åÝáíRÈ8îñ!êC>cïYP!÷C>cï >ïá> ï!ÜC> ï!ÿÿåÍ™>: BAD BLOCK X'xxxx', LEN X'xxxx' ýååÕý![0Í6"e6!6ÍŽFÅÕ€ÍÖD|µÊW:!6ÍŽFÍZF!6Í–FÃy:*[6|µÊk:!Ë6"e6Ãy:*_6|µÊy:!É6"e6*c6|µÊ°:õ!9å*R6å*e6åÍÂAñÑÍ÷FÑÍG›:áåå*T6Ñ͵F|µÊ¯:áå"T6ñ:V6o&XÍ£F|µÊÇ:!¸6ÃÍ:!§6ÃÍ:"“6!g6("N6"P6!6ÍŽFÍaE|µÊ{;!6ÍŽFÅÕÍEë"™6!6ÍŽFÅÕÍ$EÅÕ€ÍCEÍE!6Í–F*N6+Íâ4á*¾>ÝáÉ!Ý!("ß?îÝåÍŸAÝá(~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáÍ©A(RËN(NËv JT]åÝá:ƒ0þ*(Ë^#ÄGëÅyþ Ý~ÿæ />ïõÝ4þñëá }Ö ÝwþÝáÉëËöËî!Ë^(wÍ@!ÿÿå >ï ÒÍÁ? ô!À?ËÝ4þÕÝ^þÝ~ÿæ?Ëq(ö@ö€O>ïåÍ6@ñ"ß?áÉñáåõ&}íKA ¹0þ@Ðþ-.@Ð!á?…oŒ•gn&Ék@y@‹@›@¬@À@×@ö@AUnknown errorArg list too longNot a directoryInvalid argumentToo many open filesNot a character deviceMath arg oñá@ut of domain of funcResult too largeI/O erg6å!9ÍGåÍG##ÑÍGå!ÿÿ)ÑÍGÑ}!g6"N6*N6#"P6Ã=!sÍØFÂß<ñÁáåÅõåÍG##ÑÍGå!ÿÿ)ÑÍG"N6*T6ëͼF|µÊ‘õ!9å*R6å*P6å*N6~ºÂ E+~»!ÉÍžF{¦_#z¦W#y¦O#x¦GÃ…FÍžFÍ F(###Ë+Ë+Ë+ËÍPEèáÑÁé{/_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGÉÍ F!À+ÉÝåõõÝ!Ý9;å~Ýw6#~Ýw6#~Ýw6#~Ýw6.xæ€Â¥EËËEËË,ÓEÝuÿÝåáÍ@FåÍÙEáʹEÒÀEÍëEÍZF7ãÍFÝ5ÿÊÒEã¯ÍFîEñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍZFÃñEå~ƒ_#~ŠW#~‰O#~Ý!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9ÝNÝFí4ÑÁááÝáÈ&o"ê>ÉñÑáÁÅåÕõ{í5`iÈOíCê>Éñáåõ}í6Éñáåõí7bkÈOíCê>ÉñÑÕõík18!ÈOíCê>!ÿÿÉñÑáÁÅåÕõí9`iÈOíCê>Éñáåõí:!ÈOíCê>!ÿÿÉñáÁÅåõí;ÈOíCê>!Éñáåõ}í<ÉÝåÝ!Ý9ÝnÝfN#FÝnÝf^#VÝnÝf~#foÝ~í<åÝnÝfq#pÝnÝfˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õüZFÍRFò>FÍ@FÍZFÍ@Fñî€ÉñÉå~s_#~rW#~qO#~pGáÉå###~·áÉ{· ² ± xþ€Èå¯o›_}šW}™O}˜GáÉÍ€Fz·ð ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#p›FÉ!9ÉÍÂFÈ+ÉÍÂFÀ+ÉÍÂFÐ+ÉëÍÂFØ+ÉÍÂFØ+É|î€gz {½!ÉÍØFØ+Éz¼ÂßF{½!ÉDM¯og>Ë#Ë0 =È)ÃêFë¯íRs#rÑÝnÝfs#rëÝáÉÝåÝ!Ý9Ý^ÝV!ååÝnÝfåÝnÝfå!9í=ÑÁááÝáÈ&o"ê>ÉñáÁÑÕÅåõí>bkÈOíCê>ÉñÑÕõí?!ÈOíCê>!ÿÿÉ!k20å!70åÍÛ4ññ!åÍ¡=ñÉôÿÍÀG!9ͱGå!ÑÍDG|µÊ©2!9å!ÑͶGÃ^3!9ͱGå!ÑÍDG|µÊá2!9ͱGå!Í„GÑͱGå!Ñn&åÍ×Dñ|µÊ[3!9å!ÑͶG!9ÉÍG#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉW4(äÝåáíR8Ý êÝnÝfÌñÑÕõÕÕÍŠGÁÑëz³È}ö &oÉñáåõ}!ö þa8þ{Ø+Éñáåõ}!þ0Øþ:Ð#Éñáåõ}!þA”GØþ[Ð#ÉÍÎIÍPIʵIÍ‚IõÍUIÍšHñüŠIõIÍÎIÍPIʵIÍUIõÍšHñáÑÁüŠIéÍÎIÅÕå!9PXå~#¶#¶#¶áÊ÷G¯ÍAIãÜ!I¯Í3IãÃÛGñññÃͱGå!Í„GÑͱGåÍ)Bñå!ÑÍJG|µÊ3Íj2! 9å!9ͱGå!Í„GÑͱGåͽ@ñÑͶG! 9ͱGå!ÑÍVG|µÊX3Íj2Ã^3Íj2!9å! 9å!k39å!9ͱGåÍÁ1ññññ! 9ͱGå!0åÍz4ññ!åÍ¡=ñ ÍÀGÉísg0íCe0>d!Eï"i0ë!ÿóíRë0 >eïý~þ` !ÿóùÍÒ3Í€2!åÍ¡=*10"'0")0KI>Rï"V0DO>Rï"\0"b0*eåååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå0í['0Ío4( Õ Í-4 òÅÝáË!ë "'0")0Ë9AÑ+r+sùÁåÝåÅÉÃCÃ;BÅ~þ"(þ' #Ox·(y~þ 8"þ!0 ( ( ¹( þ\ G#Ú#èk4¯Á> ¾Ø> ¾È#õõÝåýå!9å! 9ÑͶG!9åͱG##ÑͶGå!ÿÿ)ÑͱGåÝá!50"Q5!W>"S5!9åÝåáåÍÛ5ññåýáýåáå!9ÍÇG!9ÍÏGáñññÉõÝåýå!9å! 9ÑͶG!Õýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý![0Õýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌñáåõ}!þ0Øþ:Ð#ÉÍžFÍ FÊ…FÍRFõÍ%FÍjEñüZFÃ…FÍžFÍ FÊ…FÍ%FõÍjEñáÑÁüZFéÍDžFÅÕå!9PXå~#¶#¶#¶áÊÇD¯ÍFãÜñE¯ÍFãëDñññÃ…FÍžFÍñEÃ…FÍêD‰F+ÉFÍêDÚ‰F+ÉF!9###xî€G~ E+~¹Â E+)0Ü3truedam = %d usage: truedam [0|1] <+0×GU0[0a0  k0Ü3ñáåõí(`iÈOíCê>ÉñáÁÅåõí*ÈOíCê>!Éñáåõí+!ÈOíCê>!ÿÿÉñáÁÑÕÅåõí0bkÈOíCê>ÉñÑÕõí1!ÈOíCê>!ÿÿÉñÑáÁÅåÕõí2`iÈOíCê>ÉñÑáÁÅåÕõí3`iÈOíCê>ÉÝå=Í'4ÁÍ'4á*É=ÝáÉ!Ý!("ê>îÝåͪ@Ýá(~æ (!Ë^(n&ÉíbÉñÁáåÅõÝååÝáÍ´@(RËN(NËv JT]åÝá:U0þ*(Ë^#ıGëÅyþ Ý~ÿæ />ïõÝ4þñëá }Ö ÝwþÝáÉëËöËî!Ë^(wÍ?!ÿÿå >ï ÒÍÌ> ô!Ë>ËÝ4þÕÝ^þÝ~ÿæHHHHHHHHHHHHHHCHHHHHCC"##%'C9åͱG##ÑͶGå!ÿÿ)ÑͱG"Q5!W>"S5!9åͱG##ÑͶGå!ÿÿ)ÑͱGåÝá!9åÝåáåÍÛ5ññåýáýåáå!9ÍÇG!9ÍÏGáñññɦ50B0b0X0x0123456789abcdef0123456789ABCDEF +-ñáåõ"W5!"U5*W5n&|µÊ#=*W5n&%ÍJG|µÊ)6*S5å*Q5ãå*W5#"W5+n&ãåͼGññ*U5#"U5à =!"n5"l5"j5"h5"f5*W5#G*Y5+"Y5å*ž5å!š5Í/GÅÕ*¢5ÍGÍ EÅÕÍ=EÅÕ*¤5ÍGÍnEëÑn&Ñ}!š5Í/GÅÕ*¢5ÍGÍ%E!š5Í7GÃè9*Y5å*[5Ñ͘Gå*_5Ñ"b5*l5|µÊ­:*Y5å¦:*[5ÑÍJG|µÊ#;:a5o&åÑ!oÍyGÂÛ:*b5ëÍ]G|µÊØ:!"b5Ã#;!xÍyGÂí:!¯5"p5Ã#;!XÍyGÂÿ:!¬5"p5Ã#;!bÍyGÂ;!©5"p5Ã#;!BÍyGÂ#;!¦5"p5Ã#;Ãñ|µÊ>=!ÿÿÃD=*U5ÃD=É*S5å*Q5ãå!9n&ãåͼGññ*U5#"U5Éñáåõå!9ͱGÑÍ]G|µÊ€=ñáåõÉ=ñÁáåÅõÉ=É!9n&0·íRÉñáåõ0ÉÍ­=ñá%¦=åõí{g0É!30A^#V#{²( ÅåëË^Ìì=áÁìÉË=!ÿÿ"É=ñáåõÝååÝáÍ´@(MË^ M¯ÝwÝwÝååÝá++å##íCÉ=~q#Ë~(ëÝnÝfåËo ><ï( Í?!ÿÿ"ɵÊe9!Ø5"p5!š5Í/GÅÕ€ÍwE|µÊb9!š5Í/GÍûF!š5Í7GÄ9*f5|µÊv9!Ö5"p5Ä9*j5|µÊ„9!Ô5"p5*n5|µÊ»9õ!9å*]5å*p5åÍ)BñÑ͘GÑͶG¦9áåå*_5ÑÍVG|µÊº9áå"_5ñ:a5o&XÍDG|µÊÒ9!Ã5ÃØ9!²5ÃØ9"ž5!r5("Y5"[5!š5Í/GÍF|µÊ†:!š5Í/GÅÕͰEë"¤5!š5Í/GÅÕÍÅEÅÕ€ÍäEͰE!š5Í7Í÷Dñ|µÊ$B!9åͱG#ÑͶGÃBñáåõÉñÑÕõ!·È#ùÉ;BñÑÕõÝåýå!"7Bý!+0*+0ý"9BÝåýáÝnÝfåÝá|µ(7ÝnÝfí[7B·íR8ÜíB0ÝnÝfýuýt ÝuÝtDMÝ ÝsÝr*7BåÍÏBÁ|¥< !#"ê>åÝáÝqÝpÝåÍdDágoýáÝáÉñÑÕõz³('!9íBíK'0íB8 íR8Åë "'0áÉ!#"ê>!ÿÿÉ*'0ÉCñÑÕõÝ ² ± ÕGxþ€Èå¯o›_}šW}™O}˜GáÉÍ!Gz·ð ÉëÉáññéñÑÁõÉ^#V#N#FÉs#r#q#pÉ!9ÉÍcGÈ+ÉÍcGÀ+ÉÍcGÐ+ÉëÍcGØ+ÉÍcGØ+É|î€gz {½!ÉÍyGØ+Éz¼Â€G{½!ÉDM¯og>Ë#Ë0 =È)ËGë¯íRÉÍ¢G#É|/g}/oÉ|µ!À#É~#foÉ}|ÉñáõéÁë9ùëÅÉ~#foåÝáÉ~#foåýáÉœ3#¶#¶#¶áÊ÷G¯ÍAIãÜ!I¯Í3IãÃÛGñññÃåýåÍCýáÝáÉ!íCÍòCÝ!üÿÝÍ™Dý!+0 ý"Cýnýfåýáý^ýVz³(ÝåáíR0âÍÒCÝåÁýqýpýå!+0Ñ·íR('ýnýf·íB ÍßCýuýtÝnÝfýuýtýåÝáý"CÝNÝFÅýáx±(ÝåáÝ^ÝV·íB ÍßCÝuÝtÍÒCý*CÝåáÝ^ÝVíK'0¯íBÀýwýwÝ"'0ÉýnýfÝuÝtÉýnýfÝ^ÝVÉFREEÝåÅÕåë+F+N++ÍDáÑÁDÝååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååCCå!/0No&ËA(þ@8>?Ëq(ö@ö€O>ïåÍA?ñ"ê>áÉñáåõ&}íK@ ¹0þ@Ðþ-.@Ð!ì>…oŒ•gn&Év?„?–?¦?·?Ë?â?@@Unknown errorArg list too longNot a directoryInvalid argumentToo many open filesNot a character deviceMath arg oì?ut of domain of funcResult too largeIáÉëÝ!-0ÝnÝf|µ(åÝáíRÈ8îñ!QD>cïYP!^D>cï >ïá> ï!CD> ï!ÿÿåͤ=: BAD BLOCK X'xxxx', LEN X'xxxx' ýååÕý!-0Õýáý^ýVz³( ÝåáíR(0êÝsÝrÝåáýuýt´ÑáýáÉýååÕý!-0Õýáý^ýVz³(äÝåáíR8Ý êÝnÝfÌñÑÕõÕÕÍçDÁÑëz³È}î &oÉñáåõ}!þ0Øþ:Ð#Éñáåõ}!þaØþ{Ð#Éñáåõ}!þ È-þ/O errorHñÑÕõ{þ@8Ö@o&þ 8l)d?ñGöÀOýå>eïýËþýáZ@>ïbk> Pí±+pëÉñáÑÝáÝåÕåõÝnÝf|µÉõõ!9å!9ͱGåÍBñÑͶG!9å!9ͱGn&-ÍDGÑͶì@G|µÊÿ@!9åͱG#ÑͶG!9å!¾Aå!×Då! E ØþÐ,ÉÍ?GÍÁFÊ&GÍóFõÍÆFÍ FñüûFÃ&GÍ?GÍÁFÊ&GÍÆFõÍ FñáÑÁüûFéÍ?GÅÕå!9PXå~#¶#¶#¶áÊhE¯Í²FãÜ’F¯Í¤FãÃLEñññÃ&GÍ?GÍ’FÃ&GÍ‹EÂ*G+Ã*GÍ‹EÚ*G+Ã*G!9###xî€G~¬E+~¹Â¬E+~ºÂ¬E+~»!ÉÍ?G{¦_#z¦W#y¦O#x¦GÃ&GÍ?GÍÁF(###Ë+Ë+Ë+ËÍñEèáÑÁé{/_z/Wy/Ox/GÉ{Ö_zÞWyÞOxÞGå!9ͱGåÍ>AññññÑͶGáå|µÊ4AñáåõÍGÃ;AñáåõÃ;AññÉõ!9ëͶG!9å!9ͱGåÍBñÑͶG!9ͱGå!9ͱGn&ãåͼGñ|µÊºA!9åñáåõå! 9ͱGÑÍ„Gå!9ͱGå! 9åͱG#ÑͶG+n&ãåͼGñÑÑͶGÃ_AáåñÉ!9n&0·íRÉ!9n&åÍ×Dñ|µÊíA!9n&0·íRÃMìAB!9n&åÍÁDñ7·íRÃBÉñáåõn&åÉÍÁFF!À+ÉÝåõõÝ!Ý9;å~Ýw6#~Ýw6#~Ýw6#~Ýw6.xæ€ÂFFËËËË,Ã4FÝuÿÝåáÍáFåÍzFáÊZFÒaFÍŒFÍûF7ãͤFÝ5ÿÊsFã¯Í²FÃOFñ3ññÝáÉ###~¸À+~¹À+~ºÀ+~»ÉÍûFÃ’Få~ƒ_#~ŠW#~‰O#~ˆGáÉåË#Ë#Ë#ËáÉ###Ë+Ë+Ë+ËÉx±²³Éx·õüûFÍóFòßFÍáFÍûFÍáFñî€ÉñÉå~s_#~rW#~qO#~pGáÉå###~·áÉ{·/cmd:#D# unix/cmd:#D# rename mount6/cmd:#D# mount/cmd:#D# rename umount6/cmd:#D# umount/cmd:#D# rename truedam6/cmd:#D# truedam/cmd:#D# N + 1 200 GET 1 220 IF (ASC(AT$) AND 16) = 0 THEN GOTO 160 240 I=INSTR(NM$, " ") 260 IF I THEN NH$ = LEFT$(NM$, I-1) ELSE NH$ = NM$ 280 I = INSTR(NX$, " ") 300 IF I THEN NT$ = LEFT$(NX$, I-1) ELSE NT$ = NX$ 320 REM print n; " "; 340 NF$ = NH$ + "/" + NT$ 360 PRINT NF$ 380 UF$ = NH$ + "." + NT$ 400 CMD "export -l " + NF$ + ".rs0lt0ff:" + DR$ + " " + UF$ 420 GOTO 160 ÑͶG!9åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå20 CLEAR 1000 40 REM-- List an LDOS directory by opening and reading DIR/SYS 50 REM-- and use the xtrs export program to export all files 60 LINE INPUT "Drive? "; DR$ 80 OPEN "ri", 1, "dir/sys.rs0lt0ff:" + DR$, 32 100 FIELD 1, 1 AS AT$, 1 AS FL$, 1 AS DT$,. Avoid running Model I/III-only xtrs utilities on Model 4 remove cd/cmd:#D# remove pwd/cmd:#D# remove unix/cmd:#D# remove mount/cmd:#D# remove umount/cmd:#D# remove truedam/cmd:#D# rename cd6/cmd:#D# cd/cmd:#D# rename pwd6/cmd:#D# pwd/cmd:#D# rename unix6 1 AS EF$, 1 AS RL$, 8 AS NM$, 3 AS NX$, 2 AS OP$, 2 AS UP$, 2 AS ER$, 10 AS XT$ 120 GET 1, 16 140 N = 0 160 IF EOF(1) THEN END 180 N = N + 1 200 GET 1 220 IF (ASC(AT$) AND 16) = 0 THEN GOTO 160 240 I=INSTR(NM$, " ") 260 IF I THEN NH$ = LEFT$(NM$, I-1) ELSååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååxtrs-4.9d/utility.jcl000066400000000000000000000024771306603614600147460ustar00rootroot00000000000000. Note: Use TRSDOS 6.2.1 to get old-style dates and . thus avoid password problems with other DOSes. format :#d#(sden,sides=1,cyl=80,dir=17,name="xtrsutil",q=n,abs) import export.cmd export/cmd:#D# import -n export.z80 export/z80:#D# import import.cmd import/cmd:#D# import -n import.z80 import/z80:#D# import -n settime.z80 settime/z80:#D# import settime.cmd settime/cmd:#D# import -n xtrsemt.ccc xtrsemt/ccc:#D# import -n xtrsemt.h xtrsemt/h:#D# import -n settime.ccc settime/ccc:#D# import -n m1format.fix m1format/fix:#D# import xtrshard.dct xtrshard/dct:#D# import -n xtrshard.z80 xtrshard/z80:#D# import xtrs8.dct xtrs8/dct:#D# import -n xtrs8.z80 xtrs8/z80:#D# import xtrsmous.cmd xtrsmous/cmd:#D# import -n xtrsmous.z80 xtrsmous/z80:#D# import -n cd.ccc cd/ccc:#D# import -n pwd.ccc pwd/ccc:#D# import -n unix.ccc unix/ccc:#D# import -n mount.ccc mount/ccc:#D# import -n umount.ccc umount/ccc:#D# import cd.cmd cd/cmd:#D# import pwd.cmd pwd/cmd:#D# import unix.cmd unix/cmd:#D# import mount.cmd mount/cmd:#D# import umount.cmd umount/cmd:#D# import truedam.cmd truedam/cmd:#D# import cd6.cmd cd6/cmd:#D# import pwd6.cmd pwd6/cmd:#D# import unix6.cmd unix6/cmd:#D# import mount6.cmd mount6/cmd:#D# import umount6.cmd umount6/cmd:#D# import truedam6.cmd truedam6/cmd:#D# import -n expall.bas expall/bas:#D# import -n do6.jcl do6/jcl:#D# xtrs-4.9d/xtrs.man000066400000000000000000001546341306603614600142510ustar00rootroot00000000000000.TH xtrs 1 .SH Name xtrs \- TRS-80 Model I/III/4/4P emulator for the X Window System .SH Syntax .B xtrs [-model m] [-diskdir d] [-debug] .I [other options] .SH Description \fBxtrs\fP is built on top of a Z-80 emulator, with added routines to support keyboard and video I/O through an X interface. The hardware emulation can operate as a TRS-80 Model I, Model III, Model 4, or Model 4P. \fBxtrs\fP supports 48K of RAM in Model I or Model III mode, 128K in Model 4 or Model 4P mode. Floppy disks and hard disks are emulated using files to store the data; or under Linux only, real floppy drives can be used. A printer is emulated by sending its output to standard output. A serial port is emulated using a Unix tty device. Cassette I/O is emulated using files to store the cassette data; real cassettes can also be read or written (with luck), either directly through your sound card (on Linux and other systems with OSS-compatible sound drivers), or via .wav files. Game sound and music output are also supported if you have an OSS-compatible sound driver; sound output though the cassette port, through the Model 4 sound option, and through the optional Orchestra-85/90 music synthesizer card are all emulated. In Model I mode, the HRG1B graphics card is emulated. In Model III and 4/4P mode, you can select whether the Radio Shack graphics card or Micro Labs Grafyx Solution is emulated. There is also a mouse driver for Model 4/4P mode. Several common time-of-day clock cards are emulated on all models. The Alpha Products joystick is emulated using the PC's numeric keypad. Because \fBxtrs\fP emulates the hardware, all known TRS-80 Model I/III/4/4P operating systems should run on it, including all flavors of TRSDOS, LDOS/LS-DOS, NEWDOS, DOSPLUS, MultiDOS, and TRS-80 CP/M. However, the emulator also includes some extensions to the standard hardware, and the special drivers, utilities, and instructions needed for these are not provided for all operating systems. The Z-80 emulator has a debugger called zbx. You can enter the debugger either by starting \fBxtrs\fP with the -debug flag or by pressing F9 while \fBxtrs\fP is running. The debugger runs in the X terminal window that you started \fBxtrs\fP from. Once you are in the debugger, type "help" for more information. Special support in the emulator allows the program to block when waiting for information from the keyboard. This will work only for programs that wait for keyboard input using the standard Model I/III ROM call; the emulator decides whether to block the Z-80 program when it tries to read from the keyboard memory by pattern-matching its stack. .SH Keys The following keys have special meanings to \fBxtrs\fP: F11 toggles onscreen help on the keyboard mappings. LeftArrow, Backspace, or Delete is the TRS-80 left arrow key. RightArrow or Tab is the right arrow key. UpArrow is the up arrow key. DownArrow or Linefeed is the down arrow key. Esc or Break is the Break key. Home, Clear, or LeftAlt is the Clear key. Control is the Model 4 Ctrl key (address bit 7, data bit 2). RightAlt is equivalent to the shifted down arrow key (used as a control key with some TRS-80 software). F1, F2, and F3 are the Model 4/4P function keys (address bit 7, data bits 4, 5, and 6). F1 is also the Model I Electric Pencil control key that some users added to their machines. F4 is the Model 4 Caps Lock key (address bit 7, data bit 3). F5, Compose, or ScrollLock is equivalent to the @ key (so that @ can be used as a modifier key). F6 is equivalent to the 0 key (so that a shifted 0 can be obtained). F7 signals a disk change in the emulated floppy drives (see below). F8 exits the program. F9 enters the debugger (zbx). F10 is the reset button. In Model III, 4, and 4P modes, the left and right shift keys are distinct; in Model I mode, they are the same. The PageUp and PageDown keys always activate the positions that correspond to the Model III/4/4P left and right shift keys (address bit 7, data bits 0 and 1 respectively), even in Model I mode. The End key activates an unused position in the keyboard matrix (address bit 7, data bit 7). The keys [, \\, ], ^, _, {, |, }, and ~ also activate unused positions in the keyboard matrix (address bit 3, data bits 3-7). With many TRS-80 keyboard drivers, these keys map to the corresponding ASCII characters; with others, they do nothing. In some cases you may find the shift state is reversed from what it should be; if you press [ but { is displayed instead (etc.), see the -shiftbracket and -noshiftbracket options below to correct the problem. The Insert key maps to the same position as underscore (address bit 3, data bit 7), so that this key can be used both with and without shift pressed; with many TRS-80 keyboard drivers one of these maps to ASCII code 0x7f. On a German keyboard, the umlaut and "ess-tsett" keys should activate the corresponding characters used in the GENIE, a German Model I clone. This feature is most useful together with the "-charset genie" command line argument. Pressing a key on a PC numeric keypad with NumLock disengaged emulates the Alpha Products joystick. Keys 2, 4, 6, 8 (KP_Down, KP_Left, KP_Right, KP_Up) are the main directions; keys 1, 3, 7, and 9 (KP_End, KP_Page_Down, KP_Home, KP_Page_Up) work as diagonal directions by activating two main directions at once; and key 0 (KP_Insert) or 5 (KP_Begin) is the fire button. Note that your X server may default to sending digits for the keys on the numeric pad even if NumLock is not pressed. If you have this problem, you can use the xmodmap program to remap your numeric pad, and use the xev program to debug it. .SH Emulated cassette To control the emulated cassette, a file called ".cassette.ctl" in the current directory keeps track of what file is currently loaded as the cassette tape and the current position within that file. The \fBcassette\fP(1) shell script provides a way to manipulate this file. You may use this script to load and position cassette tape files. The operation works very much like an actual tape recorder. See the \fBcassette\fP man page for more information about the cassette shell script and the cassette file formats that are supported. .SH Printer For printer support, any text sent to the TRS-80's printer (using LPRINT or LLIST, for example) is sent to the standard output. .SH Emulated floppy disks In Model I mode, \fBxtrs\fP emulates a Radio Shack Expansion Interface with the Percom Doubler or Radio Shack Doubler installed. The Doubler provides double-density disk access by allowing either the stock WD1771 FDC chip or a WD1791 chip to be selected under program control. At powerup the 1771 is selected, so operating systems with no Doubler driver see a stock system. By default, the emulator pretends to be both a Percom and Radio Shack Doubler at the same time -- it responds to the special commands of both -- so a driver for either should work. Under LDOS, use the command "FDUBL" (newer versions of LDOS), or "PDUBL" or "RDUBL" (older versions) to install the driver. Software that tries to detect which doubler you have (such as Super Utility) may be confused by the emulation of both at once, so you can choose to emulate only one with a command line option; see below. In Model III, 4, or 4P mode, \fBxtrs\fP emulates the stock floppy controller, which uses a WD1793 chip (software-compatible with the WD1791) to provide both single and double density. Four 5.25-inch floppy drives are emulated, with storage in files named diskM-U, where M is the TRS-80 model (1, 3, 4, or 4p) and U is the drive unit number (0, 1, 2, or 3). If a file of the required name is not found, a drive with no disk in it is emulated (but see below). If the user does not have write permission for a floppy file, and/or the file has an internal write protect flag set, a write-protect tab is emulated. Use the \fBmkdisk\fP(1) program to turn the write protect flag on or off. To change floppies in an emulated drive, rename the existing file for the drive (if any), rename the new floppy file to the proper name, and hit function key F7 in the emulator. If you try to boot an emulated Model I, III, or 4 with no file named diskM-0 (that is, no disk in drive 0), \fBxtrs\fP emulates having no floppy disk controller. The behavior of a real machine with a disk controller in this case didn't seem useful to emulate faithfully: A real Model I hangs with a screen full of garbage; a real Model III or 4 goes into a retry loop printing "Diskette?" on the screen and rechecking whether you've inserted one. A real Model 4P always has a floppy controller, however, so \fBxtrs\fP always emulates one. Due to a limitation of the original Model I hardware, drive :3 cannot be double-sided in Model I mode. In the original Model I, you could not have a drive :3 at all if any drive in the system was double-sided, but the emulator is able to be more forgiving. Emulated floppy image files can be of any of three types: JV1, compatible with Jeff Vavasour's popular freeware Model I emulator for MS-DOS; JV3, a compatible extension of a format first used in Vavasour's commercial Model III/4 emulator; or DMK, compatible with David Keil's Model 4 emulator. All three types work in \fBxtrs\fP regardless of what model it is emulating. A heuristic is used to decide which type of image is in a drive, as none of the types has a magic number or signature. JV1 supports only single density, single sided, with directory on track 17. Sectors must be 256 bytes long. Use FORMAT (DIR=17) if you want to format JV1 disks with more (or less) than 35 tracks under LDOS. JV3 is much more flexible, though it still does not support everything the real controllers could do. It is probably best to use JV3 for all the disk images you create, since it is the most widely implemented by other emulators, unless you have a special reason to use one of the others. A JV3 disk can be formatted with 128, 256, 512, or 1024-byte sectors, 1 or 2 sides, single or double density, with either FB (normal) or F8 (deleted) data address mark on any sector. In single density the nonstandard data address marks FA and F9 are also available. You cannot format a sector with an incorrect track number or head number. You can format a sector with an intentional CRC error in the data field. \fBxtrs\fP supports at most 5802 total sectors on a JV3 image. The original Vavasour JV3 format supported only 256-byte sectors, and had a limit of 2901 total sectors. If you use sector sizes other than 256 bytes or format more than 2901 sectors on a disk image, emulators other than \fBxtrs\fP may be unable to read it. Note that an 80 track, double-sided, double-density (18 sector) 5.25-inch floppy will fit within the original 2901 sector limit; the extension to 5802 is primarily for emulation of 8-inch drives (discussed below). The DMK format is the most flexible. It supports essentially everything that the original hardware could do, including all "protected" disk formats. However, a few protected disks still may not work with xtrs due to limitations in xtrs's floppy disk controller emulation rather than limitations of the DMK format; see the LIMITATIONS section below. The program \fBmkdisk\fP(1) makes a blank emulated floppy or "bulk erases" an existing one. By default, mkdisk makes a JV3 floppy, but with the -1 flag it makes a JV1 floppy, or with the -k flag a DMK floppy. See the \fBmkdisk\fP man page for more information. Early Model I operating systems used an FA data address mark for the directory on single density disks, while later ones wrote F8 but would accept either upon reading. The change was needed because FA is a nonstandard DAM that is fully supported only by the WD1771 floppy disk controller used in the Model I; the controllers in the Model III and 4 cannot distinguish between FA and FB (which is used for non-directory sectors) upon reading, and cannot write FA. To deal nicely with this problem, \fBxtrs\fP implements the following kludge. On writing in single density, an F8 data address mark is recorded as FA. On reading with an emulated WD1771 (available in Model I mode only), FA is returned as FA; on reading with a WD179x, FA is returned as F8. This trick makes the different operating systems perfectly compatible with each other, which is better than on a real Model I! You can use the -truedam flag to turn off this kludge if you need to; in that case the original hardware is emulated exactly. TRS-80 programs that attempt to measure the rotational speed of their floppy disk drives using timing loops will get the answers they expect, even when \fBxtrs\fP does not emulate instructions at the same speed as the original machines. This works because \fBxtrs\fP keeps a virtual clock (technically, a T-state counter), which measures how much time it should have taken to execute the instruction stream on a real machine, and it ties the emulation of floppy disk index holes to this clock, not to real time. .SH Emulated 8-inch floppy disks In addition to the four standard 5.25-inch drives, \fBxtrs\fP also emulates four 8-inch floppy drives. There is no widely-accepted standard hardware interface for 8-inch floppies on the TRS-80, so \fBxtrs\fP emulates a pseudo-hardware interface of its own and provides an LDOS/LS-DOS driver for it. Storage for the emulated 8-inch disks is in files named diskM-U, where M is the TRS-80 model number (1, 3, 4, or 4p) and U is a unit number (4, 5, 6, or 7). The only difference between 5.25-inch and 8-inch emulated drives is that the emulator allows you to format more bytes per track in the latter. A new JV3 floppy can be formatted as either 5.25-inch or 8-inch depending on whether you initially put it into a 5.25-inch or 8-inch emulated drive. A new DMK floppy, however, must be created with the -8 flag to mkdisk in order to be large enough for use in an 8-inch emulated drive. JV1 floppies cannot be used in 8-inch drives. Be careful not to put an emulated floppy into a 5.25-inch emulated drive after it has been formatted in an 8-inch emulated drive or vice versa; the results are likely to be confusing. Consider using different file extensions for the two types; say, \.dsk for 5.25-inch and \.8in for 8-inch. To use the emulated 8-inch drives, you'll need a driver. Under LDOS or LS-DOS, use the program XTRS8/DCT supplied on the emulated floppy \fIutility.dsk\fP. This driver is a very simple wrapper around the native LDOS/LS-DOS floppy driver. Here are detailed instructions. First, make sure an appropriate version of LDOS is in emulated floppy drive 0, and the supplied file \fIutility.dsk\fP is in another emulated floppy drive. Boot LDOS. If you are using Model I LDOS, be sure FDUBL is running. Second, type the following commands. Here \fId\fP is the LDOS drive number you want to use for the 8-inch drive and \fIu\fP is the unit number you chose when naming the file. Most likely you will choose \fId\fP and \fIu\fP to be equal to reduce confusion. .nf SYSTEM (DRIVE=\fId\fP,DRIVER="XTRS8",ENABLE) Enter unit number ([4]-7): \fIu\fP .fi You can repeat these steps with different values of \fId\fP and \fIu\fP to have more than one 8-inch drive. You might want to repeat four times using 4, 5, 6, and 7, or you might want to save some drive numbers for hard drives (see below). Finally, it's a good idea to give the SYSTEM (SYSGEN) command (Model I/III) or SYSGEN command (Model 4/4P). This command saves the SYSTEM settings, so the 8-inch drives will be available again the next time you reboot or restart the emulator. If you need to access an 8-inch drive after booting from a disk that hasn't been SYSGENed, simply use the same SYSTEM command again. In case you want to write your own driver for another TRS-80 operating system, here are details on the emulated pseudo-hardware. The 8-inch drives are accessed through the normal floppy disk controller, exactly like 5.25-inch drives. The four 5.25-inch drives have hardware select codes 1, 2, 4, and 8, corresponding respectively to files diskM-0, -1, -2, and -3. The four 8-inch drives have hardware select codes 3, 5, 6, and 7, corresponding respectively to files diskM-4, -5, -6, and -7. (See also the \-sizemap option below, however.) .SH Real floppy disks Under Linux only, any diskM-U file can be a symbolic link to a real floppy disk drive, typically /dev/fd0 or /dev/fd1. Most PCs should be able to read and write TRS-80 compatible floppies in this way. Many PC floppy controllers cannot handle single density, however, and some may have problems even with double density disks written on a real TRS-80, especially disks formatted by older TRS-80 operating systems. Use the -doublestep flag if you need to read 35-track or 40-track media in an 80-track drive. If you need to write 35-track or 40-track media in an 80-track drive, bulk-erase the media first and format it in the 80-track drive. Don't write to a disk in an 80-track drive if it has ever been written to in a 40-track drive. The narrower head used in an 80-track drive cannot erase the full track width written by the head in a 40-track drive. If you link one of the 5.25-inch floppy files (diskM-0 through diskM-3) to a real floppy drive, TRS-80 programs will see it as a 5.25-inch drive, but the actual drive can be either 3.5-inch or 5.25-inch. The drive will be operated in double density (or single density), not high density, so be sure to use the appropriate media. If you link one of the 8-inch floppy files (diskM-4 through diskM-7) to a real floppy drive, TRS-80 programs will see it as an 8-inch drive. Again, you need to use the XTRS8/DCT driver described above to enable LDOS/LS-DOS to access an 8-inch drive. The real drive can be either 3.5-inch, 5.25-inch, or 8-inch. A 3.5-inch or 5.25-inch drive will be operated in high-density mode, using MFM recording if the TRS-80 is trying to do double density, FM recording if the TRS-80 is trying to do single density. In this mode, these drives can hold as much data as a standard 8-inch drive. In fact, a 5.25-inch HD drive holds exactly the same number of bits per track as an 8-inch drive; a 3.5-inch HD drive can hold 20% more, but we waste that space when using one to emulate an 8-inch drive. In both cases we also waste the top three tracks, since an 8-inch drive has only 77 tracks, not 80. The nonstandard FA and F9 data address marks available in single density on a real Model I with the WD1771 controller also need special handling. A PC-style floppy disk controller can neither read nor write sectors with such DAMs at all. This raises three issues: (1) It will be impossible for you to read some Model I disks on your PC even if your PC otherwise supports single density. In particular, Model I TRSDOS 2.3 directory tracks will be unreadable. (2) On writing in single density, \fBxtrs\fP silently records a F9 or FA DAM as F8. (3) On reading in single density with an emulated WD1771 (Model I mode only), F8 is returned as FA. If you need more accurate behavior, the -truedam flag will turn on error messages on attempts to write F9 or FA DAMs and will turn off translation of F8 to FA on reading. Hint: Be sure to set the drive type correctly in your PC's BIOS. Linux and xtrs rely on this information to know how fast your drives are spinning and hence what data rate to use when reading and writing. All 3.5-inch drives spin at 300 RPM. Newer 5.25-inch high-density capable drives ("1.2MB" drives) normally always spin at 360 RPM. (Some can be jumpered to slow down to 300 RPM when in double-density mode, but you should not do that when plugging one into a PC.) Older 5.25-inch drives that cannot do high density ("180KB", "360KB" or "720KB" 5.25-inch drives) always spin at 300 RPM. All 8-inch drives spin at 360 RPM. If you plug an 8-inch drive into a PC (this requires a 50-pin to 34-pin adaptor cable), tell your BIOS that it is a 5.25-inch 1.2MB drive. .SH Emulated hard disks \fBxtrs\fP can emulate a hard disk in a file in one of two ways: it can use a special, xtrs-specific LDOS driver called XTRSHARD/DCT, or it can emulate the Radio Shack hard drive controller (based on the Western Digital WD1010) and use the native drivers for the original hardware. .B Using XTRSHARD/DCT The XTRSHARD/DCT driver has been tested and works under both LDOS 5.3.1 for Model I or III and TRSDOS/LS-DOS 6.3.1 for Model 4/4P. It may or may not work under earlier LDOS versions. It definitely will not work under other TRS-80 operating systems or with emulators other than \fBxtrs\fP. The hard disk format was designed by Matthew Reed for his Model I/III and Model 4 emulators; \fBxtrs\fP duplicates the format so that users can exchange hard drive images across the emulators. To use XTRSHARD/DCT, first run the \fBmkdisk\fP program under Unix to create a blank hard drive (.hdv) file. Typical usage would be: \fImkdisk -h mydisk.hdv\fP. See the \fBmkdisk\fP(1) man page for other options. Second, link the file to an appropriate name. XTRSHARD/DCT supports up to eight hard drives, with names of the form hardM-U, where M is the TRS-80 model (1, 3, or 4; in this case Model 4P also uses M=4) and U is a unit number from 0 to 7. It looks for these files in the same directory as the floppy disk files diskM-U. Third, make sure an appropriate version of LDOS is in emulated floppy drive 0, and the supplied file \fIutility.dsk\fP is in another emulated floppy drive. Boot LDOS. If you are using Model I LDOS 5.3.1, patch a bug in the FORMAT command by typing \fIPATCH FORMAT/CMD.UTILITY M1FORMAT/FIX\fP. You need to apply this patch only once. It must not be applied to Model III or Model 4/4P LDOS. Fourth, type the following commands. Here \fId\fP is the LDOS drive number you want to use for the hard drive (a typical choice would be 4) and \fIu\fP is the unit number you chose when naming the file (most likely 0). .nf SYSTEM (DRIVE=\fId\fP,DRIVER="XTRSHARD",ENABLE) Enter unit number ([0]-7): \fIu\fP FORMAT \fId\fP (DIR=1) .fi Answer the questions asked by FORMAT as you prefer. The \fIDIR=1\fP parameter to FORMAT is optional; it causes the hard drive's directory to be on track 1, making the initial size of the image smaller. You can repeat these steps with different values of \fId\fP and \fIu\fP to have more than one hard drive. Finally, it's a good idea to give the SYSTEM (SYSGEN) command (Model I/III) or SYSGEN command (Model 4/4P). This command saves the SYSTEM settings, so the drive will be available again the next time you reboot or restart the emulator. If you need to access the hard disk file after booting from a floppy that hasn't been SYSGENed, simply use the same SYSTEM command(s) again, but don't FORMAT. You can freely use a different drive number or (if you renamed the hard disk file) a different unit number. The F7 key currently doesn't allow XTRSHARD/DCT disk changes to be recognized, but you can change to a different hard disk file for the same unit by renaming files as needed and rebooting LDOS. Technical note: XTRSHARD/DCT is a small Z-80 program that implements all the required functions of an LDOS disk driver. Instead of talking to a real (or emulated) hard disk controller, however, it uses special support in \fBxtrs\fP that allows Z-80 programs to open, close, read, and write Unix files directly. This support is described further in the "Data import and export" section below. .B Using native hard disk drivers Beginning in version 4.1, \fBxtrs\fP also emulates the Radio Shack hard disk controller (based on the Western Digital WD1010) and will work with the native drivers for this hardware. This emulation uses the same hard drive (.hdv) file format that XTRSHARD/DCT does. With LDOS/LS-DOS, the RSHARDx/DCT and TRSHD/DCT drivers are known to work. With Montezuma CP/M 2.2, the optional Montezuma hard disk drivers are known to work. The hard disk drivers for NEWDOS/80 and for Radio Shack CP/M 3.0 should work, but they have not yet been tested at this writing. Any bugs should be reported. To get started, run the \fBmkdisk\fP program under Unix to create a blank hard drive (.hdv) file. Typical usage would be: \fImkdisk -h mydisk.hdv\fP. See the \fBmkdisk\fP(1) man page for other options. Second, link the file to an appropriate name. The WD1010 emulation supports up to four hard drives, with names of the form hardM-U, where M is the TRS-80 model (1, 3, 4, or 4p) and U is a unit number from 0 to 3. It looks for these files in the same directory as the floppy disk files diskM-U. If no such files are present, \fBxtrs\fP disables the WD1010 emulation. Note that if hard drive unit 0 is present on a Model 4P (file hard4p-0), the Radio Shack boot ROM will always try to boot from it, even if the operating system does not support booting from a hard drive. If you have this problem, either hold down F2 while booting to force the ROM to boot from floppy, or simply avoid using unit number 0. Stock TRSDOS/LS-DOS 6 systems do not support booting from a hard drive; M.A.D. Software's HBUILD6 add-on to LS-DOS for hard drive booting should work, but is untested. Montezuma CP/M 2.2 does boot from the emulated hard drive. Finally, obtain the correct driver for the operating system you will be using, read its documentation, configure the driver, and format the drive. Detailed instructions are beyond the scope of this manual page. .SH Data import and export Several Z-80 programs for data import and export from various TRS-80 operating systems are included with \fBxtrs\fP on two emulated floppy images. These programs use special support in the emulator to read and write external Unix files, discussed further at the end of this section. The emulated floppy \fIutility.dsk\fP contains some programs for transferring data between the emulator and ordinary Unix files. IMPORT/CMD, EXPORT/CMD, and SETTIME/CMD run on the emulator under Model I/III TRSDOS, Model I/III LDOS, Model I/III Newdos/80, and Model 4/4P TRSDOS/LS-DOS 6; they may also work under other TRS-80 operating systems. Model III TRSDOS users will have to use TRSDOS's CONVERT command to read utility.dsk. IMPORT/CMD imports a Unix file and writes it to an emulated disk. Usage: \fIIMPORT [-lne] unixfile [trsfile]\fP. The -n flag converts Unix newlines (\\n) to TRS-80 newlines (\\r). The -l flag converts the Unix filename to lower case, to compensate for TRS-80 operating systems such as Newdos/80 that convert all command line arguments to upper case. When using the -l flag, you can put a [ or up-arrow in front of a character to keep it in upper case. Give the -e flag if your TRS-80 operating system uses the Newdos/80 convention for representing the ending record number in an open file control block. This should be detected automatically for Newdos/80 itself and for TRSDOS 1.3, but you'll need to give the flag for DOSPLUS and possibly other non-LDOS operating systems. If you need the flag but don't give it (or vice versa), imported files will come out the wrong length. If the destination file is omitted, IMPORT uses the last component of the Unix pathname, but with any "." changed to "/" to match TRS-80 DOS file extension syntax. EXPORT/CMD reads a file from an emulated disk and exports it to a Unix file. Usage: \fIEXPORT [-lne] trsfile [unixfile]\fP. The -n flag converts TRS-80 newlines (\\r) to Unix newlines (\\n). The -l flag converts the Unix filename to lower case. When using the -l flag, you can put a [ or up-arrow in front of a character to keep it in upper case. Give the -e flag if your TRS-80 operating system uses the Newdos/80 convention for representing the ending record number in an open file control block. This should be detected automatically for Newdos/80 itself and for TRSDOS 1.3, but you'll need to give the flag for DOSPLUS and possibly other non-LDOS operating systems. If you need the flag but don't give it (or vice versa), exported files will come out the wrong length. If the destination file is omitted, EXPORT uses the TRS-80 filename, but with any "/" changed to "." to match Unix file extension syntax. SETTIME/CMD reads the date and time from Unix and sets the TRS-80 DOS's date and time accordingly. The next several programs were written in Misosys C and exist in two versions on utility.dsk. The one whose name ends in "6" runs on Model 4 TRSDOS/LS-DOS 6.x; the other runs on LDOS 5.x and most other Model I/III operating systems. CD/CMD (or CD6/CMD) changes xtrs's Unix working directory. Usage: \fICD [-l] unixdir\fP. The -l flag converts the Unix directory name to lower case. When using the -l flag, you can put a [ or up-arrow in front of a character to keep it in upper case. Running CD/CMD will change the interpretation of any relative pathnames given to IMPORT or EXPORT. It will also change the interpretation of disk names at the next disk change, unless you specified an absolute pathname for xtrs's -diskdir parameter. PWD/CMD (or PWD6/CMD) prints xtrs's Unix working directory. UNIX/CMD (or UNIX6/CMD) runs a Unix shell command. Usage: \fIUNIX [-l] unix command line\fP. The -l flag converts the Unix command line to lower case. When using the -l flag, you can put a [ or up-arrow in front of a character to keep it in upper case. Standard I/O for the command uses the xtrs program's standard I/O descriptors; it does not go to the TRS-80 screen or come from the TRS-80 keyboard. MOUNT/CMD (or MOUNT6/CMD) is a convenience program that switches emulated floppy disks in the drives. Usage: \fIMOUNT [-l] filename U\fP. The -l flag converts the Unix filename to lower case. When using the -l flag, you can put a [ or up-arrow in front of a character to keep it in upper case. The filename is any Unix filename; U is a single digit, 0 through 7. The command deletes the file diskM-U (where M is the TRS-80 model) from the disk directory (see -diskdir option), replaces it with a symbolic link to the given filename, and signals a disk change (as if F7 had been pressed). UMOUNT/CMD (or UMOUNT6/CMD) is a convenience program that removes an emulated floppy disk from a drive. Usage: \fIUMOUNT U\fP. U is a single digit, 0 through 7. The command deletes the file diskM-U (where M is the TRS-80 model) from the disk directory (see -diskdir option) and signals a disk change (as if F7 had been pressed). The emulated floppy \fIcpmutil.dsk\fP contains import and export programs for Montezuma CP/M, written by Roland Gerlach. It was formatted as a "Montezuma Micro Standard DATA disk (40T, SS, DD, 200K)," with 512-byte sectors. Be careful to configure your CP/M to the proper disk format and drive parameters (40 track, not 80), or you will have confusing problems reading this disk. Documentation is included in the file cpmutil.html and source code in the file cpmutil.tgz (a gzipped tar archive). See http://members.optusnet.com.au/~rgerlach/trs-80/cpmutil.html where you will sometimes find a newer version of the utilities than is included with xtrs. The emulator implements a set of pseudo-instructions (emulator traps) that give TRS-80 programs access to Unix files. The programs listed above use them. If you would like to write your own such programs, the traps are documented in the file trs_imp_exp.h. Assembler source code for the existing programs is supplied in xtrshard.z, import.z, export.z, and settime.z. You can also write programs that use the traps in Misosys C, using the files xtrsemt.h and xtrsemt.ccc as an interface; a simple example is in settime.ccc. .SH Interrupts The emulator supports only interrupt mode 1. It will complain if your program enables interrupts after powerup without executing an IM 1 instruction first. All Model I/III/4/4P software does this, as the built-in peripherals in these machines support only IM 1. The Model I has a 40 Hz heartbeat clock interrupt, while the Model III uses 30 Hz, and the Model 4/4P can run at either 30 Hz or 60 Hz. The emulator approximates this rather well even on a system where clock ticks come at some frequency that isn't divisible by the emulated frequency (e.g., 100 Hz on Intel Linux), as long as the true frequency is not slower than the emulated frequency. The emulator has a notion of the absolute time at which each tick is supposed to occur, and it asks the host system to wake it up at each of those times. The net result is that some ticks may be late, but there are always the proper number of ticks per second. For example, running in Model I mode on Intel Linux you'd see this pattern: (tick, 30ms, tick, 20ms,...) instead of seeing ticks every 25ms. .SH Processor speed selection A standard Model 4 has a software-controlled switch to select operation at either 4.05504 MHz (with heartbeat clock at 60 Hz) or 2.02752 MHz (with heartbeat clock at 30 Hz). xtrs emulates this feature. Model I's were often modified to operate at higher speeds than the standard 1.77408 MHz. With one common modification, writing a 1 to port 0xFE would double the speed to 3.54816 MHz, while writing a 0 would set the speed back to normal. The heartbeat clock runs at 40 Hz in either case. xtrs emulates this feature as well. .SH Sound Sound support uses the Open Sound System /dev/dsp device, standard on Linux and available on many other Unix versions as well. This support is compiled in automatically on Linux; if you have OSS on another version of Unix, you'll need to define the symbol HAVE_OSS in your Makefile or in trs_cassette.c. Any time TRS-80 software tries to write non-zero values to the cassette port (or the Model 4/4P optional sound port) with the cassette motor off, it is assumed to be trying to make sounds and xtrs opens /dev/dsp. It automatically closes the device again after a few seconds of silence. If you are playing a game with sound, you'll want to use the -autodelay flag to slow down instruction emulation to approximately the speed of a real TRS-80. If you don't do this, sound will still play correctly, but the gameplay may be way too fast and get ahead of the sound. On the other hand, if your machine is a bit too slow, you'll hear gaps and pops in the sound when the TRS-80 program lags behind the demand of the sound card for more samples. The -autodelay feature includes a small speed boost whenever a sound starts to play to try to prevent this, but if the boost is too much or too little, you might either find that the game runs too fast when a lot of sound is playing, or that the sound has gaps in it anyway. If your sound has gaps, you can try reducing the sample rate with the -samplerate flag. The Orchestra-85 music synthesis software will run under xtrs's Model I emulation, and the Orchestra-90 software will run with Model III operating systems under xtrs's Model III, 4, or 4P emulation. For best results, use Orchestra-90 and the Model 4 emulation, as this lets the software run at the highest emulated clock rate (4 MHz) and thus generate the best sound. If you want to run Orchestra-85 instead, you can tell it that you have a 3.5 MHz clock speedup with enable sequence 3E01D3FE and disable sequence 3E00D3FE; this will let the software run twice as fast as on an unmodified Model I and generate better sound. There is no need to use xtrs's -autodelay flag when running Orchestra-85/90, but you might want to specify a small fixed delay to keep from getting excessive key repeat. .SH Mouse A few Model 4 programs could use a mouse, such as the shareware hi-res drawing program MDRAW-II. The program XTRSMOUS/CMD on the utility disk (utility.dsk) is a mouse driver for Model 4/4P mode that should work with most such programs. \fBxtrs\fP does not emulate the actual mouse hardware (a serial mouse plugged into the Model 4 RS-232 port), so the original mouse drivers will not work under \fBxtrs\fP. Instead, XTRSMOUS accesses the X mouse pointer using an emulator trap. XTRSMOUS implements the same TRSDOS/LS-DOS 6 SVC interface as the David Goben and Matthew Reed mouse drivers. (It does not implement the interface of the older Scott McBurney mouse driver, which may be required by some programs.) By default XTRSMOUS installs itself in high memory. This is done because MDRAW-II tests for the presence of a mouse by looking to see whether the mouse SVC is vectored to high memory. If the driver is installed in low memory, MDRAW thinks it is not there at all. If you use mouse-aware programs that don't have this bug, or if you edit the first line of MDRAW to remove the test, you can install XTRSMOUS in low memory using the syntax "XTRSMOUS (LOW)". .SH Time of day clock Several battery-backed time of day clocks were sold for the various TRS-80 models, including the TimeDate80, TChron1, TRSWatch, and T-Timer. They are essentially all the same hardware, but reside at a few different port ranges. \fBxtrs\fP currently emulates them at port ranges 0x70-0x7C and 0xB0-0xBC. The T-Timer port range at 0xC0-0xCC conflicts with the Radio Shack hard drive controller and is not emulated. These clocks return only a 2-digit year, and it is unknown what their driver software will do in the year 2000 and beyond. If you have software that works with one of them, please send email to report what happens when it is used with \fBxtrs\fP. Also see SETTIME/CMD in the "Data import and export" section above for another way to get the correct time into a Z-80 operating system running under \fBxtrs\fP. Finally, you might notice that LDOS/LS-DOS always magically knows the correct date when you boot it (but not the time). When you first power up the emulated TRS-80, \fBxtrs\fP dumps the date into the places in memory where LDOS and LS-DOS normally save it across reboots, so it looks to the operating system as if you rebooted after setting the date. .SH Joystick Pressing a key on a PC numeric keypad with NumLock disengaged emulates the Alpha Products joystick. See the Keys section above for details. The emulated joystick is mapped only at port 0, to avoid conflicts with other devices. The joystick emulation could be made to work with real joysticks using the X input extension, but this is not implemented yet. .SH Running games Some games run rather well under \fBxtrs\fP now, provided that your machine is fast enough to run the emulation in real time and that you choose the right command line options. "Galaxy Invaders Plus" by Big 5 Software is particularly good. You will usually want to turn on autodelay, and if your machine is slow you may need to reduce the sound sample rate. Running your X server in 8-bit/pixel mode also seems to help in some cases. Example command lines: .nf startx -- -bpp 8 xtrs -autodelay .fi If you have a slow machine and the sound breaks up, it is possible that your machine is not fast enough to generate samples at the default rate of 44,100 Hz. If you think this may be happening, try "-samplerate 11025" or even "-samplerate 8000". .SH Options Defaults for all options can be specified using the standard X resource mechanism, and the class name for \fBxtrs\fP is "Xtrs". .TP .B \-display \fIdisplay\fP Set your X display to \fIdisplay\fP. The default is to use the DISPLAY environment variable. .TP .B \-iconic Start with the \fBxtrs\fP window iconified. .TP .B \-background \fIcolor\fP .PD 0 .TP .B \-bg \fIcolor\fP .PD Specifies the background color of the \fBxtrs\fP window. .TP .B \-foreground \fIcolor\fP .PD 0 .TP .B \-fg \fIcolor\fP .PD Specifies the foreground color of the \fBxtrs\fP window. .TP .B \-title \fItitletext\fP Use \fItitletext\fP in the window title bar instead of the program name. .TP .B \-borderwidth \fIwidth\fP Put a border of \fIwidth\fP pixels around the TRS-80 display. The default is 2. .TP .B \-scale \fIxfac[,yfac]\fP Multiply the horizontal and vertical window size by \fIxfac\fP and \fIyfac\fP, respectively. Possible values are integers in the range [1,4] for \fIxfac\fP and [1,8] for \fIyfac\fP. Defaults are \fIxfac\fP=1 and \fIyfac\fP=2*\fIxfac\fP. .TP .B \-resize In Model III or 4/4P mode, resize the X window whenever the emulated display mode changes between 64x16 text (or 512x192 graphics) and 80x24 text (or 640x240 graphics). This is the default in Model III mode, since 80x24 text is not available and the 640x240 graphics add-on card is seldom used. .TP .B \-noresize In Model III or 4/4P mode, always keep the X window large enough for 80x24 text or 640x240 graphics, putting a blank margin around the outside when the emulated display mode is 64x16 text or 512x192 graphics. This is the default in Model 4/4P mode, since otherwise there is an annoying size switch during every reboot. .TP .B \-charset \fIname\fP Select among several sets of built-in character bitmaps. In Model I mode, five sets are available. The default, \fIwider\fP, is a modified Model III set with characters 8 pixels wide; it looks better on a modern computer screen with square pixels than the real Model I fonts, which were 6 pixels wide. \fIlcmod\fP is the character set in the replacement character generator that was supplied with the Radio Shack lower case modification. (It was reconstructed partly from memory and may have some minor bit errors.) \fIstock\fP is the character set in the stock character generator supplied with most upper case only machines. Since \fIxtrs\fP currently always emulates the extra bit of display memory needed to support lower case, this character set gives you the authentic, unpleasant effect that real Model I users saw when they tried to do homebrew lower case modifications without replacing the character generator: lower case letters appear at an inconsistent height, and if you are using the Level II BASIC ROM display driver, upper case letters are replaced by meaningless symbols. \fIearly\fP is the same as stock, but with the standard ASCII characters [, \\, ], and ^ in the positions where most Model I's had directional arrows. This was the default programming in the Motorola character generator ROM that Radio Shack used, and a few early machines were actually shipped with this ROM. Finally, \fIgerman\fP or \fIgenie\fP gives an approximate emulation of the GENIE, a German Model I clone. Characters are 8 pixels wide, and double width is supported even though later GENIE models did not include it. In Model III, 4, and 4P modes, three sets are available: \fIkatakana\fP (the default for Model III) is the original Model III set with Japanese Katakana characters in the alternate character positions. This set was also used in early Model 4's. \fIinternational\fP (the default for Model 4 and 4P) is a later Model 4 set with accented Roman letters in the alternate positions. \fIbold\fP is a bold set from a character generator ROM found in one Model III, origin uncertain. .TP .B \-usefont Use X fonts instead of the built-in character bitmaps. .TP .B \-nofont Use the built-in character bitmaps, not a X font. This is the default. .TP .B \-font \fIfontname\fP If -usefont is also given, use the specified X font for normal width characters. The default uses a common X fixed-width font: "-misc-fixed-medium-r-normal--20-200-75-75-*-100-iso8859-1". .TP .B \-widefont \fIfontname\fP If -usefont is also given, use the specified X font for double width characters. The default uses a common X fixed-width font, scaled to double width: "-misc-fixed-medium-r-normal--20-200-75-75-*-200-iso8859-1". .TP .B \-nomicrolabs In Model I mode, emulate the HRG1B 384x192 hi-res graphics card. In Model III mode or Model 4/4P mode, emulate the Radio Shack hi-res card. This is now the default. .TP .B \-microlabs In Model III or 4/4P mode, emulate the Micro Labs Grafyx Solution hi-res graphics card. Note that the Model III and Model 4/4P cards from Micro Labs are very different from one another. .TP .B \-debug Enter zbx, the z80 debugger. .TP .B \-romfile \fIfilename\fP .PD 0 .TP .B \-romfile3 \fIfilename3\fP .TP .B \-romfile4p \fIfilename4p\fP .PD Use the romfile specified by \fIfilename\fP in Model I mode, the romfile specified by \fIfilename3\fP in Model III and Model 4 mode, or the romfile specified by \fIfilename4p\fP in Model 4P mode, A romfile can be either a raw binary dump, Intel hex format, or TRS-80 cmd format (for example, a MODELA/III file). If you do not set this option or the corresponding X resource, a default established at compile time is used (if any); see Makefile.local for instructions on compiling in default romfiles or default romfile names. .TP .B \-model \fIm\fP Specifies which TRS-80 model to emulate. Values accepted are 1 or I (Model I), 3 or III (Model III), 4 or IV (Model 4), and 4P or IVP (Model 4P). Model I is the default. .TP .B \-delay \fId\fP A crude speed control. After each Z-80 instruction, xtrs busy-waits for \fId\fP iterations around an empty loop. A really smart C optimizer might delete this loop entirely, so it's possible that this option won't work if you compile xtrs with too high an optimization level. The default delay is 0. .TP .B \-autodelay Dynamically adjusts the value of -delay to run instructions at roughly the same rate as a real machine. The tracking is only approximate, but it can be useful for running games. .TP .B \-noautodelay Turn off -autodelay. This is the default. .TP .B \-keystretch \fIcycles\fP Fine-tune the keyboard behavior. To prevent keystrokes from being lost, xtrs "stretches" the intervals between key transitions, so that the Z-80 program has time to see each transition before the next one occurs. Whenever the Z-80 program reads the keyboard matrix and sees an emulated key go up or down, xtrs waits \fIcycles\fP Z-80 clock cycles (T-states) before it allows the program to see another key transition. Key transitions that are received during the waiting period or when the Z-80 program is not reading the keyboard are held in a queue. The default stretch value is 4000 cycles; it should seldom if ever be necessary to change it. .TP .B \-shiftbracket Emulate [, \\, ], ^, and _ as shifted keys, and {, |, }, and ~ as unshifted. This is the default in Model 4 and 4P modes, and it works well with the keyboard driver in Model 4 TRSDOS/LS-DOS 6. .TP .B \-noshiftbracket Emulate [, \\, ], ^, and _ as unshifted keys, and {, |, }, and ~ as shifted. This is the default in Model I and III modes, and it works well with many TRS-80 keyboard drivers. With some keyboard drivers these keys do not work at all, however. .TP .B \-diskdir \fIdir\fP Specify the directory containing floppy and hard disk images. If the value starts with "~/" (or is just "~"), it is relative to your home directory. The default value is ".". .TP .B \-doubler \fItype\fP Specify what type of double density adaptor to emulate (Model I mode only). The \fItype\fP may be \fIpercom\fP, \fIradioshack\fP (or \fItandy\fP), \fIboth\fP, or \fInone\fP. The type may be abbreviated to one character. The default is \fIboth\fP, which causes the double density adaptor emulation to respond to the special commands of both the Percom and Radio Shack cards. .TP .B \-doublestep Make all real floppy drives double-step, allowing access to 35-track or 40-track media in an 80-track drive. Linux only. See the Floppy Disks section for limitations. .TP .B \-nodoublestep Turn off double-step mode for all real floppy drives. Linux only. This is the default. .TP .B \-stepmap s0,s1,s2,s3,s4,s5,s6,s7 Selectively set double-step mode for individual real floppy drives. If \fIsU\fP is 2 and \fIdiskM-U\fP is a real drive, the drive will be double-stepped; if \fIsU\fP is 1, it will be single-stepped. You can omit values from the end of the list; those drives will get the default value set by -doublestep or -nodoublestep. .TP .B \-sizemap z0,z1,z2,z3,z4,z5,z6,z7 Selectively set whether drives are emulated as 5-inch or 8-inch; see the section "Emulated 8-inch floppy disks" above. If \fIzU\fP is 5, the drive will appear to Z-80 software as 5-inch; if 8, as 8-inch. The default setting (as reflected in the documentation above) is 5,5,5,5,8,8,8,8. You can omit values from the end of the list; those drives will get the default values. Setting one or more of the first four drives to 8-inch may be useful for CP/M software that supports 8-inch drives. You can also use XTRS8/DCT with 8-inch drives in the first four positions; even though the prompt suggests the unit number must be 4-7, numbers 0-3 are accepted. XTRS8 does not check whether the unit you've selected is really being emulated as an 8-inch drive, however; you'll simply get errors during FORMAT if you get this wrong. .TP .B \-truedam Turn off the single density data address mark remapping kludges described in the "Emulated floppy disks" and "Real floppy disks" sections above. With this option given, the distinction between F8 and FA data address marks is strictly observed on both writing and reading. This option is probably not useful unless you need to deal with Model I disks that use the distinction as part of a copy-protection scheme. See also "Common File Formats for Emulated TRS-80 Floppy Disks", available at http://www.tim-mann.org/trs80/dskspec.html. .TP .B \-notruedam The opposite of -truedam. This setting is the default. .TP .B \-samplerate \fIrate\fP Set the sample rate for new cassette wav files, direct cassette I/O to the sound card, and game sound output to the sound card. Existing wav files will be read or modified using their original sample rate regardless of this flag. The default is 44,100 Hz. See also the cassette(1) man page. .TP .B \-serial \fIttyname\fP Set the tty device to be used for I/O to the TRS-80's serial port. The default is /dev/ttyS0 on Linux, /dev/tty00 on other versions of Unix. Setting the name to be empty (\-serial "") emulates having no serial port. .TP .B \-switches \fIvalue\fP Set the sense switches on the Model I serial port card. This option is meaningful only in Model I mode, and only when the -serial option is not set to "". The default value is 0x6f, which Radio Shack software conventionally interprets as 9600 bps, 8 bits/word, no parity, 1 stop bit. .TP .B \-emtsafe Disable emulator traps (see "Data import and export") that could write to host files other than disk images in the original diskdir. .TP .B \-noemtsafe The opposite of -emtsafe. This setting is the default. .SH Additional resources There are many other TRS-80 resources available on the Web, including shareware and freeware emulators that run under MSDOS and other operating systems, software for converting TRS-80 physical media to the emulator's disk file format, ROM images, and TRS-80 software that has already been converted. For pointers, see http://www.tim-mann.org/trs80.html. .SH Bugs and limitations The emulated serial port's modem status and control signals are not tied to the signals on the real serial port, because the real signals are not available to software through the Unix tty device interface. The ability to check for parity, framing, and overrun errors and receive an interrupt when one occurs is not emulated. Unix does not support 2000, 3600, or 7200 baud, so these TRS-80 data rates are remapped to 38400, 57600, and 115200 baud respectively. A better signal processing algorithm might help read real cassettes more reliably, especially at 1500bps. Some features of the floppy disk controller are not currently emulated: Force Interrupt with condition bits 0x01, 0x02, or 0x04 is not implemented. Read Track is implemented only for DMK emulated floppies. The multiple-sector flags in Read and Write are not implemented. The timing of returned sectors is emulated only for the Read Address command, and not very accurately for JV1 or JV3. If a disk has more than one sector with the same number on a track, \fBxtrs\fP will always see the first (counting from the index hole) when reading or writing; a real machine would see the next one to come under the head depending on the current rotational position of the disk. Partially reformatting a track (which TRS-80 programs like HyperZap and Model I Super Utility do to achieve mixed density) is supported for DMK but not JV3; however, switching densities while formatting (which Model III and 4 Super Utility do) works on both DMK and JV3. Real physical floppy disks are supported only under Linux, because Unix does not define a portable interface to the low-level floppy controller functionality that \fBxtrs\fP needs. There are some limitations even under Linux: Index holes are faked, not detected on the real disk, and the timing of returned sectors is not emulated at all. Due to the limitations of PC-style floppy disk controllers, when formatting a physical floppy under \fBxtrs\fP, you cannot mix sectors of different sizes on the same track, switch densities in the middle of a track, or reformat only part of a track. However, \fBxtrs\fP can read and write to physical floppies that have already been formatted in these ways (perhaps by a real TRS-80). The extended JV3 limit of 5802 sectors is somewhat arbitrary. It could be raised by generalizing the code to permit more than two blocks of 2901, but this does not seem too useful. 5802 sectors is already enough for a 3.5-inch HD (1.44MB) floppy, which the TRS-80 didn't support anyway. If you need more space, use emulated hard drives instead of emulated floppies with huge numbers of tracks. XTRSHARD/DCT ignores the internal write-protected flag in hard drive images, but a hard drive image can still be effectively write protected by turning off its Unix write permission bits. The emulator uses a heuristic to decide what format a ROM file is in. If a raw binary ROM image starts with 0x01, 0x05, or 0x22, it can be misidentified as being in a different format. This is rather unlikely to occur, as ROMs typically begin with 0xF3, the DI instruction. The joystick emulation could be made to work with real joysticks using the X input extension, but this is not implemented yet. If you discover other bugs, write fixes for any of these, or make any other enhancements, please let us know so that we can incorporate the changes into future releases. .SH Authors and acknowledgements \fBxtrs\fP 1.0 was written by David Gingold and Alec Wolman. The current version was revised and much extended by Timothy Mann (see http://tim-mann.org/). See README and README.tpm for additional notes from the authors. We also thank the following people for their help. The JV1 and JV3 floppy disk file formats were designed by Jeff Vavasour, originally for his MSDOS-based TRS-80 emulators. The DMK format was designed by David Keil for his MSDOS-based TRS-80 emulator. The hard disk file format was designed by Matthew Reed for his MSDOS-based TRS-80 emulators. Al Petrofsky and Todd P. Cromwell III supplied font data. Roland Gerlach contributed the CP/M import and export programs as well as several bug reports and fixes for the emulator itself. Ulrich Mueller added the -borderwidth option, improved the -scale option and the bitmap font scaling, ported the import, export, and settime utilities to Newdos/80, and contributed the HRG1B emulation. Branden Robinson supplied the first version of the cassette man page, fixed Makefile bugs, translated cassette to the Bourne shell, and implemented watchpoints in zbx. Mark McDougall provided documentation for the Micro Labs Grafyx Solution card. Jenz Guenther added the -title option and contributed code to emulate the GENIE (German Model I clone). Joe Peterson contributed code to emulate the TimeDate80 and the -emtsafe feature. Denis Leconte contributed part of the -scale implementation. $Id: xtrs.man,v 1.69 2009/06/15 23:44:43 mann Exp $ xtrs-4.9d/xtrs.txt000066400000000000000000001742271306603614600143150ustar00rootroot00000000000000xtrs(1) xtrs(1) Name xtrs - TRS-80 Model I/III/4/4P emulator for the X Window System Syntax xtrs [-model m] [-diskdir d] [-debug] [other options] Description xtrs is built on top of a Z-80 emulator, with added routines to support keyboard and video I/O through an X interface. The hardware emulation can operate as a TRS-80 Model I, Model III, Model 4, or Model 4P. xtrs supports 48K of RAM in Model I or Model III mode, 128K in Model 4 or Model 4P mode. Floppy disks and hard disks are emulated using files to store the data; or under Linux only, real floppy drives can be used. A printer is emulated by sending its output to standard output. A serial port is emulated using a Unix tty device. Cassette I/O is emu- lated using files to store the cassette data; real cassettes can also be read or written (with luck), either directly through your sound card (on Linux and other systems with OSS-compatible sound drivers), or via .wav files. Game sound and music output are also supported if you have an OSS-compatible sound driver; sound output though the cassette port, through the Model 4 sound option, and through the optional Orches- tra-85/90 music synthesizer card are all emulated. In Model I mode, the HRG1B graphics card is emulated. In Model III and 4/4P mode, you can select whether the Radio Shack graphics card or Micro Labs Grafyx Solution is emulated. There is also a mouse driver for Model 4/4P mode. Several common time-of-day clock cards are emulated on all mod- els. The Alpha Products joystick is emulated using the PC's numeric keypad. Because xtrs emulates the hardware, all known TRS-80 Model I/III/4/4P operating systems should run on it, including all flavors of TRSDOS, LDOS/LS-DOS, NEWDOS, DOSPLUS, MultiDOS, and TRS-80 CP/M. However, the emulator also includes some extensions to the standard hardware, and the special drivers, utilities, and instructions needed for these are not provided for all operating systems. The Z-80 emulator has a debugger called zbx. You can enter the debug- ger either by starting xtrs with the -debug flag or by pressing F9 while xtrs is running. The debugger runs in the X terminal window that you started xtrs from. Once you are in the debugger, type "help" for more information. Special support in the emulator allows the program to block when wait- ing for information from the keyboard. This will work only for pro- grams that wait for keyboard input using the standard Model I/III ROM call; the emulator decides whether to block the Z-80 program when it tries to read from the keyboard memory by pattern-matching its stack. Keys The following keys have special meanings to xtrs: F11 toggles onscreen help on the keyboard mappings. LeftArrow, Backspace, or Delete is the TRS-80 left arrow key. RightAr- row or Tab is the right arrow key. UpArrow is the up arrow key. Dow- nArrow or Linefeed is the down arrow key. Esc or Break is the Break key. Home, Clear, or LeftAlt is the Clear key. Control is the Model 4 Ctrl key (address bit 7, data bit 2). RightAlt is equivalent to the shifted down arrow key (used as a control key with some TRS-80 soft- ware). F1, F2, and F3 are the Model 4/4P function keys (address bit 7, data bits 4, 5, and 6). F1 is also the Model I Electric Pencil control key that some users added to their machines. F4 is the Model 4 Caps Lock key (address bit 7, data bit 3). F5, Compose, or ScrollLock is equiva- lent to the @ key (so that @ can be used as a modifier key). F6 is equivalent to the 0 key (so that a shifted 0 can be obtained). F7 sig- nals a disk change in the emulated floppy drives (see below). F8 exits the program. F9 enters the debugger (zbx). F10 is the reset button. In Model III, 4, and 4P modes, the left and right shift keys are dis- tinct; in Model I mode, they are the same. The PageUp and PageDown keys always activate the positions that correspond to the Model III/4/4P left and right shift keys (address bit 7, data bits 0 and 1 respectively), even in Model I mode. The End key activates an unused position in the keyboard matrix (address bit 7, data bit 7). The keys [, \, ], ^, , {, |, }, and ~ also activate unused positions in the keyboard matrix (address bit 3, data bits 3-7). With many TRS-80 keyboard drivers, these keys map to the corresponding ASCII characters; with others, they do nothing. In some cases you may find the shift state is reversed from what it should be; if you press [ but { is displayed instead (etc.), see the -shiftbracket and -noshift- bracket options below to correct the problem. The Insert key maps to the same position as underscore (address bit 3, data bit 7), so that this key can be used both with and without shift pressed; with many TRS-80 keyboard drivers one of these maps to ASCII code 0x7f. On a German keyboard, the umlaut and "ess-tsett" keys should activate the corresponding characters used in the GENIE, a German Model I clone. This feature is most useful together with the "-charset genie" command line argument. Pressing a key on a PC numeric keypad with NumLock disengaged emulates the Alpha Products joystick. Keys 2, 4, 6, 8 (KP Down, KP Left, KP Right, KP Up) are the main directions; keys 1, 3, 7, and 9 (KP End, KP Page Down, KP Home, KP Page Up) work as diagonal directions by acti- vating two main directions at once; and key 0 (KP Insert) or 5 (KP Begin) is the fire button. Note that your X server may default to sending digits for the keys on the numeric pad even if NumLock is not pressed. If you have this problem, you can use the xmodmap program to remap your numeric pad, and use the xev program to debug it. Emulated cassette To control the emulated cassette, a file called ".cassette.ctl" in the current directory keeps track of what file is currently loaded as the cassette tape and the current position within that file. The cas- sette(1) shell script provides a way to manipulate this file. You may use this script to load and position cassette tape files. The opera- tion works very much like an actual tape recorder. See the cassette man page for more information about the cassette shell script and the cassette file formats that are supported. Printer For printer support, any text sent to the TRS-80's printer (using LPRINT or LLIST, for example) is sent to the standard output. Emulated floppy disks In Model I mode, xtrs emulates a Radio Shack Expansion Interface with the Percom Doubler or Radio Shack Doubler installed. The Doubler pro- vides double-density disk access by allowing either the stock WD1771 FDC chip or a WD1791 chip to be selected under program control. At powerup the 1771 is selected, so operating systems with no Doubler driver see a stock system. By default, the emulator pretends to be both a Percom and Radio Shack Doubler at the same time -- it responds to the special commands of both -- so a driver for either should work. Under LDOS, use the command "FDUBL" (newer versions of LDOS), or "PDUBL" or "RDUBL" (older versions) to install the driver. Software that tries to detect which doubler you have (such as Super Utility) may be confused by the emulation of both at once, so you can choose to emu- late only one with a command line option; see below. In Model III, 4, or 4P mode, xtrs emulates the stock floppy controller, which uses a WD1793 chip (software-compatible with the WD1791) to pro- vide both single and double density. Four 5.25-inch floppy drives are emulated, with storage in files named diskM-U, where M is the TRS-80 model (1, 3, 4, or 4p) and U is the drive unit number (0, 1, 2, or 3). If a file of the required name is not found, a drive with no disk in it is emulated (but see below). If the user does not have write permission for a floppy file, and/or the file has an internal write protect flag set, a write-protect tab is emulated. Use the mkdisk(1) program to turn the write protect flag on or off. To change floppies in an emulated drive, rename the existing file for the drive (if any), rename the new floppy file to the proper name, and hit function key F7 in the emulator. If you try to boot an emulated Model I, III, or 4 with no file named diskM-0 (that is, no disk in drive 0), xtrs emulates having no floppy disk controller. The behavior of a real machine with a disk controller in this case didn't seem useful to emulate faithfully: A real Model I hangs with a screen full of garbage; a real Model III or 4 goes into a retry loop printing "Diskette?" on the screen and rechecking whether you've inserted one. A real Model 4P always has a floppy controller, however, so xtrs always emulates one. Due to a limitation of the original Model I hardware, drive :3 cannot be double-sided in Model I mode. In the original Model I, you could not have a drive :3 at all if any drive in the system was double-sided, but the emulator is able to be more forgiving. Emulated floppy image files can be of any of three types: JV1, compati- ble with Jeff Vavasour's popular freeware Model I emulator for MS-DOS; JV3, a compatible extension of a format first used in Vavasour's com- mercial Model III/4 emulator; or DMK, compatible with David Keil's Model 4 emulator. All three types work in xtrs regardless of what model it is emulating. A heuristic is used to decide which type of image is in a drive, as none of the types has a magic number or signa- ture. JV1 supports only single density, single sided, with directory on track 17. Sectors must be 256 bytes long. Use FORMAT (DIR=17) if you want to format JV1 disks with more (or less) than 35 tracks under LDOS. JV3 is much more flexible, though it still does not support everything the real controllers could do. It is probably best to use JV3 for all the disk images you create, since it is the most widely implemented by other emulators, unless you have a special reason to use one of the others. A JV3 disk can be formatted with 128, 256, 512, or 1024-byte sectors, 1 or 2 sides, single or double density, with either FB (nor- mal) or F8 (deleted) data address mark on any sector. In single den- sity the nonstandard data address marks FA and F9 are also available. You cannot format a sector with an incorrect track number or head num- ber. You can format a sector with an intentional CRC error in the data field. xtrs supports at most 5802 total sectors on a JV3 image. The original Vavasour JV3 format supported only 256-byte sectors, and had a limit of 2901 total sectors. If you use sector sizes other than 256 bytes or format more than 2901 sectors on a disk image, emulators other than xtrs may be unable to read it. Note that an 80 track, dou- ble-sided, double-density (18 sector) 5.25-inch floppy will fit within the original 2901 sector limit; the extension to 5802 is primarily for emulation of 8-inch drives (discussed below). The DMK format is the most flexible. It supports essentially every- thing that the original hardware could do, including all "protected" disk formats. However, a few protected disks still may not work with xtrs due to limitations in xtrs's floppy disk controller emulation rather than limitations of the DMK format; see the LIMITATIONS section below. The program mkdisk(1) makes a blank emulated floppy or "bulk erases" an existing one. By default, mkdisk makes a JV3 floppy, but with the -1 flag it makes a JV1 floppy, or with the -k flag a DMK floppy. See the mkdisk man page for more information. Early Model I operating systems used an FA data address mark for the directory on single density disks, while later ones wrote F8 but would accept either upon reading. The change was needed because FA is a non- standard DAM that is fully supported only by the WD1771 floppy disk controller used in the Model I; the controllers in the Model III and 4 cannot distinguish between FA and FB (which is used for non-directory sectors) upon reading, and cannot write FA. To deal nicely with this problem, xtrs implements the following kludge. On writing in single density, an F8 data address mark is recorded as FA. On reading with an emulated WD1771 (available in Model I mode only), FA is returned as FA; on reading with a WD179x, FA is returned as F8. This trick makes the different operating systems perfectly compatible with each other, which is better than on a real Model I! You can use the -truedam flag to turn off this kludge if you need to; in that case the original hardware is emulated exactly. TRS-80 programs that attempt to measure the rotational speed of their floppy disk drives using timing loops will get the answers they expect, even when xtrs does not emulate instructions at the same speed as the original machines. This works because xtrs keeps a virtual clock (tech- nically, a T-state counter), which measures how much time it should have taken to execute the instruction stream on a real machine, and it ties the emulation of floppy disk index holes to this clock, not to real time. Emulated 8-inch floppy disks In addition to the four standard 5.25-inch drives, xtrs also emulates four 8-inch floppy drives. There is no widely-accepted standard hard- ware interface for 8-inch floppies on the TRS-80, so xtrs emulates a pseudo-hardware interface of its own and provides an LDOS/LS-DOS driver for it. Storage for the emulated 8-inch disks is in files named diskM-U, where M is the TRS-80 model number (1, 3, 4, or 4p) and U is a unit number (4, 5, 6, or 7). The only difference between 5.25-inch and 8-inch emu- lated drives is that the emulator allows you to format more bytes per track in the latter. A new JV3 floppy can be formatted as either 5.25-inch or 8-inch depending on whether you initially put it into a 5.25-inch or 8-inch emulated drive. A new DMK floppy, however, must be created with the -8 flag to mkdisk in order to be large enough for use in an 8-inch emulated drive. JV1 floppies cannot be used in 8-inch drives. Be careful not to put an emulated floppy into a 5.25-inch emu- lated drive after it has been formatted in an 8-inch emulated drive or vice versa; the results are likely to be confusing. Consider using different file extensions for the two types; say, .dsk for 5.25-inch and .8in for 8-inch. To use the emulated 8-inch drives, you'll need a driver. Under LDOS or LS-DOS, use the program XTRS8/DCT supplied on the emulated floppy util- ity.dsk. This driver is a very simple wrapper around the native LDOS/LS-DOS floppy driver. Here are detailed instructions. First, make sure an appropriate version of LDOS is in emulated floppy drive 0, and the supplied file utility.dsk is in another emulated floppy drive. Boot LDOS. If you are using Model I LDOS, be sure FDUBL is running. Second, type the following commands. Here d is the LDOS drive number you want to use for the 8-inch drive and u is the unit number you chose when naming the file. Most likely you will choose d and u to be equal to reduce confusion. SYSTEM (DRIVE=d,DRIVER="XTRS8",ENABLE) Enter unit number ([4]-7): u You can repeat these steps with different values of d and u to have more than one 8-inch drive. You might want to repeat four times using 4, 5, 6, and 7, or you might want to save some drive numbers for hard drives (see below). Finally, it's a good idea to give the SYSTEM (SYSGEN) command (Model I/III) or SYSGEN command (Model 4/4P). This command saves the SYSTEM settings, so the 8-inch drives will be available again the next time you reboot or restart the emulator. If you need to access an 8-inch drive after booting from a disk that hasn't been SYSGENed, simply use the same SYSTEM command again. In case you want to write your own driver for another TRS-80 operating system, here are details on the emulated pseudo-hardware. The 8-inch drives are accessed through the normal floppy disk controller, exactly like 5.25-inch drives. The four 5.25-inch drives have hardware select codes 1, 2, 4, and 8, corresponding respectively to files diskM-0, -1, -2, and -3. The four 8-inch drives have hardware select codes 3, 5, 6, and 7, corresponding respectively to files diskM-4, -5, -6, and -7. (See also the -sizemap option below, however.) Real floppy disks Under Linux only, any diskM-U file can be a symbolic link to a real floppy disk drive, typically /dev/fd0 or /dev/fd1. Most PCs should be able to read and write TRS-80 compatible floppies in this way. Many PC floppy controllers cannot handle single density, however, and some may have problems even with double density disks written on a real TRS-80, especially disks formatted by older TRS-80 operating systems. Use the -doublestep flag if you need to read 35-track or 40-track media in an 80-track drive. If you need to write 35-track or 40-track media in an 80-track drive, bulk-erase the media first and format it in the 80-track drive. Don't write to a disk in an 80-track drive if it has ever been written to in a 40-track drive. The narrower head used in an 80-track drive cannot erase the full track width written by the head in a 40-track drive. If you link one of the 5.25-inch floppy files (diskM-0 through diskM-3) to a real floppy drive, TRS-80 programs will see it as a 5.25-inch drive, but the actual drive can be either 3.5-inch or 5.25-inch. The drive will be operated in double density (or single density), not high density, so be sure to use the appropriate media. If you link one of the 8-inch floppy files (diskM-4 through diskM-7) to a real floppy drive, TRS-80 programs will see it as an 8-inch drive. Again, you need to use the XTRS8/DCT driver described above to enable LDOS/LS-DOS to access an 8-inch drive. The real drive can be either 3.5-inch, 5.25-inch, or 8-inch. A 3.5-inch or 5.25-inch drive will be operated in high-density mode, using MFM recording if the TRS-80 is trying to do double density, FM recording if the TRS-80 is trying to do single density. In this mode, these drives can hold as much data as a standard 8-inch drive. In fact, a 5.25-inch HD drive holds exactly the same number of bits per track as an 8-inch drive; a 3.5-inch HD drive can hold 20% more, but we waste that space when using one to emulate an 8-inch drive. In both cases we also waste the top three tracks, since an 8-inch drive has only 77 tracks, not 80. The nonstandard FA and F9 data address marks available in single den- sity on a real Model I with the WD1771 controller also need special handling. A PC-style floppy disk controller can neither read nor write sectors with such DAMs at all. This raises three issues: (1) It will be impossible for you to read some Model I disks on your PC even if your PC otherwise supports single density. In particular, Model I TRS- DOS 2.3 directory tracks will be unreadable. (2) On writing in single density, xtrs silently records a F9 or FA DAM as F8. (3) On reading in single density with an emulated WD1771 (Model I mode only), F8 is returned as FA. If you need more accurate behavior, the -truedam flag will turn on error messages on attempts to write F9 or FA DAMs and will turn off translation of F8 to FA on reading. Hint: Be sure to set the drive type correctly in your PC's BIOS. Linux and xtrs rely on this information to know how fast your drives are spinning and hence what data rate to use when reading and writing. All 3.5-inch drives spin at 300 RPM. Newer 5.25-inch high-density capable drives ("1.2MB" drives) normally always spin at 360 RPM. (Some can be jumpered to slow down to 300 RPM when in double-density mode, but you should not do that when plugging one into a PC.) Older 5.25-inch drives that cannot do high density ("180KB", "360KB" or "720KB" 5.25-inch drives) always spin at 300 RPM. All 8-inch drives spin at 360 RPM. If you plug an 8-inch drive into a PC (this requires a 50-pin to 34-pin adaptor cable), tell your BIOS that it is a 5.25-inch 1.2MB drive. Emulated hard disks xtrs can emulate a hard disk in a file in one of two ways: it can use a special, xtrs-specific LDOS driver called XTRSHARD/DCT, or it can emu- late the Radio Shack hard drive controller (based on the Western Digi- tal WD1010) and use the native drivers for the original hardware. Using XTRSHARD/DCT The XTRSHARD/DCT driver has been tested and works under both LDOS 5.3.1 for Model I or III and TRSDOS/LS-DOS 6.3.1 for Model 4/4P. It may or may not work under earlier LDOS versions. It definitely will not work under other TRS-80 operating systems or with emulators other than xtrs. The hard disk format was designed by Matthew Reed for his Model I/III and Model 4 emulators; xtrs duplicates the format so that users can exchange hard drive images across the emulators. To use XTRSHARD/DCT, first run the mkdisk program under Unix to create a blank hard drive (.hdv) file. Typical usage would be: mkdisk -h mydisk.hdv. See the mkdisk(1) man page for other options. Second, link the file to an appropriate name. XTRSHARD/DCT supports up to eight hard drives, with names of the form hardM-U, where M is the TRS-80 model (1, 3, or 4; in this case Model 4P also uses M=4) and U is a unit number from 0 to 7. It looks for these files in the same direc- tory as the floppy disk files diskM-U. Third, make sure an appropriate version of LDOS is in emulated floppy drive 0, and the supplied file utility.dsk is in another emulated floppy drive. Boot LDOS. If you are using Model I LDOS 5.3.1, patch a bug in the FORMAT command by typing PATCH FORMAT/CMD.UTILITY M1FOR- MAT/FIX. You need to apply this patch only once. It must not be applied to Model III or Model 4/4P LDOS. Fourth, type the following commands. Here d is the LDOS drive number you want to use for the hard drive (a typical choice would be 4) and u is the unit number you chose when naming the file (most likely 0). SYSTEM (DRIVE=d,DRIVER="XTRSHARD",ENABLE) Enter unit number ([0]-7): u FORMAT d (DIR=1) Answer the questions asked by FORMAT as you prefer. The DIR=1 parame- ter to FORMAT is optional; it causes the hard drive's directory to be on track 1, making the initial size of the image smaller. You can repeat these steps with different values of d and u to have more than one hard drive. Finally, it's a good idea to give the SYSTEM (SYSGEN) command (Model I/III) or SYSGEN command (Model 4/4P). This command saves the SYSTEM settings, so the drive will be available again the next time you reboot or restart the emulator. If you need to access the hard disk file after booting from a floppy that hasn't been SYSGENed, simply use the same SYSTEM command(s) again, but don't FORMAT. You can freely use a different drive number or (if you renamed the hard disk file) a differ- ent unit number. The F7 key currently doesn't allow XTRSHARD/DCT disk changes to be rec- ognized, but you can change to a different hard disk file for the same unit by renaming files as needed and rebooting LDOS. Technical note: XTRSHARD/DCT is a small Z-80 program that implements all the required functions of an LDOS disk driver. Instead of talking to a real (or emulated) hard disk controller, however, it uses special support in xtrs that allows Z-80 programs to open, close, read, and write Unix files directly. This support is described further in the "Data import and export" section below. Using native hard disk drivers Beginning in version 4.1, xtrs also emulates the Radio Shack hard disk controller (based on the Western Digital WD1010) and will work with the native drivers for this hardware. This emulation uses the same hard drive (.hdv) file format that XTRSHARD/DCT does. With LDOS/LS-DOS, the RSHARDx/DCT and TRSHD/DCT drivers are known to work. With Montezuma CP/M 2.2, the optional Montezuma hard disk drivers are known to work. The hard disk drivers for NEWDOS/80 and for Radio Shack CP/M 3.0 should work, but they have not yet been tested at this writing. Any bugs should be reported. To get started, run the mkdisk program under Unix to create a blank hard drive (.hdv) file. Typical usage would be: mkdisk -h mydisk.hdv. See the mkdisk(1) man page for other options. Second, link the file to an appropriate name. The WD1010 emulation supports up to four hard drives, with names of the form hardM-U, where M is the TRS-80 model (1, 3, 4, or 4p) and U is a unit number from 0 to 3. It looks for these files in the same directory as the floppy disk files diskM-U. If no such files are present, xtrs disables the WD1010 emulation. Note that if hard drive unit 0 is present on a Model 4P (file hard4p-0), the Radio Shack boot ROM will always try to boot from it, even if the operating system does not support booting from a hard drive. If you have this problem, either hold down F2 while booting to force the ROM to boot from floppy, or simply avoid using unit number 0. Stock TRSDOS/LS-DOS 6 systems do not support booting from a hard drive; M.A.D. Software's HBUILD6 add-on to LS-DOS for hard drive booting should work, but is untested. Montezuma CP/M 2.2 does boot from the emulated hard drive. Finally, obtain the correct driver for the operating system you will be using, read its documentation, configure the driver, and format the drive. Detailed instructions are beyond the scope of this manual page. Data import and export Several Z-80 programs for data import and export from various TRS-80 operating systems are included with xtrs on two emulated floppy images. These programs use special support in the emulator to read and write external Unix files, discussed further at the end of this section. The emulated floppy utility.dsk contains some programs for transferring data between the emulator and ordinary Unix files. IMPORT/CMD, EXPORT/CMD, and SETTIME/CMD run on the emulator under Model I/III TRS- DOS, Model I/III LDOS, Model I/III Newdos/80, and Model 4/4P TRSDOS/LS- DOS 6; they may also work under other TRS-80 operating systems. Model III TRSDOS users will have to use TRSDOS's CONVERT command to read utility.dsk. IMPORT/CMD imports a Unix file and writes it to an emulated disk. Usage: IMPORT [-lne] unixfile [trsfile]. The -n flag converts Unix newlines (\n) to TRS-80 newlines (\r). The -l flag converts the Unix filename to lower case, to compensate for TRS-80 operating systems such as Newdos/80 that convert all command line arguments to upper case. When using the -l flag, you can put a [ or up-arrow in front of a char- acter to keep it in upper case. Give the -e flag if your TRS-80 oper- ating system uses the Newdos/80 convention for representing the ending record number in an open file control block. This should be detected automatically for Newdos/80 itself and for TRSDOS 1.3, but you'll need to give the flag for DOSPLUS and possibly other non-LDOS operating sys- tems. If you need the flag but don't give it (or vice versa), imported files will come out the wrong length. If the destination file is omit- ted, IMPORT uses the last component of the Unix pathname, but with any "." changed to "/" to match TRS-80 DOS file extension syntax. EXPORT/CMD reads a file from an emulated disk and exports it to a Unix file. Usage: EXPORT [-lne] trsfile [unixfile]. The -n flag converts TRS-80 newlines (\r) to Unix newlines (\n). The -l flag converts the Unix filename to lower case. When using the -l flag, you can put a [ or up-arrow in front of a character to keep it in upper case. Give the -e flag if your TRS-80 operating system uses the Newdos/80 convention for representing the ending record number in an open file control block. This should be detected automatically for Newdos/80 itself and for TRSDOS 1.3, but you'll need to give the flag for DOSPLUS and possi- bly other non-LDOS operating systems. If you need the flag but don't give it (or vice versa), exported files will come out the wrong length. If the destination file is omitted, EXPORT uses the TRS-80 filename, but with any "/" changed to "." to match Unix file extension syntax. SETTIME/CMD reads the date and time from Unix and sets the TRS-80 DOS's date and time accordingly. The next several programs were written in Misosys C and exist in two versions on utility.dsk. The one whose name ends in "6" runs on Model 4 TRSDOS/LS-DOS 6.x; the other runs on LDOS 5.x and most other Model I/III operating systems. CD/CMD (or CD6/CMD) changes xtrs's Unix working directory. Usage: CD [-l] unixdir. The -l flag converts the Unix directory name to lower case. When using the -l flag, you can put a [ or up-arrow in front of a character to keep it in upper case. Running CD/CMD will change the interpretation of any relative pathnames given to IMPORT or EXPORT. It will also change the interpretation of disk names at the next disk change, unless you specified an absolute pathname for xtrs's -diskdir parameter. PWD/CMD (or PWD6/CMD) prints xtrs's Unix working directory. UNIX/CMD (or UNIX6/CMD) runs a Unix shell command. Usage: UNIX [-l] unix command line. The -l flag converts the Unix command line to lower case. When using the -l flag, you can put a [ or up-arrow in front of a character to keep it in upper case. Standard I/O for the command uses the xtrs program's standard I/O descriptors; it does not go to the TRS-80 screen or come from the TRS-80 keyboard. MOUNT/CMD (or MOUNT6/CMD) is a convenience program that switches emu- lated floppy disks in the drives. Usage: MOUNT [-l] filename U. The -l flag converts the Unix filename to lower case. When using the -l flag, you can put a [ or up-arrow in front of a character to keep it in upper case. The filename is any Unix filename; U is a single digit, 0 through 7. The command deletes the file diskM-U (where M is the TRS-80 model) from the disk directory (see -diskdir option), replaces it with a symbolic link to the given filename, and signals a disk change (as if F7 had been pressed). UMOUNT/CMD (or UMOUNT6/CMD) is a convenience program that removes an emulated floppy disk from a drive. Usage: UMOUNT U. U is a single digit, 0 through 7. The command deletes the file diskM-U (where M is the TRS-80 model) from the disk directory (see -diskdir option) and signals a disk change (as if F7 had been pressed). The emulated floppy cpmutil.dsk contains import and export programs for Montezuma CP/M, written by Roland Gerlach. It was formatted as a "Mon- tezuma Micro Standard DATA disk (40T, SS, DD, 200K)," with 512-byte sectors. Be careful to configure your CP/M to the proper disk format and drive parameters (40 track, not 80), or you will have confusing problems reading this disk. Documentation is included in the file cpmutil.html and source code in the file cpmutil.tgz (a gzipped tar archive). See http://members.optusnet.com.au/~rgerlach/trs-80/cpmu- til.html where you will sometimes find a newer version of the utilities than is included with xtrs. The emulator implements a set of pseudo-instructions (emulator traps) that give TRS-80 programs access to Unix files. The programs listed above use them. If you would like to write your own such programs, the traps are documented in the file trs imp exp.h. Assembler source code for the existing programs is supplied in xtrshard.z, import.z, export.z, and settime.z. You can also write programs that use the traps in Misosys C, using the files xtrsemt.h and xtrsemt.ccc as an interface; a simple example is in settime.ccc. Interrupts The emulator supports only interrupt mode 1. It will complain if your program enables interrupts after powerup without executing an IM 1 instruction first. All Model I/III/4/4P software does this, as the built-in peripherals in these machines support only IM 1. The Model I has a 40 Hz heartbeat clock interrupt, while the Model III uses 30 Hz, and the Model 4/4P can run at either 30 Hz or 60 Hz. The emulator approximates this rather well even on a system where clock ticks come at some frequency that isn't divisible by the emulated fre- quency (e.g., 100 Hz on Intel Linux), as long as the true frequency is not slower than the emulated frequency. The emulator has a notion of the absolute time at which each tick is supposed to occur, and it asks the host system to wake it up at each of those times. The net result is that some ticks may be late, but there are always the proper number of ticks per second. For example, running in Model I mode on Intel Linux you'd see this pattern: (tick, 30ms, tick, 20ms,...) instead of seeing ticks every 25ms. Processor speed selection A standard Model 4 has a software-controlled switch to select operation at either 4.05504 MHz (with heartbeat clock at 60 Hz) or 2.02752 MHz (with heartbeat clock at 30 Hz). xtrs emulates this feature. Model I's were often modified to operate at higher speeds than the standard 1.77408 MHz. With one common modification, writing a 1 to port 0xFE would double the speed to 3.54816 MHz, while writing a 0 would set the speed back to normal. The heartbeat clock runs at 40 Hz in either case. xtrs emulates this feature as well. Sound Sound support uses the Open Sound System /dev/dsp device, standard on Linux and available on many other Unix versions as well. This support is compiled in automatically on Linux; if you have OSS on another ver- sion of Unix, you'll need to define the symbol HAVE OSS in your Make- file or in trs cassette.c. Any time TRS-80 software tries to write non-zero values to the cassette port (or the Model 4/4P optional sound port) with the cassette motor off, it is assumed to be trying to make sounds and xtrs opens /dev/dsp. It automatically closes the device again after a few seconds of silence. If you are playing a game with sound, you'll want to use the -autodelay flag to slow down instruction emulation to approximately the speed of a real TRS-80. If you don't do this, sound will still play correctly, but the gameplay may be way too fast and get ahead of the sound. On the other hand, if your machine is a bit too slow, you'll hear gaps and pops in the sound when the TRS-80 program lags behind the demand of the sound card for more samples. The -autodelay feature includes a small speed boost whenever a sound starts to play to try to prevent this, but if the boost is too much or too little, you might either find that the game runs too fast when a lot of sound is playing, or that the sound has gaps in it anyway. If your sound has gaps, you can try reducing the sample rate with the -samplerate flag. The Orchestra-85 music synthesis software will run under xtrs's Model I emulation, and the Orchestra-90 software will run with Model III oper- ating systems under xtrs's Model III, 4, or 4P emulation. For best results, use Orchestra-90 and the Model 4 emulation, as this lets the software run at the highest emulated clock rate (4 MHz) and thus gener- ate the best sound. If you want to run Orchestra-85 instead, you can tell it that you have a 3.5 MHz clock speedup with enable sequence 3E01D3FE and disable sequence 3E00D3FE; this will let the software run twice as fast as on an unmodified Model I and generate better sound. There is no need to use xtrs's -autodelay flag when running Orches- tra-85/90, but you might want to specify a small fixed delay to keep from getting excessive key repeat. Mouse A few Model 4 programs could use a mouse, such as the shareware hi-res drawing program MDRAW-II. The program XTRSMOUS/CMD on the utility disk (utility.dsk) is a mouse driver for Model 4/4P mode that should work with most such programs. xtrs does not emulate the actual mouse hard- ware (a serial mouse plugged into the Model 4 RS-232 port), so the original mouse drivers will not work under xtrs. Instead, XTRSMOUS accesses the X mouse pointer using an emulator trap. XTRSMOUS imple- ments the same TRSDOS/LS-DOS 6 SVC interface as the David Goben and Matthew Reed mouse drivers. (It does not implement the interface of the older Scott McBurney mouse driver, which may be required by some pro- grams.) By default XTRSMOUS installs itself in high memory. This is done because MDRAW-II tests for the presence of a mouse by looking to see whether the mouse SVC is vectored to high memory. If the driver is installed in low memory, MDRAW thinks it is not there at all. If you use mouse-aware programs that don't have this bug, or if you edit the first line of MDRAW to remove the test, you can install XTRSMOUS in low memory using the syntax "XTRSMOUS (LOW)". Time of day clock Several battery-backed time of day clocks were sold for the various TRS-80 models, including the TimeDate80, TChron1, TRSWatch, and T- Timer. They are essentially all the same hardware, but reside at a few different port ranges. xtrs currently emulates them at port ranges 0x70-0x7C and 0xB0-0xBC. The T-Timer port range at 0xC0-0xCC conflicts with the Radio Shack hard drive controller and is not emulated. These clocks return only a 2-digit year, and it is unknown what their driver software will do in the year 2000 and beyond. If you have soft- ware that works with one of them, please send email to report what hap- pens when it is used with xtrs. Also see SETTIME/CMD in the "Data import and export" section above for another way to get the correct time into a Z-80 operating system run- ning under xtrs. Finally, you might notice that LDOS/LS-DOS always magically knows the correct date when you boot it (but not the time). When you first power up the emulated TRS-80, xtrs dumps the date into the places in memory where LDOS and LS-DOS normally save it across reboots, so it looks to the operating system as if you rebooted after setting the date. Joystick Pressing a key on a PC numeric keypad with NumLock disengaged emulates the Alpha Products joystick. See the Keys section above for details. The emulated joystick is mapped only at port 0, to avoid conflicts with other devices. The joystick emulation could be made to work with real joysticks using the X input extension, but this is not implemented yet. Running games Some games run rather well under xtrs now, provided that your machine is fast enough to run the emulation in real time and that you choose the right command line options. "Galaxy Invaders Plus" by Big 5 Soft- ware is particularly good. You will usually want to turn on autodelay, and if your machine is slow you may need to reduce the sound sample rate. Running your X server in 8-bit/pixel mode also seems to help in some cases. Example command lines: startx -- -bpp 8 xtrs -autodelay If you have a slow machine and the sound breaks up, it is possible that your machine is not fast enough to generate samples at the default rate of 44,100 Hz. If you think this may be happening, try "-samplerate 11025" or even "-samplerate 8000". Options Defaults for all options can be specified using the standard X resource mechanism, and the class name for xtrs is "Xtrs". -display display Set your X display to display. The default is to use the DISPLAY environment variable. -iconic Start with the xtrs window iconified. -background color -bg color Specifies the background color of the xtrs window. -foreground color -fg color Specifies the foreground color of the xtrs window. -title titletext Use titletext in the window title bar instead of the program name. -borderwidth width Put a border of width pixels around the TRS-80 display. The default is 2. -scale xfac[,yfac] Multiply the horizontal and vertical window size by xfac and yfac, respectively. Possible values are integers in the range [1,4] for xfac and [1,8] for yfac. Defaults are xfac=1 and yfac=2*xfac. -resize In Model III or 4/4P mode, resize the X window whenever the emu- lated display mode changes between 64x16 text (or 512x192 graph- ics) and 80x24 text (or 640x240 graphics). This is the default in Model III mode, since 80x24 text is not available and the 640x240 graphics add-on card is seldom used. -noresize In Model III or 4/4P mode, always keep the X window large enough for 80x24 text or 640x240 graphics, putting a blank margin around the outside when the emulated display mode is 64x16 text or 512x192 graphics. This is the default in Model 4/4P mode, since otherwise there is an annoying size switch during every reboot. -charset name Select among several sets of built-in character bitmaps. In Model I mode, five sets are available. The default, wider, is a modified Model III set with characters 8 pixels wide; it looks better on a modern computer screen with square pixels than the real Model I fonts, which were 6 pixels wide. lcmod is the char- acter set in the replacement character generator that was sup- plied with the Radio Shack lower case modification. (It was reconstructed partly from memory and may have some minor bit errors.) stock is the character set in the stock character gen- erator supplied with most upper case only machines. Since xtrs currently always emulates the extra bit of display memory needed to support lower case, this character set gives you the authen- tic, unpleasant effect that real Model I users saw when they tried to do homebrew lower case modifications without replacing the character generator: lower case letters appear at an incon- sistent height, and if you are using the Level II BASIC ROM dis- play driver, upper case letters are replaced by meaningless sym- bols. early is the same as stock, but with the standard ASCII characters [, \, ], and ^ in the positions where most Model I's had directional arrows. This was the default programming in the Motorola character generator ROM that Radio Shack used, and a few early machines were actually shipped with this ROM. Finally, german or genie gives an approximate emulation of the GENIE, a German Model I clone. Characters are 8 pixels wide, and double width is supported even though later GENIE models did not include it. In Model III, 4, and 4P modes, three sets are available: katakana (the default for Model III) is the original Model III set with Japanese Katakana characters in the alternate character positions. This set was also used in early Model 4's. interna- tional (the default for Model 4 and 4P) is a later Model 4 set with accented Roman letters in the alternate positions. bold is a bold set from a character generator ROM found in one Model III, origin uncertain. -usefont Use X fonts instead of the built-in character bitmaps. -nofont Use the built-in character bitmaps, not a X font. This is the default. -font fontname If -usefont is also given, use the specified X font for normal width characters. The default uses a common X fixed-width font: "-misc-fixed-medium-r-normal--20-200-75-75-*-100-iso8859-1". -widefont fontname If -usefont is also given, use the specified X font for double width characters. The default uses a common X fixed-width font, scaled to double width: "-misc-fixed-medium-r-nor- mal--20-200-75-75-*-200-iso8859-1". -nomicrolabs In Model I mode, emulate the HRG1B 384x192 hi-res graphics card. In Model III mode or Model 4/4P mode, emulate the Radio Shack hi-res card. This is now the default. -microlabs In Model III or 4/4P mode, emulate the Micro Labs Grafyx Solu- tion hi-res graphics card. Note that the Model III and Model 4/4P cards from Micro Labs are very different from one another. -debug Enter zbx, the z80 debugger. -romfile filename -romfile3 filename3 -romfile4p filename4p Use the romfile specified by filename in Model I mode, the rom- file specified by filename3 in Model III and Model 4 mode, or the romfile specified by filename4p in Model 4P mode, A romfile can be either a raw binary dump, Intel hex format, or TRS-80 cmd format (for example, a MODELA/III file). If you do not set this option or the corresponding X resource, a default established at compile time is used (if any); see Makefile.local for instruc- tions on compiling in default romfiles or default romfile names. -model m Specifies which TRS-80 model to emulate. Values accepted are 1 or I (Model I), 3 or III (Model III), 4 or IV (Model 4), and 4P or IVP (Model 4P). Model I is the default. -delay d A crude speed control. After each Z-80 instruction, xtrs busy- waits for d iterations around an empty loop. A really smart C optimizer might delete this loop entirely, so it's possible that this option won't work if you compile xtrs with too high an optimization level. The default delay is 0. -autodelay Dynamically adjusts the value of -delay to run instructions at roughly the same rate as a real machine. The tracking is only approximate, but it can be useful for running games. -noautodelay Turn off -autodelay. This is the default. -keystretch cycles Fine-tune the keyboard behavior. To prevent keystrokes from being lost, xtrs "stretches" the intervals between key transi- tions, so that the Z-80 program has time to see each transition before the next one occurs. Whenever the Z-80 program reads the keyboard matrix and sees an emulated key go up or down, xtrs waits cycles Z-80 clock cycles (T-states) before it allows the program to see another key transition. Key transitions that are received during the waiting period or when the Z-80 program is not reading the keyboard are held in a queue. The default stretch value is 4000 cycles; it should seldom if ever be neces- sary to change it. -shiftbracket Emulate [, \, ], ^, and as shifted keys, and {, |, }, and ~ as unshifted. This is the default in Model 4 and 4P modes, and it works well with the keyboard driver in Model 4 TRSDOS/LS-DOS 6. -noshiftbracket Emulate [, \, ], ^, and as unshifted keys, and {, |, }, and ~ as shifted. This is the default in Model I and III modes, and it works well with many TRS-80 keyboard drivers. With some key- board drivers these keys do not work at all, however. -diskdir dir Specify the directory containing floppy and hard disk images. If the value starts with "~/" (or is just "~"), it is relative to your home directory. The default value is ".". -doubler type Specify what type of double density adaptor to emulate (Model I mode only). The type may be percom, radioshack (or tandy), both, or none. The type may be abbreviated to one character. The default is both, which causes the double density adaptor emulation to respond to the special commands of both the Percom and Radio Shack cards. -doublestep Make all real floppy drives double-step, allowing access to 35-track or 40-track media in an 80-track drive. Linux only. See the Floppy Disks section for limitations. -nodoublestep Turn off double-step mode for all real floppy drives. Linux only. This is the default. -stepmap s0,s1,s2,s3,s4,s5,s6,s7 Selectively set double-step mode for individual real floppy drives. If sU is 2 and diskM-U is a real drive, the drive will be double-stepped; if sU is 1, it will be single-stepped. You can omit values from the end of the list; those drives will get the default value set by -doublestep or -nodoublestep. -sizemap z0,z1,z2,z3,z4,z5,z6,z7 Selectively set whether drives are emulated as 5-inch or 8-inch; see the section "Emulated 8-inch floppy disks" above. If zU is 5, the drive will appear to Z-80 software as 5-inch; if 8, as 8-inch. The default setting (as reflected in the documentation above) is 5,5,5,5,8,8,8,8. You can omit values from the end of the list; those drives will get the default values. Setting one or more of the first four drives to 8-inch may be useful for CP/M software that supports 8-inch drives. You can also use XTRS8/DCT with 8-inch drives in the first four positions; even though the prompt suggests the unit number must be 4-7, numbers 0-3 are accepted. XTRS8 does not check whether the unit you've selected is really being emulated as an 8-inch drive, however; you'll simply get errors during FORMAT if you get this wrong. -truedam Turn off the single density data address mark remapping kludges described in the "Emulated floppy disks" and "Real floppy disks" sections above. With this option given, the distinction between F8 and FA data address marks is strictly observed on both writ- ing and reading. This option is probably not useful unless you need to deal with Model I disks that use the distinction as part of a copy-protection scheme. See also "Common File Formats for Emulated TRS-80 Floppy Disks", available at http://www.tim- mann.org/trs80/dskspec.html. -notruedam The opposite of -truedam. This setting is the default. -samplerate rate Set the sample rate for new cassette wav files, direct cassette I/O to the sound card, and game sound output to the sound card. Existing wav files will be read or modified using their original sample rate regardless of this flag. The default is 44,100 Hz. See also the cassette(1) man page. -serial ttyname Set the tty device to be used for I/O to the TRS-80's serial port. The default is /dev/ttyS0 on Linux, /dev/tty00 on other versions of Unix. Setting the name to be empty (-serial "") emulates having no serial port. -switches value Set the sense switches on the Model I serial port card. This option is meaningful only in Model I mode, and only when the -serial option is not set to "". The default value is 0x6f, which Radio Shack software conventionally interprets as 9600 bps, 8 bits/word, no parity, 1 stop bit. -emtsafe Disable emulator traps (see "Data import and export") that could write to host files other than disk images in the original diskdir. -noemtsafe The opposite of -emtsafe. This setting is the default. Additional resources There are many other TRS-80 resources available on the Web, including shareware and freeware emulators that run under MSDOS and other operat- ing systems, software for converting TRS-80 physical media to the emu- lator's disk file format, ROM images, and TRS-80 software that has already been converted. For pointers, see http://www.tim- mann.org/trs80.html. Bugs and limitations The emulated serial port's modem status and control signals are not tied to the signals on the real serial port, because the real signals are not available to software through the Unix tty device interface. The ability to check for parity, framing, and overrun errors and receive an interrupt when one occurs is not emulated. Unix does not support 2000, 3600, or 7200 baud, so these TRS-80 data rates are remapped to 38400, 57600, and 115200 baud respectively. A better signal processing algorithm might help read real cassettes more reliably, especially at 1500bps. Some features of the floppy disk controller are not currently emulated: Force Interrupt with condition bits 0x01, 0x02, or 0x04 is not imple- mented. Read Track is implemented only for DMK emulated floppies. The multiple-sector flags in Read and Write are not implemented. The tim- ing of returned sectors is emulated only for the Read Address command, and not very accurately for JV1 or JV3. If a disk has more than one sector with the same number on a track, xtrs will always see the first (counting from the index hole) when reading or writing; a real machine would see the next one to come under the head depending on the current rotational position of the disk. Partially reformatting a track (which TRS-80 programs like HyperZap and Model I Super Utility do to achieve mixed density) is supported for DMK but not JV3; however, switching densities while formatting (which Model III and 4 Super Utility do) works on both DMK and JV3. Real physical floppy disks are supported only under Linux, because Unix does not define a portable interface to the low-level floppy controller functionality that xtrs needs. There are some limitations even under Linux: Index holes are faked, not detected on the real disk, and the timing of returned sectors is not emulated at all. Due to the limita- tions of PC-style floppy disk controllers, when formatting a physical floppy under xtrs, you cannot mix sectors of different sizes on the same track, switch densities in the middle of a track, or reformat only part of a track. However, xtrs can read and write to physical floppies that have already been formatted in these ways (perhaps by a real TRS-80). The extended JV3 limit of 5802 sectors is somewhat arbitrary. It could be raised by generalizing the code to permit more than two blocks of 2901, but this does not seem too useful. 5802 sectors is already enough for a 3.5-inch HD (1.44MB) floppy, which the TRS-80 didn't sup- port anyway. If you need more space, use emulated hard drives instead of emulated floppies with huge numbers of tracks. XTRSHARD/DCT ignores the internal write-protected flag in hard drive images, but a hard drive image can still be effectively write protected by turning off its Unix write permission bits. The emulator uses a heuristic to decide what format a ROM file is in. If a raw binary ROM image starts with 0x01, 0x05, or 0x22, it can be misidentified as being in a different format. This is rather unlikely to occur, as ROMs typically begin with 0xF3, the DI instruction. The joystick emulation could be made to work with real joysticks using the X input extension, but this is not implemented yet. If you discover other bugs, write fixes for any of these, or make any other enhancements, please let us know so that we can incorporate the changes into future releases. Authors and acknowledgements xtrs 1.0 was written by David Gingold and Alec Wolman. The current version was revised and much extended by Timothy Mann (see http://tim- mann.org/). See README and README.tpm for additional notes from the authors. We also thank the following people for their help. The JV1 and JV3 floppy disk file formats were designed by Jeff Vavasour, originally for his MSDOS-based TRS-80 emulators. The DMK format was designed by David Keil for his MSDOS-based TRS-80 emulator. The hard disk file format was designed by Matthew Reed for his MSDOS-based TRS-80 emulators. Al Petrofsky and Todd P. Cromwell III supplied font data. Roland Gerlach contributed the CP/M import and export programs as well as several bug reports and fixes for the emulator itself. Ulrich Mueller added the -borderwidth option, improved the -scale option and the bitmap font scaling, ported the import, export, and settime utilities to Newdos/80, and contributed the HRG1B emulation. Branden Robinson supplied the first version of the cassette man page, fixed Makefile bugs, translated cassette to the Bourne shell, and implemented watchpoints in zbx. Mark McDougall provided documentation for the Micro Labs Grafyx Solution card. Jenz Guenther added the -title option and contributed code to emulate the GENIE (German Model I clone). Joe Peterson contributed code to emulate the TimeDate80 and the -emtsafe feature. Denis Leconte contributed part of the -scale implementation. $Id: xtrs.man,v 1.69 2009/06/15 23:44:43 mann Exp $ xtrs(1) xtrs-4.9d/xtrs8.dct000066400000000000000000000016161306603614600143270ustar00rootroot00000000000000`íS3c: þ@Âù`:%þIʆ`>Í2ça!{D"èa!GbÍgD:XGË_ÊÜaí[3cz³ÊØa!ðbÍgD!5cÍ@ÚäaÂäa:5cþ08äþ80àMd*I@ÍbÊ—a?d*I@ÍbÂÐa"Wd*I@"1c,—íR"I@ÍîaÉa>Í2ça!ŠB"èa!GbÍgD:XGË_ÊÜaí[3cz³ÊØa!ðbÍgD!5cÍ@ÚäaÂäa:5cþ08äþ80àMd*DÍbÊ—a:DþQ!…E(!ƒE"Wd*D"1c,—íR"DÍîaÉa!Gb> ï>aeïý~Ë_ÊÜaí[3cz³ÊØa!ðb> ï!5c> ïÚäaÂäa:5cþ08äþ80àMd>SïÊ—aDd>SïÂÔa"WdKI>RïÂÔa+V+^å!,T]—íBá0 s#ríS1c!E>dïÂàa"1c,—íR>dïÍîaí[1c!sd,í¸ë#ý*3cýuýtý6 :5cæO!7d ~ö@ýwý6ý6Lý6ý6'ý6 &!—É!cÝ!{bÝ!ÖbÝ!¬bÝ!ŽbÝ! c> ï!ÿÿÉ*1cý!tdsd—íRDMýnbýf|µÈ^#Vë ër+sý#ý#è#|µ =É~þÀÕå####F#þ 8¾ #ôþ 0áÑ—Éá##^#VëÑÎXTRS8 - Emulated 8" floppy driver for xtrs - 4/9/98 LS-DOS is curdled! High memory is not available! Must install via SYSTEM (DRIVE=,DRIVER=)! DRIVE= must be specified! Enter unit numbe7cr (4-7): Aborted! FDUBL must be loaded first! C7d$FDD$FD sdxtrs8ÍõýËn(IýËv 'ýpýqñÉJd`xtrs-4.9d/xtrs8.lst000066400000000000000000000501131306603614600143530ustar00rootroot00000000000000 1: ;*=*=* 2: ; xtrs8/dct 3: ; LDOS driver for xtrs emulation of 8" floppy 4: ; 5: ; Copyright (c) 1998, Timothy Mann 6: ; $Id: xtrs8.z80,v 1.2 2008/06/26 04:39:56 mann Exp $ 7: ; 8: ; This software may be copied, modified, and used for any 9: ; purpose without fee, provided that (1) the above copyright 10: ; notice is retained, and (2) modified versions are clearly 11: ; marked as having been modified, with the modifier's name and 12: ; the date included. 13: ;*=*=* 14: 15: 16: ; Number of floppy drives xtrs allows 17: 0008 ndrive equ 8 18: 19: ; ASCII chars 20: 000A LF equ 10 21: 000D CR equ 13 22: 0003 ETX equ 3 23: 24: ; Model 4 SVC numbers 25: 0064 @high equ 100 26: 000A @dsply equ 10 27: 0065 @flags equ 101 28: 000C @logot equ 12 29: 0052 @gtdcb equ 82 30: 0053 @gtmod equ 83 31: 0009 @keyin equ 9 32: 33: ; Model I/III hard addresses 34: 0125 m3flag$ equ 0125h ; 'I' in ROM on Model III 35: 447B @logot1 equ 447bh 36: 428A @logot3 equ 428ah 37: 4467 @dsply1 equ 4467h 38: 4467 @dsply3 equ 4467h 39: 4049 high$1 equ 4049h 40: 4411 high$3 equ 4411h 41: 4758 cflag$1 equ 4758h 42: 4758 cflag$3 equ 4758h 43: 0040 @keyin1 equ 0040h 44: 0040 @keyin3 equ 0040h 45: 441F osver$3 equ 441fh 46: 47: ; Very undocumented! ugh! 48: 4585 flop31 equ 4585h ;Model III LDOS 5.1.x floppy driver 49: 4583 flop33 equ 4583h ;Model III LDOS 5.3.x floppy driver 50: 51: ;*=*=* 52: ; Set origin to be safe on both LDOS 5 and 6 53: ;*=*=* 54: 6000 org 6000h 55: 56: ;*=*=* 57: ; Relocator for disk driver 58: ;*=*=* 59: 6000 ED533363 instal: ld (dct),de ;Save DCT address 60: 6004 3A0A00 ld a,(000ah) ;Determine TRS-80 model 61: 6007 FE40 cp 40h 62: 6009 C2F960 jp nz,lsdos6 ;Model 4 (or other LS-DOS, I hope) 63: 600C 3A2501 ld a,(m3flag$) 64: 600F FE49 cp 'I' 65: 6011 CA8660 jp z,model3 ;Go if Model III 66: ;*=*=* 67: ; LDOS 5 Model I - See LS-DOS 6 version for comments 68: ;*=*=* 69: 6014 3ECD ld a,0cdh ;Insert Model I @LOGOT 70: 6016 32E761 ld (logot),a 71: 6019 217B44 ld hl,@logot1 72: 601C 22E861 ld (logot+1),hl 73: 601F 214762 ld hl,hello_ 74: 6022 CD6744 call @dsply1 75: 6025 3A5847 ld a,(cflag$1) 76: 6028 CB5F bit 3,a ;System request? 77: 602A CADC61 jp z,viaset 78: 602D ED5B3363 ld de,(dct) 79: 6031 7A ld a,d ;DRIVE= must be specified 80: 6032 B3 or e 81: 6033 CAD861 jp z,needdr 82: 6036 21F062 asku1: ld hl,unit_ ;Ask which unit number 83: 6039 CD6744 call @dsply1 84: 603C 213563 ld hl,unit 85: 603F 010001 ld bc,100h 86: 6042 CD4000 call @keyin1 87: 6045 DAE461 jp c,hitbrk 88: 6048 C2E461 jp nz,hitbrk 89: 604B 3A3563 ld a,(unit) 90: 604E FE30 cp '0' 91: 6050 38E4 jr c,asku1 92: 6052 FE38 cp '0'+ndrive 93: 6054 30E0 jr nc,asku1 94: 6056 114D64 ld de,modnam ;Module already loaded? 95: 6059 2A4940 ld hl,(high$1) 96: 605C CD1562 call xgtmod 97: 605F CA9761 jp z,setdct 98: 6062 113F64 ld de,fd1 ;Find fdubl driver 99: 6065 2A4940 ld hl,(high$1) 100: 6068 CD1562 call xgtmod 101: 606B C2D061 jp nz,needfd ;go if missing 102: 606E 225764 ld (flop),hl 103: 6071 2A4940 ld hl,(high$1) 104: 6074 223163 ld (newend),hl 105: 6077 112C00 ld de,length 106: 607A 97 sub a 107: 607B ED52 sbc hl,de 108: 607D 224940 ld (high$1),hl 109: 6080 CDEE61 call relo 110: 6083 C38961 jp move 111: ;*=*=* 112: ; LDOS 5 Model III 113: ;*=*=* 114: 6086 model3: 115: 6086 3ECD ld a,0cdh ;Insert Model III @LOGOT 116: 6088 32E761 ld (logot),a 117: 608B 218A42 ld hl,@logot3 118: 608E 22E861 ld (logot+1),hl 119: 6091 214762 ld hl,hello_ 120: 6094 CD6744 call @dsply3 121: 6097 3A5847 ld a,(cflag$3) 122: 609A CB5F bit 3,a ;System request? 123: 609C CADC61 jp z,viaset 124: 609F ED5B3363 ld de,(dct) 125: 60A3 7A ld a,d ;DRIVE= must be specified 126: 60A4 B3 or e 127: 60A5 CAD861 jp z,needdr 128: 60A8 21F062 asku3: ld hl,unit_ ;Ask which unit number 129: 60AB CD6744 call @dsply3 130: 60AE 213563 ld hl,unit 131: 60B1 010001 ld bc,100h 132: 60B4 CD4000 call @keyin3 133: 60B7 DAE461 jp c,hitbrk 134: 60BA C2E461 jp nz,hitbrk 135: 60BD 3A3563 ld a,(unit) 136: 60C0 FE30 cp '0' 137: 60C2 38E4 jr c,asku3 138: 60C4 FE38 cp '0'+ndrive 139: 60C6 30E0 jr nc,asku3 140: 60C8 114D64 ld de,modnam ;Module already loaded? 141: 60CB 2A1144 ld hl,(high$3) 142: 60CE CD1562 call xgtmod 143: 60D1 CA9761 jp z,setdct 144: ; 145: ; Doesn't work on Model III: 146: ; ld de,fd3 ;Find floppy driver 147: ; ld hl,(high$3) 148: ; call xgtmod 149: ; jp nz,needfd ;go if missing 150: ; 151: ; Cheat instead: 152: 60D4 3A1F44 ld a,(osver$3) 153: 60D7 FE51 cp 51h 154: 60D9 218545 ld hl,flop31 155: 60DC 2803 jr z,gotit 156: 60DE 218345 ld hl,flop33 157: 60E1 gotit: 158: ; 159: 60E1 225764 ld (flop),hl 160: 60E4 2A1144 ld hl,(high$3) 161: 60E7 223163 ld (newend),hl 162: 60EA 112C00 ld de,length 163: 60ED 97 sub a 164: 60EE ED52 sbc hl,de 165: 60F0 221144 ld (high$3),hl 166: 60F3 CDEE61 call relo 167: 60F6 C38961 jp move 168: 169: ;*=*=* 170: ; LS-DOS 6 171: ;*=*=* 172: 60F9 214762 lsdos6: ld hl,hello_ 173: 60FC 3E0A ld a,@dsply ;Display hello 174: 60FE EF rst 40 175: ;*=*=* 176: ; Check if entry from SYSTEM command. 177: ;*=*=* 178: 60FF 3E65 ld a,@flags ;Get flags pointer into IY 179: 6101 EF rst 40 180: 6102 FD7E02 ld a,(iy+'C'-'A') ;Get CFLAG$ 181: 6105 CB5F bit 3,a ;System request? 182: 6107 CADC61 jp z,viaset 183: 610A ED5B3363 ld de,(dct) 184: 610E 7A ld a,d ;DRIVE= must be specified 185: 610F B3 or e 186: 6110 CAD861 jp z,needdr 187: ;*=*=* 188: ; Ask which unit number 189: ;*=*=* 190: 6113 21F062 asku4: ld hl,unit_ ;Ask which unit number 191: 6116 3E0A ld a,@dsply 192: 6118 EF rst 40 193: 6119 213563 ld hl,unit 194: 611C 010001 ld bc,100h 195: 611F 3E09 ld a,@keyin 196: 6121 EF rst 40 197: 6122 DAE461 jp c,hitbrk 198: 6125 C2E461 jp nz,hitbrk 199: 6128 3A3563 ld a,(unit) 200: 612B FE30 cp '0' 201: 612D 38E4 jr c,asku4 202: 612F FE38 cp '0'+ndrive 203: 6131 30E0 jr nc,asku4 204: ;*=*=* 205: ; Check if driver already loaded 206: ;*=*=* 207: 6133 114D64 ld de,modnam 208: 6136 3E53 ld a,@gtmod 209: 6138 EF rst 40 210: 6139 CA9761 jp z,setdct ;Already loaded, skip loading 211: ;*=*=* 212: ; Find system floppy driver 213: ;*=*=* 214: 613C 114464 ld de,fd4 215: 613F 3E53 ld a,@gtmod 216: 6141 EF rst 40 217: 6142 C2D461 jp nz,curdl ;Fatal error if not found 218: 6145 225764 ld (flop),hl 219: ;*=*=* 220: ; Obtain low memory driver pointer. Bizarre API here! 221: ;*=*=* 222: 6148 1E4B ld e,'K' ;Locate pointer to *KI DCB 223: 614A 1649 ld d,'I' ; via @GTDCB SVC 224: 614C 3E52 ld a,@gtdcb 225: 614E EF rst 40 226: 614F C2D461 jp nz,curdl ;No error unless KI clobbered! 227: 6152 2B dec hl ;Decrement to driver pointer 228: 6153 56 ld d,(hl) ;P/u hi-order of pointer, 229: 6154 2B dec hl ; decrement to and p/u 230: 6155 5E ld e,(hl) ; lo-order of pointer 231: ;*=*=* 232: ; Check if driver will fit into [(LCPTR), X'12FF'] 233: ;*=*=* 234: 6156 E5 push hl ;Save address of pointer 235: 6157 212C00 ld hl,length ;New pointer will be 236: 615A 19 add hl,de ; pointer + LENGTH 237: 615B 54 ld d,h ;Save a copy in DE 238: 615C 5D ld e,l 239: 615D 010113 ld bc,1301h ;If > 1300H, driver won't fit 240: 6160 97 sub a ;Reset carry flag 241: 6161 ED42 sbc hl,bc 242: 6163 E1 pop hl ;Get back address of pointer 243: 6164 300A jr nc,usehi ;Go if driver won't fit 244: 6166 73 ld (hl),e ;Store new value of pointer 245: 6167 23 inc hl 246: 6168 72 ld (hl),d 247: 6169 1B dec de ;Last byte of driver goes here 248: 616A ED533163 ld (newend),de 249: 616E 1816 jr dorelo 250: ;*=*=* 251: ; Put in high memory instead. 252: ;*=*=* 253: 6170 210000 usehi: ld hl,0 ;Get current HIGH$ 254: 6173 45 ld b,l 255: 6174 3E64 ld a,@high 256: 6176 EF rst 40 257: 6177 C2E061 jp nz,nomem 258: 617A 223163 ld (newend),hl ;Last byte of driver goes here 259: 617D 112C00 ld de,length 260: 6180 97 sub a ;Reset carry flag 261: 6181 ED52 sbc hl,de ;Compute new HIGH$ 262: 6183 3E64 ld a,@high ;Set new HIGH$ into the system 263: 6185 EF rst 40 264: ;*=*=* 265: ; Relocate internal references in driver. 266: ; HL = address for last byte of driver. 267: ;*=*=* 268: 6186 CDEE61 dorelo: call relo 269: ;*=*=* 270: ; Move driver into low or high memory. 271: ;*=*=* 272: 6189 move: 273: 6189 ED5B3163 ld de,(newend) ;Destination address 274: 618D 217364 ld hl,dvrend ;Last byte of module 275: 6190 012C00 ld bc,length ;Length of filter 276: 6193 EDB8 lddr 277: 6195 EB ex de,hl 278: 6196 23 inc hl ;Bump to driver entry 279: ;*=*=* 280: ; Setup DCT 281: ;*=*=* 282: 6197 setdct: 283: 6197 FD2A3363 ld iy,(dct) 284: 619B FD7501 ld (iy+1),l ;Driver address 285: 619E FD7402 ld (iy+2),h 286: 61A1 FD360320 ld (iy+3),00100000b ;Flags: 8" floppy 287: 61A5 3A3563 ld a,(unit) ;Xlate unit number to select code 288: 61A8 E607 and 07h 289: 61AA 4F ld c,a 290: 61AB 0600 ld b,0 291: 61AD 213764 ld hl,utab 292: 61B0 09 add hl,bc 293: 61B1 7E ld a,(hl) 294: 61B2 F640 or 01000000b ;Flags: dden capable, select code 295: 61B4 FD7704 ld (iy+4),a 296: 61B7 FD360500 ld (iy+5),0 ;current cylinder number 297: 61BB FD36064C ld (iy+6),76 ;high cylinder number 298: 61BF FD36070F ld (iy+7),0fh ;init to sden head/sec/gran config 299: 61C3 FD360827 ld (iy+8),27h 300: 61C7 FD360926 ld (iy+9),38 ;Directory cylinder (guess) 301: 302: 61CB 210000 ld hl,0 ;Successful completion 303: 61CE 97 sub a 304: 61CF C9 ret 305: ;*=*=* 306: 61D0 211363 needfd: ld hl,needfd_ 307: 61D3 DD defb 0ddh 308: 61D4 217B62 curdl: ld hl,curdl_ ;Other error 309: 61D7 DD defb 0ddh 310: 61D8 21D662 needdr: ld hl,needdr_ 311: 61DB DD defb 0ddh 312: 61DC 21AC62 viaset: ld hl,viaset_ 313: 61DF DD defb 0ddh 314: 61E0 218E62 nomem: ld hl,nomem_ 315: 61E3 DD defb 0ddh 316: 61E4 210A63 hitbrk: ld hl,hitbrk_ 317: 61E7 3E0C logot: ld a,@logot 318: 61E9 EF rst 40 319: 61EA 21FFFF ld hl,-1 ;Unuccessful completion 320: 61ED C9 ret 321: 322: ;*=*=* 323: ; Relocate internal references in driver. 324: ; HL = address for last byte of driver. 325: ;*=*=* 326: 61EE 2A3163 relo: ld hl,(newend) 327: 61F1 FD217464 ld iy,reltab ;Point to relocation tbl 328: 61F5 117364 ld de,dvrend 329: 61F8 97 sub a ;Clear carry flag 330: 61F9 ED52 sbc hl,de 331: 61FB 44 ld b,h ;Move to BC 332: 61FC 4D ld c,l 333: 61FD FD6E00 rloop: ld l,(iy) ;Get address to change 334: 6200 FD6601 ld h,(iy+1) 335: 6203 7C ld a,h 336: 6204 B5 or l 337: 6205 C8 ret z 338: 6206 5E ld e,(hl) ;P/U address 339: 6207 23 inc hl 340: 6208 56 ld d,(hl) 341: 6209 EB ex de,hl ;Offset it 342: 620A 09 add hl,bc 343: 620B EB ex de,hl 344: 620C 72 ld (hl),d ;And put back 345: 620D 2B dec hl 346: 620E 73 ld (hl),e 347: 620F FD23 inc iy 348: 6211 FD23 inc iy 349: 6213 18E8 jr rloop ;Loop till done 350: 351: ;*=*=* 352: ; Search for existing copy of driver. 353: ; Rough Model I/III emulation of Model 4 @GTMOD, 354: ; hardcoded with driver address. 355: ; Entry: HL = (HIGH$) 356: ; DE => module name, terminated with a character <= 0x1f 357: ; Exit Z: HL = driver address 358: ; NZ: driver not found 359: ;*=*=* 360: 6215 23 xgtmod: inc hl 361: 6216 7C ld a,h 362: 6217 B5 or l 363: 6218 2002 jr nz,xgtm1 364: 621A 3D dec a ;not found 365: 621B C9 ret 366: 621C 7E xgtm1: ld a,(hl) 367: 621D FE18 cp 18h ;unconditional jr? 368: 621F C0 ret nz ;not a module header 369: 6220 D5 push de ;save desired name ptr 370: 6221 E5 push hl ;save start address 371: 6222 23 inc hl ;skip jr 372: 6223 23 inc hl ;skip offset 373: 6224 23 inc hl ;skip start address 374: 6225 23 inc hl 375: 6226 46 ld b,(hl) ;get name length 376: 6227 23 inc hl 377: 6228 1A xgtm2: ld a,(de) 378: 6229 FE20 cp 20h 379: 622B 3810 jr c,nextmd ;desired name shorter - skip 380: 622D BE cp (hl) 381: 622E 200D jr nz,nextmd ;character different - skip 382: 6230 13 inc de 383: 6231 23 inc hl 384: 6232 10F4 djnz xgtm2 385: 6234 1A ld a,(de) 386: 6235 FE20 cp 20h 387: 6237 3004 jr nc,nextmd ;desired name longer - skip 388: 6239 E1 pop hl ;same - found 389: 623A D1 pop de 390: 623B 97 sub a 391: 623C C9 ret 392: 623D E1 nextmd: pop hl ;get back start of module 393: 623E 23 inc hl 394: 623F 23 inc hl 395: 6240 5E ld e,(hl) ;pointer to last byte 396: 6241 23 inc hl 397: 6242 56 ld d,(hl) 398: 6243 EB ex de,hl 399: 6244 D1 pop de 400: 6245 18CE jr xgtmod 401: 402: ;*=*=* 403: ; Messages and globals 404: ;*=*=* 405: 6247 58545253 hello_: defb 'XTRS8 - Emulated 8" floppy driver for xtrs - 4/9/98',CR 38202D20 456D756C 61746564 20382220 666C6F70 70792064 72697665 7220666F 72207874 7273202D 20342F39 2F39380D 406: 627B 4C532D44 curdl_: defb 'LS-DOS is curdled!',CR 4F532069 73206375 72646C65 64210D 407: 628E 48696768 nomem_: defb 'High memory is not available!',CR 206D656D 6F727920 6973206E 6F742061 7661696C 61626C65 210D 408: 62AC 4D757374 viaset_:defb 'Must install via SYSTEM (DRIVE=,DRIVER=)!',CR 20696E73 74616C6C 20766961 20535953 54454D20 28445249 56453D2C 44524956 45523D29 210D 409: 62D6 44524956 needdr_:defb 'DRIVE= must be specified!',CR 453D206D 75737420 62652073 70656369 66696564 210D 410: 62F0 456E7465 unit_: defb 'Enter unit number (4-7): ',ETX 7220756E 6974206E 756D6265 72202834 2D37293A 2003 411: 630A 41626F72 hitbrk_:defb 'Aborted!',CR 74656421 0D 412: 6313 46445542 needfd_:defb 'FDUBL must be loaded first!',CR 4C206D75 73742062 65206C6F 61646564 20666972 7374210D 413: 632F 0000 lcptr: defw 0 414: 6331 0000 newend: defw 0 415: 6333 0000 dct: defw 0 416: 6335 unit: defs 2 417: 6337 errbuf: defs 256 418: 6437 01020408 utab: defb 1,2,4,8,3,5,6,7 03050607 419: 643F 24464444 fd1: defb '$FDD',ETX 03 420: 6444 24464403 fd4: defb '$FD',ETX 421: 422: ; 423: ; Driver - just a tiny wrapper around LDOS dden floppy driver 424: ; 425: 426: 6448 180C entry: jr begin ;The driver starts with the 427: 644A 7364 defw dvrend ; DOS standard header 428: 644A rx00 equ $-2 429: 644C 05 defb modptr-modnam ;Length of name 430: 644D 78747273 modnam: defb 'xtrs8' ;Name for @GTMOD requests 38 431: 6452 0000 modptr: defw 0 ;These pointers are unused, but 1st byte MBZ 432: 6454 0000 defw 0 433: 434: 6456 CD0000 begin: call $-$ ;call the real driver 435: 6457 flop equ $-2 436: 6459 F5 push af 437: 645A FDCB036E bit 5,(iy+3) ;8" drive? 438: 645E 2812 jr z,done ;go if not 439: 6460 01491D ld bc,1d49h ;init for dden 440: 6463 FDCB0376 bit 6,(iy+3) ;dden? 441: 6467 2003 jr nz,ldden ;go if so 442: 6469 01270F ld bc,0f27h 443: 646C FD7007 ldden: ld (iy+7), b 444: 646F FD7108 ld (iy+8), c 445: 6472 F1 done: pop af 446: 6473 C9 ret 447: 448: 6473 dvrend equ $-1 449: 002C length equ $-entry 450: 6474 4A640000 reltab: defw rx00,0 451: 6000 end instal Statistics: 76 symbols 886 bytes Symbol Table: @dsply = a entry 6448 ndrive = 8 @dsply1 =4467 errbuf 6337+ needdr 61d8 @dsply3 =4467 etx = 3 needdr_ 62d6 @flags = 65 fd1 643f needfd 61d0 @gtdcb = 52 fd4 6444 needfd_ 6313 @gtmod = 53 flop =6457 newend 6331 @high = 64 flop31 =4585 nextmd 623d @keyin = 9 flop33 =4583 nomem 61e0 @keyin1 = 40 gotit 60e1 nomem_ 628e @keyin3 = 40 hello_ 6247 osver3 =441f @logot = c high1 =4049 relo 61ee @logot1 =447b high3 =4411 reltab 6474 @logot3 =428a hitbrk 61e4 rloop 61fd asku1 6036 hitbrk_ 630a rx00 =644a asku3 60a8 instal 6000 setdct 6197 asku4 6113 lcptr 632f+ unit 6335 begin 6456 ldden 646c unit_ 62f0 cflag1 =4758 length = 2c usehi 6170 cflag3 =4758 lf = a+ utab 6437 cr = d logot 61e7 viaset 61dc curdl 61d4 lsdos6 60f9 viaset_ 62ac curdl_ 627b m3flag = 125 xgtm1 621c dct 6333 model3 6086 xgtm2 6228 done 6472 modnam 644d xgtmod 6215 dorelo 6186 modptr 6452 dvrend =6473 move 6189 xtrs-4.9d/xtrs8.z80000066400000000000000000000227021306603614600141750ustar00rootroot00000000000000;*=*=* ; xtrs8/dct ; LDOS driver for xtrs emulation of 8" floppy ; ; Copyright (c) 1998, Timothy Mann ; $Id: xtrs8.z80,v 1.2 2008/06/26 04:39:56 mann Exp $ ; ; This software may be copied, modified, and used for any ; purpose without fee, provided that (1) the above copyright ; notice is retained, and (2) modified versions are clearly ; marked as having been modified, with the modifier's name and ; the date included. ;*=*=* ; Number of floppy drives xtrs allows ndrive equ 8 ; ASCII chars LF equ 10 CR equ 13 ETX equ 3 ; Model 4 SVC numbers @high equ 100 @dsply equ 10 @flags equ 101 @logot equ 12 @gtdcb equ 82 @gtmod equ 83 @keyin equ 9 ; Model I/III hard addresses m3flag$ equ 0125h ; 'I' in ROM on Model III @logot1 equ 447bh @logot3 equ 428ah @dsply1 equ 4467h @dsply3 equ 4467h high$1 equ 4049h high$3 equ 4411h cflag$1 equ 4758h cflag$3 equ 4758h @keyin1 equ 0040h @keyin3 equ 0040h osver$3 equ 441fh ; Very undocumented! ugh! flop31 equ 4585h ;Model III LDOS 5.1.x floppy driver flop33 equ 4583h ;Model III LDOS 5.3.x floppy driver ;*=*=* ; Set origin to be safe on both LDOS 5 and 6 ;*=*=* org 6000h ;*=*=* ; Relocator for disk driver ;*=*=* instal: ld (dct),de ;Save DCT address ld a,(000ah) ;Determine TRS-80 model cp 40h jp nz,lsdos6 ;Model 4 (or other LS-DOS, I hope) ld a,(m3flag$) cp 'I' jp z,model3 ;Go if Model III ;*=*=* ; LDOS 5 Model I - See LS-DOS 6 version for comments ;*=*=* ld a,0cdh ;Insert Model I @LOGOT ld (logot),a ld hl,@logot1 ld (logot+1),hl ld hl,hello_ call @dsply1 ld a,(cflag$1) bit 3,a ;System request? jp z,viaset ld de,(dct) ld a,d ;DRIVE= must be specified or e jp z,needdr asku1: ld hl,unit_ ;Ask which unit number call @dsply1 ld hl,unit ld bc,100h call @keyin1 jp c,hitbrk jp nz,hitbrk ld a,(unit) cp '0' jr c,asku1 cp '0'+ndrive jr nc,asku1 ld de,modnam ;Module already loaded? ld hl,(high$1) call xgtmod jp z,setdct ld de,fd1 ;Find fdubl driver ld hl,(high$1) call xgtmod jp nz,needfd ;go if missing ld (flop),hl ld hl,(high$1) ld (newend),hl ld de,length sub a sbc hl,de ld (high$1),hl call relo jp move ;*=*=* ; LDOS 5 Model III ;*=*=* model3: ld a,0cdh ;Insert Model III @LOGOT ld (logot),a ld hl,@logot3 ld (logot+1),hl ld hl,hello_ call @dsply3 ld a,(cflag$3) bit 3,a ;System request? jp z,viaset ld de,(dct) ld a,d ;DRIVE= must be specified or e jp z,needdr asku3: ld hl,unit_ ;Ask which unit number call @dsply3 ld hl,unit ld bc,100h call @keyin3 jp c,hitbrk jp nz,hitbrk ld a,(unit) cp '0' jr c,asku3 cp '0'+ndrive jr nc,asku3 ld de,modnam ;Module already loaded? ld hl,(high$3) call xgtmod jp z,setdct ; ; Doesn't work on Model III: ; ld de,fd3 ;Find floppy driver ; ld hl,(high$3) ; call xgtmod ; jp nz,needfd ;go if missing ; ; Cheat instead: ld a,(osver$3) cp 51h ld hl,flop31 jr z,gotit ld hl,flop33 gotit: ; ld (flop),hl ld hl,(high$3) ld (newend),hl ld de,length sub a sbc hl,de ld (high$3),hl call relo jp move ;*=*=* ; LS-DOS 6 ;*=*=* lsdos6: ld hl,hello_ ld a,@dsply ;Display hello rst 40 ;*=*=* ; Check if entry from SYSTEM command. ;*=*=* ld a,@flags ;Get flags pointer into IY rst 40 ld a,(iy+'C'-'A') ;Get CFLAG$ bit 3,a ;System request? jp z,viaset ld de,(dct) ld a,d ;DRIVE= must be specified or e jp z,needdr ;*=*=* ; Ask which unit number ;*=*=* asku4: ld hl,unit_ ;Ask which unit number ld a,@dsply rst 40 ld hl,unit ld bc,100h ld a,@keyin rst 40 jp c,hitbrk jp nz,hitbrk ld a,(unit) cp '0' jr c,asku4 cp '0'+ndrive jr nc,asku4 ;*=*=* ; Check if driver already loaded ;*=*=* ld de,modnam ld a,@gtmod rst 40 jp z,setdct ;Already loaded, skip loading ;*=*=* ; Find system floppy driver ;*=*=* ld de,fd4 ld a,@gtmod rst 40 jp nz,curdl ;Fatal error if not found ld (flop),hl ;*=*=* ; Obtain low memory driver pointer. Bizarre API here! ;*=*=* ld e,'K' ;Locate pointer to *KI DCB ld d,'I' ; via @GTDCB SVC ld a,@gtdcb rst 40 jp nz,curdl ;No error unless KI clobbered! dec hl ;Decrement to driver pointer ld d,(hl) ;P/u hi-order of pointer, dec hl ; decrement to and p/u ld e,(hl) ; lo-order of pointer ;*=*=* ; Check if driver will fit into [(LCPTR), X'12FF'] ;*=*=* push hl ;Save address of pointer ld hl,length ;New pointer will be add hl,de ; pointer + LENGTH ld d,h ;Save a copy in DE ld e,l ld bc,1301h ;If > 1300H, driver won't fit sub a ;Reset carry flag sbc hl,bc pop hl ;Get back address of pointer jr nc,usehi ;Go if driver won't fit ld (hl),e ;Store new value of pointer inc hl ld (hl),d dec de ;Last byte of driver goes here ld (newend),de jr dorelo ;*=*=* ; Put in high memory instead. ;*=*=* usehi: ld hl,0 ;Get current HIGH$ ld b,l ld a,@high rst 40 jp nz,nomem ld (newend),hl ;Last byte of driver goes here ld de,length sub a ;Reset carry flag sbc hl,de ;Compute new HIGH$ ld a,@high ;Set new HIGH$ into the system rst 40 ;*=*=* ; Relocate internal references in driver. ; HL = address for last byte of driver. ;*=*=* dorelo: call relo ;*=*=* ; Move driver into low or high memory. ;*=*=* move: ld de,(newend) ;Destination address ld hl,dvrend ;Last byte of module ld bc,length ;Length of filter lddr ex de,hl inc hl ;Bump to driver entry ;*=*=* ; Setup DCT ;*=*=* setdct: ld iy,(dct) ld (iy+1),l ;Driver address ld (iy+2),h ld (iy+3),00100000b ;Flags: 8" floppy ld a,(unit) ;Xlate unit number to select code and 07h ld c,a ld b,0 ld hl,utab add hl,bc ld a,(hl) or 01000000b ;Flags: dden capable, select code ld (iy+4),a ld (iy+5),0 ;current cylinder number ld (iy+6),76 ;high cylinder number ld (iy+7),0fh ;init to sden head/sec/gran config ld (iy+8),27h ld (iy+9),38 ;Directory cylinder (guess) ld hl,0 ;Successful completion sub a ret ;*=*=* needfd: ld hl,needfd_ defb 0ddh curdl: ld hl,curdl_ ;Other error defb 0ddh needdr: ld hl,needdr_ defb 0ddh viaset: ld hl,viaset_ defb 0ddh nomem: ld hl,nomem_ defb 0ddh hitbrk: ld hl,hitbrk_ logot: ld a,@logot rst 40 ld hl,-1 ;Unuccessful completion ret ;*=*=* ; Relocate internal references in driver. ; HL = address for last byte of driver. ;*=*=* relo: ld hl,(newend) ld iy,reltab ;Point to relocation tbl ld de,dvrend sub a ;Clear carry flag sbc hl,de ld b,h ;Move to BC ld c,l rloop: ld l,(iy) ;Get address to change ld h,(iy+1) ld a,h or l ret z ld e,(hl) ;P/U address inc hl ld d,(hl) ex de,hl ;Offset it add hl,bc ex de,hl ld (hl),d ;And put back dec hl ld (hl),e inc iy inc iy jr rloop ;Loop till done ;*=*=* ; Search for existing copy of driver. ; Rough Model I/III emulation of Model 4 @GTMOD, ; hardcoded with driver address. ; Entry: HL = (HIGH$) ; DE => module name, terminated with a character <= 0x1f ; Exit Z: HL = driver address ; NZ: driver not found ;*=*=* xgtmod: inc hl ld a,h or l jr nz,xgtm1 dec a ;not found ret xgtm1: ld a,(hl) cp 18h ;unconditional jr? ret nz ;not a module header push de ;save desired name ptr push hl ;save start address inc hl ;skip jr inc hl ;skip offset inc hl ;skip start address inc hl ld b,(hl) ;get name length inc hl xgtm2: ld a,(de) cp 20h jr c,nextmd ;desired name shorter - skip cp (hl) jr nz,nextmd ;character different - skip inc de inc hl djnz xgtm2 ld a,(de) cp 20h jr nc,nextmd ;desired name longer - skip pop hl ;same - found pop de sub a ret nextmd: pop hl ;get back start of module inc hl inc hl ld e,(hl) ;pointer to last byte inc hl ld d,(hl) ex de,hl pop de jr xgtmod ;*=*=* ; Messages and globals ;*=*=* hello_: defb 'XTRS8 - Emulated 8" floppy driver for xtrs - 4/9/98',CR curdl_: defb 'LS-DOS is curdled!',CR nomem_: defb 'High memory is not available!',CR viaset_:defb 'Must install via SYSTEM (DRIVE=,DRIVER=)!',CR needdr_:defb 'DRIVE= must be specified!',CR unit_: defb 'Enter unit number (4-7): ',ETX hitbrk_:defb 'Aborted!',CR needfd_:defb 'FDUBL must be loaded first!',CR lcptr: defw 0 newend: defw 0 dct: defw 0 unit: defs 2 errbuf: defs 256 utab: defb 1,2,4,8,3,5,6,7 fd1: defb '$FDD',ETX fd4: defb '$FD',ETX ; ; Driver - just a tiny wrapper around LDOS dden floppy driver ; entry: jr begin ;The driver starts with the defw dvrend ; DOS standard header rx00 equ $-2 defb modptr-modnam ;Length of name modnam: defb 'xtrs8' ;Name for @GTMOD requests modptr: defw 0 ;These pointers are unused, but 1st byte MBZ defw 0 begin: call $-$ ;call the real driver flop equ $-2 push af bit 5,(iy+3) ;8" drive? jr z,done ;go if not ld bc,1d49h ;init for dden bit 6,(iy+3) ;dden? jr nz,ldden ;go if so ld bc,0f27h ldden: ld (iy+7), b ld (iy+8), c done: pop af ret dvrend equ $-1 length equ $-entry reltab: defw rx00,0 end instal xtrs-4.9d/xtrsemt.ccc000066400000000000000000000211501306603614600147160ustar00rootroot00000000000000/* xtrsemt.ccc -- Misosys C interface to xtrs emulator traps */ /* Copyright (c) 1997, Timothy Mann */ /* $Id: xtrsemt.ccc,v 1.6 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ #include #ifndef _TIME_T #include #endif int emt_system(cmd) char *cmd; { #asm POP AF ;save return address POP HL ;cmd to HL PUSH HL ;restore stack PUSH AF DEFW 28EDH ;emt_system LD H,B ;return exit status from BC LD L,C RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC #endasm } char * emt_gtddir(buffer, bytes) char *buffer; int bytes; { #asm POP AF ;save return address POP HL ;buffer to HL POP BC ;bytes to BC PUSH BC PUSH HL PUSH AF DEFW 2AEDH ;emt_getddir RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC LD HL,0 #endasm } int emt_stddir(fname) char *fname; { #asm POP AF ;save return address POP HL ;fname to HL PUSH HL PUSH AF DEFW 2BEDH ;emt_setddir LD HL,0 ;return 0 if OK RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC LD HL,0FFFFH ;return -1 #endasm } int emt_open(fname, oflag, mode) char *fname; int oflag; int mode; { #asm POP AF ;save return address POP HL ;fname to HL POP BC ;oflag to BC POP DE ;mode to DE PUSH DE ;restore stack PUSH BC PUSH HL PUSH AF DEFW 30EDH ;emt_open LD H,D ;return fd from DE LD L,E RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC #endasm } int emt_close(fd) int fd; { #asm POP AF ;save return address POP DE ;fd to DE PUSH DE PUSH AF DEFW 31EDH ;emt_close LD HL,0 ;return 0 if no error RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC LD HL,0FFFFH ;return -1 #endasm } int emt_read(fd, buffer, bytes) int fd; char *buffer; int bytes; { #asm POP AF ;save return address POP DE ;fd to DE POP HL ;buffer to HL POP BC ;bytes to BC PUSH BC PUSH HL PUSH DE PUSH AF DEFW 32EDH ;emt_read LD H,B ;return count from BC LD L,C RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC #endasm } int emt_write(fd, buffer, bytes) int fd; char *buffer; int bytes; { #asm POP AF ;save return address POP DE ;fd to DE POP HL ;buffer to HL POP BC ;bytes to BC PUSH BC PUSH HL PUSH DE PUSH AF DEFW 33EDH ;emt_write LD H,B ;return count from BC LD L,C RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC #endasm } long emt_lseek(fd, offset, whence) int fd; long offset; /* 4 bytes */ int whence; { #asm PUSH IX LD IX,4 ;point IX to argument frame, skipping ADD IX,SP ; return address and old IX value LD E,(IX+0) ;fd to DE LD D,(IX+1) LD HL,0 ;extend offset to 8 bytes, push on stack PUSH HL PUSH HL LD L,(IX+4) ;high 2 bytes of 4-byte offset LD H,(IX+5) PUSH HL LD L,(IX+2) ;low 2 bytes LD H,(IX+3) PUSH HL LD HL,0 ;point HL to 8-byte offset ADD HL,SP LD C,(IX+6) ;whence to BC LD B,(IX+7) DEFW 34EDH ;emt_lseek POP DE ;return tell value in BCDE POP BC POP HL ;ignore high-order 4 bytes POP HL POP IX RET Z LD H,0 ;error code to errno LD L,A LD (ERRNO),HL #endasm } int emt_strerror(err, buffer, size) int err; char *buffer; int size; { #asm POP AF ;save return address POP DE ;err to DE temporarily POP HL ;buffer to HL POP BC ;size to BC PUSH BC PUSH HL PUSH DE PUSH AF LD A,E ;move err to A DEFW 35EDH ;emt_strerror LD H,B LD L,C RET Z LD B,0 ;new error code to errno LD C,A LD (ERRNO),BC #endasm } time_t emt_time(local) int local; { #asm POP AF ;save return address POP HL ;local flag to HL temporarily PUSH HL PUSH AF LD A,L ;local flag to A DEFW 36EDH ;emt_time ;return value is in BCDE (time_t == long) #endasm } int emt_dropen(fname) char *fname; { #asm POP AF ;save return address POP HL ;fname to HL PUSH HL PUSH AF DEFW 37EDH ;emt_opendir LD H,D ;return dirfd LD L,E RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC #endasm } int emt_drclose(dirfd) int dirfd; { #asm POP AF ;save return address POP DE ;dirfd to DE PUSH DE PUSH AF DEFW 38EDH ;emt_closedir LD HL,0 ;return 0 if no error RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC LD HL,0FFFFH ;return -1 #endasm } int emt_drread(dirfd, buffer, bytes) int dirfd; char *buffer; int bytes; { #asm POP AF ;save return address POP DE ;fd to DE POP HL ;buffer to HL POP BC ;bytes to BC PUSH BC PUSH HL PUSH DE PUSH AF DEFW 39EDH ;emt_readdir LD H,B LD L,C RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC #endasm } int emt_chdir(fname) char *fname; { #asm POP AF ;save return address POP HL ;fname to HL PUSH HL PUSH AF DEFW 3AEDH ;emt_chdir LD HL,0 ;return 0 if OK RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC LD HL,0FFFFH ;return -1 #endasm } char * emt_getcwd(buffer, bytes) char *buffer; int bytes; { #asm POP AF ;save return address POP HL ;buffer to HL POP BC ;bytes to BC PUSH BC PUSH HL PUSH AF DEFW 3BEDH ;emt_getcwd RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC LD HL,0 ;return NULL #endasm } int emt_misc(func) int func; { #asm POP AF ;save return address POP HL ;func to HL PUSH HL PUSH AF LD A,L ;func to A DEFW 3CEDH ;emt_misc, return HL #endasm } void emt_4misc(func, hl, bc, de) int func; int *hl; int *bc; int *de; { #asm PUSH IX LD IX,4 ;point IX to argument frame, skipping ADD IX,SP ; return address and old IX value LD L,(IX+4) ;bc arg to HL LD H,(IX+5) LD C,(HL) ;*bc to BC INC HL LD B,(HL) LD L,(IX+6) ;de arg to HL LD H,(IX+7) LD E,(HL) ;*de to DE INC HL LD D,(HL) LD L,(IX+2) ;hl arg to HL LD H,(IX+3) LD A,(HL) ;*hl to HL INC HL LD H,(HL) LD L,A LD A,(IX+0) ;func to A DEFW 3CEDH ;emt_misc PUSH HL ;save HL return LD L,(IX+4) ;bc arg to HL LD H,(IX+5) LD (HL),C ;BC return to *bc INC HL LD (HL),B LD L,(IX+6) ;de arg to HL LD H,(IX+7) LD (HL),E ;DE return to *de INC HL LD (HL),D POP DE ;HL return to DE LD L,(IX+2) ;hl arg to HL LD H,(IX+3) LD (HL),E ;DE (HL return) to *hl INC HL LD (HL),D EX DE,HL ;HL return back to HL (not needed) POP IX #endasm } int emt_ftruncate(fd, length) int fd; long length; /* 4 bytes */ { #asm PUSH IX LD IX,4 ;point IX to argument frame, skipping ADD IX,SP ; return address and old IX value LD E,(IX+0) ;fd to DE LD D,(IX+1) LD HL,0 ;extend length to 8 bytes, push on stack PUSH HL PUSH HL LD L,(IX+4) ;high 2 bytes of 4-byte offset LD H,(IX+5) PUSH HL LD L,(IX+2) ;low 2 bytes LD H,(IX+3) PUSH HL LD HL,0 ;point HL to 8-byte offset ADD HL,SP DEFW 3DEDH ;emt_ftruncate POP DE ;pop length from stack POP BC POP HL POP HL POP IX ;restore RET Z LD H,0 ;error code to errno LD L,A LD (ERRNO),HL #endasm } int emt_dkopen(fname, oflag, mode) char *fname; int oflag; int mode; { #asm POP AF ;save return address POP HL ;fname to HL POP BC ;oflag to BC POP DE ;mode to DE PUSH DE ;restore stack PUSH BC PUSH HL PUSH AF DEFW 3EEDH ;emt_opendisk LD H,D ;return fd from DE LD L,E RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC #endasm } int emt_dkclose(fd) int fd; { #asm POP AF ;save return address POP DE ;fd to DE PUSH DE PUSH AF DEFW 3FEDH ;emt_closedisk LD HL,0 ;return 0 if no error RET Z LD B,0 ;error code to errno LD C,A LD (ERRNO),BC LD HL,0FFFFH ;return -1 #endasm } xtrs-4.9d/xtrsemt.h000066400000000000000000000054531306603614600144250ustar00rootroot00000000000000/* xtrsemt.h -- Misosys C interface to xtrs emulator traps */ /* Copyright (c) 1997, Timothy Mann */ /* $Id: xtrsemt.h,v 1.7 2008/06/26 04:39:56 mann Exp $ */ /* This software may be copied, modified, and used for any purpose * without fee, provided that (1) the above copyright notice is * retained, and (2) modified versions are clearly marked as having * been modified, with the modifier's name and the date included. */ #ifndef _TIME_T #include #endif /* Some names are changed to keep them unique in the first seven characters */ extern int emt_system(/* char *cmd */); extern char* /*emt_getddir*/ emt_gtddir(/* char *buffer, int bytes */); extern int /*emt_setddir*/ emt_stddir(/* char *fname */); extern int emt_open(/* char *fname, int oflag, int mode */); extern int emt_close(/* int fd */); extern int emt_read(/* int fd, char *buffer, int bytes */); extern int emt_write(/* int fd, char *buffer, int bytes */); extern long emt_lseek(/* int fd, long offset, int whence */); extern int emt_strerror(/* int err, char *buffer, int size */); extern time_t emt_time(/* int local */); extern int /*emt_opendir*/ emt_dropen(/* char *fname */); extern int /*emt_closedir*/ emt_drclose(/* int dirfd */); extern int /*emt_readdir*/ emt_drread(/*int dirfd, char *buffer, int bytes*/); extern int emt_chdir(/* char *fname */); extern char* emt_getcwd(/* char *buffer, int bytes */); extern int emt_misc(/* int func */); extern void emt_4misc(/* int func, int *hl, int *bc, int *de */); extern int emt_ftruncate(/* int fd, long length */); extern int /*emt_opendisk*/ emt_dkopen(/* char *fname, int oflag, int mode */); extern int /*emt_closedisk*/ emt_dkclose(/* int fd */); /* oflag values for emt_open and emt_opendisk */ #define EO_ACCMODE 03 #define EO_RDONLY 00 #define EO_WRONLY 01 #define EO_RDWR 02 #define EO_CREAT 0100 #define EO_EXCL 0200 #define EO_TRUNC 01000 #define EO_APPEND 02000 /* local values for emt_time */ #define EMT_TIME_GMT 0 #define EMT_TIME_LOCAL 1 /* func values for emt_misc */ #define EMT_MISC_DISK_CHANGE 0 #define EMT_MISC_EXIT 1 #define EMT_MISC_DEBUG 2 #define EMT_MISC_RESET_BUTTON 3 #define EMT_MISC_QUERY_DISK_CHANGE 4 #define EMT_MISC_QUERY_MODEL 5 #define EMT_MISC_QUERY_DISK_SIZE 6 #define EMT_MISC_SET_DISK_SIZE 7 #define EMT_MISC_QUERY_DBL_STEP 8 #define EMT_MISC_SET_DBL_STEP 9 #define EMT_MISC_QUERY_MICROLABS 10 #define EMT_MISC_SET_MICROLABS 11 #define EMT_MISC_QUERY_DELAY 12 #define EMT_MISC_SET_DELAY 13 #define EMT_MISC_QUERY_KEYSTRETCH 14 #define EMT_MISC_SET_KEYSTRETCH 15 #define EMT_MISC_QUERY_DOUBLER 16 #define EMT_MISC_SET_DOUBLER 17 #define EMT_MISC_QUERY_VOLUME 18 #define EMT_MISC_SET_VOLUME 19 #define EMT_MISC_QUERY_TRUEDAM 20 #define EMT_MISC_SET_TRUEDAM 21 xtrs-4.9d/xtrshard.dct000066400000000000000000000026211306603614600150730ustar00rootroot00000000000000`íSsc: þ@Â6a:%þIÊ¥`>Í2Bb!{D"Cb2{e!K"|e2úe!{K"ûe>12Sf!bÍgD:XGË_Ê7bí[scz³Ê3b!JcÍgD!ucÍ@Ú?bÂ?b:ucþ08äþ80à*I@ÍpbÊïa*I@"qcà—íR"I@ÍAfÍIb:C2>f*C"?f!6f"C>Ã2CÃáa>Í2Bb!ŠB"Cb2{e!ND"|e2úe!zK"ûe>32Sf!bÍgD:XGË_Ê7bí[scz³Ê3b!JcÍgD!ucÍ@Ú?bÂ?b:ucþ08äþ80à*aDÍpbÊïa*D"qcà—íR"DÍAfÍIb:B2>f*B"?f!6f"B>Ã2BÃáa>42Sf!b> ï>eïý~Ë_Ê7bí[scz³Ê3b!Jc> ï!uc> ïÚ?bÂ?b:ucþ08äþ80à|d>SïÊïaKI>RïÂ/b+V+^å!àT]—íBá0 s#ríSqc!E>dïÂ;b"qcà—íR>dïÍAfÍIb>eïý~ýnýf2>f"?f!6fýuýtý6Ãí[qc!Vfàí¸ë#ý*scý6Ãýuýtý6b :ucæöýwý6ý6Éý6ÿý6ÿý6 ÿÍ™e!È!wcí5Ý!ÕbÝ!0cÝ!cÝ!èbÝ!fc> ï!ÿÿÉ*qcý!WfVf—íRDMýnýf|µÈ^#Vë ër+sý#ý#è#|µ =É~þÀå####~þ G|d#¾ #øáÉá##^#VëÓXTRSHARD - Emulated hard disk driver for xtrs - 5/17/00 LS-DOS is curdled! High memory is not availwcable! Must install via SYSTEM (DRIVE=,DRIVER=)! DRIVE= must be specified! Enter unit number ([0]-7): Aborted! wd'Vfxtrshard˜dÝåÍ™eÍ«dÝáÉ> Àx§Èþ(0—É—ÉËP Xþ (G0Nþ (> §Éý~º0>ÉÕåÍoeá> í2>ÑÀx± ÕåÅ6åT]ÿí°ÁáÑ—Ézý– ÆÉ—Éý~º0ï>É> §ÉýË~(>Éþ()0Eþ (ý6 ÿÕåÝ^ÝV!"™d!˜dí=áÑ>À—Éz³Ìfý~º0> ÉÕåÍoeá> í3> ÑÀ—É> §É—gý†o $JCy>[ïTXeo#ë!šdr+s+qÝ^ÝVí4í˜eÉÝ!ˆdÕý~æ_ÝÑÝ~ݦ<(—ÉÕÅå¶!Ofý~æÆ02Ufí>ÝsÝr ]ï= Ë Ë Ë ±ýwýwý6 ÿ—áÁÑÉåÅÕ!˜dBKÝ^ÝV6íC™dí4ý~ wí3ÑÁáÉÿÿí?ÍAfTim!ˆdT]6ÿí°Éhard1-0ydÙd›e£dYe¿e¦d:e=eÉeÕa 1300H, driver won't fit 269: 6196 97 sub a ;Reset carry flag 270: 6197 ED42 sbc hl,bc 271: 6199 E1 pop hl ;Get back address of pointer 272: 619A 300A jr nc,usehi ;Go if driver won't fit 273: 619C 73 ld (hl),e ;Store new value of pointer 274: 619D 23 inc hl 275: 619E 72 ld (hl),d 276: 619F 1B dec de ;Last byte of driver goes here 277: 61A0 ED537163 ld (newend),de 278: 61A4 1816 jr dorelo 279: ;*=*=* 280: ; Put in high memory instead. 281: ;*=*=* 282: 61A6 210000 usehi: ld hl,0 ;Get current HIGH$ 283: 61A9 45 ld b,l 284: 61AA 3E64 ld a,@high 285: 61AC EF rst 40 286: 61AD C23B62 jp nz,nomem 287: 61B0 227163 ld (newend),hl ;Last byte of driver goes here 288: 61B3 11E001 ld de,length 289: 61B6 97 sub a ;Reset carry flag 290: 61B7 ED52 sbc hl,de ;Compute new HIGH$ 291: 61B9 3E64 ld a,@high ;Set new HIGH$ into the system 292: 61BB EF rst 40 293: ;*=*=* 294: ; Relocate internal references in driver. 295: ; HL = address for last byte of driver. 296: ;*=*=* 297: 61BC CD4166 dorelo: call dvrini ;Final driver init before move 298: 61BF CD4962 call relo 299: ;*=*=* 300: ; Link to @ICNFG (must follow address relocation and precede movement) 301: ;*=*=* 302: 61C2 3E65 ld a,@flags ;Get flags pointer into IY 303: 61C4 EF rst 40 304: 61C5 FD7E1C ld a,(iy+28) ;Copy current @ICNFG into LINK 305: 61C8 FD6E1D ld l,(iy+29) 306: 61CB FD661E ld h,(iy+30) 307: 61CE 323E66 ld (link),a 308: 61D1 223F66 ld (link+1),hl 309: 61D4 213666 ld hl,dvrcfg ;Get relocated init address 310: 61D5 rx10 equ $-2 311: 61D7 FD751D ld (iy+29),l ;Save in @ICNFG vector 312: 61DA FD741E ld (iy+30),h 313: 61DD FD361CC3 ld (iy+28),0c3h ;Insert JP opcode 314: ;*=*=* 315: ; Move driver into low or high memory. 316: ;*=*=* 317: 61E1 move: 318: 61E1 ED5B7163 ld de,(newend) ;Destination address 319: 61E5 215666 ld hl,dvrend ;Last byte of module 320: 61E8 01E001 ld bc,length ;Length of filter 321: 61EB EDB8 lddr 322: 61ED EB ex de,hl 323: 61EE 23 inc hl ;Bump to driver entry 324: ;*=*=* 325: ; Setup DCT (iy+5 to iy+9 are reset by ckopen if successful) 326: ;*=*=* 327: 61EF setdct: 328: 61EF FD2A7363 ld iy,(dct) 329: 61F3 FD3600C3 ld (iy),0c3h ;JP instruction (enable driver) 330: 61F7 FD7501 ld (iy+1),l ;Driver address 331: 61FA FD7402 ld (iy+2),h 332: 61FD FD36030C ld (iy+3),00001100b ;Flags: rigid, fixed, step rate 0 333: 6201 3A7563 ld a,(unit) 334: 6204 E60F and 0fh 335: 6206 F610 or 00010000b ;Flags: alien (=no index pulses), unit# 336: 6208 FD7704 ld (iy+4),a 337: 620B FD360500 ld (iy+5),0 ;LDOS undefined; we use as sec/cyl (0=256). 338: 620F FD3606C9 ld (iy+6),201 ;high cylinder number 339: 6213 FD3607FF ld (iy+7),11111111b ;high head # (111), high sec/trak (11111) 340: 6217 FD3608FF ld (iy+8),11111111b ;high gran # (111), high sec/gran (11111) 341: 621B FD3609FF ld (iy+9),0ffh ;Directory cylinder 342: ;*=*=* 343: ; Open file now so user can get error if any, and so geometry 344: ; is established as early as possible. 345: ;*=*=* 346: 621F CD9965 call ckopen 347: 6222 210000 ld hl,0 ;Successful completion 348: 6225 C8 ret z ;Fall thru if error 349: ;*=*=* 350: 6226 217763 uerror: ld hl,errbuf ;Unix error 351: 6229 010001 ld bc,256 352: 622C ED35 defw emt_strerror 353: 622E DD defb 0ddh 354: 622F 21D562 curdl: ld hl,curdl_ ;Other error 355: 6232 DD defb 0ddh 356: 6233 213063 needdr: ld hl,needdr_ 357: 6236 DD defb 0ddh 358: 6237 210663 viaset: ld hl,viaset_ 359: 623A DD defb 0ddh 360: 623B 21E862 nomem: ld hl,nomem_ 361: 623E DD defb 0ddh 362: 623F 216663 hitbrk: ld hl,hitbrk_ 363: 6242 3E0C logot: ld a,@logot 364: 6244 EF rst 40 365: 6245 21FFFF ld hl,-1 ;Unuccessful completion 366: 6248 C9 ret 367: 368: ;*=*=* 369: ; Relocate internal references in driver. 370: ; HL = address for last byte of driver. 371: ;*=*=* 372: 6249 2A7163 relo: ld hl,(newend) 373: 624C FD215766 ld iy,reltab ;Point to relocation tbl 374: 6250 115666 ld de,dvrend 375: 6253 97 sub a ;Clear carry flag 376: 6254 ED52 sbc hl,de 377: 6256 44 ld b,h ;Move to BC 378: 6257 4D ld c,l 379: 6258 FD6E00 rloop: ld l,(iy) ;Get address to change 380: 625B FD6601 ld h,(iy+1) 381: 625E 7C ld a,h 382: 625F B5 or l 383: 6260 C8 ret z 384: 6261 5E ld e,(hl) ;P/U address 385: 6262 23 inc hl 386: 6263 56 ld d,(hl) 387: 6264 EB ex de,hl ;Offset it 388: 6265 09 add hl,bc 389: 6266 EB ex de,hl 390: 6267 72 ld (hl),d ;And put back 391: 6268 2B dec hl 392: 6269 73 ld (hl),e 393: 626A FD23 inc iy 394: 626C FD23 inc iy 395: 626E 18E8 jr rloop ;Loop till done 396: 397: ;*=*=* 398: ; Search for existing copy of driver. 399: ; Rough Model I/III emulation of Model 4 @GTMOD, 400: ; hardcoded with driver address. 401: ; Entry: HL holds HIGH$ 402: ; Exit Z: HL holds driver address 403: ; NZ: driver not found 404: ;*=*=* 405: 6270 23 xgtmod: inc hl 406: 6271 7C ld a,h 407: 6272 B5 or l 408: 6273 2002 jr nz,xgtm1 409: 6275 3D dec a ;not found 410: 6276 C9 ret 411: 6277 7E xgtm1: ld a,(hl) 412: 6278 FE18 cp 18h ;unconditional jr? 413: 627A C0 ret nz ;not a module header 414: 627B E5 push hl ;save start address 415: 627C 23 inc hl ;skip jr 416: 627D 23 inc hl ;skip offset 417: 627E 23 inc hl ;skip start address 418: 627F 23 inc hl 419: 6280 7E ld a,(hl) ;compare name length 420: 6281 FE08 cp modptr-modnam 421: 6283 200F jr nz,nextmd ;different - skip 422: 6285 47 ld b,a ;compare name 423: 6286 117C64 ld de,modnam 424: 6289 23 inc hl 425: 628A 1A xgtm2: ld a,(de) 426: 628B BE cp (hl) 427: 628C 2006 jr nz,nextmd ;different - skip 428: 628E 13 inc de 429: 628F 23 inc hl 430: 6290 10F8 djnz xgtm2 431: 6292 E1 pop hl ;same - found 432: 6293 C9 ret 433: 6294 E1 nextmd: pop hl ;get back start of module 434: 6295 23 inc hl 435: 6296 23 inc hl 436: 6297 5E ld e,(hl) ;pointer to last byte 437: 6298 23 inc hl 438: 6299 56 ld d,(hl) 439: 629A EB ex de,hl 440: 629B 18D3 jr xgtmod 441: 442: ;*=*=* 443: ; Messages and globals 444: ;*=*=* 445: 629D 58545253 hello_: defb 'XTRSHARD - Emulated hard disk driver for xtrs - 5/17/00',CR 48415244 202D2045 6D756C61 74656420 68617264 20646973 6B206472 69766572 20666F72 20787472 73202D20 352F3137 2F30300D 446: 62D5 4C532D44 curdl_: defb 'LS-DOS is curdled!',CR 4F532069 73206375 72646C65 64210D 447: 62E8 48696768 nomem_: defb 'High memory is not available!',CR 206D656D 6F727920 6973206E 6F742061 7661696C 61626C65 210D 448: 6306 4D757374 viaset_:defb 'Must install via SYSTEM (DRIVE=,DRIVER=)!',CR 20696E73 74616C6C 20766961 20535953 54454D20 28445249 56453D2C 44524956 45523D29 210D 449: 6330 44524956 needdr_:defb 'DRIVE= must be specified!',CR 453D206D 75737420 62652073 70656369 66696564 210D 450: 634A 456E7465 unit_: defb 'Enter unit number ([0]-','0'+ndrive-1,'): ',ETX 7220756E 6974206E 756D6265 7220285B 305D2D37 293A2003 451: 6366 41626F72 hitbrk_:defb 'Aborted!',CR 74656421 0D 452: 636F 0000 lcptr: defw 0 453: 6371 0000 newend: defw 0 454: 6373 0000 dct: defw 0 455: 6375 unit: defs 2 456: 6377 errbuf: defs 256 457: 458: ; 459: ; Driver - Based on skeletal driver from the Guide 460: ; 461: 462: 6477 1827 entry: jr begin ;The driver starts with the 463: 6479 5666 defw dvrend ; DOS standard header 464: 6479 rx00 equ $-2 465: 647B 08 defb modptr-modnam ;Length of name 466: 647C 78747273 modnam: defb 'xtrshard' ;Name for @GTMOD requests 68617264 467: 6484 0000 modptr: defw 0 ;These pointers are unused 468: 6486 0000 defw 0 469: 6488 fd: defs ndrive*2 ;Unix file descriptors 470: 6498 00000000 offset: defw 0,0,0,0 ;lseek offset buffer 00000000 471: 64A0 begin: 472: ;*=*=* 473: ; First make sure the file is open and correct the geometry 474: ; in the DCT if needed. 475: ;*=*=* 476: 64A0 DDE5 push ix 477: 64A2 CD9965 call ckopen 478: 64A3 rx03 equ $-2 479: 64A5 CDAB64 call body 480: 64A6 rx06 equ $-2 481: 64A8 DDE1 pop ix 482: 64AA C9 ret 483: 64AB 3E20 body: ld a,32 ;"Illegal drive number" 484: 64AD C0 ret nz 485: 64AE 78 ld a,b ;The first test will return 486: 64AF A7 and a ; to the caller on @DCSTAT 487: 64B0 C8 ret z ; and set the Z-flag with A=0 488: 64B1 FE07 notdcs: cp 7 489: 64B3 2804 jr z,rslct ;Transfer on @RSLCT 490: 64B5 3004 jr nc,diskio ;Transfer on physical I/O request 491: ;*=*=* 492: ; @SLCT, @DCINIT, @DCRES, @RSTOR, @STEPI or @SEEK: no-op 493: ;*=*=* 494: 64B7 97 retzer: sub a 495: 64B8 C9 ret 496: ;*=*=* 497: ; The RSLCT function should return with the hardware 498: ; write protection status. Set bit 6 of the accumulator 499: ; to indicate the drive is write-protected 500: ;*=*=* 501: 64B9 97 rslct: sub a ;No emulated hardware WP for now 502: 64BA C9 ret 503: ;*=*=* 504: 64BB CB50 diskio: bit 2,b ;Test if read or write commands 505: 64BD 2058 jr nz,wrcmd ;Transfer if functions <12-15> 506: 64BF FE0A cp 10 507: 64C1 2847 jr z,vrsec 508: 64C3 304E jr nc,rdtrk 509: 64C5 FE09 cp 9 510: 64C7 2804 jr z,rdsec 511: 64C9 3E20 rdhdr: ld a,32 ;Not supported ("Illegal drive number") 512: 64CB A7 and a 513: 64CC C9 ret 514: ;*=*=* 515: 64CD rdsec: ;Read a sector of data 516: 64CD FD7E06 ld a,(iy+6) ;Get high cyl # 517: 64D0 BA cp d ;At or below it? 518: 64D1 3003 jr nc,rdok 519: 64D3 3E02 ld a,2 ;"Seek error during read" 520: 64D5 C9 ret ;NZ already set 521: 64D6 D5 rdok: push de 522: 64D7 E5 push hl 523: 64D8 CD6F65 call doseek ;Setup and do lseek 524: 64D9 rx01 equ $-2 525: 64DB E1 pop hl 526: 64DC 3E05 ld a,5 ;"Data record not found during read" 527: 64DE 2007 jr nz,rddun 528: 64E0 010001 ld bc,256 529: 64E3 ED32 defw emt_read 530: 64E5 3E04 ld a,4 ;"Parity error during read" 531: 64E7 D1 rddun: pop de 532: 64E8 C0 ret nz 533: 64E9 78 ld a,b ;Check for end of file 534: 64EA B1 or c 535: 64EB 2012 jr nz,rddun2 536: 64ED D5 push de 537: 64EE E5 push hl ;Return a block full of 0E5H 538: 64EF C5 push bc 539: 64F0 36E5 ld (hl),0e5h 540: 64F2 54 ld d,h 541: 64F3 5D ld e,l 542: 64F4 13 inc de 543: 64F5 01FF00 ld bc,0ffh 544: 64F8 EDB0 ldir 545: 64FA C1 pop bc 546: 64FB E1 pop hl 547: 64FC D1 pop de 548: 64FD 97 sub a 549: 64FE C9 ret 550: 64FF 7A rddun2: ld a,d 551: 6500 FD9609 sub (iy+9) 552: 6503 2003 jr nz,rddun1 553: 6505 C606 add a,6 ;"Attempted to read system data record" 554: 6507 C9 ret 555: 6508 97 rddun1: sub a 556: 6509 C9 ret 557: ;*=*=* 558: 650A vrsec: ;Read/verify -- we don't bother reading 559: 650A FD7E06 ld a,(iy+6) ;Get high cyl # 560: 650D BA cp d ;At or below it? 561: 650E 30EF jr nc,rddun2 ;Go if so 562: 6510 3E02 ld a,2 ;"Seek error during read" 563: 6512 C9 ret ;NZ already set 564: ;*=*=* 565: ; On RDSEC and VRSEC, if the read referenced the 566: ; directory cylinder and was successful, 567: ; then you need to return an error code 6. A floppy 568: ; disk controller will provide the indicated status. 569: ; Hard disk users may have to compare the requested 570: ; cylinder to DIRCYL in the DCT. 571: ;*=*=* 572: 6513 3E20 rdtrk: ld a,32 ;Not supported ("Illegal drive number") 573: 6515 A7 and a 574: 6516 C9 ret 575: ;*=*=* 576: 6517 FDCB037E wrcmd: bit 7,(iy+3) ;Check for software write protect 577: 651B 2803 jr z,wrcmd1 ;Transfer if no soft WP 578: 651D 3E0F ld a,15 ;Set "Write protected disk" error 579: 651F C9 ret 580: 6520 FE0E wrcmd1: cp 14 ;Now parse functions 12-15 581: 6522 2829 jr z,wrssc 582: 6524 3045 jr nc,wrtrk 583: 6526 FE0D cp 13 584: 6528 281E jr z,wrsec 585: ;*=*=* 586: 652A hdfmt: ;Low-level format (=erase) 587: 652A FD3609FF ld (iy+9),0ffh ;Invalidate directory cylinder 588: 652E D5 push de 589: 652F E5 push hl 590: 6530 DD5E00 ld e,(ix) ;Get fd 591: 6533 DD5601 ld d,(ix+1) 592: 6536 210001 exists: ld hl,256 ;Truncate file to just the header 593: 6539 229964 ld (offset+1),hl 594: 653A rx07 equ $-2 595: 653C 219864 ld hl,offset 596: 653D rx08 equ $-2 597: 653F ED3D defw emt_ftruncate 598: 6541 E1 creatd: pop hl 599: 6542 D1 pop de 600: 6543 3E0E ld a,14 ;"Write fault on disk drive" 601: 6545 C0 ret nz 602: 6546 97 sub a 603: 6547 C9 ret 604: ;*=*=* 605: 6548 wrsec: ;Write with X'FB' data address mark 606: 6548 7A ld a,d ;Check if writing track 0, sector 0 607: 6549 B3 or e 608: 654A CC1566 call z,setdir ;Set directory cyl in Reed header 609: 654B rx20 equ $-2 610: ;*=*=* 611: 654D wrssc: ;Write with X'F8' data address mark 612: 654D FD7E06 ld a,(iy+6) ;Get high cyl # 613: 6550 BA cp d ;Beyond it? 614: 6551 3003 jr nc,wrok1 615: 6553 3E0A ld a,10 ;"Seek error during write" 616: 6555 C9 ret ;NZ already set 617: ;*=*=* 618: 6556 D5 wrok1: push de 619: 6557 E5 push hl 620: 6558 CD6F65 call doseek 621: 6559 rx04 equ $-2 622: 655B E1 pop hl 623: 655C 3E0D ld a,13 ;"Data record not found during write" 624: 655E 2007 jr nz,wrdun 625: 6560 010001 ld bc,256 626: 6563 ED33 defw emt_write 627: 6565 3E0C ld a,12 ;"Parity error during write" 628: 6567 D1 wrdun: pop de 629: 6568 C0 ret nz 630: 6569 97 sub a 631: 656A C9 ret 632: ;*=*=* 633: 656B 3E20 wrtrk: ld a,32 ;Write track 634: 656D A7 and a ;Not supported ("Illegal drive number") 635: 656E C9 ret 636: ;*=*=* 637: ; Perform lseek before r/w 638: ;*=*=* 639: 656F 97 doseek: sub a ;sec/cyl to hl, xlate 0 to 256 640: 6570 67 ld h,a 641: 6571 FD8605 add a,(iy+5) 642: 6574 6F ld l,a 643: 6575 2001 jr nz,noinc 644: 6577 24 inc h 645: 6578 4A noinc: ld c,d ;cyl# to c 646: 6579 43 ld b,e ;sec# to b 647: 657A 79 ld a,c ;model I/III call uses a, not c 648: 657B 3E5B domul: ld a,@mul16 ;hla = hl * c, smash de 649: 657D EF rst 40 650: 657E 54 ld d,h ;sec# to de (h is 0) 651: 657F 58 ld e,b 652: 6580 65 ld h,l ;product to hl 653: 6581 6F ld l,a 654: 6582 23 inc hl ;add 1 extra for header 655: 6583 19 add hl,de 656: 6584 EB ex de,hl ;offset to de 657: 6585 219A64 ld hl,offset+2 658: 6586 rx15 equ $-2 659: 6588 72 ld (hl),d 660: 6589 2B dec hl 661: 658A 73 ld (hl),e 662: 658B 2B dec hl 663: 658C 010000 ld bc,0 664: 658F 71 ld (hl),c 665: 6590 DD5E00 ld e,(ix) ;Get fd 666: 6593 DD5601 ld d,(ix+1) 667: 6596 ED34 defw emt_lseek 668: 6598 C9 ret 669: 670: ;*=*=* 671: ; Open file and read geometry if needed, and 672: ; get address of correct fd to ix. 673: ;*=*=* 674: 6599 DD218864 ckopen: ld ix,fd ;Compute fd address 675: 659B rx02 equ $-2 676: 659D D5 push de 677: 659E 1600 ld d,0 678: 65A0 FD7E04 ld a,(iy+4) 679: 65A3 E60F and 0fh 680: 65A5 07 rlca 681: 65A6 5F ld e,a 682: 65A7 DD19 add ix,de 683: 65A9 D1 pop de 684: 65AA DD7E00 ld a,(ix) ;fd == -1? 685: 65AD DDA601 and (ix+1) 686: 65B0 3C inc a 687: 65B1 2802 jr z,doopen 688: 65B3 97 sub a 689: 65B4 C9 ret 690: 65B5 D5 doopen: push de 691: 65B6 C5 push bc 692: 65B7 E5 push hl 693: 65B8 010200 ld bc,EO_RDWR ;Prepare to open 694: 65BB 11B601 ld de,0666o ;mode 695: 65BE 214F66 ld hl,hard_ ;name 696: 65BF rx05 equ $-2 697: 65C1 FD7E04 ld a,(iy+4) 698: 65C4 E60F and 0fh 699: 65C6 C630 add a,'0' 700: 65C8 325566 ld (hadr),a 701: 65C9 rx09 equ $-2 702: 65CB ED3E defw emt_opendisk 703: 65CD DD7300 ld (ix),e 704: 65D0 DD7201 ld (ix+1),d 705: 65D3 203C jr nz,opnerr 706: 65D5 219864 ld hl,offset ;Prepare to read geometry 707: 65D6 rx13 equ $-2 708: 65D8 361C ld (hl),28 ;offset to cyl/sec/gran params 709: 65DA 010000 ld bc,0 710: 65DD ED439964 ld (offset+1),bc 711: 65DF rx14 equ $-2 712: 65E1 ED34 defw emt_lseek 713: 65E3 202C jr nz,opnerr 714: 65E5 010300 ld bc,3 ;length 715: 65E8 ED32 defw emt_read ;use offset buffer 716: 65EA 2025 jr nz,opnerr 717: 65EC 7E ld a,(hl) ;cyl 718: 65ED 3D dec a 719: 65EE FD7706 ld (iy+6),a ;max cylinder 720: 65F1 23 inc hl 721: 65F2 46 ld b,(hl) ;sec 722: 65F3 FD7005 ld (iy+5),b 723: 65F6 23 inc hl 724: 65F7 4E ld c,(hl) ;gran 725: 65F8 58 ld e,b ;compute sec/gran 726: 65F9 79 ld a,c ;model I/III call uses a, not c 727: 65FA 3E5D dodiv: ld a,@div8 ;a = e / c, e = e % c 728: 65FC EF rst 40 ;remainder mbz, but we don't check here 729: 65FD 3D dec a 730: 65FE 0D dec c 731: 65FF CB09 rrc c 732: 6601 CB09 rrc c 733: 6603 CB09 rrc c 734: 6605 B1 or c 735: 6606 FD7707 ld (iy+7),a ;heads, secs per track 736: 6609 FD7708 ld (iy+8),a ;grans, secs per gran 737: 660C FD3609FF ld (iy+9),0ffh ;dircyl unknown 738: 6610 97 sub a ;no error 739: 6611 E1 opnerr: pop hl 740: 6612 C1 pop bc 741: 6613 D1 pop de 742: 6614 C9 ret 743: ;*=*=* 744: ; Sleazy trick to update dir cyl in Reed header: do 745: ; it whenever track 0, sector 0 is written. 746: ; Only important if sharing images with Reed emulator. 747: ;*=*=* 748: 6615 E5 setdir: push hl 749: 6616 C5 push bc 750: 6617 D5 push de 751: 6618 219864 ld hl,offset 752: 6619 rx18 equ $-2 753: 661B 42 ld b,d ;de is known to be 0 here 754: 661C 4B ld c,e 755: 661D DD5E00 ld e,(ix) ;Get fd 756: 6620 DD5601 ld d,(ix+1) 757: 6623 361F ld (hl),31 ;offset to dir cyl param 758: 6625 ED439964 ld (offset+1),bc 759: 6627 rx19 equ $-2 760: 6629 ED34 defw emt_lseek 761: 662B FD7E09 ld a,(iy+9) ;dir cyl value to write 762: 662E 77 ld (hl),a 763: 662F 03 inc bc 764: 6630 ED33 defw emt_write 765: 6632 D1 pop de ;cheat, ignore errors 766: 6633 C1 pop bc 767: 6634 E1 pop hl 768: 6635 C9 ret 769: ;*=*=* 770: ; Boot-time initialization 771: ;*=*=* 772: 6636 11FFFF dvrcfg: ld de,-1 ;@ICNFG chains in here 773: 6639 ED3F defw emt_closedisk ;close any files left from before reboot 774: 663B CD4166 call dvrini 775: 663C rx11 equ $-2 776: 663E 54696D link: defb 'Tim' ;Replaced by next link in @ICNFG chain 777: 6641 218864 dvrini: ld hl,fd 778: 6642 rx12 equ $-2 779: 6644 54 ld d,h 780: 6645 5D ld e,l 781: 6646 13 inc de 782: 6647 36FF ld (hl),0ffh 783: 6649 010F00 ld bc,ndrive*2-1 784: 664C EDB0 ldir 785: 664E C9 ret 786: ;*=*=* 787: ; Disk name: hardM-N for model M (1,3,4), number N (0-7) 788: ;*=*=* 789: 664F 68617264 hard_: defb 'hard' 790: 6653 312D hmod: defb '1-' 791: 6655 3000 hadr: defb '0',0 792: 793: 6656 dvrend equ $-1 794: 01E0 length equ $-entry 795: 6657 7964D964 reltab: defw rx00,rx01,rx02,rx03,rx04,rx05,rx06,rx07,rx08,rx09 9B65A364 5965BF65 A6643A65 3D65C965 796: 666B D5613C66 defw rx10,rx11,rx12,rx13,rx14,rx15,rx16,rx17,rx18,rx19 4266D665 DF658665 98602961 19662766 797: 667F 4B650000 defw rx20,0 798: 6000 end instal Statistics: 146 symbols 1393 bytes Symbol Table: @div8 = 5d emt_write =33ed rdok 64d6 @divea1 =4b7b entry 6477 rdsec 64cd @divea3 =4b7a eo_append = 400+ rdtrk 6513 @dsply = a eo_creat = 40+ relo 6249 @dsply1 =4467 eo_excl = 80+ reltab 6657 @dsply3 =4467 eo_rdonly = 0+ retzer 64b7+ @flags = 65 eo_rdwr = 2 rloop 6258 @gtdcb = 52 eo_trunc = 200+ rslct 64b9 @gtmod = 53 eo_wronly = 1+ rx00 =6479 @high = 64 errbuf 6377 rx01 =64d9 @icnfg1 =4303 etx = 3 rx02 =659b @icnfg3 =421d exists 6536+ rx03 =64a3 @keyin = 9 fd 6488 rx04 =6559 @keyin1 = 40 hadr 6655 rx05 =65bf @keyin3 = 40 hard_ 664f rx06 =64a6 @logot = c hdfmt 652a+ rx07 =653a @logot1 =447b hello_ 629d rx08 =653d @logot3 =428a high1 =4049 rx09 =65c9 @mul16 = 5b high3 =4411 rx10 =61d5 @mult1 =4b8f hitbrk 623f rx11 =663c @mult3 =444e hitbrk_ 6366 rx12 =6642 asku1 604d hmod 6653 rx13 =65d6 asku3 60de instal 6000 rx14 =65df asku4 6155 lcptr 636f+ rx15 =6586 begin 64a0 length = 1e0 rx16 =6098 body 64ab lf = a+ rx17 =6129 cflag1 =4758 link 663e rx18 =6619 cflag3 =4758 logot 6242 rx19 =6627 ckopen 6599 lsdos6 6136 rx20 =654b cr = d m3flag = 125 setdct 61ef creatd 6541+ model3 60a5 setdir 6615 curdl 622f modnam 647c uerror 6226+ curdl_ 62d5 modptr 6484 unit 6375 dct 6373 move 61e1 unit_ 634a diskio 64bb ndrive = 8 usehi 61a6 dodiv 65fa needdr 6233 viaset 6237 domul 657b needdr_ 6330 viaset_ 6306 doopen 65b5 newend 6371 vrsec 650a dorelo 61bc nextmd 6294 wrcmd 6517 doseek 656f noinc 6578 wrcmd1 6520 dvrcfg 6636 nomem 623b wrdun 6567 dvrend =6656 nomem_ 62e8 wrok1 6556 dvrini 6641 notdcs 64b1+ wrsec 6548 emt_closedisk =3fed offset 6498 wrssc 654d emt_ftruncate =3ded opnerr 6611 wrtrk 656b emt_lseek =34ed rddun 64e7 xgtm1 6277 emt_opendisk =3eed rddun1 6508 xgtm2 628a emt_read =32ed rddun2 64ff xgtmod 6270 emt_strerror =35ed rdhdr 64c9+ xtrs-4.9d/xtrshard.z80000066400000000000000000000415611306603614600147500ustar00rootroot00000000000000;*=*=* ; xtrshard/dct ; Emulate hard disk in a Unix file under xtrs ; ; Copyright (c) 1998, Timothy Mann ; $Id: xtrshard.z80,v 1.9 2008/06/26 04:39:56 mann Exp $ ; ; This software may be copied, modified, and used for any ; purpose without fee, provided that (1) the above copyright ; notice is retained, and (2) modified versions are clearly ; marked as having been modified, with the modifier's name and ; the date included. ;*=*=* ; Number of drives to allow ndrive equ 8 ; ASCII chars LF equ 10 CR equ 13 ETX equ 3 ; Model 4 SVC numbers @high equ 100 @dsply equ 10 @flags equ 101 @logot equ 12 @gtdcb equ 82 @gtmod equ 83 @div8 equ 93 @mul16 equ 91 @keyin equ 9 ; Model I/III hard addresses m3flag$ equ 0125h ; 'I' in ROM on Model III @logot1 equ 447bh @logot3 equ 428ah @dsply1 equ 4467h @dsply3 equ 4467h high$1 equ 4049h high$3 equ 4411h cflag$1 equ 4758h cflag$3 equ 4758h @icnfg1 equ 4303h @icnfg3 equ 421dh @mult1 equ 4b8fh @mult3 equ 444eh @divea1 equ 4b7bh @divea3 equ 4b7ah @keyin1 equ 0040h @keyin3 equ 0040h ; Emulator trap instructions in byte-reversed form emt_read equ 32EDH emt_write equ 33EDH emt_lseek equ 34EDH emt_strerror equ 35EDH emt_ftruncate equ 3DEDH emt_opendisk equ 3EEDH emt_closedisk equ 3FEDH ; Constants for emt_opendisk EO_RDONLY equ 00o EO_WRONLY equ 01o EO_RDWR equ 02o EO_CREAT equ 0100o EO_EXCL equ 0200o EO_TRUNC equ 01000o EO_APPEND equ 02000o ;*=*=* ; Set origin to be safe on both LDOS 5 and 6 ;*=*=* org 6000h ;*=*=* ; Relocator for disk driver ;*=*=* instal: ld (dct),de ;Save DCT address ld a,(000ah) ;Determine TRS-80 model cp 40h jp nz,lsdos6 ;Model 4 (or other LS-DOS, I hope) ld a,(m3flag$) cp 'I' jp z,model3 ;Go if Model III ;*=*=* ; LDOS 5 Model I - See LS-DOS 6 version for comments ;*=*=* ld a,0cdh ;Insert Model I @LOGOT ld (logot),a ld hl,@logot1 ld (logot+1),hl ld (domul),a ;Insert Model I MULT ld hl,@mult1 ld (domul+1),hl ld (dodiv),a ;Insert Model I DIVEA ld hl,@divea1 ld (dodiv+1),hl ld a,'1' ;Modify filename ld (hmod),a ld hl,hello_ call @dsply1 ld a,(cflag$1) bit 3,a ;System request? jp z,viaset ld de,(dct) ld a,d ;DRIVE= must be specified or e jp z,needdr asku1: ld hl,unit_ ;Ask which unit number call @dsply1 ld hl,unit ld bc,100h call @keyin1 jp c,hitbrk jp nz,hitbrk ld a,(unit) cp '0' jr c,asku1 cp '0'+ndrive jr nc,asku1 ld hl,(high$1) call xgtmod ;Module already loaded? jp z,setdct ld hl,(high$1) ld (newend),hl ld de,length sub a sbc hl,de ld (high$1),hl call dvrini call relo ld a,(@icnfg1) ld (link),a ld hl,(@icnfg1+1) ld (link+1),hl ld hl,dvrcfg rx16 equ $-2 ld (@icnfg1+1),hl ld a,0c3h ld (@icnfg1),a jp move ;*=*=* ; LDOS 5 Model III ;*=*=* model3: ld a,0cdh ;Insert Model III @LOGOT ld (logot),a ld hl,@logot3 ld (logot+1),hl ld (domul),a ;Insert Model III MULT ld hl,@mult3 ld (domul+1),hl ld (dodiv),a ;Insert Model III DIVEA ld hl,@divea3 ld (dodiv+1),hl ld a,'3' ;Modify filename ld (hmod),a ld hl,hello_ call @dsply3 ld a,(cflag$3) bit 3,a ;System request? jp z,viaset ld de,(dct) ld a,d ;DRIVE= must be specified or e jp z,needdr asku3: ld hl,unit_ ;Ask which unit number call @dsply3 ld hl,unit ld bc,100h call @keyin3 jp c,hitbrk jp nz,hitbrk ld a,(unit) cp '0' jr c,asku3 cp '0'+ndrive jr nc,asku3 ld hl,(high$3) call xgtmod ;Module already loaded? jp z,setdct ld hl,(high$3) ld (newend),hl ld de,length sub a sbc hl,de ld (high$3),hl call dvrini call relo ld a,(@icnfg3) ld (link),a ld hl,(@icnfg3+1) ld (link+1),hl ld hl,dvrcfg rx17 equ $-2 ld (@icnfg3+1),hl ld a,0c3h ld (@icnfg3),a jp move ;*=*=* ; LS-DOS 6 ;*=*=* lsdos6: ld a,'4' ;Modify filename ld (hmod),a ld hl,hello_ ld a,@dsply ;Display hello rst 40 ;*=*=* ; Check if entry from SYSTEM command. ;*=*=* ld a,@flags ;Get flags pointer into IY rst 40 ld a,(iy+'C'-'A') ;Get CFLAG$ bit 3,a ;System request? jp z,viaset ld de,(dct) ld a,d ;DRIVE= must be specified or e jp z,needdr ;*=*=* ; Ask which unit number ;*=*=* asku4: ld hl,unit_ ;Ask which unit number ld a,@dsply rst 40 ld hl,unit ld bc,100h ld a,@keyin rst 40 jp c,hitbrk jp nz,hitbrk ld a,(unit) cp '0' jr c,asku4 cp '0'+ndrive jr nc,asku4 ;*=*=* ; Check if driver already loaded ;*=*=* ld de,modnam ld a,@gtmod rst 40 jp z,setdct ;Already loaded, skip loading ;*=*=* ; Obtain low memory driver pointer. Bizarre API here! ;*=*=* ld e,'K' ;Locate pointer to *KI DCB ld d,'I' ; via @GTDCB SVC ld a,@gtdcb rst 40 jp nz,curdl ;No error unless KI clobbered! dec hl ;Decrement to driver pointer ld d,(hl) ;P/u hi-order of pointer, dec hl ; decrement to and p/u ld e,(hl) ; lo-order of pointer ;*=*=* ; Check if driver will fit into [(LCPTR), X'12FF'] ;*=*=* push hl ;Save address of pointer ld hl,length ;New pointer will be add hl,de ; pointer + LENGTH ld d,h ;Save a copy in DE ld e,l ld bc,1301h ;If > 1300H, driver won't fit sub a ;Reset carry flag sbc hl,bc pop hl ;Get back address of pointer jr nc,usehi ;Go if driver won't fit ld (hl),e ;Store new value of pointer inc hl ld (hl),d dec de ;Last byte of driver goes here ld (newend),de jr dorelo ;*=*=* ; Put in high memory instead. ;*=*=* usehi: ld hl,0 ;Get current HIGH$ ld b,l ld a,@high rst 40 jp nz,nomem ld (newend),hl ;Last byte of driver goes here ld de,length sub a ;Reset carry flag sbc hl,de ;Compute new HIGH$ ld a,@high ;Set new HIGH$ into the system rst 40 ;*=*=* ; Relocate internal references in driver. ; HL = address for last byte of driver. ;*=*=* dorelo: call dvrini ;Final driver init before move call relo ;*=*=* ; Link to @ICNFG (must follow address relocation and precede movement) ;*=*=* ld a,@flags ;Get flags pointer into IY rst 40 ld a,(iy+28) ;Copy current @ICNFG into LINK ld l,(iy+29) ld h,(iy+30) ld (link),a ld (link+1),hl ld hl,dvrcfg ;Get relocated init address rx10 equ $-2 ld (iy+29),l ;Save in @ICNFG vector ld (iy+30),h ld (iy+28),0c3h ;Insert JP opcode ;*=*=* ; Move driver into low or high memory. ;*=*=* move: ld de,(newend) ;Destination address ld hl,dvrend ;Last byte of module ld bc,length ;Length of filter lddr ex de,hl inc hl ;Bump to driver entry ;*=*=* ; Setup DCT (iy+5 to iy+9 are reset by ckopen if successful) ;*=*=* setdct: ld iy,(dct) ld (iy),0c3h ;JP instruction (enable driver) ld (iy+1),l ;Driver address ld (iy+2),h ld (iy+3),00001100b ;Flags: rigid, fixed, step rate 0 ld a,(unit) and 0fh or 00010000b ;Flags: alien (=no index pulses), unit# ld (iy+4),a ld (iy+5),0 ;LDOS undefined; we use as sec/cyl (0=256). ld (iy+6),201 ;high cylinder number ld (iy+7),11111111b ;high head # (111), high sec/trak (11111) ld (iy+8),11111111b ;high gran # (111), high sec/gran (11111) ld (iy+9),0ffh ;Directory cylinder ;*=*=* ; Open file now so user can get error if any, and so geometry ; is established as early as possible. ;*=*=* call ckopen ld hl,0 ;Successful completion ret z ;Fall thru if error ;*=*=* uerror: ld hl,errbuf ;Unix error ld bc,256 defw emt_strerror defb 0ddh curdl: ld hl,curdl_ ;Other error defb 0ddh needdr: ld hl,needdr_ defb 0ddh viaset: ld hl,viaset_ defb 0ddh nomem: ld hl,nomem_ defb 0ddh hitbrk: ld hl,hitbrk_ logot: ld a,@logot rst 40 ld hl,-1 ;Unuccessful completion ret ;*=*=* ; Relocate internal references in driver. ; HL = address for last byte of driver. ;*=*=* relo: ld hl,(newend) ld iy,reltab ;Point to relocation tbl ld de,dvrend sub a ;Clear carry flag sbc hl,de ld b,h ;Move to BC ld c,l rloop: ld l,(iy) ;Get address to change ld h,(iy+1) ld a,h or l ret z ld e,(hl) ;P/U address inc hl ld d,(hl) ex de,hl ;Offset it add hl,bc ex de,hl ld (hl),d ;And put back dec hl ld (hl),e inc iy inc iy jr rloop ;Loop till done ;*=*=* ; Search for existing copy of driver. ; Rough Model I/III emulation of Model 4 @GTMOD, ; hardcoded with driver address. ; Entry: HL holds HIGH$ ; Exit Z: HL holds driver address ; NZ: driver not found ;*=*=* xgtmod: inc hl ld a,h or l jr nz,xgtm1 dec a ;not found ret xgtm1: ld a,(hl) cp 18h ;unconditional jr? ret nz ;not a module header push hl ;save start address inc hl ;skip jr inc hl ;skip offset inc hl ;skip start address inc hl ld a,(hl) ;compare name length cp modptr-modnam jr nz,nextmd ;different - skip ld b,a ;compare name ld de,modnam inc hl xgtm2: ld a,(de) cp (hl) jr nz,nextmd ;different - skip inc de inc hl djnz xgtm2 pop hl ;same - found ret nextmd: pop hl ;get back start of module inc hl inc hl ld e,(hl) ;pointer to last byte inc hl ld d,(hl) ex de,hl jr xgtmod ;*=*=* ; Messages and globals ;*=*=* hello_: defb 'XTRSHARD - Emulated hard disk driver for xtrs - 5/17/00',CR curdl_: defb 'LS-DOS is curdled!',CR nomem_: defb 'High memory is not available!',CR viaset_:defb 'Must install via SYSTEM (DRIVE=,DRIVER=)!',CR needdr_:defb 'DRIVE= must be specified!',CR unit_: defb 'Enter unit number ([0]-','0'+ndrive-1,'): ',ETX hitbrk_:defb 'Aborted!',CR lcptr: defw 0 newend: defw 0 dct: defw 0 unit: defs 2 errbuf: defs 256 ; ; Driver - Based on skeletal driver from the Guide ; entry: jr begin ;The driver starts with the defw dvrend ; DOS standard header rx00 equ $-2 defb modptr-modnam ;Length of name modnam: defb 'xtrshard' ;Name for @GTMOD requests modptr: defw 0 ;These pointers are unused defw 0 fd: defs ndrive*2 ;Unix file descriptors offset: defw 0,0,0,0 ;lseek offset buffer begin: ;*=*=* ; First make sure the file is open and correct the geometry ; in the DCT if needed. ;*=*=* push ix call ckopen rx03 equ $-2 call body rx06 equ $-2 pop ix ret body: ld a,32 ;"Illegal drive number" ret nz ld a,b ;The first test will return and a ; to the caller on @DCSTAT ret z ; and set the Z-flag with A=0 notdcs: cp 7 jr z,rslct ;Transfer on @RSLCT jr nc,diskio ;Transfer on physical I/O request ;*=*=* ; @SLCT, @DCINIT, @DCRES, @RSTOR, @STEPI or @SEEK: no-op ;*=*=* retzer: sub a ret ;*=*=* ; The RSLCT function should return with the hardware ; write protection status. Set bit 6 of the accumulator ; to indicate the drive is write-protected ;*=*=* rslct: sub a ;No emulated hardware WP for now ret ;*=*=* diskio: bit 2,b ;Test if read or write commands jr nz,wrcmd ;Transfer if functions <12-15> cp 10 jr z,vrsec jr nc,rdtrk cp 9 jr z,rdsec rdhdr: ld a,32 ;Not supported ("Illegal drive number") and a ret ;*=*=* rdsec: ;Read a sector of data ld a,(iy+6) ;Get high cyl # cp d ;At or below it? jr nc,rdok ld a,2 ;"Seek error during read" ret ;NZ already set rdok: push de push hl call doseek ;Setup and do lseek rx01 equ $-2 pop hl ld a,5 ;"Data record not found during read" jr nz,rddun ld bc,256 defw emt_read ld a,4 ;"Parity error during read" rddun: pop de ret nz ld a,b ;Check for end of file or c jr nz,rddun2 push de push hl ;Return a block full of 0E5H push bc ld (hl),0e5h ld d,h ld e,l inc de ld bc,0ffh ldir pop bc pop hl pop de sub a ret rddun2: ld a,d sub (iy+9) jr nz,rddun1 add a,6 ;"Attempted to read system data record" ret rddun1: sub a ret ;*=*=* vrsec: ;Read/verify -- we don't bother reading ld a,(iy+6) ;Get high cyl # cp d ;At or below it? jr nc,rddun2 ;Go if so ld a,2 ;"Seek error during read" ret ;NZ already set ;*=*=* ; On RDSEC and VRSEC, if the read referenced the ; directory cylinder and was successful, ; then you need to return an error code 6. A floppy ; disk controller will provide the indicated status. ; Hard disk users may have to compare the requested ; cylinder to DIRCYL in the DCT. ;*=*=* rdtrk: ld a,32 ;Not supported ("Illegal drive number") and a ret ;*=*=* wrcmd: bit 7,(iy+3) ;Check for software write protect jr z,wrcmd1 ;Transfer if no soft WP ld a,15 ;Set "Write protected disk" error ret wrcmd1: cp 14 ;Now parse functions 12-15 jr z,wrssc jr nc,wrtrk cp 13 jr z,wrsec ;*=*=* hdfmt: ;Low-level format (=erase) ld (iy+9),0ffh ;Invalidate directory cylinder push de push hl ld e,(ix) ;Get fd ld d,(ix+1) exists: ld hl,256 ;Truncate file to just the header ld (offset+1),hl rx07 equ $-2 ld hl,offset rx08 equ $-2 defw emt_ftruncate creatd: pop hl pop de ld a,14 ;"Write fault on disk drive" ret nz sub a ret ;*=*=* wrsec: ;Write with X'FB' data address mark ld a,d ;Check if writing track 0, sector 0 or e call z,setdir ;Set directory cyl in Reed header rx20 equ $-2 ;*=*=* wrssc: ;Write with X'F8' data address mark ld a,(iy+6) ;Get high cyl # cp d ;Beyond it? jr nc,wrok1 ld a,10 ;"Seek error during write" ret ;NZ already set ;*=*=* wrok1: push de push hl call doseek rx04 equ $-2 pop hl ld a,13 ;"Data record not found during write" jr nz,wrdun ld bc,256 defw emt_write ld a,12 ;"Parity error during write" wrdun: pop de ret nz sub a ret ;*=*=* wrtrk: ld a,32 ;Write track and a ;Not supported ("Illegal drive number") ret ;*=*=* ; Perform lseek before r/w ;*=*=* doseek: sub a ;sec/cyl to hl, xlate 0 to 256 ld h,a add a,(iy+5) ld l,a jr nz,noinc inc h noinc: ld c,d ;cyl# to c ld b,e ;sec# to b ld a,c ;model I/III call uses a, not c domul: ld a,@mul16 ;hla = hl * c, smash de rst 40 ld d,h ;sec# to de (h is 0) ld e,b ld h,l ;product to hl ld l,a inc hl ;add 1 extra for header add hl,de ex de,hl ;offset to de ld hl,offset+2 rx15 equ $-2 ld (hl),d dec hl ld (hl),e dec hl ld bc,0 ld (hl),c ld e,(ix) ;Get fd ld d,(ix+1) defw emt_lseek ret ;*=*=* ; Open file and read geometry if needed, and ; get address of correct fd to ix. ;*=*=* ckopen: ld ix,fd ;Compute fd address rx02 equ $-2 push de ld d,0 ld a,(iy+4) and 0fh rlca ld e,a add ix,de pop de ld a,(ix) ;fd == -1? and (ix+1) inc a jr z,doopen sub a ret doopen: push de push bc push hl ld bc,EO_RDWR ;Prepare to open ld de,0666o ;mode ld hl,hard_ ;name rx05 equ $-2 ld a,(iy+4) and 0fh add a,'0' ld (hadr),a rx09 equ $-2 defw emt_opendisk ld (ix),e ld (ix+1),d jr nz,opnerr ld hl,offset ;Prepare to read geometry rx13 equ $-2 ld (hl),28 ;offset to cyl/sec/gran params ld bc,0 ld (offset+1),bc rx14 equ $-2 defw emt_lseek jr nz,opnerr ld bc,3 ;length defw emt_read ;use offset buffer jr nz,opnerr ld a,(hl) ;cyl dec a ld (iy+6),a ;max cylinder inc hl ld b,(hl) ;sec ld (iy+5),b inc hl ld c,(hl) ;gran ld e,b ;compute sec/gran ld a,c ;model I/III call uses a, not c dodiv: ld a,@div8 ;a = e / c, e = e % c rst 40 ;remainder mbz, but we don't check here dec a dec c rrc c rrc c rrc c or c ld (iy+7),a ;heads, secs per track ld (iy+8),a ;grans, secs per gran ld (iy+9),0ffh ;dircyl unknown sub a ;no error opnerr: pop hl pop bc pop de ret ;*=*=* ; Sleazy trick to update dir cyl in Reed header: do ; it whenever track 0, sector 0 is written. ; Only important if sharing images with Reed emulator. ;*=*=* setdir: push hl push bc push de ld hl,offset rx18 equ $-2 ld b,d ;de is known to be 0 here ld c,e ld e,(ix) ;Get fd ld d,(ix+1) ld (hl),31 ;offset to dir cyl param ld (offset+1),bc rx19 equ $-2 defw emt_lseek ld a,(iy+9) ;dir cyl value to write ld (hl),a inc bc defw emt_write pop de ;cheat, ignore errors pop bc pop hl ret ;*=*=* ; Boot-time initialization ;*=*=* dvrcfg: ld de,-1 ;@ICNFG chains in here defw emt_closedisk ;close any files left from before reboot call dvrini rx11 equ $-2 link: defb 'Tim' ;Replaced by next link in @ICNFG chain dvrini: ld hl,fd rx12 equ $-2 ld d,h ld e,l inc de ld (hl),0ffh ld bc,ndrive*2-1 ldir ret ;*=*=* ; Disk name: hardM-N for model M (1,3,4), number N (0-7) ;*=*=* hard_: defb 'hard' hmod: defb '1-' hadr: defb '0',0 dvrend equ $-1 length equ $-entry reltab: defw rx00,rx01,rx02,rx03,rx04,rx05,rx06,rx07,rx08,rx09 defw rx10,rx11,rx12,rx13,rx14,rx15,rx16,rx17,rx18,rx19 defw rx20,0 end instal xtrs-4.9d/xtrsmous.cmd000066400000000000000000000006611306603614600151330ustar00rootroot000000000000000k1>ï•0!Ò0> ï1>SïÊ™0x±((KI>RïÂ0+V+^å!T]—íBá0 s#ríSi1!E>dï¡0"i1—íR>dïÍ«0>eïý~ýnýf2‘1"’1!Ž1ýuýtý6Ãí[i1!š1í¸ë#Í”1!—É!W1Ý!71Ý!1Ý!1> ï!ÿÿÉ*i1ý!›1š1—íRDMýnýf|µÈ^#Vë ër+sý#ý#èXTRSMOUS - Emulated mouse driver for xtrs - 9/§128/98 LS-DOS is curdled! High memory is not available! Mouse driver is already loaded! Bad parameters! LOW 0L 0 š1$MOUSEí)ÉÍ”1Tim!|1"ðÉ~1s01•10xtrs-4.9d/xtrsmous.lst000066400000000000000000000275721306603614600152040ustar00rootroot00000000000000 1: ;*=*=* 2: ; xtrsmous/cmd 3: ; LS-DOS driver for xtrs emulation of mouse 4: ; 5: ; Copyright (c) 1998, Timothy Mann 6: ; $Id: xtrsmous.z80,v 1.2 2008/06/26 04:39:56 mann Exp $ 7: ; 8: ; This software may be copied, modified, and used for any 9: ; purpose without fee, provided that (1) the above copyright 10: ; notice is retained, and (2) modified versions are clearly 11: ; marked as having been modified, with the modifier's name and 12: ; the date included. 13: ; 14: ; Usage: 15: ; xtrsmous To load driver in high memory. 16: ; xtrsmous (low) To load driver in low memory if possible, 17: ; or in high memory if low memory is full. 18: ; 19: ; The default is to use high memory because MDRAW/BAS contains a 20: ; PEEK in the first line of code that looks for the driver in 21: ; high memory; if it is in low memory, MDRAW thinks the driver 22: ; is not installed and exits. If you edit this line of code to 23: ; remove the test, the driver will work fine in low memory. 24: ;*=*=* 25: 26: 27: ; ASCII chars 28: 000A LF equ 10 29: 000D CR equ 13 30: 0003 ETX equ 3 31: 32: ; Model 4 SVC numbers 33: 0064 @high equ 100 34: 000A @dsply equ 10 35: 0065 @flags equ 101 36: 000C @logot equ 12 37: 0052 @gtdcb equ 82 38: 0053 @gtmod equ 83 39: 0009 @keyin equ 9 40: 0011 @param equ 17 41: 0078 @mouse equ 120 ;unofficial value 42: 43: 01F0 svcvec equ 100h + 2*@mouse 44: 45: ; xtrs emts (byte-reversed) 46: 29ED emt_mouse equ 029edh 47: 48: 3000 org 3000h 49: ;*=*=* 50: ; Relocator for disk driver 51: ;*=*=* 52: 3000 116B31 instal: ld de,prmtab 53: 3003 3E11 ld a,@param ;Parse parameters 54: 3005 EF rst 40 55: 3006 C29530 jp nz,prmerr 56: 3009 21D230 ld hl,hello_ 57: 300C 3E0A ld a,@dsply ;Display hello 58: 300E EF rst 40 59: ;*=*=* 60: ; Check if driver already loaded 61: ;*=*=* 62: 300F 118131 ld de,modnam 63: 3012 3E53 ld a,@gtmod 64: 3014 EF rst 40 65: 3015 CA9930 jp z,loaded ;Already loaded 66: ;*=*=* 67: ; Check if OK to use low memory. 68: ;*=*=* 69: 3018 010000 lparm: ld bc,0 70: 301B 78 ld a,b 71: 301C B1 or c 72: 301D 2828 jr z,usehi 73: ;*=*=* 74: ; Obtain low memory driver pointer. Bizarre API here! 75: ;*=*=* 76: 301F 1E4B ld e,'K' ;Locate pointer to *KI DCB 77: 3021 1649 ld d,'I' ; via @GTDCB SVC 78: 3023 3E52 ld a,@gtdcb 79: 3025 EF rst 40 80: 3026 C29D30 jp nz,curdl ;No error unless KI clobbered! 81: 3029 2B dec hl ;Decrement to driver pointer 82: 302A 56 ld d,(hl) ;P/u hi-order of pointer, 83: 302B 2B dec hl ; decrement to and p/u 84: 302C 5E ld e,(hl) ; lo-order of pointer 85: ;*=*=* 86: ; Check if driver will fit into [(LCPTR), X'12FF'] 87: ;*=*=* 88: 302D E5 push hl ;Save address of pointer 89: 302E 211F00 ld hl,length ;New pointer will be 90: 3031 19 add hl,de ; pointer + LENGTH 91: 3032 54 ld d,h ;Save a copy in DE 92: 3033 5D ld e,l 93: 3034 010113 ld bc,1301h ;If > 1300H, driver won't fit 94: 3037 97 sub a ;Reset carry flag 95: 3038 ED42 sbc hl,bc 96: 303A E1 pop hl ;Get back address of pointer 97: 303B 300A jr nc,usehi ;Go if driver won't fit 98: 303D 73 ld (hl),e ;Store new value of pointer 99: 303E 23 inc hl 100: 303F 72 ld (hl),d 101: 3040 1B dec de ;Last byte of driver goes here 102: 3041 ED536931 ld (newend),de 103: 3045 1816 jr dorelo 104: ;*=*=* 105: ; Put in high memory instead. 106: ;*=*=* 107: 3047 210000 usehi: ld hl,0 ;Get current HIGH$ 108: 304A 45 ld b,l 109: 304B 3E64 ld a,@high 110: 304D EF rst 40 111: 304E C2A130 jp nz,nomem 112: 3051 226931 ld (newend),hl ;Last byte of driver goes here 113: 3054 111F00 ld de,length 114: 3057 97 sub a ;Reset carry flag 115: 3058 ED52 sbc hl,de ;Compute new HIGH$ 116: 305A 3E64 ld a,@high ;Set new HIGH$ into the system 117: 305C EF rst 40 118: ;*=*=* 119: ; Relocate internal references in driver. 120: ; HL = address for last byte of driver. 121: ;*=*=* 122: 305D CDAB30 dorelo: call relo 123: ;*=*=* 124: ; Link to @ICNFG (must follow address relocation and precede movement) 125: ;*=*=* 126: 3060 3E65 ld a,@flags ;Get flags pointer into IY 127: 3062 EF rst 40 128: 3063 FD7E1C ld a,(iy+28) ;Copy current @ICNFG into LINK 129: 3066 FD6E1D ld l,(iy+29) 130: 3069 FD661E ld h,(iy+30) 131: 306C 329131 ld (link),a 132: 306F 229231 ld (link+1),hl 133: 3072 218E31 ld hl,dvrcfg ;Get relocated init address 134: 3073 rx01 equ $-2 135: 3075 FD751D ld (iy+29),l ;Save in @ICNFG vector 136: 3078 FD741E ld (iy+30),h 137: 307B FD361CC3 ld (iy+28),0c3h ;Insert JP opcode 138: ;*=*=* 139: ; Move driver into low or high memory. 140: ;*=*=* 141: 307F move: 142: 307F ED5B6931 ld de,(newend) ;Destination address 143: 3083 219A31 ld hl,dvrend ;Last byte of module 144: 3086 011F00 ld bc,length ;Length of filter 145: 3089 EDB8 lddr 146: 308B EB ex de,hl 147: 308C 23 inc hl ;Bump to driver entry 148: ;*=*=* 149: ; Driver is loaded; finish up. 150: ;*=*=* 151: 308D CD9431 call dvrini ;Hook into SVC table 152: 153: 3090 210000 ld hl,0 ;Successful completion 154: 3093 97 sub a 155: 3094 C9 ret 156: 157: ;*=*=* 158: ; Error vectors 159: ;*=*=* 160: 3095 215731 prmerr: ld hl,prmerr_ 161: 3098 DD defb 0ddh 162: 3099 213731 loaded: ld hl,loaded_ 163: 309C DD defb 0ddh 164: 309D 210631 curdl: ld hl,curdl_ 165: 30A0 DD defb 0ddh 166: 30A1 211931 nomem: ld hl,nomem_ 167: 30A4 3E0C logot: ld a,@logot 168: 30A6 EF rst 40 169: 30A7 21FFFF ld hl,-1 ;Unuccessful completion 170: 30AA C9 ret 171: 172: ;*=*=* 173: ; Relocate internal references in driver. 174: ; HL = address for last byte of driver. 175: ;*=*=* 176: 30AB 2A6931 relo: ld hl,(newend) 177: 30AE FD219B31 ld iy,reltab ;Point to relocation tbl 178: 30B2 119A31 ld de,dvrend 179: 30B5 97 sub a ;Clear carry flag 180: 30B6 ED52 sbc hl,de 181: 30B8 44 ld b,h ;Move to BC 182: 30B9 4D ld c,l 183: 30BA FD6E00 rloop: ld l,(iy) ;Get address to change 184: 30BD FD6601 ld h,(iy+1) 185: 30C0 7C ld a,h 186: 30C1 B5 or l 187: 30C2 C8 ret z 188: 30C3 5E ld e,(hl) ;P/U address 189: 30C4 23 inc hl 190: 30C5 56 ld d,(hl) 191: 30C6 EB ex de,hl ;Offset it 192: 30C7 09 add hl,bc 193: 30C8 EB ex de,hl 194: 30C9 72 ld (hl),d ;And put back 195: 30CA 2B dec hl 196: 30CB 73 ld (hl),e 197: 30CC FD23 inc iy 198: 30CE FD23 inc iy 199: 30D0 18E8 jr rloop ;Loop till done 200: 201: ;*=*=* 202: ; Messages and globals 203: ;*=*=* 204: 30D2 58545253 hello_: defb 'XTRSMOUS - Emulated mouse driver for xtrs - 9/28/98',CR 4D4F5553 202D2045 6D756C61 74656420 6D6F7573 65206472 69766572 20666F72 20787472 73202D20 392F3238 2F39380D 205: 3106 4C532D44 curdl_: defb 'LS-DOS is curdled!',CR 4F532069 73206375 72646C65 64210D 206: 3119 48696768 nomem_: defb 'High memory is not available!',CR 206D656D 6F727920 6973206E 6F742061 7661696C 61626C65 210D 207: 3137 4D6F7573 loaded_:defb 'Mouse driver is already loaded!',CR 65206472 69766572 20697320 616C7265 61647920 6C6F6164 6564210D 208: 3157 42616420 prmerr_:defb 'Bad parameters!',CR 70617261 6D657465 7273210D 209: 3167 0000 lcptr: defw 0 210: 3169 0000 newend: defw 0 211: 212: ;*=*=* 213: ; Parameter table 214: ;*=*=* 215: 316B 4C4F5720 prmtab: defb 'LOW ' 2020 216: 3171 1930 defw lparm+1 217: 3173 4C202020 defb 'L ' 2020 218: 3179 1930 defw lparm+1 219: 317B 00 defb 0 220: 221: ;*=*=* 222: ; Driver 223: ;*=*=* 224: 317C 180D entry: jr begin ;The driver starts with the 225: 317E 9A31 defw dvrend ; DOS standard header 226: 317E rx00 equ $-2 227: 3180 06 defb modptr-modnam ;Length of name 228: 3181 244D4F55 modnam: defb '$MOUSE' ;Name for @GTMOD requests 5345 229: 3187 0000 modptr: defw 0 ;These pointers are unused, but 1st byte MBZ 230: 3189 0000 defw 0 231: ;*=*=* 232: ; Do the real work using an emulator trap 233: ;*=*=* 234: 318B ED29 begin: defw emt_mouse 235: 318D C9 ret 236: ;*=*=* 237: ; Boot-time initialization 238: ;*=*=* 239: 318E dvrcfg: ;@ICNFG chains in here 240: 318E CD9431 call dvrini 241: 318F rx02 equ $-2 242: 3191 54696D link: defb 'Tim' ;Replaced by next link in @ICNFG chain 243: ;*=*=* 244: ; Hook into SVC table 245: ;*=*=* 246: 3194 217C31 dvrini: ld hl,entry 247: 3195 rx03 equ $-2 248: 3197 22F001 ld (svcvec),hl 249: 319A C9 ret 250: 251: 319A dvrend equ $-1 252: 001F length equ $-entry 253: 319B 7E317330 reltab: defw rx00,rx01,rx02,rx03,0 8F319531 0000 254: 3000 end instal Statistics: 48 symbols 421 bytes Symbol Table: @dsply = a emt_mouse =29ed nomem 30a1 @flags = 65 entry 317c nomem_ 3119 @gtdcb = 52 etx = 3+ prmerr 3095 @gtmod = 53 hello_ 30d2 prmerr_ 3157 @high = 64 instal 3000 prmtab 316b @keyin = 9+ lcptr 3167+ relo 30ab @logot = c length = 1f reltab 319b @mouse = 78 lf = a+ rloop 30ba @param = 11 link 3191 rx00 =317e begin 318b loaded 3099 rx01 =3073 cr = d loaded_ 3137 rx02 =318f curdl 309d logot 30a4+ rx03 =3195 curdl_ 3106 lparm 3018 svcvec = 1f0 dorelo 305d modnam 3181 usehi 3047 dvrcfg 318e modptr 3187 dvrend =319a move 307f+ dvrini 3194 newend 3169 xtrs-4.9d/xtrsmous.z80000066400000000000000000000140731306603614600150130ustar00rootroot00000000000000;*=*=* ; xtrsmous/cmd ; LS-DOS driver for xtrs emulation of mouse ; ; Copyright (c) 1998, Timothy Mann ; $Id: xtrsmous.z80,v 1.2 2008/06/26 04:39:56 mann Exp $ ; ; This software may be copied, modified, and used for any ; purpose without fee, provided that (1) the above copyright ; notice is retained, and (2) modified versions are clearly ; marked as having been modified, with the modifier's name and ; the date included. ; ; Usage: ; xtrsmous To load driver in high memory. ; xtrsmous (low) To load driver in low memory if possible, ; or in high memory if low memory is full. ; ; The default is to use high memory because MDRAW/BAS contains a ; PEEK in the first line of code that looks for the driver in ; high memory; if it is in low memory, MDRAW thinks the driver ; is not installed and exits. If you edit this line of code to ; remove the test, the driver will work fine in low memory. ;*=*=* ; ASCII chars LF equ 10 CR equ 13 ETX equ 3 ; Model 4 SVC numbers @high equ 100 @dsply equ 10 @flags equ 101 @logot equ 12 @gtdcb equ 82 @gtmod equ 83 @keyin equ 9 @param equ 17 @mouse equ 120 ;unofficial value svcvec equ 100h + 2*@mouse ; xtrs emts (byte-reversed) emt_mouse equ 029edh org 3000h ;*=*=* ; Relocator for disk driver ;*=*=* instal: ld de,prmtab ld a,@param ;Parse parameters rst 40 jp nz,prmerr ld hl,hello_ ld a,@dsply ;Display hello rst 40 ;*=*=* ; Check if driver already loaded ;*=*=* ld de,modnam ld a,@gtmod rst 40 jp z,loaded ;Already loaded ;*=*=* ; Check if OK to use low memory. ;*=*=* lparm: ld bc,0 ld a,b or c jr z,usehi ;*=*=* ; Obtain low memory driver pointer. Bizarre API here! ;*=*=* ld e,'K' ;Locate pointer to *KI DCB ld d,'I' ; via @GTDCB SVC ld a,@gtdcb rst 40 jp nz,curdl ;No error unless KI clobbered! dec hl ;Decrement to driver pointer ld d,(hl) ;P/u hi-order of pointer, dec hl ; decrement to and p/u ld e,(hl) ; lo-order of pointer ;*=*=* ; Check if driver will fit into [(LCPTR), X'12FF'] ;*=*=* push hl ;Save address of pointer ld hl,length ;New pointer will be add hl,de ; pointer + LENGTH ld d,h ;Save a copy in DE ld e,l ld bc,1301h ;If > 1300H, driver won't fit sub a ;Reset carry flag sbc hl,bc pop hl ;Get back address of pointer jr nc,usehi ;Go if driver won't fit ld (hl),e ;Store new value of pointer inc hl ld (hl),d dec de ;Last byte of driver goes here ld (newend),de jr dorelo ;*=*=* ; Put in high memory instead. ;*=*=* usehi: ld hl,0 ;Get current HIGH$ ld b,l ld a,@high rst 40 jp nz,nomem ld (newend),hl ;Last byte of driver goes here ld de,length sub a ;Reset carry flag sbc hl,de ;Compute new HIGH$ ld a,@high ;Set new HIGH$ into the system rst 40 ;*=*=* ; Relocate internal references in driver. ; HL = address for last byte of driver. ;*=*=* dorelo: call relo ;*=*=* ; Link to @ICNFG (must follow address relocation and precede movement) ;*=*=* ld a,@flags ;Get flags pointer into IY rst 40 ld a,(iy+28) ;Copy current @ICNFG into LINK ld l,(iy+29) ld h,(iy+30) ld (link),a ld (link+1),hl ld hl,dvrcfg ;Get relocated init address rx01 equ $-2 ld (iy+29),l ;Save in @ICNFG vector ld (iy+30),h ld (iy+28),0c3h ;Insert JP opcode ;*=*=* ; Move driver into low or high memory. ;*=*=* move: ld de,(newend) ;Destination address ld hl,dvrend ;Last byte of module ld bc,length ;Length of filter lddr ex de,hl inc hl ;Bump to driver entry ;*=*=* ; Driver is loaded; finish up. ;*=*=* call dvrini ;Hook into SVC table ld hl,0 ;Successful completion sub a ret ;*=*=* ; Error vectors ;*=*=* prmerr: ld hl,prmerr_ defb 0ddh loaded: ld hl,loaded_ defb 0ddh curdl: ld hl,curdl_ defb 0ddh nomem: ld hl,nomem_ logot: ld a,@logot rst 40 ld hl,-1 ;Unuccessful completion ret ;*=*=* ; Relocate internal references in driver. ; HL = address for last byte of driver. ;*=*=* relo: ld hl,(newend) ld iy,reltab ;Point to relocation tbl ld de,dvrend sub a ;Clear carry flag sbc hl,de ld b,h ;Move to BC ld c,l rloop: ld l,(iy) ;Get address to change ld h,(iy+1) ld a,h or l ret z ld e,(hl) ;P/U address inc hl ld d,(hl) ex de,hl ;Offset it add hl,bc ex de,hl ld (hl),d ;And put back dec hl ld (hl),e inc iy inc iy jr rloop ;Loop till done ;*=*=* ; Messages and globals ;*=*=* hello_: defb 'XTRSMOUS - Emulated mouse driver for xtrs - 9/28/98',CR curdl_: defb 'LS-DOS is curdled!',CR nomem_: defb 'High memory is not available!',CR loaded_:defb 'Mouse driver is already loaded!',CR prmerr_:defb 'Bad parameters!',CR lcptr: defw 0 newend: defw 0 ;*=*=* ; Parameter table ;*=*=* prmtab: defb 'LOW ' defw lparm+1 defb 'L ' defw lparm+1 defb 0 ;*=*=* ; Driver ;*=*=* entry: jr begin ;The driver starts with the defw dvrend ; DOS standard header rx00 equ $-2 defb modptr-modnam ;Length of name modnam: defb '$MOUSE' ;Name for @GTMOD requests modptr: defw 0 ;These pointers are unused, but 1st byte MBZ defw 0 ;*=*=* ; Do the real work using an emulator trap ;*=*=* begin: defw emt_mouse ret ;*=*=* ; Boot-time initialization ;*=*=* dvrcfg: ;@ICNFG chains in here call dvrini rx02 equ $-2 link: defb 'Tim' ;Replaced by next link in @ICNFG chain ;*=*=* ; Hook into SVC table ;*=*=* dvrini: ld hl,entry rx03 equ $-2 ld (svcvec),hl ret dvrend equ $-1 length equ $-entry reltab: defw rx00,rx01,rx02,rx03,0 end instal xtrs-4.9d/xtrsrom4p.README000066400000000000000000000060731306603614600154060ustar00rootroot00000000000000Free Model 4P mode boot ROM for xtrs - Version 0.02 Copyright 1999, Peter W. Cervasio (cervasio@airmail.net) Modified by Tim Mann to create version 0.05, 4-4-99 This software may be copied, modified, and used for any purpose without fee, provided that (1) the above copyright notice is retained, and (2) modified versions are clearly marked as having been modified, with the modifier's name and the date included. This is a freely available Model 4P mode boot ROM which can be used with Tim Mann's version of xtrs in order to boot up LS-DOS 6.3.1. This code was written with the help of the LS-DOS 6.3.1 source code, which Roy Soltoff has allowed everyone to download and freely distribute (though he retains the copyright). The Model 4/4P technical reference manual proved invaluable, as well, even if I didn't make this do everything. The code was tested with xtrs 3.3 on Linux 2.2.2 using an LS-DOS 6.3.1 disk image. I got it to the point where xtrs would boot up LS-DOS 6.3.1 and would reboot it when pressing F10 or typing "boot" at the LS-DOS command line. It is only useful for the Model 4P mode of operation, and it might not work for all operating systems. The ROM does not contain any code to access any sector other than track 0, sector 1. It will not boot a Model III operating system, and is unable to load in a "MODELA/III" ROM image from disk, like the real Model 4P ROM does. This ROM will not work in plain Model 4 mode. If you want to use Model 4 mode, boot LS-DOS 6.3.1, export the MODELA/III file to Unix, and set it up as a Model 3 and 4 ROM. Features: ========= Small and simple (and easy to fix). To do: ====== Write code for all the RST handlers as in the real 4P ROM, which would allow xtrs to boot a Model III disk when in Model 4P mode. This would require considerable work, and isn't planned for any time in the forseeable future. Any questions? ============== Here's my list of IEQ's (Infreqently Expected Questions) about the xtrsrom4p rom image: 1) Does xtrsrom4p handle the special keypresses the 4P uses at boot up time, such as F1, F2 and F3 to modify the boot sequence? Sorry, but it doesn't look at the keyboard. See the answer to #2. 2) Will it load MODELA/III from disk so I can boot LDOS/TRSDOS 1.3 or NewDos/80 for the Model III? Sorry. You're welcome to write the code for it, though. 3) Can I use it to boot from from a hard disk image? Um.... no. See the answer to #2. 4) How about Network 4? Uh... no, it won't do that either. Also see #2's answer. 5) What about booting from RS-232? See #2 again. 6) How about the diagnostics? What diagnostics? Oh, those diagnostics. See the answer to #2. Along with not doing any of that other stuff, it also doesn't follow the technical reference as far as RST handlers go, so if you have a custom 4P setup that uses the RST instructions, that's not going to work without some additional code. I wrote this so people could get something up and running with what's in the xtrs distribution. From there, you can export a MODELA/III image from a disk (or disk image) to use in booting up Model III mode. xtrs-4.9d/xtrsrom4p.hex000066400000000000000000000025461306603614600152360ustar00rootroot00000000000000:10000000F33E01D39CC36900C30040000000000020 :10001000C303400000000000C306400000000000D1 :10002000C309400000000000C30C400000000000B5 :10003000C30F400000000000C31240C90000C90007 :1000400000C90000C90000C90000C90000C90000C3 :0B005000C32C014D4FAFD39CC30043F5 :10006600C31540AFD3E43E01D3843E50D3EC3100F8 :1000760042213B00110040012000EDB021003C115F :10008600013C01FF033620EDB0ED56CDA000CDD4E6 :1000960000CCEB00C2B900C31A403E05ED3C7DFE24 :1000A60005C8F521490111C03D013100EDB0C6304A :1000B6001218FE217A01371F3804232318F95E230C :1000C60056EB11C03D7EA728FE12231318F73E817A :1000D600D3F43ED0CD3901060010FE3E0CCD3901D9 :1000E600E699C818CE110100210043CDFA00E61C9E :1000F600C8C3B90006810EF4ED410D3E18ED51CD91 :1001060039017BD3F23E81D3F41116813E80D3F0C0 :10011600066410FE3EC0D3E4DBF0A328FBEDA27A12 :10012600D3F4EDA218FAAFD3E43E81D3F4DBF0E3C7 :10013600E1ED45D3F0066410FEDBF0CB47C8CB7F7C :10014600C018F65468697320524F4D20636F64657A :1001560020646F6573204E4F5420776F726B207743 :1001660068656E20656D756C6174696E67204D6F8C :1001760064656C20D4018C018C01A001B6018C0150 :100186008C01D4018C01456D756C61746F72206FA2 :100196007220524F4D2062756700426F6F74207354 :1001A6006563746F7220435243206572726F7200EA :1001B600426F6F7420736563746F72206E6F742064 :1001C600666F756E64206F6E206469736B00596F7D :1001D6007520646F206E6F742068617665206120DB :1001E6006469736B20696D616765206C6F61646516 :0201F6006400A3 :00000001FF xtrs-4.9d/xtrsrom4p.lst000066400000000000000000000322621306603614600152520ustar00rootroot00000000000000 1: ;------------------------------------------------------------------ 2: ; Free Model 4P mode boot ROM for xtrs - Version 0.05 3: ; Copyright 1999, Peter W. Cervasio (cervasio@airmail.net) 4: ;------------------------------------------------------------------ 5: ; This software may be copied, modified, and used for any purpose 6: ; without fee, provided that (1) the above copyright notice is 7: ; retained, and (2) modified versions are clearly marked as having 8: ; been modified, with the modifier's name and the date included. 9: ;------------------------------------------------------------------ 10: ; Checks to see if a disk image is loaded in emulated drive 0. If 11: ; so, it reads the boot sector to 0x4300 and jumps to that address. 12: ; If no disk image loaded, complains and sits in a loop. 13: ; 14: ; This is only useful for the Model 4P mode of operation, and it 15: ; might not work for all programs. Complains if xtrs thinks it's 16: ; in model 1, 3, or 4 mode. 17: ; 18: ; Written with the help of the LS-DOS 6.3.1 source code, which is 19: ; freely avaliable, though Roy Soltoff holds the copyright to it, 20: ; and the Model 4/4P technical reference. 21: ; 22: ; $Id: xtrsrom4p.z80,v 1.8 2008/06/26 04:39:56 mann Exp $ 23: ; 24: ; 3-19-99, Tim Mann: Improved disk error handling. Ruled out 25: ; attempts to work in plain Model 4 mode. (v0.03) 26: ; 4-4-99, Tim Mann: Made read loop continue until NMI instead of 27: ; counting 256 bytes; this should let boot sectors of other than 28: ; 256 bytes work. (v0.04) Fixed bug in sending fdc read command; 29: ; don't use fdcmd, since that waits for completion. (v0.05) 30: ; 31: ; TODO: 32: ; possibly write code for the RST handlers as in the real 4P rom 33: ;------------------------------------------------------------------ 34: 35: ; 36: ; misc equates needed 37: ; 38: 3DC0 video equ 3c00h+7*64 39: 4300 bootram equ 4300h ; load to this address 40: 401A goboot equ 401ah ; jump here to run boot sec! 41: ; 42: ; hardware addresses 43: ; 44: 0084 opreg equ 084h ; Operation control 45: 009C romport equ 09ch ; ROM control 46: 00E4 wrnmiport equ 0e4h ; NMI mask register 47: 00EC modport equ 0ech ; speed, etc. 48: ; 49: 00F0 fdccmnd equ 0f0h ; FDC Command register (write) 50: 00F0 fdcstat equ 0f0h ; FDC Status register (read) 51: 00F1 fdctrak equ 0f1h ; FDC Track register (r/w) 52: 00F2 fdcsect equ 0f2h ; FDC Sector register (r/w) 53: 00F3 fdcdata equ 0f3h ; FDC Data register (r/w) 54: 00F4 fdcslct equ 0f4h ; Drive select, SDEN/DDEN, 55: 56: 0000 org 0 57: 58: ; The following three instructions are what you would 59: ; have in RAM at address 0, which would set up the 60: ; Model 4/4P to turn the ROM back on (lsdos does this) 61: ; 62: 0000 F3 start: di ; disable interrupts 63: 0001 3E01 ld a,1 ; map in the ROM 64: 0003 D39C out (romport),a ; do it! 65: ; 66: ; start of "real" ROM instructions 67: ; 68: 0005 C36900 jp contin ; continue farther up 69: ; 70: ; rst 08h through rst 38h jumps (per tech ref) 71: ; 72: 0008 C30040 rst8: jp 4000h 73: 000B 00000000 db 0,0,0,0,0 00 74: 0010 C30340 rst10: jp 4003h 75: 0013 00000000 db 0,0,0,0,0 00 76: 0018 C30640 rst18: jp 4006h 77: 001B 00000000 db 0,0,0,0,0 00 78: 0020 C30940 rst20: jp 4009h 79: 0023 00000000 db 0,0,0,0,0 00 80: 0028 C30C40 rst28: jp 400ch 81: 002B 00000000 db 0,0,0,0,0 00 82: 0030 C30F40 rst30: jp 400fh 83: 0033 00000000 db 0,0,0,0,0 00 84: 0038 C31240 rst38: jp 4012h 85: ; 86: ; Data to load from 4000h to ?? 87: ; 88: 003B C9 retdat: ret ; 4000h (rst 8h) 89: 003C 0000 dw 0 90: 003E C9 ret ; 4003h (rst 10h) 91: 003F 0000 dw 0 92: 0041 C9 ret ; 4006h (rst 18h) 93: 0042 0000 dw 0 94: 0044 C9 ret ; 4009h (rst 20h) 95: 0045 0000 dw 0 96: 0047 C9 ret ; 400ch (rst 28h) 97: 0048 0000 dw 0 98: 004A C9 ret ; 400fh (rst 30h) 99: 004B 0000 dw 0 100: 004D C9 ret ; 4012h (rst 38h) 101: 004E 0000 dw 0 102: 0050 C32C01 jp nmiret ; 4015h (nmi) 103: ; 104: 0053 4D4F db 'MO' ; 4P detect by sysinit 105: ; 106: ; code that jumps to the boot sector (401ah) 107: ; 108: 0055 AF xor a 109: 0056 D39C out (romport),a ; disable rom 110: 0058 C30043 jp bootram ; run boot sector 111: ; 112: 0020 retlen equ $-retdat ; size of code 113: ; 114: ; nmi address 115: ; 116: 0066 org 66h 117: ; 118: 0066 C31540 jp 4015h ; std M4 point in RAM 119: ; 120: ; continue booting the machine 121: ; 122: 0069 AF contin: xor a 123: 006A D3E4 out (wrnmiport),a ; disable interrupts 124: 006C 3E01 ld a,1 125: 006E D384 out (opreg),a ; set ram mode 126: 0070 3E50 ld a,01010000b 127: 0072 D3EC out (modport),a ; set speed/vid 128: ; 129: 0074 310042 ld sp,bootram-100h ; set stack pointer 130: ; 131: 0077 213B00 ld hl,retdat ; code for RAM 132: 007A 110040 ld de,4000h ; move it here 133: 007D 012000 ld bc,retlen 134: 0080 EDB0 ldir 135: ; 136: 0082 21003C ld hl,3c00h ; clear video screen 137: 0085 11013C ld de,3c01h 138: 0088 01FF03 ld bc,1023 139: 008B 3620 ld (hl),' ' 140: 008D EDB0 ldir 141: ; 142: 008F ED56 im 1 143: ; 144: 0091 CDA000 call chkmdl ; check for model 4p 145: 0094 CDD400 call rstdrv ; restore drive 146: 0097 CCEB00 call z,readbt ; read boot sector 147: 009A C2B900 jp nz,dskerr ; go on error 148: ; 149: 009D C31A40 jmprom: jp goboot ; jump to boot sector 150: ; 151: ; chkmdl - make sure we're in 4P mode 152: ; 153: 00A0 3E05 chkmdl: ld a,5 ; model query 154: 00A2 ED3C dw 3cedh ; emt_misc instr. 155: 00A4 7D ld a,l ; get model in a 156: 00A5 FE05 cp 5 ; model 4p? 157: 00A7 C8 ret z 158: ; 159: ; romerr - rom installed in model 1, 3, or 4 mode!! 160: ; 161: 00A8 F5 romerr: push af 162: 00A9 214901 ld hl,rommsg ; "invalid rom for model" 163: 00AC 11C03D ld de,video 164: 00AF 013100 ld bc,romlen 165: 00B2 EDB0 ldir ; put msg 166: 00B4 C630 add a,'0' ; convert model to ascii 167: 00B6 12 ld (de),a ; stuff onto screen 168: 00B7 18FE jr $ ; and hang 169: ; 170: ; dskerr - error reading disk 171: ; 172: 00B9 217A01 dskerr: ld hl,errtab ; table of error messages 173: 00BC 37 scf ; ensure termination 174: 00BD 1F nxterr: rra ; loop through bits, low first 175: 00BE 3804 jr c,goterr ; go if error bit found 176: 00C0 23 inc hl ; no, step to next message 177: 00C1 23 inc hl 178: 00C2 18F9 jr nxterr 179: 00C4 5E goterr: ld e,(hl) ; get message address 180: 00C5 23 inc hl 181: 00C6 56 ld d,(hl) 182: 00C7 EB ex de,hl 183: 00C8 11C03D ld de,video ; where to show it 184: 00CB 7E chrout: ld a,(hl) 185: 00CC A7 and a 186: 00CD 28FE jr z,$ ; hang in a loop when done 187: 00CF 12 ld (de),a 188: 00D0 23 inc hl 189: 00D1 13 inc de 190: 00D2 18F7 jr chrout 191: ; 192: ; rstdrv - seek track 0 and set up for boot read 193: ; 194: 00D4 3E81 rstdrv: ld a,81h ; drive 0, dden (no nmi) 195: 00D6 D3F4 out (fdcslct),a ; select drive 196: 00D8 3ED0 ld a,0d0h ; force interrupt 197: 00DA CD3901 call fdcmd ; send to fdc 198: 00DD 0600 ld b,0 199: 00DF 10FE djnz $ ; wait a bit 200: 00E1 3E0C ld a,0ch ; restore w/verify 201: 00E3 CD3901 call fdcmd ; 202: 00E6 E699 and 99h ; mask error bits 203: 00E8 C8 ret z ; return if okay 204: 00E9 18CE jr dskerr 205: ; 206: ; readbt - read boot sector from drive 0 207: ; 208: 00EB 110100 readbt: ld de,0001h ; trk 0, sec 1 209: 00EE 210043 ld hl,bootram ; set buffer 210: 00F1 CDFA00 call readsb ; attempt read 211: 00F4 E61C and 1ch ; keep RNF,CRC,LOST DATA 212: 00F6 C8 ret z ; return if no error 213: 00F7 C3B900 jp dskerr ; go on error 214: ; 215: ; readsb - read sector to buffer 216: ; 217: 00FA 0681 readsb: ld b,81h 218: 00FC 0EF4 ld c,fdcslct ; set dden,ds0 219: 00FE ED41 out (c),b ; select 220: 0100 0D dec c ; set to data register 221: 0101 3E18 ld a,18h ; fdc seek command 222: 0103 ED51 out (c),d ; track # to fdc 223: 0105 CD3901 call fdcmd ; send command to fdc 224: 0108 7B ld a,e 225: 0109 D3F2 out (fdcsect),a ; desired sector 226: 010B 3E81 ld a,81h ; dden & ds0 227: 010D D3F4 out (fdcslct),a ; reselect drive 228: 010F 111681 ld de,08116h ; D=DS0, dden, wait 229: ; E=mask to see DRQ or error 230: 0112 3E80 ld a,80h ; fdc read command 231: 0114 D3F0 out (fdccmnd),a ; send command 232: 0116 0664 ld b,100 ; short delay 233: 0118 10FE djnz $ 234: 011A 3EC0 ld a,0c0h ; enable intrq 235: 011C D3E4 out (wrnmiport),a 236: 011E DBF0 rdlp1: in a,(fdcstat) ; get status 237: 0120 A3 and e ; test bit 1 238: 0121 28FB jr z,rdlp1 239: 0123 EDA2 ini 240: 0125 7A ld a,d 241: 0126 D3F4 rdlp2: out (fdcslct),a 242: 0128 EDA2 ini 243: 012A 18FA jr rdlp2 ; tight loop waiting for NMI 244: ; jr nz,rdlp2 245: ; in a,(fdcstat) 246: ; ret 247: 248: 012C AF nmiret: xor a 249: 012D D3E4 out (wrnmiport),a ; no interrupts 250: 012F 3E81 ld a,81h ; DS 0, dden 251: 0131 D3F4 out (fdcslct),a 252: 0133 DBF0 in a,(fdcstat) 253: 0135 E3 ex (sp),hl ; discard one level of return address 254: 0136 E1 pop hl 255: 0137 ED45 retn 256: 257: ; 258: ; fdcmd - send command in A to fdc and wait for completion 259: ; 260: 0139 D3F0 fdcmd: out (fdccmnd),a ; send command 261: 013B 0664 ld b,100 ; short delay 262: 013D 10FE djnz $ 263: 013F DBF0 fdst: in a,(fdcstat) 264: 0141 CB47 bit 0,a ; busy? 265: 0143 C8 ret z ; return if not 266: 0144 CB7F bit 7,a ; not ready? 267: 0146 C0 ret nz ; return if set 268: 0147 18F6 jr fdst ; else loop 269: 270: 271: ;------------------------------------------------------------------ 272: ; messages 273: ;------------------------------------------------------------------ 274: ; 275: 0149 54686973 rommsg: db 'This ROM code does NOT work when emulating Model ' 20524F4D 20636F64 6520646F 6573204E 4F542077 6F726B20 7768656E 20656D75 6C617469 6E67204D 6F64656C 20 276: 0031 romlen equ $-rommsg 277: ; 278: 017A D4018C01 errtab: dw dskmsg,ecant,elost,ecrc,ernf,ecant,ecant,dskmsg,ecant 8C01A001 B6018C01 8C01D401 8C01 279: 018C elost: 280: 018C 456D756C ecant: db 'Emulator or ROM bug',0 61746F72 206F7220 524F4D20 62756700 281: 01A0 426F6F74 ecrc: db 'Boot sector CRC error',0 20736563 746F7220 43524320 6572726F 7200 282: 01B6 426F6F74 ernf: db 'Boot sector not found on disk',0 20736563 746F7220 6E6F7420 666F756E 64206F6E 20646973 6B00 283: 01D4 596F7520 dskmsg: db 'You do not have a disk image loaded',0 646F206E 6F742068 61766520 61206469 736B2069 6D616765 206C6F61 64656400 284: ; 285: 0000 end start Statistics: 47 symbols 493 bytes Symbol Table: bootram =4300 fdcstat = f0 romerr a8+ chkmdl a0 fdctrak = f1+ romlen = 31 chrout cb fdst 13f rommsg 149 contin 69 goboot =401a romport = 9c dskerr b9 goterr c4 rst10 10+ dskmsg 1d4 jmprom 9d+ rst18 18+ ecant 18c modport = ec rst20 20+ ecrc 1a0 nmiret 12c rst28 28+ elost 18c nxterr bd rst30 30+ ernf 1b6 opreg = 84 rst38 38+ errtab 17a rdlp1 11e rst8 8+ fdccmnd = f0 rdlp2 126 rstdrv d4 fdcdata = f3+ readbt eb start 0 fdcmd 139 readsb fa video =3dc0 fdcsect = f2 retdat 3b wrnmiport = e4 fdcslct = f4 retlen = 20 xtrs-4.9d/xtrsrom4p.z80000066400000000000000000000155131306603614600150710ustar00rootroot00000000000000;------------------------------------------------------------------ ; Free Model 4P mode boot ROM for xtrs - Version 0.05 ; Copyright 1999, Peter W. Cervasio (cervasio@airmail.net) ;------------------------------------------------------------------ ; This software may be copied, modified, and used for any purpose ; without fee, provided that (1) the above copyright notice is ; retained, and (2) modified versions are clearly marked as having ; been modified, with the modifier's name and the date included. ;------------------------------------------------------------------ ; Checks to see if a disk image is loaded in emulated drive 0. If ; so, it reads the boot sector to 0x4300 and jumps to that address. ; If no disk image loaded, complains and sits in a loop. ; ; This is only useful for the Model 4P mode of operation, and it ; might not work for all programs. Complains if xtrs thinks it's ; in model 1, 3, or 4 mode. ; ; Written with the help of the LS-DOS 6.3.1 source code, which is ; freely avaliable, though Roy Soltoff holds the copyright to it, ; and the Model 4/4P technical reference. ; ; $Id: xtrsrom4p.z80,v 1.8 2008/06/26 04:39:56 mann Exp $ ; ; 3-19-99, Tim Mann: Improved disk error handling. Ruled out ; attempts to work in plain Model 4 mode. (v0.03) ; 4-4-99, Tim Mann: Made read loop continue until NMI instead of ; counting 256 bytes; this should let boot sectors of other than ; 256 bytes work. (v0.04) Fixed bug in sending fdc read command; ; don't use fdcmd, since that waits for completion. (v0.05) ; ; TODO: ; possibly write code for the RST handlers as in the real 4P rom ;------------------------------------------------------------------ ; ; misc equates needed ; video equ 3c00h+7*64 bootram equ 4300h ; load to this address goboot equ 401ah ; jump here to run boot sec! ; ; hardware addresses ; opreg equ 084h ; Operation control romport equ 09ch ; ROM control wrnmiport equ 0e4h ; NMI mask register modport equ 0ech ; speed, etc. ; fdccmnd equ 0f0h ; FDC Command register (write) fdcstat equ 0f0h ; FDC Status register (read) fdctrak equ 0f1h ; FDC Track register (r/w) fdcsect equ 0f2h ; FDC Sector register (r/w) fdcdata equ 0f3h ; FDC Data register (r/w) fdcslct equ 0f4h ; Drive select, SDEN/DDEN, org 0 ; The following three instructions are what you would ; have in RAM at address 0, which would set up the ; Model 4/4P to turn the ROM back on (lsdos does this) ; start: di ; disable interrupts ld a,1 ; map in the ROM out (romport),a ; do it! ; ; start of "real" ROM instructions ; jp contin ; continue farther up ; ; rst 08h through rst 38h jumps (per tech ref) ; rst8: jp 4000h db 0,0,0,0,0 rst10: jp 4003h db 0,0,0,0,0 rst18: jp 4006h db 0,0,0,0,0 rst20: jp 4009h db 0,0,0,0,0 rst28: jp 400ch db 0,0,0,0,0 rst30: jp 400fh db 0,0,0,0,0 rst38: jp 4012h ; ; Data to load from 4000h to ?? ; retdat: ret ; 4000h (rst 8h) dw 0 ret ; 4003h (rst 10h) dw 0 ret ; 4006h (rst 18h) dw 0 ret ; 4009h (rst 20h) dw 0 ret ; 400ch (rst 28h) dw 0 ret ; 400fh (rst 30h) dw 0 ret ; 4012h (rst 38h) dw 0 jp nmiret ; 4015h (nmi) ; db 'MO' ; 4P detect by sysinit ; ; code that jumps to the boot sector (401ah) ; xor a out (romport),a ; disable rom jp bootram ; run boot sector ; retlen equ $-retdat ; size of code ; ; nmi address ; org 66h ; jp 4015h ; std M4 point in RAM ; ; continue booting the machine ; contin: xor a out (wrnmiport),a ; disable interrupts ld a,1 out (opreg),a ; set ram mode ld a,01010000b out (modport),a ; set speed/vid ; ld sp,bootram-100h ; set stack pointer ; ld hl,retdat ; code for RAM ld de,4000h ; move it here ld bc,retlen ldir ; ld hl,3c00h ; clear video screen ld de,3c01h ld bc,1023 ld (hl),' ' ldir ; im 1 ; call chkmdl ; check for model 4p call rstdrv ; restore drive call z,readbt ; read boot sector jp nz,dskerr ; go on error ; jmprom: jp goboot ; jump to boot sector ; ; chkmdl - make sure we're in 4P mode ; chkmdl: ld a,5 ; model query dw 3cedh ; emt_misc instr. ld a,l ; get model in a cp 5 ; model 4p? ret z ; ; romerr - rom installed in model 1, 3, or 4 mode!! ; romerr: push af ld hl,rommsg ; "invalid rom for model" ld de,video ld bc,romlen ldir ; put msg add a,'0' ; convert model to ascii ld (de),a ; stuff onto screen jr $ ; and hang ; ; dskerr - error reading disk ; dskerr: ld hl,errtab ; table of error messages scf ; ensure termination nxterr: rra ; loop through bits, low first jr c,goterr ; go if error bit found inc hl ; no, step to next message inc hl jr nxterr goterr: ld e,(hl) ; get message address inc hl ld d,(hl) ex de,hl ld de,video ; where to show it chrout: ld a,(hl) and a jr z,$ ; hang in a loop when done ld (de),a inc hl inc de jr chrout ; ; rstdrv - seek track 0 and set up for boot read ; rstdrv: ld a,81h ; drive 0, dden (no nmi) out (fdcslct),a ; select drive ld a,0d0h ; force interrupt call fdcmd ; send to fdc ld b,0 djnz $ ; wait a bit ld a,0ch ; restore w/verify call fdcmd ; and 99h ; mask error bits ret z ; return if okay jr dskerr ; ; readbt - read boot sector from drive 0 ; readbt: ld de,0001h ; trk 0, sec 1 ld hl,bootram ; set buffer call readsb ; attempt read and 1ch ; keep RNF,CRC,LOST DATA ret z ; return if no error jp dskerr ; go on error ; ; readsb - read sector to buffer ; readsb: ld b,81h ld c,fdcslct ; set dden,ds0 out (c),b ; select dec c ; set to data register ld a,18h ; fdc seek command out (c),d ; track # to fdc call fdcmd ; send command to fdc ld a,e out (fdcsect),a ; desired sector ld a,81h ; dden & ds0 out (fdcslct),a ; reselect drive ld de,08116h ; D=DS0, dden, wait ; E=mask to see DRQ or error ld a,80h ; fdc read command out (fdccmnd),a ; send command ld b,100 ; short delay djnz $ ld a,0c0h ; enable intrq out (wrnmiport),a rdlp1: in a,(fdcstat) ; get status and e ; test bit 1 jr z,rdlp1 ini ld a,d rdlp2: out (fdcslct),a ini jr rdlp2 ; tight loop waiting for NMI ; jr nz,rdlp2 ; in a,(fdcstat) ; ret nmiret: xor a out (wrnmiport),a ; no interrupts ld a,81h ; DS 0, dden out (fdcslct),a in a,(fdcstat) ex (sp),hl ; discard one level of return address pop hl retn ; ; fdcmd - send command in A to fdc and wait for completion ; fdcmd: out (fdccmnd),a ; send command ld b,100 ; short delay djnz $ fdst: in a,(fdcstat) bit 0,a ; busy? ret z ; return if not bit 7,a ; not ready? ret nz ; return if set jr fdst ; else loop ;------------------------------------------------------------------ ; messages ;------------------------------------------------------------------ ; rommsg: db 'This ROM code does NOT work when emulating Model ' romlen equ $-rommsg ; errtab: dw dskmsg,ecant,elost,ecrc,ernf,ecant,ecant,dskmsg,ecant elost: ecant: db 'Emulator or ROM bug',0 ecrc: db 'Boot sector CRC error',0 ernf: db 'Boot sector not found on disk',0 dskmsg: db 'You do not have a disk image loaded',0 ; end start xtrs-4.9d/z80.c000066400000000000000000003015521306603614600133320ustar00rootroot00000000000000/* * Copyright (C) 1992 Clarendon Hill Software. * * Permission is granted to any individual or institution to use, copy, * or redistribute this software, provided this copyright notice is retained. * * This software is provided "as is" without any expressed or implied * warranty. If this software brings on any sort of damage -- physical, * monetary, emotional, or brain -- too bad. You've got no one to blame * but yourself. * * The software may be modified for your own purposes, but modified versions * must retain this notice. */ /* Modified by Timothy Mann, 1996-2008 $Id: z80.c,v 1.29 2009/06/15 23:45:19 mann Exp $ */ /* * z80.c: The guts of the Z-80 emulator. * * The Z-80 emulator should be general and complete enough to be * easily adapted to emulate any Z-80 machine. All of the documented * Z-80 flags and instructions are implemented. The only documented * features we cheat a little on are interrupt handling (modes 0 and 2 * are not supported) and the refresh register (reading it returns a * random number; writing it is ignored). * * All of the undocumented instructions, flags, and features listed in * http://www.msxnet.org/tech/Z80/z80undoc.txt are implemented too, * with some minor exceptions. There seems to be a disagreement about * undocumented flag handling for "bit" instructions between * z80undoc.txt and the ZEXALL validator from Yaze. Since ZEXALL * passes on both a real Z-80 and Yaze, but fails on my attempt to * implement "bit n,r" according to z80undoc.txt, I've imitated Yaze's * implementation. On block in/out instructions, z80undoc.txt gives * some very complicated rules for undocumented flag handling that I * have not implemented. */ #include "z80.h" #include "trs.h" #include "trs_imp_exp.h" #include /* for rand() */ #include /* for pause() */ #include /* for time() */ /* * Keep Saber quiet. */ /*SUPPRESS 53*/ /*SUPPRESS 51*/ /*SUPPRESS 112*/ /*SUPPRESS 115*/ /* * The state of our Z-80 registers is kept in this structure: */ struct z80_state_struct z80_state; /* * Tables and routines for computing various flag values: */ static Uchar sign_carry_overflow_table[] = { 0, OVERFLOW_MASK | SIGN_MASK, CARRY_MASK, SIGN_MASK, CARRY_MASK, SIGN_MASK, CARRY_MASK | OVERFLOW_MASK, CARRY_MASK | SIGN_MASK, }; static Uchar half_carry_table[] = { 0, 0, HALF_CARRY_MASK, 0, HALF_CARRY_MASK, 0, HALF_CARRY_MASK, HALF_CARRY_MASK, }; static Uchar subtract_sign_carry_overflow_table[] = { 0, CARRY_MASK | SIGN_MASK, CARRY_MASK, OVERFLOW_MASK | CARRY_MASK | SIGN_MASK, OVERFLOW_MASK, SIGN_MASK, 0, CARRY_MASK | SIGN_MASK, }; static Uchar subtract_half_carry_table[] = { 0, HALF_CARRY_MASK, HALF_CARRY_MASK, HALF_CARRY_MASK, 0, 0, 0, HALF_CARRY_MASK, }; static int parity(unsigned value) { /* for parity flag, 1 = even parity, 0 = odd parity. */ static char parity_table[256] = { 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 }; return(parity_table[value]); } static void do_add_flags(int a, int b, int result) { /* * Compute the flag values for a + b = result operation */ int index; int f; /* * Sign, carry, and overflow depend upon values of bit 7. * Half-carry depends upon values of bit 3. * We mask those bits, munge them into an index, and look * up the flag values in the above tables. * Undocumented flags in bit 3, 5 of F come from the result. */ index = ((a & 0x88) >> 1) | ((b & 0x88) >> 2) | ((result & 0x88) >> 3); f = half_carry_table[index & 7] | sign_carry_overflow_table[index >> 4] | (result & (UNDOC3_MASK|UNDOC5_MASK)); if((result & 0xFF) == 0) f |= ZERO_MASK; REG_F = f; } static void do_sub_flags(int a, int b, int result) { int index; int f; /* * Sign, carry, and overflow depend upon values of bit 7. * Half-carry depends upon values of bit 3. * We mask those bits, munge them into an index, and look * up the flag values in the above tables. * Undocumented flags in bit 3, 5 of F come from the result. */ index = ((a & 0x88) >> 1) | ((b & 0x88) >> 2) | ((result & 0x88) >> 3); f = SUBTRACT_MASK | subtract_half_carry_table[index & 7] | subtract_sign_carry_overflow_table[index >> 4] | (result & (UNDOC3_MASK|UNDOC5_MASK)); if((result & 0xFF) == 0) f |= ZERO_MASK; REG_F = f; } static void do_adc_word_flags(int a, int b, int result) { int index; int f; /* * Sign, carry, and overflow depend upon values of bit 15. * Half-carry depends upon values of bit 11. * We mask those bits, munge them into an index, and look * up the flag values in the above tables. * Undocumented flags in bit 3, 5 of F come from the result high byte. */ index = ((a & 0x8800) >> 9) | ((b & 0x8800) >> 10) | ((result & 0x8800) >> 11); f = half_carry_table[index & 7] | sign_carry_overflow_table[index >> 4] | ((result >> 8) & (UNDOC3_MASK|UNDOC5_MASK)); if((result & 0xFFFF) == 0) f |= ZERO_MASK; REG_F = f; } static void do_add_word_flags(int a, int b, int result) { int index; int f; /* * Carry depends upon values of bit 15. * Half-carry depends upon values of bit 11. * We mask those bits, munge them into an index, and look * up the flag values in the above tables. * Undocumented flags in bit 3, 5 of F come from the result high byte. */ index = ((a & 0x8800) >> 9) | ((b & 0x8800) >> 10) | ((result & 0x8800) >> 11); f = half_carry_table[index & 7] | (sign_carry_overflow_table[index >> 4] & CARRY_MASK) | (REG_F & (ZERO_MASK | PARITY_MASK | SIGN_MASK)) | ((result >> 8) & (UNDOC3_MASK | UNDOC5_MASK)); REG_F = f; } static void do_sbc_word_flags(int a, int b, int result) { int index; int f; /* * Sign, carry, and overflow depend upon values of bit 15. * Half-carry depends upon values of bit 11. * We mask those bits, munge them into an index, and look * up the flag values in the above tables. * Undocumented flags in bit 3, 5 of F come from the result high byte. */ index = ((a & 0x8800) >> 9) | ((b & 0x8800) >> 10) | ((result & 0x8800) >> 11); f = SUBTRACT_MASK | subtract_half_carry_table[index & 7] | subtract_sign_carry_overflow_table[index >> 4] | ((result >> 8) & (UNDOC3_MASK | UNDOC5_MASK)); if((result & 0xFFFF) == 0) f |= ZERO_MASK; REG_F = f; } static void do_flags_dec_byte(int value) { Uchar set; set = SUBTRACT_MASK; if(value == 0x7f) set |= OVERFLOW_MASK; if((value & 0xF) == 0xF) set |= HALF_CARRY_MASK; if(value == 0) set |= ZERO_MASK; if(value & 0x80) set |= SIGN_MASK; REG_F = (REG_F & CARRY_MASK) | set | (value & (UNDOC3_MASK | UNDOC5_MASK)); } static void do_flags_inc_byte(int value) { Uchar set; set = 0; if(value == 0x80) set |= OVERFLOW_MASK; if((value & 0xF) == 0) set |= HALF_CARRY_MASK; if(value == 0) set |= ZERO_MASK; if(value & 0x80) set |= SIGN_MASK; REG_F = (REG_F & CARRY_MASK) | set | (value & (UNDOC3_MASK | UNDOC5_MASK)); } /* * Routines for executing or assisting various non-trivial arithmetic * instructions: */ static void do_and_byte(int value) { int result; Uchar set; result = (REG_A &= value); set = HALF_CARRY_MASK; if(parity(result)) set |= PARITY_MASK; if(result == 0) set |= ZERO_MASK; if(result & 0x80) set |= SIGN_MASK; REG_F = set | (result & (UNDOC3_MASK | UNDOC5_MASK)); } static void do_or_byte(int value) { int result; /* the result of the or operation */ Uchar set; result = (REG_A |= value); set = 0; if(parity(result)) set |= PARITY_MASK; if(result == 0) set |= ZERO_MASK; if(result & 0x80) set |= SIGN_MASK; REG_F = set | (result & (UNDOC3_MASK | UNDOC5_MASK)); } static void do_xor_byte(int value) { int result; /* the result of the xor operation */ Uchar set; result = (REG_A ^= value); set = 0; if(parity(result)) set |= PARITY_MASK; if(result == 0) set |= ZERO_MASK; if(result & 0x80) set |= SIGN_MASK; REG_F = set | (result & (UNDOC3_MASK | UNDOC5_MASK)); } static void do_add_byte(int value) { int a, result; result = (a = REG_A) + value; REG_A = result; do_add_flags(a, value, result); } static void do_adc_byte(int value) { int a, result; if(CARRY_FLAG) result = (a = REG_A) + value + 1; else result = (a = REG_A) + value; REG_A = result; do_add_flags(a, value, result); } static void do_sub_byte(int value) { int a, result; result = (a = REG_A) - value; REG_A = result; do_sub_flags(a, value, result); } static void do_negate() { int a; a = REG_A; REG_A = - a; do_sub_flags(0, a, REG_A); } static void do_sbc_byte(int value) { int a, result; if(CARRY_FLAG) result = (a = REG_A) - (value + 1); else result = (a = REG_A) - value; REG_A = result; do_sub_flags(a, value, result); } static void do_add_word(int value) { int a, result; result = (a = REG_HL) + value; REG_HL = result; do_add_word_flags(a, value, result); } static void do_adc_word(int value) { int a, result; if(CARRY_FLAG) result = (a = REG_HL) + value + 1; else result = (a = REG_HL) + value; REG_HL = result; do_adc_word_flags(a, value, result); } static void do_sbc_word(int value) { int a, result; if(CARRY_FLAG) result = (a = REG_HL) - (value + 1); else result = (a = REG_HL) - value; REG_HL = result; do_sbc_word_flags(a, value, result); } static void do_add_word_index(Ushort *regp, int value) { int a, result; result = (a = *regp) + value; *regp = result; do_add_word_flags(a, value, result); } /* compare this value with A's contents */ static void do_cp(int value) { int a, result; int index; int f; result = (a = REG_A) - value; /* * Sign, carry, and overflow depend upon values of bit 7. * Half-carry depends upon values of bit 3. * We mask those bits, munge them into an index, and look * up the flag values in the above tables. * Undocumented flags in bit 3, 5 of F come from the second operand. */ index = ((a & 0x88) >> 1) | ((value & 0x88) >> 2) | ((result & 0x88) >> 3); f = SUBTRACT_MASK | subtract_half_carry_table[index & 7] | subtract_sign_carry_overflow_table[index >> 4] | (value & (UNDOC3_MASK|UNDOC5_MASK)); if((result & 0xFF) == 0) f |= ZERO_MASK; REG_F = f; } static void do_cpd() { int oldcarry = REG_F & CARRY_MASK; int a, value, result; value = mem_read(REG_HL); result = (a = REG_A) - value; REG_HL--; REG_BC--; do_sub_flags(a, value, result); REG_F = (REG_F & ~(CARRY_MASK | OVERFLOW_MASK | UNDOC5_MASK)) | oldcarry | (REG_BC == 0 ? 0 : OVERFLOW_MASK) | (((result - ((REG_F & HALF_CARRY_MASK) >> 4)) & 2) << 4); if ((result & 15) == 8 && (REG_F & HALF_CARRY_MASK) != 0) { REG_F &= ~UNDOC3_MASK; } T_COUNT(16); } static void do_cpi() { int oldcarry = REG_F & CARRY_MASK; int a, value, result; value = mem_read(REG_HL); result = (a = REG_A) - value; REG_HL++; REG_BC--; do_sub_flags(a, value, result); REG_F = (REG_F & ~(CARRY_MASK | OVERFLOW_MASK | UNDOC5_MASK)) | oldcarry | (REG_BC == 0 ? 0 : OVERFLOW_MASK) | (((result - ((REG_F & HALF_CARRY_MASK) >> 4)) & 2) << 4); if ((result & 15) == 8 && (REG_F & HALF_CARRY_MASK) != 0) { REG_F &= ~UNDOC3_MASK; } T_COUNT(16); } static void do_cpdr() { int oldcarry = REG_F & CARRY_MASK; int a = REG_A, value, result; do { result = a - (value = mem_read(REG_HL)); REG_HL--; REG_BC--; T_COUNT(21); } while((REG_BC != 0) && (result != 0)); do_sub_flags(a, value, result); REG_F = (REG_F & ~(CARRY_MASK | OVERFLOW_MASK | UNDOC5_MASK)) | oldcarry | (REG_BC == 0 ? 0 : OVERFLOW_MASK) | (((result - ((REG_F & HALF_CARRY_MASK) >> 4)) & 2) << 4); if ((result & 15) == 8 && (REG_F & HALF_CARRY_MASK) != 0) { REG_F &= ~UNDOC3_MASK; } T_COUNT(-5); } static void do_cpir() { int oldcarry = REG_F & CARRY_MASK; int a = REG_A, value, result; do { result = a - (value = mem_read(REG_HL)); REG_HL++; REG_BC--; T_COUNT(21); } while((REG_BC != 0) && (result != 0)); do_sub_flags(a, value, result); REG_F = (REG_F & ~(CARRY_MASK | OVERFLOW_MASK | UNDOC5_MASK)) | oldcarry | (REG_BC == 0 ? 0 : OVERFLOW_MASK) | (((result - ((REG_F & HALF_CARRY_MASK) >> 4)) & 2) << 4); if ((result & 15) == 8 && (REG_F & HALF_CARRY_MASK) != 0) { REG_F &= ~UNDOC3_MASK; } T_COUNT(-5); } #if 1 /* The following passes ZEXALL and matches Yaze, but if you believe http://www.msxnet.org/tech/Z80/z80undoc.txt, it gets UNDOC3 and UNDOC5 wrong. It remains to be seen which (if either) is really right. */ static void do_test_bit(int op, int value, int bit) { int result = value & (1 << bit); REG_F = (REG_F & CARRY_MASK) | HALF_CARRY_MASK | (result & SIGN_MASK) | (result ? 0 : (OVERFLOW_MASK | ZERO_MASK)) | (((op & 7) == 6) ? 0 : (value & (UNDOC3_MASK | UNDOC5_MASK))); } #else /* The following matches http://www.msxnet.org/tech/Z80/z80undoc.txt for "bit n,r", but does not attempt to emulate the full weirdness of "bit n,(ix/iy+d)" and "bit n,(hl)". It fails ZEXALL even if code is added to make the latter two instructions behave as in the version that passes ZEXALL, leading me to think that z80undoc.txt may be mistaken about "bit n,r". This should be checked in detail against a real Z-80, I suppose. Ugh. */ static void do_test_bit(int op, int value, int bit) { int result = value & (1 << bit); REG_F = (REG_F & CARRY_MASK) | HALF_CARRY_MASK | (result & (UNDOC3_MASK | UNDOC5_MASK | SIGN_MASK)) | (result ? 0 : (OVERFLOW_MASK | ZERO_MASK)); } #endif static int rl_byte(int value) { /* * Compute rotate-left-through-carry * operation, setting flags as appropriate. */ Uchar set; int result; set = 0; if(CARRY_FLAG) { result = ((value << 1) & 0xFF) | 1; } else { result = (value << 1) & 0xFF; } if(result & 0x80) set |= SIGN_MASK; if(result == 0) set |= ZERO_MASK; if(parity(result)) set |= PARITY_MASK; if(value & 0x80) set |= CARRY_MASK; REG_F = (result & (UNDOC3_MASK | UNDOC5_MASK)) | set; return result; } static int rr_byte(int value) { /* * Compute rotate-right-through-carry * operation, setting flags as appropriate. */ Uchar set; int result; set = 0; if(CARRY_FLAG) { result = (value >> 1) | 0x80; } else { result = (value >> 1); } if(result & 0x80) set |= SIGN_MASK; if(result == 0) set |= ZERO_MASK; if(parity(result)) set |= PARITY_MASK; if(value & 0x1) set |= CARRY_MASK; REG_F = (result & (UNDOC3_MASK | UNDOC5_MASK)) | set; return result; } static int rlc_byte(int value) { /* * Compute the result of an RLC operation and set the flags appropriately. * This does not do the right thing for the RLCA instruction. */ Uchar set; int result; set = 0; if(value & 0x80) { result = ((value << 1) & 0xFF) | 1; set |= CARRY_MASK; } else { result = (value << 1) & 0xFF; } if(result & 0x80) set |= SIGN_MASK; if(result == 0) set |= ZERO_MASK; if(parity(result)) set |= PARITY_MASK; REG_F = (result & (UNDOC3_MASK | UNDOC5_MASK)) | set; return result; } static int rrc_byte(int value) { Uchar set; int result; set = 0; if(value & 0x1) { result = (value >> 1) | 0x80; set |= CARRY_MASK; } else { result = (value >> 1); } if(result & 0x80) set |= SIGN_MASK; if(result == 0) set |= ZERO_MASK; if(parity(result)) set |= PARITY_MASK; REG_F = (result & (UNDOC3_MASK | UNDOC5_MASK)) | set; return result; } /* * Perform the RLA, RLCA, RRA, RRCA instructions. These set the flags * differently than the other rotate instrucitons. */ static void do_rla() { Uchar set; set = 0; if(REG_A & 0x80) set |= CARRY_MASK; if(CARRY_FLAG) { REG_A = ((REG_A << 1) & 0xFF) | 1; } else { REG_A = (REG_A << 1) & 0xFF; } REG_F = (REG_F & (OVERFLOW_MASK | ZERO_MASK | SIGN_MASK)) | set | (REG_A & (UNDOC3_MASK | UNDOC5_MASK )); } static void do_rra() { Uchar set; set = 0; if(REG_A & 0x1) set |= CARRY_MASK; if(CARRY_FLAG) { REG_A = (REG_A >> 1) | 0x80; } else { REG_A = REG_A >> 1; } REG_F = (REG_F & (OVERFLOW_MASK | ZERO_MASK | SIGN_MASK)) | set | (REG_A & (UNDOC3_MASK | UNDOC5_MASK )); } static void do_rlca() { Uchar set; set = 0; if(REG_A & 0x80) { REG_A = ((REG_A << 1) & 0xFF) | 1; set |= CARRY_MASK; } else { REG_A = (REG_A << 1) & 0xFF; } REG_F = (REG_F & (OVERFLOW_MASK | ZERO_MASK | SIGN_MASK)) | set | (REG_A & (UNDOC3_MASK | UNDOC5_MASK )); } static void do_rrca() { Uchar set; set = 0; if(REG_A & 0x1) { REG_A = (REG_A >> 1) | 0x80; set |= CARRY_MASK; } else { REG_A = REG_A >> 1; } REG_F = (REG_F & (OVERFLOW_MASK | ZERO_MASK | SIGN_MASK)) | set | (REG_A & (UNDOC3_MASK | UNDOC5_MASK )); } static int sla_byte(int value) { Uchar set; int result; set = 0; result = (value << 1) & 0xFF; if(result & 0x80) set |= SIGN_MASK; if(result == 0) set |= ZERO_MASK; if(parity(result)) set |= PARITY_MASK; if(value & 0x80) set |= CARRY_MASK; REG_F = (result & (UNDOC3_MASK | UNDOC5_MASK)) | set; return result; } static int sra_byte(int value) { Uchar set; int result; set = 0; if(value & 0x80) { result = (value >> 1) | 0x80; set |= SIGN_MASK; } else { result = value >> 1; } if(result == 0) set |= ZERO_MASK; if(parity(result)) set |= PARITY_MASK; if(value & 0x1) set |= CARRY_MASK; REG_F = (result & (UNDOC3_MASK | UNDOC5_MASK)) | set; return result; } /* undocumented opcode slia: shift left and increment */ static int slia_byte(int value) { Uchar set; int result; set = 0; result = ((value << 1) & 0xFF) | 1; if(result & 0x80) set |= SIGN_MASK; if(result == 0) set |= ZERO_MASK; if(parity(result)) set |= PARITY_MASK; if(value & 0x80) set |= CARRY_MASK; REG_F = (result & (UNDOC3_MASK | UNDOC5_MASK)) | set; return result; } static int srl_byte(int value) { Uchar set; int result; set = 0; result = value >> 1; if(result & 0x80) set |= SIGN_MASK; if(result == 0) set |= ZERO_MASK; if(parity(result)) set |= PARITY_MASK; if(value & 0x1) set |= CARRY_MASK; REG_F = (result & (UNDOC3_MASK | UNDOC5_MASK)) | set; return result; } static void do_ldd() { int moved, undoc; mem_write(REG_DE, moved = mem_read(REG_HL)); REG_DE--; REG_HL--; REG_BC--; if(REG_BC == 0) CLEAR_OVERFLOW(); else SET_OVERFLOW(); undoc = REG_A + moved; REG_F = (REG_F & ~(UNDOC3_MASK|UNDOC5_MASK|HALF_CARRY_MASK|SUBTRACT_MASK)) | (undoc & UNDOC3_MASK) | ((undoc & 2) ? UNDOC5_MASK : 0); T_COUNT(16); } static void do_ldi() { int moved, undoc; mem_write(REG_DE, moved = mem_read(REG_HL)); REG_DE++; REG_HL++; REG_BC--; if(REG_BC == 0) CLEAR_OVERFLOW(); else SET_OVERFLOW(); undoc = REG_A + moved; REG_F = (REG_F & ~(UNDOC3_MASK|UNDOC5_MASK|HALF_CARRY_MASK|SUBTRACT_MASK)) | (undoc & UNDOC3_MASK) | ((undoc & 2) ? UNDOC5_MASK : 0); T_COUNT(16); } static void do_ldir() { /* repeating block load with increment */ int moved, undoc; moved = mem_block_transfer(REG_DE, REG_HL, 1, REG_BC); T_COUNT(((REG_BC-1) & 0xffff) * 21 + 16); /* set registers to final values */ REG_DE += REG_BC; REG_HL += REG_BC; REG_BC = 0; /* set up flags */ undoc = REG_A + moved; REG_F = (REG_F & (CARRY_MASK | ZERO_MASK | SIGN_MASK)) | (undoc & UNDOC3_MASK) | ((undoc & 2) ? UNDOC5_MASK : 0); } static void do_lddr() { /* repeating block load with decrement */ int moved, undoc; moved = mem_block_transfer(REG_DE, REG_HL, -1, REG_BC); T_COUNT(((REG_BC-1) & 0xffff) * 21 + 16); /* set registers to final values */ REG_DE -= REG_BC; REG_HL -= REG_BC; REG_BC = 0; /* set up flags */ undoc = REG_A + moved; REG_F = (REG_F & (CARRY_MASK | ZERO_MASK | SIGN_MASK)) | (undoc & UNDOC3_MASK) | ((undoc & 2) ? UNDOC5_MASK : 0); } static void do_ld_a_i() { Uchar set; set = 0; REG_A = REG_I; if(REG_A & 0x80) set |= SIGN_MASK; if(REG_A == 0) set |= ZERO_MASK; if(z80_state.iff2) set |= OVERFLOW_MASK; REG_F = (REG_F & CARRY_MASK) | (REG_A & (UNDOC3_MASK | UNDOC5_MASK)) | set; } static void do_ld_a_r() { Uchar set; set = 0; /* Fetch a random value. */ REG_A = (rand() >> 8) & 0xFF; if(REG_A & 0x80) set |= SIGN_MASK; if(REG_A == 0) set |= ZERO_MASK; if(z80_state.iff2) set |= OVERFLOW_MASK; REG_F = (REG_F & CARRY_MASK) | (REG_A & (UNDOC3_MASK | UNDOC5_MASK)) | set; } /* Completely new implementation adapted from yaze. The old one was very wrong. */ static void do_daa() { int a = REG_A, f = REG_F; int alow = a & 0xf; int carry = f & CARRY_MASK; int hcarry = f & HALF_CARRY_MASK; if (f & SUBTRACT_MASK) { int hd = carry || a > 0x99; if (hcarry || alow > 9) { if (alow > 5) hcarry = 0; a = (a - 6) & 0xff; } if (hd) a -= 0x160; } else { if (hcarry || alow > 9) { hcarry = alow > 9 ? HALF_CARRY_MASK : 0; a += 6; } if (carry || ((a & 0x1f0) > 0x90)) { a += 0x60; } } if (a & 0x100) carry = CARRY_MASK; REG_A = a = a & 0xff; REG_F = ((a & 0x80) ? SIGN_MASK : 0) | (a & (UNDOC3_MASK|UNDOC5_MASK)) | (a ? 0 : ZERO_MASK) | (f & SUBTRACT_MASK) | hcarry | (parity(a) ? PARITY_MASK : 0) | carry; } static void do_rld() { /* * Rotate-left-decimal. */ int old_value, new_value; Uchar set; set = 0; old_value = mem_read(REG_HL); /* left-shift old value, add lower bits of a */ new_value = ((old_value << 4) | (REG_A & 0x0f)) & 0xff; /* rotate high bits of old value into low bits of a */ REG_A = (REG_A & 0xf0) | (old_value >> 4); if(REG_A & 0x80) set |= SIGN_MASK; if(REG_A == 0) set |= ZERO_MASK; if(parity(REG_A)) set |= PARITY_MASK; REG_F = (REG_F & CARRY_MASK) | set | (REG_A & (UNDOC3_MASK | UNDOC5_MASK)); mem_write(REG_HL,new_value); } static void do_rrd() { /* * Rotate-right-decimal. */ int old_value, new_value; Uchar set; set = 0; old_value = mem_read(REG_HL); /* right-shift old value, add lower bits of a */ new_value = (old_value >> 4) | ((REG_A & 0x0f) << 4); /* rotate low bits of old value into low bits of a */ REG_A = (REG_A & 0xf0) | (old_value & 0x0f); if(REG_A & 0x80) set |= SIGN_MASK; if(REG_A == 0) set |= ZERO_MASK; if(parity(REG_A)) set |= PARITY_MASK; REG_F = (REG_F & CARRY_MASK) | set | (REG_A & (UNDOC3_MASK | UNDOC5_MASK)); mem_write(REG_HL,new_value); } /* * Input/output instruction support: */ static void do_ind() { mem_write(REG_HL, z80_in(REG_C)); REG_HL--; REG_B--; if(REG_B == 0) SET_ZERO(); else CLEAR_ZERO(); SET_SUBTRACT(); T_COUNT(15); } static void do_indr() { do { mem_write(REG_HL, z80_in(REG_C)); REG_HL--; REG_B--; T_COUNT(20); } while(REG_B != 0); T_COUNT(-5); SET_ZERO(); SET_SUBTRACT(); } static void do_ini() { mem_write(REG_HL, z80_in(REG_C)); REG_HL++; REG_B--; if(REG_B == 0) SET_ZERO(); else CLEAR_ZERO(); SET_SUBTRACT(); T_COUNT(15); } static void do_inir() { do { mem_write(REG_HL, z80_in(REG_C)); REG_HL++; REG_B--; T_COUNT(20); } while(REG_B != 0); T_COUNT(-5); SET_ZERO(); SET_SUBTRACT(); } static int in_with_flags(int port) { /* * Do the appropriate flag calculations for the in instructions * which compute the flags. Return the input value. */ int value; Uchar clear, set; clear = (Uchar) ~(SIGN_MASK | ZERO_MASK | HALF_CARRY_MASK | PARITY_MASK | SUBTRACT_MASK); set = 0; value = z80_in(port); if(value & 0x80) set |= SIGN_MASK; if(value == 0) set |= ZERO_MASK; if(parity(value)) set |= PARITY_MASK; /* What should the half-carry do? Is this a mistake? */ REG_F = (REG_F & clear) | set; return value; } static void do_outd() { z80_out(REG_C, mem_read(REG_HL)); REG_HL--; REG_B--; if(REG_B == 0) SET_ZERO(); else CLEAR_ZERO(); SET_SUBTRACT(); T_COUNT(15); } static void do_outdr() { do { z80_out(REG_C, mem_read(REG_HL)); REG_HL--; REG_B--; T_COUNT(20); } while(REG_B != 0); T_COUNT(-5); SET_ZERO(); SET_SUBTRACT(); } static void do_outi() { z80_out(REG_C, mem_read(REG_HL)); REG_HL++; REG_B--; if(REG_B == 0) SET_ZERO(); else CLEAR_ZERO(); SET_SUBTRACT(); T_COUNT(15); } static void do_outir() { do { z80_out(REG_C, mem_read(REG_HL)); REG_HL++; REG_B--; T_COUNT(20); } while(REG_B != 0); T_COUNT(-5); SET_ZERO(); SET_SUBTRACT(); } /* * Interrupt handling routines: */ static void do_di() { z80_state.iff1 = z80_state.iff2 = 0; } static void do_ei() { z80_state.iff1 = z80_state.iff2 = 1; } static void do_im0() { z80_state.interrupt_mode = 0; } static void do_im1() { z80_state.interrupt_mode = 1; } static void do_im2() { z80_state.interrupt_mode = 2; } static void do_int() { /* handle a maskable interrupt */ REG_SP -= 2; mem_write_word(REG_SP, REG_PC); z80_state.iff1 = 0; switch (z80_state.interrupt_mode) { case 0: /* REG_PC = get_irq_vector() & 0x38; */ error("interrupt in im0 not supported"); break; case 1: REG_PC = 0x38; break; case 2: /* REG_PC = REG_I << 8 + get_irq_vector(); */ error("interrupt in im2 not supported"); break; } } static void do_nmi() { /* handle a non-maskable interrupt */ REG_SP -= 2; mem_write_word(REG_SP, REG_PC); z80_state.iff1 = 0; REG_PC = 0x66; } /* * Extended instructions which have 0xCB as the first byte: */ static void do_CB_instruction() { Uchar instruction; instruction = mem_read(REG_PC++); switch(instruction) { case 0x47: /* bit 0, a */ do_test_bit(instruction, REG_A, 0); T_COUNT(8); break; case 0x40: /* bit 0, b */ do_test_bit(instruction, REG_B, 0); T_COUNT(8); break; case 0x41: /* bit 0, c */ do_test_bit(instruction, REG_C, 0); T_COUNT(8); break; case 0x42: /* bit 0, d */ do_test_bit(instruction, REG_D, 0); T_COUNT(8); break; case 0x43: /* bit 0, e */ do_test_bit(instruction, REG_E, 0); T_COUNT(8); break; case 0x44: /* bit 0, h */ do_test_bit(instruction, REG_H, 0); T_COUNT(8); break; case 0x45: /* bit 0, l */ do_test_bit(instruction, REG_L, 0); T_COUNT(8); break; case 0x4F: /* bit 1, a */ do_test_bit(instruction, REG_A, 1); T_COUNT(8); break; case 0x48: /* bit 1, b */ do_test_bit(instruction, REG_B, 1); T_COUNT(8); break; case 0x49: /* bit 1, c */ do_test_bit(instruction, REG_C, 1); T_COUNT(8); break; case 0x4A: /* bit 1, d */ do_test_bit(instruction, REG_D, 1); T_COUNT(8); break; case 0x4B: /* bit 1, e */ do_test_bit(instruction, REG_E, 1); T_COUNT(8); break; case 0x4C: /* bit 1, h */ do_test_bit(instruction, REG_H, 1); T_COUNT(8); break; case 0x4D: /* bit 1, l */ do_test_bit(instruction, REG_L, 1); T_COUNT(8); break; case 0x57: /* bit 2, a */ do_test_bit(instruction, REG_A, 2); T_COUNT(8); break; case 0x50: /* bit 2, b */ do_test_bit(instruction, REG_B, 2); T_COUNT(8); break; case 0x51: /* bit 2, c */ do_test_bit(instruction, REG_C, 2); T_COUNT(8); break; case 0x52: /* bit 2, d */ do_test_bit(instruction, REG_D, 2); T_COUNT(8); break; case 0x53: /* bit 2, e */ do_test_bit(instruction, REG_E, 2); T_COUNT(8); break; case 0x54: /* bit 2, h */ do_test_bit(instruction, REG_H, 2); T_COUNT(8); break; case 0x55: /* bit 2, l */ do_test_bit(instruction, REG_L, 2); T_COUNT(8); break; case 0x5F: /* bit 3, a */ do_test_bit(instruction, REG_A, 3); T_COUNT(8); break; case 0x58: /* bit 3, b */ do_test_bit(instruction, REG_B, 3); T_COUNT(8); break; case 0x59: /* bit 3, c */ do_test_bit(instruction, REG_C, 3); T_COUNT(8); break; case 0x5A: /* bit 3, d */ do_test_bit(instruction, REG_D, 3); T_COUNT(8); break; case 0x5B: /* bit 3, e */ do_test_bit(instruction, REG_E, 3); T_COUNT(8); break; case 0x5C: /* bit 3, h */ do_test_bit(instruction, REG_H, 3); T_COUNT(8); break; case 0x5D: /* bit 3, l */ do_test_bit(instruction, REG_L, 3); T_COUNT(8); break; case 0x67: /* bit 4, a */ do_test_bit(instruction, REG_A, 4); T_COUNT(8); break; case 0x60: /* bit 4, b */ do_test_bit(instruction, REG_B, 4); T_COUNT(8); break; case 0x61: /* bit 4, c */ do_test_bit(instruction, REG_C, 4); T_COUNT(8); break; case 0x62: /* bit 4, d */ do_test_bit(instruction, REG_D, 4); T_COUNT(8); break; case 0x63: /* bit 4, e */ do_test_bit(instruction, REG_E, 4); T_COUNT(8); break; case 0x64: /* bit 4, h */ do_test_bit(instruction, REG_H, 4); T_COUNT(8); break; case 0x65: /* bit 4, l */ do_test_bit(instruction, REG_L, 4); T_COUNT(8); break; case 0x6F: /* bit 5, a */ do_test_bit(instruction, REG_A, 5); T_COUNT(8); break; case 0x68: /* bit 5, b */ do_test_bit(instruction, REG_B, 5); T_COUNT(8); break; case 0x69: /* bit 5, c */ do_test_bit(instruction, REG_C, 5); T_COUNT(8); break; case 0x6A: /* bit 5, d */ do_test_bit(instruction, REG_D, 5); T_COUNT(8); break; case 0x6B: /* bit 5, e */ do_test_bit(instruction, REG_E, 5); T_COUNT(8); break; case 0x6C: /* bit 5, h */ do_test_bit(instruction, REG_H, 5); T_COUNT(8); break; case 0x6D: /* bit 5, l */ do_test_bit(instruction, REG_L, 5); T_COUNT(8); break; case 0x77: /* bit 6, a */ do_test_bit(instruction, REG_A, 6); T_COUNT(8); break; case 0x70: /* bit 6, b */ do_test_bit(instruction, REG_B, 6); T_COUNT(8); break; case 0x71: /* bit 6, c */ do_test_bit(instruction, REG_C, 6); T_COUNT(8); break; case 0x72: /* bit 6, d */ do_test_bit(instruction, REG_D, 6); T_COUNT(8); break; case 0x73: /* bit 6, e */ do_test_bit(instruction, REG_E, 6); T_COUNT(8); break; case 0x74: /* bit 6, h */ do_test_bit(instruction, REG_H, 6); T_COUNT(8); break; case 0x75: /* bit 6, l */ do_test_bit(instruction, REG_L, 6); T_COUNT(8); break; case 0x7F: /* bit 7, a */ do_test_bit(instruction, REG_A, 7); T_COUNT(8); break; case 0x78: /* bit 7, b */ do_test_bit(instruction, REG_B, 7); T_COUNT(8); break; case 0x79: /* bit 7, c */ do_test_bit(instruction, REG_C, 7); T_COUNT(8); break; case 0x7A: /* bit 7, d */ do_test_bit(instruction, REG_D, 7); T_COUNT(8); break; case 0x7B: /* bit 7, e */ do_test_bit(instruction, REG_E, 7); T_COUNT(8); break; case 0x7C: /* bit 7, h */ do_test_bit(instruction, REG_H, 7); T_COUNT(8); break; case 0x7D: /* bit 7, l */ do_test_bit(instruction, REG_L, 7); T_COUNT(8); break; case 0x46: /* bit 0, (hl) */ do_test_bit(instruction, mem_read(REG_HL), 0); T_COUNT(12); break; case 0x4E: /* bit 1, (hl) */ do_test_bit(instruction, mem_read(REG_HL), 1); T_COUNT(12); break; case 0x56: /* bit 2, (hl) */ do_test_bit(instruction, mem_read(REG_HL), 2); T_COUNT(12); break; case 0x5E: /* bit 3, (hl) */ do_test_bit(instruction, mem_read(REG_HL), 3); T_COUNT(12); break; case 0x66: /* bit 4, (hl) */ do_test_bit(instruction, mem_read(REG_HL), 4); T_COUNT(12); break; case 0x6E: /* bit 5, (hl) */ do_test_bit(instruction, mem_read(REG_HL), 5); T_COUNT(12); break; case 0x76: /* bit 6, (hl) */ do_test_bit(instruction, mem_read(REG_HL), 6); T_COUNT(12); break; case 0x7E: /* bit 7, (hl) */ do_test_bit(instruction, mem_read(REG_HL), 7); T_COUNT(12); break; case 0x87: /* res 0, a */ REG_A &= ~(1 << 0); T_COUNT(8); break; case 0x80: /* res 0, b */ REG_B &= ~(1 << 0); T_COUNT(8); break; case 0x81: /* res 0, c */ REG_C &= ~(1 << 0); T_COUNT(8); break; case 0x82: /* res 0, d */ REG_D &= ~(1 << 0); T_COUNT(8); break; case 0x83: /* res 0, e */ REG_E &= ~(1 << 0); T_COUNT(8); break; case 0x84: /* res 0, h */ REG_H &= ~(1 << 0); T_COUNT(8); break; case 0x85: /* res 0, l */ REG_L &= ~(1 << 0); T_COUNT(8); break; case 0x8F: /* res 1, a */ REG_A &= ~(1 << 1); T_COUNT(8); break; case 0x88: /* res 1, b */ REG_B &= ~(1 << 1); T_COUNT(8); break; case 0x89: /* res 1, c */ REG_C &= ~(1 << 1); T_COUNT(8); break; case 0x8A: /* res 1, d */ REG_D &= ~(1 << 1); T_COUNT(8); break; case 0x8B: /* res 1, e */ REG_E &= ~(1 << 1); T_COUNT(8); break; case 0x8C: /* res 1, h */ REG_H &= ~(1 << 1); T_COUNT(8); break; case 0x8D: /* res 1, l */ REG_L &= ~(1 << 1); T_COUNT(8); break; case 0x97: /* res 2, a */ REG_A &= ~(1 << 2); T_COUNT(8); break; case 0x90: /* res 2, b */ REG_B &= ~(1 << 2); T_COUNT(8); break; case 0x91: /* res 2, c */ REG_C &= ~(1 << 2); T_COUNT(8); break; case 0x92: /* res 2, d */ REG_D &= ~(1 << 2); T_COUNT(8); break; case 0x93: /* res 2, e */ REG_E &= ~(1 << 2); T_COUNT(8); break; case 0x94: /* res 2, h */ REG_H &= ~(1 << 2); T_COUNT(8); break; case 0x95: /* res 2, l */ REG_L &= ~(1 << 2); T_COUNT(8); break; case 0x9F: /* res 3, a */ REG_A &= ~(1 << 3); T_COUNT(8); break; case 0x98: /* res 3, b */ REG_B &= ~(1 << 3); T_COUNT(8); break; case 0x99: /* res 3, c */ REG_C &= ~(1 << 3); T_COUNT(8); break; case 0x9A: /* res 3, d */ REG_D &= ~(1 << 3); T_COUNT(8); break; case 0x9B: /* res 3, e */ REG_E &= ~(1 << 3); T_COUNT(8); break; case 0x9C: /* res 3, h */ REG_H &= ~(1 << 3); T_COUNT(8); break; case 0x9D: /* res 3, l */ REG_L &= ~(1 << 3); T_COUNT(8); break; case 0xA7: /* res 4, a */ REG_A &= ~(1 << 4); T_COUNT(8); break; case 0xA0: /* res 4, b */ REG_B &= ~(1 << 4); T_COUNT(8); break; case 0xA1: /* res 4, c */ REG_C &= ~(1 << 4); T_COUNT(8); break; case 0xA2: /* res 4, d */ REG_D &= ~(1 << 4); T_COUNT(8); break; case 0xA3: /* res 4, e */ REG_E &= ~(1 << 4); T_COUNT(8); break; case 0xA4: /* res 4, h */ REG_H &= ~(1 << 4); T_COUNT(8); break; case 0xA5: /* res 4, l */ REG_L &= ~(1 << 4); T_COUNT(8); break; case 0xAF: /* res 5, a */ REG_A &= ~(1 << 5); T_COUNT(8); break; case 0xA8: /* res 5, b */ REG_B &= ~(1 << 5); T_COUNT(8); break; case 0xA9: /* res 5, c */ REG_C &= ~(1 << 5); T_COUNT(8); break; case 0xAA: /* res 5, d */ REG_D &= ~(1 << 5); T_COUNT(8); break; case 0xAB: /* res 5, e */ REG_E &= ~(1 << 5); T_COUNT(8); break; case 0xAC: /* res 5, h */ REG_H &= ~(1 << 5); T_COUNT(8); break; case 0xAD: /* res 5, l */ REG_L &= ~(1 << 5); T_COUNT(8); break; case 0xB7: /* res 6, a */ REG_A &= ~(1 << 6); T_COUNT(8); break; case 0xB0: /* res 6, b */ REG_B &= ~(1 << 6); T_COUNT(8); break; case 0xB1: /* res 6, c */ REG_C &= ~(1 << 6); T_COUNT(8); break; case 0xB2: /* res 6, d */ REG_D &= ~(1 << 6); T_COUNT(8); break; case 0xB3: /* res 6, e */ REG_E &= ~(1 << 6); T_COUNT(8); break; case 0xB4: /* res 6, h */ REG_H &= ~(1 << 6); T_COUNT(8); break; case 0xB5: /* res 6, l */ REG_L &= ~(1 << 6); T_COUNT(8); break; case 0xBF: /* res 7, a */ REG_A &= ~(1 << 7); T_COUNT(8); break; case 0xB8: /* res 7, b */ REG_B &= ~(1 << 7); T_COUNT(8); break; case 0xB9: /* res 7, c */ REG_C &= ~(1 << 7); T_COUNT(8); break; case 0xBA: /* res 7, d */ REG_D &= ~(1 << 7); T_COUNT(8); break; case 0xBB: /* res 7, e */ REG_E &= ~(1 << 7); T_COUNT(8); break; case 0xBC: /* res 7, h */ REG_H &= ~(1 << 7); T_COUNT(8); break; case 0xBD: /* res 7, l */ REG_L &= ~(1 << 7); T_COUNT(8); break; case 0x86: /* res 0, (hl) */ mem_write(REG_HL, mem_read(REG_HL) & ~(1 << 0)); T_COUNT(15); break; case 0x8E: /* res 1, (hl) */ mem_write(REG_HL, mem_read(REG_HL) & ~(1 << 1)); T_COUNT(15); break; case 0x96: /* res 2, (hl) */ mem_write(REG_HL, mem_read(REG_HL) & ~(1 << 2)); T_COUNT(15); break; case 0x9E: /* res 3, (hl) */ mem_write(REG_HL, mem_read(REG_HL) & ~(1 << 3)); T_COUNT(15); break; case 0xA6: /* res 4, (hl) */ mem_write(REG_HL, mem_read(REG_HL) & ~(1 << 4)); T_COUNT(15); break; case 0xAE: /* res 5, (hl) */ mem_write(REG_HL, mem_read(REG_HL) & ~(1 << 5)); T_COUNT(15); break; case 0xB6: /* res 6, (hl) */ mem_write(REG_HL, mem_read(REG_HL) & ~(1 << 6)); T_COUNT(15); break; case 0xBE: /* res 7, (hl) */ mem_write(REG_HL, mem_read(REG_HL) & ~(1 << 7)); T_COUNT(15); break; case 0x17: /* rl a */ REG_A = rl_byte(REG_A); T_COUNT(8); break; case 0x10: /* rl b */ REG_B = rl_byte(REG_B); T_COUNT(8); break; case 0x11: /* rl c */ REG_C = rl_byte(REG_C); T_COUNT(8); break; case 0x12: /* rl d */ REG_D = rl_byte(REG_D); T_COUNT(8); break; case 0x13: /* rl e */ REG_E = rl_byte(REG_E); T_COUNT(8); break; case 0x14: /* rl h */ REG_H = rl_byte(REG_H); T_COUNT(8); break; case 0x15: /* rl l */ REG_L = rl_byte(REG_L); T_COUNT(8); break; case 0x16: /* rl (hl) */ mem_write(REG_HL, rl_byte(mem_read(REG_HL))); T_COUNT(15); break; case 0x07: /* rlc a */ REG_A = rlc_byte(REG_A); T_COUNT(8); break; case 0x00: /* rlc b */ REG_B = rlc_byte(REG_B); T_COUNT(8); break; case 0x01: /* rlc c */ REG_C = rlc_byte(REG_C); T_COUNT(8); break; case 0x02: /* rlc d */ REG_D = rlc_byte(REG_D); T_COUNT(8); break; case 0x03: /* rlc e */ REG_E = rlc_byte(REG_E); T_COUNT(8); break; case 0x04: /* rlc h */ REG_H = rlc_byte(REG_H); T_COUNT(8); break; case 0x05: /* rlc l */ REG_L = rlc_byte(REG_L); T_COUNT(8); break; case 0x06: /* rlc (hl) */ mem_write(REG_HL, rlc_byte(mem_read(REG_HL))); T_COUNT(15); break; case 0x1F: /* rr a */ REG_A = rr_byte(REG_A); T_COUNT(8); break; case 0x18: /* rr b */ REG_B = rr_byte(REG_B); T_COUNT(8); break; case 0x19: /* rr c */ REG_C = rr_byte(REG_C); T_COUNT(8); break; case 0x1A: /* rr d */ REG_D = rr_byte(REG_D); T_COUNT(8); break; case 0x1B: /* rr e */ REG_E = rr_byte(REG_E); T_COUNT(8); break; case 0x1C: /* rr h */ REG_H = rr_byte(REG_H); T_COUNT(8); break; case 0x1D: /* rr l */ REG_L = rr_byte(REG_L); T_COUNT(8); break; case 0x1E: /* rr (hl) */ mem_write(REG_HL, rr_byte(mem_read(REG_HL))); T_COUNT(15); break; case 0x0F: /* rrc a */ REG_A = rrc_byte(REG_A); T_COUNT(8); break; case 0x08: /* rrc b */ REG_B = rrc_byte(REG_B); T_COUNT(8); break; case 0x09: /* rrc c */ REG_C = rrc_byte(REG_C); T_COUNT(8); break; case 0x0A: /* rrc d */ REG_D = rrc_byte(REG_D); T_COUNT(8); break; case 0x0B: /* rrc e */ REG_E = rrc_byte(REG_E); T_COUNT(8); break; case 0x0C: /* rrc h */ REG_H = rrc_byte(REG_H); T_COUNT(8); break; case 0x0D: /* rrc l */ REG_L = rrc_byte(REG_L); T_COUNT(8); break; case 0x0E: /* rrc (hl) */ mem_write(REG_HL, rrc_byte(mem_read(REG_HL))); T_COUNT(15); break; case 0xC7: /* set 0, a */ REG_A |= (1 << 0); T_COUNT(8); break; case 0xC0: /* set 0, b */ REG_B |= (1 << 0); T_COUNT(8); break; case 0xC1: /* set 0, c */ REG_C |= (1 << 0); T_COUNT(8); break; case 0xC2: /* set 0, d */ REG_D |= (1 << 0); T_COUNT(8); break; case 0xC3: /* set 0, e */ REG_E |= (1 << 0); T_COUNT(8); break; case 0xC4: /* set 0, h */ REG_H |= (1 << 0); T_COUNT(8); break; case 0xC5: /* set 0, l */ REG_L |= (1 << 0); T_COUNT(8); break; case 0xCF: /* set 1, a */ REG_A |= (1 << 1); T_COUNT(8); break; case 0xC8: /* set 1, b */ REG_B |= (1 << 1); T_COUNT(8); break; case 0xC9: /* set 1, c */ REG_C |= (1 << 1); T_COUNT(8); break; case 0xCA: /* set 1, d */ REG_D |= (1 << 1); T_COUNT(8); break; case 0xCB: /* set 1, e */ REG_E |= (1 << 1); T_COUNT(8); break; case 0xCC: /* set 1, h */ REG_H |= (1 << 1); T_COUNT(8); break; case 0xCD: /* set 1, l */ REG_L |= (1 << 1); T_COUNT(8); break; case 0xD7: /* set 2, a */ REG_A |= (1 << 2); T_COUNT(8); break; case 0xD0: /* set 2, b */ REG_B |= (1 << 2); T_COUNT(8); break; case 0xD1: /* set 2, c */ REG_C |= (1 << 2); T_COUNT(8); break; case 0xD2: /* set 2, d */ REG_D |= (1 << 2); T_COUNT(8); break; case 0xD3: /* set 2, e */ REG_E |= (1 << 2); T_COUNT(8); break; case 0xD4: /* set 2, h */ REG_H |= (1 << 2); T_COUNT(8); break; case 0xD5: /* set 2, l */ REG_L |= (1 << 2); T_COUNT(8); break; case 0xDF: /* set 3, a */ REG_A |= (1 << 3); T_COUNT(8); break; case 0xD8: /* set 3, b */ REG_B |= (1 << 3); T_COUNT(8); break; case 0xD9: /* set 3, c */ REG_C |= (1 << 3); T_COUNT(8); break; case 0xDA: /* set 3, d */ REG_D |= (1 << 3); T_COUNT(8); break; case 0xDB: /* set 3, e */ REG_E |= (1 << 3); T_COUNT(8); break; case 0xDC: /* set 3, h */ REG_H |= (1 << 3); T_COUNT(8); break; case 0xDD: /* set 3, l */ REG_L |= (1 << 3); T_COUNT(8); break; case 0xE7: /* set 4, a */ REG_A |= (1 << 4); T_COUNT(8); break; case 0xE0: /* set 4, b */ REG_B |= (1 << 4); T_COUNT(8); break; case 0xE1: /* set 4, c */ REG_C |= (1 << 4); T_COUNT(8); break; case 0xE2: /* set 4, d */ REG_D |= (1 << 4); T_COUNT(8); break; case 0xE3: /* set 4, e */ REG_E |= (1 << 4); T_COUNT(8); break; case 0xE4: /* set 4, h */ REG_H |= (1 << 4); T_COUNT(8); break; case 0xE5: /* set 4, l */ REG_L |= (1 << 4); T_COUNT(8); break; case 0xEF: /* set 5, a */ REG_A |= (1 << 5); T_COUNT(8); break; case 0xE8: /* set 5, b */ REG_B |= (1 << 5); T_COUNT(8); break; case 0xE9: /* set 5, c */ REG_C |= (1 << 5); T_COUNT(8); break; case 0xEA: /* set 5, d */ REG_D |= (1 << 5); T_COUNT(8); break; case 0xEB: /* set 5, e */ REG_E |= (1 << 5); T_COUNT(8); break; case 0xEC: /* set 5, h */ REG_H |= (1 << 5); T_COUNT(8); break; case 0xED: /* set 5, l */ REG_L |= (1 << 5); T_COUNT(8); break; case 0xF7: /* set 6, a */ REG_A |= (1 << 6); T_COUNT(8); break; case 0xF0: /* set 6, b */ REG_B |= (1 << 6); T_COUNT(8); break; case 0xF1: /* set 6, c */ REG_C |= (1 << 6); T_COUNT(8); break; case 0xF2: /* set 6, d */ REG_D |= (1 << 6); T_COUNT(8); break; case 0xF3: /* set 6, e */ REG_E |= (1 << 6); T_COUNT(8); break; case 0xF4: /* set 6, h */ REG_H |= (1 << 6); T_COUNT(8); break; case 0xF5: /* set 6, l */ REG_L |= (1 << 6); T_COUNT(8); break; case 0xFF: /* set 7, a */ REG_A |= (1 << 7); T_COUNT(8); break; case 0xF8: /* set 7, b */ REG_B |= (1 << 7); T_COUNT(8); break; case 0xF9: /* set 7, c */ REG_C |= (1 << 7); T_COUNT(8); break; case 0xFA: /* set 7, d */ REG_D |= (1 << 7); T_COUNT(8); break; case 0xFB: /* set 7, e */ REG_E |= (1 << 7); T_COUNT(8); break; case 0xFC: /* set 7, h */ REG_H |= (1 << 7); T_COUNT(8); break; case 0xFD: /* set 7, l */ REG_L |= (1 << 7); T_COUNT(8); break; case 0xC6: /* set 0, (hl) */ mem_write(REG_HL, mem_read(REG_HL) | (1 << 0)); T_COUNT(15); break; case 0xCE: /* set 1, (hl) */ mem_write(REG_HL, mem_read(REG_HL) | (1 << 1)); T_COUNT(15); break; case 0xD6: /* set 2, (hl) */ mem_write(REG_HL, mem_read(REG_HL) | (1 << 2)); T_COUNT(15); break; case 0xDE: /* set 3, (hl) */ mem_write(REG_HL, mem_read(REG_HL) | (1 << 3)); T_COUNT(15); break; case 0xE6: /* set 4, (hl) */ mem_write(REG_HL, mem_read(REG_HL) | (1 << 4)); T_COUNT(15); break; case 0xEE: /* set 5, (hl) */ mem_write(REG_HL, mem_read(REG_HL) | (1 << 5)); T_COUNT(15); break; case 0xF6: /* set 6, (hl) */ mem_write(REG_HL, mem_read(REG_HL) | (1 << 6)); T_COUNT(15); break; case 0xFE: /* set 7, (hl) */ mem_write(REG_HL, mem_read(REG_HL) | (1 << 7)); T_COUNT(15); break; case 0x27: /* sla a */ REG_A = sla_byte(REG_A); T_COUNT(8); break; case 0x20: /* sla b */ REG_B = sla_byte(REG_B); T_COUNT(8); break; case 0x21: /* sla c */ REG_C = sla_byte(REG_C); T_COUNT(8); break; case 0x22: /* sla d */ REG_D = sla_byte(REG_D); T_COUNT(8); break; case 0x23: /* sla e */ REG_E = sla_byte(REG_E); T_COUNT(8); break; case 0x24: /* sla h */ REG_H = sla_byte(REG_H); T_COUNT(8); break; case 0x25: /* sla l */ REG_L = sla_byte(REG_L); T_COUNT(8); break; case 0x26: /* sla (hl) */ mem_write(REG_HL, sla_byte(mem_read(REG_HL))); T_COUNT(15); break; case 0x2F: /* sra a */ REG_A = sra_byte(REG_A); T_COUNT(8); break; case 0x28: /* sra b */ REG_B = sra_byte(REG_B); T_COUNT(8); break; case 0x29: /* sra c */ REG_C = sra_byte(REG_C); T_COUNT(8); break; case 0x2A: /* sra d */ REG_D = sra_byte(REG_D); T_COUNT(8); break; case 0x2B: /* sra e */ REG_E = sra_byte(REG_E); T_COUNT(8); break; case 0x2C: /* sra h */ REG_H = sra_byte(REG_H); T_COUNT(8); break; case 0x2D: /* sra l */ REG_L = sra_byte(REG_L); T_COUNT(8); break; case 0x2E: /* sra (hl) */ mem_write(REG_HL, sra_byte(mem_read(REG_HL))); T_COUNT(15); break; case 0x37: /* slia a [undocumented] */ REG_A = slia_byte(REG_A); T_COUNT(8); break; case 0x30: /* slia b [undocumented] */ REG_B = slia_byte(REG_B); T_COUNT(8); break; case 0x31: /* slia c [undocumented] */ REG_C = slia_byte(REG_C); T_COUNT(8); break; case 0x32: /* slia d [undocumented] */ REG_D = slia_byte(REG_D); T_COUNT(8); break; case 0x33: /* slia e [undocumented] */ REG_E = slia_byte(REG_E); T_COUNT(8); break; case 0x34: /* slia h [undocumented] */ REG_H = slia_byte(REG_H); T_COUNT(8); break; case 0x35: /* slia l [undocumented] */ REG_L = slia_byte(REG_L); T_COUNT(8); break; case 0x36: /* slia (hl) [undocumented] */ mem_write(REG_HL, slia_byte(mem_read(REG_HL))); T_COUNT(15); break; case 0x3F: /* srl a */ REG_A = srl_byte(REG_A); T_COUNT(8); break; case 0x38: /* srl b */ REG_B = srl_byte(REG_B); T_COUNT(8); break; case 0x39: /* srl c */ REG_C = srl_byte(REG_C); T_COUNT(8); break; case 0x3A: /* srl d */ REG_D = srl_byte(REG_D); T_COUNT(8); break; case 0x3B: /* srl e */ REG_E = srl_byte(REG_E); T_COUNT(8); break; case 0x3C: /* srl h */ REG_H = srl_byte(REG_H); T_COUNT(8); break; case 0x3D: /* srl l */ REG_L = srl_byte(REG_L); T_COUNT(8); break; case 0x3E: /* srl (hl) */ mem_write(REG_HL, srl_byte(mem_read(REG_HL))); T_COUNT(15); break; default: disassemble(REG_PC - 2); error("unsupported instruction"); } } /* * Extended instructions which have 0xDD or 0xFD as the first byte: */ static void do_indexed_instruction(Ushort *ixp) { Uchar instruction; instruction = mem_read(REG_PC++); switch(instruction) { /* same for FD, except uses IY */ case 0x8E: /* adc a, (ix + offset) */ do_adc_byte(mem_read(*ixp + (signed char) mem_read(REG_PC++))); T_COUNT(19); break; case 0x86: /* add a, (ix + offset) */ do_add_byte(mem_read(*ixp + (signed char) mem_read(REG_PC++))); T_COUNT(19); break; case 0x09: /* add ix, bc */ do_add_word_index(ixp, REG_BC); T_COUNT(15); break; case 0x19: /* add ix, de */ do_add_word_index(ixp, REG_DE); T_COUNT(15); break; case 0x29: /* add ix, ix */ do_add_word_index(ixp, *ixp); T_COUNT(15); break; case 0x39: /* add ix, sp */ do_add_word_index(ixp, REG_SP); T_COUNT(15); break; case 0xA6: /* and (ix + offset) */ do_and_byte(mem_read(*ixp + (signed char) mem_read(REG_PC++))); T_COUNT(19); break; case 0xBE: /* cp (ix + offset) */ do_cp(mem_read(*ixp + (signed char) mem_read(REG_PC++))); T_COUNT(19); break; case 0x35: /* dec (ix + offset) */ { Ushort address; Uchar value; address = *ixp + (signed char) mem_read(REG_PC++); value = mem_read(address) - 1; mem_write(address, value); do_flags_dec_byte(value); } T_COUNT(23); break; case 0x2B: /* dec ix */ (*ixp)--; T_COUNT(10); break; case 0xE3: /* ex (sp), ix */ { Ushort temp; temp = mem_read_word(REG_SP); mem_write_word(REG_SP, *ixp); *ixp = temp; } T_COUNT(23); break; case 0x34: /* inc (ix + offset) */ { Ushort address; Uchar value; address = *ixp + (signed char) mem_read(REG_PC++); value = mem_read(address) + 1; mem_write(address, value); do_flags_inc_byte(value); } T_COUNT(23); break; case 0x23: /* inc ix */ (*ixp)++; T_COUNT(10); break; case 0xE9: /* jp (ix) */ REG_PC = *ixp; T_COUNT(8); break; case 0x7E: /* ld a, (ix + offset) */ REG_A = mem_read(*ixp + (signed char) mem_read(REG_PC++)); T_COUNT(19); break; case 0x46: /* ld b, (ix + offset) */ REG_B = mem_read(*ixp + (signed char) mem_read(REG_PC++)); T_COUNT(19); break; case 0x4E: /* ld c, (ix + offset) */ REG_C = mem_read(*ixp + (signed char) mem_read(REG_PC++)); T_COUNT(19); break; case 0x56: /* ld d, (ix + offset) */ REG_D = mem_read(*ixp + (signed char) mem_read(REG_PC++)); T_COUNT(19); break; case 0x5E: /* ld e, (ix + offset) */ REG_E = mem_read(*ixp + (signed char) mem_read(REG_PC++)); T_COUNT(19); break; case 0x66: /* ld h, (ix + offset) */ REG_H = mem_read(*ixp + (signed char) mem_read(REG_PC++)); T_COUNT(19); break; case 0x6E: /* ld l, (ix + offset) */ REG_L = mem_read(*ixp + (signed char) mem_read(REG_PC++)); T_COUNT(19); break; case 0x36: /* ld (ix + offset), value */ mem_write(*ixp + (signed char) mem_read(REG_PC), mem_read(REG_PC+1)); REG_PC += 2; T_COUNT(19); break; case 0x77: /* ld (ix + offset), a */ mem_write(*ixp + (signed char) mem_read(REG_PC++), REG_A); T_COUNT(19); break; case 0x70: /* ld (ix + offset), b */ mem_write(*ixp + (signed char) mem_read(REG_PC++), REG_B); T_COUNT(19); break; case 0x71: /* ld (ix + offset), c */ mem_write(*ixp + (signed char) mem_read(REG_PC++), REG_C); T_COUNT(19); break; case 0x72: /* ld (ix + offset), d */ mem_write(*ixp + (signed char) mem_read(REG_PC++), REG_D); T_COUNT(19); break; case 0x73: /* ld (ix + offset), e */ mem_write(*ixp + (signed char) mem_read(REG_PC++), REG_E); T_COUNT(19); break; case 0x74: /* ld (ix + offset), h */ mem_write(*ixp + (signed char) mem_read(REG_PC++), REG_H); T_COUNT(19); break; case 0x75: /* ld (ix + offset), l */ mem_write(*ixp + (signed char) mem_read(REG_PC++), REG_L); T_COUNT(19); break; case 0x22: /* ld (address), ix */ mem_write_word(mem_read_word(REG_PC), *ixp); REG_PC += 2; T_COUNT(20); break; case 0xF9: /* ld sp, ix */ REG_SP = *ixp; T_COUNT(10); break; case 0x21: /* ld ix, value */ *ixp = mem_read_word(REG_PC); REG_PC += 2; T_COUNT(14); break; case 0x2A: /* ld ix, (address) */ *ixp = mem_read_word(mem_read_word(REG_PC)); REG_PC += 2; T_COUNT(20); break; case 0xB6: /* or (ix + offset) */ do_or_byte(mem_read(*ixp + (signed char) mem_read(REG_PC++))); T_COUNT(19); break; case 0xE1: /* pop ix */ *ixp = mem_read_word(REG_SP); REG_SP += 2; T_COUNT(14); break; case 0xE5: /* push ix */ REG_SP -= 2; mem_write_word(REG_SP, *ixp); T_COUNT(15); break; case 0x9E: /* sbc a, (ix + offset) */ do_sbc_byte(mem_read(*ixp + (signed char) mem_read(REG_PC++))); T_COUNT(19); break; case 0x96: /* sub a, (ix + offset) */ do_sub_byte(mem_read(*ixp + (signed char) mem_read(REG_PC++))); T_COUNT(19); break; case 0xAE: /* xor (ix + offset) */ do_xor_byte(mem_read(*ixp + (signed char) mem_read(REG_PC++))); T_COUNT(19); break; case 0xCB: { signed char offset, result = 0; Uchar sub_instruction; offset = (signed char) mem_read(REG_PC++); sub_instruction = mem_read(REG_PC++); /* Instructions with (sub_instruction & 7) != 6 are undocumented; their extra effect is handled after this switch */ switch(sub_instruction&0xf8) { case 0x00: /* rlc (ix + offset) */ result = rlc_byte(mem_read(*ixp + offset)); mem_write(*ixp + offset, result); T_COUNT(23); break; case 0x08: /* rrc (ix + offset) */ result = rrc_byte(mem_read(*ixp + offset)); mem_write(*ixp + offset, result); T_COUNT(23); break; case 0x10: /* rl (ix + offset) */ result = rl_byte(mem_read(*ixp + offset)); mem_write(*ixp + offset, result); T_COUNT(23); break; case 0x18: /* rr (ix + offset) */ result = rr_byte(mem_read(*ixp + offset)); mem_write(*ixp + offset, result); T_COUNT(23); break; case 0x20: /* sla (ix + offset) */ result = sla_byte(mem_read(*ixp + offset)); mem_write(*ixp + offset, result); T_COUNT(23); break; case 0x28: /* sra (ix + offset) */ result = sra_byte(mem_read(*ixp + offset)); mem_write(*ixp + offset, result); T_COUNT(23); break; case 0x30: /* slia (ix + offset) [undocumented] */ result = slia_byte(mem_read(*ixp + offset)); mem_write(*ixp + offset, result); T_COUNT(23); break; case 0x38: /* srl (ix + offset) */ result = srl_byte(mem_read(*ixp + offset)); mem_write(*ixp + offset, result); T_COUNT(23); break; case 0x40: /* bit 0, (ix + offset) */ case 0x48: /* bit 1, (ix + offset) */ case 0x50: /* bit 2, (ix + offset) */ case 0x58: /* bit 3, (ix + offset) */ case 0x60: /* bit 4, (ix + offset) */ case 0x68: /* bit 5, (ix + offset) */ case 0x70: /* bit 6, (ix + offset) */ case 0x78: /* bit 7, (ix + offset) */ do_test_bit(sub_instruction, mem_read(*ixp + offset), (sub_instruction >> 3) & 7); T_COUNT(20); break; case 0x80: /* res 0, (ix + offset) */ case 0x88: /* res 1, (ix + offset) */ case 0x90: /* res 2, (ix + offset) */ case 0x98: /* res 3, (ix + offset) */ case 0xA0: /* res 4, (ix + offset) */ case 0xA8: /* res 5, (ix + offset) */ case 0xB0: /* res 6, (ix + offset) */ case 0xB8: /* res 7, (ix + offset) */ result = mem_read(*ixp + offset) & ~(1 << ((sub_instruction >> 3) & 7)); mem_write(*ixp + offset, result); T_COUNT(23); break; case 0xC0: /* set 0, (ix + offset) */ case 0xC8: /* set 1, (ix + offset) */ case 0xD0: /* set 2, (ix + offset) */ case 0xD8: /* set 3, (ix + offset) */ case 0xE0: /* set 4, (ix + offset) */ case 0xE8: /* set 5, (ix + offset) */ case 0xF0: /* set 6, (ix + offset) */ case 0xF8: /* set 7, (ix + offset) */ result = mem_read(*ixp + offset) | (1 << ((sub_instruction >> 3) & 7)); mem_write(*ixp + offset, result); T_COUNT(23); break; } if (sub_instruction < 0x40 || sub_instruction > 0x7f) { switch (sub_instruction & 7) { /* Undocumented cases */ case 0: REG_B = result; break; case 1: REG_C = result; break; case 2: REG_D = result; break; case 3: REG_E = result; break; case 4: REG_H = result; break; case 5: REG_L = result; break; case 7: REG_A = result; break; } } } break; /* begin undocumented instructions -- timings are a (good) guess */ case 0x8C: /* adc a, ixh */ do_adc_byte(HIGH(ixp)); T_COUNT(8); break; case 0x8D: /* adc a, ixl */ do_adc_byte(LOW(ixp)); T_COUNT(8); break; case 0x84: /* add a, ixh */ do_add_byte(HIGH(ixp)); T_COUNT(8); break; case 0x85: /* add a, ixl */ do_add_byte(LOW(ixp)); T_COUNT(8); break; case 0xA4: /* and ixh */ do_and_byte(HIGH(ixp)); T_COUNT(8); break; case 0xA5: /* and ixl */ do_and_byte(LOW(ixp)); T_COUNT(8); break; case 0xBC: /* cp ixh */ do_cp(HIGH(ixp)); T_COUNT(8); break; case 0xBD: /* cp ixl */ do_cp(LOW(ixp)); T_COUNT(8); break; case 0x25: /* dec ixh */ do_flags_dec_byte(--HIGH(ixp)); T_COUNT(8); break; case 0x2D: /* dec ixl */ do_flags_dec_byte(--LOW(ixp)); T_COUNT(8); break; case 0x24: /* inc ixh */ HIGH(ixp)++; do_flags_inc_byte(HIGH(ixp)); T_COUNT(8); break; case 0x2C: /* inc ixl */ LOW(ixp)++; do_flags_inc_byte(LOW(ixp)); T_COUNT(8); break; case 0x7C: /* ld a, ixh */ REG_A = HIGH(ixp); T_COUNT(8); break; case 0x7D: /* ld a, ixl */ REG_A = LOW(ixp); T_COUNT(8); break; case 0x44: /* ld b, ixh */ REG_B = HIGH(ixp); T_COUNT(8); break; case 0x45: /* ld b, ixl */ REG_B = LOW(ixp); T_COUNT(8); break; case 0x4C: /* ld c, ixh */ REG_C = HIGH(ixp); T_COUNT(8); break; case 0x4D: /* ld c, ixl */ REG_C = LOW(ixp); T_COUNT(8); break; case 0x54: /* ld d, ixh */ REG_D = HIGH(ixp); T_COUNT(8); break; case 0x55: /* ld d, ixl */ REG_D = LOW(ixp); T_COUNT(8); break; case 0x5C: /* ld e, ixh */ REG_E = HIGH(ixp); T_COUNT(8); break; case 0x5D: /* ld e, ixl */ REG_E = LOW(ixp); T_COUNT(8); break; case 0x67: /* ld ixh, a */ HIGH(ixp) = REG_A; T_COUNT(8); break; case 0x60: /* ld ixh, b */ HIGH(ixp) = REG_B; T_COUNT(8); break; case 0x61: /* ld ixh, c */ HIGH(ixp) = REG_C; T_COUNT(8); break; case 0x62: /* ld ixh, d */ HIGH(ixp) = REG_D; T_COUNT(8); break; case 0x63: /* ld ixh, e */ HIGH(ixp) = REG_E; T_COUNT(8); break; case 0x64: /* ld ixh, ixh */ HIGH(ixp) = HIGH(ixp); T_COUNT(8); break; case 0x65: /* ld ixh, ixl */ HIGH(ixp) = LOW(ixp); T_COUNT(8); break; case 0x6F: /* ld ixl, a */ LOW(ixp) = REG_A; T_COUNT(8); break; case 0x68: /* ld ixl, b */ LOW(ixp) = REG_B; T_COUNT(8); break; case 0x69: /* ld ixl, c */ LOW(ixp) = REG_C; T_COUNT(8); break; case 0x6A: /* ld ixl, d */ LOW(ixp) = REG_D; T_COUNT(8); break; case 0x6B: /* ld ixl, e */ LOW(ixp) = REG_E; T_COUNT(8); break; case 0x6C: /* ld ixl, ixh */ LOW(ixp) = HIGH(ixp); T_COUNT(8); break; case 0x6D: /* ld ixl, ixl */ LOW(ixp) = LOW(ixp); T_COUNT(8); break; case 0x26: /* ld ixh, value */ HIGH(ixp) = mem_read(REG_PC++); T_COUNT(11); break; case 0x2E: /* ld ixl, value */ LOW(ixp) = mem_read(REG_PC++); T_COUNT(11); break; case 0xB4: /* or ixh */ do_or_byte(HIGH(ixp)); T_COUNT(8); break; case 0xB5: /* or ixl */ do_or_byte(LOW(ixp)); T_COUNT(8); break; case 0x9C: /* sbc a, ixh */ do_sbc_byte(HIGH(ixp)); T_COUNT(8); break; case 0x9D: /* sbc a, ixl */ do_sbc_byte(LOW(ixp)); T_COUNT(8); break; case 0x94: /* sub a, ixh */ do_sub_byte(HIGH(ixp)); T_COUNT(8); break; case 0x95: /* sub a, ixl */ do_sub_byte(LOW(ixp)); T_COUNT(8); break; case 0xAC: /* xor ixh */ do_xor_byte(HIGH(ixp)); T_COUNT(8); break; case 0xAD: /* xor ixl */ do_xor_byte(LOW(ixp)); T_COUNT(8); break; /* end undocumented instructions */ default: /* Ignore DD or FD prefix and retry as normal instruction; this is a correct emulation. [undocumented, timing guessed] */ REG_PC--; T_COUNT(4); break; } } /* * Extended instructions which have 0xED as the first byte: */ static int do_ED_instruction() { Uchar instruction; int debug = 0; instruction = mem_read(REG_PC++); switch(instruction) { case 0x4A: /* adc hl, bc */ do_adc_word(REG_BC); T_COUNT(15); break; case 0x5A: /* adc hl, de */ do_adc_word(REG_DE); T_COUNT(15); break; case 0x6A: /* adc hl, hl */ do_adc_word(REG_HL); T_COUNT(15); break; case 0x7A: /* adc hl, sp */ do_adc_word(REG_SP); T_COUNT(15); break; case 0xA9: /* cpd */ do_cpd(); break; case 0xB9: /* cpdr */ do_cpdr(); break; case 0xA1: /* cpi */ do_cpi(); break; case 0xB1: /* cpir */ do_cpir(); break; case 0x46: /* im 0 */ case 0x66: /* im 0 [undocumented]*/ do_im0(); T_COUNT(8); break; case 0x56: /* im 1 */ case 0x76: /* im 1 [undocumented] */ do_im1(); T_COUNT(8); break; case 0x5E: /* im 2 */ case 0x7E: /* im 2 [undocumented] */ do_im2(); T_COUNT(8); break; case 0x78: /* in a, (c) */ REG_A = in_with_flags(REG_C); T_COUNT(11); break; case 0x40: /* in b, (c) */ REG_B = in_with_flags(REG_C); T_COUNT(11); break; case 0x48: /* in c, (c) */ REG_C = in_with_flags(REG_C); T_COUNT(11); break; case 0x50: /* in d, (c) */ REG_D = in_with_flags(REG_C); T_COUNT(11); break; case 0x58: /* in e, (c) */ REG_E = in_with_flags(REG_C); T_COUNT(11); break; case 0x60: /* in h, (c) */ REG_H = in_with_flags(REG_C); T_COUNT(11); break; case 0x68: /* in l, (c) */ REG_L = in_with_flags(REG_C); T_COUNT(11); break; case 0x70: /* in (c) [undocumented] */ (void) in_with_flags(REG_C); T_COUNT(11); break; case 0xAA: /* ind */ do_ind(); break; case 0xBA: /* indr */ do_indr(); break; case 0xA2: /* ini */ do_ini(); break; case 0xB2: /* inir */ do_inir(); break; case 0x57: /* ld a, i */ do_ld_a_i(); T_COUNT(9); break; case 0x47: /* ld i, a */ REG_I = REG_A; T_COUNT(9); break; case 0x5F: /* ld a, r */ do_ld_a_r(); T_COUNT(9); break; case 0x4F: /* ld r, a */ /* unimplemented; ignore */ T_COUNT(9); break; case 0x4B: /* ld bc, (address) */ REG_BC = mem_read_word(mem_read_word(REG_PC)); REG_PC += 2; T_COUNT(20); break; case 0x5B: /* ld de, (address) */ REG_DE = mem_read_word(mem_read_word(REG_PC)); REG_PC += 2; T_COUNT(20); break; case 0x6B: /* ld hl, (address) */ /* this instruction is redundant with the 2A instruction */ REG_HL = mem_read_word(mem_read_word(REG_PC)); REG_PC += 2; T_COUNT(20); break; case 0x7B: /* ld sp, (address) */ REG_SP = mem_read_word(mem_read_word(REG_PC)); REG_PC += 2; T_COUNT(20); break; case 0x43: /* ld (address), bc */ mem_write_word(mem_read_word(REG_PC), REG_BC); REG_PC += 2; T_COUNT(20); break; case 0x53: /* ld (address), de */ mem_write_word(mem_read_word(REG_PC), REG_DE); REG_PC += 2; T_COUNT(20); break; case 0x63: /* ld (address), hl */ /* this instruction is redundant with the 22 instruction */ mem_write_word(mem_read_word(REG_PC), REG_HL); REG_PC += 2; T_COUNT(20); break; case 0x73: /* ld (address), sp */ mem_write_word(mem_read_word(REG_PC), REG_SP); REG_PC += 2; T_COUNT(20); break; case 0xA8: /* ldd */ do_ldd(); break; case 0xB8: /* lddr */ do_lddr(); break; case 0xA0: /* ldi */ do_ldi(); break; case 0xB0: /* ldir */ do_ldir(); break; case 0x44: /* neg */ case 0x4C: /* neg [undocumented] */ case 0x54: /* neg [undocumented] */ case 0x5C: /* neg [undocumented] */ case 0x64: /* neg [undocumented] */ case 0x6C: /* neg [undocumented] */ case 0x74: /* neg [undocumented] */ case 0x7C: /* neg [undocumented] */ do_negate(); T_COUNT(8); break; case 0x79: /* out (c), a */ z80_out(REG_C, REG_A); T_COUNT(12); break; case 0x41: /* out (c), b */ z80_out(REG_C, REG_B); T_COUNT(12); break; case 0x49: /* out (c), c */ z80_out(REG_C, REG_C); T_COUNT(12); break; case 0x51: /* out (c), d */ z80_out(REG_C, REG_D); T_COUNT(12); break; case 0x59: /* out (c), e */ z80_out(REG_C, REG_E); T_COUNT(12); break; case 0x61: /* out (c), h */ z80_out(REG_C, REG_H); T_COUNT(12); break; case 0x69: /* out (c), l */ z80_out(REG_C, REG_L); T_COUNT(12); break; case 0x71: /* out (c), 0 [undocumented] */ z80_out(REG_C, 0); T_COUNT(12); break; case 0xAB: /* outd */ do_outd(); break; case 0xBB: /* outdr */ do_outdr(); break; case 0xA3: /* outi */ do_outi(); break; case 0xB3: /* outir */ do_outir(); break; case 0x4D: /* reti */ /* no support for alerting peripherals, just like ret */ REG_PC = mem_read_word(REG_SP); REG_SP += 2; T_COUNT(14); break; case 0x45: /* retn */ REG_PC = mem_read_word(REG_SP); REG_SP += 2; z80_state.iff1 = z80_state.iff2; /* restore the iff state */ T_COUNT(14); break; case 0x55: /* ret [undocumented] */ case 0x5D: /* ret [undocumented] */ case 0x65: /* ret [undocumented] */ case 0x6D: /* ret [undocumented] */ case 0x75: /* ret [undocumented] */ case 0x7D: /* ret [undocumented] */ REG_PC = mem_read_word(REG_SP); REG_SP += 2; T_COUNT(14); break; case 0x6F: /* rld */ do_rld(); T_COUNT(18); break; case 0x67: /* rrd */ do_rrd(); T_COUNT(18); break; case 0x42: /* sbc hl, bc */ do_sbc_word(REG_BC); T_COUNT(15); break; case 0x52: /* sbc hl, de */ do_sbc_word(REG_DE); T_COUNT(15); break; case 0x62: /* sbc hl, hl */ do_sbc_word(REG_HL); T_COUNT(15); break; case 0x72: /* sbc hl, sp */ do_sbc_word(REG_SP); T_COUNT(15); break; /* Emulator traps -- not real Z-80 instructions */ case 0x28: /* emt_system */ do_emt_system(); break; case 0x29: /* emt_mouse */ do_emt_mouse(); break; case 0x2a: /* emt_getddir */ do_emt_getddir(); break; case 0x2b: /* emt_setddir */ do_emt_setddir(); break; case 0x2f: /* emt_debug */ if (trs_continuous > 0) trs_continuous = 0; debug = 1; break; case 0x30: /* emt_open */ do_emt_open(); break; case 0x31: /* emt_close */ do_emt_close(); break; case 0x32: /* emt_read */ do_emt_read(); break; case 0x33: /* emt_write */ do_emt_write(); break; case 0x34: /* emt_lseek */ do_emt_lseek(); break; case 0x35: /* emt_strerror */ do_emt_strerror(); break; case 0x36: /* emt_time */ do_emt_time(); break; case 0x37: /* emt_opendir */ do_emt_opendir(); break; case 0x38: /* emt_closedir */ do_emt_closedir(); break; case 0x39: /* emt_readdir */ do_emt_readdir(); break; case 0x3a: /* emt_chdir */ do_emt_chdir(); break; case 0x3b: /* emt_getcwd */ do_emt_getcwd(); break; case 0x3c: /* emt_misc */ do_emt_misc(); break; case 0x3d: /* emt_ftruncate */ do_emt_ftruncate(); break; case 0x3e: /* emt_opendisk */ do_emt_opendisk(); break; case 0x3f: /* emt_closedisk */ do_emt_closedisk(); break; default: disassemble(REG_PC - 2); error("unsupported instruction"); } return debug; } volatile int x_poll_count = 0; #define X_POLL_INTERVAL 10000 int trs_continuous; int z80_run(int continuous) /* * -1 = single-step and disallow interrupts * 0 = single-step * 1 = continuous */ { Uchar instruction; Ushort address; /* generic temps */ int ret = 0; int i; trs_continuous = continuous; /* loop to do a z80 instruction */ do { /* We need to poll for X events periodically. That also flushes output to the X server. */ if (x_poll_count <= 0) { x_poll_count = X_POLL_INTERVAL; trs_get_event(0); } else { x_poll_count--; } /* Speed control */ if ((i = z80_state.delay)) { volatile int dummy; while (--i) dummy = i; } instruction = mem_read(REG_PC++); switch(instruction) { case 0xCB: /* CB.. extended instruction */ do_CB_instruction(); break; case 0xDD: /* DD.. extended instruction */ do_indexed_instruction(®_IX); break; case 0xED: /* ED.. extended instruction */ ret = do_ED_instruction(); break; case 0xFD: /* FD.. extended instruction */ do_indexed_instruction(®_IY); break; case 0x8F: /* adc a, a */ do_adc_byte(REG_A); T_COUNT(4); break; case 0x88: /* adc a, b */ do_adc_byte(REG_B); T_COUNT(4); break; case 0x89: /* adc a, c */ do_adc_byte(REG_C); T_COUNT(4); break; case 0x8A: /* adc a, d */ do_adc_byte(REG_D); T_COUNT(4); break; case 0x8B: /* adc a, e */ do_adc_byte(REG_E); T_COUNT(4); break; case 0x8C: /* adc a, h */ do_adc_byte(REG_H); T_COUNT(4); break; case 0x8D: /* adc a, l */ do_adc_byte(REG_L); T_COUNT(4); break; case 0xCE: /* adc a, value */ do_adc_byte(mem_read(REG_PC++)); T_COUNT(7); break; case 0x8E: /* adc a, (hl) */ do_adc_byte(mem_read(REG_HL)); T_COUNT(7); break; case 0x87: /* add a, a */ do_add_byte(REG_A); T_COUNT(4); break; case 0x80: /* add a, b */ do_add_byte(REG_B); T_COUNT(4); break; case 0x81: /* add a, c */ do_add_byte(REG_C); T_COUNT(4); break; case 0x82: /* add a, d */ do_add_byte(REG_D); T_COUNT(4); break; case 0x83: /* add a, e */ do_add_byte(REG_E); T_COUNT(4); break; case 0x84: /* add a, h */ do_add_byte(REG_H); T_COUNT(4); break; case 0x85: /* add a, l */ do_add_byte(REG_L); T_COUNT(4); break; case 0xC6: /* add a, value */ do_add_byte(mem_read(REG_PC++)); T_COUNT(7); break; case 0x86: /* add a, (hl) */ do_add_byte(mem_read(REG_HL)); T_COUNT(7); break; case 0x09: /* add hl, bc */ do_add_word(REG_BC); T_COUNT(11); break; case 0x19: /* add hl, de */ do_add_word(REG_DE); T_COUNT(11); break; case 0x29: /* add hl, hl */ do_add_word(REG_HL); T_COUNT(11); break; case 0x39: /* add hl, sp */ do_add_word(REG_SP); T_COUNT(11); break; case 0xA7: /* and a */ do_and_byte(REG_A); T_COUNT(4); break; case 0xA0: /* and b */ do_and_byte(REG_B); T_COUNT(4); break; case 0xA1: /* and c */ do_and_byte(REG_C); T_COUNT(4); break; case 0xA2: /* and d */ do_and_byte(REG_D); T_COUNT(4); break; case 0xA3: /* and e */ do_and_byte(REG_E); T_COUNT(4); break; case 0xA4: /* and h */ do_and_byte(REG_H); T_COUNT(4); break; case 0xA5: /* and l */ do_and_byte(REG_L); T_COUNT(4); break; case 0xE6: /* and value */ do_and_byte(mem_read(REG_PC++)); T_COUNT(7); break; case 0xA6: /* and (hl) */ do_and_byte(mem_read(REG_HL)); T_COUNT(7); break; case 0xCD: /* call address */ address = mem_read_word(REG_PC); REG_SP -= 2; mem_write_word(REG_SP, REG_PC + 2); REG_PC = address; T_COUNT(17); break; case 0xC4: /* call nz, address */ if(!ZERO_FLAG) { address = mem_read_word(REG_PC); REG_SP -= 2; mem_write_word(REG_SP, REG_PC + 2); REG_PC = address; T_COUNT(17); } else { REG_PC += 2; T_COUNT(10); } break; case 0xCC: /* call z, address */ if(ZERO_FLAG) { address = mem_read_word(REG_PC); REG_SP -= 2; mem_write_word(REG_SP, REG_PC + 2); REG_PC = address; T_COUNT(17); } else { REG_PC += 2; T_COUNT(10); } break; case 0xD4: /* call nc, address */ if(!CARRY_FLAG) { address = mem_read_word(REG_PC); REG_SP -= 2; mem_write_word(REG_SP, REG_PC + 2); REG_PC = address; T_COUNT(17); } else { REG_PC += 2; T_COUNT(10); } break; case 0xDC: /* call c, address */ if(CARRY_FLAG) { address = mem_read_word(REG_PC); REG_SP -= 2; mem_write_word(REG_SP, REG_PC + 2); REG_PC = address; T_COUNT(17); } else { REG_PC += 2; T_COUNT(10); } break; case 0xE4: /* call po, address */ if(!PARITY_FLAG) { address = mem_read_word(REG_PC); REG_SP -= 2; mem_write_word(REG_SP, REG_PC + 2); REG_PC = address; T_COUNT(17); } else { REG_PC += 2; T_COUNT(10); } break; case 0xEC: /* call pe, address */ if(PARITY_FLAG) { address = mem_read_word(REG_PC); REG_SP -= 2; mem_write_word(REG_SP, REG_PC + 2); REG_PC = address; T_COUNT(17); } else { REG_PC += 2; T_COUNT(10); } break; case 0xF4: /* call p, address */ if(!SIGN_FLAG) { address = mem_read_word(REG_PC); REG_SP -= 2; mem_write_word(REG_SP, REG_PC + 2); REG_PC = address; T_COUNT(17); } else { REG_PC += 2; T_COUNT(10); } break; case 0xFC: /* call m, address */ if(SIGN_FLAG) { address = mem_read_word(REG_PC); REG_SP -= 2; mem_write_word(REG_SP, REG_PC + 2); REG_PC = address; T_COUNT(17); } else { REG_PC += 2; T_COUNT(10); } break; case 0x3F: /* ccf */ REG_F = (REG_F & (ZERO_MASK|PARITY_MASK|SIGN_MASK)) | (~REG_F & CARRY_MASK) | ((REG_F & CARRY_MASK) ? HALF_CARRY_MASK : 0) | (REG_A & (UNDOC3_MASK|UNDOC5_MASK)); T_COUNT(4); break; case 0xBF: /* cp a */ do_cp(REG_A); T_COUNT(4); break; case 0xB8: /* cp b */ do_cp(REG_B); T_COUNT(4); break; case 0xB9: /* cp c */ do_cp(REG_C); T_COUNT(4); break; case 0xBA: /* cp d */ do_cp(REG_D); T_COUNT(4); break; case 0xBB: /* cp e */ do_cp(REG_E); T_COUNT(4); break; case 0xBC: /* cp h */ do_cp(REG_H); T_COUNT(4); break; case 0xBD: /* cp l */ do_cp(REG_L); T_COUNT(4); break; case 0xFE: /* cp value */ do_cp(mem_read(REG_PC++)); T_COUNT(7); break; case 0xBE: /* cp (hl) */ do_cp(mem_read(REG_HL)); T_COUNT(7); break; case 0x2F: /* cpl */ REG_A = ~REG_A; REG_F = (REG_F & (CARRY_MASK|PARITY_MASK|ZERO_MASK|SIGN_MASK)) | (HALF_CARRY_MASK|SUBTRACT_MASK) | (REG_A & (UNDOC3_MASK|UNDOC5_MASK)); T_COUNT(4); break; case 0x27: /* daa */ do_daa(); T_COUNT(4); break; case 0x3D: /* dec a */ do_flags_dec_byte(--REG_A); T_COUNT(4); break; case 0x05: /* dec b */ do_flags_dec_byte(--REG_B); T_COUNT(4); break; case 0x0D: /* dec c */ do_flags_dec_byte(--REG_C); T_COUNT(4); break; case 0x15: /* dec d */ do_flags_dec_byte(--REG_D); T_COUNT(4); break; case 0x1D: /* dec e */ do_flags_dec_byte(--REG_E); T_COUNT(4); break; case 0x25: /* dec h */ do_flags_dec_byte(--REG_H); T_COUNT(4); break; case 0x2D: /* dec l */ do_flags_dec_byte(--REG_L); T_COUNT(4); break; case 0x35: /* dec (hl) */ { Uchar value = mem_read(REG_HL) - 1; mem_write(REG_HL, value); do_flags_dec_byte(value); } T_COUNT(11); break; case 0x0B: /* dec bc */ REG_BC--; T_COUNT(6); break; case 0x1B: /* dec de */ REG_DE--; T_COUNT(6); break; case 0x2B: /* dec hl */ REG_HL--; T_COUNT(6); break; case 0x3B: /* dec sp */ REG_SP--; T_COUNT(6); break; case 0xF3: /* di */ do_di(); T_COUNT(4); break; case 0x10: /* djnz offset */ /* Zaks says no flag changes. */ if(--REG_B != 0) { signed char byte_value; byte_value = (signed char) mem_read(REG_PC++); REG_PC += byte_value; T_COUNT(13); } else { REG_PC++; T_COUNT(8); } break; case 0xFB: /* ei */ do_ei(); T_COUNT(4); break; case 0x08: /* ex af, af' */ { Ushort temp; temp = REG_AF; REG_AF = REG_AF_PRIME; REG_AF_PRIME = temp; } T_COUNT(4); break; case 0xEB: /* ex de, hl */ { Ushort temp; temp = REG_DE; REG_DE = REG_HL; REG_HL = temp; } T_COUNT(4); break; case 0xE3: /* ex (sp), hl */ { Ushort temp; temp = mem_read_word(REG_SP); mem_write_word(REG_SP, REG_HL); REG_HL = temp; } T_COUNT(19); break; case 0xD9: /* exx */ { Ushort tmp; tmp = REG_BC_PRIME; REG_BC_PRIME = REG_BC; REG_BC = tmp; tmp = REG_DE_PRIME; REG_DE_PRIME = REG_DE; REG_DE = tmp; tmp = REG_HL_PRIME; REG_HL_PRIME = REG_HL; REG_HL = tmp; } T_COUNT(4); break; case 0x76: /* halt */ if (trs_model == 1) { /* Z-80 HALT output is tied to reset button circuit */ trs_reset(0); } else { /* Really halt (i.e., wait for interrupt) */ /* Slight kludge: we back up the PC and keep going around the main loop reexecuting the halt. A real Z-80 does not back up and re-fetch the halt instruction repeatedly; it just executes NOPs internally. When an interrupt or NMI is delivered, (see below) we undo this decrement to get out of the halt state. */ REG_PC--; if (continuous > 0 && !(z80_state.nmi && !z80_state.nmi_seen) && !(z80_state.irq && z80_state.iff1) && !trs_event_scheduled()) { trs_paused = 1; pause(); } } T_COUNT(4); break; case 0xDB: /* in a, (port) */ REG_A = z80_in(mem_read(REG_PC++)); T_COUNT(10); break; case 0x3C: /* inc a */ REG_A++; do_flags_inc_byte(REG_A); T_COUNT(4); break; case 0x04: /* inc b */ REG_B++; do_flags_inc_byte(REG_B); T_COUNT(4); break; case 0x0C: /* inc c */ REG_C++; do_flags_inc_byte(REG_C); T_COUNT(4); break; case 0x14: /* inc d */ REG_D++; do_flags_inc_byte(REG_D); T_COUNT(4); break; case 0x1C: /* inc e */ REG_E++; do_flags_inc_byte(REG_E); T_COUNT(4); break; case 0x24: /* inc h */ REG_H++; do_flags_inc_byte(REG_H); T_COUNT(4); break; case 0x2C: /* inc l */ REG_L++; do_flags_inc_byte(REG_L); T_COUNT(4); break; case 0x34: /* inc (hl) */ { Uchar value = mem_read(REG_HL) + 1; mem_write(REG_HL, value); do_flags_inc_byte(value); } T_COUNT(11); break; case 0x03: /* inc bc */ REG_BC++; T_COUNT(6); break; case 0x13: /* inc de */ REG_DE++; T_COUNT(6); break; case 0x23: /* inc hl */ REG_HL++; T_COUNT(6); break; case 0x33: /* inc sp */ REG_SP++; T_COUNT(6); break; case 0xC3: /* jp address */ REG_PC = mem_read_word(REG_PC); T_COUNT(10); break; case 0xE9: /* jp (hl) */ REG_PC = REG_HL; T_COUNT(4); break; case 0xC2: /* jp nz, address */ if(!ZERO_FLAG) { REG_PC = mem_read_word(REG_PC); } else { REG_PC += 2; } T_COUNT(10); break; case 0xCA: /* jp z, address */ if(ZERO_FLAG) { REG_PC = mem_read_word(REG_PC); } else { REG_PC += 2; } T_COUNT(10); break; case 0xD2: /* jp nc, address */ if(!CARRY_FLAG) { REG_PC = mem_read_word(REG_PC); } else { REG_PC += 2; } T_COUNT(10); break; case 0xDA: /* jp c, address */ if(CARRY_FLAG) { REG_PC = mem_read_word(REG_PC); } else { REG_PC += 2; } T_COUNT(10); break; case 0xE2: /* jp po, address */ if(!PARITY_FLAG) { REG_PC = mem_read_word(REG_PC); } else { REG_PC += 2; } T_COUNT(10); break; case 0xEA: /* jp pe, address */ if(PARITY_FLAG) { REG_PC = mem_read_word(REG_PC); } else { REG_PC += 2; } T_COUNT(10); break; case 0xF2: /* jp p, address */ if(!SIGN_FLAG) { REG_PC = mem_read_word(REG_PC); } else { REG_PC += 2; } T_COUNT(10); break; case 0xFA: /* jp m, address */ if(SIGN_FLAG) { REG_PC = mem_read_word(REG_PC); } else { REG_PC += 2; } T_COUNT(10); break; case 0x18: /* jr offset */ { signed char byte_value; byte_value = (signed char) mem_read(REG_PC++); REG_PC += byte_value; } T_COUNT(12); break; case 0x20: /* jr nz, offset */ if(!ZERO_FLAG) { signed char byte_value; byte_value = (signed char) mem_read(REG_PC++); REG_PC += byte_value; T_COUNT(12); } else { REG_PC++; T_COUNT(7); } break; case 0x28: /* jr z, offset */ if(ZERO_FLAG) { signed char byte_value; byte_value = (signed char) mem_read(REG_PC++); REG_PC += byte_value; T_COUNT(12); } else { REG_PC++; T_COUNT(7); } break; case 0x30: /* jr nc, offset */ if(!CARRY_FLAG) { signed char byte_value; byte_value = (signed char) mem_read(REG_PC++); REG_PC += byte_value; T_COUNT(12); } else { REG_PC++; T_COUNT(7); } break; case 0x38: /* jr c, offset */ if(CARRY_FLAG) { signed char byte_value; byte_value = (signed char) mem_read(REG_PC++); REG_PC += byte_value; T_COUNT(12); } else { REG_PC++; T_COUNT(7); } break; case 0x7F: /* ld a, a */ REG_A = REG_A; T_COUNT(4); break; case 0x78: /* ld a, b */ REG_A = REG_B; T_COUNT(4); break; case 0x79: /* ld a, c */ REG_A = REG_C; T_COUNT(4); break; case 0x7A: /* ld a, d */ REG_A = REG_D; T_COUNT(4); break; case 0x7B: /* ld a, e */ REG_A = REG_E; T_COUNT(4); break; case 0x7C: /* ld a, h */ REG_A = REG_H; T_COUNT(4); break; case 0x7D: /* ld a, l */ REG_A = REG_L; T_COUNT(4); break; case 0x47: /* ld b, a */ REG_B = REG_A; T_COUNT(4); break; case 0x40: /* ld b, b */ REG_B = REG_B; T_COUNT(4); break; case 0x41: /* ld b, c */ REG_B = REG_C; T_COUNT(4); break; case 0x42: /* ld b, d */ REG_B = REG_D; T_COUNT(4); break; case 0x43: /* ld b, e */ REG_B = REG_E; T_COUNT(4); break; case 0x44: /* ld b, h */ REG_B = REG_H; T_COUNT(4); break; case 0x45: /* ld b, l */ REG_B = REG_L; T_COUNT(4); break; case 0x4F: /* ld c, a */ REG_C = REG_A; T_COUNT(4); break; case 0x48: /* ld c, b */ REG_C = REG_B; T_COUNT(4); break; case 0x49: /* ld c, c */ REG_C = REG_C; T_COUNT(4); break; case 0x4A: /* ld c, d */ REG_C = REG_D; T_COUNT(4); break; case 0x4B: /* ld c, e */ REG_C = REG_E; T_COUNT(4); break; case 0x4C: /* ld c, h */ REG_C = REG_H; T_COUNT(4); break; case 0x4D: /* ld c, l */ REG_C = REG_L; T_COUNT(4); break; case 0x57: /* ld d, a */ REG_D = REG_A; T_COUNT(4); break; case 0x50: /* ld d, b */ REG_D = REG_B; T_COUNT(4); break; case 0x51: /* ld d, c */ REG_D = REG_C; T_COUNT(4); break; case 0x52: /* ld d, d */ REG_D = REG_D; T_COUNT(4); break; case 0x53: /* ld d, e */ REG_D = REG_E; T_COUNT(4); break; case 0x54: /* ld d, h */ REG_D = REG_H; T_COUNT(4); break; case 0x55: /* ld d, l */ REG_D = REG_L; T_COUNT(4); break; case 0x5F: /* ld e, a */ REG_E = REG_A; T_COUNT(4); break; case 0x58: /* ld e, b */ REG_E = REG_B; T_COUNT(4); break; case 0x59: /* ld e, c */ REG_E = REG_C; T_COUNT(4); break; case 0x5A: /* ld e, d */ REG_E = REG_D; T_COUNT(4); break; case 0x5B: /* ld e, e */ REG_E = REG_E; T_COUNT(4); break; case 0x5C: /* ld e, h */ REG_E = REG_H; T_COUNT(4); break; case 0x5D: /* ld e, l */ REG_E = REG_L; T_COUNT(4); break; case 0x67: /* ld h, a */ REG_H = REG_A; T_COUNT(4); break; case 0x60: /* ld h, b */ REG_H = REG_B; T_COUNT(4); break; case 0x61: /* ld h, c */ REG_H = REG_C; T_COUNT(4); break; case 0x62: /* ld h, d */ REG_H = REG_D; T_COUNT(4); break; case 0x63: /* ld h, e */ REG_H = REG_E; T_COUNT(4); break; case 0x64: /* ld h, h */ REG_H = REG_H; T_COUNT(4); break; case 0x65: /* ld h, l */ REG_H = REG_L; T_COUNT(4); break; case 0x6F: /* ld l, a */ REG_L = REG_A; T_COUNT(4); break; case 0x68: /* ld l, b */ REG_L = REG_B; T_COUNT(4); break; case 0x69: /* ld l, c */ REG_L = REG_C; T_COUNT(4); break; case 0x6A: /* ld l, d */ REG_L = REG_D; T_COUNT(4); break; case 0x6B: /* ld l, e */ REG_L = REG_E; T_COUNT(4); break; case 0x6C: /* ld l, h */ REG_L = REG_H; T_COUNT(4); break; case 0x6D: /* ld l, l */ REG_L = REG_L; T_COUNT(4); break; case 0x02: /* ld (bc), a */ mem_write(REG_BC, REG_A); T_COUNT(7); break; case 0x12: /* ld (de), a */ mem_write(REG_DE, REG_A); T_COUNT(7); break; case 0x77: /* ld (hl), a */ mem_write(REG_HL, REG_A); T_COUNT(7); break; case 0x70: /* ld (hl), b */ mem_write(REG_HL, REG_B); T_COUNT(7); break; case 0x71: /* ld (hl), c */ mem_write(REG_HL, REG_C); T_COUNT(7); break; case 0x72: /* ld (hl), d */ mem_write(REG_HL, REG_D); T_COUNT(7); break; case 0x73: /* ld (hl), e */ mem_write(REG_HL, REG_E); T_COUNT(7); break; case 0x74: /* ld (hl), h */ mem_write(REG_HL, REG_H); T_COUNT(7); break; case 0x75: /* ld (hl), l */ mem_write(REG_HL, REG_L); T_COUNT(7); break; case 0x7E: /* ld a, (hl) */ REG_A = mem_read(REG_HL); T_COUNT(7); break; case 0x46: /* ld b, (hl) */ REG_B = mem_read(REG_HL); T_COUNT(7); break; case 0x4E: /* ld c, (hl) */ REG_C = mem_read(REG_HL); T_COUNT(7); break; case 0x56: /* ld d, (hl) */ REG_D = mem_read(REG_HL); T_COUNT(7); break; case 0x5E: /* ld e, (hl) */ REG_E = mem_read(REG_HL); T_COUNT(7); break; case 0x66: /* ld h, (hl) */ REG_H = mem_read(REG_HL); T_COUNT(7); break; case 0x6E: /* ld l, (hl) */ REG_L = mem_read(REG_HL); T_COUNT(7); break; case 0x3E: /* ld a, value */ REG_A = mem_read(REG_PC++); T_COUNT(7); break; case 0x06: /* ld b, value */ REG_B = mem_read(REG_PC++); T_COUNT(7); break; case 0x0E: /* ld c, value */ REG_C = mem_read(REG_PC++); T_COUNT(7); break; case 0x16: /* ld d, value */ REG_D = mem_read(REG_PC++); T_COUNT(7); break; case 0x1E: /* ld e, value */ REG_E = mem_read(REG_PC++); T_COUNT(7); break; case 0x26: /* ld h, value */ REG_H = mem_read(REG_PC++); T_COUNT(7); break; case 0x2E: /* ld l, value */ REG_L = mem_read(REG_PC++); T_COUNT(7); break; case 0x01: /* ld bc, value */ REG_BC = mem_read_word(REG_PC); REG_PC += 2; T_COUNT(10); break; case 0x11: /* ld de, value */ REG_DE = mem_read_word(REG_PC); REG_PC += 2; T_COUNT(10); break; case 0x21: /* ld hl, value */ REG_HL = mem_read_word(REG_PC); REG_PC += 2; T_COUNT(10); break; case 0x31: /* ld sp, value */ REG_SP = mem_read_word(REG_PC); REG_PC += 2; T_COUNT(10); break; case 0x3A: /* ld a, (address) */ /* this one is missing from Zaks */ REG_A = mem_read(mem_read_word(REG_PC)); REG_PC += 2; T_COUNT(13); break; case 0x0A: /* ld a, (bc) */ REG_A = mem_read(REG_BC); T_COUNT(7); break; case 0x1A: /* ld a, (de) */ REG_A = mem_read(REG_DE); T_COUNT(7); break; case 0x32: /* ld (address), a */ mem_write(mem_read_word(REG_PC), REG_A); REG_PC += 2; T_COUNT(13); break; case 0x22: /* ld (address), hl */ mem_write_word(mem_read_word(REG_PC), REG_HL); REG_PC += 2; T_COUNT(16); break; case 0x36: /* ld (hl), value */ mem_write(REG_HL, mem_read(REG_PC++)); T_COUNT(10); break; case 0x2A: /* ld hl, (address) */ REG_HL = mem_read_word(mem_read_word(REG_PC)); REG_PC += 2; T_COUNT(16); break; case 0xF9: /* ld sp, hl */ REG_SP = REG_HL; T_COUNT(6); break; case 0x00: /* nop */ T_COUNT(4); break; case 0xF6: /* or value */ do_or_byte(mem_read(REG_PC++)); T_COUNT(7); break; case 0xB7: /* or a */ do_or_byte(REG_A); T_COUNT(4); break; case 0xB0: /* or b */ do_or_byte(REG_B); T_COUNT(4); break; case 0xB1: /* or c */ do_or_byte(REG_C); T_COUNT(4); break; case 0xB2: /* or d */ do_or_byte(REG_D); T_COUNT(4); break; case 0xB3: /* or e */ do_or_byte(REG_E); T_COUNT(4); break; case 0xB4: /* or h */ do_or_byte(REG_H); T_COUNT(4); break; case 0xB5: /* or l */ do_or_byte(REG_L); T_COUNT(4); break; case 0xB6: /* or (hl) */ do_or_byte(mem_read(REG_HL)); T_COUNT(7); break; case 0xD3: /* out (port), a */ z80_out(mem_read(REG_PC++), REG_A); T_COUNT(11); break; case 0xC1: /* pop bc */ REG_BC = mem_read_word(REG_SP); REG_SP += 2; T_COUNT(10); break; case 0xD1: /* pop de */ REG_DE = mem_read_word(REG_SP); REG_SP += 2; T_COUNT(10); break; case 0xE1: /* pop hl */ REG_HL = mem_read_word(REG_SP); REG_SP += 2; T_COUNT(10); break; case 0xF1: /* pop af */ REG_AF = mem_read_word(REG_SP); REG_SP += 2; T_COUNT(10); break; case 0xC5: /* push bc */ REG_SP -= 2; mem_write_word(REG_SP, REG_BC); T_COUNT(11); break; case 0xD5: /* push de */ REG_SP -= 2; mem_write_word(REG_SP, REG_DE); T_COUNT(11); break; case 0xE5: /* push hl */ REG_SP -= 2; mem_write_word(REG_SP, REG_HL); T_COUNT(11); break; case 0xF5: /* push af */ REG_SP -= 2; mem_write_word(REG_SP, REG_AF); T_COUNT(11); break; case 0xC9: /* ret */ REG_PC = mem_read_word(REG_SP); REG_SP += 2; T_COUNT(10); break; case 0xC0: /* ret nz */ if(!ZERO_FLAG) { REG_PC = mem_read_word(REG_SP); REG_SP += 2; T_COUNT(11); } else { T_COUNT(5); } break; case 0xC8: /* ret z */ if(ZERO_FLAG) { REG_PC = mem_read_word(REG_SP); REG_SP += 2; T_COUNT(11); } else { T_COUNT(5); } break; case 0xD0: /* ret nc */ if(!CARRY_FLAG) { REG_PC = mem_read_word(REG_SP); REG_SP += 2; T_COUNT(11); } else { T_COUNT(5); } break; case 0xD8: /* ret c */ if(CARRY_FLAG) { REG_PC = mem_read_word(REG_SP); REG_SP += 2; T_COUNT(11); } else { T_COUNT(5); } break; case 0xE0: /* ret po */ if(!PARITY_FLAG) { REG_PC = mem_read_word(REG_SP); REG_SP += 2; T_COUNT(11); } else { T_COUNT(5); } break; case 0xE8: /* ret pe */ if(PARITY_FLAG) { REG_PC = mem_read_word(REG_SP); REG_SP += 2; T_COUNT(11); } else { T_COUNT(5); } break; case 0xF0: /* ret p */ if(!SIGN_FLAG) { REG_PC = mem_read_word(REG_SP); REG_SP += 2; T_COUNT(11); } else { T_COUNT(5); } break; case 0xF8: /* ret m */ if(SIGN_FLAG) { REG_PC = mem_read_word(REG_SP); REG_SP += 2; T_COUNT(11); } else { T_COUNT(5); } break; case 0x17: /* rla */ do_rla(); T_COUNT(4); break; case 0x07: /* rlca */ do_rlca(); T_COUNT(4); break; case 0x1F: /* rra */ do_rra(); T_COUNT(4); break; case 0x0F: /* rrca */ do_rrca(); T_COUNT(4); break; case 0xC7: /* rst 00h */ REG_SP -= 2; mem_write_word(REG_SP, REG_PC); REG_PC = 0x00; T_COUNT(11); break; case 0xCF: /* rst 08h */ REG_SP -= 2; mem_write_word(REG_SP, REG_PC); REG_PC = 0x08; T_COUNT(11); break; case 0xD7: /* rst 10h */ REG_SP -= 2; mem_write_word(REG_SP, REG_PC); REG_PC = 0x10; T_COUNT(11); break; case 0xDF: /* rst 18h */ REG_SP -= 2; mem_write_word(REG_SP, REG_PC); REG_PC = 0x18; T_COUNT(11); break; case 0xE7: /* rst 20h */ REG_SP -= 2; mem_write_word(REG_SP, REG_PC); REG_PC = 0x20; T_COUNT(11); break; case 0xEF: /* rst 28h */ REG_SP -= 2; mem_write_word(REG_SP, REG_PC); REG_PC = 0x28; T_COUNT(11); break; case 0xF7: /* rst 30h */ REG_SP -= 2; mem_write_word(REG_SP, REG_PC); REG_PC = 0x30; T_COUNT(11); break; case 0xFF: /* rst 38h */ REG_SP -= 2; mem_write_word(REG_SP, REG_PC); REG_PC = 0x38; T_COUNT(11); break; case 0x37: /* scf */ REG_F = (REG_F & (ZERO_FLAG|PARITY_FLAG|SIGN_FLAG)) | CARRY_MASK | (REG_A & (UNDOC3_MASK|UNDOC5_MASK)); T_COUNT(4); break; case 0x9F: /* sbc a, a */ do_sbc_byte(REG_A); T_COUNT(4); break; case 0x98: /* sbc a, b */ do_sbc_byte(REG_B); T_COUNT(4); break; case 0x99: /* sbc a, c */ do_sbc_byte(REG_C); T_COUNT(4); break; case 0x9A: /* sbc a, d */ do_sbc_byte(REG_D); T_COUNT(4); break; case 0x9B: /* sbc a, e */ do_sbc_byte(REG_E); T_COUNT(4); break; case 0x9C: /* sbc a, h */ do_sbc_byte(REG_H); T_COUNT(4); break; case 0x9D: /* sbc a, l */ do_sbc_byte(REG_L); T_COUNT(4); break; case 0xDE: /* sbc a, value */ do_sbc_byte(mem_read(REG_PC++)); T_COUNT(7); break; case 0x9E: /* sbc a, (hl) */ do_sbc_byte(mem_read(REG_HL)); T_COUNT(7); break; case 0x97: /* sub a, a */ do_sub_byte(REG_A); T_COUNT(4); break; case 0x90: /* sub a, b */ do_sub_byte(REG_B); T_COUNT(4); break; case 0x91: /* sub a, c */ do_sub_byte(REG_C); T_COUNT(4); break; case 0x92: /* sub a, d */ do_sub_byte(REG_D); T_COUNT(4); break; case 0x93: /* sub a, e */ do_sub_byte(REG_E); T_COUNT(4); break; case 0x94: /* sub a, h */ do_sub_byte(REG_H); T_COUNT(4); break; case 0x95: /* sub a, l */ do_sub_byte(REG_L); T_COUNT(4); break; case 0xD6: /* sub a, value */ do_sub_byte(mem_read(REG_PC++)); T_COUNT(7); break; case 0x96: /* sub a, (hl) */ do_sub_byte(mem_read(REG_HL)); T_COUNT(7); break; case 0xEE: /* xor value */ do_xor_byte(mem_read(REG_PC++)); T_COUNT(7); break; case 0xAF: /* xor a */ do_xor_byte(REG_A); T_COUNT(4); break; case 0xA8: /* xor b */ do_xor_byte(REG_B); T_COUNT(4); break; case 0xA9: /* xor c */ do_xor_byte(REG_C); T_COUNT(4); break; case 0xAA: /* xor d */ do_xor_byte(REG_D); T_COUNT(4); break; case 0xAB: /* xor e */ do_xor_byte(REG_E); T_COUNT(4); break; case 0xAC: /* xor h */ do_xor_byte(REG_H); T_COUNT(4); break; case 0xAD: /* xor l */ do_xor_byte(REG_L); T_COUNT(4); break; case 0xAE: /* xor (hl) */ do_xor_byte(mem_read(REG_HL)); T_COUNT(7); break; default: disassemble(REG_PC - 1); error("unsupported instruction"); } /* Event scheduler */ if (z80_state.sched && (z80_state.sched - z80_state.t_count > TSTATE_T_MID)) { /* Subtraction wrapped; time for event to happen */ trs_do_event(); } /* Check for an interrupt */ if (trs_continuous >= 0) { /* Handle NMI first */ if (z80_state.nmi && !z80_state.nmi_seen) { if (instruction == 0x76) { /* Taking a NMI gets us out of a halt */ REG_PC++; } do_nmi(); z80_state.nmi_seen = TRUE; if (trs_model == 1) { /* Simulate releasing the pushbutton here; ugh. */ trs_reset_button_interrupt(0); } } /* Allow IRQ if enabled and instruction was not EI */ else if (z80_state.irq && z80_state.iff1 == 1 && instruction != 0xFB) { if (instruction == 0x76) { /* Taking an interrupt gets us out of a halt */ REG_PC++; } do_int(); } } } while (trs_continuous > 0); return ret; } void z80_reset() { REG_PC = 0; z80_state.i = 0; z80_state.iff1 = 0; z80_state.iff2 = 0; z80_state.interrupt_mode = 0; z80_state.irq = z80_state.nmi = FALSE; z80_state.sched = 0; /* z80_state.r = 0; */ srand(time(NULL)); /* Seed the RNG, for reading the refresh register */ } xtrs-4.9d/z80.h000066400000000000000000000160201306603614600133300ustar00rootroot00000000000000/* * Copyright (C) 1992 Clarendon Hill Software. * * Permission is granted to any individual or institution to use, copy, * or redistribute this software, provided this copyright notice is retained. * * This software is provided "as is" without any expressed or implied * warranty. If this software brings on any sort of damage -- physical, * monetary, emotional, or brain -- too bad. You've got no one to blame * but yourself. * * The software may be modified for your own purposes, but modified versions * must retain this notice. */ /* Modified by Timothy Mann, 1996 and later $Id: z80.h,v 1.16 2009/06/15 23:45:56 mann Exp $ */ #ifndef _Z80_H #define _Z80_H #include "config.h" #include #include #include #ifndef TRUE #define TRUE (1) #define FALSE (0) #endif typedef unsigned int Uint; /* 4 bytes */ typedef unsigned short Ushort; /* 2 bytes */ typedef unsigned char Uchar; /* 1 byte */ #if __WORDSIZE == 32 typedef unsigned long long tstate_t; #define TSTATE_T_MID (((unsigned long long) -1LL)/2ULL) #define TSTATE_T_LEN "llu" #else typedef unsigned long tstate_t; #define TSTATE_T_MID (((unsigned long) -1L)/2UL) #define TSTATE_T_LEN "lu" #endif struct twobyte { #ifdef big_endian Uchar high, low; #else Uchar low, high; #endif }; struct fourbyte { #ifdef big_endian Uchar byte3, byte2, byte1, byte0; #else Uchar byte0, byte1, byte2, byte3; #endif }; /* for implementing registers which can be seen as bytes or words: */ typedef union { struct twobyte byte; Ushort word; } wordregister; struct z80_state_struct { wordregister af; wordregister bc; wordregister de; wordregister hl; wordregister ix; wordregister iy; wordregister sp; wordregister pc; wordregister af_prime; wordregister bc_prime; wordregister de_prime; wordregister hl_prime; Uchar i; /* interrupt-page address register */ /* Uchar r; */ /* no memory-refresh register, just fetch random values */ Uchar iff1, iff2; Uchar interrupt_mode; /* To signal a maskable interrupt, set irq TRUE. The CPU does not * turn off irq; the external device must turn it off when * appropriately tickled by some IO port or memory address that it * decodes. INT is level triggered, so Z-80 code must tickle the * device before reenabling interrupts. * * There is no support as yet for fetching an interrupt vector or * RST instruction from the interrupting device, as this gets * rather complex when there can be more than one device with an * interrupt pending. So you'd better use interrupt_mode 1 only * (which is what the TRS-80 does). */ int irq; /* To signal a nonmaskable interrupt, set nmi to TRUE. The CPU * does not turn off nmi; the external device must turn it off * when tickled (or after a timeout). NMI is edge triggered, so * it has to be turned off and back on again before it can cause * another interrupt. nmi_seen remembers that an edge has been seen, * so turn off both nmi and nmi_seen when the interrupt is acknowledged. */ int nmi, nmi_seen; /* Speed control. 0 = full speed */ int delay; /* Cyclic T-state counter */ tstate_t t_count; /* Clock in MHz = T-states per microsecond */ float clockMHz; /* Simple event scheduler. If nonzero, when t_count passes sched, * trs_do_event() is called and sched is set to zero. */ tstate_t sched; }; #define Z80_ADDRESS_LIMIT (1 << 16) /* * Register accessors: */ #define REG_A (z80_state.af.byte.high) #define REG_F (z80_state.af.byte.low) #define REG_B (z80_state.bc.byte.high) #define REG_C (z80_state.bc.byte.low) #define REG_D (z80_state.de.byte.high) #define REG_E (z80_state.de.byte.low) #define REG_H (z80_state.hl.byte.high) #define REG_L (z80_state.hl.byte.low) #define REG_IX_HIGH (z80_state.ix.byte.high) #define REG_IX_LOW (z80_state.ix.byte.low) #define REG_IY_HIGH (z80_state.iy.byte.high) #define REG_IY_LOW (z80_state.iy.byte.low) #define REG_SP (z80_state.sp.word) #define REG_PC (z80_state.pc.word) #define REG_AF (z80_state.af.word) #define REG_BC (z80_state.bc.word) #define REG_DE (z80_state.de.word) #define REG_HL (z80_state.hl.word) #define REG_AF_PRIME (z80_state.af_prime.word) #define REG_BC_PRIME (z80_state.bc_prime.word) #define REG_DE_PRIME (z80_state.de_prime.word) #define REG_HL_PRIME (z80_state.hl_prime.word) #define REG_IX (z80_state.ix.word) #define REG_IY (z80_state.iy.word) #define REG_I (z80_state.i) #define HIGH(p) (((struct twobyte *)(p))->high) #define LOW(p) (((struct twobyte *)(p))->low) #define T_COUNT(n) (z80_state.t_count += (n)) /* * Flag accessors: * * Flags are: * * 7 6 5 4 3 2 1 0 * S Z - H - P/V N C * * C Carry * N Subtract * P/V Parity/Overflow * H Half-carry * Z Zero * S Sign */ #define CARRY_MASK (0x1) #define SUBTRACT_MASK (0x2) #define PARITY_MASK (0x4) #define OVERFLOW_MASK (0x4) #define UNDOC3_MASK (0x8) #define HALF_CARRY_MASK (0x10) #define UNDOC5_MASK (0x20) #define ZERO_MASK (0x40) #define SIGN_MASK (0x80) #define ALL_FLAGS_MASK (CARRY_MASK | SUBTRACT_MASK | OVERFLOW_MASK | \ HALF_CARRY_MASK | ZERO_MASK | SIGN_MASK) #define SET_SIGN() (REG_F |= SIGN_MASK) #define CLEAR_SIGN() (REG_F &= (~SIGN_MASK)) #define SET_ZERO() (REG_F |= ZERO_MASK) #define CLEAR_ZERO() (REG_F &= (~ZERO_MASK)) #define SET_HALF_CARRY() (REG_F |= HALF_CARRY_MASK) #define CLEAR_HALF_CARRY() (REG_F &= (~HALF_CARRY_MASK)) #define SET_OVERFLOW() (REG_F |= OVERFLOW_MASK) #define CLEAR_OVERFLOW() (REG_F &= (~OVERFLOW_MASK)) #define SET_PARITY() (REG_F |= PARITY_MASK) #define CLEAR_PARITY() (REG_F &= (~PARITY_MASK)) #define SET_SUBTRACT() (REG_F |= SUBTRACT_MASK) #define CLEAR_SUBTRACT() (REG_F &= (~SUBTRACT_MASK)) #define SET_CARRY() (REG_F |= CARRY_MASK) #define CLEAR_CARRY() (REG_F &= (~CARRY_MASK)) #define SIGN_FLAG (REG_F & SIGN_MASK) #define ZERO_FLAG (REG_F & ZERO_MASK) #define HALF_CARRY_FLAG (REG_F & HALF_CARRY_MASK) #define OVERFLOW_FLAG (REG_F & OVERFLOW_MASK) #define PARITY_FLAG (REG_F & PARITY_MASK) #define SUBTRACT_FLAG (REG_F & SUBTRACT_MASK) #define CARRY_FLAG (REG_F & CARRY_MASK) extern struct z80_state_struct z80_state; extern void z80_reset(void); extern int z80_run(int continuous); extern void mem_init(void); extern int mem_read(int address); extern void mem_write(int address, int value); extern void mem_write_rom(int address, int value); extern int mem_read_word(int address); extern void mem_write_word(int address, int value); Uchar *mem_pointer(int address, int writing); extern int mem_block_transfer(Ushort dest, Ushort source, int direction, Ushort count); extern int load_hex(); /* returns highest address loaded + 1 */ extern void debug(const char *fmt, ...); extern void error(const char *fmt, ...); extern void fatal(const char *fmt, ...); extern void z80_out(int port, int value); extern int z80_in(int port); extern int disassemble(unsigned short pc); extern void debug_init(void); extern void debug_shell(void); #endif