"From the old we improve the new" SPECIAL THANKS TO: Richard Evers (Transactor Magazine) "Thanks for having faith" TITLE : Anatomy of the 4040 Disk Drive AUTHOR : Hilaire Gagne 4501 Carl Street P.O. Box 278 Hanmer, Ontario, CANADA P0M 1Y0 TELEPHONE : 1-705-969-2189 DATE BEGUN : April 26th, 1985 DATE COMPLETED : February 18th, 1988 DESCRIPTION OF BOOK: This book provides a complete description of the Commodore 4040 dual floppy drive. The book covers file management, data management disk management, file organization, advanced disk programming, hardware and software interfacing, RAM and ROM disassembly, and application examples.
F O R E W O R D To begin with, I would like to thank you; the READER! I have been assembling this work since 1985; now after almost 3 years, the "ANATOMY OF THE 4040 DISK DRIVE" becomes a reality. Some of you may wonder "WHY PURCHASE THIS BOOK" ? Well, even though the 4040 dual disk drive unit is now absolete; there still remains a very large base of these units throughout the world. Founder of the 1540/1541, 1570/1571 and now part of the new 1581 (3.5" drive) DOS, the 4040 dual drive has never quite been documented. In the very pages of this book, you will find the beginning of COMMODORE DOS: methods and operation, even DOS BUGS !, originate here ! With a detailed assembly of early COMMODORE DOS, the inquisitive minds will now be able to fully understand the newest and oldest COMMODORE eight bit technology. Hilaire Gagne February 18th, 1988
O R D E R F O R M Customer Name: Address : Enclosed is a money order for: DESCRIPTION COST (Can) COST (Usa) QUANT -------------------------------------------------------------------------- Anatomy of the 4040 dual disk drive $ 39.95 ea $ 31.95 ea Anatomy of the 8050 dual disk drive N/A N/A N/A Anatomy of the 1581 single 3.5" drive N/A N/A N/A SUB-TOTAL : $ . Postage ($ 3.00 Can/ $ 4.00 other): $ . --------- TOTAL : $ . Please address money order to: Hilaire Gagne P.O. Box 278 4501 Carl Street Hanmer, Ontario, CANADA P0M 1Y0 (Allow 2-4 weeks for delivery)
Table of Contents Chapter 1 - INTRODUCTION Unpacking your 4040 dual floppy drive .......................1- 1 Hardware tree of Commodore products .........................1- 1 Recommended books for reading ...............................1- 2 Chapter 2 - DOS file management commands DLOAD (BASIC 4.0) / LOAD (BASIC 2.0) command ................2- 1 DSAVE (BASIC 4.0) / SAVE (BASIC 2.0) command ................2- 1 BACKUP (BASIC 4.0) / DUPLICATE (BASIC 2.0) command ..........2- 2 RENAME command ..............................................2- 3 SCRATCH command .............................................2- 3 COPY (BASIC 4.0) command ....................................2- 4 CONCAT command ..............................................2- 5 Chapter 3 - DOS data management commands DOPEN (BASIC 4.0) / OPEN (BASIC 2.0) command ................3- 1 DCLOSE (BASIC 4.0) / CLOSE (BASIC 2.0) command ..............3- 1 VERIFY (BASIC 2.0) command ..................................3- 2 PRINT# command ..............................................3- 3 GET# command ................................................3- 3 INPUT# command ..............................................3- 3 APPEND# (BASIC 4.0) command .................................3- 4 RECORD# (BASIC 4.0) / POSITION (BASIC 2.0) command ..........3- 4 FILE MODES: read ............................................3- 5 write ...........................................3- 5 append ..........................................3- 5 modify ..........................................3- 6 Chapter 4 - DOS disk management commands HEADER (BASIC 4.0) / NEW (BASIC 2.0) command ................4- 1 COLLECT (BASIC 4.0) / VALIDATE (BASIC 2.0) command ..........4- 1 INITIALIZE (BASIC 2.0) command ..............................4- 2 CATALOG & DIRECTORY (BASIC 4.0) command .....................4- 3 LOAD "$" (BASIC 2.0) command ................................4- 3 DS$ (BASIC 4.0) / disk status (BASIC 2.0) command ...........4- 4 Diskette organization: Track and Sectors: SYNCs & GCR .......4- 5 Sector encodement .4- 5 Sectors per track .4- 6 Directory track: BAM .................4- 6 Directory entries ...4- 7 File organization: PRG (program files) ......................4- 8 SEQ (sequential files) ...................4- 8 REL (relative files) .....................4- 9 USR (user files) .........................4-10 DEL (deleted files) ......................4-10 Chapter 5 - Advanced disk programming BLOCK commands: ALLOCATE ....................................5- 1 FREE ........................................5- 1 READ ........................................5- 2 WRITE .......................................5- 3 EXECUTE .....................................5- 3 POINTER .....................................5- 4 MEMORY commands: WRITE ......................................5- 5 READ .......................................5- 5 EXECUTE ....................................5- 6 USER commands: U0 (set ROM jump table) ......................5- 7 U1 or UA (block-read) ........................5- 7 U2 or UB (block-write) .......................5- 8 U3 or UC ($1300) .............................5- 9 U4 or UD ($1303) .............................5- 9 U5 or UE ($1306) .............................5-10 U6 or UF ($1309) .............................5-10 U7 or UG ($130C) .............................5-11 U8 or UH ($130F) .............................5-12 U9 or UI (NMI = $10F0) .......................5-12 U: or UJ (Power on) ..........................5-13 Chapter 6 - Hardware/software interfacing Controller error messages ...................................6- 1 Permanent alteration of DEVICE number .......................6- 5 IEEE software controller (MOS 6502) .........................6- 6 FDC disk controller (MOS 6504) ..............................6- 7 Communicating between IEEE and FDC by use of the job queue ..6- 7 Trouble shooting (hardware) .................................6-11 Chapter 7 - IEEE software controller (MOS 6502) Zero page ...................................................7- 1 RAM memory ..................................................7- 7 ROM memory ..................................................7-12 Chapter 8 - FORMATTING sequence used for 4040 dual floppy drive Formatting code used for HEADER / NEW command ...............8- 1 Chapter 9 - FDC disk controller (MOS 6504) Zero page ...................................................9- 1 RAM memory ..................................................9- 4 ROM memory ..................................................9- 5 APPENDIX A - Miscellaneous programs How to type in programs .....................................A- 1 Anti chatter ................................................A- 2 Soft device change ..........................................A- 3 Get current disk ID's .......................................A- 4 Flash LED's .................................................A- 5 Move drive heads ............................................A- 6 Phase & density check .......................................A- 8 Read HEADER block ...........................................A-10 Speed up ....................................................A-12 DOS version code change .....................................A-13 Write protect sense test ....................................A-14 SPEED VARIATION .............................................A-16 APPENDIX B - IEEE bus definitions IEEE bus connector pins .....................................B- 1 IEEE 488 bus signals ........................................B- 2 IEEE byte transfer sequence .................................B- 3 IEEE port pinouts ...........................................B- 5 IEEE standard definitions ...................................B- 6 APPENDIX C - IC memory/register configurations 6522 VIA (Versatile Interface Adaptor) ......................C- 1 6502 CPU ....................................................C- 2 6522 VIA control registers ..................................C- 3
Chapter 1 - INTRODUCTION
1.1 - UNPACKING YOUR 4040 DUAL FLOPPY DRIVE Before unpacking the disk drive, inspect the shipping cartons for signs of external damage. If the carton is damaged, be especially careful when inspecting its content. Carefully remove all packing material and the contents of the carton. DO NOT discard any packing material until you have made sure you have located all the contents of the carton! The carton should contain: 1. Commodore Dual Floppy Disk Drive 2. User Manual, Part Number: 320899 3. TEST/DEMO diskette: a. 2040/3040/4040 TEST/DEMO diskette, Part Number: 4040037 Well there it is, what the manual states on PAGE 9. After reading the pages to follow, or probably proceeding to hook up our new toy without bothering to read the rest of the manual, we turn on the dual floppy unit and begin experimenting with its features. Several years pass, and Commodore Business Machines keep increasing their computer product line. But as time goes by, older machines become absolete. However, there still remains a large base of users who own some of Commodore's earlier technology. For those who still own a 4040 dual drive and have always wondered how it works, hopefully the following chapters will increase your knowledge on the inner workings of CBM DOS. 1.2 - HARDWARE TREE OF COMMODORE PRODUCTS The following is a list of all known Commodore disk drives. 2040 drive - dual floppy (DOS 1) single sided 5.5" 3040 drive - dual floppy (DOS 1) single sided 5.5" 4040 drive - dual floppy (DOS 2.1) single sided 5.5" 8050 drive - dual floppy (DOS 2.5) single sided 5.5" 2031 drive - single floppy (DOS 2.6) single sided 5.5" 1541 drive - single floppy (DOS 2.6) single sided 5.5" 8250 drive - dual floppy (DOS 2.7) double sided 5.5" SFD drive - single floppy (DOS 2.7) double sided 5.5" D9060 drive - hard disk (DOS 3.0) D9090 drive - hard disk (DOS 3.0) 1551 drive - single floppy (DOS 3.0) single sided 5.5" 1571 drive - single floppy (DOS 3.0) double sided 5.5" 1581 drive - single floppy (DOS 10) single sided 3.5" 1.3 - RECOMMENDED BOOKS FOR READING TITLE : 1571 Internals AUTHOR(S) : Rainer Ellinger PUBLISHER : Abacus Software, Inc. P.O. Box 7211 Grand Rapids, MI 49510,USA TELEPHONE : 1-616-241-5510 ISBN number: 0-916439-01-1 TITLE : Disk System User Reference Guide AUTHOR(S) : Commodore Business Machines, Inc. PUBLISHER : Commodore Business Machines, Inc. 950 Airport Road Westchester, PA 19380, USA TELEPHONE : PART number: 320972-01 TITLE : Inside Commodore DOS AUTHOR(S) : Richard Immers and Gerald G. Neufeld PUBLISHER : DATAMOST 20660 Nordhoff Street Chatsworth, CA 91311-6152, USA TELEPHONE : 1-818-709-1202 ISBN number: 0-88190-366-3 TITLE : PET/CBM and the IEEE 488 bus (GPIB) AUTHOR(S) : Eugene Fisher and C.W. Jensen PUBLISHER : Osborne/McGraw-Hill 630 Bancroft Way Berkeley, CA 94710, USA TELEPHONE : ISBN number: 0-931988-78-0 TITLE : Programming the PET/CBM AUTHOR(S) : Raeto Collin West PUBLISHER : COMPUTE! Books, (Division of: Small Sytem Services, Inc.) 625 Fulton Street P.O. Box 5406 Greensboro, North Carolina, 27403, USA TELEPHONE : 1-919-275-9809 ISBN number: 0-942386-04-3 TITLE : The Anatomy of the 1541 AUTHOR(S) : Lothar Englisch and Norbert Szczepanowski PUBLISHER : Abacus Software, Inc. P.O. Box 7211 Grand Rapids, MI 49510, USA TELEPHONE : 1-616-241-5510 ISBN number: 0-916439-01-1 TITLE : The Complete Commodore Inner Space Anthology AUTHOR(S) : Karl J. Hildon PUBLISHER : TRANSACTOR 501 Alden Road P.O. Box 3250 Markham Industrial Park Markham, Ontario, CANADA L3R 9Z9 TELEPHONE : 1-416-764-7253 ISBN number: 0-9692086-0-X TITLE : The MSD DOS reference guide AUTHOR(S) : David W. Martin PUBLISHER : The OpCode Factory 1417 South Heron Drive Seabrook, Texas, 77586, USA TELEPHONE : ISBN number: TITLE : The PET revealed AUTHOR(S) : Nick Hampshire PUBLISHER : Commodore Business Machines (UK), Ltd. 818 Leigh Road, Trading Estate Slough, Berkshire TELEPHONE : Slough (0753) 74111 ISBN number: TITLE : User's manual for CBM 5.5" dual floppy disk drives AUTHOR(S) : Commodore Business Machines, Inc. PUBLISHER : Commodore Business Machines, Inc. 3330 Scott Boulevard Santa Clara, California, 95051 TELEPHONE : PART number: 320899
Chapter 2 - DOS file management commands
2.1 - DLOAD (BASIC 4.0) / LOAD (BASIC 2.0) command PURPOSE : To retrieve a file stored on a diskette. SUPPORTED DOS : All RECOMMENDED SYNTAX: DLOAD "filename,ex",Ddr ON Udv LOAD "dr:filename,ex",dv,ch dr = Desired drive number ex = Filetype extension (D,P,R,S,U) dv = Disk drive device number ch = Secondary address channel number filename = Desired file on diskette (maximum 16 characters, 13 if extension) is used. WILDCARDS : * ? ROM ENTRY POINT : $D4A6 (main entry point) MEMORY SET-UP : $4300 (DOS command buffer) $4347 (command waiting flag) $ 16 (LOAD function = 0) REGISTERS : . X = character from command buffer . Y = .ACC = command waiting flag 2.2 - DSAVE (BASIC 4.0) / SAVE (BASIC 2.0) command PURPOSE : To store a file on a diskette SUPPORTED DOS : All RECOMMENDED SYNTAX: DSAVE "rpfilename,ex",Ddr ON Udv SAVE "dr:rpfilename,ex",dv,ch dr = Desired drive number ex = Filetype extension (D,P,R,S,U) dv = Disk drive device number rp = File replacement indicator (`) ch = Secondary address channel number filename = Desired file on diskette (maximum 16 characters, 13 if extension) is used. WILDCARDS : ` ROM ENTRY POINT : $D4A6 (main entry point) MEMORY SET-UP : $4300 (DOS command buffer) $4347 (command waiting flag) $ 16 (LOAD function = 0) REGISTERS : . X = character from command buffer . Y = .ACC = command waiting flag 2.3 - BACKUP (BASIC 4.0) / DUPLICATE (BASIC 2.0) command PURPOSE : To perform an exact copy of a diskette onto another diskette. SUPPORTED DOS : Dual drive units only RECOMMENDED SYNTAX: BACKUP Dsr TO Ddr PRINT#ch,"Ddr=sr" ch = Primary address channel number sr = Source drive number dr = Destination drive number WILDCARDS : None ROM ENTRY POINT : $E346 (main entry point) MEMORY SET-UP : $4300 (DOS command buffer) $4347 (command waiting flag) REGISTERS : . X = source drive number . Y = destination drive number .ACC = byte read from block 2.4 - RENAME command PURPOSE : To change the current title of a file on the diskette to a new title. SUPPORTED DOS : All RECOMMENDED SYNTAX: RENAME Ddr,"filename" TO "newfilename" ON Udv PRINT#ch,"Rdr:newfilename=filename" ch = Primary address channel number dr = Desired drive number dv = Disk drive device number filename = Current title of file on diskette (maximum 16 characters) newfilename = Desired title for current file on diskette (maximum 16 characters) WILDCARDS : None ROM ENTRY POINT : $E675 (main entry point) MEMORY SET-UP : $4300 (DOS command buffer) $4347 (command waiting flag) REGISTERS : . X = . Y = .ACC = desired drive number 2.5 - SCRATCH command PURPOSE : To remove a file from a diskette. SUPPORTED DOS : All RECOMMENDED SYNTAX: SCRATCH Ddr,"filename,ex" ON Udv PRINT#ch,"Sdr:filename,ex" ch = Primary address channel number dr = Desired drive number dv = Disk drive device number ex = Filetype extension (D,P,R,S,U) filename = Current title of file on diskette (maximum 16 characters) WILDCARDS : ? * ROM ENTRY POINT : $E2B7 (main entry point) MEMORY SET-UP : $4300 (DOS command buffer) $4347 (command waiting flag) REGISTERS : . X = index into file information table . Y = pointer to directory entry .ACC = 2.6 - COPY command PURPOSE : To transfer files from a diskette to another. SUPPORTED DOS : All (to certain extent) RECOMMENDED SYNTAX: COPY Dsdr,"filename" TO Ddr,"newfilename" ON Udv COPY Dsdr TO Ddr ON Udv PRINT#ch,"Cdr:newfilename=sdr:filename" PRINT#ch,"Cdr=sdr" ch = Primary address channel number dr = Destination drive number sdr = Source drive number dv = Disk drive device number filename = Current title of file on diskette (maximum 16 characters) newfilename = Desired title for current file on diskette (maximum 16 characters) WILDCARDS : ? * ROM ENTRY POINT : $E44A (main entry point) MEMORY SET-UP : $4300 (DOS command buffer) $4347 (command waiting flag) REGISTERS : . X = index into command buffer . Y = .ACC = character from command buffer 2.7 - CONCAT (BASIC 4.0) command PURPOSE : To link one or more file so as to have one file only. SUPPORTED DOS : All RECOMMENDED SYNTAX: CONCAT Dsdr,"filename" TO Ddr,"newfilename" ON Udv dr = Destination drive number sdr = Source drive number dv = Disk drive device number filename = Current title of file on diskette to be used as source file for linking (maximum 16 characters) newfilename = Current title of file on diskette to be used as destination file for linking (maximum 16 characters) WILDCARDS : None ROM ENTRY POINT : $E587 (main entry point) MEMORY SET-UP : $4300 (DOS command buffer) $437D (file stream count) $437E (file stream count) $437F (file stream count) $ 16 (internal channel mode) $ 8B (destination drive number) $ 8C (source drive number) $ B3 (internal read channel) $ B4 (internal write channel) REGISTERS : . X = . Y = .ACC = parameters for command
Chapter 3 - DOS data management commands
3.1 - DOPEN (BASIC 4.0) / OPEN (BASIC 2.0) command PURPOSE : To permit user/programmer access to DOS and files on a diskette. SUPPORTED DOS : All RECOMMENDED SYNTAX: DOPEN#pa,"filename",md,Ddr ON Udv DOPEN#pa,"rpfilename",Lrl,Ddr ON Udv DOPEN#pa,"#bf",Ddr ON Udv OPEN pa,dv,ch,"rpdr:filename,ex,md" OPEN pa,dv,ch,"rpdr:filename,Lrl" OPEN pa,dv,ch,"#bf" pa = Primary address channel number ch = Secondary address channel number dv = Disk drive device number dr = Desired drive number bf = Optional DOS buffer number (0-14) rp = File replacement indicator (`) ex = Filetype extension (D,P,R,S,U) md = File mode (R,W,A,M) rl = Record length of RELATIVE file filename = Desired file on diskette (maximum 16 characters) WILDCARDS : * ? ROM ENTRY POINT : $D4A6 (main entry point) $F279 (beginning of OPEN command) MEMORY SET-UP : $4300 (DOS command buffer) REGISTERS : . X = . Y = .ACC = 3.2 - DCLOSE (BASIC 4.0) / CLOSE (BASIC 2.0) command PURPOSE : To release user/programmer access to DOS and files on a diskette. SUPPORTED DOS : All RECOMMENDED SYNTAX: DCLOSE#pa ON Udv CLOSE pa pa = Primary address channel number dv = Disk drive device number WILDCARDS : None ROM ENTRY POINT : $D4A6 (main entry point) $F58D (beginning of CLOSE command) MEMORY SET-UP : $4300 (DOS command buffer) REGISTERS : . X = . Y = .ACC = 3.3 - VERIFY (BASIC 2.0) command PURPOSE : To compare a file stored on diskette with the current file in computer memory. SUPPORTED DOS : All RECOMMENDED SYNTAX: VERIFY "dr:filename",dv dv = Disk drive device number dr = Desired drive number filename = Desired file on diskette (maximum 16 characters) WILDCARDS : * ? ROM ENTRY POINT : None MEMORY SET-UP : $4300 (DOS command buffer) 3.4 - PRINT# command The PRINT# command is used to send information/data to the 4040 dual drive. PRINT#pa,"data" PRINT#pa,data pa = Primary address channel number data = Parameters or data to be sent to the disk unit var = Variable used to contain information/data from disk: ALPHANUMERIC NUMERIC 3.5 - GET# command The GET# command is used to retrieve information/data from the 4040 dual drive. Only a single character of information/data may be retrieved at a time with this command. GET#pa,var pa = Primary address channel number var = Variable used to contain information/data from disk: ALPHANUMERIC NUMERIC 3.6 - INPUT# command The INPUT# command is used to retrieve information/data from the 4040 dual drive. Information/data will be retrieved and stored in a specified variable until the following characters are encountered: , ; : * ? RETURN INPUT#pa,var pa = Primary address channel number var = Variable used to contain information/data from disk: ALPHANUMERIC NUMERIC This command is also used to retrieve the disk status (see CHAPTER 4). 3.7 - APPEND# (BASIC 4.0) command PURPOSE : To permit more data to be written at the end of a file on disk. SUPPORTED DOS : All RECOMMENDED SYNTAX: APPEND#pa,"filename",Ddr ON Udv dv = Disk drive device number dr = Desired drive number pa = Primary address channel number filename = Desired file on diskette (maximum 16 characters) WILDCARDS : * ? ROM ENTRY POINT : $D4A6 (main entry point) $F279 (beginning of OPEN command) $F425 (beginning of APPEND command) MEMORY SET-UP : $4300 (DOS command buffer) REGISTERS : . X = . Y = .ACC = 3.8 - RECORD# (BASIC 4.0) / POSITION (BASIC 2.0) command PURPOSE : To permit access of a specified record/field within a RELATIVE file. SUPPORTED DOS : All RECOMMENDED SYNTAX: RECORD#pa,rn,bp PRINT#15,"P"+CHR$(pa+96)+CHR$(rl)+CHR$(rh)+CHR$(bp) pa = Primary address channel number rn = Desired record number rl = LO byte of desired record number rh = HI byte of desired record number bp = Desired byte position within record WILDCARDS : None ROM ENTRY POINT : $FCED (main entry point) MEMORY SET-UP : $4300 (DOS command buffer) $4347 (command waiting flag) $4379 (length of command string) $437A (command number) $ 16 (secondary address) $ 45 (command buffer LO byte pointer) REGISTERS : . X = . Y = parameter settings .ACC = character from command buffer 3.9 - FILE MODES Before continuing into the different file modes possible, it should be noted that most BASIC 2.0 commands require that OPEN be performed. When using or making files, OPEN or DOPEN must be used. There are four types of file modes, these are: Read, Write, Append, and Modify. READ : This mode is used to view the information/data within a file. Any file type may be opened for reading. WRITE : This mode is used to create and store information/data within a file. Any file type may be opened for writing. APPEND: This mode is used to reach the end of a current file on disk. When using this mode with PRG, REL, USR, DEL, care must be taken. Improper care may cause permanent corruption of the file in question. MODIFY: This mode is used to permit access to a file on disk which has not been properly closed (*). The mode command may only be used within: OPEN pa,dv,ch,"dr:filename,ex,md" pa = Primary address channel dv = Desired device number (0-15) ch = Secondary address channel dr = Desired drive number (0-1) filename = Desired filename (16 characters maximum) ex = File type extension (P, S, R, D, U) md = Desired file mode (R, W, A, M) The number of files which DOS can allow to be OPENed concurrently depends on the mix of SEQ, PRG, USR, DEL, and REL file types opened. The following combinations are permitted on the 4040 dual drive. REL SEQ/PRG/USR/DEL files opened: 0 5 1 3 2 2 3 0
Chapter 4 - DOS disk management commands
4.1 - HEADER (BASIC 4.0) / NEW (BASIC 2.0) command PURPOSE : To make a diskette read/write compatible. SUPPORTED DOS : All RECOMMENDED SYNTAX: HEADER "diskettename",Iid,Ddr ON Udv PRINT#ch,"Ndr:diskettename,id" dr = Desired drive number id = Track/Sector identification marker dv = Disk drive device number ch = Secondary address channel number diskettename = Desired name for diskette (maximum 16 characters) WILDCARDS : None ROM ENTRY POINT : $E20D (main entry point) MEMORY SET-UP : $4300 (DOS command buffer) $4347 (command waiting flag) $4340 - 4341 (disk id location) $1003 (job queue) $1023 - 1024 (job header) $1100 - 1300 (data buffers 0, 1, 2) $ 13 (current track number) $ 14 (current sector number) REGISTERS : . X = index to storage location for parameters . Y = index to next parameter to read .ACC = parameter for command 4.2 - COLLECT (BASIC 4.0) / VALIDATE (BASIC 2.0) command PURPOSE : To verify diskette and reconstruct a new BAM SUPPORTED DOS : All RECOMMENDED SYNTAX: COLLECT Ddr ON Udv PRINT#ch,"Vdr" dr = Desired drive number dv = Disk drive device number ch = Secondary address channel number WILDCARDS : None ROM ENTRY POINT : $E6EC (main entry point) MEMORY SET-UP : $4300 (DOS command buffer) $4347 (command waiting flag) REGISTERS : . X = . Y = .ACC = parameter for command 4.3 - INITIALIZE (BASIC 2.0) command PURPOSE : To position drive head on the directory track and read the BAM. SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"Idr" dr = Desired drive number dv = Disk drive device number WILDCARDS : None ROM ENTRY POINT : $ECC5 (main entry point) MEMORY SET-UP : $4300 (DOS command buffer) $4347 (command waiting flag) $4391 (file stream image) REGISTERS : . X = . Y = .ACC = file stream image 4.4 - CATALOG & DIRECTORY (BASIC 4.0) command PURPOSE : To display the directory track on the computer's moniter. SUPPORTED DOS : BASIC 4.0 (or higher) RECOMMENDED SYNTAX: CATALOG Ddr ON Udv DIRECTORY Ddr ON Udv dr = Desired drive number dv = Disk drive device number WILDCARDS : None ROM ENTRY POINT : $F279 (main entry point) MEMORY SET-UP : $4300 (DOS command buffer) $433B (command waiting flag) $437A (command number) $ 11 (last program track link accessed) $ 12 (current drive number) $ 13 (current track number) $ 16 (current secondary address) REGISTERS : . X = parameters for command . Y = .ACC = command type 4.5 - LOAD "$" (BASIC 2.0) command PURPOSE : To retrieve the directory from the diskette and store it in the computer's memory. SUPPORTED DOS : All RECOMMENDED SYNTAX: LOAD "$dr:pattern=ftype",dv dr = Desired drive number dv = Disk drive device number pattern = Desired directory entries to view ftype = Desired file type for directory entry to view WILDCARDS : * ? ROM ENTRY POINT : $F279 (main entry point) MEMORY SET-UP : $4300 (DOS command buffer) $433B (command waiting flag) $437A (command number) $ 11 (last program track link accessed) $ 12 (current drive number) $ 13 (current track number) $ 16 (current secondary address) REGISTERS : . X = parameters for command . Y = .ACC = command type 4.6 - DS$ (BASIC 4.0) / disk status (BASIC 2.0) command PURPOSE : To retrieve the disk drive status. SUPPORTED DOS : All RECOMMENDED SYNTAX: ? DS$ INPUT#pa,var,var,var,var pa = Primary address channel number var = ALPHANUMERIC variables (example: A$,B$,C$,D$) WILDCARDS : None ROM ENTRY POINT : None MEMORY SET-UP : $43DC - 43FF (error message buffer) REGISTERS : . X = . Y = .ACC = DISKETTE ORGANIZATION 4.7 - Tracks and sectors: SYNCS & GCR The SYNC character is used to warn the DOS that there is a HEADER BLOCK or DATA BLOCK coming. The length of a SYNC mark is usually 40 bits. Beginning of SECTOR ..111 HEADER 1111111111111111111111111111111111111111 DATA 111111111111... The storage format used on the disk is called: Group Code Recording. On the 4040 dual drive, there is a special converter chip which handles the conversion and de-conversion. When using locations $0041 (data input) and $0080 (data output) of the FDC controller, the data to read/write will be processed in GCR form. HEX BINARY DECIMAL GCR $00 0000 00 01010 $01 0001 01 01011 $02 0010 02 10010 $03 0011 03 10011 $04 0100 04 01110 $05 0101 05 01111 $06 0110 06 10110 $07 0111 07 10111 $08 1000 08 01001 $09 1001 09 11001 $0A 1010 10 11010 $0B 1011 11 11011 $0C 1100 12 01101 $0D 1101 13 11101 $0E 1110 14 11110 $0F 1111 15 10101 4.8 - Tracks and sectors: Sector encodement There is a bit of discrepancy in the sector recording format. Below, is the diagram shown in most drive manuals. This diagram however, indicates how the retrieved track is displayed within DOS. SYNC 08 ID1 ID2 TRK SCT CHKSUM GAP1 SYNC 07 LNKTRK LNKSCT 254 DATA CHKSUM GAP2 The actual recording structure used is shown in the diagram below: SYNC 08 CHKSUM SCT TRK ID2 ID1 GAP1 SYNC 07 LNKTRK LNKSCT 254 DATA CHKSUM GAP2 As you can see, the HEADER BLOCK is reversed when written to the diskette. 4.9 - Track and Sectors: Sectors per track Sector distribution by track is as follows: # sectors zone density track number 1 - 17 21 1 00 18 - 24 19 2 01 25 - 30 18 3 10 31 - 35 17 4 11 4.10 - Directory track: BAM The Block Availability Map is a disk representation of available space on a diskette. As files are added or deleted from the disk directory, the BAM is altered accordingly. The BAM layout is as follows: LOCATION: Track 18, sector 0 CONTENT : Byte number DATA DESCRIPTION 0 18 Track number of first directory block 1 1 Sector number of first directory block 2 65 DOS 2.0 format, ASCII "A" 3 0 Reserved for future DOS 4 - 143 BAM: Each track controlled by 4 bytes BYTE 0: Total blocks free in track BYTE 1: Sector availability ( 0- 7) BYTE 2: Sector availability ( 8-15) BYTE 3: Sector availability (16-end) (1=FREE sector, 0=ALLOCATED sector) 144 - 161 Diskette name, padded with SHIFTED SPACES 162 - 163 Diskette ID number 164 160 SHIFTED SPACE 165 50 DOS version, ASCII "2" 166 65 DOS version, format "A" 167 - 170 160 SHIFTED SPACES 171 - 255 0 Unused (may display 'BLOCKS FREE' message) 4.11 - Directory track: Directory entries In order to store information (files) on a diskette, a filename must be provided. After the file is stored on the diskette, the information needed for retrieval of the file is stored in a directory. The directory track is as follows: LOCATION: Track 18, sectors 1 - 18 CONTENT : Byte number DATA DESCRIPTION 0 Track number of next directory block 1 Sector number of next directory block 2 - 31 File entry #1 of directory block (29 bytes) BYTE: 1 = file type 2 = track pointer to 1st block 3 = sector pointer to 1st block 5 - 20 = file name 21 = track pointer to 1st side sector if REL file 22 = sector pointer to 1st side sector if REL file 23 = record length if REL file 24 - 25 = reserved for future file information 26 = track pointer during (`) command (replacement) 27 = sector pointer during (`) command (replacement) 28 - 29 = number of blocks used by file 32 - 33 Unused 34 - 63 File entry #2 of directory block (29 bytes) 64 - 65 Unused 66 - 95 File entry #3 of directory block (29 bytes) 96 - 97 Unused 98 - 127 File entry #4 of directory block (29 bytes) 128 - 129 Unused 130 - 159 File entry #5 of directory block (29 bytes) 160 - 161 Unused 162 - 191 File entry #6 of directory block (29 bytes) 192 - 193 Unused 194 - 223 File entry #7 of directory block (29 bytes) 224 - 225 Unused 226 - 255 File entry #8 of directory block (29 bytes) FILE ORGANIZATION There are five types of file organizations used on the 4040 dual drive: PRG, SEQ, REL, USR, DEL. 4.12 - PRG (program files) The extension PRG denotes a file stored in the form of a computer usuable code. Usually BASIC or machine code programs created by a programmer are stored on the diskette with this extension following the size and filename. When looking at the file stored on the diskette, one will notice that there are three major parts/blocks to the file: Byte # Description 1st block : 0 - 1 Track/Sector of next PRoGram block 2 - 3 Load address: LO byte, HI byte 4 - 255 BASIC/machine code text next blocks : 0 - 1 Track/Sector of next PRoGram block 2 - 255 BASIC/machine code text last block : 0 Null byte to indicate last block of file 1 Last byte location in block 2 - ??? Last bytes of BASIC/machine code text There are four possible PRG representations visible on the directory, these are: TYPE HEX ASCII Description *PRG $02 2 Unclosed program file PRG $82 130 Program file PRG $A2 162 Program replacement (`) PRG< $C2 194 Locked program file 4.13 - SEQ (sequential files) The SEQ extension usually denotes that the file stored on the diskette contains information/data. This file type usually appears upon user/programmer request (See CHAPTER 3). It's internal structure consists of: Byte # Description 1st block : 0 - 1 Track/Sector of next SEQuential block 2 - 255 DATA bytes of storage next blocks : 0 - 1 Track/Sector of next SEQuential block 2 - 255 DATA bytes of storage last block : 0 Null byte to indicate last block of file 1 Last byte location in block 2 - ??? Last DATA bytes of file There are four possible SEQ representations visible on the directory, these are: TYPE HEX ASCII Description *SEQ $01 1 Unclosed sequential file SEQ $81 129 Sequential file SEQ $A1 161 Sequential replacement (`) SEQ< $C1 193 Locked sequential file 4.14 - REL (relative files) The REL extension usually denotes that the file stored on the diskette contains information/data. This file type usually appears upon user/programmer request (See CHAPTER 3). The REL file type is divided into to parts, the SIDE SECTOR and DATA SECTOR. SIDE SECTOR: Byte # Description 1st block : 0 Track number of next side sector block 1 Sector number of next side sector block 2 Side sector number 3 Record length 4 - 5 Track and sector number of 1st side sector 6 - 7 Track and sector number of 2nd side sector 8 - 9 Track and sector number of 3rd side sector 10 - 11 Track and sector number of 4th side sector 12 - 13 Track and sector number of 5th side sector 14 - 15 Track and sector number of 6th side sector 16 - 255 Track and sector pointers to 120 data blocks The largest REL file possible is 182,880 bytes long: (120 pointers /per side sector * 6 side sectors) * 254 bytes /per block DATA SECTOR: Byte # Description 1st block : 0 - 1 Track/Sector of next RELative block 2 - 255 DATA bytes of storage There are four possible REL representations visible on the directory, these are: TYPE HEX ASCII Description *REL $04 4 Cannot occur REL $84 132 Relative file REL $A4 164 Cannot occur REL< $C4 196 Locked relative file 4.15 - USR (user files) The USR extension usually denotes that the file stored on the diskette contains information/data. This file type usually appears upon user/programmer request (See CHAPTER 3). It may also denote a file stored in the form of a computer usuable code; usually BASIC or machine code programs created by a programmer. A USR file follows the PRG or SEQ structure only. However, user/programmer design may also be implemented. There are four possible USR representations visible on the directory, these are: TYPE HEX ASCII Description *USR $03 3 Unclosed user file USR $83 131 User file USR $A3 163 User replacement (`) USR< $C3 195 Locked user file 4.16 - DEL (deleted files) The DEL extension usually denotes that the file has been removed from the directory and is not to be displayed during viewing of the directory track. This file type only be visible upon user/programmer request (See CHAPTER 3). A DEL file may follow the PRG or SEQ structure. However, user/programmer design may also be implemented. There are four possible DEL representations visible on the directory, these are: TYPE HEX ASCII Description *DEL $00 0 Does not appear, scratched DEL $80 128 Deleted file DEL $A0 160 Deleted replacement (`) DEL< $C0 192 Locked deleted file
Chapter 5 - Advanced disk programming
B L O C K C O M M A N D S The BLOCK commands make up the first part of the DISK ORIENTED UTILITIES. These commands allow various access to the diskette. 5.1 - BLOCK - ALLOCATE PURPOSE : To mark a block in the BAM as used. SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"B-A:"dr;tr;se ch = Primary address channel number dr = Desired drive number tr = Desired track number se = Desired sector number WILDCARDS : None ROM ENTRY POINT : $E8AF (main entry point) $E992 (beginning of ALLOCATE command) MEMORY SET-UP : $4300 (DOS command buffer) REGISTERS : . X = drive number . Y = marker for BAM block in use (set to: #$01) .ACC = current sector in BAM 5.2 - BLOCK - FREE PURPOSE : To mark a block in the BAM as available. SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"B-F:"dr;tr;se ch = Primary address channel number dr = Desired drive number tr = Desired track number se = Desired sector number WILDCARDS : None ROM ENTRY POINT : $E8AF (main entry point) $E989 (beginning of FREE command) MEMORY SET-UP : $4300 (DOS command buffer) REGISTERS : . X = index into BIT MAP table ($EBC9) . Y = pointer to BAM block sector .ACC = marker used to set block free (set to: #$00) 5.3 - BLOCK - READ PURPOSE : Enables any block from a format compatible diskette to be read. SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"B-R:"bu;dr;tr;se ch = Primary address channel number bu = Second secondary address channel number to use as buffer dr = Desired drive number tr = Desired track number se = Desired sector number WILDCARDS : None ROM ENTRY POINT : $E8AF (main entry point) $E9F5 (beginning of READ command) MEMORY SET-UP : $4300 (DOS command buffer) REGISTERS : . X = index to next character in buffer . Y = pointer to current buffer: bu .ACC = byte read from block 5.4 - BLOCK - WRITE PURPOSE : Writes the current content of a specified buffer to any track and sector of a write compatible diskette. SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"B-W:"bu;dr;tr;se ch = Primary address channel number bu = Second secondary address channel number to use as buffer dr = Desired drive number tr = Desired track number se = Desired sector number WILDCARDS : None ROM ENTRY POINT : $E8AF (main entry point) $EA12 (beginning of WRITE command) MEMORY SET-UP : $4300 (DOS command buffer) DATA BUFFER (00 - 02: $1100 - $13FF) 256 bytes each DATA BUFFER (03 - 06: $2000 - $23FF) 256 bytes each DATA BUFFER (07 - 10: $3000 - $33FF) 256 bytes each DATA BUFFER (11 - 14: $4000 - $43FF) 256 bytes each REGISTERS : . X = index to next character in buffer . Y = pointer to current buffer: bu .ACC = byte read from block 5.5 - BLOCK - EXECUTE PURPOSE : Reads the content from s specified track and sector into a specified buffer, then jumps in machine language to the start of the data in the buffer. SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"B-E:"bu;dr;tr;se ch = Primary address channel number bu = Second secondary address channel number to use as buffer dr = Desired drive number tr = Desired track number se = Desired sector number WILDCARDS : None ROM ENTRY POINT : $E8AF (main entry point) $EA44 (beginning of EXECUTE command) MEMORY SET-UP : $4300 (DOS command buffer) REGISTERS : . X = pointer to current buffer: bu . Y = .ACC = HI/LO byte of buffer address location 5.6 - BLOCK - POINTER PURPOSE : Sets the beginning position for writing or reading data from/to a given sector/buffer. SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"B-P:"bu;po ch = Primary address channel number bu = Second secondary address channel number to use as buffer po = Byte position within sector/buffer WILDCARDS : None ROM ENTRY POINT : $E8AF (main entry point) $EA5B (beginning of POINTER command) MEMORY SET-UP : $4300 (DOS command buffer) REGISTERS : . X = pointer to current buffer: bu . Y = current channel number .ACC = byte position of next character to write/read in sector/buffer M E M O R Y C O M M A N D S The MEMORY commands make up the second part of the DISK ORIENTED UTILITIES. These commands allow various access to the ROM/RAM found within the 4040 dual drive. 5.7 - MEMORY - WRITE PURPOSE : Enables data to be placed in the 4040 dual drive RAM. A maximum of 34 BYTES may be sent with each use of this command. SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"M-W"CHR$(adl)CHR$(adh)CHR$(nu)CHR$(da) ch = Primary address channel number adl = LO byte of desired memory address adh = HI byte of desired memory address nu = Number of bytes to be sent da = Data bytes to be sent WILDCARDS : None ROM ENTRY POINT : $E7A8 (main entry point) $E7FC (beginning of WRITE command) MEMORY SET-UP : $4300 (DOS command buffer) REGISTERS : . X = . Y = pointer to next byte to be written in DOS .ACC = byte to be written to DOS 5.8 - MEMORY - READ PURPOSE : Enables data to be read from the 4040 dual drive RAM/ROM. Only 1 BYTE may be read from the DOS at a time by use of the GET# command. SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"M-W"CHR$(adl)CHR$(adh)CHR$(nu) ch = Primary address channel number adl = LO byte of desired memory address adh = HI byte of desired memory address nu = Number of bytes to be read from DOS WILDCARDS : None ROM ENTRY POINT : $E7A8 (main entry point) $E7CD (beginning of READ command) MEMORY SET-UP : $4300 (DOS command buffer) REGISTERS : . X = current byte number being read . Y = pointer to next byte to be read from DOS .ACC = byte read from DOS memory location 5.9 - MEMORY - EXECUTE PURPOSE : Jumps to the desired memory address within the IEEE DOS Controller. SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"M-E"CHR$(adl)CHR$(adh) ch = Primary address channel number adl = LO byte of desired memory address adh = HI byte of desired memory address WILDCARDS : None ROM ENTRY POINT : $E7A8 (main entry point) MEMORY SET-UP : $4300 (DOS command buffer) REGISTERS : . X = . Y = .ACC = HI/LO byte of memory address location U S E R C O M M A N D S The USER commands make up the third part of the DISK ORIENTED UTILITIES. These commands allow various access to the ROM/RAM, and diskette. 5.10 - U0 (Set ROM jump table) PURPOSE : Stores $FFEA at ZERO PAGE location ($0000). SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"U0:" ch = Primary command address channel number WILDCARDS : None ROM ENTRY POINT : $E808 (main entry point) MEMORY SET-UP : $4300 (DOS command buffer) REGISTERS : . X = . Y = byte from command buffer .ACC = HI/LO pointer for $FFEA 5.11 - U1 or UA (BLOCK - READ) PURPOSE : Enables any block from a format compatible diskette to be read. SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"U1:"bu;dr;tr;se ch = Primary command address channel number bu = Second secondary command address channel number to use as buffer dr = Desired drive number tr = Desired track number se = Desired sector number WILDCARDS : None ROM ENTRY POINT : $E808 (main entry point) $E9FE (beginning of U1/UA command) MEMORY SET-UP : $4300 (DOS command buffer) REGISTERS : . X = index to next character in buffer . Y = pointer to current buffer: bu .ACC = byte read from block 5.12 - U2 or UB (BLOCK - WRITE) PURPOSE : Writes the current content of a specified buffer to any track and sector of a write compatible diskette. SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"U2:"bu;dr;tr;se ch = Primary command address channel number bu = Second secondary command address channel number to use as buffer dr = Desired drive number tr = Desired track number se = Desired sector number WILDCARDS : None ROM ENTRY POINT : $E808 (main entry point) $EA38 (beginning of U2/UB command) MEMORY SET-UP : $4300 (DOS command buffer) DATA BUFFER (00 - 02: $1100 - $13FF) 256 bytes each DATA BUFFER (03 - 06: $2000 - $23FF) 256 bytes each DATA BUFFER (07 - 10: $3000 - $33FF) 256 bytes each DATA BUFFER (11 - 14: $4000 - $43FF) 256 bytes each REGISTERS : . X = index to next character in buffer . Y = pointer to current buffer: bu .ACC = byte read from block 5.13 - U3 or UC PURPOSE : Jump to memory address located in USER JUMP TABLE. SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"U3:" ch = Primary command address channel number WILDCARDS : None ROM ENTRY POINT : $E808 (main entry point: transferred to table at: $FFEA) $1300 (table jump address set for this command) MEMORY SET-UP : $4300 (DOS command buffer) DATA BUFFER (02: $1300) 256 bytes REGISTERS : . X = . Y = byte from command buffer .ACC = HI/LO pointer for: $1300 5.14 - U4 or UD PURPOSE : Jump to memory address located in USER JUMP TABLE. SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"U4:" ch = Primary command address channel number WILDCARDS : None ROM ENTRY POINT : $E808 (main entry point: transferred to table at: $FFEA) $1303 (table jump address set for this command) MEMORY SET-UP : $4300 (DOS command buffer) DATA BUFFER (02: $1303) 252 bytes REGISTERS : . X = . Y = byte from command buffer .ACC = HI/LO pointer for: $1303 5.15 - U5 or UE PURPOSE : Jump to memory address located in USER JUMP TABLE. SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"U5:" ch = Primary command address channel number WILDCARDS : None ROM ENTRY POINT : $E808 (main entry point: transferred to table at: $FFEA) $1306 (table jump address set for this command) MEMORY SET-UP : $4300 (DOS command buffer) DATA BUFFER (02: $1306) 250 bytes REGISTERS : . X = . Y = byte from command buffer .ACC = HI/LO pointer for: $1306 5.16 - U6 or UF PURPOSE : Jump to memory address located in USER JUMP TABLE. SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"U6:" ch = Primary command address channel number WILDCARDS : None ROM ENTRY POINT : $E808 (main entry point: transferred to table at: $FFEA) $1309 (table jump address set for this command) MEMORY SET-UP : $4300 (DOS command buffer) DATA BUFFER (02: $1309) 246 bytes REGISTERS : . X = . Y = byte from command buffer .ACC = HI/LO pointer for: $1309 5.17 - U7 or UG PURPOSE : Jump to memory address located in USER JUMP TABLE. SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"U7:" ch = Primary command address channel number WILDCARDS : None ROM ENTRY POINT : $E808 (main entry point: transferred to table at: $FFEA) $130C (table jump address set for this command) MEMORY SET-UP : $4300 (DOS command buffer) DATA BUFFER (02: $130C) 243 bytes REGISTERS : . X = . Y = byte from command buffer .ACC = HI/LO pointer for: $130C 5.18 - U8 or UH PURPOSE : Jump to memory address located in USER JUMP TABLE. SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"U8:" ch = Primary command address channel number WILDCARDS : None ROM ENTRY POINT : $E808 (main entry point: transferred to table at: $FFEA) $130F (table jump address set for this command) MEMORY SET-UP : $4300 (DOS command buffer) DATA BUFFER (02: $130F) 240 bytes REGISTERS : . X = . Y = byte from command buffer .ACC = HI/LO pointer for: $130F 5.19 - U9 or UI PURPOSE : Reset Non Maskable Interrupt vector. SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"U9:" ch = Primary command address channel number WILDCARDS : None ROM ENTRY POINT : $E808 (main entry point: transferred to table at: $FFEA) $FFE6 (table jump address set for this command) MEMORY SET-UP : $4300 (DOS command buffer) REGISTERS : . X = . Y = byte from command buffer .ACC = HI/LO pointer for: $FFE6 5.20 - U: or UJ PURPOSE : Perform POWER ON DIAGNOSTICS for drive (cold start). SUPPORTED DOS : All RECOMMENDED SYNTAX: PRINT#ch,"UJ:" ch = Primary command address channel number WILDCARDS : None ROM ENTRY POINT : $E808 (main entry point: transferred to table at: $FFEA) $D32B (table jump address set for this command) MEMORY SET-UP : $4300 (DOS command buffer) REGISTERS : . X = . Y = byte from command buffer .ACC = HI/LO pointer for: $D32B
Chapter 6 - Hardware/software interfacing
6.1 - Controller error messages When the Floppy Disk Controller or the IEEE DOS management Controller encounter and error within DOS, a special routine located at $D953 will produce the following error numbers. Below, is a definition for each possible error number: 20: READ ERROR (BLOCK HEADER not found). The disk controller is unable to locate the HEADER of the requested DATA BLOCK. Caused by an illegal sector number or the HEADER has been destroyed. 21: READ ERROR (NO SYNC character). Indicates hardware failure. 22: READ ERROR (DATA BLOCK not found). The disk controller has been requested to read or verify a DATA BLOCK that was not properly written. This error message occurs in conjunction with the BLOCK commands and indicates an illegal track and/or sector request. 23: READ ERROR (CHECKSUM error in DATA BLOCK). This error message indicates that there is an error in one or more of the DATA bytes. The DATA has been read into DOS memory, but the checksum over the DATA is in error. This message may also indicate grounding problems. 24: READ ERROR (Byte decoding error). The DATA or HEADER BLOCK has been read into DOS memory but a hardware error has been created due to an invalid bit pattern in the DATA byte. This message may also indicate grounding problems. 25: WRITE ERROR (Write-verify error). This message is generated if the controller detects a mismatch between the written DATA and the DATA in DOS memory. 26: WRITE PROTECT ON (Write sense on). This message is generated when the controller has been requested to write a DATA BLOCK while the write protect switch is depressed. Typically, this is caused by using a diskette with a write protect tab over the notch. 27: READ ERROR (CHECKSUM error in HEADER BLOCK). The controller has detected an error in the HEADER of the requested DATA BLOCK. The BLOCK has not been read into DOS memory. This message may also indicate grounding problems. 28: WRITE ERROR (Long DATA BLOCK). The controller attempts to detect the SYNC mark of the next HEADER after writing a DATA BLOCK. If the SYNC mark does not appear within a pre-determined time, the error message is generated. The error is caused by a bad diskette format (the DATA extends into the next BLOCK), or by hardware failure. 29: DISK ID MISMATCH (Invalid DISK ID). This message is generated when the controller has been requested to access a diskette which has not been initialized. The message can also occur if a diskette has a bad HEADER. 30: SYNTAX ERROR (General syntax). The DOS cannot interpret the command sent to the command channel. Typically, this is caused by an illegal number of file names, or patterns are illegally used. 31: SYNTAX ERROR (Invalid command). The DOS does not recognize the command. The command must start in the first position. 32: SYNTAX ERROR (Long line). The command sent is longer than 58 characters. 33: SYNTAX ERROR (Invalid filename). Pattern matching is invalidly used in the DOPEN, OPEN, or DSAVE, SAVE commands. 34: SYNTAX ERROR (No file given). The filename was left out of a command or the DOS does not recognize it as such. Typically, a colon (:) has been left out of the command. 39: SYNTAX ERROR (Invalid command). This error may result if the command sent to the command channel (secondary address 15) is unrecognizable by the DOS. 50: RECORD NOT PRESENT Result of disk reading past the last record via INPUT#, or GET# commands. This message will also occur after positioning to a record beyond the end of file in a relative file. If the intent is to expand the file by adding the new record (with a PRINT# command), the error message may be ignored. INPUT or GET should not be attempted after this error is detected without first repositioning to a valid record number. 51: OVERFLOW IN RECORD DATA written with a PRINT# statement exceeds the defined relative record size. DATA is truncated to defined size. Typically, cause is failing to include carriage returns sent as field or record terminators when calculating the record size. 52: FILE TOO LARGE Record position within a relative file indicates that not enough BLOCKS remain available on the disk to contain the specified number of records. 60: WRITE FILE OPEN This message is generated when a write file that has not been closed is being opened for reading. 61: FILE NOT OPEN This message is generated when a file that is being accessed has not been opened in the DOS. Sometimes, in this case, a message is not generated, the request is simply ignored. 62: FILE NOT FOUND The requested file does not exist on the currently specified diskette. 63: FILE EXISTS The file name of the file being created already exists on the diskette. 64: FILE TYPE MISMATCH The file type on a DOPEN, OPEN command does not match the file type in the directory entry for the requested file. 65: NO BLOCK This message occurs in conjunction with the B-A command. It indicates that the BLOCK to be allocated has been previously allocated. The parameters indicate the next higher track and sector number available. If the parameters are zeros (0), then all higher numbered BLOCKS are in use. 66: ILLEGAL TRACK OR SECTOR The DOS has attempted to access a track or sector which does not exist in the format being used. This may also indicate a problem reading the pointer to the next BLOCK. 66: ILLEGAL SYSTEM T OR S Special error message indicating an illegal system track or sector. 70: NO CHANNEL (No availability). The requested channel is not available, or all channels are in use. A maximum of five (5) sequential files or three (3) relative files may be opened at one time to the DOS. Direct access channels may have six (6) opened files. 71: DIRECTORY ERROR The BAM does not match the internal count. The error occurs when there is a problem in the BAM allocation or the BAM has been over-written in DOS memory. To correct this problem, re-initialize the diskette to restore the BAM in memory. Some active files may be terminated by the corrective action. 72: DISK FULL Either all BLOCKS on the disk are in use or the directory is at its limit. DISK FULL is sent when two (2) BLOCKS remain available to allow the current file to be closed. 73: DOS MISMATCH (CBM DOS V2). DOS 1 and DOS 2 are read compatible but not write compatible. Disks may be interchangeably read with either DOS, but a disk formatted on one version cannot be written upon with other versions because the format is different. This error is displayed whenever an attempt is made to write upon a disk which has been formatted in non-compatible format. This message may also appear after power-up. 76: (Controller error). A variety of conditions indicating controller hardware problems. 6.2 - Permanent alteration of DEVICE number The following alteration should be performed by a qualified service technician. The indicated pins should be bent, DO NOT CUT or BREAK OFF. Three pins on IC chip #6532 located at UE1 control the device number. The IC chip should CAREFULLY be removed and the appropriate pins SHOULD BE BENT ! Device number PIN 22 PIN 23 PIN 24 8 unchanged unchanged unchanged 9 unchanged unchanged BEND 10 unchanged BEND unchanged 11 unchanged BEND BEND 12 BEND unchanged unchanged 13 BEND unchanged BEND 14 BEND BEND unchanged 15 BEND BEND BEND 6.3 - IEEE software controller (MOS 6502) The IEEE software controller acts as a "house keeping" processor. In fact, most INPUTS and OUTPUTS must pass through here. The IEEE software controller is composed of several parts of hardware, however the important IC Chips do most of the work. These are: IC Chip #6502 This chip is located at location UN1 of the circuit board. Composed of two 1 MHz clocks, the 4040 dual drive can read information as well as write information during the same span of time. To achieve this, COMMODORE has designed the clocks to be 180 degrees phase shifted. Communication between the IEEE software controller and the FDC controller is done via 1 Kilobyte (K) of RAM. The desired jobs are scanned for proper syntax and passed on, when needed, to the FDC controller. There are two control IC Chips #6332 which compose the RAM for the operating system of the 4040 dual drive. To complement these, two other IC Chips were added to handle the INPUTS and OUTPUTS to various devices. These are: IC Chip #6532 This chip can be found at location UE1 of the circuit board. Major support chip for IC Chip #6502, this particular IC Chip handles most INPUTS such as: IEEE data and handshake lines (DAV, NDAC, etc...). From here, the device number is read and the LED's on the front panel controlled. The lower 128 BYTES of ZERO PAGE are also held within this IC Chip. For hardware purposes, the IC Chip #6532 holds exact similarity to the 6522 IC Chip. IC Chip #6532 This chip can be found at location UC1 of the circuit board. Being another major support chip for IC Chip #6502, this particular IC Chip holds the upper 128 BYTES of ZERO PAGE. Data from/to the IEEE bus is handled through here by use of three MC3446 buffers (located at UB1, UB2 & UD2 on the circuit board). Also done from this IC Chip, is the IEEE control for the 4 Kilobyte (K) RAMs located at: UC4, UD4, UE4, UF4, UC5, UD5, UE5 & UF5. 6.4 - FDC disk controller (MOS 6504) The FDC disk controller controls the physical functions of the 4040 dual drive. Anything involving physical transport of the read/write head, track or sector, is done through the software (ROM) on this IC Chip. Operations to be performed by this controller are received from the IEEE software controller. IC Chip #6522 This chip is located at UK3 on the circuit board. Its primary function is to control the drive and stepper motors of the 4040 dual drive. IC Chip #6530 This chip is located at UM3 on the circuit board. The RAM inside this IC Chip is primarily used to store drive status information, drive select lines, write protect sense, and SYNC detect lines. 6.5 - Communicating between the IEEE and the FDC by use of the job queue One of the most mystifying parts of the 4040 dual drive is the JOB QUEUE. This area of the 4040 dual drive serves as a link from IC Chip #6502 to IC Chip #6504. This area is composed of three parts: the DATA BUFFERS, the JOB HEADERS, and the JOB QUEUES. The DATA BUFFERS There are 14 data buffers on the 4040 dual drive, each buffer is linked to the IC Chip #6504 but at a different memory address. Whenever a series of instructions must be passed to the FDC controller (IC Chip #6504), the programmer must first store the data in the IEEE controller (IC Chip #6502) data buffers. From there, the machine code instructions (data) will be automatically passed to the FDC controller. The buffer layouts are as follows: Buffer number IEEE controller FDC controller 0 $1100 - $11FF imaged to $0500 - $05FF 1 $1200 - $12FF imaged to $0600 - $06FF 2 $1300 - $13FF imaged to $0700 - $07FF 3 $2000 - $20FF imaged to $0800 - $08FF 4 $2100 - $21FF imaged to $0900 - $09FF 5 $2200 - $22FF imaged to $0A00 - $0AFF 6 $2300 - $23FF imaged to $0B00 - $0BFF 7 $3000 - $30FF imaged to $0C00 - $0CFF 8 $3100 - $31FF imaged to $0D00 - $0DFF 9 $3200 - $32FF imaged to $0E00 - $0EFF 10 $3300 - $33FF imaged to $0F00 - $0FFF 11 $4000 - $40FF imaged to $1000 - $10FF 12 (BAM drive 0) $4100 - $41FF imaged to $1100 - $11FF 13 (BAM drive 1) $4200 - $42FF imaged to $1200 - $12FF 14 (NOT USABLE!) $4300 - $43FF imaged to $1300 - $13FF After storing the requested data in the required buffer, by use of the Chapter 5 commands, the start location of the machine code instructions must be given to the FDC controller. Incidentally, DATA BUFFERS 0 and 1 are used extensively by the DOS operating system; so make sure that the requested operations do not require the IEEE controller or the FDC controller to place information in these buffers if you plan on using them. The JOB HEADERS At this point, it should be mentioned that DATA BUFFERS 12, 13, and 14 are also reserved for: BAM drive 0, BAM drive 1, and $4300 - $43FF memory addresses. Now that we have covered the DATA BUFFERS, let's proceed on to the JOB HEADER. Each JOB HEADER holds the following information: BUFFER number memory location content 0 $1021 - $1022 ID1, ID2 $1023 - $1024 track, sector $1025 - $1026 checksum, OFF byte $1027 - $1028 spare 1, spare 2 1 $1029 - $102A ID1, ID2 $102B - $102C track, sector $102D - $102E checksum, OFF byte $102F - $1030 spare 1, spare 2 2 $1031 - $1032 ID1, ID2 $1033 - $1034 track, sector $1035 - $1036 checksum, OFF byte $1037 - $1038 spare 1, spare 2 3 $1039 - $103A ID1, ID2 $103B - $103C track, sector $103D - $103E checksum, OFF byte $103F - $1040 spare 1, spare 2 4 $1041 - $1042 ID1, ID2 $1043 - $1044 track, sector $1045 - $1046 checksum, OFF byte $1047 - $1048 spare 1, spare 2 5 $1049 - $104A ID1, ID2 $104B - $104C track, sector $104D - $104E checksum, OFF byte $104F - $1050 spare 1, spare 2 6 $1051 - $1052 ID1, ID2 $1053 - $1054 track, sector $1055 - $1056 checksum, OFF byte $1057 - $1058 spare 1, spare 2 7 $1059 - $105A ID1, ID2 $105B - $105C track, sector $105D - $105E checksum, OFF byte $105F - $1060 spare 1, spare 2 8 $1061 - $1062 ID1, ID2 $1063 - $1064 track, sector $1065 - $1066 checksum, OFF byte $1067 - $1068 spare 1, spare 2 9 $1069 - $106A ID1, ID2 $106B - $106C track, sector $106D - $106E checksum, OFF byte $106F - $1070 spare 1, spare 2 10 $1071 - $1072 ID1, ID2 $1073 - $1074 track, sector $1075 - $1076 checksum, OFF byte $1077 - $1078 spare 1, spare 2 11 $1079 - $107A ID1, ID2 $107B - $107C track, sector $107D - $107E checksum, OFF byte $107F - $1080 spare 1, spare 2 12 $1081 - $1082 ID1, ID2 $1083 - $1084 track, sector $1085 - $1086 checksum, OFF byte $1087 - $1088 spare 1, spare 2 13 $1089 - $108A ID1, ID2 $108B - $108C track, sector $108D - $108E checksum, OFF byte $108F - $1090 spare 1, spare 2 14 $1091 - $1092 ID1, ID2 $1093 - $1094 track, sector $1095 - $1096 checksum, OFF byte $1097 - $1098 spare 1, spare 2 Once the machine code instructions (data) have been written to the desired buffer, we must now tell the FDC controller what action is to be taken. If we wish the FDC controller to execute our instructions, we must make sure of the following: .all branch addresses must be set in accordance to the FDC buffers example: $1100 A9 40 LDA #$40 $1102 85 03 STA $03 $1104 A5 40 LDA $40 $1106 4C 00 05 JMP $0500 (not:JMP $1100) .HI byte of start address stored in JOB HEADER track byte .LO byte of start address stored in JOB HEADER sector byte It is easier to spot mistakes/bugs if you associate the JOB HEADER with its corresponding DATA BUFFER. Now that we have stored our data and set up the start address in the JOB HEADER table, we must now tell the FDC controller that there is a "JOB TO DO". The JOB QUEUE Now comes the DANGEROUS PART. Before going any further, I wish to stress the following point: YOU ARE NOW CONTROLLING THE VERY HEART OF THE 4040 DUAL DRIVE MAKE SURE TO CALCULATE AND VERIFY ALL YOUR INSTRUCTIONS, YOU ARE BY-PASSING ALL THE DOS PROTECTION. ALL COMMAND REQUESTS YOU HAVE INSTRUCTED WILL BE PERFORMED WITHOUT VERIFICATION OF SYNTAX AND PHYSICAL POSSIBILITY. Before continuing, re-read the above paragraph. You must realize that the FDC controller will listen to all your instructions. Should your instructions be harmfull to the physical parts of the 4040 dual drive, no preventive actions will be taken to stop them; unless they are implemented within your machine code instructions (data). Let's continue. There are seven (7) pre-set operations within the FDC controller. These are: JOB CODE (decimal) LABEL DESCRIPTION $80 (128) READ Read track & sector specified by header into data buffer $90 (144) WRITE Write track & sector specified by header from data buffer $A0 (160) VERIFY Compare track & sector specified by header with data buffer $B0 (176) SEEK Find any header on track specified by header, put in data buffer $C0 (192) BUMP Track must be set to: 1, positions head to track 1 $D0 (208) JUMP Jump to user ML CODE in data buffer $E0 (224) EXECUTE Same as JUMP with head in position and drive at speed The JOB QUE begins at location $1003 and goes 14 bytes (ending at: $1011) for a total of 14 JOB QUEUES for 14 JOB HEADERS and 14 DATA BUFFERS. When the FDC controller has finished the requested job, bit 7 is masked off and the status is stored back into the JOB QUE where the command originated from. This status is used to generate the appropriate error message. FDC CODE IEEE CODE DESCRIPTION 1 00 OK 2 20 HEADER BLOCK NOT FOUND 3 21 NO SYNC CHARACTER 4 22 DATA BLOCK NOT FOUND 5 23 CHECKSUM ERROR IN DATA BLOCK 6 24 BYTE DECODING ERROR 7 25 VERIFY ERROR 8 26 WRITE PROTECT SENSE ON 9 27 CHECKSUM ERROR IN HEADER BLOCK A 28 LONG DATA BLOCK B 29 DISK ID MISMATCH To pass control over to the FDC Controller, you must place one of the JOB CODES in the JOB QUE corresponding to its JOB HEADER table. At this point, the FDC Controller will perform the desired action. When the requested function is completed, the FDC Controller will return the ERROR STATUS. This FDC CODE will be stored in the JOB QUE. In order to check if the job requested is completed, simply read the value found in the JOB QUE. If it is above decimal value 128, then the job has not yet been completed. If it is below decimal value 128, then the job is completed and the value returned is the ERROR STATUS. 6.6 - TROUBLE SHOOTING (HARDWARE) Over the years, it will become more and more difficult to find a COMMODORE service depot who will be capable of servicing the 4040 dual drive. Because of this, I have decided to add this section. Hopefully it can help the service technician in locating any problems. Disk LED error diagnostics Number of flashes Error Cause Component/location 1 Zero Page 6532/C1, E1 2 ROM H1 3 ROM L1 4 ROM J1 5 Zero Page 6530/K3 6504/H3 6 N/A 7 RAM 2114/D4, D5 8 RAM 2114/E4, E5 9 RAM 2144/F4, F5 10 ROM 6530/K3 6504/H3 Power supply The power supply on the 4040 dual drive is composed of three (3) voltage regulators. These are: VR1 & VR2: 12 volt regulators, one per drive VR3 : 5 volt regulator for the rest of the unit Service hints Some other common problems are sometimes located on the ANALOG board. Below is compilation of the most common problems found on the 4040 dual drive. Symptom Solution 1. Drive #0 has read errors. Adjust speed pot by use of: a. "SPEED VARIATION" program b. adjustment screw on small block located on circuit board behind drive chassis. 2. Drive #1 has read errors. Adjust speed pot by use of: a. "SPEED VARIATION" program b. adjustment screw on small block located on circuit board behind drive chassis. 3. Drive #1 loads and Drive #0 not Check transistors on analog: loading. Q5, Q6, Q7, Q8. 4. Drive #0 loads and Drive #1 not Check transistors on analog: loading. Q1, Q2, Q3, Q4. 5. Initializes by itself after warm-up. Check IC Chip #6504 (UH3). 6. Drive motor does not run. Check drive belt. The following chart may be used as a specifications sheet. HARDWARE MODEL: Drives per unit : 2 Heads per drive : 1 FORMATTED STORAGE: Capacity per unit : 340 KB Maximum SEQuential files per drive : 168 KB Maximum RELative files per drive : 168 KB Disk system buffer : 4 KB DISK FORMATS: Tracks : 35 Sectors per track : 17-21 Bytes per sector : 256 Blocks free per unit : 1328 TRANSFER RATES (BYTES PER SECOND): Internal to unit : 40 KB IEEE-488 bus : 1.2 KB ACCESS TIMES (MILLI-SECONDS): Track to track : 30 Average track : 360 Average latency : 100 Rpm : 300 PHYSICAL DIMENSIONS: Height (inches) : 7.0 Width (inches) : 15.0 Depth (inches) : 13.75 Weight (pounds) : 28 ELECTRICAL: Power (watts) : 50 Voltage : 110-120 VAC. Frequency : 60 Hz
Chapter 7 - IEEE software controller (MOS 6502)
4040 IEEE controller RAM usage ZERO page ($0000 - $002C) CONTENT AT LOCATION POWER UP LABEL DESCRIPTION ---------------------------------------------------------------------------- $0000 EA USRJMP User jump table LO byte pointer $0001 FF User jump table HI byte pointer $0002 00 BMPNT Bit map pointer $0003 00 Bit map pointer $0004 04 TEMP: T0 Temp work space - CMD jump table $0005 00 T1 $0006 00 T2 $0007 09 T3 $0008 00 T4 $0009 00 $000A 00 IP Indirect pointer variable $000B 40 $000C 28 LSNADR Listen address: DEVICE + #$20 $000D 48 TLKADR Talker address: DEVICE + #$40 $000E 00 LSNACT Active listener flag $000F 00 TLKACT Active talker flag $0010 00 ADRSED Addressed flag $0011 11 PRGTRK Last program accessed $0012 00 DRVNUM Current drive number $0013 00 TRACK Current track $0014 00 SECTOR Current sector $0015 06 LINDX Logical index $0016 0F SA Current secondary address $0017 6F ORGSA Original secondary address $0018 3F DATA Temporary data byte $0019 00 TEMP: R0 Temp work area $001A 00 R1 $001B 00 R2 $001C 00 R3 $001D 00 R4 $001E 00 RESULT Result of multiply/divide $001F 00 $0020 00 $0021 00 $0022 00 ACCUM Remainder of multiply/divide $0023 00 $0024 00 $0025 00 $0026 00 $0027 05 DIRBUF Directory buffer LO byte pointer $0028 43 Directory buffer HI byte pointer $0029 00 BUFTAB: 0 Buffer # 0 LO byte pointer $002A 11 Buffer # 0 HI byte pointer $002B 00 BUFTAB: 1 Buffer # 1 LO byte pointer $002C 12 Buffer # 1 HI byte pointer 4040 IEEE controller RAM usage (continued) ZERO page ($002D - $0059) CONTENT AT LOCATION POWER UP LABEL DESCRIPTION ---------------------------------------------------------------------------- $002D 00 BUFTAB: 2 Buffer # 2 LO byte pointer $002E 13 Buffer # 2 HI byte pointer $002F 00 BUFTAB: 3 Buffer # 3 LO byte pointer $0030 20 Buffer # 3 HI byte pointer $0031 00 BUFTAB: 4 Buffer # 4 LO byte pointer $0032 21 Buffer # 4 HI byte pointer $0033 00 BUFTAB: 5 Buffer # 5 LO byte pointer $0034 22 Buffer # 5 HI byte pointer $0035 00 BUFTAB: 6 Buffer # 6 LO byte pointer $0036 23 Buffer # 6 HI byte pointer $0037 00 BUFTAB: 7 Buffer # 7 LO byte pointer $0038 30 Buffer # 7 HI byte pointer $0039 00 BUFTAB: 8 Buffer # 8 LO byte pointer $003A 31 Buffer # 8 HI byte pointer $003B 00 BUFTAB: 9 Buffer # 9 LO byte pointer $003C 31 Buffer # 9 HI byte pointer $003D 00 BUFTAB: 10 Buffer #10 LO byte pointer $003E 31 Buffer #10 HI byte pointer $003F 00 BUFTAB: 11 Buffer #11 LO byte pointer $0040 40 Buffer #11 HI byte pointer $0041 00 BAM drive # 0 LO byte pointer $0042 41 BAM drive # 0 HI byte pointer $0043 00 BAM drive # 1 LO byte pointer $0044 42 BAM drive # 1 HI byte pointer $0045 00 Command buffer LO byte pointer $0046 43 Command buffer HI byte pointer $0047 DD Error output buffer LO byte pointer $0048 43 Error output buffer HI byte pointer $0049 FF BUF0 Inactive flags for buffer (bit 7=1) $004A FF $004B FF $004C FF $004D FF $004E FF $004F 0E $0050 0F $0051 FF BUF1 Inactive flags for buffer (bit 7=1) $0052 FF $0053 FF $0054 FF $0055 FF $0056 FF $0057 FF $0058 FF $0059 00 NBKL Number of blocks low
4040 IEEE controller RAM usage (continued) ZERO page ($005A - $0086) CONTENT AT LOCATION POWER UP LABEL DESCRIPTION ---------------------------------------------------------------------------- $005A 00 RECL Low record number to find REL file $005B 00 $005C 00 $005D 00 $005E 00 $005F 00 $0060 00 $0061 00 NBKH Number of blocks high $0062 00 RECH High record number to find REL file $0063 00 $0064 00 $0065 00 $0066 00 $0067 00 $0068 00 $0069 00 NR Next record table $006A 00 $006B 00 $006C 00 $006D 00 TRACK Current track $006E 00 $006F 06 LINDX Logical index $0070 00 $0071 00 RS Relative record size table $0072 00 $0073 00 $0074 00 $0075 00 $0076 00 $0077 00 $0078 00 $0079 FF SS Side sector table $007A FF $007B FF $007C FF $007D FF $007E FF $007F FF $0080 FF $0081 00 F1PTR File stream 1 pointer $0082 00 RECPTR 1st byte wanted from REL file $0083 00 SSNUM Side sector number of REL record $0084 00 SSIND Index into side sector $0085 00 RELPTR Pointer to 1st byte wanted in REL $0086 00 FILENT Directory entry (bit: IIIS SSSS) 4040 IEEE controller RAM usage (continued) ZERO page ($0087 - $00A5) CONTENT AT LOCATION POWER UP LABEL DESCRIPTION ---------------------------------------------------------------------------- $0087 00 $0088 00 $0089 00 $008A 00 $008B 00 FILDAT File data (bit 7=1: search both drives) $008C 00 $008D 00 $008E 00 $008F 00 $0090 00 FILTYP Channel file type (bit 7=1: search both drives) SEQ = type 1 PRG = type 2 USR = type 3 REL = type 4 direct = type 7 $0091 00 $0092 00 $0093 00 $0094 00 $0095 00 $0096 00 $0097 00 CHNDRY Channel status bit: 7=1 (talk) 3=0 (send EOI, talker only) 0=1 (listen) $0098 00 $0099 00 $009A 00 $009B 00 $009C 00 $009D 00 $009E 01 $009F 88 $00A0 20 EOIFLG Temporary EOI $00A1 00 JOBNUM Current job number $00A2 FF LINTAB Logical index table bit 7&6: 00 = read channel 10 = write channel 01 = read/write channel 11 = no channel $00A3 FF $00A4 FF $00A5 FF
4040 IEEE controller RAM usage (continued) ZERO page ($00A6 - $00D3) CONTENT AT LOCATION POWER UP LABEL DESCRIPTION ---------------------------------------------------------------------------- $00A6 FF $00A7 FF $00A8 FF $00A9 FF $00AA FF $00AB FF $00AC FF $00AD FF $00AE FF $00AF FF $00B0 FF $00B1 86 $00B2 07 $00B3 FF $00B4 FF $00B5 00 CHNDAT Channel data byte $00B6 00 $00B7 00 $00B8 00 $00B9 00 $00BA 00 $00BB 00 $00BC 30 $00BD 00 LSTCHR Channel last character pointer $00BE 00 $00BF 00 $00C0 00 $00C1 00 $00C2 00 $00C3 00 $00C4 E7 $00C5 00 TYPE Active file type $00C6 00 NOTUSED $00C6 - $00FF not used by DOS $00C7 00 $00C8 00 $00C9 00 $00CA 00 $00CB 00 $00CD 00 $00CE 00 $00CF 00 $00D0 00 $00D1 00 $00D2 00 $00D3 00 4040 IEEE controller RAM usage (continued) ZERO page ($00D4 - $00FF) CONTENT AT LOCATION POWER UP LABEL DESCRIPTION ---------------------------------------------------------------------------- $00D4 00 $00D5 00 $00D6 00 $00D7 00 $00D8 00 $00DA 00 $00DB 00 $00DC 00 $00DD 00 $00DE 00 $00DF 00 $00F0 00 $00F1 00 $00F2 00 $00F3 00 $00F4 00 $00F5 00 $00F6 C8 $00F7 B9 $00F8 C8 $00F9 D9 $00FA 0D $00FB DA $00FC 6D $00FD DB $00FE B7 $00FF D4
4040 IEEE controller RAM usage RAM memory ($0100 - $1017) LOCATION LABEL DESCRIPTION ---------------------------------------------------------------------------- $0100 - $01FF The stack $0200 IEEEDI IEEE data in $0201 PADDI IEEE data in direction $0202 IEEED0 IEEE data out $0203 PADDI IEEE data out direction $0204 $0205 $0206 $0207 $0208 - $027F $0280 PAD2 IEEE control port: ** $0281 PADD2 ** $0282 PBD2 ** $0283 PBDD2 ** $0284 ATNND ** ATN is IRQ causing ?? $0285 ATNPD ** $0286 ATNNE ** $0287 ATNPE ** $0288 - $0FFF Unconnected $1000 ID Interrupt delay (** start of shared memory **) $1001 Motor acceleration delay $1002 Motor cutoff time $1003 JOBS que Buffer # 0 $1004 Buffer # 1 $1005 Buffer # 2 $1006 Buffer # 3 $1007 Buffer # 4 $1008 Buffer # 5 $1009 Buffer # 6 $100A Buffer # 7 $100B Buffer # 8 $100C Buffer # 9 $100D Buffer #10 $100E Buffer #11 $100F Buffer #12 $1010 Buffer #13 $1011 Buffer #14 $1012 TRKS Job's track number $1013 $1014 $1015 $1016 $1017 4040 IEEE controller RAM usage (continued) RAM memory ($1018 - $1074) LOCATION LABEL DESCRIPTION ---------------------------------------------------------------------------- $1018 $1019 $1020 $1021 - $1022 JOBHDR0 Buffer # 0: ID1 , ID2 $1023 - $1024 track , sector $1025 - $1026 checksum, off $1027 - $1028 spare1 , spare2 $1029 - $102A JOBHDR1 Buffer # 1: ID1 , ID2 $102B - $102C track , sector $102D - $102E checksum, off $102F - $1030 spare1 , spare2 $1031 - $1032 JOBHDR2 Buffer # 2: ID1 , ID2 $1033 - $1034 track , sector $1035 - $1036 checksum, off $1037 - $1038 spare1 , spare2 $1039 - $103A JOBHDR3 Buffer # 3: ID1 , ID2 $103B - $103C track , sector $103D - $103E checksum, off $103F - $1040 spare1 , spare2 $1041 - $1042 JOBHDR4 Buffer # 4: ID1 , ID2 $1043 - $1044 track , sector $1045 - $1046 checksum, off $1047 - $1048 spare1 , spare2 $1049 - $104A JOBHDR5 Buffer # 5: ID1 , ID2 $104B - $104C track , sector $104D - $104E checksum, off $104F - $1050 spare1 , spare2 $1051 - $1052 JOBHDR6 Buffer # 6: ID1 , ID2 $1053 - $1054 track , sector $1055 - $1056 checksum, off $1057 - $1058 spare1 , spare2 $1059 - $105A JOBHDR7 Buffer # 7: ID1 , ID2 $105B - $105C track , sector $105D - $105E checksum, off $105F - $1060 spare1 , spare2 $1061 - $1062 JOBHDR8 Buffer # 8: ID1 , ID2 $1063 - $1064 track , sector $1065 - $1066 checksum, off $1067 - $1068 spare1 , spare2 $1069 - $106A JOBHDR9 Buffer # 9: ID1 , ID2 $106B - $106C track , sector $106D - $106E checksum, off $106F - $1070 spare1 , spare2 $1071 - $1072 JOBHDR10 Buffer #10: ID1 , ID2 $1073 - $1074 track , sector
4040 IEEE controller RAM usage (continued) RAM memory ($1075 - $31FF) LOCATION LABEL DESCRIPTION ---------------------------------------------------------------------------- $1075 - $1076 checksum, off $1077 - $1078 spare1 , spare2 $1079 - $107A JOBHDR11 Buffer #11: ID1 , ID2 $107B - $107C track , sector $107D - $107E checksum, off $107F - $1080 spare1 , spare2 $1081 - $1082 JOBHDR12 Buffer #12: ID1 , ID2 $1083 - $1084 track , sector $1085 - $1086 checksum, off $1087 - $1088 spare1 , spare2 $1089 - $108A JOBHDR13 Buffer #13: ID1 , ID2 $108B - $108C track , sector $108D - $108E checksum, off $108F - $1090 spare1 , spare2 $1091 - $1092 JOBHDR14 Buffer #14: ID1 , ID2 $1093 - $1094 track , sector $1095 - $1096 checksum, off $1097 - $1098 spare1 , spare2 $1099 NUMSEC Number of sectors per track group $109A $109B $109C $109D GAP1 Gap spacing one (default: #$09) $109E GAP2 Gap spacing two (default: #$02) $109F VERNUM Dos version number (default: #$41) $10A0 ACTJOB Controller's active job $10A1 - $10EF Not used $10F0 - $10F1 VNMI Indirect pointer for NMI vector $10F2 NMIFLG NMI in progress flag $10F3 AUTOFG Automatic drive initialization flag $10F4 - $10FF Unused RAM $1100 - $11FF BUF0 Data buffer # 0 $1200 - $12FF BUF1 Data buffer # 1 $1300 - $13FF BUF2 Data buffer # 2 $1400 - $1CFF Unconnected $1D00 - $1FFF FBUF Format download area $2000 - $20FF BUF3 Data buffer # 3 $2100 - $21FF BUF4 Data buffer # 4 $2200 - $22FF BUF5 Data buffer # 5 $2300 - $23FF BUF6 Data buffer # 6 $2400 - $2FFF Unconnected $3000 - $30FF BUF7 Data buffer # 7 $3100 - $31FF BUF8 Data buffer # 8 4040 IEEE controller RAM usage (continued) RAM memory ($3200 - $437F) LOCATION LABEL DESCRIPTION ---------------------------------------------------------------------------- $3200 - $32FF BUF9 Data buffer # 9 $3300 - $33FF BUF10 Data buffer #10 $3400 - $3FFF Unconnected $4000 - $40FF BUF11 Data buffer #11 $4100 - $41B3 BAM0 BAM drive zero $41B4 - $41FF NAMBUF Directory buffer $4200 - $42B3 BAM1 BAM drive one $42B4 - $42FF Not used $4300 - $4339 CMDBUF Command buffer $433A STRSIZ String size in command buffer $433B TEMPSA Temporary secondary address $433C CMD Temporary job command $433D LSTSEC Last sector $433E - $433F BUFUSE Available buffers (bit = 1 if used buffer) $4340 - $4341 DSKID Current disk id - drive 0 $4342 - $4343 Current disk id - drive 1 $4344 SECINC Sector increment for sequential files $4345 ENTFND Directory entry found flag $4346 DIRLST Directory listing flag $4347 CMDWAT Command waiting flag $4348 LINUSE Available logical index (bit 1: used = 1) ( 6: command channel) ( 7: error channel) $4349 LBUSED Last buffer used $434A ERBLKS Number of blocks before abort $434B REC Record size $434C TRKSS Track of side sector $434D SECSS Sector of side sector $434E - $435B LSTJOB Last job entered in job que $435C REVCNT Error recovery count (default: #$0A) $435D - $436A ERRCNT Error count for job que $436B - $4372 DIRENT Directory entry associated with channel $4373 ERWORD Error word for recovery $4374 PRGSEC Last program sector $4375 WLINDX Write logical index $4376 RLINDX Read logical index $4377 NBTEMP Number of blocks temporary $4378 $4379 CMDSIZ Length of command string + 1 $437A CMDNUM Command number $437B CHAR Character under parser $437C LIMIT Pointer limit in compare $437D F1CNT File stream 1 count $437E F2CNT File stream 2 count $437F F3PTR File stream 3 count
4040 IEEE controller RAM usage (continued) RAM memory ($4380 - $CFFF) LOCATION LABEL DESCRIPTION ---------------------------------------------------------------------------- $4380 - $4385 FILTBL Table of filename positions in CMDBUF $4386 - $438A FILTRK Track of 1st block during search (bit 7=1 to indicated that pattern match) $438B - $438F FILSEC Sector of 1st block during search $4390 PATFLG Pattern presence flag $4391 IMAGE File stream image $4392 DRVCNT Number of drive searches $4393 DRVFLG Drive search flag $4394 LSTDRV Last drive without error $4395 FOUND Found flag in directory searches $4396 DIRSEC Directory sector $4397 DELSEC Sector of 1st available entry $4398 DELIND Index of 1st available entry $4399 LSTBUF Last block (equal to 0) $439A INDEX Current index in buffer $439B FILCNT Counter, file entries $439C TYPFLG Match by type flag $439D MODE Active file mode (Read/Write) $439E JOBRTN Job return flag $439F - $43DB Unused $43DC - $43FF ERRBUF Error message buffer $4400 - $CFFF Unconnected
4040 IEEE controller MAP Code from $D000 - $D730 LOCATION DESCRIPTION --------------------------------------------------------------------------- $D000 Format code $D2A0 Checksum byte for $D000 $D2A1 Command search table: 'ivdmbupcrsn' $D2AC Command jump table (LO bytes) $D2B7 Command jump table (HI bytes) $D2C2 Structure images for commands $D2C7 Track group table $D2CB Mode table $D2CF File type table $D2D4 1st character in name of file type $D2D9 2nd character in name of file type $D2DE 3rd character in name of file type $D2E3 Error flag variables $D2E8 BAM buffer pointer (HI bytes) $D2EA Sectors per track table (4040) $D2EE Disk & sector definition bytes (4040) $D2F1 Sectors per track table (3040) $D2F5 Disk & sector definition bytes (3040) $D2F8 Controller: jump to wait loop $D301 Error display routine $D32B Initialize disk for: Power Up Diagnostics $D348 Fill ZERO PAGE ascending pattern $D34E Test ZERO PAGE $D362 Test three 64K-bit roms $D3A0 Test all common ram pages $2000-$5000 $D3DC Diagnostics ok so far: test device number $D3F4 Initialize buffer pointer table $D46B Set up sector/track table depending on controller used $D47A Controller error $D47F Set up sectors/track, GAP1, dos version, format version $D48D Set up power on message "CBM DOS V2.1" $D492 Bump heads to track 1 $D4A6 Idle loop: does housekeeping while waiting for job $D50A ATN irq process: IRQ on ATN, listen to PET, clear stack $D549 Decide: secondary address, talk, listen, other $D5CF Set listen routine: main routine $D65C Listen routine $D65F Set talk routine: main routine $D66B From TALK: no talk = rts $D69B Talk routine $D6AF Return next available track and sector $D6DE Disk full error $D6E3 Find an available track $D6F5 Find next optimum sector on track $D72B Directory error $D730 Test for free sectors, else indicate track as used Code from $D73E - $D9C9 LOCATION DESCRIPTION --------------------------------------------------------------------------- $D73E Test lower & upper track ranges for free sectors $D75E Disk full error $D763 Find sector $D778 Directory error $D77D Mark current track as full $D78C Read sector map from BAM $D7B4 Test for available sectors on current track $D7CA Directory error $D7D2 Number of sectors for specific track table $D7DE Sectors per track group table $D7E2 OK error message $D7E6 READ error message $D7F1 FILE TOO LARGE error message $D7FD RECORD NOT PRESENT error message $D808 OVERFLOW IN RECORD error message $D815 WRITE error message $D819 WRITE PROTECT ON error message $D826 DISK ID MISMATCH error message $D82C SYNTAX error message $D838 WRITE FILE OPEN error message $D83C FILE EXISTS error message $D845 FILE TYPE MISMATCH error message $D84D NO BLOCK error message $D856 ILLEGAL TRACK & SECTOR error message $D86F FILE NOT OPEN error message $D873 FILE NOT FOUND error message $D877 FILE'S SCRATCHED error message $D884 NO CHANNEL error message $D88F DIRECTORY error message $D894 DISK FULL error message $D89B DOS MISMATCH error message $D8A6 Token word: ERROR $D8AC Token word: WRITE $D8B2 Token word: FILE $D8B7 Token word: OPEN $D8BC Token word: MISMATCH $D8C5 Token word: NOT $D8C9 Token word: FOUND $D8CF Token word: DISK $D8D4 Token word: RECORD $D8DB Transfer error message to error buffer $D8E6 Test begin/end of error message $D907 Transfer TOKEN to error message buffer $D91C Controller error entry point $D952 Process error $D956 Clear command buffer, set LED's $D970 Talker error recovery $D990 Listener error recovery $D9A8 Convert HEX to BCD $D9B7 Convert BCD to ASCII $D9C9 Set for OK error message
Code from $D9D4 - $E254 LOCATION DESCRIPTION --------------------------------------------------------------------------- $D9D4 Set up error message in error buffer $DA13 Mark a sector as free on a track in BAM $DA2C Turn on activity LED specified by drive $DA42 Turn off error LED $DA4B Directory loading function, get buffer and start it $DACF Build last line of directory $DB03 Transmit directory line to current buffer $DB11 Get byte from directory $DB2E Calculate number of free blocks $DB55 Parse and execute command string in command buffer $DB99 Successful command termination $DBA1 Clear command buffer $DBB8 Clear command input buffer $DBC3 Command level error processing $DBCE Simple parser routine $DBE0 Parse colon $DBE9 Set up command structure image and file stream pointer $DC63 Look for special characters $DCB0 Set all flags and look at command string $DCD9 Command reset: clear variables, tables $DD0A Set 1st drive and table pointers $DD1B Set drive number $DD34 Get drive number from command string $DD5E Set drive from any configuration $DD86 Toggle drive number $DD8F Set pointer to one file stream and check type $DDB5 Test drive number validity $DDC2 Auto initialization routine $DE07 Optimum search for lookup and find file $DE61 Search table $DE70 Lookup files in stream and fill tables with information $DE83 Toggle to lookup other drive $DEAD Find next file name matching any file in stream $DED7 Find directory entry and file type $DEFA Compare file names in stream table with the disk directory $DFAF Check table of unfound files $DFD0 Search directory: returns with valid entry $E039 Continue file entry search $E05F Transfer filename from command buffer $E079 Transfer command buffer to other buffer $E097 Find limit of string in command buffer $E0BF Get file entry from directory $E0CF Get directory entry $E19F Clear name buffer $E1AA New directory listing $E1F0 Display BLOCKS FREE. message $E201 BLOCKS FREE. message $E20D Command: NEW (format diskette) $E245 Initialize drive with version number $E254 Initialize track 18, 0 and track 18, 1 Code from $E2B7 - $E8F7 LOCATION DESCRIPTION --------------------------------------------------------------------------- $E2B7 Command: SCRATCH (erase files) $E313 Delete file by links $E33B Delete directory entry $E346 Command: DUPLICATE (backup diskette) $E391 Copy blocks from source to destination drive $E3A9 Copy entire track from source to destination $E3B7 Transfer HEADER blocks to destination drive $E3D2 READ 10 sectors from source drive $E3F6 WRITE 10 sectors to destination drive $E416 Transfer format code to buffers 0,1 & 2, start formatting $E44A Command: COPY (transfer file(s) to other or same disk) $E46C Normal parse $E48F Indicate invalid command structure $E494 Test if copy type is normal $E49E Verify drive numbers for disk to disk copy $E4C5 Copy disk to disk routines $E4EE Pull needed variables from stack $E519 Push needed variables onto stack $E557 Transfer name from directory buffer to command buffer $E567 Set up drive number and file information $E587 Command: CONCAT (copy file(s) to one file) $E5D3 Check files for existence $E617 Open and set up internal read file $E657 Get byte from internal read channel $E675 Command: RENAME (give new name to a current file name) $E6BC Check if input file is on hand $E6D9 Check file for existence $E6EC Command: VALIDATE (create new BAM on disk) $E712 Record blocks in file onto BAM $E738 Verify if directory entry found is properly closed $E744 Record file entry links in new BAM $E76C Create new BAM for diskette $E7A7 Checksum byte for $E000 $E7A8 Command: MEMORY (direct access to DOS) $E7CD Command: MEMORY-READ (direct read from DOS) $E7F7 Indicate invalid command structure $E7FC Command: MEMORY-WRITE (direct write to DOS) $E808 User access commands $E81E Execute user jump code $E830 Open direct access buffer from OPEN "#" $E83E Indicate invalid channel structure $E843 Validate and set up requested buffer $E8AF Search for second character (-) in command string for BLOCK commands $E8BA Indicate invalid command structure $E8BF Indicate invalid command structure $E8C4 Decide which command is being requested $E8F1 BLOCK command summary $E8F7 BLOCK - command jump table
Code from $E903 - $ECDF LOCATION DESCRIPTION --------------------------------------------------------------------------- $E903 Get command parameters and test validity $E935 Convert ASCII to HEX and store conversion result $E95E Convert digit to binary by use of decimal table $E986 Decimal table $E989 Command: BLOCK - FREE $E992 BLOCK - ALLOCATE command $E9C3 No block available error $E9CA Test for block availability $E9D5 Test BLOCK - READ parameters and read sector in buffer $E9DB Get a byte from buffer $E9E1 Read sector from disk to buffer, initialize pointers $E9F5 Command: BLOCK - READ $E9FE Command: U1: (Block - read) $EA12 Command: BLOCK - WRITE $EA38 Command: U2: (Block - write) $EA44 Command: BLOCK - EXECUTE $EA58 Execute machine code at assigned jump address $EA5B Command: BLOCK - POINTER $EA70 Test for allocated buffer and open channel $EA90 Test block operation parameters $EAAE Find relative file $EACC Calculate record's location: TOTAL=RCRD# x SIZE + PNTR $EB0E Divide by #$FE (decimal 254) $EB11 Divide by #$78 (decimal 120) $EB13 Main division routine $EB79 Clear RESULT memory area $EB82 Multiply ACCUMULATION registers by 4 $EB85 Multiply ACCUMULATION registers by 2 $EB8D Add ACCUMULATION register to RESULT registers $EB9A Mark track, sector, BAM pointer as used $EBAF Test if requested block available $EBC9 Bit mask table for BAM calculations $EBD1 Double buffer: switch the active and inactive buffers $EBE6 Set internal write channel and test if command channel $EBF8 Main routine to write to a channel $EC0A Test if file type USR, if not write to REL file $EC0F Write to USR file, get next data byte $EC19 Set for maximum channel, test buffer pointer $EC2E Set command waiting flag $EC32 Test if job done. If not done continue $EC5B Retry current job .Y amount of times $EC76 Job done properly, restore .Y register to original value $EC7A Set last job executed back up for a retry $EC82 Test if job completed, clear job present flag when done $EC8F Set track, sector, ID for current buffer $ECB1 Test for valid buffer $ECBD Store byte in assigned buffer position $ECC5 Command: INITIALIZE (read BAM) $ECDF Set up job queue and locate track 18, sector 0 Code from $ECFA - $F07C LOCATION DESCRIPTION --------------------------------------------------------------------------- $ECFA Read BAM from diskette in current drive $ED1D Start double buffering, use track and sector to start $ED35 Begin double buffering $ED41 Set for READ job $ED45 Set for WRITE job $ED47 Perform requested job $ED69 Find internal read channel $ED84 Find internal write channel $EDA1 Get current file type $EDAB Set buffer pointers $EDB3 Read byte from active buffer $EDD2 Get byte from file and read next block if needed $EDE6 Read next block of file $EE0E Set last character position for last byte of file $EE19 Write a byte to channel and write buffer out when full $EE42 Increment pointer of active buffer $EE4F Set drive number indicated by last job in active buffer $EE5B Set for opening of new write channel $EE5E Set for opening of new read channel $EE5F Perform opening of desired channel $EE87 Indicate channel unavailability $EE8F De-allocate additional buffer $EE9F Test current secondary address for command channel $EEA6 Free read/write channels $EECA Release buffers and corresponding channel $EEFE Get free buffer number $EF29 Locate buffer to steal $EF34 Free buffer index $EF48 Clear all channels except COMMAND channel $EF54 Close all channels except COMMAND channel $EF79 Find a free logical index to use $EF8B Mark free logical index as used in table $EF95 Get a byte from a channel $EFA3 Read a byte over channel from any file type $EFAD Read a byte from file $EFC7 EOI received, set new channel status $EFCC Test if LOAD command received $EFD0 Test file type for random access $EFD7 Read byte from RELative file $EFF9 Read byte from SEQuential file $F001 Test if "DIRECTORY" issued read $F00C Get character from error channel $F02B Set bytes from error buffer to be output $F032 Set pointer for error message buffer $F03B Initialize error message channel $F044 Read next buffer of a file, follow links $F057 Entrance point for direct BLOCK - READ $F05B Entrance point for direct BLOCK - WRITE $F06C Open internal read channel (SA = 17) $F07C Open internal write channel (SA = 18)
Code from $F083 - $F655 LOCATION DESCRIPTION --------------------------------------------------------------------------- $F083 Allocate next directory block on track 18 and mark BAM $F0C1 Set new pointer position $F0D3 Free internal READ and WRITE channels $F0E1 Read active buffer pointer, set directory buffer $F0EF Direct byte read $F0FF HI bytes indexes for buffers $F10E Use last job for drive number and set job command $F116 Set job up and check track and sector $F155 Indicate track or sector unavailability $F15D Set track and sector from values in JOB HEADER memory $F16E Check track and sector validity $F180 Indicate invalid format version $F188 Determine error count and activate job $F19D Set job and test if completed $F1A9 Add file to directory $F1EA Find deleted entry in directory $F20E Write RELative file $F279 Open channel from IEEE, parse input string $F2B5 Test if LOAD directory command $F2C1 Open directory as a SEQuential file $F2D6 Test if direct access command $F2DD Initialize drive zero $F2EC Parse command string $F2FD Determine mode and file type for LOAD & SAVE $F36A Handle relative file $F395 Test if file exists, if not open write channel $F39F Check if file replacement command $F3AE Indicate invalid filename structure $F3B3 Command: REPLACE (overwrite file) $F3F9 Test if file exists in directory $F405 Test if MODIFY (#$03) mode requested $F417 Verify the requested directory entry file type $F425 Test if APPEND (#$02) mode requested $F45B Open a file for reading $F49B Open a file for writing $F4BF Check mode and file type $F4DF Append information to end of specified file $F509 Transmit directory ($) to computer $F536 Load directory from one drive $F55C Search by name on both drives $F58D Close file associated with secondary address $F59C Close channels associated with LOAD/SAVE $F5AC Close all files $F5BA Close specified secondary address channel $F5C3 Locate and close specific file type associated with secondary address $F5E3 Close a RELative file $F612 Close a write channel $F655 Write out BAM to the last active drive Code from $F671 - $FA94 LOCATION DESCRIPTION --------------------------------------------------------------------------- $F671 Verify that the BAM count matches the bits $F694 Write new BAM to diskette $F6A4 Directory close on open write file $F6E1 REPLACE current file data with new file data $F722 Set "FILE CLOSED" flag, write new block count $F747 Open internal read channel with 2 buffers $F780 Initialize all pointers including REL file pointers $F7A8 Set up SEQuential file $F7B4 Initialize variables for open channel $F7E6 Open internal write channel with 2 buffers $F808 Test for available side sector buffer $F821 Set up and write out side sector and data block $F898 Put byte into side sector $F8A0 Set/Clear file type flag $F8B1 Test file type flag status $F8B6 Test if write job $F8C2 Test for active files $F8D4 Test if directory entry matches secondary address entry $F8F4 Write out buffer if no longer current $F900 Put track and sector into buffer $F90F Get track and sector from buffer $F91C Set track link to #$00 and sector link to last character in current buffer $F92E Set up pointer to active buffer $F93E Read track and sector values from HEADER $F955 Job que: WRITE a buffer $F95C Job que: READ a buffer $F963 Job que: WRITE $F96A Job que: READ $F971 Job que: WRITE side sector $F978 Job que: READ side sector $F99A Set track and sector from link in buffer $F9AA Transfer bytes from one buffer to other $F9C6 Clear requested buffer $F9D7 Set side sector pointer $F9E1 Use side sector pointer to set directory buffer pointer $F9EE Set current directory buffer and buffer table $F9FD Test if side sector and index are within allowed range $FA17 Position directory buffer and buffer table $FA20 Indirect block read $FA26 Indirect block write $FA2A Perform block read/write $FA4A Get side sector pointers $FA51 Calculate side sectors $FA6B Test side sector number and side sector index for residence and range $FA7C Indicate side sector out of range $FA80 Test side sector status $FA90 Indicate side sector out of range $FA94 Indicate side sector not resident
Code from $FA98 - $FEBE LOCATION DESCRIPTION --------------------------------------------------------------------------- $FA98 Get active buffer number $FAA3 Get active buffer number and set last buffer used $FABC Mark end of record then move on to next record $FB16 Store current pointer value in buffer and set new pointer value $FB20 Set pointer to last record $FB28 Set up next record in buffer $FB49 Test if last data block in file $FB68 Write relative data into buffer $FB8F Test if end of buffer. If not, set up next record in buffer $FB97 Write record to data buffer $FBA8 Test if overflow error and set up next record $FBC2 Test for last record flag and EOI status $FBCB Add new relative record to file and write data byte $FBDC Fill balance of relative record with #$00 $FBEE Set flag to indicate that buffer needs to be updated on disk $FBF9 Clear flag indicating that buffer needs to be updated on disk $FC04 Get byte from relative record $FC36 Set channel status to EOI (End Or Identify) $FC3C Read last byte in record and proceed to next record in file $FC47 Send end of record marker, indicate RECORD NOT PRESENT $FC56 Set pointer to last character in record $FC84 Test for last non-zero character in buffer $FC98 Find last non-zero character in record $FCAE Indicate last non-zero character as present $FCB1 Position side sector and buffer table to end of last record $FCE8 Indicate illegal track or sector $FCED Command: POSITION (move to new location in relative file) $FD4B Move to desired record and test if request valid $FD58 Indicate desired record requested valid $FD5B Position relative data block into active buffer and next block into inactive buffer $FD6F Position pointer to desired record, move to next record if necessary $FD7D Position proper data blocks into buffers $FDAC Set current track and sector and begin double buffering $FDBD Check if required block is in buffer $FDC9 Test if desired sector has been reached $FDCF Set null records in active buffer for extension $FDF1 Add next record to record size $FE05 Adjust pointer to compensate for link $FE09 Add blocks to relative file $FEB2 Mark current block as last one in file $FEBE Chain through file and set side sectors Code from $FF2E - $FFFF LOCATION DESCRIPTION --------------------------------------------------------------------------- $FF2E Indicate record not present $FF38 Generate new side sector and fix previous side sector to reflect new side sector $FF96 Revise previous side sector to reflect newly added side sector $FFBB Write side sector and update next one if needed $FFE6 Versatile non maskable interrupt $FFE9 Checksum byte for $F000 $FFEA .word BLKRD : block-read $FFEC .word BLKWRT: block-write $FFEE User command to buffer #02 $FFFA .word NMI: Non-maskable interrupt $FFFC .word DISKINIT: power-up $FFFE .word ATN/IRQ process
4040 IEEE disk ROM map ******************************* Format code. See CHAPTER 8 for detailed dissassembly D000 A5 1A LDA $1A D002 10 2F BPL $D033 D004 78 SEI D005 A9 C1 LDA #$C1 D007 95 03 STA $03,X D009 A9 0F LDA #$0F D00B 3D 9A 07 AND $079A,X D00E 05 40 ORA $40 D010 85 40 STA $40 D012 A9 8C LDA #$8C D014 95 05 STA $05,X D016 58 CLI D017 B5 05 LDA $05,X D019 D0 FC BNE $D017 D01B 98 TYA D01C 0A ASL D01D 0A ASL D01E 0A ASL D01F 18 CLC D020 69 21 ADC #$21 D022 85 18 STA $18 D024 A0 00 LDY #$00 D026 84 1D STY $1D D028 C8 INY D029 84 1A STY $1A D02B 20 65 07 JSR $0765 D02E A4 1F LDY $1F D030 6C 00 FC JMP ($FC00) D033 A0 02 LDY #$02 D035 51 18 EOR ($18),Y D037 D0 F2 BNE $D02B D039 A9 00 LDA #$00 D03B 85 1D STA $1D D03D 78 SEI D03E 20 65 07 JSR $0765 D041 A9 08 LDA #$08 D043 25 82 AND $82 D045 F0 03 BEQ $D04A D047 4C 84 06 JMP $0684 D04A 20 80 07 JSR $0780 D04D A2 FF LDX #$FF D04F A9 DA LDA #$DA D051 20 2E 07 JSR $072E D054 85 4C STA $4C D056 20 2E 07 JSR $072E D059 20 2E 07 JSR $072E D05C A9 DC LDA #$DC D05E 20 2E 07 JSR $072E D061 A2 0F LDX #$0F D063 20 2E 07 JSR $072E D066 85 4C STA $4C D068 20 0D 07 JSR $070D D06B 20 3E 07 JSR $073E D06E 20 37 07 JSR $0737 D071 C9 0F CMP #$0F D073 F0 03 BEQ $D078 D075 4C 82 06 JMP $0682 D078 A9 11 LDA #$11 D07A 18 CLC D07B 6D 9D 04 ADC $049D D07E 85 0A STA $0A D080 A6 15 LDX $15 D082 A0 00 LDY #$00 D084 A9 00 LDA #$00 D086 18 CLC D087 65 0A ADC $0A D089 90 01 BCC $D08C D08B C8 INY D08C C8 INY D08D CA DEX D08E D0 F6 BNE $D086 D090 49 FF EOR #$FF D092 38 SEC D093 69 00 ADC #$00 D095 18 CLC D096 6D A0 07 ADC $07A0 D099 B0 03 BCS $D09E D09B CE 9F 07 DEC $079F D09E AA TAX D09F 98 TYA D0A0 49 FF EOR #$FF D0A2 38 SEC D0A3 69 00 ADC #$00 D0A5 18 CLC D0A6 6D 9F 07 ADC $079F D0A9 10 03 BPL $D0AE D0AB 4C 82 06 JMP $0682 D0AE A8 TAY D0AF 8A TXA D0B0 A2 00 LDX #$00 D0B2 38 SEC D0B3 E5 15 SBC $15 D0B5 B0 03 BCS $D0BA D0B7 88 DEY D0B8 30 03 BMI $D0BD D0BA E8 INX D0BB D0 F5 BNE $D0B2 D0BD 86 0A STX $0A D0BF EC 9E 04 CPX $049E D0C2 B0 03 BCS $D0C7 D0C4 4C 82 06 JMP $0682 D0C7 18 CLC D0C8 65 15 ADC $15 D0CA 8D 9E 07 STA $079E D0CD 20 80 07 JSR $0780 D0D0 A9 DE LDA #$DE D0D2 A2 FF LDX #$FF D0DC 20 2E 07 JSR $072E D0DF A9 DC LDA #$DC D0E1 20 2E 07 JSR $072E D0E4 A2 08 LDX #$08 D0E6 20 2E 07 JSR $072E D0E9 85 4C STA $4C D0EB A2 FF LDX #$FF D0ED AD 9D 07 LDA $079D D0F0 24 4D BIT $4D D0F2 10 FC BPL $D0F0 D0F4 85 80 STA $80 D0F6 24 41 BIT $41 D0F8 4D 9C 07 EOR $079C D0FB AC 9C 07 LDY $079C D0FE EE 9C 07 INC $079C D101 24 4D BIT $4D D103 10 FC BPL $D101 D105 84 80 STY $80 D107 24 41 BIT $41 D109 4D 9C 07 EOR $079C D10C 8D 9D 07 STA $079D D10F A0 02 LDY #$02 D111 B1 18 LDA ($18),Y D113 24 4D BIT $4D D115 10 FC BPL $D113 D117 85 80 STA $80 D119 24 41 BIT $41 D11B 88 DEY D11C 10 F3 BPL $D111 D11E A9 00 LDA #$00 D120 AC 9D 04 LDY $049D D123 24 4D BIT $4D D125 10 FC BPL $D123 D127 85 80 STA $80 D129 24 41 BIT $41 D12B 88 DEY D12C D0 F5 BNE $D123 D12E A9 DE LDA #$DE D130 20 2E 07 JSR $072E D133 85 4C STA $4C D135 20 2E 07 JSR $072E D138 20 2E 07 JSR $072E D13B A9 DC LDA #$DC D13D 20 2E 07 JSR $072E D140 A2 07 LDX #$07 D142 20 2E 07 JSR $072E D145 85 4C STA $4C D147 A0 00 LDY #$00 D149 A2 00 LDX #$00 D14B 24 4D BIT $4D D14D 10 FC BPL $D14B D14F 86 80 STX $80 D151 24 41 BIT $41 D153 88 DEY D154 D0 F5 BNE $D14B D156 A4 0A LDY $0A D158 20 2E 07 JSR $072E D15B 24 4D BIT $4D D15D 10 FC BPL $D15B D15F 86 80 STX $80 D161 24 41 BIT $41 D163 88 DEY D164 10 F5 BPL $D15B D166 AD 9C 07 LDA $079C D169 C5 15 CMP $15 D16B F0 03 BEQ $D170 D16D 4C D0 05 JMP $05D0 D170 20 0D 07 JSR $070D D173 A9 00 LDA #$00 D175 8D 9C 07 STA $079C D178 20 3E 07 JSR $073E D17B 20 37 07 JSR $0737 D17E C9 08 CMP #$08 D180 F0 0E BEQ $D190 D182 A9 0C LDA #$0C D184 58 CLI D185 E6 1D INC $1D D187 A0 0A LDY #$0A D189 C4 1D CPY $1D D18B F0 79 BEQ $D206 D18D 4C 3D 05 JMP $053D D190 20 37 07 JSR $0737 D193 8D 9D 07 STA $079D D196 20 37 07 JSR $0737 D199 CD 9C 07 CMP $079C D19C D0 E4 BNE $D182 D19E 4D 9D 07 EOR $079D D1A1 A0 02 LDY #$02 D1A3 24 4D BIT $4D D1A5 10 FC BPL $D1A3 D1A7 45 41 EOR $41 D1A9 88 DEY D1AA 10 F7 BPL $D1A3 D1AC A8 TAY D1AD D0 D3 BNE $D182 D1AF EE 9C 07 INC $079C D1B2 20 3E 07 JSR $073E D1B5 20 37 07 JSR $0737 D1B8 C9 07 CMP #$07 D1BA D0 C6 BNE $D182 D1BC A0 00 LDY #$00 D1BE 24 4D BIT $4D D1C0 10 FC BPL $D1BE D1C2 A5 41 LDA $41 D1C4 D0 BC BNE $D182 D1C6 88 DEY D1C7 D0 F5 BNE $D1BE D1C9 20 37 07 JSR $0737 D1CC D0 B4 BNE $D182 D1CE AD 9C 07 LDA $079C D1D1 C5 15 CMP $15 D1D3 D0 A3 BNE $D178 D1D5 20 3E 07 JSR $073E D1D8 AD 9F 07 LDA $079F D1DB F0 03 BEQ $D1E0 D1DD 4C 82 06 JMP $0682 D1E0 AD 9E 07 LDA $079E D1E3 38 SEC D1E4 65 0A ADC $0A D1E6 38 SEC D1E7 ED A0 07 SBC $07A0 D1EA 10 05 BPL $D1F1 D1EC 49 FF EOR #$FF D1EE 38 SEC D1EF 69 00 ADC #$00 D1F1 C9 1C CMP #$1C D1F3 90 03 BCC $D1F8 D1F5 4C 82 06 JMP $0682 D1F8 E6 1A INC $1A D1FA 58 CLI D1FB A9 24 LDA #$24 D1FD C5 1A CMP $1A D1FF F0 03 BEQ $D204 D201 4C 2B 05 JMP $052B D204 A9 01 LDA #$01 D206 A0 FF LDY #$FF D208 84 1A STY $1A D20A 6C 02 FC JMP ($FC02) D20D 20 2E 07 JSR $072E D210 24 4D BIT $4D D212 10 FC BPL $D210 D214 A9 FC LDA #$FC D216 85 4C STA $4C D218 A9 92 LDA #$92 D21A 85 4E STA $4E D21C A2 03 LDX #$03 D21E 20 37 07 JSR $0737 D221 24 40 BIT $40 D223 CA DEX D224 D0 F8 BNE $D21E D226 60 RTS D227 A0 10 LDY #$10 D229 84 4E STY $4E D22B 85 4C STA $4C D22D 60 RTS D22E 24 4D BIT $4D D230 10 FC BPL $D22E D232 86 80 STX $80 D234 24 41 BIT $41 D236 60 RTS D237 24 4D BIT $4D D239 10 FC BPL $D237 D23B A5 41 LDA $41 D23D 60 RTS D23E A0 00 LDY #$00 D240 8C 9F 07 STY $079F D243 24 82 BIT $82 D245 50 16 BVC $D25D D247 24 4D BIT $4D D249 10 F8 BPL $D243 D24B 24 41 BIT $41 D24D 24 40 BIT $40 D24F C8 INY D250 D0 F1 BNE $D243 D252 EE 9F 07 INC $079F D255 D0 03 BNE $D25A D257 4C 82 06 JMP $0682 D25A 4C 43 07 JMP $0743 D25D 8C A0 07 STY $07A0 D260 24 40 BIT $40 D262 24 41 BIT $41 D264 60 RTS D265 A0 02 LDY #$02 D267 A5 1A LDA $1A D269 91 18 STA ($18),Y D26B A9 00 LDA #$00 D26D 8D 9C 07 STA $079C D270 C8 INY D271 91 18 STA ($18),Y D273 51 18 EOR ($18),Y D275 88 DEY D276 10 FB BPL $D273 D278 8D 9D 07 STA $079D D27B A0 04 LDY #$04 D27D 91 18 STA ($18),Y D27F 60 RTS D280 A2 00 LDX #$00 D282 A0 00 LDY #$00 D284 A9 20 LDA #$20 D286 8D 9F 07 STA $079F D289 A9 DC LDA #$DC D28B 20 27 07 JSR $0727 D28E 20 2E 07 JSR $072E D291 88 DEY D292 D0 FA BNE $D28E D294 CE 9F 07 DEC $079F D297 D0 F5 BNE $D28E D299 60 RTS D29A 0C ??? D29B 03 ??? D29C 48 PHA D29D 53 ??? D29E 50 AA BVC $D24A ****************************** Checksum byte for $D000 D2A0 25 ??? ;D-ROM checksum ****************************** Command Search Table: 'ivdmbupcrsn' D2A1 49 ??? ;initialize D2A2 56 ??? ;verify-dir D2A3 44 ??? ;duplicate D2A4 4D ??? ;m- D2A5 42 ??? ;b- D2A6 55 ??? ;user D2A7 50 ??? ;position D2A8 43 ??? ;copy D2A9 52 ??? ;rename D2AA 53 ??? ;scratch D2AB 4E ??? ;new ******************************* Dos command jump table (Low Bytes) D2AC C5 ??? ;initialize D2AD EC ??? ;verify-dir D2AE 46 ??? ;duplicate D2AF A8 ??? ;m- D2B0 AF ??? ;b- D2B1 08 ??? ;user D2B2 ED ??? ;position D2B3 4A ??? ;copy D2B4 75 ??? ;rename D2B5 B7 ??? ;scratch D2B6 0D ??? ;new ;m- ;b- ;user ;position ;copy ;rename ;scratch ;new *************************** **** Structure images for commands (bits 0-7) file structure 0: requires filename #02 1: not default drive 2: not greater than one file 3: not pattern file structure 4: requires filename #01 5: not default drive 6: not greater than one file 7: not pattern D2C2 51 ??? ;copy : 0101 0001 ;rename : 1101 1101 ;scratch: 0001 1100 ;new : 1001 1110 ;load : 0001 1100 ******************************* Track/group table D2C7 11 ??? ;end group #1: 17 (density 00) ;end group #2: 24 (density 01) ;end group #3: 30 (density 10) ;end group #4: 35 (density 11) ******************************* Mode table D2CB 52 ??? ;mode: read ;mode: write ;mode: append ;mode: modify ******************************* File type table D2CF 44 ??? ;D D2D0 53 ??? ;S D2D1 50 ??? ;P D2D2 55 ??? ;U D2D3 4C ??? ;L ******************************* 1st character in name of file type D2D4 44 ??? ;Del D2D5 53 ??? ;Seq D2D6 50 ??? ;Prg D2D7 55 ??? ;Usr D2D8 52 ??? ;Rel ******************************* 2nd character in name of file type D2D9 45 ??? ;dEl D2DA 45 ??? ;sEq D2DB 52 ??? ;pRg D2DC 53 ??? ;uSr D2DD 45 ??? ;rEl ******************************* 3rd character in name of file type D2DE 4C ??? ;deL D2DF 51 ??? ;seQ D2DE 47 ??? ;prG D2E1 52 ??? ;usR D2E2 4C ??? ;reL ******************************* Error flag variables for file bits: D2E3 00 ??? ;#$00: 0000 0000 D2E4 3F ??? ;#$3F: 0011 1111 D2E5 7F ??? ;#$7F: 0111 1111 D2E6 BF ??? ;#$BF: 1011 1111 D2E7 FF ??? ;#$FF: 1111 1111 ******************************* BAM buffer pointers (High bytes) D2E8 41 ??? ;BAM buffer pointer for drive 0 D2E9 42 ??? ;BAM buffer pointer for drive 1 ******************************* Sectors per track table (4040) D2EA 11 ??? ;group #4 maximum sectors: 00-16 (trk 31-35) D2EB 12 ??? ;group #3 maximum sectors: 00-17 (trk 25-30) D2EC 13 ??? ;group #2 maximum sectors: 00-18 (trk 18-24) D2ED 15 ??? ;group #1 maximum sectors: 00-20 (trk 1-17) ******************************* Disk & sector definition bytes (4040) D2EE 09 ??? ;GAP 1 spacing byte D2EF 02 ??? ;GAP 2 spacing byte D2F0 41 ??? ;Format version: A ******************************* Sectors per track table (3040) D2F1 0E ??? ;group #4 maximum sectors: 00-13 (trk 31-35) D2F2 0F ??? ;group #3 maximum sectors: 00-14 (trk 25-30) D2F3 10 ??? ;group #2 maximum sectors: 00-16 (trk 18-24) D2F4 12 ??? ;group #1 maximum sectors: 00-17 (trk 1-17) ******************************* Disk & sector definition bytes (3040) D2F5 1C ??? ;GAP 1 spacing byte D2F6 1E ??? ;GAP 2 spacing byte D2F7 42 ??? ;Format version: B ******************************* Controller: jump to wait loop D2F8 78 SEI ;transfer control over to 6504 D2F9 A9 00 LDA #$00 D2FB 8D 03 04 STA $0403 ;set job queue to no jobs: #$00 D2FE 4C 04 FC JMP $FC04 ;jump to initialize 6504 routine ******************************* Error display routine. Blinks the error number + 1 in all three LED's D301 A2 00 LDX #$00 ;set number of error flashes to #$00 D303 2C A6 04 BIT $04A6 ;** also becomes patch: D304 A6 04 LDX $04 D306 9A TXS ;use stack as storage register D307 BA TSX ;restore error number D308 A9 38 LDA #$38 ;set all LED's to on D30A 8D 82 02 STA $0282 ;turn on LED's D30D 98 TYA ;clear inner memory counter D30E 18 CLC D30F 69 01 ADC #$01 ;increment job counter D311 D0 FC BNE $D30F ;job counter equal to zero ?, no D313 88 DEY ;done clearing zero page ? D314 D0 F8 BNE $D30E ;no, D316 8C 82 02 STY $0282 ;turn off LED's D319 98 TYA D31A 18 CLC D31B 69 01 ADC #$01 ;finished counting to #$FF ? D31D D0 FC BNE $D31B ;no, D31F 88 DEY ;finished counting to #$FF D320 D0 F8 BNE $D31A ;no, D322 CA DEX ;cycle for type of failure indicated ? D323 10 E3 BPL $D308 ;no, D325 E0 FC CPX #$FC ;does flashing cycle define the proper hardware failure ? D327 D0 F0 BNE $D319 ;no, finish flashing cycle D329 F0 DC BEQ $D307 ;yes, repeat error cycle ******************************* Initialize disk for: Power Up Diagnostics D32B 78 SEI ;set interrupt timer D32C D8 CLD D32D A2 FF LDX #$FF D32F 8E 02 02 STX $0202 ;set IEEE data out port D332 8E 03 02 STX $0203 ;activate data out direction D335 E8 INX ;set LED's to off D336 8E 82 02 STX $0282 ;turn off LED's D339 A9 1C LDA #$1C D33B 8D 80 02 STA $0280 ;initialize DAV, EOI, RFD lines D33E A9 1F LDA #$1F D340 8D 81 02 STA $0281 ;initialize LED's D343 A9 38 LDA #$38 ;set LED's to on D345 8D 83 02 STA $0283 ;store IEEE control port ******************************* Fill ZERO PAGE ascending pattern D348 8A TXA ;set fill code for ZERO PAGE D349 95 00 STA $00,X ;fill ZERO PAGE with corresponding location number (ex. $01 = #$01) D34B E8 INX ;done ? D34C D0 FA BNE $D348 ;no, ******************************* Test ZERO PAGE D34E 8A TXA ;set .ACC to #$00 D34F A8 TAY ;set .Y register to #$00 D350 C8 INY D351 F6 00 INC $00,X ;increment all of ZERO PAGE by one D353 C8 INY ;done setting section of ZERO PAGE ? D354 D0 FB BNE $D351 ;no, D356 B4 00 LDY $00,X ;load .Y register with ZERO PAGE value D358 C8 INY ;is ZERO PAGE equal to #$00 ? D359 D0 A6 BNE $D301 ;no, exit to indicate ZERO PAGE hardware failure D35B F6 00 INC $00,X ;User Jump Table pointer set to #$00 D35D D0 A2 BNE $D301 ;no, exit to indicate ZERO PAGE hardware failure D35F E8 INX ;ZERO PAGE all tested ? D360 D0 EC BNE $D34E ;no, ******************************* Test three 64K-bit roms: exit if ok .X = start page D362 E6 04 INC $04 ;set for proper amount of failure flashes D364 86 0B STX $0B ;set LO byte of Indirect Pointer to #$00 D366 A9 00 LDA #$00 D368 85 0A STA $0A ;set HI byte of Indirect Pointer to #$00 D36A A8 TAY D36B A2 10 LDX #$10 ;test sixteen pages D36D 18 CLC D36E C6 0B DEC $0B ;start checking ROM backwards D370 71 0A ADC ($0A),Y ;add up checksum D372 C8 INY ;last byte of page checked ? D373 D0 FB BNE $D370 ;no, D375 CA DEX ;last page of ROM checked ? D376 D0 F6 BNE $D36E ;no, D378 69 00 ADC #$00 D37A AA TAX D37B C5 0B CMP $0B ;finished checking IEEE ROM ? D37D D0 85 BNE $D304 ;no, exit to indicate ROM hardware failure D37F E0 D0 CPX #$D0 ;is CONTROLLER ROM currently under test ? D381 D0 DF BNE $D362 ;no, D383 B9 F8 D2 LDA $D2F8,Y ;load content of ROM location D386 99 00 11 STA $1100,Y ;store content in Data Buffer #0 D389 C8 INY ;finished transfer ? D38A D0 F7 BNE $D383 ;no, D38C A9 D0 LDA #$D0 D38E 8D 03 10 STA $1003 ;set job queue to Execute Ml code in Data buffer D391 E6 04 INC $04 ;set proper amount of failure flashes D393 C8 INY ;finished testing ? D394 D0 FD BNE $D393 ;no, D396 AD 03 10 LDA $1003 ;CONTROLLER ROM tested ? D399 F0 05 BEQ $D3A0 ;yes, D39B CA DEX D39C 30 F5 BMI $D393 ;last page of CONTROLLER ROM left to test ? D39E D0 DD BNE $D37D ;no, ******************************* Test all common ram pages $2000-$5000 D3A0 A9 10 LDA #$10 D3A2 85 0B STA $0B ;set for ram page D3A4 E6 04 INC $04 ;set proper amount of failure flashes D3A6 A2 04 LDX #$04 ;divide page into four parts D3A8 98 TYA D3A9 18 CLC D3AA 65 0B ADC $0B ;do next byte in page D3AC 91 0A STA ($0A),Y ;fill page location with byte value D3AE C8 INY ;last byte of page ? D3AF D0 F7 BNE $D3A8 ;no, D3B1 E6 0B INC $0B ;increment for next page D3B3 CA DEX ;last part of current page done ? D3B4 D0 F2 BNE $D3A8 ;no, D3B6 A2 04 LDX #$04 ;divide page into four parts D3B8 C6 0B DEC $0B ;so next byte in page D3BA 88 DEY ;last byte in page ? D3BB 98 TYA D3BC 18 CLC D3BD 65 0B ADC $0B ;calculate checksum D3BF D1 0A CMP ($0A),Y ;ok ? D3C1 D0 BA BNE $D37D ;error during test, branch to error routine D3C3 49 FF EOR #$FF ;flip bits of current byte in page D3C5 91 0A STA ($0A),Y ;store result back into location D3C7 51 0A EOR ($0A),Y ;flip bits once again D3C9 91 0A STA ($0A),Y ;store result back into location, result $00 ? D3CB D0 B0 BNE $D37D ;error during test, branch to error routine D3CD 98 TYA ;another byte in page to do ? D3CE D0 EA BNE $D3BA ;yes, D3D0 CA DEX ;another page ? D3D1 D0 E5 BNE $D3B8 ;yes, D3D3 A5 0B LDA $0B ;set .ACC to current RAM page under test D3D5 18 CLC D3D6 69 10 ADC #$10 ;set up for next page to test D3D8 C9 50 CMP #$50 ;last page of RAM tested ? D3DA D0 C6 BNE $D3A2 ;no, ******************************* Diagnostics ok so far: test device number (PINS 22,23,24 on drive board location UE1) and test LED status D3DC A2 FF LDX #$FF D3DE 9A TXS ;initialize stack pointer D3DF AD 82 02 LDA $0282 ;read LED status: bit 0-2 = device number 3-5 = LED status D3E2 29 C7 AND #$C7 ;set LED's to off D3E4 8D 82 02 STA $0282 ;turn off LED's : bit 0-2 = device number 3-5 = LED status D3E7 AD 82 02 LDA $0282 ;read device number: bit 0-2 = device number 3-5 = LED status D3EA 29 07 AND #$07 ;test PINS 22,23,24 for device number D3EC 09 48 ORA #$48 ;add $40 to device number D3EE 85 0D STA $0D ;set talker device number D3F0 49 60 EOR #$60 ;add $20 to device number D3F2 85 0C STA $0C ;set listener device number ******************************* Initialize buffer pointer table D3F4 A2 00 LDX #$00 D3F6 A0 00 LDY #$00 D3F8 A9 00 LDA #$00 D3FA 95 29 STA $29,X ;set LO byte of BUFFER #0 to #$00 D3FC E8 INX ;set for HI byte of BUFFER D3FD B9 FF F0 LDA $F0FF,Y ;read HI byte for current BUFFER D400 95 29 STA $29,X ;store at BUFFER HI byte position D402 E8 INX ;move to next BUFFER D403 C8 INY ;move to next BUFFER D404 C0 0E CPY #$0E ;all fifteen BUFFERS set ? D406 D0 F0 BNE $D3F8 ;no, D408 A9 00 LDA #$00 D40A 95 29 STA $29,X ;set LO byte of command buffer to #$00 D40C E8 INX D40D A9 43 LDA #$43 D40F 95 29 STA $29,X ;set HI byte of command buffer to #$43 D411 E8 INX D412 A9 DC LDA #$DC D414 95 29 STA $29,X ;set LO byte of ERROR output buffer to #$DC D416 E8 INX D417 A9 43 LDA #$43 D419 95 29 STA $29,X ;set HI byte of ERROR output buffer to #$43 D41B A9 FF LDA #$FF D41D A2 12 LDX #$12 D41F 95 A2 STA $A2,X ;set LOGICAL INDEX TABLE to #$FF bit 6-7: 00 = read channel 10 = write channel 01 = read/write channel 11 = no channel D421 CA DEX ;last table set ? D422 10 FB BPL $D41F ;no, D424 A2 07 LDX #$07 D426 95 49 STA $49,X ;set SEQ file buffers to #$FF D428 95 51 STA $51,X ;set CHANNEL buffers to #$FF D42A 95 79 STA $79,X ;set SIDE SECTOR table to #$FF D42C CA DEX ;all flag buffers set to #$FF ? D42D 10 F7 BPL $D426 ;no, D42F A9 0E LDA #$0E D431 85 4F STA $4F ;set LO byte of SEQ file buffer to #$0E D433 A9 0F LDA #$0F D435 85 50 STA $50 ;set HI byte of SEQ file buffer to #$0F D437 A9 07 LDA #$07 D439 85 B2 STA $B2 ;set HI byte of LOGICAL INDEX TABLE to #$07 D43B A9 86 LDA #$86 D43D 85 B1 STA $B1 ;set LO byte of LOGICAL INDEX TABLE to #$86 D43F A9 3F LDA #$3F D441 8D 48 43 STA $4348 ;set available logical index bit 6-7: error channel & command channel 1: free LOGICAL INDEX D444 A9 01 LDA #$01 D446 85 9E STA $9E ;set channel status 7 bit 7: channel is talker to IEEE 3: send EOI on next byte (talker only) 1: channel is listener to IEEE D448 A9 88 LDA #$88 D44A 85 9F STA $9F ;set channel status to 8 D44C A9 00 LDA $00 D44C 8D 3E 43 STA $433E ;set SEQ file buffer to unused bit 1: indicates buffer used D451 A9 F0 LDA #$F0 D453 8D 3F 43 STA $433F ;set CHANNEL buffer bit 1: indicates buffer used D456 20 0F E8 JSR $E80F ;jump to user access commands D459 A9 DC LDA #$DC D45B 8D F0 10 STA $10F0 ;set LO byte of NMI to #$DC D45E A9 D3 LDA #$D3 D460 8D F1 10 STA $10F1 ;set HI byte of NMI to #$D3 D463 A9 0A LDA #$0A D465 8D 44 43 STA $4344 ;set sector increment to #$0A D468 8D 5C 43 STA $435C ;set error recovery count to #$0A ******************************* Set up sector/track table depending on controller used D46B AD 00 10 LDA $1000 ;read Interrupt Delay D46E A2 00 LDX #$00 D470 C9 0F CMP #$0F ;disk controller under use ? D472 F0 0B BEQ $D47F ;yes, D474 A2 07 LDX #$07 D476 C9 64 CMP #$64 ;IEEE controller under use ? D478 F0 05 BEQ $D47F ;yes, ******************************* Controller error D47A E6 04 INC $04 ;set proper amount of failure flashes D47C 4C 04 D3 JMP $D304 ;error during test, branch to error routine ******************************* Set up sectors/track, GAP1, dos version, format version D47F A0 00 LDY #$00 D481 BD EA D2 LDA $D2EA,X ;load amount of sectors for track group D484 99 99 10 STA $1099,Y ;store in sectors/track table D487 E8 INX ;set for next group D488 C8 INY ;set for next location in table D489 C0 07 CPY #$07 ;format version transferred ? D48B D0 F4 BNE $D481 ;no, ******************************* Set up power on message "cbm dos v2.1" D48D A9 73 LDA #$73 ;set for error # 73 D48F 20 CE D9 JSR $D9CE ;jump to error process routine ******************************* BUMP heads to track 1 D492 A9 01 LDA #$01 D494 8D 23 10 STA $1023 ;set track of buffer #0 to 1 D497 8D 2B 10 STA $102B ;set track of buffer #1 to 1 D49A A2 C0 LDX #$C0 D49C 8E 03 10 STX $1003 ;BUMP head of drive 0 D49F E8 INX D4A0 8E 04 10 STX $1004 ;BUMP head of drive 1 D4A3 8E 87 02 STX $0287 ;turn off LED's ******************************* Idle loop: does housekeeping while waiting for job D4A6 AD 47 43 LDA $4347 ;is there a command waiting ? D4A9 F0 0C BEQ $D4B7 ;no, D4AB 78 SEI D4AC A9 00 LDA #$00 D4AE 8D 47 43 STA $4347 ;set command waiting flag to 0 D4B1 8D F2 10 STA $10F2 ;set NMI in progress to 0 D4B4 20 55 DB JSR $DB55 ;parse and execute string in command buffer D4B7 58 CLI D4B8 A9 0E LDA #$0E D4BA 85 07 STA $07 ;assign TEMP3 flag as logical counter D4BC A9 00 LDA #$00 D4BE 85 04 STA $04 ;assign TEMP0 flag to current jobs D4C0 85 05 STA $05 ;assign TEMP1 flag as current drive indicator D4C2 A6 07 LDX $07 ;set up for index check D4C4 B5 A2 LDA $A2,X ;check for available logical index D4C6 C9 FF CMP #$FF ;logical index available ? D4C8 F0 10 BEQ $D4DA ;yes, D4CA 29 3F AND #$3F ;test index's current status (r/w,r,w,no) D4CC 85 15 STA $15 ;store in logical index status D4CE 20 98 FA JSR $FA98 ;get active buffer number D4D1 AA TAX D4D2 BD 4E 43 LDA $434E,X ;last job entered in queue D4D5 29 01 AND #$01 D4D7 AA TAX D4D8 F6 04 INC $04,X ;increment TEMP flag D4DA C6 07 DEC $07 ;last logical index ? D4DC 10 E4 BPL $D4C2 ;no, D4DE A0 0B LDY #$0B D4E0 B9 03 10 LDA $1003,Y ;job in queue ? D4E3 10 05 BPL $D4EA ;no, D4E5 29 01 AND #$01 D4E7 AA TAX D4E8 F6 04 INC $04,X ;increment TEMP flag D4EA 88 DEY ;last queue checked for job ? D4EB 10 F3 BPL $D4E0 ;no, D4ED AD 82 02 LDA $0282 ;test active LED D4F0 29 E7 AND #$E7 D4F2 48 PHA D4F3 A5 04 LDA $04 ;is drive 0 under use ? D4F5 F0 04 BEQ $D4FB ;yes, D4F7 68 PLA D4F8 09 10 ORA #$10 ;activate LED drive 1 D4FA 48 PHA D4FB A5 05 LDA $05 ;TEMP1 flag equal to 0 ? D4FD F0 04 BEQ $D503 ;yes, D4FF 68 PLA D500 09 08 ORA #$08 ;activate LED drive 0 D502 48 PHA D503 68 PLA D504 8D 82 02 STA $0282 ;activate LED drive 0 D507 4C B7 D4 JMP $D4B7 ;continue housekeeping routine ******************************* ATN irq process: IRQ on ATN, listen to PET clear stack D50A A2 FF LDX #$FF D50C 9A TXS ;purge stack D50D AD 87 02 LDA $0287 ;clear ATN line from PET D510 A9 18 LDA #$18 ;set for DAV, EOI signals D512 0D 80 02 ORA $0280 D515 8D 80 02 STA $0280 ;free DAV, EOI lines D518 A9 FF LDA #$FF D51A 8D 02 02 STA $0202 ;free data lines D51D A9 07 LDA #$07 ;set for DAC, RFD, ATN signals D51F 0D 80 02 ORA $0280 D522 8D 80 02 STA $0280 ;free DAC, RFD, ATN lines D525 2C 80 02 BIT $0280 ;have lines been freed ? D528 50 04 BVC $D52E ;DAV set low D52A 30 F9 BMI $D525 ;ATN low & ATN1 high D52C 10 7B BPL $D5A9 ;ATN high D52E A9 FB LDA #$FB ;set for NRFD signal D530 2D 80 02 AND $0280 D533 8D 80 02 STA $0280 ;set NRFD line low D536 29 20 AND #$20 D538 85 A0 STA $A0 ;temporary EOI D53A AD 00 02 LDA $0200 ;get DATA byte from IEEE port D53D 49 FF EOR #$FF D53F 85 18 STA $18 ;store byte in temp data byte D541 A9 FD LDA #$FD ;set for NDAC signal D543 2D 80 02 AND $0280 D546 8D 80 02 STA $0280 ;set NDAC line high ******************************* Decide: Secondary Address, talk, listen, other D549 A0 00 LDY #$00 D54B A5 18 LDA $18 ;read data byte from temporary location D54D 29 60 AND #$60 D54F C9 40 CMP #$40 ;is it a talk signal ? D551 F0 29 BEQ $D57C ;yes, D553 C9 20 CMP #$20 ;is it a listen signal? D555 F0 06 BEQ $D55D ;yes, D557 C9 60 CMP #$60 ;is it a secondary address ? D559 F0 2F BEQ $D58A ;yes, D55B D0 44 BNE $D5A1 ;no, D55D A5 18 LDA $18 ;load in device number sent from PET D55F C5 0C CMP $0C ;same device number ? D561 F0 0B BEQ $D56E ;yes, D563 C9 3F CMP #$3F ;is signal sent from PET an unlisten ? D565 D0 02 BNE $D569 ;no, D567 84 0E STY $0E ;set active listener flag to #$00 D569 84 10 STY $10 ;set addressed flag to #$00 D56B 4C A1 D5 JMP $D5A1 D56E 85 0E STA $0E ;set active listener flag to accessed device D570 84 0F STY $0F ;set active talker flag to #$00 D572 A9 20 LDA #$20 D574 85 16 STA $16 ;set secondary address to #$20 (decimal 32) D576 85 17 STA $17 ;set original secondary address to #$20 (decimal 32) D578 85 10 STA $10 ;addressed flag not #$00 ? D57A D0 25 BNE $D5A1 ;yes, D57C 84 0F STY $0F ;set active talker to #$00 D57E A5 18 LDA $18 ;read byte from temporary location D580 C5 0D CMP $0D ;equal to talker address ? D582 D0 E5 BNE $D569 ;no, D584 85 0F STA $0F ;set active talker to device calling D586 84 0E STY $0E ;active listener set to #$00 ? D588 F0 E8 BEQ $D572 ;yes, D58A A5 10 LDA $10 ;addressed flag #$00 ? D58C F0 13 BEQ $D5A1 ;yes, D58E A5 18 LDA $18 ;read byte from temporary location D590 85 17 STA $17 ;set as original secondary address D592 48 PHA D593 29 0F AND #$0F ;test address validity: 0-15 D595 85 16 STA $16 ;store result as current secondary address D597 68 PLA D598 29 F0 AND #$F0 D59A C9 E0 CMP #$E0 ;close command received ? D59C D0 03 BNE $D5A1 ;no, D59E 20 8D F5 JSR $F58D ;close file associated with secondary address D5A1 2C 80 02 BIT $0280 ;IEEE control port released ? D5A4 50 FB BVC $D5A1 ;no, D5A6 4C 1D D5 JMP $D51D ;yes, D5A9 A5 0E LDA $0E ;active listener to #$00 ? D5AB F0 0F BEQ $D5BC ;yes, D5AD A9 FA LDA #$FA ;set for ATN & DAC signal D5AF 2D 80 02 AND $0280 D5B2 8D 80 02 STA $0280 ;set ATN, DAC lines D5B5 58 CLI D5B6 20 CF D5 JSR $D5CF ;set for listen mode D5B9 4C A6 D4 JMP $D4A6 ;jump to idle loop D5BC A9 FC LDA #$FC ;set for RFD & ATN signal D5BE 2D 80 02 AND $0280 D5C1 8D 80 02 STA $0280 ;set RFD, ATN lines D5C4 A5 0F LDA $0F ;active talker to #$00 ? D5C6 F0 04 BEQ $D5CC ;yes, D5C8 58 CLI D5C9 20 5F D6 JSR $D65F ;set for talk mode D5CC 4C A6 D4 JMP $D4A6 ;jump to idle loop ******************************* Set listen routine: main routine D5CF A9 04 LDA #$04 ;set for RFD signal D5D1 0D 80 02 ORA $0280 D5D4 8D 80 02 STA $0280 ;set RFD high D5D7 2C 80 02 BIT $0280 ;has DAV gone low ? D5DA 70 FB BVS $D5D7 ;no, D5DC 20 84 ED JSR $ED84 ;open channel for writing D5DF B0 05 BCS $D5E6 ;channel not active ? D5E1 B5 98 LDA $98,X ;read channel status bit 0: channel is listener to IEEE bit 3: send EOI on next byte (talker only) bit 7: channel is talker to IEEE D5E3 6A ROR ;listener flag set ? D5E4 B0 49 BCS $D62F ;no, D5E6 A5 17 LDA $17 ;read secondary address D5E8 29 F0 AND #$F0 D5EA C9 F0 CMP #$F0 ;secondary address already open ? D5EC F0 41 BEQ $D62F ;no, D5EE A5 16 LDA $16 ;current secondary address D5F0 C9 01 CMP #$01 ;is it SAVE or LOAD ? D5F2 F0 0E BEQ $D602 ;yes, D5F4 2C 80 02 BIT $0280 ;has DAV gone low ? D5F7 50 FB BVC $D5F4 ;no, D5F9 A9 FD LDA #$FD ;set for DAC signal D5FB 2D 80 02 AND $0280 D5FE 8D 80 02 STA $0280 ;set DAC lines D601 60 RTS D602 A9 FB LDA #$FB ;set for RFD signal D604 2D 80 02 AND $0280 D607 8D 80 02 STA $0280 ;set RFD line low D60A A9 FD LDA #$FD ;set for DAC signal D60C 2D 80 02 AND $0280 D60F 8D 80 02 STA $0280 ;set DAC line high D612 2C 80 02 BIT $0280 ;has DAV gone high ? D615 50 FB BVC $D612 ;no, D617 A9 02 LDA #$02 ;set for DAC signal D619 0D 80 02 ORA $0280 D61C 8D 80 02 STA $0280 ;set DAC line low D61F A9 04 LDA #$04 ;set for RFD signal D621 0D 80 02 ORA $0280 D624 8D 80 02 STA $0280 ;set RFD line D627 2C 80 02 BIT $0280 ;has DAV gone low ? D62A 50 FB BVC $D627 ;no, D62C 4C 02 D6 JMP $D602 ;return to beginning of timing loop D62F A9 FB LDA #$FB ;set for RFD signal D631 2D 80 02 AND $0280 D634 8D 80 02 STA $0280 ;set RFD line D637 29 20 AND #$20 D639 85 A0 STA $A0 ;set temporary EOI flag D63B AD 00 02 LDA $0200 ;IEEE data in D63E 49 FF EOR #$FF D640 85 18 STA $18 ;store byte in temporary data location D642 78 SEI D643 A9 FD LDA #$FD ;set for DAC signal D645 2D 80 02 AND $0280 D648 8D 80 02 STA $0280 ;set DAC line D64B 2C 80 02 BIT $0280 ;has DAC been polled ? D64E 50 FB BVC $D64B ;no, D650 A9 02 LDA #$02 ;set for DAC signal D652 0D 80 02 ORA $0280 D655 8D 80 02 STA $0280 ;set DAC line D658 20 F8 EB JSR $EBF8 ;write to indicated channel D65B 58 CLI ******************************* Listen routine D65C 4C CF D5 JMP $D5CF ;jump to main listen routine ******************************* Set talk routine: main routine D65F 20 69 ED JSR $ED69 ;channel open for read ? D662 B0 06 BCS $D66A ;yes, D664 A6 15 LDX $15 ;logical index D666 B5 98 LDA $98,X ;read channel status bit 0: channel is listener to IEEE bit 3: send EOI on next byte (talker only) bit 7: channel is talker D668 30 01 BMI $D66B ;talk mode active D66A 60 RTS ******************************* From TALK: no talk = rts D66B 2C 82 02 BIT $0282 ;read device/LED port: bit 0-2 = device number 3-5 = LED status D66E 10 FB BPL $D66B ;keep polling until RFD high D670 B5 B5 LDA $B5,X ;channel data byte D672 49 FF EOR #$FF D674 8D 02 02 STA $0202 ;IEEE data out D677 B5 98 LDA $98,X ;read channel status bit 0: channel is listener to IEEE bit 3: send EOI on next byte (talker only) bit 7: channel is talker D679 09 E7 ORA #$E7 ;set for EOI & DAV signals D67B 2D 80 02 AND $0280 D67E 8D 80 02 STA $0280 ;set EOI, DAV lines D681 2C 82 02 BIT $0282 ;has DAV gone low ? D684 10 0D BPL $D693 ;yes, D686 50 F9 BVC $D681 ;no, D688 A9 18 LDA #$18 ;set for DAV & EOI signal D68A 0D 80 02 ORA $0280 D68D 8D 80 02 STA $0280 ;set DAV, EOI lines D690 4C A6 D4 JMP $D4A6 ;jump to idle loop D693 20 A3 EF JSR $EFA3 ;get a byte from channel D696 2C 82 02 BIT $0282 ;device/LED port clear ? bit 0-2 = device number 3-5 = LED status D699 50 FB BVC $D696 ;no, ******************************* Talk routine D69B A9 FF LDA #$FF D69D 8D 02 02 STA $0202 ;IEEE data out D6A0 A9 18 LDA #$18 ;set for DAV & EOI signals D6A2 0D 80 02 ORA $0280 D6A5 8D 80 02 STA $0280 ;set DAV, EOI lines D6A8 2C 82 02 BIT $0282 ;device/LED port clear ? bit 0-2 = device number 3-5 = LED status D6AB 70 FB BVS $D6A8 ;no, D6AD 50 B5 BVC $D664 ;yes, ******************************* Return next available track and sector given current T & S allocation is from track 18 towards 1 & 35 by full tracks D6AF 20 41 F9 JSR $F941 ;get track and sector number D6B2 A9 03 LDA #$03 D6B4 85 04 STA $04 ;set TEMP0 to #$03 D6B6 20 80 D7 JSR $D780 ;set proper BAM to use D6B9 A5 13 LDA $13 ;read current track location of head D6BB 0A ASL D6BC 0A ASL D6BD A8 TAY D6BE B1 02 LDA ($02),Y ;has 4 BAM track bytes been checked ? D6C0 D0 33 BNE $D6F5 ;no, D6C2 A5 13 LDA $13 ;check current track D6C4 C9 12 CMP #$12 ;is it the directory track (18) ? D6C6 F0 16 BEQ $D6DE ;yes, D6C8 90 19 BCC $D6E3 ;smaller, then check next lower track D6CA E6 13 INC $13 ;increment to next track D6CC A5 13 LDA $13 ;read track position of head D6CE C9 24 CMP #$24 ;is it at end of disk (36) ? D6D0 D0 E7 BNE $D6B9 ;no, D6D2 A9 11 LDA #$11 D6D4 85 13 STA $13 ;set track number to 17 D6D6 A9 00 LDA #$00 D6D8 85 14 STA $14 ;set sector number to 0 D6DA C6 04 DEC $04 ;track searched for available sectors ? D6DC D0 DB BNE $D6B9 ;no, ******************************* Disk full error D6DE A9 72 LDA #$72 ;set for "72 DISK FULL" error D6E0 4C C3 DB JMP $DBC3 ;jump to error process routine ******************************* Find an available track D6E3 C6 13 DEC $13 ;has track 0 been reached ? D6E5 D0 D2 BNE $D6B9 ;no, D6E7 A9 13 LDA #$13 D6E9 85 13 STA $13 ;set track number to 19 D6EB A9 00 LDA #$00 D6ED 85 14 STA $14 ;set sector number to 0 D6EF C6 04 DEC $04 ;track searched for available sectors ? D6F1 D0 C6 BNE $D6B9 ;no, D6F3 F0 E9 BEQ $D6DE ;yes, ******************************* Find the next optimum sector on track D6F5 A5 14 LDA $14 ;read current sector number D6F7 18 CLC D6F8 6D 44 43 ADC $4344 ;increment sector by step factor D6FB 85 14 STA $14 ;set head for step to new sector position D6FD A5 13 LDA $13 ;read current track number D6FF 20 D2 D7 JSR $D7D2 ;find sector allocation for track group D702 8D 3D 43 STA $433D ;store maximum sector limit for track group D705 8D 3C 43 STA $433C ;store maximum sector limit in TEMP CMD D708 C5 14 CMP $14 ;is sector number over allowed boundary ? D70A B0 12 BCS $D71E ;yes, D70C 38 SEC D70D A5 14 LDA $14 ;read current sector number D70F ED 3D 43 SBC $433D ;substract from maximum sector number for track group D712 85 14 STA $14 ;store result as current sector number, is result 0 ? D714 F0 08 BEQ $D71E ;yes, D716 C6 14 DEC $14 ;decrement sector number by 1, is result 0 ? D718 D0 04 BNE $D71E ;no, D71A A9 00 LDA #$00 D71C 85 14 STA $14 ;set sector number to 0 D71E 20 8C D7 JSR $D78C ;read sector map for current track D721 20 A8 D7 JSR $D7A8 ;track full ? D724 B0 15 BCS $D73B ;yes, D726 CE 3C 43 DEC $433C ;temporary sector count equal to #$0 ? D729 10 05 BPL $D730 ;no, ******************************* Directory error D72B A9 71 LDA #$71 ;set for "71 DIR" error D72D 4C 53 D9 JMP $D953 ;jump to error process routine ******************************* Test for free sectors, else indicate track as used D730 A5 14 LDA $14 ;read current sector number D732 E6 14 INC $14 ;increment sector number D734 CD 3D 43 CMP $433D ;has all sectors for track been checked ? D737 D0 E8 BNE $D721 ;no, D739 F0 DF BEQ $D71A ;yes, D73B 4C 9A EB JMP $EB9A ;indicate sectors for track as used ******************************* Test lower & upper track ranges for free sectors D73E A9 11 LDA #$11 D740 85 13 STA $13 ;set track number to 17 D742 20 80 D7 JSR $D780 ;set BAM for use with current drive D745 A5 13 LDA $13 ;read track number D747 0A ASL D748 0A ASL D749 A8 TAY ;set pointer to location of track in BAM D74A B1 02 LDA ($02),Y ;available sectors on track ? D74C D0 15 BNE $D763 ;yes, D74E A9 24 LDA #$24 ;set for track number 36 D750 38 SEC D751 E5 13 SBC $13 ;set pointer for upper track test D753 0A ASL D754 0A ASL D755 A8 TAY ;set pointer to location of track in BAM D756 B1 02 LDA ($02),Y ;available sectors on track ? D758 D0 09 BNE $D763 ;yes, D75A C6 13 DEC $13 ;all tracks on disk checked for free sectors ? D75C D0 E7 BNE $D745 ;no, ******************************* Disk full error D75E A9 72 LDA #$72 ;set for "72 DISK FULL" error D760 4C C3 DB JMP $DBC3 ;jump to error process routine ******************************* Find sector D763 98 TYA D764 4A LSR D765 4A LSR D766 85 13 STA $13 ;set current track to search for free sectors D768 A9 00 LDA #$00 D76A 85 14 STA $14 ;set sector number to 0 D76C 20 8C D7 JSR $D78C ;read sector map for current track D76F 20 A8 D7 JSR $D7A8 ;track full ? D772 B0 09 BCS $D77D ;yes, D774 E6 14 INC $14 ;sector count 0 ? D776 D0 F7 BNE $D76F ;no, ******************************* Directory error D778 A9 71 LDA #$71 ;set for "71 DIR" error D77A 4C 53 D9 JMP $D953 ;jump to error process routine ******************************* Mark current track as full D77D 4C 9A EB JMP $EB9A ;Mark track, sector, BAM pointer as used ******************************* Set BAM pointer for current drive D780 A6 12 LDX $12 ;get current drive number D782 BD E8 D2 LDA $D2E8,X ;read BAM HI byte pointer D785 85 03 STA $03 ;set HI byte to: drive 0: $41 drive 1: $42 D787 A9 00 LDA #$00 D789 85 02 STA $02 ;set BAM LO byte pointer to #$00 D78B 60 RTS ******************************* Read sector map from BAM D78C A5 13 LDA $13 ;read current track number D78E 0A ASL D78F 0A ASL D790 A8 TAY ;set track pointer in BAM D791 B1 02 LDA ($02),Y ;read amount of free sectors on track D793 85 07 STA $07 ;store in TEMP3 D795 A2 02 LDX #$02 D797 C8 INY D798 B1 02 LDA ($02),Y ;read part of sector map for track D79A 95 04 STA $04,X ;store in TEMP locations D79C CA DEX ;all parts of sector map read ? D79D 10 F8 BPL $D797 ;no, D79F 20 B4 D7 JSR $D7B4 ;test for free sectors on current track D7A2 A4 14 LDY $14 ;sector count 0 ? D7A4 F0 0D BEQ $D7B3 ;yes, D7A6 D0 02 BNE $D7AA ;no, D7A8 A0 01 LDY #$01 ;set track indicator as full D7AA 66 04 ROR $04 ;indicate sector part 3 for track as full D7AC 66 05 ROR $05 ;indicate sector part 2 for track as full D7AE 66 06 ROR $06 ;indicate sector part 1 for track as full D7B0 88 DEY ;all sectors on track marked as full ? D7B1 D0 F7 BNE $D7AA ;no, D7B3 60 RTS ******************************* Test for available sectors on current track D7B4 A2 00 LDX #$00 D7B6 A0 03 LDY #$03 ;all track information bytes tested for free sector ? D7B8 D0 06 BNE $D7C0 ;no, D7BA E8 INX ;check next sector in current track part D7BB 4A LSR ;all sectors in current track part tested ? D7BC B0 FC BCS $D7BA ;yes, D7BE D0 FB BNE $D7BB ;no, D7C0 B9 03 00 LDA $0003,Y ;read sector part of track D7C3 88 DEY ;last part of track tested for free sectors ? D7C4 10 F5 BPL $D7BB ;no, D7C6 E4 07 CPX $07 ;result part same as BAM reading for track ? D7C8 F0 07 BEQ $D7D1 ;yes, ******************************* Directory error D7CA A9 71 LDA #$71 ;set for "71 DIR" error D7CC A0 00 LDY #$00 D7CE 4C 53 D9 JMP $D953 ;jump to error process routine D7D1 60 RTS ******************************* Number of sectors for specific track table D7D2 A2 04 LDX #$04 D7D4 DD DD D7 CMP $D7DD,X ;maximum number of sectors for current track ? D7D7 CA DEX ;set for test of next track group D7D8 B0 FA BCS $D7D4 ;no, D7DA BD 99 10 LDA $1099,X ;read maximum sectors allowed for track D7DD 60 RTS ******************************* Sectors per track group table D7DE 24 ??? ;maximum sectors for track group #1 D7DF 1F ??? ;maximum sectors for track group #2 D7E0 19 ??? ;maximum sectors for track group #3 D7E1 12 ??? ;maximum sectors for track group #4 ******************************* OK error message D7E2 00 ;error # 00 D7E3 A0 4F CB ; oK ******************************* READ error messages D7E6 20 ;error # 20 (BLOCK HEADER NOT FOUND) D7E7 21 ;error # 21 (NO SYNC CHARACTER) D7E8 22 ;error # 22 (DATA BLOCK NOT PRESENT) D7E9 23 ;error # 23 (CHECKSUM ERROR IN DATA BLOCK) D7EA 24 ;error # 24 (BYTE DECODING ERROR) D7EB 27 ;error # 27 (CHECKSUM ERROR IN HEADER BLOCK) D7EC D2 45 41 44 ;Read D7F0 89 ;pointer to token word: error ******************************* FILE TOO LARGE error message D7F1 52 ;error # 52 D7F2 83 ;pointer to token word: file D7F3 20 54 4F 4F 20 4C 41 52 ; too lar D7FB 47 C5 ;gE ******************************* RECORD NOT PRESENT error message D7FD 50 ;error # 50 D7FE 8B ;pointer to token word: record D7FF 06 ;pointer to token word: not D801 20 50 52 45 53 45 4E D4 ; presenT ******************************* OVERFLOW IN RECORD error message D808 51 ;error # 51 D809 CF 56 45 52 46 4C 4F 57 ;Overflow D811 20 49 4E ; in D814 8B ;pointer to token word: record ******************************* WRITE error messages D815 25 ;error # 25 (WRITE-VERIFY ERROR) D816 28 ;error # 28 (LONG DATA BLOCK) D817 8A ;pointer to token word: write D818 89 ;pointer to token word: error ******************************* WRITE PROTECT ON error message D819 26 ;error # 26 (WRITE SENSE ON) D81A 8A ;pointer to token word: write D81B 20 50 52 4F 54 45 43 54 ; protect D823 20 4F CE ; oN ******************************* DISK ID MISMATCH error message D826 29 ;error # 29 (INVALID DISK ID) D827 88 ;pointer to token word: disk D828 20 49 44 ; id D82B 85 ;pointer to token word: mismatch ******************************* SYNTAX error messages D82C 30 ;error # 30 (GENERAL SYNTAX) D82D 31 ;error # 31 (INVALID COMMAND) D82E 32 ;error # 32 (LONG LINE) D82F 33 ;error # 33 (INVALID FILE NAME) D830 34 ;error # 34 (NO FILE GIVEN) D831 D3 59 4E 54 41 58 ;Syntax D837 89 ;pointer to token word: error ******************************* WRITE FILE OPEN error message D838 60 ;error # 60 D839 8A ;pointer to token word: write D83A 03 ;pointer to token word: file D83B 84 ;pointer to token word: open ******************************* FILE EXISTS error message D83C 63 ;error # 63 D83D 83 ;pointer to token word: file D83E 20 45 58 49 53 54 D3 ; existS ******************************* FILE TYPE MISMATCH error message D845 64 ;error # 64 D846 83 ;pointer to token word: file D847 20 54 59 50 45 ; type D84C 85 ;pointer to token word: mismatch ******************************* NO BLOCK error message D84D 65 ;error # 65 D84E CE 4F 20 42 4C 4F 43 CB ;No blocK ******************************* ILLEGAL TRACK & SECTOR error messages D856 66 ;error # 66 (ILLEGAL TRACK & SECTOR) D857 67 ;error # 67 (ILLEGAL SYSTEM T or S) D858 C9 4C 4C 45 47 41 4C ;Illegal D85F 20 54 52 41 43 4B 20 4F ; track o D867 52 20 53 45 43 54 4F D2 ;r sectoR ******************************* FILE NOT OPEN error message D86F 61 ;error # 61 D870 83 ;pointer to token word: file D871 06 ;pointer to token word: not D872 84 ;pointer to token word: open ******************************* FILE NOT FOUND error message D873 62 ;error # 62 D874 83 ;pointer to token word: file D875 06 ;pointer to token word: not D876 87 ;pointer to token word: found ******************************* FILE'S SCRATCHED error message D877 01 ;error # 01 D878 83 ;pointer to token word: file D879 53 20 53 43 52 41 54 43 ;s scratc D881 48 45 C4 ;heD ******************************* NO CHANNEL error message D884 70 ;error # 70 (NO CHANNEL AVAILABLE) D885 CE 4F 20 43 48 41 4E 4E ;No chann D88D 45 CC ;eL ******************************* DIRECTORY error message D88F 71 ;error # 71 D890 C4 49 52 ;Dir D893 89 ;pointer to token word: error ******************************* DISK FULL error message D894 72 ;error # 72 D895 88 ;pointer to token word: disk D896 20 46 55 4C CC ; fulL ******************************* DOS MISMATCH error message D89B 73 ;error # 73 (CBM DOS V2) D89C C3 42 4D 20 44 4F 53 ;Cbm dos D8A3 20 56 B2 ; v2 ******************************* Token word: ERROR D8A6 09 D8A7 C5 52 52 4F D2 ;ErroR ******************************* Token word: WRITE D8AC 0A D8AD D7 52 49 54 C5 ;WritE ******************************* Token word: FILE D8B2 03 D8B3 C6 49 4C C5 ;FilE ******************************* Token word: OPEN D8B7 04 D8B8 CF 50 45 CE ;OpeN ******************************* Token word: MISMATCH D8BC 05 D8BD CD 49 53 4D 41 54 43 C8 ;MismatcH ******************************* Token word: NOT D8C5 06 D8C6 CE 4F D4 ;NoT ******************************* Token word: FOUND D8C9 07 D8CA C6 4F 55 4E C4 ;FounD ******************************* Token word: DISK D8CF 08 D8D0 C4 49 53 CB ;DisK ******************************* Token word: RECORD D8D4 0B D8D5 D2 45 43 4F 52 C4 ;RecorD ******************************* Transfer error message to error buffer D8DB DD E2 D7 CMP $D7E2,X ;error number 0 ? D8DE F0 06 BEQ $D8E6 ;yes, D8E0 E8 INX D8E1 E0 F9 CPX #$F9 ;end of error message table ? D8E3 90 F6 BCC $D8DB ;no, skip this error message D8E5 60 RTS ******************************* Test for begin/end of error message D8E6 E8 INX D8E7 BD E2 D7 LDA $D7E2,X ;bit 7 of character set ? D8EA 10 FA BPL $D8E6 ;no, D8EC 29 7F AND #$7F D8EE C9 10 CMP #$10 ;token needs to be transferred ? D8F0 90 15 BCC $D907 ;yes, D8F2 91 47 STA ($47),Y ;transfer character to buffer D8F4 C8 INY D8F5 E8 INX D8F6 BD E2 D7 LDA $D7E2,X ;bit 7 of character set ? D8F9 10 F3 BPL $D8EE ;no, D8FB 48 PHA D8FC 29 7F AND #$7F D8FE C9 10 CMP #$10 ;token needs to be transferred ? D900 90 06 BCC $D908 ;yes, D902 91 47 STA ($47),Y ;transfer character to buffer D904 C8 INY D905 68 PLA D906 60 RTS ******************************* Transfer TOKEN to error message buffer D907 48 PHA D908 48 PHA D909 A9 20 LDA #$20 D90B 91 47 STA ($47),Y ;transfer a blank/space in buffer D90D C8 INY D90E 68 PLA D90F 86 07 STX $07 ;store current position in error message D911 A2 C4 LDX #$C4 ;set for beginning of token table D913 20 DB D8 JSR $D8DB ;transfer token to error buffer D916 A6 07 LDX $07 ;reset position in error message D918 68 PLA ;another token ? D919 10 DA BPL $D8F5 ;no, D91B 60 RTS ******************************* Controller error entry point D91C 48 PHA ;save controller status code D91D 86 A1 STX $A1 ;store job number D91F 8A TXA D920 0A ASL D921 0A ASL D922 0A ASL D923 AA TAX D924 BD 23 10 LDA $1023,X ;read track position of head D927 85 13 STA $13 ;set as current track D929 BD 24 10 LDA $1024,X ;read sector position of head D92C 85 14 STA $14 ;set as current sector D92E 68 PLA ;read controller status code D92F 29 0F AND #$0F ;is controller status code 0 ? D931 D0 02 BNE $D935 ;no, D933 A9 06 LDA #$06 ;set for error code #$06 (decimal 6) D935 09 20 ORA #$20 ;add #$20 (decimal 32) to error code D937 AA TAX ;transfer code D938 CA DEX D939 CA DEX D93A 8A TXA ;transfer subtracted code D93B 48 PHA ;save error code number D93C AD 7A 43 LDA $437A ;read command number D93F C9 01 CMP #$01 ;is it OPEN or VALIDATE ? D941 D0 0F BNE $D952 ;no, D943 A9 FF LDA #$FF D945 8D 7A 43 STA $437A ;set command code to #$FF D948 68 PLA ;read error code number D949 20 D4 D9 JSR $D9D4 ;generate error message D94C 20 FA EC JSR $ECFA ;load BAM D94F 4C 56 D9 JMP $D956 ;jump to error process routine ******************************* Process error D952 68 PLA ;read error code number D953 20 D4 D9 JSR $D9D4 ;generate error message ******************************* Clear command buffer, set LED's D956 20 B8 DB JSR $DBB8 ;erase command buffer D959 A9 00 LDA #$00 D95B 8D 73 43 STA $4373 ;set error word for recovery to 0 D95E AD 82 02 LDA $0282 ;read LED status: bit 0-2 = device number 3-5 = LED status D961 09 20 ORA #$20 ;set for ERROR LED on D963 8D 82 02 STA $0282 ;turn on LED: bit 0-2 = device number 3 = LED drive 1 4 = LED drive 0 5 = ERROR LED D966 20 D3 F0 JSR $F0D3 ;free internal channels D969 A9 00 LDA #$00 D96B 85 45 STA $45 ;set CMD low pointer to 0 D96D A2 FF LDX #$FF D96F 9A TXS ;purge stack ******************************* Talker error recovery D970 A5 17 LDA $17 ;read original secondary address D972 29 1F AND #$1F ;test channel validity: 0-31 D974 85 16 STA $16 ;store result as current secondary address D976 C9 0F CMP #$0F ;result 15, command channel ? D978 F0 2B BEQ $D9A5 ;yes, D97A 78 SEI D97B A5 0E LDA $0E ;is LISTENER active ? D97D D0 11 BNE $D990 ;yes, D97F A5 0F LDA $0F ;is TALKER active ? D981 F0 22 BEQ $D9A5 ;no, D983 20 69 ED JSR $ED69 ;open channel for read D986 AD 80 02 LDA $0280 ;read current signal status D989 09 10 ORA #$10 ;set for DAV signal D98B 8D 80 02 STA $0280 ;set DAV line D98E D0 0D BNE $D99D ******************************* Listener error recovery D990 20 84 ED JSR $ED84 ;open channel for write D993 A9 04 LDA #$04 ;set for RFD signal D995 0D 80 02 ORA $0280 ;read current signal status D998 29 FE AND #$FE D99A 8D 80 02 STA $0280 ;set RFD line D99D 20 A1 ED JSR $EDA1 ;valid file type ? D9A0 B0 03 BCS $D9A5 ;no, D9A2 20 9F EE JSR $EE9F ;free channel D9A5 4C A6 D4 JMP $D4A6 ;jump to idle loop ******************************* Convert HEX to BCD D9A8 AA TAX ;transfer HEX value to .X register D9A9 A9 00 LDA #$00 D9AB F8 SED ;set decimal mode D9AC E0 00 CPX #$00 ;.X register value 0 ? D9AE F0 07 BEQ $D9B7 ;yes, D9B0 18 CLC ;clear carry flags D9B1 69 01 ADC #$01 ;increment .ACC D9B3 CA DEX ;decrement value in .X register D9B4 4C AC D9 JMP $D9AC ;continue with conversion routine ******************************* Convert BCD to ASCII D9B7 D8 CLD ;clear decimal mode D9B8 AA TAX ;transfer BCD value to .X register D9B9 4A LSR D9BA 4A LSR D9BB 4A LSR D9BC 4A LSR D9BD 20 C1 D9 JSR $D9C1 ;convert most significant digit to ASCII D9C0 8A TXA D9C1 29 0F AND #$0F ;erase top 4 bits D9C3 09 30 ORA #$30 ;add 0 D9C5 91 47 STA ($47),Y ;store result in buffer D9C7 C8 INY ;do next part of BCD number D9C8 60 RTS ******************************* Set for OK error message D9C9 20 42 DA JSR $DA42 ;erase error flag D9CC A9 00 LDA #$00 D9CE A0 00 LDY #$00 D9D0 84 13 STY $13 ;set current track to 0 D9D2 84 14 STY $14 ;set current sector to 0 ******************************* Set up error message in error buffer D9D4 A0 00 LDY #$00 D9D6 A2 DC LDX #$DC D9D8 86 47 STX $47 ;set LO byte for error buffer D9DA A2 43 LDX #$43 D9DC 86 48 STX $48 ;set HI byte for error buffer D9DE 20 B8 D9 JSR $D9B8 ;convert error number to ASCII and store in error buffer D9E1 A9 2C LDA #$2C D9E3 91 47 STA ($47),Y ;store comma after error number D9E5 C8 INY D9E6 AD DC 43 LDA $43DC ;read first byte of error number D9E9 85 BC STA $BC ;send to IEEE port D9EB 8A TXA D9EC A2 00 LDX #$00 D9EE 20 DB D8 JSR $D8DB ;transfer error message to error buffer D9F1 A9 2C LDA #$2C D9F3 91 47 STA ($47),Y ;store comma after error message D9F5 C8 INY D9F6 A5 13 LDA $13 ;read track number D9F8 20 A8 D9 JSR $D9A8 ;convert track number to ASCII and store in error buffer D9FB A9 2C LDA #$2C D9FD 91 47 STA ($47),Y ;store comma (,) after error number D9FF C8 INY DA00 A5 14 LDA $14 ;read sector number DA02 20 A8 D9 JSR $D9A8 ;convert sector number to ASCII and store in error buffer DA05 88 DEY DA06 98 TYA ;mark end of error message DA07 18 CLC DA08 69 DC ADC #$DC ;calculate length/end of error message DA0A 85 C4 STA $C4 ;store in Channel Last character pointer DA0C E6 47 INC $47 ;set for IEEE transfer of all bytes in buffer DA0E A9 88 LDA #$88 DA10 85 9F STA $9F ;set channel to TALK DA12 60 RTS ******************************* Mark a sector as free on a track and BAM DA13 20 80 D7 JSR $D780 ;set BAM for current drive DA16 20 AF EB JSR $EBAF ;erase bit for sector in BAM DA19 38 SEC ;block freed ? DA1A D0 0F BNE $DA2B ;yes, DA1C B1 02 LDA ($02),Y ;read current track map from BAM DA1E 1D C9 EB ORA $EBC9,X ;mark sector as free in map DA21 91 02 STA ($02),Y ;store new track map in BAM DA23 A4 04 LDY $04 ;read BLOCK FREE counter DA25 B1 02 LDA ($02),Y ;read current track count DA27 69 00 ADC #$00 ;add free block DA29 91 02 STA ($02),Y ;store new track count DA2B 60 RTS ******************************* Turn on activity LED specified by drive DA2C A9 E7 LDA #$E7 DA2E 2D 82 02 AND $0282 ;erase LED bits: bit 0-2 = device number 3-5 = LED status DA31 48 PHA DA32 A5 12 LDA $12 ;drive 0 under use ? DA34 F0 05 BEQ $DA3B ;yes, DA36 68 PLA DA37 09 08 ORA #$08 ;drive 1 under use ? DA39 D0 03 BNE $DA3E ;yes, DA3B 68 PLA DA3C 09 10 ORA #$10 ;set for LED drive 0 DA3E 8D 82 02 STA $0282 ;turn on specified LED: bit 0-2 = device number 3-5 = LED status DA41 60 RTS ******************************* Turn off error LED DA42 AD 82 02 LDA $0282 ;read LED status: bit 0-2 = device number 3-5 = LED status DA45 29 DF AND #$DF DA47 8D 82 02 STA $0282 ;turn off LED: bit 0-2 = device number 3-5 = LED status DA4A 60 RTS ******************************* Directory loading function, get the buffer and get it started DA4B A9 00 LDA #$00 DA4D 85 16 STA $16 ;set secondary address to 0 DA4F A9 01 LDA #$01 DA51 20 5E EE JSR $EE5E ;set pointer position in appropriate buffer DA54 A9 00 LDA #$00 DA56 20 C1 F0 JSR $F0C1 ;reset buffer to null DA59 A6 15 LDX $15 ;read number of channels DA5B A9 00 LDA #$00 DA5D 95 BD STA $BD,X ;clear pointer to end of buffer entrance DA5F 20 98 FA JSR $FA98 ;get number of buffers chosen DA62 AA TAX DA63 A5 12 LDA $12 ;read current drive number DA65 9D 4E 43 STA $434E,X ;arrange drive table buffer DA68 A9 01 LDA #$01 DA6A 20 B1 EC JSR $ECB1 ;write LO byte of BASIC load location DA6D A9 04 LDA #$04 DA6F 20 B1 EC JSR $ECB1 ;write HI byte of BASIC load location DA72 A9 01 LDA #$01 DA74 20 B1 EC JSR $ECB1 ;write fill byte for line pointer DA77 20 B1 EC JSR $ECB1 ;write fill byte for line pointer DA7A AD 77 43 LDA $4377 ;get drive number DA7D 20 B1 EC JSR $ECB1 ;write as LO byte for line number DA80 A9 00 LDA #$00 DA82 20 B1 EC JSR $ECB1 ;write HI byte for line number DA85 20 03 DB JSR $DB03 ;transfer disk name to buffer DA88 20 98 FA JSR $FA98 ;get current buffer number DA8B 0A ASL ;double, DA8C AA TAX DA8D D6 29 DEC $29,X ;decrement buffer position DA8F D6 29 DEC $29,X ;decrement buffer position DA91 A9 00 LDA #$00 DA93 20 B1 EC JSR $ECB1 ;write end of BASIC DA96 A9 01 LDA #$01 DA98 20 B1 EC JSR $ECB1 ;write BASIC line place holder DA9B 20 B1 EC JSR $ECB1 ;write BASIC line place holder DA9E 20 BF E0 JSR $E0BF ;read entry from directory DAA1 90 2C BCC $DACF ;branch if all entries processed DAA3 AD 77 43 LDA $4377 ;read LO byte of file block count DAA6 20 B1 EC JSR $ECB1 ;write as LO byte of BASIC line number DAA9 AD 78 43 LDA $4378 ;read HI byte of file block count DAAC 20 B1 EC JSR $ECB1 ;write as HI byte of BASIC line number DAAF 20 03 DB JSR $DB03 ;transfer directory entry to buffer DAB2 A9 00 LDA #$00 DAB4 20 B1 EC JSR $ECB1 ;write END-OF-BASIC LINE byte DAB7 D0 DD BNE $DA96 ;continue if buffer memory available DAB9 20 98 FA JSR $FA98 ;read current number of buffers in use DABC 0A ASL ;double current amount DABD AA TAX ;preserve current character pointer DABE A9 00 LDA #$00 DAC0 95 29 STA $29,X ;reset position for current buffer to #$00 DAC2 A9 88 LDA #$88 DAC4 A4 15 LDY $15 ;read current channel number DAC6 8D 46 43 STA $4346 ;set flag to indicate more directory to come DAC9 99 98 00 STA $0098,Y ;set channel mode to read DACC A5 18 LDA $18 ;read data byte DACE 60 RTS ******************************* Build last line of directory DACF AD 77 43 LDA $4377 ;read LO byte of free block count DAD2 20 B1 EC JSR $ECB1 ;write as LO byte of BASIC line number DAD5 AD 78 43 LDA $4378 ;read HI byte of free block count DAD8 20 B1 EC JSR $ECB1 ;write as HI byte of BASIC line number DADB 20 03 DB JSR $DB03 ;write BLOCKS FREE. to buffer DADE 20 98 FA JSR $FA98 ;read current number of buffers in use DAE1 0A ASL ;double current amount DAE2 AA TAX ;preserve current character pointer DAE3 D6 29 DEC $29,X ;decrement pointer position DAE5 D6 29 DEC $29,X ;decrement pointer position DAE7 A9 00 LDA #$00 DAE9 20 B1 EC JSR $ECB1 ;write END-OF-BASIC program byte 1 DAEC 20 B1 EC JSR $ECB1 ;write END-OF-BASIC program byte 2 DAEF 20 B1 EC JSR $ECB1 ;write END-OF-BASIC program byte 3 DAF2 20 98 FA JSR $FA98 ;read current buffer number DAF5 0A ASL ;double current buffer number DAF6 A8 TAY DAF7 B9 29 00 LDA $0029,Y ;read remaining bytes in buffer DAFA A6 15 LDX $15 ;set as pointer to amount of remaining bytes DAFC 95 BD STA $BD,X ;set pointer to last character position DAFE D6 BD DEC $BD,X ;decrement pointer by one DB00 4C B9 DA JMP $DAB9 ;set channel status for exit ******************************* Transmit directory line to current buffer DB03 A0 00 LDY #$00 DB05 B9 B4 41 LDA $41B4,Y ;read character from directory buffer DB08 20 B1 EC JSR $ECB1 ;write to current buffer DB0B C8 INY DB0C C0 1B CPY #$1B ;directory line transmitted ? DB0E D0 F5 BNE $DB05 ;no, DB10 60 RTS ******************************* Get byte from directory DB11 20 B3 ED JSR $EDB3 ;get byte from file, END-OF-FILE ? DB14 F0 01 BEQ $DB17 ;yes, DB16 60 RTS DB17 85 18 STA $18 ;save last data byte DB19 A4 15 LDY $15 ;get number of channels DB1B B9 BD 00 LDA $00BD,Y ;all bytes of data transferred ? DB1E F0 08 BEQ $DB28 ;yes, DB20 A9 80 LDA #$80 ;set for READ/EOI DB22 99 98 00 STA $0098,Y ;set channel status DB25 A5 18 LDA $18 ;get last data byte DB27 60 RTS DB28 48 PHA ;store last data byte DB29 20 96 DA JSR $DA96 ;produce directory line DB2C 68 PLA ;read last data byte DB2D 60 RTS ******************************* Calculate number of free blocks DB2E A6 12 LDX $12 ;read current drive number DB30 BD E8 D2 LDA $D2E8,X ;get high byte pointer for drive BAM DB33 85 05 STA $05 ;store as TEMP1 (buffer pointer HI) DB35 A0 04 LDY #$04 DB37 A9 00 LDA #$00 DB39 85 04 STA $04 ;store as TEMP2 (buffer pointer LO) DB3B AA TAX DB3C 18 CLC DB3D 71 04 ADC ($04),Y ;add free sectors to counter, over #$FF (decimal 255) ? DB3F 90 01 BCC $DB42 ;no, DB41 E8 INX ;increment high byte of counter DB42 C8 INY ;skip FREE sectors on track byte DB43 C8 INY ;skip sectors 0-7 DB44 C8 INY ;skip sectors 8-15 DB45 C8 INY ;skip sectors 16-23 DB46 C0 48 CPY #$48 ;is this track 18 ? DB48 F0 F8 BEQ $DB42 ;yes, DB4A C0 90 CPY #$90 ;is this the last track ? DB4C D0 EE BNE $DB3C ;no, DB4E 8D 77 43 STA $4377 ;store LO byte of free blocks counter DB51 8E 78 43 STX $4378 ;store HI byte of free blocks counter DB54 60 RTS ******************************* Parse and execute string in command buffer DB55 20 C9 D9 JSR $D9C9 ;produce OK error message DB58 A5 17 LDA $17 ;get last secondary address, close command ? DB5A 10 09 BPL $DB65 ;yes, DB5C 29 0F AND #$0F ;set for command channel test DB5E C9 0F CMP #$0F ;is it the command channel DB60 F0 03 BEQ $DB65 ;yes, DB62 4C 79 F2 JMP $F279 ;jump to OPEN a channel routine DB65 20 B0 DC JSR $DCB0 ;set parameters for command processing DB68 B1 45 LDA ($45),Y ;get character from command buffer DB6A 8D 7B 43 STA $437B ;store it DB6D A2 0A LDX #$0A ;set .X register for number of disk commands DB6F BD A1 D2 LDA $D2A1,X ;read possible commands table DB72 CD 7B 43 CMP $437B ;is this the desired command ? DB75 F0 08 BEQ $DB7F ;yes, DB77 CA DEX ;last possible command in table checked ? DB78 10 F5 BPL $DB6F ;no, DB7A A9 31 LDA #$31 ;set for "31 SYNTAX ERROR", invalid command DB7C 4C C3 DB JMP $DBC3 ;jump to process command error routine DB7F 8E 7A 43 STX $437A ;save command number DB82 E0 08 CPX #$08 ;is desired command "RENAME" ? DB84 90 03 BCC $DB89 ;no, DB86 20 E9 DB JSR $DBE9 ;check syntax of command DB89 AE 7A 43 LDX $437A ;get command number DB8C BD AC D2 LDA $D2AC,X ;read LO byte of command jump address DB8F 85 04 STA $04 ;set as TEMP0 DB91 BD B7 D2 LDA $D2B7,X ;read HI byte of command jump address DB94 85 05 STA $05 ;set as TEMP1 DB96 6C 04 00 JMP ($0004) ;jump to calculated command address ******************************* Successful command termination DB99 AD 73 43 LDA $4373 ;is there an error word to recover ? DB9C D0 25 BNE $DBC3 ;yes, DB9E A0 00 LDY #$00 ;set for "OK" message DBA0 98 TYA ******************************* Clear command buffer DBA1 84 13 STY $13 ;set track to #$00 DBA3 84 14 STY $14 ;set sector to #$00 DBA5 84 45 STY $45 ;set LO byte of command buffer to #$00 DBA7 20 D4 D9 JSR $D9D4 ;produce "OK" error message DBAA 20 42 DA JSR $DA42 ;turn off error LED DBAD A5 12 LDA $12 ;read current drive number DBAF 8D 94 43 STA $4394 ;set as last drive without error DBB2 20 B8 DB JSR $DBB8 ;clear command input buffer DBB5 4C D3 F0 JMP $F0D3 ;close internal read/write channels ******************************* Clear command input buffer DBB8 A0 39 LDY #$39 ;set for overwriting of 57 character positions DBBA A9 00 LDA #$00 DBBC 99 00 43 STA $4300,Y ;set position to #$00 DBBF 88 DEY ;all positions done ? DBC0 10 FA BPL $DBBC ;no, DBC2 60 RTS ******************************* Command level error processing DBC3 A0 00 LDY #$00 DBC5 84 13 STY $13 ;set track to #$00 DBC7 84 14 STY $14 ;set sector to #$00 DBC9 4C 53 D9 JMP $D953 ;jump to process error routines ******************************* Simple parser routine DBCC A2 00 LDX #$00 DBCE 8E 80 43 STX $4380 ;clear pointer to drive number position DBD1 A9 3A LDA #$3A DBD3 20 63 DC JSR $DC63 ;has colon (:) character been found ? DBD6 F0 05 BEQ $DBDD ;no, DBD8 88 DEY ;step pointer back to colon (:) DBD9 88 DEY ;step pointer back to drive number DBDA 8C 80 43 STY $4380 ;store position number for drive number DBDD 4C 5E DD JMP $DD5E ;jump to set drive number and turn on LED ******************************* Parse colon DBE0 A0 00 LDY #$00 ;set start position for search DBE2 A2 00 LDX #$00 ;set number of filenames found DBE4 A9 3A LDA #$3A ;set for colon (:) search DBE6 4C 63 DC JMP $DC63 ;search through input command buffer ******************************* Set up command structure image and file stream pointer DBE9 20 E0 DB JSR $DBE0 ;colon (:) in input command buffer found ? DBEC D0 05 BNE $DBF3 ;yes, DBEE A9 34 LDA #$34 ;set for "34 SYNTAX ERROR", no file given DBF0 4C C3 DB JMP $DBC3 ;jump to process command error routine DBF3 88 DEY ;step pointer back to colon (:) DBF4 88 DEY ;step pointer back to drive number DBF5 8C 80 43 STY $4380 ;store position number for drive number DBF8 8A TXA ;has a filename been found ? DBF9 D0 F3 BNE $DBEE ;no, DBFB A9 3D LDA #$3D ;set for equal (=) search DBFD 20 63 DC JSR $DC63 ;search through input command buffer DC00 8A TXA ;has a filename been found ? DC01 F0 02 BEQ $DC05 ;yes, DC03 A9 40 LDA #$40 ;set bit 6 as flag for more files DC05 09 21 ORA #$21 ;set bits 0 & 5 to indicate 1st filename DC07 8D 91 43 STA $4391 ;save bit flag DC0A E8 INX DC0B 8E 7D 43 STX $437D ;set file stream 1 count DC0E 8E 7E 43 STX $437E ;set file stream 2 count DC11 AD 90 43 LDA $4390 ;pattern (* ?) presence flag active ? DC14 F0 0D BEQ $DC23 ;no, DC16 A9 80 LDA #$80 DC18 0D 91 43 ORA $4391 DC1B 8D 91 43 STA $4391 ;set flag in file stream image DC1E A9 00 LDA #$00 DC20 8D 90 43 STA $4390 ;clear search routine wildcard flag DC23 98 TYA ;end of command line found ? DC24 F0 29 BEQ $DC4F ;yes, DC26 9D 80 43 STA $4380,X ;save position of filename DC29 AD 7D 43 LDA $437D ;read file stream 1 count DC2C 8D 7F 43 STA $437F ;set stream as number for second naming DC2F A9 8D LDA #$8D ;set for SHIFTed RETURN search DC31 20 63 DC JSR $DC63 ;search through input command buffer DC34 E8 INX DC35 8E 7E 43 STX $437E ;store current number of commas (,) found DC38 CA DEX DC39 AD 90 43 LDA $4390 ;pattern (* ?) presence flag active ? DC3C F0 02 BEQ $DC40 ;no, DC3E A9 08 LDA #$08 ;set for: 0000 1000 DC40 EC 7D 43 CPX $437D ;any more filenames found ? DC43 F0 02 BEQ $DC47 ;no, DC45 09 04 ORA #$04 ;set filenames after equal (=) flag DC47 09 03 ORA #$03 ;set flag for equal (=) character on hand DC49 4D 91 43 EOR $4391 ;combine previous flags DC4C 8D 91 43 STA $4391 ;set as new syntax flag DC4F AD 91 43 LDA $4391 ;read syntax flag for command DC52 AE 7A 43 LDX $437A ;compare on hand command numbers DC55 3D BB D2 AND $D2BB,X ;does command numbers match allowable syntax ? DC58 D0 01 BNE $DC5B ;no, DC5A 60 RTS DC5B 8D 73 43 STA $4373 ;save incorrect syntax type DC5E A9 30 LDA #$30 ;set for "30 SYNTAX ERROR", general syntax DC60 4C C3 DB JMP $DBC3 ;jump to process command error routine ******************************* Look for special characters DC63 8D 7B 43 STA $437B ;store character to go under parse DC66 CC 79 43 CPY $4379 ;is this the end of the command string ? DC69 B0 2F BCS $DC9A ;yes, DC6B B1 45 LDA ($45),Y ;get character from input command buffer DC6D C8 INY ;set pointer for next character DC6E CD 7B 43 CMP $437B ;character found in input command buffer ? DC71 F0 29 BEQ $DC9C ;yes, DC73 C9 2A CMP #$2A ;is it a pattern match (*) ? DC75 F0 04 BEQ $DC7B ;yes, DC77 C9 3F CMP #$3F ;is it a wildcard (?) ? DC79 D0 03 BNE $DC7E ;no, DC7B EE 90 43 INC $4390 ;set wildcard flag DC7E C9 2C CMP #$2C ;is it a comma (,) ? DC80 D0 E4 BNE $DC66 ;no, DC82 98 TYA ;save comma (,) position DC83 9D 81 43 STA $4381,X ;set start position of next parameter DC86 AD 90 43 LDA $4390 ;read wildcard flag DC89 29 7F AND #$7F ;clear wildcard flag, found a joker ? DC8B F0 08 BEQ $DC95 ;no, DC8D A9 80 LDA #$80 ;set wildcard flag DC8F 9D 86 43 STA $4386,X ;identify name as filename with joker DC92 8D 90 43 STA $4390 ;set wildcard identifier DC95 E8 INX ;increment number of parameters found DC96 E0 04 CPX #$04 ;five files maximum opened ? DC98 90 CC BCC $DC66 ;no, DC9A A0 00 LDY #$00 DC9C AD 79 43 LDA $4379 ;read length of command line DC9F 9D 81 43 STA $4381,X ;save as start position of last parameter DCA2 AD 90 43 LDA $4390 ;get wildcard flag of last filename DCA5 29 7F AND #$7F ;wildcard in parameter on hand ? DCA7 F0 05 BEQ $DCAE ;no, DCA9 A9 80 LDA #$80 ;set wildcard flag DCAB 9D 86 43 STA $4386,X ;identify name as filename with joker DCAE 98 TYA ;set current position in input line DCAF 60 RTS ******************************* Set all flags and look at command string DCB0 A4 45 LDY $45 ;is LO byte of input buffer set to #$00 ? DCB2 F0 14 BEQ $DCC8 ;yes, DCB4 88 DEY ;adjust buffer pointer, #$00 ? DCB5 F0 10 BEQ $DCC7 ;yes, DCB7 B9 00 43 LDA $4300,Y ;get character from buffer DCBA C9 0D CMP #$0D ;is it a RETURN ? DCBC F0 0A BEQ $DCC8 ;yes, DCBE 88 DEY ;step back pointer DCBF B9 00 43 LDA $4300,Y ;get character from buffer DCC2 C9 0D CMP #$0D ;is it a RETURN ? DCC4 F0 02 BEQ $DCC8 ;yes, DCC6 C8 INY ;step pointer foward DCC7 C8 INY ;step pointer foward, back to current position DCC8 8C 79 43 STY $4379 ;save pointer position in command DCCB C0 3B CPY #$3B ;end of command buffer reached ? DCCD A0 FF LDY #$FF ;command line too long ? DCCF 90 08 BCC $DCD9 ;no, DCD1 8C 7A 43 STY $437A ;save incorrect syntax type DCD4 A9 32 LDA #$32 ;set for "32 SYNTAX ERROR", long line DCD6 4C C3 DB JMP $DBC3 ;jump to process command error routine ******************************* Command reset: clear variables, tables DCD9 A0 00 LDY #$00 DCDB 98 TYA DCDC 85 45 STA $45 ;set LO byte of input command buffer DCDE 8D 4B 43 STA $434B ;set record size to #$00 DCE1 85 C5 STA $C5 ;set active file type to #$00 DCE3 8D 9C 43 STA $439C ;set match by type flag to #$00 DCE6 85 81 STA $81 ;set file stream 1 pointer to #$00 DCE8 8D 7F 43 STA $437F ;set file stream 3 count to #$00 DCEB 8D 7D 43 STA $437D ;set file stream 1 count to #$00 DCEE 8D 7E 43 STA $437E ;set file stream 2 count to #$00 DCF1 8D 90 43 STA $4390 ;set pattern presence flag to #$00 DCF4 8D 73 43 STA $4373 ;set error recovery word to #$00 DCF7 A2 05 LDX #$05 DCF9 9D 7F 43 STA $437F,X ;set filename table to #$00 DCFC 95 85 STA $85,X ;set directory table to #$00 DCFE 95 8A STA $8A,X ;set file data table to #$00 DD00 9D 85 43 STA $4385,X ;set track number of file table to #$00 DD03 9D 8A 43 STA $438A,X ;set sector number of file table to #$00 DD06 CA DEX ;maximum five possible files opened, set ? DD07 D0 F0 BNE $DCF9 ;no, DD09 60 RTS ******************************* Set 1st drive and table pointers DD0A AD 7E 43 LDA $437E ;read file stream 2 count DD0D 8D 7D 43 STA $437D ;set as file stream 1 count DD10 A9 01 LDA #$01 DD12 8D 7E 43 STA $437E ;set file stream 2 count to #$01 DD15 8D 7F 43 STA $437F ;set file stream 3 count to #$01 DD18 AC 94 43 LDY $4394 ;read last drive without error ******************************* Set drive number DD1B A2 00 LDX #$00 DD1D 86 81 STX $81 ;set file stream 1 pointer DD1F BD 80 43 LDA $4380,X ;find start position of name in buffer DD22 20 34 DD JSR $DD34 ;get drive number from buffer DD25 A6 81 LDX $81 ;read number of current file parameters DD27 9D 80 43 STA $4380,X ;save position in command string DD2A 98 TYA DD2B 95 8B STA $8B,X ;set drive number for file DD2D E8 INX ;do next file DD2E EC 7E 43 CPX $437E ;all files ready for work ? DD31 90 EA BCC $DD1D ;no, DD33 60 RTS ******************************* Get drive number from command string DD34 AA TAX ;set .X register to position of filename DD35 A9 3A LDA #$3A ;set for colon (:) search DD37 DD 01 43 CMP $4301,X ;is it a colon ? DD3A F0 0C BEQ $DD48 ;yes, DD3C DD 00 43 CMP $4300,X ;pointer pointing at colon (:) ? DD3F D0 16 BNE $DD57 ;no, DD41 E8 INX DD42 98 TYA ;read drive number DD43 29 01 AND #$01 ;find which drive to be active DD45 A8 TAY ;set .Y register as drive to be used DD46 8A TXA ;set .X register to current position in buffer DD47 60 RTS DD48 BD 00 43 LDA $4300,X ;read drive number from command string DD4B E8 INX ;skip drive indicator byte DD4C E8 INX ;skip colon (:) byte DD4D C9 30 CMP #$30 ;is it drive 0 ? DD4F F0 F2 BEQ $DD43 ;yes, DD51 C9 31 CMP #$31 ;is it drive 1 ? DD53 F0 EE BEQ $DD43 ;yes, DD55 D0 EB BNE $DD42 ;incorrect drive number DD57 98 TYA ;transfer drive number found DD58 09 80 ORA #$80 ;set improper drive flag DD5A 29 81 AND #$81 ;is it drive 0 or 1 ? DD5C D0 E7 BNE $DD45 ;no, ******************************* Set drive from any configuration DD5E A9 00 LDA #$00 DD60 8D 91 43 STA $4391 ;clear file stream image flag DD63 AC 80 43 LDY $4380 ;get current position in input buffer DD66 B1 45 LDA ($45),Y ;read character from input buffer DD68 20 B5 DD JSR $DDB5 ;is it a legal drive number ? DD6B 10 12 BPL $DD7F ;yes, DD6D C8 INY ;move pointer in input buffer DD6E CC 79 43 CPY $4379 ;end of command string ? DD71 B0 06 BCS $DD79 ;yes, DD73 AC 79 43 LDY $4379 ;set pointer to end of command string DD76 88 DEY ;last character in input buffer a command ? DD77 D0 ED BNE $DD66 ;no, DD79 CE 91 43 DEC $4391 ;set file stream image to colon (:) position DD7C AD 94 43 LDA $4394 ;read last drive number without error DD7F 29 01 AND #$01 DD81 85 12 STA $12 ;set as current drive number DD83 4C 2C DA JMP $DA2C ;jump to turn on specified LED routine ******************************* Toggle drive number DD86 A5 12 LDA $12 ;read current drive number DD88 49 01 EOR #$01 DD8A 29 01 AND #$01 ;switch drive DD8C 85 12 STA $12 ;set as new drive DD8E 60 RTS ******************************* Set pointer to one file stream and check type DD8F A0 00 LDY #$00 ;set for first filename in table DD91 AD 7D 43 LDA $437D ;read position of filename DD94 CD 7E 43 CMP $437E ;same as file type identifier position DD97 F0 16 BEQ $DDAF ;yes, DD99 CE 7E 43 DEC $437E ;set pointer to file type DD9C AC 7E 43 LDY $437E ;read file type DD9F B9 80 43 LDA $4380,Y ;take pointer to end of filename DDA2 A8 TAY DDA3 B1 45 LDA ($45),Y ;get file type from input buffer DDA5 A0 04 LDY #$04 ;set for test of possible file types DDA7 D9 D4 D2 CMP $D2D4,Y ;is this the correct file type ? DDAA F0 03 BEQ $DDAF ;yes, DDAC 88 DEY ;all possible file types checked ? DDAD D0 F8 BNE $DDA7 ;no, DDAF 98 TYA ;transfer file type DDB0 0A ASL DDB1 8D 9C 43 STA $439C ;set file type flag DDB4 60 RTS ******************************* Test drive number validity DDB5 C9 30 CMP #$30 ;is it drive 0 ? DDB7 F0 06 BEQ $DDBF ;yes DDB9 C9 31 CMP #$31 ;is it drive 1 ? DDBB F0 02 BEQ $DDBF ;yes, DDBD 09 80 ORA #$80 ;set improper drive flag DDBF 29 81 AND #$81 ;set validity status of drive number DDC1 60 RTS ******************************* Auto initialization routine DDC2 A2 FF LDX #$FF DDC4 8E 9E 43 STX $439E ;clear job error flag DDC7 20 DF EC JSR $ECDF ;set head to track 18, sector 0 DDCA C9 03 CMP #$03 ;was SYNC mark located ? DDCC F0 07 BEQ $DDD5 ;yes, DDCE C9 02 CMP #$02 ;was HEADER BLOCK found ? DDD0 90 13 BCC $DDE5 ;yes, DDD2 4C 1C D9 JMP $D91C ;jump to controller error routine DDD5 AC 92 43 LDY $4392 ;has drive number changed ? DDD8 F0 F8 BEQ $DDD2 ;yes, DDDA A9 00 LDA #$00 DDDC 8D 92 43 STA $4392 ;clear active drive search flag DDDF 20 86 DD JSR $DD86 ;toggle drive DDE2 4C C2 DD JMP $DDC2 ;do next drive DDE5 8A TXA DDE6 0A ASL DDE7 0A ASL DDE8 0A ASL DDE9 A8 TAY DDEA A5 12 LDA $12 ;read current drive number DDEC 0A ASL DDED AA TAX DDEE B9 21 10 LDA $1021,Y ;read ID1 from disk DDF1 DD 40 43 CMP $4340,X ;same as in memory ? DDF4 D0 0E BNE $DE04 ;no, DDF6 B9 22 10 LDA $1022,Y ;read ID2 from disk DDF9 DD 41 43 CMP $4341,X ;same as in memory ? DDFC D0 06 BNE $DE04 ;no, DDFE A5 A1 LDA $A1 ;get current job number DE00 20 92 EC JSR $EC92 ;set header for current buffer DE03 60 RTS DE04 4C FA EC JMP $ECFA ;jump to initialize drive routine ******************************* Optimum search for lookup and find file DE07 A9 00 LDA #$00 DE09 85 04 STA $04 ;clear TEMP0 DE0B 8D 93 43 STA $4393 ;clear drive search flag DE0E 48 PHA DE0F AE 7E 43 LDX $437E ;read file stream 2 count DE12 68 PLA DE13 05 04 ORA $04 ;set for last entry DE15 48 PHA DE16 A9 01 LDA #$01 DE18 85 04 STA $04 ;set flag for drive on hand DE1A CA DEX ;filenames counter needs to be checked ? DE1B 30 0F BMI $DE2C ;no, DE1D B5 8B LDA $8B,X ;is file drive number set ? DE1F 10 04 BPL $DE25 ;yes, DE21 06 04 ASL $04 DE23 06 04 ASL $04 ;adjust drive flag byte DE25 4A LSR ;drive 1 chosen ? DE26 90 EA BCC $DE12 ;no, DE28 06 04 ASL $04 ;is search to be done from drive 1 ? DE2A D0 E6 BNE $DE12 ;no, DE2C 68 PLA DE2D AA TAX DE2E BD 60 DE LDA $DE60,X ;get access control byte DE31 48 PHA DE32 29 03 AND #$03 ;determine allowable drives DE34 8D 92 43 STA $4392 ;set number of possible drive searches DE37 68 PLA DE38 0A ASL ;is this the correct drive ? DE39 10 22 BPL $DE5D ;no, DE3B A5 8B LDA $8B ;read drive number for first file DE3D 29 01 AND #$01 DE3F 85 12 STA $12 ;set as current drive DE41 AD F3 10 LDA $10F3 ;is automatic initialization flag set ? DE44 D0 14 BNE $DE5A ;yes, DE46 20 C2 DD JSR $DDC2 ;initialize current drive DE49 AD 92 43 LDA $4392 ;is drive available ? DE4C F0 0C BEQ $DE5A ;yes, DE4E A5 12 LDA $12 ;read current drive number DE50 48 PHA DE51 20 86 DD JSR $DD86 ;switch drive number DE54 20 C2 DD JSR $DDC2 ;initialize current drive DE57 68 PLA DE58 85 12 STA $12 ;read current drive number DE5A 4C 2C DA JMP $DA2C ;jump to turn on LED for current drive DE5D 2A ROL DE5E 4C 3D DE JMP $DE3D ;proceed to set control byte for another drive ******************************* Search table: bits 0-1: number of drives bit 6: take control byte for drive number bit 7: drive number of control byte DE61 00 ??? DE62 80 ??? DE63 41 ??? DE64 01 ??? DE65 01 ??? DE66 01 ??? DE67 01 ??? DE68 81 ??? DE69 81 ??? DE6A 81 ??? DE6B 81 ??? DE6C 42 ??? DE6D 42 ??? DE6E 42 ??? DE6F 42 ??? ******************************* Lookup files in stream and fill tables with information DE70 20 07 DE JSR $DE07 ;set drive for file to search DE73 A9 00 LDA #$00 DE75 8D 98 43 STA $4398 ;clear index of first available entry DE78 20 D0 DF JSR $DFD0 ;is indicator for search entry set ? DE7B D0 1A BNE $DE97 ;yes, DE7D CE 92 43 DEC $4392 ;another drive available for check ? DE80 10 01 BPL $DE83 ;yes, DE82 60 RTS ******************************* Toggle to lookup other drive DE83 A9 01 LDA #$01 DE85 8D 93 43 STA $4393 ;set drive search flag for other drive DE88 20 86 DD JSR $DD86 ;switch to other drive DE8B 20 2C DA JSR $DA2C ;turn on LED for drive DE8E F0 E3 BEQ $DE73 ;no, unavailable drive DE90 D0 E1 BNE $DE73 ;no, incorrect drive DE92 20 39 E0 JSR $E039 ;found filename for search ? DE95 F0 10 BEQ $DEA7 ;no, DE97 20 FA DE JSR $DEFA ;search for number of filename patterns DE9A AD 95 43 LDA $4395 ;store number of times pattern occurred DE9D F0 01 BEQ $DEA0 ;all files not found yet, DE9F 60 RTS DEA0 AD 45 43 LDA $4345 ;file found ? DEA3 30 ED BMI $DE92 ;no, DEA5 10 F0 BPL $DE97 ;yes, DEA7 AD 95 43 LDA $4395 ;is flag for file found ? DEAA F0 D1 BEQ $DE7D ;yes, DEAC 60 RTS ******************************* Find next file name matching any file in stream & return with entry found in table DEAD 20 27 E0 JSR $E027 ;has file been found in directory ? DEB0 F0 1A BEQ $DECC ;no, DEB2 D0 28 BNE $DEDC ;yes, DEB4 A9 01 LDA #$01 DEB6 8D 93 43 STA $4393 ;set for access on both drives DEB9 20 86 DD JSR $DD86 ;toggle drive DEBC 20 2C DA JSR $DA2C ;activate LED DEBF A9 00 LDA #$00 DEC1 8D 98 43 STA $4398 ;reset index for 1st available entry DEC4 20 D0 DF JSR $DFD0 ;has file been found ? DEC7 D0 13 BNE $DEDC ;yes, DEC9 8D 95 43 STA $4395 ;set file found flag DECC AD 95 43 LDA $4395 ;last entry of directory ? DECF D0 28 BNE $DEF9 ;no, DED1 CE 92 43 DEC $4392 ;all drives searched ? DED4 10 DE BPL $DEB4 ;yes, DED6 60 RTS ******************************* Find directory entry and file type DED7 20 39 E0 JSR $E039 ;is there another directory entry ? DEDA F0 F0 BEQ $DECC ;no, DEDC 20 FA DE JSR $DEFA ;very entry with searched flag DEDF AE 45 43 LDX $4345 ;is this the correct entry ? DEE2 10 07 BPL $DEEB ;yes, DEE4 AD 95 43 LDA $4395 ;directory still available for search ? DEE7 F0 EE BEQ $DED7 ;yes, DEE9 D0 0E BNE $DEF9 ;no, DEEB AD 9C 43 LDA $439C ;is there a file type ? DEEE F0 09 BEQ $DEF9 ;no, DEF0 B5 8B LDA $8B,X ;read file type for directory entry DEF2 29 1E AND #$1E DEF4 CD 9C 43 CMP $439C ;same as requested file type ? DEF7 D0 DE BNE $DED7 ;no, DEF9 60 RTS ******************************* Compare file names in stream table with the disk directory DEFA A2 FF LDX #$FF DEFC 8E 45 43 STX $4345 ;clear entry flag DEFF E8 INX DF00 8E 90 43 STX $4390 ;clear wildcard flag DF03 20 AF DF JSR $DFAF ;is unfound files table empty ? DF06 F0 06 BEQ $DF0E ;no, DF08 60 RTS DF09 20 BA DF JSR $DFBA ;does unfound files table need to be scanned ? DF0C D0 FA BNE $DF08 ;no, DF0E A5 12 LDA $12 ;read current drive number DF10 55 8B EOR $8B,X DF12 4A LSR ;same as drive number as file entry DF13 90 0B BCC $DF20 ;yes, DF15 29 40 AND #$40 ;default drive ? DF17 F0 F0 BEQ $DF09 ;no, DF19 A9 02 LDA #$02 DF1B CD 92 43 CMP $4392 ;both drives need to be scanned ? DF1E F0 E9 BEQ $DF09 ;yes, DF20 BD 80 43 LDA $4380,X ;read position of file name DF23 AA TAX DF24 20 97 E0 JSR $E097 ;find limit of command string DF27 A0 03 LDY #$03 DF29 4C 3F DF JMP $DF3F ;verify names with command string DF2C BD 00 43 LDA $4300,X ;read character from command buffer DF2F D1 27 CMP ($27),Y ;equal to contents of directory buffer ? DF31 F0 0A BEQ $DF3D ;yes, DF33 C9 3F CMP #$3F ;is it a wildcard (?) ? DF35 D0 D2 BNE $DF09 ;no, DF37 B1 27 LDA ($27),Y ;read character from directory buffer DF39 C9 A0 CMP #$A0 ;end of filename ? DF3B F0 CC BEQ $DF09 ;yes, DF3D E8 INX DF3E C8 INY DF3F EC 7C 43 CPX $437C ;has limit been reached ? DF42 B0 09 BCS $DF4D ;yes, DF44 BD 00 43 LDA $4300,X ;read character from command buffer DF47 C9 2A CMP #$2A ;is it a wildcard (*) ? DF49 F0 0C BEQ $DF57 ;yes, DF4B D0 DF BNE $DF2C ;no, DF4D C0 13 CPY #$13 ;is ASCII code smaller than RETURN code ? DF4F B0 06 BCS $DF57 ;no, DF51 B1 27 LDA ($27),Y ;read character from directory buffer DF53 C9 A0 CMP #$A0 ;end of filename ? DF55 D0 B2 BNE $DF09 ;no, DF57 AE 7F 43 LDX $437F ;read position of directory entry DF5A 8E 45 43 STX $4345 ;set file found flag DF5D BD 86 43 LDA $4386,X ;find file entry point DF60 29 80 AND #$80 ;set for pattern matching flag DF62 8D 90 43 STA $4390 ;set pattern present flag DF65 9D 86 43 STA $4386,X ;set for filename in table DF68 AD 9A 43 LDA $439A ;read first sector location of filename DF6B 29 E0 AND #$E0 DF6D 85 04 STA $04 ;store in TEMP4 DF6F A5 14 LDA $14 ;read current sector number DF71 05 04 ORA $04 DF73 95 86 STA $86,X ;set directory position of filename DF75 A0 00 LDY #$00 DF77 B1 27 LDA ($27),Y ;get file type DF79 C8 INY ;increment buffer pointer DF7A 48 PHA ;store original file type DF7B 29 40 AND #$40 ;isolate status of scratch protect mode DF7D 85 04 STA $04 ;store scratch protect status DF7F 68 PLA ;recall file type DF80 0A ASL DF81 29 1E AND #$1E ;file type properly closed ? DF83 B0 02 BCS $DF87 ;yes, DF85 09 20 ORA #$20 ;set for unclosed file type DF87 05 04 ORA $04 ;set for calculated file type DF89 85 04 STA $04 ;set new file type status DF8B A9 80 LDA #$80 ;set wildcard flag DF8D 35 8B AND $8B,X ;read current file type data DF8F 05 12 ORA $12 ;set for proper drive DF91 05 04 ORA $04 ;fade in bits from new filetypes DF93 95 8B STA $8B,X ;save as new file type data DF95 B1 27 LDA ($27),Y ;get track number for current file DF97 1D 86 43 ORA $4386,X DF9A 9D 86 43 STA $4386,X ;store result in track table DF9D C8 INY DF9E B1 27 LDA ($27),Y ;get sector number for current file DFA0 9D 8B 43 STA $438B,X ;store result in sector table DFA3 AD 4B 43 LDA $434B ;file has determined record lengths ? DFA6 D0 07 BNE $DFAF ;yes, DFA8 A0 15 LDY #$15 ;set for record length byte DFAA B1 27 LDA ($27),Y ;read current record length DFAC 8D 4B 43 STA $434B ;set as current record length ******************************* Check table of unfound files DFAF A9 FF LDA #$FF DFB1 8D 95 43 STA $4395 ;set found flag to zero DFB4 AD 7E 43 LDA $437E ;read current position of directory entry DFB7 8D 7F 43 STA $437F ;store as current position of directory entry DFBA CE 7F 43 DEC $437F ;another directory entry to process ? DFBD 10 01 BPL $DFC0 ;yes, DFBF 60 RTS DFC0 AE 7F 43 LDX $437F ;get number of filename DFC3 BD 86 43 LDA $4386,X ;file type found ? DFC6 30 02 BMI $DFCA ;no, DFC8 D0 F0 BNE $DFBA ;yes, DFCA A9 00 LDA #$00 DFCC 8D 95 43 STA $4395 ;set last file in directory DFCF 60 RTS ******************************* Search directory: returns with valid entry DFD0 A0 00 LDY #$00 DFD2 8C 97 43 STY $4397 ;set deleted sector to #$00 DFD5 88 DEY DFD6 8C 45 43 STY $4345 ;set directory entry found to #$ff DFD9 A9 12 LDA #$12 DFDB 85 13 STA $13 ;set for track 18 DFDD A9 01 LDA #$01 DFDF 85 14 STA $14 ;set for sector 1 DFE1 8D 99 43 STA $4399 ;set for last buffer used DFE4 20 6C F0 JSR $F06C ;open internal channel for read DFE7 AD 99 43 LDA $4399 ;is there another sector ? DFEA D0 01 BNE $DFED ;yes, DFEC 60 RTS DFED A9 07 LDA #$07 DFEF 8D 9B 43 STA $439B ;set for amount of file entries per block DFF2 A9 00 LDA #$00 DFF4 20 EF F0 JSR $F0EF ;read byte from buffer DFF7 8D 99 43 STA $4399 ;store in next block byte DFFA 20 E1 F0 JSR $F0E1 ;set active buffer pointer DFFD CE 9B 43 DEC $439B ;process next directory entry E000 A0 00 LDY #$00 E002 B1 27 LDA ($27),Y ;get file type, deleted ? E004 D0 18 BNE $E01E ;no, E006 AD 97 43 LDA $4397 ;deleted entry found ? E009 D0 2E BNE $E039 ;yes, E00B 20 3E F9 JSR $F93E ;read current sector E00E A5 14 LDA $14 ;read current sector number E010 8D 97 43 STA $4397 ;set as sector number for file E013 A5 27 LDA $27 ;get current index E015 AE 98 43 LDX $4398 ;read index for 1st available entry E018 8D 98 43 STA $4398 ;was index deleted before ? E01B F0 1C BEQ $E039 ;yes, E01D 60 RTS E01E A2 01 LDX #$01 E020 EC 98 43 CPX $4398 ;looking for deleted entry ? E023 D0 2C BNE $E051 ;no, E025 F0 12 BEQ $E039 ;yes, E027 A9 12 LDA #$12 E029 85 13 STA $13 ;set for track 18 E02B AD 96 43 LDA $4396 ;read sector number E02E 85 14 STA $14 ;set as current sector number E030 20 6C F0 JSR $F06C ;open internal read channel (secondary addr=17) E033 AD 9A 43 LDA $439A ;read current index buffer E036 20 C1 F0 JSR $F0C1 ;set buffer pointer ******************************* Continue file entry search E039 A9 FF LDA #$FF E03B 8D 45 43 STA $4345 ;clear entry found flag E03E AD 9B 43 LDA $439B ;all file entries in block processed ? E041 30 08 BMI $E04B ;yes, E043 A9 20 LDA #$20 ;set number of bytes per file entry E045 20 42 EE JSR $EE42 ;move to next file entry E048 4C FA DF JMP $DFFA ;process next file entry E04B 20 44 F0 JSR $F044 ;read next block from directory E04E 4C E7 DF JMP $DFE7 ;process next directory sector E051 A5 27 LDA $27 ;read directory buffer pointer E053 8D 9A 43 STA $439A ;set as current index pointer E056 20 3E F9 JSR $F93E ;get header block E059 A5 14 LDA $14 ;read current sector number E05B 8D 96 43 STA $4396 ;store as current directory sector E05E 60 RTS ******************************* Transfer filename from command buffer .X = starting index in buffer .Y = buffer number .ACC = string size E05F 48 PHA ;store length of filename E060 20 97 E0 JSR $E097 ;find position of name in input string E063 20 79 E0 JSR $E079 ;determine and copy name in buffer E066 68 PLA ;recall length of filename E067 38 SEC E068 ED 3A 43 SBC $433A ;substract from allowed string length E06B AA TAX ;does string need padding ? E06C F0 0A BEQ $E078 ;no, E06E 90 08 BCC $E078 ;no, E070 A9 A0 LDA #$A0 E072 91 27 STA ($27),Y ;store SHIFTED SPACE in buffer E074 C8 INY ;increment file name length counter E075 CA DEX ;another SHIFTED SPACE needed ? E076 D0 FA BNE $E072 ;yes, E078 60 RTS ******************************* Transfer command buffer to other buffer .X = starting index in command buffer .Y = buffer number E079 98 TYA ;set .ACC equal to current buffer number E07A 0A ASL ;double buffer number E07B A8 TAY ;set .Y register as new buffer number E07C B9 29 00 LDA $0029,Y ;read LO byte in buffer table E07F 85 27 STA $27 ;set as low byte for directory buffer E081 B9 2A 00 LDA $002A,Y ;read HI byte in buffer table E084 85 28 STA $28 ;set as high byte for directory buffer E086 A0 00 LDY #$00 E088 BD 00 43 LDA $4300,X ;read byte from input buffer E08B 91 27 STA ($27),Y ;store in assigned directory buffer E08D C8 INY ;all bytes read ? E08E F0 06 BEQ $E096 ;yes, E090 E8 INX E091 EC 7C 43 CPX $437C ;another command byte to be read ? E094 90 F2 BCC $E088 ;yes, E096 60 RTS ******************************* Find limit of string in command buffer .X = end of string pointer E097 A9 00 LDA #$00 E099 8D 3A 43 STA $433A ;set string size to #$00 E09C 8A TXA ;transfer start position pointer to .ACC E09D 48 PHA E09E BD 00 43 LDA $4300,X ;get character from command buffer E0A1 C9 2C CMP #$2C ;is it a comma (,) ? E0A3 F0 14 BEQ $E0B9 ;yes, E0A5 C9 3D CMP #$3D ;is it an equal (=) ? E0A7 F0 10 BEQ $E0B9 ;yes, E0A9 EE 3A 43 INC $433A ;increment size pointer E0AC E8 INX ;do next next character E0AD A9 0F LDA #$0F E0AF CD 3A 43 CMP $433A ;has maximum file name length been reached ? E0B2 90 05 BCC $E0B9 ;yes, E0B4 EC 79 43 CPX $4379 ;end of command string been reached ? E0B7 90 E5 BCC $E09E ;no, E0B9 8E 7C 43 STX $437C ;set limit for command string E0BC 68 PLA E0BD AA TAX ;retrieve start position pointer E0BE 60 RTS ******************************* Get file entry from directory E0BF A5 16 LDA $16 ;read current secondary address E0C1 48 PHA ;preserve it E0C2 A5 15 LDA $15 ;read current number of active channels E0C4 48 PHA ;preserve it E0C5 20 CF E0 JSR $E0CF ;get file entry E0C8 68 PLA ;retrieve active channels E0C9 85 15 STA $15 ;restore E0CB 68 PLA ;retrieve secondary address E0CC 85 16 STA $16 ;restore E0CE 60 RTS ******************************* Get directory entry E0CF A9 11 LDA #$11 E0D1 85 16 STA $16 ;set secondary address to #$11 (decimal 17) E0D3 20 69 ED JSR $ED69 ;set read channel E0D6 20 E1 F0 JSR $F0E1 ;read active buffer pointer E0D9 AD 45 43 LDA $4345 ;directory entry found ? E0DC 10 0C BPL $E0EA ;yes, E0DE AD 93 43 LDA $4393 ;drive search flag for both drives active ? E0E1 D0 0C BNE $E0EF ;yes, E0E3 20 F0 E1 JSR $E1F0 ;get BLOCKS FREE message and write to buffer E0E6 18 CLC E0E7 4C 9E E1 JMP $E19E ;exit - end of directory E0EA AD 93 43 LDA $4393 ;drive search flag for both drives active ? E0ED F0 1F BEQ $E10E ;yes, E0EF CE 93 43 DEC $4393 ;drive search flag now inactive ? E0F2 D0 0D BNE $E101 ;no, E0F4 CE 93 43 DEC $4393 ;set drive search flag to inactive E0F7 20 86 DD JSR $DD86 ;change to other drive E0FA 20 F0 E1 JSR $E1F0 ;get BLOCKS FREE message and write to buffer E0FD 38 SEC E0FE 4C 86 DD JMP $DD86 ;change to other drive E101 A9 00 LDA #$00 E103 8D 78 43 STA $4378 ;set HI byte of blocks free count to #$00 E106 8D 93 43 STA $4393 ;set drive search flag to #$00 E109 20 AA E1 JSR $E1AA ;get new directory listing E10C 38 SEC E10D 60 RTS E10E A2 18 LDX #$18 ;length of directory line is #$18 (decimal 24) E110 A0 1D LDY #$1D ;set directory padding to #$1D (decimal 29) E112 B1 27 LDA ($27),Y ;read HI byte of file block count E114 8D 78 43 STA $4378 ;is HI block count for this file name #$00 ? E117 F0 02 BEQ $E11B ;yes, E119 A2 16 LDX #$16 ;set .X register to directory length minus 2 E11B 88 DEY ;set for LO byte of block count E11C B1 27 LDA ($27),Y ;read LO byte of file block count E11E 8D 77 43 STA $4377 ;set as LO block count for file name E121 E0 16 CPX #$16 ;is file length #$16 (decimal 22) ? E123 F0 0A BEQ $E12F ;yes, E125 C9 0A CMP #$0A ;is file length #$0A (decimal 10) ? E127 90 06 BCC $E12F ;yes, E129 CA DEX ;decrement length of file entry E12A C9 64 CMP #$64 ;is length #$64 (decimal 100) ? E12C 90 01 BCC $E12F ;yes, E12E CA DEX ;remove SHIFTED SPACE E12F 20 9F E1 JSR $E19F ;delete buffer for directory E132 B1 27 LDA ($27),Y ;read file type E134 48 PHA E135 0A ASL ;is file locked ? E136 10 05 BPL $E13D ;no, E138 A9 3C LDA #$3C ;set .ACC for locked file indicator (<) E13A 9D B5 41 STA $41B5,X ;store after file type E13D 68 PLA E13E 29 0F AND #$0F ;mask off higher bits of file type E140 A8 TAY E141 B9 DE D2 LDA $D2DE,Y ;get 3rd character of file type abbreviation E144 9D B4 41 STA $41B4,X ;build short name for directory purpose E147 CA DEX E148 B9 D9 D2 LDA $D2D9,Y ;get 2nd character of file type abbreviation E14B 9D B4 41 STA $41B4,X ;continue building short name for directory E14E CA DEX E14F B9 D4 D2 LDA $D2D4,Y ;get 1st character of file type abbreviation E152 9D B4 41 STA $41B4,X ;finish building short name for directory E155 CA DEX E156 CA DEX ;is file properly closed ? E157 B0 05 BCS $E15E ;yes, E159 A9 2A LDA #$2A ;set .ACC for unclosed file indicator (*) E15B 9D B5 41 STA $41B5,X ;store before file type E15E A9 A0 LDA #$A0 E160 9D B4 41 STA $41B4,X ;store a SHIFTED SPACE for padding E163 CA DEX E164 A0 12 LDY #$12 ;set for buffer position of file name E166 B1 27 LDA ($27),Y ;read character for file name E168 9D B4 41 STA $41B4,X ;store in directory buffer E16B CA DEX E16C 88 DEY E16D C0 03 CPY #$03 ;all characters in file name transferred ? E16F B0 F5 BCS $E166 ;no, E171 A9 22 LDA #$22 ;set .ACC for a quotation mark (") E173 9D B4 41 STA $41B4,X ;store before file name E176 E8 INX E177 E0 20 CPX #$20 ;last character in file name ? E179 B0 0B BCS $E186 ;yes, E17B BD B4 41 LDA $41B4,X ;read next character from directory buffer E17E C9 22 CMP #$22 ;is character a quotation mark (") ? E180 F0 04 BEQ $E186 ;yes, E182 C9 A0 CMP #$A0 ;is character a SHIFTED SPACE ? E184 D0 F0 BNE $E176 ;no, E186 A9 22 LDA #$22 ;set .ACC for a quotation mark (") ? E188 9D B4 41 STA $41B4,X ;store at end of file name E18B E8 INX E18C E0 20 CPX #$20 ;last character in file name ? E18E B0 0A BCS $E19A ;yes, E190 A9 7F LDA #$7F E192 3D B4 41 AND $41B4,X ;disable reverse video effect for character E195 9D B4 41 STA $41B4,X ;another character to process ? E198 10 F1 BPL $E18B ;yes, E19A 20 D7 DE JSR $DED7 ;find directory entry and file type E19D 38 SEC ;set flag for more entries to be done E19E 60 RTS ******************************* Clear name buffer E19F A0 1B LDY #$1B ;set length of name buffer (decimal 27) E1A1 A9 20 LDA #$20 ;character to blank buffer with (decimal 32) E1A3 99 B3 41 STA $41B3,Y ;set position in name buffer to blank E1A6 88 DEY ;last character in name buffer blanked ? E1A7 D0 FA BNE $E1A3 ;no, E1A9 60 RTS ******************************* New directory listing E1AA 20 9F E1 JSR $E19F ;clear name buffer E1AD A9 FF LDA #$FF E1AF 85 04 STA $04 ;set TEMP4 to #$FF (decimal 255) E1B1 A6 12 LDX $12 ;read current drive E1B3 8E 77 43 STX $4377 ;set as temporary number of blocks E1B6 A9 00 LDA #$00 E1B8 8D 78 43 STA $4378 ;set HI byte of temporary block count to #$00 E1BB BD E8 D2 LDA $D2E8,X ;read BAM pointer for selected drive E1BE 85 28 STA $28 ;set as current BAM to use E1C0 A9 90 LDA #$90 ;set LO byte of buffer pointer E1C2 85 27 STA $27 ;set for use with BAM pointer E1C4 A0 16 LDY #$16 ;set for length of diskette name E1C6 B1 27 LDA ($27),Y ;read byte from BAM E1C8 C9 A0 CMP #$A0 ;is it a SHIFTED SPACE ? E1CA D0 0B BNE $E1D7 ;no, E1CC A9 31 LDA #$31 ;set for ASCII version "1" E1CE 2C ??? ;comma (,) ** also becomes patch: E1CE 2C B1 27 BIT $27B1 E1CF B1 27 LDA ($27),Y ;read byte from BAM E1D1 C9 A0 CMP #$A0 ;is it a SHIFTED SPACE ? E1D3 D0 02 BNE $E1D7 ,no, E1D5 A9 20 LDA #$20 E1D7 99 B6 41 STA $41B6,Y ;store a blank in directory buffer E1DA 88 DEY ;another byte to read ? E1DB 10 F2 BPL $E1CF ;yes, E1DD A9 12 LDA #$12 ;set for REVERSE VIDEO code E1DF 8D B4 41 STA $41B4 ;store in directory buffer E1E2 A9 22 LDA #$22 ;set for quotation mark (") E1E4 8D B5 41 STA $41B5 ;store in directory buffer E1E7 8D C6 41 STA $41C6 ;store at end of diskette name also E1EA A9 20 LDA #$20 E1EC 8D C7 41 STA $41C7 ;store blank after end quote E1EF 60 RTS ******************************* Display BLOCKS FREE. message E1F0 20 9F E1 JSR $E19F ;clear name buffer E1F3 A0 0B LDY #$0B ;set for length of last line message E1F5 B9 01 E2 LDA $E201,Y ;read byte from memory E1F8 99 B4 41 STA $41B4,Y ;build BLOCKS FREE. message and send to buffer E1FB 88 DEY ;all characters transferred ? E1FC 10 F7 BPL $E1F5 ;no, E1FE 4C 2E DB JMP $DB2E ;jump to calculate number of blocks free ******************************* BLOCKS FREE. message E201 42 4C 4F 43 4B 53 ;blocks E207 20 46 52 45 45 2E ; free. ******************************* Command: NEW (format diskette) E20D 20 0A DD JSR $DD0A ;set 1st drive and table pointers E210 A5 8B LDA $8B ;is drive valid ? E212 10 05 BPL $E219 ;yes, E214 A9 33 LDA #$33 ;set for "33 SYNTAX ERROR", invalid file name E216 4C C3 DB JMP $DBC3 ;jump to process command error routine E219 29 01 AND #$01 E21B 85 12 STA $12 ;set as current drive number E21D 20 2C DA JSR $DA2C ;turn on LED for specified drive E220 20 80 D7 JSR $D780 ;set BAM pointer for active drive E223 A5 12 LDA $12 ;read current drive number E225 0A ASL E226 AA TAX E227 AC 81 43 LDY $4381 ;read length in command table E22A CC 79 43 CPY $4379 ;command NEW or clear ? E22D F0 16 BEQ $E245 ;clear, E22F B9 00 43 LDA $4300,Y ;read disk ID1 from command buffer E232 9D 40 43 STA $4340,X ;set as current ID1 for formatting E235 B9 01 43 LDA $4301,Y ;read disk ID2 from command buffer E238 9D 41 43 STA $4341,X ;set as current ID2 for formatting E23B A9 01 LDA #$01 E23D 85 13 STA $13 ;set track equal to #$01 E23F 20 16 E4 JSR $E416 ;jump to format diskette routine E242 4C 54 E2 JMP $E254 ;jump to set BAM routine ******************************* Initialize drive with version number E245 20 FA EC JSR $ECFA ;initialize diskette in drive E248 A0 02 LDY #$02 E24A B1 02 LDA ($02),Y ;read current DOS version of diskette E24C CD 9F 10 CMP $109F ;diskette formatted on this type of drive ? E24F F0 03 BEQ $E254 ;yes, E251 4C 80 F1 JMP $F180 ;jump to process wrong version error ******************************* Initialize track 18, 0: byte 00 - 01: next T & S 02 : DOS version 03 : 04 - 143: BAM for all tracks 144 - 161: diskette name 164 : SHIFTED SPACE 165 - 166: DOS type identifier Initialize track 18, 1: first directory block E254 A9 00 LDA #$00 E256 A8 TAY E257 91 02 STA ($02),Y ;clear BAM buffer E259 C8 INY ;entire buffer cleared ? E25A D0 FB BNE $E257 ;no, E25C A5 12 LDA $12 ;read current drive number E25E 18 CLC E25F 69 0C ADC #$0C E261 85 A1 STA $A1 ;set current job to: #$0D (decimal 13/drive 0) #$0E (decimal 14/drive 1) E263 0A ASL E264 AA TAX E265 A9 90 LDA #$90 E267 95 29 STA $29,X ;set for buffer offset of 144 bytes E269 A0 01 LDY #$01 E26B 84 14 STY $14 ;set for sector #$01 (decimal 1) E26D A9 FF LDA #$FF E26F 91 02 STA ($02),Y ;write #$FF (decimal 255) to second position in track 18, sector 1 E271 A9 12 LDA #$12 E273 85 13 STA $13 ;set for track #$12 (decimal 18) E275 20 5B F0 JSR $F05B ;clear directory entries for trk, 18, sctr 1 E278 20 6F E7 JSR $E76F ;create new Block Allocation Map E27B A0 02 LDY #$02 E27D AD 9F 10 LDA $109F ;read DOS VERSION E280 91 02 STA ($02),Y ;store DOS VERSION E282 20 9A EB JSR $EB9A ;mark track, sector, BAM pointer as used E285 C6 14 DEC $14 ;set for sector 0 of track 18 E287 20 9A EB JSR $EB9A ;mark track, sector, BAM pointer as used E28A A4 A1 LDY $A1 ;read current job number E28C AE 80 43 LDX $4380 ;read file table length E28F A9 1B LDA #$1B E291 20 5F E0 JSR $E05F ;transfer diskette name to buffer E294 A0 12 LDY #$12 ;set for buffer offset of 18 bytes E296 A5 12 LDA $12 ;read current drive number E298 0A ASL E299 AA TAX E29A BD 40 43 LDA $4340,X ;read disk ID1 E29D 91 27 STA ($27),Y ;store in directory buffer E29F C8 INY E2A0 BD 41 43 LDA $4341,X ;read disk ID2 E2A3 91 27 STA ($27),Y ;store in directory buffer E2A5 C8 INY E2A6 C8 INY E2A7 A9 32 LDA #$32 E2A9 91 27 STA ($27),Y ;store DOS TYPE ("2") in directory buffer E2AB C8 INY E2AC AD 9F 10 LDA $109F ;read current DOS VERSION ("A") number E2AF 91 27 STA ($27),Y ;store in directory buffer E2B1 20 5B F0 JSR $F05B ;write to disk E2B4 4C 99 DB JMP $DB99 ;jump to send "00, OK, 00, 00" message ******************************* Command: SCRATCH (erase files) E2B7 20 8F DD JSR $DD8F ;set pointer to one file stream and check type E2BA 20 18 DD JSR $DD18 ;set current drive number E2BD 20 07 DE JSR $DE07 ;set optimum search for lookup and find file E2C0 A9 00 LDA #$00 E2C2 85 19 STA $19 ;set file count to #$00 E2C4 20 BF DE JSR $DEBF ;another entry found ? E2C7 30 3F BMI $E308 ;no, E2C9 20 C2 F8 JSR $F8C2 ;file currently under use ? E2CC 90 35 BCC $E303 ;yes, E2CE A0 00 LDY #$00 E2D0 B1 27 LDA ($27),Y ;read file type from directory E2D2 29 40 AND #$40 ;is this file locked ? E2D4 D0 2D BNE $E303 ;yes, E2D6 20 3B E3 JSR $E33B ;delete directory entry E2D9 A0 13 LDY #$13 E2DB B1 27 LDA ($27),Y ;pointer for side sector active ? E2DD F0 0A BEQ $E2E9 ;no, E2DF 85 13 STA $13 ;set as new track E2E1 C8 INY E2E2 B1 27 LDA ($27),Y ;get side sector number E2E4 85 14 STA $14 ;set as current sector E2E6 20 13 E3 JSR $E313 ;delete by links and free blocks E2E9 AE 45 43 LDX $4345 ;read entry found flag E2EC A9 20 LDA #$20 E2EE 35 8B AND $8B,X ;file not closed properly ? E2F0 D0 0F BNE $E301 ;yes, E2F2 BD 86 43 LDA $4386,X ;read next track of file E2F5 29 7F AND #$7F ;disable pattern matching flag E2F7 85 13 STA $13 ;set as current track number E2F9 BD 8B 43 LDA $438B,X ;read next sector location of file E2FC 85 14 STA $14 ;set as current sector number E2FE 20 13 E3 JSR $E313 ;delete by links and free blocks E301 E6 19 INC $19 ;increment file count E303 20 AD DE JSR $DEAD ;another file name to delete ? E306 10 C1 BPL $E2C9 ;yes, E308 A5 19 LDA $19 ;read file count E30A 85 13 STA $13 ;set as current track number E30C A9 01 LDA #$01 E30E A0 00 LDY #$00 E310 4C A3 DB JMP $DBA3 ;jump to produce "FILES SCRATCHED" message ******************************* Delete file by links E313 20 13 DA JSR $DA13 ;mark sector as free on track and BAM E316 20 6C F0 JSR $F06C ;open internal read channel E319 A9 00 LDA #$00 E31B 20 C1 F0 JSR $F0C1 ;set pointer E31E 20 D2 ED JSR $EDD2 ;read byte from file E321 85 13 STA $13 ;set as current track number E323 20 D2 ED JSR $EDD2 ;read byte from file E326 85 14 STA $14 ;set as current sector number E328 A5 13 LDA $13 ;last track & sector link of file ? E32A D0 06 BNE $E332 ;no, E32C 20 55 F6 JSR $F655 ;write out bit map to disk E32F 4C 9F EE JMP $EE9F ;jump to free channel routine E332 20 13 DA JSR $DA13 ;mark sector as free on track and BAM E335 20 44 F0 JSR $F044 ;read next data block for current file E338 4C 19 E3 JMP $E319 ;do next link in file ******************************* Delete directory entry E33B A0 00 LDY #$00 E33D 98 TYA E33E 91 27 STA ($27),Y ;adjust directory entry to DEL E340 20 63 F9 JSR $F963 ;write adjustment to disk E343 4C 82 EC JMP $EC82 ;jump to wait until write job complete routine ******************************* Command: DUPLICATE (backup diskette) .Y = pointer for current character position E346 20 9E E4 JSR $E49E ;test for proper syntax E349 A5 8C LDA $8C ;read source drive number E34B 85 12 STA $12 ;set as current drive number E34D A9 18 LDA #$18 ;set for both LED's E34F 0D 82 02 ORA $0282 E352 8D 82 02 STA $0282 ;set LED's for drive 1 & drive 0 E355 20 FA EC JSR $ECFA ;initialize source drive E358 20 80 D7 JSR $D780 ;set BAM pointer for current drive E35B A0 02 LDY #$02 E35D B1 02 LDA ($02),Y ;read format version from disk E35F CD 9F 10 CMP $109F ;same as format version for disk unit ? E362 F0 03 BEQ $E367 ;yes, E364 4C 80 F1 JMP $F180 ;set for "73,CBM DOS V2,00,00" error E367 20 86 DD JSR $DD86 ;toggle drive number E36A 0A ASL E36B A8 TAY E36C 49 02 EOR #$02 E36E AA TAX E36F BD 40 43 LDA $4340,X ;read ID1 of source drive E372 99 40 43 STA $4340,Y ;set as ID1 for destination drive E375 BD 41 43 LDA $4341,X ;read ID2 of source drive E378 99 41 43 STA $4341,Y ;set as ID2 for destination drive E37B 20 80 D7 JSR $D780 ;set BAM pointer for current drive E37E A0 02 LDY #$02 E380 AD 9F 10 LDA $109F ;read format version for disk unit E383 91 02 STA ($02),Y ;set as format version for diskette E385 20 54 EF JSR $EF54 ;clear all dos channels E388 A9 01 LDA #$01 E38A 85 13 STA $13 ;set for track 1 on destination drive E38C 20 16 E4 JSR $E416 ;format destination drive E38F A5 13 LDA $13 ;read current track number ******************************* Copy blocks from source to destination drive E391 20 D2 D7 JSR $D7D2 ;read maximum sectors for current track E394 85 14 STA $14 ;set as end limit E396 C6 14 DEC $14 ;do next sector E398 20 A9 E3 JSR $E3A9 ;copy entire track to destination drive E39B E6 13 INC $13 ;do next track E39D A5 13 LDA $13 ;read current track number E39F C9 24 CMP #$24 ;all tracks on source disk copied ? E3A1 D0 EC BNE $E38F ;no, E3A3 20 FA EC JSR $ECFA ;initialize destination drive E3A6 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* Copy entire track from source to destination E3A9 20 B7 E3 JSR $E3B7 ;transfer HEADER images to destination drive E3AC 20 D2 E3 JSR $E3D2 ;read 10 sectors from source drive E3AF 20 F6 E3 JSR $E3F6 ;write 10 sectors to destination drive E3B2 A5 14 LDA $14 ;all sectors done ? E3B4 10 F3 BPL $E3A9 ;no, E3B6 60 RTS ******************************* Transfer HEADER blocks to destination drive E3B7 A5 12 LDA $12 ;read current drive number E3B9 49 01 EOR #$01 E3BB 8D 3C 43 STA $433C ;set temporary job command E3BE A9 0A LDA #$0A E3C0 85 06 STA $06 ;set TEMP2 to #$0A (decimal 10) E3C2 A5 06 LDA $06 ;read TEMP2 E3C4 20 92 EC JSR $EC92 ;transfer HEADER images to buffer E3C7 C6 14 DEC $14 ;another sector ? E3C9 30 06 BMI $E3D1 ;no, E3CB C6 06 DEC $06 ;TEMP2 no longer positive value ? E3CD 10 F3 BPL $E3C2 ;no, E3CF E6 06 INC $06 ;increment TEMP2 E3D1 60 RTS ******************************* READ 10 sectors from source drive E3D2 AD 3C 43 LDA $433C ;read temporary job command E3D5 09 80 ORA #$80 ;change job type to READ E3D7 8D 3C 43 STA $433C ;set job to READ E3DA A6 06 LDX $06 ;read TEMP2 value into .X register E3DC AD 3C 43 LDA $433C ;read current job command E3DF 20 16 F1 JSR $F116 ;set up job to do E3E2 E0 0A CPX #$0A ;all 10 sectors read ? E3E4 F0 03 BEQ $E3E9 ;yes, E3E6 E8 INX ;sector count #$00 ? E3E7 D0 F3 BNE $E3DC ;no, E3E9 A6 06 LDX $06 ;read TEMP2 E3EB 20 82 EC JSR $EC82 ;wait until assigned job is completed E3EE E0 0A CPX #$0A ;all 10 sectors read ? E3F0 F0 03 BEQ $E3F5 ;yes, E3F2 E8 INX ;sector count #$00 ? E3F3 D0 F6 BNE $E3EB ;no, E3F5 60 RTS ******************************* WRITE 10 sectors to destination drive E3F6 A9 90 LDA #$90 ;set for WRITE job E3F8 05 12 ORA $12 ;add in drive number E3FA 8D 3C 43 STA $433C ;set job to WRITE E3FD A6 06 LDX $06 ;read TEMP2 value into .X register E3FF 20 16 F1 JSR $F116 ;set up job to do E402 E0 0A CPX #$0A ;all 10 sectors written ? E404 F0 03 BEQ $E409 ;yes, E406 E8 INX ;sector count #$00 ? E407 D0 F6 BNE $E3FF ;no, E409 A6 06 LDX $06 ;read TEMP2 E40B 20 82 EC JSR $EC82 ;wait until assigned job is completed E40E E0 0A CPX #$0A ;all 10 sectors written ? E410 F0 03 BEQ $E415 ;yes, E412 E8 INX ;sector count #$00 ? E413 D0 F6 BNE $E40B ;no, E415 60 RTS ******************************* Transfer format code to buffers 0,1 & 2 start controller formatting E416 A0 00 LDY #$00 E418 B9 00 D0 LDA $D000,Y ;read format codes from ROM E41B 99 00 11 STA $1100,Y ;transfer to RAM E41E B9 00 D1 LDA $D100,Y ;read format codes from ROM E421 99 00 12 STA $1200,Y ;transfer to RAM E424 B9 00 D2 LDA $D200,Y ;read format codes from ROM E427 99 00 13 STA $1300,Y ;transfer to RAM E42A C8 INY ;all codes transferred ? E42B D0 EB BNE $E418 ;no, E42D A9 00 LDA #$00 E42F 20 92 EC JSR $EC92 ;transfer HEADER image to buffer E432 A5 12 LDA $12 ;read current drive number E434 09 E0 ORA #$E0 E436 8D 03 10 STA $1003 ;activate EXECUTE code in buffer (FORMAT) E439 AD 03 10 LDA $1003 ;formatting of diskette finished ? E43C 30 FB BMI $E439 ;no, E43E C9 01 CMP #$01 ;disk formatted ok ? E440 F0 07 BEQ $E449 ;yes, E442 A9 03 LDA #$03 E444 A2 00 LDX #$00 E446 4C 1C D9 JMP $D91C ;jump to process encountered error type E449 60 RTS ******************************* Command: COPY (transfer file(s) to other or same disk). Check for type and parse special case E44A 20 E0 DB JSR $DBE0 ;colon found ? E44D D0 1D BNE $E46C ;no, E44F 20 9E E4 JSR $E49E ;test for proper syntax E452 A9 2A LDA #$2A E454 A2 27 LDX #$27 E456 8E 81 43 STX $4381 ;set maximum length to #$27 (decimal 39) E459 9D 00 43 STA $4300,X ;store wildcard (*) at end of command buffer E45C E8 INX E45D 8E 79 43 STX $4379 ;set command size to #$27 + #$01 (decimal 40) E460 A2 01 LDX #$01 E462 8E 7D 43 STX $437D ;set file count1 to #$01 (decimal 1) E465 E8 INX E466 8E 7E 43 STX $437E ;set file count2 to #$02 (decimal 2) E469 4C E1 E4 JMP $E4E1 ;set for optimum search of files in tables ******************************* Normal parse E46C 20 F3 DB JSR $DBF3 ;set up command structure image and file pointer E46F 20 18 DD JSR $DD18 ;set drive number E472 AD 91 43 LDA $4391 ;read file copy image E475 29 55 AND #$55 ;concat or normal (0101 0101) ? E477 D0 1B BNE $E494 ;no, E479 AE 80 43 LDX $4380 ;read pattern from file table E47C BD 00 43 LDA $4300,X ;read byte from command buffer E47F C9 2A CMP #$2A ;is it a wildcard (*) ? E481 D0 11 BNE $E494 ;no, E483 A2 01 LDX #$01 E485 8E 7D 43 STX $437D ;set file count1 to #$01 (decimal 1) E488 E8 INX E489 8E 7E 43 STX $437E ;set file count2 to #$02 (decimal 2) E48C 4C C5 E4 JMP $E4C5 ;copy requested files ******************************* Indicate invalid command structure E48F A9 30 LDA #$30 ;set for "30 SYNTAX ERROR", general syntax E491 4C C3 DB JMP $DBC3 ;jump to process command error routine ******************************* Test if copy type is normal E494 AD 91 43 LDA $4391 ;read file copy image E497 29 D9 AND #$D9 ;normal copy ? E499 D0 F4 BNE $E48F ;no, E49B 4C 87 E5 JMP $E587 ;yes, ******************************* Verify drive numbers for disk to disk copy E49E A9 3D LDA #$3D ;set for disk to disk copying (=) E4A0 20 63 DC JSR $DC63 ;is this a disk to disk copy request ? E4A3 D0 05 BNE $E4AA ;yes, E4A5 A9 30 LDA #$30 ;set for "30 SYNTAX ERROR", general syntax E4A7 4C C3 DB JMP $DBC3 ;jump to process command error routine E4AA B9 00 43 LDA $4300,Y ;read source drive number from command buffer E4AD 20 B5 DD JSR $DDB5 ;valid drive number ? E4B0 30 F3 BMI $E4A5 ;no, E4B2 85 8C STA $8C ;store source drive number in table E4B4 88 DEY E4B5 88 DEY E4B6 B9 00 43 LDA $4300,Y ;read destination drive number from command buffer E4B9 20 B5 DD JSR $DDB5 ;valid drive number ? E4BC 30 E7 BMI $E4A5 ;no, E4BE C5 8C CMP $8C ;same drive number as source ? E4C0 F0 E3 BEQ $E4A5 ;yes, E4C2 85 8B STA $8B ;store destination drive number in table E4C4 60 RTS ******************************* Copy disk to disk routines E4C5 AD 81 43 LDA $4381 ;read byte from file data table E4C8 85 04 STA $04 ;store in TEMP0 E4CA A0 28 LDY #$28 E4CC AE 79 43 LDX $4379 ;read current command string length into .X E4CF 8C 79 43 STY $4379 ;set command string length to #$28 (decimal 40) E4D2 88 DEY E4D3 CA DEX E4D4 BD 00 43 LDA $4300,X ;read filename from directory buffer E4D7 99 00 43 STA $4300,Y ;transfer to command buffer E4DA E4 04 CPX $04 ;all transferred ? E4DC D0 F4 BNE $E4D2 ;no, E4DE 8C 81 43 STY $4381 ;store new position of filename E4E1 20 07 DE JSR $DE07 ;lookup and find file E4E4 20 67 E5 JSR $E567 ;set for copy of file according to type and specification E4E7 20 BF DE JSR $DEBF ;filename in entry table found ? E4EA 10 2D BPL $E519 ;yes, E4EC 30 28 BMI $E516 ;no, ******************************* Pull needed variables from stack E4EE 68 PLA E4EF 8D 96 43 STA $4396 ;reset previous directory sector E4F2 68 PLA E4F3 8D 81 43 STA $4381 ;reset previous file table value E4F6 68 PLA E4F7 8D 99 43 STA $4399 ;reset previous buffer position E4FA 68 PLA E4FB 8D 9B 43 STA $439B ;reset previous file entries counter E4FE 68 PLA E4FF 8D 9A 43 STA $439A ;reset previous index in buffer E502 68 PLA E503 8D 95 43 STA $4395 ;reset previous flag for directory search E506 68 PLA E507 8D 98 43 STA $4398 ;reset previous index of 1st available entry E50A 68 PLA E50B 8D 93 43 STA $4393 ;reset previous drive search flag E50E 20 67 E5 JSR $E567 ;set for copy of file according to type and specification E511 20 AD DE JSR $DEAD ;file name found in table ? E514 10 03 BPL $E519 ;yes, E516 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* Push needed variables onto stack E519 AD 93 43 LDA $4393 ;preserve drive search flag E51C 48 PHA E51D AD 98 43 LDA $4398 ;preserve index for 1st available entry E520 48 PHA E521 AD 95 43 LDA $4395 ;preserve flag for directory search E524 48 PHA E525 AD 9A 43 LDA $439A ;preserve index in buffer E528 48 PHA E529 AD 9B 43 LDA $439B ;preserve file entries counter E52C 48 PHA E52D AD 99 43 LDA $4399 ;preserve buffer position E530 48 PHA E531 AD 81 43 LDA $4381 ;preserve file table value E534 48 PHA E535 AD 96 43 LDA $4396 ;preserve directory sector E538 48 PHA E539 20 57 E5 JSR $E557 ;transfer filename E53C A9 01 LDA #$01 E53E 8D 7D 43 STA $437D ;set file count1 to #$01 (decimal 1) E541 8D 7E 43 STA $437E ;set file count2 to #$01 (decimal 1) E544 20 70 DE JSR $DE70 ;lookup files in stream and fill table with information E547 A9 01 LDA #$01 E549 8D 7D 43 STA $437D ;set file count1 to #$01 (decimal 1) E54C A9 02 LDA #$02 E54E 8D 7E 43 STA $437E ;set file count2 to #$02 (decimal 2) E551 20 D3 E5 JSR $E5D3 ;check if file already exists. If not, copy it E554 4C EE E4 JMP $E4EE ;pull needed variables from stack ******************************* Transfer name from directory buffer to command buffer E557 A0 03 LDY #$03 E559 8C 80 43 STY $4380 ;store in file table E55C B1 27 LDA ($27),Y ;read byte from directory buffer E55E 99 00 43 STA $4300,Y ;store in command buffer E561 C8 INY E562 C0 13 CPY #$13 ;all bytes copied from directory buffer ? E564 D0 F6 BNE $E55C ;no, E566 60 RTS ******************************* Set up for drive number and file information E567 A9 00 LDA #$00 E569 8D 4B 43 STA $434B ;set record size to #$00 E56C 8D 92 43 STA $4392 ;set number of drive searches to #$00 E56F 8D 86 43 STA $4386 ;set track pointer to #$00 E572 8D 87 43 STA $4387 ;set sector pointer to #$00 E575 A5 8C LDA $8C ;get drive number E577 29 01 AND #$01 ;mask off bits: 1-7 E579 85 12 STA $12 ;set as current drive number E57B 09 01 ORA #$01 E57D 8D 97 43 STA $4397 ;set for sector #$01 (decimal 1) E580 AD 81 43 LDA $4381 ;read file information from table E583 8D 80 43 STA $4380 ;store as file information for destination copy E586 60 RTS ******************************* Command: CONCAT (copy file(s) to one file) E587 20 70 DE JSR $DE70 ;lookup files in stream and fill tables with information E58A AD 73 43 LDA $437E ;read file count2 E58D C9 03 CMP #$03 ;less than 3 filenames in command ? E58F 90 3C BCC $E5CD ;no, E591 A5 8B LDA $8B ;read destination drive number E593 C5 8C CMP $8C ;same as source drive number ? E595 D0 36 BNE $E5CD ;no, E597 A5 86 LDA $86 ;read number of files appearing in destination directory block E599 C5 87 CMP $87 ;same as source drive ? E59B D0 30 BNE $E5CD ;no, E59D 20 BC E6 JSR $E6BC ;check if input file exists E5A0 A9 01 LDA #$01 E5A2 8D 7F 43 STA $437F ;set file count3 to #$01 (decimal 1) E5A5 20 17 E6 JSR $E617 ;open and set up internal read file E5A8 20 A1 ED JSR $EDA1 ;file type RELative ? E5AB F0 04 BEQ $E5B1 ;yes, E5AD C9 02 CMP #$02 ;file type PRoGram ? E5AF D0 05 BNE $E5B6 ;no, E5B1 A9 64 LDA #$64 ;set for "64 FILE TYPE MISMATCH" error E5B3 20 C3 DB JSR $DBC3 ;jump to process command error routine E5B6 A9 12 LDA #$12 E5B8 85 16 STA $16 ;set internal write channel to #$12 (decimal 18) E5BA A5 B3 LDA $B3 ;get internal read channel E5BC 85 B4 STA $B4 ;store in internal write channel E5BE A9 FF LDA #$FF E5C0 85 B3 STA $B3 ;set internal read channel to #$FF (decimal 255) E5C2 20 DF F4 JSR $F4DF ;append file E5C5 A2 02 LDX #$02 E5C7 20 E5 E5 JSR $E5E5 ;copy second file to input file E5CA 4C 99 DB JMP $DB99 ;jump to indicate command termination status E5CD 20 D3 E5 JSR $E5D3 ;copy file E5D0 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* Check files for existence E5D3 20 D9 E6 JSR $E6D9 ;check if file exists E5D6 A5 8B LDA $8B ;read destination drive number E5D8 29 01 AND #$01 E5DA 85 12 STA $12 ;set as current drive number E5DC 20 7C F0 JSR $F07C ;open internal write channel E5DF 20 A9 F1 JSR $F1A9 ;add file to directory track E5E2 AE 7D 43 LDX $437D ;read number destination file names E5E5 8E 7F 43 STX $437F ;set as number of source file names E5E8 20 17 E6 JSR $E617 ;open and set internal read file for directory E5EB A9 08 LDA #$08 E5ED 85 A0 STA $A0 ;set EOI flag to #$08 (decimal 8) E5EF 4C F5 E5 JMP $E5F5 ;proceed to read a byte from disk E5F2 20 E6 EB JSR $EBE6 ;write out byte to destination file E5F5 20 57 E6 JSR $E657 ;read byte from source file E5F8 A9 80 LDA #$80 ;set for EOI (last character) E5FA 20 B1 F8 JSR $F8B1 ;last character from source file copied ? E5FD F0 F3 BEQ $E5F2 ;no, E5FF 20 A1 ED JSR $EDA1 ;file type RELative ? E602 F0 03 BEQ $E607 ;yes, E604 20 E6 EB JSR $EBE6 ;write out byte to destination file E607 AE 7F 43 LDX $437F ;read file count3 E60A E8 INX E60B EC 7E 43 CPX $437E ;more files to copy ? E60E 90 D5 BCC $E5E5 ;yes, E610 A9 12 LDA #$12 E612 85 16 STA $16 ;set internal write channel to #$12 (decimal 18) E614 4C BA F5 JMP $F5BA ;close channels and files ******************************* Open and set up internal read file E617 AE 7F 43 LDX $437F ;read number of filenames E61A B5 8B LDA $8B,X ;get drive number of filename from file data table E61C 29 01 AND #$01 E61E 85 12 STA $12 ;set as current drive number E620 A9 12 LDA #$12 E622 85 13 STA $13 ;set as track #$12 (decimal 18) E624 B5 86 LDA $86,X ;get sector number for filename from file entry table E626 29 1F AND #$1F E628 85 14 STA $14 ;set as current sector number E62A 20 6C F0 JSR $F06C ;open internal read channel (secondary address = 17) E62D AE 7F 43 LDX $437F ;read number of filenames E630 B5 86 LDA $86,X ;get filename entry from table E632 29 E0 AND #$E0 E634 09 02 ORA #$02 E636 20 C1 F0 JSR $F0C1 ;set pointer (.ACC = new pointer value) E639 AE 7F 43 LDX $437F ;read file count2 position E63C B5 8B LDA $8B,X ;read file data information for filename E63E 29 0E AND #$0E ;mask off to get file type E640 4A LSR E641 85 C5 STA $C5 ;set as current file type E643 A9 00 LDA #$00 E645 8D 4B 43 STA $434B ;set record size to #$00 (decimal 0) E648 20 5B F4 JSR $F45B ;open file for reading E64B A0 01 LDY #$01 ;set pointer to retrieve file type from disk E64D 20 A1 ED JSR $EDA1 ;file type RELative ? E650 F0 01 BEQ $E653 ;yes, E652 C8 INY E653 98 TYA ;set for retrieval of track number from disk E654 4C C1 F0 JMP $F0C1 ;set pointer (.ACC = new pointer value) ******************************* Get byte from internal read channel E657 A9 11 LDA #$11 E659 85 16 STA $16 ;set internal read channel to #$11 (decimal 17) E65B 20 95 EF JSR $EF95 ;read byte E65E 85 18 STA $18 ;store in temporary data byte E660 A6 15 LDX $15 ;read logical file index E662 B5 98 LDA $98,X ;retrieve channel status E664 29 08 AND #$08 ;mask off bits to determine EOI (end of file) E666 85 A0 STA $A0 ;was EOI (end of file) sent ? E668 D0 0A BNE $E674 ;yes, E66A 20 A1 ED JSR $EDA1 ;file type RELative ? E66D F0 05 BEQ $E674 ;yes, E66F A9 80 LDA #$80 E671 20 A2 F8 JSR $F8A2 ;set logical index and file type flags E674 60 RTS ******************************* Command: RENAME (give new name to a current filename in directory) E675 20 18 DD JSR $DD18 ;set drive number E678 A5 8C LDA $8C ;read drive for source filename E67A 29 01 AND #$01 ;mask off all bits except drive E67C 85 8C STA $8C ;set as current source filename drive number E67E C5 8B CMP $8B ;same as destination filename drive number ? E680 F0 02 BEQ $E684 ;yes, E682 09 80 ORA #$80 E684 85 8B STA $8B ;set flag for destination drive to #$80 (decimal 128) = search both drives E686 20 70 DE JSR $DE70 ;lookup files in stream and fill tables with information E689 20 D9 E6 JSR $E6D9 ;check if filename exists already E68C A5 8C LDA $8C ;read source drive number E68E 29 01 AND #$01 E690 85 12 STA $12 ;set as current drive number E692 A5 87 LDA $87 ;read sector number for destination filename E694 48 PHA ;preserve it E695 29 1F AND #$1F E697 85 14 STA $14 ;set as current sector number E699 20 5C F9 JSR $F95C ;read directory sector E69C 20 82 EC JSR $EC82 ;wait until command is executed E69F 68 PLA ;retrieve old destination sector number E6A0 29 E0 AND #$E0 E6A2 09 05 ORA #$05 E6A4 20 C1 F0 JSR $F0C1 ;set new pointer position E6A7 20 98 FA JSR $FA98 ;get active buffer number E6AA A8 TAY E6AB AE 80 43 LDX $4380 ;read position indicator for new filename E6AE A9 10 LDA #$10 ;set for maximum filename length to #$10 (decimal 16) E6B0 20 5F E0 JSR $E05F ;transfer filename from command buffer E6B3 20 63 F9 JSR $F963 ;write directory sector E6B6 20 82 EC JSR $EC82 ;wait until command is executed E6B9 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* Check if input file is onhand E6BC A5 8C LDA $8C ;read file type of second filename E6BE 29 0E AND #$0E ;isolate file type E6C0 4A LSR E6C1 85 C5 STA $C5 ;set as current file type E6C3 AE 7E 43 LDX $437E ;read current filename length E6C6 CA DEX E6C7 EC 7D 43 CPX $437D ;new filename length exceeds current length ? E6CA 90 0C BCC $E6D8 ;no, E6CC BD 86 43 LDA $4386,X ;read track link for current file name E6CF 29 7F AND #$7F ;is it #$00 ? E6D1 D0 F3 BNE $E6C6 ;no, E6D3 A9 62 LDA #$62 ;set for "62 FILE NOT FOUND" error E6D5 4C C3 DB JMP $DBC3 ;jump to process command error routine E6D8 60 RTS ******************************* Check file for existence E6D9 20 BC E6 JSR $E6BC ;verify that input file is onhand E6DC BD 86 43 LDA $4386,X ;read track link for current file name E6DF 29 7F AND #$7F ;does file already exist ? E6E1 F0 05 BEQ $E6E8 ;no, E6E3 A9 63 LDA #$63 ;set for "63 FILE EXISTS" error E6E5 4C C3 DB JMP $DBC3 ;jump to process command error routine E6E8 CA DEX ;all file names tested from directory for possible existence with desired file name ? E6E9 10 F1 BPL $E6DC ;no, E6EB 60 RTS ******************************* Command: VALIDATE (create new BAM on disk by calculating total space used on disk by all active file types. Remove all inproperly closed files) E6EC 20 CC DB JSR $DBCC ;verify that proper command structure has been sent E6EF 20 FA EC JSR $ECFA ;initialize drive, get DISKETTE NAME and ID E6F2 20 6C E7 JSR $E76C ;set new Block Allocation Map (BAM) E6F5 A9 00 LDA #$00 E6F7 8D 98 43 STA $4398 ;set index for 1st available entry to #$00 E6FA 20 D0 DF JSR $DFD0 ;directory entry found ? E6FD D0 39 BNE $E738 ;yes, E6FF A9 00 LDA #$00 E701 85 14 STA $14 ;set current sector number to #$00 (decimal 0) E703 A9 12 LDA #$12 E705 85 13 STA $13 ;set track number to #$12 (decimal 18) E707 20 44 E7 JSR $E744 ;record in new BAM links for directory track E70A A5 12 LDA $12 ;read current drive number E70C 20 5C F6 JSR $F65C ;write new BAM to track 18, sector 0 E70F 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* Record blocks in file into BAM E712 C8 INY E713 B1 27 LDA ($27),Y ;read track number for current filename E715 48 PHA ;preserve it E716 C8 INY E717 B1 27 LDA ($27),Y ;read sector number for current filename E719 48 PHA ;preserve it E71A A0 13 LDY #$13 E71C B1 27 LDA ($27),Y ;read side track number, is it #$00 ? E71E F0 0A BEQ $E72A ;yes, E720 85 13 STA $13 ;set side track number as current track number E722 C8 INY E723 B1 27 LDA ($27),Y ;read side sector number E725 85 14 STA $14 ;set side sector number as current sector number E727 20 44 E7 JSR $E744 ;record in new BAM side track/sector links for current RELative file E72A 68 PLA ;retrieve sector number for current file E72B 85 14 STA $14 ;set as current sector number E72D 68 PLA ;retrieve track number for current file E72E 85 13 STA $13 ;set as current track number E730 20 44 E7 JSR $E744 ;record new BAM links of current file on disk E733 20 27 E0 JSR $E027 ;more filenames in directory to do ? E736 F0 C7 BEQ $E6FF ;no, ******************************* Verify if directory entry found is properly closed. If so, record in new BAM E738 A0 00 LDY #$00 E73A B1 27 LDA ($27),Y ;is current filename in directory properly properly closed ? E73C 30 D4 BMI $E712 ;yes, E73E 20 3B E3 JSR $E33B ;delete entry from directory and update BAM E741 4C 33 E7 JMP $E733 ;do next directory entry ******************************* Record file entry links in new BAM E744 20 80 D7 JSR $D780 ;set BAM pointer for current drive E747 20 9A EB JSR $EB9A ;mark current track & sector as used in BAM E74A 20 6C F0 JSR $F06C ;open internal read channel (secondary address = 17) E74D A9 00 LDA #$00 E74F 20 C1 F0 JSR $F0C1 ;set pointer (.ACC = new pointer value) E752 20 B3 ED JSR $EDB3 ;read byte from data block indicating next available track for current file E755 85 13 STA $13 ;set as current track number E757 20 B3 ED JSR $EDB3 ;read byte from data block indicating next available sector for current file E75A 85 14 STA $14 ;set as current sector number E75C A5 13 LDA $13 ;is this the last data block for current file ? E75E D0 03 BNE $E763 ;no, E760 4C 9F EE JMP $EE9F ;free channels associated with secondary address E763 20 9A EB JSR $EB9A ;mark current track & sector as used in BAM E766 20 44 F0 JSR $F044 ;read next data block for current file E769 4C 4D E7 JMP $E74D ;proceed to test validity ******************************* Create new BAM for diskette E76C 20 80 D7 JSR $D780 ;set BAM pointer for current drive E76F A0 00 LDY #$00 E771 A9 12 LDA #$12 E773 91 02 STA ($02),Y ;store #$12 (decimal 18) to position 0 in BAM E775 C8 INY E776 98 TYA E777 91 02 STA ($02),Y ;store #$01 (decimal 1) to position 1 in BAM E779 C8 INY E77A C8 INY E77B C8 INY E77C A9 00 LDA #$00 E77E 85 04 STA $04 ;clear 1st part of sectors for current track E780 85 05 STA $05 ;clear 2nd part of sectors for current track E782 85 06 STA $06 ;clear 3rd part of sectors for current track E784 98 TYA E785 4A LSR E786 4A LSR E787 20 D2 D7 JSR $D7D2 ;get maximum number of sectors possible for current track E78A 91 02 STA ($02),Y ;store maximum sector for current track in BAM E78C C8 INY E78D AA TAX E78E 38 SEC E78F 26 04 ROL $04 ;set 1st part of sector map for track as free E791 26 05 ROL $05 ;set 2nd part of sector map for track as free E793 26 06 ROL $06 ;set 3rd part of sector map for track as free and set up non valid sectors as used E795 CA DEX ;all parts initialized ? E796 D0 F6 BNE $E78E ;no, E798 B5 04 LDA $04,X ;read part of sector map for current track E79A 91 02 STA ($02),Y ;store in BAM according to track location E79C C8 INY E79D E8 INX E79E E0 03 CPX #$03 ;all parts for current track written to BAM ? E7A0 90 F6 BCC $E798 ;no, E7A2 C0 90 CPY #$90 ;all sector maps for tracks calculated ? E7A4 90 D6 BCC $E77C ;no, E7A6 60 RTS ******************************* Checksum byte for $E000 E7A7 45 ??? ;E-ROM checksum ******************************* Command: MEMORY (direct access to DOS) E7A8 AD 01 43 LDA $4301 ;read 2nd byte from command buffer E7AB C9 2D CMP #$2D ;is 2nd byte from buffer a dash (-) ? E7AD D0 48 BNE $E7F7 ;no, E7AF AD 03 43 LDA $4303 ;read 4th byte from command buffer E7B2 85 04 STA $04 ;set as LO byte for memory address E7B4 AD 04 43 LDA $4304 ;read 5th byte from command buffer E7B7 85 05 STA $05 ;set as HI byte for memory address E7B9 A0 00 LDY #$00 E7BB AD 02 43 LDA $4302 ;read 3rd byte from command buffer E7BE C9 57 CMP #$57 ;is 3rd byte a W (Write) ? E7C0 F0 3A BEQ $E7FC ;yes, E7C2 C9 52 CMP #$52 ;is 3rd byte a R (Read) ? E7C4 F0 07 BEQ $E7CD ;yes, E7C6 C9 45 CMP #$45 ;is 3rd byte a E (Execute) ? E7C8 D0 2D BNE $E7F7 ;no, E7CA 6C 04 00 JMP ($0004) ;jump to execute memory address indicated ******************************* Command: MEMORY-READ (direct read from DOS) E7CD B1 04 LDA ($04),Y ;read byte from specified memory address E7CF 85 18 STA $18 ;store byte in temporary data location E7D1 AD 79 43 LDA $4379 ;read length of command string sent from computer E7D4 C9 06 CMP #$06 ;more than one memory address to read ? E7D6 90 19 BCC $E7F1 ;no, E7D8 AE 05 43 LDX $4305 ;read amount of bytes to still left to retrieve E7DB CA DEX ;all desired memory bytes read ? E7DC F0 13 BEQ $E7F1 ;yes, E7DE 8A TXA E7DF 18 CLC E7E0 65 04 ADC $04 ;calculate last memory location to read & send E7E2 E6 04 INC $04 ;do next memory location E7E4 85 C4 STA $C4 ;save end address E7E6 A5 04 LDA $04 ;read LO byte found in TEMP0 E7E8 85 47 STA $47 ;set as LO address byte for error output buffer E7EA A5 05 LDA $05 ;read HI byte found in TEMP1 E7EC 85 48 STA $48 ;set as HI address byte for error output buffer E7EE 4C 3B F0 JMP $F03B ;continue reading desired memory locations E7F1 20 69 ED JSR $ED69 ;find unused read channel E7F4 4C 32 F0 JMP $F032 ;terminate MEMORY-READ command ******************************* Indicate invalid command structure E7F7 A9 31 LDA #$31 ;set for "31 SYNTAX ERROR", invalid command E7F9 4C C3 DB JMP $DBC3 ;jump to process command error routine ******************************* Command: MEMORY-WRITE (direct write to DOS) E7FC B9 06 43 LDA $4306,Y ;get byte value from command string E7FF 91 04 STA ($04),Y ;store at desired memory address E801 C8 INY E802 CC 05 43 CPY $4305 ;another byte to read and write to a desired memory address ? E805 90 F5 BCC $E7FC ;yes, E807 60 RTS ******************************* User access commands E808 AC 01 43 LDY $4301 ;read 2nd byte from command buffer E80B C0 30 CPY #$30 ;is it U0 command ? E80D D0 09 BNE $E818 ;no, E80F A9 EA LDA #$EA E811 85 00 STA $00 ;set LO byte of user jump table to #$EA E813 A9 FF LDA #$FF E815 85 01 STA $01 ;set HI byte of user jump table to #$FF E817 60 RTS E818 20 1E E8 JSR $E81E ;execute user jump code E81B 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* Execute user jump code E81E 88 DEY ;decrement user command code by one E81F 98 TYA E820 29 0F AND #$0F ;isolate LO order bits E822 0A ASL ;calculate buffer index E823 A8 TAY E824 B1 00 LDA ($00),Y ;read byte from user jump address E826 85 0A STA $0A ;set as LO byte of Indirect Pointer (IP) E828 C8 INY ;do next byte E829 B1 00 LDA ($00),Y ;read byte from user jump address E82B 85 0B STA $0B ;set as HI byte of Indirect Pointer (IP) E82D 6C 0A 00 JMP ($000A) ;jump to calculated memory location ******************************* Open direct access buffer from OPEN "#" E830 AE 79 43 LDX $4379 ;read length of command string E833 CA DEX ;specific buffer number (#) to open ? E834 D0 0D BNE $E843 ;yes, E836 A9 01 LDA #$01 ;set for buffer number (#) 1 E838 20 5E EE JSR $EE5E ;set up buffer number (#) E83B 4C 87 E8 JMP $E887 ;set logical index table ******************************* Indicate invalid channel structure E83E A9 70 LDA #$70 ;set for "70 NO CHANNEL", available E840 4C C3 DB JMP $DBC3 ;jump to process command error routine ******************************* Validate and set up requested buffer E843 A0 01 LDY #$01 E845 20 10 E9 JSR $E910 ;get requested buffer number E848 AE 8B 43 LDX $438B ;read desired buffer number E84B E0 0C CPX #$0C ;is it greater than #$0C (decimal 12) ? E84D B0 EF BCS $E83E ;yes, E84F A9 00 LDA #$00 E851 85 04 STA $04 ;clear LO byte of user jump address E853 85 05 STA $05 ;clear HI byte of user jump address E855 38 SEC E856 26 04 ROL $04 ;move LO pointer until requested buffer reached E858 26 05 ROL $05 ;move HI pointer until requested buffer reached E85A CA DEX ;buffer pointer set to requested buffer ? E85B 10 F9 BPL $E856 ;no, E85D A5 04 LDA $04 ;read buffer available flag E85F 2D 3E 43 AND $433E ;buffer already in use ? E862 D0 DA BNE $E83E ;yes, E864 A5 05 LDA $05 ;read next buffer number to test E866 2D 3F 43 AND $433F ;already in use ? E869 D0 D3 BNE $E83E ;yes, E86B A5 04 LDA $04 ;read buffer bit from table E86D 0D 3E 43 ORA $433E E870 8D 3E 43 STA $433E ;indicate buffer as being used E873 A5 05 LDA $05 ;read next buffer number to test E875 0D 3F 43 ORA $433F E878 8D 3F 43 STA $433F ;indicate buffer as being used E87B A9 00 LDA #$00 E87D 20 5E EE JSR $EE5E ;set up read channel E880 A6 15 LDX $15 ;read current channel number into .X register E882 AD 8B 43 LDA $438B ;read current sector number E885 95 49 STA $49,X ;store sector number in channel sector table E887 A6 16 LDX $16 ;read current secondary address E889 B5 A2 LDA $A2,X ;store as current sector channel direction bits 7-6: 00 = read channel 10 = write channel 01 = read/write channel 11 = no channel #$FF: = no active channel E88B 09 40 ORA #$40 E88D 95 A2 STA $A2,X ;set current channel direction to 01 (bit 7-6) E88F A4 15 LDY $15 ;read current channel number into .Y register E891 A9 FF LDA #$FF E893 99 BD 00 STA $00BD,Y ;set last channel character sent to #$FF (decimal 255) E896 A9 89 LDA #$89 E898 99 98 00 STA $0098,Y ;set channel ready status to 1000 1001 bit 7 = channel is talker (set to 1) 3 = channel is send EOI (talker only) 0 = channel is listener (set to 1) E89B B9 49 00 LDA $0049,Y ;read buffer number E89E 99 B5 00 STA $00B5,Y ;set as 1st character E8A1 0A ASL E8A2 AA TAX E8A3 A9 01 LDA #$01 E8A5 95 29 STA $29,X ;set buffer pointer to beginning of buffer E8A7 A9 0E LDA #$0E E8A9 99 90 00 STA $0090,Y ;set to direct file type (bit 7 = search both drives) SEQ = type 1 PRG = type 2 USR = type 3 REL = type 4 direct = type 7 E8AC 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* Search for second character (-) in command string for BLOCK commands E8AF A0 00 LDY #$00 E8B1 A2 00 LDX #$00 E8B3 A9 2D LDA #$2D ;set for dash (-) character E8B5 20 63 DC JSR $DC63 ;has character been located ? E8B8 D0 0A BNE $E8C4 ;yes, ******************************* Indicate invalid command structure E8BA A9 31 LDA #$31 ;set for "31 SYNTAX ERROR", invalid command E8BC 4C C3 DB JMP $DBC3 ;jump to process command error routine ******************************* Indicate invalid command structure E8BF A9 30 LDA #$30 ;set for "30 SYNTAX ERROR", general syntax E8C1 4C C3 DB JMP $DBC3 ;jump to process command error routine ******************************* Decide which command is being requested E8C4 8A TXA ;any extra parameters found ? E8C5 D0 F8 BNE $E8BF ;no, E8C7 A2 05 LDX #$05 ;set pointer to maximum number BLOCK commands E8C9 B9 00 43 LDA $4300,Y ;read character from input buffer E8CC DD F1 E8 CMP $E8F1,X ;is it a valid command ? E8CF F0 05 BEQ $E8D6 ;yes, E8D1 CA DEX ;character tested against all possible BLOCK commands from table ? E8D2 10 F8 BPL $E8CC ;no, E8D4 30 E4 BMI $E8BA ;yes, E8D6 8A TXA ;transfer command number value to .ACC E8D7 09 80 ORA #$80 E8D9 8D 7A 43 STA $437A ;set as current command number value E8DC 20 03 E9 JSR $E903 ;get command parameters and test E8DF AD 7A 43 LDA $437A ;read current command number value E8E2 0A ASL ;double it E8E3 AA TAX E8E4 BD F8 E8 LDA $E8F8,X ;read byte for command jump address E8E7 85 05 STA $05 ;set as HI byte for command jump address E8E9 BD F7 E8 LDA $E8F7,X ;read byte for command jump address E8EC 85 04 STA $04 ;set as LO byte for command jump address E8EE 6C 04 00 JMP ($0004) ;jump to perform desired BLOCK command ******************************* BLOCK command summary E8F1 41 ??? ;A - (allocate) E8F2 46 ??? ;F - (free ) E8F3 52 ??? ;R - (read ) E8F4 57 ??? ;W - (write ) E8F5 45 ??? ;E - (execute ) E8F6 50 ??? ;P - (pointer ) ******************************* BLOCK - command jump table E8F7 92 E9 ??? ; - Allocate E8F9 89 E9 ??? ; - Free E8FB F5 E9 ??? ; - Read E8FD 12 EA ??? ; - Write E8FF 44 EA ??? ; - Execute E901 5B EA ??? ; - Pointer ******************************* Get command parameters and test validity E903 A0 00 LDY #$00 E905 A2 00 LDX #$00 E907 A9 3A LDA #$3A ;set for colon (:) character E909 20 63 DC JSR $DC63 ;colon (:) found in input buffer ? E90C D0 02 BNE $E910 ;no, E90E A0 03 LDY #$03 ;set pointer to 4th character in buffer E910 B9 00 43 LDA $4300,Y ;get 4th character from input buffer E913 C9 20 CMP #$20 ;is it a space ( ) ? E915 F0 08 BEQ $E91F ;yes, E917 C9 1D CMP #$1D ;is it a cursor right (CRSR right) ? E919 F0 04 BEQ $E91F ;yes, E91B C9 2C CMP #$2C ;is it a comma (,) ? E91D D0 07 BNE $E926 ;no, E91F C8 INY ;move pointer to next character E920 CC 79 43 CPY $4379 ;end of input buffer ? E923 90 EB BCC $E910 ;no, E925 60 RTS E926 20 35 E9 JSR $E935 ;convert ASCII to HEX (binary) and store E929 EE 7D 43 INC $437D ;increment current number of parameters E92C AC 7F 43 LDY $437F ;read total number of parameters E92F E0 04 CPX #$04 ;reached maximum possible parameters ? E931 90 EC BCC $E91F ;no, E933 B0 8A BCS $E8BF ;yes, too many parameters error ******************************* Convert ASCII to HEX (binary) and store conversion result in appropriate tables .Y register = pointer into command buffer E935 A9 00 LDA #$00 E937 85 04 STA $04 ;clear TEMP0 E939 85 05 STA $05 ;clear TEMP1 E93B 85 07 STA $07 ;clear TEMP3 E93D A2 FF LDX #$FF E93F B9 00 43 LDA $4300,Y ;read next character from input buffer E942 C9 40 CMP #$40 ;numeric value ? E944 B0 18 BCS $E95E ;no, E946 C9 30 CMP #$30 ;ASCII digit ? E948 90 14 BCC $E95E ;no, E94A 29 0F AND #$0F ;mask off high order bits E94C 48 PHA ;preserve new result for later reference E94D A5 05 LDA $05 ;read current value found in TEMP1 E94F 85 06 STA $06 ;store in TEMP2 E951 A5 04 LDA $04 ;read current value found in TEMP0 E953 85 05 STA $05 ;store in TEMP1 E955 68 PLA ;retrieve previously calculated result E956 85 04 STA $04 ;store in TEMP0 E958 C8 INY ;increment pointer to next character E959 CC 79 43 CPY $4379 ;end of input buffer ? E95C 90 E1 BCC $E93F ;no, ******************************* Convert digit to binary by use of decimal table E95E 8C 7F 43 STY $437F ;save current buffer pointer position E961 18 CLC E962 A9 00 LDA #$00 E964 E8 INX E965 E0 03 CPX #$03 ;reached maximum possible decimal numbers E967 B0 0F BCS $E978 ;yes, too many decimal digits E969 B4 04 LDY $04,X ;read part of decimal number E96B 88 DEY ;all parts added up ? E96C 30 F6 BMI $E964 ;no, E96E 7D 86 E9 ADC $E986,X ;result calculate above 256 ? E971 90 F8 BCC $E96B ;no, E973 18 CLC E974 E6 07 INC $07 ;HI byte incremented by one ? E976 D0 F3 BNE $E96B ;yes, E978 48 PHA E979 AE 7D 43 LDX $437D ;get parameter number E97C A5 07 LDA $07 ;read binary value (HI byte) E97E 9D 86 43 STA $4386,X ;store result as track number for first block E981 68 PLA E982 9D 8B 43 STA $438B,X ;store result as sector number of first block E985 60 RTS ******************************* Decimal table E986 01 ??? ;decimal value of: 1 E987 0A ??? ;decimal value of: 10 E988 64 ??? ;decimal value of: 100 ******************************* BLOCK - FREE command. De-allocate a block used on disk E989 20 93 EA JSR $EA93 ;get track and sector number E98C 20 13 DA JSR $DA13 ;mark a sector as free on a track and BAM E98F 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* BLOCK - ALLOCATE command. Allocate a block used on disk E992 20 93 EA JSR $EA93 ;get track and sector number E995 A6 12 LDX $12 ;read current drive number E997 BD E8 D2 LDA $D2E8,X ;read BAM buffer pointer for drive 0 E99A 85 03 STA $03 ;set as buffer to use E99C 20 8C D7 JSR $D78C ;read sector map from BAM for track E99F 20 A8 D7 JSR $D7A8 ;valid track and sector number ? E9A2 B0 26 BCS $E9CA ;yes, E9A4 A6 14 LDX $14 ;read current sector number E9A6 E8 INX ;increment value by one E9A7 86 14 STX $14 ;store as new sector number E9A9 8E 73 43 STX $4373 ;set as sector number to display if error E9AC E4 19 CPX $19 ;all sectors on this track done ? E9AE 90 EF BCC $E99F ;no, E9B0 A9 00 LDA #$00 E9B2 85 14 STA $14 ;set sector number to 0 E9B4 A6 13 LDX $13 ;read current track number E9B6 E8 INX ;increment value by one E9B7 86 13 STX $13 ;set as new track number E9B9 E0 24 CPX #$24 ;last track on disk ? E9BB B0 06 BCS $E9C3 ;yes, E9BD 20 A6 EA JSR $EAA6 ;set sector requested as allocated E9C0 4C 9C E9 JMP $E99C ;do next requested sector ******************************* No block available error E9C3 85 13 STA $13 ;set current track number to #$00 E9C5 A9 65 LDA #$65 ;set for "65 NO BLOCK" error E9C7 4C 53 D9 JMP $D953 ;jump to process error and message ******************************* Test for block availability E9CA AE 73 43 LDX $4373 ;is desired block available ? E9CD D0 F6 BNE $E9C5 ;no, E9CF 20 9A EB JSR $EB9A ;set desired block as used E9D2 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* Test BLOCK-READ parameters and read sector in buffer E9D5 20 90 EA JSR $EA90 ;test parameters and get track and sector E9D8 4C 57 F0 JMP $F057 ;read sector in buffer ******************************* Get a byte from buffer E9DB 20 AB ED JSR $EDAB ;set buffer pointer E9DE A1 29 LDA ($29,X) ;read byte from buffer E9E0 60 RTS ******************************* Read sector from disk to buffer, initialize pointers, set channel direction E9E1 20 D5 E9 JSR $E9D5 ;get parameters and read sector E9E4 A9 00 LDA #$00 E9E6 20 C1 F0 JSR $F0C1 ;set new pointer E9E9 20 DB E9 JSR $E9DB ;get a byte from buffer E9EC 99 BD 00 STA $00BD,Y ;set as last data byte to be transferred E9EF A9 89 LDA #$89 E9F1 99 98 00 STA $0098,Y ;set channel ready status to 1000 1001 bit 7 = channel is talker (set to 1) 3 = channel is send EOI (talker only) 0 = channel is listener (set to 1) E9F4 60 RTS ******************************* BLOCK - READ command. Read requested sector from disk E9F5 20 E1 E9 JSR $E9E1 ;set up to read requested sector E9F8 20 E5 EF JSR $EFE5 ;read in sector E9FB 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* U1: (Block-read) command E9FE 20 03 E9 JSR $E903 ;get command parameters and test validity EA01 20 E1 E9 JSR $E9E1 ;read sector from disk to buffer, set pointers EA04 B9 BD 00 LDA $00BD,Y ;read number of bytes to read in EA07 99 B5 00 STA $00B5,Y ;set as number of bytes to send EA0A A9 FF LDA #$FF EA0C 99 BD 00 STA $00BD,Y ;set as last byte to read and send EA0F 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* BLOCK - WRITE command. Write requested sector to disk EA12 20 90 EA JSR $EA90 ;test parameters and get track and sector EA15 20 E1 F0 JSR $F0E1 ;read active buffer pointer EA18 A8 TAY EA19 88 DEY EA1A C9 02 CMP #$02 ;pointer at start of data range ? EA1C B0 02 BCS $EA20 ;no, EA1E A0 01 LDY #$01 EA20 A9 00 LDA #$00 EA22 20 C1 F0 JSR $F0C1 ;set new pointer EA25 98 TYA EA26 20 B1 EC JSR $ECB1 ;write byte in buffer EA29 8A TXA EA2A 48 PHA EA2B 20 5B F0 JSR $F05B ;write out sector to disk EA2E 68 PLA EA2F AA TAX EA30 A4 15 LDY $15 ;read current logical index EA32 20 E7 EF JSR $EFE7 ;set channel for read/write EA35 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* U2: (Block-write) command EA38 20 03 E9 JSR $E903 ;get command parameters and test validity EA3B 20 90 EA JSR $EA90 ;test parameters and get track and sector EA3E 20 5B F0 JSR $F05B ;write out sector to disk EA41 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* BLOCK - EXECUTE command. Read requested sector and execute as machine code EA44 20 D5 E9 JSR $E9D5 ;test parameter validity and read sector EA47 A9 00 LDA #$00 EA49 85 04 STA $04 ;set LO byte of jump address to #$00 EA4B A6 A1 LDX $A1 ;read buffer number to use EA4D BD FF F0 LDA $F0FF,X ;read HI byte from buffer table EA50 85 05 STA $05 ;set HI byte of jump address EA52 20 58 EA JSR $EA58 ;execute machine code starting at jump address EA55 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* Execute machine code at assigned jump address EA58 6C 04 00 JMP ($0004) ;jump to assigned machine code address and execute ******************************* BLOCK - POINTER command. Position pointer to a requested byte in sector EA5B 20 70 EA JSR $EA70 ;allocate buffer number and open channel EA5E A5 A1 LDA $A1 ;read buffer number to use EA60 0A ASL EA61 AA TAX EA62 AD 8C 43 LDA $438C ;get new buffer position EA65 95 29 STA $29,X ;set as LO byte pointer in buffer table EA67 20 AB ED JSR $EDAB ;set buffer pointer EA6A 20 E7 EF JSR $EFE7 ;set channel for read/write EA6D 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* Test for allocated buffer and open channel EA70 A6 81 LDX $81 ;get parameter number EA72 E6 81 INC $81 ;set to next assignment EA74 BD 8B 43 LDA $438B,X ;load .ACC with file's secondary address EA77 A8 TAY EA78 88 DEY ;eliminate secondary address 0 EA79 88 DEY ;eliminate secondary address 1 EA7A C0 0C CPY #$0C ;is end result #$0C (decimal 12) ? EA7C 90 05 BCC $EA83 ;yes, EA7E A9 70 LDA #$70 ;set for "70 NO CHANNEL" error, invalid secondary address EA80 4C C3 DB JMP $DBC3 ;jump to process command error routine EA83 85 16 STA $16 ;set new active secondary address EA85 20 69 ED JSR $ED69 ;unused read channel found ? EA88 B0 F4 BCS $EA7E ;no, EA8A 20 98 FA JSR $FA98 ;get active buffer number EA8D 85 A1 STA $A1 ;set as current job number EA8F 60 RTS ******************************* Test block operation parameters. Set up drive, track, and sector EA90 20 70 EA JSR $EA70 ;test for allocated buffer and open channel EA93 A6 81 LDX $81 ;get parameter number EA95 BD 8B 43 LDA $438B,X ;read drive number of 1st block for file searches EA98 29 01 AND #$01 ;mask off default drive bit EA9A 85 12 STA $12 ;set as current drive number EA9C BD 8D 43 LDA $438D,X ;read sector number of 1st block for file searches EA9F 85 14 STA $14 ;set as current sector number EAA1 BD 8C 43 LDA $438C,X ;read track number of 1st block for file searches EAA4 85 13 STA $13 ;set as current track number EAA6 20 6E F1 JSR $F16E ;test track and sector validity EAA9 85 19 STA $19 ;store sector zone in TEMPWORK0 EAAB 4C 2C DA JMP $DA2C ;turn on activity LED specified by drive ******************************* Find relative file INPUTS: OUTPUTS: ------ ------- .record # (LO byte) .side sector # .record # (HI byte) .index into side sector .record size .pointer into sector .pointer into record EAAE 20 CC EA JSR $EACC ;calculate record's location in bytes EAB1 20 0E EB JSR $EB0E ;divide result by #$FE (decimal 254) EAB4 A5 23 LDA $23 ;get remainder of division EAB6 85 85 STA $85 ;set as pointer into last sector EAB8 20 11 EB JSR $EB11 ;divide result by #$78 (decimal 120) EABB E6 85 INC $85 ;increment pointer past track marker EABD E6 85 INC $85 ;increment pointer past sector marker EABF A5 1E LDA $1E ;get remainder of division EAC1 85 83 STA $83 ;set as pointer to current side sector EAC3 A5 23 LDA $23 ;get remainder of first division EAC5 0A ASL ;multiply times two EAC6 18 CLC EAC7 69 10 ADC #$10 ;calculate side sector index EAC9 85 84 STA $84 ;set as current side sector index EACB 60 RTS ******************************* Calculate a record's location in bytes TOTAL = RCRD # x RCRD SIZE + RCRD PNTR EACC 20 79 EB JSR $EB79 ;clear RESULT memory EACF 85 25 STA $25 ;clear ACCUMULATION memory location EAD1 A6 15 LDX $15 ;read index into pointer for buffer to use EAD3 B5 59 LDA $59,X ;read LO record pointer found in buffer EAD5 85 23 STA $23 ;store in calculation area EAD7 B5 61 LDA $61,X ;read HI record pointer found in buffer EAD9 85 24 STA $24 ;is HI record pointer value found in calculation area greater than #$00 ? EADB D0 04 BNE $EAE1 ;yes, EADD A5 23 LDA $23 ;is LO record pointer value found in calculation area equal to #$00 ? EADF F0 0B BEQ $EAEC ;yes, EAE1 A5 23 LDA $23 ;get LO byte of record pointer EAE3 38 SEC EAE4 E9 01 SBC #$01 ;substract #$01 (decimal 1) from current value EAE6 85 23 STA $23 ;is new LO record pointer value #$00 ? EAE8 B0 02 BCS $EAEC ;no, EAEA C6 24 DEC $24 ;decrement HI record pointer value EAEC B5 71 LDA $71,X ;read LO record size byte found in table EAEE 85 04 STA $04 ;store value in TEMP0 EAF0 46 04 LSR $04 ;addition needed before performing multiplication ? EAF2 90 03 BCC $EAF7 ;no, EAF4 20 8D EB JSR $EB8D ;add current results to: RCRD PNTR/RCRD SIZE/RCRD # EAF7 20 85 EB JSR $EB85 ;multiply, RCRD PNTR/RCRD SIZE/RCRD # by two EAFA A5 04 LDA $04 ;multiply/addition calculations finished ? EAFC D0 F2 BNE $EAF0 ;no, EAFE A5 82 LDA $82 ;read pointer into record value EB00 18 CLC EB01 65 1E ADC $1E ;add #$01 (decimal 1) to current value EB03 85 1E STA $1E ;is new pointer value smaller than #$00 ? EB05 90 06 BCC $EB0D ;no, EB07 E6 1F INC $1F ;incremented RCRD SIZE pointer equal to #$00 ? EB09 D0 02 BNE $EB0D ;no, EB0B E6 20 INC $20 ;incremented RCRD # pointer by one EB0D 60 RTS ******************************* Divide by #$FE (decimal 254) EB0E A9 FE LDA #$FE EB10 2C ??? ;** also becomes patch: EB10 2C A9 78 BIT $78A9 ******************************* Divide by #$78 (decimal 120) EB11 A9 78 LDA #$78 ******************************* Main division routine EB13 85 04 STA $04 ;store divisor value to use in TEMP0 EB15 A2 03 LDX #$03 EB17 B5 22 LDA $22,X ;read content from ACCUMULATION table EB19 48 PHA ;preserve it EB1A B5 1D LDA $1D,X ;read content from RESULT table EB1C 95 22 STA $22,X ;transfer to ACCUMULATION table EB1E 68 PLA ;retrieve value EB1F 95 1D STA $1D,X ;store in RESULT table EB21 CA DEX ;all 3 math registers transferred ? EB22 D0 F3 BNE $EB17 ;no, EB24 20 79 EB JSR $EB79 ;clear RESULT memory EB27 A2 00 LDX #$00 EB29 B5 23 LDA $23,X ;read content from ACCUMULATION register +1 EB2B 95 22 STA $22,X ;transfer content to ACCUMULATION register -1 EB2D E8 INX EB2E E0 04 CPX #$04 ;all 4 registers copied down by one ? EB30 90 F7 BCC $EB29 ;no, EB32 A9 00 LDA #$00 EB34 85 25 STA $25 ;clear last ACCUMULATION register EB36 24 04 BIT $04 ;must a division by 256 be performed ? EB38 30 09 BMI $EB43 ;yes, EB3A 06 22 ASL $22 ;set carry flag EB3C 08 PHP ;preserve it EB3D 46 22 LSR $22 ;unset carry flag EB3F 28 PLP ;retrieve value with carry set indicator EB40 20 86 EB JSR $EB86 ;perform: 2 * (.X/256) = .X/128 EB43 20 8D EB JSR $EB8D ;add current results to: RCRD PNTR/RCRD SIZE/RCRD # EB46 20 85 EB JSR $EB85 ;multiply, RCRD PNTR/RCRD SIZE/RCRD # by two EB49 24 04 BIT $04 ;must a division by 120 be performed ? EB4B 30 03 BMI $EB50 ;no, EB4D 20 82 EB JSR $EB82 ;perform: .ACC = 4 * (2 * .ACC) = 8* .ACC EB50 A5 22 LDA $22 ;read in remainder from calculation EB52 18 CLC EB53 65 23 ADC $23 ;add with content from ACCUMULATION register 1 EB55 85 23 STA $23 ;does new ACCUMULATION1 result force a carry ? EB57 90 06 BCC $EB5F ;no, EB59 E6 24 INC $24 ;increment ACCUMULATION2, equal to #$00 ? EB5B D0 02 BNE $EB5F ;no, EB5D E6 25 INC $25 ;increment ACCUMULATION register 3 EB5F A5 25 LDA $25 ;read value found in ACCUMULATION register 3 EB61 05 24 ORA $24 ;smaller than 256 ? EB63 D0 C2 BNE $EB27 ;no, EB65 A5 23 LDA $23 ;read value found in ACCUMULATION register 1 EB67 38 SEC EB68 E5 04 SBC $04 ;content smaller than divisor factor ? EB6A 90 0C BCC $EB78 ;yes, EB6C E6 1E INC $1E ;increment RESULT0, equal to #$00 EB6E D0 06 BNE $EB76 ;no, EB70 E6 1F INC $1F ;increment RESULT1, equal to #$00 EB72 D0 02 BNE $EB76 ;no, EB74 E6 20 INC $20 ;increment RESULT2 EB76 85 23 STA $23 ;store new remainder value EB78 60 RTS ******************************* Clear RESULT memory area EB79 A9 00 LDA #$00 EB7B 85 1E STA $1E ;clear RESULT register 0 EB7D 85 1F STA $1F ;clear RESULT register 1 EB7F 85 20 STA $20 ;clear RESULT register 2 EB81 60 RTS ******************************* Multiply ACCUMULATION registers by 4 EB82 20 85 EB JSR $EB85 ;multiply ACCUMULATION registers by 2 ******************************* Multiply ACCUMULATION registers by 2 EB85 18 CLC EB86 26 23 ROL $23 ;multiply ACCUMULATION register 1 by 2 EB88 26 24 ROL $24 ;multiply ACCUMULATION register 2 by 2 EB8A 26 25 ROL $25 ;multiply ACCUMULATION register 3 by 2 EB8C 60 RTS ******************************* Add ACCUMULATION register to RESULT registers: RESULT = RESULT + ACCUMULATION 1,2,3 EB8D 18 CLC EB8E A2 FD LDX #$FD ;set for #$FD (decimal 253) EB90 B5 21 LDA $21,X ;read value from RESULT register 0 EB92 75 26 ADC $26,X ;add value from ACCUMULATION register 0 EB94 95 21 STA $21,X ;store as new RESULT register value EB96 E8 INX ;all 254 registers added ? EB97 D0 F7 BNE $EB90 ;no, EB99 60 RTS ******************************* Mark track, sector, BAM pointer as used EB9A 20 AF EB JSR $EBAF ;is desired block available ? EB9D F0 0F BEQ $EBAE ;no, EB9F B1 02 LDA ($02),Y ;read current block value from bit map EBA1 5D C9 EB EOR $EBC9,X ;set desired block as used EBA4 91 02 STA ($02),Y ;store new block value in bit map EBA6 A4 04 LDY $04 EBA8 B1 02 LDA ($02),Y ;read sector free count for current track EBAA E9 00 SBC #$00 ;substract one EBAC 91 02 STA ($02),Y ;store new sector count for track in bit map EBAE 60 RTS ******************************* Test if requested block available EBAF A5 13 LDA $13 ;read current track number EBB1 0A ASL EBB2 0A ASL ;calculate BAM index for track EBB3 85 04 STA $04 ;store BAM index for track EBB5 A5 14 LDA $14 ;read current sector number EBB7 4A LSR ;divide sector number by 2 EBB8 4A LSR ;divide new value by 2 EBB9 4A LSR ;divide new value by 2 EBBA 38 SEC EBBB 65 04 ADC $04 ;add 1 to newly calculated result EBBD A8 TAY EBBE A5 14 LDA $14 ;read current sector number EBC0 29 07 AND #$07 ;calculate bit position of sector in BAM EBC2 AA TAX EBC3 B1 02 LDA ($02),Y ;read BAM byte corresponding to requested sector number EBC5 3D C9 EB AND $EBC9,X ;test if available (.Z flag = 0) EBC8 60 RTS ******************************* Bit mask table for BAM calculations EBC9 01 ??? ;decimal 1 EBCA 02 ??? ;decimal 2 EBCB 04 ??? ;decimal 4 EBCC 08 ??? ;decimal 8 EBCD 10 ??? ;decimal 16 EBCE 20 ??? ;decimal 32 EBCF 40 ??? ;decimal 64 EBD0 80 ??? ;decimal 128 ******************************* Double buffer: switch the active and inactive buffers EBD1 A6 15 LDX $15 ;read current channel number EBD3 B5 49 LDA $49,X ;read buffer 1 status EBD5 49 80 EOR #$80 ;change status of buffer 1, active/inactive EBD7 95 49 STA $49,X ;set new status for buffer 1 EBD9 B5 51 LDA $51,X ;read buffer 2 status EBDB 49 80 EOR #$80 ;change status of buffer 2, active/inactive EBDD 95 51 STA $51,X ;set new status for buffer 2 EBDF 20 98 FA JSR $FA98 ;get active buffer number EBE2 AA TAX EBE3 4C 82 EC JMP $EC82 ;jump to wait until job done routine ******************************* Set internal write channel and test if command channel EBE6 A2 12 LDX #$12 EBE8 86 16 STX $16 ;set current secondary address to #$12 (decimal 18) EBEA 20 84 ED JSR $ED84 ;find unused internal write channel EBED 20 2C DA JSR $DA2C ;turn on activity LED specified by drive EBF0 A5 16 LDA $16 ;read current secondary address EBF2 C9 0F CMP #$0F ;command channel ? EBF4 F0 23 BEQ $EC19 ;yes, EBF6 D0 08 BNE $EC00 ;no, ******************************* Main routine to write to a channel EBF8 A5 17 LDA $17 ;read original secondary address value EBFA 29 8F AND #$8F EBFC C9 0F CMP #$0F ;command channel ? EBFE B0 19 BCS $EC19 ;yes, EC00 20 A1 ED JSR $EDA1 ;read current file type, SEQ ? EC03 B0 05 BCS $EC0A ;no, EC05 A5 18 LDA $18 ;get data byte EC07 4C 19 EE JMP $EE19 ;jump to write byte to channel for SEQ file ******************************* Test if file type USR, if not write to REL file EC0A D0 03 BNE $EC0F ;USR ? yes, EC0C 4C 97 FB JMP $FB97 ;jump to write to REL ******************************* Write to USR file, get next data byte EC0F A5 18 LDA $18 ;get data byte EC11 20 B1 EC JSR $ECB1 ;write byte to channel EC14 A4 15 LDY $15 ;read channel number for next data byte EC16 4C E7 EF JMP $EFE7 ;jump to direct file character get routine ******************************* Set for maximum channel, test buffer pointer or write until last byte EC19 A9 06 LDA #$06 EC1B 85 15 STA $15 ;set for highest possible channel number EC1D 20 E1 F0 JSR $F0E1 ;read active buffer pointer EC20 C9 3B CMP #$3B ;is buffer full ? EC22 F0 05 BEQ $EC29 ;yes, EC24 A5 18 LDA $18 ;get data byte EC26 20 B1 EC JSR $ECB1 ;write byte to channel EC29 A5 A0 LDA $A0 ;last byte (EOI) ? EC2B F0 01 BEQ $EC2E ;yes EC2D 60 RTS ******************************* Set command waiting flag EC2E EE 47 43 INC $4347 ;increment command waiting flag EC31 60 RTS ******************************* Test if job done. If not done, continue. If OK then return, else redo job EC32 BD 03 10 LDA $1003,X ;is current job completed ? EC35 30 49 BMI $EC80 ;no, EC37 C9 02 CMP #$02 ;job completed properly ? EC39 90 3D BCC $EC78 ;yes, EC3B DE 5D 43 DEC $435D,X ;job to be retried ? EC3E 10 3A BPL $EC7A ;yes, EC40 2C 9E 43 BIT $439E ;job queue returned with hard error ? EC43 30 33 BMI $EC78 ;no, EC45 2C 5C 43 BIT $435C ;has the amount of attempts to correct the problem expired ? EC48 30 29 BMI $EC73 ;yes, EC4A 98 TYA EC4B 48 PHA EC4C BD 4E 43 LDA $434E,X ;read last job executed EC4F 29 01 AND #$01 ;set corresponding drive number for job EC51 09 C0 ORA #$C0 ;set for head placement of drive to track 1 EC53 9D 03 10 STA $1003,X ;set current job for drive to: BUMP EC56 BD 03 10 LDA $1003,X ;is job completed ? EC59 30 FB BMI $EC56 ;no, ******************************* Retry current job .Y amount of times EC5B AD 5C 43 LDA $435C ;read number of attempts value to determine how many times job can be reattempted EC5E 29 3F AND #$3F ;isolate recovery count value EC60 A8 TAY EC61 BD 4E 43 LDA $434E,X ;read last job executed EC64 9D 03 10 STA $1003,X ;set as current job EC67 BD 03 10 LDA $1003,X ;is job completed ? EC6A 30 FB BMI $EC67 ;no, EC6C C9 02 CMP #$02 ;job completed properly ? EC6E 90 06 BCC $EC76 ;yes, EC70 88 DEY ;has the amount of attempts to correct the problem expired ? EC71 D0 EE BNE $EC61 ;no, EC73 4C 1C D9 JMP $D91C ;jump to controller error entry point routine ******************************* Job done properly, restore .Y register to original value EC76 68 PLA EC77 A8 TAY EC78 18 CLC ;set .C to indicate no jobs present EC79 60 RTS ******************************* Set last job executed back up for a retry EC7A BD 4E 43 LDA $434E,X ;read last job executed EC7D 9D 03 10 STA $1003,X ;set as current job EC80 38 SEC ;set .C to indicate job present EC81 60 RTS ******************************* Test if job completed, clear job present flag when job completed properly EC82 20 32 EC JSR $EC32 ;has job been executed and terminated ? EC85 B0 FB BCS $EC82 ;no, EC87 48 PHA EC88 A9 00 LDA #$00 EC8A 8D 9E 43 STA $439E ;clear job present flag EC8D 68 PLA EC8E 60 RTS ******************************* Set track, sector, ID for current buffer EC8F 20 98 FA JSR $FA98 ;get active buffer number EC92 0A ASL ;multiply by 2 EC93 0A ASL ;multiply new value by 2 EC94 0A ASL ;multiply new value by 2 EC95 A8 TAY EC96 A5 13 LDA $13 ;read current track number EC98 99 23 10 STA $1023,Y ;set as job track number EC9B A5 14 LDA $14 ;read current sector number EC9D 99 24 10 STA $1024,Y ;set as job sector number ECA0 A5 12 LDA $12 ;read current drive number ECA2 0A ASL ECA3 AA TAX ECA4 BD 40 43 LDA $4340,X ;read ID1 for current drive ECA7 99 21 10 STA $1021,Y ;set as job ID1 for disk ECAA BD 41 43 LDA $4341,X ;read ID2 for current drive ECAD 99 22 10 STA $1022,Y ;set as job ID2 for disk ECB0 60 RTS ******************************* Test for valid buffer ECB1 48 PHA ECB2 20 98 FA JSR $FA98 ;is there and active buffer number ? ECB5 10 06 BPL $ECBD ;yes, ECB7 68 PLA ECB8 A9 61 LDA #$61 ;set for "61 FILE NOT OPEN" error ECBA 4C C3 DB JMP $DBC3 ;jump to process command error routine ******************************* Store byte in assigned buffer position ECBD 0A ASL ;multiply buffer number by 2 ECBE AA TAX ECBF 68 PLA ECC0 81 29 STA ($29,X) ;store byte in assigned buffer position ECC2 F6 29 INC $29,X ;increment buffer pointer ECC4 60 RTS ******************************* Command: INITIALIZE (read BAM) ECC5 20 CC DB JSR $DBCC ;test for proper syntax and drive number ECC8 20 FA EC JSR $ECFA ;read BAM from diskette ECCB AD 91 43 LDA $4391 ;both drives request initialisation ? ECCE 10 0C BPL $ECDC ;no, ECD0 20 86 DD JSR $DD86 ;toggle drive number ECD3 20 2C DA JSR $DA2C ;turn on activity LED specified by drive ECD6 20 FA EC JSR $ECFA ;read BAM from diskette ECD9 20 86 DD JSR $DD86 ;toggle drive number ECDC 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* Set up job queue and locate track 18, sector 0 ECDF A5 12 LDA $12 ;read current drive number ECE1 18 CLC ECE2 69 0C ADC #$0C ;add job queue value to drive value ECE4 85 A1 STA $A1 ;set as current job number ECE6 A2 12 LDX #$12 ECE8 86 13 STX $13 ;set track number to #$12 (decimal 18) ECEA A2 00 LDX #$00 ECEC 86 14 STX $14 ;set sector number to #$00 ECEE 20 92 EC JSR $EC92 ;set track, sector, ID's for current drive ECF1 A6 A1 LDX $A1 ;read current job number ECF3 A5 12 LDA $12 ;read current drive number ECF5 09 B0 ORA #$B0 ;set for search of sector #$00 on specified drive: SEEK ECF7 4C 9D F1 JMP $F19D ;perform requested job ******************************* Read BAM from diskette in current drive ECFA 20 54 EF JSR $EF54 ;clear all channels ECFD 20 DF EC JSR $ECDF ;set up job queue and locate track 18, sector 0 ED00 A9 00 LDA #$00 ED02 99 24 10 STA $1024,Y ;set job track number to #$00 ED05 A5 12 LDA $12 ;read current drive number ED07 09 80 ORA #$80 ;set job type to READ ED09 20 9D F1 JSR $F19D ;perform requested job ED0C A5 12 LDA $12 ;read current drive drive number ED0E 0A ASL ED0F AA TAX ED10 B9 21 10 LDA $1021,Y ;read job disk ID1 number ED13 9D 40 43 STA $4340,X ;set as ID1 value ED16 B9 22 10 LDA $1022,Y ;read job disk ID2 number ED19 9D 41 43 STA $4341,X ;set as ID2 value ED1C 60 RTS ******************************* Start double buffering, use track and sector as starting block ED1D 20 8F EC JSR $EC8F ;set track, sector, ID for current buffer ED20 20 41 ED JSR $ED41 ;set for READ job ED23 20 82 EC JSR $EC82 ;wait until job completed ED26 20 B3 ED JSR $EDB3 ;read 1st byte from second data block ED29 85 13 STA $13 ;set as current track ED2B 20 B3 ED JSR $EDB3 ;read 2nd byte from second data block ED2E 85 14 STA $14 ;set as current sector ED30 A5 13 LDA $13 ;last data block in file chain ? ED32 D0 01 BNE $ED35 ;no, ED34 60 RTS ******************************* Begin double buffering ED35 20 D1 EB JSR $EBD1 ;perform double buffering for data block 1 ED38 20 8F EC JSR $EC8F ;set track, sector, ID for current buffer ED3B 20 41 ED JSR $ED41 ;set for READ job ED3E 4C D1 EB JMP $EBD1 ;jump to perform double buffering for data block 2 ******************************* Set for READ job ED41 A9 80 LDA #$80 ;is job type other than read ? ED43 D0 02 BNE $ED47 ;no, ******************************* Set for WRITE job ED45 A9 90 LDA #$90 ;set job type to write ******************************* Perform requested job ED47 8D 3C 43 STA $433C ;set temporary job command ED4A 20 98 FA JSR $FA98 ;get active buffer number ED4D AA TAX ED4E 20 0E F1 JSR $F10E ;test track & sector validity, read buffer number ED51 8A TXA ED52 48 PHA ;preserve buffer number ED53 0A ASL ;calculate index into buffer table ED54 AA TAX ED55 A9 00 LDA #$00 ED57 95 29 STA $29,X ;store #$00 (decimal 0) in calculate buffer table ED59 20 A1 ED JSR $EDA1 ;read current file type ED5C C9 04 CMP #$04 ;is it SEQ ? ED5E B0 06 BCS $ED66 ;no, ED60 F6 59 INC $59,X ;increment LO byte of block count, still smaller than #$FF (decimal 255) ? ED62 D0 02 BNE $ED66 ;yes, ED64 F6 61 INC $61,X ;increment HI byte of block count ED66 68 PLA ;restore previous buffer number ED67 AA TAX ED68 60 RTS ******************************* Find internal read channel ED69 A5 16 LDA $16 ;read current secondary address ED6B C9 13 CMP #$13 ;is secondary address greater than #$13 (decimal 19) ? ED6D 90 02 BCC $ED71 ;no, ED6F 29 0F AND #$0F ;mask off secondary address above #$0F (decimal 15) ED71 C9 0F CMP #$0F ;secondary address #$0F (decimal 15) ? ED73 D0 02 BNE $ED77 ;no, ED75 A9 10 LDA #$10 ;set secondary address error value to #$10 (decimal 16) ED77 AA TAX ED78 38 SEC ;set channel status flag ED79 B5 A2 LDA $A2,X ;channel status set for read mode ? bit 7-6: 00 = read channel 10 = write channel 01 = read/write channel 11 = no channel ED7B 30 06 BMI $ED83 ;no, ED7D 29 0F AND #$0F ;establish internal channel read channel number ED7F 85 15 STA $15 ;set as current logical index ED81 AA TAX ED82 18 CLC ;clear channel status flag ED83 60 RTS ******************************* Find internal write channel ED84 A5 16 LDA $16 ;read current secondary address ED86 C9 13 CMP #$13 ;is secondary address greater than #$13 (decimal 19) ? ED88 90 02 BCC $ED8C ;no, ED8A 29 0F AND #$0F ;mask off secondary address above #$0F (decimal 15) ED8C AA TAX ED8D B5 A2 LDA $A2,X ;channel status set for write mode ? bit 7-6: 00 = read channel 10 = write channel 01 = read/write channel 11 = no channel ED8F A8 TAY ;preserve channel status ED90 0A ASL ;flag set for write channel ? ED91 90 0A BCC $ED9D ;no, ED93 30 0A BMI $ED9F ;channel available ? no, ED95 98 TYA ;retrieve channel status ED96 29 0F AND #$0F ;mask off all high order bits ED98 85 15 STA $15 ;set as current active channel ED9A AA TAX ED9B 18 CLC ;clear channel status flag ED9C 60 RTS ED9D 30 F6 BMI $ED95 ;channel inactive ? yes, ED9F 38 SEC ;set channel status flag EDA0 60 RTS ******************************* Get current file type EDA1 A6 15 LDX $15 ;read current channel number EDA3 B5 90 LDA $90,X ;get appropriate file type for channel EDA5 4A LSR ;divide file type by 2 EDA6 29 07 AND #$07 ;mask off high order bits eliminating file type 7 (direct) EDA8 C9 04 CMP #$04 ;REL file type ? (.Z=1 if yes) EDAA 60 RTS ******************************* Set buffer pointers .X = buffer number .Y = channel number EDAB 20 98 FA JSR $FA98 ;get active buffer number EDAE 0A ASL ;multiply buffer number by 2 EDAF AA TAX EDB0 A4 15 LDY $15 ;read current channel number EDB2 60 RTS ******************************* Read byte from active buffer and set .Z flag if last data byte EDB3 20 AB ED JSR $EDAB ;set buffer pointers EDB6 B9 BD 00 LDA $00BD,Y ;last character pointer in buffer #$00 ? EDB9 F0 12 BEQ $EDCD ;yes, EDBB A1 29 LDA ($29,X) ;read data byte from buffer EDBD 48 PHA ;preserve it EDBE B5 29 LDA $29,X ;read LO pointer of buffer pointer EDC0 D9 BD 00 CMP $00BD,Y ;end of buffer reached ? EDC3 D0 04 BNE $EDC9 ;no, EDC5 A9 FF LDA #$FF EDC7 95 29 STA $29,X ;set LO buffer pointer to #$FF (decimal 255) EDC9 68 PLA ;retrieve data byte EDCA F6 29 INC $29,X ;set LO buffer pointer to #$00 EDCC 60 RTS EDCD A1 29 LDA ($29,X) ;read data byte from buffer EDCF F6 29 INC $29,X ;move buffer pointer to next data byte in buffer EDD1 60 RTS ******************************* Get byte from file and read next block of file if needed. Set EOI if end of file EDD2 20 B3 ED JSR $EDB3 ;last byte from active buffer read ? EDD5 D0 36 BNE $EE0D ;no, EDD7 85 18 STA $18 ;store data byte EDD9 B9 BD 00 LDA $00BD,Y ;end of buffer reached ? EDDC F0 08 BEQ $EDE6 ;no, EDDE A9 80 LDA #$80 ;set for EOI byte marker EDE0 99 98 00 STA $0098,Y ;store EOI on channel status bit 7: = 1 (channel is talker to IEEE) 3: = 0 (send EOI on next byte) 0: = 1 (channel is listener to IEEE) EDE3 A5 18 LDA $18 ;retrieve last data byte read EDE5 60 RTS ******************************* Read next block of file EDE6 20 D1 EB JSR $EBD1 ;toggle current active and inactive buffers EDE9 A9 00 LDA #$00 EDEB 20 C1 F0 JSR $F0C1 ;set new pointer position EDEE 20 B3 ED JSR $EDB3 ;read byte from active buffer EDF1 C9 00 CMP #$00 ;last sector of file ? EDF3 F0 19 BEQ $EE0E ;yes, EDF5 85 13 STA $13 ;set as current track number EDF7 20 B3 ED JSR $EDB3 ;read byte from active buffer EDFA 85 14 STA $14 ;set as current sector number EDFC 20 D1 EB JSR $EBD1 ;toggle current active and inactive buffers EDFF 20 4F EE JSR $EE4F ;set drive number according to last job done EE02 20 8F EC JSR $EC8F ;set track, sector, ID for current buffer EE05 20 41 ED JSR $ED41 ;set for READ job EE08 20 D1 EB JSR $EBD1 ;toggle current active and inactive buffers EE0B A5 18 LDA $18 ;read last data byte stored EE0D 60 RTS ******************************* Set last character position for last byte of file EE0E 20 B3 ED JSR $EDB3 ;read byte from active buffer EE11 A4 15 LDY $15 ;read current channel number EE13 99 BD 00 STA $00BD,Y ;set as last character position in buffer EE16 A5 18 LDA $18 ;read last data byte stored EE18 60 RTS ******************************* Write a byte to channel and write buffer out to disk if full EE19 20 B1 EC JSR $ECB1 ;is current buffer full ? EE1C F0 01 BEQ $EE1F ;yes, EE1E 60 RTS EE1F 20 4F EE JSR $EE4F ;set drive number according to last job done EE22 20 AF D6 JSR $D6AF ;find free sector on disk EE25 A9 00 LDA #$00 EE27 20 C1 F0 JSR $F0C1 ;set new pointer position to beginning of buffer EE2A A5 13 LDA $13 ;read current track number EE2C 20 B1 EC JSR $ECB1 ;write track number in buffer EE2F A5 14 LDA $14 ;read current sector number EE31 20 B1 EC JSR $ECB1 ;write sector number in buffer EE34 20 45 ED JSR $ED45 ;set for WRITE job EE37 20 D1 EB JSR $EBD1 ;toggle current active and inactive buffers EE3A 20 8F EC JSR $EC8F ;set track, sector, ID for current buffer EE3D A9 02 LDA #$02 EE3F 4C C1 F0 JMP $F0C1 ;set new pointer position to 3rd byte in buffer ******************************* Increment pointer of active buffer EE42 85 04 STA $04 ;store current pointer position EE44 20 E1 F0 JSR $F0E1 ;read active buffer pointer EE47 18 CLC EE48 65 04 ADC $04 ;add buffer pointer value to current buffer pointer position value EE4A 95 29 STA $29,X ;store value in buffer EE4C 85 27 STA $27 ;store value in directory buffer EE4E 60 RTS ******************************* Set drive number indicated by last job in active buffer EE4F 20 98 FA JSR $FA98 ;get active buffer number EE52 AA TAX EE53 BD 4E 43 LDA $434E,X ;read last job executed EE56 29 01 AND #$01 ;calculate appropriate drive number EE58 85 12 STA $12 ;set as current drive number EE5A 60 RTS ******************************* Set for opening of new write channel EE5B 38 SEC ;write channel active ? EE5C B0 01 BCS $EE5F ;yes, ******************************* Set for opening of new read channel EE5E 18 CLC ;activate read channel ******************************* Perform opening of desired channel EE5F 08 PHP ;preserve read/write flag status EE60 85 04 STA $04 ;store number of buffers needed EE62 20 9F EE JSR $EE9F ;free read/write channels EE65 20 79 EF JSR $EF79 ;find an available channel and allocate it EE68 85 15 STA $15 ;set as current channel number EE6A A6 16 LDX $16 ;read current secondary address EE6C 28 PLP ;retrieve read/write status, open read channel ? EE6D 90 02 BCC $EE71 ;yes, EE6F 09 80 ORA #$80 ;set for open write channel EE71 95 A2 STA $A2,X ;store channel status bits 7-6: 00 = read channel 10 = write channel 01 = read/write channel 11 = no channel EE73 29 3F AND #$3F ;establish number of internal channels EE75 A8 TAY EE76 A9 FF LDA #$FF EE78 99 49 00 STA $0049,Y ;de-allocate associated flags for buffer EE7B 99 51 00 STA $0051,Y ;de-allocate associated buffer EE7E C6 04 DEC $04 ;all buffers needed allocated ? EE80 30 1C BMI $EE9E ;yes, EE82 20 FE EE JSR $EEFE ;new buffer allocated ? EE85 10 08 BPL $EE8F ;yes, ******************************* Indicate channel unavailability EE87 20 CA EE JSR $EECA ;release all allocated buffers EE8A A9 70 LDA #$70 ;set for "70 NO CHANNEL", no channel available EE8C 4C C3 DB JMP $DBC3 ;jump to process command error routine ******************************* De-allocate additional buffer EE8F 99 49 00 STA $0049,Y ;de-allocate associated flags for buffer EE92 C6 04 DEC $04 ;all buffers needed allocated ? EE94 30 08 BMI $EE9E ;yes, EE96 20 FE EE JSR $EEFE ;new buffer allocated ? EE99 30 EC BMI $EE87 ;no, EE9B 99 51 00 STA $0051,Y ;de-allocate associated buffer EE9E 60 RTS ******************************* Test current secondary address for command channel. EE9F A5 16 LDA $16 ;read current secondary address EEA1 C9 0F CMP #$0F ;is secondary address #$0F (decimal 15) ? EEA3 D0 01 BNE $EEA6 ;no, EEA5 60 RTS ******************************* Free read/write channels EEA6 A6 16 LDX $16 ;read current secondary address EEA8 B5 A2 LDA $A2,X ;read current channel status bits 7-6: 00 = read channel 10 = write channel 01 = read/write channel 11 = no channel EEAA C9 FF CMP #$FF ;is this an active channel ? EEAC F0 1B BEQ $EEC9 ;no, EEAE 29 3F AND #$3F ;calculate channel number EEB0 85 15 STA $15 ;set as current channel number EEB2 A9 FF LDA #$FF EEB4 95 A2 STA $A2,X ;set associated channel to inactive bits 7-6: 00 = read channel 10 = write channel 01 = read/write channel 11 = no channel EEB6 20 CA EE JSR $EECA ;release all allocated buffers EEB9 A6 15 LDX $15 ;read current channel number EEBB A9 01 LDA #$01 ;set bit flag to "channel free" EEBD CA DEX ;all channels done ? EEBE 30 03 BMI $EEC3 ;yes, EEC0 0A ASL ;multiply bit flag by 2 now gives #$00 result ? EEC1 D0 FA BNE $EEBD ;no, EEC3 0D 48 43 ORA $4348 ;calculate free channels left EEC6 8D 48 43 STA $4348 ;store as new amount of free channels left EEC9 60 RTS ******************************* Release buffers and corresponding channel EECA A6 15 LDX $15 ;get current channel number EECC B5 49 LDA $49,X ;read buffer #0 status EECE C9 FF CMP #$FF ;is it already free ? EED0 F0 09 BEQ $EEDB ;yes, EED2 48 PHA ;preserve current buffer #0 index value EED3 A9 FF LDA #$FF EED5 95 49 STA $49,X ;set buffer #0 status to free, #$FF (decimal 255) EED7 68 PLA ;retrieve buffer value EED8 20 34 EF JSR $EF34 ;free buffer #0 EEDB A6 15 LDX $15 ;get current channel number EEDD B5 51 LDA $51,X ;read buffer #1 status EEDF C9 FF CMP #$FF ;is it already free ? EEE1 F0 09 BEQ $EEEC ;yes, EEE3 48 PHA ;preserve current buffer #1 index value EEE4 A9 FF LDA #$FF EEE6 95 51 STA $51,X ;set buffer #1 status to free, #$FF (decimal 255) EEE8 68 PLA ;retrieve buffer value EEE9 20 34 EF JSR $EF34 ;free buffer #1 EEEC A6 15 LDX $15 ;get current channel number EEEE B5 79 LDA $79,X ;read side sector status EEF0 C9 FF CMP #$FF ;is it already free ? EEF2 F0 09 BEQ $EEFD ;yes, EEF4 48 PHA ;preserve side sector value EEF5 A9 FF LDA #$FF EEF7 95 79 STA $79,X ;set side sector to free, #$FF (decimal 255) EEF9 68 PLA EEFA 20 34 EF JSR $EF34 ;free side sector buffer EEFD 60 RTS ******************************* Get a free buffer number. If successful, initialize $1003 and $434E .Y = channel number .ACC = buffer number EEFE A9 FF LDA #$FF EF00 85 05 STA $05 ;clear TEMP1 flag EF02 A2 0F LDX #$0F EF04 2E 3E 43 ROL $433E ;displace buffer index by one bit EF07 2E 3F 43 ROL $433F ;displace buffer index by one bit EF0A B0 05 BCS $EF11 ;buffer occupied ? yes, EF0C 86 05 STX $05 ;store free buffer location EF0E 38 SEC ;allocate buffer, buffer allocated ? EF0F B0 18 BCS $EF29 ;yes, EF11 CA DEX ;all buffers tested for availability ? EF12 10 F0 BPL $EF04 ;no, EF14 A6 05 LDX $05 ;read buffer status, ok to steal ? EF16 30 0F BMI $EF27 ;no, EF18 BD 03 10 LDA $1003,X ;job in progress ? EF1B 30 FB BMI $EF18 ;yes, EF1D A9 00 LDA #$00 EF1F 9D 03 10 STA $1003,X ;clear assigned job queue EF22 A5 12 LDA $12 ;read current drive number EF24 9D 4E 43 STA $434E,X ;store drive number in last job perform flag for assigned job queue EF27 8A TXA ;give up, no buffer available EF28 60 RTS ******************************* Locate a buffer to steal EF29 2E 3E 43 ROL $433E ;displace buffer index by one bit EF2C 2E 3F 43 ROL $433F ;displace buffer index by one bit EF2F CA DEX ;all buffer indexes tested ? EF30 10 F7 BPL $EF29 ;no, EF32 30 E0 BMI $EF14 ;found a possible buffer ? ******************************* Free buffer index EF34 29 0F AND #$0F ;mask off HI order bits EF36 A8 TAY ;transfer result to .Y register EF37 C8 INY ;increment counter EF38 A2 10 LDX #$10 ;set for total number of buffers #$10 (decimal 16) EF3A 6E 3F 43 ROR $433F ;displace buffer index by one bit EF3D 6E 3E 43 ROR $433E ;displace buffer index by one bit EF40 88 DEY ;have we counted down to #$00 ? EF41 D0 01 BNE $EF44 ;no, EF43 18 CLC ;clear buffer EF44 CA DEX ;all buffers free ? EF45 10 F3 BPL $EF3A ;no, EF47 60 RTS ******************************* Clear all channels except COMMAND channel EF48 A9 0E LDA #$0E EF4A 85 16 STA $16 ;set current secondary address to #$0E (decimal 14) EF4C 20 9F EE JSR $EE9F ;free requested read/write channel EF4F C6 16 DEC $16 ;all channels closed ? EF51 D0 F9 BNE $EF4C ;no, EF53 60 RTS ******************************* Close all channels except COMMAND channel EF54 A9 0E LDA #$0E EF56 85 16 STA $16 ;set current secondary address to #$0E (decimal 14) EF58 A6 16 LDX $16 ;get current secondary address number EF5A B5 A2 LDA $A2,X ;read current channel status bit 7-6: 00 = read channel 10 = write channel 01 = read/write channel 11 = no channel EF5C C9 FF CMP #$FF ;channel already closed ? EF5E F0 14 BEQ $EF74 ;yes, EF60 29 3F AND #$3F ;mask off HI order bits EF62 85 15 STA $15 ;set as current channel number EF64 20 98 FA JSR $FA98 ;get active buffer number EF67 AA TAX EF68 BD 4E 43 LDA $434E,X ;read next job code EF6B 29 01 AND #$01 ;test drive number EF6D C5 12 CMP $12 ;ok to close channel for requested drive ? EF6F D0 03 BNE $EF74 ;no, EF71 20 9F EE JSR $EE9F ;free requested read/write channel EF74 C6 16 DEC $16 ;all channels done ? EF76 10 E0 BPL $EF58 ;no, EF78 60 RTS ******************************* Find a free logical index to use .Y = counter for channels EF79 A0 00 LDY #$00 EF7B A9 01 LDA #$01 ;set for testing of a free channel EF7D 2C 48 43 BIT $4348 ;free channel available ? EF80 D0 09 BNE $EF8B ;yes, EF82 C8 INY ;increment channel counter EF83 0A ASL ;all possible channels tested ? EF84 D0 F7 BNE $EF7D ;no, EF86 A9 70 LDA #$70 ;set for "70 NO CHANNEL" error EF88 4C C3 DB JMP $DBC3 ;jump to process command error routine ******************************* Mark free logical index as used in table .ACC = new logical index EF8B 49 FF EOR #$FF ;toggle bit mask EF8D 2D 48 43 AND $4348 ;mark bit position as used EF90 8D 48 43 STA $4348 ;store new logical index status EF93 98 TYA ;transfer new logical index status EF94 60 RTS ******************************* Get a byte from a channel EF95 20 69 ED JSR $ED69 ;find internal read channel EF98 20 2C DA JSR $DA2C ;turn on activity LED specified by drive EF9B 20 A3 EF JSR $EFA3 ;read a byte over channel from any file type EF9E A6 15 LDX $15 ;read current channel number EFA0 B5 B5 LDA $B5,X ;read channel data byte EFA2 60 RTS ******************************* Read a byte over channel from any file type EFA3 A6 15 LDX $15 ;read current channel number EFA5 20 A1 ED JSR $EDA1 ;current file type REL ? EFA8 D0 03 BNE $EFAD ;no, EFAA 4C 04 FC JMP $FC04 ;jump to read byte from RELative file routine ******************************* Read a byte from file EFAD A5 16 LDA $16 ;get current secondary address EFAF C9 0F CMP #$0F ;is this the command channel ? EFB1 F0 59 BEQ $F00C ;yes, EFB3 B5 98 LDA $98,X ;read channel status bit 7 = 1 (channel is talker to IEEE) 3 = 0 (send EOI on next byte, talker only) 0 = 1 (channel is listener to IEEE) EFB5 29 08 AND #$08 ;last byte sent was EOI ? EFB7 D0 13 BNE $EFCC ;no, EFB9 20 A1 ED JSR $EDA1 ;get current file type EFBC C9 07 CMP #$07 ;random access file type under use ? EFBE D0 07 BNE $EFC7 ;no, EFC0 A9 89 LDA #$89 ;set for "direct file remains active" status EFC2 95 98 STA $98,X ;store new channel status bit 7 = 1 (channel is talker to IEEE) 3 = 0 (send EOI on next byte, talker only) 0 = 1 (channel is listener to IEEE) EFC4 4C D7 EF JMP $EFD7 ;jump to get byte from RELative file buffer ******************************* EOI received, set new channel status EFC7 A9 00 LDA #$00 ;set channel status to "NOT READY" EFC9 95 98 STA $98,X ;store new channel status bit 7 = 1 (channel is talker to IEEE) 3 = 0 (send EOI on next byte, talker only) 0 = 1 (channel is listener to IEEE) EFCB 60 RTS ******************************* Test if LOAD command received EFCC A5 16 LDA $16 ;current secondary address #$00 ? EFCE F0 31 BEQ $F001 ;yes, ******************************* Test file type for random access EFD0 20 A1 ED JSR $EDA1 ;get current file type EFD3 C9 04 CMP #$04 ;file type RELative ? EFD5 90 22 BCC $EFF9 ;no, ******************************* Read byte from RELative file EFD7 20 AB ED JSR $EDAB ;set buffer pointers EFDA B5 29 LDA $29,X ;read character pointer value EFDC D9 BD 00 CMP $00BD,Y ;reached last position yet ? EFDF D0 04 BNE $EFE5 ;no, EFE1 A9 00 LDA #$00 EFE3 95 29 STA $29,X ;reset character pointer value to #$00 EFE5 F6 29 INC $29,X ;move pointer to next character in buffer EFE7 A1 29 LDA ($29,X) ;read data byte from buffer EFE9 99 B5 00 STA $00B5,Y ;store data byte EFEC B5 29 LDA $29,X ;read character pointer value EFEE D9 BD 00 CMP $00BD,Y ;reached last position yet ? EFF1 D0 05 BNE $EFF8 ;no, EFF3 A9 81 LDA #$81 ;set channel status for EOI EFF5 99 98 00 STA $0098,Y ;store new channel status bit 7 = 1 (channel is talker to IEEE) 3 = 0 (send EOI on next byte, talker only) 0 = 1 (channel is listener to IEEE) EFF8 60 RTS ******************************* Read byte from SEQuential file EFF9 20 D2 ED JSR $EDD2 ;get byte from file and set for next file block EFFC A6 15 LDX $15 ;read current channel number EFFE 95 B5 STA $B5,X ;store data byte F000 60 RTS ******************************* Test if "DIRECTORY" issued read F001 AD 46 43 LDA $4346 ;is this a DIRECTORY listing ? F004 F0 F3 BEQ $EFF9 ;no, F006 20 11 DB JSR $DB11 ;get byte from directory F009 4C FC EF JMP $EFFC ;jump to process byte from directory track ******************************* Get character from error channel F00C 20 E1 F0 JSR $F0E1 ;read active buffer pointer F00F C9 DB CMP #$DB ;pointer set to error buffer ? F011 D0 18 BNE $F02B ;no, F013 A5 28 LDA $28 ;get pointer HI byte F015 C9 43 CMP #$43 ;is it pointing to #$43 (directory buffer) F017 D0 12 BNE $F02B ;no, F019 A9 0D LDA #$0D ;set for #$0D (decimal 13) F01B 85 18 STA $18 ;store a carriage RETURN value in temporary data byte location F01D 20 42 DA JSR $DA42 ;turn off LED F020 A9 00 LDA #$00 F022 20 CE D9 JSR $D9CE ;set track and sector to #$00, set up error message F025 C6 47 DEC $47 ;set pointer to start of error message F027 A9 80 LDA #$80 ;set for EOI (End Or Identify) F029 D0 12 BNE $F03D ;jump to store channel status ******************************* Set bytes from error buffer to be output F02B 20 B3 ED JSR $EDB3 ;read byte from error buffer, set .Z flag if last data byte F02E 85 18 STA $18 ;store in temporary data byte location F030 D0 09 BNE $F03B ;reached end of buffer ? no, ******************************* Set pointer for error message buffer F032 A9 DB LDA #$DB F034 20 C1 F0 JSR $F0C1 ;set buffer pointer for error buffer F037 A9 43 LDA #$43 F039 95 2A STA $2A,X ;set pointer HI byte ******************************* Initialize error message channel F03B A9 88 LDA #$88 ;set for "READ" and "EOI" F03D 85 9F STA $9F ;set channel status F03F A5 18 LDA $18 ;read byte from temporary data byte location F041 85 BC STA $BC ;store byte in output channel F043 60 RTS ******************************* Read next buffer of a file, follow links in first two bytes. End of file if: byte 0 = #$00 1 = last character position in block F044 20 98 FA JSR $FA98 ;get active buffer number F047 0A ASL ;double it F048 AA TAX F049 A9 00 LDA #$00 F04B 95 29 STA $29,X ;set pointer to start position in buffer F04D A1 29 LDA ($29,X) ;read byte 0 from buffer, is it #$00 ? F04F F0 05 BEQ $F056 ;yes, F051 D6 29 DEC $29,X ;set buffer pointer to end of current block F053 4C D2 ED JMP $EDD2 ;get byte from file and set up next block F056 60 RTS ******************************* Entrance point for direct BLOCK-READ F057 A9 80 LDA #$80 ;set for READ SECTOR job, job to do ? F059 D0 02 BNE $F05D ;yes, ******************************* Entrance point for direct BLOCK-WRITE F05B A9 90 LDA #$90 ;set for WRITE SECTOR job F05D 05 12 ORA $12 ;add in selected drive number F05F 8D 3C 43 STA $433C ;store result in temporary job command location F062 A5 A1 LDA $A1 F064 20 92 EC JSR $EC92 ;set track, sector, ID for current buffer F067 A6 A1 LDX $A1 ;read current buffer number F069 4C A0 F1 JMP $F1A0 ;perform requested job ******************************* Open internal read channel (SA = 17) F06C A9 11 LDA #$11 ;set for #$11 (decimal 17) F06E 85 16 STA $16 ;set current secondary address number F070 A9 01 LDA #$01 F072 85 C5 STA $C5 ;set SEQ file type F074 20 47 F7 JSR $F747 ;open an internal read channel with 2 buffers F077 A9 02 LDA #$02 F079 4C C1 F0 JMP $F0C1 ;set buffer pointer position ******************************* Open internal write channel (SA = 18) F07C A9 12 LDA #$12 ;set for #$12 (decimal 18) F07E 85 16 STA $16 ;set current secondary address number F080 4C E6 F7 JMP $F7E6 ;jump to open internal write channel ******************************* Allocate next directory block on track 18 and mark as used in BAM F083 20 3E F9 JSR $F93E ;set track and sector values F086 A9 01 LDA #$01 F088 85 04 STA $04 ;set number of sector to allocate F08A AD 44 43 LDA $4344 ;read sector increment value F08D 48 PHA ;preserve it F08E A9 03 LDA #$03 F090 8D 44 43 STA $4344 ;set new sector increment to #$03 F093 20 B6 D6 JSR $D6B6 ;return next available track and sector F096 68 PLA ;retrieve sector increment F097 8D 44 43 STA $4344 ;reset normal sector increment F09A A9 00 LDA #$00 F09C 20 C1 F0 JSR $F0C1 ;set buffer pointer position F09F A5 13 LDA $13 ;get track number F0A1 20 B1 EC JSR $ECB1 ;write track number in valid buffer F0A4 A5 14 LDA $14 ;get sector number F0A6 20 B1 EC JSR $ECB1 ;write sector number to valid buffer F0A9 20 45 ED JSR $ED45 ;set WRITE job F0AC 20 82 EC JSR $EC82 ;wait until job completed F0AF A9 00 LDA #$00 F0B1 20 C1 F0 JSR $F0C1 ;set buffer pointer position F0B4 20 B1 EC JSR $ECB1 ;all fill bytes written to buffer ? F0B7 D0 FB BNE $F0B4 ;no, F0B9 20 B1 EC JSR $ECB1 ;set track link to #$00 F0BC A9 FF LDA #$FF F0BE 4C B1 EC JMP $ECB1 ;set sector link to #$FF ******************************* Set new pointer position . X = index to current buffer .ACC = new pointer position F0C1 85 04 STA $04 ;store pointer position in temporary location F0C3 20 98 FA JSR $FA98 ;get active buffer number F0C6 0A ASL ;double it F0C7 AA TAX F0C8 B5 2A LDA $2A,X ;read HI byte of buffer pointer F0CA 85 28 STA $28 ;set as HI byte of directory buffer pointer F0CC A5 04 LDA $04 ;get new pointer position F0CE 95 29 STA $29,X ;set as LO byte of buffer pointer F0D0 85 27 STA $27 ;set as LO byte of directory buffer pointer F0D2 60 RTS ******************************* Free internal READ and WRITE channels F0D3 A9 11 LDA #$11 ;set for #$11 (decimal 17) F0D5 85 16 STA $16 ;set as current secondary address number F0D7 20 9F EE JSR $EE9F ;clear internal read channel F0DA A9 12 LDA #$12 ;set for #$12 (decimal 18) F0DC 85 16 STA $16 ;set as current secondary address number F0DE 4C 9F EE JMP $EE9F ;clear internal write channel ******************************* Read active buffer pointer, set directory buffer .X = index to current buffer F0E1 20 98 FA JSR $FA98 ;get active buffer number F0E4 0A ASL ;double it F0E5 AA TAX F0E6 B5 2A LDA $2A,X ;read HI byte of buffer pointer F0E8 85 28 STA $28 ;set as HI byte of directory buffer F0EA B5 29 LDA $29,X ;read LO byte of buffer pointer F0EC 85 27 STA $27 ;set as LO byte of directory buffer F0EE 60 RTS ******************************* Direct byte read . X = index to current buffer .ACC = byte number to read F0EF 85 06 STA $06 ;set LO byte of buffer pointer for desired byte F0F1 20 98 FA JSR $FA98 ;get active buffer number F0F4 AA TAX F0F5 BD FF F0 LDA $F0FF,X ;read HI byte from buffer index table F0F8 85 07 STA $07 ;set as HI byte of buffer pointer F0FA A0 00 LDY #$00 F0FC B1 06 LDA ($06),Y ;read byte from assigned buffer F0FE 60 RTS ******************************* HI byte indexes for buffers F0FF 11 ??? ;buffer # 0, HI byte: $1100 F100 12 ??? ;buffer # 1, HI byte: $1200 F101 13 ??? ;buffer # 2, HI byte: $1300 F102 20 ??? ;buffer # 3, HI byte: $2000 F103 21 ??? ;buffer # 4, HI byte: $2100 F104 22 ??? ;buffer # 5, HI byte: $2200 F105 23 ??? ;buffer # 6, HI byte: $2300 F106 30 ??? ;buffer # 7, HI byte: $3000 F107 31 ??? ;buffer # 8, HI byte: $3100 F108 32 ??? ;buffer # 9, HI byte: $3200 F109 33 ??? ;buffer #10, HI byte: $3300 F10A 40 ??? ;buffer #11, HI byte: $4000 F10B 41 ??? ;buffer #12, HI byte: $4100 F10C 42 ??? ;buffer #13, HI byte: $4200 F10D 43 ??? ;buffer #14, HI byte: $4300 ******************************* Use last job for drive number and set job command F10E BD 4E 43 LDA $434E,X ;get last job issued F111 29 01 AND #$01 ;add in drive number F113 0D 3C 43 ORA $433C ;calculate new job command ******************************* Set job up and check track and sector . X = job number .ACC = command for job F116 48 PHA ;preserve new job command F117 86 A1 STX $A1 ;store buffer number in use F119 8A TXA F11A 0A ASL ;multiply buffer number by two F11B 0A ASL ;multiply new result by two F11C 0A ASL ;multiply new result by two F11D AA TAX F11E BD 24 10 LDA $1024,X ;read job header table sector number F121 8D 3C 43 STA $433C ;store sector number F124 BD 23 10 LDA $1023,X ;track number equal to #$00 ? F127 F0 2C BEQ $F155 ;yes, F129 C9 24 CMP #$24 ;track number below #$24 (decimal 36) ? F12B B0 28 BCS $F155 ;yes, F12D AA TAX F12E 68 PLA ;retrieve new job command F12F 48 PHA ;preserve new job command F130 29 F0 AND #$F0 ;test job type F132 C9 90 CMP #$90 ;is it a WRITE job ? F134 D0 52 BNE $F188 ;no, F136 68 PLA ;retrieve new job command F137 48 PHA ;preserve new job command F138 4A LSR ;shall drive 1 be used ? F139 B0 05 BCS $F140 ;yes, F13B AD 02 41 LDA $4102 ;format version number for drive 0 present ? F13E 90 03 BCC $F143 ;yes, F140 AD 02 42 LDA $4202 ;format version number for drive 1 present ? F143 F0 05 BEQ $F14A ;no, F145 CD 9F 10 CMP $109F ;format version compatible to DOS version ? F148 D0 36 BNE $F180 ;no, F14A 8A TXA ;transfer track number F14B 20 D2 D7 JSR $D7D2 ;calculate maximum sector number for track F14E CD 3C 43 CMP $433C ;valid sector number ? F151 F0 02 BEQ $F155 ;no, F153 B0 33 BCS $F188 ;yes, ******************************* Indicate track or sector unavailability F155 20 5D F1 JSR $F15D ;set track and sector number for error F158 A9 66 LDA #$66 ;set for "66 ILLEGAL TRACK OR SECTOR" error F15A 4C 53 D9 JMP $D953 ;jump to process error message ******************************* Set track and sector from values in JOB HEADER memory F15D A5 A1 LDA $A1 ;get current buffer number F15F 0A ASL ;multiply by two F160 0A ASL ;multiply new result by two F161 0A ASL ;multiply new result by two F162 AA TAX F163 BD 23 10 LDA $1023,X ;read track number F166 85 13 STA $13 ;set as current track number F168 BD 24 10 LDA $1024,X ;read sector number F16B 85 14 STA $14 ;set as current sector number F16D 60 RTS ******************************* Check track and sector validity F16E A5 13 LDA $13 ;read track number, is it #$00 ? F170 F0 E6 BEQ $F158 ;yes, F172 C9 24 CMP #$24 ;is it smaller than #$24 (decimal 36) ? F174 B0 E2 BCS $F158 ;no, F176 20 D2 D7 JSR $D7D2 ;calculate maximum sector number for track F179 C5 14 CMP $14 ;sector number below #$00 ? F17B F0 DB BEQ $F158 ;yes, F17D 90 D9 BCC $F158 ;sector number larger than allowable for this track ? F17F 60 RTS ******************************* Indicate invalid format version F180 20 5D F1 JSR $F15D ;set track and sector number for error F183 A9 73 LDA #$73 ;set for "73 CBM DOS V2.1" error, DOS version F185 4C 53 D9 JMP $D953 ;jump to process error message ******************************* Determine error count and activate job F188 A6 A1 LDX $A1 ;get current buffer number F18A AD 5C 43 LDA $435C ;read error recovery count value F18D 29 1F AND #$1F ;determine number of attempts before generation of a hard error F18F 9D 5D 43 STA $435D,X ;store result of calculation in current error count buffer F192 68 PLA ;retrieve job code F193 8D 3C 43 STA $433C ;store in temporary job command location F196 9D 03 10 STA $1003,X ;set in JOB QUE assigned to buffer F199 9D 4E 43 STA $434E,X ;store in last job table F19C 60 RTS ******************************* Set job and test if completed F19D 8D 3C 43 STA $433C ;store job code in temporary job command location F1A0 AD 3C 43 LDA $433C ;read job code found in temporary location F1A3 20 16 F1 JSR $F116 ;set job up and check track and sector F1A6 4C 82 EC JMP $EC82 ;jump to test job completion ******************************* Add file to directory F1A9 A5 16 LDA $16 ;read current secondary address F1AB 48 PHA ;preserve it F1AC A5 15 LDA $15 ;read channel number F1AE 48 PHA ;preserve it F1AF A5 14 LDA $14 ;read current sector number F1B1 48 PHA ;preserve it F1B2 A5 13 LDA $13 ;read current track number F1B4 48 PHA ;preserve it F1B5 A9 11 LDA #$11 ;set for #$11 (decimal 17) F1B7 85 16 STA $16 ;set current secondary address number F1B9 20 3E F9 JSR $F93E ;set track and sector values F1BC A5 C5 LDA $C5 ;read current file type F1BE 48 PHA ;preserve it F1BF A5 8B LDA $8B ;read new file data byte F1C1 29 01 AND #$01 ;determine drive number F1C3 85 12 STA $12 ;set as current drive number F1C5 A6 A1 LDX $A1 ;get current job number F1C7 5D 4E 43 EOR $434E,X ;test against last job performed F1CA 4A LSR ;use same drive number ? F1CB 90 0C BCC $F1D9 ;yes, F1CD A2 01 LDX #$01 F1CF 8E 98 43 STX $4398 ;set for search of a deleted directory entry F1D2 20 D0 DF JSR $DFD0 ;available directory entry in block ? F1D5 F0 1D BEQ $F1F4 ;no, F1D7 D0 28 BNE $F201 ;yes, F1D9 AD 97 43 LDA $4397 ;directory sector number set ? F1DC F0 0C BEQ $F1EA ;no, F1DE C5 14 CMP $14 ;same as current sector number ? F1E0 F0 1F BEQ $F201 ;yes, F1E2 85 14 STA $14 ;set new current sector number F1E4 20 57 F0 JSR $F057 ;read next directory block F1E7 4C 01 F2 JMP $F201 ;write new directory entry and store file ******************************* Find deleted entry in directory F1EA A9 01 LDA #$01 F1EC 8D 98 43 STA $4398 ;set for search of a deleted directory entry F1EF 20 39 E0 JSR $E039 ;deleted directory entry available ? F1F2 D0 0D BNE $F201 ;yes, F1F4 20 83 F0 JSR $F083 ;read next directory block of track 18 F1F7 A5 14 LDA $14 ;read current sector number F1F9 8D 97 43 STA $4397 ;set directory sector number F1FC A9 02 LDA #$02 F1FE 8D 98 43 STA $4398 ;set for search of a deleted directory entry F201 AD 98 43 LDA $4398 ;read pointer value F204 20 C1 F0 JSR $F0C1 ;set buffer pointer position F207 68 PLA ;retrieve file type F208 85 C5 STA $C5 ;set as active file type F20A C9 04 CMP #$04 ;is it an REL file ? F20C D0 02 BNE $F210 ;no, ******************************* Write RELative file F20E 09 80 ORA #$80 ;mark file type as closed F210 20 B1 EC JSR $ECB1 ;write file type to buffer F213 68 PLA ;retrieve track link number F214 8D 86 43 STA $4386 ;set as track number for file F217 20 B1 EC JSR $ECB1 ;write track link to buffer F21A 68 PLA ;retrieve sector link number F21B 8D 8B 43 STA $438B ;set as sector number of file F21E 20 B1 EC JSR $ECB1 ;write sector link to buffer F221 20 98 FA JSR $FA98 ;get active buffer number F224 A8 TAY F225 AD 80 43 LDA $4380 ;get file name pointer F228 AA TAX F229 A9 10 LDA #$10 ;set length of filename to #$10 (decimal 16) F22B 20 5F E0 JSR $E05F ;transfer filename from command buffer F22E A0 10 LDY #$10 ;set pointer to end of filename F230 A9 00 LDA #$00 F232 91 27 STA ($27),Y ;store #$00 in rest of directory entry F234 C8 INY F235 C0 1B CPY #$1B ;all bytes after filename nulled ? F237 90 F9 BCC $F232 ;no, F239 A5 C5 LDA $C5 ;read active file type F23B C9 04 CMP #$04 ;is it an REL file ? F23D D0 13 BNE $F252 ;no, F23F A0 10 LDY #$10 ;set pointer to end of filename F241 AD 4C 43 LDA $434C ;get track number of first side sector F244 91 27 STA ($27),Y ;write after filename in directory entry F246 C8 INY ;move pointer to side sector location F247 AD 4D 43 LDA $434D ;get side sector number of first side sector F24A 91 27 STA ($27),Y ;write after filename in directory entry F24C C8 INY ;move pointer to record length location F24D AD 4B 43 LDA $434B ;get record length F250 91 27 STA ($27),Y ;write after filename in directory entry F252 20 5B F0 JSR $F05B ;write newly updated directory block F255 68 PLA ;retrieve channel F256 85 15 STA $15 ;set as current channel number F258 AA TAX F259 68 PLA ;retrieve secondary address F25A 85 16 STA $16 ;set as current secondary address F25C AD 97 43 LDA $4397 ;read directory sector number F25F 29 1F AND #$1F ;calculate index number F261 85 86 STA $86 ;store in file entry table F263 AD 98 43 LDA $4398 ;read newly stored file position F266 29 E0 AND #$E0 ;calculate sector F268 05 86 ORA $86 ;add in index F26A 85 86 STA $86 ;store new index/sector value F26C 9D 6B 43 STA $436B,X ;set directory entry position allocated for new file entry F26F A5 C5 LDA $C5 ;get file type F271 0A ASL ;multiply by two F272 29 1E AND #$1E ;clear drive number bit F274 05 12 ORA $12 ;add in current drive number F276 85 8B STA $8B ;set drive number corresponding to file F278 60 RTS ******************************* Open channel from IEEE, parse the input string that is sent as an open data channel (LOAD or SAVE). Channels are allocated and the directory is searched for the filename contained in the string. F279 A5 16 LDA $16 ;read current secondary address F27B 8D 3B 43 STA $433B ;store in temporary secondary address location F27E 20 B0 DC JSR $DCB0 ;set all flags and look at command string F281 8E 7A 43 STX $437A ;store command number found F284 AE 00 43 LDX $4300 ;read first character from command string F287 AD 3B 43 LDA $433B ;is this a LOAD command ? F28A D0 29 BNE $F2B5 ;no, F28C E0 2A CPX #$2A ;LOAD last referenced program ? (*) F28E D0 25 BNE $F2B5 ;no, F290 A5 11 LDA $11 ;is there a track link for last program ? F292 F0 49 BEQ $F2DD ;no, F294 4A LSR F295 85 13 STA $13 ;store link in current track number location F297 A9 00 LDA #$00 F299 2A ROL F29A 85 12 STA $12 ;set drive number for last program accessed F29C 09 04 ORA #$04 ;calculate file type and add in drive number F29E 85 8B STA $8B ;store in file data table F2A0 20 2C DA JSR $DA2C ;turn on activity LED for specified drive F2A3 AD 74 43 LDA $4374 ;read sector link for last program accessed F2A6 85 14 STA $14 ;set as current sector number F2A8 20 47 F7 JSR $F747 ;open an internal read channel with 2 buffers F2AB A5 8B LDA $8B ;read file data F2AD A6 15 LDX $15 ;get file type F2AF 99 90 00 STA $0090,Y ;store in file type table F2B2 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* Test if LOAD directory command F2B5 E0 24 CPX #$24 ;LOAD directory track ? ($) F2B7 D0 1D BNE $F2D6 ;no, F2B9 AD 3B 43 LDA $433B ;is this a LOAD command ? F2BC D0 03 BNE $F2C1 ;no, F2BE 4C 09 F5 JMP $F509 ;LOAD directory from disk ******************************* Open directory as a SEQuential file F2C1 20 CC DB JSR $DBCC ;test syntax for command received F2C4 A9 12 LDA #$12 F2C6 85 13 STA $13 ;set track number to #$12 (decimal 18) F2C8 A9 00 LDA #$00 F2CA 85 14 STA $14 ;set sector number to #$00 F2CC 20 47 F7 JSR $F747 ;open internal read channel with 2 buffers F2CF A5 12 LDA $12 ;get current drive number F2D1 09 02 ORA #$02 ;calculate file type and add in drive number F2D3 4C AD F2 JMP $F2AD ;read directory track and send as file ******************************* Test if direct access command F2D6 E0 23 CPX #$23 ;is this a direct access request ? (#) F2D8 D0 12 BNE $F2EC ;no, F2DA 4C 30 E8 JMP $E830 ;open a direct access buffer ******************************* Initialize drive zero F2DD A9 04 LDA #$04 ;calculate file type (2 * PRG) F2DF 8D 9C 43 STA $439C ;set file type to PRG F2E2 A9 00 LDA #$00 F2E4 85 12 STA $12 ;set current drive number to #$00 F2E6 8D 94 43 STA $4394 ;set as last drive without error F2E9 20 FA EC JSR $ECFA ;read BAM from diskette in current drive ******************************* Parse command string F2EC 20 E0 DB JSR $DBE0 ;colon (:) found in parsed command string ? F2EF D0 04 BNE $F2F5 ;no, F2F1 A2 00 LDX #$00 ;start position of parameters equal to #$00 ? F2F3 F0 0C BEQ $F301 ;yes, F2F5 8A TXA ;parameters separated by a comma ? F2F6 F0 05 BEQ $F2FD ;yes, F2F8 A9 30 LDA #$30 ;set for "30 SYNTAX ERROR", general syntax F2FA 4C C3 DB JMP $DBC3 ;jump to process command error routine ******************************* Determine mode and file type for LOAD & SAVE F2FD 88 DEY ;colon (:) position #$00 ? F2FE F0 01 BEQ $F301 ;yes, F300 88 DEY ;move pointer to character before colon (:) F301 8C 80 43 STY $4380 ;store current pointer position in file table F304 A9 8D LDA #$8D ;set for SHIFTED CARRIAGE RETURN F306 20 63 DC JSR $DC63 ;look for character F309 E8 INX F30A 8E 7E 43 STX $437E ;store current file count value F30D 20 0A DD JSR $DD0A ;set 1st drive and table pointers F310 20 07 DE JSR $DE07 ;determine optimum search pattern F313 20 BF DE JSR $DEBF ;search directory for requested file entry F316 A2 00 LDX #$00 F318 8E 4B 43 STX $434B ;set record size to #$00 F31B 8E 9D 43 STX $439D ;set active file mode to #$00 (READ) F31E 86 C5 STX $C5 ;set active file type to #$00 (DEL) F320 E8 INX F321 EC 7D 43 CPX $437D ;more parameters ? F324 B0 10 BCS $F336 ;no, F326 20 BF F4 JSR $F4BF ;test for file type and mode F329 E8 INX F32A EC 7D 43 CPX $437D ;more than one parameter ? F32D B0 07 BCS $F336 ;no, F32F C0 04 CPY #$04 ;is this a REL file ? F331 F0 37 BEQ $F36A ;yes, F333 20 BF F4 JSR $F4BF ;set file type and mode F336 AE 3B 43 LDX $433B ;retrieve secondary address F339 86 16 STX $16 ;set as current secondary address F33B E0 02 CPX #$02 ;is command a LOAD or SAVE ? F33D B0 0B BCS $F34A ;no, F33F 8E 9D 43 STX $439D ;set mode from value in secondary address F342 A5 C5 LDA $C5 ;is active file type a DEL ? F344 D0 1A BNE $F360 ;no, F346 A9 02 LDA #$02 F348 85 C5 STA $C5 ;set active file type to PRG F34A A5 C5 LDA $C5 ;is active file type a DEL ? F34C D0 12 BNE $F360 ;no, F34E A5 8B LDA $8B ;get file type from table F350 29 0E AND #$0E ;calculate file type F352 4A LSR F353 85 C5 STA $C5 ;set as active file type F355 AD 86 43 LDA $4386 ;get first track link from file table F358 29 3F AND #$3F ;does file exist ? F35A D0 04 BNE $F360 ;yes, F35C A9 01 LDA #$01 F35E 85 C5 STA $C5 ;set active file type to #$01 (SEQ) F360 AD 9D 43 LDA $439D ;read active file mode F363 C9 01 CMP #$01 ;is it WRITE ? F365 F0 1A BEQ $F381 ;yes, F367 4C F9 F3 JMP $F3F9 ;perform LOAD operation ******************************* Handle relative file F36A BC 80 43 LDY $4380,X ;get pointer from file table F36D B9 00 43 LDA $4300,Y ;get REL file record size F370 8D 4B 43 STA $434B ;set as current record size F373 AD 86 43 LDA $4386 ;get track link for file F376 29 3F AND #$3F ;does file exist ? F378 D0 BC BNE $F336 ;yes, F37A A9 01 LDA #$01 F37C 8D 9D 43 STA $439D ;is active file mode #$01 (WRITE) F37F D0 B5 BNE $F336 ;yes, F381 AD 86 43 LDA $4386 ;get track link for file F384 29 80 AND #$80 ;calculate file type F386 AA TAX ;is this a DEL file ? F387 D0 16 BNE $F39F ;no, F389 A9 20 LDA #$20 ;set for OPEN WRITE F38B 24 8B BIT $8B ;does file pattern match for OPEN WRITE ? F38D F0 06 BEQ $F395 ;yes, F38F 20 3B E3 JSR $E33B ;delete directory entry and write new sector F392 4C 9B F4 JMP $F49B ;open a write file ******************************* Test if file exists. If not, open a write channel F395 AD 86 43 LDA $4386 ;get track link for file F398 29 3F AND #$3F ;does file exist ? F39A D0 03 BNE $F39F ;yes, F39C 4C 9B F4 JMP $F49B ;open a write file ******************************* Check if file replacement command F39F AD 00 43 LDA $4300 ;read first character from command buffer F3A2 C9 40 CMP #$40 ;is this a replace command ? (`) F3A4 F0 0D BEQ $F3B3 ;yes, F3A6 8A TXA ;does file exist already ? F3A7 D0 05 BNE $F3AE ;no, F3A9 A9 63 LDA #$63 ;set for "63 FILE EXISTS" error F3AB 4C C3 DB JMP $DBC3 ;jump to process command error routine ******************************* Indicate invalid filename structure F3AE A9 33 LDA #$33 ;set for "33 SYNTAX ERROR", invalid filename F3B0 4C C3 DB JMP $DBC3 ;jump to process command error routine ******************************* Command: REPLACE (overwrite file) F3B3 A5 8B LDA $8B ;read file information from directory entry F3B5 29 0E AND #$0E ;calculate file type F3B7 4A LSR F3B8 C5 C5 CMP $C5 ;do file types match ? F3BA D0 64 BNE $F420 ;no, F3BC C9 04 CMP #$04 ;is this a REL file ? F3BE F0 60 BEQ $F420 ;yes, F3C0 20 E6 F7 JSR $F7E6 ;open a write channel with 2 buffers F3C3 A5 15 LDA $15 ;get active buffer number F3C5 8D 75 43 STA $4375 ;set as write buffer number F3C8 A9 11 LDA #$11 ;set internal read channel F3CA 85 16 STA $16 ;set current secondary address to #$11 (decimal 17) F3CC 20 69 ED JSR $ED69 ;find internal read channel F3CF AD 9A 43 LDA $439A ;read pointer position into buffer F3D2 20 C1 F0 JSR $F0C1 ;set new pointer position F3D5 A0 00 LDY #$00 F3D7 B1 27 LDA ($27),Y ;get file type from directory buffer F3D9 09 20 ORA #$20 ;set file replacement flag F3DB 91 27 STA ($27),Y ;store new file type in directory buffer F3DD A0 1A LDY #$1A F3DF A5 13 LDA $13 ;read current file track link F3E1 91 27 STA ($27),Y ;set as replacement track link for current file F3E3 C8 INY F3E4 A5 14 LDA $14 ;read current file sector link F3E6 91 27 STA ($27),Y ;set as replacement sector link for current file F3E8 A5 86 LDA $86 ;read directory entry information F3EA AE 75 43 LDX $4375 ;get active write buffer number F3ED 9D 6B 43 STA $436B,X ;store information in file entry table F3F0 20 3E F9 JSR $F93E ;set track and sector values F3F3 20 5B F0 JSR $F05B ;write directory block to diskette F3F6 4C A7 F4 JMP $F4A7 ;overwrite old file with new data ******************************* Test if file exists in directory F3F9 AD 86 43 LDA $4386 ;get track link for file F3FC 29 3F AND #$3F ;does file exist ? F3FE D0 05 BNE $F405 ;yes, F400 A9 62 LDA #$62 ;set for "62 FILE NOT FOUND" error F402 4C C3 DB JMP $DBC3 ;jump to process command error routine ******************************* Test if MODIFY (#$03) mode requested F405 AD 9D 43 LDA $439D ;read active file mode F408 C9 03 CMP #$03 ;is this active mode MODIFY ? F40A F0 0B BEQ $F417 ;yes, F40C A9 20 LDA #$20 ;set for replacement file open flag F40E 24 8B BIT $8B ;is file already open ? F410 F0 05 BEQ $F417 ;yes, F412 A9 60 LDA #$60 ;set for "60 FILE NOT OPEN" error F414 4C C3 DB JMP $DBC3 ;jump to process command error routine ******************************* Verify the requested directory entry file type F417 A5 8B LDA $8B ;read file information from directory entry F419 4A LSR F41A 29 0F AND #$0F ;calculate file type F41C C5 C5 CMP $C5 ;do file types match ? F41E F0 05 BEQ $F425 ;yes, F420 A9 64 LDA #$64 ;set for "64 FILE TYPE MISMATCH" error F422 4C C3 DB JMP $DBC3 ;jump to process command error routine ******************************* Test if APPEND (#$02) mode requested F425 A0 00 LDY #$00 F427 8C 7F 43 STY $437F ;clear file stream 2 count F42A AE 9D 43 LDX $439D ;read active file mode F42D E0 02 CPX #$02 ;is this active mode APPEND ? F42F D0 1A BNE $F44B ;no, F431 C9 04 CMP #$04 ;is this a REL file ? F433 F0 EB BEQ $F420 ;yes, F435 B1 27 LDA ($27),Y ;read file type from directory entry F437 29 4F AND #$4F ;set APPEND flag F439 91 27 STA ($27),Y ;store file type back in directory F43B A5 16 LDA $16 ;read current secondary address F43D 48 PHA ;preserve it F43E A9 11 LDA #$11 ;set internal read channel F440 85 16 STA $16 ;set current secondary address to #$11 (decimal 17) F442 20 3E F9 JSR $F93E ;set track and sector values F445 20 5B F0 JSR $F05B ;write directory block to diskette F448 68 PLA ;retrieve original secondary address F449 85 16 STA $16 ;set as current secondary address F44B 20 5B F4 JSR $F45B ;open file for read F44E AD 9D 43 LDA $439D ;read active file mode F451 C9 02 CMP #$02 ;is this active mode APPEND ? F453 D0 52 BNE $F4A7 ;no, F455 20 DF F4 JSR $F4DF ;read until end of file and add in new data F458 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* Open a file for reading F45B A0 13 LDY #$13 F45D B1 27 LDA ($27),Y ;read track number of first side sector from directory F45F 8D 4C 43 STA $434C ;set as current side sector track number F462 C8 INY F463 B1 27 LDA ($27),Y ;read sector number of first side sector from directory F465 8D 4D 43 STA $434D ;set as current side sector number F468 C8 INY F469 B1 27 LDA ($27),Y ;read record length for file F46B AE 4B 43 LDX $434B ;read last record length F46E 8D 4B 43 STA $434B ;set new record length for file F471 8A TXA ;is record length #$00 ? F472 F0 0A BEQ $F47E ;yes, F474 CD 4B 43 CMP $434B ;does requested record exists ? F477 F0 05 BEQ $F47E ;yes, F479 A9 50 LDA #$50 ;set for "50 RECORD NOT PRESENT" error F47B 20 C3 DB JSR $DBC3 ;indicate error message F47E AE 7F 43 LDX $437F ;read filename pointer F481 BD 86 43 LDA $4386,X ;get track number for file entry F484 29 3F AND #$3F ;extract track number F486 85 13 STA $13 ;set as current track F488 BD 8B 43 LDA $438B,X ;get sector for file entry F48B 85 14 STA $14 ;set as sector number F48D 20 47 F7 JSR $F747 ;open internal read channel with 2 buffers F490 A4 15 LDY $15 ;get channel number F492 AE 7F 43 LDX $437F ;get filename pointer F495 B5 86 LDA $86,X ;get sector number for file F497 99 6B 43 STA $436B,Y ;set first block sector number for file F49A 60 RTS ******************************* Open a file for writing F49B A5 8B LDA $8B ;read file information from table F49D 29 01 AND #$01 ;calculate drive number F49F 85 12 STA $12 ;set as current drive number F4A1 20 E6 F7 JSR $F7E6 ;open a write channel with 2 buffers F4A4 20 A9 F1 JSR $F1A9 ;add file to directory F4A7 A5 16 LDA $16 ;read current secondary address F4A9 C9 02 CMP #$02 ;is this a PRG file type ? F4AB B0 0F BCS $F4BC ;no, F4AD 20 41 F9 JSR $F941 ;set track and sector values F4B0 A5 13 LDA $13 ;read current track number F4B2 0A ASL F4B3 05 12 ORA $12 ;add in drive number F4B5 85 11 STA $11 ;set new last program track accessed flag F4B7 A5 14 LDA $14 ;read current sector number F4B9 8D 74 43 STA $4374 ;set new last program sector accessed flag F4BC 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* Check mode and file type F4BF BC 80 43 LDY $4380,X ;get pointer into file command buffer F4C2 B9 00 43 LDA $4300,Y ;get mode or file type from command string F4C5 A0 04 LDY #$04 ;set for maximum number of modes: 0 = R (read) 1 = W (write) 2 = A (append) 3 = M (modify) F4C7 88 DEY ;all file mode possibilities tested ? F4C8 30 08 BMI $F4D2 ;yes, F4CA D9 CB D2 CMP $D2CB,Y ;is selected file mode valid ? F4CD D0 F8 BNE $F4C7 ;no, F4CF 8C 9D 43 STY $439D ;set as active file mode F4D2 A0 05 LDY #$05 ;set for maximum number of file types: 0 = D (deleted) 1 = S (sequential) 2 = P (program) 3 = U (user) 4 = R (relative) F4D4 88 DEY ;all file type possibilities tested ? F4D5 30 07 BMI $F4DE ;yes, F4D7 D9 CF D2 CMP $D2CF,Y ;is selected file type valid ? F4DA D0 F8 BNE $F4D4 ;no, F4DC 84 C5 STY $C5 ;set as active file type F4DE 60 RTS ******************************* Append information to end of specified file F4DF 20 5B E6 JSR $E65B ;read data byte F4E2 A9 80 LDA #$80 ;set for EOI marker F4E4 20 B1 F8 JSR $F8B1 ;all data bytes read ? F4E7 F0 F6 BEQ $F4DF ;yes, F4E9 20 9A F9 JSR $F99A ;set track and sector link from buffer F4EC A6 14 LDX $14 ;read current sector number F4EE E8 INX ;increment sector number F4EF 8A TXA ;still room for more bytes in this sector ? F4F0 D0 05 BNE $F4F7 ;yes, F4F2 20 1F EE JSR $EE1F ;write sector buffer to disk F4F5 A9 02 LDA #$02 F4F7 20 C1 F0 JSR $F0C1 ;set new pointer position F4FA A6 15 LDX $15 ;get active buffer number F4FC A9 01 LDA #$01 F4FE 95 98 STA $98,X ;set channel status bit 0 = 1 (channel is listener to IEEE) bit 3 = 0 (send EOI - talker only) bit 7 = 1 (channel is talker to IEEE) F500 A9 80 LDA #$80 ;set channel status to #$10 (write) F502 05 15 ORA $15 ;add in active buffer number F504 A6 16 LDX $16 ;get current secondary address F506 95 A2 STA $A2,X ;store file status in logical index table bit 7-6: 00 = read channel 10 = write channel 01 = read/write channel 11 = no channel F508 60 RTS ******************************* Transmit directory ($) to computer F509 A9 0B LDA #$0B ;set for LOAD command F50B 8D 7A 43 STA $437A ;set as current command number F50E AE 79 43 LDX $4379 ;get command length + 1 F511 CA DEX ;is there a command string ? F512 D0 17 BNE $F52B ;yes, F514 A9 2A LDA #$2A ;set for wildcard pattern (*) F516 8D 00 43 STA $4300 ;store in command string F519 A9 80 LDA #$80 ;set search both drives flag F51B 8D 86 43 STA $4386 ;set wildcard (*) flag during first block search F51E 0D 94 43 ORA $4394 ;add in drive number F521 85 8B STA $8B ;set type and wildcard (*) flag for first file F523 EE 7D 43 INC $437D ;increment file stream count 1 F526 EE 7E 43 INC $437E ;increment file stream count 2; reached #$00 F529 D0 41 BNE $F56C ;no, F52B CA DEX ;load by filenames ? F52C D0 26 BNE $F554 ;yes, F52E AD 01 43 LDA $4301 ;get drive number from command buffer F531 20 B5 DD JSR $DDB5 ;ASCII code representing drive 0 found ? F534 30 1E BMI $F554 ;yes, ******************************* Load directory from one drive F536 29 01 AND #$01 F538 85 8B STA $8B ;set marker to indicate that directory will be pulled from drive 1 F53A 85 12 STA $12 ;set current drive to #$01 F53C 20 FA EC JSR $ECFA ;read BAM from diskette in drive 1 F53F EE 7D 43 INC $437D ;increment file stream count 1 F542 EE 7E 43 INC $437E ;increment file stream count 2 F545 EE 80 43 INC $4380 ;move to next position in command string F548 A9 80 LDA #$80 F54A 8D 86 43 STA $4386 ;set file marker to indicate that file has been closed properly F54D A9 2A LDA #$2A ;set for wildcard pattern (*) F54F 8D 01 43 STA $4301 ;is second character position in command buffer set to (*) ? F552 D0 18 BNE $F56C ;yes, F554 20 E0 DB JSR $DBE0 ;has a colon (:) been found ? F557 D0 05 BNE $F55E ;no, F559 20 D9 DC JSR $DCD9 ;clear variables and necessary tables ******************************* Search by name on both drives F55C A0 03 LDY #$03 ;set pointer to first character in first directory entry of directory block F55E 88 DEY ;move to directory block sector link F55F 88 DEY ;move to directory block track link F560 8C 80 43 STY $4380 ;store current pointer position F563 20 FB DB JSR $DBFB ;set file image structure to search for in directory F566 20 8F DD JSR $DD8F ;set pointer to filename and check type F569 20 18 DD JSR $DD18 ;set drive number to pull directory from F56C 20 07 DE JSR $DE07 ;determine best directory search method F56F 20 AA E1 JSR $E1AA ;set up directory heading line F572 20 BF DE JSR $DEBF ;get filename search mask from table F575 20 4B DA JSR $DA4B ;load in directory block F578 20 B3 ED JSR $EDB3 ;read byte from directory buffer F57B A6 15 LDX $15 ;get active buffer number F57D 95 B5 STA $B5,X ;send byte to IEEE F57F A5 12 LDA $12 ;read current drive number F581 8D 94 43 STA $4394 ;set as last drive number without error F584 09 04 ORA #$04 ;set for SEQ file type F586 95 90 STA $90,X ;set channel send mode to SEQ F588 A9 00 LDA #$00 F58A 85 45 STA $45 ;set command buffer LO byte to #$00 F58C 60 RTS ******************************* Close file associated with secondary address F58D A5 16 LDA $16 ;directory load function needs to be closed ? F58F D0 0B BNE $F59C ;no, F591 A9 00 LDA #$00 F593 8D 46 43 STA $4346 ;clear directory listing flag F596 20 9F EE JSR $EE9F ;get channel used during directory load F599 4C D3 F0 JMP $F0D3 ;jump to free channel routine ******************************* Close channels associated with LOAD/SAVE F59C C9 0F CMP #$0F ;all channel need to be closed ? F59E F0 0C BEQ $F5AC ;yes, F5A0 20 BA F5 JSR $F5BA ;close specified channel F5A3 A5 16 LDA $16 ;read current secondary address F5A5 C9 02 CMP #$02 ;LOAD/SAVE channel needs to be closed ? F5A7 90 F0 BCC $F599 ;yes, F5A9 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* Close all files F5AC A9 0E LDA #$0E F5AE 85 16 STA $16 ;set current secondary address to #$0E (decimal 14) F5B0 20 BA F5 JSR $F5BA ;close specified channel F5B3 C6 16 DEC $16 ;all channels closed ? F5B5 10 F9 BPL $F5B0 ;no, F5B7 4C 99 DB JMP $DB99 ;jump to indicate command termination status ******************************* Close specified secondary address channel F5BA A6 16 LDX $16 ;get current secondary address F5BC B5 A2 LDA $A2,X ;read specified channel status F5BE C9 FF CMP #$FF ;is channel already closed ? F5C0 D0 01 BNE $F5C3 ;no, F5C2 60 RTS ******************************* Locate and close specific file type associated with secondary address F5C3 29 0F AND #$0F ;determine buffer number F5C5 85 15 STA $15 ;store buffer number F5C7 20 A1 ED JSR $EDA1 ;get current file type F5CA C9 07 CMP #$07 ;is it a direct access type ? F5CC F0 0F BEQ $F5DD ;yes, F5CE C9 04 CMP #$04 ;is it an REL type ? F5D0 F0 11 BEQ $F5E3 ;yes, F5D2 20 84 ED JSR $ED84 ;internal write channel found ? F5D5 B0 09 BCS $F5E0 ;no, F5D7 20 12 F6 JSR $F612 ;close SEQ write channel F5DA 20 A4 F6 JSR $F6A4 ;close directory channel F5DD 20 55 F6 JSR $F655 ;write BAM out to diskette F5E0 4C 9F EE JMP $EE9F ;clear internal write channel ******************************* Close a RELative file F5E3 20 F4 F8 JSR $F8F4 ;write out BAM if modified F5E6 20 D1 EB JSR $EBD1 ;toggle current active and inactive buffers F5E9 20 B1 FC JSR $FCB1 ;position side sector and buffer table pointer to the end of the last record F5EC A6 83 LDX $83 ;get current side sector number F5EE 86 08 STX $08 ;store in TEMP4 location F5F0 E6 08 INC $08 ;increment current side sector number by one F5F2 A9 00 LDA #$00 F5F4 85 05 STA $05 ;clear TEMP1 location F5F6 85 06 STA $06 ;clear TEMP2 location F5F8 A5 84 LDA $84 ;read pointer value into side sector F5FA 38 SEC F5FB E9 0E SBC #$0E ;substract side sector offset F5FD 85 07 STA $07 ;store result in TEMP3 location F5FF 20 56 FA JSR $FA56 ;calculate number of side sector blocks needed F602 A6 15 LDX $15 ;get active buffer number F604 A5 05 LDA $05 ;read LO byte of side sector block count F606 95 59 STA $59,X ;store in record table as LO pointer value F608 A5 06 LDA $06 ;read HI byte of side sector block count F60A 95 61 STA $61,X ;store in record table as HI pointer value F60C 20 A4 F6 JSR $F6A4 ;close open write file in directory F60F 4C 9F EE JMP $EE9F ;clear internal write channel ******************************* Close a write channel F612 A6 15 LDX $15 ;get active buffer number F614 B5 59 LDA $59,X ;read number of bytes written in current sector F616 15 61 ORA $61,X ;has more than one data block been written ? F618 D0 0C BNE $F626 ;yes, F61A 20 E1 F0 JSR $F0E1 ;get current buffer pointer position F61D C9 02 CMP #$02 ;has more than one byte been written in current data block ? F61F D0 05 BNE $F626 ;yes, F621 A9 0D LDA #$0D ;set for #$0D (decimal 13), carriage return F623 20 B1 EC JSR $ECB1 ;write byte to assigned buffer F626 20 E1 F0 JSR $F0E1 ;get current buffer pointer position F629 C9 02 CMP #$02 ;has more than one byte been written in current data block ? F62B D0 0F BNE $F63C ;yes, F62D 20 D1 EB JSR $EBD1 ;toggle active and inactive buffers F630 A6 15 LDX $15 ;get active buffer number F632 B5 59 LDA $59,X ;any bytes written to buffer ? F634 D0 02 BNE $F638 ;yes, F636 D6 61 DEC $61,X ;decrement number of data blocks written by one F638 D6 59 DEC $59,X ;decrement number of bytes written by one F63A A9 00 LDA #$00 F63C 38 SEC F63D E9 01 SBC #$01 ;calculate number of bytes written in current sector F63F 48 PHA ;preserve result F640 A9 00 LDA #$00 F642 20 C1 F0 JSR $F0C1 ;set new pointer position F645 20 B1 EC JSR $ECB1 ;write #$00 as track link in current sector F648 68 PLA ;retrieve result from bytes written calculation F649 20 B1 EC JSR $ECB1 ;write last data byte position in current sector F64C 20 45 ED JSR $ED45 ;write sector out to diskette F64F 20 82 EC JSR $EC82 ;wait until write job completed F652 4C D1 EB JMP $EBD1 ;toggle active and inactive buffer ******************************* Write out the BAM to the last active drive F655 20 98 FA JSR $FA98 ;find active buffer number F658 AA TAX F659 BD 4E 43 LDA $434E,X ;get last job performed F65C 29 01 AND #$01 ;remove drive number F65E 48 PHA ;preserve new BAM flag F65F AA TAX F660 A9 00 LDA #$00 F662 85 14 STA $14 ;set current sector number to #$00 F664 BD E8 D2 LDA $D2E8,X ;get HI byte pointer for BAM corresponding to current drive F667 85 09 STA $09 ;store TEMP location F669 A9 00 LDA #$00 F66B 85 08 STA $08 ;clear TEMP4 location F66D A9 01 LDA #$01 F66F 85 13 STA $13 ;set current track number to #$01 ******************************* Verify that the BAM block count matches the bits F671 A5 13 LDA $13 ;read current track number F673 0A ASL ;move into track bytes reserved for track F674 0A ASL ;set for beginning of next track BAM bits test F675 A8 TAY F676 B1 08 LDA ($08),Y ;read sector count total for current track F678 85 07 STA $07 ;store in TEMP4 location F67A C8 INY F67B B1 08 LDA ($08),Y ;read first part of sector count for track F67D 85 04 STA $04 ;store in TEMP0 location F67F C8 INY F680 B1 08 LDA ($08),Y ;read second part of sector count for track F682 85 05 STA $05 ;store in TEMP1 location F684 C8 INY F685 B1 08 LDA ($08),Y ;read third part of sector count for track F687 85 06 STA $06 ;store in TEMP2 location F689 20 B4 D7 JSR $D7B4 ;verify track bits with new BAM image for track F68C E6 13 INC $13 ;do next track F68E A5 13 LDA $13 ;get current track number F690 C9 24 CMP #$24 ;all tracks in BAM tested ? F692 D0 DD BNE $F671 ;no, ******************************* Write new BAM to diskette F694 A9 12 LDA #$12 F696 85 13 STA $13 ;set current track number to #$12 (decimal 18) F698 68 PLA ;retrieve new BAM flag marker F699 A8 TAY F69A 18 CLC F69B 69 0C ADC #$0C ;add in BAM write job F69D AA TAX F69E 98 TYA F69F 09 90 ORA #$90 ;set job code to: WRITE F6A1 4C 9D F1 JMP $F19D ;perform job ******************************* Directory close on open write file F6A4 A6 15 LDX $15 ;get active buffer number F6A6 8E 75 43 STX $4375 ;set as write index flag F6A9 A5 16 LDA $16 ;get current secondary address F6AB 48 PHA ;preserve it F6AC BD 6B 43 LDA $436B,X ;get directory sector number for current file F6AF 48 PHA ;preserve it F6B0 29 1F AND #$1F ;determine sector number F6B2 85 14 STA $14 ;set as current sector number F6B4 68 PLA ;retrieve current secondary address F6B5 29 E0 AND #$E0 ;calculate sector offset F6B7 09 02 ORA #$02 ;extract current index into active buffer F6B9 8D 9A 43 STA $439A ;set as current index into active buffer F6BC B5 90 LDA $90,X ;read file type for current file F6BE 29 01 AND #$01 ;determine which drive to use F6C0 85 12 STA $12 ;set as current drive number F6C2 A9 12 LDA #$12 F6C4 85 13 STA $13 ;set current track number to #$12 (decimal 18) F6C6 20 98 FA JSR $FA98 ;get active buffer number F6C9 48 PHA ;preserve it F6CA 85 A1 STA $A1 ;set as current job number F6CC 20 57 F0 JSR $F057 ;read directory sector F6CF A0 00 LDY #$00 F6D1 BD FF F0 LDA $F0FF,X ;read byte from allocated buffer F6D4 85 1A STA $1A ;store in TEMPR1 location F6D6 AD 9A 43 LDA $439A ;get index position into current active buffer F6D9 85 19 STA $19 ;store value in TEMPR0 location F6DB B1 19 LDA ($19),Y ;read file type from directory entry F6DD 29 20 AND #$20 ;is current file open ? F6DF F0 41 BEQ $F722 ;yes, ******************************* REPLACE current file data with new file data F6E1 20 A1 ED JSR $EDA1 ;is this a RELative file entry ? F6E4 F0 44 BEQ $F72A ;yes, F6E6 B1 19 LDA ($19),Y ;get file type for current file F6E8 29 8F AND #$8F ;set file replacement flag F6EA 91 19 STA ($19),Y ;set as new file type for current file F6EC C8 INY F6ED B1 19 LDA ($19),Y ;get track link of first block for file F6EF 85 13 STA $13 ;set as current track number F6F1 84 06 STY $06 ;store pointer to beginning of directory entry in TEMP2 location F6F3 A0 1B LDY #$1B ;set new pointer position to #$1B (decimal 27) F6F5 B1 19 LDA ($19),Y ;extract replacement link to last sector F6F7 48 PHA ;preserve it F6F8 88 DEY F6F9 B1 19 LDA ($19),Y ;is replacement track link #$00 ? F6FB D0 0A BNE $F707 ;no, F6FD 85 13 STA $13 ;set as current track number F6FF 68 PLA ;retrieve last sector link F700 85 14 STA $14 ;set as current sector number F702 A9 67 LDA #$67 ;set for "67 ILLEGAL SYSTEM T or S", invalid track number F704 20 53 D9 JSR $D953 ;generate error message F707 48 PHA ;preserve track link F708 A9 00 LDA #$00 F70A 91 19 STA ($19),Y ;clear replacement track link location F70C C8 INY F70D 91 19 STA ($19),Y ;clear replacement sector link location F70F 68 PLA ;retrieve replacement track link value F710 A4 06 LDY $06 ;read original directory entry pointer value F712 91 19 STA ($19),Y ;set new track link number F714 C8 INY F715 B1 19 LDA ($19),Y ;read current sector link number F717 85 14 STA $14 ;set as current sector number F719 68 PLA ;retrieve replacement sector link value F71A 91 19 STA ($19),Y ;set new sector link value F71C 20 13 E3 JSR $E313 ;delete old file F71F 4C 2A F7 JMP $F72A ;write new block size for replaced file ******************************* Set "file closed" flag, and write new block count for replaced file. Write new sector F722 B1 19 LDA ($19),Y ;get file type for current file F724 29 0F AND #$0F ;mask off HI order bits F726 09 80 ORA #$80 ;set FILE CLOSED flag F728 91 19 STA ($19),Y ;set as new file type for current file F72A AE 75 43 LDX $4375 ;get active write buffer index F72D A0 1C LDY #$1C F72F B5 59 LDA $59,X ;get LO block count for current file F731 91 19 STA ($19),Y ;set as new LO block count for replaced file F733 C8 INY F734 B5 61 LDA $61,X ;get HI block count for current file F736 91 19 STA ($19),Y ;set as new HI block count for replaced file F738 68 PLA ;retrieve original buffer number F739 AA TAX F73A A9 90 LDA #$90 ;set job code to: WRITE F73C 05 12 ORA $12 ;add in drive number F73E 20 9D F1 JSR $F19D ;perform job F741 68 PLA ;retrieve original secondary address F742 85 16 STA $16 ;set as current secondary address F744 4C 84 ED JMP $ED84 ;find internal write channel ******************************* Open internal read channel with 2 buffers. Inserts secondary address in logical index table. Initializes all pointers, including RELative file pointers. F747 A9 02 LDA #$02 ;set for opening of two buffers F749 20 5E EE JSR $EE5E ;allocate two data buffers F74C 20 B4 F7 JSR $F7B4 ;clear pointers F74F A5 C5 LDA $C5 ;get active file type F751 48 PHA ;preserve it F752 0A ASL ;double file type F753 05 12 ORA $12 ;add in drive number F755 95 90 STA $90,X ;store file information in file table F757 20 1D ED JSR $ED1D ;read first one or two data block of file F75A A6 15 LDX $15 ;get active buffer number F75C A5 13 LDA $13 ;another sector in file available for read ? F75E D0 04 BNE $F764 ;yes, F760 A5 14 LDA $14 ;get pointer to last character position in this sector F762 95 BD STA $BD,X ;store as pointer into current active buffer F764 68 PLA ;retrieve file type F765 C9 04 CMP #$04 ;is this a REL file ? F767 D0 3F BNE $F7A8 ;no, F769 A4 16 LDY $16 ;read current secondary address F76B B9 A2 00 LDA $00A2,Y ;read channel status bit 7 & 6: 00 = read channel 10 = write channel 01 = read/write channel 11 = no channel F76E 09 40 ORA #$40 ;set channel status to: 01 (read/write) F770 99 A2 00 STA $00A2,Y ;set new channel status bit 7 & 6: 00 = read channel 10 = write channel 01 = read/write channel 11 = no channel F773 AD 4B 43 LDA $434B ;get record size value F776 95 71 STA $71,X ;store in RELative record size table F778 20 FE EE JSR $EEFE ;buffer available for use with side sectors ? F77B 10 03 BPL $F780 ;yes, F77D 4C 87 EE JMP $EE87 ;indicate no buffer available for side sectors ******************************* Initialize all pointers including REL file pointers F780 A6 15 LDX $15 ;get active side sector buffer F782 95 79 STA $79,X ;store in side sector table F784 AC 4C 43 LDY $434C ;read track number for side sector F787 84 13 STY $13 ;set as current track number F789 AC 4D 43 LDY $434D ;read sector number for side sector F78C 84 14 STY $14 ;set as current track number F78E 20 92 EC JSR $EC92 ;set track, sector, ID for current buffer F791 20 78 F9 JSR $F978 ;read side sector block F794 20 82 EC JSR $EC82 ;wait until job completed F797 A6 15 LDX $15 ;get active side sector buffer F799 A9 02 LDA #$02 F79B 95 69 STA $69,X ;set next record pointer to #$02 F79D A9 00 LDA #$00 F79F 20 C1 F0 JSR $F0C1 ;set new pointer position F7A2 20 3C FC JSR $FC3C ;set up first record F7A5 4C 41 F9 JMP $F941 ;restore track and sector ******************************* Set up SEQuential file F7A8 20 D2 ED JSR $EDD2 ;read a byte from active buffer F7AB A6 15 LDX $15 ;get current active buffer number F7AD 95 B5 STA $B5,X ;send byte out through IEEE F7AF A9 88 LDA #$88 ;set for "ready to talk" status F7B1 95 98 STA $98,X ;set channel status bit 7 = channel is talker (set to 1) 3 = channel is send EOI (talker only) 0 = channel is listener (set to 1) F7B3 60 RTS ******************************* Initialize variables for open channel. Sets active buffer number. Buffer pointer = 2 F7B4 A6 15 LDX $15 ;get active buffer number F7B6 A5 12 LDA $12 ;read current drive number F7B8 B4 49 LDY $49,X ;get main buffer number F7BA 99 4E 43 STA $434E,Y ;set as last job performed F7BD B4 51 LDY $51,X ;read alternate buffer number F7BF 99 4E 43 STA $434E,Y ;set as last job performed F7C2 99 03 10 STA $1003,Y ;set as current job F7C5 B5 49 LDA $49,X ;get main buffer number F7C7 0A ASL ;double it F7C8 A8 TAY F7C9 A9 02 LDA #$02 F7CB 99 29 00 STA $0029,Y ;set pointer to first data byte in buffer F7CE B5 51 LDA $51,X ;get alternate buffer number F7D0 09 80 ORA #$80 ;set buffer inactive flag F7D2 95 51 STA $51,X ;store new buffer status F7D4 0A ASL ;double it F7D5 A8 TAY F7D6 A9 02 LDA #$02 F7D8 99 29 00 STA $0029,Y ;set pointer to first data byte in buffer F7DB A9 00 LDA #$00 F7DD 95 59 STA $59,X ;clear LO block count F7DF 95 61 STA $61,X ;clear HI block count F7E1 A9 00 LDA #$00 F7E3 95 BD STA $BD,X ;set flag to scan next SEQ data block F7E5 60 RTS ******************************* Open internal write channel with 2 buffers F7E6 20 3E D7 JSR $D73E ;get first track and sector F7E9 A9 02 LDA #$02 F7EB 20 5B EE JSR $EE5B ;set for opening of two new write channels F7EE 20 8F EC JSR $EC8F ;set track, sector, ID for current buffer F7F1 20 B4 F7 JSR $F7B4 ;initialize pointers F7F4 A6 15 LDX $15 ;get current active buffer F7F6 A5 C5 LDA $C5 ;get current active file type F7F8 48 PHA ;preserve it F7F9 0A ASL ;double it F7FA 05 12 ORA $12 ;add in drive number F7FC 95 90 STA $90,X ;store file information in file type table SEQ = type 1 PRG = type 2 USR = type 3 REL = type 4 direct = type 7 F7FE 68 PLA ;retrieve active file type F7FF C9 04 CMP #$04 ;is this a REL file ? F801 F0 05 BEQ $F808 ;yes, F803 A9 01 LDA #$01 ;set for "active listener" status F805 95 98 STA $98,X ;set channel status bit 7 = channel is talker (set to 1) 3 = channel is send EOI (talker only) 0 = channel is listener (set to 1) F807 60 RTS ******************************* Test for available side sector buffer F808 A4 16 LDY $16 ;get current secondary address F80A B9 A2 00 LDA $00A2,Y ;read channel status bit 7 & 6: 00 = read channel 10 = write channel 01 = read/write channel 11 = no channel F80D 29 3F AND #$3F ;preserve channel status bits only F80F 09 40 ORA #$40 ;set channel status to: 01 (read/write) F811 99 A2 00 STA $00A2,Y ;set new channel status bit 7 & 6: 00 = read channel 10 = write channel 01 = read/write channel 11 = no channel F814 AD 4B 43 LDA $434B ;get record size value F817 95 71 STA $71,X ;store in RELative record size table F819 20 FE EE JSR $EEFE ;buffer available for use with side sector ? F81C 10 03 BPL $F821 ;yes, F81E 4C 87 EE JMP $EE87 ;indicate no buffer available for side sector ******************************* Set up and write out side sector and data block F821 A6 15 LDX $15 ;get active buffer number F823 95 79 STA $79,X ;store as new side sector buffer number F825 20 C6 F9 JSR $F9C6 ;clear the side sector buffer F828 20 AF D6 JSR $D6AF ;find next available track and sector F82B A5 13 LDA $13 ;read current track number F82D 8D 4C 43 STA $434C ;set as current side sector track number F830 A5 14 LDA $14 ;read current sector number F832 8D 4D 43 STA $434D ;set as current side sector number F835 A6 15 LDX $15 ;get active buffer number F837 B5 79 LDA $79,X ;get side sector buffer number F839 20 92 EC JSR $EC92 ;set track, sector, ID for current buffer F83C A9 00 LDA #$00 F83E 20 EE F9 JSR $F9EE ;set buffer pointer by use of current side sector pointer F841 A9 00 LDA #$00 F843 20 98 F8 JSR $F898 ;store null link F846 A9 11 LDA #$11 ;set side sector offset to: offset + 1 F848 20 98 F8 JSR $F898 ;store side sector offset F84B A9 00 LDA #$00 ;set side sector number F84D 20 98 F8 JSR $F898 ;store side sector number F850 AD 4B 43 LDA $434B ;read current record size F853 20 98 F8 JSR $F898 ;store record size F856 A5 13 LDA $13 ;read current side sector track number F858 20 98 F8 JSR $F898 ;store track number F85B A5 14 LDA $14 ;read current side sector number F85D 20 98 F8 JSR $F898 ;store sector number F860 A9 10 LDA #$10 ;set side sector offset F862 20 EE F9 JSR $F9EE ;set buffer pointer by use of current side sector pointer F865 20 41 F9 JSR $F941 ;get track and sector for side sector F868 A5 13 LDA $13 ;read current track number F86A 20 98 F8 JSR $F898 ;store track number F86D A5 14 LDA $14 ;read current sector number F86F 20 98 F8 JSR $F898 ;store sector number F872 20 71 F9 JSR $F971 ;write out side sector block to diskette F875 20 82 EC JSR $EC82 ;wait until job completed F878 A9 02 LDA #$02 F87A 20 C1 F0 JSR $F0C1 ;set new pointer position for data block F87D A6 15 LDX $15 ;get active buffer number F87F 38 SEC F880 A9 00 LDA #$00 F882 F5 71 SBC $71,X ;calculate last record position F884 95 69 STA $69,X ;store result in next record table F886 20 CF FD JSR $FDCF ;null records in active data buffer F889 20 1C F9 JSR $F91C ;set track link to #$00 and sector link to last character position in buffer F88C 20 63 F9 JSR $F963 ;write out nulled record block F88F 20 82 EC JSR $EC82 ;wait until job completed F892 20 55 F6 JSR $F655 ;write out BAM to diskette under use F895 4C 97 F7 JMP $F797 ;finish opening channel ******************************* Put byte into side sector F898 48 PHA ;preserve byte to send F899 A6 15 LDX $15 ;get current active buffer number F89B B5 79 LDA $79,X ;get current side sector number F89D 4C BD EC JMP $ECBD ;store byte in assigned buffer position ******************************* Set/Clear file type flag F8A0 90 06 BCC $F8A8 ;clear flag request ? yes, F8A2 A6 15 LDX $15 ;get current active buffer number F8A4 15 90 ORA $90,X ;flag set ? F8A6 D0 06 BNE $F8AE ;yes, F8A8 A6 15 LDX $15 ;get current active buffer number F8AA 49 FF EOR #$FF ;invert bits F8AC 35 90 AND $90,X ;clear flag F8AE 95 90 STA $90,X ;store new flag status F8B0 60 RTS ******************************* Test file type flag status F8B1 A6 15 LDX $15 ;get current active buffer number F8B3 35 90 AND $90,X ;determine flag status F8B5 60 RTS ******************************* Test if write job F8B6 20 98 FA JSR $FA98 ;get active buffer number F8B9 AA TAX F8BA BD 4E 43 LDA $434E,X ;read last job entered in que status F8BD 29 F0 AND #$F0 ;determine job command code number F8BF C9 90 CMP #$90 ;was it a WRITE job ? (.Z = 1) F8C1 60 RTS ******************************* Test for active files Not active (.C = 1) .X = 18 Active (.C = 0) .X = entry found .Y = channel status F8C2 A2 00 LDX #$00 ;set secondary address to #$00 F8C4 86 06 STX $06 ;store in TEMP2 location F8C6 B5 A2 LDA $A2,X ;get buffer corresponding to secondary address F8C8 C9 FF CMP #$FF ;is it active ? F8CA D0 08 BNE $F8D4 ;yes, F8CC A6 06 LDX $06 ;read secondary address count F8CE E8 INX ;do next secondary address channel F8CF E0 10 CPX #$10 ;all secondary address channel tested ? F8D1 90 F1 BCC $F8C4 ;no, F8D3 60 RTS ******************************* Test if directory entry matches secondary address entry F8D4 86 06 STX $06 ;save secondary address value F8D6 29 3F AND #$3F ;determine channel type F8D8 A8 TAY F8D9 B9 90 00 LDA $0090,Y ;get file information from table F8DC 29 01 AND #$01 ;extract drive number F8DE 85 05 STA $05 ;store in TEMP1 location F8E0 AE 45 43 LDX $4345 ;get directory entry flag F8E3 B5 8B LDA $8B,X ;read file information for secondary address F8E5 29 01 AND #$01 ;extract drive number F8E7 C5 05 CMP $05 ;same drive number ? F8E9 D0 E1 BNE $F8CC ;no, F8EB B9 6B 43 LDA $436B,Y ;get directory entry information F8EE D5 86 CMP $86,X ;file information matches secondary address information ? F8F0 D0 DA BNE $F8CC ;no, F8F2 18 CLC F8F3 60 RTS ******************************* Write out buffer if no longer current F8F4 20 A3 FA JSR $FAA3 ;should buffer be re-written to disk ? F8F7 50 06 BVC $F8FF ;no, F8F9 20 63 F9 JSR $F963 ;write buffer out to disk F8FC 20 82 EC JSR $EC82 ;wait until job completed F8FF 60 RTS ******************************* Put track and sector into buffer F900 20 2E F9 JSR $F92E ;set up current buffer pointers F903 A5 13 LDA $13 ;read current track number F905 91 27 STA ($27),Y ;store in directory buffer F907 C8 INY F908 A5 14 LDA $14 ;read current sector number F90A 91 27 STA ($27),Y ;store in directory buffer F90C 4C EE FB JMP $FBEE ;set flag to indicate that buffer needs to be written out to diskette ******************************* Get track and sector from buffer F90F 20 2E F9 JSR $F92E ;set up current buffer pointers F912 B1 27 LDA ($27),Y ;read track value from directory buffer F914 85 13 STA $13 ;set as current track number F916 C8 INY F917 B1 27 LDA ($27),Y ;read sector value from directory buffer F919 85 14 STA $14 ;set as current sector number F91B 60 RTS ******************************* Set track link to #$00 and sector link to point to last character in current buffer F91C 20 2E F9 JSR $F92E ;set up current buffer pointers F91F A9 00 LDA #$00 F921 91 27 STA ($27),Y ;set track link to #$00 F923 C8 INY F924 A6 15 LDX $15 ;get active buffer number F926 B5 69 LDA $69,X ;read pointer position into current buffer F928 AA TAX F929 CA DEX ;decrement pointer by one F92A 8A TXA F92B 91 27 STA ($27),Y ;set sector link to mark last character in buffer F92D 60 RTS ******************************* Set up pointer to active buffer F92E 20 98 FA JSR $FA98 ;get active buffer number F931 0A ASL F932 AA TAX F933 B5 2A LDA $2A,X ;read HI byte of buffer pointer F935 85 28 STA $28 ;set as HI byte for directory buffer F937 A9 00 LDA #$00 ;set LO byte of buffer pointer to #$00 F939 85 27 STA $27 ;set as LO byte for directory buffer F93B A0 00 LDY #$00 F93D 60 RTS ******************************* Read track and sector values from HEADER F93E 20 69 ED JSR $ED69 ;find internal read channel F941 20 98 FA JSR $FA98 ;get active buffer number F944 85 A1 STA $A1 ;set as current job number F946 0A ASL ;multiply buffer number by two F947 0A ASL ;multiply new result by two F948 0A ASL ;multiply new result by two F949 A8 TAY ;set HEADER buffer corresponding with current buffer F94A B9 23 10 LDA $1023,Y ;read track value from JOB HEADER table for current buffer F94D 85 13 STA $13 ;set as current track number F94F B9 24 10 LDA $1024,Y ;read sector value from JOB HEADER table for current buffer F952 85 14 STA $14 ;set as current sector number F954 60 RTS ******************************* Job que: WRITE a buffer F955 A9 90 LDA #$90 ;set job: WRITE F957 8D 3C 43 STA $433C ;is this a WRITE job ? F95A D0 28 BNE $F984 ;yes, ******************************* Job que: READ a buffer F95C A9 80 LDA #$80 ;set job: READ F95E 8D 3C 43 STA $433C ;is this a READ job ? F961 D0 21 BNE $F984 ;yes, ******************************* Job que: WRITE F963 A9 90 LDA #$90 ;set job: WRITE F965 8D 3C 43 STA $433C ;is this a WRITE job ? F968 D0 26 BNE $F990 ;yes, ******************************* Job que: READ F96A A9 80 LDA #$80 ;set job: READ F96C 8D 3C 43 STA $433C ;is this a READ job ? F96F D0 1F BNE $F990 ;yes, ******************************* Job que: WRITE side sector F971 A9 90 LDA #$90 ;set job: WRITE F973 8D 3C 43 STA $433C ;is this a WRITE job ? F976 D0 02 BNE $F97A ;yes, ******************************* Job que: READ side sector F978 A9 80 LDA #$80 ;set job: READ F97A 8D 3C 43 STA $433C ;set for READ job F97D A6 15 LDX $15 ;get active buffer number F97F B5 79 LDA $79,X ;get side sector buffer number F981 AA TAX ;is buffer used ? F982 10 13 BPL $F997 ;yes, F984 20 8F EC JSR $EC8F ;set track, sector, ID for current buffer F987 20 98 FA JSR $FA98 ;get active buffer number F98A AA TAX F98B A5 12 LDA $12 ;read current drive number F98D 9D 4E 43 STA $434E,X ;assign drive number to buffer F990 20 F9 FB JSR $FBF9 ;clear "write out buffer" flag F993 20 98 FA JSR $FA98 ;get active buffer number F996 AA TAX F997 4C 0E F1 JMP $F10E ;set drive number and job command ******************************* Set track and sector from link in buffer F99A A9 00 LDA #$00 F99C 20 C1 F0 JSR $F0C1 ;set new pointer position F99F 20 B3 ED JSR $EDB3 ;read track link byte from active buffer F9A2 85 13 STA $13 ;set as current track number F9A4 20 B3 ED JSR $EDB3 ;read sector link byte from active buffer F9A7 85 14 STA $14 ;set as current sector number F9A9 60 RTS ******************************* Transfer bytes from one buffer to other .Y = source buffer number .X = destination buffer number .ACC = number of bytes F9AA 48 PHA ;preserve number of bytes to move counter F9AB A9 00 LDA #$00 F9AD 85 04 STA $04 ;clear TEMP0 location F9AF 85 06 STA $06 ;clear TEMP2 location F9B1 B9 FF F0 LDA $F0FF,Y ;get source buffer HI byte address F9B4 85 05 STA $05 ;set source buffer number F9B6 BD FF F0 LDA $F0FF,X ;get destination buffer HI byte address F9B9 85 07 STA $07 ;set destination buffer number F9BB 68 PLA ;retrieve bytes to move counter F9BC A8 TAY F9BD 88 DEY ;decrement byte counter F9BE B1 04 LDA ($04),Y ;read byte from source buffer F9C0 91 06 STA ($06),Y ;store in destination buffer F9C2 88 DEY ;all bytes transferred ? F9C3 10 F9 BPL $F9BE ;no, F9C5 60 RTS ******************************* Clear requested buffer .ACC = buffer number F9C6 A8 TAY F9C7 B9 FF F0 LDA $F0FF,Y ;get buffer HI byte address F9CA 85 05 STA $05 ;set buffer number F9CC A9 00 LDA #$00 F9CE 85 04 STA $04 ;set buffer LO byte address F9D0 A8 TAY F9D1 91 04 STA ($04),Y ;null current position in buffer F9D3 C8 INY ;all bytes in buffer nulled ? F9D4 D0 FB BNE $F9D1 ;no, F9D6 60 RTS ******************************* Set side sector pointer F9D7 A9 00 LDA #$00 F9D9 20 E1 F9 JSR $F9E1 ;set buffer pointer for current buffer F9DC A0 02 LDY #$02 F9DE B1 27 LDA ($27),Y ;read side sector pointer from directory buffer F9E0 60 RTS ******************************* Use side sector pointer to set directory buffer pointer F9E1 85 27 STA $27 ;set LO byte address of directory buffer F9E3 A6 15 LDX $15 ;get active buffer number F9E5 B5 79 LDA $79,X ;get side sector buffer number F9E7 AA TAX F9E8 BD FF F0 LDA $F0FF,X ;read HI byte address for current buffer F9EB 85 28 STA $28 ;set as HI byte address of directory buffer F9ED 60 RTS ******************************* Set directory buffer & buffer table with current side sector pointer F9EE 48 PHA ;preserve LO byte address F9EF 20 E1 F9 JSR $F9E1 ;set directory buffer pointer F9F2 48 PHA ;preserve HI byte address F9F3 8A TXA F9F4 0A ASL ;multiply side sector buffer number by two F9F5 AA TAX F9F6 68 PLA ;retrieve HI byte address F9F7 95 2A STA $2A,X ;set current buffer HI byte address F9F9 68 PLA ;retrieve LO byte address F9FA 95 29 STA $29,X ;set current buffer LO byte address F9FC 60 RTS ******************************* Test if side sector and index are within the allowed range .V = 0 (within range) = 1 (out of range) F9FD 20 6B FA JSR $FA6B ;is side sector number and index within range ? FA00 30 0E BMI $FA10 ;no, FA02 50 13 BVC $FA17 ;yes, FA04 A6 15 LDX $15 ;get active buffer number FA06 B5 79 LDA $79,X ;get side sector buffer number FA08 20 20 FA JSR $FA20 ;read in side sector FA0B 20 6B FA JSR $FA6B ;is side sector number and index within range ? FA0E 10 07 BPL $FA17 ;yes, FA10 20 B1 FC JSR $FCB1 ;set side sector and buffer table to end of last record FA13 2C E5 D2 BIT $D2E5 ;set flags to indicate side sector and index are out of range FA16 60 RTS ******************************* Position directory buffer and buffer table FA17 A5 84 LDA $84 ;read side sector pointer FA19 20 EE F9 JSR $F9EE ;set directory buffer and buffer table FA1C 2C E4 D2 BIT $D2E4 ;set flags to indicate side sector and index are within range FA1F 60 RTS ******************************* Indirect block read .ACC = current buffer number FA20 85 A1 STA $A1 ;store buffer number as current job FA22 A9 80 LDA #$80 ;is this a READ job ? FA24 D0 04 BNE $FA2A ;yes, ******************************* Indirect block write .ACC = current buffer number FA26 85 A1 STA $A1 ;store buffer number as current job FA28 A9 90 LDA #$90 ;set for WRITE job ******************************* Perform block read/write .X = active buffer number .ACC = current buffer number FA2A 48 PHA ;preserve job code FA2B B5 90 LDA $90,X ;get filetype for channel FA2D 29 01 AND #$01 ;extract drive number FA2F 85 12 STA $12 ;set as current drive number FA31 68 PLA ;retrieve job code FA32 05 12 ORA $12 ;add in drive number FA34 8D 3C 43 STA $433C ;store job code in temporary job location FA37 B1 27 LDA ($27),Y ;get track number from directory buffer FA39 85 13 STA $13 ;set as current track number FA3B C8 INY FA3C B1 27 LDA ($27),Y ;get sector number from directory buffer FA3E 85 14 STA $14 ;set as current sector number FA40 A5 A1 LDA $A1 ;get buffer number FA42 20 92 EC JSR $EC92 ;set track, sector, ID for current buffer FA45 A6 A1 LDX $A1 ;get buffer number FA47 4C A0 F1 JMP $F1A0 ;perform request job command ******************************* Get side sector pointers FA4A A6 15 LDX $15 ;get active buffer number FA4C B5 79 LDA $79,X ;get side sector buffer number FA4E 4C E4 F0 JMP $F0E4 ;set new directory buffer pointers ******************************* Calculate side sectors FA51 A9 78 LDA #$78 ;set number of side sector pointers in a buffer FA53 20 61 FA JSR $FA61 ;add number for (side sectors needed * #$78) (decimal 120) FA56 CA DEX ;all side sectors considered ? FA57 10 F8 BPL $FA51 ;no, FA59 A5 07 LDA $07 ;get number of side sector indices needed FA5B 4A LSR ;divide by two FA5C 20 61 FA JSR $FA61 ;add number for side sectors needed FA5F A5 08 LDA $08 ;get number of side sector blocks needed FA61 18 CLC FA62 65 05 ADC $05 ;add number for side sector blocks needed FA64 85 05 STA $05 ;is result below #$FF (decimal 255) FA66 90 02 BCC $FA6A ;yes, FA68 E6 06 INC $06 ;increment HI byte for result FA6A 60 RTS ******************************* Test side sector number and side sector index for residence and range .N = range .V = residence ERROR # 0 = ok 0 = yes ER0 0 = maybe 1 = no ER1 1 = no 0 = yes ER2 1 = no 1 = no ER3 FA6B 20 D7 F9 JSR $F9D7 ;set pointer and get side sector number FA6E C5 83 CMP $83 ;correct side sector ? FA70 D0 0E BNE $FA80 ;no, FA72 A4 84 LDY $84 ;read pointer into side sector buffer value FA74 B1 27 LDA ($27),Y ;is side sector present ? FA76 F0 04 BEQ $FA7C ;no, FA78 2C E4 D2 BIT $D2E4 ;set flags to indicate residence or range valid FA7B 60 RTS ******************************* Indicate side sector out of range FA7C 2C E6 D2 BIT $D2E6 ;set flags to indicate residence or range invalid FA7F 60 RTS ******************************* Test side sector status FA80 A5 83 LDA $83 ;read side sector number FA82 C9 06 CMP #$06 ;side sector value out range ? FA84 B0 0A BCS $FA90 ;yes, FA86 0A ASL ;multiply side sector number by two FA87 A8 TAY FA88 A9 04 LDA #$04 ;set LO byte of pointer to #$04 FA8A 85 27 STA $27 ;store pointer value in directory buffer FA8C B1 27 LDA ($27),Y ;is side sector resident within range ? FA8E D0 04 BNE $FA94 ;no, ******************************* Indicate side sector out of range FA90 2C E7 D2 BIT $D2E7 ;set flags to indicate side sector way out of range FA93 60 RTS ******************************* Indicate side sector not resident FA94 2C E5 D2 BIT $D2E5 ;set flags to indicate invalid side sector residence or range FA97 60 RTS ******************************* Get active buffer number .X = logical index .ACC = active buffer number .N = no active buffer (set to 1) FA98 A6 15 LDX $15 ;get active buffer number FA9A B5 49 LDA $49,X ;is first buffer active ? FA9C 10 02 BPL $FAA0 ;yes, FA9E B5 51 LDA $51,X ;get second buffer number FAA0 29 BF AND #$BF ;clear buffer bit FAA2 60 RTS ******************************* Get active buffer number and set last buffer used .X = logical index .ACC = active buffer number .N = no active buffer (set to 1) .V = buffer needs updating FAA3 A6 15 LDX $15 ;get active buffer number FAA5 8E 49 43 STX $4349 ;set as last buffer used FAA8 B5 49 LDA $49,X ;is first buffer active ? FAAA 10 09 BPL $FAB5 ;yes, FAAC 8A TXA FAAD 18 CLC FAAE 69 08 ADC #$08 ;add in maximum possible channels to active buffer number FAB0 8D 49 43 STA $4349 ;store new result as last buffer used FAB3 B5 51 LDA $51,X ;get second buffer number FAB5 85 05 STA $05 ;store in TEMP1 location FAB7 29 1F AND #$1F ;set .N and .V flags as required FAB9 24 05 BIT $05 ;test buffer status FABB 60 RTS ******************************* Mark end of record then move on to next record FABC A9 60 LDA #$60 ;set for get record and overflow flag FABE 20 A8 F8 JSR $F8A8 ;clear record and overflow flag FAC1 A9 80 LDA #$80 ;set last record flag FAC3 20 B1 F8 JSR $F8B1 ;beyond last record ? FAC6 D0 41 BNE $FB09 ;no, FAC8 A6 15 LDX $15 ;get current active channel number FACA F6 59 INC $59,X ;has LO address counter reached #$00 ? FACC D0 02 BNE $FAD0 ;no, FACE F6 61 INC $61,X ;increment HI address counter FAD0 A6 15 LDX $15 ;get current active channel number FAD2 B5 69 LDA $69,X ;is there another record to move to ? FAD4 F0 2E BEQ $FB04 ;no, FAD6 20 E1 F0 JSR $F0E1 ;read active buffer pointer FAD9 A6 15 LDX $15 ;read current active channel number FADB D5 69 CMP $69,X ;same buffer ? FADD 90 03 BCC $FAE2 ;no, FADF 20 28 FB JSR $FB28 ;set up next buffer FAE2 A6 15 LDX $15 ;read current active channel number FAE4 B5 69 LDA $69,X ;get pointer to next record FAE6 20 C1 F0 JSR $F0C1 ;advance to next record FAE9 A1 29 LDA ($29,X) ;read first byte from record FAEB 85 18 STA $18 ;store in temporary data location FAED A9 60 LDA #$60 ;set for get record and overflow flag FAEF 20 A8 F8 JSR $F8A8 ;clear record and overflow flag FAF2 20 F1 FD JSR $FDF1 ;advance record pointer FAF5 48 PHA ;preserve current record pointer, has a block boundary been crossed ? FAF6 90 28 BCC $FB20 ;no, FAF8 A9 00 LDA #$00 FAFA 20 EF F0 JSR $F0EF ;is this the last data block for file ? FAFD D0 21 BNE $FB20 ;no, FAFF 68 PLA ;retrieve record pointer FB00 C9 02 CMP #$02 ;is pointer pointing to sector link ? FB02 F0 12 BEQ $FB16 ;yes, FB04 A9 80 LDA #$80 FB06 20 A2 F8 JSR $F8A2 ;set last record flag FB09 20 AB ED JSR $EDAB ;set buffer pointers FB0C B5 29 LDA $29,X ;read byte from active buffer FB0E 99 BD 00 STA $00BD,Y ;store as last character pointer FB11 A9 0D LDA #$0D ;set for carriage return #$0D (decimal 13) FB13 85 18 STA $18 ;store in temporary data location FB15 60 RTS ******************************* Store current pointer value in buffer and set new pointer value FB16 20 21 FB JSR $FB21 ;set pointer to last character FB19 A6 15 LDX $15 ;read current active channel number FB1B A9 00 LDA #$00 FB1D 95 69 STA $69,X ;clear pointer to next record FB1F 60 RTS ******************************* Set pointer to last character FB20 68 PLA ;retrieve pointer position to next character FB21 A6 15 LDX $15 ;read current active channel FB23 95 69 STA $69,X ;store pointer to next record FB25 4C 56 FC JMP $FC56 ;set pointer to last character in record ******************************* Set up next record in buffer FB28 20 4F EE JSR $EE4F ;set drive number used in last job FB2B 20 9A F9 JSR $F99A ;set new track and sector values from link in buffer FB2E 20 A3 FA JSR $FAA3 ;should buffer be updated on disk ? FB31 50 16 BVC $FB49 ;no, FB33 20 63 F9 JSR $F963 ;write modified buffer to diskette FB36 20 D1 EB JSR $EBD1 ;toggle active and inactive buffers FB39 A9 02 LDA #$02 FB3B 20 C1 F0 JSR $F0C1 ;set new pointer position FB3E 20 B6 F8 JSR $F8B6 ;was last job equal to WRITE ? FB41 D0 24 BNE $FB67 ;no, FB43 20 5C F9 JSR $F95C ;read in needed buffer FB46 4C 82 EC JMP $EC82 ;wait until job completed ******************************* Test if last data block in file FB49 20 D1 EB JSR $EBD1 ;toggle active and inactive buffers FB4C 20 B6 F8 JSR $F8B6 ;was last job equal to WRITE ? FB4F D0 06 BNE $FB57 ;no, FB51 20 5C F9 JSR $F95C ;read in needed buffer FB54 20 82 EC JSR $EC82 ;wait until job completed FB57 20 9A F9 JSR $F99A ;set new track and sector values from link in buffer FB5A A5 13 LDA $13 ;last data block of file ? FB5C F0 09 BEQ $FB67 ;yes, FB5E 20 D1 EB JSR $EBD1 ;toggle active and inactive buffers FB61 20 5C F9 JSR $F95C ;read in needed buffer FB64 20 D1 EB JSR $EBD1 ;toggle active and inactive buffers FB67 60 RTS ******************************* Write relative data into buffer FB68 20 EE FB JSR $FBEE ;mark buffer as being updated and ready for transfer to disk FB6B 20 98 FA JSR $FA98 ;get active buffer number FB6E 0A ASL ;double it FB6F AA TAX FB70 A5 18 LDA $18 ;read data byte stored in temporary location FB72 81 29 STA ($29,X) ;store byte in buffer FB74 B4 29 LDY $29,X ;read LO pointer value for current buffer FB76 C8 INY ;end of buffer ? FB77 D0 09 BNE $FB82 ;no, FB79 A4 15 LDY $15 ;read current active channel number FB7B B9 69 00 LDA $0069,Y ;is there another record ? FB7E F0 0A BEQ $FB8A ;no, FB80 A0 02 LDY #$02 FB82 98 TYA FB83 A4 15 LDY $15 ;read current active channel number FB85 D9 69 00 CMP $0069,Y ;is value in record table used as a pointer ? FB88 D0 05 BNE $FB8F ;no, FB8A A9 20 LDA #$20 ;set for "RECORD FULL" FB8C 4C A2 F8 JMP $F8A2 ;set overflow flag ******************************* Test if end of buffer. If not, set up next record in buffer FB8F F6 29 INC $29,X ;end of buffer ? FB91 D0 03 BNE $FB96 ;no, FB93 20 28 FB JSR $FB28 ;set up next record in buffer FB96 60 RTS ******************************* Write record to data buffer FB97 A9 A0 LDA #$A0 ;set for testing if this is the last record or if the overflow is set FB99 20 B1 F8 JSR $F8B1 ;any flags set ? FB9C D0 24 BNE $FBC2 ;yes, FB9E A5 18 LDA $18 ;get data to send from temporary location FBA0 20 68 FB JSR $FB68 ;store data in buffer FBA3 A5 A0 LDA $A0 ;was EOI signal detected ? FBA5 F0 0D BEQ $FBB4 ;no, FBA7 60 RTS ******************************* Test if overflow error and set up next record FBA8 A9 20 LDA #$20 ;set for testing of overflow flag FBAA 20 B1 F8 JSR $F8B1 ;is there an overflow error ? FBAD F0 05 BEQ $FBB4 ;no, FBAF A9 51 LDA #$51 ;set for "51 OVERFLOW IN RECORD" error FBB1 8D 73 43 STA $4373 ;store error status FBB4 20 DC FB JSR $FBDC ;clear rest of record FBB7 20 3C FC JSR $FC3C ;set up for next record FBBA AD 73 43 LDA $4373 ;is there an error detected ? FBBD F0 0B BEQ $FBCA ;no, FBBF 4C C3 DB JMP $DBC3 ;jump to process command error routine ******************************* Test for last record flag and EOI status FBC2 29 80 AND #$80 ;was last record flag detected ? FBC4 D0 05 BNE $FBCB ;no, FBC6 A5 A0 LDA $A0 ;was EOI signal detected ? FBC8 F0 DE BEQ $FBA8 ;no, FBCA 60 RTS ******************************* Add new relative record to file and write data byte FBCB A5 18 LDA $18 ;get data from temporary location FBCD 48 PHA ;preserve it FBCE 20 09 FE JSR $FE09 ;add new record to relative file FBD1 68 PLA ;retrieve data FBD2 85 18 STA $18 ;store in temporary location FBD4 A9 80 LDA #$80 ;set for last record flag mode FBD6 20 A8 F8 JSR $F8A8 ;clear last record flag status FBD9 4C 9E FB JMP $FB9E ;write record to data buffer ******************************* Fill balance of relative record with #$00 FBDC A9 20 LDA #$20 ;set for testing of overflow flag FBDE 20 B1 F8 JSR $F8B1 ;has an overflow occured ? FBE1 D0 0A BNE $FBED ;yes, FBE3 A9 00 LDA #$00 FBE5 85 18 STA $18 ;store data in temporary location FBE7 20 68 FB JSR $FB68 ;write data byte in temporary location to buffer FBEA 4C DC FB JMP $FBDC ;do balance of record until overflow detected FBED 60 RTS ******************************* Set flag to indicate that buffer needs to be updated on disk FBEE 20 A3 FA JSR $FAA3 ;get active buffer number FBF1 09 40 ORA #$40 ;set buffer needs updating flag FBF3 AE 49 43 LDX $4349 ;get buffer pointer value FBF6 95 49 STA $49,X ;store new buffer status FBF8 60 RTS ******************************* Clear flag indicating that buffer needs to be updated on disk FBF9 20 A3 FA JSR $FAA3 ;get active buffer number FBFC 29 BF AND #$BF ;clear buffer update request flag FBFE AE 49 43 LDX $4349 ;get buffer pointer value FC01 95 49 STA $49,X ;store new buffer status FC03 60 RTS ******************************* Get byte from relative record FC04 A9 80 LDA #$80 ;set for testing of EOI signal FC06 20 B1 F8 JSR $F8B1 ;last byte in file encountered ? FC09 D0 3C BNE $FC47 ;yes, FC0B A9 40 LDA #$40 ;set for active REL file type FC0D 20 A2 F8 JSR $F8A2 ;set file type and buffers for current file FC10 20 AB ED JSR $EDAB ;set buffer pointers for current record FC13 B5 29 LDA $29,X ;read LO buffer pointer value FC15 D9 BD 00 CMP $00BD,Y ;has next record been reached ? FC18 F0 22 BEQ $FC3C ;yes, FC1A F6 29 INC $29,X ;all bytes in current record read ? FC1C D0 06 BNE $FC24 ;no, FC1E 20 28 FB JSR $FB28 ;set up next record in buffer FC21 20 AB ED JSR $EDAB ;set buffer pointers for current record FC24 A1 29 LDA ($29,X) ;read byte from buffer FC26 99 B5 00 STA $00B5,Y ;send byte to IEEE channel FC29 A9 89 LDA #$89 ;set channel status to: 1000 1001 FC2B 99 98 00 STA $0098,Y ;set new channel status bit 7 = 1 (channel is talker to IEEE) 3 = 0 (send EOI) 0 = 1 (channel is listener to IEEE) FC2E B5 29 LDA $29,X ;read LO buffer pointer value FC30 D9 BD 00 CMP $00BD,Y ;has next record been reached ? FC33 F0 01 BEQ $FC36 ;yes, FC35 60 RTS ******************************* Set channel status to EOI (End Or Identify) FC36 A9 81 LDA #$81 ;set channel status to: 1000 0001 FC38 99 98 00 STA $0098,Y ;set new channel status bit 7 = 1 (channel is talker to IEEE) 3 = 0 (send EOI) 0 = 1 (channel is listener to IEEE) FC3B 60 RTS ******************************* Read last byte in record and proceed to next record in file FC3C 20 BC FA JSR $FABC ;mark end of record and move to next record FC3F 20 AB ED JSR $EDAB ;set buffer pointers for current record FC42 A5 18 LDA $18 ;get data byte from temporary location FC44 4C 26 FC JMP $FC26 ;send byte to IEEE channel ******************************* Send end of record marker, indicate RECORD NOT PRESENT error FC47 A6 15 LDX $15 ;read active channel number FC49 A9 0D LDA #$0D ;set for carriage return #$0D (decimal 13) FC4B 95 B5 STA $B5,X ;send to IEEE channel FC4D A9 81 LDA #$81 ;set channel status to: 1000 0001 FC4F 95 98 STA $98,X ;set new channel status bit 7 = 1 (channel is talker to IEEE) 3 = 0 (send EOI) 0 = 1 (channel is listener to IEEE) FC51 A9 50 LDA #$50 ;set for "50 RECORD NOT PRESENT" error FC53 20 C3 DB JSR $DBC3 ;set up and display error ******************************* Set pointer to last character in record FC56 A6 15 LDX $15 ;read active channel number FC58 B5 69 LDA $69,X ;read next record location pointer FC5A 85 1A STA $1A ;store in TEMPR1 location FC5C C6 1A DEC $1A ;decrement pointer value FC5E C9 02 CMP #$02 ;pointer set to beginning of data in sector ? FC60 D0 04 BNE $FC66 ;no, FC62 A9 FF LDA #$FF FC64 85 1A STA $1A ;set pointer to end of data block FC66 B5 71 LDA $71,X ;read record size value for current file FC68 85 1B STA $1B ;store in TEMPR2 location FC6A 20 E1 F0 JSR $F0E1 ;get active buffer pointer value FC6D A6 15 LDX $15 ;read active channel number FC6F C5 1A CMP $1A ;still in current buffer ? FC71 90 18 BCC $FC8B ;yes, FC73 F0 16 BEQ $FC8B ;yes, FC75 20 D1 EB JSR $EBD1 ;toggle active and inactive buffers FC78 20 98 FC JSR $FC98 ;last non-zero character in record found ? FC7B 90 07 BCC $FC84 ;yes, FC7D A6 15 LDX $15 ;read active channel number FC7F 95 BD STA $BD,X ;store in last character table FC81 4C D1 EB JMP $EBD1 ;toggle active and inactive buffers ******************************* Test for last non-zero character in buffer FC84 20 D1 EB JSR $EBD1 ;toggle active and inactive buffers FC87 A9 FF LDA #$FF FC89 85 1A STA $1A ;store in TEMPR1 location FC8B 20 98 FC JSR $FC98 ;last non-zero character in record found ? FC8E B0 03 BCS $FC93 ;no, FC90 20 E1 F0 JSR $F0E1 ;get active buffer pointer value FC93 A6 15 LDX $15 ;read active channel number FC95 95 BD STA $BD,X ;store in last character table FC97 60 RTS ******************************* Find last non-zero character in record FC98 20 2E F9 JSR $F92E ;set up pointer to start of buffer FC9B A4 1A LDY $1A ;read starting offset value FC9D B1 27 LDA ($27),Y ;is data byte read from buffer #$00 ? FC9F D0 0D BNE $FCAE ;no, FCA1 88 DEY ;move pointer back FCA2 C0 02 CPY #$02 ;found start of record ? FCA4 90 04 BCC $FCAA ;no, FCA6 C6 1B DEC $1B ;is record size #$00 ? FCA8 D0 F3 BNE $FC9D ;no, FCAA C6 1B DEC $1B ;decrement record size FCAC 18 CLC ;indicate that record was not found FCAD 60 RTS ******************************* Indicate last non-zero character as present FCAE 98 TYA ;transfer pointer position for last non-zero character FCAF 38 SEC ;indicate last non-zero character located FCB0 60 RTS ******************************* Position side sector and buffer table to end of last record FCB1 20 D7 F9 JSR $F9D7 ;set side sector pointer to #$00 FCB4 85 83 STA $83 ;set as new side sector number FCB6 A9 04 LDA #$04 FCB8 85 27 STA $27 ;set LO byte address of directory buffer FCBA A0 0A LDY #$0A ;is side sector offset smaller than #$06 (decimal 6) ? FCBC D0 04 BNE $FCC2 ;no, FCBE 88 DEY ;decrement current offset value FCBF 88 DEY ;has sector offset gone below #$00 ? FCC0 30 26 BMI $FCE8 ;yes, FCC2 B1 27 LDA ($27),Y ;is this the last side sector ? FCC4 F0 F8 BEQ $FCBE ;no, FCC6 98 TYA FCC7 4A LSR FCC8 C5 83 CMP $83 ;is this the last side sector ? FCCA F0 09 BEQ $FCD5 ;yes, FCCC 85 83 STA $83 ;set new side sector number as current side sector FCCE A6 15 LDX $15 ;read active channel number FCD0 B5 79 LDA $79,X ;get side sector value from table FCD2 20 20 FA JSR $FA20 ;perform indirect read of last side sector FCD5 A0 00 LDY #$00 FCD7 84 27 STY $27 ;set LO byte address of directory buffer FCD9 B1 27 LDA ($27),Y ;is track link in buffer set to #$00 ? FCDB D0 0B BNE $FCE8 ;no, FCDD C8 INY FCDE B1 27 LDA ($27),Y ;get sector link value from buffer and treat as last character position in buffer FCE0 A8 TAY FCE1 88 DEY ;decrement pointer to last character in buffer by one FCE2 84 84 STY $84 ;set as index into current side sector FCE4 98 TYA FCE5 4C EE F9 JMP $F9EE ;set directory buffer and buffer table with current side sector pointer ******************************* Indicate illegal track or sector FCE8 A9 67 LDA #$67 ;set for "67 ILLEGAL SYSTEM T OR S" error FCEA 20 53 D9 JSR $D953 ;generate error message ******************************* Command: POSITION (move to new location in a relative file) FCED 20 B0 DC JSR $DCB0 ;initialize pointers and tables FCF0 AD 01 43 LDA $4301 ;read second byte from command buffer FCF3 85 16 STA $16 ;set as current secondary address FCF5 20 69 ED JSR $ED69 ;is there an internal read channel available ? FCF8 90 05 BCC $FCFF ;yes, FCFA A9 70 LDA #$70 ;set for "70 NO CHANNEL" error FCFC 20 C3 DB JSR $DBC3 ;set up and display error FCFF A9 E0 LDA #$E0 ;set flag modes: 1110 0000 FD01 20 A8 F8 JSR $F8A8 ;clear indicated flags (last record, get byte, overflow) FD04 20 A1 ED JSR $EDA1 ;is current file type REL ? FD07 F0 05 BEQ $FD0E ;yes, FD09 A9 64 LDA #$64 ;set for "64 FILE TYPE MISMATCH" error FD0B 20 C3 DB JSR $DBC3 ;set up and display error FD0E B5 90 LDA $90,X ;read file information from table SEQ = type 1 PRG = type 2 USR = type 3 REL = type 4 direct = type 7 FD10 29 01 AND #$01 ;determine drive number FD12 85 12 STA $12 ;set as current drive number FD14 AD 02 43 LDA $4302 ;read third byte from command buffer FD17 95 59 STA $59,X ;set as LO byte of record number FD19 AD 03 43 LDA $4303 ;read fourth byte from command buffer FD1C 95 61 STA $61,X ;set as HI byte of record number FD1E A6 15 LDX $15 ;read active channel number FD20 A9 89 LDA #$89 ;set channel status to: 1000 1001 FD22 95 98 STA $98,X ;set new channel status bit 7 = channel is talker (set to 1) 3 = channel is send EOI (talker only) 0 = channel is listener (set to 1) FD24 AD 04 43 LDA $4304 ;is pointer position into desired record set to #$00 ? FD27 F0 10 BEQ $FD39 ;yes, FD29 38 SEC FD2A E9 01 SBC #$01 ;is pointer value now decremented to start of record ? FD2C F0 0B BEQ $FD39 ;yes, FD2E D5 71 CMP $71,X ;is pointer value within record range ? FD30 90 07 BCC $FD39 ;yes, FD32 A9 51 LDA #$51 ;set for "51 OVERFLOW IN RECORD" error FD34 8D 73 43 STA $4373 ;set error status FD37 A9 00 LDA #$00 FD39 85 82 STA $82 ;set byte requested from record to #$00 FD3B 20 AE EA JSR $EAAE ;calculate side sector pointers FD3E 20 FD F9 JSR $F9FD ;has side sector pointer gone beyond last record in file FD41 50 08 BVC $FD4B ;no, FD43 A9 80 LDA #$80 ;set flag mode: 1000 0000 FD45 20 A2 F8 JSR $F8A2 ;set flag to indicate last record reached FD48 4C 47 FC JMP $FC47 ;jump to indicate record not present error ******************************* Move to desired record and test if request valid FD4B 20 5B FD JSR $FD5B ;move to desired record FD4E A9 80 LDA #$80 ;set flag mode: 1000 0000 FD50 20 B1 F8 JSR $F8B1 ;is this an attempt to go beyond last record ? FD53 F0 03 BEQ $FD58 ;no, FD55 4C 47 FC JMP $FC47 ;jump to indicate record not present error ******************************* Indicate desired record requested valid FD58 4C 99 DB JMP $DB99 ;indicate successful command termination ******************************* Position relative data block into active buffer and next block into inactive buffer FD5B 20 7D FD JSR $FD7D ;position data blocks into buffers FD5E A5 85 LDA $85 ;get pointer position into desired record FD60 20 C1 F0 JSR $F0C1 ;set new pointer position FD63 A6 15 LDX $15 ;read active channel number FD65 B5 71 LDA $71,X ;read record size value from table FD67 38 SEC FD68 E5 82 SBC $82 ;is determined sector offset valid ? FD6A B0 03 BCS $FD6F ;yes, FD6C 4C E8 FC JMP $FCE8 ;indicate illegal track or sector error ******************************* Position pointer to desired record, move to next record if necessary FD6F 18 CLC FD70 65 85 ADC $85 ;has desired position within record been reached ? FD72 90 03 BCC $FD77 ;yes, FD74 69 01 ADC #$01 ;add one to current pointer value FD76 38 SEC FD77 20 F5 FA JSR $FAF5 ;set up next record FD7A 4C 21 FC JMP $FC21 ;finish setting up for next record ******************************* Position proper data blocks into buffers FD7D A5 27 LDA $27 ;read LO byte address of directory buffer FD7F 85 1C STA $1C ;store in TEMPR3 location FD81 A5 28 LDA $28 ;read HI byte address of directory buffer FD83 85 1D STA $1D ;store in TEMPR4 location FD85 20 BD FD JSR $FDBD ;is desired block in buffer ? FD88 F0 44 BEQ $FDCE ;yes, FD8A 20 F4 F8 JSR $F8F4 ;clean buffer FD8D 20 0F F9 JSR $F90F ;get track and sector link from buffer FD90 A5 13 LDA $13 ;is there another data block for file ? FD92 F0 18 BEQ $FDAC ;no, FD94 20 D1 EB JSR $EBD1 ;toggle active and inactive buffers FD97 20 BD FD JSR $FDBD ;is desired block in buffer ? FD9A D0 10 BNE $FDAC ;no, FD9C 20 0F F9 JSR $F90F ;get track and sector link from buffer FD9F A5 13 LDA $13 ;is this the last data block of file ? FDA1 F0 2B BEQ $FDCE ;yes, FDA3 20 D1 EB JSR $EBD1 ;toggle active and inactive buffers FDA6 20 5C F9 JSR $F95C ;read in next block of file FDA9 4C D1 EB JMP $EBD1 ;toggle active and inactive buffers ******************************* Set current track and sector and begin double buffering FDAC A0 00 LDY #$00 FDAE B1 1C LDA ($1C),Y ;read track value from directory buffer FDB0 85 13 STA $13 ;set as current track number FDB2 C8 INY FDB3 B1 1C LDA ($1C),Y ;read sector value from directory buffer FDB5 85 14 STA $14 ;set as current sector number FDB7 20 D1 EB JSR $EBD1 ;toggle active and inactive buffers FDBA 4C 1D ED JMP $ED1D ;begin double buffering ******************************* Check is required block is in buffer FDBD 20 41 F9 JSR $F941 ;read track and sector values from HEADER FDC0 A0 00 LDY #$00 FDC2 B1 1C LDA ($1C),Y ;read track value from directory buffer FDC4 C5 13 CMP $13 ;has desired track been reached ? FDC6 F0 01 BEQ $FDC9 ;yes, FDC8 60 RTS ******************************* Test if desired sector has been reached FDC9 C8 INY FDCA B1 1C LDA ($1C),Y ;read sector value from directory buffer FDCC C5 14 CMP $14 ;has desired sector been reached ? (.Z = 1) FDCE 60 RTS ******************************* Set null records in active buffer for extension ENTRY: last record position in previous buffer EXIT : last record position in buffer for next null buffer or to set last character FDCF 20 2E F9 JSR $F92E ;set pointers to start of data buffers FDD2 A0 02 LDY #$02 ;set pointer for third position in data buffer FDD4 A9 00 LDA #$00 FDD6 91 27 STA ($27),Y ;store #$00 in data buffer FDD8 C8 INY ;entire buffer filled ? FDD9 D0 FB BNE $FDD6 ;no, FDDB 20 F1 FD JSR $FDF1 ;calculate position of next record FDDE 95 69 STA $69,X ;store new record value in table FDE0 A8 TAY FDE1 A9 FF LDA #$FF FDE3 91 27 STA ($27),Y ;set opening record value for next record FDE5 20 F1 FD JSR $FDF1 ;all records in block set ? FDE8 90 F4 BCC $FDDE ;no, FDEA D0 04 BNE $FDF0 ;another sector block needed ? no, FDEC A9 00 LDA #$00 FDEE 95 69 STA $69,X ;set position of next record to start of next sector FDF0 60 RTS ******************************* Add next record to record size .C = 1 (buffer boundary has been crossed) FDF1 A6 15 LDX $15 ;read active channel number FDF3 B5 69 LDA $69,X ;get next record pointer value FDF5 38 SEC ;is there another record ? FDF6 F0 0D BEQ $FE05 ;no, FDF8 18 CLC FDF9 75 71 ADC $71,X ;will added record run into next sector ? FDFB 90 0B BCC $FE08 ;no, FDFD D0 06 BNE $FE05 ;record fills entire sector ? no, FDFF A9 02 LDA #$02 FE01 2C E3 D2 BIT $D2E3 ;set flag to indicate another is needed FE04 60 RTS ******************************* Adjust pointer to compensate for link FE05 69 01 ADC #$01 ;add one to pointer value to compensate for link FE07 38 SEC ;set flag to indicate no more sectors FE08 60 RTS ******************************* Add blocks to relative file FE09 20 4F EE JSR $EE4F ;set drive number FE0C 20 B1 FC JSR $FCB1 ;set up end of file FE0F 20 7D FD JSR $FD7D ;position proper data blocks into the buffers FE12 A5 84 LDA $84 ;get side sector index value FE14 85 1A STA $1A ;store in TEMPR1 location FE16 A5 83 LDA $83 ;get side sector number FE18 85 19 STA $19 ;store in TEMPR0 location FE1A A9 00 LDA #$00 FE1C 85 1B STA $1B ;clear TEMPR2 location FE1E A9 00 LDA #$00 FE20 85 82 STA $82 ;clear pointer into to record FE22 20 AE EA JSR $EAAE ;calculate side sector pointers FE25 20 2E DB JSR $DB2E ;calculate number of free blocks FE28 A4 15 LDY $15 ;read active channel number FE2A B6 71 LDX $71,Y ;get record size from table FE2C CA DEX ;decrement size by one FE2D 8A TXA FE2E 18 CLC FE2F 65 85 ADC $85 ;does next record span into next sector ? FE31 90 0C BCC $FE3F ;no, FE33 E6 84 INC $84 ;increment side sector index value by one FE35 E6 84 INC $84 ;pointer still in current side sector ? FE37 D0 06 BNE $FE3F ;yes, FE39 E6 83 INC $83 ;increment side sector number by one FE3B A9 10 LDA #$10 FE3D 85 84 STA $84 ;set side sector offset to #$10 (decimal 17) FE3F A5 1A LDA $1A ;get side sector index from TEMPR1 location FE41 18 CLC FE42 69 02 ADC #$02 ;add two to side sector index value FE44 20 EE F9 JSR $F9EE ;set directory buffer & buffer table FE47 A5 83 LDA $83 ;get side sector number FE49 C9 06 CMP #$06 ;is there more than 6 side sectors ? FE4B 90 05 BCC $FE52 ;no, FE4D A9 52 LDA #$52 ;set for "52 FILE TOO LARGE" error FE4F 20 C3 DB JSR $DBC3 ;set up and display error FE52 A5 84 LDA $84 ;get side sector index value FE54 38 SEC FE55 E5 1A SBC $1A ;calculation result still indicates blocks available ? FE57 B0 03 BCS $FE5C ;yes, FE59 E9 0F SBC #$0F ;substract side sector offset from current result FE5B 18 CLC FE5C 85 07 STA $07 ;store new result in TEMP3 as side sector indices FE5E A5 83 LDA $83 ;get side sector number FE60 E5 19 SBC $19 ;determine number of side sectors needed FE62 85 08 STA $08 ;store new result in TEMP4 location FE64 A2 00 LDX #$00 FE66 86 05 STX $05 ;clear TEMP1 location FE68 86 06 STX $06 ;clear TEMP2 location FE6A AA TAX FE6B 20 56 FA JSR $FA56 ;calculate number of blocks needed FE6E A5 06 LDA $06 ;HI byte count of blocks needed above #$FF (decimal 255) ? FE70 D0 07 BNE $FE79 ;yes, FE72 A6 05 LDX $05 ;read LO byte count of blocks needed FE74 CA DEX ;just one side sector laid out ? FE75 D0 02 BNE $FE79 ;no, FE77 E6 1B INC $1B ;indicate that one block is to be used FE79 CD 78 43 CMP $4378 ;is there enough blocks free on diskette ? FE7C 90 09 BCC $FE87 ;yes, FE7E D0 CD BNE $FE4D ;no, FE80 AD 77 43 LDA $4377 ;test LO byte for blocks free on diskette FE83 C5 05 CMP $05 ;is there enough blocks free on diskette ? FE85 90 C6 BCC $FE4D ;no, FE87 A9 01 LDA #$01 FE89 20 EF F0 JSR $F0EF ;get the sector link FE8C 18 CLC FE8D 69 01 ADC #$01 ;add in next record FE8F A6 15 LDX $15 ;read active channel number FE91 95 69 STA $69,X ;store next record value in table FE93 20 AF D6 JSR $D6AF ;get next available track and sector FE96 20 00 F9 JSR $F900 ;set track and sector link by use of values returned from track/sector search FE99 A5 1B LDA $1B ;only this sector block needed ? FE9B D0 15 BNE $FEB2 ;yes, FE9D 20 63 F9 JSR $F963 ;write current last record to diskette FEA0 20 D1 EB JSR $EBD1 ;toggle active and inactive buffers FEA3 20 8F EC JSR $EC8F ;set track, sector, ID for current buffer FEA6 20 AF D6 JSR $D6AF ;get next available track and sector FEA9 20 00 F9 JSR $F900 ;set track and sector link by use of values returned from track/sector search FEAC 20 CF FD JSR $FDCF ;clear all records in current buffer FEAF 4C BE FE JMP $FEBE ;chain through file and set side sectors ******************************* Mark current block as last one in file FEB2 20 D1 EB JSR $EBD1 ;toggle active and inactive buffers FEB5 20 8F EC JSR $EC8F ;set track, sector, ID for current buffer FEB8 20 CF FD JSR $FDCF ;clear all records in current buffer FEBB 20 1C F9 JSR $F91C ;set track link to indicate last data block and set sector link to point to last byte ******************************* Chain through file and set side sectors FEBE 20 63 F9 JSR $F963 ;write current block to diskette FEC1 20 0F F9 JSR $F90F ;get track and sector from buffer FEC4 A5 13 LDA $13 ;get current track number FEC6 48 PHA ;preserve it FEC7 A5 14 LDA $14 ;get current sector number FEC9 48 PHA ;preserve it FECA 20 41 F9 JSR $F941 ;read track and sector values from HEADER FECD A5 14 LDA $14 ;get current sector number FECF 48 PHA ;preserve it FED0 A5 13 LDA $13 ;get current track number FED2 48 PHA ;preserve it FED3 20 4A FA JSR $FA4A ;get side sector pointers FED6 AA TAX ;another side sector needed ? FED7 D0 0A BNE $FEE3 ;no, FED9 20 38 FF JSR $FF38 ;get another side sector FEDC A9 10 LDA #$10 ;set side sector offset to #$10 (decimal 17) FEDE 20 EE F9 JSR $F9EE ;set directory buffer and buffer table FEE1 E6 19 INC $19 ;increment side sector count FEE3 68 PLA ;retrieve track value from HEADER FEE4 20 98 F8 JSR $F898 ;store byte in side sector FEE7 68 PLA ;retrieve sector value from HEADER FEE8 20 98 F8 JSR $F898 ;store byte in side sector FEEB 68 PLA ;retrieve sector value FEEC 85 14 STA $14 ;set as current sector number FEEE 68 PLA ;retrieve track value FEEF 85 13 STA $13 ;is there another block in file ? FEF1 F0 0F BEQ $FF02 ;no, FEF3 A5 19 LDA $19 ;read side sector count FEF5 C5 83 CMP $83 ;all side sectors blocks done ? FEF7 D0 A7 BNE $FEA0 ;no, FEF9 20 4A FA JSR $FA4A ;get side sector pointers FEFC C5 84 CMP $84 ;almost done chaining through file ? FEFE 90 A0 BCC $FEA0 ;yes, FF00 F0 B0 BEQ $FEB2 ;yes, one more block left to do FF02 20 4A FA JSR $FA4A ;get side sector pointers FF05 48 PHA ;preserve it FF06 A9 00 LDA #$00 FF08 20 E1 F9 JSR $F9E1 ;set directory buffer pointer by use of side sector pointer value FF0B A9 00 LDA #$00 FF0D A8 TAY FF0E 91 27 STA ($27),Y ;set track link in buffer to #$00 (last block) FF10 C8 INY ;move pointer to sector link location FF11 68 PLA ;retrieve side sector pointer value FF12 38 SEC FF13 E9 01 SBC #$01 ;determine position of last byte in block FF15 91 27 STA ($27),Y ;store in sector link position FF17 20 71 F9 JSR $F971 ;write out current block of side sectors to diskette FF1A 20 82 EC JSR $EC82 ;wait until job completed FF1D 20 55 F6 JSR $F655 ;write out BAM to diskette FF20 20 AE EA JSR $EAAE ;calculate side sector pointers FF23 20 D1 EB JSR $EBD1 ;toggle active and inactive buffers FF26 20 FD F9 JSR $F9FD ;is side sector and index within range ? FF29 70 03 BVS $FF2E ;no, FF2B 4C 5B FD JMP $FD5B ;position relative data block into active buffer and next block into inactive buffer ******************************* Indicate record not present FF2E A9 80 LDA #$80 ;set last record flag mode FF30 20 A2 F8 JSR $F8A2 ;set indicated flag mode FF33 A9 50 LDA #$50 ;set for "50 RECORD NOT PRESENT" error FF35 20 C3 DB JSR $DBC3 ;set up and display error ******************************* Generate new side sector and fix previous side sector to reflect new side sector FF38 20 AF D6 JSR $D6AF ;get next available track and sector FF3B 20 D1 EB JSR $EBD1 ;toggle active and inactive buffers FF3E 20 F4 F8 JSR $F8F4 ;write out buffer if no longer current on disk FF41 20 98 FA JSR $FA98 ;get active buffer number FF44 48 PHA ;preserve it FF45 20 C6 F9 JSR $F9C6 ;clear buffer FF48 A6 15 LDX $15 ;read active channel number FF4A B5 79 LDA $79,X ;read side sector value from table FF4C A8 TAY FF4D 68 PLA ;retrieve active buffer number FF4E AA TAX FF4F A9 10 LDA #$10 ;set side sector offset to #$10 (decimal 17) FF51 20 AA F9 JSR $F9AA ;move sixteen bytes from previous side sector to other buffer FF54 A9 00 LDA #$00 FF56 20 E1 F9 JSR $F9E1 ;set directory buffer pointer by use of side sector pointer value FF59 A0 02 LDY #$02 FF5B B1 27 LDA ($27),Y ;get side sector number FF5D 48 PHA ;preserve it FF5E A9 00 LDA #$00 FF60 20 C1 F0 JSR $F0C1 ;set new pointer position to start of side sector buffer FF63 68 PLA ;retrieve side sector number FF64 18 CLC FF65 69 01 ADC #$01 ;increment side sector number by one FF67 91 27 STA ($27),Y ;store new result in buffer FF69 0A ASL ;multiply side sector number by two FF6A 69 04 ADC #$04 ;add four to result FF6C 85 1C STA $1C ;store in TEMPR3 location FF6E A8 TAY FF6F 38 SEC FF70 E9 02 SBC #$02 ;substract two from result FF72 85 1D STA $1D ;store in TEMPR4 location FF74 A5 13 LDA $13 ;get current track number FF76 85 1A STA $1A ;store in TEMPR1 location FF78 91 27 STA ($27),Y ;store in side sector FF7A C8 INY FF7B A5 14 LDA $14 ;get current sector number FF7D 85 1B STA $1B ;store in TEMPR2 location FF7F 91 27 STA ($27),Y ;store in side sector FF81 A0 00 LDY #$00 FF83 98 TYA FF84 91 27 STA ($27),Y ;store track link in new side sector to #$00 FF86 C8 INY FF87 A9 11 LDA #$11 FF89 91 27 STA ($27),Y ;set sector link to indicate last non-zero as being after the side sector offset FF8B A9 10 LDA #$10 ;set for #$10 (decimal 17) FF8D 20 C1 F0 JSR $F0C1 ;set new pointer position into side sector FF90 20 55 F9 JSR $F955 ;write out side sector block to disk FF93 20 82 EC JSR $EC82 ;wait until job completed ******************************* Revise previous side sector to reflect newly added side sector FF96 A6 15 LDX $15 ;read active channel number FF98 B5 79 LDA $79,X ;get side sector buffer number FF9A 48 PHA ;preserve it FF9B 20 A3 FA JSR $FAA3 ;get active buffer number and set flags FF9E A6 15 LDX $15 ;read active channel number FFA0 95 79 STA $79,X ;swap active buffer number and side sector buffer number FFA2 68 PLA ;retrieve side sector buffer number FFA3 AE 49 43 LDX $4349 ;get last buffer used FFA6 95 49 STA $49,X ;set buffer as inactive FFA8 A9 00 LDA #$00 FFAA 20 C1 F0 JSR $F0C1 ;set pointer position to start of buffer FFAD A0 00 LDY #$00 FFAF A5 13 LDA $13 ;get current track number FFB1 91 27 STA ($27),Y ;set as new side sector track link FFB3 C8 INY FFB4 A5 14 LDA $14 ;get current sector number FFB6 91 27 STA ($27),Y ;set as new side sector link FFB8 4C C8 FF JMP $FFC8 ;write side sector to diskette ******************************* Write side sector and update next one if needed FFBB 20 98 FA JSR $FA98 ;get active buffer number FFBE A6 15 LDX $15 ;read active channel number FFC0 20 20 FA JSR $FA20 ;read next side sector buffer number FFC3 A9 00 LDA #$00 FFC5 20 C1 F0 JSR $F0C1 ;set pointer position to start of buffer FFC8 C6 1D DEC $1D ;decrement side sector number by one FFCA C6 1D DEC $1D ;decrement side sector number by one FFCC A4 1C LDY $1C ;get pointer value into buffer FFCE A5 1A LDA $1A ;get side sector track number FFD0 91 27 STA ($27),Y ;store in buffer FFD2 C8 INY FFD3 A5 1B LDA $1B ;get side sector number FFD5 91 27 STA ($27),Y ;store in buffer FFD7 20 63 F9 JSR $F963 ;write current block to diskette FFDA 20 82 EC JSR $EC82 ;wait until job completed FFDD A4 1D LDY $1D ;read side sector count FFDF C0 03 CPY #$03 ;any more to update ? FFE1 B0 D8 BCS $FFBB ;yes, FFE3 4C D1 EB JMP $EBD1 ;jump to toggle active and inactive buffers ******************************* Versatile non maskable interrupt FFE6 6C F0 10 JMP ($10F0) ;perform NMI reset ******************************* Checksum byte for $F000 FFE9 11 ??? ;F-ROM checksum ******************************* .Word BLKRD (U1 or UA): $E9FE FFEA FE E9 ??? ;user block-read ******************************* .Word BLKWRT (U2 or UB): $EA38 FFEC 38 EA ??? ;user block-write ******************************* User command to buffer #02 (U3 - U8) FFEE 00 13 ??? ;buffer 2 link (U3 or UC): $1300 FFF0 03 13 ??? ;buffer 2 link (U4 or UD): $1303 FFF2 06 13 ??? ;buffer 2 link (U5 or UE): $1306 FFF4 09 13 ??? ;buffer 2 link (U6 or UF): $1309 FFF6 0C 13 ??? ;buffer 2 link (U7 or UG): $130C FFF8 0F 13 ??? ;buffer 2 link (U8 or UH): $130F ******************************* .Word NMI (U9 or UI): $FFE6 FFFA E6 FF ??? ******************************* .Word DISKINIT (U: or UJ): $D32B FFFC 2B D3 ??? ******************************* .Word ATN/IRQ process : $D50A FFFE 0A D5 ???
Chapter 8 - FORMATTING sequence used for 4040 dual floppy drive
4040 Format codes MAP Code from $0500 - $07A0 LOCATION DESCRIPTION --------------------------------------------------------------------------- $0500 Beginning of format codes $0504 Bump head to track one, initialize buffer pointers to point to buffer #0: $0421 $052B Initialize track number and move head to desired track number $053D Format current track $054A Erase track with SYNC $0561 Write OFF bytes and verify SYNC & OFF bytes $0578 Initialize track capacity $05D0 Set up sectors for current track. Write HEADER block to disk $05ED Write checksum $0601 Write sector number $060F Write track, ID2, ID1 $061E Write nine (9) #$00 bytes (GAP 1) $062E Write DATA block to disk $0647 Write two hundred and fifty six (256) #$00 bytes to disk $0656 Write checksum to disk, write GAP 2 to disk $0666 Test if last sector of track $0670 Verify SYNC and header identifier '08' $0682 Disk error $0690 Verify track, all sectors $06B2 Verify DATA block $06E0 Calculate interleave between first and last sector number $06F8 Check if last track of disk done $070D Send two OFF bytes, set for normal read mode $0727 Set Periphal Control Register $072E Send a byte to the disk $0737 Read a byte from the disk $073E Test if SYNC properly written $0743 Test if SYNC properly written $074F Test for SYNC 65536 times $0765 Calculate checksum for current track, sector $0780 Write #$00 to disk 8192 times $079A Format code work values
4040 Format code 0500 A5 1A LDA $1A ;is format already in progress ? 0502 10 2F BPL $0533 ;yes, ****************************** Bump head to track one, initialize buffer pointers to point to buffer #0: $0421 0504 78 SEI ;set the interrupt 0505 A9 C1 LDA #$C1 ;set for: 1100 0001 0507 95 03 STA $03,X ;set drive status: bit 0-5 = track 6 = stepping (1=yes) 7 = accel. (1=yes) 0509 A9 0F LDA #$0F ;set for: 0000 1111 050B 3D 9A 07 AND $079A,X ;AND with #$0C if drv 0, #$03 if drv 1 050E 05 40 ORA $40 ;determine drive motor to activate 0510 85 40 STA $40 ;set PORT B status bit 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off 0512 A9 8C LDA #$8C ;set for: -70 (2*35 tracks outwards) 0514 95 05 STA $05,X ;set number of steps to new track 0516 58 CLI ;clear the interrupt 0517 B5 05 LDA $05,X ;has motor reached track #$00 ? 0519 D0 FC BNE $0517 ;no, 051B 98 TYA 051C 0A ASL ;multiply job number by two 051D 0A ASL ;multiply new result by two 051E 0A ASL ;multiply new result by two 051F 18 CLC 0520 69 21 ADC #$21 ;add in pointer (buffer #0) 0522 85 18 STA $18 ;set LO pointer into HDRS table: $0421 0524 A0 00 LDY #$00 0526 84 1D STY $1D ;set error count to 0: 00, OK, 00, 00 0528 C8 INY 0529 84 1A STY $1A ;set for track #$01 ****************************** Initialize track number and move head to desired track number 052B 20 65 07 JSR $0765 ;calculate track, sector, checksum 052E A4 1F LDY $1F ;get current job number 0530 6C 00 FC JMP ($FC00) ;indirect jump to $FC54: test motor status, turn on if not and set time for acceleration 0533 A0 02 LDY #$02 ;set for extraction of track number: $0423 0535 51 18 EOR ($18),Y ;on right track ? 0537 D0 F2 BNE $052B ;no, 0539 A9 00 LDA #$00 053B 85 1D STA $1D ;set error count to 0: 00, OK, 00, 00 ****************************** Format current track 053D 78 SEI ;set the interrupt 053E 20 65 07 JSR $0765 ;calculate track, sector, checksum 0541 A9 08 LDA #$08 ;set for test of bit 3 (WPSW) 0543 25 82 AND $82 ;is PORT B write protect switch on ? 0545 F0 03 BEQ $054A ;no, 0547 4C 84 06 JMP $0684 ;yes, ***************************** Erase track with SYNC 054A 20 80 07 JSR $0780 ;write #$00 to disk 8192 times 054D A2 FF LDX #$FF ;bit mask: 1111 1111 054F A9 DA LDA #$DA ;set PCR for write (D) & 1010 (A): (1101 1010) 0551 20 2E 07 JSR $072E ;write #$FF to disk 0554 85 4C STA $4C ;set periphal control register: (PCR) bit 0 set to 1 ca1:byte ready 1=yes, 0=no bits 1-3 ca2:fill/sync normal : xC fill/sync: xE bit 4 set to 1 cb1:error detected 1=yes, 0=no bits 5-7 cb2:read/write write : Dx read : Fx 0556 20 2E 07 JSR $072E ;write #$FF to disk 0559 20 2E 07 JSR $072E ;write #$FF to disk 055C A9 DC LDA #$DC ;set PCR for write (D) & normal (C): (1101 1100) 055E 20 2E 07 JSR $072E ;write #$FF to disk ****************************** Write OFF bytes and verify SYNC & OFF bytes 0561 A2 0F LDX #$0F ;bit mask: 0000 1111 0563 20 2E 07 JSR $072E ;write #$0F to disk (OFF byte) 0566 85 4C STA $4C ;periphal control register (PCR) bit 0 set to 1 ca1:byte ready 1=yes, 0=no bits 1-3 ca2:fill/sync normal : xC fill/sync: xE bit 4 set to 1 cb1:error detected 1=yes, 0=no bits 5-7 cb2:read/write write : Dx read : Fx 0568 20 0D 07 JSR $070D ;send two OFF bytes, set for normal read mode 056B 20 3E 07 JSR $073E ;test if SYNC has been properly written 056E 20 37 07 JSR $0737 ;read a byte from the disk 0571 C9 0F CMP #$0F ;has byte #$0F been properly written ? 0573 F0 03 BEQ $0578 ;yes, 0575 4C 82 06 JMP $0682 ;error detected: OFF byte not written ****************************** Initialize track capacity 0578 A9 11 LDA #$11 ;set for #$11 (decimal 17) 057A 18 CLC 057B 6D 9D 04 ADC $049D ;add #$11 to GAP1 (pre-set to: #$09) 057E 85 0A STA $0A ;store result in number of spaces for format 0580 A6 15 LDX $15 ;read maximum sectors for current track 0582 A0 00 LDY #$00 0584 A9 00 LDA #$00 0586 18 CLC 0587 65 0A ADC $0A ;calculate sector excess, 256 bytes needed ? 0589 90 01 BCC $058C ;yes, 058B C8 INY ;increment index by 256 bytes 058C C8 INY ;increment index by 256 bytes 058D CA DEX ;all sectors calculated ? 058E D0 F6 BNE $0586 ;no, 0590 49 FF EOR #$FF ;turn number into a negative value 0592 38 SEC 0593 69 00 ADC #$00 ;set up subsraction from total track capacity 0595 18 CLC 0596 6D A0 07 ADC $07A0 ;need to borrow during substraction ? 0599 B0 03 BCS $059E ;no, 059B CE 9F 07 DEC $079F ;correct HI byte 059E AA TAX 059F 98 TYA 05A0 49 FF EOR #$FF ;turn number into a negative value 05A2 38 SEC 05A3 69 00 ADC #$00 ;set calculation from remaining bytes 05A5 18 CLC 05A6 6D 9F 07 ADC $079F ;sufficient track capacity ? 05A9 10 03 BPL $05AE ;yes, 05AB 4C 82 06 JMP $0682 ;error detected: track capacity too small 05AE A8 TAY 05AF 8A TXA ;get number of remaining bytes 05B0 A2 00 LDX #$00 05B2 38 SEC 05B3 E5 15 SBC $15 ;can number of sectors still be substracted ? 05B5 B0 03 BCS $05BA ;yes, 05B7 88 DEY ;decrement index, result negative ? 05B8 30 03 BMI $05BD ;yes, 05BA E8 INX ;increment number of remaining bytes, zero ? 05BB D0 F5 BNE $05B2 ;no, 05BD 86 0A STX $0A ;store GAP2 size 05BF EC 9E 04 CPX $049E ;is calculate size smaller than GAP2 size set by dos ? 05C2 B0 03 BCS $05C7 ;no, 05C4 4C 06 82 JMP $0682 ;error detected: not enough spaces for GAP2 05C7 18 CLC 05C8 65 15 ADC $15 ;add number of sector to track to remainder 05CA 8D 9E 07 STA $079E ;store total 05CD 20 80 07 JSR $0780 ;write #$00 to track 8192 times ***************************** Set up sectors for current track. Write HEADER block to disk 05D0 A9 DE LDA #$DE ;set PCR for write (D) & fill/sync (E) (1101 1110) 05D2 A2 FF LDX #$FF ;bit mask: 1111 1111 05D4 20 2E 07 JSR $072E ;write #$FF to disk 05D7 85 4C STA $4C ;periphal control register (PCR) bit 0 set to 1 ca1:byte ready 1=yes, 0=no bits 1-3 ca2:fill/sync normal : xC fill/sync: xE bit 4 set to 1 cb1:error detected 1=yes, 0=no bits 5-7 cb2:read/write write : Dx read : Fx 05D9 20 2E 07 JSR $072E ;write #$FF to disk 05DC 20 2E 07 JSR $072E ;write #$FF to disk 05DF A9 DC LDA #$DC ;set PCR for write (D) & normal (C): (1101 1100) 05E1 20 2E 07 JSR $072E ;write #$FF to disk 05E4 A2 08 LDX #$08 ;header block identifier: '08' 05E6 20 2E 07 JSR $072E ;send header identifier to PORT A: 05E9 85 4C STA $4C ;set periphal control register (PCR) bit 0 set to 1 ca1:byte ready 1=yes, 0=no bits 1-3 ca2:fill/sync normal : xC fill/sync: xE bit 4 set to 1 cb1:error detected 1=yes, 0=no bits 5-7 cb2:read/write write : Dx read : Fx 05EB A2 FF LDX #$FF ;bit mask: 1111 1111 ****************************** Write checksum 05ED AD 9D 07 LDA $079D ;read checksum for current track, sector 05F0 24 4D BIT $4D ;new interrupt ? 05F2 10 FC BPL $05F0 ;no, 05F4 85 80 STA $80 ;write checksum to disk 05F6 24 41 BIT $41 ;clear PORT A: data input 05F8 4D 9C 07 EOR $079C ;check if checksum correspond to track, sector 05FB AC 9C 07 LDY $079C ;load .Y register with current sector number 05FE EE 9C 07 INC $079C ;increment current sector counter ****************************** Write sector number 0601 24 4D BIT $4D ;new interrupt ? 0603 10 FC BPL $0601 ;no, 0605 84 80 STY $80 ;write sector number to disk 0607 24 41 BIT $41 ;clear PORT A: data input 0609 4D 9C 07 EOR $079C ;calculate checksum for new sector 060C 8D 9D 07 STA $079D ;store new checksum ****************************** Write track, ID2, ID1 060F A0 02 LDY #$02 ;set pointer for extraction of HEADER BYTES: $0423 0611 B1 18 LDA ($18),Y ;read header byte 0613 24 4D BIT $4D ;new interrupt ? 0615 10 FC BPL $0613 ;no, 0617 85 80 STA $80 ;write header bytes 0619 24 41 BIT $41 ;clear PORT A: data input 061B 88 DEY ;all header bytes written ? 061C 10 F3 BPL $0611 ;no, ****************************** Write 9 #$00 bytes (GAP1) 061E A9 00 LDA #$00 0620 AC 9D 04 LDY $049D ;GAP1 size set by dos 0623 24 4D BIT $4D ;new interrupt 0625 10 FC BPL $0623 ;no, 0627 85 80 STA $80 ;write GAP1 to disk 0629 24 41 BIT $41 ;clear PORT A: data input 062B 88 DEY ;all GAP1 bytes written ? 062C D0 F5 BNE $0623 ;no, ****************************** Write DATA block to disk 062E A9 DE LDA #$DE ;set PCR for write (D) & fill/sync (E) (1101 1110) 0630 20 2E 07 JSR $072E ;write #$FF to disk 0633 85 4C STA $4C ;set periphal control register (PCR) bit 0 set to 1 ca1:byte ready 1=yes, 0=no bits 1-3 ca2:fill/sync normal : xC fill/sync: xE bit 4 set to 1 cb1:error detected 1=yes, 0=no bits 5-7 cb2:read/write write : Dx read : Fx 0635 20 2E 07 JSR $072E ;write #$FF to disk 0638 20 2E 07 JSR $072E ;write #$FF to disk 063B A9 DC LDA #$DC ;set PCR for write (D) & normal (C): (1101 1100) 063D 20 2E 07 JSR $072E ;write #$FF to disk 0640 A2 2E 07 LDX #$07 ;data block identifier: '07' 0642 20 2E 07 JSR $072E ;send data identifier to PORT A: 0645 85 4C STA $4C ;set periphal control register (PCR) bit 0 set to 1 ca1:byte ready 1=yes, 0=no bits 1-3 ca2:fill/sync normal : xC fill/sync: xE bit 4 set to 1 cb1:error detected 1=yes, 0=no bits 5-7 cb2:read/write write : Dx read : Fx ****************************** Write 256, #$00 bytes to disk 0647 A0 00 LDY #$00 ;counter for writing data block 0649 A2 00 LDX #$00 ;value of data block 064B 24 4D BIT $4D ;new interrupt ? 064D 10 FC BPL $064B ;no, 064F 86 80 STX $80 ;write #$00 to disk 0651 24 41 BIT $41 ;clear PORT A: data input 0653 88 DEY ;has the data block been totally written ? 0654 D0 F5 BNE $064B ;no, ****************************** Write checksum to disk, write GAP2 to disk 0656 A4 0A LDY $0A ;get number of spaces for format 0658 20 2E 07 JSR $072E ;write checksum to disk (#$00) 065B 24 4D BIT $4D ;new interrupt ? 065D 10 FC BPL $065B ;no, 065F 86 80 STX $80 ;send byte to PORT A: data out 0661 24 41 BIT $41 ;clear PORT A: data input 0663 88 DEY ;has designated number of spaces for GAP2 been written 0664 10 F5 BPL $065B ;no, ****************************** Test if last sector of track 0666 AD 9C 07 LDA $079C ;get current sector 0669 C5 15 CMP $15 ;is this the last sector ? 066B F0 03 BEQ $0670 ;yes, 066D 4C D0 05 JMP $05D0 ;no, ****************************** Verify SYNC and header identifier '08' 0670 20 0D 07 JSR $070D ;send two OFF bytes, set for normal read mode 0673 A9 00 LDA #$00 0675 8D 9C 07 STA $079C ;set sector counter to #$00 0678 20 3E 07 JSR $073E ;test if SYNC properly written 067B 20 37 07 JSR $0737 ;get '08' header identifier 067E C9 08 CMP #$08 ;is it there ? 0680 F0 0E BEQ $0690 ;yes, ****************************** Disk error 0682 A9 0C LDA #$0C ;set for #$0C (decimal 12) 0684 58 CLI ;clear the interrupt 0685 E6 1D INC $1D ;increment error counter 0687 A0 0A LDY #$0A ;set for 10 format attempts per track 0689 C4 1D CPY $1D ;attempts to format track expired ? 068B F0 79 BEQ $0706 ;yes, disk error: BAD DISK ! 068D 4C 3D 05 JMP $053D ;no, try reformatting track ****************************** Verify track, all sectors 0690 20 37 07 JSR $0737 ;get checksum 0693 8D 9D 07 STA $079D ;store it 0696 20 37 07 JSR $0737 ;get sector number 0699 CD 9C 07 CMP $079C ;is this the right sector 069C D0 E4 BNE $0682 ;error detected: overlapped sectors 069E 4D 9D 07 EOR $079D ;calculate header checksum: sector, track, ID1, ID2 06A1 A0 02 LDY #$02 06A3 24 4D BIT $4D ;new interrupt ? 06A5 10 FC BPL $06A3 ;no, 06A7 45 41 EOR $41 ;calculate checksum 06A9 88 DEY ;has sector, track, ID1, ID2 been read ? 06AA 10 F7 BPL $06A3 ;no, 06AC A8 TAY ;is accumulator (checksum) correct ? 06AD D0 D3 BNE $0682 ;no, error detected: "CHECKSUM ERROR IN HEADER BLOCK" 06AF EE 9C 07 INC $079C ;increment sector counter ****************************** Verify DATA block 06B2 20 3E 07 JSR $073E ;test if SYNC properly written 06B5 20 37 07 JSR $0737 ;get '07' data identifier 06B8 C9 07 CMP #$07 ;is it there ? 06BA D0 C6 BNE $0682 ;no, disk error: BAD DISK ! 06BC A0 00 LDY #$00 ;set data counter 06BE 24 4D BIT $4D ;new interrupt ? 06C0 10 FC BPL $06BE ;no, 06C2 A5 41 LDA $41 ;get data byte 06C4 D0 BC BNE $0682 ;not equal to #$00 ? error detected:DATA FAULT 06C6 88 DEY ;has all 256 bytes been tested ? 06C7 D0 F5 BNE $06BE ;no, 06C9 20 37 07 JSR $0737 ;get checksum 06CC D0 B4 BNE $0682 ;not #$00 ? error detected: "CHECKSUM ERROR IN DATA BLOCK" 06CE AD 9C 07 LDA $079C ;get current sector 06D1 C5 15 CMP $15 ;have all sectors been verified ? 06D3 D0 A3 BNE $0678 ;no, 06D5 20 3E 07 JSR $073E ;test if SYNC properly written 06D8 AD 9F 07 LDA $079F ;number of spaces for GAP2 correct ? 06DB F0 03 BEQ $06E0 ;yes, 06DD 4C 82 06 JMP $0682 ;error detected: BAD SPACING (GAP2) ****************************** Calculate interleave between first and last sector 06E0 AD 9E 07 LDA $079E ;read remainder of track size 06E3 38 SEC 06E4 65 0A ADC $0A ;add in number of spaces for format 06E6 38 SEC 06E7 ED A0 07 SBC $07A0 ;substract SYNC encounter value 06EA 10 05 BPL $06F1 ;positive result ? yes, 06EC 49 FF EOR #$FF ;turn negative result ot positive value 06EE 38 SEC 06EF 69 00 ADC #$00 ;add in #$00 06F1 C9 1C CMP #$1C ;interleave between first and last sector greater than #$1C (decimal 28) ? 06F3 90 03 BCC $06F8 ;yes, 06F5 4C 82 06 JMP $0682 ;error detected: interleave space too small ****************************** Check if last track of disk done 06F8 E6 1A INC $1A ;increment track number 06FA 58 CLI ;clear the interrupt 06FB A9 24 LDA #$24 ;set accumulator to maximum tracks per disk 06FD C5 1A CMP $1A ;is track counter equal to #$24 (decimal 36) ? 06FF F0 03 BEQ $0704 ;yes, 0701 4C 2B 05 JMP $052B ;no, 0704 A9 01 LDA #$01 ;set for error: 00, OK, 00, 00 (done!) 0706 A0 FF LDY #$FF 0708 84 1A STY $1A ;store #$FF in format count (no active job) 070A 6C 02 FC JMP ($FC02) ;format finished jump to $FF08 ***************************** Send two OFF bytes, set for normal read mode 070D 20 2E 07 JSR $072E ;send byte in x register to PORT A: 0710 24 4D BIT $4D ;new interrupt ? 0712 10 FC BPL $0710 ;no, 0714 A9 FC LDA #$FC ;set PCR for read (F) & normal (C) 0716 85 4C STA $4C ;set periphal control register (PCR) bit 0 set to 1 ca1:byte ready 1=yes, 0=no bits 1-3 ca2:fill/sync normal : xC fill/sync: xE bit 4 set to 1 cb1:error detected 1=yes, 0=no bits 5-7 cb2:read/write write : Dx read : Fx 0718 A9 92 LDA #$92 ;set for: 1001 0010 071A 85 4E STA $4E ;set interrupt enable register 071C A2 03 LDX #$03 ;set for read of 3 bytes from disk 071E 20 37 07 JSR $0737 ;read byte from disk 0721 24 40 BIT $40 ;clear PORT B status: bit 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off 0723 CA DEX ;all bytes read ? 0724 D0 F8 BNE $071E ;no, 0726 60 RTS ****************************** Set PCR for write mode 0727 A0 10 LDY #$10 ;bit mask: 0001 0000 0729 84 4E STY $4E ;set enable CB1 interrupt 072B 85 4C STA $4C ;set periphal control register bit 0 set to 1 ca1:byte ready 1=yes, 0=no bits 1-3 ca2:fill/sync normal : xC fill/sync: xE bit 4 set to 1 cb1:error detected 1=yes, 0=no bits 5-7 cb2:read/write write : Dx read : Fx 072D 60 RTS ****************************** Send a byte to the disk 072E 24 4D BIT $4D ;new interrupt ? 0730 10 FC BPL $072E ;no, 0732 86 80 STX $80 ;send byte to PORT A: data out 0734 24 41 BIT $41 ;clear PORT A: data input 0736 60 RTS ****************************** Read a byte from the disk 0737 24 4D BIT $4D ;new interrupt ? 0739 10 FC BPL $0737 ;no, 073B A5 41 LDA $41 ;read byte from disk PORT A: data input 073D 60 RTS ****************************** Test if SYNC properly written 073E A0 00 LDY #$00 0740 8C 9F 07 STY $079F ;set byte counter ****************************** Test if SYNC properly written 0743 24 82 BIT $82 ;PORT B status reveals SYNC detected ? bit 0 switch 0 = drive #0 1 = drive #1 1-2 frequency (bit density) 3 write protect 1 = yes 6 sync detect 1 = no, 0 = yes 0745 50 16 BVC $075D ;yes, 0747 24 4D BIT $4D ;TIMER still counting ? 0749 10 F8 BPL $0743 ;yes, 074B 24 41 BIT $41 ;clear PORT`A: data input 074D 24 40 BIT $40 ;clear PORT B status: bit 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off ****************************** Test for SYNC 65536 times 074F C8 INY ;test 256 times 0750 D0 F1 BNE $0743 ;try again ? yes, 0752 EE 9F 07 INC $079F ;test 256 times 0755 D0 03 BNE $075A ;try again ? yes, 0757 4C 82 06 JMP $0682 ;error detected: "BYTE DECODING ERROR", no SYNC 075A 4C 43 07 JMP $0743 ;keep testing for SYNC 075D 8C A0 07 STY $07A0 ;store amount of times needed to find SYNC 0760 24 40 BIT $40 ;clear PORT B status: bit 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off 0762 24 41 BIT $41 ;clear PORT`A: data input 0764 60 RTS ****************************** Calculate checksum for current track, sector 0765 A0 02 LDY #$02 ;set pointer to extract track number 0767 A5 1A LDA $1A ;read current track being done 0769 91 18 STA ($18),Y ;store track number in table: $0423 076B A9 00 LDA #$00 ;set for sector #$00 076D 8D 9C 07 STA $079C ;store sector number 0770 C8 INY ;move up pointer 0771 91 18 STA ($18),Y ;store sector number in table: $0424 0773 51 18 EOR ($18),Y ;calculate checksum for current header block 0775 88 DEY ;all header bytes calculated ? 0776 10 FB BPL $0773 ;no, 0778 8D 9D 07 STA $079D ;read checksum counter 077B A0 04 LDY #$04 ;set pointer to checksum byte location in header table 077D 91 18 STA ($18),Y ;store checksum value in table: $0425 077F 60 RTS ****************************** Write #$00, 8192 times to disk 0780 A2 00 LDX #$00 0782 A0 00 LDY #$00 0784 A9 20 LDA #$20 ;set byte counter to #$20 (decimal 32) 0786 8D 9F 07 STA $079F ;store in byte counter 0789 A9 DC LDA #$DC ;set PCR for write (D) & normal (C): 1101 1100 078B 20 27 07 JSR $0727 ;set IER & PCR for output 078E 20 2E 07 JSR $072E ;write #$00 to disk 0791 88 DEY ;has #$00 been written 256 times 0792 D0 FA BNE $078E ;no, 0794 CE 9F 07 DEC $079F ;#$00 written 8192 times ? 0797 D0 F5 BNE $078E ;no, 0799 60 RTS ****************************** Format code work values 079A 0C ??? ;AND byte for drive 0: 0000 1100 079B 03 ??? ;AND byte for drive 1: 0000 0011 079C 48 ??? ;current sector counter 079D 53 ??? ;temporary storage for checksum value 079E 50 ??? ;remainder of track size 079F AA ??? ;byte counter 07A0 25 ??? ;number of attempts before SYNC encountered
Chapter 9 - FDC disk controller (MOS 6504)
4040 Disk controller RAM usage ZERO page ($0000 - $003F) LOCATION LABEL DESCRIPTION --------------------------------------------------------------------------- $0000 CLOCK Controllers clock $0001 - $0002 MTRTM Motor timer: drive 0/drive 1 (+) when motor fully on $0003 - $0004 DRVST Drive status words bits 0-5 track # bit 6 stepping 0=no 1=yes bit 7 accelerating 0=no 1=yes $0005 - $0006 STEPS Number of steps to new track $0007 COW Used with interrupt $0008 SEEKDIS Closest seek distance $0009 SEEKDIR Closest seek direction $000A DTRCK Number of spaces for format $000B DSECT Number of sectors until desired sector $000C CSECT Closest sector from current position $000D - $0011 STAB Sector header table: (id1,id2,trk,sct,chksm) same format as in HDRS table $0012 DRIVE Current drive # $0013 TRACK Track number for closest seek bits 0-1 part of id bits 2-7 track number $0014 NEXTS Next sector on drive $0015 SECTR Number of sectors/track $0016 - $0017 BUFPT Lo/hi pointer into BUFS table $0018 - $0019 HDRPNT Lo/hi pointer into HDRS table, if $FF then no job $001A FTNUM Format count: $FF = no action $001B - $001C IP (* indirect pointer *) $001D CNT Error count $001E JOB Current job being done $001F JOBNUM Current job id $0020 - $003F Stack for 6504 4040 Controller data read usage MOS 6522 ($0040 - $004F) LOCATION LABEL DESCRIPTION --------------------------------------------------------------------------- $0040 VB Port b bits 0-1 stepper motor drive #1 bits 2-3 stepper motor drive #1 bit 4 motor 1 off bit 5 motor 0 off bit 6-7 unused $0041 DIN Port a: data input $0042 VDDRB Data direction register b $0043 Appears unused by FDC $0044 TILL Timer 1 latch and counter low $0045 TIMER Timer 1 counter high $0046 - $004A Appears unused by FDC $004B ACR Auxiliary control register $004C PCR Peripheral control register bit 0 set to 0 ca1: byte ready 1=yes, 0=no bits 1-3 ca2 : fill/sync normal : xC sync/fill: xE bit 4 set to 1 cb1: error detected 1=yes, 0=no bits 5-7 cb2 : read/write write : Dx read : Fx $004D IFR Int flag register $004E IER Int enable register 4040 Controller data write usage MOS 6530 ($0080 - $008F) LOCATION LABEL DESCRIPTION --------------------------------------------------------------------------- $0080 DOUT Port a: data out $0081 EOUT Direction port a $0082 PB Port b bit 0 switch 0=drive #0 1=drive #1 bits 1-2 frequency (bit density) bit 3 write protect 1=yes bit 6 sync detect 1=no, 0=yes $0083 DDRB Data direction register b $0084 - $008E Appears unused by FDC $008F MITAT Timer/1024
4040 Controller data storage/retrieve usage COMMON RAM (6504: $0400 - $04FF) (6502: $1000 - $10FF) LOCATION LABEL DESCRIPTION --------------------------------------------------------------------------- $0400 TICK Interrupt interval $0401 DELAY Motor acceleration delay $0402 CUTMT Motor cutoff time $0403 - $0411 JOBS Job que bit 7 0=ignore, 1=job present bits 6-4 mode 000:read (8) (0):read data block 001:write (9) (1):write data block 010:verify (A) (2):verify data block written 011:seek (B) (3):seek specific track and sector 100:bump (C) (4):restore placement of head to trk: 1 101:jump (D) (5):jump to buffer code 110:execute(E) (6):start motor then jump $0412 - $0420 Appears unused by FDC $0421 - $0498 HDRS Headers of current blocks: 15*8 -3: sync 2 : track #(bits 7-6 part of id) -2: sync 3 : sector # -1: '08' 4 : checksum 0: id1 5 : off 1: id2 6,7: spare $0499 - $049C TAB1 Number of sectors/track initialized by DOS $049D GAP1 Gap 1 size set by DOS $049E GAP2 Gap 2 size set by DOS: used in format for min. number of bytes $049F VERNUM DOS version number $04A0 ACTJOB Active job number Data on diskette preceded by: sync,sync,'07' Checksum follows 256 data bytes, then 16 spacing bytes $0500 - $13FF BUFS Set of 15: 1-block(256 word) buffers
4040 Disk controller MAP Code from $FC00 - $FE7E LOCATION DESCRIPTION --------------------------------------------------------------------------- $FC09 Word "JOHN", Initialize controller $FC54 START: Test for a valid job $FC65 Test for job type, turn current drive motor on if not $FC80 Test motor speed $FC8A Test head status $FC8D Test next JOBs queue $FC92 Test if head needs transporting $FC99 Initialize JOBS and JOBID by .Y register offset $FCAF Test if head is on right track $FCBC Find closest seek $FCCF Decrement .Y register loop for all jobs $FCD2 Set up seek for closest track $FCEF BYTE used to test motor status: #$F3, #$FC $FCF1 TRACK zone bytes: #$1F, #$19, #$12, #$11 $FCF4 Check if motor to speed, if not, branch to $FCED $FCF8 Set up for track zone $FCFC Check for track zone $FD02 Set number of sectors/track from result of $FCFC $FD20 JOB ROUTINE: execute (mode E:110) $FD2A JOB ROUTINE: bump (mode C:100) $FD3F Decide which sector to service $FD52 Check which job type, check track, drive $FD98 Adjust header pointer: job*8+hi byte of HDRS into HDRPT $FDA5 Calculate job type for selected queue $FDBB Fix sector number for fake seek $FDC4 JOB ROUTINE: read (mode 8:000) $FDCB Get the bytes, store in BUFPT,Y, initialize checksum $FDDD Start reading data: initialize checksum, search for header and start of data $FDF0 JOB ROUTINE: write (mode 9:001) $FDFD Disable CB1 flag, get correct block $FE08 Write sync mode, load fill code $FE17 Reset port A, set 1st sync $FE22 Store normal code in PCR, set 2nd sync, checksum $FE32 Write block, write checksum, change job to verify $FE57 JOB ROUTINE: verify (mode A:010) $FE5A Get byte and compare with contents of buffer, add up checksum $FE6B End reading data, final checksum compare $FE76 Check if "DECODING ERROR" $FE7E Verify error $FE82 Seek to determine next sector number, initialize checksum, get block header $FE8D Get a byte, store in STAB, update checksum $FEA7 Load job number and type, test if seek $FEAF Check if ID in HDRPT,Y = STAB,Y Code from $FE82 - $FFFF LOCATION DESCRIPTION --------------------------------------------------------------------------- $FEBC JOB ROUTINE: seek (mode B:011) $FEBE Get complete header from STAB,Y into (HDRPT),Y $FEC6 Set for error #$01 (00, OK,00,00) $FEC8 Jump to error handling routine $FECB Checksum error $FECF Mismatch error $FED3 Search for a specific block $FED7 Compute checksum, set up search for a sector $FEE4 JSR: head set .Y for compare (all bytes in HDR must be identical) $FEE9 Compare to header loop, loop entire header $FF02 Search for block head: .X = maximum number of trials $FF08 Send job status, make motor stay on longer and check for job type $FF1E Purge stack (#$3F) $FF24 Get a byte, compare to start of header $FF2C Watch for sync character $FF3E Hunt for sync characters: set timer for 20ms limit $FF51 Get a byte $FF58 Send two bytes, set normal read mode $FF62 Change EOUT and PCR to send sync $FF79 Byte to be sent is in .X $FF82 Interrupt for a few milliseconds, set next interrupt, reset timer $FF8E Service motor: check if motor on and stepping flag set $FFA8 Service stepper motor $FFAA Check if on track, if on track: clear stepping tag, check next stepper $FFB7 Check direction, step in or step out $FFC6 Step in (+) $FFCD Step out (-) $FFD5 Store new stepper position, test if DRVST ready $FFE4 Pop the stack of .A and .X then RTI $FFE8 Cycle increment for drives: #$04, #$01 Status word for drives : #$20, #$10 AND bytes for drives : #$0C, #$03 $FFFC .word john: $FC09:initialize $FFFE .word irqh: $FF82:interrupt
4040 Disk controller ROM map ****************************** Main job entry points FC00 54 FC ??? ;start of idle loop FC02 08 FF ??? ;job status entry point ****************************** Begin at new interrupt count FC04 AD 00 04 LDA $0400 ;new interrupt ? FC07 D0 FB BNE $FC04 ;no, ****************************** Word "JOHN", Initialize controller FC09 A2 3F LDX #$3F ;set .X for: 0011 1111 FC0B 9A TXS ;store #$3F in the stack pointer FC0C D8 CLD ;clear decimal mode FC0D 8E 00 04 STX $0400 ;set interrupt interval to: #$3F (dec. 63) FC10 A9 00 LDA #$00 FC12 95 00 STA $00,X ;store #$00 at end of stack FC14 D5 00 CMP $00,X ;is end of stack equal to stored value ? FC16 D0 FE BNE $FC16 ;no, FC18 9D 03 04 STA $0403,X ;store #$00 in HDRS table FC1B CA DEX ;all JOBS & HDRS tables cleared ? FC1C 10 F4 BPL $FC12 ;no, FC1E 86 40 STX $40 ;set PORT B to #$FF: bit 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off FC20 86 42 STX $42 ;set data direction register to: #$FF FC22 8E 02 04 STX $0402 ;set motor cutoff time to: #$FF FC25 86 81 STX $81 ;set direction PORT`A to: #$FF FC27 86 1A STX $1A ;set format count to: #$FF (no action) FC29 A9 07 LDA #$07 ;bit mask: 0000 0111 FC2B 85 83 STA $83 ;set data direction register b to: #$07 FC2D A9 FC LDA #$FC ;set PCR to read (F) & normal (C) FC2F 85 4C STA $4C ;peripheral control register (PCR) bit 0 set to 1 ca1:byte ready 1=yes, 0=no bits 1-3 ca2:fill/sync normal : xC fill/sync: xE bit 4 set to 1 cb1:error detect 1=yes, 0=no bits 5-7 cb2:read/write write : Dx read : Fx FC31 A9 92 LDA #$92 ;set .ACC for: 0101 1100 FC33 85 4E STA $4E ;set interrupt enable register FC35 A9 01 LDA #$01 ;set .ACC for: 0000 0001 FC37 85 4B STA $4B ;set auxiliary control register to: #$00 FC39 4A LSR FC3A 85 44 STA $44 ;set TIMER latch 1 and COUNTER low bytes to: #$00 FC3C 85 16 STA $16 ;set HI buffer pointer to: #$00 FC3E A9 0F LDA #$0F FC40 8D 00 04 STA $0400 ;set INTERRUPT interval to: #$0F (dec. 15) FC43 85 8F STA $8F ;set TIMER to: #$0F (TIMER/1024) = 15.36 ms FC45 A9 80 LDA #$80 ;set .ACC for: 0101 0000 FC47 85 03 STA $03 ;set drive 0 status: bit 0-5 = track 6 = stepping (1=yes) 7 = accel. (1=yes) FC49 85 04 STA $04 ;set drive 1 status: bit 0-5 = track 6 = stepping (1=yes) 7 = accel. (1=yes) FC4B A9 32 LDA #$32 FC4D 8D 04 04 STA $0401 ;set motor acceleration delay to: #$32 (dec. 50) FC50 A9 04 LDA #$04 FC52 85 19 STA $19 ;set HI header pointer to: #$04 ****************************** START: Test for a valid job .Y = job queue number .ACC = job FC54 A0 0E LDY #$0E ;set for #$0E jobs scan (dec. 14) FC56 58 CLI ;clear interrupt FC57 B9 03 04 LDA $0403,Y ;does this queue have a job to do ? FC5A 10 31 BPL $FC8D ;no, FC5C C9 D0 CMP #$D0 ;is the job equal to #$D0 (execute ml user code from data buffer) FC5E D0 05 BNE $FC65 ;no, FC60 84 1F STY $1F ;store which job queue is being processed FC62 4C 20 FD JMP $FD20 ;jump to EXECUTE routine ****************************** Turn current drive motor on if needed FC65 29 01 AND #$01 ;test which drive FC67 AA TAX ;set .X register to indicate selected drive FC68 85 12 STA $12 ;set the current drive number FC6A 78 SEI ;set interrupt FC6B A5 40 LDA $40 ;read PORT B: bit 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off FC6D 3D EA FF AND $FFEA,X ;is motor for selected drive off ? FC70 F0 0E BEQ $FC80 ;no, FC72 A5 40 LDA $40 ;read PORT B: bit 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off FC74 5D EA FF EOR $FFEA,X ;turn on selected drive motor FC77 85 40 STA $40 ;store PORT B: bit 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off FC79 A5 00 LDA #$00 FC7B 6F 01 04 ADC $0401 ;motor acceleration delay: #$32 (dec. 50) FC7E 95 01 STA $01,X ;set motor TIMER of selected drive to:#$32 ****************************** Test motor speed FC80 B5 03 LDA $03,X ;get drive status: bit 0-5 = track 6 = stepping (1=yes) 7 = accel. (1=yes) FC82 30 06 BMI $FC8A ;motor not up to proper speed ? FC84 A5 00 LDA #$00 FC86 95 01 STA $01,X ;set motor TIMER to #$00: turn off motor FC88 B5 03 LDA $03,X ;get drive status: bit 0-5 = track 6 = stepping (1=yes) 7 = accel. (1=yes) ****************************** Test head status FC8A 0A ASL ;head currently stepping ? FC8B 10 05 BPL $FC92 ;no, ****************************** Test next JOBs queue FC8D 88 DEY ;is this the last job queue to test ? FC8E 10 C6 BPL $FC56 ;no, FC90 D0 C2 BNE $FC54 ;no jobs, start over ****************************** Test if head needs transporting FC92 58 CLI ;clear the interrupt FC93 A9 40 LDA #$40 ;initialize to maximum distance+1 (dec. 64) FC95 85 08 STA $08 ;set closest seek distance FC97 A0 0E LDY #$0E ;set for maximum number of jobs ****************************** Initialize JOBS and JOBID by .Y register offset .Y = maximum job number FC99 84 1F STY $1F ;current job number FC9B 20 A5 FD JSR $FDA5 ;is there a job in selected queue ? FC9E 10 2F BPL $FCCF ;no, FCA0 29 01 AND #$01 ;test selected drive bit FCA2 C5 12 CMP $12 ;is this the right drive ? FCA4 D0 29 BNE $FCCF ;no, FCA6 A5 1E LDA $1E ;get current job being done FCA8 C9 40 CMP #$40 ;is job type #$40 (BUMP THE HUB) ? FCAA D0 03 BNE $FCAF ;no, FCAC 4C 2A FD JMP $FD2A ;jump to BUMP routine ****************************** Test if head on right track FCAF B5 03 LDA $03,X ;read drive status: bit 0-5 = track 6 = stepping (1=yes) 7 = accel. (1=yes) FCB1 29 3F AND #$3F ;isolate track number FCB3 85 13 STA $13 ;store track number for closest seek bits 0-1 = part of ID 2-7 = track number FCB5 F0 3D BEQ $FCF4 ;track equal to #$00 ? yes, FCB7 38 SEC FCB8 F1 18 SBC ($18),Y ;has track been reached ? FCBA F0 38 BEQ $FCF4 ;yes, ****************************** Find closest seek FCBC 85 0A STA $0A ;store result from track calculation FCBE 10 05 BPL $FCC5 ;stepping out required ? yes, FCC0 18 CLC FCC1 49 FF EOR #$FF ;calculate distance to track for: IN step FCC3 69 01 ADC #$01 ;add one to result FCC5 C5 08 CMP $08 ;all queues tested for possible use of current track ? FCC7 B0 06 BCS $FCCF ;no, FCC9 85 08 STA $08 ;set closest seek distance FCCB A5 0A LDA $0A ;number of spaces for format FCCD 85 09 STA $09 ;closest seek direction ****************************** Decrement .Y register loop for all jobs FCCF C6 1F DEC $1F ;has job been performed ? FCD1 10 C8 BPL $FC9B ;no, ****************************** Set up seek for closest track FCD2 A5 08 LDA $08 ;get seek distance FCD5 24 09 BIT $09 ;seek direction inwards ? FCD7 30 05 BMI $FCDE ;yes, FCD9 18 CLC FCDA 49 FF EOR #$FF ;calculate distance to track FCDC 69 01 ADC #$01 ;add one to result FCDE 85 08 STA $08 ;store new seek distance FCE0 0A ASL FCE1 78 SEI ;set the interrupt FCE2 95 05 STA $05,X ;store number of steps to new track FCE4 A9 40 LDA #$40 ;set for: 0100 0000 FCE6 15 03 ORA $03,X ;add in drive status: bit 0-5 = track 6 = stepping (1=yes) 7 = accel. (1=yes) FCE8 18 CLC FCE9 65 08 ADC $08 ;add in desired track FCEB 95 03 STA $03,X ;store drive status: bit 0-5 = track 6 = stepping (1=yes) 7 = accel. (1=yes) FCED D0 A1 BNE $FC90 ;another job to do ? yes, ****************************** BYTE used to test motor status FCEF F3 ??? ;motor status drive 0 FCF0 FC ??? ;motor status drive 1 ****************************** TRACK zone bytes FCF1 1F ??? ;track zone: 31-35 FCF2 19 ??? ;track zone: 25-30 FCF3 12 ??? ;track zone: 18-24 ****************************** Check if motor to speed, if not, branch to $FCED FCF4 B5 03 LDA $03,X ;get drive status: bit 0-5 = track 6 = stepping (1=yes) 7 = accel. (1=yes) FCF6 30 F5 BMI $FCED ;motor up to speed ? no, ****************************** Set up for track zone FCF8 A2 04 LDX #$04 ;set for minimum track zone FCFA B1 18 LDA ($18),Y ;read track number from HDRS table ****************************** Check for track zone FCFC DD EF FC CMP $FCEF,X ;is track part of this track zone ? FCFF CA DEX ;all track zones tested ? FD00 B0 FA BCS $FCFC ;no, ****************************** Set number of sectors per track and density from result of $FCFC FD02 BD 99 04 LDA $0499,X ;read sectors per track table FD05 85 15 STA $15 ;set as number of sectors per track FD07 8A TXA FD08 0A ASL ;multiply byt two FD09 85 08 STA $08 ;set as closest seek distance FD0B A5 82 LDA $82 ;read PORT B status: bit 0 switch 0 = drive #0 1 = drive #1 1-2 frequency (bit density) 3 write protect 1 = no 6 sync detect 1 = no, 0 = yes FD0D 29 F8 AND #$F8 ;bit mask: 1111 1000 FD0F 05 08 ORA $08 ;calculate track density for zone FD11 05 08 ORA $12 ;add in drive number FD13 85 82 STA $82 ;set PORT`B status: bit 0 switch 0 = drive #0 1 = drive #1 1-2 frequency (bit density) 3 write protect 1 = no 6 sync detect 1 = no, 0 = yes FD15 A6 12 LDX $12 ;get current drive number FD17 A5 1E LDA $1E ;get current job being done FD19 C9 60 CMP #$60 ;is job type #$60 (EXECUTE ML CODE WITH MOTOR ON) ? FD1B F0 03 BEQ $FD20 ;yes, FD1D 4C 82 FE JMP $FE82 ;no, ****************************** JOB ROUTINE: mode=110 (E)=execute (6)=start motor then jump FD20 A5 1F LDA $1F ;get current job number FD22 18 CLC FD23 69 05 ADC #$05 ;add in buffer index FD25 85 17 STA $17 ;set HI pointer to USER assigned ML CODE area FD27 6C 16 00 JMP ($0016) ;jump to user assigned buffer code ****************************** JOB ROUTINE: mode=100 (C)=bump (4)=restore placement of head to track #$01 FD2A 78 SEI ;set the interrupt FD2B A9 C1 LDA #$C1 ;bit mask: 1100 0001 FD2D 95 03 STA $03,X ;set drive status: bit 0-5 = track 6 = stepping (1=yes) 7 = accel. (1=yes) FD2F A9 0F LDA #$0F FD31 3D EC FF AND $FFEC,X ;AND with #$0C if drv 0, #$03 if drv 1 FD34 05 40 ORA $40 ;add in PORT B status bit 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off FD36 85 40 STA $40 ;store new PORT B status bit 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off FD38 A9 8C LDA #$8C ;amount to step motor: -70 (2*35 tracks outward) FD3A 95 05 STA $05,X ;set number of steps to new track FD3C 4C C6 FE JMP $FEC6 ;jump to job completed routine ****************************** Decide which sector to service FD3F A9 7F LDA #$7F FD41 85 0C STA $0C ;set current sector number to #$7F (decimal 127) FD43 A5 10 LDA $10 ;read sector number from header table FD45 18 CLC FD46 69 02 ADC #$02 ;add two to current sector count FD48 C5 15 CMP $15 ;number of sectors greater than amount allowed for this track ? FD4A 90 02 BCC $FD4E ;no, FD4C A9 00 LDA #$00 FD4E 85 14 STA $14 ;store desired sector number FD50 A2 0E LDX #$0E ;set .X for scanning all job queues ****************************** Check which job type, check track, drive FD52 86 1F STX $1F ;set for last job queue FD54 A2 FF LDX #$FF FD56 20 A5 FD JSR $FDA5 ;is there a job to do ? FD59 10 33 BPL $FD8E ;no, FD5B 85 08 STA $08 ;store job code in temporary location FD5D B1 18 LDA ($18),Y ;is head on desired track ? FD5F C5 13 CMP $13 ;correct track number ? bit 0-1 = part of id 2-7 = track number FD61 D0 2B BNE $FD8E ;no, FD63 A5 08 LDA $08 ;load up job to perform FD65 29 01 AND #$01 ;isolate drive number FD67 C5 12 CMP $12 ;is this the correct drive ? FD69 D0 23 BNE $FD8E ;no, FD6B 98 TYA FD6C C9 60 CMP #$60 ;is job type #$60 (EXECUTE ML CODE WITH MOTOR ON) ? FD6E F0 1E BEQ $FD8E ;yes, FD70 C8 INY FD71 38 SEC FD72 B1 18 LDA ($18),Y ;get desired sector number FD74 E5 14 SBC $14 ;result of sector substraction positive ? FD76 10 03 BPL $FD7B ;yes, (sector is coming up) FD78 18 CLC FD79 65 15 ADC $15 ;add value of next sector back in FD7B 85 0B STA $0B ;store result as number of sectors until desired sector FD7D 38 SEC FD7E E5 0C SBC $0C ;distance to other sector request closer ? FD80 10 0C BPL $FD8E ;yes, FD82 A6 1F LDX $1F ;read current job number FD84 A5 0B LDA $0B ;get amount of sectors before requested sector FD86 85 0C STA $0C ;set as closest sector from current position FD88 8A TXA FD89 18 CLC FD8A 69 05 ADC #$05 ;add in buffer index FD8C 85 17 STA $17 ;set as HI pointer into BUFS table FD8E C6 1F DEC $1F ;all jobs in queue finished ? FD90 10 C4 BPL $FD56 ;yes, FD92 8A TXA ;any jobs to do found ? FD93 10 03 BPL $FD98 ;yes, FD95 4C 54 FC JMP $FC54 ;jump to START ****************************** Adjust header pointer: job*8+hi byte of HDRS into HDRPNT FD98 8E A0 04 STX $04A0 ;store active job number FD9B 86 1F STX $1F ;store as current job number FD9D 20 A5 FD JSR $FDA5 ;calculate job type and index pointers FDA0 A5 1E LDA $1E ;get current job being done FDA2 4C C4 FD JMP $FDC4 ;jump to READ BLOCK routine ****************************** Calculate job type for selected queue and set buffer pointers .Y = byte position in buffer .ACC = job number FDA5 A4 1F LDY $1F ;get current job number FDA7 B9 03 04 LDA $0403,Y ;read job queue status: bit 7 job : 0=ignore, 1=job present bits 6-4 mode: 000: read (8) (0): read data block 001: write (9) (1): write data block 010: verify (A) (2): verify data block written 011: seek (B) (3): seek specific track & sector 100: bump (C) (4): restore placement of head: trk 1 101: jump (D) (5): jump to buffer code 110: execute (E) (6): start motor then jump bit 0 drive: 0=#B, 1=#A FDAA 48 PHA ;preserve job FDAB 29 70 AND #$70 ;clear bits: 6, 5, 4 FDAD 85 1E STA $1E ;save calculated command code FDAF 98 TYA FDB0 0A ASL ;multiply job number by two FDB1 0A ASL ;multiply new result by two FDB2 0A ASL ;multiply new result by two FDB3 69 21 ADC #$21 ;add in buffer index FDB5 85 18 STA $18 ;set as LO pointer into HDRS table: #$FF=no job FDB7 A0 02 LDY #$02 ;set pointer to byte position #$02 FDB9 68 PLA ;retrieve job number FDBA 60 RTS ****************************** Fix sector number for fake seek FDBB A0 03 LDY #$03 ;set pointer for extraction of sector number FDBD B1 18 STA ($18),Y ;get sector number from HDRS table FDBF 85 10 STA $10 ;store value in sector header table FDC1 4C 3F FD JMP $FD3F ;jump to DECIDE SECTOR TO SERVICE routine ****************************** JOB ROUTINE: mode=000 (8)=read (0)=read data block FDC4 C9 00 CMP #$00 ;is job type #$00 (READ DATA BLOCK) ? FDC6 D0 28 BNE $FDF0 ;no, FDC8 20 DD FD JSR $FDDD ;jump to START READING DATA routine ****************************** Get the bytes, store in BUFPT,Y, initialize checksum FDCB 24 4D BIT $4D ;new interrupt ? FDCD 10 FC BPL $FDCB ;no, FDCF A5 41 LDA $41 ;read PORT A: data input FDD1 91 16 STA ($16),Y ;store into assigned buffer FDD3 45 08 EOR $08 ;calculate new checksum FDD5 85 08 STA $08 ;store new checksum result FDD7 C8 INY ;all bytes read ? FDD8 D0 F1 BNE $FDCB ;no, FDDA 4C 6B FE JMP $FE6B ;jump to END READING DATA routine ****************************** Start reading data: initialize checksum, search for header and start of data FDDD A0 00 LDY #$00 FDDF A0 00 STY $08 ;set checksum value to #$00 FDE1 20 D3 FE JSR $FED3 ;find desired sector FDE4 20 3E FF JSR $FF3E ;get DATA BLOCK identifier: '07' FDE7 C9 07 CMP #$07 ;is this the beginning of the DATA BLOCK ? FDE9 F0 04 BEQ $FDEF ;yes, FDEB A9 04 LDA #$04 ;set for "DATA BLOCK NOT PRESENT" error FDED D0 0B BNE $FDFA ;abort job, FDEF 60 RTS ****************************** JOB ROUTINE: mode=001 (9)=write (1)=write data block FDF0 C9 20 CMP #$20 ;is job type #$20 (VERIFY DATA BLOCK WRITTEN) ? FDF2 10 63 BPL $FE57 ;yes, FDF4 A5 82 LDA $82 ;read PORT B status: bit 0 switch 0 = drive #0 1 = drive #1 1-2 frequency (bit density) 3 write protect 1 = yes 6 sync detect 1 = no, 0 = yes FDF6 29 08 AND #$08 ;"WRITE PROTECT ON" error ? FDF8 F0 03 BEQ $FDFD ;no, FDFA 4C 08 FF JMP $FF08 ;abort job, ****************************** Disable CB1 flag, get correct block FDFD A9 10 LDA #$10 ;set for: 0001 0000 FDFF 85 4E STA $4E ;set interrupt enable register FE01 20 D3 FE JSR $FED3 ;skip SYNC and find proper HEADER BLOCK FE04 AE 9D 04 LDX $049D ;read GAP1 size set by dos: #$09 FE07 CA DEX ;set GAP1 size to: #$08 ****************************** Write SYNC mode, load fill code FE08 24 4D BIT $4D ;new interrupt ? FE0A 10 FC BPL $FE08 ;no, FE0C 24 41 BIT $41 ;read GAP1 bytes FE0E CA DEX ;last GAP1 byte ? FE0F D0 F7 BNE $FE08 ;no, FE11 A9 DE LDA #$DE ;set PCR to write (D) & fill/sync (E) FE13 85 4C STA $4C ;peripheral control register (PCR) bit 0 set to 1 ca1:byte ready 1=yes, 0=no bit 1-3 ca2:fill/sync normal : xC fill/sync: xE bit 4 set to 1 cb1:error detect 1=yes, 0=no bits 5-7 cb2:read/write write : Dx read : Fx FE15 A9 DC LDA #$DC ;set PCR for write (D) & normal (C) ****************************** Reset PORT a, set 1st SYNC FE17 A2 FF LDX #$FF FE19 20 79 FF JSR $FF79 ;send byte FE1C 20 79 FF JSR $FF79 ;send byte FE1F 20 79 FF JSR $FF79 ;send byte ****************************** Store normal code mode in PCR, set 2nd SYNC, checksum FE22 24 4D BIT $4D ;new interrupt ? FE24 10 FC BPL $FE22 ;no, FE26 24 41 BIT $41 ;read PORT a: data input FE28 85 4C STA $4C ;peripheral control register (PCR) bit 0 set to 1 ca1:byte ready 1=yes, 0=no bit 1-3 ca2:fill/sync normal : xC fill/sync: xE bit 4 set to 1 cb1:error detect 1=yes, 0=no bits 5-7 cb2:read/write write : Dx read : Fx FE2A A9 07 LDA #$07 ;data block identifier: '07' FE2C 85 80 STA $80 ;send to PORT a: data out FE2E A0 00 LDY #$00 FE30 84 08 STY $08 ;set checksum value to: #$00 ****************************** Write block, write checksum, change job to verify FE32 24 4D BIT $4D ;new interrupt ? FE34 10 FC BPL $FE32 ;no, FE36 24 41 BIT $41 ;reset PORT A: data input FE38 B1 16 LDA ($16),Y ;load DATA byte to send to disk FE3A 85 80 STA $80 ;write assigned byte to disk FE3C 45 08 EOR $08 ;calculate new checksum FE3E 85 08 STA $08 ;store new checksum total FE40 C8 INY ;is this the 256th byte ? FE41 D0 EF BNE $FE32 ;no, FE43 AA TAX ;load up checksum FE44 20 79 FF JSR $FF79 ;send byte FE47 20 58 FF JSR $FF58 ;write two OFF bytes FE4A A4 1F LDY $1F ;get current job number FE4C B9 03 04 LDA $0403,Y ;get current job in queue: bit 7 job : 0=ignore, 1=job present bits 6-4 mode: 000: read (8) (0): read data block 001: write (9) (1): write data block 010: verify (A) (2): verify data block written 011: seek (B) (3): seek specific track & sector 100: bump (C) (4): restore placement of head: trk 1 101: jump (D) (5): jump to buffer code 110: execute (E) (6): start motor then jump bit 0 drive: 0=#B, 1=#A FE4F 49 30 EOR #$30 ;set for: 0001 1110 FE51 99 03 04 STA $0403,Y ;store job code back in current queue: bit 7 job : 0=ignore, 1=job present bits 6-4 mode: 000: read (8) (0): read data block 001: write (9) (1): write data block 010: verify (A) (2): verify data block written 011: seek (B) (3): seek specific track & sector 100: bump (C) (4): restore placement of head: trk 1 101: jump (D) (5): jump to buffer code 110: execute (E) (6): start motor then jump bit 0 drive: 0=#B, 1=#A FE54 4C BB FD JMP $FDBB ;jump to FIX SECTOR FAKE SEEK routine ****************************** JOB ROUTINE: mode=010 (A)=verify (2)=verify data block written FE57 20 DD FD JSR $FDDD ;read header block and set beginning data block ****************************** Get byte and compare with contents of buffer, add up checksum FE5A 24 4D BIT $4D ;new interrupt ? FE5C 10 FC BPL $FE5A ;no, FE5E A5 41 LDA $41 ;read byte from PORT A: data input FE60 D1 16 CMP ($16),Y ;has byte been correctly written ? FE62 D0 1A BNE $FE7E ;no, FE64 45 08 EOR $08 ;calculate checksum FE66 85 08 STA $08 ;store new checksum value FE68 C8 INY ;is this the 256th byte ? FE69 D0 EF BNE $FE5A ;no, ****************************** End reading data, final checksum compare FE6B 20 51 FF JSR $FF51 ;get checksum byte FE6E C5 08 CMP $08 ;does checksum match recorded checksum ? FE70 F0 04 BEQ $FE76 ;yes, FE72 A9 05 LDA #$05 ;set for "CHECKSUM ERROR IN DATA BLOCK" error FE74 D0 0A BNE $FE80 ;abort job, ****************************** Check if decoding error FE76 A9 10 LDA #$10 ;set for "BYTE DECODING ERROR" error FE78 24 4D BIT $4D ;has DECODING ERROR occurred ? FE7A F0 4A BEQ $FEC6 ;no, FE7C D0 02 BNE $FE80 ;abort job, ****************************** Verify error FE7E A9 07 LDA #$07 ;set for "VERIFY ERROR" error FE80 D0 46 BNE $FEC8 ;abort job, ****************************** Seek to determine next sector number, initialize checksum, get block header FE82 A9 00 LDA #$00 FE84 85 08 STA $08 ;set checksum value to: #$00 FE86 A2 06 LDX #$06 ;set attempts to read HEADER BLOCK to: 6 FE88 20 02 FF JSR $FF02 ;get HEADER BLOCK FE8B A0 04 LDY #$04 ;set HEADER BLOCK storage pointer ****************************** Get a byte, store in STAB, update checksum FE8D 24 4D BIT $4D ;new interrupt ? FE8F 10 FC BPL $FE8D ;no, FE91 A5 41 LDA $41 ;read byte from PORT A: data input FE93 99 0D 00 STA $000D,Y ;store byte HDR table FE96 45 08 EOR $08 ;calculate checksum FE98 85 08 STA $08 ;store new checksum value FE9A 88 DEY ;all bytes read ? FE9B 10 F0 BPL $FE8D ;no, FE9D C9 00 CMP #$00 ;do header checksums match ? FE9F D0 2A BNE $FECB ;no, FEA1 A5 0F LDA $0F ;get track number FEA3 A6 12 LDX $12 ;get current drive number FEA5 95 03 STX $03,X ;set drive status: bit 0-5 = track 6 = stepping (1=yes) 5 = accel. (1=yes) ****************************** Load job number and type, test if seek FEA7 A5 1E LDA $1E ;get current job being done FEA9 C9 30 CMP #$30 ;is job type #$30 (SEEK SPECIFIC TRACK & SECTOR) ? FEAB F0 0F BEQ $FEBC ;yes, FEAD A0 01 LDY #$01 ;set for checking of ID2, ID1 ****************************** Check if ID in HDRPT,Y = STAB,Y FEAF B1 18 LDA ($18),Y ;get ID from buffer containing master ID's FEB1 D9 0D 00 CMP $000D,Y ;does ID match master ID ? FEB4 D0 19 BNE $FECF ;no, FEB6 88 DEY ;set for ID2 FEB7 10 F6 BPL $FEAF ;do next ID FEB9 4C 3F FD JMP $FD3F ;jump to DECIDE SECTOR TO SERVICE routine ****************************** JOB ROUTINE: mode=011 (B)=seek (3)=seek specific track & sector FEBC A0 04 LDY #$04 ;set up for transfer of HEADER BLOCK ****************************** Get complete header from STAB,Y into (HDRPT),Y FEBE B9 0D 00 LDA $000D,Y ;read byte from header FEC1 91 18 STA ($18),Y ;store in assigned header buffer FEC3 88 DEY ;all bytes transferred ? FEC4 10 F8 BPL $FEBE ;no, ****************************** Set for error #$01 (00, OK,00,00) FEC6 A9 01 LDA #$01 ;set for "00, OK,00,00" error ****************************** Jump to error handling routine FEC8 4C 08 FF JMP $FF08 ;jump to SEND JOB STATUS routine ****************************** Checksum error FECB A9 09 LDA #$09 ;set for "CHECKSUM ERROR IN SEEKED HEADER" FECD D0 FA BNE $FEC8 ;abort job, ****************************** Mismatch error FECF A9 0B LDA #$0B ;set for "DISK ID MISMATCH" error FED1 D0 F5 BNE $FEC8 ;abort job, ****************************** Search for a specific block FED3 A0 03 LDY #$03 ;set for calculation of ID1, ID2, TRK, SCT FED5 A9 00 LDA #$00 ;set checksum value to #$00 ****************************** Compute checksum, set up search for a sector FED7 51 18 EOR ($18),Y ;calculate checksum of HEADER BLOCK FED9 88 DEY ;another header byte to calculate ? FEDA 10 FB BPL $FED7 ;yes, FEDC A0 04 LDY #$04 ;set buffer pointer to checksum byte location FEDE 91 18 STA ($18),Y ;store result of checksum in buffer FEE0 A4 1F LDY $1F ;get current job number FEE2 A2 5A LDX #$5A ;set attempts to read HEADER BLOCK to: 90 ****************************** JSR: head set .Y for compare (all bytes in HDR must be identical) FEE4 20 02 FF JSR $FF02 ;locate HEADER BLOCK for sector FFE7 A0 04 LDY #$04 ;set for end of HEADER BLOCK ****************************** Compare to header loop, loop entire header FEE9 24 4D BIT $4D ;new interrupt ? FEEB 10 FC BPL $FEE9 ;no, FEED A5 41 LDA $41 ;read HEADER BLOCK checksum FEEF D1 18 CMP ($18),Y ;is this the correct sector ? FEF1 D0 F1 BNE $FEE4 ;no, FEF3 88 DEY ;all bytes for HEADER BLOCK read ? FEF4 10 F3 BPL $FEE9 ;no, FEF6 C8 INY ;move pointer back up FEF7 A5 40 LDA $40 ;read PORT B status: 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off FEF9 09 80 ORA #$80 ;set motor as still: 1000 0000 FEFB 85 40 STA $40 ;set new PORT B status: 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off FEFD 29 7F AND #$7F ;turn off motor: 0111 1111 FEFF 85 40 STA $40 ;set new PORT B status: 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off FF01 60 RTS ****************************** Search for block head .X = maximum number of trials FF02 58 CLI ;clear the interrupt FF03 CA DEX ;attempts to find HEADER BLOCK expired ? FF04 10 1E BPL $FF24 ;no, FF06 A9 02 LDA #$02 ;set for "CAN'T FIND HEADER BLOCK" error ****************************** Send job status, make motor stay on longer and check job type FF08 A4 1F LDY $1F ;read current job number FF0A 99 03 04 STA $0403,Y ;store result of job in same queue: bit 7 job : 0=ignore, 1=job present bits 6-4 mode: 000: read (9) (0): read data block 001: write (8) (1): write data block 010: verify (A) (2): verify data block written 011: seek (B) (3): seek specific track & sector 100: bump (C) (4): restore placement of head: trk 1 101: jump (D) (5): jump to buffer code 110: execute (E) (6): start motor then jump bit 0 drive: 0=#B, 1=#A FF0D 48 PHA FF0E A6 12 LDX $12 ;set for current drive FF10 A5 00 LDA $00 ;set .ACC to current clock time FF12 6F 02 04 ADC $0402 ;add .ACC to motor cutoff time FF15 95 01 STA $01,X ;set deceleration time FF17 68 PLA FF18 4A LSR ;has drive stopped spinning ? FF19 D0 03 BNE $FF1E ;yes, FF1B 4C BB FD JMP $FDBB ;jump to FIX SECTOR FAKE SEEK routine ****************************** Purge stack (#$3F) FF1E A2 3F LDX #$3F ;set .X for: 0011 1111 FF20 9A TXS ;set stack pointer and go into "IDLE LOOP" mode FF21 4C 54 FC JMP $FC54 ;jump to START ****************************** Get a byte, compare to start of header FF24 20 3E FF JSR $FF3E ;get HEADER BLOCK identifier: '08' FF27 C9 08 CMP #$08 ;is this the beginning of the HEADER BLOCK ? FF29 D0 D7 BNE $FF02 ;no, FF2B 60 RTS ****************************** Watch for sync character FF2C 24 82 BIT $82 ;PORT B status reveals SYNC detected ? bit 0 switch 0 = drive #0 1 = drive #1 1-2 frequency (bit density) 3 write protect 1 = yes 6 sync detect 1 = no, 0 = yes FF2E 50 0D BVC $FF3D ;no, FF30 24 4D BIT $4D ;is there a sync ? FF32 10 F8 BPL $FF2C ;yes, FF34 24 41 BIT $41 ;clear PORT A: data input FF36 24 40 BIT $40 ;clear PORT B: bit 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off FF38 CA DEX ;amount of attempts to test up ? FF39 D0 F1 BNE $FF2C ;no, FF3B 24 82 BIT $82 ;clear PORT B: bit 0 switch 0 = drive #0 1 = drive #1 1-2 frequency (bit density) 3 write protect 1 = yes 6 sync detect 1 = no, 0 = yes FF3D 60 RTS ****************************** Hunt for sync characters: set timer for 20ms limit FF3E 78 SEI ;set the interrupt FF3F A9 D0 LDA #$D0 ;set TIMER to #$D0 (decimal 208) FF41 85 45 STA $45 ;TIMER 1 counter high FF43 A9 03 LDA #$03 ;set for "NO SYNC CHARACTER" error FF45 24 45 BIT $45 ;is TIMER up ? FF47 10 BF BPL $FF08 ;yes, FF49 24 82 BIT $82 ;PORT B status reveals SYNC detected ? bit 0 switch 0 = drive #0 1 = drive #1 1-2 frequency (bit density) 3 write protect 1 = yes 6 sync detect 1 = no, 0 = yes FF4B 70 F8 BVS $FF45 ;no, FF4D 24 40 BIT $40 ;clear PORT B status 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off FF4F 24 41 BIT $41 ;clear interrupt flag register ****************************** Get a byte FF51 24 4D BIT $4D ;new interrupt ? FF53 10 FC BPL $FF51 ;no, FF55 85 41 LDA $41 ;get a byte from PORT A: data input FF57 60 RTS ****************************** Send two bytes, set normal read mode FF58 20 79 FF JSR $FF79 ;send byte FF5B A2 00 LDX #$00 ;set byte to send: #$00 FF5D 20 79 FF JSR $FF79 ;send byte FF60 A9 FC LDA #$FC ;set PCR for read (F) & normal (C) ****************************** Change EOUT and PCR to send SYNC FF62 24 4D BIT $4D ;new interrupt FF64 10 FC BPL $FF62 ;no, FF66 85 4C STA $4C ;peripheral control register (PCR) bit 0 set to 1 ca1:byte ready 1=yes, 0=no bit 1-3 ca2:fill/sync normal : xC fill/sync: xE bit 4 set to 1 cb1:error detect 1=yes, 0=no bit 5-7 cb2:read/write write : Dx read : Fx FF68 A9 92 LDA #$92 ;set for: 1001 0010 FF6A 85 4E STA $4E ;set interrupt enable register FF6C 20 51 FF JSR $FF51 ;get a byte FF6F 24 40 BIT $40 ;clear PORT B status: bit 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off FF71 20 51 FF JSR $FF51 ;get a byte FF74 24 40 BIT $40 ;clear PORT B status: bit 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off FF76 4C 51 FF JMP $FF51 ;jump to GET A BYTE routine ****************************** Byte to be sent is in .X FF79 24 4D BIT $4D ;new interrupt ? FF7B 10 FC BPL $FF79 ;no, FF7C 86 80 STX $80 ;send byte to PORT A: data out FF7F 24 41 BIT $41 ;reset port for new byte FF81 60 RTS ****************************** Interrupt for a few milliseconds, set next interrupt, reset timer FF82 48 PHA ;preserve content of .ACC FF83 8A TXA FF84 48 PHA ;preserve content of .X FF85 AD 00 04 LDA $0400 ;read interrupt interval FF88 85 8F STA $8F ;reset TIMER FF8A E6 00 INC $00 ;increment controller clock FF8C A2 01 LDX #$01 ;set for drive 1 ****************************** Service motor: check if motor on and stepping flag set FF8E A5 00 LDA $00 ;read controller clock FF90 D5 01 CMP $01,X ;motor TIMER on (running) ? FF92 D0 16 BNE $FFAA ;yes, FF94 BD EA FF LDA $FFEA,X ;get status word for corresponding drive FF97 16 03 ASL $03,X ;calculate new drive status bit 0-5 = track 6 = stepping (1=yes) 7 = accel. (1=yes) FF99 24 40 BIT $40 ;test PORT B: bit 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off FF9B B0 08 BCS $FFA5 ;stepping flag set ? yes, FF9D 38 SEC FF9E BD EA FF LDA $FFEA,X ;get status word for corresponding drive FFA1 45 40 EOR $40 ;calculate PORT B status: bit 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off FFA3 85 40 STA $40 ;set new PORT B status: bit 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off FFA5 D0 01 BNE $FFA8 ;stepping job completed ? no, FFA7 18 CLC ****************************** Service stepper motor FFA8 76 06 ROR $03,X ;perform drive step: bit 0-5 = track 6 = stepping 7 = accel. ****************************** Check if on track, if on track: clear stepping tag, check next stepper FFAA B5 05 LDA $05,X ;is number of steps to new track equal to zero ? FFAC D0 09 BNE $FFB7 ;no, FFAE 85 03 LDA $03,X ;get drive status: bit 0-5 = track 6 = stepping 7 = accel. FFB0 29 BF AND #$BF ;set for: 1011 1111 (clear bit 6) FFB2 95 03 STA $03,X ;set new drive status: bit 0-5 = track 6 = stepping 7 = accel. FFB4 4C E1 FF JMP $FFE1 ;jump to STEPPER POSITION routine ****************************** Check direction, step in or step out FFB7 0A ASL ;multiply by two FFB8 A5 40 LDA $40 ;read PORT B: bit 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off FFBA 3D EF FC AND $FCEF,X ;isolate cycle bits for assigned drive FFBD 85 07 STA $07 ;set result as new interrupt time FFBF A5 40 LDA $40 ;read PORT B status: bit 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off FFC1 3D EC FF AND $FFEC,X ;head stepping inwards ? FFC4 B0 07 BCS $FFCD ;no, ****************************** Step in (+) FFC6 D6 05 DEC $05,X ;decrement number of steps to new track FFC8 7D E8 FF ADC $FFE8,X ;full cycle completed ? FFCB D0 05 BNE $FFD2 ;no, ****************************** Step out (-) FFCD F6 05 INC $05,X ;increment number of steps to new track FFCF FD E8 FF SBC $FFE8,X ;read service cycle FFD2 3D EC FF AND $FFEC ;cycle stepper ****************************** Store new stepper position, test if DRVST ready FFD5 05 07 ORA $07 ;calculate new PORT B by use of interrupt result FFD7 85 40 STA $40 ;set PORT B: bit 0-1 = stepper motor drv 1 2-3 = stepper motor drv 0 4 = motor 1 off 5 = motor 0 off FFD9 85 03 LDA $03,X ;get drive status: bit 0-5 = track 6 = stepping 7 = accel. FFDB 30 04 BMI $FFE1 ;accelerating ? no, FFDD A5 00 LDA $00 ;read controller clock FFDF 95 01 STA $01,X ;set motor TIMER FFE1 CA DEX ;time up ? FFE2 10 AA BPL $FF8E ;no, ****************************** Pop the STACK of .A and .X then RTI FFE4 68 PLA ;retrieve .X FFE5 AA TAX FFE6 68 PLA ;retrieve .ACC FFE7 40 RTI ****************************** Stepper control bytes FFE8 04 ??? ;cycle increment drive 0: (0000 0100) FFE9 01 ??? ;cycle increment drive 1: (0000 0001) FFEA 20 ??? ;status word drive 0 : (0010 0000) FFEB 10 ??? ;status word drive 1 : (0001 0000) FFEC 0C ??? ;cycle byte for drive 0 : (0000 1100) FFED 03 ??? ;cycle byte for drive 1 : (0000 0011) FFEE AA ??? FFEF AA ??? FFF0 AA ??? FFF1 AA ??? FFF2 AA ??? FFF3 AA ??? FFF4 AA ??? FFF5 AA ??? FFF6 AA ??? FFF7 AA ??? FFF8 AA ??? FFF9 AA ??? FFFA AA ??? FFFB 18 ??? ****************************** .Word john: $FC09: initialize FFFC 09 FC ??? ****************************** .Word irqh: $FF82: interrupt FFFE 82 FF ???
APPENDIX A - Miscellaneous programs
A.1 - How to type in programs There is a description underneath each program so as to explain what this particular utility will do. The memory addresses used within the drive are listed as well as any machine code instructions which may be required to perform the routines listed within the programs. Before typing in the programs, make sure to have set your computer in LOWER CASE. Below, is a list of notations which represent special key sequences which need to be pressed on your keyboard. Notation Description Sequence {clr/home} Clear screen Press SHIFT + CLR/HOME {home} Home cursor Press HOME {lft} Cursor left Press SHIFT + CRSR LEFT/RIGHT {rgt} Cursor right Press CRSR LEFT/RIGHT {up} Cursor up Press SHIFT + CRSR UP/DOWN {dwn} Cursor down Press CRSR UP/DOWN
4040 ANTI-CHATTER 10 open 15,8,15 20 print#15,"m-w";chr$(92)chr$(67)chr$(1)chr$(138) 30 close 15 Description: This routine disables the chatter operation in the 4040. Note : Location $435C MUST contain the value of $8A. Other values do not properly set the "TIME OUT" on the error recovery. The drive will not "BUMP the hub" on errors encountered. Drive memory addresses and/or machine code routines: $435C = Error recovery count
4040 SOFT DEVICE CHANGE 10 print "{clr/home}" 20 input "new device number *{lft}{lft}{lft}";dn 30 open 15,8,15 40 print#15,"m-w"chr$(12)chr$(0)chr$(2)chr$(dn+32)chr$(dn+64) 50 close 15 Description: This routine changes the current device number to any other device number (range 8-15). Note : If unit is turned off and on again, the device number is reset to it's original number. Drive memory addresses and/or machine code routines: $000C = Listen address $000D = Talker address
4040 GET CURRENT DISK ID'S 10 open 15,8,15 20 print#15,"m-r"chr$(64)chr$(67)chr$(4) 30 for x=1 to 4 40 get#15,x$(x) 50 x(x)=asc(x$(x)+chr$(0)) 60 next x 70 close 15 80 id$(0)=chr$(x(1))+chr$(x(2)) 90 id$(1)=chr$(x(3))+chr$(x(4)) 100 print "{clr/home}" 110 print "disk id for drive 0: "id$(0) 120 print "disk id for drive 1: "id$(1) Description: This routine returns the current DISK DRIVE id's for the 4040 drive 0 and drive 1. Note : The id's returned are those which are found in the disk's track 18, sector 0. No id is returned if drive has not been previously initialized. Drive memory addresses and/or machine code routines: $4340 - $4341 = Current disk id (drive 0) $4342 - $4343 = Current disk id (drive 1)
4040 FLASH LED'S 10 print "{clr/home}" 20 open 15,8,15 30 for y=1 to 20 40 read v 50 y$=y$+chr$(v) 60 next y 70 data 0, 0,173, 1, 17,172, 0, 17,162,255,141,130, 2,202,208,250,136 80 data 208,247, 96 90 print#15,"m-w"chr$(0)chr$(17)chr$(20)y$ 100 print"{home}{dwn}{dwn}flash which led (<0>/<1>/<e>rror) 110 get le$:if le$="0" then le=16:goto 120 120 if le$="1" then le=8:goto 120 130 if le$<>"e" then 80 140 le=32 150 print#15,"m-w"chr$(0)chr$(17)chr$(2)chr$(64)chr$(le) 160 for x=1 to 10 170 print#15,"m-w"chr$(0)chr$(17)chr$(2)chr$(64)chr$(le) 180 print#15,"m-e"chr$(2)chr$(17) 190 print#15,"m-w"chr$(0)chr$(17)chr$(2)chr$(128)chr$(0) 200 print#15,"m-e"chr$(0)chr$(17) 210 next x 220 close 15 Description: This routine will flash SELECTED led on the 4040 unit. Note : Selected led will flash 10 times. User code assembly required. User code resides in BUFFER #0. Drive memory addresses and/or machine code routines: $0282 = PBD2 $1100 00 ??? $1101 00 ??? $1102 AD 01 11 LDA $1101 $1105 AC 00 11 LDY $1100 $1108 A2 FF LDX #$FF $110A 8D 82 02 STA $0282 $110D CA DEX $110E D0 FA BNE $110A $1110 88 DEY $1111 D0 F7 BNE $110A $1113 60 RTS
4040 HEAD MOVE 10 print "{clr/home}":se$=" " 20 input"enter drive *{lft}{lft}{lft}";d 30 if d=0 then d$="0":dr=12:df=243:ad=4:goto 50 40 d$="1":dr=3:df=252:ad=1 50 open 15,8,15,"i"+d$ 60 for x=1 to 12 70 read cd 80 in$=in$+chr$(cd) 90 next x 100 data 169, 64,133, 3,165, 64,141, 64, 5, 76,198,254 110 for x=1 to 12 120 read cd 130 ou$=ou$+chr$(cd) 140 next x 150 data 169, 64,133, 3,173, 65, 5,133, 64, 76,198,254 160 print#15,"m-w"chr$(0)chr$(17)chr$(12)in$ 170 print#15,"m-w"chr$(35)chr$(16)chr$(2)chr$(5)chr$(0) 180 jb=208 190 print#15,"m-w"chr$(3)chr$(16)chr$(1)chr$(jb) 200 print#15,"m-r"chr$(64)chr$(17)chr$(1) 210 get#15,x$ 220 x=asc(x$+chr$(0)) 230 bi=x and dr 240 print "{home}{dwn}{dwn}{dwn}commands: <U>p/<D>own/<Q>uit" 250 print "{home}{dwn}{dwn}{dwn}{dwn}{dwn}head stepping: ";se$; 260 print ", step: {lft}{lft}{lft}";bi 270 geta$ 280 if a$="u" then bi=bi+ad:se$="in " 290 if a$="d" then bi=bi-ad:se$="out" 300 if a$="q" then print:close 15:end 310 bi=bi and dr 320 r=(x and df) or bi 330 print#15,"m-w"chr$(65)chr(17)chr$(1)chr$(r) 340 print#15,"m-w"chr$(0)chr$(17)chr$(12)ou$ 350 print#15,"m-w"chr$(35)chr$(16)chr$(2)chr$(5)chr$(0) 360 print#15,"m-w"chr$(3)chr$(16)chr$(1)chr$(jb) 370 goto 160 Description: This routine displays the stepping pattern of the 4040 head. Note : BUFFER #0 is the work buffer. The stepper location is read and displayed to the screen. Cycling the bits produce the following results: Drive 0 (bits 2-3): 00-01-10-11-00 moves head inwards 11-10-01-00-11 moves head outwards Drive 1 (bits 0-1): 00-01-10-11-00 moves head inwards 11-10-01-00-11 moves head outwards Drive memory addresses and/or machine code routines: $0003 = 6404 drive status word $0040 = MOS 6522: port b $0500 - $05FF = Data buffer #0 on 6404 $1003 = Job queue $1023 - $1024 = Track, sector buffer #0 $1100 - $11FF = Data buffer #0 on 6502 imaged from data buffer #0 of 6404 Data set #1: $1100 A9 40 LDA #$40 $1102 85 03 STA $03 $1104 A5 40 LDA $40 $1106 8D 40 05 STA $0540 $1109 4C C6 FE JMP $FEC6 Data set #2: $1100 A9 40 LDA #$40 $1102 85 03 STA $03 $1104 AD 41 05 LDA $0541 $1107 85 40 STA $40 $1109 4C C6 FE JMP $FEC6
4040 PHASE & DENSITY CHECK 10 print "{clr/home}" 20 input"enter drive *{lft}{lft}{lft}";d 30 if d=0 then d$="0":dr=12:goto 50 40 d$="1":dr=3 50 open 15,8,15,"i"+d$ 60 open 1,8,5,"#4" 70 for x=1 to 13 80 read cd 90 in$=in$+chr$(cd) 100 next x 110 data 165, 64,141, 64, 5,165,130,141, 65, 5, 76,198,254 120 print "{home}{dwn}{dwn}press <space> to pause" 130 print "{home}{dwn}{dwn}{dwn}{dwn}track phase density{dwn}" 140 for tr=1 to 35 150 print#15,"u1:";5;d;tr;0 160 print#15,"m-w"chr$(0)chr$(17)chr$(13)in$ 170 print#15,"m-w"chr$(35)chr$(16)chr$(2)chr$(5)chr$(0) 180 jb=208 190 print#15,"m-w"chr$(3)chr$(16)chr$(1)chr$(jb) 200 print#15,"m-r"chr$(64)chr$(17)chr$(1) 210 get#15,ph$ 220 ph=asc(ph$+chr$(0)) 230 print#15,"m-r"chr$(65)chr$(17)chr$(1) 240 get#15,de$ 250 de=asc(de$+chr$(0)) 260 print tab(2);tr;tab(11);ph and dr;tab(22);de and 6 270 get ps$:if ps$<>chr$(32) then 290 280 get ps$:if ps$<>chr$(32) then 280 290 next tr 300 close 15 Description: This routine returns the phase pattern along with the density value for all the tracks of the 4040. Note : BUFFER #0 is the work buffer. Two locations are read in and displayed to the screen. One location is the stepping tag and the other the density select. It seems that the head is on track at every ODD value and that the head is in between tracks at every EVEN value. Drive memory addresses and/or machine code routines: $0040 = MOS 6522: port b $0082 = MOS 6530: port b $0500 - $05FF = Data buffer #0 on 6404 $1003 = Job queue $1023 - $1024 = Track, sector buffer #0 $1100 - $11FF = Data buffer #0 on 6502 imaged from data buffer #0 of 6404 Data set #1: $1100 A5 40 LDA $40 $1102 8D 40 05 STA $0540 $1105 A5 82 LDA $82 $1107 8D 41 05 STA $0541 $110A 4C C6 FE JMP $FEC6
4040 READ HEADER BLOCK 10 print "{clr/home}" 20 open 15,8,15 30 input"track *{lft}{lft}{lft}";tr 40 input"sector *{lft}{lft}{lft}";se 50 print#15,"m-w"chr$(67)chr$(16)chr$(2)chr$(tr)chr$(se) 60 jb=176 70 print#15,"m-w"chr$(7)chr$(16)chr$(1)chr$(jb) 80 print#15,"m-r"chr$(7)chr$(16)chr$(1) 90 get#15,er$(1) 100 er(1)=asc(er$(1)+chr$(0)) 110 if er(1)>127 then 80 120 print#15,"m-w"chr$(67)chr$(16)chr$(2)chr$(tr)chr$(se) 130 jb=128 140 print#15,"m-w"chr$(7)chr$(16)chr$(1)chr$(jb) 150 print#15,"m-r"chr$(7)chr$(16)chr$(1) 160 get#15,er$(2) 170 er(2)=asc(er$(2)+chr$(0)) 180 if er(2)>127 then 150 190 print#15,"m-r"chr$(65)chr$(16)chr$(8) 200 for x=1 to 8 210 get#15,a$(x) 220 a(x)=asc(a$(x)+chr$(0)) 230 next x 240 close 15 250 print "{home}{dwn}{dwn}{dwn}{dwn}" 260 print "seek status :"er(1) 270 print "read status :"er(2) 280 print "id1 :"a(1) 290 print "id2 :"a(2) 300 print "id1+id2 : "chr$(a(1))+chr$(a(2)) 310 print "track :"a(3) 320 print "sector :"a(4) 330 print "checksum :"a(5) 340 print "off :"a(6) 350 print "spare1 :"a(7) 360 print "spare2 :"a(8) Description: This routine returns the header block status of any 4040 track and sector. Note : BUFFER #4 is the buffer in which the result of the operation is found. The routine is composed of 3 parts: SEEK, READ, display information. Drive memory addresses and/or machine code routines: $1007 = Job queue $1041 = Id1 $1042 = Id2 $1043 = Track $1044 = Sector $1045 = Checksum $2100 - $21FF = Data buffer #4
4040 SPEED-UP 10 open 15,8,15 20 print#15,"m-w"chr$(0)chr$(16)chr$(10)chr$(2)chr$(2) 30 close 15 Description: This routine speeds up the 4040 read/write operation. Note : Location $1000 SHOULD NEVER hold a value smaller than #$0A. Smaller values may cause severe hardware failure. It is also noted that the read/write efficiency drops in the outer tracks. Drive memory addresses and/or machine code routines: $1000 = Interrupt delay $1001 = Motor acceleration delay $1002 = Motor cutoff time
A.1 - How to type in programs There is a description underneath each program so as to explain what this particular utility will do. The memory addresses used within the drive are listed as well as any machine code instructions which may be required to perform the routines listed within the programs. Before typing in the programs, make sure to have set your computer in LOWER CASE. Below, is a list of notations which represent special key sequences which need to be pressed on your keyboard. Notation Description Sequence {clr/home} Clear screen Press SHIFT + CLR/HOME {home} Home cursor Press HOME {lft} Cursor left Press SHIFT + CRSR LEFT/RIGHT {rgt} Cursor right Press CRSR LEFT/RIGHT {up} Cursor up Press SHIFT + CRSR UP/DOWN {dwn} Cursor down Press CRSR UP/DOWN
4040 DOS VERSION CODE CHANGE 10 print "{clr/home}" 20 input "dos version code to set drive to *{lft}{lft}{lft}";cd 30 open 15,8,15 40 print#15,"m-w"chr$(159)chr$(16)chr$(1)chr$(cd) 50 close 15 Description: This routine permits read/write to any 4040 formatted disks which the dos character $41 (A) had been altered. Note : This location usually contains ASCII value of 65 which will represent the dos version (2A). Drive memory addresses and/or machine code routines: $109F = Dos version number
4040 WRITE PROTECT TEST 10 print "{clr/home}" 20 input"enter drive *{lft}{lft}{lft}";d 30 d$=chr$(169)+chr$(d) 40 for x=1 to 5 50 read cd 60 d$=d$+chr$(cd) 70 next x 80 data 133,130, 76,198,254 90 for x=1 to 11 100 read cd 110 sw$=sw+chr$(cd) 120 next x 130 data 234,165,130, 41, 9,141, 19, 5, 76,198,254 140 open 15,8,15 150 print#15,"m-w"chr$(0)chr$(17)chr$(7)d$ 160 print#15,"m-w"chr$(17)chr$(16)chr$(2)chr$(5)chr$(0) 170 jb=208 180 print#15,"m-w"chr$(3)chr$(16)chr$(1)chr$(jb) 190 print#15,"m-r"chr$(3)chr$(16)chr$(1) 200 get#15,b$ 210 b=asc(b$+chr$(0)) 220 if b>127 then 190 230 close 15 240 open 15,8,15 250 print#15,"m-w"chr$(0)chr$(17)chr$(11)sw$ 260 print#15,"m-w"chr$(17)chr$(16)chr$(2)chr$(5)chr$(0) 270 print#15,"m-w"chr$(3)chr$(16)chr$(1)chr$(jb) 280 print#15,"m-r"chr$(3)chr$(16)chr$(1) 290 get#15,b$ 300 b=asc(b$+chr$(0)) 310 if b>127 then 280 320 print#15,"m-r"chr$(19)chr$(17)chr$(1) 330 get#15,c$ 340 c=asc(c$+chr$(0)) 350 if c=8 and d=0 then sa$="on":goto 340 360 if c=9 and d=1 then sa$="on":goto 340 370 sa$="off" 380 print "{home}{dwn}{dwn}{dwn}write protect switch drive";d;"is ";sa$ 390 close 15 Description: This routine will scan the write protect sense switch in order to determine if the switch is ON or OFF. All processing done by the 6504. Note : BUFFER #0 is the work buffer. Two routines of which one sets the drive to test and two, tests the write protect switch. Drive memory addresses and/or machine code routines: $0082 = 6404 port b $0519 = State of switch stored at 6404 buffer zero $1003 = Job queue $1023 - $1024 = Track, sector buffer #0 $1100 - $11FF = Data buffer $1119 = State of switch imaged from 6404 Data set #1: $1100 A9 ?? LDA #$?? $1102 82 82 STA $82 $1104 4C C6 FE JMP $FEC6 Data set #2: $1100 A5 82 LDA $82 $1102 A9 09 AND #$82 $1104 8D 13 05 STA $0513 $1107 4C C6 FE JMP $FEC6
4040 SPEED TEST 10 print "{clr/home}":sp$="" 20 print "speed check on unit 8, drive 0 & 1" 30 open 15,8,15 40 for x=0 to 182 50 read a 60 print#15,"m-w"chr$(x)chr$(17)chr$(1)chr$(a) 70 next x 80 ps=0:sc=0:jb=192:dr=0 90 print#15,"m-w"chr$(35)chr$(16)chr$(2)chr$(0)chr$(10) 100 print#15,"m-w"chr$(3)chr$(16)chr$(1)chr$(jb+dr) 110 print#15,"m-r"chr$(3)chr$(16) 120 get#15,a$ 130 a=asc(a$+chr$(0)) 140 if a>127 then 110 150 print "{home}{dwn}{dwn}{dwn}adjust speed deviation to: 0 or +/- 1 ms" 160 for i=1 to 2000:tq=ti:next i 170 print#15,"m-w"chr$(1)chr$(17)chr$(1)chr$(7) 180 print#15,"m-w"chr$(35)chr$(16)chr$(1)chr$(36) 190 print#15,"m-w"chr$(18)chr$(16)chr$(1)chr$(36) 200 jb=224:print#15,"m-w"chr$(3)chr$(16)chr$(1)chr$(jb+dr) 210 jb=192 220 print#15,"m-r"chr$(3)chr$(16) 230 get#15,a$ 240 a=asc(a$+chr$(0)) 250 if a>127 then 220 260 for i=1 to 4 270 print#15,"m-r"chr$(i+2)chr$(17) 280 get#15,a$ 290 sv(i)=asc(a$+chr$(0)) 300 next i 310 no=0:if sv(3)=0 or sv(4)=0 then no=1 320 if no then 340 330 goto 390 340 sc=sc+1:if sc<3 then 170 350 print "{home}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}"; 360 print "{dwn}{dwn}write protect/sync failure on drive";dr:print#15,"uj" 370 close 15:end 380 print "{home}{dwn}{dwn}{dwn}write protect switch drive";d;"is ";sa$ 390 sa=(256*sv(4)+sv(2)-1998) 400 sb=(256*sv(3)+sv(1)-1998) 410 sd=int((sa+sb)/20+.5) 420 print "{home}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}speed deviation"; 430 print " is {lft}{lft}{lft}{lft}{lft}"sd"ms/rev, on drive {lft}"; 440 print "{lft}"dr 450 ps=1:print "{home}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}"; 460 print "speed adjusted for drive {lft}"dr"? y/n" 470 if abs(sd)>5 then 550 480 print#15,"m-w"chr$(1)chr$(17)chr$(1)chr$(60) 490 get a$:if a$="y" then 550 500 if a$="n" and abs(sd)<2 then 550 510 if ti-tq<7000 then 180 520 print "{home}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}{dwn}"; 530 print "{dwn}{dwn}speed test stopped after 2 minutes !":print#15,"uj" 540 close 15:end
550 dr=dr+1:if dr>1 then print#15,"uj":close 15:end 560 ps=0:sc=0:jb=192:goto 90 570 data 76, 7, 5, 0, 0, 0, 0,120,162, 16,134, 78,162, 40,169,220 580 data 133, 76,169, 0,168, 32,167, 5,136,208,250,202,208,247,162,222 590 data 169 600 data 255,134, 76,162, 4, 32,167, 5,202,208,250,169,252,133, 76,169 610 data 146,133, 78,162, 4, 32,176, 5,202,208,250,120,160, 0,140, 4 620 data 5 630 data 140, 6, 5,140, 3, 5,140, 5, 5,140,183, 5,140,184, 5,132 640 data 69,169, 98,133, 68,169, 64,133, 75, 36,130,112, 48,162, 1, 36 650 data 130 660 data 80, 54,132, 69, 36,130, 80, 17,165, 77, 10, 16,247,165, 68,254 670 data 3, 5,208,240,254, 5, 5,208,235,202,240,226,169, 1,133, 75 680 data 88 690 data 173,252,255,240, 3,108, 2,252, 76,249,254,206,183, 5,208,199 700 data 206,184, 5,208,194,240,228,206,183, 5,208,193,206,184, 5,208 710 data 188 720 data 240,216, 36, 77, 16,252,133,128, 36, 65, 96, 36, 77, 16,252,165 730 data 65, 96 Description: This routine will test the timing speed for drive 0 and drive 1 Note : BUFFER #0 is the work buffer. A routine is transferred to this buffer and then passed on to the controller. The disks must be formatted and there must not be any write protect labels. Drive memory addresses and/or machine code routines: $0041 = port a: data input $0044 = timer 1 latch and counter low $0045 = timer 1 counter high $004B = auxiliary control register $004C = peripheral control register $004D = int flag register $004E = int enable register $0080 =6404 port a $0082 = 6404 port b $0519 = State of switch stored at 6404 buffer zero $1003 = Job queue $1023 - $1024 = Track, sector buffer #0 $1100 - $11FF = Data buffer $1119 = State of switch imaged from 6404 Data set #1: $0500 4C 07 05 JMP $0507 $0503 00 BRK $0504 00 BRK $0505 00 BRK $0506 00 BRK $0507 78 SEI $0508 A2 10 LDX #$10 $050A 86 4E STX $4E $050C A2 28 LDX #$28 $050E A9 DC LDA #$DC $0510 85 4C STA $4C $0512 A9 00 LDA #$00 $0514 A8 TAY $0515 20 A7 05 JSR $05A7 $0518 88 DEY $0519 D0 FA BNE $0515 $051B CA DEX $051C D0 F7 BNE $0515 $051E A2 DE LDX #$DE $0520 A9 FF LDA #$FF $0522 86 4C STX $4C $0524 A2 04 LDX #$04 $0526 20 A7 05 JSR $05A7 $0529 CA DEX
$052A D0 FA BNE $0526 $052C A9 FC LDA #$FC $052E 85 4C STA $4C $0530 A9 92 LDA #$92 $0532 85 4E STA $4E $0534 A2 04 LDX #$04 $0536 20 B0 05 JSR $05B0 $0539 CA DEX $053A D0 FA BNE $0536 $053C 78 SEI $053D A0 00 LDY #$00 $053F 8C 04 05 STY $0504 $0542 8C 06 05 STY $0506 $0545 8C 03 05 STY $0503 $0548 8C 05 05 STY $0505 $054B 8C B7 05 STY $05B7 $054E 8C B8 05 STY $05B8 $0551 84 45 STY $45 $0553 A9 62 LDA #$62 $0555 85 44 STA $44 $0557 A9 40 LDA #$40 $0559 85 4B STA $4B $055B 24 82 BIT $82 $055D 70 30 BVS $058F $055F A2 01 LDX #$01 $0561 24 82 BIT $82 $0563 50 36 BVC $059B $0565 84 45 STY $45 $0567 24 82 BIT $82 $0569 50 11 BVC $057C $056B A5 4D LDA $4D $056D 0A ASL $056E 10 F7 BPL $0567 $0570 A5 44 LDA $44 $0572 FE 03 05 INC $0503,X $0575 D0 F0 BNE $0567 $0577 FE 05 05 INC $0505,X $057A D0 EB BNE $0567 $057C CA DEX $057D F0 E2 BEQ $0561 $057F A9 01 LDA #$01 $0581 85 4B STA $4B $0583 58 CLI $0584 AD FC FF LDA $FFFC $0587 F0 03 BEQ $058C $0589 6C 02 FC JMP ($FC02) $058C 4C F9 FE JMP $FEF9 $058F CE B7 05 DEC $05B7 $0592 D0 C7 BNE $055B $0594 CE B8 05 DEC $05B8 $0597 D0 C2 BNE $055B $0599 F0 E4 BEQ $057F $059B CE B7 05 DEC $05B7 $059E D0 C1 BNE $0561 $05A0 CE B8 05 DEC $05B8 $05A3 D0 BC BNE $0561 $05A5 F0 D8 BEQ $057F $05A7 24 4D BIT $4D $05A9 10 FC BPL $05A7 $05AB 85 80 STA $80 $05AD 24 41 BIT $41 $05AF 60 RTS $05B0 24 4D BIT $4D $05B2 10 FC BPL $05B0 $05B4 A5 41 LDA $41 $05B6 60 RTS
APPENDIX B - IEEE bus definitions
B.1 - IEEE Bus connector pins DIO1 DIO5 DIO2 DIO6 DIO3 DIO7 DIO4 DIO8 EOI REN DAV DAV ground NRFD NRFD ground NDAC NDAC ground IFC IFC ground SRQ SRQ ground ATN ATN ground Shield/Earth ground Signal ground
B.2 - IEEE 488 bus signals TYPE PIN LINE DESCRIPTION ----------------------------------------------------------------------------- Manager ATN The controller (PET/CBM) sets this signal low while it is sending commands on the data bus. When ATN is low, only peripheral addresses and control messages are on the data bus. When ATN is high, only previously assigned devices can transfer data Transfer DAV When DAV is low, this signifies that data is valid on the data bus. Manager EOI When the last byte of data is being transferred, the talker has the option of setting EOI low. The controller always sets EOI low while the last data byte is being transferred from the controller. Manager IFC The controller sends its internal reset signal as IFC low (true) to initialize all devices to the idle state. When the controller is switched on or reset, IFC goes low for about 100 milliseconds. Transfer NDAC This signal is held low (true) by the listener while reading. When the data byte has been read, the listener sets NDAC high. This signals the talker that data has been accepted. Transfer NRFD When NRFD is low (true), one or more listeners are not ready for the next byte of data. When all devices are ready, NRFD goes high. Manager SRQ Not implemented in BASIC, but available to the user Manager REN REN is held low by the bus controller. The PET/CBM has a pin grounded that keeps REN permanently low. Data DIO1 - 8 These signals represent the bits of information on the data bus. When a DIO signal is low, it will represent 1 and when high 0. General GROUND Ground connections. There are six control and management signal ground returns, one data signal ground return and one chassis shield ground lead.
B.3 - IEEE Byte transfer sequence (talker)
B.3 - IEEE Byte transfer sequence (listener)
B.4 - IEEE Port pinouts 1 2 3 4 5 6 7 8 9 10 11 12 A B C D E F H J K L M N PIN # PIN # (*) MNEMONIC DEFINITION ----------------------------------------------------------------------------- 1 1 DIO1 Data input/output line #1 2 2 DIO2 Data input/output line #2 3 3 DIO3 Data input/output line #3 4 4 DIO4 Data input/output line #4 5 5 EOI End or identify 6 6 DAV Data valid 7 7 NRFD Not ready for data 8 8 NDAC Data not accepted 9 9 IFC Interface clear 10 10 SRQ Service request 11 11 ATN Attention 12 12 GND Chassis ground (IEEE cable shield) A 13 DIO5 Data input/output line #5 B 14 DIO6 Data input/output line #6 C 15 DIO7 Data input/output line #7 D 16 DIO8 Data input/output line #8 E 17 REN Remote enable F 18 GND DAV ground H 19 GND NRFD ground J 20 GND NDAC ground K 21 GND IFC ground L 22 GND SRQ ground M 23 GND ATN ground N 24 GND Data ground (DIO1 - 8) (*) Pin numbers for standard IEEE cable connector
B.5 - IEEE Standard definitions NAME DEFINITION ----------------------------------------------------------------------------- AC Addressed command ACDS Accept data state ACG Addressed command group ACRS Acceptor ready state AD Addressed AH Acceptor handshake AH1 Complete capability AH0 No capability AIDS Acceptor idle state ANRS Acceptor not ready state ANSI American National Standard's Institute APRS Affirmative poll response state ATN Attention AWNS Acceptor wait for new state C Controller CACS Controller addressed state CADS Controller idle state CAWS Controller active wait state CIDS Controller idle state CPPS Controller parallel poll state CPWS Controller parallel poll wait state CSBS Controller standy state CSNS Controller service not requested state CSRS Controller service request state CSWS Controller synchronous wait state CTRS Controller transfer state DAB Data byte DAC Data accepted DAV Data valid DC Device clear DCAS Device clear active state DCIS Device clear idle state DCL Device clear DD Device dependent DIO Data input DT Data trigger DTAS Device trigger active state DTIS Device trigger state END End EOI End or identify EOS End of string F Active false (F) Passive false GET Group execute trigger NAME DEFINITION ----------------------------------------------------------------------------- GTL Go to local gts Go to standby IDY Identify IFC Interface clear ist Individual status L or LE Listener or extended listener LACS Listener active status LADS Listener addressed state LAG Listener address group LIDS Listener idle state LLO Local lockout LOCS Local state lon Listener only LPAS Listener primary addressed state (lpe) Local poll enable LPIS Listener primary idle state ltn Listen Lun Local unlisten LWLS Local with lockout state M Multiline MLA or (MLA) My listen address MSA or (MSA) My secondary address MTA or (MTA) My talk address nba New byte available NDAC Not data accepted NPRS Negative poll response state NRFD Not ready for data NUL Null byte OSA Other secondary address OTA Other talk address PACS Parallel poll addressed to configure state PCG Primary command group POFS Power off pon Power on PP Parallel poll PPAS Parallel poll active state PPC Parallel poll configure PPD or (PPD) Parallel poll disable PPE or (PPE) Parallel poll enable PPIS Parallel poll idle state PPR Parallel poll response PPSS Parallel poll standby state PPU Parallel poll unconfigure PUCS Parallel poll unaddressed to configure state rdy Ready (for next message) REMS Remote state REN Remote enable
NAME DEFINITION ----------------------------------------------------------------------------- RFD Ready for data RL Remote local rpp Request parallel poll RQS Request service rsc Request system control rsv Request service rtl Return to local RWLS Remote with lockout state SACS System control active state SCG Secondary command group SDC or (SDC) Selected device clear SDYS Source delay state SE Secondary SGNS Source generated state SH Source handshake SIAS System central interface clear active state sic Send interface clear SIDS Source idle state SIIS System control interface clear active state SINS System control interface clear not active state SIWS Source idle wait state SNAS System control not active state SPAS Serial poll active state SPD Serial poll disable SPE Serial poll enable SPIS Serial poll idle state SPMS Serial poll mode state SR Service request SRAS System control remote enable active state sre Send remote enable SRIS System control remote enable idle state SRNS System control remote enable not active state SRQ Service request SRQS Service request state ST Status STB Status byte STRS Source transfer state SWNS Source wait for new cycle state T or (TE) Talker or extended talker T Active true (T) Passive true TACS Talker active state TADS Talker addressed state TAG Talk address group tca Take control asynchronously tcs Take control synchronously TCT or (TCT) Take control TIDS Talker idle state ton Talk only TPAS Talker primary address state U Uniline message NAME DEFINITION ----------------------------------------------------------------------------- UC Universal command UCG Universal command group UNL Unlisten UNT Untalk
APPENDIX C - IC memory/register configurations
C.1 - 6522 VIA (Versatile Interface Adaptor) Vss CA1 PA0 CA2 PA1 RS0 PA2 RS1 PA3 RS2 PA4 RS3 PA5 Reset PA6 D0 PA7 D1 PB0 D2 PB1 D3 PB2 D4 PB3 D5 PB4 D6 PB5 D7 PB6 O2 PB7 CS1 CB1 CS2 CB2 R/W Vcc IRQ
C.2 - 6502 CPU Vss Reset RDY O2 OUT O1 OUT S.O. IRQ O0 IN N.C. N.C. NMI N.C. SYNC R/W Vcc DB0 AB0 DB1 AB1 DB2 AB2 DB3 AB3 DB4 AB4 DB5 AB5 DB6 AB6 DB7 AB7 AB15 AB8 AB14 AB9 AB13 AB10 AB12 AB11 Vss
C.3 - 6522 VIA control registers AUXILLARY CONTROL REGISTER (Chip Address + 11) 7 6 5 4 3 2 1 0 Timer 1 Ctrl T2 Shift Reg Control Latch Ctrl control 0 0 PA Latch disabled, PB Latch disabled 1 1 PA Latch enabled, PB Latch enabled 0 0 0 Shift Register Disabled 0 0 1 Shift IN: shift controlled by Timer 2 0 1 0 Shift IN: shift rate controlled by O2 0 1 1 Shift IN: shift rate controlled by External Clock source 1 0 0 Shift OUT: Free-Running Mode, rate controlled by Timer 2 1 0 1 SHIFT OUT: rate controlled by Timer 2 1 1 0 SHIFT OUT: rate controlled by O2 1 1 1 SHIFT OUT: rate controlled by External Clock source 0 Decrement Counter 2 at O2 clock rate (in one-shot mode) 1 Decrement Counter 2 on pulses from PB6 0 One-Shot Mode 1 Free-Running Mode 0 PB7 disabled 1 PB7 enabled PERIPHERAL CONTROL REGISTER (Chip Address + 12) 7 6 5 4 3 2 1 0 CB2 Control CB1 IRQ CA2 Control CA1 IRQ Control Control 0 A 1 B 0 0 0 C 0 0 1 D 0 1 0 E 0 1 1 F 1 0 0 G 1 0 1 H 1 1 0 I 1 1 1 J 0 K 1 L 0 0 0 M 0 0 1 N 0 1 0 O 0 1 1 P 1 0 0 Q 1 0 1 R 1 1 0 S 1 1 1 T DESCRIPTION A Interrupt Flag Reg Bit1 = 1 on CA1 going low B Interrupt Flag Reg Bit1 = 1 on CA1 going high Interrupt Flag Reg Bit1 cleared by reading I/O Port A C Input Mode: IFR Bit0 = 1 on CA2 going low (cleared by R/W on I/O Port A) D Independent Int. Input Mode: IFR Bit0 = 1 on CA2 going low (Bit0 not cleared by R/W on I/O Port A) C Input Mode: IFR Bit0 = 1 on CA2 going high (cleared by R/W on I/O Port A) F Independent Int. Input Mode: IFR Bit0 = 1 on CA2 going high (Bit0 not cleared by R/W on I/O Port A) G Output Mode w/Handshaking: CA2 goes low on R/W I/O Port A (CA2 goes high on pulse from CA1) H Pulse Output Mode: CA2 goes low for one O2 cycle for R/W on I/O Port A I Manual Output Mode: CA2 set low J Manual Output Mode: CA2 set high K Interrupt Flag Reg Bit4 = 1 on CB1 going low L Interrupt Flag Reg Bit4 = 1 on CB1 going high Interrupt Flag Reg Bit4 cleared by reading I/O Port A M Input Mode: IFR Bit3 = 1 on CB2 going low (cleared by R/W on I/O Port B) N Independent Int. Input Mode: IFR Bit3 = 1 on CB2 going low (Bit3 not cleared by R/W on I/O Port B) O Input Mode: IFR Bit3 = 1 on CB2 going high (cleared by R/W on I/O Port B) P Independent Int. Input Mode: IFR Bit3 = 1 on CB2 going high (Bit3 not cleared by R/W on I/O Port B) Q Output Mode w/Handshaking: CB2 goes low on R/W I/O Port B (CB2 goes high on pulse from CB1) R Pulse Output Mode: CB2 goes low for one O2 cycle for R/W on I/O Port B S Manual Output Mode: CB2 set low T Manual Output Mode: CB2 set high
INTERRUPT FLAG REGISTER (Chip Address + 13) 7 6 5 4 3 2 1 0 IRQ T1 T2 CB1 CB2 SR CA1 CA2 A B C D E F G H Flag set Flag cleared A Transition at CA2 Reading/Writing I/O Port A B Transition at CA1 Reading/Writing I/O Port A C 8 Bits Shifted IN/OUT Reading/Writing Shift Reg D Transition at CB2 Reading/Writing I/O Port B E Transition at CB1 Reading/Writing I/O Port B F Timer 2 Timeout Reading T2 low/Writing T2 High G Timer 1 Timeout Reading T1 low/Writing T1 High H Interrupt Occurring Clearing any interrupt INTERRUPT ENABLE REGISTER (Chip Address + 14) 7 6 5 4 3 2 1 0 S/C T1 T2 CB1 CB2 SR CA1 CA2 0 0 0 0 0 0 0 Interrupt Disabled 1 1 1 1 1 1 1 Interrupt Enabled Set Enable Flag: (write 1 OR'd with Flag Bit n=1) Clear Enable Flag: (write 0 OR'd with Flag Bit n=1)