Percom DoubleDOS 4.24 for the Model I - COPY/CMD Disassembled

Page Customization

Introduction/Summary

Percom DoubleDOS 4.24 COPY/CMD Disassembly (Model I)

COPY/CMD is DBLDOS's COPY command, which takes the place of TRSDOS's library COPY (the manual's 3.2). It copies one file, a sector at a time through a buffer that fills the memory above 5D00H, and adds two things to TRSDOS's COPY: a copy with one drive, COPY :d filespec1 TO filespec2, which asks for the source and the destination diskette in turn on drive d, and single density files, marked by a dollar sign just before the file name ($NAME/EXT), so that files can be moved between DBLDOS diskettes and single density TRSDOS diskettes. It is the only part of DoubleDOS that reads or writes single density files.

The file is 1024 bytes: a name record, seven load blocks, 5200H-54D7H (728 bytes) and 5CD8H-5CE1H (10 bytes), and the transfer address 5200H. Every loaded byte is on exactly one row below: 568 bytes of code and 170 bytes of tables, texts and variables; the 2048 bytes 54D8H-5CD7H between the blocks are not in the file and hold COPY's copies of SYS2/SYS and SYS3/SYS while it runs. TRSDOS 2.1 has no COPY/CMD (its COPY is a library command of SYS6/SYS), so the code is compared with nothing but DBLDOS 4.20's.

Load Map

AddressesContents
5200H-523EHThe command line: the drive of a copy with one drive, the two file specifications and TO (5200H)
523FH-5279HThe size of the buffer, SYS2/SYS and SYS3/SYS loaded and copied (523FH)
527AH-5291HThe passes, COPY COMPLETED (527AH)
5292H-52FCHA read pass (5292H)
52FDH-5359HA write pass (52FDH)
535AH-5391HA file specification into an FCB, the dollar sign and the drive (535AH)
5392H-53D8HThe density of each file and the prompts (5392H)
53D9H-53F2HPut SYS2/SYS or SYS3/SYS back at 4E00H (53D9H)
53F3H-542DHSet the density in the Doubler and in SYS0/SYS (53F3H)
542EH-5437HThe error exit (542EH)
5438H-54D7HTexts, variables and the two FCBs (5438H)
54D8H-5CD7HNot in the file: the copies of SYS2/SYS and SYS3/SYS
5CD8H-5CE1HThe end of a read pass, added by DPM-0002 (5CD8H)

How It Works

The command line is taken first (5200H). In a copy with one drive the drive digit is kept at 5468H, inside the prompt text, and put into both specifications (5369H), over a drive the user gave. The buffer is the whole pages from 5D00H to the top of memory (4049H), 162 sectors with 48K.

COPY then makes sure that no overlay will have to be read while the diskettes are changed or set to the other density: an @OPEN and an @CLOSE of a file control block with no file name (5492H) fail, but each loads its overlay at 4E00H, and COPY copies SYS2/SYS to 54D8H and SYS3/SYS to 58D8H with their request codes (524CH). Before each open it puts SYS2/SYS back at 4E00H and its code in 430EH, before each close SYS3/SYS (53D9H), so that the dispatcher of RST 28H finds the overlay in memory. Reading and writing sectors are done by SYS0/SYS itself.

Each pass reads sectors into the buffer until it is full or the source ends (5292H), then writes them to the destination with read back, @VERF (52FDH). The source is opened on the first pass and closed when its end is read, and its end of file offset and sector are kept; the destination is opened or made on the first pass and, after the last, given that end and closed, so that the copy has the size of the source. In a copy with one drive, MOUNT SOURCE DISK ON DRIVE d AND PUSH "ENTER" and MOUNT DESTINATION DISK ... come before each pass, and at the end, when d is 0, MOUNT DBLDOS DISK ON DRIVE 0 AND PUSH "ENTER" (53B2H).

Single Density

Before each pass the density of the file is set by 53F3H: the Doubler gets the command FFH (double) or FEH (single) and the Force Interrupt D0H, with the track register kept around them, and two places of SYS0/SYS are changed. At 4651H the call of 43A5H, which turns a block and sector into the cylinder and the sector of a double density track, 18 sectors, becomes LD (37EEH),DE for single density, so that the block is the track and the sector is the sector, ten a track, as TRSDOS lays out a single density diskette (the CP D at 4650H already set the Z FLAG the RET Z at 4655H needs). The operands at 4A4AH and 4A72H, where SYS0/SYS stops looking for a free granule in the GAT, become 60H instead of C0H. The bytes are at 5424H and 5429H; every error and the end put double density back (53B2H).

Differences Between the Versions

COPY/CMD is the same in 4.23 (all three sets) and 4.24. 4.20 differs by Percom's patch memo DPM-0002 of September 29, 1980 ("The COPY command fails to copy all sectors of files which are longer than the memory buffer used for the copy operation (162 sectors on a 48K machine)"; the memo adds that this made the Microsoft BASIC compiler malfunction under DBLDOS):

Address4.20
5242H, 52AFH, 5314HThe buffer starts at 5CD8H, the first byte after the copy of SYS3/SYS; 4.23 and 4.24 start it at 5D00H to make room for the code at 5CD8H.
52DCHJR NZ,52B5H and RET, where 4.23 and 4.24 have JP 5CD8H. At a full buffer the end of the data at 548BH was still the start of the last sector read, so the write pass left that sector out: one sector lost for each full buffer.
5CD8HNot in 4.20's file: the load block 5CD8H-5CE1H is the memo's new record.

Percom's letter of September 8, 1980 has one patch line for COPY/CMD: record 3, offset 75, one byte 64 (40H), the operand at 542EH of OR 40H in the error exit, which makes @ERROR end at the DOS's exit instead of returning (the letter's FILE NOT FOUND loop). Every set in hand, 4.20 included, has 40H there.

Bugs

No.
Address
What happens
B43
5304H
A destination that is open from an earlier pass is written without COPY's copy of SYS2/SYS being put back. After the read pass that reached the source's end, SYS3/SYS is at 4E00H (52DFH). If the destination needs another directory entry in that last write pass (SYS0/SYS 4A6BH, request code B4H), the dispatcher reads SYS2/SYS from the diskette in drive 0: in a copy with one drive on drive 0 that is the destination diskette, which as a data diskette has no SYS2/SYS (error 58H, a missing overlay), and with a single density destination SYS0/SYS is still set for single density.

Every bug found in DoubleDOS is listed, with what a user would do to set it off, on the DoubleDOS reference page.

Differences From the Manual

  • The manual (3.2.2) writes the prompts as MOUNT ... AND PUSH ENTER; the text has "ENTER" in quotation marks.
  • The manual's first example, COPY $SUPERZAP:1 TO $SUPERZAP:0, is said to make a double density file on drive 0; with the dollar sign before the second name COPY writes it in single density.
  • The manual says a copy with two drives aborts when a single density file has no drive in its specification, and that a single density file cannot be on drive 0 with two drives; COPY itself tests neither. The abort comes from the open, which searches the drives in the density set and so cannot read a directory of the other density, and from the error message, which needs SYS4/SYS from the DBLDOS diskette in drive 0 (542EH sets double density first).
  • The manual says nothing of the buffer size, of the read back of every sector written, or that the destination is made or overwritten without a question.

Notes

  • The file control block at 5492H whose open and close fail is 32 bytes long like any FCB, so it takes in the source FCB at 5497H; @OPEN makes those bytes capitals before it finds no name, which leaves the source specification as 441CH stored it.
  • The key typed at a prompt is put at 5200H by the ROM's 0040H, over the first bytes of COPY, which have run (53D0H).
  • An error code goes to @ERROR with bit 6 set (542EH); SYS4/SYS shows the message of the code without bit 6.

Variables

Places in COPY/CMD

Address
Size
Contents
5468H
1 byte
The Drive of a Copy With One Drive
The digit, inside the prompt text; 00H for two drives.
548AH
1 byte
The Sectors of the Buffer
548BH-548CH
2 bytes
The End of the Data in the Buffer
548DH-548FH
3 bytes
The End of File Offset and Sector of the Source
5490H
1 byte
The Last Pass
FFH when the source has been read to its end.
5491H
1 byte
The Sectors Still to Read in This Pass
5492H-5493H
2 bytes
A File Specification With No Name
1FH and 0DH, for the open and close that load SYS2/SYS and SYS3/SYS.
5494H, 5495H
1 byte each
The Request Codes of SYS2/SYS and SYS3/SYS
5496H, 54B7H
1 byte each
The Density of the Source and the Destination
24H, a dollar sign, for single density; 00H double.
5497H-54B6H, 54B8H-54D7H
32 bytes each
The FCBs of the Source and the Destination
+03H-+04H the buffer address, moved a page for each sector.
54D8H-58D7H, 58D8H-5CD7H
1024 bytes each
The Copies of SYS2/SYS and SYS3/SYS
5D00H upThe Buffer
To the top of memory, a sector in each page.

Places Outside COPY/CMD

Address
Size
Contents
37ECH, 37EDHThe Controller
The command register, which takes the Doubler's FEH and FFH, and the track register, kept around them.
4049H-404AH
2 bytes
The Top of Memory
430EH
1 byte
SYS0/SYS: The Overlay in Memory
Set to the code of the copy put back.
4651H-4654H
4 bytes
SYS0/SYS: The Call of the Sector Conversion
CALL 43A5H and NOP, or LD (37EEH),DE for single density.
4A4AH, 4A72H
1 byte each
SYS0/SYS: The End of the GAT Searched
The operands of CP at 4A49H and 4A71H: C0H, or 60H for single density.
4E00H-51FFH
1024 bytes
The Overlay Area

Outside Routines

AddressUse
402DHSYS0/SYS: DOS READY
4409HSYS0/SYS: @ERROR (SYS4/SYS)
441CHSYS0/SYS: Parse a File Specification (SYS1/SYS)
4420HSYS0/SYS: @INIT, open or make a file (SYS2/SYS)
4424HSYS0/SYS: @OPEN (SYS2/SYS)
4428HSYS0/SYS: @CLOSE (SYS3/SYS)
4436HSYS0/SYS: @READ
443CHSYS0/SYS: @VERF, write and read back
4467HSYS0/SYS: Display a Text
0040HROM: Line Input
Up to Register B characters at Register Pair HL.

Disassembly

5200H - COPY: The Command Line

The transfer address, entered from SYS1/SYS's @RUN (4433H) with Register Pair HL past the name COPY. COPY :d filespec1 TO filespec2 copies with one drive, d (0-3), asking for each diskette in turn (the drive digit goes into the prompt text at 5468H); without :d the two files may be on two drives and nothing is asked. A dollar sign just before a file name marks a single density file (535AH). A bad drive is ILLEGAL DRIVE NUMBER (20H), a bad name or a missing TO is ILLEGAL FILE NAME (13H), both through 542EH.

5200
LD A,(HL) 7E
Load Register A with the first character of the command line after COPY at Register Pair HL.
5201
CP 3AH FE 3A
Compare Register A with 3AH, the colon of :d, the drive of a copy with one drive.
5203
If the NZ FLAG is set (no colon), jump to 521DH: a copy with two drives.
5205
INC HL 23
Increment Register Pair HL to the drive digit after the colon.
5206
LD A,(HL) 7E
Load Register A with the drive digit at Register Pair HL.
5207
CP 30H FE 30
Compare Register A, the drive digit, with 30H, the digit 0.
5209
If the C FLAG is set (below 0), jump to 520FH, the drive error.
520B
CP 34H FE 34
Compare Register A with 34H, one more than the digit 3.
520D
If the C FLAG is set (0-3), jump to 5214H, which keeps the drive digit.
520F
LD A,20H 3E 20
Load Register A with 20H, the code ILLEGAL DRIVE NUMBER (also from 5382H).
5211
Jump to 542EH, which gives the error of Register A.
5214
LD (5468H),A 32 68 54
Store Register A, the drive digit, at 5468H, the digit of the prompt text; not 00H means a copy with one drive.
5217
INC HL 23
Increment Register Pair HL to the next character of the command line.
5218
LD A,(HL) 7E
Load Register A with the character at Register Pair HL.
5219
CP 20H FE 20
Compare Register A, the character after the drive, with 20H, a space.
521B
If the Z FLAG is set (a space), jump back to 5217H to pass over it.
521D
LD DE,5497H 11 97 54
Load Register Pair DE with 5497H, the FCB of the source file.
5220
Call 535AH, which puts the file specification at Register Pair HL into the FCB at Register Pair DE.
5223
LD A,(HL) 7E
Load Register A with the character at Register Pair HL after the source specification.
5224
CP 54H FE 54
Compare Register A with 54H, the letter T of TO.
5226
If the NZ FLAG is set (not T), jump to 522EH, ILLEGAL FILE NAME.
5228
INC HL 23
Increment Register Pair HL to the next character.
5229
LD A,(HL) 7E
Load Register A with the character at Register Pair HL.
522A
CP 4FH FE 4F
Compare Register A with 4FH, the letter O of TO.
522C
If the Z FLAG is set (the word TO), jump to 5233H for the destination.
522E
LD A,13H 3E 13
Load Register A with 13H, the code ILLEGAL FILE NAME (also from 5366H).
5230
Jump to 542EH, which gives the error of Register A.
5233
INC HL 23
Increment Register Pair HL to the next character after TO.
5234
LD A,(HL) 7E
Load Register A with the character at Register Pair HL.
5235
CP 20H FE 20
Compare Register A, the character after TO, with 20H, a space.
5237
If the Z FLAG is set (a space), jump back to 5233H to pass over it.
5239
LD DE,54B8H 11 B8 54
Load Register Pair DE with 54B8H, the FCB of the destination file.
523C
Call 535AH, which puts the file specification at Register Pair HL into the FCB at Register Pair DE.

523FH - COPY: Keep SYS2/SYS and SYS3/SYS in Memory

The buffer is the memory from 5D00H (5CD8H in 4.20, DPM-0002 moved it for the code at 5CD8H) to the top, in pages of 256 bytes. An @OPEN and an @CLOSE of the bad file specification at 5492H (1FH and 0DH) fail, but they load SYS2/SYS and SYS3/SYS into 4E00H; each is copied, 1024 bytes, to 54D8H and 58D8H, with its request code from 430EH. From then on COPY puts the copy back at 4E00H before each open or close (53D9H, 53E1H), so that no overlay is read from a diskette that may have been changed or that is in the other density.

523F
LD HL,(4049H) 2A 49 40
Load Register Pair HL with the word at 4049H, the top of memory.
5242
LD DE,5D00H 11 00 5D
Load Register Pair DE with 5D00H, the start of the buffer; DPM-0002 changed this operand from 5CD8H.
5245
XOR A AF
Clear Register A to 00H and the C FLAG for the SBC.
5246
SBC HL,DE ED 52
Subtract Register Pair DE, 5D00H, from Register Pair HL: the bytes from the buffer to the top of memory.
5248
LD A,H 7C
Load Register A with Register H, the number of whole pages of 256 bytes in the buffer.
5249
LD (548AH),A 32 8A 54
Store Register A at 548AH, the number of sectors the buffer holds (A2H, 162, with 48K).
524C
LD DE,5492H 11 92 54
Load Register Pair DE with 5492H, a file control block holding 1FH and 0DH, no file name.
524F
Call 4424H, @OPEN of SYS0/SYS, which loads SYS2/SYS at 4E00H; the open fails (ILLEGAL FILE NAME) and the error is not tested.
5252
LD HL,4E00H 21 00 4E
Load Register Pair HL with 4E00H, the overlay area, which holds SYS2/SYS now.
5255
LD DE,54D8H 11 D8 54
Load Register Pair DE with 54D8H, the place of COPY's copy of SYS2/SYS.
5258
LD BC,0400H 01 00 04
Load Register Pair BC with 0400H, the 1024 bytes of the overlay area 4E00H-51FFH.
525B
LDIR ED B0
Copy Register Pair BC bytes from Register Pair HL, 4E00H, to Register Pair DE, 54D8H.
525D
LD A,(430EH) 3A 0E 43
Load Register A with the byte at 430EH, the request code of the overlay in memory, that of SYS2/SYS.
5260
LD (5494H),A 32 94 54
Store Register A at 5494H, the request code put back with SYS2/SYS by 53D9H.
5263
LD DE,5492H 11 92 54
Load Register Pair DE with 5492H, the file control block that is not open.
5266
Call 4428H, @CLOSE of SYS0/SYS, which loads SYS3/SYS at 4E00H; the close fails (FILE NOT OPEN) and the error is not tested.
5269
LD HL,4E00H 21 00 4E
Load Register Pair HL with 4E00H, the overlay area, which holds SYS3/SYS now.
526C
LD DE,58D8H 11 D8 58
Load Register Pair DE with 58D8H, the place of COPY's copy of SYS3/SYS.
526F
LD BC,0400H 01 00 04
Load Register Pair BC with 0400H, the 1024 bytes of the overlay area 4E00H-51FFH.
5272
LDIR ED B0
Copy Register Pair BC bytes from Register Pair HL, 4E00H, to Register Pair DE, 58D8H.
5274
LD A,(430EH) 3A 0E 43
Load Register A with the byte at 430EH, the request code of the overlay in memory, that of SYS3/SYS.
5277
LD (5495H),A 32 95 54
Store Register A at 5495H, the request code put back with SYS3/SYS by 53E1H.

527AH - COPY: The Passes

A read pass fills the buffer from the source (5292H), a write pass writes it to the destination (52FDH), until the source's end has been read (5490H). Then COPY COMPLETED, the DBLDOS diskette is asked for when drive 0 was used alone (53B2H), and DOS READY.

527A
Call 5292H, which reads the next part of the source file into the buffer.
527D
Call 52FDH, which writes that part to the destination file.
5280
LD A,(5490H) 3A 90 54
Load Register A with the byte at 5490H, FFH when the end of the source has been read.
5283
OR A B7
OR Register A with itself: the Z FLAG is set while the source has more to read.
5284
If the Z FLAG is set (more to copy), jump back to 527AH for the next pass.
5286
LD HL,547BH 21 7B 54
Load Register Pair HL with 547BH, the text COPY COMPLETED and 0DH.
5289
Call 4467H of SYS0/SYS, which shows the text at Register Pair HL.
528C
Call 53B2H, which sets double density again and asks for the DBLDOS diskette after a copy on drive 0.
528F
Jump to 402DH, the DOS's normal exit to DOS READY.

5292H - COPY: Read a Pass

The source diskette is asked for (one drive) and its density set (5392H). The first time the source is opened with the copy of SYS2/SYS (53D9H). Sectors are read into the buffer from 5D00H, the buffer address of the FCB (+03H-+04H) moved on a page each time, until the buffer is full (5491H) or the end of the file (1CH or 1DH), when the end of file offset and sector are kept (548DH-548FH) and the source closed with the copy of SYS3/SYS. 548BH-548CH is the end of the data in the buffer for the write pass.

5292
Call 5392H, which sets the density of the source and asks for the source diskette in a copy with one drive.
5295
LD A,(5497H) 3A 97 54
Load Register A with the first byte of the source FCB at 5497H; bit 7 is set once the file is open.
5298
RLCA 07
Rotate Register A left: the C FLAG is bit 7, the file is open.
5299
If the C FLAG is set (open from an earlier pass), jump to 52A9H.
529B
Call 53D9H, which puts COPY's copy of SYS2/SYS back at 4E00H.
529E
LD DE,5497H 11 97 54
Load Register Pair DE with 5497H, the FCB of the source file.
52A1
LD B,00H 06 00
Load Register B with 00H, the record length 256: a sector at a time.
52A3
Call 4424H, @OPEN of SYS0/SYS (SYS2/SYS, in memory), which opens the source file of the FCB at Register Pair DE.
52A6
If the NZ FLAG is set (an error, its code in Register A), jump to 542EH, which gives it.
52A9
LD A,(548AH) 3A 8A 54
Load Register A with the byte at 548AH, the number of sectors the buffer holds.
52AC
LD (5491H),A 32 91 54
Store Register A at 5491H, the count of the sectors still to read in this pass.
52AF
LD HL,5D00H 21 00 5D
Load Register Pair HL with 5D00H, the start of the buffer; DPM-0002 changed this operand from 5CD8H.
52B2
LD (549AH),HL 22 9A 54
Store Register Pair HL, 5D00H, at 549AH, the buffer address of the source FCB (FCB+03H).
52B5
LD HL,(549AH) 2A 9A 54
Load Register Pair HL with the word at 549AH, the buffer address where the next sector goes (also from 5CD8H).
52B8
LD (548BH),HL 22 8B 54
Store Register Pair HL at 548BH, the end of the data in the buffer so far.
52BB
LD DE,5497H 11 97 54
Load Register Pair DE with 5497H, the FCB of the source file.
52BE
Call 4436H, @READ of SYS0/SYS, which reads the next sector of the file of the FCB at Register Pair DE into the buffer.
52C1
If the Z FLAG is set (the sector was read), jump to 52CEH.
52C3
CP 1CH FE 1C
Compare Register A, the error code, with 1CH, END OF FILE ENCOUNTERED.
52C5
If the Z FLAG is set (error 1CH), jump to 52DFH: the whole source has been read.
52C7
CP 1DH FE 1D
Compare Register A, the error code, with 1DH, RECORD NUMBER OUT OF RANGE, the end of the file too.
52C9
If the Z FLAG is set (error 1DH), jump to 52DFH: the whole source has been read.
52CB
Jump to 542EH, which gives the error of Register A.
52CE
LD IX,5497H DD 21 97 54
Load Index Register IX with 5497H, the FCB of the source file.
52D2
INC (IX+04H) DD 34 04
Increment FCB+04H through Index Register IX, the high byte of the buffer address: the next sector goes a page further on.
52D5
LD A,(5491H) 3A 91 54
Load Register A with the byte at 5491H, the sectors still to read in this pass.
52D8
DEC A 3D
Decrement Register A by one for the sector just read.
52D9
LD (5491H),A 32 91 54
Store Register A at 5491H, the sectors still to read.
52DC
Jump to 5CD8H, DPM-0002's code; 4.20 has JR NZ,52B5H and RET here, which left 548BH one sector short at a full buffer.
52DF
Call 53E1H, which puts COPY's copy of SYS3/SYS back at 4E00H.
52E2
LD A,(549FH) 3A 9F 54
Load Register A with the byte at 549FH, FCB+08H of the source, the end of file offset.
52E5
LD (548DH),A 32 8D 54
Store Register A at 548DH, kept for the destination.
52E8
LD HL,(54A3H) 2A A3 54
Load Register Pair HL with the word at 54A3H, FCB+0CH-+0DH of the source, the end of file sector.
52EB
LD (548EH),HL 22 8E 54
Store Register Pair HL at 548EH, kept for the destination.
52EE
LD DE,5497H 11 97 54
Load Register Pair DE with 5497H, the FCB of the source file.
52F1
Call 4428H, @CLOSE of SYS0/SYS (SYS3/SYS, in memory), which closes the source file of the FCB at Register Pair DE.
52F4
If the NZ FLAG is set (an error, its code in Register A), jump to 542EH, which gives it.
52F7
LD A,FFH 3E FF
Load Register A with FFH, the mark that the source has been read to its end.
52F9
LD (5490H),A 32 90 54
Store Register A, FFH, at 5490H: this pass is the last one.
52FC
RET C9
Return to 527DH, which writes this last part.

52FDH - COPY: Write a Pass

The destination diskette is asked for (one drive) and its density set (53A2H). The first time the destination is opened or made with the copy of SYS2/SYS (@INIT). The buffer is written from 5D00H up to the end kept at 548BH, a sector at a time with read back (@VERF). After the last pass the destination FCB gets the source's end of file offset and sector (FCB+05H, +08H, +0AH, +0CH) and is closed with the copy of SYS3/SYS.

52FD
Call 53A2H, which sets the density of the destination and asks for the destination diskette in a copy with one drive.
5300
LD A,(54B8H) 3A B8 54
Load Register A with the first byte of the destination FCB at 54B8H; bit 7 is set once the file is open.
5303
RLCA 07
Rotate Register A left: the C FLAG is bit 7, the file is open.
5304
If the C FLAG is set (open from an earlier pass), jump to 5314H.
5306
Call 53D9H, which puts COPY's copy of SYS2/SYS back at 4E00H.
5309
LD DE,54B8H 11 B8 54
Load Register Pair DE with 54B8H, the FCB of the destination file.
530C
LD B,00H 06 00
Load Register B with 00H, the record length 256: a sector at a time.
530E
Call 4420H, @INIT of SYS0/SYS (SYS2/SYS, in memory), which opens the destination file of the FCB at Register Pair DE or makes it.
5311
If the NZ FLAG is set (an error, its code in Register A), jump to 542EH, which gives it.
5314
LD HL,5D00H 21 00 5D
Load Register Pair HL with 5D00H, the start of the buffer; DPM-0002 changed this operand from 5CD8H.
5317
LD (54BBH),HL 22 BB 54
Store Register Pair HL, 5D00H, at 54BBH, the buffer address of the destination FCB (FCB+03H).
531A
LD HL,(54BBH) 2A BB 54
Load Register Pair HL with the word at 54BBH, the buffer address of the next sector to write.
531D
LD A,(548CH) 3A 8C 54
Load Register A with the byte at 548CH, the high byte of the end of the data in the buffer.
5320
CP H BC
Compare Register A with Register H: the Z FLAG is set when every sector read in this pass has been written.
5321
If the Z FLAG is set (all written), jump to 5335H.
5323
LD DE,54B8H 11 B8 54
Load Register Pair DE with 54B8H, the FCB of the destination file.
5326
Call 443CH, @VERF of SYS0/SYS, which writes the sector at the buffer address and reads it back.
5329
If the NZ FLAG is set (an error, its code in Register A), jump to 542EH, which gives it.
532C
LD IX,54B8H DD 21 B8 54
Load Index Register IX with 54B8H, the FCB of the destination file.
5330
INC (IX+04H) DD 34 04
Increment FCB+04H through Index Register IX, the high byte of the buffer address: the next sector is a page further on.
5333
Jump back to 531AH for the next sector of the buffer.
5335
LD A,(5490H) 3A 90 54
Load Register A with the byte at 5490H, FFH when the end of the source has been read.
5338
OR A B7
OR Register A with itself: the Z FLAG is set when more passes follow.
5339
If the Z FLAG is set (more to copy), jump to 5359H, the return.
533B
LD A,(548DH) 3A 8D 54
Load Register A with the byte at 548DH, the end of file offset of the source.
533E
LD HL,(548EH) 2A 8E 54
Load Register Pair HL with the word at 548EH, the end of file sector of the source.
5341
LD (54C0H),A 32 C0 54
Store Register A at 54C0H, FCB+08H of the destination, the end of file offset.
5344
LD (54BDH),A 32 BD 54
Store Register A at 54BDH, FCB+05H of the destination, the offset of the next byte.
5347
LD (54C2H),HL 22 C2 54
Store Register Pair HL at 54C2H, FCB+0AH-+0BH of the destination, the next sector.
534A
LD (54C4H),HL 22 C4 54
Store Register Pair HL at 54C4H, FCB+0CH-+0DH of the destination, the end of file sector.
534D
Call 53E1H, which puts COPY's copy of SYS3/SYS back at 4E00H.
5350
LD DE,54B8H 11 B8 54
Load Register Pair DE with 54B8H, the FCB of the destination file.
5353
Call 4428H, @CLOSE of SYS0/SYS (SYS3/SYS, in memory), which closes the destination with the source's size.
5356
If the NZ FLAG is set (an error, its code in Register A), jump to 542EH, which gives it.
5359
RET C9
Return to 5280H after the pass, which tests 5490H.

535AH - COPY: A File Specification into an FCB

Called with Register Pair HL at the specification and Register Pair DE the FCB. A dollar sign first is stored in the byte before the FCB (5496H for the source, 54B7H for the destination), the mark of a single density file, and passed over. 441CH puts the specification in the FCB, ending it with 03H. In a copy with one drive the drive of the command (5468H) is put into the specification: over the digit after a colon, or with a colon added before the 03H.

535A
LD A,(HL) 7E
Load Register A with the first character of the specification at Register Pair HL.
535B
CP 24H FE 24
Compare Register A with 24H, the dollar sign of a single density file.
535D
If the NZ FLAG is set (no dollar sign), jump to 5363H.
535F
DEC DE 1B
Decrement Register Pair DE to the byte before the FCB, the density of this file.
5360
LD (DE),A 12
Store Register A, 24H, at Register Pair DE: the file is in single density.
5361
INC DE 13
Increment Register Pair DE to the first byte of the FCB again.
5362
INC HL 23
Increment Register Pair HL past the dollar sign.
5363
Call 441CH of SYS0/SYS (SYS1/SYS), which parses the file specification at Register Pair HL into the FCB at Register Pair DE.
5366
If the NZ FLAG is set (a bad specification), jump to 522EH, ILLEGAL FILE NAME.
5369
LD A,(5468H) 3A 68 54
Load Register A with the byte at 5468H, the drive digit of a copy with one drive, 00H for two drives.
536C
OR A B7
OR Register A with itself: the Z FLAG is set when no drive was given.
536D
RET Z C8
If the Z FLAG is set (two drives), return: the specification keeps its own drive.
536E
PUSH HL E5
Save Register Pair HL, the text pointer after the specification, on the stack.
536F
LD H,D 62
Load Register H with Register D, the high byte of the FCB.
5370
LD L,E 6B
Load Register L with Register E: Register Pair HL is the FCB.
5371
LD BC,0020H 01 20 00
Load Register Pair BC with 0020H, the 32 bytes of the FCB to search.
5374
LD A,3AH 3E 3A
Load Register A with 3AH, a colon, the start of a drive in the specification.
5376
CPIR ED B1
Search the FCB from Register Pair HL for Register A, Register Pair BC bytes at most: the Z FLAG is set when found.
5378
If the Z FLAG is set (a colon), jump to 5389H, which puts the drive after it.
537A
EX DE,HL EB
Exchange Register Pair DE and Register Pair HL: Register Pair HL is the FCB again.
537B
LD A,03H 3E 03
Load Register A with 03H, the byte that ends the specification in the FCB.
537D
LD BC,0020H 01 20 00
Load Register Pair BC with 0020H, the 32 bytes of the FCB to search.
5380
CPIR ED B1
Search the FCB from Register Pair HL for Register A, Register Pair BC bytes at most: the Z FLAG is set when found.
5382
If the NZ FLAG is set (no end byte), jump to 520FH, ILLEGAL DRIVE NUMBER.
5385
DEC HL 2B
Decrement Register Pair HL back to the end byte 03H.
5386
LD (HL),3AH 36 3A
Store 3AH, a colon, at Register Pair HL in place of the end byte.
5388
INC HL 23
Increment Register Pair HL to the place of the drive digit.
5389
LD A,(5468H) 3A 68 54
Load Register A with the byte at 5468H, the drive digit of the command.
538C
LD (HL),A 77
Store Register A, the drive digit, at Register Pair HL in the specification.
538D
INC HL 23
Increment Register Pair HL to the byte after the digit.
538E
LD (HL),03H 36 03
Store 03H at Register Pair HL: the specification ends after the drive.
5390
POP HL E1
Restore Register Pair HL, the text pointer after the specification, from the stack.
5391
RET C9
Return with the FCB holding the specification on the drive of the command.

5392H - COPY: The Density and the Prompts

5392H for the source and 53A2H for the destination: the density of the file (5496H or 54B7H, 24H single) is set by 53F3H, and in a copy with one drive MOUNT SOURCE DISK ON DRIVE d AND PUSH "ENTER" or MOUNT DESTINATION ... is shown and a key waited for (53BFH). 53B2H sets double density and, when the drive of the command is 0, asks for the DBLDOS diskette.

5392
LD A,(5496H) 3A 96 54
Load Register A with the byte at 5496H, the density mark of the source (24H single, 00H double).
5395
Call 53F3H, which sets the controller and SYS0/SYS for the density of Register A.
5398
LD A,(5468H) 3A 68 54
Load Register A with the byte at 5468H, the drive digit of a copy with one drive.
539B
OR A B7
OR Register A with itself: the Z FLAG is set for a copy with two drives.
539C
RET Z C8
If the Z FLAG is set (two drives), return without a prompt.
539D
LD HL,543FH 21 3F 54
Load Register Pair HL with 543FH, the text SOURCE.
53A0
Jump to 53BFH, which shows the prompt and waits for a key.
53A2
LD A,(54B7H) 3A B7 54
Load Register A with the byte at 54B7H, the density mark of the destination (24H single, 00H double).
53A5
Call 53F3H, which sets the controller and SYS0/SYS for the density of Register A.
53A8
LD A,(5468H) 3A 68 54
Load Register A with the byte at 5468H, the drive digit of a copy with one drive.
53AB
OR A B7
OR Register A with itself: the Z FLAG is set for a copy with two drives.
53AC
RET Z C8
If the Z FLAG is set (two drives), return without a prompt.
53AD
LD HL,5446H 21 46 54
Load Register Pair HL with 5446H, the text DESTINATION.
53B0
Jump to 53BFH, which shows the prompt and waits for a key.
53B2
XOR A AF
Clear Register A to 00H, the mark of double density, for the system diskette.
53B3
Call 53F3H, which sets the controller and SYS0/SYS for double density.
53B6
LD A,(5468H) 3A 68 54
Load Register A with the byte at 5468H, the drive digit of a copy with one drive.
53B9
CP 30H FE 30
Compare Register A, the drive digit, with 30H, the digit 0.
53BB
RET NZ C0
If the NZ FLAG is set (not drive 0), return: the system diskette was not taken out.
53BC
LD HL,5452H 21 52 54
Load Register Pair HL with 5452H, the text DBLDOS.
53BF
PUSH HL E5
Save Register Pair HL, the word of the prompt, on the stack.
53C0
LD HL,5438H 21 38 54
Load Register Pair HL with 5438H, the text MOUNT and a space.
53C3
Call 4467H of SYS0/SYS, which shows the text at Register Pair HL to 03H.
53C6
POP HL E1
Restore Register Pair HL, the word of the prompt, SOURCE, DESTINATION or DBLDOS.
53C7
Call 4467H of SYS0/SYS, which shows the text at Register Pair HL to 03H.
53CA
LD HL,5459H 21 59 54
Load Register Pair HL with 5459H, the text DISK ON DRIVE, the digit at 5468H and AND PUSH "ENTER".
53CD
Call 4467H of SYS0/SYS, which shows the text at Register Pair HL to 03H.
53D0
LD HL,5200H 21 00 52
Load Register Pair HL with 5200H, a buffer for the key, over COPY's start, which has run.
53D3
LD B,01H 06 01
Load Register B with 01H: one character may be typed.
53D5
Call 0040H in the ROM, the line input, which waits for ENTER (or one character and ENTER).
53D8
RET C9
Return when ENTER has been pressed at the prompt.

53D9H - COPY: Put SYS2/SYS or SYS3/SYS Back

53D9H copies COPY's copy of SYS2/SYS (54D8H) to 4E00H and stores its request code (5494H) at 430EH, 53E1H does the same for SYS3/SYS (58D8H, 5495H): the dispatcher of RST 28H then finds the overlay in memory and reads nothing from the diskette.

53D9
LD A,(5494H) 3A 94 54
Load Register A with the byte at 5494H, the request code of SYS2/SYS.
53DC
LD HL,54D8H 21 D8 54
Load Register Pair HL with 54D8H, COPY's copy of SYS2/SYS.
53DF
Jump to 53E7H, which copies it to 4E00H with its request code.
53E1
LD A,(5495H) 3A 95 54
Load Register A with the byte at 5495H, the request code of SYS3/SYS.
53E4
LD HL,58D8H 21 D8 58
Load Register Pair HL with 58D8H, COPY's copy of SYS3/SYS.
53E7
LD (430EH),A 32 0E 43
Store Register A at 430EH, the overlay request code of SYS0/SYS: the overlay is taken as being in memory.
53EA
LD DE,4E00H 11 00 4E
Load Register Pair DE with 4E00H, the overlay area.
53ED
LD BC,0400H 01 00 04
Load Register Pair BC with 0400H, the 1024 bytes of the overlay.
53F0
LDIR ED B0
Copy Register Pair BC bytes from Register Pair HL to Register Pair DE, 4E00H.
53F2
RET C9
Return with the overlay in place at 4E00H-51FFH.

53F3H - COPY: Set the Density

Register A 00H for double density, any other value for single. The Doubler gets FFH (double) or FEH (single) and the Force Interrupt D0H, with the track register kept around them. SYS0/SYS is patched: the four bytes at 4651H become CALL 43A5H and NOP (double: the block and sector are converted, 18 sectors a track) or LD (37EEH),DE (single: Register E the sector and Register D the track go to the controller as they are), and the operands 4A4AH and 4A72H, the end of the GAT searched for a free granule, C0H or 60H.

53F3
EX AF,AF' 08
Exchange Register Pair AF with the alternate Register Pair AF: the density in Register A is kept.
53F4
LD A,(37EDH) 3A ED 37
Load Register A with the byte at 37EDH, the track register of the controller.
53F7
EX AF,AF' 08
Exchange Register Pair AF with the alternate Register Pair AF: the track is kept, Register A is the density again.
53F8
OR A B7
OR Register A with itself: the Z FLAG is set for double density.
53F9
LD A,FEH 3E FE
Load Register A with FEH, the Doubler's single density command.
53FB
If the NZ FLAG is set (single density), jump to 53FEH with Register A FEH.
53FD
INC A 3C
Increment Register A to FFH, the Doubler's double density command.
53FE
LD (37ECH),A 32 EC 37
Store Register A, FEH or FFH, at 37ECH, the command register: the Doubler switches the density.
5401
RRA 1F
Rotate Register A right through the C FLAG: the C FLAG is set for FFH, double density.
5402
LD A,D0H 3E D0
Load Register A with D0H, the Force Interrupt command.
5404
LD (37ECH),A 32 EC 37
Store Register A, D0H, at 37ECH, the command register.
5407
EX AF,AF' 08
Exchange Register Pair AF with the alternate Register Pair AF: Register A is the track kept at 53F4H.
5408
LD (37EDH),A 32 ED 37
Store Register A at 37EDH, the track register, as it was.
540B
EX AF,AF' 08
Exchange Register Pair AF with the alternate Register Pair AF: the C FLAG of the density is back.
540C
LD HL,5424H 21 24 54
Load Register Pair HL with 5424H, the five bytes for double density.
540F
If the C FLAG is set (double density), jump to 5414H.
5411
LD HL,5429H 21 29 54
Load Register Pair HL with 5429H, the five bytes for single density.
5414
LD DE,4651H 11 51 46
Load Register Pair DE with 4651H, the call of the sector conversion in SYS0/SYS.
5417
LD BC,0004H 01 04 00
Load Register Pair BC with 0004H, the four bytes of 4651H-4654H.
541A
LDIR ED B0
Copy Register Pair BC bytes from Register Pair HL to Register Pair DE, 4651H.
541C
LD A,(HL) 7E
Load Register A with the fifth byte at Register Pair HL, C0H or 60H.
541D
LD (4A4AH),A 32 4A 4A
Store Register A at 4A4AH, the operand of a CP in SYS0/SYS's search of the GAT for a free granule.
5420
LD (4A72H),A 32 72 4A
Store Register A at 4A72H, the operand of the other CP of that search.
5423
RET C9
Return with the density set in the Doubler and in SYS0/SYS.
5424-5428
DEFB CDH,A5H,43H,00H,C0H CD A5 43 00 C0
The bytes for double density: CALL 43A5H and NOP for 4651H-4654H, and C0H, the GAT's 192 blocks, for 4A4AH and 4A72H.
5429-542D
DEFB EDH,53H,EEH,37H,60H ED 53 EE 37 60
The bytes for single density: LD (37EEH),DE for 4651H-4654H, and 60H, 96 blocks, for 4A4AH and 4A72H.

542EH - COPY: An Error

Every error of COPY comes here with its code in Register A. Bit 6 is set, double density and the DBLDOS diskette are put back (53B2H), and @ERROR (4409H) shows the message; bit 7 is clear, so SYS4/SYS goes on to the DOS's exit after an error (4030H). Percom's letter of September 8, 1980 patches the operand 542FH (COPY/CMD record 3, offset 75) to 40H, the value in every set in hand.

542E
OR 40H F6 40
OR Register A with 40H: bit 6 set, bit 7 clear, so @ERROR does not return; the operand 542FH is the September 1980 patch byte.
5430
PUSH AF F5
Save Register Pair AF, the error code, on the stack.
5431
Call 53B2H, which sets double density again and asks for the DBLDOS diskette after a copy on drive 0.
5434
POP AF F1
Restore Register Pair AF, the error code, from the stack.
5435
Jump to 4409H, @ERROR of SYS0/SYS, which shows the message of the code in Register A through SYS4/SYS.

5438H - COPY: Texts and Variables

The parts of the prompts, each ended by 03H, the drive digit inside the prompt, the end text, the variables of the passes, the bad file specification used to load SYS2/SYS and SYS3/SYS, and the two FCBs, each with its density mark before it.

5438-543E
DEFM "MOUNT " / DEFB 03H 4D 4F 55 4E 54 20 03
The text MOUNT and a space at 5438H, shown first by 53C0H.
543F-5445
DEFM "SOURCE" / DEFB 03H 53 4F 55 52 43 45 03
The text SOURCE at 543FH, for the source diskette (539DH).
5446-5451
DEFM "DESTINATION" / DEFB 03H 44 45 53 54 49 4E 41 54 49 4F 4E 03
The text DESTINATION at 5446H, for the destination diskette (53ADH).
5452-5458
DEFM "DBLDOS" / DEFB 03H 44 42 4C 44 4F 53 03
The text DBLDOS at 5452H, for the system diskette (53BCH).
5459-5467
DEFM " DISK ON DRIVE " 20 44 49 53 4B 20 4F 4E 20 44 52 49 56 45 20
The text DISK ON DRIVE between spaces at 5459H, shown by 53CAH.
5468
DEFB 00H 00
The drive digit of a copy with one drive, stored by 5214H; 00H for two drives. It is part of the prompt text.
5469-547A
DEFM " AND PUSH " / DEFB 22H,45H,4EH,54H,45H,52H,22H,03H 20 41 4E 44 20 50 55 53 48 20 22 45 4E 54 45 52 22 03
The text AND PUSH "ENTER" at 5469H, the end of the prompt.
547B-5489
DEFM "COPY COMPLETED" / DEFB 0DH 43 4F 50 59 20 43 4F 4D 50 4C 45 54 45 44 0D
The text COPY COMPLETED and 0DH at 547BH, shown by 5289H.
548A
DEFB 00H 00
The number of sectors the buffer holds, the pages from 5D00H to the top of memory (5249H).
548B-548C
DEFW 0000H 00 00
The end of the data read into the buffer in this pass (52B8H, 5CDEH); 548CH is compared by 531DH.
548D
DEFB 00H 00
The end of file offset of the source, kept by 52E5H for the destination.
548E-548F
DEFW 0000H 00 00
The end of file sector of the source, kept by 52EBH for the destination.
5490
DEFB 00H 00
FFH when the end of the source has been read (52F9H): the last pass.
5491
DEFB 00H 00
The count of the sectors still to read in this pass (52ACH, 52D9H).
5492-5493
DEFB 1FH,0DH 1F 0D
The file specification of the FCB at 5492H, 1FH and 0DH, which no file has: @OPEN and @CLOSE of it fail but load SYS2/SYS and SYS3/SYS (524CH, 5263H).
5494
DEFB 00H 00
The request code of SYS2/SYS, stored by 5260H and put back by 53D9H.
5495
DEFB 00H 00
The request code of SYS3/SYS, stored by 5277H and put back by 53E1H.
5496
DEFB 00H 00
The density mark of the source: 24H (a dollar sign, 535FH) single density, 00H double.
5497-54B6
DEFB 20H x 32 20 x 32
The FCB of the source file at 5497H-54B6H, 32 spaces in the file; the specification is put here by 535AH.
54B7
DEFB 00H 00
The density mark of the destination: 24H (a dollar sign, 535FH) single density, 00H double.
54B8-54D7
DEFB 20H x 32 20 x 32
The FCB of the destination file at 54B8H-54D7H, 32 spaces in the file; the specification is put here by 535AH.
54D8-5CD7
DEFS 2048
Not in the file: the copies of SYS2/SYS (54D8H-58D7H) and SYS3/SYS (58D8H-5CD7H) that 525BH and 5272H make.

5CD8H - COPY: The End of a Read Pass (DPM-0002)

Added by Percom's patch memo DPM-0002 (September 29, 1980; 4.23 and 4.24 have it, 4.20 not): the jump at 52DCH comes here. While sectors are left the pass goes on at 52B5H; at a full buffer the end of the data is set past the last sector read. 4.20's JR NZ,52B5H and RET at 52DCH left 548BH at the start of the last sector, so the write pass dropped one sector of each full buffer: DPM-0002's "fails to copy all sectors of files which are longer than the memory buffer".

5CD8
If the NZ FLAG is set (sectors left in the buffer), jump to 52B5H to read the next sector.
5CDB
LD HL,(549AH) 2A 9A 54
Load Register Pair HL with the word at 549AH, the buffer address after the last sector read.
5CDE
LD (548BH),HL 22 8B 54
Store Register Pair HL at 548BH, the end of the data for the write pass.
5CE1
RET C9
Return to 527DH, which writes the full buffer.