öXCP-M+ ARTŽV“JSYS ASM‘‚ âJSYS HEX* RJSYS PRN="JSYS SYMK6LDRBIOS ASMYVºNOTICE ¯ÑßSYSTRK ASM³ÒüUTIL ÐDÈyÿCP-M+ ARTŠÊ¢ÿ+-----------------------------------------------------------------+ | ****** NOTICE ****** | | Copyright 1985 by Micro/Systems Journal | | PO Box 1192, Mountainside, NJ 07092 : | All rights reserved, reproduction prohibited without permission : +-----------------------------------------------------------------+ Reprinted from Micro/Systems March/April 1985 Bringing up CP/M Plus on your System by Sheldon Kolansky Many of us have been watching Digital Research tout the new CP/M- Plus. The features look so nice and they are. The buffering should make it run much faster, etc. I went out and bought the new version and worked for several weeks getting it going. I would like to pass on my trials and tribulations, maybe I can make it easier for you (if you should decide to do it). This article was originally written in the sumer of 1983 and submitted to Microsystems. It was never published so I updated it and submitted it to Microcomputer Journal. The recommended first and most important step is to bring up the simplest system possible. My fisrt system started with just a single density disk and only console I/O. After succesfully getting the basic system working, new features were added and debugged, one by one. These features included double density disk support, automatic drive sizing on logon, I/O redirection support and settable baud rates. The BIOS provided is broken up into several modules which can be assembled separately and then linked together. I modified the appropriate modules and tested the linked BIOS to my satisfaction. The BIOS was tested by loading and running it under SID in my current 2.2 system. The CP/M 3 BDOS is provided in relocatable format, and your BIOS must be linked to it. Assemble your BIOS so it stays in one memory segment at this time. After the entire system is linked together, a program called CPMGEN must be executed. CPMGEN asks you for pertinent information via a question and answer session at the terminal. This information includes how much memory you have, terminal parameters, etc. The output of CPMGEN is CPM3.SYS, the actual operating system image. CPM3.SYS is a file that exists on the data portion of a diskette. Two tidbits of important information: 1. Make the size of your CP/M 3 system fit under SID loaded via your current system. This will allow you to debug the new system using SID operating under your current system. See figure xxxx 2. The sample BIOS provided assigns space for the allocation vectors of the DPH. GENCPM asks if double allocation vectors are to be used. If you answer GENCPMs question Yes, then be doubly sure you have allotted sufficient space in the allocation vector. If sufficient space was not allocated, CPM Plus will write over the next routines in memory. Now with an operating system image on the diskette, it is time to figure out how to boot it. The Digital Research manuals are getting better, but some areas still leave a lot to be desired. The DRI manuals talk about CPMLDR which is read into memory by your hardware boot, and CPMLDR reads the system image off the disk and executes it. If you read closely, you will find out that you must write a LDRBIOS, but the description in the manual is severly limited. The LDRBIOS is a basic BIOS that, when linked to CPMLDR, performs limited functions of an operating system for the sole purpose of reading a file (CPM3.SYS) into memory and executing it. The LDRBIOS is linked to CPMLDR.REL to form CPMLDR.COM. CPMLDR.COM is read into memory by whatever boot process you intend to use. CPMLDR can also be executed as a file under your current operating system allowing you to debug the boot process of your new system while running under SID on your current system. DRI manuals present about a page of "information" on the LDRBIOS. After many hours of playing, I determined that the only calls used by CPMLDR are: BOOT, CONOUT, SELDSK, HOME, SETTRK, SETSEC, SETDMA, SECTRN, and READ. I formed my version of the LDRBIOS by combining the BIOSKRNL, CHARIO, and my disk module together in one file and deleted all the extraneous "nice" features, and returned calls that wouldn't be used. Shortening the LDRBIOS like this would give more flexibilty later when I had to find room for it on the system tracks. I did not include the SCB as it didn't seem to be necessary. The DPH macro that the sample BIOS calls can not be used since it relies upon GENCPM to allocate buffers, and GENCPM is only used on generating the operating system, not the LDRBIOS. You have to allocate buffers for the directory, data, check vector and allocation vector (I guessed on the last 2). This reduced the size of the code immensely. The basic single density system worked after a couple of minor bugs were squashed. The single density system worked well. Be sure to test it completely and save a copy of this system for future reference. In the proceding steps I wished I had not blown away this version of the system, so I could go back and test certain features with which I was having trouble. I got brave and decided to get double density working with automatic density selection, and that's when all the problems started. The following notes should outline some of my solutions / problems with the LDRBIOS: MOVE: The call to MOVE is required if the CPMLDR is to do the built in blocking/deblocking. SECTRN: must be modified if no translation is required. CPMLDR or BDOS reads sectors starting at 0 and relies upon SECTRN to provide a legal sector number for the disk. A no translation required routine, as usually provided with the sample BIOS, will pass sector 0 to the floppy, and since most floppies start with sector 1, this causes a problem. This same "problem" existed with 2.2 if you did the deblocking. You can get around it by incrementing the sector number by one if no translation is required. The blocking and deblocking algorithyms were designed for hard disks which start at sector 0, not sector 1 like the floppies do. DIRBCB: I didn't know what the values for sector, etc. would be so I arbitrarily assigned 0 to all except the buffer address. Boy, was that a mistake! The blocking / deblocking algorithym of the CPMLDR went to read the first sector of the directory, checked the DIRBCB and decided that the sector had already been read since the bytes described block 0, the first sector. CPMLDR then went and searched the directory buffer for CPM3.SYS, didn't find it, and then read the next directory sector. Therefore if CPM3.SYS was in the first directory sector CPMLDR could not find it. The answer to this problem took 4 calls to DRI (I dialed about 400 times to get through 4 times). Set the first byte of the DIRBCB to 0FFH and this will unallocate the buffer. SID is provided with CP/M 3, and is a handy debugging tool, but could use some new features to work with relocatable files. The linker does not provide a memory map that is useful to locate code when debugging. It is difficult at best to determine where the code segment is that you are working on, and when you do find it, SID does not allow you to enter it as an offset for all furture address references. Isn't it wonderful, SID is described in the manuals 2 or 3 times and DRI provides a handy SID command summary card, of which all but one are wrong. The correct description is in table 5-18 of the Users Guide. The old SID required: Ifilename.typ Roffset to read a .HEX file. The new SID uses: Rfilename.typ,offset to read either a .COM or .HEX file. I like the new SID better, but think the manuals should reflect how it works. SAVE function works a little different in CP/M Plus. It must be executed before the code you wish saved is put into memory. For example, in 2.2 you would load a program with DDT, modify it, and SAVE it back to the disk. In Plus you must execute SAVE, then load and modify your program using SID. When you exit SID, SAVE comes alive and asks you what to name the file and how big it is. It worked well in unbanked versions of Plus, but it sometimes doesn't work in my banked system. I work around it by using the W command in SID. SID is the only utility that SAVE seems not to work with, and that is only in a banked environment. DRI was no help when I finally got through. LINK is also provided with CP/M 3. It does a fine job providing you write excellent code the first time and don't have to find it for debug. You should become familiar with the HEX math commands in SID. In version 2.2, if you wished to redirect the console or printer, you built the feature into your BIOS and used the IOBYTE to control it. DRI has been nice enough to reserve location 3H for the IOBYTE, but no longer supports the IOBYTE function and has replaced it with DEVICE. DEVICE is much better than IOBYTE, in that it is much more flexible, and allows more choices. But my boot ROM had the IOBYTE support blown in. I strongly recommend that the IOBYTE support in ROM be removed if you have a banked system. If not, you must limit the buffer area to avoid 0003H in bank 0 which may be in context whenever character I/O is done, so that the contents of IOBYTE will not be modified. Upon initialization you must now clear the IOBYTE in both banks, 0 and 1. Failure to use caution will result in your system trying to talk to alternate devices and mislead you in wondering where your system went. The version 1 and 2 SYSGEN program has been replaced by COPYSYS. I have found two bugs in COPYSYS. COPYSYS will read a .COM file and place it on the system tracks. One bug dealt with reading the track image file under the Plus version. COPYSYS calls BDOS function 50 (direct BIOS) to set the DMA address and should have called BDOS function 26 (set DMA address) while reading the file, and COPYSYS should call function 50 when reading or writing the system tracks image. The other bug appeared when I wrote the track image under Plus to a 1K sector track. CP/M was doing the blocking and deblocking, and COPYSYS never told it to flush the buffer; therefore, it never wrote the last sector to the disk. This can be fixed by calling BDOS function 48 (Flush Buffers) at the end of the copy. In trying to make life simple, I wrote the file shown in figure 2 to test COPYSYS, and also to be sure I was placing the binary code in the proper place on the system tracks. As you can see, the first track is single density and the second track is double. I assembled the file, used SID to load it over a field of zeros, and then saved it. After writing it to the system tracks, I used a dump program running under version 2.2 to see that each sector contained data which verified its address. I also read this file into memory in order to easily determine what offsets to use in loading the files that made up the system tracks image I built many versions of the system as each new feature was incorporated. All the features that could be incorporated in the non-banked system were installed and tested before I continued on to banked systems. When I started working with banking, my common area was a 32K segment from 8000H up. I had four 32K banked memory segments initially which increased to 10 by the completion of this article. The 32K common area allowed me to keep the version 2.2 system I was operating under, the version 3.0 system being debugged, and SID in common memory. The next version of the system progressed to 3 extra banks, and the final system only one extra bank using the rest of the memory for a RAMDISK. I went back and built several verions of the system with as much code in common as possible, and saved them for benchmarks. My benchmarks are very oriented to the type of work that I do, like editing assembly language files, and assembling them. I realize that it seems self centered, but I can relate these to what I do better that some sieve program. The source file I used for the test happens to be a format program which is relatively large (28K). The three tests I used for comparison are the assembly of the file using MAC, read in PMATE and the file for editing, and lastly typing the file to the console. I always used the same diskette and just changed the operating system on it. The six operating systems used are CP/M V2.2; CP/M Plus non-banked (NB); CP/M Plus with 1 bank (1B); CP/M Plus with 3 32K banks (3B); CP/M Plus with 1 bank and a RAM disk using the floppy drive (RD- A); and the same system as RD-A only using the RAM disk (RD-C). The computer is an S100 with a 4 MHz. Z80 (JADE BIG Z) and a JADE DD Disk controller running 1 KB sectors on 8" diskettes. Command Line> MAC FMT PMATE FMT.ASM TYPE FMT.ASM [NOPAGE] System V2.2 1:47 9.8 44.5 Plus NB 1:46 9.8 45.0 S1 1:46 12.9 49.9 S3 1:38 12.8 50.3 RD-A 1:49 13.0 49.8 RD-C 1:10 7.7 46.0 The above figures were obtained in only one run of each system and relied on the accuracy of a human and a stop watch. The assembly was in minutes and seconds, the others in seconds. Of course, the RAM disk figures were not obtained using the same exact floppy. As you can see there isn't a great deal of change between systems. These tests are relatively unfair to the new features of CPM Plus since the assembly is CPU bound, and the TYPE is bound by the 9600 baud serial link to the terminal but, non-the-less, they are things I do. As expected, the assembly time is best on the RAM disk. The buffering in S3 does help, but maybe the extra RAM is best used by making a RAM disk. CP/M 3 does not allow any control of the LRU (least record used) buffering algorithym, and therefore you are not able to optimize it for your application. The loading of a file to edit is very dependant upon I/O. The banked systems seem to add about 30% to the I/O bound operation, and the RAM disk takes about 20% less. The files had not been used previously, so were not in the Data Buffers. When editing the file twice in a row, the second load also took 12.8 on S3. No improvement even though I allocated a 48 sector buffer. I went back and regened the system to have 240 1K buffers, and still no improvement. Maybe the LRU buffering is not working in my system. The TYPE test was included since I thought that things were going slower, and they are, about 10%. The RAM disk makes up for the 10% lost by banking. The increased time to type a file in a banked system could be due to BDOS always saving the old stack, changing banks, and restoring the stack on a per character basis. To do or not to do CP/M Plus, that is the question. Well if you are looking for the added goodies like I/O redirection, ease in adding multiple disk controllers, editing command lines, fast warm boot, etc., then it is worth the effort. If you are looking for increased operating speed, stay with 2.2 and get a RAM disk. The things I really like are: Fast warm boot I/O redirection Ease of installing RAM disk Editing of previous command line. Confirm of wild card ERA, PIP SAVE features Auto disk relog I put CCP.COM and CPMLDR.COM on the system tracks, and when reading CCP during cold boot, save an image of it in bank 0. This gives me the feature of not having to have a system disk in drive A all the time. Due to auto density select, I still must use CNTRL-C if the floppies are of different densities. This makes a two drive system very easy to use. Things I don't really like are: CP/M Plus on encountering a disk error returns to the CCP, whereas 2.2 would ignore the error if a return was typed, and continue what it was doing. Some programs can be restarted if they crashed by executing location 103H. In a banked environment this is very difficult since you must first switch to bank 1, and then execute the program. Will all my software run under Plus? - Yes and No. I have not found anything that would not run in a non-banked system on single density diskettes. In a banked environment anything that jumps directly to the disk I/O BIOS vectors will not work. The disk routines are in bank 0, and the program is executing in bank 1. Since the wrong bank is in context when the routine is called, your system will probrably jump to the right place in the wrong bank, and get lost. If CP/M Plus is doing blocking and deblocking for the BIOS, any utility that calls the disk BIOS vectors directly will not work. In PLUS, the entire sector is transferred on a read or write, instead of only the deblocked 128 byte segment as in V2.2. Also the maximum sector number for each track in CP/M Plus is the Physical number not the Logical. For example if you have 8 1KB sectors per track on your diskette, in V2.2 all calls to the BIOS are relative to the maximum sector number of 64 (8 physical sectors X 8 128 byte logical sectors per physical sector) and transfer 128 bytes per READ or WRITE. In Plus the maximum sector number would be 8 and every time you call the READ or WRITE, it puts 1024 bytes into your buffer. Many of the utilities like DU expect only 128 bytes, therefore do not function properly. There are reasons to go to CP/M Plus, but performance increases on a floppy based system doesn't seem to be one of them. There are many nice features, but are they worth the $270 - 350 cost. Many of the features like hashed directories would be more beneficial on hard disk systems. Also, many of the features such as the multiple desk device support, character I/O direction, the nice error reporting and minimal banking could be incorporated in your version 2.2 BIOS.  TITLE 'JSYS - UPDATED SYSGEN PROGRAM 7/22/83' ; SYSTEM GENERATION PROGRAM ; ;LAST EDITED 08/01/83 16:53:23 ;LAST EDITED 07/22/83 09:43:02 ;MODIFIED TO WRITE LARGE SECTOR TRK 1 UNDER 3.0 ;LAST EDITED 07/04/83 23:52:29 ;CHANGED TO WRITE LARGE TRACK 1 - SHELODN KOLANSKY VERS EQU 30 ;VERSION X.X FOR CP/M X.X FALSE EQU 0 TRUE EQU NOT FALSE ; NSECTS EQU 26 ;NO. OF SECTORS NSECTS1 EQU 64+1 ;NO. OF SECTORS TRACK 1+1 SK 7/4/83 NSTS30: EQU 8+1 ;NO OF SECTORS FOR CPM3 ON TRK 1SK 7/22/83 NTRKS EQU 2 ;NO. OF SYSTEMS TRACKS NDISKS EQU 4 ;NO. OF DISKS DRIVES SECSIZ EQU 128 ;SIZE OF SECTOR LOG2SEC EQU 7 ;LOG2 128 SKEW EQU 4 ;SKEW SECTOR FACTOR ; FCB EQU 005CH ;LOCATION OF FCB FCBCR EQU FCB+32 ;CURRENT RECORD LOCATION TPA EQU 0100H ;TRANSIENT PROGRAM AREA LOADP EQU 1000H ;LOAD POINT FOR SYSTEM BDOS EQU 05H ;DOS ENTRY POINT BOOT EQU 00H ;REBOOT FOR SYSTEM CONI EQU 1H ;CONSOLE INPUT FUNCTION CONO EQU 2H ;CONSOLE OUTPUT FUNCTION SELD EQU 14 ;SELECT A DISK FLUSH: EQU 30H ;BDOS FLUSH BUFFERS OPENF EQU 15 ;DISK OPEN FUNCTION CLOSEF EQU 16 ;OPEN A FILE DWRITF EQU 21 ;WRITE FUNC MAKEF EQU 22 ;MAE A FILE DELTEF EQU 19 ;DELETE A FILE DREADF EQU 20 ;DISK READ FUNCTION DRBIOS EQU 50 ;DIRECT BIOS CALL FUNCTION EIGHTY EQU 080H ;VALUE OF 80 CTLC EQU 'C'-'@' ;CONTROL C Y EQU 89 ;ASCII VALUE OF Y ; MAXTRY EQU 01 ;MAXIMUM NUMBER OF TRIES CR EQU 0DH ;CARRIAGE RETURN LF EQU 0AH ;LINE FEED STACKSIZE EQU 016H ;SIZE OF LOCAL STACK ; WBOOT EQU 01 ;ADDRESS OF WARM BOOT ; SELDSK EQU 9 ;BIOS FUNC #9 SELECT DISK SETTRK EQU 10 ;BIOS FUNC #10 SET TRACK SETSEC EQU 11 ;BIOS FUNC #11 SET SECTOR SETDMA EQU 12 ;BIOS FUNC #12 SET DMA ADDRESS READF EQU 13 ;BIOS FUNC #13 READ SELECTED SECTOR WRITF EQU 14 ;BIOS FUNC #14 WRITE SELECTED SECTOR ; ORG TPA ;TRANSIENT PROGRAM AREA JMP START DB 'LAST EDITED 07/22/83 09:44:39' DW 0,0,0,0,0,0,0,0 DW 0,0,0,0,0,0,0,0 DW 0,0,0,0,0,0,0,0 DW 0,0,0,0,0 DB 0,0,0 DB 'COPYRIGHT 1982, ' DB 'DIGITAL RESEARCH' DB '151282' DB 0,0,0,0 DB '654321' ; ; TRANSLATE TABLE-SECTOR NUMBERS ARE TRANSLATED HERE TO DECREASE ; THE SYSTEN TIME FOR MISSED SECTORS WHEN SLOW CONTROLLERS ARE ; INVOLVED. TRANSLATE TAKES PLACE ACCORDING TO THE "SKEW" FACTOR ; SET ABOVE. ; OST: DB NTRKS ;OPERATING SYSTEM TRACKS SPT: DB NSECTS ;SECTORS PER TRACK TRAN: TRELT SET 1 TRBASE SET 1 REPT NSECTS DB TRELT ;GENERATE FIRST/NEXT SECTOR TRELT SET TRELT+SKEW IF TRELT GT NSECTS TRBASE SET TRBASE+1 TRELT SET TRBASE ENDIF ENDM ; ; NOW LEAVE SPACE FOR EXTENSIONS TO TRANSLATE TABLE ; IF NSECTS LT 64 REPT 64-NSECTS DB 0 ENDM ENDIF ; ; UTILITY SUBROUTINES ; MLTBY3: ;MULTIPLY THE CONTENTS OF REGE TO GET JMP ADDRESS MOV A,E ;ACC = E SUI 1 MOV E,A ;GET READY FOR MULTIPLY ADD E ADD E MOV E,A RET ;BACK AT IT ; SEL: STA TEMP LDA V3FLG CPI TRUE LDA TEMP JNZ SEL2 ; STA CREG ;CREG = SELECTED REGISTER LXI H,0000H SHLD EREG ;FOR FIRST TIME MVI A,SELDSK STA BIOSFC ;STORE IT IN FUNC SPACE MVI C,DRBIOS LXI D,BIOSPB JMP BDOS SEL2: MOV C,A LHLD WBOOT LXI D,SELDSK CALL MLTBY3 DAD D MVI E,0 ;LOG REQUEST PCHL ; TRK: ; SET UP TRACK STA TEMP LDA V3FLG CPI TRUE LDA TEMP JNZ TRK2 ; MVI A,00H STA BREG ;ZERO OUT B REGISTER MOV A,C ;ACC = TRACK # STA CREG ;SET UP PB MVI A,SETTRK ;SETTRK FUNC # STA BIOSFC MVI C,DRBIOS LXI D,BIOSPB JMP BDOS TRK2: LHLD WBOOT LXI D,SETTRK CALL MLTBY3 DAD D PCHL ;GONE TO SET TRACK ; SEC: ; SET UP SECTOR NUMBER STA TEMP LDA V3FLG CPI TRUE LDA TEMP JNZ SEC2 ; MVI A,00H STA BREG ;ZERO OUT BREG MOV A,C ; ACC = C STA CREG ;CREG = SECTOR # MVI A,SETSEC STA BIOSFC ;SET UP BIOS CALL MVI C,DRBIOS LXI D,BIOSPB JMP BDOS SEC2: LHLD WBOOT LXI D,SETSEC CALL MLTBY3 DAD D PCHL ; DMA: ; SET DMA ADDRESS TO VALUE OF BC STA TEMP LDA V3FLG CPI TRUE LDA TEMP JNZ DMA2 ; MOV A,B ; STA BREG ; MOV A,C ;SET UP THE BC STA CREG ;REGISTER PAIR MVI A,SETDMA ; STA BIOSFC ;SET UP BIOS # MVI C,DRBIOS LXI D,BIOSPB JMP BDOS DMA2: LHLD WBOOT LXI D,SETDMA CALL MLTBY3 DAD D PCHL DDMA: ;VER 3.0 REQUIRES FILE READ DMA TO BDOS ; ROUTINE ADDED 7/22/83 SK ; SET DMA ADDRESS TO VALUE OF BC LDA V3FLG CPI TRUE JNZ DMA2 ; MOV D,B ;MOVE TO DE MOV E,C MVI C,1AH ;BDOS SET DMA JMP BDOS ; READ: ; PERFORM READ OPERATION STA TEMP LDA V3FLG CPI TRUE LDA TEMP JNZ READ2 ; MVI A,READF STA BIOSFC MVI C,DRBIOS LXI D,BIOSPB JMP BDOS READ2: LHLD WBOOT LXI D,READF CALL MLTBY3 DAD D PCHL ; WRITE: ; PERFORM WRITE OPERATION STA TEMP LDA V3FLG CPI TRUE LDA TEMP JNZ WRITE2 ; MVI A,WRITF STA BIOSFC ;SET UP BIOS # MVI C,DRBIOS LXI D,BIOSPB JMP BDOS ; WRITE2: LHLD WBOOT LXI D,WRITF CALL MLTBY3 DAD D LDA SECTOR CPI 64 ;ON SECTOR 64 FORCE WRITE SK 7/4/83 JNZ WRIT3 ;TO FLUSH DEBLOCK SECTOR SK MVI C,1 ;WRITE TYPE DIRECTORY SK WRIT3: PCHL ; MULTSEC: ; MULTIPLY THE SECTOR # IN RA BY THE SECTOR SIZE MOV L,A MVI H,0 ;SECTOR IN HL ; REPT LOG2SEC ; SK 7/4/83 ; DAD H ; ENDM DAD H ; SK 7/4/83 DAD H ; SK 7/4/83 DAD H ; SK 7/4/83 DAD H ; SK 7/4/83 DAD H ; SK 7/4/83 DAD H ; SK 7/4/83 DAD H ; SK 7/4/83 LDA TRACK ; SK 7/4/83 ANA A ;TEST FOR TRACK 0 OR 1 SK 7/4/83 RZ ;TRACK 0 ONLY 128 BYTES SK 7/4/83 LDA V3FLG ;FOR VER 3.0 SK 7/4/83 ANA A ;V2.2 SECT SIZE IS 128 SK 7/4/83 RZ ; SK 7/4/83 DAD H ;TRACK 1 1024 SK 7/4/83 DAD H ; SK 7/4/83 DAD H RET ;WITH HL - SECTOR*SECTORSIZE ; GETCHAR: ; READ CONSOLE CHARACTER TO RA MVI C,CONI CALL BDOS ; CONVERT TO UPPER CASE CPI 'A' OR 20H RC CPI ('Z' OR 20H)+1 RNC ANI 05FH RET ; PUTCHAR: ; WRITE CHARACTER FROM RA TO CONSOLE MOV E,A MVI C,CONO CALL BDOS RET ; CRLF: ; SEND CARRIAGE RETURN, LINE FEED MVI A,CR CALL PUTCHAR MVI A,LF CALL PUTCHAR RET ; CRMSG: ; PRINT MESSAGE ADDRESSED BY THE HL UNTIL ZERO WITH LEADING CRLF PUSH D CALL CRLF POP D ;DROP THROUGH TO OUTMSG OUTMSG: MVI C,9 JMP BDOS ; SELCT: ; SELECT DISK GIVEN BY RA MVI C,0EH JMP BDOS ; DWRITE: ; WRITE FOR FILE COPY MVI C,DWRITF JMP BDOS ; DREAD: ; DISK READ FUNCTION MVI C,DREADF JMP BDOS ; OPEN: ; FILE OPEN FUNCTION MVI C,OPENF JMP BDOS ; CLOSE: MVI C,CLOSEF JMP BDOS ; MAKE: MVI C,MAKEF JMP BDOS ; DELETE: MVI C,DELTEF JMP BDOS ; ; ; DSTDMA: MVI C,26 JMP BDOS ; SOURCE: LXI D,GETPRM ;ASK USER FOR SOURCE DRIVE CALL CRMSG CALL GETCHAR ;OBTAIN RESPONSE CPI CR ;IS IT CR? JZ DFLTDR ;SKIP IF CR ONLY CPI CTLC ;ISIT ^C? JZ REBOOT ; SUI 'A' ;NORMALIZE DRIVE # CPI NDISKS ;VALID DRIVE? JC GETC ;SKIP TO GETC IF SO ; ; INVALID DRIVE CALL BADDISK ;TELL USER BAD DRIVE JMP SOURCE ;TRY AGAIN ; GETC: ; SELECT DISK GIVEN BY ACC. ADI 'A' STA GDISK ;STORE SOURCE DISK SUI 'A' MOV E,A ;MOVE DISK INTO E FOR SELECT FUNC CALL SEL ;SELECT THE DISK JMP GETVER ; DFLTDR: MVI C,25 ;FUNC 25 FOR CURRENT DISK CALL BDOS ;GET CURDSK ADI 'A' STA GDISK CALL CRLF LXI D,VERGET CALL OUTMSG JMP VERCR ; GETVER: ; GETSYS SET R/W TO READ AND GET THE SYSTEM CALL CRLF LXI D,VERGET ;VERIFY SOURCE DISK CALL OUTMSG VERCR: CALL GETCHAR CPI CR JNZ REBOOT ;JMP ONLY IF NOT VERIFIED CALL CRLF RET ; DESTIN: LXI D,PUTPRM ;ADDRESS OF MESSAGE CALL CRMSG ;PRINT IT CALL GETCHAR ;GET ANSWER CPI CR JZ REBOOT ;ALL DONE SUI 'A' CPI NDISKS ;VALID DISK JC PUTC ; ; INVALID DRIVE CALL BADDISK ;TELL USER BAD DRIVE JMP PUTSYS ;TO TRY AGAIN ; PUTC: ; SET DISK FRON RA ADI 'A' STA PDISK ;MESSAGE SENT SUI 'A' MOV E,A ;DISK # IN E CALL SEL ;SELECT DESTINATION DRIVE ; PUT SYSTEM, SET R/W TO WRITE LXI D,VERPUT ;VERIFY DEST PRMPT CALL CRMSG ;PRINT IT OUT CALL GETCHAR ;RETRIEVE ANSWER CPI CR JNZ REBOOT ;EXIT TO SYSTEM IF ERROR CALL CRLF RET ; ; GETPUT: ; GET OR PUT CP/M (RW = 0 FOR READ, 1 FOR WRITE) ; DISK IS ALREADY SELECTED LXI H,LOADP ;LOAD POINT IN RAM FOR DMA ADDRESS SHLD DMADDR ; ; ; ; ; CLEAR TRACK 00 MVI A,-1 ; STA TRACK ; RWTRK: ; READ OR WRITE NEXT TRACK LXI H,TRACK INR M ;TRACK = TRACK+1 LDA OST ;# OF OS TRACKS CMP M ;=TRACK # ? JZ ENDRW ;END OF READ/WRITE ; ; OTHERWISE NOT DONE MOV C,M ;TRACK NUMBER CALL TRK ;SET TO TRACK MVI A,0 ;COUNTS 0,1,2,...,25 STA SECTOR ; RWSEC: ; READ OR WRITE A SECTOR LDA SPT ;SECTORS PER TRACK LXI H,SECTOR INR M ;SET TO NEXT SECTOR CMP M ;A=26 AND M=0,1,..,25 JZ ENDTRK ; ; READ OR WRITE SECTOR TO OR FROM CURRENT DMA ADDRESS LXI H,SECTOR MVI B,1 ;IF NOTRANS B MUST = 0 FORD DMA ADDR SK LDA TRACK ;SEE IF TRACK 1 SK 07/04/83 CPI 1 ;NO TRANSLATE ON 1 SK JZ NOTRANS ; SK MOV E,M ;SECTOR NUMBER MVI D,0 ;TO DE LXI H,TRAN MOV B,M ;TRAN(0) IN B DAD D ;SECTOR TRANSLATED NOTRANS MOV C,M ;VALUE TO C READY FOR SELECT PUSH B ;SAVE TRAN(0) CALL SEC POP B ;RECALL TRAN(0),TRAN(SECTOR) MOV A,C ;TRAN(SECTOR) SUB B ;--TRAN(SECTOR) CALL MULTSEC ;*SECTOR SIZE XCHG ;TO DE LHLD DMADDR ;BASE DMA DAD D MOV B,H MOV C,L ;TO SET BC FOR SEC CALL CALL DMA ;DMA ADDRESS SET FROM BC XRA A STA RETRY ;TO SET ZERO RETRIES ; TRYSEC: ; TRY TO READ OR WRITE CURRENT SECTOR LDA RETRY CPI MAXTRY JC TRYOK ; ; PAST MAXTRY, MESSAGE AND IGNORE LXI D,ERRMSG CALL OUTMSG CALL GETCHAR CPI CR JNZ REBOOT ; ; TYPED A CR, OK TO IGNORE CALL CRLF JMP RWSEC ; TRYOK: ; OK TO TYR READ WRITE INR A STA RETRY LDA RW ORA A JZ TRYREAD ; ; MUST BE WRITE CALL WRITE ANA A ;SEE IF ERROR SK JNZ CHKRW ;YES JUMP SK ;TEST FOR LAST SECTOR SK 8/1/83 LDA TRACK ; SK ORA A ;OF LAST TRACK SK JZ CHKRW ; SK LDA SECTOR ;AND FLUSH SK CPI NSTS30 ; SK MVI A,0 ;SHOW NO ERROR SK JNZ CHKRW ; SK MVI C,FLUSH ; SK CALL BDOS ; SK JMP CHKRW ; TRYREAD: CALL READ CHKRW: ORA A JZ RWSEC ;ZERO FLAG IF READ/WRITE OK ; ;ERROR, RETRY OPERATION JMP TRYSEC ; ; END OF TRACK ENDTRK: LDA SPT ;SECTORS PER TRACK CALL MULTSEC ;*SECSIZE XCHG ; TO DE LHLD DMADDR ;BASE DMA FOR THIS TRACK DAD D ;+SPT*SECSIZE SHLD DMADDR ;READY FOR NEXT TRACK LDA V3FLG ;GET VERSION 3 FLAG SK 07/22/83 ORA A ;TEST FOR FALSE = 0 SK MVI A,NSTS30 ;GET VERIONS 3 SECTS PER TRK SK JNZ ENDT1 ;AND JUMP IF 3.0 SK MVI A,NSECTS1 ;SET UP FOR TRACK 1 SK 07/04/83 ENDT1: STA SPT ; SK JMP RWTRK ;FOR ANOTHER TRACK ; ENDRW: ; END OF READ OR WRITE MVI A,NSECTS ;RESTORE SPT FOR NEXT TRACK 0 SK STA SPT ; SK RET ; ;******************* ;* ;* MAIN ROUTINE ;* ;* ;******************* ; START: LXI SP,STACK LXI D,SIGNON CALL OUTMSG ; ;GET VERSION NUMBER TO CHECK COMPATABILITY MVI C,12 ;VERSION CHECK CALL BDOS MOV A,L ;VERSION IN ACC CPI 30H ;VERSION 3 OR NEWER? JC OLDRVR ; MVI A,TRUE STA V3FLG ; JMP FCBCHK OLDRVR: MVI A,FALSE STA V3FLG ; ; CHECK FOR DEFAULT FILE LIAD INSTEAD OF GET FCBCHK: LDA FCB+1 ;BLANK IF NO FILE CPI ' ' JZ GETSYS ;SKIP TO SYSTEM MESSAGE LXI D,FCB ;TRY TO OPEN IT CALL OPEN INR A ;255 BECOMES 00 JNZ RDOK ; ; FILE NOT PRESENT LXI D,NOFILE CALL CRMSG JMP REBOOT ; ;FILE PRESENT RDOK: XRA A STA FCBCR ;CURRENT RECORD = 0 LXI H,LOADP RDINP: PUSH H MOV B,H MOV C,L CALL DDMA ;DMA ADDRESS SET SK LXI D,FCB ;READY FR READ CALL DREAD POP H ;RECALL ORA A ;00 IF READ OK JNZ PUTSYS ;ASSUME EOF IF NOT ; MORE TO READ CONTINUE LXI D,SECSIZ DAD D ;HL IS NEW LOAD ADDRESS JMP RDINP ; GETSYS: CALL SOURCE ;FIND OUT SOURCE DRIVE ; XRA A ;ZERO OUT A STA RW ;RW = 0 TO SIGNIFY READ CALL GETPUT ;GET OR READ SYSTEM LXI D,DONE ;END MESSAGE OF GET OR READ FUNC CALL OUTMSG ;PRINT IT OUT ; ; PUT THE SYSTEM PUTSYS: CALL DESTIN ;GET DEST DRIVE ; LXI H,RW ;LOAD ADDRESS MVI M,1 CALL GETPUT ;TO PUT SYSTEM BACK ON DISK LXI D,DONE CALL OUTMSG ;PRINT OUT END PROMPT ; ; FILE COPY FOR CPM.SYS ; CPYCPM: ; PROMPT THE USER FOR THE SOURCE OF CP/M3.SYS ; LXI D,CPYMSG ;PRINT COPYS PROMPT CALL CRMSG ;PRINT IT CALL GETCHAR ;OBTAIN REPLY CPI Y ;IS IT YES? JNZ REBOOT ;IF NOT EXIT ;ELSE ; ; MVI C,13 ;FUNC # FOR RESET CALL BDOS ; INR A LXI D,ERRMSG CZ FINIS ; CALL SOURCE ;GET SOURCE DISK FOR CPM3.SYS CNTNUE: LDA GDISK ;ACC = SOURCE DISK SUI 'A' MVI D,00H MOV E,A ;DE = SELECTED DISK CALL SELCT ; NOW COPY THE FCBS MVI C,36 ;FOR COPY LXI D,SFCB ;SOURCE FILE LXI H,DFCB ;DESTINATION FILE MFCB: LDAX D INX D ;READY NEXT MOV M,A INX H ;READY NEXT DEST DCR C ;DECREMENT COUN JNZ MFCB ; LDA GDISK ;ACC = SOURCE DISK SUI 40H ;CORRECT DISK LXI H,SFCB MOV M,A ;SFCB HAS SOURCE DISK # LDA PDISK ;GET THE DEST. DISK LXI H,DFCB ; SUI 040H ;NORMALIZE DISK MOV M,A ; XRA A ;ZERO OUT A STA DFCBCR ;CURRENT REC = 0 ; ; SOURCE AND DESTINATION FCB'S READY ; LXI D,SFCB ; CALL OPEN ;OPEN THE FILE LXI D,NOFILE ;ERROR MESSG INR A ;255 BECOMES 0 CZ FINIS ;DONE IF NO FILE ; ; SOURCE FILE IS PRESENT AND OPEN LXI D,LOADP ;GET DMA ADDRESS XCHG ;MOVE ADDRESS TO HL REGS SHLD BEGIN ;SAVE FOR BEGIN OF WRITE ; LDA BEGIN ;GET LOW BYTE OF MOV L,A ;DMA ADDRESS INTO L LDA BEGIN+1 ; MOV H,A ;INTO H ALSO COPY1: XCHG ;DE = ADDRESS OF DMA CALL DSTDMA ; ; LXI D,SFCB ; CALL DREAD ;READ NEXT RECORD ORA A ;END OF FILE? JNZ EOF ;SKIP WRITE IF SO ; LDA CRNREC INR A ;BUMP IT STA CRNREC ; LDA BEGIN MOV L,A LDA BEGIN+1 MOV H,A LXI D,EIGHTY DAD D ;ADD EIGHTY TO BEGIN ADDRESS SHLD BEGIN JMP COPY1 ;LOOP UNTIL EOF ; EOF: LXI D,DONE CALL OUTMSG ; COPY2: CALL DESTIN ;GET DESTINATION DRIVE FOR CPM3.SYS LXI D,DFCB ;SET UP DEST FCB XCHG LDA PDISK SUI 040H ;NORMALIZE DISK MOV M,A ;CORRECT DISK FOR DEST XCHG ;DE = DFCB CALL DELETE ;DELETE FILE IF THERE ; LXI D,DFCB ; CALL MAKE ;MAKE A NEW ONE LXI D,NODIR INR A ;CHECK DIRECTORY SPACE CZ FINIS ;END IF NONE ; LXI D,LOADP XCHG SHLD BEGIN ; LDA BEGIN MOV L,A LDA BEGIN+1 MOV H,A LOOP2: XCHG CALL DSTDMA LXI D,DFCB CALL DWRITE LXI D,FSPACE ORA A CNZ FINIS LDA CRNREC DCR A STA CRNREC CPI 0 JZ FNLMSG LDA BEGIN MOV L,A LDA BEGIN+1 MOV H,A LXI D,EIGHTY DAD D SHLD BEGIN JMP LOOP2 ; COPY OPERATION COMPLETE FNLMSG: LXI D,DFCB MVI C,CLOSEF CALL BDOS ; LXI D,DONE ; FINIS: ; WRITE MESSAGE GIVEN BY DE, REBOOT CALL OUTMSG ; REBOOT: MVI C,13 CALL BDOS CALL CRLF JMP BOOT ; BADDISK: LXI D,QDISK CALL CRMSG RET ;**************************** ;* ;* ;* DATA STRUCTURES ;* ;* ;**************************** ; BIOSPB: ; BIOS PARAMETER BLOCK BIOSFC: DB 0 ;BIOS FUNCTION NUMBER AREG: DB 0 ;A REGISTER CONTENTS CREG: DB 0 ;C REGISTER CONTENTS BREG: DB 0 ;B REGISTER CONTENTS EREG: DB 0 ;E REGISTER CONTENTS DREG: DB 0 ;D REGISTER CONTENTS HLREG: DW 0 ;HL REGISTER CONTENTS ; SFCB: DR: DS 1 F1F8: DB 'CPM3 ' T1T3: DB 'SYS' EXT: DB 0 CS: DB 0 RS: DB 0 RCC: DB 0 D0D15: DS 16 CCR: DB 0 R0R2: DS 3 ; DFCB: DS 36 DFCBCR EQU DFCB+32 ; ; V3FLG: DB 0 ;FLAG FOR VERSION # TEMP: DB 0 SDISK: DS 1 ;SELECTED DISK BEGIN: DW 0 DFLAG: DB 0 TRACK: DS 1 ;CURRENT TRACK CRNREC: DB 0 ;CURRENT REC COUNT SECTOR: DS 1 ;CURRENT SECTOR RW: DS 1 ;READ IF 0 WRITE IF 1 DMADDR: DS 2 ;CURRENT DMA ADDRESS RETRY: DS 1 ;NUMBER OF TRIES ON THIS SECTOR SIGNON: DB 'CP/M 3 COPYSYS - VERSION ' DB VERS/10+'0','.',VERS MOD 10 +'0' DB '$' GETPRM: DB 'SOURCE DRIVE NAME (OR RETURN FOR DEFAULT) $' VERGET: DB 'SOURCE ON ' GDISK: DS 1 DB ' THEN TYPE RETURN $' PUTPRM: DB 'DESTINATION DRIVE NAME (OR RETURN TO REBOOT) $' VERPUT: DB 'DESTINATION ON ' PDISK: DS 1 DB ' THEN TYPE RETURN $' CPYMSG: DB 'DO YOU WISH TO COPY CPM3.SYS? $' DONE: DB 'FUNCTION COMPLETE$' ; ; ERROR MESSAGES...... ; QDISK: DB 'ERROR: INVALID DRIVE NAME (USE A, B, C, OR D)$' NOFILE: DB 'ERROR: NO SOURCE FILE ON DISK.$' NODIR: DB 'ERROR: NO DIRECTORY SPACE.$' FSPACE: DB 'ERROR: OUT OF DATA SPACE.$' WRPROT: DB 'ERROR: WRITE PROTECTED?$' ERRMSG: DB 'ERROR: POSSIBLE INCOMPATIBLE DISK FORMAT.' DB CR,LF,' TYPE RETURN TO IGNORE.$' CLSERR: DB 'ERROR: CLOSE OPERATION FAILED.$' ; DS STACKSIZE * 3 STACK: END :10010000C3C3044C41535420454449544544203012 :10011000372F32322F38332030393A34343A3339AA :1001200000000000000000000000000000000000CF :1001300000000000000000000000000000000000BF :1001400000000000000000000000000000000000AF :1001500000000000000000000000000000434F50BD :1001600059524947485420313938322C20444947A4 :100170004954414C20524553454152434831353151 :1001800032383200000000363534333231021A0181 :1001900005090D11151902060A0E12161A03070B8E :1001A0000F131704080C10141800000000000000C2 :1001B000000000000000000000000000000000003F :1001C0000000000000000000000000000000007BB4 :1001D000D6015F83835FC932A3063AA206FEFF3AC7 :1001E000A306C2FB013254062100002256063E0936 :1001F0003252060E32115206C305004F2A01001179 :100200000900CDCF01191E00E932A3063AA206FE6D :10021000FF3AA306C22D023E00325506793254063B :100220003E0A3252060E32115206C305002A010060 :10023000110A00CDCF0119E932A3063AA206FEFF4A :100240003AA306C25C023E00325506793254063E9D :100250000B3252060E32115206C305002A0100115C :100260000B00CDCF0119E932A3063AA206FEFF3AF0 :10027000A306C28A0278325506793254063E0C3201 :1002800052060E32115206C305002A0100110C005D :10029000CDCF0119E93AA206FEFFC28A0250590EDB :1002A0001AC3050032A3063AA206FEFF3AA306C20D :1002B000BF023E0D3252060E32115206C305002A0D :1002C0000100110D00CDCF0119E932A3063AA206B3 :1002D000FEFF3AA306C2E5023E0E3252060E32116E :1002E0005206C305002A0100110E00CDCF01193AB4 :1002F000AA06FE40C2F9020E01E96F26002929294B :10030000292929293AA806A7C83AA206A7C829294F :1003100029C90E01CD0500FE61D8FE7BD0E65FC97C :100320005F0E02CD0500C93E0DCD20033E0ACD2053 :1003300003C9D5CD2703D10E09C305000E0EC30591 :10034000000E15C305000E14C305000E0FC30500F3 :100350000E10C305000E16C305000E13C305000ED4 :100360001AC3050011CC06CD3203CD1203FE0DCA0F :100370009203FE03CA4006D641FE04DA8403CD4B45 :1003800006C36403C641320107D6415FCDD701C31E :10039000A8030E19CD0500C641320107CD27031170 :1003A000F706CD3703C3B103CD270311F706CD37C9 :1003B00003CD1203FE0DC24006CD2703C911150758 :1003C000CD3203CD1203FE0DCA4006D641FE04DA3B :1003D000D803CD4B06C32E05C641325207D6415F26 :1003E000CDD701114307CD3203CD1203FE0DC2401C :1003F00006CD2703C921001022AC063EFF32A80615 :1004000021A806343A8D01BECABD044ECD09023E74 :100410000032AA063A8E0121AA0634BECA9E0421E1 :10042000AA0606013AA806FE01CA34045E16002197 :100430008F0146194EC5CD3802C17990CDFA02EB35 :100440002AAC0619444DCD6702AF32AE063AAE066D :10045000FE01DA6904113108CD3703CD1203FE0D18 :10046000C24006CD2703C314043C32AE063AAB06A5 :10047000B7CA9404CDCA02A7C297043AA806B7CA5D :1004800097043AAA06FE093E00C297040E30CD0535 :1004900000C39704CDA402B7CA1404C34D043A8E16 :1004A00001CDFA02EB2AAC061922AC063AA206B735 :1004B0003E09C2B7043E41328E01C300043E1A32E7 :1004C0008E01C931D50811AF06CD37030E0CCD050D :1004D000007DFE30DADF043EFF32A206C3E4043EB4 :1004E0000032A2063A5D00FE20CA1E05115C00CD56 :1004F0004B033CC2FF0411C507CD3203C34006AF16 :10050000327C00210010E5444DCD9502115C00CDF8 :100510004603E1B7C22E0511800019C30605CD645C :1005200003AF32AB06CDF503118507CD3703CDBD43 :100530000321AB063601CDF503118507CD37031135 :100540006607CD3203CD1203FE59C240060E0DCD13 :1005500005003C113108CC3D06CD64033A0107D6B5 :100560004116005FCD3C030E24115A06217E061A67 :100570001377230DC26F053A0107D640215A06773B :100580003A5207217E06D64077AF329E06115A06B0 :10059000CD4B0311C5073CCC3D06110010EB22A545 :1005A000063AA5066F3AA60667EBCD5F03115A0619 :1005B000CD4603B7C2D0053AA9063C32A9063AA5F2 :1005C000066F3AA606671180001922A506C3A90581 :1005D000118507CD3703CDBD03117E06EB3A5207D7 :1005E000D64077EBCD5A03117E06CD550311E407B3 :1005F0003CCC3D06110010EB22A5063AA5066F3A49 :10060000A60667EBCD5F03117E06CD410311FF0700 :10061000B7C43D063AA9063D32A906FE00CA320615 :100620003AA5066F3AA606671180001922A506C3EF :100630000306117E060E10CD0500118507CD370388 :100640000E0DCD0500CD2703C30000119707CD3255 :0A06500003C90000000000000000D4 :0F065B0043504D332020202053595300000000FE :01067A00007F :0206A200000056 :0306A50000000052 :0106A9000050 :1006AF0043502F4D203320434F5059535953202D32 :1006BF002056455253494F4E20332E3024534F5519 :1006CF00524345204452495645204E414D4520281E :1006DF004F522052455455524E20464F52204445BA :1006EF004641554C54292024534F55524345204FD2 :0206FF004E208B :10070200205448454E205459504520524554555284 :100712004E202444455354494E4154494F4E20449F :1007220052495645204E414D4520284F52205245B0 :100732005455524E20544F205245424F4F54292077 :100742002444455354494E4154494F4E204F4E2064 :10075300205448454E205459504520524554555233 :100763004E2024444F20594F552057495348205475 :100773004F20434F50592043504D332E5359533F2D :10078300202446554E4354494F4E20434F4D504C21 :10079300455445244552524F523A20494E56414CF6 :1007A3004944204452495645204E414D4520285541 :1007B300534520412C20422C20432C204F522044CF :1007C30029244552524F523A204E4F20534F5552EF :1007D30043452046494C45204F4E204449534B2E18 :1007E300244552524F523A204E4F204449524543DA :1007F300544F52592053504143452E244552524F92 :10080300523A204F5554204F4620444154412053DF :10081300504143452E244552524F523A2057524994 :1008230054452050524F5445435445443F24455268 :10083300524F523A20504F535349424C4520494E50 :10084300434F4D50415449424C45204449534B205A :10085300464F524D41542E0D0A20545950452052B3 :10086300455455524E20544F2049474E4F52452E22 :10087300244552524F523A20434C4F5345204F5038 :1008830045524154494F4E204641494C45442E243C :0000000000  CP/M MACRO ASSEM 2.0 #001 JSYS - UPDATED SYSGEN PROGRAM 7/22/83 TITLE 'JSYS - UPDATED SYSGEN PROGRAM 7/22/83' ; SYSTEM GENERATION PROGRAM ; ;LAST EDITED 08/01/83 16:53:23 ;LAST EDITED 07/22/83 09:43:02 ;MODIFIED TO WRITE LARGE SECTOR TRK 1 UNDER 3.0 ;LAST EDITED 07/04/83 23:52:29 ;CHANGED TO WRITE LARGE TRACK 1 - SHELODN KOLANSKY 001E = VERS EQU 30 ;VERSION X.X FOR CP/M X.X 0000 = FALSE EQU 0 FFFF = TRUE EQU NOT FALSE ; 001A = NSECTS EQU 26 ;NO. OF SECTORS 0041 = NSECTS1 EQU 64+1 ;NO. OF SECTORS TRACK 1+1 SK 7/4/83 0009 = NSTS30: EQU 8+1 ;NO OF SECTORS FOR CPM3 ON TRK 1SK 7/22/83 0002 = NTRKS EQU 2 ;NO. OF SYSTEMS TRACKS 0004 = NDISKS EQU 4 ;NO. OF DISKS DRIVES 0080 = SECSIZ EQU 128 ;SIZE OF SECTOR 0007 = LOG2SEC EQU 7 ;LOG2 128 0004 = SKEW EQU 4 ;SKEW SECTOR FACTOR ; 005C = FCB EQU 005CH ;LOCATION OF FCB 007C = FCBCR EQU FCB+32 ;CURRENT RECORD LOCATION 0100 = TPA EQU 0100H ;TRANSIENT PROGRAM AREA 1000 = LOADP EQU 1000H ;LOAD POINT FOR SYSTEM 0005 = BDOS EQU 05H ;DOS ENTRY POINT 0000 = BOOT EQU 00H ;REBOOT FOR SYSTEM 0001 = CONI EQU 1H ;CONSOLE INPUT FUNCTION 0002 = CONO EQU 2H ;CONSOLE OUTPUT FUNCTION 000E = SELD EQU 14 ;SELECT A DISK 0030 = FLUSH: EQU 30H ;BDOS FLUSH BUFFERS 000F = OPENF EQU 15 ;DISK OPEN FUNCTION 0010 = CLOSEF EQU 16 ;OPEN A FILE 0015 = DWRITF EQU 21 ;WRITE FUNC 0016 = MAKEF EQU 22 ;MAE A FILE 0013 = DELTEF EQU 19 ;DELETE A FILE 0014 = DREADF EQU 20 ;DISK READ FUNCTION 0032 = DRBIOS EQU 50 ;DIRECT BIOS CALL FUNCTION 0080 = EIGHTY EQU 080H ;VALUE OF 80 0003 = CTLC EQU 'C'-'@' ;CONTROL C 0059 = Y EQU 89 ;ASCII VALUE OF Y ; 0001 = MAXTRY EQU 01 ;MAXIMUM NUMBER OF TRIES 000D = CR EQU 0DH ;CARRIAGE RETURN 000A = LF EQU 0AH ;LINE FEED 0016 = STACKSIZE EQU 016H ;SIZE OF LOCAL STACK ; 0001 = WBOOT EQU 01 ;ADDRESS OF WARM BOOT ; 0009 = SELDSK EQU 9 ;BIOS FUNC #9 SELECT DISK 000A = SETTRK EQU 10 ;BIOS FUNC #10 SET TRACK 000B = SETSEC EQU 11 ;BIOS FUNC #11 SET SECTOR 000C = SETDMA EQU 12 ;BIOS FUNC #12 SET DMA ADDRESS 000D = READF EQU 13 ;BIOS FUNC #13 READ SELECTED SECTOR 000E = WRITF EQU 14 ;BIOS FUNC #14 WRITE SELECTED SECTOR CP/M MACRO ASSEM 2.0 #002 JSYS - UPDATED SYSGEN PROGRAM 7/22/83 ; 0100 ORG TPA ;TRANSIENT PROGRAM AREA 0100 C3C304 JMP START 0103 4C41535420 DB 'LAST EDITED 07/22/83 09:44:39' 0120 0000000000 DW 0,0,0,0,0,0,0,0 0130 0000000000 DW 0,0,0,0,0,0,0,0 0140 0000000000 DW 0,0,0,0,0,0,0,0 0150 0000000000 DW 0,0,0,0,0 015A 000000 DB 0,0,0 015D 434F505952 DB 'COPYRIGHT 1982, ' 016D 4449474954 DB 'DIGITAL RESEARCH' 017D 3135313238 DB '151282' 0183 00000000 DB 0,0,0,0 0187 3635343332 DB '654321' ; ; TRANSLATE TABLE-SECTOR NUMBERS ARE TRANSLATED HERE TO DECREASE ; THE SYSTEN TIME FOR MISSED SECTORS WHEN SLOW CONTROLLERS ARE ; INVOLVED. TRANSLATE TAKES PLACE ACCORDING TO THE "SKEW" FACTOR ; SET ABOVE. ; 018D 02 OST: DB NTRKS ;OPERATING SYSTEM TRACKS 018E 1A SPT: DB NSECTS ;SECTORS PER TRACK TRAN: 0001 # TRELT SET 1 0001 # TRBASE SET 1 REPT NSECTS DB TRELT ;GENERATE FIRST/NEXT SECTOR TRELT SET TRELT+SKEW IF TRELT GT NSECTS TRBASE SET TRBASE+1 TRELT SET TRBASE ENDIF ENDM 018F+01 DB TRELT ;GENERATE FIRST/NEXT SECTOR 0190+05 DB TRELT ;GENERATE FIRST/NEXT SECTOR 0191+09 DB TRELT ;GENERATE FIRST/NEXT SECTOR 0192+0D DB TRELT ;GENERATE FIRST/NEXT SECTOR 0193+11 DB TRELT ;GENERATE FIRST/NEXT SECTOR 0194+15 DB TRELT ;GENERATE FIRST/NEXT SECTOR 0195+19 DB TRELT ;GENERATE FIRST/NEXT SECTOR 0196+02 DB TRELT ;GENERATE FIRST/NEXT SECTOR 0197+06 DB TRELT ;GENERATE FIRST/NEXT SECTOR 0198+0A DB TRELT ;GENERATE FIRST/NEXT SECTOR 0199+0E DB TRELT ;GENERATE FIRST/NEXT SECTOR 019A+12 DB TRELT ;GENERATE FIRST/NEXT SECTOR 019B+16 DB TRELT ;GENERATE FIRST/NEXT SECTOR 019C+1A DB TRELT ;GENERATE FIRST/NEXT SECTOR 019D+03 DB TRELT ;GENERATE FIRST/NEXT SECTOR 019E+07 DB TRELT ;GENERATE FIRST/NEXT SECTOR 019F+0B DB TRELT ;GENERATE FIRST/NEXT SECTOR 01A0+0F DB TRELT ;GENERATE FIRST/NEXT SECTOR 01A1+13 DB TRELT ;GENERATE FIRST/NEXT SECTOR 01A2+17 DB TRELT ;GENERATE FIRST/NEXT SECTOR 01A3+04 DB TRELT ;GENERATE FIRST/NEXT SECTOR 01A4+08 DB TRELT ;GENERATE FIRST/NEXT SECTOR 01A5+0C DB TRELT ;GENERATE FIRST/NEXT SECTOR CP/M MACRO ASSEM 2.0 #003 JSYS - UPDATED SYSGEN PROGRAM 7/22/83 01A6+10 DB TRELT ;GENERATE FIRST/NEXT SECTOR 01A7+14 DB TRELT ;GENERATE FIRST/NEXT SECTOR 01A8+18 DB TRELT ;GENERATE FIRST/NEXT SECTOR ; ; NOW LEAVE SPACE FOR EXTENSIONS TO TRANSLATE TABLE ; IF NSECTS LT 64 REPT 64-NSECTS DB 0 ENDM 01A9+00 DB 0 01AA+00 DB 0 01AB+00 DB 0 01AC+00 DB 0 01AD+00 DB 0 01AE+00 DB 0 01AF+00 DB 0 01B0+00 DB 0 01B1+00 DB 0 01B2+00 DB 0 01B3+00 DB 0 01B4+00 DB 0 01B5+00 DB 0 01B6+00 DB 0 01B7+00 DB 0 01B8+00 DB 0 01B9+00 DB 0 01BA+00 DB 0 01BB+00 DB 0 01BC+00 DB 0 01BD+00 DB 0 01BE+00 DB 0 01BF+00 DB 0 01C0+00 DB 0 01C1+00 DB 0 01C2+00 DB 0 01C3+00 DB 0 01C4+00 DB 0 01C5+00 DB 0 01C6+00 DB 0 01C7+00 DB 0 01C8+00 DB 0 01C9+00 DB 0 01CA+00 DB 0 01CB+00 DB 0 01CC+00 DB 0 01CD+00 DB 0 01CE+00 DB 0 ENDIF ; ; UTILITY SUBROUTINES ; MLTBY3: ;MULTIPLY THE CONTENTS OF REGE TO GET JMP ADDRESS 01CF 7B MOV A,E ;ACC = E 01D0 D601 SUI 1 CP/M MACRO ASSEM 2.0 #004 JSYS - UPDATED SYSGEN PROGRAM 7/22/83 01D2 5F MOV E,A ;GET READY FOR MULTIPLY 01D3 83 ADD E 01D4 83 ADD E 01D5 5F MOV E,A 01D6 C9 RET ;BACK AT IT ; SEL: 01D7 32A306 STA TEMP 01DA 3AA206 LDA V3FLG 01DD FEFF CPI TRUE 01DF 3AA306 LDA TEMP 01E2 C2FB01 JNZ SEL2 ; 01E5 325406 STA CREG ;CREG = SELECTED REGISTER 01E8 210000 LXI H,0000H 01EB 225606 SHLD EREG ;FOR FIRST TIME 01EE 3E09 MVI A,SELDSK 01F0 325206 STA BIOSFC ;STORE IT IN FUNC SPACE 01F3 0E32 MVI C,DRBIOS 01F5 115206 LXI D,BIOSPB 01F8 C30500 JMP BDOS SEL2: 01FB 4F MOV C,A 01FC 2A0100 LHLD WBOOT 01FF 110900 LXI D,SELDSK 0202 CDCF01 CALL MLTBY3 0205 19 DAD D 0206 1E00 MVI E,0 ;LOG REQUEST 0208 E9 PCHL ; TRK: ; SET UP TRACK 0209 32A306 STA TEMP 020C 3AA206 LDA V3FLG 020F FEFF CPI TRUE 0211 3AA306 LDA TEMP 0214 C22D02 JNZ TRK2 ; 0217 3E00 MVI A,00H 0219 325506 STA BREG ;ZERO OUT B REGISTER 021C 79 MOV A,C ;ACC = TRACK # 021D 325406 STA CREG ;SET UP PB 0220 3E0A MVI A,SETTRK ;SETTRK FUNC # 0222 325206 STA BIOSFC 0225 0E32 MVI C,DRBIOS 0227 115206 LXI D,BIOSPB 022A C30500 JMP BDOS TRK2: 022D 2A0100 LHLD WBOOT 0230 110A00 LXI D,SETTRK 0233 CDCF01 CALL MLTBY3 0236 19 DAD D 0237 E9 PCHL ;GONE TO SET TRACK ; CP/M MACRO ASSEM 2.0 #005 JSYS - UPDATED SYSGEN PROGRAM 7/22/83 SEC: ; SET UP SECTOR NUMBER 0238 32A306 STA TEMP 023B 3AA206 LDA V3FLG 023E FEFF CPI TRUE 0240 3AA306 LDA TEMP 0243 C25C02 JNZ SEC2 ; 0246 3E00 MVI A,00H 0248 325506 STA BREG ;ZERO OUT BREG 024B 79 MOV A,C ; ACC = C 024C 325406 STA CREG ;CREG = SECTOR # 024F 3E0B MVI A,SETSEC 0251 325206 STA BIOSFC ;SET UP BIOS CALL 0254 0E32 MVI C,DRBIOS 0256 115206 LXI D,BIOSPB 0259 C30500 JMP BDOS SEC2: 025C 2A0100 LHLD WBOOT 025F 110B00 LXI D,SETSEC 0262 CDCF01 CALL MLTBY3 0265 19 DAD D 0266 E9 PCHL ; DMA: ; SET DMA ADDRESS TO VALUE OF BC 0267 32A306 STA TEMP 026A 3AA206 LDA V3FLG 026D FEFF CPI TRUE 026F 3AA306 LDA TEMP 0272 C28A02 JNZ DMA2 ; 0275 78 MOV A,B ; 0276 325506 STA BREG ; 0279 79 MOV A,C ;SET UP THE BC 027A 325406 STA CREG ;REGISTER PAIR 027D 3E0C MVI A,SETDMA ; 027F 325206 STA BIOSFC ;SET UP BIOS # 0282 0E32 MVI C,DRBIOS 0284 115206 LXI D,BIOSPB 0287 C30500 JMP BDOS DMA2: 028A 2A0100 LHLD WBOOT 028D 110C00 LXI D,SETDMA 0290 CDCF01 CALL MLTBY3 0293 19 DAD D 0294 E9 PCHL DDMA: ;VER 3.0 REQUIRES FILE READ DMA TO BDOS ; ROUTINE ADDED 7/22/83 SK ; SET DMA ADDRESS TO VALUE OF BC 0295 3AA206 LDA V3FLG 0298 FEFF CPI TRUE 029A C28A02 JNZ DMA2 ; 029D 50 MOV D,B ;MOVE TO DE CP/M MACRO ASSEM 2.0 #006 JSYS - UPDATED SYSGEN PROGRAM 7/22/83 029E 59 MOV E,C 029F 0E1A MVI C,1AH ;BDOS SET DMA 02A1 C30500 JMP BDOS ; READ: ; PERFORM READ OPERATION 02A4 32A306 STA TEMP 02A7 3AA206 LDA V3FLG 02AA FEFF CPI TRUE 02AC 3AA306 LDA TEMP 02AF C2BF02 JNZ READ2 ; 02B2 3E0D MVI A,READF 02B4 325206 STA BIOSFC 02B7 0E32 MVI C,DRBIOS 02B9 115206 LXI D,BIOSPB 02BC C30500 JMP BDOS READ2: 02BF 2A0100 LHLD WBOOT 02C2 110D00 LXI D,READF 02C5 CDCF01 CALL MLTBY3 02C8 19 DAD D 02C9 E9 PCHL ; WRITE: ; PERFORM WRITE OPERATION 02CA 32A306 STA TEMP 02CD 3AA206 LDA V3FLG 02D0 FEFF CPI TRUE 02D2 3AA306 LDA TEMP 02D5 C2E502 JNZ WRITE2 ; 02D8 3E0E MVI A,WRITF 02DA 325206 STA BIOSFC ;SET UP BIOS # 02DD 0E32 MVI C,DRBIOS 02DF 115206 LXI D,BIOSPB 02E2 C30500 JMP BDOS ; WRITE2: 02E5 2A0100 LHLD WBOOT 02E8 110E00 LXI D,WRITF 02EB CDCF01 CALL MLTBY3 02EE 19 DAD D 02EF 3AAA06 LDA SECTOR 02F2 FE40 CPI 64 ;ON SECTOR 64 FORCE WRITE SK 7/4/83 02F4 C2F902 JNZ WRIT3 ;TO FLUSH DEBLOCK SECTOR SK 02F7 0E01 MVI C,1 ;WRITE TYPE DIRECTORY SK 02F9 E9 WRIT3: PCHL ; MULTSEC: ; MULTIPLY THE SECTOR # IN RA BY THE SECTOR SIZE 02FA 6F MOV L,A 02FB 2600 MVI H,0 ;SECTOR IN HL ; REPT LOG2SEC ; SK 7/4/83 ; DAD H ; ENDM CP/M MACRO ASSEM 2.0 #007 JSYS - UPDATED SYSGEN PROGRAM 7/22/83 02FD 29 DAD H ; SK 7/4/83 02FE 29 DAD H ; SK 7/4/83 02FF 29 DAD H ; SK 7/4/83 0300 29 DAD H ; SK 7/4/83 0301 29 DAD H ; SK 7/4/83 0302 29 DAD H ; SK 7/4/83 0303 29 DAD H ; SK 7/4/83 0304 3AA806 LDA TRACK ; SK 7/4/83 0307 A7 ANA A ;TEST FOR TRACK 0 OR 1 SK 7/4/83 0308 C8 RZ ;TRACK 0 ONLY 128 BYTES SK 7/4/83 0309 3AA206 LDA V3FLG ;FOR VER 3.0 SK 7/4/83 030C A7 ANA A ;V2.2 SECT SIZE IS 128 SK 7/4/83 030D C8 RZ ; SK 7/4/83 030E 29 DAD H ;TRACK 1 1024 SK 7/4/83 030F 29 DAD H ; SK 7/4/83 0310 29 DAD H 0311 C9 RET ;WITH HL - SECTOR*SECTORSIZE ; GETCHAR: ; READ CONSOLE CHARACTER TO RA 0312 0E01 MVI C,CONI 0314 CD0500 CALL BDOS ; CONVERT TO UPPER CASE 0317 FE61 CPI 'A' OR 20H 0319 D8 RC 031A FE7B CPI ('Z' OR 20H)+1 031C D0 RNC 031D E65F ANI 05FH 031F C9 RET ; PUTCHAR: ; WRITE CHARACTER FROM RA TO CONSOLE 0320 5F MOV E,A 0321 0E02 MVI C,CONO 0323 CD0500 CALL BDOS 0326 C9 RET ; CRLF: ; SEND CARRIAGE RETURN, LINE FEED 0327 3E0D MVI A,CR 0329 CD2003 CALL PUTCHAR 032C 3E0A MVI A,LF 032E CD2003 CALL PUTCHAR 0331 C9 RET ; CRMSG: ; PRINT MESSAGE ADDRESSED BY THE HL UNTIL ZERO WITH LEADING CRLF 0332 D5 PUSH D 0333 CD2703 CALL CRLF 0336 D1 POP D ;DROP THROUGH TO OUTMSG OUTMSG: 0337 0E09 MVI C,9 0339 C30500 JMP BDOS ; SELCT: CP/M MACRO ASSEM 2.0 #008 JSYS - UPDATED SYSGEN PROGRAM 7/22/83 ; SELECT DISK GIVEN BY RA 033C 0E0E MVI C,0EH 033E C30500 JMP BDOS ; DWRITE: ; WRITE FOR FILE COPY 0341 0E15 MVI C,DWRITF 0343 C30500 JMP BDOS ; DREAD: ; DISK READ FUNCTION 0346 0E14 MVI C,DREADF 0348 C30500 JMP BDOS ; OPEN: ; FILE OPEN FUNCTION 034B 0E0F MVI C,OPENF 034D C30500 JMP BDOS ; CLOSE: 0350 0E10 MVI C,CLOSEF 0352 C30500 JMP BDOS ; MAKE: 0355 0E16 MVI C,MAKEF 0357 C30500 JMP BDOS ; DELETE: 035A 0E13 MVI C,DELTEF 035C C30500 JMP BDOS ; ; ; DSTDMA: 035F 0E1A MVI C,26 0361 C30500 JMP BDOS ; SOURCE: 0364 11CC06 LXI D,GETPRM ;ASK USER FOR SOURCE DRIVE 0367 CD3203 CALL CRMSG 036A CD1203 CALL GETCHAR ;OBTAIN RESPONSE 036D FE0D CPI CR ;IS IT CR? 036F CA9203 JZ DFLTDR ;SKIP IF CR ONLY 0372 FE03 CPI CTLC ;ISIT ^C? 0374 CA4006 JZ REBOOT ; 0377 D641 SUI 'A' ;NORMALIZE DRIVE # 0379 FE04 CPI NDISKS ;VALID DRIVE? 037B DA8403 JC GETC ;SKIP TO GETC IF SO ; ; INVALID DRIVE 037E CD4B06 CALL BADDISK ;TELL USER BAD DRIVE 0381 C36403 JMP SOURCE ;TRY AGAIN ; GETC: ; SELECT DISK GIVEN BY ACC. CP/M MACRO ASSEM 2.0 #009 JSYS - UPDATED SYSGEN PROGRAM 7/22/83 0384 C641 ADI 'A' 0386 320107 STA GDISK ;STORE SOURCE DISK 0389 D641 SUI 'A' 038B 5F MOV E,A ;MOVE DISK INTO E FOR SELECT FUNC 038C CDD701 CALL SEL ;SELECT THE DISK 038F C3A803 JMP GETVER ; DFLTDR: 0392 0E19 MVI C,25 ;FUNC 25 FOR CURRENT DISK 0394 CD0500 CALL BDOS ;GET CURDSK 0397 C641 ADI 'A' 0399 320107 STA GDISK 039C CD2703 CALL CRLF 039F 11F706 LXI D,VERGET 03A2 CD3703 CALL OUTMSG 03A5 C3B103 JMP VERCR ; GETVER: ; GETSYS SET R/W TO READ AND GET THE SYSTEM 03A8 CD2703 CALL CRLF 03AB 11F706 LXI D,VERGET ;VERIFY SOURCE DISK 03AE CD3703 CALL OUTMSG 03B1 CD1203 VERCR: CALL GETCHAR 03B4 FE0D CPI CR 03B6 C24006 JNZ REBOOT ;JMP ONLY IF NOT VERIFIED 03B9 CD2703 CALL CRLF 03BC C9 RET ; DESTIN: 03BD 111507 LXI D,PUTPRM ;ADDRESS OF MESSAGE 03C0 CD3203 CALL CRMSG ;PRINT IT 03C3 CD1203 CALL GETCHAR ;GET ANSWER 03C6 FE0D CPI CR 03C8 CA4006 JZ REBOOT ;ALL DONE 03CB D641 SUI 'A' 03CD FE04 CPI NDISKS ;VALID DISK 03CF DAD803 JC PUTC ; ; INVALID DRIVE 03D2 CD4B06 CALL BADDISK ;TELL USER BAD DRIVE 03D5 C32E05 JMP PUTSYS ;TO TRY AGAIN ; PUTC: ; SET DISK FRON RA 03D8 C641 ADI 'A' 03DA 325207 STA PDISK ;MESSAGE SENT 03DD D641 SUI 'A' 03DF 5F MOV E,A ;DISK # IN E 03E0 CDD701 CALL SEL ;SELECT DESTINATION DRIVE ; PUT SYSTEM, SET R/W TO WRITE 03E3 114307 LXI D,VERPUT ;VERIFY DEST PRMPT 03E6 CD3203 CALL CRMSG ;PRINT IT OUT 03E9 CD1203 CALL GETCHAR ;RETRIEVE ANSWER 03EC FE0D CPI CR 03EE C24006 JNZ REBOOT ;EXIT TO SYSTEM IF ERROR 03F1 CD2703 CALL CRLF CP/M MACRO ASSEM 2.0 #010 JSYS - UPDATED SYSGEN PROGRAM 7/22/83 03F4 C9 RET ; ; GETPUT: ; GET OR PUT CP/M (RW = 0 FOR READ, 1 FOR WRITE) ; DISK IS ALREADY SELECTED 03F5 210010 LXI H,LOADP ;LOAD POINT IN RAM FOR DMA ADDRESS 03F8 22AC06 SHLD DMADDR ; ; ; ; ; CLEAR TRACK 00 03FB 3EFF MVI A,-1 ; 03FD 32A806 STA TRACK ; RWTRK: ; READ OR WRITE NEXT TRACK 0400 21A806 LXI H,TRACK 0403 34 INR M ;TRACK = TRACK+1 0404 3A8D01 LDA OST ;# OF OS TRACKS 0407 BE CMP M ;=TRACK # ? 0408 CABD04 JZ ENDRW ;END OF READ/WRITE ; ; OTHERWISE NOT DONE 040B 4E MOV C,M ;TRACK NUMBER 040C CD0902 CALL TRK ;SET TO TRACK 040F 3E00 MVI A,0 ;COUNTS 0,1,2,...,25 0411 32AA06 STA SECTOR ; RWSEC: ; READ OR WRITE A SECTOR 0414 3A8E01 LDA SPT ;SECTORS PER TRACK 0417 21AA06 LXI H,SECTOR 041A 34 INR M ;SET TO NEXT SECTOR 041B BE CMP M ;A=26 AND M=0,1,..,25 041C CA9E04 JZ ENDTRK ; ; READ OR WRITE SECTOR TO OR FROM CURRENT DMA ADDRESS 041F 21AA06 LXI H,SECTOR 0422 0601 MVI B,1 ;IF NOTRANS B MUST = 0 FORD DMA ADDR SK 0424 3AA806 LDA TRACK ;SEE IF TRACK 1 SK 07/04/83 0427 FE01 CPI 1 ;NO TRANSLATE ON 1 SK 0429 CA3404 JZ NOTRANS ; SK 042C 5E MOV E,M ;SECTOR NUMBER 042D 1600 MVI D,0 ;TO DE 042F 218F01 LXI H,TRAN 0432 46 MOV B,M ;TRAN(0) IN B 0433 19 DAD D ;SECTOR TRANSLATED 0434 4E NOTRANS MOV C,M ;VALUE TO C READY FOR SELECT 0435 C5 PUSH B ;SAVE TRAN(0) 0436 CD3802 CALL SEC 0439 C1 POP B ;RECALL TRAN(0),TRAN(SECTOR) 043A 79 MOV A,C ;TRAN(SECTOR) 043B 90 SUB B ;--TRAN(SECTOR) CP/M MACRO ASSEM 2.0 #011 JSYS - UPDATED SYSGEN PROGRAM 7/22/83 043C CDFA02 CALL MULTSEC ;*SECTOR SIZE 043F EB XCHG ;TO DE 0440 2AAC06 LHLD DMADDR ;BASE DMA 0443 19 DAD D 0444 44 MOV B,H 0445 4D MOV C,L ;TO SET BC FOR SEC CALL 0446 CD6702 CALL DMA ;DMA ADDRESS SET FROM BC 0449 AF XRA A 044A 32AE06 STA RETRY ;TO SET ZERO RETRIES ; TRYSEC: ; TRY TO READ OR WRITE CURRENT SECTOR 044D 3AAE06 LDA RETRY 0450 FE01 CPI MAXTRY 0452 DA6904 JC TRYOK ; ; PAST MAXTRY, MESSAGE AND IGNORE 0455 113108 LXI D,ERRMSG 0458 CD3703 CALL OUTMSG 045B CD1203 CALL GETCHAR 045E FE0D CPI CR 0460 C24006 JNZ REBOOT ; ; TYPED A CR, OK TO IGNORE 0463 CD2703 CALL CRLF 0466 C31404 JMP RWSEC ; TRYOK: ; OK TO TYR READ WRITE 0469 3C INR A 046A 32AE06 STA RETRY 046D 3AAB06 LDA RW 0470 B7 ORA A 0471 CA9404 JZ TRYREAD ; ; MUST BE WRITE 0474 CDCA02 CALL WRITE 0477 A7 ANA A ;SEE IF ERROR SK 0478 C29704 JNZ CHKRW ;YES JUMP SK ;TEST FOR LAST SECTOR SK 8/1/83 047B 3AA806 LDA TRACK ; SK 047E B7 ORA A ;OF LAST TRACK SK 047F CA9704 JZ CHKRW ; SK 0482 3AAA06 LDA SECTOR ;AND FLUSH SK 0485 FE09 CPI NSTS30 ; SK 0487 3E00 MVI A,0 ;SHOW NO ERROR SK 0489 C29704 JNZ CHKRW ; SK 048C 0E30 MVI C,FLUSH ; SK 048E CD0500 CALL BDOS ; SK 0491 C39704 JMP CHKRW ; TRYREAD: 0494 CDA402 CALL READ CHKRW: 0497 B7 ORA A 0498 CA1404 JZ RWSEC ;ZERO FLAG IF READ/WRITE OK CP/M MACRO ASSEM 2.0 #012 JSYS - UPDATED SYSGEN PROGRAM 7/22/83 ; ;ERROR, RETRY OPERATION 049B C34D04 JMP TRYSEC ; ; END OF TRACK ENDTRK: 049E 3A8E01 LDA SPT ;SECTORS PER TRACK 04A1 CDFA02 CALL MULTSEC ;*SECSIZE 04A4 EB XCHG ; TO DE 04A5 2AAC06 LHLD DMADDR ;BASE DMA FOR THIS TRACK 04A8 19 DAD D ;+SPT*SECSIZE 04A9 22AC06 SHLD DMADDR ;READY FOR NEXT TRACK 04AC 3AA206 LDA V3FLG ;GET VERSION 3 FLAG SK 07/22/83 04AF B7 ORA A ;TEST FOR FALSE = 0 SK 04B0 3E09 MVI A,NSTS30 ;GET VERIONS 3 SECTS PER TRK SK 04B2 C2B704 JNZ ENDT1 ;AND JUMP IF 3.0 SK 04B5 3E41 MVI A,NSECTS1 ;SET UP FOR TRACK 1 SK 07/04/83 04B7 328E01 ENDT1: STA SPT ; SK 04BA C30004 JMP RWTRK ;FOR ANOTHER TRACK ; ENDRW: ; END OF READ OR WRITE 04BD 3E1A MVI A,NSECTS ;RESTORE SPT FOR NEXT TRACK 0 SK 04BF 328E01 STA SPT ; SK 04C2 C9 RET ; ;******************* ;* ;* MAIN ROUTINE ;* ;* ;******************* ; START: 04C3 31D508 LXI SP,STACK 04C6 11AF06 LXI D,SIGNON 04C9 CD3703 CALL OUTMSG ; ;GET VERSION NUMBER TO CHECK COMPATABILITY 04CC 0E0C MVI C,12 ;VERSION CHECK 04CE CD0500 CALL BDOS 04D1 7D MOV A,L ;VERSION IN ACC 04D2 FE30 CPI 30H ;VERSION 3 OR NEWER? 04D4 DADF04 JC OLDRVR ; 04D7 3EFF MVI A,TRUE 04D9 32A206 STA V3FLG ; 04DC C3E404 JMP FCBCHK OLDRVR: 04DF 3E00 MVI A,FALSE 04E1 32A206 STA V3FLG ; ; CHECK FOR DEFAULT FILE LIAD INSTEAD OF GET 04E4 3A5D00 FCBCHK: LDA FCB+1 ;BLANK IF NO FILE 04E7 FE20 CPI ' ' CP/M MACRO ASSEM 2.0 #013 JSYS - UPDATED SYSGEN PROGRAM 7/22/83 04E9 CA1E05 JZ GETSYS ;SKIP TO SYSTEM MESSAGE 04EC 115C00 LXI D,FCB ;TRY TO OPEN IT 04EF CD4B03 CALL OPEN 04F2 3C INR A ;255 BECOMES 00 04F3 C2FF04 JNZ RDOK ; ; FILE NOT PRESENT 04F6 11C507 LXI D,NOFILE 04F9 CD3203 CALL CRMSG 04FC C34006 JMP REBOOT ; ;FILE PRESENT RDOK: 04FF AF XRA A 0500 327C00 STA FCBCR ;CURRENT RECORD = 0 0503 210010 LXI H,LOADP RDINP: 0506 E5 PUSH H 0507 44 MOV B,H 0508 4D MOV C,L 0509 CD9502 CALL DDMA ;DMA ADDRESS SET SK 050C 115C00 LXI D,FCB ;READY FR READ 050F CD4603 CALL DREAD 0512 E1 POP H ;RECALL 0513 B7 ORA A ;00 IF READ OK 0514 C22E05 JNZ PUTSYS ;ASSUME EOF IF NOT ; MORE TO READ CONTINUE 0517 118000 LXI D,SECSIZ 051A 19 DAD D ;HL IS NEW LOAD ADDRESS 051B C30605 JMP RDINP ; GETSYS: 051E CD6403 CALL SOURCE ;FIND OUT SOURCE DRIVE ; 0521 AF XRA A ;ZERO OUT A 0522 32AB06 STA RW ;RW = 0 TO SIGNIFY READ 0525 CDF503 CALL GETPUT ;GET OR READ SYSTEM 0528 118507 LXI D,DONE ;END MESSAGE OF GET OR READ FUNC 052B CD3703 CALL OUTMSG ;PRINT IT OUT ; ; PUT THE SYSTEM PUTSYS: 052E CDBD03 CALL DESTIN ;GET DEST DRIVE ; 0531 21AB06 LXI H,RW ;LOAD ADDRESS 0534 3601 MVI M,1 0536 CDF503 CALL GETPUT ;TO PUT SYSTEM BACK ON DISK 0539 118507 LXI D,DONE 053C CD3703 CALL OUTMSG ;PRINT OUT END PROMPT ; ; FILE COPY FOR CPM.SYS ; CPYCPM: ; PROMPT THE USER FOR THE SOURCE OF CP/M3.SYS ; 053F 116607 LXI D,CPYMSG ;PRINT COPYS PROMPT CP/M MACRO ASSEM 2.0 #014 JSYS - UPDATED SYSGEN PROGRAM 7/22/83 0542 CD3203 CALL CRMSG ;PRINT IT 0545 CD1203 CALL GETCHAR ;OBTAIN REPLY 0548 FE59 CPI Y ;IS IT YES? 054A C24006 JNZ REBOOT ;IF NOT EXIT ;ELSE ; ; 054D 0E0D MVI C,13 ;FUNC # FOR RESET 054F CD0500 CALL BDOS ; 0552 3C INR A 0553 113108 LXI D,ERRMSG 0556 CC3D06 CZ FINIS ; 0559 CD6403 CALL SOURCE ;GET SOURCE DISK FOR CPM3.SYS CNTNUE: 055C 3A0107 LDA GDISK ;ACC = SOURCE DISK 055F D641 SUI 'A' 0561 1600 MVI D,00H 0563 5F MOV E,A ;DE = SELECTED DISK 0564 CD3C03 CALL SELCT ; NOW COPY THE FCBS 0567 0E24 MVI C,36 ;FOR COPY 0569 115A06 LXI D,SFCB ;SOURCE FILE 056C 217E06 LXI H,DFCB ;DESTINATION FILE MFCB: 056F 1A LDAX D 0570 13 INX D ;READY NEXT 0571 77 MOV M,A 0572 23 INX H ;READY NEXT DEST 0573 0D DCR C ;DECREMENT COUN 0574 C26F05 JNZ MFCB ; 0577 3A0107 LDA GDISK ;ACC = SOURCE DISK 057A D640 SUI 40H ;CORRECT DISK 057C 215A06 LXI H,SFCB 057F 77 MOV M,A ;SFCB HAS SOURCE DISK # 0580 3A5207 LDA PDISK ;GET THE DEST. DISK 0583 217E06 LXI H,DFCB ; 0586 D640 SUI 040H ;NORMALIZE DISK 0588 77 MOV M,A ; 0589 AF XRA A ;ZERO OUT A 058A 329E06 STA DFCBCR ;CURRENT REC = 0 ; ; SOURCE AND DESTINATION FCB'S READY ; 058D 115A06 LXI D,SFCB ; 0590 CD4B03 CALL OPEN ;OPEN THE FILE 0593 11C507 LXI D,NOFILE ;ERROR MESSG 0596 3C INR A ;255 BECOMES 0 0597 CC3D06 CZ FINIS ;DONE IF NO FILE ; ; SOURCE FILE IS PRESENT AND OPEN 059A 110010 LXI D,LOADP ;GET DMA ADDRESS CP/M MACRO ASSEM 2.0 #015 JSYS - UPDATED SYSGEN PROGRAM 7/22/83 059D EB XCHG ;MOVE ADDRESS TO HL REGS 059E 22A506 SHLD BEGIN ;SAVE FOR BEGIN OF WRITE ; 05A1 3AA506 LDA BEGIN ;GET LOW BYTE OF 05A4 6F MOV L,A ;DMA ADDRESS INTO L 05A5 3AA606 LDA BEGIN+1 ; 05A8 67 MOV H,A ;INTO H ALSO COPY1: 05A9 EB XCHG ;DE = ADDRESS OF DMA 05AA CD5F03 CALL DSTDMA ; ; 05AD 115A06 LXI D,SFCB ; 05B0 CD4603 CALL DREAD ;READ NEXT RECORD 05B3 B7 ORA A ;END OF FILE? 05B4 C2D005 JNZ EOF ;SKIP WRITE IF SO ; 05B7 3AA906 LDA CRNREC 05BA 3C INR A ;BUMP IT 05BB 32A906 STA CRNREC ; 05BE 3AA506 LDA BEGIN 05C1 6F MOV L,A 05C2 3AA606 LDA BEGIN+1 05C5 67 MOV H,A 05C6 118000 LXI D,EIGHTY 05C9 19 DAD D ;ADD EIGHTY TO BEGIN ADDRESS 05CA 22A506 SHLD BEGIN 05CD C3A905 JMP COPY1 ;LOOP UNTIL EOF ; EOF: 05D0 118507 LXI D,DONE 05D3 CD3703 CALL OUTMSG ; COPY2: 05D6 CDBD03 CALL DESTIN ;GET DESTINATION DRIVE FOR CPM3.SYS 05D9 117E06 LXI D,DFCB ;SET UP DEST FCB 05DC EB XCHG 05DD 3A5207 LDA PDISK 05E0 D640 SUI 040H ;NORMALIZE DISK 05E2 77 MOV M,A ;CORRECT DISK FOR DEST 05E3 EB XCHG ;DE = DFCB 05E4 CD5A03 CALL DELETE ;DELETE FILE IF THERE ; 05E7 117E06 LXI D,DFCB ; 05EA CD5503 CALL MAKE ;MAKE A NEW ONE 05ED 11E407 LXI D,NODIR 05F0 3C INR A ;CHECK DIRECTORY SPACE 05F1 CC3D06 CZ FINIS ;END IF NONE ; 05F4 110010 LXI D,LOADP 05F7 EB XCHG 05F8 22A506 SHLD BEGIN ; 05FB 3AA506 LDA BEGIN 05FE 6F MOV L,A 05FF 3AA606 LDA BEGIN+1 CP/M MACRO ASSEM 2.0 #016 JSYS - UPDATED SYSGEN PROGRAM 7/22/83 0602 67 MOV H,A LOOP2: 0603 EB XCHG 0604 CD5F03 CALL DSTDMA 0607 117E06 LXI D,DFCB 060A CD4103 CALL DWRITE 060D 11FF07 LXI D,FSPACE 0610 B7 ORA A 0611 C43D06 CNZ FINIS 0614 3AA906 LDA CRNREC 0617 3D DCR A 0618 32A906 STA CRNREC 061B FE00 CPI 0 061D CA3206 JZ FNLMSG 0620 3AA506 LDA BEGIN 0623 6F MOV L,A 0624 3AA606 LDA BEGIN+1 0627 67 MOV H,A 0628 118000 LXI D,EIGHTY 062B 19 DAD D 062C 22A506 SHLD BEGIN 062F C30306 JMP LOOP2 ; COPY OPERATION COMPLETE FNLMSG: 0632 117E06 LXI D,DFCB 0635 0E10 MVI C,CLOSEF 0637 CD0500 CALL BDOS ; 063A 118507 LXI D,DONE ; FINIS: ; WRITE MESSAGE GIVEN BY DE, REBOOT 063D CD3703 CALL OUTMSG ; REBOOT: 0640 0E0D MVI C,13 0642 CD0500 CALL BDOS 0645 CD2703 CALL CRLF 0648 C30000 JMP BOOT ; BADDISK: 064B 119707 LXI D,QDISK 064E CD3203 CALL CRMSG 0651 C9 RET ;**************************** ;* ;* ;* DATA STRUCTURES ;* ;* ;**************************** ; BIOSPB: ; BIOS PARAMETER BLOCK 0652 00 BIOSFC: DB 0 ;BIOS FUNCTION NUMBER 0653 00 AREG: DB 0 ;A REGISTER CONTENTS CP/M MACRO ASSEM 2.0 #017 JSYS - UPDATED SYSGEN PROGRAM 7/22/83 0654 00 CREG: DB 0 ;C REGISTER CONTENTS 0655 00 BREG: DB 0 ;B REGISTER CONTENTS 0656 00 EREG: DB 0 ;E REGISTER CONTENTS 0657 00 DREG: DB 0 ;D REGISTER CONTENTS 0658 0000 HLREG: DW 0 ;HL REGISTER CONTENTS ; SFCB: 065A DR: DS 1 065B 43504D3320F1F8: DB 'CPM3 ' 0663 535953 T1T3: DB 'SYS' 0666 00 EXT: DB 0 0667 00 CS: DB 0 0668 00 RS: DB 0 0669 00 RCC: DB 0 066A D0D15: DS 16 067A 00 CCR: DB 0 067B R0R2: DS 3 ; 067E DFCB: DS 36 069E = DFCBCR EQU DFCB+32 ; ; 06A2 00 V3FLG: DB 0 ;FLAG FOR VERSION # 06A3 00 TEMP: DB 0 06A4 SDISK: DS 1 ;SELECTED DISK 06A5 0000 BEGIN: DW 0 06A7 00 DFLAG: DB 0 06A8 TRACK: DS 1 ;CURRENT TRACK 06A9 00 CRNREC: DB 0 ;CURRENT REC COUNT 06AA SECTOR: DS 1 ;CURRENT SECTOR 06AB RW: DS 1 ;READ IF 0 WRITE IF 1 06AC DMADDR: DS 2 ;CURRENT DMA ADDRESS 06AE RETRY: DS 1 ;NUMBER OF TRIES ON THIS SECTOR 06AF 43502F4D20SIGNON: DB 'CP/M 3 COPYSYS - VERSION ' 06C8 332E30 DB VERS/10+'0','.',VERS MOD 10 +'0' 06CB 24 DB '$' 06CC 534F555243GETPRM: DB 'SOURCE DRIVE NAME (OR RETURN FOR DEFAULT) $' 06F7 534F555243VERGET: DB 'SOURCE ON ' 0701 GDISK: DS 1 0702 205448454E DB ' THEN TYPE RETURN $' 0715 4445535449PUTPRM: DB 'DESTINATION DRIVE NAME (OR RETURN TO REBOOT) $' 0743 4445535449VERPUT: DB 'DESTINATION ON ' 0752 PDISK: DS 1 0753 205448454E DB ' THEN TYPE RETURN $' 0766 444F20594FCPYMSG: DB 'DO YOU WISH TO COPY CPM3.SYS? $' 0785 46554E4354DONE: DB 'FUNCTION COMPLETE$' ; ; ERROR MESSAGES...... ; 0797 4552524F52QDISK: DB 'ERROR: INVALID DRIVE NAME (USE A, B, C, OR D)$' 07C5 4552524F52NOFILE: DB 'ERROR: NO SOURCE FILE ON DISK.$' 07E4 4552524F52NODIR: DB 'ERROR: NO DIRECTORY SPACE.$' 07FF 4552524F52FSPACE: DB 'ERROR: OUT OF DATA SPACE.$' 0819 4552524F52WRPROT: DB 'ERROR: WRITE PROTECTED?$' 0831 4552524F52ERRMSG: DB 'ERROR: POSSIBLE INCOMPATIBLE DISK FORMAT.' 085A 0D0A205459 DB CR,LF,' TYPE RETURN TO IGNORE.$' CP/M MACRO ASSEM 2.0 #018 JSYS - UPDATED SYSGEN PROGRAM 7/22/83 0874 4552524F52CLSERR: DB 'ERROR: CLOSE OPERATION FAILED.$' ; 0893 DS STACKSIZE * 3 STACK: 08D5 END 0653 AREG 064B BADDISK 0005 BDOS 06A5 BEGIN 0652 BIOSFC 0652 BIOSPB 0000 BOOT 0655 BREG 067A CCR 0497 CHKRW 0350 CLOSE 0010 CLOSEF 0874 CLSERR 055C CNTNUE 0001 CONI 0002 CONO 05A9 COPY1 05D6 COPY2 053F CPYCPM 0766 CPYMSG 000D CR 0654 CREG 0327 CRLF 0332 CRMSG 06A9 CRNREC 0667 CS 0003 CTLC 066A D0D15 0295 DDMA 035A DELETE 0013 DELTEF 03BD DESTIN 067E DFCB 069E DFCBCR 06A7 DFLAG 0392 DFLTDR 0267 DMA 028A DMA2 06AC DMADDR 0785 DONE 0032 DRBIOS 0346 DREAD 0014 DREADF 0657 DREG 065A DR 035F DSTDMA 0341 DWRITE 0015 DWRITF 0080 EIGHTY 04BD ENDRW 04B7 ENDT1 049E ENDTRK 05D0 EOF 0656 EREG 0831 ERRMSG 0666 EXT 065B F1F8 0000 FALSE 005C FCB 04E4 FCBCHK 007C FCBCR 063D FINIS 0030 FLUSH 0632 FNLMSG 07FF FSPACE 0701 GDISK 0312 GETCHAR 0384 GETC 06CC GETPRM 03F5 GETPUT 051E GETSYS 03A8 GETVER 0658 HLREG 000A LF 1000 LOADP 0007 LOG2SEC 0603 LOOP2 0355 MAKE 0016 MAKEF 0001 MAXTRY 056F MFCB 01CF MLTBY3 02FA MULTSEC 0004 NDISKS 07E4 NODIR 07C5 NOFILE 0434 NOTRANS 001A NSECTS 0041 NSECTS1 0009 NSTS30 0002 NTRKS 04DF OLDRVR 034B OPEN 000F OPENF 018D OST 0337 OUTMSG 0752 PDISK 0320 PUTCHAR 03D8 PUTC 0715 PUTPRM 052E PUTSYS 0797 QDISK 067B R0R2 0669 RCC 0506 RDINP 04FF RDOK 02BF READ2 000D READF 02A4 READ 0640 REBOOT 06AE RETRY 0668 RS 06AB RW 0414 RWSEC 0400 RWTRK 06A4 SDISK 0238 SEC 025C SEC2 0080 SECSIZ 06AA SECTOR 01D7 SEL 01FB SEL2 033C SELCT 000E SELD 0009 SELDSK 000C SETDMA 000B SETSEC 000A SETTRK 065A SFCB 06AF SIGNON 0004 SKEW 0364 SOURCE 018E SPT 08D5 STACK 0016 STACKSIZE 04C3 START 0663 T1T3 06A3 TEMP 0100 TPA 06A8 TRACK 018F TRAN 0209 TRK 022D TRK2 FFFF TRUE 0469 TRYOK 0494 TRYREAD 044D TRYSEC 06A2 V3FLG 03B1 VERCR 06F7 VERGET 0743 VERPUT 001E VERS 0001 WBOOT 02F9 WRIT3 02CA WRITE 02E5 WRITE2 000E WRITF 0819 WRPROT 0059 Y ;LAST EDITED 07/06/83 12:20:40 ;ADDED DOUBLE DENSITY SUPPORT ;LAST EDITED 07/02/83 16:09:42 ;LDRBIOS BIOS FOR CPM3 CPMLDR ; MACLIB CPM3 ; DISK READ AND WRITE ENTRY POINTS. D$PORT EQU 043H ;DOUBLE D PORT ADDRESS D$ADDR: EQU 0FC00H ;ADDRESS OF DD BUFFER ; DOUBLE D HARDWARE COMMANDS DC$MB0 EQU 01H ;SELECT DOUBLE D BANK 0 DC$MB1 EQU 03H ;SELECT DOUBLE D BANK 1 DC$SOT EQU 0 ;SWITCH DD MEM OUT OF SYSTEM DC$INT EQU 02H ;ISSUE DD Z80A INTERRUPT ; DISK CONTROLLER MODULE LINKAGE (DCM - VER 2.2) ;( DCM ADDRESSES DEFINED ) DD$CBT EQU 0370H+D$ADDR ;COMMAND BLOCK (BANK 0) DD$SBUF EQU 0380H+D$ADDR ;SD SECTOR BUFFER (BANK 0) DD$DBUF EQU 0+D$ADDR ;DD SECTOR BUFFER (BANK 1) DD$DPB EQU 03A0H+D$ADDR ;ID SEC DPB (BANK 0) DD$DDF EQU 03B1H+D$ADDR ;ID SEC FLAGS (BANK 0) ;( DCM COMMANDS ) DC$LOG EQU 000H ;LOG ON DISKETTE DC$RDS EQU 001H ;READ SECTOR DC$WRS EQU 002H ;WRITE SECTOR ; DPB$SZ EQU 15 ;BYTES TO DISK PAR HEADER ROM EQU 0F000H ; MONIT EQU ROM BLOCK: EQU ROM+36 ;BLOCK MOVE ROUTINE(LDIR) ; cr equ 13 lf equ 10 ?boot: jmp INIT ; initial entry on cold start ?wboot: jmp STOP ; reentry on program exit, warm start ?const: jmp STOP ; return console input status ?conin: jmp ROM+0CH ; return console input character ?cono: jmp ROM+0FH ; send console output character ?list: jmp STOP ; send list output character ?auxo: jmp STOP ; send auxilliary output character ?auxi: jmp STOP ; return auxilliary input character ?home: jmp HOME ; set disks to logical home ?sldsk: jmp seldsk ; select disk drive, return disk parameter info ?sttrk: jmp settrk ; set disk track ?stsec: jmp setsec ; set disk sector ?stdma: jmp setdma ; set disk I/O memory address ?read: jmp read ; read physical block(s) ?write: jmp STOP ; write physical block(s) ?lists: jmp STOP ; return list device status ?sctrn: jmp sectrn ; translate logical to physical sector ?conos: jmp STOP ; return console output status ?auxis: jmp STOP ; return aux input status ?auxos: jmp STOP ; return aux output status ?dvtbl: jmp STOP ; return address of device def table ?devin: jmp STOP ; change baud rate of device ?drtbl: jmp STOP ; return address of disk drive table ?mltio: jmp STOP ; set multiple record count for disk I/O ?flush: jmp STOP ; flush BIOS maintained disk caching ?mov: jmp MOVE ; block move memory to memory ?tim: jmp STOP ; Signal Time and Date operation ?bnksl: jmp STOP ; select bank for code execution and default DMA ?stbnk: jmp STOP ; select different bank for disk I/O DMA operations. ?xmov: JMP STOP ; set source and destination banks for one operation STOP: RST 7 ;NOT IMPLEMENTED ; pmsg: ; print message @ up to a null ; saves & push b push d pmsg$loop: mov a,m ora a jz pmsg$exit mov c,a push h call ?cono pop h inx h jmp pmsg$loop pmsg$exit: pop d pop b ret ; SELDSK SELDSK: XRA A ;SET FOR DRIVE ZERO STA @RDRV LOGIN: LXI D,LOG$MSG SHLD OPERATION$NAME LXI H,FDSD0 ;POINT TO DRV 0 LGIN1: SHLD DT$PTR ;SAVE FOR LATER CALL BNK0 ;SWITCH TO BANK 0 CALL PMOVE ;SET UP COMMAND BLOCK MVI A,DC$LOG ;LOAD DCM LOG-ON CMND CALL DSK$EX ;PERFORM DISK OP JZ LOG$CK ;GO TO LOGON DISKETTE LXI H,0 ;ERROR, BAD LOG ON JMP DSK$ER ;BIOS EXIT SETDD: LXI H,1024 ;MUST BE DOUBLE SHLD SEC$SZ LXI H,DD$DBUF ;1K SECTOR BUFFER ADDR SHLD DD$BUF JMP BNK1 ; ; ;( CHECK FOR JADE ID )* LOG$CK: LHLD DD$BUF ;DD BUFFER LXI D,JADEID ;DE PNTS BIOS ID MVI B,ID$SZE ;SET LABEL SIZE LOG$ID: LDAX D! INX D ;GET LABEL CHARACTER CMP M! INX H ;DOES ID SECTOR MATCH JNZ TR3740 ;ASSUME DISKETTE 3740 DCR B ;DECREMENT COUNT JNZ LOG$ID ;CHECK IF ANOTHER CHR ;( DISKETTE CONTAINS ID ) ;( SET NO SECTOR TRANSLATION ) TRNONE: LXI D,TRANS1 LHLD DT$PTR ;ADDR OF PARA HDER MOV M,E ;SET LOW ORDER ADDR INX H ;NEXT BYTE MOV M,D ;SET HIGH BYTE ; ;GET PARAMETER BLOCK FROM DD BUFFER AND MOVE TO HOST MEMORY ; CALL DPB$AD ;GET DPB ADDR IN DE LXI H,DD$DPB ;DPB ADDR LXI B,DPB$SZ ;DPB SIZE IN BYTES CALL BLOCK ;MOVE INTO DPB LXI H,DD$DPB ;ID DTA DNS MOV A,M ;LOAD SEC/TRK CPI 26 ;TEST FOR SD CZ TR3740 ;IF 0 USE 3740 TRN LHLD DT$PTR ;GET POINTER RET ;EXIT BIOS ; ;( SET 3740 SECTOR TRANSLATION )* ; TR3740: LXI D,TRANS ;SECTOR TRAN TBL ADDR LHLD DT$PTR ;ADDR DISK PARA HDER MOV M,E ;SET UP TRANSLATE VECTOR INX H MOV M,D LXI D,11 ;OFFSET TO DPB ADDR DAD D ;POINT TO DPB LXI D,DPBSD0 MOV M,E ;SET DPB TO SINGL DENS INX H MOV M,D XRA A ;A = 0 STA DNS ;SAV IT RET ;EXIT BIOS ;( GET DRIVE PARA BLK ADDR ) DPB$AD: LHLD DT$PTR ;ADDR DISK PARA HDER LXI D,12 ;DPB TBL PNTR OFFSET DAD D ;NOW AT DPB PNTR MOV E,M ;LOW ORDER ADDR INX H ;NEXT BYTE MOV D,M ;HIGH ORDER ADDR RET ;RETURN TO LOG USER ; ; MOVE: XCHG DB 0EDH,0B0H XCHG RET ; ; HOME: LXI B,0 ;SET TRACK TO 0 ; SETTRK ; Set Track. Saves track address from ; in @TRK for further operations. settrk: mov l,c mov h,b shld @trk ret ; SETSEC ; Set Sector. Saves sector number from ; in @sect for further operations. setsec: mov l,c mov h,b shld @sect ret ; SETDMA ; Set Disk Memory Address. Saves DMA address ; from in @DMA and sets @DBNK to @CBNK ; so that further disk operations take place ; in current bank. setdma: mov l,c mov h,b shld @dma ; SECTRN ; Sector Translate. Indexes skew table in ; with sector in . Returns physical sector ; in . If no skew table (=0) then ; returns physical=logical. sectrn: mov l,c mov h,b mov a,d ora e rz xchg dad b mov l,m mvi h,0 ret ; DISK I/O ROUTINES FOR STANDARDIZED BIOS INTERFACE ; INITIALIZATION ENTRY POINT. ; CALLED FOR FIRST TIME INITIALIZATION. INIT: XRA A ;SET FOR DRIVE ZERO STA @RDRV RET ; ; ; READ A DISK SECTOR ROUTINE ; READ: LXI H,READ$MSG SHLD OPERATION$NAME CALL BNK0 ;SWITCH TO BANK 0 CALL PMOVE ;SET UP COMMAND BLOCK MVI A,DC$RDS ;READ SECTOR COMMAND CALL DSK$EX ;PERFORM OPERATION JNZ DSK$ER ;ERROR EXIT LHLD @DMA ;LOAD USER BUF ADDRESS XCHG ;MOVE HL TO DE LDA DNS ;GET DENSITY FLAG ORA A CNZ SETDD ;NOT 0 MST BE DOUBLE LHLD SEC$SZ ;LOAD SECTOR SIZE MOV B,H MOV C,L ;MOVE COUNT TO B LHLD DD$BUF ;LOAD BUFFER CALL BLOCK ;BLOCK MOVE ROUTINE JMP DSK$OK ;NORMAL RETURN ; ; ; DISK READ/WRITE EXITS ; DSK$OK: CALL BNK1 ;SWITCH DD TO BANK 1 XRA A ;CLEAR A FOR GOOD END RET ; ; ;MOVE TRANSFER PARAMETERS TO DCM BLOCK PMOVE: LDA @RDRV ;GET DRIVE NUMBER STA DISK ;PUT IN COMMAND BLOC LHLD @TRK MOV A,L ;GET LOW 8 BITS STA TRACK LHLD @SECT MOV A,L STA SECTOR RET ; ; DOUBLE D EXECUTION SUBROUTINE ; ;( COMMAND BLOCK TO DOUBLE D AND EXEC ) DSK$EX: STA BT$CMD ;STORE DCM COMMAND LXI B,7 ;NMBR BYTE TO MOVE LXI D,DD$CBT ;COMMAND BYTE OFFSET LXI H,BT$CMD ;BIOS CMND BLOCK CALL BLOCK ;PERFORM BLOCK MOVE MVI A,DC$INT ;LOAD DD INTERRUPT OUT D$PORT ;ISSUE DD INTERRUPT ;( WAIT FOR DOUBLE D HALT )* MVI B,01H ;HALT MASK IN B REGISTER DSK$WT: IN D$PORT ;READ DD STATUS ANA B ;TEST HALT* FLAG JNZ DSK$WT ;TEST UNTIL HALTED ;( GET DOUBLE D STATUS ) CALL BNK0 ;SWITCH DD ON TO BANK 0 LDAX D ;GET STATUS BYTE MOV M,A ;STORE IN CMD BLK STA ERFLAG ANA A ;TEST FOR ERRORS RET ;RETURN TO CALLER ; ;TURN DD TO BANK 0 ; BNK0 MVI A,DC$MB0 ;BANK O NUMBER OUT D$PORT ;SEND IT RET ; ;TURN DD TO BANK 1 ; BNK1 MVI A,DC$MB1 ;BANK 1 VALUE OUT D$PORT RET ; ; SUPPRESS ERROR MESSAGE IF BDOS IS RETURNING ERRORS TO APPLICATION... DSK$ER: CALL BNK1 ;SWITCH DD TO BANK 1 ; LHLD OPERATION$NAME CALL PMSG ; LAST FUNCTION ; THEN, MESSAGES FOR ALL INDICATED ERROR BITS LDA BT$STS ; GET STATUS BYTE FROM LAST ERROR LXI H,ERROR$TABLE ; POINT AT TABLE OF MESSAGE ADDRESSES ERRM1: MOV E,M INX H MOV D,M INX H ; GET NEXT MESSAGE ADDRESS ADD A PUSH PSW ; SHIFT LEFT AND PUSH RESIDUAL BITS WITH STATUS XCHG CC PMSG XCHG ; PRINT MESSAGE, SAVING TABLE POINTER POP PSW JNZ ERRM1 ; IF ANY MORE BITS LEFT, CONTINUE LXI H,ERROR$MSG CALL PMSG ; PRINT ", RETRY (Y/N) ? " CALL U$CONIN$ECHO ; GET OPERATOR RESPONSE CPI 'Y' JZ MORE$RETRIES ; YES, THEN RETRY 10 MORE TIMES HARD$ERROR: ; OTHERWISE, JMP MONIT ; MORE$RETRIES: LDA BT$CMD ANA A ;WAS IT A LOGIN JZ LOGIN JMP READ ; U$CONIN$ECHO: ; GET CONSOLE INPUT, ECHO IT, AND SHIFT TO UPPER CASE CALL ?CONIN PUSH PSW MOV C,A CALL ?CONO POP PSW CPI 'a' RC SUI 'a'-'A' ; MAKE UPPER CASE RET ; ERROR MESSAGE COMPONENTS LOG$MSG: DB ' LOG-',0 READ$MSG DB ' READ-',0 OPERATION$NAME DW READ$MSG ; TABLE OF POINTERS TO ERROR MESSAGE STRINGS ; FIRST ENTRY IS FOR BIT 7 OF 1797 STATUS BYTE ERROR$TABLE DW B7$MSG DW B6$MSG DW B5$MSG DW B4$MSG DW B3$MSG DW B2$MSG DW B1$MSG DW B0$MSG B7$MSG DB ' NOT READY,',0 B6$MSG DB ' PROTECT,',0 B5$MSG DB ' FAULT,',0 B4$MSG DB ' RECORD NOT FOUND,',0 B3$MSG DB ' CRC,',0 B2$MSG DB ' LOST DATA,',0 B1$MSG DB ' DREQ,',0 B0$MSG DB ' BUSY,',0 ERROR$MSG DB ' RETRY (Y/N) ? ',0 ; ; ID LABEL DEFINITIONS ; JADEID: DB 'Jade' ;ID LABEL ID$SZE EQU $-JADEID ;LABEL SIZE ; ; DOUBLE D - DCM COMMAND BLOCK BUFFER ; BT$CMD: DB 0 ;DCM COMMAND DISK: DB 0 ;DRIVE NUMBER TRACK: DB 0 ;TRACK NUMBER SECTOR: DB 0 ;SECTOR NUMBER BT$SP0: DB 0 ;SPARE BYTE 0 BT$CHR: DB 0 ;LIST CHARACTER BT$MOD: DB 0 ;MODE CONTROLS BT$STS: DB 0 ;COMMAND STATUS ; ; BIOS VARIABLE STORAGE ; DT$PTR: DW FDSD0 ;DPH POINTER DD$BUF: DW DD$SBUF ;SINGLE DENSITY BUFFER SEC$SZ: DW 80H ;STANADRD SECTOR SIZE LOG$RQ: DB 0 ;LOG ON REQUEST REG DNS: DB 1 ;DENSITY 1 = DD; 0 = SD ERFLAG: DS 1 ; ; disk communication data items @adrv ds 1 ; currently selected disk drive @rdrv ds 1 ; controller relative disk drive @trk ds 2 ; current track number @sect ds 2 ; current sector number @dma ds 2 ; current DMA address ; EXTENDED DISK PARAMETER HEADERS (XPDHS) ; DW WRITE ; DW READ ; DW LOGIN ; DW INIT ; DB 0,0 ; RELATIVE DRIVE ZERO FDSD0 DW TRANS DB 0,0,0,0,0,0,0,0,0 DB 0 ;MEDIA FLAG DW DPBSD DW CVEC ;CHECKSUM VECTOR DW AVEC ;ALLOCATION VECTOR DW DIRBCB ;DIRECTORY BUFFER CONTROL BLK DW DTABCB ;DATA BCB DW 0FFFFH ;NO HASH DB 0 ;HASH BANK ; CVEC: DS 32 AVEC: DS 40 ; DIRBCB: DB 0FFH ;DRIVE NUMBER DB 0,0,0 ;RECORD # DB 0 ;WFLG DB 0 ;0 DW 0 ;TRACK DW 0 ;SECTOR DW BUF0 ;BUFFERADDR DB 0 ;BANK DW 0 ;LINK DTABCB: DB 0FFH ;DRIVE NUMBER DB 0,0,0 ;RECORD # DB 0 ;WFLG DB 0 ;0 DW 0 ;TRACK DW 0 ;SECTOR DW BUF1 ;BUFFERADDR DB 0 ;BANK DW 0 ;LINK DPBSD DPB 1024,9,77,2048,128,2 DPBSD0 DPB 128,26,77,1024,64,2 TRANS SKEW 26,6,1 TRANS1 DB 1,2,3,4,5,6,7,8,9 BUF0: EQU $ BUF1: EQU $+1024 END +-----------------------------------------------------------------+ | ****** NOTICE ****** | | Copyright 1985 by Micro/Systems Journal | | PO Box 1192, Mountainside, NJ 07092 : | All rights reserved, reproduction prohibited without permission : +-----------------------------------------------------------------+;SYSTEM TEST PROGRAM SECSZ EQU 80H ; ORG 2*SECSZ DB 'SECTOR 1 TRACK 0' ORG 3*SECSZ DB 'SECTOR 2 TRACK 0' ORG 4*SECSZ DB 'SECTOR 3 TRACK 0' ORG 5*SECSZ DB 'SECTOR 4 TRACK 0' ORG 6*SECSZ DB 'SECTOR 5 TRACK 0' ORG 7*SECSZ DB 'SECTOR 6 TRACK 0' ORG 8*SECSZ DB 'SECTOR 7 TRACK 0' ORG 9*SECSZ DB 'SECTOR 8 TRACK 0' ORG 10*SECSZ DB 'SECTOR 9 TRACK 0' ORG 11*SECSZ DB 'SECTOR 10 TRACK 0' ORG 12*SECSZ DB 'SECTOR 11 TRACK 0' ORG 13*SECSZ DB 'SECTOR 12 TRACK 0' ORG 14*SECSZ DB 'SECTOR 13 TRACK 0' ORG 15*SECSZ DB 'SECTOR 14 TRACK 0' ORG 16*SECSZ DB 'SECTOR 15 TRACK 0' ORG 17*SECSZ DB 'SECTOR 16 TRACK 0' ORG 18*SECSZ DB 'SECTOR 17 TRACK 0' ORG 19*SECSZ DB 'SECTOR 18 TRACK 0' ORG 20*SECSZ DB 'SECTOR 19 TRACK 0' ORG 21*SECSZ DB 'SECTOR 20 TRACK 0' ORG 22*SECSZ DB 'SECTOR 21 TRACK 0' ORG 23*SECSZ DB 'SECTOR 22 TRACK 0' ORG 24*SECSZ DB 'SECTOR 23 TRACK 0' ORG 25*SECSZ DB 'SECTOR 24 TRACK 0' ORG 26*SECSZ DB 'SECTOR 25 TRACK 0' ORG 27*SECSZ DB 'SECTOR 26 TRACK 0' ORG 28*SECSZ DB 'SECTOR 1 TRACK 1' ORG 29*SECSZ DB 'SECTOR 2 TRACK 1' ORG 30*SECSZ DB 'SECTOR 3 TRACK 1' ORG 31*SECSZ DB 'SECTOR 4 TRACK 1' ORG 32*SECSZ DB 'SECTOR 5 TRACK 1' ORG 33*SECSZ DB 'SECTOR 6 TRACK 1' ORG 34*SECSZ DB 'SECTOR 7 TRACK 1' ORG 35*SECSZ DB 'SECTOR 8 TRACK 1' ORG 36*SECSZ DB 'SECTOR 9 TRACK 1' ORG 37*SECSZ DB 'SECTOR 10 TRACK 1' ORG 38*SECSZ DB 'SECTOR 11 TRACK 1' ORG 39*SECSZ DB 'SECTOR 12 TRACK 1' ORG 40*SECSZ DB 'SECTOR 13 TRACK 1' ORG 41*SECSZ DB 'SECTOR 14 TRACK 1' ORG 42*SECSZ DB 'SECTOR 15 TRACK 1' ORG 43*SECSZ DB 'SECTOR 16 TRACK 1' ORG 44*SECSZ DB 'SECTOR 17 TRACK 1' ORG 45*SECSZ DB 'SECTOR 18 TRACK 1' ORG 46*SECSZ DB 'SECTOR 19 TRACK 1' ORG 47*SECSZ DB 'SECTOR 20 TRACK 1' ORG 48*SECSZ DB 'SECTOR 21 TRACK 1' ORG 49*SECSZ DB 'SECTOR 22 TRACK 1' ORG 50*SECSZ DB 'SECTOR 23 TRACK 1' ORG 51*SECSZ DB 'SECTOR 24 TRACK 1' ORG 52*SECSZ DB 'SECTOR 25 TRACK 1' ORG 53*SECSZ DB 'SECTOR 26 TRACK 1' ORG 54*SECSZ DB 'SECTOR 27 TRACK 1' ORG 55*SECSZ DB 'SECTOR 28 TRACK 1' ORG 56*SECSZ DB 'SECTOR 29 TRACK 1' ORG 57*SECSZ DB 'SECTOR 30 TRACK 1' ORG 58*SECSZ DB 'SECTOR 31 TRACK 1' ORG 59*SECSZ DB 'SECTOR 32 TRACK 1' ORG 60*SECSZ DB 'SECTOR 33 TRACK 1' ORG 61*SECSZ DB 'SECTOR 34 TRACK 1' ORG 62*SECSZ DB 'SECTOR 35 TRACK 1' ORG 63*SECSZ DB 'SECTOR 36 TRACK 1' ORG 64*SECSZ DB 'SECTOR 37 TRACK 1' ORG 65*SECSZ DB 'SECTOR 38 TRACK 1' ORG 66*SECSZ DB 'SECTOR 39 TRACK 1' ORG 67*SECSZ DB 'SECTOR 40 TRACK 1' ORG 68*SECSZ DB 'SECTOR 41 TRACK 1' ORG 69*SECSZ DB 'SECTOR 42 TRACK 1' ORG 70*SECSZ DB 'SECTOR 43 TRACK 1' ORG 71*SECSZ DB 'SECTOR 44 TRACK 1' ORG 72*SECSZ DB 'SECTOR 45 TRACK 1' ORG 73*SECSZ DB 'SECTOR 46 TRACK 1' ORG 74*SECSZ DB 'SECTOR 47 TRACK 1' ORG 75*SECSZ DB 'SECTOR 48 TRACK 1' ORG 76*SECSZ DB 'SECTOR 49 TRACK 1' ORG 77*SECSZ DB 'SECTOR 50 TRACK 1' ORG 78*SECSZ DB 'SECTOR 51 TRACK 1' ORG 79*SECSZ DB 'SECTOR 52 TRACK 1' ORG 80*SECSZ DB 'SECTOR 53 TRACK 1' ORG 81*SECSZ DB 'SECTOR 54 TRACK 1' ORG 82*SECSZ DB 'SECTOR 55 TRACK 1' ORG 83*SECSZ DB 'SECTOR 56 TRACK 1' ORG 84*SECSZ DB 'SECTOR 57 TRACK 1' ORG 85*SECSZ DB 'SECTOR 58 TRACK 1' ORG 86*SECSZ DB 'SECTOR 59 TRACK 1' ORG 87*SECSZ DB 'SECTOR 60 TRACK 1' ORG 88*SECSZ DB 'SECTOR 61 TRACK 1' ORG 89*SECSZ DB 'SECTOR 62 TRACK 1' ORG 90*SECSZ DB 'SECTOR 63 TRACK 1' ORG 91*SECSZ DB 'SECTOR 64 TRACK 1' END Utilities and CP/M Plus Whenever an operating system is upgraded, there is always a risk that some of your old programs will not work in the new system. The change from CP/M version 2.2 to Plus is no different. The programs that are mainly affected are utilities such as DU and FORMAT. These tend to use BIOS calls instead of BDOS calls. This article will try to give some insight as to the hows and whys. How to determine if a utility should work: Any utility that uses direct BIOS calls, or transfers data to or from a disk without operating system intervention is an excellent candidate for problems with CP/M Plus. Some versions of Plus will impose more difficulty than others. The following will give more light to the source of problems: 1. Are the sectors on the diskettes larger than 128 bytes? 2. If so, does the BDOS do the blocking and deblocking? 3. Does the program use the BIOS jump vector table? Questions 1 and 2: If the sector size on the diskettes is larger than 128 bytes, then either the BIOS or the BDOS can break it into 128 byte chunks. This is called blocking / deblocking. In version 2.2 all blocking and deblocking was done in the BIOS, so all calls to the BIOS provided 128 byte blocks. In CP/M Plus either the BIOS or the BDOS can perform the blocking and deblocking. If it is performed in the BIOS, then there is little difference between version 2.2 and Plus as far as the size of blocks, and the sector number. If the BDOS performs the function, then any program that calls a BIOS vector, or does a BDOS call to a BIOS vector must expect a full physical sectors worth of data, (not a 128 byte block), and must deal with actual sector numbers (not the equivalent number of 128 byte blocks). Question 3: Programs that directly jump to BIOS vectors can be playing with fire in Plus. Jumps to the console routine are relatively safe since CP/M takes care to provide a legal stack before it changes the memory bank in context. The other vectors expect the proper bank to be in context when called. If the wrong bank is in context the routine will jump to the right address in the wrong memory bank, and who knows what will happen. Utilities that work: Some of the programs that I use repeatedly and without any trouble are: BDS-C WORDSTAR DBASE PMATE CATALOG COMPARE SUPERCALC MODEM DU86 MBASIC In fact if everyone used their AUX device for a modem, MODEM with basic functionality could work in every system without custom configuration. CP/M version 2.2 does not have a STATUS routine available for the AUX device, and Plus does. This routine is necessary for MODEM to function. Some of the programs that I have had to modify and/or just do without for now are: COPYFAST FORMAT Some really great programs (under version 2.2) don't seem worthwhile under Plus. SWEEP and WASH still have some use, but with PIP now allowing a CONFIRM for each on a wildacard transfer they have lost much of their value. PIP requires an answer for each file (which means you have to be awake) where with SWEEP you can tag files, and while the selected ones are transfering, you can have a beer. XDIR and other DIR type programs also have lost their flare. DIR has SORT and FULL functions amongst others which provide the same functionality. Another utility kept track of changes in the directory of the diskette since the last time it was invoked. This also isn't quite as necessary since the ARCHIVE function will keep track of this for you. How to Modify a Utility to Work: It's time to get to the nitty-gritty - what to do if your favorite utility doesn't work. First of all get the source, because without it you may have only one chance which I will discuss later. The first thing to modify is to have all direct BIOS calls now use BDOS calls. The disk calls can use BDOS call 50. This should make your utility work in banked systems. If it uses disk I/O you may have to add blocking and deblocking to it. Use the routines provided in version 2.2 BIOS. Blocking and Deblocking - since the manuals do not go into the theory of blocking, it might help if I shed some light on it. CP/M can only function with 128 byte blocks of data or files. If the diskette in use has 1024 bytes per sector, it can only transfer full sectors at a time, so it must transfer 8 equivalent CP/M data blocks at one time. The operating system can only use one at a time so some program must extract the proper 128 byte block from the 1024 byte sector. This program is called the blocking / deblocking program. The following comprise a basic set of rules that this program must follow: 1. It checks to see if the data in the buffer contains the 128 byte block to be read or written. If it does, then it returns the data on a read, or writes the data into the buffer on a write and returns to the calling program. 2. If the data is not present, it does two things. First it determines if data from previous write commands has been placed in the buffer and not written to the disk yet. If so, then it writes the data in the buffer to the proper sector. 3. It then determines the physical sector number on the track for the new data, and reads that sector into the buffer (defined as a pre-read for write commands. It determines which 128 byte block the system is addressing and either reads or writes the data from or to the buffer and returns to the calling buffer. 4. The writes can be modified by three subfunctions: Write Unallocated, Write Allocated, and Write Directory. The Write Unallocated tells the BIOS that the group of sectors it is currently writing has never been used before, and therefore it is not necessary to do the pre-read. The Write allocated infers that valid data may be contained in adjacent sectors, and a pre-read is neccessary. The Write Directory forces a write after each 128 byte block is written. This is because a directory write is the last function when writing files, and will purge the buffer of all data and write it to the disk. The data in the buffer acts as a temporary cache for data, and speeds up disk accesses by not having to wait an average half revolution for each transfer. In this case you will only have to wait one in every eight transfers. For example, in reading a file CP/M requests sector 7 on track 43 from the BIOS. The data buffer in the BIOS does not contain valid data and therefore the physical sector must be read from the disk. It calculates which physical sector(1024 bytes long) logical sector 7(128 bytes long) will be in and then reads that sector (sector 1). The BIOS calculates that the address of logical sector 7 within the buffer is 300h (sector 1 at 0h, sector 2 at 80h, sector 3 at 100h, etc.) It passes the data from 300h to 380h back to CP/M. In this example, the BIOS is doing the blocking deblocking. Now, the above example with the BDOS performing the blocking and deblocking: The BDOS has determined that the data it wants is in physical sector 1 of track 43. It requests this sector from the BIOS. The BIOS will send the BDOS all 1024 bytes of data in sector 1 and the BDOS will figure out which 128 byte block it really wants. This makes the BIOS much easier to write and debug. The problem lies with utilities and BDOS deblocking. When the utility requests data from a disk, it specifies a logical CP/M sector number, and expects 128 bytes of data. The BIOS will send the full sector size of 1024 bytes from that physical sector number if it exists on the track. Hence the problem. In the first example, the BIOS expected sector numbers in the range of 1 - 64. That is 8 - 1024 byte sectors per track, and 8 logical CP/M sectors per physical sector or 64 total sectors. In the second example, the BIOS expects only the physical sector number (1-8) since it does not divide the physical into logical sectors. There are two answers. Rewrite the utility to contain blocking and deblocking algorithyms. Or write an RSX (Resident System Extension) that will remain in memory and do the blocking, deblocking, and memory bank context handling to simulate CP/M version 2.2. I have not tried the latter, but believe it is possible. The RSX is the only answer I have to programs where the source is unavailable. The warm boot vector in the first page of memory will have to point to the RSX and it will have to have a duplicate of the BIOS jump vector table.