Most of the editing was done for the sake of saving the reader's eye-sight and for easier transfer to electronic media such as this web site. Otherwise, this instruction manual is as Larry Kenny wrote it.
There are a few other things that should be noted:
David Solly
Bibliotheca Sagittarii
Ottawa, Ontario
© 9 November 1998
ac355@freenet.carleton.ca
It is supplied on a 48-TPI, 5¼ inch disk. If you have a
different type of drive, return it with a blank disk and $2 and I will put
it on your disk.
Organization of Blocks
| Side 1: | 1 | 3 | 5 | 7 | 9 | 11 | 13 | 15 | 17 | 19 | -> |
| Side 0: | 0 | 2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | 18 | -> |
Block 0 is reserved for the catalog, track map and disk name. The track map is a 165-byte table beginning at address 24 in block 0. The map is used when saving to let LKDOS know what blocks on the disk are available (unused).
The track map is created according to the number of tracks and sides entered when the disk is formatted. Numbers starting from 0 are listed sequentially up to a possible 164 blocks. Any blocks that don't exist on the actual disk, or are reserved (block 0 is reserved for the catalog), are replaced with the number 245. LKDOS uses numbers from 245 through 255 as markers in the catalog.
Example:
If a 40-track, single-sided disk was formatted, the track
map would show all odd numbered blocks as 245 (used), as well as the even
numbered blocks past the 40 track limit.
When a file is saved, the blocks that the file uses are replaced by 245 in the track map. When a file is deleted, the blocks used by the file are restored in the track map with the block number. If you save a file with a name that is already on the disk, the existing file is erased before the new file is saved.
Following the track map are the directory name cells. This is a list
of about 100 formatted areas for storing the file name of each file and
the blocks used by that file. The length of each cell is 34 bytes, but
this may vary if the file is a custom type file.
Markers
Each cell begins with a 255 marker, then a nine-character file name. If
the cell is not used, or the file has been deleted, then a 254 marker
follows the 255. After the file name is a 253, marking the beginning of
the block list used by the file.
The end of the block list is marked by a 249. The 249 is a floating marker, and if the file is deleted, it is moved to just after the 253, indicating no blocks used. There is room in each cell for 21 blocks (over 100K), but this can be expanded for sequential files, etc. On the other hand, if you would like more than 100 files per disk for a quad-density drive that has 160 blocks, you can reduce the size of the block area so you can put in more name cells.
The end of the list of 100 or so name cells is marked by a 250. At address 4500 in the catalog block is the disk name. It can be very long (over 500 characters), and ends with a 0.
|
Markers used by LKDOS in the catalog block | |
| 245 | - Block in use. Only used in track map. |
| 249 | - Marks the end of the block list in the name cell. |
| 250 | - Marks the end of the directory name cells. |
| 253 | - Marks the beginning of the block list in the name cell. |
| 254 | - Follows the 255 marker if the cell is not in use. |
| 255 | - Marks the beginning of each directory name cell. |
Also, in block 0, address 20 hold the number of sides on the disk,
address 21 holds the number of tracks, and address 22 holds the head
speed. The head speed is the speed at which the disk drive's head steps
from track to track.
Data Blocks
All blocks from block 1 up to the maximum on the disk are data blocks. Each data block contains a 24-byte information header, and then room for 5090 bytes of data.
|
Header Information
| |
| Address In Block | Description |
| 0 | - Reserved |
| 1 | - Block number |
| 2 - 11 | - File name |
| 12, 13 | - Start address of file |
| 14, 15 | - Length of data (in block only) |
| 16 | - Sum check (CRC) number |
| 17, 18 | - Auto-run line number for BASIC |
| 20, 21 | - Variable - Prog (Offset for BASIC) |
| 22, 23 | - Total length of file |
| 24 | - Start of data (5090 bytes, maximum) |
Press Enter to scroll the screen, or press the space bar to single-step through the buffer.
The bar across the left side of the screen is the address of the line that can be edited. Press "n" to enter a new number, "c" to enter a character or entire character string or file name.
To go to a new address in the buffer, press "g", then the address. You cannot go beyond the limits of the buffer. The buffer starts at 50000; so, if you want to go to the 4500 th address in the buffer to see the disk name, then enter 54500.
Pressing "f" will let you search for a byte (such as the next 255 marker), or a character by entering that character's code.
To save the buffer back to the disk, press "s". You can load a block or catalog from one disk and then save it to another disk.
To exit to the main menu, press "q".
2. Read Disk Headers
This will print, to the screen or to a printer, the headers of all the
tracks. This is useful if you want to find the start and length of a code
file, or to find the blocks used by files when you are reconstructing a
damaged directory. The printer option prints to the Timex/Sinclair 2040
thermal printer, unless you open channel 3 to a line printer (OPEN #3,
"lp") or load a printer driver.
3. Change Disk Speed
This allows the head speed on a disk to be changed. Enter "4" to abort.
4. Reformat Single Block
A block can be damaged by turning on the drive power when a disk is in it,
or in numerous other ways. You can reformat a single block using this
option. Since the format code is the only code that can only be used on a
specific interface, you must insert the Disk Editor disk and load the
format code before actually formatting. After the code has been loaded
once, though, you can enter "z" to suppress repeated loading of the format
code.
5. Initialize Directory
With this, you can initialize the directory and the track map, but not
change the disk name. Warning: This will wipe out all files on the disk!
6. Map Out Bad Blocks
A disk that has bad blocks caused by a scratch or other physical defect
can be automatically mapped as "used" by this command. However, you
should first make certain that the source of the CRC errors is the disk,
and not a hardware problem. A disk that clicks while rotating in the drive
usually has a surface defect.
A common source of false CRC error reports is the board in the command
cartridge dock. Sometimes, after sitting in the command cartridge dock
for a time, the edge connector on this board becomes dirty or corroded and
fails to make proper contact with the computer. Cleaning the edge
connector will correct this problem, but take care to shut down and remove
the power cable from your Timex/Sinclair 2068 before removing the board
from the command cartridge dock. Failing to do this will irreparably
damage your computer and put you at risk of receiving an electric shock.
7. Change Disk Name
You can change the disk name without altering anything else on the disk
using this option. You can even break the program and load the disk
name from a word processor file to address 54500, then save the buffer.
Tasword II® can't be used because it formats each line as a 64
character array. Jack Dohany's (but not the original!) version of
M-Script® which has been modified for LARKEN I/O works well.
8. Catalog / Go To Drive (Now 0)
This allows you to change drives and display the catalog. If you don't
want to change drives, just press enter.
9. Display Track Map
This brings up a graphical representation of the track map. The vertical
numbers represent "tens" and the horizontal numbers are "ones". This
gives you a picture of the state of the disk. If many files have been
deleted, you will see how LKDOS keeps track of unused tracks.
Note: You can break and alter the program as you wish. It is safe to RUN it. Most of the editor (option 1) runs as compiled BASIC (compiled with Time Machine at 60000). The compiled section begins at line 910 and ends at 1450.
To access LKDOS subroutines within the cartridge directly, you must use machine language.
To call these subroutines, you must first turn on the cartridge with a call to address 98 (decimal). The cartridge is turned off by a memory read from address 100 (decimal).
You should also disable the interrupts before entering, and enable them after you're done.
An example for accessing the cartridge:
DI
CALL 98
CALL LKDOS subroutine
other code
LD A,(100)
EI
RET
| SAVEBF | - Saves the buffer to the current track and side as set up by TRACK or NEXTR. The disk should be spinning for 1 second before using this routine. You can load data to and from the buffer using the LDIR command in machine language. |
| LOADBF | - Loads the buffer from the current track and side. No spin-up necessary. |
| TRACK | - Restores the drive head to track 0, then seeks the track held in curtrk. The number in curtrk is actually the block number. Even blocks are side 0 and odd blocks are side 1. The track number is equal to INT(block/2). Example: Block 11 equals track 5, side 1. TRACK also does the one-second spin-up required by save and load routines. It should be the first call in any disk access. The data in the buffer may be erased by the TRACK routine, so only place data in the buffer after calling TRACK. |
| NEXTR | - Increments curtrk by one and moves the head to the next track or side. The drive should be running before this is called. |
| INDIR | - Sets the head on track 0, loads the directory track, then searches for a file name matching the one the user has put at prognm. The temp2 pointer hold the address of the file name if found. Errnu will contain 10 if the file was not found. Clear errnu before calling this command. Pad the file name with spaces if it is less than 10 characters. |
| WPROT | - Does a 0.75 second spin-up, then checks if the disk is write-protected. If it is, then the program is halted and the error statement S - Protect Error is printed. Because this halts the program on an error and could thereby cause loss of data, it's better to check it manually. |
| DECDP | - Prints the contents of temp1 and the accumulator as a decimal number. |
| DOSER | - This will print a standard error message in the same manner as the 2068 does. The HL register should hold the address of the error message and the message should end with a period. |
| EVALU | - This is used to evaluate a numeric expression in a BASIC command. CHADD should point to the start of the number or formula. Use RST #20 to move CHADD. The result will be returned in the BC register. EVALU uses the Sinclair ROM calls to do this very complicated math. It checks to see if you are running in 2068 mode or in ZX Spectrum mode and then makes the appropriate ROM call. |
| GTFIL | - This is like EVALU, but for string expressions. CHADD should point to one character before the string. The result string will be found in prognm. The DE register will point to the quote mark (\") at the end of the string. If you're then going to search for that file with INDIR, replace the quote mark with a space by doing LD A,32 / LD (DE),A right after calling GTFIL. |
When you send LKDOS a command from BASIC, it scans the line for the information it needs. But in machine code, we must put the information in certain locations before calling LKDOS to use it.
The LKDOS location NmiF is used to tell LKDOS how it is being called:
from the NMI, BASIC, or a machine code program. It should be loaded with
11 (decimal) before you call the following routines.
Saving Files from Machine Code
To save an area of memory to disk from machine code, you must first give
it a file name, and transfer the file name to prognm. The file name
should be a code type; but since there's no syntax checking, any name and
extension will work. In other words, you're not limited to .A, .B or .C
type files.
Then, call the SV#1 subroutine. This will enter the file name into the directory, and fill the directory work area with free blocks to use for saving. If the file already exists, then the old file is deleted first.
Now, load temp2 with the length of the file and temp4 with the start address of the file. Then call SV#2 to finish the save.
Example: To save a file named test.ZZ, with start address 30000 and a length of 10000 bytes:
Save DI ;Disable interrupt.
CALL 98 ;Turn on the cartridge.
LD HL,Name ;Transfer file name
LD DE,prognm ;to program.
LD BC,10
LDIR
LD A,11 ;Set MC save.
LD (NmiF),A
CALL SV#1 ;Save name.
LD HL,30000
LD (temp4),HL ;Set start address.
LD HL,10000
LD (temp2),HL ;Set length of save.
CALL SV#2 ;Second data.
LD A,(100) ;Exit cartridge.
EI
RET
Name DEFM /test.ZZ / ;Name of file padded to 10 chars.
The SV#1 main routine first calls the WPROT subroutine to see if the disk is protected. If it is, then the routine will terminate with an error. This will stop the machine code program.
If you don't want your program to be stopped, the best way around this is to find the address of the actual SV#1 routine in the EPROM by reading locations 205 and 206, add 3 to this to skip past the WPROT call, and call the new address directly. This address must be calculated dynamically because it may change with new EPROM revisions.
If you're saving a file from one address, but you want the file's absolute load address (that is, what you get with LOAD "file" CODE, and no address specified) to be different, then you should change the locations Destin and Totlen on the first block of the file to reflect the new start or length. Also, if you're adding data to the end of a file (as in sequential files), you must update Totlen on the first block of the file.
If the file is a BASIC or ARRAY file, the first and last blocks should
have their pointers updated.
Loading a File from Disk
Loading a file from machine code is similar to saving. Just use LD#1
instead of SV#1 and LD#2 instead of SV#2. The start and length still go
into temp4 and temp2. The file name is also moved into place the same way.
If you want to use the start address and length that the file was saved from to load it, then after calling LD#1 (the first block of the file is now in the buffer), use the Destin and Totlen pointers as your start and length.
You can poke 23728,100 as you do in BASIC so your program will not
stop with a File Not Found error.
Selecting Drives from Machine Code
The LKDOS variable Dvsel specifies which drive is currently active. You
can change the current drive by changing the value of Dvsel, as follows:
1 = drive 0
2 = drive 1
4 = drive 2
8 = drive 3
128 = drive 4 (RAM Disk)
When changing drives, (especially floppies), insert a 0.05 second delay before and after changing drives between any disk call.
This routine allows you to find the number of free blocks without displaying the catalog. It will return the number of free blocks in the BC register so it can be accessed from BASIC with PRINT USR FREEBL or LET x = USR FREEBL.
FREEBL DI
CALL,98 ;Turn on the LKDOS cartridge
LD A,0
LD (curtrk),A ;Move the disk drive to
CALL TRACK ;block 0 (side 0, track 0)
CALL LOADBF ;Load disk to buffer
LD C,0 ;Set counter to 0
LD HL,data ;Set HL to the start of the track map
USED INC HL ;First block always used anyway
LD A,(HL)
CP 255 ;255 means "end of track map"
JR Z,EXIT ;If so then exit
CP 245 ;245 marker means "block used"
JR Z,USED ;If so then on to the next one
INC C ;Must be a free block, update count
JR USED ;Continue searching for free blocks
EXIT LD B,0
LD A,(100) ;Turn the LKDOS cartridge off
EI
RET
Nmif EQU 8194 ;Nmi, USER or BASIC flag Dvsel EQU 8195 ;Drive select byte (1770) Hspd EQU 8202 ;Head speed for FD1770 Rbank EQU 8203 ;RAM disk bank number Raddr EQU 8204 ;RAM disk bank address Chars EQU 8218 ;Address of window char set - 256 wrkspc EQU 8220 ;Start of disk work space buffer EQU wrkspc + 84 ;Start of track buffer data EQU buffer + 24 ;Start of actual data block curtrk EQU wrkspc + 1 ;Block number for head to seek errnu EQU wrkspc + 4 ;Holds 0 if no error has occurred prognm EQU wrkspc + 6 ;Holds string from Gtfil temp1 EQU wrkspc + 20 ;Used by DECDMP temp2 EQU wrkspc + 21 ;Usually holds the length of a file temp4 EQU wrkspc + 23 ;Start address of file temp6 EQU wrkspc + 25 ;Temporary address dirwka EQU wrkspc + 30 ;Holds cell being used ;**** These registers are saved with each track **** destin EQU buffer + 12 ;Address of data block lenth EQU buffer + 14 ;Length of data block Linenu EQU buffer + 17 ;Auto-run BASIC line Vofset EQU buffer + 20 ;Vars Offset (Vars-Prog) Totlen EQU buffer + 22 ;Total length of file
| Buffer Length | Data Length | |
| 5114 | 5090 | Standard double-density controller |
| 1984 | 1960 | Old single-density controller |
ADDR CALL Description 120 SAVEBF JP crcsv ;Save the buffer to the disk 123 LOADBF JP loadbf ;Load the buffer from the disk 126 TRACK JP trac ;Restore Trk0, then seek current track 129 NEXTR JP nextrk ;Increment disk head 1 track or side 132 INDIR JP indir ;Check directory for file (in prognm) 135 MOVDR JP movdr ;Move cell to dirwka 138 CMDCK JP cmdck ;Check command syntax 141 ENDLN JP Endoln ;Move CHADD to the end of BASIC line 144 EVALU JP Evalu ;Evaluate numeric formula 147 NOFIL JP nofil ;No file error 150 WPROT JP WPROt ;Check if the disk is write protected 153 ZER0 JP zer0 ;Restore blocks used by cell 156 GTFIL JP Gtfil ;Evaluate string, put in prognm 159 ROMM JP ROMS ;Check for the ZX Spectrum ROM 162 NEWET JP newet ;Put new entry into the directory 165 DECDP JP decdmp ;Print temp1 in decimal 168 TRANOK JP tranok ;Final routine for save 171 DOScp JP DOSOP ;Close the disk channel 174 DOSER JP Doserr ;Print error. HL holds the message 177 CLRBF JP clrbf ;Clear the buffer 180 ENCOD JP encdbf ;Encode the buffer with addresses 183 VSERCH JP vserch ;Look for arrays 186 JPOUT JP GTOUT ;Exit the LKDOS cartridge 189 GROW JP Grow ;Insert space in program 192 SHrnk JP Shrink ;Delete space in program 195 DTERR JP Fatal ;Catalog data error 198 LD#1 JP Lsubr ;First half of user load command 201 LD#2 JP LDdata ;Second half of user load command 204 SV#1 JP Ssubr ;First half of user save command 207 SV#2 JP SMEM ;Second half of user save command
Note:
Most of the cartridge RAM is used by LKDOS and Extended
BASIC (Ex-BASIC); however, the merge buffer can be used for temporary
storage. The merge buffer follows the data buffer and is 1200 bytes long.